Title: [290284] trunk
Revision
290284
Author
hey...@apple.com
Date
2022-02-21 19:36:52 -0800 (Mon, 21 Feb 2022)

Log Message

Make input element UA shadow tree creation lazy
https://bugs.webkit.org/show_bug.cgi?id=236747

Reviewed by Aditya Keerthi.

Source/WebCore:

We currently delay InputType creation for parser inserted elements until
just after the attributes have been set, so that we don't wastefully
create an InputType and the UA shadow tree creation if a non-text
type="" was specified on the tag. We don't do anything similar for
script inserted input elements. We could make the InputType creation
lazy, but most of the wasted time is due to the shadow tree creation.

This patch makes InputType shadow tree creation lazy by delaying it
until one of the following happens:

1. the element is inserted into the document
2. the type="" or value="" attributes are changed before the element
   is inserted into the document
3. any DOM methods that need access to the innerTextElement() are
   called on the element before the element is inserted into the
   document

Not all places where we call innerTextElement() on the
HTMLInputElement are safe to lazily create the shadow trees, so we
have two accessors:

- innerTextElement() returns the inner text element if it's been
  created already
- innerTextElementCreatingShadowSubtreeIfNeeded will perform the lazy
  shadow tree construction if it hasn't already been done

Since the existing
createShadowSubtreeAndUpdateInnerTextElementEditability function has
more responsibility than just creating the subtree and ensuring the
editability is set appropriately, it's renamed to a more manageable
createShadowSubtree.

This change is a 0.5% progression on Speedometer 2.

Test: fast/forms/lazy-shadow-tree-creation.html

* html/BaseDateAndTimeInputType.h:
* html/BaseDateAndTimeInputType.cpp:
(WebCore::BaseDateAndTimeInputType::createShadowSubtree):
(WebCore::BaseDateAndTimeInputType::createShadowSubtreeAndUpdateInnerTextElementEditability):
* html/ColorInputType.h:
* html/ColorInputType.cpp:
(WebCore::ColorInputType::createShadowSubtree):
(WebCore::ColorInputType::createShadowSubtreeAndUpdateInnerTextElementEditability):
* html/FileInputType.h:
* html/FileInputType.cpp:
(WebCore::FileInputType::createShadowSubtree):
(WebCore::FileInputType::createShadowSubtreeAndUpdateInnerTextElementEditability):
* html/InputType.cpp:
(WebCore::InputType::createShadowSubtree):
(WebCore::InputType::createShadowSubtreeAndUpdateInnerTextElementEditability):
* html/RangeInputType.h:
* html/RangeInputType.cpp:
(WebCore::RangeInputType::createShadowSubtree):
(WebCore::RangeInputType::createShadowSubtreeAndUpdateInnerTextElementEditability):
* html/SearchInputType.h:
* html/SearchInputType.cpp:
(WebCore::SearchInputType::createShadowSubtree):
(WebCore::SearchInputType::createShadowSubtreeAndUpdateInnerTextElementEditability):
Renamed createShadowSubtreeAndUpdateInnerTextElementEditability to
createShadowSubtree and remove the "isInnerTextElementEditable"
argument, since we can ask the element() for its value if needed.
createShadowSubtree is now also responsible for creating the shadow
root.

* html/TextFieldInputType.h:
* html/TextFieldInputType.cpp:
(WebCore::TextFieldInputType::createShadowSubtree):
(WebCore::TextFieldInputType::createShadowSubtreeAndUpdateInnerTextElementEditability):
Renamed. Ensure all shadow tree state is up to date now that it can be
created later.

* html/InputType.h:
* html/InputType.cpp:
(WebCore::InputType::createShadowSubtree):
(WebCore::InputType::hasCreatedShadowSubtree const):
New functions to create the shadow subtree if it hasn't been done
already, and to query whether it's been done.

* html/HTMLInputElement.h:
* html/HTMLInputElement.cpp:
(WebCore::HTMLInputElement::innerTextElementCreatingShadowSubtreeIfNeeded):
* html/HTMLTextAreaElement.h:
* html/HTMLTextAreaElement.cpp:
(WebCore::HTMLTextAreaElement::innerTextElementCreatingShadowSubtreeIfNeeded):
* html/HTMLTextFormControlElement.h:
* html/InputType.h:
* html/InputType.cpp:
(WebCore::InputType::innerTextElementCreatingShadowSubtreeIfNeeded):
New functions to first create the shadow subtree before returning
innerTextElement(). HTMLTextAreaElement never lazily creates its
shadow subtree and so just returns innerTextElement().

* html/HTMLInputElement.h:
* html/HTMLInputElement.cpp:
(WebCore::HTMLInputElement::createShadowSubtreeAndUpdateInnerTextElementEditability):
Deleted. Just call through to m_inputType->createShadowTree()
directly.

(WebCore::HTMLInputElement::HTMLInputElement):
(WebCore::HTMLInputElement::create):
(WebCore::HTMLInputElement::initializeInputType):
(WebCore::HTMLInputElement::updateType):
Don't immediately create the shadow tree.

(WebCore::HTMLInputElement::didFinishInsertingNode):
Create the shadow subtree now that the element's been inserted. No
need to call dataListMayHaveChanged since
TextFieldInputType::createShadowSubtree will now do this.

* html/BaseDateAndTimeInputType.cpp:
(WebCore::BaseDateAndTimeInputType::updateInnerTextValue):
Ensure the shadow subtree is created since we need to poke at it.

* html/HTMLTextFormControlElement.cpp:
(WebCore::HTMLTextFormControlElement::forwardEvent):
Don't forward the event if the shadow tree hasn't been created yet.

(WebCore::HTMLTextFormControlElement::setSelectionRange):
Ensure the shadow tree has been created. This is needed if the
selection APIs are called on the input element before it's inserted
into the document.

(WebCore::HTMLTextFormControlElement::visiblePositionForIndex const):
Assert that the shadow tree has been created, since editing
functionality should only be needed if the element's been inserted
into the document.

(WebCore::HTMLTextFormControlElement::setInnerTextValue):
Ensure the shadow tree has been created.

* html/RangeInputType.cpp:
(WebCore::RangeInputType::handleMouseDownEvent):
(WebCore::RangeInputType::handleTouchEvent):
(WebCore::RangeInputType::handleKeydownEvent):
Ensure the shadow tree has been created in case the event will change
the value.

(WebCore::RangeInputType::sliderTrackElement const):
Only return the element if it's been created.

(WebCore::RangeInputType::typedSliderThumbElement const):
Assert that the element has been created.

(WebCore::RangeInputType::dataListMayHaveChanged):
Only try to re-layout if the shadow tree has been created.

* html/TextFieldInputType.cpp:
(WebCore::TextFieldInputType::isEmptyValue const):
Avoid creating the shadow subtree.

