diff --git a/components/script/devtools.rs b/components/script/devtools.rs index 6b7cac9a086..ce4279b2574 100644 --- a/components/script/devtools.rs +++ b/components/script/devtools.rs @@ -42,7 +42,7 @@ use crate::dom::node::{Node, NodeTraits, ShadowIncluding}; use crate::dom::types::HTMLElement; use crate::realms::enter_realm; use crate::script_module::ScriptFetchOptions; -use crate::script_runtime::CanGc; +use crate::script_runtime::{CanGc, IntroductionType}; #[allow(unsafe_code)] pub(crate) fn handle_evaluate_js( @@ -57,6 +57,8 @@ pub(crate) fn handle_evaluate_js( let _ac = enter_realm(global); rooted!(in(*cx) let mut rval = UndefinedValue()); let source_code = SourceCode::Text(Rc::new(DOMString::from_string(eval))); + // TODO: run code with SpiderMonkey Debugger API, like Firefox does + // global.evaluate_script_on_global_with_result( &source_code, "", @@ -65,7 +67,7 @@ pub(crate) fn handle_evaluate_js( ScriptFetchOptions::default_classic_script(global), global.api_base_url(), can_gc, - None, + Some(IntroductionType::DEBUGGER_EVAL), ); if rval.is_undefined() { diff --git a/components/script/dom/debuggerglobalscope.rs b/components/script/dom/debuggerglobalscope.rs index c928e1dd89d..06e3de7ac63 100644 --- a/components/script/dom/debuggerglobalscope.rs +++ b/components/script/dom/debuggerglobalscope.rs @@ -112,6 +112,7 @@ impl DebuggerGlobalScope { ScriptFetchOptions::default_classic_script(&self.global_scope), self.global_scope.api_base_url(), can_gc, + None, ) } diff --git a/components/script/dom/globalscope.rs b/components/script/dom/globalscope.rs index bbba356a122..77c11cd28a4 100644 --- a/components/script/dom/globalscope.rs +++ b/components/script/dom/globalscope.rs @@ -2759,6 +2759,7 @@ impl GlobalScope { fetch_options: ScriptFetchOptions, script_base_url: ServoUrl, can_gc: CanGc, + introduction_type: Option<&'static CStr>, ) -> bool { let source_code = SourceCode::Text(Rc::new(DOMString::from_string((*code).to_string()))); self.evaluate_script_on_global_with_result( @@ -2769,7 +2770,7 @@ impl GlobalScope { fetch_options, script_base_url, can_gc, - None, + introduction_type, ) } diff --git a/components/script/dom/htmlscriptelement.rs b/components/script/dom/htmlscriptelement.rs index 17b255b492c..677f07b4aa2 100644 --- a/components/script/dom/htmlscriptelement.rs +++ b/components/script/dom/htmlscriptelement.rs @@ -213,6 +213,11 @@ pub(crate) struct HTMLScriptElement { /// script_text: DomRefCell, + + /// `introductionType` value to set in the `CompileOptionsWrapper`, overriding the usual + /// `srcScript` or `inlineScript` that this script would normally use. + #[no_trace] + introduction_type_override: Cell>, } impl HTMLScriptElement { @@ -232,6 +237,7 @@ impl HTMLScriptElement { preparation_time_document: MutNullableDom::new(None), line_number: creator.return_line_number(), script_text: DomRefCell::new(DOMString::new()), + introduction_type_override: Cell::new(None), } } @@ -688,7 +694,10 @@ impl HTMLScriptElement { } /// - pub(crate) fn prepare(&self, can_gc: CanGc) { + pub(crate) fn prepare(&self, introduction_type_override: Option<&'static CStr>, can_gc: CanGc) { + self.introduction_type_override + .set(introduction_type_override); + // Step 1. If el's already started is true, then return. if self.already_started.get() { return; @@ -1165,7 +1174,14 @@ impl HTMLScriptElement { // Step 6. let document = self.owner_document(); let old_script = document.GetCurrentScript(); - let introduction_type = (!script.external).then_some(IntroductionType::INLINE_SCRIPT); + let introduction_type = + self.introduction_type_override + .get() + .unwrap_or(if script.external { + IntroductionType::SRC_SCRIPT + } else { + IntroductionType::INLINE_SCRIPT + }); match script.type_ { ScriptType::Classic => { @@ -1174,7 +1190,7 @@ impl HTMLScriptElement { } else { document.set_current_script(Some(self)) } - self.run_a_classic_script(&script, can_gc, introduction_type); + self.run_a_classic_script(&script, can_gc, Some(introduction_type)); document.set_current_script(old_script.as_deref()); }, ScriptType::Module => { @@ -1428,7 +1444,7 @@ impl VirtualMethods for HTMLScriptElement { if *attr.local_name() == local_name!("src") { if let AttributeMutation::Set(_) = mutation { if !self.parser_inserted.get() && self.upcast::().is_connected() { - self.prepare(can_gc); + self.prepare(Some(IntroductionType::INJECTED_SCRIPT), can_gc); } } } @@ -1447,7 +1463,7 @@ impl VirtualMethods for HTMLScriptElement { // running any scripts until the DOM tree is safe for interactions. self.owner_document().add_delayed_task( task!(ScriptPrepare: |script: DomRoot| { - script.prepare(CanGc::note()); + script.prepare(Some(IntroductionType::INJECTED_SCRIPT), CanGc::note()); }), ); } @@ -1460,7 +1476,7 @@ impl VirtualMethods for HTMLScriptElement { } if self.upcast::().is_connected() && !self.parser_inserted.get() { - self.prepare(CanGc::note()); + self.prepare(Some(IntroductionType::INJECTED_SCRIPT), CanGc::note()); } } diff --git a/components/script/dom/servoparser/mod.rs b/components/script/dom/servoparser/mod.rs index 79f58e6ad8f..b049397d502 100644 --- a/components/script/dom/servoparser/mod.rs +++ b/components/script/dom/servoparser/mod.rs @@ -76,7 +76,7 @@ use crate::dom::text::Text; use crate::dom::virtualmethods::vtable_for; use crate::network_listener::PreInvoke; use crate::realms::enter_realm; -use crate::script_runtime::CanGc; +use crate::script_runtime::{CanGc, IntroductionType}; use crate::script_thread::ScriptThread; mod async_html; @@ -682,7 +682,9 @@ impl ServoParser { self.script_nesting_level.set(script_nesting_level + 1); script.set_initial_script_text(); - script.prepare(can_gc); + let introduction_type_override = + (script_nesting_level > 0).then_some(IntroductionType::INJECTED_SCRIPT); + script.prepare(introduction_type_override, can_gc); self.script_nesting_level.set(script_nesting_level); if self.document.has_pending_parsing_blocking_script() { diff --git a/components/script/dom/workletglobalscope.rs b/components/script/dom/workletglobalscope.rs index c20fd59c1c7..bfb70ea1741 100644 --- a/components/script/dom/workletglobalscope.rs +++ b/components/script/dom/workletglobalscope.rs @@ -34,7 +34,7 @@ use crate::dom::worklet::WorkletExecutor; use crate::messaging::MainThreadScriptMsg; use crate::realms::enter_realm; use crate::script_module::ScriptFetchOptions; -use crate::script_runtime::{CanGc, JSContext}; +use crate::script_runtime::{CanGc, IntroductionType, JSContext}; #[dom_struct] /// @@ -133,6 +133,7 @@ impl WorkletGlobalScope { ScriptFetchOptions::default_classic_script(&self.globalscope), self.globalscope.api_base_url(), can_gc, + Some(IntroductionType::WORKLET), ) } diff --git a/components/script/script_module.rs b/components/script/script_module.rs index 4328b7e974c..8dd3be4897b 100644 --- a/components/script/script_module.rs +++ b/components/script/script_module.rs @@ -836,6 +836,7 @@ impl ModuleTree { } #[allow(unsafe_code)] + // FIXME: spec links in this function are all broken, so it’s unclear what this algorithm does /// fn fetch_module_descendants( &self, @@ -929,6 +930,8 @@ impl ModuleTree { Some(parent_identity.clone()), false, None, + // TODO: is this correct? + Some(IntroductionType::IMPORTED_MODULE), can_gc, ); } @@ -1200,6 +1203,8 @@ struct ModuleContext { status: Result<(), NetworkError>, /// Timing object for this resource resource_timing: ResourceFetchTiming, + /// `introductionType` value to set in the `CompileOptionsWrapper`. + introduction_type: Option<&'static CStr>, } impl FetchResponseListener for ModuleContext { @@ -1336,7 +1341,7 @@ impl FetchResponseListener for ModuleContext { compiled_module.handle_mut(), false, CanGc::note(), - None, + self.introduction_type, ); match compiled_module_result { @@ -1570,6 +1575,7 @@ fn fetch_an_import_module_script_graph( None, true, Some(dynamic_module), + Some(IntroductionType::IMPORTED_MODULE), can_gc, ); Ok(()) @@ -1675,6 +1681,7 @@ pub(crate) fn fetch_external_module_script( None, true, None, + Some(IntroductionType::SRC_SCRIPT), can_gc, ) } @@ -1738,6 +1745,7 @@ fn fetch_single_module_script( parent_identity: Option, top_level_module_fetch: bool, dynamic_module: Option>, + introduction_type: Option<&'static CStr>, can_gc: CanGc, ) { { @@ -1857,6 +1865,7 @@ fn fetch_single_module_script( options, status: Ok(()), resource_timing: ResourceFetchTiming::new(ResourceTimingType::Resource), + introduction_type, })); let network_listener = NetworkListener { diff --git a/components/script/script_runtime.rs b/components/script/script_runtime.rs index 2ad95cda739..a40583aca09 100644 --- a/components/script/script_runtime.rs +++ b/components/script/script_runtime.rs @@ -1255,6 +1255,13 @@ pub(crate) use script_bindings::script_runtime::CanGc; // TODO: squish `scriptElement` pub(crate) struct IntroductionType; impl IntroductionType { + /// `introductionType` for code evaluated by debugger. + /// This includes code run via the devtools repl, even if the thread is not paused. + pub const DEBUGGER_EVAL: &CStr = c"debugger eval"; + + /// `introductionType` for code loaded by worklet. + pub const WORKLET: &CStr = c"Worklet"; + /// `introductionType` for code belonging to `")` + /// - `var s = document.createElement("script"); s.text = "code";` + pub const INJECTED_SCRIPT: &CStr = c"injectedScript"; + + /// `introductionType` for code that was loaded indirectly by being imported by another script + /// using ESM static or dynamic imports. + pub const IMPORTED_MODULE: &CStr = c"importedModule"; + + /// `introductionType` for code presented in `javascript:` URLs. + pub const JAVASCRIPT_URL: &CStr = c"javascriptURL"; + + /// `introductionType` for code passed to `setTimeout`/`setInterval` as a string. + pub const DOM_TIMER: &CStr = c"domTimer"; + /// `introductionType` for web workers. /// pub const WORKER: &CStr = c"Worker"; diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index ed9d1b3980c..59bf9c585c8 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -154,7 +154,8 @@ use crate::navigation::{InProgressLoad, NavigationListener}; use crate::realms::enter_realm; use crate::script_module::ScriptFetchOptions; use crate::script_runtime::{ - CanGc, JSContext, JSContextHelper, Runtime, ScriptThreadEventCategory, ThreadSafeJSContext, + CanGc, IntroductionType, JSContext, JSContextHelper, Runtime, ScriptThreadEventCategory, + ThreadSafeJSContext, }; use crate::task_queue::TaskQueue; use crate::task_source::{SendableTaskSource, TaskSourceName}; @@ -3739,6 +3740,7 @@ impl ScriptThread { ScriptFetchOptions::default_classic_script(global_scope), global_scope.api_base_url(), can_gc, + Some(IntroductionType::JAVASCRIPT_URL), ); load_data.js_eval_result = if jsval.get().is_string() { @@ -4093,6 +4095,7 @@ impl ScriptThread { ScriptFetchOptions::default_classic_script(global_scope), global_scope.api_base_url(), can_gc, + None, // No known `introductionType` for JS code from embedder ); let result = match jsval_to_webdriver( context, diff --git a/components/script/timers.rs b/components/script/timers.rs index 803ee63e5ae..0fbd07cd77a 100644 --- a/components/script/timers.rs +++ b/components/script/timers.rs @@ -35,7 +35,7 @@ use crate::dom::testbinding::TestBindingCallback; use crate::dom::types::{Window, WorkerGlobalScope}; use crate::dom::xmlhttprequest::XHRTimeoutCallback; use crate::script_module::ScriptFetchOptions; -use crate::script_runtime::CanGc; +use crate::script_runtime::{CanGc, IntroductionType}; use crate::script_thread::ScriptThread; use crate::task_source::SendableTaskSource; @@ -562,6 +562,7 @@ impl JsTimerTask { ScriptFetchOptions::default_classic_script(&global), global.api_base_url(), can_gc, + Some(IntroductionType::DOM_TIMER), ); }, InternalTimerCallback::FunctionTimerCallback(ref function, ref arguments) => { diff --git a/components/script/webdriver_handlers.rs b/components/script/webdriver_handlers.rs index e42dabc8215..c86d173052f 100644 --- a/components/script/webdriver_handlers.rs +++ b/components/script/webdriver_handlers.rs @@ -529,6 +529,7 @@ pub(crate) fn handle_execute_script( ScriptFetchOptions::default_classic_script(global), global.api_base_url(), can_gc, + None, // No known `introductionType` for JS code from WebDriver ) { jsval_to_webdriver(cx, global, rval.handle(), realm, can_gc) } else { @@ -570,6 +571,7 @@ pub(crate) fn handle_execute_async_script( ScriptFetchOptions::default_classic_script(global_scope), global_scope.api_base_url(), can_gc, + None, // No known `introductionType` for JS code from WebDriver ) { reply_sender.send(Err(WebDriverJSError::JSError)).unwrap(); }