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