Changeset 207810 in webkit


Ignore:
Timestamp:
Oct 24, 2016 11:18:13 PM (7 years ago)
Author:
rniwa@webkit.org
Message:

Custom elements reactions should have a queue per element
https://bugs.webkit.org/show_bug.cgi?id=163878

Reviewed by Antti Koivisto.

Source/WebCore:

This patch splits the custom elements reaction queue into per element to match the latest HTML specifications:
https://html.spec.whatwg.org/multipage/scripting.html#custom-element-reaction-queue
and introduces the backup element queue:
https://html.spec.whatwg.org/multipage/scripting.html#backup-element-queue

In terms of code changes, CustomElementReactionStack now holds onto ElementQueue, an ordered list of elements,
and make each ElementRareData keep its own CustomElementReactionQueue. CustomElementReactionQueue is created
for each custom element when it is synchronously constructed or enqueued to upgrade.

Because each reaction queue is now specific to each element, CustomElementReactionQueue instead of
CustomElementReactionQueueItem stores JSCustomElementInterface.

The backup element queue is created as a singleton returned by CustomElementReactionStack's backupElementQueue,
and ensureBackupQueue() schedules a new mirotask to process the backup queue when there isn't already one.

ensureCurrentQueue() now returns a reference to CustomElementReactionQueue instead of a pointer since it can
fallback to the backup queue when the stack is empty as specified:
https://html.spec.whatwg.org/multipage/scripting.html#enqueue-an-element-on-the-appropriate-element-queue

Note that ensureCurrentQueue() may insert the same element multiple times into the element queue for now since
avoiding this duplication would require either doing O(n) iteration on m_elements or adding a HashSet.
We can revisit this in the future if the reaction queue is found to grow beyond a few entries since elements in
the element queue will have duplicates only when each reaction queue has more than one item.

Tests: fast/custom-elements/backup-element-queue.html

fast/custom-elements/custom-element-reaction-queue.html

  • bindings/js/JSCustomElementInterface.cpp:

(WebCore::JSCustomElementInterface::upgradeElement):

  • dom/CustomElementReactionQueue.cpp:

(WebCore::CustomElementReactionQueueItem::CustomElementReactionQueueItem):
(WebCore::CustomElementReactionQueueItem::invoke): Removed the check for isFailedCustomElement since the queue
is explicitly cleared in Element::setIsFailedCustomElement.
(WebCore::CustomElementReactionQueue::CustomElementReactionQueue): Now takes JSCustomElementInterface since
each item in the queue no longer stores Element or JSCustomElementInterface.
(WebCore::CustomElementReactionQueue::clear):
(WebCore::CustomElementReactionQueue::enqueueElementUpgrade):
(WebCore::CustomElementReactionQueue::enqueueElementUpgradeIfDefined):
(WebCore::CustomElementReactionQueue::enqueueConnectedCallbackIfNeeded):
(WebCore::CustomElementReactionQueue::enqueueDisconnectedCallbackIfNeeded):
(WebCore::CustomElementReactionQueue::enqueueAdoptedCallbackIfNeeded):
(WebCore::CustomElementReactionQueue::enqueueAttributeChangedCallbackIfNeeded):
(WebCore::CustomElementReactionQueue::enqueuePostUpgradeReactions):
(WebCore::CustomElementReactionQueue::invokeAll):
(WebCore::CustomElementReactionStack::ElementQueue::add): Added.
(WebCore::CustomElementReactionStack::ElementQueue::invokeAll): Added.
(WebCore::CustomElementReactionStack::ensureCurrentQueue):
(WebCore::BackupElementQueueMicrotask): Added.
(WebCore::CustomElementReactionStack::ensureBackupQueue): Added.
(WebCore::CustomElementReactionStack::processBackupQueue): Added.
(WebCore::CustomElementReactionStack::backupElementQueue): Added.

  • dom/CustomElementReactionQueue.h:
  • dom/CustomElementRegistry.cpp:

(WebCore::enqueueUpgradeInShadowIncludingTreeOrder):

  • dom/Document.cpp:

