Skip to content

Commit

Permalink
fix specificity of shorthand props
Browse files Browse the repository at this point in the history
  • Loading branch information
Sharktheone committed Dec 5, 2024
1 parent c845980 commit e92f2a3
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 39 deletions.
103 changes: 71 additions & 32 deletions crates/gosub_css3/src/matcher/shorthands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,18 @@ pub struct Shorthands {

#[derive(Debug, Clone, PartialEq)]
pub struct FixList {
list: Vec<(String, Vec<CssValue>)>,
list: Vec<(String, Vec<DeclarationProperty>)>,
multipliers: Vec<(String, usize)>,

current_info: Option<FixListInfo>,
}

#[derive(Debug, Clone, PartialEq)]
pub struct FixListInfo {
origin: CssOrigin,
important: bool,
location: String,
specificity: Specificity,
}

#[derive(Debug, Clone)]
Expand Down Expand Up @@ -192,6 +202,7 @@ pub struct Snapshot {
}

impl<'a> ShorthandResolver<'a> {
#[allow(clippy::result_large_err)]
pub fn step(&'a mut self, idx: usize) -> Result<Option<Self>, CompleteStep<'a>> {
let snapshot = Some(self.snapshot());

Expand Down Expand Up @@ -318,26 +329,54 @@ impl FixList {
Self {
list: Vec::new(),
multipliers: Vec::new(),
current_info: None,
}
}

pub fn insert(&mut self, name: String, value: Vec<CssValue>) {
pub fn set_info(&mut self, info: FixListInfo) {
self.current_info = Some(info);
}

fn get_declaration(&self, value: CssValue) -> DeclarationProperty {
if let Some(info) = &self.current_info {
DeclarationProperty {
value,
origin: info.origin,
important: info.important,
specificity: info.specificity,
location: info.location.clone(),
}
} else {
DeclarationProperty {
value,
origin: CssOrigin::Author,
important: false,
specificity: Specificity::new(0, 0, 0),
location: String::new(),
}
}
}

pub fn insert(&mut self, name: String, value: CssValue) {
let value = self.get_declaration(value);

for (k, v) in &mut self.list {
if *k == name {
*v = value;
v.clear(); //TODO: This is a hack, we should not have to clear the vec
v.push(value);
return;
}
}

self.list.push((name, value));
self.list.push((name, vec![value]));
}

pub fn resolve_nested(&mut self, definitions: &CssDefinitions) {
let mut fix_list = FixList::new();

let mut had_shorthands = false;

for (name, value) in &self.list {
for (name, decl) in &self.list {
let Some(prop) = definitions.find_property(name) else {
continue;
};
Expand All @@ -346,9 +385,11 @@ impl FixList {
continue;
}

let Some(decl) = decl.iter().max() else { continue };

had_shorthands = true;

prop.matches_and_shorthands(value, &mut fix_list);
prop.matches_and_shorthands(decl.value.to_slice(), &mut fix_list);
}

if had_shorthands {
Expand All @@ -364,18 +405,10 @@ impl FixList {

pub fn apply(&mut self, props: &mut CssProperties) {
for (name, value) in &self.list {
let Some(value) = value.first().cloned() else {
let Some(decl) = value.iter().max().cloned() else {
continue;
};

let decl = DeclarationProperty {
value,
origin: CssOrigin::Author,
important: false,
location: "".to_string(),
specificity: Specificity::new(0, 1, 0),
};

match props.properties.entry(name.clone()) {
Entry::Occupied(mut entry) => {
let prop = entry.get_mut();
Expand All @@ -396,8 +429,10 @@ impl FixList {

impl CompleteStep<'_> {
pub fn complete(mut self, value: Vec<CssValue>) {
let val = CssValue::from_vec(value);

for name in self.name.clone() {
self.list.insert(name.to_string(), value.clone());
self.list.insert(name.to_string(), val.clone())
}

self.completed = true;
Expand Down Expand Up @@ -619,12 +654,13 @@ mod tests {
fix_list,
FixList {
list: vec![
("margin-bottom".to_string(), vec![unit!(1.0, "px")]),
("margin-left".to_string(), vec![unit!(1.0, "px")]),
("margin-right".to_string(), vec![unit!(1.0, "px")]),
("margin-top".to_string(), vec![unit!(1.0, "px")]),
("margin-bottom".to_string(), vec![unit!(1.0, "px").into()]),
("margin-left".to_string(), vec![unit!(1.0, "px").into()]),
("margin-right".to_string(), vec![unit!(1.0, "px").into()]),
("margin-top".to_string(), vec![unit!(1.0, "px").into()]),
],
multipliers: vec![("margin".to_string(), 1),],
current_info: None
}
);

Expand All @@ -638,12 +674,13 @@ mod tests {
fix_list,
FixList {
list: vec![
("margin-bottom".to_string(), vec![unit!(1.0, "px")]),
("margin-left".to_string(), vec![unit!(2.0, "px")]),
("margin-right".to_string(), vec![unit!(2.0, "px")]),
("margin-top".to_string(), vec![unit!(1.0, "px")]),
("margin-bottom".to_string(), vec![unit!(1.0, "px").into()]),
("margin-left".to_string(), vec![unit!(2.0, "px").into()]),
("margin-right".to_string(), vec![unit!(2.0, "px").into()]),
("margin-top".to_string(), vec![unit!(1.0, "px").into()]),
],
multipliers: vec![("margin".to_string(), 2),],
current_info: None
}
);

Expand All @@ -656,12 +693,13 @@ mod tests {
fix_list,
FixList {
list: vec![
("margin-bottom".to_string(), vec![unit!(3.0, "px")]),
("margin-left".to_string(), vec![unit!(2.0, "px")]),
("margin-right".to_string(), vec![unit!(2.0, "px")]),
("margin-top".to_string(), vec![unit!(1.0, "px")]),
("margin-bottom".to_string(), vec![unit!(3.0, "px").into()]),
("margin-left".to_string(), vec![unit!(2.0, "px").into()]),
("margin-right".to_string(), vec![unit!(2.0, "px").into()]),
("margin-top".to_string(), vec![unit!(1.0, "px").into()]),
],
multipliers: vec![("margin".to_string(), 3),],
current_info: None
}
);

Expand All @@ -675,12 +713,13 @@ mod tests {
fix_list,
FixList {
list: vec![
("margin-bottom".to_string(), vec![unit!(3.0, "px")]),
("margin-left".to_string(), vec![unit!(4.0, "px")]),
("margin-right".to_string(), vec![unit!(2.0, "px")]),
("margin-top".to_string(), vec![unit!(1.0, "px")]),
("margin-bottom".to_string(), vec![unit!(3.0, "px").into()]),
("margin-left".to_string(), vec![unit!(4.0, "px").into()]),
("margin-right".to_string(), vec![unit!(2.0, "px").into()]),
("margin-top".to_string(), vec![unit!(1.0, "px").into()]),
],
multipliers: vec![("margin".to_string(), 4),],
current_info: None
}
);

Expand Down
21 changes: 16 additions & 5 deletions crates/gosub_css3/src/matcher/styling.rs
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,9 @@ impl Eq for DeclarationProperty {}

impl Ord for DeclarationProperty {
fn cmp(&self, other: &Self) -> Ordering {
self.priority().cmp(&other.priority())
self.priority()
.cmp(&other.priority())
.then_with(|| self.specificity.cmp(&other.specificity))
}
}

Expand Down Expand Up @@ -446,10 +448,7 @@ impl CssProperty {
}

fn find_cascaded_value(&self) -> Option<CssValue> {
self.declared
.iter()
.max_by(|a, b| a.cmp(b).then_with(|| a.specificity.cmp(&b.specificity)))
.map(|v| v.value.clone())
self.declared.iter().max().map(|v| v.value.clone())
}

fn find_specified_value(&self) -> CssValue {
Expand Down Expand Up @@ -528,6 +527,18 @@ impl From<CssValue> for CssProperty {
}
}

impl From<CssValue> for DeclarationProperty {
fn from(value: CssValue) -> Self {
Self {
location: "".into(),
important: false,
value,
origin: CssOrigin::Author,
specificity: Specificity::new(0, 0, 0),
}
}
}

impl Display for CssProperty {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Display::fmt(&self.actual, f)
Expand Down
25 changes: 24 additions & 1 deletion crates/gosub_css3/src/stylesheet.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use core::fmt::Debug;
use core::slice;
use gosub_shared::byte_stream::Location;
use gosub_shared::errors::CssError;
use gosub_shared::errors::CssResult;
Expand Down Expand Up @@ -286,7 +287,7 @@ impl Display for MatcherType {
}

/// Defines the specificity for a selector
#[derive(Debug, PartialEq, Eq, Clone)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct Specificity(u32, u32, u32);

impl Specificity {
Expand Down Expand Up @@ -438,6 +439,28 @@ impl CssValue {
}
}

pub fn from_vec(mut value: Vec<Self>) -> Self {
match value.len() {
0 => Self::None,
1 => value.swap_remove(0),
_ => Self::List(value),
}
}

pub fn to_slice(&self) -> &[Self] {
match self {
Self::List(l) => l,
this => slice::from_ref(this),
}
}

pub fn into_vec(self) -> Vec<Self> {
match self {
Self::List(l) => l,
this => vec![this],
}
}

/// Converts a CSS AST node to a CSS value
pub fn parse_ast_node(node: &crate::node::Node) -> CssResult<CssValue> {
match *node.node_type.clone() {
Expand Down
2 changes: 1 addition & 1 deletion crates/gosub_css3/src/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ impl CssSystem for Css3System {
important: declaration.important,
};

add_property_to_map(&mut css_map_entry, sheet, specificity.clone(), &decl);
add_property_to_map(&mut css_map_entry, sheet, specificity, &decl);
}
}
}
Expand Down

0 comments on commit e92f2a3

Please sign in to comment.