Remove extraneous references to flow tree objects.

This commit is contained in:
Eric Atkinson 2013-08-12 10:19:59 -07:00
parent e4bfad144e
commit eb58e4f5d1
6 changed files with 133 additions and 119 deletions

View file

@ -19,19 +19,22 @@ use render_context::RenderContext;
use std::cell::Cell; use std::cell::Cell;
use std::comm::{Chan, Port, SharedChan}; use std::comm::{Chan, Port, SharedChan};
use extra::arc::Arc;
use servo_util::time::{ProfilerChan, profile}; use servo_util::time::{ProfilerChan, profile};
use servo_util::time; use servo_util::time;
use extra::arc; use extra::arc;
pub struct RenderLayer {
display_list: DisplayList<()>,
pub struct RenderLayer<T> {
display_list: Arc<DisplayList<T>>,
size: Size2D<uint> size: Size2D<uint>
} }
pub enum Msg { pub enum Msg<T> {
RenderMsg(RenderLayer), RenderMsg(RenderLayer<T>),
ReRenderMsg(~[BufferRequest], f32, PipelineId, Epoch), ReRenderMsg(~[BufferRequest], f32, PipelineId, Epoch),
PaintPermissionGranted, PaintPermissionGranted,
PaintPermissionRevoked, PaintPermissionRevoked,
@ -56,24 +59,24 @@ pub fn BufferRequest(screen_rect: Rect<uint>, page_rect: Rect<f32>) -> BufferReq
} }
#[deriving(Clone)] #[deriving(Clone)]
pub struct RenderChan { pub struct RenderChan<T> {
chan: SharedChan<Msg>, chan: SharedChan<Msg<T>>,
} }
impl RenderChan { impl<T> RenderChan<T> {
pub fn new(chan: Chan<Msg>) -> RenderChan { pub fn new(chan: Chan<Msg<T>>) -> RenderChan<T> {
RenderChan { RenderChan {
chan: SharedChan::new(chan), chan: SharedChan::new(chan),
} }
} }
pub fn send(&self, msg: Msg) { pub fn send(&self, msg: Msg<T>) {
self.chan.send(msg); self.chan.send(msg);
} }
} }
struct RenderTask<C> { struct RenderTask<C,T> {
id: PipelineId, id: PipelineId,
port: Port<Msg>, port: Port<Msg<T>>,
compositor: C, compositor: C,
font_ctx: @mut FontContext, font_ctx: @mut FontContext,
opts: Opts, opts: Opts,
@ -84,7 +87,7 @@ struct RenderTask<C> {
share_gl_context: AzGLContext, share_gl_context: AzGLContext,
/// The layer to be rendered /// The layer to be rendered
render_layer: Option<RenderLayer>, render_layer: Option<RenderLayer<T>>,
/// Permission to send paint messages to the compositor /// Permission to send paint messages to the compositor
paint_permission: bool, paint_permission: bool,
/// Cached copy of last layers rendered /// Cached copy of last layers rendered
@ -93,9 +96,9 @@ struct RenderTask<C> {
epoch: Epoch, epoch: Epoch,
} }
impl<C: RenderListener + Send> RenderTask<C> { impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> {
pub fn create(id: PipelineId, pub fn create(id: PipelineId,
port: Port<Msg>, port: Port<Msg<T>>,
compositor: C, compositor: C,
opts: Opts, opts: Opts,
profiler_chan: ProfilerChan) { profiler_chan: ProfilerChan) {
@ -226,7 +229,7 @@ impl<C: RenderListener + Send> RenderTask<C> {
// Draw the display list. // Draw the display list.
do profile(time::RenderingDrawingCategory, self.profiler_chan.clone()) { do profile(time::RenderingDrawingCategory, self.profiler_chan.clone()) {
render_layer.display_list.draw_into_context(&ctx); render_layer.display_list.get().draw_into_context(&ctx);
ctx.canvas.draw_target.flush(); ctx.canvas.draw_target.flush();
} }
} }

View file

@ -4,13 +4,20 @@
//! Code for managing the layout data in the DOM. //! Code for managing the layout data in the DOM.
use layout::flow::FlowContext;
use layout::incremental::RestyleDamage; use layout::incremental::RestyleDamage;
use gfx::display_list::DisplayList;
use servo_util::range::Range;
use extra::arc::Arc;
use newcss::complete::CompleteSelectResults; use newcss::complete::CompleteSelectResults;
use script::dom::node::{AbstractNode, LayoutView}; use script::dom::node::{AbstractNode, LayoutView};
use servo_util::tree::TreeNodeRef; use servo_util::tree::TreeNodeRef;
pub struct DisplayBoxes {
display_list: Option<Arc<DisplayList<AbstractNode<()>>>>,
range: Option<Range>,
}
/// Data that layout associates with a node. /// Data that layout associates with a node.
pub struct LayoutData { pub struct LayoutData {
/// The results of CSS styling for this node. /// The results of CSS styling for this node.
@ -19,8 +26,9 @@ pub struct LayoutData {
/// Description of how to account for recent style changes. /// Description of how to account for recent style changes.
restyle_damage: Option<RestyleDamage>, restyle_damage: Option<RestyleDamage>,
/// The CSS flow that this node is associated with. /// The boxes assosiated with this flow.
flow: Option<FlowContext>, /// Used for getBoundingClientRect and friends.
boxes: DisplayBoxes,
} }
impl LayoutData { impl LayoutData {
@ -29,7 +37,7 @@ impl LayoutData {
LayoutData { LayoutData {
style: None, style: None,
restyle_damage: None, restyle_damage: None,
flow: None, boxes: DisplayBoxes{ display_list: None, range: None },
} }
} }
} }
@ -65,14 +73,8 @@ impl LayoutAuxMethods for AbstractNode<LayoutView> {
/// box in the COW model) and populates it with an empty style object. /// box in the COW model) and populates it with an empty style object.
fn initialize_layout_data(self) -> Option<@mut LayoutData> { fn initialize_layout_data(self) -> Option<@mut LayoutData> {
if self.has_layout_data() { if self.has_layout_data() {
{ self.layout_data().boxes.display_list = None;
let layout_data = &mut self.layout_data().flow; self.layout_data().boxes.range = None;
match *layout_data {
Some(ref flow) => flow.teardown(),
None => ()
}
}
self.layout_data().flow = None;
None None
} else { } else {
let data = @mut LayoutData::new(); let data = @mut LayoutData::new();

View file

@ -4,7 +4,6 @@
//! Creates CSS boxes from a DOM tree. //! Creates CSS boxes from a DOM tree.
use layout::aux::LayoutAuxMethods;
use layout::block::BlockFlowData; use layout::block::BlockFlowData;
use layout::float::FloatFlowData; use layout::float::FloatFlowData;
use layout::box::{GenericRenderBoxClass, ImageRenderBox, ImageRenderBoxClass, RenderBox}; use layout::box::{GenericRenderBoxClass, ImageRenderBox, ImageRenderBoxClass, RenderBox};
@ -334,18 +333,6 @@ impl LayoutTreeBuilder {
this_generator.pop_node(layout_ctx, cur_node); this_generator.pop_node(layout_ctx, cur_node);
self.simplify_children_of_flow(layout_ctx, &mut this_generator.flow); self.simplify_children_of_flow(layout_ctx, &mut this_generator.flow);
// store reference to the flow context which contains any
// boxes that correspond to child_flow.node. These boxes may
// eventually be elided or split, but the mapping between
// nodes and FlowContexts should not change during layout.
let flow: &FlowContext = &this_generator.flow;
for child_flow in flow.children() {
do child_flow.with_base |child_node| {
let dom_node = child_node.node;
assert!(dom_node.has_layout_data());
dom_node.layout_data().flow = Some(child_flow);
}
}
Some(next_generator) Some(next_generator)
} }

View file

@ -6,20 +6,29 @@
use layout::box::RenderBox; use layout::box::RenderBox;
use layout::context::LayoutContext; use layout::context::LayoutContext;
use std::cast::transmute;
use script::dom::node::AbstractNode;
use gfx; use gfx;
use newcss; use newcss;
/// Extra display list data is either nothing (if the display list is to be rendered) or the /// Display list data is usually an AbstractNode with view () to indicate
/// originating render box (if the display list is generated for hit testing). /// that nodes in this view shoud not really be touched. The idea is to
/// store the nodes in the display list and have layout transmute them.
pub trait ExtraDisplayListData { pub trait ExtraDisplayListData {
fn new(box: RenderBox) -> Self; fn new(box: RenderBox) -> Self;
} }
/// The type representing the lack of extra display list data. This is used when sending display
/// list data off to be rendered.
pub type Nothing = (); pub type Nothing = ();
impl ExtraDisplayListData for AbstractNode<()> {
fn new (box: RenderBox) -> AbstractNode<()> {
unsafe {
transmute(box.node())
}
}
}
impl ExtraDisplayListData for Nothing { impl ExtraDisplayListData for Nothing {
fn new(_: RenderBox) -> Nothing { fn new(_: RenderBox) -> Nothing {
() ()

View file

@ -8,7 +8,6 @@
use css::matching::MatchMethods; use css::matching::MatchMethods;
use css::select::new_css_select_ctx; use css::select::new_css_select_ctx;
use layout::aux::{LayoutData, LayoutAuxMethods}; use layout::aux::{LayoutData, LayoutAuxMethods};
use layout::box::RenderBox;
use layout::box_builder::LayoutTreeBuilder; use layout::box_builder::LayoutTreeBuilder;
use layout::context::LayoutContext; use layout::context::LayoutContext;
use layout::display_list_builder::{DisplayListBuilder}; use layout::display_list_builder::{DisplayListBuilder};
@ -17,7 +16,9 @@ use layout::incremental::{RestyleDamage, BubbleWidths};
use std::cast::transmute; use std::cast::transmute;
use std::cell::Cell; use std::cell::Cell;
use std::uint;
use std::comm::{Port}; use std::comm::{Port};
use extra::arc::Arc;
use geom::point::Point2D; use geom::point::Point2D;
use geom::rect::Rect; use geom::rect::Rect;
use geom::size::Size2D; use geom::size::Size2D;
@ -44,6 +45,7 @@ use servo_net::local_image_cache::LocalImageCache;
use servo_util::tree::TreeNodeRef; use servo_util::tree::TreeNodeRef;
use servo_util::time::{ProfilerChan, profile}; use servo_util::time::{ProfilerChan, profile};
use servo_util::time; use servo_util::time;
use servo_util::range::Range;
use extra::url::Url; use extra::url::Url;
struct LayoutTask { struct LayoutTask {
@ -51,7 +53,7 @@ struct LayoutTask {
port: Port<Msg>, port: Port<Msg>,
constellation_chan: ConstellationChan, constellation_chan: ConstellationChan,
script_chan: ScriptChan, script_chan: ScriptChan,
render_chan: RenderChan, render_chan: RenderChan<AbstractNode<()>>,
image_cache_task: ImageCacheTask, image_cache_task: ImageCacheTask,
local_image_cache: @mut LocalImageCache, local_image_cache: @mut LocalImageCache,
font_ctx: @mut FontContext, font_ctx: @mut FontContext,
@ -61,6 +63,8 @@ struct LayoutTask {
/// This is used to root reader data. /// This is used to root reader data.
layout_refs: ~[@mut LayoutData], layout_refs: ~[@mut LayoutData],
display_list: Option<Arc<DisplayList<AbstractNode<()>>>>,
css_select_ctx: @mut SelectCtx, css_select_ctx: @mut SelectCtx,
profiler_chan: ProfilerChan, profiler_chan: ProfilerChan,
} }
@ -70,7 +74,7 @@ impl LayoutTask {
port: Port<Msg>, port: Port<Msg>,
constellation_chan: ConstellationChan, constellation_chan: ConstellationChan,
script_chan: ScriptChan, script_chan: ScriptChan,
render_chan: RenderChan, render_chan: RenderChan<AbstractNode<()>>,
img_cache_task: ImageCacheTask, img_cache_task: ImageCacheTask,
opts: Opts, opts: Opts,
profiler_chan: ProfilerChan) { profiler_chan: ProfilerChan) {
@ -99,7 +103,7 @@ impl LayoutTask {
port: Port<Msg>, port: Port<Msg>,
constellation_chan: ConstellationChan, constellation_chan: ConstellationChan,
script_chan: ScriptChan, script_chan: ScriptChan,
render_chan: RenderChan, render_chan: RenderChan<AbstractNode<()>>,
image_cache_task: ImageCacheTask, image_cache_task: ImageCacheTask,
opts: &Opts, opts: &Opts,
profiler_chan: ProfilerChan) profiler_chan: ProfilerChan)
@ -117,6 +121,8 @@ impl LayoutTask {
font_ctx: fctx, font_ctx: fctx,
doc_url: None, doc_url: None,
screen_size: None, screen_size: None,
display_list: None,
layout_refs: ~[], layout_refs: ~[],
css_select_ctx: @mut new_css_select_ctx(), css_select_ctx: @mut new_css_select_ctx(),
@ -271,7 +277,7 @@ impl LayoutTask {
}; };
// FIXME: We want to do // FIXME: We want to do
// for flow in layout_root.traverse_preorder_prune(|f| f.restyle_damage().lacks(Reflow)) { // for flow in layout_root.traverse_preorder_prune(|f| f.restyle_damage().lacks(Reflow))
// but FloatContext values can't be reused, so we need to recompute them every time. // but FloatContext values can't be reused, so we need to recompute them every time.
for flow in layout_root.traverse_preorder() { for flow in layout_root.traverse_preorder() {
flow.assign_widths(&mut layout_ctx); flow.assign_widths(&mut layout_ctx);
@ -291,7 +297,7 @@ impl LayoutTask {
ctx: &layout_ctx, ctx: &layout_ctx,
}; };
let display_list = @Cell::new(DisplayList::new()); let display_list = ~Cell::new(DisplayList::new::<AbstractNode<()>>());
// TODO: Set options on the builder before building. // TODO: Set options on the builder before building.
// TODO: Be smarter about what needs painting. // TODO: Be smarter about what needs painting.
@ -303,11 +309,39 @@ impl LayoutTask {
base.position.size base.position.size
}; };
let display_list = Arc::new(display_list.take());
for i in range(0,display_list.get().list.len()) {
let node: AbstractNode<LayoutView> = unsafe {
transmute(display_list.get().list[i].base().extra)
};
assert!(node.has_layout_data(), "Node has display item but no layout data");
let layout_data = node.layout_data();
layout_data.boxes.display_list = Some(display_list.clone());
if layout_data.boxes.range.is_none() {
debug!("Creating initial range for node");
layout_data.boxes.range = Some(Range::new(i,1));
} else {
debug!("Appending item to range");
unsafe {
let old_node: AbstractNode<()> = transmute(node);
assert!(old_node == display_list.get().list[i-1].base().extra,
"Non-contiguous arrangement of display items");
}
layout_data.boxes.range.unwrap().extend_by(1);
}
}
let render_layer = RenderLayer { let render_layer = RenderLayer {
display_list: display_list.take(), display_list: display_list.clone(),
size: Size2D(root_size.width.to_px() as uint, root_size.height.to_px() as uint) size: Size2D(root_size.width.to_px() as uint, root_size.height.to_px() as uint)
}; };
self.display_list = Some(display_list.clone());
self.render_chan.send(RenderMsg(render_layer)); self.render_chan.send(RenderMsg(render_layer));
} // time(layout: display list building) } // time(layout: display list building)
} }
@ -330,19 +364,15 @@ impl LayoutTask {
transmute(node) transmute(node)
}; };
let response = match node.layout_data().flow { let response = match (node.layout_data().boxes.display_list.clone(), node.layout_data().boxes.range) {
None => { (Some(display_list), Some(range)) => {
error!("no flow present"); let mut rect: Option<Rect<Au>> = None;
Err(()) for i in range.eachi() {
} rect = match rect {
Some(flow) => { Some(acc) => Some(acc.union(&display_list.get().list[i].bounds())),
let start_val: Option<Rect<Au>> = None; None => Some(display_list.get().list[i].bounds())
let rect = do flow.foldl_boxes_for_node(node, start_val) |acc, box| {
match acc {
Some(acc) => Some(acc.union(&box.content_box())),
None => Some(box.content_box())
} }
}; }
match rect { match rect {
None => { None => {
@ -352,6 +382,10 @@ impl LayoutTask {
Some(rect) => Ok(ContentBoxResponse(rect)) Some(rect) => Ok(ContentBoxResponse(rect))
} }
} }
_ => {
error!("no display list present");
Err(())
}
}; };
reply_chan.send(response) reply_chan.send(response)
@ -362,71 +396,49 @@ impl LayoutTask {
transmute(node) transmute(node)
}; };
let response = match node.layout_data().flow { let response = match (node.layout_data().boxes.display_list.clone(), node.layout_data().boxes.range) {
None => Err(()), (Some(display_list), Some(range)) => {
Some(flow) => {
let mut boxes = ~[]; let mut boxes = ~[];
for box in flow.iter_all_boxes() { for i in range.eachi() {
if box.node() == node { boxes.push(display_list.get().list[i].bounds());
boxes.push(box.content_box());
}
} }
Ok(ContentBoxesResponse(boxes)) Ok(ContentBoxesResponse(boxes))
} }
_ => Err(()),
}; };
reply_chan.send(response) reply_chan.send(response)
} }
HitTestQuery(node, point, reply_chan) => { HitTestQuery(_, point, reply_chan) => {
// FIXME: Isolate this transmutation into a single "bridge" module. let response = {
let node: AbstractNode<LayoutView> = unsafe { match self.display_list {
transmute(node) Some(ref list) => {
}; let display_list = list.get();
let mut flow_node: AbstractNode<LayoutView> = node; let (x, y) = (Au::from_frac_px(point.x as float),
for node in node.traverse_preorder() { Au::from_frac_px(point.y as float));
if node.layout_data().flow.is_some() { let mut resp = Err(());
flow_node = node; // iterate in reverse to ensure we have the most recently painted render box
break; for display_item in display_list.list.rev_iter() {
} let bounds = display_item.bounds();
}; // TODO this check should really be performed by a method of DisplayItem
if x <= bounds.origin.x + bounds.size.width &&
let response = match flow_node.layout_data().flow { bounds.origin.x <= x &&
None => { y < bounds.origin.y + bounds.size.height &&
debug!("HitTestQuery: flow is None"); bounds.origin.y < y {
Err(()) let node: AbstractNode<LayoutView> = unsafe {
} transmute(display_item.base().extra)
Some(flow) => { };
let layout_ctx = self.build_layout_context(); resp = Ok(HitTestResponse(node));
let builder = DisplayListBuilder { break;
ctx: &layout_ctx, }
};
let display_list: @Cell<DisplayList<RenderBox>> =
@Cell::new(DisplayList::new());
do flow.partially_traverse_preorder |this_flow| {
this_flow.build_display_list(&builder,
&flow.position(),
display_list)
}
let (x, y) = (Au::from_frac_px(point.x as float),
Au::from_frac_px(point.y as float));
let mut resp = Err(());
let display_list = &display_list.take().list;
// iterate in reverse to ensure we have the most recently painted render box
for display_item in display_list.rev_iter() {
let bounds = display_item.bounds();
// TODO this check should really be performed by a method of DisplayItem
if x <= bounds.origin.x + bounds.size.width &&
bounds.origin.x <= x &&
y < bounds.origin.y + bounds.size.height &&
bounds.origin.y < y {
resp = Ok(HitTestResponse(display_item.base().extra.node()));
break;
} }
resp
} }
resp None => {
error!("Can't hit test: no display list");
Err(())
},
} }
}; };

View file

@ -12,6 +12,7 @@ use layout::layout_task::LayoutTask;
use script::layout_interface::LayoutChan; use script::layout_interface::LayoutChan;
use script::script_task::{ExecuteMsg, LoadMsg}; use script::script_task::{ExecuteMsg, LoadMsg};
use servo_msg::constellation_msg::{ConstellationChan, PipelineId, SubpageId}; use servo_msg::constellation_msg::{ConstellationChan, PipelineId, SubpageId};
use script::dom::node::AbstractNode;
use script::script_task::{AttachLayoutMsg, NewLayoutInfo, ScriptTask, ScriptChan}; use script::script_task::{AttachLayoutMsg, NewLayoutInfo, ScriptTask, ScriptChan};
use script::script_task; use script::script_task;
use servo_net::image_cache_task::ImageCacheTask; use servo_net::image_cache_task::ImageCacheTask;
@ -28,7 +29,7 @@ pub struct Pipeline {
subpage_id: Option<SubpageId>, subpage_id: Option<SubpageId>,
script_chan: ScriptChan, script_chan: ScriptChan,
layout_chan: LayoutChan, layout_chan: LayoutChan,
render_chan: RenderChan, render_chan: RenderChan<AbstractNode<()>>,
/// The most recently loaded url /// The most recently loaded url
url: Option<Url>, url: Option<Url>,
} }
@ -130,7 +131,7 @@ impl Pipeline {
subpage_id: Option<SubpageId>, subpage_id: Option<SubpageId>,
script_chan: ScriptChan, script_chan: ScriptChan,
layout_chan: LayoutChan, layout_chan: LayoutChan,
render_chan: RenderChan) render_chan: RenderChan<AbstractNode<()>>)
-> Pipeline { -> Pipeline {
Pipeline { Pipeline {
id: id, id: id,