Skip to content

Commit

Permalink
separate into tasks that actually parse
Browse files Browse the repository at this point in the history
  • Loading branch information
nikomatsakis committed May 4, 2012
1 parent 480d361 commit 275185a
Show file tree
Hide file tree
Showing 10 changed files with 166 additions and 104 deletions.
60 changes: 45 additions & 15 deletions src/servo/content.rs
@@ -1,29 +1,59 @@
export msg;
export msg, ping;
export content;

import gfx::geom::*;
import dom::rcu::*;
import dom::base::*;
import layout::base::{rd_tree_ops, wr_tree_ops};
import dom::rcu::writer_methods;
import dom=dom::base;
import layout::layout;

enum msg {
parse(str),
exit
}

fn content(layout: chan<layout::layout::msg>) -> chan<msg> {
enum ping {
pong
}

task::spawn_listener::<msg> {|po|
// TODO: Get a DOM from the parser
// let s: int = scope();
// sends a ping to layout and awaits the response.
fn join_layout(scope: dom::node_scope,
to_layout: chan<layout::msg>) {
if scope.is_reader_forked() {
comm::listen { |ch|
to_layout.send(layout::ping(ch));
ch.recv();
}
scope.reader_joined();
}
}

// TODO: RCU this stuff over to layout
fn content(to_layout: chan<layout::msg>) -> chan<msg> {
task::spawn_listener::<msg> {|from_master|
let scope = dom::node_scope();
loop {
if po.peek() {
alt from_master.recv() {
parse(filename) {
#debug["content: Received filename `%s`", filename];

// Note: we can parse the next document in parallel
// with any previous documents.
let stream = html::spawn_parser_task(filename);
let root = parser::html_builder::build_dom(scope, stream);

// Now, join the layout so that they will see the latest
// changes we have made.
join_layout(scope, to_layout);

// Send new document to layout.
to_layout.send(layout::build(root));

// Indicate that reader was forked so any further
// changes will be isolated.
scope.reader_forked();
}
exit {
to_layout.send(layout::exit);
break;
} else {
#debug("content: requesting layout");
layout.send(layout::layout::build);
std::timer::sleep(1000u);
}
}
}
}
Expand Down
19 changes: 13 additions & 6 deletions src/servo/dom/base.rs
@@ -1,4 +1,4 @@
import dom::rcu::{scope, writer_methods};
import dom::rcu::{writer_methods};
import gfx::geom::{au, size};
import layout::base::box;
import util::tree;
Expand All @@ -16,30 +16,37 @@ enum node_kind {
// The rd_aux data is a (weak) pointer to the primary box. Note that
// there may be multiple boxes per DOM node.
type node = rcu::handle<node_data, box>;
type node_scope = rcu::scope<node_data, box>;

impl methods for scope<node_data, box> {
fn node_scope() -> node_scope { rcu::scope() }

impl methods for node_scope {
fn new_node(+k: node_kind) -> node {
self.handle(node_data({tree: tree::empty(),
kind: k}))
}
}

impl of tree::rd_tree_ops<node> for scope<node_data, box> {
impl of tree::rd_tree_ops<node> for node_scope {
fn each_child(node: node, f: fn(node) -> bool) {
tree::each_child(self, node, f)
}

fn get_parent(node: node) -> option<node> {
tree::get_parent(self, node)
}

fn with_tree_fields<R>(node: node, f: fn(tree::fields<node>) -> R) -> R {
f(self.rd(node) { |f| f.tree })
self.rd(node) { |n| f(n.tree) }
}
}

impl of tree::wr_tree_ops<node> for scope<node_data, box> {
impl of tree::wr_tree_ops<node> for node_scope {
fn add_child(node: node, child: node) {
tree::add_child(self, node, child)
}

fn with_tree_fields<R>(node: node, f: fn(tree::fields<node>) -> R) -> R {
f(self.wr(node) { |f| f.tree })
self.wr(node) { |n| f(n.tree) }
}
}
16 changes: 10 additions & 6 deletions src/servo/dom/rcu.rs
Expand Up @@ -98,6 +98,10 @@ fn scope<T:send,A>() -> scope<T,A> {
}

impl writer_methods<T:send,A> for scope<T,A> {
fn is_reader_forked() -> bool {
self.layout_active
}

fn reader_forked() {
assert !self.layout_active;
assert self.first_dirty.is_null();
Expand All @@ -120,6 +124,7 @@ impl writer_methods<T:send,A> for scope<T,A> {
self.first_dirty = null_handle();
}

assert self.first_dirty.is_null();
self.layout_active = false;
}

Expand All @@ -130,12 +135,11 @@ impl writer_methods<T:send,A> for scope<T,A> {
}

fn wr<U>(h: handle<T,A>, f: fn(T) -> U) -> U unsafe {
if self.layout_active {
if h.rd_ptr() == h.wr_ptr() {
h.set_wr_ptr(self.clone(h.rd_ptr()));
h.set_next_dirty(self.first_dirty);
self.first_dirty = h;
}
if self.layout_active && h.rd_ptr() == h.wr_ptr() {
#debug["marking handle %? as dirty", h];
h.set_wr_ptr(self.clone(h.rd_ptr()));
h.set_next_dirty(self.first_dirty);
self.first_dirty = h;
}
f(*h.wr_ptr())
}
Expand Down
10 changes: 5 additions & 5 deletions src/servo/gfx/renderer.rs
@@ -1,12 +1,12 @@
import platform::osmain;
import geom::*;
import comm::*;
import layout::display_list::*;
import dl = layout::display_list;
import azure::*;
import azure::bindgen::*;

enum msg {
render(display_list),
render(dl::display_list),
exit(comm::chan<()>)
}

Expand All @@ -15,7 +15,7 @@ fn renderer(osmain: chan<osmain::msg>) -> chan<msg> {
listen {|draw_target_ch|
#debug("renderer: beginning rendering loop");
osmain.send(osmain::begin_drawing(draw_target_ch));

loop {
alt po.recv() {
render(display_list) {
Expand All @@ -38,13 +38,13 @@ fn renderer(osmain: chan<osmain::msg>) -> chan<msg> {

fn draw_display_list(
draw_target: AzDrawTargetRef,
display_list: display_list
display_list: dl::display_list
) {
clear(draw_target);

for display_list.each {|item|
let (r, g, b) = alt check item.item_type {
solid_color(r, g, b) { (r, g, b) }
dl::solid_color(r, g, b) { (r, g, b) }
};
let bounds = (*item).bounds;

Expand Down
9 changes: 9 additions & 0 deletions src/servo/layout/base.rs
Expand Up @@ -55,6 +55,15 @@ fn linked_box(n: node) -> @box {
ret b;
}

fn linked_subtree(p: node) -> @box {
let p_box = linked_box(p);
for ntree.each_child(p) { |c|
let c_box = linked_box(c);
btree.add_child(p_box, c_box);
}
ret p_box;
}

fn reflow_block(root: @box, available_width: au) {
// Root here is the root of the reflow, not necessarily the doc as
// a whole.
Expand Down
60 changes: 20 additions & 40 deletions src/servo/layout/layout.rs
Expand Up @@ -8,56 +8,34 @@ them to be rendered
import task::*;
import comm::*;
import gfx::geom;
import gfx::geom::*;
import gfx::renderer;
import dom::base::*;
import display_list::*;
import dom::base::node;
import dom::rcu::scope;
import base::{btree, rd_tree_ops, wr_tree_ops};
import base::{btree, rd_tree_ops, wr_tree_ops, linked_subtree};
import dl = display_list;

enum msg {
build,
build(node),
ping(chan<content::ping>),
exit
}

fn layout(renderer: chan<renderer::msg>) -> chan<msg> {

spawn_listener::<msg> {|po|

let r = rand::rng();

fn layout(to_renderer: chan<renderer::msg>) -> chan<msg> {
spawn_listener::<msg> { |po|
loop {

let s = scope();
let ndiv = s.new_node(nk_div);
let bdiv = base::linked_box(ndiv);

iter::repeat(100u) {||
let node = s.new_node(nk_img(
size(
int_to_au(r.next() as int % 800),
int_to_au(r.next() as int % 200)
)));
s.add_child(ndiv, node);
let b = base::linked_box(node);
btree.add_child(bdiv, b);
}

alt recv(po) {
build {
alt po.recv() {
ping(ch) { ch.send(content::pong); }
exit { break; }
build(node) {
#debug("layout: received layout request");
base::reflow_block(bdiv, int_to_au(800));
let dlist = build_display_list(bdiv);

send(renderer, gfx::renderer::render(dlist));
}
exit {
break;
let box = linked_subtree(node);
base::reflow_block(box, geom::int_to_au(800));
let dlist = build_display_list(box);
to_renderer.send(renderer::render(dlist));
}
}
}
}

}

fn build_display_list(box: @base::box) -> display_list::display_list {
Expand All @@ -71,10 +49,12 @@ fn build_display_list(box: @base::box) -> display_list::display_list {
ret list;
}

fn box_to_display_item(box: @base::box) -> display_item {
fn box_to_display_item(box: @base::box) -> dl::display_item {
let r = rand::rng();
let item = display_item({
item_type: solid_color(r.next() as u8, r.next() as u8, r.next() as u8),
let item = dl::display_item({
item_type: dl::solid_color(r.next() as u8,
r.next() as u8,
r.next() as u8),
bounds: box.bounds
});
#debug("layout: display item: %?", item);
Expand Down
38 changes: 38 additions & 0 deletions src/servo/parser/html_builder.rs
@@ -0,0 +1,38 @@
// Constructs a DOM tree from an incoming token stream.

import dom::rcu::writer_methods;
import dom::base::{methods, rd_tree_ops, wr_tree_ops};
import dom = dom::base;
import parser = parser::html;
import html::token;

fn build_dom(scope: dom::node_scope,
stream: port<token>) -> dom::node {
// The current reference node.
let mut cur = scope.new_node(dom::nk_div);
loop {
let token = stream.recv();
#debug["token=%?", token];
alt token {
parser::to_eof { break; }
parser::to_start_tag(_) {
let new_node = scope.new_node(dom::nk_div);
scope.add_child(cur, new_node);
cur = new_node;
}
parser::to_end_tag(_) {
// TODO: Assert that the closing tag has the right name.
// TODO: Fail more gracefully (i.e. according to the HTML5
// spec) if we close more tags than we open.
cur = scope.get_parent(cur).get();
}
parser::to_text(_) {
// TODO
}
parser::to_doctype {
// TODO: Do something here...
}
}
}
ret cur;
}
1 change: 1 addition & 0 deletions src/servo/servo.rc
Expand Up @@ -35,6 +35,7 @@ mod layout {

mod parser {
mod html;
mod html_builder;
}

mod platform {
Expand Down

0 comments on commit 275185a

Please sign in to comment.