Skip to content

Commit cd46513

Browse files
committed
Refactor references, implement grouping rules
1 parent 698b912 commit cd46513

File tree

1 file changed

+126
-37
lines changed

1 file changed

+126
-37
lines changed

node/src/stylesheet.rs

Lines changed: 126 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
use std::{
44
borrow::{BorrowMut, Cow},
55
cell::RefCell,
6+
ops::{Deref, DerefMut},
67
rc::Rc,
78
};
89

@@ -47,7 +48,7 @@ impl OwnedStyleSheet {
4748
// https://drafts.csswg.org/cssom/#the-cssstylesheet-interface
4849
#[napi(js_name = "CSSStyleSheet")]
4950
struct CSSStyleSheet {
50-
stylesheet: Rc<RefCell<OwnedStyleSheet>>,
51+
stylesheet: OwnedStyleSheet,
5152
rules: Option<Reference<CSSRuleList>>,
5253
}
5354

@@ -56,27 +57,27 @@ impl CSSStyleSheet {
5657
#[napi(constructor)]
5758
pub fn new() -> Self {
5859
CSSStyleSheet {
59-
stylesheet: Rc::new(RefCell::new(OwnedStyleSheet::new())),
60+
stylesheet: OwnedStyleSheet::new(),
6061
rules: None,
6162
}
6263
}
6364

6465
#[napi]
6566
pub fn replace_sync(&mut self, env: Env, code: String) -> Result<()> {
66-
let mut stylesheet = (*self.stylesheet).borrow_mut();
67+
// let mut stylesheet = (*self.stylesheet).borrow_mut();
6768

6869
// Disconnect all existing rules from the stylesheet.
6970
if let Some(rules) = &mut self.rules {
7071
let rules = &mut **rules;
7172
for (index, rule) in rules.rules.iter_mut().enumerate() {
7273
if let Some(rule) = rule {
7374
let rule: &mut CSSRule = get_reference(env, rule)?;
74-
rule.inner = RuleInner::Disconnected(RefCell::new(stylesheet.stylesheet.rules.0[index].clone()));
75+
rule.inner = RuleInner::Disconnected(self.stylesheet.stylesheet.rules.0[index].clone());
7576
}
7677
}
7778
}
7879

79-
stylesheet.replace_sync(code);
80+
self.stylesheet.replace_sync(code);
8081
Ok(())
8182
}
8283

@@ -87,7 +88,11 @@ impl CSSStyleSheet {
8788
}
8889

8990
let rules = CSSRuleList {
90-
stylesheet: self.stylesheet.clone(),
91+
rule_list: RuleListReference::StyleSheet(
92+
reference
93+
.clone(env)?
94+
.share_with(env, |stylesheet| Ok(&mut stylesheet.stylesheet.stylesheet.rules))?,
95+
),
9196
rules: Vec::new(),
9297
stylesheet_reference: reference,
9398
};
@@ -100,7 +105,8 @@ impl CSSStyleSheet {
100105
pub fn insert_rule(&mut self, env: Env, rule: String, index: Option<u32>) -> Result<u32> {
101106
// https://drafts.csswg.org/cssom/#insert-a-css-rule
102107
let index = index.unwrap_or(0) as usize;
103-
let stylesheet = &mut (*self.stylesheet).borrow_mut().stylesheet;
108+
// let stylesheet = &mut (*self.stylesheet).borrow_mut().stylesheet;
109+
let stylesheet = &mut self.stylesheet.stylesheet;
104110
let rules = &mut stylesheet.rules.0;
105111
if index > rules.len() {
106112
return Err(napi::Error::new(
@@ -148,7 +154,8 @@ impl CSSStyleSheet {
148154
pub fn delete_rule(&mut self, env: Env, index: u32) -> Result<()> {
149155
// https://drafts.csswg.org/cssom/#remove-a-css-rule
150156
let index = index as usize;
151-
let stylesheet = &mut (*self.stylesheet).borrow_mut().stylesheet;
157+
// let stylesheet = &mut (*self.stylesheet).borrow_mut().stylesheet;
158+
let stylesheet = &mut self.stylesheet.stylesheet;
152159
let rules = &mut stylesheet.rules.0;
153160
if index > rules.len() {
154161
return Err(napi::Error::new(
@@ -162,7 +169,7 @@ impl CSSStyleSheet {
162169
if index < rule_objects.rules.len() {
163170
if let Some(rule) = &rule_objects.rules[index] {
164171
let rule: &mut CSSRule = get_reference(env, rule)?;
165-
rule.inner = RuleInner::Disconnected(RefCell::new(rules[index].clone()));
172+
rule.inner = RuleInner::Disconnected(rules[index].clone());
166173
}
167174

168175
for rule in &rule_objects.rules[index + 1..] {
@@ -200,9 +207,43 @@ fn get_reference<T: napi::bindgen_prelude::FromNapiMutRef>(
200207
}
201208
}
202209

210+
enum RuleListReference {
211+
StyleSheet(SharedReference<CSSStyleSheet, &'static mut CssRuleList<'static>>),
212+
Rule(SharedReference<CSSGroupingRule, &'static mut CssRuleList<'static>>),
213+
}
214+
215+
impl RuleListReference {
216+
fn clone(&self, env: Env) -> Result<Self> {
217+
match self {
218+
RuleListReference::StyleSheet(s) => Ok(RuleListReference::StyleSheet(s.clone(env)?)),
219+
RuleListReference::Rule(r) => Ok(RuleListReference::Rule(r.clone(env)?)),
220+
}
221+
}
222+
}
223+
224+
impl Deref for RuleListReference {
225+
type Target = CssRuleList<'static>;
226+
227+
fn deref(&self) -> &Self::Target {
228+
match self {
229+
RuleListReference::StyleSheet(s) => &**s,
230+
RuleListReference::Rule(r) => &**r,
231+
}
232+
}
233+
}
234+
235+
impl DerefMut for RuleListReference {
236+
fn deref_mut(&mut self) -> &mut CssRuleList<'static> {
237+
match self {
238+
RuleListReference::StyleSheet(s) => &mut **s,
239+
RuleListReference::Rule(r) => &mut **r,
240+
}
241+
}
242+
}
243+
203244
#[napi(js_name = "CSSRuleList")]
204245
struct CSSRuleList {
205-
stylesheet: Rc<RefCell<OwnedStyleSheet>>,
246+
rule_list: RuleListReference,
206247
rules: Vec<Option<Ref<()>>>,
207248
stylesheet_reference: Reference<CSSStyleSheet>,
208249
}
@@ -216,7 +257,7 @@ impl CSSRuleList {
216257

217258
#[napi(getter)]
218259
pub fn length(&self) -> u32 {
219-
self.stylesheet.borrow().stylesheet.rules.0.len() as u32
260+
self.rule_list.0.len() as u32
220261
}
221262

222263
#[napi]
@@ -226,15 +267,14 @@ impl CSSRuleList {
226267
return env.get_reference_value(rule);
227268
}
228269

229-
let stylesheet = self.stylesheet.borrow();
230-
let rule = match stylesheet.stylesheet.rules.0.get(index) {
270+
let rule = match self.rule_list.0.get(index) {
231271
Some(rule) => rule,
232272
None => return Ok(env.get_null()?.into_unknown()),
233273
};
234274

235275
let css_rule = CSSRule {
236276
inner: RuleInner::Connected {
237-
stylesheet: self.stylesheet.clone(),
277+
rule_list: self.rule_list.clone(env)?,
238278
index,
239279
},
240280
parent_stylesheet: self.stylesheet_reference.clone(env)?,
@@ -245,6 +285,15 @@ impl CSSRuleList {
245285
let rule = CSSStyleRule::new(css_rule);
246286
unsafe { napi::bindgen_prelude::ToNapiValue::to_napi_value(env.raw(), rule)? }
247287
}
288+
CssRule::Media(_) => {
289+
let rule = CSSMediaRule {
290+
rule: CSSGroupingRule {
291+
rule: css_rule,
292+
rules: None,
293+
},
294+
};
295+
unsafe { napi::bindgen_prelude::ToNapiValue::to_napi_value(env.raw(), rule)? }
296+
}
248297
_ => unreachable!(),
249298
};
250299

@@ -260,11 +309,8 @@ impl CSSRuleList {
260309
}
261310

262311
enum RuleInner {
263-
Connected {
264-
stylesheet: Rc<RefCell<OwnedStyleSheet>>,
265-
index: usize,
266-
},
267-
Disconnected(RefCell<CssRule<'static>>),
312+
Connected { rule_list: RuleListReference, index: usize },
313+
Disconnected(CssRule<'static>),
268314
}
269315

270316
#[napi(js_name = "CSSRule")]
@@ -307,23 +353,20 @@ impl CSSRule {
307353
// On setting the cssText attribute must do nothing.
308354
}
309355

310-
fn rule(&self) -> std::cell::Ref<CssRule<'static>> {
356+
fn rule(&self) -> &CssRule<'static> {
311357
match &self.inner {
312-
RuleInner::Connected { stylesheet, index } => {
313-
let stylesheet = stylesheet.borrow();
314-
std::cell::Ref::map(stylesheet, |stylesheet| &stylesheet.stylesheet.rules.0[*index])
358+
RuleInner::Connected { rule_list, index } => {
359+
// std::cell::Ref::map(stylesheet, |stylesheet| &stylesheet.stylesheet.rules.0[*index])
360+
&rule_list.0[*index]
315361
}
316-
RuleInner::Disconnected(rule) => rule.borrow(),
362+
RuleInner::Disconnected(rule) => &rule,
317363
}
318364
}
319365

320-
fn rule_mut(&mut self) -> std::cell::RefMut<CssRule<'static>> {
321-
match &self.inner {
322-
RuleInner::Connected { stylesheet, index } => {
323-
let stylesheet = (**stylesheet).borrow_mut();
324-
std::cell::RefMut::map(stylesheet, |stylesheet| &mut stylesheet.stylesheet.rules.0[*index])
325-
}
326-
RuleInner::Disconnected(rule) => rule.borrow_mut(),
366+
fn rule_mut(&mut self) -> &mut CssRule<'static> {
367+
match &mut self.inner {
368+
RuleInner::Connected { rule_list, index } => &mut rule_list.0[*index],
369+
RuleInner::Disconnected(rule) => rule,
327370
}
328371
}
329372

@@ -396,20 +439,20 @@ impl CSSStyleRule {
396439
};
397440
}
398441

399-
fn rule(&self) -> std::cell::Ref<StyleRule<'static>> {
442+
fn rule(&self) -> &StyleRule<'static> {
400443
let rule = self.rule.rule();
401-
std::cell::Ref::map(rule, |rule| match rule {
444+
match rule {
402445
CssRule::Style(style) => style,
403446
_ => unreachable!(),
404-
})
447+
}
405448
}
406449

407-
fn rule_mut(&mut self) -> std::cell::RefMut<StyleRule<'static>> {
450+
fn rule_mut(&mut self) -> &mut StyleRule<'static> {
408451
let rule = self.rule.rule_mut();
409-
std::cell::RefMut::map(rule, |rule| match rule {
452+
match rule {
410453
CssRule::Style(style) => style,
411454
_ => unreachable!(),
412-
})
455+
}
413456
}
414457
}
415458

@@ -528,6 +571,52 @@ impl CSSStyleDeclaration {
528571
}
529572
}
530573

574+
#[napi(js_name = "CSSGroupingRule")]
575+
struct CSSGroupingRule {
576+
rule: CSSRule,
577+
rules: Option<Reference<CSSRuleList>>,
578+
}
579+
580+
#[napi]
581+
impl CSSGroupingRule {
582+
#[napi(constructor)]
583+
pub fn new() {
584+
unreachable!()
585+
}
586+
587+
#[napi(getter)]
588+
pub fn css_rules(&mut self, env: Env, reference: Reference<CSSGroupingRule>) -> Result<Reference<CSSRuleList>> {
589+
if let Some(rules) = &self.rules {
590+
return rules.clone(env);
591+
}
592+
593+
let rules = CSSRuleList {
594+
rule_list: RuleListReference::Rule(reference.share_with(env, |rule| match rule.rule.rule_mut() {
595+
CssRule::Media(media) => Ok(&mut media.rules),
596+
_ => unreachable!(),
597+
})?),
598+
rules: Vec::new(),
599+
stylesheet_reference: self.rule.parent_stylesheet.clone(env)?,
600+
};
601+
602+
self.rules = Some(CSSRuleList::into_reference(rules, env)?);
603+
self.rules.as_ref().unwrap().clone(env)
604+
}
605+
}
606+
607+
#[napi(js_name = "CSSMediaRule")]
608+
struct CSSMediaRule {
609+
rule: CSSGroupingRule,
610+
}
611+
612+
#[napi]
613+
impl CSSMediaRule {
614+
#[napi(constructor)]
615+
pub fn new() {
616+
unreachable!()
617+
}
618+
}
619+
531620
fn leak_str(string: String) -> &'static str {
532621
let res = unsafe {
533622
let slice = std::slice::from_raw_parts(string.as_ptr(), string.len());

0 commit comments

Comments
 (0)