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