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 crate::dom::bindings::codegen::Bindings::CSSRuleBinding::CSSRuleMethods;
12use crate::dom::bindings::inheritance::Castable;
13use crate::dom::bindings::reflector::Reflector;
14use crate::dom::bindings::root::{Dom, DomRoot};
15use crate::dom::bindings::str::DOMString;
16use crate::dom::cssfontfacerule::CSSFontFaceRule;
17use crate::dom::cssimportrule::CSSImportRule;
18use crate::dom::csskeyframerule::CSSKeyframeRule;
19use crate::dom::csskeyframesrule::CSSKeyframesRule;
20use crate::dom::csslayerblockrule::CSSLayerBlockRule;
21use crate::dom::csslayerstatementrule::CSSLayerStatementRule;
22use crate::dom::cssmediarule::CSSMediaRule;
23use crate::dom::cssnamespacerule::CSSNamespaceRule;
24use crate::dom::cssnesteddeclarations::CSSNestedDeclarations;
25use crate::dom::cssstylerule::CSSStyleRule;
26use crate::dom::cssstylesheet::CSSStyleSheet;
27use crate::dom::csssupportsrule::CSSSupportsRule;
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::NestedDeclarations(s) => DomRoot::upcast(CSSNestedDeclarations::new(
132 window,
133 parent_stylesheet,
134 s,
135 can_gc,
136 )),
137 }
138 }
139
140 pub(crate) fn detach(&self) {
142 self.deparent();
143 }
145
146 pub(crate) fn deparent(&self) {
148 self.parent_stylesheet_removed.set(true);
149 self.as_specific().deparent_children();
153 }
154
155 pub(crate) fn parent_stylesheet(&self) -> &CSSStyleSheet {
156 &self.parent_stylesheet
157 }
158
159 pub(crate) fn shared_lock(&self) -> &SharedRwLock {
160 self.parent_stylesheet.shared_lock()
161 }
162
163 pub(crate) fn update_rule(&self, style_rule: &StyleCssRule, guard: &SharedRwLockReadGuard) {
164 match style_rule {
165 StyleCssRule::Import(s) => {
166 if let Some(rule) = self.downcast::<CSSImportRule>() {
167 rule.update_rule(s.clone());
168 }
169 },
170 StyleCssRule::Style(s) => {
171 if let Some(rule) = self.downcast::<CSSStyleRule>() {
172 rule.update_rule(s.clone(), guard);
173 }
174 },
175 StyleCssRule::FontFace(s) => {
176 if let Some(rule) = self.downcast::<CSSFontFaceRule>() {
177 rule.update_rule(s.clone());
178 }
179 },
180 StyleCssRule::FontFeatureValues(_) => unimplemented!(),
181 StyleCssRule::CounterStyle(_) => unimplemented!(),
182 StyleCssRule::Keyframes(s) => {
183 if let Some(rule) = self.downcast::<CSSKeyframesRule>() {
184 rule.update_rule(s.clone(), guard);
185 }
186 },
187 StyleCssRule::Media(s) => {
188 if let Some(rule) = self.downcast::<CSSMediaRule>() {
189 rule.update_rule(s.clone(), guard);
190 }
191 },
192 StyleCssRule::Namespace(s) => {
193 if let Some(rule) = self.downcast::<CSSNamespaceRule>() {
194 rule.update_rule(s.clone());
195 }
196 },
197 StyleCssRule::Supports(s) => {
198 if let Some(rule) = self.downcast::<CSSSupportsRule>() {
199 rule.update_rule(s.clone(), guard);
200 }
201 },
202 StyleCssRule::Page(_) => unreachable!(),
203 StyleCssRule::Container(_) => unimplemented!(), StyleCssRule::Document(_) => unimplemented!(), StyleCssRule::LayerBlock(s) => {
206 if let Some(rule) = self.downcast::<CSSLayerBlockRule>() {
207 rule.update_rule(s.clone(), guard);
208 }
209 },
210 StyleCssRule::LayerStatement(s) => {
211 if let Some(rule) = self.downcast::<CSSLayerStatementRule>() {
212 rule.update_rule(s.clone());
213 }
214 },
215 StyleCssRule::FontPaletteValues(_) => unimplemented!(), StyleCssRule::Property(_) => unimplemented!(), StyleCssRule::Margin(_) => unimplemented!(), StyleCssRule::Scope(_) => unimplemented!(), StyleCssRule::StartingStyle(_) => unimplemented!(), StyleCssRule::PositionTry(_) => unimplemented!(), StyleCssRule::NestedDeclarations(s) => {
222 if let Some(rule) = self.downcast::<CSSNestedDeclarations>() {
223 rule.update_rule(s.clone(), guard);
224 }
225 },
226 }
227 }
228}
229
230impl CSSRuleMethods<crate::DomTypeHolder> for CSSRule {
231 fn Type(&self) -> u16 {
233 let rule_type = self.as_specific().ty() as u16;
234 if rule_type > 15 { 0 } else { rule_type }
237 }
238
239 fn GetParentStyleSheet(&self) -> Option<DomRoot<CSSStyleSheet>> {
241 if self.parent_stylesheet_removed.get() {
242 None
243 } else {
244 Some(DomRoot::from_ref(&*self.parent_stylesheet))
245 }
246 }
247
248 fn CssText(&self) -> DOMString {
250 self.as_specific().get_css()
251 }
252
253 fn SetCssText(&self, _: DOMString) {
255 }
257}
258
259pub(crate) trait SpecificCSSRule {
260 fn ty(&self) -> CssRuleType;
261 fn get_css(&self) -> DOMString;
262 fn deparent_children(&self) {
264 }
266}