Repository: servo/servo
Pull request #37135: canvas: Add HTMLVideoElement to CanvasImageSource union type
Author: login: tharkum
Created: 2025-05-26T13:56:58Z | Merged: 2025-05-28T12:58:15Z

Follow to the specification and add HTMLVideoElement to CanvasImageSource union type
to allow use it as image source for createPattern/drawImage operations.
https://html.spec.whatwg.org/multipage/#canvasimagesource

https://html.spec.whatwg.org/multipage/#dom-context-2d-createpattern
https://html.spec.whatwg.org/multipage/#dom-context-2d-drawimage

The HTMLVideoElement media resource has an associated origin:
 - media provider object (MediaStream/MediaSource/Blob): CORS-same-origin
 - URL record: CORS-cross-origin/CORS-same-origin

https://html.spec.whatwg.org/multipage/media.html#media-resource

Testing:
 - html/canvas/element/*
 - html/semantics/embedded-content/the-canvas-element/*


Diff:
diff --git a/components/script/canvas_state.rs b/components/script/canvas_state.rs
index 9c9a29661fc84..d788d2f5929cc 100644
--- a/components/script/canvas_state.rs
+++ b/components/script/canvas_state.rs
@@ -54,6 +54,7 @@ use crate::dom::dommatrix::DOMMatrix;
 use crate::dom::element::{Element, cors_setting_for_element};
 use crate::dom::globalscope::GlobalScope;
 use crate::dom::htmlcanvaselement::HTMLCanvasElement;
+use crate::dom::htmlvideoelement::HTMLVideoElement;
 use crate::dom::imagedata::ImageData;
 use crate::dom::node::{Node, NodeTraits};
 use crate::dom::offscreencanvas::OffscreenCanvas;
@@ -310,14 +311,15 @@ impl CanvasState {
         self.origin_clean.set(false)
     }
 
-    // https://html.spec.whatwg.org/multipage/#the-image-argument-is-not-origin-clean
-    fn is_origin_clean(&self, image: CanvasImageSource) -> bool {
-        match image {
-            CanvasImageSource::HTMLCanvasElement(canvas) => canvas.origin_is_clean(),
-            CanvasImageSource::OffscreenCanvas(canvas) => canvas.origin_is_clean(),
+    /// <https://html.spec.whatwg.org/multipage/#the-image-argument-is-not-origin-clean>
+    fn is_origin_clean(&self, source: CanvasImageSource) -> bool {
+        match source {
             CanvasImageSource::HTMLImageElement(image) => {
                 image.same_origin(GlobalScope::entry().origin())
             },
+            CanvasImageSource::HTMLVideoElement(video) => video.origin_is_clean(),
+            CanvasImageSource::HTMLCanvasElement(canvas) => canvas.origin_is_clean(),
+            CanvasImageSource::OffscreenCanvas(canvas) => canvas.origin_is_clean(),
             CanvasImageSource::CSSStyleValue(_) => true,
         }
     }
@@ -438,6 +440,17 @@ impl CanvasState {
         }
 
         let result = match image {
+            CanvasImageSource::HTMLVideoElement(ref video) => {
+                // <https://html.spec.whatwg.org/multipage/#check-the-usability-of-the-image-argument>
+                // Step 2. Let usability be the result of checking the usability of image.
+                // Step 3. If usability is bad, then return (without drawing anything).
+                if !video.is_usable() {
+                    return Ok(());
+                }
+
+                self.draw_html_video_element(video, htmlcanvas, sx, sy, sw, sh, dx, dy, dw, dh);
+                Ok(())
+            },
             CanvasImageSource::HTMLCanvasElement(ref canvas) => {
                 // <https://html.spec.whatwg.org/multipage/#check-the-usability-of-the-image-argument>
                 if canvas.get_size().is_empty() {
@@ -498,6 +511,52 @@ impl CanvasState {
         result
     }
 
+    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-drawimage>
+    #[allow(clippy::too_many_arguments)]
+    fn draw_html_video_element(
+        &self,
+        video: &HTMLVideoElement,
+        canvas: Option<&HTMLCanvasElement>,
+        sx: f64,
+        sy: f64,
+        sw: Option<f64>,
+        sh: Option<f64>,
+        dx: f64,
+        dy: f64,
+        dw: Option<f64>,
+        dh: Option<f64>,
+    ) {
+        let Some(snapshot) = video.get_current_frame_data() else {
+            return;
+        };
+
+        // Step 4. Establish the source and destination rectangles.
+        let video_size = snapshot.size().to_f64();
+        let dw = dw.unwrap_or(video_size.width);
+        let dh = dh.unwrap_or(video_size.height);
+        let sw = sw.unwrap_or(video_size.width);
+        let sh = sh.unwrap_or(video_size.height);
+
+        let (source_rect, dest_rect) =
+            self.adjust_source_dest_rects(video_size, sx, sy, sw, sh, dx, dy, dw, dh);
+
+        // Step 5. If one of the sw or sh arguments is zero, then return. Nothing is painted.
+        if !is_rect_valid(source_rect) || !is_rect_valid(dest_rect) {
+            return;
+        }
+
+        let smoothing_enabled = self.state.borrow().image_smoothing_enabled;
+
+        self.send_canvas_2d_msg(Canvas2dMsg::DrawImage(
+            snapshot.as_ipc(),
+            dest_rect,
+            source_rect,
+            smoothing_enabled,
+        ));
+
+        self.mark_as_dirty(canvas);
+    }
+
     #[allow(clippy::too_many_arguments)]
     fn draw_offscreen_canvas(
         &self,
@@ -966,7 +1025,7 @@ impl CanvasState {
         ))
     }
 
-    // https://html.spec.whatwg.org/multipage/#dom-context-2d-createpattern
+    /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-createpattern>
     pub(crate) fn create_pattern(
         &self,
         global: &GlobalScope,
@@ -976,7 +1035,7 @@ impl CanvasState {
     ) -> Fallible<Option<DomRoot<CanvasPattern>>> {
         let snapshot = match image {
             CanvasImageSource::HTMLImageElement(ref image) => {
-                // https://html.spec.whatwg.org/multipage/#check-the-usability-of-the-image-argument
+                // <https://html.spec.whatwg.org/multipage/#check-the-usability-of-the-image-argument>
                 if !image.is_usable()? {
                     return Ok(None);
                 }
@@ -988,10 +1047,28 @@ impl CanvasState {
                     })
                     .ok_or(Error::InvalidState)?
             },
+            CanvasImageSource::HTMLVideoElement(ref video) => {
+                // <https://html.spec.whatwg.org/multipage/#check-the-usability-of-the-image-argument>
+                if !video.is_usable() {
+                    return Ok(None);
+                }
+
+                video.get_current_frame_data().ok_or(Error::InvalidState)?
+            },
             CanvasImageSource::HTMLCanvasElement(ref canvas) => {
+                // <https://html.spec.whatwg.org/multipage/#check-the-usability-of-the-image-argument>
+                if canvas.get_size().is_empty() {
+                    return Err(Error::InvalidState);
+                }
+
                 canvas.get_image_data().ok_or(Error::InvalidState)?
             },
             CanvasImageSource::OffscreenCanvas(ref canvas) => {
+                // <https://html.spec.whatwg.org/multipage/#check-the-usability-of-the-image-argument>
+                if canvas.get_size().is_empty() {
+                    return Err(Error::InvalidState);
+                }
+
                 canvas.get_image_data().ok_or(Error::InvalidState)?
             },
             CanvasImageSource::CSSStyleValue(ref value) => value
diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs
index b05dae8b6bf2f..e2b31e918dec0 100644
--- a/components/script/dom/htmlmediaelement.rs
+++ b/components/script/dom/htmlmediaelement.rs
@@ -24,8 +24,8 @@ use js::jsapi::JSAutoRealm;
 use media::{GLPlayerMsg, GLPlayerMsgForward, WindowGLContext};
 use net_traits::request::{Destination, RequestId};
 use net_traits::{
-    FetchMetadata, FetchResponseListener, Metadata, NetworkError, ResourceFetchTiming,
-    ResourceTimingType,
+    FetchMetadata, FetchResponseListener, FilteredMetadata, Metadata, NetworkError,
+    ResourceFetchTiming, ResourceTimingType,
 };
 use pixels::RasterImage;
 use script_bindings::codegen::GenericBindings::TimeRangesBinding::TimeRangesMethods;
@@ -2069,6 +2069,28 @@ impl HTMLMediaElement {
             }
         }
     }
+
+    /// <https://html.spec.whatwg.org/multipage/#concept-media-load-resource>
+    pub(crate) fn origin_is_clean(&self) -> bool {
+        // Step 5.local (media provider object).
+        if self.src_object.borrow().is_some() {
+            // The resource described by the current media resource, if any,
+            // contains the media data. It is CORS-same-origin.
+            return true;
+        }
+
+        // Step 5.remote (URL record).
+        if self.resource_url.borrow().is_some() {
+            // Update the media data with the contents
+            // of response's unsafe response obtained in this fashion.
+            // Response can be CORS-same-origin or CORS-cross-origin;
+            if let Some(ref current_fetch_context) = *self.current_fetch_context.borrow() {
+                return current_fetch_context.origin_is_clean();
+            }
+        }
+
+        true
+    }
 }
 
 // XXX Placeholder for [https://github.com/servo/servo/issues/22293]
@@ -2654,6 +2676,8 @@ pub(crate) struct HTMLMediaElementFetchContext {
     cancel_reason: Option<CancelReason>,
     /// Indicates whether the fetched stream is seekable.
     is_seekable: bool,
+    /// Indicates whether the fetched stream is origin clean.
+    origin_clean: bool,
     /// Fetch canceller. Allows cancelling the current fetch request by
     /// manually calling its .cancel() method or automatically on Drop.
     fetch_canceller: FetchCanceller,
@@ -2664,6 +2688,7 @@ impl HTMLMediaElementFetchContext {
         HTMLMediaElementFetchContext {
             cancel_reason: None,
             is_seekable: false,
+            origin_clean: true,
             fetch_canceller: FetchCanceller::new(request_id),
         }
     }
@@ -2676,6 +2701,14 @@ impl HTMLMediaElementFetchContext {
         self.is_seekable = seekable;
     }
 
+    pub(crate) fn origin_is_clean(&self) -> bool {
+        self.origin_clean
+    }
+
+    fn set_origin_unclean(&mut self) {
+        self.origin_clean = false;
+    }
+
     fn cancel(&mut self, reason: CancelReason) {
         if self.cancel_reason.is_some() {
             return;
@@ -2730,6 +2763,16 @@ impl FetchResponseListener for HTMLMediaElementFetchListener {
             return;
         }
 
+        if let Ok(FetchMetadata::Filtered {
+            filtered: FilteredMetadata::Opaque | FilteredMetadata::OpaqueRedirect(_),
+            ..
+        }) = metadata
+        {
+            if let Some(ref mut current_fetch_context) = *elem.current_fetch_context.borrow_mut() {
+                current_fetch_context.set_origin_unclean();
+            }
+        }
+
         self.metadata = metadata.ok().map(|m| match m {
             FetchMetadata::Unfiltered(m) => m,
             FetchMetadata::Filtered { unsafe_, .. } => unsafe_,
diff --git a/components/script/dom/htmlvideoelement.rs b/components/script/dom/htmlvideoelement.rs
index 95124da8ea24e..c5699014ee2ea 100644
--- a/components/script/dom/htmlvideoelement.rs
+++ b/components/script/dom/htmlvideoelement.rs
@@ -9,7 +9,6 @@ use content_security_policy as csp;
 use dom_struct::dom_struct;
 use euclid::default::Size2D;
 use html5ever::{LocalName, Prefix, local_name, ns};
-use ipc_channel::ipc;
 use js::rust::HandleObject;
 use net_traits::image_cache::{
     ImageCache, ImageCacheResult, ImageLoadListener, ImageOrMetadataAvailable, ImageResponse,
@@ -23,6 +22,7 @@ use net_traits::{
 use script_layout_interface::{HTMLMediaData, MediaMetadata};
 use servo_media::player::video::VideoFrame;
 use servo_url::ServoUrl;
+use snapshot::Snapshot;
 use style::attr::{AttrValue, LengthOrPercentageOrAuto};
 
 use crate::document_loader::{LoadBlocker, LoadType};
@@ -133,9 +133,7 @@ impl HTMLVideoElement {
         sent_resize
     }
 
-    pub(crate) fn get_current_frame_data(
-        &self,
-    ) -> Option<(Option<ipc::IpcSharedMemory>, Size2D<u32>)> {
+    pub(crate) fn get_current_frame_data(&self) -> Option<Snapshot> {
         let frame = self.htmlmediaelement.get_current_frame();
         if frame.is_some() {
             *self.last_frame.borrow_mut() = frame;
@@ -145,11 +143,19 @@ impl HTMLVideoElement {
             Some(frame) => {
                 let size = Size2D::new(frame.get_width() as u32, frame.get_height() as u32);
                 if !frame.is_gl_texture() {
-                    let data = Some(ipc::IpcSharedMemory::from_bytes(&frame.get_data()));
-                    Some((data, size))
+                    let alpha_mode = snapshot::AlphaMode::Transparent {
+                        premultiplied: false,
+                    };
+
+                    Some(Snapshot::from_vec(
+                        size.cast(),
+                        snapshot::PixelFormat::BGRA,
+                        alpha_mode,
+                        frame.get_data().to_vec(),
+                    ))
                 } else {
                     // XXX(victor): here we only have the GL texture ID.
-                    Some((None, size))
+                    Some(Snapshot::cleared(size.cast()))
                 }
             },
             None => None,
@@ -276,6 +282,18 @@ impl HTMLVideoElement {
             },
         }
     }
+
+    /// <https://html.spec.whatwg.org/multipage/#check-the-usability-of-the-image-argument>
+    pub(crate) fn is_usable(&self) -> bool {
+        !matches!(
+            self.htmlmediaelement.get_ready_state(),
+            ReadyState::HaveNothing | ReadyState::HaveMetadata
+        )
+    }
+
+    pub(crate) fn origin_is_clean(&self) -> bool {
+        self.htmlmediaelement.origin_is_clean()
+    }
 }
 
 impl HTMLVideoElementMethods<crate::DomTypeHolder> for HTMLVideoElement {
diff --git a/components/script/dom/webgl2renderingcontext.rs b/components/script/dom/webgl2renderingcontext.rs
index 5e538b53b5f90..d2bbf3bba57fc 100644
--- a/components/script/dom/webgl2renderingcontext.rs
+++ b/components/script/dom/webgl2renderingcontext.rs
@@ -32,12 +32,11 @@ use crate::dom::bindings::codegen::Bindings::WebGL2RenderingContextBinding::{
     WebGL2RenderingContextConstants as constants, WebGL2RenderingContextMethods,
 };
 use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::{
-    WebGLContextAttributes, WebGLRenderingContextMethods,
+    TexImageSource, WebGLContextAttributes, WebGLRenderingContextMethods,
 };
 use crate::dom::bindings::codegen::UnionTypes::{
     ArrayBufferViewOrArrayBuffer, Float32ArrayOrUnrestrictedFloatSequence,
-    HTMLCanvasElementOrOffscreenCanvas,
-    ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement, Int32ArrayOrLongSequence,
+    HTMLCanvasElementOrOffscreenCanvas, Int32ArrayOrLongSequence,
     Uint32ArrayOrUnsignedLongSequence,
 };
 use crate::dom::bindings::error::{ErrorResult, Fallible};
@@ -3023,7 +3022,7 @@ impl WebGL2RenderingContextMethods<crate::DomTypeHolder> for WebGL2RenderingCont
         internal_format: i32,
         format: u32,
         data_type: u32,
-        source: ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement,
+        source: TexImageSource,
     ) -> ErrorResult {
         self.base
             .TexImage2D_(target, level, internal_format, format, data_type, source)
@@ -3118,7 +3117,7 @@ impl WebGL2RenderingContextMethods<crate::DomTypeHolder> for WebGL2RenderingCont
         border: i32,
         format: u32,
         type_: u32,
-        source: ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement,
+        source: TexImageSource,
     ) -> Fallible<()> {
         if self.bound_pixel_unpack_buffer.get().is_some() {
             self.base.webgl_error(InvalidOperation);
@@ -3301,7 +3300,7 @@ impl WebGL2RenderingContextMethods<crate::DomTypeHolder> for WebGL2RenderingCont
         yoffset: i32,
         format: u32,
         data_type: u32,
-        source: ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement,
+        source: TexImageSource,
     ) -> ErrorResult {
         self.base
             .TexSubImage2D_(target, level, xoffset, yoffset, format, data_type, source)
diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs
index 9b9f35aefee00..70463ae15287b 100644
--- a/components/script/dom/webglrenderingcontext.rs
+++ b/components/script/dom/webglrenderingcontext.rs
@@ -658,14 +658,23 @@ impl WebGLRenderingContext {
                     return Ok(None);
                 }
             },
-            TexImageSource::HTMLVideoElement(video) => match video.get_current_frame_data() {
-                Some((data, size)) => {
-                    let data = data.unwrap_or_else(|| {
-                        IpcSharedMemory::from_bytes(&vec![0; size.area() as usize * 4])
-                    });
-                    TexPixels::new(data, size, PixelFormat::BGRA8, false)
-                },
-                None => return Ok(None),
+            TexImageSource::HTMLVideoElement(video) => {
+                if !video.origin_is_clean() {
+                    return Err(Error::Security);
+                }
+
+                let Some(snapshot) = video.get_current_frame_data() else {
+                    return Ok(None);
+                };
+
+                let snapshot = snapshot.as_ipc();
+                let size = snapshot.size().cast();
+                let format: PixelFormat = match snapshot.format() {
+                    snapshot::PixelFormat::RGBA => PixelFormat::RGBA8,
+                    snapshot::PixelFormat::BGRA => PixelFormat::BGRA8,
+                };
+                let premultiply = snapshot.alpha_mode().is_premultiplied();
+                TexPixels::new(snapshot.to_ipc_shared_memory(), size, format, premultiply)
             },
         }))
     }
diff --git a/components/script_bindings/webidls/CanvasRenderingContext2D.webidl b/components/script_bindings/webidls/CanvasRenderingContext2D.webidl
index 46d916835774d..47612a299373a 100644
--- a/components/script_bindings/webidls/CanvasRenderingContext2D.webidl
+++ b/components/script_bindings/webidls/CanvasRenderingContext2D.webidl
@@ -9,7 +9,7 @@
 typedef HTMLImageElement HTMLOrSVGImageElement;
 
 typedef (HTMLOrSVGImageElement or
-         /*HTMLVideoElement or*/
+         HTMLVideoElement or
          HTMLCanvasElement or
          /*ImageBitmap or*/
          OffscreenCanvas or
