mirror of
https://github.com/servo/servo.git
synced 2025-06-18 05:14:28 +00:00
structural changes to support Iframes
This commit is contained in:
parent
eaa20edcd7
commit
e9888b299c
30 changed files with 1416 additions and 835 deletions
|
@ -9,6 +9,7 @@ use azure::azure_hl::{B8G8R8A8, DrawTarget};
|
||||||
use display_list::DisplayList;
|
use display_list::DisplayList;
|
||||||
use servo_msg::compositor_msg::{RenderListener, IdleRenderState, RenderingRenderState, LayerBuffer};
|
use servo_msg::compositor_msg::{RenderListener, IdleRenderState, RenderingRenderState, LayerBuffer};
|
||||||
use servo_msg::compositor_msg::{LayerBufferSet};
|
use servo_msg::compositor_msg::{LayerBufferSet};
|
||||||
|
use servo_msg::constellation_msg::PipelineId;
|
||||||
use font_context::FontContext;
|
use font_context::FontContext;
|
||||||
use geom::matrix2d::Matrix2D;
|
use geom::matrix2d::Matrix2D;
|
||||||
use geom::size::Size2D;
|
use geom::size::Size2D;
|
||||||
|
@ -70,7 +71,7 @@ impl RenderChan {
|
||||||
}
|
}
|
||||||
|
|
||||||
priv struct RenderTask<C> {
|
priv struct RenderTask<C> {
|
||||||
id: uint,
|
id: PipelineId,
|
||||||
port: Port<Msg>,
|
port: Port<Msg>,
|
||||||
compositor: C,
|
compositor: C,
|
||||||
font_ctx: @mut FontContext,
|
font_ctx: @mut FontContext,
|
||||||
|
@ -90,7 +91,7 @@ priv struct RenderTask<C> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C: RenderListener + Send> RenderTask<C> {
|
impl<C: RenderListener + Send> RenderTask<C> {
|
||||||
pub fn create(id: uint,
|
pub fn create(id: PipelineId,
|
||||||
port: Port<Msg>,
|
port: Port<Msg>,
|
||||||
compositor: C,
|
compositor: C,
|
||||||
opts: Opts,
|
opts: Opts,
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
use platform::{Application, Window};
|
use platform::{Application, Window};
|
||||||
use script::dom::event::{Event, ClickEvent, MouseDownEvent, MouseUpEvent, ResizeEvent};
|
use script::dom::event::{Event, ClickEvent, MouseDownEvent, MouseUpEvent, ResizeEvent};
|
||||||
use script::script_task::{LoadMsg, NavigateMsg, SendEventMsg};
|
use script::script_task::{LoadMsg, NavigateMsg, SendEventMsg};
|
||||||
use script::layout_interface::{LayoutChan, RouteScriptMsg};
|
|
||||||
|
|
||||||
use windowing::{ApplicationMethods, WindowEvent, WindowMethods};
|
use windowing::{ApplicationMethods, WindowEvent, WindowMethods};
|
||||||
use windowing::{IdleWindowEvent, ResizeWindowEvent, LoadUrlWindowEvent, MouseWindowEventClass};
|
use windowing::{IdleWindowEvent, ResizeWindowEvent, LoadUrlWindowEvent, MouseWindowEventClass};
|
||||||
|
@ -14,9 +13,9 @@ use windowing::{QuitWindowEvent, MouseWindowClickEvent, MouseWindowMouseDownEven
|
||||||
|
|
||||||
use servo_msg::compositor_msg::{RenderListener, LayerBuffer, LayerBufferSet, RenderState};
|
use servo_msg::compositor_msg::{RenderListener, LayerBuffer, LayerBufferSet, RenderState};
|
||||||
use servo_msg::compositor_msg::{ReadyState, ScriptListener};
|
use servo_msg::compositor_msg::{ReadyState, ScriptListener};
|
||||||
use servo_msg::constellation_msg::{CompositorAck, ConstellationChan};
|
use servo_msg::constellation_msg::{CompositorAck, ConstellationChan, PipelineId};
|
||||||
use servo_msg::constellation_msg;
|
use servo_msg::constellation_msg;
|
||||||
use gfx::render_task::{RenderChan, ReRenderMsg};
|
use gfx::render_task::ReRenderMsg;
|
||||||
use gfx::opts::Opts;
|
use gfx::opts::Opts;
|
||||||
|
|
||||||
use azure::azure_hl::{DataSourceSurface, DrawTarget, SourceSurfaceMethods, current_gl_context};
|
use azure::azure_hl::{DataSourceSurface, DrawTarget, SourceSurfaceMethods, current_gl_context};
|
||||||
|
@ -50,6 +49,8 @@ pub use windowing;
|
||||||
|
|
||||||
use extra::time::precise_time_s;
|
use extra::time::precise_time_s;
|
||||||
use compositing::quadtree::Quadtree;
|
use compositing::quadtree::Quadtree;
|
||||||
|
use constellation::SendableFrameTree;
|
||||||
|
use pipeline::Pipeline;
|
||||||
mod quadtree;
|
mod quadtree;
|
||||||
|
|
||||||
/// The implementation of the layers-based compositor.
|
/// The implementation of the layers-based compositor.
|
||||||
|
@ -78,7 +79,7 @@ impl RenderListener for CompositorChan {
|
||||||
port.recv()
|
port.recv()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint(&self, id: uint, layer_buffer_set: arc::ARC<LayerBufferSet>, new_size: Size2D<uint>) {
|
fn paint(&self, id: PipelineId, layer_buffer_set: arc::ARC<LayerBufferSet>, new_size: Size2D<uint>) {
|
||||||
self.chan.send(Paint(id, layer_buffer_set, new_size))
|
self.chan.send(Paint(id, layer_buffer_set, new_size))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,13 +135,13 @@ pub enum Msg {
|
||||||
DeleteLayer,
|
DeleteLayer,
|
||||||
|
|
||||||
/// Requests that the compositor paint the given layer buffer set for the given page size.
|
/// Requests that the compositor paint the given layer buffer set for the given page size.
|
||||||
Paint(uint, arc::ARC<LayerBufferSet>, Size2D<uint>),
|
Paint(PipelineId, arc::ARC<LayerBufferSet>, Size2D<uint>),
|
||||||
/// Alerts the compositor to the current status of page loading.
|
/// Alerts the compositor to the current status of page loading.
|
||||||
ChangeReadyState(ReadyState),
|
ChangeReadyState(ReadyState),
|
||||||
/// 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
|
||||||
SetLayoutRenderChans(LayoutChan, RenderChan , uint, ConstellationChan)
|
SetIds(SendableFrameTree, ConstellationChan)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Azure surface wrapping to work with the layers infrastructure.
|
/// Azure surface wrapping to work with the layers infrastructure.
|
||||||
|
@ -234,12 +235,12 @@ impl CompositorTask {
|
||||||
let mut world_zoom = 1f32;
|
let mut world_zoom = 1f32;
|
||||||
// Keeps track of local zoom factor. Reset to 1 after a rerender event.
|
// Keeps track of local zoom factor. Reset to 1 after a rerender event.
|
||||||
let mut local_zoom = 1f32;
|
let mut local_zoom = 1f32;
|
||||||
// Channel to the current renderer.
|
// Channel to the outermost frame's pipeline.
|
||||||
// FIXME: This probably shouldn't be stored like this.
|
// FIXME: Compositor currently only asks for tiles to composite from this pipeline,
|
||||||
|
// Subframes need to be handled, as well. Additionally, events are only forwarded
|
||||||
let mut render_chan: Option<RenderChan> = None;
|
// to this pipeline, but they should be routed to the appropriate pipeline via
|
||||||
let mut pipeline_id: Option<uint> = None;
|
// the constellation.
|
||||||
let mut layout_chan: Option<LayoutChan> = None;
|
let mut pipeline: Option<Pipeline> = None;
|
||||||
|
|
||||||
// Quadtree for this layer
|
// Quadtree for this layer
|
||||||
// FIXME: This should be one-per-layer
|
// FIXME: This should be one-per-layer
|
||||||
|
@ -317,9 +318,9 @@ impl CompositorTask {
|
||||||
window_size), world_zoom);
|
window_size), world_zoom);
|
||||||
|
|
||||||
if !tile_request.is_empty() {
|
if !tile_request.is_empty() {
|
||||||
match render_chan {
|
match pipeline {
|
||||||
Some(ref chan) => {
|
Some(ref pipeline) => {
|
||||||
chan.send(ReRenderMsg(tile_request, world_zoom));
|
pipeline.render_chan.send(ReRenderMsg(tile_request, world_zoom));
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
println("Warning: Compositor: Cannot send tile request, no render chan initialized");
|
println("Warning: Compositor: Cannot send tile request, no render chan initialized");
|
||||||
|
@ -344,14 +345,9 @@ 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),
|
||||||
|
|
||||||
SetLayoutRenderChans(new_layout_chan,
|
SetIds(frame_tree, response_chan) => {
|
||||||
new_render_chan,
|
pipeline = Some(frame_tree.pipeline);
|
||||||
new_pipeline_id,
|
response_chan.send(CompositorAck(pipeline.get_ref().id.clone()));
|
||||||
response_chan) => {
|
|
||||||
layout_chan = Some(new_layout_chan);
|
|
||||||
render_chan = Some(new_render_chan);
|
|
||||||
pipeline_id = Some(new_pipeline_id);
|
|
||||||
response_chan.send(CompositorAck(new_pipeline_id));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GetSize(chan) => {
|
GetSize(chan) => {
|
||||||
|
@ -378,8 +374,8 @@ impl CompositorTask {
|
||||||
}
|
}
|
||||||
|
|
||||||
Paint(id, new_layer_buffer_set, new_size) => {
|
Paint(id, new_layer_buffer_set, new_size) => {
|
||||||
match pipeline_id {
|
match pipeline {
|
||||||
Some(pipeline_id) => if id != pipeline_id { loop; },
|
Some(ref pipeline) => if id != pipeline.id { loop; },
|
||||||
None => { loop; },
|
None => { loop; },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -417,8 +413,8 @@ impl CompositorTask {
|
||||||
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 layout_chan {
|
match pipeline {
|
||||||
Some(ref chan) => chan.send(RouteScriptMsg(SendEventMsg(ResizeEvent(width, height)))),
|
Some(ref pipeline) => pipeline.script_chan.send(SendEventMsg(pipeline.id.clone(), ResizeEvent(width, height))),
|
||||||
None => error!("Compositor: Recieved resize event without initialized layout chan"),
|
None => error!("Compositor: Recieved resize event without initialized layout chan"),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -428,8 +424,8 @@ impl CompositorTask {
|
||||||
|
|
||||||
LoadUrlWindowEvent(url_string) => {
|
LoadUrlWindowEvent(url_string) => {
|
||||||
debug!("osmain: loading URL `%s`", url_string);
|
debug!("osmain: loading URL `%s`", url_string);
|
||||||
match layout_chan {
|
match pipeline {
|
||||||
Some(ref chan) => chan.send(RouteScriptMsg(LoadMsg(url::make_url(url_string.to_str(), None)))),
|
Some(ref pipeline) => pipeline.script_chan.send(LoadMsg(pipeline.id.clone(), url::make_url(url_string.to_str(), None))),
|
||||||
None => error!("Compositor: Recieved loadurl event without initialized layout chan"),
|
None => error!("Compositor: Recieved loadurl event without initialized layout chan"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -450,8 +446,8 @@ impl CompositorTask {
|
||||||
event = MouseUpEvent(button, world_mouse_point(layer_mouse_point));
|
event = MouseUpEvent(button, world_mouse_point(layer_mouse_point));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
match layout_chan {
|
match pipeline {
|
||||||
Some(ref chan) => chan.send(RouteScriptMsg(SendEventMsg(event))),
|
Some(ref pipeline) => pipeline.script_chan.send(SendEventMsg(pipeline.id.clone(), event)),
|
||||||
None => error!("Compositor: Recieved mouse event without initialized layout chan"),
|
None => error!("Compositor: Recieved mouse event without initialized layout chan"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -530,8 +526,8 @@ impl CompositorTask {
|
||||||
windowing::Forward => constellation_msg::Forward,
|
windowing::Forward => constellation_msg::Forward,
|
||||||
windowing::Back => constellation_msg::Back,
|
windowing::Back => constellation_msg::Back,
|
||||||
};
|
};
|
||||||
match layout_chan {
|
match pipeline {
|
||||||
Some(ref chan) => chan.send(RouteScriptMsg(NavigateMsg(direction))),
|
Some(ref pipeline) => pipeline.script_chan.send(NavigateMsg(pipeline.id.clone(), direction)),
|
||||||
None => error!("Compositor: Recieved navigation event without initialized layout chan"),
|
None => error!("Compositor: Recieved navigation event without initialized layout chan"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* 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, SetLayoutRenderChans};
|
use compositing::{CompositorChan, SetIds};
|
||||||
|
|
||||||
use extra::net::url;
|
use extra::net::url;
|
||||||
|
|
||||||
|
@ -10,11 +10,13 @@ use std::cell::Cell;
|
||||||
use std::comm;
|
use std::comm;
|
||||||
use std::comm::Port;
|
use std::comm::Port;
|
||||||
use std::task;
|
use std::task;
|
||||||
|
use geom::size::Size2D;
|
||||||
use gfx::opts::Opts;
|
use gfx::opts::Opts;
|
||||||
use gfx::render_task::{PaintPermissionGranted, PaintPermissionRevoked};
|
|
||||||
use pipeline::Pipeline;
|
use pipeline::Pipeline;
|
||||||
use servo_msg::constellation_msg::{CompositorAck, ConstellationChan, ExitMsg, LoadUrlMsg};
|
use servo_msg::constellation_msg::{CompositorAck, ConstellationChan, ExitMsg};
|
||||||
use servo_msg::constellation_msg::{Msg, NavigateMsg, RendererReadyMsg, ResizedWindowBroadcast};
|
use servo_msg::constellation_msg::{InitLoadUrlMsg, LoadIframeUrlMsg, LoadUrlMsg};
|
||||||
|
use servo_msg::constellation_msg::{Msg, NavigateMsg};
|
||||||
|
use servo_msg::constellation_msg::{PipelineId, RendererReadyMsg, ResizedWindowBroadcast};
|
||||||
use servo_msg::constellation_msg;
|
use servo_msg::constellation_msg;
|
||||||
use script::script_task::{ResizeInactiveMsg, ExecuteMsg};
|
use script::script_task::{ResizeInactiveMsg, ExecuteMsg};
|
||||||
use servo_net::image_cache_task::{ImageCacheTask, ImageCacheTaskClient};
|
use servo_net::image_cache_task::{ImageCacheTask, ImageCacheTaskClient};
|
||||||
|
@ -23,6 +25,7 @@ use servo_net::resource_task;
|
||||||
use servo_util::time::ProfilerChan;
|
use servo_util::time::ProfilerChan;
|
||||||
use std::hashmap::HashMap;
|
use std::hashmap::HashMap;
|
||||||
use std::util::replace;
|
use std::util::replace;
|
||||||
|
use extra::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 {
|
||||||
|
@ -31,20 +34,121 @@ pub struct Constellation {
|
||||||
compositor_chan: CompositorChan,
|
compositor_chan: CompositorChan,
|
||||||
resource_task: ResourceTask,
|
resource_task: ResourceTask,
|
||||||
image_cache_task: ImageCacheTask,
|
image_cache_task: ImageCacheTask,
|
||||||
pipelines: HashMap<uint, Pipeline>,
|
pipelines: HashMap<PipelineId, @mut Pipeline>,
|
||||||
navigation_context: NavigationContext,
|
navigation_context: NavigationContext,
|
||||||
next_id: uint,
|
priv next_pipeline_id: PipelineId,
|
||||||
current_painter: Option<uint>,
|
pending_frames: ~[FrameChange],
|
||||||
next_painter: Option<uint>,
|
|
||||||
profiler_chan: ProfilerChan,
|
profiler_chan: ProfilerChan,
|
||||||
opts: Opts,
|
opts: Opts,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stores the ID's of the pipelines previous and next in the browser's history
|
/// Stores the Id of the outermost frame's pipeline, along with a vector of children frames
|
||||||
pub struct NavigationContext {
|
#[deriving(Clone)]
|
||||||
previous: ~[uint],
|
struct FrameTree {
|
||||||
next: ~[uint],
|
pipeline: @mut Pipeline,
|
||||||
current: Option<uint>,
|
parent: Option<@mut Pipeline>,
|
||||||
|
children: ~[@mut FrameTree],
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SendableFrameTree {
|
||||||
|
pipeline: Pipeline,
|
||||||
|
children: ~[SendableFrameTree],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SendableFrameTree {
|
||||||
|
fn contains(&self, id: PipelineId) -> bool {
|
||||||
|
self.pipeline.id == id ||
|
||||||
|
do self.children.iter().any |frame_tree| {
|
||||||
|
frame_tree.contains(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FrameTree {
|
||||||
|
fn contains(&self, id: PipelineId) -> bool {
|
||||||
|
self.pipeline.id == id ||
|
||||||
|
do self.children.iter().any |frame_tree| {
|
||||||
|
frame_tree.contains(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the frame tree whose key is id
|
||||||
|
fn find_mut(@mut self, id: PipelineId) -> Option<@mut FrameTree> {
|
||||||
|
if self.pipeline.id == id { return Some(self); }
|
||||||
|
for self.children.mut_iter().advance |frame_tree| {
|
||||||
|
let found = frame_tree.find_mut(id);
|
||||||
|
if found.is_some() { return found; }
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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.
|
||||||
|
fn replace_child(&mut self, id: PipelineId, new_child: @mut FrameTree) -> Result<@mut FrameTree, @mut FrameTree> {
|
||||||
|
let new_child_cell = Cell::new(new_child);
|
||||||
|
for self.children.mut_iter().advance |child| {
|
||||||
|
let new_child = new_child_cell.take();
|
||||||
|
if child.pipeline.id == id {
|
||||||
|
new_child.parent = child.parent;
|
||||||
|
return Ok(replace(child, new_child));
|
||||||
|
}
|
||||||
|
let replaced = child.replace_child(id, new_child);
|
||||||
|
if replaced.is_ok() {
|
||||||
|
return replaced;
|
||||||
|
}
|
||||||
|
new_child_cell.put_back(replaced.get_err());
|
||||||
|
}
|
||||||
|
Err(new_child_cell.take())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_sendable(&self) -> SendableFrameTree {
|
||||||
|
let mut sendable_frame_tree = SendableFrameTree {
|
||||||
|
pipeline: (*self.pipeline).clone(),
|
||||||
|
children: ~[],
|
||||||
|
};
|
||||||
|
|
||||||
|
for self.children.iter().advance |frame_tree| {
|
||||||
|
sendable_frame_tree.children.push(frame_tree.to_sendable());
|
||||||
|
}
|
||||||
|
sendable_frame_tree
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter(@mut self) -> FrameTreeIterator {
|
||||||
|
FrameTreeIterator {
|
||||||
|
stack: ~[self],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct FrameTreeIterator {
|
||||||
|
priv stack: ~[@mut FrameTree],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Iterator<@mut FrameTree> for FrameTreeIterator {
|
||||||
|
fn next(&mut self) -> Option<@mut FrameTree> {
|
||||||
|
if !self.stack.is_empty() {
|
||||||
|
let next = self.stack.pop();
|
||||||
|
for next.children.iter().advance |&child| {
|
||||||
|
self.stack.push(child);
|
||||||
|
}
|
||||||
|
Some(next)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Represents the portion of a page that is changing in navigating.
|
||||||
|
struct FrameChange {
|
||||||
|
before: Option<PipelineId>,
|
||||||
|
after: @mut FrameTree,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Stores the Id's of the pipelines previous and next in the browser's history
|
||||||
|
struct NavigationContext {
|
||||||
|
previous: ~[@mut FrameTree],
|
||||||
|
next: ~[@mut FrameTree],
|
||||||
|
current: Option<@mut FrameTree>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NavigationContext {
|
impl NavigationContext {
|
||||||
|
@ -57,32 +161,61 @@ 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, e.g., there exists 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) -> uint {
|
pub fn back(&mut self) -> @mut FrameTree {
|
||||||
self.next.push(self.current.get());
|
self.next.push(self.current.swap_unwrap());
|
||||||
self.current = Some(self.previous.pop());
|
self.current = Some(self.previous.pop());
|
||||||
debug!("previous: %? next: %? current: %u", self.previous, self.next, self.current.get());
|
debug!("previous: %? next: %? current: %?", self.previous, self.next, *self.current.get_ref());
|
||||||
self.current.get()
|
self.current.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn forward(&mut self) -> uint {
|
pub fn forward(&mut self) -> @mut FrameTree {
|
||||||
self.previous.push(self.current.get());
|
self.previous.push(self.current.swap_unwrap());
|
||||||
self.current = Some(self.next.pop());
|
self.current = Some(self.next.pop());
|
||||||
debug!("previous: %? next: %? current: %u", self.previous, self.next, self.current.get());
|
debug!("previous: %? next: %? current: %?", self.previous, self.next, *self.current.get_ref());
|
||||||
self.current.get()
|
self.current.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Navigates to a new id, returning all id's evicted from next
|
/// Navigates to a new set of page frames, returning all evicted frame trees
|
||||||
pub fn navigate(&mut self, id: uint) -> ~[uint] {
|
pub fn navigate(&mut self, frame_tree: @mut FrameTree) -> ~[@mut FrameTree] {
|
||||||
debug!("navigating to %u", id);
|
debug!("navigating to %?", frame_tree);
|
||||||
let evicted = replace(&mut self.next, ~[]);
|
let evicted = replace(&mut self.next, ~[]);
|
||||||
do self.current.mutate_default(id) |cur_id| {
|
if self.current.is_some() {
|
||||||
self.previous.push(cur_id);
|
self.previous.push(self.current.swap_unwrap());
|
||||||
id
|
|
||||||
}
|
}
|
||||||
|
self.current = Some(frame_tree);
|
||||||
evicted
|
evicted
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the frame tree whose key is pipeline_id.
|
||||||
|
pub fn find(&mut self, pipeline_id: PipelineId) -> Option<@mut FrameTree> {
|
||||||
|
for self.current.mut_iter().advance |frame_tree| {
|
||||||
|
let found = frame_tree.find_mut(pipeline_id);
|
||||||
|
if found.is_some() { return found; }
|
||||||
|
}
|
||||||
|
let mut forward = self.next.mut_rev_iter();
|
||||||
|
let mut backward = self.previous.mut_rev_iter();
|
||||||
|
loop {
|
||||||
|
match (forward.next(), backward.next()) {
|
||||||
|
(None, None) => {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
(next_forward, next_backward) => {
|
||||||
|
let mut next_forward = next_forward;
|
||||||
|
let mut next_backward = next_backward;
|
||||||
|
for next_forward.mut_iter().advance |frame_tree| {
|
||||||
|
let found = frame_tree.find_mut(pipeline_id);
|
||||||
|
if found.is_some() { return found; }
|
||||||
|
}
|
||||||
|
for next_backward.mut_iter().advance |frame_tree| {
|
||||||
|
let found = frame_tree.find_mut(pipeline_id);
|
||||||
|
if found.is_some() { return found; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Constellation {
|
impl Constellation {
|
||||||
|
@ -114,9 +247,8 @@ impl Constellation {
|
||||||
image_cache_task: image_cache_task.take(),
|
image_cache_task: image_cache_task.take(),
|
||||||
pipelines: HashMap::new(),
|
pipelines: HashMap::new(),
|
||||||
navigation_context: NavigationContext::new(),
|
navigation_context: NavigationContext::new(),
|
||||||
next_id: 0,
|
next_pipeline_id: PipelineId(0),
|
||||||
current_painter: None,
|
pending_frames: ~[],
|
||||||
next_painter: None,
|
|
||||||
profiler_chan: profiler_chan.take(),
|
profiler_chan: profiler_chan.take(),
|
||||||
opts: opts.take(),
|
opts: opts.take(),
|
||||||
};
|
};
|
||||||
|
@ -134,41 +266,216 @@ impl Constellation {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper function for getting a unique pipeline ID
|
/// Helper function for getting a unique pipeline Id
|
||||||
fn get_next_id(&mut self) -> uint {
|
fn get_next_pipeline_id(&mut self) -> PipelineId {
|
||||||
let id = self.next_id;
|
let id = self.next_pipeline_id;
|
||||||
self.next_id = id + 1;
|
self.next_pipeline_id = PipelineId(*id + 1);
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convenience function for getting the currently active frame tree.
|
||||||
|
/// The currently active frame tree should always be the current painter
|
||||||
|
fn current_frame<'a>(&'a self) -> &'a Option<@mut FrameTree> {
|
||||||
|
&self.navigation_context.current
|
||||||
|
}
|
||||||
|
|
||||||
/// 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 {
|
||||||
// Load a new page, usually either from a mouse click or typed url
|
|
||||||
LoadUrlMsg(url) => {
|
// Acknowledgement from the compositor that it has updated its active pipeline id
|
||||||
debug!("received message to load %s", url::to_str(&url));
|
CompositorAck(id) => {
|
||||||
let pipeline_id = self.get_next_id();
|
let pending_index = do self.pending_frames.rposition |frame_change| {
|
||||||
let mut pipeline = Pipeline::create(pipeline_id,
|
frame_change.after.pipeline.id == id
|
||||||
self.chan.clone(),
|
}.expect("Constellation: received compositor ack for frame tree not currently
|
||||||
self.compositor_chan.clone(),
|
pending compositor ack. This is a bug.");
|
||||||
self.image_cache_task.clone(),
|
let frame_tree = self.pending_frames.swap_remove(pending_index).after;
|
||||||
self.resource_task.clone(),
|
self.grant_paint_permission(frame_tree);
|
||||||
self.profiler_chan.clone(),
|
}
|
||||||
copy self.opts);
|
|
||||||
|
ExitMsg(sender) => {
|
||||||
|
for self.pipelines.iter().advance |(_id, ref pipeline)| {
|
||||||
|
pipeline.exit();
|
||||||
|
}
|
||||||
|
self.image_cache_task.exit();
|
||||||
|
self.resource_task.send(resource_task::Exit);
|
||||||
|
|
||||||
|
sender.send(());
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// This should only be called once per constellation, and only by the browser
|
||||||
|
InitLoadUrlMsg(url) => {
|
||||||
|
let pipeline = @mut Pipeline::create(self.get_next_pipeline_id(),
|
||||||
|
self.chan.clone(),
|
||||||
|
self.compositor_chan.clone(),
|
||||||
|
self.image_cache_task.clone(),
|
||||||
|
self.resource_task.clone(),
|
||||||
|
self.profiler_chan.clone(),
|
||||||
|
copy self.opts,
|
||||||
|
{
|
||||||
|
let size = self.compositor_chan.get_size();
|
||||||
|
from_value(Size2D(size.width as uint, size.height as uint))
|
||||||
|
});
|
||||||
if url.path.ends_with(".js") {
|
if url.path.ends_with(".js") {
|
||||||
pipeline.script_chan.send(ExecuteMsg(url));
|
pipeline.script_chan.send(ExecuteMsg(pipeline.id, url));
|
||||||
} else {
|
} else {
|
||||||
pipeline.load(url);
|
pipeline.load(url);
|
||||||
pipeline.navigation_type = Some(constellation_msg::Load);
|
pipeline.navigation_type = Some(constellation_msg::Load);
|
||||||
self.next_painter = Some(pipeline_id);
|
|
||||||
|
self.pending_frames.push(FrameChange{
|
||||||
|
before: None,
|
||||||
|
after: @mut FrameTree {
|
||||||
|
pipeline: pipeline,
|
||||||
|
parent: None,
|
||||||
|
children: ~[],
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
self.pipelines.insert(pipeline_id, pipeline);
|
self.pipelines.insert(pipeline.id, pipeline);
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadIframeUrlMsg(url, source_pipeline_id, size_future) => {
|
||||||
|
// A message from the script associated with pipeline_id that it has
|
||||||
|
// 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
|
||||||
|
// frame tree's children. This message is never the result of a link clicked
|
||||||
|
// or a new url entered.
|
||||||
|
// Start by finding the frame tree matching the pipeline id,
|
||||||
|
// and add the new pipeline to its sub frames. The frame tree
|
||||||
|
// could already be in the navigation context, or it could still
|
||||||
|
// be loading, in which case it is a new id in a constellation.pending_frames
|
||||||
|
// frame change, because pages aren't added to the navi context until they finish
|
||||||
|
// loading (excluding iframes). Which is checked first is seemingly arbitrary
|
||||||
|
let next_pipeline_id = self.get_next_pipeline_id();
|
||||||
|
let frame_tree = {
|
||||||
|
let frame_tree = self.navigation_context.find(source_pipeline_id);
|
||||||
|
match frame_tree {
|
||||||
|
Some(frame_tree) => frame_tree,
|
||||||
|
None => {
|
||||||
|
let frame_change = do self.pending_frames.mut_iter().find_ |frame_change| {
|
||||||
|
frame_change.after.pipeline.id == source_pipeline_id
|
||||||
|
};
|
||||||
|
let frame_change = frame_change.expect("Constellation: source pipeline id
|
||||||
|
of LoadIframeUrlMsg is not in navigation context nor a pending painter.
|
||||||
|
This should be impossible.");
|
||||||
|
frame_change.after
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Compare the pipeline's url to the new url. If the origin is the same,
|
||||||
|
// then reuse the script task in creating the new pipeline
|
||||||
|
let source_pipeline = *self.pipelines.find(&source_pipeline_id).expect("Constellation:
|
||||||
|
source Id of LoadIframeUrlMsg does have an associated pipeline in
|
||||||
|
constellation. This should be impossible.");
|
||||||
|
|
||||||
|
let source_url = source_pipeline.url.clone().expect("Constellation: LoadUrlIframeMsg's
|
||||||
|
source's Url is None. There should never be a LoadUrlIframeMsg from a pipeline
|
||||||
|
that was never given a url to load.");
|
||||||
|
|
||||||
|
let pipeline = @mut if (source_url.host == url.host &&
|
||||||
|
source_url.port == url.port) {
|
||||||
|
// Reuse the script task if same-origin url's
|
||||||
|
Pipeline::with_script(next_pipeline_id,
|
||||||
|
self.chan.clone(),
|
||||||
|
self.compositor_chan.clone(),
|
||||||
|
self.image_cache_task.clone(),
|
||||||
|
self.profiler_chan.clone(),
|
||||||
|
copy self.opts,
|
||||||
|
source_pipeline,
|
||||||
|
size_future)
|
||||||
|
} else {
|
||||||
|
// Create a new script task if not same-origin url's
|
||||||
|
Pipeline::create(next_pipeline_id,
|
||||||
|
self.chan.clone(),
|
||||||
|
self.compositor_chan.clone(),
|
||||||
|
self.image_cache_task.clone(),
|
||||||
|
self.resource_task.clone(),
|
||||||
|
self.profiler_chan.clone(),
|
||||||
|
copy self.opts,
|
||||||
|
size_future)
|
||||||
|
};
|
||||||
|
|
||||||
|
if url.path.ends_with(".js") {
|
||||||
|
pipeline.execute(url);
|
||||||
|
} else {
|
||||||
|
pipeline.load(url);
|
||||||
|
pipeline.navigation_type = None;
|
||||||
|
}
|
||||||
|
frame_tree.children.push(@mut FrameTree {
|
||||||
|
pipeline: pipeline,
|
||||||
|
parent: Some(source_pipeline),
|
||||||
|
children: ~[],
|
||||||
|
});
|
||||||
|
self.pipelines.insert(pipeline.id, pipeline);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) => {
|
||||||
|
debug!("received message to load %s", url::to_str(&url));
|
||||||
|
// Make sure no pending page would be overridden.
|
||||||
|
for self.pending_frames.iter().advance |frame_change| {
|
||||||
|
let old_id = frame_change.before.expect("Constellation: Received load msg
|
||||||
|
from pipeline, but there is no currently active page. This should
|
||||||
|
be impossible.");
|
||||||
|
let changing_frame = self.current_frame().get_ref().find_mut(old_id).expect("Constellation:
|
||||||
|
Pending change has non-active source pipeline. This should be
|
||||||
|
impossible.");
|
||||||
|
if changing_frame.contains(source_id) {
|
||||||
|
// id that sent load msg is being changed already; abort
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
let next_pipeline_id = self.get_next_pipeline_id();
|
||||||
|
let pipeline = @mut Pipeline::create(next_pipeline_id,
|
||||||
|
self.chan.clone(),
|
||||||
|
self.compositor_chan.clone(),
|
||||||
|
self.image_cache_task.clone(),
|
||||||
|
self.resource_task.clone(),
|
||||||
|
self.profiler_chan.clone(),
|
||||||
|
copy self.opts,
|
||||||
|
size_future);
|
||||||
|
|
||||||
|
if url.path.ends_with(".js") {
|
||||||
|
pipeline.script_chan.send(ExecuteMsg(pipeline.id, url));
|
||||||
|
} else {
|
||||||
|
pipeline.load(url);
|
||||||
|
pipeline.navigation_type = Some(constellation_msg::Load);
|
||||||
|
|
||||||
|
let parent = if self.current_frame().get_ref().pipeline.id == source_id {
|
||||||
|
// source_id is the root of the current frame tree; replace whole tree
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
// id is not the root of the current frame tree, but is in the frame tree;
|
||||||
|
// replace only the subtree
|
||||||
|
let source_frame = self.current_frame().get_ref().find_mut(source_id).expect(
|
||||||
|
"Constellation: received a LoadUrlMsg from a pipeline_id associated
|
||||||
|
with a pipeline not in the active frame tree. This should be
|
||||||
|
impossible.");
|
||||||
|
source_frame.parent
|
||||||
|
};
|
||||||
|
self.pending_frames.push(FrameChange{
|
||||||
|
before: Some(source_id),
|
||||||
|
after: @mut FrameTree {
|
||||||
|
pipeline: pipeline,
|
||||||
|
parent: parent,
|
||||||
|
children: ~[],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
self.pipelines.insert(pipeline.id, pipeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle a forward or back request
|
// Handle a forward or back request
|
||||||
NavigateMsg(direction) => {
|
NavigateMsg(direction) => {
|
||||||
debug!("received message to navigate %?", direction);
|
debug!("received message to navigate %?", direction);
|
||||||
let destination_id = match direction {
|
let destination_frame = match direction {
|
||||||
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");
|
||||||
|
@ -184,79 +491,152 @@ impl Constellation {
|
||||||
self.navigation_context.back()
|
self.navigation_context.back()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let mut pipeline = self.pipelines.pop(&destination_id).unwrap();
|
|
||||||
pipeline.navigation_type = Some(constellation_msg::Navigate);
|
for destination_frame.iter().advance |frame| {
|
||||||
pipeline.reload();
|
let pipeline = &frame.pipeline;
|
||||||
self.pipelines.insert(destination_id, pipeline);
|
pipeline.navigation_type = Some(constellation_msg::Navigate);
|
||||||
self.next_painter = Some(destination_id);
|
pipeline.reload();
|
||||||
self.update_painter();
|
}
|
||||||
|
self.compositor_chan.send(SetIds(destination_frame.to_sendable(), self.chan.clone()));
|
||||||
|
|
||||||
|
let before_id = self.current_frame().get_ref().pipeline.id.clone();
|
||||||
|
self.pending_frames.clear();
|
||||||
|
self.pending_frames.push(FrameChange {
|
||||||
|
before: Some(before_id),
|
||||||
|
after: destination_frame,
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO(tkuehn): what is the "critical point" beyond which pending frames
|
||||||
|
// should not be cleared? Currently, the behavior is that forward/back
|
||||||
|
// navigation always has navigation priority, and after that new page loading is
|
||||||
|
// first come, first served.
|
||||||
|
let old = self.current_frame().get_ref();
|
||||||
|
for old.iter().advance |frame| {
|
||||||
|
frame.pipeline.revoke_paint_permission();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notification that rendering has finished and is requesting permission to paint.
|
// Notification that rendering has finished and is requesting permission to paint.
|
||||||
RendererReadyMsg(pipeline_id) => {
|
RendererReadyMsg(pipeline_id) => {
|
||||||
let next_painter = self.next_painter;
|
// This message could originate from a pipeline in the navigation context or
|
||||||
for next_painter.iter().advance |&id| {
|
// from a pending frame. The only time that we will grant paint permission is
|
||||||
if pipeline_id == id {
|
// when the message originates from a pending frame or the current frame.
|
||||||
self.update_painter();
|
|
||||||
|
for self.current_frame().iter().advance |current_frame| {
|
||||||
|
// Messages originating in the current frame are not navigations;
|
||||||
|
// TODO(tkuehn): In fact, this kind of message might be provably
|
||||||
|
// impossible to occur.
|
||||||
|
if current_frame.contains(pipeline_id) {
|
||||||
|
for current_frame.iter().advance |frame| {
|
||||||
|
frame.pipeline.grant_paint_permission();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the pending frame change whose new pipeline id is pipeline_id.
|
||||||
|
// If it is not found, it simply means that this pipeline will not receive
|
||||||
|
// permission to paint.
|
||||||
|
let pending_index = do self.pending_frames.rposition |frame_change| {
|
||||||
|
frame_change.after.pipeline.id == pipeline_id
|
||||||
|
};
|
||||||
|
for pending_index.iter().advance |&pending_index| {
|
||||||
|
let frame_change = self.pending_frames.swap_remove(pending_index);
|
||||||
|
let to_add = frame_change.after;
|
||||||
|
|
||||||
|
// Create the next frame tree that will be given to the compositor
|
||||||
|
let next_frame_tree = match to_add.parent {
|
||||||
|
None => to_add, // to_add is the root
|
||||||
|
Some(_parent) => self.current_frame().get(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// If there are frames to revoke permission from, do so now.
|
||||||
|
match frame_change.before {
|
||||||
|
Some(revoke_id) => {
|
||||||
|
let current_frame = self.current_frame().get();
|
||||||
|
|
||||||
|
let to_revoke = current_frame.find_mut(revoke_id).expect(
|
||||||
|
"Constellation: pending frame change refers to an old
|
||||||
|
frame not contained in the current frame. This is a bug");
|
||||||
|
|
||||||
|
for to_revoke.iter().advance |frame| {
|
||||||
|
frame.pipeline.revoke_paint_permission();
|
||||||
|
}
|
||||||
|
|
||||||
|
// If to_add is not the root frame, then replace revoked_frame with it
|
||||||
|
if to_add.parent.is_some() {
|
||||||
|
next_frame_tree.replace_child(revoke_id, to_add);
|
||||||
|
}
|
||||||
|
self.pending_frames.push(FrameChange {
|
||||||
|
before: Some(revoke_id),
|
||||||
|
after: next_frame_tree
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
None => {
|
||||||
|
// Add to_add to parent's children, if it is not the root
|
||||||
|
let parent = &to_add.parent;
|
||||||
|
let to_add = Cell::new(to_add);
|
||||||
|
for parent.iter().advance |parent| {
|
||||||
|
let parent = next_frame_tree.find_mut(parent.id).expect(
|
||||||
|
"Constellation: pending frame has a parent frame that is not
|
||||||
|
active. This is a bug.");
|
||||||
|
parent.children.push(to_add.take());
|
||||||
|
}
|
||||||
|
self.pending_frames.push(FrameChange {
|
||||||
|
before: None,
|
||||||
|
after: next_frame_tree
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.compositor_chan.send(SetIds(next_frame_tree.to_sendable(), self.chan.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ResizedWindowBroadcast(new_size) => match *self.current_frame() {
|
||||||
|
Some(ref current_frame) => {
|
||||||
|
let current_frame_id = current_frame.pipeline.id.clone();
|
||||||
|
for self.navigation_context.previous.iter().advance |frame_tree| {
|
||||||
|
let pipeline = &frame_tree.pipeline;
|
||||||
|
if current_frame_id != pipeline.id {
|
||||||
|
pipeline.script_chan.send(ResizeInactiveMsg(new_size));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for self.navigation_context.next.iter().advance |frame_tree| {
|
||||||
|
let pipeline = &frame_tree.pipeline;
|
||||||
|
if current_frame_id != pipeline.id {
|
||||||
|
pipeline.script_chan.send(ResizeInactiveMsg(new_size));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
for self.navigation_context.previous.iter().advance |frame_tree| {
|
||||||
|
frame_tree.pipeline.script_chan.send(ResizeInactiveMsg(new_size));
|
||||||
|
}
|
||||||
|
for self.navigation_context.next.iter().advance |frame_tree| {
|
||||||
|
frame_tree.pipeline.script_chan.send(ResizeInactiveMsg(new_size));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ResizedWindowBroadcast(new_size) => match self.current_painter {
|
|
||||||
Some(current_painter_id) => for self.pipelines.iter().advance |(&id, pipeline)| {
|
|
||||||
if current_painter_id != id {
|
|
||||||
pipeline.script_chan.send(ResizeInactiveMsg(new_size));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
None => for self.pipelines.iter().advance |(_, pipeline)| {
|
|
||||||
pipeline.script_chan.send(ResizeInactiveMsg(new_size));
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
// Acknowledgement from the compositor that it has updated its active pipeline id
|
|
||||||
CompositorAck(id) => {
|
|
||||||
self.grant_paint_permission(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
ExitMsg(sender) => {
|
|
||||||
for self.pipelines.iter().advance |(_, pipeline)| {
|
|
||||||
pipeline.exit();
|
|
||||||
}
|
|
||||||
self.image_cache_task.exit();
|
|
||||||
self.resource_task.send(resource_task::Exit);
|
|
||||||
|
|
||||||
sender.send(());
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_painter(&mut self) {
|
// Grants a frame tree permission to paint; optionally updates navigation to reflect a new page
|
||||||
let current_painter = replace(&mut self.current_painter, None);
|
fn grant_paint_permission(&mut self, frame_tree: @mut FrameTree) {
|
||||||
for current_painter.iter().advance |id| {
|
// Give permission to paint to the new frame and all child frames
|
||||||
self.pipelines.get(id).render_chan.send(PaintPermissionRevoked);
|
for frame_tree.iter().advance |frame| {
|
||||||
|
frame.pipeline.grant_paint_permission();
|
||||||
}
|
}
|
||||||
let id = replace(&mut self.next_painter, None);
|
|
||||||
let id = id.expect("constellation: called update painter when there was no next painter");
|
|
||||||
let pipeline = self.pipelines.get(&id);
|
|
||||||
self.compositor_chan.send(SetLayoutRenderChans(pipeline.layout_chan.clone(),
|
|
||||||
pipeline.render_chan.clone(),
|
|
||||||
id,
|
|
||||||
self.chan.clone()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Grants a renderer permission to paint; optionally updates navigation to reflect a new page
|
// Don't navigate on Navigate type (or None, as in the case of parsed iframes that finish
|
||||||
fn grant_paint_permission(&mut self, id: uint) {
|
// loading)
|
||||||
let pipeline = self.pipelines.get(&id);
|
match frame_tree.pipeline.navigation_type {
|
||||||
pipeline.render_chan.send(PaintPermissionGranted);
|
Some(constellation_msg::Load) => {
|
||||||
self.current_painter = Some(id);
|
let evicted = self.navigation_context.navigate(frame_tree);
|
||||||
// Don't navigate on Navigate type, because that is handled by forward/back
|
for evicted.iter().advance |frame_tree| {
|
||||||
match pipeline.navigation_type.get() {
|
frame_tree.pipeline.exit();
|
||||||
constellation_msg::Load => {
|
|
||||||
let evicted = self.navigation_context.navigate(id);
|
|
||||||
for evicted.iter().advance |id| {
|
|
||||||
self.pipelines.get(id).exit();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
|
@ -34,9 +34,10 @@ use script::layout_interface::{AddStylesheetMsg, ContentBoxQuery};
|
||||||
use script::layout_interface::{HitTestQuery, ContentBoxResponse, HitTestResponse};
|
use script::layout_interface::{HitTestQuery, ContentBoxResponse, HitTestResponse};
|
||||||
use script::layout_interface::{ContentBoxesQuery, ContentBoxesResponse, ExitMsg, LayoutQuery};
|
use script::layout_interface::{ContentBoxesQuery, ContentBoxesResponse, ExitMsg, LayoutQuery};
|
||||||
use script::layout_interface::{MatchSelectorsDocumentDamage, Msg};
|
use script::layout_interface::{MatchSelectorsDocumentDamage, Msg};
|
||||||
use script::layout_interface::{QueryMsg, RouteScriptMsg, Reflow, ReflowDocumentDamage};
|
use script::layout_interface::{QueryMsg, Reflow, ReflowDocumentDamage};
|
||||||
use script::layout_interface::{ReflowForDisplay, ReflowMsg};
|
use script::layout_interface::{ReflowForDisplay, ReflowMsg};
|
||||||
use script::script_task::{ReflowCompleteMsg, ScriptChan, ScriptMsg, SendEventMsg};
|
use script::script_task::{ReflowCompleteMsg, ScriptChan, SendEventMsg};
|
||||||
|
use servo_msg::constellation_msg::{ConstellationChan, PipelineId};
|
||||||
use servo_net::image_cache_task::{ImageCacheTask, ImageResponseMsg};
|
use servo_net::image_cache_task::{ImageCacheTask, ImageResponseMsg};
|
||||||
use servo_net::local_image_cache::LocalImageCache;
|
use servo_net::local_image_cache::LocalImageCache;
|
||||||
use servo_util::tree::{TreeNodeRef, TreeUtils};
|
use servo_util::tree::{TreeNodeRef, TreeUtils};
|
||||||
|
@ -45,7 +46,9 @@ use servo_util::time;
|
||||||
use extra::net::url::Url;
|
use extra::net::url::Url;
|
||||||
|
|
||||||
struct LayoutTask {
|
struct LayoutTask {
|
||||||
|
id: PipelineId,
|
||||||
port: Port<Msg>,
|
port: Port<Msg>,
|
||||||
|
constellation_chan: ConstellationChan,
|
||||||
script_chan: ScriptChan,
|
script_chan: ScriptChan,
|
||||||
render_chan: RenderChan,
|
render_chan: RenderChan,
|
||||||
image_cache_task: ImageCacheTask,
|
image_cache_task: ImageCacheTask,
|
||||||
|
@ -62,25 +65,38 @@ struct LayoutTask {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LayoutTask {
|
impl LayoutTask {
|
||||||
pub fn create(port: Port<Msg>,
|
pub fn create(id: PipelineId,
|
||||||
script_chan: ScriptChan,
|
port: Port<Msg>,
|
||||||
render_chan: RenderChan,
|
constellation_chan: ConstellationChan,
|
||||||
img_cache_task: ImageCacheTask,
|
script_chan: ScriptChan,
|
||||||
opts: Opts,
|
render_chan: RenderChan,
|
||||||
profiler_chan: ProfilerChan) {
|
img_cache_task: ImageCacheTask,
|
||||||
|
opts: Opts,
|
||||||
|
profiler_chan: ProfilerChan) {
|
||||||
|
|
||||||
let port = Cell::new(port);
|
let port = Cell::new(port);
|
||||||
|
let constellation_chan = Cell::new(constellation_chan);
|
||||||
|
let script_chan = Cell::new(script_chan);
|
||||||
|
let render_chan = Cell::new(render_chan);
|
||||||
|
let img_cache_task = Cell::new(img_cache_task);
|
||||||
|
let profiler_chan = Cell::new(profiler_chan);
|
||||||
|
|
||||||
do spawn {
|
do spawn {
|
||||||
let mut layout = LayoutTask::new(port.take(),
|
let mut layout = LayoutTask::new(id,
|
||||||
script_chan.clone(),
|
port.take(),
|
||||||
render_chan.clone(),
|
constellation_chan.take(),
|
||||||
img_cache_task.clone(),
|
script_chan.take(),
|
||||||
&opts,
|
render_chan.take(),
|
||||||
profiler_chan.clone());
|
img_cache_task.take(),
|
||||||
|
&opts,
|
||||||
|
profiler_chan.take());
|
||||||
layout.start();
|
layout.start();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new(port: Port<Msg>,
|
fn new(id: PipelineId,
|
||||||
|
port: Port<Msg>,
|
||||||
|
constellation_chan: ConstellationChan,
|
||||||
script_chan: ScriptChan,
|
script_chan: ScriptChan,
|
||||||
render_chan: RenderChan,
|
render_chan: RenderChan,
|
||||||
image_cache_task: ImageCacheTask,
|
image_cache_task: ImageCacheTask,
|
||||||
|
@ -90,7 +106,9 @@ impl LayoutTask {
|
||||||
let fctx = @mut FontContext::new(opts.render_backend, true, profiler_chan.clone());
|
let fctx = @mut FontContext::new(opts.render_backend, true, profiler_chan.clone());
|
||||||
|
|
||||||
LayoutTask {
|
LayoutTask {
|
||||||
|
id: id,
|
||||||
port: port,
|
port: port,
|
||||||
|
constellation_chan: constellation_chan,
|
||||||
script_chan: script_chan,
|
script_chan: script_chan,
|
||||||
render_chan: render_chan,
|
render_chan: render_chan,
|
||||||
image_cache_task: image_cache_task.clone(),
|
image_cache_task: image_cache_task.clone(),
|
||||||
|
@ -140,10 +158,6 @@ impl LayoutTask {
|
||||||
self.handle_query(query.take());
|
self.handle_query(query.take());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RouteScriptMsg(script_msg) => {
|
|
||||||
debug!("layout: routing %? to script task", script_msg);
|
|
||||||
self.route_script_msg(script_msg);
|
|
||||||
}
|
|
||||||
ExitMsg => {
|
ExitMsg => {
|
||||||
debug!("layout: ExitMsg received");
|
debug!("layout: ExitMsg received");
|
||||||
return false
|
return false
|
||||||
|
@ -265,7 +279,7 @@ impl LayoutTask {
|
||||||
// FIXME(pcwalton): This should probably be *one* channel, but we can't fix this without
|
// FIXME(pcwalton): This should probably be *one* channel, but we can't fix this without
|
||||||
// either select or a filtered recv() that only looks for messages of a given type.
|
// either select or a filtered recv() that only looks for messages of a given type.
|
||||||
data.script_join_chan.send(());
|
data.script_join_chan.send(());
|
||||||
data.script_chan.send(ReflowCompleteMsg);
|
data.script_chan.send(ReflowCompleteMsg(self.id));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handles a query from the script task. This is the main routine that DOM functions like
|
/// Handles a query from the script task. This is the main routine that DOM functions like
|
||||||
|
@ -381,12 +395,6 @@ impl LayoutTask {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(tkuehn): once there are multiple script tasks, this is where the layout task will
|
|
||||||
// determine which script task should receive the message. The prototype will need to change
|
|
||||||
fn route_script_msg(&self, script_msg: ScriptMsg) {
|
|
||||||
self.script_chan.send(script_msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
// When images can't be loaded in time to display they trigger
|
// When images can't be loaded in time to display they trigger
|
||||||
// this callback in some task somewhere. This will send a message
|
// this callback in some task somewhere. This will send a message
|
||||||
// to the script task, and ultimately cause the image to be
|
// to the script task, and ultimately cause the image to be
|
||||||
|
@ -398,10 +406,11 @@ impl LayoutTask {
|
||||||
// make multiple copies of the callback, and the dom event
|
// make multiple copies of the callback, and the dom event
|
||||||
// channel is not a copyable type, so this is actually a
|
// channel is not a copyable type, so this is actually a
|
||||||
// little factory to produce callbacks
|
// little factory to produce callbacks
|
||||||
|
let id = self.id.clone();
|
||||||
let f: @fn() -> ~fn(ImageResponseMsg) = || {
|
let f: @fn() -> ~fn(ImageResponseMsg) = || {
|
||||||
let script_chan = script_chan.clone();
|
let script_chan = script_chan.clone();
|
||||||
let f: ~fn(ImageResponseMsg) = |_| {
|
let f: ~fn(ImageResponseMsg) = |_| {
|
||||||
script_chan.send(SendEventMsg(ReflowEvent))
|
script_chan.send(SendEventMsg(id.clone(), ReflowEvent))
|
||||||
};
|
};
|
||||||
f
|
f
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,22 +5,26 @@
|
||||||
use extra::net::url::Url;
|
use extra::net::url::Url;
|
||||||
use compositing::CompositorChan;
|
use compositing::CompositorChan;
|
||||||
use gfx::render_task::{RenderChan, RenderTask};
|
use gfx::render_task::{RenderChan, RenderTask};
|
||||||
|
use gfx::render_task::{PaintPermissionGranted, PaintPermissionRevoked};
|
||||||
use gfx::render_task;
|
use gfx::render_task;
|
||||||
use gfx::opts::Opts;
|
use gfx::opts::Opts;
|
||||||
use layout::layout_task::LayoutTask;
|
use layout::layout_task::LayoutTask;
|
||||||
use script::layout_interface::LayoutChan;
|
use script::layout_interface::LayoutChan;
|
||||||
use script::script_task::LoadMsg;
|
use script::script_task::{ExecuteMsg, LoadMsg};
|
||||||
use servo_msg::constellation_msg::{ConstellationChan, NavigationType};
|
use servo_msg::constellation_msg::{ConstellationChan, NavigationType, PipelineId};
|
||||||
use script::script_task::{ScriptTask, ScriptChan};
|
use script::script_task::{AttachLayoutMsg, NewLayoutInfo, ScriptTask, ScriptChan};
|
||||||
use script::script_task;
|
use script::script_task;
|
||||||
use servo_net::image_cache_task::ImageCacheTask;
|
use servo_net::image_cache_task::ImageCacheTask;
|
||||||
use servo_net::resource_task::ResourceTask;
|
use servo_net::resource_task::ResourceTask;
|
||||||
use servo_util::time::ProfilerChan;
|
use servo_util::time::ProfilerChan;
|
||||||
|
use geom::size::Size2D;
|
||||||
|
use extra::future::Future;
|
||||||
use std::comm;
|
use std::comm;
|
||||||
|
|
||||||
/// A uniquely-identifiable pipeline of stript task, layout task, and render task.
|
/// A uniquely-identifiable pipeline of stript task, layout task, and render task.
|
||||||
|
#[deriving(Clone)]
|
||||||
pub struct Pipeline {
|
pub struct Pipeline {
|
||||||
id: uint,
|
id: PipelineId,
|
||||||
script_chan: ScriptChan,
|
script_chan: ScriptChan,
|
||||||
layout_chan: LayoutChan,
|
layout_chan: LayoutChan,
|
||||||
render_chan: RenderChan,
|
render_chan: RenderChan,
|
||||||
|
@ -31,15 +35,15 @@ pub struct Pipeline {
|
||||||
|
|
||||||
impl Pipeline {
|
impl Pipeline {
|
||||||
/// Starts a render task, layout task, and script task. Returns the channels wrapped in a struct.
|
/// Starts a render task, layout task, and script task. Returns the channels wrapped in a struct.
|
||||||
pub fn create(id: uint,
|
pub fn with_script(id: PipelineId,
|
||||||
constellation_chan: ConstellationChan,
|
constellation_chan: ConstellationChan,
|
||||||
compositor_chan: CompositorChan,
|
compositor_chan: CompositorChan,
|
||||||
image_cache_task: ImageCacheTask,
|
image_cache_task: ImageCacheTask,
|
||||||
resource_task: ResourceTask,
|
profiler_chan: ProfilerChan,
|
||||||
profiler_chan: ProfilerChan,
|
opts: Opts,
|
||||||
opts: Opts) -> Pipeline {
|
script_pipeline: &Pipeline,
|
||||||
|
size_future: Future<Size2D<uint>>) -> Pipeline {
|
||||||
|
|
||||||
let (script_port, script_chan) = special_stream!(ScriptChan);
|
|
||||||
let (layout_port, layout_chan) = special_stream!(LayoutChan);
|
let (layout_port, layout_chan) = special_stream!(LayoutChan);
|
||||||
let (render_port, render_chan) = special_stream!(RenderChan);
|
let (render_port, render_chan) = special_stream!(RenderChan);
|
||||||
|
|
||||||
|
@ -49,30 +53,76 @@ impl Pipeline {
|
||||||
copy opts,
|
copy opts,
|
||||||
profiler_chan.clone());
|
profiler_chan.clone());
|
||||||
|
|
||||||
LayoutTask::create(layout_port,
|
LayoutTask::create(id,
|
||||||
script_chan.clone(),
|
layout_port,
|
||||||
|
constellation_chan,
|
||||||
|
script_pipeline.script_chan.clone(),
|
||||||
render_chan.clone(),
|
render_chan.clone(),
|
||||||
image_cache_task.clone(),
|
image_cache_task.clone(),
|
||||||
copy opts,
|
copy opts,
|
||||||
profiler_chan);
|
profiler_chan);
|
||||||
|
|
||||||
|
let new_layout_info = NewLayoutInfo {
|
||||||
|
old_id: script_pipeline.id.clone(),
|
||||||
|
new_id: id,
|
||||||
|
layout_chan: layout_chan.clone(),
|
||||||
|
size_future: size_future,
|
||||||
|
};
|
||||||
|
|
||||||
|
script_pipeline.script_chan.send(AttachLayoutMsg(new_layout_info));
|
||||||
|
|
||||||
|
Pipeline::new(id,
|
||||||
|
script_pipeline.script_chan.clone(),
|
||||||
|
layout_chan,
|
||||||
|
render_chan)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create(id: PipelineId,
|
||||||
|
constellation_chan: ConstellationChan,
|
||||||
|
compositor_chan: CompositorChan,
|
||||||
|
image_cache_task: ImageCacheTask,
|
||||||
|
resource_task: ResourceTask,
|
||||||
|
profiler_chan: ProfilerChan,
|
||||||
|
opts: Opts,
|
||||||
|
size: Future<Size2D<uint>>) -> Pipeline {
|
||||||
|
|
||||||
|
let (script_port, script_chan) = special_stream!(ScriptChan);
|
||||||
|
let (layout_port, layout_chan) = special_stream!(LayoutChan);
|
||||||
|
let (render_port, render_chan) = special_stream!(RenderChan);
|
||||||
|
|
||||||
ScriptTask::create(id,
|
ScriptTask::create(id,
|
||||||
compositor_chan.clone(),
|
compositor_chan.clone(),
|
||||||
layout_chan.clone(),
|
layout_chan.clone(),
|
||||||
script_port,
|
script_port,
|
||||||
script_chan.clone(),
|
script_chan.clone(),
|
||||||
constellation_chan,
|
constellation_chan.clone(),
|
||||||
resource_task,
|
resource_task,
|
||||||
image_cache_task,
|
image_cache_task.clone(),
|
||||||
compositor_chan.get_size());
|
size);
|
||||||
|
|
||||||
|
|
||||||
|
RenderTask::create(id,
|
||||||
|
render_port,
|
||||||
|
compositor_chan.clone(),
|
||||||
|
copy opts,
|
||||||
|
profiler_chan.clone());
|
||||||
|
|
||||||
|
LayoutTask::create(id,
|
||||||
|
layout_port,
|
||||||
|
constellation_chan,
|
||||||
|
script_chan.clone(),
|
||||||
|
render_chan.clone(),
|
||||||
|
image_cache_task,
|
||||||
|
copy opts,
|
||||||
|
profiler_chan);
|
||||||
Pipeline::new(id,
|
Pipeline::new(id,
|
||||||
script_chan,
|
script_chan,
|
||||||
layout_chan,
|
layout_chan,
|
||||||
render_chan)
|
render_chan)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(id: uint,
|
pub fn new(id: PipelineId,
|
||||||
script_chan: ScriptChan,
|
script_chan: ScriptChan,
|
||||||
layout_chan: LayoutChan,
|
layout_chan: LayoutChan,
|
||||||
render_chan: RenderChan)
|
render_chan: RenderChan)
|
||||||
|
@ -89,12 +139,25 @@ impl Pipeline {
|
||||||
|
|
||||||
pub fn load(&mut self, url: Url) {
|
pub fn load(&mut self, url: Url) {
|
||||||
self.url = Some(url.clone());
|
self.url = Some(url.clone());
|
||||||
self.script_chan.send(LoadMsg(url));
|
self.script_chan.send(LoadMsg(self.id, url));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn execute(&mut self, url: Url) {
|
||||||
|
self.url = Some(url.clone());
|
||||||
|
self.script_chan.send(ExecuteMsg(self.id, url));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn grant_paint_permission(&self) {
|
||||||
|
self.render_chan.send(PaintPermissionGranted);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn revoke_paint_permission(&self) {
|
||||||
|
self.render_chan.send(PaintPermissionRevoked);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reload(&self) {
|
pub fn reload(&self) {
|
||||||
for self.url.iter().advance |url| {
|
for self.url.iter().advance |url| {
|
||||||
self.script_chan.send(LoadMsg(url.clone()));
|
self.script_chan.send(LoadMsg(self.id, url.clone()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ extern mod core_text;
|
||||||
|
|
||||||
use compositing::{CompositorChan, CompositorTask};
|
use compositing::{CompositorChan, CompositorTask};
|
||||||
use constellation::Constellation;
|
use constellation::Constellation;
|
||||||
use servo_msg::constellation_msg::{ExitMsg, LoadUrlMsg};
|
use servo_msg::constellation_msg::{ExitMsg, InitLoadUrlMsg};
|
||||||
|
|
||||||
use gfx::opts;
|
use gfx::opts;
|
||||||
use servo_net::image_cache_task::ImageCacheTask;
|
use servo_net::image_cache_task::ImageCacheTask;
|
||||||
|
@ -133,7 +133,7 @@ fn run(opts: &Opts) {
|
||||||
|
|
||||||
// Send the URL command to the constellation.
|
// Send the URL command to the constellation.
|
||||||
for opts.urls.iter().advance |filename| {
|
for opts.urls.iter().advance |filename| {
|
||||||
constellation_chan.send(LoadUrlMsg(make_url(copy *filename, None)))
|
constellation_chan.send(InitLoadUrlMsg(make_url(copy *filename, None)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for the compositor to shut down.
|
// Wait for the compositor to shut down.
|
||||||
|
|
|
@ -7,6 +7,7 @@ use azure::azure::AzGLContext;
|
||||||
use geom::rect::Rect;
|
use geom::rect::Rect;
|
||||||
use geom::size::Size2D;
|
use geom::size::Size2D;
|
||||||
|
|
||||||
|
use constellation_msg::PipelineId;
|
||||||
use extra::arc;
|
use extra::arc;
|
||||||
|
|
||||||
|
|
||||||
|
@ -60,7 +61,7 @@ pub trait RenderListener {
|
||||||
fn new_layer(&self, Size2D<uint>, uint);
|
fn new_layer(&self, Size2D<uint>, uint);
|
||||||
fn resize_layer(&self, Size2D<uint>);
|
fn resize_layer(&self, Size2D<uint>);
|
||||||
fn delete_layer(&self);
|
fn delete_layer(&self);
|
||||||
fn paint(&self, id: uint, layer_buffer_set: arc::ARC<LayerBufferSet>, new_size: Size2D<uint>);
|
fn paint(&self, id: PipelineId, layer_buffer_set: arc::ARC<LayerBufferSet>, new_size: Size2D<uint>);
|
||||||
fn set_render_state(&self, render_state: RenderState);
|
fn set_render_state(&self, render_state: RenderState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
use std::comm::{Chan, SharedChan};
|
use std::comm::{Chan, SharedChan};
|
||||||
use extra::net::url::Url;
|
use extra::net::url::Url;
|
||||||
|
use extra::future::Future;
|
||||||
use geom::size::Size2D;
|
use geom::size::Size2D;
|
||||||
|
|
||||||
#[deriving(Clone)]
|
#[deriving(Clone)]
|
||||||
|
@ -26,21 +27,28 @@ impl ConstellationChan {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum Msg {
|
pub enum Msg {
|
||||||
LoadUrlMsg(Url),
|
CompositorAck(PipelineId),
|
||||||
NavigateMsg(NavigationDirection),
|
|
||||||
ExitMsg(Chan<()>),
|
ExitMsg(Chan<()>),
|
||||||
RendererReadyMsg(uint),
|
InitLoadUrlMsg(Url),
|
||||||
CompositorAck(uint),
|
LoadUrlMsg(PipelineId, Url, Future<Size2D<uint>>),
|
||||||
|
LoadIframeUrlMsg(Url, PipelineId, Future<Size2D<uint>>),
|
||||||
|
NavigateMsg(NavigationDirection),
|
||||||
|
RendererReadyMsg(PipelineId),
|
||||||
ResizedWindowBroadcast(Size2D<uint>),
|
ResizedWindowBroadcast(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
|
||||||
|
#[deriving(Clone, Eq, IterBytes)]
|
||||||
enum NavigationType {
|
enum NavigationType {
|
||||||
Load, // entered or clicked on a url
|
Load, // entered or clicked on a url
|
||||||
Navigate, // browser forward/back buttons
|
Navigate, // browser forward/back buttons
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[deriving(Clone, Eq, IterBytes)]
|
||||||
pub enum NavigationDirection {
|
pub enum NavigationDirection {
|
||||||
Forward,
|
Forward,
|
||||||
Back,
|
Back,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[deriving(Clone, Eq, IterBytes)]
|
||||||
|
pub struct PipelineId(uint);
|
||||||
|
|
|
@ -2458,8 +2458,8 @@ def CreateBindingJSObject(descriptor, parent):
|
||||||
if descriptor.proxy:
|
if descriptor.proxy:
|
||||||
handler = """ //let cache = ptr::to_unsafe_ptr(aObject.get_wrappercache());
|
handler = """ //let cache = ptr::to_unsafe_ptr(aObject.get_wrappercache());
|
||||||
|
|
||||||
let script_context = task_from_context(aCx);
|
let page = page_from_context(aCx);
|
||||||
let handler = (*script_context).dom_static.proxy_handlers.get(&(PrototypeList::id::%s as uint));
|
let handler = (*page).js_info.get_ref().dom_static.proxy_handlers.get(&(PrototypeList::id::%s as uint));
|
||||||
""" % descriptor.name
|
""" % descriptor.name
|
||||||
create = handler + """ let obj = NewProxyObject(aCx, *handler,
|
create = handler + """ let obj = NewProxyObject(aCx, *handler,
|
||||||
ptr::to_unsafe_ptr(&RUST_PRIVATE_TO_JSVAL(squirrel_away(aObject) as *libc::c_void)),
|
ptr::to_unsafe_ptr(&RUST_PRIVATE_TO_JSVAL(squirrel_away(aObject) as *libc::c_void)),
|
||||||
|
@ -2629,8 +2629,8 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
|
||||||
elif props.hasNonChromeOnly():
|
elif props.hasNonChromeOnly():
|
||||||
idsToInit.append(props.variableName(False))
|
idsToInit.append(props.variableName(False))
|
||||||
if len(idsToInit) > 0:
|
if len(idsToInit) > 0:
|
||||||
setup = CGList([CGGeneric("let script_context = task_from_context(aCx);"),
|
setup = CGList([CGGeneric("let page = page_from_context(aCx);"),
|
||||||
CGList([CGGeneric("let %s_ids_mut = (*script_context).dom_static.attribute_ids.get(&(PrototypeList::id::%s as uint));" % (varname, self.descriptor.name)) for varname in idsToInit], '\n')], '\n')
|
CGList([CGGeneric("let %s_ids_mut = (*page).js_info.get_ref().dom_static.attribute_ids.get(&(PrototypeList::id::%s as uint));" % (varname, self.descriptor.name)) for varname in idsToInit], '\n')], '\n')
|
||||||
initIds = CGList(
|
initIds = CGList(
|
||||||
[CGGeneric("!InitIds(aCx, %s, *%s_ids_mut)" % (varname, varname)) for
|
[CGGeneric("!InitIds(aCx, %s, *%s_ids_mut)" % (varname, varname)) for
|
||||||
varname in idsToInit], ' ||\n')
|
varname in idsToInit], ' ||\n')
|
||||||
|
@ -2818,7 +2818,7 @@ class CGDefineDOMInterfaceMethod(CGAbstractMethod):
|
||||||
else:
|
else:
|
||||||
getter = "GetConstructorObject"
|
getter = "GetConstructorObject"
|
||||||
|
|
||||||
body = " let script_context = task_from_context(aCx);\n"
|
body = "let page = page_from_context(aCx);"
|
||||||
#XXXjdm This self.descriptor.concrete check shouldn't be necessary
|
#XXXjdm This self.descriptor.concrete check shouldn't be necessary
|
||||||
if not self.descriptor.concrete or self.descriptor.proxy:
|
if not self.descriptor.concrete or self.descriptor.proxy:
|
||||||
body += """ let traps = ProxyTraps {
|
body += """ let traps = ProxyTraps {
|
||||||
|
@ -2851,12 +2851,12 @@ class CGDefineDOMInterfaceMethod(CGAbstractMethod):
|
||||||
getElementIfPresent: ptr::null(),
|
getElementIfPresent: ptr::null(),
|
||||||
getPrototypeOf: ptr::null()
|
getPrototypeOf: ptr::null()
|
||||||
};
|
};
|
||||||
(*script_context).dom_static.proxy_handlers.insert(PrototypeList::id::%s as uint,
|
(*page).js_info.get_mut_ref().dom_static.proxy_handlers.insert(PrototypeList::id::%s as uint,
|
||||||
CreateProxyHandler(ptr::to_unsafe_ptr(&traps), ptr::to_unsafe_ptr(&Class) as *libc::c_void));
|
CreateProxyHandler(ptr::to_unsafe_ptr(&traps), ptr::to_unsafe_ptr(&Class) as *libc::c_void));
|
||||||
|
|
||||||
""" % self.descriptor.name
|
""" % self.descriptor.name
|
||||||
else:
|
else:
|
||||||
body += """ (*script_context).dom_static.attribute_ids.insert(PrototypeList::id::%s as uint,
|
body += """ (*page).js_info.get_ref().dom_static.attribute_ids.insert(PrototypeList::id::%s as uint,
|
||||||
vec::cast_to_mut(vec::from_slice(sAttributes_ids)));
|
vec::cast_to_mut(vec::from_slice(sAttributes_ids)));
|
||||||
""" % self.descriptor.name
|
""" % self.descriptor.name
|
||||||
body = "" #XXXjdm xray stuff isn't necessary yet
|
body = "" #XXXjdm xray stuff isn't necessary yet
|
||||||
|
@ -3445,12 +3445,12 @@ class CGXrayHelper(CGAbstractExternMethod):
|
||||||
def definition_body(self):
|
def definition_body(self):
|
||||||
varNames = self.properties.variableNames(True)
|
varNames = self.properties.variableNames(True)
|
||||||
|
|
||||||
setup = "let script_context = task_from_context(cx);\n"
|
setup = "let page = page_from_context(cx);\n"
|
||||||
|
|
||||||
methods = self.properties.methods
|
methods = self.properties.methods
|
||||||
if methods.hasNonChromeOnly() or methods.hasChromeOnly():
|
if methods.hasNonChromeOnly() or methods.hasChromeOnly():
|
||||||
methodArgs = "Some(vec::zip_slice(%(methods)s, *method_ids))" % varNames
|
methodArgs = "Some(vec::zip_slice(%(methods)s, *method_ids))" % varNames
|
||||||
setup += "let method_ids = (*script_context).dom_static.method_ids.get(&(PrototypeList::id::ClientRect as uint));\n"
|
setup += "let method_ids = (*page).js_info.get_ref().dom_static.method_ids.get(&(PrototypeList::id::ClientRect as uint));\n"
|
||||||
else:
|
else:
|
||||||
methodArgs = "None"
|
methodArgs = "None"
|
||||||
methodArgs = CGGeneric(methodArgs)
|
methodArgs = CGGeneric(methodArgs)
|
||||||
|
@ -3458,7 +3458,7 @@ class CGXrayHelper(CGAbstractExternMethod):
|
||||||
attrs = self.properties.attrs
|
attrs = self.properties.attrs
|
||||||
if attrs.hasNonChromeOnly() or attrs.hasChromeOnly():
|
if attrs.hasNonChromeOnly() or attrs.hasChromeOnly():
|
||||||
attrArgs = "Some(vec::zip_slice(%(attrs)s, *attr_ids))" % varNames
|
attrArgs = "Some(vec::zip_slice(%(attrs)s, *attr_ids))" % varNames
|
||||||
setup += "let attr_ids = (*script_context).dom_static.attribute_ids.get(&(PrototypeList::id::ClientRect as uint));\n"
|
setup += "let attr_ids = (*page).js_info.get_ref().dom_static.attribute_ids.get(&(PrototypeList::id::ClientRect as uint));\n"
|
||||||
else:
|
else:
|
||||||
attrArgs = "None"
|
attrArgs = "None"
|
||||||
attrArgs = CGGeneric(attrArgs)
|
attrArgs = CGGeneric(attrArgs)
|
||||||
|
@ -3466,7 +3466,7 @@ class CGXrayHelper(CGAbstractExternMethod):
|
||||||
consts = self.properties.consts
|
consts = self.properties.consts
|
||||||
if consts.hasNonChromeOnly() or consts.hasChromeOnly():
|
if consts.hasNonChromeOnly() or consts.hasChromeOnly():
|
||||||
constArgs = "Some(vec::zip_slice(%(consts)s, *const_ids))" % varNames
|
constArgs = "Some(vec::zip_slice(%(consts)s, *const_ids))" % varNames
|
||||||
setup += "let const_ids = (*script_context).dom_static.constant_ids.get(&(PrototypeList::id::ClientRect as uint));\n"
|
setup += "let const_ids = (*page).js_info.get_ref().dom_static.constant_ids.get(&(PrototypeList::id::ClientRect as uint));\n"
|
||||||
else:
|
else:
|
||||||
constArgs = "None"
|
constArgs = "None"
|
||||||
constArgs = CGGeneric(constArgs)
|
constArgs = CGGeneric(constArgs)
|
||||||
|
@ -3751,8 +3751,8 @@ class CGClassConstructHook(CGAbstractExternMethod):
|
||||||
//XXXjdm Gecko obtains a GlobalObject from the global (maybe from the private value,
|
//XXXjdm Gecko obtains a GlobalObject from the global (maybe from the private value,
|
||||||
// or through unwrapping a slot or something). We'll punt and get the Window
|
// or through unwrapping a slot or something). We'll punt and get the Window
|
||||||
// from the context for now.
|
// from the context for now.
|
||||||
let script_context = task_from_context(cx);
|
let page = page_from_context(cx);
|
||||||
let global = (*script_context).root_frame.get_ref().window;
|
let global = (*page).frame.get_ref().window;
|
||||||
let obj = global.get_wrappercache().get_wrapper();
|
let obj = global.get_wrappercache().get_wrapper();
|
||||||
"""
|
"""
|
||||||
preArgs = ["global"]
|
preArgs = ["global"]
|
||||||
|
@ -4365,7 +4365,7 @@ class CGBindingRoot(CGThing):
|
||||||
'dom::uievent::*', #XXXjdm
|
'dom::uievent::*', #XXXjdm
|
||||||
'dom::windowproxy::*', #XXXjdm
|
'dom::windowproxy::*', #XXXjdm
|
||||||
'dom::bindings::codegen::*', #XXXjdm
|
'dom::bindings::codegen::*', #XXXjdm
|
||||||
'script_task::task_from_context',
|
'script_task::{JSPageInfo, page_from_context}',
|
||||||
'dom::bindings::utils::EnumEntry',
|
'dom::bindings::utils::EnumEntry',
|
||||||
'dom::node::ScriptView',
|
'dom::node::ScriptView',
|
||||||
'std::cast',
|
'std::cast',
|
||||||
|
|
|
@ -11,7 +11,7 @@ use dom::element::{HTMLImageElementTypeId, HTMLHeadElementTypeId, HTMLScriptElem
|
||||||
HTMLDivElementTypeId};
|
HTMLDivElementTypeId};
|
||||||
use dom::node::{AbstractNode, ScriptView, ElementNodeTypeId};
|
use dom::node::{AbstractNode, ScriptView, ElementNodeTypeId};
|
||||||
use layout_interface::{ContentBoxQuery, ContentBoxResponse};
|
use layout_interface::{ContentBoxQuery, ContentBoxResponse};
|
||||||
use script_task::task_from_context;
|
use script_task::page_from_context;
|
||||||
use super::utils;
|
use super::utils;
|
||||||
|
|
||||||
use std::cast;
|
use std::cast;
|
||||||
|
@ -230,9 +230,10 @@ extern fn HTMLImageElement_getWidth(cx: *JSContext, _argc: c_uint, vp: *mut JSVa
|
||||||
let node = unwrap(obj);
|
let node = unwrap(obj);
|
||||||
let width = match node.type_id() {
|
let width = match node.type_id() {
|
||||||
ElementNodeTypeId(HTMLImageElementTypeId) => {
|
ElementNodeTypeId(HTMLImageElementTypeId) => {
|
||||||
let script_context = task_from_context(cx);
|
let page = page_from_context(cx);
|
||||||
let (port, chan) = comm::stream();
|
let (port, chan) = comm::stream();
|
||||||
match (*script_context).query_layout(ContentBoxQuery(node, chan), port) {
|
// TODO(tkuehn): currently this just queries top-level page's layout. Need to handle subframes.
|
||||||
|
match (*page).query_layout(ContentBoxQuery(node, chan), port) {
|
||||||
Ok(ContentBoxResponse(rect)) => rect.size.width.to_px(),
|
Ok(ContentBoxResponse(rect)) => rect.size.width.to_px(),
|
||||||
Err(()) => 0
|
Err(()) => 0
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
use dom::bindings::codegen::PrototypeList;
|
use dom::bindings::codegen::PrototypeList;
|
||||||
use dom::bindings::node;
|
use dom::bindings::node;
|
||||||
use dom::node::{AbstractNode, ScriptView};
|
use dom::node::{AbstractNode, ScriptView};
|
||||||
use script_task::task_from_context;
|
use script_task::page_from_context;
|
||||||
|
|
||||||
use std::cast;
|
use std::cast;
|
||||||
use std::hashmap::HashMap;
|
use std::hashmap::HashMap;
|
||||||
|
@ -217,8 +217,8 @@ pub unsafe fn domstring_to_jsval(cx: *JSContext, string: &DOMString) -> JSVal {
|
||||||
|
|
||||||
pub fn get_compartment(cx: *JSContext) -> @mut Compartment {
|
pub fn get_compartment(cx: *JSContext) -> @mut Compartment {
|
||||||
unsafe {
|
unsafe {
|
||||||
let script_context = task_from_context(cx);
|
let page = page_from_context(cx);
|
||||||
let compartment = (*script_context).js_compartment;
|
let compartment = (*page).js_info.get_ref().js_compartment;
|
||||||
assert!(cx == compartment.cx.ptr);
|
assert!(cx == compartment.cx.ptr);
|
||||||
compartment
|
compartment
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
use dom::bindings::utils::{WrapperCache, BindingObject, CacheableWrapper};
|
use dom::bindings::utils::{WrapperCache, BindingObject, CacheableWrapper};
|
||||||
use dom::bindings::codegen::BlobBinding;
|
use dom::bindings::codegen::BlobBinding;
|
||||||
use script_task::{task_from_context};
|
use script_task::{page_from_context};
|
||||||
|
|
||||||
use js::jsapi::{JSContext, JSObject};
|
use js::jsapi::{JSContext, JSObject};
|
||||||
|
|
||||||
|
@ -35,9 +35,9 @@ impl CacheableWrapper for Blob {
|
||||||
|
|
||||||
impl BindingObject for Blob {
|
impl BindingObject for Blob {
|
||||||
fn GetParentObject(&self, cx: *JSContext) -> @mut CacheableWrapper {
|
fn GetParentObject(&self, cx: *JSContext) -> @mut CacheableWrapper {
|
||||||
let script_context = task_from_context(cx);
|
let page = page_from_context(cx);
|
||||||
unsafe {
|
unsafe {
|
||||||
(*script_context).root_frame.get_ref().window as @mut CacheableWrapper
|
(*page).frame.get_ref().window as @mut CacheableWrapper
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
use dom::bindings::utils::{CacheableWrapper, WrapperCache, BindingObject, DerivedWrapper};
|
use dom::bindings::utils::{CacheableWrapper, WrapperCache, BindingObject, DerivedWrapper};
|
||||||
use dom::bindings::codegen::ClientRectBinding;
|
use dom::bindings::codegen::ClientRectBinding;
|
||||||
use script_task::{task_from_context, global_script_context};
|
use script_task::page_from_context;
|
||||||
|
|
||||||
use js::jsapi::{JSObject, JSContext, JSVal};
|
use js::jsapi::{JSObject, JSContext, JSVal};
|
||||||
use js::glue::RUST_OBJECT_TO_JSVAL;
|
use js::glue::RUST_OBJECT_TO_JSVAL;
|
||||||
|
@ -21,7 +21,7 @@ pub struct ClientRect {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClientRect {
|
impl ClientRect {
|
||||||
pub fn new(top: f32, bottom: f32, left: f32, right: f32) -> @mut ClientRect {
|
pub fn new(top: f32, bottom: f32, left: f32, right: f32, cx: *JSContext, scope: *JSObject) -> @mut ClientRect {
|
||||||
let rect = @mut ClientRect {
|
let rect = @mut ClientRect {
|
||||||
top: top,
|
top: top,
|
||||||
bottom: bottom,
|
bottom: bottom,
|
||||||
|
@ -29,16 +29,11 @@ impl ClientRect {
|
||||||
right: right,
|
right: right,
|
||||||
wrapper: WrapperCache::new()
|
wrapper: WrapperCache::new()
|
||||||
};
|
};
|
||||||
rect.init_wrapper();
|
rect.init_wrapper(cx, scope);
|
||||||
rect
|
rect
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init_wrapper(@mut self) {
|
pub fn init_wrapper(@mut self, cx: *JSContext, scope: *JSObject) {
|
||||||
let script_context = global_script_context();
|
|
||||||
let cx = script_context.js_compartment.cx.ptr;
|
|
||||||
let owner = script_context.root_frame.get_ref().window;
|
|
||||||
let cache = owner.get_wrappercache();
|
|
||||||
let scope = cache.get_wrapper();
|
|
||||||
self.wrap_object_shared(cx, scope);
|
self.wrap_object_shared(cx, scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,9 +77,9 @@ impl CacheableWrapper for ClientRect {
|
||||||
|
|
||||||
impl BindingObject for ClientRect {
|
impl BindingObject for ClientRect {
|
||||||
fn GetParentObject(&self, cx: *JSContext) -> @mut CacheableWrapper {
|
fn GetParentObject(&self, cx: *JSContext) -> @mut CacheableWrapper {
|
||||||
let script_context = task_from_context(cx);
|
let page = page_from_context(cx);
|
||||||
unsafe {
|
unsafe {
|
||||||
(*script_context).root_frame.get_ref().window as @mut CacheableWrapper
|
(*page).frame.get_ref().window as @mut CacheableWrapper
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
use dom::bindings::codegen::ClientRectListBinding;
|
use dom::bindings::codegen::ClientRectListBinding;
|
||||||
use dom::bindings::utils::{WrapperCache, CacheableWrapper, BindingObject};
|
use dom::bindings::utils::{WrapperCache, CacheableWrapper, BindingObject};
|
||||||
use dom::clientrect::ClientRect;
|
use dom::clientrect::ClientRect;
|
||||||
use script_task::{task_from_context, global_script_context};
|
use script_task::page_from_context;
|
||||||
|
|
||||||
use js::jsapi::{JSObject, JSContext};
|
use js::jsapi::{JSObject, JSContext};
|
||||||
|
|
||||||
|
@ -17,21 +17,16 @@ pub struct ClientRectList {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClientRectList {
|
impl ClientRectList {
|
||||||
pub fn new(rects: ~[@mut ClientRect]) -> @mut ClientRectList {
|
pub fn new(rects: ~[@mut ClientRect], cx: *JSContext, scope: *JSObject) -> @mut ClientRectList {
|
||||||
let list = @mut ClientRectList {
|
let list = @mut ClientRectList {
|
||||||
wrapper: WrapperCache::new(),
|
wrapper: WrapperCache::new(),
|
||||||
rects: rects
|
rects: rects
|
||||||
};
|
};
|
||||||
list.init_wrapper();
|
list.init_wrapper(cx, scope);
|
||||||
list
|
list
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init_wrapper(@mut self) {
|
pub fn init_wrapper(@mut self, cx: *JSContext, scope: *JSObject) {
|
||||||
let script_context = global_script_context();
|
|
||||||
let cx = script_context.js_compartment.cx.ptr;
|
|
||||||
let owner = script_context.root_frame.get_ref().window;
|
|
||||||
let cache = owner.get_wrappercache();
|
|
||||||
let scope = cache.get_wrapper();
|
|
||||||
self.wrap_object_shared(cx, scope);
|
self.wrap_object_shared(cx, scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,9 +63,9 @@ impl CacheableWrapper for ClientRectList {
|
||||||
|
|
||||||
impl BindingObject for ClientRectList {
|
impl BindingObject for ClientRectList {
|
||||||
fn GetParentObject(&self, cx: *JSContext) -> @mut CacheableWrapper {
|
fn GetParentObject(&self, cx: *JSContext) -> @mut CacheableWrapper {
|
||||||
let script_context = task_from_context(cx);
|
let page = page_from_context(cx);
|
||||||
unsafe {
|
unsafe {
|
||||||
(*script_context).root_frame.get_ref().window as @mut CacheableWrapper
|
(*page).frame.get_ref().window as @mut CacheableWrapper
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,6 @@ use dom::htmlcollection::HTMLCollection;
|
||||||
use dom::node::{AbstractNode, ScriptView, Node};
|
use dom::node::{AbstractNode, ScriptView, Node};
|
||||||
use dom::window::Window;
|
use dom::window::Window;
|
||||||
use dom::windowproxy::WindowProxy;
|
use dom::windowproxy::WindowProxy;
|
||||||
use script_task::global_script_context;
|
|
||||||
|
|
||||||
use js::JSPROP_ENUMERATE;
|
use js::JSPROP_ENUMERATE;
|
||||||
use js::glue::*;
|
use js::glue::*;
|
||||||
|
@ -37,20 +36,20 @@ pub fn Document(root: AbstractNode<ScriptView>, window: Option<@mut Window>) ->
|
||||||
wrapper: WrapperCache::new(),
|
wrapper: WrapperCache::new(),
|
||||||
window: window
|
window: window
|
||||||
};
|
};
|
||||||
let compartment = global_script_context().js_compartment;
|
let compartment = (*window.get_ref().page).js_info.get_ref().js_compartment;
|
||||||
do root.with_base |base| {
|
do root.with_base |base| {
|
||||||
assert!(base.wrapper.get_wrapper().is_not_null());
|
assert!(base.wrapper.get_wrapper().is_not_null());
|
||||||
let rootable = base.wrapper.get_rootable();
|
let rootable = base.wrapper.get_rootable();
|
||||||
JS_AddObjectRoot(compartment.cx.ptr, rootable);
|
JS_AddObjectRoot(compartment.cx.ptr, rootable);
|
||||||
}
|
}
|
||||||
|
|
||||||
let cx = global_script_context().js_compartment.cx.ptr;
|
let cx = (*window.get_ref().page).js_info.get_ref().js_compartment.cx.ptr;
|
||||||
doc.wrap_object_shared(cx, ptr::null()); //XXXjdm a proper scope would be nice
|
doc.wrap_object_shared(cx, ptr::null()); //XXXjdm a proper scope would be nice
|
||||||
|
|
||||||
match window {
|
match window {
|
||||||
Some(win) => {
|
Some(win) => {
|
||||||
//FIXME: This is a hack until Window is autogenerated
|
//FIXME: This is a hack until Window is autogenerated
|
||||||
let compartment = (*win.script_task).js_compartment;
|
let compartment = (*win.page).js_info.get_ref().js_compartment;
|
||||||
compartment.define_property(~"document",
|
compartment.define_property(~"document",
|
||||||
RUST_OBJECT_TO_JSVAL(doc.wrapper.wrapper),
|
RUST_OBJECT_TO_JSVAL(doc.wrapper.wrapper),
|
||||||
GetJSClassHookStubPointer(PROPERTY_STUB) as *u8,
|
GetJSClassHookStubPointer(PROPERTY_STUB) as *u8,
|
||||||
|
@ -89,7 +88,8 @@ impl Document {
|
||||||
parent: Element::new(HTMLHtmlElementTypeId, ~"html")
|
parent: Element::new(HTMLHtmlElementTypeId, ~"html")
|
||||||
};
|
};
|
||||||
|
|
||||||
let root = unsafe { Node::as_abstract_node(root) };
|
let cx = unsafe {(*_owner.page).js_info.get_ref().js_compartment.cx.ptr};
|
||||||
|
let root = unsafe { Node::as_abstract_node(cx, root) };
|
||||||
Document(root, None)
|
Document(root, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,15 +129,27 @@ impl Document {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
HTMLCollection::new(elements)
|
let win = self.window.get_ref();
|
||||||
|
let cx = unsafe {(*win.page).js_info.get_ref().js_compartment.cx.ptr};
|
||||||
|
let cache = win.get_wrappercache();
|
||||||
|
let scope = cache.get_wrapper();
|
||||||
|
HTMLCollection::new(elements, cx, scope)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn GetElementsByTagNameNS(&self, _ns: DOMString, _tag: DOMString) -> @mut HTMLCollection {
|
pub fn GetElementsByTagNameNS(&self, _ns: DOMString, _tag: DOMString) -> @mut HTMLCollection {
|
||||||
HTMLCollection::new(~[])
|
let win = self.window.get_ref();
|
||||||
|
let cx = unsafe {(*win.page).js_info.get_ref().js_compartment.cx.ptr};
|
||||||
|
let cache = win.get_wrappercache();
|
||||||
|
let scope = cache.get_wrapper();
|
||||||
|
HTMLCollection::new(~[], cx, scope)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn GetElementsByClassName(&self, _class: DOMString) -> @mut HTMLCollection {
|
pub fn GetElementsByClassName(&self, _class: DOMString) -> @mut HTMLCollection {
|
||||||
HTMLCollection::new(~[])
|
let win = self.window.get_ref();
|
||||||
|
let cx = unsafe {(*win.page).js_info.get_ref().js_compartment.cx.ptr};
|
||||||
|
let cache = win.get_wrappercache();
|
||||||
|
let scope = cache.get_wrapper();
|
||||||
|
HTMLCollection::new(~[], cx, scope)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -276,7 +288,11 @@ impl Document {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
HTMLCollection::new(elements)
|
let win = self.window.get_ref();
|
||||||
|
let cx = unsafe {(*win.page).js_info.get_ref().js_compartment.cx.ptr};
|
||||||
|
let cache = win.get_wrappercache();
|
||||||
|
let scope = cache.get_wrapper();
|
||||||
|
HTMLCollection::new(elements, cx, scope)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn content_changed(&self) {
|
pub fn content_changed(&self) {
|
||||||
|
@ -287,7 +303,7 @@ impl Document {
|
||||||
|
|
||||||
pub fn teardown(&self) {
|
pub fn teardown(&self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let compartment = global_script_context().js_compartment;
|
let compartment = (*self.window.get_ref().page).js_info.get_ref().js_compartment;
|
||||||
do self.root.with_base |node| {
|
do self.root.with_base |node| {
|
||||||
assert!(node.wrapper.get_wrapper().is_not_null());
|
assert!(node.wrapper.get_wrapper().is_not_null());
|
||||||
let rootable = node.wrapper.get_rootable();
|
let rootable = node.wrapper.get_rootable();
|
||||||
|
|
|
@ -8,7 +8,6 @@ use dom::document::Document;
|
||||||
use dom::element::{Element, HTMLHtmlElement, HTMLHtmlElementTypeId};
|
use dom::element::{Element, HTMLHtmlElement, HTMLHtmlElementTypeId};
|
||||||
use dom::node::Node;
|
use dom::node::Node;
|
||||||
use dom::window::Window;
|
use dom::window::Window;
|
||||||
use script_task::global_script_context;
|
|
||||||
|
|
||||||
pub struct DOMParser {
|
pub struct DOMParser {
|
||||||
owner: @mut Window, //XXXjdm Document instead?
|
owner: @mut Window, //XXXjdm Document instead?
|
||||||
|
@ -22,7 +21,8 @@ impl DOMParser {
|
||||||
wrapper: WrapperCache::new()
|
wrapper: WrapperCache::new()
|
||||||
};
|
};
|
||||||
|
|
||||||
let cx = global_script_context().js_compartment.cx.ptr;
|
// TODO(tkuehn): This just handles the top-level page. Need to handle subframes.
|
||||||
|
let cx = unsafe {(*owner.page).js_info.get_ref().js_compartment.cx.ptr};
|
||||||
let cache = owner.get_wrappercache();
|
let cache = owner.get_wrappercache();
|
||||||
let scope = cache.get_wrapper();
|
let scope = cache.get_wrapper();
|
||||||
parser.wrap_object_shared(cx, scope);
|
parser.wrap_object_shared(cx, scope);
|
||||||
|
@ -43,7 +43,7 @@ impl DOMParser {
|
||||||
parent: Element::new(HTMLHtmlElementTypeId, ~"html")
|
parent: Element::new(HTMLHtmlElementTypeId, ~"html")
|
||||||
};
|
};
|
||||||
|
|
||||||
let root = Node::as_abstract_node(root);
|
let root = Node::as_abstract_node((*self.owner.page).js_info.get_ref().js_compartment.cx.ptr, root);
|
||||||
Document(root, None)
|
Document(root, None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,19 +4,20 @@
|
||||||
|
|
||||||
//! Element nodes.
|
//! Element nodes.
|
||||||
|
|
||||||
use dom::bindings::utils::DOMString;
|
use dom::bindings::utils::{DOMString, CacheableWrapper};
|
||||||
use dom::clientrect::ClientRect;
|
use dom::clientrect::ClientRect;
|
||||||
use dom::clientrectlist::ClientRectList;
|
use dom::clientrectlist::ClientRectList;
|
||||||
use dom::node::{ElementNodeTypeId, Node, ScriptView};
|
use dom::node::{ElementNodeTypeId, Node, ScriptView};
|
||||||
use html::hubbub_html_parser::HtmlParserResult;
|
|
||||||
use layout_interface::{ContentBoxQuery, ContentBoxResponse, ContentBoxesQuery};
|
use layout_interface::{ContentBoxQuery, ContentBoxResponse, ContentBoxesQuery};
|
||||||
use layout_interface::{ContentBoxesResponse};
|
use layout_interface::{ContentBoxesResponse};
|
||||||
|
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
|
use std::comm::ChanOne;
|
||||||
use std::comm;
|
use std::comm;
|
||||||
use std::uint;
|
use std::uint;
|
||||||
use std::str::eq_slice;
|
use std::str::eq_slice;
|
||||||
use extra::net::url::Url;
|
use extra::net::url::Url;
|
||||||
|
use geom::size::Size2D;
|
||||||
|
|
||||||
pub struct Element {
|
pub struct Element {
|
||||||
parent: Node<ScriptView>,
|
parent: Node<ScriptView>,
|
||||||
|
@ -112,7 +113,7 @@ pub struct HTMLHeadingElement {
|
||||||
pub struct HTMLIframeElement {
|
pub struct HTMLIframeElement {
|
||||||
parent: Element,
|
parent: Element,
|
||||||
frame: Option<Url>,
|
frame: Option<Url>,
|
||||||
parse_result: Option<Port<HtmlParserResult>>
|
size_future_chan: Option<ChanOne<Size2D<uint>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct HTMLImageElement {
|
pub struct HTMLImageElement {
|
||||||
|
@ -168,44 +169,53 @@ impl<'self> Element {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getClientRects(&self) -> Option<@mut ClientRectList> {
|
pub fn getClientRects(&self) -> Option<@mut ClientRectList> {
|
||||||
let rects = match self.parent.owner_doc {
|
let (rects, cx, scope) = match self.parent.owner_doc {
|
||||||
Some(doc) => {
|
Some(doc) => {
|
||||||
match doc.window {
|
match doc.window {
|
||||||
Some(win) => {
|
Some(win) => {
|
||||||
let node = self.parent.abstract.get();
|
let node = self.parent.abstract.get();
|
||||||
assert!(node.is_element());
|
assert!(node.is_element());
|
||||||
let script_task = unsafe {
|
let page = unsafe {
|
||||||
&mut *win.script_task
|
&mut *win.page
|
||||||
};
|
};
|
||||||
let (port, chan) = comm::stream();
|
let (port, chan) = comm::stream();
|
||||||
match script_task.query_layout(ContentBoxesQuery(node, chan), port) {
|
// TODO(tkuehn): currently just queries top-level page layout. Needs to query
|
||||||
|
// subframe layout if this element is in a subframe. Probably need an ID field.
|
||||||
|
match page.query_layout(ContentBoxesQuery(node, chan), port) {
|
||||||
Ok(ContentBoxesResponse(rects)) => {
|
Ok(ContentBoxesResponse(rects)) => {
|
||||||
do rects.map |r| {
|
let cx = (*page).js_info.get_ref().js_compartment.cx.ptr;
|
||||||
|
let cache = win.get_wrappercache();
|
||||||
|
let scope = cache.get_wrapper();
|
||||||
|
let rects = do rects.map |r| {
|
||||||
ClientRect::new(
|
ClientRect::new(
|
||||||
r.origin.y.to_f32(),
|
r.origin.y.to_f32(),
|
||||||
(r.origin.y + r.size.height).to_f32(),
|
(r.origin.y + r.size.height).to_f32(),
|
||||||
r.origin.x.to_f32(),
|
r.origin.x.to_f32(),
|
||||||
(r.origin.x + r.size.width).to_f32())
|
(r.origin.x + r.size.width).to_f32(),
|
||||||
}
|
cx,
|
||||||
|
scope)
|
||||||
|
};
|
||||||
|
Some((rects, cx, scope))
|
||||||
},
|
},
|
||||||
Err(()) => {
|
Err(()) => {
|
||||||
debug!("layout query error");
|
debug!("layout query error");
|
||||||
~[]
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
debug!("no window");
|
debug!("no window");
|
||||||
~[]
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
debug!("no document");
|
debug!("no document");
|
||||||
~[]
|
None
|
||||||
}
|
}
|
||||||
};
|
}.get();
|
||||||
Some(ClientRectList::new(rects))
|
|
||||||
|
Some(ClientRectList::new(rects, cx, scope))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getBoundingClientRect(&self) -> Option<@mut ClientRect> {
|
pub fn getBoundingClientRect(&self) -> Option<@mut ClientRect> {
|
||||||
|
@ -213,17 +223,26 @@ impl<'self> Element {
|
||||||
Some(doc) => {
|
Some(doc) => {
|
||||||
match doc.window {
|
match doc.window {
|
||||||
Some(win) => {
|
Some(win) => {
|
||||||
|
let page = unsafe {
|
||||||
|
&mut *win.page
|
||||||
|
};
|
||||||
let node = self.parent.abstract.get();
|
let node = self.parent.abstract.get();
|
||||||
assert!(node.is_element());
|
assert!(node.is_element());
|
||||||
let script_task = unsafe { &mut *win.script_task };
|
|
||||||
let (port, chan) = comm::stream();
|
let (port, chan) = comm::stream();
|
||||||
match script_task.query_layout(ContentBoxQuery(node, chan), port) {
|
// TODO(tkuehn): currently just queries top-level page layout. Needs to query
|
||||||
|
// subframe layout if this element is in a subframe. Probably need an ID field.
|
||||||
|
match page.query_layout(ContentBoxQuery(node, chan), port) {
|
||||||
Ok(ContentBoxResponse(rect)) => {
|
Ok(ContentBoxResponse(rect)) => {
|
||||||
|
let cx = (*page).js_info.get_ref().js_compartment.cx.ptr;
|
||||||
|
let cache = win.get_wrappercache();
|
||||||
|
let scope = cache.get_wrapper();
|
||||||
Some(ClientRect::new(
|
Some(ClientRect::new(
|
||||||
rect.origin.y.to_f32(),
|
rect.origin.y.to_f32(),
|
||||||
(rect.origin.y + rect.size.height).to_f32(),
|
(rect.origin.y + rect.size.height).to_f32(),
|
||||||
rect.origin.x.to_f32(),
|
rect.origin.x.to_f32(),
|
||||||
(rect.origin.x + rect.size.width).to_f32()))
|
(rect.origin.x + rect.size.width).to_f32(),
|
||||||
|
cx,
|
||||||
|
scope))
|
||||||
},
|
},
|
||||||
Err(()) => {
|
Err(()) => {
|
||||||
debug!("error querying layout");
|
debug!("error querying layout");
|
||||||
|
|
|
@ -7,12 +7,13 @@ use dom::window::Window;
|
||||||
use dom::bindings::codegen::EventBinding;
|
use dom::bindings::codegen::EventBinding;
|
||||||
use dom::bindings::utils::{CacheableWrapper, BindingObject, DerivedWrapper};
|
use dom::bindings::utils::{CacheableWrapper, BindingObject, DerivedWrapper};
|
||||||
use dom::bindings::utils::{DOMString, ErrorResult, WrapperCache};
|
use dom::bindings::utils::{DOMString, ErrorResult, WrapperCache};
|
||||||
use script_task::{task_from_context, global_script_context};
|
|
||||||
|
|
||||||
use geom::point::Point2D;
|
use geom::point::Point2D;
|
||||||
use js::glue::RUST_OBJECT_TO_JSVAL;
|
use js::glue::RUST_OBJECT_TO_JSVAL;
|
||||||
use js::jsapi::{JSObject, JSContext, JSVal};
|
use js::jsapi::{JSObject, JSContext, JSVal};
|
||||||
|
|
||||||
|
use script_task::page_from_context;
|
||||||
|
|
||||||
use std::cast;
|
use std::cast;
|
||||||
|
|
||||||
|
|
||||||
|
@ -45,12 +46,7 @@ impl Event_ {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init_wrapper(@mut self) {
|
pub fn init_wrapper(@mut self, cx: *JSContext, scope: *JSObject) {
|
||||||
let script_context = global_script_context();
|
|
||||||
let cx = script_context.js_compartment.cx.ptr;
|
|
||||||
let owner = script_context.root_frame.get_ref().window;
|
|
||||||
let cache = owner.get_wrappercache();
|
|
||||||
let scope = cache.get_wrapper();
|
|
||||||
self.wrap_object_shared(cx, scope);
|
self.wrap_object_shared(cx, scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,9 +127,9 @@ impl CacheableWrapper for Event_ {
|
||||||
|
|
||||||
impl BindingObject for Event_ {
|
impl BindingObject for Event_ {
|
||||||
fn GetParentObject(&self, cx: *JSContext) -> @mut CacheableWrapper {
|
fn GetParentObject(&self, cx: *JSContext) -> @mut CacheableWrapper {
|
||||||
let script_context = task_from_context(cx);
|
let page = page_from_context(cx);
|
||||||
unsafe {
|
unsafe {
|
||||||
(*script_context).root_frame.get_ref().window as @mut CacheableWrapper
|
(*page).frame.get_ref().window as @mut CacheableWrapper
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
use dom::bindings::codegen::EventTargetBinding;
|
use dom::bindings::codegen::EventTargetBinding;
|
||||||
use dom::bindings::utils::{CacheableWrapper, WrapperCache, BindingObject, DerivedWrapper};
|
use dom::bindings::utils::{CacheableWrapper, WrapperCache, BindingObject, DerivedWrapper};
|
||||||
use script_task::{task_from_context, global_script_context};
|
use script_task::page_from_context;
|
||||||
|
|
||||||
use js::glue::RUST_OBJECT_TO_JSVAL;
|
use js::glue::RUST_OBJECT_TO_JSVAL;
|
||||||
use js::jsapi::{JSObject, JSContext, JSVal};
|
use js::jsapi::{JSObject, JSContext, JSVal};
|
||||||
|
@ -22,12 +22,7 @@ impl EventTarget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init_wrapper(@mut self) {
|
pub fn init_wrapper(@mut self, cx: *JSContext, scope: *JSObject) {
|
||||||
let script_context = global_script_context();
|
|
||||||
let cx = script_context.js_compartment.cx.ptr;
|
|
||||||
let owner = script_context.root_frame.get_ref().window;
|
|
||||||
let cache = owner.get_wrappercache();
|
|
||||||
let scope = cache.get_wrapper();
|
|
||||||
self.wrap_object_shared(cx, scope);
|
self.wrap_object_shared(cx, scope);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,9 +40,10 @@ impl CacheableWrapper for EventTarget {
|
||||||
|
|
||||||
impl BindingObject for EventTarget {
|
impl BindingObject for EventTarget {
|
||||||
fn GetParentObject(&self, cx: *JSContext) -> @mut CacheableWrapper {
|
fn GetParentObject(&self, cx: *JSContext) -> @mut CacheableWrapper {
|
||||||
let script_context = task_from_context(cx);
|
let page = page_from_context(cx);
|
||||||
|
// TODO(tkuehn): This only handles top-level pages. Needs to handle subframes.
|
||||||
unsafe {
|
unsafe {
|
||||||
(*script_context).root_frame.get_ref().window as @mut CacheableWrapper
|
(*page).frame.get_ref().window as @mut CacheableWrapper
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ use dom::bindings::utils::{CacheableWrapper, BindingObject, DerivedWrapper};
|
||||||
use dom::bindings::utils::{WrapperCache, DOMString, str};
|
use dom::bindings::utils::{WrapperCache, DOMString, str};
|
||||||
use dom::bindings::codegen::FormDataBinding;
|
use dom::bindings::codegen::FormDataBinding;
|
||||||
use dom::blob::Blob;
|
use dom::blob::Blob;
|
||||||
use script_task::{task_from_context, global_script_context};
|
use script_task::{page_from_context};
|
||||||
|
|
||||||
use js::jsapi::{JSObject, JSContext, JSVal};
|
use js::jsapi::{JSObject, JSContext, JSVal};
|
||||||
use js::glue::RUST_OBJECT_TO_JSVAL;
|
use js::glue::RUST_OBJECT_TO_JSVAL;
|
||||||
|
@ -32,12 +32,7 @@ impl FormData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init_wrapper(@mut self) {
|
pub fn init_wrapper(@mut self, cx: *JSContext, scope: *JSObject) {
|
||||||
let script_context = global_script_context();
|
|
||||||
let cx = script_context.js_compartment.cx.ptr;
|
|
||||||
let owner = script_context.root_frame.get_ref().window;
|
|
||||||
let cache = owner.get_wrappercache();
|
|
||||||
let scope = cache.get_wrapper();
|
|
||||||
self.wrap_object_shared(cx, scope);
|
self.wrap_object_shared(cx, scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,9 +64,9 @@ impl CacheableWrapper for FormData {
|
||||||
|
|
||||||
impl BindingObject for FormData {
|
impl BindingObject for FormData {
|
||||||
fn GetParentObject(&self, cx: *JSContext) -> @mut CacheableWrapper {
|
fn GetParentObject(&self, cx: *JSContext) -> @mut CacheableWrapper {
|
||||||
let script_context = task_from_context(cx);
|
let page = page_from_context(cx);
|
||||||
unsafe {
|
unsafe {
|
||||||
(*script_context).root_frame.get_ref().window as @mut CacheableWrapper
|
(*page).frame.get_ref().window as @mut CacheableWrapper
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ use dom::bindings::codegen::HTMLCollectionBinding;
|
||||||
use dom::bindings::utils::{CacheableWrapper, BindingObject, WrapperCache};
|
use dom::bindings::utils::{CacheableWrapper, BindingObject, WrapperCache};
|
||||||
use dom::bindings::utils::{DOMString, ErrorResult};
|
use dom::bindings::utils::{DOMString, ErrorResult};
|
||||||
use dom::node::{AbstractNode, ScriptView};
|
use dom::node::{AbstractNode, ScriptView};
|
||||||
use script_task::{task_from_context, global_script_context};
|
use script_task::page_from_context;
|
||||||
|
|
||||||
use js::jsapi::{JSObject, JSContext};
|
use js::jsapi::{JSObject, JSContext};
|
||||||
|
|
||||||
|
@ -19,21 +19,16 @@ pub struct HTMLCollection {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HTMLCollection {
|
impl HTMLCollection {
|
||||||
pub fn new(elements: ~[AbstractNode<ScriptView>]) -> @mut HTMLCollection {
|
pub fn new(elements: ~[AbstractNode<ScriptView>], cx: *JSContext, scope: *JSObject) -> @mut HTMLCollection {
|
||||||
let collection = @mut HTMLCollection {
|
let collection = @mut HTMLCollection {
|
||||||
elements: elements,
|
elements: elements,
|
||||||
wrapper: WrapperCache::new()
|
wrapper: WrapperCache::new()
|
||||||
};
|
};
|
||||||
collection.init_wrapper();
|
collection.init_wrapper(cx, scope);
|
||||||
collection
|
collection
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init_wrapper(@mut self) {
|
pub fn init_wrapper(@mut self, cx: *JSContext, scope: *JSObject) {
|
||||||
let script_context = global_script_context();
|
|
||||||
let cx = script_context.js_compartment.cx.ptr;
|
|
||||||
let owner = script_context.root_frame.get_ref().window;
|
|
||||||
let cache = owner.get_wrappercache();
|
|
||||||
let scope = cache.get_wrapper();
|
|
||||||
self.wrap_object_shared(cx, scope);
|
self.wrap_object_shared(cx, scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,9 +57,10 @@ impl HTMLCollection {
|
||||||
|
|
||||||
impl BindingObject for HTMLCollection {
|
impl BindingObject for HTMLCollection {
|
||||||
fn GetParentObject(&self, cx: *JSContext) -> @mut CacheableWrapper {
|
fn GetParentObject(&self, cx: *JSContext) -> @mut CacheableWrapper {
|
||||||
let script_context = task_from_context(cx);
|
let page = page_from_context(cx);
|
||||||
|
// TODO(tkuehn): This only handles the top-level frame. Need to grab subframes.
|
||||||
unsafe {
|
unsafe {
|
||||||
(*script_context).root_frame.get_ref().window as @mut CacheableWrapper
|
(*page).frame.get_ref().window as @mut CacheableWrapper
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,6 @@ use dom::eventtarget::EventTarget;
|
||||||
use dom::uievent::UIEvent;
|
use dom::uievent::UIEvent;
|
||||||
use dom::window::Window;
|
use dom::window::Window;
|
||||||
use dom::windowproxy::WindowProxy;
|
use dom::windowproxy::WindowProxy;
|
||||||
use script_task::{global_script_context};
|
|
||||||
|
|
||||||
use js::glue::RUST_OBJECT_TO_JSVAL;
|
use js::glue::RUST_OBJECT_TO_JSVAL;
|
||||||
use js::jsapi::{JSObject, JSContext, JSVal};
|
use js::jsapi::{JSObject, JSContext, JSVal};
|
||||||
|
@ -49,12 +48,7 @@ impl MouseEvent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init_wrapper(@mut self) {
|
pub fn init_wrapper(@mut self, cx: *JSContext, scope: *JSObject) {
|
||||||
let script_context = global_script_context();
|
|
||||||
let cx = script_context.js_compartment.cx.ptr;
|
|
||||||
let owner = script_context.root_frame.get_ref().window;
|
|
||||||
let cache = owner.get_wrappercache();
|
|
||||||
let scope = cache.get_wrapper();
|
|
||||||
self.wrap_object_shared(cx, scope);
|
self.wrap_object_shared(cx, scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,4 +175,4 @@ impl DerivedWrapper for MouseEvent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,13 +11,13 @@ use dom::characterdata::CharacterData;
|
||||||
use dom::document::Document;
|
use dom::document::Document;
|
||||||
use dom::element::{Element, ElementTypeId, HTMLImageElement, HTMLImageElementTypeId, HTMLIframeElementTypeId, HTMLIframeElement};
|
use dom::element::{Element, ElementTypeId, HTMLImageElement, HTMLImageElementTypeId, HTMLIframeElementTypeId, HTMLIframeElement};
|
||||||
use dom::element::{HTMLStyleElementTypeId};
|
use dom::element::{HTMLStyleElementTypeId};
|
||||||
use script_task::global_script_context;
|
|
||||||
|
|
||||||
use std::cast;
|
use std::cast;
|
||||||
use std::cast::transmute;
|
use std::cast::transmute;
|
||||||
use std::libc::c_void;
|
use std::libc::c_void;
|
||||||
use std::uint;
|
use std::uint;
|
||||||
use js::rust::Compartment;
|
use js::rust::Compartment;
|
||||||
|
use js::jsapi::{JSContext};
|
||||||
use netsurfcss::util::VoidPtrLike;
|
use netsurfcss::util::VoidPtrLike;
|
||||||
use servo_util::tree::{TreeNode, TreeNodeRef, TreeUtils};
|
use servo_util::tree::{TreeNode, TreeNodeRef, TreeUtils};
|
||||||
|
|
||||||
|
@ -424,12 +424,11 @@ impl<View> Iterator<AbstractNode<View>> for AbstractNodeChildrenIterator<View> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Node<ScriptView> {
|
impl Node<ScriptView> {
|
||||||
pub unsafe fn as_abstract_node<N>(node: ~N) -> AbstractNode<ScriptView> {
|
pub unsafe fn as_abstract_node<N>(cx: *JSContext, node: ~N) -> AbstractNode<ScriptView> {
|
||||||
// This surrenders memory management of the node!
|
// This surrenders memory management of the node!
|
||||||
let mut node = AbstractNode {
|
let mut node = AbstractNode {
|
||||||
obj: transmute(node),
|
obj: transmute(node),
|
||||||
};
|
};
|
||||||
let cx = global_script_context().js_compartment.cx.ptr;
|
|
||||||
node::create(cx, &mut node);
|
node::create(cx, &mut node);
|
||||||
node
|
node
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,6 @@ use dom::event::Event_;
|
||||||
use dom::window::Window;
|
use dom::window::Window;
|
||||||
use dom::windowproxy::WindowProxy;
|
use dom::windowproxy::WindowProxy;
|
||||||
|
|
||||||
use script_task::global_script_context;
|
|
||||||
|
|
||||||
use js::glue::RUST_OBJECT_TO_JSVAL;
|
use js::glue::RUST_OBJECT_TO_JSVAL;
|
||||||
use js::jsapi::{JSObject, JSContext, JSVal};
|
use js::jsapi::{JSObject, JSContext, JSVal};
|
||||||
|
|
||||||
|
@ -35,12 +33,7 @@ impl UIEvent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init_wrapper(@mut self) {
|
pub fn init_wrapper(@mut self, cx: *JSContext, scope: *JSObject) {
|
||||||
let script_context = global_script_context();
|
|
||||||
let cx = script_context.js_compartment.cx.ptr;
|
|
||||||
let owner = script_context.root_frame.get_ref().window;
|
|
||||||
let cache = owner.get_wrappercache();
|
|
||||||
let scope = cache.get_wrapper();
|
|
||||||
self.wrap_object_shared(cx, scope);
|
self.wrap_object_shared(cx, scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,8 @@ use dom::bindings::utils::WrapperCache;
|
||||||
use dom::bindings::window;
|
use dom::bindings::window;
|
||||||
|
|
||||||
use layout_interface::ReflowForScriptQuery;
|
use layout_interface::ReflowForScriptQuery;
|
||||||
use script_task::{ExitMsg, FireTimerMsg, ScriptChan, ScriptTask};
|
use script_task::{ExitMsg, FireTimerMsg, Page, ScriptChan};
|
||||||
|
use servo_msg::compositor_msg::ScriptListener;
|
||||||
|
|
||||||
use std::comm;
|
use std::comm;
|
||||||
use std::comm::Chan;
|
use std::comm::Chan;
|
||||||
|
@ -27,12 +28,14 @@ pub enum TimerControlMsg {
|
||||||
//FIXME If we're going to store the script task, find a way to do so safely. Currently it's
|
//FIXME If we're going to store the script task, find a way to do so safely. Currently it's
|
||||||
// only used for querying layout from arbitrary script.
|
// only used for querying layout from arbitrary script.
|
||||||
pub struct Window {
|
pub struct Window {
|
||||||
timer_chan: Chan<TimerControlMsg>,
|
page: *mut Page,
|
||||||
script_chan: ScriptChan,
|
script_chan: ScriptChan,
|
||||||
script_task: *mut ScriptTask,
|
compositor: @ScriptListener,
|
||||||
wrapper: WrapperCache
|
wrapper: WrapperCache,
|
||||||
|
timer_chan: Chan<TimerControlMsg>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[unsafe_destructor]
|
||||||
impl Drop for Window {
|
impl Drop for Window {
|
||||||
fn drop(&self) {
|
fn drop(&self) {
|
||||||
self.timer_chan.send(TimerMessage_Close);
|
self.timer_chan.send(TimerMessage_Close);
|
||||||
|
@ -89,34 +92,37 @@ impl Window {
|
||||||
|
|
||||||
pub fn content_changed(&self) {
|
pub fn content_changed(&self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
(*self.script_task).reflow_all(ReflowForScriptQuery)
|
// TODO(tkuehn): currently reflow top-level, but want to reflow only the associated frame
|
||||||
|
(*self.page).reflow_all(ReflowForScriptQuery, self.script_chan.clone(), self.compositor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(script_chan: ScriptChan, script_task: *mut ScriptTask)
|
pub fn new(page: *mut Page, script_chan: ScriptChan, compositor: @ScriptListener)
|
||||||
-> @mut Window {
|
-> @mut Window {
|
||||||
let script_chan_clone = script_chan.clone();
|
let script_chan_clone = script_chan.clone();
|
||||||
let win = @mut Window {
|
let win = @mut Window {
|
||||||
wrapper: WrapperCache::new(),
|
page: page,
|
||||||
script_chan: script_chan,
|
script_chan: script_chan,
|
||||||
|
compositor: compositor,
|
||||||
|
wrapper: WrapperCache::new(),
|
||||||
timer_chan: {
|
timer_chan: {
|
||||||
let (timer_port, timer_chan) = comm::stream::<TimerControlMsg>();
|
let (timer_port, timer_chan) = comm::stream::<TimerControlMsg>();
|
||||||
do spawn {
|
do spawn {
|
||||||
loop {
|
loop {
|
||||||
match timer_port.recv() {
|
match timer_port.recv() {
|
||||||
TimerMessage_Close => break,
|
TimerMessage_Close => break,
|
||||||
TimerMessage_Fire(td) => script_chan_clone.chan.send(FireTimerMsg(td)),
|
TimerMessage_Fire(td) => unsafe {script_chan_clone.chan.send(FireTimerMsg((*page).id.clone(), td))},
|
||||||
TimerMessage_TriggerExit => script_chan_clone.chan.send(ExitMsg),
|
TimerMessage_TriggerExit => script_chan_clone.chan.send(ExitMsg),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
timer_chan
|
timer_chan
|
||||||
},
|
},
|
||||||
script_task: script_task,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let compartment = (*script_task).js_compartment;
|
// TODO(tkuehn): This just grabs the top-level page. Need to handle subframes.
|
||||||
|
let compartment = (*page).js_info.get_ref().js_compartment;
|
||||||
window::create(compartment, win);
|
window::create(compartment, win);
|
||||||
}
|
}
|
||||||
win
|
win
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
* 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 dom::bindings::utils::{CacheableWrapper, WrapperCache, BindingObject};
|
use dom::bindings::utils::{CacheableWrapper, WrapperCache, BindingObject};
|
||||||
use script_task::{global_script_context, task_from_context};
|
use script_task::page_from_context;
|
||||||
|
|
||||||
use js::jsapi::{JSContext, JSObject};
|
use js::jsapi::{JSContext, JSObject};
|
||||||
|
|
||||||
|
@ -18,21 +18,16 @@ impl WindowProxy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init_wrapper(@mut self) {
|
pub fn init_wrapper(@mut self, cx: *JSContext, scope: *JSObject) {
|
||||||
let script_context = global_script_context();
|
|
||||||
let cx = script_context.js_compartment.cx.ptr;
|
|
||||||
let owner = script_context.root_frame.get_ref().window;
|
|
||||||
let cache = owner.get_wrappercache();
|
|
||||||
let scope = cache.get_wrapper();
|
|
||||||
self.wrap_object_shared(cx, scope);
|
self.wrap_object_shared(cx, scope);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BindingObject for WindowProxy {
|
impl BindingObject for WindowProxy {
|
||||||
fn GetParentObject(&self, cx: *JSContext) -> @mut CacheableWrapper {
|
fn GetParentObject(&self, cx: *JSContext) -> @mut CacheableWrapper {
|
||||||
let script_context = task_from_context(cx);
|
let page = page_from_context(cx);
|
||||||
unsafe {
|
unsafe {
|
||||||
(*script_context).root_frame.get_ref().window as @mut CacheableWrapper
|
(*page).frame.get_ref().window as @mut CacheableWrapper
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ use dom::element::{Element, Attr};
|
||||||
use dom::node::{AbstractNode, Comment, Doctype, ElementNodeTypeId, Node, ScriptView};
|
use dom::node::{AbstractNode, Comment, Doctype, ElementNodeTypeId, Node, ScriptView};
|
||||||
use dom::node::{Text};
|
use dom::node::{Text};
|
||||||
use html::cssparse::{InlineProvenance, StylesheetProvenance, UrlProvenance, spawn_css_parser};
|
use html::cssparse::{InlineProvenance, StylesheetProvenance, UrlProvenance, spawn_css_parser};
|
||||||
|
use js::jsapi::JSContext;
|
||||||
use newcss::stylesheet::Stylesheet;
|
use newcss::stylesheet::Stylesheet;
|
||||||
|
|
||||||
use std::cast;
|
use std::cast;
|
||||||
|
@ -48,9 +49,11 @@ use servo_util::tree::TreeUtils;
|
||||||
use servo_util::url::make_url;
|
use servo_util::url::make_url;
|
||||||
use extra::net::url::Url;
|
use extra::net::url::Url;
|
||||||
use extra::net::url;
|
use extra::net::url;
|
||||||
|
use extra::future::{Future, from_port};
|
||||||
|
use geom::size::Size2D;
|
||||||
|
|
||||||
macro_rules! handle_element(
|
macro_rules! handle_element(
|
||||||
($tag:expr, $string:expr, $type_id:expr, $ctor:ident, [ $(($field:ident : $field_init:expr)),* ]) => (
|
($cx: expr, $tag:expr, $string:expr, $type_id:expr, $ctor:ident, [ $(($field:ident : $field_init:expr)),* ]) => (
|
||||||
if eq_slice($tag, $string) {
|
if eq_slice($tag, $string) {
|
||||||
let _element = ~$ctor {
|
let _element = ~$ctor {
|
||||||
parent: Element::new($type_id, ($tag).to_str()),
|
parent: Element::new($type_id, ($tag).to_str()),
|
||||||
|
@ -59,7 +62,7 @@ macro_rules! handle_element(
|
||||||
)*
|
)*
|
||||||
};
|
};
|
||||||
unsafe {
|
unsafe {
|
||||||
return Node::as_abstract_node(_element);
|
return Node::as_abstract_node(cx, _element);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -79,7 +82,8 @@ enum JSMessage {
|
||||||
|
|
||||||
pub struct HtmlParserResult {
|
pub struct HtmlParserResult {
|
||||||
root: AbstractNode<ScriptView>,
|
root: AbstractNode<ScriptView>,
|
||||||
style_port: Port<Option<Stylesheet>>,
|
style_port: Port<Stylesheet>,
|
||||||
|
iframe_port: Port<(Url, Future<Size2D<uint>>)>,
|
||||||
js_port: Port<JSResult>,
|
js_port: Port<JSResult>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,7 +116,7 @@ spawned, collates them, and sends them to the given result channel.
|
||||||
* `from_parent` - A port on which to receive new links.
|
* `from_parent` - A port on which to receive new links.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
fn css_link_listener(to_parent: Chan<Option<Stylesheet>>,
|
fn css_link_listener(to_parent: Chan<Stylesheet>,
|
||||||
from_parent: Port<CSSMessage>,
|
from_parent: Port<CSSMessage>,
|
||||||
resource_task: ResourceTask) {
|
resource_task: ResourceTask) {
|
||||||
let mut result_vec = ~[];
|
let mut result_vec = ~[];
|
||||||
|
@ -131,9 +135,8 @@ fn css_link_listener(to_parent: Chan<Option<Stylesheet>>,
|
||||||
// Send the sheets back in order
|
// Send the sheets back in order
|
||||||
// FIXME: Shouldn't wait until after we've recieved CSSTaskExit to start sending these
|
// FIXME: Shouldn't wait until after we've recieved CSSTaskExit to start sending these
|
||||||
for result_vec.iter().advance |port| {
|
for result_vec.iter().advance |port| {
|
||||||
to_parent.send(Some(port.recv()));
|
to_parent.send(port.recv());
|
||||||
}
|
}
|
||||||
to_parent.send(None);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn js_script_listener(to_parent: Chan<~[~[u8]]>,
|
fn js_script_listener(to_parent: Chan<~[~[u8]]>,
|
||||||
|
@ -184,63 +187,62 @@ fn js_script_listener(to_parent: Chan<~[~[u8]]>,
|
||||||
// Silly macros to handle constructing DOM nodes. This produces bad code and should be optimized
|
// Silly macros to handle constructing DOM nodes. This produces bad code and should be optimized
|
||||||
// via atomization (issue #85).
|
// via atomization (issue #85).
|
||||||
|
|
||||||
fn build_element_from_tag(tag: &str) -> AbstractNode<ScriptView> {
|
fn build_element_from_tag(cx: *JSContext, tag: &str) -> AbstractNode<ScriptView> {
|
||||||
// TODO (Issue #85): use atoms
|
// TODO (Issue #85): use atoms
|
||||||
handle_element!(tag, "a", HTMLAnchorElementTypeId, HTMLAnchorElement, []);
|
handle_element!(cx, tag, "a", HTMLAnchorElementTypeId, HTMLAnchorElement, []);
|
||||||
handle_element!(tag, "aside", HTMLAsideElementTypeId, HTMLAsideElement, []);
|
handle_element!(cx, tag, "aside", HTMLAsideElementTypeId, HTMLAsideElement, []);
|
||||||
handle_element!(tag, "br", HTMLBRElementTypeId, HTMLBRElement, []);
|
handle_element!(cx, tag, "br", HTMLBRElementTypeId, HTMLBRElement, []);
|
||||||
handle_element!(tag, "body", HTMLBodyElementTypeId, HTMLBodyElement, []);
|
handle_element!(cx, tag, "body", HTMLBodyElementTypeId, HTMLBodyElement, []);
|
||||||
handle_element!(tag, "bold", HTMLBoldElementTypeId, HTMLBoldElement, []);
|
handle_element!(cx, tag, "bold", HTMLBoldElementTypeId, HTMLBoldElement, []);
|
||||||
handle_element!(tag, "div", HTMLDivElementTypeId, HTMLDivElement, []);
|
handle_element!(cx, tag, "div", HTMLDivElementTypeId, HTMLDivElement, []);
|
||||||
handle_element!(tag, "font", HTMLFontElementTypeId, HTMLFontElement, []);
|
handle_element!(cx, tag, "font", HTMLFontElementTypeId, HTMLFontElement, []);
|
||||||
handle_element!(tag, "form", HTMLFormElementTypeId, HTMLFormElement, []);
|
handle_element!(cx, tag, "form", HTMLFormElementTypeId, HTMLFormElement, []);
|
||||||
handle_element!(tag, "hr", HTMLHRElementTypeId, HTMLHRElement, []);
|
handle_element!(cx, tag, "hr", HTMLHRElementTypeId, HTMLHRElement, []);
|
||||||
handle_element!(tag, "head", HTMLHeadElementTypeId, HTMLHeadElement, []);
|
handle_element!(cx, tag, "head", HTMLHeadElementTypeId, HTMLHeadElement, []);
|
||||||
handle_element!(tag, "html", HTMLHtmlElementTypeId, HTMLHtmlElement, []);
|
handle_element!(cx, tag, "html", HTMLHtmlElementTypeId, HTMLHtmlElement, []);
|
||||||
handle_element!(tag, "input", HTMLInputElementTypeId, HTMLInputElement, []);
|
handle_element!(cx, tag, "input", HTMLInputElementTypeId, HTMLInputElement, []);
|
||||||
handle_element!(tag, "i", HTMLItalicElementTypeId, HTMLItalicElement, []);
|
handle_element!(cx, tag, "i", HTMLItalicElementTypeId, HTMLItalicElement, []);
|
||||||
handle_element!(tag, "link", HTMLLinkElementTypeId, HTMLLinkElement, []);
|
handle_element!(cx, tag, "link", HTMLLinkElementTypeId, HTMLLinkElement, []);
|
||||||
handle_element!(tag, "li", HTMLListItemElementTypeId, HTMLListItemElement, []);
|
handle_element!(cx, tag, "li", HTMLListItemElementTypeId, HTMLListItemElement, []);
|
||||||
handle_element!(tag, "meta", HTMLMetaElementTypeId, HTMLMetaElement, []);
|
handle_element!(cx, tag, "meta", HTMLMetaElementTypeId, HTMLMetaElement, []);
|
||||||
handle_element!(tag, "ol", HTMLOListElementTypeId, HTMLOListElement, []);
|
handle_element!(cx, tag, "ol", HTMLOListElementTypeId, HTMLOListElement, []);
|
||||||
handle_element!(tag, "option", HTMLOptionElementTypeId, HTMLOptionElement, []);
|
handle_element!(cx, tag, "option", HTMLOptionElementTypeId, HTMLOptionElement, []);
|
||||||
handle_element!(tag, "p", HTMLParagraphElementTypeId, HTMLParagraphElement, []);
|
handle_element!(cx, tag, "p", HTMLParagraphElementTypeId, HTMLParagraphElement, []);
|
||||||
handle_element!(tag, "script", HTMLScriptElementTypeId, HTMLScriptElement, []);
|
handle_element!(cx, tag, "script", HTMLScriptElementTypeId, HTMLScriptElement, []);
|
||||||
handle_element!(tag, "section", HTMLSectionElementTypeId, HTMLSectionElement, []);
|
handle_element!(cx, tag, "section", HTMLSectionElementTypeId, HTMLSectionElement, []);
|
||||||
handle_element!(tag, "select", HTMLSelectElementTypeId, HTMLSelectElement, []);
|
handle_element!(cx, tag, "select", HTMLSelectElementTypeId, HTMLSelectElement, []);
|
||||||
handle_element!(tag, "small", HTMLSmallElementTypeId, HTMLSmallElement, []);
|
handle_element!(cx, tag, "small", HTMLSmallElementTypeId, HTMLSmallElement, []);
|
||||||
handle_element!(tag, "span", HTMLSpanElementTypeId, HTMLSpanElement, []);
|
handle_element!(cx, tag, "span", HTMLSpanElementTypeId, HTMLSpanElement, []);
|
||||||
handle_element!(tag, "style", HTMLStyleElementTypeId, HTMLStyleElement, []);
|
handle_element!(cx, tag, "style", HTMLStyleElementTypeId, HTMLStyleElement, []);
|
||||||
handle_element!(tag, "tbody", HTMLTableBodyElementTypeId, HTMLTableBodyElement, []);
|
handle_element!(cx, tag, "tbody", HTMLTableBodyElementTypeId, HTMLTableBodyElement, []);
|
||||||
handle_element!(tag, "td", HTMLTableCellElementTypeId, HTMLTableCellElement, []);
|
handle_element!(cx, tag, "td", HTMLTableCellElementTypeId, HTMLTableCellElement, []);
|
||||||
handle_element!(tag, "table", HTMLTableElementTypeId, HTMLTableElement, []);
|
handle_element!(cx, tag, "table", HTMLTableElementTypeId, HTMLTableElement, []);
|
||||||
handle_element!(tag, "tr", HTMLTableRowElementTypeId, HTMLTableRowElement, []);
|
handle_element!(cx, tag, "tr", HTMLTableRowElementTypeId, HTMLTableRowElement, []);
|
||||||
handle_element!(tag, "title", HTMLTitleElementTypeId, HTMLTitleElement, []);
|
handle_element!(cx, tag, "title", HTMLTitleElementTypeId, HTMLTitleElement, []);
|
||||||
handle_element!(tag, "ul", HTMLUListElementTypeId, HTMLUListElement, []);
|
handle_element!(cx, tag, "ul", HTMLUListElementTypeId, HTMLUListElement, []);
|
||||||
|
|
||||||
handle_element!(tag, "img", HTMLImageElementTypeId, HTMLImageElement, [(image: None)]);
|
handle_element!(cx, tag, "img", HTMLImageElementTypeId, HTMLImageElement, [(image: None)]);
|
||||||
handle_element!(tag, "iframe", HTMLIframeElementTypeId, HTMLIframeElement,
|
handle_element!(cx, tag, "iframe", HTMLIframeElementTypeId, HTMLIframeElement, [(frame: None), (size_future_chan: None)]);
|
||||||
[(frame: None), (parse_result: None)]);
|
|
||||||
|
|
||||||
handle_element!(tag, "h1", HTMLHeadingElementTypeId, HTMLHeadingElement, [(level: Heading1)]);
|
handle_element!(cx, tag, "h1", HTMLHeadingElementTypeId, HTMLHeadingElement, [(level: Heading1)]);
|
||||||
handle_element!(tag, "h2", HTMLHeadingElementTypeId, HTMLHeadingElement, [(level: Heading2)]);
|
handle_element!(cx, tag, "h2", HTMLHeadingElementTypeId, HTMLHeadingElement, [(level: Heading2)]);
|
||||||
handle_element!(tag, "h3", HTMLHeadingElementTypeId, HTMLHeadingElement, [(level: Heading3)]);
|
handle_element!(cx, tag, "h3", HTMLHeadingElementTypeId, HTMLHeadingElement, [(level: Heading3)]);
|
||||||
handle_element!(tag, "h4", HTMLHeadingElementTypeId, HTMLHeadingElement, [(level: Heading4)]);
|
handle_element!(cx, tag, "h4", HTMLHeadingElementTypeId, HTMLHeadingElement, [(level: Heading4)]);
|
||||||
handle_element!(tag, "h5", HTMLHeadingElementTypeId, HTMLHeadingElement, [(level: Heading5)]);
|
handle_element!(cx, tag, "h5", HTMLHeadingElementTypeId, HTMLHeadingElement, [(level: Heading5)]);
|
||||||
handle_element!(tag, "h6", HTMLHeadingElementTypeId, HTMLHeadingElement, [(level: Heading6)]);
|
handle_element!(cx, tag, "h6", HTMLHeadingElementTypeId, HTMLHeadingElement, [(level: Heading6)]);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
Node::as_abstract_node(~Element::new(UnknownElementTypeId, tag.to_str()))
|
Node::as_abstract_node(cx, ~Element::new(UnknownElementTypeId, tag.to_str()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(non_implicitly_copyable_typarams)]
|
#[allow(non_implicitly_copyable_typarams)]
|
||||||
pub fn parse_html(url: Url,
|
pub fn parse_html(cx: *JSContext,
|
||||||
|
url: Url,
|
||||||
resource_task: ResourceTask,
|
resource_task: ResourceTask,
|
||||||
image_cache_task: ImageCacheTask) -> HtmlParserResult {
|
image_cache_task: ImageCacheTask) -> HtmlParserResult {
|
||||||
// Spawn a CSS parser to receive links to CSS style sheets.
|
// Spawn a CSS parser to receive links to CSS style sheets.
|
||||||
let resource_task2 = resource_task.clone();
|
let resource_task2 = resource_task.clone();
|
||||||
let resource_task3 = resource_task.clone();
|
|
||||||
|
|
||||||
let (stylesheet_port, stylesheet_chan) = comm::stream();
|
let (stylesheet_port, stylesheet_chan) = comm::stream();
|
||||||
let stylesheet_chan = Cell::new(stylesheet_chan);
|
let stylesheet_chan = Cell::new(stylesheet_chan);
|
||||||
|
@ -268,7 +270,7 @@ pub fn parse_html(url: Url,
|
||||||
|
|
||||||
// Build the root node.
|
// Build the root node.
|
||||||
let root = ~HTMLHtmlElement { parent: Element::new(HTMLHtmlElementTypeId, ~"html") };
|
let root = ~HTMLHtmlElement { parent: Element::new(HTMLHtmlElementTypeId, ~"html") };
|
||||||
let root = unsafe { Node::as_abstract_node(root) };
|
let root = unsafe { Node::as_abstract_node(cx, root) };
|
||||||
debug!("created new node");
|
debug!("created new node");
|
||||||
let mut parser = hubbub::Parser("UTF-8", false);
|
let mut parser = hubbub::Parser("UTF-8", false);
|
||||||
debug!("created parser");
|
debug!("created parser");
|
||||||
|
@ -277,11 +279,12 @@ pub fn parse_html(url: Url,
|
||||||
parser.enable_styling(true);
|
parser.enable_styling(true);
|
||||||
|
|
||||||
let (css_chan2, css_chan3, js_chan2) = (css_chan.clone(), css_chan.clone(), js_chan.clone());
|
let (css_chan2, css_chan3, js_chan2) = (css_chan.clone(), css_chan.clone(), js_chan.clone());
|
||||||
|
let (iframe_port, iframe_chan) = comm::stream();
|
||||||
parser.set_tree_handler(~hubbub::TreeHandler {
|
parser.set_tree_handler(~hubbub::TreeHandler {
|
||||||
create_comment: |data: ~str| {
|
create_comment: |data: ~str| {
|
||||||
debug!("create comment");
|
debug!("create comment");
|
||||||
unsafe {
|
unsafe {
|
||||||
Node::as_abstract_node(~Comment::new(data)).to_hubbub_node()
|
Node::as_abstract_node(cx, ~Comment::new(data)).to_hubbub_node()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
create_doctype: |doctype: ~hubbub::Doctype| {
|
create_doctype: |doctype: ~hubbub::Doctype| {
|
||||||
|
@ -295,12 +298,12 @@ pub fn parse_html(url: Url,
|
||||||
system_id,
|
system_id,
|
||||||
force_quirks);
|
force_quirks);
|
||||||
unsafe {
|
unsafe {
|
||||||
Node::as_abstract_node(node).to_hubbub_node()
|
Node::as_abstract_node(cx, node).to_hubbub_node()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
create_element: |tag: ~hubbub::Tag| {
|
create_element: |tag: ~hubbub::Tag| {
|
||||||
debug!("create element");
|
debug!("create element");
|
||||||
let node = build_element_from_tag(tag.name);
|
let node = build_element_from_tag(cx, tag.name);
|
||||||
|
|
||||||
debug!("-- attach attrs");
|
debug!("-- attach attrs");
|
||||||
do node.as_mut_element |element| {
|
do node.as_mut_element |element| {
|
||||||
|
@ -325,30 +328,22 @@ pub fn parse_html(url: Url,
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
ElementNodeTypeId(HTMLIframeElementTypeId) => {
|
ElementNodeTypeId(HTMLIframeElementTypeId) => {
|
||||||
do node.with_mut_iframe_element |iframe_element| {
|
do node.with_mut_iframe_element |iframe_element| {
|
||||||
let src_opt = iframe_element.parent.get_attr("src").map(|x| x.to_str());
|
let src_opt = iframe_element.parent.get_attr("src").map(|x| x.to_str());
|
||||||
match src_opt {
|
for src_opt.iter().advance |src| {
|
||||||
None => {}
|
let iframe_url = make_url(src.clone(), Some(url2.clone()));
|
||||||
Some(src) => {
|
iframe_element.frame = Some(iframe_url.clone());
|
||||||
let iframe_url = make_url(src, Some(url2.clone()));
|
let (port, chan) = comm::oneshot();
|
||||||
iframe_element.frame = Some(iframe_url.clone());
|
iframe_element.size_future_chan = Some(chan);
|
||||||
let (parse_port, parse_chan) = comm::stream();
|
let size_future = from_port(port);
|
||||||
iframe_element.parse_result = Some(parse_port);
|
iframe_chan.send((iframe_url, size_future));
|
||||||
let image_cache_task2 = Cell::new(image_cache_task.clone());
|
|
||||||
let resource_task3 = Cell::new(resource_task3.clone());
|
|
||||||
let iframe_url = Cell::new(iframe_url);
|
|
||||||
do task::spawn {
|
|
||||||
let result = parse_html(iframe_url.take(),
|
|
||||||
resource_task3.take(),
|
|
||||||
image_cache_task2.take());
|
|
||||||
parse_chan.send(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ElementNodeTypeId(HTMLImageElementTypeId) => {
|
ElementNodeTypeId(HTMLImageElementTypeId) => {
|
||||||
do node.with_mut_image_element |image_element| {
|
do node.with_mut_image_element |image_element| {
|
||||||
let src_opt = image_element.parent.get_attr("src").map(|x| x.to_str());
|
let src_opt = image_element.parent.get_attr("src").map(|x| x.to_str());
|
||||||
|
@ -365,6 +360,7 @@ pub fn parse_html(url: Url,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO (Issue #86): handle inline styles ('style' attr)
|
//TODO (Issue #86): handle inline styles ('style' attr)
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
@ -374,7 +370,7 @@ pub fn parse_html(url: Url,
|
||||||
create_text: |data: ~str| {
|
create_text: |data: ~str| {
|
||||||
debug!("create text");
|
debug!("create text");
|
||||||
unsafe {
|
unsafe {
|
||||||
Node::as_abstract_node(~Text::new(data)).to_hubbub_node()
|
Node::as_abstract_node(cx, ~Text::new(data)).to_hubbub_node()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ref_node: |_| {},
|
ref_node: |_| {},
|
||||||
|
@ -496,6 +492,7 @@ pub fn parse_html(url: Url,
|
||||||
HtmlParserResult {
|
HtmlParserResult {
|
||||||
root: root,
|
root: root,
|
||||||
style_port: stylesheet_port,
|
style_port: stylesheet_port,
|
||||||
|
iframe_port: iframe_port,
|
||||||
js_port: js_result_port,
|
js_port: js_result_port,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,7 @@
|
||||||
/// from layout.
|
/// from layout.
|
||||||
|
|
||||||
use dom::node::{AbstractNode, ScriptView, LayoutView};
|
use dom::node::{AbstractNode, ScriptView, LayoutView};
|
||||||
use script_task::{ScriptMsg, ScriptChan};
|
use script_task::{ScriptChan};
|
||||||
|
|
||||||
use std::comm::{Chan, SharedChan};
|
use std::comm::{Chan, SharedChan};
|
||||||
use geom::rect::Rect;
|
use geom::rect::Rect;
|
||||||
use geom::size::Size2D;
|
use geom::size::Size2D;
|
||||||
|
@ -32,9 +31,6 @@ pub enum Msg {
|
||||||
/// FIXME(pcwalton): As noted below, this isn't very type safe.
|
/// FIXME(pcwalton): As noted below, this isn't very type safe.
|
||||||
QueryMsg(LayoutQuery),
|
QueryMsg(LayoutQuery),
|
||||||
|
|
||||||
/// Routes a message (usually from the compositor) to the appropriate script task
|
|
||||||
RouteScriptMsg(ScriptMsg),
|
|
||||||
|
|
||||||
/// Requests that the layout task shut down and exit.
|
/// Requests that the layout task shut down and exit.
|
||||||
ExitMsg,
|
ExitMsg,
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -7,6 +7,7 @@ use extra::time::precise_time_ns;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::comm::{Port, SharedChan};
|
use std::comm::{Port, SharedChan};
|
||||||
use extra::sort::tim_sort;
|
use extra::sort::tim_sort;
|
||||||
|
use std::iterator::AdditiveIterator;
|
||||||
|
|
||||||
// front-end representation of the profiler used to communicate with the profiler
|
// front-end representation of the profiler used to communicate with the profiler
|
||||||
#[deriving(Clone)]
|
#[deriving(Clone)]
|
||||||
|
@ -162,7 +163,7 @@ impl Profiler {
|
||||||
let data_len = data.len();
|
let data_len = data.len();
|
||||||
if data_len > 0 {
|
if data_len > 0 {
|
||||||
let (mean, median, &min, &max) =
|
let (mean, median, &min, &max) =
|
||||||
(data.iter().fold(0f, |a, b| a + *b) / (data_len as float),
|
(data.iter().transform(|&x|x).sum() / (data_len as float),
|
||||||
data[data_len / 2],
|
data[data_len / 2],
|
||||||
data.iter().min().unwrap(),
|
data.iter().min().unwrap(),
|
||||||
data.iter().max().unwrap());
|
data.iter().max().unwrap());
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue