Skip to content

Commit 436073e

Browse files
committed
Implement keyframe style property
1 parent c4c4a80 commit 436073e

File tree

2 files changed

+107
-19
lines changed

2 files changed

+107
-19
lines changed

node/src/stylesheet.rs

Lines changed: 81 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,10 @@ fn css_rule_to_js_unknown(rule: &CssRule<'static>, env: Env, css_rule: CSSRule)
252252
}
253253

254254
fn keyframe_to_js_unknown(env: Env, css_rule: CSSRule) -> Result<JsUnknown> {
255-
let rule = CSSKeyframeRule { rule: css_rule };
255+
let rule = CSSKeyframeRule {
256+
rule: css_rule,
257+
style: None,
258+
};
256259
let napi_value = unsafe { napi::bindgen_prelude::ToNapiValue::to_napi_value(env.raw(), rule)? };
257260
unsafe { napi::JsUnknown::from_napi_value(env.raw(), napi_value) }
258261
}
@@ -552,19 +555,31 @@ impl CSSStyleRule {
552555
return rules.clone(env);
553556
}
554557

555-
let style = CSSStyleDeclaration::into_reference(CSSStyleDeclaration { rule: reference }, env)?;
558+
let declarations = reference
559+
.clone(env)?
560+
.share_with(env, |reference| Ok(&mut reference.rule_mut().declarations))?;
561+
let declarations = unsafe {
562+
std::mem::transmute::<
563+
SharedReference<CSSStyleRule, &mut DeclarationBlock<'static>>,
564+
SharedReference<CSSRule, &mut DeclarationBlock<'static>>,
565+
>(declarations)
566+
};
567+
let parent_rule = unsafe { std::mem::transmute::<Reference<CSSStyleRule>, Reference<CSSRule>>(reference) };
568+
let style = CSSStyleDeclaration::into_reference(
569+
CSSStyleDeclaration {
570+
parent_rule,
571+
declarations,
572+
},
573+
env,
574+
)?;
556575
self.style = Some(style.clone(env)?);
557576
Ok(style)
558577
}
559578

560579
#[napi(setter)]
561580
pub fn set_style(&mut self, text: String) {
562-
match &mut *self.rule.rule_mut() {
563-
CssRule::Style(style) => {
564-
style.declarations = DeclarationBlock::parse_string(leak_str(text), ParserOptions::default()).unwrap();
565-
}
566-
_ => unreachable!(),
567-
};
581+
self.rule_mut().declarations =
582+
DeclarationBlock::parse_string(leak_str(text), ParserOptions::default()).unwrap();
568583
}
569584

