diff --git a/src/servo/css/resolve/apply.rs b/src/servo/css/resolve/apply.rs index 2d1205d7541..ca58696a750 100644 --- a/src/servo/css/resolve/apply.rs +++ b/src/servo/css/resolve/apply.rs @@ -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 : ResolveMethods { 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. */ } diff --git a/src/servo/css/styles.rs b/src/servo/css/styles.rs index 9e4d4d89987..f1fbb372760 100644 --- a/src/servo/css/styles.rs +++ b/src/servo/css/styles.rs @@ -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, mut display_type : CSSValue, @@ -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); + fn recompute_style_for_subtree(ctx: &LayoutContext, styles : ARC); } 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) { - 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) { + 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)); } } diff --git a/src/servo/gfx/display_list.rs b/src/servo/gfx/display_list.rs index dd8920b110e..736a24184fb 100644 --- a/src/servo/gfx/display_list.rs +++ b/src/servo/gfx/display_list.rs @@ -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, // 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, 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); diff --git a/src/servo/gfx/render_task.rs b/src/servo/gfx/render_task.rs index f2b1b3ab7fc..b05668cedad 100644 --- a/src/servo/gfx/render_task.rs +++ b/src/servo/gfx/render_task.rs @@ -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; fn RenderTask(+compositor: C) -> RenderTask { @@ -37,6 +43,8 @@ fn RenderTask(+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(+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 : ToAzureRect { } } -pub fn draw_solid_color(draw_target: &DrawTarget, bounds: &Rect, r: u8, g: u8, b: u8) { +pub fn draw_solid_color(ctx: &RenderContext, bounds: &Rect, 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, image: ARC<~Image>) { +pub fn draw_image(ctx: &RenderContext, bounds: Rect, 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, text_run: &GlyphRun) { +pub fn draw_glyphs(ctx: &RenderContext, bounds: Rect, 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, 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, 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); } diff --git a/src/servo/layout/base.rs b/src/servo/layout/base.rs index 2d32368feff..145f435a22c 100644 --- a/src/servo/layout/base.rs +++ b/src/servo/layout/base.rs @@ -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) }) } } diff --git a/src/servo/layout/block.rs b/src/servo/layout/block.rs index ae222ef6571..ea566b2b780 100644 --- a/src/servo/layout/block.rs +++ b/src/servo/layout/block.rs @@ -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(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); diff --git a/src/servo/layout/box_builder.rs b/src/servo/layout/box_builder.rs index a8b34a55b92..25431ef48f6 100644 --- a/src/servo/layout/box_builder.rs +++ b/src/servo/layout/box_builder.rs @@ -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; + fn create_box_data(layout_ctx: &LayoutContext, display: CSSDisplay) -> Option; } impl Node : PrivateBuilderMethods { - fn create_box_data(display: CSSDisplay) -> Option { + fn create_box_data(layout_ctx: &LayoutContext, display: CSSDisplay) -> Option { 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]))) } diff --git a/src/servo/layout/inline.rs b/src/servo/layout/inline.rs index b0b7cfe1a1d..4e57bafa6dd 100644 --- a/src/servo/layout/inline.rs +++ b/src/servo/layout/inline.rs @@ -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(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. } diff --git a/src/servo/layout/layout_task.rs b/src/servo/layout/layout_task.rs index 35d9148f603..3cceb75aba2 100644 --- a/src/servo/layout/layout_task.rs +++ b/src/servo/layout/layout_task.rs @@ -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)); + } } - } } } } diff --git a/src/servo/layout/root.rs b/src/servo/layout/root.rs index de0a44da691..8bedaacc0dc 100644 --- a/src/servo/layout/root.rs +++ b/src/servo/layout/root.rs @@ -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(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); } } diff --git a/src/servo/layout/text.rs b/src/servo/layout/text.rs index a00d7805d12..b2335f870b6 100644 --- a/src/servo/layout/text.rs +++ b/src/servo/layout/text.rs @@ -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); diff --git a/src/servo/layout/traverse.rs b/src/servo/layout/traverse.rs index bf488300034..ad2c5fd22e4 100644 --- a/src/servo/layout/traverse.rs +++ b/src/servo/layout/traverse.rs @@ -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); } diff --git a/src/servo/servo.rc b/src/servo/servo.rc index 12782355e32..3ebaca479fd 100755 --- a/src/servo/servo.rc +++ b/src/servo/servo.rc @@ -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")] diff --git a/src/servo/text/font.rs b/src/servo/text/font.rs index 2c514b02295..2a7883ffde4 100644 --- a/src/servo/text/font.rs +++ b/src/servo/text/font.rs @@ -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(); } } diff --git a/src/servo/text/font_library.rs b/src/servo/text/font_cache.rs similarity index 71% rename from src/servo/text/font_library.rs rename to src/servo/text/font_cache.rs index 584dcd3743a..c6d1b82b164 100644 --- a/src/servo/text/font_library.rs +++ b/src/servo/text/font_cache.rs @@ -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(); } diff --git a/src/servo/text/native_font.rs b/src/servo/text/native_font.rs index 76f5c6e6950..0f59c49a77f 100644 --- a/src/servo/text/native_font.rs +++ b/src/servo/text/native_font.rs @@ -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 { +fn create(_native_lib: &NativeFontCache, buf: @~[u8]) -> Result { quartz_native_font::create(buf) } #[cfg(target_os = "linux")] -fn create(native_lib: &NativeFontLibrary, buf: @~[u8]) -> Result { +fn create(native_lib: &NativeFontCache, buf: @~[u8]) -> Result { ft_native_font::create(native_lib, buf) } diff --git a/src/servo/text/shaper.rs b/src/servo/text/shaper.rs index 3745c81fc6e..13735f553fd 100644 --- a/src/servo/text/shaper.rs +++ b/src/servo/text/shaper.rs @@ -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); diff --git a/src/servo/text/text_run.rs b/src/servo/text/text_run.rs index c8a847c4090..c0ca6622aef 100644 --- a/src/servo/text/text_run.rs +++ b/src/servo/text/text_run.rs @@ -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));