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

View file

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

View file

@ -4,7 +4,6 @@
//! Creates CSS boxes from a DOM tree.
use layout::aux::LayoutAuxMethods;
use layout::block::BlockFlowData;
use layout::float::FloatFlowData;
use layout::box::{GenericRenderBoxClass, ImageRenderBox, ImageRenderBoxClass, RenderBox};
@ -334,18 +333,6 @@ impl LayoutTreeBuilder {
this_generator.pop_node(layout_ctx, cur_node);
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)
}

View file

@ -6,20 +6,29 @@
use layout::box::RenderBox;
use layout::context::LayoutContext;
use std::cast::transmute;
use script::dom::node::AbstractNode;
use gfx;
use newcss;
/// Extra display list data is either nothing (if the display list is to be rendered) or the
/// originating render box (if the display list is generated for hit testing).
/// Display list data is usually an AbstractNode with view () to indicate
/// 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 {
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 = ();
impl ExtraDisplayListData for AbstractNode<()> {
fn new (box: RenderBox) -> AbstractNode<()> {
unsafe {
transmute(box.node())
}
}
}
impl ExtraDisplayListData for Nothing {
fn new(_: RenderBox) -> Nothing {
()

View file

@ -8,7 +8,6 @@
use css::matching::MatchMethods;
use css::select::new_css_select_ctx;
use layout::aux::{LayoutData, LayoutAuxMethods};
use layout::box::RenderBox;
use layout::box_builder::LayoutTreeBuilder;
use layout::context::LayoutContext;
use layout::display_list_builder::{DisplayListBuilder};
@ -17,7 +16,9 @@ use layout::incremental::{RestyleDamage, BubbleWidths};
use std::cast::transmute;
use std::cell::Cell;
use std::uint;
use std::comm::{Port};
use extra::arc::Arc;
use geom::point::Point2D;
use geom::rect::Rect;
use geom::size::Size2D;
@ -44,6 +45,7 @@ use servo_net::local_image_cache::LocalImageCache;
use servo_util::tree::TreeNodeRef;
use servo_util::time::{ProfilerChan, profile};
use servo_util::time;
use servo_util::range::Range;
use extra::url::Url;
struct LayoutTask {
@ -51,7 +53,7 @@ struct LayoutTask {
port: Port<Msg>,
constellation_chan: ConstellationChan,
script_chan: ScriptChan,
render_chan: RenderChan,
render_chan: RenderChan<AbstractNode<()>>,
image_cache_task: ImageCacheTask,
local_image_cache: @mut LocalImageCache,
font_ctx: @mut FontContext,
@ -61,6 +63,8 @@ struct LayoutTask {
/// This is used to root reader data.
layout_refs: ~[@mut LayoutData],
display_list: Option<Arc<DisplayList<AbstractNode<()>>>>,
css_select_ctx: @mut SelectCtx,
profiler_chan: ProfilerChan,
}
@ -70,7 +74,7 @@ impl LayoutTask {
port: Port<Msg>,
constellation_chan: ConstellationChan,
script_chan: ScriptChan,
render_chan: RenderChan,
render_chan: RenderChan<AbstractNode<()>>,
img_cache_task: ImageCacheTask,
opts: Opts,
profiler_chan: ProfilerChan) {
@ -99,7 +103,7 @@ impl LayoutTask {
port: Port<Msg>,
constellation_chan: ConstellationChan,
script_chan: ScriptChan,
render_chan: RenderChan,
render_chan: RenderChan<AbstractNode<()>>,
image_cache_task: ImageCacheTask,
opts: &Opts,
profiler_chan: ProfilerChan)
@ -118,6 +122,8 @@ impl LayoutTask {
doc_url: None,
screen_size: None,
display_list: None,
layout_refs: ~[],
css_select_ctx: @mut new_css_select_ctx(),
profiler_chan: profiler_chan,
@ -271,7 +277,7 @@ impl LayoutTask {
};
// 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.
for flow in layout_root.traverse_preorder() {
flow.assign_widths(&mut layout_ctx);
@ -291,7 +297,7 @@ impl LayoutTask {
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: Be smarter about what needs painting.
@ -303,11 +309,39 @@ impl LayoutTask {
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 {
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)
};
self.display_list = Some(display_list.clone());
self.render_chan.send(RenderMsg(render_layer));
} // time(layout: display list building)
}
@ -330,19 +364,15 @@ impl LayoutTask {
transmute(node)
};
let response = match node.layout_data().flow {
None => {
error!("no flow present");
Err(())
let response = match (node.layout_data().boxes.display_list.clone(), node.layout_data().boxes.range) {
(Some(display_list), Some(range)) => {
let mut rect: Option<Rect<Au>> = None;
for i in range.eachi() {
rect = match rect {
Some(acc) => Some(acc.union(&display_list.get().list[i].bounds())),
None => Some(display_list.get().list[i].bounds())
}
Some(flow) => {
let start_val: Option<Rect<Au>> = None;
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 {
None => {
@ -352,6 +382,10 @@ impl LayoutTask {
Some(rect) => Ok(ContentBoxResponse(rect))
}
}
_ => {
error!("no display list present");
Err(())
}
};
reply_chan.send(response)
@ -362,72 +396,50 @@ impl LayoutTask {
transmute(node)
};
let response = match node.layout_data().flow {
None => Err(()),
Some(flow) => {
let response = match (node.layout_data().boxes.display_list.clone(), node.layout_data().boxes.range) {
(Some(display_list), Some(range)) => {
let mut boxes = ~[];
for box in flow.iter_all_boxes() {
if box.node() == node {
boxes.push(box.content_box());
}
for i in range.eachi() {
boxes.push(display_list.get().list[i].bounds());
}
Ok(ContentBoxesResponse(boxes))
}
_ => Err(()),
};
reply_chan.send(response)
}
HitTestQuery(node, point, reply_chan) => {
// FIXME: Isolate this transmutation into a single "bridge" module.
let node: AbstractNode<LayoutView> = unsafe {
transmute(node)
};
let mut flow_node: AbstractNode<LayoutView> = node;
for node in node.traverse_preorder() {
if node.layout_data().flow.is_some() {
flow_node = node;
break;
}
};
let response = match flow_node.layout_data().flow {
None => {
debug!("HitTestQuery: flow is None");
Err(())
}
Some(flow) => {
let layout_ctx = self.build_layout_context();
let builder = DisplayListBuilder {
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)
}
HitTestQuery(_, point, reply_chan) => {
let response = {
match self.display_list {
Some(ref list) => {
let display_list = list.get();
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() {
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 &&
bounds.origin.x <= x &&
y < bounds.origin.y + bounds.size.height &&
bounds.origin.y < y {
resp = Ok(HitTestResponse(display_item.base().extra.node()));
let node: AbstractNode<LayoutView> = unsafe {
transmute(display_item.base().extra)
};
resp = Ok(HitTestResponse(node));
break;
}
}
resp
}
None => {
error!("Can't hit test: no display list");
Err(())
},
}
};
reply_chan.send(response)

View file

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