styling: added preliminary styling application
This commit is contained in:
33
src/css.rs
33
src/css.rs
@@ -1,9 +1,9 @@
|
||||
use std;
|
||||
|
||||
struct SimpleSelector {
|
||||
tag_name: Option<String>,
|
||||
id: Option<String>,
|
||||
class: Vec<String>,
|
||||
pub struct SimpleSelector {
|
||||
pub tag_name: Option<String>,
|
||||
pub id: Option<String>,
|
||||
pub class: Vec<String>,
|
||||
}
|
||||
|
||||
struct ChainSelector {
|
||||
@@ -12,7 +12,7 @@ struct ChainSelector {
|
||||
class: Vec<Vec<String>>,
|
||||
}
|
||||
|
||||
enum Selector {
|
||||
pub enum Selector {
|
||||
Simple(SimpleSelector),
|
||||
//Chain(ChainSelector),
|
||||
}
|
||||
@@ -43,7 +43,8 @@ impl std::fmt::Display for Selector {
|
||||
}
|
||||
}
|
||||
|
||||
enum Unit {
|
||||
#[derive(Clone)]
|
||||
pub enum Unit {
|
||||
Px,
|
||||
Em,
|
||||
Rm,
|
||||
@@ -65,14 +66,16 @@ impl std::fmt::Display for Unit {
|
||||
}
|
||||
}
|
||||
|
||||
struct Color {
|
||||
#[derive(Clone)]
|
||||
pub struct Color {
|
||||
r: u8,
|
||||
g: u8,
|
||||
b: u8,
|
||||
a: u8,
|
||||
}
|
||||
|
||||
enum Value {
|
||||
#[derive(Clone)]
|
||||
pub enum Value {
|
||||
Keyword(String),
|
||||
Length(f32, Unit),
|
||||
ColorValue(Color),
|
||||
@@ -88,9 +91,9 @@ impl std::fmt::Display for Value {
|
||||
}
|
||||
}
|
||||
|
||||
struct Declaration {
|
||||
name: String,
|
||||
value: Value,
|
||||
pub struct Declaration {
|
||||
pub name: String,
|
||||
pub value: Value,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Declaration {
|
||||
@@ -99,9 +102,9 @@ impl std::fmt::Display for Declaration {
|
||||
}
|
||||
}
|
||||
|
||||
struct Rule {
|
||||
selectors: Vec<Selector>,
|
||||
declarations: Vec<Declaration>,
|
||||
pub struct Rule {
|
||||
pub selectors: Vec<Selector>,
|
||||
pub declarations: Vec<Declaration>,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Rule {
|
||||
@@ -124,7 +127,7 @@ impl std::fmt::Display for Rule {
|
||||
}
|
||||
|
||||
pub struct Stylesheet {
|
||||
rules: Vec<Rule>,
|
||||
pub rules: Vec<Rule>,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Stylesheet {
|
||||
|
29
src/dom.rs
29
src/dom.rs
@@ -1,4 +1,4 @@
|
||||
use std::collections::HashMap;
|
||||
use std::collections::{HashMap,HashSet};
|
||||
use std;
|
||||
|
||||
use css;
|
||||
@@ -7,17 +7,30 @@ pub struct Attr {
|
||||
attrs: HashMap<String, String>,
|
||||
}
|
||||
|
||||
struct EData {
|
||||
name: String,
|
||||
attr: Attr,
|
||||
pub struct EData {
|
||||
pub name: String,
|
||||
pub attr: Attr,
|
||||
}
|
||||
|
||||
struct SData {
|
||||
impl EData {
|
||||
pub fn id(&self) -> Option<&String> {
|
||||
self.attr.attrs.get("id")
|
||||
}
|
||||
|
||||
pub fn classes(&self) -> HashSet<&str> {
|
||||
match self.attr.attrs.get("class") {
|
||||
Some(classlist) => classlist.split(' ').collect(),
|
||||
None => HashSet::new()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SData {
|
||||
attr: Attr,
|
||||
content: css::Stylesheet,
|
||||
}
|
||||
|
||||
enum NType {
|
||||
pub enum NType {
|
||||
Text(String),
|
||||
Comment(String),
|
||||
Element(EData),
|
||||
@@ -25,8 +38,8 @@ enum NType {
|
||||
}
|
||||
|
||||
pub struct Node {
|
||||
children: Vec<Node>,
|
||||
ntype: NType,
|
||||
pub children: Vec<Node>,
|
||||
pub ntype: NType,
|
||||
}
|
||||
|
||||
pub fn text(d: String) -> Node {
|
||||
|
@@ -6,6 +6,7 @@ use std::fs::File;
|
||||
pub mod css;
|
||||
pub mod dom;
|
||||
pub mod html;
|
||||
pub mod styling;
|
||||
|
||||
fn read_source(filename: String) -> String {
|
||||
let mut str = String::new();
|
||||
|
73
src/styling.rs
Normal file
73
src/styling.rs
Normal file
@@ -0,0 +1,73 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use css;
|
||||
use dom;
|
||||
|
||||
type Properties = HashMap<String, css::Value>;
|
||||
|
||||
pub struct Node<'a> {
|
||||
node: & 'a dom::Node,
|
||||
values: Properties,
|
||||
children: Vec<Node<'a>>,
|
||||
}
|
||||
|
||||
fn matches(elem: &dom::EData, selector: &css::Selector) -> bool {
|
||||
match *selector {
|
||||
css::Selector::Simple(ref s) => matches_simple(elem, s)
|
||||
}
|
||||
}
|
||||
|
||||
fn matches_simple(elem: &dom::EData, selector: &css::SimpleSelector) -> bool {
|
||||
if selector.tag_name.iter().any(|name| elem.name != *name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if selector.id.iter().any(|id| elem.id() != Some(id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let elem_classes = elem.classes();
|
||||
if selector.class.iter().any(|class| !elem_classes.contains(&**class)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
type Rule<'a> = (css::Specificity, &'a css::Rule);
|
||||
|
||||
fn match_rule<'a>(elem: &dom::EData, rule: &'a css::Rule) -> Option<Rule<'a>> {
|
||||
rule.selectors.iter()
|
||||
.find(|selector| matches(elem, *selector))
|
||||
.map(|selector| (selector.specificity(), rule))
|
||||
}
|
||||
|
||||
fn matching_rules<'a>(elem: &dom::EData, stylesheet: &'a css::Stylesheet) -> Vec<Rule<'a>> {
|
||||
stylesheet.rules.iter().filter_map(|rule| match_rule(elem, rule)).collect()
|
||||
}
|
||||
|
||||
fn values(elem: &dom::EData, stylesheet: &css::Stylesheet) -> Properties {
|
||||
let mut values = HashMap::new();
|
||||
let mut rules = matching_rules(elem, stylesheet);
|
||||
|
||||
rules.sort_by(|&(a, _), &(b, _)| a.cmp(&b));
|
||||
for (_, rule) in rules {
|
||||
for decl in &rule.declarations {
|
||||
values.insert(decl.name.clone(), decl.value.clone());
|
||||
}
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
pub fn style_tree<'a>(root: &'a dom::Node, stylesheet: &'a css::Stylesheet) -> Node<'a> {
|
||||
Node {
|
||||
node: root,
|
||||
values: match root.ntype {
|
||||
dom::NType::Element(ref elem) => values(elem, stylesheet),
|
||||
dom::NType::Text(_) => HashMap::new(),
|
||||
dom::NType::Comment(_) => HashMap::new(),
|
||||
dom::NType::Stylesheet(_) => HashMap::new(),
|
||||
},
|
||||
children: root.children.iter().map(|child| style_tree(child, stylesheet)).collect(),
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user