⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 118886 in webkit


Ignore:
Timestamp:
May 29, 2012, 8:33:21 PM (14 years ago)
Author:
morrita@google.com
Message:

[Shadow DOM] Node distribution should be orthogonal from node attachment
https://bugs.webkit.org/show_bug.cgi?id=87223

Reviewed by Dimitri Glazkov.

This chagne reorganizes Shadow DOM subtree distribution implementation.

Originally, it was interleaved across attach() of several classes like
InsertionPoint and ShadowRoot. Its invalidation was also mixed as a part of
the style recalculation and detach()-es.

This change extracts these bits of code to a set of ContentDistributor methods, which are
facaded by two ElementShadow API. Following two API are the primary entry points:

  • ElementShadow::ensureDistribution()
  • ElementShadow::invalidateDistribution()

The actual implementations are ContentDistributor::distribute() and
ContentDistributor::invalidate() respectively.

When clients need to traverse composed tree, before attach() for
example, they should call ensureDistribution() to make sure that
the traversal data structure ("the distribution") is ready. When
there is any DOM mutation which can result a composed tree
mutation, then clients should call invalidateDistribution() to
mark the distribution being dated.

Here are such DOM mutations:

  • The children of any ShadowRoots are changed,
  • The children of any InsertionPoints are changed,
  • The children of any host elements are changed,
  • Any insertion point is inserted to or removed from the shadow tree,
  • @select attribute of <content> is modified and
  • New ShadowRoot is added to the shadow tree.

Note that the validity of the distribution is tracked and
unnecessary distribution requests are ignored.

After the invalidation, that shadow subtrees are detached once and
request their re-attachment through the style recalculation.
Then, on the responding style recalculation and attach(), new
distribution will be computed.

No new tests. Covered by existing tests.

  • dom/Element.cpp:

(WebCore::Element::~Element):
(WebCore::Element::childrenChanged):

  • dom/ElementShadow.cpp:

(WebCore::ElementShadow::~ElementShadow):
(WebCore::ElementShadow::addShadowRoot):
(WebCore::ElementShadow::removeAllShadowRoots):
(WebCore::ElementShadow::attach):
(WebCore::ElementShadow::recalcStyle):
(WebCore::ElementShadow::ensureDistribution):
(WebCore::ElementShadow::invalidateDistribution):

  • dom/ElementShadow.h:

(ElementShadow):

  • dom/NodeRenderingContext.cpp:

(WebCore::NodeRenderingContext::NodeRenderingContext):
(WebCore::NodeRendererFactory::createRendererIfNeeded):

  • dom/NodeRenderingContext.h:

(NodeRenderingContext):

  • dom/ShadowRoot.cpp:

(WebCore::ShadowRoot::setApplyAuthorStyles):
(WebCore::ShadowRoot::attach):
(WebCore::ShadowRoot::childrenChanged):
(WebCore):

  • dom/ShadowRoot.h:

(ShadowRoot):

  • html/HTMLFormControlElement.cpp:
  • html/ValidationMessage.cpp:

(WebCore::ValidationMessage::buildBubbleTree):

  • html/shadow/ContentDistributor.cpp:

(WebCore::ContentDistributor::ContentDistributor):
(WebCore::ContentDistributor::~ContentDistributor):
(WebCore::ContentDistributor::findInsertionPointFor):
(WebCore::ContentDistributor::distribute):
(WebCore::ContentDistributor::invalidate):
(WebCore::ContentDistributor::finishInivalidation):
(WebCore::ContentDistributor::distributeSelectionsTo):
(WebCore::ContentDistributor::distributeShadowChildrenTo):
(WebCore::ContentDistributor::invalidateDistributionIn):

  • html/shadow/ContentDistributor.h:

(WebCore::ContentDistributor::needsInvalidation):
(ContentDistributor):
(WebCore::ContentDistributor::needsDistribution):

  • html/shadow/HTMLContentElement.cpp:

(WebCore::HTMLContentElement::parseAttribute):

  • html/shadow/InsertionPoint.cpp:

(WebCore::InsertionPoint::attach):
(WebCore::InsertionPoint::detach):
(WebCore::InsertionPoint::nextTo):
(WebCore::InsertionPoint::previousTo):
(WebCore::InsertionPoint::childrenChanged):

  • html/shadow/InsertionPoint.h:

(WebCore::InsertionPoint::setDistribution):
(WebCore::InsertionPoint::clearDistribution):
(InsertionPoint):

