Diff
Modified: trunk/Source/WebCore/ChangeLog (118885 => 118886)
--- trunk/Source/WebCore/ChangeLog 2012-05-30 03:30:23 UTC (rev 118885)
+++ trunk/Source/WebCore/ChangeLog 2012-05-30 03:33:21 UTC (rev 118886)
@@ -1,3 +1,106 @@
+2012-05-29 MORITA Hajime <[email protected]>
+
+ [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):
+
2012-05-29 Luke Macpherson <[email protected]>
Implement post-landing feedback for WebKitCSSTransformValue::customCSSText().
Modified: trunk/Source/WebCore/dom/Element.cpp (118885 => 118886)
--- trunk/Source/WebCore/dom/Element.cpp 2012-05-30 03:30:23 UTC (rev 118885)
+++ trunk/Source/WebCore/dom/Element.cpp 2012-05-30 03:33:21 UTC (rev 118886)
@@ -132,8 +132,10 @@
}
#endif
- if (shadow())
+ if (ElementShadow* elementShadow = shadow()) {
+ elementShadow->removeAllShadowRoots();
rareData()->m_shadow.clear();
+ }
if (hasAttrList()) {
ASSERT(m_attributeData);
@@ -1330,7 +1332,7 @@
checkForSiblingStyleChanges(this, renderStyle(), false, beforeChange, afterChange, childCountDelta);
if (ElementShadow * shadow = this->shadow())
- shadow->hostChildrenChanged();
+ shadow->invalidateDistribution();
}
void Element::beginParsingChildren()
Modified: trunk/Source/WebCore/dom/ElementShadow.cpp (118885 => 118886)
--- trunk/Source/WebCore/dom/ElementShadow.cpp 2012-05-30 03:30:23 UTC (rev 118885)
+++ trunk/Source/WebCore/dom/ElementShadow.cpp 2012-05-30 03:33:21 UTC (rev 118886)
@@ -44,7 +44,7 @@
ElementShadow::~ElementShadow()
{
- removeAllShadowRoots();
+ ASSERT(m_shadowRoots.isEmpty());
}
static bool validateShadowRoot(Document* document, ShadowRoot* shadowRoot, ExceptionCode& ec)
@@ -74,15 +74,13 @@
return;
shadowRoot->setHost(shadowHost);
+ m_shadowRoots.push(shadowRoot.get());
+ invalidateDistribution(shadowHost);
ChildNodeInsertionNotifier(shadowHost).notify(shadowRoot.get());
- if (shadowHost->attached()) {
- shadowRoot->lazyAttach();
- detach();
- shadowHost->detachChildren();
- }
+ if (shadowHost->attached() && !shadowRoot->attached())
+ shadowRoot->attach();
- m_shadowRoots.push(shadowRoot.get());
InspectorInstrumentation::didPushShadowRoot(shadowHost, shadowRoot.get());
}
@@ -91,13 +89,14 @@
// Dont protect this ref count.
Element* shadowHost = host();
- while (RefPtr<ShadowRoot> oldRoot = m_shadowRoots.removeHead()) {
+ while (RefPtr<ShadowRoot> oldRoot = m_shadowRoots.head()) {
InspectorInstrumentation::willPopShadowRoot(shadowHost, oldRoot.get());
shadowHost->document()->removeFocusedNodeOfSubtree(oldRoot.get());
if (oldRoot->attached())
oldRoot->detach();
+ m_shadowRoots.removeHead();
oldRoot->setHost(0);
oldRoot->setPrev(0);
oldRoot->setNext(0);
@@ -105,22 +104,16 @@
ChildNodeRemovalNotifier(shadowHost).notify(oldRoot.get());
}
- if (shadowHost->attached())
- shadowHost->attachChildrenLazily();
+ invalidateDistribution(shadowHost);
}
void ElementShadow::attach()
{
- // The pool nodes are populated lazily in
- // ensureDistributor(), and here we just ensure that it is in clean state.
- ASSERT(!distributor().poolIsReady());
-
- distributor().willDistribute();
+ ensureDistribution();
for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) {
if (!root->attached())
root->attach();
}
- distributor().didDistribute();
}
void ElementShadow::detach()
@@ -167,63 +160,46 @@
void ElementShadow::recalcStyle(Node::StyleChange change)
{
- ShadowRoot* youngest = youngestShadowRoot();
- if (!youngest)
- return;
+ for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) {
+ StyleResolver* styleResolver = root->document()->styleResolver();
+ styleResolver->pushParentShadowRoot(root);
- if (needsRedistributing())
- reattachHostChildrenAndShadow();
- else {
- StyleResolver* styleResolver = youngest->document()->styleResolver();
-
- styleResolver->pushParentShadowRoot(youngest);
- for (Node* n = youngest->firstChild(); n; n = n->nextSibling()) {
+ for (Node* n = root->firstChild(); n; n = n->nextSibling()) {
if (n->isElementNode())
static_cast<Element*>(n)->recalcStyle(change);
else if (n->isTextNode())
toText(n)->recalcTextStyle(change);
}
- styleResolver->popParentShadowRoot(youngest);
- }
- m_distributor.clearNeedsRedistributing();
- for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) {
+ styleResolver->popParentShadowRoot(root);
root->clearNeedsStyleRecalc();
root->clearChildNeedsStyleRecalc();
}
}
-bool ElementShadow::needsRedistributing()
+void ElementShadow::ensureDistribution()
{
- return m_distributor.needsRedistributing() || (youngestShadowRoot() && youngestShadowRoot()->hasInsertionPoint());
-}
-
-void ElementShadow::hostChildrenChanged()
-{
- ASSERT(youngestShadowRoot());
-
- if (!youngestShadowRoot()->hasInsertionPoint())
+ if (!m_distributor.needsDistribution())
return;
-
- // This results in forced detaching/attaching of the shadow render tree. See ShadowRoot::recalcStyle().
- setNeedsRedistributing();
+ m_distributor.distribute(host());
}
-void ElementShadow::setNeedsRedistributing()
+void ElementShadow::invalidateDistribution()
{
- m_distributor.setNeedsRedistributing();
- host()->setNeedsStyleRecalc();
+ invalidateDistribution(host());
}
-void ElementShadow::reattachHostChildrenAndShadow()
+void ElementShadow::invalidateDistribution(Element* host)
{
- ASSERT(youngestShadowRoot());
+ if (!m_distributor.needsInvalidation())
+ return;
+ bool needsReattach = m_distributor.invalidate(host);
+ if (needsReattach && host->attached()) {
+ host->detach();
+ host->lazyAttach(Node::DoNotSetAttached);
+ }
- Element* hostNode = youngestShadowRoot()->host();
- hostNode->detachChildrenIfNeeded();
- detach();
- attach();
- hostNode->attachChildrenIfNeeded();
+ m_distributor.finishInivalidation();
}
} // namespace
Modified: trunk/Source/WebCore/dom/ElementShadow.h (118885 => 118886)
--- trunk/Source/WebCore/dom/ElementShadow.h 2012-05-30 03:30:23 UTC (rev 118885)
+++ trunk/Source/WebCore/dom/ElementShadow.h 2012-05-30 03:33:21 UTC (rev 118886)
@@ -52,6 +52,7 @@
ShadowRoot* youngestShadowRoot() const;
ShadowRoot* oldestShadowRoot() const;
+ void removeAllShadowRoots();
void addShadowRoot(Element* shadowHost, PassRefPtr<ShadowRoot>, ExceptionCode&);
void attach();
@@ -60,18 +61,17 @@
bool childNeedsStyleRecalc();
bool needsStyleRecalc();
void recalcStyle(Node::StyleChange);
- void setNeedsRedistributing();
- bool needsRedistributing();
- void hostChildrenChanged();
+ void ensureDistribution();
+ void invalidateDistribution();
+
InsertionPoint* insertionPointFor(const Node*) const;
ContentDistributor& distributor();
const ContentDistributor& distributor() const;
private:
- void removeAllShadowRoots();
- void reattachHostChildrenAndShadow();
+ void invalidateDistribution(Element* host);
DoublyLinkedList<ShadowRoot> m_shadowRoots;
ContentDistributor m_distributor;
Modified: trunk/Source/WebCore/dom/NodeRenderingContext.cpp (118885 => 118886)
--- trunk/Source/WebCore/dom/NodeRenderingContext.cpp 2012-05-30 03:30:23 UTC (rev 118885)
+++ trunk/Source/WebCore/dom/NodeRenderingContext.cpp 2012-05-30 03:33:21 UTC (rev 118886)
@@ -77,6 +77,8 @@
m_visualParentShadow = toShadowRoot(parent)->owner();
if (m_visualParentShadow) {
+ m_visualParentShadow->ensureDistribution();
+
if ((m_insertionPoint = m_visualParentShadow->insertionPointFor(m_node))) {
if (m_insertionPoint->shadowRoot()->isUsedForRendering()) {
m_phase = AttachingDistributed;
@@ -91,7 +93,10 @@
}
if (isShadowBoundary(parent)) {
- if (!parent->shadowRoot()->isUsedForRendering()) {
+ ShadowRoot* parentShadowRoot = parent->shadowRoot();
+ parentShadowRoot->owner()->ensureDistribution();
+
+ if (!parentShadowRoot->isUsedForRendering()) {
m_phase = AttachingNotDistributed;
m_parentNodeForRenderingAndStyle = parent;
return;
@@ -285,12 +290,6 @@
return m_parentNodeForRenderingAndStyle ? m_parentNodeForRenderingAndStyle->renderer() : 0;
}
-void NodeRenderingContext::hostChildrenChanged()
-{
- if (m_phase == AttachingNotDistributed && m_visualParentShadow)
- m_visualParentShadow->hostChildrenChanged();
-}
-
bool NodeRenderingContext::shouldCreateRenderer() const
{
ASSERT(m_phase != Calculating);
@@ -366,9 +365,6 @@
ASSERT(!node->renderer());
ASSERT(document->shouldCreateRenderers());
- // FIXME: This side effect should be visible from attach() code.
- m_context.hostChildrenChanged();
-
if (!m_context.shouldCreateRenderer())
return;
Modified: trunk/Source/WebCore/dom/NodeRenderingContext.h (118885 => 118886)
--- trunk/Source/WebCore/dom/NodeRenderingContext.h 2012-05-30 03:30:23 UTC (rev 118885)
+++ trunk/Source/WebCore/dom/NodeRenderingContext.h 2012-05-30 03:33:21 UTC (rev 118886)
@@ -60,8 +60,6 @@
bool shouldCreateRenderer() const;
- void hostChildrenChanged();
-
bool isOnUpperEncapsulationBoundary() const;
bool isOnEncapsulationBoundary() const;
bool hasFlowThreadParent() const { return m_parentFlowRenderer; }
Modified: trunk/Source/WebCore/dom/ShadowRoot.cpp (118885 => 118886)
--- trunk/Source/WebCore/dom/ShadowRoot.cpp 2012-05-30 03:30:23 UTC (rev 118885)
+++ trunk/Source/WebCore/dom/ShadowRoot.cpp 2012-05-30 03:33:21 UTC (rev 118886)
@@ -189,8 +189,7 @@
{
if (m_applyAuthorStyles != value) {
m_applyAuthorStyles = value;
- if (attached() && owner())
- owner()->setNeedsRedistributing();
+ host()->setNeedsStyleRecalc();
}
}
@@ -198,8 +197,15 @@
{
StyleResolver* styleResolver = document()->styleResolver();
styleResolver->pushParentShadowRoot(this);
- DocumentFragment::attach();
+ attachChildrenIfNeeded();
+ attachAsNode();
styleResolver->popParentShadowRoot(this);
}
+void ShadowRoot::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
+{
+ ContainerNode::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
+ owner()->invalidateDistribution();
}
+
+}
Modified: trunk/Source/WebCore/dom/ShadowRoot.h (118885 => 118886)
--- trunk/Source/WebCore/dom/ShadowRoot.h 2012-05-30 03:30:23 UTC (rev 118885)
+++ trunk/Source/WebCore/dom/ShadowRoot.h 2012-05-30 03:33:21 UTC (rev 118886)
@@ -60,7 +60,6 @@
void recalcShadowTreeStyle(StyleChange);
InsertionPoint* insertionPointFor(Node*) const;
- void hostChildrenChanged();
virtual bool applyAuthorStyles() const OVERRIDE;
void setApplyAuthorStyles(bool);
@@ -91,10 +90,10 @@
private:
ShadowRoot(Document*);
virtual ~ShadowRoot();
-
virtual String nodeName() const;
virtual PassRefPtr<Node> cloneNode(bool deep);
virtual bool childTypeAllowed(NodeType) const;
+ virtual void childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta) OVERRIDE;
ShadowRoot* m_prev;
ShadowRoot* m_next;
Modified: trunk/Source/WebCore/html/HTMLFormControlElement.cpp (118885 => 118886)
--- trunk/Source/WebCore/html/HTMLFormControlElement.cpp 2012-05-30 03:30:23 UTC (rev 118885)
+++ trunk/Source/WebCore/html/HTMLFormControlElement.cpp 2012-05-30 03:33:21 UTC (rev 118886)
@@ -26,6 +26,7 @@
#include "HTMLFormControlElement.h"
#include "Attribute.h"
+#include "ElementShadow.h"
#include "Event.h"
#include "EventHandler.h"
#include "EventNames.h"
Modified: trunk/Source/WebCore/html/ValidationMessage.cpp (118885 => 118886)
--- trunk/Source/WebCore/html/ValidationMessage.cpp 2012-05-30 03:30:23 UTC (rev 118885)
+++ trunk/Source/WebCore/html/ValidationMessage.cpp 2012-05-30 03:33:21 UTC (rev 118886)
@@ -132,6 +132,7 @@
void ValidationMessage::buildBubbleTree(Timer<ValidationMessage>*)
{
HTMLElement* host = toHTMLElement(m_element);
+
Document* doc = host->document();
m_bubble = HTMLDivElement::create(doc);
m_bubble->setShadowPseudoId("-webkit-validation-bubble");
@@ -141,6 +142,7 @@
ExceptionCode ec = 0;
host->ensureShadowRoot()->appendChild(m_bubble.get(), ec);
ASSERT(!ec);
+ host->document()->updateLayout();
adjustBubblePosition(host->getRect(), m_bubble.get());
RefPtr<HTMLDivElement> clipper = HTMLDivElement::create(doc);
Modified: trunk/Source/WebCore/html/shadow/ContentDistributor.cpp (118885 => 118886)
--- trunk/Source/WebCore/html/shadow/ContentDistributor.cpp 2012-05-30 03:30:23 UTC (rev 118885)
+++ trunk/Source/WebCore/html/shadow/ContentDistributor.cpp 2012-05-30 03:33:21 UTC (rev 118886)
@@ -28,6 +28,7 @@
#include "ContentDistributor.h"
#include "ContentSelectorQuery.h"
+#include "ElementShadow.h"
#include "HTMLContentElement.h"
#include "ShadowRoot.h"
@@ -35,72 +36,113 @@
namespace WebCore {
ContentDistributor::ContentDistributor()
- : m_phase(Prevented)
- , m_needsRedistributing(false)
+ : m_validity(Undetermined)
{
}
ContentDistributor::~ContentDistributor()
{
- ASSERT(m_pool.isEmpty());
}
-void ContentDistributor::distribute(InsertionPoint* insertionPoint, ContentDistribution* distribution)
+InsertionPoint* ContentDistributor::findInsertionPointFor(const Node* key) const
{
- ASSERT(m_phase == Prepared);
- ASSERT(distribution->isEmpty());
+ return m_nodeToInsertionPoint.get(key);
+}
- ContentSelectorQuery query(insertionPoint);
- for (size_t i = 0; i < m_pool.size(); ++i) {
- Node* child = m_pool[i].get();
- if (!child)
- continue;
- if (!query.matches(child))
- continue;
+void ContentDistributor::distribute(Element* host)
+{
+ ASSERT(needsDistribution());
+ ASSERT(m_nodeToInsertionPoint.isEmpty());
- distribution->append(child);
- m_nodeToInsertionPoint.add(child, insertionPoint);
- m_pool[i] = 0;
+ m_validity = Valid;
+
+ ContentDistribution pool;
+ for (Node* node = host->firstChild(); node; node = node->nextSibling())
+ pool.append(node);
+
+ for (ShadowRoot* root = host->youngestShadowRoot(); root; root = root->olderShadowRoot()) {
+ for (Node* node = root; node; node = node->traverseNextNode(root)) {
+ if (!isInsertionPoint(node))
+ continue;
+ InsertionPoint* point = toInsertionPoint(node);
+ if (!point->isActive())
+ continue;
+ ShadowRoot* older = root->olderShadowRoot();
+ if (point->doesSelectFromHostChildren())
+ distributeSelectionsTo(point, pool);
+ else if (older && !older->assignedTo()) {
+ distributeShadowChildrenTo(point, older);
+ older->setAssignedTo(point);
+ }
+ }
}
}
-void ContentDistributor::clearDistribution(ContentDistribution* list)
+bool ContentDistributor::invalidate(Element* host)
{
- for (size_t i = 0; i < list->size(); ++i)
- m_nodeToInsertionPoint.remove(list->at(i).get());
- list->clear();
+ ASSERT(needsInvalidation());
+ bool needsReattach = (m_validity == Undetermined) || !m_nodeToInsertionPoint.isEmpty();
+
+ for (ShadowRoot* root = host->youngestShadowRoot(); root; root = root->olderShadowRoot()) {
+ root->setAssignedTo(0);
+
+ for (Node* node = root; node; node = node->traverseNextNode(root)) {
+ if (!isInsertionPoint(node))
+ continue;
+ needsReattach = needsReattach || true;
+ InsertionPoint* point = toInsertionPoint(node);
+ point->clearDistribution();
+ }
+ }
+
+ m_validity = Invalidating;
+ m_nodeToInsertionPoint.clear();
+ return needsReattach;
}
-InsertionPoint* ContentDistributor::findInsertionPointFor(const Node* key) const
+void ContentDistributor::finishInivalidation()
{
- return m_nodeToInsertionPoint.get(key);
+ ASSERT(m_validity == Invalidating);
+ m_validity = Invalidated;
}
-void ContentDistributor::willDistribute()
+void ContentDistributor::distributeSelectionsTo(InsertionPoint* insertionPoint, ContentDistribution& pool)
{
- m_phase = Started;
+ ContentDistribution distribution;
+ ContentSelectorQuery query(insertionPoint);
+
+ for (size_t i = 0; i < pool.size(); ++i) {
+ Node* child = pool[i].get();
+ if (!child)
+ continue;
+ if (!query.matches(child))
+ continue;
+
+ distribution.append(child);
+ m_nodeToInsertionPoint.add(child, insertionPoint);
+ pool[i] = 0;
+ }
+
+ insertionPoint->setDistribution(distribution);
}
-void ContentDistributor::didDistribute()
+void ContentDistributor::distributeShadowChildrenTo(InsertionPoint* insertionPoint, ShadowRoot* root)
{
- ASSERT(m_phase != Prevented);
- m_phase = Prevented;
- m_pool.clear();
+ ContentDistribution distribution;
+ for (Node* node = root->firstChild(); node; node = node->nextSibling()) {
+ distribution.append(node);
+ m_nodeToInsertionPoint.add(node, insertionPoint);
+ }
+
+ insertionPoint->setDistribution(distribution);
}
-void ContentDistributor::preparePoolFor(Element* shadowHost)
+void ContentDistributor::invalidateDistributionIn(ContentDistribution* list)
{
- if (poolIsReady())
- return;
-
- ASSERT(m_pool.isEmpty());
- ASSERT(shadowHost);
- ASSERT(m_phase == Started);
-
- m_phase = Prepared;
- for (Node* node = shadowHost->firstChild(); node; node = node->nextSibling())
- m_pool.append(node);
+ for (size_t i = 0; i < list->size(); ++i)
+ m_nodeToInsertionPoint.remove(list->at(i).get());
+ list->clear();
}
}
Modified: trunk/Source/WebCore/html/shadow/ContentDistributor.h (118885 => 118886)
--- trunk/Source/WebCore/html/shadow/ContentDistributor.h 2012-05-30 03:30:23 UTC (rev 118885)
+++ trunk/Source/WebCore/html/shadow/ContentDistributor.h 2012-05-30 03:33:21 UTC (rev 118886)
@@ -48,45 +48,39 @@
class ContentDistributor {
WTF_MAKE_NONCOPYABLE(ContentDistributor);
public:
+ enum Validity {
+ Valid = 0,
+ Invalidated = 1,
+ Invalidating = 2,
+ Undetermined = 3
+ };
+
ContentDistributor();
~ContentDistributor();
- void distribute(InsertionPoint*, ContentDistribution*);
- void clearDistribution(ContentDistribution*);
InsertionPoint* findInsertionPointFor(const Node* key) const;
- void willDistribute();
- bool inDistribution() const;
- void didDistribute();
+ void distribute(Element* host);
+ bool invalidate(Element* host);
+ void finishInivalidation();
+ bool needsDistribution() const;
+ bool needsInvalidation() const { return m_validity != Invalidated; }
- void preparePoolFor(Element* shadowHost);
- bool poolIsReady() const;
- bool needsRedistributing() const { return m_needsRedistributing; }
- void setNeedsRedistributing() { m_needsRedistributing = true; }
- void clearNeedsRedistributing() { m_needsRedistributing = false; }
-private:
- enum DistributionPhase {
- Prevented,
- Started,
- Prepared,
- };
+ void distributeSelectionsTo(InsertionPoint*, ContentDistribution& pool);
+ void distributeShadowChildrenTo(InsertionPoint*, ShadowRoot*);
+ void invalidateDistributionIn(ContentDistribution*);
- Vector<RefPtr<Node> > m_pool;
- DistributionPhase m_phase;
+private:
HashMap<const Node*, InsertionPoint*> m_nodeToInsertionPoint;
- bool m_needsRedistributing : 1;
+ unsigned m_validity : 2;
};
-inline bool ContentDistributor::inDistribution() const
+inline bool ContentDistributor::needsDistribution() const
{
- return m_phase != Prevented;
+ // During the invalidation, re-distribution should be supressed.
+ return m_validity != Valid && m_validity != Invalidating;
}
-inline bool ContentDistributor::poolIsReady() const
-{
- return m_phase == Prepared;
}
-}
-
#endif
Modified: trunk/Source/WebCore/html/shadow/HTMLContentElement.cpp (118885 => 118886)
--- trunk/Source/WebCore/html/shadow/HTMLContentElement.cpp 2012-05-30 03:30:23 UTC (rev 118885)
+++ trunk/Source/WebCore/html/shadow/HTMLContentElement.cpp 2012-05-30 03:33:21 UTC (rev 118886)
@@ -91,7 +91,7 @@
{
if (attribute.name() == selectAttr) {
if (ShadowRoot* root = shadowRoot())
- root->owner()->setNeedsRedistributing();
+ root->owner()->invalidateDistribution();
} else
InsertionPoint::parseAttribute(attribute);
}
Modified: trunk/Source/WebCore/html/shadow/InsertionPoint.cpp (118885 => 118886)
--- trunk/Source/WebCore/html/shadow/InsertionPoint.cpp 2012-05-30 03:30:23 UTC (rev 118885)
+++ trunk/Source/WebCore/html/shadow/InsertionPoint.cpp 2012-05-30 03:33:21 UTC (rev 118886)
@@ -47,53 +47,22 @@
void InsertionPoint::attach()
{
- if (isShadowBoundary()) {
- ShadowRoot* root = toShadowRoot(treeScope()->rootNode());
- if (doesSelectFromHostChildren()) {
- distributeHostChildren(root->owner());
- attachDistributedNode();
- } else if (!root->olderShadowRoot()->assignedTo()) {
- ASSERT(!root->olderShadowRoot()->attached());
- assignShadowRoot(root->olderShadowRoot());
- root->olderShadowRoot()->attach();
- }
- }
-
+ if (ShadowRoot* root = shadowRoot())
+ root->owner()->ensureDistribution();
+ for (size_t i = 0; i < m_distribution.size(); ++i)
+ m_distribution.at(i)->attach();
HTMLElement::attach();
}
void InsertionPoint::detach()
{
- ShadowRoot* root = shadowRoot();
- if (root && isActive()) {
- ElementShadow* shadow = root->owner();
-
- if (doesSelectFromHostChildren())
- clearDistribution(shadow);
- else if (ShadowRoot* assignedShadowRoot = assignedFrom())
- clearAssignment(assignedShadowRoot);
-
- // When shadow element is detached, shadow tree should be recreated to re-calculate selector for
- // other insertion points.
- shadow->setNeedsRedistributing();
- }
-
- ASSERT(m_distribution.isEmpty());
+ if (ShadowRoot* root = shadowRoot())
+ root->owner()->ensureDistribution();
+ for (size_t i = 0; i < m_distribution.size(); ++i)
+ m_distribution.at(i)->detach();
HTMLElement::detach();
}
-ShadowRoot* InsertionPoint::assignedFrom() const
-{
- Node* treeScopeRoot = treeScope()->rootNode();
- if (!treeScopeRoot->isShadowRoot())
- return 0;
-
- ShadowRoot* olderShadowRoot = toShadowRoot(treeScopeRoot)->olderShadowRoot();
- if (olderShadowRoot && olderShadowRoot->assignedTo() == this)
- return olderShadowRoot;
- return 0;
-}
-
bool InsertionPoint::isShadowBoundary() const
{
return treeScope()->rootNode()->isShadowRoot() && isActive();
@@ -118,59 +87,57 @@
return !isShadowBoundary() && HTMLElement::rendererIsNeeded(context);
}
-inline void InsertionPoint::distributeHostChildren(ElementShadow* shadow)
+Node* InsertionPoint::nextTo(const Node* node) const
{
- if (!shadow->distributor().inDistribution()) {
- // If ContentDistributor is not int selecting phase, it means InsertionPoint is attached from
- // non-ElementShadow node. To run distribute algorithm, we have to reattach ElementShadow.
- shadow->setNeedsRedistributing();
- return;
- }
-
- shadow->distributor().preparePoolFor(shadow->host());
- shadow->distributor().clearDistribution(&m_distribution);
- shadow->distributor().distribute(this, &m_distribution);
+ size_t index = m_distribution.find(node);
+ if (index == notFound || index + 1 == m_distribution.size())
+ return 0;
+ return m_distribution.at(index + 1).get();
}
-inline void InsertionPoint::clearDistribution(ElementShadow* shadow)
+Node* InsertionPoint::previousTo(const Node* node) const
{
- shadow->distributor().clearDistribution(&m_distribution);
+ size_t index = m_distribution.find(node);
+ if (index == notFound || !index)
+ return 0;
+ return m_distribution.at(index - 1).get();
}
-inline void InsertionPoint::attachDistributedNode()
+void InsertionPoint::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
{
- for (size_t i = 0; i < m_distribution.size(); ++i)
- m_distribution.at(i)->attach();
+ HTMLElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
+ if (ShadowRoot* root = shadowRoot())
+ root->owner()->invalidateDistribution();
}
-inline void InsertionPoint::assignShadowRoot(ShadowRoot* shadowRoot)
+Node::InsertionNotificationRequest InsertionPoint::insertedInto(ContainerNode* insertionPoint)
{
- shadowRoot->setAssignedTo(this);
- m_distribution.clear();
- for (Node* node = shadowRoot->firstChild(); node; node = node->nextSibling())
- m_distribution.append(node);
-}
+ HTMLElement::insertedInto(insertionPoint);
+ if (insertionPoint->inDocument()) {
+ if (ShadowRoot* root = shadowRoot())
+ root->owner()->invalidateDistribution();
+ }
-inline void InsertionPoint::clearAssignment(ShadowRoot* shadowRoot)
-{
- shadowRoot->setAssignedTo(0);
- m_distribution.clear();
+ return InsertionDone;
}
-Node* InsertionPoint::nextTo(const Node* node) const
+void InsertionPoint::removedFrom(ContainerNode* insertionPoint)
{
- size_t index = m_distribution.find(node);
- if (index == notFound || index + 1 == m_distribution.size())
- return 0;
- return m_distribution.at(index + 1).get();
-}
+ if (insertionPoint->inDocument()) {
+ Node* parent = parentNode();
+ if (!parent)
+ parent = insertionPoint;
+ if (ShadowRoot* root = parent->shadowRoot()) {
+ // host can be null when removedFrom() is called from ElementShadow destructor.
+ if (root->host())
+ root->owner()->invalidateDistribution();
+ }
-Node* InsertionPoint::previousTo(const Node* node) const
-{
- size_t index = m_distribution.find(node);
- if (index == notFound || !index)
- return 0;
- return m_distribution.at(index - 1).get();
+ // Since this insertion point is no longer visible from the shadow subtree, it need to clean itself up.
+ clearDistribution();
+ }
+
+ HTMLElement::removedFrom(insertionPoint);
}
Modified: trunk/Source/WebCore/html/shadow/InsertionPoint.h (118885 => 118886)
--- trunk/Source/WebCore/html/shadow/InsertionPoint.h 2012-05-30 03:30:23 UTC (rev 118885)
+++ trunk/Source/WebCore/html/shadow/InsertionPoint.h 2012-05-30 03:33:21 UTC (rev 118886)
@@ -43,6 +43,8 @@
virtual ~InsertionPoint();
bool hasDistribution() const { return !m_distribution.isEmpty(); }
+ void setDistribution(ContentDistribution& distribution) { m_distribution.swap(distribution); }
+ void clearDistribution() { m_distribution.clear(); }
bool isShadowBoundary() const;
bool isActive() const;
@@ -52,9 +54,7 @@
virtual void attach();
virtual void detach();
-
virtual bool isInsertionPoint() const OVERRIDE { return true; }
- ShadowRoot* assignedFrom() const;
size_t indexOf(Node* node) const { return m_distribution.find(node); }
size_t size() const { return m_distribution.size(); }
@@ -67,15 +67,11 @@
protected:
InsertionPoint(const QualifiedName&, Document*);
virtual bool rendererIsNeeded(const NodeRenderingContext&) OVERRIDE;
+ virtual void childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta) OVERRIDE;
+ virtual InsertionNotificationRequest insertedInto(ContainerNode*) OVERRIDE;
+ virtual void removedFrom(ContainerNode*) OVERRIDE;
private:
- void distributeHostChildren(ElementShadow*);
- void clearDistribution(ElementShadow*);
- void attachDistributedNode();
-
- void assignShadowRoot(ShadowRoot*);
- void clearAssignment(ShadowRoot*);
-
ContentDistribution m_distribution;
};