CVE-2026-43700
Overview
Impact:
Description: Processing maliciously crafted web content may disclose sensitive user information
Researchers: Vitaly Simonovich, Muhamad Syaiful, Christian Meurer Xavier
Key insight. importExternalTexture enforced the cross-origin video taint check on only some paths; adding it to the reused-external-texture fast path and the main path closes the remaining SOP holes.
Patch Details
diff --git a/LayoutTests/fast/webgpu/regression/repro_315368-expected.txt b/LayoutTests/fast/webgpu/regression/repro_315368-expected.txt
new file mode 100644
index 000000000000..f3f8a6a97a34
--- /dev/null
+++ b/LayoutTests/fast/webgpu/regression/repro_315368-expected.txt
@@ -0,0 +1,2 @@
+CONSOLE MESSAGE: Pass
+
diff --git a/LayoutTests/fast/webgpu/regression/repro_315368.html b/LayoutTests/fast/webgpu/regression/repro_315368.html
new file mode 100644
index 000000000000..cecbedb144ce
--- /dev/null
+++ b/LayoutTests/fast/webgpu/regression/repro_315368.html
@@ -0,0 +1,29 @@
+<script>
+ globalThis.testRunner?.waitUntilDone();
+ const log = console.debug;
+
+ const veryBrightVideo = `data:video/mp4;base64,AAAAHGZ0eXBpc29tAAACAGlzb21pc28ybXA0MQAAAAhmcmVlAAAAvG1kYXQAAAAfTgEFGkdWStxcTEM/lO/FETzRQ6gD7gAA7gIAA3EYgAAAAEgoAa8iNjAkszOL+e58c//cEe//0TT//scp1n/381P/RWP/zOW4QtxorfVogeh8nQDbQAAAAwAQMCcWUTAAAAMAAAMAAAMA84AAAAAVAgHQAyu+KT35E7gAADFgAAADABLQAAAAEgIB4AiS76MTkNbgAAF3AAAPSAAAABICAeAEn8+hBOTXYAADUgAAHRAAAAPibW9vdgAAAGxtdmhkAAAAAAAAAAAAAAAAAAAD6AAAAKcAAQAAAQAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAw10cmFrAAAAXHRraGQAAAADAAAAAAAAAAAAAAABAAAAAAAAAKcAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAABAAAAAABAAAAAQAAAAAAAkZWR0cwAAABxlbHN0AAAAAAAAAAEAAACnAAAAAAABAAAAAAKFbWRpYQAAACBtZGhkAAAAAAAAAAAAAAAAAABdwAAAD6BVxAAAAAAAMWhkbHIAAAAAAAAAAHZpZGUAAAAAAAAAAAAAAABDb3JlIE1lZGlhIFZpZGVvAAAAAixtaW5mAAAAFHZtaGQAAAABAAAAAAAAAAAAAAAkZGluZgAAABxkcmVmAAAAAAAAAAEAAAAMdXJsIAAAAAEAAAHsc3RibAAAARxzdHNkAAAAAAAAAAEAAAEMaHZjMQAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAQABAASAAAAEgAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABj//wAAAHVodmNDAQIgAAAAsAAAAAAAPPAA/P36+gAACwOgAAEAGEABDAH//wIgAAADALAAAAMAAAMAPBXAkKEAAQAmQgEBAiAAAAMAsAAAAwAAAwA8oBQgQcCTDLYgV7kWVYC1CRAJAICiAAEACUQBwChkuNBTJAAAAApmaWVsAQAAAAATY29scm5jbHgACQAQAAkAAAAAEHBhc3AAAAABAAAAAQAAABRidHJ0AAAAAAAALPwAACz8AAAAKHN0dHMAAAAAAAAAAwAAAAIAAAPoAAAAAQAAAAEAAAABAAAD6AAAABRzdHNzAAAAAAAAAAEAAAABAAAAEHNkdHAAAAAAIBAQGAAAAChjdHRzAAAAAAAAAAMAAAABAAAAAAAAAAEAAAfQAAAAAgAAAAAAAAAcc3RzYwAAAAAAAAABAAAAAQAAAAQAAAABAAAAJHN0c3oAAAAAAAAAAAAAAAQAAABvAAAAGQAAABYAAAAWAAAAFHN0Y28AAAAAAAAAAQAAACwAAABhdWR0YQAAAFltZXRhAAAAAAAAACFoZGxyAAAAAAAAAABtZGlyYXBwbAAAAAAAAAAAAAAAACxpbHN0AAAAJKl0b28AAAAcZGF0YQAAAAEAAAAATGF2ZjYwLjMuMTAw`;
+
+ // Tests the new texture path in importExternalTexture: first import of a same-origin video
+ // element exercises the code path that creates a new GPUExternalTexture (bug 315368).
+ onload = async () => {
+ let adapter = await navigator.gpu.requestAdapter({});
+ let device = await adapter.requestDevice({});
+
+ let video = document.createElement('video');
+ video.src = veryBrightVideo;
+ video.muted = true;
+ await new Promise(resolve => { video.onloadeddata = () => { video.play(); resolve(); }; });
+
+ video.requestVideoFrameCallback(() => {
+ try {
+ device.importExternalTexture({source: video});
+ log('Pass');
+ } catch (e) {
+ log('FAIL: ' + e.message);
+ }
+ globalThis.testRunner?.dumpAsText();
+ globalThis.testRunner?.notifyDone();
+ });
+ };
+</script>
diff --git a/LayoutTests/fast/webgpu/regression/repro_315368b-expected.txt b/LayoutTests/fast/webgpu/regression/repro_315368b-expected.txt
new file mode 100644
index 000000000000..f3f8a6a97a34
--- /dev/null
+++ b/LayoutTests/fast/webgpu/regression/repro_315368b-expected.txt
@@ -0,0 +1,2 @@
+CONSOLE MESSAGE: Pass
+
diff --git a/LayoutTests/fast/webgpu/regression/repro_315368b.html b/LayoutTests/fast/webgpu/regression/repro_315368b.html
new file mode 100644
index 000000000000..b5efaa958908
--- /dev/null
+++ b/LayoutTests/fast/webgpu/regression/repro_315368b.html
@@ -0,0 +1,31 @@
+<script>
+ globalThis.testRunner?.waitUntilDone();
+ const log = console.debug;
+
+ const veryBrightVideo = `data:video/mp4;base64,AAAAHGZ0eXBpc29tAAACAGlzb21pc28ybXA0MQAAAAhmcmVlAAAAvG1kYXQAAAAfTgEFGkdWStxcTEM/lO/FETzRQ6gD7gAA7gIAA3EYgAAAAEgoAa8iNjAkszOL+e58c//cEe//0TT//scp1n/381P/RWP/zOW4QtxorfVogeh8nQDbQAAAAwAQMCcWUTAAAAMAAAMAAAMA84AAAAAVAgHQAyu+KT35E7gAADFgAAADABLQAAAAEgIB4AiS76MTkNbgAAF3AAAPSAAAABICAeAEn8+hBOTXYAADUgAAHRAAAAPibW9vdgAAAGxtdmhkAAAAAAAAAAAAAAAAAAAD6AAAAKcAAQAAAQAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAw10cmFrAAAAXHRraGQAAAADAAAAAAAAAAAAAAABAAAAAAAAAKcAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAABAAAAAABAAAAAQAAAAAAAkZWR0cwAAABxlbHN0AAAAAAAAAAEAAACnAAAAAAABAAAAAAKFbWRpYQAAACBtZGhkAAAAAAAAAAAAAAAAAABdwAAAD6BVxAAAAAAAMWhkbHIAAAAAAAAAAHZpZGUAAAAAAAAAAAAAAABDb3JlIE1lZGlhIFZpZGVvAAAAAixtaW5mAAAAFHZtaGQAAAABAAAAAAAAAAAAAAAkZGluZgAAABxkcmVmAAAAAAAAAAEAAAAMdXJsIAAAAAEAAAHsc3RibAAAARxzdHNkAAAAAAAAAAEAAAEMaHZjMQAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAQABAASAAAAEgAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABj//wAAAHVodmNDAQIgAAAAsAAAAAAAPPAA/P36+gAACwOgAAEAGEABDAH//wIgAAADALAAAAMAAAMAPBXAkKEAAQAmQgEBAiAAAAMAsAAAAwAAAwA8oBQgQcCTDLYgV7kWVYC1CRAJAICiAAEACUQBwChkuNBTJAAAAApmaWVsAQAAAAATY29scm5jbHgACQAQAAkAAAAAEHBhc3AAAAABAAAAAQAAABRidHJ0AAAAAAAALPwAACz8AAAAKHN0dHMAAAAAAAAAAwAAAAIAAAPoAAAAAQAAAAEAAAABAAAD6AAAABRzdHNzAAAAAAAAAAEAAAABAAAAEHNkdHAAAAAAIBAQGAAAAChjdHRzAAAAAAAAAAMAAAABAAAAAAAAAAEAAAfQAAAAAgAAAAAAAAAcc3RzYwAAAAAAAAABAAAAAQAAAAQAAAABAAAAJHN0c3oAAAAAAAAAAAAAAAQAAABvAAAAGQAAABYAAAAWAAAAFHN0Y28AAAAAAAAAAQAAACwAAABhdWR0YQAAAFltZXRhAAAAAAAAACFoZGxyAAAAAAAAAABtZGlyYXBwbAAAAAAAAAAAAAAAACxpbHN0AAAAJKl0b28AAAAcZGF0YQAAAAEAAAAATGF2ZjYwLjMuMTAw`;
+
+ // Tests the cached texture path in importExternalTexture: a second synchronous import of the
+ // same same-origin video element exercises the early-return path that reuses a cached
+ // GPUExternalTexture (bug 315368, PLATFORM(COCOA) only).
+ onload = async () => {
+ let adapter = await navigator.gpu.requestAdapter({});
+ let device = await adapter.requestDevice({});
+
+ let video = document.createElement('video');
+ video.src = veryBrightVideo;
+ video.muted = true;
+ await new Promise(resolve => { video.onloadeddata = () => { video.play(); resolve(); }; });
+
+ video.requestVideoFrameCallback(() => {
+ try {
+ let et1 = device.importExternalTexture({source: video}); // new texture path
+ let et2 = device.importExternalTexture({source: video}); // cached texture path (Cocoa)
+ log('Pass');
+ } catch (e) {
+ log('FAIL: ' + e.message);
+ }
+ globalThis.testRunner?.dumpAsText();
+ globalThis.testRunner?.notifyDone();
+ });
+ };
+</script>
diff --git a/Source/WebCore/Modules/WebGPU/GPUDevice.cpp b/Source/WebCore/Modules/WebGPU/GPUDevice.cpp
index add1e02b8303..3d03ba423a61 100644
--- a/Source/WebCore/Modules/WebGPU/GPUDevice.cpp
+++ b/Source/WebCore/Modules/WebGPU/GPUDevice.cpp
@@ -74,6 +74,7 @@
#include "JSGPUUncapturedErrorEvent.h"
#include "JSGPUValidationError.h"
#include "RequestAnimationFrameCallback.h"
+#include "SecurityOrigin.h"
#include "WebGPUXRBinding.h"
#include "XRGPUBinding.h"
#include <wtf/TZoneMallocInlines.h>
@@ -394,6 +395,15 @@ private:
ExceptionOr<Ref<GPUExternalTexture>> GPUDevice::importExternalTexture(GPUExternalTextureDescriptor&& externalTextureDescriptor)
{
+#if ENABLE(VIDEO)
+ auto checkVideoElementOriginTaint = [this](const HTMLVideoElement& videoElement) -> std::optional<Exception> {
+ RefPtr context = scriptExecutionContext();
+ if (RefPtr securityOrigin = context ? context->securityOrigin() : nullptr; securityOrigin && videoElement.taintsOrigin(*securityOrigin))
+ return Exception { ExceptionCode::SecurityError, "GPUDevice.importExternalTexture: Cross origin external videos are not allowed in WebGPU"_s };
+ return std::nullopt;
+ };
+#endif
+
#if ENABLE(VIDEO) && PLATFORM(COCOA)
if (RefPtr externalTexture = externalTextureForDescriptor(externalTextureDescriptor)) {
externalTexture->undestroy();
@@ -402,6 +412,9 @@ ExceptionOr<Ref<GPUExternalTexture>> GPUDevice::importExternalTexture(GPUExterna
#else
Ref videoElementRef = externalTextureDescriptor.source;
#endif
+ if (auto exception = checkVideoElementOriginTaint(videoElementRef))
+ return WTF::move(*exception);
+
m_videoElementToExternalTextureMap.remove(videoElementRef);
if (auto optionalMediaIdentifier = externalTextureDescriptor.mediaIdentifier()) {
m_backing->updateExternalTexture(externalTexture->backing(), *optionalMediaIdentifier);
@@ -425,6 +438,9 @@ ExceptionOr<Ref<GPUExternalTexture>> GPUDevice::importExternalTexture(GPUExterna
#else
Ref videoElementRef = externalTextureDescriptor.source;
#endif
+ if (auto exception = checkVideoElementOriginTaint(videoElementRef))
+ return WTF::move(*exception);
+
WeakPtr videoElementPtr = videoElementRef.ptr();
m_videoElementToExternalTextureMap.set(videoElementRef, externalTexture.get());
m_previouslyImportedExternalTexture.first = videoElementRef.ptr();
Background
Advisory: Apple Security Advisory
| Attribute | Value |
|---|---|
| CVE | CVE-2026-43700 |
| Bugzilla | 315368 |
| Component | WebCore |
| Bug Class | CrossOrigin |
| Severity | medium |
| Commit | 67b563b85f480c70… |
| Advisory | Apple Advisory |
Terminology
- importExternalTexture — A WebGPU API ingesting HTMLVideoElement frames as a texture that shaders can sample and read back.
- Origin taint / taintsOrigin — Cross-origin non-CORS media is tainted; its pixels must not be readable, as canvas enforces.
- External-texture reuse path — A Cocoa fast path that undestroys/reuses a previously-created external texture; it also needs the taint check.
Root Cause Analysis
This closes remaining cross-origin video paths in WebGPU’s importExternalTexture that were not covered by the origin-taint check, defeating the Same-Origin Policy for video pixels. GPUDevice::importExternalTexture ingests an HTMLVideoElement’s frames as a WebGPU external texture that a shader can sample and read back. To respect the SOP (as canvas does by tainting), an origin-taint check must reject a cross-origin, non-CORS video before it enters the pipeline. Pre-patch, importExternalTexture had paths that imported the video WITHOUT that check — notably the Cocoa fast path that reuses/undestroys a previously-created external texture (externalTextureForDescriptor) and the main import path. The fix adds a checkVideoElementOriginTaint lambda that fetches the caller’s security origin from scriptExecutionContext()->securityOrigin() and, if videoElement.taintsOrigin(securityOrigin), returns a SecurityError (‘Cross origin external videos are not allowed in WebGPU’); it invokes this check on BOTH the reused-external-texture path and the main path before importing. The restored invariant is that a cross-origin tainted video cannot enter (or be reused in) a WebGPU external texture through any importExternalTexture path, so its pixels cannot be sampled and exfiltrated. This is an information-disclosure fix, not memory corruption.
Attack Path
1. Load a cross-origin video
Load a cross-origin video without CORS so it is origin-tainted.
2. Import it as an external texture
Call GPUDevice.importExternalTexture on the tainted video, hitting a path that lacked the taint check (e.g. the reused-texture fast path).
3. Sample and read back
Sample the external texture in a shader and read the result into a GPU buffer readable by script.
4. Exfiltrate cross-origin pixels
Recover the cross-origin video’s pixels, defeating the Same-Origin Policy.
Impact Assessment
A cross-origin information disclosure in the WebContent process defeating the Same-Origin Policy for video: uncovered importExternalTexture paths let a page read pixels of a cross-origin video. No memory corruption; the risk is exfiltration of cross-origin visual content (e.g. authenticated video), reliable and stealthy.
Audit Directions
All media-ingestion paths
Audit every importExternalTexture / external-texture reuse and update path (and WebGL video uploads) for a consistent taintsOrigin check.
Origin retrieval
Confirm each path obtains the caller’s security origin (scriptExecutionContext()->securityOrigin()) before importing media.
Changed Functions
| Function | File | Change | Note |
|---|---|---|---|
GPUDevice::importExternalTexture |
Source/WebCore/Modules/WebGPU/GPUDevice.cpp |
modified | Adds checkVideoElementOriginTaint (using scriptExecutionContext()->securityOrigin() and videoElement.taintsOrigin) and applies it on both the reused/undestroyed external-texture path and the main import path, rejecting cross-origin tainted video with a SecurityError. |
Files Changed
Source Files
Source/WebCore/Modules/WebGPU/GPUDevice.cpp
Test Files
LayoutTests/fast/webgpu/regression/repro_315368-expected.txtLayoutTests/fast/webgpu/regression/repro_315368.htmlLayoutTests/fast/webgpu/regression/repro_315368b-expected.txtLayoutTests/fast/webgpu/regression/repro_315368b.html
Regression Test
The fix ships this proof-of-concept / regression test:
diff --git a/LayoutTests/fast/webgpu/regression/repro_315368-expected.txt b/LayoutTests/fast/webgpu/regression/repro_315368-expected.txt
new file mode 100644
index 000000000000..f3f8a6a97a34
--- /dev/null
+++ b/LayoutTests/fast/webgpu/regression/repro_315368-expected.txt
@@ -0,0 +1,2 @@
+CONSOLE MESSAGE: Pass
+
diff --git a/LayoutTests/fast/webgpu/regression/repro_315368.html b/LayoutTests/fast/webgpu/regression/repro_315368.html
new file mode 100644
index 000000000000..cecbedb144ce
--- /dev/null
+++ b/LayoutTests/fast/webgpu/regression/repro_315368.html
@@ -0,0 +1,29 @@
+<script>
+ globalThis.testRunner?.waitUntilDone();
+ const log = console.debug;
+
+ const veryBrightVideo = `data:video/mp4;base64,AAAAHGZ0eXBpc29tAAACAGlzb21pc28ybXA0MQAAAAhmcmVlAAAAvG1kYXQAAAAfTgEFGkdWStxcTEM/lO/FETzRQ6gD7gAA7gIAA3EYgAAAAEgoAa8iNjAkszOL+e58c//cEe//0TT//scp1n/381P/RWP/zOW4QtxorfVogeh8nQDbQAAAAwAQMCcWUTAAAAMAAAMAAAMA84AAAAAVAgHQAyu+KT35E7gAADFgAAADABLQAAAAEgIB4AiS76MTkNbgAAF3AAAPSAAAABICAeAEn8+hBOTXYAADUgAAHRAAAAPibW9vdgAAAGxtdmhkAAAAAAAAAAAAAAAAAAAD6AAAAKcAAQAAAQAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAw10cmFrAAAAXHRraGQAAAADAAAAAAAAAAAAAAABAAAAAAAAAKcAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAABAAAAAABAAAAAQAAAAAAAkZWR0cwAAABxlbHN0AAAAAAAAAAEAAACnAAAAAAABAAAAAAKFbWRpYQAAACBtZGhkAAAAAAAAAAAAAAAAAABdwAAAD6BVxAAAAAAAMWhkbHIAAAAAAAAAAHZpZGUAAAAAAAAAAAAAAABDb3JlIE1lZGlhIFZpZGVvAAAAAixtaW5mAAAAFHZtaGQAAAABAAAAAAAAAAAAAAAkZGluZgAAABxkcmVmAAAAAAAAAAEAAAAMdXJsIAAAAAEAAAHsc3RibAAAARxzdHNkAAAAAAAAAAEAAAEMaHZjMQAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAQABAASAAAAEgAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABj//wAAAHVodmNDAQIgAAAAsAAAAAAAPPAA/P36+gAACwOgAAEAGEABDAH//wIgAAADALAAAAMAAAMAPBXAkKEAAQAmQgEBAiAAAAMAsAAAAwAAAwA8oBQgQcCTDLYgV7kWVYC1CRAJAICiAAEACUQBwChkuNBTJAAAAApmaWVsAQAAAAATY29scm5jbHgACQAQAAkAAAAAEHBhc3AAAAABAAAAAQAAABRidHJ0AAAAAAAALPwAACz8AAAAKHN0dHMAAAAAAAAAAwAAAAIAAAPoAAAAAQAAAAEAAAABAAAD6AAAABRzdHNzAAAAAAAAAAEAAAABAAAAEHNkdHAAAAAAIBAQGAAAAChjdHRzAAAAAAAAAAMAAAABAAAAAAAAAAEAAAfQAAAAAgAAAAAAAAAcc3RzYwAAAAAAAAABAAAAAQAAAAQAAAABAAAAJHN0c3oAAAAAAAAAAAAAAAQAAABvAAAAGQAAABYAAAAWAAAAFHN0Y28AAAAAAAAAAQAAACwAAABhdWR0YQAAAFltZXRhAAAAAAAAACFoZGxyAAAAAAAAAABtZGlyYXBwbAAAAAAAAAAAAAAAACxpbHN0AAAAJKl0b28AAAAcZGF0YQAAAAEAAAAATGF2ZjYwLjMuMTAw`;
+
+ // Tests the new texture path in importExternalTexture: first import of a same-origin video
+ // element exercises the code path that creates a new GPUExternalTexture (bug 315368).
+ onload = async () => {
+ let adapter = await navigator.gpu.requestAdapter({});
+ let device = await adapter.requestDevice({});
+
+ let video = document.createElement('video');
+ video.src = veryBrightVideo;
+ video.muted = true;
+ await new Promise(resolve => { video.onloadeddata = () => { video.play(); resolve(); }; });
+
+ video.requestVideoFrameCallback(() => {
+ try {
+ device.importExternalTexture({source: video});
+ log('Pass');
+ } catch (e) {
+ log('FAIL: ' + e.message);
+ }
+ globalThis.testRunner?.dumpAsText();
+ globalThis.testRunner?.notifyDone();
+ });
+ };
+</script>
diff --git a/LayoutTests/fast/webgpu/regression/repro_315368b-expected.txt b/LayoutTests/fast/webgpu/regression/repro_315368b-expected.txt
new file mode 100644
index 000000000000..f3f8a6a97a34
--- /dev/null
+++ b/LayoutTests/fast/webgpu/regression/repro_315368b-expected.txt
@@ -0,0 +1,2 @@
+CONSOLE MESSAGE: Pass
+
diff --git a/LayoutTests/fast/webgpu/regression/repro_315368b.html b/LayoutTests/fast/webgpu/regression/repro_315368b.html
new file mode 100644
index 000000000000..b5efaa958908
--- /dev/null
+++ b/LayoutTests/fast/webgpu/regression/repro_315368b.html
@@ -0,0 +1,31 @@
+<script>
+ globalThis.testRunner?.waitUntilDone();
+ const log = console.debug;
+
+ const veryBrightVideo = `data:video/mp4;base64,AAAAHGZ0eXBpc29tAAACAGlzb21pc28ybXA0MQAAAAhmcmVlAAAAvG1kYXQAAAAfTgEFGkdWStxcTEM/lO/FETzRQ6gD7gAA7gIAA3EYgAAAAEgoAa8iNjAkszOL+e58c//cEe//0TT//scp1n/381P/RWP/zOW4QtxorfVogeh8nQDbQAAAAwAQMCcWUTAAAAMAAAMAAAMA84AAAAAVAgHQAyu+KT35E7gAADFgAAADABLQAAAAEgIB4AiS76MTkNbgAAF3AAAPSAAAABICAeAEn8+hBOTXYAADUgAAHRAAAAPibW9vdgAAAGxtdmhkAAAAAAAAAAAAAAAAAAAD6AAAAKcAAQAAAQAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAw10cmFrAAAAXHRraGQAAAADAAAAAAAAAAAAAAABAAAAAAAAAKcAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAABAAAAAABAAAAAQAAAAAAAkZWR0cwAAABxlbHN0AAAAAAAAAAEAAACnAAAAAAABAAAAAAKFbWRpYQAAACBtZGhkAAAAAAAAAAAAAAAAAABdwAAAD6BVxAAAAAAAMWhkbHIAAAAAAAAAAHZpZGUAAAAAAAAAAAAAAABDb3JlIE1lZGlhIFZpZGVvAAAAAixtaW5mAAAAFHZtaGQAAAABAAAAAAAAAAAAAAAkZGluZgAAABxkcmVmAAAAAAAAAAEAAAAMdXJsIAAAAAEAAAHsc3RibAAAARxzdHNkAAAAAAAAAAEAAAEMaHZjMQAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAQABAASAAAAEgAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABj//wAAAHVodmNDAQIgAAAAsAAAAAAAPPAA/P36+gAACwOgAAEAGEABDAH//wIgAAADALAAAAMAAAMAPBXAkKEAAQAmQgEBAiAAAAMAsAAAAwAAAwA8oBQgQcCTDLYgV7kWVYC1CRAJAICiAAEACUQBwChkuNBTJAAAAApmaWVsAQAAAAATY29scm5jbHgACQAQAAkAAAAAEHBhc3AAAAABAAAAAQAAABRidHJ0AAAAAAAALPwAACz8AAAAKHN0dHMAAAAAAAAAAwAAAAIAAAPoAAAAAQAAAAEAAAABAAAD6AAAABRzdHNzAAAAAAAAAAEAAAABAAAAEHNkdHAAAAAAIBAQGAAAAChjdHRzAAAAAAAAAAMAAAABAAAAAAAAAAEAAAfQAAAAAgAAAAAAAAAcc3RzYwAAAAAAAAABAAAAAQAAAAQAAAABAAAAJHN0c3oAAAAAAAAAAAAAAAQAAABvAAAAGQAAABYAAAAWAAAAFHN0Y28AAAAAAAAAAQAAACwAAABhdWR0YQAAAFltZXRhAAAAAAAAACFoZGxyAAAAAAAAAABtZGlyYXBwbAAAAAAAAAAAAAAAACxpbHN0AAAAJKl0b28AAAAcZGF0YQAAAAEAAAAATGF2ZjYwLjMuMTAw`;
+
+ // Tests the cached texture path in importExternalTexture: a second synchronous import of the
+ // same same-origin video element exercises the early-return path that reuses a cached
+ // GPUExternalTexture (bug 315368, PLATFORM(COCOA) only).
+ onload = async () => {
+ let adapter = await navigator.gpu.requestAdapter({});
+ let device = await adapter.requestDevice({});
+
+ let video = document.createElement('video');
+ video.src = veryBrightVideo;
+ video.muted = true;
+ await new Promise(resolve => { video.onloadeddata = () => { video.play(); resolve(); }; });
+
+ video.requestVideoFrameCallback(() => {
+ try {
+ let et1 = device.importExternalTexture({source: video}); // new texture path
+ let et2 = device.importExternalTexture({source: video}); // cached texture path (Cocoa)
+ log('Pass');
+ } catch (e) {
+ log('FAIL: ' + e.message);
+ }
+ globalThis.testRunner?.dumpAsText();
+ globalThis.testRunner?.notifyDone();
+ });
+ };
+</script>