script/dom/
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};
15
16use crate::dom::bindings::codegen::Bindings::CSSStyleRuleBinding::CSSStyleRuleMethods;
17use crate::dom::bindings::inheritance::Castable;
18use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object};
19use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
20use crate::dom::bindings::str::DOMString;
21use crate::dom::cssgroupingrule::CSSGroupingRule;
22use crate::dom::cssrule::SpecificCSSRule;
23use crate::dom::cssstyledeclaration::{CSSModificationAccess, CSSStyleDeclaration, CSSStyleOwner};
24use crate::dom::cssstylesheet::CSSStyleSheet;
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 = "Arc"]
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 contents = &self
139 .cssgroupingrule
140 .parent_stylesheet()
141 .style_stylesheet()
142 .contents
143 .clone();
144 let namespaces = contents.namespaces.read();
147 let url_data = contents.url_data.read();
148 let parser = SelectorParser {
149 stylesheet_origin: Origin::Author,
150 namespaces: &namespaces,
151 url_data: &url_data,
152 for_supports_rule: false,
153 };
154 let mut css_parser = CssParserInput::new(&value);
155 let mut css_parser = CssParser::new(&mut css_parser);
156 if let Ok(mut s) = SelectorList::parse(&parser, &mut css_parser, ParseRelative::No) {
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 s,
165 );
166 self.cssgroupingrule
167 .parent_stylesheet()
168 .notify_invalidations();
169 }
170 }
171}