diff --git a/src/components/gfx/platform/linux/font.rs b/src/components/gfx/platform/linux/font.rs index cb2573a9a13..05f792ca1a4 100644 --- a/src/components/gfx/platform/linux/font.rs +++ b/src/components/gfx/platform/linux/font.rs @@ -79,7 +79,7 @@ impl FontHandleMethods for FontHandle { buf: ~[u8], style: &SpecifiedFontStyle) -> Result { - let ft_ctx: FT_Library = fctx.ctx.ctx; + let ft_ctx: FT_Library = fctx.ctx.get().ctx; if ft_ctx.is_null() { return Err(()); } let face_result = do buf.as_imm_buf |bytes: *u8, len: uint| { @@ -292,7 +292,7 @@ impl<'self> FontHandle { pub fn new_from_file(fctx: &FontContextHandle, file: &str, style: &SpecifiedFontStyle) -> Result { unsafe { - let ft_ctx: FT_Library = fctx.ctx.ctx; + let ft_ctx: FT_Library = fctx.ctx.get().ctx; if ft_ctx.is_null() { return Err(()); } let mut face: FT_Face = ptr::null(); @@ -320,7 +320,7 @@ impl<'self> FontHandle { pub fn new_from_file_unstyled(fctx: &FontContextHandle, file: ~str) -> Result { unsafe { - let ft_ctx: FT_Library = fctx.ctx.ctx; + let ft_ctx: FT_Library = fctx.ctx.get().ctx; if ft_ctx.is_null() { return Err(()); } let mut face: FT_Face = ptr::null(); diff --git a/src/components/main/layout/construct.rs b/src/components/main/layout/construct.rs index 18ff1654888..e758409c31c 100644 --- a/src/components/main/layout/construct.rs +++ b/src/components/main/layout/construct.rs @@ -33,7 +33,7 @@ use layout::util::LayoutDataAccess; use script::dom::element::HTMLImageElementTypeId; use script::dom::node::{AbstractNode, CommentNodeTypeId, DoctypeNodeTypeId}; use script::dom::node::{DocumentFragmentNodeTypeId, DocumentNodeTypeId, ElementNodeTypeId}; -use script::dom::node::{LayoutView, PostorderNodeTraversal, TextNodeTypeId}; +use script::dom::node::{LayoutView, PostorderNodeMutTraversal, TextNodeTypeId}; use servo_util::slot::Slot; use servo_util::tree::TreeNodeRef; use std::util; @@ -173,7 +173,7 @@ pub struct FlowConstructor<'self> { /// The layout context. /// /// FIXME(pcwalton): Why does this contain `@`??? That destroys parallelism!!! - layout_context: &'self LayoutContext, + layout_context: &'self mut LayoutContext, /// The next flow ID to assign. /// @@ -183,7 +183,7 @@ pub struct FlowConstructor<'self> { impl<'self> FlowConstructor<'self> { /// Creates a new flow constructor. - pub fn init<'a>(layout_context: &'a LayoutContext) -> FlowConstructor<'a> { + pub fn init<'a>(layout_context: &'a mut LayoutContext) -> FlowConstructor<'a> { FlowConstructor { layout_context: layout_context, next_flow_id: Slot::init(0), @@ -198,7 +198,7 @@ impl<'self> FlowConstructor<'self> { } /// Builds the `ImageBoxInfo` for the given image. This is out of line to guide inlining. - fn build_box_info_for_image(&self, node: AbstractNode) -> Option { + fn build_box_info_for_image(&mut self, node: AbstractNode) -> Option { // FIXME(pcwalton): Don't copy URLs. let url = node.with_imm_image_element(|image_element| { image_element.image.as_ref().map(|url| (*url).clone()) @@ -215,7 +215,7 @@ impl<'self> FlowConstructor<'self> { } /// Builds a `Box` for the given node. - fn build_box_for_node(&self, node: AbstractNode) -> @Box { + fn build_box_for_node(&mut self, node: AbstractNode) -> @Box { let specific = match node.type_id() { ElementNodeTypeId(HTMLImageElementTypeId) => { match self.build_box_info_for_image(node) { @@ -234,7 +234,7 @@ impl<'self> FlowConstructor<'self> { /// `#[inline(always)]` because this is performance critical and LLVM will not inline it /// otherwise. #[inline(always)] - fn flush_inline_boxes_to_flow(&self, + fn flush_inline_boxes_to_flow(&mut self, boxes: ~[@Box], flow: &mut ~Flow:, node: AbstractNode) { @@ -248,7 +248,7 @@ impl<'self> FlowConstructor<'self> { /// Creates an inline flow from a set of inline boxes, if present, and adds it as a child of /// the given flow. - fn flush_inline_boxes_to_flow_if_necessary(&self, + fn flush_inline_boxes_to_flow_if_necessary(&mut self, opt_boxes: &mut Option<~[@Box]>, flow: &mut ~Flow:, node: AbstractNode) { @@ -261,7 +261,7 @@ impl<'self> FlowConstructor<'self> { /// Builds the children flows underneath a node with `display: block`. After this call, /// other `BlockFlow`s or `InlineFlow`s will be populated underneath this node, depending on /// whether {ib} splits needed to happen. - fn build_children_of_block_flow(&self, + fn build_children_of_block_flow(&mut self, flow: &mut ~Flow:, node: AbstractNode) { // Gather up boxes for the inline flows we might need to create. @@ -341,7 +341,7 @@ impl<'self> FlowConstructor<'self> { /// Builds a flow for a node with `display: block`. This yields a `BlockFlow` with possibly /// other `BlockFlow`s or `InlineFlow`s underneath it, depending on whether {ib} splits needed /// to happen. - fn build_flow_for_block(&self, node: AbstractNode) -> ~Flow: { + fn build_flow_for_block(&mut self, node: AbstractNode) -> ~Flow: { let base = FlowData::new(self.next_flow_id(), node); let box = self.build_box_for_node(node); let mut flow = ~BlockFlow::from_box(base, box) as ~Flow:; @@ -351,7 +351,7 @@ impl<'self> FlowConstructor<'self> { /// Builds the flow for a node with `float: {left|right}`. This yields a float `BlockFlow` with /// a `BlockFlow` underneath it. - fn build_flow_for_floated_block(&self, node: AbstractNode, float_type: FloatType) + fn build_flow_for_floated_block(&mut self, node: AbstractNode, float_type: FloatType) -> ~Flow: { let base = FlowData::new(self.next_flow_id(), node); let box = self.build_box_for_node(node); @@ -363,7 +363,7 @@ impl<'self> FlowConstructor<'self> { /// Concatenates the boxes of kids, adding in our own borders/padding/margins if necessary. /// Returns the `InlineBoxesConstructionResult`, if any. There will be no /// `InlineBoxesConstructionResult` if this node consisted entirely of ignorable whitespace. - fn build_boxes_for_nonreplaced_inline_content(&self, node: AbstractNode) + fn build_boxes_for_nonreplaced_inline_content(&mut self, node: AbstractNode) -> ConstructionResult { let mut opt_inline_block_splits = None; let mut opt_box_accumulator = None; @@ -429,7 +429,7 @@ impl<'self> FlowConstructor<'self> { /// Creates an `InlineBoxesConstructionResult` for replaced content. Replaced content doesn't /// render its children, so this just nukes a child's boxes and creates a `Box`. - fn build_boxes_for_replaced_inline_content(&self, node: AbstractNode) + fn build_boxes_for_replaced_inline_content(&mut self, node: AbstractNode) -> ConstructionResult { for kid in node.children() { kid.set_flow_construction_result(NoConstructionResult) @@ -446,7 +446,7 @@ impl<'self> FlowConstructor<'self> { /// Builds one or more boxes for a node with `display: inline`. This yields an /// `InlineBoxesConstructionResult`. - fn build_boxes_for_inline(&self, node: AbstractNode) -> ConstructionResult { + fn build_boxes_for_inline(&mut self, node: AbstractNode) -> ConstructionResult { // Is this node replaced content? if !node.is_replaced_content() { // Go to a path that concatenates our kids' boxes. @@ -458,11 +458,11 @@ impl<'self> FlowConstructor<'self> { } } -impl<'self> PostorderNodeTraversal for FlowConstructor<'self> { +impl<'self> PostorderNodeMutTraversal for FlowConstructor<'self> { // `#[inline(always)]` because this is always called from the traversal function and for some // reason LLVM's inlining heuristics go awry here. #[inline(always)] - fn process(&self, node: AbstractNode) -> bool { + fn process(&mut self, node: AbstractNode) -> bool { // Get the `display` property for this node, and determine whether this node is floated. let (display, float) = match node.type_id() { ElementNodeTypeId(_) => (node.style().Box.display, node.style().Box.float), diff --git a/src/components/main/layout/context.rs b/src/components/main/layout/context.rs index 748ed66d4ad..2eaa7eafc8c 100644 --- a/src/components/main/layout/context.rs +++ b/src/components/main/layout/context.rs @@ -13,7 +13,7 @@ use extra::arc::MutexArc; /// Data needed by the layout task. pub struct LayoutContext { - font_ctx: @mut FontContext, + font_ctx: ~FontContext, image_cache: MutexArc, screen_size: Rect } diff --git a/src/components/main/layout/layout_task.rs b/src/components/main/layout/layout_task.rs index af14f96a9c6..125037dc654 100644 --- a/src/components/main/layout/layout_task.rs +++ b/src/components/main/layout/layout_task.rs @@ -77,9 +77,6 @@ struct LayoutTask { /// The local image cache. local_image_cache: MutexArc, - /// The local font context. - font_ctx: @mut FontContext, - /// The size of the viewport. screen_size: Option>, @@ -90,6 +87,8 @@ struct LayoutTask { /// The channel on which messages can be sent to the profiler. profiler_chan: ProfilerChan, + + opts: Opts } /// The damage computation traversal. @@ -229,7 +228,6 @@ impl LayoutTask { opts: &Opts, profiler_chan: ProfilerChan) -> LayoutTask { - let fctx = @mut FontContext::new(opts.render_backend, true, profiler_chan.clone()); LayoutTask { id: id, @@ -239,13 +237,13 @@ impl LayoutTask { render_chan: render_chan, image_cache_task: image_cache_task.clone(), local_image_cache: MutexArc::new(LocalImageCache(image_cache_task)), - font_ctx: fctx, screen_size: None, display_list: None, stylist: RWArc::new(new_stylist()), profiler_chan: profiler_chan, + opts: opts.clone() } } @@ -259,7 +257,8 @@ impl LayoutTask { // Create a layout context for use in building display lists, hit testing, &c. fn build_layout_context(&self) -> LayoutContext { let image_cache = self.local_image_cache.clone(); - let font_ctx = self.font_ctx; + let font_ctx = ~FontContext::new(self.opts.render_backend, true, + self.profiler_chan.clone()); let screen_size = self.screen_size.unwrap(); LayoutContext { @@ -344,9 +343,9 @@ impl LayoutTask { /// is intertwined with selector matching, making it difficult to compare directly. It is /// marked `#[inline(never)]` to aid benchmarking in sampling profilers. #[inline(never)] - fn construct_flow_tree(&self, layout_context: &LayoutContext, node: AbstractNode) + fn construct_flow_tree(&self, layout_context: &mut LayoutContext, node: AbstractNode) -> ~Flow: { - node.traverse_postorder(&FlowConstructor::init(layout_context)); + node.traverse_postorder_mut(&mut FlowConstructor::init(layout_context)); let result = match *node.mutate_layout_data().ptr { Some(ref mut layout_data) => { @@ -441,7 +440,7 @@ impl LayoutTask { // Construct the flow tree. let mut layout_root = profile(time::LayoutTreeBuilderCategory, self.profiler_chan.clone(), - || self.construct_flow_tree(&layout_ctx, *node)); + || self.construct_flow_tree(&mut layout_ctx, *node)); // Propagate damage. layout_root.traverse_preorder(&mut PropagateDamageTraversal { diff --git a/src/components/main/layout/text.rs b/src/components/main/layout/text.rs index 3ca9b90826a..b2dee93eb5e 100644 --- a/src/components/main/layout/text.rs +++ b/src/components/main/layout/text.rs @@ -26,7 +26,7 @@ impl TextRunScanner { } } - pub fn scan_for_runs(&mut self, ctx: &LayoutContext, flow: &mut Flow) { + pub fn scan_for_runs(&mut self, ctx: &mut LayoutContext, flow: &mut Flow) { { let inline = flow.as_immutable_inline(); // FIXME: this assertion fails on wikipedia, but doesn't seem @@ -76,7 +76,7 @@ impl TextRunScanner { /// responsible for swapping out the list. It is not clear to me (pcwalton) that this is still /// necessary. pub fn flush_clump_to_list(&mut self, - ctx: &LayoutContext, + ctx: &mut LayoutContext, flow: &mut Flow, last_whitespace: bool, out_boxes: &mut ~[@Box]) diff --git a/src/components/script/dom/node.rs b/src/components/script/dom/node.rs index b0394528d95..a3edd1eb054 100644 --- a/src/components/script/dom/node.rs +++ b/src/components/script/dom/node.rs @@ -1217,6 +1217,20 @@ pub trait PostorderNodeTraversal { } } +/// A bottom-up, parallelizable traversal. +pub trait PostorderNodeMutTraversal { + /// The operation to perform. Return true to continue or false to stop. + fn process(&mut self, node: AbstractNode) -> bool; + + /// Returns true if this node should be pruned. If this returns true, we skip the operation + /// entirely and do not process any descendant nodes. This is called *before* child nodes are + /// visited. The default implementation never prunes any nodes. + fn should_prune(&self, _node: AbstractNode) -> bool { + false + } +} + + impl AbstractNode { /// Traverses the tree in postorder. /// @@ -1241,4 +1255,29 @@ impl AbstractNode { traversal.process(self) } + + /// Traverses the tree in postorder. + /// + /// TODO(pcwalton): Offer a parallel version with a compatible API. + pub fn traverse_postorder_mut(mut self, traversal: &mut T) -> bool { + if traversal.should_prune(self) { + return true + } + + let mut opt_kid = self.first_child(); + loop { + match opt_kid { + None => break, + Some(kid) => { + if !kid.traverse_postorder_mut(traversal) { + return false + } + opt_kid = kid.next_sibling() + } + } + } + + traversal.process(self) + } + }