diff options
Diffstat (limited to 'components')
-rw-r--r-- | components/compositing/constellation.rs | 16 | ||||
-rw-r--r-- | components/msg/constellation_msg.rs | 2 | ||||
-rw-r--r-- | components/script/dom/document.rs | 24 | ||||
-rw-r--r-- | components/script/dom/htmliframeelement.rs | 25 | ||||
-rw-r--r-- | components/script/script_task.rs | 12 | ||||
-rw-r--r-- | components/script_traits/lib.rs | 7 |
6 files changed, 71 insertions, 15 deletions
diff --git a/components/compositing/constellation.rs b/components/compositing/constellation.rs index 3abb1d5a54e..22a22d459e7 100644 --- a/components/compositing/constellation.rs +++ b/components/compositing/constellation.rs @@ -758,6 +758,20 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> { })).unwrap(); } + fn handle_subframe_loaded(&mut self, pipeline_id: PipelineId) { + let subframe_pipeline = self.pipeline(pipeline_id); + let subframe_parent = match subframe_pipeline.parent_info { + Some(ref parent) => parent, + None => return, + }; + let parent_pipeline = self.pipeline(subframe_parent.0); + let msg = ConstellationControlMsg::DispatchFrameLoadEvent { + target: pipeline_id, + parent: subframe_parent.0 + }; + parent_pipeline.script_chan.send(msg).unwrap(); + } + // The script task associated with pipeline_id has loaded a URL in an iframe via script. This // will result in a new pipeline being spawned and a frame tree being added to // containing_page_pipeline_id's frame tree's children. This message is never the result of a @@ -908,6 +922,8 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> { if webdriver_reset { self.webdriver.load_channel = None; } + + self.handle_subframe_loaded(pipeline_id); } fn handle_navigate_msg(&mut self, diff --git a/components/msg/constellation_msg.rs b/components/msg/constellation_msg.rs index af44eac4c1b..027d8efddd8 100644 --- a/components/msg/constellation_msg.rs +++ b/components/msg/constellation_msg.rs @@ -277,6 +277,8 @@ pub enum ScriptMsg { GLContextAttributes, IpcSender<Result<(IpcSender<CanvasMsg>, usize), String>>), /// Dispatched after the DOM load event has fired on a document + /// Causes a `load` event to be dispatched to any enclosing frame context element + /// for the given pipeline. DOMLoad(PipelineId), Failure(Failure), /// Notifies the constellation that this frame has received focus. diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 31f67f33801..92942012def 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -58,7 +58,7 @@ use dom::keyboardevent::KeyboardEvent; use dom::location::Location; use dom::messageevent::MessageEvent; use dom::mouseevent::MouseEvent; -use dom::node::{self, CloneChildrenFlag, Node, NodeDamage, window_from_node}; +use dom::node::{self, CloneChildrenFlag, Node, NodeDamage}; use dom::nodeiterator::NodeIterator; use dom::nodelist::NodeList; use dom::processinginstruction::ProcessingInstruction; @@ -79,9 +79,9 @@ use layout_interface::{HitTestResponse, MouseOverResponse}; use layout_interface::{LayoutChan, Msg}; use layout_interface::{ReflowGoal, ReflowQueryType}; use msg::compositor_msg::ScriptToCompositorMsg; -use msg::constellation_msg::AnimationState; use msg::constellation_msg::ScriptMsg as ConstellationMsg; use msg::constellation_msg::{ALT, CONTROL, SHIFT, SUPER}; +use msg::constellation_msg::{AnimationState, PipelineId}; use msg::constellation_msg::{ConstellationChan, FocusType, Key, KeyModifiers, KeyState, MozBrowserEvent, SubpageId}; use net_traits::ControlMsg::{GetCookiesForUrl, SetCookiesForUrl}; use net_traits::CookieSource::NonHTTP; @@ -1333,6 +1333,14 @@ impl Document { .find(|node| node.subpage_id() == Some(subpage_id)) } + /// Find an iframe element in the document. + pub fn find_iframe_by_pipeline(&self, pipeline: PipelineId) -> Option<Root<HTMLIFrameElement>> { + self.upcast::<Node>() + .traverse_preorder() + .filter_map(Root::downcast::<HTMLIFrameElement>) + .find(|node| node.pipeline() == Some(pipeline)) + } + pub fn get_dom_loading(&self) -> u64 { self.dom_loading.get() } @@ -2433,18 +2441,6 @@ impl DocumentProgressHandler { event.set_trusted(true); let _ = wintarget.dispatch_event_with_target(document.upcast(), &event); - let browsing_context = window.browsing_context(); - let browsing_context = browsing_context.as_ref().unwrap(); - - if let Some(frame_element) = browsing_context.frame_element() { - let frame_window = window_from_node(frame_element); - let event = Event::new(GlobalRef::Window(frame_window.r()), - DOMString::from("load"), - EventBubbles::DoesNotBubble, - EventCancelable::NotCancelable); - event.fire(frame_element.upcast()); - }; - document.notify_constellation_load(); // https://developer.mozilla.org/en-US/docs/Web/Events/mozbrowserloadend diff --git a/components/script/dom/htmliframeelement.rs b/components/script/dom/htmliframeelement.rs index 66bade67a7d..78400b6d49a 100644 --- a/components/script/dom/htmliframeelement.rs +++ b/components/script/dom/htmliframeelement.rs @@ -16,7 +16,7 @@ use dom::bindings::reflector::Reflectable; use dom::customevent::CustomEvent; use dom::document::Document; use dom::element::{AttributeMutation, Element, RawLayoutElementHelpers}; -use dom::event::Event; +use dom::event::{Event, EventBubbles, EventCancelable}; use dom::htmlelement::HTMLElement; use dom::node::{Node, window_from_node}; use dom::urlhelper::UrlHelper; @@ -189,6 +189,29 @@ impl HTMLIFrameElement { pub fn subpage_id(&self) -> Option<SubpageId> { self.subpage_id.get() } + + pub fn pipeline(&self) -> Option<PipelineId> { + self.pipeline_id.get() + } + + /// https://html.spec.whatwg.org/multipage/#iframe-load-event-steps steps 1-4 + pub fn iframe_load_event_steps(&self) { + // TODO A cross-origin child document would not be easily accessible + // from this script thread. It's unclear how to implement + // steps 2, 3, and 5 efficiently in this case. + // TODO Step 2 - check child document `mute iframe load` flag + // TODO Step 3 - set child document `mut iframe load` flag + + // Step 4 + let window = window_from_node(self); + let event = Event::new(GlobalRef::Window(window.r()), + DOMString::from("load".to_owned()), + EventBubbles::DoesNotBubble, + EventCancelable::NotCancelable); + event.fire(self.upcast()); + + // TODO Step 5 - unset child document `mut iframe load` flag + } } pub trait HTMLIFrameElementLayoutMethods { diff --git a/components/script/script_task.rs b/components/script/script_task.rs index 848f964d2c0..8b9800063e2 100644 --- a/components/script/script_task.rs +++ b/components/script/script_task.rs @@ -1006,6 +1006,9 @@ impl ScriptTask { self.handle_tick_all_animations(pipeline_id), ConstellationControlMsg::WebFontLoaded(pipeline_id) => self.handle_web_font_loaded(pipeline_id), + ConstellationControlMsg::DispatchFrameLoadEvent { + target: pipeline_id, parent: containing_id } => + self.handle_frame_load_event(containing_id, pipeline_id), ConstellationControlMsg::GetCurrentState(sender, pipeline_id) => { let state = self.handle_get_current_state(pipeline_id); sender.send(state).unwrap(); @@ -1535,6 +1538,15 @@ impl ScriptTask { } } + /// Notify the containing document of a child frame that has completed loading. + fn handle_frame_load_event(&self, containing_pipeline: PipelineId, id: PipelineId) { + let page = get_page(&self.root_page(), containing_pipeline); + let document = page.document(); + if let Some(iframe) = document.find_iframe_by_pipeline(id) { + iframe.iframe_load_event_steps(); + } + } + /// 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, metadata: Metadata, incomplete: InProgressLoad) -> Root<ServoHTMLParser> { diff --git a/components/script_traits/lib.rs b/components/script_traits/lib.rs index 685e29c48ec..8a5ffcb459f 100644 --- a/components/script_traits/lib.rs +++ b/components/script_traits/lib.rs @@ -137,6 +137,13 @@ pub enum ConstellationControlMsg { WebFontLoaded(PipelineId), /// Get the current state of the script task for a given pipeline. GetCurrentState(IpcSender<ScriptState>, 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 pipeline that contains a frame loading the target pipeline. + parent: PipelineId + }, } /// The mouse button involved in the event. |