1/*
2 * Copyright (C) 2012, 2014, 2017 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "StyleInvalidator.h"
28
29#include "CSSSelectorList.h"
30#include "Document.h"
31#include "ElementIterator.h"
32#include "ElementRuleCollector.h"
33#include "HTMLSlotElement.h"
34#include "SelectorFilter.h"
35#include "ShadowRoot.h"
36#include "StyleRuleImport.h"
37#include "StyleSheetContents.h"
38
39namespace WebCore {
40namespace Style {
41
42static bool shouldDirtyAllStyle(const Vector<RefPtr<StyleRuleBase>>& rules)
43{
44 for (auto& rule : rules) {
45 if (is<StyleRuleMedia>(*rule)) {
46 const auto* childRules = downcast<StyleRuleMedia>(*rule).childRulesWithoutDeferredParsing();
47 if (childRules && shouldDirtyAllStyle(*childRules))
48 return true;
49 continue;
50 }
51 // FIXME: At least font faces don't need full recalc in all cases.
52 if (!is<StyleRule>(*rule))
53 return true;
54 }
55 return false;
56}
57
58static bool shouldDirtyAllStyle(const StyleSheetContents& sheet)
59{
60 for (auto& import : sheet.importRules()) {
61 if (!import->styleSheet())
62 continue;
63 if (shouldDirtyAllStyle(*import->styleSheet()))
64 return true;
65 }
66 if (shouldDirtyAllStyle(sheet.childRules()))
67 return true;
68 return false;
69}
70
71static bool shouldDirtyAllStyle(const Vector<StyleSheetContents*>& sheets)
72{
73 for (auto& sheet : sheets) {
74 if (shouldDirtyAllStyle(*sheet))
75 return true;
76 }
77 return false;
78}
79
80Invalidator::Invalidator(const Vector<StyleSheetContents*>& sheets, const MediaQueryEvaluator& mediaQueryEvaluator)
81 : m_ownedRuleSet(std::make_unique<RuleSet>())
82 , m_ruleSet(*m_ownedRuleSet)
83 , m_dirtiesAllStyle(shouldDirtyAllStyle(sheets))
84{
85 if (m_dirtiesAllStyle)
86 return;
87
88 m_ownedRuleSet->disableAutoShrinkToFit();
89 for (auto& sheet : sheets)
90 m_ownedRuleSet->addRulesFromSheet(*sheet, mediaQueryEvaluator);
91
92 m_hasShadowPseudoElementRulesInAuthorSheet = m_ruleSet.hasShadowPseudoElementRules();
93}
94
95Invalidator::Invalidator(const RuleSet& ruleSet)
96 : m_ruleSet(ruleSet)
97 , m_hasShadowPseudoElementRulesInAuthorSheet(ruleSet.hasShadowPseudoElementRules())
98{
99}
100
101Invalidator::CheckDescendants Invalidator::invalidateIfNeeded(Element& element, const SelectorFilter* filter)
102{
103 if (m_hasShadowPseudoElementRulesInAuthorSheet) {
104 // FIXME: This could do actual rule matching too.
105 if (element.shadowRoot())
106 element.invalidateStyleForSubtreeInternal();
107 }
108
109 bool shouldCheckForSlots = !m_ruleSet.slottedPseudoElementRules().isEmpty() && !m_didInvalidateHostChildren;
110 if (shouldCheckForSlots && is<HTMLSlotElement>(element)) {
111 auto* containingShadowRoot = element.containingShadowRoot();
112 if (containingShadowRoot && containingShadowRoot->host()) {
113 for (auto& possiblySlotted : childrenOfType<Element>(*containingShadowRoot->host()))
114 possiblySlotted.invalidateStyleInternal();
115 }
116 // No need to do this again.
117 m_didInvalidateHostChildren = true;
118 }
119
120 switch (element.styleValidity()) {
121 case Style::Validity::Valid: {
122 ElementRuleCollector ruleCollector(element, m_ruleSet, filter);
123 ruleCollector.setMode(SelectorChecker::Mode::CollectingRulesIgnoringVirtualPseudoElements);
124 ruleCollector.matchAuthorRules(false);
125
126 if (ruleCollector.hasMatchedRules())
127 element.invalidateStyleInternal();
128 return CheckDescendants::Yes;
129 }
130 case Style::Validity::ElementInvalid:
131 return CheckDescendants::Yes;
132 case Style::Validity::SubtreeInvalid:
133 case Style::Validity::SubtreeAndRenderersInvalid:
134 if (shouldCheckForSlots)
135 return CheckDescendants::Yes;
136 return CheckDescendants::No;
137 }
138 ASSERT_NOT_REACHED();
139 return CheckDescendants::Yes;
140}
141
142void Invalidator::invalidateStyleForTree(Element& root, SelectorFilter* filter)
143{
144 if (invalidateIfNeeded(root, filter) == CheckDescendants::No)
145 return;
146 invalidateStyleForDescendants(root, filter);
147}
148
149void Invalidator::invalidateStyleForDescendants(Element& root, SelectorFilter* filter)
150{
151 Vector<Element*, 20> parentStack;
152 Element* previousElement = &root;
153 auto descendants = descendantsOfType<Element>(root);
154 for (auto it = descendants.begin(), end = descendants.end(); it != end;) {
155 auto& descendant = *it;
156 auto* parent = descendant.parentElement();
157 if (parentStack.isEmpty() || parentStack.last() != parent) {
158 if (parent == previousElement) {
159 parentStack.append(parent);
160 if (filter)
161 filter->pushParentInitializingIfNeeded(*parent);
162 } else {
163 while (parentStack.last() != parent) {
164 parentStack.removeLast();
165 if (filter)
166 filter->popParent();
167 }
168 }
169 }
170 previousElement = &descendant;
171
172 if (invalidateIfNeeded(descendant, filter) == CheckDescendants::Yes)
173 it.traverseNext();
174 else
175 it.traverseNextSkippingChildren();
176 }
177}
178
179void Invalidator::invalidateStyle(Document& document)
180{
181 ASSERT(!m_dirtiesAllStyle);
182
183 Element* documentElement = document.documentElement();
184 if (!documentElement)
185 return;
186
187 SelectorFilter filter;
188 invalidateStyleForTree(*documentElement, &filter);
189}
190
191void Invalidator::invalidateStyle(ShadowRoot& shadowRoot)
192{
193 ASSERT(!m_dirtiesAllStyle);
194
195 if (!m_ruleSet.hostPseudoClassRules().isEmpty() && shadowRoot.host())
196 shadowRoot.host()->invalidateStyleInternal();
197
198 for (auto& child : childrenOfType<Element>(shadowRoot)) {
199 SelectorFilter filter;
200 invalidateStyleForTree(child, &filter);
201 }
202}
203
204void Invalidator::invalidateStyle(Element& element)
205{
206 ASSERT(!m_dirtiesAllStyle);
207
208 // Don't use SelectorFilter as the rule sets here tend to be small and the filter would have setup cost deep in the tree.
209 invalidateStyleForTree(element, nullptr);
210}
211
212void Invalidator::invalidateStyleWithMatchElement(Element& element, MatchElement matchElement)
213{
214 switch (matchElement) {
215 case MatchElement::Subject: {
216 invalidateIfNeeded(element, nullptr);
217 break;
218 }
219 case MatchElement::Parent: {
220 auto children = childrenOfType<Element>(element);
221 for (auto& child : children)
222 invalidateIfNeeded(child, nullptr);
223 break;
224 }
225 case MatchElement::Ancestor: {
226 SelectorFilter filter;
227 invalidateStyleForDescendants(element, &filter);
228 break;
229 }
230 case MatchElement::DirectSibling:
231 if (auto* sibling = element.nextElementSibling())
232 invalidateIfNeeded(*sibling, nullptr);
233 break;
234 case MatchElement::IndirectSibling:
235 for (auto* sibling = element.nextElementSibling(); sibling; sibling = sibling->nextElementSibling())
236 invalidateIfNeeded(*sibling, nullptr);
237 break;
238 case MatchElement::AnySibling: {
239 auto parentChildren = childrenOfType<Element>(*element.parentNode());
240 for (auto& parentChild : parentChildren)
241 invalidateIfNeeded(parentChild, nullptr);
242 break;
243 }
244 case MatchElement::ParentSibling:
245 for (auto* sibling = element.nextElementSibling(); sibling; sibling = sibling->nextElementSibling()) {
246 auto siblingChildren = childrenOfType<Element>(*sibling);
247 for (auto& siblingChild : siblingChildren)
248 invalidateIfNeeded(siblingChild, nullptr);
249 }
250 break;
251 case MatchElement::AncestorSibling: {
252 SelectorFilter filter;
253 for (auto* sibling = element.nextElementSibling(); sibling; sibling = sibling->nextElementSibling()) {
254 filter.popParentsUntil(element.parentElement());
255 invalidateStyleForDescendants(*sibling, &filter);
256 }
257 break;
258 }
259 case MatchElement::Host:
260 // FIXME: Handle this here as well.
261 break;
262 }
263}
264
265}
266}
267