(WebCore::TextFieldInputType::forwardEvent):
Move the element assertion up to be consistent with other functions.

(WebCore::TextFieldInputType::innerTextElement const):
Don't assert, since this now can legitimately return null.

* html/FileInputType.cpp:
(WebCore::FileInputType::disabledStateChanged):
(WebCore::FileInputType::attributeChanged):
* html/RangeInputType.cpp:
(WebCore::RangeInputType::disabledStateChanged):
(WebCore::RangeInputType::attributeChanged):
(WebCore::RangeInputType::setValue):
* html/TextFieldInputType.cpp:
(WebCore::TextFieldInputType::disabledStateChanged):
(WebCore::TextFieldInputType::readOnlyStateChanged):
(WebCore::TextFieldInputType::updatePlaceholderText):
(WebCore::TextFieldInputType::updateAutoFillButton):
(WebCore::TextFieldInputType::dataListMayHaveChanged):
Don't update the shadow tree contents if it hasn't been created yet.
createShadowTree is responsible for ensuring it creates the shadow
tree contents reflecting the current state.

LayoutTests:

* fast/forms/lazy-shadow-tree-creation-expected.html: Added.
* fast/forms/lazy-shadow-tree-creation.html: Added.
* fast/forms/lazy-shadow-tree-creation.js: Added.
(supportsType):
(makeAndAppendInput):

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (290283 => 290284)


--- trunk/LayoutTests/ChangeLog	2022-02-22 02:16:28 UTC (rev 290283)
+++ trunk/LayoutTests/ChangeLog	2022-02-22 03:36:52 UTC (rev 290284)
@@ -1,3 +1,16 @@
+2022-02-21  Cameron McCormack  <hey...@apple.com>
+
+        Make input element UA shadow tree creation lazy
+        https://bugs.webkit.org/show_bug.cgi?id=236747
+
+        Reviewed by Aditya Keerthi.
+
+        * fast/forms/lazy-shadow-tree-creation-expected.html: Added.
+        * fast/forms/lazy-shadow-tree-creation.html: Added.
+        * fast/forms/lazy-shadow-tree-creation.js: Added.
+        (supportsType):
+        (makeAndAppendInput):
+
 2022-02-21  Jon Lee  <jon...@apple.com>
 
         Unreviewed gardening for the GPU Process bots.

Added: trunk/LayoutTests/fast/forms/lazy-shadow-tree-creation-expected.html (0 => 290284)


--- trunk/LayoutTests/fast/forms/lazy-shadow-tree-creation-expected.html	                        (rev 0)
+++ trunk/LayoutTests/fast/forms/lazy-shadow-tree-creation-expected.html	2022-02-22 03:36:52 UTC (rev 290284)
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<body>
+<script src=""
+<script>
+run({ useParser: true });
+</script>

Added: trunk/LayoutTests/fast/forms/lazy-shadow-tree-creation.html (0 => 290284)


--- trunk/LayoutTests/fast/forms/lazy-shadow-tree-creation.html	                        (rev 0)
+++ trunk/LayoutTests/fast/forms/lazy-shadow-tree-creation.html	2022-02-22 03:36:52 UTC (rev 290284)
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<body>
+<script src=""
+<script>
+run({ useParser: false });
+</script>

Added: trunk/LayoutTests/fast/forms/lazy-shadow-tree-creation.js (0 => 290284)


--- trunk/LayoutTests/fast/forms/lazy-shadow-tree-creation.js	                        (rev 0)
+++ trunk/LayoutTests/fast/forms/lazy-shadow-tree-creation.js	2022-02-22 03:36:52 UTC (rev 290284)
@@ -0,0 +1,57 @@
+const types = {
+    "color": { value: "#008000" },
+    "date": { value: "2022-01-01" },
+    "datetime-local": { value: "2022-01-01" },
+    "email": { value: "he...@example.com" },
+    "file": { },
+    "month": { value: "2022-01" },
+    "number": { value: "123" },
+    "password": { },
+    "range": { value: "75" },
+    "search": { value: "abc" },
+    "telephone": { value: "+61300000000" },
+    "text": { value: "abc" },
+    "time": { value: "10:00" },
+    "url": { value: "https://example.com/" },
+    "week": { value: "2022-W1" },
+};
+
+function supportsType(typeName) {
+    let e = document.createElement("input");
+    e.type = typeName;
+    return e.type == typeName;
+}
+
+function makeAndAppendInput(options, typeName, attributes = { }) {
+    let span = document.createElement("span");
+    document.body.append(span);
+
+    if (options.useParser) {
+        let tag = `<input type="${typeName}"`;
+        for (let name in attributes)
+            tag += ` ${name}="${attributes[name]}"`;
+        tag += ">";
+        span.innerHTML = tag;
+    } else {
+        let input = document.createElement("input");
+        input.type = typeName;
+        for (let name in attributes)
+            input.setAttribute(name, attributes[name]);
+        span.append(input);
+    }
+}
+
+function run(options) {
+    for (let typeName in types) {
+        if (!supportsType(typeName))
+            continue;
+
+        let type = types[typeName];
+        makeAndAppendInput(options, typeName);
+
+        if (type.value)
+            makeAndAppendInput(options, typeName, { value: type.value });
+
+        makeAndAppendInput(options, typeName, { value: type.value, disabled: "disabled" });
+    }
+}

Modified: trunk/Source/WebCore/ChangeLog (290283 => 290284)


