Changeset 290284 in webkit


Ignore:
Timestamp:
Feb 21, 2022 7:36:52 PM (5 months ago)
Author:
Cameron McCormack
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):

Location:
trunk
Files:
3 added
22 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r290281 r290284  
     12022-02-21  Cameron McCormack  <heycam@apple.com>
     2
     3        Make input element UA shadow tree creation lazy
     4        https://bugs.webkit.org/show_bug.cgi?id=236747
     5
     6        Reviewed by Aditya Keerthi.
     7
     8        * fast/forms/lazy-shadow-tree-creation-expected.html: Added.
     9        * fast/forms/lazy-shadow-tree-creation.html: Added.
     10        * fast/forms/lazy-shadow-tree-creation.js: Added.
     11        (supportsType):
     12        (makeAndAppendInput):
     13
    1142022-02-21  Jon Lee  <jonlee@apple.com>
    215
  • trunk/Source/WebCore/ChangeLog

    r290278 r290284  
     12022-02-21  Cameron McCormack  <heycam@apple.com>
     2
     3        Make input element UA shadow tree creation lazy
     4        https://bugs.webkit.org/show_bug.cgi?id=236747
     5
     6        Reviewed by Aditya Keerthi.
     7
     8        We currently delay InputType creation for parser inserted elements until
     9        just after the attributes have been set, so that we don't wastefully
     10        create an InputType and the UA shadow tree creation if a non-text
     11        type="" was specified on the tag. We don't do anything similar for
     12        script inserted input elements. We could make the InputType creation
     13        lazy, but most of the wasted time is due to the shadow tree creation.
     14
     15        This patch makes InputType shadow tree creation lazy by delaying it
     16        until one of the following happens:
     17
     18        1. the element is inserted into the document
     19        2. the type="" or value="" attributes are changed before the element
     20           is inserted into the document
     21        3. any DOM methods that need access to the innerTextElement() are
     22           called on the element before the element is inserted into the
     23           document
     24
     25        Not all places where we call innerTextElement() on the
     26        HTMLInputElement are safe to lazily create the shadow trees, so we
     27        have two accessors:
     28
     29        - innerTextElement() returns the inner text element if it's been
     30          created already
     31        - innerTextElementCreatingShadowSubtreeIfNeeded will perform the lazy
     32          shadow tree construction if it hasn't already been done
     33
     34        Since the existing
     35        createShadowSubtreeAndUpdateInnerTextElementEditability function has
     36        more responsibility than just creating the subtree and ensuring the
     37        editability is set appropriately, it's renamed to a more manageable
     38        createShadowSubtree.
     39
     40        This change is a 0.5% progression on Speedometer 2.
     41
     42        Test: fast/forms/lazy-shadow-tree-creation.html
     43
     44        * html/BaseDateAndTimeInputType.h:
     45        * html/BaseDateAndTimeInputType.cpp:
     46        (WebCore::BaseDateAndTimeInputType::createShadowSubtree):
     47        (WebCore::BaseDateAndTimeInputType::createShadowSubtreeAndUpdateInnerTextElementEditability):
     48        * html/ColorInputType.h:
     49        * html/ColorInputType.cpp:
     50        (WebCore::ColorInputType::createShadowSubtree):
     51        (WebCore::ColorInputType::createShadowSubtreeAndUpdateInnerTextElementEditability):
     52        * html/FileInputType.h:
     53        * html/FileInputType.cpp:
     54        (WebCore::FileInputType::createShadowSubtree):
     55        (WebCore::FileInputType::createShadowSubtreeAndUpdateInnerTextElementEditability):
     56        * html/InputType.cpp:
     57        (WebCore::InputType::createShadowSubtree):
     58        (WebCore::InputType::createShadowSubtreeAndUpdateInnerTextElementEditability):
     59        * html/RangeInputType.h:
     60        * html/RangeInputType.cpp:
     61        (WebCore::RangeInputType::createShadowSubtree):
     62        (WebCore::RangeInputType::createShadowSubtreeAndUpdateInnerTextElementEditability):
     63        * html/SearchInputType.h:
     64        * html/SearchInputType.cpp:
     65        (WebCore::SearchInputType::createShadowSubtree):
     66        (WebCore::SearchInputType::createShadowSubtreeAndUpdateInnerTextElementEditability):
     67        Renamed createShadowSubtreeAndUpdateInnerTextElementEditability to
     68        createShadowSubtree and remove the "isInnerTextElementEditable"
     69        argument, since we can ask the element() for its value if needed.
     70        createShadowSubtree is now also responsible for creating the shadow
     71        root.
     72
     73        * html/TextFieldInputType.h:
     74        * html/TextFieldInputType.cpp:
     75        (WebCore::TextFieldInputType::createShadowSubtree):
     76        (WebCore::TextFieldInputType::createShadowSubtreeAndUpdateInnerTextElementEditability):
     77        Renamed. Ensure all shadow tree state is up to date now that it can be
     78        created later.
     79
     80        * html/InputType.h:
     81        * html/InputType.cpp:
     82        (WebCore::InputType::createShadowSubtree):
     83        (WebCore::InputType::hasCreatedShadowSubtree const):
     84        New functions to create the shadow subtree if it hasn't been done
     85        already, and to query whether it's been done.
     86
     87        * html/HTMLInputElement.h:
     88        * html/HTMLInputElement.cpp:
     89        (WebCore::HTMLInputElement::innerTextElementCreatingShadowSubtreeIfNeeded):
     90        * html/HTMLTextAreaElement.h:
     91        * html/HTMLTextAreaElement.cpp:
     92        (WebCore::HTMLTextAreaElement::innerTextElementCreatingShadowSubtreeIfNeeded):
     93        * html/HTMLTextFormControlElement.h:
     94        * html/InputType.h:
     95        * html/InputType.cpp:
     96        (WebCore::InputType::innerTextElementCreatingShadowSubtreeIfNeeded):
     97        New functions to first create the shadow subtree before returning
     98        innerTextElement(). HTMLTextAreaElement never lazily creates its
     99        shadow subtree and so just returns innerTextElement().
     100
     101        * html/HTMLInputElement.h:
     102        * html/HTMLInputElement.cpp:
     103        (WebCore::HTMLInputElement::createShadowSubtreeAndUpdateInnerTextElementEditability):
     104        Deleted. Just call through to m_inputType->createShadowTree()
     105        directly.
     106
     107        (WebCore::HTMLInputElement::HTMLInputElement):
     108        (WebCore::HTMLInputElement::create):
     109        (WebCore::HTMLInputElement::initializeInputType):
     110        (WebCore::HTMLInputElement::updateType):
     111        Don't immediately create the shadow tree.
     112
     113        (WebCore::HTMLInputElement::didFinishInsertingNode):
     114        Create the shadow subtree now that the element's been inserted. No
     115        need to call dataListMayHaveChanged since
     116        TextFieldInputType::createShadowSubtree will now do this.
     117
     118        * html/BaseDateAndTimeInputType.cpp:
     119        (WebCore::BaseDateAndTimeInputType::updateInnerTextValue):
     120        Ensure the shadow subtree is created since we need to poke at it.
     121
     122        * html/HTMLTextFormControlElement.cpp:
     123        (WebCore::HTMLTextFormControlElement::forwardEvent):
     124        Don't forward the event if the shadow tree hasn't been created yet.
     125
     126        (WebCore::HTMLTextFormControlElement::setSelectionRange):
     127        Ensure the shadow tree has been created. This is needed if the
     128        selection APIs are called on the input element before it's inserted
     129        into the document.
     130
     131        (WebCore::HTMLTextFormControlElement::visiblePositionForIndex const):
     132        Assert that the shadow tree has been created, since editing
     133        functionality should only be needed if the element's been inserted
     134        into the document.
     135
     136        (WebCore::HTMLTextFormControlElement::setInnerTextValue):
     137        Ensure the shadow tree has been created.
     138
     139        * html/RangeInputType.cpp:
     140        (WebCore::RangeInputType::handleMouseDownEvent):
     141        (WebCore::RangeInputType::handleTouchEvent):
     142        (WebCore::RangeInputType::handleKeydownEvent):
     143        Ensure the shadow tree has been created in case the event will change
     144        the value.
     145
     146        (WebCore::RangeInputType::sliderTrackElement const):
     147        Only return the element if it's been created.
     148
     149        (WebCore::RangeInputType::typedSliderThumbElement const):
     150        Assert that the element has been created.
     151
     152        (WebCore::RangeInputType::dataListMayHaveChanged):
     153        Only try to re-layout if the shadow tree has been created.
     154
     155        * html/TextFieldInputType.cpp:
     156        (WebCore::TextFieldInputType::isEmptyValue const):
     157        Avoid creating the shadow subtree.
     158
     159        (WebCore::TextFieldInputType::forwardEvent):
     160        Move the element assertion up to be consistent with other functions.
     161
     162        (WebCore::TextFieldInputType::innerTextElement const):
     163        Don't assert, since this now can legitimately return null.
     164
     165        * html/FileInputType.cpp:
     166        (WebCore::FileInputType::disabledStateChanged):
     167        (WebCore::FileInputType::attributeChanged):
     168        * html/RangeInputType.cpp:
     169        (WebCore::RangeInputType::disabledStateChanged):
     170        (WebCore::RangeInputType::attributeChanged):
     171        (WebCore::RangeInputType::setValue):
     172        * html/TextFieldInputType.cpp:
     173        (WebCore::TextFieldInputType::disabledStateChanged):
     174        (WebCore::TextFieldInputType::readOnlyStateChanged):
     175        (WebCore::TextFieldInputType::updatePlaceholderText):
     176        (WebCore::TextFieldInputType::updateAutoFillButton):
     177        (WebCore::TextFieldInputType::dataListMayHaveChanged):
     178        Don't update the shadow tree contents if it hasn't been created yet.
     179        createShadowTree is responsible for ensuring it creates the shadow
     180        tree contents reflecting the current state.
     181
    11822022-02-21  Wenson Hsieh  <wenson_hsieh@apple.com>
    2183
  • trunk/Source/WebCore/html/BaseDateAndTimeInputType.cpp

    r290086 r290284  
    307307}
    308308
    309 void BaseDateAndTimeInputType::createShadowSubtreeAndUpdateInnerTextElementEditability(bool)
     309void BaseDateAndTimeInputType::createShadowSubtree()
    310310{
    311311    ASSERT(needsShadowSubtree());
     
    335335{
    336336    ASSERT(element());
     337
     338    createShadowSubtreeIfNeeded();
     339
    337340    if (!m_dateTimeEditElement) {
    338341        auto node = element()->userAgentShadowRoot()->firstChild();
  • trunk/Source/WebCore/html/BaseDateAndTimeInputType.h

    r290086 r290284  
    115115
    116116    void handleDOMActivateEvent(Event&) override;
    117     void createShadowSubtreeAndUpdateInnerTextElementEditability(bool) final;
     117    void createShadowSubtree() final;
    118118    void destroyShadowSubtree() final;
    119119    void updateInnerTextValue() final;
  • trunk/Source/WebCore/html/ColorInputType.cpp

    r290086 r290284  
    137137}
    138138
    139 void ColorInputType::createShadowSubtreeAndUpdateInnerTextElementEditability(bool)
     139void ColorInputType::createShadowSubtree()
    140140{
    141141    ASSERT(needsShadowSubtree());
  • trunk/Source/WebCore/html/ColorInputType.h

    r290086 r290284  
    6363    String fallbackValue() const final;
    6464    String sanitizeValue(const String&) const final;
    65     void createShadowSubtreeAndUpdateInnerTextElementEditability(bool) final;
     65    void createShadowSubtree() final;
    6666    void setValue(const String&, bool valueChanged, TextFieldEventBehavior) final;
    6767    void attributeChanged(const QualifiedName&) final;
  • trunk/Source/WebCore/html/FileInputType.cpp

    r290086 r290284  
    263263}
    264264
    265 void FileInputType::createShadowSubtreeAndUpdateInnerTextElementEditability(bool)
     265void FileInputType::createShadowSubtree()
    266266{
    267267    ASSERT(needsShadowSubtree());
    268268    ASSERT(element());
    269269    ASSERT(element()->shadowRoot());
    270     element()->userAgentShadowRoot()->appendChild(ContainerNode::ChildChange::Source::Parser, element()->multiple() ? UploadButtonElement::createForMultiple(element()->document()): UploadButtonElement::create(element()->document()));
     270
     271    auto button = element()->multiple() ? UploadButtonElement::createForMultiple(element()->document()) : UploadButtonElement::create(element()->document());
     272    element()->userAgentShadowRoot()->appendChild(ContainerNode::ChildChange::Source::Parser, button);
     273    disabledStateChanged();
    271274}
    272275
     
    274277{
    275278    ASSERT(element());
    276     ASSERT(element()->shadowRoot());
    277279
    278280    auto root = element()->userAgentShadowRoot();
     
    288290    if (name == multipleAttr) {
    289291        if (auto* element = this->element()) {
    290             ASSERT(element->shadowRoot());
    291292            if (auto root = element->userAgentShadowRoot()) {
    292293                if (RefPtr button = childrenOfType<UploadButtonElement>(*root).first())
  • trunk/Source/WebCore/html/FileInputType.h

    r290086 r290284  
    7878
    7979    Icon* icon() const final;
    80     void createShadowSubtreeAndUpdateInnerTextElementEditability(bool) final;
     80    void createShadowSubtree() final;
    8181    void disabledStateChanged() final;
    8282    void attributeChanged(const QualifiedName&) final;
  • trunk/Source/WebCore/html/HTMLInputElement.cpp

    r290086 r290284  
    137137    , m_isSpellcheckDisabledExceptTextReplacement(false)
    138138{
    139     // m_inputType is lazily created when constructed by the parser to avoid constructing unnecessarily a text inputType and
    140     // its shadow subtree, just to destroy them when the |type| attribute gets set by the parser to something else than 'text'.
     139    // m_inputType is lazily created when constructed by the parser to avoid constructing unnecessarily a text inputType,
     140    // just to destroy them when the |type| attribute gets set by the parser to something else than 'text'.
    141141    if (!createdByParser)
    142142        m_inputType = InputType::createText(*this);
     
    148148Ref<HTMLInputElement> HTMLInputElement::create(const QualifiedName& tagName, Document& document, HTMLFormElement* form, bool createdByParser)
    149149{
    150     bool shouldCreateShadowRootLazily = createdByParser;
    151     Ref<HTMLInputElement> inputElement = adoptRef(*new HTMLInputElement(tagName, document, form, createdByParser));
    152     if (!shouldCreateShadowRootLazily) {
    153         ASSERT(inputElement->m_inputType->needsShadowSubtree());
    154         inputElement->createUserAgentShadowRoot();
    155         inputElement->createShadowSubtreeAndUpdateInnerTextElementEditability();
    156     }
    157     return inputElement;
     150    return adoptRef(*new HTMLInputElement(tagName, document, form, createdByParser));
    158151}
    159152
     
    163156        m_imageLoader = makeUnique<HTMLImageLoader>(*this);
    164157    return *m_imageLoader;
    165 }
    166 
    167 void HTMLInputElement::createShadowSubtreeAndUpdateInnerTextElementEditability()
    168 {
    169     Ref<InputType> protectedInputType(*m_inputType);
    170     protectedInputType->createShadowSubtreeAndUpdateInnerTextElementEditability(isInnerTextElementEditable());
    171158}
    172159
     
    211198{
    212199    return m_inputType->innerTextElement();
     200}
     201
     202RefPtr<TextControlInnerTextElement> HTMLInputElement::innerTextElementCreatingShadowSubtreeIfNeeded()
     203{
     204    return m_inputType->innerTextElementCreatingShadowSubtreeIfNeeded();
    213205}
    214206
     
    581573
    582574    m_inputType = WTFMove(newType);
    583     if (m_inputType->needsShadowSubtree()) {
    584         ensureUserAgentShadowRoot();
    585         createShadowSubtreeAndUpdateInnerTextElementEditability();
    586     }
     575    m_inputType->createShadowSubtreeIfNeeded();
    587576
    588577    updateWillValidateAndValidity();
     
    737726    if (type.isNull()) {
    738727        m_inputType = InputType::createText(*this);
    739         ASSERT(m_inputType->needsShadowSubtree());
    740         createUserAgentShadowRoot();
    741         createShadowSubtreeAndUpdateInnerTextElementEditability();
    742728        updateWillValidateAndValidity();
    743729        return;
     
    746732    m_hasType = true;
    747733    m_inputType = InputType::create(*this, type);
    748     if (m_inputType->needsShadowSubtree()) {
    749         createUserAgentShadowRoot();
    750         createShadowSubtreeAndUpdateInnerTextElementEditability();
    751     }
    752734    updateWillValidateAndValidity();
    753735    registerForSuspensionCallbackIfNeeded();
     
    16001582    if (isInTreeScope() && !form())
    16011583        addToRadioButtonGroup();
    1602 #if ENABLE(DATALIST_ELEMENT)
    1603     if (isConnected() && m_hasNonEmptyList)
    1604         dataListMayHaveChanged();
    1605 #endif
     1584    if (isConnected())
     1585        m_inputType->createShadowSubtreeIfNeeded();
    16061586}
    16071587
  • trunk/Source/WebCore/html/HTMLInputElement.h

    r289813 r290284  
    138138   
    139139    RefPtr<TextControlInnerTextElement> innerTextElement() const final;
     140    RefPtr<TextControlInnerTextElement> innerTextElementCreatingShadowSubtreeIfNeeded() final;
    140141    RenderStyle createInnerTextStyle(const RenderStyle&) final;
    141142
     
    357358    String resultForDialogSubmit() const final;
    358359
     360    bool isInnerTextElementEditable() const final { return !hasAutoFillStrongPasswordButton() && HTMLTextFormControlElement::isInnerTextElementEditable(); }
     361
    359362protected:
    360363    HTMLInputElement(const QualifiedName&, Document&, HTMLFormElement*, bool createdByParser);
     
    371374    void removedFromAncestor(RemovalType, ContainerNode&) final;
    372375    void didMoveToNewDocument(Document& oldDocument, Document& newDocument) final;
    373 
    374     void createShadowSubtreeAndUpdateInnerTextElementEditability();
    375376
    376377    int defaultTabIndex() const final;
     
    384385
    385386    bool isInteractiveContent() const final;
    386 
    387     bool isInnerTextElementEditable() const final { return !hasAutoFillStrongPasswordButton() && HTMLTextFormControlElement::isInnerTextElementEditable(); }
    388387
    389388    bool canTriggerImplicitSubmission() const final { return isTextField(); }
  • trunk/Source/WebCore/html/HTMLTextAreaElement.cpp

    r288005 r290284  
    346346}
    347347
     348RefPtr<TextControlInnerTextElement> HTMLTextAreaElement::innerTextElementCreatingShadowSubtreeIfNeeded()
     349{
     350    return innerTextElement();
     351}
     352
    348353void HTMLTextAreaElement::rendererWillBeDestroyed()
    349354{
  • trunk/Source/WebCore/html/HTMLTextAreaElement.h

    r286447 r290284  
    5858   
    5959    WEBCORE_EXPORT RefPtr<TextControlInnerTextElement> innerTextElement() const final;
     60    WEBCORE_EXPORT RefPtr<TextControlInnerTextElement> innerTextElementCreatingShadowSubtreeIfNeeded() final;
    6061    RenderStyle createInnerTextStyle(const RenderStyle&) final;
    6162    void copyNonAttributePropertiesFromElement(const Element&) final;
  • trunk/Source/WebCore/html/HTMLTextFormControlElement.cpp

    r289246 r290284  
    158158    if (event.type() == eventNames().blurEvent || event.type() == eventNames().focusEvent)
    159159        return;
    160     innerTextElement()->defaultEventHandler(event);
     160
     161    if (auto innerText = innerTextElement())
     162        innerText->defaultEventHandler(event);
    161163}
    162164
     
    310312    start = std::min(std::max(start, 0), end);
    311313
    312     auto innerText = innerTextElement();
     314    auto innerText = innerTextElementCreatingShadowSubtreeIfNeeded();
    313315    bool hasFocus = document().focusedElement() == this;
    314316    if (!hasFocus && innerText) {
     
    370372VisiblePosition HTMLTextFormControlElement::visiblePositionForIndex(int index) const
    371373{
     374    ASSERT(innerTextElement());
    372375    VisiblePosition position = positionForIndex(innerTextElement().get(), index);
    373376    ASSERT(indexForVisiblePosition(position) == index);
     
    588591{
    589592    LayoutDisallowedScope layoutDisallowedScope(LayoutDisallowedScope::Reason::PerformanceOptimization);
    590     auto innerText = innerTextElement();
     593    auto innerText = innerTextElementCreatingShadowSubtreeIfNeeded();
    591594    if (!innerText)
    592595        return;
  • trunk/Source/WebCore/html/HTMLTextFormControlElement.h

    r289246 r290284  
    9090
    9191    virtual RefPtr<TextControlInnerTextElement> innerTextElement() const = 0;
     92    virtual RefPtr<TextControlInnerTextElement> innerTextElementCreatingShadowSubtreeIfNeeded() = 0;
    9293    virtual RenderStyle createInnerTextStyle(const RenderStyle&) = 0;
    9394
  • trunk/Source/WebCore/html/InputType.cpp

    r290086 r290284  
    562562}
    563563
    564 void InputType::createShadowSubtreeAndUpdateInnerTextElementEditability(bool)
     564void InputType::createShadowSubtree()
    565565{
    566566}
     
    11201120}
    11211121
     1122RefPtr<TextControlInnerTextElement> InputType::innerTextElementCreatingShadowSubtreeIfNeeded()
     1123{
     1124    createShadowSubtreeIfNeeded();
     1125    return innerTextElement();
     1126}
     1127
    11221128String InputType::resultForDialogSubmit() const
    11231129{
     
    11261132}
    11271133
     1134void InputType::createShadowSubtreeIfNeeded()
     1135{
     1136    if (m_hasCreatedShadowSubtree || !needsShadowSubtree())
     1137        return;
     1138    Ref protectedThis { *this };
     1139    element()->ensureUserAgentShadowRoot();
     1140    m_hasCreatedShadowSubtree = true;
     1141    createShadowSubtree();
     1142}
     1143
    11281144} // namespace WebCore
  • trunk/Source/WebCore/html/InputType.h

    r290086 r290284  
    207207    bool isEnumeratable() const;
    208208    bool needsShadowSubtree() const { return !nonShadowRootTypes.contains(m_type); }
     209    bool hasCreatedShadowSubtree() const { return m_hasCreatedShadowSubtree; }
    209210
    210211    // Form value functions.
     
    307308    // Shadow tree handling.
    308309
    309     virtual void createShadowSubtreeAndUpdateInnerTextElementEditability(bool);
     310    void createShadowSubtreeIfNeeded();
     311    virtual void createShadowSubtree();
    310312    virtual void destroyShadowSubtree();
    311313
     
    324326    virtual HTMLElement* dataListButtonElement() const { return nullptr; }
    325327#endif
     328    RefPtr<TextControlInnerTextElement> innerTextElementCreatingShadowSubtreeIfNeeded();
    326329
    327330    // Miscellaneous functions.
     
    414417
    415418    const Type m_type;
     419    bool m_hasCreatedShadowSubtree { false };
    416420    // m_element is null if this InputType is no longer associated with an element (either the element died or changed input type).
    417421    WeakPtr<HTMLInputElement> m_element;
  • trunk/Source/WebCore/html/RangeInputType.cpp

    r290086 r290284  
    134134{
    135135    ASSERT(element());
     136
     137    if (!hasCreatedShadowSubtree())
     138        return;
     139
    136140    if (element()->isDisabledFormControl())
    137141        return;
     
    152156void RangeInputType::handleTouchEvent(TouchEvent& event)
    153157{
     158    ASSERT(element());
     159
     160    if (!hasCreatedShadowSubtree())
     161        return;
     162
    154163#if PLATFORM(IOS_FAMILY)
    155164    typedSliderThumbElement().handleTouchEvent(event);
    156165#elif ENABLE(TOUCH_SLIDER)
    157     ASSERT(element());
     166
    158167    if (element()->isDisabledFormControl())
    159168        return;
     
    184193void RangeInputType::disabledStateChanged()
    185194{
     195    if (!hasCreatedShadowSubtree())
     196        return;
    186197    typedSliderThumbElement().hostDisabledStateChanged();
    187198}
     
    190201{
    191202    ASSERT(element());
     203
     204    if (!hasCreatedShadowSubtree())
     205        return ShouldCallBaseEventHandler::Yes;
     206
    192207    if (element()->isDisabledFormControl())
    193208        return ShouldCallBaseEventHandler::Yes;
     
    242257}
    243258
    244 void RangeInputType::createShadowSubtreeAndUpdateInnerTextElementEditability(bool)
     259void RangeInputType::createShadowSubtree()
    245260{
    246261    ASSERT(needsShadowSubtree());
     
    260275{
    261276    ASSERT(element());
     277
     278    if (!hasCreatedShadowSubtree())
     279        return nullptr;
     280
    262281    ASSERT(element()->userAgentShadowRoot());
    263282    ASSERT(element()->userAgentShadowRoot()->firstChild()); // container
     
    278297SliderThumbElement& RangeInputType::typedSliderThumbElement() const
    279298{
     299    ASSERT(hasCreatedShadowSubtree());
    280300    ASSERT(sliderTrackElement()->firstChild()); // thumb
    281301    ASSERT(sliderTrackElement()->firstChild()->isHTMLElement());
     
    323343                element->setValue(element->value());
    324344        }
    325         typedSliderThumbElement().setPositionFromValue();
     345        if (hasCreatedShadowSubtree())
     346            typedSliderThumbElement().setPositionFromValue();
    326347    }
    327348    InputType::attributeChanged(name);
     
    340361    }
    341362
    342     typedSliderThumbElement().setPositionFromValue();
     363    if (hasCreatedShadowSubtree())
     364        typedSliderThumbElement().setPositionFromValue();
    343365}
    344366
     
    369391    m_tickMarkValuesDirty = true;
    370392    RefPtr<HTMLElement> sliderTrackElement = this->sliderTrackElement();
    371     if (sliderTrackElement->renderer())
     393    if (sliderTrackElement && sliderTrackElement->renderer())
    372394        sliderTrackElement->renderer()->setNeedsLayout();
    373395}
  • trunk/Source/WebCore/html/RangeInputType.h

    r290086 r290284  
    5353    ShouldCallBaseEventHandler handleKeydownEvent(KeyboardEvent&) final;
    5454    RenderPtr<RenderElement> createInputRenderer(RenderStyle&&) final;
    55     void createShadowSubtreeAndUpdateInnerTextElementEditability(bool) final;
     55    void createShadowSubtree() final;
    5656    Decimal parseToNumber(const String&, const Decimal&) const final;
    5757    String serialize(const Decimal&) const final;
  • trunk/Source/WebCore/html/SearchInputType.cpp

    r290086 r290284  
    103103}
    104104
    105 void SearchInputType::createShadowSubtreeAndUpdateInnerTextElementEditability(bool isInnerTextElementEditable)
     105void SearchInputType::createShadowSubtree()
    106106{
    107107    ASSERT(needsShadowSubtree());
     
    109109    ASSERT(!m_cancelButton);
    110110
    111     TextFieldInputType::createShadowSubtreeAndUpdateInnerTextElementEditability(isInnerTextElementEditable);
     111    TextFieldInputType::createShadowSubtree();
    112112    RefPtr<HTMLElement> container = containerElement();
    113113    RefPtr<HTMLElement> textWrapper = innerBlockElement();
  • trunk/Source/WebCore/html/SearchInputType.h

    r290086 r290284  
    5252    const AtomString& formControlType() const final;
    5353    bool needsContainer() const final;
    54     void createShadowSubtreeAndUpdateInnerTextElementEditability(bool) final;
     54    void createShadowSubtree() final;
    5555    void destroyShadowSubtree() final;
    5656    HTMLElement* resultsButtonElement() const final;
  • trunk/Source/WebCore/html/TextFieldInputType.cpp

    r290086 r290284  
    109109{
    110110    auto innerText = innerTextElement();
    111     ASSERT(innerText);
     111    if (!innerText) {
     112        // Since we always create the shadow subtree if a value is set, we know
     113        // that the value is empty.
     114        return true;
     115    }
    112116
    113117    for (Text* text = TextNodeTraversal::firstWithin(*innerText); text; text = TextNodeTraversal::next(*text, innerText.get())) {
     
    222226void TextFieldInputType::forwardEvent(Event& event)
    223227{
     228    ASSERT(element());
     229
    224230    if (m_innerSpinButton) {
    225231        m_innerSpinButton->forwardEvent(event);
     
    232238    if (isFocusEvent || isBlurEvent)
    233239        capsLockStateMayHaveChanged();
    234     if (event.isMouseEvent() || isFocusEvent || isBlurEvent) {
    235         ASSERT(element());
     240    if (event.isMouseEvent() || isFocusEvent || isBlurEvent)
    236241        element()->forwardEvent(event);
    237     }
    238242}
    239243
     
    317321}
    318322
    319 void TextFieldInputType::createShadowSubtreeAndUpdateInnerTextElementEditability(bool isInnerTextElementEditable)
     323void TextFieldInputType::createShadowSubtree()
    320324{
    321325    ASSERT(needsShadowSubtree());
    322326    ASSERT(element());
    323327    ASSERT(element()->shadowRoot());
     328    ASSERT(!element()->shadowRoot()->hasChildNodes());
    324329
    325330    ASSERT(!m_innerText);
     
    332337    bool shouldHaveSpinButton = this->shouldHaveSpinButton();
    333338    bool shouldHaveCapsLockIndicator = this->shouldHaveCapsLockIndicator();
    334     bool createsContainer = shouldHaveSpinButton || shouldHaveCapsLockIndicator || needsContainer();
    335 
    336     m_innerText = TextControlInnerTextElement::create(document, isInnerTextElementEditable);
     339    bool shouldDrawAutoFillButton = this->shouldDrawAutoFillButton();
     340#if ENABLE(DATALIST_ELEMENT)
     341    bool hasDataList = element()->list();
     342#endif
     343    bool createsContainer = shouldHaveSpinButton || shouldHaveCapsLockIndicator || shouldDrawAutoFillButton
     344#if ENABLE(DATALIST_ELEMENT)
     345        || hasDataList
     346#endif
     347        || needsContainer();
     348
     349    m_innerText = TextControlInnerTextElement::create(document, element()->isInnerTextElementEditable());
    337350
    338351    if (!createsContainer) {
     
    359372        m_container->appendChild(ContainerNode::ChildChange::Source::Parser, *m_capsLockIndicator);
    360373    }
     374
    361375    updateAutoFillButton();
     376
     377#if ENABLE(DATALIST_ELEMENT)
     378    dataListMayHaveChanged();
     379#endif
    362380}
    363381
     
    374392RefPtr<TextControlInnerTextElement> TextFieldInputType::innerTextElement() const
    375393{
    376     ASSERT(m_innerText);
    377394    return m_innerText;
    378395}
     
    426443void TextFieldInputType::disabledStateChanged()
    427444{
     445    if (!hasCreatedShadowSubtree())
     446        return;
     447
    428448    if (m_innerSpinButton)
    429449        m_innerSpinButton->releaseCapture();
     
    434454void TextFieldInputType::readOnlyStateChanged()
    435455{
     456    if (!hasCreatedShadowSubtree())
     457        return;
     458
    436459    if (m_innerSpinButton)
    437460        m_innerSpinButton->releaseCapture();
     
    617640void TextFieldInputType::updatePlaceholderText()
    618641{
     642    ASSERT(element());
     643
     644    if (!hasCreatedShadowSubtree())
     645        return;
     646
    619647    if (!supportsPlaceholder())
    620648        return;
    621     ASSERT(element());
     649
    622650    String placeholderText = element()->placeholder();
    623651    if (placeholderText.isEmpty()) {
     
    817845void TextFieldInputType::updateAutoFillButton()
    818846{
     847    ASSERT(element());
     848
     849    if (!hasCreatedShadowSubtree())
     850        return;
     851
    819852    capsLockStateMayHaveChanged();
    820853
     
    823856            createContainer();
    824857
    825         ASSERT(element());
    826858        AutoFillButtonType autoFillButtonType = element()->autoFillButtonType();
    827859        if (!m_autoFillButton)
     
    847879void TextFieldInputType::dataListMayHaveChanged()
    848880{
     881    if (!hasCreatedShadowSubtree())
     882        return;
     883
    849884    m_cachedSuggestions = { };
    850885
  • trunk/Source/WebCore/html/TextFieldInputType.h

    r290086 r290284  
    7171
    7272    virtual bool needsContainer() const;
    73     void createShadowSubtreeAndUpdateInnerTextElementEditability(bool) override;
     73    void createShadowSubtree() override;
    7474    void destroyShadowSubtree() override;
    7575    void attributeChanged(const QualifiedName&) override;
Note: See TracChangeset for help on using the changeset viewer.