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;
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::cssgroupingrule::CSSGroupingRule;
19use super::cssrule::SpecificCSSRule;
20use super::cssstyledeclaration::{CSSModificationAccess, CSSStyleDeclaration, CSSStyleOwner};
21use super::cssstylesheet::CSSStyleSheet;
22use crate::dom::bindings::codegen::Bindings::CSSStyleRuleBinding::CSSStyleRuleMethods;
23use crate::dom::bindings::inheritance::Castable;
24use crate::dom::bindings::reflector::DomGlobal;
25use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
26use crate::dom::bindings::str::DOMString;
27use crate::dom::window::Window;
28use crate::script_runtime::CanGc;
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_stylesheet: &CSSStyleSheet,
42 stylerule: Arc<Locked<StyleRule>>,
43 ) -> CSSStyleRule {
44 CSSStyleRule {
45 css_grouping_rule: CSSGroupingRule::new_inherited(parent_stylesheet),
46 style_rule: RefCell::new(stylerule),
47 style_declaration: Default::default(),
48 }
49 }
50
51 pub(crate) fn new(
52 cx: &mut JSContext,
53 window: &Window,
54 parent_stylesheet: &CSSStyleSheet,
55 stylerule: Arc<Locked<StyleRule>>,
56 ) -> DomRoot<CSSStyleRule> {
57 reflect_dom_object_with_cx(
58 Box::new(CSSStyleRule::new_inherited(parent_stylesheet, stylerule)),
59 window,
60 cx,
61 )
62 }
63
64 pub(crate) fn ensure_rules(&self) -> Arc<Locked<CssRules>> {
65 let lock = self.css_grouping_rule.shared_lock();
66 let mut guard = lock.write();
67 self.style_rule
68 .borrow()
69 .write_with(&mut guard)
70 .rules
71 .get_or_insert_with(|| CssRules::new(vec![], lock))
72 .clone()
73 }
74
75 pub(crate) fn update_rule(
76 &self,
77 stylerule: Arc<Locked<StyleRule>>,
78 guard: &SharedRwLockReadGuard,
79 ) {
80 if let Some(ref rules) = stylerule.read_with(guard).rules {
81 self.css_grouping_rule.update_rules(rules, guard);
82 }
83
84 if let Some(ref style_decl) = self.style_declaration.get() {
85 style_decl.update_property_declaration_block(&stylerule.read_with(guard).block);
86 }
87
88 *self.style_rule.borrow_mut() = stylerule;
89 }
90
91 pub(crate) fn block_id(&self) -> usize {
92 let guard = self.css_grouping_rule.shared_lock().read();
93 self.style_rule
94 .borrow()
95 .read_with(&guard)
96 .block
97 .raw_ptr()
98 .as_ptr() as usize
99 }
100}
101
102impl SpecificCSSRule for CSSStyleRule {
103 fn ty(&self) -> CssRuleType {
104 CssRuleType::Style
105 }
106
107 fn get_css(&self) -> DOMString {
108 let guard = self.css_grouping_rule.shared_lock().read();
109 self.style_rule
110 .borrow()
111 .read_with(&guard)
112 .to_css_string(&guard)
113 .into()
114 }
115}
116
117impl CSSStyleRuleMethods<crate::DomTypeHolder> for CSSStyleRule {
118 fn Style(&self, cx: &mut JSContext) -> DomRoot<CSSStyleDeclaration> {
120 self.style_declaration.or_init(|| {
121 let guard = self.css_grouping_rule.shared_lock().read();
122 CSSStyleDeclaration::new(
123 self.global().as_window(),
124 CSSStyleOwner::CSSRule(
125 Dom::from_ref(self.upcast()),
126 RefCell::new(self.style_rule.borrow().read_with(&guard).block.clone()),
127 ),
128 None,
129 CSSModificationAccess::ReadWrite,
130 CanGc::from_cx(cx),
131 )
132 })
133 }
134
135 fn SelectorText(&self) -> DOMString {
137 let guard = self.css_grouping_rule.shared_lock().read();
138 self.style_rule
139 .borrow()
140 .read_with(&guard)
141 .selectors
142 .to_css_string()
143 .into()
144 }
145
146 fn SetSelectorText(&self, value: DOMString) {
148 let value = value.str();
149 let Ok(mut selector) = ({
150 let guard = self.css_grouping_rule.shared_lock().read();
151 let sheet = self
152 .css_grouping_rule
153 .parent_stylesheet()
154 .style_stylesheet();
155 let contents = sheet.contents(&guard);
156 let parser = SelectorParser {
159 stylesheet_origin: Origin::Author,
160 namespaces: &contents.namespaces,
161 url_data: &contents.url_data,
162 for_supports_rule: false,
163 };
164 let mut css_parser = CssParserInput::new(&value);
165 let mut css_parser = CssParser::new(&mut css_parser);
166 SelectorList::parse(&parser, &mut css_parser, ParseRelative::No)
169 }) else {
170 return;
171 };
172 self.css_grouping_rule.parent_stylesheet().will_modify();
173 let mut guard = self.css_grouping_rule.shared_lock().write();
175 mem::swap(
176 &mut self.style_rule.borrow().write_with(&mut guard).selectors,
177 &mut selector,
178 );
179 self.css_grouping_rule
180 .parent_stylesheet()
181 .notify_invalidations();
182 }
183}