aboutsummaryrefslogtreecommitdiffstats
path: root/components/script
diff options
context:
space:
mode:
Diffstat (limited to 'components/script')
-rw-r--r--components/script/Cargo.toml4
-rw-r--r--components/script/canvas_state.rs35
-rw-r--r--components/script/document_loader.rs2
-rw-r--r--components/script/dom/abstractworkerglobalscope.rs21
-rw-r--r--components/script/dom/audiocontext.rs16
-rw-r--r--components/script/dom/bindings/callback.rs6
-rw-r--r--components/script/dom/bindings/codegen/Bindings.conf5
-rw-r--r--components/script/dom/bindings/codegen/CodegenRust.py83
-rw-r--r--components/script/dom/bindings/conversions.rs23
-rw-r--r--components/script/dom/bindings/refcounted.rs2
-rw-r--r--components/script/dom/bindings/reflector.rs2
-rw-r--r--components/script/dom/bindings/root.rs12
-rw-r--r--components/script/dom/bindings/trace.rs31
-rw-r--r--components/script/dom/bindings/utils.rs62
-rw-r--r--components/script/dom/bindings/weakref.rs8
-rw-r--r--components/script/dom/blob.rs2
-rw-r--r--components/script/dom/bluetooth.rs32
-rw-r--r--components/script/dom/canvasrenderingcontext2d.rs28
-rw-r--r--components/script/dom/cssstyledeclaration.rs2
-rw-r--r--components/script/dom/customelementregistry.rs6
-rw-r--r--components/script/dom/dedicatedworkerglobalscope.rs63
-rw-r--r--components/script/dom/dissimilaroriginwindow.rs23
-rw-r--r--components/script/dom/document.rs129
-rw-r--r--components/script/dom/documentorshadowroot.rs4
-rw-r--r--components/script/dom/formdataevent.rs13
-rw-r--r--components/script/dom/globalscope.rs191
-rw-r--r--components/script/dom/gpu.rs161
-rw-r--r--components/script/dom/gpuadapter.rs63
-rw-r--r--components/script/dom/htmlcanvaselement.rs7
-rw-r--r--components/script/dom/htmliframeelement.rs78
-rw-r--r--components/script/dom/htmlimageelement.rs7
-rwxr-xr-xcomponents/script/dom/htmlinputelement.rs2
-rw-r--r--components/script/dom/htmlmediaelement.rs134
-rw-r--r--components/script/dom/htmlvideoelement.rs6
-rw-r--r--components/script/dom/identityhub.rs47
-rw-r--r--components/script/dom/imagedata.rs14
-rw-r--r--components/script/dom/mediaelementaudiosourcenode.rs80
-rw-r--r--components/script/dom/mediametadata.rs97
-rw-r--r--components/script/dom/mediasession.rs213
-rw-r--r--components/script/dom/messageevent.rs79
-rw-r--r--components/script/dom/messageport.rs2
-rw-r--r--components/script/dom/mod.rs7
-rw-r--r--components/script/dom/navigator.rs39
-rw-r--r--components/script/dom/nodelist.rs4
-rw-r--r--components/script/dom/offscreencanvas.rs20
-rw-r--r--components/script/dom/offscreencanvasrenderingcontext2d.rs46
-rw-r--r--components/script/dom/paintrenderingcontext2d.rs3
-rw-r--r--components/script/dom/paintworkletglobalscope.rs2
-rw-r--r--components/script/dom/promise.rs2
-rw-r--r--components/script/dom/promiserejectionevent.rs11
-rw-r--r--components/script/dom/range.rs2
-rw-r--r--components/script/dom/raredata.rs4
-rw-r--r--components/script/dom/response.rs1
-rw-r--r--components/script/dom/serviceworker.rs2
-rw-r--r--components/script/dom/serviceworkerglobalscope.rs89
-rw-r--r--components/script/dom/servoparser/async_html.rs2
-rw-r--r--components/script/dom/servoparser/html.rs2
-rw-r--r--components/script/dom/servoparser/mod.rs4
-rw-r--r--components/script/dom/servoparser/prefetch.rs2
-rw-r--r--components/script/dom/servoparser/xml.rs2
-rw-r--r--components/script/dom/stylesheetlist.rs2
-rw-r--r--components/script/dom/trackevent.rs2
-rw-r--r--components/script/dom/url.rs16
-rw-r--r--components/script/dom/webgl2renderingcontext.rs601
-rw-r--r--components/script/dom/webgl_extensions/extensions.rs2
-rw-r--r--components/script/dom/webgl_extensions/wrapper.rs2
-rw-r--r--components/script/dom/webglframebuffer.rs2
-rw-r--r--components/script/dom/webglprogram.rs16
-rw-r--r--components/script/dom/webglrenderingcontext.rs33
-rw-r--r--components/script/dom/webgltransformfeedback.rs133
-rw-r--r--components/script/dom/webglvertexarrayobjectoes.rs2
-rw-r--r--components/script/dom/webidls/AudioContext.webidl2
-rw-r--r--components/script/dom/webidls/Bluetooth.webidl2
-rw-r--r--components/script/dom/webidls/BluetoothPermissionResult.webidl2
-rw-r--r--components/script/dom/webidls/DissimilarOriginWindow.webidl2
-rw-r--r--components/script/dom/webidls/FormDataEvent.webidl4
-rw-r--r--components/script/dom/webidls/GPU.webidl21
-rw-r--r--components/script/dom/webidls/GPUAdapter.webidl14
-rw-r--r--components/script/dom/webidls/HTMLIFrameElement.webidl4
-rw-r--r--components/script/dom/webidls/MediaElementAudioSourceNode.webidl17
-rw-r--r--components/script/dom/webidls/MediaMetadata.webidl30
-rw-r--r--components/script/dom/webidls/MediaSession.webidl57
-rw-r--r--components/script/dom/webidls/MessageEvent.webidl11
-rw-r--r--components/script/dom/webidls/MessagePort.webidl4
-rw-r--r--components/script/dom/webidls/Navigator.webidl5
-rw-r--r--components/script/dom/webidls/PromiseRejectionEvent.webidl4
-rw-r--r--components/script/dom/webidls/WebGL2RenderingContext.webidl15
-rw-r--r--components/script/dom/webidls/WebGLTransformFeedback.webidl11
-rw-r--r--components/script/dom/webidls/Window.webidl5
-rw-r--r--components/script/dom/webidls/WindowOrWorkerGlobalScope.webidl11
-rw-r--r--components/script/dom/webidls/WorkerNavigator.webidl5
-rw-r--r--components/script/dom/webidls/XRSession.webidl3
-rw-r--r--components/script/dom/window.rs124
-rw-r--r--components/script/dom/worker.rs2
-rw-r--r--components/script/dom/workerglobalscope.rs63
-rw-r--r--components/script/dom/workernavigator.rs8
-rw-r--r--components/script/dom/worklet.rs4
-rw-r--r--components/script/dom/workletglobalscope.rs4
-rw-r--r--components/script/dom/xrsession.rs30
-rw-r--r--components/script/euclidext.rs43
-rw-r--r--components/script/init.rs5
-rw-r--r--components/script/lib.rs5
-rw-r--r--components/script/script_runtime.rs196
-rw-r--r--components/script/script_thread.rs174
-rw-r--r--components/script/serviceworkerjob.rs4
-rw-r--r--components/script/task_manager.rs13
-rw-r--r--components/script/task_source/mod.rs2
-rw-r--r--components/script/task_source/timer.rs42
-rw-r--r--components/script/timers.rs25
109 files changed, 3054 insertions, 769 deletions
diff --git a/components/script/Cargo.toml b/components/script/Cargo.toml
index 23873d59767..d7032f290e0 100644
--- a/components/script/Cargo.toml
+++ b/components/script/Cargo.toml
@@ -91,6 +91,7 @@ script_plugins = {path = "../script_plugins"}
script_traits = {path = "../script_traits"}
selectors = { path = "../selectors" }
serde = {version = "1", features = ["derive"]}
+serde_bytes = "0.11"
servo_allocator = {path = "../allocator"}
servo_arc = {path = "../servo_arc"}
servo_atoms = {path = "../atoms"}
@@ -112,7 +113,8 @@ utf-8 = "0.7"
uuid = {version = "0.8", features = ["v4"]}
xml5ever = "0.16"
webdriver = "0.40"
-webrender_api = {git = "https://github.com/servo/webrender", features = ["ipc"]}
+webgpu = {path = "../webgpu"}
+webrender_api = {git = "https://github.com/servo/webrender"}
webvr_traits = {path = "../webvr_traits"}
webxr-api = {git = "https://github.com/servo/webxr", features = ["ipc"]}
diff --git a/components/script/canvas_state.rs b/components/script/canvas_state.rs
index 90630fb07c3..7c9ad232f30 100644
--- a/components/script/canvas_state.rs
+++ b/components/script/canvas_state.rs
@@ -24,6 +24,7 @@ use crate::dom::imagedata::ImageData;
use crate::dom::node::{Node, NodeDamage};
use crate::dom::paintworkletglobalscope::PaintWorkletGlobalScope;
use crate::dom::textmetrics::TextMetrics;
+use crate::euclidext::Size2DExt;
use crate::unpremultiplytable::UNPREMULTIPLY_TABLE;
use canvas_traits::canvas::{Canvas2dMsg, CanvasId, CanvasMsg};
use canvas_traits::canvas::{CompositionOrBlending, FillOrStrokeStyle, FillRule};
@@ -46,13 +47,14 @@ use net_traits::request::CorsSettings;
use pixels::PixelFormat;
use profile_traits::ipc as profiled_ipc;
use script_traits::ScriptMsg;
+use serde_bytes::ByteBuf;
use servo_url::{ImmutableOrigin, ServoUrl};
use std::cell::Cell;
use std::fmt;
use std::str::FromStr;
use std::sync::Arc;
-#[must_root]
+#[unrooted_must_root_lint::must_root]
#[derive(Clone, JSTraceable, MallocSizeOf)]
#[allow(dead_code)]
pub(crate) enum CanvasFillOrStrokeStyle {
@@ -61,7 +63,7 @@ pub(crate) enum CanvasFillOrStrokeStyle {
Pattern(Dom<CanvasPattern>),
}
-#[must_root]
+#[unrooted_must_root_lint::must_root]
#[derive(Clone, JSTraceable, MallocSizeOf)]
pub(crate) struct CanvasContextState {
global_alpha: f64,
@@ -102,7 +104,7 @@ impl CanvasContextState {
}
}
-#[must_root]
+#[unrooted_must_root_lint::must_root]
#[derive(JSTraceable, MallocSizeOf)]
pub(crate) struct CanvasState {
#[ignore_malloc_size_of = "Defined in ipc-channel"]
@@ -180,6 +182,19 @@ impl CanvasState {
.unwrap()
}
+ // https://html.spec.whatwg.org/multipage/#concept-canvas-set-bitmap-dimensions
+ pub fn set_bitmap_dimensions(&self, size: Size2D<u64>) {
+ self.reset_to_initial_state();
+ self.ipc_renderer
+ .send(CanvasMsg::Recreate(size, self.get_canvas_id()))
+ .unwrap();
+ }
+
+ pub fn reset_to_initial_state(&self) {
+ self.saved_states.borrow_mut().clear();
+ *self.state.borrow_mut() = CanvasContextState::new();
+ }
+
fn create_drawable_rect(&self, x: f64, y: f64, w: f64, h: f64) -> Option<Rect<f32>> {
if !([x, y, w, h].iter().all(|val| val.is_finite())) {
return None;
@@ -300,7 +315,7 @@ impl CanvasState {
}
}
- pub fn get_rect(&self, canvas_size: Size2D<u32>, rect: Rect<u32>) -> Vec<u8> {
+ pub fn get_rect(&self, canvas_size: Size2D<u64>, rect: Rect<u64>) -> Vec<u8> {
assert!(self.origin_is_clean());
assert!(Rect::from_size(canvas_size).contains_rect(&rect));
@@ -491,7 +506,7 @@ impl CanvasState {
let smoothing_enabled = self.state.borrow().image_smoothing_enabled;
self.send_canvas_2d_msg(Canvas2dMsg::DrawImage(
- Some(image_data.into()),
+ Some(ByteBuf::from(image_data)),
image_size,
dest_rect,
source_rect,
@@ -1019,7 +1034,7 @@ impl CanvasState {
// https://html.spec.whatwg.org/multipage/#dom-context-2d-getimagedata
pub fn get_image_data(
&self,
- canvas_size: Size2D<u32>,
+ canvas_size: Size2D<u64>,
global: &GlobalScope,
sx: i32,
sy: i32,
@@ -1038,7 +1053,7 @@ impl CanvasState {
}
let (origin, size) = adjust_size_sign(Point2D::new(sx, sy), Size2D::new(sw, sh));
- let read_rect = match pixels::clip(origin, size, canvas_size) {
+ let read_rect = match pixels::clip(origin, size.to_u64(), canvas_size) {
Some(rect) => rect,
None => {
// All the pixels are outside the canvas surface.
@@ -1057,7 +1072,7 @@ impl CanvasState {
// https://html.spec.whatwg.org/multipage/#dom-context-2d-putimagedata
pub fn put_image_data(
&self,
- canvas_size: Size2D<u32>,
+ canvas_size: Size2D<u64>,
imagedata: &ImageData,
dx: i32,
dy: i32,
@@ -1078,7 +1093,7 @@ impl CanvasState {
#[allow(unsafe_code)]
pub fn put_image_data_(
&self,
- canvas_size: Size2D<u32>,
+ canvas_size: Size2D<u64>,
imagedata: &ImageData,
dx: i32,
dy: i32,
@@ -1106,7 +1121,7 @@ impl CanvasState {
Point2D::new(dirty_x, dirty_y),
Size2D::new(dirty_width, dirty_height),
);
- let src_rect = match pixels::clip(src_origin, src_size, imagedata_size) {
+ let src_rect = match pixels::clip(src_origin, src_size.to_u64(), imagedata_size.to_u64()) {
Some(rect) => rect,
None => return,
};
diff --git a/components/script/document_loader.rs b/components/script/document_loader.rs
index ef60cbc2a6c..9e103b91380 100644
--- a/components/script/document_loader.rs
+++ b/components/script/document_loader.rs
@@ -29,7 +29,7 @@ pub enum LoadType {
/// created via DocumentLoader::fetch_async) are always removed by the time
/// that the owner is destroyed.
#[derive(JSTraceable, MallocSizeOf)]
-#[must_root]
+#[unrooted_must_root_lint::must_root]
pub struct LoadBlocker {
/// The document whose load event is blocked by this object existing.
doc: Dom<Document>,
diff --git a/components/script/dom/abstractworkerglobalscope.rs b/components/script/dom/abstractworkerglobalscope.rs
index e8e41375b70..d5186f91845 100644
--- a/components/script/dom/abstractworkerglobalscope.rs
+++ b/components/script/dom/abstractworkerglobalscope.rs
@@ -81,32 +81,27 @@ impl ScriptPort for Receiver<DedicatedWorkerScriptMsg> {
}
pub trait WorkerEventLoopMethods {
- type TimerMsg: Send;
type WorkerMsg: QueuedTaskConversion + Send;
type Event;
- fn timer_event_port(&self) -> &Receiver<Self::TimerMsg>;
fn task_queue(&self) -> &TaskQueue<Self::WorkerMsg>;
fn handle_event(&self, event: Self::Event);
fn handle_worker_post_event(&self, worker: &TrustedWorkerAddress) -> Option<AutoWorkerReset>;
fn from_worker_msg(&self, msg: Self::WorkerMsg) -> Self::Event;
- fn from_timer_msg(&self, msg: Self::TimerMsg) -> Self::Event;
fn from_devtools_msg(&self, msg: DevtoolScriptControlMsg) -> Self::Event;
}
// https://html.spec.whatwg.org/multipage/#worker-event-loop
-pub fn run_worker_event_loop<T, TimerMsg, WorkerMsg, Event>(
+pub fn run_worker_event_loop<T, WorkerMsg, Event>(
worker_scope: &T,
worker: Option<&TrustedWorkerAddress>,
) where
- TimerMsg: Send,
WorkerMsg: QueuedTaskConversion + Send,
- T: WorkerEventLoopMethods<TimerMsg = TimerMsg, WorkerMsg = WorkerMsg, Event = Event>
+ T: WorkerEventLoopMethods<WorkerMsg = WorkerMsg, Event = Event>
+ DerivedFrom<WorkerGlobalScope>
+ DerivedFrom<GlobalScope>
+ DomObject,
{
let scope = worker_scope.upcast::<WorkerGlobalScope>();
- let timer_event_port = worker_scope.timer_event_port();
let devtools_port = match scope.from_devtools_sender() {
Some(_) => Some(scope.from_devtools_receiver()),
None => None,
@@ -117,7 +112,6 @@ pub fn run_worker_event_loop<T, TimerMsg, WorkerMsg, Event>(
task_queue.take_tasks(msg.unwrap());
worker_scope.from_worker_msg(task_queue.recv().unwrap())
},
- recv(timer_event_port) -> msg => worker_scope.from_timer_msg(msg.unwrap()),
recv(devtools_port.unwrap_or(&crossbeam_channel::never())) -> msg =>
worker_scope.from_devtools_msg(msg.unwrap()),
};
@@ -132,13 +126,10 @@ pub fn run_worker_event_loop<T, TimerMsg, WorkerMsg, Event>(
// Batch all events that are ready.
// The task queue will throttle non-priority tasks if necessary.
match task_queue.try_recv() {
- Err(_) => match timer_event_port.try_recv() {
- Err(_) => match devtools_port.map(|port| port.try_recv()) {
- None => {},
- Some(Err(_)) => break,
- Some(Ok(ev)) => sequential.push(worker_scope.from_devtools_msg(ev)),
- },
- Ok(ev) => sequential.push(worker_scope.from_timer_msg(ev)),
+ Err(_) => match devtools_port.map(|port| port.try_recv()) {
+ None => {},
+ Some(Err(_)) => break,
+ Some(Ok(ev)) => sequential.push(worker_scope.from_devtools_msg(ev)),
},
Ok(ev) => sequential.push(worker_scope.from_worker_msg(ev)),
}
diff --git a/components/script/dom/audiocontext.rs b/components/script/dom/audiocontext.rs
index 2b6f04b421b..0212cb78ffa 100644
--- a/components/script/dom/audiocontext.rs
+++ b/components/script/dom/audiocontext.rs
@@ -20,6 +20,8 @@ use crate::dom::bindings::num::Finite;
use crate::dom::bindings::refcounted::{Trusted, TrustedPromise};
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
use crate::dom::bindings::root::DomRoot;
+use crate::dom::htmlmediaelement::HTMLMediaElement;
+use crate::dom::mediaelementaudiosourcenode::MediaElementAudioSourceNode;
use crate::dom::promise::Promise;
use crate::dom::window::Window;
use crate::task_source::TaskSource;
@@ -97,6 +99,10 @@ impl AudioContext {
self.context.resume();
}
}
+
+ pub fn base(&self) -> DomRoot<BaseAudioContext> {
+ DomRoot::from_ref(&self.context)
+ }
}
impl AudioContextMethods for AudioContext {
@@ -240,6 +246,16 @@ impl AudioContextMethods for AudioContext {
// Step 6.
promise
}
+
+ /// https://webaudio.github.io/web-audio-api/#dom-audiocontext-createmediaelementsource
+ fn CreateMediaElementSource(
+ &self,
+ media_element: &HTMLMediaElement,
+ ) -> Fallible<DomRoot<MediaElementAudioSourceNode>> {
+ let global = self.global();
+ let window = global.as_window();
+ MediaElementAudioSourceNode::new(window, self, media_element)
+ }
}
impl From<AudioContextLatencyCategory> for LatencyCategory {
diff --git a/components/script/dom/bindings/callback.rs b/components/script/dom/bindings/callback.rs
index 6059d75605a..fe6b8d36d39 100644
--- a/components/script/dom/bindings/callback.rs
+++ b/components/script/dom/bindings/callback.rs
@@ -40,7 +40,7 @@ pub enum ExceptionHandling {
/// A common base class for representing IDL callback function and
/// callback interface types.
#[derive(JSTraceable)]
-#[must_root]
+#[unrooted_must_root_lint::must_root]
pub struct CallbackObject {
/// The underlying `JSObject`.
callback: Heap<*mut JSObject>,
@@ -131,7 +131,7 @@ pub trait CallbackContainer {
/// A common base class for representing IDL callback function types.
#[derive(JSTraceable, PartialEq)]
-#[must_root]
+#[unrooted_must_root_lint::must_root]
pub struct CallbackFunction {
object: CallbackObject,
}
@@ -159,7 +159,7 @@ impl CallbackFunction {
/// A common base class for representing IDL callback interface types.
#[derive(JSTraceable, PartialEq)]
-#[must_root]
+#[unrooted_must_root_lint::must_root]
pub struct CallbackInterface {
object: CallbackObject,
}
diff --git a/components/script/dom/bindings/codegen/Bindings.conf b/components/script/dom/bindings/codegen/Bindings.conf
index 3ff7a044b53..5dc9e141ed5 100644
--- a/components/script/dom/bindings/codegen/Bindings.conf
+++ b/components/script/dom/bindings/codegen/Bindings.conf
@@ -134,7 +134,10 @@ DOMInterfaces = {
'XR': {
'inCompartments': ['SupportsSessionMode', 'RequestSession'],
-}
+},
+'GPU': {
+ 'inCompartments': ['RequestAdapter'],
+}
}
diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py
index 86ee03d7ddd..39e8bfa275d 100644
--- a/components/script/dom/bindings/codegen/CodegenRust.py
+++ b/components/script/dom/bindings/codegen/CodegenRust.py
@@ -836,6 +836,8 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
descriptorType = descriptor.nativeType
elif isArgument:
descriptorType = descriptor.argumentType
+ elif descriptor.interface.identifier.name == "WindowProxy":
+ conversionFunction = "windowproxy_from_handlevalue"
if failureCode is None:
substitutions = {
@@ -2409,7 +2411,9 @@ def UnionTypes(descriptors, dictionaries, callbacks, typedefs, config):
'crate::dom::bindings::conversions::ConversionBehavior',
'crate::dom::bindings::conversions::StringificationBehavior',
'crate::dom::bindings::conversions::root_from_handlevalue',
+ 'crate::dom::bindings::conversions::windowproxy_from_handlevalue',
'std::ptr::NonNull',
+ 'std::rc::Rc',
'crate::dom::bindings::record::Record',
'crate::dom::bindings::num::Finite',
'crate::dom::bindings::root::DomRoot',
@@ -2419,10 +2423,12 @@ def UnionTypes(descriptors, dictionaries, callbacks, typedefs, config):
'crate::dom::bindings::trace::RootedTraceableBox',
'crate::dom::bindings::utils::find_enum_value',
'crate::dom::types::*',
+ 'crate::dom::windowproxy::WindowProxy',
'crate::script_runtime::JSContext as SafeJSContext',
'js::error::throw_type_error',
'js::rust::HandleValue',
'js::jsapi::Heap',
+ 'js::jsapi::IsCallable',
'js::jsapi::JSContext',
'js::jsapi::JSObject',
'js::rust::MutableHandleValue',
@@ -2438,9 +2444,10 @@ def UnionTypes(descriptors, dictionaries, callbacks, typedefs, config):
if not t.isUnion():
continue
for memberType in t.flatMemberTypes:
- if memberType.isDictionary() or memberType.isEnum():
+ if memberType.isDictionary() or memberType.isEnum() or memberType.isCallback():
memberModule = getModuleFromObject(memberType)
- memberName = memberType.inner.identifier.name
+ memberName = (memberType.callback.identifier.name
+ if memberType.isCallback() else memberType.inner.identifier.name)
imports.append("%s::%s" % (memberModule, memberName))
if memberType.isEnum():
imports.append("%s::%sValues" % (memberModule, memberName))
@@ -4380,6 +4387,9 @@ def getUnionTypeTemplateVars(type, descriptorProvider):
elif is_typed_array(type):
name = type.name
typeName = "typedarray::Heap" + name
+ elif type.isCallback():
+ name = type.name
+ typeName = name
else:
raise TypeError("Can't handle %s in unions yet" % type)
@@ -4418,12 +4428,19 @@ class CGUnionStruct(CGThing):
return False
def define(self):
+ def getTypeWrapper(t):
+ if type_needs_tracing(t):
+ return "RootedTraceableBox"
+ if t.isCallback():
+ return "Rc"
+ return ""
+
templateVars = map(lambda t: (getUnionTypeTemplateVars(t, self.descriptorProvider),
- type_needs_tracing(t)),
+ getTypeWrapper(t)),
self.type.flatMemberTypes)
enumValues = [
- " %s(%s)," % (v["name"], "RootedTraceableBox<%s>" % v["typeName"] if trace else v["typeName"])
- for (v, trace) in templateVars
+ " %s(%s)," % (v["name"], "%s<%s>" % (wrapper, v["typeName"]) if wrapper else v["typeName"])
+ for (v, wrapper) in templateVars
]
enumConversions = [
" %s::%s(ref inner) => inner.to_jsval(cx, rval),"
@@ -4506,7 +4523,8 @@ class CGUnionConversionStruct(CGThing):
callbackMemberTypes = filter(lambda t: t.isCallback() or t.isCallbackInterface(), memberTypes)
if len(callbackMemberTypes) > 0:
assert len(callbackMemberTypes) == 1
- raise TypeError("Can't handle callbacks in unions.")
+ typeName = callbackMemberTypes[0].name
+ callbackObject = CGGeneric(get_match(typeName))
else:
callbackObject = None
@@ -4537,7 +4555,7 @@ class CGUnionConversionStruct(CGThing):
else:
mozMapObject = None
- hasObjectTypes = object or interfaceObject or arrayObject or dateObject or mozMapObject
+ hasObjectTypes = object or interfaceObject or arrayObject or dateObject or callbackObject or mozMapObject
if hasObjectTypes:
# "object" is not distinguishable from other types
assert not object or not (interfaceObject or arrayObject or dateObject or callbackObject or mozMapObject)
@@ -4548,6 +4566,8 @@ class CGUnionConversionStruct(CGThing):
templateBody.append(interfaceObject)
if arrayObject:
templateBody.append(arrayObject)
+ if callbackObject:
+ templateBody.append(callbackObject)
if mozMapObject:
templateBody.append(mozMapObject)
conversions.append(CGIfWrapper("value.get().is_object()", templateBody))
@@ -4608,6 +4628,8 @@ class CGUnionConversionStruct(CGThing):
actualType = templateVars["typeName"]
if type_needs_tracing(t):
actualType = "RootedTraceableBox<%s>" % actualType
+ if t.isCallback():
+ actualType = "Rc<%s>" % actualType
returnType = "Result<Option<%s>, ()>" % actualType
jsConversion = templateVars["jsConversion"]
@@ -6388,8 +6410,11 @@ class CGDictionary(CGThing):
def struct(self):
d = self.dictionary
if d.parent:
- inheritance = " pub parent: %s::%s,\n" % (self.makeModuleName(d.parent),
- self.makeClassName(d.parent))
+ typeName = "%s::%s" % (self.makeModuleName(d.parent),
+ self.makeClassName(d.parent))
+ if type_needs_tracing(d.parent):
+ typeName = "RootedTraceableBox<%s>" % typeName
+ inheritance = " pub parent: %s,\n" % typeName
else:
inheritance = ""
memberDecls = [" pub %s: %s," %
@@ -6399,8 +6424,9 @@ class CGDictionary(CGThing):
derive = ["JSTraceable"]
mustRoot = ""
if self.membersNeedTracing():
- mustRoot = "#[must_root]\n"
- derive += ["Default"]
+ mustRoot = "#[unrooted_must_root_lint::must_root]\n"
+ if not self.hasRequiredFields(self.dictionary):
+ derive += ["Default"]
return (string.Template(
"#[derive(${derive})]\n"
@@ -6460,16 +6486,14 @@ class CGDictionary(CGThing):
selfName = self.makeClassName(d)
if self.membersNeedTracing():
actualType = "RootedTraceableBox<%s>" % selfName
- preInitial = "let mut dictionary = RootedTraceableBox::new(%s::default());\n" % selfName
- initParent = initParent = ("dictionary.parent = %s;\n" % initParent) if initParent else ""
- memberInits = CGList([memberInit(m, False) for m in self.memberInfo])
- postInitial = ""
+ preInitial = "let dictionary = RootedTraceableBox::new(%s {\n" % selfName
+ postInitial = "});\n"
else:
actualType = selfName
preInitial = "let dictionary = %s {\n" % selfName
postInitial = "};\n"
- initParent = ("parent: %s,\n" % initParent) if initParent else ""
- memberInits = CGList([memberInit(m, True) for m in self.memberInfo])
+ initParent = ("parent: %s,\n" % initParent) if initParent else ""
+ memberInits = CGList([memberInit(m, True) for m in self.memberInfo])
return string.Template(
"impl ${selfName} {\n"
@@ -6515,15 +6539,12 @@ class CGDictionary(CGThing):
"initParent": CGIndenter(CGGeneric(initParent), indentLevel=16).define(),
"initMembers": CGIndenter(memberInits, indentLevel=16).define(),
"insertMembers": CGIndenter(memberInserts, indentLevel=8).define(),
- "preInitial": CGIndenter(CGGeneric(preInitial), indentLevel=16).define(),
- "postInitial": CGIndenter(CGGeneric(postInitial), indentLevel=16).define(),
+ "preInitial": CGIndenter(CGGeneric(preInitial), indentLevel=8).define(),
+ "postInitial": CGIndenter(CGGeneric(postInitial), indentLevel=8).define(),
})
def membersNeedTracing(self):
- for member, _ in self.memberInfo:
- if type_needs_tracing(member.type):
- return True
- return False
+ return type_needs_tracing(self.dictionary)
@staticmethod
def makeDictionaryName(dictionary):
@@ -6923,7 +6944,8 @@ class CGCallback(CGClass):
bases=[ClassBase(baseName)],
constructors=self.getConstructors(),
methods=realMethods,
- decorators="#[derive(JSTraceable, PartialEq)]\n#[allow_unrooted_interior]")
+ decorators="#[derive(JSTraceable, PartialEq)]\n"
+ "#[unrooted_must_root_lint::allow_unrooted_interior]")
def getConstructors(self):
return [ClassConstructor(
@@ -7386,7 +7408,16 @@ class CGIterableMethodGenerator(CGGeneric):
rooted!(in(*cx) let mut call_arg2 = UndefinedValue());
let mut call_args = vec![UndefinedValue(), UndefinedValue(), ObjectValue(*_obj)];
rooted!(in(*cx) let mut ignoredReturnVal = UndefinedValue());
- for i in 0..(*this).get_iterable_length() {
+
+ // This has to be a while loop since get_iterable_length() may change during
+ // the callback, and we need to avoid iterator invalidation.
+ //
+ // It is possible for this to loop infinitely, but that matches the spec
+ // and other browsers.
+ //
+ // https://heycam.github.io/webidl/#es-forEach
+ let mut i = 0;
+ while i < (*this).get_iterable_length() {
(*this).get_value_at_index(i).to_jsval(*cx, call_arg1.handle_mut());
(*this).get_key_at_index(i).to_jsval(*cx, call_arg2.handle_mut());
call_args[0] = call_arg1.handle().get();
@@ -7396,6 +7427,8 @@ class CGIterableMethodGenerator(CGGeneric):
ignoredReturnVal.handle_mut()) {
return false;
}
+
+ i += 1;
}
let result = ();
diff --git a/components/script/dom/bindings/conversions.rs b/components/script/dom/bindings/conversions.rs
index c84adf64dbb..531ff6ea885 100644
--- a/components/script/dom/bindings/conversions.rs
+++ b/components/script/dom/bindings/conversions.rs
@@ -45,6 +45,7 @@ use crate::dom::htmlcollection::HTMLCollection;
use crate::dom::htmlformcontrolscollection::HTMLFormControlsCollection;
use crate::dom::htmloptionscollection::HTMLOptionsCollection;
use crate::dom::nodelist::NodeList;
+use crate::dom::windowproxy::WindowProxy;
use js::conversions::latin1_to_string;
pub use js::conversions::ConversionBehavior;
pub use js::conversions::{ConversionResult, FromJSValConvertible, ToJSValConvertible};
@@ -55,10 +56,10 @@ use js::glue::{IsWrapper, UnwrapObjectDynamic};
use js::glue::{RUST_JSID_IS_INT, RUST_JSID_TO_INT};
use js::glue::{RUST_JSID_IS_STRING, RUST_JSID_TO_STRING};
use js::jsapi::{Heap, JSContext, JSObject, JSString};
+use js::jsapi::{IsWindowProxy, JS_NewStringCopyN, JS_StringHasLatin1Chars};
use js::jsapi::{
JS_GetLatin1StringCharsAndLength, JS_GetTwoByteStringCharsAndLength, JS_IsExceptionPending,
};
-use js::jsapi::{JS_NewStringCopyN, JS_StringHasLatin1Chars};
use js::jsval::{ObjectValue, StringValue, UndefinedValue};
use js::rust::wrappers::{JS_GetProperty, JS_HasProperty, JS_IsArrayObject};
use js::rust::{get_object_class, is_dom_class, is_dom_object, maybe_wrap_value, ToString};
@@ -74,7 +75,6 @@ pub trait IDLInterface {
}
/// A trait to mark an IDL interface as deriving from another one.
-#[rustc_on_unimplemented(message = "The IDL interface `{Self}` is not derived from `{T}`.")]
pub trait DerivedFrom<T: Castable>: Castable {}
impl<T: Float + ToJSValConvertible> ToJSValConvertible for Finite<T> {
@@ -634,3 +634,22 @@ where
Err(()) => Err(Error::JSFailed),
}
}
+
+/// Get a `DomRoot<T>` for a WindowProxy accessible from a `HandleValue`.
+/// Caller is responsible for throwing a JS exception if needed in case of error.
+pub unsafe fn windowproxy_from_handlevalue(
+ v: HandleValue,
+ _cx: *mut JSContext,
+) -> Result<DomRoot<WindowProxy>, ()> {
+ if !v.get().is_object() {
+ return Err(());
+ }
+ let object = v.get().to_object();
+ if !IsWindowProxy(object) {
+ return Err(());
+ }
+ let mut value = UndefinedValue();
+ GetProxyReservedSlot(object, 0, &mut value);
+ let ptr = value.to_private() as *const WindowProxy;
+ Ok(DomRoot::from_ref(&*ptr))
+}
diff --git a/components/script/dom/bindings/refcounted.rs b/components/script/dom/bindings/refcounted.rs
index 8636f910121..ad5be5bb0cf 100644
--- a/components/script/dom/bindings/refcounted.rs
+++ b/components/script/dom/bindings/refcounted.rs
@@ -151,7 +151,7 @@ impl TrustedPromise {
/// shared among threads for use in asynchronous operations. The underlying
/// DOM object is guaranteed to live at least as long as the last outstanding
/// `Trusted<T>` instance.
-#[allow_unrooted_interior]
+#[unrooted_must_root_lint::allow_unrooted_interior]
pub struct Trusted<T: DomObject> {
/// A pointer to the Rust DOM object of type T, but void to allow
/// sending `Trusted<T>` between threads, regardless of T's sendability.
diff --git a/components/script/dom/bindings/reflector.rs b/components/script/dom/bindings/reflector.rs
index dc13fca77b0..2b5a4987eb5 100644
--- a/components/script/dom/bindings/reflector.rs
+++ b/components/script/dom/bindings/reflector.rs
@@ -30,7 +30,7 @@ where
/// A struct to store a reference to the reflector of a DOM object.
#[allow(unrooted_must_root)]
#[derive(MallocSizeOf)]
-#[must_root]
+#[unrooted_must_root_lint::must_root]
// If you're renaming or moving this field, update the path in plugins::reflector as well
pub struct Reflector {
#[ignore_malloc_size_of = "defined and measured in rust-mozjs"]
diff --git a/components/script/dom/bindings/root.rs b/components/script/dom/bindings/root.rs
index 6e2c883984c..19df89df53f 100644
--- a/components/script/dom/bindings/root.rs
+++ b/components/script/dom/bindings/root.rs
@@ -46,7 +46,7 @@ use style::thread_state;
/// A rooted value.
#[allow(unrooted_must_root)]
-#[allow_unrooted_interior]
+#[unrooted_must_root_lint::allow_unrooted_interior]
pub struct Root<T: StableTraceObject> {
/// The value to root.
value: T,
@@ -283,7 +283,7 @@ where
/// on the stack, the `Dom<T>` can point to freed memory.
///
/// This should only be used as a field in other DOM objects.
-#[must_root]
+#[unrooted_must_root_lint::must_root]
pub struct Dom<T> {
ptr: ptr::NonNull<T>,
}
@@ -343,7 +343,7 @@ unsafe impl<T: DomObject> JSTraceable for Dom<T> {
/// An unrooted reference to a DOM object for use in layout. `Layout*Helpers`
/// traits must be implemented on this.
-#[allow_unrooted_interior]
+#[unrooted_must_root_lint::allow_unrooted_interior]
pub struct LayoutDom<T> {
ptr: ptr::NonNull<T>,
}
@@ -463,7 +463,7 @@ impl LayoutDom<Node> {
///
/// This should only be used as a field in other DOM objects; see warning
/// on `Dom<T>`.
-#[must_root]
+#[unrooted_must_root_lint::must_root]
#[derive(JSTraceable)]
pub struct MutDom<T: DomObject> {
val: UnsafeCell<Dom<T>>,
@@ -518,7 +518,7 @@ impl<T: DomObject + PartialEq> PartialEq<T> for MutDom<T> {
///
/// This should only be used as a field in other DOM objects; see warning
/// on `Dom<T>`.
-#[must_root]
+#[unrooted_must_root_lint::must_root]
#[derive(JSTraceable)]
pub struct MutNullableDom<T: DomObject> {
ptr: UnsafeCell<Option<Dom<T>>>,
@@ -616,7 +616,7 @@ impl<T: DomObject> MallocSizeOf for MutNullableDom<T> {
///
/// This should only be used as a field in other DOM objects; see warning
/// on `Dom<T>`.
-#[must_root]
+#[unrooted_must_root_lint::must_root]
pub struct DomOnceCell<T: DomObject> {
ptr: OnceCell<Dom<T>>,
}
diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs
index 7869d1499ac..65717bb81bf 100644
--- a/components/script/dom/bindings/trace.rs
+++ b/components/script/dom/bindings/trace.rs
@@ -39,6 +39,7 @@ use crate::dom::bindings::utils::WindowProxyHandler;
use crate::dom::document::PendingRestyle;
use crate::dom::htmlimageelement::SourceSet;
use crate::dom::htmlmediaelement::{HTMLMediaElementFetchContext, MediaFrameRenderer};
+use crate::dom::identityhub::Identities;
use crate::task::TaskBox;
use app_units::Au;
use canvas_traits::canvas::{
@@ -57,7 +58,7 @@ use content_security_policy::CspList;
use crossbeam_channel::{Receiver, Sender};
use cssparser::RGBA;
use devtools_traits::{CSSError, TimelineMarkerType, WorkerId};
-use embedder_traits::EventLoopWaker;
+use embedder_traits::{EventLoopWaker, MediaMetadata};
use encoding_rs::{Decoder, Encoding};
use euclid::default::{Point2D, Rect, Rotation3D, Transform2D, Transform3D};
use euclid::Length as EuclidLength;
@@ -94,9 +95,9 @@ use profile_traits::time::ProfilerChan as TimeProfilerChan;
use script_layout_interface::rpc::LayoutRPC;
use script_layout_interface::OpaqueStyleAndLayoutData;
use script_traits::transferable::MessagePortImpl;
-use script_traits::DrawAPaintImageResult;
-use script_traits::{DocumentActivity, ScriptToConstellationChan, TimerEventId, TimerSource};
-use script_traits::{UntrustedNodeAddress, WindowSizeData, WindowSizeType};
+use script_traits::{DocumentActivity, DrawAPaintImageResult};
+use script_traits::{MediaSessionActionType, ScriptToConstellationChan, TimerEventId, TimerSource};
+use script_traits::{UntrustedNodeAddress, WebrenderIpcSender, WindowSizeData, WindowSizeType};
use selectors::matching::ElementSelectorFlags;
use serde::{Deserialize, Serialize};
use servo_arc::Arc as ServoArc;
@@ -107,7 +108,8 @@ use servo_media::audio::context::AudioContext;
use servo_media::audio::graph::NodeId;
use servo_media::audio::panner_node::{DistanceModel, PanningModel};
use servo_media::audio::param::ParamType;
-use servo_media::player::frame::Frame;
+use servo_media::player::audio::AudioRenderer;
+use servo_media::player::video::VideoFrame;
use servo_media::player::Player;
use servo_media::streams::registry::MediaStreamId;
use servo_media::streams::MediaStreamType;
@@ -144,7 +146,8 @@ use tendril::stream::LossyDecoder;
use tendril::{StrTendril, TendrilSink};
use time::{Duration, Timespec};
use uuid::Uuid;
-use webrender_api::{DocumentId, ImageKey, RenderApiSender};
+use webgpu::{WebGPU, WebGPUAdapter};
+use webrender_api::{DocumentId, ImageKey};
use webvr_traits::{WebVRGamepadData, WebVRGamepadHand, WebVRGamepadState};
use webxr_api::SwapChainId as WebXRSwapChainId;
@@ -501,6 +504,9 @@ unsafe_no_jsmanaged_fields!(WebGLTextureId);
unsafe_no_jsmanaged_fields!(WebGLVertexArrayId);
unsafe_no_jsmanaged_fields!(WebGLVersion);
unsafe_no_jsmanaged_fields!(WebGLSLVersion);
+unsafe_no_jsmanaged_fields!(WebGPU);
+unsafe_no_jsmanaged_fields!(RefCell<Identities>);
+unsafe_no_jsmanaged_fields!(WebGPUAdapter);
unsafe_no_jsmanaged_fields!(WebXRSwapChainId);
unsafe_no_jsmanaged_fields!(MediaList);
unsafe_no_jsmanaged_fields!(WebVRGamepadData, WebVRGamepadState, WebVRGamepadHand);
@@ -523,7 +529,6 @@ unsafe_no_jsmanaged_fields!(Arc<Mutex<dyn Player>>);
unsafe_no_jsmanaged_fields!(WebRtcController);
unsafe_no_jsmanaged_fields!(MediaStreamId, MediaStreamType);
unsafe_no_jsmanaged_fields!(Mutex<MediaFrameRenderer>);
-unsafe_no_jsmanaged_fields!(RenderApiSender);
unsafe_no_jsmanaged_fields!(ResourceFetchTiming);
unsafe_no_jsmanaged_fields!(Timespec);
unsafe_no_jsmanaged_fields!(HTMLMediaElementFetchContext);
@@ -532,8 +537,12 @@ unsafe_no_jsmanaged_fields!(Point2D<f32>, Rect<Au>);
unsafe_no_jsmanaged_fields!(Rect<f32>);
unsafe_no_jsmanaged_fields!(CascadeData);
unsafe_no_jsmanaged_fields!(WindowGLContext);
-unsafe_no_jsmanaged_fields!(Frame);
+unsafe_no_jsmanaged_fields!(VideoFrame);
unsafe_no_jsmanaged_fields!(WebGLContextId);
+unsafe_no_jsmanaged_fields!(Arc<Mutex<dyn AudioRenderer>>);
+unsafe_no_jsmanaged_fields!(MediaSessionActionType);
+unsafe_no_jsmanaged_fields!(MediaMetadata);
+unsafe_no_jsmanaged_fields!(WebrenderIpcSender);
unsafe impl<'a> JSTraceable for &'a str {
#[inline]
@@ -883,7 +892,7 @@ impl<'a, T: JSTraceable + 'static> Drop for RootedTraceable<'a, T> {
/// If you have GC things like *mut JSObject or JSVal, use rooted!.
/// If you have an arbitrary number of DomObjects to root, use rooted_vec!.
/// If you know what you're doing, use this.
-#[allow_unrooted_interior]
+#[unrooted_must_root_lint::allow_unrooted_interior]
pub struct RootedTraceableBox<T: 'static + JSTraceable> {
ptr: *mut T,
}
@@ -954,7 +963,7 @@ impl<T: JSTraceable + 'static> Drop for RootedTraceableBox<T> {
/// iterator of `DomRoot`s, `rooted_vec!(let v <- iterator);`.
#[allow(unrooted_must_root)]
#[derive(JSTraceable)]
-#[allow_unrooted_interior]
+#[unrooted_must_root_lint::allow_unrooted_interior]
pub struct RootableVec<T: JSTraceable> {
v: Vec<T>,
}
@@ -967,7 +976,7 @@ impl<T: JSTraceable> RootableVec<T> {
}
/// A vector of items that are rooted for the lifetime 'a.
-#[allow_unrooted_interior]
+#[unrooted_must_root_lint::allow_unrooted_interior]
pub struct RootedVec<'a, T: 'static + JSTraceable> {
root: &'a mut RootableVec<T>,
}
diff --git a/components/script/dom/bindings/utils.rs b/components/script/dom/bindings/utils.rs
index ef3b270b130..e344e9ae279 100644
--- a/components/script/dom/bindings/utils.rs
+++ b/components/script/dom/bindings/utils.rs
@@ -16,11 +16,13 @@ use crate::dom::bindings::trace::trace_object;
use crate::dom::messageport::MessagePort;
use crate::dom::windowproxy;
use crate::script_runtime::JSContext as SafeJSContext;
-use js::conversions::ToJSValConvertible;
+use js::conversions::{jsstr_to_string, ToJSValConvertible};
use js::glue::{CallJitGetterOp, CallJitMethodOp, CallJitSetterOp, IsWrapper};
use js::glue::{GetCrossCompartmentWrapper, JS_GetReservedSlot, WrapperNew};
use js::glue::{UnwrapObjectDynamic, RUST_JSID_TO_INT, RUST_JSID_TO_STRING};
-use js::glue::{RUST_FUNCTION_VALUE_TO_JITINFO, RUST_JSID_IS_INT, RUST_JSID_IS_STRING};
+use js::glue::{
+ RUST_FUNCTION_VALUE_TO_JITINFO, RUST_JSID_IS_INT, RUST_JSID_IS_STRING, RUST_JSID_IS_VOID,
+};
use js::jsapi::HandleId as RawHandleId;
use js::jsapi::HandleObject as RawHandleObject;
use js::jsapi::MutableHandleObject as RawMutableHandleObject;
@@ -29,7 +31,10 @@ use js::jsapi::{Heap, JSAutoRealm, JSContext, JS_FreezeObject};
use js::jsapi::{JSJitInfo, JSObject, JSTracer, JSWrapObjectCallbacks};
use js::jsapi::{JS_EnumerateStandardClasses, JS_GetLatin1StringCharsAndLength};
use js::jsapi::{JS_IsExceptionPending, JS_IsGlobalObject};
-use js::jsapi::{JS_ResolveStandardClass, JS_StringHasLatin1Chars, ObjectOpResult};
+use js::jsapi::{
+ JS_ResolveStandardClass, JS_StringHasLatin1Chars, ObjectOpResult, StringIsArrayIndex1,
+ StringIsArrayIndex2,
+};
use js::jsval::{JSVal, UndefinedValue};
use js::rust::wrappers::JS_DeletePropertyById;
use js::rust::wrappers::JS_ForwardGetPropertyTo;
@@ -178,28 +183,41 @@ pub unsafe fn get_property_on_prototype(
/// Get an array index from the given `jsid`. Returns `None` if the given
/// `jsid` is not an integer.
-pub fn get_array_index_from_id(_cx: *mut JSContext, id: HandleId) -> Option<u32> {
+pub unsafe fn get_array_index_from_id(cx: *mut JSContext, id: HandleId) -> Option<u32> {
let raw_id = id.into();
- unsafe {
- if RUST_JSID_IS_INT(raw_id) {
- return Some(RUST_JSID_TO_INT(raw_id) as u32);
- }
+ if RUST_JSID_IS_INT(raw_id) {
+ return Some(RUST_JSID_TO_INT(raw_id) as u32);
+ }
+
+ if RUST_JSID_IS_VOID(raw_id) || !RUST_JSID_IS_STRING(raw_id) {
+ return None;
+ }
+
+ let s = jsstr_to_string(cx, RUST_JSID_TO_STRING(raw_id));
+ if s.len() == 0 {
+ return None;
+ }
+
+ let first = s.chars().next().unwrap();
+ if first.is_ascii_lowercase() {
+ return None;
+ }
+
+ let mut i: u32 = 0;
+ let is_array = if s.is_ascii() {
+ let chars = s.as_bytes();
+ StringIsArrayIndex1(chars.as_ptr() as *const _, chars.len() as u32, &mut i)
+ } else {
+ let chars = s.encode_utf16().collect::<Vec<u16>>();
+ let slice = chars.as_slice();
+ StringIsArrayIndex2(slice.as_ptr(), chars.len() as u32, &mut i)
+ };
+
+ if is_array {
+ Some(i)
+ } else {
None
}
- // if id is length atom, -1, otherwise
- // return if JSID_IS_ATOM(id) {
- // let atom = JSID_TO_ATOM(id);
- // //let s = *GetAtomChars(id);
- // if s > 'a' && s < 'z' {
- // return -1;
- // }
- //
- // let i = 0;
- // let str = AtomToLinearString(JSID_TO_ATOM(id));
- // return if StringIsArray(str, &mut i) != 0 { i } else { -1 }
- // } else {
- // IdToInt32(cx, id);
- // }
}
/// Find the enum equivelent of a string given by `v` in `pairs`.
diff --git a/components/script/dom/bindings/weakref.rs b/components/script/dom/bindings/weakref.rs
index bea2141d142..5c74e111816 100644
--- a/components/script/dom/bindings/weakref.rs
+++ b/components/script/dom/bindings/weakref.rs
@@ -34,13 +34,13 @@ pub const DOM_WEAK_SLOT: u32 = 1;
/// A weak reference to a JS-managed DOM object.
#[allow(unrooted_must_root)]
-#[allow_unrooted_interior]
+#[unrooted_must_root_lint::allow_unrooted_interior]
pub struct WeakRef<T: WeakReferenceable> {
ptr: ptr::NonNull<WeakBox<T>>,
}
/// The inner box of weak references, public for the finalization in codegen.
-#[must_root]
+#[unrooted_must_root_lint::must_root]
pub struct WeakBox<T: WeakReferenceable> {
/// The reference count. When it reaches zero, the `value` field should
/// have already been set to `None`. The pointee contributes one to the count.
@@ -218,7 +218,7 @@ unsafe impl<T: WeakReferenceable> JSTraceable for MutableWeakRef<T> {
/// A vector of weak references. On tracing, the vector retains
/// only references which still point to live objects.
-#[allow_unrooted_interior]
+#[unrooted_must_root_lint::allow_unrooted_interior]
#[derive(MallocSizeOf)]
pub struct WeakRefVec<T: WeakReferenceable> {
vec: Vec<WeakRef<T>>,
@@ -268,7 +268,7 @@ impl<T: WeakReferenceable> DerefMut for WeakRefVec<T> {
/// An entry of a vector of weak references. Passed to the closure
/// given to `WeakRefVec::update`.
-#[allow_unrooted_interior]
+#[unrooted_must_root_lint::allow_unrooted_interior]
pub struct WeakRefEntry<'a, T: WeakReferenceable> {
vec: &'a mut WeakRefVec<T>,
index: &'a mut usize,
diff --git a/components/script/dom/blob.rs b/components/script/dom/blob.rs
index fbf3e5819be..db90b2d2bda 100644
--- a/components/script/dom/blob.rs
+++ b/components/script/dom/blob.rs
@@ -31,7 +31,7 @@ pub struct FileBlob {
}
/// Different backends of Blob
-#[must_root]
+#[unrooted_must_root_lint::must_root]
#[derive(JSTraceable)]
pub enum BlobImpl {
/// File-based blob, whose content lives in the net process
diff --git a/components/script/dom/bluetooth.rs b/components/script/dom/bluetooth.rs
index 989bcce27b7..fad367bb454 100644
--- a/components/script/dom/bluetooth.rs
+++ b/components/script/dom/bluetooth.rs
@@ -164,7 +164,7 @@ impl Bluetooth {
&self,
p: &Rc<Promise>,
filters: &Option<Vec<BluetoothLEScanFilterInit>>,
- optional_services: &Option<Vec<BluetoothServiceUUID>>,
+ optional_services: &[BluetoothServiceUUID],
sender: IpcSender<BluetoothResponseResult>,
) {
// TODO: Step 1: Triggered by user activation.
@@ -197,23 +197,21 @@ impl Bluetooth {
}
let mut optional_services_uuids = vec![];
- if let &Some(ref opt_services) = optional_services {
- for opt_service in opt_services {
- // Step 2.5 - 2.6.
- let uuid = match BluetoothUUID::service(opt_service.clone()) {
- Ok(u) => u.to_string(),
- Err(e) => {
- p.reject_error(e);
- return;
- },
- };
+ for opt_service in optional_services {
+ // Step 2.5 - 2.6.
+ let uuid = match BluetoothUUID::service(opt_service.clone()) {
+ Ok(u) => u.to_string(),
+ Err(e) => {
+ p.reject_error(e);
+ return;
+ },
+ };
- // Step 2.7.
- // Note: What we are doing here, is adding the not blocklisted UUIDs to the result vector,
- // instead of removing them from an already filled vector.
- if !uuid_is_blocklisted(uuid.as_ref(), Blocklist::All) {
- optional_services_uuids.push(uuid);
- }
+ // Step 2.7.
+ // Note: What we are doing here, is adding the not blocklisted UUIDs to the result vector,
+ // instead of removing them from an already filled vector.
+ if !uuid_is_blocklisted(uuid.as_ref(), Blocklist::All) {
+ optional_services_uuids.push(uuid);
}
}
diff --git a/components/script/dom/canvasrenderingcontext2d.rs b/components/script/dom/canvasrenderingcontext2d.rs
index 9f6403bec5c..371b31bbdb0 100644
--- a/components/script/dom/canvasrenderingcontext2d.rs
+++ b/components/script/dom/canvasrenderingcontext2d.rs
@@ -22,9 +22,10 @@ use crate::dom::globalscope::GlobalScope;
use crate::dom::htmlcanvaselement::HTMLCanvasElement;
use crate::dom::imagedata::ImageData;
use crate::dom::textmetrics::TextMetrics;
+use crate::euclidext::Size2DExt;
use canvas_traits::canvas::{Canvas2dMsg, CanvasId, CanvasMsg};
use dom_struct::dom_struct;
-use euclid::default::{Rect, Size2D};
+use euclid::default::{Point2D, Rect, Size2D};
use ipc_channel::ipc::IpcSender;
use servo_url::ServoUrl;
use std::mem;
@@ -75,12 +76,13 @@ impl CanvasRenderingContext2D {
.borrow()
.get_ipc_renderer()
.send(CanvasMsg::Recreate(
- size,
+ size.to_u64(),
self.canvas_state.borrow().get_canvas_id(),
))
.unwrap();
}
+ // TODO: This duplicates functionality in canvas state
// https://html.spec.whatwg.org/multipage/#reset-the-rendering-context-to-its-default-state
fn reset_to_initial_state(&self) {
self.canvas_state
@@ -90,6 +92,15 @@ impl CanvasRenderingContext2D {
.clear();
*self.canvas_state.borrow().get_state().borrow_mut() = CanvasContextState::new();
}
+ /*
+ pub fn get_canvas_state(&self) -> Ref<CanvasState> {
+ self.canvas_state.borrow()
+ }
+ */
+
+ pub fn set_canvas_bitmap_dimensions(&self, size: Size2D<u64>) {
+ self.canvas_state.borrow().set_bitmap_dimensions(size);
+ }
pub fn mark_as_dirty(&self) {
self.canvas_state
@@ -116,6 +127,7 @@ impl CanvasRenderingContext2D {
self.canvas_state.borrow().send_canvas_2d_msg(msg)
}
+ // TODO: Remove this
pub fn get_ipc_renderer(&self) -> IpcSender<CanvasMsg> {
self.canvas_state.borrow().get_ipc_renderer().clone()
}
@@ -125,10 +137,14 @@ impl CanvasRenderingContext2D {
}
pub fn get_rect(&self, rect: Rect<u32>) -> Vec<u8> {
+ let rect = Rect::new(
+ Point2D::new(rect.origin.x as u64, rect.origin.y as u64),
+ Size2D::new(rect.size.width as u64, rect.size.height as u64),
+ );
self.canvas_state.borrow().get_rect(
self.canvas
.as_ref()
- .map_or(Size2D::zero(), |c| c.get_size()),
+ .map_or(Size2D::zero(), |c| c.get_size().to_u64()),
rect,
)
}
@@ -469,7 +485,7 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
self.canvas_state.borrow().get_image_data(
self.canvas
.as_ref()
- .map_or(Size2D::zero(), |c| c.get_size()),
+ .map_or(Size2D::zero(), |c| c.get_size().to_u64()),
&self.global(),
sx,
sy,
@@ -483,7 +499,7 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
self.canvas_state.borrow().put_image_data(
self.canvas
.as_ref()
- .map_or(Size2D::zero(), |c| c.get_size()),
+ .map_or(Size2D::zero(), |c| c.get_size().to_u64()),
imagedata,
dx,
dy,
@@ -505,7 +521,7 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
self.canvas_state.borrow().put_image_data_(
self.canvas
.as_ref()
- .map_or(Size2D::zero(), |c| c.get_size()),
+ .map_or(Size2D::zero(), |c| c.get_size().to_u64()),
imagedata,
dx,
dy,
diff --git a/components/script/dom/cssstyledeclaration.rs b/components/script/dom/cssstyledeclaration.rs
index d623f46005a..2ad565f9b45 100644
--- a/components/script/dom/cssstyledeclaration.rs
+++ b/components/script/dom/cssstyledeclaration.rs
@@ -39,7 +39,7 @@ pub struct CSSStyleDeclaration {
}
#[derive(JSTraceable, MallocSizeOf)]
-#[must_root]
+#[unrooted_must_root_lint::must_root]
pub enum CSSStyleOwner {
Element(Dom<Element>),
CSSRule(
diff --git a/components/script/dom/customelementregistry.rs b/components/script/dom/customelementregistry.rs
index 64117959500..7b4229835e2 100644
--- a/components/script/dom/customelementregistry.rs
+++ b/components/script/dom/customelementregistry.rs
@@ -706,7 +706,7 @@ pub fn try_upgrade_element(element: &Element) {
}
#[derive(JSTraceable, MallocSizeOf)]
-#[must_root]
+#[unrooted_must_root_lint::must_root]
pub enum CustomElementReaction {
Upgrade(#[ignore_malloc_size_of = "Rc"] Rc<CustomElementDefinition>),
Callback(
@@ -752,7 +752,7 @@ enum BackupElementQueueFlag {
/// <https://html.spec.whatwg.org/multipage/#custom-element-reactions-stack>
#[derive(JSTraceable, MallocSizeOf)]
-#[must_root]
+#[unrooted_must_root_lint::must_root]
pub struct CustomElementReactionStack {
stack: DomRefCell<Vec<ElementQueue>>,
backup_queue: ElementQueue,
@@ -934,7 +934,7 @@ impl CustomElementReactionStack {
/// <https://html.spec.whatwg.org/multipage/#element-queue>
#[derive(JSTraceable, MallocSizeOf)]
-#[must_root]
+#[unrooted_must_root_lint::must_root]
struct ElementQueue {
queue: DomRefCell<VecDeque<Dom<Element>>>,
}
diff --git a/components/script/dom/dedicatedworkerglobalscope.rs b/components/script/dom/dedicatedworkerglobalscope.rs
index 3745ef9f1ac..2f339d1f8f8 100644
--- a/components/script/dom/dedicatedworkerglobalscope.rs
+++ b/components/script/dom/dedicatedworkerglobalscope.rs
@@ -32,11 +32,12 @@ use crate::script_runtime::{
new_child_runtime, CommonScriptMsg, JSContext as SafeJSContext, Runtime, ScriptChan, ScriptPort,
};
use crate::task_queue::{QueuedTask, QueuedTaskConversion, TaskQueue};
+use crate::task_source::networking::NetworkingTaskSource;
use crate::task_source::TaskSourceName;
use crossbeam_channel::{unbounded, Receiver, Sender};
use devtools_traits::DevtoolScriptControlMsg;
use dom_struct::dom_struct;
-use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
+use ipc_channel::ipc::IpcReceiver;
use ipc_channel::router::ROUTER;
use js::jsapi::JS_AddInterruptCallback;
use js::jsapi::{Heap, JSContext, JSObject};
@@ -47,7 +48,7 @@ use net_traits::image_cache::ImageCache;
use net_traits::request::{CredentialsMode, Destination, ParserMetadata};
use net_traits::request::{Referrer, RequestBuilder, RequestMode};
use net_traits::IpcSend;
-use script_traits::{TimerEvent, TimerSource, WorkerGlobalScopeInit, WorkerScriptLoadOrigin};
+use script_traits::{WorkerGlobalScopeInit, WorkerScriptLoadOrigin};
use servo_rand::random;
use servo_url::ServoUrl;
use std::mem::replace;
@@ -92,7 +93,6 @@ pub enum DedicatedWorkerScriptMsg {
pub enum MixedMessage {
FromWorker(DedicatedWorkerScriptMsg),
- FromScheduler((TrustedWorkerAddress, TimerEvent)),
FromDevtools(DevtoolScriptControlMsg),
}
@@ -173,8 +173,6 @@ pub struct DedicatedWorkerGlobalScope {
task_queue: TaskQueue<DedicatedWorkerScriptMsg>,
#[ignore_malloc_size_of = "Defined in std"]
own_sender: Sender<DedicatedWorkerScriptMsg>,
- #[ignore_malloc_size_of = "Defined in std"]
- timer_event_port: Receiver<(TrustedWorkerAddress, TimerEvent)>,
#[ignore_malloc_size_of = "Trusted<T> has unclear ownership like Dom<T>"]
worker: DomRefCell<Option<TrustedWorkerAddress>>,
#[ignore_malloc_size_of = "Can't measure trait objects"]
@@ -185,14 +183,9 @@ pub struct DedicatedWorkerGlobalScope {
}
impl WorkerEventLoopMethods for DedicatedWorkerGlobalScope {
- type TimerMsg = (TrustedWorkerAddress, TimerEvent);
type WorkerMsg = DedicatedWorkerScriptMsg;
type Event = MixedMessage;
- fn timer_event_port(&self) -> &Receiver<(TrustedWorkerAddress, TimerEvent)> {
- &self.timer_event_port
- }
-
fn task_queue(&self) -> &TaskQueue<DedicatedWorkerScriptMsg> {
&self.task_queue
}
@@ -210,10 +203,6 @@ impl WorkerEventLoopMethods for DedicatedWorkerGlobalScope {
MixedMessage::FromWorker(msg)
}
- fn from_timer_msg(&self, msg: (TrustedWorkerAddress, TimerEvent)) -> MixedMessage {
- MixedMessage::FromScheduler(msg)
- }
-
fn from_devtools_msg(&self, msg: DevtoolScriptControlMsg) -> MixedMessage {
MixedMessage::FromDevtools(msg)
}
@@ -230,8 +219,6 @@ impl DedicatedWorkerGlobalScope {
parent_sender: Box<dyn ScriptChan + Send>,
own_sender: Sender<DedicatedWorkerScriptMsg>,
receiver: Receiver<DedicatedWorkerScriptMsg>,
- timer_event_chan: IpcSender<TimerEvent>,
- timer_event_port: Receiver<(TrustedWorkerAddress, TimerEvent)>,
closing: Arc<AtomicBool>,
image_cache: Arc<dyn ImageCache>,
) -> DedicatedWorkerGlobalScope {
@@ -243,12 +230,10 @@ impl DedicatedWorkerGlobalScope {
worker_url,
runtime,
from_devtools_receiver,
- timer_event_chan,
Some(closing),
),
task_queue: TaskQueue::new(receiver, own_sender.clone()),
own_sender: own_sender,
- timer_event_port: timer_event_port,
parent_sender: parent_sender,
worker: DomRefCell::new(None),
image_cache: image_cache,
@@ -266,8 +251,6 @@ impl DedicatedWorkerGlobalScope {
parent_sender: Box<dyn ScriptChan + Send>,
own_sender: Sender<DedicatedWorkerScriptMsg>,
receiver: Receiver<DedicatedWorkerScriptMsg>,
- timer_event_chan: IpcSender<TimerEvent>,
- timer_event_port: Receiver<(TrustedWorkerAddress, TimerEvent)>,
closing: Arc<AtomicBool>,
image_cache: Arc<dyn ImageCache>,
) -> DomRoot<DedicatedWorkerGlobalScope> {
@@ -282,8 +265,6 @@ impl DedicatedWorkerGlobalScope {
parent_sender,
own_sender,
receiver,
- timer_event_chan,
- timer_event_port,
closing,
image_cache,
));
@@ -344,7 +325,20 @@ impl DedicatedWorkerGlobalScope {
.referrer_policy(referrer_policy)
.origin(origin);
- let runtime = unsafe { new_child_runtime(parent) };
+ let runtime = unsafe {
+ if let Some(pipeline_id) = pipeline_id {
+ let task_source = NetworkingTaskSource(
+ Box::new(WorkerThreadWorkerChan {
+ sender: own_sender.clone(),
+ worker: worker.clone(),
+ }),
+ pipeline_id,
+ );
+ new_child_runtime(parent, Some(task_source))
+ } else {
+ new_child_runtime(parent, None)
+ }
+ };
let (devtools_mpsc_chan, devtools_mpsc_port) = unbounded();
ROUTER.route_ipc_receiver_to_crossbeam_sender(
@@ -352,17 +346,6 @@ impl DedicatedWorkerGlobalScope {
devtools_mpsc_chan,
);
- let (timer_tx, timer_rx) = unbounded();
- let (timer_ipc_chan, timer_ipc_port) = ipc::channel().unwrap();
- let worker_for_route = worker.clone();
- ROUTER.add_route(
- timer_ipc_port.to_opaque(),
- Box::new(move |message| {
- let event = message.to().unwrap();
- timer_tx.send((worker_for_route.clone(), event)).unwrap();
- }),
- );
-
let global = DedicatedWorkerGlobalScope::new(
init,
DOMString::from_string(worker_name),
@@ -373,8 +356,6 @@ impl DedicatedWorkerGlobalScope {
parent_sender.clone(),
own_sender,
receiver,
- timer_ipc_chan,
- timer_rx,
closing,
image_cache,
);
@@ -503,14 +484,6 @@ impl DedicatedWorkerGlobalScope {
},
_ => debug!("got an unusable devtools control message inside the worker!"),
},
- MixedMessage::FromScheduler((linked_worker, timer_event)) => match timer_event {
- TimerEvent(TimerSource::FromWorker, id) => {
- let _ar = AutoWorkerReset::new(self, linked_worker);
- let scope = self.upcast::<WorkerGlobalScope>();
- scope.handle_fire_timer(id);
- },
- TimerEvent(_, _) => panic!("A worker received a TimerEvent from a window."),
- },
MixedMessage::FromWorker(DedicatedWorkerScriptMsg::CommonWorker(
linked_worker,
msg,
@@ -619,8 +592,6 @@ impl DedicatedWorkerGlobalScopeMethods for DedicatedWorkerGlobalScope {
let mut rooted = CustomAutoRooter::new(
options
.transfer
- .as_ref()
- .unwrap_or(&Vec::with_capacity(0))
.iter()
.map(|js: &RootedTraceableBox<Heap<*mut JSObject>>| js.get())
.collect(),
diff --git a/components/script/dom/dissimilaroriginwindow.rs b/components/script/dom/dissimilaroriginwindow.rs
index c628923604e..ac866a90ff8 100644
--- a/components/script/dom/dissimilaroriginwindow.rs
+++ b/components/script/dom/dissimilaroriginwindow.rs
@@ -15,7 +15,6 @@ use crate::dom::globalscope::GlobalScope;
use crate::dom::windowproxy::WindowProxy;
use crate::script_runtime::JSContext;
use dom_struct::dom_struct;
-use ipc_channel::ipc;
use js::jsapi::{Heap, JSObject};
use js::jsval::{JSVal, UndefinedValue};
use js::rust::{CustomAutoRooter, CustomAutoRooterGuard, HandleValue};
@@ -48,8 +47,6 @@ impl DissimilarOriginWindow {
#[allow(unsafe_code)]
pub fn new(global_to_clone_from: &GlobalScope, window_proxy: &WindowProxy) -> DomRoot<Self> {
let cx = global_to_clone_from.get_cx();
- // Any timer events fired on this window are ignored.
- let (timer_event_chan, _) = ipc::channel().unwrap();
let win = Box::new(Self {
globalscope: GlobalScope::new_inherited(
PipelineId::new(),
@@ -59,7 +56,6 @@ impl DissimilarOriginWindow {
global_to_clone_from.script_to_constellation_chan().clone(),
global_to_clone_from.scheduler_chan().clone(),
global_to_clone_from.resource_threads().clone(),
- timer_event_chan,
global_to_clone_from.origin().clone(),
// FIXME(nox): The microtask queue is probably not important
// here, but this whole DOM interface is a hack anyway.
@@ -141,15 +137,9 @@ impl DissimilarOriginWindowMethods for DissimilarOriginWindow {
cx: JSContext,
message: HandleValue,
target_origin: USVString,
- mut transfer: CustomAutoRooterGuard<Option<Vec<*mut JSObject>>>,
+ transfer: CustomAutoRooterGuard<Vec<*mut JSObject>>,
) -> ErrorResult {
- if transfer.is_some() {
- let mut rooted = CustomAutoRooter::new(transfer.take().unwrap());
- let transfer = Some(CustomAutoRooterGuard::new(*cx, &mut rooted));
- self.post_message_impl(&target_origin, cx, message, transfer)
- } else {
- self.post_message_impl(&target_origin, cx, message, None)
- }
+ self.post_message_impl(&target_origin, cx, message, transfer)
}
/// https://html.spec.whatwg.org/multipage/#dom-window-postmessage-options
@@ -161,14 +151,13 @@ impl DissimilarOriginWindowMethods for DissimilarOriginWindow {
) -> ErrorResult {
let mut rooted = CustomAutoRooter::new(
options
+ .parent
.transfer
- .as_ref()
- .unwrap_or(&Vec::with_capacity(0))
.iter()
.map(|js: &RootedTraceableBox<Heap<*mut JSObject>>| js.get())
.collect(),
);
- let transfer = Some(CustomAutoRooterGuard::new(*cx, &mut rooted));
+ let transfer = CustomAutoRooterGuard::new(*cx, &mut rooted);
self.post_message_impl(&options.targetOrigin, cx, message, transfer)
}
@@ -208,10 +197,10 @@ impl DissimilarOriginWindow {
target_origin: &USVString,
cx: JSContext,
message: HandleValue,
- transfer: Option<CustomAutoRooterGuard<Vec<*mut JSObject>>>,
+ transfer: CustomAutoRooterGuard<Vec<*mut JSObject>>,
) -> ErrorResult {
// Step 6-7.
- let data = structuredclone::write(cx, message, transfer)?;
+ let data = structuredclone::write(cx, message, Some(transfer))?;
self.post_message(target_origin, data)
}
diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs
index 0efb0856098..a7a56665bf1 100644
--- a/components/script/dom/document.rs
+++ b/components/script/dom/document.rs
@@ -506,62 +506,69 @@ impl Document {
pub fn set_activity(&self, activity: DocumentActivity) {
// This function should only be called on documents with a browsing context
assert!(self.has_browsing_context);
+ if activity == self.activity.get() {
+ return;
+ }
+
// Set the document's activity level, reflow if necessary, and suspend or resume timers.
- if activity != self.activity.get() {
- self.activity.set(activity);
- let media = ServoMedia::get().unwrap();
- let pipeline_id = self.window().pipeline_id().expect("doc with no pipeline");
- let client_context_id =
- ClientContextId::build(pipeline_id.namespace_id.0, pipeline_id.index.0.get());
- if activity == DocumentActivity::FullyActive {
- self.title_changed();
- self.dirty_all_nodes();
- self.window()
- .reflow(ReflowGoal::Full, ReflowReason::CachedPageNeededReflow);
- self.window().resume();
- media.resume(&client_context_id);
- // html.spec.whatwg.org/multipage/#history-traversal
- // Step 4.6
- if self.ready_state.get() == DocumentReadyState::Complete {
- let document = Trusted::new(self);
- self.window
- .task_manager()
- .dom_manipulation_task_source()
- .queue(
- task!(fire_pageshow_event: move || {
- let document = document.root();
- let window = document.window();
- // Step 4.6.1
- if document.page_showing.get() {
- return;
- }
- // Step 4.6.2
- document.page_showing.set(true);
- // Step 4.6.4
- let event = PageTransitionEvent::new(
- window,
- atom!("pageshow"),
- false, // bubbles
- false, // cancelable
- true, // persisted
- );
- let event = event.upcast::<Event>();
- event.set_trusted(true);
- // FIXME(nox): Why are errors silenced here?
- let _ = window.upcast::<EventTarget>().dispatch_event_with_target(
- document.upcast(),
- &event,
- );
- }),
- self.window.upcast(),
- )
- .unwrap();
- }
- } else {
- self.window().suspend();
- media.suspend(&client_context_id);
- }
+ self.activity.set(activity);
+ let media = ServoMedia::get().unwrap();
+ let pipeline_id = self.window().pipeline_id().expect("doc with no pipeline");
+ let client_context_id =
+ ClientContextId::build(pipeline_id.namespace_id.0, pipeline_id.index.0.get());
+
+ if activity != DocumentActivity::FullyActive {
+ self.window().suspend();
+ media.suspend(&client_context_id);
+ return;
}
+
+ self.title_changed();
+ self.dirty_all_nodes();
+ self.window()
+ .reflow(ReflowGoal::Full, ReflowReason::CachedPageNeededReflow);
+ self.window().resume();
+ media.resume(&client_context_id);
+
+ if self.ready_state.get() != DocumentReadyState::Complete {
+ return;
+ }
+
+ // html.spec.whatwg.org/multipage/#history-traversal
+ // Step 4.6
+ let document = Trusted::new(self);
+ self.window
+ .task_manager()
+ .dom_manipulation_task_source()
+ .queue(
+ task!(fire_pageshow_event: move || {
+ let document = document.root();
+ let window = document.window();
+ // Step 4.6.1
+ if document.page_showing.get() {
+ return;
+ }
+ // Step 4.6.2
+ document.page_showing.set(true);
+ // Step 4.6.4
+ let event = PageTransitionEvent::new(
+ window,
+ atom!("pageshow"),
+ false, // bubbles
+ false, // cancelable
+ true, // persisted
+ );
+ let event = event.upcast::<Event>();
+ event.set_trusted(true);
+ // FIXME(nox): Why are errors silenced here?
+ let _ = window.upcast::<EventTarget>().dispatch_event_with_target(
+ document.upcast(),
+ &event,
+ );
+ }),
+ self.window.upcast(),
+ )
+ .unwrap();
}
pub fn origin(&self) -> &MutableOrigin {
@@ -1436,7 +1443,8 @@ impl Document {
// https://w3c.github.io/uievents/#keys-cancelable-keys
if keyboard_event.state == KeyState::Down &&
- keyboard_event.key.legacy_charcode() != 0 &&
+ is_character_value_key(&(keyboard_event.key)) &&
+ !keyboard_event.is_composing &&
cancel_state != EventDefault::Prevented
{
// https://w3c.github.io/uievents/#keypress-event-order
@@ -2517,6 +2525,13 @@ impl Document {
}
}
+fn is_character_value_key(key: &Key) -> bool {
+ match key {
+ Key::Character(_) | Key::Enter => true,
+ _ => false,
+ }
+}
+
#[derive(MallocSizeOf, PartialEq)]
pub enum DocumentSource {
FromParser,
@@ -4741,7 +4756,7 @@ impl AnimationFrameCallback {
}
#[derive(Default, JSTraceable, MallocSizeOf)]
-#[must_root]
+#[unrooted_must_root_lint::must_root]
struct PendingInOrderScriptVec {
scripts: DomRefCell<VecDeque<PendingScript>>,
}
@@ -4779,7 +4794,7 @@ impl PendingInOrderScriptVec {
}
#[derive(JSTraceable, MallocSizeOf)]
-#[must_root]
+#[unrooted_must_root_lint::must_root]
struct PendingScript {
element: Dom<HTMLScriptElement>,
load: Option<ScriptResult>,
diff --git a/components/script/dom/documentorshadowroot.rs b/components/script/dom/documentorshadowroot.rs
index 594801584c8..724ea11da8c 100644
--- a/components/script/dom/documentorshadowroot.rs
+++ b/components/script/dom/documentorshadowroot.rs
@@ -28,7 +28,7 @@ use style::shared_lock::{SharedRwLock as StyleSharedRwLock, SharedRwLockReadGuar
use style::stylesheets::{CssRule, Origin, Stylesheet};
#[derive(Clone, JSTraceable, MallocSizeOf)]
-#[must_root]
+#[unrooted_must_root_lint::must_root]
pub struct StyleSheetInDocument {
#[ignore_malloc_size_of = "Arc"]
pub sheet: Arc<Stylesheet>,
@@ -76,7 +76,7 @@ impl ::style::stylesheets::StylesheetInDocument for StyleSheetInDocument {
}
// https://w3c.github.io/webcomponents/spec/shadow/#extensions-to-the-documentorshadowroot-mixin
-#[must_root]
+#[unrooted_must_root_lint::must_root]
#[derive(JSTraceable, MallocSizeOf)]
pub struct DocumentOrShadowRoot {
window: Dom<Window>,
diff --git a/components/script/dom/formdataevent.rs b/components/script/dom/formdataevent.rs
index f7ebb57bbfb..c380abf217a 100644
--- a/components/script/dom/formdataevent.rs
+++ b/components/script/dom/formdataevent.rs
@@ -5,7 +5,7 @@
use crate::dom::bindings::codegen::Bindings::EventBinding::EventMethods;
use crate::dom::bindings::codegen::Bindings::FormDataEventBinding;
use crate::dom::bindings::codegen::Bindings::FormDataEventBinding::FormDataEventMethods;
-use crate::dom::bindings::error::{Error, Fallible};
+use crate::dom::bindings::error::Fallible;
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
use crate::dom::bindings::root::{Dom, DomRoot};
@@ -56,21 +56,12 @@ impl FormDataEvent {
let bubbles = EventBubbles::from(init.parent.bubbles);
let cancelable = EventCancelable::from(init.parent.cancelable);
- let form_data = match init.formData {
- Some(ref form_data) => form_data.clone(),
- None => {
- return Err(Error::Type(
- "required member formData is undefined".to_string(),
- ));
- },
- };
-
let event = FormDataEvent::new(
&window.global(),
Atom::from(type_),
bubbles,
cancelable,
- &*form_data,
+ &*init.formData.clone(),
);
Ok(event)
diff --git a/components/script/dom/globalscope.rs b/components/script/dom/globalscope.rs
index 7d07e67f9ec..4896c59e048 100644
--- a/components/script/dom/globalscope.rs
+++ b/components/script/dom/globalscope.rs
@@ -39,6 +39,7 @@ use crate::task_source::networking::NetworkingTaskSource;
use crate::task_source::performance_timeline::PerformanceTimelineTaskSource;
use crate::task_source::port_message::PortMessageQueue;
use crate::task_source::remote_event::RemoteEventTaskSource;
+use crate::task_source::timer::TimerTaskSource;
use crate::task_source::websocket::WebsocketTaskSource;
use crate::task_source::TaskSource;
use crate::task_source::TaskSourceName;
@@ -134,8 +135,13 @@ pub struct GlobalScope {
/// including resource_thread, filemanager_thread and storage_thread
resource_threads: ResourceThreads,
+ /// The mechanism by which time-outs and intervals are scheduled.
+ /// <https://html.spec.whatwg.org/multipage/#timers>
timers: OneshotTimers,
+ /// Have timers been initialized?
+ init_timers: Cell<bool>,
+
/// The origin of the globalscope
origin: MutableOrigin,
@@ -188,6 +194,13 @@ struct MessageListener {
context: Trusted<GlobalScope>,
}
+/// A wrapper between timer events coming in over IPC, and the event-loop.
+struct TimerListener {
+ canceller: TaskCanceller,
+ task_source: TimerTaskSource,
+ context: Trusted<GlobalScope>,
+}
+
/// Data representing a message-port managed by this global.
#[derive(JSTraceable, MallocSizeOf)]
pub enum ManagedMessagePort {
@@ -212,18 +225,82 @@ pub enum MessagePortState {
UnManaged,
}
+impl TimerListener {
+ /// Handle a timer-event coming-in over IPC,
+ /// by queuing the appropriate task on the relevant event-loop.
+ fn handle(&self, event: TimerEvent) {
+ let context = self.context.clone();
+ // Step 18, queue a task,
+ // https://html.spec.whatwg.org/multipage/#timer-initialisation-steps
+ let _ = self.task_source.queue_with_canceller(
+ task!(timer_event: move || {
+ let global = context.root();
+ let TimerEvent(source, id) = event;
+ match source {
+ TimerSource::FromWorker => {
+ global.downcast::<WorkerGlobalScope>().expect("Window timer delivered to worker");
+ },
+ TimerSource::FromWindow(pipeline) => {
+ assert_eq!(pipeline, global.pipeline_id());
+ global.downcast::<Window>().expect("Worker timer delivered to window");
+ },
+ };
+ // Step 7, substeps run in a task.
+ global.fire_timer(id);
+ }),
+ &self.canceller,
+ );
+ }
+}
+
impl MessageListener {
/// A new message came in, handle it via a task enqueued on the event-loop.
/// A task is required, since we are using a trusted globalscope,
/// and we can only access the root from the event-loop.
fn notify(&self, msg: MessagePortMsg) {
match msg {
- MessagePortMsg::CompleteTransfer(port_id, tasks) => {
+ MessagePortMsg::CompleteTransfer(ports) => {
let context = self.context.clone();
let _ = self.task_source.queue_with_canceller(
task!(process_complete_transfer: move || {
let global = context.root();
- global.complete_port_transfer(port_id, tasks);
+
+ let router_id = match global.port_router_id() {
+ Some(router_id) => router_id,
+ None => {
+ // If not managing any ports, no transfer can succeed,
+ // so just send back everything.
+ let _ = global.script_to_constellation_chan().send(
+ ScriptMsg::MessagePortTransferResult(None, vec![], ports),
+ );
+ return;
+ }
+ };
+
+ let mut succeeded = vec![];
+ let mut failed = HashMap::new();
+
+ for (id, buffer) in ports.into_iter() {
+ if global.is_managing_port(&id) {
+ succeeded.push(id.clone());
+ global.complete_port_transfer(id, buffer);
+ } else {
+ failed.insert(id, buffer);
+ }
+ }
+ let _ = global.script_to_constellation_chan().send(
+ ScriptMsg::MessagePortTransferResult(Some(router_id), succeeded, failed),
+ );
+ }),
+ &self.canceller,
+ );
+ },
+ MessagePortMsg::CompletePendingTransfer(port_id, buffer) => {
+ let context = self.context.clone();
+ let _ = self.task_source.queue_with_canceller(
+ task!(complete_pending: move || {
+ let global = context.root();
+ global.complete_port_transfer(port_id, buffer);
}),
&self.canceller,
);
@@ -261,7 +338,6 @@ impl GlobalScope {
script_to_constellation_chan: ScriptToConstellationChan,
scheduler_chan: IpcSender<TimerSchedulerMsg>,
resource_threads: ResourceThreads,
- timer_event_chan: IpcSender<TimerEvent>,
origin: MutableOrigin,
microtask_queue: Rc<MicrotaskQueue>,
is_headless: bool,
@@ -282,7 +358,8 @@ impl GlobalScope {
scheduler_chan: scheduler_chan.clone(),
in_error_reporting_mode: Default::default(),
resource_threads,
- timers: OneshotTimers::new(timer_event_chan, scheduler_chan),
+ timers: OneshotTimers::new(scheduler_chan),
+ init_timers: Default::default(),
origin,
microtask_queue,
list_auto_close_worker: Default::default(),
@@ -294,6 +371,55 @@ impl GlobalScope {
}
}
+ /// The message-port router Id of the global, if any
+ fn port_router_id(&self) -> Option<MessagePortRouterId> {
+ if let MessagePortState::Managed(id, _message_ports) = &*self.message_port_state.borrow() {
+ Some(id.clone())
+ } else {
+ None
+ }
+ }
+
+ /// Is this global managing a given port?
+ fn is_managing_port(&self, port_id: &MessagePortId) -> bool {
+ if let MessagePortState::Managed(_router_id, message_ports) =
+ &*self.message_port_state.borrow()
+ {
+ return message_ports.contains_key(port_id);
+ }
+ false
+ }
+
+ /// Setup the IPC-to-event-loop glue for timers to schedule themselves.
+ fn setup_timers(&self) {
+ if self.init_timers.get() {
+ return;
+ }
+ self.init_timers.set(true);
+
+ let (timer_ipc_chan, timer_ipc_port) = ipc::channel().unwrap();
+ self.timers.setup_scheduling(timer_ipc_chan);
+
+ // Setup route from IPC to task-queue for the timer-task-source.
+ let context = Trusted::new(&*self);
+ let (task_source, canceller) = (
+ self.timer_task_source(),
+ self.task_canceller(TaskSourceName::Timer),
+ );
+ let timer_listener = TimerListener {
+ context,
+ task_source,
+ canceller,
+ };
+ ROUTER.add_route(
+ timer_ipc_port.to_opaque(),
+ Box::new(move |message| {
+ let event = message.to().unwrap();
+ timer_listener.handle(event);
+ }),
+ );
+ }
+
/// Complete the transfer of a message-port.
fn complete_port_transfer(&self, port_id: MessagePortId, tasks: VecDeque<PortMessageTask>) {
let should_start = if let MessagePortState::Managed(_id, message_ports) =
@@ -301,7 +427,7 @@ impl GlobalScope {
{
match message_ports.get_mut(&port_id) {
None => {
- panic!("CompleteTransfer msg received in a global not managing the port.");
+ panic!("complete_port_transfer called for an unknown port.");
},
Some(ManagedMessagePort::Pending(_, _)) => {
panic!("CompleteTransfer msg received for a pending port.");
@@ -312,7 +438,7 @@ impl GlobalScope {
},
}
} else {
- return warn!("CompleteTransfer msg received in a global not managing any ports.");
+ panic!("complete_port_transfer called for an unknown port.");
};
if should_start {
self.start_message_port(&port_id);
@@ -554,22 +680,25 @@ impl GlobalScope {
_ => None,
})
.collect();
- for id in to_be_added {
+ for id in to_be_added.iter() {
let (id, port_info) = message_ports
.remove_entry(&id)
.expect("Collected port-id to match an entry");
- if let ManagedMessagePort::Pending(port_impl, dom_port) = port_info {
- let _ = self
- .script_to_constellation_chan()
- .send(ScriptMsg::NewMessagePort(
- router_id.clone(),
- port_impl.message_port_id().clone(),
- ));
- let new_port_info = ManagedMessagePort::Added(port_impl, dom_port);
- let present = message_ports.insert(id, new_port_info);
- assert!(present.is_none());
+ match port_info {
+ ManagedMessagePort::Pending(port_impl, dom_port) => {
+ let new_port_info = ManagedMessagePort::Added(port_impl, dom_port);
+ let present = message_ports.insert(id, new_port_info);
+ assert!(present.is_none());
+ },
+ _ => panic!("Only pending ports should be found in to_be_added"),
}
}
+ let _ =
+ self.script_to_constellation_chan()
+ .send(ScriptMsg::CompleteMessagePortTransfer(
+ router_id.clone(),
+ to_be_added,
+ ));
} else {
warn!("maybe_add_pending_ports called on a global not managing any ports.");
}
@@ -1005,6 +1134,18 @@ impl GlobalScope {
unreachable!();
}
+ /// `TaskSource` to send messages to the timer queue of
+ /// this global scope.
+ pub fn timer_task_source(&self) -> TimerTaskSource {
+ if let Some(window) = self.downcast::<Window>() {
+ return window.task_manager().timer_task_source();
+ }
+ if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
+ return worker.timer_task_source();
+ }
+ unreachable!();
+ }
+
/// `TaskSource` to send messages to the remote-event task source of
/// this global scope.
pub fn remote_event_task_source(&self) -> RemoteEventTaskSource {
@@ -1087,11 +1228,13 @@ impl GlobalScope {
)
}
+ /// <https://html.spec.whatwg.org/multipage/#timer-initialisation-steps>
pub fn schedule_callback(
&self,
callback: OneshotTimerCallback,
duration: MsDuration,
) -> OneshotTimerHandle {
+ self.setup_timers();
self.timers
.schedule_callback(callback, duration, self.timer_source())
}
@@ -1100,6 +1243,7 @@ impl GlobalScope {
self.timers.unschedule_callback(handle);
}
+ /// <https://html.spec.whatwg.org/multipage/#timer-initialisation-steps>
pub fn set_timeout_or_interval(
&self,
callback: TimerCallback,
@@ -1107,6 +1251,7 @@ impl GlobalScope {
timeout: i32,
is_interval: IsInterval,
) -> i32 {
+ self.setup_timers();
self.timers.set_timeout_or_interval(
self,
callback,
@@ -1118,27 +1263,27 @@ impl GlobalScope {
}
pub fn clear_timeout_or_interval(&self, handle: i32) {
- self.timers.clear_timeout_or_interval(self, handle)
+ self.timers.clear_timeout_or_interval(self, handle);
}
pub fn fire_timer(&self, handle: TimerEventId) {
- self.timers.fire_timer(handle, self)
+ self.timers.fire_timer(handle, self);
}
pub fn resume(&self) {
- self.timers.resume()
+ self.timers.resume();
}
pub fn suspend(&self) {
- self.timers.suspend()
+ self.timers.suspend();
}
pub fn slow_down_timers(&self) {
- self.timers.slow_down()
+ self.timers.slow_down();
}
pub fn speed_up_timers(&self) {
- self.timers.speed_up()
+ self.timers.speed_up();
}
fn timer_source(&self) -> TimerSource {
diff --git a/components/script/dom/gpu.rs b/components/script/dom/gpu.rs
new file mode 100644
index 00000000000..4e47620052e
--- /dev/null
+++ b/components/script/dom/gpu.rs
@@ -0,0 +1,161 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+use crate::compartments::InCompartment;
+use crate::dom::bindings::codegen::Bindings::GPUBinding::GPURequestAdapterOptions;
+use crate::dom::bindings::codegen::Bindings::GPUBinding::{self, GPUMethods, GPUPowerPreference};
+use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods;
+use crate::dom::bindings::error::Error;
+use crate::dom::bindings::refcounted::{Trusted, TrustedPromise};
+use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
+use crate::dom::bindings::root::DomRoot;
+use crate::dom::bindings::str::DOMString;
+use crate::dom::globalscope::GlobalScope;
+use crate::dom::gpuadapter::GPUAdapter;
+use crate::dom::promise::Promise;
+use crate::task_source::TaskSource;
+use dom_struct::dom_struct;
+use ipc_channel::ipc::{self, IpcSender};
+use ipc_channel::router::ROUTER;
+use js::jsapi::Heap;
+use std::rc::Rc;
+use webgpu::wgpu;
+use webgpu::{WebGPU, WebGPURequest, WebGPUResponse, WebGPUResponseResult};
+
+#[dom_struct]
+pub struct GPU {
+ reflector_: Reflector,
+}
+
+impl GPU {
+ pub fn new_inherited() -> GPU {
+ GPU {
+ reflector_: Reflector::new(),
+ }
+ }
+
+ pub fn new(global: &GlobalScope) -> DomRoot<GPU> {
+ reflect_dom_object(Box::new(GPU::new_inherited()), global, GPUBinding::Wrap)
+ }
+
+ fn wgpu_channel(&self) -> Option<WebGPU> {
+ self.global().as_window().webgpu_channel()
+ }
+}
+
+pub trait AsyncWGPUListener {
+ fn handle_response(&self, response: WebGPUResponse, promise: &Rc<Promise>);
+}
+
+struct WGPUResponse<T: AsyncWGPUListener + DomObject> {
+ trusted: TrustedPromise,
+ receiver: Trusted<T>,
+}
+
+impl<T: AsyncWGPUListener + DomObject> WGPUResponse<T> {
+ #[allow(unrooted_must_root)]
+ fn response(self, response: WebGPUResponseResult) {
+ let promise = self.trusted.root();
+ match response {
+ Ok(response) => self.receiver.root().handle_response(response, &promise),
+ Err(error) => promise.reject_error(Error::Type(format!(
+ "Received error from WebGPU thread: {}",
+ error
+ ))),
+ }
+ }
+}
+
+pub fn response_async<T: AsyncWGPUListener + DomObject + 'static>(
+ promise: &Rc<Promise>,
+ receiver: &T,
+) -> IpcSender<WebGPUResponseResult> {
+ let (action_sender, action_receiver) = ipc::channel().unwrap();
+ let (task_source, canceller) = receiver
+ .global()
+ .as_window()
+ .task_manager()
+ .dom_manipulation_task_source_with_canceller();
+ let mut trusted = Some(TrustedPromise::new(promise.clone()));
+ let trusted_receiver = Trusted::new(receiver);
+ ROUTER.add_route(
+ action_receiver.to_opaque(),
+ Box::new(move |message| {
+ let trusted = if let Some(trusted) = trusted.take() {
+ trusted
+ } else {
+ error!("WebGPU callback called twice!");
+ return;
+ };
+
+ let context = WGPUResponse {
+ trusted,
+ receiver: trusted_receiver.clone(),
+ };
+ let result = task_source.queue_with_canceller(
+ task!(process_webgpu_task: move|| {
+ context.response(message.to().unwrap());
+ }),
+ &canceller,
+ );
+ if let Err(err) = result {
+ error!("Failed to queue GPU listener-task: {:?}", err);
+ }
+ }),
+ );
+ action_sender
+}
+
+impl GPUMethods for GPU {
+ // https://gpuweb.github.io/gpuweb/#dom-gpu-requestadapter
+ fn RequestAdapter(
+ &self,
+ options: &GPURequestAdapterOptions,
+ comp: InCompartment,
+ ) -> Rc<Promise> {
+ let promise = Promise::new_in_current_compartment(&self.global(), comp);
+ let sender = response_async(&promise, self);
+ let power_preference = match options.powerPreference {
+ Some(GPUPowerPreference::Low_power) => wgpu::PowerPreference::LowPower,
+ Some(GPUPowerPreference::High_performance) => wgpu::PowerPreference::HighPerformance,
+ None => wgpu::PowerPreference::Default,
+ };
+ let id = self.global().as_window().Navigator().create_adapter_id();
+
+ match self.wgpu_channel() {
+ Some(channel) => {
+ channel
+ .0
+ .send(WebGPURequest::RequestAdapter(
+ sender,
+ wgpu::RequestAdapterOptions { power_preference },
+ id,
+ ))
+ .unwrap();
+ },
+ None => promise.reject_error(Error::Type("No WebGPU thread...".to_owned())),
+ };
+ promise
+ }
+}
+
+impl AsyncWGPUListener for GPU {
+ fn handle_response(&self, response: WebGPUResponse, promise: &Rc<Promise>) {
+ match response {
+ WebGPUResponse::RequestAdapter(name, adapter) => {
+ let adapter = GPUAdapter::new(
+ &self.global(),
+ DOMString::from(name),
+ Heap::default(),
+ adapter,
+ );
+ promise.resolve_native(&adapter);
+ },
+ response => promise.reject_error(Error::Type(format!(
+ "Wrong response received for GPU from WebGPU thread {:?}",
+ response,
+ ))),
+ }
+ }
+}
diff --git a/components/script/dom/gpuadapter.rs b/components/script/dom/gpuadapter.rs
new file mode 100644
index 00000000000..ec970439e8a
--- /dev/null
+++ b/components/script/dom/gpuadapter.rs
@@ -0,0 +1,63 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+use crate::dom::bindings::codegen::Bindings::GPUAdapterBinding::{self, GPUAdapterMethods};
+use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
+use crate::dom::bindings::root::DomRoot;
+use crate::dom::bindings::str::DOMString;
+use crate::dom::globalscope::GlobalScope;
+use crate::script_runtime::JSContext as SafeJSContext;
+use dom_struct::dom_struct;
+use js::jsapi::{Heap, JSObject};
+use std::ptr::NonNull;
+use webgpu::WebGPUAdapter;
+
+#[dom_struct]
+pub struct GPUAdapter {
+ reflector_: Reflector,
+ name: DOMString,
+ #[ignore_malloc_size_of = "mozjs"]
+ extensions: Heap<*mut JSObject>,
+ adapter: WebGPUAdapter,
+}
+
+impl GPUAdapter {
+ pub fn new_inherited(
+ name: DOMString,
+ extensions: Heap<*mut JSObject>,
+ adapter: WebGPUAdapter,
+ ) -> GPUAdapter {
+ GPUAdapter {
+ reflector_: Reflector::new(),
+ name,
+ extensions,
+ adapter,
+ }
+ }
+
+ pub fn new(
+ global: &GlobalScope,
+ name: DOMString,
+ extensions: Heap<*mut JSObject>,
+ adapter: WebGPUAdapter,
+ ) -> DomRoot<GPUAdapter> {
+ reflect_dom_object(
+ Box::new(GPUAdapter::new_inherited(name, extensions, adapter)),
+ global,
+ GPUAdapterBinding::Wrap,
+ )
+ }
+}
+
+impl GPUAdapterMethods for GPUAdapter {
+ // https://gpuweb.github.io/gpuweb/#dom-gpuadapter-name
+ fn Name(&self) -> DOMString {
+ self.name.clone()
+ }
+
+ // https://gpuweb.github.io/gpuweb/#dom-gpuadapter-extensions
+ fn Extensions(&self, _cx: SafeJSContext) -> NonNull<JSObject> {
+ NonNull::new(self.extensions.get()).unwrap()
+ }
+}
diff --git a/components/script/dom/htmlcanvaselement.rs b/components/script/dom/htmlcanvaselement.rs
index 9e638539995..89410a6b6b0 100644
--- a/components/script/dom/htmlcanvaselement.rs
+++ b/components/script/dom/htmlcanvaselement.rs
@@ -28,6 +28,7 @@ use crate::dom::webgl2renderingcontext::WebGL2RenderingContext;
use crate::dom::webglrenderingcontext::{
LayoutCanvasWebGLRenderingContextHelpers, WebGLRenderingContext,
};
+use crate::euclidext::Size2DExt;
use crate::script_runtime::JSContext;
use base64;
use canvas_traits::canvas::{CanvasId, CanvasMsg, FromScriptMsg};
@@ -49,7 +50,7 @@ use style::attr::{AttrValue, LengthOrPercentageOrAuto};
const DEFAULT_WIDTH: u32 = 300;
const DEFAULT_HEIGHT: u32 = 150;
-#[must_root]
+#[unrooted_must_root_lint::must_root]
#[derive(Clone, JSTraceable, MallocSizeOf)]
pub enum CanvasContext {
Context2d(Dom<CanvasRenderingContext2D>),
@@ -94,7 +95,9 @@ impl HTMLCanvasElement {
let size = self.get_size();
if let Some(ref context) = *self.context.borrow() {
match *context {
- CanvasContext::Context2d(ref context) => context.set_bitmap_dimensions(size),
+ CanvasContext::Context2d(ref context) => {
+ context.set_canvas_bitmap_dimensions(size.to_u64())
+ },
CanvasContext::WebGL(ref context) => context.recreate(size),
CanvasContext::WebGL2(ref context) => context.recreate(size),
}
diff --git a/components/script/dom/htmliframeelement.rs b/components/script/dom/htmliframeelement.rs
index f5a820458c2..b70663a6949 100644
--- a/components/script/dom/htmliframeelement.rs
+++ b/components/script/dom/htmliframeelement.rs
@@ -28,7 +28,6 @@ use crate::dom::windowproxy::WindowProxy;
use crate::script_thread::ScriptThread;
use crate::task_source::TaskSource;
use dom_struct::dom_struct;
-use euclid::Size2D;
use html5ever::{LocalName, Prefix};
use ipc_channel::ipc;
use msg::constellation_msg::{BrowsingContextId, PipelineId, TopLevelBrowsingContextId};
@@ -131,10 +130,12 @@ impl HTMLIFrameElement {
let document = document_from_node(self);
- let mut load_blocker = self.load_blocker.borrow_mut();
- // Any oustanding load is finished from the point of view of the blocked
- // document; the new navigation will continue blocking it.
- LoadBlocker::terminate(&mut load_blocker);
+ {
+ let mut load_blocker = self.load_blocker.borrow_mut();
+ // Any oustanding load is finished from the point of view of the blocked
+ // document; the new navigation will continue blocking it.
+ LoadBlocker::terminate(&mut load_blocker);
+ }
if load_data.url.scheme() == "javascript" {
let window_proxy = self.GetContentWindow();
@@ -151,6 +152,7 @@ impl HTMLIFrameElement {
match load_data.js_eval_result {
Some(JsEvalResult::NoContent) => (),
_ => {
+ let mut load_blocker = self.load_blocker.borrow_mut();
*load_blocker = Some(LoadBlocker::new(
&*document,
LoadType::Subframe(load_data.url.clone()),
@@ -173,6 +175,13 @@ impl HTMLIFrameElement {
replace: replace,
};
+ let window_size = WindowSizeData {
+ initial_viewport: window
+ .inner_window_dimensions_query(browsing_context_id)
+ .unwrap_or_default(),
+ device_pixel_ratio: window.device_pixel_ratio(),
+ };
+
match nav_type {
NavigationType::InitialAboutBlank => {
let (pipeline_sender, pipeline_receiver) = ipc::channel().unwrap();
@@ -184,6 +193,7 @@ impl HTMLIFrameElement {
load_data: load_data.clone(),
old_pipeline_id: old_pipeline_id,
sandbox: sandboxed,
+ window_size,
};
global_scope
.script_to_constellation_chan()
@@ -198,13 +208,7 @@ impl HTMLIFrameElement {
opener: None,
load_data: load_data,
pipeline_port: pipeline_receiver,
- window_size: WindowSizeData {
- initial_viewport: {
- let rect = self.upcast::<Node>().bounding_content_box_or_zero();
- Size2D::new(rect.size.width.to_f32_px(), rect.size.height.to_f32_px())
- },
- device_pixel_ratio: window.device_pixel_ratio(),
- },
+ window_size,
};
self.pipeline_id.set(Some(new_pipeline_id));
@@ -216,6 +220,7 @@ impl HTMLIFrameElement {
load_data: load_data,
old_pipeline_id: old_pipeline_id,
sandbox: sandboxed,
+ window_size,
};
global_scope
.script_to_constellation_chan()
@@ -227,7 +232,30 @@ impl HTMLIFrameElement {
/// <https://html.spec.whatwg.org/multipage/#process-the-iframe-attributes>
fn process_the_iframe_attributes(&self, mode: ProcessingMode) {
- // TODO: srcdoc
+ if self
+ .upcast::<Element>()
+ .has_attribute(&local_name!("srcdoc"))
+ {
+ let url = ServoUrl::parse("about:srcdoc").unwrap();
+ let document = document_from_node(self);
+ let window = window_from_node(self);
+ let pipeline_id = Some(window.upcast::<GlobalScope>().pipeline_id());
+ let mut load_data = LoadData::new(
+ LoadOrigin::Script(document.origin().immutable().clone()),
+ url,
+ pipeline_id,
+ Some(Referrer::ReferrerUrl(document.url())),
+ document.get_referrer_policy(),
+ );
+ let element = self.upcast::<Element>();
+ load_data.srcdoc = String::from(element.get_string_attribute(&local_name!("srcdoc")));
+ self.navigate_or_reload_child_browsing_context(
+ load_data,
+ NavigationType::InitialAboutBlank,
+ HistoryEntryReplacement::Disabled,
+ );
+ return;
+ }
let window = window_from_node(self);
@@ -478,6 +506,12 @@ impl HTMLIFrameElementMethods for HTMLIFrameElement {
// https://html.spec.whatwg.org/multipage/#dom-iframe-src
make_url_setter!(SetSrc, "src");
+ // https://html.spec.whatwg.org/multipage/#dom-iframe-srcdoc
+ make_getter!(Srcdoc, "srcdoc");
+
+ // https://html.spec.whatwg.org/multipage/#dom-iframe-srcdoc
+ make_setter!(SetSrcdoc, "srcdoc");
+
// https://html.spec.whatwg.org/multipage/#dom-iframe-sandbox
fn Sandbox(&self) -> DomRoot<DOMTokenList> {
self.sandbox
@@ -578,13 +612,29 @@ impl VirtualMethods for HTMLIFrameElement {
modes
}));
},
+ &local_name!("srcdoc") => {
+ // https://html.spec.whatwg.org/multipage/#the-iframe-element:the-iframe-element-9
+ // "Whenever an iframe element with a non-null nested browsing context has its
+ // srcdoc attribute set, changed, or removed, the user agent must process the
+ // iframe attributes."
+ // but we can't check that directly, since the child browsing context
+ // may be in a different script thread. Instead, we check to see if the parent
+ // is in a document tree and has a browsing context, which is what causes
+ // the child browsing context to be created.
+
+ // trigger the processing of iframe attributes whenever "srcdoc" attribute is set, changed or removed
+ if self.upcast::<Node>().is_connected_with_browsing_context() {
+ debug!("iframe srcdoc modified while in browsing context.");
+ self.process_the_iframe_attributes(ProcessingMode::NotFirstTime);
+ }
+ },
&local_name!("src") => {
// https://html.spec.whatwg.org/multipage/#the-iframe-element
// "Similarly, whenever an iframe element with a non-null nested browsing context
// but with no srcdoc attribute specified has its src attribute set, changed, or removed,
// the user agent must process the iframe attributes,"
// but we can't check that directly, since the child browsing context
- // may be in a different script thread. Instread, we check to see if the parent
+ // may be in a different script thread. Instead, we check to see if the parent
// is in a document tree and has a browsing context, which is what causes
// the child browsing context to be created.
if self.upcast::<Node>().is_connected_with_browsing_context() {
diff --git a/components/script/dom/htmlimageelement.rs b/components/script/dom/htmlimageelement.rs
index 525f35d3e95..5b6bd321534 100644
--- a/components/script/dom/htmlimageelement.rs
+++ b/components/script/dom/htmlimageelement.rs
@@ -133,7 +133,7 @@ enum ImageRequestPhase {
Current,
}
#[derive(JSTraceable, MallocSizeOf)]
-#[must_root]
+#[unrooted_must_root_lint::must_root]
struct ImageRequest {
state: State,
parsed_url: Option<ServoUrl>,
@@ -927,10 +927,7 @@ impl HTMLImageElement {
*self.last_selected_source.borrow_mut() = selected_source.clone();
// Step 6, check the list of available images
- if !selected_source
- .as_ref()
- .map_or(false, |source| source.is_empty())
- {
+ if let Some(src) = selected_source {
if let Ok(img_url) = base_url.join(&src) {
let image_cache = window.image_cache();
let response = image_cache.find_image_or_metadata(
diff --git a/components/script/dom/htmlinputelement.rs b/components/script/dom/htmlinputelement.rs
index 60b5cb9bcb1..5fdbad5c1bd 100755
--- a/components/script/dom/htmlinputelement.rs
+++ b/components/script/dom/htmlinputelement.rs
@@ -237,7 +237,7 @@ pub struct HTMLInputElement {
}
#[derive(JSTraceable)]
-#[must_root]
+#[unrooted_must_root_lint::must_root]
#[derive(MallocSizeOf)]
struct InputActivationState {
indeterminate: bool,
diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs
index 13c5cd126c7..651084cfb84 100644
--- a/components/script/dom/htmlmediaelement.rs
+++ b/components/script/dom/htmlmediaelement.rs
@@ -15,8 +15,10 @@ use crate::dom::bindings::codegen::Bindings::HTMLMediaElementBinding::HTMLMediaE
use crate::dom::bindings::codegen::Bindings::HTMLSourceElementBinding::HTMLSourceElementMethods;
use crate::dom::bindings::codegen::Bindings::MediaErrorBinding::MediaErrorConstants::*;
use crate::dom::bindings::codegen::Bindings::MediaErrorBinding::MediaErrorMethods;
+use crate::dom::bindings::codegen::Bindings::NavigatorBinding::NavigatorBinding::NavigatorMethods;
use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeBinding::NodeMethods;
use crate::dom::bindings::codegen::Bindings::TextTrackBinding::{TextTrackKind, TextTrackMode};
+use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods;
use crate::dom::bindings::codegen::InheritTypes::{ElementTypeId, HTMLElementTypeId};
use crate::dom::bindings::codegen::InheritTypes::{HTMLMediaElementTypeId, NodeTypeId};
use crate::dom::bindings::codegen::UnionTypes::{
@@ -65,6 +67,7 @@ use crate::script_thread::ScriptThread;
use crate::task_source::TaskSource;
use dom_struct::dom_struct;
use embedder_traits::resources::{self, Resource as EmbedderResource};
+use embedder_traits::{MediaSessionEvent, MediaSessionPlaybackState};
use euclid::default::Size2D;
use headers::{ContentLength, ContentRange, HeaderMapExt};
use html5ever::{LocalName, Prefix};
@@ -78,8 +81,10 @@ use net_traits::request::{Destination, Referrer};
use net_traits::{CoreResourceMsg, FetchChannels, FetchMetadata, FetchResponseListener, Metadata};
use net_traits::{NetworkError, ResourceFetchTiming, ResourceTimingType};
use script_layout_interface::HTMLMediaData;
+use script_traits::WebrenderIpcSender;
use servo_config::pref;
-use servo_media::player::frame::{Frame, FrameRenderer};
+use servo_media::player::audio::AudioRenderer;
+use servo_media::player::video::{VideoFrame, VideoFrameRenderer};
use servo_media::player::{PlaybackState, Player, PlayerError, PlayerEvent, SeekLock, StreamType};
use servo_media::{ClientContextId, ServoMedia, SupportsMediaType};
use servo_url::ServoUrl;
@@ -91,8 +96,7 @@ use std::rc::Rc;
use std::sync::{Arc, Mutex};
use time::{self, Duration, Timespec};
use webrender_api::{ExternalImageData, ExternalImageId, ExternalImageType, TextureTarget};
-use webrender_api::{ImageData, ImageDescriptor, ImageFormat, ImageKey, RenderApi};
-use webrender_api::{RenderApiSender, Transaction};
+use webrender_api::{ImageData, ImageDescriptor, ImageFormat, ImageKey, Transaction};
#[derive(PartialEq)]
enum FrameStatus {
@@ -100,10 +104,10 @@ enum FrameStatus {
Unlocked,
}
-struct FrameHolder(FrameStatus, Frame);
+struct FrameHolder(FrameStatus, VideoFrame);
impl FrameHolder {
- fn new(frame: Frame) -> FrameHolder {
+ fn new(frame: VideoFrame) -> FrameHolder {
FrameHolder(FrameStatus::Unlocked, frame)
}
@@ -119,7 +123,7 @@ impl FrameHolder {
};
}
- fn set(&mut self, new_frame: Frame) {
+ fn set(&mut self, new_frame: VideoFrame) {
if self.0 == FrameStatus::Unlocked {
self.1 = new_frame
};
@@ -137,14 +141,14 @@ impl FrameHolder {
}
}
- fn get_frame(&self) -> Frame {
+ fn get_frame(&self) -> VideoFrame {
self.1.clone()
}
}
pub struct MediaFrameRenderer {
player_id: Option<u64>,
- api: RenderApi,
+ api: WebrenderIpcSender,
current_frame: Option<(ImageKey, i32, i32)>,
old_frame: Option<ImageKey>,
very_old_frame: Option<ImageKey>,
@@ -152,10 +156,10 @@ pub struct MediaFrameRenderer {
}
impl MediaFrameRenderer {
- fn new(render_api_sender: RenderApiSender) -> Self {
+ fn new(render_api_sender: WebrenderIpcSender) -> Self {
Self {
player_id: None,
- api: render_api_sender.create_api(),
+ api: render_api_sender,
current_frame: None,
old_frame: None,
very_old_frame: None,
@@ -170,8 +174,8 @@ impl MediaFrameRenderer {
}
}
-impl FrameRenderer for MediaFrameRenderer {
- fn render(&mut self, frame: Frame) {
+impl VideoFrameRenderer for MediaFrameRenderer {
+ fn render(&mut self, frame: VideoFrame) {
let mut txn = Transaction::new();
if let Some(old_image_key) = mem::replace(&mut self.very_old_frame, self.old_frame.take()) {
@@ -268,7 +272,7 @@ impl FrameRenderer for MediaFrameRenderer {
}
}
-#[must_root]
+#[unrooted_must_root_lint::must_root]
#[derive(JSTraceable, MallocSizeOf)]
enum SrcObject {
MediaStream(Dom<MediaStream>),
@@ -325,7 +329,9 @@ pub struct HTMLMediaElement {
#[ignore_malloc_size_of = "servo_media"]
player: DomRefCell<Option<Arc<Mutex<dyn Player>>>>,
#[ignore_malloc_size_of = "Arc"]
- frame_renderer: Arc<Mutex<MediaFrameRenderer>>,
+ video_renderer: Arc<Mutex<MediaFrameRenderer>>,
+ #[ignore_malloc_size_of = "Arc"]
+ audio_renderer: DomRefCell<Option<Arc<Mutex<dyn AudioRenderer>>>>,
/// https://html.spec.whatwg.org/multipage/#show-poster-flag
show_poster: Cell<bool>,
/// https://html.spec.whatwg.org/multipage/#dom-media-duration
@@ -410,9 +416,10 @@ impl HTMLMediaElement {
pending_play_promises: Default::default(),
in_flight_play_promises_queue: Default::default(),
player: Default::default(),
- frame_renderer: Arc::new(Mutex::new(MediaFrameRenderer::new(
+ video_renderer: Arc::new(Mutex::new(MediaFrameRenderer::new(
document.window().get_webrender_api_sender(),
))),
+ audio_renderer: Default::default(),
show_poster: Cell::new(true),
duration: Cell::new(f64::NAN),
playback_position: Cell::new(0.),
@@ -588,7 +595,6 @@ impl HTMLMediaElement {
match (old_ready_state, ready_state) {
(ReadyState::HaveNothing, ReadyState::HaveMetadata) => {
task_source.queue_simple_event(self.upcast(), atom!("loadedmetadata"), &window);
-
// No other steps are applicable in this case.
return;
},
@@ -1293,7 +1299,7 @@ impl HTMLMediaElement {
// Step 6.
if let ImageResponse::Loaded(image, _) = image {
- self.frame_renderer
+ self.video_renderer
.lock()
.unwrap()
.render_poster_frame(image);
@@ -1325,11 +1331,14 @@ impl HTMLMediaElement {
let window = window_from_node(self);
let (action_sender, action_receiver) = ipc::channel::<PlayerEvent>().unwrap();
- let renderer: Option<Arc<Mutex<dyn FrameRenderer>>> = match self.media_type_id() {
+ let video_renderer: Option<Arc<Mutex<dyn VideoFrameRenderer>>> = match self.media_type_id()
+ {
HTMLMediaElementTypeId::HTMLAudioElement => None,
- HTMLMediaElementTypeId::HTMLVideoElement => Some(self.frame_renderer.clone()),
+ HTMLMediaElementTypeId::HTMLVideoElement => Some(self.video_renderer.clone()),
};
+ let audio_renderer = self.audio_renderer.borrow().as_ref().map(|r| r.clone());
+
let pipeline_id = window
.pipeline_id()
.expect("Cannot create player outside of a pipeline");
@@ -1339,7 +1348,8 @@ impl HTMLMediaElement {
&client_context_id,
stream_type,
action_sender,
- renderer,
+ video_renderer,
+ audio_renderer,
Box::new(window.get_player_context()),
);
@@ -1385,7 +1395,7 @@ impl HTMLMediaElement {
.unwrap_or((0, None));
self.id.set(player_id);
- self.frame_renderer.lock().unwrap().player_id = Some(player_id);
+ self.video_renderer.lock().unwrap().player_id = Some(player_id);
if let Some(image_receiver) = image_receiver {
let trusted_node = Trusted::new(self);
@@ -1400,11 +1410,11 @@ impl HTMLMediaElement {
if let Err(err) = task_source.queue_with_canceller(
task!(handle_glplayer_message: move || {
trace!("GLPlayer message {:?}", msg);
- let frame_renderer = this.root().frame_renderer.clone();
+ let video_renderer = this.root().video_renderer.clone();
match msg {
GLPlayerMsgForward::Lock(sender) => {
- frame_renderer
+ video_renderer
.lock()
.unwrap()
.current_frame_holder
@@ -1415,7 +1425,7 @@ impl HTMLMediaElement {
});
},
GLPlayerMsgForward::Unlock() => {
- frame_renderer
+ video_renderer
.lock()
.unwrap()
.current_frame_holder
@@ -1527,7 +1537,7 @@ impl HTMLMediaElement {
)));
self.upcast::<EventTarget>().fire_event(atom!("error"));
},
- PlayerEvent::FrameUpdated => {
+ PlayerEvent::VideoFrameUpdated => {
self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
},
PlayerEvent::MetadataUpdated(ref metadata) => {
@@ -1717,6 +1727,17 @@ impl HTMLMediaElement {
if self.Controls() {
self.render_controls();
}
+
+ let global = self.global();
+ let window = global.as_window();
+
+ // Update the media session metadata title with the obtained metadata.
+ window.Navigator().MediaSession().update_title(
+ metadata
+ .title
+ .clone()
+ .unwrap_or(window.get_url().into_string()),
+ );
},
PlayerEvent::NeedData => {
// The player needs more data.
@@ -1774,13 +1795,33 @@ impl HTMLMediaElement {
};
ScriptThread::await_stable_state(Microtask::MediaElement(task));
},
- PlayerEvent::StateChanged(ref state) => match *state {
- PlaybackState::Paused => {
- if self.ready_state.get() == ReadyState::HaveMetadata {
- self.change_ready_state(ReadyState::HaveEnoughData);
- }
- },
- _ => {},
+ PlayerEvent::StateChanged(ref state) => {
+ let mut media_session_playback_state = MediaSessionPlaybackState::None_;
+ match *state {
+ PlaybackState::Paused => {
+ media_session_playback_state = MediaSessionPlaybackState::Paused;
+ if self.ready_state.get() == ReadyState::HaveMetadata {
+ self.change_ready_state(ReadyState::HaveEnoughData);
+ }
+ },
+ PlaybackState::Playing => {
+ media_session_playback_state = MediaSessionPlaybackState::Playing;
+ },
+ PlaybackState::Buffering => {
+ // Do not send the media session playback state change event
+ // in this case as a None_ state is expected to clean up the
+ // session.
+ return;
+ },
+ _ => {},
+ };
+ debug!(
+ "Sending media session event playback state changed to {:?}",
+ media_session_playback_state
+ );
+ self.send_media_session_event(MediaSessionEvent::PlaybackStateChange(
+ media_session_playback_state,
+ ));
},
}
}
@@ -1855,12 +1896,35 @@ impl HTMLMediaElement {
}
}
- pub fn get_current_frame(&self) -> Option<Frame> {
- match self.frame_renderer.lock().unwrap().current_frame_holder {
+ pub fn get_current_frame(&self) -> Option<VideoFrame> {
+ match self.video_renderer.lock().unwrap().current_frame_holder {
Some(ref holder) => Some(holder.get_frame()),
None => return None,
}
}
+
+ /// By default the audio is rendered through the audio sink automatically
+ /// selected by the servo-media Player instance. However, in some cases, like
+ /// the WebAudio MediaElementAudioSourceNode, we need to set a custom audio
+ /// renderer.
+ pub fn set_audio_renderer(&self, audio_renderer: Arc<Mutex<dyn AudioRenderer>>) {
+ *self.audio_renderer.borrow_mut() = Some(audio_renderer);
+ if let Some(ref player) = *self.player.borrow() {
+ if let Err(e) = player.lock().unwrap().stop() {
+ eprintln!("Could not stop player {:?}", e);
+ }
+ self.media_element_load_algorithm();
+ }
+ }
+
+ fn send_media_session_event(&self, event: MediaSessionEvent) {
+ let global = self.global();
+ let media_session = global.as_window().Navigator().MediaSession();
+
+ media_session.register_media_instance(&self);
+
+ media_session.send_event(event);
+ }
}
// XXX Placeholder for [https://github.com/servo/servo/issues/22293]
@@ -2365,7 +2429,7 @@ impl LayoutHTMLMediaElementHelpers for LayoutDom<HTMLMediaElement> {
fn data(&self) -> HTMLMediaData {
let media = unsafe { &*self.unsafe_get() };
HTMLMediaData {
- current_frame: media.frame_renderer.lock().unwrap().current_frame.clone(),
+ current_frame: media.video_renderer.lock().unwrap().current_frame.clone(),
}
}
}
diff --git a/components/script/dom/htmlvideoelement.rs b/components/script/dom/htmlvideoelement.rs
index 55990c1ffe5..69f8b9a85e6 100644
--- a/components/script/dom/htmlvideoelement.rs
+++ b/components/script/dom/htmlvideoelement.rs
@@ -35,7 +35,7 @@ use net_traits::{
CoreResourceMsg, FetchChannels, FetchMetadata, FetchResponseListener, FetchResponseMsg,
};
use net_traits::{NetworkError, ResourceFetchTiming, ResourceTimingType};
-use servo_media::player::frame::Frame;
+use servo_media::player::video::VideoFrame;
use servo_url::ServoUrl;
use std::cell::Cell;
use std::sync::{Arc, Mutex};
@@ -58,8 +58,8 @@ pub struct HTMLVideoElement {
/// is being fetched.
load_blocker: DomRefCell<Option<LoadBlocker>>,
/// A copy of the last frame
- #[ignore_malloc_size_of = "Frame"]
- last_frame: DomRefCell<Option<Frame>>,
+ #[ignore_malloc_size_of = "VideoFrame"]
+ last_frame: DomRefCell<Option<VideoFrame>>,
}
impl HTMLVideoElement {
diff --git a/components/script/dom/identityhub.rs b/components/script/dom/identityhub.rs
new file mode 100644
index 00000000000..489eaacc78d
--- /dev/null
+++ b/components/script/dom/identityhub.rs
@@ -0,0 +1,47 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+use webgpu::wgpu::{AdapterId, Backend, DeviceId, IdentityManager, SurfaceId};
+
+#[derive(Debug)]
+pub struct IdentityHub {
+ adapters: IdentityManager<AdapterId>,
+ devices: IdentityManager<DeviceId>,
+}
+
+impl IdentityHub {
+ fn new(backend: Backend) -> Self {
+ IdentityHub {
+ adapters: IdentityManager::new(backend),
+ devices: IdentityManager::new(backend),
+ }
+ }
+}
+
+#[derive(Debug)]
+pub struct Identities {
+ surface: IdentityManager<SurfaceId>,
+ hub: IdentityHub,
+}
+
+impl Identities {
+ pub fn new() -> Self {
+ let hub = if cfg!(any(target_os = "linux", target_os = "windows")) {
+ IdentityHub::new(Backend::Vulkan)
+ } else if cfg!(any(target_os = "ios", target_os = "macos")) {
+ IdentityHub::new(Backend::Metal)
+ } else {
+ IdentityHub::new(Backend::Empty)
+ };
+
+ Identities {
+ surface: IdentityManager::new(Backend::Empty),
+ hub,
+ }
+ }
+
+ pub fn create_adapter_id(&mut self) -> AdapterId {
+ self.hub.adapters.alloc()
+ }
+}
diff --git a/components/script/dom/imagedata.rs b/components/script/dom/imagedata.rs
index d89e5e36d1b..b09984e267f 100644
--- a/components/script/dom/imagedata.rs
+++ b/components/script/dom/imagedata.rs
@@ -169,8 +169,8 @@ impl ImageData {
}
#[allow(unsafe_code)]
- pub unsafe fn get_rect(&self, rect: Rect<u32>) -> Cow<[u8]> {
- pixels::rgba8_get_rect(self.as_slice(), self.get_size(), rect)
+ pub unsafe fn get_rect(&self, rect: Rect<u64>) -> Cow<[u8]> {
+ pixels::rgba8_get_rect(self.as_slice(), self.get_size().to_u64(), rect)
}
pub fn get_size(&self) -> Size2D<u32> {
@@ -194,3 +194,13 @@ impl ImageDataMethods for ImageData {
NonNull::new(self.data.get()).expect("got a null pointer")
}
}
+
+pub trait Size2DExt {
+ fn to_u64(&self) -> Size2D<u64>;
+}
+
+impl Size2DExt for Size2D<u32> {
+ fn to_u64(&self) -> Size2D<u64> {
+ return Size2D::new(self.width as u64, self.height as u64);
+ }
+}
diff --git a/components/script/dom/mediaelementaudiosourcenode.rs b/components/script/dom/mediaelementaudiosourcenode.rs
new file mode 100644
index 00000000000..07ca70bd80e
--- /dev/null
+++ b/components/script/dom/mediaelementaudiosourcenode.rs
@@ -0,0 +1,80 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+use crate::dom::audiocontext::AudioContext;
+use crate::dom::audionode::AudioNode;
+use crate::dom::bindings::codegen::Bindings::MediaElementAudioSourceNodeBinding;
+use crate::dom::bindings::codegen::Bindings::MediaElementAudioSourceNodeBinding::MediaElementAudioSourceNodeMethods;
+use crate::dom::bindings::codegen::Bindings::MediaElementAudioSourceNodeBinding::MediaElementAudioSourceOptions;
+use crate::dom::bindings::error::Fallible;
+use crate::dom::bindings::reflector::reflect_dom_object;
+use crate::dom::bindings::root::{Dom, DomRoot};
+use crate::dom::htmlmediaelement::HTMLMediaElement;
+use crate::dom::window::Window;
+use dom_struct::dom_struct;
+use servo_media::audio::media_element_source_node::MediaElementSourceNodeMessage;
+use servo_media::audio::node::{AudioNodeInit, AudioNodeMessage};
+use std::sync::mpsc;
+
+#[dom_struct]
+pub struct MediaElementAudioSourceNode {
+ node: AudioNode,
+ media_element: Dom<HTMLMediaElement>,
+}
+
+impl MediaElementAudioSourceNode {
+ #[allow(unrooted_must_root)]
+ fn new_inherited(
+ context: &AudioContext,
+ media_element: &HTMLMediaElement,
+ ) -> Fallible<MediaElementAudioSourceNode> {
+ let node = AudioNode::new_inherited(
+ AudioNodeInit::MediaElementSourceNode,
+ &*context.base(),
+ Default::default(),
+ 0,
+ 1,
+ )?;
+ let (sender, receiver) = mpsc::channel();
+ node.message(AudioNodeMessage::MediaElementSourceNode(
+ MediaElementSourceNodeMessage::GetAudioRenderer(sender),
+ ));
+ let audio_renderer = receiver.recv().unwrap();
+ media_element.set_audio_renderer(audio_renderer);
+ let media_element = Dom::from_ref(media_element);
+ Ok(MediaElementAudioSourceNode {
+ node,
+ media_element,
+ })
+ }
+
+ #[allow(unrooted_must_root)]
+ pub fn new(
+ window: &Window,
+ context: &AudioContext,
+ media_element: &HTMLMediaElement,
+ ) -> Fallible<DomRoot<MediaElementAudioSourceNode>> {
+ let node = MediaElementAudioSourceNode::new_inherited(context, media_element)?;
+ Ok(reflect_dom_object(
+ Box::new(node),
+ window,
+ MediaElementAudioSourceNodeBinding::Wrap,
+ ))
+ }
+
+ pub fn Constructor(
+ window: &Window,
+ context: &AudioContext,
+ options: &MediaElementAudioSourceOptions,
+ ) -> Fallible<DomRoot<MediaElementAudioSourceNode>> {
+ MediaElementAudioSourceNode::new(window, context, &*options.mediaElement)
+ }
+}
+
+impl MediaElementAudioSourceNodeMethods for MediaElementAudioSourceNode {
+ /// https://webaudio.github.io/web-audio-api/#dom-mediaelementaudiosourcenode-mediaelement
+ fn MediaElement(&self) -> DomRoot<HTMLMediaElement> {
+ DomRoot::from_ref(&*self.media_element)
+ }
+}
diff --git a/components/script/dom/mediametadata.rs b/components/script/dom/mediametadata.rs
new file mode 100644
index 00000000000..f2e94abfaa1
--- /dev/null
+++ b/components/script/dom/mediametadata.rs
@@ -0,0 +1,97 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+use crate::dom::bindings::cell::DomRefCell;
+use crate::dom::bindings::codegen::Bindings::MediaMetadataBinding;
+use crate::dom::bindings::codegen::Bindings::MediaMetadataBinding::MediaMetadataInit;
+use crate::dom::bindings::codegen::Bindings::MediaMetadataBinding::MediaMetadataMethods;
+use crate::dom::bindings::error::Fallible;
+use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
+use crate::dom::bindings::root::{DomRoot, MutNullableDom};
+use crate::dom::bindings::str::DOMString;
+use crate::dom::mediasession::MediaSession;
+use crate::dom::window::Window;
+use dom_struct::dom_struct;
+
+#[dom_struct]
+pub struct MediaMetadata {
+ reflector_: Reflector,
+ session: MutNullableDom<MediaSession>,
+ title: DomRefCell<DOMString>,
+ artist: DomRefCell<DOMString>,
+ album: DomRefCell<DOMString>,
+}
+
+impl MediaMetadata {
+ fn new_inherited(init: &MediaMetadataInit) -> MediaMetadata {
+ MediaMetadata {
+ reflector_: Reflector::new(),
+ session: Default::default(),
+ title: DomRefCell::new(init.title.clone()),
+ artist: DomRefCell::new(init.artist.clone()),
+ album: DomRefCell::new(init.album.clone()),
+ }
+ }
+
+ pub fn new(global: &Window, init: &MediaMetadataInit) -> DomRoot<MediaMetadata> {
+ reflect_dom_object(
+ Box::new(MediaMetadata::new_inherited(init)),
+ global,
+ MediaMetadataBinding::Wrap,
+ )
+ }
+
+ /// https://w3c.github.io/mediasession/#dom-mediametadata-mediametadata
+ pub fn Constructor(
+ window: &Window,
+ init: &MediaMetadataInit,
+ ) -> Fallible<DomRoot<MediaMetadata>> {
+ Ok(MediaMetadata::new(window, init))
+ }
+
+ fn queue_update_metadata_algorithm(&self) {
+ if self.session.get().is_none() {
+ return;
+ }
+ }
+
+ pub fn set_session(&self, session: &MediaSession) {
+ self.session.set(Some(&session));
+ }
+}
+
+impl MediaMetadataMethods for MediaMetadata {
+ /// https://w3c.github.io/mediasession/#dom-mediametadata-title
+ fn Title(&self) -> DOMString {
+ self.title.borrow().clone()
+ }
+
+ /// https://w3c.github.io/mediasession/#dom-mediametadata-title
+ fn SetTitle(&self, value: DOMString) {
+ *self.title.borrow_mut() = value;
+ self.queue_update_metadata_algorithm();
+ }
+
+ /// https://w3c.github.io/mediasession/#dom-mediametadata-artist
+ fn Artist(&self) -> DOMString {
+ self.artist.borrow().clone()
+ }
+
+ /// https://w3c.github.io/mediasession/#dom-mediametadata-artist
+ fn SetArtist(&self, value: DOMString) {
+ *self.artist.borrow_mut() = value;
+ self.queue_update_metadata_algorithm();
+ }
+
+ /// https://w3c.github.io/mediasession/#dom-mediametadata-album
+ fn Album(&self) -> DOMString {
+ self.album.borrow().clone()
+ }
+
+ /// https://w3c.github.io/mediasession/#dom-mediametadata-album
+ fn SetAlbum(&self, value: DOMString) {
+ *self.album.borrow_mut() = value;
+ self.queue_update_metadata_algorithm();
+ }
+}
diff --git a/components/script/dom/mediasession.rs b/components/script/dom/mediasession.rs
new file mode 100644
index 00000000000..1523e9a0ae6
--- /dev/null
+++ b/components/script/dom/mediasession.rs
@@ -0,0 +1,213 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+use crate::compartments::{AlreadyInCompartment, InCompartment};
+use crate::dom::bindings::callback::ExceptionHandling;
+use crate::dom::bindings::cell::DomRefCell;
+use crate::dom::bindings::codegen::Bindings::HTMLMediaElementBinding::HTMLMediaElementMethods;
+use crate::dom::bindings::codegen::Bindings::MediaMetadataBinding::MediaMetadataInit;
+use crate::dom::bindings::codegen::Bindings::MediaMetadataBinding::MediaMetadataMethods;
+use crate::dom::bindings::codegen::Bindings::MediaSessionBinding;
+use crate::dom::bindings::codegen::Bindings::MediaSessionBinding::MediaSessionAction;
+use crate::dom::bindings::codegen::Bindings::MediaSessionBinding::MediaSessionActionHandler;
+use crate::dom::bindings::codegen::Bindings::MediaSessionBinding::MediaSessionMethods;
+use crate::dom::bindings::codegen::Bindings::MediaSessionBinding::MediaSessionPlaybackState;
+use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
+use crate::dom::bindings::root::{DomRoot, MutNullableDom};
+use crate::dom::bindings::str::DOMString;
+use crate::dom::htmlmediaelement::HTMLMediaElement;
+use crate::dom::mediametadata::MediaMetadata;
+use crate::dom::window::Window;
+use dom_struct::dom_struct;
+use embedder_traits::MediaMetadata as EmbedderMediaMetadata;
+use embedder_traits::MediaSessionEvent;
+use script_traits::MediaSessionActionType;
+use script_traits::ScriptMsg;
+use std::collections::HashMap;
+use std::rc::Rc;
+
+#[dom_struct]
+pub struct MediaSession {
+ reflector_: Reflector,
+ /// https://w3c.github.io/mediasession/#dom-mediasession-metadata
+ #[ignore_malloc_size_of = "defined in embedder_traits"]
+ metadata: DomRefCell<Option<EmbedderMediaMetadata>>,
+ /// https://w3c.github.io/mediasession/#dom-mediasession-playbackstate
+ playback_state: DomRefCell<MediaSessionPlaybackState>,
+ /// https://w3c.github.io/mediasession/#supported-media-session-actions
+ #[ignore_malloc_size_of = "Rc"]
+ action_handlers: DomRefCell<HashMap<MediaSessionActionType, Rc<MediaSessionActionHandler>>>,
+ /// The media instance controlled by this media session.
+ /// For now only HTMLMediaElements are controlled by media sessions.
+ media_instance: MutNullableDom<HTMLMediaElement>,
+}
+
+impl MediaSession {
+ #[allow(unrooted_must_root)]
+ fn new_inherited() -> MediaSession {
+ let media_session = MediaSession {
+ reflector_: Reflector::new(),
+ metadata: DomRefCell::new(None),
+ playback_state: DomRefCell::new(MediaSessionPlaybackState::None),
+ action_handlers: DomRefCell::new(HashMap::new()),
+ media_instance: Default::default(),
+ };
+ media_session
+ }
+
+ pub fn new(window: &Window) -> DomRoot<MediaSession> {
+ reflect_dom_object(
+ Box::new(MediaSession::new_inherited()),
+ window,
+ MediaSessionBinding::Wrap,
+ )
+ }
+
+ pub fn register_media_instance(&self, media_instance: &HTMLMediaElement) {
+ self.media_instance.set(Some(media_instance));
+ }
+
+ pub fn handle_action(&self, action: MediaSessionActionType) {
+ debug!("Handle media session action {:?}", action);
+
+ if let Some(handler) = self.action_handlers.borrow().get(&action) {
+ if handler.Call__(ExceptionHandling::Report).is_err() {
+ warn!("Error calling MediaSessionActionHandler callback");
+ }
+ return;
+ }
+
+ // Default action.
+ if let Some(media) = self.media_instance.get() {
+ match action {
+ MediaSessionActionType::Play => {
+ let in_compartment_proof = AlreadyInCompartment::assert(&self.global());
+ media.Play(InCompartment::Already(&in_compartment_proof));
+ },
+ MediaSessionActionType::Pause => {
+ media.Pause();
+ },
+ MediaSessionActionType::SeekBackward => {},
+ MediaSessionActionType::SeekForward => {},
+ MediaSessionActionType::PreviousTrack => {},
+ MediaSessionActionType::NextTrack => {},
+ MediaSessionActionType::SkipAd => {},
+ MediaSessionActionType::Stop => {},
+ MediaSessionActionType::SeekTo => {},
+ }
+ }
+ }
+
+ pub fn send_event(&self, event: MediaSessionEvent) {
+ let global = self.global();
+ let window = global.as_window();
+ let pipeline_id = window
+ .pipeline_id()
+ .expect("Cannot send media session event outside of a pipeline");
+ window.send_to_constellation(ScriptMsg::MediaSessionEvent(pipeline_id, event));
+ }
+
+ pub fn update_title(&self, title: String) {
+ let mut metadata = self.metadata.borrow_mut();
+ if let Some(ref mut metadata) = *metadata {
+ // We only update the title with the data provided by the media
+ // player and iff the user did not provide a title.
+ if !metadata.title.is_empty() {
+ return;
+ }
+ metadata.title = title;
+ } else {
+ *metadata = Some(EmbedderMediaMetadata::new(title));
+ }
+ self.send_event(MediaSessionEvent::SetMetadata(
+ metadata.as_ref().unwrap().clone(),
+ ));
+ }
+}
+
+impl MediaSessionMethods for MediaSession {
+ /// https://w3c.github.io/mediasession/#dom-mediasession-metadata
+ fn GetMetadata(&self) -> Option<DomRoot<MediaMetadata>> {
+ if let Some(ref metadata) = *self.metadata.borrow() {
+ let mut init = MediaMetadataInit::empty();
+ init.title = DOMString::from_string(metadata.title.clone());
+ init.artist = DOMString::from_string(metadata.artist.clone());
+ init.album = DOMString::from_string(metadata.album.clone());
+ let global = self.global();
+ Some(MediaMetadata::new(&global.as_window(), &init))
+ } else {
+ None
+ }
+ }
+
+ /// https://w3c.github.io/mediasession/#dom-mediasession-metadata
+ fn SetMetadata(&self, metadata: Option<&MediaMetadata>) {
+ if let Some(ref metadata) = metadata {
+ metadata.set_session(self);
+ }
+
+ let global = self.global();
+ let window = global.as_window();
+ let _metadata = match metadata {
+ Some(m) => {
+ let title = if m.Title().is_empty() {
+ window.get_url().into_string()
+ } else {
+ m.Title().into()
+ };
+ EmbedderMediaMetadata {
+ title,
+ artist: m.Artist().into(),
+ album: m.Album().into(),
+ }
+ },
+ None => EmbedderMediaMetadata::new(window.get_url().into_string()),
+ };
+
+ *self.metadata.borrow_mut() = Some(_metadata.clone());
+
+ self.send_event(MediaSessionEvent::SetMetadata(_metadata));
+ }
+
+ /// https://w3c.github.io/mediasession/#dom-mediasession-playbackstate
+ fn PlaybackState(&self) -> MediaSessionPlaybackState {
+ *self.playback_state.borrow()
+ }
+
+ /// https://w3c.github.io/mediasession/#dom-mediasession-playbackstate
+ fn SetPlaybackState(&self, state: MediaSessionPlaybackState) {
+ *self.playback_state.borrow_mut() = state;
+ }
+
+ /// https://w3c.github.io/mediasession/#update-action-handler-algorithm
+ fn SetActionHandler(
+ &self,
+ action: MediaSessionAction,
+ handler: Option<Rc<MediaSessionActionHandler>>,
+ ) {
+ match handler {
+ Some(handler) => self
+ .action_handlers
+ .borrow_mut()
+ .insert(action.into(), handler.clone()),
+ None => self.action_handlers.borrow_mut().remove(&action.into()),
+ };
+ }
+}
+
+impl From<MediaSessionAction> for MediaSessionActionType {
+ fn from(action: MediaSessionAction) -> MediaSessionActionType {
+ match action {
+ MediaSessionAction::Play => MediaSessionActionType::Play,
+ MediaSessionAction::Pause => MediaSessionActionType::Pause,
+ MediaSessionAction::Seekbackward => MediaSessionActionType::SeekBackward,
+ MediaSessionAction::Seekforward => MediaSessionActionType::SeekForward,
+ MediaSessionAction::Previoustrack => MediaSessionActionType::PreviousTrack,
+ MediaSessionAction::Nexttrack => MediaSessionActionType::NextTrack,
+ MediaSessionAction::Skipad => MediaSessionActionType::SkipAd,
+ MediaSessionAction::Stop => MediaSessionActionType::Stop,
+ MediaSessionAction::Seekto => MediaSessionActionType::SeekTo,
+ }
+ }
+}
diff --git a/components/script/dom/messageevent.rs b/components/script/dom/messageevent.rs
index cb8ebaaebd1..9d9e5f88e35 100644
--- a/components/script/dom/messageevent.rs
+++ b/components/script/dom/messageevent.rs
@@ -5,9 +5,10 @@
use crate::dom::bindings::codegen::Bindings::EventBinding::EventMethods;
use crate::dom::bindings::codegen::Bindings::MessageEventBinding;
use crate::dom::bindings::codegen::Bindings::MessageEventBinding::MessageEventMethods;
+use crate::dom::bindings::codegen::UnionTypes::WindowProxyOrMessagePortOrServiceWorker;
use crate::dom::bindings::error::Fallible;
use crate::dom::bindings::inheritance::Castable;
-use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
+use crate::dom::bindings::reflector::reflect_dom_object;
use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::bindings::str::DOMString;
use crate::dom::bindings::trace::RootedTraceableBox;
@@ -16,14 +17,39 @@ use crate::dom::event::Event;
use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope;
use crate::dom::messageport::MessagePort;
+use crate::dom::serviceworker::ServiceWorker;
use crate::dom::windowproxy::WindowProxy;
use crate::script_runtime::JSContext;
use dom_struct::dom_struct;
-use js::jsapi::{Heap, JSObject};
+use js::jsapi::Heap;
use js::jsval::JSVal;
use js::rust::HandleValue;
use servo_atoms::Atom;
-use std::ptr::NonNull;
+
+#[unrooted_must_root_lint::must_root]
+#[derive(JSTraceable, MallocSizeOf)]
+enum SrcObject {
+ WindowProxy(Dom<WindowProxy>),
+ MessagePort(Dom<MessagePort>),
+ ServiceWorker(Dom<ServiceWorker>),
+}
+
+impl From<&WindowProxyOrMessagePortOrServiceWorker> for SrcObject {
+ #[allow(unrooted_must_root)]
+ fn from(src_object: &WindowProxyOrMessagePortOrServiceWorker) -> SrcObject {
+ match src_object {
+ WindowProxyOrMessagePortOrServiceWorker::WindowProxy(blob) => {
+ SrcObject::WindowProxy(Dom::from_ref(&*blob))
+ },
+ WindowProxyOrMessagePortOrServiceWorker::MessagePort(stream) => {
+ SrcObject::MessagePort(Dom::from_ref(&*stream))
+ },
+ WindowProxyOrMessagePortOrServiceWorker::ServiceWorker(stream) => {
+ SrcObject::ServiceWorker(Dom::from_ref(&*stream))
+ },
+ }
+ }
+}
#[dom_struct]
pub struct MessageEvent {
@@ -31,7 +57,7 @@ pub struct MessageEvent {
#[ignore_malloc_size_of = "mozjs"]
data: Heap<JSVal>,
origin: DOMString,
- source: Option<Dom<WindowProxy>>,
+ source: Option<SrcObject>,
lastEventId: DOMString,
ports: Vec<DomRoot<MessagePort>>,
}
@@ -52,14 +78,14 @@ impl MessageEvent {
global: &GlobalScope,
data: HandleValue,
origin: DOMString,
- source: Option<&WindowProxy>,
+ source: Option<&WindowProxyOrMessagePortOrServiceWorker>,
lastEventId: DOMString,
ports: Vec<DomRoot<MessagePort>>,
) -> DomRoot<MessageEvent> {
let ev = Box::new(MessageEvent {
event: Event::new_inherited(),
data: Heap::default(),
- source: source.map(Dom::from_ref),
+ source: source.map(|source| source.into()),
origin,
lastEventId,
ports,
@@ -77,7 +103,7 @@ impl MessageEvent {
cancelable: bool,
data: HandleValue,
origin: DOMString,
- source: Option<&WindowProxy>,
+ source: Option<&WindowProxyOrMessagePortOrServiceWorker>,
lastEventId: DOMString,
ports: Vec<DomRoot<MessagePort>>,
) -> DomRoot<MessageEvent> {
@@ -94,10 +120,6 @@ impl MessageEvent {
type_: DOMString,
init: RootedTraceableBox<MessageEventBinding::MessageEventInit>,
) -> Fallible<DomRoot<MessageEvent>> {
- let source = init
- .source
- .as_ref()
- .and_then(|inner| inner.as_ref().map(|source| source.window_proxy()));
let ev = MessageEvent::new(
global,
Atom::from(type_),
@@ -105,9 +127,9 @@ impl MessageEvent {
init.parent.cancelable,
init.data.handle(),
init.origin.clone(),
- source.as_ref().map(|source| &**source),
+ init.source.as_ref(),
init.lastEventId.clone(),
- init.ports.clone().unwrap_or(vec![]),
+ init.ports.clone(),
);
Ok(ev)
}
@@ -129,7 +151,11 @@ impl MessageEvent {
false,
message,
DOMString::from(origin.unwrap_or("")),
- source,
+ source
+ .map(|source| {
+ WindowProxyOrMessagePortOrServiceWorker::WindowProxy(DomRoot::from_ref(source))
+ })
+ .as_ref(),
DOMString::new(),
ports,
);
@@ -138,10 +164,6 @@ impl MessageEvent {
pub fn dispatch_error(target: &EventTarget, scope: &GlobalScope) {
let init = MessageEventBinding::MessageEventInit::empty();
- let source = init
- .source
- .as_ref()
- .and_then(|inner| inner.as_ref().map(|source| source.window_proxy()));
let messageevent = MessageEvent::new(
scope,
atom!("messageerror"),
@@ -149,9 +171,9 @@ impl MessageEvent {
init.parent.cancelable,
init.data.handle(),
init.origin.clone(),
- source.as_ref().map(|source| &**source),
+ init.source.as_ref(),
init.lastEventId.clone(),
- init.ports.clone().unwrap_or(vec![]),
+ init.ports.clone(),
);
messageevent.upcast::<Event>().fire(target);
}
@@ -169,10 +191,19 @@ impl MessageEventMethods for MessageEvent {
}
// https://html.spec.whatwg.org/multipage/#dom-messageevent-source
- fn GetSource(&self, _cx: JSContext) -> Option<NonNull<JSObject>> {
- self.source
- .as_ref()
- .and_then(|source| NonNull::new(source.reflector().get_jsobject().get()))
+ fn GetSource(&self) -> Option<WindowProxyOrMessagePortOrServiceWorker> {
+ match &self.source {
+ Some(SrcObject::WindowProxy(i)) => Some(
+ WindowProxyOrMessagePortOrServiceWorker::WindowProxy(DomRoot::from_ref(&*i)),
+ ),
+ Some(SrcObject::MessagePort(i)) => Some(
+ WindowProxyOrMessagePortOrServiceWorker::MessagePort(DomRoot::from_ref(&*i)),
+ ),
+ Some(SrcObject::ServiceWorker(i)) => Some(
+ WindowProxyOrMessagePortOrServiceWorker::ServiceWorker(DomRoot::from_ref(&*i)),
+ ),
+ None => None,
+ }
}
/// <https://html.spec.whatwg.org/multipage/#dom-messageevent-lasteventid>
diff --git a/components/script/dom/messageport.rs b/components/script/dom/messageport.rs
index 67d470a10a2..3198df50923 100644
--- a/components/script/dom/messageport.rs
+++ b/components/script/dom/messageport.rs
@@ -294,8 +294,6 @@ impl MessagePortMethods for MessagePort {
let mut rooted = CustomAutoRooter::new(
options
.transfer
- .as_ref()
- .unwrap_or(&Vec::with_capacity(0))
.iter()
.map(|js: &RootedTraceableBox<Heap<*mut JSObject>>| js.get())
.collect(),
diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs
index 302ae5baad4..d348633df88 100644
--- a/components/script/dom/mod.rs
+++ b/components/script/dom/mod.rs
@@ -315,6 +315,8 @@ pub mod gamepadbuttonlist;
pub mod gamepadevent;
pub mod gamepadlist;
pub mod globalscope;
+pub mod gpu;
+pub mod gpuadapter;
pub mod hashchangeevent;
pub mod headers;
pub mod history;
@@ -389,16 +391,20 @@ pub mod htmltrackelement;
pub mod htmlulistelement;
pub mod htmlunknownelement;
pub mod htmlvideoelement;
+pub mod identityhub;
pub mod imagedata;
pub mod inputevent;
pub mod keyboardevent;
pub mod location;
pub mod mediadevices;
+pub mod mediaelementaudiosourcenode;
pub mod mediaerror;
pub mod mediafragmentparser;
pub mod medialist;
+pub mod mediametadata;
pub mod mediaquerylist;
pub mod mediaquerylistevent;
+pub mod mediasession;
pub mod mediastream;
pub mod mediastreamtrack;
pub mod messagechannel;
@@ -532,6 +538,7 @@ pub mod webglshader;
pub mod webglshaderprecisionformat;
pub mod webglsync;
pub mod webgltexture;
+pub mod webgltransformfeedback;
pub mod webgluniformlocation;
pub mod webglvertexarrayobjectoes;
pub mod websocket;
diff --git a/components/script/dom/navigator.rs b/components/script/dom/navigator.rs
index 8a0f6a21d98..9121f7ef54d 100644
--- a/components/script/dom/navigator.rs
+++ b/components/script/dom/navigator.rs
@@ -11,7 +11,10 @@ use crate::dom::bindings::root::{DomRoot, MutNullableDom};
use crate::dom::bindings::str::DOMString;
use crate::dom::bluetooth::Bluetooth;
use crate::dom::gamepadlist::GamepadList;
+use crate::dom::gpu::GPU;
+use crate::dom::identityhub::Identities;
use crate::dom::mediadevices::MediaDevices;
+use crate::dom::mediasession::MediaSession;
use crate::dom::mimetypearray::MimeTypeArray;
use crate::dom::navigatorinfo;
use crate::dom::permissions::Permissions;
@@ -21,7 +24,9 @@ use crate::dom::serviceworkercontainer::ServiceWorkerContainer;
use crate::dom::window::Window;
use crate::dom::xr::XR;
use dom_struct::dom_struct;
+use std::cell::RefCell;
use std::rc::Rc;
+use webgpu::wgpu::AdapterId;
#[dom_struct]
pub struct Navigator {
@@ -34,6 +39,10 @@ pub struct Navigator {
mediadevices: MutNullableDom<MediaDevices>,
gamepads: MutNullableDom<GamepadList>,
permissions: MutNullableDom<Permissions>,
+ mediasession: MutNullableDom<MediaSession>,
+ gpu: MutNullableDom<GPU>,
+ #[ignore_malloc_size_of = "Defined in wgpu"]
+ gpu_id_hub: RefCell<Identities>,
}
impl Navigator {
@@ -48,6 +57,9 @@ impl Navigator {
mediadevices: Default::default(),
gamepads: Default::default(),
permissions: Default::default(),
+ mediasession: Default::default(),
+ gpu: Default::default(),
+ gpu_id_hub: RefCell::new(Identities::new()),
}
}
@@ -60,6 +72,12 @@ impl Navigator {
}
}
+impl Navigator {
+ pub fn create_adapter_id(&self) -> AdapterId {
+ self.gpu_id_hub.borrow_mut().create_adapter_id()
+ }
+}
+
impl NavigatorMethods for Navigator {
// https://html.spec.whatwg.org/multipage/#dom-navigator-product
fn Product(&self) -> DOMString {
@@ -186,4 +204,25 @@ impl NavigatorMethods for Navigator {
self.mediadevices
.or_init(|| MediaDevices::new(&self.global()))
}
+
+ /// https://w3c.github.io/mediasession/#dom-navigator-mediasession
+ fn MediaSession(&self) -> DomRoot<MediaSession> {
+ self.mediasession.or_init(|| {
+ // There is a single MediaSession instance per Pipeline
+ // and only one active MediaSession globally.
+ //
+ // MediaSession creation can happen in two cases:
+ //
+ // - If content gets `navigator.mediaSession`
+ // - If a media instance (HTMLMediaElement so far) starts playing media.
+ let global = self.global();
+ let window = global.as_window();
+ MediaSession::new(window)
+ })
+ }
+
+ // https://gpuweb.github.io/gpuweb/#dom-navigator-gpu
+ fn Gpu(&self) -> DomRoot<GPU> {
+ self.gpu.or_init(|| GPU::new(&self.global()))
+ }
}
diff --git a/components/script/dom/nodelist.rs b/components/script/dom/nodelist.rs
index 82fd3be59d6..930fedbbec4 100644
--- a/components/script/dom/nodelist.rs
+++ b/components/script/dom/nodelist.rs
@@ -13,7 +13,7 @@ use dom_struct::dom_struct;
use std::cell::Cell;
#[derive(JSTraceable, MallocSizeOf)]
-#[must_root]
+#[unrooted_must_root_lint::must_root]
pub enum NodeListType {
Simple(Vec<Dom<Node>>),
Children(ChildrenList),
@@ -119,7 +119,7 @@ impl NodeList {
}
#[derive(JSTraceable, MallocSizeOf)]
-#[must_root]
+#[unrooted_must_root_lint::must_root]
pub struct ChildrenList {
node: Dom<Node>,
#[ignore_malloc_size_of = "Defined in rust-mozjs"]
diff --git a/components/script/dom/offscreencanvas.rs b/components/script/dom/offscreencanvas.rs
index 142379519fb..2186ba54bc8 100644
--- a/components/script/dom/offscreencanvas.rs
+++ b/components/script/dom/offscreencanvas.rs
@@ -23,7 +23,7 @@ use ref_filter_map;
use std::cell::Cell;
use std::cell::Ref;
-#[must_root]
+#[unrooted_must_root_lint::must_root]
#[derive(Clone, JSTraceable, MallocSizeOf)]
pub enum OffscreenCanvasContext {
OffscreenContext2d(Dom<OffscreenCanvasRenderingContext2D>),
@@ -92,11 +92,9 @@ impl OffscreenCanvas {
OffscreenCanvasContext::OffscreenContext2d(ref ctx) => Some(DomRoot::from_ref(ctx)),
};
}
- let size = self.get_size();
let context = OffscreenCanvasRenderingContext2D::new(
&self.global(),
self,
- size,
self.placeholder.as_ref().map(|c| &**c),
);
*self.context.borrow_mut() = Some(OffscreenCanvasContext::OffscreenContext2d(
@@ -136,6 +134,14 @@ impl OffscreenCanvasMethods for OffscreenCanvas {
// https://html.spec.whatwg.org/multipage/#dom-offscreencanvas-width
fn SetWidth(&self, value: u64) {
self.width.set(value);
+
+ if let Some(canvas_context) = self.context() {
+ match &*canvas_context {
+ OffscreenCanvasContext::OffscreenContext2d(rendering_context) => {
+ rendering_context.set_canvas_bitmap_dimensions(self.get_size());
+ },
+ }
+ }
}
// https://html.spec.whatwg.org/multipage/#dom-offscreencanvas-height
@@ -146,5 +152,13 @@ impl OffscreenCanvasMethods for OffscreenCanvas {
// https://html.spec.whatwg.org/multipage/#dom-offscreencanvas-height
fn SetHeight(&self, value: u64) {
self.height.set(value);
+
+ if let Some(canvas_context) = self.context() {
+ match &*canvas_context {
+ OffscreenCanvasContext::OffscreenContext2d(rendering_context) => {
+ rendering_context.set_canvas_bitmap_dimensions(self.get_size());
+ },
+ }
+ }
}
}
diff --git a/components/script/dom/offscreencanvasrenderingcontext2d.rs b/components/script/dom/offscreencanvasrenderingcontext2d.rs
index 04e0a13032c..077752d9d6e 100644
--- a/components/script/dom/offscreencanvasrenderingcontext2d.rs
+++ b/components/script/dom/offscreencanvasrenderingcontext2d.rs
@@ -30,44 +30,32 @@ use euclid::default::Size2D;
#[dom_struct]
pub struct OffscreenCanvasRenderingContext2D {
reflector_: Reflector,
- canvas: Option<Dom<OffscreenCanvas>>,
+ canvas: Dom<OffscreenCanvas>,
canvas_state: DomRefCell<CanvasState>,
htmlcanvas: Option<Dom<HTMLCanvasElement>>,
- width: u32,
- height: u32,
}
impl OffscreenCanvasRenderingContext2D {
fn new_inherited(
global: &GlobalScope,
- canvas: Option<&OffscreenCanvas>,
- size: Size2D<u64>,
+ canvas: &OffscreenCanvas,
htmlcanvas: Option<&HTMLCanvasElement>,
) -> OffscreenCanvasRenderingContext2D {
OffscreenCanvasRenderingContext2D {
reflector_: Reflector::new(),
- canvas: canvas.map(Dom::from_ref),
+ canvas: Dom::from_ref(canvas),
htmlcanvas: htmlcanvas.map(Dom::from_ref),
- canvas_state: DomRefCell::new(CanvasState::new(
- global,
- Size2D::new(size.width as u64, size.height as u64),
- )),
- width: size.width as u32,
- height: size.height as u32,
+ canvas_state: DomRefCell::new(CanvasState::new(global, canvas.get_size())),
}
}
pub fn new(
global: &GlobalScope,
canvas: &OffscreenCanvas,
- size: Size2D<u64>,
htmlcanvas: Option<&HTMLCanvasElement>,
) -> DomRoot<OffscreenCanvasRenderingContext2D> {
let boxed = Box::new(OffscreenCanvasRenderingContext2D::new_inherited(
- global,
- Some(canvas),
- size,
- htmlcanvas,
+ global, canvas, htmlcanvas,
));
reflect_dom_object(
boxed,
@@ -75,12 +63,21 @@ impl OffscreenCanvasRenderingContext2D {
OffscreenCanvasRenderingContext2DBinding::Wrap,
)
}
+ /*
+ pub fn get_canvas_state(&self) -> Ref<CanvasState> {
+ self.canvas_state.borrow()
+ }
+ */
+
+ pub fn set_canvas_bitmap_dimensions(&self, size: Size2D<u64>) {
+ self.canvas_state.borrow().set_bitmap_dimensions(size);
+ }
}
impl OffscreenCanvasRenderingContext2DMethods for OffscreenCanvasRenderingContext2D {
// https://html.spec.whatwg.org/multipage/offscreencontext2d-canvas
fn Canvas(&self) -> DomRoot<OffscreenCanvas> {
- DomRoot::from_ref(self.canvas.as_ref().expect("No canvas."))
+ DomRoot::from_ref(&self.canvas)
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-fillrect
@@ -315,7 +312,7 @@ impl OffscreenCanvasRenderingContext2DMethods for OffscreenCanvasRenderingContex
// https://html.spec.whatwg.org/multipage/#dom-context-2d-getimagedata
fn GetImageData(&self, sx: i32, sy: i32, sw: i32, sh: i32) -> Fallible<DomRoot<ImageData>> {
self.canvas_state.borrow().get_image_data(
- Size2D::new(self.width, self.height),
+ self.canvas.get_size(),
&self.global(),
sx,
sy,
@@ -326,12 +323,9 @@ impl OffscreenCanvasRenderingContext2DMethods for OffscreenCanvasRenderingContex
// https://html.spec.whatwg.org/multipage/#dom-context-2d-putimagedata
fn PutImageData(&self, imagedata: &ImageData, dx: i32, dy: i32) {
- self.canvas_state.borrow().put_image_data(
- Size2D::new(self.width, self.height),
- imagedata,
- dx,
- dy,
- )
+ self.canvas_state
+ .borrow()
+ .put_image_data(self.canvas.get_size(), imagedata, dx, dy)
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-putimagedata
@@ -347,7 +341,7 @@ impl OffscreenCanvasRenderingContext2DMethods for OffscreenCanvasRenderingContex
dirty_height: i32,
) {
self.canvas_state.borrow().put_image_data_(
- Size2D::new(self.width, self.height),
+ self.canvas.get_size(),
imagedata,
dx,
dy,
diff --git a/components/script/dom/paintrenderingcontext2d.rs b/components/script/dom/paintrenderingcontext2d.rs
index 1bbb52d05fe..e4b0a3cf71e 100644
--- a/components/script/dom/paintrenderingcontext2d.rs
+++ b/components/script/dom/paintrenderingcontext2d.rs
@@ -21,6 +21,7 @@ use crate::dom::canvasgradient::CanvasGradient;
use crate::dom::canvaspattern::CanvasPattern;
use crate::dom::canvasrenderingcontext2d::CanvasRenderingContext2D;
use crate::dom::paintworkletglobalscope::PaintWorkletGlobalScope;
+use crate::euclidext::Size2DExt;
use canvas_traits::canvas::CanvasImageData;
use canvas_traits::canvas::CanvasMsg;
use canvas_traits::canvas::FromLayoutMsg;
@@ -75,7 +76,7 @@ impl PaintRenderingContext2D {
let size = size * device_pixel_ratio;
self.device_pixel_ratio.set(device_pixel_ratio);
self.context
- .set_bitmap_dimensions(size.to_untyped().to_u32());
+ .set_canvas_bitmap_dimensions(size.to_untyped().to_u64());
self.scale_by_device_pixel_ratio();
}
diff --git a/components/script/dom/paintworkletglobalscope.rs b/components/script/dom/paintworkletglobalscope.rs
index bc04ab63440..ce3f955cc9c 100644
--- a/components/script/dom/paintworkletglobalscope.rs
+++ b/components/script/dom/paintworkletglobalscope.rs
@@ -473,7 +473,7 @@ pub enum PaintWorkletTask {
/// This type is dangerous, because it contains uboxed `Heap<JSVal>` values,
/// which can't be moved.
#[derive(JSTraceable, MallocSizeOf)]
-#[must_root]
+#[unrooted_must_root_lint::must_root]
struct PaintDefinition {
#[ignore_malloc_size_of = "mozjs"]
class_constructor: Heap<JSVal>,
diff --git a/components/script/dom/promise.rs b/components/script/dom/promise.rs
index b101c449348..d2e209b98dd 100644
--- a/components/script/dom/promise.rs
+++ b/components/script/dom/promise.rs
@@ -37,7 +37,7 @@ use std::ptr;
use std::rc::Rc;
#[dom_struct]
-#[allow_unrooted_in_rc]
+#[unrooted_must_root_lint::allow_unrooted_in_rc]
pub struct Promise {
reflector: Reflector,
/// Since Promise values are natively reference counted without the knowledge of
diff --git a/components/script/dom/promiserejectionevent.rs b/components/script/dom/promiserejectionevent.rs
index 4e4a148905a..19bf96b9b12 100644
--- a/components/script/dom/promiserejectionevent.rs
+++ b/components/script/dom/promiserejectionevent.rs
@@ -5,7 +5,7 @@
use crate::dom::bindings::codegen::Bindings::EventBinding::EventMethods;
use crate::dom::bindings::codegen::Bindings::PromiseRejectionEventBinding;
use crate::dom::bindings::codegen::Bindings::PromiseRejectionEventBinding::PromiseRejectionEventMethods;
-use crate::dom::bindings::error::{Error, Fallible};
+use crate::dom::bindings::error::Fallible;
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::reflector::reflect_dom_object;
use crate::dom::bindings::root::DomRoot;
@@ -72,14 +72,7 @@ impl PromiseRejectionEvent {
init: RootedTraceableBox<PromiseRejectionEventBinding::PromiseRejectionEventInit>,
) -> Fallible<DomRoot<Self>> {
let reason = init.reason.handle();
- let promise = match init.promise.as_ref() {
- Some(promise) => promise.clone(),
- None => {
- return Err(Error::Type(
- "required member promise is undefined.".to_string(),
- ));
- },
- };
+ let promise = init.promise.clone();
let bubbles = EventBubbles::from(init.parent.bubbles);
let cancelable = EventCancelable::from(init.parent.cancelable);
diff --git a/components/script/dom/range.rs b/components/script/dom/range.rs
index 64a26fa0ba9..819cc284d63 100644
--- a/components/script/dom/range.rs
+++ b/components/script/dom/range.rs
@@ -1011,7 +1011,7 @@ impl RangeMethods for Range {
}
#[derive(DenyPublicFields, JSTraceable, MallocSizeOf)]
-#[must_root]
+#[unrooted_must_root_lint::must_root]
pub struct BoundaryPoint {
node: MutDom<Node>,
offset: Cell<u32>,
diff --git a/components/script/dom/raredata.rs b/components/script/dom/raredata.rs
index 8c481425982..e32f218ce89 100644
--- a/components/script/dom/raredata.rs
+++ b/components/script/dom/raredata.rs
@@ -15,7 +15,7 @@ use std::rc::Rc;
// storage.
#[derive(Default, JSTraceable, MallocSizeOf)]
-#[must_root]
+#[unrooted_must_root_lint::must_root]
pub struct NodeRareData {
/// The shadow root the node belongs to.
/// This is None if the node is not in a shadow tree or
@@ -28,7 +28,7 @@ pub struct NodeRareData {
}
#[derive(Default, JSTraceable, MallocSizeOf)]
-#[must_root]
+#[unrooted_must_root_lint::must_root]
pub struct ElementRareData {
/// https://dom.spec.whatwg.org/#dom-element-shadowroot
/// The ShadowRoot this element is host of.
diff --git a/components/script/dom/response.rs b/components/script/dom/response.rs
index d618c9823e4..184e5ff8888 100644
--- a/components/script/dom/response.rs
+++ b/components/script/dom/response.rs
@@ -403,6 +403,7 @@ impl Response {
Some(hyper_headers) => hyper_headers.into_inner(),
None => HyperHeaders::new(),
});
+ *self.mime_type.borrow_mut() = self.Headers().extract_mime_type();
}
pub fn set_raw_status(&self, status: Option<(u16, Vec<u8>)>) {
diff --git a/components/script/dom/serviceworker.rs b/components/script/dom/serviceworker.rs
index ec64036d305..43e7245f3c5 100644
--- a/components/script/dom/serviceworker.rs
+++ b/components/script/dom/serviceworker.rs
@@ -141,8 +141,6 @@ impl ServiceWorkerMethods for ServiceWorker {
let mut rooted = CustomAutoRooter::new(
options
.transfer
- .as_ref()
- .unwrap_or(&Vec::with_capacity(0))
.iter()
.map(|js: &RootedTraceableBox<Heap<*mut JSObject>>| js.get())
.collect(),
diff --git a/components/script/dom/serviceworkerglobalscope.rs b/components/script/dom/serviceworkerglobalscope.rs
index 657f43627ed..2a3f4d7041a 100644
--- a/components/script/dom/serviceworkerglobalscope.rs
+++ b/components/script/dom/serviceworkerglobalscope.rs
@@ -28,24 +28,22 @@ use crate::script_runtime::{
};
use crate::task_queue::{QueuedTask, QueuedTaskConversion, TaskQueue};
use crate::task_source::TaskSourceName;
-use crossbeam_channel::{unbounded, Receiver, Sender};
+use crossbeam_channel::{after, unbounded, Receiver, Sender};
use devtools_traits::DevtoolScriptControlMsg;
use dom_struct::dom_struct;
-use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
+use ipc_channel::ipc::{IpcReceiver, IpcSender};
use ipc_channel::router::ROUTER;
use js::jsapi::{JSContext, JS_AddInterruptCallback};
use js::jsval::UndefinedValue;
use msg::constellation_msg::PipelineId;
use net_traits::request::{CredentialsMode, Destination, ParserMetadata, Referrer, RequestBuilder};
use net_traits::{CustomResponseMediator, IpcSend};
-use script_traits::{
- ScopeThings, ServiceWorkerMsg, TimerEvent, WorkerGlobalScopeInit, WorkerScriptLoadOrigin,
-};
+use script_traits::{ScopeThings, ServiceWorkerMsg, WorkerGlobalScopeInit, WorkerScriptLoadOrigin};
use servo_config::pref;
use servo_rand::random;
use servo_url::ServoUrl;
use std::thread;
-use std::time::Duration;
+use std::time::{Duration, Instant};
use style::thread_state::{self, ThreadState};
/// Messages used to control service worker event loop
@@ -118,7 +116,6 @@ impl QueuedTaskConversion for ServiceWorkerScriptMsg {
pub enum MixedMessage {
FromServiceWorker(ServiceWorkerScriptMsg),
FromDevtools(DevtoolScriptControlMsg),
- FromTimeoutThread(()),
}
#[derive(Clone, JSTraceable)]
@@ -147,26 +144,30 @@ unsafe_no_jsmanaged_fields!(TaskQueue<ServiceWorkerScriptMsg>);
#[dom_struct]
pub struct ServiceWorkerGlobalScope {
workerglobalscope: WorkerGlobalScope,
+
#[ignore_malloc_size_of = "Defined in std"]
task_queue: TaskQueue<ServiceWorkerScriptMsg>,
+
#[ignore_malloc_size_of = "Defined in std"]
own_sender: Sender<ServiceWorkerScriptMsg>,
+
+ /// A port on which a single "time-out" message can be received,
+ /// indicating the sw should stop running,
+ /// while still draining the task-queue
+ // and running all enqueued, and not cancelled, tasks.
#[ignore_malloc_size_of = "Defined in std"]
- timer_event_port: Receiver<()>,
+ time_out_port: Receiver<Instant>,
+
#[ignore_malloc_size_of = "Defined in std"]
swmanager_sender: IpcSender<ServiceWorkerMsg>,
+
scope_url: ServoUrl,
}
impl WorkerEventLoopMethods for ServiceWorkerGlobalScope {
- type TimerMsg = ();
type WorkerMsg = ServiceWorkerScriptMsg;
type Event = MixedMessage;
- fn timer_event_port(&self) -> &Receiver<()> {
- &self.timer_event_port
- }
-
fn task_queue(&self) -> &TaskQueue<ServiceWorkerScriptMsg> {
&self.task_queue
}
@@ -183,10 +184,6 @@ impl WorkerEventLoopMethods for ServiceWorkerGlobalScope {
MixedMessage::FromServiceWorker(msg)
}
- fn from_timer_msg(&self, msg: ()) -> MixedMessage {
- MixedMessage::FromTimeoutThread(msg)
- }
-
fn from_devtools_msg(&self, msg: DevtoolScriptControlMsg) -> MixedMessage {
MixedMessage::FromDevtools(msg)
}
@@ -200,8 +197,7 @@ impl ServiceWorkerGlobalScope {
runtime: Runtime,
own_sender: Sender<ServiceWorkerScriptMsg>,
receiver: Receiver<ServiceWorkerScriptMsg>,
- timer_event_chan: IpcSender<TimerEvent>,
- timer_event_port: Receiver<()>,
+ time_out_port: Receiver<Instant>,
swmanager_sender: IpcSender<ServiceWorkerMsg>,
scope_url: ServoUrl,
) -> ServiceWorkerGlobalScope {
@@ -213,12 +209,11 @@ impl ServiceWorkerGlobalScope {
worker_url,
runtime,
from_devtools_receiver,
- timer_event_chan,
None,
),
task_queue: TaskQueue::new(receiver, own_sender.clone()),
- timer_event_port: timer_event_port,
own_sender: own_sender,
+ time_out_port,
swmanager_sender: swmanager_sender,
scope_url: scope_url,
}
@@ -232,8 +227,7 @@ impl ServiceWorkerGlobalScope {
runtime: Runtime,
own_sender: Sender<ServiceWorkerScriptMsg>,
receiver: Receiver<ServiceWorkerScriptMsg>,
- timer_event_chan: IpcSender<TimerEvent>,
- timer_event_port: Receiver<()>,
+ time_out_port: Receiver<Instant>,
swmanager_sender: IpcSender<ServiceWorkerMsg>,
scope_url: ServoUrl,
) -> DomRoot<ServiceWorkerGlobalScope> {
@@ -245,8 +239,7 @@ impl ServiceWorkerGlobalScope {
runtime,
own_sender,
receiver,
- timer_event_chan,
- timer_event_port,
+ time_out_port,
swmanager_sender,
scope_url,
));
@@ -315,14 +308,17 @@ impl ServiceWorkerGlobalScope {
},
};
- let runtime = new_rt_and_cx();
+ let runtime = new_rt_and_cx(None);
let (devtools_mpsc_chan, devtools_mpsc_port) = unbounded();
ROUTER
.route_ipc_receiver_to_crossbeam_sender(devtools_receiver, devtools_mpsc_chan);
- // TODO XXXcreativcoder use this timer_ipc_port, when we have a service worker instance here
- let (timer_ipc_chan, _timer_ipc_port) = ipc::channel().unwrap();
- let (timer_chan, timer_port) = unbounded();
+
+ // Service workers are time limited
+ // https://w3c.github.io/ServiceWorker/#service-worker-lifetime
+ let sw_lifetime_timeout = pref!(dom.serviceworker.timeout_seconds) as u64;
+ let time_out_port = after(Duration::new(sw_lifetime_timeout, 0));
+
let global = ServiceWorkerGlobalScope::new(
init,
url,
@@ -330,8 +326,7 @@ impl ServiceWorkerGlobalScope {
runtime,
own_sender,
receiver,
- timer_ipc_chan,
- timer_port,
+ time_out_port,
swmanager_sender,
scope_url,
);
@@ -343,15 +338,6 @@ impl ServiceWorkerGlobalScope {
}
scope.execute_script(DOMString::from(source));
- // Service workers are time limited
- thread::Builder::new()
- .name("SWTimeoutThread".to_owned())
- .spawn(move || {
- let sw_lifetime_timeout = pref!(dom.serviceworker.timeout_seconds) as u64;
- thread::sleep(Duration::new(sw_lifetime_timeout, 0));
- let _ = timer_chan.send(());
- })
- .expect("Thread spawning failed");
global.dispatch_activate();
let reporter_name = format!("service-worker-reporter-{}", random::<u64>());
@@ -364,8 +350,9 @@ impl ServiceWorkerGlobalScope {
// by inside settings until it is destroyed.
// The worker processing model remains on this step
// until the event loop is destroyed,
- // which happens after the closing flag is set to true.
- while !scope.is_closing() {
+ // which happens after the closing flag is set to true,
+ // or until the worker has run beyond its allocated time.
+ while !scope.is_closing() || !global.has_timed_out() {
run_worker_event_loop(&*global, None);
}
},
@@ -398,15 +385,21 @@ impl ServiceWorkerGlobalScope {
self.handle_script_event(msg);
true
},
- MixedMessage::FromTimeoutThread(_) => {
- let _ = self
- .swmanager_sender
- .send(ServiceWorkerMsg::Timeout(self.scope_url.clone()));
- false
- },
}
}
+ fn has_timed_out(&self) -> bool {
+ // Note: this should be included in the `select` inside `run_worker_event_loop`,
+ // otherwise a block on the select can prevent the timeout.
+ if self.time_out_port.try_recv().is_ok() {
+ let _ = self
+ .swmanager_sender
+ .send(ServiceWorkerMsg::Timeout(self.scope_url.clone()));
+ return true;
+ }
+ false
+ }
+
fn handle_script_event(&self, msg: ServiceWorkerScriptMsg) {
use self::ServiceWorkerScriptMsg::*;
diff --git a/components/script/dom/servoparser/async_html.rs b/components/script/dom/servoparser/async_html.rs
index 42296062840..6930f2553c5 100644
--- a/components/script/dom/servoparser/async_html.rs
+++ b/components/script/dom/servoparser/async_html.rs
@@ -196,7 +196,7 @@ fn create_buffer_queue(mut buffers: VecDeque<SendTendril<UTF8>>) -> BufferQueue
// |_____________| |_______________|
//
#[derive(JSTraceable, MallocSizeOf)]
-#[must_root]
+#[unrooted_must_root_lint::must_root]
pub struct Tokenizer {
document: Dom<Document>,
#[ignore_malloc_size_of = "Defined in std"]
diff --git a/components/script/dom/servoparser/html.rs b/components/script/dom/servoparser/html.rs
index c9e3a06f34f..22e2574a9b4 100644
--- a/components/script/dom/servoparser/html.rs
+++ b/components/script/dom/servoparser/html.rs
@@ -30,7 +30,7 @@ use servo_url::ServoUrl;
use std::io;
#[derive(JSTraceable, MallocSizeOf)]
-#[must_root]
+#[unrooted_must_root_lint::must_root]
pub struct Tokenizer {
#[ignore_malloc_size_of = "Defined in html5ever"]
inner: HtmlTokenizer<TreeBuilder<Dom<Node>, Sink>>,
diff --git a/components/script/dom/servoparser/mod.rs b/components/script/dom/servoparser/mod.rs
index 91b5c9bfce6..004daeed9be 100644
--- a/components/script/dom/servoparser/mod.rs
+++ b/components/script/dom/servoparser/mod.rs
@@ -626,7 +626,7 @@ enum ParserKind {
}
#[derive(JSTraceable, MallocSizeOf)]
-#[must_root]
+#[unrooted_must_root_lint::must_root]
enum Tokenizer {
Html(self::html::Tokenizer),
AsyncHtml(self::async_html::Tokenizer),
@@ -945,7 +945,7 @@ fn insert(parent: &Node, reference_child: Option<&Node>, child: NodeOrText<Dom<N
}
#[derive(JSTraceable, MallocSizeOf)]
-#[must_root]
+#[unrooted_must_root_lint::must_root]
pub struct Sink {
base_url: ServoUrl,
document: Dom<Document>,
diff --git a/components/script/dom/servoparser/prefetch.rs b/components/script/dom/servoparser/prefetch.rs
index 906c9352771..d9de4d7036f 100644
--- a/components/script/dom/servoparser/prefetch.rs
+++ b/components/script/dom/servoparser/prefetch.rs
@@ -32,7 +32,7 @@ use servo_url::ImmutableOrigin;
use servo_url::ServoUrl;
#[derive(JSTraceable, MallocSizeOf)]
-#[must_root]
+#[unrooted_must_root_lint::must_root]
pub struct Tokenizer {
#[ignore_malloc_size_of = "Defined in html5ever"]
inner: HtmlTokenizer<PrefetchSink>,
diff --git a/components/script/dom/servoparser/xml.rs b/components/script/dom/servoparser/xml.rs
index 8f30e54174d..ac900d61ce0 100644
--- a/components/script/dom/servoparser/xml.rs
+++ b/components/script/dom/servoparser/xml.rs
@@ -17,7 +17,7 @@ use xml5ever::tokenizer::XmlTokenizer;
use xml5ever::tree_builder::{Tracer as XmlTracer, XmlTreeBuilder};
#[derive(JSTraceable, MallocSizeOf)]
-#[must_root]
+#[unrooted_must_root_lint::must_root]
pub struct Tokenizer {
#[ignore_malloc_size_of = "Defined in xml5ever"]
inner: XmlTokenizer<XmlTreeBuilder<Dom<Node>, Sink>>,
diff --git a/components/script/dom/stylesheetlist.rs b/components/script/dom/stylesheetlist.rs
index 236f1c9cd9a..391ac55ed91 100644
--- a/components/script/dom/stylesheetlist.rs
+++ b/components/script/dom/stylesheetlist.rs
@@ -16,7 +16,7 @@ use dom_struct::dom_struct;
use servo_arc::Arc;
use style::stylesheets::Stylesheet;
-#[must_root]
+#[unrooted_must_root_lint::must_root]
#[derive(JSTraceable, MallocSizeOf)]
pub enum StyleSheetListOwner {
Document(Dom<Document>),
diff --git a/components/script/dom/trackevent.rs b/components/script/dom/trackevent.rs
index 684a0fcde52..5a734a0e4c9 100644
--- a/components/script/dom/trackevent.rs
+++ b/components/script/dom/trackevent.rs
@@ -20,7 +20,7 @@ use crate::dom::window::Window;
use dom_struct::dom_struct;
use servo_atoms::Atom;
-#[must_root]
+#[unrooted_must_root_lint::must_root]
#[derive(JSTraceable, MallocSizeOf)]
enum MediaTrack {
Video(Dom<VideoTrack>),
diff --git a/components/script/dom/url.rs b/components/script/dom/url.rs
index 9952739243b..cc6c83e2c18 100644
--- a/components/script/dom/url.rs
+++ b/components/script/dom/url.rs
@@ -129,13 +129,15 @@ impl URL {
let origin = get_blob_origin(&global.get_url());
if let Ok(url) = ServoUrl::parse(&url) {
- if let Ok((id, _)) = parse_blob_url(&url) {
- let resource_threads = global.resource_threads();
- let (tx, rx) = ipc::channel(global.time_profiler_chan().clone()).unwrap();
- let msg = FileManagerThreadMsg::RevokeBlobURL(id, origin, tx);
- let _ = resource_threads.send(CoreResourceMsg::ToFileManager(msg));
-
- let _ = rx.recv().unwrap();
+ if url.fragment().is_none() && origin == get_blob_origin(&url) {
+ if let Ok((id, _)) = parse_blob_url(&url) {
+ let resource_threads = global.resource_threads();
+ let (tx, rx) = ipc::channel(global.time_profiler_chan().clone()).unwrap();
+ let msg = FileManagerThreadMsg::RevokeBlobURL(id, origin, tx);
+ let _ = resource_threads.send(CoreResourceMsg::ToFileManager(msg));
+
+ let _ = rx.recv().unwrap();
+ }
}
}
}
diff --git a/components/script/dom/webgl2renderingcontext.rs b/components/script/dom/webgl2renderingcontext.rs
index beff6ec6bfd..2c63b775bb1 100644
--- a/components/script/dom/webgl2renderingcontext.rs
+++ b/components/script/dom/webgl2renderingcontext.rs
@@ -11,8 +11,8 @@ use crate::dom::bindings::codegen::UnionTypes::ArrayBufferViewOrArrayBuffer;
use crate::dom::bindings::codegen::UnionTypes::Float32ArrayOrUnrestrictedFloatSequence;
use crate::dom::bindings::codegen::UnionTypes::ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement;
use crate::dom::bindings::codegen::UnionTypes::Int32ArrayOrLongSequence;
-use crate::dom::bindings::conversions::ToJSValConvertible;
use crate::dom::bindings::error::{ErrorResult, Fallible};
+use crate::dom::bindings::reflector::DomObject;
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
use crate::dom::bindings::root::{Dom, DomRoot, LayoutDom, MutNullableDom};
use crate::dom::bindings::str::DOMString;
@@ -25,28 +25,32 @@ use crate::dom::webglprogram::WebGLProgram;
use crate::dom::webglquery::WebGLQuery;
use crate::dom::webglrenderbuffer::WebGLRenderbuffer;
use crate::dom::webglrenderingcontext::{
- LayoutCanvasWebGLRenderingContextHelpers, WebGLRenderingContext,
+ LayoutCanvasWebGLRenderingContextHelpers, Size2DExt, WebGLRenderingContext,
};
use crate::dom::webglsampler::{WebGLSampler, WebGLSamplerValue};
use crate::dom::webglshader::WebGLShader;
use crate::dom::webglshaderprecisionformat::WebGLShaderPrecisionFormat;
use crate::dom::webglsync::WebGLSync;
use crate::dom::webgltexture::WebGLTexture;
+use crate::dom::webgltransformfeedback::WebGLTransformFeedback;
use crate::dom::webgluniformlocation::WebGLUniformLocation;
use crate::dom::window::Window;
+use crate::js::conversions::ToJSValConvertible;
use crate::script_runtime::JSContext;
use canvas_traits::webgl::WebGLError::*;
use canvas_traits::webgl::{
webgl_channel, GLContextAttributes, WebGLCommand, WebGLResult, WebGLVersion,
};
use dom_struct::dom_struct;
-use euclid::default::Size2D;
+use euclid::default::{Point2D, Rect, Size2D};
use ipc_channel::ipc;
use js::jsapi::{JSObject, Type};
use js::jsval::{BooleanValue, DoubleValue, Int32Value, JSVal, NullValue, UInt32Value};
use js::rust::CustomAutoRooterGuard;
use js::typedarray::ArrayBufferView;
use script_layout_interface::HTMLCanvasDataSource;
+use std::cell::Cell;
+use std::cmp;
use std::ptr::NonNull;
#[dom_struct]
@@ -62,6 +66,10 @@ pub struct WebGL2RenderingContext {
bound_pixel_unpack_buffer: MutNullableDom<WebGLBuffer>,
bound_transform_feedback_buffer: MutNullableDom<WebGLBuffer>,
bound_uniform_buffer: MutNullableDom<WebGLBuffer>,
+ current_transform_feedback: MutNullableDom<WebGLTransformFeedback>,
+ texture_pack_row_length: Cell<usize>,
+ texture_pack_skip_pixels: Cell<usize>,
+ texture_pack_skip_rows: Cell<usize>,
}
fn typedarray_elem_size(typeid: Type) -> usize {
@@ -74,6 +82,17 @@ fn typedarray_elem_size(typeid: Type) -> usize {
}
}
+struct ReadPixelsAllowedFormats<'a> {
+ array_types: &'a [Type],
+ channels: usize,
+}
+
+struct ReadPixelsSizes {
+ row_stride: usize,
+ skipped_bytes: usize,
+ size: usize,
+}
+
impl WebGL2RenderingContext {
fn new_inherited(
window: &Window,
@@ -100,6 +119,10 @@ impl WebGL2RenderingContext {
bound_pixel_unpack_buffer: MutNullableDom::new(None),
bound_transform_feedback_buffer: MutNullableDom::new(None),
bound_uniform_buffer: MutNullableDom::new(None),
+ current_transform_feedback: MutNullableDom::new(None),
+ texture_pack_row_length: Cell::new(0),
+ texture_pack_skip_pixels: Cell::new(0),
+ texture_pack_skip_rows: Cell::new(0),
})
}
@@ -143,6 +166,213 @@ impl WebGL2RenderingContext {
slot.set(None);
}
}
+
+ fn calc_read_pixel_formats(
+ &self,
+ pixel_type: u32,
+ format: u32,
+ ) -> WebGLResult<ReadPixelsAllowedFormats> {
+ let array_types = match pixel_type {
+ constants::BYTE => &[Type::Int8][..],
+ constants::SHORT => &[Type::Int16][..],
+ constants::INT => &[Type::Int32][..],
+ constants::UNSIGNED_BYTE => &[Type::Uint8, Type::Uint8Clamped][..],
+ constants::UNSIGNED_SHORT |
+ constants::UNSIGNED_SHORT_4_4_4_4 |
+ constants::UNSIGNED_SHORT_5_5_5_1 |
+ constants::UNSIGNED_SHORT_5_6_5 => &[Type::Uint16][..],
+ constants::UNSIGNED_INT |
+ constants::UNSIGNED_INT_2_10_10_10_REV |
+ constants::UNSIGNED_INT_10F_11F_11F_REV |
+ constants::UNSIGNED_INT_5_9_9_9_REV => &[Type::Uint32][..],
+ constants::FLOAT => &[Type::Float32][..],
+ constants::HALF_FLOAT => &[Type::Uint16][..],
+ _ => return Err(InvalidEnum),
+ };
+ let channels = match format {
+ constants::ALPHA | constants::RED | constants::RED_INTEGER => 1,
+ constants::RG | constants::RG_INTEGER => 2,
+ constants::RGB | constants::RGB_INTEGER => 3,
+ constants::RGBA | constants::RGBA_INTEGER => 4,
+ _ => return Err(InvalidEnum),
+ };
+ Ok(ReadPixelsAllowedFormats {
+ array_types,
+ channels,
+ })
+ }
+
+ fn calc_read_pixel_sizes(
+ &self,
+ width: i32,
+ height: i32,
+ bytes_per_pixel: usize,
+ ) -> WebGLResult<ReadPixelsSizes> {
+ if width < 0 || height < 0 {
+ return Err(InvalidValue);
+ }
+
+ // See also https://www.khronos.org/registry/webgl/specs/latest/2.0/#5.36
+ let pixels_per_row = if self.texture_pack_row_length.get() > 0 {
+ self.texture_pack_row_length.get()
+ } else {
+ width as usize
+ };
+ if self.texture_pack_skip_pixels.get() + width as usize > pixels_per_row {
+ return Err(InvalidOperation);
+ }
+
+ let bytes_per_row = pixels_per_row
+ .checked_mul(bytes_per_pixel)
+ .ok_or(InvalidOperation)?;
+ let row_padding_bytes = {
+ let pack_alignment = self.base.get_texture_packing_alignment() as usize;
+ match bytes_per_row % pack_alignment {
+ 0 => 0,
+ remainder => pack_alignment - remainder,
+ }
+ };
+ let row_stride = bytes_per_row + row_padding_bytes;
+ let size = if width == 0 || height == 0 {
+ 0
+ } else {
+ let full_row_bytes = row_stride
+ .checked_mul(height as usize - 1)
+ .ok_or(InvalidOperation)?;
+ let last_row_bytes = bytes_per_pixel
+ .checked_mul(width as usize)
+ .ok_or(InvalidOperation)?;
+ let result = full_row_bytes
+ .checked_add(last_row_bytes)
+ .ok_or(InvalidOperation)?;
+ result
+ };
+ let skipped_bytes = {
+ let skipped_row_bytes = self
+ .texture_pack_skip_rows
+ .get()
+ .checked_mul(row_stride)
+ .ok_or(InvalidOperation)?;
+ let skipped_pixel_bytes = self
+ .texture_pack_skip_pixels
+ .get()
+ .checked_mul(bytes_per_pixel)
+ .ok_or(InvalidOperation)?;
+ let result = skipped_row_bytes
+ .checked_add(skipped_pixel_bytes)
+ .ok_or(InvalidOperation)?;
+ result
+ };
+ Ok(ReadPixelsSizes {
+ row_stride,
+ skipped_bytes,
+ size,
+ })
+ }
+
+ #[allow(unsafe_code)]
+ fn read_pixels_into(
+ &self,
+ x: i32,
+ y: i32,
+ width: i32,
+ height: i32,
+ format: u32,
+ pixel_type: u32,
+ dst: &mut ArrayBufferView,
+ dst_elem_offset: u32,
+ ) {
+ handle_potential_webgl_error!(self.base, self.base.validate_framebuffer(), return);
+
+ if self.bound_pixel_pack_buffer.get().is_some() {
+ return self.base.webgl_error(InvalidOperation);
+ }
+
+ let dst_byte_offset = {
+ let dst_elem_size = typedarray_elem_size(dst.get_array_type());
+ dst_elem_offset as usize * dst_elem_size
+ };
+ if dst_byte_offset > dst.len() {
+ return self.base.webgl_error(InvalidValue);
+ }
+
+ let dst_array_type = dst.get_array_type();
+ let ReadPixelsAllowedFormats {
+ array_types: allowed_array_types,
+ channels,
+ } = match self.calc_read_pixel_formats(pixel_type, format) {
+ Ok(result) => result,
+ Err(error) => return self.base.webgl_error(error),
+ };
+ if !allowed_array_types.contains(&dst_array_type) {
+ return self.base.webgl_error(InvalidOperation);
+ }
+ if format != constants::RGBA || pixel_type != constants::UNSIGNED_BYTE {
+ return self.base.webgl_error(InvalidOperation);
+ }
+
+ let bytes_per_pixel = typedarray_elem_size(dst_array_type) * channels;
+ let ReadPixelsSizes {
+ row_stride,
+ skipped_bytes,
+ size,
+ } = match self.calc_read_pixel_sizes(width, height, bytes_per_pixel) {
+ Ok(result) => result,
+ Err(error) => return self.base.webgl_error(error),
+ };
+ let dst_end = dst_byte_offset + skipped_bytes + size;
+ let dst_pixels = unsafe { dst.as_mut_slice() };
+ if dst_pixels.len() < dst_end {
+ return self.base.webgl_error(InvalidOperation);
+ }
+
+ let dst_byte_offset = {
+ let margin_left = cmp::max(0, -x) as usize;
+ let margin_top = cmp::max(0, -y) as usize;
+ dst_byte_offset +
+ skipped_bytes +
+ margin_left * bytes_per_pixel +
+ margin_top * row_stride
+ };
+ let src_rect = {
+ let (fb_width, fb_height) = handle_potential_webgl_error!(
+ self.base,
+ self.base
+ .get_current_framebuffer_size()
+ .ok_or(InvalidOperation),
+ return
+ );
+ let src_origin = Point2D::new(x, y);
+ let src_size = Size2D::new(width as u32, height as u32);
+ let fb_size = Size2D::new(fb_width as u32, fb_height as u32);
+ match pixels::clip(src_origin, src_size.to_u64(), fb_size.to_u64()) {
+ Some(rect) => rect.to_u32(),
+ None => return,
+ }
+ };
+ let src_row_bytes = handle_potential_webgl_error!(
+ self.base,
+ src_rect
+ .size
+ .width
+ .checked_mul(bytes_per_pixel as u32)
+ .ok_or(InvalidOperation),
+ return
+ );
+
+ let (sender, receiver) = ipc::bytes_channel().unwrap();
+ self.base.send_command(WebGLCommand::ReadPixels(
+ src_rect, format, pixel_type, sender,
+ ));
+ let src = receiver.recv().unwrap();
+
+ for i in 0..src_rect.size.height as usize {
+ let src_start = i * src_row_bytes as usize;
+ let dst_start = dst_byte_offset + i * row_stride;
+ dst_pixels[dst_start..dst_start + src_row_bytes as usize]
+ .copy_from_slice(&src[src_start..src_start + src_row_bytes as usize]);
+ }
+ }
}
impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
@@ -210,6 +440,9 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
constants::UNIFORM_BUFFER_BINDING => unsafe {
optional_root_object_to_js_or_null!(*cx, &self.bound_uniform_buffer.get())
},
+ constants::TRANSFORM_FEEDBACK_BINDING => unsafe {
+ optional_root_object_to_js_or_null!(*cx, self.current_transform_feedback.get())
+ },
_ => self.base.GetParameter(cx, parameter),
}
}
@@ -824,7 +1057,24 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
/// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9
fn GetProgramParameter(&self, cx: JSContext, program: &WebGLProgram, param_id: u32) -> JSVal {
- self.base.GetProgramParameter(cx, program, param_id)
+ handle_potential_webgl_error!(
+ self.base,
+ self.base.validate_ownership(program),
+ return NullValue()
+ );
+ if program.is_deleted() {
+ self.base.webgl_error(InvalidOperation);
+ return NullValue();
+ }
+ match param_id {
+ constants::TRANSFORM_FEEDBACK_VARYINGS => {
+ Int32Value(program.transform_feedback_varyings_length())
+ },
+ constants::TRANSFORM_FEEDBACK_BUFFER_MODE => {
+ Int32Value(program.transform_feedback_buffer_mode())
+ },
+ _ => self.base.GetProgramParameter(cx, program, param_id),
+ }
}
/// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9
@@ -912,9 +1162,18 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
self.base.LineWidth(width)
}
- /// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.2
fn PixelStorei(&self, param_name: u32, param_value: i32) {
- self.base.PixelStorei(param_name, param_value)
+ if param_value < 0 {
+ return self.base.webgl_error(InvalidValue);
+ }
+
+ match param_name {
+ constants::PACK_ROW_LENGTH => self.texture_pack_row_length.set(param_value as _),
+ constants::PACK_SKIP_PIXELS => self.texture_pack_skip_pixels.set(param_value as _),
+ constants::PACK_SKIP_ROWS => self.texture_pack_skip_rows.set(param_value as _),
+ _ => self.base.PixelStorei(param_name, param_value),
+ }
}
/// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3
@@ -931,10 +1190,128 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
height: i32,
format: u32,
pixel_type: u32,
- pixels: CustomAutoRooterGuard<Option<ArrayBufferView>>,
+ mut pixels: CustomAutoRooterGuard<Option<ArrayBufferView>>,
) {
- self.base
- .ReadPixels(x, y, width, height, format, pixel_type, pixels)
+ let pixels =
+ handle_potential_webgl_error!(self.base, pixels.as_mut().ok_or(InvalidValue), return);
+
+ self.read_pixels_into(x, y, width, height, format, pixel_type, pixels, 0)
+ }
+
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.10
+ fn ReadPixels_(
+ &self,
+ x: i32,
+ y: i32,
+ width: i32,
+ height: i32,
+ format: u32,
+ pixel_type: u32,
+ dst_byte_offset: i64,
+ ) {
+ handle_potential_webgl_error!(self.base, self.base.validate_framebuffer(), return);
+
+ let dst = match self.bound_pixel_pack_buffer.get() {
+ Some(buffer) => buffer,
+ None => return self.base.webgl_error(InvalidOperation),
+ };
+
+ if dst_byte_offset < 0 {
+ return self.base.webgl_error(InvalidValue);
+ }
+ let dst_byte_offset = dst_byte_offset as usize;
+ if dst_byte_offset > dst.capacity() {
+ return self.base.webgl_error(InvalidOperation);
+ }
+
+ let ReadPixelsAllowedFormats {
+ array_types: _,
+ channels: bytes_per_pixel,
+ } = match self.calc_read_pixel_formats(pixel_type, format) {
+ Ok(result) => result,
+ Err(error) => return self.base.webgl_error(error),
+ };
+ if format != constants::RGBA || pixel_type != constants::UNSIGNED_BYTE {
+ return self.base.webgl_error(InvalidOperation);
+ }
+
+ let ReadPixelsSizes {
+ row_stride: _,
+ skipped_bytes,
+ size,
+ } = match self.calc_read_pixel_sizes(width, height, bytes_per_pixel) {
+ Ok(result) => result,
+ Err(error) => return self.base.webgl_error(error),
+ };
+ let dst_end = dst_byte_offset + skipped_bytes + size;
+ if dst.capacity() < dst_end {
+ return self.base.webgl_error(InvalidOperation);
+ }
+
+ {
+ let (fb_width, fb_height) = handle_potential_webgl_error!(
+ self.base,
+ self.base
+ .get_current_framebuffer_size()
+ .ok_or(InvalidOperation),
+ return
+ );
+ let src_origin = Point2D::new(x, y);
+ let src_size = Size2D::new(width as u32, height as u32);
+ let fb_size = Size2D::new(fb_width as u32, fb_height as u32);
+ if pixels::clip(src_origin, src_size.to_u64(), fb_size.to_u64()).is_none() {
+ return;
+ }
+ }
+ let src_rect = Rect::new(Point2D::new(x, y), Size2D::new(width, height));
+
+ self.base.send_command(WebGLCommand::PixelStorei(
+ constants::PACK_ALIGNMENT,
+ self.base.get_texture_packing_alignment() as _,
+ ));
+ self.base.send_command(WebGLCommand::PixelStorei(
+ constants::PACK_ROW_LENGTH,
+ self.texture_pack_row_length.get() as _,
+ ));
+ self.base.send_command(WebGLCommand::PixelStorei(
+ constants::PACK_SKIP_ROWS,
+ self.texture_pack_skip_rows.get() as _,
+ ));
+ self.base.send_command(WebGLCommand::PixelStorei(
+ constants::PACK_SKIP_PIXELS,
+ self.texture_pack_skip_pixels.get() as _,
+ ));
+ self.base.send_command(WebGLCommand::ReadPixelsPP(
+ src_rect,
+ format,
+ pixel_type,
+ dst_byte_offset,
+ ));
+ }
+
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.10
+ #[allow(unsafe_code)]
+ fn ReadPixels__(
+ &self,
+ x: i32,
+ y: i32,
+ width: i32,
+ height: i32,
+ format: u32,
+ pixel_type: u32,
+ mut dst: CustomAutoRooterGuard<ArrayBufferView>,
+ dst_elem_offset: u32,
+ ) {
+ self.read_pixels_into(
+ x,
+ y,
+ width,
+ height,
+ format,
+ pixel_type,
+ &mut dst,
+ dst_elem_offset,
+ )
}
/// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3
@@ -1721,6 +2098,212 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
},
}
}
+
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.15
+ fn CreateTransformFeedback(&self) -> Option<DomRoot<WebGLTransformFeedback>> {
+ Some(WebGLTransformFeedback::new(&self.base))
+ }
+
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.15
+ fn DeleteTransformFeedback(&self, tf: Option<&WebGLTransformFeedback>) {
+ if let Some(tf) = tf {
+ handle_potential_webgl_error!(self.base, self.base.validate_ownership(tf), return);
+ if tf.is_active() {
+ self.base.webgl_error(InvalidOperation);
+ return;
+ }
+ tf.delete(false);
+ self.current_transform_feedback.set(None);
+ }
+ }
+
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.15
+ fn IsTransformFeedback(&self, tf: Option<&WebGLTransformFeedback>) -> bool {
+ match tf {
+ Some(tf) => {
+ if !tf.is_valid() {
+ return false;
+ }
+ handle_potential_webgl_error!(
+ self.base,
+ self.base.validate_ownership(tf),
+ return false
+ );
+ let (sender, receiver) = webgl_channel().unwrap();
+ self.base
+ .send_command(WebGLCommand::IsTransformFeedback(tf.id(), sender));
+ receiver.recv().unwrap()
+ },
+ None => false,
+ }
+ }
+
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.15
+ fn BindTransformFeedback(&self, target: u32, tf: Option<&WebGLTransformFeedback>) {
+ if target != constants::TRANSFORM_FEEDBACK {
+ self.base.webgl_error(InvalidEnum);
+ return;
+ }
+ match tf {
+ Some(transform_feedback) => {
+ handle_potential_webgl_error!(
+ self.base,
+ self.base.validate_ownership(transform_feedback),
+ return
+ );
+ if !transform_feedback.is_valid() {
+ self.base.webgl_error(InvalidOperation);
+ return;
+ }
+ if let Some(current_tf) = self.current_transform_feedback.get() {
+ if current_tf.is_active() && !current_tf.is_paused() {
+ self.base.webgl_error(InvalidOperation);
+ return;
+ }
+ }
+ transform_feedback.bind(&self.base, target);
+ self.current_transform_feedback
+ .set(Some(transform_feedback));
+ },
+ None => self
+ .base
+ .send_command(WebGLCommand::BindTransformFeedback(target, 0)),
+ }
+ }
+
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.15
+ fn BeginTransformFeedback(&self, primitiveMode: u32) {
+ match primitiveMode {
+ constants::POINTS | constants::LINES | constants::TRIANGLES => {},
+ _ => {
+ self.base.webgl_error(InvalidEnum);
+ return;
+ },
+ };
+ let current_tf = match self.current_transform_feedback.get() {
+ Some(current_tf) => current_tf,
+ None => {
+ self.base.webgl_error(InvalidOperation);
+ return;
+ },
+ };
+ if current_tf.is_active() {
+ self.base.webgl_error(InvalidOperation);
+ return;
+ };
+ let program = match self.base.current_program() {
+ Some(program) => program,
+ None => {
+ self.base.webgl_error(InvalidOperation);
+ return;
+ },
+ };
+ if !program.is_linked() || program.transform_feedback_varyings_length() != 0 {
+ self.base.webgl_error(InvalidOperation);
+ return;
+ };
+ current_tf.begin(&self.base, primitiveMode);
+ }
+
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.15
+ fn EndTransformFeedback(&self) {
+ if let Some(current_tf) = self.current_transform_feedback.get() {
+ if !current_tf.is_active() {
+ self.base.webgl_error(InvalidOperation);
+ return;
+ }
+ current_tf.end(&self.base);
+ }
+ }
+
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.15
+ fn ResumeTransformFeedback(&self) {
+ if let Some(current_tf) = self.current_transform_feedback.get() {
+ if !current_tf.is_active() || !current_tf.is_paused() {
+ self.base.webgl_error(InvalidOperation);
+ return;
+ }
+ current_tf.resume(&self.base);
+ }
+ }
+
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.15
+ fn PauseTransformFeedback(&self) {
+ if let Some(current_tf) = self.current_transform_feedback.get() {
+ if !current_tf.is_active() || current_tf.is_paused() {
+ self.base.webgl_error(InvalidOperation);
+ return;
+ }
+ current_tf.pause(&self.base);
+ }
+ }
+
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.15
+ fn TransformFeedbackVaryings(
+ &self,
+ program: &WebGLProgram,
+ varyings: Vec<DOMString>,
+ bufferMode: u32,
+ ) {
+ handle_potential_webgl_error!(self.base, program.validate(), return);
+ let strs = varyings
+ .iter()
+ .map(|name| String::from(name.to_owned()))
+ .collect::<Vec<String>>();
+ match bufferMode {
+ constants::INTERLEAVED_ATTRIBS => {
+ self.base
+ .send_command(WebGLCommand::TransformFeedbackVaryings(
+ program.id(),
+ strs,
+ bufferMode,
+ ));
+ },
+ constants::SEPARATE_ATTRIBS => {
+ let max_tf_sp_att =
+ self.base.limits().max_transform_feedback_separate_attribs as usize;
+ if strs.len() >= max_tf_sp_att {
+ self.base.webgl_error(InvalidValue);
+ return;
+ }
+ self.base
+ .send_command(WebGLCommand::TransformFeedbackVaryings(
+ program.id(),
+ strs,
+ bufferMode,
+ ));
+ },
+ _ => self.base.webgl_error(InvalidEnum),
+ }
+ }
+
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.15
+ fn GetTransformFeedbackVarying(
+ &self,
+ program: &WebGLProgram,
+ index: u32,
+ ) -> Option<DomRoot<WebGLActiveInfo>> {
+ handle_potential_webgl_error!(self.base, program.validate(), return None);
+ if index >= program.transform_feedback_varyings_length() as u32 {
+ self.base.webgl_error(InvalidValue);
+ return None;
+ }
+
+ let (sender, receiver) = webgl_channel().unwrap();
+ self.base
+ .send_command(WebGLCommand::GetTransformFeedbackVarying(
+ program.id(),
+ index,
+ sender,
+ ));
+ let (size, ty, name) = receiver.recv().unwrap();
+ Some(WebGLActiveInfo::new(
+ self.base.global().as_window(),
+ size,
+ ty,
+ DOMString::from(name),
+ ))
+ }
}
impl LayoutCanvasWebGLRenderingContextHelpers for LayoutDom<WebGL2RenderingContext> {
diff --git a/components/script/dom/webgl_extensions/extensions.rs b/components/script/dom/webgl_extensions/extensions.rs
index fa502ca26cd..b7a2f2beb80 100644
--- a/components/script/dom/webgl_extensions/extensions.rs
+++ b/components/script/dom/webgl_extensions/extensions.rs
@@ -140,7 +140,7 @@ impl WebGLExtensionFeatures {
}
/// Handles the list of implemented, supported and enabled WebGL extensions.
-#[must_root]
+#[unrooted_must_root_lint::must_root]
#[derive(JSTraceable, MallocSizeOf)]
pub struct WebGLExtensions {
extensions: DomRefCell<HashMap<String, Box<dyn WebGLExtensionWrapper>>>,
diff --git a/components/script/dom/webgl_extensions/wrapper.rs b/components/script/dom/webgl_extensions/wrapper.rs
index 6af68c4678e..bf8db31418c 100644
--- a/components/script/dom/webgl_extensions/wrapper.rs
+++ b/components/script/dom/webgl_extensions/wrapper.rs
@@ -28,7 +28,7 @@ pub trait WebGLExtensionWrapper: JSTraceable + MallocSizeOf {
fn as_any(&self) -> &dyn Any;
}
-#[must_root]
+#[unrooted_must_root_lint::must_root]
#[derive(JSTraceable, MallocSizeOf)]
pub struct TypedWebGLExtensionWrapper<T: WebGLExtension> {
extension: MutNullableDom<T::Extension>,
diff --git a/components/script/dom/webglframebuffer.rs b/components/script/dom/webglframebuffer.rs
index df9e194962e..def5b36a27f 100644
--- a/components/script/dom/webglframebuffer.rs
+++ b/components/script/dom/webglframebuffer.rs
@@ -29,7 +29,7 @@ pub enum CompleteForRendering {
MissingColorAttachment,
}
-#[must_root]
+#[unrooted_must_root_lint::must_root]
#[derive(Clone, JSTraceable, MallocSizeOf)]
enum WebGLFramebufferAttachment {
Renderbuffer(Dom<WebGLRenderbuffer>),
diff --git a/components/script/dom/webglprogram.rs b/components/script/dom/webglprogram.rs
index 6863bc89e53..e4f5f89c6d3 100644
--- a/components/script/dom/webglprogram.rs
+++ b/components/script/dom/webglprogram.rs
@@ -34,6 +34,8 @@ pub struct WebGLProgram {
vertex_shader: MutNullableDom<WebGLShader>,
active_attribs: DomRefCell<Box<[ActiveAttribInfo]>>,
active_uniforms: DomRefCell<Box<[ActiveUniformInfo]>>,
+ transform_feedback_varyings_length: Cell<i32>,
+ transform_feedback_mode: Cell<i32>,
}
impl WebGLProgram {
@@ -50,6 +52,8 @@ impl WebGLProgram {
vertex_shader: Default::default(),
active_attribs: DomRefCell::new(vec![].into()),
active_uniforms: DomRefCell::new(vec![].into()),
+ transform_feedback_varyings_length: Default::default(),
+ transform_feedback_mode: Default::default(),
}
}
@@ -187,6 +191,10 @@ impl WebGLProgram {
self.linked.set(link_info.linked);
self.link_called.set(true);
+ self.transform_feedback_varyings_length
+ .set(link_info.transform_feedback_length);
+ self.transform_feedback_mode
+ .set(link_info.transform_feedback_mode);
*self.active_attribs.borrow_mut() = link_info.active_attribs;
*self.active_uniforms.borrow_mut() = link_info.active_uniforms;
Ok(())
@@ -444,6 +452,14 @@ impl WebGLProgram {
pub fn link_generation(&self) -> u64 {
self.link_generation.get()
}
+
+ pub fn transform_feedback_varyings_length(&self) -> i32 {
+ self.transform_feedback_varyings_length.get()
+ }
+
+ pub fn transform_feedback_buffer_mode(&self) -> i32 {
+ self.transform_feedback_mode.get()
+ }
}
impl Drop for WebGLProgram {
diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs
index f0e4887858c..85930cd3529 100644
--- a/components/script/dom/webglrenderingcontext.rs
+++ b/components/script/dom/webglrenderingcontext.rs
@@ -380,7 +380,7 @@ impl WebGLRenderingContext {
//
// The WebGL spec mentions a couple more operations that trigger
// this: clear() and getParameter(IMPLEMENTATION_COLOR_READ_*).
- fn validate_framebuffer(&self) -> WebGLResult<()> {
+ pub fn validate_framebuffer(&self) -> WebGLResult<()> {
match self.bound_framebuffer.get() {
Some(fb) => match fb.check_status_for_rendering() {
CompleteForRendering::Complete => Ok(()),
@@ -481,7 +481,7 @@ impl WebGLRenderingContext {
self.send_command(WebGLCommand::VertexAttrib(indx, x, y, z, w));
}
- fn get_current_framebuffer_size(&self) -> Option<(i32, i32)> {
+ pub fn get_current_framebuffer_size(&self) -> Option<(i32, i32)> {
match self.bound_framebuffer.get() {
Some(fb) => return fb.size(),
@@ -490,6 +490,10 @@ impl WebGLRenderingContext {
}
}
+ pub fn get_texture_packing_alignment(&self) -> u8 {
+ self.texture_packing_alignment.get()
+ }
+
// LINEAR filtering may be forbidden when using WebGL extensions.
// https://www.khronos.org/registry/webgl/extensions/OES_texture_float_linear/
fn validate_filterable_texture(
@@ -1165,6 +1169,10 @@ impl WebGLRenderingContext {
slot.set(buffer);
}
+
+ pub fn current_program(&self) -> Option<DomRoot<WebGLProgram>> {
+ self.current_program.get()
+ }
}
#[cfg(not(feature = "webgl_backtrace"))]
@@ -2959,11 +2967,16 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
let src_origin = Point2D::new(x, y);
let src_size = Size2D::new(width as u32, height as u32);
let fb_size = Size2D::new(fb_width as u32, fb_height as u32);
- let src_rect = match pixels::clip(src_origin, src_size, fb_size) {
+ let src_rect = match pixels::clip(src_origin, src_size.to_u64(), fb_size.to_u64()) {
Some(rect) => rect,
None => return,
};
+ // Note: we're casting a Rect<u64> back into a Rect<u32> here, but it's okay because
+ // it used u32 data types to begin with. It just got converted to Rect<u64> in
+ // pixels::clip
+ let src_rect = src_rect.to_u32();
+
let mut dest_offset = 0;
if x < 0 {
dest_offset += -x * bytes_per_pixel;
@@ -4266,7 +4279,7 @@ capabilities! {
STENCIL_TEST,
}
-#[must_root]
+#[unrooted_must_root_lint::must_root]
#[derive(JSTraceable, MallocSizeOf)]
pub struct Textures {
active_unit: Cell<u32>,
@@ -4334,7 +4347,7 @@ impl Textures {
}
}
-#[must_root]
+#[unrooted_must_root_lint::must_root]
#[derive(Default, JSTraceable, MallocSizeOf)]
struct TextureUnit {
tex_2d: MutNullableDom<WebGLTexture>,
@@ -4481,3 +4494,13 @@ impl WebGLMessageSender {
self.wake_after_send(|| self.sender.send_dom_to_texture(command))
}
}
+
+pub trait Size2DExt {
+ fn to_u64(&self) -> Size2D<u64>;
+}
+
+impl Size2DExt for Size2D<u32> {
+ fn to_u64(&self) -> Size2D<u64> {
+ return Size2D::new(self.width as u64, self.height as u64);
+ }
+}
diff --git a/components/script/dom/webgltransformfeedback.rs b/components/script/dom/webgltransformfeedback.rs
new file mode 100644
index 00000000000..a58a8e43577
--- /dev/null
+++ b/components/script/dom/webgltransformfeedback.rs
@@ -0,0 +1,133 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+use crate::dom::bindings::codegen::Bindings::WebGLTransformFeedbackBinding;
+use crate::dom::bindings::inheritance::Castable;
+use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
+use crate::dom::bindings::root::DomRoot;
+use crate::dom::webglobject::WebGLObject;
+use crate::dom::webglrenderingcontext::WebGLRenderingContext;
+use canvas_traits::webgl::{webgl_channel, WebGLCommand};
+use dom_struct::dom_struct;
+use std::cell::Cell;
+
+#[dom_struct]
+pub struct WebGLTransformFeedback {
+ webgl_object: WebGLObject,
+ id: u32,
+ marked_for_deletion: Cell<bool>,
+ has_been_bound: Cell<bool>,
+ is_active: Cell<bool>,
+ is_paused: Cell<bool>,
+}
+
+impl WebGLTransformFeedback {
+ fn new_inherited(context: &WebGLRenderingContext, id: u32) -> Self {
+ Self {
+ webgl_object: WebGLObject::new_inherited(context),
+ id,
+ marked_for_deletion: Cell::new(false),
+ has_been_bound: Cell::new(false),
+ is_active: Cell::new(false),
+ is_paused: Cell::new(false),
+ }
+ }
+
+ pub fn new(context: &WebGLRenderingContext) -> DomRoot<Self> {
+ let (sender, receiver) = webgl_channel().unwrap();
+ context.send_command(WebGLCommand::CreateTransformFeedback(sender));
+ let id = receiver.recv().unwrap();
+
+ reflect_dom_object(
+ Box::new(WebGLTransformFeedback::new_inherited(context, id)),
+ &*context.global(),
+ WebGLTransformFeedbackBinding::Wrap,
+ )
+ }
+}
+
+impl WebGLTransformFeedback {
+ pub fn bind(&self, context: &WebGLRenderingContext, target: u32) {
+ context.send_command(WebGLCommand::BindTransformFeedback(target, self.id()));
+ self.has_been_bound.set(true);
+ }
+
+ pub fn begin(&self, context: &WebGLRenderingContext, primitive_mode: u32) {
+ if self.has_been_bound.get() && !self.is_active() {
+ context.send_command(WebGLCommand::BeginTransformFeedback(primitive_mode));
+ self.set_active(true);
+ }
+ }
+
+ pub fn end(&self, context: &WebGLRenderingContext) {
+ if self.has_been_bound.get() && self.is_active() {
+ if self.is_paused() {
+ context.send_command(WebGLCommand::ResumeTransformFeedback());
+ }
+ context.send_command(WebGLCommand::EndTransformFeedback());
+ self.set_active(false);
+ }
+ }
+
+ pub fn resume(&self, context: &WebGLRenderingContext) {
+ if self.is_active() && self.is_paused() {
+ context.send_command(WebGLCommand::ResumeTransformFeedback());
+ self.set_pause(false);
+ }
+ }
+
+ pub fn pause(&self, context: &WebGLRenderingContext) {
+ if self.is_active() && !self.is_paused() {
+ context.send_command(WebGLCommand::PauseTransformFeedback());
+ self.set_pause(true);
+ }
+ }
+
+ pub fn id(&self) -> u32 {
+ self.id
+ }
+
+ pub fn is_valid(&self) -> bool {
+ !self.marked_for_deletion.get()
+ }
+
+ pub fn is_active(&self) -> bool {
+ self.is_active.get()
+ }
+
+ pub fn is_paused(&self) -> bool {
+ self.is_paused.get()
+ }
+
+ pub fn delete(&self, fallible: bool) {
+ if self.is_valid() && self.id() != 0 {
+ self.marked_for_deletion.set(true);
+ let context = self.upcast::<WebGLObject>().context();
+ let cmd = WebGLCommand::DeleteTransformFeedback(self.id);
+ if fallible {
+ context.send_command_ignored(cmd);
+ } else {
+ context.send_command(cmd);
+ }
+ }
+ }
+
+ pub fn set_active(&self, value: bool) {
+ if self.is_valid() && self.has_been_bound.get() {
+ self.is_active.set(value);
+ }
+ }
+
+ pub fn set_pause(&self, value: bool) {
+ if self.is_valid() && self.is_active() {
+ self.is_active.set(value);
+ }
+ }
+}
+
+impl Drop for WebGLTransformFeedback {
+ fn drop(&mut self) {
+ self.delete(true);
+ }
+}
diff --git a/components/script/dom/webglvertexarrayobjectoes.rs b/components/script/dom/webglvertexarrayobjectoes.rs
index 22d162782d8..e54eaf3f04a 100644
--- a/components/script/dom/webglvertexarrayobjectoes.rs
+++ b/components/script/dom/webglvertexarrayobjectoes.rs
@@ -258,7 +258,7 @@ impl Drop for WebGLVertexArrayObjectOES {
}
#[derive(Clone, JSTraceable, MallocSizeOf)]
-#[must_root]
+#[unrooted_must_root_lint::must_root]
pub struct VertexAttribData {
pub enabled_as_array: bool,
pub size: u8,
diff --git a/components/script/dom/webidls/AudioContext.webidl b/components/script/dom/webidls/AudioContext.webidl
index 9e5dd6bd556..cd9e18edfa0 100644
--- a/components/script/dom/webidls/AudioContext.webidl
+++ b/components/script/dom/webidls/AudioContext.webidl
@@ -33,7 +33,7 @@ interface AudioContext : BaseAudioContext {
Promise<void> suspend();
Promise<void> close();
- // MediaElementAudioSourceNode createMediaElementSource(HTMLMediaElement mediaElement);
+ [Throws] MediaElementAudioSourceNode createMediaElementSource(HTMLMediaElement mediaElement);
// MediaStreamAudioSourceNode createMediaStreamSource(MediaStream mediaStream);
// MediaStreamTrackAudioSourceNode createMediaStreamTrackSource(MediaStreamTrack mediaStreamTrack);
// MediaStreamAudioDestinationNode createMediaStreamDestination();
diff --git a/components/script/dom/webidls/Bluetooth.webidl b/components/script/dom/webidls/Bluetooth.webidl
index a24206036bf..e5e135c0577 100644
--- a/components/script/dom/webidls/Bluetooth.webidl
+++ b/components/script/dom/webidls/Bluetooth.webidl
@@ -21,7 +21,7 @@ dictionary BluetoothLEScanFilterInit {
dictionary RequestDeviceOptions {
sequence<BluetoothLEScanFilterInit> filters;
- sequence<BluetoothServiceUUID> optionalServices /*= []*/;
+ sequence<BluetoothServiceUUID> optionalServices = [];
boolean acceptAllDevices = false;
};
diff --git a/components/script/dom/webidls/BluetoothPermissionResult.webidl b/components/script/dom/webidls/BluetoothPermissionResult.webidl
index 4f9f2871a2e..95c06797aef 100644
--- a/components/script/dom/webidls/BluetoothPermissionResult.webidl
+++ b/components/script/dom/webidls/BluetoothPermissionResult.webidl
@@ -8,7 +8,7 @@ dictionary BluetoothPermissionDescriptor : PermissionDescriptor {
DOMString deviceId;
// These match RequestDeviceOptions.
sequence<BluetoothLEScanFilterInit> filters;
- sequence<BluetoothServiceUUID> optionalServices/* = []*/;
+ sequence<BluetoothServiceUUID> optionalServices = [];
boolean acceptAllDevices = false;
};
diff --git a/components/script/dom/webidls/DissimilarOriginWindow.webidl b/components/script/dom/webidls/DissimilarOriginWindow.webidl
index bbfcb75b69b..b690736469a 100644
--- a/components/script/dom/webidls/DissimilarOriginWindow.webidl
+++ b/components/script/dom/webidls/DissimilarOriginWindow.webidl
@@ -25,7 +25,7 @@ interface DissimilarOriginWindow : GlobalScope {
void close();
readonly attribute boolean closed;
- [Throws] void postMessage(any message, USVString targetOrigin, optional sequence<object> transfer /*= []*/);
+ [Throws] void postMessage(any message, USVString targetOrigin, optional sequence<object> transfer = []);
[Throws] void postMessage(any message, optional WindowPostMessageOptions options = {});
attribute any opener;
void blur();
diff --git a/components/script/dom/webidls/FormDataEvent.webidl b/components/script/dom/webidls/FormDataEvent.webidl
index 5160a396081..0cb81b93962 100644
--- a/components/script/dom/webidls/FormDataEvent.webidl
+++ b/components/script/dom/webidls/FormDataEvent.webidl
@@ -5,10 +5,10 @@
// https://html.spec.whatwg.org/multipage/#the-formdataevent-interface
[Exposed=Window]
interface FormDataEvent : Event {
- [Throws] constructor(DOMString type, optional FormDataEventInit eventInitDict = {});
+ [Throws] constructor(DOMString type, FormDataEventInit eventInitDict);
readonly attribute FormData formData;
};
dictionary FormDataEventInit : EventInit {
- /*required*/ FormData formData;
+ required FormData formData;
};
diff --git a/components/script/dom/webidls/GPU.webidl b/components/script/dom/webidls/GPU.webidl
new file mode 100644
index 00000000000..856c5027569
--- /dev/null
+++ b/components/script/dom/webidls/GPU.webidl
@@ -0,0 +1,21 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+// https://gpuweb.github.io/gpuweb/#gpu-interface
+[Exposed=(Window, DedicatedWorker), Pref="dom.webgpu.enabled"]
+interface GPU {
+ // May reject with DOMException // TODO: DOMException("OperationError")?
+ Promise<GPUAdapter> requestAdapter(optional GPURequestAdapterOptions options = {});
+};
+
+// https://gpuweb.github.io/gpuweb/#dictdef-gpurequestadapteroptions
+dictionary GPURequestAdapterOptions {
+ GPUPowerPreference powerPreference;
+};
+
+// https://gpuweb.github.io/gpuweb/#enumdef-gpupowerpreference
+enum GPUPowerPreference {
+ "low-power",
+ "high-performance"
+};
diff --git a/components/script/dom/webidls/GPUAdapter.webidl b/components/script/dom/webidls/GPUAdapter.webidl
new file mode 100644
index 00000000000..0c2118a5f56
--- /dev/null
+++ b/components/script/dom/webidls/GPUAdapter.webidl
@@ -0,0 +1,14 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+// https://gpuweb.github.io/gpuweb/#gpuadapter
+[Exposed=(Window, DedicatedWorker), Pref="dom.webgpu.enabled"]
+interface GPUAdapter {
+ readonly attribute DOMString name;
+ readonly attribute object extensions;
+ //readonly attribute GPULimits limits; Don’t expose higher limits for now.
+
+ // May reject with DOMException // TODO: DOMException("OperationError")?
+ // Promise<GPUDevice> requestDevice(optional GPUDeviceDescriptor descriptor = {});
+};
diff --git a/components/script/dom/webidls/HTMLIFrameElement.webidl b/components/script/dom/webidls/HTMLIFrameElement.webidl
index acc4f0f201d..b9dd97bdea6 100644
--- a/components/script/dom/webidls/HTMLIFrameElement.webidl
+++ b/components/script/dom/webidls/HTMLIFrameElement.webidl
@@ -9,8 +9,8 @@ interface HTMLIFrameElement : HTMLElement {
[CEReactions]
attribute USVString src;
- // [CEReactions]
- // attribute DOMString srcdoc;
+ [CEReactions]
+ attribute DOMString srcdoc;
[CEReactions]
attribute DOMString name;
diff --git a/components/script/dom/webidls/MediaElementAudioSourceNode.webidl b/components/script/dom/webidls/MediaElementAudioSourceNode.webidl
new file mode 100644
index 00000000000..5afe7775caa
--- /dev/null
+++ b/components/script/dom/webidls/MediaElementAudioSourceNode.webidl
@@ -0,0 +1,17 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+/*
+ * The origin of this IDL file is
+ * https://webaudio.github.io/web-audio-api/#mediaelementaudiosourcenode
+ */
+
+dictionary MediaElementAudioSourceOptions {
+ required HTMLMediaElement mediaElement;
+};
+
+[Exposed=Window]
+interface MediaElementAudioSourceNode : AudioNode {
+ [Throws] constructor (AudioContext context, MediaElementAudioSourceOptions options);
+ [SameObject] readonly attribute HTMLMediaElement mediaElement;
+};
diff --git a/components/script/dom/webidls/MediaMetadata.webidl b/components/script/dom/webidls/MediaMetadata.webidl
new file mode 100644
index 00000000000..495aeef8e35
--- /dev/null
+++ b/components/script/dom/webidls/MediaMetadata.webidl
@@ -0,0 +1,30 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+/*
+ * The origin of this IDL file is
+ * https://w3c.github.io/mediasession/#mediametadata
+ */
+
+dictionary MediaImage {
+ required USVString src;
+ DOMString sizes = "";
+ DOMString type = "";
+};
+
+[Exposed=Window]
+interface MediaMetadata {
+ [Throws] constructor(optional MediaMetadataInit init = {});
+ attribute DOMString title;
+ attribute DOMString artist;
+ attribute DOMString album;
+ // TODO: https://github.com/servo/servo/issues/10072
+ // attribute FrozenArray<MediaImage> artwork;
+};
+
+dictionary MediaMetadataInit {
+ DOMString title = "";
+ DOMString artist = "";
+ DOMString album = "";
+ sequence<MediaImage> artwork = [];
+};
diff --git a/components/script/dom/webidls/MediaSession.webidl b/components/script/dom/webidls/MediaSession.webidl
new file mode 100644
index 00000000000..12b3fe062ba
--- /dev/null
+++ b/components/script/dom/webidls/MediaSession.webidl
@@ -0,0 +1,57 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+/*
+ * The origin of this IDL file is
+ * https://w3c.github.io/mediasession/#mediasession
+ */
+
+[Exposed=Window]
+partial interface Navigator {
+ [SameObject] readonly attribute MediaSession mediaSession;
+};
+
+enum MediaSessionPlaybackState {
+ "none",
+ "paused",
+ "playing"
+};
+
+enum MediaSessionAction {
+ "play",
+ "pause",
+ "seekbackward",
+ "seekforward",
+ "previoustrack",
+ "nexttrack",
+ "skipad",
+ "stop",
+ "seekto"
+};
+
+dictionary MediaSessionActionDetails {
+ required MediaSessionAction action;
+};
+
+dictionary MediaSessionSeekActionDetails : MediaSessionActionDetails {
+ double? seekOffset;
+};
+
+dictionary MediaSessionSeekToActionDetails : MediaSessionActionDetails {
+ required double seekTime;
+ boolean? fastSeek;
+};
+
+callback MediaSessionActionHandler = void(/*MediaSessionActionDetails details*/);
+
+[Exposed=Window]
+interface MediaSession {
+ attribute MediaMetadata? metadata;
+
+ attribute MediaSessionPlaybackState playbackState;
+
+ void setActionHandler(MediaSessionAction action, MediaSessionActionHandler? handler);
+
+ //void setPositionState(optional MediaPositionState? state);
+};
+
diff --git a/components/script/dom/webidls/MessageEvent.webidl b/components/script/dom/webidls/MessageEvent.webidl
index 63dd9019cc9..1d4699cbe3c 100644
--- a/components/script/dom/webidls/MessageEvent.webidl
+++ b/components/script/dom/webidls/MessageEvent.webidl
@@ -9,9 +9,7 @@ interface MessageEvent : Event {
readonly attribute any data;
readonly attribute DOMString origin;
readonly attribute DOMString lastEventId;
- // FIXME(#22617): WindowProxy is not exposed in Worker globals
- readonly attribute object? source;
- //readonly attribute (WindowProxy or MessagePort)? source;
+ readonly attribute MessageEventSource? source;
readonly attribute /*FrozenArray<MessagePort>*/any ports;
};
@@ -20,9 +18,8 @@ dictionary MessageEventInit : EventInit {
DOMString origin = "";
DOMString lastEventId = "";
//DOMString channel;
- Window? source;
- //(WindowProxy or MessagePort)? source;
- sequence<MessagePort> ports;
+ MessageEventSource? source = null;
+ sequence<MessagePort> ports = [];
};
-typedef (/*WindowProxy or */MessagePort or ServiceWorker) MessageEventSource;
+typedef (WindowProxy or MessagePort or ServiceWorker) MessageEventSource;
diff --git a/components/script/dom/webidls/MessagePort.webidl b/components/script/dom/webidls/MessagePort.webidl
index c2fd1dbd1f4..58a3f06a960 100644
--- a/components/script/dom/webidls/MessagePort.webidl
+++ b/components/script/dom/webidls/MessagePort.webidl
@@ -8,7 +8,7 @@
[Exposed=(Window,Worker)]
interface MessagePort : EventTarget {
- [Throws] void postMessage(any message, sequence<object> transfer /*= []*/);
+ [Throws] void postMessage(any message, sequence<object> transfer);
[Throws] void postMessage(any message, optional PostMessageOptions options = {});
void start();
void close();
@@ -19,5 +19,5 @@ interface MessagePort : EventTarget {
};
dictionary PostMessageOptions {
- sequence<object> transfer;
+ sequence<object> transfer = [];
};
diff --git a/components/script/dom/webidls/Navigator.webidl b/components/script/dom/webidls/Navigator.webidl
index 6b5b1e1f283..b51e2ba52f0 100644
--- a/components/script/dom/webidls/Navigator.webidl
+++ b/components/script/dom/webidls/Navigator.webidl
@@ -75,3 +75,8 @@ partial interface Navigator {
partial interface Navigator {
[Pref="dom.gamepad.enabled"] GamepadList getGamepads();
};
+
+[Exposed=Window]
+partial interface Navigator {
+ [SameObject, Pref="dom.webgpu.enabled"] readonly attribute GPU gpu;
+};
diff --git a/components/script/dom/webidls/PromiseRejectionEvent.webidl b/components/script/dom/webidls/PromiseRejectionEvent.webidl
index 6ef93b8b1a7..70d11b1ff33 100644
--- a/components/script/dom/webidls/PromiseRejectionEvent.webidl
+++ b/components/script/dom/webidls/PromiseRejectionEvent.webidl
@@ -6,12 +6,12 @@
[Exposed=(Window,Worker)]
interface PromiseRejectionEvent : Event {
- [Throws] constructor(DOMString type, optional PromiseRejectionEventInit eventInitDict = {});
+ [Throws] constructor(DOMString type, PromiseRejectionEventInit eventInitDict);
readonly attribute Promise<any> promise;
readonly attribute any reason;
};
dictionary PromiseRejectionEventInit : EventInit {
- /* required */ Promise<any> promise;
+ required Promise<any> promise;
any reason;
};
diff --git a/components/script/dom/webidls/WebGL2RenderingContext.webidl b/components/script/dom/webidls/WebGL2RenderingContext.webidl
index c171a9bb866..71b5ab10034 100644
--- a/components/script/dom/webidls/WebGL2RenderingContext.webidl
+++ b/components/script/dom/webidls/WebGL2RenderingContext.webidl
@@ -12,9 +12,6 @@ typedef long long GLint64;
typedef unsigned long long GLuint64;
-// interface WebGLTransformFeedback : WebGLObject {
-// };
-
// interface WebGLVertexArrayObject : WebGLObject {
// };
@@ -500,10 +497,10 @@ interface mixin WebGL2RenderingContextBase
void readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type,
/*[AllowShared]*/ ArrayBufferView? dstData);
// WebGL2:
- // void readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type,
- // GLintptr offset);
- // void readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type,
- // [AllowShared] ArrayBufferView dstData, GLuint dstOffset);
+ void readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type,
+ GLintptr offset);
+ void readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type,
+ /*[AllowShared]*/ ArrayBufferView dstData, GLuint dstOffset);
/* Multiple Render Targets */
// void drawBuffers(sequence<GLenum> buffers);
@@ -544,7 +541,7 @@ interface mixin WebGL2RenderingContextBase
any getSyncParameter(WebGLSync sync, GLenum pname);
/* Transform Feedback */
- /*WebGLTransformFeedback? createTransformFeedback();
+ WebGLTransformFeedback? createTransformFeedback();
void deleteTransformFeedback(WebGLTransformFeedback? tf);
[WebGLHandlesContextLoss] GLboolean isTransformFeedback(WebGLTransformFeedback? tf);
void bindTransformFeedback (GLenum target, WebGLTransformFeedback? tf);
@@ -553,7 +550,7 @@ interface mixin WebGL2RenderingContextBase
void transformFeedbackVaryings(WebGLProgram program, sequence<DOMString> varyings, GLenum bufferMode);
WebGLActiveInfo? getTransformFeedbackVarying(WebGLProgram program, GLuint index);
void pauseTransformFeedback();
- void resumeTransformFeedback();*/
+ void resumeTransformFeedback();
/* Uniform Buffer Objects and Transform Feedback Buffers */
// void bindBufferBase(GLenum target, GLuint index, WebGLBuffer? buffer);
diff --git a/components/script/dom/webidls/WebGLTransformFeedback.webidl b/components/script/dom/webidls/WebGLTransformFeedback.webidl
new file mode 100644
index 00000000000..871c0f15c7b
--- /dev/null
+++ b/components/script/dom/webidls/WebGLTransformFeedback.webidl
@@ -0,0 +1,11 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+//
+// WebGL IDL definitions scraped from the Khronos specification:
+// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.15
+//
+
+[Exposed=(Window), Pref="dom.webgl2.enabled"]
+interface WebGLTransformFeedback : WebGLObject {
+};
diff --git a/components/script/dom/webidls/Window.webidl b/components/script/dom/webidls/Window.webidl
index 26edbca5c7a..f2cdeeb18a5 100644
--- a/components/script/dom/webidls/Window.webidl
+++ b/components/script/dom/webidls/Window.webidl
@@ -64,7 +64,7 @@
void cancelAnimationFrame(unsigned long handle);
[Throws]
- void postMessage(any message, USVString targetOrigin, optional sequence<object> transfer /*= []*/);
+ void postMessage(any message, USVString targetOrigin, optional sequence<object> transfer = []);
[Throws]
void postMessage(any message, optional WindowPostMessageOptions options = {});
@@ -175,7 +175,6 @@ partial interface Window {
readonly attribute unsigned long runningAnimationCount;
};
-dictionary WindowPostMessageOptions {
+dictionary WindowPostMessageOptions : PostMessageOptions {
USVString targetOrigin = "/";
- sequence<object> transfer;
};
diff --git a/components/script/dom/webidls/WindowOrWorkerGlobalScope.webidl b/components/script/dom/webidls/WindowOrWorkerGlobalScope.webidl
index b4cc66705af..c798b56ab00 100644
--- a/components/script/dom/webidls/WindowOrWorkerGlobalScope.webidl
+++ b/components/script/dom/webidls/WindowOrWorkerGlobalScope.webidl
@@ -4,8 +4,7 @@
// https://html.spec.whatwg.org/multipage/#windoworworkerglobalscope
-// FIXME(nox): https://github.com/servo/servo/issues/20700
-// typedef (DOMString or Function) TimerHandler;
+typedef (DOMString or Function) TimerHandler;
[Exposed=(Window,Worker)]
interface mixin WindowOrWorkerGlobalScope {
@@ -16,13 +15,9 @@ interface mixin WindowOrWorkerGlobalScope {
[Throws] DOMString atob(DOMString data);
// timers
- // FIXME(nox): https://github.com/servo/servo/issues/20700
- long setTimeout(Function handler, optional long timeout = 0, any... arguments);
- long setTimeout(DOMString handler, optional long timeout = 0, any... arguments);
+ long setTimeout(TimerHandler handler, optional long timeout = 0, any... arguments);
void clearTimeout(optional long handle = 0);
- // FIXME(nox): https://github.com/servo/servo/issues/20700
- long setInterval(Function handler, optional long timeout = 0, any... arguments);
- long setInterval(DOMString handler, optional long timeout = 0, any... arguments);
+ long setInterval(TimerHandler handler, optional long timeout = 0, any... arguments);
void clearInterval(optional long handle = 0);
// ImageBitmap
diff --git a/components/script/dom/webidls/WorkerNavigator.webidl b/components/script/dom/webidls/WorkerNavigator.webidl
index 119e22ea11f..5be43960802 100644
--- a/components/script/dom/webidls/WorkerNavigator.webidl
+++ b/components/script/dom/webidls/WorkerNavigator.webidl
@@ -15,3 +15,8 @@ WorkerNavigator includes NavigatorLanguage;
partial interface WorkerNavigator {
[Pref="dom.permissions.enabled"] readonly attribute Permissions permissions;
};
+
+[Exposed=DedicatedWorker]
+partial interface WorkerNavigator {
+ [SameObject, Pref="dom.webgpu.enabled"] readonly attribute GPU gpu;
+};
diff --git a/components/script/dom/webidls/XRSession.webidl b/components/script/dom/webidls/XRSession.webidl
index be8fb36e7bf..e726a500cb7 100644
--- a/components/script/dom/webidls/XRSession.webidl
+++ b/components/script/dom/webidls/XRSession.webidl
@@ -39,8 +39,11 @@ interface XRSession : EventTarget {
// // Events
attribute EventHandler onend;
attribute EventHandler onselect;
+ attribute EventHandler onsqueeze;
// attribute EventHandler oninputsourceschange;
attribute EventHandler onselectstart;
attribute EventHandler onselectend;
+ attribute EventHandler onsqueezestart;
+ attribute EventHandler onsqueezeend;
attribute EventHandler onvisibilitychange;
};
diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs
index 37b5b5e3b2c..d48f16ea662 100644
--- a/components/script/dom/window.rs
+++ b/components/script/dom/window.rs
@@ -7,7 +7,6 @@ use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::DocumentBinding::{
DocumentMethods, DocumentReadyState,
};
-use crate::dom::bindings::codegen::Bindings::FunctionBinding::Function;
use crate::dom::bindings::codegen::Bindings::HistoryBinding::HistoryBinding::HistoryMethods;
use crate::dom::bindings::codegen::Bindings::MediaQueryListBinding::MediaQueryListBinding::MediaQueryListMethods;
use crate::dom::bindings::codegen::Bindings::PermissionStatusBinding::PermissionState;
@@ -16,7 +15,7 @@ use crate::dom::bindings::codegen::Bindings::WindowBinding::{
self, FrameRequestCallback, WindowMethods, WindowPostMessageOptions,
};
use crate::dom::bindings::codegen::Bindings::WindowBinding::{ScrollBehavior, ScrollToOptions};
-use crate::dom::bindings::codegen::UnionTypes::RequestOrUSVString;
+use crate::dom::bindings::codegen::UnionTypes::{RequestOrUSVString, StringOrFunction};
use crate::dom::bindings::error::{Error, ErrorResult, Fallible};
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::num::Finite;
@@ -89,7 +88,7 @@ use js::jsval::{JSVal, NullValue};
use js::rust::wrappers::JS_DefineProperty;
use js::rust::{CustomAutoRooter, CustomAutoRooterGuard, HandleValue};
use media::WindowGLContext;
-use msg::constellation_msg::PipelineId;
+use msg::constellation_msg::{BrowsingContextId, PipelineId};
use net_traits::image_cache::{ImageCache, ImageResponder, ImageResponse};
use net_traits::image_cache::{PendingImageId, PendingImageResponse};
use net_traits::storage_thread::StorageType;
@@ -107,10 +106,9 @@ use script_layout_interface::{PendingImageState, TrustedNodeAddress};
use script_traits::webdriver_msg::{WebDriverJSError, WebDriverJSResult};
use script_traits::{ConstellationControlMsg, DocumentState, HistoryEntryReplacement, LoadData};
use script_traits::{
- ScriptMsg, ScriptToConstellationChan, ScrollState, StructuredSerializedData, TimerEvent,
- TimerEventId,
+ ScriptMsg, ScriptToConstellationChan, ScrollState, StructuredSerializedData, TimerEventId,
};
-use script_traits::{TimerSchedulerMsg, WindowSizeData, WindowSizeType};
+use script_traits::{TimerSchedulerMsg, WebrenderIpcSender, WindowSizeData, WindowSizeType};
use selectors::attr::CaseSensitivity;
use servo_geometry::{f32_rect_to_au_rect, MaxRect};
use servo_url::{Host, ImmutableOrigin, MutableOrigin, ServoUrl};
@@ -137,8 +135,9 @@ use style::str::HTML_SPACE_CHARACTERS;
use style::stylesheets::CssRuleType;
use style_traits::{CSSPixel, DevicePixel, ParsingMode};
use url::Position;
+use webgpu::WebGPU;
use webrender_api::units::{DeviceIntPoint, DeviceIntSize, LayoutPixel};
-use webrender_api::{DocumentId, ExternalScrollId, RenderApiSender};
+use webrender_api::{DocumentId, ExternalScrollId};
use webvr_traits::WebVRMsg;
/// Current state of the window object
@@ -268,6 +267,10 @@ pub struct Window {
#[ignore_malloc_size_of = "channels are hard"]
webgl_chan: Option<WebGLChan>,
+ #[ignore_malloc_size_of = "channels are hard"]
+ /// A handle for communicating messages to the WebGPU threads.
+ webgpu: Option<WebGPU>,
+
/// A handle for communicating messages to the webvr thread, if available.
#[ignore_malloc_size_of = "channels are hard"]
webvr_chan: Option<IpcSender<WebVRMsg>>,
@@ -300,8 +303,8 @@ pub struct Window {
exists_mut_observer: Cell<bool>,
/// Webrender API Sender
- #[ignore_malloc_size_of = "defined in webrender_api"]
- webrender_api_sender: RenderApiSender,
+ #[ignore_malloc_size_of = "Wraps an IpcSender"]
+ webrender_api_sender: WebrenderIpcSender,
/// Indicate whether a SetDocumentStatus message has been sent after a reflow is complete.
/// It is used to avoid sending idle message more than once, which is unneccessary.
@@ -463,6 +466,10 @@ impl Window {
.map(|chan| WebGLCommandSender::new(chan.clone(), self.get_event_loop_waker()))
}
+ pub fn webgpu_channel(&self) -> Option<WebGPU> {
+ self.webgpu.clone()
+ }
+
pub fn webvr_thread(&self) -> Option<IpcSender<WebVRMsg>> {
self.webvr_chan.clone()
}
@@ -506,7 +513,7 @@ impl Window {
self.add_pending_reflow();
}
- pub fn get_webrender_api_sender(&self) -> RenderApiSender {
+ pub fn get_webrender_api_sender(&self) -> WebrenderIpcSender {
self.webrender_api_sender.clone()
}
@@ -817,28 +824,16 @@ impl WindowMethods for Window {
fn SetTimeout(
&self,
_cx: JSContext,
- callback: Rc<Function>,
- timeout: i32,
- args: Vec<HandleValue>,
- ) -> i32 {
- self.upcast::<GlobalScope>().set_timeout_or_interval(
- TimerCallback::FunctionTimerCallback(callback),
- args,
- timeout,
- IsInterval::NonInterval,
- )
- }
-
- // https://html.spec.whatwg.org/multipage/#dom-windowtimers-settimeout
- fn SetTimeout_(
- &self,
- _cx: JSContext,
- callback: DOMString,
+ callback: StringOrFunction,
timeout: i32,
args: Vec<HandleValue>,
) -> i32 {
+ let callback = match callback {
+ StringOrFunction::String(i) => TimerCallback::StringTimerCallback(i),
+ StringOrFunction::Function(i) => TimerCallback::FunctionTimerCallback(i),
+ };
self.upcast::<GlobalScope>().set_timeout_or_interval(
- TimerCallback::StringTimerCallback(callback),
+ callback,
args,
timeout,
IsInterval::NonInterval,
@@ -855,28 +850,16 @@ impl WindowMethods for Window {
fn SetInterval(
&self,
_cx: JSContext,
- callback: Rc<Function>,
- timeout: i32,
- args: Vec<HandleValue>,
- ) -> i32 {
- self.upcast::<GlobalScope>().set_timeout_or_interval(
- TimerCallback::FunctionTimerCallback(callback),
- args,
- timeout,
- IsInterval::Interval,
- )
- }
-
- // https://html.spec.whatwg.org/multipage/#dom-windowtimers-setinterval
- fn SetInterval_(
- &self,
- _cx: JSContext,
- callback: DOMString,
+ callback: StringOrFunction,
timeout: i32,
args: Vec<HandleValue>,
) -> i32 {
+ let callback = match callback {
+ StringOrFunction::String(i) => TimerCallback::StringTimerCallback(i),
+ StringOrFunction::Function(i) => TimerCallback::FunctionTimerCallback(i),
+ };
self.upcast::<GlobalScope>().set_timeout_or_interval(
- TimerCallback::StringTimerCallback(callback),
+ callback,
args,
timeout,
IsInterval::Interval,
@@ -979,19 +962,13 @@ impl WindowMethods for Window {
cx: JSContext,
message: HandleValue,
target_origin: USVString,
- mut transfer: CustomAutoRooterGuard<Option<Vec<*mut JSObject>>>,
+ transfer: CustomAutoRooterGuard<Vec<*mut JSObject>>,
) -> ErrorResult {
let incumbent = GlobalScope::incumbent().expect("no incumbent global?");
let source = incumbent.as_window();
let source_origin = source.Document().origin().immutable().clone();
- if transfer.is_some() {
- let mut rooted = CustomAutoRooter::new(transfer.take().unwrap());
- let transfer = Some(CustomAutoRooterGuard::new(*cx, &mut rooted));
- self.post_message_impl(&target_origin, source_origin, source, cx, message, transfer)
- } else {
- self.post_message_impl(&target_origin, source_origin, source, cx, message, None)
- }
+ self.post_message_impl(&target_origin, source_origin, source, cx, message, transfer)
}
/// <https://html.spec.whatwg.org/multipage/#dom-messageport-postmessage>
@@ -1003,14 +980,13 @@ impl WindowMethods for Window {
) -> ErrorResult {
let mut rooted = CustomAutoRooter::new(
options
+ .parent
.transfer
- .as_ref()
- .unwrap_or(&Vec::with_capacity(0))
.iter()
.map(|js: &RootedTraceableBox<Heap<*mut JSObject>>| js.get())
.collect(),
);
- let transfer = Some(CustomAutoRooterGuard::new(*cx, &mut rooted));
+ let transfer = CustomAutoRooterGuard::new(*cx, &mut rooted);
let incumbent = GlobalScope::incumbent().expect("no incumbent global?");
let source = incumbent.as_window();
@@ -1330,10 +1306,10 @@ impl Window {
source: &Window,
cx: JSContext,
message: HandleValue,
- transfer: Option<CustomAutoRooterGuard<Vec<*mut JSObject>>>,
+ transfer: CustomAutoRooterGuard<Vec<*mut JSObject>>,
) -> ErrorResult {
// Step 1-2, 6-8.
- let data = structuredclone::write(cx, message, transfer)?;
+ let data = structuredclone::write(cx, message, Some(transfer))?;
// Step 3-5.
let target_origin = match target_origin.0[..].as_ref() {
@@ -1421,7 +1397,18 @@ impl Window {
self.current_state.set(WindowState::Zombie);
*self.js_runtime.borrow_mut() = None;
- self.window_proxy.set(None);
+
+ // If this is the currently active pipeline,
+ // nullify the window_proxy.
+ if let Some(proxy) = self.window_proxy.get() {
+ let pipeline_id = self.upcast::<GlobalScope>().pipeline_id();
+ if let Some(currently_active) = proxy.currently_active() {
+ if currently_active == pipeline_id {
+ self.window_proxy.set(None);
+ }
+ }
+ }
+
if let Some(performance) = self.performance.get() {
performance.clear_and_disable_performance_entry_buffer();
}
@@ -1836,6 +1823,16 @@ impl Window {
DOMString::from(resolved)
}
+ pub fn inner_window_dimensions_query(
+ &self,
+ browsing_context: BrowsingContextId,
+ ) -> Option<Size2D<f32, CSSPixel>> {
+ if !self.layout_reflow(QueryMsg::InnerWindowDimensionsQuery(browsing_context)) {
+ return None;
+ }
+ self.layout_rpc.inner_window_dimensions()
+ }
+
#[allow(unsafe_code)]
pub fn offset_parent_query(&self, node: &Node) -> (Option<DomRoot<Element>>, UntypedRect<Au>) {
if !self.layout_reflow(QueryMsg::OffsetParentQuery(node.to_opaque())) {
@@ -2208,7 +2205,6 @@ impl Window {
constellation_chan: ScriptToConstellationChan,
control_chan: IpcSender<ConstellationControlMsg>,
scheduler_chan: IpcSender<TimerSchedulerMsg>,
- timer_event_chan: IpcSender<TimerEvent>,
layout_chan: Sender<Msg>,
pipelineid: PipelineId,
parent_info: Option<PipelineId>,
@@ -2217,11 +2213,12 @@ impl Window {
navigation_start: u64,
navigation_start_precise: u64,
webgl_chan: Option<WebGLChan>,
+ webgpu: Option<WebGPU>,
webvr_chan: Option<IpcSender<WebVRMsg>>,
webxr_registry: webxr_api::Registry,
microtask_queue: Rc<MicrotaskQueue>,
webrender_document: DocumentId,
- webrender_api_sender: RenderApiSender,
+ webrender_api_sender: WebrenderIpcSender,
layout_is_busy: Arc<AtomicBool>,
relayout_event: bool,
prepare_for_screenshot: bool,
@@ -2251,7 +2248,6 @@ impl Window {
constellation_chan,
scheduler_chan,
resource_threads,
- timer_event_chan,
origin,
microtask_queue,
is_headless,
@@ -2296,6 +2292,7 @@ impl Window {
media_query_lists: DOMTracker::new(),
test_runner: Default::default(),
webgl_chan,
+ webgpu,
webvr_chan,
webxr_registry,
permission_state_invocation_results: Default::default(),
@@ -2366,6 +2363,7 @@ fn debug_reflow_events(id: PipelineId, reflow_goal: &ReflowGoal, reason: &Reflow
&QueryMsg::StyleQuery(_n) => "\tStyleQuery",
&QueryMsg::TextIndexQuery(..) => "\tTextIndexQuery",
&QueryMsg::ElementInnerTextQuery(_) => "\tElementInnerTextQuery",
+ &QueryMsg::InnerWindowDimensionsQuery(_) => "\tInnerWindowDimensionsQuery",
},
});
diff --git a/components/script/dom/worker.rs b/components/script/dom/worker.rs
index 3b9830f8ded..f08bdcab79e 100644
--- a/components/script/dom/worker.rs
+++ b/components/script/dom/worker.rs
@@ -218,8 +218,6 @@ impl WorkerMethods for Worker {
let mut rooted = CustomAutoRooter::new(
options
.transfer
- .as_ref()
- .unwrap_or(&Vec::with_capacity(0))
.iter()
.map(|js: &RootedTraceableBox<Heap<*mut JSObject>>| js.get())
.collect(),
diff --git a/components/script/dom/workerglobalscope.rs b/components/script/dom/workerglobalscope.rs
index 50cb8bb5aaf..e943b6b0ef4 100644
--- a/components/script/dom/workerglobalscope.rs
+++ b/components/script/dom/workerglobalscope.rs
@@ -4,11 +4,10 @@
use crate::compartments::InCompartment;
use crate::dom::bindings::cell::DomRefCell;
-use crate::dom::bindings::codegen::Bindings::FunctionBinding::Function;
use crate::dom::bindings::codegen::Bindings::RequestBinding::RequestInit;
use crate::dom::bindings::codegen::Bindings::WorkerBinding::WorkerType;
use crate::dom::bindings::codegen::Bindings::WorkerGlobalScopeBinding::WorkerGlobalScopeMethods;
-use crate::dom::bindings::codegen::UnionTypes::RequestOrUSVString;
+use crate::dom::bindings::codegen::UnionTypes::{RequestOrUSVString, StringOrFunction};
use crate::dom::bindings::error::{report_pending_exception, Error, ErrorResult, Fallible};
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::reflector::DomObject;
@@ -35,6 +34,7 @@ use crate::task_source::networking::NetworkingTaskSource;
use crate::task_source::performance_timeline::PerformanceTimelineTaskSource;
use crate::task_source::port_message::PortMessageQueue;
use crate::task_source::remote_event::RemoteEventTaskSource;
+use crate::task_source::timer::TimerTaskSource;
use crate::task_source::websocket::WebsocketTaskSource;
use crate::timers::{IsInterval, TimerCallback};
use crossbeam_channel::Receiver;
@@ -51,7 +51,6 @@ use net_traits::request::{
};
use net_traits::IpcSend;
use script_traits::WorkerGlobalScopeInit;
-use script_traits::{TimerEvent, TimerEventId};
use servo_url::{MutableOrigin, ServoUrl};
use std::cell::Ref;
use std::default::Default;
@@ -121,7 +120,6 @@ impl WorkerGlobalScope {
worker_url: ServoUrl,
runtime: Runtime,
from_devtools_receiver: Receiver<DevtoolScriptControlMsg>,
- timer_event_chan: IpcSender<TimerEvent>,
closing: Option<Arc<AtomicBool>>,
) -> Self {
// Install a pipeline-namespace in the current thread.
@@ -135,7 +133,6 @@ impl WorkerGlobalScope {
init.script_to_constellation_chan,
init.scheduler_chan,
init.resource_threads,
- timer_event_chan,
MutableOrigin::new(init.origin),
runtime.microtask_queue.clone(),
init.is_headless,
@@ -297,28 +294,16 @@ impl WorkerGlobalScopeMethods for WorkerGlobalScope {
fn SetTimeout(
&self,
_cx: JSContext,
- callback: Rc<Function>,
+ callback: StringOrFunction,
timeout: i32,
args: Vec<HandleValue>,
) -> i32 {
+ let callback = match callback {
+ StringOrFunction::String(i) => TimerCallback::StringTimerCallback(i),
+ StringOrFunction::Function(i) => TimerCallback::FunctionTimerCallback(i),
+ };
self.upcast::<GlobalScope>().set_timeout_or_interval(
- TimerCallback::FunctionTimerCallback(callback),
- args,
- timeout,
- IsInterval::NonInterval,
- )
- }
-
- // https://html.spec.whatwg.org/multipage/#dom-windowtimers-settimeout
- fn SetTimeout_(
- &self,
- _cx: JSContext,
- callback: DOMString,
- timeout: i32,
- args: Vec<HandleValue>,
- ) -> i32 {
- self.upcast::<GlobalScope>().set_timeout_or_interval(
- TimerCallback::StringTimerCallback(callback),
+ callback,
args,
timeout,
IsInterval::NonInterval,
@@ -335,28 +320,16 @@ impl WorkerGlobalScopeMethods for WorkerGlobalScope {
fn SetInterval(
&self,
_cx: JSContext,
- callback: Rc<Function>,
- timeout: i32,
- args: Vec<HandleValue>,
- ) -> i32 {
- self.upcast::<GlobalScope>().set_timeout_or_interval(
- TimerCallback::FunctionTimerCallback(callback),
- args,
- timeout,
- IsInterval::Interval,
- )
- }
-
- // https://html.spec.whatwg.org/multipage/#dom-windowtimers-setinterval
- fn SetInterval_(
- &self,
- _cx: JSContext,
- callback: DOMString,
+ callback: StringOrFunction,
timeout: i32,
args: Vec<HandleValue>,
) -> i32 {
+ let callback = match callback {
+ StringOrFunction::String(i) => TimerCallback::StringTimerCallback(i),
+ StringOrFunction::Function(i) => TimerCallback::FunctionTimerCallback(i),
+ };
self.upcast::<GlobalScope>().set_timeout_or_interval(
- TimerCallback::StringTimerCallback(callback),
+ callback,
args,
timeout,
IsInterval::Interval,
@@ -462,6 +435,10 @@ impl WorkerGlobalScope {
PortMessageQueue(self.script_chan(), self.pipeline_id())
}
+ pub fn timer_task_source(&self) -> TimerTaskSource {
+ TimerTaskSource(self.script_chan(), self.pipeline_id())
+ }
+
pub fn remote_event_task_source(&self) -> RemoteEventTaskSource {
RemoteEventTaskSource(self.script_chan(), self.pipeline_id())
}
@@ -491,10 +468,6 @@ impl WorkerGlobalScope {
}
}
- pub fn handle_fire_timer(&self, timer_id: TimerEventId) {
- self.upcast::<GlobalScope>().fire_timer(timer_id);
- }
-
pub fn close(&self) {
if let Some(ref closing) = self.closing {
closing.store(true, Ordering::SeqCst);
diff --git a/components/script/dom/workernavigator.rs b/components/script/dom/workernavigator.rs
index 92dfa9951e5..cc1dfee13bd 100644
--- a/components/script/dom/workernavigator.rs
+++ b/components/script/dom/workernavigator.rs
@@ -7,6 +7,7 @@ use crate::dom::bindings::codegen::Bindings::WorkerNavigatorBinding::WorkerNavig
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
use crate::dom::bindings::root::{DomRoot, MutNullableDom};
use crate::dom::bindings::str::DOMString;
+use crate::dom::gpu::GPU;
use crate::dom::navigatorinfo;
use crate::dom::permissions::Permissions;
use crate::dom::workerglobalscope::WorkerGlobalScope;
@@ -17,6 +18,7 @@ use dom_struct::dom_struct;
pub struct WorkerNavigator {
reflector_: Reflector,
permissions: MutNullableDom<Permissions>,
+ gpu: MutNullableDom<GPU>,
}
impl WorkerNavigator {
@@ -24,6 +26,7 @@ impl WorkerNavigator {
WorkerNavigator {
reflector_: Reflector::new(),
permissions: Default::default(),
+ gpu: Default::default(),
}
}
@@ -97,4 +100,9 @@ impl WorkerNavigatorMethods for WorkerNavigator {
self.permissions
.or_init(|| Permissions::new(&self.global()))
}
+
+ // https://gpuweb.github.io/gpuweb/#dom-navigator-gpu
+ fn Gpu(&self) -> DomRoot<GPU> {
+ self.gpu.or_init(|| GPU::new(&self.global()))
+ }
}
diff --git a/components/script/dom/worklet.rs b/components/script/dom/worklet.rs
index 398710ee558..196864f5527 100644
--- a/components/script/dom/worklet.rs
+++ b/components/script/dom/worklet.rs
@@ -417,7 +417,7 @@ struct WorkletThreadInit {
}
/// A thread for executing worklets.
-#[must_root]
+#[unrooted_must_root_lint::must_root]
struct WorkletThread {
/// Which role the thread is currently playing
role: WorkletThreadRole,
@@ -477,7 +477,7 @@ impl WorkletThread {
global_init: init.global_init,
global_scopes: HashMap::new(),
control_buffer: None,
- runtime: new_rt_and_cx(),
+ runtime: new_rt_and_cx(None),
should_gc: false,
gc_threshold: MIN_GC_THRESHOLD,
});
diff --git a/components/script/dom/workletglobalscope.rs b/components/script/dom/workletglobalscope.rs
index 90fa5bd0115..995014cfc1a 100644
--- a/components/script/dom/workletglobalscope.rs
+++ b/components/script/dom/workletglobalscope.rs
@@ -15,7 +15,6 @@ use crate::script_thread::MainThreadScriptMsg;
use crossbeam_channel::Sender;
use devtools_traits::ScriptToDevtoolsControlMsg;
use dom_struct::dom_struct;
-use ipc_channel::ipc;
use ipc_channel::ipc::IpcSender;
use js::jsval::UndefinedValue;
use js::rust::Runtime;
@@ -55,8 +54,6 @@ impl WorkletGlobalScope {
executor: WorkletExecutor,
init: &WorkletGlobalScopeInit,
) -> Self {
- // Any timer events fired on this global are ignored.
- let (timer_event_chan, _) = ipc::channel().unwrap();
let script_to_constellation_chan = ScriptToConstellationChan {
sender: init.to_constellation_sender.clone(),
pipeline_id,
@@ -70,7 +67,6 @@ impl WorkletGlobalScope {
script_to_constellation_chan,
init.scheduler_chan.clone(),
init.resource_threads.clone(),
- timer_event_chan,
MutableOrigin::new(ImmutableOrigin::new_opaque()),
Default::default(),
init.is_headless,
diff --git a/components/script/dom/xrsession.rs b/components/script/dom/xrsession.rs
index 6fbdc592b0e..438705853f6 100644
--- a/components/script/dom/xrsession.rs
+++ b/components/script/dom/xrsession.rs
@@ -47,7 +47,8 @@ use std::cell::Cell;
use std::mem;
use std::rc::Rc;
use webxr_api::{
- self, EnvironmentBlendMode, Event as XREvent, Frame, SelectEvent, Session, Visibility,
+ self, EnvironmentBlendMode, Event as XREvent, Frame, SelectEvent, SelectKind, Session,
+ Visibility,
};
#[dom_struct]
@@ -218,16 +219,22 @@ impl XRSession {
let event = XRSessionEvent::new(&self.global(), atom!("end"), false, false, self);
event.upcast::<Event>().fire(self.upcast());
},
- XREvent::Select(input, kind, frame) => {
+ XREvent::Select(input, kind, ty, frame) => {
+ use servo_atoms::Atom;
+ const START_ATOMS: [Atom; 2] = [atom!("selectstart"), atom!("squeezestart")];
+ const EVENT_ATOMS: [Atom; 2] = [atom!("select"), atom!("squeeze")];
+ const END_ATOMS: [Atom; 2] = [atom!("selectend"), atom!("squeezeend")];
+
// https://immersive-web.github.io/webxr/#primary-action
let source = self.input_sources.find(input);
+ let atom_index = if kind == SelectKind::Squeeze { 1 } else { 0 };
if let Some(source) = source {
let frame = XRFrame::new(&self.global(), self, frame);
frame.set_active(true);
- if kind == SelectEvent::Start {
+ if ty == SelectEvent::Start {
let event = XRInputSourceEvent::new(
&self.global(),
- atom!("selectstart"),
+ START_ATOMS[atom_index].clone(),
false,
false,
&frame,
@@ -235,10 +242,10 @@ impl XRSession {
);
event.upcast::<Event>().fire(self.upcast());
} else {
- if kind == SelectEvent::Select {
+ if ty == SelectEvent::Select {
let event = XRInputSourceEvent::new(
&self.global(),
- atom!("select"),
+ EVENT_ATOMS[atom_index].clone(),
false,
false,
&frame,
@@ -248,7 +255,7 @@ impl XRSession {
}
let event = XRInputSourceEvent::new(
&self.global(),
- atom!("selectend"),
+ END_ATOMS[atom_index].clone(),
false,
false,
&frame,
@@ -353,6 +360,15 @@ impl XRSessionMethods for XRSession {
/// https://immersive-web.github.io/webxr/#eventdef-xrsession-selectend
event_handler!(selectend, GetOnselectend, SetOnselectend);
+ /// https://immersive-web.github.io/webxr/#eventdef-xrsession-squeeze
+ event_handler!(squeeze, GetOnsqueeze, SetOnsqueeze);
+
+ /// https://immersive-web.github.io/webxr/#eventdef-xrsession-squeezestart
+ event_handler!(squeezestart, GetOnsqueezestart, SetOnsqueezestart);
+
+ /// https://immersive-web.github.io/webxr/#eventdef-xrsession-squeezeend
+ event_handler!(squeezeend, GetOnsqueezeend, SetOnsqueezeend);
+
/// https://immersive-web.github.io/webxr/#eventdef-xrsession-visibilitychange
event_handler!(
visibilitychange,
diff --git a/components/script/euclidext.rs b/components/script/euclidext.rs
new file mode 100644
index 00000000000..39de2aa2ccb
--- /dev/null
+++ b/components/script/euclidext.rs
@@ -0,0 +1,43 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+use euclid::default::{Rect, Size2D};
+
+pub trait Size2DExt {
+ fn to_u64(&self) -> Size2D<u64>;
+}
+
+impl Size2DExt for Size2D<f32> {
+ fn to_u64(&self) -> Size2D<u64> {
+ self.cast()
+ }
+}
+
+impl Size2DExt for Size2D<f64> {
+ fn to_u64(&self) -> Size2D<u64> {
+ self.cast()
+ }
+}
+
+impl Size2DExt for Size2D<u32> {
+ fn to_u64(&self) -> Size2D<u64> {
+ self.cast()
+ }
+}
+
+pub trait RectExt {
+ fn to_u64(&self) -> Rect<u64>;
+}
+
+impl RectExt for Rect<f64> {
+ fn to_u64(&self) -> Rect<u64> {
+ self.cast()
+ }
+}
+
+impl RectExt for Rect<u32> {
+ fn to_u64(&self) -> Rect<u64> {
+ self.cast()
+ }
+}
diff --git a/components/script/init.rs b/components/script/init.rs
index 15428f4f3fe..30e01dda74e 100644
--- a/components/script/init.rs
+++ b/components/script/init.rs
@@ -4,6 +4,7 @@
use crate::dom::bindings::codegen::RegisterBindings;
use crate::dom::bindings::proxyhandler;
+use crate::script_runtime::JSEngineSetup;
use crate::serviceworker_manager::ServiceWorkerManager;
use script_traits::SWManagerSenders;
@@ -56,7 +57,7 @@ pub fn init_service_workers(sw_senders: SWManagerSenders) {
}
#[allow(unsafe_code)]
-pub fn init() {
+pub fn init() -> JSEngineSetup {
unsafe {
proxyhandler::init();
@@ -66,4 +67,6 @@ pub fn init() {
}
perform_platform_specific_initialization();
+
+ JSEngineSetup::new()
}
diff --git a/components/script/lib.rs b/components/script/lib.rs
index 48f42cd7a38..79c0657b996 100644
--- a/components/script/lib.rs
+++ b/components/script/lib.rs
@@ -6,14 +6,15 @@
#![feature(core_intrinsics)]
#![feature(drain_filter)]
#![feature(inner_deref)]
-#![feature(on_unimplemented)]
#![feature(plugin)]
+#![feature(register_tool)]
#![deny(unsafe_code)]
#![allow(non_snake_case)]
#![doc = "The script crate contains all matters DOM."]
#![cfg_attr(not(feature = "unrooted_must_root_lint"), allow(unknown_lints))]
#![allow(deprecated)] // FIXME: Can we make `allow` only apply to the `plugin` crate attribute?
#![plugin(script_plugins)]
+#![register_tool(unrooted_must_root_lint)]
#[macro_use]
extern crate bitflags;
@@ -66,6 +67,7 @@ mod dom;
mod canvas_state;
#[warn(deprecated)]
mod compartments;
+mod euclidext;
#[warn(deprecated)]
pub mod fetch;
#[warn(deprecated)]
@@ -111,6 +113,7 @@ mod unpremultiplytable;
mod webdriver_handlers;
pub use init::{init, init_service_workers};
+pub use script_runtime::JSEngineSetup;
/// A module with everything layout can use from script.
///
diff --git a/components/script/script_runtime.rs b/components/script/script_runtime.rs
index 10198050ace..fa02e7e564e 100644
--- a/components/script/script_runtime.rs
+++ b/components/script/script_runtime.rs
@@ -7,9 +7,14 @@
#![allow(dead_code)]
+use crate::body::BodyOperations;
use crate::dom::bindings::codegen::Bindings::PromiseBinding::PromiseJobCallback;
+use crate::dom::bindings::codegen::Bindings::ResponseBinding::ResponseBinding::ResponseMethods;
+use crate::dom::bindings::codegen::Bindings::ResponseBinding::ResponseType as DOMResponseType;
use crate::dom::bindings::conversions::get_dom_class;
use crate::dom::bindings::conversions::private_from_object;
+use crate::dom::bindings::conversions::root_from_handleobject;
+use crate::dom::bindings::error::{throw_dom_exception, Error};
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::refcounted::{trace_refcounted_objects, LiveDOMReferences};
use crate::dom::bindings::refcounted::{Trusted, TrustedPromise};
@@ -23,16 +28,24 @@ use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope;
use crate::dom::promise::Promise;
use crate::dom::promiserejectionevent::PromiseRejectionEvent;
+use crate::dom::response::Response;
use crate::microtask::{EnqueuedPromiseCallback, Microtask, MicrotaskQueue};
use crate::script_thread::trace_thread;
use crate::task::TaskBox;
+use crate::task_source::networking::NetworkingTaskSource;
use crate::task_source::{TaskSource, TaskSourceName};
-use js::glue::{CollectServoSizes, CreateJobQueue, DeleteJobQueue, JobQueueTraps, SetBuildId};
-use js::glue::{RUST_js_GetErrorMessage, StreamConsumerConsumeChunk, StreamConsumerStreamEnd};
-use js::glue::{StreamConsumerNoteResponseURLs, StreamConsumerStreamError};
+use js::glue::{CollectServoSizes, CreateJobQueue, DeleteJobQueue, DispatchableRun};
+use js::glue::{JobQueueTraps, RUST_js_GetErrorMessage, SetBuildId, StreamConsumerConsumeChunk};
+use js::glue::{
+ StreamConsumerNoteResponseURLs, StreamConsumerStreamEnd, StreamConsumerStreamError,
+};
use js::jsapi::ContextOptionsRef;
+use js::jsapi::InitConsumeStreamCallback;
+use js::jsapi::InitDispatchToEventLoop;
+use js::jsapi::MimeType;
use js::jsapi::StreamConsumer as JSStreamConsumer;
use js::jsapi::{BuildIdCharVector, DisableIncrementalGC, GCDescription, GCProgress};
+use js::jsapi::{Dispatchable as JSRunnable, Dispatchable_MaybeShuttingDown};
use js::jsapi::{HandleObject, Heap, JobQueue};
use js::jsapi::{JSContext as RawJSContext, JSTracer, SetDOMCallbacks, SetGCSliceCallback};
use js::jsapi::{JSGCInvocationKind, JSGCStatus, JS_AddExtraGCRootsTracer, JS_SetGCCallback};
@@ -46,10 +59,11 @@ use js::jsval::UndefinedValue;
use js::panic::wrap_panic;
use js::rust::wrappers::{GetPromiseIsHandled, JS_GetPromiseResult};
use js::rust::Handle;
+use js::rust::HandleObject as RustHandleObject;
use js::rust::IntoHandle;
-use js::rust::JSEngine;
use js::rust::ParentRuntime;
use js::rust::Runtime as RustRuntime;
+use js::rust::{JSEngine, JSEngineHandle};
use malloc_size_of::MallocSizeOfOps;
use msg::constellation_msg::PipelineId;
use profile_traits::mem::{Report, ReportKind, ReportsChan};
@@ -65,7 +79,9 @@ use std::os::raw::c_void;
use std::panic::AssertUnwindSafe;
use std::ptr;
use std::rc::Rc;
-use std::sync::Arc;
+use std::sync::Mutex;
+use std::thread;
+use std::time::Duration;
use style::thread_state::{self, ThreadState};
use time::{now, Tm};
@@ -381,27 +397,53 @@ impl Deref for Runtime {
}
}
+pub struct JSEngineSetup(JSEngine);
+
+impl JSEngineSetup {
+ pub fn new() -> Self {
+ let engine = JSEngine::init().unwrap();
+ *JS_ENGINE.lock().unwrap() = Some(engine.handle());
+ Self(engine)
+ }
+}
+
+impl Drop for JSEngineSetup {
+ fn drop(&mut self) {
+ *JS_ENGINE.lock().unwrap() = None;
+
+ while !self.0.can_shutdown() {
+ thread::sleep(Duration::from_millis(50));
+ }
+ }
+}
+
lazy_static! {
- static ref JS_ENGINE: Arc<JSEngine> = JSEngine::init().unwrap();
+ static ref JS_ENGINE: Mutex<Option<JSEngineHandle>> = Mutex::new(None);
}
#[allow(unsafe_code)]
-pub unsafe fn new_child_runtime(parent: ParentRuntime) -> Runtime {
- new_rt_and_cx_with_parent(Some(parent))
+pub unsafe fn new_child_runtime(
+ parent: ParentRuntime,
+ networking_task_source: Option<NetworkingTaskSource>,
+) -> Runtime {
+ new_rt_and_cx_with_parent(Some(parent), networking_task_source)
}
#[allow(unsafe_code)]
-pub fn new_rt_and_cx() -> Runtime {
- unsafe { new_rt_and_cx_with_parent(None) }
+pub fn new_rt_and_cx(networking_task_source: Option<NetworkingTaskSource>) -> Runtime {
+ unsafe { new_rt_and_cx_with_parent(None, networking_task_source) }
}
#[allow(unsafe_code)]
-unsafe fn new_rt_and_cx_with_parent(parent: Option<ParentRuntime>) -> Runtime {
+unsafe fn new_rt_and_cx_with_parent(
+ parent: Option<ParentRuntime>,
+ networking_task_source: Option<NetworkingTaskSource>,
+) -> Runtime {
LiveDOMReferences::initialize();
let runtime = if let Some(parent) = parent {
RustRuntime::create_with_parent(parent)
} else {
- RustRuntime::new(JS_ENGINE.clone())
+ RustRuntime::new(JS_ENGINE.lock().unwrap().as_ref().unwrap().clone())
};
let cx = runtime.cx();
@@ -424,6 +466,30 @@ unsafe fn new_rt_and_cx_with_parent(parent: Option<ParentRuntime>) -> Runtime {
// Pre barriers aren't working correctly at the moment
DisableIncrementalGC(cx);
+ unsafe extern "C" fn dispatch_to_event_loop(
+ closure: *mut c_void,
+ dispatchable: *mut JSRunnable,
+ ) -> bool {
+ let networking_task_src: &NetworkingTaskSource = &*(closure as *mut NetworkingTaskSource);
+ let runnable = Runnable(dispatchable);
+ let task = task!(dispatch_to_event_loop_message: move || {
+ runnable.run(RustRuntime::get(), Dispatchable_MaybeShuttingDown::NotShuttingDown);
+ });
+
+ networking_task_src.queue_unconditionally(task).is_ok()
+ }
+
+ if let Some(source) = networking_task_source {
+ let networking_task_src = Box::new(source);
+ InitDispatchToEventLoop(
+ cx,
+ Some(dispatch_to_event_loop),
+ Box::into_raw(networking_task_src) as *mut c_void,
+ );
+ }
+
+ InitConsumeStreamCallback(cx, Some(consume_stream), Some(report_stream_error));
+
let microtask_queue = Rc::new(MicrotaskQueue::default());
let job_queue = CreateJobQueue(
&JOB_QUEUE_TRAPS,
@@ -750,7 +816,7 @@ unsafe fn set_gc_zeal_options(cx: *mut RawJSContext) {
use js::jsapi::{JS_SetGCZeal, JS_DEFAULT_ZEAL_FREQ};
let level = match pref!(js.mem.gc.zeal.level) {
- level @ 0...14 => level as u8,
+ level @ 0..=14 => level as u8,
_ => return,
};
let frequency = match pref!(js.mem.gc.zeal.frequency) {
@@ -825,10 +891,112 @@ impl StreamConsumer {
}
}
+/// Implements the steps to compile webassembly response mentioned here
+/// <https://webassembly.github.io/spec/web-api/#compile-a-potential-webassembly-response>
+#[allow(unsafe_code)]
+unsafe extern "C" fn consume_stream(
+ _cx: *mut RawJSContext,
+ obj: HandleObject,
+ _mimeType: MimeType,
+ _consumer: *mut JSStreamConsumer,
+) -> bool {
+ let cx = JSContext::from_ptr(_cx);
+ let global = GlobalScope::from_context(*cx);
+
+ //Step 2.1 Upon fulfillment of source, store the Response with value unwrappedSource.
+ if let Ok(unwrapped_source) =
+ root_from_handleobject::<Response>(RustHandleObject::from_raw(obj), *cx)
+ {
+ //Step 2.2 Let mimeType be the result of extracting a MIME type from response’s header list.
+ let mimetype = unwrapped_source.Headers().extract_mime_type();
+
+ //Step 2.3 If mimeType is not `application/wasm`, return with a TypeError and abort these substeps.
+ match &mimetype[..] {
+ b"application/wasm" | b"APPLICATION/wasm" | b"APPLICATION/WASM" => {},
+ _ => {
+ throw_dom_exception(
+ cx,
+ &global,
+ Error::Type("Response has unsupported MIME type".to_string()),
+ );
+ return false;
+ },
+ }
+
+ //Step 2.4 If response is not CORS-same-origin, return with a TypeError and abort these substeps.
+ match unwrapped_source.Type() {
+ DOMResponseType::Basic | DOMResponseType::Cors | DOMResponseType::Default => {},
+ _ => {
+ throw_dom_exception(
+ cx,
+ &global,
+ Error::Type("Response.type must be 'basic', 'cors' or 'default'".to_string()),
+ );
+ return false;
+ },
+ }
+
+ //Step 2.5 If response’s status is not an ok status, return with a TypeError and abort these substeps.
+ if !unwrapped_source.Ok() {
+ throw_dom_exception(
+ cx,
+ &global,
+ Error::Type("Response does not have ok status".to_string()),
+ );
+ return false;
+ }
+
+ // Step 2.6.1 If response body is locked, return with a TypeError and abort these substeps.
+ if unwrapped_source.is_locked() {
+ throw_dom_exception(
+ cx,
+ &global,
+ Error::Type("There was an error consuming the Response".to_string()),
+ );
+ return false;
+ }
+
+ // Step 2.6.2 If response body is alreaady consumed, return with a TypeError and abort these substeps.
+ if unwrapped_source.get_body_used() {
+ throw_dom_exception(
+ cx,
+ &global,
+ Error::Type("Response already consumed".to_string()),
+ );
+ return false;
+ }
+ } else {
+ //Step 3 Upon rejection of source, return with reason.
+ throw_dom_exception(
+ cx,
+ &global,
+ Error::Type("expected Response or Promise resolving to Response".to_string()),
+ );
+ return false;
+ }
+ return true;
+}
+
#[allow(unsafe_code)]
-unsafe extern "C" fn report_stream_error_callback(_cx: *mut JSContext, error_code: usize) {
+unsafe extern "C" fn report_stream_error(_cx: *mut RawJSContext, error_code: usize) {
error!(
"Error initializing StreamConsumer: {:?}",
RUST_js_GetErrorMessage(ptr::null_mut(), error_code as u32)
);
}
+
+pub struct Runnable(*mut JSRunnable);
+
+#[allow(unsafe_code)]
+unsafe impl Sync for Runnable {}
+#[allow(unsafe_code)]
+unsafe impl Send for Runnable {}
+
+#[allow(unsafe_code)]
+impl Runnable {
+ fn run(&self, cx: *mut RawJSContext, maybe_shutting_down: Dispatchable_MaybeShuttingDown) {
+ unsafe {
+ DispatchableRun(cx, self.0, maybe_shutting_down);
+ }
+ }
+}
diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs
index 6a7a69651e7..c01ad08220c 100644
--- a/components/script/script_thread.rs
+++ b/components/script/script_thread.rs
@@ -82,6 +82,7 @@ use crate::task_source::networking::NetworkingTaskSource;
use crate::task_source::performance_timeline::PerformanceTimelineTaskSource;
use crate::task_source::port_message::PortMessageQueue;
use crate::task_source::remote_event::RemoteEventTaskSource;
+use crate::task_source::timer::TimerTaskSource;
use crate::task_source::user_interaction::UserInteractionTaskSource;
use crate::task_source::websocket::WebsocketTaskSource;
use crate::task_source::TaskSource;
@@ -138,11 +139,11 @@ use script_traits::{
DiscardBrowsingContext, DocumentActivity, EventResult, HistoryEntryReplacement,
};
use script_traits::{InitialScriptState, JsEvalResult, LayoutMsg, LoadData, LoadOrigin};
-use script_traits::{MouseButton, MouseEventType, NewLayoutInfo};
+use script_traits::{MediaSessionActionType, MouseButton, MouseEventType, NewLayoutInfo};
use script_traits::{Painter, ProgressiveWebMetricType, ScriptMsg, ScriptThreadFactory};
-use script_traits::{ScriptToConstellationChan, TimerEvent, TimerSchedulerMsg};
-use script_traits::{TimerSource, TouchEventType, TouchId, UntrustedNodeAddress, WheelDelta};
-use script_traits::{UpdatePipelineIdReason, WindowSizeData, WindowSizeType};
+use script_traits::{ScriptToConstellationChan, TimerSchedulerMsg};
+use script_traits::{TouchEventType, TouchId, UntrustedNodeAddress, WheelDelta};
+use script_traits::{UpdatePipelineIdReason, WebrenderIpcSender, WindowSizeData, WindowSizeType};
use servo_atoms::Atom;
use servo_url::{ImmutableOrigin, MutableOrigin, ServoUrl};
use std::borrow::Cow;
@@ -163,8 +164,9 @@ use style::dom::OpaqueNode;
use style::thread_state::{self, ThreadState};
use time::{at_utc, get_time, precise_time_ns, Timespec};
use url::Position;
+use webgpu::WebGPU;
use webrender_api::units::LayoutPixel;
-use webrender_api::{DocumentId, RenderApiSender};
+use webrender_api::DocumentId;
use webvr_traits::{WebVREvent, WebVRMsg};
pub type ImageCacheMsg = (PipelineId, PendingImageResponse);
@@ -263,7 +265,6 @@ enum MixedMessage {
FromScript(MainThreadScriptMsg),
FromDevtools(DevtoolScriptControlMsg),
FromImageCache((PipelineId, PendingImageResponse)),
- FromScheduler(TimerEvent),
}
/// Messages used to control the script event loop.
@@ -434,7 +435,7 @@ impl OpaqueSender<CommonScriptMsg> for Sender<MainThreadScriptMsg> {
/// The set of all documents managed by this script thread.
#[derive(JSTraceable)]
-#[must_root]
+#[unrooted_must_root_lint::must_root]
pub struct Documents {
map: HashMap<PipelineId, Dom<Document>>,
}
@@ -569,6 +570,8 @@ pub struct ScriptThread {
port_message_sender: Box<dyn ScriptChan>,
+ timer_task_sender: Box<dyn ScriptChan>,
+
remote_event_task_sender: Box<dyn ScriptChan>,
/// A channel to hand out to threads that need to respond to a message from the script thread.
@@ -612,8 +615,6 @@ pub struct ScriptThread {
closed_pipelines: DomRefCell<HashSet<PipelineId>>,
scheduler_chan: IpcSender<TimerSchedulerMsg>,
- timer_event_chan: Sender<TimerEvent>,
- timer_event_port: Receiver<TimerEvent>,
content_process_shutdown_chan: Sender<()>,
@@ -629,6 +630,9 @@ pub struct ScriptThread {
/// A handle to the WebGL thread
webgl_chan: Option<WebGLPipeline>,
+ /// A handle to the WebGPU threads
+ webgpu: Option<WebGPU>,
+
/// A handle to the webvr thread, if available
webvr_chan: Option<IpcSender<WebVRMsg>>,
@@ -653,7 +657,7 @@ pub struct ScriptThread {
webrender_document: DocumentId,
/// Webrender API sender.
- webrender_api_sender: RenderApiSender,
+ webrender_api_sender: WebrenderIpcSender,
/// Periodically print out on which events script threads spend their processing time.
profile_script_events: bool,
@@ -1244,7 +1248,12 @@ impl ScriptThread {
replace_surrogates: bool,
user_agent: Cow<'static, str>,
) -> ScriptThread {
- let runtime = new_rt_and_cx();
+ let boxed_script_sender = Box::new(MainThreadScriptChan(chan.clone()));
+
+ let runtime = new_rt_and_cx(Some(NetworkingTaskSource(
+ boxed_script_sender.clone(),
+ state.id,
+ )));
let cx = runtime.cx();
unsafe {
@@ -1257,13 +1266,9 @@ impl ScriptThread {
let devtools_port =
ROUTER.route_ipc_receiver_to_new_crossbeam_receiver(ipc_devtools_receiver);
- let (timer_event_chan, timer_event_port) = unbounded();
-
// Ask the router to proxy IPC messages from the control port to us.
let control_port = ROUTER.route_ipc_receiver_to_new_crossbeam_receiver(state.control_port);
- let boxed_script_sender = Box::new(MainThreadScriptChan(chan.clone()));
-
let (image_cache_channel, image_cache_port) = unbounded();
let task_queue = TaskQueue::new(port, chan.clone());
@@ -1302,6 +1307,7 @@ impl ScriptThread {
port_message_sender: boxed_script_sender.clone(),
file_reading_task_sender: boxed_script_sender.clone(),
performance_timeline_task_sender: boxed_script_sender.clone(),
+ timer_task_sender: boxed_script_sender.clone(),
remote_event_task_sender: boxed_script_sender.clone(),
history_traversal_task_sender: chan.clone(),
@@ -1323,8 +1329,6 @@ impl ScriptThread {
closed_pipelines: DomRefCell::new(HashSet::new()),
scheduler_chan: state.scheduler_chan,
- timer_event_chan: timer_event_chan,
- timer_event_port: timer_event_port,
content_process_shutdown_chan: state.content_process_shutdown_chan,
@@ -1335,6 +1339,7 @@ impl ScriptThread {
layout_to_constellation_chan: state.layout_to_constellation_chan,
webgl_chan: state.webgl_chan,
+ webgpu: state.webgpu,
webvr_chan: state.webvr_chan,
webxr_registry: state.webxr_registry,
@@ -1386,8 +1391,8 @@ impl ScriptThread {
/// Handle incoming control messages.
fn handle_msgs(&self) -> bool {
+ use self::MixedMessage::FromScript;
use self::MixedMessage::{FromConstellation, FromDevtools, FromImageCache};
- use self::MixedMessage::{FromScheduler, FromScript};
// Handle pending resize events.
// Gather them first to avoid a double mut borrow on self.
@@ -1422,7 +1427,6 @@ impl ScriptThread {
FromScript(event)
},
recv(self.control_port) -> msg => FromConstellation(msg.unwrap()),
- recv(self.timer_event_port) -> msg => FromScheduler(msg.unwrap()),
recv(self.devtools_chan.as_ref().map(|_| &self.devtools_port).unwrap_or(&crossbeam_channel::never())) -> msg
=> FromDevtools(msg.unwrap()),
recv(self.image_cache_port) -> msg => FromImageCache(msg.unwrap()),
@@ -1520,15 +1524,12 @@ impl ScriptThread {
// on and execute the sequential non-resize events we've seen.
match self.control_port.try_recv() {
Err(_) => match self.task_queue.try_recv() {
- Err(_) => match self.timer_event_port.try_recv() {
- Err(_) => match self.devtools_port.try_recv() {
- Err(_) => match self.image_cache_port.try_recv() {
- Err(_) => break,
- Ok(ev) => event = FromImageCache(ev),
- },
- Ok(ev) => event = FromDevtools(ev),
+ Err(_) => match self.devtools_port.try_recv() {
+ Err(_) => match self.image_cache_port.try_recv() {
+ Err(_) => break,
+ Ok(ev) => event = FromImageCache(ev),
},
- Ok(ev) => event = FromScheduler(ev),
+ Ok(ev) => event = FromDevtools(ev),
},
Ok(ev) => event = FromScript(ev),
},
@@ -1552,7 +1553,6 @@ impl ScriptThread {
},
FromConstellation(inner_msg) => self.handle_msg_from_constellation(inner_msg),
FromScript(inner_msg) => self.handle_msg_from_script(inner_msg),
- FromScheduler(inner_msg) => self.handle_timer_event(inner_msg),
FromDevtools(inner_msg) => self.handle_msg_from_devtools(inner_msg),
FromImageCache(inner_msg) => self.handle_msg_from_image_cache(inner_msg),
}
@@ -1625,7 +1625,6 @@ impl ScriptThread {
},
_ => ScriptThreadEventCategory::ScriptEvent,
},
- MixedMessage::FromScheduler(_) => ScriptThreadEventCategory::TimerEvent,
}
}
@@ -1713,6 +1712,7 @@ impl ScriptThread {
WebVREvents(id, ..) => Some(id),
PaintMetric(..) => None,
ExitFullScreen(id, ..) => Some(id),
+ MediaSessionAction(..) => None,
}
},
MixedMessage::FromDevtools(_) => None,
@@ -1728,13 +1728,6 @@ impl ScriptThread {
MainThreadScriptMsg::WakeUp => None,
},
MixedMessage::FromImageCache((pipeline_id, _)) => Some(pipeline_id),
- MixedMessage::FromScheduler(ref timer_event) => {
- let TimerEvent(source, _) = *timer_event;
- match source {
- TimerSource::FromWindow(pipeline_id) => Some(pipeline_id),
- _ => None,
- }
- },
}
}
@@ -1942,6 +1935,9 @@ impl ScriptThread {
ConstellationControlMsg::PaintMetric(pipeline_id, metric_type, metric_value) => {
self.handle_paint_metric(pipeline_id, metric_type, metric_value)
},
+ ConstellationControlMsg::MediaSessionAction(pipeline_id, action) => {
+ self.handle_media_session_action(pipeline_id, action)
+ },
msg @ ConstellationControlMsg::AttachLayout(..) |
msg @ ConstellationControlMsg::Viewport(..) |
msg @ ConstellationControlMsg::SetScrollState(..) |
@@ -1976,36 +1972,6 @@ impl ScriptThread {
}
}
- fn handle_timer_event(&self, timer_event: TimerEvent) {
- let TimerEvent(source, id) = timer_event;
-
- let pipeline_id = match source {
- TimerSource::FromWindow(pipeline_id) => pipeline_id,
- TimerSource::FromWorker => panic!("Worker timeouts must not be sent to script thread"),
- };
-
- let window = self.documents.borrow().find_window(pipeline_id);
- let window = match window {
- Some(w) => {
- if w.Closed() {
- return warn!(
- "Received fire timer msg for a discarded browsing context whose pipeline is pending exit {}.",
- pipeline_id
- );
- }
- w
- },
- None => {
- return warn!(
- "Received fire timer msg for a closed pipeline {}.",
- pipeline_id
- );
- },
- };
-
- window.handle_fire_timer(id);
- }
-
fn handle_msg_from_devtools(&self, msg: DevtoolScriptControlMsg) {
let documents = self.documents.borrow();
match msg {
@@ -2392,6 +2358,7 @@ impl ScriptThread {
load_data.url.clone(),
),
layout_is_busy: layout_is_busy.clone(),
+ window_size,
});
// Pick a layout thread, any layout thread
@@ -2429,6 +2396,8 @@ impl ScriptThread {
);
if load_data.url.as_str() == "about:blank" {
self.start_page_load_about_blank(new_load, load_data.js_eval_result);
+ } else if load_data.url.as_str() == "about:srcdoc" {
+ self.page_load_about_srcdoc(new_load, load_data.srcdoc);
} else {
self.pre_page_load(new_load, load_data);
}
@@ -2535,7 +2504,8 @@ impl ScriptThread {
source_origin: ImmutableOrigin,
data: StructuredSerializedData,
) {
- match { self.documents.borrow().find_window(pipeline_id) } {
+ let window = self.documents.borrow().find_window(pipeline_id);
+ match window {
None => return warn!("postMessage after target pipeline {} closed.", pipeline_id),
Some(window) => {
// FIXME: synchronously talks to constellation.
@@ -2618,7 +2588,8 @@ impl ScriptThread {
history_state_id: Option<HistoryStateId>,
url: ServoUrl,
) {
- match { self.documents.borrow().find_window(pipeline_id) } {
+ let window = self.documents.borrow().find_window(pipeline_id);
+ match window {
None => {
return warn!(
"update history state after pipeline {} closed.",
@@ -2634,7 +2605,8 @@ impl ScriptThread {
pipeline_id: PipelineId,
history_states: Vec<HistoryStateId>,
) {
- match { self.documents.borrow().find_window(pipeline_id) } {
+ let window = self.documents.borrow().find_window(pipeline_id);
+ match window {
None => {
return warn!(
"update history state after pipeline {} closed.",
@@ -2806,6 +2778,10 @@ impl ScriptThread {
RemoteEventTaskSource(self.remote_event_task_sender.clone(), pipeline_id)
}
+ pub fn timer_task_source(&self, pipeline_id: PipelineId) -> TimerTaskSource {
+ TimerTaskSource(self.timer_task_sender.clone(), pipeline_id)
+ }
+
pub fn websocket_task_source(&self, pipeline_id: PipelineId) -> WebsocketTaskSource {
WebsocketTaskSource(self.remote_event_task_sender.clone(), pipeline_id)
}
@@ -2834,6 +2810,14 @@ impl ScriptThread {
let document = self.documents.borrow_mut().remove(id);
+ // Abort the parser, if any,
+ // to prevent any further incoming networking messages from being handled.
+ if let Some(document) = document.as_ref() {
+ if let Some(parser) = document.get_current_parser() {
+ parser.abort();
+ }
+ }
+
// We should never have a pipeline that's still an incomplete load,
// but also has a Document.
debug_assert!(idx.is_none() || document.is_none());
@@ -3112,7 +3096,8 @@ impl ScriptThread {
opener: Option<BrowsingContextId>,
) -> DomRoot<WindowProxy> {
if let Some(window_proxy) = self.window_proxies.borrow().get(&browsing_context_id) {
- window_proxy.set_currently_active(&*window);
+ // Note: we do not set the window to be the currently-active one,
+ // this will be done instead when the script-thread handles the `SetDocumentActivity` msg.
return DomRoot::from_ref(window_proxy);
}
let iframe = parent_info.and_then(|parent_id| {
@@ -3170,13 +3155,8 @@ impl ScriptThread {
let MainThreadScriptChan(ref sender) = self.chan;
- let (ipc_timer_event_chan, ipc_timer_event_port) = ipc::channel().unwrap();
- ROUTER.route_ipc_receiver_to_crossbeam_sender(
- ipc_timer_event_port,
- self.timer_event_chan.clone(),
- );
-
- let origin = if final_url.as_str() == "about:blank" {
+ let origin = if final_url.as_str() == "about:blank" || final_url.as_str() == "about:srcdoc"
+ {
incomplete.origin.clone()
} else {
MutableOrigin::new(final_url.origin())
@@ -3198,6 +3178,7 @@ impl ScriptThread {
self.port_message_queue(incomplete.pipeline_id),
self.user_interaction_task_source(incomplete.pipeline_id),
self.remote_event_task_source(incomplete.pipeline_id),
+ self.timer_task_source(incomplete.pipeline_id),
self.websocket_task_source(incomplete.pipeline_id),
);
// Create the window and document objects.
@@ -3215,7 +3196,6 @@ impl ScriptThread {
script_to_constellation_chan,
self.control_chan.clone(),
self.scheduler_chan.clone(),
- ipc_timer_event_chan,
incomplete.layout_chan,
incomplete.pipeline_id,
incomplete.parent_info,
@@ -3224,6 +3204,7 @@ impl ScriptThread {
incomplete.navigation_start,
incomplete.navigation_start_precise,
self.webgl_chan.as_ref().map(|chan| chan.channel()),
+ self.webgpu.clone(),
self.webvr_chan.clone(),
self.webxr_registry.clone(),
self.microtask_queue.clone(),
@@ -3696,6 +3677,15 @@ impl ScriptThread {
};
let window = document.window();
+ if window.window_size() == new_size {
+ return;
+ }
+ debug!(
+ "resizing pipeline {:?} from {:?} to {:?}",
+ pipeline_id,
+ window.window_size(),
+ new_size
+ );
window.set_window_size(new_size);
window.force_reflow(ReflowGoal::Full, ReflowReason::WindowResize);
@@ -3828,6 +3818,25 @@ impl ScriptThread {
context.process_response_eof(Ok(ResourceFetchTiming::new(ResourceTimingType::None)));
}
+ /// Synchronously parse a srcdoc document from a giving HTML string.
+ fn page_load_about_srcdoc(&self, incomplete: InProgressLoad, src_doc: String) {
+ let id = incomplete.pipeline_id;
+
+ self.incomplete_loads.borrow_mut().push(incomplete);
+
+ let url = ServoUrl::parse("about:srcdoc").unwrap();
+ let mut context = ParserContext::new(id, url.clone());
+
+ let mut meta = Metadata::default(url);
+ meta.set_content_type(Some(&mime::TEXT_HTML));
+
+ let chunk = src_doc.into_bytes();
+
+ context.process_response(Ok(FetchMetadata::Unfiltered(meta)));
+ context.process_response_chunk(chunk);
+ context.process_response_eof(Ok(ResourceFetchTiming::new(ResourceTimingType::None)));
+ }
+
fn handle_css_error_reporting(
&self,
pipeline_id: PipelineId,
@@ -3890,6 +3899,15 @@ impl ScriptThread {
}
}
+ fn handle_media_session_action(&self, pipeline_id: PipelineId, action: MediaSessionActionType) {
+ if let Some(window) = self.documents.borrow().find_window(pipeline_id) {
+ let media_session = window.Navigator().MediaSession();
+ media_session.handle_action(action);
+ } else {
+ warn!("No MediaSession for this pipeline ID");
+ };
+ }
+
pub fn enqueue_microtask(job: Microtask) {
SCRIPT_THREAD_ROOT.with(|root| {
let script_thread = unsafe { &*root.get().unwrap() };
diff --git a/components/script/serviceworkerjob.rs b/components/script/serviceworkerjob.rs
index 8ba955928a3..93340cabe27 100644
--- a/components/script/serviceworkerjob.rs
+++ b/components/script/serviceworkerjob.rs
@@ -38,7 +38,7 @@ pub enum SettleType {
Reject(Error),
}
-#[must_root]
+#[unrooted_must_root_lint::must_root]
#[derive(JSTraceable)]
pub struct Job {
pub job_type: JobType,
@@ -97,7 +97,7 @@ impl PartialEq for Job {
}
}
-#[must_root]
+#[unrooted_must_root_lint::must_root]
#[derive(JSTraceable)]
pub struct JobQueue(pub DomRefCell<HashMap<ServoUrl, Vec<Job>>>);
diff --git a/components/script/task_manager.rs b/components/script/task_manager.rs
index a8908ea00a2..063b5700484 100644
--- a/components/script/task_manager.rs
+++ b/components/script/task_manager.rs
@@ -12,6 +12,7 @@ use crate::task_source::networking::NetworkingTaskSource;
use crate::task_source::performance_timeline::PerformanceTimelineTaskSource;
use crate::task_source::port_message::PortMessageQueue;
use crate::task_source::remote_event::RemoteEventTaskSource;
+use crate::task_source::timer::TimerTaskSource;
use crate::task_source::user_interaction::UserInteractionTaskSource;
use crate::task_source::websocket::WebsocketTaskSource;
use crate::task_source::TaskSourceName;
@@ -54,6 +55,8 @@ pub struct TaskManager {
#[ignore_malloc_size_of = "task sources are hard"]
remote_event_task_source: RemoteEventTaskSource,
#[ignore_malloc_size_of = "task sources are hard"]
+ timer_task_source: TimerTaskSource,
+ #[ignore_malloc_size_of = "task sources are hard"]
websocket_task_source: WebsocketTaskSource,
}
@@ -68,6 +71,7 @@ impl TaskManager {
port_message_queue: PortMessageQueue,
user_interaction_task_source: UserInteractionTaskSource,
remote_event_task_source: RemoteEventTaskSource,
+ timer_task_source: TimerTaskSource,
websocket_task_source: WebsocketTaskSource,
) -> Self {
TaskManager {
@@ -80,6 +84,7 @@ impl TaskManager {
port_message_queue,
user_interaction_task_source,
remote_event_task_source,
+ timer_task_source,
websocket_task_source,
task_cancellers: Default::default(),
}
@@ -159,6 +164,14 @@ impl TaskManager {
task_source_functions!(
self,
+ timer_task_source_with_canceller,
+ timer_task_source,
+ TimerTaskSource,
+ Timer
+ );
+
+ task_source_functions!(
+ self,
websocket_task_source_with_canceller,
websocket_task_source,
WebsocketTaskSource,
diff --git a/components/script/task_source/mod.rs b/components/script/task_source/mod.rs
index d315b34fcae..7defd922779 100644
--- a/components/script/task_source/mod.rs
+++ b/components/script/task_source/mod.rs
@@ -10,6 +10,7 @@ pub mod networking;
pub mod performance_timeline;
pub mod port_message;
pub mod remote_event;
+pub mod timer;
pub mod user_interaction;
pub mod websocket;
@@ -34,6 +35,7 @@ pub enum TaskSourceName {
RemoteEvent,
MediaElement,
Websocket,
+ Timer,
}
impl TaskSourceName {
diff --git a/components/script/task_source/timer.rs b/components/script/task_source/timer.rs
new file mode 100644
index 00000000000..cd134fb12a2
--- /dev/null
+++ b/components/script/task_source/timer.rs
@@ -0,0 +1,42 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use crate::script_runtime::{CommonScriptMsg, ScriptChan, ScriptThreadEventCategory};
+use crate::task::{TaskCanceller, TaskOnce};
+use crate::task_source::{TaskSource, TaskSourceName};
+use msg::constellation_msg::PipelineId;
+use std::fmt;
+
+#[derive(JSTraceable)]
+/// https://html.spec.whatwg.org/multipage/#timer-task-source
+pub struct TimerTaskSource(pub Box<dyn ScriptChan + Send + 'static>, pub PipelineId);
+
+impl Clone for TimerTaskSource {
+ fn clone(&self) -> TimerTaskSource {
+ TimerTaskSource(self.0.clone(), self.1.clone())
+ }
+}
+
+impl fmt::Debug for TimerTaskSource {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "TimerTaskSource(...)")
+ }
+}
+
+impl TaskSource for TimerTaskSource {
+ const NAME: TaskSourceName = TaskSourceName::Timer;
+
+ fn queue_with_canceller<T>(&self, task: T, canceller: &TaskCanceller) -> Result<(), ()>
+ where
+ T: TaskOnce + 'static,
+ {
+ let msg = CommonScriptMsg::Task(
+ ScriptThreadEventCategory::TimerEvent,
+ Box::new(canceller.wrap_task(task)),
+ Some(self.1),
+ Self::NAME,
+ );
+ self.0.send(msg).map_err(|_| ())
+ }
+}
diff --git a/components/script/timers.rs b/components/script/timers.rs
index f65d1013f48..4be6f822263 100644
--- a/components/script/timers.rs
+++ b/components/script/timers.rs
@@ -34,8 +34,12 @@ pub struct OneshotTimerHandle(i32);
pub struct OneshotTimers {
js_timers: JsTimers,
#[ignore_malloc_size_of = "Defined in std"]
- timer_event_chan: IpcSender<TimerEvent>,
+ /// The sender, to be cloned for each timer,
+ /// on which the timer scheduler in the constellation can send an event
+ /// when the timer is due.
+ timer_event_chan: DomRefCell<Option<IpcSender<TimerEvent>>>,
#[ignore_malloc_size_of = "Defined in std"]
+ /// The sender to the timer scheduler in the constellation.
scheduler_chan: IpcSender<TimerSchedulerMsg>,
next_timer_handle: Cell<OneshotTimerHandle>,
timers: DomRefCell<Vec<OneshotTimer>>,
@@ -109,13 +113,10 @@ impl PartialEq for OneshotTimer {
}
impl OneshotTimers {
- pub fn new(
- timer_event_chan: IpcSender<TimerEvent>,
- scheduler_chan: IpcSender<TimerSchedulerMsg>,
- ) -> OneshotTimers {
+ pub fn new(scheduler_chan: IpcSender<TimerSchedulerMsg>) -> OneshotTimers {
OneshotTimers {
js_timers: JsTimers::new(),
- timer_event_chan: timer_event_chan,
+ timer_event_chan: DomRefCell::new(None),
scheduler_chan: scheduler_chan,
next_timer_handle: Cell::new(OneshotTimerHandle(1)),
timers: DomRefCell::new(Vec::new()),
@@ -125,6 +126,12 @@ impl OneshotTimers {
}
}
+ pub fn setup_scheduling(&self, timer_event_chan: IpcSender<TimerEvent>) {
+ let mut chan = self.timer_event_chan.borrow_mut();
+ assert!(chan.is_none());
+ *chan = Some(timer_event_chan);
+ }
+
pub fn schedule_callback(
&self,
callback: OneshotTimerCallback,
@@ -279,7 +286,10 @@ impl OneshotTimers {
.saturating_sub(precise_time_ms().get()),
);
let request = TimerEventRequest(
- self.timer_event_chan.clone(),
+ self.timer_event_chan
+ .borrow()
+ .clone()
+ .expect("Timer event chan not setup to schedule timers."),
timer.source,
expected_event_id,
delay,
@@ -331,6 +341,7 @@ pub struct JsTimerHandle(i32);
#[derive(DenyPublicFields, JSTraceable, MallocSizeOf)]
pub struct JsTimers {
next_timer_handle: Cell<JsTimerHandle>,
+ /// https://html.spec.whatwg.org/multipage/#list-of-active-timers
active_timers: DomRefCell<HashMap<JsTimerHandle, JsTimerEntry>>,
/// The nesting level of the currently executing timer task or 0.
nesting_level: Cell<u32>,