aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom
diff options
context:
space:
mode:
Diffstat (limited to 'components/script/dom')
-rw-r--r--components/script/dom/canvasrenderingcontext2d.rs8
-rw-r--r--components/script/dom/element.rs54
-rw-r--r--components/script/dom/gamepad.rs41
-rw-r--r--components/script/dom/gamepadbutton.rs6
-rw-r--r--components/script/dom/gamepadbuttonlist.rs44
-rw-r--r--components/script/dom/gamepadhapticactuator.rs20
-rw-r--r--components/script/dom/globalscope.rs171
-rw-r--r--components/script/dom/gpucanvascontext.rs4
-rw-r--r--components/script/dom/htmlcanvaselement.rs4
-rw-r--r--components/script/dom/htmlelement.rs19
-rw-r--r--components/script/dom/htmliframeelement.rs17
-rw-r--r--components/script/dom/htmlscriptelement.rs116
-rw-r--r--components/script/dom/macros.rs26
-rw-r--r--components/script/dom/node.rs30
-rw-r--r--components/script/dom/servoparser/mod.rs22
-rw-r--r--components/script/dom/shadowroot.rs9
-rw-r--r--components/script/dom/trustedscript.rs36
-rw-r--r--components/script/dom/trustedscripturl.rs29
-rw-r--r--components/script/dom/trustedtypepolicy.rs195
-rw-r--r--components/script/dom/trustedtypepolicyfactory.rs60
-rw-r--r--components/script/dom/webgl2renderingcontext.rs4
-rw-r--r--components/script/dom/webglrenderingcontext.rs8
-rw-r--r--components/script/dom/webgpu/gpucanvascontext.rs9
-rw-r--r--components/script/dom/webxr/xrhittestsource.rs6
-rw-r--r--components/script/dom/webxr/xrinputsource.rs13
-rw-r--r--components/script/dom/webxr/xrinputsourcearray.rs10
-rw-r--r--components/script/dom/webxr/xrrenderstate.rs8
-rw-r--r--components/script/dom/webxr/xrsession.rs12
-rw-r--r--components/script/dom/webxr/xrsystem.rs8
-rw-r--r--components/script/dom/window.rs137
30 files changed, 639 insertions, 487 deletions
diff --git a/components/script/dom/canvasrenderingcontext2d.rs b/components/script/dom/canvasrenderingcontext2d.rs
index 38bd38ad511..046d478e49d 100644
--- a/components/script/dom/canvasrenderingcontext2d.rs
+++ b/components/script/dom/canvasrenderingcontext2d.rs
@@ -7,9 +7,9 @@ use dom_struct::dom_struct;
use euclid::default::Size2D;
use profile_traits::ipc;
use script_bindings::inheritance::Castable;
-use script_layout_interface::HTMLCanvasDataSource;
use servo_url::ServoUrl;
use snapshot::Snapshot;
+use webrender_api::ImageKey;
use crate::canvas_context::{CanvasContext, CanvasHelpers, LayoutCanvasRenderingContextHelpers};
use crate::canvas_state::CanvasState;
@@ -98,13 +98,13 @@ impl CanvasRenderingContext2D {
}
impl LayoutCanvasRenderingContextHelpers for LayoutDom<'_, CanvasRenderingContext2D> {
- fn canvas_data_source(self) -> HTMLCanvasDataSource {
+ fn canvas_data_source(self) -> Option<ImageKey> {
let canvas_state = &self.unsafe_get().canvas_state;
if canvas_state.is_paintable() {
- HTMLCanvasDataSource::Image(canvas_state.image_key())
+ Some(canvas_state.image_key())
} else {
- HTMLCanvasDataSource::Empty
+ None
}
}
}
diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs
index 2831fc3d8f0..d92d5c124d1 100644
--- a/components/script/dom/element.rs
+++ b/components/script/dom/element.rs
@@ -149,7 +149,6 @@ use crate::dom::raredata::ElementRareData;
use crate::dom::servoparser::ServoParser;
use crate::dom::shadowroot::{IsUserAgentWidget, ShadowRoot};
use crate::dom::text::Text;
-use crate::dom::types::TrustedTypePolicyFactory;
use crate::dom::validation::Validatable;
use crate::dom::validitystate::ValidationFlags;
use crate::dom::virtualmethods::{VirtualMethods, vtable_for};
@@ -1961,35 +1960,6 @@ impl Element {
.unwrap_or_else(|_| TrustedScriptURLOrUSVString::USVString(USVString(value.to_owned())))
}
- pub(crate) fn set_trusted_type_url_attribute(
- &self,
- local_name: &LocalName,
- value: TrustedScriptURLOrUSVString,
- can_gc: CanGc,
- ) -> Fallible<()> {
- assert_eq!(*local_name, local_name.to_ascii_lowercase());
- let value = match value {
- TrustedScriptURLOrUSVString::USVString(url) => {
- let global = self.owner_global();
- // TODO(36258): Reflectively get the name of the class
- let sink = format!("{} {}", "HTMLScriptElement", &local_name);
- let result = TrustedTypePolicyFactory::get_trusted_type_compliant_string(
- &global,
- url.to_string(),
- &sink,
- "'script'",
- can_gc,
- );
- result?
- },
- // This partially implements <https://w3c.github.io/trusted-types/dist/spec/#get-trusted-type-compliant-string-algorithm>
- // Step 1: If input is an instance of expectedType, return stringified input and abort these steps.
- TrustedScriptURLOrUSVString::TrustedScriptURL(script_url) => script_url.to_string(),
- };
- self.set_attribute(local_name, AttrValue::String(value), can_gc);
- Ok(())
- }
-
pub(crate) fn get_string_attribute(&self, local_name: &LocalName) -> DOMString {
match self.get_attribute(&ns!(), local_name) {
Some(x) => x.Value(),
@@ -3025,28 +2995,8 @@ impl ElementMethods<crate::DomTypeHolder> for Element {
DomRoot::from_ref(self.upcast())
};
- // Step 3. Unsafely set HTML given target, this, and compliantHTML.
- // Let newChildren be the result of the HTML fragment parsing algorithm.
- let new_children = ServoParser::parse_html_fragment(self, html, true, can_gc);
-
- let context_document = {
- if let Some(template) = self.downcast::<HTMLTemplateElement>() {
- template.Content(can_gc).upcast::<Node>().owner_doc()
- } else {
- self.owner_document()
- }
- };
-
- // Let fragment be a new DocumentFragment whose node document is contextElement's node document.
- let frag = DocumentFragment::new(&context_document, can_gc);
-
- // For each node in newChildren, append node to fragment.
- for child in new_children {
- frag.upcast::<Node>().AppendChild(&child, can_gc).unwrap();
- }
-
- // Replace all with fragment within target.
- Node::replace_all(Some(frag.upcast()), &target, can_gc);
+ // Step 3. Unsafely set HTML given target, this, and compliantHTML
+ Node::unsafely_set_html(&target, self, html, can_gc);
}
/// <https://html.spec.whatwg.org/multipage/#dom-element-gethtml>
diff --git a/components/script/dom/gamepad.rs b/components/script/dom/gamepad.rs
index dcafc58bcd9..baf3af7466f 100644
--- a/components/script/dom/gamepad.rs
+++ b/components/script/dom/gamepad.rs
@@ -13,7 +13,7 @@ use crate::dom::bindings::codegen::Bindings::GamepadBinding::{GamepadHand, Gamep
use crate::dom::bindings::codegen::Bindings::GamepadButtonListBinding::GamepadButtonListMethods;
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::num::Finite;
-use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object_with_proto};
+use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object};
use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::bindings::str::DOMString;
use crate::dom::event::Event;
@@ -23,6 +23,7 @@ use crate::dom::gamepadevent::{GamepadEvent, GamepadEventType};
use crate::dom::gamepadhapticactuator::GamepadHapticActuator;
use crate::dom::gamepadpose::GamepadPose;
use crate::dom::globalscope::GlobalScope;
+use crate::dom::window::Window;
use crate::script_runtime::{CanGc, JSContext};
// This value is for determining when to consider a gamepad as having a user gesture
@@ -88,39 +89,14 @@ impl Gamepad {
}
}
- #[allow(clippy::too_many_arguments)]
- pub(crate) fn new(
- global: &GlobalScope,
- gamepad_id: u32,
- id: String,
- mapping_type: String,
- axis_bounds: (f64, f64),
- button_bounds: (f64, f64),
- supported_haptic_effects: GamepadSupportedHapticEffects,
- xr: bool,
- can_gc: CanGc,
- ) -> DomRoot<Gamepad> {
- Self::new_with_proto(
- global,
- gamepad_id,
- id,
- mapping_type,
- axis_bounds,
- button_bounds,
- supported_haptic_effects,
- xr,
- can_gc,
- )
- }
-
/// When we construct a new gamepad, we initialize the number of buttons and
/// axes corresponding to the "standard" gamepad mapping.
/// The spec says UAs *may* do this for fingerprint mitigation, and it also
/// happens to simplify implementation
/// <https://www.w3.org/TR/gamepad/#fingerprinting-mitigation>
#[allow(clippy::too_many_arguments)]
- fn new_with_proto(
- global: &GlobalScope,
+ pub(crate) fn new(
+ window: &Window,
gamepad_id: u32,
id: String,
mapping_type: String,
@@ -130,11 +106,11 @@ impl Gamepad {
xr: bool,
can_gc: CanGc,
) -> DomRoot<Gamepad> {
- let button_list = GamepadButtonList::init_buttons(global, can_gc);
+ let button_list = GamepadButtonList::init_buttons(window, can_gc);
let vibration_actuator =
- GamepadHapticActuator::new(global, gamepad_id, supported_haptic_effects, can_gc);
+ GamepadHapticActuator::new(window, gamepad_id, supported_haptic_effects, can_gc);
let index = if xr { -1 } else { 0 };
- let gamepad = reflect_dom_object_with_proto(
+ let gamepad = reflect_dom_object(
Box::new(Gamepad::new_inherited(
gamepad_id,
id,
@@ -149,8 +125,7 @@ impl Gamepad {
button_bounds,
&vibration_actuator,
)),
- global,
- None,
+ window,
can_gc,
);
gamepad.init_axes(can_gc);
diff --git a/components/script/dom/gamepadbutton.rs b/components/script/dom/gamepadbutton.rs
index fead990ccd3..3588ba775ca 100644
--- a/components/script/dom/gamepadbutton.rs
+++ b/components/script/dom/gamepadbutton.rs
@@ -10,7 +10,7 @@ use crate::dom::bindings::codegen::Bindings::GamepadButtonBinding::GamepadButton
use crate::dom::bindings::num::Finite;
use crate::dom::bindings::reflector::{Reflector, reflect_dom_object};
use crate::dom::bindings::root::DomRoot;
-use crate::dom::globalscope::GlobalScope;
+use crate::dom::window::Window;
use crate::script_runtime::CanGc;
#[dom_struct]
@@ -32,14 +32,14 @@ impl GamepadButton {
}
pub(crate) fn new(
- global: &GlobalScope,
+ window: &Window,
pressed: bool,
touched: bool,
can_gc: CanGc,
) -> DomRoot<GamepadButton> {
reflect_dom_object(
Box::new(GamepadButton::new_inherited(pressed, touched)),
- global,
+ window,
can_gc,
)
}
diff --git a/components/script/dom/gamepadbuttonlist.rs b/components/script/dom/gamepadbuttonlist.rs
index 50d9c8172bc..7e540ab56bb 100644
--- a/components/script/dom/gamepadbuttonlist.rs
+++ b/components/script/dom/gamepadbuttonlist.rs
@@ -8,7 +8,7 @@ use crate::dom::bindings::codegen::Bindings::GamepadButtonListBinding::GamepadBu
use crate::dom::bindings::reflector::{Reflector, reflect_dom_object};
use crate::dom::bindings::root::{Dom, DomRoot, DomSlice};
use crate::dom::gamepadbutton::GamepadButton;
-use crate::dom::globalscope::GlobalScope;
+use crate::dom::window::Window;
use crate::script_runtime::CanGc;
// https://w3c.github.io/gamepad/#gamepadbutton-interface
@@ -28,13 +28,13 @@ impl GamepadButtonList {
}
pub(crate) fn new(
- global: &GlobalScope,
+ window: &Window,
list: &[&GamepadButton],
can_gc: CanGc,
) -> DomRoot<GamepadButtonList> {
reflect_dom_object(
Box::new(GamepadButtonList::new_inherited(list)),
- global,
+ window,
can_gc,
)
}
@@ -62,27 +62,27 @@ impl GamepadButtonListMethods<crate::DomTypeHolder> for GamepadButtonList {
impl GamepadButtonList {
/// Initialize the number of buttons in the "standard" gamepad mapping.
/// <https://www.w3.org/TR/gamepad/#dfn-initializing-buttons>
- pub(crate) fn init_buttons(global: &GlobalScope, can_gc: CanGc) -> DomRoot<GamepadButtonList> {
+ pub(crate) fn init_buttons(window: &Window, can_gc: CanGc) -> DomRoot<GamepadButtonList> {
let standard_buttons = &[
- GamepadButton::new(global, false, false, can_gc), // Bottom button in right cluster
- GamepadButton::new(global, false, false, can_gc), // Right button in right cluster
- GamepadButton::new(global, false, false, can_gc), // Left button in right cluster
- GamepadButton::new(global, false, false, can_gc), // Top button in right cluster
- GamepadButton::new(global, false, false, can_gc), // Top left front button
- GamepadButton::new(global, false, false, can_gc), // Top right front button
- GamepadButton::new(global, false, false, can_gc), // Bottom left front button
- GamepadButton::new(global, false, false, can_gc), // Bottom right front button
- GamepadButton::new(global, false, false, can_gc), // Left button in center cluster
- GamepadButton::new(global, false, false, can_gc), // Right button in center cluster
- GamepadButton::new(global, false, false, can_gc), // Left stick pressed button
- GamepadButton::new(global, false, false, can_gc), // Right stick pressed button
- GamepadButton::new(global, false, false, can_gc), // Top button in left cluster
- GamepadButton::new(global, false, false, can_gc), // Bottom button in left cluster
- GamepadButton::new(global, false, false, can_gc), // Left button in left cluster
- GamepadButton::new(global, false, false, can_gc), // Right button in left cluster
- GamepadButton::new(global, false, false, can_gc), // Center button in center cluster
+ GamepadButton::new(window, false, false, can_gc), // Bottom button in right cluster
+ GamepadButton::new(window, false, false, can_gc), // Right button in right cluster
+ GamepadButton::new(window, false, false, can_gc), // Left button in right cluster
+ GamepadButton::new(window, false, false, can_gc), // Top button in right cluster
+ GamepadButton::new(window, false, false, can_gc), // Top left front button
+ GamepadButton::new(window, false, false, can_gc), // Top right front button
+ GamepadButton::new(window, false, false, can_gc), // Bottom left front button
+ GamepadButton::new(window, false, false, can_gc), // Bottom right front button
+ GamepadButton::new(window, false, false, can_gc), // Left button in center cluster
+ GamepadButton::new(window, false, false, can_gc), // Right button in center cluster
+ GamepadButton::new(window, false, false, can_gc), // Left stick pressed button
+ GamepadButton::new(window, false, false, can_gc), // Right stick pressed button
+ GamepadButton::new(window, false, false, can_gc), // Top button in left cluster
+ GamepadButton::new(window, false, false, can_gc), // Bottom button in left cluster
+ GamepadButton::new(window, false, false, can_gc), // Left button in left cluster
+ GamepadButton::new(window, false, false, can_gc), // Right button in left cluster
+ GamepadButton::new(window, false, false, can_gc), // Center button in center cluster
];
rooted_vec!(let buttons <- standard_buttons.iter().map(DomRoot::as_traced));
- Self::new(global, buttons.r(), can_gc)
+ Self::new(window, buttons.r(), can_gc)
}
}
diff --git a/components/script/dom/gamepadhapticactuator.rs b/components/script/dom/gamepadhapticactuator.rs
index d19db6d1279..ddea21b97ee 100644
--- a/components/script/dom/gamepadhapticactuator.rs
+++ b/components/script/dom/gamepadhapticactuator.rs
@@ -18,12 +18,12 @@ use crate::dom::bindings::codegen::Bindings::GamepadHapticActuatorBinding::{
use crate::dom::bindings::codegen::Bindings::WindowBinding::Window_Binding::WindowMethods;
use crate::dom::bindings::error::Error;
use crate::dom::bindings::refcounted::{Trusted, TrustedPromise};
-use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object_with_proto};
+use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object};
use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::str::DOMString;
use crate::dom::bindings::utils::to_frozen_array;
-use crate::dom::globalscope::GlobalScope;
use crate::dom::promise::Promise;
+use crate::dom::window::Window;
use crate::realms::InRealm;
use crate::script_runtime::{CanGc, JSContext};
use crate::task_source::SendableTaskSource;
@@ -98,27 +98,17 @@ impl GamepadHapticActuator {
}
pub(crate) fn new(
- global: &GlobalScope,
+ window: &Window,
gamepad_index: u32,
supported_haptic_effects: GamepadSupportedHapticEffects,
can_gc: CanGc,
) -> DomRoot<GamepadHapticActuator> {
- Self::new_with_proto(global, gamepad_index, supported_haptic_effects, can_gc)
- }
-
- fn new_with_proto(
- global: &GlobalScope,
- gamepad_index: u32,
- supported_haptic_effects: GamepadSupportedHapticEffects,
- can_gc: CanGc,
- ) -> DomRoot<GamepadHapticActuator> {
- reflect_dom_object_with_proto(
+ reflect_dom_object(
Box::new(GamepadHapticActuator::new_inherited(
gamepad_index,
supported_haptic_effects,
)),
- global,
- None,
+ window,
can_gc,
)
}
diff --git a/components/script/dom/globalscope.rs b/components/script/dom/globalscope.rs
index efa9a9a97ab..527d03eed4e 100644
--- a/components/script/dom/globalscope.rs
+++ b/components/script/dom/globalscope.rs
@@ -18,18 +18,17 @@ use base::id::{
ServiceWorkerId, ServiceWorkerRegistrationId, WebViewId,
};
use constellation_traits::{
- BlobData, BlobImpl, BroadcastMsg, FileBlob, MessagePortImpl, MessagePortMsg, PortMessageTask,
- ScriptToConstellationChan, ScriptToConstellationMessage,
+ BlobData, BlobImpl, BroadcastMsg, FileBlob, LoadData, LoadOrigin, MessagePortImpl,
+ MessagePortMsg, PortMessageTask, ScriptToConstellationChan, ScriptToConstellationMessage,
};
use content_security_policy::{
- CheckResult, CspList, PolicyDisposition, PolicySource, Violation, ViolationResource,
+ CheckResult, CspList, Destination, Initiator, NavigationCheckType, ParserMetadata,
+ PolicyDisposition, PolicySource, Request, Violation, ViolationResource,
};
use crossbeam_channel::Sender;
use devtools_traits::{PageError, ScriptToDevtoolsControlMsg};
use dom_struct::dom_struct;
-use embedder_traits::{
- EmbedderMsg, GamepadEvent, GamepadSupportedHapticEffects, GamepadUpdateType,
-};
+use embedder_traits::EmbedderMsg;
use http::HeaderMap;
use hyper_serde::Serde;
use ipc_channel::ipc::{self, IpcSender};
@@ -64,6 +63,7 @@ use profile_traits::{ipc as profile_ipc, mem as profile_mem, time as profile_tim
use script_bindings::interfaces::GlobalScopeHelpers;
use servo_url::{ImmutableOrigin, MutableOrigin, ServoUrl};
use timers::{TimerEventId, TimerEventRequest, TimerSource};
+use url::Origin;
use uuid::Uuid;
#[cfg(feature = "webgpu")]
use webgpu_traits::{DeviceLostReason, WebGPUDevice};
@@ -81,9 +81,7 @@ use crate::dom::bindings::codegen::Bindings::FunctionBinding::Function;
use crate::dom::bindings::codegen::Bindings::ImageBitmapBinding::{
ImageBitmapOptions, ImageBitmapSource,
};
-use crate::dom::bindings::codegen::Bindings::NavigatorBinding::NavigatorMethods;
use crate::dom::bindings::codegen::Bindings::NotificationBinding::NotificationPermissionCallback;
-use crate::dom::bindings::codegen::Bindings::PerformanceBinding::Performance_Binding::PerformanceMethods;
use crate::dom::bindings::codegen::Bindings::PermissionStatusBinding::{
PermissionName, PermissionState,
};
@@ -113,8 +111,6 @@ use crate::dom::event::{Event, EventBubbles, EventCancelable, EventStatus};
use crate::dom::eventsource::EventSource;
use crate::dom::eventtarget::EventTarget;
use crate::dom::file::File;
-use crate::dom::gamepad::{Gamepad, contains_user_gesture};
-use crate::dom::gamepadevent::GamepadEventType;
use crate::dom::htmlscriptelement::{ScriptId, SourceCode};
use crate::dom::imagebitmap::ImageBitmap;
use crate::dom::messageevent::MessageEvent;
@@ -2957,6 +2953,33 @@ impl GlobalScope {
is_js_evaluation_allowed == CheckResult::Allowed
}
+ pub(crate) fn should_navigation_request_be_blocked(&self, load_data: &LoadData) -> bool {
+ let Some(csp_list) = self.get_csp_list() else {
+ return false;
+ };
+ let request = Request {
+ url: load_data.url.clone().into_url(),
+ origin: match &load_data.load_origin {
+ LoadOrigin::Script(immutable_origin) => immutable_origin.clone().into_url_origin(),
+ _ => Origin::new_opaque(),
+ },
+ // TODO: populate this field correctly
+ redirect_count: 0,
+ destination: Destination::None,
+ initiator: Initiator::None,
+ nonce: "".to_owned(),
+ integrity_metadata: "".to_owned(),
+ parser_metadata: ParserMetadata::None,
+ };
+ // TODO: set correct navigation check type for form submission if applicable
+ let (result, violations) =
+ csp_list.should_navigation_request_be_blocked(&request, NavigationCheckType::Other);
+
+ self.report_csp_violations(violations);
+
+ result == CheckResult::Blocked
+ }
+
pub(crate) fn create_image_bitmap(
&self,
image: ImageBitmapSource,
@@ -3287,134 +3310,6 @@ impl GlobalScope {
}
}
- pub(crate) fn handle_gamepad_event(&self, gamepad_event: GamepadEvent) {
- match gamepad_event {
- GamepadEvent::Connected(index, name, bounds, supported_haptic_effects) => {
- self.handle_gamepad_connect(
- index.0,
- name,
- bounds.axis_bounds,
- bounds.button_bounds,
- supported_haptic_effects,
- );
- },
- GamepadEvent::Disconnected(index) => {
- self.handle_gamepad_disconnect(index.0);
- },
- GamepadEvent::Updated(index, update_type) => {
- self.receive_new_gamepad_button_or_axis(index.0, update_type);
- },
- };
- }
-
- /// <https://www.w3.org/TR/gamepad/#dfn-gamepadconnected>
- fn handle_gamepad_connect(
- &self,
- // As the spec actually defines how to set the gamepad index, the GilRs index
- // is currently unused, though in practice it will almost always be the same.
- // More infra is currently needed to track gamepads across windows.
- _index: usize,
- name: String,
- axis_bounds: (f64, f64),
- button_bounds: (f64, f64),
- supported_haptic_effects: GamepadSupportedHapticEffects,
- ) {
- // TODO: 2. If document is not null and is not allowed to use the "gamepad" permission,
- // then abort these steps.
- let this = Trusted::new(self);
- self.task_manager()
- .gamepad_task_source()
- .queue(task!(gamepad_connected: move || {
- let global = this.root();
-
- if let Some(window) = global.downcast::<Window>() {
- let navigator = window.Navigator();
- let selected_index = navigator.select_gamepad_index();
- let gamepad = Gamepad::new(
- &global,
- selected_index,
- name,
- "standard".into(),
- axis_bounds,
- button_bounds,
- supported_haptic_effects,
- false,
- CanGc::note(),
- );
- navigator.set_gamepad(selected_index as usize, &gamepad, CanGc::note());
- }
- }));
- }
-
- /// <https://www.w3.org/TR/gamepad/#dfn-gamepaddisconnected>
- pub(crate) fn handle_gamepad_disconnect(&self, index: usize) {
- let this = Trusted::new(self);
- self.task_manager()
- .gamepad_task_source()
- .queue(task!(gamepad_disconnected: move || {
- let global = this.root();
- if let Some(window) = global.downcast::<Window>() {
- let navigator = window.Navigator();
- if let Some(gamepad) = navigator.get_gamepad(index) {
- if window.Document().is_fully_active() {
- gamepad.update_connected(false, gamepad.exposed(), CanGc::note());
- navigator.remove_gamepad(index);
- }
- }
- }
- }));
- }
-
- /// <https://www.w3.org/TR/gamepad/#receiving-inputs>
- pub(crate) fn receive_new_gamepad_button_or_axis(
- &self,
- index: usize,
- update_type: GamepadUpdateType,
- ) {
- let this = Trusted::new(self);
-
- // <https://w3c.github.io/gamepad/#dfn-update-gamepad-state>
- self.task_manager().gamepad_task_source().queue(
- task!(update_gamepad_state: move || {
- let global = this.root();
- if let Some(window) = global.downcast::<Window>() {
- let navigator = window.Navigator();
- if let Some(gamepad) = navigator.get_gamepad(index) {
- let current_time = global.performance().Now();
- gamepad.update_timestamp(*current_time);
- match update_type {
- GamepadUpdateType::Axis(index, value) => {
- gamepad.map_and_normalize_axes(index, value);
- },
- GamepadUpdateType::Button(index, value) => {
- gamepad.map_and_normalize_buttons(index, value);
- }
- };
- if !navigator.has_gamepad_gesture() && contains_user_gesture(update_type) {
- navigator.set_has_gamepad_gesture(true);
- navigator.GetGamepads()
- .iter()
- .filter_map(|g| g.as_ref())
- .for_each(|gamepad| {
- gamepad.set_exposed(true);
- gamepad.update_timestamp(*current_time);
- let new_gamepad = Trusted::new(&**gamepad);
- if window.Document().is_fully_active() {
- global.task_manager().gamepad_task_source().queue(
- task!(update_gamepad_connect: move || {
- let gamepad = new_gamepad.root();
- gamepad.notify_event(GamepadEventType::Connected, CanGc::note());
- })
- );
- }
- });
- }
- }
- }
- })
- );
- }
-
pub(crate) fn current_group_label(&self) -> Option<DOMString> {
self.console_group_stack
.borrow()
diff --git a/components/script/dom/gpucanvascontext.rs b/components/script/dom/gpucanvascontext.rs
index 5304d0f5d3b..f47e1dfddd1 100644
--- a/components/script/dom/gpucanvascontext.rs
+++ b/components/script/dom/gpucanvascontext.rs
@@ -3,7 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use dom_struct::dom_struct;
-use script_layout_interface::HTMLCanvasDataSource;
+use webrender_api::ImageKey;
use crate::dom::bindings::codegen::Bindings::GPUCanvasContextBinding::GPUCanvasContextMethods;
use crate::dom::bindings::codegen::UnionTypes;
@@ -31,7 +31,7 @@ impl GPUCanvasContextMethods<crate::DomTypeHolder> for GPUCanvasContext {
}
impl LayoutCanvasRenderingContextHelpers for LayoutDom<'_, GPUCanvasContext> {
- fn canvas_data_source(self) -> HTMLCanvasDataSource {
+ fn canvas_data_source(self) -> Option<ImageKey> {
unimplemented!()
}
}
diff --git a/components/script/dom/htmlcanvaselement.rs b/components/script/dom/htmlcanvaselement.rs
index cc6df183f42..56e008839ba 100644
--- a/components/script/dom/htmlcanvaselement.rs
+++ b/components/script/dom/htmlcanvaselement.rs
@@ -21,7 +21,7 @@ use image::{ColorType, ImageEncoder};
use ipc_channel::ipc::{self as ipcchan};
use js::error::throw_type_error;
use js::rust::{HandleObject, HandleValue};
-use script_layout_interface::{HTMLCanvasData, HTMLCanvasDataSource};
+use script_layout_interface::HTMLCanvasData;
use servo_media::streams::MediaStreamType;
use servo_media::streams::registry::MediaStreamId;
use snapshot::Snapshot;
@@ -201,7 +201,7 @@ impl LayoutHTMLCanvasElementHelpers for LayoutDom<'_, HTMLCanvasElement> {
Some(RenderingContext::WebGL2(context)) => context.to_layout().canvas_data_source(),
#[cfg(feature = "webgpu")]
Some(RenderingContext::WebGPU(context)) => context.to_layout().canvas_data_source(),
- Some(RenderingContext::Placeholder(_)) | None => HTMLCanvasDataSource::Empty,
+ Some(RenderingContext::Placeholder(_)) | None => None,
}
};
diff --git a/components/script/dom/htmlelement.rs b/components/script/dom/htmlelement.rs
index e7efbde9b1d..59b71543d6d 100644
--- a/components/script/dom/htmlelement.rs
+++ b/components/script/dom/htmlelement.rs
@@ -116,7 +116,7 @@ impl HTMLElement {
/// `.outerText` in JavaScript.`
///
/// <https://html.spec.whatwg.org/multipage/#get-the-text-steps>
- fn get_inner_outer_text(&self, can_gc: CanGc) -> DOMString {
+ pub(crate) fn get_inner_outer_text(&self, can_gc: CanGc) -> DOMString {
let node = self.upcast::<Node>();
let window = node.owner_window();
let element = self.as_element();
@@ -134,6 +134,16 @@ impl HTMLElement {
DOMString::from(text)
}
+
+ /// <https://html.spec.whatwg.org/multipage/#set-the-inner-text-steps>
+ pub(crate) fn set_inner_text(&self, input: DOMString, can_gc: CanGc) {
+ // Step 1: Let fragment be the rendered text fragment for value given element's node
+ // document.
+ let fragment = self.rendered_text_fragment(input, can_gc);
+
+ // Step 2: Replace all with fragment within element.
+ Node::replace_all(Some(fragment.upcast()), self.upcast::<Node>(), can_gc);
+ }
}
impl HTMLElementMethods<crate::DomTypeHolder> for HTMLElement {
@@ -494,12 +504,7 @@ impl HTMLElementMethods<crate::DomTypeHolder> for HTMLElement {
/// <https://html.spec.whatwg.org/multipage/#set-the-inner-text-steps>
fn SetInnerText(&self, input: DOMString, can_gc: CanGc) {
- // Step 1: Let fragment be the rendered text fragment for value given element's node
- // document.
- let fragment = self.rendered_text_fragment(input, can_gc);
-
- // Step 2: Replace all with fragment within element.
- Node::replace_all(Some(fragment.upcast()), self.upcast::<Node>(), can_gc);
+ self.set_inner_text(input, can_gc)
}
/// <https://html.spec.whatwg.org/multipage/#dom-outertext>
diff --git a/components/script/dom/htmliframeelement.rs b/components/script/dom/htmliframeelement.rs
index c5194c4527f..0fbff86e44a 100644
--- a/components/script/dom/htmliframeelement.rs
+++ b/components/script/dom/htmliframeelement.rs
@@ -162,8 +162,13 @@ impl HTMLIFrameElement {
if load_data.url.scheme() == "javascript" {
let window_proxy = self.GetContentWindow();
if let Some(window_proxy) = window_proxy {
+ if document
+ .global()
+ .should_navigation_request_be_blocked(&load_data)
+ {
+ return;
+ }
// Important re security. See https://github.com/servo/servo/issues/23373
- // TODO: check according to https://w3c.github.io/webappsec-csp/#should-block-navigation-request
if ScriptThread::check_load_origin(&load_data.load_origin, &document.url().origin())
{
ScriptThread::eval_js_url(&window_proxy.global(), &mut load_data, can_gc);
@@ -274,6 +279,7 @@ impl HTMLIFrameElement {
Some(document.insecure_requests_policy()),
document.has_trustworthy_ancestor_or_current_origin(),
);
+ load_data.policy_container = Some(window.as_global_scope().policy_container());
let element = self.upcast::<Element>();
load_data.srcdoc = String::from(element.get_string_attribute(&local_name!("srcdoc")));
self.navigate_or_reload_child_browsing_context(
@@ -356,7 +362,7 @@ impl HTMLIFrameElement {
None
};
- let load_data = LoadData::new(
+ let mut load_data = LoadData::new(
LoadOrigin::Script(document.origin().immutable().clone()),
url,
creator_pipeline_id,
@@ -373,6 +379,10 @@ impl HTMLIFrameElement {
let is_about_blank =
pipeline_id.is_some() && pipeline_id == self.about_blank_pipeline_id.get();
+ if is_about_blank {
+ load_data.policy_container = Some(window.as_global_scope().policy_container());
+ }
+
let history_handling = if is_about_blank {
NavigationHistoryBehavior::Replace
} else {
@@ -402,7 +412,7 @@ impl HTMLIFrameElement {
let document = self.owner_document();
let window = self.owner_window();
let pipeline_id = Some(window.pipeline_id());
- let load_data = LoadData::new(
+ let mut load_data = LoadData::new(
LoadOrigin::Script(document.origin().immutable().clone()),
url,
pipeline_id,
@@ -412,6 +422,7 @@ impl HTMLIFrameElement {
Some(document.insecure_requests_policy()),
document.has_trustworthy_ancestor_or_current_origin(),
);
+ load_data.policy_container = Some(window.as_global_scope().policy_container());
let browsing_context_id = BrowsingContextId::new();
let webview_id = window.window_proxy().webview_id();
self.pipeline_id.set(None);
diff --git a/components/script/dom/htmlscriptelement.rs b/components/script/dom/htmlscriptelement.rs
index 58853f600d2..9d0ca807748 100644
--- a/components/script/dom/htmlscriptelement.rs
+++ b/components/script/dom/htmlscriptelement.rs
@@ -32,6 +32,7 @@ use net_traits::{
};
use servo_config::pref;
use servo_url::{ImmutableOrigin, ServoUrl};
+use style::attr::AttrValue;
use style::str::{HTML_SPACE_CHARACTERS, StaticStringVec};
use stylo_atoms::Atom;
use uuid::Uuid;
@@ -44,7 +45,9 @@ use crate::dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
use crate::dom::bindings::codegen::Bindings::HTMLScriptElementBinding::HTMLScriptElementMethods;
use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
use crate::dom::bindings::codegen::GenericBindings::HTMLElementBinding::HTMLElement_Binding::HTMLElementMethods;
-use crate::dom::bindings::codegen::UnionTypes::TrustedScriptURLOrUSVString;
+use crate::dom::bindings::codegen::UnionTypes::{
+ TrustedScriptOrString, TrustedScriptURLOrUSVString,
+};
use crate::dom::bindings::error::Fallible;
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::refcounted::Trusted;
@@ -64,6 +67,8 @@ use crate::dom::globalscope::GlobalScope;
use crate::dom::htmlelement::HTMLElement;
use crate::dom::node::{ChildrenMutation, CloneChildrenFlag, Node, NodeTraits};
use crate::dom::performanceresourcetiming::InitiatorType;
+use crate::dom::trustedscript::TrustedScript;
+use crate::dom::trustedscripturl::TrustedScriptURL;
use crate::dom::virtualmethods::VirtualMethods;
use crate::fetch::create_a_potential_cors_request;
use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener};
@@ -667,7 +672,7 @@ impl HTMLScriptElement {
// Step 5. Let source text be el's child text content.
// Step 6. If el has no src attribute, and source text is the empty string, then return.
- let text = self.Text();
+ let text = self.text();
if text.is_empty() && !element.has_attribute(&local_name!("src")) {
return;
}
@@ -1272,6 +1277,15 @@ impl HTMLScriptElement {
let event = Event::new(window.upcast(), type_, bubbles, cancelable, can_gc);
event.fire(self.upcast(), can_gc)
}
+
+ fn text(&self) -> DOMString {
+ match self.Text() {
+ TrustedScriptOrString::String(value) => value,
+ TrustedScriptOrString::TrustedScript(trusted_script) => {
+ DOMString::from(trusted_script.to_string())
+ },
+ }
+ }
}
impl VirtualMethods for HTMLScriptElement {
@@ -1286,7 +1300,7 @@ impl VirtualMethods for HTMLScriptElement {
if *attr.local_name() == local_name!("src") {
if let AttributeMutation::Set(_) = mutation {
if !self.parser_inserted.get() && self.upcast::<Node>().is_connected() {
- self.prepare(CanGc::note());
+ self.prepare(can_gc);
}
}
}
@@ -1344,10 +1358,25 @@ impl VirtualMethods for HTMLScriptElement {
impl HTMLScriptElementMethods<crate::DomTypeHolder> for HTMLScriptElement {
// https://html.spec.whatwg.org/multipage/#dom-script-src
- make_trusted_type_url_getter!(Src, "src");
+ fn Src(&self) -> TrustedScriptURLOrUSVString {
+ let element = self.upcast::<Element>();
+ element.get_trusted_type_url_attribute(&local_name!("src"))
+ }
- // https://html.spec.whatwg.org/multipage/#dom-script-src
- make_trusted_type_url_setter!(SetSrc, "src");
+ /// <https://w3c.github.io/trusted-types/dist/spec/#the-src-idl-attribute>
+ fn SetSrc(&self, value: TrustedScriptURLOrUSVString, can_gc: CanGc) -> Fallible<()> {
+ let element = self.upcast::<Element>();
+ let local_name = &local_name!("src");
+ let value = TrustedScriptURL::get_trusted_script_url_compliant_string(
+ &element.owner_global(),
+ value,
+ "HTMLScriptElement",
+ local_name,
+ can_gc,
+ )?;
+ element.set_attribute(local_name, AttrValue::String(value), can_gc);
+ Ok(())
+ }
// https://html.spec.whatwg.org/multipage/#dom-script-type
make_getter!(Type, "type");
@@ -1416,14 +1445,77 @@ impl HTMLScriptElementMethods<crate::DomTypeHolder> for HTMLScriptElement {
// https://html.spec.whatwg.org/multipage/#dom-script-referrerpolicy
make_setter!(SetReferrerPolicy, "referrerpolicy");
- // https://html.spec.whatwg.org/multipage/#dom-script-text
- fn Text(&self) -> DOMString {
- self.upcast::<Node>().child_text_content()
+ /// <https://w3c.github.io/trusted-types/dist/spec/#dom-htmlscriptelement-innertext>
+ fn InnerText(&self, can_gc: CanGc) -> TrustedScriptOrString {
+ // Step 1: Return the result of running get the text steps with this.
+ TrustedScriptOrString::String(self.upcast::<HTMLElement>().get_inner_outer_text(can_gc))
}
- // https://html.spec.whatwg.org/multipage/#dom-script-text
- fn SetText(&self, value: DOMString, can_gc: CanGc) {
- self.upcast::<Node>().SetTextContent(Some(value), can_gc)
+ /// <https://w3c.github.io/trusted-types/dist/spec/#the-innerText-idl-attribute>
+ fn SetInnerText(&self, input: TrustedScriptOrString, can_gc: CanGc) -> Fallible<()> {
+ // Step 1: Let value be the result of calling Get Trusted Type compliant string with TrustedScript,
+ // this's relevant global object, the given value, HTMLScriptElement innerText, and script.
+ let value = TrustedScript::get_trusted_script_compliant_string(
+ &self.owner_global(),
+ input,
+ "HTMLScriptElement",
+ "innerText",
+ can_gc,
+ )?;
+ // Step 3: Run set the inner text steps with this and value.
+ self.upcast::<HTMLElement>()
+ .set_inner_text(DOMString::from(value), can_gc);
+ Ok(())
+ }
+
+ /// <https://html.spec.whatwg.org/multipage/#dom-script-text>
+ fn Text(&self) -> TrustedScriptOrString {
+ TrustedScriptOrString::String(self.upcast::<Node>().child_text_content())
+ }
+
+ /// <https://w3c.github.io/trusted-types/dist/spec/#the-text-idl-attribute>
+ fn SetText(&self, value: TrustedScriptOrString, can_gc: CanGc) -> Fallible<()> {
+ // Step 1: Let value be the result of calling Get Trusted Type compliant string with TrustedScript,
+ // this's relevant global object, the given value, HTMLScriptElement text, and script.
+ let value = TrustedScript::get_trusted_script_compliant_string(
+ &self.owner_global(),
+ value,
+ "HTMLScriptElement",
+ "text",
+ can_gc,
+ )?;
+ // Step 2: Set this's script text value to the given value.
+ // TODO: Implement for https://w3c.github.io/trusted-types/dist/spec/#prepare-script-text
+ // Step 3: String replace all with the given value within this.
+ Node::string_replace_all(DOMString::from(value), self.upcast::<Node>(), can_gc);
+ Ok(())
+ }
+
+ /// <https://w3c.github.io/trusted-types/dist/spec/#the-textContent-idl-attribute>
+ fn GetTextContent(&self) -> Option<TrustedScriptOrString> {
+ // Step 1: Return the result of running get text content with this.
+ Some(TrustedScriptOrString::String(
+ self.upcast::<Node>().GetTextContent()?,
+ ))
+ }
+
+ /// <https://w3c.github.io/trusted-types/dist/spec/#the-textContent-idl-attribute>
+ fn SetTextContent(&self, value: Option<TrustedScriptOrString>, can_gc: CanGc) -> Fallible<()> {
+ // Step 1: Let value be the result of calling Get Trusted Type compliant string with TrustedScript,
+ // this's relevant global object, the given value, HTMLScriptElement textContent, and script.
+ let value = TrustedScript::get_trusted_script_compliant_string(
+ &self.owner_global(),
+ value.unwrap_or(TrustedScriptOrString::String(DOMString::from(""))),
+ "HTMLScriptElement",
+ "textContent",
+ can_gc,
+ )?;
+ // Step 2: Set this's script text value to value.
+ // TODO: Implement for https://w3c.github.io/trusted-types/dist/spec/#prepare-script-text
+ // Step 3: Run set text content with this and value.
+ self.upcast::<Node>()
+ .SetTextContent(Some(DOMString::from(value)), can_gc);
+ Ok(())
}
}
diff --git a/components/script/dom/macros.rs b/components/script/dom/macros.rs
index 997341984c6..cc44497d0b9 100644
--- a/components/script/dom/macros.rs
+++ b/components/script/dom/macros.rs
@@ -122,32 +122,6 @@ macro_rules! make_url_setter(
);
#[macro_export]
-macro_rules! make_trusted_type_url_getter(
- ( $attr:ident, $htmlname:tt ) => (
- fn $attr(&self) -> TrustedScriptURLOrUSVString {
- use $crate::dom::bindings::inheritance::Castable;
- use $crate::dom::element::Element;
- let element = self.upcast::<Element>();
- element.get_trusted_type_url_attribute(&html5ever::local_name!($htmlname))
- }
- );
-);
-
-#[macro_export]
-macro_rules! make_trusted_type_url_setter(
- ( $attr:ident, $htmlname:tt ) => (
- fn $attr(&self, value: TrustedScriptURLOrUSVString, can_gc: CanGc) -> Fallible<()> {
- use $crate::dom::bindings::inheritance::Castable;
- use $crate::dom::element::Element;
- use $crate::script_runtime::CanGc;
- let element = self.upcast::<Element>();
- element.set_trusted_type_url_attribute(&html5ever::local_name!($htmlname),
- value, can_gc)
- }
- );
-);
-
-#[macro_export]
macro_rules! make_form_action_getter(
( $attr:ident, $htmlname:tt ) => (
fn $attr(&self) -> DOMString {
diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs
index 2caec47de25..e9d36a01426 100644
--- a/components/script/dom/node.rs
+++ b/components/script/dom/node.rs
@@ -110,7 +110,7 @@ use crate::dom::pointerevent::{PointerEvent, PointerId};
use crate::dom::processinginstruction::ProcessingInstruction;
use crate::dom::range::WeakRangeVec;
use crate::dom::raredata::NodeRareData;
-use crate::dom::servoparser::serialize_html_fragment;
+use crate::dom::servoparser::{ServoParser, serialize_html_fragment};
use crate::dom::shadowroot::{IsUserAgentWidget, LayoutShadowRootHelpers, ShadowRoot};
use crate::dom::stylesheetlist::StyleSheetListOwner;
use crate::dom::svgsvgelement::{LayoutSVGSVGElementHelpers, SVGSVGElement};
@@ -316,6 +316,34 @@ impl Node {
}
}
+ /// Implements the "unsafely set HTML" algorithm as specified in:
+ /// <https://html.spec.whatwg.org/multipage/#concept-unsafely-set-html>
+ pub fn unsafely_set_html(
+ target: &Node,
+ context_element: &Element,
+ html: DOMString,
+ can_gc: CanGc,
+ ) {
+ // Step 1. Let newChildren be the result of the HTML fragment parsing algorithm.
+ let new_children = ServoParser::parse_html_fragment(context_element, html, true, can_gc);
+
+ // Step 2. Let fragment be a new DocumentFragment whose node document is contextElement's node document.
+
+ let context_document = context_element.owner_document();
+ let fragment = DocumentFragment::new(&context_document, can_gc);
+
+ // Step 3. For each node in newChildren, append node to fragment.
+ for child in new_children {
+ fragment
+ .upcast::<Node>()
+ .AppendChild(&child, can_gc)
+ .unwrap();
+ }
+
+ // Step 4. Replace all with fragment within target.
+ Node::replace_all(Some(fragment.upcast()), target, can_gc);
+ }
+
pub(crate) fn clean_up_style_and_layout_data(&self) {
self.owner_doc().cancel_animations_for_node(self);
self.style_data.borrow_mut().take();
diff --git a/components/script/dom/servoparser/mod.rs b/components/script/dom/servoparser/mod.rs
index 0650fde676e..5878573d552 100644
--- a/components/script/dom/servoparser/mod.rs
+++ b/components/script/dom/servoparser/mod.rs
@@ -21,6 +21,7 @@ use html5ever::{Attribute, ExpandedName, LocalName, QualName, local_name, ns};
use hyper_serde::Serde;
use markup5ever::TokenizerResult;
use mime::{self, Mime};
+use net_traits::policy_container::PolicyContainer;
use net_traits::request::RequestId;
use net_traits::{
FetchMetadata, FetchResponseListener, Metadata, NetworkError, ResourceFetchTiming,
@@ -813,6 +814,27 @@ impl ParserContext {
pushed_entry_index: None,
}
}
+
+ pub(crate) fn append_parent_to_csp_list(&self, policy_container: Option<&PolicyContainer>) {
+ let Some(policy_container) = policy_container else {
+ return;
+ };
+ let Some(parent_csp_list) = &policy_container.csp_list else {
+ return;
+ };
+ let Some(parser) = self.parser.as_ref().map(|p| p.root()) else {
+ return;
+ };
+ let new_csp_list = match parser.document.get_csp_list() {
+ None => parent_csp_list.clone(),
+ Some(original_csp_list) => {
+ let mut appended_csp_list = original_csp_list.clone();
+ appended_csp_list.append(parent_csp_list.clone());
+ appended_csp_list.to_owned()
+ },
+ };
+ parser.document.set_csp_list(Some(new_csp_list));
+ }
}
impl FetchResponseListener for ParserContext {
diff --git a/components/script/dom/shadowroot.rs b/components/script/dom/shadowroot.rs
index 72b074ed6f4..14d9c24b10e 100644
--- a/components/script/dom/shadowroot.rs
+++ b/components/script/dom/shadowroot.rs
@@ -453,6 +453,15 @@ impl ShadowRootMethods<crate::DomTypeHolder> for ShadowRoot {
self.slot_assignment_mode
}
+ /// <https://html.spec.whatwg.org/multipage/#dom-shadowroot-sethtmlunsafe>
+ fn SetHTMLUnsafe(&self, html: DOMString, can_gc: CanGc) {
+ // Step 2. Unsafely set HTMl given this, this's shadow host, and complaintHTML
+ let target = self.upcast::<Node>();
+ let context_element = self.Host();
+
+ Node::unsafely_set_html(target, &context_element, html, can_gc);
+ }
+
// https://dom.spec.whatwg.org/#dom-shadowroot-onslotchange
event_handler!(onslotchange, GetOnslotchange, SetOnslotchange);
}
diff --git a/components/script/dom/trustedscript.rs b/components/script/dom/trustedscript.rs
index 5ce51c24989..648fcc8c239 100644
--- a/components/script/dom/trustedscript.rs
+++ b/components/script/dom/trustedscript.rs
@@ -1,14 +1,19 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+use std::fmt;
use dom_struct::dom_struct;
use crate::dom::bindings::codegen::Bindings::TrustedScriptBinding::TrustedScriptMethods;
+use crate::dom::bindings::codegen::UnionTypes::TrustedScriptOrString;
+use crate::dom::bindings::error::Fallible;
use crate::dom::bindings::reflector::{Reflector, reflect_dom_object};
use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::str::DOMString;
use crate::dom::globalscope::GlobalScope;
+use crate::dom::trustedtypepolicy::TrustedType;
+use crate::dom::trustedtypepolicyfactory::TrustedTypePolicyFactory;
use crate::script_runtime::CanGc;
#[dom_struct]
@@ -30,6 +35,37 @@ impl TrustedScript {
pub(crate) fn new(data: String, global: &GlobalScope, can_gc: CanGc) -> DomRoot<Self> {
reflect_dom_object(Box::new(Self::new_inherited(data)), global, can_gc)
}
+
+ pub(crate) fn get_trusted_script_compliant_string(
+ global: &GlobalScope,
+ value: TrustedScriptOrString,
+ containing_class: &str,
+ field: &str,
+ can_gc: CanGc,
+ ) -> Fallible<String> {
+ match value {
+ TrustedScriptOrString::String(value) => {
+ let sink = format!("{} {}", containing_class, field);
+ TrustedTypePolicyFactory::get_trusted_type_compliant_string(
+ TrustedType::TrustedScript,
+ global,
+ value.as_ref().to_owned(),
+ &sink,
+ "'script'",
+ can_gc,
+ )
+ },
+
+ TrustedScriptOrString::TrustedScript(trusted_script) => Ok(trusted_script.to_string()),
+ }
+ }
+}
+
+impl fmt::Display for TrustedScript {
+ #[inline]
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.write_str(&self.data)
+ }
}
impl TrustedScriptMethods<crate::DomTypeHolder> for TrustedScript {
diff --git a/components/script/dom/trustedscripturl.rs b/components/script/dom/trustedscripturl.rs
index ba1e0335abc..3f0aef248b3 100644
--- a/components/script/dom/trustedscripturl.rs
+++ b/components/script/dom/trustedscripturl.rs
@@ -7,10 +7,14 @@ use std::fmt;
use dom_struct::dom_struct;
use crate::dom::bindings::codegen::Bindings::TrustedScriptURLBinding::TrustedScriptURLMethods;
+use crate::dom::bindings::codegen::UnionTypes::TrustedScriptURLOrUSVString;
+use crate::dom::bindings::error::Fallible;
use crate::dom::bindings::reflector::{Reflector, reflect_dom_object};
use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::str::DOMString;
use crate::dom::globalscope::GlobalScope;
+use crate::dom::trustedtypepolicy::TrustedType;
+use crate::dom::trustedtypepolicyfactory::TrustedTypePolicyFactory;
use crate::script_runtime::CanGc;
#[dom_struct]
@@ -32,6 +36,31 @@ impl TrustedScriptURL {
pub(crate) fn new(data: String, global: &GlobalScope, can_gc: CanGc) -> DomRoot<Self> {
reflect_dom_object(Box::new(Self::new_inherited(data)), global, can_gc)
}
+
+ pub(crate) fn get_trusted_script_url_compliant_string(
+ global: &GlobalScope,
+ value: TrustedScriptURLOrUSVString,
+ containing_class: &str,
+ field: &str,
+ can_gc: CanGc,
+ ) -> Fallible<String> {
+ match value {
+ TrustedScriptURLOrUSVString::USVString(value) => {
+ let sink = format!("{} {}", containing_class, field);
+ TrustedTypePolicyFactory::get_trusted_type_compliant_string(
+ TrustedType::TrustedScriptURL,
+ global,
+ value.as_ref().to_owned(),
+ &sink,
+ "'script'",
+ can_gc,
+ )
+ },
+ TrustedScriptURLOrUSVString::TrustedScriptURL(trusted_script_url) => {
+ Ok(trusted_script_url.to_string())
+ },
+ }
+ }
}
impl fmt::Display for TrustedScriptURL {
diff --git a/components/script/dom/trustedtypepolicy.rs b/components/script/dom/trustedtypepolicy.rs
index 2ec5015eb88..d4def7269ed 100644
--- a/components/script/dom/trustedtypepolicy.rs
+++ b/components/script/dom/trustedtypepolicy.rs
@@ -7,6 +7,7 @@ use std::rc::Rc;
use dom_struct::dom_struct;
use js::jsapi::JSObject;
use js::rust::HandleValue;
+use strum_macros::IntoStaticStr;
use crate::dom::bindings::callback::ExceptionHandling;
use crate::dom::bindings::codegen::Bindings::TrustedTypePolicyBinding::TrustedTypePolicyMethods;
@@ -38,6 +39,13 @@ pub struct TrustedTypePolicy {
create_script_url: Option<Rc<CreateScriptURLCallback>>,
}
+#[derive(Clone, IntoStaticStr)]
+pub(crate) enum TrustedType {
+ TrustedHTML,
+ TrustedScript,
+ TrustedScriptURL,
+}
+
impl TrustedTypePolicy {
fn new_inherited(name: String, options: &TrustedTypePolicyOptions) -> Self {
Self {
@@ -59,51 +67,87 @@ impl TrustedTypePolicy {
reflect_dom_object(Box::new(Self::new_inherited(name, options)), global, can_gc)
}
- // TODO(36258): Remove when we refactor get_trusted_type_policy_value to take an enum
- // value to handle which callback to call. The callback should not be exposed outside
- // of the policy object, but is currently used in TrustedPolicyFactory::process_value_with_default_policy
- pub(crate) fn create_script_url(&self) -> Option<Rc<CreateScriptURLCallback>> {
- self.create_script_url.clone()
+ /// <https://w3c.github.io/trusted-types/dist/spec/#get-trusted-type-policy-value-algorithm>
+ fn check_callback_if_missing(throw_if_missing: bool) -> Fallible<Option<String>> {
+ // Step 3.1: If throwIfMissing throw a TypeError.
+ if throw_if_missing {
+ Err(Type("Cannot find type".to_owned()))
+ } else {
+ // Step 3.2: Else return null.
+ Ok(None)
+ }
}
- /// This does not take all arguments as specified. That's because the return type of the
- /// trusted type function and object are not the same. 2 of the 3 string callbacks return
- /// a DOMString, while the other one returns an USVString. Additionally, all three callbacks
- /// have a unique type signature in WebIDL.
- ///
- /// To circumvent these type problems, rather than implementing the full functionality here,
- /// part of the algorithm is implemented on the caller side. There, we only call the callback
- /// and create the object. The rest of the machinery is ensuring the right values pass through
- /// to the relevant callbacks.
- ///
/// <https://w3c.github.io/trusted-types/dist/spec/#get-trusted-type-policy-value-algorithm>
- pub(crate) fn get_trusted_type_policy_value<S, PolicyCallback>(
+ pub(crate) fn get_trusted_type_policy_value(
&self,
- policy_value_callback: PolicyCallback,
+ expected_type: TrustedType,
+ cx: JSContext,
+ input: DOMString,
+ arguments: Vec<HandleValue>,
throw_if_missing: bool,
- ) -> Fallible<Option<S>>
- where
- S: AsRef<str>,
- PolicyCallback: FnOnce() -> Option<Fallible<Option<S>>>,
- {
+ can_gc: CanGc,
+ ) -> Fallible<Option<String>> {
+ rooted!(in(*cx) let this_object: *mut JSObject);
// Step 1: Let functionName be a function name for the given trustedTypeName, based on the following table:
- // Step 2: Let function be policy’s options[functionName].
- let function = policy_value_callback();
- match function {
- // Step 3: If function is null, then:
- None => {
- // Step 3.1: If throwIfMissing throw a TypeError.
- if throw_if_missing {
- Err(Type("Cannot find type".to_owned()))
- } else {
- // Step 3.2: Else return null.
- Ok(None)
- }
+ match expected_type {
+ TrustedType::TrustedHTML => match &self.create_html {
+ // Step 3: If function is null, then:
+ None => TrustedTypePolicy::check_callback_if_missing(throw_if_missing),
+ // Step 2: Let function be policy’s options[functionName].
+ Some(callback) => {
+ // Step 4: Let policyValue be the result of invoking function with value as a first argument,
+ // items of arguments as subsequent arguments, and callback **this** value set to null,
+ // rethrowing any exceptions.
+ callback
+ .Call_(
+ &this_object.handle(),
+ input,
+ arguments,
+ ExceptionHandling::Rethrow,
+ can_gc,
+ )
+ .map(|result| result.map(|str| str.as_ref().to_owned()))
+ },
+ },
+ TrustedType::TrustedScript => match &self.create_script {
+ // Step 3: If function is null, then:
+ None => TrustedTypePolicy::check_callback_if_missing(throw_if_missing),
+ // Step 2: Let function be policy’s options[functionName].
+ Some(callback) => {
+ // Step 4: Let policyValue be the result of invoking function with value as a first argument,
+ // items of arguments as subsequent arguments, and callback **this** value set to null,
+ // rethrowing any exceptions.
+ callback
+ .Call_(
+ &this_object.handle(),
+ input,
+ arguments,
+ ExceptionHandling::Rethrow,
+ can_gc,
+ )
+ .map(|result| result.map(|str| str.as_ref().to_owned()))
+ },
+ },
+ TrustedType::TrustedScriptURL => match &self.create_script_url {
+ // Step 3: If function is null, then:
+ None => TrustedTypePolicy::check_callback_if_missing(throw_if_missing),
+ // Step 2: Let function be policy’s options[functionName].
+ Some(callback) => {
+ // Step 4: Let policyValue be the result of invoking function with value as a first argument,
+ // items of arguments as subsequent arguments, and callback **this** value set to null,
+ // rethrowing any exceptions.
+ callback
+ .Call_(
+ &this_object.handle(),
+ input,
+ arguments,
+ ExceptionHandling::Rethrow,
+ can_gc,
+ )
+ .map(|result| result.map(|str| str.as_ref().to_owned()))
+ },
},
- // Step 4: Let policyValue be the result of invoking function with value as a first argument,
- // items of arguments as subsequent arguments, and callback **this** value set to null,
- // rethrowing any exceptions.
- Some(policy_value) => policy_value,
}
}
@@ -118,27 +162,30 @@ impl TrustedTypePolicy {
/// to the relevant callbacks.
///
/// <https://w3c.github.io/trusted-types/dist/spec/#create-a-trusted-type-algorithm>
- pub(crate) fn create_trusted_type<R, S, PolicyCallback, TrustedTypeCallback>(
+ pub(crate) fn create_trusted_type<R, TrustedTypeCallback>(
&self,
- policy_value_callback: PolicyCallback,
+ expected_type: TrustedType,
+ cx: JSContext,
+ input: DOMString,
+ arguments: Vec<HandleValue>,
trusted_type_creation_callback: TrustedTypeCallback,
+ can_gc: CanGc,
) -> Fallible<DomRoot<R>>
where
R: DomObject,
- S: AsRef<str>,
- PolicyCallback: FnOnce() -> Option<Fallible<Option<S>>>,
TrustedTypeCallback: FnOnce(String) -> DomRoot<R>,
{
// Step 1: Let policyValue be the result of executing Get Trusted Type policy value
// with the same arguments as this algorithm and additionally true as throwIfMissing.
- let policy_value = self.get_trusted_type_policy_value(policy_value_callback, true);
+ let policy_value =
+ self.get_trusted_type_policy_value(expected_type, cx, input, arguments, true, can_gc);
match policy_value {
// Step 2: If the algorithm threw an error, rethrow the error and abort the following steps.
Err(error) => Err(error),
Ok(policy_value) => {
// Step 3: Let dataString be the result of stringifying policyValue.
let data_string = match policy_value {
- Some(value) => value.as_ref().into(),
+ Some(value) => value,
// Step 4: If policyValue is null or undefined, set dataString to the empty string.
None => "".to_owned(),
};
@@ -164,22 +211,12 @@ impl TrustedTypePolicyMethods<crate::DomTypeHolder> for TrustedTypePolicy {
can_gc: CanGc,
) -> Fallible<DomRoot<TrustedHTML>> {
self.create_trusted_type(
- || {
- self.create_html.clone().map(|callback| {
- rooted!(in(*cx) let this_object: *mut JSObject);
- // Step 4: Let policyValue be the result of invoking function with value as a first argument,
- // items of arguments as subsequent arguments, and callback **this** value set to null,
- // rethrowing any exceptions.
- callback.Call_(
- &this_object.handle(),
- input,
- arguments,
- ExceptionHandling::Rethrow,
- can_gc,
- )
- })
- },
+ TrustedType::TrustedHTML,
+ cx,
+ input,
+ arguments,
|data_string| TrustedHTML::new(data_string, &self.global(), can_gc),
+ can_gc,
)
}
/// <https://www.w3.org/TR/trusted-types/#dom-trustedtypepolicy-createscript>
@@ -191,22 +228,12 @@ impl TrustedTypePolicyMethods<crate::DomTypeHolder> for TrustedTypePolicy {
can_gc: CanGc,
) -> Fallible<DomRoot<TrustedScript>> {
self.create_trusted_type(
- || {
- self.create_script.clone().map(|callback| {
- rooted!(in(*cx) let this_object: *mut JSObject);
- // Step 4: Let policyValue be the result of invoking function with value as a first argument,
- // items of arguments as subsequent arguments, and callback **this** value set to null,
- // rethrowing any exceptions.
- callback.Call_(
- &this_object.handle(),
- input,
- arguments,
- ExceptionHandling::Rethrow,
- can_gc,
- )
- })
- },
+ TrustedType::TrustedScript,
+ cx,
+ input,
+ arguments,
|data_string| TrustedScript::new(data_string, &self.global(), can_gc),
+ can_gc,
)
}
/// <https://www.w3.org/TR/trusted-types/#dom-trustedtypepolicy-createscripturl>
@@ -218,22 +245,12 @@ impl TrustedTypePolicyMethods<crate::DomTypeHolder> for TrustedTypePolicy {
can_gc: CanGc,
) -> Fallible<DomRoot<TrustedScriptURL>> {
self.create_trusted_type(
- || {
- self.create_script_url.clone().map(|callback| {
- rooted!(in(*cx) let this_object: *mut JSObject);
- // Step 4: Let policyValue be the result of invoking function with value as a first argument,
- // items of arguments as subsequent arguments, and callback **this** value set to null,
- // rethrowing any exceptions.
- callback.Call_(
- &this_object.handle(),
- input,
- arguments,
- ExceptionHandling::Rethrow,
- can_gc,
- )
- })
- },
+ TrustedType::TrustedScriptURL,
+ cx,
+ input,
+ arguments,
|data_string| TrustedScriptURL::new(data_string, &self.global(), can_gc),
+ can_gc,
)
}
}
diff --git a/components/script/dom/trustedtypepolicyfactory.rs b/components/script/dom/trustedtypepolicyfactory.rs
index 0dcc78b7cd0..0927446b904 100644
--- a/components/script/dom/trustedtypepolicyfactory.rs
+++ b/components/script/dom/trustedtypepolicyfactory.rs
@@ -6,11 +6,9 @@ use std::cell::RefCell;
use content_security_policy::CheckResult;
use dom_struct::dom_struct;
use html5ever::{LocalName, Namespace, QualName, local_name, ns};
-use js::jsapi::JSObject;
use js::jsval::NullValue;
use js::rust::HandleValue;
-use crate::dom::bindings::callback::ExceptionHandling;
use crate::dom::bindings::codegen::Bindings::TrustedTypePolicyFactoryBinding::{
TrustedTypePolicyFactoryMethods, TrustedTypePolicyOptions,
};
@@ -23,7 +21,7 @@ use crate::dom::globalscope::GlobalScope;
use crate::dom::trustedhtml::TrustedHTML;
use crate::dom::trustedscript::TrustedScript;
use crate::dom::trustedscripturl::TrustedScriptURL;
-use crate::dom::trustedtypepolicy::TrustedTypePolicy;
+use crate::dom::trustedtypepolicy::{TrustedType, TrustedTypePolicy};
use crate::js::conversions::ToJSValConvertible;
use crate::script_runtime::{CanGc, JSContext};
@@ -144,50 +142,40 @@ impl TrustedTypePolicyFactory {
/// <https://w3c.github.io/trusted-types/dist/spec/#process-value-with-a-default-policy-algorithm>
#[allow(unsafe_code)]
pub(crate) fn process_value_with_default_policy(
+ expected_type: TrustedType,
global: &GlobalScope,
input: String,
sink: &str,
can_gc: CanGc,
- ) -> Fallible<Option<DomRoot<TrustedScriptURL>>> {
+ ) -> Fallible<Option<String>> {
// Step 1: Let defaultPolicy be the value of global’s trusted type policy factory's default policy.
let global_policy_factory = global.trusted_types(can_gc);
let default_policy = match global_policy_factory.default_policy.get() {
- None => return Ok(Some(TrustedScriptURL::new(input, global, can_gc))),
+ None => return Ok(None),
Some(default_policy) => default_policy,
};
let cx = GlobalScope::get_cx();
// Step 2: Let policyValue be the result of executing Get Trusted Type policy value,
// with the following arguments:
- let policy_value = default_policy.get_trusted_type_policy_value(
- || {
- // TODO(36258): support other trusted types as well by changing get_trusted_type_policy_value to accept
- // the trusted type as enum and call the appropriate callback based on that.
- default_policy.create_script_url().map(|callback| {
- rooted!(in(*cx) let this_object: *mut JSObject);
- rooted!(in(*cx) let mut trusted_type_name_value = NullValue());
- unsafe {
- "TrustedScriptURL".to_jsval(*cx, trusted_type_name_value.handle_mut());
- }
+ rooted!(in(*cx) let mut trusted_type_name_value = NullValue());
+ unsafe {
+ let trusted_type_name: &'static str = expected_type.clone().into();
+ trusted_type_name.to_jsval(*cx, trusted_type_name_value.handle_mut());
+ }
- rooted!(in(*cx) let mut sink_value = NullValue());
- unsafe {
- sink.to_jsval(*cx, sink_value.handle_mut());
- }
+ rooted!(in(*cx) let mut sink_value = NullValue());
+ unsafe {
+ sink.to_jsval(*cx, sink_value.handle_mut());
+ }
- let args = vec![trusted_type_name_value.handle(), sink_value.handle()];
- // Step 4: Let policyValue be the result of invoking function with value as a first argument,
- // items of arguments as subsequent arguments, and callback **this** value set to null,
- // rethrowing any exceptions.
- callback.Call_(
- &this_object.handle(),
- DOMString::from(input.to_owned()),
- args,
- ExceptionHandling::Rethrow,
- can_gc,
- )
- })
- },
+ let arguments = vec![trusted_type_name_value.handle(), sink_value.handle()];
+ let policy_value = default_policy.get_trusted_type_policy_value(
+ expected_type,
+ cx,
+ DOMString::from(input.to_owned()),
+ arguments,
false,
+ can_gc,
);
let data_string = match policy_value {
// Step 3: If the algorithm threw an error, rethrow the error and abort the following steps.
@@ -196,14 +184,15 @@ impl TrustedTypePolicyFactory {
// Step 4: If policyValue is null or undefined, return policyValue.
None => return Ok(None),
// Step 5: Let dataString be the result of stringifying policyValue.
- Some(policy_value) => policy_value.as_ref().into(),
+ Some(policy_value) => policy_value,
},
};
- Ok(Some(TrustedScriptURL::new(data_string, global, can_gc)))
+ Ok(Some(data_string))
}
/// Step 1 is implemented by the caller
/// <https://w3c.github.io/trusted-types/dist/spec/#get-trusted-type-compliant-string-algorithm>
pub(crate) fn get_trusted_type_compliant_string(
+ expected_type: TrustedType,
global: &GlobalScope,
input: String,
sink: &str,
@@ -224,6 +213,7 @@ impl TrustedTypePolicyFactory {
// Step 4: Let convertedInput be the result of executing Process value with a default policy
// with the same arguments as this algorithm.
let converted_input = TrustedTypePolicyFactory::process_value_with_default_policy(
+ expected_type,
global,
input.clone(),
sink,
@@ -252,7 +242,7 @@ impl TrustedTypePolicyFactory {
}
},
// Step 8: Return stringified convertedInput.
- Some(converted_input) => Ok((*converted_input).to_string()),
+ Some(converted_input) => Ok(converted_input),
}
// Step 7: Assert: convertedInput is an instance of expectedType.
// TODO(https://github.com/w3c/trusted-types/issues/566): Implement when spec is resolved
diff --git a/components/script/dom/webgl2renderingcontext.rs b/components/script/dom/webgl2renderingcontext.rs
index 416454d8719..5e538b53b5f 100644
--- a/components/script/dom/webgl2renderingcontext.rs
+++ b/components/script/dom/webgl2renderingcontext.rs
@@ -22,10 +22,10 @@ use js::jsval::{BooleanValue, DoubleValue, Int32Value, NullValue, ObjectValue, U
use js::rust::{CustomAutoRooterGuard, HandleObject, MutableHandleValue};
use js::typedarray::{ArrayBufferView, CreateWith, Float32, Int32Array, Uint32, Uint32Array};
use script_bindings::interfaces::WebGL2RenderingContextHelpers;
-use script_layout_interface::HTMLCanvasDataSource;
use servo_config::pref;
use snapshot::Snapshot;
use url::Host;
+use webrender_api::ImageKey;
use crate::canvas_context::CanvasContext;
use crate::dom::bindings::codegen::Bindings::WebGL2RenderingContextBinding::{
@@ -4702,7 +4702,7 @@ impl WebGL2RenderingContextMethods<crate::DomTypeHolder> for WebGL2RenderingCont
impl LayoutCanvasRenderingContextHelpers for LayoutDom<'_, WebGL2RenderingContext> {
#[allow(unsafe_code)]
- fn canvas_data_source(self) -> HTMLCanvasDataSource {
+ fn canvas_data_source(self) -> Option<ImageKey> {
let this = self.unsafe_get();
unsafe { (*this.base.to_layout().unsafe_get()).layout_handle() }
}
diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs
index 9996a3cf504..98170f9655b 100644
--- a/components/script/dom/webglrenderingcontext.rs
+++ b/components/script/dom/webglrenderingcontext.rs
@@ -31,7 +31,6 @@ use js::typedarray::{
};
use net_traits::image_cache::ImageResponse;
use pixels::{self, PixelFormat};
-use script_layout_interface::HTMLCanvasDataSource;
use serde::{Deserialize, Serialize};
use servo_config::pref;
use snapshot::Snapshot;
@@ -875,9 +874,8 @@ impl WebGLRenderingContext {
receiver.recv().unwrap()
}
- pub(crate) fn layout_handle(&self) -> HTMLCanvasDataSource {
- let image_key = self.webrender_image;
- HTMLCanvasDataSource::WebGL(image_key)
+ pub(crate) fn layout_handle(&self) -> Option<ImageKey> {
+ Some(self.webrender_image)
}
// https://www.khronos.org/registry/webgl/extensions/ANGLE_instanced_arrays/
@@ -4829,7 +4827,7 @@ impl WebGLRenderingContextMethods<crate::DomTypeHolder> for WebGLRenderingContex
}
impl LayoutCanvasRenderingContextHelpers for LayoutDom<'_, WebGLRenderingContext> {
- fn canvas_data_source(self) -> HTMLCanvasDataSource {
+ fn canvas_data_source(self) -> Option<ImageKey> {
(*self.unsafe_get()).layout_handle()
}
}
diff --git a/components/script/dom/webgpu/gpucanvascontext.rs b/components/script/dom/webgpu/gpucanvascontext.rs
index c81f96f651f..359b1b14003 100644
--- a/components/script/dom/webgpu/gpucanvascontext.rs
+++ b/components/script/dom/webgpu/gpucanvascontext.rs
@@ -8,7 +8,6 @@ use std::cell::RefCell;
use arrayvec::ArrayVec;
use dom_struct::dom_struct;
use ipc_channel::ipc::{self};
-use script_layout_interface::HTMLCanvasDataSource;
use snapshot::Snapshot;
use webgpu_traits::{
ContextConfiguration, PRESENTATION_BUFFER_COUNT, WebGPU, WebGPUContextId, WebGPURequest,
@@ -227,11 +226,11 @@ impl GPUCanvasContext {
// Internal helper methods
impl GPUCanvasContext {
- fn layout_handle(&self) -> HTMLCanvasDataSource {
+ fn layout_handle(&self) -> Option<ImageKey> {
if self.drawing_buffer.borrow().cleared {
- HTMLCanvasDataSource::Empty
+ None
} else {
- HTMLCanvasDataSource::WebGPU(self.webrender_image)
+ Some(self.webrender_image)
}
}
@@ -301,7 +300,7 @@ impl CanvasContext for GPUCanvasContext {
}
impl LayoutCanvasRenderingContextHelpers for LayoutDom<'_, GPUCanvasContext> {
- fn canvas_data_source(self) -> HTMLCanvasDataSource {
+ fn canvas_data_source(self) -> Option<ImageKey> {
(*self.unsafe_get()).layout_handle()
}
}
diff --git a/components/script/dom/webxr/xrhittestsource.rs b/components/script/dom/webxr/xrhittestsource.rs
index 0ec9560db6e..f73f8f79655 100644
--- a/components/script/dom/webxr/xrhittestsource.rs
+++ b/components/script/dom/webxr/xrhittestsource.rs
@@ -8,7 +8,7 @@ use webxr_api::HitTestId;
use crate::dom::bindings::codegen::Bindings::XRHitTestSourceBinding::XRHitTestSourceMethods;
use crate::dom::bindings::reflector::{Reflector, reflect_dom_object};
use crate::dom::bindings::root::{Dom, DomRoot};
-use crate::dom::globalscope::GlobalScope;
+use crate::dom::window::Window;
use crate::dom::xrsession::XRSession;
use crate::script_runtime::CanGc;
@@ -31,14 +31,14 @@ impl XRHitTestSource {
}
pub(crate) fn new(
- global: &GlobalScope,
+ window: &Window,
id: HitTestId,
session: &XRSession,
can_gc: CanGc,
) -> DomRoot<XRHitTestSource> {
reflect_dom_object(
Box::new(XRHitTestSource::new_inherited(id, session)),
- global,
+ window,
can_gc,
)
}
diff --git a/components/script/dom/webxr/xrinputsource.rs b/components/script/dom/webxr/xrinputsource.rs
index 009b210646a..e454e785424 100644
--- a/components/script/dom/webxr/xrinputsource.rs
+++ b/components/script/dom/webxr/xrinputsource.rs
@@ -17,6 +17,7 @@ use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object};
use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
use crate::dom::gamepad::Gamepad;
use crate::dom::globalscope::GlobalScope;
+use crate::dom::window::Window;
use crate::dom::xrhand::XRHand;
use crate::dom::xrsession::XRSession;
use crate::dom::xrspace::XRSpace;
@@ -40,14 +41,14 @@ pub(crate) struct XRInputSource {
impl XRInputSource {
pub(crate) fn new_inherited(
- global: &GlobalScope,
+ window: &Window,
session: &XRSession,
info: InputSource,
can_gc: CanGc,
) -> XRInputSource {
// <https://www.w3.org/TR/webxr-gamepads-module-1/#gamepad-differences>
let gamepad = Gamepad::new(
- global,
+ window,
0,
"".into(),
"xr-standard".into(),
@@ -74,18 +75,18 @@ impl XRInputSource {
#[allow(unsafe_code)]
pub(crate) fn new(
- global: &GlobalScope,
+ window: &Window,
session: &XRSession,
info: InputSource,
can_gc: CanGc,
) -> DomRoot<XRInputSource> {
let source = reflect_dom_object(
- Box::new(XRInputSource::new_inherited(global, session, info, can_gc)),
- global,
+ Box::new(XRInputSource::new_inherited(window, session, info, can_gc)),
+ window,
can_gc,
);
- let _ac = enter_realm(global);
+ let _ac = enter_realm(window);
let cx = GlobalScope::get_cx();
unsafe {
rooted!(in(*cx) let mut profiles = UndefinedValue());
diff --git a/components/script/dom/webxr/xrinputsourcearray.rs b/components/script/dom/webxr/xrinputsourcearray.rs
index d7dcdfcbb6d..26a2c42f598 100644
--- a/components/script/dom/webxr/xrinputsourcearray.rs
+++ b/components/script/dom/webxr/xrinputsourcearray.rs
@@ -11,7 +11,7 @@ use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object};
use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::event::Event;
-use crate::dom::globalscope::GlobalScope;
+use crate::dom::window::Window;
use crate::dom::xrinputsource::XRInputSource;
use crate::dom::xrinputsourceschangeevent::XRInputSourcesChangeEvent;
use crate::dom::xrsession::XRSession;
@@ -31,10 +31,10 @@ impl XRInputSourceArray {
}
}
- pub(crate) fn new(global: &GlobalScope, can_gc: CanGc) -> DomRoot<XRInputSourceArray> {
+ pub(crate) fn new(window: &Window, can_gc: CanGc) -> DomRoot<XRInputSourceArray> {
reflect_dom_object(
Box::new(XRInputSourceArray::new_inherited()),
- global,
+ window,
can_gc,
)
}
@@ -60,7 +60,7 @@ impl XRInputSourceArray {
.any(|i| i.id() == info.id),
"Should never add a duplicate input id!"
);
- let input = XRInputSource::new(&global, session, info.clone(), can_gc);
+ let input = XRInputSource::new(window, session, info.clone(), can_gc);
self.input_sources.borrow_mut().push(Dom::from_ref(&input));
added.push(input);
}
@@ -121,7 +121,7 @@ impl XRInputSourceArray {
&[]
};
self.input_sources.borrow_mut().retain(|i| i.id() != id);
- let input = XRInputSource::new(&global, session, info, can_gc);
+ let input = XRInputSource::new(window, session, info, can_gc);
self.input_sources.borrow_mut().push(Dom::from_ref(&input));
let added = [input];
diff --git a/components/script/dom/webxr/xrrenderstate.rs b/components/script/dom/webxr/xrrenderstate.rs
index 3f546c2353d..d114020e16e 100644
--- a/components/script/dom/webxr/xrrenderstate.rs
+++ b/components/script/dom/webxr/xrrenderstate.rs
@@ -14,7 +14,7 @@ use crate::dom::bindings::num::Finite;
use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object};
use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
use crate::dom::bindings::utils::to_frozen_array;
-use crate::dom::globalscope::GlobalScope;
+use crate::dom::window::Window;
use crate::dom::xrlayer::XRLayer;
use crate::dom::xrwebgllayer::XRWebGLLayer;
use crate::script_runtime::{CanGc, JSContext};
@@ -49,7 +49,7 @@ impl XRRenderState {
}
pub(crate) fn new(
- global: &GlobalScope,
+ window: &Window,
depth_near: f64,
depth_far: f64,
inline_vertical_fov: Option<f64>,
@@ -65,14 +65,14 @@ impl XRRenderState {
layer,
layers,
)),
- global,
+ window,
can_gc,
)
}
pub(crate) fn clone_object(&self) -> DomRoot<Self> {
XRRenderState::new(
- &self.global(),
+ self.global().as_window(),
self.depth_near.get(),
self.depth_far.get(),
self.inline_vertical_fov.get(),
diff --git a/components/script/dom/webxr/xrsession.rs b/components/script/dom/webxr/xrsession.rs
index a171a769b71..6ead8f65445 100644
--- a/components/script/dom/webxr/xrsession.rs
+++ b/components/script/dom/webxr/xrsession.rs
@@ -54,8 +54,8 @@ use crate::dom::bindings::root::{Dom, DomRoot, MutDom, MutNullableDom};
use crate::dom::bindings::utils::to_frozen_array;
use crate::dom::event::Event;
use crate::dom::eventtarget::EventTarget;
-use crate::dom::globalscope::GlobalScope;
use crate::dom::promise::Promise;
+use crate::dom::window::Window;
use crate::dom::xrboundedreferencespace::XRBoundedReferenceSpace;
use crate::dom::xrframe::XRFrame;
use crate::dom::xrhittestsource::XRHitTestSource;
@@ -152,7 +152,7 @@ impl XRSession {
}
pub(crate) fn new(
- global: &GlobalScope,
+ window: &Window,
session: Session,
mode: XRSessionMode,
frame_receiver: IpcReceiver<Frame>,
@@ -163,8 +163,8 @@ impl XRSession {
} else {
None
};
- let render_state = XRRenderState::new(global, 0.1, 1000.0, ivfov, None, Vec::new(), can_gc);
- let input_sources = XRInputSourceArray::new(global, can_gc);
+ let render_state = XRRenderState::new(window, 0.1, 1000.0, ivfov, None, Vec::new(), can_gc);
+ let input_sources = XRInputSourceArray::new(window, can_gc);
let ret = reflect_dom_object(
Box::new(XRSession::new_inherited(
session,
@@ -172,7 +172,7 @@ impl XRSession {
&input_sources,
mode,
)),
- global,
+ window,
can_gc,
);
ret.attach_event_handler();
@@ -587,7 +587,7 @@ impl XRSession {
FrameUpdateEvent::HitTestSourceAdded(id) => {
if let Some(promise) = self.pending_hit_test_promises.borrow_mut().remove(&id) {
promise.resolve_native(
- &XRHitTestSource::new(&self.global(), id, self, can_gc),
+ &XRHitTestSource::new(self.global().as_window(), id, self, can_gc),
can_gc,
);
} else {
diff --git a/components/script/dom/webxr/xrsystem.rs b/components/script/dom/webxr/xrsystem.rs
index eabe7a72119..9963d92fa59 100644
--- a/components/script/dom/webxr/xrsystem.rs
+++ b/components/script/dom/webxr/xrsystem.rs
@@ -297,7 +297,13 @@ impl XRSystem {
return;
},
};
- let session = XRSession::new(&self.global(), session, mode, frame_receiver, CanGc::note());
+ let session = XRSession::new(
+ self.global().as_window(),
+ session,
+ mode,
+ frame_receiver,
+ CanGc::note(),
+ );
if mode == XRSessionMode::Inline {
self.active_inline_sessions
.borrow_mut()
diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs
index a685bbb25f2..b115add8611 100644
--- a/components/script/dom/window.rs
+++ b/components/script/dom/window.rs
@@ -32,8 +32,9 @@ use devtools_traits::{ScriptToDevtoolsControlMsg, TimelineMarker, TimelineMarker
use dom_struct::dom_struct;
use embedder_traits::user_content_manager::{UserContentManager, UserScript};
use embedder_traits::{
- AlertResponse, ConfirmResponse, EmbedderMsg, PromptResponse, SimpleDialog, Theme,
- ViewportDetails, WebDriverJSError, WebDriverJSResult,
+ AlertResponse, ConfirmResponse, EmbedderMsg, GamepadEvent, GamepadSupportedHapticEffects,
+ GamepadUpdateType, PromptResponse, SimpleDialog, Theme, ViewportDetails, WebDriverJSError,
+ WebDriverJSResult,
};
use euclid::default::{Point2D as UntypedPoint2D, Rect as UntypedRect};
use euclid::{Point2D, Rect, Scale, Size2D, Vector2D};
@@ -61,6 +62,8 @@ use num_traits::ToPrimitive;
use profile_traits::ipc as ProfiledIpc;
use profile_traits::mem::ProfilerChan as MemProfilerChan;
use profile_traits::time::ProfilerChan as TimeProfilerChan;
+use script_bindings::codegen::GenericBindings::NavigatorBinding::NavigatorMethods;
+use script_bindings::codegen::GenericBindings::PerformanceBinding::PerformanceMethods;
use script_bindings::interfaces::WindowHelpers;
use script_layout_interface::{
FragmentType, Layout, PendingImageState, QueryMsg, Reflow, ReflowGoal, ReflowRequest,
@@ -125,6 +128,8 @@ use crate::dom::document::{AnimationFrameCallback, Document, ReflowTriggerCondit
use crate::dom::element::Element;
use crate::dom::event::{Event, EventBubbles, EventCancelable, EventStatus};
use crate::dom::eventtarget::EventTarget;
+use crate::dom::gamepad::{Gamepad, contains_user_gesture};
+use crate::dom::gamepadevent::GamepadEventType;
use crate::dom::globalscope::GlobalScope;
use crate::dom::hashchangeevent::HashChangeEvent;
use crate::dom::history::History;
@@ -642,6 +647,126 @@ impl Window {
pub(crate) fn font_context(&self) -> &Arc<FontContext> {
&self.font_context
}
+
+ pub(crate) fn handle_gamepad_event(&self, gamepad_event: GamepadEvent) {
+ match gamepad_event {
+ GamepadEvent::Connected(index, name, bounds, supported_haptic_effects) => {
+ self.handle_gamepad_connect(
+ index.0,
+ name,
+ bounds.axis_bounds,
+ bounds.button_bounds,
+ supported_haptic_effects,
+ );
+ },
+ GamepadEvent::Disconnected(index) => {
+ self.handle_gamepad_disconnect(index.0);
+ },
+ GamepadEvent::Updated(index, update_type) => {
+ self.receive_new_gamepad_button_or_axis(index.0, update_type);
+ },
+ };
+ }
+
+ /// <https://www.w3.org/TR/gamepad/#dfn-gamepadconnected>
+ fn handle_gamepad_connect(
+ &self,
+ // As the spec actually defines how to set the gamepad index, the GilRs index
+ // is currently unused, though in practice it will almost always be the same.
+ // More infra is currently needed to track gamepads across windows.
+ _index: usize,
+ name: String,
+ axis_bounds: (f64, f64),
+ button_bounds: (f64, f64),
+ supported_haptic_effects: GamepadSupportedHapticEffects,
+ ) {
+ // TODO: 2. If document is not null and is not allowed to use the "gamepad" permission,
+ // then abort these steps.
+ let this = Trusted::new(self);
+ self.upcast::<GlobalScope>()
+ .task_manager()
+ .gamepad_task_source()
+ .queue(task!(gamepad_connected: move || {
+ let window = this.root();
+
+ let navigator = window.Navigator();
+ let selected_index = navigator.select_gamepad_index();
+ let gamepad = Gamepad::new(
+ &window,
+ selected_index,
+ name,
+ "standard".into(),
+ axis_bounds,
+ button_bounds,
+ supported_haptic_effects,
+ false,
+ CanGc::note(),
+ );
+ navigator.set_gamepad(selected_index as usize, &gamepad, CanGc::note());
+ }));
+ }
+
+ /// <https://www.w3.org/TR/gamepad/#dfn-gamepaddisconnected>
+ fn handle_gamepad_disconnect(&self, index: usize) {
+ let this = Trusted::new(self);
+ self.upcast::<GlobalScope>()
+ .task_manager()
+ .gamepad_task_source()
+ .queue(task!(gamepad_disconnected: move || {
+ let window = this.root();
+ let navigator = window.Navigator();
+ if let Some(gamepad) = navigator.get_gamepad(index) {
+ if window.Document().is_fully_active() {
+ gamepad.update_connected(false, gamepad.exposed(), CanGc::note());
+ navigator.remove_gamepad(index);
+ }
+ }
+ }));
+ }
+
+ /// <https://www.w3.org/TR/gamepad/#receiving-inputs>
+ fn receive_new_gamepad_button_or_axis(&self, index: usize, update_type: GamepadUpdateType) {
+ let this = Trusted::new(self);
+
+ // <https://w3c.github.io/gamepad/#dfn-update-gamepad-state>
+ self.upcast::<GlobalScope>().task_manager().gamepad_task_source().queue(
+ task!(update_gamepad_state: move || {
+ let window = this.root();
+ let navigator = window.Navigator();
+ if let Some(gamepad) = navigator.get_gamepad(index) {
+ let current_time = window.Performance().Now();
+ gamepad.update_timestamp(*current_time);
+ match update_type {
+ GamepadUpdateType::Axis(index, value) => {
+ gamepad.map_and_normalize_axes(index, value);
+ },
+ GamepadUpdateType::Button(index, value) => {
+ gamepad.map_and_normalize_buttons(index, value);
+ }
+ };
+ if !navigator.has_gamepad_gesture() && contains_user_gesture(update_type) {
+ navigator.set_has_gamepad_gesture(true);
+ navigator.GetGamepads()
+ .iter()
+ .filter_map(|g| g.as_ref())
+ .for_each(|gamepad| {
+ gamepad.set_exposed(true);
+ gamepad.update_timestamp(*current_time);
+ let new_gamepad = Trusted::new(&**gamepad);
+ if window.Document().is_fully_active() {
+ window.upcast::<GlobalScope>().task_manager().gamepad_task_source().queue(
+ task!(update_gamepad_connect: move || {
+ let gamepad = new_gamepad.root();
+ gamepad.notify_event(GamepadEventType::Connected, CanGc::note());
+ })
+ );
+ }
+ });
+ }
+ }
+ })
+ );
+ }
}
// https://html.spec.whatwg.org/multipage/#atob
@@ -1246,7 +1371,7 @@ impl WindowMethods<crate::DomTypeHolder> for Window {
let rv = jsval_to_webdriver(cx, &self.globalscope, val, realm, can_gc);
let opt_chan = self.webdriver_script_chan.borrow_mut().take();
if let Some(chan) = opt_chan {
- chan.send(rv).unwrap();
+ let _ = chan.send(rv);
}
}
@@ -1255,9 +1380,9 @@ impl WindowMethods<crate::DomTypeHolder> for Window {
let opt_chan = self.webdriver_script_chan.borrow_mut().take();
if let Some(chan) = opt_chan {
if let Ok(rv) = rv {
- chan.send(Err(WebDriverJSError::JSException(rv))).unwrap();
+ let _ = chan.send(Err(WebDriverJSError::JSException(rv)));
} else {
- chan.send(rv).unwrap();
+ let _ = chan.send(rv);
}
}
}
@@ -1265,7 +1390,7 @@ impl WindowMethods<crate::DomTypeHolder> for Window {
fn WebdriverTimeout(&self) {
let opt_chan = self.webdriver_script_chan.borrow_mut().take();
if let Some(chan) = opt_chan {
- chan.send(Err(WebDriverJSError::Timeout)).unwrap();
+ let _ = chan.send(Err(WebDriverJSError::Timeout));
}
}