This source file includes following definitions.
- invalidate
- scheduleInvalidation
- ensurePendingInvalidationList
- clearInvalidation
- clearPendingInvalidations
- pushInvalidationSet
- matchesCurrentInvalidationSets
- checkInvalidationSetsAgainstElement
- invalidateChildren
- invalidate
#include "config.h"
#include "core/css/invalidation/StyleInvalidator.h"
#include "core/dom/Document.h"
#include "core/dom/Element.h"
#include "core/dom/ElementTraversal.h"
#include "core/dom/shadow/ElementShadow.h"
#include "core/dom/shadow/ShadowRoot.h"
#include "core/rendering/RenderObject.h"
namespace WebCore {
void StyleInvalidator::invalidate(Document& document)
{
if (Element* documentElement = document.documentElement())
invalidate(*documentElement);
document.clearChildNeedsStyleInvalidation();
document.clearNeedsStyleInvalidation();
clearPendingInvalidations();
}
void StyleInvalidator::scheduleInvalidation(PassRefPtr<DescendantInvalidationSet> invalidationSet, Element& element)
{
ensurePendingInvalidationList(element).append(invalidationSet);
element.setNeedsStyleInvalidation();
}
StyleInvalidator::InvalidationList& StyleInvalidator::ensurePendingInvalidationList(Element& element)
{
PendingInvalidationMap::AddResult addResult = m_pendingInvalidationMap.add(&element, nullptr);
if (addResult.isNewEntry)
addResult.storedValue->value = adoptPtr(new InvalidationList);
return *addResult.storedValue->value;
}
void StyleInvalidator::clearInvalidation(Node& node)
{
if (node.isElementNode() && node.needsStyleInvalidation())
m_pendingInvalidationMap.remove(toElement(&node));
node.clearChildNeedsStyleInvalidation();
node.clearNeedsStyleInvalidation();
}
void StyleInvalidator::clearPendingInvalidations()
{
m_pendingInvalidationMap.clear();
}
StyleInvalidator::StyleInvalidator()
{ }
void StyleInvalidator::RecursionData::pushInvalidationSet(const DescendantInvalidationSet& invalidationSet)
{
invalidationSet.getClasses(m_invalidationClasses);
invalidationSet.getAttributes(m_invalidationAttributes);
invalidationSet.getIds(m_invalidationIds);
invalidationSet.getTagNames(m_invalidationTagNames);
m_invalidateCustomPseudo = invalidationSet.customPseudoInvalid();
m_foundInvalidationSet = true;
}
bool StyleInvalidator::RecursionData::matchesCurrentInvalidationSets(Element& element)
{
if (element.hasClass()) {
const SpaceSplitString& classNames = element.classNames();
for (Vector<AtomicString>::const_iterator it = m_invalidationClasses.begin(); it != m_invalidationClasses.end(); ++it) {
if (classNames.contains(*it))
return true;
}
}
if (element.hasAttributes()) {
for (Vector<AtomicString>::const_iterator it = m_invalidationAttributes.begin(); it != m_invalidationAttributes.end(); ++it) {
if (element.hasAttribute(*it))
return true;
}
}
if (element.hasID()) {
const AtomicString& id = element.idForStyleResolution();
if (m_invalidationIds.contains(id))
return true;
}
if (!m_invalidationTagNames.isEmpty() && m_invalidationTagNames.contains(element.tagQName().localName()))
return true;
if (m_invalidateCustomPseudo && element.shadowPseudoId() != nullAtom)
return true;
return false;
}
bool StyleInvalidator::checkInvalidationSetsAgainstElement(Element& element)
{
bool thisElementNeedsStyleRecalc = false;
if (element.needsStyleInvalidation()) {
if (InvalidationList* invalidationList = m_pendingInvalidationMap.get(&element)) {
thisElementNeedsStyleRecalc = true;
for (InvalidationList::const_iterator it = invalidationList->begin(); it != invalidationList->end(); ++it) {
m_recursionData.pushInvalidationSet(**it);
if ((*it)->wholeSubtreeInvalid()) {
element.setNeedsStyleRecalc(SubtreeStyleChange);
break;
}
}
}
}
if (!thisElementNeedsStyleRecalc)
thisElementNeedsStyleRecalc = m_recursionData.matchesCurrentInvalidationSets(element);
return thisElementNeedsStyleRecalc;
}
bool StyleInvalidator::invalidateChildren(Element& element)
{
bool someChildrenNeedStyleRecalc = false;
for (ShadowRoot* root = element.youngestShadowRoot(); root; root = root->olderShadowRoot()) {
for (Element* child = ElementTraversal::firstWithin(*root); child; child = ElementTraversal::nextSibling(*child)) {
bool childRecalced = invalidate(*child);
someChildrenNeedStyleRecalc = someChildrenNeedStyleRecalc || childRecalced;
}
root->clearChildNeedsStyleInvalidation();
root->clearNeedsStyleInvalidation();
}
for (Element* child = ElementTraversal::firstWithin(element); child; child = ElementTraversal::nextSibling(*child)) {
bool childRecalced = invalidate(*child);
someChildrenNeedStyleRecalc = someChildrenNeedStyleRecalc || childRecalced;
}
return someChildrenNeedStyleRecalc;
}
bool StyleInvalidator::invalidate(Element& element)
{
RecursionCheckpoint checkpoint(&m_recursionData);
bool thisElementNeedsStyleRecalc = checkInvalidationSetsAgainstElement(element);
bool someChildrenNeedStyleRecalc = false;
if (m_recursionData.foundInvalidationSet() || element.childNeedsStyleInvalidation())
someChildrenNeedStyleRecalc = invalidateChildren(element);
if (thisElementNeedsStyleRecalc) {
element.setNeedsStyleRecalc(LocalStyleChange);
} else if (m_recursionData.foundInvalidationSet() && someChildrenNeedStyleRecalc) {
if (RenderObject* renderer = element.renderer()) {
ASSERT(renderer->style());
renderer->setStyleInternal(RenderStyle::clone(renderer->style()));
} else {
element.setNeedsStyleRecalc(LocalStyleChange);
}
}
element.clearChildNeedsStyleInvalidation();
element.clearNeedsStyleInvalidation();
return thisElementNeedsStyleRecalc;
}
}