styling: added preliminary styling application
This commit is contained in:
33
src/css.rs
33
src/css.rs
@@ -1,9 +1,9 @@
|
|||||||
use std;
|
use std;
|
||||||
|
|
||||||
struct SimpleSelector {
|
pub struct SimpleSelector {
|
||||||
tag_name: Option<String>,
|
pub tag_name: Option<String>,
|
||||||
id: Option<String>,
|
pub id: Option<String>,
|
||||||
class: Vec<String>,
|
pub class: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ChainSelector {
|
struct ChainSelector {
|
||||||
@@ -12,7 +12,7 @@ struct ChainSelector {
|
|||||||
class: Vec<Vec<String>>,
|
class: Vec<Vec<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Selector {
|
pub enum Selector {
|
||||||
Simple(SimpleSelector),
|
Simple(SimpleSelector),
|
||||||
//Chain(ChainSelector),
|
//Chain(ChainSelector),
|
||||||
}
|
}
|
||||||
@@ -43,7 +43,8 @@ impl std::fmt::Display for Selector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Unit {
|
#[derive(Clone)]
|
||||||
|
pub enum Unit {
|
||||||
Px,
|
Px,
|
||||||
Em,
|
Em,
|
||||||
Rm,
|
Rm,
|
||||||
@@ -65,14 +66,16 @@ impl std::fmt::Display for Unit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Color {
|
#[derive(Clone)]
|
||||||
|
pub struct Color {
|
||||||
r: u8,
|
r: u8,
|
||||||
g: u8,
|
g: u8,
|
||||||
b: u8,
|
b: u8,
|
||||||
a: u8,
|
a: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Value {
|
#[derive(Clone)]
|
||||||
|
pub enum Value {
|
||||||
Keyword(String),
|
Keyword(String),
|
||||||
Length(f32, Unit),
|
Length(f32, Unit),
|
||||||
ColorValue(Color),
|
ColorValue(Color),
|
||||||
@@ -88,9 +91,9 @@ impl std::fmt::Display for Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Declaration {
|
pub struct Declaration {
|
||||||
name: String,
|
pub name: String,
|
||||||
value: Value,
|
pub value: Value,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for Declaration {
|
impl std::fmt::Display for Declaration {
|
||||||
@@ -99,9 +102,9 @@ impl std::fmt::Display for Declaration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Rule {
|
pub struct Rule {
|
||||||
selectors: Vec<Selector>,
|
pub selectors: Vec<Selector>,
|
||||||
declarations: Vec<Declaration>,
|
pub declarations: Vec<Declaration>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for Rule {
|
impl std::fmt::Display for Rule {
|
||||||
@@ -124,7 +127,7 @@ impl std::fmt::Display for Rule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct Stylesheet {
|
pub struct Stylesheet {
|
||||||
rules: Vec<Rule>,
|
pub rules: Vec<Rule>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for Stylesheet {
|
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 std;
|
||||||
|
|
||||||
use css;
|
use css;
|
||||||
@@ -7,17 +7,30 @@ pub struct Attr {
|
|||||||
attrs: HashMap<String, String>,
|
attrs: HashMap<String, String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct EData {
|
pub struct EData {
|
||||||
name: String,
|
pub name: String,
|
||||||
attr: Attr,
|
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,
|
attr: Attr,
|
||||||
content: css::Stylesheet,
|
content: css::Stylesheet,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum NType {
|
pub enum NType {
|
||||||
Text(String),
|
Text(String),
|
||||||
Comment(String),
|
Comment(String),
|
||||||
Element(EData),
|
Element(EData),
|
||||||
@@ -25,8 +38,8 @@ enum NType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct Node {
|
pub struct Node {
|
||||||
children: Vec<Node>,
|
pub children: Vec<Node>,
|
||||||
ntype: NType,
|
pub ntype: NType,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn text(d: String) -> Node {
|
pub fn text(d: String) -> Node {
|
||||||
|
@@ -6,6 +6,7 @@ use std::fs::File;
|
|||||||
pub mod css;
|
pub mod css;
|
||||||
pub mod dom;
|
pub mod dom;
|
||||||
pub mod html;
|
pub mod html;
|
||||||
|
pub mod styling;
|
||||||
|
|
||||||
fn read_source(filename: String) -> String {
|
fn read_source(filename: String) -> String {
|
||||||
let mut str = String::new();
|
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