REGRESSION(r231291): InputType should hold a WeakPtr to its HTMLInputElement
authorbfulgham@apple.com <bfulgham@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 5 Jun 2018 02:31:25 +0000 (02:31 +0000)
committerbfulgham@apple.com <bfulgham@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 5 Jun 2018 02:31:25 +0000 (02:31 +0000)
https://bugs.webkit.org/show_bug.cgi?id=186096
<rdar://problem/40651015>

Reviewed by Ryosuke Niwa.

Now that the InputType may be kept alive as part of in-flight form submissions, we
shouldn't assume that the referenced HTMLInputElement is still valid before using it.

The only time we should be lacking a referencing element is in cases where the InputType
is changing, either through a change in the HTMLInputElement's type attribute. In those
cases we should check for a valid HTMLInputElement. In other cases, we should ASSERT.

* html/BaseButtonInputType.cpp:
(WebCore::BaseButtonInputType::createInputRenderer):
(WebCore::BaseButtonInputType::setValue):
* html/BaseCheckableInputType.cpp:
(WebCore::BaseCheckableInputType::saveFormControlState const):
(WebCore::BaseCheckableInputType::restoreFormControlState):
(WebCore::BaseCheckableInputType::appendFormData const):
(WebCore::BaseCheckableInputType::handleKeydownEvent):
(WebCore::BaseCheckableInputType::accessKeyAction):
(WebCore::BaseCheckableInputType::setValue):
* html/BaseChooserOnlyDateAndTimeInputType.cpp:
(WebCore::BaseChooserOnlyDateAndTimeInputType::attributeChanged): Add a nullptr check
here, since this is called directly by code that causes the old InputType to be removed,
which could leave us with a nullptr element().
* html/BaseClickableWithKeyInputType.cpp:
(WebCore::BaseClickableWithKeyInputType::handleKeydownEvent):
(WebCore::BaseClickableWithKeyInputType::handleKeypressEvent):
(WebCore::BaseClickableWithKeyInputType::accessKeyAction):
* html/BaseDateAndTimeInputType.cpp:
(WebCore::BaseDateAndTimeInputType::attributeChanged): Add a nullptr check
here, since this is called directly by code that causes the old InputType to be removed,
which could leave us with a nullptr element().
* html/BaseTextInputType.cpp:
(WebCore::BaseTextInputType::patternMismatch const):
* html/CheckboxInputType.cpp:
(WebCore::CheckboxInputType::valueMissing const):
(WebCore::CheckboxInputType::willDispatchClick):
(WebCore::CheckboxInputType::didDispatchClick):
(WebCore::CheckboxInputType::shouldAppearIndeterminate const):
* html/ColorInputType.cpp:
(WebCore::ColorInputType::valueAsColor const):
(WebCore::ColorInputType::createShadowSubtree):
(WebCore::ColorInputType::handleDOMActivateEvent):
(WebCore::ColorInputType::didChooseColor):
(WebCore::ColorInputType::updateColorSwatch):
(WebCore::ColorInputType::shadowColorSwatch const):
(WebCore::ColorInputType::elementRectRelativeToRootView const):
(WebCore::ColorInputType::shouldShowSuggestions const):
(WebCore::ColorInputType::suggestions const):
* html/EmailInputType.cpp:
(WebCore::EmailInputType::typeMismatchFor const):
(WebCore::EmailInputType::typeMismatch const):
(WebCore::EmailInputType::typeMismatchText const):
(WebCore::EmailInputType::sanitizeValue const):
* html/FileInputType.cpp:
(WebCore::FileInputType::appendFormData const):
(WebCore::FileInputType::attributeChanged): Add a nullptr check here, since
this is called directly by code that causes the old InputType to be removed,
which could leave us with a nullptr element().
(WebCore::FileInputType::valueMissing const):
(WebCore::FileInputType::valueMissingText const):
(WebCore::FileInputType::handleDOMActivateEvent):
(WebCore::FileInputType::createInputRenderer):
(WebCore::FileInputType::setValue):
(WebCore::FileInputType::createShadowSubtree):
(WebCore::FileInputType::disabledAttributeChanged):
(WebCore::FileInputType::multipleAttributeChanged):
(WebCore::FileInputType::allowsDirectories const):
(WebCore::FileInputType::setFiles):
(WebCore::FileInputType::iconLoaded):
(WebCore::FileInputType::receiveDroppedFiles):
(WebCore::FileInputType::defaultToolTip const):
* html/HTMLInputElement.h:
(WebCore::HTMLInputElement::weakPtrFactory const):
* html/HiddenInputType.cpp:
(WebCore::HiddenInputType::saveFormControlState const):
(WebCore::HiddenInputType::restoreFormControlState):
(WebCore::HiddenInputType::setValue):
(WebCore::HiddenInputType::appendFormData const):
* html/ImageInputType.cpp:
(WebCore::ImageInputType::appendFormData const):
(WebCore::ImageInputType::handleDOMActivateEvent):
(WebCore::ImageInputType::createInputRenderer):
(WebCore::ImageInputType::altAttributeChanged):
(WebCore::ImageInputType::srcAttributeChanged):
(WebCore::ImageInputType::attach):
(WebCore::ImageInputType::height const):
(WebCore::ImageInputType::width const):
* html/InputType.cpp:
(WebCore::InputType::saveFormControlState const):
(WebCore::InputType::restoreFormControlState):
(WebCore::InputType::isFormDataAppendable const):
(WebCore::InputType::appendFormData const):
(WebCore::InputType::sizeShouldIncludeDecoration const):
(WebCore::InputType::validationMessage const):
(WebCore::InputType::createInputRenderer):
(WebCore::InputType::blur):
(WebCore::InputType::destroyShadowSubtree):
(WebCore::InputType::dispatchSimulatedClickIfActive const):
(WebCore::InputType::chrome const):
(WebCore::InputType::isKeyboardFocusable const):
(WebCore::InputType::isMouseFocusable const):
(WebCore::InputType::accessKeyAction):
(WebCore::InputType::setValue):
(WebCore::InputType::visibleValue const):
(WebCore::InputType::applyStep):
(WebCore::InputType::stepUpFromRenderer):
* html/InputType.h:
(WebCore::InputType::InputType):
(WebCore::InputType::element const):
* html/NumberInputType.cpp:
(WebCore::NumberInputType::attributeChanged): Add a nullptr check here, since
this is called directly by code that causes the old InputType to be removed,
which could leave us with a nullptr element().
(WebCore::NumberInputType::setValue):
(WebCore::NumberInputType::valueAsDouble const):
(WebCore::NumberInputType::setValueAsDouble const):
(WebCore::NumberInputType::setValueAsDecimal const):
(WebCore::NumberInputType::typeMismatch const):
(WebCore::NumberInputType::createStepRange const):
(WebCore::NumberInputType::sizeShouldIncludeDecoration const):
(WebCore::NumberInputType::decorationWidth const):
(WebCore::NumberInputType::localizeValue const):
(WebCore::NumberInputType::visibleValue const):
(WebCore::NumberInputType::convertFromVisibleValue const):
(WebCore::NumberInputType::hasBadInput const):
(WebCore::NumberInputType::minOrMaxAttributeChanged):
(WebCore::NumberInputType::stepAttributeChanged):
* html/RadioInputType.cpp:
(WebCore::RadioInputType::valueMissing const):
(WebCore::RadioInputType::handleKeydownEvent):
(WebCore::RadioInputType::handleKeyupEvent):
(WebCore::RadioInputType::isKeyboardFocusable const):
(WebCore::RadioInputType::shouldSendChangeEventAfterCheckedChanged):
(WebCore::RadioInputType::willDispatchClick):
(WebCore::RadioInputType::didDispatchClick):
(WebCore::RadioInputType::matchesIndeterminatePseudoClass const):
* html/RangeInputType.cpp:
(WebCore::RangeInputType::attributeChanged): Add a nullptr check here, since
this is called directly by code that causes the old InputType to be removed,
which could leave us with a nullptr element().
(WebCore::RangeInputType::valueAsDouble const):
(WebCore::RangeInputType::setValueAsDecimal const):
(WebCore::RangeInputType::createStepRange const):
(WebCore::RangeInputType::handleMouseDownEvent):
(WebCore::RangeInputType::handleTouchEvent):
(WebCore::RangeInputType::handleKeydownEvent):
(WebCore::RangeInputType::createShadowSubtree):
(WebCore::RangeInputType::sliderTrackElement const):
(WebCore::RangeInputType::createInputRenderer):
(WebCore::RangeInputType::accessKeyAction):
(WebCore::RangeInputType::minOrMaxAttributeChanged):
(WebCore::RangeInputType::setValue):
(WebCore::RangeInputType::updateTickMarkValues):
* html/ResetInputType.cpp:
(WebCore::ResetInputType::handleDOMActivateEvent):
* html/SearchInputType.cpp:
(WebCore::SearchInputType::addSearchResult):
(WebCore::SearchInputType::maxResultsAttributeChanged):
(WebCore::SearchInputType::createInputRenderer):
(WebCore::SearchInputType::createShadowSubtree):
(WebCore::SearchInputType::handleKeydownEvent):
(WebCore::SearchInputType::startSearchEventTimer):
(WebCore::SearchInputType::searchEventTimerFired):
(WebCore::SearchInputType::searchEventsShouldBeDispatched const):
(WebCore::SearchInputType::didSetValueByUserEdit):
(WebCore::SearchInputType::sizeShouldIncludeDecoration const):
* html/SubmitInputType.cpp:
(WebCore::SubmitInputType::appendFormData const):
(WebCore::SubmitInputType::handleDOMActivateEvent):
* html/TextFieldInputType.cpp:
(WebCore::TextFieldInputType::attributeChanged): Add a nullptr check here, since
this is called directly by code that causes the old InputType to be removed,
which could leave us with a nullptr element().
(WebCore::TextFieldInputType::isKeyboardFocusable const):
(WebCore::TextFieldInputType::isMouseFocusable const):
(WebCore::TextFieldInputType::valueMissing const):
(WebCore::TextFieldInputType::setValue):
(WebCore::TextFieldInputType::handleKeydownEvent):
(WebCore::TextFieldInputType::handleKeydownEventForSpinButton):
(WebCore::TextFieldInputType::forwardEvent):
(WebCore::TextFieldInputType::elementDidBlur):
(WebCore::TextFieldInputType::handleFocusEvent):
(WebCore::TextFieldInputType::handleBlurEvent):
(WebCore::TextFieldInputType::createInputRenderer):
(WebCore::TextFieldInputType::shouldHaveSpinButton const):
(WebCore::TextFieldInputType::shouldHaveCapsLockIndicator const):
(WebCore::TextFieldInputType::createShadowSubtree):
(WebCore::TextFieldInputType::handleBeforeTextInsertedEvent):
(WebCore::TextFieldInputType::updatePlaceholderText):
(WebCore::TextFieldInputType::appendFormData const):
(WebCore::TextFieldInputType::subtreeHasChanged):
(WebCore::TextFieldInputType::didSetValueByUserEdit):
(WebCore::TextFieldInputType::updateInnerTextValue):
(WebCore::TextFieldInputType::focusAndSelectSpinButtonOwner):
(WebCore::TextFieldInputType::shouldSpinButtonRespondToMouseEvents):
(WebCore::TextFieldInputType::shouldSpinButtonRespondToWheelEvents):
(WebCore::TextFieldInputType::shouldDrawCapsLockIndicator const):
(WebCore::TextFieldInputType::shouldDrawAutoFillButton const):
(WebCore::TextFieldInputType::autoFillButtonElementWasClicked):
(WebCore::TextFieldInputType::createContainer):
(WebCore::TextFieldInputType::createAutoFillButton):
(WebCore::TextFieldInputType::updateAutoFillButton):
* html/URLInputType.cpp:
(WebCore::URLInputType::typeMismatch const):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@232496 268f45cc-cd09-0410-ab3c-d52691b4dbfc

24 files changed:
Source/WebCore/ChangeLog
Source/WebCore/html/BaseButtonInputType.cpp
Source/WebCore/html/BaseCheckableInputType.cpp
Source/WebCore/html/BaseChooserOnlyDateAndTimeInputType.cpp
Source/WebCore/html/BaseClickableWithKeyInputType.cpp
Source/WebCore/html/BaseDateAndTimeInputType.cpp
Source/WebCore/html/BaseTextInputType.cpp
Source/WebCore/html/CheckboxInputType.cpp
Source/WebCore/html/ColorInputType.cpp
Source/WebCore/html/EmailInputType.cpp
Source/WebCore/html/FileInputType.cpp
Source/WebCore/html/HTMLInputElement.h
Source/WebCore/html/HiddenInputType.cpp
Source/WebCore/html/ImageInputType.cpp
Source/WebCore/html/InputType.cpp
Source/WebCore/html/InputType.h
Source/WebCore/html/NumberInputType.cpp
Source/WebCore/html/RadioInputType.cpp
Source/WebCore/html/RangeInputType.cpp
Source/WebCore/html/ResetInputType.cpp
Source/WebCore/html/SearchInputType.cpp
Source/WebCore/html/SubmitInputType.cpp
Source/WebCore/html/TextFieldInputType.cpp
Source/WebCore/html/URLInputType.cpp

