mirror of
https://github.com/servo/servo.git
synced 2025-08-06 14:10:11 +01:00
Changed css matching to match nodes in parallel.
This commit is contained in:
parent
d7db7a56c3
commit
a322542825
11 changed files with 74 additions and 62 deletions
|
@ -9,6 +9,9 @@ export content;
|
|||
import dom::base::NodeScope;
|
||||
import dom::rcu::WriterMethods;
|
||||
import dom::style;
|
||||
import parser::lexer::{spawn_css_lexer_task, spawn_html_parser_task};
|
||||
import parser::css_builder::build_stylesheet;
|
||||
import parser::html_builder::build_dom;
|
||||
import layout::layout_task;
|
||||
|
||||
import js::rust::methods;
|
||||
|
@ -51,26 +54,23 @@ fn content(to_layout: chan<layout_task::Msg>) -> chan<ControlMsg> {
|
|||
// TODO actually parse where the css sheet should be
|
||||
// Replace .html with .css and try to open a stylesheet
|
||||
assert (*filename).ends_with(".html");
|
||||
let new_file = (*filename).substr(0u, (*filename).len() - 5u)
|
||||
+ ".css";
|
||||
let new_file = (*filename).substr(0u, (*filename).len() - 5u) + ".css";
|
||||
|
||||
// Send off a task to parse the stylesheet
|
||||
let css_port = comm::port();
|
||||
let css_chan = comm::chan(css_port);
|
||||
task::spawn {||
|
||||
let new_file <- new_file;
|
||||
let css_stream = parser::lexer::
|
||||
spawn_css_lexer_task(~new_file);
|
||||
let css_rules = parser::css_builder::
|
||||
build_stylesheet(css_stream);
|
||||
let css_stream = spawn_css_lexer_task(~new_file);
|
||||
let css_rules = build_stylesheet(css_stream);
|
||||
css_chan.send(css_rules);
|
||||
};
|
||||
|
||||
// Note: we can parse the next document in parallel
|
||||
// with any previous documents.
|
||||
let stream = parser::lexer::spawn_html_parser_task(filename);
|
||||
let root = parser::html_builder::build_dom(scope, stream);
|
||||
|
||||
let stream = spawn_html_parser_task(filename);
|
||||
let root = build_dom(scope, stream);
|
||||
|
||||
// Collect the css stylesheet
|
||||
let css_rules = comm::recv(css_port);
|
||||
|
||||
|
@ -92,8 +92,7 @@ fn content(to_layout: chan<layout_task::Msg>) -> chan<ControlMsg> {
|
|||
}
|
||||
|
||||
ExecuteMsg(filename) {
|
||||
#debug["content: Received filename `%s` to execute",
|
||||
*filename];
|
||||
#debug["content: Received filename `%s` to execute", *filename];
|
||||
|
||||
alt io::read_whole_file(*filename) {
|
||||
result::err(msg) {
|
||||
|
@ -106,8 +105,7 @@ fn content(to_layout: chan<layout_task::Msg>) -> chan<ControlMsg> {
|
|||
cx.new_compartment(js::global::global_class).chain {
|
||||
|compartment|
|
||||
compartment.define_functions(js::global::debug_fns);
|
||||
cx.evaluate_script(compartment.global_obj, bytes,
|
||||
*filename, 1u)
|
||||
cx.evaluate_script(compartment.global_obj, bytes, *filename, 1u)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ class Box {
|
|||
}
|
||||
|
||||
enum layout_data = {
|
||||
mut computed_style: computed_style,
|
||||
mut computed_style: ~computed_style,
|
||||
mut box: option<@Box>
|
||||
};
|
||||
|
||||
|
|
|
@ -55,9 +55,11 @@ fn build_display_list_from_origin(box: @Box, origin: Point2D<au>)
|
|||
#[doc="
|
||||
|
||||
Creates a display list item for a single block.
|
||||
Args:
|
||||
-box: the box to build the display list for
|
||||
-origin: the coordinates of upper-left corner of the passed in box.
|
||||
|
||||
# Arguments
|
||||
|
||||
* `box` - The box to build the display list for
|
||||
* `origin` - The coordinates of upper-left corner of the passed in box.
|
||||
|
||||
"]
|
||||
fn box_to_display_items(box: @Box, origin: Point2D<au>) -> [dl::display_item] {
|
||||
|
|
|
@ -35,6 +35,7 @@ fn layout(to_renderer: chan<renderer::Msg>) -> chan<Msg> {
|
|||
#debug("layout: received layout request for:");
|
||||
node.dump();
|
||||
|
||||
node.initialize_style_for_subtree();
|
||||
node.recompute_style_for_subtree(styles);
|
||||
|
||||
let this_box = node.construct_boxes();
|
||||
|
|
|
@ -10,15 +10,6 @@ import style::{computed_style, default_style_for_node_kind};
|
|||
|
||||
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: ElementData) -> bool {
|
||||
alt attr {
|
||||
|
@ -170,14 +161,23 @@ impl priv_matching_methods for Node {
|
|||
}
|
||||
}
|
||||
|
||||
impl priv_style_methods for Node {
|
||||
#[doc="Update the computed style of an HTML element with a style specified by CSS."]
|
||||
fn update_style(decl : style_decl) {
|
||||
self.aux() { |layout|
|
||||
alt decl {
|
||||
display(dis) { layout.computed_style.display = dis; }
|
||||
background_color(col) { layout.computed_style.back_color = col; }
|
||||
text_color(*) | font_size(*) { /* not supported yet */ }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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.read { |n| copy *n.kind };
|
||||
let style =
|
||||
@default_style_for_node_kind(node_kind);
|
||||
|
||||
fn match_css_style(styles : stylesheet) {
|
||||
// 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 over the others. So we just overwrite style
|
||||
|
@ -187,20 +187,18 @@ impl matching_methods for Node {
|
|||
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);
|
||||
self.update_style(decl);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#debug["Changed the style to: %?", *style];
|
||||
|
||||
ret copy *(style);
|
||||
|
||||
self.aux() { |a| #debug["Changed the style to: %?", copy *a.computed_style]; }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
import dom::base::{Attr, Element, HTMLDivElement, HTMLHeadElement, HTMLImageElement};
|
||||
import dom::base::{NodeScope, TreeReadMethods, TreeWriteMethods, UnknownElement};
|
||||
|
|
|
@ -9,8 +9,7 @@ import matching::matching_methods;
|
|||
import util::color::{Color, rgb};
|
||||
import util::color::css_colors::{white, black};
|
||||
|
||||
type computed_style = {mut display : display_type,
|
||||
mut back_color : Color};
|
||||
type computed_style = {mut display : display_type, mut back_color : Color};
|
||||
|
||||
#[doc="Returns the default style for the given node kind."]
|
||||
fn default_style_for_node_kind(kind: NodeKind) -> computed_style {
|
||||
|
@ -34,29 +33,30 @@ fn default_style_for_node_kind(kind: NodeKind) -> computed_style {
|
|||
}
|
||||
|
||||
impl style_priv for Node {
|
||||
#[doc="
|
||||
Performs CSS selector matching on a node.
|
||||
#[doc="Set a default auxilliary data so that other threads can modify it.
|
||||
|
||||
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.
|
||||
"]
|
||||
fn recompute_style(styles : stylesheet) {
|
||||
let style = self.match_css_style(styles);
|
||||
|
||||
#debug("recomputing style; parent node:");
|
||||
|
||||
auxiliary box in the RCU model) and populates it with the default style.
|
||||
"]
|
||||
fn initialize_style() {
|
||||
let node_kind = self.read { |n| copy *n.kind };
|
||||
let the_layout_data = @layout_data({
|
||||
mut computed_style: style,
|
||||
mut box: none
|
||||
mut computed_style : ~default_style_for_node_kind(node_kind),
|
||||
mut box : none
|
||||
});
|
||||
|
||||
#debug("layout data: %?", the_layout_data);
|
||||
|
||||
self.set_aux(the_layout_data);
|
||||
}
|
||||
}
|
||||
|
||||
impl style_methods for Node {
|
||||
#[doc="Sequentially initialize the nodes' auxilliary data so they can be updated in parallel."]
|
||||
fn initialize_style_for_subtree() {
|
||||
self.initialize_style();
|
||||
|
||||
for ntree.each_child(self) { |kid| kid.initialize_style_for_subtree(); }
|
||||
}
|
||||
|
||||
#[doc="
|
||||
Returns the computed style for the given node. If CSS selector matching has not yet been
|
||||
performed, fails.
|
||||
|
@ -67,23 +67,30 @@ impl style_methods for Node {
|
|||
if !self.has_aux() {
|
||||
fail "get_computed_style() called on a node without a style!";
|
||||
}
|
||||
ret copy self.aux({ |x| copy x }).computed_style;
|
||||
ret copy *self.aux({ |x| copy x }).computed_style;
|
||||
}
|
||||
|
||||
#[doc="
|
||||
Performs CSS selector matching on a subtree.
|
||||
|
||||
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.
|
||||
This is, importantly, the function that updates the layout data for the node (the reader-
|
||||
auxiliary box in the RCU model) with the computed style.
|
||||
"]
|
||||
fn recompute_style_for_subtree(styles : stylesheet) {
|
||||
self.recompute_style(styles);
|
||||
for ntree.each_child(self) {
|
||||
|kid|
|
||||
kid.recompute_style_for_subtree(styles);
|
||||
listen { |ack_chan|
|
||||
|
||||
// TODO: Don't copy this for every element, look into shared, immutable state
|
||||
let new_styles = copy styles;
|
||||
|
||||
task::spawn { ||
|
||||
self.match_css_style(new_styles);
|
||||
ack_chan.send(());
|
||||
}
|
||||
|
||||
for ntree.each_child(self) { |kid| kid.recompute_style_for_subtree(styles); }
|
||||
|
||||
// Make sure we finish updating the tree before returning
|
||||
ack_chan.recv();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -174,6 +174,7 @@ mod parsing {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
import css_colors::*;
|
||||
import parsing::parse_color;
|
||||
|
|
1
src/test/small_color_test.css
Normal file
1
src/test/small_color_test.css
Normal file
|
@ -0,0 +1 @@
|
|||
img {background-color : red }
|
1
src/test/small_color_test.html
Normal file
1
src/test/small_color_test.html
Normal file
|
@ -0,0 +1 @@
|
|||
<img></img>
|
|
@ -4,6 +4,8 @@ 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 : lime}
|
||||
* * * {background-color : yellow}
|
||||
* * * * {background-color : white}
|
||||
* * * * * {background-color : rgb(200,0,200)}
|
||||
div div {background-color : green}
|
||||
|
|
1
src/test/tiny_test.html
Normal file
1
src/test/tiny_test.html
Normal file
|
@ -0,0 +1 @@
|
|||
|
Loading…
Add table
Add a link
Reference in a new issue