diff --git a/components/compositing/constellation.rs b/components/compositing/constellation.rs index ffd898934cc..2f456b3e464 100644 --- a/components/compositing/constellation.rs +++ b/components/compositing/constellation.rs @@ -26,8 +26,9 @@ use msg::constellation_msg::AnimationState; use msg::constellation_msg::Msg as ConstellationMsg; use msg::constellation_msg::WebDriverCommandMsg; use msg::constellation_msg::{FrameId, PipelineExitType, PipelineId}; -use msg::constellation_msg::{IFrameSandboxState, MozBrowserEvent, NavigationDirection}; +use msg::constellation_msg::{IframeLoadInfo, IFrameSandboxState, MozBrowserEvent, NavigationDirection}; use msg::constellation_msg::{Key, KeyModifiers, KeyState, LoadData}; +use msg::constellation_msg::{PipelineNamespace, PipelineNamespaceId}; use msg::constellation_msg::{SubpageId, WindowSizeData}; use msg::constellation_msg::{self, ConstellationChan, Failure}; use msg::webdriver_msg; @@ -101,8 +102,8 @@ pub struct Constellation { /// ID of the root frame. root_frame_id: Option, - /// The next free ID to assign to a pipeline. - next_pipeline_id: PipelineId, + /// The next free ID to assign to a pipeline ID namespace. + next_pipeline_namespace_id: PipelineNamespaceId, /// The next free ID to assign to a frame. next_frame_id: FrameId, @@ -260,7 +261,7 @@ impl Constellation { pipeline_to_frame_map: HashMap::new(), subpage_map: HashMap::new(), pending_frames: vec!(), - next_pipeline_id: PipelineId(0), + next_pipeline_namespace_id: PipelineNamespaceId(0), root_frame_id: None, next_frame_id: FrameId(0), focus_pipeline_id: None, @@ -284,6 +285,8 @@ impl Constellation { webgl_paint_tasks: Vec::new(), subpage_id_senders: HashMap::new(), }; + let namespace_id = constellation.next_pipeline_namespace_id(); + PipelineNamespace::install(namespace_id); constellation.run(); }); constellation_chan @@ -298,17 +301,20 @@ impl Constellation { } } + fn next_pipeline_namespace_id(&mut self) -> PipelineNamespaceId { + let namespace_id = self.next_pipeline_namespace_id; + let PipelineNamespaceId(ref mut i) = self.next_pipeline_namespace_id; + *i += 1; + namespace_id + } + /// Helper function for creating a pipeline fn new_pipeline(&mut self, + pipeline_id: PipelineId, parent_info: Option<(PipelineId, SubpageId)>, initial_window_size: Option>, script_channel: Option>, - load_data: LoadData) - -> PipelineId { - let pipeline_id = self.next_pipeline_id; - let PipelineId(ref mut i) = self.next_pipeline_id; - *i += 1; - + load_data: LoadData) { let spawning_paint_only = script_channel.is_some(); let (pipeline, mut pipeline_content) = Pipeline::create::(InitialPipelineState { @@ -327,6 +333,7 @@ impl Constellation { script_chan: script_channel, load_data: load_data, device_pixel_ratio: self.window_size.device_pixel_ratio, + pipeline_namespace_id: self.next_pipeline_namespace_id(), }); // TODO(pcwalton): In multiprocess mode, send that `PipelineContent` instance over to @@ -339,7 +346,6 @@ impl Constellation { assert!(!self.pipelines.contains_key(&pipeline_id)); self.pipelines.insert(pipeline_id, pipeline); - pipeline_id } // Push a new (loading) pipeline to the list of pending frame changes @@ -405,20 +411,12 @@ impl Constellation { debug!("constellation got frame size message"); self.handle_frame_size_msg(pipeline_id, subpage_id, &Size2D::from_untyped(&size)); } - ConstellationMsg::ScriptLoadedURLInIFrame(url, - source_pipeline_id, - new_subpage_id, - old_subpage_id, - sandbox) => { + ConstellationMsg::ScriptLoadedURLInIFrame(load_info) => { debug!("constellation got iframe URL load message {:?} {:?} {:?}", - source_pipeline_id, - old_subpage_id, - new_subpage_id); - self.handle_script_loaded_url_in_iframe_msg(url, - source_pipeline_id, - new_subpage_id, - old_subpage_id, - sandbox); + load_info.containing_pipeline_id, + load_info.old_subpage_id, + load_info.new_subpage_id); + self.handle_script_loaded_url_in_iframe_msg(load_info); } ConstellationMsg::SetCursor(cursor) => { self.handle_set_cursor_msg(cursor) @@ -597,19 +595,21 @@ impl Constellation { debug!("creating replacement pipeline for about:failure"); let window_size = self.pipeline(pipeline_id).size; - let new_pipeline_id = - self.new_pipeline(parent_info, - window_size, - None, - LoadData::new(Url::parse("about:failure").unwrap())); + let new_pipeline_id = PipelineId::new(); + self.new_pipeline(new_pipeline_id, + parent_info, + window_size, + None, + LoadData::new(Url::parse("about:failure").unwrap())); self.push_pending_frame(new_pipeline_id, Some(pipeline_id)); } fn handle_init_load(&mut self, url: Url) { let window_size = self.window_size.visible_viewport; - let root_pipeline_id = - self.new_pipeline(None, Some(window_size), None, LoadData::new(url.clone())); + let root_pipeline_id = PipelineId::new(); + debug_assert!(PipelineId::fake_root_pipeline_id() == root_pipeline_id); + self.new_pipeline(root_pipeline_id, None, Some(window_size), None, LoadData::new(url.clone())); self.handle_load_start_msg(&root_pipeline_id); self.push_pending_frame(root_pipeline_id, None); self.compositor_proxy.send(CompositorMsg::ChangePageUrl(root_pipeline_id, url)); @@ -646,59 +646,56 @@ impl Constellation { // 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 // page navigation. - fn handle_script_loaded_url_in_iframe_msg(&mut self, - url: Url, - containing_pipeline_id: PipelineId, - new_subpage_id: SubpageId, - old_subpage_id: Option, - sandbox: IFrameSandboxState) { + fn handle_script_loaded_url_in_iframe_msg(&mut self, load_info: IframeLoadInfo) { // Compare the pipeline's url to the new url. If the origin is the same, // then reuse the script task in creating the new pipeline let script_chan = { - let source_pipeline = self.pipeline(containing_pipeline_id); + let source_pipeline = self.pipeline(load_info.containing_pipeline_id); let source_url = source_pipeline.url.clone(); - let same_script = (source_url.host() == url.host() && - source_url.port() == url.port()) && - sandbox == IFrameSandboxState::IFrameUnsandboxed; + let same_script = (source_url.host() == load_info.url.host() && + source_url.port() == load_info.url.port()) && + load_info.sandbox == IFrameSandboxState::IFrameUnsandboxed; // FIXME(tkuehn): Need to follow the standardized spec for checking same-origin // Reuse the script task if the URL is same-origin if same_script { debug!("Constellation: loading same-origin iframe, \ - parent url {:?}, iframe url {:?}", source_url, url); + parent url {:?}, iframe url {:?}", source_url, load_info.url); Some(source_pipeline.script_chan.clone()) } else { debug!("Constellation: loading cross-origin iframe, \ - parent url {:?}, iframe url {:?}", source_url, url); + parent url {:?}, iframe url {:?}", source_url, load_info.url); None } }; // Create the new pipeline, attached to the parent and push to pending frames - let old_pipeline_id = old_subpage_id.map(|old_subpage_id| { - self.find_subpage(containing_pipeline_id, old_subpage_id).id + let old_pipeline_id = load_info.old_subpage_id.map(|old_subpage_id| { + self.find_subpage(load_info.containing_pipeline_id, old_subpage_id).id }); let window_size = old_pipeline_id.and_then(|old_pipeline_id| { self.pipeline(old_pipeline_id).size }); - let new_pipeline_id = self.new_pipeline(Some((containing_pipeline_id, new_subpage_id)), - window_size, - script_chan, - LoadData::new(url)); + self.new_pipeline(load_info.new_pipeline_id, + Some((load_info.containing_pipeline_id, load_info.new_subpage_id)), + window_size, + script_chan, + LoadData::new(load_info.url)); - self.subpage_map.insert((containing_pipeline_id, new_subpage_id), new_pipeline_id); + self.subpage_map.insert((load_info.containing_pipeline_id, load_info.new_subpage_id), + load_info.new_pipeline_id); // If anyone is waiting to know the pipeline ID, send that information now. - if let Some(subpage_id_senders) = self.subpage_id_senders.remove(&(containing_pipeline_id, - new_subpage_id)) { + if let Some(subpage_id_senders) = self.subpage_id_senders.remove(&(load_info.containing_pipeline_id, + load_info.new_subpage_id)) { for subpage_id_sender in subpage_id_senders.into_iter() { - subpage_id_sender.send(new_pipeline_id).unwrap(); + subpage_id_sender.send(load_info.new_pipeline_id).unwrap(); } } - self.push_pending_frame(new_pipeline_id, old_pipeline_id); + self.push_pending_frame(load_info.new_pipeline_id, old_pipeline_id); } fn handle_set_cursor_msg(&mut self, cursor: Cursor) { @@ -756,7 +753,8 @@ impl Constellation { // Create the new pipeline let window_size = self.pipeline(source_id).size; - let new_pipeline_id = self.new_pipeline(None, window_size, None, load_data); + let new_pipeline_id = PipelineId::new(); + self.new_pipeline(new_pipeline_id, None, window_size, None, load_data); self.push_pending_frame(new_pipeline_id, Some(source_id)); // Send message to ScriptTask that will suspend all timers diff --git a/components/compositing/pipeline.rs b/components/compositing/pipeline.rs index 59870d23ab8..34490730708 100644 --- a/components/compositing/pipeline.rs +++ b/components/compositing/pipeline.rs @@ -16,6 +16,7 @@ use layers::geometry::DevicePixel; use layout_traits::{LayoutControlChan, LayoutTaskFactory}; use msg::constellation_msg::{ConstellationChan, Failure, FrameId, PipelineId, SubpageId}; use msg::constellation_msg::{LoadData, MozBrowserEvent, PipelineExitType, WindowSizeData}; +use msg::constellation_msg::{PipelineNamespaceId}; use net_traits::ResourceTask; use net_traits::image_cache_task::ImageCacheTask; use net_traits::storage_task::StorageTask; @@ -99,6 +100,8 @@ pub struct InitialPipelineState { pub script_chan: Option>, /// Information about the page to load. pub load_data: LoadData, + /// The ID of the pipeline namespace for this script thread. + pub pipeline_namespace_id: PipelineNamespaceId, } impl Pipeline { @@ -198,6 +201,7 @@ impl Pipeline { pipeline_port: pipeline_port, paint_shutdown_chan: paint_shutdown_chan, layout_shutdown_chan: layout_shutdown_chan, + pipeline_namespace_id: state.pipeline_namespace_id, }; (pipeline, pipeline_content) @@ -332,6 +336,7 @@ pub struct PipelineContent { paint_shutdown_chan: Sender<()>, pipeline_port: Option>, layout_shutdown_chan: Sender<()>, + pipeline_namespace_id: PipelineNamespaceId, } impl PipelineContent { @@ -364,6 +369,7 @@ impl PipelineContent { mem_profiler_chan: self.mem_profiler_chan.clone(), devtools_chan: self.devtools_chan, window_size: self.window_size, + pipeline_namespace_id: self.pipeline_namespace_id, }, &layout_pair, self.load_data.clone()); LayoutTaskFactory::create(None::<&mut LTF>, diff --git a/components/devtools/lib.rs b/components/devtools/lib.rs index c0049b31ad3..c294e4bfa72 100644 --- a/components/devtools/lib.rs +++ b/components/devtools/lib.rs @@ -433,7 +433,7 @@ fn run_server(sender: Sender, //TODO: Get pipeline_id from NetworkEventMessage after fixing the send in http_loader // For now, the id of the first pipeline is passed handle_network_event(actors.clone(), connections, &actor_pipelines, &mut actor_requests, - &actor_workers, PipelineId(0), request_id, network_event); + &actor_workers, PipelineId::fake_root_pipeline_id(), request_id, network_event); }, Ok(DevtoolsControlMsg::FromChrome(ChromeToDevtoolsControlMsg::ServerExitMsg)) | Err(RecvError) => break diff --git a/components/gfx/paint_task.rs b/components/gfx/paint_task.rs index c63c84d9970..25c4522fc44 100644 --- a/components/gfx/paint_task.rs +++ b/components/gfx/paint_task.rs @@ -183,7 +183,7 @@ impl PaintTask where C: PaintListener + Send + 'static { canvas_map: HashMap::new() }; - let reporter_name = format!("paint-reporter-{}", id.0); + let reporter_name = format!("paint-reporter-{}", id); mem_profiler_chan.run_with_memory_reporting(|| { paint_task.start(); }, reporter_name, chrome_to_paint_chan, ChromeToPaintMsg::CollectReports); diff --git a/components/layout/layout_task.rs b/components/layout/layout_task.rs index 3535b8137df..06e545493bd 100644 --- a/components/layout/layout_task.rs +++ b/components/layout/layout_task.rs @@ -277,7 +277,7 @@ impl LayoutTaskFactory for LayoutTask { time_profiler_chan, mem_profiler_chan.clone()); - let reporter_name = format!("layout-reporter-{}", id.0); + let reporter_name = format!("layout-reporter-{}", id); mem_profiler_chan.run_with_memory_reporting(|| { layout.start(); }, reporter_name, layout_chan.0, Msg::CollectReports); diff --git a/components/msg/constellation_msg.rs b/components/msg/constellation_msg.rs index 49d673b1097..cefcd0da4c8 100644 --- a/components/msg/constellation_msg.rs +++ b/components/msg/constellation_msg.rs @@ -15,7 +15,9 @@ use ipc_channel::ipc::IpcSender; use layers::geometry::DevicePixel; use offscreen_gl_context::GLContextAttributes; use png::Image; +use std::cell::Cell; use std::collections::HashMap; +use std::fmt; use std::sync::mpsc::{Receiver, Sender, channel}; use style_traits::viewport::ViewportConstraints; use url::Url; @@ -211,6 +213,23 @@ pub enum FocusType { Parent, // Focusing a parent element (an iframe) } +/// Specifies the information required to load a URL in an iframe. +#[derive(Deserialize, Serialize)] +pub struct IframeLoadInfo { + /// Url to load + pub url: Url, + /// Pipeline ID of the parent of this iframe + pub containing_pipeline_id: PipelineId, + /// The new subpage ID for this load + pub new_subpage_id: SubpageId, + /// The old subpage ID for this iframe, if a page was previously loaded. + pub old_subpage_id: Option, + /// The new pipeline ID that the iframe has generated. + pub new_pipeline_id: PipelineId, + /// Sandbox type of this iframe + pub sandbox: IFrameSandboxState, +} + /// Messages from the compositor and script to the constellation. #[derive(Deserialize, Serialize)] pub enum Msg { @@ -222,7 +241,7 @@ pub enum Msg { DOMLoad(PipelineId), FrameSize(PipelineId, SubpageId, Size2D), LoadUrl(PipelineId, LoadData), - ScriptLoadedURLInIFrame(Url, PipelineId, SubpageId, Option, IFrameSandboxState), + ScriptLoadedURLInIFrame(IframeLoadInfo), Navigate(Option<(PipelineId, SubpageId)>, NavigationDirection), PainterReady(PipelineId), ResizedWindow(WindowSizeData), @@ -393,8 +412,95 @@ pub struct FrameId(pub u32); #[derive(Clone, PartialEq, Eq, Copy, Hash, Debug, Deserialize, Serialize, HeapSizeOf)] pub struct WorkerId(pub u32); +/// Each pipeline ID needs to be unique. However, it also needs to be possible to +/// generate the pipeline ID from an iframe element (this simplifies a lot of other +/// code that makes use of pipeline IDs). +/// +/// To achieve this, each pipeline index belongs to a particular namespace. There is +/// a namespace for the constellation thread, and also one for every script thread. +/// This allows pipeline IDs to be generated by any of those threads without conflicting +/// with pipeline IDs created by other script threads or the constellation. The +/// constellation is the only code that is responsible for creating new *namespaces*. +/// This ensures that namespaces are always unique, even when using multi-process mode. +/// +/// It may help conceptually to think of the namespace ID as an identifier for the +/// thread that created this pipeline ID - however this is really an implementation +/// detail so shouldn't be relied upon in code logic. It's best to think of the +/// pipeline ID as a simple unique identifier that doesn't convey any more information. +#[derive(Clone, Copy)] +pub struct PipelineNamespace { + id: PipelineNamespaceId, + next_index: PipelineIndex, +} + +impl PipelineNamespace { + pub fn install(namespace_id: PipelineNamespaceId) { + PIPELINE_NAMESPACE.with(|tls| { + assert!(tls.get().is_none()); + tls.set(Some(PipelineNamespace { + id: namespace_id, + next_index: PipelineIndex(0), + })); + }); + } + + fn next(&mut self) -> PipelineId { + let pipeline_id = PipelineId { + namespace_id: self.id, + index: self.next_index, + }; + + let PipelineIndex(current_index) = self.next_index; + self.next_index = PipelineIndex(current_index + 1); + + pipeline_id + } +} + +thread_local!(pub static PIPELINE_NAMESPACE: Cell> = Cell::new(None)); + #[derive(Clone, PartialEq, Eq, Copy, Hash, Debug, Deserialize, Serialize, HeapSizeOf)] -pub struct PipelineId(pub u32); +pub struct PipelineNamespaceId(pub u32); + +#[derive(Clone, PartialEq, Eq, Copy, Hash, Debug, Deserialize, Serialize, HeapSizeOf)] +pub struct PipelineIndex(u32); + +#[derive(Clone, PartialEq, Eq, Copy, Hash, Debug, Deserialize, Serialize, HeapSizeOf)] +pub struct PipelineId { + namespace_id: PipelineNamespaceId, + index: PipelineIndex +} + +impl PipelineId { + pub fn new() -> PipelineId { + PIPELINE_NAMESPACE.with(|tls| { + let mut namespace = tls.get().expect("No namespace set for this thread!"); + let new_pipeline_id = namespace.next(); + tls.set(Some(namespace)); + new_pipeline_id + }) + } + + // TODO(gw): This should be removed. It's only required because of the code + // that uses it in the devtools lib.rs file (which itself is a TODO). Once + // that is fixed, this should be removed. It also relies on the first + // call to PipelineId::new() returning (0,0), which is checked with an + // assert in handle_init_load(). + pub fn fake_root_pipeline_id() -> PipelineId { + PipelineId { + namespace_id: PipelineNamespaceId(0), + index: PipelineIndex(0), + } + } +} + +impl fmt::Display for PipelineId { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let PipelineNamespaceId(namespace_id) = self.namespace_id; + let PipelineIndex(index) = self.index; + write!(fmt, "({},{})", namespace_id, index) + } +} #[derive(Clone, PartialEq, Eq, Copy, Hash, Debug, Deserialize, Serialize, HeapSizeOf)] pub struct SubpageId(pub u32); diff --git a/components/script/dom/htmliframeelement.rs b/components/script/dom/htmliframeelement.rs index 8e0016f4bb0..38c82610b6b 100644 --- a/components/script/dom/htmliframeelement.rs +++ b/components/script/dom/htmliframeelement.rs @@ -28,7 +28,8 @@ use js::jsapi::{JSAutoCompartment, JSAutoRequest, RootedValue}; use js::jsval::UndefinedValue; use msg::constellation_msg::IFrameSandboxState::{IFrameSandboxed, IFrameUnsandboxed}; use msg::constellation_msg::Msg as ConstellationMsg; -use msg::constellation_msg::{ConstellationChan, MozBrowserEvent, NavigationDirection, PipelineId, SubpageId}; +use msg::constellation_msg::{ConstellationChan, IframeLoadInfo, MozBrowserEvent}; +use msg::constellation_msg::{NavigationDirection, PipelineId, SubpageId}; use page::IterablePage; use std::ascii::AsciiExt; use std::borrow::ToOwned; @@ -57,6 +58,7 @@ enum SandboxAllowance { #[dom_struct] pub struct HTMLIFrameElement { htmlelement: HTMLElement, + pipeline_id: Cell>, subpage_id: Cell>, containing_page_pipeline_id: Cell>, sandbox: Cell>, @@ -92,6 +94,8 @@ impl HTMLIFrameElement { } pub fn generate_new_subpage_id(&self) -> (SubpageId, Option) { + self.pipeline_id.set(Some(PipelineId::new())); + let old_subpage_id = self.subpage_id.get(); let win = window_from_node(self); let subpage_id = win.r().get_next_subpage_id(); @@ -109,15 +113,20 @@ impl HTMLIFrameElement { let window = window_from_node(self); let window = window.r(); let (new_subpage_id, old_subpage_id) = self.generate_new_subpage_id(); + let new_pipeline_id = self.pipeline_id.get().unwrap(); self.containing_page_pipeline_id.set(Some(window.pipeline())); let ConstellationChan(ref chan) = window.constellation_chan(); - chan.send(ConstellationMsg::ScriptLoadedURLInIFrame(url, - window.pipeline(), - new_subpage_id, - old_subpage_id, - sandboxed)).unwrap(); + let load_info = IframeLoadInfo { + url: url, + containing_pipeline_id: window.pipeline(), + new_subpage_id: new_subpage_id, + old_subpage_id: old_subpage_id, + new_pipeline_id: new_pipeline_id, + sandbox: sandboxed, + }; + chan.send(ConstellationMsg::ScriptLoadedURLInIFrame(load_info)).unwrap(); if mozbrowser_enabled() { // https://developer.mozilla.org/en-US/docs/Web/Events/mozbrowserloadstart @@ -190,6 +199,7 @@ impl HTMLIFrameElement { HTMLIFrameElement { htmlelement: HTMLElement::new_inherited(HTMLElementTypeId::HTMLIFrameElement, localName, prefix, document), + pipeline_id: Cell::new(None), subpage_id: Cell::new(None), containing_page_pipeline_id: Cell::new(None), sandbox: Cell::new(None), diff --git a/components/script/script_task.rs b/components/script/script_task.rs index a935e4b91f5..ba4581cbdc1 100644 --- a/components/script/script_task.rs +++ b/components/script/script_task.rs @@ -66,6 +66,7 @@ use msg::compositor_msg::{LayerId, ScriptToCompositorMsg}; use msg::constellation_msg::Msg as ConstellationMsg; use msg::constellation_msg::{ConstellationChan, FocusType, LoadData}; use msg::constellation_msg::{MozBrowserEvent, PipelineExitType, PipelineId}; +use msg::constellation_msg::{PipelineNamespace}; use msg::constellation_msg::{SubpageId, WindowSizeData, WorkerId}; use msg::webdriver_msg::WebDriverScriptCommand; use net_traits::LoadData as NetLoadData; @@ -468,6 +469,8 @@ impl ScriptTaskFactory for ScriptTask { let layout_chan = LayoutChan(layout_chan.sender()); let failure_info = state.failure_info; spawn_named_with_send_on_failure(format!("ScriptTask {:?}", state.id), task_state::SCRIPT, move || { + PipelineNamespace::install(state.pipeline_namespace_id); + let roots = RootCollection::new(); let _stack_roots_tls = StackRootTLS::new(&roots); let chan = MainThreadScriptChan(script_chan); @@ -490,7 +493,7 @@ impl ScriptTaskFactory for ScriptTask { load_data.url.clone()); script_task.start_page_load(new_load, load_data); - let reporter_name = format!("script-reporter-{}", id.0); + let reporter_name = format!("script-reporter-{}", id); mem_profiler_chan.run_with_memory_reporting(|| { script_task.start(); }, reporter_name, channel_for_reporter, CommonScriptMsg::CollectReports); diff --git a/components/script_traits/lib.rs b/components/script_traits/lib.rs index 274c3eb4924..7693529d4b1 100644 --- a/components/script_traits/lib.rs +++ b/components/script_traits/lib.rs @@ -31,7 +31,7 @@ use libc::c_void; use msg::compositor_msg::{Epoch, LayerId, ScriptToCompositorMsg}; use msg::constellation_msg::{ConstellationChan, Failure, PipelineId, WindowSizeData}; use msg::constellation_msg::{Key, KeyModifiers, KeyState, LoadData, SubpageId}; -use msg::constellation_msg::{MozBrowserEvent, PipelineExitType}; +use msg::constellation_msg::{MozBrowserEvent, PipelineExitType, PipelineNamespaceId}; use msg::webdriver_msg::WebDriverScriptCommand; use net_traits::ResourceTask; use net_traits::image_cache_task::ImageCacheTask; @@ -208,6 +208,8 @@ pub struct InitialScriptState { pub devtools_chan: Option>, /// Information about the initial window size. pub window_size: Option, + /// The ID of the pipeline namespace for this script thread. + pub pipeline_namespace_id: PipelineNamespaceId, } /// This trait allows creating a `ScriptTask` without depending on the `script`