aboutsummaryrefslogtreecommitdiffstats
path: root/components/script
diff options
context:
space:
mode:
Diffstat (limited to 'components/script')
-rw-r--r--components/script/canvas_context.rs190
-rw-r--r--components/script/canvas_state.rs13
-rw-r--r--components/script/dom/canvasrenderingcontext2d.rs8
-rw-r--r--components/script/dom/dissimilaroriginwindow.rs7
-rw-r--r--components/script/dom/document.rs445
-rw-r--r--components/script/dom/element.rs70
-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.rs370
-rw-r--r--components/script/dom/gpucanvascontext.rs4
-rw-r--r--components/script/dom/htmlcanvaselement.rs101
-rw-r--r--components/script/dom/htmldetailselement.rs4
-rw-r--r--components/script/dom/htmlelement.rs28
-rw-r--r--components/script/dom/htmlformelement.rs10
-rw-r--r--components/script/dom/htmliframeelement.rs17
-rw-r--r--components/script/dom/htmlscriptelement.rs116
-rw-r--r--components/script/dom/htmltablecellelement.rs35
-rw-r--r--components/script/dom/htmltablecolelement.rs17
-rw-r--r--components/script/dom/macros.rs69
-rw-r--r--components/script/dom/messageport.rs38
-rw-r--r--components/script/dom/node.rs107
-rw-r--r--components/script/dom/nodelist.rs1
-rw-r--r--components/script/dom/offscreencanvas.rs58
-rw-r--r--components/script/dom/offscreencanvasrenderingcontext2d.rs29
-rw-r--r--components/script/dom/readablestream.rs8
-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/underlyingsourcecontainer.rs2
-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.rs163
-rw-r--r--components/script/dom/windowproxy.rs17
-rw-r--r--components/script/dom/writablestream.rs4
-rw-r--r--components/script/dom/writablestreamdefaultcontroller.rs10
-rw-r--r--components/script/messaging.rs2
-rw-r--r--components/script/script_module.rs5
-rw-r--r--components/script/script_thread.rs96
50 files changed, 1715 insertions, 869 deletions
diff --git a/components/script/canvas_context.rs b/components/script/canvas_context.rs
index d49d31997e1..7dfdf48e3f5 100644
--- a/components/script/canvas_context.rs
+++ b/components/script/canvas_context.rs
@@ -5,16 +5,25 @@
//! Common interfaces for Canvas Contexts
use euclid::default::Size2D;
-use script_layout_interface::{HTMLCanvasData, HTMLCanvasDataSource};
+use script_bindings::root::Dom;
+use script_layout_interface::HTMLCanvasData;
use snapshot::Snapshot;
+use webrender_api::ImageKey;
use crate::dom::bindings::codegen::UnionTypes::HTMLCanvasElementOrOffscreenCanvas;
use crate::dom::bindings::inheritance::Castable;
use crate::dom::htmlcanvaselement::HTMLCanvasElement;
use crate::dom::node::{Node, NodeDamage};
+#[cfg(feature = "webgpu")]
+use crate::dom::types::GPUCanvasContext;
+use crate::dom::types::{
+ CanvasRenderingContext2D, OffscreenCanvas, OffscreenCanvasRenderingContext2D,
+ WebGL2RenderingContext, WebGLRenderingContext,
+};
pub(crate) trait LayoutCanvasRenderingContextHelpers {
- fn canvas_data_source(self) -> HTMLCanvasDataSource;
+ /// `None` is rendered as transparent black (cleared canvas)
+ fn canvas_data_source(self) -> Option<ImageKey>;
}
pub(crate) trait LayoutHTMLCanvasElementHelpers {
@@ -85,3 +94,180 @@ impl CanvasHelpers for HTMLCanvasElementOrOffscreenCanvas {
}
}
}
+
+/// Non rooted variant of [`crate::dom::bindings::codegen::Bindings::HTMLCanvasElementBinding::RenderingContext`]
+#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
+#[derive(Clone, JSTraceable, MallocSizeOf)]
+pub(crate) enum RenderingContext {
+ Placeholder(Dom<OffscreenCanvas>),
+ Context2d(Dom<CanvasRenderingContext2D>),
+ WebGL(Dom<WebGLRenderingContext>),
+ WebGL2(Dom<WebGL2RenderingContext>),
+ #[cfg(feature = "webgpu")]
+ WebGPU(Dom<GPUCanvasContext>),
+}
+
+impl CanvasContext for RenderingContext {
+ type ID = ();
+
+ fn context_id(&self) -> Self::ID {}
+
+ fn canvas(&self) -> HTMLCanvasElementOrOffscreenCanvas {
+ match self {
+ RenderingContext::Placeholder(context) => (*context.context().unwrap()).canvas(),
+ RenderingContext::Context2d(context) => context.canvas(),
+ RenderingContext::WebGL(context) => context.canvas(),
+ RenderingContext::WebGL2(context) => context.canvas(),
+ #[cfg(feature = "webgpu")]
+ RenderingContext::WebGPU(context) => context.canvas(),
+ }
+ }
+
+ fn resize(&self) {
+ match self {
+ RenderingContext::Placeholder(context) => (*context.context().unwrap()).resize(),
+ RenderingContext::Context2d(context) => context.resize(),
+ RenderingContext::WebGL(context) => context.resize(),
+ RenderingContext::WebGL2(context) => context.resize(),
+ #[cfg(feature = "webgpu")]
+ RenderingContext::WebGPU(context) => context.resize(),
+ }
+ }
+
+ fn get_image_data(&self) -> Option<Snapshot> {
+ match self {
+ RenderingContext::Placeholder(context) => {
+ (*context.context().unwrap()).get_image_data()
+ },
+ RenderingContext::Context2d(context) => context.get_image_data(),
+ RenderingContext::WebGL(context) => context.get_image_data(),
+ RenderingContext::WebGL2(context) => context.get_image_data(),
+ #[cfg(feature = "webgpu")]
+ RenderingContext::WebGPU(context) => context.get_image_data(),
+ }
+ }
+
+ fn origin_is_clean(&self) -> bool {
+ match self {
+ RenderingContext::Placeholder(context) => {
+ (*context.context().unwrap()).origin_is_clean()
+ },
+ RenderingContext::Context2d(context) => context.origin_is_clean(),
+ RenderingContext::WebGL(context) => context.origin_is_clean(),
+ RenderingContext::WebGL2(context) => context.origin_is_clean(),
+ #[cfg(feature = "webgpu")]
+ RenderingContext::WebGPU(context) => context.origin_is_clean(),
+ }
+ }
+
+ fn size(&self) -> Size2D<u64> {
+ match self {
+ RenderingContext::Placeholder(context) => (*context.context().unwrap()).size(),
+ RenderingContext::Context2d(context) => context.size(),
+ RenderingContext::WebGL(context) => context.size(),
+ RenderingContext::WebGL2(context) => context.size(),
+ #[cfg(feature = "webgpu")]
+ RenderingContext::WebGPU(context) => context.size(),
+ }
+ }
+
+ fn mark_as_dirty(&self) {
+ match self {
+ RenderingContext::Placeholder(context) => (*context.context().unwrap()).mark_as_dirty(),
+ RenderingContext::Context2d(context) => context.mark_as_dirty(),
+ RenderingContext::WebGL(context) => context.mark_as_dirty(),
+ RenderingContext::WebGL2(context) => context.mark_as_dirty(),
+ #[cfg(feature = "webgpu")]
+ RenderingContext::WebGPU(context) => context.mark_as_dirty(),
+ }
+ }
+
+ fn update_rendering(&self) {
+ match self {
+ RenderingContext::Placeholder(context) => {
+ (*context.context().unwrap()).update_rendering()
+ },
+ RenderingContext::Context2d(context) => context.update_rendering(),
+ RenderingContext::WebGL(context) => context.update_rendering(),
+ RenderingContext::WebGL2(context) => context.update_rendering(),
+ #[cfg(feature = "webgpu")]
+ RenderingContext::WebGPU(context) => context.update_rendering(),
+ }
+ }
+
+ fn onscreen(&self) -> bool {
+ match self {
+ RenderingContext::Placeholder(context) => (*context.context().unwrap()).onscreen(),
+ RenderingContext::Context2d(context) => context.onscreen(),
+ RenderingContext::WebGL(context) => context.onscreen(),
+ RenderingContext::WebGL2(context) => context.onscreen(),
+ #[cfg(feature = "webgpu")]
+ RenderingContext::WebGPU(context) => context.onscreen(),
+ }
+ }
+}
+
+/// Non rooted variant of [`crate::dom::bindings::codegen::Bindings::OffscreenCanvasBinding::OffscreenRenderingContext`]
+#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
+#[derive(Clone, JSTraceable, MallocSizeOf)]
+pub(crate) enum OffscreenRenderingContext {
+ Context2d(Dom<OffscreenCanvasRenderingContext2D>),
+ //WebGL(Dom<WebGLRenderingContext>),
+ //WebGL2(Dom<WebGL2RenderingContext>),
+ //#[cfg(feature = "webgpu")]
+ //WebGPU(Dom<GPUCanvasContext>),
+}
+
+impl CanvasContext for OffscreenRenderingContext {
+ type ID = ();
+
+ fn context_id(&self) -> Self::ID {}
+
+ fn canvas(&self) -> HTMLCanvasElementOrOffscreenCanvas {
+ match self {
+ OffscreenRenderingContext::Context2d(context) => context.canvas(),
+ }
+ }
+
+ fn resize(&self) {
+ match self {
+ OffscreenRenderingContext::Context2d(context) => context.resize(),
+ }
+ }
+
+ fn get_image_data(&self) -> Option<Snapshot> {
+ match self {
+ OffscreenRenderingContext::Context2d(context) => context.get_image_data(),
+ }
+ }
+
+ fn origin_is_clean(&self) -> bool {
+ match self {
+ OffscreenRenderingContext::Context2d(context) => context.origin_is_clean(),
+ }
+ }
+
+ fn size(&self) -> Size2D<u64> {
+ match self {
+ OffscreenRenderingContext::Context2d(context) => context.size(),
+ }
+ }
+
+ fn mark_as_dirty(&self) {
+ match self {
+ OffscreenRenderingContext::Context2d(context) => context.mark_as_dirty(),
+ }
+ }
+
+ fn update_rendering(&self) {
+ match self {
+ OffscreenRenderingContext::Context2d(context) => context.update_rendering(),
+ }
+ }
+
+ fn onscreen(&self) -> bool {
+ match self {
+ OffscreenRenderingContext::Context2d(context) => context.onscreen(),
+ }
+ }
+}
diff --git a/components/script/canvas_state.rs b/components/script/canvas_state.rs
index e9892818e92..dabe6a5728b 100644
--- a/components/script/canvas_state.rs
+++ b/components/script/canvas_state.rs
@@ -36,6 +36,7 @@ use style_traits::{CssWriter, ParsingMode};
use url::Url;
use webrender_api::ImageKey;
+use crate::canvas_context::{OffscreenRenderingContext, RenderingContext};
use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::{
CanvasDirection, CanvasFillRule, CanvasImageSource, CanvasLineCap, CanvasLineJoin,
@@ -52,10 +53,10 @@ use crate::dom::canvaspattern::CanvasPattern;
use crate::dom::dommatrix::DOMMatrix;
use crate::dom::element::{Element, cors_setting_for_element};
use crate::dom::globalscope::GlobalScope;
-use crate::dom::htmlcanvaselement::{CanvasContext, HTMLCanvasElement};
+use crate::dom::htmlcanvaselement::HTMLCanvasElement;
use crate::dom::imagedata::ImageData;
use crate::dom::node::{Node, NodeTraits};
-use crate::dom::offscreencanvas::{OffscreenCanvas, OffscreenCanvasContext};
+use crate::dom::offscreencanvas::OffscreenCanvas;
use crate::dom::paintworkletglobalscope::PaintWorkletGlobalScope;
use crate::dom::textmetrics::TextMetrics;
use crate::script_runtime::CanGc;
@@ -522,7 +523,7 @@ impl CanvasState {
if let Some(context) = canvas.context() {
match *context {
- OffscreenCanvasContext::OffscreenContext2d(ref context) => {
+ OffscreenRenderingContext::Context2d(ref context) => {
context.send_canvas_2d_msg(Canvas2dMsg::DrawImageInOther(
self.get_canvas_id(),
image_size,
@@ -577,7 +578,7 @@ impl CanvasState {
if let Some(context) = canvas.context() {
match *context {
- CanvasContext::Context2d(ref context) => {
+ RenderingContext::Context2d(ref context) => {
context.send_canvas_2d_msg(Canvas2dMsg::DrawImageInOther(
self.get_canvas_id(),
image_size,
@@ -586,12 +587,12 @@ impl CanvasState {
smoothing_enabled,
));
},
- CanvasContext::Placeholder(ref context) => {
+ RenderingContext::Placeholder(ref context) => {
let Some(context) = context.context() else {
return Err(Error::InvalidState);
};
match *context {
- OffscreenCanvasContext::OffscreenContext2d(ref context) => context
+ OffscreenRenderingContext::Context2d(ref context) => context
.send_canvas_2d_msg(Canvas2dMsg::DrawImageInOther(
self.get_canvas_id(),
image_size,
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/dissimilaroriginwindow.rs b/components/script/dom/dissimilaroriginwindow.rs
index b7fbe0855fe..70c384db822 100644
--- a/components/script/dom/dissimilaroriginwindow.rs
+++ b/components/script/dom/dissimilaroriginwindow.rs
@@ -181,12 +181,13 @@ impl DissimilarOriginWindowMethods<crate::DomTypeHolder> for DissimilarOriginWin
// https://html.spec.whatwg.org/multipage/#dom-window-blur
fn Blur(&self) {
- // TODO: Implement x-origin blur
+ // > User agents are encouraged to ignore calls to this `blur()` method
+ // > entirely.
}
- // https://html.spec.whatwg.org/multipage/#dom-focus
+ // https://html.spec.whatwg.org/multipage/#dom-window-focus
fn Focus(&self) {
- // TODO: Implement x-origin focus
+ self.window_proxy().focus();
}
// https://html.spec.whatwg.org/multipage/#dom-location
diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs
index 1e2a3747751..2baab15e1b8 100644
--- a/components/script/dom/document.rs
+++ b/components/script/dom/document.rs
@@ -30,8 +30,8 @@ use devtools_traits::ScriptToDevtoolsControlMsg;
use dom_struct::dom_struct;
use embedder_traits::{
AllowOrDeny, AnimationState, CompositorHitTestResult, ContextMenuResult, EditingActionEvent,
- EmbedderMsg, ImeEvent, InputEvent, LoadStatus, MouseButton, MouseButtonAction,
- MouseButtonEvent, TouchEvent, TouchEventType, TouchId, WheelEvent,
+ EmbedderMsg, FocusSequenceNumber, ImeEvent, InputEvent, LoadStatus, MouseButton,
+ MouseButtonAction, MouseButtonEvent, TouchEvent, TouchEventType, TouchId, WheelEvent,
};
use encoding_rs::{Encoding, UTF_8};
use euclid::default::{Point2D, Rect, Size2D};
@@ -270,12 +270,11 @@ pub(crate) enum IsHTMLDocument {
#[derive(JSTraceable, MallocSizeOf)]
#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
-enum FocusTransaction {
- /// No focus operation is in effect.
- NotInTransaction,
- /// A focus operation is in effect.
- /// Contains the element that has most recently requested focus for itself.
- InTransaction(Option<Dom<Element>>),
+struct FocusTransaction {
+ /// The focused element of this document.
+ element: Option<Dom<Element>>,
+ /// See [`Document::has_focus`].
+ has_focus: bool,
}
/// Information about a declarative refresh
@@ -341,9 +340,16 @@ pub(crate) struct Document {
/// Whether the DOMContentLoaded event has already been dispatched.
domcontentloaded_dispatched: Cell<bool>,
/// The state of this document's focus transaction.
- focus_transaction: DomRefCell<FocusTransaction>,
+ focus_transaction: DomRefCell<Option<FocusTransaction>>,
/// The element that currently has the document focus context.
focused: MutNullableDom<Element>,
+ /// The last sequence number sent to the constellation.
+ #[no_trace]
+ focus_sequence: Cell<FocusSequenceNumber>,
+ /// Indicates whether the container is included in the top-level browsing
+ /// context's focus chain (not considering system focus). Permanently `true`
+ /// for a top-level document.
+ has_focus: Cell<bool>,
/// The script element that is currently executing.
current_script: MutNullableDom<HTMLScriptElement>,
/// <https://html.spec.whatwg.org/multipage/#pending-parsing-blocking-script>
@@ -1120,122 +1126,318 @@ impl Document {
self.focused.get()
}
+ /// Get the last sequence number sent to the constellation.
+ ///
+ /// Received focus-related messages with sequence numbers less than the one
+ /// returned by this method must be discarded.
+ pub fn get_focus_sequence(&self) -> FocusSequenceNumber {
+ self.focus_sequence.get()
+ }
+
+ /// Generate the next sequence number for focus-related messages.
+ fn increment_fetch_focus_sequence(&self) -> FocusSequenceNumber {
+ self.focus_sequence.set(FocusSequenceNumber(
+ self.focus_sequence
+ .get()
+ .0
+ .checked_add(1)
+ .expect("too many focus messages have been sent"),
+ ));
+ self.focus_sequence.get()
+ }
+
/// Initiate a new round of checking for elements requesting focus. The last element to call
/// `request_focus` before `commit_focus_transaction` is called will receive focus.
fn begin_focus_transaction(&self) {
- *self.focus_transaction.borrow_mut() = FocusTransaction::InTransaction(Default::default());
+ // Initialize it with the current state
+ *self.focus_transaction.borrow_mut() = Some(FocusTransaction {
+ element: self.focused.get().as_deref().map(Dom::from_ref),
+ has_focus: self.has_focus.get(),
+ });
}
/// <https://html.spec.whatwg.org/multipage/#focus-fixup-rule>
pub(crate) fn perform_focus_fixup_rule(&self, not_focusable: &Element, can_gc: CanGc) {
+ // Return if `not_focusable` is not the designated focused area of the
+ // `Document`.
if Some(not_focusable) != self.focused.get().as_deref() {
return;
}
- self.request_focus(
- self.GetBody().as_ref().map(|e| e.upcast()),
- FocusType::Element,
- can_gc,
- )
+
+ let implicit_transaction = self.focus_transaction.borrow().is_none();
+
+ if implicit_transaction {
+ self.begin_focus_transaction();
+ }
+
+ // Designate the viewport as the new focused area of the `Document`, but
+ // do not run the focusing steps.
+ {
+ let mut focus_transaction = self.focus_transaction.borrow_mut();
+ focus_transaction.as_mut().unwrap().element = None;
+ }
+
+ if implicit_transaction {
+ self.commit_focus_transaction(FocusInitiator::Local, can_gc);
+ }
}
- /// Request that the given element receive focus once the current transaction is complete.
- /// If None is passed, then whatever element is currently focused will no longer be focused
- /// once the transaction is complete.
+ /// Request that the given element receive focus once the current
+ /// transaction is complete. `None` specifies to focus the document.
+ ///
+ /// If there's no ongoing transaction, this method automatically starts and
+ /// commits an implicit transaction.
pub(crate) fn request_focus(
&self,
elem: Option<&Element>,
- focus_type: FocusType,
+ focus_initiator: FocusInitiator,
can_gc: CanGc,
) {
- let implicit_transaction = matches!(
- *self.focus_transaction.borrow(),
- FocusTransaction::NotInTransaction
- );
+ // If an element is specified, and it's non-focusable, ignore the
+ // request.
+ if elem.is_some_and(|e| !e.is_focusable_area()) {
+ return;
+ }
+
+ let implicit_transaction = self.focus_transaction.borrow().is_none();
+
if implicit_transaction {
self.begin_focus_transaction();
}
- if elem.is_none_or(|e| e.is_focusable_area()) {
- *self.focus_transaction.borrow_mut() =
- FocusTransaction::InTransaction(elem.map(Dom::from_ref));
+
+ {
+ let mut focus_transaction = self.focus_transaction.borrow_mut();
+ let focus_transaction = focus_transaction.as_mut().unwrap();
+ focus_transaction.element = elem.map(Dom::from_ref);
+ focus_transaction.has_focus = true;
}
+
if implicit_transaction {
- self.commit_focus_transaction(focus_type, can_gc);
+ self.commit_focus_transaction(focus_initiator, can_gc);
+ }
+ }
+
+ /// Update the local focus state accordingly after being notified that the
+ /// document's container is removed from the top-level browsing context's
+ /// focus chain (not considering system focus).
+ pub(crate) fn handle_container_unfocus(&self, can_gc: CanGc) {
+ assert!(
+ self.window().parent_info().is_some(),
+ "top-level document cannot be unfocused",
+ );
+
+ // Since this method is called from an event loop, there mustn't be
+ // an in-progress focus transaction
+ assert!(
+ self.focus_transaction.borrow().is_none(),
+ "there mustn't be an in-progress focus transaction at this point"
+ );
+
+ // Start an implicit focus transaction
+ self.begin_focus_transaction();
+
+ // Update the transaction
+ {
+ let mut focus_transaction = self.focus_transaction.borrow_mut();
+ focus_transaction.as_mut().unwrap().has_focus = false;
}
+
+ // Commit the implicit focus transaction
+ self.commit_focus_transaction(FocusInitiator::Remote, can_gc);
}
/// Reassign the focus context to the element that last requested focus during this
- /// transaction, or none if no elements requested it.
- fn commit_focus_transaction(&self, focus_type: FocusType, can_gc: CanGc) {
- let possibly_focused = match *self.focus_transaction.borrow() {
- FocusTransaction::NotInTransaction => unreachable!(),
- FocusTransaction::InTransaction(ref elem) => {
- elem.as_ref().map(|e| DomRoot::from_ref(&**e))
- },
+ /// transaction, or the document if no elements requested it.
+ fn commit_focus_transaction(&self, focus_initiator: FocusInitiator, can_gc: CanGc) {
+ let (mut new_focused, new_focus_state) = {
+ let focus_transaction = self.focus_transaction.borrow();
+ let focus_transaction = focus_transaction
+ .as_ref()
+ .expect("no focus transaction in progress");
+ (
+ focus_transaction
+ .element
+ .as_ref()
+ .map(|e| DomRoot::from_ref(&**e)),
+ focus_transaction.has_focus,
+ )
};
- *self.focus_transaction.borrow_mut() = FocusTransaction::NotInTransaction;
- if self.focused == possibly_focused.as_deref() {
- return;
+ *self.focus_transaction.borrow_mut() = None;
+
+ if !new_focus_state {
+ // In many browsers, a document forgets its focused area when the
+ // document is removed from the top-level BC's focus chain
+ if new_focused.take().is_some() {
+ trace!(
+ "Forgetting the document's focused area because the \
+ document's container was removed from the top-level BC's \
+ focus chain"
+ );
+ }
}
- if let Some(ref elem) = self.focused.get() {
- let node = elem.upcast::<Node>();
- elem.set_focus_state(false);
- // FIXME: pass appropriate relatedTarget
- self.fire_focus_event(FocusEventType::Blur, node, None, can_gc);
- // Notify the embedder to hide the input method.
- if elem.input_method_type().is_some() {
- self.send_to_embedder(EmbedderMsg::HideIME(self.webview_id()));
+ let old_focused = self.focused.get();
+ let old_focus_state = self.has_focus.get();
+
+ debug!(
+ "Committing focus transaction: {:?} → {:?}",
+ (&old_focused, old_focus_state),
+ (&new_focused, new_focus_state),
+ );
+
+ // `*_focused_filtered` indicates the local element (if any) included in
+ // the top-level BC's focus chain.
+ let old_focused_filtered = old_focused.as_ref().filter(|_| old_focus_state);
+ let new_focused_filtered = new_focused.as_ref().filter(|_| new_focus_state);
+
+ let trace_focus_chain = |name, element, doc| {
+ trace!(
+ "{} local focus chain: {}",
+ name,
+ match (element, doc) {
+ (Some(e), _) => format!("[{:?}, document]", e),
+ (None, true) => "[document]".to_owned(),
+ (None, false) => "[]".to_owned(),
+ }
+ );
+ };
+
+ trace_focus_chain("Old", old_focused_filtered, old_focus_state);
+ trace_focus_chain("New", new_focused_filtered, new_focus_state);
+
+ if old_focused_filtered != new_focused_filtered {
+ if let Some(elem) = &old_focused_filtered {
+ let node = elem.upcast::<Node>();
+ elem.set_focus_state(false);
+ // FIXME: pass appropriate relatedTarget
+ if node.is_connected() {
+ self.fire_focus_event(FocusEventType::Blur, node.upcast(), None, can_gc);
+ }
+
+ // Notify the embedder to hide the input method.
+ if elem.input_method_type().is_some() {
+ self.send_to_embedder(EmbedderMsg::HideIME(self.webview_id()));
+ }
}
}
- self.focused.set(possibly_focused.as_deref());
+ if old_focus_state != new_focus_state && !new_focus_state {
+ self.fire_focus_event(FocusEventType::Blur, self.global().upcast(), None, can_gc);
+ }
- if let Some(ref elem) = self.focused.get() {
- elem.set_focus_state(true);
- let node = elem.upcast::<Node>();
- // FIXME: pass appropriate relatedTarget
- self.fire_focus_event(FocusEventType::Focus, node, None, can_gc);
- // Update the focus state for all elements in the focus chain.
- // https://html.spec.whatwg.org/multipage/#focus-chain
- if focus_type == FocusType::Element {
- self.window()
- .send_to_constellation(ScriptToConstellationMessage::Focus);
+ self.focused.set(new_focused.as_deref());
+ self.has_focus.set(new_focus_state);
+
+ if old_focus_state != new_focus_state && new_focus_state {
+ self.fire_focus_event(FocusEventType::Focus, self.global().upcast(), None, can_gc);
+ }
+
+ if old_focused_filtered != new_focused_filtered {
+ if let Some(elem) = &new_focused_filtered {
+ elem.set_focus_state(true);
+ let node = elem.upcast::<Node>();
+ // FIXME: pass appropriate relatedTarget
+ self.fire_focus_event(FocusEventType::Focus, node.upcast(), None, can_gc);
+
+ // Notify the embedder to display an input method.
+ if let Some(kind) = elem.input_method_type() {
+ let rect = elem.upcast::<Node>().bounding_content_box_or_zero(can_gc);
+ let rect = Rect::new(
+ Point2D::new(rect.origin.x.to_px(), rect.origin.y.to_px()),
+ Size2D::new(rect.size.width.to_px(), rect.size.height.to_px()),
+ );
+ let (text, multiline) = if let Some(input) = elem.downcast::<HTMLInputElement>()
+ {
+ (
+ Some((
+ (input.Value()).to_string(),
+ input.GetSelectionEnd().unwrap_or(0) as i32,
+ )),
+ false,
+ )
+ } else if let Some(textarea) = elem.downcast::<HTMLTextAreaElement>() {
+ (
+ Some((
+ (textarea.Value()).to_string(),
+ textarea.GetSelectionEnd().unwrap_or(0) as i32,
+ )),
+ true,
+ )
+ } else {
+ (None, false)
+ };
+ self.send_to_embedder(EmbedderMsg::ShowIME(
+ self.webview_id(),
+ kind,
+ text,
+ multiline,
+ DeviceIntRect::from_untyped(&rect.to_box2d()),
+ ));
+ }
}
+ }
+
+ if focus_initiator != FocusInitiator::Local {
+ return;
+ }
- // Notify the embedder to display an input method.
- if let Some(kind) = elem.input_method_type() {
- let rect = elem.upcast::<Node>().bounding_content_box_or_zero(can_gc);
- let rect = Rect::new(
- Point2D::new(rect.origin.x.to_px(), rect.origin.y.to_px()),
- Size2D::new(rect.size.width.to_px(), rect.size.height.to_px()),
+ // We are the initiator of the focus operation, so we must broadcast
+ // the change we intend to make.
+ match (old_focus_state, new_focus_state) {
+ (_, true) => {
+ // Advertise the change in the focus chain.
+ // <https://html.spec.whatwg.org/multipage/#focus-chain>
+ // <https://html.spec.whatwg.org/multipage/#focusing-steps>
+ //
+ // If the top-level BC doesn't have system focus, this won't
+ // have an immediate effect, but it will when we gain system
+ // focus again. Therefore we still have to send `ScriptMsg::
+ // Focus`.
+ //
+ // When a container with a non-null nested browsing context is
+ // focused, its active document becomes the focused area of the
+ // top-level browsing context instead. Therefore we need to let
+ // the constellation know if such a container is focused.
+ //
+ // > The focusing steps for an object `new focus target` [...]
+ // >
+ // > 3. If `new focus target` is a browsing context container
+ // > with non-null nested browsing context, then set
+ // > `new focus target` to the nested browsing context's
+ // > active document.
+ let child_browsing_context_id = new_focused
+ .as_ref()
+ .and_then(|elem| elem.downcast::<HTMLIFrameElement>())
+ .and_then(|iframe| iframe.browsing_context_id());
+
+ let sequence = self.increment_fetch_focus_sequence();
+
+ debug!(
+ "Advertising the focus request to the constellation \
+ with sequence number {} and child BC ID {}",
+ sequence,
+ child_browsing_context_id
+ .as_ref()
+ .map(|id| id as &dyn std::fmt::Display)
+ .unwrap_or(&"(none)"),
);
- let (text, multiline) = if let Some(input) = elem.downcast::<HTMLInputElement>() {
- (
- Some((
- input.Value().to_string(),
- input.GetSelectionEnd().unwrap_or(0) as i32,
- )),
- false,
- )
- } else if let Some(textarea) = elem.downcast::<HTMLTextAreaElement>() {
- (
- Some((
- textarea.Value().to_string(),
- textarea.GetSelectionEnd().unwrap_or(0) as i32,
- )),
- true,
- )
- } else {
- (None, false)
- };
- self.send_to_embedder(EmbedderMsg::ShowIME(
- self.webview_id(),
- kind,
- text,
- multiline,
- DeviceIntRect::from_untyped(&rect.to_box2d()),
- ));
- }
+
+ self.window()
+ .send_to_constellation(ScriptToConstellationMessage::Focus(
+ child_browsing_context_id,
+ sequence,
+ ));
+ },
+ (false, false) => {
+ // Our `Document` doesn't have focus, and we intend to keep it
+ // this way.
+ },
+ (true, false) => {
+ unreachable!(
+ "Can't lose the document's focus without specifying \
+ another one to focus"
+ );
+ },
}
}
@@ -1350,7 +1552,10 @@ impl Document {
}
self.begin_focus_transaction();
- self.request_focus(Some(&*el), FocusType::Element, can_gc);
+ // Try to focus `el`. If it's not focusable, focus the document
+ // instead.
+ self.request_focus(None, FocusInitiator::Local, can_gc);
+ self.request_focus(Some(&*el), FocusInitiator::Local, can_gc);
}
let dom_event = DomRoot::upcast::<Event>(MouseEvent::for_platform_mouse_event(
@@ -1388,7 +1593,9 @@ impl Document {
}
if let MouseButtonAction::Click = event.action {
- self.commit_focus_transaction(FocusType::Element, can_gc);
+ if self.focus_transaction.borrow().is_some() {
+ self.commit_focus_transaction(FocusInitiator::Local, can_gc);
+ }
self.maybe_fire_dblclick(
hit_test_result.point_in_viewport,
node,
@@ -2215,7 +2422,7 @@ impl Document {
ImeEvent::Dismissed => {
self.request_focus(
self.GetBody().as_ref().map(|e| e.upcast()),
- FocusType::Element,
+ FocusInitiator::Local,
can_gc,
);
return;
@@ -3194,7 +3401,7 @@ impl Document {
fn fire_focus_event(
&self,
focus_event_type: FocusEventType,
- node: &Node,
+ event_target: &EventTarget,
related_target: Option<&EventTarget>,
can_gc: CanGc,
) {
@@ -3214,8 +3421,7 @@ impl Document {
);
let event = event.upcast::<Event>();
event.set_trusted(true);
- let target = node.upcast();
- event.fire(target, can_gc);
+ event.fire(event_target, can_gc);
}
/// <https://html.spec.whatwg.org/multipage/#cookie-averse-document-object>
@@ -3795,6 +4001,8 @@ impl Document {
.and_then(|charset| Encoding::for_label(charset.as_bytes()))
.unwrap_or(UTF_8);
+ let has_focus = window.parent_info().is_none();
+
let has_browsing_context = has_browsing_context == HasBrowsingContext::Yes;
Document {
@@ -3842,8 +4050,10 @@ impl Document {
stylesheet_list: MutNullableDom::new(None),
ready_state: Cell::new(ready_state),
domcontentloaded_dispatched: Cell::new(domcontentloaded_dispatched),
- focus_transaction: DomRefCell::new(FocusTransaction::NotInTransaction),
+ focus_transaction: DomRefCell::new(None),
focused: Default::default(),
+ focus_sequence: Cell::new(FocusSequenceNumber::default()),
+ has_focus: Cell::new(has_focus),
current_script: Default::default(),
pending_parsing_blocking_script: Default::default(),
script_blocking_stylesheets_count: Cell::new(0u32),
@@ -4989,12 +5199,34 @@ impl DocumentMethods<crate::DomTypeHolder> for Document {
// https://html.spec.whatwg.org/multipage/#dom-document-hasfocus
fn HasFocus(&self) -> bool {
- // Step 1-2.
- if self.window().parent_info().is_none() && self.is_fully_active() {
- return true;
+ // <https://html.spec.whatwg.org/multipage/#has-focus-steps>
+ //
+ // > The has focus steps, given a `Document` object `target`, are as
+ // > follows:
+ // >
+ // > 1. If `target`'s browsing context's top-level browsing context does
+ // > not have system focus, then return false.
+
+ // > 2. Let `candidate` be `target`'s browsing context's top-level
+ // > browsing context's active document.
+ // >
+ // > 3. While true:
+ // >
+ // > 3.1. If `candidate` is target, then return true.
+ // >
+ // > 3.2. If the focused area of `candidate` is a browsing context
+ // > container with a non-null nested browsing context, then set
+ // > `candidate` to the active document of that browsing context
+ // > container's nested browsing context.
+ // >
+ // > 3.3. Otherwise, return false.
+ if self.window().parent_info().is_none() {
+ // 2 → 3 → (3.1 || ⋯ → 3.3)
+ self.is_fully_active()
+ } else {
+ // 2 → 3 → 3.2 → (⋯ → 3.1 || ⋯ → 3.3)
+ self.is_fully_active() && self.has_focus.get()
}
- // TODO Step 3.
- false
}
// https://html.spec.whatwg.org/multipage/#dom-document-domain
@@ -6397,6 +6629,17 @@ pub(crate) enum FocusType {
Parent, // Focusing a parent element (an iframe)
}
+/// Specifies the initiator of a focus operation.
+#[derive(Clone, Copy, PartialEq)]
+pub enum FocusInitiator {
+ /// The operation is initiated by this document and to be broadcasted
+ /// through the constellation.
+ Local,
+ /// The operation is initiated somewhere else, and we are updating our
+ /// internal state accordingly.
+ Remote,
+}
+
/// Focus events
pub(crate) enum FocusEventType {
Focus, // Element gained focus. Doesn't bubble.
diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs
index 3a8ac8f0cd8..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};
@@ -327,7 +326,21 @@ impl Element {
)
}
- impl_rare_data!(ElementRareData);
+ fn rare_data(&self) -> Ref<Option<Box<ElementRareData>>> {
+ self.rare_data.borrow()
+ }
+
+ fn rare_data_mut(&self) -> RefMut<Option<Box<ElementRareData>>> {
+ self.rare_data.borrow_mut()
+ }
+
+ fn ensure_rare_data(&self) -> RefMut<Box<ElementRareData>> {
+ let mut rare_data = self.rare_data.borrow_mut();
+ if rare_data.is_none() {
+ *rare_data = Some(Default::default());
+ }
+ RefMut::map(rare_data, |rare_data| rare_data.as_mut().unwrap())
+ }
pub(crate) fn restyle(&self, damage: NodeDamage) {
let doc = self.node.owner_doc();
@@ -1947,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(),
@@ -3011,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 b3345b90fc0..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;
@@ -457,8 +453,9 @@ pub(crate) struct ManagedMessagePort {
/// and only add them, and ask the constellation to complete the transfer,
/// in a subsequent task if the port hasn't been re-transfered.
pending: bool,
- /// Has the port been closed? If closed, it can be dropped and later GC'ed.
- closed: bool,
+ /// Whether the port has been closed by script in this global,
+ /// so it can be removed.
+ explicitly_closed: bool,
/// Note: it may seem strange to use a pair of options, versus for example an enum.
/// But it looks like tranform streams will require both of those in their transfer.
/// This will be resolved when we reach that point of the implementation.
@@ -546,12 +543,17 @@ impl MessageListener {
let mut succeeded = vec![];
let mut failed = HashMap::new();
- for (id, buffer) in ports.into_iter() {
+ for (id, info) in ports.into_iter() {
if global.is_managing_port(&id) {
succeeded.push(id);
- global.complete_port_transfer(id, buffer);
+ global.complete_port_transfer(
+ id,
+ info.port_message_queue,
+ info.disentangled,
+ CanGc::note()
+ );
} else {
- failed.insert(id, buffer);
+ failed.insert(id, info);
}
}
let _ = global.script_to_constellation_chan().send(
@@ -560,13 +562,21 @@ impl MessageListener {
})
);
},
- MessagePortMsg::CompletePendingTransfer(port_id, buffer) => {
+ MessagePortMsg::CompletePendingTransfer(port_id, info) => {
let context = self.context.clone();
self.task_source.queue(task!(complete_pending: move || {
let global = context.root();
- global.complete_port_transfer(port_id, buffer);
+ global.complete_port_transfer(port_id, info.port_message_queue, info.disentangled, CanGc::note());
}));
},
+ MessagePortMsg::CompleteDisentanglement(port_id) => {
+ let context = self.context.clone();
+ self.task_source
+ .queue(task!(try_complete_disentanglement: move || {
+ let global = context.root();
+ global.try_complete_disentanglement(port_id, CanGc::note());
+ }));
+ },
MessagePortMsg::NewTask(port_id, task) => {
let context = self.context.clone();
self.task_source.queue(task!(process_new_task: move || {
@@ -574,14 +584,6 @@ impl MessageListener {
global.route_task_to_port(port_id, task, CanGc::note());
}));
},
- MessagePortMsg::RemoveMessagePort(port_id) => {
- let context = self.context.clone();
- self.task_source
- .queue(task!(process_remove_message_port: move || {
- let global = context.root();
- global.note_entangled_port_removed(&port_id);
- }));
- },
}
}
}
@@ -871,7 +873,13 @@ impl GlobalScope {
}
/// Complete the transfer of a message-port.
- fn complete_port_transfer(&self, port_id: MessagePortId, tasks: VecDeque<PortMessageTask>) {
+ fn complete_port_transfer(
+ &self,
+ port_id: MessagePortId,
+ tasks: VecDeque<PortMessageTask>,
+ disentangled: bool,
+ can_gc: CanGc,
+ ) {
let should_start = if let MessagePortState::Managed(_id, message_ports) =
&mut *self.message_port_state.borrow_mut()
{
@@ -885,6 +893,10 @@ impl GlobalScope {
}
if let Some(port_impl) = managed_port.port_impl.as_mut() {
port_impl.complete_transfer(tasks);
+ if disentangled {
+ port_impl.disentangle();
+ managed_port.dom_port.disentangle();
+ }
port_impl.enabled()
} else {
panic!("managed-port has no port-impl.");
@@ -895,7 +907,45 @@ impl GlobalScope {
panic!("complete_port_transfer called for an unknown port.");
};
if should_start {
- self.start_message_port(&port_id);
+ self.start_message_port(&port_id, can_gc);
+ }
+ }
+
+ /// The closing of `otherPort`, if it is in a different global.
+ /// <https://html.spec.whatwg.org/multipage/#disentangle>
+ fn try_complete_disentanglement(&self, port_id: MessagePortId, can_gc: CanGc) {
+ let dom_port = if let MessagePortState::Managed(_id, message_ports) =
+ &mut *self.message_port_state.borrow_mut()
+ {
+ let dom_port = if let Some(managed_port) = message_ports.get_mut(&port_id) {
+ if managed_port.pending {
+ unreachable!("CompleteDisentanglement msg received for a pending port.");
+ }
+ let port_impl = managed_port
+ .port_impl
+ .as_mut()
+ .expect("managed-port has no port-impl.");
+ port_impl.disentangle();
+ managed_port.dom_port.as_rooted()
+ } else {
+ // Note: this, and the other return below,
+ // can happen if the port has already been transferred out of this global,
+ // in which case the disentanglement will complete along with the transfer.
+ return;
+ };
+ dom_port
+ } else {
+ return;
+ };
+
+ // Fire an event named close at otherPort.
+ dom_port.upcast().fire_event(atom!("close"), can_gc);
+
+ let res = self.script_to_constellation_chan().send(
+ ScriptToConstellationMessage::DisentanglePorts(port_id, None),
+ );
+ if res.is_err() {
+ warn!("Sending DisentanglePorts failed");
}
}
@@ -951,8 +1001,64 @@ impl GlobalScope {
}
/// <https://html.spec.whatwg.org/multipage/#disentangle>
- pub(crate) fn disentangle_port(&self, _port: &MessagePort) {
- // TODO: #36465
+ pub(crate) fn disentangle_port(&self, port: &MessagePort, can_gc: CanGc) {
+ let initiator_port = port.message_port_id();
+ // Let otherPort be the MessagePort which initiatorPort was entangled with.
+ let Some(other_port) = port.disentangle() else {
+ // Assert: otherPort exists.
+ // Note: ignoring the assert,
+ // because the streams spec seems to disentangle ports that are disentangled already.
+ return;
+ };
+
+ // Disentangle initiatorPort and otherPort, so that they are no longer entangled or associated with each other.
+ // Note: this is done in part here, and in part at the constellation(if otherPort is in another global).
+ let dom_port = if let MessagePortState::Managed(_id, message_ports) =
+ &mut *self.message_port_state.borrow_mut()
+ {
+ let mut dom_port = None;
+ for port_id in &[initiator_port, &other_port] {
+ match message_ports.get_mut(port_id) {
+ None => {
+ continue;
+ },
+ Some(managed_port) => {
+ let port_impl = managed_port
+ .port_impl
+ .as_mut()
+ .expect("managed-port has no port-impl.");
+ managed_port.dom_port.disentangle();
+ port_impl.disentangle();
+
+ if **port_id == other_port {
+ dom_port = Some(managed_port.dom_port.as_rooted())
+ }
+ },
+ }
+ }
+ dom_port
+ } else {
+ panic!("disentangle_port called on a global not managing any ports.");
+ };
+
+ // Fire an event named close at `otherPort`.
+ // Note: done here if the port is managed by the same global as `initialPort`.
+ if let Some(dom_port) = dom_port {
+ dom_port.upcast().fire_event(atom!("close"), can_gc);
+ }
+
+ let chan = self.script_to_constellation_chan().clone();
+ let initiator_port = *initiator_port;
+ self.task_manager()
+ .port_message_queue()
+ .queue(task!(post_message: move || {
+ // Note: we do this in a task to ensure it doesn't affect messages that are still to be routed,
+ // see the task queueing in `post_messageport_msg`.
+ let res = chan.send(ScriptToConstellationMessage::DisentanglePorts(initiator_port, Some(other_port)));
+ if res.is_err() {
+ warn!("Sending DisentanglePorts failed");
+ }
+ }));
}
/// <https://html.spec.whatwg.org/multipage/#entangle>
@@ -984,18 +1090,6 @@ impl GlobalScope {
.send(ScriptToConstellationMessage::EntanglePorts(port1, port2));
}
- /// Note that the entangled port of `port_id` has been removed in another global.
- pub(crate) fn note_entangled_port_removed(&self, port_id: &MessagePortId) {
- // Note: currently this is a no-op,
- // as we only use the `close` method to manage the local lifecyle of a port.
- // This could be used as part of lifecyle management to determine a port can be GC'ed.
- // See https://github.com/servo/servo/issues/25772
- warn!(
- "Entangled port of {:?} has been removed in another global",
- port_id
- );
- }
-
/// Handle the transfer of a port in the current task.
pub(crate) fn mark_port_as_transferred(&self, port_id: &MessagePortId) -> MessagePortImpl {
if let MessagePortState::Managed(_id, message_ports) =
@@ -1021,20 +1115,21 @@ impl GlobalScope {
}
/// <https://html.spec.whatwg.org/multipage/#dom-messageport-start>
- pub(crate) fn start_message_port(&self, port_id: &MessagePortId) {
- let message_buffer = if let MessagePortState::Managed(_id, message_ports) =
+ pub(crate) fn start_message_port(&self, port_id: &MessagePortId, can_gc: CanGc) {
+ let (message_buffer, dom_port) = if let MessagePortState::Managed(_id, message_ports) =
&mut *self.message_port_state.borrow_mut()
{
- match message_ports.get_mut(port_id) {
+ let (message_buffer, dom_port) = match message_ports.get_mut(port_id) {
None => panic!("start_message_port called on a unknown port."),
Some(managed_port) => {
if let Some(port_impl) = managed_port.port_impl.as_mut() {
- port_impl.start()
+ (port_impl.start(), managed_port.dom_port.as_rooted())
} else {
panic!("managed-port has no port-impl.");
}
},
- }
+ };
+ (message_buffer, dom_port)
} else {
return warn!("start_message_port called on a global not managing any ports.");
};
@@ -1042,6 +1137,18 @@ impl GlobalScope {
for task in message_buffer {
self.route_task_to_port(*port_id, task, CanGc::note());
}
+ if dom_port.disentangled() {
+ // <https://html.spec.whatwg.org/multipage/#disentangle>
+ // Fire an event named close at otherPort.
+ dom_port.upcast().fire_event(atom!("close"), can_gc);
+
+ let res = self.script_to_constellation_chan().send(
+ ScriptToConstellationMessage::DisentanglePorts(*port_id, None),
+ );
+ if res.is_err() {
+ warn!("Sending DisentanglePorts failed");
+ }
+ }
}
}
@@ -1055,7 +1162,7 @@ impl GlobalScope {
Some(managed_port) => {
if let Some(port_impl) = managed_port.port_impl.as_mut() {
port_impl.close();
- managed_port.closed = true;
+ managed_port.explicitly_closed = true;
} else {
panic!("managed-port has no port-impl.");
}
@@ -1436,12 +1543,7 @@ impl GlobalScope {
let to_be_removed: Vec<MessagePortId> = message_ports
.iter()
.filter_map(|(id, managed_port)| {
- if managed_port.closed {
- // Let the constellation know to drop this port and the one it is entangled with,
- // and to forward this message to the script-process where the entangled is found.
- let _ = self
- .script_to_constellation_chan()
- .send(ScriptToConstellationMessage::RemoveMessagePort(*id));
+ if managed_port.explicitly_closed {
Some(*id)
} else {
None
@@ -1451,6 +1553,9 @@ impl GlobalScope {
for id in to_be_removed {
message_ports.remove(&id);
}
+ // Note: ports are only removed throught explicit closure by script in this global.
+ // TODO: #25772
+ // TODO: remove ports when we can be sure their port message queue is empty(via the constellation).
message_ports.is_empty()
} else {
false
@@ -1581,7 +1686,7 @@ impl GlobalScope {
port_impl: Some(port_impl),
dom_port: Dom::from_ref(dom_port),
pending: true,
- closed: false,
+ explicitly_closed: false,
cross_realm_transform_readable: None,
cross_realm_transform_writable: None,
},
@@ -1605,7 +1710,7 @@ impl GlobalScope {
port_impl: Some(port_impl),
dom_port: Dom::from_ref(dom_port),
pending: false,
- closed: false,
+ explicitly_closed: false,
cross_realm_transform_readable: None,
cross_realm_transform_writable: None,
},
@@ -2848,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,
@@ -3178,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 bb27d28cea8..56e008839ba 100644
--- a/components/script/dom/htmlcanvaselement.rs
+++ b/components/script/dom/htmlcanvaselement.rs
@@ -21,20 +21,19 @@ 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;
use style::attr::AttrValue;
-use crate::canvas_context::CanvasContext as _;
pub(crate) use crate::canvas_context::*;
use crate::conversions::Convert;
use crate::dom::attr::Attr;
use crate::dom::bindings::callback::ExceptionHandling;
use crate::dom::bindings::cell::{DomRefCell, Ref, ref_filter_map};
use crate::dom::bindings::codegen::Bindings::HTMLCanvasElementBinding::{
- BlobCallback, HTMLCanvasElementMethods, RenderingContext,
+ BlobCallback, HTMLCanvasElementMethods, RenderingContext as RootedRenderingContext,
};
use crate::dom::bindings::codegen::Bindings::MediaStreamBinding::MediaStreamMethods;
use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLContextAttributes;
@@ -104,21 +103,10 @@ impl EncodedImageType {
}
}
-#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
-#[derive(Clone, JSTraceable, MallocSizeOf)]
-pub(crate) enum CanvasContext {
- Placeholder(Dom<OffscreenCanvas>),
- Context2d(Dom<CanvasRenderingContext2D>),
- WebGL(Dom<WebGLRenderingContext>),
- WebGL2(Dom<WebGL2RenderingContext>),
- #[cfg(feature = "webgpu")]
- WebGPU(Dom<GPUCanvasContext>),
-}
-
#[dom_struct]
pub(crate) struct HTMLCanvasElement {
htmlelement: HTMLElement,
- context: DomRefCell<Option<CanvasContext>>,
+ context: DomRefCell<Option<RenderingContext>>,
// This id and hashmap are used to keep track of ongoing toBlob() calls.
callback_id: Cell<u32>,
#[ignore_malloc_size_of = "not implemented for webidl callbacks"]
@@ -159,14 +147,7 @@ impl HTMLCanvasElement {
fn recreate_contexts_after_resize(&self) {
if let Some(ref context) = *self.context.borrow() {
- match *context {
- CanvasContext::Context2d(ref context) => context.resize(),
- CanvasContext::WebGL(ref context) => context.resize(),
- CanvasContext::WebGL2(ref context) => context.resize(),
- #[cfg(feature = "webgpu")]
- CanvasContext::WebGPU(ref context) => context.resize(),
- CanvasContext::Placeholder(ref context) => context.resize(self.get_size().cast()),
- }
+ context.resize()
}
}
@@ -176,23 +157,14 @@ impl HTMLCanvasElement {
pub(crate) fn origin_is_clean(&self) -> bool {
match *self.context.borrow() {
- Some(CanvasContext::Context2d(ref context)) => context.origin_is_clean(),
+ Some(ref context) => context.origin_is_clean(),
_ => true,
}
}
pub(crate) fn mark_as_dirty(&self) {
if let Some(ref context) = *self.context.borrow() {
- match *context {
- CanvasContext::Context2d(ref context) => context.mark_as_dirty(),
- CanvasContext::WebGL(ref context) => context.mark_as_dirty(),
- CanvasContext::WebGL2(ref context) => context.mark_as_dirty(),
- #[cfg(feature = "webgpu")]
- CanvasContext::WebGPU(ref context) => context.mark_as_dirty(),
- CanvasContext::Placeholder(ref _context) => {
- // TODO: Should this be marked as dirty?
- },
- }
+ context.mark_as_dirty()
}
}
@@ -222,12 +194,14 @@ impl LayoutHTMLCanvasElementHelpers for LayoutDom<'_, HTMLCanvasElement> {
fn data(self) -> HTMLCanvasData {
let source = unsafe {
match self.unsafe_get().context.borrow_for_layout().as_ref() {
- Some(CanvasContext::Context2d(context)) => context.to_layout().canvas_data_source(),
- Some(CanvasContext::WebGL(context)) => context.to_layout().canvas_data_source(),
- Some(CanvasContext::WebGL2(context)) => context.to_layout().canvas_data_source(),
+ Some(RenderingContext::Context2d(context)) => {
+ context.to_layout().canvas_data_source()
+ },
+ Some(RenderingContext::WebGL(context)) => context.to_layout().canvas_data_source(),
+ Some(RenderingContext::WebGL2(context)) => context.to_layout().canvas_data_source(),
#[cfg(feature = "webgpu")]
- Some(CanvasContext::WebGPU(context)) => context.to_layout().canvas_data_source(),
- Some(CanvasContext::Placeholder(_)) | None => HTMLCanvasDataSource::Empty,
+ Some(RenderingContext::WebGPU(context)) => context.to_layout().canvas_data_source(),
+ Some(RenderingContext::Placeholder(_)) | None => None,
}
};
@@ -246,14 +220,14 @@ impl LayoutHTMLCanvasElementHelpers for LayoutDom<'_, HTMLCanvasElement> {
}
impl HTMLCanvasElement {
- pub(crate) fn context(&self) -> Option<Ref<CanvasContext>> {
+ pub(crate) fn context(&self) -> Option<Ref<RenderingContext>> {
ref_filter_map(self.context.borrow(), |ctx| ctx.as_ref())
}
fn get_or_init_2d_context(&self, can_gc: CanGc) -> Option<DomRoot<CanvasRenderingContext2D>> {
if let Some(ctx) = self.context() {
return match *ctx {
- CanvasContext::Context2d(ref ctx) => Some(DomRoot::from_ref(ctx)),
+ RenderingContext::Context2d(ref ctx) => Some(DomRoot::from_ref(ctx)),
_ => None,
};
}
@@ -261,7 +235,7 @@ impl HTMLCanvasElement {
let window = self.owner_window();
let size = self.get_size();
let context = CanvasRenderingContext2D::new(window.as_global_scope(), self, size, can_gc);
- *self.context.borrow_mut() = Some(CanvasContext::Context2d(Dom::from_ref(&*context)));
+ *self.context.borrow_mut() = Some(RenderingContext::Context2d(Dom::from_ref(&*context)));
Some(context)
}
@@ -273,7 +247,7 @@ impl HTMLCanvasElement {
) -> Option<DomRoot<WebGLRenderingContext>> {
if let Some(ctx) = self.context() {
return match *ctx {
- CanvasContext::WebGL(ref ctx) => Some(DomRoot::from_ref(ctx)),
+ RenderingContext::WebGL(ref ctx) => Some(DomRoot::from_ref(ctx)),
_ => None,
};
}
@@ -289,7 +263,7 @@ impl HTMLCanvasElement {
attrs,
can_gc,
)?;
- *self.context.borrow_mut() = Some(CanvasContext::WebGL(Dom::from_ref(&*context)));
+ *self.context.borrow_mut() = Some(RenderingContext::WebGL(Dom::from_ref(&*context)));
Some(context)
}
@@ -305,7 +279,7 @@ impl HTMLCanvasElement {
}
if let Some(ctx) = self.context() {
return match *ctx {
- CanvasContext::WebGL2(ref ctx) => Some(DomRoot::from_ref(ctx)),
+ RenderingContext::WebGL2(ref ctx) => Some(DomRoot::from_ref(ctx)),
_ => None,
};
}
@@ -314,7 +288,7 @@ impl HTMLCanvasElement {
let attrs = Self::get_gl_attributes(cx, options)?;
let canvas = HTMLCanvasElementOrOffscreenCanvas::HTMLCanvasElement(DomRoot::from_ref(self));
let context = WebGL2RenderingContext::new(&window, &canvas, size, attrs, can_gc)?;
- *self.context.borrow_mut() = Some(CanvasContext::WebGL2(Dom::from_ref(&*context)));
+ *self.context.borrow_mut() = Some(RenderingContext::WebGL2(Dom::from_ref(&*context)));
Some(context)
}
@@ -327,7 +301,7 @@ impl HTMLCanvasElement {
fn get_or_init_webgpu_context(&self, can_gc: CanGc) -> Option<DomRoot<GPUCanvasContext>> {
if let Some(ctx) = self.context() {
return match *ctx {
- CanvasContext::WebGPU(ref ctx) => Some(DomRoot::from_ref(ctx)),
+ RenderingContext::WebGPU(ref ctx) => Some(DomRoot::from_ref(ctx)),
_ => None,
};
}
@@ -341,7 +315,8 @@ impl HTMLCanvasElement {
.expect("Failed to get WebGPU channel")
.map(|channel| {
let context = GPUCanvasContext::new(&global_scope, self, channel, can_gc);
- *self.context.borrow_mut() = Some(CanvasContext::WebGPU(Dom::from_ref(&*context)));
+ *self.context.borrow_mut() =
+ Some(RenderingContext::WebGPU(Dom::from_ref(&*context)));
context
})
}
@@ -349,8 +324,8 @@ impl HTMLCanvasElement {
/// Gets the base WebGLRenderingContext for WebGL or WebGL 2, if exists.
pub(crate) fn get_base_webgl_context(&self) -> Option<DomRoot<WebGLRenderingContext>> {
match *self.context.borrow() {
- Some(CanvasContext::WebGL(ref context)) => Some(DomRoot::from_ref(context)),
- Some(CanvasContext::WebGL2(ref context)) => Some(context.base_context()),
+ Some(RenderingContext::WebGL(ref context)) => Some(DomRoot::from_ref(context)),
+ Some(RenderingContext::WebGL2(ref context)) => Some(context.base_context()),
_ => None,
}
}
@@ -378,12 +353,7 @@ impl HTMLCanvasElement {
pub(crate) fn get_image_data(&self) -> Option<Snapshot> {
match self.context.borrow().as_ref() {
- Some(CanvasContext::Context2d(context)) => context.get_image_data(),
- Some(CanvasContext::WebGL(context)) => context.get_image_data(),
- Some(CanvasContext::WebGL2(context)) => context.get_image_data(),
- #[cfg(feature = "webgpu")]
- Some(CanvasContext::WebGPU(context)) => context.get_image_data(),
- Some(CanvasContext::Placeholder(context)) => context.get_image_data(),
+ Some(context) => context.get_image_data(),
None => {
let size = self.get_size();
if size.width == 0 || size.height == 0 {
@@ -466,7 +436,7 @@ impl HTMLCanvasElementMethods<crate::DomTypeHolder> for HTMLCanvasElement {
// is set to placeholder, the user agent must throw an "InvalidStateError" DOMException and leave the
// attribute's value unchanged.
fn SetWidth(&self, value: u32, can_gc: CanGc) -> Fallible<()> {
- if let Some(CanvasContext::Placeholder(_)) = *self.context.borrow() {
+ if let Some(RenderingContext::Placeholder(_)) = *self.context.borrow() {
return Err(Error::InvalidState);
}
@@ -485,7 +455,7 @@ impl HTMLCanvasElementMethods<crate::DomTypeHolder> for HTMLCanvasElement {
// https://html.spec.whatwg.org/multipage/#dom-canvas-height
fn SetHeight(&self, value: u32, can_gc: CanGc) -> Fallible<()> {
- if let Some(CanvasContext::Placeholder(_)) = *self.context.borrow() {
+ if let Some(RenderingContext::Placeholder(_)) = *self.context.borrow() {
return Err(Error::InvalidState);
}
@@ -506,26 +476,26 @@ impl HTMLCanvasElementMethods<crate::DomTypeHolder> for HTMLCanvasElement {
id: DOMString,
options: HandleValue,
can_gc: CanGc,
- ) -> Fallible<Option<RenderingContext>> {
+ ) -> Fallible<Option<RootedRenderingContext>> {
// Always throw an InvalidState exception when the canvas is in Placeholder mode (See table in the spec).
- if let Some(CanvasContext::Placeholder(_)) = *self.context.borrow() {
+ if let Some(RenderingContext::Placeholder(_)) = *self.context.borrow() {
return Err(Error::InvalidState);
}
Ok(match &*id {
"2d" => self
.get_or_init_2d_context(can_gc)
- .map(RenderingContext::CanvasRenderingContext2D),
+ .map(RootedRenderingContext::CanvasRenderingContext2D),
"webgl" | "experimental-webgl" => self
.get_or_init_webgl_context(cx, options, can_gc)
- .map(RenderingContext::WebGLRenderingContext),
+ .map(RootedRenderingContext::WebGLRenderingContext),
"webgl2" | "experimental-webgl2" => self
.get_or_init_webgl2_context(cx, options, can_gc)
- .map(RenderingContext::WebGL2RenderingContext),
+ .map(RootedRenderingContext::WebGL2RenderingContext),
#[cfg(feature = "webgpu")]
"webgpu" => self
.get_or_init_webgpu_context(can_gc)
- .map(RenderingContext::GPUCanvasContext),
+ .map(RootedRenderingContext::GPUCanvasContext),
_ => None,
})
}
@@ -672,7 +642,8 @@ impl HTMLCanvasElementMethods<crate::DomTypeHolder> for HTMLCanvasElement {
can_gc,
);
// Step 4. Set this canvas element's context mode to placeholder.
- *self.context.borrow_mut() = Some(CanvasContext::Placeholder(offscreen_canvas.as_traced()));
+ *self.context.borrow_mut() =
+ Some(RenderingContext::Placeholder(offscreen_canvas.as_traced()));
// Step 5. Return offscreenCanvas.
Ok(offscreen_canvas)
diff --git a/components/script/dom/htmldetailselement.rs b/components/script/dom/htmldetailselement.rs
index a3e2a05af32..1d48b8e7a97 100644
--- a/components/script/dom/htmldetailselement.rs
+++ b/components/script/dom/htmldetailselement.rs
@@ -178,8 +178,6 @@ impl HTMLDetailsElement {
}
}
shadow_tree.descendants.Assign(slottable_children);
-
- self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
}
fn update_shadow_tree_styles(&self, can_gc: CanGc) {
@@ -214,8 +212,6 @@ impl HTMLDetailsElement {
.implicit_summary
.upcast::<Element>()
.set_string_attribute(&local_name!("style"), implicit_summary_style.into(), can_gc);
-
- self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
}
}
diff --git a/components/script/dom/htmlelement.rs b/components/script/dom/htmlelement.rs
index 9505d5182c7..59b71543d6d 100644
--- a/components/script/dom/htmlelement.rs
+++ b/components/script/dom/htmlelement.rs
@@ -32,7 +32,7 @@ use crate::dom::bindings::str::DOMString;
use crate::dom::characterdata::CharacterData;
use crate::dom::cssstyledeclaration::{CSSModificationAccess, CSSStyleDeclaration, CSSStyleOwner};
use crate::dom::customelementregistry::CallbackReaction;
-use crate::dom::document::{Document, FocusType};
+use crate::dom::document::{Document, FocusInitiator};
use crate::dom::documentfragment::DocumentFragment;
use crate::dom::domstringmap::DOMStringMap;
use crate::dom::element::{AttributeMutation, Element};
@@ -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 {
@@ -415,18 +425,19 @@ impl HTMLElementMethods<crate::DomTypeHolder> for HTMLElement {
// TODO: Mark the element as locked for focus and run the focusing steps.
// https://html.spec.whatwg.org/multipage/#focusing-steps
let document = self.owner_document();
- document.request_focus(Some(self.upcast()), FocusType::Element, can_gc);
+ document.request_focus(Some(self.upcast()), FocusInitiator::Local, can_gc);
}
// https://html.spec.whatwg.org/multipage/#dom-blur
fn Blur(&self, can_gc: CanGc) {
- // TODO: Run the unfocusing steps.
+ // TODO: Run the unfocusing steps. Focus the top-level document, not
+ // the current document.
if !self.as_element().focus_state() {
return;
}
// https://html.spec.whatwg.org/multipage/#unfocusing-steps
let document = self.owner_document();
- document.request_focus(None, FocusType::Element, can_gc);
+ document.request_focus(None, FocusInitiator::Local, can_gc);
}
// https://drafts.csswg.org/cssom-view/#dom-htmlelement-offsetparent
@@ -493,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/htmlformelement.rs b/components/script/dom/htmlformelement.rs
index ce6dcca66f3..2421b683bf7 100644
--- a/components/script/dom/htmlformelement.rs
+++ b/components/script/dom/htmlformelement.rs
@@ -1270,8 +1270,14 @@ impl HTMLFormElement {
return;
}
- let controls = self.controls.borrow();
- for child in controls.iter() {
+ let controls: Vec<_> = self
+ .controls
+ .borrow()
+ .iter()
+ .map(|c| c.as_rooted())
+ .collect();
+
+ for child in controls {
let child = child.upcast::<Node>();
match child.type_id() {
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/htmltablecellelement.rs b/components/script/dom/htmltablecellelement.rs
index 4f312e928c4..8b553923230 100644
--- a/components/script/dom/htmltablecellelement.rs
+++ b/components/script/dom/htmltablecellelement.rs
@@ -70,13 +70,17 @@ impl HTMLTableCellElementMethods<crate::DomTypeHolder> for HTMLTableCellElement
make_uint_getter!(ColSpan, "colspan", DEFAULT_COLSPAN);
// https://html.spec.whatwg.org/multipage/#dom-tdth-colspan
- make_uint_setter!(SetColSpan, "colspan", DEFAULT_COLSPAN);
+ // > The colSpan IDL attribute must reflect the colspan content attribute. It is clamped to
+ // > the range [1, 1000], and its default value is 1.
+ make_clamped_uint_setter!(SetColSpan, "colspan", 1, 1000, 1);
// https://html.spec.whatwg.org/multipage/#dom-tdth-rowspan
make_uint_getter!(RowSpan, "rowspan", DEFAULT_ROWSPAN);
// https://html.spec.whatwg.org/multipage/#dom-tdth-rowspan
- make_uint_setter!(SetRowSpan, "rowspan", DEFAULT_ROWSPAN);
+ // > The rowSpan IDL attribute must reflect the rowspan content attribute. It is clamped to
+ // > the range [0, 65534], and its default value is 1.
+ make_clamped_uint_setter!(SetRowSpan, "rowspan", 0, 65534, 1);
// https://html.spec.whatwg.org/multipage/#dom-tdth-bgcolor
make_getter!(BgColor, "bgcolor");
@@ -174,23 +178,26 @@ impl VirtualMethods for HTMLTableCellElement {
match *local_name {
local_name!("colspan") => {
let mut attr = AttrValue::from_u32(value.into(), DEFAULT_COLSPAN);
- if let AttrValue::UInt(_, ref mut val) = attr {
- if *val == 0 {
- *val = 1;
- }
+ if let AttrValue::UInt(_, ref mut value) = attr {
+ // From <https://html.spec.whatwg.org/multipage/#dom-tdth-colspan>:
+ // > The colSpan IDL attribute must reflect the colspan content attribute. It is clamped to
+ // > the range [1, 1000], and its default value is 1.
+ *value = (*value).clamp(1, 1000);
}
attr
},
local_name!("rowspan") => {
let mut attr = AttrValue::from_u32(value.into(), DEFAULT_ROWSPAN);
- if let AttrValue::UInt(_, ref mut val) = attr {
- if *val == 0 {
- let node = self.upcast::<Node>();
- let doc = node.owner_doc();
- // rowspan = 0 is not supported in quirks mode
- if doc.quirks_mode() != QuirksMode::NoQuirks {
- *val = 1;
- }
+ if let AttrValue::UInt(_, ref mut value) = attr {
+ // From <https://html.spec.whatwg.org/multipage/#dom-tdth-rowspan>:
+ // > The rowSpan IDL attribute must reflect the rowspan content attribute. It is clamped to
+ // > the range [0, 65534], and its default value is 1.
+ // Note that rowspan = 0 is not supported in quirks mode.
+ let document = self.upcast::<Node>().owner_doc();
+ if document.quirks_mode() != QuirksMode::NoQuirks {
+ *value = (*value).clamp(1, 65534);
+ } else {
+ *value = (*value).clamp(0, 65534);
}
}
attr
diff --git a/components/script/dom/htmltablecolelement.rs b/components/script/dom/htmltablecolelement.rs
index c7ad4afd944..9e8eecf1147 100644
--- a/components/script/dom/htmltablecolelement.rs
+++ b/components/script/dom/htmltablecolelement.rs
@@ -20,8 +20,6 @@ use crate::dom::node::Node;
use crate::dom::virtualmethods::VirtualMethods;
use crate::script_runtime::CanGc;
-const DEFAULT_SPAN: u32 = 1;
-
#[dom_struct]
pub(crate) struct HTMLTableColElement {
htmlelement: HTMLElement,
@@ -62,9 +60,11 @@ impl HTMLTableColElement {
impl HTMLTableColElementMethods<crate::DomTypeHolder> for HTMLTableColElement {
// <https://html.spec.whatwg.org/multipage/#attr-col-span>
- make_uint_getter!(Span, "span", DEFAULT_SPAN);
+ make_uint_getter!(Span, "span", 1);
// <https://html.spec.whatwg.org/multipage/#attr-col-span>
- make_uint_setter!(SetSpan, "span", DEFAULT_SPAN);
+ // > The span IDL attribute must reflect the content attribute of the same name. It is clamped
+ // > to the range [1, 1000], and its default value is 1.
+ make_clamped_uint_setter!(SetSpan, "span", 1, 1000, 1);
}
pub(crate) trait HTMLTableColElementLayoutHelpers<'dom> {
@@ -96,11 +96,12 @@ impl VirtualMethods for HTMLTableColElement {
fn parse_plain_attribute(&self, local_name: &LocalName, value: DOMString) -> AttrValue {
match *local_name {
local_name!("span") => {
- let mut attr = AttrValue::from_u32(value.into(), DEFAULT_SPAN);
+ let mut attr = AttrValue::from_u32(value.into(), 1);
if let AttrValue::UInt(_, ref mut val) = attr {
- if *val == 0 {
- *val = 1;
- }
+ // From <https://html.spec.whatwg.org/multipage/#attr-col-span>:
+ // > The span IDL attribute must reflect the content attribute of the same name.
+ // > It is clamped to the range [1, 1000], and its default value is 1.
+ *val = (*val).clamp(1, 1000);
}
attr
},
diff --git a/components/script/dom/macros.rs b/components/script/dom/macros.rs
index b3f222af0da..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 {
@@ -318,6 +292,26 @@ macro_rules! make_uint_setter(
);
#[macro_export]
+macro_rules! make_clamped_uint_setter(
+ ($attr:ident, $htmlname:tt, $min:expr, $max:expr, $default:expr) => (
+ fn $attr(&self, value: u32) {
+ use $crate::dom::bindings::inheritance::Castable;
+ use $crate::dom::element::Element;
+ use $crate::dom::values::UNSIGNED_LONG_MAX;
+ use $crate::script_runtime::CanGc;
+ let value = if value > UNSIGNED_LONG_MAX {
+ $default
+ } else {
+ value.clamp($min, $max)
+ };
+
+ let element = self.upcast::<Element>();
+ element.set_uint_attribute(&html5ever::local_name!($htmlname), value, CanGc::note())
+ }
+ );
+);
+
+#[macro_export]
macro_rules! make_limited_uint_setter(
($attr:ident, $htmlname:tt, $default:expr) => (
fn $attr(&self, value: u32) -> $crate::dom::bindings::error::ErrorResult {
@@ -719,26 +713,3 @@ macro_rules! handle_potential_webgl_error {
handle_potential_webgl_error!($context, $call, ())
};
}
-
-macro_rules! impl_rare_data (
- ($type:ty) => (
- fn rare_data(&self) -> Ref<Option<Box<$type>>> {
- self.rare_data.borrow()
- }
-
- #[allow(dead_code)]
- fn rare_data_mut(&self) -> RefMut<Option<Box<$type>>> {
- self.rare_data.borrow_mut()
- }
-
- fn ensure_rare_data(&self) -> RefMut<Box<$type>> {
- let mut rare_data = self.rare_data.borrow_mut();
- if rare_data.is_none() {
- *rare_data = Some(Default::default());
- }
- RefMut::map(rare_data, |rare_data| {
- rare_data.as_mut().unwrap()
- })
- }
- );
-);
diff --git a/components/script/dom/messageport.rs b/components/script/dom/messageport.rs
index 85d94c1aa7a..d70d3139b96 100644
--- a/components/script/dom/messageport.rs
+++ b/components/script/dom/messageport.rs
@@ -83,6 +83,20 @@ impl MessagePort {
*self.entangled_port.borrow_mut() = Some(other_id);
}
+ /// <https://html.spec.whatwg.org/multipage/#disentangle>
+ pub(crate) fn disentangle(&self) -> Option<MessagePortId> {
+ // Disentangle initiatorPort and otherPort, so that they are no longer entangled or associated with each other.
+ // Note: called from `disentangle_port` in the global, where the rest happens.
+ self.entangled_port.borrow_mut().take()
+ }
+
+ /// Has the port been disentangled?
+ /// Used when starting the port to fire the `close` event,
+ /// to cover the case of a disentanglement while in transfer.
+ pub(crate) fn disentangled(&self) -> bool {
+ self.entangled_port.borrow().is_none()
+ }
+
pub(crate) fn message_port_id(&self) -> &MessagePortId {
&self.message_port_id
}
@@ -314,20 +328,28 @@ impl MessagePortMethods<crate::DomTypeHolder> for MessagePort {
}
/// <https://html.spec.whatwg.org/multipage/#dom-messageport-start>
- fn Start(&self) {
+ fn Start(&self, can_gc: CanGc) {
if self.detached.get() {
return;
}
- self.global().start_message_port(self.message_port_id());
+ self.global()
+ .start_message_port(self.message_port_id(), can_gc);
}
/// <https://html.spec.whatwg.org/multipage/#dom-messageport-close>
- fn Close(&self) {
+ fn Close(&self, can_gc: CanGc) {
if self.detached.get() {
return;
}
+
+ // Set this's [[Detached]] internal slot value to true.
self.detached.set(true);
- self.global().close_message_port(self.message_port_id());
+
+ let global = self.global();
+ global.close_message_port(self.message_port_id());
+
+ // If this is entangled, disentangle it.
+ global.disentangle_port(self, can_gc);
}
/// <https://html.spec.whatwg.org/multipage/#handler-messageport-onmessage>
@@ -340,15 +362,19 @@ impl MessagePortMethods<crate::DomTypeHolder> for MessagePort {
}
/// <https://html.spec.whatwg.org/multipage/#handler-messageport-onmessage>
- fn SetOnmessage(&self, listener: Option<Rc<EventHandlerNonNull>>) {
+ fn SetOnmessage(&self, listener: Option<Rc<EventHandlerNonNull>>, can_gc: CanGc) {
if self.detached.get() {
return;
}
self.set_onmessage(listener);
// Note: we cannot use the event_handler macro, due to the need to start the port.
- self.global().start_message_port(self.message_port_id());
+ self.global()
+ .start_message_port(self.message_port_id(), can_gc);
}
// <https://html.spec.whatwg.org/multipage/#handler-messageport-onmessageerror>
event_handler!(messageerror, GetOnmessageerror, SetOnmessageerror);
+
+ // <https://html.spec.whatwg.org/multipage/#handler-messageport-onclose>
+ event_handler!(close, GetOnclose, SetOnclose);
}
diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs
index b56126076da..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();
@@ -564,7 +592,17 @@ impl Iterator for QuerySelectorIterator {
}
impl Node {
- impl_rare_data!(NodeRareData);
+ fn rare_data(&self) -> Ref<Option<Box<NodeRareData>>> {
+ self.rare_data.borrow()
+ }
+
+ fn ensure_rare_data(&self) -> RefMut<Box<NodeRareData>> {
+ let mut rare_data = self.rare_data.borrow_mut();
+ if rare_data.is_none() {
+ *rare_data = Some(Default::default());
+ }
+ RefMut::map(rare_data, |rare_data| rare_data.as_mut().unwrap())
+ }
/// Returns true if this node is before `other` in the same connected DOM
/// tree.
@@ -1007,24 +1045,25 @@ impl Node {
/// <https://dom.spec.whatwg.org/#dom-childnode-replacewith>
pub(crate) fn replace_with(&self, nodes: Vec<NodeOrString>, can_gc: CanGc) -> ErrorResult {
- // Step 1.
- let parent = if let Some(parent) = self.GetParentNode() {
- parent
- } else {
- // Step 2.
+ // Step 1. Let parent be this’s parent.
+ let Some(parent) = self.GetParentNode() else {
+ // Step 2. If parent is null, then return.
return Ok(());
};
- // Step 3.
+
+ // Step 3. Let viableNextSibling be this’s first following sibling not in nodes; otherwise null.
let viable_next_sibling = first_node_not_in(self.following_siblings(), &nodes);
- // Step 4.
+
+ // Step 4. Let node be the result of converting nodes into a node, given nodes and this’s node document.
let node = self
.owner_doc()
.node_from_nodes_and_strings(nodes, can_gc)?;
+
if self.parent_node == Some(&*parent) {
- // Step 5.
+ // Step 5. If this’s parent is parent, replace this with node within parent.
parent.ReplaceChild(&node, self, can_gc)?;
} else {
- // Step 6.
+ // Step 6. Otherwise, pre-insert node into parent before viableNextSibling.
Node::pre_insert(&node, &parent, viable_next_sibling.as_deref(), can_gc)?;
}
Ok(())
@@ -1272,6 +1311,21 @@ impl Node {
is_shadow_host,
shadow_root_mode,
display,
+ doctype_name: self
+ .downcast::<DocumentType>()
+ .map(DocumentType::name)
+ .cloned()
+ .map(String::from),
+ doctype_public_identifier: self
+ .downcast::<DocumentType>()
+ .map(DocumentType::public_id)
+ .cloned()
+ .map(String::from),
+ doctype_system_identifier: self
+ .downcast::<DocumentType>()
+ .map(DocumentType::system_id)
+ .cloned()
+ .map(String::from),
}
}
@@ -3172,24 +3226,29 @@ impl NodeMethods<crate::DomTypeHolder> for Node {
/// <https://dom.spec.whatwg.org/#concept-node-replace>
fn ReplaceChild(&self, node: &Node, child: &Node, can_gc: CanGc) -> Fallible<DomRoot<Node>> {
- // Step 1.
+ // Step 1. If parent is not a Document, DocumentFragment, or Element node,
+ // then throw a "HierarchyRequestError" DOMException.
match self.type_id() {
NodeTypeId::Document(_) | NodeTypeId::DocumentFragment(_) | NodeTypeId::Element(..) => {
},
_ => return Err(Error::HierarchyRequest),
}
- // Step 2.
+ // Step 2. If node is a host-including inclusive ancestor of parent,
+ // then throw a "HierarchyRequestError" DOMException.
if node.is_inclusive_ancestor_of(self) {
return Err(Error::HierarchyRequest);
}
- // Step 3.
+ // Step 3. If child’s parent is not parent, then throw a "NotFoundError" DOMException.
if !self.is_parent_of(child) {
return Err(Error::NotFound);
}
- // Step 4-5.
+ // Step 4. If node is not a DocumentFragment, DocumentType, Element, or CharacterData node,
+ // then throw a "HierarchyRequestError" DOMException.
+ // Step 5. If either node is a Text node and parent is a document,
+ // or node is a doctype and parent is not a document, then throw a "HierarchyRequestError" DOMException.
match node.type_id() {
NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) if self.is::<Document>() => {
return Err(Error::HierarchyRequest);
@@ -3201,7 +3260,8 @@ impl NodeMethods<crate::DomTypeHolder> for Node {
_ => (),
}
- // Step 6.
+ // Step 6. If parent is a document, and any of the statements below, switched on the interface node implements,
+ // are true, then throw a "HierarchyRequestError" DOMException.
if self.is::<Document>() {
match node.type_id() {
// Step 6.1
@@ -3255,7 +3315,8 @@ impl NodeMethods<crate::DomTypeHolder> for Node {
}
}
- // Step 7-8.
+ // Step 7. Let referenceChild be child’s next sibling.
+ // Step 8. If referenceChild is node, then set referenceChild to node’s next sibling.
let child_next_sibling = child.GetNextSibling();
let node_next_sibling = node.GetNextSibling();
let reference_child = if child_next_sibling.as_deref() == Some(node) {
@@ -3264,7 +3325,7 @@ impl NodeMethods<crate::DomTypeHolder> for Node {
child_next_sibling.as_deref()
};
- // Step 9.
+ // Step 9. Let previousSibling be child’s previous sibling.
let previous_sibling = child.GetPreviousSibling();
// NOTE: All existing browsers assume that adoption is performed here, which does not follow the DOM spec.
@@ -3285,7 +3346,7 @@ impl NodeMethods<crate::DomTypeHolder> for Node {
None
};
- // Step 12.
+ // Step 12. Let nodes be node’s children if node is a DocumentFragment node; otherwise « node ».
rooted_vec!(let mut nodes);
let nodes = if node.type_id() ==
NodeTypeId::DocumentFragment(DocumentFragmentTypeId::DocumentFragment) ||
@@ -3297,7 +3358,7 @@ impl NodeMethods<crate::DomTypeHolder> for Node {
from_ref(&node)
};
- // Step 13.
+ // Step 13. Insert node into parent before referenceChild with the suppress observers flag set.
Node::insert(
node,
self,
@@ -3306,13 +3367,15 @@ impl NodeMethods<crate::DomTypeHolder> for Node {
can_gc,
);
- // Step 14.
vtable_for(self).children_changed(&ChildrenMutation::replace(
previous_sibling.as_deref(),
&removed_child,
nodes,
reference_child,
));
+
+ // Step 14. Queue a tree mutation record for parent with nodes, removedNodes,
+ // previousSibling, and referenceChild.
let removed = removed_child.map(|r| [r]);
let mutation = LazyCell::new(|| Mutation::ChildList {
added: Some(nodes),
@@ -3323,7 +3386,7 @@ impl NodeMethods<crate::DomTypeHolder> for Node {
MutationObserver::queue_a_mutation_record(self, mutation);
- // Step 15.
+ // Step 15. Return child.
Ok(DomRoot::from_ref(child))
}
diff --git a/components/script/dom/nodelist.rs b/components/script/dom/nodelist.rs
index b349f16a986..1ec2dc3f78b 100644
--- a/components/script/dom/nodelist.rs
+++ b/components/script/dom/nodelist.rs
@@ -175,7 +175,6 @@ impl NodeList {
#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
pub(crate) struct ChildrenList {
node: Dom<Node>,
- #[ignore_malloc_size_of = "Defined in rust-mozjs"]
last_visited: MutNullableDom<Node>,
last_index: Cell<u32>,
}
diff --git a/components/script/dom/offscreencanvas.rs b/components/script/dom/offscreencanvas.rs
index aabe5955e12..9947d35f4e0 100644
--- a/components/script/dom/offscreencanvas.rs
+++ b/components/script/dom/offscreencanvas.rs
@@ -9,9 +9,10 @@ use euclid::default::Size2D;
use js::rust::{HandleObject, HandleValue};
use snapshot::Snapshot;
+use crate::canvas_context::{CanvasContext, OffscreenRenderingContext};
use crate::dom::bindings::cell::{DomRefCell, Ref, ref_filter_map};
use crate::dom::bindings::codegen::Bindings::OffscreenCanvasBinding::{
- OffscreenCanvasMethods, OffscreenRenderingContext,
+ OffscreenCanvasMethods, OffscreenRenderingContext as RootedOffscreenRenderingContext,
};
use crate::dom::bindings::error::{Error, Fallible};
use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object_with_proto};
@@ -23,20 +24,12 @@ use crate::dom::htmlcanvaselement::HTMLCanvasElement;
use crate::dom::offscreencanvasrenderingcontext2d::OffscreenCanvasRenderingContext2D;
use crate::script_runtime::{CanGc, JSContext};
-#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
-#[derive(Clone, JSTraceable, MallocSizeOf)]
-pub(crate) enum OffscreenCanvasContext {
- OffscreenContext2d(Dom<OffscreenCanvasRenderingContext2D>),
- //WebGL(Dom<WebGLRenderingContext>),
- //WebGL2(Dom<WebGL2RenderingContext>),
-}
-
#[dom_struct]
pub(crate) struct OffscreenCanvas {
eventtarget: EventTarget,
width: Cell<u64>,
height: Cell<u64>,
- context: DomRefCell<Option<OffscreenCanvasContext>>,
+ context: DomRefCell<Option<OffscreenRenderingContext>>,
placeholder: Option<Dom<HTMLCanvasElement>>,
}
@@ -77,20 +70,18 @@ impl OffscreenCanvas {
pub(crate) fn origin_is_clean(&self) -> bool {
match *self.context.borrow() {
- Some(OffscreenCanvasContext::OffscreenContext2d(ref context)) => {
- context.origin_is_clean()
- },
+ Some(ref context) => context.origin_is_clean(),
_ => true,
}
}
- pub(crate) fn context(&self) -> Option<Ref<OffscreenCanvasContext>> {
+ pub(crate) fn context(&self) -> Option<Ref<OffscreenRenderingContext>> {
ref_filter_map(self.context.borrow(), |ctx| ctx.as_ref())
}
pub(crate) fn get_image_data(&self) -> Option<Snapshot> {
match self.context.borrow().as_ref() {
- Some(OffscreenCanvasContext::OffscreenContext2d(context)) => context.get_image_data(),
+ Some(context) => context.get_image_data(),
None => {
let size = self.get_size();
if size.width == 0 || size.height == 0 {
@@ -108,13 +99,13 @@ impl OffscreenCanvas {
) -> Option<DomRoot<OffscreenCanvasRenderingContext2D>> {
if let Some(ctx) = self.context() {
return match *ctx {
- OffscreenCanvasContext::OffscreenContext2d(ref ctx) => Some(DomRoot::from_ref(ctx)),
+ OffscreenRenderingContext::Context2d(ref ctx) => Some(DomRoot::from_ref(ctx)),
};
}
let context = OffscreenCanvasRenderingContext2D::new(&self.global(), self, can_gc);
- *self.context.borrow_mut() = Some(OffscreenCanvasContext::OffscreenContext2d(
- Dom::from_ref(&*context),
- ));
+ *self.context.borrow_mut() = Some(OffscreenRenderingContext::Context2d(Dom::from_ref(
+ &*context,
+ )));
Some(context)
}
@@ -125,19 +116,6 @@ impl OffscreenCanvas {
pub(crate) fn placeholder(&self) -> Option<&HTMLCanvasElement> {
self.placeholder.as_deref()
}
-
- pub(crate) fn resize(&self, size: Size2D<u64>) {
- self.width.set(size.width);
- self.height.set(size.height);
-
- if let Some(canvas_context) = self.context() {
- match &*canvas_context {
- OffscreenCanvasContext::OffscreenContext2d(rendering_context) => {
- rendering_context.set_canvas_bitmap_dimensions(self.get_size());
- },
- }
- }
- }
}
impl OffscreenCanvasMethods<crate::DomTypeHolder> for OffscreenCanvas {
@@ -160,11 +138,11 @@ impl OffscreenCanvasMethods<crate::DomTypeHolder> for OffscreenCanvas {
id: DOMString,
_options: HandleValue,
can_gc: CanGc,
- ) -> Fallible<Option<OffscreenRenderingContext>> {
+ ) -> Fallible<Option<RootedOffscreenRenderingContext>> {
match &*id {
"2d" => Ok(self
.get_or_init_2d_context(can_gc)
- .map(OffscreenRenderingContext::OffscreenCanvasRenderingContext2D)),
+ .map(RootedOffscreenRenderingContext::OffscreenCanvasRenderingContext2D)),
/*"webgl" | "experimental-webgl" => self
.get_or_init_webgl_context(cx, options)
.map(OffscreenRenderingContext::WebGLRenderingContext),
@@ -187,11 +165,7 @@ impl OffscreenCanvasMethods<crate::DomTypeHolder> for OffscreenCanvas {
self.width.set(value);
if let Some(canvas_context) = self.context() {
- match &*canvas_context {
- OffscreenCanvasContext::OffscreenContext2d(rendering_context) => {
- rendering_context.set_canvas_bitmap_dimensions(self.get_size());
- },
- }
+ canvas_context.resize();
}
if let Some(canvas) = &self.placeholder {
@@ -209,11 +183,7 @@ impl OffscreenCanvasMethods<crate::DomTypeHolder> for OffscreenCanvas {
self.height.set(value);
if let Some(canvas_context) = self.context() {
- match &*canvas_context {
- OffscreenCanvasContext::OffscreenContext2d(rendering_context) => {
- rendering_context.set_canvas_bitmap_dimensions(self.get_size());
- },
- }
+ canvas_context.resize();
}
if let Some(canvas) = &self.placeholder {
diff --git a/components/script/dom/offscreencanvasrenderingcontext2d.rs b/components/script/dom/offscreencanvasrenderingcontext2d.rs
index b2d0f3201ca..d7ca0e9dc4d 100644
--- a/components/script/dom/offscreencanvasrenderingcontext2d.rs
+++ b/components/script/dom/offscreencanvasrenderingcontext2d.rs
@@ -3,11 +3,10 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::dom::bindings::codegen::GenericBindings::CanvasRenderingContext2DBinding::CanvasRenderingContext2D_Binding::CanvasRenderingContext2DMethods;
-use crate::canvas_context::CanvasContext as _;
+use crate::canvas_context::CanvasContext;
use crate::dom::bindings::codegen::UnionTypes::HTMLCanvasElementOrOffscreenCanvas;
use canvas_traits::canvas::Canvas2dMsg;
use dom_struct::dom_struct;
-use euclid::default::Size2D;
use snapshot::Snapshot;
use crate::dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::{
@@ -64,21 +63,33 @@ impl OffscreenCanvasRenderingContext2D {
reflect_dom_object(boxed, global, can_gc)
}
- pub(crate) fn set_canvas_bitmap_dimensions(&self, size: Size2D<u64>) {
- self.context.set_canvas_bitmap_dimensions(size.cast());
- }
-
pub(crate) fn send_canvas_2d_msg(&self, msg: Canvas2dMsg) {
self.context.send_canvas_2d_msg(msg)
}
+}
- pub(crate) fn origin_is_clean(&self) -> bool {
- self.context.origin_is_clean()
+impl CanvasContext for OffscreenCanvasRenderingContext2D {
+ type ID = <CanvasRenderingContext2D as CanvasContext>::ID;
+
+ fn context_id(&self) -> Self::ID {
+ self.context.context_id()
+ }
+
+ fn canvas(&self) -> HTMLCanvasElementOrOffscreenCanvas {
+ self.context.canvas()
+ }
+
+ fn resize(&self) {
+ self.context.resize()
}
- pub(crate) fn get_image_data(&self) -> Option<Snapshot> {
+ fn get_image_data(&self) -> Option<Snapshot> {
self.context.get_image_data()
}
+
+ fn origin_is_clean(&self) -> bool {
+ self.context.origin_is_clean()
+ }
}
impl OffscreenCanvasRenderingContext2DMethods<crate::DomTypeHolder>
diff --git a/components/script/dom/readablestream.rs b/components/script/dom/readablestream.rs
index 51393ab33ae..4982bfa32e3 100644
--- a/components/script/dom/readablestream.rs
+++ b/components/script/dom/readablestream.rs
@@ -1825,7 +1825,7 @@ impl ReadableStream {
global.note_cross_realm_transform_readable(&cross_realm_transform_readable, port_id);
// Enable port’s port message queue.
- port.Start();
+ port.Start(can_gc);
// Perform ! SetUpReadableStreamDefaultController
controller
@@ -2093,7 +2093,7 @@ impl CrossRealmTransformReadable {
self.controller.close(can_gc);
// Disentangle port.
- global.disentangle_port(port);
+ global.disentangle_port(port, can_gc);
}
// Otherwise, if type is "error",
@@ -2102,7 +2102,7 @@ impl CrossRealmTransformReadable {
self.controller.error(value.handle(), can_gc);
// Disentangle port.
- global.disentangle_port(port);
+ global.disentangle_port(port, can_gc);
}
}
@@ -2129,7 +2129,7 @@ impl CrossRealmTransformReadable {
self.controller.error(rooted_error.handle(), can_gc);
// Disentangle port.
- global.disentangle_port(port);
+ global.disentangle_port(port, can_gc);
}
}
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/underlyingsourcecontainer.rs b/components/script/dom/underlyingsourcecontainer.rs
index 541a831693a..4acb58bafef 100644
--- a/components/script/dom/underlyingsourcecontainer.rs
+++ b/components/script/dom/underlyingsourcecontainer.rs
@@ -151,7 +151,7 @@ impl UnderlyingSourceContainer {
let result = port.pack_and_post_message_handling_error("error", reason, can_gc);
// Disentangle port.
- self.global().disentangle_port(port);
+ self.global().disentangle_port(port, can_gc);
let promise = Promise::new(&self.global(), can_gc);
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 e210476a5df..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
@@ -787,6 +912,32 @@ impl WindowMethods<crate::DomTypeHolder> for Window {
doc.abort(can_gc);
}
+ /// <https://html.spec.whatwg.org/multipage/#dom-window-focus>
+ fn Focus(&self) {
+ // > 1. Let `current` be this `Window` object's browsing context.
+ // >
+ // > 2. If `current` is null, then return.
+ let current = match self.undiscarded_window_proxy() {
+ Some(proxy) => proxy,
+ None => return,
+ };
+
+ // > 3. Run the focusing steps with `current`.
+ current.focus();
+
+ // > 4. If current is a top-level browsing context, user agents are
+ // > encouraged to trigger some sort of notification to indicate to
+ // > the user that the page is attempting to gain focus.
+ //
+ // TODO: Step 4
+ }
+
+ // https://html.spec.whatwg.org/multipage/#dom-window-blur
+ fn Blur(&self) {
+ // > User agents are encouraged to ignore calls to this `blur()` method
+ // > entirely.
+ }
+
// https://html.spec.whatwg.org/multipage/#dom-open
fn Open(
&self,
@@ -1220,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);
}
}
@@ -1229,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);
}
}
}
@@ -1239,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));
}
}
diff --git a/components/script/dom/windowproxy.rs b/components/script/dom/windowproxy.rs
index e3fc81bf7ec..dc02f9feb49 100644
--- a/components/script/dom/windowproxy.rs
+++ b/components/script/dom/windowproxy.rs
@@ -620,6 +620,23 @@ impl WindowProxy {
result
}
+ /// Run [the focusing steps] with this browsing context.
+ ///
+ /// [the focusing steps]: https://html.spec.whatwg.org/multipage/#focusing-steps
+ pub fn focus(&self) {
+ debug!(
+ "Requesting the constellation to initiate a focus operation for \
+ browsing context {}",
+ self.browsing_context_id()
+ );
+ self.global()
+ .script_to_constellation_chan()
+ .send(ScriptToConstellationMessage::FocusRemoteDocument(
+ self.browsing_context_id(),
+ ))
+ .unwrap();
+ }
+
#[allow(unsafe_code)]
/// Change the Window that this WindowProxy resolves to.
// TODO: support setting the window proxy to a dummy value,
diff --git a/components/script/dom/writablestream.rs b/components/script/dom/writablestream.rs
index 8c2b2434cd2..1b029f592de 100644
--- a/components/script/dom/writablestream.rs
+++ b/components/script/dom/writablestream.rs
@@ -893,7 +893,7 @@ impl WritableStream {
global.note_cross_realm_transform_writable(&cross_realm_transform_writable, port_id);
// Enable port’s port message queue.
- port.Start();
+ port.Start(can_gc);
// Perform ! SetUpWritableStreamDefaultController
controller
@@ -1202,7 +1202,7 @@ impl CrossRealmTransformWritable {
.error_if_needed(cx, rooted_error.handle(), global, can_gc);
// Disentangle port.
- global.disentangle_port(port);
+ global.disentangle_port(port, can_gc);
}
}
diff --git a/components/script/dom/writablestreamdefaultcontroller.rs b/components/script/dom/writablestreamdefaultcontroller.rs
index 301404ffdb2..084165a6892 100644
--- a/components/script/dom/writablestreamdefaultcontroller.rs
+++ b/components/script/dom/writablestreamdefaultcontroller.rs
@@ -173,11 +173,11 @@ impl Callback for TransferBackPressurePromiseReaction {
self.port
.pack_and_post_message_handling_error("chunk", chunk.handle(), can_gc);
- // Disentangle port.
- global.disentangle_port(&self.port);
-
// If result is an abrupt completion,
if let Err(error) = result {
+ // Disentangle port.
+ global.disentangle_port(&self.port, can_gc);
+
// Return a promise rejected with result.[[Value]].
self.result_promise.reject_error(error, can_gc);
} else {
@@ -609,7 +609,7 @@ impl WritableStreamDefaultController {
let result = port.pack_and_post_message_handling_error("error", reason, can_gc);
// Disentangle port.
- global.disentangle_port(port);
+ global.disentangle_port(port, can_gc);
let promise = Promise::new(global, can_gc);
@@ -752,7 +752,7 @@ impl WritableStreamDefaultController {
.expect("Sending close should not fail.");
// Disentangle port.
- global.disentangle_port(port);
+ global.disentangle_port(port, can_gc);
// Return a promise resolved with undefined.
Promise::new_resolved(global, cx, (), can_gc)
diff --git a/components/script/messaging.rs b/components/script/messaging.rs
index 7d0b7aabe05..e0ea9e30af2 100644
--- a/components/script/messaging.rs
+++ b/components/script/messaging.rs
@@ -72,6 +72,8 @@ impl MixedMessage {
ScriptThreadMessage::UpdateHistoryState(id, ..) => Some(*id),
ScriptThreadMessage::RemoveHistoryStates(id, ..) => Some(*id),
ScriptThreadMessage::FocusIFrame(id, ..) => Some(*id),
+ ScriptThreadMessage::FocusDocument(id, ..) => Some(*id),
+ ScriptThreadMessage::Unfocus(id, ..) => Some(*id),
ScriptThreadMessage::WebDriverScriptCommand(id, ..) => Some(*id),
ScriptThreadMessage::TickAllAnimations(..) => None,
ScriptThreadMessage::WebFontLoaded(id, ..) => Some(*id),
diff --git a/components/script/script_module.rs b/components/script/script_module.rs
index c7697adeea6..0aa35a2eda8 100644
--- a/components/script/script_module.rs
+++ b/components/script/script_module.rs
@@ -1369,7 +1369,7 @@ pub(crate) unsafe extern "C" fn host_import_module_dynamically(
true
}
-#[derive(Clone, JSTraceable, MallocSizeOf)]
+#[derive(Clone, Debug, JSTraceable, MallocSizeOf)]
/// <https://html.spec.whatwg.org/multipage/#script-fetch-options>
pub(crate) struct ScriptFetchOptions {
#[no_trace]
@@ -1763,7 +1763,8 @@ fn fetch_single_module_script(
.mode(mode)
.insecure_requests_policy(global.insecure_requests_policy())
.has_trustworthy_ancestor_origin(global.has_trustworthy_ancestor_origin())
- .policy_container(global.policy_container().to_owned());
+ .policy_container(global.policy_container().to_owned())
+ .cryptographic_nonce_metadata(options.cryptographic_nonce.clone());
let context = Arc::new(Mutex::new(ModuleContext {
owner,
diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs
index f78b5bf281b..7241c115a2a 100644
--- a/components/script/script_thread.rs
+++ b/components/script/script_thread.rs
@@ -50,8 +50,9 @@ use devtools_traits::{
};
use embedder_traits::user_content_manager::UserContentManager;
use embedder_traits::{
- CompositorHitTestResult, EmbedderMsg, InputEvent, MediaSessionActionType, MouseButton,
- MouseButtonAction, MouseButtonEvent, Theme, ViewportDetails, WebDriverScriptCommand,
+ CompositorHitTestResult, EmbedderMsg, FocusSequenceNumber, InputEvent, MediaSessionActionType,
+ MouseButton, MouseButtonAction, MouseButtonEvent, Theme, ViewportDetails,
+ WebDriverScriptCommand,
};
use euclid::Point2D;
use euclid::default::Rect;
@@ -124,7 +125,7 @@ use crate::dom::customelementregistry::{
CallbackReaction, CustomElementDefinition, CustomElementReactionStack,
};
use crate::dom::document::{
- Document, DocumentSource, FocusType, HasBrowsingContext, IsHTMLDocument, TouchEventResult,
+ Document, DocumentSource, FocusInitiator, HasBrowsingContext, IsHTMLDocument, TouchEventResult,
};
use crate::dom::element::Element;
use crate::dom::globalscope::GlobalScope;
@@ -331,8 +332,7 @@ pub struct ScriptThread {
#[no_trace]
layout_factory: Arc<dyn LayoutFactory>,
- // Mouse down point.
- // In future, this shall be mouse_down_point for primary button
+ /// The screen coordinates where the primary mouse button was pressed.
#[no_trace]
relative_mouse_down_point: Cell<Point2D<f32, DevicePixel>>,
}
@@ -598,7 +598,7 @@ impl ScriptThread {
with_script_thread(|script_thread| {
let is_javascript = load_data.url.scheme() == "javascript";
// If resource is a request whose url's scheme is "javascript"
- // https://html.spec.whatwg.org/multipage/#javascript-protocol
+ // https://html.spec.whatwg.org/multipage/#navigate-to-a-javascript:-url
if is_javascript {
let window = match script_thread.documents.borrow().find_window(pipeline_id) {
None => return,
@@ -612,8 +612,12 @@ impl ScriptThread {
.clone();
let task = task!(navigate_javascript: move || {
// 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 let Some(window) = trusted_global.root().downcast::<Window>() {
+ // Step 5: If the result of should navigation request of type be blocked by
+ // Content Security Policy? given request and cspNavigationType is "Blocked", then return. [CSP]
+ if trusted_global.root().should_navigation_request_be_blocked(&load_data) {
+ return;
+ }
if ScriptThread::check_load_origin(&load_data.load_origin, &window.get_url().origin()) {
ScriptThread::eval_js_url(&trusted_global.root(), &mut load_data, CanGc::note());
sender
@@ -622,6 +626,7 @@ impl ScriptThread {
}
}
});
+ // Step 19 of <https://html.spec.whatwg.org/multipage/#navigate>
global
.task_manager()
.dom_manipulation_task_source()
@@ -1126,7 +1131,7 @@ impl ScriptThread {
document.dispatch_ime_event(ime_event, can_gc);
},
InputEvent::Gamepad(gamepad_event) => {
- window.as_global_scope().handle_gamepad_event(gamepad_event);
+ window.handle_gamepad_event(gamepad_event);
},
InputEvent::EditingAction(editing_action_event) => {
document.handle_editing_action(editing_action_event, can_gc);
@@ -1804,8 +1809,14 @@ impl ScriptThread {
ScriptThreadMessage::RemoveHistoryStates(pipeline_id, history_states) => {
self.handle_remove_history_states(pipeline_id, history_states)
},
- ScriptThreadMessage::FocusIFrame(parent_pipeline_id, frame_id) => {
- self.handle_focus_iframe_msg(parent_pipeline_id, frame_id, can_gc)
+ ScriptThreadMessage::FocusIFrame(parent_pipeline_id, frame_id, sequence) => {
+ self.handle_focus_iframe_msg(parent_pipeline_id, frame_id, sequence, can_gc)
+ },
+ ScriptThreadMessage::FocusDocument(pipeline_id, sequence) => {
+ self.handle_focus_document_msg(pipeline_id, sequence, can_gc)
+ },
+ ScriptThreadMessage::Unfocus(pipeline_id, sequence) => {
+ self.handle_unfocus_msg(pipeline_id, sequence, can_gc)
},
ScriptThreadMessage::WebDriverScriptCommand(pipeline_id, msg) => {
self.handle_webdriver_msg(pipeline_id, msg, can_gc)
@@ -2514,6 +2525,7 @@ impl ScriptThread {
&self,
parent_pipeline_id: PipelineId,
browsing_context_id: BrowsingContextId,
+ sequence: FocusSequenceNumber,
can_gc: CanGc,
) {
let document = self
@@ -2533,7 +2545,65 @@ impl ScriptThread {
return;
};
- document.request_focus(Some(&iframe_element_root), FocusType::Parent, can_gc);
+ if document.get_focus_sequence() > sequence {
+ debug!(
+ "Disregarding the FocusIFrame message because the contained sequence number is \
+ too old ({:?} < {:?})",
+ sequence,
+ document.get_focus_sequence()
+ );
+ return;
+ }
+
+ document.request_focus(Some(&iframe_element_root), FocusInitiator::Remote, can_gc);
+ }
+
+ fn handle_focus_document_msg(
+ &self,
+ pipeline_id: PipelineId,
+ sequence: FocusSequenceNumber,
+ can_gc: CanGc,
+ ) {
+ if let Some(doc) = self.documents.borrow().find_document(pipeline_id) {
+ if doc.get_focus_sequence() > sequence {
+ debug!(
+ "Disregarding the FocusDocument message because the contained sequence number is \
+ too old ({:?} < {:?})",
+ sequence,
+ doc.get_focus_sequence()
+ );
+ return;
+ }
+ doc.request_focus(None, FocusInitiator::Remote, can_gc);
+ } else {
+ warn!(
+ "Couldn't find document by pipleline_id:{pipeline_id:?} when handle_focus_document_msg."
+ );
+ }
+ }
+
+ fn handle_unfocus_msg(
+ &self,
+ pipeline_id: PipelineId,
+ sequence: FocusSequenceNumber,
+ can_gc: CanGc,
+ ) {
+ if let Some(doc) = self.documents.borrow().find_document(pipeline_id) {
+ if doc.get_focus_sequence() > sequence {
+ debug!(
+ "Disregarding the Unfocus message because the contained sequence number is \
+ too old ({:?} < {:?})",
+ sequence,
+ doc.get_focus_sequence()
+ );
+ return;
+ }
+ doc.handle_container_unfocus(can_gc);
+ } else {
+ warn!(
+ "Couldn't find document by pipleline_id:{pipeline_id:?} when handle_unfocus_msg."
+ );
+ }
}
fn handle_post_message_msg(
@@ -3604,10 +3674,12 @@ impl ScriptThread {
None => vec![],
};
+ let policy_container = incomplete.load_data.policy_container.clone();
self.incomplete_loads.borrow_mut().push(incomplete);
let dummy_request_id = RequestId::default();
context.process_response(dummy_request_id, Ok(FetchMetadata::Unfiltered(meta)));
+ context.append_parent_to_csp_list(policy_container.as_ref());
context.process_response_chunk(dummy_request_id, chunk);
context.process_response_eof(
dummy_request_id,
@@ -3627,12 +3699,14 @@ impl ScriptThread {
let srcdoc = std::mem::take(&mut incomplete.load_data.srcdoc);
let chunk = srcdoc.into_bytes();
+ let policy_container = incomplete.load_data.policy_container.clone();
self.incomplete_loads.borrow_mut().push(incomplete);
let mut context = ParserContext::new(id, url);
let dummy_request_id = RequestId::default();
context.process_response(dummy_request_id, Ok(FetchMetadata::Unfiltered(meta)));
+ context.append_parent_to_csp_list(policy_container.as_ref());
context.process_response_chunk(dummy_request_id, chunk);
context.process_response_eof(
dummy_request_id,