mirror of
https://github.com/servo/servo.git
synced 2025-08-06 22:15:33 +01:00
reorganized constellation.
compositor routes dom events via constellation. constellation handles iframe sizing and resizing.
This commit is contained in:
parent
e4d44fb8d2
commit
86f0aacb3d
5 changed files with 445 additions and 348 deletions
|
@ -136,7 +136,7 @@ impl<C: RenderListener + Send> RenderTask<C> {
|
||||||
match self.port.recv() {
|
match self.port.recv() {
|
||||||
RenderMsg(render_layer) => {
|
RenderMsg(render_layer) => {
|
||||||
if self.paint_permission {
|
if self.paint_permission {
|
||||||
self.compositor.new_layer(self.id, render_layer.size);
|
self.compositor.resize_layer(self.id, render_layer.size);
|
||||||
}
|
}
|
||||||
self.render_layer = Some(render_layer);
|
self.render_layer = Some(render_layer);
|
||||||
}
|
}
|
||||||
|
@ -147,7 +147,7 @@ impl<C: RenderListener + Send> RenderTask<C> {
|
||||||
self.paint_permission = true;
|
self.paint_permission = true;
|
||||||
match self.render_layer {
|
match self.render_layer {
|
||||||
Some(ref render_layer) => {
|
Some(ref render_layer) => {
|
||||||
self.compositor.new_layer(self.id, render_layer.size);
|
self.compositor.resize_layer(self.id, render_layer.size);
|
||||||
}
|
}
|
||||||
None => {}
|
None => {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use platform::{Application, Window};
|
use platform::{Application, Window};
|
||||||
use script::dom::event::ResizeEvent;
|
|
||||||
use script::script_task::{LoadMsg, NavigateMsg, SendEventMsg};
|
|
||||||
|
|
||||||
pub use windowing;
|
pub use windowing;
|
||||||
use windowing::{ApplicationMethods, WindowEvent, WindowMethods};
|
use windowing::{ApplicationMethods, WindowEvent, WindowMethods};
|
||||||
|
@ -14,7 +12,7 @@ use windowing::{QuitWindowEvent, MouseWindowClickEvent, MouseWindowMouseDownEven
|
||||||
|
|
||||||
use servo_msg::compositor_msg::{RenderListener, LayerBufferSet, RenderState};
|
use servo_msg::compositor_msg::{RenderListener, LayerBufferSet, RenderState};
|
||||||
use servo_msg::compositor_msg::{ReadyState, ScriptListener};
|
use servo_msg::compositor_msg::{ReadyState, ScriptListener};
|
||||||
use servo_msg::constellation_msg::PipelineId;
|
use servo_msg::constellation_msg::{ConstellationChan, NavigateMsg, PipelineId, ResizedWindowMsg, LoadUrlMsg};
|
||||||
use servo_msg::constellation_msg;
|
use servo_msg::constellation_msg;
|
||||||
use gfx::opts::Opts;
|
use gfx::opts::Opts;
|
||||||
|
|
||||||
|
@ -40,11 +38,11 @@ use servo_util::{time, url};
|
||||||
use servo_util::time::profile;
|
use servo_util::time::profile;
|
||||||
use servo_util::time::ProfilerChan;
|
use servo_util::time::ProfilerChan;
|
||||||
|
|
||||||
|
use extra::future::from_value;
|
||||||
use extra::time::precise_time_s;
|
use extra::time::precise_time_s;
|
||||||
use extra::arc;
|
use extra::arc;
|
||||||
|
|
||||||
use constellation::SendableFrameTree;
|
use constellation::SendableFrameTree;
|
||||||
use pipeline::Pipeline;
|
|
||||||
use compositing::compositor_layer::CompositorLayer;
|
use compositing::compositor_layer::CompositorLayer;
|
||||||
|
|
||||||
mod quadtree;
|
mod quadtree;
|
||||||
|
@ -86,10 +84,12 @@ impl RenderListener for CompositorChan {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_layer(&self, id: PipelineId, page_size: Size2D<uint>) {
|
fn new_layer(&self, id: PipelineId, page_size: Size2D<uint>) {
|
||||||
self.chan.send(NewLayer(id, page_size))
|
let Size2D { width, height } = page_size;
|
||||||
|
self.chan.send(NewLayer(id, Size2D(width as f32, height as f32)))
|
||||||
}
|
}
|
||||||
fn resize_layer(&self, id: PipelineId, page_size: Size2D<uint>) {
|
fn resize_layer(&self, id: PipelineId, page_size: Size2D<uint>) {
|
||||||
self.chan.send(ResizeLayer(id, page_size))
|
let Size2D { width, height } = page_size;
|
||||||
|
self.chan.send(ResizeLayer(id, Size2D(width as f32, height as f32)))
|
||||||
}
|
}
|
||||||
fn delete_layer(&self, id: PipelineId) {
|
fn delete_layer(&self, id: PipelineId) {
|
||||||
self.chan.send(DeleteLayer(id))
|
self.chan.send(DeleteLayer(id))
|
||||||
|
@ -130,9 +130,9 @@ pub enum Msg {
|
||||||
|
|
||||||
// TODO: Attach epochs to these messages
|
// TODO: Attach epochs to these messages
|
||||||
/// Alerts the compositor that there is a new layer to be rendered.
|
/// Alerts the compositor that there is a new layer to be rendered.
|
||||||
NewLayer(PipelineId, Size2D<uint>),
|
NewLayer(PipelineId, Size2D<f32>),
|
||||||
/// Alerts the compositor that the specified layer has changed size.
|
/// Alerts the compositor that the specified layer has changed size.
|
||||||
ResizeLayer(PipelineId, Size2D<uint>),
|
ResizeLayer(PipelineId, Size2D<f32>),
|
||||||
/// Alerts the compositor that the specified layer has been deleted.
|
/// Alerts the compositor that the specified layer has been deleted.
|
||||||
DeleteLayer(PipelineId),
|
DeleteLayer(PipelineId),
|
||||||
/// Invalidate a rect for a given layer
|
/// Invalidate a rect for a given layer
|
||||||
|
@ -145,7 +145,7 @@ pub enum Msg {
|
||||||
/// Alerts the compositor to the current status of rendering.
|
/// Alerts the compositor to the current status of rendering.
|
||||||
ChangeRenderState(RenderState),
|
ChangeRenderState(RenderState),
|
||||||
/// Sets the channel to the current layout and render tasks, along with their id
|
/// Sets the channel to the current layout and render tasks, along with their id
|
||||||
SetIds(SendableFrameTree, Chan<()>),
|
SetIds(SendableFrameTree, Chan<()>, ConstellationChan),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Azure surface wrapping to work with the layers infrastructure.
|
/// Azure surface wrapping to work with the layers infrastructure.
|
||||||
|
@ -207,7 +207,7 @@ impl CompositorTask {
|
||||||
let root_layer = @mut ContainerLayer();
|
let root_layer = @mut ContainerLayer();
|
||||||
let window_size = window.size();
|
let window_size = window.size();
|
||||||
let mut scene = Scene(ContainerLayerKind(root_layer), window_size, identity());
|
let mut scene = Scene(ContainerLayerKind(root_layer), window_size, identity());
|
||||||
let mut window_size = Size2D(window_size.width as int, window_size.height as int);
|
let mut window_size = Size2D(window_size.width as uint, window_size.height as uint);
|
||||||
let mut done = false;
|
let mut done = false;
|
||||||
let mut recomposite = false;
|
let mut recomposite = false;
|
||||||
|
|
||||||
|
@ -216,13 +216,9 @@ impl CompositorTask {
|
||||||
let mut zoom_action = false;
|
let mut zoom_action = false;
|
||||||
let mut zoom_time = 0f;
|
let mut zoom_time = 0f;
|
||||||
|
|
||||||
// Channel to the outermost frame's pipeline.
|
|
||||||
// FIXME: Events are only forwarded to this pipeline, but they should be
|
|
||||||
// routed to the appropriate pipeline via the constellation.
|
|
||||||
let mut pipeline: Option<Pipeline> = None;
|
|
||||||
|
|
||||||
// The root CompositorLayer
|
// The root CompositorLayer
|
||||||
let mut compositor_layer: Option<CompositorLayer> = None;
|
let mut compositor_layer: Option<CompositorLayer> = None;
|
||||||
|
let mut constellation_chan: Option<ConstellationChan> = None;
|
||||||
|
|
||||||
// Get BufferRequests from each layer.
|
// Get BufferRequests from each layer.
|
||||||
let ask_for_tiles = || {
|
let ask_for_tiles = || {
|
||||||
|
@ -243,9 +239,22 @@ impl CompositorTask {
|
||||||
ChangeReadyState(ready_state) => window.set_ready_state(ready_state),
|
ChangeReadyState(ready_state) => window.set_ready_state(ready_state),
|
||||||
ChangeRenderState(render_state) => window.set_render_state(render_state),
|
ChangeRenderState(render_state) => window.set_render_state(render_state),
|
||||||
|
|
||||||
SetIds(frame_tree, response_chan) => {
|
SetIds(frame_tree, response_chan, new_constellation_chan) => {
|
||||||
pipeline = Some(frame_tree.pipeline);
|
|
||||||
response_chan.send(());
|
response_chan.send(());
|
||||||
|
|
||||||
|
// This assumes there is at most one child, which should be the case.
|
||||||
|
match root_layer.first_child {
|
||||||
|
Some(old_layer) => root_layer.remove_child(old_layer),
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
let layer = CompositorLayer::from_frame_tree(frame_tree,
|
||||||
|
self.opts.tile_size,
|
||||||
|
Some(10000000u));
|
||||||
|
root_layer.add_child(ContainerLayerKind(layer.root_layer));
|
||||||
|
compositor_layer = Some(layer);
|
||||||
|
|
||||||
|
constellation_chan = Some(new_constellation_chan);
|
||||||
}
|
}
|
||||||
|
|
||||||
GetSize(chan) => {
|
GetSize(chan) => {
|
||||||
|
@ -259,12 +268,12 @@ impl CompositorTask {
|
||||||
// FIXME: This should create an additional layer instead of replacing the current one.
|
// FIXME: This should create an additional layer instead of replacing the current one.
|
||||||
// Once ResizeLayer messages are set up, we can switch to the new functionality.
|
// Once ResizeLayer messages are set up, we can switch to the new functionality.
|
||||||
|
|
||||||
let p = match pipeline {
|
let p = match compositor_layer {
|
||||||
Some(ref pipeline) => pipeline,
|
Some(ref compositor_layer) => compositor_layer.pipeline.clone(),
|
||||||
None => fail!("Compositor: Received new layer without initialized pipeline"),
|
None => fail!("Compositor: Received new layer without initialized pipeline"),
|
||||||
};
|
};
|
||||||
let page_size = Size2D(new_size.width as f32, new_size.height as f32);
|
let page_size = Size2D(new_size.width as f32, new_size.height as f32);
|
||||||
let new_layer = CompositorLayer::new(p.clone(), Some(page_size),
|
let new_layer = CompositorLayer::new(p, Some(page_size),
|
||||||
self.opts.tile_size, Some(10000000u));
|
self.opts.tile_size, Some(10000000u));
|
||||||
|
|
||||||
let current_child = root_layer.first_child;
|
let current_child = root_layer.first_child;
|
||||||
|
@ -284,7 +293,8 @@ impl CompositorTask {
|
||||||
Some(ref mut layer) => {
|
Some(ref mut layer) => {
|
||||||
let page_window = Size2D(window_size.width as f32 / world_zoom,
|
let page_window = Size2D(window_size.width as f32 / world_zoom,
|
||||||
window_size.height as f32 / world_zoom);
|
window_size.height as f32 / world_zoom);
|
||||||
assert!(layer.resize(id, Size2D(new_size.width as f32,
|
assert!(layer.resize(id,
|
||||||
|
Size2D(new_size.width as f32,
|
||||||
new_size.height as f32),
|
new_size.height as f32),
|
||||||
page_window));
|
page_window));
|
||||||
ask_for_tiles();
|
ask_for_tiles();
|
||||||
|
@ -340,12 +350,12 @@ impl CompositorTask {
|
||||||
IdleWindowEvent => {}
|
IdleWindowEvent => {}
|
||||||
|
|
||||||
ResizeWindowEvent(width, height) => {
|
ResizeWindowEvent(width, height) => {
|
||||||
let new_size = Size2D(width as int, height as int);
|
let new_size = Size2D(width, height);
|
||||||
if window_size != new_size {
|
if window_size != new_size {
|
||||||
debug!("osmain: window resized to %ux%u", width, height);
|
debug!("osmain: window resized to %ux%u", width, height);
|
||||||
window_size = new_size;
|
window_size = new_size;
|
||||||
match pipeline {
|
match constellation_chan {
|
||||||
Some(ref pipeline) => pipeline.script_chan.send(SendEventMsg(pipeline.id.clone(), ResizeEvent(width, height))),
|
Some(ref chan) => chan.send(ResizedWindowMsg(new_size)),
|
||||||
None => error!("Compositor: Recieved resize event without initialized layout chan"),
|
None => error!("Compositor: Recieved resize event without initialized layout chan"),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -355,8 +365,14 @@ impl CompositorTask {
|
||||||
|
|
||||||
LoadUrlWindowEvent(url_string) => {
|
LoadUrlWindowEvent(url_string) => {
|
||||||
debug!("osmain: loading URL `%s`", url_string);
|
debug!("osmain: loading URL `%s`", url_string);
|
||||||
match pipeline {
|
let root_pipeline_id = match compositor_layer {
|
||||||
Some(ref pipeline) => pipeline.script_chan.send(LoadMsg(pipeline.id.clone(), url::make_url(url_string.to_str(), None))),
|
Some(ref layer) => layer.pipeline.id.clone(),
|
||||||
|
None => fail!("Compositor: Received LoadUrlWindowEvent without initialized compositor layers"),
|
||||||
|
};
|
||||||
|
match constellation_chan {
|
||||||
|
Some(ref chan) => chan.send(LoadUrlMsg(root_pipeline_id,
|
||||||
|
url::make_url(url_string.to_str(), None),
|
||||||
|
from_value(window_size))),
|
||||||
None => error!("Compositor: Recieved loadurl event without initialized layout chan"),
|
None => error!("Compositor: Recieved loadurl event without initialized layout chan"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -413,8 +429,8 @@ impl CompositorTask {
|
||||||
windowing::Forward => constellation_msg::Forward,
|
windowing::Forward => constellation_msg::Forward,
|
||||||
windowing::Back => constellation_msg::Back,
|
windowing::Back => constellation_msg::Back,
|
||||||
};
|
};
|
||||||
match pipeline {
|
match constellation_chan {
|
||||||
Some(ref pipeline) => pipeline.script_chan.send(NavigateMsg(direction)),
|
Some(ref chan) => chan.send(NavigateMsg(direction)),
|
||||||
None => error!("Compositor: Recieved navigation event without initialized layout chan"),
|
None => error!("Compositor: Recieved navigation event without initialized layout chan"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use compositing::{CompositorChan, SetIds};
|
use compositing::{CompositorChan, SetIds, ResizeLayer};
|
||||||
|
use script::dom::event::ResizeEvent;
|
||||||
|
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::comm;
|
use std::comm;
|
||||||
|
@ -12,19 +13,19 @@ use geom::size::Size2D;
|
||||||
use geom::rect::Rect;
|
use geom::rect::Rect;
|
||||||
use gfx::opts::Opts;
|
use gfx::opts::Opts;
|
||||||
use pipeline::Pipeline;
|
use pipeline::Pipeline;
|
||||||
use servo_msg::constellation_msg::{ConstellationChan, ExitMsg};
|
use servo_msg::constellation_msg::{ConstellationChan, ExitMsg, FrameRectMsg};
|
||||||
use servo_msg::constellation_msg::{InitLoadUrlMsg, LoadIframeUrlMsg, LoadUrlMsg};
|
use servo_msg::constellation_msg::{InitLoadUrlMsg, LoadIframeUrlMsg, LoadUrlMsg};
|
||||||
use servo_msg::constellation_msg::{Msg, NavigateMsg};
|
use servo_msg::constellation_msg::{Msg, NavigateMsg};
|
||||||
use servo_msg::constellation_msg::{PipelineId, RendererReadyMsg, ResizedWindowBroadcast, SubpageId};
|
use servo_msg::constellation_msg::{PipelineId, RendererReadyMsg, ResizedWindowMsg, SubpageId};
|
||||||
use servo_msg::constellation_msg;
|
use servo_msg::constellation_msg;
|
||||||
use script::script_task::{ResizeInactiveMsg, ExecuteMsg};
|
use script::script_task::{SendEventMsg, ResizeInactiveMsg, ExecuteMsg};
|
||||||
use servo_net::image_cache_task::{ImageCacheTask, ImageCacheTaskClient};
|
use servo_net::image_cache_task::{ImageCacheTask, ImageCacheTaskClient};
|
||||||
use servo_net::resource_task::ResourceTask;
|
use servo_net::resource_task::ResourceTask;
|
||||||
use servo_net::resource_task;
|
use servo_net::resource_task;
|
||||||
use servo_util::time::ProfilerChan;
|
use servo_util::time::ProfilerChan;
|
||||||
use std::hashmap::HashMap;
|
use std::hashmap::{HashMap, HashSet};
|
||||||
use std::util::replace;
|
use std::util::replace;
|
||||||
use extra::future::from_value;
|
use extra::future::{Future, from_value};
|
||||||
|
|
||||||
/// Maintains the pipelines and navigation context and grants permission to composite
|
/// Maintains the pipelines and navigation context and grants permission to composite
|
||||||
pub struct Constellation {
|
pub struct Constellation {
|
||||||
|
@ -167,7 +168,7 @@ impl Iterator<@mut FrameTree> for FrameTreeIterator {
|
||||||
fn next(&mut self) -> Option<@mut FrameTree> {
|
fn next(&mut self) -> Option<@mut FrameTree> {
|
||||||
if !self.stack.is_empty() {
|
if !self.stack.is_empty() {
|
||||||
let next = self.stack.pop();
|
let next = self.stack.pop();
|
||||||
for next.children.iter().advance |&ChildFrameTree { frame_tree, _ }| {
|
for &ChildFrameTree { frame_tree, _ } in next.children.iter() {
|
||||||
self.stack.push(frame_tree);
|
self.stack.push(frame_tree);
|
||||||
}
|
}
|
||||||
Some(next)
|
Some(next)
|
||||||
|
@ -318,8 +319,45 @@ impl Constellation {
|
||||||
/// Handles loading pages, navigation, and granting access to the compositor
|
/// Handles loading pages, navigation, and granting access to the compositor
|
||||||
fn handle_request(&mut self, request: Msg) -> bool {
|
fn handle_request(&mut self, request: Msg) -> bool {
|
||||||
match request {
|
match request {
|
||||||
|
|
||||||
ExitMsg(sender) => {
|
ExitMsg(sender) => {
|
||||||
|
self.handle_exit(sender);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// This should only be called once per constellation, and only by the browser
|
||||||
|
InitLoadUrlMsg(url) => {
|
||||||
|
self.handle_init_load(url);
|
||||||
|
}
|
||||||
|
// A layout assigned a size and position to a subframe. This needs to be reflected by all
|
||||||
|
// frame trees in the navigation context containing the subframe.
|
||||||
|
FrameRectMsg(pipeline_id, subpage_id, rect) => {
|
||||||
|
self.handle_frame_rect_msg(pipeline_id, subpage_id, rect);
|
||||||
|
}
|
||||||
|
LoadIframeUrlMsg(url, source_pipeline_id, subpage_id, size_future) => {
|
||||||
|
self.handle_load_iframe_url_msg(url, source_pipeline_id, subpage_id, size_future);
|
||||||
|
}
|
||||||
|
// Load a new page, usually -- but not always -- from a mouse click or typed url
|
||||||
|
// If there is already a pending page (self.pending_frames), it will not be overridden;
|
||||||
|
// However, if the id is not encompassed by another change, it will be.
|
||||||
|
LoadUrlMsg(source_id, url, size_future) => {
|
||||||
|
self.handle_load_url_msg(source_id, url, size_future);
|
||||||
|
}
|
||||||
|
// Handle a forward or back request
|
||||||
|
NavigateMsg(direction) => {
|
||||||
|
self.handle_navigate_msg(direction);
|
||||||
|
}
|
||||||
|
// Notification that rendering has finished and is requesting permission to paint.
|
||||||
|
RendererReadyMsg(pipeline_id) => {
|
||||||
|
self.handle_renderer_ready_msg(pipeline_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
ResizedWindowMsg(new_size) => {
|
||||||
|
self.handle_resized_window_msg(new_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_exit(&self, sender: Chan<()>) {
|
||||||
for (_id, ref pipeline) in self.pipelines.iter() {
|
for (_id, ref pipeline) in self.pipelines.iter() {
|
||||||
pipeline.exit();
|
pipeline.exit();
|
||||||
}
|
}
|
||||||
|
@ -327,11 +365,9 @@ impl Constellation {
|
||||||
self.resource_task.send(resource_task::Exit);
|
self.resource_task.send(resource_task::Exit);
|
||||||
|
|
||||||
sender.send(());
|
sender.send(());
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This should only be called once per constellation, and only by the browser
|
fn handle_init_load(&mut self, url: Url) {
|
||||||
InitLoadUrlMsg(url) => {
|
|
||||||
let pipeline = @mut Pipeline::create(self.get_next_pipeline_id(),
|
let pipeline = @mut Pipeline::create(self.get_next_pipeline_id(),
|
||||||
None,
|
None,
|
||||||
self.chan.clone(),
|
self.chan.clone(),
|
||||||
|
@ -361,7 +397,64 @@ impl Constellation {
|
||||||
self.pipelines.insert(pipeline.id, pipeline);
|
self.pipelines.insert(pipeline.id, pipeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
LoadIframeUrlMsg(url, source_pipeline_id, subpage_id, size_future) => {
|
fn handle_frame_rect_msg(&mut self, pipeline_id: PipelineId, subpage_id: SubpageId, rect: Rect<f32>) {
|
||||||
|
let mut already_sent = HashSet::new();
|
||||||
|
|
||||||
|
// If the subframe is in the current frame tree, the compositor needs the new size
|
||||||
|
let source_frame = self.current_frame().unwrap().find_mut(pipeline_id);
|
||||||
|
for source_frame in source_frame.iter() {
|
||||||
|
for child_frame_tree in source_frame.children.mut_iter() {
|
||||||
|
let pipeline = &child_frame_tree.frame_tree.pipeline;
|
||||||
|
if pipeline.subpage_id.expect("Constellation: child frame does not have a
|
||||||
|
subpage id. This should not be possible.") == subpage_id {
|
||||||
|
child_frame_tree.rect = Some(rect.clone());
|
||||||
|
let Rect { size: Size2D { width, height }, _ } = rect;
|
||||||
|
pipeline.script_chan.send(SendEventMsg(pipeline.id.clone(),
|
||||||
|
ResizeEvent(width as uint,
|
||||||
|
height as uint)));
|
||||||
|
self.compositor_chan.send(ResizeLayer(pipeline.id, rect.size));
|
||||||
|
already_sent.insert(pipeline.id.clone());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Go through the navigation context and tell each associated pipeline to resize.
|
||||||
|
let frame_trees: ~[@mut FrameTree] = {
|
||||||
|
let matching_navi_frames = self.navigation_context.find_all(pipeline_id);
|
||||||
|
let matching_pending_frames = do self.pending_frames.iter().filter_map |frame_change| {
|
||||||
|
frame_change.after.find_mut(pipeline_id)
|
||||||
|
};
|
||||||
|
matching_navi_frames.move_iter().chain(matching_pending_frames).collect()
|
||||||
|
};
|
||||||
|
for frame_tree in frame_trees.iter() {
|
||||||
|
for child_frame_tree in frame_tree.children.mut_iter() {
|
||||||
|
let pipeline = &child_frame_tree.frame_tree.pipeline;
|
||||||
|
if pipeline.subpage_id.expect("Constellation: child frame does not have a
|
||||||
|
subpage id. This should not be possible.") == subpage_id {
|
||||||
|
child_frame_tree.rect = Some(rect.clone());
|
||||||
|
if !already_sent.contains(&pipeline.id) {
|
||||||
|
let Size2D { width, height } = rect.size;
|
||||||
|
pipeline.script_chan.send(ResizeInactiveMsg(pipeline.id.clone(),
|
||||||
|
Size2D(width as uint, height as uint)));
|
||||||
|
already_sent.insert(pipeline.id.clone());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// At this point, if no pipelines were sent a resize msg, then this subpage id
|
||||||
|
// should be added to pending sizes
|
||||||
|
if already_sent.len() == 0 {
|
||||||
|
self.pending_sizes.insert((pipeline_id, subpage_id), rect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_load_iframe_url_msg(&mut self,
|
||||||
|
url: Url,
|
||||||
|
source_pipeline_id: PipelineId,
|
||||||
|
subpage_id: SubpageId,
|
||||||
|
size_future: Future<Size2D<uint>>) {
|
||||||
// A message from the script associated with pipeline_id that it has
|
// A message from the script associated with pipeline_id that it has
|
||||||
// parsed an iframe during html parsing. This iframe will result in a
|
// parsed an iframe during html parsing. This iframe will result in a
|
||||||
// new pipeline being spawned and a frame tree being added to pipeline_id's
|
// new pipeline being spawned and a frame tree being added to pipeline_id's
|
||||||
|
@ -440,10 +533,7 @@ impl Constellation {
|
||||||
self.pipelines.insert(pipeline.id, pipeline);
|
self.pipelines.insert(pipeline.id, pipeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load a new page, usually -- but not always -- from a mouse click or typed url
|
fn handle_load_url_msg(&mut self, source_id: PipelineId, url: Url, size_future: Future<Size2D<uint>>) {
|
||||||
// If there is already a pending page (self.pending_frames), it will not be overridden;
|
|
||||||
// However, if the id is not encompassed by another change, it will be.
|
|
||||||
LoadUrlMsg(source_id, url, size_future) => {
|
|
||||||
debug!("received message to load %s", url.to_str());
|
debug!("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_mut(source_id).expect(
|
let source_frame = self.current_frame().get_ref().find_mut(source_id).expect(
|
||||||
|
@ -460,7 +550,7 @@ impl Constellation {
|
||||||
impossible.");
|
impossible.");
|
||||||
if changing_frame.contains(source_id) || source_frame.contains(old_id) {
|
if changing_frame.contains(source_id) || source_frame.contains(old_id) {
|
||||||
// id that sent load msg is being changed already; abort
|
// id that sent load msg is being changed already; abort
|
||||||
return true;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 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
|
||||||
|
@ -497,8 +587,7 @@ impl Constellation {
|
||||||
self.pipelines.insert(pipeline.id, pipeline);
|
self.pipelines.insert(pipeline.id, pipeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle a forward or back request
|
fn handle_navigate_msg(&mut self, direction: constellation_msg::NavigationDirection) {
|
||||||
NavigateMsg(direction) => {
|
|
||||||
debug!("received message to navigate %?", direction);
|
debug!("received message to navigate %?", direction);
|
||||||
|
|
||||||
// TODO(tkuehn): what is the "critical point" beyond which pending frames
|
// TODO(tkuehn): what is the "critical point" beyond which pending frames
|
||||||
|
@ -509,7 +598,7 @@ impl Constellation {
|
||||||
constellation_msg::Forward => {
|
constellation_msg::Forward => {
|
||||||
if self.navigation_context.next.is_empty() {
|
if self.navigation_context.next.is_empty() {
|
||||||
debug!("no next page to navigate to");
|
debug!("no next page to navigate to");
|
||||||
return true
|
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.iter() {
|
||||||
|
@ -521,7 +610,7 @@ impl Constellation {
|
||||||
constellation_msg::Back => {
|
constellation_msg::Back => {
|
||||||
if self.navigation_context.previous.is_empty() {
|
if self.navigation_context.previous.is_empty() {
|
||||||
debug!("no previous page to navigate to");
|
debug!("no previous page to navigate to");
|
||||||
return true
|
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.iter() {
|
||||||
|
@ -540,8 +629,7 @@ impl Constellation {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notification that rendering has finished and is requesting permission to paint.
|
fn handle_renderer_ready_msg(&mut self, pipeline_id: PipelineId) {
|
||||||
RendererReadyMsg(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.
|
||||||
|
@ -552,7 +640,7 @@ impl Constellation {
|
||||||
// impossible to occur.
|
// impossible to occur.
|
||||||
if current_frame.contains(pipeline_id) {
|
if current_frame.contains(pipeline_id) {
|
||||||
self.set_ids(current_frame);
|
self.set_ids(current_frame);
|
||||||
return true;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -585,7 +673,8 @@ impl Constellation {
|
||||||
frame.pipeline.revoke_paint_permission();
|
frame.pipeline.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.
|
||||||
if to_add.parent.is_some() {
|
if to_add.parent.is_some() {
|
||||||
next_frame_tree.replace_child(revoke_id, to_add);
|
next_frame_tree.replace_child(revoke_id, to_add);
|
||||||
}
|
}
|
||||||
|
@ -596,12 +685,16 @@ impl Constellation {
|
||||||
let parent = &to_add.parent;
|
let parent = &to_add.parent;
|
||||||
let to_add = Cell::new(to_add);
|
let to_add = Cell::new(to_add);
|
||||||
for parent in parent.iter() {
|
for parent in parent.iter() {
|
||||||
|
let to_add = to_add.take();
|
||||||
|
let subpage_id = to_add.pipeline.subpage_id.expect("Constellation:
|
||||||
|
Child frame's subpage id is None. This should be impossible.");
|
||||||
|
let rect = self.pending_sizes.pop(&(parent.id, subpage_id));
|
||||||
let parent = next_frame_tree.find_mut(parent.id).expect(
|
let parent = next_frame_tree.find_mut(parent.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 {
|
parent.children.push(ChildFrameTree {
|
||||||
frame_tree: to_add.take(),
|
frame_tree: to_add,
|
||||||
rect: None,
|
rect: rect,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -610,34 +703,21 @@ impl Constellation {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ResizedWindowBroadcast(new_size) => match *self.current_frame() {
|
fn handle_resized_window_msg(&mut self, new_size: Size2D<uint>) {
|
||||||
Some(ref current_frame) => {
|
let mut already_seen = HashSet::new();
|
||||||
let current_frame_id = current_frame.pipeline.id.clone();
|
for &@FrameTree { pipeline: ref pipeline, _ } in self.current_frame().iter() {
|
||||||
for frame_tree in self.navigation_context.previous.iter() {
|
let Size2D { width, height } = new_size;
|
||||||
let pipeline = &frame_tree.pipeline;
|
pipeline.script_chan.send(SendEventMsg(pipeline.id.clone(),
|
||||||
if current_frame_id != pipeline.id {
|
ResizeEvent(width, height)));
|
||||||
pipeline.script_chan.send(ResizeInactiveMsg(new_size));
|
already_seen.insert(pipeline.id.clone());
|
||||||
|
}
|
||||||
|
for &@FrameTree { pipeline: ref pipeline, _ } in self.navigation_context.previous.iter()
|
||||||
|
.chain(self.navigation_context.next.iter()) {
|
||||||
|
if !already_seen.contains(&pipeline.id) {
|
||||||
|
pipeline.script_chan.send(ResizeInactiveMsg(pipeline.id.clone(), new_size));
|
||||||
|
already_seen.insert(pipeline.id.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for frame_tree in self.navigation_context.next.iter() {
|
|
||||||
let pipeline = &frame_tree.pipeline;
|
|
||||||
if current_frame_id != pipeline.id {
|
|
||||||
pipeline.script_chan.send(ResizeInactiveMsg(new_size));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
for frame_tree in self.navigation_context.previous.iter() {
|
|
||||||
frame_tree.pipeline.script_chan.send(ResizeInactiveMsg(new_size));
|
|
||||||
}
|
|
||||||
for frame_tree in self.navigation_context.next.iter() {
|
|
||||||
frame_tree.pipeline.script_chan.send(ResizeInactiveMsg(new_size));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
|
@ -666,7 +746,7 @@ impl Constellation {
|
||||||
|
|
||||||
fn set_ids(&self, frame_tree: @mut FrameTree) {
|
fn set_ids(&self, frame_tree: @mut FrameTree) {
|
||||||
let (port, chan) = comm::stream();
|
let (port, chan) = comm::stream();
|
||||||
self.compositor_chan.send(SetIds(frame_tree.to_sendable(), chan));
|
self.compositor_chan.send(SetIds(frame_tree.to_sendable(), chan, self.chan.clone()));
|
||||||
port.recv();
|
port.recv();
|
||||||
for frame in frame_tree.iter() {
|
for frame in frame_tree.iter() {
|
||||||
frame.pipeline.grant_paint_permission();
|
frame.pipeline.grant_paint_permission();
|
||||||
|
|
|
@ -9,6 +9,7 @@ use std::comm::{Chan, SharedChan};
|
||||||
use extra::url::Url;
|
use extra::url::Url;
|
||||||
use extra::future::Future;
|
use extra::future::Future;
|
||||||
use geom::size::Size2D;
|
use geom::size::Size2D;
|
||||||
|
use geom::rect::Rect;
|
||||||
|
|
||||||
#[deriving(Clone)]
|
#[deriving(Clone)]
|
||||||
pub struct ConstellationChan {
|
pub struct ConstellationChan {
|
||||||
|
@ -29,12 +30,12 @@ impl ConstellationChan {
|
||||||
pub enum Msg {
|
pub enum Msg {
|
||||||
ExitMsg(Chan<()>),
|
ExitMsg(Chan<()>),
|
||||||
InitLoadUrlMsg(Url),
|
InitLoadUrlMsg(Url),
|
||||||
//FrameRectMsg(PipelineId, SubpageId, Rect<?>),
|
FrameRectMsg(PipelineId, SubpageId, Rect<f32>),
|
||||||
LoadUrlMsg(PipelineId, Url, Future<Size2D<uint>>),
|
LoadUrlMsg(PipelineId, Url, Future<Size2D<uint>>),
|
||||||
LoadIframeUrlMsg(Url, PipelineId, SubpageId, Future<Size2D<uint>>),
|
LoadIframeUrlMsg(Url, PipelineId, SubpageId, Future<Size2D<uint>>),
|
||||||
NavigateMsg(NavigationDirection),
|
NavigateMsg(NavigationDirection),
|
||||||
RendererReadyMsg(PipelineId),
|
RendererReadyMsg(PipelineId),
|
||||||
ResizedWindowBroadcast(Size2D<uint>),
|
ResizedWindowMsg(Size2D<uint>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents the two different ways to which a page can be navigated
|
/// Represents the two different ways to which a page can be navigated
|
||||||
|
|
|
@ -21,7 +21,7 @@ use layout_interface::{ReflowDocumentDamage, ReflowForDisplay, ReflowGoal};
|
||||||
use layout_interface::ReflowMsg;
|
use layout_interface::ReflowMsg;
|
||||||
use layout_interface;
|
use layout_interface;
|
||||||
use servo_msg::constellation_msg::{ConstellationChan, LoadUrlMsg, NavigationDirection};
|
use servo_msg::constellation_msg::{ConstellationChan, LoadUrlMsg, NavigationDirection};
|
||||||
use servo_msg::constellation_msg::{PipelineId, SubpageId, RendererReadyMsg, ResizedWindowBroadcast};
|
use servo_msg::constellation_msg::{PipelineId, SubpageId, RendererReadyMsg};
|
||||||
use servo_msg::constellation_msg::{LoadIframeUrlMsg};
|
use servo_msg::constellation_msg::{LoadIframeUrlMsg};
|
||||||
use servo_msg::constellation_msg;
|
use servo_msg::constellation_msg;
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ pub enum ScriptMsg {
|
||||||
/// Notifies script that reflow is finished.
|
/// Notifies script that reflow is finished.
|
||||||
ReflowCompleteMsg(PipelineId),
|
ReflowCompleteMsg(PipelineId),
|
||||||
/// Notifies script that window has been resized but to not take immediate action.
|
/// Notifies script that window has been resized but to not take immediate action.
|
||||||
ResizeInactiveMsg(Size2D<uint>),
|
ResizeInactiveMsg(PipelineId, Size2D<uint>),
|
||||||
/// Exits the constellation.
|
/// Exits the constellation.
|
||||||
ExitMsg,
|
ExitMsg,
|
||||||
}
|
}
|
||||||
|
@ -454,7 +454,7 @@ impl ScriptTask {
|
||||||
FireTimerMsg(id, timer_data) => self.handle_fire_timer_msg(id, timer_data),
|
FireTimerMsg(id, timer_data) => self.handle_fire_timer_msg(id, timer_data),
|
||||||
NavigateMsg(direction) => self.handle_navigate_msg(direction),
|
NavigateMsg(direction) => self.handle_navigate_msg(direction),
|
||||||
ReflowCompleteMsg(id) => self.handle_reflow_complete_msg(id),
|
ReflowCompleteMsg(id) => self.handle_reflow_complete_msg(id),
|
||||||
ResizeInactiveMsg(new_size) => self.handle_resize_inactive_msg(new_size),
|
ResizeInactiveMsg(id, new_size) => self.handle_resize_inactive_msg(id, new_size),
|
||||||
ExitMsg => {
|
ExitMsg => {
|
||||||
self.handle_exit_msg();
|
self.handle_exit_msg();
|
||||||
return false
|
return false
|
||||||
|
@ -543,11 +543,13 @@ impl ScriptTask {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Window was resized, but this script was not active, so don't reflow yet
|
/// Window was resized, but this script was not active, so don't reflow yet
|
||||||
fn handle_resize_inactive_msg(&mut self, new_size: Size2D<uint>) {
|
fn handle_resize_inactive_msg(&mut self, id: PipelineId, new_size: Size2D<uint>) {
|
||||||
self.page_tree.page.window_size = from_value(new_size);
|
let page = self.page_tree.find(id).expect("Received resize message for PipelineId not associated
|
||||||
let last_loaded_url = replace(&mut self.page_tree.page.url, None);
|
with a page in the page tree. This is a bug.").page;
|
||||||
|
page.window_size = from_value(new_size);
|
||||||
|
let last_loaded_url = replace(&mut page.url, None);
|
||||||
for url in last_loaded_url.iter() {
|
for url in last_loaded_url.iter() {
|
||||||
self.page_tree.page.url = Some((url.first(), true));
|
page.url = Some((url.first(), true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -700,8 +702,6 @@ impl ScriptTask {
|
||||||
page.damage(ReflowDocumentDamage);
|
page.damage(ReflowDocumentDamage);
|
||||||
page.reflow(ReflowForDisplay, self.chan.clone(), self.compositor)
|
page.reflow(ReflowForDisplay, self.chan.clone(), self.compositor)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.constellation_chan.send(ResizedWindowBroadcast(page.window_size.get().clone()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME(pcwalton): This reflows the entire document and is not incremental-y.
|
// FIXME(pcwalton): This reflows the entire document and is not incremental-y.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue