Skip to content

Commit

Permalink
Merge pull request #595 from Sharktheone/css/or-selector
Browse files Browse the repository at this point in the history
fix "," in css selectors
  • Loading branch information
Sharktheone authored Sep 13, 2024
2 parents 05c20b2 + 7cb4a6e commit 84fff9d
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 48 deletions.
14 changes: 12 additions & 2 deletions crates/gosub_css3/src/convert/ast_converter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,9 @@ pub fn convert_ast_to_stylesheet(
continue;
}

let mut selector = CssSelector { parts: vec![] };
let mut selector = CssSelector {
parts: vec![vec![]],
};
for node in node.as_selector_list().iter() {
if !node.is_selector() {
continue;
Expand Down Expand Up @@ -134,11 +136,19 @@ pub fn convert_ast_to_stylesheet(
value: value.clone(),
case_insensitive: flags.eq_ignore_ascii_case("i"),
})),
NodeType::Comma => {
selector.parts.push(vec![]);
continue;
}
_ => {
return Err(anyhow!("Unsupported selector part: {:?}", node.node_type))
}
};
selector.parts.push(part);
if let Some(x) = selector.parts.last_mut() {
x.push(part)
} else {
selector.parts.push(vec![part]); //unreachable, but still, we handle it
}
}
}
rule.selectors.push(selector);
Expand Down
16 changes: 16 additions & 0 deletions crates/gosub_css3/src/parser/selector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -255,11 +255,22 @@ impl Css3<'_> {
let mut space = false;
let mut whitespace_location = loc.clone();

let mut skip_space = false;

