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 cssgroupingrule: CSSGroupingRule,
31 #[ignore_malloc_size_of = "Stylo"]
32 #[no_trace]
33 stylerule: RefCell<Arc<Locked<StyleRule>>>,
34 style_decl: MutNullableDom<CSSStyleDeclaration>,
35}
36
37impl CSSStyleRule {
38 fn new_inherited(
39 parent_stylesheet: &CSSStyleSheet,
40 stylerule: Arc<Locked<StyleRule>>,
41 ) -> CSSStyleRule {
42 CSSStyleRule {
43 cssgroupingrule: CSSGroupingRule::new_inherited(parent_stylesheet),
44 stylerule: RefCell::new(stylerule),
45 style_decl: Default::default(),
46 }
47 }
48
49 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
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.cssgroupingrule.shared_lock();
65 let mut guard = lock.write();
66 self.stylerule
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.cssgroupingrule.update_rules(rules, guard);
81 }
82
83 if let Some(ref style_decl) = self.style_decl.get() {
84 style_decl.update_property_declaration_block(&stylerule.read_with(guard).block);
85 }
86
87 *self.stylerule.borrow_mut() = stylerule;
88 }
89}
90
91impl SpecificCSSRule for CSSStyleRule {
92 fn ty(&self) -> CssRuleType {
93 CssRuleType::Style
94 }
95
96 fn get_css(&self) -> DOMString {
97 let guard = self.cssgroupingrule.shared_lock().read();
98 self.stylerule
99 .borrow()
100 .read_with(&guard)
101 .to_css_string(&guard)
102 .into()
103 }
104}
105
106impl CSSStyleRuleMethods<crate::DomTypeHolder> for CSSStyleRule {
107 fn Style(&self, can_gc: CanGc) -> DomRoot<CSSStyleDeclaration> {
109 self.style_decl.or_init(|| {
110 let guard = self.cssgroupingrule.shared_lock().read();
111 CSSStyleDeclaration::new(
112 self.global().as_window(),
113 CSSStyleOwner::CSSRule(
114 Dom::from_ref(self.upcast()),
115 RefCell::new(self.stylerule.borrow().read_with(&guard).block.clone()),
116 ),
117 None,
118 CSSModificationAccess::ReadWrite,
119 can_gc,
120 )
121 })
122 }
123
124 fn SelectorText(&self) -> DOMString {
126 let guard = self.cssgroupingrule.shared_lock().read();
127 DOMString::from_string(
128 self.stylerule
129 .borrow()
130 .read_with(&guard)
131 .selectors
132 .to_css_string(),
133 )
134 }
135
136 fn SetSelectorText(&self, value: DOMString) {
138 let value = value.str();
139 let Ok(mut selector) = ({
140 let guard = self.cssgroupingrule.shared_lock().read();
141 let sheet = self.cssgroupingrule.parent_stylesheet().style_stylesheet();
142 let contents = sheet.contents(&guard);
143 let parser = SelectorParser {
146 stylesheet_origin: Origin::Author,
147 namespaces: &contents.namespaces,
148 url_data: &contents.url_data,
149 for_supports_rule: false,
150 };
151 let mut css_parser = CssParserInput::new(&value);
152 let mut css_parser = CssParser::new(&mut css_parser);
153 SelectorList::parse(&parser, &mut css_parser, ParseRelative::No)
156 }) else {
157 return;
158 };
159 self.cssgroupingrule.parent_stylesheet().will_modify();
160 let mut guard = self.cssgroupingrule.shared_lock().write();
162 mem::swap(
163 &mut self.stylerule.borrow().write_with(&mut guard).selectors,
164 &mut selector,
165 );
166 self.cssgroupingrule
167 .parent_stylesheet()
168 .notify_invalidations();
169 }
170}