diff options
author | Josh Matthews <josh@joshmatthews.net> | 2015-02-19 10:00:02 -0500 |
---|---|---|
committer | Josh Matthews <josh@joshmatthews.net> | 2015-03-03 16:25:40 -0500 |
commit | d9f04180a5d9146f4486ede6fabb9da638cccd41 (patch) | |
tree | e9cc19470b3d21bf8e012be90752f7999e1e3045 /components/script/script_task.rs | |
parent | 621150db1ca2d6ac9d4ba5d2709726dbc4139883 (diff) | |
download | servo-d9f04180a5d9146f4486ede6fabb9da638cccd41.tar.gz servo-d9f04180a5d9146f4486ede6fabb9da638cccd41.zip |
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.
Diffstat (limited to 'components/script/script_task.rs')
-rw-r--r-- | components/script/script_task.rs | 422 |
1 files changed, 249 insertions, 173 deletions
diff --git a/components/script/script_task.rs b/components/script/script_task.rs index 51361bd1436..28a2e6437c0 100644 --- a/components/script/script_task.rs +++ b/components/script/script_task.rs @@ -49,16 +49,17 @@ use msg::constellation_msg::{LoadData, PipelineId, SubpageId}; use msg::constellation_msg::{Failure, Msg, WindowSizeData, PipelineExitType}; use msg::constellation_msg::Msg as ConstellationMsg; 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::storage_task::StorageTask; use string_cache::Atom; use util::geometry::to_frac_px; use util::smallvec::SmallVec; 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 geom::Rect; use geom::point::Point2D; use hyper::header::{LastModified, Headers}; 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)); +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)] pub enum TimerSource { FromWindow(PipelineId), @@ -118,6 +145,8 @@ pub enum ScriptMsg { RunnableMsg(Box<Runnable+Send>), /// A DOM object's last pinned reference was removed (dispatched to all tasks). 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. @@ -175,11 +204,15 @@ impl Drop for StackRootTLS { /// FIXME: Rename to `Page`, following WebKit? pub struct ScriptTask { /// 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. image_cache_task: ImageCacheTask, /// A handle to the resource task. 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.) port: Receiver<ScriptMsg>, @@ -274,15 +307,14 @@ impl ScriptTaskFactory for ScriptTask { storage_task: StorageTask, image_cache_task: ImageCacheTask, devtools_chan: Option<DevtoolsControlChan>, - window_size: WindowSizeData) + window_size: WindowSizeData, + load_data: LoadData) where C: ScriptListener + Send + 'static { let ConstellationChan(const_chan) = constellation_chan.clone(); let (script_chan, script_port) = channel(); let layout_chan = LayoutChan(layout_chan.sender()); spawn_named_with_send_on_failure("ScriptTask", task_state::SCRIPT, move || { - let script_task = ScriptTask::new(id, - box compositor as Box<ScriptListener>, - layout_chan, + let script_task = ScriptTask::new(box compositor as Box<ScriptListener>, script_port, NonWorkerScriptChan(script_chan), control_chan, @@ -291,9 +323,13 @@ impl ScriptTaskFactory for ScriptTask { resource_task, storage_task, image_cache_task, - devtools_chan, - window_size); + devtools_chan); 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(); // 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 { /// Creates a new script task. - pub fn new(id: PipelineId, - compositor: Box<ScriptListener+'static>, - layout_chan: LayoutChan, + pub fn new(compositor: Box<ScriptListener+'static>, port: Receiver<ScriptMsg>, chan: NonWorkerScriptChan, control_chan: ScriptControlChan, @@ -323,8 +357,7 @@ impl ScriptTask { resource_task: ResourceTask, storage_task: StorageTask, img_cache_task: ImageCacheTask, - devtools_chan: Option<DevtoolsControlChan>, - window_size: WindowSizeData) + devtools_chan: Option<DevtoolsControlChan>) -> ScriptTask { let (js_runtime, js_context) = ScriptTask::new_rt_and_cx(); let wrap_for_same_compartment = wrap_for_same_compartment as @@ -348,19 +381,14 @@ impl ScriptTask { 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(); ScriptTask { - page: DOMRefCell::new(Rc::new(page)), + page: DOMRefCell::new(None), + incomplete_loads: DOMRefCell::new(vec!()), image_cache_task: img_cache_task, resource_task: resource_task, + storage_task: storage_task, port: port, chan: chan, @@ -417,6 +445,10 @@ impl ScriptTask { (js_runtime, js_context) } + fn root_page(&self) -> Rc<Page> { + self.page.borrow().as_ref().unwrap().clone() + } + pub fn get_cx(&self) -> *mut JSContext { (**self.js_context.borrow().as_ref().unwrap()).ptr } @@ -439,17 +471,19 @@ impl ScriptTask { let mut resizes = vec!(); { - let page = self.page.borrow_mut(); - for page in page.iter() { - // Only process a resize if layout is idle. - let layout_join_port = page.layout_join_port.borrow(); - if layout_join_port.is_none() { - let mut resize_event = page.resize_event.get(); - match resize_event.take() { - Some(size) => resizes.push((page.id, size)), - None => () + let page = self.page.borrow(); + if let Some(ref page) = page.as_ref() { + for page in page.iter() { + // Only process a resize if layout is idle. + let layout_join_port = page.layout_join_port.borrow(); + if layout_join_port.is_none() { + let mut resize_event = page.resize_event.get(); + match resize_event.take() { + Some(size) => resizes.push((page.id, size)), + None => () + } + page.resize_event.set(None); } - page.resize_event.set(None); } } } @@ -502,17 +536,10 @@ impl ScriptTask { self.handle_new_layout(new_layout_info); } MixedMessage::FromConstellation(ConstellationControlMsg::Resize(id, size)) => { - let page = self.page.borrow_mut(); - let page = page.find(id).expect("resize sent to nonexistent pipeline"); - page.resize_event.set(Some(size)); + self.handle_resize(id, size); } MixedMessage::FromConstellation(ConstellationControlMsg::Viewport(id, rect)) => { - let page = self.page.borrow_mut(); - 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); - } + self.handle_viewport(id, rect); } _ => { sequential.push(event); @@ -555,8 +582,8 @@ impl ScriptTask { match msg { ConstellationControlMsg::AttachLayout(_) => panic!("should have handled AttachLayout already"), - ConstellationControlMsg::Load(id, parent, load_data) => - self.load(id, parent, load_data), + ConstellationControlMsg::Activate(id) => + self.handle_activate(id), ConstellationControlMsg::SendEvent(id, event) => self.handle_event(id, event), ConstellationControlMsg::ReflowComplete(id, reflow_id) => @@ -598,57 +625,91 @@ impl ScriptTask { runnable.handler(), ScriptMsg::RefcountCleanup(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) { + let page = self.root_page(); match msg { 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) => - devtools::handle_get_root_node(&*self.page.borrow(), id, reply), + devtools::handle_get_root_node(&page, 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) => - 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) => - 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) => - 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) => - 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) { let NewLayoutInfo { old_pipeline_id, new_pipeline_id, subpage_id, - layout_chan + layout_chan, + load_data, } = 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 whose parent has a PipelineId which does not correspond to a pipeline in the script task's page tree. This is a bug."); - let new_page = { - let window_size = parent_page.window_size.get(); - Page::new(new_pipeline_id, Some(subpage_id), - LayoutChan(layout_chan.downcast_ref::<Sender<layout_interface::Msg>>().unwrap().clone()), - window_size, - parent_page.resource_task.clone(), - parent_page.storage_task.clone(), - 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)); + + let chan = layout_chan.downcast_ref::<Sender<layout_interface::Msg>>().unwrap(); + let layout_chan = LayoutChan(chan.clone()); + let new_load = InProgressLoad::new(new_pipeline_id, Some((old_pipeline_id, subpage_id)), + layout_chan, parent_page.window_size.get(), + load_data.url.clone()); + self.start_page_load(new_load, load_data); } /// Handles a timer that fired. 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 pipeline ID not associated with this script task. This is a bug."); let frame = page.frame(); @@ -658,7 +719,7 @@ impl ScriptTask { /// Handles freeze message 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 pipeline ID not associated with this script task. This is a bug."); let frame = page.frame(); @@ -668,7 +729,7 @@ impl ScriptTask { /// Handles thaw message 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 pipeline ID not associated with this script task. This is a bug."); let frame = page.frame(); @@ -676,10 +737,26 @@ impl ScriptTask { 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. fn handle_reflow_complete_msg(&self, pipeline_id: PipelineId, reflow_id: uint) { 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( "ScriptTask: received a load message for a layout channel that is not associated \ 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 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 with a page in the page tree. This is a bug."); page.window_size.set(new_size); match &mut *page.mut_url() { - &mut Some((_, ref mut needs_reflow)) => *needs_reflow = true, - &mut None => (), + &mut (_, ref mut needs_reflow) => *needs_reflow = true, } } @@ -724,20 +800,29 @@ impl ScriptTask { 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. 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. /// Returns true if the script task should shut down and false otherwise. fn handle_exit_pipeline_msg(&self, id: PipelineId, exit_type: PipelineExitType) -> bool { // If root is being exited, shut down all pages - let page = self.page.borrow_mut(); + let page = self.root_page(); if page.id == id { debug!("shutting down layout for root page {:?}", id); *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 } @@ -758,98 +843,56 @@ impl ScriptTask { /// The entry point to document loading. Defines bindings, sets up the window and document /// objects, parses HTML and CSS, and kicks off initial layout. - fn load(&self, pipeline_id: PipelineId, - parent: Option<(PipelineId, SubpageId)>, load_data: LoadData) { - let url = load_data.url.clone(); - debug!("ScriptTask: loading {} on page {:?}", url.serialize(), pipeline_id); - - let borrowed_page = self.page.borrow_mut(); - - let frame_element = parent.and_then(|(parent_id, subpage_id)| { - // In the case a parent id exists but the matching page - // cannot be found, this means the page exists in a different - // script task (due to origin) so it shouldn't be returned. - // TODO: window.parent will continue to return self in that - // case, which is wrong. We should be returning an object that - // denies access to most properties (per - // https://github.com/servo/servo/issues/3939#issuecomment-62287025). - borrowed_page.find(parent_id).and_then(|page| { - let doc = page.frame().as_ref().unwrap().document.root(); - let doc: JSRef<Node> = NodeCast::from_ref(doc.r()); - - doc.traverse_preorder() - .filter_map(HTMLIFrameElementCast::to_ref) - .find(|node| node.subpage_id() == Some(subpage_id)) - .map(ElementCast::from_ref) - .map(Temporary::from_rooted) - }) + fn load(&self, response: LoadResponse, incomplete: InProgressLoad) { + let final_url = response.metadata.final_url.clone(); + debug!("ScriptTask: loading {} on page {:?}", incomplete.url.serialize(), incomplete.pipeline_id); + + let root_page_exists = self.page.borrow().is_none(); + assert!(incomplete.subpage_id.is_none() || root_page_exists); + + 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 + // cannot be found, this means the page exists in a different + // script task (due to origin) so it shouldn't be returned. + // TODO: window.parent will continue to return self in that + // case, which is wrong. We should be returning an object that + // denies access to most properties (per + // https://github.com/servo/servo/issues/3939#issuecomment-62287025). + borrowed_page.find(parent_id).and_then(|page| { + let doc = page.frame().as_ref().unwrap().document.root(); + let doc: JSRef<Node> = NodeCast::from_ref(doc.r()); + + doc.traverse_preorder() + .filter_map(HTMLIFrameElementCast::to_ref) + .find(|node| node.subpage_id() == Some(subpage_id)) + .map(ElementCast::from_ref) + .map(Temporary::from_rooted) + }) }).root(); - let page = borrowed_page.find(pipeline_id).expect("ScriptTask: received a load - message for a layout channel that is not associated with this script task. This - is a bug."); - - // Are we reloading? - 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(); + self.compositor.borrow_mut().set_ready_state(incomplete.pipeline_id, Loading); - let last_modified = load_response.metadata.headers.as_ref().and_then(|headers| { - headers.get().map(|&LastModified(ref tm)| tm.clone()) - }); - - let final_url = load_response.metadata.final_url.clone(); + let last_modified = response.metadata.headers.as_ref().and_then(|headers| { + headers.get().map(|&LastModified(ref tm)| tm.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) - }; + let cx = self.js_context.borrow(); + let cx = cx.as_ref().unwrap(); - // 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 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()); } - let cx = self.js_context.borrow(); - let cx = cx.as_ref().unwrap(); // Create the window and document objects. let window = Window::new(cx.ptr, page.clone(), @@ -876,18 +919,21 @@ impl ScriptTask { }); } - if is_javascript { - let evalstr = load_data.url.non_relative_scheme_data().unwrap(); + let is_javascript = incomplete.url.scheme.as_slice() == "javascript"; + 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 strval = FromJSValConvertible::from_jsval(self.get_cx(), jsval, 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); - 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. debug!("kicking off initial reflow of {:?}", final_url); @@ -898,7 +944,7 @@ impl ScriptTask { { // No more reflow required 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 @@ -927,7 +973,7 @@ impl ScriptTask { title: document.r().Title(), url: final_url }; - chan.send(DevtoolsControlMsg::NewGlobal(pipeline_id, + chan.send(DevtoolsControlMsg::NewGlobal(incomplete.pipeline_id, self.devtools_sender.clone(), page_info)).unwrap(); } @@ -978,7 +1024,7 @@ impl ScriptTask { for node in nodes.iter() { let node_to_dirty = node::from_untrusted_node_address(self.js_runtime.ptr, *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 document = frame.as_ref().unwrap().document.root(); document.r().content_changed(node_to_dirty.r(), @@ -989,7 +1035,7 @@ impl ScriptTask { } 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 document = frame.as_ref().unwrap().document.root(); document.r().handle_click_event(self.js_runtime.ptr, _button, point); @@ -998,7 +1044,7 @@ impl ScriptTask { MouseDownEvent(..) => {} MouseUpEvent(..) => {} 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 document = frame.as_ref().unwrap().document.root(); let mouse_over_targets = &mut *self.mouse_over_targets.borrow_mut(); @@ -1009,7 +1055,7 @@ impl ScriptTask { } 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 document = frame.as_ref().unwrap().document.root(); 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 /// for the given pipeline. 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() { Some(node) => { 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) { 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); let frame = page.frame(); @@ -1081,12 +1127,42 @@ impl ScriptTask { fn handle_reflow_event(&self, pipeline_id: PipelineId) { 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(); if frame.is_some() { 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. |