diff options
-rw-r--r-- | components/compositing/compositor.rs | 1 | ||||
-rw-r--r-- | components/constellation/constellation.rs | 160 | ||||
-rw-r--r-- | components/constellation/pipeline.rs | 10 | ||||
-rw-r--r-- | components/net/http_loader.rs | 2 | ||||
-rw-r--r-- | components/script/document_loader.rs | 3 | ||||
-rw-r--r-- | components/script/dom/document.rs | 14 | ||||
-rw-r--r-- | components/script/dom/htmliframeelement.rs | 5 | ||||
-rw-r--r-- | components/script/script_thread.rs | 90 | ||||
-rw-r--r-- | components/script_traits/lib.rs | 40 | ||||
-rw-r--r-- | components/script_traits/script_msg.rs | 7 | ||||
-rw-r--r-- | tests/wpt/mozilla/tests/mozilla/mozbrowser/mozbrowserlocationchange_event.html | 4 | ||||
-rw-r--r-- | tests/wpt/web-platform-tests/html/browsers/history/the-location-interface/location_reload-iframe.html | 2 | ||||
-rw-r--r-- | tests/wpt/web-platform-tests/html/browsers/history/the-location-interface/location_reload.html | 13 |
13 files changed, 187 insertions, 164 deletions
diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index 55127bd64fe..dca6d253e56 100644 --- a/components/compositing/compositor.rs +++ b/components/compositing/compositor.rs @@ -739,6 +739,7 @@ impl<Window: WindowMethods> IOCompositor<Window> { fn set_frame_tree(&mut self, frame_tree: &SendableFrameTree, response_chan: IpcSender<()>) { + debug!("Setting the frame tree for pipeline {}", frame_tree.pipeline.id); if let Err(e) = response_chan.send(()) { warn!("Sending reponse to set frame tree failed ({}).", e); } diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index eed55cf3b25..99b0ac0b0a5 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -668,13 +668,16 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> // Create a new frame and update the internal bookkeeping. fn new_frame(&mut self, frame_id: FrameId, pipeline_id: PipelineId) { let frame = Frame::new(frame_id, pipeline_id); - - match self.pipelines.get_mut(&pipeline_id) { - Some(pipeline) => pipeline.is_mature = true, - None => return warn!("Pipeline {} matured after closure.", pipeline_id), - }; - self.frames.insert(frame_id, frame); + + // If a child frame, add it to the parent pipeline. + let parent_info = self.pipelines.get(&pipeline_id) + .and_then(|pipeline| pipeline.parent_info); + if let Some((parent_id, _)) = parent_info { + if let Some(parent) = self.pipelines.get_mut(&parent_id) { + parent.add_child(frame_id); + } + } } /// Handles loading pages, navigation, and granting access to the compositor @@ -777,6 +780,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> } FromCompositorMsg::IsReadyToSaveImage(pipeline_states) => { let is_ready = self.handle_is_ready_to_save_image(pipeline_states); + debug!("Ready to save image {:?}.", is_ready); if opts::get().is_running_problem_test { println!("got ready to save image query, result is {:?}", is_ready); } @@ -1022,8 +1026,31 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> self.shutting_down = true; // TODO: exit before the root frame is initialized? + debug!("Removing root frame."); let root_frame_id = self.root_frame_id; self.close_frame(root_frame_id, ExitPipelineMode::Normal); + + // Close any pending frames and pipelines + while let Some(pending) = self.pending_frames.pop() { + debug!("Removing pending frame {}.", pending.frame_id); + self.close_frame(pending.frame_id, ExitPipelineMode::Normal); + debug!("Removing pending pipeline {}.", pending.new_pipeline_id); + self.close_pipeline(pending.new_pipeline_id, ExitPipelineMode::Normal); + } + + // In case there are frames which weren't attached to the frame tree, we close them. + let frame_ids: Vec<FrameId> = self.frames.keys().cloned().collect(); + for frame_id in frame_ids { + debug!("Removing detached frame {}.", frame_id); + self.close_frame(frame_id, ExitPipelineMode::Normal); + } + + // In case there are pipelines which weren't attached to the pipeline tree, we close them. + let pipeline_ids: Vec<PipelineId> = self.pipelines.keys().cloned().collect(); + for pipeline_id in pipeline_ids { + debug!("Removing detached pipeline {}.", pipeline_id); + self.close_pipeline(pipeline_id, ExitPipelineMode::Normal); + } } fn handle_shutdown(&mut self) { @@ -1208,8 +1235,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> } fn handle_subframe_loaded(&mut self, pipeline_id: PipelineId) { - let parent_info = match self.pipelines.get(&pipeline_id) { - Some(pipeline) => pipeline.parent_info, + let (frame_id, parent_info) = match self.pipelines.get(&pipeline_id) { + Some(pipeline) => (pipeline.frame_id, pipeline.parent_info), None => return warn!("Pipeline {:?} loaded after closure.", pipeline_id), }; let subframe_parent_id = match parent_info { @@ -1217,8 +1244,9 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> None => return warn!("Pipeline {:?} has no parent.", pipeline_id), }; let msg = ConstellationControlMsg::DispatchFrameLoadEvent { - target: pipeline_id, + target: frame_id, parent: subframe_parent_id, + child: pipeline_id, }; let result = match self.pipelines.get(&subframe_parent_id) { Some(pipeline) => pipeline.script_chan.send(msg), @@ -1392,13 +1420,19 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> // requested change so it can update its internal state. // // If replace is true, the current entry is replaced instead of a new entry being added. - let parent_info = self.pipelines.get(&source_id).and_then(|source| source.parent_info); + let (frame_id, parent_info) = match self.pipelines.get(&source_id) { + Some(pipeline) => (pipeline.frame_id, pipeline.parent_info), + None => { + warn!("Pipeline {:?} loaded after closure.", source_id); + return None; + } + }; match parent_info { Some((parent_pipeline_id, _)) => { self.handle_load_start_msg(source_id); // Message the constellation to find the script thread for this iframe // and issue an iframe load through there. - let msg = ConstellationControlMsg::Navigate(parent_pipeline_id, source_id, load_data, replace); + let msg = ConstellationControlMsg::Navigate(parent_pipeline_id, frame_id, load_data, replace); let result = match self.pipelines.get(&parent_pipeline_id) { Some(parent_pipeline) => parent_pipeline.script_chan.send(msg), None => { @@ -1586,16 +1620,17 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> fn handle_mozbrowser_event_msg(&mut self, parent_pipeline_id: PipelineId, - pipeline_id: Option<PipelineId>, + pipeline_id: PipelineId, event: MozBrowserEvent) { assert!(PREFS.is_mozbrowser_enabled()); + let frame_id = self.pipelines.get(&pipeline_id).map(|pipeline| pipeline.frame_id); // Find the script channel for the given parent pipeline, // and pass the event to that script thread. // If the pipeline lookup fails, it is because we have torn down the pipeline, // so it is reasonable to silently ignore the event. match self.pipelines.get(&parent_pipeline_id) { - Some(pipeline) => pipeline.trigger_mozbrowser_event(pipeline_id, event), + Some(pipeline) => pipeline.trigger_mozbrowser_event(frame_id, event), None => warn!("Pipeline {:?} handling mozbrowser event after closure.", parent_pipeline_id), } } @@ -1626,8 +1661,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> } fn focus_parent_pipeline(&mut self, pipeline_id: PipelineId) { - let parent_info = match self.pipelines.get(&pipeline_id) { - Some(pipeline) => pipeline.parent_info, + let (frame_id, parent_info) = match self.pipelines.get(&pipeline_id) { + Some(pipeline) => (pipeline.frame_id, pipeline.parent_info), None => return warn!("Pipeline {:?} focus parent after closure.", pipeline_id), }; let (parent_pipeline_id, _) = match parent_info { @@ -1637,7 +1672,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> // Send a message to the parent of the provided pipeline (if it exists) // telling it to mark the iframe element as focused. - let msg = ConstellationControlMsg::FocusIFrame(parent_pipeline_id, pipeline_id); + let msg = ConstellationControlMsg::FocusIFrame(parent_pipeline_id, frame_id); let result = match self.pipelines.get(&parent_pipeline_id) { Some(pipeline) => pipeline.script_chan.send(msg), None => return warn!("Pipeline {:?} focus after closure.", parent_pipeline_id), @@ -1691,10 +1726,13 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> } fn handle_visibility_change_complete(&mut self, pipeline_id: PipelineId, visibility: bool) { - let parent_pipeline_info = self.pipelines.get(&pipeline_id).and_then(|source| source.parent_info); + let (frame_id, parent_pipeline_info) = match self.pipelines.get(&pipeline_id) { + None => return warn!("Visibity change for closed pipeline {:?}.", pipeline_id), + Some(pipeline) => (pipeline.frame_id, pipeline.parent_info), + }; if let Some((parent_pipeline_id, _)) = parent_pipeline_info { let visibility_msg = ConstellationControlMsg::NotifyVisibilityChange(parent_pipeline_id, - pipeline_id, + frame_id, visibility); let result = match self.pipelines.get(&parent_pipeline_id) { None => return warn!("Parent pipeline {:?} closed", parent_pipeline_id), @@ -1856,7 +1894,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> // This makes things like contentDocument work correctly. if let Some((parent_pipeline_id, _)) = pipeline_info { let msg = ConstellationControlMsg::UpdatePipelineId(parent_pipeline_id, - prev_pipeline_id, + frame_id, next_pipeline_id); let result = match self.pipelines.get(&parent_pipeline_id) { None => return warn!("Pipeline {:?} child traversed after closure.", parent_pipeline_id), @@ -1875,8 +1913,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> fn get_top_level_frame_for_pipeline(&self, pipeline_id: Option<PipelineId>) -> FrameId { if PREFS.is_mozbrowser_enabled() { pipeline_id.and_then(|id| self.get_mozbrowser_ancestor_info(id)) - .and_then(|pipeline_info| self.pipelines.get(&pipeline_info.1)) - .map(|pipeline| pipeline.frame_id) + .map(|(_, mozbrowser_iframe_id)| mozbrowser_iframe_id) .unwrap_or(self.root_frame_id) } else { // If mozbrowser is not enabled, the root frame is the only top-level frame @@ -1910,11 +1947,6 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> } if self.frames.contains_key(&frame_change.frame_id) { - // Mature the new pipeline, and return frames evicted from history. - if let Some(ref mut pipeline) = self.pipelines.get_mut(&frame_change.new_pipeline_id) { - pipeline.is_mature = true; - } - if frame_change.replace { let evicted = self.frames.get_mut(&frame_change.frame_id).map(|frame| { frame.replace_current(frame_change.new_pipeline_id) @@ -1930,16 +1962,6 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> } else { // The new pipeline is in a new frame with no history self.new_frame(frame_change.frame_id, frame_change.new_pipeline_id); - - // If a child frame, add it to the parent pipeline. Otherwise - // it must surely be the root frame being created! - let parent_info = self.pipelines.get(&frame_change.new_pipeline_id) - .and_then(|pipeline| pipeline.parent_info); - if let Some((parent_id, _)) = parent_info { - if let Some(parent) = self.pipelines.get_mut(&parent_id) { - parent.add_child(frame_change.frame_id); - } - } } if !frame_change.replace { @@ -1958,49 +1980,25 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> fn handle_activate_document_msg(&mut self, pipeline_id: PipelineId) { debug!("Document ready to activate {:?}", pipeline_id); - if let Some(ref child_pipeline) = self.pipelines.get(&pipeline_id) { - if let Some(ref parent_info) = child_pipeline.parent_info { - if let Some(parent_pipeline) = self.pipelines.get(&parent_info.0) { - let _ = parent_pipeline.script_chan - .send(ConstellationControlMsg::FramedContentChanged( - parent_info.0, - pipeline_id)); + // Notify the parent (if there is one). + if let Some(pipeline) = self.pipelines.get(&pipeline_id) { + if let Some((parent_pipeline_id, _)) = pipeline.parent_info { + if let Some(parent_pipeline) = self.pipelines.get(&parent_pipeline_id) { + let msg = ConstellationControlMsg::FramedContentChanged(parent_pipeline_id, pipeline.frame_id); + let _ = parent_pipeline.script_chan.send(msg); } } } - // If this pipeline is already part of the current frame tree, - // we don't need to do anything. - if self.pipeline_is_in_current_frame(pipeline_id) { - return; - } - // Find the pending frame change whose new pipeline id is pipeline_id. - // If it is found, mark this pending frame as ready to be enabled. let pending_index = self.pending_frames.iter().rposition(|frame_change| { frame_change.new_pipeline_id == pipeline_id }); + + // If it is found, remove it from the pending frames, and make it + // the active document of its frame. if let Some(pending_index) = pending_index { - self.pending_frames[pending_index].document_ready = true; - } - - // This is a bit complex. We need to loop through pending frames and find - // ones that can be swapped. A frame can be swapped (enabled) once it is - // ready to layout (has document_ready set), and also is mature - // (i.e. the pipeline it is replacing has been enabled and now has a frame). - // The outer loop is required because any time a pipeline is enabled, that - // may affect whether other pending frames are now able to be enabled. On the - // other hand, if no frames can be enabled after looping through all pending - // frames, we can safely exit the loop, knowing that we will need to wait on - // a dependent pipeline to be ready to paint. - while let Some(valid_frame_change) = self.pending_frames.iter().rposition(|frame_change| { - let frame_is_mature = frame_change.old_pipeline_id - .and_then(|old_pipeline_id| self.pipelines.get(&old_pipeline_id)) - .map(|old_pipeline| old_pipeline.is_mature) - .unwrap_or(true); - frame_change.document_ready && frame_is_mature - }) { - let frame_change = self.pending_frames.swap_remove(valid_frame_change); + let frame_change = self.pending_frames.swap_remove(pending_index); self.add_or_replace_pipeline_in_frame_tree(frame_change); } } @@ -2100,6 +2098,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> // screenshot can safely be written. for frame in self.current_frame_tree_iter(self.root_frame_id) { let pipeline_id = frame.current.pipeline_id; + debug!("Checking readiness of frame {}, pipeline {}.", frame.id, pipeline_id); let pipeline = match self.pipelines.get(&pipeline_id) { None => { @@ -2265,7 +2264,9 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> self.close_frame(*child_frame, exit_mode); } - let pipeline = match self.pipelines.get_mut(&pipeline_id) { + // Note, we don't remove the pipeline now, we wait for the message to come back from + // the pipeline. + let pipeline = match self.pipelines.get(&pipeline_id) { Some(pipeline) => pipeline, None => return warn!("Closing pipeline {:?} twice.", pipeline_id), }; @@ -2337,6 +2338,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> // Note that this function can panic, due to ipc-channel creation failure. // avoiding this panic would require a mechanism for dealing // with low-resource scenarios. + debug!("Sending frame tree for frame {}.", self.root_frame_id); if let Some(frame_tree) = self.frame_to_sendable(self.root_frame_id) { let (chan, port) = ipc::channel().expect("Failed to create IPC channel!"); self.compositor_proxy.send(ToCompositorMsg::SetFrameTree(frame_tree, @@ -2350,12 +2352,12 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> /// For a given pipeline, determine the mozbrowser iframe that transitively contains /// it. There could be arbitrary levels of nested iframes in between them. - fn get_mozbrowser_ancestor_info(&self, original_pipeline_id: PipelineId) -> Option<(PipelineId, PipelineId)> { + fn get_mozbrowser_ancestor_info(&self, original_pipeline_id: PipelineId) -> Option<(PipelineId, FrameId)> { let mut pipeline_id = original_pipeline_id; loop { match self.pipelines.get(&pipeline_id) { Some(pipeline) => match pipeline.parent_info { - Some((parent_id, FrameType::MozBrowserIFrame)) => return Some((parent_id, pipeline_id)), + Some((parent_id, FrameType::MozBrowserIFrame)) => return Some((parent_id, pipeline.frame_id)), Some((parent_id, _)) => pipeline_id = parent_id, None => return None, }, @@ -2378,14 +2380,12 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> }; // If this is a mozbrowser iframe, then send the event with new url - if let Some((ancestor_id, mozbrowser_iframe_id)) = self.get_mozbrowser_ancestor_info(pipeline_id) { + if let Some((ancestor_id, mozbrowser_frame_id)) = self.get_mozbrowser_ancestor_info(pipeline_id) { if let Some(ancestor) = self.pipelines.get(&ancestor_id) { - if let Some(pipeline) = self.pipelines.get(&mozbrowser_iframe_id) { - let can_go_forward = !self.joint_session_future(pipeline.frame_id).is_empty(); - let can_go_back = !self.joint_session_past(pipeline.frame_id).is_empty(); - let event = MozBrowserEvent::LocationChange(url, can_go_back, can_go_forward); - ancestor.trigger_mozbrowser_event(Some(mozbrowser_iframe_id), event); - } + let can_go_forward = !self.joint_session_future(mozbrowser_frame_id).is_empty(); + let can_go_back = !self.joint_session_past(mozbrowser_frame_id).is_empty(); + let event = MozBrowserEvent::LocationChange(url, can_go_back, can_go_forward); + ancestor.trigger_mozbrowser_event(Some(mozbrowser_frame_id), event); } } } diff --git a/components/constellation/pipeline.rs b/components/constellation/pipeline.rs index 66de70a9737..d2098c58447 100644 --- a/components/constellation/pipeline.rs +++ b/components/constellation/pipeline.rs @@ -69,9 +69,6 @@ pub struct Pipeline { /// Whether this pipeline should be treated as visible for the purposes of scheduling and /// resource management. pub visible: bool, - /// Whether this pipeline is has matured or not. - /// A pipeline is considered mature when it has an associated frame. - pub is_mature: bool, } /// Initial setup data needed to construct a pipeline. @@ -152,6 +149,7 @@ impl Pipeline { let new_layout_info = NewLayoutInfo { parent_pipeline_id: parent_pipeline_id, new_pipeline_id: state.id, + frame_id: state.frame_id, frame_type: frame_type, load_data: state.load_data.clone(), pipeline_port: pipeline_port, @@ -203,6 +201,7 @@ impl Pipeline { let unprivileged_pipeline_content = UnprivilegedPipelineContent { id: state.id, + frame_id: state.frame_id, parent_info: state.parent_info, constellation_chan: state.constellation_chan, scheduler_chan: state.scheduler_chan, @@ -281,7 +280,6 @@ impl Pipeline { running_animations: false, visible: visible, is_private: is_private, - is_mature: false, } } @@ -348,7 +346,7 @@ impl Pipeline { } pub fn trigger_mozbrowser_event(&self, - child_id: Option<PipelineId>, + child_id: Option<FrameId>, event: MozBrowserEvent) { assert!(PREFS.is_mozbrowser_enabled()); @@ -380,6 +378,7 @@ impl Pipeline { #[derive(Deserialize, Serialize)] pub struct UnprivilegedPipelineContent { id: PipelineId, + frame_id: FrameId, parent_info: Option<(PipelineId, FrameType)>, constellation_chan: IpcSender<ScriptMsg>, layout_to_constellation_chan: IpcSender<LayoutMsg>, @@ -414,6 +413,7 @@ impl UnprivilegedPipelineContent { { let layout_pair = STF::create(InitialScriptState { id: self.id, + frame_id: self.frame_id, parent_info: self.parent_info, control_chan: self.script_chan.clone(), control_port: self.script_port, diff --git a/components/net/http_loader.rs b/components/net/http_loader.rs index 885ce794b6d..5b15166b9dd 100644 --- a/components/net/http_loader.rs +++ b/components/net/http_loader.rs @@ -784,7 +784,7 @@ pub fn obtain_response<A>(request_factory: &HttpRequestFactory<R=A>, } if log_enabled!(log::LogLevel::Info) { - info!("{}", method); + info!("{} {}", method, connection_url); for header in headers.iter() { info!(" - {}", header); } diff --git a/components/script/document_loader.rs b/components/script/document_loader.rs index 837660109c3..04b9e258573 100644 --- a/components/script/document_loader.rs +++ b/components/script/document_loader.rs @@ -94,6 +94,7 @@ impl DocumentLoader { pub fn new_with_threads(resource_threads: ResourceThreads, initial_load: Option<Url>) -> DocumentLoader { + debug!("Initial blocking load {:?}.", initial_load); let initial_loads = initial_load.into_iter().map(LoadType::PageSource).collect(); DocumentLoader { @@ -105,6 +106,7 @@ impl DocumentLoader { /// Add a load to the list of blocking loads. fn add_blocking_load(&mut self, load: LoadType) { + debug!("Adding blocking load {:?} ({}).", load, self.blocking_loads.len()); self.blocking_loads.push(load); } @@ -119,6 +121,7 @@ impl DocumentLoader { /// Mark an in-progress network request complete. pub fn finish_load(&mut self, load: &LoadType) { + debug!("Removing blocking load {:?} ({}).", load, self.blocking_loads.len()); let idx = self.blocking_loads.iter().position(|unfinished| *unfinished == *load); self.blocking_loads.remove(idx.expect(&format!("unknown completed load {:?}", load))); } diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 2728bc757fb..91824f0e354 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -96,8 +96,8 @@ use ipc_channel::ipc::{self, IpcSender}; use js::jsapi::{JSContext, JSObject, JSRuntime}; use js::jsapi::JS_GetRuntime; use msg::constellation_msg::{ALT, CONTROL, SHIFT, SUPER}; +use msg::constellation_msg::{FrameId, ReferrerPolicy}; use msg::constellation_msg::{Key, KeyModifiers, KeyState}; -use msg::constellation_msg::{PipelineId, ReferrerPolicy}; use net_traits::{FetchResponseMsg, IpcSend}; use net_traits::CookieSource::NonHTTP; use net_traits::CoreResourceMsg::{GetCookiesForUrl, SetCookiesForUrl}; @@ -1400,7 +1400,7 @@ impl Document { if let Some((parent_pipeline_id, _)) = self.window.parent_info() { let global_scope = self.window.upcast::<GlobalScope>(); let event = ConstellationMsg::MozBrowserEvent(parent_pipeline_id, - Some(global_scope.pipeline_id()), + global_scope.pipeline_id(), event); global_scope.constellation_chan().send(event).unwrap(); } @@ -1513,8 +1513,10 @@ impl Document { } } - let loader = self.loader.borrow(); - if !loader.is_blocked() && !loader.events_inhibited() { + if !self.loader.borrow().is_blocked() && !self.loader.borrow().events_inhibited() { + // Schedule a task to fire a "load" event (if no blocking loads have arrived in the mean time) + // NOTE: we can end up executing this code more than once, in case more blocking loads arrive. + debug!("Document loads are complete."); let win = self.window(); let msg = MainThreadScriptMsg::DocumentLoadsComplete( win.upcast::<GlobalScope>().pipeline_id()); @@ -1630,11 +1632,11 @@ impl Document { } /// Find an iframe element in the document. - pub fn find_iframe(&self, pipeline: PipelineId) -> Option<Root<HTMLIFrameElement>> { + pub fn find_iframe(&self, frame_id: FrameId) -> Option<Root<HTMLIFrameElement>> { self.upcast::<Node>() .traverse_preorder() .filter_map(Root::downcast::<HTMLIFrameElement>) - .find(|node| node.pipeline_id() == Some(pipeline)) + .find(|node| node.frame_id() == frame_id) } pub fn get_dom_loading(&self) -> u64 { diff --git a/components/script/dom/htmliframeelement.rs b/components/script/dom/htmliframeelement.rs index fef2cd70d85..e9ccf61cc7a 100644 --- a/components/script/dom/htmliframeelement.rs +++ b/components/script/dom/htmliframeelement.rs @@ -207,6 +207,11 @@ impl HTMLIFrameElement { self.pipeline_id.get() } + #[inline] + pub fn frame_id(&self) -> FrameId { + self.frame_id + } + pub fn change_visibility_status(&self, visibility: bool) { if self.visibility.get() != visibility { self.visibility.set(visibility); diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index c460472ac13..d48552f14f6 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -72,7 +72,7 @@ use js::jsval::UndefinedValue; use js::rust::Runtime; use layout_wrapper::ServoLayoutNode; use mem::heap_size_of_self_and_children; -use msg::constellation_msg::{FrameType, PipelineId, PipelineNamespace, ReferrerPolicy}; +use msg::constellation_msg::{FrameId, FrameType, PipelineId, PipelineNamespace, ReferrerPolicy}; use net_traits::{CoreResourceMsg, IpcSend, Metadata, ResourceThreads}; use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheResult, ImageCacheThread}; use net_traits::request::{CredentialsMode, Destination, RequestInit}; @@ -135,6 +135,8 @@ pub unsafe fn trace_thread(tr: *mut JSTracer) { struct InProgressLoad { /// The pipeline which requested this load. pipeline_id: PipelineId, + /// The frame being loaded into. + frame_id: FrameId, /// The parent pipeline and frame type associated with this load, if any. parent_info: Option<(PipelineId, FrameType)>, /// The current window size associated with this pipeline. @@ -154,12 +156,14 @@ struct InProgressLoad { impl InProgressLoad { /// Create a new InProgressLoad object. fn new(id: PipelineId, + frame_id: FrameId, parent_info: Option<(PipelineId, FrameType)>, layout_chan: Sender<message::Msg>, window_size: Option<WindowSizeData>, url: Url) -> InProgressLoad { InProgressLoad { pipeline_id: id, + frame_id: frame_id, parent_info: parent_info, layout_chan: layout_chan, window_size: window_size, @@ -452,15 +456,15 @@ impl ScriptThreadFactory for ScriptThread { let (sender, receiver) = channel(); let layout_chan = sender.clone(); - let pipeline_id = state.id; thread::spawn_named(format!("ScriptThread {:?}", state.id), move || { thread_state::initialize(thread_state::SCRIPT); - PipelineId::install(pipeline_id); + PipelineId::install(state.id); PipelineNamespace::install(state.pipeline_namespace_id); let roots = RootCollection::new(); let _stack_roots_tls = StackRootTLS::new(&roots); let id = state.id; + let frame_id = state.frame_id; let parent_info = state.parent_info; let mem_profiler_chan = state.mem_profiler_chan.clone(); let window_size = state.window_size; @@ -474,7 +478,7 @@ impl ScriptThreadFactory for ScriptThread { let mut failsafe = ScriptMemoryFailsafe::new(&script_thread); - let new_load = InProgressLoad::new(id, parent_info, layout_chan, window_size, + let new_load = InProgressLoad::new(id, frame_id, parent_info, layout_chan, window_size, load_data.url.clone()); script_thread.start_page_load(new_load, load_data); @@ -888,8 +892,8 @@ impl ScriptThread { fn handle_msg_from_constellation(&self, msg: ConstellationControlMsg) { match msg { - ConstellationControlMsg::Navigate(parent_pipeline_id, pipeline_id, load_data, replace) => - self.handle_navigate(parent_pipeline_id, Some(pipeline_id), load_data, replace), + ConstellationControlMsg::Navigate(parent_pipeline_id, frame_id, load_data, replace) => + self.handle_navigate(parent_pipeline_id, Some(frame_id), load_data, replace), ConstellationControlMsg::SendEvent(id, event) => self.handle_event(id, event), ConstellationControlMsg::ResizeInactive(id, new_size) => @@ -902,22 +906,22 @@ impl ScriptThread { self.handle_thaw_msg(pipeline_id), ConstellationControlMsg::ChangeFrameVisibilityStatus(pipeline_id, visible) => self.handle_visibility_change_msg(pipeline_id, visible), - ConstellationControlMsg::NotifyVisibilityChange(parent_pipeline_id, pipeline_id, visible) => - self.handle_visibility_change_complete_msg(parent_pipeline_id, pipeline_id, visible), + ConstellationControlMsg::NotifyVisibilityChange(parent_pipeline_id, frame_id, visible) => + self.handle_visibility_change_complete_msg(parent_pipeline_id, frame_id, visible), ConstellationControlMsg::MozBrowserEvent(parent_pipeline_id, - pipeline_id, + frame_id, event) => self.handle_mozbrowser_event_msg(parent_pipeline_id, - pipeline_id, + frame_id, event), ConstellationControlMsg::UpdatePipelineId(parent_pipeline_id, - old_pipeline_id, + frame_id, new_pipeline_id) => self.handle_update_pipeline_id(parent_pipeline_id, - old_pipeline_id, + frame_id, new_pipeline_id), - ConstellationControlMsg::FocusIFrame(parent_pipeline_id, pipeline_id) => - self.handle_focus_iframe_msg(parent_pipeline_id, pipeline_id), + ConstellationControlMsg::FocusIFrame(parent_pipeline_id, frame_id) => + self.handle_focus_iframe_msg(parent_pipeline_id, frame_id), ConstellationControlMsg::WebDriverScriptCommand(pipeline_id, msg) => self.handle_webdriver_msg(pipeline_id, msg), ConstellationControlMsg::TickAllAnimations(pipeline_id) => @@ -927,10 +931,10 @@ impl ScriptThread { ConstellationControlMsg::WebFontLoaded(pipeline_id) => self.handle_web_font_loaded(pipeline_id), ConstellationControlMsg::DispatchFrameLoadEvent { - target: pipeline_id, parent: parent_pipeline_id } => - self.handle_frame_load_event(parent_pipeline_id, pipeline_id), - ConstellationControlMsg::FramedContentChanged(parent_pipeline_id, pipeline_id) => - self.handle_framed_content_changed(parent_pipeline_id, pipeline_id), + target: frame_id, parent: parent_id, child: child_id } => + self.handle_frame_load_event(parent_id, frame_id, child_id), + ConstellationControlMsg::FramedContentChanged(parent_pipeline_id, frame_id) => + self.handle_framed_content_changed(parent_pipeline_id, frame_id), ConstellationControlMsg::ReportCSSError(pipeline_id, filename, line, column, msg) => self.handle_css_error_reporting(pipeline_id, filename, line, column, msg), ConstellationControlMsg::Reload(pipeline_id) => @@ -1139,6 +1143,7 @@ impl ScriptThread { let NewLayoutInfo { parent_pipeline_id, new_pipeline_id, + frame_id, frame_type, load_data, pipeline_port, @@ -1175,7 +1180,7 @@ impl ScriptThread { .unwrap(); // Kick off the fetch for the new resource. - let new_load = InProgressLoad::new(new_pipeline_id, Some((parent_pipeline_id, frame_type)), + let new_load = InProgressLoad::new(new_pipeline_id, frame_id, Some((parent_pipeline_id, frame_type)), layout_chan, parent_window.window_size(), load_data.url.clone()); self.start_page_load(new_load, load_data); @@ -1187,12 +1192,15 @@ impl ScriptThread { None => return warn!("Message sent to closed pipeline {}.", pipeline), }; if doc.loader().is_blocked() { + debug!("Script thread got loads complete while loader is blocked."); return; } doc.mut_loader().inhibit_events(); // https://html.spec.whatwg.org/multipage/#the-end step 7 + // Schedule a task to fire a "load" event (if no blocking loads have arrived in the mean time) + // NOTE: we can end up executing this code more than once, in case more blocking loads arrive. let handler = box DocumentProgressHandler::new(Trusted::new(&doc)); self.dom_manipulation_task_source.queue(handler, doc.window().upcast()).unwrap(); @@ -1259,7 +1267,7 @@ impl ScriptThread { } /// Updates iframe element after a change in visibility - fn handle_visibility_change_complete_msg(&self, parent_pipeline_id: PipelineId, id: PipelineId, visible: bool) { + fn handle_visibility_change_complete_msg(&self, parent_pipeline_id: PipelineId, id: FrameId, visible: bool) { if let Some(root_context) = self.browsing_context.get() { if let Some(ref inner_context) = root_context.find(parent_pipeline_id) { if let Some(iframe) = inner_context.active_document().find_iframe(id) { @@ -1328,12 +1336,12 @@ impl ScriptThread { fn handle_focus_iframe_msg(&self, parent_pipeline_id: PipelineId, - pipeline_id: PipelineId) { + frame_id: FrameId) { let borrowed_context = self.root_browsing_context(); let context = borrowed_context.find(parent_pipeline_id).unwrap(); let doc = context.active_document(); - let frame_element = doc.find_iframe(pipeline_id); + let frame_element = doc.find_iframe(frame_id); if let Some(ref frame_element) = frame_element { doc.begin_focus_transaction(); @@ -1344,11 +1352,11 @@ impl ScriptThread { fn handle_framed_content_changed(&self, parent_pipeline_id: PipelineId, - pipeline_id: PipelineId) { + frame_id: FrameId) { let root_context = self.root_browsing_context(); let context = root_context.find(parent_pipeline_id).unwrap(); let doc = context.active_document(); - let frame_element = doc.find_iframe(pipeline_id); + let frame_element = doc.find_iframe(frame_id); if let Some(ref frame_element) = frame_element { frame_element.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage); let window = context.active_window(); @@ -1362,14 +1370,14 @@ impl ScriptThread { /// https://developer.mozilla.org/en-US/docs/Web/Events/mozbrowserloadstart fn handle_mozbrowser_event_msg(&self, parent_pipeline_id: PipelineId, - pipeline_id: Option<PipelineId>, + frame_id: Option<FrameId>, event: MozBrowserEvent) { match self.root_browsing_context().find(parent_pipeline_id) { None => warn!("Mozbrowser event after pipeline {:?} closed.", parent_pipeline_id), - Some(context) => match pipeline_id { + Some(context) => match frame_id { None => context.active_window().dispatch_mozbrowser_event(event), - Some(pipeline_id) => match context.active_document().find_iframe(pipeline_id) { - None => warn!("Mozbrowser event after iframe {:?}/{:?} closed.", parent_pipeline_id, pipeline_id), + Some(frame_id) => match context.active_document().find_iframe(frame_id) { + None => warn!("Mozbrowser event after iframe {:?}/{:?} closed.", parent_pipeline_id, frame_id), Some(frame_element) => frame_element.dispatch_mozbrowser_event(event), }, }, @@ -1378,13 +1386,13 @@ impl ScriptThread { fn handle_update_pipeline_id(&self, parent_pipeline_id: PipelineId, - old_pipeline_id: PipelineId, + frame_id: FrameId, new_pipeline_id: PipelineId) { let borrowed_context = self.root_browsing_context(); let frame_element = borrowed_context.find(parent_pipeline_id).and_then(|context| { let doc = context.active_document(); - doc.find_iframe(old_pipeline_id) + doc.find_iframe(frame_id) }); frame_element.unwrap().update_pipeline_id(new_pipeline_id); @@ -1567,13 +1575,15 @@ impl ScriptThread { } /// Notify the containing document of a child frame that has completed loading. - fn handle_frame_load_event(&self, parent_pipeline_id: PipelineId, id: PipelineId) { - let document = match self.root_browsing_context().find(parent_pipeline_id) { + fn handle_frame_load_event(&self, parent_id: PipelineId, frame_id: FrameId, child_id: PipelineId) { + let document = match self.root_browsing_context().find(parent_id) { Some(browsing_context) => browsing_context.active_document(), - None => return warn!("Message sent to closed pipeline {}.", parent_pipeline_id), + None => return warn!("Message sent to closed pipeline {}.", parent_id), }; - if let Some(iframe) = document.find_iframe(id) { - iframe.iframe_load_event_steps(id); + if let Some(iframe) = document.find_iframe(frame_id) { + if iframe.pipeline_id() == Some(child_id) { + iframe.iframe_load_event_steps(child_id); + } } } @@ -1609,7 +1619,7 @@ impl ScriptThread { root_context.and_then(|root_context| { root_context.find(parent_id).and_then(|context| { let doc = context.active_document(); - doc.find_iframe(incomplete.pipeline_id) + doc.find_iframe(incomplete.frame_id) }) }) }); @@ -2033,7 +2043,7 @@ impl ScriptThread { /// The entry point for content to notify that a new load has been requested /// for the given pipeline (specifically the "navigate" algorithm). fn handle_navigate(&self, parent_pipeline_id: PipelineId, - pipeline_id: Option<PipelineId>, + frame_id: Option<FrameId>, load_data: LoadData, replace: bool) { // Step 7. @@ -2053,12 +2063,12 @@ impl ScriptThread { } } - match pipeline_id { - Some(pipeline_id) => { + match frame_id { + Some(frame_id) => { let root_context = self.root_browsing_context(); let iframe = root_context.find(parent_pipeline_id).and_then(|context| { let doc = context.active_document(); - doc.find_iframe(pipeline_id) + doc.find_iframe(frame_id) }); if let Some(iframe) = iframe.r() { iframe.navigate_or_reload_child_browsing_context(Some(load_data), replace); diff --git a/components/script_traits/lib.rs b/components/script_traits/lib.rs index b28a7118790..a308c9e3dab 100644 --- a/components/script_traits/lib.rs +++ b/components/script_traits/lib.rs @@ -168,7 +168,9 @@ pub struct NewLayoutInfo { pub parent_pipeline_id: PipelineId, /// Id of the newly-created pipeline. pub new_pipeline_id: PipelineId, - /// Type of the new frame associated with this pipeline. + /// Id of the frame associated with this pipeline. + pub frame_id: FrameId, + /// Type of the frame associated with this pipeline. pub frame_type: FrameType, /// Network request data which will be initiated by the script thread. pub load_data: LoadData, @@ -208,22 +210,20 @@ pub enum ConstellationControlMsg { /// Notifies script thread whether frame is visible ChangeFrameVisibilityStatus(PipelineId, bool), /// Notifies script thread that frame visibility change is complete - /// First PipelineId is for the parent, second PipelineId is for the actual pipeline. - NotifyVisibilityChange(PipelineId, PipelineId, bool), + /// PipelineId is for the parent, FrameId is for the actual frame. + NotifyVisibilityChange(PipelineId, FrameId, bool), /// Notifies script thread that a url should be loaded in this iframe. - /// First PipelineId is for the parent, second PipelineId is for the actual pipeline. - Navigate(PipelineId, PipelineId, LoadData, bool), + /// PipelineId is for the parent, FrameId is for the actual frame. + Navigate(PipelineId, FrameId, LoadData, bool), /// Requests the script thread forward a mozbrowser event to an iframe it owns, - /// or to the window if no child pipeline id is provided. - /// First PipelineId is for the parent, second PipelineId is for the actual pipeline. - MozBrowserEvent(PipelineId, Option<PipelineId>, MozBrowserEvent), + /// or to the window if no child frame id is provided. + MozBrowserEvent(PipelineId, Option<FrameId>, MozBrowserEvent), /// Updates the current pipeline ID of a given iframe. - /// First PipelineId is for the parent, second is the old PipelineId for the frame, - /// third is the new PipelineId for the frame. - UpdatePipelineId(PipelineId, PipelineId, PipelineId), + /// First PipelineId is for the parent, second is the new PipelineId for the frame. + UpdatePipelineId(PipelineId, FrameId, PipelineId), /// Set an iframe to be focused. Used when an element in an iframe gains focus. - /// First PipelineId is for the parent, second PipelineId is for the actual pipeline. - FocusIFrame(PipelineId, PipelineId), + /// PipelineId is for the parent, FrameId is for the actual frame. + FocusIFrame(PipelineId, FrameId), /// Passes a webdriver command to the script thread for execution WebDriverScriptCommand(PipelineId, WebDriverScriptCommand), /// Notifies script thread that all animations are done @@ -235,14 +235,16 @@ pub enum ConstellationControlMsg { WebFontLoaded(PipelineId), /// Cause a `load` event to be dispatched at the appropriate frame element. DispatchFrameLoadEvent { - /// The pipeline that has been marked as loaded. - target: PipelineId, + /// The frame that has been marked as loaded. + target: FrameId, /// The pipeline that contains a frame loading the target pipeline. parent: PipelineId, + /// The pipeline that has completed loading. + child: PipelineId, }, - /// Notifies a parent frame that one of its child frames is now active. - /// First PipelineId is for the parent, second PipelineId is for the actual pipeline. - FramedContentChanged(PipelineId, PipelineId), + /// Notifies a parent pipeline that one of its child frames is now active. + /// PipelineId is for the parent, FrameId is the child frame. + FramedContentChanged(PipelineId, FrameId), /// Report an error from a CSS parser for the given pipeline ReportCSSError(PipelineId, String, usize, usize, String), /// Reload the given page. @@ -430,6 +432,8 @@ pub struct InitialScriptState { /// The subpage ID of this pipeline to create in its pipeline parent. /// If `None`, this is the root. pub parent_info: Option<(PipelineId, FrameType)>, + /// The ID of the frame this script is part of. + pub frame_id: FrameId, /// A channel with which messages can be sent to us (the script thread). pub control_chan: IpcSender<ConstellationControlMsg>, /// A port on which messages sent by the constellation to script can be received. diff --git a/components/script_traits/script_msg.rs b/components/script_traits/script_msg.rs index 82b7af96f81..b73be67c023 100644 --- a/components/script_traits/script_msg.rs +++ b/components/script_traits/script_msg.rs @@ -83,10 +83,9 @@ pub enum ScriptMsg { /// A new load has been requested, with an option to replace the current entry once loaded /// instead of adding a new entry. LoadUrl(PipelineId, LoadData, bool), - /// Dispatch a mozbrowser event to a given iframe, - /// or to the window if no subpage id is provided. - /// First PipelineId is for the parent, second PipelineId is for the actual pipeline. - MozBrowserEvent(PipelineId, Option<PipelineId>, MozBrowserEvent), + /// Dispatch a mozbrowser event to the parent of this pipeline. + /// The first PipelineId is for the parent, the second is for the originating pipeline. + MozBrowserEvent(PipelineId, PipelineId, MozBrowserEvent), /// HTMLIFrameElement Forward or Back traversal. TraverseHistory(Option<PipelineId>, TraversalDirection), /// Gets the length of the joint session history from the constellation. diff --git a/tests/wpt/mozilla/tests/mozilla/mozbrowser/mozbrowserlocationchange_event.html b/tests/wpt/mozilla/tests/mozilla/mozbrowser/mozbrowserlocationchange_event.html index c2ba1d3e4e8..3866cc6dadb 100644 --- a/tests/wpt/mozilla/tests/mozilla/mozbrowser/mozbrowserlocationchange_event.html +++ b/tests/wpt/mozilla/tests/mozilla/mozbrowser/mozbrowserlocationchange_event.html @@ -38,7 +38,7 @@ async_test(function(t) { var action_idx = 0; - iframe.addEventListener("mozbrowserlocationchange", e => { + iframe.addEventListener("mozbrowserlocationchange", t.step_func(e => { received_events.push(e.detail.url); received_events.push(e.detail.canGoBack); received_events.push(e.detail.canGoForward); @@ -49,7 +49,7 @@ async_test(function(t) { assert_array_equals(received_events, expected_events); t.done(); } - }); + })); document.body.appendChild(iframe); diff --git a/tests/wpt/web-platform-tests/html/browsers/history/the-location-interface/location_reload-iframe.html b/tests/wpt/web-platform-tests/html/browsers/history/the-location-interface/location_reload-iframe.html index 95b63d9f5d4..f08cf5de3e8 100644 --- a/tests/wpt/web-platform-tests/html/browsers/history/the-location-interface/location_reload-iframe.html +++ b/tests/wpt/web-platform-tests/html/browsers/history/the-location-interface/location_reload-iframe.html @@ -1,4 +1,4 @@ <script> parent._ping(window.location.href) - location.reload(); + if (parent._pingCount < 5) { location.reload(); } </script> diff --git a/tests/wpt/web-platform-tests/html/browsers/history/the-location-interface/location_reload.html b/tests/wpt/web-platform-tests/html/browsers/history/the-location-interface/location_reload.html index 78b3cc35eb4..eb2c21b38a3 100644 --- a/tests/wpt/web-platform-tests/html/browsers/history/the-location-interface/location_reload.html +++ b/tests/wpt/web-platform-tests/html/browsers/history/the-location-interface/location_reload.html @@ -15,18 +15,17 @@ async_test(function(t) { var url = new URL("./location_reload-iframe.html", window.location).href; - var pingCount = 0; + window._pingCount = 0; window._ping = t.step_func(function(innerURL) { // Some browsers keep 'about:blank' in the session history - if (pingCount == 0) { + if (_pingCount == 0) { history_length = history.length; } - assert_equals(url, innerURL, "iframe url (" + pingCount + ")"); - assert_equals(history_length, history.length, "history length (" + pingCount + ")"); - pingCount++; - if (pingCount == 5) { - iframe.src = 'about:blank'; + assert_equals(url, innerURL, "iframe url (" + _pingCount + ")"); + assert_equals(history_length, history.length, "history length (" + _pingCount + ")"); + _pingCount++; + if (_pingCount == 5) { t.done(); } }); |