--- trunk/Source/WebCore/ChangeLog	2022-02-22 02:16:28 UTC (rev 290283)
+++ trunk/Source/WebCore/ChangeLog	2022-02-22 03:36:52 UTC (rev 290284)
@@ -1,3 +1,184 @@
+2022-02-21  Cameron McCormack  <hey...@apple.com>
+
+        Make input element UA shadow tree creation lazy
+        https://bugs.webkit.org/show_bug.cgi?id=236747
+
+        Reviewed by Aditya Keerthi.
+
+        We currently delay InputType creation for parser inserted elements until
+        just after the attributes have been set, so that we don't wastefully
+        create an InputType and the UA shadow tree creation if a non-text
+        type="" was specified on the tag. We don't do anything similar for
+        script inserted input elements. We could make the InputType creation
+        lazy, but most of the wasted time is due to the shadow tree creation.
+
+        This patch makes InputType shadow tree creation lazy by delaying it
+        until one of the following happens:
+
+        1. the element is inserted into the document
+        2. the type="" or value="" attributes are changed before the element
+           is inserted into the document
+        3. any DOM methods that need access to the innerTextElement() are
+           called on the element before the element is inserted into the
+           document
+
+        Not all places where we call innerTextElement() on the
+        HTMLInputElement are safe to lazily create the shadow trees, so we
+        have two accessors:
+
+        - innerTextElement() returns the inner text element if it's been
+          created already
+        - innerTextElementCreatingShadowSubtreeIfNeeded will perform the lazy
+          shadow tree construction if it hasn't already been done
+
+        Since the existing
+        createShadowSubtreeAndUpdateInnerTextElementEditability function has
+        more responsibility than just creating the subtree and ensuring the
+        editability is set appropriately, it's renamed to a more manageable
+        createShadowSubtree.
+
+        This change is a 0.5% progression on Speedometer 2.
+
+        Test: fast/forms/lazy-shadow-tree-creation.html
+
+        * html/BaseDateAndTimeInputType.h:
+        * html/BaseDateAndTimeInputType.cpp:
+        (WebCore::BaseDateAndTimeInputType::createShadowSubtree):
+        (WebCore::BaseDateAndTimeInputType::createShadowSubtreeAndUpdateInnerTextElementEditability):
+        * html/ColorInputType.h:
+        * html/ColorInputType.cpp:
+        (WebCore::ColorInputType::createShadowSubtree):
+        (WebCore::ColorInputType::createShadowSubtreeAndUpdateInnerTextElementEditability):
+        * html/FileInputType.h:
+        * html/FileInputType.cpp:
+        (WebCore::FileInputType::createShadowSubtree):
+        (WebCore::FileInputType::createShadowSubtreeAndUpdateInnerTextElementEditability):
+        * html/InputType.cpp:
+        (WebCore::InputType::createShadowSubtree):
+        (WebCore::InputType::createShadowSubtreeAndUpdateInnerTextElementEditability):
+        * html/RangeInputType.h:
+        * html/RangeInputType.cpp:
+        (WebCore::RangeInputType::createShadowSubtree):
+        (WebCore::RangeInputType::createShadowSubtreeAndUpdateInnerTextElementEditability):
+        * html/SearchInputType.h:
+        * html/SearchInputType.cpp:
+        (WebCore::SearchInputType::createShadowSubtree):
+        (WebCore::SearchInputType::createShadowSubtreeAndUpdateInnerTextElementEditability):
+        Renamed createShadowSubtreeAndUpdateInnerTextElementEditability to
+        createShadowSubtree and remove the "isInnerTextElementEditable"
+        argument, since we can ask the element() for its value if needed.
+        createShadowSubtree is now also responsible for creating the shadow
+        root.
+
+        * html/TextFieldInputType.h:
+        * html/TextFieldInputType.cpp:
+        (WebCore::TextFieldInputType::createShadowSubtree):
+        (WebCore::TextFieldInputType::createShadowSubtreeAndUpdateInnerTextElementEditability):
+        Renamed. Ensure all shadow tree state is up to date now that it can be
+        created later.
+
+        * html/InputType.h:
+        * html/InputType.cpp:
+        (WebCore::InputType::createShadowSubtree):
+        (WebCore::InputType::hasCreatedShadowSubtree const):
+        New functions to create the shadow subtree if it hasn't been done
+        already, and to query whether it's been done.
+
+        * html/HTMLInputElement.h:
+        * html/HTMLInputElement.cpp:
+        (WebCore::HTMLInputElement::innerTextElementCreatingShadowSubtreeIfNeeded):
+        * html/HTMLTextAreaElement.h:
+        * html/HTMLTextAreaElement.cpp:
+        (WebCore::HTMLTextAreaElement::innerTextElementCreatingShadowSubtreeIfNeeded):
+        * html/HTMLTextFormControlElement.h:
+        * html/InputType.h:
+        * html/InputType.cpp:
+        (WebCore::InputType::innerTextElementCreatingShadowSubtreeIfNeeded):
+        New functions to first create the shadow subtree before returning
+        innerTextElement(). HTMLTextAreaElement never lazily creates its
+        shadow subtree and so just returns innerTextElement().
+
+        * html/HTMLInputElement.h:
+        * html/HTMLInputElement.cpp:
+        (WebCore::HTMLInputElement::createShadowSubtreeAndUpdateInnerTextElementEditability):
+        Deleted. Just call through to m_inputType->createShadowTree()
+        directly.
+
+        (WebCore::HTMLInputElement::HTMLInputElement):
+        (WebCore::HTMLInputElement::create):
+        (WebCore::HTMLInputElement::initializeInputType):
+        (WebCore::HTMLInputElement::updateType):
+        Don't immediately create the shadow tree.
+
+        (WebCore::HTMLInputElement::didFinishInsertingNode):
+        Create the shadow subtree now that the element's been inserted. No
+        need to call dataListMayHaveChanged since
+        TextFieldInputType::createShadowSubtree will now do this.
+
+        * html/BaseDateAndTimeInputType.cpp:
+        (WebCore::BaseDateAndTimeInputType::updateInnerTextValue):
+        Ensure the shadow subtree is created since we need to poke at it.
+
+        * html/HTMLTextFormControlElement.cpp:
+        (WebCore::HTMLTextFormControlElement::forwardEvent):
+        Don't forward the event if the shadow tree hasn't been created yet.
+
+        (WebCore::HTMLTextFormControlElement::setSelectionRange):
+        Ensure the shadow tree has been created. This is needed if the
+        selection APIs are called on the input element before it's inserted
+        into the document.
+
+        (WebCore::HTMLTextFormControlElement::visiblePositionForIndex const):
+        Assert that the shadow tree has been created, since editing
+        functionality should only be needed if the element's been inserted
+        into the document.
+
+        (WebCore::HTMLTextFormControlElement::setInnerTextValue):
+        Ensure the shadow tree has been created.
+
+        * html/RangeInputType.cpp:
+        (WebCore::RangeInputType::handleMouseDownEvent):
+        (WebCore::RangeInputType::handleTouchEvent):
+        (WebCore::RangeInputType::handleKeydownEvent):
+        Ensure the shadow tree has been created in case the event will change
+        the value.
+
+        (WebCore::RangeInputType::sliderTrackElement const):
+        Only return the element if it's been created.
+
+        (WebCore::RangeInputType::typedSliderThumbElement const):
+        Assert that the element has been created.
+
+        (WebCore::RangeInputType::dataListMayHaveChanged):
+        Only try to re-layout if the shadow tree has been created.
+
+        * html/TextFieldInputType.cpp:
+        (WebCore::TextFieldInputType::isEmptyValue const):
+        Avoid creating the shadow subtree.
+
+        (WebCore::TextFieldInputType::forwardEvent):
+        Move the element assertion up to be consistent with other functions.
+
+        (WebCore::TextFieldInputType::innerTextElement const):
+        Don't assert, since this now can legitimately return null.
+
+        * html/FileInputType.cpp:
+        (WebCore::FileInputType::disabledStateChanged):
+        (WebCore::FileInputType::attributeChanged):
+        * html/RangeInputType.cpp:
+        (WebCore::RangeInputType::disabledStateChanged):
+        (WebCore::RangeInputType::attributeChanged):
+        (WebCore::RangeInputType::setValue):
+        * html/TextFieldInputType.cpp:
+        (WebCore::TextFieldInputType::disabledStateChanged):
+        (WebCore::TextFieldInputType::readOnlyStateChanged):
+        (WebCore::TextFieldInputType::updatePlaceholderText):
+        (WebCore::TextFieldInputType::updateAutoFillButton):
+        (WebCore::TextFieldInputType::dataListMayHaveChanged):
+        Don't update the shadow tree contents if it hasn't been created yet.
+        createShadowTree is responsible for ensuring it creates the shadow
+        tree contents reflecting the current state.
+
 2022-02-21  Wenson Hsieh  <wenson_hs...@apple.com>
 
         Add test coverage for the pasteboard writing codepath added in r289839

