Thread RenderContext and LayoutContext throughout computations needing task assets, such as document URL, font cache, or image cache.

This commit is contained in:
Brian J. Burg 2012-09-17 17:24:10 -07:00
parent bcdc2ac597
commit 972791bb9f
18 changed files with 221 additions and 212 deletions

View file

@ -1,7 +1,8 @@
#[doc="Applies the appropriate CSS style to boxes."]
use au = gfx::geometry;
use layout::base::{Box, SpecifiedStyle};
use layout::base::{Box, SpecifiedStyle, BoxTree};
use layout::context::LayoutContext;
use layout::traverse_parallel::top_down_traversal;
use image::ImageHolder;
use resource::image_cache_task::ImageCacheTask;
@ -32,35 +33,29 @@ impl CSSValue<CSSFontSize> : ResolveMethods<CSSFontSize> {
struct StyleApplicator {
box: @Box,
doc_url: &Url,
image_cache_task: ImageCacheTask,
reflow: fn~(),
}
// TODO: normalize this into a normal preorder tree traversal function
fn apply_style(box: @Box, doc_url: &Url, image_cache_task: ImageCacheTask, reflow: fn~()) {
fn apply_style(layout_ctx: &LayoutContext, box: @Box, reflow: fn~()) {
let applicator = StyleApplicator {
box: box,
doc_url: doc_url,
image_cache_task: image_cache_task,
reflow: reflow
};
applicator.apply_css_style();
applicator.apply_css_style(layout_ctx);
}
// TODO: this is misleadingly-named. It is actually trying to resolve CSS 'inherit' values.
#[doc="A wrapper around a set of functions that can be applied as a top-down traversal of layout
boxes."]
fn inheritance_wrapper(box : @Box, doc_url: &Url, image_cache_task: ImageCacheTask, reflow: fn~()) {
fn inheritance_wrapper(layout_ctx: &LayoutContext, box : @Box, reflow: fn~()) {
let applicator = StyleApplicator {
box: box,
doc_url: doc_url,
image_cache_task: image_cache_task,
reflow: reflow
};
applicator.apply_style();
applicator.apply_style(layout_ctx);
}
/*
@ -104,12 +99,11 @@ fn resolve_width(box : @Box) {
}*/
impl StyleApplicator {
fn apply_css_style() {
let doc_url = copy *self.doc_url;
let image_cache_task = self.image_cache_task;
fn apply_css_style(layout_ctx: &LayoutContext) {
let reflow = copy self.reflow;
do top_down_traversal(self.box) |box, move doc_url| {
inheritance_wrapper(box, &doc_url, image_cache_task, reflow);
do BoxTree.each_child(self.box) |child| {
inheritance_wrapper(layout_ctx, child, reflow); true
}
}
@ -120,7 +114,7 @@ impl StyleApplicator {
value for the given type of element and use that instead.
"]
fn apply_style() {
fn apply_style(layout_ctx: &LayoutContext) {
// Right now, we only handle images.
do self.box.node.read |node| {
@ -133,8 +127,8 @@ impl StyleApplicator {
if url.is_some() {
// FIXME: Some sort of BASE HREF support!
// FIXME: Parse URLs!
let new_url = make_url(option::unwrap(url), Some(copy *self.doc_url));
self.box.data.background_image = Some(ImageHolder(new_url, self.image_cache_task, self.reflow))
let new_url = make_url(option::unwrap(url), Some(copy layout_ctx.doc_url));
self.box.data.background_image = Some(ImageHolder(new_url, layout_ctx.image_cache, self.reflow))
};
}
_ => { /* Ignore. */ }

View file

@ -10,6 +10,7 @@ use dom::base::{LayoutData};
use util::color::{Color, rgb};
use util::color::css_colors::{white, black};
use dom::base::NodeTree;
use layout::context::LayoutContext;
type SpecifiedStyle = {mut background_color : CSSValue<CSSBackgroundColor>,
mut display_type : CSSValue<CSSDisplay>,
@ -114,7 +115,7 @@ impl Node : StylePriv {
trait StyleMethods {
fn initialize_style_for_subtree() -> ~[@LayoutData];
fn style() -> SpecifiedStyle;
fn recompute_style_for_subtree(styles : ARC<Stylesheet>);
fn recompute_style_for_subtree(ctx: &LayoutContext, styles : ARC<Stylesheet>);
}
impl Node : StyleMethods {
@ -145,31 +146,20 @@ impl Node : StyleMethods {
#[doc="
Performs CSS selector matching on a subtree.
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 : ARC<Stylesheet>) {
listen(|ack_chan| {
let mut i = 0u;
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(ctx: &LayoutContext, styles : ARC<Stylesheet>) {
let mut i = 0u;
// Compute the styles of each of our children in parallel
for NodeTree.each_child(self) |kid| {
i = i + 1u;
let new_styles = clone(&styles);
// Compute the styles of each of our children in parallel
for NodeTree.each_child(self) |kid| {
i = i + 1u;
let new_styles = clone(&styles);
task::spawn(|| {
kid.recompute_style_for_subtree(new_styles);
ack_chan.send(());
})
}
kid.recompute_style_for_subtree(ctx, new_styles);
}
self.match_css_style(*get(&styles));
// Make sure we have finished updating the tree before returning
while i > 0 {
ack_chan.recv();
i = i - 1u;
}
})
self.match_css_style(*get(&styles));
}
}

View file

@ -3,13 +3,14 @@ use gfx::render_task::{draw_solid_color, draw_image, draw_glyphs};
use gfx::geometry::*;
use geom::rect::Rect;
use image::base::Image;
use render_task::RenderContext;
use std::arc::{ARC, clone};
use dvec::DVec;
use text::glyph::Glyph;
struct DisplayItem {
draw: ~fn((&DisplayItem), (&DrawTarget)),
draw: ~fn((&DisplayItem), (&RenderContext)),
bounds : Rect<au>, // TODO: whose coordinate system should this use?
data : DisplayItemData
}
@ -30,21 +31,21 @@ struct GlyphRun {
glyphs: ~[Glyph]
}
fn draw_SolidColor(self: &DisplayItem, ctx: &DrawTarget) {
fn draw_SolidColor(self: &DisplayItem, ctx: &RenderContext) {
match self.data {
SolidColorData(r,g,b) => draw_solid_color(ctx, &self.bounds, r, g, b),
_ => fail
}
}
fn draw_Glyphs(self: &DisplayItem, ctx: &DrawTarget) {
fn draw_Glyphs(self: &DisplayItem, ctx: &RenderContext) {
match self.data {
GlyphData(run) => draw_glyphs(ctx, self.bounds, &run),
_ => fail
}
}
fn draw_Image(self: &DisplayItem, ctx: &DrawTarget) {
fn draw_Image(self: &DisplayItem, ctx: &RenderContext) {
match self.data {
ImageData(img) => draw_image(ctx, self.bounds, img),
_ => fail
@ -81,11 +82,11 @@ fn Image(bounds: Rect<au>, image: ARC<~image::base::Image>) -> DisplayItem {
type DisplayList = DVec<~DisplayItem>;
trait DisplayListMethods {
fn draw(ctx: &DrawTarget);
fn draw(ctx: &RenderContext);
}
impl DisplayList : DisplayListMethods {
fn draw(ctx: &DrawTarget) {
fn draw(ctx: &RenderContext) {
for self.each |item| {
#debug["drawing %?", item];
item.draw(item, ctx);

View file

@ -19,6 +19,7 @@ use std::arc::ARC;
use azure::cairo::{cairo_font_face_t, cairo_scaled_font_t};
use std::cell::Cell;
use compositor::Compositor;
use servo_text::font_cache::FontCache;
use pipes::{Port, Chan};
@ -29,6 +30,11 @@ pub enum Msg {
ExitMsg(pipes::Chan<()>)
}
struct RenderContext {
canvas: &DrawTarget,
font_cache: @FontCache,
}
type RenderTask = comm::Chan<Msg>;
fn RenderTask<C: Compositor Send>(+compositor: C) -> RenderTask {
@ -37,6 +43,8 @@ fn RenderTask<C: Compositor Send>(+compositor: C) -> RenderTask {
let mut draw_target_ch = draw_target_ch;
let mut draw_target_po = draw_target_po;
let font_cache = FontCache();
debug!("renderer: beginning rendering loop");
compositor.begin_drawing(draw_target_ch);
@ -56,8 +64,13 @@ fn RenderTask<C: Compositor Send>(+compositor: C) -> RenderTask {
let draw_target_ch = option::unwrap(draw_target_ch);
do draw_target.with_ref |draw_target| {
clear(draw_target);
display_list.draw(draw_target)
let ctx = RenderContext {
canvas: draw_target,
font_cache: font_cache
};
clear(&ctx);
display_list.draw(&ctx)
}
#debug("renderer: returning surface");
@ -94,37 +107,37 @@ impl Rect<au> : ToAzureRect {
}
}
pub fn draw_solid_color(draw_target: &DrawTarget, bounds: &Rect<au>, r: u8, g: u8, b: u8) {
pub fn draw_solid_color(ctx: &RenderContext, bounds: &Rect<au>, r: u8, g: u8, b: u8) {
let color = Color(r.to_float() as AzFloat,
g.to_float() as AzFloat,
b.to_float() as AzFloat,
1f as AzFloat);
draw_target.fill_rect(bounds.to_azure_rect(), ColorPattern(color));
ctx.canvas.fill_rect(bounds.to_azure_rect(), ColorPattern(color));
}
pub fn draw_image(draw_target: &DrawTarget, bounds: Rect<au>, image: ARC<~Image>) {
pub fn draw_image(ctx: &RenderContext, bounds: Rect<au>, image: ARC<~Image>) {
let image = std::arc::get(&image);
let size = Size2D(image.width as i32, image.height as i32);
let stride = image.width * 4;
let azure_surface = draw_target.create_source_surface_from_data(image.data, size, stride as i32,
let azure_surface = ctx.canvas.create_source_surface_from_data(image.data, size, stride as i32,
B8G8R8A8);
let source_rect = Rect(Point2D(0 as AzFloat, 0 as AzFloat),
Size2D(image.width as AzFloat, image.height as AzFloat));
let dest_rect = bounds.to_azure_rect();
let draw_surface_options = DrawSurfaceOptions(Linear, true);
let draw_options = DrawOptions(1.0f as AzFloat, 0);
draw_target.draw_surface(azure_surface, dest_rect, source_rect, draw_surface_options,
ctx.canvas.draw_surface(azure_surface, dest_rect, source_rect, draw_surface_options,
draw_options);
}
pub fn draw_glyphs(draw_target: &DrawTarget, bounds: Rect<au>, text_run: &GlyphRun) {
pub fn draw_glyphs(ctx: &RenderContext, bounds: Rect<au>, text_run: &GlyphRun) {
use ptr::{addr_of, null};
use vec::raw::to_ptr;
use libc::types::common::c99::{uint16_t, uint32_t};
use geom::point::Point2D;
use text::font_library::FontLibrary;
use text::font_cache::FontCache;
use text::font::Font;
use azure::{AzNativeFont, AzFloat, AZ_NATIVE_FONT_CAIRO_FONT_FACE};
use azure::bindgen::{AzCreateScaledFontWithCairo,
@ -133,10 +146,10 @@ pub fn draw_glyphs(draw_target: &DrawTarget, bounds: Rect<au>, text_run: &GlyphR
AzReleaseColorPattern};
use azure::cairo::bindgen::cairo_scaled_font_destroy;
let draw_target = draw_target.azure_draw_target;
let draw_target = ctx.canvas.azure_draw_target;
// FIXME: The font library should not be created here
let flib = FontLibrary();
let flib = FontCache();
let font = flib.get_test_font();
let nfont: AzNativeFont = {
@ -182,7 +195,8 @@ pub fn draw_glyphs(draw_target: &DrawTarget, bounds: Rect<au>, text_run: &GlyphR
mNumGlyphs: azglyphs.len() as uint32_t
}};
AzDrawTargetFillGlyphs(draw_target, azfont, addr_of(glyphbuf),
// TODO: this call needs to move into azure_hl.rs
AzDrawTargetFillGlyphs(ctx.canvas.azure_draw_target, azfont, addr_of(glyphbuf),
pattern, addr_of(options), null());
AzReleaseColorPattern(pattern);
@ -249,8 +263,8 @@ fn get_cairo_font(font: &Font) -> *cairo_scaled_font_t {
return cfont;
}
fn clear(draw_target: &DrawTarget) {
fn clear(ctx: &RenderContext) {
let pattern = ColorPattern(Color(1f as AzFloat, 1f as AzFloat, 1f as AzFloat, 1f as AzFloat));
let rect = Rect(Point2D(0 as AzFloat, 0 as AzFloat), Size2D(800 as AzFloat, 600 as AzFloat));
draw_target.fill_rect(rect, pattern);
ctx.canvas.fill_rect(rect, pattern);
}

View file

@ -14,6 +14,7 @@ use geom::size::Size2D;
use gfx::geometry::au;
use image::{Image, ImageHolder};
use layout::block::BlockFlowData;
use layout::context::LayoutContext;
use layout::debug::DebugMethods;
use layout::inline::InlineFlowData;
use layout::root::RootFlowData;
@ -85,29 +86,29 @@ impl @FlowContext : cmp::Eq {
}
impl @FlowContext {
fn bubble_widths() {
fn bubble_widths(ctx: &LayoutContext) {
match self.kind {
BlockFlow(*) => self.bubble_widths_block(),
InlineFlow(*) => self.bubble_widths_inline(),
RootFlow(*) => self.bubble_widths_root(),
BlockFlow(*) => self.bubble_widths_block(ctx),
InlineFlow(*) => self.bubble_widths_inline(ctx),
RootFlow(*) => self.bubble_widths_root(ctx),
_ => fail fmt!("Tried to bubble_widths of flow: %?", self.kind)
}
}
fn assign_widths() {
fn assign_widths(ctx: &LayoutContext) {
match self.kind {
BlockFlow(*) => self.assign_widths_block(),
InlineFlow(*) => self.assign_widths_inline(),
RootFlow(*) => self.assign_widths_root(),
BlockFlow(*) => self.assign_widths_block(ctx),
InlineFlow(*) => self.assign_widths_inline(ctx),
RootFlow(*) => self.assign_widths_root(ctx),
_ => fail fmt!("Tried to assign_widths of flow: %?", self.kind)
}
}
fn assign_height() {
fn assign_height(ctx: &LayoutContext) {
match self.kind {
BlockFlow(*) => self.assign_height_block(),
InlineFlow(*) => self.assign_height_inline(),
RootFlow(*) => self.assign_height_root(),
BlockFlow(*) => self.assign_height_block(ctx),
InlineFlow(*) => self.assign_height_inline(ctx),
RootFlow(*) => self.assign_height_root(ctx),
_ => fail fmt!("Tried to assign_height of flow: %?", self.kind)
}
}
@ -224,9 +225,7 @@ impl @Box {
// how to compute its own min and pref widths, and should
// probably cache them.
TextBox(d) => d.runs.foldl(au(0), |sum, run| {
let ret = au::max(sum, run.min_break_width());
debug!("text min width: %?px", au::to_px(ret));
ret
au::max(sum, run.min_break_width())
})
}
}
@ -248,9 +247,7 @@ impl @Box {
// how to compute its own min and pref widths, and should
// probably cache them.
TextBox(d) => d.runs.foldl(au(0), |sum, run| {
let ret = au::max(sum, run.size().width);
debug!("text pref width: %?px", au::to_px(ret));
ret
au::max(sum, run.size().width)
})
}
}

View file

@ -4,6 +4,7 @@ use geom::point::Point2D;
use geom::size::Size2D;
use gfx::geometry::au;
use layout::base::{Box, FlowContext, FlowTree, InlineBlockFlow, BlockFlow, RootFlow};
use layout::context::LayoutContext;
use util::tree;
struct BlockFlowData {
@ -21,9 +22,9 @@ trait BlockLayout {
pure fn access_block<T>(fn(&&BlockFlowData) -> T) -> T;
pure fn with_block_box(fn(&&@Box) -> ()) -> ();
fn bubble_widths_block();
fn assign_widths_block();
fn assign_height_block();
fn bubble_widths_block(ctx: &LayoutContext);
fn assign_widths_block(ctx: &LayoutContext);
fn assign_height_block(ctx: &LayoutContext);
}
impl @FlowContext : BlockLayout {
@ -71,7 +72,7 @@ impl @FlowContext : BlockLayout {
/* TODO: floats */
/* TODO: absolute contexts */
/* TODO: inline-blocks */
fn bubble_widths_block() {
fn bubble_widths_block(ctx: &LayoutContext) {
assert self.starts_block_flow();
let mut min_width = au(0);
@ -103,7 +104,7 @@ impl @FlowContext : BlockLayout {
Dual boxes consume some width first, and the remainder is assigned to
all child (block) contexts. */
fn assign_widths_block() {
fn assign_widths_block(ctx: &LayoutContext) {
assert self.starts_block_flow();
let mut remaining_width = self.data.position.size.width;
@ -125,7 +126,7 @@ impl @FlowContext : BlockLayout {
}
}
fn assign_height_block() {
fn assign_height_block(ctx: &LayoutContext) {
assert self.starts_block_flow();
let mut cur_y = au(0);

View file

@ -8,13 +8,14 @@ use dom::base::{Element, Text, Node, Doctype, Comment, NodeTree};
use layout::base::{Box, BoxData, GenericBox, ImageBox, TextBox, BoxTree};
use layout::base::{FlowContext, FlowContextData, BlockFlow, InlineFlow, InlineBlockFlow, RootFlow, FlowTree};
use layout::block::BlockFlowData;
use layout::context::LayoutContext;
use layout::inline::InlineFlowData;
use layout::root::RootFlowData;
use layout::text::TextBoxData;
use option::is_none;
use util::tree;
use servo_text::text_run::TextRun;
use servo_text::font_library::FontLibrary;
use servo_text::font_cache::FontCache;
export LayoutTreeBuilder;
@ -41,7 +42,7 @@ impl LayoutTreeBuilder {
/** Creates necessary box(es) and flow context(s) for the current DOM node,
and recurses on its children. */
fn construct_recursively(cur_node: Node, parent_ctx: @FlowContext, parent_box: @Box) {
fn construct_recursively(layout_ctx: &LayoutContext, cur_node: Node, parent_ctx: @FlowContext, parent_box: @Box) {
let style = cur_node.style();
// DEBUG
@ -60,7 +61,7 @@ impl LayoutTreeBuilder {
};
// first, create the proper box kind, based on node characteristics
let box_data = match cur_node.create_box_data(display) {
let box_data = match cur_node.create_box_data(layout_ctx, display) {
None => return,
Some(data) => data
};
@ -116,7 +117,7 @@ impl LayoutTreeBuilder {
}
// recurse
do NodeTree.each_child(cur_node) |child_node| {
self.construct_recursively(child_node, next_ctx, new_box); true
self.construct_recursively(layout_ctx, child_node, next_ctx, new_box); true
}
// Fixup any irregularities, such as split inlines (CSS 2.1 Section 9.2.1.1)
@ -145,11 +146,11 @@ impl LayoutTreeBuilder {
/** entry point for box creation. Should only be
called on root DOM element. */
fn construct_trees(root: Node) -> Result<@Box, ()> {
fn construct_trees(layout_ctx: &LayoutContext, root: Node) -> Result<@Box, ()> {
self.root_ctx = Some(self.make_ctx(RootFlow(RootFlowData()), tree::empty()));
self.root_box = Some(self.make_box(root, self.root_ctx.get(), GenericBox));
self.construct_recursively(root, self.root_ctx.get(), self.root_box.get());
self.construct_recursively(layout_ctx, root, self.root_ctx.get(), self.root_box.get());
return Ok(self.root_box.get())
}
@ -167,18 +168,17 @@ impl LayoutTreeBuilder {
}
trait PrivateBuilderMethods {
fn create_box_data(display: CSSDisplay) -> Option<BoxData>;
fn create_box_data(layout_ctx: &LayoutContext, display: CSSDisplay) -> Option<BoxData>;
}
impl Node : PrivateBuilderMethods {
fn create_box_data(display: CSSDisplay) -> Option<BoxData> {
fn create_box_data(layout_ctx: &LayoutContext, display: CSSDisplay) -> Option<BoxData> {
do self.read |node| {
match node.kind {
~Doctype(*) | ~Comment(*) => None,
~Text(string) => {
// TODO: clean this up. Fonts should not be created here.
let flib = FontLibrary();
let font = flib.get_test_font();
let font = layout_ctx.font_cache.get_test_font();
let run = TextRun(font, string);
Some(TextBox(TextBoxData(copy string, ~[move run])))
}

View file

@ -6,6 +6,7 @@ use dom::rcu;
use geom::point::Point2D;
use geom::size::Size2D;
use gfx::geometry::au;
use layout::context::LayoutContext;
use layout::base::{FlowContext, InlineFlow, BoxTree, ImageBox, TextBox, GenericBox};
use num::Num;
use util::tree;
@ -24,9 +25,9 @@ trait InlineLayout {
pure fn starts_inline_flow() -> bool;
pure fn access_inline<T>(fn(&&InlineFlowData) -> T) -> T;
fn bubble_widths_inline();
fn assign_widths_inline();
fn assign_height_inline();
fn bubble_widths_inline(ctx: &LayoutContext);
fn assign_widths_inline(ctx: &LayoutContext);
fn assign_height_inline(ctx: &LayoutContext);
}
impl @FlowContext : InlineLayout {
@ -39,7 +40,7 @@ impl @FlowContext : InlineLayout {
}
}
fn bubble_widths_inline() {
fn bubble_widths_inline(ctx: &LayoutContext) {
assert self.starts_inline_flow();
let mut min_width = au(0);
@ -66,7 +67,7 @@ impl @FlowContext : InlineLayout {
/* Recursively (top-down) determines the actual width of child
contexts and boxes. When called on this context, the context has
had its width set by the parent context. */
fn assign_widths_inline() {
fn assign_widths_inline(ctx: &LayoutContext) {
assert self.starts_inline_flow();
/* Perform inline flow with the available width. */
@ -117,7 +118,7 @@ impl @FlowContext : InlineLayout {
} // fn assign_widths_inline
fn assign_height_inline() {
fn assign_height_inline(ctx: &LayoutContext) {
// Don't need to set box or ctx heights, since that is done
// during inline flowing.
}

View file

@ -13,10 +13,12 @@ use dom::event::{Event, ReflowEvent};
use gfx::render_task;
use layout::base::Box;
use layout::box_builder::LayoutTreeBuilder;
use layout::context::LayoutContext;
use render_task::RenderTask;
use resource::image_cache_task::ImageCacheTask;
use std::arc::ARC;
use std::net::url::Url;
use servo_text::font_cache::FontCache;
use layout::traverse::*;
use comm::*;
@ -35,52 +37,61 @@ fn LayoutTask(render_task: RenderTask, image_cache_task: ImageCacheTask) -> Layo
// This just keeps our dom aux objects alive
let mut layout_data_refs = ~[];
let font_cache = FontCache();
loop {
match request.recv() {
PingMsg(ping_channel) => ping_channel.send(content_task::PongMsg),
ExitMsg => {
debug!("layout: ExitMsg received");
break;
}
BuildMsg(node, styles, doc_url, event_chan) => {
debug!("layout: received layout request for: %s", doc_url.to_str());
debug!("layout: parsed Node tree");
node.dump();
do util::time::time(~"layout") {
layout_data_refs += node.initialize_style_for_subtree();
node.recompute_style_for_subtree(styles);
let root_box: @Box;
let builder = LayoutTreeBuilder();
match builder.construct_trees(node) {
Ok(root) => root_box = root,
Err(*) => fail ~"Root node should always exist"
}
debug!("layout: constructed Box tree");
root_box.dump();
debug!("layout: constructed Flow tree");
root_box.ctx.dump();
/* resolve styles (convert relative values) down the box tree */
let reflow_cb: fn~() = || event_chan.send(ReflowEvent);
apply_style(root_box, &doc_url, image_cache_task, reflow_cb);
/* perform layout passes over the flow tree */
let root_flow = root_box.ctx;
do root_flow.traverse_postorder |f| { f.bubble_widths() }
root_flow.data.position.origin = au::zero_point();
root_flow.data.position.size.width = au::from_px(800); // TODO: window/frame size
do root_flow.traverse_preorder |f| { f.assign_widths() }
do root_flow.traverse_postorder |f| { f.assign_height() }
let dlist = build_display_list(root_box);
render_task.send(render_task::RenderMsg(dlist));
PingMsg(ping_channel) => ping_channel.send(content_task::PongMsg),
ExitMsg => {
debug!("layout: ExitMsg received");
break;
}
BuildMsg(node, styles, doc_url, event_chan) => {
debug!("layout: received layout request for: %s", doc_url.to_str());
debug!("layout: parsed Node tree");
node.dump();
let layout_ctx = LayoutContext {
image_cache: image_cache_task,
font_cache: font_cache,
doc_url: doc_url,
};
do util::time::time(~"layout") {
layout_data_refs += node.initialize_style_for_subtree();
node.recompute_style_for_subtree(&layout_ctx, styles);
let root_box: @Box;
let builder = LayoutTreeBuilder();
match builder.construct_trees(&layout_ctx, node) {
Ok(root) => root_box = root,
Err(*) => fail ~"Root node should always exist"
}
debug!("layout: constructed Box tree");
root_box.dump();
debug!("layout: constructed Flow tree");
root_box.ctx.dump();
/* resolve styles (convert relative values) down the box tree */
let reflow_cb: fn~() = || event_chan.send(ReflowEvent);
apply_style(&layout_ctx, root_box, reflow_cb);
/* perform layout passes over the flow tree */
let root_flow = root_box.ctx;
do root_flow.traverse_postorder |f| { f.bubble_widths(&layout_ctx) }
// TODO: window/frame size should be set inside RootBox::assign_widths
root_flow.data.position.origin = au::zero_point();
root_flow.data.position.size.width = au::from_px(800);
// end TODO
do root_flow.traverse_preorder |f| { f.assign_widths(&layout_ctx) }
do root_flow.traverse_postorder |f| { f.assign_height(&layout_ctx) }
let dlist = build_display_list(root_box);
render_task.send(render_task::RenderMsg(dlist));
}
}
}
}
}
}

View file

@ -4,6 +4,7 @@ use geom::point::Point2D;
use geom::size::Size2D;
use gfx::geometry::au;
use layout::base::{Box, FlowContext, FlowTree, InlineBlockFlow, BlockFlow, RootFlow};
use layout::context::LayoutContext;
use util::tree;
struct RootFlowData {
@ -20,9 +21,9 @@ trait RootLayout {
pure fn starts_root_flow() -> bool;
pure fn access_root<T>(fn(&&RootFlowData) -> T) -> T;
fn bubble_widths_root();
fn assign_widths_root();
fn assign_height_root();
fn bubble_widths_root(ctx: &LayoutContext);
fn assign_widths_root(ctx: &LayoutContext);
fn assign_height_root(ctx: &LayoutContext);
}
impl @FlowContext : RootLayout {
@ -42,21 +43,21 @@ impl @FlowContext : RootLayout {
}
/* defer to the block algorithm */
fn bubble_widths_root() {
fn bubble_widths_root(ctx: &LayoutContext) {
assert self.starts_root_flow();
self.bubble_widths_block()
self.bubble_widths_block(ctx)
}
fn assign_widths_root() {
fn assign_widths_root(ctx: &LayoutContext) {
assert self.starts_root_flow();
/* TODO: should determine frame width here, not in
LayoutTask. Until then, defer to block. */
self.assign_widths_block() }
self.assign_widths_block(ctx) }
fn assign_height_root() {
fn assign_height_root(ctx: &LayoutContext) {
assert self.starts_root_flow();
self.assign_height_block();
self.assign_height_block(ctx);
}
}

View file

@ -4,8 +4,9 @@ use au = gfx::geometry;
use geom::size::Size2D;
use gfx::geometry::au;
use servo_text::text_run::TextRun;
use servo_text::font_library::FontLibrary;
use servo_text::font_cache::FontCache;
use layout::base::{TextBox, Box};
use layout::context::LayoutContext;
struct TextBoxData {
text: ~str,
@ -20,20 +21,18 @@ fn TextBoxData(text: ~str, runs: ~[TextRun]) -> TextBoxData {
}
trait TextLayout {
fn reflow_text();
fn reflow_text(ctx: &LayoutContext);
}
#[doc="The main reflow routine for text layout."]
impl @Box : TextLayout {
fn reflow_text() {
fn reflow_text(ctx: &LayoutContext) {
let d = match self.kind {
TextBox(d) => { d }
_ => { fail ~"expected text box in reflow_text!" }
};
// FIXME: The font library should not be initialized here
let flib = FontLibrary();
let font = flib.get_test_font();
let font = ctx.font_cache.get_test_font();
// Do line breaking.
let mut current = TextRun(font, d.text);

View file

@ -4,28 +4,28 @@ use layout::base::{Box, BoxTree};
use layout::base::{FlowContext, FlowTree};
trait BoxTraversals {
fn traverse_preorder(preorder_cb: ~fn(@Box));
fn traverse_preorder(preorder_cb: &fn(@Box));
}
impl @Box : BoxTraversals {
fn traverse_preorder(preorder_cb: ~fn(@Box)) {
fn traverse_preorder(preorder_cb: &fn(@Box)) {
preorder_cb(self);
do BoxTree.each_child(self) |child| { child.traverse_preorder(preorder_cb); true }
}
}
trait FlowContextTraversals {
fn traverse_preorder(preorder_cb: ~fn(@FlowContext));
fn traverse_postorder(postorder_cb: ~fn(@FlowContext));
fn traverse_preorder(preorder_cb: &fn(@FlowContext));
fn traverse_postorder(postorder_cb: &fn(@FlowContext));
}
impl @FlowContext : FlowContextTraversals {
fn traverse_preorder(preorder_cb: ~fn(@FlowContext)) {
fn traverse_preorder(preorder_cb: &fn(@FlowContext)) {
preorder_cb(self);
do FlowTree.each_child(self) |child| { child.traverse_preorder(preorder_cb); true }
}
fn traverse_postorder(postorder_cb: ~fn(@FlowContext)) {
fn traverse_postorder(postorder_cb: &fn(@FlowContext)) {
do FlowTree.each_child(self) |child| { child.traverse_postorder(postorder_cb); true }
postorder_cb(self);
}

View file

@ -55,6 +55,7 @@ mod layout {
mod base;
mod block;
mod box_builder;
mod context;
mod debug;
mod display_list_builder;
mod inline;
@ -97,12 +98,12 @@ mod platform {
mod text {
export glyph;
export text_run;
export font_library;
export font;
export font_cache;
export shaper;
mod font;
mod font_library;
mod font_cache;
mod glyph;
mod native_font {
#[cfg(target_os = "macos")]

View file

@ -1,3 +1,4 @@
pub use font_cache::FontCache;
export Font, FontMetrics, test_font_bin, create_test_font;
use glyph::GlyphIndex;
@ -5,7 +6,6 @@ use vec_to_ptr = vec::raw::to_ptr;
use libc::{ c_int, c_double, c_ulong };
use ptr::{ null, addr_of };
use native_font::NativeFont;
use font_library::FontLibrary;
#[doc = "
A font handle. Layout can use this to calculate glyph metrics
@ -13,7 +13,7 @@ and the renderer can use it to render text.
"]
struct Font {
// A back reference to keep the library alive
lib: @FontLibrary,
lib: @FontCache,
fontbuf: @~[u8],
native_font: NativeFont,
metrics: FontMetrics
@ -36,7 +36,7 @@ impl Font {
}
}
fn Font(lib: @FontLibrary, fontbuf: @~[u8], +native_font: NativeFont, +metrics: FontMetrics) -> Font {
fn Font(lib: @FontCache, fontbuf: @~[u8], +native_font: NativeFont, +metrics: FontMetrics) -> Font {
Font {
lib: lib,
fontbuf : fontbuf,
@ -67,7 +67,7 @@ fn should_destruct_on_fail_without_leaking() {
#[test];
#[should_fail];
let lib = FontLibrary();
let lib = FontCache();
let _font = lib.get_test_font();
fail;
}
@ -75,7 +75,7 @@ fn should_destruct_on_fail_without_leaking() {
fn should_get_glyph_indexes() {
#[test];
let lib = FontLibrary();
let lib = FontCache();
let font = lib.get_test_font();
let glyph_idx = font.glyph_index('w');
assert glyph_idx == Some(40u);
@ -84,7 +84,7 @@ fn should_get_glyph_indexes() {
fn should_get_glyph_advance() {
#[test];
let lib = FontLibrary();
let lib = FontCache();
let font = lib.get_test_font();
let x = font.glyph_h_advance(40u);
assert x == 15;
@ -100,7 +100,7 @@ fn should_get_glyph_advance_stress() {
let (chan, port) = pipes::stream();
ports += [@move port];
do task::spawn {
let lib = FontLibrary();
let lib = FontCache();
let font = lib.get_test_font();
let x = font.glyph_h_advance(40u);
assert x == 15;
@ -118,7 +118,7 @@ fn should_be_able_to_create_instances_in_multiple_threads() {
for iter::repeat(10u) {
do task::spawn {
let lib = FontLibrary();
let lib = FontCache();
let _font = lib.get_test_font();
}
}

View file

@ -1,20 +1,19 @@
export FontLibrary, native;
export FontCache, native;
use font::{Font, test_font_bin};
struct FontLibrary {
struct FontCache {
// FIXME: This is a hack to hold onto a boxed reference to
// the self pointer until explicit self types work on methods.
// This is a huge space leak.
mut at_self: Option<@FontLibrary>,
native_lib: native::NativeFontLibrary,
mut at_self: Option<@FontCache>,
native_lib: native::NativeFontCache,
drop {
native::destroy_native_lib(&self.native_lib);
}
}
impl FontLibrary {
impl FontCache {
fn get_font() -> @Font {
assert self.at_self.is_some();
match create_font(self.at_self.get(), &self.native_lib) {
@ -28,8 +27,8 @@ impl FontLibrary {
}
}
fn FontLibrary() -> @FontLibrary {
let lib = @FontLibrary {
fn FontCache() -> @FontCache {
let lib = @FontCache {
mut at_self: None,
native_lib: native::create_native_lib()
};
@ -38,7 +37,7 @@ fn FontLibrary() -> @FontLibrary {
return lib;
}
fn create_font(lib: @FontLibrary, native_lib: &native::NativeFontLibrary) -> Result<@Font, ()> {
fn create_font(lib: @FontCache, native_lib: &native::NativeFontCache) -> Result<@Font, ()> {
let font_bin = @test_font_bin();
let native_font = native_font::create(native_lib, font_bin);
let native_font = if native_font.is_ok() {
@ -57,9 +56,9 @@ mod native {
use freetype::{FT_Library, FT_Error};
use freetype::bindgen::{FT_Init_FreeType, FT_Done_FreeType};
type NativeFontLibrary = FT_Library;
type NativeFontCache = FT_Library;
fn create_native_lib() -> NativeFontLibrary {
fn create_native_lib() -> NativeFontCache {
let lib: FT_Library = null();
let res = FT_Init_FreeType(addr_of(lib));
// FIXME: error handling
@ -67,7 +66,7 @@ mod native {
return lib;
}
fn destroy_native_lib(native_lib: &NativeFontLibrary) {
fn destroy_native_lib(native_lib: &NativeFontCache) {
assert native_lib.is_not_null();
FT_Done_FreeType(*native_lib);
}
@ -75,14 +74,14 @@ mod native {
#[cfg(target_os = "macos")]
mod native {
type NativeFontLibrary = ();
type NativeFontCache = ();
fn create_native_lib() -> NativeFontLibrary { () }
fn destroy_native_lib(_native_lib: &NativeFontLibrary) { }
fn create_native_lib() -> NativeFontCache { () }
fn destroy_native_lib(_native_lib: &NativeFontCache) { }
}
#[test]
fn should_get_fonts() {
let lib = FontLibrary();
let lib = FontCache();
lib.get_font();
}

View file

@ -9,7 +9,7 @@ font resources needed by the graphics layer to draw glyphs.
export NativeFont, create;
use font_library::native::NativeFontLibrary;
use font_cache::native::NativeFontCache;
#[cfg(target_os = "macos")]
type NativeFont/& = quartz_native_font::QuartzNativeFont;
@ -18,12 +18,12 @@ type NativeFont/& = quartz_native_font::QuartzNativeFont;
type NativeFont/& = ft_native_font::FreeTypeNativeFont;
#[cfg(target_os = "macos")]
fn create(_native_lib: &NativeFontLibrary, buf: @~[u8]) -> Result<NativeFont, ()> {
fn create(_native_lib: &NativeFontCache, buf: @~[u8]) -> Result<NativeFont, ()> {
quartz_native_font::create(buf)
}
#[cfg(target_os = "linux")]
fn create(native_lib: &NativeFontLibrary, buf: @~[u8]) -> Result<NativeFont, ()> {
fn create(native_lib: &NativeFontCache, buf: @~[u8]) -> Result<NativeFont, ()> {
ft_native_font::create(native_lib, buf)
}

View file

@ -10,7 +10,7 @@ use glyph::{Glyph, GlyphPos};
use ptr::{null, addr_of, offset};
use gfx::geometry::au;
use geom::point::Point2D;
use font_library::FontLibrary;
use font_cache::FontCache;
use unsafe::reinterpret_cast;
use harfbuzz::{HB_MEMORY_MODE_READONLY,
@ -148,7 +148,7 @@ fn should_get_glyph_indexes() {
#[test];
#[ignore(cfg(target_os = "macos"), reason = "bad metrics")];
let lib = FontLibrary();
let lib = FontCache();
let font = lib.get_test_font();
let glyphs = shape_text(font, ~"firecracker");
let idxs = glyphs.map(|glyph| glyph.index);
@ -159,7 +159,7 @@ fn should_get_glyph_h_advance() {
#[test];
#[ignore(cfg(target_os = "macos"), reason = "bad metrics")];
let lib = FontLibrary();
let lib = FontCache();
let font = lib.get_test_font();
let glyphs = shape_text(font, ~"firecracker");
let actual = glyphs.map(|g| g.pos.advance.x);

View file

@ -3,7 +3,7 @@ use geom::point::Point2D;
use geom::size::Size2D;
use gfx::geometry::au;
use libc::{c_void};
use font_library::FontLibrary;
use font_cache::FontCache;
use font::Font;
use glyph::Glyph;
use shaper::shape_text;
@ -135,7 +135,7 @@ fn iter_indivisible_slices(font: &Font, text: &r/str,
#[test]
fn test_calc_min_break_width1() {
let flib = FontLibrary();
let flib = FontCache();
let font = flib.get_test_font();
let actual = calc_min_break_width(font, ~"firecracker");
let expected = au::from_px(84);
@ -144,7 +144,7 @@ fn test_calc_min_break_width1() {
#[test]
fn test_calc_min_break_width2() {
let flib = FontLibrary();
let flib = FontCache();
let font = flib.get_test_font();
let actual = calc_min_break_width(font, ~"firecracker yumyum");
let expected = au::from_px(84);
@ -153,7 +153,7 @@ fn test_calc_min_break_width2() {
#[test]
fn test_calc_min_break_width3() {
let flib = FontLibrary();
let flib = FontCache();
let font = flib.get_test_font();
let actual = calc_min_break_width(font, ~"yumyum firecracker");
let expected = au::from_px(84);
@ -162,7 +162,7 @@ fn test_calc_min_break_width3() {
#[test]
fn test_calc_min_break_width4() {
let flib = FontLibrary();
let flib = FontCache();
let font = flib.get_test_font();
let actual = calc_min_break_width(font, ~"yumyum firecracker yumyum");
let expected = au::from_px(84);
@ -171,7 +171,7 @@ fn test_calc_min_break_width4() {
#[test]
fn test_iter_indivisible_slices() {
let flib = FontLibrary();
let flib = FontCache();
let font = flib.get_test_font();
let mut slices = ~[];
for iter_indivisible_slices(font, "firecracker yumyum woopwoop") |slice| {
@ -182,7 +182,7 @@ fn test_iter_indivisible_slices() {
#[test]
fn test_iter_indivisible_slices_trailing_whitespace() {
let flib = FontLibrary();
let flib = FontCache();
let font = flib.get_test_font();
let mut slices = ~[];
for iter_indivisible_slices(font, "firecracker ") |slice| {
@ -193,7 +193,7 @@ fn test_iter_indivisible_slices_trailing_whitespace() {
#[test]
fn test_iter_indivisible_slices_leading_whitespace() {
let flib = FontLibrary();
let flib = FontCache();
let font = flib.get_test_font();
let mut slices = ~[];
for iter_indivisible_slices(font, " firecracker") |slice| {
@ -204,7 +204,7 @@ fn test_iter_indivisible_slices_leading_whitespace() {
#[test]
fn test_iter_indivisible_slices_empty() {
let flib = FontLibrary();
let flib = FontCache();
let font = flib.get_test_font();
let mut slices = ~[];
for iter_indivisible_slices(font, "") |slice| {
@ -215,7 +215,7 @@ fn test_iter_indivisible_slices_empty() {
#[test]
fn test_split() {
let flib = FontLibrary();
let flib = FontCache();
let font = flib.get_test_font();
let run = TextRun(font, ~"firecracker yumyum");
let break_runs = run.split(font, run.min_break_width());
@ -225,7 +225,7 @@ fn test_split() {
#[test]
fn test_split2() {
let flib = FontLibrary();
let flib = FontCache();
let font = flib.get_test_font();
let run = TextRun(font, ~"firecracker yum yum yum yum yum");
let break_runs = run.split(font, run.min_break_width());
@ -235,7 +235,7 @@ fn test_split2() {
#[test]
fn test_split3() {
let flib = FontLibrary();
let flib = FontCache();
let font = flib.get_test_font();
let run = TextRun(font, ~"firecracker firecracker");
let break_runs = run.split(font, run.min_break_width() + au::from_px(10));
@ -247,7 +247,7 @@ fn test_split3() {
#[test]
#[ignore(cfg(target_os = "macos"))]
fn should_calculate_the_total_size() {
let flib = FontLibrary();
let flib = FontCache();
let font = flib.get_test_font();
let run = TextRun(font, ~"firecracker");
let expected = Size2D(au::from_px(84), au::from_px(20));