Remove code for compilers that did not support NSDMI for aggregates
[WebKit-https.git] / Source / WebCore / style / StyleInvalidator.cpp
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
39 namespace WebCore {
40 namespace Style {
41
42 static 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
58 static 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
71 static 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
80 Invalidator::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
95 Invalidator::Invalidator(const RuleSet& ruleSet)
96     : m_ruleSet(ruleSet)
97     , m_hasShadowPseudoElementRulesInAuthorSheet(ruleSet.hasShadowPseudoElementRules())
98 {
99 }
100
101 Invalidator::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
142 void Invalidator::invalidateStyleForTree(Element& root, SelectorFilter* filter)
143 {
144     if (invalidateIfNeeded(root, filter) == CheckDescendants::No)
145         return;
146     invalidateStyleForDescendants(root, filter);
147 }
148
149 void 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
179 void 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
191 void 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
204 void 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
212 void 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 }