aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom
diff options
context:
space:
mode:
Diffstat (limited to 'components/script/dom')
-rw-r--r--components/script/dom/bindings/codegen/Bindings.conf4
-rw-r--r--components/script/dom/bindings/codegen/CodegenRust.py14
-rw-r--r--components/script/dom/bindings/codegen/Configuration.py6
-rw-r--r--components/script/dom/bindings/error.rs3
-rw-r--r--components/script/dom/bindings/str.rs10
-rw-r--r--components/script/dom/bindings/trace.rs32
-rw-r--r--components/script/dom/closeevent.rs8
-rw-r--r--components/script/dom/compositionevent.rs15
-rw-r--r--components/script/dom/dedicatedworkerglobalscope.rs27
-rw-r--r--components/script/dom/document.rs28
-rw-r--r--components/script/dom/domexception.rs10
-rw-r--r--components/script/dom/domtokenlist.rs6
-rw-r--r--components/script/dom/eventtarget.rs13
-rw-r--r--components/script/dom/fakexrdevice.rs111
-rw-r--r--components/script/dom/filereader.rs69
-rw-r--r--components/script/dom/formdata.rs2
-rw-r--r--components/script/dom/globalscope.rs56
-rw-r--r--components/script/dom/gpu.rs16
-rw-r--r--components/script/dom/gpuadapter.rs67
-rw-r--r--components/script/dom/gpubuffer.rs120
-rw-r--r--components/script/dom/gpubufferusage.rs11
-rw-r--r--components/script/dom/gpudevice.rs249
-rw-r--r--components/script/dom/headers.rs44
-rw-r--r--[-rwxr-xr-x]components/script/dom/htmlformelement.rs242
-rwxr-xr-xcomponents/script/dom/htmlinputelement.rs48
-rw-r--r--components/script/dom/htmlmediaelement.rs23
-rw-r--r--components/script/dom/htmlscriptelement.rs7
-rw-r--r--components/script/dom/identityhub.rs113
-rw-r--r--components/script/dom/macros.rs1
-rw-r--r--components/script/dom/mediasession.rs59
-rw-r--r--components/script/dom/messageevent.rs47
-rw-r--r--components/script/dom/mod.rs3
-rw-r--r--components/script/dom/navigator.rs18
-rw-r--r--components/script/dom/node.rs5
-rw-r--r--components/script/dom/offscreencanvas.rs51
-rw-r--r--components/script/dom/offscreencanvasrenderingcontext2d.rs18
-rw-r--r--components/script/dom/performance.rs45
-rw-r--r--components/script/dom/progressevent.rs7
-rw-r--r--components/script/dom/request.rs145
-rw-r--r--components/script/dom/response.rs17
-rw-r--r--components/script/dom/serviceworkerglobalscope.rs5
-rw-r--r--components/script/dom/serviceworkerregistration.rs6
-rw-r--r--components/script/dom/servoparser/mod.rs21
-rw-r--r--components/script/dom/webglcontextevent.rs12
-rw-r--r--components/script/dom/webidls/CanvasRenderingContext2D.webidl2
-rw-r--r--components/script/dom/webidls/DOMException.webidl2
-rw-r--r--components/script/dom/webidls/DOMTokenList.webidl2
-rw-r--r--components/script/dom/webidls/EventHandler.webidl1
-rw-r--r--components/script/dom/webidls/FakeXRDevice.webidl14
-rw-r--r--components/script/dom/webidls/GPUAdapter.webidl22
-rw-r--r--components/script/dom/webidls/GPUBuffer.webidl25
-rw-r--r--components/script/dom/webidls/GPUBufferUsage.webidl17
-rw-r--r--components/script/dom/webidls/GPUDevice.webidl31
-rw-r--r--components/script/dom/webidls/GPUObjectBase.webidl13
-rw-r--r--components/script/dom/webidls/HTMLFormElement.webidl2
-rw-r--r--components/script/dom/webidls/MediaSession.webidl9
-rw-r--r--components/script/dom/webidls/MessageEvent.webidl11
-rw-r--r--components/script/dom/webidls/Node.webidl3
-rw-r--r--components/script/dom/webidls/Performance.webidl15
-rw-r--r--components/script/dom/webidls/XRRenderState.webidl2
-rw-r--r--components/script/dom/webidls/XRWebGLLayer.webidl2
-rw-r--r--components/script/dom/worker.rs7
-rw-r--r--components/script/dom/workerglobalscope.rs3
-rw-r--r--components/script/dom/xr.rs45
-rw-r--r--components/script/dom/xrframe.rs6
-rw-r--r--components/script/dom/xrreferencespace.rs55
-rw-r--r--components/script/dom/xrrenderstate.rs21
-rw-r--r--components/script/dom/xrsession.rs137
-rw-r--r--components/script/dom/xrspace.rs2
-rw-r--r--components/script/dom/xrtest.rs19
-rw-r--r--components/script/dom/xrviewerpose.rs7
-rw-r--r--components/script/dom/xrwebgllayer.rs77
72 files changed, 1842 insertions, 524 deletions
diff --git a/components/script/dom/bindings/codegen/Bindings.conf b/components/script/dom/bindings/codegen/Bindings.conf
index d1d55d462bf..3a5f8576cef 100644
--- a/components/script/dom/bindings/codegen/Bindings.conf
+++ b/components/script/dom/bindings/codegen/Bindings.conf
@@ -146,6 +146,10 @@ DOMInterfaces = {
'GPU': {
'inCompartments': ['RequestAdapter'],
+},
+
+'GPUAdapter': {
+ 'inCompartments': ['RequestDevice'],
}
}
diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py
index 39e8bfa275d..ec29a59c9d4 100644
--- a/components/script/dom/bindings/codegen/CodegenRust.py
+++ b/components/script/dom/bindings/codegen/CodegenRust.py
@@ -3943,8 +3943,8 @@ class CGMemberJITInfo(CGThing):
depth=self.descriptor.interface.inheritanceDepth(),
opType=opType,
aliasSet=aliasSet,
- returnType=reduce(CGMemberJITInfo.getSingleReturnType, returnTypes,
- ""),
+ returnType=functools.reduce(CGMemberJITInfo.getSingleReturnType, returnTypes,
+ ""),
isInfallible=toStringBool(infallible),
isMovable=toStringBool(movable),
# FIXME(nox): https://github.com/servo/servo/issues/10991
@@ -4131,8 +4131,8 @@ class CGMemberJITInfo(CGThing):
if u.hasNullableType:
# Might be null or not
return "JSVAL_TYPE_UNKNOWN"
- return reduce(CGMemberJITInfo.getSingleReturnType,
- u.flatMemberTypes, "")
+ return functools.reduce(CGMemberJITInfo.getSingleReturnType,
+ u.flatMemberTypes, "")
if t.isDictionary():
return "JSVAL_TYPE_OBJECT"
if t.isDate():
@@ -4202,8 +4202,8 @@ class CGMemberJITInfo(CGThing):
if t.isUnion():
u = t.unroll()
type = "JSJitInfo::Null as i32" if u.hasNullableType else ""
- return reduce(CGMemberJITInfo.getSingleArgType,
- u.flatMemberTypes, type)
+ return functools.reduce(CGMemberJITInfo.getSingleArgType,
+ u.flatMemberTypes, type)
if t.isDictionary():
return "JSJitInfo_ArgType::Object as i32"
if t.isDate():
@@ -5858,7 +5858,7 @@ class CGInterfaceTrait(CGThing):
def contains_unsafe_arg(arguments):
if not arguments or len(arguments) == 0:
return False
- return reduce((lambda x, y: x or y[1] == '*mut JSContext'), arguments, False)
+ return functools.reduce((lambda x, y: x or y[1] == '*mut JSContext'), arguments, False)
methods = []
for name, arguments, rettype in members():
diff --git a/components/script/dom/bindings/codegen/Configuration.py b/components/script/dom/bindings/codegen/Configuration.py
index 71c988e5378..84d8bd974aa 100644
--- a/components/script/dom/bindings/codegen/Configuration.py
+++ b/components/script/dom/bindings/codegen/Configuration.py
@@ -2,6 +2,7 @@
# 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/.
+import functools
import os
from WebIDL import IDLExternalInterface, IDLSequenceType, IDLWrapperType, WebIDLError
@@ -15,7 +16,7 @@ class Configuration:
def __init__(self, filename, parseData):
# Read the configuration file.
glbl = {}
- execfile(filename, glbl)
+ exec(compile(open(filename).read(), filename, 'exec'), glbl)
config = glbl['DOMInterfaces']
# Build descriptors for all the interfaces we have in the parse data.
@@ -62,7 +63,8 @@ class Configuration:
c.isCallback() and not c.isInterface()]
# Keep the descriptor list sorted for determinism.
- self.descriptors.sort(lambda x, y: cmp(x.name, y.name))
+ cmp = lambda x, y: (x > y) - (x < y)
+ self.descriptors.sort(key=functools.cmp_to_key(lambda x, y: cmp(x.name, y.name)))
def getInterface(self, ifname):
return self.interfaces[ifname]
diff --git a/components/script/dom/bindings/error.rs b/components/script/dom/bindings/error.rs
index b0b6ca1f685..dc03b660824 100644
--- a/components/script/dom/bindings/error.rs
+++ b/components/script/dom/bindings/error.rs
@@ -6,7 +6,6 @@
#[cfg(feature = "js_backtrace")]
use crate::dom::bindings::cell::DomRefCell;
-use crate::dom::bindings::codegen::Bindings::DOMExceptionBinding::DOMExceptionMethods;
use crate::dom::bindings::codegen::PrototypeList::proto_id_to_name;
use crate::dom::bindings::conversions::root_from_object;
use crate::dom::bindings::conversions::{
@@ -221,7 +220,7 @@ impl ErrorInfo {
Some(ErrorInfo {
filename: "".to_string(),
- message: exception.Stringifier().into(),
+ message: exception.stringifier().into(),
lineno: 0,
column: 0,
})
diff --git a/components/script/dom/bindings/str.rs b/components/script/dom/bindings/str.rs
index 38091fcf19e..2b4830dccfc 100644
--- a/components/script/dom/bindings/str.rs
+++ b/components/script/dom/bindings/str.rs
@@ -3,11 +3,11 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
//! The `ByteString` struct.
-
use chrono::prelude::{Utc, Weekday};
use chrono::{Datelike, TimeZone};
use cssparser::CowRcStr;
use html5ever::{LocalName, Namespace};
+use regex::Regex;
use servo_atoms::Atom;
use std::borrow::{Borrow, Cow, ToOwned};
use std::default::Default;
@@ -337,11 +337,11 @@ impl DOMString {
/// https://html.spec.whatwg.org/multipage/#valid-floating-point-number
pub fn is_valid_floating_point_number_string(&self) -> bool {
- // for the case that `parse_floating_point_number` cannot handle
- if self.0.contains(" ") {
- return false;
+ lazy_static! {
+ static ref RE: Regex =
+ Regex::new(r"^-?(?:\d+\.\d+|\d+|\.\d+)(?:(e|E)(\+|\-)?\d+)?$").unwrap();
}
- parse_floating_point_number(&self.0).is_ok()
+ RE.is_match(&self.0) && parse_floating_point_number(&self.0).is_ok()
}
/// https://html.spec.whatwg.org/multipage/#best-representation-of-the-number-as-a-floating-point-number
diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs
index e865cf19e18..217e66837bb 100644
--- a/components/script/dom/bindings/trace.rs
+++ b/components/script/dom/bindings/trace.rs
@@ -37,9 +37,11 @@ use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::bindings::str::{DOMString, USVString};
use crate::dom::bindings::utils::WindowProxyHandler;
use crate::dom::document::PendingRestyle;
+use crate::dom::gpubuffer::GPUBufferState;
use crate::dom::htmlimageelement::SourceSet;
use crate::dom::htmlmediaelement::{HTMLMediaElementFetchContext, MediaFrameRenderer};
use crate::dom::identityhub::Identities;
+use crate::script_runtime::StreamConsumer;
use crate::task::TaskBox;
use app_units::Au;
use canvas_traits::canvas::{
@@ -60,7 +62,7 @@ use cssparser::RGBA;
use devtools_traits::{CSSError, TimelineMarkerType, WorkerId};
use embedder_traits::{EventLoopWaker, MediaMetadata};
use encoding_rs::{Decoder, Encoding};
-use euclid::default::{Point2D, Rect, Rotation3D, Transform2D, Transform3D};
+use euclid::default::{Point2D, Rect, Rotation3D, Transform2D};
use euclid::Length as EuclidLength;
use html5ever::buffer_queue::BufferQueue;
use html5ever::{LocalName, Namespace, Prefix, QualName};
@@ -145,13 +147,15 @@ use style::values::specified::Length;
use tendril::fmt::UTF8;
use tendril::stream::LossyDecoder;
use tendril::{StrTendril, TendrilSink};
-use time::{Duration, Timespec};
+use time::{Duration, Timespec, Tm};
use uuid::Uuid;
-use webgpu::{WebGPU, WebGPUAdapter};
+use webgpu::{WebGPU, WebGPUAdapter, WebGPUBuffer, WebGPUDevice};
use webrender_api::{DocumentId, ImageKey};
use webvr_traits::{WebVRGamepadData, WebVRGamepadHand, WebVRGamepadState};
use webxr_api::SwapChainId as WebXRSwapChainId;
+unsafe_no_jsmanaged_fields!(Tm);
+
/// A trait to allow tracing (only) DOM objects.
pub unsafe trait JSTraceable {
/// Trace `self`.
@@ -508,9 +512,12 @@ 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!(WebGPU);
unsafe_no_jsmanaged_fields!(WebGPUAdapter);
+unsafe_no_jsmanaged_fields!(WebGPUDevice);
+unsafe_no_jsmanaged_fields!(WebGPUBuffer);
+unsafe_no_jsmanaged_fields!(GPUBufferState);
unsafe_no_jsmanaged_fields!(WebXRSwapChainId);
unsafe_no_jsmanaged_fields!(MediaList);
unsafe_no_jsmanaged_fields!(WebVRGamepadData, WebVRGamepadState, WebVRGamepadHand);
@@ -536,7 +543,7 @@ unsafe_no_jsmanaged_fields!(Mutex<MediaFrameRenderer>);
unsafe_no_jsmanaged_fields!(ResourceFetchTiming);
unsafe_no_jsmanaged_fields!(Timespec);
unsafe_no_jsmanaged_fields!(HTMLMediaElementFetchContext);
-unsafe_no_jsmanaged_fields!(Rotation3D<f64>, Transform2D<f32>, Transform3D<f64>);
+unsafe_no_jsmanaged_fields!(Rotation3D<f64>, Transform2D<f32>);
unsafe_no_jsmanaged_fields!(Point2D<f32>, Rect<Au>);
unsafe_no_jsmanaged_fields!(Rect<f32>);
unsafe_no_jsmanaged_fields!(CascadeData);
@@ -547,6 +554,7 @@ unsafe_no_jsmanaged_fields!(Arc<Mutex<dyn AudioRenderer>>);
unsafe_no_jsmanaged_fields!(MediaSessionActionType);
unsafe_no_jsmanaged_fields!(MediaMetadata);
unsafe_no_jsmanaged_fields!(WebrenderIpcSender);
+unsafe_no_jsmanaged_fields!(StreamConsumer);
unsafe impl<'a> JSTraceable for &'a str {
#[inline]
@@ -666,6 +674,20 @@ unsafe impl<T, U> JSTraceable for euclid::RigidTransform3D<f64, T, U> {
}
}
+unsafe impl<T, U> JSTraceable for euclid::Transform3D<f32, T, U> {
+ #[inline]
+ unsafe fn trace(&self, _trc: *mut JSTracer) {
+ // Do nothing
+ }
+}
+
+unsafe impl<T, U> JSTraceable for euclid::Transform3D<f64, T, U> {
+ #[inline]
+ unsafe fn trace(&self, _trc: *mut JSTracer) {
+ // Do nothing
+ }
+}
+
unsafe impl<T> JSTraceable for EuclidLength<u64, T> {
#[inline]
unsafe fn trace(&self, _trc: *mut JSTracer) {
diff --git a/components/script/dom/closeevent.rs b/components/script/dom/closeevent.rs
index c88c3ac76aa..1c07813bce3 100644
--- a/components/script/dom/closeevent.rs
+++ b/components/script/dom/closeevent.rs
@@ -33,14 +33,6 @@ impl CloseEvent {
}
}
- pub fn new_uninitialized(global: &GlobalScope) -> DomRoot<CloseEvent> {
- reflect_dom_object(
- Box::new(CloseEvent::new_inherited(false, 0, DOMString::new())),
- global,
- CloseEventBinding::Wrap,
- )
- }
-
pub fn new(
global: &GlobalScope,
type_: Atom,
diff --git a/components/script/dom/compositionevent.rs b/components/script/dom/compositionevent.rs
index aa72db95d21..8b00ed1ac9c 100644
--- a/components/script/dom/compositionevent.rs
+++ b/components/script/dom/compositionevent.rs
@@ -21,6 +21,21 @@ pub struct CompositionEvent {
}
impl CompositionEvent {
+ pub fn new_inherited() -> CompositionEvent {
+ CompositionEvent {
+ uievent: UIEvent::new_inherited(),
+ data: DOMString::new(),
+ }
+ }
+
+ pub fn new_uninitialized(window: &Window) -> DomRoot<CompositionEvent> {
+ reflect_dom_object(
+ Box::new(CompositionEvent::new_inherited()),
+ window,
+ CompositionEventBinding::Wrap,
+ )
+ }
+
pub fn new(
window: &Window,
type_: DOMString,
diff --git a/components/script/dom/dedicatedworkerglobalscope.rs b/components/script/dom/dedicatedworkerglobalscope.rs
index 829c0be6b4e..567d4fa6861 100644
--- a/components/script/dom/dedicatedworkerglobalscope.rs
+++ b/components/script/dom/dedicatedworkerglobalscope.rs
@@ -320,24 +320,20 @@ impl DedicatedWorkerGlobalScope {
.credentials_mode(CredentialsMode::CredentialsSameOrigin)
.parser_metadata(ParserMetadata::NotParserInserted)
.use_url_credentials(true)
- .pipeline_id(pipeline_id)
+ .pipeline_id(Some(pipeline_id))
.referrer(referrer)
.referrer_policy(referrer_policy)
.origin(origin);
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 task_source = NetworkingTaskSource(
+ Box::new(WorkerThreadWorkerChan {
+ sender: own_sender.clone(),
+ worker: worker.clone(),
+ }),
+ pipeline_id,
+ );
+ new_child_runtime(parent, Some(task_source))
};
let (devtools_mpsc_chan, devtools_mpsc_port) = unbounded();
@@ -375,7 +371,7 @@ impl DedicatedWorkerGlobalScope {
.send(CommonScriptMsg::Task(
WorkerEvent,
Box::new(SimpleWorkerErrorHandler::new(worker)),
- pipeline_id,
+ Some(pipeline_id),
TaskSourceName::DOMManipulation,
))
.unwrap();
@@ -476,9 +472,6 @@ impl DedicatedWorkerGlobalScope {
DevtoolScriptControlMsg::EvaluateJS(_pipe_id, string, sender) => {
devtools::handle_evaluate_js(self.upcast(), string, sender)
},
- DevtoolScriptControlMsg::GetCachedMessages(pipe_id, message_types, sender) => {
- devtools::handle_get_cached_messages(pipe_id, message_types, sender)
- },
DevtoolScriptControlMsg::WantsLiveNotifications(_pipe_id, bool_val) => {
devtools::handle_wants_live_notifications(self.upcast(), bool_val)
},
diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs
index f936dde16cb..94c9c8603c4 100644
--- a/components/script/dom/document.rs
+++ b/components/script/dom/document.rs
@@ -38,7 +38,6 @@ use crate::dom::bindings::xmlname::{
namespace_from_domstring, validate_and_extract, xml_name_type,
};
use crate::dom::cdatasection::CDATASection;
-use crate::dom::closeevent::CloseEvent;
use crate::dom::comment::Comment;
use crate::dom::compositionevent::CompositionEvent;
use crate::dom::cssstylesheet::CSSStyleSheet;
@@ -52,7 +51,6 @@ use crate::dom::element::CustomElementCreationMode;
use crate::dom::element::{
Element, ElementCreator, ElementPerformFullscreenEnter, ElementPerformFullscreenExit,
};
-use crate::dom::errorevent::ErrorEvent;
use crate::dom::event::{Event, EventBubbles, EventCancelable, EventDefault, EventStatus};
use crate::dom::eventtarget::EventTarget;
use crate::dom::focusevent::FocusEvent;
@@ -81,9 +79,7 @@ use crate::dom::node::{LayoutNodeHelpers, Node, NodeDamage, NodeFlags, ShadowInc
use crate::dom::nodeiterator::NodeIterator;
use crate::dom::nodelist::NodeList;
use crate::dom::pagetransitionevent::PageTransitionEvent;
-use crate::dom::popstateevent::PopStateEvent;
use crate::dom::processinginstruction::ProcessingInstruction;
-use crate::dom::progressevent::ProgressEvent;
use crate::dom::promise::Promise;
use crate::dom::range::Range;
use crate::dom::servoparser::ServoParser;
@@ -97,7 +93,6 @@ use crate::dom::touchlist::TouchList;
use crate::dom::treewalker::TreeWalker;
use crate::dom::uievent::UIEvent;
use crate::dom::virtualmethods::vtable_for;
-use crate::dom::webglcontextevent::WebGLContextEvent;
use crate::dom::webglrenderingcontext::WebGLRenderingContext;
use crate::dom::wheelevent::WheelEvent;
use crate::dom::window::{ReflowReason, Window};
@@ -3814,15 +3809,14 @@ impl DocumentMethods for Document {
"beforeunloadevent" => Ok(DomRoot::upcast(BeforeUnloadEvent::new_uninitialized(
&self.window,
))),
- "closeevent" => Ok(DomRoot::upcast(CloseEvent::new_uninitialized(
- self.window.upcast(),
- ))),
+ "compositionevent" | "textevent" => Ok(DomRoot::upcast(
+ CompositionEvent::new_uninitialized(&self.window),
+ )),
"customevent" => Ok(DomRoot::upcast(CustomEvent::new_uninitialized(
self.window.upcast(),
))),
- "errorevent" => Ok(DomRoot::upcast(ErrorEvent::new_uninitialized(
- self.window.upcast(),
- ))),
+ // FIXME(#25136): devicemotionevent, deviceorientationevent
+ // FIXME(#7529): dragevent
"events" | "event" | "htmlevents" | "svgevents" => {
Ok(Event::new_uninitialized(&self.window.upcast()))
},
@@ -3839,15 +3833,6 @@ impl DocumentMethods for Document {
"mouseevent" | "mouseevents" => {
Ok(DomRoot::upcast(MouseEvent::new_uninitialized(&self.window)))
},
- "pagetransitionevent" => Ok(DomRoot::upcast(PageTransitionEvent::new_uninitialized(
- &self.window,
- ))),
- "popstateevent" => Ok(DomRoot::upcast(PopStateEvent::new_uninitialized(
- &self.window,
- ))),
- "progressevent" => Ok(DomRoot::upcast(ProgressEvent::new_uninitialized(
- self.window.upcast(),
- ))),
"storageevent" => Ok(DomRoot::upcast(StorageEvent::new_uninitialized(
&self.window,
"".into(),
@@ -3859,9 +3844,6 @@ impl DocumentMethods for Document {
&TouchList::new(&self.window, &[]),
))),
"uievent" | "uievents" => Ok(DomRoot::upcast(UIEvent::new_uninitialized(&self.window))),
- "webglcontextevent" => Ok(DomRoot::upcast(WebGLContextEvent::new_uninitialized(
- &self.window,
- ))),
_ => Err(Error::NotSupported),
}
}
diff --git a/components/script/dom/domexception.rs b/components/script/dom/domexception.rs
index 3cfe6092dd1..218771851b6 100644
--- a/components/script/dom/domexception.rs
+++ b/components/script/dom/domexception.rs
@@ -149,6 +149,11 @@ impl DOMException {
DOMExceptionBinding::Wrap,
))
}
+
+ // not an IDL stringifier, used internally
+ pub fn stringifier(&self) -> DOMString {
+ DOMString::from(format!("{}: {}", self.name, self.message))
+ }
}
impl DOMExceptionMethods for DOMException {
@@ -169,9 +174,4 @@ impl DOMExceptionMethods for DOMException {
fn Message(&self) -> DOMString {
self.message.clone()
}
-
- // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-error.prototype.tostring
- fn Stringifier(&self) -> DOMString {
- DOMString::from(format!("{}: {}", self.name, self.message))
- }
}
diff --git a/components/script/dom/domtokenlist.rs b/components/script/dom/domtokenlist.rs
index d6c5ac1537f..b870ab4f16d 100644
--- a/components/script/dom/domtokenlist.rs
+++ b/components/script/dom/domtokenlist.rs
@@ -151,7 +151,7 @@ impl DOMTokenListMethods for DOMTokenList {
}
// https://dom.spec.whatwg.org/#dom-domtokenlist-replace
- fn Replace(&self, token: DOMString, new_token: DOMString) -> ErrorResult {
+ fn Replace(&self, token: DOMString, new_token: DOMString) -> Fallible<bool> {
if token.is_empty() || new_token.is_empty() {
// Step 1.
return Err(Error::Syntax);
@@ -164,6 +164,7 @@ impl DOMTokenListMethods for DOMTokenList {
let token = Atom::from(token);
let new_token = Atom::from(new_token);
let mut atoms = self.element.get_tokenlist_attribute(&self.local_name);
+ let mut result = false;
if let Some(pos) = atoms.iter().position(|atom| *atom == token) {
if !atoms.contains(&new_token) {
atoms[pos] = new_token;
@@ -173,8 +174,9 @@ impl DOMTokenListMethods for DOMTokenList {
// Step 5.
self.element
.set_atomic_tokenlist_attribute(&self.local_name, atoms);
+ result = true;
}
- Ok(())
+ Ok(result)
}
// check-tidy: no specs after this line
diff --git a/components/script/dom/eventtarget.rs b/components/script/dom/eventtarget.rs
index 12cf7d0253b..ea259a6d2d7 100644
--- a/components/script/dom/eventtarget.rs
+++ b/components/script/dom/eventtarget.rs
@@ -227,14 +227,13 @@ impl CompiledEventListener {
rooted!(in(*cx) let value = value);
let value = value.handle();
- //Step 4
- let should_cancel = match event.type_() {
- atom!("mouseover") => {
- value.is_boolean() && value.to_boolean() == true
- },
- _ => value.is_boolean() && value.to_boolean() == false,
- };
+ //Step 5
+ let should_cancel = value.is_boolean() && value.to_boolean() == false;
+
if should_cancel {
+ // FIXME: spec says to set the cancelled flag directly
+ // here, not just to prevent default;
+ // can that ever make a difference?
event.PreventDefault();
}
}
diff --git a/components/script/dom/fakexrdevice.rs b/components/script/dom/fakexrdevice.rs
index d76c94751c0..bb73580e98a 100644
--- a/components/script/dom/fakexrdevice.rs
+++ b/components/script/dom/fakexrdevice.rs
@@ -20,7 +20,7 @@ use ipc_channel::ipc::IpcSender;
use ipc_channel::router::ROUTER;
use profile_traits::ipc;
use std::rc::Rc;
-use webxr_api::{MockDeviceMsg, View, Views};
+use webxr_api::{MockDeviceMsg, MockViewInit, MockViewsInit};
#[dom_struct]
pub struct FakeXRDevice {
@@ -50,58 +50,57 @@ impl FakeXRDevice {
}
}
-pub fn get_views(views: &[FakeXRViewInit]) -> Fallible<Views> {
- if views.len() != 2 {
- return Err(Error::NotSupported);
- }
-
- let (left, right) = match (views[0].eye, views[1].eye) {
- (XREye::Left, XREye::Right) => (&views[0], &views[1]),
- (XREye::Right, XREye::Left) => (&views[1], &views[0]),
- _ => return Err(Error::NotSupported),
- };
-
- if left.projectionMatrix.len() != 16 ||
- right.projectionMatrix.len() != 16 ||
- left.viewOffset.position.len() != 3 ||
- right.viewOffset.position.len() != 3
- {
+pub fn view<Eye>(view: &FakeXRViewInit) -> Fallible<MockViewInit<Eye>> {
+ if view.projectionMatrix.len() != 16 || view.viewOffset.position.len() != 3 {
return Err(Error::Type("Incorrectly sized array".into()));
}
- let mut proj_l = [0.; 16];
- let mut proj_r = [0.; 16];
- let v: Vec<_> = left.projectionMatrix.iter().map(|x| **x).collect();
- proj_l.copy_from_slice(&v);
- let proj_l = Transform3D::from_array(proj_l);
- let v: Vec<_> = right.projectionMatrix.iter().map(|x| **x).collect();
- proj_r.copy_from_slice(&v);
- let proj_r = Transform3D::from_array(proj_r);
+ let mut proj = [0.; 16];
+ let v: Vec<_> = view.projectionMatrix.iter().map(|x| **x).collect();
+ proj.copy_from_slice(&v);
+ let projection = Transform3D::from_array(proj);
// spec defines offsets as origins, but mock API expects the inverse transform
- let offset_l = get_origin(&left.viewOffset)?.inverse();
- let offset_r = get_origin(&right.viewOffset)?.inverse();
-
- let size_l = Size2D::new(views[0].resolution.width, views[0].resolution.height);
- let size_r = Size2D::new(views[1].resolution.width, views[1].resolution.height);
+ let transform = get_origin(&view.viewOffset)?.inverse();
- let origin_l = Point2D::new(0, 0);
- let origin_r = Point2D::new(size_l.width, 0);
-
- let viewport_l = Rect::new(origin_l, size_l);
- let viewport_r = Rect::new(origin_r, size_r);
-
- let left = View {
- projection: proj_l,
- transform: offset_l,
- viewport: viewport_l,
+ let size = Size2D::new(view.resolution.width, view.resolution.height);
+ let origin = match view.eye {
+ XREye::Right => Point2D::new(size.width, 0),
+ _ => Point2D::new(0, 0),
};
- let right = View {
- projection: proj_r,
- transform: offset_r,
- viewport: viewport_r,
+ let viewport = Rect::new(origin, size);
+
+ let fov = if let Some(ref fov) = view.fieldOfView {
+ Some((
+ fov.leftDegrees.to_radians(),
+ fov.rightDegrees.to_radians(),
+ fov.upDegrees.to_radians(),
+ fov.downDegrees.to_radians(),
+ ))
+ } else {
+ None
};
- Ok(Views::Stereo(left, right))
+
+ Ok(MockViewInit {
+ projection,
+ transform,
+ viewport,
+ fov,
+ })
+}
+pub fn get_views(views: &[FakeXRViewInit]) -> Fallible<MockViewsInit> {
+ match views.len() {
+ 1 => Ok(MockViewsInit::Mono(view(&views[0])?)),
+ 2 => {
+ let (left, right) = match (views[0].eye, views[1].eye) {
+ (XREye::Left, XREye::Right) => (&views[0], &views[1]),
+ (XREye::Right, XREye::Left) => (&views[1], &views[0]),
+ _ => return Err(Error::NotSupported),
+ };
+ Ok(MockViewsInit::Stereo(view(left)?, view(right)?))
+ },
+ _ => Err(Error::NotSupported),
+ }
}
pub fn get_origin<T, U>(
@@ -134,7 +133,7 @@ impl FakeXRDeviceMethods for FakeXRDevice {
Ok(())
}
- /// https://github.com/immersive-web/webxr-test-api/blob/master/explainer.md
+ /// https://immersive-web.github.io/webxr-test-api/#dom-fakexrdevice-setviewerorigin
fn SetViewerOrigin(
&self,
origin: &FakeXRRigidTransformInit,
@@ -142,7 +141,25 @@ impl FakeXRDeviceMethods for FakeXRDevice {
) -> Fallible<()> {
let _ = self
.sender
- .send(MockDeviceMsg::SetViewerOrigin(get_origin(origin)?));
+ .send(MockDeviceMsg::SetViewerOrigin(Some(get_origin(origin)?)));
+ Ok(())
+ }
+
+ /// https://immersive-web.github.io/webxr-test-api/#dom-fakexrdevice-clearviewerorigin
+ fn ClearViewerOrigin(&self) {
+ let _ = self.sender.send(MockDeviceMsg::SetViewerOrigin(None));
+ }
+
+ /// https://immersive-web.github.io/webxr-test-api/#dom-fakexrdevice-clearfloororigin
+ fn ClearFloorOrigin(&self) {
+ let _ = self.sender.send(MockDeviceMsg::SetFloorOrigin(None));
+ }
+
+ /// https://immersive-web.github.io/webxr-test-api/#dom-fakexrdevice-setfloororigin
+ fn SetFloorOrigin(&self, origin: &FakeXRRigidTransformInit) -> Fallible<()> {
+ let _ = self
+ .sender
+ .send(MockDeviceMsg::SetFloorOrigin(Some(get_origin(origin)?)));
Ok(())
}
diff --git a/components/script/dom/filereader.rs b/components/script/dom/filereader.rs
index 95b0572c3c5..d40ae95aac3 100644
--- a/components/script/dom/filereader.rs
+++ b/components/script/dom/filereader.rs
@@ -23,8 +23,7 @@ use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope;
use crate::dom::progressevent::ProgressEvent;
use crate::script_runtime::JSContext;
-use crate::task::TaskCanceller;
-use crate::task_source::file_reading::{FileReadingTask, FileReadingTaskSource};
+use crate::task_source::file_reading::FileReadingTask;
use crate::task_source::{TaskSource, TaskSourceName};
use base64;
use dom_struct::dom_struct;
@@ -37,8 +36,6 @@ use mime::{self, Mime};
use servo_atoms::Atom;
use std::cell::Cell;
use std::ptr;
-use std::sync::Arc;
-use std::thread;
#[derive(Clone, Copy, JSTraceable, MallocSizeOf, PartialEq)]
pub enum FileReaderFunction {
@@ -236,7 +233,7 @@ impl FileReader {
filereader: TrustedFileReader,
gen_id: GenerationId,
data: ReadMetaData,
- blob_contents: Arc<Vec<u8>>,
+ blob_contents: Vec<u8>,
) {
let fr = filereader.root();
@@ -426,6 +423,7 @@ impl FileReader {
self.generation_id.set(GenerationId(prev_id + 1));
}
+ /// <https://w3c.github.io/FileAPI/#readOperation>
fn read(
&self,
function: FileReaderFunction,
@@ -443,35 +441,40 @@ impl FileReader {
// Step 3
*self.result.borrow_mut() = None;
- let blob_contents = Arc::new(blob.get_bytes().unwrap_or(vec![]));
-
let type_ = blob.Type();
let load_data = ReadMetaData::new(String::from(type_), label.map(String::from), function);
- let fr = Trusted::new(self);
-
let GenerationId(prev_id) = self.generation_id.get();
self.generation_id.set(GenerationId(prev_id + 1));
let gen_id = self.generation_id.get();
+ // Step 10, in parallel, wait on stream promises to resolve and queue tasks.
+
+ // TODO: follow the spec which requires implementing blob `get_stream`,
+ // see https://github.com/servo/servo/issues/25209
+
+ // Currently bytes are first read "sync", and then the appropriate tasks are queued.
+
+ // Read the blob bytes "sync".
+ let blob_contents = blob.get_bytes().unwrap_or_else(|_| vec![]);
+
+ let filereader = Trusted::new(self);
let global = self.global();
let canceller = global.task_canceller(TaskSourceName::FileReading);
let task_source = global.file_reading_task_source();
- thread::Builder::new()
- .name("file reader async operation".to_owned())
- .spawn(move || {
- perform_annotated_read_operation(
- gen_id,
- load_data,
- blob_contents,
- fr,
- task_source,
- canceller,
- )
- })
- .expect("Thread spawning failed");
+ // Queue tasks as appropriate.
+ let task = FileReadingTask::ProcessRead(filereader.clone(), gen_id);
+ task_source.queue_with_canceller(task, &canceller).unwrap();
+
+ if !blob_contents.is_empty() {
+ let task = FileReadingTask::ProcessReadData(filereader.clone(), gen_id);
+ task_source.queue_with_canceller(task, &canceller).unwrap();
+ }
+
+ let task = FileReadingTask::ProcessReadEOF(filereader, gen_id, load_data, blob_contents);
+ task_source.queue_with_canceller(task, &canceller).unwrap();
Ok(())
}
@@ -480,25 +483,3 @@ impl FileReader {
self.ready_state.set(state);
}
}
-
-// https://w3c.github.io/FileAPI/#thread-read-operation
-fn perform_annotated_read_operation(
- gen_id: GenerationId,
- data: ReadMetaData,
- blob_contents: Arc<Vec<u8>>,
- filereader: TrustedFileReader,
- task_source: FileReadingTaskSource,
- canceller: TaskCanceller,
-) {
- // Step 4
- let task = FileReadingTask::ProcessRead(filereader.clone(), gen_id);
- task_source.queue_with_canceller(task, &canceller).unwrap();
-
- if !blob_contents.is_empty() {
- let task = FileReadingTask::ProcessReadData(filereader.clone(), gen_id);
- task_source.queue_with_canceller(task, &canceller).unwrap();
- }
-
- let task = FileReadingTask::ProcessReadEOF(filereader, gen_id, data, blob_contents);
- task_source.queue_with_canceller(task, &canceller).unwrap();
-}
diff --git a/components/script/dom/formdata.rs b/components/script/dom/formdata.rs
index d8df761cea7..b8503a4f0dc 100644
--- a/components/script/dom/formdata.rs
+++ b/components/script/dom/formdata.rs
@@ -56,7 +56,7 @@ impl FormData {
form: Option<&HTMLFormElement>,
) -> Fallible<DomRoot<FormData>> {
if let Some(opt_form) = form {
- return match opt_form.get_form_dataset(None) {
+ return match opt_form.get_form_dataset(None, None) {
Some(form_datums) => Ok(FormData::new(Some(form_datums), global)),
None => Err(Error::InvalidState),
};
diff --git a/components/script/dom/globalscope.rs b/components/script/dom/globalscope.rs
index e6b367a9858..f0748433e64 100644
--- a/components/script/dom/globalscope.rs
+++ b/components/script/dom/globalscope.rs
@@ -48,7 +48,7 @@ use crate::task_source::TaskSourceName;
use crate::timers::{IsInterval, OneshotTimerCallback, OneshotTimerHandle};
use crate::timers::{OneshotTimers, TimerCallback};
use content_security_policy::CspList;
-use devtools_traits::{ScriptToDevtoolsControlMsg, WorkerId};
+use devtools_traits::{PageError, ScriptToDevtoolsControlMsg};
use dom_struct::dom_struct;
use ipc_channel::ipc::{self, IpcSender};
use ipc_channel::router::ROUTER;
@@ -102,7 +102,6 @@ impl Drop for AutoCloseWorker {
pub struct GlobalScope {
eventtarget: EventTarget,
crypto: MutNullableDom<Crypto>,
- next_worker_id: Cell<WorkerId>,
/// The message-port router id for this global, if it is managing ports.
message_port_state: DomRefCell<MessagePortState>,
@@ -389,7 +388,6 @@ impl GlobalScope {
blob_state: DomRefCell::new(BlobState::UnManaged),
eventtarget: EventTarget::new_inherited(),
crypto: Default::default(),
- next_worker_id: Cell::new(WorkerId(0)),
pipeline_id,
devtools_wants_updates: Default::default(),
console_timers: DomRefCell::new(Default::default()),
@@ -1368,14 +1366,6 @@ impl GlobalScope {
self.crypto.or_init(|| Crypto::new(self))
}
- /// Get next worker id.
- pub fn get_next_worker_id(&self) -> WorkerId {
- let worker_id = self.next_worker_id.get();
- let WorkerId(id_num) = worker_id;
- self.next_worker_id.set(WorkerId(id_num + 1));
- worker_id
- }
-
pub fn live_devtools_updates(&self) -> bool {
self.devtools_wants_updates.get()
}
@@ -1412,6 +1402,29 @@ impl GlobalScope {
self.devtools_chan.as_ref()
}
+ pub fn issue_page_warning(&self, warning: &str) {
+ if let Some(ref chan) = self.devtools_chan {
+ let _ = chan.send(ScriptToDevtoolsControlMsg::ReportPageError(
+ self.pipeline_id.clone(),
+ PageError {
+ type_: "PageError".to_string(),
+ errorMessage: warning.to_string(),
+ sourceName: self.get_url().to_string(),
+ lineText: "".to_string(),
+ lineNumber: 0,
+ columnNumber: 0,
+ category: "script".to_string(),
+ timeStamp: 0, //TODO
+ error: false,
+ warning: true,
+ exception: true,
+ strict: false,
+ private: false,
+ },
+ ));
+ }
+ }
+
/// Get a sender to the memory profiler thread.
pub fn mem_profiler_chan(&self) -> &profile_mem::ProfilerChan {
&self.mem_profiler_chan
@@ -1527,6 +1540,27 @@ impl GlobalScope {
// https://html.spec.whatwg.org/multipage/#runtime-script-errors-2
if let Some(dedicated) = self.downcast::<DedicatedWorkerGlobalScope>() {
dedicated.forward_error_to_worker_object(error_info);
+ } else if self.is::<Window>() {
+ if let Some(ref chan) = self.devtools_chan {
+ let _ = chan.send(ScriptToDevtoolsControlMsg::ReportPageError(
+ self.pipeline_id.clone(),
+ PageError {
+ type_: "PageError".to_string(),
+ errorMessage: error_info.message.clone(),
+ sourceName: error_info.filename.clone(),
+ lineText: "".to_string(), //TODO
+ lineNumber: error_info.lineno,
+ columnNumber: error_info.column,
+ category: "script".to_string(),
+ timeStamp: 0, //TODO
+ error: true,
+ warning: false,
+ exception: true,
+ strict: false,
+ private: false,
+ },
+ ));
+ }
}
}
}
diff --git a/components/script/dom/gpu.rs b/components/script/dom/gpu.rs
index 4e47620052e..8a3e05f2d79 100644
--- a/components/script/dom/gpu.rs
+++ b/components/script/dom/gpu.rs
@@ -117,11 +117,13 @@ impl GPUMethods for GPU {
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,
+ Some(GPUPowerPreference::Low_power) => wgpu::instance::PowerPreference::LowPower,
+ Some(GPUPowerPreference::High_performance) => {
+ wgpu::instance::PowerPreference::HighPerformance
+ },
+ None => wgpu::instance::PowerPreference::Default,
};
- let id = self.global().as_window().Navigator().create_adapter_id();
+ let ids = self.global().as_window().Navigator().create_adapter_ids();
match self.wgpu_channel() {
Some(channel) => {
@@ -129,8 +131,8 @@ impl GPUMethods for GPU {
.0
.send(WebGPURequest::RequestAdapter(
sender,
- wgpu::RequestAdapterOptions { power_preference },
- id,
+ wgpu::instance::RequestAdapterOptions { power_preference },
+ ids,
))
.unwrap();
},
@@ -146,7 +148,7 @@ impl AsyncWGPUListener for GPU {
WebGPUResponse::RequestAdapter(name, adapter) => {
let adapter = GPUAdapter::new(
&self.global(),
- DOMString::from(name),
+ DOMString::from(format!("{} ({:?})", name, adapter.0.backend())),
Heap::default(),
adapter,
);
diff --git a/components/script/dom/gpuadapter.rs b/components/script/dom/gpuadapter.rs
index ec970439e8a..cbb24917ebe 100644
--- a/components/script/dom/gpuadapter.rs
+++ b/components/script/dom/gpuadapter.rs
@@ -2,16 +2,28 @@
* 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::compartments::InCompartment;
+use crate::dom::bindings::codegen::Bindings::GPUAdapterBinding::{
+ self, GPUAdapterMethods, GPUDeviceDescriptor,
+};
+use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods;
+use crate::dom::bindings::error::Error;
+use crate::dom::bindings::inheritance::Castable;
+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::gpu::response_async;
+use crate::dom::gpu::AsyncWGPUListener;
+use crate::dom::gpudevice::GPUDevice;
+use crate::dom::promise::Promise;
+use crate::dom::window::Window;
use crate::script_runtime::JSContext as SafeJSContext;
use dom_struct::dom_struct;
use js::jsapi::{Heap, JSObject};
use std::ptr::NonNull;
-use webgpu::WebGPUAdapter;
+use std::rc::Rc;
+use webgpu::{wgpu, WebGPUAdapter, WebGPURequest, WebGPUResponse};
#[dom_struct]
pub struct GPUAdapter {
@@ -60,4 +72,53 @@ impl GPUAdapterMethods for GPUAdapter {
fn Extensions(&self, _cx: SafeJSContext) -> NonNull<JSObject> {
NonNull::new(self.extensions.get()).unwrap()
}
+
+ /// https://gpuweb.github.io/gpuweb/#dom-gpuadapter-requestdevice
+ fn RequestDevice(&self, descriptor: &GPUDeviceDescriptor, comp: InCompartment) -> Rc<Promise> {
+ let promise = Promise::new_in_current_compartment(&self.global(), comp);
+ let sender = response_async(&promise, self);
+ let desc = wgpu::instance::DeviceDescriptor {
+ extensions: wgpu::instance::Extensions {
+ anisotropic_filtering: descriptor.extensions.anisotropicFiltering,
+ },
+ limits: wgpu::instance::Limits {
+ max_bind_groups: descriptor.limits.maxBindGroups,
+ },
+ };
+ if let Some(window) = self.global().downcast::<Window>() {
+ let id = window
+ .Navigator()
+ .create_device_id(self.adapter.0.backend());
+ match window.webgpu_channel() {
+ Some(thread) => thread
+ .0
+ .send(WebGPURequest::RequestDevice(sender, self.adapter, desc, id))
+ .unwrap(),
+ None => promise.reject_error(Error::Type("No WebGPU thread...".to_owned())),
+ }
+ } else {
+ promise.reject_error(Error::Type("No WebGPU thread...".to_owned()))
+ };
+ promise
+ }
+}
+
+impl AsyncWGPUListener for GPUAdapter {
+ fn handle_response(&self, response: WebGPUResponse, promise: &Rc<Promise>) {
+ match response {
+ WebGPUResponse::RequestDevice(device_id, _descriptor) => {
+ let device = GPUDevice::new(
+ &self.global(),
+ &self,
+ Heap::default(),
+ Heap::default(),
+ device_id,
+ );
+ promise.resolve_native(&device);
+ },
+ _ => promise.reject_error(Error::Type(
+ "Wrong response type from WebGPU thread...".to_owned(),
+ )),
+ }
+ }
}
diff --git a/components/script/dom/gpubuffer.rs b/components/script/dom/gpubuffer.rs
new file mode 100644
index 00000000000..a2a3e3b62eb
--- /dev/null
+++ b/components/script/dom/gpubuffer.rs
@@ -0,0 +1,120 @@
+/* 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::GPUBufferBinding::{
+ self, GPUBufferMethods, GPUBufferSize,
+};
+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 dom_struct::dom_struct;
+use ipc_channel::ipc::IpcSender;
+use std::cell::Cell;
+use webgpu::{WebGPUBuffer, WebGPUDevice, WebGPURequest};
+
+#[derive(MallocSizeOf)]
+pub enum GPUBufferState {
+ Mapped,
+ Unmapped,
+ Destroyed,
+}
+
+#[dom_struct]
+pub struct GPUBuffer {
+ reflector_: Reflector,
+ #[ignore_malloc_size_of = "channels are hard"]
+ channel: IpcSender<WebGPURequest>,
+ label: DomRefCell<Option<DOMString>>,
+ size: GPUBufferSize,
+ usage: u32,
+ state: DomRefCell<GPUBufferState>,
+ buffer: WebGPUBuffer,
+ device: WebGPUDevice,
+ valid: Cell<bool>,
+}
+
+impl GPUBuffer {
+ fn new_inherited(
+ channel: IpcSender<WebGPURequest>,
+ buffer: WebGPUBuffer,
+ device: WebGPUDevice,
+ state: GPUBufferState,
+ size: GPUBufferSize,
+ usage: u32,
+ valid: bool,
+ ) -> GPUBuffer {
+ Self {
+ reflector_: Reflector::new(),
+ channel,
+ label: DomRefCell::new(None),
+ state: DomRefCell::new(state),
+ size: size,
+ usage: usage,
+ valid: Cell::new(valid),
+ device,
+ buffer,
+ }
+ }
+
+ #[allow(unsafe_code)]
+ pub fn new(
+ global: &GlobalScope,
+ channel: IpcSender<WebGPURequest>,
+ buffer: WebGPUBuffer,
+ device: WebGPUDevice,
+ state: GPUBufferState,
+ size: GPUBufferSize,
+ usage: u32,
+ valid: bool,
+ ) -> DomRoot<GPUBuffer> {
+ reflect_dom_object(
+ Box::new(GPUBuffer::new_inherited(
+ channel, buffer, device, state, size, usage, valid,
+ )),
+ global,
+ GPUBufferBinding::Wrap,
+ )
+ }
+}
+
+impl Drop for GPUBuffer {
+ fn drop(&mut self) {
+ self.Destroy()
+ }
+}
+
+impl GPUBufferMethods for GPUBuffer {
+ /// https://gpuweb.github.io/gpuweb/#dom-gpubuffer-unmap
+ fn Unmap(&self) {
+ self.channel
+ .send(WebGPURequest::UnmapBuffer(self.buffer))
+ .unwrap();
+ }
+
+ /// https://gpuweb.github.io/gpuweb/#dom-gpubuffer-destroy
+ fn Destroy(&self) {
+ match *self.state.borrow() {
+ GPUBufferState::Mapped => {
+ self.Unmap();
+ },
+ _ => {},
+ };
+ self.channel
+ .send(WebGPURequest::DestroyBuffer(self.buffer))
+ .unwrap();
+ *self.state.borrow_mut() = GPUBufferState::Destroyed;
+ }
+
+ /// https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label
+ fn GetLabel(&self) -> Option<DOMString> {
+ self.label.borrow().clone()
+ }
+
+ /// https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label
+ fn SetLabel(&self, value: Option<DOMString>) {
+ *self.label.borrow_mut() = value;
+ }
+}
diff --git a/components/script/dom/gpubufferusage.rs b/components/script/dom/gpubufferusage.rs
new file mode 100644
index 00000000000..9b3a97d26fd
--- /dev/null
+++ b/components/script/dom/gpubufferusage.rs
@@ -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/. */
+
+use crate::dom::bindings::reflector::Reflector;
+use dom_struct::dom_struct;
+
+#[dom_struct]
+pub struct GPUBufferUsage {
+ reflector_: Reflector,
+}
diff --git a/components/script/dom/gpudevice.rs b/components/script/dom/gpudevice.rs
new file mode 100644
index 00000000000..81974735b55
--- /dev/null
+++ b/components/script/dom/gpudevice.rs
@@ -0,0 +1,249 @@
+/* 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/. */
+
+#![allow(unsafe_code)]
+
+use crate::dom::bindings::cell::DomRefCell;
+use crate::dom::bindings::codegen::Bindings::GPUBufferBinding::GPUBufferDescriptor;
+use crate::dom::bindings::codegen::Bindings::GPUDeviceBinding::{self, GPUDeviceMethods};
+use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods;
+use crate::dom::bindings::inheritance::Castable;
+use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
+use crate::dom::bindings::root::{Dom, DomRoot};
+use crate::dom::bindings::str::DOMString;
+use crate::dom::eventtarget::EventTarget;
+use crate::dom::globalscope::GlobalScope;
+use crate::dom::gpuadapter::GPUAdapter;
+use crate::dom::gpubuffer::{GPUBuffer, GPUBufferState};
+use crate::dom::window::Window;
+use crate::script_runtime::JSContext as SafeJSContext;
+use dom_struct::dom_struct;
+use ipc_channel::ipc;
+use js::jsapi::{Heap, JSObject};
+use js::jsval::{JSVal, ObjectValue, UndefinedValue};
+use js::typedarray::{ArrayBuffer, CreateWith};
+use std::ptr::{self, NonNull};
+use webgpu::wgpu::resource::{BufferDescriptor, BufferUsage};
+use webgpu::{WebGPUBuffer, WebGPUDevice, WebGPURequest};
+
+#[dom_struct]
+pub struct GPUDevice {
+ eventtarget: EventTarget,
+ adapter: Dom<GPUAdapter>,
+ #[ignore_malloc_size_of = "mozjs"]
+ extensions: Heap<*mut JSObject>,
+ #[ignore_malloc_size_of = "mozjs"]
+ limits: Heap<*mut JSObject>,
+ label: DomRefCell<Option<DOMString>>,
+ device: WebGPUDevice,
+}
+
+impl GPUDevice {
+ fn new_inherited(
+ adapter: &GPUAdapter,
+ extensions: Heap<*mut JSObject>,
+ limits: Heap<*mut JSObject>,
+ device: WebGPUDevice,
+ ) -> GPUDevice {
+ Self {
+ eventtarget: EventTarget::new_inherited(),
+ adapter: Dom::from_ref(adapter),
+ extensions,
+ limits,
+ label: DomRefCell::new(None),
+ device,
+ }
+ }
+
+ #[allow(unsafe_code)]
+ pub fn new(
+ global: &GlobalScope,
+ adapter: &GPUAdapter,
+ extensions: Heap<*mut JSObject>,
+ limits: Heap<*mut JSObject>,
+ device: WebGPUDevice,
+ ) -> DomRoot<GPUDevice> {
+ reflect_dom_object(
+ Box::new(GPUDevice::new_inherited(
+ adapter, extensions, limits, device,
+ )),
+ global,
+ GPUDeviceBinding::Wrap,
+ )
+ }
+}
+
+impl GPUDevice {
+ unsafe fn resolve_create_buffer_mapped(
+ &self,
+ cx: SafeJSContext,
+ channel: ipc_channel::ipc::IpcSender<WebGPURequest>,
+ gpu_buffer: WebGPUBuffer,
+ array_buffer: Vec<u8>,
+ descriptor: BufferDescriptor,
+ valid: bool,
+ ) -> Vec<JSVal> {
+ rooted!(in(*cx) let mut js_array_buffer = ptr::null_mut::<JSObject>());
+ let mut out = Vec::new();
+ assert!(ArrayBuffer::create(
+ *cx,
+ CreateWith::Slice(array_buffer.as_slice()),
+ js_array_buffer.handle_mut(),
+ )
+ .is_ok());
+
+ let buff = GPUBuffer::new(
+ &self.global(),
+ channel,
+ gpu_buffer,
+ self.device,
+ GPUBufferState::Mapped,
+ descriptor.size,
+ descriptor.usage.bits(),
+ valid,
+ );
+ out.push(ObjectValue(buff.reflector().get_jsobject().get()));
+ out.push(ObjectValue(js_array_buffer.get()));
+ out
+ }
+
+ fn validate_buffer_descriptor(
+ &self,
+ descriptor: &GPUBufferDescriptor,
+ ) -> (bool, BufferDescriptor) {
+ // TODO: Record a validation error in the current scope if the descriptor is invalid.
+ let wgpu_usage = BufferUsage::from_bits(descriptor.usage);
+ let valid = wgpu_usage.is_some() && descriptor.size > 0;
+
+ if valid {
+ (
+ true,
+ BufferDescriptor {
+ size: descriptor.size,
+ usage: wgpu_usage.unwrap(),
+ },
+ )
+ } else {
+ (
+ false,
+ BufferDescriptor {
+ size: 0,
+ usage: BufferUsage::STORAGE,
+ },
+ )
+ }
+ }
+}
+
+impl GPUDeviceMethods for GPUDevice {
+ /// https://gpuweb.github.io/gpuweb/#dom-gpudevice-adapter
+ fn Adapter(&self) -> DomRoot<GPUAdapter> {
+ DomRoot::from_ref(&self.adapter)
+ }
+
+ /// https://gpuweb.github.io/gpuweb/#dom-gpudevice-extensions
+ fn Extensions(&self, _cx: SafeJSContext) -> NonNull<JSObject> {
+ NonNull::new(self.extensions.get()).unwrap()
+ }
+
+ /// https://gpuweb.github.io/gpuweb/#dom-gpudevice-limits
+ fn Limits(&self, _cx: SafeJSContext) -> NonNull<JSObject> {
+ NonNull::new(self.extensions.get()).unwrap()
+ }
+
+ /// https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label
+ fn GetLabel(&self) -> Option<DOMString> {
+ self.label.borrow().clone()
+ }
+
+ /// https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label
+ fn SetLabel(&self, value: Option<DOMString>) {
+ *self.label.borrow_mut() = value;
+ }
+
+ /// https://gpuweb.github.io/gpuweb/#dom-gpudevice-createbuffer
+ fn CreateBuffer(&self, descriptor: &GPUBufferDescriptor) -> DomRoot<GPUBuffer> {
+ let (valid, wgpu_descriptor) = self.validate_buffer_descriptor(descriptor);
+ let channel;
+ let (sender, receiver) = ipc::channel().unwrap();
+ if let Some(window) = self.global().downcast::<Window>() {
+ let id = window.Navigator().create_buffer_id(self.device.0.backend());
+ match window.webgpu_channel() {
+ Some(thread) => {
+ channel = thread.0.clone();
+ thread
+ .0
+ .send(WebGPURequest::CreateBuffer(
+ sender,
+ self.device,
+ id,
+ wgpu_descriptor,
+ ))
+ .unwrap();
+ },
+ None => unimplemented!(),
+ }
+ } else {
+ unimplemented!()
+ };
+
+ let buffer = receiver.recv().unwrap();
+
+ GPUBuffer::new(
+ &self.global(),
+ channel,
+ buffer,
+ self.device,
+ GPUBufferState::Unmapped,
+ descriptor.size,
+ descriptor.usage,
+ valid,
+ )
+ }
+
+ /// https://gpuweb.github.io/gpuweb/#dom-gpudevice-createbuffermapped
+ fn CreateBufferMapped(
+ &self,
+ cx: SafeJSContext,
+ descriptor: &GPUBufferDescriptor,
+ ) -> Vec<JSVal> {
+ let (valid, wgpu_descriptor) = self.validate_buffer_descriptor(descriptor);
+ let channel;
+ let (sender, receiver) = ipc::channel().unwrap();
+ rooted!(in(*cx) let js_val = UndefinedValue());
+ if let Some(window) = self.global().downcast::<Window>() {
+ let id = window.Navigator().create_buffer_id(self.device.0.backend());
+ match window.webgpu_channel() {
+ Some(thread) => {
+ channel = thread.0.clone();
+ thread
+ .0
+ .send(WebGPURequest::CreateBufferMapped(
+ sender,
+ self.device,
+ id,
+ wgpu_descriptor.clone(),
+ ))
+ .unwrap()
+ },
+ None => return vec![js_val.get()],
+ }
+ } else {
+ return vec![js_val.get()];
+ };
+
+ let (buffer, array_buffer) = receiver.recv().unwrap();
+
+ unsafe {
+ self.resolve_create_buffer_mapped(
+ cx,
+ channel,
+ buffer,
+ array_buffer,
+ wgpu_descriptor,
+ valid,
+ )
+ }
+ }
+}
diff --git a/components/script/dom/headers.rs b/components/script/dom/headers.rs
index 017cde9268a..61c6fc1f98e 100644
--- a/components/script/dom/headers.rs
+++ b/components/script/dom/headers.rs
@@ -14,9 +14,8 @@ use crate::dom::bindings::str::{is_token, ByteString};
use crate::dom::globalscope::GlobalScope;
use dom_struct::dom_struct;
use http::header::{self, HeaderMap as HyperHeaders, HeaderName, HeaderValue};
-use mime::{self, Mime};
+use net_traits::request::is_cors_safelisted_request_header;
use std::cell::Cell;
-use std::result::Result;
use std::str::{self, FromStr};
#[dom_struct]
@@ -28,7 +27,7 @@ pub struct Headers {
}
// https://fetch.spec.whatwg.org/#concept-headers-guard
-#[derive(Clone, Copy, JSTraceable, MallocSizeOf, PartialEq)]
+#[derive(Clone, Copy, Debug, JSTraceable, MallocSizeOf, PartialEq)]
pub enum Guard {
Immutable,
Request,
@@ -88,6 +87,9 @@ impl HeadersMethods for Headers {
return Ok(());
}
// Step 7
+ // FIXME: this is NOT what WHATWG says to do when appending
+ // another copy of an existing header. HyperHeaders
+ // might not expose the information we need to do it right.
let mut combined_value: Vec<u8> = vec![];
if let Some(v) = self
.header_list
@@ -301,35 +303,6 @@ impl Iterable for Headers {
}
}
-fn is_cors_safelisted_request_content_type(value: &[u8]) -> bool {
- let value_string = if let Ok(s) = str::from_utf8(value) {
- s
- } else {
- return false;
- };
- let value_mime_result: Result<Mime, _> = value_string.parse();
- match value_mime_result {
- Err(_) => false,
- Ok(value_mime) => match (value_mime.type_(), value_mime.subtype()) {
- (mime::APPLICATION, mime::WWW_FORM_URLENCODED) |
- (mime::MULTIPART, mime::FORM_DATA) |
- (mime::TEXT, mime::PLAIN) => true,
- _ => false,
- },
- }
-}
-
-// TODO: "DPR", "Downlink", "Save-Data", "Viewport-Width", "Width":
-// ... once parsed, the value should not be failure.
-// https://fetch.spec.whatwg.org/#cors-safelisted-request-header
-fn is_cors_safelisted_request_header(name: &str, value: &[u8]) -> bool {
- match name {
- "accept" | "accept-language" | "content-language" => true,
- "content-type" => is_cors_safelisted_request_content_type(value),
- _ => false,
- }
-}
-
// https://fetch.spec.whatwg.org/#forbidden-response-header-name
fn is_forbidden_response_header(name: &str) -> bool {
match name {
@@ -394,11 +367,18 @@ pub fn is_forbidden_header_name(name: &str) -> bool {
// [2] https://tools.ietf.org/html/rfc7230#section-3.2
// [3] https://tools.ietf.org/html/rfc7230#section-3.2.6
// [4] https://www.rfc-editor.org/errata_search.php?rfc=7230
+//
+// As of December 2019 WHATWG, isn't even using grammar productions for value;
+// https://fetch.spec.whatg.org/#concept-header-value just says not to have
+// newlines, nulls, or leading/trailing whitespace.
fn validate_name_and_value(name: ByteString, value: ByteString) -> Fallible<(String, Vec<u8>)> {
let valid_name = validate_name(name)?;
+
+ // this is probably out of date
if !is_field_content(&value) {
return Err(Error::Type("Value is not valid".to_string()));
}
+
Ok((valid_name, value.into()))
}
diff --git a/components/script/dom/htmlformelement.rs b/components/script/dom/htmlformelement.rs
index 913f5f8530a..959bca74b54 100755..100644
--- a/components/script/dom/htmlformelement.rs
+++ b/components/script/dom/htmlformelement.rs
@@ -64,6 +64,13 @@ use std::cell::Cell;
use style::attr::AttrValue;
use style::str::split_html_space_chars;
+use crate::dom::bindings::codegen::UnionTypes::RadioNodeListOrElement;
+use crate::dom::radionodelist::RadioNodeList;
+use std::collections::HashMap;
+use time::{now, Duration, Tm};
+
+use crate::dom::bindings::codegen::Bindings::NodeBinding::{NodeConstants, NodeMethods};
+
#[derive(Clone, Copy, JSTraceable, MallocSizeOf, PartialEq)]
pub struct GenerationId(u32);
@@ -76,6 +83,7 @@ pub struct HTMLFormElement {
elements: DomOnceCell<HTMLFormControlsCollection>,
generation_id: Cell<GenerationId>,
controls: DomRefCell<Vec<Dom<Element>>>,
+ past_names_map: DomRefCell<HashMap<DOMString, (Dom<Element>, Tm)>>,
}
impl HTMLFormElement {
@@ -91,6 +99,7 @@ impl HTMLFormElement {
elements: Default::default(),
generation_id: Cell::new(GenerationId(0)),
controls: DomRefCell::new(Vec::new()),
+ past_names_map: DomRefCell::new(HashMap::new()),
}
}
@@ -253,6 +262,219 @@ impl HTMLFormElementMethods for HTMLFormElement {
let elements = self.Elements();
elements.IndexedGetter(index)
}
+
+ // https://html.spec.whatwg.org/multipage/#the-form-element%3Adetermine-the-value-of-a-named-property
+ fn NamedGetter(&self, name: DOMString) -> Option<RadioNodeListOrElement> {
+ let mut candidates: Vec<DomRoot<Node>> = Vec::new();
+
+ let controls = self.controls.borrow();
+ // Step 1
+ for child in controls.iter() {
+ if child
+ .downcast::<HTMLElement>()
+ .map_or(false, |c| c.is_listed_element())
+ {
+ if (child.has_attribute(&local_name!("id")) &&
+ child.get_string_attribute(&local_name!("id")) == name) ||
+ (child.has_attribute(&local_name!("name")) &&
+ child.get_string_attribute(&local_name!("name")) == name)
+ {
+ candidates.push(DomRoot::from_ref(&*child.upcast::<Node>()));
+ }
+ }
+ }
+ // Step 2
+ if candidates.len() == 0 {
+ for child in controls.iter() {
+ if child.is::<HTMLImageElement>() {
+ if (child.has_attribute(&local_name!("id")) &&
+ child.get_string_attribute(&local_name!("id")) == name) ||
+ (child.has_attribute(&local_name!("name")) &&
+ child.get_string_attribute(&local_name!("name")) == name)
+ {
+ candidates.push(DomRoot::from_ref(&*child.upcast::<Node>()));
+ }
+ }
+ }
+ }
+
+ let mut past_names_map = self.past_names_map.borrow_mut();
+
+ // Step 3
+ if candidates.len() == 0 {
+ if past_names_map.contains_key(&name) {
+ return Some(RadioNodeListOrElement::Element(DomRoot::from_ref(
+ &*past_names_map.get(&name).unwrap().0,
+ )));
+ }
+ return None;
+ }
+
+ // Step 4
+ if candidates.len() > 1 {
+ let window = window_from_node(self);
+
+ return Some(RadioNodeListOrElement::RadioNodeList(
+ RadioNodeList::new_simple_list(&window, candidates.into_iter()),
+ ));
+ }
+
+ // Step 5
+ let element_node = &candidates[0];
+ past_names_map.insert(
+ name,
+ (
+ Dom::from_ref(&*element_node.downcast::<Element>().unwrap()),
+ now(),
+ ),
+ );
+
+ // Step 6
+ return Some(RadioNodeListOrElement::Element(DomRoot::from_ref(
+ &*element_node.downcast::<Element>().unwrap(),
+ )));
+ }
+
+ // https://html.spec.whatwg.org/multipage/#the-form-element:supported-property-names
+ fn SupportedPropertyNames(&self) -> Vec<DOMString> {
+ // Step 1
+ #[derive(Debug, Eq, Ord, PartialEq, PartialOrd)]
+ enum SourcedNameSource {
+ Id,
+ Name,
+ Past(Duration),
+ }
+
+ impl SourcedNameSource {
+ fn is_past(&self) -> bool {
+ match self {
+ SourcedNameSource::Past(..) => true,
+ _ => false,
+ }
+ }
+ }
+
+ struct SourcedName {
+ name: DOMString,
+ element: DomRoot<Element>,
+ source: SourcedNameSource,
+ }
+
+ let mut sourcedNamesVec: Vec<SourcedName> = Vec::new();
+
+ let controls = self.controls.borrow();
+
+ // Step 2
+ for child in controls.iter() {
+ if child
+ .downcast::<HTMLElement>()
+ .map_or(false, |c| c.is_listed_element())
+ {
+ if child.has_attribute(&local_name!("id")) {
+ let entry = SourcedName {
+ name: child.get_string_attribute(&local_name!("id")),
+ element: DomRoot::from_ref(&*child),
+ source: SourcedNameSource::Id,
+ };
+ sourcedNamesVec.push(entry);
+ }
+ if child.has_attribute(&local_name!("name")) {
+ let entry = SourcedName {
+ name: child.get_string_attribute(&local_name!("name")),
+ element: DomRoot::from_ref(&*child),
+ source: SourcedNameSource::Name,
+ };
+ sourcedNamesVec.push(entry);
+ }
+ }
+ }
+
+ // Step 3
+ for child in controls.iter() {
+ if child.is::<HTMLImageElement>() {
+ if child.has_attribute(&local_name!("id")) {
+ let entry = SourcedName {
+ name: child.get_string_attribute(&local_name!("id")),
+ element: DomRoot::from_ref(&*child),
+ source: SourcedNameSource::Id,
+ };
+ sourcedNamesVec.push(entry);
+ }
+ if child.has_attribute(&local_name!("name")) {
+ let entry = SourcedName {
+ name: child.get_string_attribute(&local_name!("name")),
+ element: DomRoot::from_ref(&*child),
+ source: SourcedNameSource::Name,
+ };
+ sourcedNamesVec.push(entry);
+ }
+ }
+ }
+
+ // Step 4
+ let past_names_map = self.past_names_map.borrow();
+ for (key, val) in past_names_map.iter() {
+ let entry = SourcedName {
+ name: key.clone(),
+ element: DomRoot::from_ref(&*val.0),
+ source: SourcedNameSource::Past(now() - val.1), // calculate difference now()-val.1 to find age
+ };
+ sourcedNamesVec.push(entry);
+ }
+
+ // Step 5
+ // TODO need to sort as per spec.
+ // if a.CompareDocumentPosition(b) returns 0 that means a=b in which case
+ // the remaining part where sorting is to be done by putting entries whose source is id first,
+ // then entries whose source is name, and finally entries whose source is past,
+ // and sorting entries with the same element and source by their age, oldest first.
+
+ // if a.CompareDocumentPosition(b) has set NodeConstants::DOCUMENT_POSITION_FOLLOWING
+ // (this can be checked by bitwise operations) then b would follow a in tree order and
+ // Ordering::Less should be returned in the closure else Ordering::Greater
+
+ sourcedNamesVec.sort_by(|a, b| {
+ if a.element
+ .upcast::<Node>()
+ .CompareDocumentPosition(b.element.upcast::<Node>()) ==
+ 0
+ {
+ if a.source.is_past() && b.source.is_past() {
+ b.source.cmp(&a.source)
+ } else {
+ a.source.cmp(&b.source)
+ }
+ } else {
+ if a.element
+ .upcast::<Node>()
+ .CompareDocumentPosition(b.element.upcast::<Node>()) &
+ NodeConstants::DOCUMENT_POSITION_FOLLOWING ==
+ NodeConstants::DOCUMENT_POSITION_FOLLOWING
+ {
+ std::cmp::Ordering::Less
+ } else {
+ std::cmp::Ordering::Greater
+ }
+ }
+ });
+
+ // Step 6
+ sourcedNamesVec.retain(|sn| !sn.name.to_string().is_empty());
+
+ // Step 7-8
+ let mut namesVec: Vec<DOMString> = Vec::new();
+ for elem in sourcedNamesVec.iter() {
+ if namesVec
+ .iter()
+ .find(|name| name.to_string() == elem.name.to_string())
+ .is_none()
+ {
+ namesVec.push(elem.name.clone());
+ }
+ }
+
+ return namesVec;
+ }
}
#[derive(Clone, Copy, MallocSizeOf, PartialEq)]
@@ -357,7 +579,7 @@ impl HTMLFormElement {
let encoding = self.pick_encoding();
// Step 9
- let mut form_data = match self.get_form_dataset(Some(submitter)) {
+ let mut form_data = match self.get_form_dataset(Some(submitter), Some(encoding)) {
Some(form_data) => form_data,
None => return,
};
@@ -645,8 +867,14 @@ impl HTMLFormElement {
}
/// <https://html.spec.whatwg.org/multipage/#constructing-the-form-data-set>
+ /// terminology note: "form data set" = "entry list"
/// Steps range from 3 to 5
- fn get_unclean_dataset(&self, submitter: Option<FormSubmitter>) -> Vec<FormDatum> {
+ /// 5.x substeps are mostly handled inside element-specific methods
+ fn get_unclean_dataset(
+ &self,
+ submitter: Option<FormSubmitter>,
+ encoding: Option<&'static Encoding>,
+ ) -> Vec<FormDatum> {
let controls = self.controls.borrow();
let mut data_set = Vec::new();
for child in controls.iter() {
@@ -668,7 +896,7 @@ impl HTMLFormElement {
HTMLElementTypeId::HTMLInputElement => {
let input = child.downcast::<HTMLInputElement>().unwrap();
- data_set.append(&mut input.form_datums(submitter));
+ data_set.append(&mut input.form_datums(submitter, encoding));
},
HTMLElementTypeId::HTMLButtonElement => {
let button = child.downcast::<HTMLButtonElement>().unwrap();
@@ -705,7 +933,11 @@ impl HTMLFormElement {
}
/// <https://html.spec.whatwg.org/multipage/#constructing-the-form-data-set>
- pub fn get_form_dataset(&self, submitter: Option<FormSubmitter>) -> Option<Vec<FormDatum>> {
+ pub fn get_form_dataset(
+ &self,
+ submitter: Option<FormSubmitter>,
+ encoding: Option<&'static Encoding>,
+ ) -> Option<Vec<FormDatum>> {
fn clean_crlf(s: &str) -> DOMString {
// Step 4
let mut buf = "".to_owned();
@@ -746,7 +978,7 @@ impl HTMLFormElement {
self.constructing_entry_list.set(true);
// Step 3-6
- let mut ret = self.get_unclean_dataset(submitter);
+ let mut ret = self.get_unclean_dataset(submitter, encoding);
for datum in &mut ret {
match &*datum.ty {
"file" | "textarea" => (), // TODO
diff --git a/components/script/dom/htmlinputelement.rs b/components/script/dom/htmlinputelement.rs
index 5fdbad5c1bd..9018f05813a 100755
--- a/components/script/dom/htmlinputelement.rs
+++ b/components/script/dom/htmlinputelement.rs
@@ -49,6 +49,7 @@ use crate::textinput::{Direction, SelectionDirection, TextInput, UTF16CodeUnits,
use caseless::compatibility_caseless_match_str;
use dom_struct::dom_struct;
use embedder_traits::FilterPattern;
+use encoding_rs::Encoding;
use html5ever::{LocalName, Prefix};
use msg::constellation_msg::InputMethodType;
use net_traits::blob_url_store::get_blob_origin;
@@ -929,14 +930,18 @@ impl HTMLInputElement {
}
/// <https://html.spec.whatwg.org/multipage/#constructing-the-form-data-set>
- /// Steps range from 3.1 to 3.7 (specific to HTMLInputElement)
- pub fn form_datums(&self, submitter: Option<FormSubmitter>) -> Vec<FormDatum> {
+ /// Steps range from 5.1 to 5.10 (specific to HTMLInputElement)
+ pub fn form_datums(
+ &self,
+ submitter: Option<FormSubmitter>,
+ encoding: Option<&'static Encoding>,
+ ) -> Vec<FormDatum> {
// 3.1: disabled state check is in get_unclean_dataset
- // Step 3.2
+ // Step 5.2
let ty = self.Type();
- // Step 3.4
+ // Step 5.4
let name = self.Name();
let is_submitter = match submitter {
Some(FormSubmitter::InputElement(s)) => self == s,
@@ -944,12 +949,12 @@ impl HTMLInputElement {
};
match self.input_type() {
- // Step 3.1: it's a button but it is not submitter.
+ // Step 5.1: it's a button but it is not submitter.
InputType::Submit | InputType::Button | InputType::Reset if !is_submitter => {
return vec![];
},
- // Step 3.1: it's the "Checkbox" or "Radio Button" and whose checkedness is false.
+ // Step 5.1: it's the "Checkbox" or "Radio Button" and whose checkedness is false.
InputType::Radio | InputType::Checkbox => {
if !self.Checked() || name.is_empty() {
return vec![];
@@ -959,7 +964,7 @@ impl HTMLInputElement {
InputType::File => {
let mut datums = vec![];
- // Step 3.2-3.7
+ // Step 5.2-5.7
let name = self.Name();
match self.GetFiles() {
@@ -988,7 +993,21 @@ impl HTMLInputElement {
InputType::Image => return vec![], // Unimplemented
- // Step 3.1: it's not the "Image Button" and doesn't have a name attribute.
+ // Step 5.10: it's a hidden field named _charset_
+ InputType::Hidden => {
+ if name == "_charset_" {
+ return vec![FormDatum {
+ ty: ty.clone(),
+ name: name,
+ value: FormDatumValue::String(match encoding {
+ None => DOMString::from("UTF-8"),
+ Some(enc) => DOMString::from(enc.name()),
+ }),
+ }];
+ }
+ },
+
+ // Step 5.1: it's not the "Image Button" and doesn't have a name attribute.
_ => {
if name.is_empty() {
return vec![];
@@ -996,7 +1015,7 @@ impl HTMLInputElement {
},
}
- // Step 3.9
+ // Step 5.12
vec![FormDatum {
ty: ty.clone(),
name: name,
@@ -1213,7 +1232,16 @@ impl HTMLInputElement {
value.push_str(sanitized.as_str());
}
},
- _ => (),
+ // The following inputs don't have a value sanitization algorithm.
+ // See https://html.spec.whatwg.org/multipage/#value-sanitization-algorithm
+ InputType::Button |
+ InputType::Checkbox |
+ InputType::File |
+ InputType::Hidden |
+ InputType::Image |
+ InputType::Radio |
+ InputType::Reset |
+ InputType::Submit => (),
}
}
diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs
index 651084cfb84..91acd4b97e7 100644
--- a/components/script/dom/htmlmediaelement.rs
+++ b/components/script/dom/htmlmediaelement.rs
@@ -67,7 +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 embedder_traits::{MediaPositionState, MediaSessionEvent, MediaSessionPlaybackState};
use euclid::default::Size2D;
use headers::{ContentLength, ContentRange, HeaderMapExt};
use html5ever::{LocalName, Prefix};
@@ -1780,6 +1780,15 @@ impl HTMLMediaElement {
.add(self.playback_position.get(), position);
self.playback_position.set(position);
self.time_marches_on();
+ let media_position_state =
+ MediaPositionState::new(self.duration.get(), self.playbackRate.get(), position);
+ debug!(
+ "Sending media session event set position state {:?}",
+ media_position_state
+ );
+ self.send_media_session_event(MediaSessionEvent::SetPositionState(
+ media_position_state,
+ ));
},
PlayerEvent::SeekData(p, ref seek_lock) => {
self.fetch_request(Some(p), Some(seek_lock.clone()));
@@ -1925,6 +1934,18 @@ impl HTMLMediaElement {
media_session.send_event(event);
}
+
+ pub fn set_duration(&self, duration: f64) {
+ self.duration.set(duration);
+ }
+
+ pub fn reset(&self) {
+ if let Some(ref player) = *self.player.borrow() {
+ if let Err(e) = player.lock().unwrap().stop() {
+ eprintln!("Could not stop player {:?}", e);
+ }
+ }
+ }
}
// XXX Placeholder for [https://github.com/servo/servo/issues/22293]
diff --git a/components/script/dom/htmlscriptelement.rs b/components/script/dom/htmlscriptelement.rs
index dfac55a6f66..fdeca285e30 100644
--- a/components/script/dom/htmlscriptelement.rs
+++ b/components/script/dom/htmlscriptelement.rs
@@ -559,6 +559,10 @@ impl HTMLScriptElement {
"{} is a module script. It should be fixed after #23545 landed.",
url.clone()
);
+ self.global().issue_page_warning(&format!(
+ "Module scripts are not supported; {} will not be executed.",
+ url.clone()
+ ));
},
}
} else {
@@ -578,6 +582,9 @@ impl HTMLScriptElement {
"{} is a module script. It should be fixed after #23545 landed.",
base_url.clone()
);
+ self.global().issue_page_warning(
+ "Module scripts are not supported; ignoring inline module script.",
+ );
return;
}
diff --git a/components/script/dom/identityhub.rs b/components/script/dom/identityhub.rs
index 489eaacc78d..64e4cad3867 100644
--- a/components/script/dom/identityhub.rs
+++ b/components/script/dom/identityhub.rs
@@ -2,46 +2,121 @@
* 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};
+use smallvec::SmallVec;
+use webgpu::wgpu::{
+ hub::IdentityManager,
+ id::{AdapterId, BufferId, DeviceId},
+ Backend,
+};
#[derive(Debug)]
pub struct IdentityHub {
- adapters: IdentityManager<AdapterId>,
- devices: IdentityManager<DeviceId>,
+ adapters: IdentityManager,
+ devices: IdentityManager,
+ buffers: IdentityManager,
+ backend: Backend,
}
impl IdentityHub {
fn new(backend: Backend) -> Self {
IdentityHub {
- adapters: IdentityManager::new(backend),
- devices: IdentityManager::new(backend),
+ adapters: IdentityManager::default(),
+ devices: IdentityManager::default(),
+ buffers: IdentityManager::default(),
+ backend,
}
}
+
+ fn create_adapter_id(&mut self) -> AdapterId {
+ self.adapters.alloc(self.backend)
+ }
+
+ fn create_device_id(&mut self) -> DeviceId {
+ self.devices.alloc(self.backend)
+ }
+
+ pub fn create_buffer_id(&mut self) -> BufferId {
+ self.buffers.alloc(self.backend)
+ }
}
#[derive(Debug)]
pub struct Identities {
- surface: IdentityManager<SurfaceId>,
- hub: IdentityHub,
+ surface: IdentityManager,
+ #[cfg(any(target_os = "linux", target_os = "windows"))]
+ vk_hub: IdentityHub,
+ #[cfg(target_os = "windows")]
+ dx12_hub: IdentityHub,
+ #[cfg(target_os = "windows")]
+ dx11_hub: IdentityHub,
+ #[cfg(any(target_os = "ios", target_os = "macos"))]
+ metal_hub: IdentityHub,
+ dummy_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,
+ surface: IdentityManager::default(),
+ #[cfg(any(target_os = "linux", target_os = "windows"))]
+ vk_hub: IdentityHub::new(Backend::Vulkan),
+ #[cfg(target_os = "windows")]
+ dx12_hub: IdentityHub::new(Backend::Dx12),
+ #[cfg(target_os = "windows")]
+ dx11_hub: IdentityHub::new(Backend::Dx11),
+ #[cfg(any(target_os = "ios", target_os = "macos"))]
+ metal_hub: IdentityHub::new(Backend::Metal),
+ dummy_hub: IdentityHub::new(Backend::Empty),
+ }
+ }
+
+ fn hubs(&mut self) -> Vec<&mut IdentityHub> {
+ vec![
+ #[cfg(any(target_os = "linux", target_os = "windows"))]
+ &mut self.vk_hub,
+ #[cfg(target_os = "windows")]
+ &mut self.dx12_hub,
+ #[cfg(target_os = "windows")]
+ &mut self.dx11_hub,
+ #[cfg(any(target_os = "ios", target_os = "macos"))]
+ &mut self.metal_hub,
+ &mut self.dummy_hub,
+ ]
+ }
+
+ pub fn create_device_id(&mut self, backend: Backend) -> DeviceId {
+ match backend {
+ #[cfg(any(target_os = "linux", target_os = "windows"))]
+ Backend::Vulkan => self.vk_hub.create_device_id(),
+ #[cfg(target_os = "windows")]
+ Backend::Dx12 => self.dx12_hub.create_device_id(),
+ #[cfg(target_os = "windows")]
+ Backend::Dx11 => self.dx11_hub.create_device_id(),
+ #[cfg(any(target_os = "ios", target_os = "macos"))]
+ Backend::Metal => self.metal_hub.create_device_id(),
+ _ => self.dummy_hub.create_device_id(),
}
}
- pub fn create_adapter_id(&mut self) -> AdapterId {
- self.hub.adapters.alloc()
+ pub fn create_adapter_ids(&mut self) -> SmallVec<[AdapterId; 4]> {
+ let mut ids = SmallVec::new();
+ for hub in self.hubs() {
+ ids.push(hub.create_adapter_id())
+ }
+ ids
+ }
+
+ pub fn create_buffer_id(&mut self, backend: Backend) -> BufferId {
+ match backend {
+ #[cfg(any(target_os = "linux", target_os = "windows"))]
+ Backend::Vulkan => self.vk_hub.create_buffer_id(),
+ #[cfg(target_os = "windows")]
+ Backend::Dx12 => self.dx12_hub.create_buffer_id(),
+ #[cfg(target_os = "windows")]
+ Backend::Dx11 => self.dx11_hub.create_buffer_id(),
+ #[cfg(any(target_os = "ios", target_os = "macos"))]
+ Backend::Metal => self.metal_hub.create_buffer_id(),
+ _ => self.dummy_hub.create_buffer_id(),
+ }
}
}
diff --git a/components/script/dom/macros.rs b/components/script/dom/macros.rs
index 755624a8855..a1941662963 100644
--- a/components/script/dom/macros.rs
+++ b/components/script/dom/macros.rs
@@ -446,6 +446,7 @@ macro_rules! global_event_handlers(
event_handler!(emptied, GetOnemptied, SetOnemptied);
event_handler!(ended, GetOnended, SetOnended);
error_event_handler!(error, GetOnerror, SetOnerror);
+ event_handler!(formdata, GetOnformdata, SetOnformdata);
event_handler!(input, GetOninput, SetOninput);
event_handler!(invalid, GetOninvalid, SetOninvalid);
event_handler!(keydown, GetOnkeydown, SetOnkeydown);
diff --git a/components/script/dom/mediasession.rs b/components/script/dom/mediasession.rs
index 1523e9a0ae6..8dfc88a1c04 100644
--- a/components/script/dom/mediasession.rs
+++ b/components/script/dom/mediasession.rs
@@ -9,10 +9,13 @@ use crate::dom::bindings::codegen::Bindings::HTMLMediaElementBinding::HTMLMediaE
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::MediaPositionState;
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::error::{Error, Fallible};
+use crate::dom::bindings::num::Finite;
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
use crate::dom::bindings::root::{DomRoot, MutNullableDom};
use crate::dom::bindings::str::DOMString;
@@ -194,6 +197,62 @@ impl MediaSessionMethods for MediaSession {
None => self.action_handlers.borrow_mut().remove(&action.into()),
};
}
+
+ /// https://w3c.github.io/mediasession/#dom-mediasession-setpositionstate
+ fn SetPositionState(&self, state: &MediaPositionState) -> Fallible<()> {
+ // If the state is an empty dictionary then clear the position state.
+ if state.duration.is_none() && state.position.is_none() && state.playbackRate.is_none() {
+ if let Some(media_instance) = self.media_instance.get() {
+ media_instance.reset();
+ }
+ return Ok(());
+ }
+
+ // If the duration is not present or its value is null, throw a TypeError.
+ if state.duration.is_none() {
+ return Err(Error::Type(
+ "duration is not present or its value is null".to_owned(),
+ ));
+ }
+
+ // If the duration is negative, throw a TypeError.
+ if let Some(state_duration) = state.duration {
+ if *state_duration < 0.0 {
+ return Err(Error::Type("duration is negative".to_owned()));
+ }
+ }
+
+ // If the position is negative or greater than duration, throw a TypeError.
+ if let Some(state_position) = state.position {
+ if *state_position < 0.0 {
+ return Err(Error::Type("position is negative".to_owned()));
+ }
+ if let Some(state_duration) = state.duration {
+ if *state_position > *state_duration {
+ return Err(Error::Type("position is greater than duration".to_owned()));
+ }
+ }
+ }
+
+ // If the playbackRate is zero throw a TypeError.
+ if let Some(state_playback_rate) = state.playbackRate {
+ if *state_playback_rate <= 0.0 {
+ return Err(Error::Type("playbackRate is zero".to_owned()));
+ }
+ }
+
+ // Update the position state and last position updated time.
+ if let Some(media_instance) = self.media_instance.get() {
+ media_instance.set_duration(state.duration.map(|v| *v).unwrap());
+ // If the playbackRate is not present or its value is null, set it to 1.0.
+ let _ =
+ media_instance.SetPlaybackRate(state.playbackRate.unwrap_or(Finite::wrap(1.0)))?;
+ // If the position is not present or its value is null, set it to zero.
+ media_instance.SetCurrentTime(state.position.unwrap_or(Finite::wrap(0.0)));
+ }
+
+ Ok(())
+ }
}
impl From<MediaSessionAction> for MediaSessionActionType {
diff --git a/components/script/dom/messageevent.rs b/components/script/dom/messageevent.rs
index 9d9e5f88e35..cc5725ffb6c 100644
--- a/components/script/dom/messageevent.rs
+++ b/components/script/dom/messageevent.rs
@@ -2,6 +2,7 @@
* 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::EventBinding::EventMethods;
use crate::dom::bindings::codegen::Bindings::MessageEventBinding;
use crate::dom::bindings::codegen::Bindings::MessageEventBinding::MessageEventMethods;
@@ -56,10 +57,10 @@ pub struct MessageEvent {
event: Event,
#[ignore_malloc_size_of = "mozjs"]
data: Heap<JSVal>,
- origin: DOMString,
- source: Option<SrcObject>,
- lastEventId: DOMString,
- ports: Vec<DomRoot<MessagePort>>,
+ origin: DomRefCell<DOMString>,
+ source: DomRefCell<Option<SrcObject>>,
+ lastEventId: DomRefCell<DOMString>,
+ ports: DomRefCell<Vec<DomRoot<MessagePort>>>,
}
impl MessageEvent {
@@ -85,10 +86,10 @@ impl MessageEvent {
let ev = Box::new(MessageEvent {
event: Event::new_inherited(),
data: Heap::default(),
- source: source.map(|source| source.into()),
- origin,
- lastEventId,
- ports,
+ source: DomRefCell::new(source.map(|source| source.into())),
+ origin: DomRefCell::new(origin),
+ lastEventId: DomRefCell::new(lastEventId),
+ ports: DomRefCell::new(ports),
});
let ev = reflect_dom_object(ev, global, MessageEventBinding::Wrap);
ev.data.set(data.get());
@@ -187,12 +188,12 @@ impl MessageEventMethods for MessageEvent {
/// <https://html.spec.whatwg.org/multipage/#dom-messageevent-origin>
fn Origin(&self) -> DOMString {
- self.origin.clone()
+ self.origin.borrow().clone()
}
// https://html.spec.whatwg.org/multipage/#dom-messageevent-source
fn GetSource(&self) -> Option<WindowProxyOrMessagePortOrServiceWorker> {
- match &self.source {
+ match &*self.source.borrow() {
Some(SrcObject::WindowProxy(i)) => Some(
WindowProxyOrMessagePortOrServiceWorker::WindowProxy(DomRoot::from_ref(&*i)),
),
@@ -208,7 +209,7 @@ impl MessageEventMethods for MessageEvent {
/// <https://html.spec.whatwg.org/multipage/#dom-messageevent-lasteventid>
fn LastEventId(&self) -> DOMString {
- self.lastEventId.clone()
+ self.lastEventId.borrow().clone()
}
/// <https://dom.spec.whatwg.org/#dom-event-istrusted>
@@ -218,6 +219,28 @@ impl MessageEventMethods for MessageEvent {
/// <https://html.spec.whatwg.org/multipage/#dom-messageevent-ports>
fn Ports(&self, cx: JSContext) -> JSVal {
- message_ports_to_frozen_array(self.ports.as_slice(), cx)
+ message_ports_to_frozen_array(self.ports.borrow().as_slice(), cx)
+ }
+
+ /// <https://html.spec.whatwg.org/multipage/#dom-messageevent-initmessageevent>
+ fn InitMessageEvent(
+ &self,
+ _cx: JSContext,
+ type_: DOMString,
+ bubbles: bool,
+ cancelable: bool,
+ data: HandleValue,
+ origin: DOMString,
+ lastEventId: DOMString,
+ source: Option<WindowProxyOrMessagePortOrServiceWorker>,
+ ports: Vec<DomRoot<MessagePort>>,
+ ) {
+ self.data.set(data.get());
+ *self.origin.borrow_mut() = origin.clone();
+ *self.source.borrow_mut() = source.as_ref().map(|source| source.into());
+ *self.lastEventId.borrow_mut() = lastEventId.clone();
+ *self.ports.borrow_mut() = ports;
+ self.event
+ .init_event(Atom::from(type_), bubbles, cancelable);
}
}
diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs
index d348633df88..b8bdc638c17 100644
--- a/components/script/dom/mod.rs
+++ b/components/script/dom/mod.rs
@@ -317,6 +317,9 @@ pub mod gamepadlist;
pub mod globalscope;
pub mod gpu;
pub mod gpuadapter;
+pub mod gpubuffer;
+pub mod gpubufferusage;
+pub mod gpudevice;
pub mod hashchangeevent;
pub mod headers;
pub mod history;
diff --git a/components/script/dom/navigator.rs b/components/script/dom/navigator.rs
index 9121f7ef54d..03c6b27d156 100644
--- a/components/script/dom/navigator.rs
+++ b/components/script/dom/navigator.rs
@@ -24,9 +24,13 @@ use crate::dom::serviceworkercontainer::ServiceWorkerContainer;
use crate::dom::window::Window;
use crate::dom::xr::XR;
use dom_struct::dom_struct;
+use smallvec::SmallVec;
use std::cell::RefCell;
use std::rc::Rc;
-use webgpu::wgpu::AdapterId;
+use webgpu::wgpu::{
+ id::{AdapterId, BufferId, DeviceId},
+ Backend,
+};
#[dom_struct]
pub struct Navigator {
@@ -73,8 +77,16 @@ impl Navigator {
}
impl Navigator {
- pub fn create_adapter_id(&self) -> AdapterId {
- self.gpu_id_hub.borrow_mut().create_adapter_id()
+ pub fn create_adapter_ids(&self) -> SmallVec<[AdapterId; 4]> {
+ self.gpu_id_hub.borrow_mut().create_adapter_ids()
+ }
+
+ pub fn create_device_id(&self, backend: Backend) -> DeviceId {
+ self.gpu_id_hub.borrow_mut().create_device_id(backend)
+ }
+
+ pub fn create_buffer_id(&self, backend: Backend) -> BufferId {
+ self.gpu_id_hub.borrow_mut().create_buffer_id(backend)
}
}
diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs
index 4885d87c64b..8ee51283146 100644
--- a/components/script/dom/node.rs
+++ b/components/script/dom/node.rs
@@ -2296,6 +2296,11 @@ impl NodeMethods for Node {
USVString(String::from(self.owner_doc().base_url().as_str()))
}
+ // https://dom.spec.whatwg.org/#dom-node-isconnected
+ fn IsConnected(&self) -> bool {
+ return self.is_connected();
+ }
+
// https://dom.spec.whatwg.org/#dom-node-ownerdocument
fn GetOwnerDocument(&self) -> Option<DomRoot<Document>> {
match self.type_id() {
diff --git a/components/script/dom/offscreencanvas.rs b/components/script/dom/offscreencanvas.rs
index 2186ba54bc8..6d7cafed6f6 100644
--- a/components/script/dom/offscreencanvas.rs
+++ b/components/script/dom/offscreencanvas.rs
@@ -16,9 +16,12 @@ use crate::dom::globalscope::GlobalScope;
use crate::dom::htmlcanvaselement::HTMLCanvasElement;
use crate::dom::offscreencanvasrenderingcontext2d::OffscreenCanvasRenderingContext2D;
use crate::script_runtime::JSContext;
+use canvas_traits::canvas::{CanvasMsg, FromScriptMsg};
use dom_struct::dom_struct;
use euclid::default::Size2D;
+use ipc_channel::ipc::IpcSharedMemory;
use js::rust::HandleValue;
+use profile_traits::ipc;
use ref_filter_map;
use std::cell::Cell;
use std::cell::Ref;
@@ -34,22 +37,22 @@ pub enum OffscreenCanvasContext {
#[dom_struct]
pub struct OffscreenCanvas {
eventtarget: EventTarget,
- height: Cell<u64>,
width: Cell<u64>,
+ height: Cell<u64>,
context: DomRefCell<Option<OffscreenCanvasContext>>,
placeholder: Option<Dom<HTMLCanvasElement>>,
}
impl OffscreenCanvas {
pub fn new_inherited(
- height: u64,
width: u64,
+ height: u64,
placeholder: Option<&HTMLCanvasElement>,
) -> OffscreenCanvas {
OffscreenCanvas {
eventtarget: EventTarget::new_inherited(),
- height: Cell::new(height),
width: Cell::new(width),
+ height: Cell::new(height),
context: DomRefCell::new(None),
placeholder: placeholder.map(Dom::from_ref),
}
@@ -57,12 +60,12 @@ impl OffscreenCanvas {
pub fn new(
global: &GlobalScope,
- height: u64,
width: u64,
+ height: u64,
placeholder: Option<&HTMLCanvasElement>,
) -> DomRoot<OffscreenCanvas> {
reflect_dom_object(
- Box::new(OffscreenCanvas::new_inherited(height, width, placeholder)),
+ Box::new(OffscreenCanvas::new_inherited(width, height, placeholder)),
global,
OffscreenCanvasWrap,
)
@@ -70,10 +73,10 @@ impl OffscreenCanvas {
pub fn Constructor(
global: &GlobalScope,
- height: u64,
width: u64,
+ height: u64,
) -> Fallible<DomRoot<OffscreenCanvas>> {
- let offscreencanvas = OffscreenCanvas::new(global, height, width, None);
+ let offscreencanvas = OffscreenCanvas::new(global, width, height, None);
Ok(offscreencanvas)
}
@@ -81,10 +84,44 @@ impl OffscreenCanvas {
Size2D::new(self.Width(), self.Height())
}
+ pub fn origin_is_clean(&self) -> bool {
+ match *self.context.borrow() {
+ Some(OffscreenCanvasContext::OffscreenContext2d(ref context)) => {
+ context.origin_is_clean()
+ },
+ _ => true,
+ }
+ }
+
pub fn context(&self) -> Option<Ref<OffscreenCanvasContext>> {
ref_filter_map::ref_filter_map(self.context.borrow(), |ctx| ctx.as_ref())
}
+ pub fn fetch_all_data(&self) -> Option<(Option<IpcSharedMemory>, Size2D<u32>)> {
+ let size = self.get_size();
+
+ if size.width == 0 || size.height == 0 {
+ return None;
+ }
+
+ let data = match self.context.borrow().as_ref() {
+ Some(&OffscreenCanvasContext::OffscreenContext2d(ref context)) => {
+ let (sender, receiver) =
+ ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
+ let msg = CanvasMsg::FromScript(
+ FromScriptMsg::SendPixels(sender),
+ context.get_canvas_id(),
+ );
+ context.get_ipc_renderer().send(msg).unwrap();
+
+ Some(receiver.recv().unwrap())
+ },
+ None => None,
+ };
+
+ Some((data, size.to_u32()))
+ }
+
#[allow(unsafe_code)]
fn get_or_init_2d_context(&self) -> Option<DomRoot<OffscreenCanvasRenderingContext2D>> {
if let Some(ctx) = self.context() {
diff --git a/components/script/dom/offscreencanvasrenderingcontext2d.rs b/components/script/dom/offscreencanvasrenderingcontext2d.rs
index 077752d9d6e..277b5925f27 100644
--- a/components/script/dom/offscreencanvasrenderingcontext2d.rs
+++ b/components/script/dom/offscreencanvasrenderingcontext2d.rs
@@ -24,8 +24,10 @@ use crate::dom::htmlcanvaselement::HTMLCanvasElement;
use crate::dom::imagedata::ImageData;
use crate::dom::offscreencanvas::OffscreenCanvas;
use crate::dom::textmetrics::TextMetrics;
+use canvas_traits::canvas::{Canvas2dMsg, CanvasId, CanvasMsg};
use dom_struct::dom_struct;
use euclid::default::Size2D;
+use ipc_channel::ipc::IpcSender;
#[dom_struct]
pub struct OffscreenCanvasRenderingContext2D {
@@ -72,6 +74,22 @@ impl OffscreenCanvasRenderingContext2D {
pub fn set_canvas_bitmap_dimensions(&self, size: Size2D<u64>) {
self.canvas_state.borrow().set_bitmap_dimensions(size);
}
+
+ pub fn send_canvas_2d_msg(&self, msg: Canvas2dMsg) {
+ self.canvas_state.borrow().send_canvas_2d_msg(msg)
+ }
+
+ pub fn origin_is_clean(&self) -> bool {
+ self.canvas_state.borrow().origin_is_clean()
+ }
+
+ pub fn get_canvas_id(&self) -> CanvasId {
+ self.canvas_state.borrow().get_canvas_id()
+ }
+
+ pub fn get_ipc_renderer(&self) -> IpcSender<CanvasMsg> {
+ self.canvas_state.borrow().get_ipc_renderer().clone()
+ }
}
impl OffscreenCanvasRenderingContext2DMethods for OffscreenCanvasRenderingContext2D {
diff --git a/components/script/dom/performance.rs b/components/script/dom/performance.rs
index 6c418b44316..b1f72f405f2 100644
--- a/components/script/dom/performance.rs
+++ b/components/script/dom/performance.rs
@@ -96,10 +96,10 @@ impl PerformanceEntryList {
entry_type: Option<DOMString>,
) {
self.entries.retain(|e| {
- name.as_ref().map_or(true, |name_| *e.name() == *name_) &&
+ name.as_ref().map_or(true, |name_| *e.name() != *name_) &&
entry_type
.as_ref()
- .map_or(true, |type_| *e.entry_type() == *type_)
+ .map_or(true, |type_| *e.entry_type() != *type_)
});
}
@@ -233,10 +233,10 @@ impl Performance {
/// <https://w3c.github.io/performance-timeline/#queue-a-performanceentry>
/// Also this algorithm has been extented according to :
/// <https://w3c.github.io/resource-timing/#sec-extensions-performance-interface>
- pub fn queue_entry(&self, entry: &PerformanceEntry, add_to_performance_entries_buffer: bool) {
+ pub fn queue_entry(&self, entry: &PerformanceEntry) -> Option<usize> {
// https://w3c.github.io/performance-timeline/#dfn-determine-eligibility-for-adding-a-performance-entry
if entry.entry_type() == "resource" && !self.should_queue_resource_entry(entry) {
- return;
+ return None;
}
// Steps 1-3.
@@ -253,19 +253,18 @@ impl Performance {
}
// Step 4.
- // If the "add to performance entry buffer flag" is set, add the
- // new entry to the buffer.
- if add_to_performance_entries_buffer {
- self.buffer
- .borrow_mut()
- .entries
- .push(DomRoot::from_ref(entry));
- }
+ //add the new entry to the buffer.
+ self.buffer
+ .borrow_mut()
+ .entries
+ .push(DomRoot::from_ref(entry));
+
+ let entry_last_index = self.buffer.borrow_mut().entries.len() - 1;
// Step 5.
// If there is already a queued notification task, we just bail out.
if self.pending_notification_observers_task.get() {
- return;
+ return None;
}
// Step 6.
@@ -273,6 +272,8 @@ impl Performance {
self.pending_notification_observers_task.set(true);
let task_source = self.global().performance_timeline_task_source();
task_source.queue_notification(&self.global());
+
+ Some(entry_last_index)
}
/// Observers notifications task.
@@ -321,7 +322,7 @@ impl Performance {
.borrow_mut()
.pop_front();
if let Some(ref entry) = entry {
- self.queue_entry(entry, true);
+ self.queue_entry(entry);
} else {
break;
}
@@ -370,6 +371,12 @@ impl Performance {
.push_back(DomRoot::from_ref(entry));
false
}
+
+ pub fn update_entry(&self, index: usize, entry: &PerformanceEntry) {
+ if let Some(e) = self.buffer.borrow_mut().entries.get_mut(index) {
+ *e = DomRoot::from_ref(entry);
+ }
+ }
}
impl PerformanceMethods for Performance {
@@ -438,10 +445,7 @@ impl PerformanceMethods for Performance {
// Steps 2 to 6.
let entry = PerformanceMark::new(&global, mark_name, self.now(), 0.);
// Steps 7 and 8.
- self.queue_entry(
- &entry.upcast::<PerformanceEntry>(),
- true, /* buffer performance entry */
- );
+ self.queue_entry(&entry.upcast::<PerformanceEntry>());
// Step 9.
Ok(())
@@ -488,10 +492,7 @@ impl PerformanceMethods for Performance {
);
// Step 9 and 10.
- self.queue_entry(
- &entry.upcast::<PerformanceEntry>(),
- true, /* buffer performance entry */
- );
+ self.queue_entry(&entry.upcast::<PerformanceEntry>());
// Step 11.
Ok(())
diff --git a/components/script/dom/progressevent.rs b/components/script/dom/progressevent.rs
index a1272baf8e3..c5f33dfe305 100644
--- a/components/script/dom/progressevent.rs
+++ b/components/script/dom/progressevent.rs
@@ -32,13 +32,6 @@ impl ProgressEvent {
total: total,
}
}
- pub fn new_uninitialized(global: &GlobalScope) -> DomRoot<ProgressEvent> {
- reflect_dom_object(
- Box::new(ProgressEvent::new_inherited(false, 0, 0)),
- global,
- ProgressEventBinding::Wrap,
- )
- }
pub fn new(
global: &GlobalScope,
type_: Atom,
diff --git a/components/script/dom/request.rs b/components/script/dom/request.rs
index d22d4680355..03e5dee683d 100644
--- a/components/script/dom/request.rs
+++ b/components/script/dom/request.rs
@@ -90,59 +90,63 @@ impl Request {
// Step 4
let base_url = global.api_base_url();
+ // Step 5 TODO: "Let signal be null."
+
match input {
- // Step 5
+ // Step 6
RequestInfo::USVString(USVString(ref usv_string)) => {
- // Step 5.1
+ // Step 6.1
let parsed_url = base_url.join(&usv_string);
- // Step 5.2
+ // Step 6.2
if parsed_url.is_err() {
return Err(Error::Type("Url could not be parsed".to_string()));
}
- // Step 5.3
+ // Step 6.3
let url = parsed_url.unwrap();
if includes_credentials(&url) {
return Err(Error::Type("Url includes credentials".to_string()));
}
- // Step 5.4
+ // Step 6.4
temporary_request = net_request_from_global(global, url);
- // Step 5.5
+ // Step 6.5
fallback_mode = Some(NetTraitsRequestMode::CorsMode);
- // Step 5.6
+ // Step 6.6
fallback_credentials = Some(NetTraitsRequestCredentials::CredentialsSameOrigin);
},
- // Step 6
+ // Step 7
RequestInfo::Request(ref input_request) => {
- // Step 6.1
+ // This looks like Step 38
+ // TODO do this in the right place to not mask other errors
if request_is_disturbed(input_request) || request_is_locked(input_request) {
return Err(Error::Type("Input is disturbed or locked".to_string()));
}
- // Step 6.2
+ // Step 7.1
temporary_request = input_request.request.borrow().clone();
+ // Step 7.2 TODO: "Set signal to input's signal."
},
}
- // Step 7
+ // Step 8
// TODO: `entry settings object` is not implemented yet.
let origin = base_url.origin();
- // Step 8
+ // Step 9
let mut window = Window::Client;
- // Step 9
+ // Step 10
// TODO: `environment settings object` is not implemented in Servo yet.
- // Step 10
+ // Step 11
if !init.window.handle().is_null_or_undefined() {
return Err(Error::Type("Window is present and is not null".to_string()));
}
- // Step 11
+ // Step 12
if !init.window.handle().is_undefined() {
window = Window::NoWindow;
}
- // Step 12
+ // Step 13
let mut request: NetTraitsRequest;
request = net_request_from_global(global, temporary_request.current_url());
request.method = temporary_request.method;
@@ -159,7 +163,7 @@ impl Request {
request.redirect_mode = temporary_request.redirect_mode;
request.integrity_metadata = temporary_request.integrity_metadata;
- // Step 13
+ // Step 14
if init.body.is_some() ||
init.cache.is_some() ||
init.credentials.is_some() ||
@@ -172,31 +176,33 @@ impl Request {
init.referrerPolicy.is_some() ||
!init.window.handle().is_undefined()
{
- // Step 13.1
+ // Step 14.1
if request.mode == NetTraitsRequestMode::Navigate {
request.mode = NetTraitsRequestMode::SameOrigin;
}
- // Step 13.2
+ // Step 14.2 TODO: "Unset request's reload-navigation flag."
+ // Step 14.3 TODO: "Unset request's history-navigation flag."
+ // Step 14.4
request.referrer = NetTraitsRequestReferrer::Client;
- // Step 13.3
+ // Step 14.5
request.referrer_policy = None;
}
- // Step 14
+ // Step 15
if let Some(init_referrer) = init.referrer.as_ref() {
- // Step 14.1
+ // Step 15.1
let ref referrer = init_referrer.0;
- // Step 14.2
+ // Step 15.2
if referrer.is_empty() {
request.referrer = NetTraitsRequestReferrer::NoReferrer;
} else {
- // Step 14.3
+ // Step 15.3.1
let parsed_referrer = base_url.join(referrer);
- // Step 14.4
+ // Step 15.3.2
if parsed_referrer.is_err() {
return Err(Error::Type("Failed to parse referrer url".to_string()));
}
- // Step 14.5
+ // Step 15.3.3
if let Ok(parsed_referrer) = parsed_referrer {
if (parsed_referrer.cannot_be_a_base() &&
parsed_referrer.scheme() == "about" &&
@@ -205,55 +211,55 @@ impl Request {
{
request.referrer = NetTraitsRequestReferrer::Client;
} else {
- // Step 14.6
+ // Step 15.3.4
request.referrer = NetTraitsRequestReferrer::ReferrerUrl(parsed_referrer);
}
}
}
}
- // Step 15
+ // Step 16
if let Some(init_referrerpolicy) = init.referrerPolicy.as_ref() {
let init_referrer_policy = init_referrerpolicy.clone().into();
request.referrer_policy = Some(init_referrer_policy);
}
- // Step 16
+ // Step 17
let mode = init
.mode
.as_ref()
.map(|m| m.clone().into())
.or(fallback_mode);
- // Step 17
+ // Step 18
if let Some(NetTraitsRequestMode::Navigate) = mode {
return Err(Error::Type("Request mode is Navigate".to_string()));
}
- // Step 18
+ // Step 19
if let Some(m) = mode {
request.mode = m;
}
- // Step 19
+ // Step 20
let credentials = init
.credentials
.as_ref()
.map(|m| m.clone().into())
.or(fallback_credentials);
- // Step 20
+ // Step 21
if let Some(c) = credentials {
request.credentials_mode = c;
}
- // Step 21
+ // Step 22
if let Some(init_cache) = init.cache.as_ref() {
let cache = init_cache.clone().into();
request.cache_mode = cache;
}
- // Step 22
+ // Step 23
if request.cache_mode == NetTraitsRequestCache::OnlyIfCached {
if request.mode != NetTraitsRequestMode::SameOrigin {
return Err(Error::Type(
@@ -262,45 +268,55 @@ impl Request {
}
}
- // Step 23
+ // Step 24
if let Some(init_redirect) = init.redirect.as_ref() {
let redirect = init_redirect.clone().into();
request.redirect_mode = redirect;
}
- // Step 24
+ // Step 25
if let Some(init_integrity) = init.integrity.as_ref() {
let integrity = init_integrity.clone().to_string();
request.integrity_metadata = integrity;
}
- // Step 25
+ // Step 26 TODO: "If init["keepalive"] exists..."
+
+ // Step 27.1
if let Some(init_method) = init.method.as_ref() {
- // Step 25.1
+ // Step 27.2
if !is_method(&init_method) {
return Err(Error::Type("Method is not a method".to_string()));
}
if is_forbidden_method(&init_method) {
return Err(Error::Type("Method is forbidden".to_string()));
}
- // Step 25.2
+ // Step 27.3
let method = match init_method.as_str() {
Some(s) => normalize_method(s)
.map_err(|e| Error::Type(format!("Method is not valid: {:?}", e)))?,
None => return Err(Error::Type("Method is not a valid UTF8".to_string())),
};
- // Step 25.3
+ // Step 27.4
request.method = method;
}
- // Step 26
+ // Step 28 TODO: "If init["signal"] exists..."
+
+ // Step 29
let r = Request::from_net_request(global, request);
+
+ // Step 30 TODO: "If signal is not null..."
+
+ // Step 31
+ // "or_init" looks unclear here
r.headers.or_init(|| Headers::for_request(&r.global()));
- // Step 27
+ // Step 32 - but spec says this should only be when non-empty init?
+ // Step 32.1
let mut headers_copy = r.Headers();
- // Step 28
+ // Step 32.2
if let Some(possible_header) = init.headers.as_ref() {
match possible_header {
&HeadersInit::Headers(ref init_headers) => {
@@ -319,7 +335,7 @@ impl Request {
}
}
- // Step 29
+ // Step 32.3
// We cannot empty `r.Headers().header_list` because
// we would undo the Step 27 above. One alternative is to set
// `headers_copy` as a deep copy of `r.Headers()`. However,
@@ -328,21 +344,21 @@ impl Request {
// mutable reference, we cannot mutate `r.Headers()` to be the
// deep copied headers in Step 27.
- // Step 30
+ // Step 32.4
if r.request.borrow().mode == NetTraitsRequestMode::NoCors {
let borrowed_request = r.request.borrow();
- // Step 30.1
+ // Step 32.4.1
if !is_cors_safelisted_method(&borrowed_request.method) {
return Err(Error::Type(
"The mode is 'no-cors' but the method is not a cors-safelisted method"
.to_string(),
));
}
- // Step 30.2
+ // Step 32.4.2
r.Headers().set_guard(Guard::RequestNoCors);
}
- // Step 31
+ // Step 32.5
match init.headers {
None => {
// This is equivalent to the specification's concept of
@@ -360,10 +376,11 @@ impl Request {
_ => {},
}
+ // Step 32.5-6 depending on how we got here
// Copy the headers list onto the headers of net_traits::Request
r.request.borrow_mut().headers = r.Headers().get_headers_list();
- // Step 32
+ // Step 33
let mut input_body = if let RequestInfo::Request(ref input_request) = input {
let input_request_request = input_request.request.borrow();
input_request_request.body.clone()
@@ -371,7 +388,7 @@ impl Request {
None
};
- // Step 33
+ // Step 34
if let Some(init_body_option) = init.body.as_ref() {
if init_body_option.is_some() || input_body.is_some() {
let req = r.request.borrow();
@@ -392,14 +409,16 @@ impl Request {
}
}
- // Step 34
+ // Step 35-36
if let Some(Some(ref init_body)) = init.body {
- // Step 34.2
+ // Step 36.2 TODO "If init["keepalive"] exists and is true..."
+
+ // Step 36.3
let extracted_body_tmp = init_body.extract();
input_body = Some(extracted_body_tmp.0);
let content_type = extracted_body_tmp.1;
- // Step 34.3
+ // Step 36.4
if let Some(contents) = content_type {
if !r
.Headers()
@@ -414,17 +433,23 @@ impl Request {
}
}
- // Step 35
+ // Step 37 "TODO if body is non-null and body's source is null..."
+ // This looks like where we need to set the use-preflight flag
+ // if the request has a body and nothing else has set the flag.
+
+ // Step 38 is done earlier
+
+ // Step 39
+ // TODO: `ReadableStream` object is not implemented in Servo yet.
+
+ // Step 40
r.request.borrow_mut().body = input_body;
- // Step 36
+ // Step 41
let extracted_mime_type = r.Headers().extract_mime_type();
*r.mime_type.borrow_mut() = extracted_mime_type;
- // Step 37
- // TODO: `ReadableStream` object is not implemented in Servo yet.
-
- // Step 38
+ // Step 42
Ok(r)
}
diff --git a/components/script/dom/response.rs b/components/script/dom/response.rs
index 184e5ff8888..0e756513b9a 100644
--- a/components/script/dom/response.rs
+++ b/components/script/dom/response.rs
@@ -19,6 +19,7 @@ use crate::dom::headers::{is_obs_text, is_vchar};
use crate::dom::headers::{Guard, Headers};
use crate::dom::promise::Promise;
use crate::dom::xmlhttprequest::Extractable;
+use crate::script_runtime::StreamConsumer;
use dom_struct::dom_struct;
use http::header::HeaderMap as HyperHeaders;
use hyper::StatusCode;
@@ -48,6 +49,8 @@ pub struct Response {
body: DomRefCell<NetTraitsResponseBody>,
#[ignore_malloc_size_of = "Rc"]
body_promise: DomRefCell<Option<(Rc<Promise>, BodyType)>>,
+ #[ignore_malloc_size_of = "StreamConsumer"]
+ stream_consumer: DomRefCell<Option<StreamConsumer>>,
}
impl Response {
@@ -64,6 +67,7 @@ impl Response {
url_list: DomRefCell::new(vec![]),
body: DomRefCell::new(NetTraitsResponseBody::Empty),
body_promise: DomRefCell::new(None),
+ stream_consumer: DomRefCell::new(None),
}
}
@@ -441,11 +445,24 @@ impl Response {
}
}
+ pub fn set_stream_consumer(&self, sc: Option<StreamConsumer>) {
+ *self.stream_consumer.borrow_mut() = sc;
+ }
+
+ pub fn stream_chunk(&self, stream: &[u8]) {
+ if let Some(stream_consumer) = self.stream_consumer.borrow_mut().as_ref() {
+ stream_consumer.consume_chunk(stream);
+ }
+ }
+
#[allow(unrooted_must_root)]
pub fn finish(&self, body: Vec<u8>) {
*self.body.borrow_mut() = NetTraitsResponseBody::Done(body);
if let Some((p, body_type)) = self.body_promise.borrow_mut().take() {
consume_body_with_promise(self, body_type, &p);
}
+ if let Some(stream_consumer) = self.stream_consumer.borrow_mut().take() {
+ stream_consumer.stream_end();
+ }
}
}
diff --git a/components/script/dom/serviceworkerglobalscope.rs b/components/script/dom/serviceworkerglobalscope.rs
index 2a3f4d7041a..ada042c17ac 100644
--- a/components/script/dom/serviceworkerglobalscope.rs
+++ b/components/script/dom/serviceworkerglobalscope.rs
@@ -289,7 +289,7 @@ impl ServiceWorkerGlobalScope {
.credentials_mode(CredentialsMode::Include)
.parser_metadata(ParserMetadata::NotParserInserted)
.use_url_credentials(true)
- .pipeline_id(pipeline_id)
+ .pipeline_id(Some(pipeline_id))
.referrer(referrer)
.referrer_policy(referrer_policy)
.origin(origin);
@@ -371,9 +371,6 @@ impl ServiceWorkerGlobalScope {
DevtoolScriptControlMsg::EvaluateJS(_pipe_id, string, sender) => {
devtools::handle_evaluate_js(self.upcast(), string, sender)
},
- DevtoolScriptControlMsg::GetCachedMessages(pipe_id, message_types, sender) => {
- devtools::handle_get_cached_messages(pipe_id, message_types, sender)
- },
DevtoolScriptControlMsg::WantsLiveNotifications(_pipe_id, bool_val) => {
devtools::handle_wants_live_notifications(self.upcast(), bool_val)
},
diff --git a/components/script/dom/serviceworkerregistration.rs b/components/script/dom/serviceworkerregistration.rs
index a2165a82115..647fb9518c5 100644
--- a/components/script/dom/serviceworkerregistration.rs
+++ b/components/script/dom/serviceworkerregistration.rs
@@ -16,10 +16,12 @@ use crate::dom::globalscope::GlobalScope;
use crate::dom::navigationpreloadmanager::NavigationPreloadManager;
use crate::dom::serviceworker::ServiceWorker;
use crate::dom::workerglobalscope::prepare_workerscope_init;
+use devtools_traits::WorkerId;
use dom_struct::dom_struct;
use script_traits::{ScopeThings, WorkerScriptLoadOrigin};
use servo_url::ServoUrl;
use std::cell::Cell;
+use uuid::Uuid;
#[dom_struct]
pub struct ServiceWorkerRegistration {
@@ -108,10 +110,10 @@ impl ServiceWorkerRegistration {
let worker_load_origin = WorkerScriptLoadOrigin {
referrer_url: None,
referrer_policy: None,
- pipeline_id: Some(global.pipeline_id()),
+ pipeline_id: global.pipeline_id(),
};
- let worker_id = global.get_next_worker_id();
+ let worker_id = WorkerId(Uuid::new_v4());
let devtools_chan = global.devtools_chan().cloned();
let init = prepare_workerscope_init(&global, None);
ScopeThings {
diff --git a/components/script/dom/servoparser/mod.rs b/components/script/dom/servoparser/mod.rs
index 004daeed9be..b968aa47274 100644
--- a/components/script/dom/servoparser/mod.rs
+++ b/components/script/dom/servoparser/mod.rs
@@ -689,6 +689,8 @@ pub struct ParserContext {
url: ServoUrl,
/// timing data for this resource
resource_timing: ResourceFetchTiming,
+ /// pushed entry index
+ pushed_entry_index: Option<usize>,
}
impl ParserContext {
@@ -699,6 +701,7 @@ impl ParserContext {
id: id,
url: url,
resource_timing: ResourceFetchTiming::new(ResourceTimingType::Navigation),
+ pushed_entry_index: None,
}
}
}
@@ -774,6 +777,8 @@ impl FetchResponseListener for ParserContext {
self.parser = Some(Trusted::new(&*parser));
+ self.submit_resource_timing();
+
match content_type {
Some(ref mime) if mime.type_() == mime::IMAGE => {
self.is_synthesized_document = true;
@@ -881,8 +886,16 @@ impl FetchResponseListener for ParserContext {
parser.parse_sync();
}
- //TODO only submit if this is the current document resource
- self.submit_resource_timing();
+ //TODO only update if this is the current document resource
+ if let Some(pushed_index) = self.pushed_entry_index {
+ let document = &parser.document;
+ let performance_entry =
+ PerformanceNavigationTiming::new(&document.global(), 0, 0, &document);
+ document
+ .global()
+ .performance()
+ .update_entry(pushed_index, performance_entry.upcast::<PerformanceEntry>());
+ }
}
fn resource_timing_mut(&mut self) -> &mut ResourceFetchTiming {
@@ -908,10 +921,10 @@ impl FetchResponseListener for ParserContext {
//TODO nav_start and nav_start_precise
let performance_entry =
PerformanceNavigationTiming::new(&document.global(), 0, 0, &document);
- document
+ self.pushed_entry_index = document
.global()
.performance()
- .queue_entry(performance_entry.upcast::<PerformanceEntry>(), true);
+ .queue_entry(performance_entry.upcast::<PerformanceEntry>());
}
}
diff --git a/components/script/dom/webglcontextevent.rs b/components/script/dom/webglcontextevent.rs
index 5bc153ddccd..e4b0efe0360 100644
--- a/components/script/dom/webglcontextevent.rs
+++ b/components/script/dom/webglcontextevent.rs
@@ -42,18 +42,6 @@ impl WebGLContextEvent {
}
}
- pub fn new_uninitialized(window: &Window) -> DomRoot<WebGLContextEvent> {
- // according to https://www.khronos.org/registry/webgl/specs/1.0/#5.15 this is
- // additional information or the empty string if no additional information is
- // available.
- let status_message = DOMString::new();
- reflect_dom_object(
- Box::new(WebGLContextEvent::new_inherited(status_message)),
- window,
- WebGLContextEventBinding::Wrap,
- )
- }
-
pub fn new(
window: &Window,
type_: Atom,
diff --git a/components/script/dom/webidls/CanvasRenderingContext2D.webidl b/components/script/dom/webidls/CanvasRenderingContext2D.webidl
index 743661cdf53..52e532e3a8b 100644
--- a/components/script/dom/webidls/CanvasRenderingContext2D.webidl
+++ b/components/script/dom/webidls/CanvasRenderingContext2D.webidl
@@ -12,7 +12,7 @@ typedef (HTMLOrSVGImageElement or
/*HTMLVideoElement or*/
HTMLCanvasElement or
/*ImageBitmap or*/
- /*OffscreenCanvas or*/
+ OffscreenCanvas or
/*CSSImageValue*/ CSSStyleValue) CanvasImageSource;
enum CanvasFillRule { "nonzero", "evenodd" };
diff --git a/components/script/dom/webidls/DOMException.webidl b/components/script/dom/webidls/DOMException.webidl
index 8475238cb9b..d61d30151fa 100644
--- a/components/script/dom/webidls/DOMException.webidl
+++ b/components/script/dom/webidls/DOMException.webidl
@@ -47,6 +47,4 @@ interface DOMException {
// A custom message set by the thrower.
readonly attribute DOMString message;
-
- stringifier;
};
diff --git a/components/script/dom/webidls/DOMTokenList.webidl b/components/script/dom/webidls/DOMTokenList.webidl
index ed4a541f730..b2d604ee2a9 100644
--- a/components/script/dom/webidls/DOMTokenList.webidl
+++ b/components/script/dom/webidls/DOMTokenList.webidl
@@ -19,7 +19,7 @@ interface DOMTokenList {
[CEReactions, Throws]
boolean toggle(DOMString token, optional boolean force);
[CEReactions, Throws]
- void replace(DOMString token, DOMString newToken);
+ boolean replace(DOMString token, DOMString newToken);
[CEReactions, Pure]
stringifier attribute DOMString value;
diff --git a/components/script/dom/webidls/EventHandler.webidl b/components/script/dom/webidls/EventHandler.webidl
index b5566db7153..53df17fe7e0 100644
--- a/components/script/dom/webidls/EventHandler.webidl
+++ b/components/script/dom/webidls/EventHandler.webidl
@@ -51,6 +51,7 @@ interface mixin GlobalEventHandlers {
attribute EventHandler onended;
attribute OnErrorEventHandler onerror;
attribute EventHandler onfocus;
+ attribute EventHandler onformdata;
attribute EventHandler oninput;
attribute EventHandler oninvalid;
attribute EventHandler onkeydown;
diff --git a/components/script/dom/webidls/FakeXRDevice.webidl b/components/script/dom/webidls/FakeXRDevice.webidl
index bb008bdc73f..4dde2678435 100644
--- a/components/script/dom/webidls/FakeXRDevice.webidl
+++ b/components/script/dom/webidls/FakeXRDevice.webidl
@@ -13,8 +13,11 @@ interface FakeXRDevice {
// // behaves as if device was disconnected
// Promise<void> disconnect();
- // Sets the origin of the viewer
[Throws] void setViewerOrigin(FakeXRRigidTransformInit origin, optional boolean emulatedPosition = false);
+ void clearViewerOrigin();
+
+ [Throws] void setFloorOrigin(FakeXRRigidTransformInit origin);
+ void clearFloorOrigin();
// // Simulates devices focusing and blurring sessions.
// void simulateVisibilityChange(XRVisibilityState);
@@ -40,6 +43,8 @@ dictionary FakeXRViewInit {
required FakeXRRigidTransformInit viewOffset;
// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-getviewport
required FakeXRDeviceResolution resolution;
+
+ FakeXRFieldOfViewInit fieldOfView;
};
// https://immersive-web.github.io/webxr/#xrviewport
@@ -56,3 +61,10 @@ dictionary FakeXRRigidTransformInit {
required sequence<float> position;
required sequence<float> orientation;
};
+
+dictionary FakeXRFieldOfViewInit {
+ required float upDegrees;
+ required float downDegrees;
+ required float leftDegrees;
+ required float rightDegrees;
+};
diff --git a/components/script/dom/webidls/GPUAdapter.webidl b/components/script/dom/webidls/GPUAdapter.webidl
index 0c2118a5f56..cc664fabffa 100644
--- a/components/script/dom/webidls/GPUAdapter.webidl
+++ b/components/script/dom/webidls/GPUAdapter.webidl
@@ -10,5 +10,25 @@ interface GPUAdapter {
//readonly attribute GPULimits limits; Don’t expose higher limits for now.
// May reject with DOMException // TODO: DOMException("OperationError")?
- // Promise<GPUDevice> requestDevice(optional GPUDeviceDescriptor descriptor = {});
+ Promise<GPUDevice> requestDevice(optional GPUDeviceDescriptor descriptor = {});
+};
+
+dictionary GPUDeviceDescriptor : GPUObjectDescriptorBase {
+ GPUExtensions extensions = {};
+ GPULimits limits = {};
+};
+
+dictionary GPUExtensions {
+ boolean anisotropicFiltering = false;
+};
+
+dictionary GPULimits {
+ unsigned long maxBindGroups = 4;
+ unsigned long maxDynamicUniformBuffersPerPipelineLayout = 8;
+ unsigned long maxDynamicStorageBuffersPerPipelineLayout = 4;
+ unsigned long maxSampledTexturesPerShaderStage = 16;
+ unsigned long maxSamplersPerShaderStage = 16;
+ unsigned long maxStorageBuffersPerShaderStage = 4;
+ unsigned long maxStorageTexturesPerShaderStage = 4;
+ unsigned long maxUniformBuffersPerShaderStage = 12;
};
diff --git a/components/script/dom/webidls/GPUBuffer.webidl b/components/script/dom/webidls/GPUBuffer.webidl
new file mode 100644
index 00000000000..0b327bdcbd2
--- /dev/null
+++ b/components/script/dom/webidls/GPUBuffer.webidl
@@ -0,0 +1,25 @@
+/* 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/#gpubuffer
+[Exposed=(Window, DedicatedWorker), Serializable, Pref="dom.webgpu.enabled"]
+interface GPUBuffer {
+ // Promise<ArrayBuffer> mapReadAsync();
+ // Promise<ArrayBuffer> mapWriteAsync();
+ void unmap();
+
+ void destroy();
+};
+GPUBuffer includes GPUObjectBase;
+
+dictionary GPUBufferDescriptor : GPUObjectDescriptorBase {
+ required GPUBufferSize size;
+ required GPUBufferUsageFlags usage;
+};
+
+typedef unsigned long long GPUBufferSize;
+
+typedef unsigned long GPUBufferUsageFlags;
+
+typedef sequence<any> GPUMappedBuffer;
diff --git a/components/script/dom/webidls/GPUBufferUsage.webidl b/components/script/dom/webidls/GPUBufferUsage.webidl
new file mode 100644
index 00000000000..549f6652d1f
--- /dev/null
+++ b/components/script/dom/webidls/GPUBufferUsage.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/. */
+
+// https://gpuweb.github.io/gpuweb/#buffer-usage
+[Exposed=(Window, DedicatedWorker), Pref="dom.webgpu.enabled"]
+interface GPUBufferUsage {
+ const GPUBufferUsageFlags MAP_READ = 0x0001;
+ const GPUBufferUsageFlags MAP_WRITE = 0x0002;
+ const GPUBufferUsageFlags COPY_SRC = 0x0004;
+ const GPUBufferUsageFlags COPY_DST = 0x0008;
+ const GPUBufferUsageFlags INDEX = 0x0010;
+ const GPUBufferUsageFlags VERTEX = 0x0020;
+ const GPUBufferUsageFlags UNIFORM = 0x0040;
+ const GPUBufferUsageFlags STORAGE = 0x0080;
+ const GPUBufferUsageFlags INDIRECT = 0x0100;
+};
diff --git a/components/script/dom/webidls/GPUDevice.webidl b/components/script/dom/webidls/GPUDevice.webidl
new file mode 100644
index 00000000000..965f7e1b7d5
--- /dev/null
+++ b/components/script/dom/webidls/GPUDevice.webidl
@@ -0,0 +1,31 @@
+/* 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/#gpudevice
+[Exposed=(Window, DedicatedWorker)/*, Serializable */, Pref="dom.webgpu.enabled"]
+interface GPUDevice : EventTarget {
+ readonly attribute GPUAdapter adapter;
+ readonly attribute object extensions;
+ readonly attribute object limits;
+
+ GPUBuffer createBuffer(GPUBufferDescriptor descriptor);
+ GPUMappedBuffer createBufferMapped(GPUBufferDescriptor descriptor);
+ /*Promise<GPUMappedBuffer> createBufferMappedAsync(GPUBufferDescriptor descriptor);
+ GPUTexture createTexture(GPUTextureDescriptor descriptor);
+ GPUSampler createSampler(optional GPUSamplerDescriptor descriptor = {});
+
+ GPUBindGroupLayout createBindGroupLayout(GPUBindGroupLayoutDescriptor descriptor);
+ GPUPipelineLayout createPipelineLayout(GPUPipelineLayoutDescriptor descriptor);
+ GPUBindGroup createBindGroup(GPUBindGroupDescriptor descriptor);
+
+ GPUShaderModule createShaderModule(GPUShaderModuleDescriptor descriptor);
+ GPUComputePipeline createComputePipeline(GPUComputePipelineDescriptor descriptor);
+ GPURenderPipeline createRenderPipeline(GPURenderPipelineDescriptor descriptor);
+
+ GPUCommandEncoder createCommandEncoder(optional GPUCommandEncoderDescriptor descriptor = {});
+ GPURenderBundleEncoder createRenderBundleEncoder(GPURenderBundleEncoderDescriptor descriptor);
+
+ GPUQueue getQueue();*/
+};
+GPUDevice includes GPUObjectBase;
diff --git a/components/script/dom/webidls/GPUObjectBase.webidl b/components/script/dom/webidls/GPUObjectBase.webidl
new file mode 100644
index 00000000000..c9a35992fb8
--- /dev/null
+++ b/components/script/dom/webidls/GPUObjectBase.webidl
@@ -0,0 +1,13 @@
+/* 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/#gpuobjectbase
+[Exposed=(Window)]
+interface mixin GPUObjectBase {
+ attribute DOMString? label;
+};
+
+dictionary GPUObjectDescriptorBase {
+ DOMString? label;
+};
diff --git a/components/script/dom/webidls/HTMLFormElement.webidl b/components/script/dom/webidls/HTMLFormElement.webidl
index f48726c343a..13ffbf4dfe8 100644
--- a/components/script/dom/webidls/HTMLFormElement.webidl
+++ b/components/script/dom/webidls/HTMLFormElement.webidl
@@ -29,7 +29,7 @@ interface HTMLFormElement : HTMLElement {
[SameObject] readonly attribute HTMLFormControlsCollection elements;
readonly attribute unsigned long length;
getter Element? (unsigned long index);
- //getter (RadioNodeList or Element) (DOMString name);
+ getter (RadioNodeList or Element) (DOMString name);
void submit();
[CEReactions]
diff --git a/components/script/dom/webidls/MediaSession.webidl b/components/script/dom/webidls/MediaSession.webidl
index 12b3fe062ba..2680ea0c40b 100644
--- a/components/script/dom/webidls/MediaSession.webidl
+++ b/components/script/dom/webidls/MediaSession.webidl
@@ -42,6 +42,12 @@ dictionary MediaSessionSeekToActionDetails : MediaSessionActionDetails {
boolean? fastSeek;
};
+dictionary MediaPositionState {
+ double duration;
+ double playbackRate;
+ double position;
+};
+
callback MediaSessionActionHandler = void(/*MediaSessionActionDetails details*/);
[Exposed=Window]
@@ -52,6 +58,5 @@ interface MediaSession {
void setActionHandler(MediaSessionAction action, MediaSessionActionHandler? handler);
- //void setPositionState(optional MediaPositionState? state);
+ [Throws] void setPositionState(optional MediaPositionState state = {});
};
-
diff --git a/components/script/dom/webidls/MessageEvent.webidl b/components/script/dom/webidls/MessageEvent.webidl
index 1d4699cbe3c..b37d725b793 100644
--- a/components/script/dom/webidls/MessageEvent.webidl
+++ b/components/script/dom/webidls/MessageEvent.webidl
@@ -11,6 +11,17 @@ interface MessageEvent : Event {
readonly attribute DOMString lastEventId;
readonly attribute MessageEventSource? source;
readonly attribute /*FrozenArray<MessagePort>*/any ports;
+
+ void initMessageEvent(
+ DOMString type,
+ optional boolean bubbles = false,
+ optional boolean cancelable = false,
+ optional any data = null,
+ optional DOMString origin = "",
+ optional DOMString lastEventId = "",
+ optional MessageEventSource? source = null,
+ optional sequence<MessagePort> ports = []
+ );
};
dictionary MessageEventInit : EventInit {
diff --git a/components/script/dom/webidls/Node.webidl b/components/script/dom/webidls/Node.webidl
index 6879518b017..c8a71dbebb7 100644
--- a/components/script/dom/webidls/Node.webidl
+++ b/components/script/dom/webidls/Node.webidl
@@ -29,6 +29,9 @@ interface Node : EventTarget {
readonly attribute USVString baseURI;
[Pure]
+ readonly attribute boolean isConnected;
+
+ [Pure]
readonly attribute Document? ownerDocument;
[Pure]
diff --git a/components/script/dom/webidls/Performance.webidl b/components/script/dom/webidls/Performance.webidl
index 0e2f7a960d5..5db6551ff96 100644
--- a/components/script/dom/webidls/Performance.webidl
+++ b/components/script/dom/webidls/Performance.webidl
@@ -34,23 +34,20 @@ partial interface Performance {
[Throws]
void measure(DOMString measureName, optional DOMString startMark, optional DOMString endMark);
void clearMeasures(optional DOMString measureName);
-
-
};
+
//https://w3c.github.io/resource-timing/#sec-extensions-performance-interface
partial interface Performance {
void clearResourceTimings ();
void setResourceTimingBufferSize (unsigned long maxSize);
attribute EventHandler onresourcetimingbufferfull;
};
-// FIXME(avada): this should be deprecated, but is currently included for web compat
-// https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/NavigationTiming/Overview.html#performance-timing-attribute
-[Exposed=(Window)]
-partial interface Performance {
- PerformanceNavigationTiming timing();
-};
+
// https://w3c.github.io/navigation-timing/#extensions-to-the-performance-interface
+[Exposed=Window]
partial interface Performance {
- [SameObject, Exposed=Window]
+ [SameObject]
+ readonly attribute PerformanceNavigationTiming timing;
+ [SameObject]
readonly attribute PerformanceNavigation navigation;
};
diff --git a/components/script/dom/webidls/XRRenderState.webidl b/components/script/dom/webidls/XRRenderState.webidl
index 01d7fd39191..e361ced6597 100644
--- a/components/script/dom/webidls/XRRenderState.webidl
+++ b/components/script/dom/webidls/XRRenderState.webidl
@@ -7,11 +7,13 @@
dictionary XRRenderStateInit {
double depthNear;
double depthFar;
+ double inlineVerticalFieldOfView;
XRWebGLLayer baseLayer;
};
[SecureContext, Exposed=Window, Pref="dom.webxr.enabled"] interface XRRenderState {
readonly attribute double depthNear;
readonly attribute double depthFar;
+ readonly attribute double? inlineVerticalFieldOfView;
readonly attribute XRWebGLLayer? baseLayer;
};
diff --git a/components/script/dom/webidls/XRWebGLLayer.webidl b/components/script/dom/webidls/XRWebGLLayer.webidl
index 40091ccc73e..dd2420dd13a 100644
--- a/components/script/dom/webidls/XRWebGLLayer.webidl
+++ b/components/script/dom/webidls/XRWebGLLayer.webidl
@@ -30,7 +30,7 @@ interface XRWebGLLayer {
readonly attribute boolean stencil;
readonly attribute boolean alpha;
- readonly attribute WebGLFramebuffer framebuffer;
+ readonly attribute WebGLFramebuffer? framebuffer;
readonly attribute unsigned long framebufferWidth;
readonly attribute unsigned long framebufferHeight;
diff --git a/components/script/dom/worker.rs b/components/script/dom/worker.rs
index f08bdcab79e..2d126933849 100644
--- a/components/script/dom/worker.rs
+++ b/components/script/dom/worker.rs
@@ -26,7 +26,7 @@ use crate::dom::workerglobalscope::prepare_workerscope_init;
use crate::script_runtime::JSContext;
use crate::task::TaskOnce;
use crossbeam_channel::{unbounded, Sender};
-use devtools_traits::{DevtoolsPageInfo, ScriptToDevtoolsControlMsg};
+use devtools_traits::{DevtoolsPageInfo, ScriptToDevtoolsControlMsg, WorkerId};
use dom_struct::dom_struct;
use ipc_channel::ipc;
use js::jsapi::{Heap, JSObject, JS_RequestInterruptCallback};
@@ -36,6 +36,7 @@ use script_traits::{StructuredSerializedData, WorkerScriptLoadOrigin};
use std::cell::Cell;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
+use uuid::Uuid;
pub type TrustedWorkerAddress = Trusted<Worker>;
@@ -96,11 +97,11 @@ impl Worker {
let worker_load_origin = WorkerScriptLoadOrigin {
referrer_url: None,
referrer_policy: None,
- pipeline_id: Some(global.pipeline_id()),
+ pipeline_id: global.pipeline_id(),
};
let (devtools_sender, devtools_receiver) = ipc::channel().unwrap();
- let worker_id = global.get_next_worker_id();
+ let worker_id = WorkerId(Uuid::new_v4());
if let Some(ref chan) = global.devtools_chan() {
let pipeline_id = global.pipeline_id();
let title = format!("Worker for {}", worker_url);
diff --git a/components/script/dom/workerglobalscope.rs b/components/script/dom/workerglobalscope.rs
index e943b6b0ef4..8624208423e 100644
--- a/components/script/dom/workerglobalscope.rs
+++ b/components/script/dom/workerglobalscope.rs
@@ -58,6 +58,7 @@ use std::rc::Rc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use time::precise_time_ns;
+use uuid::Uuid;
pub fn prepare_workerscope_init(
global: &GlobalScope,
@@ -71,7 +72,7 @@ pub fn prepare_workerscope_init(
from_devtools_sender: devtools_sender,
script_to_constellation_chan: global.script_to_constellation_chan().clone(),
scheduler_chan: global.scheduler_chan().clone(),
- worker_id: global.get_next_worker_id(),
+ worker_id: WorkerId(Uuid::new_v4()),
pipeline_id: global.pipeline_id(),
origin: global.origin().immutable().clone(),
is_headless: global.is_headless(),
diff --git a/components/script/dom/xr.rs b/components/script/dom/xr.rs
index a916d7a8267..72cc573d645 100644
--- a/components/script/dom/xr.rs
+++ b/components/script/dom/xr.rs
@@ -42,6 +42,7 @@ pub struct XR {
gamepads: DomRefCell<Vec<Dom<Gamepad>>>,
pending_immersive_session: Cell<bool>,
active_immersive_session: MutNullableDom<XRSession>,
+ active_inline_sessions: DomRefCell<Vec<Dom<XRSession>>>,
test: MutNullableDom<XRTest>,
}
@@ -53,6 +54,7 @@ impl XR {
gamepads: DomRefCell::new(Vec::new()),
pending_immersive_session: Cell::new(false),
active_immersive_session: Default::default(),
+ active_inline_sessions: DomRefCell::new(Vec::new()),
test: Default::default(),
}
}
@@ -86,7 +88,9 @@ impl XR {
self.active_immersive_session.set(None);
}
}
- // XXXManishearth when we support inline sessions we should remove them too
+ self.active_inline_sessions
+ .borrow_mut()
+ .retain(|sess| Dom::from_ref(&**sess) != Dom::from_ref(session));
}
}
@@ -158,17 +162,19 @@ impl XRMethods for XR {
) -> Rc<Promise> {
let promise = Promise::new_in_current_compartment(&self.global(), comp);
- if !ScriptThread::is_user_interacting() {
- promise.reject_error(Error::Security);
- return promise;
- }
+ if mode != XRSessionMode::Inline {
+ if !ScriptThread::is_user_interacting() {
+ promise.reject_error(Error::Security);
+ return promise;
+ }
- if self.pending_or_active_session() {
- promise.reject_error(Error::InvalidState);
- return promise;
- }
+ if self.pending_or_active_session() {
+ promise.reject_error(Error::InvalidState);
+ return promise;
+ }
- self.set_pending();
+ self.set_pending();
+ }
let promise = Promise::new_in_current_compartment(&self.global(), comp);
let mut trusted = Some(TrustedPromise::new(promise.clone()));
@@ -193,7 +199,7 @@ impl XRMethods for XR {
};
let _ = task_source.queue_with_canceller(
task!(request_session: move || {
- this.root().session_obtained(message, trusted.root());
+ this.root().session_obtained(message, trusted.root(), mode);
}),
&canceller,
);
@@ -211,7 +217,12 @@ impl XRMethods for XR {
}
impl XR {
- fn session_obtained(&self, response: Result<Session, XRError>, promise: Rc<Promise>) {
+ fn session_obtained(
+ &self,
+ response: Result<Session, XRError>,
+ promise: Rc<Promise>,
+ mode: XRSessionMode,
+ ) {
let session = match response {
Ok(session) => session,
Err(_) => {
@@ -220,8 +231,14 @@ impl XR {
},
};
- let session = XRSession::new(&self.global(), session);
- self.set_active_immersive_session(&session);
+ let session = XRSession::new(&self.global(), session, mode);
+ if mode == XRSessionMode::Inline {
+ self.active_inline_sessions
+ .borrow_mut()
+ .push(Dom::from_ref(&*session));
+ } else {
+ self.set_active_immersive_session(&session);
+ }
promise.resolve_native(&session);
}
diff --git a/components/script/dom/xrframe.rs b/components/script/dom/xrframe.rs
index 6c67d896f81..9a752abf759 100644
--- a/components/script/dom/xrframe.rs
+++ b/components/script/dom/xrframe.rs
@@ -77,7 +77,11 @@ impl XRFrameMethods for XRFrame {
return Err(Error::InvalidState);
}
- let pose = reference.get_viewer_pose(&self.data);
+ let pose = if let Some(pose) = reference.get_viewer_pose(&self.data) {
+ pose
+ } else {
+ return Ok(None);
+ };
Ok(Some(XRViewerPose::new(&self.global(), &self.session, pose)))
}
diff --git a/components/script/dom/xrreferencespace.rs b/components/script/dom/xrreferencespace.rs
index 35e106d1125..1116407cf46 100644
--- a/components/script/dom/xrreferencespace.rs
+++ b/components/script/dom/xrreferencespace.rs
@@ -10,10 +10,10 @@ use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::globalscope::GlobalScope;
use crate::dom::xrrigidtransform::XRRigidTransform;
-use crate::dom::xrsession::{cast_transform, ApiPose, ApiRigidTransform, ApiViewerPose, XRSession};
+use crate::dom::xrsession::{cast_transform, ApiPose, ApiViewerPose, XRSession};
use crate::dom::xrspace::XRSpace;
use dom_struct::dom_struct;
-use euclid::{RigidTransform3D, Vector3D};
+use euclid::RigidTransform3D;
use webxr_api::Frame;
#[dom_struct]
@@ -80,8 +80,8 @@ impl XRReferenceSpace {
///
/// This is equivalent to `get_pose(self).inverse() * get_pose(viewerSpace)` (in column vector notation),
/// however we specialize it to be efficient
- pub fn get_viewer_pose(&self, base_pose: &Frame) -> ApiViewerPose {
- let pose = self.get_unoffset_viewer_pose(base_pose);
+ pub fn get_viewer_pose(&self, base_pose: &Frame) -> Option<ApiViewerPose> {
+ let pose = self.get_unoffset_viewer_pose(base_pose)?;
// in column-vector notation,
// get_viewer_pose(space) = get_pose(space).inverse() * get_pose(viewer_space)
// = (get_unoffset_pose(space) * offset).inverse() * get_pose(viewer_space)
@@ -89,14 +89,13 @@ impl XRReferenceSpace {
// = offset.inverse() * get_unoffset_viewer_pose(space)
let offset = self.offset.transform();
let inverse = offset.inverse();
- inverse.pre_transform(&pose)
+ Some(inverse.pre_transform(&pose))
}
/// Gets pose of the viewer with respect to this space
///
/// Does not apply originOffset, use get_viewer_pose instead if you need it
- pub fn get_unoffset_viewer_pose(&self, base_pose: &Frame) -> ApiViewerPose {
- let viewer_pose: ApiViewerPose = cast_transform(base_pose.transform);
+ pub fn get_unoffset_viewer_pose(&self, base_pose: &Frame) -> Option<ApiViewerPose> {
// all math is in column-vector notation
// we use the following equation to verify correctness here:
// get_viewer_pose(space) = get_pose(space).inverse() * get_pose(viewer_space)
@@ -105,25 +104,27 @@ impl XRReferenceSpace {
// get_viewer_pose(eye_level) = get_pose(eye_level).inverse() * get_pose(viewer_space)
// = I * viewer_pose
// = viewer_pose
+ let viewer_pose: ApiViewerPose = cast_transform(base_pose.transform?);
// we get viewer poses in eye-level space by default
- viewer_pose
+ Some(viewer_pose)
},
XRReferenceSpaceType::Local_floor => {
- // XXXManishearth support getting floor info from stage parameters
-
// get_viewer_pose(floor_level) = get_pose(floor_level).inverse() * get_pose(viewer_space)
- // = Translate(-2).inverse() * viewer_pose
- // = Translate(2) * viewer_pose
+ // = floor_to_native.inverse() * viewer_pose
+ // = native_to_floor * viewer_pose
+ let viewer_pose = base_pose.transform?;
+ let native_to_floor = self
+ .upcast::<XRSpace>()
+ .session()
+ .with_session(|s| s.floor_transform())?;
- // assume approximate user height of 2 meters
- let floor_to_eye: ApiRigidTransform = Vector3D::new(0., 2., 0.).into();
- floor_to_eye.pre_transform(&viewer_pose)
+ Some(cast_transform(native_to_floor.pre_transform(&viewer_pose)))
},
XRReferenceSpaceType::Viewer => {
// This reference space follows the viewer around, so the viewer is
// always at an identity transform with respect to it
- RigidTransform3D::identity()
+ Some(RigidTransform3D::identity())
},
_ => unimplemented!(),
}
@@ -134,34 +135,34 @@ impl XRReferenceSpace {
/// The reference origin used is common between all
/// get_pose calls for spaces from the same device, so this can be used to compare
/// with other spaces
- pub fn get_pose(&self, base_pose: &Frame) -> ApiPose {
- let pose = self.get_unoffset_pose(base_pose);
+ pub fn get_pose(&self, base_pose: &Frame) -> Option<ApiPose> {
+ let pose = self.get_unoffset_pose(base_pose)?;
let offset = self.offset.transform();
// pose is a transform from the unoffset space to native space,
// offset is a transform from offset space to unoffset space,
// we want a transform from unoffset space to native space,
// which is pose * offset in column vector notation
- pose.pre_transform(&offset)
+ Some(pose.pre_transform(&offset))
}
/// Gets pose represented by this space
///
/// Does not apply originOffset, use get_viewer_pose instead if you need it
- pub fn get_unoffset_pose(&self, base_pose: &Frame) -> ApiPose {
+ pub fn get_unoffset_pose(&self, base_pose: &Frame) -> Option<ApiPose> {
match self.ty {
XRReferenceSpaceType::Local => {
// The eye-level pose is basically whatever the headset pose was at t=0, which
// for most devices is (0, 0, 0)
- RigidTransform3D::identity()
+ Some(RigidTransform3D::identity())
},
XRReferenceSpaceType::Local_floor => {
- // XXXManishearth support getting floor info from stage parameters
-
- // Assume approximate height of 2m
- // the floor-level space is 2m below the eye-level space, which is (0, 0, 0)
- Vector3D::new(0., -2., 0.).into()
+ let native_to_floor = self
+ .upcast::<XRSpace>()
+ .session()
+ .with_session(|s| s.floor_transform())?;
+ Some(cast_transform(native_to_floor.inverse()))
},
- XRReferenceSpaceType::Viewer => cast_transform(base_pose.transform),
+ XRReferenceSpaceType::Viewer => base_pose.transform.map(cast_transform),
_ => unimplemented!(),
}
}
diff --git a/components/script/dom/xrrenderstate.rs b/components/script/dom/xrrenderstate.rs
index 2aba4e46493..bebcfd7de61 100644
--- a/components/script/dom/xrrenderstate.rs
+++ b/components/script/dom/xrrenderstate.rs
@@ -17,6 +17,7 @@ pub struct XRRenderState {
reflector_: Reflector,
depth_near: Cell<f64>,
depth_far: Cell<f64>,
+ inline_vertical_fov: Cell<Option<f64>>,
layer: MutNullableDom<XRWebGLLayer>,
}
@@ -24,12 +25,14 @@ impl XRRenderState {
pub fn new_inherited(
depth_near: f64,
depth_far: f64,
+ inline_vertical_fov: Option<f64>,
layer: Option<&XRWebGLLayer>,
) -> XRRenderState {
XRRenderState {
reflector_: Reflector::new(),
depth_near: Cell::new(depth_near),
depth_far: Cell::new(depth_far),
+ inline_vertical_fov: Cell::new(inline_vertical_fov),
layer: MutNullableDom::new(layer),
}
}
@@ -38,10 +41,16 @@ impl XRRenderState {
global: &GlobalScope,
depth_near: f64,
depth_far: f64,
+ inline_vertical_fov: Option<f64>,
layer: Option<&XRWebGLLayer>,
) -> DomRoot<XRRenderState> {
reflect_dom_object(
- Box::new(XRRenderState::new_inherited(depth_near, depth_far, layer)),
+ Box::new(XRRenderState::new_inherited(
+ depth_near,
+ depth_far,
+ inline_vertical_fov,
+ layer,
+ )),
global,
XRRenderStateBinding::Wrap,
)
@@ -52,6 +61,7 @@ impl XRRenderState {
&self.global(),
self.depth_near.get(),
self.depth_far.get(),
+ self.inline_vertical_fov.get(),
self.layer.get().as_ref().map(|x| &**x),
)
}
@@ -62,6 +72,10 @@ impl XRRenderState {
pub fn set_depth_far(&self, depth: f64) {
self.depth_far.set(depth)
}
+ pub fn set_inline_vertical_fov(&self, fov: f64) {
+ debug_assert!(self.inline_vertical_fov.get().is_some());
+ self.inline_vertical_fov.set(Some(fov))
+ }
pub fn set_layer(&self, layer: Option<&XRWebGLLayer>) {
self.layer.set(layer)
}
@@ -78,6 +92,11 @@ impl XRRenderStateMethods for XRRenderState {
Finite::wrap(self.depth_far.get())
}
+ /// https://immersive-web.github.io/webxr/#dom-xrrenderstate-inlineverticalfieldofview
+ fn GetInlineVerticalFieldOfView(&self) -> Option<Finite<f64>> {
+ self.inline_vertical_fov.get().map(Finite::wrap)
+ }
+
/// https://immersive-web.github.io/webxr/#dom-xrrenderstate-baselayer
fn GetBaseLayer(&self) -> Option<DomRoot<XRWebGLLayer>> {
self.layer.get()
diff --git a/components/script/dom/xrsession.rs b/components/script/dom/xrsession.rs
index 438705853f6..6e076b6daba 100644
--- a/components/script/dom/xrsession.rs
+++ b/components/script/dom/xrsession.rs
@@ -8,6 +8,7 @@ use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::NavigatorBinding::NavigatorBinding::NavigatorMethods;
use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextMethods;
use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods;
+use crate::dom::bindings::codegen::Bindings::XRBinding::XRSessionMode;
use crate::dom::bindings::codegen::Bindings::XRReferenceSpaceBinding::XRReferenceSpaceType;
use crate::dom::bindings::codegen::Bindings::XRRenderStateBinding::XRRenderStateInit;
use crate::dom::bindings::codegen::Bindings::XRRenderStateBinding::XRRenderStateMethods;
@@ -39,16 +40,18 @@ use crate::dom::xrspace::XRSpace;
use crate::dom::xrwebgllayer::XRWebGLLayer;
use crate::task_source::TaskSource;
use dom_struct::dom_struct;
-use euclid::RigidTransform3D;
+use euclid::{Rect, RigidTransform3D, Transform3D};
use ipc_channel::ipc::IpcSender;
use ipc_channel::router::ROUTER;
+use metrics::ToMs;
use profile_traits::ipc;
use std::cell::Cell;
+use std::f64::consts::{FRAC_PI_2, PI};
use std::mem;
use std::rc::Rc;
use webxr_api::{
- self, EnvironmentBlendMode, Event as XREvent, Frame, SelectEvent, SelectKind, Session,
- Visibility,
+ self, util, Display, EnvironmentBlendMode, Event as XREvent, Frame, SelectEvent, SelectKind,
+ Session, View, Viewer, Visibility,
};
#[dom_struct]
@@ -56,6 +59,7 @@ pub struct XRSession {
eventtarget: EventTarget,
base_layer: MutNullableDom<XRWebGLLayer>,
blend_mode: XREnvironmentBlendMode,
+ mode: XRSessionMode,
visibility_state: Cell<XRVisibilityState>,
viewer_space: MutNullableDom<XRSpace>,
#[ignore_malloc_size_of = "defined in webxr"]
@@ -63,12 +67,14 @@ pub struct XRSession {
frame_requested: Cell<bool>,
pending_render_state: MutNullableDom<XRRenderState>,
active_render_state: MutDom<XRRenderState>,
+ /// Cached projection matrix for inline sessions
+ inline_projection_matrix: DomRefCell<Transform3D<f32, Viewer, Display>>,
next_raf_id: Cell<i32>,
#[ignore_malloc_size_of = "closures are hard"]
raf_callback_list: DomRefCell<Vec<(i32, Option<Rc<XRFrameRequestCallback>>)>>,
#[ignore_malloc_size_of = "defined in ipc-channel"]
- raf_sender: DomRefCell<Option<IpcSender<(f64, Frame)>>>,
+ raf_sender: DomRefCell<Option<IpcSender<Frame>>>,
input_sources: Dom<XRInputSourceArray>,
// Any promises from calling end()
#[ignore_malloc_size_of = "promises are hard"]
@@ -85,17 +91,20 @@ impl XRSession {
session: Session,
render_state: &XRRenderState,
input_sources: &XRInputSourceArray,
+ mode: XRSessionMode,
) -> XRSession {
XRSession {
eventtarget: EventTarget::new_inherited(),
base_layer: Default::default(),
blend_mode: session.environment_blend_mode().into(),
+ mode,
visibility_state: Cell::new(XRVisibilityState::Visible),
viewer_space: Default::default(),
session: DomRefCell::new(session),
frame_requested: Cell::new(false),
pending_render_state: MutNullableDom::new(None),
active_render_state: MutDom::new(render_state),
+ inline_projection_matrix: Default::default(),
next_raf_id: Cell::new(0),
raf_callback_list: DomRefCell::new(vec![]),
@@ -107,14 +116,20 @@ impl XRSession {
}
}
- pub fn new(global: &GlobalScope, session: Session) -> DomRoot<XRSession> {
- let render_state = XRRenderState::new(global, 0.1, 1000.0, None);
+ pub fn new(global: &GlobalScope, session: Session, mode: XRSessionMode) -> DomRoot<XRSession> {
+ let ivfov = if mode == XRSessionMode::Inline {
+ Some(FRAC_PI_2)
+ } else {
+ None
+ };
+ let render_state = XRRenderState::new(global, 0.1, 1000.0, ivfov, None);
let input_sources = XRInputSourceArray::new(global);
let ret = reflect_dom_object(
Box::new(XRSession::new_inherited(
session,
&render_state,
&input_sources,
+ mode,
)),
global,
XRSessionBinding::Wrap,
@@ -134,6 +149,10 @@ impl XRSession {
self.ended.get()
}
+ pub fn is_immersive(&self) -> bool {
+ self.mode != XRSessionMode::Inline
+ }
+
fn setup_raf_loop(&self) {
assert!(
self.raf_sender.borrow().is_none(),
@@ -287,7 +306,7 @@ impl XRSession {
}
/// https://immersive-web.github.io/webxr/#xr-animation-frame
- fn raf_callback(&self, (time, mut frame): (f64, Frame)) {
+ fn raf_callback(&self, mut frame: Frame) {
debug!("WebXR RAF callback");
// Step 1
@@ -298,9 +317,12 @@ impl XRSession {
self.active_render_state.set(&pending);
// Step 6-7: XXXManishearth handle inlineVerticalFieldOfView
- // XXXManishearth handle inline sessions and composition disabled flag
- let swap_chain_id = pending.GetBaseLayer().map(|layer| layer.swap_chain_id());
- self.session.borrow_mut().set_swap_chain(swap_chain_id);
+ if self.is_immersive() {
+ let swap_chain_id = pending.GetBaseLayer().map(|layer| layer.swap_chain_id());
+ self.session.borrow_mut().set_swap_chain(swap_chain_id);
+ } else {
+ self.update_inline_projection_matrix()
+ }
}
for event in frame.events.drain(..) {
@@ -317,6 +339,8 @@ impl XRSession {
// Step 4-5
let mut callbacks = mem::replace(&mut *self.raf_callback_list.borrow_mut(), vec![]);
+ let start = self.global().as_window().get_navigation_start();
+ let time = (frame.time_ns - start).to_ms();
let frame = XRFrame::new(&self.global(), self, frame);
// Step 6,7
@@ -333,8 +357,10 @@ impl XRSession {
self.outside_raf.set(true);
frame.set_active(false);
- base_layer.swap_buffers();
- self.session.borrow_mut().render_animation_frame();
+ if self.is_immersive() {
+ base_layer.swap_buffers();
+ self.session.borrow_mut().render_animation_frame();
+ }
self.request_new_xr_frame();
// If the canvas element is attached to the DOM, it is now dirty,
@@ -345,6 +371,47 @@ impl XRSession {
.upcast::<Node>()
.dirty(NodeDamage::OtherNodeDamage);
}
+
+ fn update_inline_projection_matrix(&self) {
+ debug_assert!(!self.is_immersive());
+ let render_state = self.active_render_state.get();
+ let size = if let Some(base) = render_state.GetBaseLayer() {
+ base.size()
+ } else {
+ return;
+ };
+ let mut clip_planes = util::ClipPlanes::default();
+ let near = *render_state.DepthNear() as f32;
+ let far = *render_state.DepthFar() as f32;
+ clip_planes.update(near, far);
+ let top = *render_state
+ .GetInlineVerticalFieldOfView()
+ .expect("IVFOV should be non null for inline sessions") /
+ 2.;
+ let top = near * top.tan() as f32;
+ let bottom = top;
+ let left = top * size.width as f32 / size.height as f32;
+ let right = left;
+ let matrix = util::frustum_to_projection_matrix(left, right, top, bottom, clip_planes);
+ *self.inline_projection_matrix.borrow_mut() = matrix;
+ }
+
+ /// Constructs a View suitable for inline sessions using the inlineVerticalFieldOfView and canvas size
+ pub fn inline_view(&self) -> View<Viewer> {
+ debug_assert!(!self.is_immersive());
+ let size = self
+ .active_render_state
+ .get()
+ .GetBaseLayer()
+ .expect("Must never construct views when base layer is not set")
+ .size();
+ View {
+ // Inline views have no offset
+ transform: RigidTransform3D::identity(),
+ projection: *self.inline_projection_matrix.borrow(),
+ viewport: Rect::from_size(size.to_i32()),
+ }
+ }
}
impl XRSessionMethods for XRSession {
@@ -394,19 +461,43 @@ impl XRSessionMethods for XRSession {
}
}
- // XXXManishearth step 4:
- // If newState’s inlineVerticalFieldOfView is set and session is an
- // immersive session, throw an InvalidStateError and abort these steps.
+ // Step 4:
+ if init.inlineVerticalFieldOfView.is_some() && self.is_immersive() {
+ return Err(Error::InvalidState);
+ }
let pending = self
.pending_render_state
.or_init(|| self.active_render_state.get().clone_object());
if let Some(near) = init.depthNear {
- pending.set_depth_near(*near);
+ let mut near = *near;
+ // Step 8 from #apply-the-pending-render-state
+ // this may need to be changed if backends wish to impose
+ // further constraints
+ if near < 0. {
+ near = 0.;
+ }
+ pending.set_depth_near(near);
}
if let Some(far) = init.depthFar {
+ // Step 9 from #apply-the-pending-render-state
+ // this may need to be changed if backends wish to impose
+ // further constraints
+ // currently the maximum is infinity, so we do nothing
pending.set_depth_far(*far);
}
+ if let Some(fov) = init.inlineVerticalFieldOfView {
+ let mut fov = *fov;
+ // Step 10 from #apply-the-pending-render-state
+ // this may need to be changed if backends wish to impose
+ // further constraints
+ if fov < 0. {
+ fov = 0.0001;
+ } else if fov > PI {
+ fov = PI - 0.0001;
+ }
+ pending.set_inline_vertical_fov(fov);
+ }
if let Some(ref layer) = init.baseLayer {
pending.set_layer(Some(&layer))
}
@@ -416,7 +507,6 @@ impl XRSessionMethods for XRSession {
.borrow_mut()
.update_clip_planes(*pending.DepthNear() as f32, *pending.DepthFar() as f32);
}
- // XXXManishearth handle inlineVerticalFieldOfView
Ok(())
}
@@ -481,6 +571,19 @@ impl XRSessionMethods for XRSession {
fn End(&self) -> Rc<Promise> {
let global = self.global();
let p = Promise::new(&global);
+ if self.ended.get() && self.end_promises.borrow().is_empty() {
+ // If the session has completely ended and all end promises have been resolved,
+ // don't queue up more end promises
+ //
+ // We need to check for end_promises being empty because `ended` is set
+ // before everything has been completely shut down, and we do not want to
+ // prematurely resolve the promise then
+ //
+ // However, if end_promises is empty, then all end() promises have already resolved,
+ // so the session has completely shut down and we should not queue up more promises
+ p.resolve_native(&());
+ return p;
+ }
self.end_promises.borrow_mut().push(p.clone());
// This is duplicated in event_callback since this should
// happen ASAP for end() but can happen later if the device
diff --git a/components/script/dom/xrspace.rs b/components/script/dom/xrspace.rs
index 29d81fa6afe..652a4345ce2 100644
--- a/components/script/dom/xrspace.rs
+++ b/components/script/dom/xrspace.rs
@@ -68,7 +68,7 @@ impl XRSpace {
/// with other spaces
pub fn get_pose(&self, base_pose: &Frame) -> Option<ApiPose> {
if let Some(reference) = self.downcast::<XRReferenceSpace>() {
- Some(reference.get_pose(base_pose))
+ reference.get_pose(base_pose)
} else if let Some(source) = self.input_source.get() {
// XXXManishearth we should be able to request frame information
// for inputs when necessary instead of always loading it
diff --git a/components/script/dom/xrtest.rs b/components/script/dom/xrtest.rs
index 05d608b46a4..b00a69b8fca 100644
--- a/components/script/dom/xrtest.rs
+++ b/components/script/dom/xrtest.rs
@@ -21,18 +21,15 @@ use crate::dom::promise::Promise;
use crate::script_thread::ScriptThread;
use crate::task_source::TaskSource;
use dom_struct::dom_struct;
-use euclid::RigidTransform3D;
use ipc_channel::ipc::IpcSender;
use ipc_channel::router::ROUTER;
use profile_traits::ipc;
-use std::cell::Cell;
use std::rc::Rc;
use webxr_api::{self, Error as XRError, MockDeviceInit, MockDeviceMsg};
#[dom_struct]
pub struct XRTest {
reflector: Reflector,
- session_started: Cell<bool>,
devices_connected: DomRefCell<Vec<Dom<FakeXRDevice>>>,
}
@@ -40,7 +37,6 @@ impl XRTest {
pub fn new_inherited() -> XRTest {
XRTest {
reflector: Reflector::new(),
- session_started: Cell::new(false),
devices_connected: DomRefCell::new(vec![]),
}
}
@@ -76,33 +72,28 @@ impl XRTestMethods for XRTest {
fn SimulateDeviceConnection(&self, init: &FakeXRDeviceInit) -> Rc<Promise> {
let p = Promise::new(&self.global());
- if !init.supportsImmersive || self.session_started.get() {
- p.reject_native(&());
- return p;
- }
-
let origin = if let Some(ref o) = init.viewerOrigin {
match get_origin(&o) {
- Ok(origin) => origin,
+ Ok(origin) => Some(origin),
Err(e) => {
p.reject_error(e);
return p;
},
}
} else {
- RigidTransform3D::identity()
+ None
};
let floor_origin = if let Some(ref o) = init.floorOrigin {
match get_origin(&o) {
- Ok(origin) => origin,
+ Ok(origin) => Some(origin),
Err(e) => {
p.reject_error(e);
return p;
},
}
} else {
- RigidTransform3D::identity()
+ None
};
let views = match get_views(&init.views) {
@@ -121,8 +112,6 @@ impl XRTestMethods for XRTest {
floor_origin,
};
- self.session_started.set(true);
-
let global = self.global();
let window = global.as_window();
let this = Trusted::new(self);
diff --git a/components/script/dom/xrviewerpose.rs b/components/script/dom/xrviewerpose.rs
index 8ebabc0781f..0e64613294b 100644
--- a/components/script/dom/xrviewerpose.rs
+++ b/components/script/dom/xrviewerpose.rs
@@ -42,6 +42,13 @@ impl XRViewerPose {
) -> DomRoot<XRViewerPose> {
rooted_vec!(let mut views);
session.with_session(|s| match s.views() {
+ Views::Inline => views.push(XRView::new(
+ global,
+ session,
+ &session.inline_view(),
+ XREye::None,
+ &pose,
+ )),
Views::Mono(view) => {
views.push(XRView::new(global, session, &view, XREye::None, &pose))
},
diff --git a/components/script/dom/xrwebgllayer.rs b/components/script/dom/xrwebgllayer.rs
index 44bc10868b6..498a5035ce0 100644
--- a/components/script/dom/xrwebgllayer.rs
+++ b/components/script/dom/xrwebgllayer.rs
@@ -20,9 +20,10 @@ use crate::dom::xrview::XRView;
use crate::dom::xrviewport::XRViewport;
use canvas_traits::webgl::WebGLFramebufferId;
use dom_struct::dom_struct;
+use euclid::{Point2D, Rect, Size2D};
use std::convert::TryInto;
use webxr_api::SwapChainId as WebXRSwapChainId;
-use webxr_api::Views;
+use webxr_api::{Viewport, Views};
#[dom_struct]
pub struct XRWebGLLayer {
@@ -32,19 +33,20 @@ pub struct XRWebGLLayer {
stencil: bool,
alpha: bool,
#[ignore_malloc_size_of = "ids don't malloc"]
- swap_chain_id: WebXRSwapChainId,
+ swap_chain_id: Option<WebXRSwapChainId>,
context: Dom<WebGLRenderingContext>,
session: Dom<XRSession>,
- framebuffer: Dom<WebGLFramebuffer>,
+ /// If none, this is an inline session (the composition disabled flag is true)
+ framebuffer: Option<Dom<WebGLFramebuffer>>,
}
impl XRWebGLLayer {
pub fn new_inherited(
- swap_chain_id: WebXRSwapChainId,
+ swap_chain_id: Option<WebXRSwapChainId>,
session: &XRSession,
context: &WebGLRenderingContext,
init: &XRWebGLLayerInit,
- framebuffer: &WebGLFramebuffer,
+ framebuffer: Option<&WebGLFramebuffer>,
) -> XRWebGLLayer {
XRWebGLLayer {
reflector_: Reflector::new(),
@@ -55,17 +57,17 @@ impl XRWebGLLayer {
swap_chain_id,
context: Dom::from_ref(context),
session: Dom::from_ref(session),
- framebuffer: Dom::from_ref(framebuffer),
+ framebuffer: framebuffer.map(Dom::from_ref),
}
}
pub fn new(
global: &GlobalScope,
- swap_chain_id: WebXRSwapChainId,
+ swap_chain_id: Option<WebXRSwapChainId>,
session: &XRSession,
context: &WebGLRenderingContext,
init: &XRWebGLLayerInit,
- framebuffer: &WebGLFramebuffer,
+ framebuffer: Option<&WebGLFramebuffer>,
) -> DomRoot<XRWebGLLayer> {
reflect_dom_object(
Box::new(XRWebGLLayer::new_inherited(
@@ -87,6 +89,7 @@ impl XRWebGLLayer {
context: &WebGLRenderingContext,
init: &XRWebGLLayerInit,
) -> Fallible<DomRoot<Self>> {
+ let framebuffer;
// Step 2
if session.is_ended() {
return Err(Error::InvalidState);
@@ -95,9 +98,15 @@ impl XRWebGLLayer {
// XXXManishearth step 4: check XR compat flag for immersive sessions
// Step 9.2. "Initialize layer’s framebuffer to a new opaque framebuffer created with context."
- let size = session.with_session(|session| session.recommended_framebuffer_resolution());
- let (swap_chain_id, framebuffer) =
- WebGLFramebuffer::maybe_new_webxr(session, context, size).ok_or(Error::Operation)?;
+ let (swap_chain_id, framebuffer) = if session.is_immersive() {
+ let size = session.with_session(|session| session.recommended_framebuffer_resolution());
+ let (swap_chain_id, fb) = WebGLFramebuffer::maybe_new_webxr(session, context, size)
+ .ok_or(Error::Operation)?;
+ framebuffer = fb;
+ (Some(swap_chain_id), Some(&*framebuffer))
+ } else {
+ (None, None)
+ };
// Step 9.3. "Allocate and initialize resources compatible with session’s XR device,
// including GPU accessible memory buffers, as required to support the compositing of layer."
@@ -115,12 +124,13 @@ impl XRWebGLLayer {
session,
context,
init,
- &framebuffer,
+ framebuffer,
))
}
pub fn swap_chain_id(&self) -> WebXRSwapChainId {
self.swap_chain_id
+ .expect("swap_chain_id must not be called for inline sessions")
}
pub fn session(&self) -> &XRSession {
@@ -128,10 +138,27 @@ impl XRWebGLLayer {
}
pub fn swap_buffers(&self) {
- if let WebGLFramebufferId::Opaque(id) = self.framebuffer.id() {
+ if let WebGLFramebufferId::Opaque(id) = self
+ .framebuffer
+ .as_ref()
+ .expect("swap_buffers must not be called for inline sessions")
+ .id()
+ {
self.context.swap_buffers(Some(id));
}
}
+
+ pub fn size(&self) -> Size2D<u32, Viewport> {
+ if let Some(framebuffer) = self.framebuffer.as_ref() {
+ let size = framebuffer.size().unwrap_or((0, 0));
+ Size2D::new(
+ size.0.try_into().unwrap_or(0),
+ size.1.try_into().unwrap_or(0),
+ )
+ } else {
+ Size2D::from_untyped(self.context.Canvas().get_size())
+ }
+ }
}
impl XRWebGLLayerMethods for XRWebGLLayer {
@@ -161,28 +188,18 @@ impl XRWebGLLayerMethods for XRWebGLLayer {
}
/// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-framebuffer
- fn Framebuffer(&self) -> DomRoot<WebGLFramebuffer> {
- DomRoot::from_ref(&self.framebuffer)
+ fn GetFramebuffer(&self) -> Option<DomRoot<WebGLFramebuffer>> {
+ self.framebuffer.as_ref().map(|x| DomRoot::from_ref(&**x))
}
/// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-framebufferwidth
fn FramebufferWidth(&self) -> u32 {
- self.framebuffer
- .size()
- .unwrap_or((0, 0))
- .0
- .try_into()
- .unwrap_or(0)
+ self.size().width
}
/// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-framebufferheight
fn FramebufferHeight(&self) -> u32 {
- self.framebuffer
- .size()
- .unwrap_or((0, 0))
- .1
- .try_into()
- .unwrap_or(0)
+ self.size().height
}
/// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-getviewport
@@ -194,11 +211,13 @@ impl XRWebGLLayerMethods for XRWebGLLayer {
let views = self.session.with_session(|s| s.views().clone());
let viewport = match (view.Eye(), views) {
+ (XREye::None, Views::Inline) => {
+ let origin = Point2D::new(0, 0);
+ Rect::new(origin, self.size().cast())
+ },
(XREye::None, Views::Mono(view)) => view.viewport,
(XREye::Left, Views::Stereo(view, _)) => view.viewport,
(XREye::Right, Views::Stereo(_, view)) => view.viewport,
- // The spec doesn't really say what to do in this case
- // https://github.com/immersive-web/webxr/issues/769
_ => return None,
};