diff --git a/servo/components/constellation/constellation.rs b/servo/components/constellation/constellation.rs index 8cb82a5cdd50..19e70c90bfcd 100644 --- a/servo/components/constellation/constellation.rs +++ b/servo/components/constellation/constellation.rs @@ -42,7 +42,7 @@ use rand::{Rng, SeedableRng, StdRng, random}; use script_traits::{AnimationState, AnimationTickType, CompositorEvent}; use script_traits::{ConstellationControlMsg, ConstellationMsg as FromCompositorMsg}; use script_traits::{DocumentState, LayoutControlMsg, LoadData}; -use script_traits::{IFrameLoadInfo, IFrameSandboxState, TimerEventRequest}; +use script_traits::{IFrameLoadInfo, IFrameLoadInfoWithData, IFrameSandboxState, TimerEventRequest}; use script_traits::{LayoutMsg as FromLayoutMsg, ScriptMsg as FromScriptMsg, ScriptThreadFactory}; use script_traits::{LogEntry, ServiceWorkerMsg, webdriver_msg}; use script_traits::{MozBrowserErrorType, MozBrowserEvent, WebDriverCommandMsg, WindowSizeData}; @@ -914,11 +914,17 @@ impl Constellation } FromScriptMsg::ScriptLoadedURLInIFrame(load_info) => { debug!("constellation got iframe URL load message {:?} {:?} {:?}", - load_info.parent_pipeline_id, + load_info.info.parent_pipeline_id, load_info.old_pipeline_id, - load_info.new_pipeline_id); + load_info.info.new_pipeline_id); self.handle_script_loaded_url_in_iframe_msg(load_info); } + FromScriptMsg::ScriptLoadedAboutBlankInIFrame(load_info, lc) => { + debug!("constellation got loaded `about:blank` in iframe message {:?} {:?}", + load_info.parent_pipeline_id, + load_info.new_pipeline_id); + self.handle_script_loaded_about_blank_in_iframe_msg(load_info, lc); + } FromScriptMsg::ChangeRunningAnimationsState(pipeline_id, animation_state) => { self.handle_change_running_animations_state(pipeline_id, animation_state) } @@ -1363,14 +1369,14 @@ impl Constellation // will result in a new pipeline being spawned and a frame tree being added to // parent_pipeline_id's frame tree's children. This message is never the result of a // page navigation. - fn handle_script_loaded_url_in_iframe_msg(&mut self, load_info: IFrameLoadInfo) { + fn handle_script_loaded_url_in_iframe_msg(&mut self, load_info: IFrameLoadInfoWithData) { let (load_data, window_size, is_private) = { let old_pipeline = load_info.old_pipeline_id .and_then(|old_pipeline_id| self.pipelines.get(&old_pipeline_id)); - let source_pipeline = match self.pipelines.get(&load_info.parent_pipeline_id) { + let source_pipeline = match self.pipelines.get(&load_info.info.parent_pipeline_id) { Some(source_pipeline) => source_pipeline, - None => return warn!("Script loaded url in closed iframe {}.", load_info.parent_pipeline_id), + None => return warn!("Script loaded url in closed iframe {}.", load_info.info.parent_pipeline_id), }; // If no url is specified, reload. @@ -1384,7 +1390,7 @@ impl Constellation LoadData::new(url, None, None) }); - let is_private = load_info.is_private || source_pipeline.is_private; + let is_private = load_info.info.is_private || source_pipeline.is_private; let window_size = old_pipeline.and_then(|old_pipeline| old_pipeline.size); @@ -1396,20 +1402,65 @@ impl Constellation }; // Create the new pipeline, attached to the parent and push to pending frames - self.new_pipeline(load_info.new_pipeline_id, - load_info.frame_id, - Some((load_info.parent_pipeline_id, load_info.frame_type)), + self.new_pipeline(load_info.info.new_pipeline_id, + load_info.info.frame_id, + Some((load_info.info.parent_pipeline_id, load_info.info.frame_type)), window_size, load_data, load_info.sandbox, is_private); self.pending_frames.push(FrameChange { - frame_id: load_info.frame_id, + frame_id: load_info.info.frame_id, old_pipeline_id: load_info.old_pipeline_id, - new_pipeline_id: load_info.new_pipeline_id, + new_pipeline_id: load_info.info.new_pipeline_id, document_ready: false, - replace: load_info.replace, + replace: load_info.info.replace, + }); + } + + fn handle_script_loaded_about_blank_in_iframe_msg(&mut self, + load_info: IFrameLoadInfo, + layout_sender: IpcSender) { + let IFrameLoadInfo { + parent_pipeline_id, + new_pipeline_id, + frame_type, + replace, + frame_id, + is_private, + } = load_info; + + let pipeline = { + let parent_pipeline = match self.pipelines.get(&parent_pipeline_id) { + Some(parent_pipeline) => parent_pipeline, + None => return warn!("Script loaded url in closed iframe {}.", parent_pipeline_id), + }; + + let script_sender = parent_pipeline.script_chan.clone(); + + let url = ServoUrl::parse("about:blank").expect("infallible"); + Pipeline::new(new_pipeline_id, + frame_id, + Some((parent_pipeline_id, frame_type)), + script_sender, + layout_sender, + self.compositor_proxy.clone_compositor_proxy(), + is_private || parent_pipeline.is_private, + url, + None, + parent_pipeline.visible) + }; + + assert!(!self.pipelines.contains_key(&new_pipeline_id)); + self.pipelines.insert(new_pipeline_id, pipeline); + + self.pending_frames.push(FrameChange { + frame_id: frame_id, + old_pipeline_id: None, + new_pipeline_id: new_pipeline_id, + document_ready: false, + replace: replace, }); } diff --git a/servo/components/constellation/pipeline.rs b/servo/components/constellation/pipeline.rs index d77db028f2b3..890476e5010a 100644 --- a/servo/components/constellation/pipeline.rs +++ b/servo/components/constellation/pipeline.rs @@ -165,8 +165,7 @@ impl Pipeline { load_data: state.load_data.clone(), window_size: window_size, pipeline_port: pipeline_port, - layout_to_constellation_chan: state.layout_to_constellation_chan.clone(), - content_process_shutdown_chan: layout_content_process_shutdown_chan.clone(), + content_process_shutdown_chan: Some(layout_content_process_shutdown_chan.clone()), layout_threads: PREFS.get("layout.threads").as_u64().expect("count") as usize, }; @@ -254,23 +253,23 @@ impl Pipeline { state.window_size, state.prev_visibility.unwrap_or(true)); - pipeline.notify_visibility(); - Ok((pipeline, child_process)) } - fn new(id: PipelineId, - frame_id: FrameId, - parent_info: Option<(PipelineId, FrameType)>, - script_chan: Rc, - layout_chan: IpcSender, - compositor_proxy: Box, - is_private: bool, - url: ServoUrl, - size: Option>, - visible: bool) - -> Pipeline { - Pipeline { + /// Creates a new `Pipeline`, after the script and layout threads have been + /// spawned. + pub fn new(id: PipelineId, + frame_id: FrameId, + parent_info: Option<(PipelineId, FrameType)>, + script_chan: Rc, + layout_chan: IpcSender, + compositor_proxy: Box, + is_private: bool, + url: ServoUrl, + size: Option>, + visible: bool) + -> Pipeline { + let pipeline = Pipeline { id: id, frame_id: frame_id, parent_info: parent_info, @@ -284,7 +283,11 @@ impl Pipeline { running_animations: false, visible: visible, is_private: is_private, - } + }; + + pipeline.notify_visibility(); + + pipeline } pub fn exit(&self) { @@ -424,6 +427,7 @@ impl UnprivilegedPipelineContent { control_chan: self.script_chan.clone(), control_port: self.script_port, constellation_chan: self.constellation_chan, + layout_to_constellation_chan: self.layout_to_constellation_chan.clone(), scheduler_chan: self.scheduler_chan, bluetooth_thread: self.bluetooth_thread, resource_threads: self.resource_threads, @@ -448,7 +452,7 @@ impl UnprivilegedPipelineContent { self.font_cache_thread, self.time_profiler_chan, self.mem_profiler_chan, - self.layout_content_process_shutdown_chan, + Some(self.layout_content_process_shutdown_chan), self.webrender_api_sender, self.prefs.get("layout.threads").expect("exists").value() .as_u64().expect("count") as usize); diff --git a/servo/components/layout_thread/lib.rs b/servo/components/layout_thread/lib.rs index 72f1327620ed..5e919138d5c1 100644 --- a/servo/components/layout_thread/lib.rs +++ b/servo/components/layout_thread/lib.rs @@ -246,7 +246,7 @@ impl LayoutThreadFactory for LayoutThread { font_cache_thread: FontCacheThread, time_profiler_chan: time::ProfilerChan, mem_profiler_chan: mem::ProfilerChan, - content_process_shutdown_chan: IpcSender<()>, + content_process_shutdown_chan: Option>, webrender_api_sender: webrender_traits::RenderApiSender, layout_threads: usize) { thread::spawn_named(format!("LayoutThread {:?}", id), @@ -278,7 +278,9 @@ impl LayoutThreadFactory for LayoutThread { layout.start(); }, reporter_name, sender, Msg::CollectReports); } - let _ = content_process_shutdown_chan.send(()); + if let Some(content_process_shutdown_chan) = content_process_shutdown_chan { + let _ = content_process_shutdown_chan.send(()); + } }); } } diff --git a/servo/components/layout_traits/lib.rs b/servo/components/layout_traits/lib.rs index 70d6eab10fff..632300aa61b3 100644 --- a/servo/components/layout_traits/lib.rs +++ b/servo/components/layout_traits/lib.rs @@ -44,7 +44,7 @@ pub trait LayoutThreadFactory { font_cache_thread: FontCacheThread, time_profiler_chan: time::ProfilerChan, mem_profiler_chan: mem::ProfilerChan, - content_process_shutdown_chan: IpcSender<()>, + content_process_shutdown_chan: Option>, webrender_api_sender: webrender_traits::RenderApiSender, layout_threads: usize); } diff --git a/servo/components/script/dom/htmliframeelement.rs b/servo/components/script/dom/htmliframeelement.rs index a31baa9f0459..c322b96a5556 100644 --- a/servo/components/script/dom/htmliframeelement.rs +++ b/servo/components/script/dom/htmliframeelement.rs @@ -20,6 +20,7 @@ use dom::bindings::conversions::ToJSValConvertible; use dom::bindings::error::{Error, ErrorResult, Fallible}; use dom::bindings::inheritance::Castable; use dom::bindings::js::{JS, LayoutJS, MutNullableHeap, Root}; +use dom::bindings::refcounted::Trusted; use dom::bindings::reflector::Reflectable; use dom::bindings::str::DOMString; use dom::browsingcontext::BrowsingContext; @@ -42,14 +43,16 @@ use js::jsval::{NullValue, UndefinedValue}; use msg::constellation_msg::{FrameType, FrameId, PipelineId, TraversalDirection}; use net_traits::response::HttpsState; use script_layout_interface::message::ReflowQueryType; -use script_thread::ScriptThread; -use script_traits::{IFrameLoadInfo, LoadData, MozBrowserEvent, ScriptMsg as ConstellationMsg}; +use script_thread::{ScriptThread, Runnable}; +use script_traits::{IFrameLoadInfo, IFrameLoadInfoWithData, LoadData}; +use script_traits::{MozBrowserEvent, NewLayoutInfo, ScriptMsg as ConstellationMsg}; use script_traits::IFrameSandboxState::{IFrameSandboxed, IFrameUnsandboxed}; use servo_atoms::Atom; use servo_url::ServoUrl; use std::cell::Cell; use style::attr::{AttrValue, LengthOrPercentageOrAuto}; use style::context::ReflowGoal; +use task_source::TaskSource; use util::prefs::PREFS; use util::servo_version; @@ -66,6 +69,12 @@ bitflags! { } } +#[derive(PartialEq)] +enum ProcessingMode { + FirstTime, + NotFirstTime, +} + #[dom_struct] pub struct HTMLIFrameElement { htmlelement: HTMLElement, @@ -131,20 +140,46 @@ impl HTMLIFrameElement { let global_scope = window.upcast::(); let load_info = IFrameLoadInfo { - load_data: load_data, parent_pipeline_id: global_scope.pipeline_id(), frame_id: self.frame_id, - old_pipeline_id: old_pipeline_id, new_pipeline_id: new_pipeline_id, - sandbox: sandboxed, is_private: private_iframe, frame_type: frame_type, replace: replace, }; - global_scope - .constellation_chan() - .send(ConstellationMsg::ScriptLoadedURLInIFrame(load_info)) - .unwrap(); + + if load_data.as_ref().map_or(false, |d| d.url.as_str() == "about:blank") { + let (pipeline_sender, pipeline_receiver) = ipc::channel().unwrap(); + + global_scope + .constellation_chan() + .send(ConstellationMsg::ScriptLoadedAboutBlankInIFrame(load_info, pipeline_sender)) + .unwrap(); + + let new_layout_info = NewLayoutInfo { + parent_info: Some((global_scope.pipeline_id(), frame_type)), + new_pipeline_id: new_pipeline_id, + frame_id: self.frame_id, + load_data: load_data.unwrap(), + pipeline_port: pipeline_receiver, + content_process_shutdown_chan: None, + window_size: None, + layout_threads: PREFS.get("layout.threads").as_u64().expect("count") as usize, + }; + + ScriptThread::process_attach_layout(new_layout_info); + } else { + let load_info = IFrameLoadInfoWithData { + info: load_info, + load_data: load_data, + old_pipeline_id: old_pipeline_id, + sandbox: sandboxed, + }; + global_scope + .constellation_chan() + .send(ConstellationMsg::ScriptLoadedURLInIFrame(load_info)) + .unwrap(); + } if PREFS.is_mozbrowser_enabled() { // https://developer.mozilla.org/en-US/docs/Web/Events/mozbrowserloadstart @@ -152,9 +187,23 @@ impl HTMLIFrameElement { } } - pub fn process_the_iframe_attributes(&self) { + /// https://html.spec.whatwg.org/multipage/#process-the-iframe-attributes + fn process_the_iframe_attributes(&self, mode: ProcessingMode) { + // TODO: srcdoc + + // https://github.com/whatwg/html/issues/490 + if mode == ProcessingMode::FirstTime && !self.upcast::().has_attribute(&local_name!("src")) { + let window = window_from_node(self); + let event_loop = window.dom_manipulation_task_source(); + let _ = event_loop.queue(box IframeLoadEventSteps::new(self), + window.upcast()); + return; + } + let url = self.get_url(); + // TODO: check ancestor browsing contexts for same URL + let document = document_from_node(self); self.navigate_or_reload_child_browsing_context( Some(LoadData::new(url, document.get_referrer_policy(), Some(document.url()))), false); @@ -171,6 +220,16 @@ impl HTMLIFrameElement { } } + fn create_nested_browsing_context(&self) { + // Synchronously create a new context and navigate it to about:blank. + let url = ServoUrl::parse("about:blank").unwrap(); + let document = document_from_node(self); + let load_data = LoadData::new(url, + document.get_referrer_policy(), + Some(document.url().clone())); + self.navigate_or_reload_child_browsing_context(Some(load_data), false); + } + pub fn update_pipeline_id(&self, new_pipeline_id: PipelineId) { self.pipeline_id.set(Some(new_pipeline_id)); @@ -272,7 +331,11 @@ impl HTMLIFrameElement { self.pipeline_id.get() .and_then(|pipeline_id| ScriptThread::find_document(pipeline_id)) .and_then(|document| { - if self.global().get_url().origin() == document.global().get_url().origin() { + // FIXME(#10964): this should use the Document's origin and the + // origin of the incumbent settings object. + let contained_url = document.global().get_url(); + if self.global().get_url().origin() == contained_url.origin() || + contained_url.as_str() == "about:blank" { Some(Root::from_ref(document.window())) } else { None @@ -458,18 +521,7 @@ impl HTMLIFrameElementMethods for HTMLIFrameElement { // https://html.spec.whatwg.org/multipage/#dom-iframe-contentdocument fn GetContentDocument(&self) -> Option> { - self.get_content_window().and_then(|window| { - // FIXME(#10964): this should use the Document's origin and the - // origin of the incumbent settings object. - let self_url = self.get_url(); - let win_url = window_from_node(self).get_url(); - - if UrlHelper::SameOrigin(&self_url, &win_url) { - Some(window.Document()) - } else { - None - } - }) + self.get_content_window().map(|window| window.Document()) } // Experimental mozbrowser implementation is based on the webidl @@ -601,19 +653,17 @@ impl VirtualMethods for HTMLIFrameElement { })); }, &local_name!("src") => { - if let AttributeMutation::Set(_) = mutation { - // https://html.spec.whatwg.org/multipage/#the-iframe-element - // "Similarly, whenever an iframe element with a non-null nested browsing context - // but with no srcdoc attribute specified has its src attribute set, changed, or removed, - // the user agent must process the iframe attributes," - // but we can't check that directly, since the child browsing context - // may be in a different script thread. Instread, we check to see if the parent - // is in a document tree and has a browsing context, which is what causes - // the child browsing context to be created. - if self.upcast::().is_in_doc_with_browsing_context() { - debug!("iframe {} src set while in browsing context.", self.frame_id); - self.process_the_iframe_attributes(); - } + // https://html.spec.whatwg.org/multipage/#the-iframe-element + // "Similarly, whenever an iframe element with a non-null nested browsing context + // but with no srcdoc attribute specified has its src attribute set, changed, or removed, + // the user agent must process the iframe attributes," + // but we can't check that directly, since the child browsing context + // may be in a different script thread. Instread, we check to see if the parent + // is in a document tree and has a browsing context, which is what causes + // the child browsing context to be created. + if self.upcast::().is_in_doc_with_browsing_context() { + debug!("iframe {} src set while in browsing context.", self.frame_id); + self.process_the_iframe_attributes(ProcessingMode::NotFirstTime); } }, _ => {}, @@ -642,7 +692,8 @@ impl VirtualMethods for HTMLIFrameElement { // iframe attributes for the "first time"." if self.upcast::().is_in_doc_with_browsing_context() { debug!("iframe {} bound to browsing context.", self.frame_id); - self.process_the_iframe_attributes(); + self.create_nested_browsing_context(); + self.process_the_iframe_attributes(ProcessingMode::FirstTime); } } @@ -667,7 +718,7 @@ impl VirtualMethods for HTMLIFrameElement { // HTMLIFrameElement::contentDocument. let self_url = self.get_url(); let win_url = window_from_node(self).get_url(); - UrlHelper::SameOrigin(&self_url, &win_url) + UrlHelper::SameOrigin(&self_url, &win_url) || self_url.as_str() == "about:blank" }; let (sender, receiver) = if same_origin { (None, None) @@ -690,3 +741,24 @@ impl VirtualMethods for HTMLIFrameElement { } } } + +struct IframeLoadEventSteps { + frame_element: Trusted, + pipeline_id: PipelineId, +} + +impl IframeLoadEventSteps { + fn new(frame_element: &HTMLIFrameElement) -> IframeLoadEventSteps { + IframeLoadEventSteps { + frame_element: Trusted::new(frame_element), + pipeline_id: frame_element.pipeline_id().unwrap(), + } + } +} + +impl Runnable for IframeLoadEventSteps { + fn handler(self: Box) { + let this = self.frame_element.root(); + this.iframe_load_event_steps(self.pipeline_id); + } +} diff --git a/servo/components/script/script_thread.rs b/servo/components/script/script_thread.rs index b902c6df1014..140d57ec7547 100644 --- a/servo/components/script/script_thread.rs +++ b/servo/components/script/script_thread.rs @@ -71,7 +71,8 @@ use js::rust::Runtime; use layout_wrapper::ServoLayoutNode; use mem::heap_size_of_self_and_children; use msg::constellation_msg::{FrameId, FrameType, PipelineId, PipelineNamespace}; -use net_traits::{CoreResourceMsg, IpcSend, Metadata, ReferrerPolicy, ResourceThreads}; +use net_traits::{CoreResourceMsg, FetchMetadata, FetchResponseListener}; +use net_traits::{IpcSend, Metadata, ReferrerPolicy, ResourceThreads}; use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheResult, ImageCacheThread}; use net_traits::request::{CredentialsMode, Destination, RequestInit}; use net_traits::storage_thread::StorageType; @@ -82,7 +83,7 @@ use script_layout_interface::message::{self, NewLayoutThreadInfo, ReflowQueryTyp use script_runtime::{CommonScriptMsg, ScriptChan, ScriptThreadEventCategory, EnqueuedPromiseCallback}; use script_runtime::{ScriptPort, StackRootTLS, get_reports, new_rt_and_cx, PromiseJobQueue}; use script_traits::{CompositorEvent, ConstellationControlMsg, EventResult}; -use script_traits::{InitialScriptState, LoadData, MouseButton, MouseEventType, MozBrowserEvent}; +use script_traits::{InitialScriptState, LayoutMsg, LoadData, MouseButton, MouseEventType, MozBrowserEvent}; use script_traits::{NewLayoutInfo, ScriptMsg as ConstellationMsg}; use script_traits::{ScriptThreadFactory, TimerEvent, TimerEventRequest, TimerSource}; use script_traits::{TouchEventType, TouchId, UntrustedNodeAddress, WindowSizeData, WindowSizeType}; @@ -434,6 +435,9 @@ pub struct ScriptThread { /// For communicating load url messages to the constellation constellation_chan: IpcSender, + /// A sender for new layout threads to communicate to the constellation. + layout_to_constellation_chan: IpcSender, + /// The port on which we receive messages from the image cache image_cache_port: Receiver, @@ -602,6 +606,17 @@ impl ScriptThread { }); } + pub fn process_attach_layout(new_layout_info: NewLayoutInfo) { + SCRIPT_THREAD_ROOT.with(|root| { + if let Some(script_thread) = root.get() { + let script_thread = unsafe { &*script_thread }; + script_thread.profile_event(ScriptThreadEventCategory::AttachLayout, || { + script_thread.handle_new_layout(new_layout_info); + }) + } + }); + } + pub fn find_document(id: PipelineId) -> Option> { SCRIPT_THREAD_ROOT.with(|root| root.get().and_then(|script_thread| { let script_thread = unsafe { &*script_thread }; @@ -681,6 +696,8 @@ impl ScriptThread { content_process_shutdown_chan: state.content_process_shutdown_chan, promise_job_queue: PromiseJobQueue::new(), + + layout_to_constellation_chan: state.layout_to_constellation_chan, } } @@ -1179,7 +1196,6 @@ impl ScriptThread { load_data, window_size, pipeline_port, - layout_to_constellation_chan, content_process_shutdown_chan, layout_threads, } = new_layout_info; @@ -1193,7 +1209,7 @@ impl ScriptThread { is_parent: false, layout_pair: layout_pair, pipeline_port: pipeline_port, - constellation_chan: layout_to_constellation_chan, + constellation_chan: self.layout_to_constellation_chan.clone(), script_chan: self.control_chan.clone(), image_cache_thread: self.image_cache_thread.clone(), content_process_shutdown_chan: content_process_shutdown_chan, @@ -1215,7 +1231,11 @@ impl ScriptThread { let new_load = InProgressLoad::new(new_pipeline_id, frame_id, parent_info, layout_chan, window_size, load_data.url.clone()); - self.start_page_load(new_load, load_data); + if load_data.url.as_str() == "about:blank" { + self.start_page_load_about_blank(new_load); + } else { + self.start_page_load(new_load, load_data); + } } fn handle_loads_complete(&self, pipeline: PipelineId) { @@ -1641,7 +1661,8 @@ impl ScriptThread { /// Notify the containing document of a child frame that has completed loading. fn handle_frame_load_event(&self, parent_id: PipelineId, frame_id: FrameId, child_id: PipelineId) { - match self.documents.borrow().find_iframe(parent_id, frame_id) { + let iframe = self.documents.borrow().find_iframe(parent_id, frame_id); + match iframe { Some(iframe) => iframe.iframe_load_event_steps(child_id), None => warn!("Message sent to closed pipeline {}.", parent_id), } @@ -2014,7 +2035,8 @@ impl ScriptThread { replace: bool) { match frame_id { Some(frame_id) => { - if let Some(iframe) = self.documents.borrow().find_iframe(parent_pipeline_id, frame_id) { + let iframe = self.documents.borrow().find_iframe(parent_pipeline_id, frame_id); + if let Some(iframe) = iframe { iframe.navigate_or_reload_child_browsing_context(Some(load_data), replace); } } @@ -2092,6 +2114,23 @@ impl ScriptThread { self.incomplete_loads.borrow_mut().push(incomplete); } + /// Synchronously fetch `about:blank`. Stores the `InProgressLoad` + /// argument until a notification is received that the fetch is complete. + fn start_page_load_about_blank(&self, incomplete: InProgressLoad) { + let id = incomplete.pipeline_id; + + self.incomplete_loads.borrow_mut().push(incomplete); + + let url = ServoUrl::parse("about:blank").unwrap(); + let mut context = ParserContext::new(id, url.clone()); + + let mut meta = Metadata::default(url); + meta.set_content_type(Some(&mime!(Text / Html))); + context.process_response(Ok(FetchMetadata::Unfiltered(meta))); + context.process_response_chunk(vec![]); + context.process_response_eof(Ok(())); + } + fn handle_parsing_complete(&self, id: PipelineId) { let document = match self.documents.borrow().find_document(id) { Some(document) => document, diff --git a/servo/components/script_layout_interface/message.rs b/servo/components/script_layout_interface/message.rs index 3af9af32c799..a2ca0414e917 100644 --- a/servo/components/script_layout_interface/message.rs +++ b/servo/components/script_layout_interface/message.rs @@ -142,6 +142,6 @@ pub struct NewLayoutThreadInfo { pub constellation_chan: IpcSender, pub script_chan: IpcSender, pub image_cache_thread: ImageCacheThread, - pub content_process_shutdown_chan: IpcSender<()>, + pub content_process_shutdown_chan: Option>, pub layout_threads: usize, } diff --git a/servo/components/script_traits/lib.rs b/servo/components/script_traits/lib.rs index 1f825e60783c..0494f44c70d6 100644 --- a/servo/components/script_traits/lib.rs +++ b/servo/components/script_traits/lib.rs @@ -177,10 +177,8 @@ pub struct NewLayoutInfo { pub window_size: Option, /// A port on which layout can receive messages from the pipeline. pub pipeline_port: IpcReceiver, - /// A sender for the layout thread to communicate to the constellation. - pub layout_to_constellation_chan: IpcSender, /// A shutdown channel so that layout can tell the content process to shut down when it's done. - pub content_process_shutdown_chan: IpcSender<()>, + pub content_process_shutdown_chan: Option>, /// Number of threads to use for layout. pub layout_threads: usize, } @@ -450,6 +448,8 @@ pub struct InitialScriptState { pub control_port: IpcReceiver, /// A channel on which messages can be sent to the constellation from script. pub constellation_chan: IpcSender, + /// A sender for the layout thread to communicate to the constellation. + pub layout_to_constellation_chan: IpcSender, /// A channel to schedule timer events. pub scheduler_chan: IpcSender, /// A channel to the resource manager thread. @@ -492,21 +492,15 @@ pub enum IFrameSandboxState { IFrameUnsandboxed } -/// Specifies the information required to load a URL in an iframe. +/// Specifies the information required to load an iframe. #[derive(Deserialize, Serialize)] pub struct IFrameLoadInfo { - /// Load data containing the url to load - pub load_data: Option, /// Pipeline ID of the parent of this iframe pub parent_pipeline_id: PipelineId, /// The ID for this iframe. pub frame_id: FrameId, - /// The old pipeline ID for this iframe, if a page was previously loaded. - pub old_pipeline_id: Option, /// The new pipeline ID that the iframe has generated. pub new_pipeline_id: PipelineId, - /// Sandbox type of this iframe - pub sandbox: IFrameSandboxState, /// Whether this iframe should be considered private pub is_private: bool, /// Whether this iframe is a mozbrowser iframe @@ -516,6 +510,19 @@ pub struct IFrameLoadInfo { pub replace: bool, } +/// Specifies the information required to load a URL in an iframe. +#[derive(Deserialize, Serialize)] +pub struct IFrameLoadInfoWithData { + /// The information required to load an iframe. + pub info: IFrameLoadInfo, + /// Load data containing the url to load + pub load_data: Option, + /// The old pipeline ID for this iframe, if a page was previously loaded. + pub old_pipeline_id: Option, + /// Sandbox type of this iframe + pub sandbox: IFrameSandboxState, +} + // https://developer.mozilla.org/en-US/docs/Web/API/Using_the_Browser_API#Events /// The events fired in a Browser API context (`