1use std::cell::Cell;
6
7use dom_struct::dom_struct;
8use js::context::JSContext;
9use script_bindings::reflector::Reflector;
10use style::shared_lock::{SharedRwLock, SharedRwLockReadGuard};
11use style::stylesheets::{CssRule as StyleCssRule, CssRuleType};
12
13use super::cssfontfacerule::CSSFontFaceRule;
14use super::cssfontfeaturevaluesrule::CSSFontFeatureValuesRule;
15use super::cssimportrule::CSSImportRule;
16use super::csskeyframerule::CSSKeyframeRule;
17use super::csskeyframesrule::CSSKeyframesRule;
18use super::csslayerblockrule::CSSLayerBlockRule;
19use super::csslayerstatementrule::CSSLayerStatementRule;
20use super::cssmediarule::CSSMediaRule;
21use super::cssnamespacerule::CSSNamespaceRule;
22use super::cssnesteddeclarations::CSSNestedDeclarations;
23use super::csspropertyrule::CSSPropertyRule;
24use super::cssstylerule::CSSStyleRule;
25use super::cssstylesheet::CSSStyleSheet;
26use super::csssupportsrule::CSSSupportsRule;
27use crate::dom::bindings::codegen::Bindings::CSSRuleBinding::CSSRuleMethods;
28use crate::dom::bindings::inheritance::Castable;
29use crate::dom::bindings::root::{Dom, DomRoot};
30use crate::dom::bindings::str::DOMString;
31use crate::dom::cssgroupingrule::CSSGroupingRule;
32use crate::dom::window::Window;
33
34#[dom_struct]
35pub(crate) struct CSSRule {
36 reflector_: Reflector,
37 parent_rule: Option<Dom<CSSGroupingRule>>,
38 parent_stylesheet: Dom<CSSStyleSheet>,
39
40 parent_stylesheet_removed: Cell<bool>,
44}
45
46impl CSSRule {
47 pub(crate) fn new_inherited(
48 parent_rule: Option<&CSSGroupingRule>,
49 parent_stylesheet: &CSSStyleSheet,
50 ) -> CSSRule {
51 CSSRule {
52 reflector_: Reflector::new(),
53 parent_rule: parent_rule.map(Dom::from_ref),
54 parent_stylesheet: Dom::from_ref(parent_stylesheet),
55 parent_stylesheet_removed: Cell::new(false),
56 }
57 }
58
59 pub(crate) fn as_specific(&self) -> &dyn SpecificCSSRule {
60 if let Some(rule) = self.downcast::<CSSStyleRule>() {
61 rule as &dyn SpecificCSSRule
62 } else if let Some(rule) = self.downcast::<CSSFontFaceRule>() {
63 rule as &dyn SpecificCSSRule
64 } else if let Some(rule) = self.downcast::<CSSKeyframesRule>() {
65 rule as &dyn SpecificCSSRule
66 } else if let Some(rule) = self.downcast::<CSSMediaRule>() {
67 rule as &dyn SpecificCSSRule
68 } else if let Some(rule) = self.downcast::<CSSNamespaceRule>() {
69 rule as &dyn SpecificCSSRule
70 } else if let Some(rule) = self.downcast::<CSSKeyframeRule>() {
71 rule as &dyn SpecificCSSRule
72 } else if let Some(rule) = self.downcast::<CSSImportRule>() {
73 rule as &dyn SpecificCSSRule
74 } else if let Some(rule) = self.downcast::<CSSSupportsRule>() {
75 rule as &dyn SpecificCSSRule
76 } else if let Some(rule) = self.downcast::<CSSLayerBlockRule>() {
77 rule as &dyn SpecificCSSRule
78 } else if let Some(rule) = self.downcast::<CSSLayerStatementRule>() {
79 rule as &dyn SpecificCSSRule
80 } else if let Some(rule) = self.downcast::<CSSNestedDeclarations>() {
81 rule as &dyn SpecificCSSRule
82 } else if let Some(rule) = self.downcast::<CSSPropertyRule>() {
83 rule as &dyn SpecificCSSRule
84 } else if let Some(rule) = self.downcast::<CSSFontFeatureValuesRule>() {
85 rule as &dyn SpecificCSSRule
86 } else {
87 unreachable!()
88 }
89 }
90
91 pub(crate) fn new_specific(
94 cx: &mut JSContext,
95 window: &Window,
96 parent_rule: Option<&CSSGroupingRule>,
97 parent_stylesheet: &CSSStyleSheet,
98 rule: StyleCssRule,
99 ) -> DomRoot<CSSRule> {
100 match rule {
102 StyleCssRule::Import(s) => DomRoot::upcast(CSSImportRule::new(
103 cx,
104 window,
105 parent_rule,
106 parent_stylesheet,
107 s,
108 )),
109 StyleCssRule::Style(s) => DomRoot::upcast(CSSStyleRule::new(
110 cx,
111 window,
112 parent_rule,
113 parent_stylesheet,
114 s,
115 )),
116 StyleCssRule::FontFace(s) => DomRoot::upcast(CSSFontFaceRule::new(
117 cx,
118 window,
119 parent_rule,
120 parent_stylesheet,
121 s,
122 )),
123 StyleCssRule::FontFeatureValues(rule) => DomRoot::upcast(
124 CSSFontFeatureValuesRule::new(cx, window, parent_rule, parent_stylesheet, rule),
125 ),
126 StyleCssRule::CounterStyle(_) => unimplemented!(),
127 StyleCssRule::Keyframes(s) => DomRoot::upcast(CSSKeyframesRule::new(
128 cx,
129 window,
130 parent_rule,
131 parent_stylesheet,
132 s,
133 )),
134 StyleCssRule::Media(s) => DomRoot::upcast(CSSMediaRule::new(
135 cx,
136 window,
137 parent_rule,
138 parent_stylesheet,
139 s,
140 )),
141 StyleCssRule::Namespace(s) => DomRoot::upcast(CSSNamespaceRule::new(
142 cx,
143 window,
144 parent_rule,
145 parent_stylesheet,
146 s,
147 )),
148 StyleCssRule::Supports(s) => DomRoot::upcast(CSSSupportsRule::new(
149 cx,
150 window,
151 parent_rule,
152 parent_stylesheet,
153 s,
154 )),
155 StyleCssRule::Page(_) => unreachable!(),
156 StyleCssRule::Container(_) => unimplemented!(), StyleCssRule::Document(_) => unimplemented!(), StyleCssRule::LayerBlock(s) => DomRoot::upcast(CSSLayerBlockRule::new(
159 cx,
160 window,
161 parent_rule,
162 parent_stylesheet,
163 s,
164 )),
165 StyleCssRule::LayerStatement(s) => DomRoot::upcast(CSSLayerStatementRule::new(
166 cx,
167 window,
168 parent_rule,
169 parent_stylesheet,
170 s,
171 )),
172 StyleCssRule::FontPaletteValues(_) => unimplemented!(), StyleCssRule::Property(s) => DomRoot::upcast(CSSPropertyRule::new(
174 cx,
175 window,
176 parent_rule,
177 parent_stylesheet,
178 s,
179 )),
180 StyleCssRule::Margin(_) => unimplemented!(), StyleCssRule::Scope(_) => unimplemented!(), StyleCssRule::StartingStyle(_) => unimplemented!(), StyleCssRule::PositionTry(_) => unimplemented!(), StyleCssRule::CustomMedia(_) => unimplemented!(), StyleCssRule::NestedDeclarations(s) => DomRoot::upcast(CSSNestedDeclarations::new(
186 cx,
187 window,
188 parent_rule,
189 parent_stylesheet,
190 s,
191 )),
192 StyleCssRule::AppearanceBase(_) => unimplemented!(), StyleCssRule::ViewTransition(_) => unimplemented!(), }
195 }
196
197 pub(crate) fn detach(&self) {
199 self.deparent();
200 }
202
203 pub(crate) fn deparent(&self) {
205 self.parent_stylesheet_removed.set(true);
206 self.as_specific().deparent_children();
210 }
211
212 pub(crate) fn parent_rule(&self) -> Option<&CSSGroupingRule> {
213 self.parent_rule.as_deref()
214 }
215
216 pub(crate) fn parent_stylesheet(&self) -> &CSSStyleSheet {
217 &self.parent_stylesheet
218 }
219
220 pub(crate) fn shared_lock(&self) -> &SharedRwLock {
221 self.parent_stylesheet.shared_lock()
222 }
223
224 pub(crate) fn rule_type(&self) -> CssRuleType {
225 self.as_specific().ty()
226 }
227
228 pub(crate) fn update_rule(&self, style_rule: &StyleCssRule, guard: &SharedRwLockReadGuard) {
229 match style_rule {
230 StyleCssRule::Import(s) => {
231 if let Some(rule) = self.downcast::<CSSImportRule>() {
232 rule.update_rule(s.clone());
233 }
234 },
235 StyleCssRule::Style(s) => {
236 if let Some(rule) = self.downcast::<CSSStyleRule>() {
237 rule.update_rule(s.clone(), guard);
238 }
239 },
240 StyleCssRule::FontFace(s) => {
241 if let Some(rule) = self.downcast::<CSSFontFaceRule>() {
242 rule.update_rule(s.clone());
243 }
244 },
245 StyleCssRule::FontFeatureValues(_) => unimplemented!(),
246 StyleCssRule::CounterStyle(_) => unimplemented!(),
247 StyleCssRule::Keyframes(s) => {
248 if let Some(rule) = self.downcast::<CSSKeyframesRule>() {
249 rule.update_rule(s.clone(), guard);
250 }
251 },
252 StyleCssRule::Media(s) => {
253 if let Some(rule) = self.downcast::<CSSMediaRule>() {
254 rule.update_rule(s.clone(), guard);
255 }
256 },
257 StyleCssRule::Namespace(s) => {
258 if let Some(rule) = self.downcast::<CSSNamespaceRule>() {
259 rule.update_rule(s.clone());
260 }
261 },
262 StyleCssRule::Supports(s) => {
263 if let Some(rule) = self.downcast::<CSSSupportsRule>() {
264 rule.update_rule(s.clone(), guard);
265 }
266 },
267 StyleCssRule::Page(_) => unreachable!(),
268 StyleCssRule::Container(_) => unimplemented!(), StyleCssRule::Document(_) => unimplemented!(), StyleCssRule::LayerBlock(s) => {
271 if let Some(rule) = self.downcast::<CSSLayerBlockRule>() {
272 rule.update_rule(s.clone(), guard);
273 }
274 },
275 StyleCssRule::LayerStatement(s) => {
276 if let Some(rule) = self.downcast::<CSSLayerStatementRule>() {
277 rule.update_rule(s.clone());
278 }
279 },
280 StyleCssRule::FontPaletteValues(_) => unimplemented!(), StyleCssRule::Property(s) => {
282 if let Some(rule) = self.downcast::<CSSPropertyRule>() {
283 rule.update_rule(s.clone());
284 }
285 },
286 StyleCssRule::Margin(_) => unimplemented!(), StyleCssRule::Scope(_) => unimplemented!(), StyleCssRule::StartingStyle(_) => unimplemented!(), StyleCssRule::PositionTry(_) => unimplemented!(), StyleCssRule::CustomMedia(_) => unimplemented!(), StyleCssRule::NestedDeclarations(s) => {
292 if let Some(rule) = self.downcast::<CSSNestedDeclarations>() {
293 rule.update_rule(s.clone(), guard);
294 }
295 },
296 StyleCssRule::AppearanceBase(_) => unimplemented!(), StyleCssRule::ViewTransition(_) => unimplemented!(), }
299 }
300}
301
302impl CSSRuleMethods<crate::DomTypeHolder> for CSSRule {
303 fn Type(&self) -> u16 {
305 let rule_type = self.as_specific().ty() as u16;
306 if rule_type > 15 { 0 } else { rule_type }
309 }
310
311 fn GetParentStyleSheet(&self) -> Option<DomRoot<CSSStyleSheet>> {
313 if self.parent_stylesheet_removed.get() {
314 None
315 } else {
316 Some(DomRoot::from_ref(&*self.parent_stylesheet))
317 }
318 }
319
320 fn CssText(&self) -> DOMString {
322 self.as_specific().get_css()
323 }
324
325 fn SetCssText(&self, _: DOMString) {
327 }
329}
330
331pub(crate) trait SpecificCSSRule {
332 fn ty(&self) -> CssRuleType;
333 fn get_css(&self) -> DOMString;
334 fn deparent_children(&self) {
336 }
338}