script/dom/css/
cssstylerule.rs1use std::cell::RefCell;
6use std::mem;
7
8use cssparser::{Parser as CssParser, ParserInput as CssParserInput, ToCss};
9use dom_struct::dom_struct;
10use js::context::{JSContext, NoGC};
11use script_bindings::reflector::reflect_dom_object_with_cx;
12use selectors::parser::{ParseRelative, SelectorList};
13use servo_arc::Arc;
14use style::selector_parser::SelectorParser;
15use style::shared_lock::{Locked, SharedRwLockReadGuard, ToCssWithGuard};
16use style::stylesheets::{CssRuleType, CssRules, Origin, StyleRule, StylesheetInDocument};
17
18use super::cssrule::SpecificCSSRule;
19use super::cssstyledeclaration::{CSSModificationAccess, CSSStyleDeclaration, CSSStyleOwner};
20use super::cssstylesheet::CSSStyleSheet;
21use crate::dom::bindings::codegen::Bindings::CSSStyleRuleBinding::CSSStyleRuleMethods;
22use crate::dom::bindings::inheritance::Castable;
23use crate::dom::bindings::reflector::DomGlobal;
24use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
25use crate::dom::bindings::str::DOMString;
26use crate::dom::cssgroupingrule::CSSGroupingRule;
27use crate::dom::types::CSSRule;
28use crate::dom::window::Window;
29
30#[dom_struct]
31pub(crate) struct CSSStyleRule {
32 css_grouping_rule: CSSGroupingRule,
33 #[ignore_malloc_size_of = "Stylo"]
34 #[no_trace]
35 style_rule: RefCell<Arc<Locked<StyleRule>>>,
36 style_declaration: MutNullableDom<CSSStyleDeclaration>,
37}
38
39impl CSSStyleRule {
40 fn new_inherited(
41 parent_rule: Option<&CSSGroupingRule>,
42 parent_stylesheet: &CSSStyleSheet,
43 stylerule: Arc<Locked<StyleRule>>,
44 ) -> CSSStyleRule {
45 CSSStyleRule {
46 css_grouping_rule: CSSGroupingRule::new_inherited(parent_rule, parent_stylesheet),
47 style_rule: RefCell::new(stylerule),
48 style_declaration: Default::default(),
49 }
50 }
51
52 pub(crate) fn new(
53 cx: &mut JSContext,
54 window: &Window,
55 parent_rule: Option<&CSSGroupingRule>,
56 parent_stylesheet: &CSSStyleSheet,
57 stylerule: Arc<Locked<StyleRule>>,
58 ) -> DomRoot<CSSStyleRule> {
59 reflect_dom_object_with_cx(
60 Box::new(CSSStyleRule::new_inherited(
61 parent_rule,
62 parent_stylesheet,
63 stylerule,
64 )),
65 window,
66 cx,
67 )
68 }
69
70 pub(crate) fn ensure_rules(&self) -> Arc<Locked<CssRules>> {
71 let lock = self.css_grouping_rule.shared_lock();
72 let mut guard = lock.write();
73 self.style_rule
74 .borrow()
75 .write_with(&mut guard)
76 .rules
77 .get_or_insert_with(|| CssRules::new(vec![], lock))
78 .clone()
79 }
80
81 pub(crate) fn update_rule(
82 &self,
83 stylerule: Arc<Locked<StyleRule>>,
84 guard: &SharedRwLockReadGuard,
85 ) {
86 if let Some(ref rules) = stylerule.read_with(guard).rules {
87 self.css_grouping_rule.update_rules(rules, guard);
88 }
89
90 if let Some(ref style_decl) = self.style_declaration.get() {
91 style_decl.update_property_declaration_block(&stylerule.read_with(guard).block);
92 }
93
94 *self.style_rule.borrow_mut() = stylerule;
95 }
96
97 pub(crate) fn block_id(&self) -> usize {
98 let guard = self.css_grouping_rule.shared_lock().read();
99 self.style_rule
100 .borrow()
101 .read_with(&guard)
102 .block
103 .raw_ptr()
104 .as_ptr() as usize
105 }
106}
107
108impl SpecificCSSRule for CSSStyleRule {
109 fn ty(&self) -> CssRuleType {
110 CssRuleType::Style
111 }
112
113 fn get_css(&self) -> DOMString {
114 let guard = self.css_grouping_rule.shared_lock().read();
115 self.style_rule
116 .borrow()
117 .read_with(&guard)
118 .to_css_string(&guard)
119 .into()
120 }
121}
122
123impl CSSStyleRuleMethods<crate::DomTypeHolder> for CSSStyleRule {
124 fn Style(&self, cx: &mut JSContext) -> DomRoot<CSSStyleDeclaration> {
126 self.style_declaration.or_init(|| {
127 let guard = self.css_grouping_rule.shared_lock().read();
128 CSSStyleDeclaration::new(
129 cx,
130 self.global().as_window(),
131 CSSStyleOwner::CSSRule(
132 Dom::from_ref(self.upcast()),
133 RefCell::new(self.style_rule.borrow().read_with(&guard).block.clone()),
134 ),
135 None,
136 CSSModificationAccess::ReadWrite,
137 )
138 })
139 }
140
141 fn SelectorText(&self) -> DOMString {
143 let guard = self.css_grouping_rule.shared_lock().read();
144 self.style_rule
145 .borrow()
146 .read_with(&guard)
147 .selectors
148 .to_css_string()
149 .into()
150 }
151
152 fn SetSelectorText(&self, no_gc: &NoGC, value: DOMString) {
154 let value = value.str();
155 let Ok(mut selector) = ({
156 let guard = self.css_grouping_rule.shared_lock().read();
157 let sheet = self
158 .css_grouping_rule
159 .parent_stylesheet()
160 .style_stylesheet();
161 let contents = sheet.contents(&guard);
162 let parser = SelectorParser {
165 stylesheet_origin: Origin::Author,
166 namespaces: &contents.namespaces,
167 url_data: &contents.url_data,
168 for_supports_rule: false,
169 };
170 let mut css_parser = CssParserInput::new(&value);
171 let mut css_parser = CssParser::new(&mut css_parser);
172
173 let parse_relative = match self
174 .upcast::<CSSRule>()
175 .parent_rule()
176 .map(|parent| parent.upcast::<CSSRule>().rule_type())
177 {
178 Some(CssRuleType::Style) => ParseRelative::ForNesting,
179 Some(CssRuleType::Scope) => ParseRelative::ForScope,
180 _ => ParseRelative::No,
181 };
182 SelectorList::parse(&parser, &mut css_parser, parse_relative)
183 }) else {
184 return;
185 };
186 self.css_grouping_rule.parent_stylesheet().will_modify();
187 let mut guard = self.css_grouping_rule.shared_lock().write();
189 mem::swap(
190 &mut self.style_rule.borrow().write_with(&mut guard).selectors,
191 &mut selector,
192 );
193 self.css_grouping_rule
194 .parent_stylesheet()
195 .notify_invalidations(no_gc);
196 }
197}