1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #include "mozilla/ServoStyleRuleMap.h"
8 
9 #include "mozilla/css/GroupRule.h"
10 #include "mozilla/dom/CSSImportRule.h"
11 #include "mozilla/dom/CSSRuleBinding.h"
12 #include "mozilla/dom/CSSStyleRule.h"
13 #include "mozilla/dom/Document.h"
14 #include "mozilla/dom/Element.h"
15 #include "mozilla/dom/ShadowRoot.h"
16 #include "mozilla/IntegerRange.h"
17 #include "mozilla/ServoStyleSet.h"
18 #include "mozilla/StyleSheetInlines.h"
19 #include "nsStyleSheetService.h"
20 
21 using namespace mozilla::dom;
22 
23 namespace mozilla {
24 
EnsureTable(ServoStyleSet & aStyleSet)25 void ServoStyleRuleMap::EnsureTable(ServoStyleSet& aStyleSet) {
26   if (!IsEmpty()) {
27     return;
28   }
29   aStyleSet.EnumerateStyleSheets(
30       [&](StyleSheet& aSheet) { FillTableFromStyleSheet(aSheet); });
31 }
32 
EnsureTable(ShadowRoot & aShadowRoot)33 void ServoStyleRuleMap::EnsureTable(ShadowRoot& aShadowRoot) {
34   if (!IsEmpty()) {
35     return;
36   }
37   for (auto index : IntegerRange(aShadowRoot.SheetCount())) {
38     FillTableFromStyleSheet(*aShadowRoot.SheetAt(index));
39   }
40 }
41 
SheetAdded(StyleSheet & aStyleSheet)42 void ServoStyleRuleMap::SheetAdded(StyleSheet& aStyleSheet) {
43   if (!IsEmpty()) {
44     FillTableFromStyleSheet(aStyleSheet);
45   }
46 }
47 
SheetRemoved(StyleSheet & aStyleSheet)48 void ServoStyleRuleMap::SheetRemoved(StyleSheet& aStyleSheet) {
49   // Invalidate all data inside. This isn't strictly necessary since
50   // we should always get update from document before new queries come.
51   // But it is probably still safer if we try to avoid having invalid
52   // pointers inside. Also if the document keep adding and removing
53   // stylesheets, this would also prevent us from infinitely growing
54   // memory usage.
55   mTable.Clear();
56 }
57 
RuleAdded(StyleSheet & aStyleSheet,css::Rule & aStyleRule)58 void ServoStyleRuleMap::RuleAdded(StyleSheet& aStyleSheet,
59                                   css::Rule& aStyleRule) {
60   if (!IsEmpty()) {
61     FillTableFromRule(aStyleRule);
62   }
63 }
64 
RuleRemoved(StyleSheet & aStyleSheet,css::Rule & aStyleRule)65 void ServoStyleRuleMap::RuleRemoved(StyleSheet& aStyleSheet,
66                                     css::Rule& aStyleRule) {
67   if (IsEmpty()) {
68     return;
69   }
70 
71   switch (aStyleRule.Type()) {
72     case CSSRule_Binding::STYLE_RULE: {
73       auto& rule = static_cast<CSSStyleRule&>(aStyleRule);
74       mTable.Remove(rule.Raw());
75       break;
76     }
77     case CSSRule_Binding::IMPORT_RULE:
78     case CSSRule_Binding::MEDIA_RULE:
79     case CSSRule_Binding::SUPPORTS_RULE:
80     case CSSRule_Binding::DOCUMENT_RULE: {
81       // See the comment in StyleSheetRemoved.
82       mTable.Clear();
83       break;
84     }
85     case CSSRule_Binding::FONT_FACE_RULE:
86     case CSSRule_Binding::PAGE_RULE:
87     case CSSRule_Binding::KEYFRAMES_RULE:
88     case CSSRule_Binding::KEYFRAME_RULE:
89     case CSSRule_Binding::NAMESPACE_RULE:
90     case CSSRule_Binding::COUNTER_STYLE_RULE:
91     case CSSRule_Binding::FONT_FEATURE_VALUES_RULE:
92       break;
93     default:
94       MOZ_ASSERT_UNREACHABLE("Unhandled rule");
95   }
96 }
97 
SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const98 size_t ServoStyleRuleMap::SizeOfIncludingThis(
99     MallocSizeOf aMallocSizeOf) const {
100   size_t n = aMallocSizeOf(this);
101   n += mTable.ShallowSizeOfExcludingThis(aMallocSizeOf);
102   return n;
103 }
104 
FillTableFromRule(css::Rule & aRule)105 void ServoStyleRuleMap::FillTableFromRule(css::Rule& aRule) {
106   switch (aRule.Type()) {
107     case CSSRule_Binding::STYLE_RULE: {
108       auto& rule = static_cast<CSSStyleRule&>(aRule);
109       mTable.InsertOrUpdate(rule.Raw(), &rule);
110       break;
111     }
112     case CSSRule_Binding::MEDIA_RULE:
113     case CSSRule_Binding::SUPPORTS_RULE:
114     case CSSRule_Binding::DOCUMENT_RULE: {
115       auto& rule = static_cast<css::GroupRule&>(aRule);
116       auto ruleList = static_cast<ServoCSSRuleList*>(rule.CssRules());
117       FillTableFromRuleList(*ruleList);
118       break;
119     }
120     case CSSRule_Binding::IMPORT_RULE: {
121       auto& rule = static_cast<CSSImportRule&>(aRule);
122       MOZ_ASSERT(aRule.GetStyleSheet());
123       FillTableFromStyleSheet(*rule.GetStyleSheet());
124       break;
125     }
126   }
127 }
128 
FillTableFromRuleList(ServoCSSRuleList & aRuleList)129 void ServoStyleRuleMap::FillTableFromRuleList(ServoCSSRuleList& aRuleList) {
130   for (uint32_t i : IntegerRange(aRuleList.Length())) {
131     FillTableFromRule(*aRuleList.GetRule(i));
132   }
133 }
134 
FillTableFromStyleSheet(StyleSheet & aSheet)135 void ServoStyleRuleMap::FillTableFromStyleSheet(StyleSheet& aSheet) {
136   if (aSheet.IsComplete()) {
137     FillTableFromRuleList(*aSheet.GetCssRulesInternal());
138   }
139 }
140 
141 }  // namespace mozilla
142