index 945638a..b07d2ea 100644 (file)
@@ -1,3 +1,214 @@
+2018-06-04  Brent Fulgham  <bfulgham@apple.com>
+
+        REGRESSION(r231291): InputType should hold a WeakPtr to its HTMLInputElement
+        https://bugs.webkit.org/show_bug.cgi?id=186096
+        <rdar://problem/40651015>
+
+        Reviewed by Ryosuke Niwa.
+
+        Now that the InputType may be kept alive as part of in-flight form submissions, we
+        shouldn't assume that the referenced HTMLInputElement is still valid before using it.
+
+        The only time we should be lacking a referencing element is in cases where the InputType
+        is changing, either through a change in the HTMLInputElement's type attribute. In those
+        cases we should check for a valid HTMLInputElement. In other cases, we should ASSERT.
+
+        * html/BaseButtonInputType.cpp:
+        (WebCore::BaseButtonInputType::createInputRenderer):
+        (WebCore::BaseButtonInputType::setValue):
+        * html/BaseCheckableInputType.cpp:
+        (WebCore::BaseCheckableInputType::saveFormControlState const):
+        (WebCore::BaseCheckableInputType::restoreFormControlState):
+        (WebCore::BaseCheckableInputType::appendFormData const):
+        (WebCore::BaseCheckableInputType::handleKeydownEvent):
+        (WebCore::BaseCheckableInputType::accessKeyAction):
+        (WebCore::BaseCheckableInputType::setValue):
+        * html/BaseChooserOnlyDateAndTimeInputType.cpp:
+        (WebCore::BaseChooserOnlyDateAndTimeInputType::attributeChanged): Add a nullptr check
+        here, since this is called directly by code that causes the old InputType to be removed,
+        which could leave us with a nullptr element().
+        * html/BaseClickableWithKeyInputType.cpp:
+        (WebCore::BaseClickableWithKeyInputType::handleKeydownEvent):
+        (WebCore::BaseClickableWithKeyInputType::handleKeypressEvent):
+        (WebCore::BaseClickableWithKeyInputType::accessKeyAction):
+        * html/BaseDateAndTimeInputType.cpp:
+        (WebCore::BaseDateAndTimeInputType::attributeChanged): Add a nullptr check
+        here, since this is called directly by code that causes the old InputType to be removed,
+        which could leave us with a nullptr element().
+        * html/BaseTextInputType.cpp:
+        (WebCore::BaseTextInputType::patternMismatch const):
+        * html/CheckboxInputType.cpp:
+        (WebCore::CheckboxInputType::valueMissing const):
+        (WebCore::CheckboxInputType::willDispatchClick):
+        (WebCore::CheckboxInputType::didDispatchClick):
+        (WebCore::CheckboxInputType::shouldAppearIndeterminate const):
+        * html/ColorInputType.cpp:
+        (WebCore::ColorInputType::valueAsColor const):
+        (WebCore::ColorInputType::createShadowSubtree):
+        (WebCore::ColorInputType::handleDOMActivateEvent):
+        (WebCore::ColorInputType::didChooseColor):
+        (WebCore::ColorInputType::updateColorSwatch):
+        (WebCore::ColorInputType::shadowColorSwatch const):
+        (WebCore::ColorInputType::elementRectRelativeToRootView const):
+        (WebCore::ColorInputType::shouldShowSuggestions const):
+        (WebCore::ColorInputType::suggestions const):
+        * html/EmailInputType.cpp:
+        (WebCore::EmailInputType::typeMismatchFor const):
+        (WebCore::EmailInputType::typeMismatch const):
+        (WebCore::EmailInputType::typeMismatchText const):
+        (WebCore::EmailInputType::sanitizeValue const):
+        * html/FileInputType.cpp:
+        (WebCore::FileInputType::appendFormData const):
+        (WebCore::FileInputType::attributeChanged): Add a nullptr check here, since
+        this is called directly by code that causes the old InputType to be removed,
+        which could leave us with a nullptr element().
+        (WebCore::FileInputType::valueMissing const):
+        (WebCore::FileInputType::valueMissingText const):
+        (WebCore::FileInputType::handleDOMActivateEvent):
+        (WebCore::FileInputType::createInputRenderer):
+        (WebCore::FileInputType::setValue):
+        (WebCore::FileInputType::createShadowSubtree):
+        (WebCore::FileInputType::disabledAttributeChanged):
+        (WebCore::FileInputType::multipleAttributeChanged):
+        (WebCore::FileInputType::allowsDirectories const):
+        (WebCore::FileInputType::setFiles):
+        (WebCore::FileInputType::iconLoaded):
+        (WebCore::FileInputType::receiveDroppedFiles):
+        (WebCore::FileInputType::defaultToolTip const):
+        * html/HTMLInputElement.h:
+        (WebCore::HTMLInputElement::weakPtrFactory const):
+        * html/HiddenInputType.cpp:
+        (WebCore::HiddenInputType::saveFormControlState const):
+        (WebCore::HiddenInputType::restoreFormControlState):
+        (WebCore::HiddenInputType::setValue):
+        (WebCore::HiddenInputType::appendFormData const):
+        * html/ImageInputType.cpp:
+        (WebCore::ImageInputType::appendFormData const):
+        (WebCore::ImageInputType::handleDOMActivateEvent):
+        (WebCore::ImageInputType::createInputRenderer):
+        (WebCore::ImageInputType::altAttributeChanged):
+        (WebCore::ImageInputType::srcAttributeChanged):
+        (WebCore::ImageInputType::attach):
+        (WebCore::ImageInputType::height const):
+        (WebCore::ImageInputType::width const):
+        * html/InputType.cpp:
+        (WebCore::InputType::saveFormControlState const):
+        (WebCore::InputType::restoreFormControlState):
+        (WebCore::InputType::isFormDataAppendable const):
+        (WebCore::InputType::appendFormData const):
+        (WebCore::InputType::sizeShouldIncludeDecoration const):
+        (WebCore::InputType::validationMessage const):
+        (WebCore::InputType::createInputRenderer):
+        (WebCore::InputType::blur):
+        (WebCore::InputType::destroyShadowSubtree):
+        (WebCore::InputType::dispatchSimulatedClickIfActive const):
+        (WebCore::InputType::chrome const):
+        (WebCore::InputType::isKeyboardFocusable const):
+        (WebCore::InputType::isMouseFocusable const):
+        (WebCore::InputType::accessKeyAction):
+        (WebCore::InputType::setValue):
+        (WebCore::InputType::visibleValue const):
+        (WebCore::InputType::applyStep):
+        (WebCore::InputType::stepUpFromRenderer):
+        * html/InputType.h:
+        (WebCore::InputType::InputType):
+        (WebCore::InputType::element const):
+        * html/NumberInputType.cpp:
+        (WebCore::NumberInputType::attributeChanged): Add a nullptr check here, since
+        this is called directly by code that causes the old InputType to be removed,
+        which could leave us with a nullptr element().
+        (WebCore::NumberInputType::setValue):
+        (WebCore::NumberInputType::valueAsDouble const):
+        (WebCore::NumberInputType::setValueAsDouble const):
+        (WebCore::NumberInputType::setValueAsDecimal const):
+        (WebCore::NumberInputType::typeMismatch const):
+        (WebCore::NumberInputType::createStepRange const):
+        (WebCore::NumberInputType::sizeShouldIncludeDecoration const):
+        (WebCore::NumberInputType::decorationWidth const):
+        (WebCore::NumberInputType::localizeValue const):
+        (WebCore::NumberInputType::visibleValue const):
+        (WebCore::NumberInputType::convertFromVisibleValue const):
+        (WebCore::NumberInputType::hasBadInput const):
+        (WebCore::NumberInputType::minOrMaxAttributeChanged):
+        (WebCore::NumberInputType::stepAttributeChanged):
+        * html/RadioInputType.cpp:
+        (WebCore::RadioInputType::valueMissing const):
+        (WebCore::RadioInputType::handleKeydownEvent):
+        (WebCore::RadioInputType::handleKeyupEvent):
+        (WebCore::RadioInputType::isKeyboardFocusable const):
+        (WebCore::RadioInputType::shouldSendChangeEventAfterCheckedChanged):
+        (WebCore::RadioInputType::willDispatchClick):
+        (WebCore::RadioInputType::didDispatchClick):
+        (WebCore::RadioInputType::matchesIndeterminatePseudoClass const):
+        * html/RangeInputType.cpp:
+        (WebCore::RangeInputType::attributeChanged): Add a nullptr check here, since
+        this is called directly by code that causes the old InputType to be removed,
+        which could leave us with a nullptr element().
+        (WebCore::RangeInputType::valueAsDouble const):
+        (WebCore::RangeInputType::setValueAsDecimal const):
+        (WebCore::RangeInputType::createStepRange const):
+        (WebCore::RangeInputType::handleMouseDownEvent):
+        (WebCore::RangeInputType::handleTouchEvent):
+        (WebCore::RangeInputType::handleKeydownEvent):
+        (WebCore::RangeInputType::createShadowSubtree):
+        (WebCore::RangeInputType::sliderTrackElement const):
+        (WebCore::RangeInputType::createInputRenderer):
+        (WebCore::RangeInputType::accessKeyAction):
+        (WebCore::RangeInputType::minOrMaxAttributeChanged):
+        (WebCore::RangeInputType::setValue):
+        (WebCore::RangeInputType::updateTickMarkValues):
+        * html/ResetInputType.cpp:
+        (WebCore::ResetInputType::handleDOMActivateEvent):
+        * html/SearchInputType.cpp:
+        (WebCore::SearchInputType::addSearchResult):
+        (WebCore::SearchInputType::maxResultsAttributeChanged):
+        (WebCore::SearchInputType::createInputRenderer):
+        (WebCore::SearchInputType::createShadowSubtree):
+        (WebCore::SearchInputType::handleKeydownEvent):
+        (WebCore::SearchInputType::startSearchEventTimer):
+        (WebCore::SearchInputType::searchEventTimerFired):
+        (WebCore::SearchInputType::searchEventsShouldBeDispatched const):
+        (WebCore::SearchInputType::didSetValueByUserEdit):
+        (WebCore::SearchInputType::sizeShouldIncludeDecoration const):
+        * html/SubmitInputType.cpp:
+        (WebCore::SubmitInputType::appendFormData const):
+        (WebCore::SubmitInputType::handleDOMActivateEvent):
+        * html/TextFieldInputType.cpp:
+        (WebCore::TextFieldInputType::attributeChanged): Add a nullptr check here, since
+        this is called directly by code that causes the old InputType to be removed,
+        which could leave us with a nullptr element().
+        (WebCore::TextFieldInputType::isKeyboardFocusable const):
+        (WebCore::TextFieldInputType::isMouseFocusable const):
+        (WebCore::TextFieldInputType::valueMissing const):
+        (WebCore::TextFieldInputType::setValue):
+        (WebCore::TextFieldInputType::handleKeydownEvent):
+        (WebCore::TextFieldInputType::handleKeydownEventForSpinButton):
+        (WebCore::TextFieldInputType::forwardEvent):
+        (WebCore::TextFieldInputType::elementDidBlur):
+        (WebCore::TextFieldInputType::handleFocusEvent):
+        (WebCore::TextFieldInputType::handleBlurEvent):
+        (WebCore::TextFieldInputType::createInputRenderer):
+        (WebCore::TextFieldInputType::shouldHaveSpinButton const):
+        (WebCore::TextFieldInputType::shouldHaveCapsLockIndicator const):
+        (WebCore::TextFieldInputType::createShadowSubtree):
+        (WebCore::TextFieldInputType::handleBeforeTextInsertedEvent):
+        (WebCore::TextFieldInputType::updatePlaceholderText):
+        (WebCore::TextFieldInputType::appendFormData const):
+        (WebCore::TextFieldInputType::subtreeHasChanged):
+        (WebCore::TextFieldInputType::didSetValueByUserEdit):
+        (WebCore::TextFieldInputType::updateInnerTextValue):
+        (WebCore::TextFieldInputType::focusAndSelectSpinButtonOwner):
+        (WebCore::TextFieldInputType::shouldSpinButtonRespondToMouseEvents):
+        (WebCore::TextFieldInputType::shouldSpinButtonRespondToWheelEvents):
+        (WebCore::TextFieldInputType::shouldDrawCapsLockIndicator const):
+        (WebCore::TextFieldInputType::shouldDrawAutoFillButton const):
+        (WebCore::TextFieldInputType::autoFillButtonElementWasClicked):
+        (WebCore::TextFieldInputType::createContainer):
+        (WebCore::TextFieldInputType::createAutoFillButton):
+        (WebCore::TextFieldInputType::updateAutoFillButton):
+        * html/URLInputType.cpp:
+        (WebCore::URLInputType::typeMismatch const):
+
 2018-06-04  Chris Dumez  <cdumez@apple.com>
 
         Unreviewed iOS build fix with recent SDKs.
index 8dcb72c..2ddbaeb 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2010 Google Inc. All rights reserved.
- * Copyright (C) 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2011-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -53,7 +53,8 @@ bool BaseButtonInputType::appendFormData(DOMFormData&, bool) const
 
 RenderPtr<RenderElement> BaseButtonInputType::createInputRenderer(RenderStyle&& style)
 {
-    return createRenderer<RenderButton>(element(), WTFMove(style));
+    ASSERT(element());
+    return createRenderer<RenderButton>(*element(), WTFMove(style));
 }
 
 bool BaseButtonInputType::storesValueSeparateFromAttribute()
@@ -63,7 +64,8 @@ bool BaseButtonInputType::storesValueSeparateFromAttribute()
 
 void BaseButtonInputType::setValue(const String& sanitizedValue, bool, TextFieldEventBehavior)
 {
-    element().setAttributeWithoutSynchronization(valueAttr, sanitizedValue);
+    ASSERT(element());
+    element()->setAttributeWithoutSynchronization(valueAttr, sanitizedValue);
 }
 
 } // namespace WebCore
index 33130fb..6a25671 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2010 Google Inc. All rights reserved.
- * Copyright (C) 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2011-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -45,19 +45,22 @@ using namespace HTMLNames;
 
 FormControlState BaseCheckableInputType::saveFormControlState() const
 {
-    return { element().checked() ? ASCIILiteral("on") : ASCIILiteral("off") };
+    ASSERT(element());
+    return { element()->checked() ? ASCIILiteral("on") : ASCIILiteral("off") };
 }
 
 void BaseCheckableInputType::restoreFormControlState(const FormControlState& state)
 {
-    element().setChecked(state[0] == "on");
+    ASSERT(element());
+    element()->setChecked(state[0] == "on");
 }
 
 bool BaseCheckableInputType::appendFormData(DOMFormData& formData, bool) const
 {
-    if (!element().checked())
+    ASSERT(element());
+    if (!element()->checked())
         return false;
-    formData.append(element().name(), element().value());
+    formData.append(element()->name(), element()->value());
     return true;
 }
 