570585
fn rule(&self) -> &StyleRule<'static> {
@@ -586,7 +601,8 @@ impl CSSStyleRule {
586601

587602
#[napi(js_name = "CSSStyleDeclaration")]
588603
struct CSSStyleDeclaration {
589-
rule: Reference<CSSStyleRule>,
604+
parent_rule: Reference<CSSRule>,
605+
declarations: SharedReference<CSSRule, &'static mut DeclarationBlock<'static>>,
590606
}
591607

592608
#[napi]
@@ -597,24 +613,23 @@ impl CSSStyleDeclaration {
597613
}
598614

599615
#[napi(getter)]
600-
pub fn parent_rule(&self, env: Env) -> Result<Reference<CSSStyleRule>> {
601-
self.rule.clone(env)
616+
pub fn parent_rule(&self, env: Env) -> Result<Reference<CSSRule>> {
617+
self.parent_rule.clone(env)
602618
}
603619

604620
#[napi(getter)]
605621
pub fn css_text(&self) -> String {
606-
self.rule.rule().declarations.to_css_string(PrinterOptions::default()).unwrap()
622+
self.declarations.to_css_string(PrinterOptions::default()).unwrap()
607623
}
608624

609625
#[napi(setter)]
610626
pub fn set_css_text(&mut self, text: String) {
611-
self.rule.set_style(text)
627+
**self.declarations = DeclarationBlock::parse_string(leak_str(text), ParserOptions::default()).unwrap();
612628
}
613629

614630
fn get_longhands(&self) -> Vec<String> {
615-
let rule = self.rule.rule();
616631
let mut longhands = Vec::new();
617-
for (property, _important) in rule.declarations.iter() {
632+
for (property, _important) in self.declarations.iter() {
618633
let property_id = property.property_id();
619634
if let Some(properties) = property_id.longhands() {
620635
longhands.extend(properties.iter().map(|property_id| property_id.name().to_owned()))
@@ -646,7 +661,7 @@ impl CSSStyleDeclaration {
646661
let property_id = PropertyId::parse_string(&property).unwrap();
647662
let opts = PrinterOptions::default();
648663

649-
if let Some((value, _important)) = self.rule.rule().declarations.get(&property_id) {
664+
if let Some((value, _important)) = self.declarations.get(&property_id) {
650665
return value.value_to_css_string(opts).unwrap();
651666
}
652667

@@ -656,7 +671,7 @@ impl CSSStyleDeclaration {
656671
#[napi]
657672
pub fn get_property_priority(&mut self, property: String) -> &str {
658673
let property_id = PropertyId::parse_string(&property).unwrap();
659-
let important = if let Some((_value, important)) = self.rule.rule().declarations.get(&property_id) {
674+
let important = if let Some((_value, important)) = self.declarations.get(&property_id) {
660675
important
661676
} else {
662677
false
@@ -678,7 +693,7 @@ impl CSSStyleDeclaration {
678693

679694
let property =
680695
Property::parse_string(leak_str(property).into(), leak_str(value), ParserOptions::default()).unwrap();
681-
self.rule.rule_mut().declarations.set(
696+
self.declarations.set(
682697
property,
683698
if let Some(priority) = priority {
684699
priority.eq_ignore_ascii_case("important")
@@ -693,7 +708,7 @@ impl CSSStyleDeclaration {
693708
let value = self.get_property_value(property.clone());
694709

695710
let property_id = PropertyId::parse_string(&property).unwrap();
696-
self.rule.rule_mut().declarations.remove(&property_id);
711+
self.declarations.remove(&property_id);
697712

698713
value
699714
}
@@ -1118,6 +1133,7 @@ impl CSSKeyframesRule {
11181133
#[napi(js_name = "CSSKeyframeRule")]
11191134
struct CSSKeyframeRule {
11201135
rule: CSSRule,
1136+
style: Option<Reference<CSSStyleDeclaration>>,
11211137
}
11221138

11231139
#[napi]
@@ -1150,6 +1166,52 @@ impl CSSKeyframeRule {
11501166
// Spec says to throw a SyntaxError, but no browser does?
11511167
}
11521168
}
1169+
1170+
#[napi(getter)]
1171+
pub fn style(
1172+
&mut self,
1173+
env: Env,
1174+
reference: Reference<CSSKeyframeRule>,
1175+
) -> Result<Reference<CSSStyleDeclaration>> {
1176+
if let Some(rules) = &self.style {
1177+
return rules.clone(env);
1178+
}
1179+
1180+
let declarations =
1181+
reference
1182+
.clone(env)?
1183+
.share_with(env, |reference| match reference.rule.inner.rule_mut() {
1184+
RuleOrKeyframeRefMut::Keyframe(keyframe) => Ok(&mut keyframe.declarations),
1185+
_ => unreachable!(),
1186+
})?;
1187+
let declarations = unsafe {
1188+
std::mem::transmute::<
1189+
SharedReference<CSSKeyframeRule, &mut DeclarationBlock<'static>>,
1190+
SharedReference<CSSRule, &mut DeclarationBlock<'static>>,
1191+
>(declarations)
1192+
};
1193+
let parent_rule = unsafe { std::mem::transmute::<Reference<CSSKeyframeRule>, Reference<CSSRule>>(reference) };
1194+
1195+
let style = CSSStyleDeclaration::into_reference(
1196+
CSSStyleDeclaration {
1197+
parent_rule,
1198+
declarations,
1199+
},
1200+
env,
1201+
)?;
1202+
self.style = Some(style.clone(env)?);
1203+
Ok(style)
1204+
}
1205+
1206+
#[napi(setter)]
1207+
pub fn set_style(&mut self, text: String) {
1208+
match self.rule.inner.rule_mut() {
1209+
RuleOrKeyframeRefMut::Keyframe(keyframe) => {
1210+
keyframe.declarations = DeclarationBlock::parse_string(leak_str(text), ParserOptions::default()).unwrap();
1211+
}
1212+
_ => unreachable!(),
1213+
};
1214+
}
11531215
}
11541216

11551217
fn leak_str(string: String) -> &'static str {

node/test/cssom.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,12 @@ run('CSSStyleDeclaration', test => {
269269
assert.equal(declaration().cssText, 'border: 1px solid #000; color: green !important');
270270
});
271271

272+
test('set cssText', () => {
273+
let decl = declaration();
274+
decl.cssText = 'color: purple';
275+
assert.equal(decl.cssText, 'color: purple');
276+
});
277+
272278
test('parentRule', () => {
273279
let rule = styleRule();
274280
assert.equal(rule.style.parentRule, rule);
@@ -700,6 +706,26 @@ run('CSSKeyframeRule', test => {
700706
assert.equal(rule.keyText, '23%');
701707
assert.equal(rule.cssText, `23% {
702708
opacity: 0;
709+
}`);
710+
});
711+
712+
test('style', () => {
713+
let rule = keyframeRule();
714+
assert(rule.style instanceof CSSStyleDeclaration);
715+
assert.equal(rule.style.getPropertyValue('opacity'), '0');
716+
assert.equal(rule.style.cssText, 'opacity: 0');
717+
718+
rule.style.setProperty('opacity', '0.5');
719+
assert.equal(rule.cssText, `from {
720+
opacity: .5;
721+
}`);
722+
});
723+
724+
test('set style', () => {
725+
let rule = keyframeRule();
726+
rule.style = 'opacity: 0.5';
727+
assert.equal(rule.cssText, `from {
728+
opacity: .5;
703729
}`);
704730
});
705731
});

0 commit comments

Comments
 (0)