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/CSSRuleBinding.h"
11 #include "mozilla/IntegerRange.h"
12 #include "mozilla/ServoStyleRule.h"
13 #include "mozilla/ServoStyleSet.h"
14 #include "mozilla/ServoImportRule.h"
15 #include "mozilla/StyleSheetInlines.h"
16 #include "nsDocument.h"
17 #include "nsStyleSheetService.h"
18 
19 namespace mozilla {
20 
EnsureTable(ServoStyleSet & aStyleSet)21 void ServoStyleRuleMap::EnsureTable(ServoStyleSet& aStyleSet) {
22   if (!IsEmpty()) {
23     return;
24   }
25   aStyleSet.EnumerateStyleSheetArrays(
26       [this](const nsTArray<RefPtr<ServoStyleSheet>>& aArray) {
27         for (auto& sheet : aArray) {
28           FillTableFromStyleSheet(*sheet);
29         }
30       });
31 }
32 
EnsureTable(nsXBLPrototypeResources & aXBLResources)33 void ServoStyleRuleMap::EnsureTable(nsXBLPrototypeResources& aXBLResources) {
34   if (!IsEmpty() || !aXBLResources.GetServoStyles()) {
35     return;
36   }
37   for (auto index : IntegerRange(aXBLResources.SheetCount())) {
38     FillTableFromStyleSheet(*aXBLResources.StyleSheetAt(index)->AsServo());
39   }
40 }
41 
EnsureTable(ShadowRoot & aShadowRoot)42 void ServoStyleRuleMap::EnsureTable(ShadowRoot& aShadowRoot) {
43   if (!IsEmpty()) {
44     return;
45   }
46   for (auto index : IntegerRange(aShadowRoot.SheetCount())) {
47     FillTableFromStyleSheet(*aShadowRoot.SheetAt(index)->AsServo());
48   }
49 }
50 
SheetAdded(ServoStyleSheet & aStyleSheet)51 void ServoStyleRuleMap::SheetAdded(ServoStyleSheet& aStyleSheet) {
52   if (!IsEmpty()) {
53     FillTableFromStyleSheet(aStyleSheet);
54   }
55 }
56 
SheetRemoved(ServoStyleSheet & aStyleSheet)57 void ServoStyleRuleMap::SheetRemoved(ServoStyleSheet& aStyleSheet) {
58   // Invalidate all data inside. This isn't strictly necessary since
59   // we should always get update from document before new queries come.
60   // But it is probably still safer if we try to avoid having invalid
61   // pointers inside. Also if the document keep adding and removing
62   // stylesheets, this would also prevent us from infinitely growing
63   // memory usage.
64   mTable.Clear();
65 }
66 
RuleAdded(ServoStyleSheet & aStyleSheet,css::Rule & aStyleRule)67 void ServoStyleRuleMap::RuleAdded(ServoStyleSheet& aStyleSheet,
68                                   css::Rule& aStyleRule) {
69   if (!IsEmpty()) {
70     FillTableFromRule(aStyleRule);
71   }
72 }
73 
RuleRemoved(ServoStyleSheet & aStyleSheet,css::Rule & aStyleRule)74 void ServoStyleRuleMap::RuleRemoved(ServoStyleSheet& aStyleSheet,
75                                     css::Rule& aStyleRule) {
76   if (IsEmpty()) {
77     return;
78   }
79 
80   switch (aStyleRule.Type()) {
81     case CSSRuleBinding::STYLE_RULE: {
82       auto& rule = static_cast<ServoStyleRule&>(aStyleRule);
83       mTable.Remove(rule.Raw());
84       break;
85     }
86     case CSSRuleBinding::IMPORT_RULE:
87     case CSSRuleBinding::MEDIA_RULE:
88     case CSSRuleBinding::SUPPORTS_RULE:
89     case CSSRuleBinding::DOCUMENT_RULE: {
90       // See the comment in StyleSheetRemoved.
91       mTable.Clear();
92       break;
93     }
94     case CSSRuleBinding::FONT_FACE_RULE:
95     case CSSRuleBinding::PAGE_RULE:
96     case CSSRuleBinding::KEYFRAMES_RULE:
97     case CSSRuleBinding::KEYFRAME_RULE:
98     case CSSRuleBinding::NAMESPACE_RULE:
99     case CSSRuleBinding::COUNTER_STYLE_RULE:
100     case CSSRuleBinding::FONT_FEATURE_VALUES_RULE:
101       break;
102     default:
103       MOZ_ASSERT_UNREACHABLE("Unhandled rule");
104   }
105 }
106 
SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const107 size_t ServoStyleRuleMap::SizeOfIncludingThis(
108     MallocSizeOf aMallocSizeOf) const {
109   size_t n = aMallocSizeOf(this);
110   n += mTable.ShallowSizeOfExcludingThis(aMallocSizeOf);
111   return n;
112 }
113 
FillTableFromRule(css::Rule & aRule)114 void ServoStyleRuleMap::FillTableFromRule(css::Rule& aRule) {
115   switch (aRule.Type()) {
116     case CSSRuleBinding::STYLE_RULE: {
117       auto& rule = static_cast<ServoStyleRule&>(aRule);
118       mTable.Put(rule.Raw(), &rule);
119       break;
120     }
121     case CSSRuleBinding::MEDIA_RULE:
122     case CSSRuleBinding::SUPPORTS_RULE:
123     case CSSRuleBinding::DOCUMENT_RULE: {
124       auto& rule = static_cast<css::GroupRule&>(aRule);
125       auto ruleList = static_cast<ServoCSSRuleList*>(rule.CssRules());
126       FillTableFromRuleList(*ruleList);
127       break;
128     }
129     case CSSRuleBinding::IMPORT_RULE: {
130       auto& rule = static_cast<ServoImportRule&>(aRule);
131       MOZ_ASSERT(aRule.GetStyleSheet());
132       FillTableFromStyleSheet(*rule.GetStyleSheet()->AsServo());
133       break;
134     }
135   }
136 }
137 
FillTableFromRuleList(ServoCSSRuleList & aRuleList)138 void ServoStyleRuleMap::FillTableFromRuleList(ServoCSSRuleList& aRuleList) {
139   for (uint32_t i : IntegerRange(aRuleList.Length())) {
140     FillTableFromRule(*aRuleList.GetRule(i));
141   }
142 }
143 
FillTableFromStyleSheet(ServoStyleSheet & aSheet)144 void ServoStyleRuleMap::FillTableFromStyleSheet(ServoStyleSheet& aSheet) {
145   if (aSheet.IsComplete()) {
146     FillTableFromRuleList(*aSheet.GetCssRulesInternal());
147   }
148 }
149 
150 }  // namespace mozilla
151