| OLD | NEW |
| (Empty) |
| 1 | |
| 2 // Copyright 2014 The Chromium Authors. All rights reserved. | |
| 3 // Use of this source code is governed by a BSD-style license that can be | |
| 4 // found in the LICENSE file. | |
| 5 | |
| 6 #include "config.h" | |
| 7 | |
| 8 #include "core/css/invalidation/StyleInvalidator.h" | |
| 9 | |
| 10 #include "core/css/invalidation/DescendantInvalidationSet.h" | |
| 11 #include "core/dom/Document.h" | |
| 12 #include "core/dom/Element.h" | |
| 13 #include "core/dom/ElementTraversal.h" | |
| 14 #include "core/dom/shadow/ElementShadow.h" | |
| 15 #include "core/dom/shadow/ShadowRoot.h" | |
| 16 #include "core/rendering/RenderObject.h" | |
| 17 | |
| 18 namespace blink { | |
| 19 | |
| 20 void StyleInvalidator::invalidate(Document& document) | |
| 21 { | |
| 22 RecursionData recursionData; | |
| 23 if (Element* documentElement = document.documentElement()) | |
| 24 invalidate(*documentElement, recursionData); | |
| 25 document.clearChildNeedsStyleInvalidation(); | |
| 26 document.clearNeedsStyleInvalidation(); | |
| 27 clearPendingInvalidations(); | |
| 28 } | |
| 29 | |
| 30 void StyleInvalidator::scheduleInvalidation(PassRefPtr<DescendantInvalidationSet
> invalidationSet, Element& element) | |
| 31 { | |
| 32 ASSERT(element.inActiveDocument()); | |
| 33 ASSERT(element.styleChangeType() < SubtreeStyleChange); | |
| 34 InvalidationList& list = ensurePendingInvalidationList(element); | |
| 35 // If we're already going to invalidate the whole subtree we don't need to s
tore any new sets. | |
| 36 if (!list.isEmpty() && list.last()->wholeSubtreeInvalid()) | |
| 37 return; | |
| 38 // If this set would invalidate the whole subtree we can discard all existin
g sets. | |
| 39 if (invalidationSet->wholeSubtreeInvalid()) | |
| 40 list.clear(); | |
| 41 list.append(invalidationSet); | |
| 42 element.setNeedsStyleInvalidation(); | |
| 43 } | |
| 44 | |
| 45 StyleInvalidator::InvalidationList& StyleInvalidator::ensurePendingInvalidationL
ist(Element& element) | |
| 46 { | |
| 47 PendingInvalidationMap::AddResult addResult = m_pendingInvalidationMap.add(&
element, nullptr); | |
| 48 if (addResult.isNewEntry) | |
| 49 addResult.storedValue->value = adoptPtr(new InvalidationList); | |
| 50 return *addResult.storedValue->value; | |
| 51 } | |
| 52 | |
| 53 void StyleInvalidator::clearInvalidation(Node& node) | |
| 54 { | |
| 55 if (node.isElementNode() && node.needsStyleInvalidation()) | |
| 56 m_pendingInvalidationMap.remove(toElement(&node)); | |
| 57 } | |
| 58 | |
| 59 void StyleInvalidator::clearPendingInvalidations() | |
| 60 { | |
| 61 m_pendingInvalidationMap.clear(); | |
| 62 } | |
| 63 | |
| 64 StyleInvalidator::StyleInvalidator() | |
| 65 { | |
| 66 } | |
| 67 | |
| 68 StyleInvalidator::~StyleInvalidator() | |
| 69 { | |
| 70 } | |
| 71 | |
| 72 void StyleInvalidator::RecursionData::pushInvalidationSet(const DescendantInvali
dationSet& invalidationSet) | |
| 73 { | |
| 74 ASSERT(!m_wholeSubtreeInvalid); | |
| 75 if (invalidationSet.treeBoundaryCrossing()) | |
| 76 m_treeBoundaryCrossing = true; | |
| 77 if (invalidationSet.wholeSubtreeInvalid()) { | |
| 78 m_wholeSubtreeInvalid = true; | |
| 79 return; | |
| 80 } | |
| 81 m_invalidationSets.append(&invalidationSet); | |
| 82 m_invalidateCustomPseudo = invalidationSet.customPseudoInvalid(); | |
| 83 } | |
| 84 | |
| 85 bool StyleInvalidator::RecursionData::matchesCurrentInvalidationSets(Element& el
ement) | |
| 86 { | |
| 87 ASSERT(!m_wholeSubtreeInvalid); | |
| 88 | |
| 89 for (InvalidationSets::iterator it = m_invalidationSets.begin(); it != m_inv
alidationSets.end(); ++it) { | |
| 90 if ((*it)->invalidatesElement(element)) | |
| 91 return true; | |
| 92 } | |
| 93 | |
| 94 return false; | |
| 95 } | |
| 96 | |
| 97 bool StyleInvalidator::checkInvalidationSetsAgainstElement(Element& element, Sty
leInvalidator::RecursionData& recursionData) | |
| 98 { | |
| 99 if (element.styleChangeType() >= SubtreeStyleChange || recursionData.wholeSu
btreeInvalid()) { | |
| 100 recursionData.setWholeSubtreeInvalid(); | |
| 101 return false; | |
| 102 } | |
| 103 if (element.needsStyleInvalidation()) { | |
| 104 if (InvalidationList* invalidationList = m_pendingInvalidationMap.get(&e
lement)) { | |
| 105 for (InvalidationList::const_iterator it = invalidationList->begin()
; it != invalidationList->end(); ++it) | |
| 106 recursionData.pushInvalidationSet(**it); | |
| 107 // FIXME: It's really only necessary to clone the render style for t
his element, not full style recalc. | |
| 108 return true; | |
| 109 } | |
| 110 } | |
| 111 return recursionData.matchesCurrentInvalidationSets(element); | |
| 112 } | |
| 113 | |
| 114 bool StyleInvalidator::invalidateChildren(Element& element, StyleInvalidator::Re
cursionData& recursionData) | |
| 115 { | |
| 116 bool someChildrenNeedStyleRecalc = false; | |
| 117 for (ShadowRoot* root = element.youngestShadowRoot(); root; root = root->old
erShadowRoot()) { | |
| 118 if (!recursionData.treeBoundaryCrossing() && !root->childNeedsStyleInval
idation() && !root->needsStyleInvalidation()) | |
| 119 continue; | |
| 120 for (Element* child = ElementTraversal::firstChild(*root); child; child
= ElementTraversal::nextSibling(*child)) { | |
| 121 bool childRecalced = invalidate(*child, recursionData); | |
| 122 someChildrenNeedStyleRecalc = someChildrenNeedStyleRecalc || childRe
calced; | |
| 123 } | |
| 124 root->clearChildNeedsStyleInvalidation(); | |
| 125 root->clearNeedsStyleInvalidation(); | |
| 126 } | |
| 127 for (Element* child = ElementTraversal::firstChild(element); child; child =
ElementTraversal::nextSibling(*child)) { | |
| 128 bool childRecalced = invalidate(*child, recursionData); | |
| 129 someChildrenNeedStyleRecalc = someChildrenNeedStyleRecalc || childRecalc
ed; | |
| 130 } | |
| 131 return someChildrenNeedStyleRecalc; | |
| 132 } | |
| 133 | |
| 134 bool StyleInvalidator::invalidate(Element& element, StyleInvalidator::RecursionD
ata& recursionData) | |
| 135 { | |
| 136 RecursionCheckpoint checkpoint(&recursionData); | |
| 137 | |
| 138 bool thisElementNeedsStyleRecalc = checkInvalidationSetsAgainstElement(eleme
nt, recursionData); | |
| 139 | |
| 140 bool someChildrenNeedStyleRecalc = false; | |
| 141 if (recursionData.hasInvalidationSets() || element.childNeedsStyleInvalidati
on()) | |
| 142 someChildrenNeedStyleRecalc = invalidateChildren(element, recursionData)
; | |
| 143 | |
| 144 if (thisElementNeedsStyleRecalc) { | |
| 145 element.setNeedsStyleRecalc(recursionData.wholeSubtreeInvalid() ? Subtre
eStyleChange : LocalStyleChange); | |
| 146 } else if (recursionData.hasInvalidationSets() && someChildrenNeedStyleRecal
c) { | |
| 147 // Clone the RenderStyle in order to preserve correct style sharing, if
possible. Otherwise recalc style. | |
| 148 if (RenderObject* renderer = element.renderer()) | |
| 149 renderer->setStyleInternal(RenderStyle::clone(renderer->style())); | |
| 150 else | |
| 151 element.setNeedsStyleRecalc(LocalStyleChange); | |
| 152 } | |
| 153 | |
| 154 element.clearChildNeedsStyleInvalidation(); | |
| 155 element.clearNeedsStyleInvalidation(); | |
| 156 | |
| 157 return thisElementNeedsStyleRecalc; | |
| 158 } | |
| 159 | |
| 160 void StyleInvalidator::trace(Visitor* visitor) | |
| 161 { | |
| 162 #if ENABLE(OILPAN) | |
| 163 visitor->trace(m_pendingInvalidationMap); | |
| 164 #endif | |
| 165 } | |
| 166 | |
| 167 } // namespace blink | |
| OLD | NEW |