Skip to content

Commit

Permalink
Added the ability to iterate over the layout-box tree in parallel.
Browse files Browse the repository at this point in the history
  • Loading branch information
mmeyerho committed Aug 2, 2012
1 parent f2c9747 commit fa122b2
Show file tree
Hide file tree
Showing 7 changed files with 237 additions and 41 deletions.
81 changes: 73 additions & 8 deletions src/servo/layout/base.rs
Expand Up @@ -4,23 +4,23 @@ import dom::base::{Element, ElementKind, HTMLDivElement, HTMLImageElement, Node,
import dom::base::{NodeKind};
import dom::rcu;
import dom::rcu::ReaderMethods;
import dom::style::Unit;
import gfx::geometry;
import gfx::geometry::{au, zero_size_au};
import geom::point::Point2D;
import geom::rect::Rect;
import geom::size::Size2D;
import image::base::image;
import image::base::{image, load};
import layout::block::block_layout_methods;
import layout::inline::inline_layout_methods;
import util::tree;
import util::color::{Color, css_colors};
import text::text_box;
import style::style::SpecifiedStyle;
import style::style::{SpecifiedStyle, default_style_methods};
import text::text_layout_methods;
import vec::{push, push_all};

import future::future;
import arc::arc;
import arc::{arc, clone};

enum BoxKind {
BlockBox,
Expand All @@ -30,12 +30,35 @@ enum BoxKind {
}

class Appearance {
let mut background_image: option<~future<~arc<~image>>>;
let mut background_image: option<ImageHolder>;
let mut background_color: Color;
let mut width: Unit;
let mut height: Unit;

new() {
new(kind: NodeKind) {
self.background_image = none;
self.background_color = css_colors::black();
self.background_color = kind.default_color();
self.width = kind.default_width();
self.height = kind.default_height();
}

// This will be very unhappy if it is getting run in parallel with
// anything trying to read the background image
fn get_image() -> option<~arc<~image>> {
let mut image = none;

// Do a dance where we swap the ImageHolder out before we can
// get the image out of it because we can't alt over it
// because holder.get_image() is not pure.
if (self.background_image).is_some() {
let mut temp = none;
temp <-> self.background_image;
let holder <- option::unwrap(temp);
image = some(holder.get_image());
self.background_image = some(holder);
}

ret image;
}
}

Expand All @@ -47,11 +70,52 @@ class Box {
let appearance: Appearance;

new(node: Node, kind: BoxKind) {
self.appearance = node.read(|n| Appearance(*n.kind));
self.tree = tree::empty();
self.node = node;
self.kind = kind;
self.bounds = geometry::zero_rect_au();
self.appearance = Appearance();
}
}

#[doc="A class to store image data. The image will be loaded once,
the first time it is requested, and an arc will be stored. Clones of
this arc are given out on demand."]
class ImageHolder {
// Invariant: at least one of url and image is not none, except
// occasionally while get_image is being called
let mut url : option<~str>;
let mut image : option<arc<~image>>;

new(-url : ~str) {
self.url = some(url);
self.image = none;
}

// This function should not be called by two tasks at the same time
fn get_image() -> ~arc<~image> {
// If this is the first time we've called this function, load
// the image and store it for the future
if self.image.is_none() {
assert self.url.is_some();

let mut temp = none;
temp <-> self.url;
let url = option::unwrap(temp);
let image = load(url);

self.image = some(arc(~image));
}

// Temporarily swap out the arc of the image so we can clone
// it without breaking purity, then put it back and return the
// clone. This is not threadsafe.
let mut temp = none;
temp <-> self.image;
let im_arc = option::unwrap(temp);
self.image = some(clone(&im_arc));

ret ~im_arc;
}
}

Expand All @@ -74,6 +138,7 @@ impl NodeTreeReadMethods of tree::ReadMethods<Node> for NTree {
}

enum BTree { BTree }

impl BoxTreeReadMethods of tree::ReadMethods<@Box> for BTree {
fn each_child(node: @Box, f: fn(&&@Box) -> bool) {
tree::each_child(self, node, f)
Expand Down
27 changes: 17 additions & 10 deletions src/servo/layout/display_list_builder.rs
@@ -1,15 +1,17 @@
export build_display_list;

import base::{Box, TextBox, BTree, BoxTreeReadMethods};
import base::{Box, TextBox, BTree, BoxTreeReadMethods, ImageHolder};
import box_builder::box_builder_methods;
import dl = display_list;
import dom::base::{Text, NodeScope};
import dom::rcu::Scope;
import either::{left, right};
import geom::point::Point2D;
import geom::rect::Rect;
import geom::size::Size2D;
import gfx::geometry::{au, au_to_px, box, px_to_au};
import gfx::renderer;
import image::base::load;
import text::text_layout_methods;
import util::color::methods;
import util::tree;
Expand Down Expand Up @@ -70,8 +72,8 @@ fn box_to_display_items(list: dl::display_list, box: @Box, origin: Point2D<au>)
let bounds = Rect(origin, copy box.bounds.size);
let col = box.appearance.background_color;

alt (box.kind, copy box.appearance.background_image) {
(TextBox(subbox), _) {
alt box.kind {
TextBox(subbox) {
let run = copy subbox.run;
assert run.is_some();
list.push(dl::display_item({
Expand All @@ -82,24 +84,29 @@ fn box_to_display_items(list: dl::display_list, box: @Box, origin: Point2D<au>)
item_type: dl::display_item_text(run.get()),
bounds: bounds
}));
ret;
}
(_, some(image)) {
_ {
// Fall through
}
};

// Check if there is a background image, if not set the background color.
let image = box.appearance.get_image();

if image.is_some() {
let display_item = dl::display_item({
item_type: do future::with(*image) |image| {
dl::display_item_image(~arc::clone(&*image))
},
item_type: dl::display_item_image(option::unwrap(image)),
bounds: bounds
});
list.push(display_item);
}
(_, none) {
} else {
#debug("Assigning color %? to box with bounds %?", col, bounds);
let col = box.appearance.background_color;
list.push(dl::display_item({
item_type: dl::display_item_solid_color(col.red, col.green, col.blue),
bounds: bounds
}));
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/servo/layout/layout_task.rs
Expand Up @@ -48,7 +48,7 @@ fn Layout(renderer: Renderer) -> Layout {
let this_box = node.construct_boxes();
this_box.dump();

this_box.apply_style_for_subtree();
this_box.apply_css_style();
this_box.reflow(px_to_au(800));

let dlist = build_display_list(this_box);
Expand Down
37 changes: 16 additions & 21 deletions src/servo/layout/style/apply.rs
Expand Up @@ -2,23 +2,25 @@

import dom::base::{Element, HTMLImageElement, Node};
import dom::rcu::ReaderMethods;
import either::right;
import image::base::load;
import base::{Box, BTree, NTree, LayoutData, BoxTreeReadMethods, SpecifiedStyle};
import base::{Box, BTree, NTree, LayoutData, BoxTreeReadMethods, SpecifiedStyle, ImageHolder};
import style::{default_style_methods, style_methods};

import future_spawn = future::spawn;
import traverse::top_down_traversal;

trait ApplyStyleBoxMethods {
fn apply_style_for_subtree();
fn apply_css_style();
fn apply_style();
}

#[doc="A wrapper so the function can be passed around by name."]
fn apply_style_wrapper(box : @Box) {
box.apply_style();
}

impl ApplyStyleBoxMethods of ApplyStyleBoxMethods for @Box {
fn apply_style_for_subtree() {
self.apply_style();
for BTree.each_child(self) |child| {
child.apply_style_for_subtree();
}
fn apply_css_style() {
top_down_traversal(self, apply_style_wrapper);
}

#[doc="Applies CSS style to a layout box.
Expand All @@ -42,19 +44,13 @@ impl ApplyStyleBoxMethods of ApplyStyleBoxMethods for @Box {

alt element.kind {
~HTMLImageElement(*) {
alt element.get_attr(~"src") {
some(url) {
let url = element.get_attr(~"src");

if url.is_some() {
// FIXME: Some sort of BASE HREF support!
// FIXME: Parse URLs!
#debug("loading image from %s", url);
self.appearance.background_image = some(~do future_spawn |copy url| {
~arc::arc(~load(url))
});
}
none {
/* Ignore. */
}
}
self.appearance.background_image = some(ImageHolder(option::unwrap(url)))
};
}
_ { /* Ignore. */ }
}
Expand All @@ -64,4 +60,3 @@ impl ApplyStyleBoxMethods of ApplyStyleBoxMethods for @Box {
}
}
}

12 changes: 11 additions & 1 deletion src/servo/layout/style/style.rs
Expand Up @@ -2,7 +2,7 @@

import arc::{arc, get, clone};

import dom::style::{DisplayType, DisBlock, DisInline, DisNone, Stylesheet, Unit};
import dom::style::{DisplayType, DisBlock, DisInline, DisNone, Stylesheet, Unit, Auto};
import dom::base::{Element, HTMLDivElement, HTMLHeadElement, HTMLImageElement, Node, NodeKind};
import dom::base::{Text};
import dom::rcu::ReaderMethods;
Expand All @@ -22,6 +22,8 @@ type SpecifiedStyle = {mut background_color : option<Color>,
trait default_style_methods {
fn default_color() -> Color;
fn default_display_type() -> DisplayType;
fn default_width() -> Unit;
fn default_height() -> Unit;
}

#[doc="Default stylesfor various attributes in case they don't get initialized from css selectors"]
Expand Down Expand Up @@ -49,6 +51,14 @@ impl default_style_methods of default_style_methods for NodeKind {
}
}
}

fn default_width() -> Unit {
Auto
}

fn default_height() -> Unit {
Auto
}
}

#[doc="Create a specified style that can be used to initialize a node before selector matching.
Expand Down

0 comments on commit fa122b2

Please sign in to comment.