diff --git a/tests/wpt/meta/html/canvas/element/manual/wide-gamut-canvas/canvas-display-p3-drawImage-video.html.ini b/tests/wpt/meta/html/canvas/element/manual/wide-gamut-canvas/canvas-display-p3-drawImage-video.html.ini
index f44385a52e39b..afde84082dde3 100644
--- a/tests/wpt/meta/html/canvas/element/manual/wide-gamut-canvas/canvas-display-p3-drawImage-video.html.ini
+++ b/tests/wpt/meta/html/canvas/element/manual/wide-gamut-canvas/canvas-display-p3-drawImage-video.html.ini
@@ -1,70 +1,34 @@
 [canvas-display-p3-drawImage-video.html]
-  [sRGB-FF0100, Context srgb, ImageData srgb, scaleImage=false]
-    expected: FAIL
-
-  [sRGB-FF0100, Context srgb, ImageData srgb, scaleImage=true]
-    expected: FAIL
-
   [sRGB-FF0100, Context srgb, ImageData display-p3, scaleImage=false]
     expected: FAIL
 
   [sRGB-FF0100, Context srgb, ImageData display-p3, scaleImage=true]
     expected: FAIL
 
-  [sRGB-FF0100, Context display-p3, ImageData srgb, scaleImage=false]
-    expected: FAIL
-
-  [sRGB-FF0100, Context display-p3, ImageData srgb, scaleImage=true]
-    expected: FAIL
-
   [sRGB-FF0100, Context display-p3, ImageData display-p3, scaleImage=false]
     expected: FAIL
 
   [sRGB-FF0100, Context display-p3, ImageData display-p3, scaleImage=true]
     expected: FAIL
 
