mirror of
https://github.com/servo/servo.git
synced 2025-08-06 06:00:15 +01:00
Added css selector matching and now render specified background colors
added comments and put back random colors for unspecified boxes
This commit is contained in:
parent
10294134ab
commit
e3d9650196
14 changed files with 509 additions and 100 deletions
|
@ -50,7 +50,7 @@ fn content(to_layout: chan<layout::msg>) -> chan<msg> {
|
|||
let css_chan = comm::chan(css_port);
|
||||
task::spawn {||
|
||||
let css_stream = parser::lexer::
|
||||
spawn_css_parser_task(new_file);
|
||||
spawn_css_lexer_task(new_file);
|
||||
let css_rules = parser::css_builder::
|
||||
build_stylesheet(css_stream);
|
||||
css_chan.send(css_rules);
|
||||
|
@ -74,7 +74,7 @@ fn content(to_layout: chan<layout::msg>) -> chan<msg> {
|
|||
join_layout(scope, to_layout);
|
||||
|
||||
// Send new document to layout.
|
||||
to_layout.send(layout::build(root));
|
||||
to_layout.send(layout::build(root, css_rules));
|
||||
|
||||
// Indicate that reader was forked so any further
|
||||
// changes will be isolated.
|
||||
|
|
|
@ -2,8 +2,9 @@ import io::println;
|
|||
|
||||
|
||||
enum display_type{
|
||||
block,
|
||||
inline
|
||||
di_block,
|
||||
di_inline,
|
||||
di_none
|
||||
}
|
||||
|
||||
enum style_decl{
|
||||
|
@ -66,8 +67,9 @@ fn print_list_vert<T>(list : [T], print : fn(T) -> str) -> str {
|
|||
|
||||
fn print_display(dis_ty : display_type) -> str {
|
||||
alt dis_ty {
|
||||
block { "block" }
|
||||
inline { "inline" }
|
||||
di_block { "block" }
|
||||
di_inline { "inline" }
|
||||
di_none { "none" }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -130,7 +132,7 @@ fn test_pretty_print() {
|
|||
let elmt2 = ~element("body", [exact("class", "2")]);
|
||||
|
||||
let test2 = [~([~descendant(elmt1, elmt2)],
|
||||
[display(block), text_color(0u)])];
|
||||
[display(di_block), text_color(0u)])];
|
||||
|
||||
let actual2 = print_sheet(test2);
|
||||
let expected2 = "CSS Rules:\n-Selectors: (Element * with attributes: ) "
|
||||
|
|
|
@ -21,9 +21,11 @@ enum box_kind {
|
|||
|
||||
class appearance {
|
||||
let mut background_image: option<@image>;
|
||||
let mut background_color: option<uint>;
|
||||
|
||||
new() {
|
||||
self.background_image = none;
|
||||
self.background_color = none;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
#[doc="Creates CSS boxes from a DOM."]
|
||||
|
||||
import dom::base::{element, es_div, es_img, nk_element, nk_text, node};
|
||||
import dom::style::{display_type, di_block, di_inline, di_none};
|
||||
import dom::rcu::reader_methods;
|
||||
import gfx::geom;
|
||||
import /*layout::*/base::{appearance, bk_block, bk_inline, bk_intrinsic};
|
||||
import /*layout::*/base::{bk_text, box, box_kind, btree, node_methods, ntree};
|
||||
import /*layout::*/base::{rd_tree_ops, wr_tree_ops};
|
||||
import /*layout::*/style::style::{di_block, di_inline, style_methods};
|
||||
import /*layout::*/style::style::{style_methods};
|
||||
import /*layout::*/text::text_box;
|
||||
import util::tree;
|
||||
|
||||
|
@ -62,7 +63,9 @@ impl methods for ctxt {
|
|||
// Add the child's box to the current enclosing box or the current
|
||||
// anonymous box.
|
||||
alt kid.get_computed_style().display {
|
||||
di_block { btree.add_child(self.parent_box, kid_box); }
|
||||
di_block {
|
||||
btree.add_child(self.parent_box, kid_box);
|
||||
}
|
||||
di_inline {
|
||||
let anon_box = alt self.anon_box {
|
||||
none {
|
||||
|
|
|
@ -11,6 +11,7 @@ import gfx::geom;
|
|||
import gfx::renderer;
|
||||
import dom::base::node;
|
||||
import dom::rcu::scope;
|
||||
import dom::style::stylesheet;
|
||||
import /*layout::*/base::*;
|
||||
import /*layout::*/style::apply::apply_style_methods;
|
||||
import /*layout::*/style::style::style_methods;
|
||||
|
@ -18,7 +19,7 @@ import box_builder::box_builder_methods;
|
|||
import dl = display_list;
|
||||
|
||||
enum msg {
|
||||
build(node),
|
||||
build(node, stylesheet),
|
||||
ping(chan<content::ping>),
|
||||
exit
|
||||
}
|
||||
|
@ -29,16 +30,16 @@ fn layout(to_renderer: chan<renderer::msg>) -> chan<msg> {
|
|||
alt po.recv() {
|
||||
ping(ch) { ch.send(content::pong); }
|
||||
exit { break; }
|
||||
build(node) {
|
||||
build(node, styles) {
|
||||
#debug("layout: received layout request for:");
|
||||
node.dump();
|
||||
|
||||
node.recompute_style_for_subtree();
|
||||
node.recompute_style_for_subtree(styles);
|
||||
|
||||
let this_box = node.construct_boxes();
|
||||
this_box.dump();
|
||||
|
||||
this_box.apply_style_for_subtree();
|
||||
this_box.apply_style_for_subtree();
|
||||
this_box.reflow(geom::px_to_au(800));
|
||||
|
||||
let dlist = build_display_list(this_box);
|
||||
|
@ -61,25 +62,41 @@ fn build_display_list(box: @base::box) -> display_list::display_list {
|
|||
}
|
||||
|
||||
fn box_to_display_item(box: @base::box) -> dl::display_item {
|
||||
let mut item;
|
||||
alt box.appearance.background_image {
|
||||
some(image) {
|
||||
item = dl::display_item({
|
||||
item_type: dl::display_item_image(~copy *image),
|
||||
bounds: copy box.bounds
|
||||
});
|
||||
}
|
||||
none {
|
||||
let r = rand::rng();
|
||||
item = dl::display_item({
|
||||
item_type: dl::display_item_solid_color(r.next() as u8,
|
||||
r.next() as u8,
|
||||
r.next() as u8),
|
||||
bounds: copy box.bounds
|
||||
});
|
||||
}
|
||||
}
|
||||
let mut item;
|
||||
alt box.appearance.background_image {
|
||||
some(image) {
|
||||
item = dl::display_item({
|
||||
item_type: dl::display_item_image(~copy *image),
|
||||
bounds: copy box.bounds
|
||||
});
|
||||
}
|
||||
none {
|
||||
alt box.appearance.background_color {
|
||||
some(col) {
|
||||
let red_col = (col >> 16u) & 255u;
|
||||
let green_col = (col >> 8u) & 255u;
|
||||
let blue_col = col & 255u;
|
||||
|
||||
#debug("layout: display item: %?", item);
|
||||
item = dl::display_item({
|
||||
item_type: dl::display_item_solid_color(red_col as u8,
|
||||
green_col as u8,
|
||||
blue_col as u8),
|
||||
bounds: copy box.bounds
|
||||
});
|
||||
}
|
||||
none {
|
||||
let r = rand::rng();
|
||||
item = dl::display_item({
|
||||
item_type: dl::display_item_solid_color(r.next() as u8,
|
||||
r.next() as u8,
|
||||
r.next() as u8),
|
||||
bounds: copy box.bounds
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#debug("layout: display item: %?", item);
|
||||
ret item;
|
||||
}
|
||||
|
|
|
@ -3,46 +3,51 @@ import dom::base::{es_img, nk_element, node};
|
|||
import dom::rcu::reader_methods;
|
||||
import image::base::load;
|
||||
import /*layout::*/base::*;
|
||||
import style::style_methods;
|
||||
|
||||
impl apply_style_methods for @box {
|
||||
fn apply_style_for_subtree() {
|
||||
self.apply_style();
|
||||
for btree.each_child(self) {
|
||||
|child|
|
||||
child.apply_style_for_subtree();
|
||||
}
|
||||
}
|
||||
fn apply_style_for_subtree() {
|
||||
self.apply_style();
|
||||
for btree.each_child(self) {
|
||||
|child|
|
||||
child.apply_style_for_subtree();
|
||||
}
|
||||
}
|
||||
|
||||
#[doc="Applies CSS style."]
|
||||
fn apply_style() {
|
||||
// Right now, we only handle images.
|
||||
self.node.rd {
|
||||
|node|
|
||||
alt node.kind {
|
||||
~nk_element(element) {
|
||||
alt element.subclass {
|
||||
~es_img(*) {
|
||||
alt element.get_attr("src") {
|
||||
some(url) {
|
||||
// FIXME: Some sort of BASE HREF support!
|
||||
// FIXME: Parse URLs!
|
||||
// FIXME: Don't load synchronously!
|
||||
#debug("loading image from %s", url);
|
||||
let image = @load(url);
|
||||
self.appearance.background_image =
|
||||
some(image);
|
||||
}
|
||||
none {
|
||||
/* Ignore. */
|
||||
}
|
||||
}
|
||||
}
|
||||
_ { /* Ignore. */ }
|
||||
}
|
||||
}
|
||||
_ { /* Ignore. */ }
|
||||
}
|
||||
}
|
||||
}
|
||||
#[doc="Applies CSS style."]
|
||||
fn apply_style() {
|
||||
// Right now, we only handle images.
|
||||
self.node.rd {
|
||||
|node|
|
||||
alt node.kind {
|
||||
~nk_element(element) {
|
||||
let style = self.node.get_computed_style();
|
||||
|
||||
self.appearance.background_color = some(style.back_color);
|
||||
|
||||
alt element.subclass {
|
||||
~es_img(*) {
|
||||
alt element.get_attr("src") {
|
||||
some(url) {
|
||||
// FIXME: Some sort of BASE HREF support!
|
||||
// FIXME: Parse URLs!
|
||||
// FIXME: Don't load synchronously!
|
||||
#debug("loading image from %s", url);
|
||||
let image = @load(url);
|
||||
self.appearance.background_image =
|
||||
some(image);
|
||||
}
|
||||
none {
|
||||
/* Ignore. */
|
||||
}
|
||||
}
|
||||
}
|
||||
_ { /* Ignore. */ }
|
||||
}
|
||||
}
|
||||
_ { /* Ignore. */ }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
339
src/servo/layout/style/matching.rs
Normal file
339
src/servo/layout/style/matching.rs
Normal file
|
@ -0,0 +1,339 @@
|
|||
#[doc="Perform css selector matching"]
|
||||
|
||||
import dom::base::{node, nk_element, nk_text};
|
||||
import dom::style::{selector, style_decl, font_size, display, text_color,
|
||||
background_color, stylesheet, element, child, descendant,
|
||||
sibling, attr, exact, exists, includes, starts_with};
|
||||
import dom::rcu::{reader_methods};
|
||||
import style::{computed_style, default_style_for_node_kind};
|
||||
import base::{layout_data};
|
||||
|
||||
export matching_methods;
|
||||
|
||||
#[doc="Update the computed style of an html element with a style specified
|
||||
by css."]
|
||||
fn update_style(style : @computed_style, decl : style_decl) {
|
||||
alt decl {
|
||||
display(dis) { (*style).display = dis; }
|
||||
background_color(col) { (*style).back_color = col; }
|
||||
text_color(*) | font_size(*) { /* not supported yet */ }
|
||||
}
|
||||
}
|
||||
|
||||
#[doc="Check if a css attribute matches the attribute of an html element."]
|
||||
fn attrs_match(attr : attr, elmt : dom::base::element) -> bool {
|
||||
alt attr {
|
||||
exists(name) {
|
||||
alt elmt.get_attr(name) {
|
||||
some(_) { ret true; }
|
||||
none { ret false; }
|
||||
}
|
||||
}
|
||||
exact(name, val) {
|
||||
alt elmt.get_attr(name) {
|
||||
some(value) { ret value == val; }
|
||||
none { ret false; }
|
||||
}
|
||||
}
|
||||
includes(name, val) {
|
||||
// Comply with css spec, if the specified attribute is empty
|
||||
// it cannot match.
|
||||
if val == "" { ret false; }
|
||||
|
||||
alt elmt.get_attr(name) {
|
||||
some(value) { ret value.split_char(' ').contains(val); }
|
||||
none { ret false; }
|
||||
}
|
||||
}
|
||||
starts_with(name, val) {
|
||||
alt elmt.get_attr(name) {
|
||||
some(value) {
|
||||
//check that there is only one attribute value and it
|
||||
//starts with the perscribed value
|
||||
if !value.starts_with(val) || value.contains(" ") { ret false; }
|
||||
|
||||
// We match on either the exact value or value-foo
|
||||
if value.len() == val.len() { ret true; }
|
||||
else { ret value.starts_with(val + "-"); }
|
||||
}
|
||||
none { ret false; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl priv_matching_methods for node {
|
||||
#[doc="Checks if the given css selector, which must describe a single
|
||||
element with no relational information, describes the given
|
||||
html element."]
|
||||
fn matches_element(sel : ~selector) -> bool {
|
||||
alt *sel {
|
||||
child(_, _) | descendant(_, _) | sibling(_, _) { ret false; }
|
||||
element(tag, attrs) {
|
||||
alt self.rd { |n| copy *n.kind } {
|
||||
nk_element(elmt) {
|
||||
if !(tag == "*" || tag == elmt.tag_name) {
|
||||
ret false;
|
||||
}
|
||||
|
||||
let mut i = 0u;
|
||||
while i < attrs.len() {
|
||||
if !attrs_match(attrs[i], elmt) { ret false; }
|
||||
i += 1u;
|
||||
}
|
||||
|
||||
ret true;
|
||||
}
|
||||
nk_text(str) { /*fall through, currently unsupported*/ }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret false; //If we got this far it was because something was
|
||||
//unsupported.
|
||||
}
|
||||
|
||||
#[doc = "Checks if a generic css selector matches a given html element"]
|
||||
fn matches_selector(sel : ~selector) -> bool {
|
||||
alt *sel {
|
||||
element(str, atts) { ret self.matches_element(sel); }
|
||||
child(sel1, sel2) {
|
||||
alt self.rd { |n| n.tree.parent } {
|
||||
some(parent) {
|
||||
ret self.matches_element(sel2) &&
|
||||
parent.matches_selector(sel1);
|
||||
}
|
||||
none { ret false; }
|
||||
}
|
||||
}
|
||||
descendant(sel1, sel2) {
|
||||
if !self.matches_element(sel2) {
|
||||
ret false;
|
||||
}
|
||||
|
||||
//loop over all ancestors to check if they are the person
|
||||
//we should be descended from.
|
||||
let mut cur_parent = alt self.rd { |n| n.tree.parent } {
|
||||
some(parent) { parent }
|
||||
none { ret false; }
|
||||
};
|
||||
|
||||
loop {
|
||||
if cur_parent.matches_selector(sel1) { ret true; }
|
||||
|
||||
cur_parent = alt cur_parent.rd { |n| n.tree.parent } {
|
||||
some(parent) { parent }
|
||||
none { ret false; }
|
||||
};
|
||||
}
|
||||
}
|
||||
sibling(sel1, sel2) {
|
||||
if !self.matches_element(sel2) { ret false; }
|
||||
|
||||
// loop over this node's previous siblings to see if they
|
||||
// match
|
||||
alt self.rd { |n| n.tree.prev_sibling } {
|
||||
some(sib) {
|
||||
let mut cur_sib = sib;
|
||||
loop {
|
||||
if cur_sib.matches_selector(sel1) { ret true; }
|
||||
|
||||
cur_sib = alt cur_sib.rd { |n| n.tree.prev_sibling } {
|
||||
some(sib) { sib }
|
||||
none { break; }
|
||||
};
|
||||
}
|
||||
}
|
||||
none { }
|
||||
}
|
||||
|
||||
// check the rest of the siblings
|
||||
alt self.rd { |n| n.tree.next_sibling } {
|
||||
some(sib) {
|
||||
let mut cur_sib = sib;
|
||||
loop {
|
||||
if cur_sib.matches_selector(sel1) { ret true; }
|
||||
|
||||
cur_sib = alt cur_sib.rd { |n| n.tree.next_sibling } {
|
||||
some(sib) { sib }
|
||||
none { break; }
|
||||
};
|
||||
}
|
||||
}
|
||||
none { }
|
||||
}
|
||||
|
||||
ret false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl matching_methods for node {
|
||||
#[doc="Compare an html element to a list of css rules and update its
|
||||
style according to the rules matching it."]
|
||||
fn match_css_style(styles : stylesheet) -> computed_style {
|
||||
let node_kind = self.rd { |n| copy *n.kind };
|
||||
let style =
|
||||
@default_style_for_node_kind(node_kind);
|
||||
|
||||
// Loop over each rule, see if our node matches what is
|
||||
// described in the rule. If it matches, update its style.
|
||||
// As we don't currently have priorities of style information,
|
||||
// the latest rule takes precedence so we can just overwrite
|
||||
// style information.
|
||||
for styles.each { |sty|
|
||||
let (selectors, decls) <- *(copy sty);
|
||||
for selectors.each { |sel|
|
||||
if self.matches_selector(sel) {
|
||||
#debug("Matched selector {%?} with node {%?}",
|
||||
*sel, node_kind);
|
||||
for decls.each { |decl|
|
||||
update_style(style, decl);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#debug["Changed the style to: %?", *style];
|
||||
|
||||
ret copy *(style);
|
||||
}
|
||||
}
|
||||
|
||||
mod test {
|
||||
import dom::base::{node_scope, methods, nk_element, attr, es_div,
|
||||
es_img, es_unknown, es_head, wr_tree_ops};
|
||||
import dvec::{dvec, extensions};
|
||||
import io::println;
|
||||
|
||||
fn new_node_from_attr(scope : node_scope, name : str, val : str) -> node {
|
||||
let elmt = dom::base::element("div", ~es_div);
|
||||
let attr = ~attr(name, val);
|
||||
elmt.attrs.push(copy attr);
|
||||
ret scope.new_node(nk_element(elmt));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_match_pipe1() {
|
||||
let scope = node_scope();
|
||||
let node = new_node_from_attr(scope, "lang", "en-us");
|
||||
|
||||
let sel = element("*", [starts_with("lang", "en")]);
|
||||
|
||||
assert node.matches_selector(~sel);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_match_pipe2() {
|
||||
let scope = node_scope();
|
||||
let node = new_node_from_attr(scope, "lang", "en");
|
||||
|
||||
let sel = element("*", [starts_with("lang", "en")]);
|
||||
|
||||
assert node.matches_selector(~sel);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_not_match_pipe() {
|
||||
let scope = node_scope();
|
||||
let node = new_node_from_attr(scope, "lang", "english");
|
||||
|
||||
let sel = element("*", [starts_with("lang", "en")]);
|
||||
|
||||
assert !node.matches_selector(~sel);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_match_includes() {
|
||||
let scope = node_scope();
|
||||
let node = new_node_from_attr(scope, "mad", "hatter cobler cooper");
|
||||
|
||||
let sel = element("div", [includes("mad", "hatter")]);
|
||||
|
||||
assert node.matches_selector(~sel);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_match_exists() {
|
||||
let scope = node_scope();
|
||||
let node = new_node_from_attr(scope, "mad", "hatter cobler cooper");
|
||||
|
||||
let sel1 = element("div", [exists("mad")]);
|
||||
let sel2 = element("div", [exists("hatter")]);
|
||||
|
||||
assert node.matches_selector(~sel1);
|
||||
assert !node.matches_selector(~sel2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_match_exact() {
|
||||
let scope = node_scope();
|
||||
let node1 = new_node_from_attr(scope, "mad", "hatter cobler cooper");
|
||||
let node2 = new_node_from_attr(scope, "mad", "hatter");
|
||||
|
||||
let sel = element("div", [exact("mad", "hatter")]);
|
||||
|
||||
assert !node1.matches_selector(~copy sel);
|
||||
assert node2.matches_selector(~sel);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn match_tree() {
|
||||
let scope = node_scope();
|
||||
|
||||
let root = new_node_from_attr(scope, "class", "blue");
|
||||
let child1 = new_node_from_attr(scope, "id", "green");
|
||||
let child2 = new_node_from_attr(scope, "flag", "black");
|
||||
let gchild = new_node_from_attr(scope, "flag", "grey");
|
||||
let ggchild = new_node_from_attr(scope, "flag", "white");
|
||||
let gggchild = new_node_from_attr(scope, "flag", "purple");
|
||||
|
||||
scope.add_child(root, child1);
|
||||
scope.add_child(root, child2);
|
||||
scope.add_child(child2, gchild);
|
||||
scope.add_child(gchild, ggchild);
|
||||
scope.add_child(ggchild, gggchild);
|
||||
|
||||
let sel1 = descendant(~element("*", [exact("class", "blue")]),
|
||||
~element("*", []));
|
||||
|
||||
assert !root.matches_selector(~copy sel1);
|
||||
assert child1.matches_selector(~copy sel1);
|
||||
assert child2.matches_selector(~copy sel1);
|
||||
assert gchild.matches_selector(~copy sel1);
|
||||
assert ggchild.matches_selector(~copy sel1);
|
||||
assert gggchild.matches_selector(~sel1);
|
||||
|
||||
let sel2 = descendant(~child(~element("*", [exact("class", "blue")]),
|
||||
~element("*", [])),
|
||||
~element("div", [exists("flag")]));
|
||||
|
||||
assert !root.matches_selector(~copy sel2);
|
||||
assert !child1.matches_selector(~copy sel2);
|
||||
assert !child2.matches_selector(~copy sel2);
|
||||
assert gchild.matches_selector(~copy sel2);
|
||||
assert ggchild.matches_selector(~copy sel2);
|
||||
assert gggchild.matches_selector(~sel2);
|
||||
|
||||
let sel3 = sibling(~element("*", []), ~element("*", []));
|
||||
|
||||
assert !root.matches_selector(~copy sel3);
|
||||
assert child1.matches_selector(~copy sel3);
|
||||
assert child2.matches_selector(~copy sel3);
|
||||
assert !gchild.matches_selector(~copy sel3);
|
||||
assert !ggchild.matches_selector(~copy sel3);
|
||||
assert !gggchild.matches_selector(~sel3);
|
||||
|
||||
let sel4 = descendant(~child(~element("*", [exists("class")]),
|
||||
~element("*", [])),
|
||||
~element("*", []));
|
||||
|
||||
assert !root.matches_selector(~copy sel4);
|
||||
assert !child1.matches_selector(~copy sel4);
|
||||
assert !child2.matches_selector(~copy sel4);
|
||||
assert gchild.matches_selector(~copy sel4);
|
||||
assert ggchild.matches_selector(~copy sel4);
|
||||
assert gggchild.matches_selector(~sel4);
|
||||
}
|
||||
}
|
|
@ -1,35 +1,39 @@
|
|||
#[doc="High-level interface to CSS selector matching."]
|
||||
|
||||
import dom::style::{display_type, di_block, di_inline, di_none,
|
||||
stylesheet};
|
||||
import dom::base::{element, es_div, es_head, es_img, nk_element, nk_text};
|
||||
import dom::base::{node};
|
||||
import dom::base::node_kind;
|
||||
import dom::rcu::reader_methods;
|
||||
import /*layout::*/base::*; // FIXME: resolve bug requires *
|
||||
import matching::matching_methods;
|
||||
|
||||
enum computed_style = {
|
||||
mut display: display
|
||||
};
|
||||
|
||||
enum display {
|
||||
di_block,
|
||||
di_inline,
|
||||
di_none
|
||||
}
|
||||
type computed_style = {mut display : display_type,
|
||||
mut back_color : uint};
|
||||
|
||||
#[doc="Returns the default style for the given node kind."]
|
||||
fn default_style_for_node_kind(kind: node_kind) -> computed_style {
|
||||
alt kind {
|
||||
nk_text(*) {
|
||||
computed_style({ mut display: di_inline })
|
||||
}
|
||||
nk_element(element) {
|
||||
alt *element.subclass {
|
||||
es_div { computed_style({ mut display: di_block }) }
|
||||
es_head { computed_style({ mut display: di_none }) }
|
||||
es_img(*) { computed_style({ mut display: di_inline }) }
|
||||
es_unknown { computed_style({ mut display: di_inline }) }
|
||||
}
|
||||
nk_text(*) {
|
||||
{mut display: di_inline,
|
||||
mut back_color : 256u*256u*256u-1u}
|
||||
}
|
||||
nk_element(element) {
|
||||
let r = rand::rng();
|
||||
let rand_color = 256u*256u*((r.next() & (255 as u32)) as uint)
|
||||
+ 256u*((r.next() & (255 as u32)) as uint)
|
||||
+ ((r.next() & (255 as u32)) as uint);
|
||||
|
||||
alt *element.subclass {
|
||||
es_div { {mut display : di_block,
|
||||
mut back_color : rand_color} }
|
||||
es_head { {mut display : di_none, mut back_color : rand_color} }
|
||||
es_img(*) { {mut display : di_inline, mut back_color : rand_color} }
|
||||
es_unknown { {mut display : di_inline, mut back_color :
|
||||
rand_color} }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,14 +45,13 @@ impl style_priv for node {
|
|||
the node (the reader-auxiliary box in the RCU model) and populates it
|
||||
with the computed style.
|
||||
"]
|
||||
fn recompute_style() {
|
||||
let default_style: computed_style =
|
||||
default_style_for_node_kind(self.rd { |n| copy *n.kind });
|
||||
fn recompute_style(styles : stylesheet) {
|
||||
let style = self.match_css_style(styles);
|
||||
|
||||
#debug("recomputing style; parent node:");
|
||||
|
||||
let the_layout_data = @layout_data({
|
||||
mut computed_style: default_style,
|
||||
mut computed_style: style,
|
||||
mut box: none
|
||||
});
|
||||
|
||||
|
@ -78,12 +81,14 @@ impl style_methods for node {
|
|||
This is, importantly, the function that creates the layout data for
|
||||
the node (the reader-auxiliary box in the RCU model) and populates it
|
||||
with the computed style.
|
||||
|
||||
TODO: compute the style of multiple nodes in parallel.
|
||||
"]
|
||||
fn recompute_style_for_subtree() {
|
||||
self.recompute_style();
|
||||
fn recompute_style_for_subtree(styles : stylesheet) {
|
||||
self.recompute_style(styles);
|
||||
for ntree.each_child(self) {
|
||||
|kid|
|
||||
kid.recompute_style_for_subtree();
|
||||
kid.recompute_style_for_subtree(styles);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ impl methods for token_reader {
|
|||
}
|
||||
|
||||
fn unget(tok : token) {
|
||||
assert self.lookahead.is_none();
|
||||
self.lookahead = some(tok);
|
||||
}
|
||||
}
|
||||
|
@ -85,7 +86,7 @@ fn parse_color(color : str) -> uint {
|
|||
|
||||
i += 1u;
|
||||
|
||||
while i < color_vec.len() && color_vec[i] != ',' as u8 {
|
||||
while i < color_vec.len() && color_vec[i] != ')' as u8 {
|
||||
blue_vec += [color_vec[i]];
|
||||
i += 1u;
|
||||
}
|
||||
|
@ -220,8 +221,9 @@ fn parse_rule(reader : token_reader) -> option<~rule> {
|
|||
}
|
||||
"display" {
|
||||
alt val {
|
||||
"inline" { desc_list += [display(inline)]; }
|
||||
"block" { desc_list += [display(block)]; }
|
||||
"inline" { desc_list += [display(di_inline)]; }
|
||||
"block" { desc_list += [display(di_block)]; }
|
||||
"none" { desc_list += [display(di_none)]; }
|
||||
_ { #debug["Recieved unknown display value '%s'",
|
||||
val]; }
|
||||
}
|
||||
|
|
|
@ -493,7 +493,7 @@ fn spawn_html_parser_task(filename: str) -> port<html::token> {
|
|||
ret result_port;
|
||||
}
|
||||
|
||||
fn spawn_css_parser_task(filename: str) -> port<css::token> {
|
||||
fn spawn_css_lexer_task(filename: str) -> port<css::token> {
|
||||
let result_port = port();
|
||||
let result_chan = chan(result_port);
|
||||
task::spawn {||
|
||||
|
|
|
@ -37,6 +37,7 @@ mod layout {
|
|||
mod style {
|
||||
mod apply;
|
||||
mod style;
|
||||
mod matching;
|
||||
}
|
||||
|
||||
mod base;
|
||||
|
|
|
@ -3,3 +3,8 @@ p img {color : rgb(0,255,0); display : block }
|
|||
p.blue > p.green + p.red { background-color : blue ;color : green }
|
||||
img[class] .pastoral *[lang|=en] { display:inline}
|
||||
.book > #novel + *[type=novella] p { color : blue; color : white }
|
||||
* {background-color : red}
|
||||
* * * * {background-color : black}
|
||||
div div {background-color : green}
|
||||
* * div {background-color : blue}
|
||||
div div div {background-color : rgb(100,100,100)}
|
||||
|
|
16
src/test/test_bg_color.css
Normal file
16
src/test/test_bg_color.css
Normal file
|
@ -0,0 +1,16 @@
|
|||
.green {background-color : green}
|
||||
.blue {background-color : blue}
|
||||
.red {background-color : red}
|
||||
.white {background-color : white}
|
||||
.black {background-color : black}
|
||||
.brown {background-color : rgb(200,100,0)}
|
||||
.gray {background-color : rgb(100,100,100)}
|
||||
.lightgray {background-color : rgb(200,200,200)}
|
||||
.darkgray {background-color : rgb(50,50,50)}
|
||||
.cyan {background-color : rgb(0,255,255)}
|
||||
.maroon {background-color : rgb(100,0,20)}
|
||||
.pink {background-color : rgb(255,0,255)}
|
||||
.orange {background-color : rgb(255,175,0)}
|
||||
.violet {background-color : rgb(100,0,150)}
|
||||
.darkgreen {background-color : rgb(0,100,0)}
|
||||
.darkblue {background-color : rgb(0,0,100)}
|
12
src/test/test_bg_color.html
Normal file
12
src/test/test_bg_color.html
Normal file
|
@ -0,0 +1,12 @@
|
|||
<div class="darkgrey">
|
||||
<div class="green">
|
||||
<div class="darkblue"><img class="maroon"></img><div class="darkgreen"><img class="gray"></img></div></div>
|
||||
<img class="black"></img>
|
||||
<img class="brown"></img>
|
||||
<div class="pink"><img class="orange"></img><img class="violet"></img></div>
|
||||
<div class="lightgray">
|
||||
<img class="blue"></img>
|
||||
<img class="red"></img>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
Loading…
Add table
Add a link
Reference in a new issue