styling: added preliminary styling application

This commit is contained in:
2017-08-25 17:58:25 +02:00
parent 02f5aee141
commit e4966a6536
4 changed files with 113 additions and 23 deletions

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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
View 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(),
}
}