while !self.tokenizer.eof() {
let t = self.consume_any()?;
if t.is_comment() {
continue;
}

if skip_space {
if t.is_whitespace() {
continue;
} else {
skip_space = false;
}
}

if t.is_whitespace() {
// on whitespace for selector
whitespace_location = t.location.clone();
Expand Down Expand Up @@ -324,6 +335,11 @@ impl Css3<'_> {
self.tokenizer.reconsume();
self.parse_nesting_selector()?
}
TokenType::Comma => {
skip_space = true;

Node::new(NodeType::Comma, t.location)
}
_ => {
self.tokenizer.reconsume();
break;
Expand Down
84 changes: 51 additions & 33 deletions crates/gosub_css3/src/stylesheet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,30 +61,16 @@ pub struct CssDeclaration {
#[derive(Debug, PartialEq, Clone)]
pub struct CssSelector {
// List of parts that make up this selector
pub parts: Vec<CssSelectorPart>,
pub parts: Vec<Vec<CssSelectorPart>>,
}

impl CssSelector {
/// Generate specificity for this selector
pub fn specificity(&self) -> Specificity {
let mut id_count = 0;
let mut class_count = 0;
let mut element_count = 0;
for part in &self.parts {
match part {
CssSelectorPart::Id(_) => {
id_count += 1;
}
CssSelectorPart::Class(_) => {
class_count += 1;
}
CssSelectorPart::Type(_) => {
element_count += 1;
}
_ => {}
}
}
Specificity::new(id_count, class_count, element_count)
pub fn specificity(&self) -> Vec<Specificity> {
self.parts
.iter()
.map(|part| Specificity::from(part.as_slice()))
.collect()
}
}

Expand Down Expand Up @@ -219,6 +205,29 @@ impl Specificity {
}
}

impl From<&[CssSelectorPart]> for Specificity {
fn from(parts: &[CssSelectorPart]) -> Self {
let mut id_count = 0;
let mut class_count = 0;
let mut element_count = 0;
for part in parts {
match part {
CssSelectorPart::Id(_) => {
id_count += 1;
}
CssSelectorPart::Class(_) => {
class_count += 1;
}
CssSelectorPart::Type(_) => {
element_count += 1;
}
_ => {}
}
}
Specificity::new(id_count, class_count, element_count)
}
}

impl PartialOrd for Specificity {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
Expand Down Expand Up @@ -429,6 +438,7 @@ impl CssValue {
#[cfg(test)]
mod test {
use super::*;
use std::vec;

// #[test]
// fn test_css_value_to_color() {
Expand All @@ -448,7 +458,7 @@ mod test {
fn test_css_rule() {
let rule = CssRule {
selectors: vec![CssSelector {
parts: vec![CssSelectorPart::Type("h1".to_string())],
parts: vec![vec![CssSelectorPart::Type("h1".to_string())]],
}],
declarations: vec![CssDeclaration {
property: "color".to_string(),
Expand All @@ -458,7 +468,15 @@ mod test {
};

assert_eq!(rule.selectors().len(), 1);
let part = rule.selectors().first().unwrap().parts.first().unwrap();
let part = rule
.selectors()
.first()
.unwrap()
.parts
.first()
.unwrap()
.first()
.unwrap();

assert_eq!(part, &CssSelectorPart::Type("h1".to_string()));
assert_eq!(rule.declarations().len(), 1);
Expand All @@ -468,42 +486,42 @@ mod test {
#[test]
fn test_specificity() {
let selector = CssSelector {
parts: vec![
parts: vec![vec![
CssSelectorPart::Type("h1".to_string()),
CssSelectorPart::Class("myclass".to_string()),
CssSelectorPart::Id("myid".to_string()),
],
]],
};

let specificity = selector.specificity();
assert_eq!(specificity, Specificity::new(1, 1, 1));
assert_eq!(specificity, vec![Specificity::new(1, 1, 1)]);

let selector = CssSelector {
parts: vec![
parts: vec![vec![
CssSelectorPart::Type("h1".to_string()),
CssSelectorPart::Class("myclass".to_string()),
],
]],
};

let specificity = selector.specificity();
assert_eq!(specificity, Specificity::new(0, 1, 1));
assert_eq!(specificity, vec![Specificity::new(0, 1, 1)]);

let selector = CssSelector {
parts: vec![CssSelectorPart::Type("h1".to_string())],
parts: vec![vec![CssSelectorPart::Type("h1".to_string())]],
};

let specificity = selector.specificity();
assert_eq!(specificity, Specificity::new(0, 0, 1));
assert_eq!(specificity, vec![Specificity::new(0, 0, 1)]);

let selector = CssSelector {
parts: vec![
parts: vec![vec![
CssSelectorPart::Class("myclass".to_string()),
CssSelectorPart::Class("otherclass".to_string()),
],
]],
};

let specificity = selector.specificity();
assert_eq!(specificity, Specificity::new(0, 2, 0));
assert_eq!(specificity, vec![Specificity::new(0, 2, 0)]);
}

#[test]
Expand Down
30 changes: 19 additions & 11 deletions crates/gosub_styling/src/render_tree.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
use std::collections::HashMap;
use std::fmt::{Debug, Formatter};

use crate::property_definitions::get_css_definitions;
use crate::shorthands::FixList;
use crate::styling::{
match_selector, prop_is_inherit, CssProperties, CssProperty, DeclarationProperty,
};
use log::warn;

use gosub_css3::stylesheet::{CssDeclaration, CssOrigin, CssSelector, CssStylesheet, CssValue};
use gosub_css3::stylesheet::{CssDeclaration, CssOrigin, CssStylesheet, CssValue, Specificity};
use gosub_html5::node::data::element::ElementData;
use gosub_html5::node::{NodeData, NodeId};
use gosub_html5::parser::document::{DocumentHandle, TreeIterator};
use gosub_render_backend::geo::Size;
use gosub_render_backend::layout::{HasTextLayout, Layout, LayoutTree, Layouter, Node, TextLayout};
use gosub_shared::types::Result;

use crate::property_definitions::get_css_definitions;
use crate::shorthands::FixList;
use crate::styling::{
match_selector, prop_is_inherit, CssProperties, CssProperty, DeclarationProperty,
};

mod desc;

const INLINE_ELEMENTS: [&str; 31] = [
Expand Down Expand Up @@ -291,11 +292,13 @@ impl<L: Layouter> RenderTree<L> {

for rule in sheet.rules.iter() {
for selector in rule.selectors().iter() {
if !match_selector(
let (matched, specificity) = match_selector(
DocumentHandle::clone(&document),
current_node_id,
selector,
) {
);

if !matched {
continue;
}

Expand Down Expand Up @@ -328,7 +331,12 @@ impl<L: Layouter> RenderTree<L> {
important: declaration.important,
};

add_property_to_map(&mut css_map_entry, sheet, selector, &decl);
add_property_to_map(
&mut css_map_entry,
sheet,
specificity.clone(),
&decl,
);
}
}
}
Expand Down Expand Up @@ -557,7 +565,7 @@ impl<L: Layouter> RenderTree<L> {
pub fn add_property_to_map(
css_map_entry: &mut CssProperties,
sheet: &CssStylesheet,
selector: &CssSelector,
specificity: Specificity,
declaration: &CssDeclaration,
) {
let property_name = declaration.property.clone();
Expand All @@ -583,7 +591,7 @@ pub fn add_property_to_map(
origin: sheet.origin.clone(),
important: declaration.important,
location: sheet.location.clone(),
specificity: selector.specificity(),
specificity,
};

if let std::collections::hash_map::Entry::Vacant(e) =
Expand Down
10 changes: 8 additions & 2 deletions crates/gosub_styling/src/styling.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,14 @@ pub(crate) fn match_selector(
document: DocumentHandle,
node_id: NodeId,
selector: &CssSelector,
) -> bool {
match_selector_parts(document, node_id, &selector.parts)
) -> (bool, Specificity) {
for part in &selector.parts {
if match_selector_parts(DocumentHandle::clone(&document), node_id, part) {
return (true, Specificity::from(part.as_slice()));
}
}

(false, Specificity::new(0, 0, 0))
}

fn consume<'a, T>(this: &mut &'a [T]) -> Option<&'a T> {
Expand Down

0 comments on commit 84fff9d

Please sign in to comment.