-  [sRGB-BB0000, Context srgb, ImageData srgb, scaleImage=false]
-    expected: FAIL
-
-  [sRGB-BB0000, Context srgb, ImageData srgb, scaleImage=true]
-    expected: FAIL
-
   [sRGB-BB0000, Context srgb, ImageData display-p3, scaleImage=false]
     expected: FAIL
 
   [sRGB-BB0000, Context srgb, ImageData display-p3, scaleImage=true]
     expected: FAIL
 
-  [sRGB-BB0000, Context display-p3, ImageData srgb, scaleImage=false]
-    expected: FAIL
-
-  [sRGB-BB0000, Context display-p3, ImageData srgb, scaleImage=true]
-    expected: FAIL
-
   [sRGB-BB0000, Context display-p3, ImageData display-p3, scaleImage=false]
     expected: FAIL
 
   [sRGB-BB0000, Context display-p3, ImageData display-p3, scaleImage=true]
     expected: FAIL
 
-  [Rec2020-3FF000000, Context srgb, ImageData srgb, scaleImage=false]
-    expected: FAIL
-
-  [Rec2020-3FF000000, Context srgb, ImageData srgb, scaleImage=true]
-    expected: FAIL
-
   [Rec2020-3FF000000, Context srgb, ImageData display-p3, scaleImage=false]
     expected: FAIL
 
   [Rec2020-3FF000000, Context srgb, ImageData display-p3, scaleImage=true]
     expected: FAIL
 
-  [Rec2020-3FF000000, Context display-p3, ImageData srgb, scaleImage=false]
-    expected: FAIL
-
-  [Rec2020-3FF000000, Context display-p3, ImageData srgb, scaleImage=true]
-    expected: FAIL
-
   [Rec2020-3FF000000, Context display-p3, ImageData display-p3, scaleImage=false]
     expected: FAIL
 
