avm2: Transform css properties from with-dashes to snakeCase

This commit is contained in:
Nathan Adams 2024-05-13 01:49:00 +02:00
parent 24b01b8f89
commit 7309e457d5
8 changed files with 75 additions and 4 deletions

View File

@ -1,6 +1,6 @@
use crate::avm2::parameters::ParametersExt;
use crate::avm2::{Activation, Error, Object, TObject, Value};
use crate::html::CssStream;
use crate::html::{transform_dashes_to_camel_case, CssStream};
use crate::string::AvmString;
use ruffle_wstr::{WStr, WString};
@ -25,7 +25,7 @@ pub fn inner_parse_css<'gc>(
.construct(activation, &[])?;
for (key, value) in properties.into_iter() {
object.set_public_property(
AvmString::new(activation.gc(), key),
AvmString::new(activation.gc(), transform_dashes_to_camel_case(key)),
Value::String(AvmString::new(activation.gc(), value)),
activation,
)?;

View File

@ -8,7 +8,7 @@ mod text_format;
pub use dimensions::BoxBounds;
pub use dimensions::Position;
pub use layout::{LayoutBox, LayoutContent, LayoutMetrics};
pub use stylesheet::CssStream;
pub use stylesheet::{transform_dashes_to_camel_case, CssStream};
pub use text_format::{FormatSpans, TextDisplay, TextFormat, TextSpan};
mod stylesheet;

View File

@ -1,5 +1,6 @@
use fnv::FnvHashMap;
use ruffle_wstr::WStr;
use ruffle_wstr::{WStr, WString};
use std::borrow::Cow;
pub type CssProperties<'a> = FnvHashMap<&'a WStr, &'a WStr>;
@ -209,6 +210,29 @@ impl<'a> CssStream<'a> {
}
}
pub fn transform_dashes_to_camel_case(input: &WStr) -> Cow<WStr> {
if !input.contains(b'-') {
return Cow::Borrowed(input);
}
let mut result = WString::with_capacity(input.len(), input.is_wide());
let mut make_upper = false;
let mut pos = 0;
while let Some(char) = input.get(pos) {
match char {
0x002D if !make_upper => make_upper = true, // - as u16, can't use `as` in arm
_ if make_upper => {
make_upper = false;
result.push_str(&input[pos..=pos].to_ascii_uppercase())
}
_ => result.push(char),
}
pos += 1;
}
Cow::Owned(result)
}
// More exhaustive tests live inside avm2 stylesheet swf test
// These are just some useful ones extracted out
#[cfg(test)]

View File

@ -186,6 +186,16 @@
"}");
});
test("parseCSS: name transformation", styleSheet, function() {
styleSheet.clear();
styleSheet.parseCSS("key {" +
"name-with-dashes: value" +
" name-with-dashes-and-spaces : value;" +
"this--one--has--two--dashes: value;" +
"UPPER-DASHES: value;" +
"}");
});
styleSheet = new AlwaysRedStyleSheet();
test("transform", styleSheet, function() {
styleSheet.setStyle("anything", "blue");

View File

@ -189,6 +189,14 @@ styleSheet.getStyle("key") = {
}
styleSheet.getStyle("nonexistant") = {}
/// parseCSS: name transformation
styleSheet.getStyle("key") = {
"UPPERDASHES" = string "value"
"nameWithDashes" = string "value name-with-dashes-and-spaces : value"
"this-one-has-two-dashes" = string "value"
}
styleSheet.getStyle("nonexistant") = {}
/// transform
styleSheet.getStyle("anything") = {}
styleSheet.getStyle("nonexistant") = {}

Binary file not shown.

View File

@ -346,6 +346,18 @@ impl WStr {
super::ops::str_make_ascii_lowercase(self)
}
/// Returns a new string with all ASCII characters mapped to their uppercase equivalent.
#[inline]
pub fn to_ascii_uppercase(&self) -> WString {
super::ops::str_to_ascii_uppercase(self)
}
/// Converts this string to its ASCII uppercase equivalent in-place.
#[inline]
pub fn make_ascii_uppercase(&mut self) {
super::ops::str_make_ascii_uppercase(self)
}
/// Analogue of [`str::replace`].
#[inline]
pub fn replace<'a, P: Pattern<'a>>(&'a self, pattern: P, with: &WStr) -> WString {

View File

@ -215,6 +215,23 @@ pub fn str_make_ascii_lowercase(s: &mut WStr) {
}
}
pub fn str_to_ascii_uppercase(s: &WStr) -> WString {
map_latin1_chars(s, |c| c.to_ascii_uppercase())
}
pub fn str_make_ascii_uppercase(s: &mut WStr) {
match s.units_mut() {
Units::Bytes(us) => us.make_ascii_uppercase(),
Units::Wide(us) => {
for c in us {
if let Ok(b) = u8::try_from(*c) {
*c = b.to_ascii_uppercase().into();
}
}
}
}
}
pub fn str_is_latin1(s: &WStr) -> bool {
match s.units() {
Units::Bytes(_) => true,