(WebCore::createFallbackHTMLElement):

  • dom/Element.cpp:

(WebCore::Element::setIsDefinedCustomElement): Create a new reaction queue if there isn't already one; when
this element had been upgraded, the reaction queue have already been created in Element::enqueueToUpgrade.
(WebCore::Element::setIsFailedCustomElement): Clear the reaction queue when the upgrading had failed.
(WebCore::Element::enqueueToUpgrade): Added.
(WebCore::Element::reactionQueue): Added.

  • dom/Element.h:
  • dom/ElementRareData.h:

(WebCore::ElementRareData::customElementReactionQueue): Replaced customElementInterface.
(WebCore::ElementRareData::setCustomElementReactionQueue): Replaced setCustomElementReactionQueue.

LayoutTests:

Added a W3C style testharness.js test for making sure the custom element reaction queue exists per element,
and added a WebKit style test for making sure that the backup element queue exists.

  • fast/custom-elements/backup-element-queue-expected.txt: Added.
  • fast/custom-elements/backup-element-queue.html: Added.
  • fast/custom-elements/custom-element-reaction-queue-expected.txt: Added.
  • fast/custom-elements/custom-element-reaction-queue.html: Added.
Location:
trunk
Files:
4 added
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r207809 r207810  
     12016-10-24  Ryosuke Niwa  <rniwa@webkit.org>
     2
     3        Custom elements reactions should have a queue per element
     4        https://bugs.webkit.org/show_bug.cgi?id=163878
     5
     6        Reviewed by Antti Koivisto.
     7
     8        Added a W3C style testharness.js test for making sure the custom element reaction queue exists per element,
     9        and added a WebKit style test for making sure that the backup element queue exists.
     10
     11        * fast/custom-elements/backup-element-queue-expected.txt: Added.
     12        * fast/custom-elements/backup-element-queue.html: Added.
     13        * fast/custom-elements/custom-element-reaction-queue-expected.txt: Added.
     14        * fast/custom-elements/custom-element-reaction-queue.html: Added.
     15
    1162016-10-24  Jiewen Tan  <jiewen_tan@apple.com>
    217
  • trunk/Source/WebCore/ChangeLog

    r207809 r207810  
     12016-10-24  Ryosuke Niwa  <rniwa@webkit.org>
     2
     3        Custom elements reactions should have a queue per element
     4        https://bugs.webkit.org/show_bug.cgi?id=163878
     5
     6        Reviewed by Antti Koivisto.
     7
     8        This patch splits the custom elements reaction queue into per element to match the latest HTML specifications:
     9        https://html.spec.whatwg.org/multipage/scripting.html#custom-element-reaction-queue
     10        and introduces the backup element queue:
     11        https://html.spec.whatwg.org/multipage/scripting.html#backup-element-queue
     12
     13        In terms of code changes, CustomElementReactionStack now holds onto ElementQueue, an ordered list of elements,
     14        and make each ElementRareData keep its own CustomElementReactionQueue. CustomElementReactionQueue is created
     15        for each custom element when it is synchronously constructed or enqueued to upgrade.
     16
     17        Because each reaction queue is now specific to each element, CustomElementReactionQueue instead of
     18        CustomElementReactionQueueItem stores JSCustomElementInterface.
     19
     20        The backup element queue is created as a singleton returned by CustomElementReactionStack's backupElementQueue,
     21        and ensureBackupQueue() schedules a new mirotask to process the backup queue when there isn't already one.
     22
     23        ensureCurrentQueue() now returns a reference to CustomElementReactionQueue instead of a pointer since it can
     24        fallback to the backup queue when the stack is empty as specified:
     25        https://html.spec.whatwg.org/multipage/scripting.html#enqueue-an-element-on-the-appropriate-element-queue
     26
     27        Note that ensureCurrentQueue() may insert the same element multiple times into the element queue for now since
     28        avoiding this duplication would require either doing O(n) iteration on m_elements or adding a HashSet.
     29        We can revisit this in the future if the reaction queue is found to grow beyond a few entries since elements in
     30        the element queue will have duplicates only when each reaction queue has more than one item.
     31
     32        Tests: fast/custom-elements/backup-element-queue.html
     33               fast/custom-elements/custom-element-reaction-queue.html
     34
     35        * bindings/js/JSCustomElementInterface.cpp:
     36        (WebCore::JSCustomElementInterface::upgradeElement):
     37        * dom/CustomElementReactionQueue.cpp:
     38        (WebCore::CustomElementReactionQueueItem::CustomElementReactionQueueItem):
     39        (WebCore::CustomElementReactionQueueItem::invoke): Removed the check for isFailedCustomElement since the queue
     40        is explicitly cleared in Element::setIsFailedCustomElement.
     41        (WebCore::CustomElementReactionQueue::CustomElementReactionQueue): Now takes JSCustomElementInterface since
     42        each item in the queue no longer stores Element or JSCustomElementInterface.
     43        (WebCore::CustomElementReactionQueue::clear):
     44        (WebCore::CustomElementReactionQueue::enqueueElementUpgrade):
     45        (WebCore::CustomElementReactionQueue::enqueueElementUpgradeIfDefined):
     46        (WebCore::CustomElementReactionQueue::enqueueConnectedCallbackIfNeeded):
     47        (WebCore::CustomElementReactionQueue::enqueueDisconnectedCallbackIfNeeded):
     48        (WebCore::CustomElementReactionQueue::enqueueAdoptedCallbackIfNeeded):
     49        (WebCore::CustomElementReactionQueue::enqueueAttributeChangedCallbackIfNeeded):
     50        (WebCore::CustomElementReactionQueue::enqueuePostUpgradeReactions):
     51        (WebCore::CustomElementReactionQueue::invokeAll):
     52        (WebCore::CustomElementReactionStack::ElementQueue::add): Added.
     53        (WebCore::CustomElementReactionStack::ElementQueue::invokeAll): Added.
     54        (WebCore::CustomElementReactionStack::ensureCurrentQueue):
     55        (WebCore::BackupElementQueueMicrotask): Added.
     56        (WebCore::CustomElementReactionStack::ensureBackupQueue): Added.
     57        (WebCore::CustomElementReactionStack::processBackupQueue): Added.
     58        (WebCore::CustomElementReactionStack::backupElementQueue): Added.
     59        * dom/CustomElementReactionQueue.h:
     60        * dom/CustomElementRegistry.cpp:
     61        (WebCore::enqueueUpgradeInShadowIncludingTreeOrder):
     62        * dom/Document.cpp:
     63        (WebCore::createFallbackHTMLElement):
     64        * dom/Element.cpp:
     65        (WebCore::Element::setIsDefinedCustomElement): Create a new reaction queue if there isn't already one; when
     66        this element had been upgraded, the reaction queue have already been created in Element::enqueueToUpgrade.
     67        (WebCore::Element::setIsFailedCustomElement): Clear the reaction queue when the upgrading had failed.
     68        (WebCore::Element::enqueueToUpgrade): Added.
     69        (WebCore::Element::reactionQueue): Added.
     70        * dom/Element.h:
     71        * dom/ElementRareData.h:
     72        (WebCore::ElementRareData::customElementReactionQueue): Replaced customElementInterface.
     73        (WebCore::ElementRareData::setCustomElementReactionQueue): Replaced setCustomElementReactionQueue.
     74
    1752016-10-24  Jiewen Tan  <jiewen_tan@apple.com>
    276
  • trunk/Source/WebCore/bindings/js/JSCustomElementInterface.cpp

    r207710 r207810  
    183183    }
    184184
    185     CustomElementReactionQueue::enqueuePostUpgradeReactions(element, *this);
     185    CustomElementReactionQueue::enqueuePostUpgradeReactions(element);
    186186
    187187    m_constructionStack.append(&element);
  • trunk/Source/WebCore/dom/CustomElementReactionQueue.cpp

    r207710 r207810  
    3535#include "JSCustomElementInterface.h"
    3636#include "JSDOMBinding.h"
     37#include "Microtasks.h"
    3738#include <heap/Heap.h>
    3839#include <wtf/Optional.h>
     
    5152    };
    5253
    53     CustomElementReactionQueueItem(Type type, Element& element, JSCustomElementInterface& elementInterface)
     54    CustomElementReactionQueueItem(Type type)
    5455        : m_type(type)
    55         , m_element(element)
    56         , m_interface(elementInterface)
    5756    { }
    5857
    59     CustomElementReactionQueueItem(Element& element, JSCustomElementInterface& elementInterface, Document& oldDocument, Document& newDocument)
     58    CustomElementReactionQueueItem(Document& oldDocument, Document& newDocument)
    6059        : m_type(Type::Adopted)
    61         , m_element(element)
    62         , m_interface(elementInterface)
    6360        , m_oldDocument(&oldDocument)
    6461        , m_newDocument(&newDocument)
    6562    { }
    6663
    67     CustomElementReactionQueueItem(Element& element, JSCustomElementInterface& elementInterface, const QualifiedName& attributeName, const AtomicString& oldValue, const AtomicString& newValue)
     64    CustomElementReactionQueueItem(const QualifiedName& attributeName, const AtomicString& oldValue, const AtomicString& newValue)
    6865        : m_type(Type::AttributeChanged)
    69         , m_element(element)
    70         , m_interface(elementInterface)
    7166        , m_attributeName(attributeName)
    7267        , m_oldValue(oldValue)
     
    7469    { }
    7570
    76     void invoke()
     71    void invoke(Element& element, JSCustomElementInterface& elementInterface)
    7772    {
    78         if (m_element->isFailedCustomElement())
    79             return;
    8073        switch (m_type) {
    8174        case Type::ElementUpgrade:
    82             m_interface->upgradeElement(m_element.get());
     75            elementInterface.upgradeElement(element);
    8376            break;
    8477        case Type::Connected:
    85             m_interface->invokeConnectedCallback(m_element.get());
     78            elementInterface.invokeConnectedCallback(element);
    8679            break;
    8780        case Type::Disconnected:
    88             m_interface->invokeDisconnectedCallback(m_element.get());
     81            elementInterface.invokeDisconnectedCallback(element);
    8982            break;
    9083        case Type::Adopted:
    91             m_interface->invokeAdoptedCallback(m_element.get(), *m_oldDocument, *m_newDocument);
     84            elementInterface.invokeAdoptedCallback(element, *m_oldDocument, *m_newDocument);
    9285            break;
    9386        case Type::AttributeChanged:
    9487            ASSERT(m_attributeName);
    95             m_interface->invokeAttributeChangedCallback(m_element.get(), m_attributeName.value(), m_oldValue, m_newValue);
     88            elementInterface.invokeAttributeChangedCallback(element, m_attributeName.value(), m_oldValue, m_newValue);
    9689            break;
    9790        }
     
    10093private:
    10194    Type m_type;
    102     Ref<Element> m_element;
    103     Ref<JSCustomElementInterface> m_interface;
    10495    RefPtr<Document> m_oldDocument;
    10596    RefPtr<Document> m_newDocument;
     
    109100};
    110101
    111 CustomElementReactionQueue::CustomElementReactionQueue()
     102CustomElementReactionQueue::CustomElementReactionQueue(JSCustomElementInterface& elementInterface)
     103    : m_interface(elementInterface)
    112104{ }
    113105
     
    117109}
    118110
    119 void CustomElementReactionQueue::enqueueElementUpgrade(Element& element, JSCustomElementInterface& elementInterface)
    120 {
    121     ASSERT(element.tagQName() == elementInterface.name());
    122     if (auto* queue = CustomElementReactionStack::ensureCurrentQueue())
    123         queue->m_items.append({CustomElementReactionQueueItem::Type::ElementUpgrade, element, elementInterface});
     111void CustomElementReactionQueue::clear()
     112{
     113    m_items.clear();
     114}
     115
     116void CustomElementReactionQueue::enqueueElementUpgrade(Element& element)
     117{
     118    auto& queue = CustomElementReactionStack::ensureCurrentQueue(element);
     119    queue.m_items.append({CustomElementReactionQueueItem::Type::ElementUpgrade});
    124120}
    125121
     
    140136        return;
    141137
    142     enqueueElementUpgrade(element, *elementInterface);
     138    element.enqueueToUpgrade(*elementInterface);
    143139}
    144140
     
    146142{
    147143    ASSERT(element.isDefinedCustomElement());
    148     auto* elementInterface = element.customElementInterface();
    149     ASSERT(elementInterface);
    150     if (!elementInterface->hasConnectedCallback())
    151         return;
    152 
    153     if (auto* queue = CustomElementReactionStack::ensureCurrentQueue())
    154         queue->m_items.append({CustomElementReactionQueueItem::Type::Connected, element, *elementInterface});
     144    auto& queue = CustomElementReactionStack::ensureCurrentQueue(element);
     145    if (queue.m_interface->hasConnectedCallback())
     146        queue.m_items.append({CustomElementReactionQueueItem::Type::Connected});
    155147}
    156148
     
    158150{
    159151    ASSERT(element.isDefinedCustomElement());
    160     auto* elementInterface = element.customElementInterface();
    161     ASSERT(elementInterface);
    162     if (!elementInterface->hasDisconnectedCallback())
    163         return;
    164 
    165     if (auto* queue = CustomElementReactionStack::ensureCurrentQueue())
    166         queue->m_items.append({CustomElementReactionQueueItem::Type::Disconnected, element, *elementInterface});
     152    auto& queue = CustomElementReactionStack::ensureCurrentQueue(element);
     153    if (queue.m_interface->hasDisconnectedCallback())
     154        queue.m_items.append({CustomElementReactionQueueItem::Type::Disconnected});
    167155}
    168156
     
    170158{
    171159    ASSERT(element.isDefinedCustomElement());
    172     auto* elementInterface = element.customElementInterface();
    173     ASSERT(elementInterface);
    174     if (!elementInterface->hasAdoptedCallback())
    175         return;
    176 
    177     if (auto* queue = CustomElementReactionStack::ensureCurrentQueue())
    178         queue->m_items.append({element, *elementInterface, oldDocument, newDocument});
     160    auto& queue = CustomElementReactionStack::ensureCurrentQueue(element);
     161    if (queue.m_interface->hasAdoptedCallback())
     162        queue.m_items.append({oldDocument, newDocument});
    179163}
    180164
     
    182166{
    183167    ASSERT(element.isDefinedCustomElement());
    184     auto* elementInterface = element.customElementInterface();
    185     ASSERT(elementInterface);
    186     if (!elementInterface->observesAttribute(attributeName.localName()))
    187         return;
    188 
    189     if (auto* queue = CustomElementReactionStack::ensureCurrentQueue())
    190         queue->m_items.append({element, *elementInterface, attributeName, oldValue, newValue});
    191 }
    192 
    193 void CustomElementReactionQueue::enqueuePostUpgradeReactions(Element& element, JSCustomElementInterface& elementInterface)
    194 {
     168    auto& queue = CustomElementReactionStack::ensureCurrentQueue(element);
     169    if (queue.m_interface->observesAttribute(attributeName.localName()))
     170        queue.m_items.append({attributeName, oldValue, newValue});
     171}
     172
     173void CustomElementReactionQueue::enqueuePostUpgradeReactions(Element& element)
     174{
     175    ASSERT(element.isCustomElementUpgradeCandidate());
    195176    if (!element.hasAttributes() && !element.inDocument())
    196177        return;
    197178
    198     auto* queue = CustomElementReactionStack::ensureCurrentQueue();
    199     if (!queue)
    200         return;
     179    auto* queue = element.reactionQueue();
     180    ASSERT(queue);
    201181
    202182    if (element.hasAttributes()) {
    203183        for (auto& attribute : element.attributesIterator()) {
    204             if (elementInterface.observesAttribute(attribute.localName()))
    205                 queue->m_items.append({element, elementInterface, attribute.name(), nullAtom, attribute.value()});
     184            if (queue->m_interface->observesAttribute(attribute.localName()))
     185                queue->m_items.append({attribute.name(), nullAtom, attribute.value()});
    206186        }
    207187    }
    208188
    209     if (element.inDocument() && elementInterface.hasConnectedCallback())
    210         queue->m_items.append({CustomElementReactionQueueItem::Type::Connected, element, elementInterface});
    211 }
    212 
    213 void CustomElementReactionQueue::invokeAll()
    214 {
    215     // FIXME: This queue needs to be per element.
     189    if (element.inDocument() && queue->m_interface->hasConnectedCallback())
     190        queue->m_items.append({CustomElementReactionQueueItem::Type::Connected});
     191}
     192
     193void CustomElementReactionQueue::invokeAll(Element& element)
     194{
    216195    while (!m_items.isEmpty()) {
    217196        Vector<CustomElementReactionQueueItem> items = WTFMove(m_items);
    218197        for (auto& item : items)
    219             item.invoke();
    220     }
    221 }
    222 
    223 CustomElementReactionQueue* CustomElementReactionStack::ensureCurrentQueue()
    224 {
    225     // FIXME: This early exit indicates a bug that some DOM API is missing CEReactions
    226     if (!s_currentProcessingStack)
    227         return nullptr;
     198            item.invoke(element, m_interface.get());
     199    }
     200}
     201
     202inline void CustomElementReactionStack::ElementQueue::add(Element& element)
     203{
     204    // FIXME: Avoid inserting the same element multiple times.
     205    m_elements.append(element);
     206}
     207
     208inline void CustomElementReactionStack::ElementQueue::invokeAll()
     209{
     210    Vector<Ref<Element>> elements;
     211    elements.swap(m_elements);
     212    for (auto& element : elements) {
     213        auto* queue = element->reactionQueue();
     214        ASSERT(queue);
     215        queue->invokeAll(element.get());
     216    }
     217    ASSERT(m_elements.isEmpty());
     218}
     219
     220CustomElementReactionQueue& CustomElementReactionStack::ensureCurrentQueue(Element& element)
     221{
     222    ASSERT(element.reactionQueue());
     223    if (!s_currentProcessingStack) {
     224        auto& queue = CustomElementReactionStack::ensureBackupQueue();
     225        queue.add(element);
     226        return *element.reactionQueue();
     227    }
    228228
    229229    auto*& queue = s_currentProcessingStack->m_queue;
    230230    if (!queue) // We use a raw pointer to avoid genearing code to delete it in ~CustomElementReactionStack.
    231         queue = new CustomElementReactionQueue;
    232     return queue;
     231        queue = new ElementQueue;
     232    queue->add(element);
     233    return *element.reactionQueue();
    233234}
    234235
     
    243244}
    244245
     246class BackupElementQueueMicrotask final : public Microtask {
     247    WTF_MAKE_FAST_ALLOCATED;
     248private:
     249    Result run() final
     250    {
     251        CustomElementReactionStack::processBackupQueue();
     252        return Result::Done;
     253    }
     254};
     255
     256static bool s_processingBackupElementQueue = false;
     257
     258CustomElementReactionStack::ElementQueue& CustomElementReactionStack::ensureBackupQueue()
     259{
     260    if (!s_processingBackupElementQueue) {
     261        s_processingBackupElementQueue = true;
     262        MicrotaskQueue::mainThreadQueue().append(std::make_unique<BackupElementQueueMicrotask>());
     263    }
     264    return backupElementQueue();
     265}
     266
     267void CustomElementReactionStack::processBackupQueue()
     268{
     269    backupElementQueue().invokeAll();
     270    s_processingBackupElementQueue = false;
     271}
     272
     273CustomElementReactionStack::ElementQueue& CustomElementReactionStack::backupElementQueue()
     274{
     275    static NeverDestroyed<ElementQueue> queue;
     276    return queue.get();
     277}
     278
    245279}
    246280
  • trunk/Source/WebCore/dom/CustomElementReactionQueue.h

    r207710 r207810  
    4343    WTF_MAKE_NONCOPYABLE(CustomElementReactionQueue);
    4444public:
    45     CustomElementReactionQueue();
     45    CustomElementReactionQueue(JSCustomElementInterface&);
    4646    ~CustomElementReactionQueue();
    4747
    48     static void enqueueElementUpgrade(Element&, JSCustomElementInterface&);
     48    static void enqueueElementUpgrade(Element&);
    4949    static void enqueueElementUpgradeIfDefined(Element&);
    5050    static void enqueueConnectedCallbackIfNeeded(Element&);
     
    5252    static void enqueueAdoptedCallbackIfNeeded(Element&, Document& oldDocument, Document& newDocument);
    5353    static void enqueueAttributeChangedCallbackIfNeeded(Element&, const QualifiedName&, const AtomicString& oldValue, const AtomicString& newValue);
    54     static void enqueuePostUpgradeReactions(Element&, JSCustomElementInterface&);
     54    static void enqueuePostUpgradeReactions(Element&);
    5555
    56     void invokeAll();
     56    void invokeAll(Element&);
     57    void clear();
    5758
    5859private:
     60    Ref<JSCustomElementInterface> m_interface;
    5961    Vector<CustomElementReactionQueueItem> m_items;
    6062};
     
    7577    }
    7678
    77     // FIXME: This should be a reference once "ensure" starts to work.
    78     static CustomElementReactionQueue* ensureCurrentQueue();
     79    static CustomElementReactionQueue& ensureCurrentQueue(Element&);
    7980
    8081    static bool hasCurrentProcessingStack() { return s_currentProcessingStack; }
    8182
     83    static void processBackupQueue();
     84
    8285private:
     86    class ElementQueue {
     87    public:
     88        void add(Element&);
     89        void invokeAll();
     90
     91    private:
     92        Vector<Ref<Element>> m_elements;
     93    };
     94
    8395    WEBCORE_EXPORT void processQueue();
    8496
    85     CustomElementReactionQueue* m_queue { nullptr };
     97    static ElementQueue& ensureBackupQueue();
     98    static ElementQueue& backupElementQueue();
     99
     100    ElementQueue* m_queue { nullptr };
    86101    CustomElementReactionStack* m_previousProcessingStack;
    87102
  • trunk/Source/WebCore/dom/CustomElementRegistry.cpp

    r206252 r207810  
    6161    for (Element* element = ElementTraversal::firstWithin(node); element; element = ElementTraversal::next(*element)) {
    6262        if (element->isCustomElementUpgradeCandidate() && element->tagQName() == elementInterface.name())
    63             CustomElementReactionQueue::enqueueElementUpgrade(*element, elementInterface);
     63            element->enqueueToUpgrade(elementInterface);
    6464        if (auto* shadowRoot = element->shadowRoot()) {
    6565            if (shadowRoot->mode() != ShadowRoot::Mode::UserAgent)
  • trunk/Source/WebCore/dom/Document.cpp

    r207669 r207810  
    10761076            if (auto* elementInterface = registry->findInterface(name)) {
    10771077                auto element = HTMLElement::create(name, document);
    1078                 element->setIsCustomElementUpgradeCandidate();
    1079                 CustomElementReactionQueue::enqueueElementUpgrade(element.get(), *elementInterface);
     1078                element->enqueueToUpgrade(*elementInterface);
    10801079                return element;
    10811080            }
  • trunk/Source/WebCore/dom/Element.cpp

    r207669 r207810  
    19031903    clearFlag(IsEditingTextOrUndefinedCustomElementFlag);
    19041904    setFlag(IsCustomElement);
    1905     ensureElementRareData().setCustomElementInterface(elementInterface);
    1906 }
    1907 
    1908 void Element::setIsFailedCustomElement(JSCustomElementInterface& elementInterface)
     1905    auto& data = ensureElementRareData();
     1906    if (!data.customElementReactionQueue())
     1907        data.setCustomElementReactionQueue(std::make_unique<CustomElementReactionQueue>(elementInterface));
     1908}
     1909
     1910void Element::setIsFailedCustomElement(JSCustomElementInterface&)
    19091911{
    19101912    ASSERT(isUndefinedCustomElement());
    19111913    ASSERT(getFlag(IsEditingTextOrUndefinedCustomElementFlag));
    19121914    clearFlag(IsCustomElement);
    1913     ensureElementRareData().setCustomElementInterface(elementInterface);
     1915
     1916    if (hasRareData()) {
     1917        // Clear the queue instead of deleting it since this function can be called inside CustomElementReactionQueue::invokeAll during upgrades.
     1918        if (auto* queue = elementRareData()->customElementReactionQueue())
     1919            queue->clear();
     1920    }
    19141921}
    19151922
     
    19211928}
    19221929
    1923 JSCustomElementInterface* Element::customElementInterface() const
    1924 {
    1925     ASSERT(isDefinedCustomElement());
     1930void Element::enqueueToUpgrade(JSCustomElementInterface& elementInterface)
     1931{
     1932    ASSERT(!isDefinedCustomElement() && !isFailedCustomElement());
     1933    setFlag(IsCustomElement);
     1934    setFlag(IsEditingTextOrUndefinedCustomElementFlag);
     1935
     1936    auto& data = ensureElementRareData();
     1937    ASSERT(!data.customElementReactionQueue());
     1938
     1939    data.setCustomElementReactionQueue(std::make_unique<CustomElementReactionQueue>(elementInterface));
     1940    data.customElementReactionQueue()->enqueueElementUpgrade(*this);
     1941}
     1942
     1943CustomElementReactionQueue* Element::reactionQueue() const
     1944{
     1945    ASSERT(isDefinedCustomElement() || isCustomElementUpgradeCandidate());
    19261946    if (!hasRareData())
    19271947        return nullptr;
    1928     return elementRareData()->customElementInterface();
     1948    return elementRareData()->customElementReactionQueue();
    19291949}
    19301950
  • trunk/Source/WebCore/dom/Element.h

    r207689 r207810  
    4040class ClientRect;
    4141class ClientRectList;
     42class CustomElementReactionQueue;
    4243class DatasetDOMStringMap;
    4344class Dictionary;
     
    285286    void setIsFailedCustomElement(JSCustomElementInterface&);
    286287    void setIsCustomElementUpgradeCandidate();
    287     JSCustomElementInterface* customElementInterface() const;
     288    void enqueueToUpgrade(JSCustomElementInterface&);
     289    CustomElementReactionQueue* reactionQueue() const;
    288290#endif
    289291
  • trunk/Source/WebCore/dom/ElementRareData.h

    r205060 r207810  
    2323#define ElementRareData_h
    2424
     25#include "CustomElementReactionQueue.h"
    2526#include "DOMTokenList.h"
    2627#include "DatasetDOMStringMap.h"
     
    9697
    9798#if ENABLE(CUSTOM_ELEMENTS)
    98     JSCustomElementInterface* customElementInterface() { return m_customElementInterface.get(); }
    99     void setCustomElementInterface(JSCustomElementInterface& customElementInterface) { m_customElementInterface = &customElementInterface; }
     99    CustomElementReactionQueue* customElementReactionQueue() { return m_customElementReactionQueue.get(); }
     100    void setCustomElementReactionQueue(std::unique_ptr<CustomElementReactionQueue>&& queue) { m_customElementReactionQueue = WTFMove(queue); }
    100101#endif
    101102
     
    157158    RefPtr<ShadowRoot> m_shadowRoot;
    158159#if ENABLE(CUSTOM_ELEMENTS)
    159     RefPtr<JSCustomElementInterface> m_customElementInterface;
     160    std::unique_ptr<CustomElementReactionQueue> m_customElementReactionQueue;
    160161#endif
    161162    std::unique_ptr<NamedNodeMap> m_attributeMap;
Note: See TracChangeset for help on using the changeset viewer.