1use std::cell::Cell;
6
7use dom_struct::dom_struct;
8use style::shared_lock::{SharedRwLock, SharedRwLockReadGuard};
9use style::stylesheets::{CssRule as StyleCssRule, CssRuleType};
10
11use super::cssfontfacerule::CSSFontFaceRule;
12use super::cssimportrule::CSSImportRule;
13use super::csskeyframerule::CSSKeyframeRule;
14use super::csskeyframesrule::CSSKeyframesRule;
15use super::csslayerblockrule::CSSLayerBlockRule;
16use super::csslayerstatementrule::CSSLayerStatementRule;
17use super::cssmediarule::CSSMediaRule;
18use super::cssnamespacerule::CSSNamespaceRule;
19use super::cssnesteddeclarations::CSSNestedDeclarations;
20use super::cssstylerule::CSSStyleRule;
21use super::cssstylesheet::CSSStyleSheet;
22use super::csssupportsrule::CSSSupportsRule;
23use crate::dom::bindings::codegen::Bindings::CSSRuleBinding::CSSRuleMethods;
24use crate::dom::bindings::inheritance::Castable;
25use crate::dom::bindings::reflector::Reflector;
26use crate::dom::bindings::root::{Dom, DomRoot};
27use crate::dom::bindings::str::DOMString;
28use crate::dom::window::Window;
29use crate::script_runtime::CanGc;
30
31#[dom_struct]
32pub(crate) struct CSSRule {
33 reflector_: Reflector,
34 parent_stylesheet: Dom<CSSStyleSheet>,
35
36 parent_stylesheet_removed: Cell<bool>,
40}
41
42impl CSSRule {
43 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
44 pub(crate) fn new_inherited(parent_stylesheet: &CSSStyleSheet) -> CSSRule {
45 CSSRule {
46 reflector_: Reflector::new(),
47 parent_stylesheet: Dom::from_ref(parent_stylesheet),
48 parent_stylesheet_removed: Cell::new(false),
49 }
50 }
51
52 pub(crate) fn as_specific(&self) -> &dyn SpecificCSSRule {
53 if let Some(rule) = self.downcast::<CSSStyleRule>() {
54 rule as &dyn SpecificCSSRule
55 } else if let Some(rule) = self.downcast::<CSSFontFaceRule>() {
56 rule as &dyn SpecificCSSRule
57 } else if let Some(rule) = self.downcast::<CSSKeyframesRule>() {
58 rule as &dyn SpecificCSSRule
59 } else if let Some(rule) = self.downcast::<CSSMediaRule>() {
60 rule as &dyn SpecificCSSRule
61 } else if let Some(rule) = self.downcast::<CSSNamespaceRule>() {
62 rule as &dyn SpecificCSSRule
63 } else if let Some(rule) = self.downcast::<CSSKeyframeRule>() {
64 rule as &dyn SpecificCSSRule
65 } else if let Some(rule) = self.downcast::<CSSImportRule>() {
66 rule as &dyn SpecificCSSRule
67 } else if let Some(rule) = self.downcast::<CSSSupportsRule>() {
68 rule as &dyn SpecificCSSRule
69 } else if let Some(rule) = self.downcast::<CSSLayerBlockRule>() {
70 rule as &dyn SpecificCSSRule
71 } else if let Some(rule) = self.downcast::<CSSLayerStatementRule>() {
72 rule as &dyn SpecificCSSRule
73 } else if let Some(rule) = self.downcast::<CSSNestedDeclarations>() {
74 rule as &dyn SpecificCSSRule
75 } else {
76 unreachable!()
77 }
78 }
79
80 pub(crate) fn new_specific(
83 window: &Window,
84 parent_stylesheet: &CSSStyleSheet,
85 rule: StyleCssRule,
86 can_gc: CanGc,
87 ) -> DomRoot<CSSRule> {
88 match rule {
90 StyleCssRule::Import(s) => {
91 DomRoot::upcast(CSSImportRule::new(window, parent_stylesheet, s, can_gc))
92 },
93 StyleCssRule::Style(s) => {
94 DomRoot::upcast(CSSStyleRule::new(window, parent_stylesheet, s, can_gc))
95 },
96 StyleCssRule::FontFace(s) => {
97 DomRoot::upcast(CSSFontFaceRule::new(window, parent_stylesheet, s, can_gc))
98 },
99 StyleCssRule::FontFeatureValues(_) => unimplemented!(),
100 StyleCssRule::CounterStyle(_) => unimplemented!(),
101 StyleCssRule::Keyframes(s) => {
102 DomRoot::upcast(CSSKeyframesRule::new(window, parent_stylesheet, s, can_gc))
103 },
104 StyleCssRule::Media(s) => {
105 DomRoot::upcast(CSSMediaRule::new(window, parent_stylesheet, s, can_gc))
106 },
107 StyleCssRule::Namespace(s) => {
108 DomRoot::upcast(CSSNamespaceRule::new(window, parent_stylesheet, s, can_gc))
109 },
110 StyleCssRule::Supports(s) => {
111 DomRoot::upcast(CSSSupportsRule::new(window, parent_stylesheet, s, can_gc))
112 },
113 StyleCssRule::Page(_) => unreachable!(),
114 StyleCssRule::Container(_) => unimplemented!(), StyleCssRule::Document(_) => unimplemented!(), StyleCssRule::LayerBlock(s) => {
117 DomRoot::upcast(CSSLayerBlockRule::new(window, parent_stylesheet, s, can_gc))
118 },
119 StyleCssRule::LayerStatement(s) => DomRoot::upcast(CSSLayerStatementRule::new(
120 window,
121 parent_stylesheet,
122 s,
123 can_gc,
124 )),
125 StyleCssRule::FontPaletteValues(_) => unimplemented!(), StyleCssRule::Property(_) => unimplemented!(), StyleCssRule::Margin(_) => unimplemented!(), StyleCssRule::Scope(_) => unimplemented!(), StyleCssRule::StartingStyle(_) => unimplemented!(), StyleCssRule::PositionTry(_) => unimplemented!(), StyleCssRule::CustomMedia(_) => unimplemented!(), StyleCssRule::NestedDeclarations(s) => DomRoot::upcast(CSSNestedDeclarations::new(
133 window,
134 parent_stylesheet,
135 s,
136 can_gc,
137 )),
138 }
139 }
140
141 pub(crate) fn detach(&self) {
143 self.deparent();
144 }
146
147 pub(crate) fn deparent(&self) {
149 self.parent_stylesheet_removed.set(true);
150 self.as_specific().deparent_children();
154 }
155
156 pub(crate) fn parent_stylesheet(&self) -> &CSSStyleSheet {
157 &self.parent_stylesheet
158 }
159
160 pub(crate) fn shared_lock(&self) -> &SharedRwLock {
161 self.parent_stylesheet.shared_lock()
162 }
163
164 pub(crate) fn update_rule(&self, style_rule: &StyleCssRule, guard: &SharedRwLockReadGuard) {
165 match style_rule {
166 StyleCssRule::Import(s) => {
167 if let Some(rule) = self.downcast::<CSSImportRule>() {
168 rule.update_rule(s.clone());
169 }
170 },
171 StyleCssRule::Style(s) => {
172 if let Some(rule) = self.downcast::<CSSStyleRule>() {
173 rule.update_rule(s.clone(), guard);
174 }
175 },
176 StyleCssRule::FontFace(s) => {
177 if let Some(rule) = self.downcast::<CSSFontFaceRule>() {
178 rule.update_rule(s.clone());
179 }
180 },
181 StyleCssRule::FontFeatureValues(_) => unimplemented!(),
182 StyleCssRule::CounterStyle(_) => unimplemented!(),
183 StyleCssRule::Keyframes(s) => {
184 if let Some(rule) = self.downcast::<CSSKeyframesRule>() {
185 rule.update_rule(s.clone(), guard);
186 }
187 },
188 StyleCssRule::Media(s) => {
189 if let Some(rule) = self.downcast::<CSSMediaRule>() {
190 rule.update_rule(s.clone(), guard);
191 }
192 },
193 StyleCssRule::Namespace(s) => {
194 if let Some(rule) = self.downcast::<CSSNamespaceRule>() {
195 rule.update_rule(s.clone());
196 }
197 },
198 StyleCssRule::Supports(s) => {
199 if let Some(rule) = self.downcast::<CSSSupportsRule>() {
200 rule.update_rule(s.clone(), guard);
201 }
202 },
203 StyleCssRule::Page(_) => unreachable!(),
204 StyleCssRule::Container(_) => unimplemented!(), StyleCssRule::Document(_) => unimplemented!(), StyleCssRule::LayerBlock(s) => {
207 if let Some(rule) = self.downcast::<CSSLayerBlockRule>() {
208 rule.update_rule(s.clone(), guard);
209 }
210 },
211 StyleCssRule::LayerStatement(s) => {
212 if let Some(rule) = self.downcast::<CSSLayerStatementRule>() {
213 rule.update_rule(s.clone());
214 }
215 },
216 StyleCssRule::FontPaletteValues(_) => unimplemented!(), StyleCssRule::Property(_) => unimplemented!(), StyleCssRule::Margin(_) => unimplemented!(), StyleCssRule::Scope(_) => unimplemented!(), StyleCssRule::StartingStyle(_) => unimplemented!(), StyleCssRule::PositionTry(_) => unimplemented!(), StyleCssRule::CustomMedia(_) => unimplemented!(), StyleCssRule::NestedDeclarations(s) => {
224 if let Some(rule) = self.downcast::<CSSNestedDeclarations>() {
225 rule.update_rule(s.clone(), guard);
226 }
227 },
228 }
229 }
230}
231
232impl CSSRuleMethods<crate::DomTypeHolder> for CSSRule {
233 fn Type(&self) -> u16 {
235 let rule_type = self.as_specific().ty() as u16;
236 if rule_type > 15 { 0 } else { rule_type }
239 }
240
241 fn GetParentStyleSheet(&self) -> Option<DomRoot<CSSStyleSheet>> {
243 if self.parent_stylesheet_removed.get() {
244 None
245 } else {
246 Some(DomRoot::from_ref(&*self.parent_stylesheet))
247 }
248 }
249
250 fn CssText(&self) -> DOMString {
252 self.as_specific().get_css()
253 }
254
255 fn SetCssText(&self, _: DOMString) {
257 }
259}
260
261pub(crate) trait SpecificCSSRule {
262 fn ty(&self) -> CssRuleType;
263 fn get_css(&self) -> DOMString;
264 fn deparent_children(&self) {
266 }
268}