1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc.
4  * All rights reserved.
5  * Copyright (C) 2012 Google Inc. All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1.  Redistributions of source code must retain the above copyright
11  *     notice, this list of conditions and the following disclaimer.
12  * 2.  Redistributions in binary form must reproduce the above copyright
13  *     notice, this list of conditions and the following disclaimer in the
14  *     documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
26  * DAMAGE.
27  */
28 
29 #include "third_party/blink/renderer/core/css/resolver/scoped_style_resolver.h"
30 
31 #include "third_party/blink/renderer/core/animation/document_timeline.h"
32 #include "third_party/blink/renderer/core/css/css_font_selector.h"
33 #include "third_party/blink/renderer/core/css/css_style_sheet.h"
34 #include "third_party/blink/renderer/core/css/font_face.h"
35 #include "third_party/blink/renderer/core/css/page_rule_collector.h"
36 #include "third_party/blink/renderer/core/css/part_names.h"
37 #include "third_party/blink/renderer/core/css/resolver/match_request.h"
38 #include "third_party/blink/renderer/core/css/rule_feature_set.h"
39 #include "third_party/blink/renderer/core/css/style_change_reason.h"
40 #include "third_party/blink/renderer/core/css/style_engine.h"
41 #include "third_party/blink/renderer/core/css/style_rule.h"
42 #include "third_party/blink/renderer/core/css/style_sheet_contents.h"
43 #include "third_party/blink/renderer/core/dom/document.h"
44 #include "third_party/blink/renderer/core/dom/shadow_root.h"
45 #include "third_party/blink/renderer/core/html/html_style_element.h"
46 #include "third_party/blink/renderer/core/html_names.h"
47 #include "third_party/blink/renderer/core/svg/svg_style_element.h"
48 
49 namespace blink {
50 
Parent() const51 ScopedStyleResolver* ScopedStyleResolver::Parent() const {
52   for (TreeScope* scope = GetTreeScope().ParentTreeScope(); scope;
53        scope = scope->ParentTreeScope()) {
54     if (ScopedStyleResolver* resolver = scope->GetScopedStyleResolver())
55       return resolver;
56   }
57   return nullptr;
58 }
59 
AddKeyframeRules(const RuleSet & rule_set)60 void ScopedStyleResolver::AddKeyframeRules(const RuleSet& rule_set) {
61   if (RuntimeEnabledFeatures::CSSKeyframesMemoryReductionEnabled())
62     return;
63 
64   const HeapVector<Member<StyleRuleKeyframes>> keyframes_rules =
65       rule_set.KeyframesRules();
66   for (auto rule : keyframes_rules)
67     AddKeyframeStyle(rule);
68 }
69 
AddFontFaceRules(const RuleSet & rule_set)70 void ScopedStyleResolver::AddFontFaceRules(const RuleSet& rule_set) {
71   // FIXME(BUG 72461): We don't add @font-face rules of scoped style sheets for
72   // the moment.
73   if (!GetTreeScope().RootNode().IsDocumentNode())
74     return;
75 
76   Document& document = GetTreeScope().GetDocument();
77   CSSFontSelector* css_font_selector =
78       document.GetStyleEngine().GetFontSelector();
79   const HeapVector<Member<StyleRuleFontFace>> font_face_rules =
80       rule_set.FontFaceRules();
81   for (auto& font_face_rule : font_face_rules) {
82     if (FontFace* font_face = FontFace::Create(&document, font_face_rule))
83       css_font_selector->GetFontFaceCache()->Add(font_face_rule, font_face);
84   }
85   if (font_face_rules.size())
86     document.GetStyleResolver().InvalidateMatchedPropertiesCache();
87 }
88 
AppendActiveStyleSheets(unsigned index,const ActiveStyleSheetVector & active_sheets)89 void ScopedStyleResolver::AppendActiveStyleSheets(
90     unsigned index,
91     const ActiveStyleSheetVector& active_sheets) {
92   for (auto* active_iterator = active_sheets.begin() + index;
93        active_iterator != active_sheets.end(); active_iterator++) {
94     CSSStyleSheet* sheet = active_iterator->first;
95     viewport_dependent_media_query_results_.AppendVector(
96         sheet->ViewportDependentMediaQueryResults());
97     device_dependent_media_query_results_.AppendVector(
98         sheet->DeviceDependentMediaQueryResults());
99     if (!active_iterator->second)
100       continue;
101     const RuleSet& rule_set = *active_iterator->second;
102     author_style_sheets_.push_back(sheet);
103     AddKeyframeRules(rule_set);
104     AddFontFaceRules(rule_set);
105     AddTreeBoundaryCrossingRules(rule_set, sheet, index);
106     AddSlottedRules(rule_set, sheet, index++);
107   }
108 }
109 
CollectFeaturesTo(RuleFeatureSet & features,HeapHashSet<Member<const StyleSheetContents>> & visited_shared_style_sheet_contents) const110 void ScopedStyleResolver::CollectFeaturesTo(
111     RuleFeatureSet& features,
112     HeapHashSet<Member<const StyleSheetContents>>&
113         visited_shared_style_sheet_contents) const {
114   features.ViewportDependentMediaQueryResults().AppendVector(
115       viewport_dependent_media_query_results_);
116   features.DeviceDependentMediaQueryResults().AppendVector(
117       device_dependent_media_query_results_);
118 
119   for (auto sheet : author_style_sheets_) {
120     DCHECK(sheet->ownerNode() || sheet->IsConstructed());
121     StyleSheetContents* contents = sheet->Contents();
122     if (contents->HasOneClient() ||
123         visited_shared_style_sheet_contents.insert(contents).is_new_entry)
124       features.Add(contents->GetRuleSet().Features());
125   }
126 
127   if (tree_boundary_crossing_rule_set_) {
128     for (const auto& rules : *tree_boundary_crossing_rule_set_)
129       features.Add(rules->rule_set_->Features());
130   }
131   if (slotted_rule_set_) {
132     for (const auto& rules : *slotted_rule_set_)
133       features.Add(rules->rule_set_->Features());
134   }
135 }
136 
ResetAuthorStyle()137 void ScopedStyleResolver::ResetAuthorStyle() {
138   author_style_sheets_.clear();
139   viewport_dependent_media_query_results_.clear();
140   device_dependent_media_query_results_.clear();
141   keyframes_rule_map_.clear();
142   tree_boundary_crossing_rule_set_ = nullptr;
143   slotted_rule_set_ = nullptr;
144   has_deep_or_shadow_selector_ = false;
145   needs_append_all_sheets_ = false;
146 }
147 
ActiveAuthorStyleSheets()148 const ActiveStyleSheetVector& ScopedStyleResolver::ActiveAuthorStyleSheets() {
149   StyleSheetCollection* collection =
150       GetTreeScope().GetDocument().GetStyleEngine().StyleSheetCollectionFor(
151           *scope_);
152   DCHECK(collection);
153   return collection->ActiveAuthorStyleSheets();
154 }
155 
156 // static
157 StyleRuleKeyframes*
KeyframeStylesForAnimationFromActiveSheets(const AtomicString & name,const ActiveStyleSheetVector & sheets)158 ScopedStyleResolver::KeyframeStylesForAnimationFromActiveSheets(
159     const AtomicString& name,
160     const ActiveStyleSheetVector& sheets) {
161   // We prefer non-vendor-prefixed over vendor-prefixed rules.
162   StyleRuleKeyframes* vendor_prefixed_result = nullptr;
163   for (auto sheet = sheets.rbegin(); sheet != sheets.rend(); ++sheet) {
164     RuleSet* rule_set = sheet->second;
165     if (!rule_set)
166       continue;
167     if (StyleRuleKeyframes* rule = rule_set->KeyframeStylesForAnimation(name)) {
168       if (!rule->IsVendorPrefixed())
169         return rule;
170       if (!vendor_prefixed_result)
171         vendor_prefixed_result = rule;
172     }
173   }
174   return vendor_prefixed_result;
175 }
176 
KeyframeStylesForAnimation(const AtomicString & animation_name)177 StyleRuleKeyframes* ScopedStyleResolver::KeyframeStylesForAnimation(
178     const AtomicString& animation_name) {
179   if (RuntimeEnabledFeatures::CSSKeyframesMemoryReductionEnabled()) {
180     return KeyframeStylesForAnimationFromActiveSheets(
181         animation_name, ActiveAuthorStyleSheets());
182   }
183 
184   if (keyframes_rule_map_.IsEmpty())
185     return nullptr;
186 
187   KeyframesRuleMap::iterator it = keyframes_rule_map_.find(animation_name);
188   if (it == keyframes_rule_map_.end())
189     return nullptr;
190 
191   return it->value.Get();
192 }
193 
AddKeyframeStyle(StyleRuleKeyframes * rule)194 void ScopedStyleResolver::AddKeyframeStyle(StyleRuleKeyframes* rule) {
195   DCHECK(!RuntimeEnabledFeatures::CSSKeyframesMemoryReductionEnabled());
196   AtomicString name = rule->GetName();
197 
198   if (rule->IsVendorPrefixed()) {
199     KeyframesRuleMap::iterator it = keyframes_rule_map_.find(name);
200     if (it == keyframes_rule_map_.end())
201       keyframes_rule_map_.Set(name, rule);
202     else if (it->value->IsVendorPrefixed())
203       keyframes_rule_map_.Set(name, rule);
204   } else {
205     keyframes_rule_map_.Set(name, rule);
206   }
207 }
208 
InvalidationRootForTreeScope(const TreeScope & tree_scope)209 Element& ScopedStyleResolver::InvalidationRootForTreeScope(
210     const TreeScope& tree_scope) {
211   DCHECK(tree_scope.GetDocument().documentElement());
212   if (tree_scope.RootNode() == tree_scope.GetDocument())
213     return *tree_scope.GetDocument().documentElement();
214   return To<ShadowRoot>(tree_scope.RootNode()).host();
215 }
216 
KeyframesRulesAdded(const TreeScope & tree_scope)217 void ScopedStyleResolver::KeyframesRulesAdded(const TreeScope& tree_scope) {
218   // Called when @keyframes rules are about to be added/removed from a
219   // TreeScope. @keyframes rules may apply to animations on elements in the
220   // same TreeScope as the stylesheet, or the host element in the parent
221   // TreeScope if the TreeScope is a shadow tree.
222   if (!tree_scope.GetDocument().documentElement())
223     return;
224 
225   ScopedStyleResolver* resolver = tree_scope.GetScopedStyleResolver();
226   ScopedStyleResolver* parent_resolver =
227       tree_scope.ParentTreeScope()
228           ? tree_scope.ParentTreeScope()->GetScopedStyleResolver()
229           : nullptr;
230 
231   bool had_unresolved_keyframes = false;
232   if (resolver && resolver->has_unresolved_keyframes_rule_) {
233     resolver->has_unresolved_keyframes_rule_ = false;
234     had_unresolved_keyframes = true;
235   }
236   if (parent_resolver && parent_resolver->has_unresolved_keyframes_rule_) {
237     parent_resolver->has_unresolved_keyframes_rule_ = false;
238     had_unresolved_keyframes = true;
239   }
240 
241   if (had_unresolved_keyframes) {
242     // If an animation ended up not being started because no @keyframes
243     // rules were found for the animation-name, we need to recalculate style
244     // for the elements in the scope, including its shadow host if
245     // applicable.
246     InvalidationRootForTreeScope(tree_scope)
247         .SetNeedsStyleRecalc(kSubtreeStyleChange,
248                              StyleChangeReasonForTracing::Create(
249                                  style_change_reason::kStyleSheetChange));
250     return;
251   }
252 
253   // If we have animations running, added/removed @keyframes may affect these.
254   tree_scope.GetDocument().Timeline().InvalidateKeyframeEffects(tree_scope);
255 }
256 
CollectMatchingAuthorRules(ElementRuleCollector & collector,ShadowV0CascadeOrder cascade_order)257 void ScopedStyleResolver::CollectMatchingAuthorRules(
258     ElementRuleCollector& collector,
259     ShadowV0CascadeOrder cascade_order) {
260   wtf_size_t sheet_index = 0;
261   for (auto sheet : author_style_sheets_) {
262     DCHECK(sheet->ownerNode() || sheet->IsConstructed());
263     MatchRequest match_request(&sheet->Contents()->GetRuleSet(),
264                                &scope_->RootNode(), sheet, sheet_index++);
265     collector.CollectMatchingRules(match_request, cascade_order);
266   }
267 }
268 
CollectMatchingShadowHostRules(ElementRuleCollector & collector,ShadowV0CascadeOrder cascade_order)269 void ScopedStyleResolver::CollectMatchingShadowHostRules(
270     ElementRuleCollector& collector,
271     ShadowV0CascadeOrder cascade_order) {
272   wtf_size_t sheet_index = 0;
273   for (auto sheet : author_style_sheets_) {
274     DCHECK(sheet->ownerNode() || sheet->IsConstructed());
275     MatchRequest match_request(&sheet->Contents()->GetRuleSet(),
276                                &scope_->RootNode(), sheet, sheet_index++);
277     collector.CollectMatchingShadowHostRules(match_request, cascade_order);
278   }
279 }
280 
CollectMatchingSlottedRules(ElementRuleCollector & collector,ShadowV0CascadeOrder cascade_order)281 void ScopedStyleResolver::CollectMatchingSlottedRules(
282     ElementRuleCollector& collector,
283     ShadowV0CascadeOrder cascade_order) {
284   if (!slotted_rule_set_)
285     return;
286 
287   for (const auto& rules : *slotted_rule_set_) {
288     MatchRequest request(rules->rule_set_.Get(), &GetTreeScope().RootNode(),
289                          rules->parent_style_sheet_, rules->parent_index_);
290     collector.CollectMatchingRules(request, cascade_order, true);
291   }
292 }
293 
CollectMatchingTreeBoundaryCrossingRules(ElementRuleCollector & collector,ShadowV0CascadeOrder cascade_order)294 void ScopedStyleResolver::CollectMatchingTreeBoundaryCrossingRules(
295     ElementRuleCollector& collector,
296     ShadowV0CascadeOrder cascade_order) {
297   if (!tree_boundary_crossing_rule_set_)
298     return;
299 
300   for (const auto& rules : *tree_boundary_crossing_rule_set_) {
301     MatchRequest request(rules->rule_set_.Get(), &GetTreeScope().RootNode(),
302                          rules->parent_style_sheet_, rules->parent_index_);
303     collector.CollectMatchingRules(request, cascade_order, true);
304   }
305 }
306 
CollectMatchingPartPseudoRules(ElementRuleCollector & collector,PartNames & part_names,ShadowV0CascadeOrder cascade_order)307 void ScopedStyleResolver::CollectMatchingPartPseudoRules(
308     ElementRuleCollector& collector,
309     PartNames& part_names,
310     ShadowV0CascadeOrder cascade_order) {
311   wtf_size_t sheet_index = 0;
312   for (auto sheet : author_style_sheets_) {
313     DCHECK(sheet->ownerNode() || sheet->IsConstructed());
314     MatchRequest match_request(&sheet->Contents()->GetRuleSet(),
315                                &scope_->RootNode(), sheet, sheet_index++);
316     collector.CollectMatchingPartPseudoRules(match_request, part_names,
317                                              cascade_order);
318   }
319 }
320 
MatchPageRules(PageRuleCollector & collector)321 void ScopedStyleResolver::MatchPageRules(PageRuleCollector& collector) {
322   // Only consider the global author RuleSet for @page rules, as per the HTML5
323   // spec.
324   DCHECK(scope_->RootNode().IsDocumentNode());
325   for (auto sheet : author_style_sheets_)
326     collector.MatchPageRules(&sheet->Contents()->GetRuleSet());
327 }
328 
Trace(Visitor * visitor) const329 void ScopedStyleResolver::Trace(Visitor* visitor) const {
330   visitor->Trace(scope_);
331   visitor->Trace(author_style_sheets_);
332   visitor->Trace(keyframes_rule_map_);
333   visitor->Trace(tree_boundary_crossing_rule_set_);
334   visitor->Trace(slotted_rule_set_);
335 }
336 
AddRules(RuleSet * rule_set,const HeapVector<MinimalRuleData> & rules)337 static void AddRules(RuleSet* rule_set,
338                      const HeapVector<MinimalRuleData>& rules) {
339   for (const auto& info : rules)
340     rule_set->AddRule(info.rule_, info.selector_index_, info.flags_);
341 }
342 
AddTreeBoundaryCrossingRules(const RuleSet & author_rules,CSSStyleSheet * parent_style_sheet,unsigned sheet_index)343 void ScopedStyleResolver::AddTreeBoundaryCrossingRules(
344     const RuleSet& author_rules,
345     CSSStyleSheet* parent_style_sheet,
346     unsigned sheet_index) {
347   bool is_document_scope = GetTreeScope().RootNode().IsDocumentNode();
348   if (author_rules.DeepCombinatorOrShadowPseudoRules().IsEmpty() &&
349       (is_document_scope ||
350        (author_rules.ContentPseudoElementRules().IsEmpty())))
351     return;
352 
353   if (!author_rules.DeepCombinatorOrShadowPseudoRules().IsEmpty())
354     has_deep_or_shadow_selector_ = true;
355 
356   auto* rule_set_for_scope = MakeGarbageCollected<RuleSet>();
357   AddRules(rule_set_for_scope,
358            author_rules.DeepCombinatorOrShadowPseudoRules());
359 
360   if (!is_document_scope)
361     AddRules(rule_set_for_scope, author_rules.ContentPseudoElementRules());
362 
363   if (!tree_boundary_crossing_rule_set_) {
364     tree_boundary_crossing_rule_set_ =
365         MakeGarbageCollected<CSSStyleSheetRuleSubSet>();
366     GetTreeScope().GetDocument().GetStyleEngine().AddTreeBoundaryCrossingScope(
367         GetTreeScope());
368   }
369 
370   tree_boundary_crossing_rule_set_->push_back(MakeGarbageCollected<RuleSubSet>(
371       parent_style_sheet, sheet_index, rule_set_for_scope));
372 }
373 
V0ShadowAddedOnV1Document()374 void ScopedStyleResolver::V0ShadowAddedOnV1Document() {
375   // See the comment in AddSlottedRules().
376   if (!slotted_rule_set_)
377     return;
378 
379   if (!tree_boundary_crossing_rule_set_) {
380     tree_boundary_crossing_rule_set_ =
381         MakeGarbageCollected<CSSStyleSheetRuleSubSet>();
382     GetTreeScope().GetDocument().GetStyleEngine().AddTreeBoundaryCrossingScope(
383         GetTreeScope());
384   }
385   tree_boundary_crossing_rule_set_->AppendVector(*slotted_rule_set_);
386   slotted_rule_set_ = nullptr;
387 }
388 
AddSlottedRules(const RuleSet & author_rules,CSSStyleSheet * parent_style_sheet,unsigned sheet_index)389 void ScopedStyleResolver::AddSlottedRules(const RuleSet& author_rules,
390                                           CSSStyleSheet* parent_style_sheet,
391                                           unsigned sheet_index) {
392   bool is_document_scope = GetTreeScope().RootNode().IsDocumentNode();
393   if (is_document_scope || author_rules.SlottedPseudoElementRules().IsEmpty())
394     return;
395 
396   auto* slotted_rule_set = MakeGarbageCollected<RuleSet>();
397   AddRules(slotted_rule_set, author_rules.SlottedPseudoElementRules());
398 
399   // In case ::slotted rule is used in V0/V1 mixed document, put ::slotted
400   // rules in tree boundary crossing rules as the pure v1 fast path in
401   // StyleResolver misses them.
402   // Adding this tree scope to tree boundary crossing scopes may end up in
403   // O(N^2) where N is number of scopes which has ::slotted() rules.
404   // Once the document-wide cascade order flag downgrades from V1 to V0,
405   // these slotted rules have to be moved back to tree boundary crossing
406   // rule sets. See V0ShadowAddedOnV1Document().
407   if (GetTreeScope().GetDocument().MayContainV0Shadow()) {
408     if (!tree_boundary_crossing_rule_set_) {
409       tree_boundary_crossing_rule_set_ =
410           MakeGarbageCollected<CSSStyleSheetRuleSubSet>();
411       GetTreeScope()
412           .GetDocument()
413           .GetStyleEngine()
414           .AddTreeBoundaryCrossingScope(GetTreeScope());
415     }
416     tree_boundary_crossing_rule_set_->push_back(
417         MakeGarbageCollected<RuleSubSet>(parent_style_sheet, sheet_index,
418                                          slotted_rule_set));
419     return;
420   }
421   if (!slotted_rule_set_)
422     slotted_rule_set_ = MakeGarbageCollected<CSSStyleSheetRuleSubSet>();
423   slotted_rule_set_->push_back(MakeGarbageCollected<RuleSubSet>(
424       parent_style_sheet, sheet_index, slotted_rule_set));
425 }
426 
Trace(Visitor * visitor) const427 void ScopedStyleResolver::RuleSubSet::Trace(Visitor* visitor) const {
428   visitor->Trace(parent_style_sheet_);
429   visitor->Trace(rule_set_);
430 }
431 
432 }  // namespace blink
433