Make it possible for iframes to create their own pipeline ID.

This doesn't change any functionality, but it's the first step towards removing SubpageId.

Adding this change now will allow us to gradually change over code referencing subpage id rather than in one massive PR.

Introduces a namespace for pipeline ID generation - there is a namespace for the constellation thread, and one per script thread.
This commit is contained in:
Glenn Watson 2015-10-01 08:53:36 +10:00
parent 35888e5a1d
commit 5645dba1fa
9 changed files with 193 additions and 68 deletions

View file

@ -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<LTF, STF> {
/// ID of the root frame.
root_frame_id: Option<FrameId>,
/// 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<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
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<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
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<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
}
}
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<TypedSize2D<PagePx, f32>>,
script_channel: Option<Sender<ConstellationControlMsg>>,
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::<LTF, STF>(InitialPipelineState {
@ -327,6 +333,7 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
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<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
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<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
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,8 +595,9 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
debug!("creating replacement pipeline for about:failure");
let window_size = self.pipeline(pipeline_id).size;
let new_pipeline_id =
self.new_pipeline(parent_info,
let new_pipeline_id = PipelineId::new();
self.new_pipeline(new_pipeline_id,
parent_info,
window_size,
None,
LoadData::new(Url::parse("about:failure").unwrap()));
@ -608,8 +607,9 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
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<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
// 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<SubpageId>,
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)),
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(url));
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<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
// 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

View file

@ -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<Sender<ConstellationControlMsg>>,
/// 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<IpcReceiver<LayoutControlMsg>>,
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>,

View file

@ -433,7 +433,7 @@ fn run_server(sender: Sender<DevtoolsControlMsg>,
//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

View file

@ -183,7 +183,7 @@ impl<C> PaintTask<C> 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);

View file

@ -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);

View file

@ -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<SubpageId>,
/// 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<f32>),
LoadUrl(PipelineId, LoadData),
ScriptLoadedURLInIFrame(Url, PipelineId, SubpageId, Option<SubpageId>, 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<Option<PipelineNamespace>> = 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);

View file

@ -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<Option<PipelineId>>,
subpage_id: Cell<Option<SubpageId>>,
containing_page_pipeline_id: Cell<Option<PipelineId>>,
sandbox: Cell<Option<u8>>,
@ -92,6 +94,8 @@ impl HTMLIFrameElement {
}
pub fn generate_new_subpage_id(&self) -> (SubpageId, Option<SubpageId>) {
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),

View file

@ -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);

View file

@ -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<IpcSender<ScriptToDevtoolsControlMsg>>,
/// Information about the initial window size.
pub window_size: Option<WindowSizeData>,
/// 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`