diff --git a/tests/wpt/meta/html/canvas/element/video/2d.video.invalid.html.ini b/tests/wpt/meta/html/canvas/element/video/2d.video.invalid.html.ini
deleted file mode 100644
index de473e60ca3e0..0000000000000
--- a/tests/wpt/meta/html/canvas/element/video/2d.video.invalid.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[2d.video.invalid.html]
-  [Verify test doesn't crash with invalid video.]
-    expected: FAIL
-
diff --git a/tests/wpt/meta/html/semantics/embedded-content/the-canvas-element/security.pattern.fillStyle.sub.html.ini b/tests/wpt/meta/html/semantics/embedded-content/the-canvas-element/security.pattern.fillStyle.sub.html.ini
index 81329bc1635cf..186191eebae08 100644
--- a/tests/wpt/meta/html/semantics/embedded-content/the-canvas-element/security.pattern.fillStyle.sub.html.ini
+++ b/tests/wpt/meta/html/semantics/embedded-content/the-canvas-element/security.pattern.fillStyle.sub.html.ini
@@ -1,5 +1,4 @@
 [security.pattern.fillStyle.sub.html]
-  expected: TIMEOUT
   [cross-origin SVGImageElement: Setting fillStyle to an origin-unclean pattern makes the canvas origin-unclean]
     expected: FAIL
 
@@ -10,31 +9,22 @@
     expected: FAIL
 
   [redirected to same-origin HTMLVideoElement: Setting fillStyle to an origin-unclean pattern makes the canvas origin-unclean]
-    expected: TIMEOUT
-
-  [unclean HTMLCanvasElement: Setting fillStyle to an origin-unclean pattern makes the canvas origin-unclean]
-    expected: NOTRUN
+    expected: FAIL
 
   [unclean ImageBitmap: Setting fillStyle to an origin-unclean pattern makes the canvas origin-unclean]
-    expected: NOTRUN
-
-  [cross-origin HTMLImageElement: Setting fillStyle to an origin-unclean offscreen canvas pattern makes the canvas origin-unclean]
-    expected: NOTRUN
+    expected: FAIL
 
   [cross-origin SVGImageElement: Setting fillStyle to an origin-unclean offscreen canvas pattern makes the canvas origin-unclean]
-    expected: NOTRUN
+    expected: FAIL
 
   [cross-origin HTMLVideoElement: Setting fillStyle to an origin-unclean offscreen canvas pattern makes the canvas origin-unclean]
-    expected: NOTRUN
+    expected: FAIL
 
   [redirected to cross-origin HTMLVideoElement: Setting fillStyle to an origin-unclean offscreen canvas pattern makes the canvas origin-unclean]
-    expected: NOTRUN
+    expected: FAIL
 
   [redirected to same-origin HTMLVideoElement: Setting fillStyle to an origin-unclean offscreen canvas pattern makes the canvas origin-unclean]
-    expected: NOTRUN
-
-  [unclean HTMLCanvasElement: Setting fillStyle to an origin-unclean offscreen canvas pattern makes the canvas origin-unclean]
-    expected: NOTRUN
+    expected: FAIL
 
   [unclean ImageBitmap: Setting fillStyle to an origin-unclean offscreen canvas pattern makes the canvas origin-unclean]
-    expected: NOTRUN
+    expected: FAIL


Reviews:
user: login: jdm
body: Good start! I appreciate being able to review these changes on their own.
state: CHANGES_REQUESTED
author_association: MEMBER
submitted_at: 2025-05-26T19:17:39Z
user: login: jdm
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-27T02:49:25Z
user: login: tharkum
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-27T06:35:45Z
user: login: tharkum
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-27T06:39:26Z
user: login: tharkum
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-27T06:39:38Z
user: login: tharkum
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-27T06:39:45Z
user: login: jdm
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-27T13:34:10Z
user: login: tharkum
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-28T05:05:04Z
user: login: tharkum
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-28T05:05:16Z
user: login: jdm
body: Thanks for investigating that! I've opened a new issue for it.
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-28T12:03:54Z

Review comments:
diff_hunk: @@ -490,6 +502,51 @@ impl CanvasState {
         result
     }
 
+    #[allow(clippy::too_many_arguments)]
+    fn draw_html_video_element(
+        &self,
+        video: &HTMLVideoElement,
+        canvas: Option<&HTMLCanvasElement>,
+        sx: f64,
+        sy: f64,
+        sw: Option<f64>,
+        sh: Option<f64>,
+        dx: f64,
+        dy: f64,
+        dw: Option<f64>,
+        dh: Option<f64>,
+    ) -> ErrorResult {
+        let Some(snapshot) = video.get_current_frame_data() else {
+            return Ok(());
+        };
+
+        let video_size = snapshot.size().to_f64();
+        let dw = dw.unwrap_or(video_size.width);
+        let dh = dh.unwrap_or(video_size.height);
+        let sw = sw.unwrap_or(video_size.width);
+        let sh = sh.unwrap_or(video_size.height);
+
+        // Step 4. Establish the source and destination rectangles.
path: components/script/canvas_state.rs
user: login: jdm
body: Which specification algorithm is this referencing? Can we drop a link either above it or on the method itself?
created_at: 2025-05-26T19:04:50Z
author_association: MEMBER
diff_hunk: @@ -490,6 +502,51 @@ impl CanvasState {
         result
     }
 
+    #[allow(clippy::too_many_arguments)]
+    fn draw_html_video_element(
+        &self,
+        video: &HTMLVideoElement,
+        canvas: Option<&HTMLCanvasElement>,
+        sx: f64,
+        sy: f64,
+        sw: Option<f64>,
+        sh: Option<f64>,
+        dx: f64,
+        dy: f64,
+        dw: Option<f64>,
+        dh: Option<f64>,
+    ) -> ErrorResult {
path: components/script/canvas_state.rs
user: login: jdm
body: Since we only return Ok from this method, why do we need a return value at all?
created_at: 2025-05-26T19:06:20Z
author_association: MEMBER
diff_hunk: @@ -2069,6 +2069,15 @@ impl HTMLMediaElement {
             }
         }
     }
+
+    pub(crate) fn same_origin(&self, origin: &MutableOrigin) -> bool {
+        // TODO: Step 8.6. Update the media data with the contents of response.
+        // <https://html.spec.whatwg.org/multipage/#concept-media-load-resource>
+        match self.resource_url.borrow().as_ref() {
path: components/script/dom/htmlmediaelement.rs
user: login: jdm
body: This will treat a request that is initially same-origin but redirects to a cross-origin URL as same-origin, which explains why there are tests for that case that are failing after these changes. Can we implement the correct fix here, by storing the Metadata.final_url that's available in process_response and using that to compare instead of self.resource_url?
created_at: 2025-05-26T19:12:24Z
author_association: MEMBER
diff_hunk: @@ -642,14 +642,32 @@ impl WebGLRenderingContext {
                     return Ok(None);
                 }
             },
-            TexImageSource::HTMLVideoElement(video) => match video.get_current_frame_data() {
-                Some((data, size)) => {
-                    let data = data.unwrap_or_else(|| {
-                        IpcSharedMemory::from_bytes(&vec![0; size.area() as usize * 4])
-                    });
-                    TexPixels::new(data, size, PixelFormat::BGRA8, false)
-                },
-                None => return Ok(None),
+            TexImageSource::HTMLVideoElement(video) => {
+                let document = match self.canvas {
+                    HTMLCanvasElementOrOffscreenCanvas::HTMLCanvasElement(ref canvas) => {
+                        canvas.owner_document()
+                    },
+                    HTMLCanvasElementOrOffscreenCanvas::OffscreenCanvas(ref _canvas) => {
+                        // TODO: Support retrieving image pixels here for OffscreenCanvas
+                        return Ok(None);
+                    },
+                };
+                if !video.same_origin(document.origin()) {
+                    return Err(Error::Security);
+                }
+
+                if let Some(snapshot) = video.get_current_frame_data() {
+                    let snapshot = snapshot.as_ipc();
+                    let size = snapshot.size().cast();
+                    let format: PixelFormat = match snapshot.format() {
+                        snapshot::PixelFormat::RGBA => PixelFormat::RGBA8,
+                        snapshot::PixelFormat::BGRA => PixelFormat::BGRA8,
+                    };
+                    let premultiply = snapshot.alpha_mode().is_premultiplied();
+                    TexPixels::new(snapshot.to_ipc_shared_memory(), size, format, premultiply)
+                } else {
+                    return Ok(None);
+                }
path: components/script/dom/webglrenderingcontext.rs
user: login: jdm
body: ```suggestion
                let Some(snapshot) = video.get_current_frame_data() else { return Ok(None) };
                let snapshot = snapshot.as_ipc();
                let size = snapshot.size().cast();
                let format: PixelFormat = match snapshot.format() {
                    snapshot::PixelFormat::RGBA => PixelFormat::RGBA8,
                    snapshot::PixelFormat::BGRA => PixelFormat::BGRA8,
                };
                let premultiply = snapshot.alpha_mode().is_premultiplied();
                TexPixels::new(snapshot.to_ipc_shared_memory(), size, format, premultiply)
```
created_at: 2025-05-26T19:17:15Z
author_association: MEMBER
diff_hunk: @@ -2069,6 +2069,15 @@ impl HTMLMediaElement {
             }
         }
     }
+
+    pub(crate) fn same_origin(&self, origin: &MutableOrigin) -> bool {
+        // TODO: Step 8.6. Update the media data with the contents of response.
+        // <https://html.spec.whatwg.org/multipage/#concept-media-load-resource>
+        match self.resource_url.borrow().as_ref() {
path: components/script/dom/htmlmediaelement.rs
user: login: jdm
body: https://github.com/servo/servo/blob/cf3ad2de774c8f8022135b0a9d466c197d961aa2/components/script/stylesheet_loader.rs#L132-L138 is another way to handle this situation.
created_at: 2025-05-27T02:49:25Z
author_association: MEMBER
diff_hunk: @@ -490,6 +502,51 @@ impl CanvasState {
         result
     }
 
+    #[allow(clippy::too_many_arguments)]
+    fn draw_html_video_element(
+        &self,
+        video: &HTMLVideoElement,
+        canvas: Option<&HTMLCanvasElement>,
+        sx: f64,
+        sy: f64,
+        sw: Option<f64>,
+        sh: Option<f64>,
+        dx: f64,
+        dy: f64,
+        dw: Option<f64>,
+        dh: Option<f64>,
+    ) -> ErrorResult {
+        let Some(snapshot) = video.get_current_frame_data() else {
+            return Ok(());
+        };
+
+        let video_size = snapshot.size().to_f64();
+        let dw = dw.unwrap_or(video_size.width);
+        let dh = dh.unwrap_or(video_size.height);
+        let sw = sw.unwrap_or(video_size.width);
+        let sh = sh.unwrap_or(video_size.height);
+
+        // Step 4. Establish the source and destination rectangles.
path: components/script/canvas_state.rs
user: login: tharkum
body: I will add link on the method itself.
created_at: 2025-05-27T06:35:45Z
author_association: CONTRIBUTOR
diff_hunk: @@ -490,6 +502,51 @@ impl CanvasState {
         result
     }
 
+    #[allow(clippy::too_many_arguments)]
+    fn draw_html_video_element(
+        &self,
+        video: &HTMLVideoElement,
+        canvas: Option<&HTMLCanvasElement>,
+        sx: f64,
+        sy: f64,
+        sw: Option<f64>,
+        sh: Option<f64>,
+        dx: f64,
+        dy: f64,
+        dw: Option<f64>,
+        dh: Option<f64>,
+    ) -> ErrorResult {
path: components/script/canvas_state.rs
user: login: tharkum
body: I made it similar to `fn draw_****()` to mimic the common function signature output.
It is not necessary right now to have `ErrorResult` as output.

Remove it and add `Ok` to function call?

`self.draw_html_video_element(video, htmlcanvas, sx, sy, sw, sh, dx, dy, dw, dh);
Ok(())
`
created_at: 2025-05-27T06:39:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2069,6 +2069,15 @@ impl HTMLMediaElement {
             }
         }
     }
+
+    pub(crate) fn same_origin(&self, origin: &MutableOrigin) -> bool {
+        // TODO: Step 8.6. Update the media data with the contents of response.
+        // <https://html.spec.whatwg.org/multipage/#concept-media-load-resource>
+        match self.resource_url.borrow().as_ref() {
path: components/script/dom/htmlmediaelement.rs
user: login: tharkum
body: Thanks I will check it
created_at: 2025-05-27T06:39:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -642,14 +642,32 @@ impl WebGLRenderingContext {
                     return Ok(None);
                 }
             },
-            TexImageSource::HTMLVideoElement(video) => match video.get_current_frame_data() {
-                Some((data, size)) => {
-                    let data = data.unwrap_or_else(|| {
-                        IpcSharedMemory::from_bytes(&vec![0; size.area() as usize * 4])
-                    });
-                    TexPixels::new(data, size, PixelFormat::BGRA8, false)
-                },
-                None => return Ok(None),
+            TexImageSource::HTMLVideoElement(video) => {
+                let document = match self.canvas {
+                    HTMLCanvasElementOrOffscreenCanvas::HTMLCanvasElement(ref canvas) => {
+                        canvas.owner_document()
+                    },
+                    HTMLCanvasElementOrOffscreenCanvas::OffscreenCanvas(ref _canvas) => {
+                        // TODO: Support retrieving image pixels here for OffscreenCanvas
+                        return Ok(None);
+                    },
+                };
+                if !video.same_origin(document.origin()) {
+                    return Err(Error::Security);
+                }
+
+                if let Some(snapshot) = video.get_current_frame_data() {
+                    let snapshot = snapshot.as_ipc();
+                    let size = snapshot.size().cast();
+                    let format: PixelFormat = match snapshot.format() {
+                        snapshot::PixelFormat::RGBA => PixelFormat::RGBA8,
+                        snapshot::PixelFormat::BGRA => PixelFormat::BGRA8,
+                    };
+                    let premultiply = snapshot.alpha_mode().is_premultiplied();
+                    TexPixels::new(snapshot.to_ipc_shared_memory(), size, format, premultiply)
+                } else {
+                    return Ok(None);
+                }
path: components/script/dom/webglrenderingcontext.rs
user: login: tharkum
body: Ok
created_at: 2025-05-27T06:39:44Z
author_association: CONTRIBUTOR
diff_hunk: @@ -490,6 +502,51 @@ impl CanvasState {
         result
     }
 
+    #[allow(clippy::too_many_arguments)]
+    fn draw_html_video_element(
+        &self,
+        video: &HTMLVideoElement,
+        canvas: Option<&HTMLCanvasElement>,
+        sx: f64,
+        sy: f64,
+        sw: Option<f64>,
+        sh: Option<f64>,
+        dx: f64,
+        dy: f64,
+        dw: Option<f64>,
+        dh: Option<f64>,
+    ) -> ErrorResult {
path: components/script/canvas_state.rs
user: login: jdm
body: Yep!
created_at: 2025-05-27T13:34:10Z
author_association: MEMBER
diff_hunk: @@ -2069,6 +2069,15 @@ impl HTMLMediaElement {
             }
         }
     }
+
+    pub(crate) fn same_origin(&self, origin: &MutableOrigin) -> bool {
+        // TODO: Step 8.6. Update the media data with the contents of response.
+        // <https://html.spec.whatwg.org/multipage/#concept-media-load-resource>
+        match self.resource_url.borrow().as_ref() {
path: components/script/dom/htmlmediaelement.rs
user: login: tharkum
body: Done
created_at: 2025-05-28T05:05:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -490,6 +502,51 @@ impl CanvasState {
         result
     }
 
+    #[allow(clippy::too_many_arguments)]
+    fn draw_html_video_element(
+        &self,
+        video: &HTMLVideoElement,
+        canvas: Option<&HTMLCanvasElement>,
+        sx: f64,
+        sy: f64,
+        sw: Option<f64>,
+        sh: Option<f64>,
+        dx: f64,
+        dy: f64,
+        dw: Option<f64>,
+        dh: Option<f64>,
+    ) -> ErrorResult {
path: components/script/canvas_state.rs
user: login: tharkum
body: Done
created_at: 2025-05-28T05:05:15Z
author_association: CONTRIBUTOR

PR comments:
user: login: tharkum
created_at: 2025-05-26T14:11:22Z
body: @sagudev @xiaochengh < Please take a look.

I moved HTMLVideoElement related code in this PR for easy reviewing (https://github.com/servo/servo/pull/37025)
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-05-27T19:00:36Z
body: 🔨 Triggering try run ([#15283467371](https://github.com/servo/servo/actions/runs/15283467371)) for Linux (WPT)
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-05-27T19:23:43Z
body: <span>Test results for linux-wpt from try job ([#15283467371](https://github.com/servo/servo/actions/runs/15283467371)):<div><details><summary>Flaky unexpected result (18)</summary><ul><li><span>OK [expected TIMEOUT] `/_webgl/conformance/textures/image_bitmap_from_video/tex-2d-alpha-alpha-unsigned_byte.html`</span><ul><li><span>PASS [expected NOTRUN] subtest: `Overall test`</span></li></ul></li><li><span>OK `/content-security-policy/frame-ancestors/frame-ancestors-path-ignored.window.html` ([#36468](http://github.com/servo/servo/issues/36468))</span><ul><li><span>PASS [expected FAIL] subtest: `A 'frame-ancestors' CSP directive with a URL that includes a path should be ignored.`</span></li></ul></li><li><span>TIMEOUT [expected OK] `/fetch/api/redirect/redirect-keepalive.https.any.html` ([#32153](http://github.com/servo/servo/issues/32153))</span><ul><li><span>TIMEOUT [expected PASS] subtest: `[keepalive][iframe][load] mixed content redirect; setting up` 
```
Test timed out
```
</span></li></ul></li><li><span>OK `/fetch/metadata/generated/css-font-face.https.sub.tentative.html` ([#32732](http://github.com/servo/servo/issues/32732))</span><ul><li><span>PASS [expected FAIL] subtest: `sec-fetch-dest`</span></li><li><span>PASS [expected FAIL] subtest: `sec-fetch-user`</span></li><li><span>PASS [expected FAIL] subtest: `sec-fetch-storage-access - Cross-site`</span></li><li><span>PASS [expected FAIL] subtest: `sec-fetch-storage-access - Same site`</span></li></ul></li><li><span>OK `/fetch/metadata/generated/css-font-face.sub.tentative.html` ([#34624](http://github.com/servo/servo/issues/34624))</span><ul><li><span>PASS [expected FAIL] subtest: `sec-fetch-storage-access - Not sent to non-trustworthy same-site destination`</span></li></ul></li><li><span>OK `/html/browsers/browsing-the-web/navigating-across-documents/008.html` ([#24456](http://github.com/servo/servo/issues/24456))</span><ul><li><span>PASS [expected FAIL] subtest: `Link with onclick form submit to javascript url and href navigation `</span></li></ul></li><li><span>OK `/html/browsers/browsing-the-web/navigating-across-documents/initial-empty-document/iframe-src-aboutblank-navigate-immediately.html` ([#29048](http://github.com/servo/servo/issues/29048))</span><ul><li><span>FAIL [expected PASS] subtest: `Navigating to a different document with link click` 
```
assert_equals: expected "http://web-platform.test:8000/common/blank.html?1" but got "about:blank"
```
</span></li></ul></li><li><span>OK `/html/browsers/browsing-the-web/navigating-across-documents/initial-empty-document/load-pageshow-events-window-open.html` ([#28691](http://github.com/servo/servo/issues/28691))</span><ul><li><span>PASS [expected FAIL] subtest: `load event does not fire on window.open('about:blank')`</span></li></ul></li><li><span>OK `/html/browsers/browsing-the-web/navigating-across-documents/javascript-url-return-value-handling-dynamic.html` ([#28066](http://github.com/servo/servo/issues/28066))</span><ul><li><span>FAIL [expected PASS] subtest: `0041 set in href="" targeting a frame and clicked` 
```
assert_equals: expected "A" but got ""
```
</span></li><li><span>FAIL [expected PASS] subtest: `0080 00FF set in href="" targeting a frame and clicked` 
```
assert_equals: expected "ÿ" but got ""
```
</span></li><li><span>FAIL [expected PASS] subtest: `0080 00FF 0100 set in href="" targeting a frame and clicked` 
```
assert_equals: expected "ÿĀ" but got ""
```
</span></li><li><span>FAIL [expected PASS] subtest: `D83D DE0D set in href="" targeting a frame and clicked` 
```
assert_equals: expected "😍" but got ""
```
</span></li><li><span>FAIL [expected PASS] subtest: `DE0D 0041 set in href="" targeting a frame and clicked` 
```
assert_equals: expected "\ufffdA" but got ""
```
</span></li></ul></li><li><span>OK `/html/browsers/history/the-history-interface/traverse_the_history_2.html` ([#21383](http://github.com/servo/servo/issues/21383))</span><ul><li><span>PASS [expected FAIL] subtest: `Multiple history traversals, last would be aborted`</span></li></ul></li><li><span>TIMEOUT [expected ERROR] `/html/canvas/element/manual/imagebitmap/createImageBitmap-flipY.html` ([#32745](http://github.com/servo/servo/issues/32745))</span><ul><li><span>TIMEOUT [expected FAIL] subtest: `createImageBitmap from an HTMLVideoElement from a data URL imageOrientation: "from-image", and drawImage on the created ImageBitmap` 
```
Test timed out
```
</span></li><li><span>NOTRUN [expected FAIL] subtest: `createImageBitmap from an HTMLVideoElement from a data URL imageOrientation: "flipY", and drawImage on the created ImageBitmap`</span></li><li><span>NOTRUN [expected FAIL] subtest: `createImageBitmap from a bitmap HTMLImageElement imageOrientation: "from-image", and drawImage on the created ImageBitmap`</span></li><li><span>NOTRUN [expected FAIL] subtest: `createImageBitmap from a bitmap HTMLImageElement imageOrientation: "flipY", and drawImage on the created ImageBitmap`</span></li><li><span>NOTRUN [expected FAIL] subtest: `createImageBitmap from a vector HTMLImageElement imageOrientation: "from-image", and drawImage on the created ImageBitmap`</span></li><li><span>NOTRUN [expected FAIL] subtest: `createImageBitmap from a vector HTMLImageElement imageOrientation: "flipY", and drawImage on the created ImageBitmap`</span></li><li><span>NOTRUN [expected FAIL] subtest: `createImageBitmap from a bitmap SVGImageElement imageOrientation: "from-image", and drawImage on the created ImageBitmap`</span></li><li><span>NOTRUN [expected FAIL] subtest: `createImageBitmap from a bitmap SVGImageElement imageOrientation: "flipY", and drawImage on the created ImageBitmap`</span></li><li><span>NOTRUN [expected FAIL] subtest: `createImageBitmap from a vector SVGImageElement imageOrientation: "from-image", and drawImage on the created ImageBitmap`</span></li><li><span>NOTRUN [expected FAIL] subtest: `createImageBitmap from a vector SVGImageElement imageOrientation: "flipY", and drawImage on the created ImageBitmap`</span></li><li><span>And 8 more unexpected results...</span></li></ul></li><li><span>OK `/html/semantics/embedded-content/media-elements/offsets-into-the-media-resource/currentTime.html`</span><ul><li><span>FAIL [expected PASS] subtest: `setting currentTime when readyState is greater than HAVE_NOTHING` 
```
assert_true: expected true got false
```
</span></li></ul></li><li><span>OK [expected TIMEOUT] `/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-3.html` ([#24057](http://github.com/servo/servo/issues/24057))</span><ul><li><span>FAIL [expected TIMEOUT] subtest: `Check that popups from a sandboxed iframe escape the sandbox if
       allow-popups-to-escape-sandbox is used` 
```
assert_equals: It came from a sandboxed iframe expected "null" but got "http://web-platform.test:8000"
```
</span></li></ul></li><li><span>OK `/html/semantics/embedded-content/the-video-element/intrinsic_sizes.htm`</span><ul><li><span>FAIL [expected PASS] subtest: `default object size after src is removed` 
```
assert_equals: expected "300px" but got "320px"
```
</span></li></ul></li><li><span>TIMEOUT `/resource-timing/test_resource_timing.html` ([#25720](http://github.com/servo/servo/issues/25720))</span><ul><li><span>PASS [expected FAIL] subtest: `PerformanceEntry has correct name, initiatorType, startTime, and duration (img)`</span></li></ul></li><li><span>TIMEOUT [expected OK] `/webmessaging/with-ports/017.html` ([#24486](http://github.com/servo/servo/issues/24486))</span><ul><li><span>TIMEOUT [expected PASS] subtest: `origin of the script that invoked the method, about:blank` 
```
Test timed out
```
</span></li></ul></li><li><span>TIMEOUT [expected OK] `/webstorage/localstorage-about-blank-3P-iframe-opens-3P-window.partitioned.html` ([#29053](http://github.com/servo/servo/issues/29053))</span><ul><li><span>TIMEOUT [expected PASS] subtest: `StorageKey: test 3P about:blank window opened from a 3P iframe` 
```
Test timed out
```
</span></li></ul></li><li><span>OK `/xhr/open-url-multi-window-5.htm` ([#23360](http://github.com/servo/servo/issues/23360))</span><ul><li><span>FAIL [expected PASS] subtest: `XMLHttpRequest: open() resolving URLs (multi-Window; 5)` 
```
assert_throws_dom: function "function() {client.open("GET", "...") }" did not throw
```
</span></li></ul></li></ul></details><details><summary>Stable unexpected results that are known to be intermittent (22)</summary><ul><li><span>OK `/FileAPI/url/url-with-fetch.any.worker.html` ([#21517](http://github.com/servo/servo/issues/21517))</span><ul><li><span>PASS [expected FAIL] subtest: `Revoke blob URL after calling fetch, fetch should succeed`</span></li></ul></li><li><span>FAIL [expected PASS] `/_mozilla/mozilla/sslfail.html` ([#10760](http://github.com/servo/servo/issues/10760))</span></li><li><span>TIMEOUT [expected OK] `/_mozilla/mozilla/window_resizeTo.html` ([#36741](http://github.com/servo/servo/issues/36741))</span><ul><li><span>TIMEOUT [expected PASS] subtest: `Popup onresize event fires after resizeTo` 
```
Test timed out
```
</span></li></ul></li><li><span>PASS [expected FAIL] `/css/compositing/mix-blend-mode/mix-blend-mode-video-sibling.html` ([#32849](http://github.com/servo/servo/issues/32849))</span></li><li><span>PASS [expected FAIL] `/css/css-overflow/overflow-video.html` ([#34720](http://github.com/servo/servo/issues/34720))</span></li><li><span>FAIL [expected PASS] `/css/css-tables/table-cell-overflow-auto-scrolled.html` ([#35011](http://github.com/servo/servo/issues/35011))</span></li><li><span>OK [expected ERROR] `/fetch/nosniff/importscripts.html` ([#27144](http://github.com/servo/servo/issues/27144))</span><ul><li><span>PASS [expected TIMEOUT] subtest: `Test importScripts()`</span></li></ul></li><li><span>OK `/html/browsers/browsing-the-web/navigating-across-documents/initial-empty-document/iframe-nosrc.html` ([#34819](http://github.com/servo/servo/issues/34819))</span><ul><li><span>FAIL [expected PASS] subtest: `form submission` 
```
assert_equals: expected "http://web-platform.test:8000/common/blank.html?1=" but got "about:blank"
```
</span></li></ul></li><li><span>TIMEOUT [expected OK] `/html/browsers/history/the-history-interface/001.html` ([#12580](http://github.com/servo/servo/issues/12580))</span></li><li><span>OK `/html/browsers/history/the-history-interface/traverse_the_history_3.html` ([#21383](http://github.com/servo/servo/issues/21383))</span><ul><li><span>FAIL [expected PASS] subtest: `Multiple history traversals, last would be aborted` 
```
assert_array_equals: Pages opened during history navigation expected property 1 to be 3 but got 2 (expected array [6, 3] got [6, 2])
```
</span></li></ul></li><li><span>OK `/html/browsers/history/the-history-interface/traverse_the_history_4.html` ([#21383](http://github.com/servo/servo/issues/21383))</span><ul><li><span>FAIL [expected PASS] subtest: `Multiple history traversals, last would be aborted` 
```
assert_array_equals: Pages opened during history navigation expected property 1 to be 5 but got 3 (expected array [6, 5] got [6, 3])
```
</span></li></ul></li><li><span>OK `/html/browsers/history/the-history-interface/traverse_the_history_5.html` ([#21383](http://github.com/servo/servo/issues/21383))</span><ul><li><span>PASS [expected FAIL] subtest: `Multiple history traversals, last would be aborted`</span></li></ul></li><li><span>OK [expected TIMEOUT] `/html/canvas/element/manual/imagebitmap/createImageBitmap-origin.sub.html` ([#31931](http://github.com/servo/servo/issues/31931))</span></li><li><span>OK [expected TIMEOUT] `/html/interaction/focus/the-autofocus-attribute/supported-elements.html` ([#24145](http://github.com/servo/servo/issues/24145))</span><ul><li><span>FAIL [expected NOTRUN] subtest: `Host element with delegatesFocus should support autofocus` 
```
assert_equals: expected Element node &lt;div autofocus=""&gt;&lt;/div&gt; but got Element node &lt;body&gt;&lt;/body&gt;
```
</span></li><li><span>FAIL [expected NOTRUN] subtest: `Host element with delegatesFocus including no focusable descendants should be skipped` 
```
assert_equals: expected Element node &lt;input autofocus=""&gt;&lt;/input&gt; but got Element node &lt;body&gt;&lt;div autofocus=""&gt;&lt;/div&gt;&lt;input autofocus=""&gt;&lt;/body&gt;
```
</span></li><li><span>FAIL [expected NOTRUN] subtest: `Area element should support autofocus` 
```
promise_test: Unhandled rejection with value: object "TypeError: w.document.querySelector(...) is null"
```
</span></li></ul></li><li><span>OK [expected CRASH] `/html/semantics/embedded-content/media-elements/media_fragment_seek.html` ([#24114](http://github.com/servo/servo/issues/24114))</span></li><li><span>OK `/html/semantics/embedded-content/the-iframe-element/iframe-loading-lazy-reload-location-reload.html` ([#32595](http://github.com/servo/servo/issues/32595))</span><ul><li><span>FAIL [expected PASS] subtest: `Reloading iframe loading='lazy' before it is loaded: location.reload` 
```
uncaught exception: Error: assert_equals: expected "http://web-platform.test:8000/html/semantics/embedded-content/the-iframe-element/support/blank.htm?src" but got "about:blank"
```
</span></li></ul></li><li><span>OK `/html/semantics/forms/form-submission-0/multipart-formdata.window.html` ([#28725](http://github.com/servo/servo/issues/28725))</span><ul><li><span>PASS [expected FAIL] subtest: `multipart/form-data: Basic test (formdata event)`</span></li></ul></li><li><span>OK `/html/semantics/forms/form-submission-0/urlencoded2.window.html` ([#28687](http://github.com/servo/servo/issues/28687))</span><ul><li><span>PASS [expected FAIL] subtest: `application/x-www-form-urlencoded: single quote in value (formdata event)`</span></li></ul></li><li><span>OK `/navigation-timing/test-navigation-type-reload.html` ([#33334](http://github.com/servo/servo/issues/33334))</span><ul><li><span>FAIL [expected PASS] subtest: `Reload domContentLoadedEventEnd &gt; Original domContentLoadedEventEnd` 
```
assert_true: Reload domContentLoadedEventEnd &gt; Original domContentLoadedEventEnd expected true got false
```
</span></li></ul></li><li><span>OK `/resize-observer/change-layout-in-error.html` ([#32629](http://github.com/servo/servo/issues/32629))</span><ul><li><span>FAIL [expected PASS] subtest: `Changing layout in window error handler should not result in lifecyle loop when resize observer loop limit is reached.` 
```
assert_equals: expected 1 but got 2
```
</span></li></ul></li><li><span>OK `/resize-observer/eventloop.html` ([#33599](http://github.com/servo/servo/issues/33599))</span><ul><li><span>FAIL [expected PASS] subtest: `test0: multiple notifications inside same event loop` 
```
assert_equals: new loop expected 1 but got 0
```
</span></li></ul></li><li><span>OK `/webaudio/the-audio-api/the-audiobuffersourcenode-interface/sub-sample-buffer-stitching.html` ([#22849](http://github.com/servo/servo/issues/22849))</span><ul><li><span>FAIL [expected PASS] subtest: `X Stitched sine-wave buffers at sample rate 43800 does not equal [0,0.06264832615852356,0.12505052983760834,0.18696144223213196,0.24813786149024963,0.308339387178421,0.36732959747314453,0.4248766601085663,0.480754554271698,0.5347436666488647,0.5866320133209229,0.6362156271934509,0.6832997798919678,0.7276994585990906,0.7692402601242065,0.8077589869499207...] with an element-wise tolerance of {"absoluteThreshold":0.0038986,"relativeThreshold":0}.
	Index	Actual			Expected		AbsError		RelError		Test threshold
	[14650]	2.9400666000000000e+7	8.6956524848937988e-1	2.9400665130434752e+7	3.3810763690832831e+7	3.8985999999999999e-3
	[14651]	3.0547976493835449e-1	8.9879405498504639e-1	5.9331429004669189e-1	6.6012262403823208e-1	3.8985999999999999e-3
	Max AbsError of 2.9400665130434752e+7 at index of 14650.
	Max RelError of 3.3810763690832831e+7 at index of 14650.
` 
```
assert_true: expected true got false
```
</span></li><li><span>FAIL [expected PASS] subtest: `X SNR (-105.9330571670632 dB) is not greater than or equal to 65.737. Got -105.9330571670632.` 
```
assert_true: expected true got false
```
</span></li></ul></li></ul></details><details><summary>Stable unexpected results (1)</summary><ul><li><span>CRASH [expected TIMEOUT] `/html/canvas/element/manual/wide-gamut-canvas/canvas-display-p3-drawImage.https.html`</span></li></ul></details></div></span>
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-05-27T19:23:53Z
body: ⚠️ Try run ([#15283467371](https://github.com/servo/servo/actions/runs/15283467371)) failed.
author_association: NONE
user: login: tharkum
created_at: 2025-05-27T19:45:19Z
body:  Quite strange, I didn't  observe CRASH on local PC or in try [action](https://github.com/tharkum/servo/actions/runs/15276092018)

There are 3 commits different only with my main branch. 

@jdm BTW, did you run WPT with https://github.com/servo/servo/pull/37136?
author_association: CONTRIBUTOR
user: login: jdm
created_at: 2025-05-27T19:48:34Z
body: > Quite strange, I didn't observe CRASH on local PC or in try [action](https://github.com/tharkum/servo/actions/runs/15276092018)
> 
> There are 3 commits different only with my main branch.
> 
> @jdm BTW, did you run WPT with #37136?

It ran as part of the merge.
author_association: MEMBER
user: login: tharkum
created_at: 2025-05-27T19:53:17Z
body: OK, thanks. I will try find error in my PR code :)
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-05-27T22:18:54Z
body: 🔨 Triggering try run ([#15286872580](https://github.com/servo/servo/actions/runs/15286872580)) for Linux (WPT)
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-05-27T22:43:22Z
body: <span>Test results for linux-wpt from try job ([#15286872580](https://github.com/servo/servo/actions/runs/15286872580)):<div><details><summary>Flaky unexpected result (20)</summary><ul><li><span>TIMEOUT [expected OK] `/_mozilla/mozilla/window_resizeTo.html` ([#36741](http://github.com/servo/servo/issues/36741))</span><ul><li><span>TIMEOUT [expected PASS] subtest: `Popup onresize event fires after resizeTo` 
```
Test timed out
```
</span></li></ul></li><li><span>OK `/content-security-policy/frame-ancestors/frame-ancestors-path-ignored.window.html` ([#36468](http://github.com/servo/servo/issues/36468))</span><ul><li><span>PASS [expected FAIL] subtest: `A 'frame-ancestors' CSP directive with a URL that includes a path should be ignored.`</span></li></ul></li><li><span>FAIL [expected PASS] `/css/css-overflow/line-clamp/line-clamp-021.tentative.html` ([#35008](http://github.com/servo/servo/issues/35008))</span></li><li><span>FAIL [expected PASS] `/css/css-tables/table-cell-overflow-auto-scrolled.html` ([#35011](http://github.com/servo/servo/issues/35011))</span></li><li><span>OK [expected ERROR] `/fetch/fetch-later/quota/same-origin-iframe/multiple-iframes.tentative.https.window.html` ([#35176](http://github.com/servo/servo/issues/35176))</span></li><li><span>OK [expected ERROR] `/fetch/fetch-later/quota/same-origin-iframe/oversized-payload.tentative.https.window.html` ([#35210](http://github.com/servo/servo/issues/35210))</span></li><li><span>OK `/html/browsers/browsing-the-web/navigating-across-documents/refresh/same-document-refresh.html` ([#34597](http://github.com/servo/servo/issues/34597))</span><ul><li><span>FAIL [expected PASS] subtest: `Same-Document Referrer from Refresh` 
```
assert_equals: original page loads expected "http://web-platform.test:8000/html/browsers/browsing-the-web/navigating-across-documents/refresh/resources/refresh-with-section.sub.html?url=%23section" but got "http://web-platform.test:8000/html/browsers/browsing-the-web/navigating-across-documents/refresh/resources/refresh-with-section.sub.html?url=%23section#section"
```
</span></li></ul></li><li><span>OK `/html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/a-click.html` ([#28697](http://github.com/servo/servo/issues/28697))</span><ul><li><span>FAIL [expected PASS] subtest: `aElement.click() before the load event must NOT replace` 
```
assert_equals: expected "http://web-platform.test:8000/common/blank.html?thereplacement" but got "http://web-platform.test:8000/html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/resources/code-injector.html?pipe=sub(none)&amp;code=%0A%20%20%20%20const%20a%20%3D%20document.createElement(%22a%22)%3B%0A%20%20%20%20a.href%20%3D%20%22%2Fcommon%2Fblank.html%3Fthereplacement%22%3B%0A%20%20%20%20document.currentScript.before(a)%3B%0A%20%20%20%20a.click()%3B%0A%20%20"
```
</span></li></ul></li><li><span>OK `/html/browsers/browsing-the-web/overlapping-navigations-and-traversals/cross-document-nav-cross-document-nav.html` ([#29181](http://github.com/servo/servo/issues/29181))</span><ul><li><span>PASS [expected FAIL] subtest: `cross-document navigation then cross-document navigation`</span></li></ul></li><li><span>OK `/html/browsers/windows/browsing-context-names/duplicate-name-order.html` ([#34623](http://github.com/servo/servo/issues/34623))</span><ul><li><span>PASS [expected FAIL] subtest: `Duplicate name lookup order`</span></li></ul></li><li><span>TIMEOUT [expected ERROR] `/html/canvas/element/manual/imagebitmap/createImageBitmap-colorSpaceConversion.html` ([#34151](http://github.com/servo/servo/issues/34151))</span></li><li><span>PASS [expected FAIL] `/html/canvas/element/manual/text/canvas.2d.disconnected.html` ([#30063](http://github.com/servo/servo/issues/30063))</span></li><li><span>TIMEOUT [expected OK] `/html/interaction/focus/the-autofocus-attribute/update-the-rendering.html` ([#24145](http://github.com/servo/servo/issues/24145))</span><ul><li><span>TIMEOUT [expected FAIL] subtest: `"Flush autofocus candidates" should be happen before a scroll event and animation frame callbacks` 
```
Test timed out
```
</span></li></ul></li><li><span>TIMEOUT [expected OK] `/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-3.html` ([#24066](http://github.com/servo/servo/issues/24066))</span><ul><li><span>NOTRUN [expected FAIL] subtest: `Check that popups from a sandboxed iframe do not escape the sandbox`</span></li></ul></li><li><span>OK `/html/semantics/forms/form-submission-0/multipart-formdata.window.html` ([#28725](http://github.com/servo/servo/issues/28725))</span><ul><li><span>PASS [expected FAIL] subtest: `multipart/form-data: Basic test (normal form)`</span></li><li><span>PASS [expected FAIL] subtest: `multipart/form-data: 0x00 in name (normal form)`</span></li></ul></li><li><span>OK `/html/semantics/forms/form-submission-0/text-plain.window.html` ([#28687](http://github.com/servo/servo/issues/28687))</span><ul><li><span>PASS [expected FAIL] subtest: `text/plain: 0x00 in name (normal form)`</span></li></ul></li><li><span>TIMEOUT [expected CRASH] `/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/ignore-opens-during-unload.window.html` ([#21444](http://github.com/servo/servo/issues/21444))</span></li><li><span>OK `/navigation-timing/test-navigation-type-reload.html` ([#33334](http://github.com/servo/servo/issues/33334))</span><ul><li><span>PASS [expected FAIL] subtest: `Reload domContentLoadedEventStart &gt; Original domContentLoadedEventStart`</span></li><li><span>PASS [expected FAIL] subtest: `Reload fetchStart &gt; Original fetchStart`</span></li></ul></li><li><span>TIMEOUT [expected OK] `/resource-timing/nested-context-navigations-iframe.html` ([#24311](http://github.com/servo/servo/issues/24311))</span><ul><li><span>TIMEOUT [expected PASS] subtest: `Test that iframe navigations are not observable by the parent, even after history navigations by the parent` 
```
Test timed out
```
</span></li><li><span>NOTRUN [expected PASS] subtest: `Test that crossorigin iframe navigations are not observable by the parent, even after history navigations by the parent`</span></li><li><span>NOTRUN [expected PASS] subtest: `Test that cross-site iframe navigations are not observable by the parent, even after history navigations by the parent`</span></li><li><span>NOTRUN [expected PASS] subtest: `Test that iframe navigations are not observable by the parent`</span></li><li><span>NOTRUN [expected PASS] subtest: `Test that crossorigin iframe navigations are not observable by the parent`</span></li><li><span>NOTRUN [expected PASS] subtest: `Test that cross-site iframe navigations are not observable by the parent`</span></li><li><span>NOTRUN [expected PASS] subtest: `Test that iframe refreshes are not observable by the parent`</span></li><li><span>NOTRUN [expected PASS] subtest: `Test that crossorigin iframe refreshes are not observable by the parent`</span></li><li><span>NOTRUN [expected PASS] subtest: `Test that cross-site iframe refreshes are not observable by the parent`</span></li></ul></li><li><span>ERROR [expected OK] `/workers/baseurl/alpha/import-in-moduleworker.html` ([#21315](http://github.com/servo/servo/issues/21315))</span></li></ul></details><details><summary>Stable unexpected results that are known to be intermittent (20)</summary><ul><li><span>TIMEOUT `/FileAPI/url/url-in-tags-revoke.window.html` ([#19978](http://github.com/servo/servo/issues/19978))</span><ul><li><span>TIMEOUT [expected PASS] subtest: `Fetching a blob URL immediately before revoking it works in &lt;script&gt; tags.` 
```
Test timed out
```
</span></li></ul></li><li><span>OK `/FileAPI/url/url-with-fetch.any.worker.html` ([#21517](http://github.com/servo/servo/issues/21517))</span><ul><li><span>PASS [expected FAIL] subtest: `Revoke blob URL after calling fetch, fetch should succeed`</span></li></ul></li><li><span>FAIL [expected PASS] `/_mozilla/mozilla/sslfail.html` ([#10760](http://github.com/servo/servo/issues/10760))</span></li><li><span>OK `/_webgl/conformance/textures/misc/texture-upload-size.html` ([#21770](http://github.com/servo/servo/issues/21770))</span><ul><li><span>FAIL [expected PASS] subtest: `WebGL test #68` 
```
assert_true: could not create image (SVG) expected true got false
```
</span></li><li><span>PASS [expected FAIL] subtest: `WebGL test #156`</span></li><li><span>PASS [expected FAIL] subtest: `WebGL test #172`</span></li></ul></li><li><span>PASS [expected FAIL] `/css/css-overflow/overflow-video.html` ([#34720](http://github.com/servo/servo/issues/34720))</span></li><li><span>ERROR `/fetch/metadata/generated/serviceworker.https.sub.html` ([#36247](http://github.com/servo/servo/issues/36247))</span><ul><li><span>PASS [expected FAIL] subtest: `sec-fetch-site - Same origin, no options - registration`</span></li></ul></li><li><span>OK [expected ERROR] `/fetch/nosniff/importscripts.html` ([#27144](http://github.com/servo/servo/issues/27144))</span><ul><li><span>PASS [expected TIMEOUT] subtest: `Test importScripts()`</span></li></ul></li><li><span>OK `/html/browsers/browsing-the-web/navigating-across-documents/009.html` ([#24456](http://github.com/servo/servo/issues/24456))</span><ul><li><span>FAIL [expected PASS] subtest: `Link with onclick form submit to javascript url with document.write and href navigation ` 
```
assert_array_equals: expected property 1 to be "href" but got "click" (expected array ["write", "href"] got ["write", "click"])
```
</span></li></ul></li><li><span>OK `/html/browsers/browsing-the-web/navigating-across-documents/initial-empty-document/iframe-nosrc.html` ([#34819](http://github.com/servo/servo/issues/34819))</span><ul><li><span>PASS [expected FAIL] subtest: `link click`</span></li><li><span>FAIL [expected PASS] subtest: `form submission` 
```
assert_equals: expected "http://web-platform.test:8000/common/blank.html?1=" but got "about:blank"
```
</span></li></ul></li><li><span>TIMEOUT [expected OK] `/html/browsers/history/the-history-interface/001.html` ([#12580](http://github.com/servo/servo/issues/12580))</span></li><li><span>OK `/html/browsers/history/the-history-interface/traverse_the_history_4.html` ([#21383](http://github.com/servo/servo/issues/21383))</span><ul><li><span>FAIL [expected PASS] subtest: `Multiple history traversals, last would be aborted` 
```
assert_array_equals: Pages opened during history navigation expected property 1 to be 5 but got 3 (expected array [6, 5] got [6, 3])
```
</span></li></ul></li><li><span>OK `/html/browsers/history/the-history-interface/traverse_the_history_5.html` ([#21383](http://github.com/servo/servo/issues/21383))</span><ul><li><span>PASS [expected FAIL] subtest: `Multiple history traversals, last would be aborted`</span></li></ul></li><li><span>TIMEOUT `/html/canvas/element/manual/imagebitmap/createImageBitmap-origin.sub.html` ([#31931](http://github.com/servo/servo/issues/31931))</span><ul><li><span>TIMEOUT [expected FAIL] subtest: `cross-origin HTMLVideoElement: origin unclear 2dContext.drawImage` 
```
Test timed out
```
</span></li><li><span>NOTRUN [expected FAIL] subtest: `cross-origin HTMLVideoElement: origin unclear bitmaprenderer.transferFromImageBitmap`</span></li><li><span>NOTRUN [expected FAIL] subtest: `redirected to cross-origin HTMLVideoElement: origin unclear getImageData`</span></li><li><span>NOTRUN [expected FAIL] subtest: `redirected to cross-origin HTMLVideoElement: origin unclear 2dContext.drawImage`</span></li><li><span>NOTRUN [expected FAIL] subtest: `redirected to cross-origin HTMLVideoElement: origin unclear bitmaprenderer.transferFromImageBitmap`</span></li><li><span>NOTRUN [expected FAIL] subtest: `redirected to same-origin HTMLVideoElement: origin unclear getImageData`</span></li><li><span>NOTRUN [expected FAIL] subtest: `redirected to same-origin HTMLVideoElement: origin unclear 2dContext.drawImage`</span></li><li><span>NOTRUN [expected FAIL] subtest: `redirected to same-origin HTMLVideoElement: origin unclear bitmaprenderer.transferFromImageBitmap`</span></li><li><span>NOTRUN [expected FAIL] subtest: `unclean HTMLCanvasElement: origin unclear getImageData`</span></li><li><span>NOTRUN [expected FAIL] subtest: `unclean HTMLCanvasElement: origin unclear 2dContext.drawImage`</span></li><li><span>And 4 more unexpected results...</span></li></ul></li><li><span>TIMEOUT `/html/interaction/focus/the-autofocus-attribute/supported-elements.html` ([#24145](http://github.com/servo/servo/issues/24145))</span><ul><li><span>TIMEOUT [expected PASS] subtest: `Non-HTMLElement should not support autofocus` 
```
Test timed out
```
</span></li></ul></li><li><span>OK [expected CRASH] `/html/semantics/embedded-content/media-elements/media_fragment_seek.html` ([#24114](http://github.com/servo/servo/issues/24114))</span></li><li><span>TIMEOUT [expected OK] `/html/semantics/embedded-content/the-canvas-element/security.pattern.fillStyle.sub.html` ([#36989](http://github.com/servo/servo/issues/36989))</span><ul><li><span>TIMEOUT [expected FAIL] subtest: `redirected to same-origin HTMLVideoElement: Setting fillStyle to an origin-unclean offscreen canvas pattern makes the canvas origin-unclean` 
```
Test timed out
```
</span></li><li><span>NOTRUN [expected PASS] subtest: `unclean HTMLCanvasElement: Setting fillStyle to an origin-unclean offscreen canvas pattern makes the canvas origin-unclean`</span></li><li><span>NOTRUN [expected FAIL] subtest: `unclean ImageBitmap: Setting fillStyle to an origin-unclean offscreen canvas pattern makes the canvas origin-unclean`</span></li></ul></li><li><span>OK [expected TIMEOUT] `/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-3.html` ([#24057](http://github.com/servo/servo/issues/24057))</span><ul><li><span>FAIL [expected TIMEOUT] subtest: `Check that popups from a sandboxed iframe escape the sandbox if
       allow-popups-to-escape-sandbox is used` 
```
assert_equals: It came from a sandboxed iframe expected "null" but got "http://web-platform.test:8000"
```
</span></li></ul></li><li><span>OK `/html/semantics/forms/historical.html` ([#28568](http://github.com/servo/servo/issues/28568))</span><ul><li><span>PASS [expected FAIL] subtest: `&lt;input name=isindex&gt; should not be supported`</span></li></ul></li><li><span>OK `/resize-observer/change-layout-in-error.html` ([#32629](http://github.com/servo/servo/issues/32629))</span><ul><li><span>FAIL [expected PASS] subtest: `Changing layout in window error handler should not result in lifecyle loop when resize observer loop limit is reached.` 
```
assert_equals: expected 1 but got 2
```
</span></li></ul></li><li><span>OK `/webaudio/the-audio-api/the-audiobuffersourcenode-interface/sub-sample-buffer-stitching.html` ([#22849](http://github.com/servo/servo/issues/22849))</span><ul><li><span>FAIL [expected PASS] subtest: `X Stitched sine-wave buffers at sample rate 43800 does not equal [0,0.06264832615852356,0.12505052983760834,0.18696144223213196,0.24813786149024963,0.308339387178421,0.36732959747314453,0.4248766601085663,0.480754554271698,0.5347436666488647,0.5866320133209229,0.6362156271934509,0.6832997798919678,0.7276994585990906,0.7692402601242065,0.8077589869499207...] with an element-wise tolerance of {"absoluteThreshold":0.0038986,"relativeThreshold":0}.
	Index	Actual			Expected		AbsError		RelError		Test threshold
	[14650]	-9.4988031946911032e-20	8.6956524848937988e-1	8.6956524848937988e-1	1.0000000000000000e+0	3.8985999999999999e-3
	[14651]	3.0547976493835449e-1	8.9879405498504639e-1	5.9331429004669189e-1	6.6012262403823208e-1	3.8985999999999999e-3
	Max AbsError of 8.6956524848937988e-1 at index of 14650.
	Max RelError of 1.0000000000000000e+0 at index of 14650.
` 
```
assert_true: expected true got false
```
</span></li></ul></li></ul></details></div></span>
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-05-27T22:43:33Z
body: ✨ Try run ([#15286872580](https://github.com/servo/servo/actions/runs/15286872580)) succeeded.
author_association: NONE
user: login: tharkum
created_at: 2025-05-28T04:06:38Z
body: @jdm < May be I found root case of this suspicious CRASH (happened only on first WPT run) - https://github.com/servo/servo/issues/37161
author_association: CONTRIBUTOR
user: login: tharkum
created_at: 2025-05-28T04:25:03Z
body: - Rebased on top of `main` branch
author_association: CONTRIBUTOR
user: login: jdm
created_at: 2025-05-28T04:55:05Z
body: I'm surprised that there was no change in result for the tests with cross-origin redirects. I'll try to step through one of those tomorrow to figure out what's going wrong.
author_association: MEMBER
user: login: tharkum
created_at: 2025-05-28T05:27:27Z
body: > I'm surprised that there was no change in result for the tests with cross-origin redirects. I'll try to step through one of those tomorrow to figure out what's going wrong.

Actually change for croos-origin redirects is working, but test results are blocked by media rendering issue.
Some initial frames from media pipeline decoder come to us before we are ready to accept them (discards all of them) because `show_poster` flag is enabled.

https://github.com/servo/servo/blob/2d3a7c87c2887d851eddc36ce760771ae3e861df/components/script/dom/htmlmediaelement.rs#L204

After we will be ready to accept new media frames, media decoder doesn't send to us anything (media renderer current frame is empty), so on createPattern() we have `InvalidStateError` exception
and haven't possibility to test canvas against origin clean state.

If you comment this check the cross-origin redirects tests will be passed.
author_association: CONTRIBUTOR