Modified: trunk/Source/WebCore/html/BaseDateAndTimeInputType.cpp (290283 => 290284)


--- trunk/Source/WebCore/html/BaseDateAndTimeInputType.cpp	2022-02-22 02:16:28 UTC (rev 290283)
+++ trunk/Source/WebCore/html/BaseDateAndTimeInputType.cpp	2022-02-22 03:36:52 UTC (rev 290284)
@@ -306,7 +306,7 @@
     }
 }
 
-void BaseDateAndTimeInputType::createShadowSubtreeAndUpdateInnerTextElementEditability(bool)
+void BaseDateAndTimeInputType::createShadowSubtree()
 {
     ASSERT(needsShadowSubtree());
     ASSERT(element());
@@ -334,6 +334,9 @@
 void BaseDateAndTimeInputType::updateInnerTextValue()
 {
     ASSERT(element());
+
+    createShadowSubtreeIfNeeded();
+
     if (!m_dateTimeEditElement) {
         auto node = element()->userAgentShadowRoot()->firstChild();
         if (!is<HTMLElement>(node))

Modified: trunk/Source/WebCore/html/BaseDateAndTimeInputType.h (290283 => 290284)


--- trunk/Source/WebCore/html/BaseDateAndTimeInputType.h	2022-02-22 02:16:28 UTC (rev 290283)
+++ trunk/Source/WebCore/html/BaseDateAndTimeInputType.h	2022-02-22 03:36:52 UTC (rev 290284)
@@ -114,7 +114,7 @@
     bool isMouseFocusable() const final;
 
     void handleDOMActivateEvent(Event&) override;
-    void createShadowSubtreeAndUpdateInnerTextElementEditability(bool) final;
+    void createShadowSubtree() final;
     void destroyShadowSubtree() final;
     void updateInnerTextValue() final;
     bool hasCustomFocusLogic() const final;

Modified: trunk/Source/WebCore/html/ColorInputType.cpp (290283 => 290284)


--- trunk/Source/WebCore/html/ColorInputType.cpp	2022-02-22 02:16:28 UTC (rev 290283)
+++ trunk/Source/WebCore/html/ColorInputType.cpp	2022-02-22 03:36:52 UTC (rev 290284)
@@ -136,7 +136,7 @@
     return parseSimpleColorValue(element()->value()).value();
 }
 
-void ColorInputType::createShadowSubtreeAndUpdateInnerTextElementEditability(bool)
+void ColorInputType::createShadowSubtree()
 {
     ASSERT(needsShadowSubtree());
     ASSERT(element());

Modified: trunk/Source/WebCore/html/ColorInputType.h (290283 => 290284)


--- trunk/Source/WebCore/html/ColorInputType.h	2022-02-22 02:16:28 UTC (rev 290283)
+++ trunk/Source/WebCore/html/ColorInputType.h	2022-02-22 03:36:52 UTC (rev 290284)
@@ -62,7 +62,7 @@
     bool supportsRequired() const final;
     String fallbackValue() const final;
     String sanitizeValue(const String&) const final;
-    void createShadowSubtreeAndUpdateInnerTextElementEditability(bool) final;
+    void createShadowSubtree() final;
     void setValue(const String&, bool valueChanged, TextFieldEventBehavior) final;
     void attributeChanged(const QualifiedName&) final;
     void handleDOMActivateEvent(Event&) final;

Modified: trunk/Source/WebCore/html/FileInputType.cpp (290283 => 290284)


--- trunk/Source/WebCore/html/FileInputType.cpp	2022-02-22 02:16:28 UTC (rev 290283)
+++ trunk/Source/WebCore/html/FileInputType.cpp	2022-02-22 03:36:52 UTC (rev 290284)
@@ -262,18 +262,20 @@
     element()->invalidateStyleForSubtree();
 }
 
-void FileInputType::createShadowSubtreeAndUpdateInnerTextElementEditability(bool)
+void FileInputType::createShadowSubtree()
 {
     ASSERT(needsShadowSubtree());
     ASSERT(element());
     ASSERT(element()->shadowRoot());
-    element()->userAgentShadowRoot()->appendChild(ContainerNode::ChildChange::Source::Parser, element()->multiple() ? UploadButtonElement::createForMultiple(element()->document()): UploadButtonElement::create(element()->document()));
+
+    auto button = element()->multiple() ? UploadButtonElement::createForMultiple(element()->document()) : UploadButtonElement::create(element()->document());
+    element()->userAgentShadowRoot()->appendChild(ContainerNode::ChildChange::Source::Parser, button);
+    disabledStateChanged();
 }
 
 void FileInputType::disabledStateChanged()
 {
     ASSERT(element());
-    ASSERT(element()->shadowRoot());
 
     auto root = element()->userAgentShadowRoot();
     if (!root)
@@ -287,7 +289,6 @@
 {
     if (name == multipleAttr) {
         if (auto* element = this->element()) {
-            ASSERT(element->shadowRoot());
             if (auto root = element->userAgentShadowRoot()) {
                 if (RefPtr button = childrenOfType<UploadButtonElement>(*root).first())
                     button->setValue(element->multiple() ? fileButtonChooseMultipleFilesLabel() : fileButtonChooseFileLabel());

Modified: trunk/Source/WebCore/html/FileInputType.h (290283 => 290284)


--- trunk/Source/WebCore/html/FileInputType.h	2022-02-22 02:16:28 UTC (rev 290283)
+++ trunk/Source/WebCore/html/FileInputType.h	2022-02-22 03:36:52 UTC (rev 290284)
@@ -77,7 +77,7 @@
 #endif
 
     Icon* icon() const final;
-    void createShadowSubtreeAndUpdateInnerTextElementEditability(bool) final;
+    void createShadowSubtree() final;
     void disabledStateChanged() final;
     void attributeChanged(const QualifiedName&) final;
     String defaultToolTip() const final;

Modified: trunk/Source/WebCore/html/HTMLInputElement.cpp (290283 => 290284)


--- trunk/Source/WebCore/html/HTMLInputElement.cpp	2022-02-22 02:16:28 UTC (rev 290283)
+++ trunk/Source/WebCore/html/HTMLInputElement.cpp	2022-02-22 03:36:52 UTC (rev 290284)
@@ -136,8 +136,8 @@
 #endif
     , m_isSpellcheckDisabledExceptTextReplacement(false)
 {
-    // m_inputType is lazily created when constructed by the parser to avoid constructing unnecessarily a text inputType and
-    // its shadow subtree, just to destroy them when the |type| attribute gets set by the parser to something else than 'text'.
+    // m_inputType is lazily created when constructed by the parser to avoid constructing unnecessarily a text inputType,
+    // just to destroy them when the |type| attribute gets set by the parser to something else than 'text'.
     if (!createdByParser)
         m_inputType = InputType::createText(*this);
 
@@ -147,14 +147,7 @@
 
 Ref<HTMLInputElement> HTMLInputElement::create(const QualifiedName& tagName, Document& document, HTMLFormElement* form, bool createdByParser)
 {
-    bool shouldCreateShadowRootLazily = createdByParser;
-    Ref<HTMLInputElement> inputElement = adoptRef(*new HTMLInputElement(tagName, document, form, createdByParser));
-    if (!shouldCreateShadowRootLazily) {
-        ASSERT(inputElement->m_inputType->needsShadowSubtree());
-        inputElement->createUserAgentShadowRoot();
-        inputElement->createShadowSubtreeAndUpdateInnerTextElementEditability();
-    }
-    return inputElement;
+    return adoptRef(*new HTMLInputElement(tagName, document, form, createdByParser));
 }
 
 HTMLImageLoader& HTMLInputElement::ensureImageLoader()
@@ -164,12 +157,6 @@
     return *m_imageLoader;
 }
 
-void HTMLInputElement::createShadowSubtreeAndUpdateInnerTextElementEditability()
-{
-    Ref<InputType> protectedInputType(*m_inputType);
-    protectedInputType->createShadowSubtreeAndUpdateInnerTextElementEditability(isInnerTextElementEditable());
-}
-
 HTMLInputElement::~HTMLInputElement()
 {
     if (needsSuspensionCallback())
@@ -212,6 +199,11 @@
     return m_inputType->innerTextElement();
 }
 
+RefPtr<TextControlInnerTextElement> HTMLInputElement::innerTextElementCreatingShadowSubtreeIfNeeded()
+{
+    return m_inputType->innerTextElementCreatingShadowSubtreeIfNeeded();
+}
+
 HTMLElement* HTMLInputElement::innerBlockElement() const
 {
     return m_inputType->innerBlockElement();
@@ -580,10 +572,7 @@
     m_inputType->detachFromElement();
 
     m_inputType = WTFMove(newType);
-    if (m_inputType->needsShadowSubtree()) {
-        ensureUserAgentShadowRoot();
-        createShadowSubtreeAndUpdateInnerTextElementEditability();
-    }
+    m_inputType->createShadowSubtreeIfNeeded();
 
     updateWillValidateAndValidity();
 
@@ -736,9 +725,6 @@
     const AtomString& type = attributeWithoutSynchronization(typeAttr);
     if (type.isNull()) {
         m_inputType = InputType::createText(*this);
-        ASSERT(m_inputType->needsShadowSubtree());
-        createUserAgentShadowRoot();
-        createShadowSubtreeAndUpdateInnerTextElementEditability();
         updateWillValidateAndValidity();
         return;
     }
@@ -745,10 +731,6 @@
 
     m_hasType = true;
     m_inputType = InputType::create(*this, type);
-    if (m_inputType->needsShadowSubtree()) {
-        createUserAgentShadowRoot();
-        createShadowSubtreeAndUpdateInnerTextElementEditability();
-    }
     updateWillValidateAndValidity();
     registerForSuspensionCallbackIfNeeded();
     runPostTypeUpdateTasks();
@@ -1599,10 +1581,8 @@
     HTMLTextFormControlElement::didFinishInsertingNode();
     if (isInTreeScope() && !form())
         addToRadioButtonGroup();
-#if ENABLE(DATALIST_ELEMENT)
-    if (isConnected() && m_hasNonEmptyList)
-        dataListMayHaveChanged();
-#endif
+    if (isConnected())
+        m_inputType->createShadowSubtreeIfNeeded();
 }
 
 void HTMLInputElement::removedFromAncestor(RemovalType removalType, ContainerNode& oldParentOfRemovedTree)

Modified: trunk/Source/WebCore/html/HTMLInputElement.h (290283 => 290284)


--- trunk/Source/WebCore/html/HTMLInputElement.h	2022-02-22 02:16:28 UTC (rev 290283)
+++ trunk/Source/WebCore/html/HTMLInputElement.h	2022-02-22 03:36:52 UTC (rev 290284)
@@ -137,6 +137,7 @@
     HTMLElement* containerElement() const;
     
     RefPtr<TextControlInnerTextElement> innerTextElement() const final;
+    RefPtr<TextControlInnerTextElement> innerTextElementCreatingShadowSubtreeIfNeeded() final;
     RenderStyle createInnerTextStyle(const RenderStyle&) final;
 
     HTMLElement* innerBlockElement() const;
@@ -356,6 +357,8 @@
 
     String resultForDialogSubmit() const final;
 
+    bool isInnerTextElementEditable() const final { return !hasAutoFillStrongPasswordButton() && HTMLTextFormControlElement::isInnerTextElementEditable(); }
+
 protected:
     HTMLInputElement(const QualifiedName&, Document&, HTMLFormElement*, bool createdByParser);
 
@@ -371,8 +374,6 @@
     void removedFromAncestor(RemovalType, ContainerNode&) final;
     void didMoveToNewDocument(Document& oldDocument, Document& newDocument) final;
 
-    void createShadowSubtreeAndUpdateInnerTextElementEditability();
-
     int defaultTabIndex() const final;
     bool hasCustomFocusLogic() const final;
     bool isKeyboardFocusable(KeyboardEvent*) const final;
@@ -384,8 +385,6 @@
 
     bool isInteractiveContent() const final;
 
-    bool isInnerTextElementEditable() const final { return !hasAutoFillStrongPasswordButton() && HTMLTextFormControlElement::isInnerTextElementEditable(); }
-
     bool canTriggerImplicitSubmission() const final { return isTextField(); }
 
     const AtomString& formControlType() const final;

Modified: trunk/Source/WebCore/html/HTMLTextAreaElement.cpp (290283 => 290284)


--- trunk/Source/WebCore/html/HTMLTextAreaElement.cpp	2022-02-22 02:16:28 UTC (rev 290283)
+++ trunk/Source/WebCore/html/HTMLTextAreaElement.cpp	2022-02-22 03:36:52 UTC (rev 290284)
@@ -345,6 +345,11 @@
     return childrenOfType<TextControlInnerTextElement>(*root).first();
 }
 
+RefPtr<TextControlInnerTextElement> HTMLTextAreaElement::innerTextElementCreatingShadowSubtreeIfNeeded()
+{
+    return innerTextElement();
+}
+
 void HTMLTextAreaElement::rendererWillBeDestroyed()
 {
     updateValue();

Modified: trunk/Source/WebCore/html/HTMLTextAreaElement.h (290283 => 290284)


--- trunk/Source/WebCore/html/HTMLTextAreaElement.h	2022-02-22 02:16:28 UTC (rev 290283)
+++ trunk/Source/WebCore/html/HTMLTextAreaElement.h	2022-02-22 03:36:52 UTC (rev 290284)
@@ -57,6 +57,7 @@
     bool isValidValue(const String&) const;
     
     WEBCORE_EXPORT RefPtr<TextControlInnerTextElement> innerTextElement() const final;
+    WEBCORE_EXPORT RefPtr<TextControlInnerTextElement> innerTextElementCreatingShadowSubtreeIfNeeded() final;
     RenderStyle createInnerTextStyle(const RenderStyle&) final;
     void copyNonAttributePropertiesFromElement(const Element&) final;
 

Modified: trunk/Source/WebCore/html/HTMLTextFormControlElement.cpp (290283 => 290284)


--- trunk/Source/WebCore/html/HTMLTextFormControlElement.cpp	2022-02-22 02:16:28 UTC (rev 290283)
+++ trunk/Source/WebCore/html/HTMLTextFormControlElement.cpp	2022-02-22 03:36:52 UTC (rev 290284)
@@ -157,7 +157,9 @@
 {
     if (event.type() == eventNames().blurEvent || event.type() == eventNames().focusEvent)
         return;
-    innerTextElement()->defaultEventHandler(event);
+
+    if (auto innerText = innerTextElement())
+        innerText->defaultEventHandler(event);
 }
 
 static bool isNotLineBreak(UChar ch) { return ch != newlineCharacter && ch != carriageReturn; }
@@ -309,7 +311,7 @@
     end = std::max(end, 0);
     start = std::min(std::max(start, 0), end);
 
-    auto innerText = innerTextElement();
+    auto innerText = innerTextElementCreatingShadowSubtreeIfNeeded();
     bool hasFocus = document().focusedElement() == this;
     if (!hasFocus && innerText) {
         if (!isConnected()) {
@@ -369,6 +371,7 @@
 
 VisiblePosition HTMLTextFormControlElement::visiblePositionForIndex(int index) const
 {
+    ASSERT(innerTextElement());
     VisiblePosition position = positionForIndex(innerTextElement().get(), index);
     ASSERT(indexForVisiblePosition(position) == index);
     return position;
@@ -587,7 +590,7 @@
 void HTMLTextFormControlElement::setInnerTextValue(const String& value)
 {
     LayoutDisallowedScope layoutDisallowedScope(LayoutDisallowedScope::Reason::PerformanceOptimization);
-    auto innerText = innerTextElement();
+    auto innerText = innerTextElementCreatingShadowSubtreeIfNeeded();
     if (!innerText)
         return;
 

Modified: trunk/Source/WebCore/html/HTMLTextFormControlElement.h (290283 => 290284)


--- trunk/Source/WebCore/html/HTMLTextFormControlElement.h	2022-02-22 02:16:28 UTC (rev 290283)
+++ trunk/Source/WebCore/html/HTMLTextFormControlElement.h	2022-02-22 03:36:52 UTC (rev 290284)
@@ -89,6 +89,7 @@
     virtual String value() const = 0;
 
     virtual RefPtr<TextControlInnerTextElement> innerTextElement() const = 0;
+    virtual RefPtr<TextControlInnerTextElement> innerTextElementCreatingShadowSubtreeIfNeeded() = 0;
     virtual RenderStyle createInnerTextStyle(const RenderStyle&) = 0;
 
     void selectionChanged(bool shouldFireSelectEvent);

Modified: trunk/Source/WebCore/html/InputType.cpp (290283 => 290284)


--- trunk/Source/WebCore/html/InputType.cpp	2022-02-22 02:16:28 UTC (rev 290283)
+++ trunk/Source/WebCore/html/InputType.cpp	2022-02-22 03:36:52 UTC (rev 290284)
@@ -561,7 +561,7 @@
     element()->defaultBlur();
 }
 
-void InputType::createShadowSubtreeAndUpdateInnerTextElementEditability(bool)
+void InputType::createShadowSubtree()
 {
 }
 
@@ -1119,6 +1119,12 @@
     return nullptr;
 }
 
+RefPtr<TextControlInnerTextElement> InputType::innerTextElementCreatingShadowSubtreeIfNeeded()
+{
+    createShadowSubtreeIfNeeded();
+    return innerTextElement();
+}
+
 String InputType::resultForDialogSubmit() const
 {
     ASSERT(element());
@@ -1125,4 +1131,14 @@
     return element()->value();
 }
 
+void InputType::createShadowSubtreeIfNeeded()
+{
+    if (m_hasCreatedShadowSubtree || !needsShadowSubtree())
+        return;
+    Ref protectedThis { *this };
+    element()->ensureUserAgentShadowRoot();
+    m_hasCreatedShadowSubtree = true;
+    createShadowSubtree();
+}
+
 } // namespace WebCore

Modified: trunk/Source/WebCore/html/InputType.h (290283 => 290284)


--- trunk/Source/WebCore/html/InputType.h	2022-02-22 02:16:28 UTC (rev 290283)
+++ trunk/Source/WebCore/html/InputType.h	2022-02-22 03:36:52 UTC (rev 290284)
@@ -206,6 +206,7 @@
     bool supportLabels() const;
     bool isEnumeratable() const;
     bool needsShadowSubtree() const { return !nonShadowRootTypes.contains(m_type); }
+    bool hasCreatedShadowSubtree() const { return m_hasCreatedShadowSubtree; }
 
     // Form value functions.
 
@@ -306,7 +307,8 @@
 
     // Shadow tree handling.
 
-    virtual void createShadowSubtreeAndUpdateInnerTextElementEditability(bool);
+    void createShadowSubtreeIfNeeded();
+    virtual void createShadowSubtree();
     virtual void destroyShadowSubtree();
 
     virtual HTMLElement* containerElement() const { return nullptr; }
@@ -323,6 +325,7 @@
 #if ENABLE(DATALIST_ELEMENT)
     virtual HTMLElement* dataListButtonElement() const { return nullptr; }
 #endif
+    RefPtr<TextControlInnerTextElement> innerTextElementCreatingShadowSubtreeIfNeeded();
 
     // Miscellaneous functions.
 
@@ -413,6 +416,7 @@
     ExceptionOr<void> applyStep(int count, AnyStepHandling, TextFieldEventBehavior);
 
     const Type m_type;
+    bool m_hasCreatedShadowSubtree { false };
     // m_element is null if this InputType is no longer associated with an element (either the element died or changed input type).
     WeakPtr<HTMLInputElement> m_element;
 };

Modified: trunk/Source/WebCore/html/RangeInputType.cpp (290283 => 290284)


--- trunk/Source/WebCore/html/RangeInputType.cpp	2022-02-22 02:16:28 UTC (rev 290283)
+++ trunk/Source/WebCore/html/RangeInputType.cpp	2022-02-22 03:36:52 UTC (rev 290284)
@@ -133,6 +133,10 @@
 void RangeInputType::handleMouseDownEvent(MouseEvent& event)
 {
     ASSERT(element());
+
+    if (!hasCreatedShadowSubtree())
+        return;
+
     if (element()->isDisabledFormControl())
         return;
 
@@ -151,10 +155,15 @@
 #if ENABLE(TOUCH_EVENTS)
 void RangeInputType::handleTouchEvent(TouchEvent& event)
 {
+    ASSERT(element());
+
+    if (!hasCreatedShadowSubtree())
+        return;
+
 #if PLATFORM(IOS_FAMILY)
     typedSliderThumbElement().handleTouchEvent(event);
 #elif ENABLE(TOUCH_SLIDER)
-    ASSERT(element());
+
     if (element()->isDisabledFormControl())
         return;
 
@@ -183,6 +192,8 @@
 
 void RangeInputType::disabledStateChanged()
 {
+    if (!hasCreatedShadowSubtree())
+        return;
     typedSliderThumbElement().hostDisabledStateChanged();
 }
 
@@ -189,6 +200,10 @@
 auto RangeInputType::handleKeydownEvent(KeyboardEvent& event) -> ShouldCallBaseEventHandler
 {
     ASSERT(element());
+
+    if (!hasCreatedShadowSubtree())
+        return ShouldCallBaseEventHandler::Yes;
+
     if (element()->isDisabledFormControl())
         return ShouldCallBaseEventHandler::Yes;
 
@@ -241,7 +256,7 @@
     return ShouldCallBaseEventHandler::Yes;
 }
 
-void RangeInputType::createShadowSubtreeAndUpdateInnerTextElementEditability(bool)
+void RangeInputType::createShadowSubtree()
 {
     ASSERT(needsShadowSubtree());
     ASSERT(element());
@@ -259,6 +274,10 @@
 HTMLElement* RangeInputType::sliderTrackElement() const
 {
     ASSERT(element());
+
+    if (!hasCreatedShadowSubtree())
+        return nullptr;
+
     ASSERT(element()->userAgentShadowRoot());
     ASSERT(element()->userAgentShadowRoot()->firstChild()); // container
     ASSERT(element()->userAgentShadowRoot()->firstChild()->isHTMLElement());
@@ -277,6 +296,7 @@
 
 SliderThumbElement& RangeInputType::typedSliderThumbElement() const
 {
+    ASSERT(hasCreatedShadowSubtree());
     ASSERT(sliderTrackElement()->firstChild()); // thumb
     ASSERT(sliderTrackElement()->firstChild()->isHTMLElement());
 
@@ -322,7 +342,8 @@
             if (element->hasDirtyValue())
                 element->setValue(element->value());
         }
-        typedSliderThumbElement().setPositionFromValue();
+        if (hasCreatedShadowSubtree())
+            typedSliderThumbElement().setPositionFromValue();
     }
     InputType::attributeChanged(name);
 }
@@ -339,7 +360,8 @@
         element()->setTextAsOfLastFormControlChangeEvent(value);
     }
 
-    typedSliderThumbElement().setPositionFromValue();
+    if (hasCreatedShadowSubtree())
+        typedSliderThumbElement().setPositionFromValue();
 }
 
 String RangeInputType::fallbackValue() const
@@ -368,7 +390,7 @@
 {
     m_tickMarkValuesDirty = true;
     RefPtr<HTMLElement> sliderTrackElement = this->sliderTrackElement();
-    if (sliderTrackElement->renderer())
+    if (sliderTrackElement && sliderTrackElement->renderer())
         sliderTrackElement->renderer()->setNeedsLayout();
 }
 

Modified: trunk/Source/WebCore/html/RangeInputType.h (290283 => 290284)


--- trunk/Source/WebCore/html/RangeInputType.h	2022-02-22 02:16:28 UTC (rev 290283)
+++ trunk/Source/WebCore/html/RangeInputType.h	2022-02-22 03:36:52 UTC (rev 290284)
@@ -52,7 +52,7 @@
     void handleMouseDownEvent(MouseEvent&) final;
     ShouldCallBaseEventHandler handleKeydownEvent(KeyboardEvent&) final;
     RenderPtr<RenderElement> createInputRenderer(RenderStyle&&) final;
-    void createShadowSubtreeAndUpdateInnerTextElementEditability(bool) final;
+    void createShadowSubtree() final;
     Decimal parseToNumber(const String&, const Decimal&) const final;
     String serialize(const Decimal&) const final;
     bool accessKeyAction(bool sendMouseEvents) final;

Modified: trunk/Source/WebCore/html/SearchInputType.cpp (290283 => 290284)


--- trunk/Source/WebCore/html/SearchInputType.cpp	2022-02-22 02:16:28 UTC (rev 290283)
+++ trunk/Source/WebCore/html/SearchInputType.cpp	2022-02-22 03:36:52 UTC (rev 290284)
@@ -102,13 +102,13 @@
     return true;
 }
 
-void SearchInputType::createShadowSubtreeAndUpdateInnerTextElementEditability(bool isInnerTextElementEditable)
+void SearchInputType::createShadowSubtree()
 {
     ASSERT(needsShadowSubtree());
     ASSERT(!m_resultsButton);
     ASSERT(!m_cancelButton);
 
-    TextFieldInputType::createShadowSubtreeAndUpdateInnerTextElementEditability(isInnerTextElementEditable);
+    TextFieldInputType::createShadowSubtree();
     RefPtr<HTMLElement> container = containerElement();
     RefPtr<HTMLElement> textWrapper = innerBlockElement();
     ASSERT(container);

Modified: trunk/Source/WebCore/html/SearchInputType.h (290283 => 290284)


--- trunk/Source/WebCore/html/SearchInputType.h	2022-02-22 02:16:28 UTC (rev 290283)
+++ trunk/Source/WebCore/html/SearchInputType.h	2022-02-22 03:36:52 UTC (rev 290284)
@@ -51,7 +51,7 @@
     RenderPtr<RenderElement> createInputRenderer(RenderStyle&&) final;
     const AtomString& formControlType() const final;
     bool needsContainer() const final;
-    void createShadowSubtreeAndUpdateInnerTextElementEditability(bool) final;
+    void createShadowSubtree() final;
     void destroyShadowSubtree() final;
     HTMLElement* resultsButtonElement() const final;
     HTMLElement* cancelButtonElement() const final;

Modified: trunk/Source/WebCore/html/TextFieldInputType.cpp (290283 => 290284)


--- trunk/Source/WebCore/html/TextFieldInputType.cpp	2022-02-22 02:16:28 UTC (rev 290283)
+++ trunk/Source/WebCore/html/TextFieldInputType.cpp	2022-02-22 03:36:52 UTC (rev 290284)
@@ -108,7 +108,11 @@
 bool TextFieldInputType::isEmptyValue() const
 {
     auto innerText = innerTextElement();
-    ASSERT(innerText);
+    if (!innerText) {
+        // Since we always create the shadow subtree if a value is set, we know
+        // that the value is empty.
+        return true;
+    }
 
     for (Text* text = TextNodeTraversal::firstWithin(*innerText); text; text = TextNodeTraversal::next(*text, innerText.get())) {
         if (text->length())
@@ -221,6 +225,8 @@
 
 void TextFieldInputType::forwardEvent(Event& event)
 {
+    ASSERT(element());
+
     if (m_innerSpinButton) {
         m_innerSpinButton->forwardEvent(event);
         if (event.defaultHandled())
@@ -231,10 +237,8 @@
     bool isBlurEvent = event.type() == eventNames().blurEvent;
     if (isFocusEvent || isBlurEvent)
         capsLockStateMayHaveChanged();
-    if (event.isMouseEvent() || isFocusEvent || isBlurEvent) {
-        ASSERT(element());
+    if (event.isMouseEvent() || isFocusEvent || isBlurEvent)
         element()->forwardEvent(event);
-    }
 }
 
 void TextFieldInputType::elementDidBlur()
@@ -316,11 +320,12 @@
     return RenderTheme::singleton().shouldHaveCapsLockIndicator(*element());
 }
 
-void TextFieldInputType::createShadowSubtreeAndUpdateInnerTextElementEditability(bool isInnerTextElementEditable)
+void TextFieldInputType::createShadowSubtree()
 {
     ASSERT(needsShadowSubtree());
     ASSERT(element());
     ASSERT(element()->shadowRoot());
+    ASSERT(!element()->shadowRoot()->hasChildNodes());
 
     ASSERT(!m_innerText);
     ASSERT(!m_innerBlock);
@@ -331,9 +336,17 @@
     Document& document = element()->document();
     bool shouldHaveSpinButton = this->shouldHaveSpinButton();
     bool shouldHaveCapsLockIndicator = this->shouldHaveCapsLockIndicator();
-    bool createsContainer = shouldHaveSpinButton || shouldHaveCapsLockIndicator || needsContainer();
+    bool shouldDrawAutoFillButton = this->shouldDrawAutoFillButton();
+#if ENABLE(DATALIST_ELEMENT)
+    bool hasDataList = element()->list();
+#endif
+    bool createsContainer = shouldHaveSpinButton || shouldHaveCapsLockIndicator || shouldDrawAutoFillButton
+#if ENABLE(DATALIST_ELEMENT)
+        || hasDataList
+#endif
+        || needsContainer();
 
-    m_innerText = TextControlInnerTextElement::create(document, isInnerTextElementEditable);
+    m_innerText = TextControlInnerTextElement::create(document, element()->isInnerTextElementEditable());
 
     if (!createsContainer) {
         element()->userAgentShadowRoot()->appendChild(ContainerNode::ChildChange::Source::Parser, *m_innerText);
@@ -358,7 +371,12 @@
 
         m_container->appendChild(ContainerNode::ChildChange::Source::Parser, *m_capsLockIndicator);
     }
+
     updateAutoFillButton();
+
+#if ENABLE(DATALIST_ELEMENT)
+    dataListMayHaveChanged();
+#endif
 }
 
 HTMLElement* TextFieldInputType::containerElement() const
@@ -373,7 +391,6 @@
 
 RefPtr<TextControlInnerTextElement> TextFieldInputType::innerTextElement() const
 {
-    ASSERT(m_innerText);
     return m_innerText;
 }
 
@@ -425,6 +442,9 @@
 
 void TextFieldInputType::disabledStateChanged()
 {
+    if (!hasCreatedShadowSubtree())
+        return;
+
     if (m_innerSpinButton)
         m_innerSpinButton->releaseCapture();
     capsLockStateMayHaveChanged();
@@ -433,6 +453,9 @@
 
 void TextFieldInputType::readOnlyStateChanged()
 {
+    if (!hasCreatedShadowSubtree())
+        return;
+
     if (m_innerSpinButton)
         m_innerSpinButton->releaseCapture();
     capsLockStateMayHaveChanged();
@@ -616,9 +639,14 @@
 
 void TextFieldInputType::updatePlaceholderText()
 {
+    ASSERT(element());
+
+    if (!hasCreatedShadowSubtree())
+        return;
+
     if (!supportsPlaceholder())
         return;
-    ASSERT(element());
+
     String placeholderText = element()->placeholder();
     if (placeholderText.isEmpty()) {
         if (m_placeholder) {
@@ -816,6 +844,11 @@
 
 void TextFieldInputType::updateAutoFillButton()
 {
+    ASSERT(element());
+
+    if (!hasCreatedShadowSubtree())
+        return;
+
     capsLockStateMayHaveChanged();
 
     if (shouldDrawAutoFillButton()) {
@@ -822,7 +855,6 @@
         if (!m_container)
             createContainer();
 
-        ASSERT(element());
         AutoFillButtonType autoFillButtonType = element()->autoFillButtonType();
         if (!m_autoFillButton)
             createAutoFillButton(autoFillButtonType);
@@ -846,6 +878,9 @@
 
 void TextFieldInputType::dataListMayHaveChanged()
 {
+    if (!hasCreatedShadowSubtree())
+        return;
+
     m_cachedSuggestions = { };
 
     if (!m_dataListDropdownIndicator)

Modified: trunk/Source/WebCore/html/TextFieldInputType.h (290283 => 290284)


--- trunk/Source/WebCore/html/TextFieldInputType.h	2022-02-22 02:16:28 UTC (rev 290283)
+++ trunk/Source/WebCore/html/TextFieldInputType.h	2022-02-22 03:36:52 UTC (rev 290284)
@@ -70,7 +70,7 @@
 #endif
 
     virtual bool needsContainer() const;
-    void createShadowSubtreeAndUpdateInnerTextElementEditability(bool) override;
+    void createShadowSubtree() override;
     void destroyShadowSubtree() override;
     void attributeChanged(const QualifiedName&) override;
     void disabledStateChanged() final;
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to