@@ -65,7 +68,8 @@ void BaseCheckableInputType::handleKeydownEvent(KeyboardEvent& event)
 {
     const String& key = event.keyIdentifier();
     if (key == "U+0020") {
-        element().setActive(true, true);
+        ASSERT(element());
+        element()->setActive(true, true);
         // No setDefaultHandled(), because IE dispatches a keypress in this case
         // and the caller will only dispatch a keypress if we don't call setDefaultHandled().
     }
@@ -89,7 +93,8 @@ void BaseCheckableInputType::accessKeyAction(bool sendMouseEvents)
 {
     InputType::accessKeyAction(sendMouseEvents);
 
-    element().dispatchSimulatedClick(0, sendMouseEvents ? SendMouseUpDownEvents : SendNoEvents);
+    ASSERT(element());
+    element()->dispatchSimulatedClick(0, sendMouseEvents ? SendMouseUpDownEvents : SendNoEvents);
 }
 
 String BaseCheckableInputType::fallbackValue() const
@@ -105,7 +110,8 @@ bool BaseCheckableInputType::storesValueSeparateFromAttribute()
 
 void BaseCheckableInputType::setValue(const String& sanitizedValue, bool, TextFieldEventBehavior)
 {
-    element().setAttributeWithoutSynchronization(valueAttr, sanitizedValue);
+    ASSERT(element());
+    element()->setAttributeWithoutSynchronization(valueAttr, sanitizedValue);
 }
 
 bool BaseCheckableInputType::isCheckable()
index 302a5c3..5c463a0 100644 (file)
@@ -138,8 +138,10 @@ bool BaseChooserOnlyDateAndTimeInputType::isMouseFocusable() const
 void BaseChooserOnlyDateAndTimeInputType::attributeChanged(const QualifiedName& name)
 {
     if (name == valueAttr) {
-        if (!element().hasDirtyValue())
-            updateInnerTextValue();
+        if (auto* element = this->element()) {
+            if (!element->hasDirtyValue())
+                updateInnerTextValue();
+        }
     }
     BaseDateAndTimeInputType::attributeChanged(name);
 }
index 26eb957..2c4dd55 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2010, 2012 Google Inc. All rights reserved.
- * Copyright (C) 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2011-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -80,12 +80,14 @@ void BaseClickableWithKeyInputType::accessKeyAction(HTMLInputElement& element, b
 
 void BaseClickableWithKeyInputType::handleKeydownEvent(KeyboardEvent& event)
 {
-    handleKeydownEvent(element(), event);
+    ASSERT(element());
+    handleKeydownEvent(*element(), event);
 }
 
 void BaseClickableWithKeyInputType::handleKeypressEvent(KeyboardEvent& event)
 {
-    handleKeypressEvent(element(), event);
+    ASSERT(element());
+    handleKeypressEvent(*element(), event);
 }
 
 void BaseClickableWithKeyInputType::handleKeyupEvent(KeyboardEvent& event)
@@ -96,7 +98,8 @@ void BaseClickableWithKeyInputType::handleKeyupEvent(KeyboardEvent& event)
 void BaseClickableWithKeyInputType::accessKeyAction(bool sendMouseEvents)
 {
     InputType::accessKeyAction(sendMouseEvents);
-    accessKeyAction(element(), sendMouseEvents);
+    ASSERT(element());
+    accessKeyAction(*element(), sendMouseEvents);
 }
 
 } // namespace WebCore
index 9ec9a0a..cc9070a 100644 (file)
@@ -97,8 +97,10 @@ bool BaseDateAndTimeInputType::isSteppable() const
 
 void BaseDateAndTimeInputType::attributeChanged(const QualifiedName& name)
 {
-    if (name == maxAttr || name == minAttr)
-        element().invalidateStyleForSubtree();
+    if (name == maxAttr || name == minAttr) {
+        if (auto* element = this->element())
+            element->invalidateStyleForSubtree();
+    }
     InputType::attributeChanged(name);
 }
 
index e29ddf2..b3685b9 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Copyright (C) 2009 Michelangelo De Simone <micdesim@gmail.com>
  * Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -39,9 +40,10 @@ bool BaseTextInputType::isTextType() const
 
 bool BaseTextInputType::patternMismatch(const String& value) const
 {
+    ASSERT(element());
     // FIXME: We should execute RegExp parser first to check validity instead of creating an actual RegularExpression.
     // https://bugs.webkit.org/show_bug.cgi?id=183361
-    const AtomicString& rawPattern = element().attributeWithoutSynchronization(patternAttr);
+    const AtomicString& rawPattern = element()->attributeWithoutSynchronization(patternAttr);
     if (rawPattern.isNull() || value.isEmpty() || !JSC::Yarr::RegularExpression(rawPattern, JSC::Yarr::TextCaseSensitive, JSC::Yarr::MultilineDisabled, JSC::Yarr::UnicodeAwareMode).isValid())
         return false;
     String pattern = "^(?:" + rawPattern + ")$";
index 62c4f7a..8937e53 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2010 Google Inc. All rights reserved.
- * Copyright (C) 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2011-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -46,7 +46,8 @@ const AtomicString& CheckboxInputType::formControlType() const
 
 bool CheckboxInputType::valueMissing(const String&) const
 {
-    return element().isRequired() && !element().checked();
+    ASSERT(element());
+    return element()->isRequired() && !element()->checked();
 }
 
 String CheckboxInputType::valueMissingText() const
@@ -64,23 +65,26 @@ void CheckboxInputType::handleKeyupEvent(KeyboardEvent& event)
 
 void CheckboxInputType::willDispatchClick(InputElementClickState& state)
 {
+    ASSERT(element());
+
     // An event handler can use preventDefault or "return false" to reverse the checking we do here.
     // The InputElementClickState object contains what we need to undo what we did here in didDispatchClick.
 
-    state.checked = element().checked();
-    state.indeterminate = element().indeterminate();
+    state.checked = element()->checked();
+    state.indeterminate = element()->indeterminate();
 
     if (state.indeterminate)
-        element().setIndeterminate(false);
+        element()->setIndeterminate(false);
 
-    element().setChecked(!state.checked, DispatchChangeEvent);
+    element()->setChecked(!state.checked, DispatchChangeEvent);
 }
 
 void CheckboxInputType::didDispatchClick(Event& event, const InputElementClickState& state)
 {
     if (event.defaultPrevented() || event.defaultHandled()) {
-        element().setIndeterminate(state.indeterminate);
-        element().setChecked(state.checked);
+        ASSERT(element());
+        element()->setIndeterminate(state.indeterminate);
+        element()->setChecked(state.checked);
     }
 
     // The work we did in willDispatchClick was default handling.
@@ -99,7 +103,8 @@ bool CheckboxInputType::matchesIndeterminatePseudoClass() const
 
 bool CheckboxInputType::shouldAppearIndeterminate() const
 {
-    return element().indeterminate();
+    ASSERT(element());
+    return element()->indeterminate();
 }
 
 } // namespace WebCore
index d9e4d42..4dac86f 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2010 Google Inc. All rights reserved.
- * Copyright (C) 2015-2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -111,20 +111,22 @@ String ColorInputType::sanitizeValue(const String& proposedValue) const
 
 Color ColorInputType::valueAsColor() const
 {
-    return parseSimpleColorValue(element().value()).value();
+    ASSERT(element());
+    return parseSimpleColorValue(element()->value()).value();
 }
 
 void ColorInputType::createShadowSubtree()
 {
-    ASSERT(element().shadowRoot());
+    ASSERT(element());
+    ASSERT(element()->shadowRoot());
 
-    Document& document = element().document();
+    Document& document = element()->document();
     auto wrapperElement = HTMLDivElement::create(document);
     wrapperElement->setPseudo(AtomicString("-webkit-color-swatch-wrapper", AtomicString::ConstructFromLiteral));
     auto colorSwatch = HTMLDivElement::create(document);
     colorSwatch->setPseudo(AtomicString("-webkit-color-swatch", AtomicString::ConstructFromLiteral));
     wrapperElement->appendChild(colorSwatch);
-    element().userAgentShadowRoot()->appendChild(wrapperElement);
+    element()->userAgentShadowRoot()->appendChild(wrapperElement);
 
     updateColorSwatch();
 }
@@ -143,7 +145,8 @@ void ColorInputType::setValue(const String& value, bool valueChanged, TextFieldE
 
 void ColorInputType::handleDOMActivateEvent(Event& event)
 {
-    if (element().isDisabledFormControl() || !element().renderer())
+    ASSERT(element());
+    if (element()->isDisabledFormControl() || !element()->renderer())
         return;
 
     if (!UserGestureIndicator::processingUserGesture())
@@ -181,12 +184,13 @@ bool ColorInputType::shouldResetOnDocumentActivation()
 
 void ColorInputType::didChooseColor(const Color& color)
 {
-    if (element().isDisabledFormControl() || color == valueAsColor())
+    ASSERT(element());
+    if (element()->isDisabledFormControl() || color == valueAsColor())
         return;
     EventQueueScope scope;
-    element().setValueFromRenderer(color.serialized());
+    element()->setValueFromRenderer(color.serialized());
     updateColorSwatch();
-    element().dispatchFormControlChangeEvent();
+    element()->dispatchFormControlChangeEvent();
 }
 
 void ColorInputType::didEndChooser()
@@ -206,12 +210,14 @@ void ColorInputType::updateColorSwatch()
     if (!colorSwatch)
         return;
 
-    colorSwatch->setInlineStyleProperty(CSSPropertyBackgroundColor, element().value(), false);
+    ASSERT(element());
+    colorSwatch->setInlineStyleProperty(CSSPropertyBackgroundColor, element()->value(), false);
 }
 
 HTMLElement* ColorInputType::shadowColorSwatch() const
 {
-    RefPtr<ShadowRoot> shadow = element().userAgentShadowRoot();
+    ASSERT(element());
+    RefPtr<ShadowRoot> shadow = element()->userAgentShadowRoot();
     if (!shadow)
         return nullptr;
 
@@ -224,9 +230,10 @@ HTMLElement* ColorInputType::shadowColorSwatch() const
 
 IntRect ColorInputType::elementRectRelativeToRootView() const
 {
-    if (!element().renderer())
+    ASSERT(element());
+    if (!element()->renderer())
         return IntRect();
-    return element().document().view()->contentsToRootView(element().renderer()->absoluteBoundingBoxRect());
+    return element()->document().view()->contentsToRootView(element()->renderer()->absoluteBoundingBoxRect());
 }
 
 Color ColorInputType::currentColor()
@@ -237,7 +244,8 @@ Color ColorInputType::currentColor()
 bool ColorInputType::shouldShowSuggestions() const
 {
 #if ENABLE(DATALIST_ELEMENT)
-    return element().hasAttributeWithoutSynchronization(listAttr);
+    ASSERT(element());
+    return element()->hasAttributeWithoutSynchronization(listAttr);
 #else
     return false;
 #endif
@@ -247,7 +255,8 @@ Vector<Color> ColorInputType::suggestions() const
 {
     Vector<Color> suggestions;
 #if ENABLE(DATALIST_ELEMENT)
-    if (auto dataList = element().dataList()) {
+    ASSERT(element());
+    if (auto dataList = element()->dataList()) {
         Ref<HTMLCollection> options = dataList->options();
         unsigned length = options->length();
         suggestions.reserveInitialCapacity(length);
index b93e12b..0a84339 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Copyright (C) 2009 Michelangelo De Simone <micdesim@gmail.com>
  * Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -58,9 +59,10 @@ const AtomicString& EmailInputType::formControlType() const
 
 bool EmailInputType::typeMismatchFor(const String& value) const
 {
+    ASSERT(element());
     if (value.isEmpty())
         return false;
-    if (!element().multiple())
+    if (!element()->multiple())
         return !isValidEmailAddress(value);
     Vector<String> addresses;
     value.split(',', true, addresses);
@@ -73,12 +75,14 @@ bool EmailInputType::typeMismatchFor(const String& value) const
 
 bool EmailInputType::typeMismatch() const
 {
-    return typeMismatchFor(element().value());
+    ASSERT(element());
+    return typeMismatchFor(element()->value());
 }
 
 String EmailInputType::typeMismatchText() const
 {
-    return element().multiple() ? validationMessageTypeMismatchForMultipleEmailText() : validationMessageTypeMismatchForEmailText();
+    ASSERT(element());
+    return element()->multiple() ? validationMessageTypeMismatchForMultipleEmailText() : validationMessageTypeMismatchForEmailText();
 }
 
 bool EmailInputType::isEmailField() const
@@ -94,7 +98,8 @@ bool EmailInputType::supportsSelectionAPI() const
 String EmailInputType::sanitizeValue(const String& proposedValue) const
 {
     String noLineBreakValue = proposedValue.removeCharacters(isHTMLLineBreak);
-    if (!element().multiple())
+    ASSERT(element());
+    if (!element()->multiple())
         return stripLeadingAndTrailingHTMLSpaces(noLineBreakValue);
     Vector<String> addresses;
     noLineBreakValue.split(',', true, addresses);
index a972461..03af3a9 100644 (file)
@@ -153,10 +153,11 @@ void FileInputType::restoreFormControlState(const FormControlState& state)
 
 bool FileInputType::appendFormData(DOMFormData& formData, bool multipart) const
 {
-    auto fileList = makeRefPtr(element().files());
+    ASSERT(element());
+    auto fileList = makeRefPtr(element()->files());
     ASSERT(fileList);
 
-    auto name = element().name();
+    auto name = element()->name();
 
     if (!multipart) {
         // Send only the basenames.
@@ -186,17 +187,20 @@ bool FileInputType::appendFormData(DOMFormData& formData, bool multipart) const
 
 bool FileInputType::valueMissing(const String& value) const
 {
-    return element().isRequired() && value.isEmpty();
+    ASSERT(element());
+    return element()->isRequired() && value.isEmpty();
 }
 
 String FileInputType::valueMissingText() const
 {
-    return element().multiple() ? validationMessageValueMissingForMultipleFileText() : validationMessageValueMissingForFileText();
+    ASSERT(element());
+    return element()->multiple() ? validationMessageValueMissingForMultipleFileText() : validationMessageValueMissingForFileText();
 }
 
 void FileInputType::handleDOMActivateEvent(Event& event)
 {
-    auto& input = element();
+    ASSERT(element());
+    auto& input = *element();
 
     if (input.isDisabledFormControl())
         return;
@@ -223,7 +227,8 @@ void FileInputType::handleDOMActivateEvent(Event& event)
 
 RenderPtr<RenderElement> FileInputType::createInputRenderer(RenderStyle&& style)
 {
-    return createRenderer<RenderFileUploadControl>(element(), WTFMove(style));
+    ASSERT(element());
+    return createRenderer<RenderFileUploadControl>(*element(), WTFMove(style));
 }
 
 bool FileInputType::canSetStringValue() const
@@ -267,7 +272,8 @@ void FileInputType::setValue(const String&, bool, TextFieldEventBehavior)
     // FIXME: Should we clear the file list, or replace it with a new empty one here? This is observable from JavaScript through custom properties.
     m_fileList->clear();
     m_icon = nullptr;
-    element().invalidateStyleForSubtree();
+    ASSERT(element());
+    element()->invalidateStyleForSubtree();
 }
 
 bool FileInputType::isFileUpload() const
@@ -277,29 +283,33 @@ bool FileInputType::isFileUpload() const
 
 void FileInputType::createShadowSubtree()
 {
-    ASSERT(element().shadowRoot());
-    element().userAgentShadowRoot()->appendChild(element().multiple() ? UploadButtonElement::createForMultiple(element().document()): UploadButtonElement::create(element().document()));
+    ASSERT(element());
+    ASSERT(element()->shadowRoot());
+    element()->userAgentShadowRoot()->appendChild(element()->multiple() ? UploadButtonElement::createForMultiple(element()->document()): UploadButtonElement::create(element()->document()));
 }
 
 void FileInputType::disabledStateChanged()
 {
-    ASSERT(element().shadowRoot());
+    ASSERT(element());
+    ASSERT(element()->shadowRoot());
 
-    auto root = element().userAgentShadowRoot();
+    auto root = element()->userAgentShadowRoot();
     if (!root)
         return;
     
     if (auto button = makeRefPtr(childrenOfType<UploadButtonElement>(*root).first()))
-        button->setBooleanAttribute(disabledAttr, element().isDisabledFormControl());
+        button->setBooleanAttribute(disabledAttr, element()->isDisabledFormControl());
 }
 
 void FileInputType::attributeChanged(const QualifiedName& name)
 {
     if (name == multipleAttr) {
-        ASSERT(element().shadowRoot());
-        if (auto root = element().userAgentShadowRoot()) {
-            if (auto button = makeRefPtr(childrenOfType<UploadButtonElement>(*root).first()))
-                button->setValue(element().multiple() ? fileButtonChooseMultipleFilesLabel() : fileButtonChooseFileLabel());
+        if (auto* element = this->element()) {
+            ASSERT(element->shadowRoot());
+            if (auto root = element->userAgentShadowRoot()) {
+                if (auto button = makeRefPtr(childrenOfType<UploadButtonElement>(*root).first()))
+                    button->setValue(element->multiple() ? fileButtonChooseMultipleFilesLabel() : fileButtonChooseFileLabel());
+            }
         }
     }
     BaseClickableWithKeyInputType::attributeChanged(name);
@@ -339,7 +349,8 @@ bool FileInputType::allowsDirectories() const
 {
     if (!RuntimeEnabledFeatures::sharedFeatures().directoryUploadEnabled())
         return false;
-    return element().hasAttributeWithoutSynchronization(webkitdirectoryAttr);
+    ASSERT(element());
+    return element()->hasAttributeWithoutSynchronization(webkitdirectoryAttr);
 }
 
 void FileInputType::setFiles(RefPtr<FileList>&& files)
@@ -352,7 +363,8 @@ void FileInputType::setFiles(RefPtr<FileList>&& files, RequestIcon shouldRequest
     if (!files)
         return;
 
-    Ref<HTMLInputElement> input(element());
+    ASSERT(element());
+    Ref<HTMLInputElement> protectedInputElement(*element());
 
     unsigned length = files->length();
 
@@ -370,8 +382,8 @@ void FileInputType::setFiles(RefPtr<FileList>&& files, RequestIcon shouldRequest
 
     m_fileList = files.releaseNonNull();
 
-    input->setFormControlValueMatchesRenderer(true);
-    input->updateValidity();
+    protectedInputElement->setFormControlValueMatchesRenderer(true);
+    protectedInputElement->updateValidity();
 
     if (shouldRequestIcon == RequestIcon::Yes) {
         Vector<String> paths;
@@ -381,15 +393,15 @@ void FileInputType::setFiles(RefPtr<FileList>&& files, RequestIcon shouldRequest
         requestIcon(paths);
     }
 
-    if (input->renderer())
-        input->renderer()->repaint();
+    if (protectedInputElement->renderer())
+        protectedInputElement->renderer()->repaint();
 
     if (pathsChanged) {
         // This call may cause destruction of this instance.
         // input instance is safe since it is ref-counted.
-        input->dispatchChangeEvent();
+        protectedInputElement->dispatchChangeEvent();
     }
-    input->setChangedSinceLastFormControlChangeEvent(false);
+    protectedInputElement->setChangedSinceLastFormControlChangeEvent(false);
 }
 
 void FileInputType::filesChosen(const Vector<FileChooserFileInfo>& paths, const String& displayString, Icon* icon)
@@ -422,8 +434,9 @@ void FileInputType::iconLoaded(RefPtr<Icon>&& icon)
         return;
 
     m_icon = WTFMove(icon);
-    if (element().renderer())
-        element().renderer()->repaint();
+    ASSERT(element());
+    if (auto* renderer = element()->renderer())
+        renderer->repaint();
 }
 
 #if ENABLE(DRAG_SUPPORT)
@@ -433,7 +446,8 @@ bool FileInputType::receiveDroppedFiles(const DragData& dragData)
     if (paths.isEmpty())
         return false;
 
-    if (element().hasAttributeWithoutSynchronization(multipleAttr)) {
+    ASSERT(element());
+    if (element()->hasAttributeWithoutSynchronization(multipleAttr)) {
         Vector<FileChooserFileInfo> files;
         files.reserveInitialCapacity(paths.size());
         for (auto& path : paths)
@@ -456,7 +470,8 @@ String FileInputType::defaultToolTip() const
 {
     unsigned listSize = m_fileList->length();
     if (!listSize) {
-        if (element().multiple())
+        ASSERT(element());
+        if (element()->multiple())
             return fileButtonNoFilesSelectedLabel();
         return fileButtonNoFileSelectedLabel();
     }
index 0299f0c..bf605df 100644 (file)
@@ -28,6 +28,7 @@
 #include "HTMLTextFormControlElement.h"
 #include "StepRange.h"
 #include <memory>
+#include <wtf/WeakPtr.h>
 
 #if PLATFORM(IOS)
 #include "DateComponents.h"
@@ -342,6 +343,8 @@ public:
 
     ExceptionOr<void> setSelectionRangeForBindings(int start, int end, const String& direction);
 
+    auto& weakPtrFactory() const { return m_weakFactory; }
+
 protected:
     HTMLInputElement(const QualifiedName&, Document&, HTMLFormElement*, bool createdByParser);
 
@@ -482,6 +485,7 @@ private:
 #if ENABLE(DATALIST_ELEMENT)
     std::unique_ptr<ListAttributeTargetObserver> m_listAttributeTargetObserver;
 #endif
+    WeakPtrFactory<HTMLInputElement> m_weakFactory;
 };
 
 }
index 69706e2..a882c8f 100644 (file)
@@ -52,12 +52,14 @@ FormControlState HiddenInputType::saveFormControlState() const
 {
     // valueAttributeWasUpdatedAfterParsing() never be true for form controls create by createElement() or cloneNode().
     // It's OK for now because we restore values only to form controls created by parsing.
-    return element().valueAttributeWasUpdatedAfterParsing() ? FormControlState { { element().value() } } : FormControlState { };
+    ASSERT(element());
+    return element()->valueAttributeWasUpdatedAfterParsing() ? FormControlState { { element()->value() } } : FormControlState { };
 }
 
 void HiddenInputType::restoreFormControlState(const FormControlState& state)
 {
-    element().setAttributeWithoutSynchronization(valueAttr, state[0]);
+    ASSERT(element());
+    element()->setAttributeWithoutSynchronization(valueAttr, state[0]);
 }
 
 bool HiddenInputType::supportsValidation() const
@@ -87,7 +89,8 @@ bool HiddenInputType::storesValueSeparateFromAttribute()
 
 void HiddenInputType::setValue(const String& sanitizedValue, bool, TextFieldEventBehavior)
 {
-    element().setAttributeWithoutSynchronization(valueAttr, sanitizedValue);
+    ASSERT(element());
+    element()->setAttributeWithoutSynchronization(valueAttr, sanitizedValue);
 }
 
 bool HiddenInputType::isHiddenType() const
@@ -97,7 +100,8 @@ bool HiddenInputType::isHiddenType() const
 
 bool HiddenInputType::appendFormData(DOMFormData& formData, bool isMultipartForm) const
 {
-    auto name = element().name();
+    ASSERT(element());
+    auto name = element()->name();
 
     if (equalIgnoringASCIICase(name, "_charset_")) {
         formData.append(name, String { formData.encoding().name() });
index 6b5be49..38cd0da 100644 (file)
@@ -56,10 +56,11 @@ bool ImageInputType::isFormDataAppendable() const
 
 bool ImageInputType::appendFormData(DOMFormData& formData, bool) const
 {
-    if (!element().isActivatedSubmit())
+    ASSERT(element());
+    if (!element()->isActivatedSubmit())
         return false;
 
-    auto& name = element().name();
+    auto& name = element()->name();
     if (name.isEmpty()) {
         formData.append(ASCIILiteral("x"), String::number(m_clickLocation.x()));
         formData.append(ASCIILiteral("y"), String::number(m_clickLocation.y()));
@@ -69,7 +70,7 @@ bool ImageInputType::appendFormData(DOMFormData& formData, bool) const
     formData.append(makeString(name, ".x"), String::number(m_clickLocation.x()));
     formData.append(makeString(name, ".y"), String::number(m_clickLocation.y()));
 
-    auto value = element().value();
+    auto value = element()->value();
     if (!value.isEmpty())
         formData.append(name, value);
 
@@ -83,13 +84,14 @@ bool ImageInputType::supportsValidation() const
 
 void ImageInputType::handleDOMActivateEvent(Event& event)
 {
-    Ref<HTMLInputElement> element(this->element());
-    if (element->isDisabledFormControl() || !element->form())
+    ASSERT(element());
+    Ref<HTMLInputElement> protectedElement(*element());
+    if (protectedElement->isDisabledFormControl() || !protectedElement->form())
         return;
 
-    Ref<HTMLFormElement> protectedForm(*element->form());
+    Ref<HTMLFormElement> protectedForm(*protectedElement->form());
 
-    element->setActivatedSubmit(true);
+    protectedElement->setActivatedSubmit(true);
 
     m_clickLocation = IntPoint();
     if (event.underlyingEvent()) {
@@ -103,30 +105,34 @@ void ImageInputType::handleDOMActivateEvent(Event& event)
 
     // Update layout before processing form actions in case the style changes
     // the Form or button relationships.
-    element->document().updateLayoutIgnorePendingStylesheets();
+    protectedElement->document().updateLayoutIgnorePendingStylesheets();
 
-    if (auto currentForm = element->form())
+    if (auto currentForm = protectedElement->form())
         currentForm->prepareForSubmission(event); // Event handlers can run.
 
-    element->setActivatedSubmit(false);
+    protectedElement->setActivatedSubmit(false);
     event.setDefaultHandled();
 }
 
 RenderPtr<RenderElement> ImageInputType::createInputRenderer(RenderStyle&& style)
 {
-    return createRenderer<RenderImage>(element(), WTFMove(style));
+    ASSERT(element());
+    return createRenderer<RenderImage>(*element(), WTFMove(style));
 }
 
 void ImageInputType::attributeChanged(const QualifiedName& name)
 {
     if (name == altAttr) {
-        auto* renderer = element().renderer();
-        if (is<RenderImage>(renderer))
-            downcast<RenderImage>(*renderer).updateAltText();
+        if (auto* element = this->element()) {
+            auto* renderer = element->renderer();
+            if (is<RenderImage>(renderer))
+                downcast<RenderImage>(*renderer).updateAltText();
+        }
     } else if (name == srcAttr) {
-        auto& element = this->element();
-        if (element.renderer())
-            element.ensureImageLoader().updateFromElementIgnoringPreviousError();
+        if (auto* element = this->element()) {
+            if (element->renderer())
+                element->ensureImageLoader().updateFromElementIgnoringPreviousError();
+        }
     }
     BaseButtonInputType::attributeChanged(name);
 }
@@ -135,10 +141,11 @@ void ImageInputType::attach()
 {
     BaseButtonInputType::attach();
 
-    HTMLImageLoader& imageLoader = element().ensureImageLoader();
+    ASSERT(element());
+    HTMLImageLoader& imageLoader = element()->ensureImageLoader();
     imageLoader.updateFromElement();
 
-    auto* renderer = downcast<RenderImage>(element().renderer());
+    auto* renderer = downcast<RenderImage>(element()->renderer());
     if (!renderer)
         return;
 
@@ -181,7 +188,8 @@ bool ImageInputType::shouldRespectHeightAndWidthAttributes()
 
 unsigned ImageInputType::height() const
 {
-    Ref<HTMLInputElement> element(this->element());
+    ASSERT(element());
+    Ref<HTMLInputElement> element(*this->element());
 
     element->document().updateLayout();
 
@@ -202,7 +210,8 @@ unsigned ImageInputType::height() const
 
 unsigned ImageInputType::width() const
 {
-    Ref<HTMLInputElement> element(this->element());
+    ASSERT(element());
+    Ref<HTMLInputElement> element(*this->element());
 
     element->document().updateLayout();
 
index 4853666..9167fe9 100644 (file)
@@ -193,27 +193,31 @@ bool InputType::shouldSaveAndRestoreFormControlState() const
 
 FormControlState InputType::saveFormControlState() const
 {
-    auto currentValue = element().value();
-    if (currentValue == element().defaultValue())
+    ASSERT(element());
+    auto currentValue = element()->value();
+    if (currentValue == element()->defaultValue())
         return { };
     return { { currentValue } };
 }
 
 void InputType::restoreFormControlState(const FormControlState& state)
 {
-    element().setValue(state[0]);
+    ASSERT(element());
+    element()->setValue(state[0]);
 }
 
 bool InputType::isFormDataAppendable() const
 {
+    ASSERT(element());
     // There is no form data unless there's a name for non-image types.
-    return !element().name().isEmpty();
+    return !element()->name().isEmpty();
 }
 
 bool InputType::appendFormData(DOMFormData& formData, bool) const
 {
+    ASSERT(element());
     // Always successful.
-    formData.append(element().name(), element().value());
+    formData.append(element()->name(), element()->value());
     return true;
 }
 
@@ -319,7 +323,8 @@ double InputType::maximum() const
 
 bool InputType::sizeShouldIncludeDecoration(int, int& preferredSize) const
 {
-    preferredSize = element().size();
+    ASSERT(element());
+    preferredSize = element()->size();
     return false;
 }
 
@@ -390,7 +395,8 @@ String InputType::valueMissingText() const
 
 String InputType::validationMessage() const
 {
-    String value = element().value();
+    ASSERT(element());
+    String value = element()->value();
 
     // The order of the following checks is meaningful. e.g. We'd like to show the
     // badInput message even if the control has other validation errors.
@@ -406,11 +412,11 @@ String InputType::validationMessage() const
     if (patternMismatch(value))
         return validationMessagePatternMismatchText();
 
-    if (element().tooShort())
-        return validationMessageTooShortText(numGraphemeClusters(value), element().minLength());
+    if (element()->tooShort())
+        return validationMessageTooShortText(numGraphemeClusters(value), element()->minLength());
 
-    if (element().tooLong())
-        return validationMessageTooLongText(numGraphemeClusters(value), element().effectiveMaxLength());
+    if (element()->tooLong())
+        return validationMessageTooLongText(numGraphemeClusters(value), element()->effectiveMaxLength());
 
     if (!isSteppable())
         return emptyString();
@@ -480,12 +486,14 @@ bool InputType::shouldSubmitImplicitly(Event& event)
 
 RenderPtr<RenderElement> InputType::createInputRenderer(RenderStyle&& style)
 {
-    return RenderPtr<RenderElement>(RenderElement::createFor(element(), WTFMove(style)));
+    ASSERT(element());
+    return RenderPtr<RenderElement>(RenderElement::createFor(*element(), WTFMove(style)));
 }
 
 void InputType::blur()
 {
-    element().defaultBlur();
+    ASSERT(element());
+    element()->defaultBlur();
 }
 
 void InputType::createShadowSubtree()
@@ -494,7 +502,8 @@ void InputType::createShadowSubtree()
 
 void InputType::destroyShadowSubtree()
 {
-    RefPtr<ShadowRoot> root = element().userAgentShadowRoot();
+    ASSERT(element());
+    RefPtr<ShadowRoot> root = element()->userAgentShadowRoot();
     if (!root)
         return;
 
@@ -533,14 +542,16 @@ DateComponents::Type InputType::dateType() const
 
 void InputType::dispatchSimulatedClickIfActive(KeyboardEvent& event) const
 {
-    if (element().active())
-        element().dispatchSimulatedClick(&event);
+    ASSERT(element());
+    if (element()->active())
+        element()->dispatchSimulatedClick(&event);
     event.setDefaultHandled();
 }
 
 Chrome* InputType::chrome() const
 {
-    if (Page* page = element().document().page())
+    ASSERT(element());
+    if (Page* page = element()->document().page())
         return &page->chrome();
     return nullptr;
 }
@@ -557,12 +568,14 @@ bool InputType::hasCustomFocusLogic() const
 
 bool InputType::isKeyboardFocusable(KeyboardEvent* event) const
 {
-    return !element().isReadOnly() && element().isTextFormControlKeyboardFocusable(event);
+    ASSERT(element());
+    return !element()->isReadOnly() && element()->isTextFormControlKeyboardFocusable(event);
 }
 
 bool InputType::isMouseFocusable() const
 {
-    return element().isTextFormControlMouseFocusable();
+    ASSERT(element());
+    return element()->isTextFormControlMouseFocusable();
 }
 
 bool InputType::shouldUseInputMethod() const
@@ -580,7 +593,8 @@ void InputType::handleBlurEvent()
 
 void InputType::accessKeyAction(bool)
 {
-    element().focus(false);
+    ASSERT(element());
+    element()->focus(false);
 }
 
 void InputType::addSearchResult()
@@ -651,17 +665,20 @@ bool InputType::storesValueSeparateFromAttribute()
 
 void InputType::setValue(const String& sanitizedValue, bool valueChanged, TextFieldEventBehavior eventBehavior)
 {
-    element().setValueInternal(sanitizedValue, eventBehavior);
-    element().invalidateStyleForSubtree();
+    ASSERT(element());
+    element()->setValueInternal(sanitizedValue, eventBehavior);
+    element()->invalidateStyleForSubtree();
     if (!valueChanged)
         return;
+
     switch (eventBehavior) {
     case DispatchChangeEvent:
-        element().dispatchFormControlChangeEvent();
+        element()->dispatchFormControlChangeEvent();
         break;
     case DispatchInputAndChangeEvent:
-        element().dispatchFormControlInputEvent();
-        element().dispatchFormControlChangeEvent();
+        element()->dispatchFormControlInputEvent();
+        if (auto element = this->element())
+            element->dispatchFormControlChangeEvent();
         break;
     case DispatchNoEvent:
         break;
@@ -688,7 +705,8 @@ String InputType::localizeValue(const String& proposedValue) const
 
 String InputType::visibleValue() const
 {
-    return element().value();
+    ASSERT(element());
+    return element()->value();
 }
 
 bool InputType::isEmptyValue() const
@@ -944,7 +962,8 @@ ExceptionOr<void> InputType::applyStep(int count, AnyStepHandling anyStepHandlin
     if (!stepRange.hasStep())
         return Exception { InvalidStateError };
 
-    const Decimal current = parseToNumberOrNaN(element().value());
+    ASSERT(element());
+    const Decimal current = parseToNumberOrNaN(element()->value());
     if (!current.isFinite())
         return Exception { InvalidStateError };
     Decimal newValue = current + stepRange.step() * count;
@@ -957,7 +976,7 @@ ExceptionOr<void> InputType::applyStep(int count, AnyStepHandling anyStepHandlin
     if (newValue < stepRange.minimum())
         newValue = stepRange.minimum();
 
-    if (!equalLettersIgnoringASCIICase(element().attributeWithoutSynchronization(stepAttr), "any"))
+    if (!equalLettersIgnoringASCIICase(element()->attributeWithoutSynchronization(stepAttr), "any"))
         newValue = stepRange.alignValueForStep(current, newValue);
 
     if (newValue - stepRange.maximum() > acceptableErrorValue)
@@ -969,8 +988,8 @@ ExceptionOr<void> InputType::applyStep(int count, AnyStepHandling anyStepHandlin
     if (result.hasException())
         return result;
 
-    if (AXObjectCache* cache = element().document().existingAXObjectCache())
-        cache->postNotification(&element(), AXObjectCache::AXValueChanged);
+    if (AXObjectCache* cache = element()->document().existingAXObjectCache())
+        cache->postNotification(element(), AXObjectCache::AXValueChanged);
 
     return result;
 }
@@ -1057,7 +1076,8 @@ void InputType::stepUpFromRenderer(int n)
     else
         sign = 0;
 
-    String currentStringValue = element().value();
+    ASSERT(element());
+    String currentStringValue = element()->value();
     Decimal current = parseToNumberOrNaN(currentStringValue);
     if (!current.isFinite()) {
         current = defaultValueForStepUp();
@@ -1071,7 +1091,7 @@ void InputType::stepUpFromRenderer(int n)
     if ((sign > 0 && current < stepRange.minimum()) || (sign < 0 && current > stepRange.maximum()))
         setValueAsDecimal(sign > 0 ? stepRange.minimum() : stepRange.maximum(), DispatchInputAndChangeEvent);
     else {
-        if (stepMismatch(element().value())) {
+        if (stepMismatch(element()->value())) {
             ASSERT(!step.isZero());
             const Decimal base = stepRange.stepBase();
             Decimal newValue;
index f6c9af1..c994cce 100644 (file)
@@ -304,8 +304,9 @@ public:
     virtual String displayString() const;
 
 protected:
-    explicit InputType(HTMLInputElement& element) : m_element(element) { }
-    HTMLInputElement& element() const { return m_element; }
+    explicit InputType(HTMLInputElement& element)
+        : m_element(makeWeakPtr(element)) { }
+    HTMLInputElement* element() const { return m_element.get(); }
     Chrome* chrome() const;
     Decimal parseToNumberOrNaN(const String&) const;
 
@@ -314,7 +315,7 @@ private:
     ExceptionOr<void> applyStep(int count, AnyStepHandling, TextFieldEventBehavior);
 
     // Raw pointer because the HTMLInputElement object owns this InputType object.
-    HTMLInputElement& m_element;
+    WeakPtr<HTMLInputElement> m_element;
 };
 
 } // namespace WebCore
index 7bfce3f..3a92afc 100644 (file)
@@ -93,14 +93,16 @@ const AtomicString& NumberInputType::formControlType() const
 
 void NumberInputType::setValue(const String& sanitizedValue, bool valueChanged, TextFieldEventBehavior eventBehavior)
 {
-    if (!valueChanged && sanitizedValue.isEmpty() && !element().innerTextValue().isEmpty())
+    ASSERT(element());
+    if (!valueChanged && sanitizedValue.isEmpty() && !element()->innerTextValue().isEmpty())
         updateInnerTextValue();
     TextFieldInputType::setValue(sanitizedValue, valueChanged, eventBehavior);
 }
 
 double NumberInputType::valueAsDouble() const
 {
-    return parseToDoubleForNumberType(element().value());
+    ASSERT(element());
+    return parseToDoubleForNumberType(element()->value());
 }
 
 ExceptionOr<void> NumberInputType::setValueAsDouble(double newValue, TextFieldEventBehavior eventBehavior) const
@@ -109,7 +111,8 @@ ExceptionOr<void> NumberInputType::setValueAsDouble(double newValue, TextFieldEv
     const double floatMax = std::numeric_limits<float>::max();
     if (newValue < -floatMax || newValue > floatMax)
         return Exception { InvalidStateError };
-    element().setValue(serializeForNumberType(newValue), eventBehavior);
+    ASSERT(element());
+    element()->setValue(serializeForNumberType(newValue), eventBehavior);
     return { };
 }
 
@@ -119,7 +122,8 @@ ExceptionOr<void> NumberInputType::setValueAsDecimal(const Decimal& newValue, Te
     const Decimal floatMax = Decimal::fromDouble(std::numeric_limits<float>::max());
     if (newValue < -floatMax || newValue > floatMax)
         return Exception { InvalidStateError };
-    element().setValue(serializeForNumberType(newValue), eventBehavior);
+    ASSERT(element());
+    element()->setValue(serializeForNumberType(newValue), eventBehavior);
     return { };
 }
 
@@ -130,17 +134,20 @@ bool NumberInputType::typeMismatchFor(const String& value) const
 
 bool NumberInputType::typeMismatch() const
 {
-    ASSERT(!typeMismatchFor(element().value()));
+    ASSERT(element());
+    ASSERT(!typeMismatchFor(element()->value()));
     return false;
 }
 
 StepRange NumberInputType::createStepRange(AnyStepHandling anyStepHandling) const
 {
     static NeverDestroyed<const StepRange::StepDescription> stepDescription(numberDefaultStep, numberDefaultStepBase, numberStepScaleFactor);
-    const Decimal stepBase = parseToDecimalForNumberType(element().attributeWithoutSynchronization(minAttr), numberDefaultStepBase);
+
+    ASSERT(element());
+    const Decimal stepBase = parseToDecimalForNumberType(element()->attributeWithoutSynchronization(minAttr), numberDefaultStepBase);
     // FIXME: We should use numeric_limits<double>::max for number input type.
     const Decimal floatMax = Decimal::fromDouble(std::numeric_limits<float>::max());
-    const Element& element = this->element();
+    const Element& element = *this->element();
 
     RangeLimitations rangeLimitations = RangeLimitations::Invalid;
     auto extractBound = [&] (const QualifiedName& attributeName, const Decimal& defaultValue) -> Decimal {
@@ -163,15 +170,16 @@ bool NumberInputType::sizeShouldIncludeDecoration(int defaultSize, int& preferre
 {
     preferredSize = defaultSize;
 
-    auto& stepString = element().attributeWithoutSynchronization(stepAttr);
+    ASSERT(element());
+    auto& stepString = element()->attributeWithoutSynchronization(stepAttr);
     if (equalLettersIgnoringASCIICase(stepString, "any"))
         return false;
 
-    const Decimal minimum = parseToDecimalForNumberType(element().attributeWithoutSynchronization(minAttr));
+    const Decimal minimum = parseToDecimalForNumberType(element()->attributeWithoutSynchronization(minAttr));
     if (!minimum.isFinite())
         return false;
 
-    const Decimal maximum = parseToDecimalForNumberType(element().attributeWithoutSynchronization(maxAttr));
+    const Decimal maximum = parseToDecimalForNumberType(element()->attributeWithoutSynchronization(maxAttr));
     if (!maximum.isFinite())
         return false;
 
@@ -187,8 +195,10 @@ bool NumberInputType::sizeShouldIncludeDecoration(int defaultSize, int& preferre
 
 float NumberInputType::decorationWidth() const
 {
+    ASSERT(element());
+
     float width = 0;
-    RefPtr<HTMLElement> spinButton = element().innerSpinButtonElement();
+    RefPtr<HTMLElement> spinButton = element()->innerSpinButtonElement();
     if (RenderBox* spinRenderer = spinButton ? spinButton->renderBox() : 0) {
         width += spinRenderer->borderAndPaddingLogicalWidth();
         // Since the width of spinRenderer is not calculated yet, spinRenderer->logicalWidth() returns 0.
@@ -234,12 +244,14 @@ String NumberInputType::localizeValue(const String& proposedValue) const
     // We don't localize scientific notations.
     if (proposedValue.find(isE) != notFound)
         return proposedValue;
-    return element().locale().convertToLocalizedNumber(proposedValue);
+    ASSERT(element());
+    return element()->locale().convertToLocalizedNumber(proposedValue);
 }
 
 String NumberInputType::visibleValue() const
 {
-    return localizeValue(element().value());
+    ASSERT(element());
+    return localizeValue(element()->value());
 }
 
 String NumberInputType::convertFromVisibleValue(const String& visibleValue) const
@@ -249,7 +261,8 @@ String NumberInputType::convertFromVisibleValue(const String& visibleValue) cons
     // We don't localize scientific notations.
     if (visibleValue.find(isE) != notFound)
         return visibleValue;
-    return element().locale().convertFromLocalizedNumber(visibleValue);
+    ASSERT(element());
+    return element()->locale().convertFromLocalizedNumber(visibleValue);
 }
 
 String NumberInputType::sanitizeValue(const String& proposedValue) const
@@ -261,7 +274,8 @@ String NumberInputType::sanitizeValue(const String& proposedValue) const
 
 bool NumberInputType::hasBadInput() const
 {
-    String standardValue = convertFromVisibleValue(element().innerTextValue());
+    ASSERT(element());
+    String standardValue = convertFromVisibleValue(element()->innerTextValue());
     return !standardValue.isEmpty() && !std::isfinite(parseToDoubleForNumberType(standardValue));
 }
 
@@ -282,14 +296,18 @@ bool NumberInputType::isNumberField() const
 
 void NumberInputType::attributeChanged(const QualifiedName& name)
 {
+    ASSERT(element());
     if (name == maxAttr || name == minAttr) {
-        auto& element = this->element();
-        element.invalidateStyleForSubtree();
-        if (auto* renderer = element.renderer())
-            renderer->setNeedsLayoutAndPrefWidthsRecalc();
+        if (auto* element = this->element()) {
+            element->invalidateStyleForSubtree();
+            if (auto* renderer = element->renderer())
+                renderer->setNeedsLayoutAndPrefWidthsRecalc();
+        }
     } else if (name == stepAttr) {
-        if (auto* renderer = element().renderer())
-        renderer->setNeedsLayoutAndPrefWidthsRecalc();
+        if (auto* element = this->element()) {
+            if (auto* renderer = element->renderer())
+                renderer->setNeedsLayoutAndPrefWidthsRecalc();
+        }
     }
     TextFieldInputType::attributeChanged(name);
 }
index 4b1d6d5..c11f6c9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2005, 2011, 2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2005-2018 Apple Inc. All rights reserved.
  * Copyright (C) 2010 Google Inc. All rights reserved.
  *
  * This library is free software; you can redistribute it and/or
@@ -44,7 +44,8 @@ const AtomicString& RadioInputType::formControlType() const
 
 bool RadioInputType::valueMissing(const String&) const
 {
-    return element().isInRequiredRadioButtonGroup() && !element().checkedRadioButtonForGroup();
+    ASSERT(element());
+    return element()->isInRequiredRadioButtonGroup() && !element()->checkedRadioButtonForGroup();
 }
 
 String RadioInputType::valueMissingText() const
@@ -66,18 +67,19 @@ void RadioInputType::handleKeydownEvent(KeyboardEvent& event)
     if (key != "Up" && key != "Down" && key != "Left" && key != "Right")
         return;
 
+    ASSERT(element());
     // Left and up mean "previous radio button".
     // Right and down mean "next radio button".
     // Tested in WinIE, and even for RTL, left still means previous radio button (and so moves
     // to the right).  Seems strange, but we'll match it.
     // However, when using Spatial Navigation, we need to be able to navigate without changing the selection.
-    if (isSpatialNavigationEnabled(element().document().frame()))
+    if (isSpatialNavigationEnabled(element()->document().frame()))
         return;
     bool forward = (key == "Down" || key == "Right");
 
     // We can only stay within the form's children if the form hasn't been demoted to a leaf because
     // of malformed HTML.
-    RefPtr<Node> node = &element();
+    RefPtr<Node> node = element();
     while ((node = (forward ? NodeTraversal::next(*node) : NodeTraversal::previous(*node)))) {
         // Once we encounter a form element, we know we're through.
         if (is<HTMLFormElement>(*node))
@@ -86,10 +88,10 @@ void RadioInputType::handleKeydownEvent(KeyboardEvent& event)
         if (!is<HTMLInputElement>(*node))
             continue;
         RefPtr<HTMLInputElement> inputElement = downcast<HTMLInputElement>(node.get());
-        if (inputElement->form() != element().form())
+        if (inputElement->form() != element()->form())
             break;
-        if (inputElement->isRadioButton() && inputElement->name() == element().name() && inputElement->isFocusable()) {
-            element().document().setFocusedElement(inputElement.get());
+        if (inputElement->isRadioButton() && inputElement->name() == element()->name() && inputElement->isFocusable()) {
+            element()->document().setFocusedElement(inputElement.get());
             inputElement->dispatchSimulatedClick(&event, SendNoEvents, DoNotShowPressedLook);
             event.setDefaultHandled();
             return;
@@ -102,9 +104,11 @@ void RadioInputType::handleKeyupEvent(KeyboardEvent& event)
     const String& key = event.keyIdentifier();
     if (key != "U+0020")
         return;
+
+    ASSERT(element());
     // If an unselected radio is tabbed into (because the entire group has nothing
     // checked, or because of some explicit .focus() call), then allow space to check it.
-    if (element().checked())
+    if (element()->checked())
         return;
     dispatchSimulatedClickIfActive(event);
 }
@@ -114,32 +118,35 @@ bool RadioInputType::isKeyboardFocusable(KeyboardEvent* event) const
     if (!InputType::isKeyboardFocusable(event))
         return false;
 
+    ASSERT(element());
     // When using Spatial Navigation, every radio button should be focusable.
-    if (isSpatialNavigationEnabled(element().document().frame()))
+    if (isSpatialNavigationEnabled(element()->document().frame()))
         return true;
 
     // Never allow keyboard tabbing to leave you in the same radio group.  Always
     // skip any other elements in the group.
-    RefPtr<Element> currentFocusedNode = element().document().focusedElement();
+    RefPtr<Element> currentFocusedNode = element()->document().focusedElement();
     if (is<HTMLInputElement>(currentFocusedNode)) {
         HTMLInputElement& focusedInput = downcast<HTMLInputElement>(*currentFocusedNode);
-        if (focusedInput.isRadioButton() && focusedInput.form() == element().form() && focusedInput.name() == element().name())
+        if (focusedInput.isRadioButton() && focusedInput.form() == element()->form() && focusedInput.name() == element()->name())
             return false;
     }
 
     // Allow keyboard focus if we're checked or if nothing in the group is checked.
-    return element().checked() || !element().checkedRadioButtonForGroup();
+    return element()->checked() || !element()->checkedRadioButtonForGroup();
 }
 
 bool RadioInputType::shouldSendChangeEventAfterCheckedChanged()
 {
     // Don't send a change event for a radio button that's getting unchecked.
     // This was done to match the behavior of other browsers.
-    return element().checked();
+    ASSERT(element());
+    return element()->checked();
 }
 
 void RadioInputType::willDispatchClick(InputElementClickState& state)
 {
+    ASSERT(element());
     // An event handler can use preventDefault or "return false" to reverse the selection we do here.
     // The InputElementClickState object contains what we need to undo what we did here in didDispatchClick.
 
@@ -147,10 +154,10 @@ void RadioInputType::willDispatchClick(InputElementClickState& state)
     // Therefore if nothing is currently selected, we won't allow the upcoming action to be "undone", since
     // we want some object in the radio group to actually get selected.
 
-    state.checked = element().checked();
-    state.checkedRadioButton = element().checkedRadioButtonForGroup();
+    state.checked = element()->checked();
+    state.checkedRadioButton = element()->checkedRadioButtonForGroup();
 
-    element().setChecked(true, DispatchChangeEvent);
+    element()->setChecked(true, DispatchChangeEvent);
 }
 
 void RadioInputType::didDispatchClick(Event& event, const InputElementClickState& state)
@@ -159,7 +166,8 @@ void RadioInputType::didDispatchClick(Event& event, const InputElementClickState
         // Restore the original selected radio button if possible.
         // Make sure it is still a radio button and only do the restoration if it still belongs to our group.
         auto& button = state.checkedRadioButton;
-        if (button && button->isRadioButton() && button->form() == element().form() && button->name() == element().name())
+        ASSERT(element());
+        if (button && button->isRadioButton() && button->form() == element()->form() && button->name() == element()->name())
             button->setChecked(true);
     }
 
@@ -174,7 +182,8 @@ bool RadioInputType::isRadioButton() const
 
 bool RadioInputType::matchesIndeterminatePseudoClass() const
 {
-    const HTMLInputElement& element = this->element();
+    ASSERT(element());
+    const HTMLInputElement& element = *this->element();
     if (const RadioButtonGroups* radioButtonGroups = element.radioButtonGroups())
         return !radioButtonGroups->hasCheckedButton(&element);
     return !element.checked();
index cc14441..2759558 100644 (file)
@@ -92,12 +92,14 @@ const AtomicString& RangeInputType::formControlType() const
 
 double RangeInputType::valueAsDouble() const
 {
-    return parseToDoubleForNumberType(element().value());
+    ASSERT(element());
+    return parseToDoubleForNumberType(element()->value());
 }
 
 ExceptionOr<void> RangeInputType::setValueAsDecimal(const Decimal& newValue, TextFieldEventBehavior eventBehavior) const
 {
-    element().setValue(serialize(newValue), eventBehavior);
+    ASSERT(element());
+    element()->setValue(serialize(newValue), eventBehavior);
     return { };
 }
 
@@ -115,16 +117,17 @@ StepRange RangeInputType::createStepRange(AnyStepHandling anyStepHandling) const
 {
     static NeverDestroyed<const StepRange::StepDescription> stepDescription(rangeDefaultStep, rangeDefaultStepBase, rangeStepScaleFactor);
 
-    const Decimal minimum = parseToNumber(element().attributeWithoutSynchronization(minAttr), rangeDefaultMinimum);
-    const Decimal maximum = ensureMaximum(parseToNumber(element().attributeWithoutSynchronization(maxAttr), rangeDefaultMaximum), minimum, rangeDefaultMaximum);
+    ASSERT(element());
+    const Decimal minimum = parseToNumber(element()->attributeWithoutSynchronization(minAttr), rangeDefaultMinimum);
+    const Decimal maximum = ensureMaximum(parseToNumber(element()->attributeWithoutSynchronization(maxAttr), rangeDefaultMaximum), minimum, rangeDefaultMaximum);
 
-    const AtomicString& precisionValue = element().attributeWithoutSynchronization(precisionAttr);
+    const AtomicString& precisionValue = element()->attributeWithoutSynchronization(precisionAttr);
     if (!precisionValue.isNull()) {
         const Decimal step = equalLettersIgnoringASCIICase(precisionValue, "float") ? Decimal::nan() : 1;
         return StepRange(minimum, RangeLimitations::Valid, minimum, maximum, step, stepDescription);
     }
 
-    const Decimal step = StepRange::parseStep(anyStepHandling, stepDescription, element().attributeWithoutSynchronization(stepAttr));
+    const Decimal step = StepRange::parseStep(anyStepHandling, stepDescription, element()->attributeWithoutSynchronization(stepAttr));
     return StepRange(minimum, RangeLimitations::Valid, minimum, maximum, step, stepDescription);
 }
 
@@ -137,14 +140,15 @@ bool RangeInputType::isSteppable() const
 
 void RangeInputType::handleMouseDownEvent(MouseEvent& event)
 {
-    if (element().isDisabledFormControl())
+    ASSERT(element());
+    if (element()->isDisabledFormControl())
         return;
 
     if (event.button() != LeftButton || !is<Node>(event.target()))
         return;
-    ASSERT(element().shadowRoot());
+    ASSERT(element()->shadowRoot());
     auto& targetNode = downcast<Node>(*event.target());
-    if (&targetNode != &element() && !targetNode.isDescendantOf(element().userAgentShadowRoot().get()))
+    if (&targetNode != element() && !targetNode.isDescendantOf(element()->userAgentShadowRoot().get()))
         return;
     auto& thumb = typedSliderThumbElement();
     if (&targetNode == &thumb)
@@ -160,7 +164,8 @@ void RangeInputType::handleTouchEvent(TouchEvent& event)
 #if PLATFORM(IOS)
     typedSliderThumbElement().handleTouchEvent(event);
 #elif ENABLE(TOUCH_SLIDER)
-    if (element().isDisabledFormControl())
+    ASSERT(element());
+    if (element()->isDisabledFormControl())
         return;
 
     if (event.type() == eventNames().touchendEvent) {
@@ -193,12 +198,13 @@ void RangeInputType::disabledStateChanged()
 
 void RangeInputType::handleKeydownEvent(KeyboardEvent& event)
 {
-    if (element().isDisabledFormControl())
+    ASSERT(element());
+    if (element()->isDisabledFormControl())
         return;
 
     const String& key = event.keyIdentifier();
 
-    const Decimal current = parseToNumberOrNaN(element().value());
+    const Decimal current = parseToNumberOrNaN(element()->value());
     ASSERT(current.isFinite());
 
     StepRange stepRange(createStepRange(RejectAny));
@@ -206,12 +212,12 @@ void RangeInputType::handleKeydownEvent(KeyboardEvent& event)
 
     // FIXME: We can't use stepUp() for the step value "any". So, we increase
     // or decrease the value by 1/100 of the value range. Is it reasonable?
-    const Decimal step = equalLettersIgnoringASCIICase(element().attributeWithoutSynchronization(stepAttr), "any") ? (stepRange.maximum() - stepRange.minimum()) / 100 : stepRange.step();
+    const Decimal step = equalLettersIgnoringASCIICase(element()->attributeWithoutSynchronization(stepAttr), "any") ? (stepRange.maximum() - stepRange.minimum()) / 100 : stepRange.step();
     const Decimal bigStep = std::max((stepRange.maximum() - stepRange.minimum()) / 10, step);
 
     bool isVertical = false;
-    if (element().renderer()) {
-        ControlPart part = element().renderer()->style().appearance();
+    if (auto* renderer = element()->renderer()) {
+        ControlPart part = renderer->style().appearance();
         isVertical = part == SliderVerticalPart || part == MediaVolumeSliderPart;
     }
 
@@ -241,8 +247,8 @@ void RangeInputType::handleKeydownEvent(KeyboardEvent& event)
         EventQueueScope scope;
         setValueAsDecimal(newValue, DispatchInputAndChangeEvent);
 
-        if (AXObjectCache* cache = element().document().existingAXObjectCache())
-            cache->postNotification(&element(), AXObjectCache::AXValueChanged);
+        if (AXObjectCache* cache = element()->document().existingAXObjectCache())
+            cache->postNotification(element(), AXObjectCache::AXValueChanged);
     }
 
     event.setDefaultHandled();
@@ -250,25 +256,27 @@ void RangeInputType::handleKeydownEvent(KeyboardEvent& event)
 
 void RangeInputType::createShadowSubtree()
 {
-    ASSERT(element().userAgentShadowRoot());
+    ASSERT(element());
+    ASSERT(element()->userAgentShadowRoot());
 
-    Document& document = element().document();
+    Document& document = element()->document();
     auto track = HTMLDivElement::create(document);
     track->setPseudo(AtomicString("-webkit-slider-runnable-track", AtomicString::ConstructFromLiteral));
     track->appendChild(SliderThumbElement::create(document));
     auto container = SliderContainerElement::create(document);
     container->appendChild(track);
-    element().userAgentShadowRoot()->appendChild(container);
+    element()->userAgentShadowRoot()->appendChild(container);
 }
 
 HTMLElement* RangeInputType::sliderTrackElement() const
 {
-    ASSERT(element().userAgentShadowRoot());
-    ASSERT(element().userAgentShadowRoot()->firstChild()); // container
-    ASSERT(element().userAgentShadowRoot()->firstChild()->isHTMLElement());
-    ASSERT(element().userAgentShadowRoot()->firstChild()->firstChild()); // track
+    ASSERT(element());
+    ASSERT(element()->userAgentShadowRoot());
+    ASSERT(element()->userAgentShadowRoot()->firstChild()); // container
+    ASSERT(element()->userAgentShadowRoot()->firstChild()->isHTMLElement());
+    ASSERT(element()->userAgentShadowRoot()->firstChild()->firstChild()); // track
 
-    RefPtr<ShadowRoot> root = element().userAgentShadowRoot();
+    RefPtr<ShadowRoot> root = element()->userAgentShadowRoot();
     if (!root)
         return nullptr;
     
@@ -294,7 +302,8 @@ HTMLElement* RangeInputType::sliderThumbElement() const
 
 RenderPtr<RenderElement> RangeInputType::createInputRenderer(RenderStyle&& style)
 {
-    return createRenderer<RenderSlider>(element(), WTFMove(style));
+    ASSERT(element());
+    return createRenderer<RenderSlider>(*element(), WTFMove(style));
 }
 
 Decimal RangeInputType::parseToNumber(const String& src, const Decimal& defaultValue) const
@@ -314,7 +323,8 @@ void RangeInputType::accessKeyAction(bool sendMouseEvents)
 {
     InputType::accessKeyAction(sendMouseEvents);
 
-    element().dispatchSimulatedClick(0, sendMouseEvents ? SendMouseUpDownEvents : SendNoEvents);
+    ASSERT(element());
+    element()->dispatchSimulatedClick(0, sendMouseEvents ? SendMouseUpDownEvents : SendNoEvents);
 }
 
 void RangeInputType::attributeChanged(const QualifiedName& name)
@@ -322,10 +332,10 @@ void RangeInputType::attributeChanged(const QualifiedName& name)
     // FIXME: Don't we need to do this work for precisionAttr too?
     if (name == maxAttr || name == minAttr) {
         // Sanitize the value.
-        auto& element = this->element();
-        if (element.hasDirtyValue())
-            element.setValue(element.value());
-
+        if (auto* element = this->element()) {
+            if (element->hasDirtyValue())
+                element->setValue(element->value());
+        }
         typedSliderThumbElement().setPositionFromValue();
     }
     InputType::attributeChanged(name);
@@ -338,8 +348,10 @@ void RangeInputType::setValue(const String& value, bool valueChanged, TextFieldE
     if (!valueChanged)
         return;
 
-    if (eventBehavior == DispatchNoEvent)
-        element().setTextAsOfLastFormControlChangeEvent(value);
+    if (eventBehavior == DispatchNoEvent) {
+        ASSERT(element());
+        element()->setTextAsOfLastFormControlChangeEvent(value);
+    }
 
     typedSliderThumbElement().setPositionFromValue();
 }
@@ -376,7 +388,8 @@ void RangeInputType::updateTickMarkValues()
         return;
     m_tickMarkValues.clear();
     m_tickMarkValuesDirty = false;
-    auto dataList = element().dataList();
+    ASSERT(element());
+    auto dataList = element()->dataList();
     if (!dataList)
         return;
     Ref<HTMLCollection> options = dataList->options();
@@ -385,7 +398,7 @@ void RangeInputType::updateTickMarkValues()
         RefPtr<Node> node = options->item(i);
         HTMLOptionElement& optionElement = downcast<HTMLOptionElement>(*node);
         String optionValue = optionElement.value();
-        if (!element().isValidValue(optionValue))
+        if (!element()->isValidValue(optionValue))
             continue;
         m_tickMarkValues.append(parseToNumber(optionValue, Decimal::nan()));
     }
index 016fe10..405cb2c 100644 (file)
@@ -52,9 +52,10 @@ bool ResetInputType::supportsValidation() const
 
 void ResetInputType::handleDOMActivateEvent(Event& event)
 {
-    if (element().isDisabledFormControl() || !element().form())
+    ASSERT(element());
+    if (element()->isDisabledFormControl() || !element()->form())
         return;
-    element().form()->reset();
+    element()->form()->reset();
     event.setDefaultHandled();
 }
 
index c9fd228..7124391 100644 (file)
@@ -56,8 +56,9 @@ void SearchInputType::addSearchResult()
     // Normally we've got the correct renderer by the time we get here. However when the input type changes
     // we don't update the associated renderers until after the next tree update, so we could actually end up here
     // with a mismatched renderer (e.g. through form submission).
-    if (is<RenderSearchField>(element().renderer()))
-        downcast<RenderSearchField>(*element().renderer()).addSearchResult();
+    ASSERT(element());
+    if (is<RenderSearchField>(element()->renderer()))
+        downcast<RenderSearchField>(*element()->renderer()).addSearchResult();
 #endif
 }
 
@@ -74,15 +75,18 @@ static void updateResultButtonPseudoType(SearchFieldResultsButtonElement& result
 void SearchInputType::attributeChanged(const QualifiedName& name)
 {
     if (name == resultsAttr) {
-        if (m_resultsButton)
-            updateResultButtonPseudoType(*m_resultsButton, element().maxResults());
+        if (m_resultsButton) {
+            if (auto* element = this->element())
+                updateResultButtonPseudoType(*m_resultsButton, element->maxResults());
+        }
     }
     BaseTextInputType::attributeChanged(name);
 }
 
 RenderPtr<RenderElement> SearchInputType::createInputRenderer(RenderStyle&& style)
 {
-    return createRenderer<RenderSearchField>(element(), WTFMove(style));
+    ASSERT(element());
+    return createRenderer<RenderSearchField>(*element(), WTFMove(style));
 }
 
 const AtomicString& SearchInputType::formControlType() const
@@ -111,11 +115,12 @@ void SearchInputType::createShadowSubtree()
     ASSERT(container);
     ASSERT(textWrapper);
 
-    m_resultsButton = SearchFieldResultsButtonElement::create(element().document());
-    updateResultButtonPseudoType(*m_resultsButton, element().maxResults());
+    ASSERT(element());
+    m_resultsButton = SearchFieldResultsButtonElement::create(element()->document());
+    updateResultButtonPseudoType(*m_resultsButton, element()->maxResults());
     container->insertBefore(*m_resultsButton, textWrapper.get());
 
-    m_cancelButton = SearchFieldCancelButtonElement::create(element().document());
+    m_cancelButton = SearchFieldCancelButtonElement::create(element()->document());
     container->insertBefore(*m_cancelButton, textWrapper->nextSibling());
 }
 
@@ -131,16 +136,17 @@ HTMLElement* SearchInputType::cancelButtonElement() const
 
 void SearchInputType::handleKeydownEvent(KeyboardEvent& event)
 {
-    if (element().isDisabledOrReadOnly()) {
+    ASSERT(element());
+    if (element()->isDisabledOrReadOnly()) {
         TextFieldInputType::handleKeydownEvent(event);
         return;
     }
 
     const String& key = event.keyIdentifier();
     if (key == "U+001B") {
-        Ref<HTMLInputElement> input(this->element());
-        input->setValueForUser(emptyString());
-        input->onSearch();
+        Ref<HTMLInputElement> protectedInputElement(*element());
+        protectedInputElement->setValueForUser(emptyString());
+        protectedInputElement->onSearch();
         event.setDefaultHandled();
         return;
     }
@@ -156,8 +162,9 @@ void SearchInputType::destroyShadowSubtree()
 
 void SearchInputType::startSearchEventTimer()
 {
-    ASSERT(element().renderer());
-    unsigned length = element().innerTextValue().length();
+    ASSERT(element());
+    ASSERT(element()->renderer());
+    unsigned length = element()->innerTextValue().length();
 
     if (!length) {
         m_searchEventTimer.startOneShot(0_ms);
@@ -176,18 +183,21 @@ void SearchInputType::stopSearchEventTimer()
 
 void SearchInputType::searchEventTimerFired()
 {
-    element().onSearch();
+    ASSERT(element());
+    element()->onSearch();
 }
 
 bool SearchInputType::searchEventsShouldBeDispatched() const
 {
-    return element().hasAttributeWithoutSynchronization(incrementalAttr);
+    ASSERT(element());
+    return element()->hasAttributeWithoutSynchronization(incrementalAttr);
 }
 
 void SearchInputType::didSetValueByUserEdit()
 {
-    if (m_cancelButton && is<RenderSearchField>(element().renderer()))
-        downcast<RenderSearchField>(*element().renderer()).updateCancelButtonVisibility();
+    ASSERT(element());
+    if (m_cancelButton && is<RenderSearchField>(element()->renderer()))
+        downcast<RenderSearchField>(*element()->renderer()).updateCancelButtonVisibility();
     // If the incremental attribute is set, then dispatch the search event
     if (searchEventsShouldBeDispatched())
         startSearchEventTimer();
@@ -197,7 +207,8 @@ void SearchInputType::didSetValueByUserEdit()
 
 bool SearchInputType::sizeShouldIncludeDecoration(int, int& preferredSize) const
 {
-    preferredSize = element().size();
+    ASSERT(element());
+    preferredSize = element()->size();
     return true;
 }
 
index dc33983..1b1ea08 100644 (file)
@@ -48,9 +48,10 @@ const AtomicString& SubmitInputType::formControlType() const
 
 bool SubmitInputType::appendFormData(DOMFormData& formData, bool) const
 {
-    if (!element().isActivatedSubmit())
+    ASSERT(element());
+    if (!element()->isActivatedSubmit())
         return false;
-    formData.append(element().name(), element().valueWithDefault());
+    formData.append(element()->name(), element()->valueWithDefault());
     return true;
 }
 
@@ -61,20 +62,21 @@ bool SubmitInputType::supportsRequired() const
 
 void SubmitInputType::handleDOMActivateEvent(Event& event)
 {
-    Ref<HTMLInputElement> element(this->element());
-    if (element->isDisabledFormControl() || !element->form())
+    ASSERT(element());
+    Ref<HTMLInputElement> protectedElement(*element());
+    if (protectedElement->isDisabledFormControl() || !protectedElement->form())
         return;
 
-    Ref<HTMLFormElement> protectedForm(*element->form());
+    Ref<HTMLFormElement> protectedForm(*protectedElement->form());
 
     // Update layout before processing form actions in case the style changes
     // the Form or button relationships.
-    element->document().updateLayoutIgnorePendingStylesheets();
+    protectedElement->document().updateLayoutIgnorePendingStylesheets();
 
-    element->setActivatedSubmit(true);
-    if (auto currentForm = element->form())
+    protectedElement->setActivatedSubmit(true);
+    if (auto currentForm = protectedElement->form())
         currentForm->prepareForSubmission(event); // Event handlers can run.
-    element->setActivatedSubmit(false);
+    protectedElement->setActivatedSubmit(false);
     event.setDefaultHandled();
 }
 
index 1faeb51..dc054fe 100644 (file)
@@ -75,16 +75,18 @@ TextFieldInputType::~TextFieldInputType()
 
 bool TextFieldInputType::isKeyboardFocusable(KeyboardEvent*) const
 {
+    ASSERT(element());
 #if PLATFORM(IOS)
-    if (element().isReadOnly())
+    if (element()->isReadOnly())
         return false;
 #endif
-    return element().isTextFormControlFocusable();
+    return element()->isTextFormControlFocusable();
 }
 
 bool TextFieldInputType::isMouseFocusable() const
 {
-    return element().isTextFormControlFocusable();
+    ASSERT(element());
+    return element()->isTextFormControlFocusable();
 }
 
 bool TextFieldInputType::isTextField() const
@@ -106,14 +108,17 @@ bool TextFieldInputType::isEmptyValue() const
 
 bool TextFieldInputType::valueMissing(const String& value) const
 {
-    return element().isRequired() && value.isEmpty();
+    ASSERT(element());
+    return element()->isRequired() && value.isEmpty();
 }
 
 void TextFieldInputType::setValue(const String& sanitizedValue, bool valueChanged, TextFieldEventBehavior eventBehavior)
 {
+    ASSERT(element());
+
     // Grab this input element to keep reference even if JS event handler
     // changes input type.
-    Ref<HTMLInputElement> input(element());
+    Ref<HTMLInputElement> input(*element());
 
     // We don't ask InputType::setValue to dispatch events because
     // TextFieldInputType dispatches events different way from InputType.
@@ -158,17 +163,19 @@ void TextFieldInputType::setValue(const String& sanitizedValue, bool valueChange
 
 void TextFieldInputType::handleKeydownEvent(KeyboardEvent& event)
 {
-    if (!element().focused())
+    ASSERT(element());
+    if (!element()->focused())
         return;
-    RefPtr<Frame> frame = element().document().frame();
-    if (!frame || !frame->editor().doTextFieldCommandFromEvent(&element(), &event))
+    RefPtr<Frame> frame = element()->document().frame();
+    if (!frame || !frame->editor().doTextFieldCommandFromEvent(element(), &event))
         return;
     event.setDefaultHandled();
 }
 
 void TextFieldInputType::handleKeydownEventForSpinButton(KeyboardEvent& event)
 {
-    if (element().isDisabledOrReadOnly())
+    ASSERT(element());
+    if (element()->isDisabledOrReadOnly())
         return;
     const String& key = event.keyIdentifier();
     if (key == "Up")
@@ -192,13 +199,16 @@ void TextFieldInputType::forwardEvent(Event& event)
     bool isBlurEvent = event.type() == eventNames().blurEvent;
     if (isFocusEvent || isBlurEvent)
         capsLockStateMayHaveChanged();
-    if (event.isMouseEvent() || isFocusEvent || isBlurEvent)
-        element().forwardEvent(event);
+    if (event.isMouseEvent() || isFocusEvent || isBlurEvent) {
+        ASSERT(element());
+        element()->forwardEvent(event);
+    }
 }
 
 void TextFieldInputType::elementDidBlur()
 {
-    auto* renderer = element().renderer();
+    ASSERT(element());
+    auto* renderer = element()->renderer();
     if (!renderer)
         return;
 
@@ -217,15 +227,17 @@ void TextFieldInputType::elementDidBlur()
 
 void TextFieldInputType::handleFocusEvent(Node* oldFocusedNode, FocusDirection)
 {
-    ASSERT_UNUSED(oldFocusedNode, oldFocusedNode != &element());
-    if (RefPtr<Frame> frame = element().document().frame())
-        frame->editor().textFieldDidBeginEditing(&element());
+    ASSERT(element());
+    ASSERT_UNUSED(oldFocusedNode, oldFocusedNode != element());
+    if (RefPtr<Frame> frame = element()->document().frame())
+        frame->editor().textFieldDidBeginEditing(element());
 }
 
 void TextFieldInputType::handleBlurEvent()
 {
     InputType::handleBlurEvent();
-    element().endEditing();
+    ASSERT(element());
+    element()->endEditing();
 }
 
 bool TextFieldInputType::shouldSubmitImplicitly(Event& event)
@@ -236,7 +248,8 @@ bool TextFieldInputType::shouldSubmitImplicitly(Event& event)
 
 RenderPtr<RenderElement> TextFieldInputType::createInputRenderer(RenderStyle&& style)
 {
-    return createRenderer<RenderTextControlSingleLine>(element(), WTFMove(style));
+    ASSERT(element());
+    return createRenderer<RenderTextControlSingleLine>(*element(), WTFMove(style));
 }
 
 bool TextFieldInputType::needsContainer() const
@@ -246,17 +259,20 @@ bool TextFieldInputType::needsContainer() const
 
 bool TextFieldInputType::shouldHaveSpinButton() const
 {
-    return RenderTheme::singleton().shouldHaveSpinButton(element());
+    ASSERT(element());
+    return RenderTheme::singleton().shouldHaveSpinButton(*element());
 }
 
 bool TextFieldInputType::shouldHaveCapsLockIndicator() const
 {
-    return RenderTheme::singleton().shouldHaveCapsLockIndicator(element());
+    ASSERT(element());
+    return RenderTheme::singleton().shouldHaveCapsLockIndicator(*element());
 }
 
 void TextFieldInputType::createShadowSubtree()
 {
-    ASSERT(element().shadowRoot());
+    ASSERT(element());
+    ASSERT(element()->shadowRoot());
 
     ASSERT(!m_innerText);
     ASSERT(!m_innerBlock);
@@ -264,7 +280,7 @@ void TextFieldInputType::createShadowSubtree()
     ASSERT(!m_capsLockIndicator);
     ASSERT(!m_autoFillButton);
 
-    Document& document = element().document();
+    Document& document = element()->document();
     bool shouldHaveSpinButton = this->shouldHaveSpinButton();
     bool shouldHaveCapsLockIndicator = this->shouldHaveCapsLockIndicator();
     bool createsContainer = shouldHaveSpinButton || shouldHaveCapsLockIndicator || needsContainer();
@@ -272,7 +288,7 @@ void TextFieldInputType::createShadowSubtree()
     m_innerText = TextControlInnerTextElement::create(document);
 
     if (!createsContainer) {
-        element().userAgentShadowRoot()->appendChild(*m_innerText);
+        element()->userAgentShadowRoot()->appendChild(*m_innerText);
         updatePlaceholderText();
         return;
     }
@@ -350,8 +366,10 @@ void TextFieldInputType::destroyShadowSubtree()
 
 void TextFieldInputType::attributeChanged(const QualifiedName& name)
 {
-    if (name == valueAttr || name == placeholderAttr)
-        updateInnerTextValue();
+    if (name == valueAttr || name == placeholderAttr) {
+        if (element())
+            updateInnerTextValue();
+    }
     InputType::attributeChanged(name);
 }
 
@@ -475,12 +493,13 @@ String TextFieldInputType::sanitizeValue(const String& proposedValue) const
 
 void TextFieldInputType::handleBeforeTextInsertedEvent(BeforeTextInsertedEvent& event)
 {
+    ASSERT(element());
     // Make sure that the text to be inserted will not violate the maxLength.
 
     // We use RenderTextControlSingleLine::text() instead of InputElement::value()
     // because they can be mismatched by sanitizeValue() in
     // HTMLInputElement::subtreeHasChanged() in some cases.
-    String innerText = element().innerTextValue();
+    String innerText = element()->innerTextValue();
     unsigned oldLength = numGraphemeClusters(innerText);
 
     // selectionLength represents the selection length of this text field to be
@@ -489,18 +508,18 @@ void TextFieldInputType::handleBeforeTextInsertedEvent(BeforeTextInsertedEvent&
     // selection length. The selection is the source of text drag-and-drop in
     // that case, and nothing in the text field will be removed.
     unsigned selectionLength = 0;
-    if (element().focused()) {
-        ASSERT(enclosingTextFormControl(element().document().frame()->selection().selection().start()) == &element());
-        int selectionStart = element().selectionStart();
-        ASSERT(selectionStart <= element().selectionEnd());
-        int selectionCodeUnitCount = element().selectionEnd() - selectionStart;
+    if (element()->focused()) {
+        ASSERT(enclosingTextFormControl(element()->document().frame()->selection().selection().start()) == element());
+        int selectionStart = element()->selectionStart();
+        ASSERT(selectionStart <= element()->selectionEnd());
+        int selectionCodeUnitCount = element()->selectionEnd() - selectionStart;
         selectionLength = selectionCodeUnitCount ? numGraphemeClusters(StringView(innerText).substring(selectionStart, selectionCodeUnitCount)) : 0;
     }
     ASSERT(oldLength >= selectionLength);
 
     // Selected characters will be removed by the next text event.
     unsigned baseLength = oldLength - selectionLength;
-    unsigned maxLength = isTextType() ? element().effectiveMaxLength() : HTMLInputElement::maxEffectiveLength;
+    unsigned maxLength = isTextType() ? element()->effectiveMaxLength() : HTMLInputElement::maxEffectiveLength;
     unsigned appendableLength = maxLength > baseLength ? maxLength - baseLength : 0;
 
     // Truncate the inserted text to avoid violating the maxLength and other constraints.
@@ -524,7 +543,8 @@ void TextFieldInputType::updatePlaceholderText()
 {
     if (!supportsPlaceholder())
         return;
-    String placeholderText = element().strippedPlaceholder();
+    ASSERT(element());
+    String placeholderText = element()->strippedPlaceholder();
     if (placeholderText.isEmpty()) {
         if (m_placeholder) {
             m_placeholder->parentNode()->removeChild(*m_placeholder);
@@ -533,8 +553,8 @@ void TextFieldInputType::updatePlaceholderText()
         return;
     }
     if (!m_placeholder) {
-        m_placeholder = TextControlPlaceholderElement::create(element().document());
-        element().userAgentShadowRoot()->insertBefore(*m_placeholder, m_container ? m_container.get() : innerTextElement().get());
+        m_placeholder = TextControlPlaceholderElement::create(element()->document());
+        element()->userAgentShadowRoot()->insertBefore(*m_placeholder, m_container ? m_container.get() : innerTextElement().get());
     }
     m_placeholder->setInnerText(placeholderText);
 }
@@ -542,9 +562,10 @@ void TextFieldInputType::updatePlaceholderText()
 bool TextFieldInputType::appendFormData(DOMFormData& formData, bool multipart) const
 {
     InputType::appendFormData(formData, multipart);
-    auto& dirnameAttrValue = element().attributeWithoutSynchronization(dirnameAttr);
+    ASSERT(element());
+    auto& dirnameAttrValue = element()->attributeWithoutSynchronization(dirnameAttr);
     if (!dirnameAttrValue.isNull())
-        formData.append(dirnameAttrValue, element().directionForFormData());
+        formData.append(dirnameAttrValue, element()->directionForFormData());
     return true;
 }
 
@@ -555,7 +576,8 @@ String TextFieldInputType::convertFromVisibleValue(const String& visibleValue) c
 
 void TextFieldInputType::subtreeHasChanged()
 {
-    element().setChangedSinceLastFormControlChangeEvent(true);
+    ASSERT(element());
+    element()->setChangedSinceLastFormControlChangeEvent(true);
 
     // We don't need to call sanitizeUserInputValue() function here because
     // HTMLInputElement::handleBeforeTextInsertedEvent() has already called
@@ -567,23 +589,24 @@ void TextFieldInputType::subtreeHasChanged()
     // user input in order to retain parity between what's in the model and
     // what's on the screen. Otherwise, we retain the sanitization process for
     // backward compatibility. https://bugs.webkit.org/show_bug.cgi?id=150346
-    String innerText = convertFromVisibleValue(element().innerTextValue());
+    String innerText = convertFromVisibleValue(element()->innerTextValue());
     if (!supportsSelectionAPI())
         innerText = sanitizeValue(innerText);
-    element().setValueFromRenderer(innerText);
-    element().updatePlaceholderVisibility();
+    element()->setValueFromRenderer(innerText);
+    element()->updatePlaceholderVisibility();
     // Recalc for :invalid change.
-    element().invalidateStyleForSubtree();
+    element()->invalidateStyleForSubtree();
 
     didSetValueByUserEdit();
 }
 
 void TextFieldInputType::didSetValueByUserEdit()
 {
-    if (!element().focused())
+    ASSERT(element());
+    if (!element()->focused())
         return;
-    if (RefPtr<Frame> frame = element().document().frame())
-        frame->editor().textDidChangeInTextField(&element());
+    if (RefPtr<Frame> frame = element()->document().frame())
+        frame->editor().textDidChangeInTextField(element());
 }
 
 void TextFieldInputType::spinButtonStepDown()
@@ -598,40 +621,45 @@ void TextFieldInputType::spinButtonStepUp()
 
 void TextFieldInputType::updateInnerTextValue()
 {
-    if (!element().formControlValueMatchesRenderer()) {
+    ASSERT(element());
+    if (!element()->formControlValueMatchesRenderer()) {
         // Update the renderer value if the formControlValueMatchesRenderer() flag is false.
         // It protects an unacceptable renderer value from being overwritten with the DOM value.
-        element().setInnerTextValue(visibleValue());
-        element().updatePlaceholderVisibility();
+        element()->setInnerTextValue(visibleValue());
+        element()->updatePlaceholderVisibility();
     }
 }
 
 void TextFieldInputType::focusAndSelectSpinButtonOwner()
 {
-    Ref<HTMLInputElement> input(element());
+    ASSERT(element());
+    Ref<HTMLInputElement> input(*element());
     input->focus();
     input->select();
 }
 
 bool TextFieldInputType::shouldSpinButtonRespondToMouseEvents()
 {
-    return !element().isDisabledOrReadOnly();
+    ASSERT(element());
+    return !element()->isDisabledOrReadOnly();
 }
 
 bool TextFieldInputType::shouldSpinButtonRespondToWheelEvents()
 {
-    return shouldSpinButtonRespondToMouseEvents() && element().focused();
+    ASSERT(element());
+    return shouldSpinButtonRespondToMouseEvents() && element()->focused();
 }
 
 bool TextFieldInputType::shouldDrawCapsLockIndicator() const
 {
-    if (element().document().focusedElement() != &element())
+    ASSERT(element());
+    if (element()->document().focusedElement() != element())
         return false;
 
-    if (element().isDisabledOrReadOnly())
+    if (element()->isDisabledOrReadOnly())
         return false;
 
-    RefPtr<Frame> frame = element().document().frame();
+    RefPtr<Frame> frame = element()->document().frame();
     if (!frame)
         return false;
 
@@ -652,30 +680,33 @@ void TextFieldInputType::capsLockStateMayHaveChanged()
 
 bool TextFieldInputType::shouldDrawAutoFillButton() const
 {
-    return !element().isDisabledOrReadOnly() && element().autoFillButtonType() != AutoFillButtonType::None;
+    ASSERT(element());
+    return !element()->isDisabledOrReadOnly() && element()->autoFillButtonType() != AutoFillButtonType::None;
 }
 
 void TextFieldInputType::autoFillButtonElementWasClicked()
 {
-    Page* page = element().document().page();
+    ASSERT(element());
+    Page* page = element()->document().page();
     if (!page)
         return;
 
-    page->chrome().client().handleAutoFillButtonClick(element());
+    page->chrome().client().handleAutoFillButtonClick(*element());
 }
 
 void TextFieldInputType::createContainer()
 {
     ASSERT(!m_container);
+    ASSERT(element());
 
-    m_container = TextControlInnerContainer::create(element().document());
+    m_container = TextControlInnerContainer::create(element()->document());
     m_container->setPseudo(AtomicString("-webkit-textfield-decoration-container", AtomicString::ConstructFromLiteral));
 
-    m_innerBlock = TextControlInnerElement::create(element().document());
+    m_innerBlock = TextControlInnerElement::create(element()->document());
     m_innerBlock->appendChild(*m_innerText);
     m_container->appendChild(*m_innerBlock);
 
-    element().userAgentShadowRoot()->appendChild(*m_container);
+    element()->userAgentShadowRoot()->appendChild(*m_container);
 }
 
 void TextFieldInputType::createAutoFillButton(AutoFillButtonType autoFillButtonType)
@@ -685,7 +716,8 @@ void TextFieldInputType::createAutoFillButton(AutoFillButtonType autoFillButtonT
     if (autoFillButtonType == AutoFillButtonType::None)
         return;
 
-    m_autoFillButton = AutoFillButtonElement::create(element().document(), *this);
+    ASSERT(element());
+    m_autoFillButton = AutoFillButtonElement::create(element()->document(), *this);
     m_autoFillButton->setPseudo(autoFillButtonTypeToAutoFillButtonPseudoClassName(autoFillButtonType));
     m_autoFillButton->setAttributeWithoutSynchronization(roleAttr, AtomicString("button", AtomicString::ConstructFromLiteral));
     m_autoFillButton->setAttributeWithoutSynchronization(aria_labelAttr, autoFillButtonTypeToAccessibilityLabel(autoFillButtonType));
@@ -699,7 +731,8 @@ void TextFieldInputType::updateAutoFillButton()
         if (!m_container)
             createContainer();
 
-        AutoFillButtonType autoFillButtonType = element().autoFillButtonType();
+        ASSERT(element());
+        AutoFillButtonType autoFillButtonType = element()->autoFillButtonType();
         if (!m_autoFillButton)
             createAutoFillButton(autoFillButtonType);
 
index 05820ce..6ca0ac1 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -51,7 +52,8 @@ bool URLInputType::typeMismatchFor(const String& value) const
 
 bool URLInputType::typeMismatch() const
 {
-    return typeMismatchFor(element().value());
+    ASSERT(element());
+    return typeMismatchFor(element()->value());
 }
 
 String URLInputType::typeMismatchText() const