Location:
trunk/Source/WebCore
Files:
15 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r118885 r118886  
     12012-05-29  MORITA Hajime  <morrita@google.com>
     2
     3        [Shadow DOM] Node distribution should be orthogonal from node attachment
     4        https://bugs.webkit.org/show_bug.cgi?id=87223
     5
     6        Reviewed by Dimitri Glazkov.
     7
     8        This chagne reorganizes Shadow DOM subtree distribution implementation.
     9
     10        Originally, it was interleaved across attach() of several classes like
     11        InsertionPoint and ShadowRoot. Its invalidation was also mixed as a part of
     12        the style recalculation and detach()-es.
     13
     14        This change extracts these bits of code to a set of ContentDistributor methods, which are
     15        facaded by two ElementShadow API. Following two API are the primary entry points:
     16
     17        - ElementShadow::ensureDistribution()
     18        - ElementShadow::invalidateDistribution()
     19
     20        The actual implementations are ContentDistributor::distribute() and
     21        ContentDistributor::invalidate() respectively.
     22
     23        When clients need to traverse composed tree, before attach() for
     24        example, they should call ensureDistribution() to make sure that
     25        the traversal data structure ("the distribution") is ready.  When
     26        there is any DOM mutation which can result a composed tree
     27        mutation, then clients should call invalidateDistribution() to
     28        mark the distribution being dated.
     29
     30        Here are such DOM mutations:
     31
     32        - The children of any ShadowRoots are changed,
     33        - The children of any InsertionPoints are changed,
     34        - The children of any host elements are changed,
     35        - Any insertion point is inserted to or removed from the shadow tree,
     36        - @select attribute of <content> is modified and
     37        - New ShadowRoot is added to the shadow tree.
     38
     39        Note that the validity of the distribution is tracked and
     40        unnecessary distribution requests are ignored.
     41
     42        After the invalidation, that shadow subtrees are detached once and
     43        request  their  re-attachment  through  the  style  recalculation.
     44        Then,  on the  responding  style recalculation  and attach(),  new
     45        distribution will be computed.
     46
     47        No new tests. Covered by existing tests.
     48
     49        * dom/Element.cpp:
     50        (WebCore::Element::~Element):
     51        (WebCore::Element::childrenChanged):
     52        * dom/ElementShadow.cpp:
     53        (WebCore::ElementShadow::~ElementShadow):
     54        (WebCore::ElementShadow::addShadowRoot):
     55        (WebCore::ElementShadow::removeAllShadowRoots):
     56        (WebCore::ElementShadow::attach):
     57        (WebCore::ElementShadow::recalcStyle):
     58        (WebCore::ElementShadow::ensureDistribution):
     59        (WebCore::ElementShadow::invalidateDistribution):
     60        * dom/ElementShadow.h:
     61        (ElementShadow):
     62        * dom/NodeRenderingContext.cpp:
     63        (WebCore::NodeRenderingContext::NodeRenderingContext):
     64        (WebCore::NodeRendererFactory::createRendererIfNeeded):
     65        * dom/NodeRenderingContext.h:
     66        (NodeRenderingContext):
     67        * dom/ShadowRoot.cpp:
     68        (WebCore::ShadowRoot::setApplyAuthorStyles):
     69        (WebCore::ShadowRoot::attach):
     70        (WebCore::ShadowRoot::childrenChanged):
     71        (WebCore):
     72        * dom/ShadowRoot.h:
     73        (ShadowRoot):
     74        * html/HTMLFormControlElement.cpp:
     75        * html/ValidationMessage.cpp:
     76        (WebCore::ValidationMessage::buildBubbleTree):
     77        * html/shadow/ContentDistributor.cpp:
     78        (WebCore::ContentDistributor::ContentDistributor):
     79        (WebCore::ContentDistributor::~ContentDistributor):
     80        (WebCore::ContentDistributor::findInsertionPointFor):
     81        (WebCore::ContentDistributor::distribute):
     82        (WebCore::ContentDistributor::invalidate):
     83        (WebCore::ContentDistributor::finishInivalidation):
     84        (WebCore::ContentDistributor::distributeSelectionsTo):
     85        (WebCore::ContentDistributor::distributeShadowChildrenTo):
     86        (WebCore::ContentDistributor::invalidateDistributionIn):
     87        * html/shadow/ContentDistributor.h:
     88        (WebCore::ContentDistributor::needsInvalidation):
     89        (ContentDistributor):
     90        (WebCore::ContentDistributor::needsDistribution):
     91        * html/shadow/HTMLContentElement.cpp:
     92        (WebCore::HTMLContentElement::parseAttribute):
     93        * html/shadow/InsertionPoint.cpp:
     94        (WebCore::InsertionPoint::attach):
     95        (WebCore::InsertionPoint::detach):
     96        (WebCore::InsertionPoint::nextTo):
     97        (WebCore::InsertionPoint::previousTo):
     98        (WebCore::InsertionPoint::childrenChanged):
     99        * html/shadow/InsertionPoint.h:
     100        (WebCore::InsertionPoint::setDistribution):
     101        (WebCore::InsertionPoint::clearDistribution):
     102        (InsertionPoint):
     103
    11042012-05-29  Luke Macpherson  <macpherson@chromium.org>
    2105
  • trunk/Source/WebCore/dom/Element.cpp

    r118804 r118886  
    133133#endif
    134134
    135     if (shadow())
     135    if (ElementShadow* elementShadow = shadow()) {
     136        elementShadow->removeAllShadowRoots();
    136137        rareData()->m_shadow.clear();
     138    }
    137139
    138140    if (hasAttrList()) {
     
    13311333
    13321334    if (ElementShadow * shadow = this->shadow())
    1333         shadow->hostChildrenChanged();
     1335        shadow->invalidateDistribution();
    13341336}
    13351337
  • trunk/Source/WebCore/dom/ElementShadow.cpp

    r118654 r118886  
    4545ElementShadow::~ElementShadow()
    4646{
    47     removeAllShadowRoots();
     47    ASSERT(m_shadowRoots.isEmpty());
    4848}
    4949
     
    7575
    7676    shadowRoot->setHost(shadowHost);
     77    m_shadowRoots.push(shadowRoot.get());
     78    invalidateDistribution(shadowHost);
    7779    ChildNodeInsertionNotifier(shadowHost).notify(shadowRoot.get());
    7880
    79     if (shadowHost->attached()) {
    80         shadowRoot->lazyAttach();
    81         detach();
    82         shadowHost->detachChildren();
    83     }
    84 
    85     m_shadowRoots.push(shadowRoot.get());
     81    if (shadowHost->attached() && !shadowRoot->attached())
     82        shadowRoot->attach();
     83
    8684    InspectorInstrumentation::didPushShadowRoot(shadowHost, shadowRoot.get());
    8785}
     
    9290    Element* shadowHost = host();
    9391
    94     while (RefPtr<ShadowRoot> oldRoot = m_shadowRoots.removeHead()) {
     92    while (RefPtr<ShadowRoot> oldRoot = m_shadowRoots.head()) {
    9593        InspectorInstrumentation::willPopShadowRoot(shadowHost, oldRoot.get());
    9694        shadowHost->document()->removeFocusedNodeOfSubtree(oldRoot.get());
     
    9997            oldRoot->detach();
    10098
     99        m_shadowRoots.removeHead();
    101100        oldRoot->setHost(0);
    102101        oldRoot->setPrev(0);
     
    106105    }
    107106
    108     if (shadowHost->attached())
    109         shadowHost->attachChildrenLazily();
     107    invalidateDistribution(shadowHost);
    110108}
    111109
    112110void ElementShadow::attach()
    113111{
    114     // The pool nodes are populated lazily in
    115     // ensureDistributor(), and here we just ensure that it is in clean state.
    116     ASSERT(!distributor().poolIsReady());
    117 
    118     distributor().willDistribute();
     112    ensureDistribution();
    119113    for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) {
    120114        if (!root->attached())
    121115            root->attach();
    122116    }
    123     distributor().didDistribute();
    124117}
    125118
     
    168161void ElementShadow::recalcStyle(Node::StyleChange change)
    169162{
    170     ShadowRoot* youngest = youngestShadowRoot();
    171     if (!youngest)
    172         return;
    173 
    174     if (needsRedistributing())
    175         reattachHostChildrenAndShadow();
    176     else {
    177         StyleResolver* styleResolver = youngest->document()->styleResolver();
    178 
    179         styleResolver->pushParentShadowRoot(youngest);
    180         for (Node* n = youngest->firstChild(); n; n = n->nextSibling()) {
     163    for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) {
     164        StyleResolver* styleResolver = root->document()->styleResolver();
     165        styleResolver->pushParentShadowRoot(root);
     166
     167        for (Node* n = root->firstChild(); n; n = n->nextSibling()) {
    181168            if (n->isElementNode())
    182169                static_cast<Element*>(n)->recalcStyle(change);
     
    184171                toText(n)->recalcTextStyle(change);
    185172        }
    186         styleResolver->popParentShadowRoot(youngest);
    187     }
    188 
    189     m_distributor.clearNeedsRedistributing();
    190     for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) {
     173
     174        styleResolver->popParentShadowRoot(root);
    191175        root->clearNeedsStyleRecalc();
    192176        root->clearChildNeedsStyleRecalc();
     
    194178}
    195179
    196 bool ElementShadow::needsRedistributing()
    197 {
    198     return m_distributor.needsRedistributing() || (youngestShadowRoot() && youngestShadowRoot()->hasInsertionPoint());
    199 }
    200 
    201 void ElementShadow::hostChildrenChanged()
    202 {
    203     ASSERT(youngestShadowRoot());
    204 
    205     if (!youngestShadowRoot()->hasInsertionPoint())
     180void ElementShadow::ensureDistribution()
     181{
     182    if (!m_distributor.needsDistribution())
    206183        return;
    207 
    208     // This results in forced detaching/attaching of the shadow render tree. See ShadowRoot::recalcStyle().
    209     setNeedsRedistributing();
    210 }
    211 
    212 void ElementShadow::setNeedsRedistributing()
    213 {
    214     m_distributor.setNeedsRedistributing();
    215     host()->setNeedsStyleRecalc();
    216 }
    217 
    218 void ElementShadow::reattachHostChildrenAndShadow()
    219 {
    220     ASSERT(youngestShadowRoot());
    221 
    222     Element* hostNode = youngestShadowRoot()->host();
    223     hostNode->detachChildrenIfNeeded();
    224     detach();
    225     attach();
    226     hostNode->attachChildrenIfNeeded();
     184    m_distributor.distribute(host());
     185}
     186
     187void ElementShadow::invalidateDistribution()
     188{
     189    invalidateDistribution(host());
     190}
     191
     192void ElementShadow::invalidateDistribution(Element* host)
     193{
     194    if (!m_distributor.needsInvalidation())
     195        return;
     196    bool needsReattach = m_distributor.invalidate(host);
     197    if (needsReattach && host->attached()) {
     198        host->detach();
     199        host->lazyAttach(Node::DoNotSetAttached);
     200    }
     201
     202    m_distributor.finishInivalidation();
    227203}
    228204
  • trunk/Source/WebCore/dom/ElementShadow.h

    r118654 r118886  
    5353    ShadowRoot* oldestShadowRoot() const;
    5454
     55    void removeAllShadowRoots();
    5556    void addShadowRoot(Element* shadowHost, PassRefPtr<ShadowRoot>, ExceptionCode&);
    5657
     
    6162    bool needsStyleRecalc();
    6263    void recalcStyle(Node::StyleChange);
    63     void setNeedsRedistributing();
    64     bool needsRedistributing();
    65     void hostChildrenChanged();
    6664
     65    void ensureDistribution();
     66    void invalidateDistribution();
     67 
    6768    InsertionPoint* insertionPointFor(const Node*) const;
    6869
     
    7172
    7273private:
    73     void removeAllShadowRoots();
    74     void reattachHostChildrenAndShadow();
     74    void invalidateDistribution(Element* host);
    7575
    7676    DoublyLinkedList<ShadowRoot> m_shadowRoots;
  • trunk/Source/WebCore/dom/NodeRenderingContext.cpp

    r117723 r118886  
    7878
    7979        if (m_visualParentShadow) {
     80            m_visualParentShadow->ensureDistribution();
     81
    8082            if ((m_insertionPoint = m_visualParentShadow->insertionPointFor(m_node))) {
    8183                if (m_insertionPoint->shadowRoot()->isUsedForRendering()) {
     
    9294
    9395        if (isShadowBoundary(parent)) {
    94             if (!parent->shadowRoot()->isUsedForRendering()) {
     96            ShadowRoot* parentShadowRoot = parent->shadowRoot();
     97            parentShadowRoot->owner()->ensureDistribution();
     98
     99            if (!parentShadowRoot->isUsedForRendering()) {
    95100                m_phase = AttachingNotDistributed;
    96101                m_parentNodeForRenderingAndStyle = parent;
     
    284289    ASSERT(m_phase != Calculating);
    285290    return m_parentNodeForRenderingAndStyle ? m_parentNodeForRenderingAndStyle->renderer() : 0;
    286 }
    287 
    288 void NodeRenderingContext::hostChildrenChanged()
    289 {
    290     if (m_phase == AttachingNotDistributed && m_visualParentShadow)
    291         m_visualParentShadow->hostChildrenChanged();
    292291}
    293292
     
    367366    ASSERT(document->shouldCreateRenderers());
    368367
    369     // FIXME: This side effect should be visible from attach() code.
    370     m_context.hostChildrenChanged();
    371 
    372368    if (!m_context.shouldCreateRenderer())
    373369        return;
  • trunk/Source/WebCore/dom/NodeRenderingContext.h

    r116277 r118886  
    6060
    6161    bool shouldCreateRenderer() const;
    62 
    63     void hostChildrenChanged();
    6462
    6563    bool isOnUpperEncapsulationBoundary() const;
  • trunk/Source/WebCore/dom/ShadowRoot.cpp

    r118570 r118886  
    190190    if (m_applyAuthorStyles != value) {
    191191        m_applyAuthorStyles = value;
    192         if (attached() && owner())
    193             owner()->setNeedsRedistributing();
     192        host()->setNeedsStyleRecalc();
    194193    }
    195194}
     
    199198    StyleResolver* styleResolver = document()->styleResolver();
    200199    styleResolver->pushParentShadowRoot(this);
    201     DocumentFragment::attach();
     200    attachChildrenIfNeeded();
     201    attachAsNode();
    202202    styleResolver->popParentShadowRoot(this);
    203203}
    204204
    205 }
     205void ShadowRoot::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
     206{
     207    ContainerNode::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
     208    owner()->invalidateDistribution();
     209}
     210
     211}
  • trunk/Source/WebCore/dom/ShadowRoot.h

    r118131 r118886  
    6161
    6262    InsertionPoint* insertionPointFor(Node*) const;
    63     void hostChildrenChanged();
    6463
    6564    virtual bool applyAuthorStyles() const OVERRIDE;
     
    9291    ShadowRoot(Document*);
    9392    virtual ~ShadowRoot();
    94 
    9593    virtual String nodeName() const;
    9694    virtual PassRefPtr<Node> cloneNode(bool deep);
    9795    virtual bool childTypeAllowed(NodeType) const;
     96    virtual void childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta) OVERRIDE;
    9897
    9998    ShadowRoot* m_prev;
  • trunk/Source/WebCore/html/HTMLFormControlElement.cpp

    r118725 r118886  
    2727
    2828#include "Attribute.h"
     29#include "ElementShadow.h"
    2930#include "Event.h"
    3031#include "EventHandler.h"
  • trunk/Source/WebCore/html/ValidationMessage.cpp

    r116277 r118886  
    133133{
    134134    HTMLElement* host = toHTMLElement(m_element);
     135
    135136    Document* doc = host->document();
    136137    m_bubble = HTMLDivElement::create(doc);
     
    142143    host->ensureShadowRoot()->appendChild(m_bubble.get(), ec);
    143144    ASSERT(!ec);
     145    host->document()->updateLayout();
    144146    adjustBubblePosition(host->getRect(), m_bubble.get());
    145147
  • trunk/Source/WebCore/html/shadow/ContentDistributor.cpp

    r118131 r118886  
    2929
    3030#include "ContentSelectorQuery.h"
     31#include "ElementShadow.h"
    3132#include "HTMLContentElement.h"
    3233#include "ShadowRoot.h"
     
    3637
    3738ContentDistributor::ContentDistributor()
    38     : m_phase(Prevented)
    39     , m_needsRedistributing(false)
     39    : m_validity(Undetermined)
    4040{
    4141}
     
    4343ContentDistributor::~ContentDistributor()
    4444{
    45     ASSERT(m_pool.isEmpty());
    46 }
    47 
    48 void ContentDistributor::distribute(InsertionPoint* insertionPoint, ContentDistribution* distribution)
    49 {
    50     ASSERT(m_phase == Prepared);
    51     ASSERT(distribution->isEmpty());
    52 
    53     ContentSelectorQuery query(insertionPoint);
    54 
    55     for (size_t i = 0; i < m_pool.size(); ++i) {
    56         Node* child = m_pool[i].get();
    57         if (!child)
    58             continue;
    59         if (!query.matches(child))
    60             continue;
    61 
    62         distribution->append(child);
    63         m_nodeToInsertionPoint.add(child, insertionPoint);
    64         m_pool[i] = 0;
    65     }
    66 }
    67 
    68 void ContentDistributor::clearDistribution(ContentDistribution* list)
    69 {
    70     for (size_t i = 0; i < list->size(); ++i)
    71         m_nodeToInsertionPoint.remove(list->at(i).get());
    72     list->clear();
    7345}
    7446
     
    7850}
    7951
    80 void ContentDistributor::willDistribute()
     52
     53void ContentDistributor::distribute(Element* host)
    8154{
    82     m_phase = Started;
     55    ASSERT(needsDistribution());
     56    ASSERT(m_nodeToInsertionPoint.isEmpty());
     57
     58    m_validity = Valid;
     59
     60    ContentDistribution pool;
     61    for (Node* node = host->firstChild(); node; node = node->nextSibling())
     62        pool.append(node);
     63
     64    for (ShadowRoot* root = host->youngestShadowRoot(); root; root = root->olderShadowRoot()) {
     65        for (Node* node = root; node; node = node->traverseNextNode(root)) {
     66            if (!isInsertionPoint(node))
     67                continue;
     68            InsertionPoint* point = toInsertionPoint(node);
     69            if (!point->isActive())
     70                continue;
     71            ShadowRoot* older = root->olderShadowRoot();
     72            if (point->doesSelectFromHostChildren())
     73                distributeSelectionsTo(point, pool);
     74            else if (older && !older->assignedTo()) {
     75                distributeShadowChildrenTo(point, older);
     76                older->setAssignedTo(point);
     77            }
     78        }
     79    }
    8380}
    8481
    85 void ContentDistributor::didDistribute()
     82bool ContentDistributor::invalidate(Element* host)
    8683{
    87     ASSERT(m_phase != Prevented);
    88     m_phase = Prevented;
    89     m_pool.clear();
     84    ASSERT(needsInvalidation());
     85    bool needsReattach = (m_validity == Undetermined) || !m_nodeToInsertionPoint.isEmpty();
     86
     87    for (ShadowRoot* root = host->youngestShadowRoot(); root; root = root->olderShadowRoot()) {
     88        root->setAssignedTo(0);
     89
     90        for (Node* node = root; node; node = node->traverseNextNode(root)) {
     91            if (!isInsertionPoint(node))
     92                continue;
     93            needsReattach = needsReattach || true;
     94            InsertionPoint* point = toInsertionPoint(node);
     95            point->clearDistribution();
     96        }
     97    }
     98
     99    m_validity = Invalidating;
     100    m_nodeToInsertionPoint.clear();
     101    return needsReattach;
    90102}
    91103
    92 void ContentDistributor::preparePoolFor(Element* shadowHost)
     104void ContentDistributor::finishInivalidation()
    93105{
    94     if (poolIsReady())
    95         return;
     106    ASSERT(m_validity == Invalidating);
     107    m_validity = Invalidated;
     108}
    96109
    97     ASSERT(m_pool.isEmpty());
    98     ASSERT(shadowHost);
    99     ASSERT(m_phase == Started);
     110void ContentDistributor::distributeSelectionsTo(InsertionPoint* insertionPoint, ContentDistribution& pool)
     111{
     112    ContentDistribution distribution;
     113    ContentSelectorQuery query(insertionPoint);
    100114
    101     m_phase = Prepared;
    102     for (Node* node = shadowHost->firstChild(); node; node = node->nextSibling())
    103         m_pool.append(node);
     115    for (size_t i = 0; i < pool.size(); ++i) {
     116        Node* child = pool[i].get();
     117        if (!child)
     118            continue;
     119        if (!query.matches(child))
     120            continue;
     121
     122        distribution.append(child);
     123        m_nodeToInsertionPoint.add(child, insertionPoint);
     124        pool[i] = 0;
     125    }
     126
     127    insertionPoint->setDistribution(distribution);
     128}
     129
     130void ContentDistributor::distributeShadowChildrenTo(InsertionPoint* insertionPoint, ShadowRoot* root)
     131{
     132    ContentDistribution distribution;
     133    for (Node* node = root->firstChild(); node; node = node->nextSibling()) {
     134        distribution.append(node);
     135        m_nodeToInsertionPoint.add(node, insertionPoint);
     136    }
     137
     138    insertionPoint->setDistribution(distribution);
     139}
     140
     141void ContentDistributor::invalidateDistributionIn(ContentDistribution* list)
     142{
     143    for (size_t i = 0; i < list->size(); ++i)
     144        m_nodeToInsertionPoint.remove(list->at(i).get());
     145    list->clear();
    104146}
    105147
  • trunk/Source/WebCore/html/shadow/ContentDistributor.h

    r118131 r118886  
    4949    WTF_MAKE_NONCOPYABLE(ContentDistributor);
    5050public:
     51    enum Validity {
     52        Valid = 0,
     53        Invalidated = 1,
     54        Invalidating = 2,
     55        Undetermined = 3
     56    };
     57
    5158    ContentDistributor();
    5259    ~ContentDistributor();
    5360
    54     void distribute(InsertionPoint*, ContentDistribution*);
    55     void clearDistribution(ContentDistribution*);
    5661    InsertionPoint* findInsertionPointFor(const Node* key) const;
    5762
    58     void willDistribute();
    59     bool inDistribution() const;
    60     void didDistribute();
     63    void distribute(Element* host);
     64    bool invalidate(Element* host);
     65    void finishInivalidation();
     66    bool needsDistribution() const;
     67    bool needsInvalidation() const { return m_validity != Invalidated; }
    6168
    62     void preparePoolFor(Element* shadowHost);
    63     bool poolIsReady() const;
    64     bool needsRedistributing() const { return m_needsRedistributing; }
    65     void setNeedsRedistributing() { m_needsRedistributing = true; }
    66     void clearNeedsRedistributing() { m_needsRedistributing = false; }
     69    void distributeSelectionsTo(InsertionPoint*, ContentDistribution& pool);
     70    void distributeShadowChildrenTo(InsertionPoint*, ShadowRoot*);
     71    void invalidateDistributionIn(ContentDistribution*);
     72
    6773private:
    68     enum DistributionPhase {
    69         Prevented,
    70         Started,
    71         Prepared,
    72     };
    73 
    74     Vector<RefPtr<Node> > m_pool;
    75     DistributionPhase m_phase;
    7674    HashMap<const Node*, InsertionPoint*> m_nodeToInsertionPoint;
    77     bool m_needsRedistributing : 1;
     75    unsigned m_validity : 2;
    7876};
    7977
    80 inline bool ContentDistributor::inDistribution() const
     78inline bool ContentDistributor::needsDistribution() const
    8179{
    82     return m_phase != Prevented;
    83 }
    84 
    85 inline bool ContentDistributor::poolIsReady() const
    86 {
    87     return m_phase == Prepared;
     80    // During the invalidation, re-distribution should be supressed.
     81    return m_validity != Valid && m_validity != Invalidating;
    8882}
    8983
  • trunk/Source/WebCore/html/shadow/HTMLContentElement.cpp

    r117898 r118886  
    9292    if (attribute.name() == selectAttr) {
    9393        if (ShadowRoot* root = shadowRoot())
    94             root->owner()->setNeedsRedistributing();
     94            root->owner()->invalidateDistribution();
    9595    } else
    9696        InsertionPoint::parseAttribute(attribute);
  • trunk/Source/WebCore/html/shadow/InsertionPoint.cpp

    r118111 r118886  
    4848void InsertionPoint::attach()
    4949{
    50     if (isShadowBoundary()) {
    51         ShadowRoot* root = toShadowRoot(treeScope()->rootNode());
    52         if (doesSelectFromHostChildren()) {
    53             distributeHostChildren(root->owner());
    54             attachDistributedNode();
    55         } else if (!root->olderShadowRoot()->assignedTo()) {
    56             ASSERT(!root->olderShadowRoot()->attached());
    57             assignShadowRoot(root->olderShadowRoot());
    58             root->olderShadowRoot()->attach();
    59         }
    60     }
    61 
     50    if (ShadowRoot* root = shadowRoot())
     51        root->owner()->ensureDistribution();
     52    for (size_t i = 0; i < m_distribution.size(); ++i)
     53        m_distribution.at(i)->attach();
    6254    HTMLElement::attach();
    6355}
     
    6557void InsertionPoint::detach()
    6658{
    67     ShadowRoot* root = shadowRoot();
    68     if (root && isActive()) {
    69         ElementShadow* shadow = root->owner();
    70 
    71         if (doesSelectFromHostChildren())
    72             clearDistribution(shadow);
    73         else if (ShadowRoot* assignedShadowRoot = assignedFrom())
    74             clearAssignment(assignedShadowRoot);
    75 
    76         // When shadow element is detached, shadow tree should be recreated to re-calculate selector for
    77         // other insertion points.
    78         shadow->setNeedsRedistributing();
    79     }
    80 
    81     ASSERT(m_distribution.isEmpty());
     59    if (ShadowRoot* root = shadowRoot())
     60        root->owner()->ensureDistribution();
     61    for (size_t i = 0; i < m_distribution.size(); ++i)
     62        m_distribution.at(i)->detach();
    8263    HTMLElement::detach();
    83 }
    84 
    85 ShadowRoot* InsertionPoint::assignedFrom() const
    86 {
    87     Node* treeScopeRoot = treeScope()->rootNode();
    88     if (!treeScopeRoot->isShadowRoot())
    89         return 0;
    90 
    91     ShadowRoot* olderShadowRoot = toShadowRoot(treeScopeRoot)->olderShadowRoot();
    92     if (olderShadowRoot && olderShadowRoot->assignedTo() == this)
    93         return olderShadowRoot;
    94     return 0;
    9564}
    9665
     
    11988}
    12089
    121 inline void InsertionPoint::distributeHostChildren(ElementShadow* shadow)
    122 {
    123     if (!shadow->distributor().inDistribution()) {
    124         // If ContentDistributor is not int selecting phase, it means InsertionPoint is attached from
    125         // non-ElementShadow node. To run distribute algorithm, we have to reattach ElementShadow.
    126         shadow->setNeedsRedistributing();
    127         return;
    128     }
    129 
    130     shadow->distributor().preparePoolFor(shadow->host());
    131     shadow->distributor().clearDistribution(&m_distribution);
    132     shadow->distributor().distribute(this, &m_distribution);
    133 }
    134 
    135 inline void InsertionPoint::clearDistribution(ElementShadow* shadow)
    136 {
    137     shadow->distributor().clearDistribution(&m_distribution);
    138 }
    139 
    140 inline void InsertionPoint::attachDistributedNode()
    141 {
    142     for (size_t i = 0; i < m_distribution.size(); ++i)
    143         m_distribution.at(i)->attach();
    144 }
    145 
    146 inline void InsertionPoint::assignShadowRoot(ShadowRoot* shadowRoot)
    147 {
    148     shadowRoot->setAssignedTo(this);
    149     m_distribution.clear();
    150     for (Node* node = shadowRoot->firstChild(); node; node = node->nextSibling())
    151         m_distribution.append(node);
    152 }
    153 
    154 inline void InsertionPoint::clearAssignment(ShadowRoot* shadowRoot)
    155 {
    156     shadowRoot->setAssignedTo(0);
    157     m_distribution.clear();
    158 }
    159 
    16090Node* InsertionPoint::nextTo(const Node* node) const
    16191{
     
    174104}
    175105
     106void InsertionPoint::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
     107{
     108    HTMLElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
     109    if (ShadowRoot* root = shadowRoot())
     110        root->owner()->invalidateDistribution();
     111}
     112
     113Node::InsertionNotificationRequest InsertionPoint::insertedInto(ContainerNode* insertionPoint)
     114{
     115    HTMLElement::insertedInto(insertionPoint);
     116    if (insertionPoint->inDocument()) {
     117        if (ShadowRoot* root = shadowRoot())
     118            root->owner()->invalidateDistribution();
     119    }
     120
     121    return InsertionDone;
     122}
     123
     124void InsertionPoint::removedFrom(ContainerNode* insertionPoint)
     125{
     126    if (insertionPoint->inDocument()) {
     127        Node* parent = parentNode();
     128        if (!parent)
     129            parent = insertionPoint;
     130        if (ShadowRoot* root = parent->shadowRoot()) {
     131            // host can be null when removedFrom() is called from ElementShadow destructor.
     132            if (root->host())
     133                root->owner()->invalidateDistribution();
     134        }
     135
     136        // Since this insertion point is no longer visible from the shadow subtree, it need to clean itself up.
     137        clearDistribution();
     138    }
     139
     140    HTMLElement::removedFrom(insertionPoint);
     141}
     142
    176143
    177144} // namespace WebCore
  • trunk/Source/WebCore/html/shadow/InsertionPoint.h

    r118111 r118886  
    4444
    4545    bool hasDistribution() const { return !m_distribution.isEmpty(); }
     46    void setDistribution(ContentDistribution& distribution) { m_distribution.swap(distribution); }
     47    void clearDistribution() { m_distribution.clear(); }
    4648    bool isShadowBoundary() const;
    4749    bool isActive() const;
     
    5355    virtual void attach();
    5456    virtual void detach();
    55 
    5657    virtual bool isInsertionPoint() const OVERRIDE { return true; }
    57     ShadowRoot* assignedFrom() const;
    5858
    5959    size_t indexOf(Node* node) const { return m_distribution.find(node); }
     
    6868    InsertionPoint(const QualifiedName&, Document*);
    6969    virtual bool rendererIsNeeded(const NodeRenderingContext&) OVERRIDE;
     70    virtual void childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta) OVERRIDE;
     71    virtual InsertionNotificationRequest insertedInto(ContainerNode*) OVERRIDE;
     72    virtual void removedFrom(ContainerNode*) OVERRIDE;
    7073
    7174private:
    72     void distributeHostChildren(ElementShadow*);
    73     void clearDistribution(ElementShadow*);
    74     void attachDistributedNode();
    75 
    76     void assignShadowRoot(ShadowRoot*);
    77     void clearAssignment(ShadowRoot*);
    78 
    7975    ContentDistribution m_distribution;
    8076};
Note: See TracChangeset for help on using the changeset viewer.