De-@mut the FrameTree.

This commit is contained in:
Lars Bergstrom 2014-02-13 19:09:39 -06:00
parent 683c2fada1
commit 347bbd2883
5 changed files with 366 additions and 219 deletions

View file

@ -39,12 +39,16 @@ use servo_util::{time, url};
use std::comm::Port; use std::comm::Port;
use std::num::Orderable; use std::num::Orderable;
use std::path::Path; use std::path::Path;
use std::rc::Rc;
//FIXME: switch to std::rc when we upgrade Rust
use layers::temp_rc::Rc;
//use std::rc::Rc;
use std::rc;
pub struct IOCompositor { pub struct IOCompositor {
/// The application window. /// The application window.
window: Rc<Window>, window: rc::Rc<Window>,
/// The port on which we receive messages. /// The port on which we receive messages.
port: Port<Msg>, port: Port<Msg>,
@ -53,7 +57,7 @@ pub struct IOCompositor {
context: RenderContext, context: RenderContext,
/// The root ContainerLayer. /// The root ContainerLayer.
root_layer: @mut ContainerLayer, root_layer: Rc<ContainerLayer>,
/// The canvas to paint a page. /// The canvas to paint a page.
scene: Scene, scene: Scene,
@ -116,13 +120,13 @@ impl IOCompositor {
port: Port<Msg>, port: Port<Msg>,
constellation_chan: ConstellationChan, constellation_chan: ConstellationChan,
profiler_chan: ProfilerChan) -> IOCompositor { profiler_chan: ProfilerChan) -> IOCompositor {
let window: Rc<Window> = WindowMethods::new(app); let window: rc::Rc<Window> = WindowMethods::new(app);
// Create an initial layer tree. // Create an initial layer tree.
// //
// TODO: There should be no initial layer tree until the renderer creates one from the display // TODO: There should be no initial layer tree until the renderer creates one from the display
// list. This is only here because we don't have that logic in the renderer yet. // list. This is only here because we don't have that logic in the renderer yet.
let root_layer = @mut ContainerLayer(); let root_layer = Rc::new(ContainerLayer());
let window_size = window.borrow().size(); let window_size = window.borrow().size();
IOCompositor { IOCompositor {
@ -130,7 +134,7 @@ impl IOCompositor {
port: port, port: port,
opts: opts, opts: opts,
context: rendergl::init_render_context(), context: rendergl::init_render_context(),
root_layer: root_layer, root_layer: root_layer.clone(),
scene: Scene(ContainerLayerKind(root_layer), window_size, identity()), scene: Scene(ContainerLayerKind(root_layer), window_size, identity()),
window_size: Size2D(window_size.width as uint, window_size.height as uint), window_size: Size2D(window_size.width as uint, window_size.height as uint),
graphics_context: CompositorTask::create_graphics_context(), graphics_context: CompositorTask::create_graphics_context(),
@ -317,16 +321,22 @@ impl IOCompositor {
response_chan.send(()); response_chan.send(());
// This assumes there is at most one child, which should be the case. // This assumes there is at most one child, which should be the case.
match self.root_layer.first_child { // NOTE: work around borrowchk
Some(old_layer) => self.root_layer.remove_child(old_layer), {
None => {} let tmp = self.root_layer.borrow().first_child.borrow();
match *tmp.get() {
Some(ref old_layer) => ContainerLayer::remove_child(self.root_layer.clone(),
old_layer.clone()),
None => {}
}
} }
let layer = CompositorLayer::from_frame_tree(frame_tree, let layer = CompositorLayer::from_frame_tree(frame_tree,
self.opts.tile_size, self.opts.tile_size,
Some(10000000u), Some(10000000u),
self.opts.cpu_painting); self.opts.cpu_painting);
self.root_layer.add_child_start(ContainerLayerKind(layer.root_layer)); ContainerLayer::add_child_start(self.root_layer.clone(),
ContainerLayerKind(layer.root_layer.clone()));
// If there's already a root layer, destroy it cleanly. // If there's already a root layer, destroy it cleanly.
match self.compositor_layer { match self.compositor_layer {
@ -360,13 +370,17 @@ impl IOCompositor {
Some(10000000u), Some(10000000u),
self.opts.cpu_painting); self.opts.cpu_painting);
let current_child = self.root_layer.first_child; {
// This assumes there is at most one child, which should be the case. let current_child = self.root_layer.borrow().first_child.borrow();
match current_child { // This assumes there is at most one child, which should be the case.
Some(old_layer) => self.root_layer.remove_child(old_layer), match *current_child.get() {
None => {} Some(ref old_layer) => ContainerLayer::remove_child(self.root_layer.clone(),
old_layer.clone()),
None => {}
}
} }
self.root_layer.add_child_start(ContainerLayerKind(new_layer.root_layer)); ContainerLayer::add_child_start(self.root_layer.clone(),
ContainerLayerKind(new_layer.root_layer.clone()));
self.compositor_layer = Some(new_layer); self.compositor_layer = Some(new_layer);
self.ask_for_tiles(); self.ask_for_tiles();
@ -617,7 +631,7 @@ impl IOCompositor {
self.world_zoom = (self.world_zoom * magnification).max(&1.0); self.world_zoom = (self.world_zoom * magnification).max(&1.0);
let world_zoom = self.world_zoom; let world_zoom = self.world_zoom;
self.root_layer.common.set_transform(identity().scale(world_zoom, world_zoom, 1f32)); self.root_layer.borrow().common.with_mut(|common| common.set_transform(identity().scale(world_zoom, world_zoom, 1f32)));
// Scroll as needed // Scroll as needed
let page_delta = Point2D(window_size.width as f32 * (1.0 / world_zoom - 1.0 / old_world_zoom) * 0.5, let page_delta = Point2D(window_size.width as f32 * (1.0 / world_zoom - 1.0 / old_world_zoom) * 0.5,

View file

@ -22,6 +22,9 @@ use script::dom::event::{ClickEvent, MouseDownEvent, MouseMoveEvent, MouseUpEven
use script::script_task::SendEventMsg; use script::script_task::SendEventMsg;
use servo_msg::compositor_msg::{LayerBuffer, LayerBufferSet, Epoch, Tile}; use servo_msg::compositor_msg::{LayerBuffer, LayerBufferSet, Epoch, Tile};
use servo_msg::constellation_msg::PipelineId; use servo_msg::constellation_msg::PipelineId;
//FIXME: switch to std::rc when we upgrade Rust
use layers::temp_rc::Rc;
//use std::rc::Rc;
use windowing::{MouseWindowEvent, MouseWindowClickEvent, MouseWindowMouseDownEvent}; use windowing::{MouseWindowEvent, MouseWindowClickEvent, MouseWindowMouseDownEvent};
use windowing::{MouseWindowMouseUpEvent}; use windowing::{MouseWindowMouseUpEvent};
use azure::azure_hl::Color; use azure::azure_hl::Color;
@ -57,7 +60,7 @@ pub struct CompositorLayer {
/// The root layer of this CompositorLayer's layer tree. Buffers are collected /// The root layer of this CompositorLayer's layer tree. Buffers are collected
/// from the quadtree and inserted here when the layer is painted to the screen. /// from the quadtree and inserted here when the layer is painted to the screen.
root_layer: @mut ContainerLayer, root_layer: Rc<ContainerLayer>,
/// When set to true, this layer is ignored by its parents. This is useful for /// When set to true, this layer is ignored by its parents. This is useful for
/// soft deletion or when waiting on a page size. /// soft deletion or when waiting on a page size.
@ -80,10 +83,10 @@ pub struct CompositorLayer {
/// Helper struct for keeping CompositorLayer children organized. /// Helper struct for keeping CompositorLayer children organized.
struct CompositorLayerChild { struct CompositorLayerChild {
/// The child itself. /// The child itself.
child: ~CompositorLayer, child: ~CompositorLayer,
/// A ContainerLayer managed by the parent node. This deals with clipping and /// A ContainerLayer managed by the parent node. This deals with clipping and
/// positioning, and is added above the child's layer tree. /// positioning, and is added above the child's layer tree.
container: @mut ContainerLayer, container: Rc<ContainerLayer>,
} }
/// Helper enum for storing quadtrees. Either contains a quadtree, or contains /// Helper enum for storing quadtrees. Either contains a quadtree, or contains
@ -123,7 +126,7 @@ impl CompositorLayer {
tile_size, tile_size,
max_mem)), max_mem)),
}, },
root_layer: @mut ContainerLayer(), root_layer: Rc::new(ContainerLayer()),
hidden: true, hidden: true,
epoch: Epoch(0), epoch: Epoch(0),
scroll_behavior: Scroll, scroll_behavior: Scroll,
@ -142,24 +145,23 @@ impl CompositorLayer {
let mut layer = CompositorLayer::new(pipeline, None, tile_size, max_mem, cpu_painting); let mut layer = CompositorLayer::new(pipeline, None, tile_size, max_mem, cpu_painting);
layer.children = (children.move_iter().map(|child| { layer.children = (children.move_iter().map(|child| {
let SendableChildFrameTree { frame_tree, rect } = child; let SendableChildFrameTree { frame_tree, rect } = child;
let container = @mut ContainerLayer(); let container = Rc::new(ContainerLayer());
match rect { match rect {
Some(rect) => { Some(rect) => {
container.scissor = Some(rect); container.borrow().scissor.set(Some(rect));
container.common.transform = identity().translate(rect.origin.x, container.borrow().common.with_mut(|common| common.transform = identity().translate(rect.origin.x,
rect.origin.y, rect.origin.y,
0f32); 0f32));
} }
None => {} None => {}
} }
let child_layer = ~CompositorLayer::from_frame_tree(frame_tree, let child_layer = ~CompositorLayer::from_frame_tree(frame_tree,
tile_size, tile_size,
max_mem, max_mem,
cpu_painting); cpu_painting);
container.add_child_start(ContainerLayerKind(child_layer.root_layer)); ContainerLayer::add_child_start(container.clone(), ContainerLayerKind(child_layer.root_layer.clone()));
CompositorLayerChild { CompositorLayerChild {
child: child_layer, child: child_layer,
container: container, container: container,
@ -177,7 +179,9 @@ impl CompositorLayer {
-> bool { -> bool {
let cursor = cursor - self.scroll_offset; let cursor = cursor - self.scroll_offset;
for child in self.children.mut_iter().filter(|x| !x.child.hidden) { for child in self.children.mut_iter().filter(|x| !x.child.hidden) {
match child.container.scissor { // NOTE: work around borrowchk
let tmp = child.container.borrow().scissor.borrow();
match *tmp.get() {
None => { None => {
error!("CompositorLayer: unable to perform cursor hit test for layer"); error!("CompositorLayer: unable to perform cursor hit test for layer");
} }
@ -213,9 +217,9 @@ impl CompositorLayer {
return false; return false;
} }
self.root_layer.common.set_transform(identity().translate(self.scroll_offset.x, self.root_layer.borrow().common.with_mut(|common| common.set_transform(identity().translate(self.scroll_offset.x,
self.scroll_offset.y, self.scroll_offset.y,
0.0)); 0.0)));
true true
} }
FixedPosition => false, // Ignore this scroll event. FixedPosition => false, // Ignore this scroll event.
@ -228,7 +232,9 @@ impl CompositorLayer {
pub fn send_mouse_event(&self, event: MouseWindowEvent, cursor: Point2D<f32>) { pub fn send_mouse_event(&self, event: MouseWindowEvent, cursor: Point2D<f32>) {
let cursor = cursor - self.scroll_offset; let cursor = cursor - self.scroll_offset;
for child in self.children.iter().filter(|&x| !x.child.hidden) { for child in self.children.iter().filter(|&x| !x.child.hidden) {
match child.container.scissor { // NOTE: work around borrowchk
let tmp = child.container.borrow().scissor.borrow();
match *tmp.get() {
None => { None => {
error!("CompositorLayer: unable to perform cursor hit test for layer"); error!("CompositorLayer: unable to perform cursor hit test for layer");
} }
@ -287,7 +293,9 @@ impl CompositorLayer {
self.build_layer_tree(graphics_context); self.build_layer_tree(graphics_context);
} }
let transform = |x: &mut CompositorLayerChild| -> bool { let transform = |x: &mut CompositorLayerChild| -> bool {
match x.container.scissor { // NOTE: work around borrowchk
let tmp = x.container.borrow().scissor.borrow();
match *tmp.get() {
Some(scissor) => { Some(scissor) => {
let new_rect = rect.intersection(&scissor); let new_rect = rect.intersection(&scissor);
match new_rect { match new_rect {
@ -323,12 +331,16 @@ impl CompositorLayer {
match self.children.iter().position(|x| pipeline_id == x.child.pipeline.id) { match self.children.iter().position(|x| pipeline_id == x.child.pipeline.id) {
Some(i) => { Some(i) => {
let child_node = &mut self.children[i]; let child_node = &mut self.children[i];
let con = child_node.container; child_node.container.borrow().common.with_mut(|common|
con.common.set_transform(identity().translate(new_rect.origin.x, common.set_transform(identity().translate(new_rect.origin.x,
new_rect.origin.y, new_rect.origin.y,
0.0)); 0.0)));
let old_rect = con.scissor; let old_rect = {
con.scissor = Some(new_rect); // NOTE: work around borrowchk
let tmp = child_node.container.borrow().scissor.borrow();
tmp.get().clone()
};
child_node.container.borrow().scissor.set(Some(new_rect));
match self.quadtree { match self.quadtree {
NoTree(..) => {} // Nothing to do NoTree(..) => {} // Nothing to do
Tree(ref mut quadtree) => { Tree(ref mut quadtree) => {
@ -408,9 +420,10 @@ impl CompositorLayer {
return false; return false;
} }
self.root_layer.common.set_transform(identity().translate(self.scroll_offset.x, self.root_layer.borrow().common.with_mut(|common|
self.scroll_offset.y, common.set_transform(identity().translate(self.scroll_offset.x,
0.0)); self.scroll_offset.y,
0.0)));
true true
} }
FixedPosition => false // Ignore this scroll event. FixedPosition => false // Ignore this scroll event.
@ -465,7 +478,9 @@ impl CompositorLayer {
max_mem)) max_mem))
} }
} }
match child_node.container.scissor { // NOTE: work around borrowchk
let tmp = child_node.container.borrow().scissor.borrow();
match *tmp.get() {
Some(scissor) => { Some(scissor) => {
// Call scroll for bounds checking if the page shrunk. Use (-1, -1) as the cursor position // Call scroll for bounds checking if the page shrunk. Use (-1, -1) as the cursor position
// to make sure the scroll isn't propagated downwards. // to make sure the scroll isn't propagated downwards.
@ -492,15 +507,21 @@ impl CompositorLayer {
// are not rebuilt directly from this method. // are not rebuilt directly from this method.
pub fn build_layer_tree(&mut self, graphics_context: &NativeCompositingGraphicsContext) { pub fn build_layer_tree(&mut self, graphics_context: &NativeCompositingGraphicsContext) {
// Iterate over the children of the container layer. // Iterate over the children of the container layer.
let mut current_layer_child = self.root_layer.first_child; let mut current_layer_child;
// NOTE: work around borrowchk
{
let tmp = self.root_layer.borrow().first_child.borrow();
current_layer_child = tmp.get().clone();
}
// Delete old layer. // Delete old layer.
while current_layer_child.is_some() { while current_layer_child.is_some() {
let trash = current_layer_child.unwrap(); let trash = current_layer_child.clone().unwrap();
current_layer_child.unwrap().with_common(|common| { current_layer_child.clone().unwrap().with_common(|common| {
current_layer_child = common.next_sibling; current_layer_child = common.next_sibling.clone();
}); });
self.root_layer.remove_child(trash); ContainerLayer::remove_child(self.root_layer.clone(), trash);
} }
// Add new tiles. // Add new tiles.
@ -519,7 +540,7 @@ impl CompositorLayer {
// Find or create a texture layer. // Find or create a texture layer.
let texture_layer; let texture_layer;
current_layer_child = match current_layer_child { current_layer_child = match current_layer_child.clone() {
None => { None => {
debug!("osmain: adding new texture layer"); debug!("osmain: adding new texture layer");
@ -536,19 +557,20 @@ impl CompositorLayer {
buffer.native_surface.bind_to_texture(graphics_context, &texture, size); buffer.native_surface.bind_to_texture(graphics_context, &texture, size);
// Make a texture layer and add it. // Make a texture layer and add it.
texture_layer = @mut TextureLayer::new(texture, buffer.screen_pos.size, flip); texture_layer = Rc::new(TextureLayer::new(texture, buffer.screen_pos.size, flip));
self.root_layer.add_child_end(TextureLayerKind(texture_layer)); ContainerLayer::add_child_end(self.root_layer.clone(),
TextureLayerKind(texture_layer.clone()));
None None
} }
Some(TextureLayerKind(existing_texture_layer)) => { Some(TextureLayerKind(existing_texture_layer)) => {
texture_layer = existing_texture_layer; texture_layer = existing_texture_layer.clone();
let texture = &texture_layer.texture; let texture = &existing_texture_layer.borrow().texture;
buffer.native_surface.bind_to_texture(graphics_context, texture, size); buffer.native_surface.bind_to_texture(graphics_context, texture, size);
// Move on to the next sibling. // Move on to the next sibling.
current_layer_child.unwrap().with_common(|common| { current_layer_child.unwrap().with_common(|common| {
common.next_sibling common.next_sibling.clone()
}) })
} }
Some(_) => fail!(~"found unexpected layer kind"), Some(_) => fail!(~"found unexpected layer kind"),
@ -558,17 +580,20 @@ impl CompositorLayer {
let rect = buffer.rect; let rect = buffer.rect;
let transform = identity().translate(rect.origin.x, rect.origin.y, 0.0); let transform = identity().translate(rect.origin.x, rect.origin.y, 0.0);
let transform = transform.scale(rect.size.width, rect.size.height, 1.0); let transform = transform.scale(rect.size.width, rect.size.height, 1.0);
texture_layer.common.set_transform(transform); texture_layer.borrow().common.with_mut(|common| common.set_transform(transform));
} }
// Add child layers. // Add child layers.
for child in self.children.mut_iter().filter(|x| !x.child.hidden) { for child in self.children.mut_iter().filter(|x| !x.child.hidden) {
current_layer_child = match current_layer_child { current_layer_child = match current_layer_child {
None => { None => {
child.container.common.parent = None; child.container.borrow().common.with_mut(|common| {
child.container.common.prev_sibling = None; common.parent = None;
child.container.common.next_sibling = None; common.prev_sibling = None;
self.root_layer.add_child_end(ContainerLayerKind(child.container)); common.next_sibling = None;
});
ContainerLayer::add_child_end(self.root_layer.clone(),
ContainerLayerKind(child.container.clone()));
None None
} }
Some(_) => { Some(_) => {
@ -648,7 +673,9 @@ impl CompositorLayer {
match self.quadtree { match self.quadtree {
NoTree(..) => {} // Nothing to do NoTree(..) => {} // Nothing to do
Tree(ref mut quadtree) => { Tree(ref mut quadtree) => {
match child.container.scissor { // NOTE: work around borrowchk
let tmp = child.container.borrow().scissor.borrow();
match *tmp.get() {
Some(rect) => { Some(rect) => {
quadtree.set_status_page(rect, Normal, false); // Unhide this rect quadtree.set_status_page(rect, Normal, false); // Unhide this rect
} }
@ -692,7 +719,9 @@ impl CompositorLayer {
Tree(ref mut quadtree) => quadtree, Tree(ref mut quadtree) => quadtree,
}; };
for child in self.children.iter().filter(|x| !x.child.hidden) { for child in self.children.iter().filter(|x| !x.child.hidden) {
match child.container.scissor { // NOTE: work around borrowchk
let tmp = child.container.borrow().scissor.borrow();
match *tmp.get() {
None => {} // Nothing to do None => {} // Nothing to do
Some(rect) => { Some(rect) => {
quadtree.set_status_page(rect, Hidden, false); quadtree.set_status_page(rect, Hidden, false);

View file

@ -24,8 +24,11 @@ use servo_net::resource_task;
use servo_util::time::ProfilerChan; use servo_util::time::ProfilerChan;
use servo_util::url::parse_url; use servo_util::url::parse_url;
use servo_util::task::spawn_named; use servo_util::task::spawn_named;
use std::cell::RefCell;
use std::hashmap::{HashMap, HashSet}; use std::hashmap::{HashMap, HashSet};
use std::rc::Rc; //FIXME: switch to std::rc when we upgrade Rust
use layers::temp_rc::Rc;
//use std::rc::Rc;
use std::util::replace; use std::util::replace;
use std::io; use std::io;
use std::libc; use std::libc;
@ -49,27 +52,28 @@ pub struct Constellation {
/// Stores the Id of the outermost frame's pipeline, along with a vector of children frames /// Stores the Id of the outermost frame's pipeline, along with a vector of children frames
struct FrameTree { struct FrameTree {
pipeline: Rc<Pipeline>, pipeline: RefCell<Rc<Pipeline>>,
parent: Option<Rc<Pipeline>>, parent: RefCell<Option<Rc<Pipeline>>>,
children: ~[ChildFrameTree], children: RefCell<~[ChildFrameTree]>,
} }
// Need to clone the FrameTrees, but _not_ the Pipelines // Need to clone the FrameTrees, but _not_ the Pipelines
impl Clone for FrameTree { impl Clone for FrameTree {
fn clone(&self) -> FrameTree { fn clone(&self) -> FrameTree {
let mut children = self.children.iter().map(|child_frame_tree| { let children = self.children.borrow();
let mut children = children.get().iter().map(|child_frame_tree| {
child_frame_tree.clone() child_frame_tree.clone()
}); });
FrameTree { FrameTree {
pipeline: self.pipeline.clone(), pipeline: self.pipeline.clone(),
parent: self.parent.clone(), parent: self.parent.clone(),
children: children.collect(), children: RefCell::new(children.collect()),
} }
} }
} }
struct ChildFrameTree { struct ChildFrameTree {
frame_tree: @mut FrameTree, frame_tree: Rc<FrameTree>,
/// Clipping rect representing the size and position, in page coordinates, of the visible /// Clipping rect representing the size and position, in page coordinates, of the visible
/// region of the child frame relative to the parent. /// region of the child frame relative to the parent.
rect: Option<Rect<f32>>, rect: Option<Rect<f32>>,
@ -78,7 +82,7 @@ struct ChildFrameTree {
impl Clone for ChildFrameTree { impl Clone for ChildFrameTree {
fn clone(&self) -> ChildFrameTree { fn clone(&self) -> ChildFrameTree {
ChildFrameTree { ChildFrameTree {
frame_tree: @mut (*self.frame_tree).clone(), frame_tree: self.frame_tree.clone(),
rect: self.rect.clone(), rect: self.rect.clone(),
} }
} }
@ -104,32 +108,46 @@ pub struct SendableChildFrameTree {
// } // }
enum ReplaceResult { enum ReplaceResult {
ReplacedNode(@mut FrameTree), ReplacedNode(Rc<FrameTree>),
OriginalNode(@mut FrameTree), OriginalNode(Rc<FrameTree>),
} }
impl FrameTree { impl FrameTree {
fn contains(@mut self, id: PipelineId) -> bool { fn contains(&self, id: PipelineId) -> bool {
self.iter().any(|frame_tree| { self.iter().any(|frame_tree| {
id == frame_tree.pipeline.borrow().id // NOTE: work around borrowchk issue
let tmp = frame_tree.borrow().pipeline.borrow();
id == tmp.get().borrow().id
}) })
} }
/// Returns the frame tree whose key is id /// Returns the frame tree whose key is id
fn find(@mut self, id: PipelineId) -> Option<@mut FrameTree> { fn find(&self, id: PipelineId) -> Option<Rc<FrameTree>> {
self.iter().find(|frame_tree| { self.iter().find(|frame_tree| {
id == frame_tree.pipeline.borrow().id // NOTE: work around borrowchk issue
let tmp = frame_tree.borrow().pipeline.borrow();
id == tmp.get().borrow().id
}) })
} }
/// Replaces a node of the frame tree in place. Returns the node that was removed or the original node /// Replaces a node of the frame tree in place. Returns the node that was removed or the original node
/// if the node to replace could not be found. /// if the node to replace could not be found.
fn replace_child(@mut self, id: PipelineId, new_child: @mut FrameTree) -> ReplaceResult { fn replace_child(&self, id: PipelineId, new_child: Rc<FrameTree>) -> ReplaceResult {
for frame_tree in self.iter() { for frame_tree in self.iter() {
let mut child = frame_tree.children.mut_iter() // NOTE: work around mutability issue
.find(|child| child.frame_tree.pipeline.borrow().id == id); let mut children = frame_tree.borrow().children.borrow_mut();
let mut child = children.get().mut_iter()
.find(|child| {
// NOTE: work around borrowchk issue
let tmp = child.frame_tree.borrow().pipeline.borrow();
tmp.get().borrow().id == id
});
for child in child.mut_iter() { for child in child.mut_iter() {
new_child.parent = child.frame_tree.parent.clone(); // NOTE: work around lifetime issues
{
let tmp = child.frame_tree.borrow().parent.borrow();
new_child.borrow().parent.set(tmp.get().clone());
}
return ReplacedNode(replace(&mut child.frame_tree, new_child)); return ReplacedNode(replace(&mut child.frame_tree, new_child));
} }
} }
@ -138,15 +156,23 @@ impl FrameTree {
fn to_sendable(&self) -> SendableFrameTree { fn to_sendable(&self) -> SendableFrameTree {
let sendable_frame_tree = SendableFrameTree { let sendable_frame_tree = SendableFrameTree {
pipeline: self.pipeline.borrow().to_sendable(), pipeline: {
children: self.children.iter().map(|frame_tree| frame_tree.to_sendable()).collect(), // NOTE: work around borrowchk issues
let tmp = self.pipeline.borrow();
tmp.get().borrow().to_sendable()
},
children: {
// NOTE: work around borrowchk issues
let tmp = self.children.borrow();
tmp.get().iter().map(|frame_tree| frame_tree.to_sendable()).collect()
},
}; };
sendable_frame_tree sendable_frame_tree
} }
pub fn iter(@mut self) -> FrameTreeIterator { pub fn iter(&self) -> FrameTreeIterator {
FrameTreeIterator { FrameTreeIterator {
stack: ~[self], stack: ~[Rc::new(self.clone())],
} }
} }
} }
@ -154,7 +180,7 @@ impl FrameTree {
impl ChildFrameTree { impl ChildFrameTree {
fn to_sendable(&self) -> SendableChildFrameTree { fn to_sendable(&self) -> SendableChildFrameTree {
SendableChildFrameTree { SendableChildFrameTree {
frame_tree: self.frame_tree.to_sendable(), frame_tree: self.frame_tree.borrow().to_sendable(),
rect: self.rect, rect: self.rect,
} }
} }
@ -164,15 +190,19 @@ impl ChildFrameTree {
/// Note that this iterator should _not_ be used to mutate nodes _during_ /// Note that this iterator should _not_ be used to mutate nodes _during_
/// iteration. Mutating nodes once the iterator is out of scope is OK. /// iteration. Mutating nodes once the iterator is out of scope is OK.
pub struct FrameTreeIterator { pub struct FrameTreeIterator {
priv stack: ~[@mut FrameTree], priv stack: ~[Rc<FrameTree>],
} }
impl Iterator<@mut FrameTree> for FrameTreeIterator { impl Iterator<Rc<FrameTree>> for FrameTreeIterator {
fn next(&mut self) -> Option<@mut FrameTree> { fn next(&mut self) -> Option<Rc<FrameTree>> {
if !self.stack.is_empty() { if !self.stack.is_empty() {
let next = self.stack.pop(); let next = self.stack.pop();
for &ChildFrameTree { frame_tree, .. } in next.children.rev_iter() { {
self.stack.push(frame_tree); // NOTE: work around borrowchk issues
let tmp = next.borrow().children.borrow();
for cft in tmp.get().rev_iter() {
self.stack.push(cft.frame_tree.clone());
}
} }
Some(next) Some(next)
} else { } else {
@ -184,15 +214,15 @@ impl Iterator<@mut FrameTree> for FrameTreeIterator {
/// Represents the portion of a page that is changing in navigating. /// Represents the portion of a page that is changing in navigating.
struct FrameChange { struct FrameChange {
before: Option<PipelineId>, before: Option<PipelineId>,
after: @mut FrameTree, after: Rc<FrameTree>,
navigation_type: NavigationType, navigation_type: NavigationType,
} }
/// Stores the Id's of the pipelines previous and next in the browser's history /// Stores the Id's of the pipelines previous and next in the browser's history
struct NavigationContext { struct NavigationContext {
previous: ~[@mut FrameTree], previous: ~[Rc<FrameTree>],
next: ~[@mut FrameTree], next: ~[Rc<FrameTree>],
current: Option<@mut FrameTree>, current: Option<Rc<FrameTree>>,
} }
impl NavigationContext { impl NavigationContext {
@ -207,39 +237,45 @@ impl NavigationContext {
/* Note that the following two methods can fail. They should only be called * /* Note that the following two methods can fail. They should only be called *
* when it is known that there exists either a previous page or a next page. */ * when it is known that there exists either a previous page or a next page. */
pub fn back(&mut self) -> @mut FrameTree { pub fn back(&mut self) -> Rc<FrameTree> {
self.next.push(self.current.take_unwrap()); self.next.push(self.current.take_unwrap());
self.current = Some(self.previous.pop()); let prev = self.previous.pop();
self.current.unwrap() self.current = Some(prev.clone());
prev
} }
pub fn forward(&mut self) -> @mut FrameTree { pub fn forward(&mut self) -> Rc<FrameTree> {
self.previous.push(self.current.take_unwrap()); self.previous.push(self.current.take_unwrap());
self.current = Some(self.next.pop()); let next = self.next.pop();
self.current.unwrap() self.current = Some(next.clone());
next
} }
/// Loads a new set of page frames, returning all evicted frame trees /// Loads a new set of page frames, returning all evicted frame trees
pub fn load(&mut self, frame_tree: @mut FrameTree) -> ~[@mut FrameTree] { pub fn load(&mut self, frame_tree: Rc<FrameTree>) -> ~[Rc<FrameTree>] {
debug!("navigating to {:?}", frame_tree.pipeline.borrow().id); debug!("navigating to {:?}", {
// NOTE: work around borrowchk issues
let tmp = frame_tree.borrow().pipeline.borrow();
tmp.get().borrow().id
});
let evicted = replace(&mut self.next, ~[]); let evicted = replace(&mut self.next, ~[]);
if self.current.is_some() { if self.current.is_some() {
self.previous.push(self.current.take_unwrap()); self.previous.push(self.current.take_unwrap());
} }
self.current = Some(frame_tree); self.current = Some(frame_tree.clone());
evicted evicted
} }
/// Returns the frame trees whose keys are pipeline_id. /// Returns the frame trees whose keys are pipeline_id.
pub fn find_all(&mut self, pipeline_id: PipelineId) -> ~[@mut FrameTree] { pub fn find_all(&mut self, pipeline_id: PipelineId) -> ~[Rc<FrameTree>] {
let from_current = self.current.iter().filter_map(|frame_tree| { let from_current = self.current.iter().filter_map(|frame_tree| {
frame_tree.find(pipeline_id) frame_tree.borrow().find(pipeline_id)
}); });
let from_next = self.next.iter().filter_map(|frame_tree| { let from_next = self.next.iter().filter_map(|frame_tree| {
frame_tree.find(pipeline_id) frame_tree.borrow().find(pipeline_id)
}); });
let from_prev = self.previous.iter().filter_map(|frame_tree| { let from_prev = self.previous.iter().filter_map(|frame_tree| {
frame_tree.find(pipeline_id) frame_tree.borrow().find(pipeline_id)
}); });
from_prev.chain(from_current).chain(from_next).collect() from_prev.chain(from_current).chain(from_next).collect()
} }
@ -251,7 +287,7 @@ impl NavigationContext {
let mut all_contained = from_prev.chain(from_current).chain(from_next); let mut all_contained = from_prev.chain(from_current).chain(from_next);
all_contained.any(|frame_tree| { all_contained.any(|frame_tree| {
frame_tree.contains(pipeline_id) frame_tree.borrow().contains(pipeline_id)
}) })
} }
} }
@ -302,18 +338,18 @@ impl Constellation {
*self.next_pipeline_id += 1; *self.next_pipeline_id += 1;
id id
} }
/// Convenience function for getting the currently active frame tree. /// Convenience function for getting the currently active frame tree.
/// The currently active frame tree should always be the current painter /// The currently active frame tree should always be the current painter
fn current_frame<'a>(&'a self) -> &'a Option<@mut FrameTree> { fn current_frame<'a>(&'a self) -> &'a Option<Rc<FrameTree>> {
&self.navigation_context.current &self.navigation_context.current
} }
/// Returns both the navigation context and pending frame trees whose keys are pipeline_id. /// Returns both the navigation context and pending frame trees whose keys are pipeline_id.
pub fn find_all(&mut self, pipeline_id: PipelineId) -> ~[@mut FrameTree] { pub fn find_all(&mut self, pipeline_id: PipelineId) -> ~[Rc<FrameTree>] {
let matching_navi_frames = self.navigation_context.find_all(pipeline_id); let matching_navi_frames = self.navigation_context.find_all(pipeline_id);
let matching_pending_frames = self.pending_frames.iter().filter_map(|frame_change| { let matching_pending_frames = self.pending_frames.iter().filter_map(|frame_change| {
frame_change.after.find(pipeline_id) frame_change.after.borrow().find(pipeline_id)
}); });
matching_navi_frames.move_iter().chain(matching_pending_frames).collect() matching_navi_frames.move_iter().chain(matching_pending_frames).collect()
} }
@ -398,12 +434,12 @@ impl Constellation {
let old_pipeline = match self.pipelines.find(&pipeline_id) { let old_pipeline = match self.pipelines.find(&pipeline_id) {
None => return, // already failed? None => return, // already failed?
Some(id) => *id Some(id) => id.clone()
}; };
old_pipeline.script_chan.try_send(ExitPipelineMsg(pipeline_id)); old_pipeline.borrow().script_chan.try_send(ExitPipelineMsg(pipeline_id));
old_pipeline.render_chan.try_send(render_task::ExitMsg(None)); old_pipeline.borrow().render_chan.try_send(render_task::ExitMsg(None));
old_pipeline.layout_chan.try_send(layout_interface::ExitNowMsg); old_pipeline.borrow().layout_chan.try_send(layout_interface::ExitNowMsg);
self.pipelines.remove(&pipeline_id); self.pipelines.remove(&pipeline_id);
let new_id = self.get_next_pipeline_id(); let new_id = self.get_next_pipeline_id();
@ -419,17 +455,17 @@ impl Constellation {
let url = parse_url("about:failure", None); let url = parse_url("about:failure", None);
pipeline.load(url); pipeline.load(url);
let pipeline_wrapped = Rc::from_send(pipeline); let pipeline_wrapped = Rc::new(pipeline);
self.pending_frames.push(FrameChange{ self.pending_frames.push(FrameChange{
before: Some(pipeline_id), before: Some(pipeline_id),
after: Rc::from_send(FrameTree { after: Rc::new(FrameTree {
pipeline: pipeline_wrapped.clone(), pipeline: RefCell::new(pipeline_wrapped.clone()),
parent: None, parent: RefCell::new(None),
children: ~[], children: RefCell::new(~[]),
}), }),
navigation_type: constellation_msg::Navigate, navigation_type: constellation_msg::Navigate,
}); });
self.pipelines.insert(pipeline_id, pipeline_wrapped); self.pipelines.insert(pipeline_id, pipeline_wrapped);
} }
@ -444,27 +480,30 @@ impl Constellation {
self.window_size, self.window_size,
self.opts.clone()); self.opts.clone());
pipeline.load(url); pipeline.load(url);
let pipeline_wrapped = Rc::from_send(pipeline); let pipeline_wrapped = Rc::new(pipeline);
self.pending_frames.push(FrameChange { self.pending_frames.push(FrameChange {
before: None, before: None,
after: @mut FrameTree { after: Rc::new(FrameTree {
pipeline: pipeline_wrapped.clone(), pipeline: RefCell::new(pipeline_wrapped.clone()),
parent: None, parent: RefCell::new(None),
children: ~[], children: RefCell::new(~[]),
}, }),
navigation_type: constellation_msg::Load, navigation_type: constellation_msg::Load,
}); });
self.pipelines.insert(pipeline_wrapped.borrow().id, pipeline_wrapped); self.pipelines.insert(pipeline_wrapped.borrow().id, pipeline_wrapped);
} }
fn handle_frame_rect_msg(&mut self, pipeline_id: PipelineId, subpage_id: SubpageId, rect: Rect<f32>) { fn handle_frame_rect_msg(&mut self, pipeline_id: PipelineId, subpage_id: SubpageId, rect: Rect<f32>) {
debug!("Received frame rect {} from {:?}, {:?}", rect, pipeline_id, subpage_id); debug!("Received frame rect {} from {:?}, {:?}", rect, pipeline_id, subpage_id);
let mut already_sent = HashSet::new(); let mut already_sent = HashSet::new();
// Returns true if a child frame tree's subpage id matches the given subpage id // Returns true if a child frame tree's subpage id matches the given subpage id
let subpage_eq = |child_frame_tree: & &mut ChildFrameTree| { let subpage_eq = |child_frame_tree: & &mut ChildFrameTree| {
child_frame_tree.frame_tree.pipeline.borrow().subpage_id.expect("Constellation: // NOTE: work around borrowchk issues
let tmp = child_frame_tree.frame_tree.borrow().pipeline.borrow();
tmp.get().borrow().
subpage_id.expect("Constellation:
child frame does not have a subpage id. This should not be possible.") child frame does not have a subpage id. This should not be possible.")
== subpage_id == subpage_id
}; };
@ -474,22 +513,23 @@ impl Constellation {
// resize happens immediately. // resize happens immediately.
let update_child_rect = |child_frame_tree: &mut ChildFrameTree, is_active: bool| { let update_child_rect = |child_frame_tree: &mut ChildFrameTree, is_active: bool| {
child_frame_tree.rect = Some(rect.clone()); child_frame_tree.rect = Some(rect.clone());
let pipeline = &child_frame_tree.frame_tree.pipeline; // NOTE: work around borrowchk issues
if !already_sent.contains(&pipeline.borrow().id) { let pipeline = &child_frame_tree.frame_tree.borrow().pipeline.borrow();
if !already_sent.contains(&pipeline.get().borrow().id) {
let Size2D { width, height } = rect.size; let Size2D { width, height } = rect.size;
if is_active { if is_active {
let pipeline = pipeline.borrow(); let pipeline = pipeline.get().borrow();
pipeline.script_chan.send(ResizeMsg(pipeline.id, Size2D { pipeline.script_chan.send(ResizeMsg(pipeline.id, Size2D {
width: width as uint, width: width as uint,
height: height as uint height: height as uint
})); }));
self.compositor_chan.send(SetLayerClipRect(pipeline.id, rect)); self.compositor_chan.send(SetLayerClipRect(pipeline.id, rect));
} else { } else {
let pipeline = pipeline.borrow(); let pipeline = pipeline.get().borrow();
pipeline.script_chan.send(ResizeInactiveMsg(pipeline.id, pipeline.script_chan.send(ResizeInactiveMsg(pipeline.id,
Size2D(width as uint, height as uint))); Size2D(width as uint, height as uint)));
} }
let pipeline = pipeline.borrow(); let pipeline = pipeline.get().borrow();
already_sent.insert(pipeline.id); already_sent.insert(pipeline.id);
} }
}; };
@ -497,10 +537,11 @@ impl Constellation {
// If the subframe is in the current frame tree, the compositor needs the new size // If the subframe is in the current frame tree, the compositor needs the new size
for current_frame in self.current_frame().iter() { for current_frame in self.current_frame().iter() {
debug!("Constellation: Sending size for frame in current frame tree."); debug!("Constellation: Sending size for frame in current frame tree.");
let source_frame = current_frame.find(pipeline_id); let source_frame = current_frame.borrow().find(pipeline_id);
for source_frame in source_frame.iter() { for source_frame in source_frame.iter() {
let found_child = source_frame.children.mut_iter() // NOTE: work around borrowchk issues
.find(|child| subpage_eq(child)); let mut tmp = source_frame.borrow().children.borrow_mut();
let found_child = tmp.get().mut_iter().find(|child| subpage_eq(child));
found_child.map(|child| update_child_rect(child, true)); found_child.map(|child| update_child_rect(child, true));
} }
} }
@ -508,8 +549,9 @@ impl Constellation {
// Update all frames with matching pipeline- and subpage-ids // Update all frames with matching pipeline- and subpage-ids
let frames = self.find_all(pipeline_id); let frames = self.find_all(pipeline_id);
for frame_tree in frames.iter() { for frame_tree in frames.iter() {
let found_child = frame_tree.children.mut_iter() // NOTE: work around borrowchk issues
.find(|child| subpage_eq(child)); let mut tmp = frame_tree.borrow().children.borrow_mut();
let found_child = tmp.get().mut_iter().find(|child| subpage_eq(child));
found_child.map(|child| update_child_rect(child, false)); found_child.map(|child| update_child_rect(child, false));
} }
@ -532,10 +574,10 @@ impl Constellation {
// or a new url entered. // or a new url entered.
// Start by finding the frame trees matching the pipeline id, // Start by finding the frame trees matching the pipeline id,
// and add the new pipeline to their sub frames. // and add the new pipeline to their sub frames.
let frame_trees: ~[@mut FrameTree] = { let frame_trees: ~[Rc<FrameTree>] = {
let matching_navi_frames = self.navigation_context.find_all(source_pipeline_id); let matching_navi_frames = self.navigation_context.find_all(source_pipeline_id);
let matching_pending_frames = self.pending_frames.iter().filter_map(|frame_change| { let matching_pending_frames = self.pending_frames.iter().filter_map(|frame_change| {
frame_change.after.find(source_pipeline_id) frame_change.after.borrow().find(source_pipeline_id)
}); });
matching_navi_frames.move_iter().chain(matching_pending_frames).collect() matching_navi_frames.move_iter().chain(matching_pending_frames).collect()
}; };
@ -588,15 +630,17 @@ impl Constellation {
debug!("Constellation: sending load msg to pipeline {:?}", pipeline.id); debug!("Constellation: sending load msg to pipeline {:?}", pipeline.id);
pipeline.load(url); pipeline.load(url);
let pipeline_wrapped = Rc::from_send(pipeline); let pipeline_wrapped = Rc::new(pipeline);
let rect = self.pending_sizes.pop(&(source_pipeline_id, subpage_id)); let rect = self.pending_sizes.pop(&(source_pipeline_id, subpage_id));
for frame_tree in frame_trees.iter() { for frame_tree in frame_trees.iter() {
frame_tree.children.push(ChildFrameTree { // NOTE: work around borrowchk issues
frame_tree: @mut FrameTree { let mut tmp = frame_tree.borrow().children.borrow_mut();
pipeline: pipeline_wrapped.clone(), tmp.get().push(ChildFrameTree {
parent: Some(source_pipeline.clone()), frame_tree: Rc::new(FrameTree {
children: ~[], pipeline: RefCell::new(pipeline_wrapped.clone()),
}, parent: RefCell::new(Some(source_pipeline.clone())),
children: RefCell::new(~[]),
}),
rect: rect, rect: rect,
}); });
} }
@ -606,7 +650,7 @@ impl Constellation {
fn handle_load_url_msg(&mut self, source_id: PipelineId, url: Url) { fn handle_load_url_msg(&mut self, source_id: PipelineId, url: Url) {
debug!("Constellation: received message to load {:s}", url.to_str()); debug!("Constellation: received message to load {:s}", url.to_str());
// Make sure no pending page would be overridden. // Make sure no pending page would be overridden.
let source_frame = self.current_frame().get_ref().find(source_id).expect( let source_frame = self.current_frame().get_ref().borrow().find(source_id).expect(
"Constellation: received a LoadUrlMsg from a pipeline_id associated "Constellation: received a LoadUrlMsg from a pipeline_id associated
with a pipeline not in the active frame tree. This should be with a pipeline not in the active frame tree. This should be
impossible."); impossible.");
@ -615,10 +659,10 @@ impl Constellation {
let old_id = frame_change.before.expect("Constellation: Received load msg let old_id = frame_change.before.expect("Constellation: Received load msg
from pipeline, but there is no currently active page. This should from pipeline, but there is no currently active page. This should
be impossible."); be impossible.");
let changing_frame = self.current_frame().get_ref().find(old_id).expect("Constellation: let changing_frame = self.current_frame().get_ref().borrow().find(old_id).expect("Constellation:
Pending change has non-active source pipeline. This should be Pending change has non-active source pipeline. This should be
impossible."); impossible.");
if changing_frame.contains(source_id) || source_frame.contains(old_id) { if changing_frame.borrow().contains(source_id) || source_frame.borrow().contains(old_id) {
// id that sent load msg is being changed already; abort // id that sent load msg is being changed already; abort
return; return;
} }
@ -626,8 +670,10 @@ impl Constellation {
// Being here means either there are no pending frames, or none of the pending // Being here means either there are no pending frames, or none of the pending
// changes would be overriden by changing the subframe associated with source_id. // changes would be overriden by changing the subframe associated with source_id.
let parent = source_frame.parent.clone(); let parent = source_frame.borrow().parent.clone();
let subpage_id = source_frame.pipeline.borrow().subpage_id; // NOTE: work around borrowchk issues
let tmp = source_frame.borrow().pipeline.borrow();
let subpage_id = tmp.get().borrow().subpage_id;
let next_pipeline_id = self.get_next_pipeline_id(); let next_pipeline_id = self.get_next_pipeline_id();
let pipeline = Pipeline::create(next_pipeline_id, let pipeline = Pipeline::create(next_pipeline_id,
@ -641,20 +687,20 @@ impl Constellation {
self.opts.clone()); self.opts.clone());
pipeline.load(url); pipeline.load(url);
let pipeline_wrapped = Rc::from_send(pipeline); let pipeline_wrapped = Rc::new(pipeline);
self.pending_frames.push(FrameChange{ self.pending_frames.push(FrameChange{
before: Some(source_id), before: Some(source_id),
after: @mut FrameTree { after: Rc::new(FrameTree {
pipeline: pipeline_wrapped.clone(), pipeline: RefCell::new(pipeline_wrapped.clone()),
parent: parent, parent: parent,
children: ~[], children: RefCell::new(~[]),
}, }),
navigation_type: constellation_msg::Load, navigation_type: constellation_msg::Load,
}); });
self.pipelines.insert(pipeline_wrapped.borrow().id, pipeline_wrapped); self.pipelines.insert(pipeline_wrapped.borrow().id, pipeline_wrapped);
} }
fn handle_navigate_msg(&mut self, direction: constellation_msg::NavigationDirection) { fn handle_navigate_msg(&mut self, direction: constellation_msg::NavigationDirection) {
debug!("received message to navigate {:?}", direction); debug!("received message to navigate {:?}", direction);
@ -669,8 +715,10 @@ impl Constellation {
return; return;
} else { } else {
let old = self.current_frame().get_ref(); let old = self.current_frame().get_ref();
for frame in old.iter() { for frame in old.borrow().iter() {
frame.pipeline.borrow().revoke_paint_permission(); // NOTE: work around borrowchk issues
let tmp = frame.borrow().pipeline.borrow();
tmp.get().borrow().revoke_paint_permission();
} }
} }
self.navigation_context.forward() self.navigation_context.forward()
@ -681,35 +729,40 @@ impl Constellation {
return; return;
} else { } else {
let old = self.current_frame().get_ref(); let old = self.current_frame().get_ref();
for frame in old.iter() { for frame in old.borrow().iter() {
frame.pipeline.borrow().revoke_paint_permission(); // NOTE: work around borrowchk issues
let tmp = frame.borrow().pipeline.borrow();
tmp.get().borrow().revoke_paint_permission();
} }
} }
self.navigation_context.back() self.navigation_context.back()
} }
}; };
for frame in destination_frame.iter() { for frame in destination_frame.borrow().iter() {
let pipeline = &frame.pipeline; // NOTE: work around borrowchk issues
pipeline.borrow().reload(); let pipeline = &frame.borrow().pipeline.borrow();
pipeline.get().borrow().reload();
} }
self.grant_paint_permission(destination_frame, constellation_msg::Navigate); self.grant_paint_permission(destination_frame, constellation_msg::Navigate);
} }
fn handle_renderer_ready_msg(&mut self, pipeline_id: PipelineId) { fn handle_renderer_ready_msg(&mut self, pipeline_id: PipelineId) {
debug!("Renderer {:?} ready to send paint msg", pipeline_id); debug!("Renderer {:?} ready to send paint msg", pipeline_id);
// This message could originate from a pipeline in the navigation context or // This message could originate from a pipeline in the navigation context or
// from a pending frame. The only time that we will grant paint permission is // from a pending frame. The only time that we will grant paint permission is
// when the message originates from a pending frame or the current frame. // when the message originates from a pending frame or the current frame.
for &current_frame in self.current_frame().iter() { for current_frame in self.current_frame().iter() {
// Messages originating in the current frame are not navigations; // Messages originating in the current frame are not navigations;
// TODO(tkuehn): In fact, this kind of message might be provably // TODO(tkuehn): In fact, this kind of message might be provably
// impossible to occur. // impossible to occur.
if current_frame.contains(pipeline_id) { if current_frame.borrow().contains(pipeline_id) {
for frame in current_frame.iter() { for frame in current_frame.borrow().iter() {
frame.pipeline.borrow().grant_paint_permission(); // NOTE: work around borrowchk issues
let tmp = frame.borrow().pipeline.borrow();
tmp.get().borrow().grant_paint_permission();
} }
return; return;
} }
@ -719,53 +772,87 @@ impl Constellation {
// If it is not found, it simply means that this pipeline will not receive // If it is not found, it simply means that this pipeline will not receive
// permission to paint. // permission to paint.
let pending_index = self.pending_frames.iter().rposition(|frame_change| { let pending_index = self.pending_frames.iter().rposition(|frame_change| {
frame_change.after.pipeline.borrow().id == pipeline_id // NOTE: work around borrowchk issues
let tmp = frame_change.after.borrow().pipeline.borrow();
tmp.get().borrow().id == pipeline_id
}); });
for &pending_index in pending_index.iter() { for &pending_index in pending_index.iter() {
let frame_change = self.pending_frames.swap_remove(pending_index); let frame_change = self.pending_frames.swap_remove(pending_index);
let to_add = frame_change.after; let to_add = frame_change.after.clone();
// Create the next frame tree that will be given to the compositor // Create the next frame tree that will be given to the compositor
let next_frame_tree = match to_add.parent.clone() { // NOTE: work around borrowchk issues
None => to_add, // to_add is the root let tmp = to_add.borrow().parent.clone();
Some(_parent) => @mut (*self.current_frame().unwrap()).clone(), let tmp = tmp.borrow();
let next_frame_tree = if tmp.get().is_some() {
// NOTE: work around borrowchk issues
let tmp = self.current_frame().get_ref();
tmp.clone()
} else {
to_add.clone()
}; };
// If there are frames to revoke permission from, do so now. // If there are frames to revoke permission from, do so now.
match frame_change.before { match frame_change.before {
Some(revoke_id) => { Some(revoke_id) => {
debug!("Constellation: revoking permission from {:?}", revoke_id); debug!("Constellation: revoking permission from {:?}", revoke_id);
let current_frame = self.current_frame().unwrap(); let current_frame = self.current_frame().get_ref();
let to_revoke = current_frame.find(revoke_id).expect( let to_revoke = current_frame.borrow().find(revoke_id).expect(
"Constellation: pending frame change refers to an old "Constellation: pending frame change refers to an old
frame not contained in the current frame. This is a bug"); frame not contained in the current frame. This is a bug");
for frame in to_revoke.iter() { for frame in to_revoke.borrow().iter() {
frame.pipeline.borrow().revoke_paint_permission(); // NOTE: work around borrowchk issues
let tmp = frame.borrow().pipeline.borrow();
tmp.get().borrow().revoke_paint_permission();
} }
// If to_add is not the root frame, then replace revoked_frame with it. // If to_add is not the root frame, then replace revoked_frame with it.
// This conveniently keeps scissor rect size intact. // This conveniently keeps scissor rect size intact.
if to_add.parent.is_some() { // NOTE: work around borrowchk issue
debug!("Constellation: replacing {:?} with {:?} in {:?}", let mut flag = false;
revoke_id, to_add.pipeline.borrow().id, next_frame_tree.pipeline.borrow().id); {
next_frame_tree.replace_child(revoke_id, to_add); // NOTE: work around borrowchk issue
let tmp = to_add.borrow().parent.borrow();
if tmp.get().is_some() {
debug!("Constellation: replacing {:?} with {:?} in {:?}",
revoke_id, {
// NOTE: work around borrowchk issues
let tmp = to_add.borrow().pipeline.borrow();
tmp.get().borrow().id
}, {
// NOTE: work around borrowchk issues
let tmp = next_frame_tree.borrow().pipeline.borrow();
tmp.get().borrow().id
});
flag = true;
}
}
if flag {
next_frame_tree.borrow().replace_child(revoke_id, to_add);
} }
} }
None => { None => {
// Add to_add to parent's children, if it is not the root // Add to_add to parent's children, if it is not the root
let parent = &to_add.parent; let parent = &to_add.borrow().parent;
for parent in parent.iter() { // NOTE: work around borrowchk issue
let subpage_id = to_add.pipeline.borrow().subpage_id.expect("Constellation: let tmp = parent.borrow();
for parent in tmp.get().iter() {
// NOTE: work around borrowchk issues
let tmp = to_add.borrow().pipeline.borrow();
let subpage_id = tmp.get().borrow().subpage_id
.expect("Constellation:
Child frame's subpage id is None. This should be impossible."); Child frame's subpage id is None. This should be impossible.");
let rect = self.pending_sizes.pop(&(parent.borrow().id, subpage_id)); let rect = self.pending_sizes.pop(&(parent.borrow().id, subpage_id));
let parent = next_frame_tree.find(parent.borrow().id).expect( let parent = next_frame_tree.borrow().find(parent.borrow().id).expect(
"Constellation: pending frame has a parent frame that is not "Constellation: pending frame has a parent frame that is not
active. This is a bug."); active. This is a bug.");
parent.children.push(ChildFrameTree { // NOTE: work around borrowchk issue
frame_tree: to_add, let mut tmp = parent.borrow().children.borrow_mut();
tmp.get().push(ChildFrameTree {
frame_tree: to_add.clone(),
rect: rect, rect: rect,
}); });
} }
@ -781,16 +868,19 @@ impl Constellation {
let mut already_seen = HashSet::new(); let mut already_seen = HashSet::new();
for frame_tree in self.current_frame().iter() { for frame_tree in self.current_frame().iter() {
debug!("constellation sending resize message to active frame"); debug!("constellation sending resize message to active frame");
let pipeline = frame_tree.pipeline.borrow(); // NOTE: work around borrowchk issues
let tmp = frame_tree.borrow().pipeline.borrow();
let pipeline = tmp.get().borrow();
pipeline.script_chan.try_send(ResizeMsg(pipeline.id, new_size)); pipeline.script_chan.try_send(ResizeMsg(pipeline.id, new_size));
already_seen.insert(pipeline.id); already_seen.insert(pipeline.id);
} }
for frame_tree in self.navigation_context.previous.iter() for frame_tree in self.navigation_context.previous.iter()
.chain(self.navigation_context.next.iter()) { .chain(self.navigation_context.next.iter()) {
let pipeline = &frame_tree.pipeline; // NOTE: work around borrowchk issues
if !already_seen.contains(&pipeline.borrow().id) { let tmp = frame_tree.borrow().pipeline.borrow();
let pipeline = &tmp.get().borrow();
if !already_seen.contains(&pipeline.id) {
debug!("constellation sending resize message to inactive frame"); debug!("constellation sending resize message to inactive frame");
let pipeline = pipeline.borrow();
pipeline.script_chan.try_send(ResizeInactiveMsg(pipeline.id, new_size)); pipeline.script_chan.try_send(ResizeInactiveMsg(pipeline.id, new_size));
already_seen.insert(pipeline.id); already_seen.insert(pipeline.id);
} }
@ -799,10 +889,14 @@ impl Constellation {
// If there are any pending outermost frames, then tell them to resize. (This is how the // If there are any pending outermost frames, then tell them to resize. (This is how the
// initial window size gets sent to the first page loaded, giving it permission to reflow.) // initial window size gets sent to the first page loaded, giving it permission to reflow.)
for change in self.pending_frames.iter() { for change in self.pending_frames.iter() {
let frame_tree = change.after; let frame_tree = change.after.borrow();
if frame_tree.parent.is_none() { // NOTE: work around borrowchk issue
let tmp = frame_tree.parent.borrow();
if tmp.get().is_none() {
debug!("constellation sending resize message to pending outer frame"); debug!("constellation sending resize message to pending outer frame");
let pipeline = frame_tree.pipeline.borrow(); // NOTE: work around borrowchk issues
let tmp = frame_tree.pipeline.borrow();
let pipeline = tmp.get().borrow();
pipeline.script_chan.send(ResizeMsg(pipeline.id, new_size)) pipeline.script_chan.send(ResizeMsg(pipeline.id, new_size))
} }
} }
@ -811,32 +905,38 @@ impl Constellation {
} }
// Close all pipelines at and beneath a given frame // Close all pipelines at and beneath a given frame
fn close_pipelines(&mut self, frame_tree: @mut FrameTree) { fn close_pipelines(&mut self, frame_tree: Rc<FrameTree>) {
// TODO(tkuehn): should only exit once per unique script task, // TODO(tkuehn): should only exit once per unique script task,
// and then that script task will handle sub-exits // and then that script task will handle sub-exits
for frame_tree in frame_tree.iter() { for frame_tree in frame_tree.borrow().iter() {
let pipeline = frame_tree.pipeline.borrow(); // NOTE: work around borrowchk issues
let tmp = frame_tree.borrow().pipeline.borrow();
let pipeline = tmp.get().borrow();
pipeline.exit(); pipeline.exit();
self.pipelines.remove(&pipeline.id); self.pipelines.remove(&pipeline.id);
} }
} }
fn handle_evicted_frames(&mut self, evicted: ~[@mut FrameTree]) { fn handle_evicted_frames(&mut self, evicted: ~[Rc<FrameTree>]) {
for &frame_tree in evicted.iter() { for frame_tree in evicted.iter() {
if !self.navigation_context.contains(frame_tree.pipeline.borrow().id) { // NOTE: work around borrowchk issues
self.close_pipelines(frame_tree); let tmp = frame_tree.borrow().pipeline.borrow();
if !self.navigation_context.contains(tmp.get().borrow().id) {
self.close_pipelines(frame_tree.clone());
} else { } else {
self.handle_evicted_frames(frame_tree.children.iter() // NOTE: work around borrowchk issue
.map(|child| child.frame_tree) let tmp = frame_tree.borrow().children.borrow();
.collect()); let mut frames = tmp.get().iter()
.map(|child| child.frame_tree.clone());
self.handle_evicted_frames(frames.collect());
} }
} }
} }
// Grants a frame tree permission to paint; optionally updates navigation to reflect a new page // Grants a frame tree permission to paint; optionally updates navigation to reflect a new page
fn grant_paint_permission(&mut self, frame_tree: @mut FrameTree, navigation_type: NavigationType) { fn grant_paint_permission(&mut self, frame_tree: Rc<FrameTree>, navigation_type: NavigationType) {
// Give permission to paint to the new frame and all child frames // Give permission to paint to the new frame and all child frames
self.set_ids(frame_tree); self.set_ids(&frame_tree);
// Don't call navigation_context.load() on a Navigate type (or None, as in the case of // Don't call navigation_context.load() on a Navigate type (or None, as in the case of
// parsed iframes that finish loading) // parsed iframes that finish loading)
@ -849,14 +949,17 @@ impl Constellation {
} }
} }
fn set_ids(&self, frame_tree: @mut FrameTree) { fn set_ids(&self, frame_tree: &Rc<FrameTree>) {
let (port, chan) = Chan::new(); let (port, chan) = Chan::new();
debug!("Constellation sending SetIds"); debug!("Constellation sending SetIds");
self.compositor_chan.send(SetIds(frame_tree.to_sendable(), chan, self.chan.clone())); self.compositor_chan.send(SetIds(frame_tree.borrow().to_sendable(), chan, self.chan.clone()));
match port.recv_opt() { match port.recv_opt() {
Some(()) => { Some(()) => {
for frame in frame_tree.iter() { let mut iter = frame_tree.borrow().iter();
frame.pipeline.borrow().grant_paint_permission(); for frame in iter {
// NOTE: work around borrowchk issues
let tmp = frame.borrow().pipeline.borrow();
tmp.get().borrow().grant_paint_permission();
} }
} }
None => {} // message has been discarded, probably shutting down None => {} // message has been discarded, probably shutting down

View file

@ -20,7 +20,9 @@ use servo_net::image_cache_task::ImageCacheTask;
use servo_net::resource_task::ResourceTask; use servo_net::resource_task::ResourceTask;
use servo_util::time::ProfilerChan; use servo_util::time::ProfilerChan;
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; //FIXME: switch to std::rc when we upgrade Rust
use layers::temp_rc::Rc;
//use std::rc::Rc;
/// A uniquely-identifiable pipeline of script task, layout task, and render task. /// A uniquely-identifiable pipeline of script task, layout task, and render task.
pub struct Pipeline { pub struct Pipeline {

View file

@ -27,4 +27,3 @@ pub mod time;
pub mod url; pub mod url;
pub mod vec; pub mod vec;
pub mod workqueue; pub mod workqueue;