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 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.cssgroupingrule.shared_lock();
64 let mut guard = lock.write();
65 self.stylerule
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.cssgroupingrule.update_rules(rules, guard);
80 }
81
82 if let Some(ref style_decl) = self.style_decl.get() {
83 style_decl.update_property_declaration_block(&stylerule.read_with(guard).block);
84 }
85
86 *self.stylerule.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.cssgroupingrule.shared_lock().read();
97 self.stylerule
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_decl.or_init(|| {
109 let guard = self.cssgroupingrule.shared_lock().read();
110 CSSStyleDeclaration::new(
111 self.global().as_window(),
112 CSSStyleOwner::CSSRule(
113 Dom::from_ref(self.upcast()),
114 RefCell::new(self.stylerule.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.cssgroupingrule.shared_lock().read();
126 DOMString::from_string(
127 self.stylerule
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.cssgroupingrule.shared_lock().read();
140 let sheet = self.cssgroupingrule.parent_stylesheet().style_stylesheet();
141 let contents = sheet.contents(&guard);
142 let parser = SelectorParser {
145 stylesheet_origin: Origin::Author,
146 namespaces: &contents.namespaces,
147 url_data: &contents.url_data,
148 for_supports_rule: false,
149 };
150 let mut css_parser = CssParserInput::new(&value);
151 let mut css_parser = CssParser::new(&mut css_parser);
152 SelectorList::parse(&parser, &mut css_parser, ParseRelative::No)
155 }) else {
156 return;
157 };
158 self.cssgroupingrule.parent_stylesheet().will_modify();
159 let mut guard = self.cssgroupingrule.shared_lock().write();
161 mem::swap(
162 &mut self.stylerule.borrow().write_with(&mut guard).selectors,
163 &mut selector,
164 );
165 self.cssgroupingrule
166 .parent_stylesheet()
167 .notify_invalidations();
168 }
169}