mirror of
https://github.com/servo/servo.git
synced 2025-08-03 20:50:07 +01:00
Split page load into separate network and parsing stages. Delay Page creation until the load is finished. Make session history traversal simply activate existing pipelines, rather than potentially loading them from the network.
This commit is contained in:
parent
621150db1c
commit
d9f04180a5
5 changed files with 267 additions and 189 deletions
|
@ -407,8 +407,7 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
|
||||||
self.time_profiler_chan.clone(),
|
self.time_profiler_chan.clone(),
|
||||||
self.window_size,
|
self.window_size,
|
||||||
script_pipeline,
|
script_pipeline,
|
||||||
load_data.clone());
|
load_data);
|
||||||
pipe.load();
|
|
||||||
Rc::new(pipe)
|
Rc::new(pipe)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -876,7 +875,7 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
|
||||||
};
|
};
|
||||||
|
|
||||||
for frame in destination_frame.iter() {
|
for frame in destination_frame.iter() {
|
||||||
frame.pipeline.borrow().load();
|
frame.pipeline.borrow().activate();
|
||||||
frame.pipeline.borrow().thaw();
|
frame.pipeline.borrow().thaw();
|
||||||
}
|
}
|
||||||
self.send_frame_tree_and_grant_paint_permission(destination_frame);
|
self.send_frame_tree_and_grant_paint_permission(destination_frame);
|
||||||
|
|
|
@ -88,7 +88,8 @@ impl Pipeline {
|
||||||
storage_task.clone(),
|
storage_task.clone(),
|
||||||
image_cache_task.clone(),
|
image_cache_task.clone(),
|
||||||
devtools_chan,
|
devtools_chan,
|
||||||
window_size);
|
window_size,
|
||||||
|
load_data.clone());
|
||||||
ScriptControlChan(script_chan)
|
ScriptControlChan(script_chan)
|
||||||
}
|
}
|
||||||
Some(spipe) => {
|
Some(spipe) => {
|
||||||
|
@ -97,6 +98,7 @@ impl Pipeline {
|
||||||
new_pipeline_id: id,
|
new_pipeline_id: id,
|
||||||
subpage_id: parent.expect("script_pipeline != None but subpage_id == None").1,
|
subpage_id: parent.expect("script_pipeline != None but subpage_id == None").1,
|
||||||
layout_chan: ScriptTaskFactory::clone_layout_channel(None::<&mut STF>, &layout_pair),
|
layout_chan: ScriptTaskFactory::clone_layout_channel(None::<&mut STF>, &layout_pair),
|
||||||
|
load_data: load_data.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let ScriptControlChan(ref chan) = spipe.script_chan;
|
let ScriptControlChan(ref chan) = spipe.script_chan;
|
||||||
|
@ -160,11 +162,9 @@ impl Pipeline {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load(&self) {
|
pub fn activate(&self) {
|
||||||
let ScriptControlChan(ref chan) = self.script_chan;
|
let ScriptControlChan(ref chan) = self.script_chan;
|
||||||
chan.send(ConstellationControlMsg::Load(self.id,
|
chan.send(ConstellationControlMsg::Activate(self.id)).unwrap();
|
||||||
self.parent,
|
|
||||||
self.load_data.clone())).unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn grant_paint_permission(&self) {
|
pub fn grant_paint_permission(&self) {
|
||||||
|
|
|
@ -68,11 +68,11 @@ pub struct Page {
|
||||||
|
|
||||||
js_info: DOMRefCell<Option<JSPageInfo>>,
|
js_info: DOMRefCell<Option<JSPageInfo>>,
|
||||||
|
|
||||||
/// Cached copy of the most recent url loaded by the script
|
/// Cached copy of the most recent url loaded by the script, after all redirections.
|
||||||
/// TODO(tkuehn): this currently does not follow any particular caching policy
|
/// TODO(tkuehn): this currently does not follow any particular caching policy
|
||||||
/// and simply caches pages forever (!). The bool indicates if reflow is required
|
/// and simply caches pages forever (!). The bool indicates if reflow is required
|
||||||
/// when reloading.
|
/// when reloading.
|
||||||
url: DOMRefCell<Option<(Url, bool)>>,
|
url: DOMRefCell<(Url, bool)>,
|
||||||
|
|
||||||
next_subpage_id: Cell<SubpageId>,
|
next_subpage_id: Cell<SubpageId>,
|
||||||
|
|
||||||
|
@ -140,7 +140,8 @@ impl Page {
|
||||||
storage_task: StorageTask,
|
storage_task: StorageTask,
|
||||||
constellation_chan: ConstellationChan,
|
constellation_chan: ConstellationChan,
|
||||||
js_context: Rc<Cx>,
|
js_context: Rc<Cx>,
|
||||||
devtools_chan: Option<DevtoolsControlChan>) -> Page {
|
devtools_chan: Option<DevtoolsControlChan>,
|
||||||
|
url: Url) -> Page {
|
||||||
let js_info = JSPageInfo {
|
let js_info = JSPageInfo {
|
||||||
dom_static: GlobalStaticData::new(),
|
dom_static: GlobalStaticData::new(),
|
||||||
js_context: js_context,
|
js_context: js_context,
|
||||||
|
@ -160,7 +161,7 @@ impl Page {
|
||||||
layout_join_port: DOMRefCell::new(None),
|
layout_join_port: DOMRefCell::new(None),
|
||||||
window_size: Cell::new(window_size),
|
window_size: Cell::new(window_size),
|
||||||
js_info: DOMRefCell::new(Some(js_info)),
|
js_info: DOMRefCell::new(Some(js_info)),
|
||||||
url: DOMRefCell::new(None),
|
url: DOMRefCell::new((url, true)),
|
||||||
next_subpage_id: Cell::new(SubpageId(0)),
|
next_subpage_id: Cell::new(SubpageId(0)),
|
||||||
resize_event: Cell::new(None),
|
resize_event: Cell::new(None),
|
||||||
fragment_name: DOMRefCell::new(None),
|
fragment_name: DOMRefCell::new(None),
|
||||||
|
@ -292,11 +293,11 @@ impl Page {
|
||||||
self.js_info.borrow()
|
self.js_info.borrow()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn url<'a>(&'a self) -> Ref<'a, Option<(Url, bool)>> {
|
pub fn url<'a>(&'a self) -> Ref<'a, (Url, bool)> {
|
||||||
self.url.borrow()
|
self.url.borrow()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mut_url<'a>(&'a self) -> RefMut<'a, Option<(Url, bool)>> {
|
pub fn mut_url<'a>(&'a self) -> RefMut<'a, (Url, bool)> {
|
||||||
self.url.borrow_mut()
|
self.url.borrow_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -316,7 +317,7 @@ impl Page {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_url(&self) -> Url {
|
pub fn get_url(&self) -> Url {
|
||||||
self.url().as_ref().unwrap().0.clone()
|
self.url().0.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME(cgaebel): join_layout is racey. What if the compositor triggers a
|
// FIXME(cgaebel): join_layout is racey. What if the compositor triggers a
|
||||||
|
|
|
@ -49,16 +49,17 @@ use msg::constellation_msg::{LoadData, PipelineId, SubpageId};
|
||||||
use msg::constellation_msg::{Failure, Msg, WindowSizeData, PipelineExitType};
|
use msg::constellation_msg::{Failure, Msg, WindowSizeData, PipelineExitType};
|
||||||
use msg::constellation_msg::Msg as ConstellationMsg;
|
use msg::constellation_msg::Msg as ConstellationMsg;
|
||||||
use net::image_cache_task::ImageCacheTask;
|
use net::image_cache_task::ImageCacheTask;
|
||||||
use net::resource_task::{ResourceTask, ControlMsg};
|
use net::resource_task::{ResourceTask, ControlMsg, LoadResponse};
|
||||||
use net::resource_task::LoadData as NetLoadData;
|
use net::resource_task::LoadData as NetLoadData;
|
||||||
use net::storage_task::StorageTask;
|
use net::storage_task::StorageTask;
|
||||||
use string_cache::Atom;
|
use string_cache::Atom;
|
||||||
use util::geometry::to_frac_px;
|
use util::geometry::to_frac_px;
|
||||||
use util::smallvec::SmallVec;
|
use util::smallvec::SmallVec;
|
||||||
use util::str::DOMString;
|
use util::str::DOMString;
|
||||||
use util::task::spawn_named_with_send_on_failure;
|
use util::task::{spawn_named, spawn_named_with_send_on_failure};
|
||||||
use util::task_state;
|
use util::task_state;
|
||||||
|
|
||||||
|
use geom::Rect;
|
||||||
use geom::point::Point2D;
|
use geom::point::Point2D;
|
||||||
use hyper::header::{LastModified, Headers};
|
use hyper::header::{LastModified, Headers};
|
||||||
use js::jsapi::{JS_SetWrapObjectCallbacks, JS_SetGCZeal, JS_DEFAULT_ZEAL_FREQ, JS_GC};
|
use js::jsapi::{JS_SetWrapObjectCallbacks, JS_SetGCZeal, JS_DEFAULT_ZEAL_FREQ, JS_GC};
|
||||||
|
@ -83,6 +84,32 @@ use time::Tm;
|
||||||
|
|
||||||
thread_local!(pub static STACK_ROOTS: Cell<Option<RootCollectionPtr>> = Cell::new(None));
|
thread_local!(pub static STACK_ROOTS: Cell<Option<RootCollectionPtr>> = Cell::new(None));
|
||||||
|
|
||||||
|
struct InProgressLoad {
|
||||||
|
pipeline_id: PipelineId,
|
||||||
|
subpage_id: Option<(PipelineId, SubpageId)>,
|
||||||
|
window_size: WindowSizeData,
|
||||||
|
layout_chan: LayoutChan,
|
||||||
|
clip_rect: Option<Rect<f32>>,
|
||||||
|
url: Url,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InProgressLoad {
|
||||||
|
fn new(id: PipelineId,
|
||||||
|
subpage_id: Option<(PipelineId, SubpageId)>,
|
||||||
|
layout_chan: LayoutChan,
|
||||||
|
window_size: WindowSizeData,
|
||||||
|
url: Url) -> InProgressLoad {
|
||||||
|
InProgressLoad {
|
||||||
|
pipeline_id: id,
|
||||||
|
subpage_id: subpage_id,
|
||||||
|
layout_chan: layout_chan,
|
||||||
|
window_size: window_size,
|
||||||
|
clip_rect: None,
|
||||||
|
url: url,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy)]
|
#[derive(Copy)]
|
||||||
pub enum TimerSource {
|
pub enum TimerSource {
|
||||||
FromWindow(PipelineId),
|
FromWindow(PipelineId),
|
||||||
|
@ -118,6 +145,8 @@ pub enum ScriptMsg {
|
||||||
RunnableMsg(Box<Runnable+Send>),
|
RunnableMsg(Box<Runnable+Send>),
|
||||||
/// A DOM object's last pinned reference was removed (dispatched to all tasks).
|
/// A DOM object's last pinned reference was removed (dispatched to all tasks).
|
||||||
RefcountCleanup(TrustedReference),
|
RefcountCleanup(TrustedReference),
|
||||||
|
/// The final network response for a page has arrived.
|
||||||
|
PageFetchComplete(PipelineId, Option<SubpageId>, LoadResponse),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A cloneable interface for communicating with an event loop.
|
/// A cloneable interface for communicating with an event loop.
|
||||||
|
@ -175,11 +204,15 @@ impl Drop for StackRootTLS {
|
||||||
/// FIXME: Rename to `Page`, following WebKit?
|
/// FIXME: Rename to `Page`, following WebKit?
|
||||||
pub struct ScriptTask {
|
pub struct ScriptTask {
|
||||||
/// A handle to the information pertaining to page layout
|
/// A handle to the information pertaining to page layout
|
||||||
page: DOMRefCell<Rc<Page>>,
|
page: DOMRefCell<Option<Rc<Page>>>,
|
||||||
|
/// A list of data pertaining to loads that have not yet received a network response
|
||||||
|
incomplete_loads: DOMRefCell<Vec<InProgressLoad>>,
|
||||||
/// A handle to the image cache task.
|
/// A handle to the image cache task.
|
||||||
image_cache_task: ImageCacheTask,
|
image_cache_task: ImageCacheTask,
|
||||||
/// A handle to the resource task.
|
/// A handle to the resource task.
|
||||||
resource_task: ResourceTask,
|
resource_task: ResourceTask,
|
||||||
|
/// A handle to the storage task.
|
||||||
|
storage_task: StorageTask,
|
||||||
|
|
||||||
/// The port on which the script task receives messages (load URL, exit, etc.)
|
/// The port on which the script task receives messages (load URL, exit, etc.)
|
||||||
port: Receiver<ScriptMsg>,
|
port: Receiver<ScriptMsg>,
|
||||||
|
@ -274,15 +307,14 @@ impl ScriptTaskFactory for ScriptTask {
|
||||||
storage_task: StorageTask,
|
storage_task: StorageTask,
|
||||||
image_cache_task: ImageCacheTask,
|
image_cache_task: ImageCacheTask,
|
||||||
devtools_chan: Option<DevtoolsControlChan>,
|
devtools_chan: Option<DevtoolsControlChan>,
|
||||||
window_size: WindowSizeData)
|
window_size: WindowSizeData,
|
||||||
|
load_data: LoadData)
|
||||||
where C: ScriptListener + Send + 'static {
|
where C: ScriptListener + Send + 'static {
|
||||||
let ConstellationChan(const_chan) = constellation_chan.clone();
|
let ConstellationChan(const_chan) = constellation_chan.clone();
|
||||||
let (script_chan, script_port) = channel();
|
let (script_chan, script_port) = channel();
|
||||||
let layout_chan = LayoutChan(layout_chan.sender());
|
let layout_chan = LayoutChan(layout_chan.sender());
|
||||||
spawn_named_with_send_on_failure("ScriptTask", task_state::SCRIPT, move || {
|
spawn_named_with_send_on_failure("ScriptTask", task_state::SCRIPT, move || {
|
||||||
let script_task = ScriptTask::new(id,
|
let script_task = ScriptTask::new(box compositor as Box<ScriptListener>,
|
||||||
box compositor as Box<ScriptListener>,
|
|
||||||
layout_chan,
|
|
||||||
script_port,
|
script_port,
|
||||||
NonWorkerScriptChan(script_chan),
|
NonWorkerScriptChan(script_chan),
|
||||||
control_chan,
|
control_chan,
|
||||||
|
@ -291,9 +323,13 @@ impl ScriptTaskFactory for ScriptTask {
|
||||||
resource_task,
|
resource_task,
|
||||||
storage_task,
|
storage_task,
|
||||||
image_cache_task,
|
image_cache_task,
|
||||||
devtools_chan,
|
devtools_chan);
|
||||||
window_size);
|
|
||||||
let mut failsafe = ScriptMemoryFailsafe::new(&script_task);
|
let mut failsafe = ScriptMemoryFailsafe::new(&script_task);
|
||||||
|
|
||||||
|
let new_load = InProgressLoad::new(id, None, layout_chan, window_size,
|
||||||
|
load_data.url.clone());
|
||||||
|
script_task.start_page_load(new_load, load_data);
|
||||||
|
|
||||||
script_task.start();
|
script_task.start();
|
||||||
|
|
||||||
// This must always be the very last operation performed before the task completes
|
// This must always be the very last operation performed before the task completes
|
||||||
|
@ -312,9 +348,7 @@ unsafe extern "C" fn debug_gc_callback(_rt: *mut JSRuntime, status: JSGCStatus)
|
||||||
|
|
||||||
impl ScriptTask {
|
impl ScriptTask {
|
||||||
/// Creates a new script task.
|
/// Creates a new script task.
|
||||||
pub fn new(id: PipelineId,
|
pub fn new(compositor: Box<ScriptListener+'static>,
|
||||||
compositor: Box<ScriptListener+'static>,
|
|
||||||
layout_chan: LayoutChan,
|
|
||||||
port: Receiver<ScriptMsg>,
|
port: Receiver<ScriptMsg>,
|
||||||
chan: NonWorkerScriptChan,
|
chan: NonWorkerScriptChan,
|
||||||
control_chan: ScriptControlChan,
|
control_chan: ScriptControlChan,
|
||||||
|
@ -323,8 +357,7 @@ impl ScriptTask {
|
||||||
resource_task: ResourceTask,
|
resource_task: ResourceTask,
|
||||||
storage_task: StorageTask,
|
storage_task: StorageTask,
|
||||||
img_cache_task: ImageCacheTask,
|
img_cache_task: ImageCacheTask,
|
||||||
devtools_chan: Option<DevtoolsControlChan>,
|
devtools_chan: Option<DevtoolsControlChan>)
|
||||||
window_size: WindowSizeData)
|
|
||||||
-> ScriptTask {
|
-> ScriptTask {
|
||||||
let (js_runtime, js_context) = ScriptTask::new_rt_and_cx();
|
let (js_runtime, js_context) = ScriptTask::new_rt_and_cx();
|
||||||
let wrap_for_same_compartment = wrap_for_same_compartment as
|
let wrap_for_same_compartment = wrap_for_same_compartment as
|
||||||
|
@ -348,19 +381,14 @@ impl ScriptTask {
|
||||||
Some(pre_wrap));
|
Some(pre_wrap));
|
||||||
}
|
}
|
||||||
|
|
||||||
let page = Page::new(id, None, layout_chan, window_size,
|
|
||||||
resource_task.clone(),
|
|
||||||
storage_task,
|
|
||||||
constellation_chan.clone(),
|
|
||||||
js_context.clone(),
|
|
||||||
devtools_chan.clone());
|
|
||||||
|
|
||||||
let (devtools_sender, devtools_receiver) = channel();
|
let (devtools_sender, devtools_receiver) = channel();
|
||||||
ScriptTask {
|
ScriptTask {
|
||||||
page: DOMRefCell::new(Rc::new(page)),
|
page: DOMRefCell::new(None),
|
||||||
|
incomplete_loads: DOMRefCell::new(vec!()),
|
||||||
|
|
||||||
image_cache_task: img_cache_task,
|
image_cache_task: img_cache_task,
|
||||||
resource_task: resource_task,
|
resource_task: resource_task,
|
||||||
|
storage_task: storage_task,
|
||||||
|
|
||||||
port: port,
|
port: port,
|
||||||
chan: chan,
|
chan: chan,
|
||||||
|
@ -417,6 +445,10 @@ impl ScriptTask {
|
||||||
(js_runtime, js_context)
|
(js_runtime, js_context)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn root_page(&self) -> Rc<Page> {
|
||||||
|
self.page.borrow().as_ref().unwrap().clone()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_cx(&self) -> *mut JSContext {
|
pub fn get_cx(&self) -> *mut JSContext {
|
||||||
(**self.js_context.borrow().as_ref().unwrap()).ptr
|
(**self.js_context.borrow().as_ref().unwrap()).ptr
|
||||||
}
|
}
|
||||||
|
@ -439,7 +471,8 @@ impl ScriptTask {
|
||||||
let mut resizes = vec!();
|
let mut resizes = vec!();
|
||||||
|
|
||||||
{
|
{
|
||||||
let page = self.page.borrow_mut();
|
let page = self.page.borrow();
|
||||||
|
if let Some(ref page) = page.as_ref() {
|
||||||
for page in page.iter() {
|
for page in page.iter() {
|
||||||
// Only process a resize if layout is idle.
|
// Only process a resize if layout is idle.
|
||||||
let layout_join_port = page.layout_join_port.borrow();
|
let layout_join_port = page.layout_join_port.borrow();
|
||||||
|
@ -453,6 +486,7 @@ impl ScriptTask {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (id, size) in resizes.into_iter() {
|
for (id, size) in resizes.into_iter() {
|
||||||
self.handle_event(id, ResizeEvent(size));
|
self.handle_event(id, ResizeEvent(size));
|
||||||
|
@ -502,17 +536,10 @@ impl ScriptTask {
|
||||||
self.handle_new_layout(new_layout_info);
|
self.handle_new_layout(new_layout_info);
|
||||||
}
|
}
|
||||||
MixedMessage::FromConstellation(ConstellationControlMsg::Resize(id, size)) => {
|
MixedMessage::FromConstellation(ConstellationControlMsg::Resize(id, size)) => {
|
||||||
let page = self.page.borrow_mut();
|
self.handle_resize(id, size);
|
||||||
let page = page.find(id).expect("resize sent to nonexistent pipeline");
|
|
||||||
page.resize_event.set(Some(size));
|
|
||||||
}
|
}
|
||||||
MixedMessage::FromConstellation(ConstellationControlMsg::Viewport(id, rect)) => {
|
MixedMessage::FromConstellation(ConstellationControlMsg::Viewport(id, rect)) => {
|
||||||
let page = self.page.borrow_mut();
|
self.handle_viewport(id, rect);
|
||||||
let inner_page = page.find(id).expect("Page rect message sent to nonexistent pipeline");
|
|
||||||
if inner_page.set_page_clip_rect_with_new_viewport(rect) {
|
|
||||||
let page = get_page(&*page, id);
|
|
||||||
self.force_reflow(&*page);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
sequential.push(event);
|
sequential.push(event);
|
||||||
|
@ -555,8 +582,8 @@ impl ScriptTask {
|
||||||
match msg {
|
match msg {
|
||||||
ConstellationControlMsg::AttachLayout(_) =>
|
ConstellationControlMsg::AttachLayout(_) =>
|
||||||
panic!("should have handled AttachLayout already"),
|
panic!("should have handled AttachLayout already"),
|
||||||
ConstellationControlMsg::Load(id, parent, load_data) =>
|
ConstellationControlMsg::Activate(id) =>
|
||||||
self.load(id, parent, load_data),
|
self.handle_activate(id),
|
||||||
ConstellationControlMsg::SendEvent(id, event) =>
|
ConstellationControlMsg::SendEvent(id, event) =>
|
||||||
self.handle_event(id, event),
|
self.handle_event(id, event),
|
||||||
ConstellationControlMsg::ReflowComplete(id, reflow_id) =>
|
ConstellationControlMsg::ReflowComplete(id, reflow_id) =>
|
||||||
|
@ -598,57 +625,91 @@ impl ScriptTask {
|
||||||
runnable.handler(),
|
runnable.handler(),
|
||||||
ScriptMsg::RefcountCleanup(addr) =>
|
ScriptMsg::RefcountCleanup(addr) =>
|
||||||
LiveDOMReferences::cleanup(self.get_cx(), addr),
|
LiveDOMReferences::cleanup(self.get_cx(), addr),
|
||||||
|
ScriptMsg::PageFetchComplete(id, subpage, response) =>
|
||||||
|
self.handle_page_fetch_complete(id, subpage, response),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_msg_from_devtools(&self, msg: DevtoolScriptControlMsg) {
|
fn handle_msg_from_devtools(&self, msg: DevtoolScriptControlMsg) {
|
||||||
|
let page = self.root_page();
|
||||||
match msg {
|
match msg {
|
||||||
DevtoolScriptControlMsg::EvaluateJS(id, s, reply) =>
|
DevtoolScriptControlMsg::EvaluateJS(id, s, reply) =>
|
||||||
devtools::handle_evaluate_js(&*self.page.borrow(), id, s, reply),
|
devtools::handle_evaluate_js(&page, id, s, reply),
|
||||||
DevtoolScriptControlMsg::GetRootNode(id, reply) =>
|
DevtoolScriptControlMsg::GetRootNode(id, reply) =>
|
||||||
devtools::handle_get_root_node(&*self.page.borrow(), id, reply),
|
devtools::handle_get_root_node(&page, id, reply),
|
||||||
DevtoolScriptControlMsg::GetDocumentElement(id, reply) =>
|
DevtoolScriptControlMsg::GetDocumentElement(id, reply) =>
|
||||||
devtools::handle_get_document_element(&*self.page.borrow(), id, reply),
|
devtools::handle_get_document_element(&page, id, reply),
|
||||||
DevtoolScriptControlMsg::GetChildren(id, node_id, reply) =>
|
DevtoolScriptControlMsg::GetChildren(id, node_id, reply) =>
|
||||||
devtools::handle_get_children(&*self.page.borrow(), id, node_id, reply),
|
devtools::handle_get_children(&page, id, node_id, reply),
|
||||||
DevtoolScriptControlMsg::GetLayout(id, node_id, reply) =>
|
DevtoolScriptControlMsg::GetLayout(id, node_id, reply) =>
|
||||||
devtools::handle_get_layout(&*self.page.borrow(), id, node_id, reply),
|
devtools::handle_get_layout(&page, id, node_id, reply),
|
||||||
DevtoolScriptControlMsg::ModifyAttribute(id, node_id, modifications) =>
|
DevtoolScriptControlMsg::ModifyAttribute(id, node_id, modifications) =>
|
||||||
devtools::handle_modify_attribute(&*self.page.borrow(), id, node_id, modifications),
|
devtools::handle_modify_attribute(&page, id, node_id, modifications),
|
||||||
DevtoolScriptControlMsg::WantsLiveNotifications(pipeline_id, to_send) =>
|
DevtoolScriptControlMsg::WantsLiveNotifications(pipeline_id, to_send) =>
|
||||||
devtools::handle_wants_live_notifications(&*self.page.borrow(), pipeline_id, to_send),
|
devtools::handle_wants_live_notifications(&page, pipeline_id, to_send),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_resize(&self, id: PipelineId, size: WindowSizeData) {
|
||||||
|
let page = self.page.borrow();
|
||||||
|
if let Some(ref page) = page.as_ref() {
|
||||||
|
if let Some(ref page) = page.find(id) {
|
||||||
|
page.resize_event.set(Some(size));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut loads = self.incomplete_loads.borrow_mut();
|
||||||
|
if let Some(ref mut load) = loads.iter_mut().find(|load| load.pipeline_id == id) {
|
||||||
|
load.window_size = size;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
panic!("resize sent to nonexistent pipeline");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_viewport(&self, id: PipelineId, rect: Rect<f32>) {
|
||||||
|
let page = self.page.borrow();
|
||||||
|
if let Some(page) = page.as_ref() {
|
||||||
|
if let Some(ref inner_page) = page.find(id) {
|
||||||
|
if inner_page.set_page_clip_rect_with_new_viewport(rect) {
|
||||||
|
let page = get_page(page, id);
|
||||||
|
self.force_reflow(&*page);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut loads = self.incomplete_loads.borrow_mut();
|
||||||
|
if let Some(ref mut load) = loads.iter_mut().find(|load| load.pipeline_id == id) {
|
||||||
|
load.clip_rect = Some(rect);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
panic!("Page rect message sent to nonexistent pipeline");
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_new_layout(&self, new_layout_info: NewLayoutInfo) {
|
fn handle_new_layout(&self, new_layout_info: NewLayoutInfo) {
|
||||||
let NewLayoutInfo {
|
let NewLayoutInfo {
|
||||||
old_pipeline_id,
|
old_pipeline_id,
|
||||||
new_pipeline_id,
|
new_pipeline_id,
|
||||||
subpage_id,
|
subpage_id,
|
||||||
layout_chan
|
layout_chan,
|
||||||
|
load_data,
|
||||||
} = new_layout_info;
|
} = new_layout_info;
|
||||||
|
|
||||||
let page = self.page.borrow_mut();
|
let page = self.root_page();
|
||||||
let parent_page = page.find(old_pipeline_id).expect("ScriptTask: received a layout
|
let parent_page = page.find(old_pipeline_id).expect("ScriptTask: received a layout
|
||||||
whose parent has a PipelineId which does not correspond to a pipeline in the script
|
whose parent has a PipelineId which does not correspond to a pipeline in the script
|
||||||
task's page tree. This is a bug.");
|
task's page tree. This is a bug.");
|
||||||
let new_page = {
|
|
||||||
let window_size = parent_page.window_size.get();
|
let chan = layout_chan.downcast_ref::<Sender<layout_interface::Msg>>().unwrap();
|
||||||
Page::new(new_pipeline_id, Some(subpage_id),
|
let layout_chan = LayoutChan(chan.clone());
|
||||||
LayoutChan(layout_chan.downcast_ref::<Sender<layout_interface::Msg>>().unwrap().clone()),
|
let new_load = InProgressLoad::new(new_pipeline_id, Some((old_pipeline_id, subpage_id)),
|
||||||
window_size,
|
layout_chan, parent_page.window_size.get(),
|
||||||
parent_page.resource_task.clone(),
|
load_data.url.clone());
|
||||||
parent_page.storage_task.clone(),
|
self.start_page_load(new_load, load_data);
|
||||||
self.constellation_chan.clone(),
|
|
||||||
self.js_context.borrow().as_ref().unwrap().clone(),
|
|
||||||
self.devtools_chan.clone())
|
|
||||||
};
|
|
||||||
parent_page.children.borrow_mut().push(Rc::new(new_page));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handles a timer that fired.
|
/// Handles a timer that fired.
|
||||||
fn handle_fire_timer_msg(&self, id: PipelineId, timer_id: TimerId) {
|
fn handle_fire_timer_msg(&self, id: PipelineId, timer_id: TimerId) {
|
||||||
let page = self.page.borrow_mut();
|
let page = self.root_page();
|
||||||
let page = page.find(id).expect("ScriptTask: received fire timer msg for a
|
let page = page.find(id).expect("ScriptTask: received fire timer msg for a
|
||||||
pipeline ID not associated with this script task. This is a bug.");
|
pipeline ID not associated with this script task. This is a bug.");
|
||||||
let frame = page.frame();
|
let frame = page.frame();
|
||||||
|
@ -658,7 +719,7 @@ impl ScriptTask {
|
||||||
|
|
||||||
/// Handles freeze message
|
/// Handles freeze message
|
||||||
fn handle_freeze_msg(&self, id: PipelineId) {
|
fn handle_freeze_msg(&self, id: PipelineId) {
|
||||||
let page = self.page.borrow_mut();
|
let page = self.root_page();
|
||||||
let page = page.find(id).expect("ScriptTask: received freeze msg for a
|
let page = page.find(id).expect("ScriptTask: received freeze msg for a
|
||||||
pipeline ID not associated with this script task. This is a bug.");
|
pipeline ID not associated with this script task. This is a bug.");
|
||||||
let frame = page.frame();
|
let frame = page.frame();
|
||||||
|
@ -668,7 +729,7 @@ impl ScriptTask {
|
||||||
|
|
||||||
/// Handles thaw message
|
/// Handles thaw message
|
||||||
fn handle_thaw_msg(&self, id: PipelineId) {
|
fn handle_thaw_msg(&self, id: PipelineId) {
|
||||||
let page = self.page.borrow_mut();
|
let page = self.root_page();
|
||||||
let page = page.find(id).expect("ScriptTask: received thaw msg for a
|
let page = page.find(id).expect("ScriptTask: received thaw msg for a
|
||||||
pipeline ID not associated with this script task. This is a bug.");
|
pipeline ID not associated with this script task. This is a bug.");
|
||||||
let frame = page.frame();
|
let frame = page.frame();
|
||||||
|
@ -676,10 +737,26 @@ impl ScriptTask {
|
||||||
window.r().thaw();
|
window.r().thaw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_activate(&self, pipeline_id: PipelineId) {
|
||||||
|
// We should only get this message when moving in history, so all pages requested
|
||||||
|
// should exist.
|
||||||
|
let page = self.root_page().find(pipeline_id).unwrap();
|
||||||
|
|
||||||
|
// Pull out the `needs_reflow` flag explicitly because `reflow` can ask for the
|
||||||
|
// page's URL, and we can't be holding a borrow on that URL (#4402).
|
||||||
|
let needed_reflow = {
|
||||||
|
let &mut (_, ref mut needs_reflow) = &mut *page.mut_url();
|
||||||
|
replace(needs_reflow, false)
|
||||||
|
};
|
||||||
|
if needed_reflow {
|
||||||
|
self.force_reflow(&*page);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Handles a notification that reflow completed.
|
/// Handles a notification that reflow completed.
|
||||||
fn handle_reflow_complete_msg(&self, pipeline_id: PipelineId, reflow_id: uint) {
|
fn handle_reflow_complete_msg(&self, pipeline_id: PipelineId, reflow_id: uint) {
|
||||||
debug!("Script: Reflow {:?} complete for {:?}", reflow_id, pipeline_id);
|
debug!("Script: Reflow {:?} complete for {:?}", reflow_id, pipeline_id);
|
||||||
let page = self.page.borrow_mut();
|
let page = self.root_page();
|
||||||
let page = page.find(pipeline_id).expect(
|
let page = page.find(pipeline_id).expect(
|
||||||
"ScriptTask: received a load message for a layout channel that is not associated \
|
"ScriptTask: received a load message for a layout channel that is not associated \
|
||||||
with this script task. This is a bug.");
|
with this script task. This is a bug.");
|
||||||
|
@ -700,13 +777,12 @@ impl ScriptTask {
|
||||||
|
|
||||||
/// Window was resized, but this script was not active, so don't reflow yet
|
/// Window was resized, but this script was not active, so don't reflow yet
|
||||||
fn handle_resize_inactive_msg(&self, id: PipelineId, new_size: WindowSizeData) {
|
fn handle_resize_inactive_msg(&self, id: PipelineId, new_size: WindowSizeData) {
|
||||||
let page = self.page.borrow_mut();
|
let page = self.root_page();
|
||||||
let page = page.find(id).expect("Received resize message for PipelineId not associated
|
let page = page.find(id).expect("Received resize message for PipelineId not associated
|
||||||
with a page in the page tree. This is a bug.");
|
with a page in the page tree. This is a bug.");
|
||||||
page.window_size.set(new_size);
|
page.window_size.set(new_size);
|
||||||
match &mut *page.mut_url() {
|
match &mut *page.mut_url() {
|
||||||
&mut Some((_, ref mut needs_reflow)) => *needs_reflow = true,
|
&mut (_, ref mut needs_reflow) => *needs_reflow = true,
|
||||||
&mut None => (),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -724,20 +800,29 @@ impl ScriptTask {
|
||||||
self.compositor.borrow_mut().close();
|
self.compositor.borrow_mut().close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_page_fetch_complete(&self, id: PipelineId, subpage: Option<SubpageId>,
|
||||||
|
response: LoadResponse) {
|
||||||
|
let idx = self.incomplete_loads.borrow().iter().position(|&:load| {
|
||||||
|
load.pipeline_id == id && load.subpage_id.map(|sub| sub.1) == subpage
|
||||||
|
}).unwrap();
|
||||||
|
let load = self.incomplete_loads.borrow_mut().remove(idx);
|
||||||
|
self.load(response, load);
|
||||||
|
}
|
||||||
|
|
||||||
/// Handles a request for the window title.
|
/// Handles a request for the window title.
|
||||||
fn handle_get_title_msg(&self, pipeline_id: PipelineId) {
|
fn handle_get_title_msg(&self, pipeline_id: PipelineId) {
|
||||||
get_page(&*self.page.borrow(), pipeline_id).send_title_to_compositor();
|
get_page(&self.root_page(), pipeline_id).send_title_to_compositor();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handles a request to exit the script task and shut down layout.
|
/// Handles a request to exit the script task and shut down layout.
|
||||||
/// Returns true if the script task should shut down and false otherwise.
|
/// Returns true if the script task should shut down and false otherwise.
|
||||||
fn handle_exit_pipeline_msg(&self, id: PipelineId, exit_type: PipelineExitType) -> bool {
|
fn handle_exit_pipeline_msg(&self, id: PipelineId, exit_type: PipelineExitType) -> bool {
|
||||||
// If root is being exited, shut down all pages
|
// If root is being exited, shut down all pages
|
||||||
let page = self.page.borrow_mut();
|
let page = self.root_page();
|
||||||
if page.id == id {
|
if page.id == id {
|
||||||
debug!("shutting down layout for root page {:?}", id);
|
debug!("shutting down layout for root page {:?}", id);
|
||||||
*self.js_context.borrow_mut() = None;
|
*self.js_context.borrow_mut() = None;
|
||||||
shut_down_layout(&*page, (*self.js_runtime).ptr, exit_type);
|
shut_down_layout(&page, (*self.js_runtime).ptr, exit_type);
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -758,14 +843,15 @@ impl ScriptTask {
|
||||||
|
|
||||||
/// The entry point to document loading. Defines bindings, sets up the window and document
|
/// The entry point to document loading. Defines bindings, sets up the window and document
|
||||||
/// objects, parses HTML and CSS, and kicks off initial layout.
|
/// objects, parses HTML and CSS, and kicks off initial layout.
|
||||||
fn load(&self, pipeline_id: PipelineId,
|
fn load(&self, response: LoadResponse, incomplete: InProgressLoad) {
|
||||||
parent: Option<(PipelineId, SubpageId)>, load_data: LoadData) {
|
let final_url = response.metadata.final_url.clone();
|
||||||
let url = load_data.url.clone();
|
debug!("ScriptTask: loading {} on page {:?}", incomplete.url.serialize(), incomplete.pipeline_id);
|
||||||
debug!("ScriptTask: loading {} on page {:?}", url.serialize(), pipeline_id);
|
|
||||||
|
|
||||||
let borrowed_page = self.page.borrow_mut();
|
let root_page_exists = self.page.borrow().is_none();
|
||||||
|
assert!(incomplete.subpage_id.is_none() || root_page_exists);
|
||||||
|
|
||||||
let frame_element = parent.and_then(|(parent_id, subpage_id)| {
|
let frame_element = incomplete.subpage_id.and_then(|(parent_id, subpage_id)| {
|
||||||
|
let borrowed_page = self.root_page();
|
||||||
// In the case a parent id exists but the matching page
|
// In the case a parent id exists but the matching page
|
||||||
// cannot be found, this means the page exists in a different
|
// cannot be found, this means the page exists in a different
|
||||||
// script task (due to origin) so it shouldn't be returned.
|
// script task (due to origin) so it shouldn't be returned.
|
||||||
|
@ -785,71 +871,28 @@ impl ScriptTask {
|
||||||
})
|
})
|
||||||
}).root();
|
}).root();
|
||||||
|
|
||||||
let page = borrowed_page.find(pipeline_id).expect("ScriptTask: received a load
|
self.compositor.borrow_mut().set_ready_state(incomplete.pipeline_id, Loading);
|
||||||
message for a layout channel that is not associated with this script task. This
|
|
||||||
is a bug.");
|
|
||||||
|
|
||||||
// Are we reloading?
|
let last_modified = response.metadata.headers.as_ref().and_then(|headers| {
|
||||||
let reloading = match *page.url() {
|
|
||||||
Some((ref loaded, _)) => *loaded == url,
|
|
||||||
_ => false,
|
|
||||||
};
|
|
||||||
if reloading {
|
|
||||||
// Pull out the `needs_reflow` flag explicitly because `reflow` can ask for the page's
|
|
||||||
// URL, and we can't be holding a borrow on that URL (#4402).
|
|
||||||
let needed_reflow = match &mut *page.mut_url() {
|
|
||||||
&mut Some((_, ref mut needs_reflow)) => replace(needs_reflow, false),
|
|
||||||
_ => panic!("can't reload a page with no URL!")
|
|
||||||
};
|
|
||||||
if needed_reflow {
|
|
||||||
self.force_reflow(&*page);
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
let last_url = replace(&mut *page.mut_url(), None).map(|(last_url, _)| last_url);
|
|
||||||
|
|
||||||
let is_javascript = url.scheme.as_slice() == "javascript";
|
|
||||||
|
|
||||||
self.compositor.borrow_mut().set_ready_state(pipeline_id, Loading);
|
|
||||||
|
|
||||||
let (mut parser_input, final_url, last_modified) = if !is_javascript {
|
|
||||||
// Wait for the LoadResponse so that the parser knows the final URL.
|
|
||||||
let (input_chan, input_port) = channel();
|
|
||||||
self.resource_task.send(ControlMsg::Load(NetLoadData {
|
|
||||||
url: url,
|
|
||||||
method: load_data.method,
|
|
||||||
headers: Headers::new(),
|
|
||||||
preserved_headers: load_data.headers,
|
|
||||||
data: load_data.data,
|
|
||||||
cors: None,
|
|
||||||
consumer: input_chan,
|
|
||||||
})).unwrap();
|
|
||||||
|
|
||||||
let load_response = input_port.recv().unwrap();
|
|
||||||
|
|
||||||
let last_modified = load_response.metadata.headers.as_ref().and_then(|headers| {
|
|
||||||
headers.get().map(|&LastModified(ref tm)| tm.clone())
|
headers.get().map(|&LastModified(ref tm)| tm.clone())
|
||||||
});
|
});
|
||||||
|
|
||||||
let final_url = load_response.metadata.final_url.clone();
|
|
||||||
|
|
||||||
(Some(HTMLInput::InputUrl(load_response)), final_url, last_modified)
|
|
||||||
} else {
|
|
||||||
let doc_url = last_url.unwrap_or_else(|| {
|
|
||||||
Url::parse("about:blank").unwrap()
|
|
||||||
});
|
|
||||||
(None, doc_url, None)
|
|
||||||
};
|
|
||||||
|
|
||||||
// Store the final URL before we start parsing, so that DOM routines
|
|
||||||
// (e.g. HTMLImageElement::update_image) can resolve relative URLs
|
|
||||||
// correctly.
|
|
||||||
{
|
|
||||||
*page.mut_url() = Some((final_url.clone(), true));
|
|
||||||
}
|
|
||||||
|
|
||||||
let cx = self.js_context.borrow();
|
let cx = self.js_context.borrow();
|
||||||
let cx = cx.as_ref().unwrap();
|
let cx = cx.as_ref().unwrap();
|
||||||
|
|
||||||
|
let page = Rc::new(Page::new(incomplete.pipeline_id, incomplete.subpage_id.map(|p| p.1),
|
||||||
|
incomplete.layout_chan, incomplete.window_size,
|
||||||
|
self.resource_task.clone(), self.storage_task.clone(),
|
||||||
|
self.constellation_chan.clone(), cx.clone(),
|
||||||
|
self.devtools_chan.clone(), final_url.clone()));
|
||||||
|
if root_page_exists {
|
||||||
|
*self.page.borrow_mut() = Some(page.clone());
|
||||||
|
} else if let Some((parent, _)) = incomplete.subpage_id {
|
||||||
|
let parent_page = self.root_page();
|
||||||
|
parent_page.find(parent).expect("received load for subpage with missing parent");
|
||||||
|
parent_page.children.borrow_mut().push(page.clone());
|
||||||
|
}
|
||||||
|
|
||||||
// Create the window and document objects.
|
// Create the window and document objects.
|
||||||
let window = Window::new(cx.ptr,
|
let window = Window::new(cx.ptr,
|
||||||
page.clone(),
|
page.clone(),
|
||||||
|
@ -876,18 +919,21 @@ impl ScriptTask {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_javascript {
|
let is_javascript = incomplete.url.scheme.as_slice() == "javascript";
|
||||||
let evalstr = load_data.url.non_relative_scheme_data().unwrap();
|
let parse_input = if is_javascript {
|
||||||
|
let evalstr = incomplete.url.non_relative_scheme_data().unwrap();
|
||||||
let jsval = window.r().evaluate_js_on_global_with_result(evalstr);
|
let jsval = window.r().evaluate_js_on_global_with_result(evalstr);
|
||||||
let strval = FromJSValConvertible::from_jsval(self.get_cx(), jsval,
|
let strval = FromJSValConvertible::from_jsval(self.get_cx(), jsval,
|
||||||
StringificationBehavior::Empty);
|
StringificationBehavior::Empty);
|
||||||
parser_input = Some(HTMLInput::InputString(strval.unwrap_or("".to_owned())));
|
HTMLInput::InputString(strval.unwrap_or("".to_owned()))
|
||||||
|
} else {
|
||||||
|
HTMLInput::InputUrl(response)
|
||||||
};
|
};
|
||||||
|
|
||||||
parse_html(document.r(), parser_input.unwrap(), &final_url);
|
parse_html(document.r(), parse_input, &final_url);
|
||||||
|
|
||||||
document.r().set_ready_state(DocumentReadyState::Interactive);
|
document.r().set_ready_state(DocumentReadyState::Interactive);
|
||||||
self.compositor.borrow_mut().set_ready_state(pipeline_id, PerformingLayout);
|
self.compositor.borrow_mut().set_ready_state(incomplete.pipeline_id, PerformingLayout);
|
||||||
|
|
||||||
// Kick off the initial reflow of the page.
|
// Kick off the initial reflow of the page.
|
||||||
debug!("kicking off initial reflow of {:?}", final_url);
|
debug!("kicking off initial reflow of {:?}", final_url);
|
||||||
|
@ -898,7 +944,7 @@ impl ScriptTask {
|
||||||
{
|
{
|
||||||
// No more reflow required
|
// No more reflow required
|
||||||
let mut page_url = page.mut_url();
|
let mut page_url = page.mut_url();
|
||||||
*page_url = Some((final_url.clone(), false));
|
(*page_url).1 = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#the-end step 4
|
// https://html.spec.whatwg.org/multipage/#the-end step 4
|
||||||
|
@ -927,7 +973,7 @@ impl ScriptTask {
|
||||||
title: document.r().Title(),
|
title: document.r().Title(),
|
||||||
url: final_url
|
url: final_url
|
||||||
};
|
};
|
||||||
chan.send(DevtoolsControlMsg::NewGlobal(pipeline_id,
|
chan.send(DevtoolsControlMsg::NewGlobal(incomplete.pipeline_id,
|
||||||
self.devtools_sender.clone(),
|
self.devtools_sender.clone(),
|
||||||
page_info)).unwrap();
|
page_info)).unwrap();
|
||||||
}
|
}
|
||||||
|
@ -978,7 +1024,7 @@ impl ScriptTask {
|
||||||
for node in nodes.iter() {
|
for node in nodes.iter() {
|
||||||
let node_to_dirty = node::from_untrusted_node_address(self.js_runtime.ptr,
|
let node_to_dirty = node::from_untrusted_node_address(self.js_runtime.ptr,
|
||||||
*node).root();
|
*node).root();
|
||||||
let page = get_page(&*self.page.borrow(), pipeline_id);
|
let page = get_page(&self.root_page(), pipeline_id);
|
||||||
let frame = page.frame();
|
let frame = page.frame();
|
||||||
let document = frame.as_ref().unwrap().document.root();
|
let document = frame.as_ref().unwrap().document.root();
|
||||||
document.r().content_changed(node_to_dirty.r(),
|
document.r().content_changed(node_to_dirty.r(),
|
||||||
|
@ -989,7 +1035,7 @@ impl ScriptTask {
|
||||||
}
|
}
|
||||||
|
|
||||||
ClickEvent(_button, point) => {
|
ClickEvent(_button, point) => {
|
||||||
let page = get_page(&*self.page.borrow(), pipeline_id);
|
let page = get_page(&self.root_page(), pipeline_id);
|
||||||
let frame = page.frame();
|
let frame = page.frame();
|
||||||
let document = frame.as_ref().unwrap().document.root();
|
let document = frame.as_ref().unwrap().document.root();
|
||||||
document.r().handle_click_event(self.js_runtime.ptr, _button, point);
|
document.r().handle_click_event(self.js_runtime.ptr, _button, point);
|
||||||
|
@ -998,7 +1044,7 @@ impl ScriptTask {
|
||||||
MouseDownEvent(..) => {}
|
MouseDownEvent(..) => {}
|
||||||
MouseUpEvent(..) => {}
|
MouseUpEvent(..) => {}
|
||||||
MouseMoveEvent(point) => {
|
MouseMoveEvent(point) => {
|
||||||
let page = get_page(&*self.page.borrow(), pipeline_id);
|
let page = get_page(&self.root_page(), pipeline_id);
|
||||||
let frame = page.frame();
|
let frame = page.frame();
|
||||||
let document = frame.as_ref().unwrap().document.root();
|
let document = frame.as_ref().unwrap().document.root();
|
||||||
let mouse_over_targets = &mut *self.mouse_over_targets.borrow_mut();
|
let mouse_over_targets = &mut *self.mouse_over_targets.borrow_mut();
|
||||||
|
@ -1009,7 +1055,7 @@ impl ScriptTask {
|
||||||
}
|
}
|
||||||
|
|
||||||
KeyEvent(key, state, modifiers) => {
|
KeyEvent(key, state, modifiers) => {
|
||||||
let page = get_page(&*self.page.borrow(), pipeline_id);
|
let page = get_page(&self.root_page(), pipeline_id);
|
||||||
let frame = page.frame();
|
let frame = page.frame();
|
||||||
let document = frame.as_ref().unwrap().document.root();
|
let document = frame.as_ref().unwrap().document.root();
|
||||||
document.r().dispatch_key_event(
|
document.r().dispatch_key_event(
|
||||||
|
@ -1028,7 +1074,7 @@ impl ScriptTask {
|
||||||
/// The entry point for content to notify that a fragment url has been requested
|
/// The entry point for content to notify that a fragment url has been requested
|
||||||
/// for the given pipeline.
|
/// for the given pipeline.
|
||||||
fn trigger_fragment(&self, pipeline_id: PipelineId, fragment: String) {
|
fn trigger_fragment(&self, pipeline_id: PipelineId, fragment: String) {
|
||||||
let page = get_page(&*self.page.borrow(), pipeline_id);
|
let page = get_page(&self.root_page(), pipeline_id);
|
||||||
match page.find_fragment_node(fragment).root() {
|
match page.find_fragment_node(fragment).root() {
|
||||||
Some(node) => {
|
Some(node) => {
|
||||||
self.scroll_fragment_point(pipeline_id, node.r());
|
self.scroll_fragment_point(pipeline_id, node.r());
|
||||||
|
@ -1040,7 +1086,7 @@ impl ScriptTask {
|
||||||
|
|
||||||
fn handle_resize_event(&self, pipeline_id: PipelineId, new_size: WindowSizeData) {
|
fn handle_resize_event(&self, pipeline_id: PipelineId, new_size: WindowSizeData) {
|
||||||
let window = {
|
let window = {
|
||||||
let page = get_page(&*self.page.borrow(), pipeline_id);
|
let page = get_page(&self.root_page(), pipeline_id);
|
||||||
page.window_size.set(new_size);
|
page.window_size.set(new_size);
|
||||||
|
|
||||||
let frame = page.frame();
|
let frame = page.frame();
|
||||||
|
@ -1081,12 +1127,42 @@ impl ScriptTask {
|
||||||
|
|
||||||
fn handle_reflow_event(&self, pipeline_id: PipelineId) {
|
fn handle_reflow_event(&self, pipeline_id: PipelineId) {
|
||||||
debug!("script got reflow event");
|
debug!("script got reflow event");
|
||||||
let page = get_page(&*self.page.borrow(), pipeline_id);
|
let page = get_page(&self.root_page(), pipeline_id);
|
||||||
let frame = page.frame();
|
let frame = page.frame();
|
||||||
if frame.is_some() {
|
if frame.is_some() {
|
||||||
self.force_reflow(&*page);
|
self.force_reflow(&*page);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn start_page_load(&self, incomplete: InProgressLoad, mut load_data: LoadData) {
|
||||||
|
let id = incomplete.pipeline_id.clone();
|
||||||
|
let subpage = incomplete.subpage_id.clone().map(|p| p.1);
|
||||||
|
|
||||||
|
let script_chan = self.chan.clone();
|
||||||
|
let resource_task = self.resource_task.clone();
|
||||||
|
|
||||||
|
spawn_named(format!("fetch for {:?}", load_data.url), move || {
|
||||||
|
if load_data.url.scheme.as_slice() == "javascript" {
|
||||||
|
load_data.url = Url::parse("about:blank").unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let (input_chan, input_port) = channel();
|
||||||
|
resource_task.send(ControlMsg::Load(NetLoadData {
|
||||||
|
url: load_data.url,
|
||||||
|
method: load_data.method,
|
||||||
|
headers: Headers::new(),
|
||||||
|
preserved_headers: load_data.headers,
|
||||||
|
data: load_data.data,
|
||||||
|
cors: None,
|
||||||
|
consumer: input_chan,
|
||||||
|
})).unwrap();
|
||||||
|
|
||||||
|
let load_response = input_port.recv().unwrap();
|
||||||
|
script_chan.send(ScriptMsg::PageFetchComplete(id, subpage, load_response)).unwrap();
|
||||||
|
});
|
||||||
|
|
||||||
|
self.incomplete_loads.borrow_mut().push(incomplete);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Shuts down layout for the given page tree.
|
/// Shuts down layout for the given page tree.
|
||||||
|
|
|
@ -48,12 +48,13 @@ pub struct NewLayoutInfo {
|
||||||
pub new_pipeline_id: PipelineId,
|
pub new_pipeline_id: PipelineId,
|
||||||
pub subpage_id: SubpageId,
|
pub subpage_id: SubpageId,
|
||||||
pub layout_chan: Box<Any+Send>, // opaque reference to a LayoutChannel
|
pub layout_chan: Box<Any+Send>, // opaque reference to a LayoutChannel
|
||||||
|
pub load_data: LoadData,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Messages sent from the constellation to the script task
|
/// Messages sent from the constellation to the script task
|
||||||
pub enum ConstellationControlMsg {
|
pub enum ConstellationControlMsg {
|
||||||
/// Loads a new URL on the specified pipeline.
|
/// Reactivate an existing pipeline.
|
||||||
Load(PipelineId, Option<(PipelineId, SubpageId)>, LoadData),
|
Activate(PipelineId),
|
||||||
/// Gives a channel and ID to a layout task, as well as the ID of that layout's parent
|
/// Gives a channel and ID to a layout task, as well as the ID of that layout's parent
|
||||||
AttachLayout(NewLayoutInfo),
|
AttachLayout(NewLayoutInfo),
|
||||||
/// Window resized. Sends a DOM event eventually, but first we combine events.
|
/// Window resized. Sends a DOM event eventually, but first we combine events.
|
||||||
|
@ -111,7 +112,8 @@ pub trait ScriptTaskFactory {
|
||||||
storage_task: StorageTask,
|
storage_task: StorageTask,
|
||||||
image_cache_task: ImageCacheTask,
|
image_cache_task: ImageCacheTask,
|
||||||
devtools_chan: Option<DevtoolsControlChan>,
|
devtools_chan: Option<DevtoolsControlChan>,
|
||||||
window_size: WindowSizeData)
|
window_size: WindowSizeData,
|
||||||
|
load_data: LoadData)
|
||||||
where C: ScriptListener + Send;
|
where C: ScriptListener + Send;
|
||||||
fn create_layout_channel(_phantom: Option<&mut Self>) -> OpaqueScriptLayoutChannel;
|
fn create_layout_channel(_phantom: Option<&mut Self>) -> OpaqueScriptLayoutChannel;
|
||||||
fn clone_layout_channel(_phantom: Option<&mut Self>, pair: &OpaqueScriptLayoutChannel)
|
fn clone_layout_channel(_phantom: Option<&mut Self>, pair: &OpaqueScriptLayoutChannel)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue