#include "config.h"
#include "ShadowRoot.h"
#include "Element.h"
#include "Document.h"
#include "NodeRareData.h"
#include "ShadowContentElement.h"
namespace WebCore {
static inline void forceReattach(Node* node)
{
if (!node->attached())
return;
node->detach();
node->attach();
}
class ShadowContentSelector {
WTF_MAKE_NONCOPYABLE(ShadowContentSelector);
public:
explicit ShadowContentSelector(ShadowRoot*);
~ShadowContentSelector();
void attachChildrenFor(ShadowContentElement*);
ShadowRoot* shadowRoot() const { return m_shadowRoot; }
Element* activeElement() const { return m_activeElement; }
static ShadowContentSelector* currentInstance() { return s_currentInstance; }
private:
ShadowContentSelector* m_parent;
ShadowRoot* m_shadowRoot;
Element* m_activeElement;
Vector<RefPtr<Node> > m_children;
static ShadowContentSelector* s_currentInstance;
};
ShadowContentSelector* ShadowContentSelector::s_currentInstance = 0;
ShadowContentSelector::ShadowContentSelector(ShadowRoot* shadowRoot)
: m_parent(s_currentInstance)
, m_shadowRoot(shadowRoot)
, m_activeElement(0)
{
s_currentInstance = this;
for (Node* node = shadowRoot->shadowHost()->firstChild(); node; node = node->nextSibling())
m_children.append(node);
}
ShadowContentSelector::~ShadowContentSelector()
{
ASSERT(s_currentInstance == this);
s_currentInstance = m_parent;
}
void ShadowContentSelector::attachChildrenFor(ShadowContentElement* contentElement)
{
m_activeElement = contentElement;
for (size_t i = 0; i < m_children.size(); ++i) {
Node* child = m_children[i].get();
if (!child)
continue;
if (!contentElement->shouldInclude(child))
continue;
forceReattach(child);
m_children[i] = 0;
}
m_activeElement = 0;
}
void ShadowContentElement::attach()
{
ASSERT(!firstChild()); HTMLDivElement::attach();
if (ShadowContentSelector* selector = ShadowContentSelector::currentInstance())
selector->attachChildrenFor(this);
}
ShadowRoot::ShadowRoot(Document* document)
: TreeScope(document)
{
ASSERT(document);
setParentTreeScope(document);
ensureRareData()->setTreeScope(this);
}
ShadowRoot::~ShadowRoot()
{
}
String ShadowRoot::nodeName() const
{
return "#shadow-root";
}
Node::NodeType ShadowRoot::nodeType() const
{
return SHADOW_ROOT_NODE;
}
PassRefPtr<Node> ShadowRoot::cloneNode(bool)
{
return 0;
}
bool ShadowRoot::childTypeAllowed(NodeType type) const
{
switch (type) {
case ELEMENT_NODE:
case PROCESSING_INSTRUCTION_NODE:
case COMMENT_NODE:
case TEXT_NODE:
case CDATA_SECTION_NODE:
case ENTITY_REFERENCE_NODE:
return true;
default:
return false;
}
}
void ShadowRoot::recalcStyle(StyleChange change)
{
if (hasContentElement())
forceReattach(this);
else {
for (Node* n = firstChild(); n; n = n->nextSibling())
n->recalcStyle(change);
}
clearNeedsStyleRecalc();
clearChildNeedsStyleRecalc();
}
ContainerNode* ShadowRoot::activeContentContainer()
{
ShadowContentSelector* selector = ShadowContentSelector::currentInstance();
if (!selector || selector->shadowRoot() != this)
return 0;
return selector->activeElement();
}
void ShadowRoot::hostChildrenChanged()
{
if (!hasContentElement())
return;
setNeedsStyleRecalc();
}
bool ShadowRoot::hasContentElement() const
{
for (Node* n = firstChild(); n; n = n->traverseNextNode(this)) {
if (n->isShadowBoundary())
return true;
}
return false;
}
bool ShadowRoot::applyAuthorSheets() const
{
return false;
}
void ShadowRoot::attach()
{
ShadowContentSelector selector(this);
TreeScope::attach();
}
}