aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom
diff options
context:
space:
mode:
Diffstat (limited to 'components/script/dom')
-rw-r--r--components/script/dom/audiocontext.rs4
-rw-r--r--components/script/dom/baseaudiocontext.rs2
-rw-r--r--components/script/dom/bindings/codegen/Bindings.conf4
-rw-r--r--components/script/dom/bindings/codegen/CodegenRust.py282
-rw-r--r--components/script/dom/bindings/codegen/parser/WebIDL.py315
-rw-r--r--components/script/dom/bindings/codegen/parser/ext-attribute-no-value-error.patch11
-rw-r--r--components/script/dom/bindings/codegen/parser/tests/test_attributes_on_types.py221
-rw-r--r--components/script/dom/bindings/codegen/parser/tests/test_constructor.py71
-rw-r--r--components/script/dom/bindings/codegen/parser/tests/test_date.py15
-rw-r--r--components/script/dom/bindings/codegen/parser/tests/test_distinguishability.py27
-rw-r--r--components/script/dom/bindings/codegen/parser/tests/test_extended_attributes.py8
-rw-r--r--components/script/dom/bindings/codegen/parser/tests/test_nullable_equivalency.py2
-rw-r--r--components/script/dom/bindings/codegen/parser/tests/test_toJSON.py11
-rwxr-xr-xcomponents/script/dom/bindings/codegen/parser/update.sh6
-rw-r--r--components/script/dom/bindings/error.rs3
-rw-r--r--components/script/dom/bindings/interface.rs16
-rw-r--r--components/script/dom/bindings/namespace.rs5
-rw-r--r--components/script/dom/bindings/proxyhandler.rs6
-rw-r--r--components/script/dom/bindings/record.rs4
-rw-r--r--components/script/dom/bindings/reflector.rs9
-rw-r--r--components/script/dom/bindings/root.rs75
-rw-r--r--components/script/dom/bindings/structuredclone.rs3
-rw-r--r--components/script/dom/bindings/trace.rs45
-rw-r--r--components/script/dom/bindings/utils.rs12
-rw-r--r--components/script/dom/broadcastchannel.rs106
-rw-r--r--components/script/dom/document.rs70
-rw-r--r--components/script/dom/element.rs10
-rw-r--r--components/script/dom/eventtarget.rs25
-rw-r--r--components/script/dom/globalscope.rs379
-rw-r--r--components/script/dom/gpu.rs12
-rw-r--r--components/script/dom/gpuadapter.rs16
-rw-r--r--components/script/dom/gpubuffer.rs176
-rw-r--r--components/script/dom/gpucommandencoder.rs16
-rw-r--r--components/script/dom/gpucomputepassencoder.rs7
-rw-r--r--components/script/dom/gpudevice.rs179
-rw-r--r--components/script/dom/gpuqueue.rs7
-rw-r--r--components/script/dom/htmlcanvaselement.rs2
-rw-r--r--components/script/dom/htmlelement.rs48
-rw-r--r--components/script/dom/htmlformelement.rs25
-rw-r--r--components/script/dom/htmlimageelement.rs11
-rwxr-xr-xcomponents/script/dom/htmlinputelement.rs34
-rw-r--r--components/script/dom/htmlmediaelement.rs20
-rwxr-xr-xcomponents/script/dom/htmltextareaelement.rs12
-rw-r--r--components/script/dom/mediasession.rs4
-rw-r--r--components/script/dom/messageport.rs2
-rw-r--r--components/script/dom/mod.rs5
-rw-r--r--components/script/dom/navigator.rs3
-rw-r--r--components/script/dom/node.rs54
-rw-r--r--components/script/dom/nodelist.rs42
-rw-r--r--components/script/dom/offlineaudiocontext.rs4
-rw-r--r--components/script/dom/permissions.rs100
-rw-r--r--components/script/dom/promise.rs10
-rw-r--r--components/script/dom/rtcpeerconnection.rs16
-rw-r--r--components/script/dom/texttrackcue.rs24
-rw-r--r--components/script/dom/vertexarrayobject.rs296
-rw-r--r--components/script/dom/vrdisplay.rs34
-rw-r--r--components/script/dom/vrdisplaycapabilities.rs4
-rw-r--r--components/script/dom/vreyeparameters.rs4
-rw-r--r--components/script/dom/vrfieldofview.rs4
-rw-r--r--components/script/dom/vrstageparameters.rs7
-rw-r--r--components/script/dom/vttcue.rs232
-rw-r--r--components/script/dom/vttregion.rs167
-rw-r--r--components/script/dom/webgl2renderingcontext.rs433
-rw-r--r--components/script/dom/webglframebuffer.rs244
-rw-r--r--components/script/dom/webglprogram.rs24
-rw-r--r--components/script/dom/webglrenderbuffer.rs65
-rw-r--r--components/script/dom/webglrenderingcontext.rs358
-rw-r--r--components/script/dom/webglvertexarrayobject.rs100
-rw-r--r--components/script/dom/webglvertexarrayobjectoes.rs251
-rw-r--r--components/script/dom/webidls/BroadcastChannel.webidl18
-rw-r--r--components/script/dom/webidls/GPUBuffer.webidl2
-rw-r--r--components/script/dom/webidls/HTMLElement.webidl4
-rw-r--r--components/script/dom/webidls/HTMLTextAreaElement.webidl4
-rw-r--r--components/script/dom/webidls/VTTCue.webidl30
-rw-r--r--components/script/dom/webidls/VTTRegion.webidl26
-rw-r--r--components/script/dom/webidls/WebGL2RenderingContext.webidl32
-rw-r--r--components/script/dom/webidls/WebGLVertexArrayObject.webidl11
-rw-r--r--components/script/dom/window.rs35
-rw-r--r--components/script/dom/windowproxy.rs4
-rw-r--r--components/script/dom/xrsession.rs36
-rw-r--r--components/script/dom/xrsystem.rs35
81 files changed, 3841 insertions, 1195 deletions
diff --git a/components/script/dom/audiocontext.rs b/components/script/dom/audiocontext.rs
index d5b1c3bdb56..b81caed793b 100644
--- a/components/script/dom/audiocontext.rs
+++ b/components/script/dom/audiocontext.rs
@@ -75,9 +75,7 @@ impl AudioContext {
#[allow(unrooted_must_root)]
pub fn new(window: &Window, options: &AudioContextOptions) -> DomRoot<AudioContext> {
- let pipeline_id = window
- .pipeline_id()
- .expect("Cannot create AudioContext outside of a pipeline");
+ let pipeline_id = window.pipeline_id();
let context = AudioContext::new_inherited(options, pipeline_id);
let context = reflect_dom_object(Box::new(context), window, AudioContextBinding::Wrap);
context.resume();
diff --git a/components/script/dom/baseaudiocontext.rs b/components/script/dom/baseaudiocontext.rs
index c84d62f6dc3..14c6bc94e1c 100644
--- a/components/script/dom/baseaudiocontext.rs
+++ b/components/script/dom/baseaudiocontext.rs
@@ -331,7 +331,7 @@ impl BaseAudioContextMethods for BaseAudioContext {
self.listener.or_init(|| AudioListener::new(&window, self))
}
- /// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-onstatechange
+ // https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-onstatechange
event_handler!(statechange, GetOnstatechange, SetOnstatechange);
/// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-createoscillator
diff --git a/components/script/dom/bindings/codegen/Bindings.conf b/components/script/dom/bindings/codegen/Bindings.conf
index 5f978f5d3c4..7aa8ffa4c8b 100644
--- a/components/script/dom/bindings/codegen/Bindings.conf
+++ b/components/script/dom/bindings/codegen/Bindings.conf
@@ -150,6 +150,10 @@ DOMInterfaces = {
'GPUAdapter': {
'inRealms': ['RequestDevice'],
+},
+
+'GPUBuffer': {
+ 'inRealms': ['MapReadAsync'],
}
}
diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py
index ce1487d5fa6..fab5e1e713a 100644
--- a/components/script/dom/bindings/codegen/CodegenRust.py
+++ b/components/script/dom/bindings/codegen/CodegenRust.py
@@ -427,17 +427,6 @@ class CGMethodCall(CGThing):
(s[1][distinguishingIndex].type.isSequence() or
s[1][distinguishingIndex].type.isObject()))
- # Check for Date objects
- # XXXbz Do we need to worry about security wrappers around the Date?
- pickFirstSignature("%s.get().is_object() && "
- "{ rooted!(in(*cx) let obj = %s.get().to_object()); "
- "let mut is_date = false; "
- "assert!(ObjectIsDate(*cx, obj.handle(), &mut is_date)); "
- "is_date }" %
- (distinguishingArg, distinguishingArg),
- lambda s: (s[1][distinguishingIndex].type.isDate() or
- s[1][distinguishingIndex].type.isObject()))
-
# Check for vanilla JS objects
# XXXbz Do we need to worry about security wrappers?
pickFirstSignature("%s.get().is_object() && !is_platform_object(%s.get().to_object(), *cx)" %
@@ -596,8 +585,8 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
# We should not have a defaultValue if we know we're an object
assert not isDefinitelyObject or defaultValue is None
- isEnforceRange = type.enforceRange
- isClamp = type.clamp
+ isEnforceRange = type.hasEnforceRange()
+ isClamp = type.hasClamp()
if type.treatNullAsEmpty:
treatNullAs = "EmptyString"
else:
@@ -1654,7 +1643,7 @@ class MethodDefiner(PropertyDefiner):
if any(m.isGetter() and m.isIndexed() for m in methods):
self.regular.append({"name": '@@iterator',
"methodInfo": False,
- "selfHostedName": "ArrayValues",
+ "selfHostedName": "$ArrayValues",
"length": 0,
"flags": "0", # Not enumerable, per spec.
"condition": "Condition::Satisfied"})
@@ -1665,6 +1654,8 @@ class MethodDefiner(PropertyDefiner):
(maplikeOrSetlikeOrIterable and
maplikeOrSetlikeOrIterable.isIterable() and
maplikeOrSetlikeOrIterable.isValueIterator())):
+ m = maplikeOrSetlikeOrIterable
+
# Add our keys/values/entries/forEach
self.regular.append({
"name": "keys",
@@ -1678,7 +1669,7 @@ class MethodDefiner(PropertyDefiner):
self.regular.append({
"name": "values",
"methodInfo": False,
- "selfHostedName": "ArrayValues",
+ "selfHostedName": "$ArrayValues",
"length": 0,
"flags": "JSPROP_ENUMERATE",
"condition": PropertyDefiner.getControllingCondition(m,
@@ -1731,7 +1722,7 @@ class MethodDefiner(PropertyDefiner):
selfHostedName = '%s as *const u8 as *const libc::c_char' % str_to_const_array(m["selfHostedName"])
assert not m.get("methodInfo", True)
accessor = "None"
- jitinfo = "0 as *const JSJitInfo"
+ jitinfo = "ptr::null()"
else:
selfHostedName = "0 as *const libc::c_char"
if m.get("methodInfo", True):
@@ -1743,28 +1734,30 @@ class MethodDefiner(PropertyDefiner):
jitinfo = "&%s_methodinfo as *const _ as *const JSJitInfo" % identifier
accessor = "Some(generic_method)"
else:
- jitinfo = "0 as *const JSJitInfo"
+ jitinfo = "ptr::null()"
accessor = 'Some(%s)' % m.get("nativeName", m["name"])
if m["name"].startswith("@@"):
- return ('(SymbolCode::%s as i32 + 1)'
- % m["name"][2:], accessor, jitinfo, m["length"], flags, selfHostedName)
- return (str_to_const_array(m["name"]), accessor, jitinfo, m["length"], flags, selfHostedName)
+ name = 'JSPropertySpec_Name { symbol_: SymbolCode::%s as usize + 1 }' % m["name"][2:]
+ else:
+ name = ('JSPropertySpec_Name { string_: %s as *const u8 as *const libc::c_char }'
+ % str_to_const_array(m["name"]))
+ return (name, accessor, jitinfo, m["length"], flags, selfHostedName)
return self.generateGuardedArray(
array, name,
' JSFunctionSpec {\n'
- ' name: %s as *const u8 as *const libc::c_char,\n'
+ ' name: %s,\n'
' call: JSNativeWrapper { op: %s, info: %s },\n'
' nargs: %s,\n'
' flags: (%s) as u16,\n'
' selfHostedName: %s\n'
' }',
' JSFunctionSpec {\n'
- ' name: 0 as *const libc::c_char,\n'
- ' call: JSNativeWrapper { op: None, info: 0 as *const JSJitInfo },\n'
+ ' name: JSPropertySpec_Name { string_: ptr::null() },\n'
+ ' call: JSNativeWrapper { op: None, info: ptr::null() },\n'
' nargs: 0,\n'
' flags: 0,\n'
- ' selfHostedName: 0 as *const libc::c_char\n'
+ ' selfHostedName: ptr::null()\n'
' }',
'JSFunctionSpec',
condition, specData)
@@ -1834,14 +1827,14 @@ class AttrDefiner(PropertyDefiner):
return self.generateGuardedArray(
array, name,
' JSPropertySpec {\n'
- ' name: %s as *const u8 as *const libc::c_char,\n'
+ ' name: JSPropertySpec_Name { string_: %s as *const u8 as *const libc::c_char },\n'
' flags: (%s) as u8,\n'
- ' __bindgen_anon_1: JSPropertySpec__bindgen_ty_1 {\n'
- ' accessors: JSPropertySpec__bindgen_ty_1__bindgen_ty_1 {\n'
- ' getter: JSPropertySpec__bindgen_ty_1__bindgen_ty_1__bindgen_ty_1 {\n'
+ ' u: JSPropertySpec_AccessorsOrValue {\n'
+ ' accessors: JSPropertySpec_AccessorsOrValue_Accessors {\n'
+ ' getter: JSPropertySpec_Accessor {\n'
' native: %s,\n'
' },\n'
- ' setter: JSPropertySpec__bindgen_ty_1__bindgen_ty_1__bindgen_ty_2 {\n'
+ ' setter: JSPropertySpec_Accessor {\n'
' native: %s,\n'
' }\n'
' }\n'
@@ -2203,7 +2196,9 @@ static Class: DOMJSClass = DOMJSClass {
(((%(slots)s) & JSCLASS_RESERVED_SLOTS_MASK) << JSCLASS_RESERVED_SLOTS_SHIFT)
/* JSCLASS_HAS_RESERVED_SLOTS(%(slots)s) */,
cOps: &CLASS_OPS,
- reserved: [0 as *mut _; 3],
+ spec: ptr::null(),
+ ext: ptr::null(),
+ oOps: ptr::null(),
},
dom_class: %(domClass)s
};
@@ -2274,7 +2269,9 @@ static PrototypeClass: JSClass = JSClass {
// JSCLASS_HAS_RESERVED_SLOTS(%(slotCount)s)
(%(slotCount)s & JSCLASS_RESERVED_SLOTS_MASK) << JSCLASS_RESERVED_SLOTS_SHIFT,
cOps: 0 as *const _,
- reserved: [0 as *mut os::raw::c_void; 3]
+ spec: ptr::null(),
+ ext: ptr::null(),
+ oOps: ptr::null(),
};
""" % {'name': name, 'slotCount': slotCount}
@@ -2632,35 +2629,6 @@ class CGConstructorEnabled(CGAbstractMethod):
return CGList((CGGeneric(cond) for cond in conditions), " &&\n")
-def CreateBindingJSObject(descriptor):
- assert not descriptor.isGlobal()
- create = "let raw = Box::into_raw(object);\nlet _rt = RootedTraceable::new(&*raw);\n"
- if descriptor.proxy:
- create += """
-let handler = RegisterBindings::PROXY_HANDLERS[PrototypeList::Proxies::%s as usize];
-rooted!(in(*cx) let private = PrivateValue(raw as *const libc::c_void));
-let obj = NewProxyObject(*cx, handler,
- Handle::from_raw(UndefinedHandleValue),
- proto.get());
-assert!(!obj.is_null());
-SetProxyReservedSlot(obj, 0, &private.get());
-rooted!(in(*cx) let obj = obj);\
-""" % (descriptor.name)
- else:
- create += ("rooted!(in(*cx) let obj = JS_NewObjectWithGivenProto(\n"
- " *cx, &Class.base as *const JSClass, proto.handle()));\n"
- "assert!(!obj.is_null());\n"
- "\n"
- "let val = PrivateValue(raw as *const libc::c_void);\n"
- "\n"
- "JS_SetReservedSlot(obj.get(), DOM_OBJECT_SLOT, &val);")
- if descriptor.weakReferenceable:
- create += """
-let val = PrivateValue(ptr::null());
-JS_SetReservedSlot(obj.get(), DOM_WEAK_SLOT, &val);"""
- return create
-
-
def InitUnforgeablePropertiesOnHolder(descriptor, properties):
"""
Define the unforgeable properties on the unforgeable holder for
@@ -2738,23 +2706,62 @@ class CGWrapMethod(CGAbstractMethod):
def definition_body(self):
unforgeable = CopyUnforgeablePropertiesToInstance(self.descriptor)
- create = CreateBindingJSObject(self.descriptor)
+ if self.descriptor.proxy:
+ create = """
+let handler = RegisterBindings::PROXY_HANDLERS[PrototypeList::Proxies::%(concreteType)s as usize];
+rooted!(in(*cx) let obj = NewProxyObject(
+ *cx,
+ handler,
+ Handle::from_raw(UndefinedHandleValue),
+ proto.get(),
+));
+assert!(!obj.is_null());
+SetProxyReservedSlot(
+ obj.get(),
+ 0,
+ &PrivateValue(raw.as_ptr() as *const %(concreteType)s as *const libc::c_void),
+);
+"""
+ else:
+ create = """
+rooted!(in(*cx) let obj = JS_NewObjectWithGivenProto(
+ *cx,
+ &Class.base,
+ proto.handle(),
+));
+assert!(!obj.is_null());
+JS_SetReservedSlot(
+ obj.get(),
+ DOM_OBJECT_SLOT,
+ &PrivateValue(raw.as_ptr() as *const %(concreteType)s as *const libc::c_void),
+);
+"""
+ create = create % {"concreteType": self.descriptor.concreteType}
+ if self.descriptor.weakReferenceable:
+ create += """
+let val = PrivateValue(ptr::null());
+JS_SetReservedSlot(obj.get(), DOM_WEAK_SLOT, &val);
+"""
+
return CGGeneric("""\
+let raw = Root::new(MaybeUnreflectedDom::from_box(object));
+
let scope = scope.reflector().get_jsobject();
assert!(!scope.get().is_null());
assert!(((*get_object_class(scope.get())).flags & JSCLASS_IS_GLOBAL) != 0);
+let _ac = JSAutoRealm::new(*cx, scope.get());
rooted!(in(*cx) let mut proto = ptr::null_mut::<JSObject>());
-let _ac = JSAutoRealm::new(*cx, scope.get());
GetProtoObject(cx, scope, proto.handle_mut());
assert!(!proto.is_null());
%(createObject)s
+let root = raw.reflect_with(obj.get());
%(copyUnforgeable)s
-(*raw).init_reflector(obj.get());
-DomRoot::from_ref(&*raw)""" % {'copyUnforgeable': unforgeable, 'createObject': create})
+DomRoot::from_ref(&*root)\
+""" % {'copyUnforgeable': unforgeable, 'createObject': create})
class CGWrapGlobalMethod(CGAbstractMethod):
@@ -2773,6 +2780,7 @@ class CGWrapGlobalMethod(CGAbstractMethod):
def definition_body(self):
values = {
+ "concreteType": self.descriptor.concreteType,
"unforgeable": CopyUnforgeablePropertiesToInstance(self.descriptor)
}
@@ -2786,19 +2794,18 @@ class CGWrapGlobalMethod(CGAbstractMethod):
values["members"] = "\n".join(members)
return CGGeneric("""\
-let raw = Box::into_raw(object);
-let _rt = RootedTraceable::new(&*raw);
+let raw = Root::new(MaybeUnreflectedDom::from_box(object));
rooted!(in(*cx) let mut obj = ptr::null_mut::<JSObject>());
create_global_object(
cx,
&Class.base,
- raw as *const libc::c_void,
+ raw.as_ptr() as *const %(concreteType)s as *const libc::c_void,
_trace,
obj.handle_mut());
assert!(!obj.is_null());
-(*raw).init_reflector(obj.get());
+let root = raw.reflect_with(obj.get());
let _ac = JSAutoRealm::new(*cx, obj.get());
rooted!(in(*cx) let mut proto = ptr::null_mut::<JSObject>());
@@ -2812,7 +2819,7 @@ assert!(immutable);
%(unforgeable)s
-DomRoot::from_ref(&*raw)\
+DomRoot::from_ref(&*root)\
""" % values)
@@ -2906,9 +2913,9 @@ class CGCollectJSONAttributesMethod(CGAbstractMethod):
Generate the CollectJSONAttributes method for an interface descriptor
"""
def __init__(self, descriptor, toJSONMethod):
- args = [Argument('SafeJSContext', 'cx'),
- Argument('HandleObject', 'obj'),
- Argument('*const %s' % descriptor.concreteType, 'this'),
+ args = [Argument('*mut JSContext', 'cx'),
+ Argument('RawHandleObject', 'obj'),
+ Argument('*mut libc::c_void', 'this'),
Argument('&RootedGuard<*mut JSObject>', 'result')]
CGAbstractMethod.__init__(self, descriptor, 'CollectJSONAttributes',
'bool', args, pub=True, unsafe=True)
@@ -2922,11 +2929,11 @@ class CGCollectJSONAttributesMethod(CGAbstractMethod):
name = m.identifier.name
ret += fill(
"""
- rooted!(in(*cx) let mut temp = UndefinedValue());
+ rooted!(in(cx) let mut temp = UndefinedValue());
if !get_${name}(cx, obj, this, JSJitGetterCallArgs { _base: temp.handle_mut().into() }) {
return false;
}
- if !JS_DefineProperty(*cx, result.handle().into(),
+ if !JS_DefineProperty(cx, result.handle().into(),
${nameAsArray} as *const u8 as *const libc::c_char,
temp.handle(), JSPROP_ENUMERATE as u32) {
return false;
@@ -3658,8 +3665,9 @@ class CGSpecializedMethod(CGAbstractExternMethod):
def __init__(self, descriptor, method):
self.method = method
name = method.identifier.name
- args = [Argument('SafeJSContext', 'cx'), Argument('HandleObject', '_obj'),
- Argument('*const %s' % descriptor.concreteType, 'this'),
+ args = [Argument('*mut JSContext', 'cx'),
+ Argument('RawHandleObject', '_obj'),
+ Argument('*mut libc::c_void', 'this'),
Argument('*const JSJitMethodCallArgs', 'args')]
CGAbstractExternMethod.__init__(self, descriptor, name, 'bool', args)
@@ -3668,7 +3676,8 @@ class CGSpecializedMethod(CGAbstractExternMethod):
self.method)
return CGWrapper(CGMethodCall([], nativeName, self.method.isStatic(),
self.descriptor, self.method),
- pre="let this = &*this;\n"
+ pre="let cx = SafeJSContext::from_ptr(cx);\n" +
+ ("let this = &*(this as *const %s);\n" % self.descriptor.concreteType) +
"let args = &*args;\n"
"let argc = args.argc_;\n")
@@ -3691,7 +3700,7 @@ class CGDefaultToJSONMethod(CGSpecializedMethod):
def definition_body(self):
ret = dedent("""
use crate::dom::bindings::inheritance::HasParent;
- rooted!(in(*cx) let result = JS_NewPlainObject(*cx));
+ rooted!(in(cx) let result = JS_NewPlainObject(cx));
if result.is_null() {
return false;
}
@@ -3707,17 +3716,16 @@ class CGDefaultToJSONMethod(CGSpecializedMethod):
parents = len(jsonDescriptors) - 1
form = """
- if !${parentclass}CollectJSONAttributes(cx, _obj, this${asparent}, &result) {
+ if !${parentclass}CollectJSONAttributes(cx, _obj, this, &result) {
return false;
}
"""
# Iterate the array in reverse: oldest ancestor first
for descriptor in jsonDescriptors[:0:-1]:
- ret += fill(form, parentclass=toBindingNamespace(descriptor.name) + "::",
- asparent=".as_ref().unwrap()" + ".as_parent()" * parents)
+ ret += fill(form, parentclass=toBindingNamespace(descriptor.name) + "::")
parents -= 1
- ret += fill(form, parentclass="", asparent="")
+ ret += fill(form, parentclass="")
ret += ('(*args).rval().set(ObjectValue(*result));\n'
'return true;\n')
return CGGeneric(ret)
@@ -3749,9 +3757,9 @@ class CGSpecializedGetter(CGAbstractExternMethod):
def __init__(self, descriptor, attr):
self.attr = attr
name = 'get_' + descriptor.internalNameFor(attr.identifier.name)
- args = [Argument('SafeJSContext', 'cx'),
- Argument('HandleObject', '_obj'),
- Argument('*const %s' % descriptor.concreteType, 'this'),
+ args = [Argument('*mut JSContext', 'cx'),
+ Argument('RawHandleObject', '_obj'),
+ Argument('*mut libc::c_void', 'this'),
Argument('JSJitGetterCallArgs', 'args')]
CGAbstractExternMethod.__init__(self, descriptor, name, "bool", args)
@@ -3761,7 +3769,8 @@ class CGSpecializedGetter(CGAbstractExternMethod):
return CGWrapper(CGGetterCall([], self.attr.type, nativeName,
self.descriptor, self.attr),
- pre="let this = &*this;\n")
+ pre="let cx = SafeJSContext::from_ptr(cx);\n" +
+ ("let this = &*(this as *const %s);\n" % self.descriptor.concreteType))
@staticmethod
def makeNativeName(descriptor, attr):
@@ -3805,9 +3814,9 @@ class CGSpecializedSetter(CGAbstractExternMethod):
def __init__(self, descriptor, attr):
self.attr = attr
name = 'set_' + descriptor.internalNameFor(attr.identifier.name)
- args = [Argument('SafeJSContext', 'cx'),
- Argument('HandleObject', 'obj'),
- Argument('*const %s' % descriptor.concreteType, 'this'),
+ args = [Argument('*mut JSContext', 'cx'),
+ Argument('RawHandleObject', 'obj'),
+ Argument('*mut libc::c_void', 'this'),
Argument('JSJitSetterCallArgs', 'args')]
CGAbstractExternMethod.__init__(self, descriptor, name, "bool", args)
@@ -3816,7 +3825,8 @@ class CGSpecializedSetter(CGAbstractExternMethod):
self.attr)
return CGWrapper(CGSetterCall([], self.attr.type, nativeName,
self.descriptor, self.attr),
- pre="let this = &*this;\n")
+ pre="let cx = SafeJSContext::from_ptr(cx);\n" +
+ ("let this = &*(this as *const %s);\n" % self.descriptor.concreteType))
@staticmethod
def makeNativeName(descriptor, attr):
@@ -3865,8 +3875,9 @@ class CGSpecializedForwardingSetter(CGSpecializedSetter):
assert all(ord(c) < 128 for c in attrName)
assert all(ord(c) < 128 for c in forwardToAttrName)
return CGGeneric("""\
+let cx = SafeJSContext::from_ptr(cx);
rooted!(in(*cx) let mut v = UndefinedValue());
-if !JS_GetProperty(*cx, obj, %s as *const u8 as *const libc::c_char, v.handle_mut()) {
+if !JS_GetProperty(*cx, HandleObject::from_raw(obj), %s as *const u8 as *const libc::c_char, v.handle_mut()) {
return false;
}
if !v.is_object() {
@@ -3891,7 +3902,7 @@ class CGSpecializedReplaceableSetter(CGSpecializedSetter):
# JS_DefineProperty can only deal with ASCII.
assert all(ord(c) < 128 for c in name)
return CGGeneric("""\
-JS_DefineProperty(*cx, obj, %s as *const u8 as *const libc::c_char,
+JS_DefineProperty(cx, HandleObject::from_raw(obj), %s as *const u8 as *const libc::c_char,
HandleValue::from_raw(args.get(0)), JSPROP_ENUMERATE as u32)""" % name)
@@ -3921,27 +3932,34 @@ class CGMemberJITInfo(CGThing):
initializer = fill(
"""
JSJitInfo {
- call: ${opName} as *const os::raw::c_void,
- protoID: PrototypeList::ID::${name} as u16,
- depth: ${depth},
- _bitfield_1: new_jsjitinfo_bitfield_1!(
- JSJitInfo_OpType::${opType} as u8,
- JSJitInfo_AliasSet::${aliasSet} as u8,
- JSValueType::${returnType} as u8,
- ${isInfallible},
- ${isMovable},
- ${isEliminatable},
- ${isAlwaysInSlot},
- ${isLazilyCachedInSlot},
- ${isTypedMethod},
- ${slotIndex},
- ),
+ __bindgen_anon_1: JSJitInfo__bindgen_ty_1 {
+ ${opKind}: Some(${opName})
+ },
+ __bindgen_anon_2: JSJitInfo__bindgen_ty_2 {
+ protoID: PrototypeList::ID::${name} as u16,
+ },
+ __bindgen_anon_3: JSJitInfo__bindgen_ty_3 { depth: ${depth} },
+ _bitfield_1: unsafe {
+ mem::transmute(new_jsjitinfo_bitfield_1!(
+ JSJitInfo_OpType::${opType} as u8,
+ JSJitInfo_AliasSet::${aliasSet} as u8,
+ JSValueType::${returnType} as u8,
+ ${isInfallible},
+ ${isMovable},
+ ${isEliminatable},
+ ${isAlwaysInSlot},
+ ${isLazilyCachedInSlot},
+ ${isTypedMethod},
+ ${slotIndex},
+ ))
+ },
}
""",
opName=opName,
name=self.descriptor.name,
depth=self.descriptor.interface.inheritanceDepth(),
opType=opType,
+ opKind=opType.lower(),
aliasSet=aliasSet,
returnType=functools.reduce(CGMemberJITInfo.getSingleReturnType, returnTypes,
""),
@@ -4135,8 +4153,6 @@ class CGMemberJITInfo(CGThing):
u.flatMemberTypes, "")
if t.isDictionary():
return "JSVAL_TYPE_OBJECT"
- if t.isDate():
- return "JSVAL_TYPE_OBJECT"
if not t.isPrimitive():
raise TypeError("No idea what type " + str(t) + " is.")
tag = t.tag()
@@ -4201,13 +4217,11 @@ class CGMemberJITInfo(CGThing):
return "JSJitInfo_ArgType::Object as i32"
if t.isUnion():
u = t.unroll()
- type = "JSJitInfo::Null as i32" if u.hasNullableType else ""
+ type = "JSJitInfo_ArgType::Null as i32" if u.hasNullableType else ""
return functools.reduce(CGMemberJITInfo.getSingleArgType,
u.flatMemberTypes, type)
if t.isDictionary():
return "JSJitInfo_ArgType::Object as i32"
- if t.isDate():
- return "JSJitInfo_ArgType::Object as i32"
if not t.isPrimitive():
raise TypeError("No idea what type " + str(t) + " is.")
tag = t.tag()
@@ -4513,13 +4527,6 @@ class CGUnionConversionStruct(CGThing):
else:
arrayObject = None
- dateObjectMemberTypes = filter(lambda t: t.isDate(), memberTypes)
- if len(dateObjectMemberTypes) > 0:
- assert len(dateObjectMemberTypes) == 1
- raise TypeError("Can't handle dates in unions.")
- else:
- dateObject = None
-
callbackMemberTypes = filter(lambda t: t.isCallback() or t.isCallbackInterface(), memberTypes)
if len(callbackMemberTypes) > 0:
assert len(callbackMemberTypes) == 1
@@ -4555,10 +4562,10 @@ class CGUnionConversionStruct(CGThing):
else:
mozMapObject = None
- hasObjectTypes = object or interfaceObject or arrayObject or dateObject or callbackObject or mozMapObject
+ hasObjectTypes = object or interfaceObject or arrayObject or callbackObject or mozMapObject
if hasObjectTypes:
# "object" is not distinguishable from other types
- assert not object or not (interfaceObject or arrayObject or dateObject or callbackObject or mozMapObject)
+ assert not object or not (interfaceObject or arrayObject or callbackObject or mozMapObject)
templateBody = CGList([], "\n")
if object:
templateBody.append(object)
@@ -5301,7 +5308,7 @@ class CGDOMJSProxyHandler_ownPropertyKeys(CGAbstractExternMethod):
def __init__(self, descriptor):
args = [Argument('*mut JSContext', 'cx'),
Argument('RawHandleObject', 'proxy'),
- Argument('*mut AutoIdVector', 'props')]
+ Argument('RawMutableHandleIdVector', 'props')]
CGAbstractExternMethod.__init__(self, descriptor, "own_property_keys", "bool", args)
self.descriptor = descriptor
@@ -5318,7 +5325,7 @@ class CGDOMJSProxyHandler_ownPropertyKeys(CGAbstractExternMethod):
for i in 0..(*unwrapped_proxy).Length() {
rooted!(in(*cx) let mut rooted_jsid: jsid);
int_to_jsid(i as i32, rooted_jsid.handle_mut());
- AppendToAutoIdVector(props, rooted_jsid.handle());
+ AppendToIdVector(props, rooted_jsid.handle());
}
""")
@@ -5331,7 +5338,7 @@ class CGDOMJSProxyHandler_ownPropertyKeys(CGAbstractExternMethod):
rooted!(in(*cx) let rooted = jsstring);
rooted!(in(*cx) let mut rooted_jsid: jsid);
RUST_INTERNED_STRING_TO_JSID(*cx, rooted.handle().get(), rooted_jsid.handle_mut());
- AppendToAutoIdVector(props, rooted_jsid.handle());
+ AppendToIdVector(props, rooted_jsid.handle());
}
""")
@@ -5359,7 +5366,7 @@ class CGDOMJSProxyHandler_getOwnEnumerablePropertyKeys(CGAbstractExternMethod):
descriptor.interface.getExtendedAttribute("LegacyUnenumerableNamedProperties"))
args = [Argument('*mut JSContext', 'cx'),
Argument('RawHandleObject', 'proxy'),
- Argument('*mut AutoIdVector', 'props')]
+ Argument('RawMutableHandleIdVector', 'props')]
CGAbstractExternMethod.__init__(self, descriptor,
"getOwnEnumerablePropertyKeys", "bool", args)
self.descriptor = descriptor
@@ -5377,7 +5384,7 @@ class CGDOMJSProxyHandler_getOwnEnumerablePropertyKeys(CGAbstractExternMethod):
for i in 0..(*unwrapped_proxy).Length() {
rooted!(in(*cx) let mut rooted_jsid: jsid);
int_to_jsid(i as i32, rooted_jsid.handle_mut());
- AppendToAutoIdVector(props, rooted_jsid.handle());
+ AppendToIdVector(props, rooted_jsid.handle());
}
""")
@@ -5907,11 +5914,9 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries
'js::JS_CALLEE',
'js::error::throw_type_error',
'js::error::throw_internal_error',
- 'js::jsapi::AutoIdVector',
'js::rust::wrappers::Call',
'js::jsapi::CallArgs',
'js::jsapi::CurrentGlobalOrNull',
- 'js::jsapi::FreeOp',
'js::rust::wrappers::GetPropertyKeys',
'js::jsapi::GetWellKnownSymbol',
'js::rust::Handle',
@@ -5938,6 +5943,9 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries
'js::jsapi::JSITER_SYMBOLS',
'js::jsapi::JSJitGetterCallArgs',
'js::jsapi::JSJitInfo',
+ 'js::jsapi::JSJitInfo__bindgen_ty_1',
+ 'js::jsapi::JSJitInfo__bindgen_ty_2',
+ 'js::jsapi::JSJitInfo__bindgen_ty_3',
'js::jsapi::JSJitInfo_AliasSet',
'js::jsapi::JSJitInfo_ArgType',
'js::jsapi::JSJitInfo_OpType',
@@ -5950,10 +5958,10 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries
'js::jsapi::JSPROP_PERMANENT',
'js::jsapi::JSPROP_READONLY',
'js::jsapi::JSPropertySpec',
- 'js::jsapi::JSPropertySpec__bindgen_ty_1',
- 'js::jsapi::JSPropertySpec__bindgen_ty_1__bindgen_ty_1',
- 'js::jsapi::JSPropertySpec__bindgen_ty_1__bindgen_ty_1__bindgen_ty_1',
- 'js::jsapi::JSPropertySpec__bindgen_ty_1__bindgen_ty_1__bindgen_ty_2',
+ 'js::jsapi::JSPropertySpec_Accessor',
+ 'js::jsapi::JSPropertySpec_AccessorsOrValue',
+ 'js::jsapi::JSPropertySpec_AccessorsOrValue_Accessors',
+ 'js::jsapi::JSPropertySpec_Name',
'js::jsapi::JSString',
'js::jsapi::JSTracer',
'js::jsapi::JSType',
@@ -5995,6 +6003,7 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries
'js::jsapi::MutableHandleObject as RawMutableHandleObject',
'js::rust::MutableHandleValue',
'js::jsapi::MutableHandleValue as RawMutableHandleValue',
+ 'js::jsapi::MutableHandleIdVector as RawMutableHandleIdVector',
'js::jsapi::ObjectOpResult',
'js::jsapi::PropertyDescriptor',
'js::jsapi::Rooted',
@@ -6010,7 +6019,7 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries
'js::jsval::PrivateValue',
'js::jsval::UndefinedValue',
'js::jsapi::UndefinedHandleValue',
- 'js::rust::wrappers::AppendToAutoIdVector',
+ 'js::rust::wrappers::AppendToIdVector',
'js::glue::CallJitGetterOp',
'js::glue::CallJitMethodOp',
'js::glue::CallJitSetterOp',
@@ -6060,8 +6069,10 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries
'crate::dom::bindings::reflector::DomObject',
'crate::dom::bindings::root::Dom',
'crate::dom::bindings::root::DomRoot',
- 'crate::dom::bindings::root::OptionalHeapSetter',
'crate::dom::bindings::root::DomSlice',
+ 'crate::dom::bindings::root::MaybeUnreflectedDom',
+ 'crate::dom::bindings::root::OptionalHeapSetter',
+ 'crate::dom::bindings::root::Root',
'crate::dom::bindings::utils::AsVoidPtr',
'crate::dom::bindings::utils::DOMClass',
'crate::dom::bindings::utils::DOMJSClass',
@@ -6086,7 +6097,6 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries
'crate::dom::bindings::utils::set_dictionary_property',
'crate::dom::bindings::utils::trace_global',
'crate::dom::bindings::trace::JSTraceable',
- 'crate::dom::bindings::trace::RootedTraceable',
'crate::dom::bindings::trace::RootedTraceableBox',
'crate::dom::bindings::callback::CallSetup',
'crate::dom::bindings::callback::CallbackContainer',
@@ -6818,7 +6828,7 @@ def type_needs_tracing(t):
def is_typed_array(t):
assert isinstance(t, IDLObject), (t, type(t))
- return t.isTypedArray() or t.isArrayBuffer() or t.isArrayBufferView() or t.isSharedArrayBuffer()
+ return t.isTypedArray() or t.isArrayBuffer() or t.isArrayBufferView()
def type_needs_auto_root(t):
diff --git a/components/script/dom/bindings/codegen/parser/WebIDL.py b/components/script/dom/bindings/codegen/parser/WebIDL.py
index b2e56c9deaf..223fd7efbb4 100644
--- a/components/script/dom/bindings/codegen/parser/WebIDL.py
+++ b/components/script/dom/bindings/codegen/parser/WebIDL.py
@@ -481,9 +481,6 @@ class IDLExposureMixins():
def isExposedInWindow(self):
return 'Window' in self.exposureSet
- def isExposedOnMainThread(self):
- return self.isExposedInWindow()
-
def isExposedInAnyWorker(self):
return len(self.getWorkerExposureSet()) > 0
@@ -2090,9 +2087,9 @@ class IDLType(IDLObject):
'domstring',
'bytestring',
'usvstring',
+ 'utf8string',
'jsstring',
'object',
- 'date',
'void',
# Funny stuff
'interface',
@@ -2109,15 +2106,17 @@ class IDLType(IDLObject):
IDLObject.__init__(self, location)
self.name = name
self.builtin = False
- self.clamp = False
self.treatNullAsEmpty = False
- self.enforceRange = False
+ self._clamp = False
+ self._enforceRange = False
+ self._allowShared = False
self._extendedAttrDict = {}
def __eq__(self, other):
return (other and self.builtin == other.builtin and self.name == other.name and
- self.clamp == other.clamp and self.enforceRange == other.enforceRange and
- self.treatNullAsEmpty == other.treatNullAsEmpty)
+ self._clamp == other.hasClamp() and self._enforceRange == other.hasEnforceRange() and
+ self.treatNullAsEmpty == other.treatNullAsEmpty and
+ self._allowShared == other.hasAllowShared())
def __ne__(self, other):
return not self == other
@@ -2125,6 +2124,14 @@ class IDLType(IDLObject):
def __str__(self):
return str(self.name)
+ def prettyName(self):
+ """
+ A name that looks like what this type is named in the IDL spec. By default
+ this is just our .name, but types that have more interesting spec
+ representations should override this.
+ """
+ return str(self.name)
+
def isType(self):
return True
@@ -2152,6 +2159,9 @@ class IDLType(IDLObject):
def isUSVString(self):
return False
+ def isUTF8String(self):
+ return False
+
def isJSString(self):
return False
@@ -2173,12 +2183,12 @@ class IDLType(IDLObject):
def isArrayBufferView(self):
return False
- def isSharedArrayBuffer(self):
- return False
-
def isTypedArray(self):
return False
+ def isBufferSource(self):
+ return self.isArrayBuffer() or self.isArrayBufferView() or self.isTypedArray()
+
def isCallbackInterface(self):
return False
@@ -2195,10 +2205,7 @@ class IDLType(IDLObject):
def isSpiderMonkeyInterface(self):
""" Returns a boolean indicating whether this type is an 'interface'
type that is implemented in SpiderMonkey. """
- return self.isInterface() and (self.isArrayBuffer() or
- self.isArrayBufferView() or
- self.isSharedArrayBuffer() or
- self.isTypedArray() or
+ return self.isInterface() and (self.isBufferSource() or
self.isReadableStream())
def isDictionary(self):
@@ -2210,9 +2217,6 @@ class IDLType(IDLObject):
def isAny(self):
return self.tag() == IDLType.Tags.any
- def isDate(self):
- return self.tag() == IDLType.Tags.date
-
def isObject(self):
return self.tag() == IDLType.Tags.object
@@ -2235,6 +2239,15 @@ class IDLType(IDLObject):
def isJSONType(self):
return False
+ def hasClamp(self):
+ return self._clamp
+
+ def hasEnforceRange(self):
+ return self._enforceRange
+
+ def hasAllowShared(self):
+ return self._allowShared
+
def tag(self):
assert False # Override me!
@@ -2342,10 +2355,7 @@ class IDLNullableType(IDLParametrizedType):
assert not innerType.isVoid()
assert not innerType == BuiltinTypes[IDLBuiltinType.Types.any]
- name = innerType.name
- if innerType.isComplete():
- name += "OrNull"
- IDLParametrizedType.__init__(self, location, name, innerType)
+ IDLParametrizedType.__init__(self, location, None, innerType)
def __eq__(self, other):
return isinstance(other, IDLNullableType) and self.inner == other.inner
@@ -2353,6 +2363,9 @@ class IDLNullableType(IDLParametrizedType):
def __str__(self):
return self.inner.__str__() + "OrNull"
+ def prettyName(self):
+ return self.inner.prettyName() + "?"
+
def nullable(self):
return True
@@ -2380,6 +2393,9 @@ class IDLNullableType(IDLParametrizedType):
def isUSVString(self):
return self.inner.isUSVString()
+ def isUTF8String(self):
+ return self.inner.isUTF8String()
+
def isJSString(self):
return self.inner.isJSString()
@@ -2410,9 +2426,6 @@ class IDLNullableType(IDLParametrizedType):
def isArrayBufferView(self):
return self.inner.isArrayBufferView()
- def isSharedArrayBuffer(self):
- return self.inner.isSharedArrayBuffer()
-
def isTypedArray(self):
return self.inner.isTypedArray()
@@ -2442,11 +2455,26 @@ class IDLNullableType(IDLParametrizedType):
def isJSONType(self):
return self.inner.isJSONType()
+ def hasClamp(self):
+ return self.inner.hasClamp()
+
+ def hasEnforceRange(self):
+ return self.inner.hasEnforceRange()
+
+ def hasAllowShared(self):
+ return self.inner.hasAllowShared()
+
+ def isComplete(self):
+ return self.name is not None
+
def tag(self):
return self.inner.tag()
def complete(self, scope):
- self.inner = self.inner.complete(scope)
+ if not self.inner.isComplete():
+ self.inner = self.inner.complete(scope)
+ assert self.inner.isComplete()
+
if self.inner.nullable():
raise WebIDLError("The inner type of a nullable type must not be "
"a nullable type",
@@ -2456,6 +2484,10 @@ class IDLNullableType(IDLParametrizedType):
raise WebIDLError("The inner type of a nullable type must not "
"be a union type that itself has a nullable "
"type as a member type", [self.location])
+ if self.inner.isDOMString():
+ if self.inner.treatNullAsEmpty:
+ raise WebIDLError("[TreatNullAs] not allowed on a nullable DOMString",
+ [self.location, self.inner.location])
self.name = self.inner.name + "OrNull"
return self
@@ -2469,6 +2501,13 @@ class IDLNullableType(IDLParametrizedType):
return False
return self.inner.isDistinguishableFrom(other)
+ def withExtendedAttributes(self, attrs):
+ # See https://github.com/heycam/webidl/issues/827#issuecomment-565131350
+ # Allowing extended attributes to apply to a nullable type is an intermediate solution.
+ # A potential longer term solution is to introduce a null type and get rid of nullables.
+ # For example, we could do `([Clamp] long or null) foo` in the future.
+ return IDLNullableType(self.location, self.inner.withExtendedAttributes(attrs))
+
class IDLSequenceType(IDLParametrizedType):
def __init__(self, location, parameterType):
@@ -2486,6 +2525,9 @@ class IDLSequenceType(IDLParametrizedType):
def __str__(self):
return self.inner.__str__() + "Sequence"
+ def prettyName(self):
+ return "sequence<%s>" % self.inner.prettyName()
+
def nullable(self):
return False
@@ -2504,6 +2546,9 @@ class IDLSequenceType(IDLParametrizedType):
def isUSVString(self):
return False
+ def isUTF8String(self):
+ return False
+
def isJSString(self):
return False
@@ -2540,8 +2585,7 @@ class IDLSequenceType(IDLParametrizedType):
# Just forward to the union; it'll deal
return other.isDistinguishableFrom(self)
return (other.isPrimitive() or other.isString() or other.isEnum() or
- other.isDate() or other.isInterface() or
- other.isDictionary() or
+ other.isInterface() or other.isDictionary() or
other.isCallback() or other.isRecord())
@@ -2565,6 +2609,9 @@ class IDLRecordType(IDLParametrizedType):
def __str__(self):
return self.keyType.__str__() + self.inner.__str__() + "Record"
+ def prettyName(self):
+ return "record<%s, %s>" % (self.keyType.prettyName(), self.inner.prettyName())
+
def isRecord(self):
return True
@@ -2592,7 +2639,7 @@ class IDLRecordType(IDLParametrizedType):
# Just forward to the union; it'll deal
return other.isDistinguishableFrom(self)
return (other.isPrimitive() or other.isString() or other.isEnum() or
- other.isDate() or other.isNonCallbackInterface() or other.isSequence())
+ other.isNonCallbackInterface() or other.isSequence())
def isExposedInAllOf(self, exposureSet):
return self.inner.unroll().isExposedInAllOf(exposureSet)
@@ -2614,6 +2661,9 @@ class IDLUnionType(IDLType):
assert self.isComplete()
return self.name.__hash__()
+ def prettyName(self):
+ return "(" + " or ".join(m.prettyName() for m in self.memberTypes) + ")"
+
def isVoid(self):
return False
@@ -2645,6 +2695,9 @@ class IDLUnionType(IDLType):
return typeName(type._identifier.object())
if isinstance(type, IDLObjectWithIdentifier):
return typeName(type.identifier)
+ if isinstance(type, IDLBuiltinType) and type.hasAllowShared():
+ assert type.isBufferSource()
+ return "MaybeShared" + type.name
return type.name
for (i, type) in enumerate(self.memberTypes):
@@ -2768,6 +2821,9 @@ class IDLTypedefType(IDLType):
def isUSVString(self):
return self.inner.isUSVString()
+ def isUTF8String(self):
+ return self.inner.isUTF8String()
+
def isJSString(self):
return self.inner.isJSString()
@@ -2795,9 +2851,6 @@ class IDLTypedefType(IDLType):
def isArrayBufferView(self):
return self.inner.isArrayBufferView()
- def isSharedArrayBuffer(self):
- return self.inner.isSharedArrayBuffer()
-
def isTypedArray(self):
return self.inner.isTypedArray()
@@ -2901,6 +2954,9 @@ class IDLWrapperType(IDLType):
def isUSVString(self):
return False
+ def isUTF8String(self):
+ return False
+
def isJSString(self):
return False
@@ -2976,11 +3032,11 @@ class IDLWrapperType(IDLType):
if self.isEnum():
return (other.isPrimitive() or other.isInterface() or other.isObject() or
other.isCallback() or other.isDictionary() or
- other.isSequence() or other.isRecord() or other.isDate())
+ other.isSequence() or other.isRecord())
if self.isDictionary() and other.nullable():
return False
if (other.isPrimitive() or other.isString() or other.isEnum() or
- other.isDate() or other.isSequence()):
+ other.isSequence()):
return True
if self.isDictionary():
return other.isNonCallbackInterface()
@@ -3052,6 +3108,9 @@ class IDLPromiseType(IDLParametrizedType):
def __str__(self):
return self.inner.__str__() + "Promise"
+ def prettyName(self):
+ return "Promise<%s>" % self.inner.prettyName()
+
def isPromise(self):
return True
@@ -3104,14 +3163,13 @@ class IDLBuiltinType(IDLType):
'domstring',
'bytestring',
'usvstring',
+ 'utf8string',
'jsstring',
'object',
- 'date',
'void',
# Funny stuff
'ArrayBuffer',
'ArrayBufferView',
- 'SharedArrayBuffer',
'Int8Array',
'Uint8Array',
'Uint8ClampedArray',
@@ -3142,13 +3200,12 @@ class IDLBuiltinType(IDLType):
Types.domstring: IDLType.Tags.domstring,
Types.bytestring: IDLType.Tags.bytestring,
Types.usvstring: IDLType.Tags.usvstring,
+ Types.utf8string: IDLType.Tags.utf8string,
Types.jsstring: IDLType.Tags.jsstring,
Types.object: IDLType.Tags.object,
- Types.date: IDLType.Tags.date,
Types.void: IDLType.Tags.void,
Types.ArrayBuffer: IDLType.Tags.interface,
Types.ArrayBufferView: IDLType.Tags.interface,
- Types.SharedArrayBuffer: IDLType.Tags.interface,
Types.Int8Array: IDLType.Tags.interface,
Types.Uint8Array: IDLType.Tags.interface,
Types.Uint8ClampedArray: IDLType.Tags.interface,
@@ -3161,11 +3218,48 @@ class IDLBuiltinType(IDLType):
Types.ReadableStream: IDLType.Tags.interface,
}
+ PrettyNames = {
+ Types.byte: "byte",
+ Types.octet: "octet",
+ Types.short: "short",
+ Types.unsigned_short: "unsigned short",
+ Types.long: "long",
+ Types.unsigned_long: "unsigned long",
+ Types.long_long: "long long",
+ Types.unsigned_long_long: "unsigned long long",
+ Types.boolean: "boolean",
+ Types.unrestricted_float: "unrestricted float",
+ Types.float: "float",
+ Types.unrestricted_double: "unrestricted double",
+ Types.double: "double",
+ Types.any: "any",
+ Types.domstring: "DOMString",
+ Types.bytestring: "ByteString",
+ Types.usvstring: "USVString",
+ Types.utf8string: "USVString", # That's what it is in spec terms
+ Types.jsstring: "USVString", # Again, that's what it is in spec terms
+ Types.object: "object",
+ Types.void: "void",
+ Types.ArrayBuffer: "ArrayBuffer",
+ Types.ArrayBufferView: "ArrayBufferView",
+ Types.Int8Array: "Int8Array",
+ Types.Uint8Array: "Uint8Array",
+ Types.Uint8ClampedArray: "Uint8ClampedArray",
+ Types.Int16Array: "Int16Array",
+ Types.Uint16Array: "Uint16Array",
+ Types.Int32Array: "Int32Array",
+ Types.Uint32Array: "Uint32Array",
+ Types.Float32Array: "Float32Array",
+ Types.Float64Array: "Float64Array",
+ Types.ReadableStream: "ReadableStream",
+ }
+
def __init__(self, location, name, type, clamp=False, enforceRange=False, treatNullAsEmpty=False,
- attrLocation=[]):
+ allowShared=False, attrLocation=[]):
"""
- The mutually exclusive clamp/enforceRange/treatNullAsEmpty arguments are used to create instances
- of this type with the appropriate attributes attached. Use .clamped(), .rangeEnforced(), and .treatNullAs().
+ The mutually exclusive clamp/enforceRange/treatNullAsEmpty/allowShared arguments are used
+ to create instances of this type with the appropriate attributes attached. Use .clamped(),
+ .rangeEnforced(), .withTreatNullAs() and .withAllowShared().
attrLocation is an array of source locations of these attributes for error reporting.
"""
@@ -3175,24 +3269,40 @@ class IDLBuiltinType(IDLType):
self._clamped = None
self._rangeEnforced = None
self._withTreatNullAs = None
- if self.isNumeric():
+ self._withAllowShared = None;
+ if self.isInteger():
if clamp:
- self.clamp = True
+ self._clamp = True
self.name = "Clamped" + self.name
self._extendedAttrDict["Clamp"] = True
elif enforceRange:
- self.enforceRange = True
+ self._enforceRange = True
self.name = "RangeEnforced" + self.name
self._extendedAttrDict["EnforceRange"] = True
elif clamp or enforceRange:
- raise WebIDLError("Non-numeric types cannot be [Clamp] or [EnforceRange]", attrLocation)
- if self.isDOMString():
+ raise WebIDLError("Non-integer types cannot be [Clamp] or [EnforceRange]", attrLocation)
+ if self.isDOMString() or self.isUTF8String():
if treatNullAsEmpty:
self.treatNullAsEmpty = True
self.name = "NullIsEmpty" + self.name
self._extendedAttrDict["TreatNullAs"] = ["EmptyString"]
elif treatNullAsEmpty:
raise WebIDLError("Non-string types cannot be [TreatNullAs]", attrLocation)
+ if self.isBufferSource():
+ if allowShared:
+ self._allowShared = True
+ self._extendedAttrDict["AllowShared"] = True
+ elif allowShared:
+ raise WebIDLError("Types that are not buffer source types cannot be [AllowShared]", attrLocation)
+
+ def __str__(self):
+ if self._allowShared:
+ assert self.isBufferSource()
+ return "MaybeShared" + str(self.name)
+ return str(self.name)
+
+ def prettyName(self):
+ return IDLBuiltinType.PrettyNames[self._typeTag]
def clamped(self, attrLocation):
if not self._clamped:
@@ -3215,6 +3325,13 @@ class IDLBuiltinType(IDLType):
attrLocation=attrLocation)
return self._withTreatNullAs
+ def withAllowShared(self, attrLocation):
+ if not self._withAllowShared:
+ self._withAllowShared = IDLBuiltinType(self.location, self.name,
+ self._typeTag, allowShared=True,
+ attrLocation=attrLocation)
+ return self._withAllowShared
+
def isPrimitive(self):
return self._typeTag <= IDLBuiltinType.Types.double
@@ -3228,6 +3345,7 @@ class IDLBuiltinType(IDLType):
return (self._typeTag == IDLBuiltinType.Types.domstring or
self._typeTag == IDLBuiltinType.Types.bytestring or
self._typeTag == IDLBuiltinType.Types.usvstring or
+ self._typeTag == IDLBuiltinType.Types.utf8string or
self._typeTag == IDLBuiltinType.Types.jsstring)
def isByteString(self):
@@ -3239,6 +3357,9 @@ class IDLBuiltinType(IDLType):
def isUSVString(self):
return self._typeTag == IDLBuiltinType.Types.usvstring
+ def isUTF8String(self):
+ return self._typeTag == IDLBuiltinType.Types.utf8string
+
def isJSString(self):
return self._typeTag == IDLBuiltinType.Types.jsstring
@@ -3251,9 +3372,6 @@ class IDLBuiltinType(IDLType):
def isArrayBufferView(self):
return self._typeTag == IDLBuiltinType.Types.ArrayBufferView
- def isSharedArrayBuffer(self):
- return self._typeTag == IDLBuiltinType.Types.SharedArrayBuffer
-
def isTypedArray(self):
return (self._typeTag >= IDLBuiltinType.Types.Int8Array and
self._typeTag <= IDLBuiltinType.Types.Float64Array)
@@ -3267,7 +3385,6 @@ class IDLBuiltinType(IDLType):
# all of it internally.
return (self.isArrayBuffer() or
self.isArrayBufferView() or
- self.isSharedArrayBuffer() or
self.isTypedArray() or
self.isReadableStream())
@@ -3305,27 +3422,22 @@ class IDLBuiltinType(IDLType):
return (other.isNumeric() or other.isString() or other.isEnum() or
other.isInterface() or other.isObject() or
other.isCallback() or other.isDictionary() or
- other.isSequence() or other.isRecord() or other.isDate())
+ other.isSequence() or other.isRecord())
if self.isNumeric():
return (other.isBoolean() or other.isString() or other.isEnum() or
other.isInterface() or other.isObject() or
other.isCallback() or other.isDictionary() or
- other.isSequence() or other.isRecord() or other.isDate())
+ other.isSequence() or other.isRecord())
if self.isString():
return (other.isPrimitive() or other.isInterface() or
other.isObject() or
other.isCallback() or other.isDictionary() or
- other.isSequence() or other.isRecord() or other.isDate())
+ other.isSequence() or other.isRecord())
if self.isAny():
# Can't tell "any" apart from anything
return False
if self.isObject():
return other.isPrimitive() or other.isString() or other.isEnum()
- if self.isDate():
- return (other.isPrimitive() or other.isString() or other.isEnum() or
- other.isInterface() or other.isCallback() or
- other.isDictionary() or other.isSequence() or
- other.isRecord())
if self.isVoid():
return not other.isVoid()
# Not much else we could be!
@@ -3333,12 +3445,11 @@ class IDLBuiltinType(IDLType):
# Like interfaces, but we know we're not a callback
return (other.isPrimitive() or other.isString() or other.isEnum() or
other.isCallback() or other.isDictionary() or
- other.isSequence() or other.isRecord() or other.isDate() or
+ other.isSequence() or other.isRecord() or
(other.isInterface() and (
# ArrayBuffer is distinguishable from everything
# that's not an ArrayBuffer or a callback interface
(self.isArrayBuffer() and not other.isArrayBuffer()) or
- (self.isSharedArrayBuffer() and not other.isSharedArrayBuffer()) or
(self.isReadableStream() and not other.isReadableStream()) or
# ArrayBufferView is distinguishable from everything
# that's not an ArrayBufferView or typed array.
@@ -3361,7 +3472,7 @@ class IDLBuiltinType(IDLType):
if not attribute.noArguments():
raise WebIDLError("[Clamp] must take no arguments",
[attribute.location])
- if ret.enforceRange or self.enforceRange:
+ if ret.hasEnforceRange() or self._enforceRange:
raise WebIDLError("[EnforceRange] and [Clamp] are mutually exclusive",
[self.location, attribute.location])
ret = self.clamped([self.location, attribute.location])
@@ -3369,17 +3480,17 @@ class IDLBuiltinType(IDLType):
if not attribute.noArguments():
raise WebIDLError("[EnforceRange] must take no arguments",
[attribute.location])
- if ret.clamp or self.clamp:
+ if ret.hasClamp() or self._clamp:
raise WebIDLError("[EnforceRange] and [Clamp] are mutually exclusive",
[self.location, attribute.location])
ret = self.rangeEnforced([self.location, attribute.location])
elif identifier == "TreatNullAs":
- if not self.isDOMString():
- raise WebIDLError("[TreatNullAs] only allowed on DOMStrings",
+ if not (self.isDOMString() or self.isUTF8String()):
+ raise WebIDLError("[TreatNullAs] only allowed on DOMStrings and UTF8Strings",
[self.location, attribute.location])
assert not self.nullable()
if not attribute.hasValue():
- raise WebIDLError("[TreatNullAs] must take an identifier argument"
+ raise WebIDLError("[TreatNullAs] must take an identifier argument",
[attribute.location])
value = attribute.value()
if value != 'EmptyString':
@@ -3387,6 +3498,15 @@ class IDLBuiltinType(IDLType):
"'EmptyString', not '%s'" % value,
[attribute.location])
ret = self.withTreatNullAs([self.location, attribute.location])
+ elif identifier == "AllowShared":
+ if not attribute.noArguments():
+ raise WebIDLError("[AllowShared] must take no arguments",
+ [attribute.location])
+ if not self.isBufferSource():
+ raise WebIDLError("[AllowShared] only allowed on buffer source types",
+ [self.location, attribute.location])
+ ret = self.withAllowShared([self.location, attribute.location])
+
else:
raise WebIDLError("Unhandled extended attribute on type",
[self.location, attribute.location])
@@ -3444,15 +3564,15 @@ BuiltinTypes = {
IDLBuiltinType.Types.usvstring:
IDLBuiltinType(BuiltinLocation("<builtin type>"), "USVString",
IDLBuiltinType.Types.usvstring),
+ IDLBuiltinType.Types.utf8string:
+ IDLBuiltinType(BuiltinLocation("<builtin type>"), "UTF8String",
+ IDLBuiltinType.Types.utf8string),
IDLBuiltinType.Types.jsstring:
IDLBuiltinType(BuiltinLocation("<builtin type>"), "JSString",
IDLBuiltinType.Types.jsstring),
IDLBuiltinType.Types.object:
IDLBuiltinType(BuiltinLocation("<builtin type>"), "Object",
IDLBuiltinType.Types.object),
- IDLBuiltinType.Types.date:
- IDLBuiltinType(BuiltinLocation("<builtin type>"), "Date",
- IDLBuiltinType.Types.date),
IDLBuiltinType.Types.void:
IDLBuiltinType(BuiltinLocation("<builtin type>"), "Void",
IDLBuiltinType.Types.void),
@@ -3462,9 +3582,6 @@ BuiltinTypes = {
IDLBuiltinType.Types.ArrayBufferView:
IDLBuiltinType(BuiltinLocation("<builtin type>"), "ArrayBufferView",
IDLBuiltinType.Types.ArrayBufferView),
- IDLBuiltinType.Types.SharedArrayBuffer:
- IDLBuiltinType(BuiltinLocation("<builtin type>"), "SharedArrayBuffer",
- IDLBuiltinType.Types.SharedArrayBuffer),
IDLBuiltinType.Types.Int8Array:
IDLBuiltinType(BuiltinLocation("<builtin type>"), "Int8Array",
IDLBuiltinType.Types.Int8Array),
@@ -3613,8 +3730,9 @@ class IDLValue(IDLObject):
# TreatNullAsEmpty is a different type for resolution reasons,
# however once you have a value it doesn't matter
return self
- elif self.type.isString() and (type.isByteString() or type.isJSString()):
- # Allow ByteStrings and JSStrings to use a default value like DOMString.
+ elif self.type.isString() and (type.isByteString() or type.isJSString() or type.isUTF8String()):
+ # Allow ByteStrings, UTF8String, and JSStrings to use a default
+ # value like DOMString.
# No coercion is required as Codegen.py will handle the
# extra steps. We want to make sure that our string contains
# only valid characters, so we check that here.
@@ -4307,8 +4425,9 @@ class IDLAttribute(IDLInterfaceMember):
assert not isinstance(t.name, IDLUnresolvedIdentifier)
self.type = t
- if self.readonly and (self.type.clamp or self.type.enforceRange or self.type.treatNullAsEmpty):
- raise WebIDLError("A readonly attribute cannot be [Clamp] or [EnforceRange]",
+ if self.readonly and (self.type.hasClamp() or self.type.hasEnforceRange() or
+ self.type.hasAllowShared() or self.type.treatNullAsEmpty):
+ raise WebIDLError("A readonly attribute cannot be [Clamp] or [EnforceRange] or [AllowShared]",
[self.location])
if self.type.isDictionary() and not self.getExtendedAttribute("Cached"):
raise WebIDLError("An attribute cannot be of a dictionary type",
@@ -4709,7 +4828,7 @@ class IDLArgument(IDLObjectWithIdentifier):
for attribute in attrs:
identifier = attribute.identifier()
if self.allowTypeAttributes and (identifier == "EnforceRange" or identifier == "Clamp" or
- identifier == "TreatNullAs"):
+ identifier == "TreatNullAs" or identifier == "AllowShared"):
self.type = self.type.withExtendedAttributes([attribute])
elif identifier == "TreatNonCallableAsNull":
self._allowTreatNonCallableAsNull = True
@@ -4879,8 +4998,7 @@ class IDLCallbackType(IDLType):
# Just forward to the union; it'll deal
return other.isDistinguishableFrom(self)
return (other.isPrimitive() or other.isString() or other.isEnum() or
- other.isNonCallbackInterface() or other.isDate() or
- other.isSequence())
+ other.isNonCallbackInterface() or other.isSequence())
def _getDependentObjects(self):
return self.callback._getDependentObjects()
@@ -5475,7 +5593,9 @@ class IDLConstructor(IDLMethod):
identifier == "ChromeOnly" or
identifier == "NewObject" or
identifier == "SecureContext" or
- identifier == "Throws"):
+ identifier == "Throws" or
+ identifier == "Func" or
+ identifier == "Pref"):
IDLMethod.handleExtendedAttribute(self, attr)
elif identifier == "HTMLConstructor":
if not attr.noArguments():
@@ -5675,11 +5795,11 @@ class Tokenizer(object):
"optional": "OPTIONAL",
"...": "ELLIPSIS",
"::": "SCOPE",
- "Date": "DATE",
"DOMString": "DOMSTRING",
"ByteString": "BYTESTRING",
"USVString": "USVSTRING",
"JSString": "JSSTRING",
+ "UTF8String": "UTF8STRING",
"any": "ANY",
"boolean": "BOOLEAN",
"byte": "BYTE",
@@ -5709,7 +5829,6 @@ class Tokenizer(object):
"<": "LT",
">": "GT",
"ArrayBuffer": "ARRAYBUFFER",
- "SharedArrayBuffer": "SHAREDARRAYBUFFER",
"or": "OR",
"maplike": "MAPLIKE",
"setlike": "SETLIKE",
@@ -6939,10 +7058,10 @@ class Parser(Tokenizer):
| EQUALS
| GT
| QUESTIONMARK
- | DATE
| DOMSTRING
| BYTESTRING
| USVSTRING
+ | UTF8STRING
| JSSTRING
| PROMISE
| ANY
@@ -7050,7 +7169,6 @@ class Parser(Tokenizer):
"""
DistinguishableType : PrimitiveType Null
| ARRAYBUFFER Null
- | SHAREDARRAYBUFFER Null
| READABLESTREAM Null
| OBJECT Null
"""
@@ -7058,8 +7176,6 @@ class Parser(Tokenizer):
type = BuiltinTypes[IDLBuiltinType.Types.object]
elif p[1] == "ArrayBuffer":
type = BuiltinTypes[IDLBuiltinType.Types.ArrayBuffer]
- elif p[1] == "SharedArrayBuffer":
- type = BuiltinTypes[IDLBuiltinType.Types.SharedArrayBuffer]
elif p[1] == "ReadableStream":
type = BuiltinTypes[IDLBuiltinType.Types.ReadableStream]
else:
@@ -7122,13 +7238,6 @@ class Parser(Tokenizer):
type = IDLUnresolvedType(self.getLocation(p, 1), p[1])
p[0] = self.handleNullable(type, p[2])
- def p_DistinguishableTypeDate(self, p):
- """
- DistinguishableType : DATE Null
- """
- p[0] = self.handleNullable(BuiltinTypes[IDLBuiltinType.Types.date],
- p[2])
-
def p_ConstType(self, p):
"""
ConstType : PrimitiveType
@@ -7215,6 +7324,12 @@ class Parser(Tokenizer):
"""
p[0] = IDLBuiltinType.Types.usvstring
+ def p_BuiltinStringTypeUTF8String(self, p):
+ """
+ BuiltinStringType : UTF8STRING
+ """
+ p[0] = IDLBuiltinType.Types.utf8string
+
def p_BuiltinStringTypeJSString(self, p):
"""
BuiltinStringType : JSSTRING
@@ -7354,7 +7469,13 @@ class Parser(Tokenizer):
IdentifierList : IDENTIFIER Identifiers
"""
idents = list(p[2])
- idents.insert(0, p[1])
+ # This is only used for identifier-list-valued extended attributes, and if
+ # we're going to restrict to IDENTIFIER here we should at least allow
+ # escaping with leading '_' as usual for identifiers.
+ ident = p[1]
+ if ident[0] == '_':
+ ident = ident[1:]
+ idents.insert(0, ident)
p[0] = idents
def p_IdentifiersList(self, p):
@@ -7362,7 +7483,13 @@ class Parser(Tokenizer):
Identifiers : COMMA IDENTIFIER Identifiers
"""
idents = list(p[3])
- idents.insert(0, p[2])
+ # This is only used for identifier-list-valued extended attributes, and if
+ # we're going to restrict to IDENTIFIER here we should at least allow
+ # escaping with leading '_' as usual for identifiers.
+ ident = p[2]
+ if ident[0] == '_':
+ ident = ident[1:]
+ idents.insert(0, ident)
p[0] = idents
def p_IdentifiersEmpty(self, p):
diff --git a/components/script/dom/bindings/codegen/parser/ext-attribute-no-value-error.patch b/components/script/dom/bindings/codegen/parser/ext-attribute-no-value-error.patch
new file mode 100644
index 00000000000..210134d8ca6
--- /dev/null
+++ b/components/script/dom/bindings/codegen/parser/ext-attribute-no-value-error.patch
@@ -0,0 +1,11 @@
+--- WebIDL.py
++++ WebIDL.py
+@@ -3490,7 +3490,7 @@ class IDLBuiltinType(IDLType):
+ [self.location, attribute.location])
+ assert not self.nullable()
+ if not attribute.hasValue():
+- raise WebIDLError("[TreatNullAs] must take an identifier argument"
++ raise WebIDLError("[TreatNullAs] must take an identifier argument",
+ [attribute.location])
+ value = attribute.value()
+ if value != 'EmptyString':
diff --git a/components/script/dom/bindings/codegen/parser/tests/test_attributes_on_types.py b/components/script/dom/bindings/codegen/parser/tests/test_attributes_on_types.py
index 43daca3c453..ff08791d16f 100644
--- a/components/script/dom/bindings/codegen/parser/tests/test_attributes_on_types.py
+++ b/components/script/dom/bindings/codegen/parser/tests/test_attributes_on_types.py
@@ -25,6 +25,12 @@ def WebIDLTest(parser, harness):
void method2(optional [EnforceRange] long foo, optional [Clamp] long bar,
optional [TreatNullAs=EmptyString] DOMString baz);
};
+ interface C {
+ attribute [EnforceRange] long? foo;
+ attribute [Clamp] long? bar;
+ void method([EnforceRange] long? foo, [Clamp] long? bar);
+ void method2(optional [EnforceRange] long? foo, optional [Clamp] long? bar);
+ };
interface Setlike {
setlike<[Clamp] long>;
};
@@ -41,29 +47,105 @@ def WebIDLTest(parser, harness):
harness.ok(not threw, "Should not have thrown on parsing normal")
if not threw:
- harness.check(results[0].innerType.enforceRange, True, "Foo is [EnforceRange]")
- harness.check(results[1].innerType.clamp, True, "Bar is [Clamp]")
+ harness.check(results[0].innerType.hasEnforceRange(), True, "Foo is [EnforceRange]")
+ harness.check(results[1].innerType.hasClamp(), True, "Bar is [Clamp]")
harness.check(results[2].innerType.treatNullAsEmpty, True, "Baz is [TreatNullAs=EmptyString]")
A = results[3]
- harness.check(A.members[0].type.enforceRange, True, "A.a is [EnforceRange]")
- harness.check(A.members[1].type.clamp, True, "A.b is [Clamp]")
- harness.check(A.members[2].type.enforceRange, True, "A.c is [EnforceRange]")
- harness.check(A.members[3].type.enforceRange, True, "A.d is [EnforceRange]")
+ harness.check(A.members[0].type.hasEnforceRange(), True, "A.a is [EnforceRange]")
+ harness.check(A.members[1].type.hasClamp(), True, "A.b is [Clamp]")
+ harness.check(A.members[2].type.hasEnforceRange(), True, "A.c is [EnforceRange]")
+ harness.check(A.members[3].type.hasEnforceRange(), True, "A.d is [EnforceRange]")
B = results[4]
- harness.check(B.members[0].type.enforceRange, True, "B.typedefFoo is [EnforceRange]")
- harness.check(B.members[1].type.enforceRange, True, "B.foo is [EnforceRange]")
- harness.check(B.members[2].type.clamp, True, "B.bar is [Clamp]")
+ harness.check(B.members[0].type.hasEnforceRange(), True, "B.typedefFoo is [EnforceRange]")
+ harness.check(B.members[1].type.hasEnforceRange(), True, "B.foo is [EnforceRange]")
+ harness.check(B.members[2].type.hasClamp(), True, "B.bar is [Clamp]")
harness.check(B.members[3].type.treatNullAsEmpty, True, "B.baz is [TreatNullAs=EmptyString]")
method = B.members[4].signatures()[0][1]
- harness.check(method[0].type.enforceRange, True, "foo argument of method is [EnforceRange]")
- harness.check(method[1].type.clamp, True, "bar argument of method is [Clamp]")
+ harness.check(method[0].type.hasEnforceRange(), True, "foo argument of method is [EnforceRange]")
+ harness.check(method[1].type.hasClamp(), True, "bar argument of method is [Clamp]")
harness.check(method[2].type.treatNullAsEmpty, True, "baz argument of method is [TreatNullAs=EmptyString]")
method2 = B.members[5].signatures()[0][1]
- harness.check(method[0].type.enforceRange, True, "foo argument of method2 is [EnforceRange]")
- harness.check(method[1].type.clamp, True, "bar argument of method2 is [Clamp]")
+ harness.check(method[0].type.hasEnforceRange(), True, "foo argument of method2 is [EnforceRange]")
+ harness.check(method[1].type.hasClamp(), True, "bar argument of method2 is [Clamp]")
harness.check(method[2].type.treatNullAsEmpty, True, "baz argument of method2 is [TreatNullAs=EmptyString]")
+ C = results[5]
+ harness.ok(C.members[0].type.nullable(), "C.foo is nullable")
+ harness.ok(C.members[0].type.hasEnforceRange(), "C.foo has [EnforceRange]")
+ harness.ok(C.members[1].type.nullable(), "C.bar is nullable")
+ harness.ok(C.members[1].type.hasClamp(), "C.bar has [Clamp]")
+ method = C.members[2].signatures()[0][1]
+ harness.ok(method[0].type.nullable(), "foo argument of method is nullable")
+ harness.ok(method[0].type.hasEnforceRange(), "foo argument of method has [EnforceRange]")
+ harness.ok(method[1].type.nullable(), "bar argument of method is nullable")
+ harness.ok(method[1].type.hasClamp(), "bar argument of method has [Clamp]")
+ method2 = C.members[3].signatures()[0][1]
+ harness.ok(method2[0].type.nullable(), "foo argument of method2 is nullable")
+ harness.ok(method2[0].type.hasEnforceRange(), "foo argument of method2 has [EnforceRange]")
+ harness.ok(method2[1].type.nullable(), "bar argument of method2 is nullable")
+ harness.ok(method2[1].type.hasClamp(), "bar argument of method2 has [Clamp]")
+
+ # Test [AllowShared]
+ parser = parser.reset()
+ threw = False
+ try:
+ parser.parse("""
+ typedef [AllowShared] ArrayBufferView Foo;
+ dictionary A {
+ required [AllowShared] ArrayBufferView a;
+ [ChromeOnly, AllowShared] ArrayBufferView b;
+ Foo c;
+ };
+ interface B {
+ attribute Foo typedefFoo;
+ attribute [AllowShared] ArrayBufferView foo;
+ void method([AllowShared] ArrayBufferView foo);
+ void method2(optional [AllowShared] ArrayBufferView foo);
+ };
+ interface C {
+ attribute [AllowShared] ArrayBufferView? foo;
+ void method([AllowShared] ArrayBufferView? foo);
+ void method2(optional [AllowShared] ArrayBufferView? foo);
+ };
+ interface Setlike {
+ setlike<[AllowShared] ArrayBufferView>;
+ };
+ interface Maplike {
+ maplike<[Clamp] long, [AllowShared] ArrayBufferView>;
+ };
+ interface Iterable {
+ iterable<[Clamp] long, [AllowShared] ArrayBufferView>;
+ };
+ """)
+ results = parser.finish()
+ except:
+ threw = True
+
+ harness.ok(not threw, "Should not have thrown on parsing normal")
+ if not threw:
+ harness.ok(results[0].innerType.hasAllowShared(), "Foo is [AllowShared]")
+ A = results[1]
+ harness.ok(A.members[0].type.hasAllowShared(), "A.a is [AllowShared]")
+ harness.ok(A.members[1].type.hasAllowShared(), "A.b is [AllowShared]")
+ harness.ok(A.members[2].type.hasAllowShared(), "A.c is [AllowShared]")
+ B = results[2]
+ harness.ok(B.members[0].type.hasAllowShared(), "B.typedefFoo is [AllowShared]")
+ harness.ok(B.members[1].type.hasAllowShared(), "B.foo is [AllowShared]")
+ method = B.members[2].signatures()[0][1]
+ harness.ok(method[0].type.hasAllowShared(), "foo argument of method is [AllowShared]")
+ method2 = B.members[3].signatures()[0][1]
+ harness.ok(method2[0].type.hasAllowShared(), "foo argument of method2 is [AllowShared]")
+ C = results[3]
+ harness.ok(C.members[0].type.nullable(), "C.foo is nullable")
+ harness.ok(C.members[0].type.hasAllowShared(), "C.foo is [AllowShared]")
+ method = C.members[1].signatures()[0][1]
+ harness.ok(method[0].type.nullable(), "foo argument of method is nullable")
+ harness.ok(method[0].type.hasAllowShared(), "foo argument of method is [AllowShared]")
+ method2 = C.members[2].signatures()[0][1]
+ harness.ok(method2[0].type.nullable(), "foo argument of method2 is nullable")
+ harness.ok(method2[0].type.hasAllowShared(), "foo argument of method2 is [AllowShared]")
- ATTRIBUTES = [("[Clamp]", "long"), ("[EnforceRange]", "long"), ("[TreatNullAs=EmptyString]", "DOMString")]
+ ATTRIBUTES = [("[Clamp]", "long"), ("[EnforceRange]", "long"),
+ ("[TreatNullAs=EmptyString]", "DOMString"), ("[AllowShared]", "ArrayBufferView")]
TEMPLATES = [
("required dictionary members", """
dictionary Foo {
@@ -93,7 +175,54 @@ def WebIDLTest(parser, harness):
readonly attribute Bar baz;
};
typedef %s %s Bar;
- """)
+ """),
+ ("method", """
+ interface Foo {
+ %s %s foo();
+ };
+ """),
+ ("interface","""
+ %s
+ interface Foo {
+ attribute %s foo;
+ };
+ """),
+ ("partial interface","""
+ interface Foo {
+ void foo();
+ };
+ %s
+ partial interface Foo {
+ attribute %s bar;
+ };
+ """),
+ ("interface mixin","""
+ %s
+ interface mixin Foo {
+ attribute %s foo;
+ };
+ """),
+ ("namespace","""
+ %s
+ namespace Foo {
+ attribute %s foo;
+ };
+ """),
+ ("partial namespace","""
+ namespace Foo {
+ void foo();
+ };
+ %s
+ partial namespace Foo {
+ attribute %s bar;
+ };
+ """),
+ ("dictionary","""
+ %s
+ dictionary Foo {
+ %s foo;
+ };
+ """)
];
for (name, template) in TEMPLATES:
@@ -167,55 +296,91 @@ def WebIDLTest(parser, harness):
harness.ok(threw, "Should not allow mixing [Clamp] and [EnforceRange] via typedefs")
+ TYPES = ["DOMString", "unrestricted float", "float", "unrestricted double", "double"]
+
+ for type in TYPES:
+ parser = parser.reset()
+ threw = False
+ try:
+ parser.parse("""
+ typedef [Clamp] %s Foo;
+ """ % type)
+ parser.finish()
+ except:
+ threw = True
+
+ harness.ok(threw, "Should not allow [Clamp] on %s" % type)
+
+ parser = parser.reset()
+ threw = False
+ try:
+ parser.parse("""
+ typedef [EnforceRange] %s Foo;
+ """ % type)
+ parser.finish()
+ except:
+ threw = True
+
+ harness.ok(threw, "Should not allow [EnforceRange] on %s" % type)
+
+
parser = parser.reset()
threw = False
try:
parser.parse("""
- typedef [Clamp] DOMString Foo;
+ typedef [TreatNullAs=EmptyString] long Foo;
""")
parser.finish()
except:
threw = True
- harness.ok(threw, "Should not allow [Clamp] on DOMString")
-
+ harness.ok(threw, "Should not allow [TreatNullAs] on long")
parser = parser.reset()
threw = False
try:
parser.parse("""
- typedef [EnforceRange] DOMString Foo;
+ typedef [TreatNullAs=EmptyString] JSString Foo;
""")
parser.finish()
except:
threw = True
- harness.ok(threw, "Should not allow [EnforceRange] on DOMString")
-
+ harness.ok(threw, "Should not allow [TreatNullAs] on JSString")
parser = parser.reset()
threw = False
try:
parser.parse("""
- typedef [TreatNullAs=EmptyString] long Foo;
+ typedef [TreatNullAs=EmptyString] DOMString? Foo;
""")
parser.finish()
except:
threw = True
- harness.ok(threw, "Should not allow [TreatNullAs] on long")
+ harness.ok(threw, "Should not allow [TreatNullAs] on nullable DOMString")
parser = parser.reset()
threw = False
try:
parser.parse("""
- typedef [TreatNullAs=EmptyString] JSString Foo;
+ typedef [AllowShared] DOMString Foo;
""")
- parser.finish()
+ results = parser.finish()
except:
threw = True
+ harness.ok(threw, "[AllowShared] only allowed on buffer source types")
- harness.ok(threw, "Should not allow [TreatNullAs] on JSString")
+ parser = parser.reset()
+ threw = False
+ try:
+ parser.parse("""
+ typedef [AllowShared=something] ArrayBufferView Foo;
+ """)
+ results = parser.finish()
+ except:
+ threw = True
+ harness.ok(threw, "[AllowShared] must take no arguments")
parser = parser.reset()
threw = False
@@ -230,7 +395,7 @@ def WebIDLTest(parser, harness):
except:
threw = True
harness.ok(not threw, "Should allow type attributes on unresolved types")
- harness.check(results[0].members[0].signatures()[0][1][0].type.clamp, True,
+ harness.check(results[0].members[0].signatures()[0][1][0].type.hasClamp(), True,
"Unresolved types with type attributes should correctly resolve with attributes")
parser = parser.reset()
@@ -246,5 +411,5 @@ def WebIDLTest(parser, harness):
except:
threw = True
harness.ok(not threw, "Should allow type attributes on typedefs")
- harness.check(results[0].members[0].signatures()[0][1][0].type.clamp, True,
+ harness.check(results[0].members[0].signatures()[0][1][0].type.hasClamp(), True,
"Unresolved types that resolve to typedefs with attributes should correctly resolve with attributes")
diff --git a/components/script/dom/bindings/codegen/parser/tests/test_constructor.py b/components/script/dom/bindings/codegen/parser/tests/test_constructor.py
index 721f9c2089e..83e1f4fc34f 100644
--- a/components/script/dom/bindings/codegen/parser/tests/test_constructor.py
+++ b/components/script/dom/bindings/codegen/parser/tests/test_constructor.py
@@ -11,9 +11,9 @@ def WebIDLTest(parser, harness):
harness.check(argument.variadic, variadic, "Argument has the right variadic value")
def checkMethod(method, QName, name, signatures,
- static=True, getter=False, setter=False,
- deleter=False, legacycaller=False, stringifier=False,
- chromeOnly=False, htmlConstructor=False):
+ static=True, getter=False, setter=False, deleter=False,
+ legacycaller=False, stringifier=False, chromeOnly=False,
+ htmlConstructor=False, secureContext=False, pref=None, func=None):
harness.ok(isinstance(method, WebIDL.IDLMethod),
"Should be an IDLMethod")
harness.ok(method.isMethod(), "Method is a method")
@@ -30,6 +30,9 @@ def WebIDLTest(parser, harness):
harness.check(method.getExtendedAttribute("ChromeOnly") is not None, chromeOnly, "Method has the correct value for ChromeOnly")
harness.check(method.isHTMLConstructor(), htmlConstructor, "Method has the correct htmlConstructor value")
harness.check(len(method.signatures()), len(signatures), "Method has the correct number of signatures")
+ harness.check(method.getExtendedAttribute("Pref"), pref, "Method has the correct pref value")
+ harness.check(method.getExtendedAttribute("Func"), func, "Method has the correct func value")
+ harness.check(method.getExtendedAttribute("SecureContext") is not None, secureContext, "Method has the correct SecureContext value")
sigpairs = zip(method.signatures(), signatures)
for (gotSignature, expectedSignature) in sigpairs:
@@ -90,6 +93,21 @@ def WebIDLTest(parser, harness):
parser = parser.reset()
parser.parse("""
+ interface TestPrefConstructor {
+ [Pref="dom.webidl.test1"] constructor();
+ };
+ """)
+ results = parser.finish()
+ harness.check(len(results), 1, "Should be one production")
+ harness.ok(isinstance(results[0], WebIDL.IDLInterface),
+ "Should be an IDLInterface")
+
+ checkMethod(results[0].ctor(), "::TestPrefConstructor::constructor",
+ "constructor", [("TestPrefConstructor (Wrapper)", [])],
+ pref=["dom.webidl.test1"])
+
+ parser = parser.reset()
+ parser.parse("""
interface TestChromeOnlyConstructor {
[ChromeOnly] constructor();
};
@@ -105,6 +123,53 @@ def WebIDLTest(parser, harness):
parser = parser.reset()
parser.parse("""
+ interface TestSCConstructor {
+ [SecureContext] constructor();
+ };
+ """)
+ results = parser.finish()
+ harness.check(len(results), 1, "Should be one production")
+ harness.ok(isinstance(results[0], WebIDL.IDLInterface),
+ "Should be an IDLInterface")
+
+ checkMethod(results[0].ctor(), "::TestSCConstructor::constructor",
+ "constructor", [("TestSCConstructor (Wrapper)", [])],
+ secureContext=True)
+
+ parser = parser.reset()
+ parser.parse("""
+ interface TestFuncConstructor {
+ [Func="Document::IsWebAnimationsEnabled"] constructor();
+ };
+ """)
+ results = parser.finish()
+ harness.check(len(results), 1, "Should be one production")
+ harness.ok(isinstance(results[0], WebIDL.IDLInterface),
+ "Should be an IDLInterface")
+
+ checkMethod(results[0].ctor(), "::TestFuncConstructor::constructor",
+ "constructor", [("TestFuncConstructor (Wrapper)", [])],
+ func=["Document::IsWebAnimationsEnabled"])
+
+ parser = parser.reset()
+ parser.parse("""
+ interface TestPrefChromeOnlySCFuncConstructor {
+ [ChromeOnly, Pref="dom.webidl.test1", SecureContext, Func="Document::IsWebAnimationsEnabled"]
+ constructor();
+ };
+ """)
+ results = parser.finish()
+ harness.check(len(results), 1, "Should be one production")
+ harness.ok(isinstance(results[0], WebIDL.IDLInterface),
+ "Should be an IDLInterface")
+
+ checkMethod(results[0].ctor(), "::TestPrefChromeOnlySCFuncConstructor::constructor",
+ "constructor", [("TestPrefChromeOnlySCFuncConstructor (Wrapper)", [])],
+ func=["Document::IsWebAnimationsEnabled"], pref=["dom.webidl.test1"],
+ chromeOnly=True, secureContext=True)
+
+ parser = parser.reset()
+ parser.parse("""
interface TestHTMLConstructor {
[HTMLConstructor] constructor();
};
diff --git a/components/script/dom/bindings/codegen/parser/tests/test_date.py b/components/script/dom/bindings/codegen/parser/tests/test_date.py
deleted file mode 100644
index 2bdfc95e14f..00000000000
--- a/components/script/dom/bindings/codegen/parser/tests/test_date.py
+++ /dev/null
@@ -1,15 +0,0 @@
-def WebIDLTest(parser, harness):
- parser.parse("""
- interface WithDates {
- attribute Date foo;
- void bar(Date arg);
- void baz(sequence<Date> arg);
- };
- """)
-
- results = parser.finish()
- harness.ok(results[0].members[0].type.isDate(), "Should have Date")
- harness.ok(results[0].members[1].signatures()[0][1][0].type.isDate(),
- "Should have Date argument")
- harness.ok(not results[0].members[2].signatures()[0][1][0].type.isDate(),
- "Should have non-Date argument")
diff --git a/components/script/dom/bindings/codegen/parser/tests/test_distinguishability.py b/components/script/dom/bindings/codegen/parser/tests/test_distinguishability.py
index bd9996e34c9..505b36468d6 100644
--- a/components/script/dom/bindings/codegen/parser/tests/test_distinguishability.py
+++ b/components/script/dom/bindings/codegen/parser/tests/test_distinguishability.py
@@ -149,7 +149,7 @@ def WebIDLTest(parser, harness):
# Now let's test our whole distinguishability table
argTypes = [ "long", "short", "long?", "short?", "boolean",
- "boolean?", "DOMString", "ByteString", "Enum", "Enum2",
+ "boolean?", "DOMString", "ByteString", "UTF8String", "Enum", "Enum2",
"Interface", "Interface?",
"AncestorInterface", "UnrelatedInterface", "CallbackInterface",
"CallbackInterface?", "CallbackInterface2",
@@ -158,14 +158,12 @@ def WebIDLTest(parser, harness):
"record<DOMString, object>",
"record<USVString, Dict>",
"record<ByteString, long>",
- "Date", "Date?", "any",
- "Promise<any>", "Promise<any>?",
- "USVString", "JSString", "ArrayBuffer", "ArrayBufferView", "SharedArrayBuffer",
+ "record<UTF8String, long>",
+ "any", "Promise<any>", "Promise<any>?",
+ "USVString", "JSString", "ArrayBuffer", "ArrayBufferView",
"Uint8Array", "Uint16Array",
"(long or Callback)", "(long or Dict)",
]
- # When we can parse Date, we need to add it here.
- # XXXbz we can, and should really do that...
# Try to categorize things a bit to keep list lengths down
def allBut(list1, list2):
@@ -177,26 +175,24 @@ def WebIDLTest(parser, harness):
primitives = numerics + booleans
nonNumerics = allBut(argTypes, numerics + unions)
nonBooleans = allBut(argTypes, booleans)
- strings = [ "DOMString", "ByteString", "Enum", "Enum2", "USVString", "JSString" ]
+ strings = [ "DOMString", "ByteString", "Enum", "Enum2", "USVString", "JSString", "UTF8String" ]
nonStrings = allBut(argTypes, strings)
nonObjects = primitives + strings
objects = allBut(argTypes, nonObjects )
bufferSourceTypes = ["ArrayBuffer", "ArrayBufferView", "Uint8Array", "Uint16Array"]
- sharedBufferSourceTypes = ["SharedArrayBuffer"]
interfaces = [ "Interface", "Interface?", "AncestorInterface",
- "UnrelatedInterface" ] + bufferSourceTypes + sharedBufferSourceTypes
+ "UnrelatedInterface" ] + bufferSourceTypes
nullables = (["long?", "short?", "boolean?", "Interface?",
"CallbackInterface?", "Dict", "Dict2",
"Date?", "any", "Promise<any>?"] +
allBut(unions, [ "(long or Callback)" ]))
- dates = [ "Date", "Date?" ]
sequences = [ "sequence<long>", "sequence<short>" ]
- nonUserObjects = nonObjects + interfaces + dates + sequences
+ nonUserObjects = nonObjects + interfaces + sequences
otherObjects = allBut(argTypes, nonUserObjects + ["object"])
notRelatedInterfaces = (nonObjects + ["UnrelatedInterface"] +
- otherObjects + dates + sequences + bufferSourceTypes + sharedBufferSourceTypes)
+ otherObjects + sequences + bufferSourceTypes)
records = [ "record<DOMString, object>", "record<USVString, Dict>",
- "record<ByteString, long>" ] # JSString not supported in records
+ "record<ByteString, long>", "record<UTF8String, long>" ] # JSString not supported in records
# Build a representation of the distinguishability table as a dict
# of dicts, holding True values where needed, holes elsewhere.
@@ -215,6 +211,7 @@ def WebIDLTest(parser, harness):
setDistinguishable("boolean?", allBut(nonBooleans, nullables))
setDistinguishable("DOMString", nonStrings)
setDistinguishable("ByteString", nonStrings)
+ setDistinguishable("UTF8String", nonStrings)
setDistinguishable("USVString", nonStrings)
setDistinguishable("JSString", nonStrings)
setDistinguishable("Enum", nonStrings)
@@ -240,8 +237,7 @@ def WebIDLTest(parser, harness):
setDistinguishable("record<USVString, Dict>", nonUserObjects)
# JSString not supported in records
setDistinguishable("record<ByteString, long>", nonUserObjects)
- setDistinguishable("Date", allBut(argTypes, dates + ["object"]))
- setDistinguishable("Date?", allBut(argTypes, dates + nullables + ["object"]))
+ setDistinguishable("record<UTF8String, long>", nonUserObjects)
setDistinguishable("any", [])
setDistinguishable("Promise<any>", [])
setDistinguishable("Promise<any>?", [])
@@ -249,7 +245,6 @@ def WebIDLTest(parser, harness):
setDistinguishable("ArrayBufferView", allBut(argTypes, ["ArrayBufferView", "Uint8Array", "Uint16Array", "object"]))
setDistinguishable("Uint8Array", allBut(argTypes, ["ArrayBufferView", "Uint8Array", "object"]))
setDistinguishable("Uint16Array", allBut(argTypes, ["ArrayBufferView", "Uint16Array", "object"]))
- setDistinguishable("SharedArrayBuffer", allBut(argTypes, ["SharedArrayBuffer", "object"]))
setDistinguishable("(long or Callback)",
allBut(nonUserObjects, numerics))
setDistinguishable("(long or Dict)",
diff --git a/components/script/dom/bindings/codegen/parser/tests/test_extended_attributes.py b/components/script/dom/bindings/codegen/parser/tests/test_extended_attributes.py
index 97184ec2478..144c945bc10 100644
--- a/components/script/dom/bindings/codegen/parser/tests/test_extended_attributes.py
+++ b/components/script/dom/bindings/codegen/parser/tests/test_extended_attributes.py
@@ -56,9 +56,9 @@ def WebIDLTest(parser, harness):
results = parser.finish()
# Pull out the first argument out of the arglist of the first (and
# only) signature.
- harness.ok(results[0].members[0].signatures()[0][1][0].type.clamp,
+ harness.ok(results[0].members[0].signatures()[0][1][0].type.hasClamp(),
"Should be clamped")
- harness.ok(not results[0].members[1].signatures()[0][1][0].type.clamp,
+ harness.ok(not results[0].members[1].signatures()[0][1][0].type.hasClamp(),
"Should not be clamped")
parser = parser.reset()
@@ -86,9 +86,9 @@ def WebIDLTest(parser, harness):
results = parser.finish()
# Pull out the first argument out of the arglist of the first (and
# only) signature.
- harness.ok(results[0].members[0].signatures()[0][1][0].type.enforceRange,
+ harness.ok(results[0].members[0].signatures()[0][1][0].type.hasEnforceRange(),
"Should be enforceRange")
- harness.ok(not results[0].members[1].signatures()[0][1][0].type.enforceRange,
+ harness.ok(not results[0].members[1].signatures()[0][1][0].type.hasEnforceRange(),
"Should not be enforceRange")
parser = parser.reset()
diff --git a/components/script/dom/bindings/codegen/parser/tests/test_nullable_equivalency.py b/components/script/dom/bindings/codegen/parser/tests/test_nullable_equivalency.py
index 2b48b615dd4..8ba6771677a 100644
--- a/components/script/dom/bindings/codegen/parser/tests/test_nullable_equivalency.py
+++ b/components/script/dom/bindings/codegen/parser/tests/test_nullable_equivalency.py
@@ -80,7 +80,7 @@ def checkEquivalent(iface, harness):
for attr in dir(type1):
if attr.startswith('_') or \
attr in ['nullable', 'builtin', 'filename', 'location',
- 'inner', 'QName', 'getDeps', 'name'] or \
+ 'inner', 'QName', 'getDeps', 'name', 'prettyName'] or \
(hasattr(type(type1), attr) and not callable(getattr(type1, attr))):
continue
diff --git a/components/script/dom/bindings/codegen/parser/tests/test_toJSON.py b/components/script/dom/bindings/codegen/parser/tests/test_toJSON.py
index b8b4f796ccb..ad01330e65a 100644
--- a/components/script/dom/bindings/codegen/parser/tests/test_toJSON.py
+++ b/components/script/dom/bindings/codegen/parser/tests/test_toJSON.py
@@ -85,7 +85,7 @@ def WebIDLTest(parser, harness):
JsonTypes = [ "byte", "octet", "short", "unsigned short", "long", "unsigned long", "long long",
"unsigned long long", "float", "unrestricted float", "double", "unrestricted double", "boolean",
- "DOMString", "ByteString", "USVString", "Enum", "InterfaceWithToJSON", "object" ]
+ "DOMString", "ByteString", "UTF8String", "USVString", "Enum", "InterfaceWithToJSON", "object" ]
nonJsonTypes = [ "InterfaceWithoutToJSON", "any", "Int8Array", "Int16Array", "Int32Array","Uint8Array",
"Uint16Array", "Uint32Array", "Uint8ClampedArray", "Float32Array", "Float64Array", "ArrayBuffer" ]
@@ -129,9 +129,12 @@ def WebIDLTest(parser, harness):
doTest("interface Test { record<DOMString, %s> toJSON(); };" % type, False,
"record<DOMString, %s> should be a JSON type" % type)
- doTest("interface Test { record<ByteString, %s> toJSON(); };" % type, False,
+ doTest("interface Test { record<ByteString, %s> toJSON(); };" % type, False,
"record<ByteString, %s> should be a JSON type" % type)
+ doTest("interface Test { record<UTF8String, %s> toJSON(); };" % type, False,
+ "record<UTF8String, %s> should be a JSON type" % type)
+
doTest("interface Test { record<USVString, %s> toJSON(); };" % type, False,
"record<USVString, %s> should be a JSON type" % type)
@@ -174,12 +177,12 @@ def WebIDLTest(parser, harness):
doTest("interface Test { record<USVString, %s> toJSON(); };" % type, True,
"record<USVString, %s> should not be a JSON type" % type)
-
+
if type != "any":
doTest("interface Foo { object toJSON(); }; "
"interface Test { (Foo or %s) toJSON(); };" % type, True,
"union containing a non-JSON type (%s) should not be a JSON type" % type)
-
+
doTest("interface test { %s? toJSON(); };" % type, True,
"Nullable type (%s) should not be a JSON type" % type)
diff --git a/components/script/dom/bindings/codegen/parser/update.sh b/components/script/dom/bindings/codegen/parser/update.sh
index fee9720ab2d..dd7803c940c 100755
--- a/components/script/dom/bindings/codegen/parser/update.sh
+++ b/components/script/dom/bindings/codegen/parser/update.sh
@@ -5,8 +5,8 @@ patch < callback-location.patch
patch < union-typedef.patch
patch < inline.patch
-wget https://hg.mozilla.org/mozilla-central/archive/tip.tar.gz/dom/bindings/parser/tests/ -O tests.tar.gz
+wget https://hg.mozilla.org/mozilla-central/archive/tip.zip/dom/bindings/parser/tests/ -O tests.zip
rm -r tests
mkdir tests
-tar xvpf tests.tar.gz -C tests --strip-components=5
-rm tests.tar.gz WebIDL.py.orig
+unzip -d tests -j tests.zip
+rm tests.zip WebIDL.py.orig
diff --git a/components/script/dom/bindings/error.rs b/components/script/dom/bindings/error.rs
index b88a6cabed3..f678611423b 100644
--- a/components/script/dom/bindings/error.rs
+++ b/components/script/dom/bindings/error.rs
@@ -19,6 +19,7 @@ use crate::script_runtime::JSContext as SafeJSContext;
#[cfg(feature = "js_backtrace")]
use backtrace::Backtrace;
use js::error::{throw_range_error, throw_type_error};
+use js::jsapi::ExceptionStackBehavior;
use js::jsapi::JSContext;
use js::jsapi::JS_ClearPendingException;
use js::jsapi::JS_IsExceptionPending;
@@ -161,7 +162,7 @@ pub fn throw_dom_exception(cx: SafeJSContext, global: &GlobalScope, result: Erro
let exception = DOMException::new(global, code);
rooted!(in(*cx) let mut thrown = UndefinedValue());
exception.to_jsval(*cx, thrown.handle_mut());
- JS_SetPendingException(*cx, thrown.handle());
+ JS_SetPendingException(*cx, thrown.handle(), ExceptionStackBehavior::Capture);
}
}
diff --git a/components/script/dom/bindings/interface.rs b/components/script/dom/bindings/interface.rs
index 2097769cb31..d0b3771890e 100644
--- a/components/script/dom/bindings/interface.rs
+++ b/components/script/dom/bindings/interface.rs
@@ -15,8 +15,8 @@ use js::error::throw_type_error;
use js::glue::UncheckedUnwrapObject;
use js::jsapi::GetWellKnownSymbol;
use js::jsapi::HandleObject as RawHandleObject;
-use js::jsapi::{jsid, Class, ClassOps};
-use js::jsapi::{JSAutoRealm, JSClass, JSContext, JSFunctionSpec, JSObject, JSFUN_CONSTRUCTOR};
+use js::jsapi::{jsid, JSClass, JSClassOps};
+use js::jsapi::{JSAutoRealm, JSContext, JSFunctionSpec, JSObject, JSFUN_CONSTRUCTOR};
use js::jsapi::{JSPropertySpec, JSString, JSTracer, JS_AtomizeAndPinString};
use js::jsapi::{JS_GetFunctionObject, JS_NewFunction, JS_NewGlobalObject};
use js::jsapi::{JS_NewObject, JS_NewPlainObject};
@@ -38,8 +38,8 @@ use std::ptr;
/// The class of a non-callback interface object.
#[derive(Clone, Copy)]
pub struct NonCallbackInterfaceObjectClass {
- /// The SpiderMonkey Class structure.
- pub class: Class,
+ /// The SpiderMonkey class structure.
+ pub class: JSClass,
/// The prototype id of that interface, used in the hasInstance hook.
pub proto_id: PrototypeList::ID,
/// The prototype depth of that interface, used in the hasInstance hook.
@@ -59,7 +59,7 @@ impl NonCallbackInterfaceObjectClass {
proto_depth: u16,
) -> NonCallbackInterfaceObjectClass {
NonCallbackInterfaceObjectClass {
- class: Class {
+ class: JSClass {
name: b"Function\0" as *const _ as *const libc::c_char,
flags: 0,
cOps: &constructor_behavior.0,
@@ -84,12 +84,12 @@ pub type ConstructorClassHook =
unsafe extern "C" fn(cx: *mut JSContext, argc: u32, vp: *mut Value) -> bool;
/// The constructor behavior of a non-callback interface object.
-pub struct InterfaceConstructorBehavior(ClassOps);
+pub struct InterfaceConstructorBehavior(JSClassOps);
impl InterfaceConstructorBehavior {
/// An interface constructor that unconditionally throws a type error.
pub const fn throw() -> Self {
- InterfaceConstructorBehavior(ClassOps {
+ InterfaceConstructorBehavior(JSClassOps {
addProperty: None,
delProperty: None,
enumerate: None,
@@ -106,7 +106,7 @@ impl InterfaceConstructorBehavior {
/// An interface constructor that calls a native Rust function.
pub const fn call(hook: ConstructorClassHook) -> Self {
- InterfaceConstructorBehavior(ClassOps {
+ InterfaceConstructorBehavior(JSClassOps {
addProperty: None,
delProperty: None,
enumerate: None,
diff --git a/components/script/dom/bindings/namespace.rs b/components/script/dom/bindings/namespace.rs
index 82b7bd8834e..64b7b0b2626 100644
--- a/components/script/dom/bindings/namespace.rs
+++ b/components/script/dom/bindings/namespace.rs
@@ -9,6 +9,7 @@ use crate::dom::bindings::interface::{create_object, define_on_global_object};
use crate::script_runtime::JSContext;
use js::jsapi::{JSClass, JSFunctionSpec};
use js::rust::{HandleObject, MutableHandleObject};
+use std::ptr;
/// The class of a namespace object.
#[derive(Clone, Copy)]
@@ -23,7 +24,9 @@ impl NamespaceObjectClass {
name: name as *const _ as *const libc::c_char,
flags: 0,
cOps: 0 as *mut _,
- reserved: [0 as *mut _; 3],
+ spec: ptr::null(),
+ ext: ptr::null(),
+ oOps: ptr::null(),
})
}
}
diff --git a/components/script/dom/bindings/proxyhandler.rs b/components/script/dom/bindings/proxyhandler.rs
index a4b5f418cd2..11913c03642 100644
--- a/components/script/dom/bindings/proxyhandler.rs
+++ b/components/script/dom/bindings/proxyhandler.rs
@@ -55,7 +55,11 @@ pub unsafe extern "C" fn shadow_check_callback(
/// Initialize the infrastructure for DOM proxy objects.
pub unsafe fn init() {
- SetDOMProxyInformation(GetProxyHandlerFamily(), Some(shadow_check_callback));
+ SetDOMProxyInformation(
+ GetProxyHandlerFamily(),
+ Some(shadow_check_callback),
+ ptr::null(),
+ );
}
/// Defines an expando on the given `proxy`.
diff --git a/components/script/dom/bindings/record.rs b/components/script/dom/bindings/record.rs
index 86453b59fc3..c54a2403d70 100644
--- a/components/script/dom/bindings/record.rs
+++ b/components/script/dom/bindings/record.rs
@@ -120,12 +120,12 @@ where
}
rooted!(in(cx) let object = value.to_object());
- let ids = IdVector::new(cx);
+ let mut ids = IdVector::new(cx);
if !GetPropertyKeys(
cx,
object.handle(),
JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS,
- ids.get(),
+ ids.handle_mut(),
) {
return Err(());
}
diff --git a/components/script/dom/bindings/reflector.rs b/components/script/dom/bindings/reflector.rs
index 2b5a4987eb5..78635b2be31 100644
--- a/components/script/dom/bindings/reflector.rs
+++ b/components/script/dom/bindings/reflector.rs
@@ -6,6 +6,7 @@
use crate::dom::bindings::conversions::DerivedFrom;
use crate::dom::bindings::root::DomRoot;
+use crate::dom::bindings::trace::JSTraceable;
use crate::dom::globalscope::GlobalScope;
use crate::script_runtime::JSContext;
use js::jsapi::{Heap, JSObject};
@@ -53,7 +54,7 @@ impl Reflector {
}
/// Initialize the reflector. (May be called only once.)
- pub fn set_jsobject(&mut self, object: *mut JSObject) {
+ pub unsafe fn set_jsobject(&self, object: *mut JSObject) {
assert!(self.object.get().is_null());
assert!(!object.is_null());
self.object.set(object);
@@ -75,7 +76,7 @@ impl Reflector {
}
/// A trait to provide access to the `Reflector` for a DOM object.
-pub trait DomObject: 'static {
+pub trait DomObject: JSTraceable + 'static {
/// Returns the receiver's reflector.
fn reflector(&self) -> &Reflector;
@@ -97,11 +98,11 @@ impl DomObject for Reflector {
/// A trait to initialize the `Reflector` for a DOM object.
pub trait MutDomObject: DomObject {
/// Initializes the Reflector
- fn init_reflector(&mut self, obj: *mut JSObject);
+ unsafe fn init_reflector(&self, obj: *mut JSObject);
}
impl MutDomObject for Reflector {
- fn init_reflector(&mut self, obj: *mut JSObject) {
+ unsafe fn init_reflector(&self, obj: *mut JSObject) {
self.set_jsobject(obj)
}
}
diff --git a/components/script/dom/bindings/root.rs b/components/script/dom/bindings/root.rs
index 19df89df53f..0ba69687dba 100644
--- a/components/script/dom/bindings/root.rs
+++ b/components/script/dom/bindings/root.rs
@@ -26,7 +26,7 @@
use crate::dom::bindings::conversions::DerivedFrom;
use crate::dom::bindings::inheritance::Castable;
-use crate::dom::bindings::reflector::{DomObject, Reflector};
+use crate::dom::bindings::reflector::{DomObject, MutDomObject, Reflector};
use crate::dom::bindings::trace::trace_reflector;
use crate::dom::bindings::trace::JSTraceable;
use crate::dom::node::Node;
@@ -62,7 +62,7 @@ where
/// It cannot outlive its associated `RootCollection`, and it gives
/// out references which cannot outlive this new `Root`.
#[allow(unrooted_must_root)]
- unsafe fn new(value: T) -> Self {
+ pub unsafe fn new(value: T) -> Self {
debug_assert!(thread_state::get().is_script());
STACK_ROOTS.with(|ref root_list| {
let root_list = &*root_list.get().unwrap();
@@ -99,6 +99,32 @@ where
}
}
+unsafe impl<T> StableTraceObject for MaybeUnreflectedDom<T>
+where
+ T: DomObject,
+{
+ fn stable_trace_object<'a>(&'a self) -> *const dyn JSTraceable {
+ // The JSTraceable impl for Reflector doesn't actually do anything,
+ // so we need this shenanigan to actually trace the reflector of the
+ // T pointer in Dom<T>.
+ #[allow(unrooted_must_root)]
+ struct MaybeUnreflectedStackRoot<T>(T);
+ unsafe impl<T> JSTraceable for MaybeUnreflectedStackRoot<T>
+ where
+ T: DomObject,
+ {
+ unsafe fn trace(&self, tracer: *mut JSTracer) {
+ if self.0.reflector().get_jsobject().is_null() {
+ self.0.trace(tracer);
+ } else {
+ trace_reflector(tracer, "on stack", &self.0.reflector());
+ }
+ }
+ }
+ unsafe { &*(self.ptr.as_ptr() as *const T as *const MaybeUnreflectedStackRoot<T>) }
+ }
+}
+
impl<T> Deref for Root<T>
where
T: Deref + StableTraceObject,
@@ -236,7 +262,10 @@ impl RootCollection {
unsafe fn unroot(&self, object: *const dyn JSTraceable) {
debug_assert!(thread_state::get().is_script());
let roots = &mut *self.roots.get();
- match roots.iter().rposition(|r| *r == object) {
+ match roots
+ .iter()
+ .rposition(|r| *r as *const () == object as *const ())
+ {
Some(idx) => {
roots.remove(idx);
},
@@ -341,6 +370,46 @@ unsafe impl<T: DomObject> JSTraceable for Dom<T> {
}
}
+/// A traced reference to a DOM object that may not be reflected yet.
+#[unrooted_must_root_lint::must_root]
+pub struct MaybeUnreflectedDom<T> {
+ ptr: ptr::NonNull<T>,
+}
+
+impl<T> MaybeUnreflectedDom<T>
+where
+ T: DomObject,
+{
+ #[allow(unrooted_must_root)]
+ pub unsafe fn from_box(value: Box<T>) -> Self {
+ Self {
+ ptr: Box::into_raw_non_null(value),
+ }
+ }
+}
+
+impl<T> Root<MaybeUnreflectedDom<T>>
+where
+ T: DomObject,
+{
+ pub fn as_ptr(&self) -> *const T {
+ self.value.ptr.as_ptr()
+ }
+}
+
+impl<T> Root<MaybeUnreflectedDom<T>>
+where
+ T: MutDomObject,
+{
+ pub unsafe fn reflect_with(self, obj: *mut JSObject) -> DomRoot<T> {
+ let ptr = self.as_ptr();
+ drop(self);
+ let root = DomRoot::from_ref(&*ptr);
+ root.init_reflector(obj);
+ root
+ }
+}
+
/// An unrooted reference to a DOM object for use in layout. `Layout*Helpers`
/// traits must be implemented on this.
#[unrooted_must_root_lint::allow_unrooted_interior]
diff --git a/components/script/dom/bindings/structuredclone.rs b/components/script/dom/bindings/structuredclone.rs
index dbf852907a8..511b8d1650e 100644
--- a/components/script/dom/bindings/structuredclone.rs
+++ b/components/script/dom/bindings/structuredclone.rs
@@ -361,6 +361,9 @@ pub fn read(
JS_STRUCTURED_CLONE_VERSION,
StructuredCloneScope::DifferentProcess,
rval,
+ CloneDataPolicy {
+ sharedArrayBuffer_: false,
+ },
&STRUCTURED_CLONE_CALLBACKS,
sc_holder_ptr as *mut raw::c_void,
);
diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs
index 3fb93b98dfa..2d6b6c04379 100644
--- a/components/script/dom/bindings/trace.rs
+++ b/components/script/dom/bindings/trace.rs
@@ -83,8 +83,8 @@ use media::WindowGLContext;
use metrics::{InteractiveMetrics, InteractiveWindow};
use mime::Mime;
use msg::constellation_msg::{
- BlobId, BrowsingContextId, HistoryStateId, MessagePortId, MessagePortRouterId, PipelineId,
- TopLevelBrowsingContextId,
+ BlobId, BroadcastChannelRouterId, BrowsingContextId, HistoryStateId, MessagePortId,
+ MessagePortRouterId, PipelineId, TopLevelBrowsingContextId,
};
use net_traits::filemanager_thread::RelativePos;
use net_traits::image::base::{Image, ImageMetadata};
@@ -175,6 +175,8 @@ unsafe_no_jsmanaged_fields!(MessagePortId);
unsafe_no_jsmanaged_fields!(RefCell<Option<MessagePortId>>);
unsafe_no_jsmanaged_fields!(MessagePortRouterId);
+unsafe_no_jsmanaged_fields!(BroadcastChannelRouterId);
+
unsafe_no_jsmanaged_fields!(BlobId);
unsafe_no_jsmanaged_fields!(BlobImpl);
@@ -889,7 +891,11 @@ impl RootedTraceableSet {
unsafe fn remove(traceable: *const dyn JSTraceable) {
ROOTED_TRACEABLES.with(|ref traceables| {
let mut traceables = traceables.borrow_mut();
- let idx = match traceables.set.iter().rposition(|x| *x == traceable) {
+ let idx = match traceables
+ .set
+ .iter()
+ .rposition(|x| *x as *const () == traceable as *const ())
+ {
Some(idx) => idx,
None => unreachable!(),
};
@@ -916,35 +922,6 @@ impl RootedTraceableSet {
/// If you have GC things like *mut JSObject or JSVal, use rooted!.
/// If you have an arbitrary number of DomObjects to root, use rooted_vec!.
/// If you know what you're doing, use this.
-#[derive(JSTraceable)]
-pub struct RootedTraceable<'a, T: 'static + JSTraceable> {
- ptr: &'a T,
-}
-
-impl<'a, T: JSTraceable + 'static> RootedTraceable<'a, T> {
- /// DomRoot a JSTraceable thing for the life of this RootedTraceable
- pub fn new(traceable: &'a T) -> RootedTraceable<'a, T> {
- unsafe {
- RootedTraceableSet::add(traceable);
- }
- RootedTraceable { ptr: traceable }
- }
-}
-
-impl<'a, T: JSTraceable + 'static> Drop for RootedTraceable<'a, T> {
- fn drop(&mut self) {
- unsafe {
- RootedTraceableSet::remove(self.ptr);
- }
- }
-}
-
-/// Roots any JSTraceable thing
-///
-/// If you have a valid DomObject, use DomRoot.
-/// If you have GC things like *mut JSObject or JSVal, use rooted!.
-/// If you have an arbitrary number of DomObjects to root, use rooted_vec!.
-/// If you know what you're doing, use this.
#[unrooted_must_root_lint::allow_unrooted_interior]
pub struct RootedTraceableBox<T: 'static + JSTraceable> {
ptr: *mut T,
@@ -957,12 +934,12 @@ unsafe impl<T: JSTraceable + 'static> JSTraceable for RootedTraceableBox<T> {
}
impl<T: JSTraceable + 'static> RootedTraceableBox<T> {
- /// DomRoot a JSTraceable thing for the life of this RootedTraceable
+ /// DomRoot a JSTraceable thing for the life of this RootedTraceableBox
pub fn new(traceable: T) -> RootedTraceableBox<T> {
Self::from_box(Box::new(traceable))
}
- /// Consumes a boxed JSTraceable and roots it for the life of this RootedTraceable.
+ /// Consumes a boxed JSTraceable and roots it for the life of this RootedTraceableBox.
pub fn from_box(boxed_traceable: Box<T>) -> RootedTraceableBox<T> {
let traceable = Box::into_raw(boxed_traceable);
unsafe {
diff --git a/components/script/dom/bindings/utils.rs b/components/script/dom/bindings/utils.rs
index 56b2112e498..21f82be9cee 100644
--- a/components/script/dom/bindings/utils.rs
+++ b/components/script/dom/bindings/utils.rs
@@ -23,8 +23,9 @@ use js::glue::{
};
use js::jsapi::HandleId as RawHandleId;
use js::jsapi::HandleObject as RawHandleObject;
+use js::jsapi::MutableHandleIdVector as RawMutableHandleIdVector;
use js::jsapi::MutableHandleObject as RawMutableHandleObject;
-use js::jsapi::{AutoIdVector, CallArgs, DOMCallbacks, GetNonCCWObjectGlobal};
+use js::jsapi::{CallArgs, DOMCallbacks, GetNonCCWObjectGlobal};
use js::jsapi::{Heap, JSAutoRealm, JSContext, JS_FreezeObject};
use js::jsapi::{JSJitInfo, JSObject, JSTracer, JSWrapObjectCallbacks};
use js::jsapi::{JS_EnumerateStandardClasses, JS_GetLatin1StringCharsAndLength};
@@ -375,7 +376,7 @@ pub unsafe fn trace_global(tracer: *mut JSTracer, obj: *mut JSObject) {
pub unsafe extern "C" fn enumerate_global(
cx: *mut JSContext,
obj: RawHandleObject,
- _props: *mut AutoIdVector,
+ _props: RawMutableHandleIdVector,
_enumerable_only: bool,
) -> bool {
assert!(JS_IsGlobalObject(obj.get()));
@@ -439,6 +440,7 @@ unsafe extern "C" fn wrap(
unsafe extern "C" fn pre_wrap(
cx: *mut JSContext,
_scope: RawHandleObject,
+ _orig_obj: RawHandleObject,
obj: RawHandleObject,
_object_passed_to_wrap: RawHandleObject,
rval: RawMutableHandleObject,
@@ -482,7 +484,7 @@ unsafe fn generic_call(
let args = CallArgs::from_vp(vp, argc);
let info = RUST_FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, vp));
- let proto_id = (*info).protoID;
+ let proto_id = (*info).__bindgen_anon_2.protoID;
let thisobj = args.thisv();
if !thisobj.get().is_null_or_undefined() && !thisobj.get().is_object() {
@@ -495,7 +497,7 @@ unsafe fn generic_call(
} else {
GetNonCCWObjectGlobal(JS_CALLEE(cx, vp).to_object_or_null())
});
- let depth = (*info).depth;
+ let depth = (*info).__bindgen_anon_3.depth;
let proto_check =
|class: &'static DOMClass| class.interface_chain[depth as usize] as u16 == proto_id;
let this = match private_from_proto_check(obj.get(), cx, proto_check) {
@@ -582,7 +584,7 @@ pub unsafe extern "C" fn generic_lenient_setter(
}
unsafe extern "C" fn instance_class_has_proto_at_depth(
- clasp: *const js::jsapi::Class,
+ clasp: *const js::jsapi::JSClass,
proto_id: u32,
depth: u32,
) -> bool {
diff --git a/components/script/dom/broadcastchannel.rs b/components/script/dom/broadcastchannel.rs
new file mode 100644
index 00000000000..f7d75d8c101
--- /dev/null
+++ b/components/script/dom/broadcastchannel.rs
@@ -0,0 +1,106 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use crate::dom::bindings::codegen::Bindings::BroadcastChannelBinding::{
+ BroadcastChannelMethods, Wrap,
+};
+use crate::dom::bindings::error::{Error, ErrorResult};
+use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
+use crate::dom::bindings::root::DomRoot;
+use crate::dom::bindings::str::DOMString;
+use crate::dom::bindings::structuredclone;
+use crate::dom::eventtarget::EventTarget;
+use crate::dom::globalscope::GlobalScope;
+use crate::script_runtime::JSContext as SafeJSContext;
+use dom_struct::dom_struct;
+use js::rust::HandleValue;
+use script_traits::BroadcastMsg;
+use std::cell::Cell;
+use uuid::Uuid;
+
+#[dom_struct]
+pub struct BroadcastChannel {
+ eventtarget: EventTarget,
+ name: DOMString,
+ closed: Cell<bool>,
+ id: Uuid,
+}
+
+impl BroadcastChannel {
+ /// <https://html.spec.whatwg.org/multipage/#broadcastchannel>
+ #[allow(non_snake_case)]
+ pub fn Constructor(global: &GlobalScope, name: DOMString) -> DomRoot<BroadcastChannel> {
+ BroadcastChannel::new(global, name)
+ }
+
+ pub fn new(global: &GlobalScope, name: DOMString) -> DomRoot<BroadcastChannel> {
+ let channel = reflect_dom_object(
+ Box::new(BroadcastChannel::new_inherited(name)),
+ global,
+ Wrap,
+ );
+ global.track_broadcast_channel(&*channel);
+ channel
+ }
+
+ pub fn new_inherited(name: DOMString) -> BroadcastChannel {
+ BroadcastChannel {
+ eventtarget: EventTarget::new_inherited(),
+ name,
+ closed: Default::default(),
+ id: Uuid::new_v4(),
+ }
+ }
+
+ /// The unique Id of this channel.
+ /// Used for filtering out the sender from the local broadcast.
+ pub fn id(&self) -> &Uuid {
+ &self.id
+ }
+
+ /// Is this channel closed?
+ pub fn closed(&self) -> bool {
+ self.closed.get()
+ }
+}
+
+impl BroadcastChannelMethods for BroadcastChannel {
+ /// <https://html.spec.whatwg.org/multipage/#dom-messageport-postmessage>
+ fn PostMessage(&self, cx: SafeJSContext, message: HandleValue) -> ErrorResult {
+ // Step 3, if closed.
+ if self.closed.get() {
+ return Err(Error::InvalidState);
+ }
+
+ // Step 6, StructuredSerialize(message).
+ let data = structuredclone::write(cx, message, None)?;
+
+ let global = self.global();
+
+ let msg = BroadcastMsg {
+ origin: global.origin().immutable().clone(),
+ channel_name: self.Name().to_string(),
+ data,
+ };
+
+ global.schedule_broadcast(msg, &self.id);
+ Ok(())
+ }
+
+ /// <https://html.spec.whatwg.org/multipage/#dom-broadcastchannel-name>
+ fn Name(&self) -> DOMString {
+ self.name.clone()
+ }
+
+ /// <https://html.spec.whatwg.org/multipage/#dom-broadcastchannel-close>
+ fn Close(&self) {
+ self.closed.set(true);
+ }
+
+ // <https://html.spec.whatwg.org/multipage/#handler-broadcastchannel-onmessageerror>
+ event_handler!(messageerror, GetOnmessageerror, SetOnmessageerror);
+
+ // <https://html.spec.whatwg.org/multipage/#handler-broadcastchannel-onmessage>
+ event_handler!(message, GetOnmessage, SetOnmessage);
+}
diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs
index 6ee46bea95b..303c51660f0 100644
--- a/components/script/dom/document.rs
+++ b/components/script/dom/document.rs
@@ -519,7 +519,7 @@ impl Document {
// Set the document's activity level, reflow if necessary, and suspend or resume timers.
self.activity.set(activity);
let media = ServoMedia::get().unwrap();
- let pipeline_id = self.window().pipeline_id().expect("doc with no pipeline");
+ let pipeline_id = self.window().pipeline_id();
let client_context_id =
ClientContextId::build(pipeline_id.namespace_id.0, pipeline_id.index.0.get());
@@ -1636,11 +1636,10 @@ impl Document {
.borrow_mut()
.push((ident, Some(callback)));
- // TODO: Should tick animation only when document is visible
-
// If we are running 'fake' animation frames, we unconditionally
// set up a one-shot timer for script to execute the rAF callbacks.
- if self.is_faking_animation_frames() {
+ if self.is_faking_animation_frames() && self.window().visible() {
+ warn!("Scheduling fake animation frame. Animation frames tick too fast.");
let callback = FakeRequestAnimationFrameCallback {
document: Trusted::new(self),
};
@@ -3062,14 +3061,56 @@ impl Document {
self.redirect_count.set(count)
}
- fn create_node_list<F: Fn(&Node) -> bool>(&self, callback: F) -> DomRoot<NodeList> {
+ pub fn elements_by_name_count(&self, name: &DOMString) -> u32 {
+ if name.is_empty() {
+ return 0;
+ }
+ self.count_node_list(|n| Document::is_element_in_get_by_name(n, name))
+ }
+
+ pub fn nth_element_by_name(&self, index: u32, name: &DOMString) -> Option<DomRoot<Node>> {
+ if name.is_empty() {
+ return None;
+ }
+ self.nth_in_node_list(index, |n| Document::is_element_in_get_by_name(n, name))
+ }
+
+ // Note that document.getByName does not match on the same conditions
+ // as the document named getter.
+ fn is_element_in_get_by_name(node: &Node, name: &DOMString) -> bool {
+ let element = match node.downcast::<Element>() {
+ Some(element) => element,
+ None => return false,
+ };
+ if element.namespace() != &ns!(html) {
+ return false;
+ }
+ element.get_name().map_or(false, |n| *n == **name)
+ }
+
+ fn count_node_list<F: Fn(&Node) -> bool>(&self, callback: F) -> u32 {
+ let doc = self.GetDocumentElement();
+ let maybe_node = doc.as_deref().map(Castable::upcast::<Node>);
+ maybe_node
+ .iter()
+ .flat_map(|node| node.traverse_preorder(ShadowIncluding::No))
+ .filter(|node| callback(&node))
+ .count() as u32
+ }
+
+ fn nth_in_node_list<F: Fn(&Node) -> bool>(
+ &self,
+ index: u32,
+ callback: F,
+ ) -> Option<DomRoot<Node>> {
let doc = self.GetDocumentElement();
let maybe_node = doc.as_deref().map(Castable::upcast::<Node>);
- let iter = maybe_node
+ maybe_node
.iter()
.flat_map(|node| node.traverse_preorder(ShadowIncluding::No))
- .filter(|node| callback(&node));
- NodeList::new_simple_list(&self.window, iter)
+ .filter(|node| callback(&node))
+ .nth(index as usize)
+ .map(|n| DomRoot::from_ref(&*n))
}
fn get_html_element(&self) -> Option<DomRoot<HTMLHtmlElement>> {
@@ -3318,7 +3359,7 @@ impl Document {
let script_msg = CommonScriptMsg::Task(
ScriptThreadEventCategory::EnterFullscreen,
handler,
- pipeline_id,
+ Some(pipeline_id),
TaskSourceName::DOMManipulation,
);
let msg = MainThreadScriptMsg::Common(script_msg);
@@ -4250,16 +4291,7 @@ impl DocumentMethods for Document {
// https://html.spec.whatwg.org/multipage/#dom-document-getelementsbyname
fn GetElementsByName(&self, name: DOMString) -> DomRoot<NodeList> {
- self.create_node_list(|node| {
- let element = match node.downcast::<Element>() {
- Some(element) => element,
- None => return false,
- };
- if element.namespace() != &ns!(html) {
- return false;
- }
- element.get_name().map_or(false, |atom| *atom == *name)
- })
+ NodeList::new_elements_by_name_list(self.window(), self, name)
}
// https://html.spec.whatwg.org/multipage/#dom-document-images
diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs
index eecff289cdb..268b263fc41 100644
--- a/components/script/dom/element.rs
+++ b/components/script/dom/element.rs
@@ -540,6 +540,16 @@ impl Element {
}
true // whatwg/html#5239
}
+
+ // https://html.spec.whatwg.org/multipage/#the-directionality
+ pub fn directionality(&self) -> String {
+ self.downcast::<HTMLElement>()
+ .and_then(|html_element| html_element.directionality())
+ .unwrap_or_else(|| {
+ let node = self.upcast::<Node>();
+ node.parent_directionality()
+ })
+ }
}
#[allow(unsafe_code)]
diff --git a/components/script/dom/eventtarget.rs b/components/script/dom/eventtarget.rs
index 4020f938b24..90e533c8cc3 100644
--- a/components/script/dom/eventtarget.rs
+++ b/components/script/dom/eventtarget.rs
@@ -37,9 +37,9 @@ use crate::dom::workerglobalscope::WorkerGlobalScope;
use crate::realms::{enter_realm, InRealm};
use dom_struct::dom_struct;
use fnv::FnvHasher;
-use js::jsapi::{JSFunction, JS_GetFunctionObject, SourceText};
+use js::jsapi::{JS_GetFunctionObject, SourceText};
use js::rust::wrappers::CompileFunction;
-use js::rust::{AutoObjectVectorWrapper, CompileOptionsWrapper};
+use js::rust::{CompileOptionsWrapper, RootedObjectVectorWrapper};
use libc::c_char;
use servo_atoms::Atom;
use servo_url::ServoUrl;
@@ -51,7 +51,6 @@ use std::hash::BuildHasherDefault;
use std::marker::PhantomData;
use std::mem;
use std::ops::{Deref, DerefMut};
-use std::ptr;
use std::rc::Rc;
#[derive(Clone, JSTraceable, MallocSizeOf, PartialEq)]
@@ -491,9 +490,10 @@ impl EventTarget {
// source text, we handle parse errors later
// Step 3.8 TODO: settings objects not implemented
+ let window = document.window();
+ let _ac = enter_realm(&*window);
// Step 3.9
- let window = document.window();
let url_serialized = CString::new(handler.url.to_string()).unwrap();
let name = CString::new(&**ty).unwrap();
@@ -517,10 +517,12 @@ impl EventTarget {
};
let cx = window.get_cx();
- let options = CompileOptionsWrapper::new(*cx, url_serialized.as_ptr(), handler.line as u32);
+ let options = unsafe {
+ CompileOptionsWrapper::new(*cx, url_serialized.as_ptr(), handler.line as u32)
+ };
// Step 3.9, subsection Scope steps 1-6
- let scopechain = AutoObjectVectorWrapper::new(*cx);
+ let scopechain = RootedObjectVectorWrapper::new(*cx);
if let Some(element) = element {
scopechain.append(document.reflector().get_jsobject().get());
@@ -530,12 +532,10 @@ impl EventTarget {
scopechain.append(element.reflector().get_jsobject().get());
}
- let _ac = enter_realm(&*window); // TODO 3.8 should replace this
- rooted!(in(*cx) let mut handler = ptr::null_mut::<JSFunction>());
- let rv = unsafe {
+ rooted!(in(*cx) let mut handler = unsafe {
CompileFunction(
*cx,
- scopechain.ptr,
+ scopechain.handle(),
options.ptr,
name.as_ptr(),
args.len() as u32,
@@ -546,10 +546,9 @@ impl EventTarget {
ownsUnits_: false,
_phantom_0: PhantomData,
},
- handler.handle_mut().into(),
)
- };
- if !rv || handler.get().is_null() {
+ });
+ if handler.get().is_null() {
// Step 3.7
unsafe {
let ar = enter_realm(&*self);
diff --git a/components/script/dom/globalscope.rs b/components/script/dom/globalscope.rs
index de3e83101e1..9e55f593f59 100644
--- a/components/script/dom/globalscope.rs
+++ b/components/script/dom/globalscope.rs
@@ -3,7 +3,9 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::dom::bindings::cell::DomRefCell;
+use crate::dom::bindings::codegen::Bindings::BroadcastChannelBinding::BroadcastChannelMethods;
use crate::dom::bindings::codegen::Bindings::EventSourceBinding::EventSourceBinding::EventSourceMethods;
+use crate::dom::bindings::codegen::Bindings::PermissionStatusBinding::PermissionState;
use crate::dom::bindings::codegen::Bindings::VoidFunctionBinding::VoidFunction;
use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
use crate::dom::bindings::codegen::Bindings::WorkerGlobalScopeBinding::WorkerGlobalScopeMethods;
@@ -19,6 +21,7 @@ use crate::dom::bindings::structuredclone;
use crate::dom::bindings::utils::to_frozen_array;
use crate::dom::bindings::weakref::{DOMTracker, WeakRef};
use crate::dom::blob::Blob;
+use crate::dom::broadcastchannel::BroadcastChannel;
use crate::dom::crypto::Crypto;
use crate::dom::dedicatedworkerglobalscope::DedicatedWorkerGlobalScope;
use crate::dom::errorevent::ErrorEvent;
@@ -58,20 +61,22 @@ use crate::timers::{OneshotTimers, TimerCallback};
use content_security_policy::CspList;
use devtools_traits::{PageError, ScriptToDevtoolsControlMsg};
use dom_struct::dom_struct;
+use embedder_traits::EmbedderMsg;
use ipc_channel::ipc::{self, IpcSender};
use ipc_channel::router::ROUTER;
use js::glue::{IsWrapper, UnwrapObjectDynamic};
-use js::jsapi::JSContext;
-use js::jsapi::JSObject;
use js::jsapi::{CurrentGlobalOrNull, GetNonCCWObjectGlobal};
use js::jsapi::{HandleObject, Heap};
+use js::jsapi::{JSContext, JSObject, SourceText};
use js::jsval::{JSVal, UndefinedValue};
use js::panic::maybe_resume_unwind;
-use js::rust::wrappers::EvaluateUtf8;
+use js::rust::wrappers::Evaluate2;
use js::rust::{get_object_class, CompileOptionsWrapper, ParentRuntime, Runtime};
use js::rust::{HandleValue, MutableHandleValue};
use js::{JSCLASS_IS_DOMJSCLASS, JSCLASS_IS_GLOBAL};
-use msg::constellation_msg::{BlobId, MessagePortId, MessagePortRouterId, PipelineId};
+use msg::constellation_msg::{
+ BlobId, BroadcastChannelRouterId, MessagePortId, MessagePortRouterId, PipelineId,
+};
use net_traits::blob_url_store::{get_blob_origin, BlobBuf};
use net_traits::filemanager_thread::{
FileManagerResult, FileManagerThreadMsg, ReadFileProgress, RelativePos,
@@ -82,16 +87,17 @@ use profile_traits::{ipc as profile_ipc, mem as profile_mem, time as profile_tim
use script_traits::serializable::{BlobData, BlobImpl, FileBlob};
use script_traits::transferable::MessagePortImpl;
use script_traits::{
- MessagePortMsg, MsDuration, PortMessageTask, ScriptMsg, ScriptToConstellationChan, TimerEvent,
+ BroadcastMsg, MessagePortMsg, MsDuration, PortMessageTask, ScriptMsg,
+ ScriptToConstellationChan, TimerEvent,
};
use script_traits::{TimerEventId, TimerSchedulerMsg, TimerSource};
use servo_url::{MutableOrigin, ServoUrl};
-use smallvec::SmallVec;
use std::borrow::Cow;
-use std::cell::{Cell, RefCell};
+use std::cell::{Cell, RefCell, RefMut};
use std::collections::hash_map::Entry;
use std::collections::{HashMap, VecDeque};
use std::ffi::CString;
+use std::marker::PhantomData;
use std::mem;
use std::ops::Index;
use std::rc::Rc;
@@ -99,13 +105,6 @@ use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use time::{get_time, Timespec};
use uuid::Uuid;
-use webgpu::wgpu::{
- id::{
- AdapterId, BindGroupId, BindGroupLayoutId, BufferId, CommandEncoderId, ComputePipelineId,
- DeviceId, PipelineLayoutId, ShaderModuleId,
- },
- Backend,
-};
#[derive(JSTraceable)]
pub struct AutoCloseWorker(Arc<AtomicBool>);
@@ -124,6 +123,9 @@ pub struct GlobalScope {
/// The message-port router id for this global, if it is managing ports.
message_port_state: DomRefCell<MessagePortState>,
+ /// The broadcast channels state this global, if it is managing any.
+ broadcast_channel_state: DomRefCell<BroadcastChannelState>,
+
/// The blobs managed by this global, if any.
blob_state: DomRefCell<BlobState>,
@@ -181,6 +183,9 @@ pub struct GlobalScope {
/// The origin of the globalscope
origin: MutableOrigin,
+ /// A map for storing the previous permission state read results.
+ permission_state_invocation_results: DomRefCell<HashMap<String, PermissionState>>,
+
/// The microtask queue associated with this global.
///
/// It is refcounted because windows in the same script thread share the
@@ -237,6 +242,13 @@ struct MessageListener {
context: Trusted<GlobalScope>,
}
+/// A wrapper for broadcasts coming in over IPC, and the event-loop.
+struct BroadcastListener {
+ canceller: TaskCanceller,
+ task_source: DOMManipulationTaskSource,
+ context: Trusted<GlobalScope>,
+}
+
/// A wrapper between timer events coming in over IPC, and the event-loop.
struct TimerListener {
canceller: TaskCanceller,
@@ -310,6 +322,23 @@ pub struct ManagedMessagePort {
closed: bool,
}
+/// State representing whether this global is currently managing broadcast channels.
+#[derive(JSTraceable, MallocSizeOf)]
+#[unrooted_must_root_lint::must_root]
+pub enum BroadcastChannelState {
+ /// The broadcast-channel router id for this global, and a queue of managed channels.
+ /// Step 9, "sort destinations"
+ /// of https://html.spec.whatwg.org/multipage/#dom-broadcastchannel-postmessage
+ /// requires keeping track of creation order, hence the queue.
+ Managed(
+ BroadcastChannelRouterId,
+ /// The map of channel-name to queue of channels, in order of creation.
+ HashMap<DOMString, VecDeque<Dom<BroadcastChannel>>>,
+ ),
+ /// This global is not managing any broadcast channels at this time.
+ UnManaged,
+}
+
/// State representing whether this global is currently managing messageports.
#[derive(JSTraceable, MallocSizeOf)]
#[unrooted_must_root_lint::must_root]
@@ -323,6 +352,29 @@ pub enum MessagePortState {
UnManaged,
}
+impl BroadcastListener {
+ /// Handle a broadcast coming in over IPC,
+ /// by queueing the appropriate task on the relevant event-loop.
+ fn handle(&self, event: BroadcastMsg) {
+ let context = self.context.clone();
+
+ // Note: strictly speaking we should just queue the message event tasks,
+ // not queue a task that then queues more tasks.
+ // This however seems to be hard to avoid in the light of the IPC.
+ // One can imagine queueing tasks directly,
+ // for channels that would be in the same script-thread.
+ let _ = self.task_source.queue_with_canceller(
+ task!(broadcast_message_event: move || {
+ let global = context.root();
+ // Step 10 of https://html.spec.whatwg.org/multipage/#dom-broadcastchannel-postmessage,
+ // For each BroadcastChannel object destination in destinations, queue a task.
+ global.broadcast_message_event(event, None);
+ }),
+ &self.canceller,
+ );
+ }
+}
+
impl TimerListener {
/// Handle a timer-event coming-in over IPC,
/// by queuing the appropriate task on the relevant event-loop.
@@ -501,6 +553,7 @@ impl GlobalScope {
) -> Self {
Self {
message_port_state: DomRefCell::new(MessagePortState::UnManaged),
+ broadcast_channel_state: DomRefCell::new(BroadcastChannelState::UnManaged),
blob_state: DomRefCell::new(BlobState::UnManaged),
eventtarget: EventTarget::new_inherited(),
crypto: Default::default(),
@@ -519,6 +572,7 @@ impl GlobalScope {
timers: OneshotTimers::new(scheduler_chan),
init_timers: Default::default(),
origin,
+ permission_state_invocation_results: Default::default(),
microtask_queue,
list_auto_close_worker: Default::default(),
event_source_tracker: DOMTracker::new(),
@@ -613,11 +667,18 @@ impl GlobalScope {
pub fn perform_a_dom_garbage_collection_checkpoint(&self) {
self.perform_a_message_port_garbage_collection_checkpoint();
self.perform_a_blob_garbage_collection_checkpoint();
+ self.perform_a_broadcast_channel_garbage_collection_checkpoint();
+ }
+
+ /// Remove the routers for ports and broadcast-channels.
+ pub fn remove_web_messaging_infra(&self) {
+ self.remove_message_ports_router();
+ self.remove_broadcast_channel_router();
}
/// Update our state to un-managed,
/// and tell the constellation to drop the sender to our message-port router.
- pub fn remove_message_ports_router(&self) {
+ fn remove_message_ports_router(&self) {
if let MessagePortState::Managed(router_id, _message_ports) =
&*self.message_port_state.borrow()
{
@@ -628,6 +689,22 @@ impl GlobalScope {
*self.message_port_state.borrow_mut() = MessagePortState::UnManaged;
}
+ /// Update our state to un-managed,
+ /// and tell the constellation to drop the sender to our broadcast router.
+ fn remove_broadcast_channel_router(&self) {
+ if let BroadcastChannelState::Managed(router_id, _channels) =
+ &*self.broadcast_channel_state.borrow()
+ {
+ let _ =
+ self.script_to_constellation_chan()
+ .send(ScriptMsg::RemoveBroadcastChannelRouter(
+ router_id.clone(),
+ self.origin().immutable().clone(),
+ ));
+ }
+ *self.broadcast_channel_state.borrow_mut() = BroadcastChannelState::UnManaged;
+ }
+
/// <https://html.spec.whatwg.org/multipage/#entangle>
pub fn entangle_ports(&self, port1: MessagePortId, port2: MessagePortId) {
if let MessagePortState::Managed(_id, message_ports) =
@@ -789,6 +866,115 @@ impl GlobalScope {
.send(ScriptMsg::RerouteMessagePort(port_id, task));
}
+ /// <https://html.spec.whatwg.org/multipage/#dom-broadcastchannel-postmessage>
+ /// Step 7 and following steps.
+ pub fn schedule_broadcast(&self, msg: BroadcastMsg, channel_id: &Uuid) {
+ // First, broadcast locally.
+ self.broadcast_message_event(msg.clone(), Some(channel_id));
+
+ if let BroadcastChannelState::Managed(router_id, _) =
+ &*self.broadcast_channel_state.borrow()
+ {
+ // Second, broadcast to other globals via the constellation.
+ //
+ // Note: for globals in the same script-thread,
+ // we could skip the hop to the constellation.
+ let _ = self
+ .script_to_constellation_chan()
+ .send(ScriptMsg::ScheduleBroadcast(router_id.clone(), msg));
+ } else {
+ panic!("Attemps to broadcast a message via global not managing any channels.");
+ }
+ }
+
+ /// <https://html.spec.whatwg.org/multipage/#dom-broadcastchannel-postmessage>
+ /// Step 7 and following steps.
+ pub fn broadcast_message_event(&self, event: BroadcastMsg, channel_id: Option<&Uuid>) {
+ if let BroadcastChannelState::Managed(_, channels) = &*self.broadcast_channel_state.borrow()
+ {
+ let BroadcastMsg {
+ data,
+ origin,
+ channel_name,
+ } = event;
+
+ // Step 7, a few preliminary steps.
+
+ // - Check the worker is not closing.
+ if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
+ if worker.is_closing() {
+ return;
+ }
+ }
+
+ // - Check the associated document is fully-active.
+ if let Some(window) = self.downcast::<Window>() {
+ if !window.Document().is_fully_active() {
+ return;
+ }
+ }
+
+ // - Check for a case-sensitive match for the name of the channel.
+ let channel_name = DOMString::from_string(channel_name);
+
+ if let Some(channels) = channels.get(&channel_name) {
+ channels
+ .iter()
+ .filter(|ref channel| {
+ // Step 8.
+ // Filter out the sender.
+ if let Some(id) = channel_id {
+ channel.id() != id
+ } else {
+ true
+ }
+ })
+ .map(|channel| DomRoot::from_ref(&**channel))
+ // Step 9, sort by creation order,
+ // done by using a queue to store channels in creation order.
+ .for_each(|channel| {
+ let data = data.clone_for_broadcast();
+ let origin = origin.clone();
+
+ // Step 10: Queue a task on the DOM manipulation task-source,
+ // to fire the message event
+ let channel = Trusted::new(&*channel);
+ let global = Trusted::new(&*self);
+ let _ = self.dom_manipulation_task_source().queue(
+ task!(process_pending_port_messages: move || {
+ let destination = channel.root();
+ let global = global.root();
+
+ // 10.1 Check for closed flag.
+ if destination.closed() {
+ return;
+ }
+
+ rooted!(in(*global.get_cx()) let mut message = UndefinedValue());
+
+ // Step 10.3 StructuredDeserialize(serialized, targetRealm).
+ if let Ok(ports) = structuredclone::read(&global, data, message.handle_mut()) {
+ // Step 10.4, Fire an event named message at destination.
+ MessageEvent::dispatch_jsval(
+ &*destination.upcast(),
+ &global,
+ message.handle(),
+ Some(&origin.ascii_serialization()),
+ None,
+ ports,
+ );
+ } else {
+ // Step 10.3, fire an event named messageerror at destination.
+ MessageEvent::dispatch_error(&*destination.upcast(), &global);
+ }
+ }),
+ &self,
+ );
+ });
+ }
+ }
+ }
+
/// Route the task to be handled by the relevant port.
pub fn route_task_to_port(&self, port_id: MessagePortId, task: PortMessageTask) {
let should_dispatch = if let MessagePortState::Managed(_id, message_ports) =
@@ -905,6 +1091,93 @@ impl GlobalScope {
}
}
+ /// Remove broadcast-channels that are closed.
+ /// TODO: Also remove them if they do not have an event-listener.
+ /// see https://github.com/servo/servo/issues/25772
+ pub fn perform_a_broadcast_channel_garbage_collection_checkpoint(&self) {
+ let is_empty = if let BroadcastChannelState::Managed(router_id, ref mut channels) =
+ &mut *self.broadcast_channel_state.borrow_mut()
+ {
+ channels.retain(|name, ref mut channels| {
+ channels.retain(|ref chan| !chan.closed());
+ if channels.is_empty() {
+ let _ = self.script_to_constellation_chan().send(
+ ScriptMsg::RemoveBroadcastChannelNameInRouter(
+ router_id.clone(),
+ name.to_string(),
+ self.origin().immutable().clone(),
+ ),
+ );
+ false
+ } else {
+ true
+ }
+ });
+ channels.is_empty()
+ } else {
+ false
+ };
+ if is_empty {
+ self.remove_broadcast_channel_router();
+ }
+ }
+
+ /// Start tracking a broadcast-channel.
+ pub fn track_broadcast_channel(&self, dom_channel: &BroadcastChannel) {
+ let mut current_state = self.broadcast_channel_state.borrow_mut();
+
+ if let BroadcastChannelState::UnManaged = &*current_state {
+ // Setup a route for IPC, for broadcasts from the constellation to our channels.
+ let (broadcast_control_sender, broadcast_control_receiver) =
+ ipc::channel().expect("ipc channel failure");
+ let context = Trusted::new(self);
+ let (task_source, canceller) = (
+ self.dom_manipulation_task_source(),
+ self.task_canceller(TaskSourceName::DOMManipulation),
+ );
+ let listener = BroadcastListener {
+ canceller,
+ task_source,
+ context,
+ };
+ ROUTER.add_route(
+ broadcast_control_receiver.to_opaque(),
+ Box::new(move |message| {
+ let msg = message.to();
+ match msg {
+ Ok(msg) => listener.handle(msg),
+ Err(err) => warn!("Error receiving a BroadcastMsg: {:?}", err),
+ }
+ }),
+ );
+ let router_id = BroadcastChannelRouterId::new();
+ *current_state = BroadcastChannelState::Managed(router_id.clone(), HashMap::new());
+ let _ = self
+ .script_to_constellation_chan()
+ .send(ScriptMsg::NewBroadcastChannelRouter(
+ router_id,
+ broadcast_control_sender,
+ self.origin().immutable().clone(),
+ ));
+ }
+
+ if let BroadcastChannelState::Managed(router_id, channels) = &mut *current_state {
+ let entry = channels.entry(dom_channel.Name()).or_insert_with(|| {
+ let _ = self.script_to_constellation_chan().send(
+ ScriptMsg::NewBroadcastChannelNameInRouter(
+ router_id.clone(),
+ dom_channel.Name().to_string(),
+ self.origin().immutable().clone(),
+ ),
+ );
+ VecDeque::new()
+ });
+ entry.push_back(Dom::from_ref(dom_channel));
+ } else {
+ panic!("track_broadcast_channel should have first switched the state to managed.");
+ }
+ }
+
/// Start tracking a message-port
pub fn track_message_port(&self, dom_port: &MessagePort, port_impl: Option<MessagePortImpl>) {
let mut current_state = self.message_port_state.borrow_mut();
@@ -1400,8 +1673,7 @@ impl GlobalScope {
let resource_threads = self.resource_threads();
let (chan, recv) = profile_ipc::channel(self.time_profiler_chan().clone()).unwrap();
let origin = get_blob_origin(&self.get_url());
- let check_url_validity = false;
- let msg = FileManagerThreadMsg::ReadFile(chan, id, check_url_validity, origin);
+ let msg = FileManagerThreadMsg::ReadFile(chan, id, origin);
let _ = resource_threads.send(CoreResourceMsg::ToFileManager(msg));
recv
}
@@ -1427,6 +1699,12 @@ impl GlobalScope {
}
}
+ pub fn permission_state_invocation_results(
+ &self,
+ ) -> &DomRefCell<HashMap<String, PermissionState>> {
+ &self.permission_state_invocation_results
+ }
+
pub fn track_worker(&self, closing_worker: Arc<AtomicBool>) {
self.list_auto_close_worker
.borrow_mut()
@@ -1632,6 +1910,14 @@ impl GlobalScope {
&self.script_to_constellation_chan
}
+ pub fn send_to_embedder(&self, msg: EmbedderMsg) {
+ self.send_to_constellation(ScriptMsg::ForwardToEmbedder(msg));
+ }
+
+ pub fn send_to_constellation(&self, msg: ScriptMsg) {
+ self.script_to_constellation_chan().send(msg).unwrap();
+ }
+
pub fn scheduler_chan(&self) -> &IpcSender<TimerSchedulerMsg> {
&self.scheduler_chan
}
@@ -1872,15 +2158,20 @@ impl GlobalScope {
let ar = enter_realm(&*self);
let _aes = AutoEntryScript::new(self);
- let options = CompileOptionsWrapper::new(*cx, filename.as_ptr(), line_number);
+ let options =
+ unsafe { CompileOptionsWrapper::new(*cx, filename.as_ptr(), line_number) };
debug!("evaluating Dom string");
let result = unsafe {
- EvaluateUtf8(
+ Evaluate2(
*cx,
options.ptr,
- code.as_ptr() as *const _,
- code.len() as libc::size_t,
+ &mut SourceText {
+ units_: code.as_ptr() as *const _,
+ length_: code.len() as u32,
+ ownsUnits_: false,
+ _phantom_0: PhantomData,
+ },
rval,
)
};
@@ -2155,50 +2446,8 @@ impl GlobalScope {
None
}
- pub fn wgpu_create_adapter_ids(&self) -> SmallVec<[AdapterId; 4]> {
- self.gpu_id_hub.borrow_mut().create_adapter_ids()
- }
-
- pub fn wgpu_create_bind_group_id(&self, backend: Backend) -> BindGroupId {
- self.gpu_id_hub.borrow_mut().create_bind_group_id(backend)
- }
-
- pub fn wgpu_create_bind_group_layout_id(&self, backend: Backend) -> BindGroupLayoutId {
- self.gpu_id_hub
- .borrow_mut()
- .create_bind_group_layout_id(backend)
- }
-
- pub fn wgpu_create_buffer_id(&self, backend: Backend) -> BufferId {
- self.gpu_id_hub.borrow_mut().create_buffer_id(backend)
- }
-
- pub fn wgpu_create_device_id(&self, backend: Backend) -> DeviceId {
- self.gpu_id_hub.borrow_mut().create_device_id(backend)
- }
-
- pub fn wgpu_create_pipeline_layout_id(&self, backend: Backend) -> PipelineLayoutId {
- self.gpu_id_hub
- .borrow_mut()
- .create_pipeline_layout_id(backend)
- }
-
- pub fn wgpu_create_shader_module_id(&self, backend: Backend) -> ShaderModuleId {
- self.gpu_id_hub
- .borrow_mut()
- .create_shader_module_id(backend)
- }
-
- pub fn wgpu_create_compute_pipeline_id(&self, backend: Backend) -> ComputePipelineId {
- self.gpu_id_hub
- .borrow_mut()
- .create_compute_pipeline_id(backend)
- }
-
- pub fn wgpu_create_command_encoder_id(&self, backend: Backend) -> CommandEncoderId {
- self.gpu_id_hub
- .borrow_mut()
- .create_command_encoder_id(backend)
+ pub fn wgpu_id_hub(&self) -> RefMut<Identities> {
+ self.gpu_id_hub.borrow_mut()
}
}
diff --git a/components/script/dom/gpu.rs b/components/script/dom/gpu.rs
index 8f129e14c30..e2f7e3e5a82 100644
--- a/components/script/dom/gpu.rs
+++ b/components/script/dom/gpu.rs
@@ -115,7 +115,7 @@ impl GPUMethods for GPU {
},
None => wgpu::instance::PowerPreference::Default,
};
- let ids = global.wgpu_create_adapter_ids();
+ let ids = global.wgpu_id_hub().create_adapter_ids();
let script_to_constellation_chan = global.script_to_constellation_chan();
if script_to_constellation_chan
@@ -135,13 +135,17 @@ impl GPUMethods for GPU {
impl AsyncWGPUListener for GPU {
fn handle_response(&self, response: WebGPUResponse, promise: &Rc<Promise>) {
match response {
- WebGPUResponse::RequestAdapter(name, adapter, channel) => {
+ WebGPUResponse::RequestAdapter {
+ adapter_name,
+ adapter_id,
+ channel,
+ } => {
let adapter = GPUAdapter::new(
&self.global(),
channel,
- DOMString::from(format!("{} ({:?})", name, adapter.0.backend())),
+ DOMString::from(format!("{} ({:?})", adapter_name, adapter_id.0.backend())),
Heap::default(),
- adapter,
+ adapter_id,
);
promise.resolve_native(&adapter);
},
diff --git a/components/script/dom/gpuadapter.rs b/components/script/dom/gpuadapter.rs
index abf8844522d..34f040405c1 100644
--- a/components/script/dom/gpuadapter.rs
+++ b/components/script/dom/gpuadapter.rs
@@ -91,11 +91,17 @@ impl GPUAdapterMethods for GPUAdapter {
};
let id = self
.global()
- .wgpu_create_device_id(self.adapter.0.backend());
+ .wgpu_id_hub()
+ .create_device_id(self.adapter.0.backend());
if self
.channel
.0
- .send(WebGPURequest::RequestDevice(sender, self.adapter, desc, id))
+ .send(WebGPURequest::RequestDevice {
+ sender,
+ adapter_id: self.adapter,
+ descriptor: desc,
+ device_id: id,
+ })
.is_err()
{
promise.reject_error(Error::Operation);
@@ -107,7 +113,11 @@ impl GPUAdapterMethods for GPUAdapter {
impl AsyncWGPUListener for GPUAdapter {
fn handle_response(&self, response: WebGPUResponse, promise: &Rc<Promise>) {
match response {
- WebGPUResponse::RequestDevice(device_id, queue_id, _descriptor) => {
+ WebGPUResponse::RequestDevice {
+ device_id,
+ queue_id,
+ _descriptor,
+ } => {
let device = GPUDevice::new(
&self.global(),
self.channel.clone(),
diff --git a/components/script/dom/gpubuffer.rs b/components/script/dom/gpubuffer.rs
index e0694e4d726..fc2d17a689e 100644
--- a/components/script/dom/gpubuffer.rs
+++ b/components/script/dom/gpubuffer.rs
@@ -6,17 +6,36 @@ use crate::dom::bindings::cell::{DomRefCell, Ref};
use crate::dom::bindings::codegen::Bindings::GPUBufferBinding::{
self, GPUBufferMethods, GPUBufferSize,
};
+use crate::dom::bindings::error::Error;
+use crate::dom::bindings::reflector::DomObject;
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::str::DOMString;
+use crate::dom::bindings::trace::RootedTraceableBox;
use crate::dom::globalscope::GlobalScope;
+use crate::dom::gpu::{response_async, AsyncWGPUListener};
+use crate::dom::promise::Promise;
+use crate::realms::InRealm;
use dom_struct::dom_struct;
+use js::jsapi::{Heap, JSObject};
+use js::jsval::UndefinedValue;
+use js::rust::jsapi_wrapped::{DetachArrayBuffer, IsPromiseObject, RejectPromise};
+use js::rust::MutableHandle;
+use js::typedarray::{ArrayBuffer, CreateWith};
use std::cell::Cell;
-use webgpu::{WebGPU, WebGPUBuffer, WebGPUDevice, WebGPURequest};
+use std::ptr;
+use std::rc::Rc;
+use webgpu::{
+ wgpu::resource::BufferUsage, WebGPU, WebGPUBuffer, WebGPUDevice, WebGPURequest, WebGPUResponse,
+};
-#[derive(MallocSizeOf)]
+// https://gpuweb.github.io/gpuweb/#buffer-state
+#[derive(Clone, MallocSizeOf)]
pub enum GPUBufferState {
- Mapped,
+ MappedForReading,
+ MappedForWriting,
+ MappedPendingForReading,
+ MappedPendingForWriting,
Unmapped,
Destroyed,
}
@@ -24,7 +43,7 @@ pub enum GPUBufferState {
#[dom_struct]
pub struct GPUBuffer {
reflector_: Reflector,
- #[ignore_malloc_size_of = "channels are hard"]
+ #[ignore_malloc_size_of = "defined in webgpu"]
channel: WebGPU,
label: DomRefCell<Option<DOMString>>,
size: GPUBufferSize,
@@ -33,6 +52,8 @@ pub struct GPUBuffer {
buffer: WebGPUBuffer,
device: WebGPUDevice,
valid: Cell<bool>,
+ #[ignore_malloc_size_of = "defined in mozjs"]
+ mapping: RootedTraceableBox<Heap<*mut JSObject>>,
}
impl GPUBuffer {
@@ -44,6 +65,7 @@ impl GPUBuffer {
size: GPUBufferSize,
usage: u32,
valid: bool,
+ mapping: RootedTraceableBox<Heap<*mut JSObject>>,
) -> GPUBuffer {
Self {
reflector_: Reflector::new(),
@@ -55,6 +77,7 @@ impl GPUBuffer {
valid: Cell::new(valid),
device,
buffer,
+ mapping,
}
}
@@ -68,10 +91,11 @@ impl GPUBuffer {
size: GPUBufferSize,
usage: u32,
valid: bool,
+ mapping: RootedTraceableBox<Heap<*mut JSObject>>,
) -> DomRoot<GPUBuffer> {
reflect_dom_object(
Box::new(GPUBuffer::new_inherited(
- channel, buffer, device, state, size, usage, valid,
+ channel, buffer, device, state, size, usage, valid, mapping,
)),
global,
GPUBufferBinding::Wrap,
@@ -104,30 +128,136 @@ impl Drop for GPUBuffer {
}
impl GPUBufferMethods for GPUBuffer {
+ #[allow(unsafe_code)]
/// https://gpuweb.github.io/gpuweb/#dom-gpubuffer-unmap
fn Unmap(&self) {
- self.channel
- .0
- .send(WebGPURequest::UnmapBuffer(self.buffer))
- .unwrap();
+ let cx = self.global().get_cx();
+ // Step 1
+ match *self.state.borrow() {
+ GPUBufferState::Unmapped | GPUBufferState::Destroyed => {
+ // TODO: Record validation error on the current scope
+ return;
+ },
+ GPUBufferState::MappedForWriting => {
+ // Step 3.1
+ match ArrayBuffer::from(self.mapping.get()) {
+ Ok(array_buffer) => {
+ self.channel
+ .0
+ .send(WebGPURequest::UnmapBuffer {
+ device_id: self.device.0,
+ buffer_id: self.id().0,
+ array_buffer: array_buffer.to_vec(),
+ })
+ .unwrap();
+ // Step 3.2
+ unsafe {
+ DetachArrayBuffer(*cx, self.mapping.handle());
+ }
+ },
+ _ => {
+ // Step 2
+ unsafe {
+ if IsPromiseObject(self.mapping.handle()) {
+ let err = Error::Abort;
+ rooted!(in(*cx) let mut undef = UndefinedValue());
+ err.to_jsval(*cx, &self.global(), undef.handle_mut());
+ RejectPromise(*cx, self.mapping.handle(), undef.handle());
+ };
+ }
+ },
+ };
+ },
+ _ => {},
+ };
+ // Step 3.3
+ self.mapping.set(ptr::null_mut());
+ // Step 4
*self.state.borrow_mut() = GPUBufferState::Unmapped;
}
/// https://gpuweb.github.io/gpuweb/#dom-gpubuffer-destroy
fn Destroy(&self) {
- match *self.state.borrow() {
- GPUBufferState::Mapped => {
+ let state = self.state.borrow().clone();
+ match state {
+ GPUBufferState::MappedForReading | GPUBufferState::MappedForWriting => {
self.Unmap();
},
_ => {},
};
self.channel
.0
- .send(WebGPURequest::DestroyBuffer(self.buffer))
+ .send(WebGPURequest::DestroyBuffer(self.buffer.0))
.unwrap();
*self.state.borrow_mut() = GPUBufferState::Destroyed;
}
+ #[allow(unsafe_code)]
+ /// https://gpuweb.github.io/gpuweb/#dom-gpubuffer-mapreadasync
+ fn MapReadAsync(&self, comp: InRealm) -> Rc<Promise> {
+ // Step 1 & 2
+ let promise = Promise::new_in_current_realm(&self.global(), comp);
+ match *self.state.borrow() {
+ GPUBufferState::Unmapped => {
+ match BufferUsage::from_bits(self.usage) {
+ Some(usage) => {
+ if !usage.contains(BufferUsage::MAP_READ) {
+ // TODO: Record validation error on the current scope
+ promise.reject_error(Error::Abort);
+ return promise;
+ };
+ },
+ None => {
+ promise.reject_error(Error::Abort);
+ return promise;
+ },
+ }
+ },
+ _ => {
+ promise.reject_error(Error::Abort);
+ return promise;
+ },
+ }
+ // Step 3
+ self.mapping.set(*promise.promise_obj());
+ // Step 4
+ *self.state.borrow_mut() = GPUBufferState::MappedPendingForReading;
+
+ // Step 5.1
+ if unsafe {
+ ArrayBuffer::create(
+ *self.global().get_cx(),
+ CreateWith::Length(self.size as u32),
+ MutableHandle::from_raw(self.mapping.handle_mut()),
+ )
+ }
+ .is_err()
+ {
+ promise.reject_error(Error::Operation);
+ return promise;
+ }
+
+ let sender = response_async(&promise, self);
+ if self
+ .channel
+ .0
+ .send(WebGPURequest::MapReadAsync {
+ sender,
+ buffer_id: self.buffer.0,
+ device_id: self.device.0,
+ usage: self.usage,
+ size: self.size,
+ })
+ .is_err()
+ {
+ promise.reject_error(Error::Operation);
+ return promise;
+ }
+
+ // Step 6
+ promise
+ }
+
/// https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label
fn GetLabel(&self) -> Option<DOMString> {
self.label.borrow().clone()
@@ -138,3 +268,25 @@ impl GPUBufferMethods for GPUBuffer {
*self.label.borrow_mut() = value;
}
}
+
+impl AsyncWGPUListener for GPUBuffer {
+ #[allow(unsafe_code)]
+ fn handle_response(&self, response: WebGPUResponse, promise: &Rc<Promise>) {
+ match response {
+ WebGPUResponse::MapReadAsync(bytes) => unsafe {
+ match ArrayBuffer::from(self.mapping.get()) {
+ Ok(mut array_buffer) => {
+ // Step 5.2
+ array_buffer.update(&bytes);
+ // Step 5.3
+ *self.state.borrow_mut() = GPUBufferState::MappedForReading;
+ // Step 5.4
+ promise.resolve_native(&array_buffer);
+ },
+ _ => promise.reject_error(Error::Operation),
+ };
+ },
+ _ => promise.reject_error(Error::Operation),
+ }
+ }
+}
diff --git a/components/script/dom/gpucommandencoder.rs b/components/script/dom/gpucommandencoder.rs
index 03b9373f3ab..348e77828f1 100644
--- a/components/script/dom/gpucommandencoder.rs
+++ b/components/script/dom/gpucommandencoder.rs
@@ -87,14 +87,14 @@ impl GPUCommandEncoderMethods for GPUCommandEncoder {
.insert(DomRoot::from_ref(destination));
self.channel
.0
- .send(WebGPURequest::CopyBufferToBuffer(
- self.encoder.0,
- source.id().0,
+ .send(WebGPURequest::CopyBufferToBuffer {
+ command_encoder_id: self.encoder.0,
+ source_id: source.id().0,
source_offset,
- destination.id().0,
+ destination_id: destination.id().0,
destination_offset,
size,
- ))
+ })
.expect("Failed to send CopyBufferToBuffer");
}
@@ -103,12 +103,12 @@ impl GPUCommandEncoderMethods for GPUCommandEncoder {
let (sender, receiver) = ipc::channel().unwrap();
self.channel
.0
- .send(WebGPURequest::CommandEncoderFinish(
+ .send(WebGPURequest::CommandEncoderFinish {
sender,
- self.encoder.0,
+ command_encoder_id: self.encoder.0,
// TODO(zakorgy): We should use `_descriptor` here after it's not empty
// and the underlying wgpu-core struct is serializable
- ))
+ })
.expect("Failed to send Finish");
let buffer = receiver.recv().unwrap();
diff --git a/components/script/dom/gpucomputepassencoder.rs b/components/script/dom/gpucomputepassencoder.rs
index f6116c88f9d..a25f47e1330 100644
--- a/components/script/dom/gpucomputepassencoder.rs
+++ b/components/script/dom/gpucomputepassencoder.rs
@@ -81,11 +81,14 @@ impl GPUComputePassEncoderMethods for GPUComputePassEncoder {
/// https://gpuweb.github.io/gpuweb/#dom-gpurenderpassencoder-endpass
fn EndPass(&self) {
if let Some(raw_pass) = self.raw_pass.borrow_mut().take() {
- let (pass_data, id) = unsafe { raw_pass.finish_compute() };
+ let (pass_data, command_encoder_id) = unsafe { raw_pass.finish_compute() };
self.channel
.0
- .send(WebGPURequest::RunComputePass(id, pass_data))
+ .send(WebGPURequest::RunComputePass {
+ command_encoder_id,
+ pass_data,
+ })
.unwrap();
}
}
diff --git a/components/script/dom/gpudevice.rs b/components/script/dom/gpudevice.rs
index 1d17961f87c..4a1e4747715 100644
--- a/components/script/dom/gpudevice.rs
+++ b/components/script/dom/gpudevice.rs
@@ -46,7 +46,7 @@ use webgpu::wgpu::binding_model::{
ShaderStage,
};
use webgpu::wgpu::resource::{BufferDescriptor, BufferUsage};
-use webgpu::{WebGPU, WebGPUBuffer, WebGPUDevice, WebGPUQueue, WebGPURequest};
+use webgpu::{WebGPU, WebGPUDevice, WebGPUQueue, WebGPURequest};
#[dom_struct]
pub struct GPUDevice {
@@ -106,38 +106,6 @@ impl GPUDevice {
}
impl GPUDevice {
- unsafe fn resolve_create_buffer_mapped(
- &self,
- cx: SafeJSContext,
- 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(),
- self.channel.clone(),
- 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,
@@ -201,15 +169,18 @@ impl GPUDeviceMethods for GPUDevice {
fn CreateBuffer(&self, descriptor: &GPUBufferDescriptor) -> DomRoot<GPUBuffer> {
let (valid, wgpu_descriptor) = self.validate_buffer_descriptor(descriptor);
let (sender, receiver) = ipc::channel().unwrap();
- let id = self.global().wgpu_create_buffer_id(self.device.0.backend());
+ let id = self
+ .global()
+ .wgpu_id_hub()
+ .create_buffer_id(self.device.0.backend());
self.channel
.0
- .send(WebGPURequest::CreateBuffer(
+ .send(WebGPURequest::CreateBuffer {
sender,
- self.device,
- id,
- wgpu_descriptor,
- ))
+ device_id: self.device.0,
+ buffer_id: id,
+ descriptor: wgpu_descriptor,
+ })
.expect("Failed to create WebGPU buffer");
let buffer = receiver.recv().unwrap();
@@ -223,6 +194,7 @@ impl GPUDeviceMethods for GPUDevice {
descriptor.size,
descriptor.usage,
valid,
+ RootedTraceableBox::new(Heap::default()),
)
}
@@ -234,22 +206,47 @@ impl GPUDeviceMethods for GPUDevice {
) -> Vec<JSVal> {
let (valid, wgpu_descriptor) = self.validate_buffer_descriptor(descriptor);
let (sender, receiver) = ipc::channel().unwrap();
- let id = self.global().wgpu_create_buffer_id(self.device.0.backend());
+ let buffer_id = self
+ .global()
+ .wgpu_id_hub()
+ .create_buffer_id(self.device.0.backend());
self.channel
.0
- .send(WebGPURequest::CreateBufferMapped(
+ .send(WebGPURequest::CreateBufferMapped {
sender,
- self.device,
- id,
- wgpu_descriptor.clone(),
- ))
+ device_id: self.device.0,
+ buffer_id,
+ descriptor: wgpu_descriptor.clone(),
+ })
.expect("Failed to create WebGPU buffer");
- let (buffer, array_buffer) = receiver.recv().unwrap();
-
+ rooted!(in(*cx) let mut js_array_buffer = ptr::null_mut::<JSObject>());
unsafe {
- self.resolve_create_buffer_mapped(cx, buffer, array_buffer, wgpu_descriptor, valid)
+ assert!(ArrayBuffer::create(
+ *cx,
+ CreateWith::Length(descriptor.size as u32),
+ js_array_buffer.handle_mut(),
+ )
+ .is_ok());
}
+
+ let buffer = receiver.recv().unwrap();
+ let buff = GPUBuffer::new(
+ &self.global(),
+ self.channel.clone(),
+ buffer,
+ self.device,
+ GPUBufferState::MappedForWriting,
+ wgpu_descriptor.size,
+ wgpu_descriptor.usage.bits(),
+ valid,
+ RootedTraceableBox::from_box(Heap::boxed(js_array_buffer.get())),
+ );
+
+ vec![
+ ObjectValue(buff.reflector().get_jsobject().get()),
+ ObjectValue(js_array_buffer.get()),
+ ]
}
/// https://gpuweb.github.io/gpuweb/#GPUDevice-createBindGroupLayout
@@ -394,17 +391,18 @@ impl GPUDeviceMethods for GPUDevice {
max_dynamic_storage_buffers_per_pipeline_layout >= 0;
let (sender, receiver) = ipc::channel().unwrap();
- let id = self
+ let bind_group_layout_id = self
.global()
- .wgpu_create_bind_group_layout_id(self.device.0.backend());
+ .wgpu_id_hub()
+ .create_bind_group_layout_id(self.device.0.backend());
self.channel
.0
- .send(WebGPURequest::CreateBindGroupLayout(
+ .send(WebGPURequest::CreateBindGroupLayout {
sender,
- self.device,
- id,
- bindings.clone(),
- ))
+ device_id: self.device.0,
+ bind_group_layout_id,
+ bindings: bindings.clone(),
+ })
.expect("Failed to create WebGPU BindGroupLayout");
let bgl = receiver.recv().unwrap();
@@ -472,17 +470,18 @@ impl GPUDeviceMethods for GPUDevice {
max_dynamic_storage_buffers_per_pipeline_layout >= 0;
let (sender, receiver) = ipc::channel().unwrap();
- let id = self
+ let pipeline_layout_id = self
.global()
- .wgpu_create_pipeline_layout_id(self.device.0.backend());
+ .wgpu_id_hub()
+ .create_pipeline_layout_id(self.device.0.backend());
self.channel
.0
- .send(WebGPURequest::CreatePipelineLayout(
+ .send(WebGPURequest::CreatePipelineLayout {
sender,
- self.device,
- id,
- bgl_ids,
- ))
+ device_id: self.device.0,
+ pipeline_layout_id,
+ bind_group_layouts: bgl_ids,
+ })
.expect("Failed to create WebGPU PipelineLayout");
let pipeline_layout = receiver.recv().unwrap();
@@ -531,18 +530,19 @@ impl GPUDeviceMethods for GPUDevice {
})
.collect::<Vec<_>>();
let (sender, receiver) = ipc::channel().unwrap();
- let id = self
+ let bind_group_id = self
.global()
- .wgpu_create_bind_group_id(self.device.0.backend());
+ .wgpu_id_hub()
+ .create_bind_group_id(self.device.0.backend());
self.channel
.0
- .send(WebGPURequest::CreateBindGroup(
+ .send(WebGPURequest::CreateBindGroup {
sender,
- self.device,
- id,
- descriptor.layout.id(),
+ device_id: self.device.0,
+ bind_group_id,
+ bind_group_layout_id: descriptor.layout.id().0,
bindings,
- ))
+ })
.expect("Failed to create WebGPU BindGroup");
let bind_group = receiver.recv().unwrap();
@@ -559,17 +559,18 @@ impl GPUDeviceMethods for GPUDevice {
Uint32Array(program) => program.to_vec(),
String(program) => program.chars().map(|c| c as u32).collect::<Vec<u32>>(),
};
- let id = self
+ let program_id = self
.global()
- .wgpu_create_shader_module_id(self.device.0.backend());
+ .wgpu_id_hub()
+ .create_shader_module_id(self.device.0.backend());
self.channel
.0
- .send(WebGPURequest::CreateShaderModule(
+ .send(WebGPURequest::CreateShaderModule {
sender,
- self.device,
- id,
+ device_id: self.device.0,
+ program_id,
program,
- ))
+ })
.expect("Failed to create WebGPU ShaderModule");
let shader_module = receiver.recv().unwrap();
@@ -584,20 +585,21 @@ impl GPUDeviceMethods for GPUDevice {
let pipeline = descriptor.parent.layout.id();
let program = descriptor.computeStage.module.id();
let entry_point = descriptor.computeStage.entryPoint.to_string();
- let id = self
+ let compute_pipeline_id = self
.global()
- .wgpu_create_compute_pipeline_id(self.device.0.backend());
+ .wgpu_id_hub()
+ .create_compute_pipeline_id(self.device.0.backend());
let (sender, receiver) = ipc::channel().unwrap();
self.channel
.0
- .send(WebGPURequest::CreateComputePipeline(
+ .send(WebGPURequest::CreateComputePipeline {
sender,
- self.device,
- id,
- pipeline.0,
- program.0,
+ device_id: self.device.0,
+ compute_pipeline_id,
+ pipeline_layout_id: pipeline.0,
+ program_id: program.0,
entry_point,
- ))
+ })
.expect("Failed to create WebGPU ComputePipeline");
let compute_pipeline = receiver.recv().unwrap();
@@ -609,12 +611,17 @@ impl GPUDeviceMethods for GPUDevice {
_descriptor: &GPUCommandEncoderDescriptor,
) -> DomRoot<GPUCommandEncoder> {
let (sender, receiver) = ipc::channel().unwrap();
- let id = self
+ let command_encoder_id = self
.global()
- .wgpu_create_command_encoder_id(self.device.0.backend());
+ .wgpu_id_hub()
+ .create_command_encoder_id(self.device.0.backend());
self.channel
.0
- .send(WebGPURequest::CreateCommandEncoder(sender, self.device, id))
+ .send(WebGPURequest::CreateCommandEncoder {
+ sender,
+ device_id: self.device.0,
+ command_encoder_id,
+ })
.expect("Failed to create WebGPU command encoder");
let encoder = receiver.recv().unwrap();
diff --git a/components/script/dom/gpuqueue.rs b/components/script/dom/gpuqueue.rs
index dfa97402253..c257ec5ef09 100644
--- a/components/script/dom/gpuqueue.rs
+++ b/components/script/dom/gpuqueue.rs
@@ -64,10 +64,13 @@ impl GPUQueueMethods for GPUQueue {
// TODO: Generate error to the ErrorScope
return;
}
- let buffer_ids = command_buffers.iter().map(|cb| cb.id().0).collect();
+ let command_buffers = command_buffers.iter().map(|cb| cb.id().0).collect();
self.channel
.0
- .send(WebGPURequest::Submit(self.queue.0, buffer_ids))
+ .send(WebGPURequest::Submit {
+ queue_id: self.queue.0,
+ command_buffers,
+ })
.unwrap();
}
}
diff --git a/components/script/dom/htmlcanvaselement.rs b/components/script/dom/htmlcanvaselement.rs
index e800a89bdf1..e56ca4a8266 100644
--- a/components/script/dom/htmlcanvaselement.rs
+++ b/components/script/dom/htmlcanvaselement.rs
@@ -392,7 +392,7 @@ impl HTMLCanvasElementMethods for HTMLCanvasElement {
// FIXME(nox): https://github.com/PistonDevelopers/image-png/issues/86
// FIXME(nox): https://github.com/PistonDevelopers/image-png/issues/87
PNGEncoder::new(&mut png)
- .encode(&file, self.Width(), self.Height(), ColorType::RGBA(8))
+ .encode(&file, self.Width(), self.Height(), ColorType::Rgba8)
.unwrap();
let mut url = "data:image/png;base64,".to_owned();
// FIXME(nox): Should this use base64::URL_SAFE?
diff --git a/components/script/dom/htmlelement.rs b/components/script/dom/htmlelement.rs
index ac0f99416c2..00d7a64ed32 100644
--- a/components/script/dom/htmlelement.rs
+++ b/components/script/dom/htmlelement.rs
@@ -27,6 +27,7 @@ use crate::dom::htmlframesetelement::HTMLFrameSetElement;
use crate::dom::htmlhtmlelement::HTMLHtmlElement;
use crate::dom::htmlinputelement::{HTMLInputElement, InputType};
use crate::dom::htmllabelelement::HTMLLabelElement;
+use crate::dom::htmltextareaelement::HTMLTextAreaElement;
use crate::dom::node::{document_from_node, window_from_node};
use crate::dom::node::{BindContext, Node, NodeFlags, ShadowIncluding};
use crate::dom::text::Text;
@@ -170,6 +171,11 @@ impl HTMLElementMethods for HTMLElement {
// https://html.spec.whatwg.org/multipage/#dom-hidden
make_bool_setter!(SetHidden, "hidden");
+ // https://html.spec.whatwg.org/multipage/#the-dir-attribute
+ make_getter!(Dir, "dir");
+ // https://html.spec.whatwg.org/multipage/#the-dir-attribute
+ make_setter!(SetDir, "dir");
+
// https://html.spec.whatwg.org/multipage/#globaleventhandlers
global_event_handlers!(NoOnload);
@@ -767,6 +773,48 @@ impl HTMLElement {
})
.count() as u32
}
+
+ // https://html.spec.whatwg.org/multipage/#the-directionality.
+ // returns Some if can infer direction by itself or from child nodes
+ // returns None if requires to go up to parent
+ pub fn directionality(&self) -> Option<String> {
+ let element_direction: &str = &self.Dir();
+
+ if element_direction == "ltr" {
+ return Some("ltr".to_owned());
+ }
+
+ if element_direction == "rtl" {
+ return Some("rtl".to_owned());
+ }
+
+ if let Some(input) = self.downcast::<HTMLInputElement>() {
+ if input.input_type() == InputType::Tel {
+ return Some("ltr".to_owned());
+ }
+ }
+
+ if element_direction == "auto" {
+ if let Some(directionality) = self
+ .downcast::<HTMLInputElement>()
+ .and_then(|input| input.auto_directionality())
+ {
+ return Some(directionality);
+ }
+
+ if let Some(area) = self.downcast::<HTMLTextAreaElement>() {
+ return Some(area.auto_directionality());
+ }
+ }
+
+ // TODO(NeverHappened): Implement condition
+ // If the element's dir attribute is in the auto state OR
+ // If the element is a bdi element and the dir attribute is not in a defined state
+ // (i.e. it is not present or has an invalid value)
+ // Requires bdi element implementation (https://html.spec.whatwg.org/multipage/#the-bdi-element)
+
+ None
+ }
}
impl VirtualMethods for HTMLElement {
diff --git a/components/script/dom/htmlformelement.rs b/components/script/dom/htmlformelement.rs
index adbb790a181..30d1857de9d 100644
--- a/components/script/dom/htmlformelement.rs
+++ b/components/script/dom/htmlformelement.rs
@@ -950,7 +950,6 @@ impl HTMLFormElement {
match element {
HTMLElementTypeId::HTMLInputElement => {
let input = child.downcast::<HTMLInputElement>().unwrap();
-
data_set.append(&mut input.form_datums(submitter, encoding));
},
HTMLElementTypeId::HTMLButtonElement => {
@@ -981,10 +980,30 @@ impl HTMLFormElement {
_ => (),
}
}
+
+ // Step: 5.13. Add an entry if element has dirname attribute
+ // An element can only have a dirname attribute if it is a textarea element
+ // or an input element whose type attribute is in either the Text state or the Search state
+ let child_element = child.downcast::<Element>().unwrap();
+ let input_matches =
+ child_element
+ .downcast::<HTMLInputElement>()
+ .map_or(false, |input| {
+ input.input_type() == InputType::Text ||
+ input.input_type() == InputType::Search
+ });
+ let textarea_matches = child_element.is::<HTMLTextAreaElement>();
+ let dirname = child_element.get_string_attribute(&local_name!("dirname"));
+ if (input_matches || textarea_matches) && !dirname.is_empty() {
+ let dir = DOMString::from(child_element.directionality());
+ data_set.push(FormDatum {
+ ty: DOMString::from("string"),
+ name: dirname,
+ value: FormDatumValue::String(dir),
+ });
+ }
}
data_set
- // TODO: Handle `dirnames` (needs directionality support)
- // https://html.spec.whatwg.org/multipage/#the-directionality
}
/// <https://html.spec.whatwg.org/multipage/#constructing-the-form-data-set>
diff --git a/components/script/dom/htmlimageelement.rs b/components/script/dom/htmlimageelement.rs
index a18eedebfb8..95e5c43af66 100644
--- a/components/script/dom/htmlimageelement.rs
+++ b/components/script/dom/htmlimageelement.rs
@@ -167,13 +167,10 @@ impl HTMLImageElement {
// https://html.spec.whatwg.org/multipage/#check-the-usability-of-the-image-argument
pub fn is_usable(&self) -> Fallible<bool> {
// If image has an intrinsic width or intrinsic height (or both) equal to zero, then return bad.
- match &self.current_request.borrow().image {
- Some(image) => {
- if image.width == 0 || image.height == 0 {
- return Ok(false);
- }
- },
- None => return Ok(false),
+ if let Some(image) = &self.current_request.borrow().image {
+ if image.width == 0 || image.height == 0 {
+ return Ok(false);
+ }
}
match self.current_request.borrow().state {
diff --git a/components/script/dom/htmlinputelement.rs b/components/script/dom/htmlinputelement.rs
index 441206c9dad..c27d5b2f9b5 100755
--- a/components/script/dom/htmlinputelement.rs
+++ b/components/script/dom/htmlinputelement.rs
@@ -75,6 +75,7 @@ use std::ptr::NonNull;
use style::attr::AttrValue;
use style::element_state::ElementState;
use style::str::{split_commas, str_join};
+use unicode_bidi::{bidi_class, BidiClass};
const DEFAULT_SUBMIT_VALUE: &'static str = "Submit";
const DEFAULT_RESET_VALUE: &'static str = "Reset";
@@ -327,6 +328,36 @@ impl HTMLInputElement {
)
}
+ pub fn auto_directionality(&self) -> Option<String> {
+ match self.input_type() {
+ InputType::Text | InputType::Search | InputType::Url | InputType::Email => {
+ let value: String = self.Value().to_string();
+ Some(HTMLInputElement::directionality_from_value(&value))
+ },
+ _ => None,
+ }
+ }
+
+ pub fn directionality_from_value(value: &str) -> String {
+ if HTMLInputElement::is_first_strong_character_rtl(value) {
+ "rtl".to_owned()
+ } else {
+ "ltr".to_owned()
+ }
+ }
+
+ fn is_first_strong_character_rtl(value: &str) -> bool {
+ for ch in value.chars() {
+ return match bidi_class(ch) {
+ BidiClass::L => false,
+ BidiClass::AL => true,
+ BidiClass::R => true,
+ _ => continue,
+ };
+ }
+ false
+ }
+
// https://html.spec.whatwg.org/multipage/#dom-input-value
// https://html.spec.whatwg.org/multipage/#concept-input-apply
fn value_mode(&self) -> ValueMode {
@@ -2457,6 +2488,9 @@ impl Activatable for HTMLInputElement {
// https://html.spec.whatwg.org/multipage/#checkbox-state-(type=checkbox):activation-behavior
// https://html.spec.whatwg.org/multipage/#radio-button-state-(type=radio):activation-behavior
// Check if document owner is fully active
+ if !self.upcast::<Node>().is_connected() {
+ return ();
+ }
let target = self.upcast::<EventTarget>();
target.fire_bubbling_event(atom!("input"));
target.fire_bubbling_event(atom!("change"));
diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs
index d9b0f11beef..f8c686d34f2 100644
--- a/components/script/dom/htmlmediaelement.rs
+++ b/components/script/dom/htmlmediaelement.rs
@@ -74,7 +74,7 @@ use html5ever::{LocalName, Prefix};
use http::header::{self, HeaderMap, HeaderValue};
use ipc_channel::ipc;
use ipc_channel::router::ROUTER;
-use media::{glplayer_channel, GLPlayerMsg, GLPlayerMsgForward};
+use media::{glplayer_channel, GLPlayerMsg, GLPlayerMsgForward, WindowGLContext};
use net_traits::image::base::Image;
use net_traits::image_cache::ImageResponse;
use net_traits::request::{Destination, Referrer};
@@ -96,7 +96,8 @@ use std::rc::Rc;
use std::sync::{Arc, Mutex};
use time::{self, Duration, Timespec};
use webrender_api::{ExternalImageData, ExternalImageId, ExternalImageType, TextureTarget};
-use webrender_api::{ImageData, ImageDescriptor, ImageFormat, ImageKey, Transaction};
+use webrender_api::{ImageData, ImageDescriptor, ImageDescriptorFlags, ImageFormat};
+use webrender_api::{ImageKey, Transaction};
#[derive(PartialEq)]
enum FrameStatus {
@@ -186,8 +187,7 @@ impl VideoFrameRenderer for MediaFrameRenderer {
frame.get_width(),
frame.get_height(),
ImageFormat::BGRA8,
- false,
- false,
+ ImageDescriptorFlags::empty(),
);
match self.current_frame {
@@ -373,6 +373,8 @@ pub struct HTMLMediaElement {
/// the access to the "privileged" document.servoGetMediaControls(id) API by
/// keeping a whitelist of media controls identifiers.
media_controls_id: DomRefCell<Option<String>>,
+ #[ignore_malloc_size_of = "Defined in other crates"]
+ player_context: WindowGLContext,
}
/// <https://html.spec.whatwg.org/multipage/#dom-media-networkstate>
@@ -437,6 +439,7 @@ impl HTMLMediaElement {
current_fetch_context: DomRefCell::new(None),
id: Cell::new(0),
media_controls_id: DomRefCell::new(None),
+ player_context: document.window().get_player_context(),
}
}
@@ -1340,9 +1343,7 @@ impl HTMLMediaElement {
let audio_renderer = self.audio_renderer.borrow().as_ref().map(|r| r.clone());
- let pipeline_id = window
- .pipeline_id()
- .expect("Cannot create player outside of a pipeline");
+ let pipeline_id = window.pipeline_id();
let client_context_id =
ClientContextId::build(pipeline_id.namespace_id.0, pipeline_id.index.0.get());
let player = ServoMedia::get().unwrap().create_player(
@@ -1969,15 +1970,14 @@ impl HTMLMediaElement {
impl Drop for HTMLMediaElement {
fn drop(&mut self) {
- let window = window_from_node(self);
- window.get_player_context().glplayer_chan.map(|pipeline| {
+ if let Some(ref pipeline) = self.player_context.glplayer_chan {
if let Err(err) = pipeline
.channel()
.send(GLPlayerMsg::UnregisterPlayer(self.id.get()))
{
warn!("GLPlayer disappeared!: {:?}", err);
}
- });
+ }
self.remove_controls();
}
diff --git a/components/script/dom/htmltextareaelement.rs b/components/script/dom/htmltextareaelement.rs
index 9fd316e3a18..d077d9eec8f 100755
--- a/components/script/dom/htmltextareaelement.rs
+++ b/components/script/dom/htmltextareaelement.rs
@@ -22,6 +22,7 @@ use crate::dom::globalscope::GlobalScope;
use crate::dom::htmlelement::HTMLElement;
use crate::dom::htmlfieldsetelement::HTMLFieldSetElement;
use crate::dom::htmlformelement::{FormControl, HTMLFormElement};
+use crate::dom::htmlinputelement::HTMLInputElement;
use crate::dom::keyboardevent::KeyboardEvent;
use crate::dom::node::{document_from_node, window_from_node};
use crate::dom::node::{
@@ -173,6 +174,11 @@ impl HTMLTextAreaElement {
)
}
+ pub fn auto_directionality(&self) -> String {
+ let value: String = self.Value().to_string();
+ return HTMLInputElement::directionality_from_value(&value);
+ }
+
fn update_placeholder_shown_state(&self) {
let has_placeholder = !self.placeholder.borrow().is_empty();
let has_value = !self.textinput.borrow().is_empty();
@@ -205,6 +211,12 @@ impl HTMLTextAreaElementMethods for HTMLTextAreaElement {
// https://html.spec.whatwg.org/multipage/#dom-textarea-cols
make_limited_uint_setter!(SetCols, "cols", DEFAULT_COLS);
+ // https://html.spec.whatwg.org/multipage/#dom-input-dirName
+ make_getter!(DirName, "dirname");
+
+ // https://html.spec.whatwg.org/multipage/#dom-input-dirName
+ make_setter!(SetDirName, "dirname");
+
// https://html.spec.whatwg.org/multipage/#dom-fe-disabled
make_bool_getter!(Disabled, "disabled");
diff --git a/components/script/dom/mediasession.rs b/components/script/dom/mediasession.rs
index c8df282f364..54a6d2d3660 100644
--- a/components/script/dom/mediasession.rs
+++ b/components/script/dom/mediasession.rs
@@ -105,9 +105,7 @@ impl MediaSession {
pub fn send_event(&self, event: MediaSessionEvent) {
let global = self.global();
let window = global.as_window();
- let pipeline_id = window
- .pipeline_id()
- .expect("Cannot send media session event outside of a pipeline");
+ let pipeline_id = window.pipeline_id();
window.send_to_constellation(ScriptMsg::MediaSessionEvent(pipeline_id, event));
}
diff --git a/components/script/dom/messageport.rs b/components/script/dom/messageport.rs
index 9cbf7152f01..ee2f54323a6 100644
--- a/components/script/dom/messageport.rs
+++ b/components/script/dom/messageport.rs
@@ -338,6 +338,6 @@ impl MessagePortMethods for MessagePort {
self.global().start_message_port(self.message_port_id());
}
- /// <https://html.spec.whatwg.org/multipage/#handler-messageport-onmessageerror>
+ // <https://html.spec.whatwg.org/multipage/#handler-messageport-onmessageerror>
event_handler!(messageerror, GetOnmessageerror, SetOnmessageerror);
}
diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs
index e25a88b9da2..3691ba5a299 100644
--- a/components/script/dom/mod.rs
+++ b/components/script/dom/mod.rs
@@ -239,6 +239,7 @@ pub mod bluetoothremotegattdescriptor;
pub mod bluetoothremotegattserver;
pub mod bluetoothremotegattservice;
pub mod bluetoothuuid;
+pub mod broadcastchannel;
pub mod canvasgradient;
pub mod canvaspattern;
pub mod canvasrenderingcontext2d;
@@ -526,6 +527,7 @@ pub mod userscripts;
pub mod validation;
pub mod validitystate;
pub mod values;
+pub mod vertexarrayobject;
pub mod videotrack;
pub mod videotracklist;
pub mod virtualmethods;
@@ -537,6 +539,8 @@ pub mod vrfieldofview;
pub mod vrframedata;
pub mod vrpose;
pub mod vrstageparameters;
+pub mod vttcue;
+pub mod vttregion;
pub mod webgl_extensions;
pub use self::webgl_extensions::ext::*;
pub mod webgl2renderingcontext;
@@ -557,6 +561,7 @@ pub mod webglsync;
pub mod webgltexture;
pub mod webgltransformfeedback;
pub mod webgluniformlocation;
+pub mod webglvertexarrayobject;
pub mod webglvertexarrayobjectoes;
pub mod websocket;
pub mod wheelevent;
diff --git a/components/script/dom/navigator.rs b/components/script/dom/navigator.rs
index 690eb72abd3..b297b02bc69 100644
--- a/components/script/dom/navigator.rs
+++ b/components/script/dom/navigator.rs
@@ -184,7 +184,8 @@ impl NavigatorMethods for Navigator {
/// https://immersive-web.github.io/webxr/#dom-navigator-xr
fn Xr(&self) -> DomRoot<XRSystem> {
- self.xr.or_init(|| XRSystem::new(&self.global()))
+ self.xr
+ .or_init(|| XRSystem::new(&self.global().as_window()))
}
/// https://w3c.github.io/mediacapture-main/#dom-navigator-mediadevices
diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs
index 457c1f0d55c..05b81a84d5d 100644
--- a/components/script/dom/node.rs
+++ b/components/script/dom/node.rs
@@ -67,6 +67,7 @@ use crate::dom::window::Window;
use crate::script_runtime::JSContext;
use crate::script_thread::ScriptThread;
use app_units::Au;
+use crossbeam_channel::Sender;
use devtools_traits::NodeInfo;
use dom_struct::dom_struct;
use euclid::default::{Point2D, Rect, Size2D, Vector2D};
@@ -209,7 +210,9 @@ impl NodeFlags {
impl Drop for Node {
#[allow(unsafe_code)]
fn drop(&mut self) {
- self.style_and_layout_data.get().map(|d| self.dispose(d));
+ if let Some(data) = self.style_and_layout_data.get() {
+ self.dispose(data, ScriptThread::get_any_layout_chan().as_ref());
+ }
}
}
@@ -224,15 +227,16 @@ enum SuppressObserver {
impl Node {
/// Sends the style and layout data, if any, back to the layout thread to be destroyed.
- pub fn dispose(&self, data: OpaqueStyleAndLayoutData) {
+ pub(crate) fn dispose(
+ &self,
+ data: OpaqueStyleAndLayoutData,
+ layout_chan: Option<&Sender<Msg>>,
+ ) {
debug_assert!(thread_state::get().is_script());
- let win = window_from_node(self);
self.style_and_layout_data.set(None);
- if win
- .layout_chan()
- .send(Msg::ReapStyleAndLayoutData(data))
- .is_err()
- {
+ if layout_chan.map_or(false, |chan| {
+ chan.send(Msg::ReapStyleAndLayoutData(data)).is_err()
+ }) {
warn!("layout thread unreachable - leaking layout data");
}
}
@@ -315,12 +319,16 @@ impl Node {
false,
);
}
+ let window = window_from_node(root);
+ let layout_chan = window.layout_chan();
for node in root.traverse_preorder(ShadowIncluding::Yes) {
// This needs to be in its own loop, because unbind_from_tree may
// rely on the state of IS_IN_DOC of the context node's descendants,
// e.g. when removing a <form>.
vtable_for(&&*node).unbind_from_tree(&context);
- node.style_and_layout_data.get().map(|d| node.dispose(d));
+ if let Some(data) = node.style_and_layout_data.get() {
+ node.dispose(data, Some(layout_chan));
+ }
// https://dom.spec.whatwg.org/#concept-node-remove step 14
if let Some(element) = node.as_custom_element() {
ScriptThread::enqueue_callback_reaction(
@@ -432,6 +440,26 @@ impl Node {
.upcast::<Event>()
.dispatch(self.upcast::<EventTarget>(), false);
}
+
+ pub fn parent_directionality(&self) -> String {
+ let mut current = self.GetParentNode();
+
+ loop {
+ match current {
+ Some(node) => {
+ if let Some(directionality) = node
+ .downcast::<HTMLElement>()
+ .and_then(|html_element| html_element.directionality())
+ {
+ return directionality;
+ } else {
+ current = node.GetParentNode();
+ }
+ },
+ None => return "ltr".to_owned(),
+ }
+ }
+ }
}
pub struct QuerySelectorIterator {
@@ -481,10 +509,12 @@ impl<'a> Iterator for QuerySelectorIterator {
impl Node {
impl_rare_data!(NodeRareData);
- pub fn teardown(&self) {
- self.style_and_layout_data.get().map(|d| self.dispose(d));
+ pub(crate) fn teardown(&self, layout_chan: &Sender<Msg>) {
+ if let Some(data) = self.style_and_layout_data.get() {
+ self.dispose(data, Some(layout_chan));
+ }
for kid in self.children() {
- kid.teardown();
+ kid.teardown(layout_chan);
}
}
diff --git a/components/script/dom/nodelist.rs b/components/script/dom/nodelist.rs
index 8c4f6d39358..5218d1b3026 100644
--- a/components/script/dom/nodelist.rs
+++ b/components/script/dom/nodelist.rs
@@ -7,6 +7,8 @@ use crate::dom::bindings::codegen::Bindings::NodeListBinding;
use crate::dom::bindings::codegen::Bindings::NodeListBinding::NodeListMethods;
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
+use crate::dom::bindings::str::DOMString;
+use crate::dom::document::Document;
use crate::dom::htmlelement::HTMLElement;
use crate::dom::htmlformelement::HTMLFormElement;
use crate::dom::node::{ChildrenMutation, Node};
@@ -22,6 +24,7 @@ pub enum NodeListType {
Children(ChildrenList),
Labels(LabelsList),
Radio(RadioList),
+ ElementsByName(ElementsByNameList),
}
// https://dom.spec.whatwg.org/#interface-nodelist
@@ -74,6 +77,17 @@ impl NodeList {
NodeList::new(window, NodeListType::Labels(LabelsList::new(element)))
}
+ pub fn new_elements_by_name_list(
+ window: &Window,
+ document: &Document,
+ name: DOMString,
+ ) -> DomRoot<NodeList> {
+ NodeList::new(
+ window,
+ NodeListType::ElementsByName(ElementsByNameList::new(document, name)),
+ )
+ }
+
pub fn empty(window: &Window) -> DomRoot<NodeList> {
NodeList::new(window, NodeListType::Simple(vec![]))
}
@@ -87,6 +101,7 @@ impl NodeListMethods for NodeList {
NodeListType::Children(ref list) => list.len(),
NodeListType::Labels(ref list) => list.len(),
NodeListType::Radio(ref list) => list.len(),
+ NodeListType::ElementsByName(ref list) => list.len(),
}
}
@@ -99,6 +114,7 @@ impl NodeListMethods for NodeList {
NodeListType::Children(ref list) => list.item(index),
NodeListType::Labels(ref list) => list.item(index),
NodeListType::Radio(ref list) => list.item(index),
+ NodeListType::ElementsByName(ref list) => list.item(index),
}
}
@@ -401,3 +417,29 @@ impl RadioList {
self.form.nth_for_radio_list(index, self.mode, &self.name)
}
}
+
+#[derive(JSTraceable, MallocSizeOf)]
+#[unrooted_must_root_lint::must_root]
+pub struct ElementsByNameList {
+ document: Dom<Document>,
+ name: DOMString,
+}
+
+impl ElementsByNameList {
+ pub fn new(document: &Document, name: DOMString) -> ElementsByNameList {
+ ElementsByNameList {
+ document: Dom::from_ref(document),
+ name: name,
+ }
+ }
+
+ pub fn len(&self) -> u32 {
+ self.document.elements_by_name_count(&self.name)
+ }
+
+ pub fn item(&self, index: u32) -> Option<DomRoot<Node>> {
+ self.document
+ .nth_element_by_name(index, &self.name)
+ .and_then(|n| Some(DomRoot::from_ref(&*n)))
+ }
+}
diff --git a/components/script/dom/offlineaudiocontext.rs b/components/script/dom/offlineaudiocontext.rs
index a524595d6ea..7b8d3f52111 100644
--- a/components/script/dom/offlineaudiocontext.rs
+++ b/components/script/dom/offlineaudiocontext.rs
@@ -83,9 +83,7 @@ impl OfflineAudioContext {
{
return Err(Error::NotSupported);
}
- let pipeline_id = window
- .pipeline_id()
- .expect("Cannot create audio context outside of a pipeline");
+ let pipeline_id = window.pipeline_id();
let context =
OfflineAudioContext::new_inherited(channel_count, length, sample_rate, pipeline_id);
Ok(reflect_dom_object(
diff --git a/components/script/dom/permissions.rs b/components/script/dom/permissions.rs
index cb91fb692f9..37887f60773 100644
--- a/components/script/dom/permissions.rs
+++ b/components/script/dom/permissions.rs
@@ -19,19 +19,13 @@ use crate::dom::promise::Promise;
use crate::realms::{AlreadyInRealm, InRealm};
use crate::script_runtime::JSContext;
use dom_struct::dom_struct;
+use embedder_traits::{self, EmbedderMsg, PermissionPrompt, PermissionRequest};
+use ipc_channel::ipc;
use js::conversions::ConversionResult;
use js::jsapi::JSObject;
use js::jsval::{ObjectValue, UndefinedValue};
use servo_config::pref;
use std::rc::Rc;
-#[cfg(target_os = "linux")]
-use tinyfiledialogs::{self, MessageBoxIcon, YesNo};
-
-#[cfg(target_os = "linux")]
-const DIALOG_TITLE: &'static str = "Permission request dialog";
-const NONSECURE_DIALOG_MESSAGE: &'static str = "feature is only safe to use in secure context,\
- but servo can't guarantee\n that the current context is secure. Do you want to proceed and grant permission?";
-const REQUEST_DIALOG_MESSAGE: &'static str = "Do you want to grant permission for";
pub trait PermissionAlgorithm {
type Descriptor;
@@ -143,7 +137,6 @@ impl Permissions {
// (Revoke) Step 3.
let globalscope = self.global();
globalscope
- .as_window()
.permission_state_invocation_results()
.borrow_mut()
.remove(&root_desc.name.to_string());
@@ -176,7 +169,6 @@ impl Permissions {
// (Revoke) Step 3.
let globalscope = self.global();
globalscope
- .as_window()
.permission_state_invocation_results()
.borrow_mut()
.remove(&root_desc.name.to_string());
@@ -259,17 +251,13 @@ impl PermissionAlgorithm for Permissions {
// Step 3.
PermissionState::Prompt => {
let perm_name = status.get_query();
-
- let globalscope = GlobalScope::current().expect("No current global object");
+ let prompt =
+ PermissionPrompt::Request(embedder_traits::PermissionName::from(perm_name));
// https://w3c.github.io/permissions/#request-permission-to-use (Step 3 - 4)
- let state = prompt_user(
- &format!("{} {} ?", REQUEST_DIALOG_MESSAGE, perm_name.clone()),
- globalscope.is_headless(),
- );
-
+ let globalscope = GlobalScope::current().expect("No current global object");
+ let state = prompt_user_from_embedder(prompt, &globalscope);
globalscope
- .as_window()
.permission_state_invocation_results()
.borrow_mut()
.insert(perm_name.to_string(), state);
@@ -292,7 +280,7 @@ pub fn get_descriptor_permission_state(
env_settings_obj: Option<&GlobalScope>,
) -> PermissionState {
// Step 1.
- let settings = match env_settings_obj {
+ let globalscope = match env_settings_obj {
Some(env_settings_obj) => DomRoot::from_ref(env_settings_obj),
None => GlobalScope::current().expect("No current global object"),
};
@@ -308,22 +296,20 @@ pub fn get_descriptor_permission_state(
if pref!(dom.permissions.testing.allowed_in_nonsecure_contexts) {
PermissionState::Granted
} else {
- settings
- .as_window()
+ globalscope
.permission_state_invocation_results()
.borrow_mut()
.remove(&permission_name.to_string());
- prompt_user(
- &format!("The {} {}", permission_name, NONSECURE_DIALOG_MESSAGE),
- settings.is_headless(),
+ prompt_user_from_embedder(
+ PermissionPrompt::Insecure(embedder_traits::PermissionName::from(permission_name)),
+ &globalscope,
)
}
};
// Step 3.
- if let Some(prev_result) = settings
- .as_window()
+ if let Some(prev_result) = globalscope
.permission_state_invocation_results()
.borrow()
.get(&permission_name.to_string())
@@ -332,8 +318,7 @@ pub fn get_descriptor_permission_state(
}
// Store the invocation result
- settings
- .as_window()
+ globalscope
.permission_state_invocation_results()
.borrow_mut()
.insert(permission_name.to_string(), state);
@@ -342,28 +327,6 @@ pub fn get_descriptor_permission_state(
state
}
-#[cfg(target_os = "linux")]
-fn prompt_user(message: &str, headless: bool) -> PermissionState {
- if headless {
- return PermissionState::Denied;
- }
- match tinyfiledialogs::message_box_yes_no(
- DIALOG_TITLE,
- message,
- MessageBoxIcon::Question,
- YesNo::No,
- ) {
- YesNo::Yes => PermissionState::Granted,
- YesNo::No => PermissionState::Denied,
- }
-}
-
-#[cfg(not(target_os = "linux"))]
-fn prompt_user(_message: &str, _headless: bool) -> PermissionState {
- // TODO popup only supported on linux
- PermissionState::Denied
-}
-
// https://w3c.github.io/permissions/#allowed-in-non-secure-contexts
fn allowed_in_nonsecure_contexts(permission_name: &PermissionName) -> bool {
match *permission_name {
@@ -391,3 +354,40 @@ fn allowed_in_nonsecure_contexts(permission_name: &PermissionName) -> bool {
PermissionName::Persistent_storage => false,
}
}
+
+fn prompt_user_from_embedder(prompt: PermissionPrompt, gs: &GlobalScope) -> PermissionState {
+ let (sender, receiver) = ipc::channel().expect("Failed to create IPC channel!");
+ gs.send_to_embedder(EmbedderMsg::PromptPermission(prompt, sender));
+
+ match receiver.recv() {
+ Ok(PermissionRequest::Granted) => PermissionState::Granted,
+ Ok(PermissionRequest::Denied) => PermissionState::Denied,
+ Err(e) => {
+ warn!(
+ "Failed to receive permission state from embedder ({:?}).",
+ e
+ );
+ PermissionState::Denied
+ },
+ }
+}
+
+impl From<PermissionName> for embedder_traits::PermissionName {
+ fn from(permission_name: PermissionName) -> Self {
+ match permission_name {
+ PermissionName::Geolocation => embedder_traits::PermissionName::Geolocation,
+ PermissionName::Notifications => embedder_traits::PermissionName::Notifications,
+ PermissionName::Push => embedder_traits::PermissionName::Push,
+ PermissionName::Midi => embedder_traits::PermissionName::Midi,
+ PermissionName::Camera => embedder_traits::PermissionName::Camera,
+ PermissionName::Microphone => embedder_traits::PermissionName::Microphone,
+ PermissionName::Speaker => embedder_traits::PermissionName::Speaker,
+ PermissionName::Device_info => embedder_traits::PermissionName::DeviceInfo,
+ PermissionName::Background_sync => embedder_traits::PermissionName::BackgroundSync,
+ PermissionName::Bluetooth => embedder_traits::PermissionName::Bluetooth,
+ PermissionName::Persistent_storage => {
+ embedder_traits::PermissionName::PersistentStorage
+ },
+ }
+ }
+}
diff --git a/components/script/dom/promise.rs b/components/script/dom/promise.rs
index f3671a5057f..5e60507f8fc 100644
--- a/components/script/dom/promise.rs
+++ b/components/script/dom/promise.rs
@@ -91,7 +91,7 @@ impl Promise {
pub fn new_in_current_realm(global: &GlobalScope, _comp: InRealm) -> Rc<Promise> {
let cx = global.get_cx();
rooted!(in(*cx) let mut obj = ptr::null_mut::<JSObject>());
- Promise::create_js_promise(cx, HandleObject::null(), obj.handle_mut());
+ Promise::create_js_promise(cx, obj.handle_mut());
Promise::new_with_js_promise(obj.handle(), cx)
}
@@ -109,15 +109,15 @@ impl Promise {
reflector: Reflector::new(),
permanent_js_root: Heap::default(),
};
- let mut promise = Rc::new(promise);
- Rc::get_mut(&mut promise).unwrap().init_reflector(obj.get());
+ let promise = Rc::new(promise);
+ promise.init_reflector(obj.get());
promise.initialize(cx);
promise
}
}
#[allow(unsafe_code)]
- fn create_js_promise(cx: SafeJSContext, proto: HandleObject, mut obj: MutableHandleObject) {
+ fn create_js_promise(cx: SafeJSContext, mut obj: MutableHandleObject) {
unsafe {
let do_nothing_func = JS_NewFunction(
*cx,
@@ -129,7 +129,7 @@ impl Promise {
assert!(!do_nothing_func.is_null());
rooted!(in(*cx) let do_nothing_obj = JS_GetFunctionObject(do_nothing_func));
assert!(!do_nothing_obj.is_null());
- obj.set(NewPromiseObject(*cx, do_nothing_obj.handle(), proto));
+ obj.set(NewPromiseObject(*cx, do_nothing_obj.handle()));
assert!(!obj.is_null());
}
}
diff --git a/components/script/dom/rtcpeerconnection.rs b/components/script/dom/rtcpeerconnection.rs
index ae246cae5b4..e6b45d93676 100644
--- a/components/script/dom/rtcpeerconnection.rs
+++ b/components/script/dom/rtcpeerconnection.rs
@@ -55,8 +55,8 @@ pub struct RTCPeerConnection {
#[ignore_malloc_size_of = "defined in servo-media"]
controller: DomRefCell<Option<WebRtcController>>,
closed: Cell<bool>,
- /// Helps track state changes between the time createOffer/createAnswer
- /// is called and resolved
+ // Helps track state changes between the time createOffer/createAnswer
+ // is called and resolved
offer_answer_generation: Cell<u32>,
#[ignore_malloc_size_of = "promises are hard"]
offer_promises: DomRefCell<Vec<Rc<Promise>>>,
@@ -419,34 +419,34 @@ impl RTCPeerConnection {
}
impl RTCPeerConnectionMethods for RTCPeerConnection {
- /// https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-icecandidate
+ // https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-icecandidate
event_handler!(icecandidate, GetOnicecandidate, SetOnicecandidate);
- /// https://www.w3.org/TR/webrtc/#dom-rtcpeerconnection-ontrack
+ // https://www.w3.org/TR/webrtc/#dom-rtcpeerconnection-ontrack
event_handler!(track, GetOntrack, SetOntrack);
- /// https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-iceconnectionstatechange
+ // https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-iceconnectionstatechange
event_handler!(
iceconnectionstatechange,
GetOniceconnectionstatechange,
SetOniceconnectionstatechange
);
- /// https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-icegatheringstatechange
+ // https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-icegatheringstatechange
event_handler!(
icegatheringstatechange,
GetOnicegatheringstatechange,
SetOnicegatheringstatechange
);
- /// https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-onnegotiationneeded
+ // https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-onnegotiationneeded
event_handler!(
negotiationneeded,
GetOnnegotiationneeded,
SetOnnegotiationneeded
);
- /// https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-signalingstatechange
+ // https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-signalingstatechange
event_handler!(
signalingstatechange,
GetOnsignalingstatechange,
diff --git a/components/script/dom/texttrackcue.rs b/components/script/dom/texttrackcue.rs
index ce55cdf3259..61a07d2cb3c 100644
--- a/components/script/dom/texttrackcue.rs
+++ b/components/script/dom/texttrackcue.rs
@@ -25,24 +25,32 @@ pub struct TextTrackCue {
}
impl TextTrackCue {
- // FIXME(#22314, dlrobertson) implement VTTCue.
- #[allow(dead_code)]
- pub fn new_inherited(id: DOMString, track: Option<&TextTrack>) -> TextTrackCue {
+ pub fn new_inherited(
+ id: DOMString,
+ start_time: f64,
+ end_time: f64,
+ track: Option<&TextTrack>,
+ ) -> TextTrackCue {
TextTrackCue {
eventtarget: EventTarget::new_inherited(),
id: DomRefCell::new(id),
track: track.map(Dom::from_ref),
- start_time: Cell::new(0.),
- end_time: Cell::new(0.),
+ start_time: Cell::new(start_time),
+ end_time: Cell::new(end_time),
pause_on_exit: Cell::new(false),
}
}
- // FIXME(#22314, dlrobertson) implement VTTCue.
#[allow(dead_code)]
- pub fn new(window: &Window, id: DOMString, track: Option<&TextTrack>) -> DomRoot<TextTrackCue> {
+ pub fn new(
+ window: &Window,
+ id: DOMString,
+ start_time: f64,
+ end_time: f64,
+ track: Option<&TextTrack>,
+ ) -> DomRoot<TextTrackCue> {
reflect_dom_object(
- Box::new(TextTrackCue::new_inherited(id, track)),
+ Box::new(TextTrackCue::new_inherited(id, start_time, end_time, track)),
window,
TextTrackCueBinding::Wrap,
)
diff --git a/components/script/dom/vertexarrayobject.rs b/components/script/dom/vertexarrayobject.rs
new file mode 100644
index 00000000000..025cff9194a
--- /dev/null
+++ b/components/script/dom/vertexarrayobject.rs
@@ -0,0 +1,296 @@
+/* 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::{ref_filter_map, DomRefCell, Ref};
+use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants;
+use crate::dom::bindings::root::{Dom, MutNullableDom};
+use crate::dom::webglbuffer::WebGLBuffer;
+use crate::dom::webglrenderingcontext::WebGLRenderingContext;
+use canvas_traits::webgl::{
+ ActiveAttribInfo, WebGLCommand, WebGLError, WebGLResult, WebGLVertexArrayId,
+};
+use std::cell::Cell;
+
+#[derive(JSTraceable, MallocSizeOf)]
+#[unrooted_must_root_lint::must_root]
+pub struct VertexArrayObject {
+ context: Dom<WebGLRenderingContext>,
+ id: Option<WebGLVertexArrayId>,
+ ever_bound: Cell<bool>,
+ is_deleted: Cell<bool>,
+ vertex_attribs: DomRefCell<Box<[VertexAttribData]>>,
+ element_array_buffer: MutNullableDom<WebGLBuffer>,
+}
+
+impl VertexArrayObject {
+ pub fn new(context: &WebGLRenderingContext, id: Option<WebGLVertexArrayId>) -> Self {
+ let max_vertex_attribs = context.limits().max_vertex_attribs as usize;
+ Self {
+ context: Dom::from_ref(context),
+ id,
+ ever_bound: Default::default(),
+ is_deleted: Default::default(),
+ vertex_attribs: DomRefCell::new(vec![Default::default(); max_vertex_attribs].into()),
+ element_array_buffer: Default::default(),
+ }
+ }
+
+ pub fn id(&self) -> Option<WebGLVertexArrayId> {
+ self.id
+ }
+
+ pub fn is_deleted(&self) -> bool {
+ self.is_deleted.get()
+ }
+
+ pub fn delete(&self, fallible: bool) {
+ assert!(self.id.is_some());
+ if self.is_deleted.get() {
+ return;
+ }
+ self.is_deleted.set(true);
+ let cmd = WebGLCommand::DeleteVertexArray(self.id.unwrap());
+ if fallible {
+ self.context.send_command_ignored(cmd);
+ } else {
+ self.context.send_command(cmd);
+ }
+
+ for attrib_data in &**self.vertex_attribs.borrow() {
+ if let Some(buffer) = attrib_data.buffer() {
+ buffer.decrement_attached_counter();
+ }
+ }
+ if let Some(buffer) = self.element_array_buffer.get() {
+ buffer.decrement_attached_counter();
+ }
+ }
+
+ pub fn ever_bound(&self) -> bool {
+ return self.ever_bound.get();
+ }
+
+ pub fn set_ever_bound(&self) {
+ self.ever_bound.set(true);
+ }
+
+ pub fn element_array_buffer(&self) -> &MutNullableDom<WebGLBuffer> {
+ &self.element_array_buffer
+ }
+
+ pub fn get_vertex_attrib(&self, index: u32) -> Option<Ref<VertexAttribData>> {
+ ref_filter_map(self.vertex_attribs.borrow(), |attribs| {
+ attribs.get(index as usize)
+ })
+ }
+
+ pub fn vertex_attrib_pointer(
+ &self,
+ index: u32,
+ size: i32,
+ type_: u32,
+ normalized: bool,
+ stride: i32,
+ offset: i64,
+ ) -> WebGLResult<()> {
+ let mut attribs = self.vertex_attribs.borrow_mut();
+ let data = attribs
+ .get_mut(index as usize)
+ .ok_or(WebGLError::InvalidValue)?;
+
+ if size < 1 || size > 4 {
+ return Err(WebGLError::InvalidValue);
+ }
+
+ // https://www.khronos.org/registry/webgl/specs/latest/1.0/#BUFFER_OFFSET_AND_STRIDE
+ // https://www.khronos.org/registry/webgl/specs/latest/1.0/#VERTEX_STRIDE
+ if stride < 0 || stride > 255 || offset < 0 {
+ return Err(WebGLError::InvalidValue);
+ }
+ let bytes_per_component: i32 = match type_ {
+ constants::BYTE | constants::UNSIGNED_BYTE => 1,
+ constants::SHORT | constants::UNSIGNED_SHORT => 2,
+ constants::FLOAT => 4,
+ _ => return Err(WebGLError::InvalidEnum),
+ };
+ if offset % bytes_per_component as i64 > 0 || stride % bytes_per_component > 0 {
+ return Err(WebGLError::InvalidOperation);
+ }
+
+ let buffer = self.context.array_buffer();
+ match buffer {
+ Some(ref buffer) => buffer.increment_attached_counter(),
+ None if offset != 0 => {
+ // https://github.com/KhronosGroup/WebGL/pull/2228
+ return Err(WebGLError::InvalidOperation);
+ },
+ _ => {},
+ }
+ self.context.send_command(WebGLCommand::VertexAttribPointer(
+ index,
+ size,
+ type_,
+ normalized,
+ stride,
+ offset as u32,
+ ));
+ if let Some(old) = data.buffer() {
+ old.decrement_attached_counter();
+ }
+
+ *data = VertexAttribData {
+ enabled_as_array: data.enabled_as_array,
+ size: size as u8,
+ type_,
+ bytes_per_vertex: size as u8 * bytes_per_component as u8,
+ normalized,
+ stride: stride as u8,
+ offset: offset as u32,
+ buffer: buffer.map(|b| Dom::from_ref(&*b)),
+ divisor: data.divisor,
+ };
+
+ Ok(())
+ }
+
+ pub fn vertex_attrib_divisor(&self, index: u32, value: u32) {
+ self.vertex_attribs.borrow_mut()[index as usize].divisor = value;
+ }
+
+ pub fn enabled_vertex_attrib_array(&self, index: u32, value: bool) {
+ self.vertex_attribs.borrow_mut()[index as usize].enabled_as_array = value;
+ }
+
+ pub fn unbind_buffer(&self, buffer: &WebGLBuffer) {
+ for attrib in &mut **self.vertex_attribs.borrow_mut() {
+ if let Some(b) = attrib.buffer() {
+ if b.id() != buffer.id() {
+ continue;
+ }
+ b.decrement_attached_counter();
+ }
+ attrib.buffer = None;
+ }
+ if self
+ .element_array_buffer
+ .get()
+ .map_or(false, |b| buffer == &*b)
+ {
+ buffer.decrement_attached_counter();
+ self.element_array_buffer.set(None);
+ }
+ }
+
+ pub fn validate_for_draw(
+ &self,
+ required_len: u32,
+ instance_count: u32,
+ active_attribs: &[ActiveAttribInfo],
+ ) -> WebGLResult<()> {
+ // TODO(nox): Cache limits per VAO.
+ let attribs = self.vertex_attribs.borrow();
+ // https://www.khronos.org/registry/webgl/specs/latest/1.0/#6.2
+ if attribs
+ .iter()
+ .any(|data| data.enabled_as_array && data.buffer.is_none())
+ {
+ return Err(WebGLError::InvalidOperation);
+ }
+ let mut has_active_attrib = false;
+ let mut has_divisor_0 = false;
+ for active_info in active_attribs {
+ if active_info.location < 0 {
+ continue;
+ }
+ has_active_attrib = true;
+ let attrib = &attribs[active_info.location as usize];
+ if attrib.divisor == 0 {
+ has_divisor_0 = true;
+ }
+ if !attrib.enabled_as_array {
+ continue;
+ }
+ // https://www.khronos.org/registry/webgl/specs/latest/1.0/#6.6
+ if required_len > 0 && instance_count > 0 {
+ let max_vertices = attrib.max_vertices();
+ if attrib.divisor == 0 {
+ if max_vertices < required_len {
+ return Err(WebGLError::InvalidOperation);
+ }
+ } else if max_vertices
+ .checked_mul(attrib.divisor)
+ .map_or(false, |v| v < instance_count)
+ {
+ return Err(WebGLError::InvalidOperation);
+ }
+ }
+ }
+ if has_active_attrib && !has_divisor_0 {
+ return Err(WebGLError::InvalidOperation);
+ }
+ Ok(())
+ }
+}
+
+impl Drop for VertexArrayObject {
+ fn drop(&mut self) {
+ if self.id.is_some() {
+ self.delete(true);
+ }
+ }
+}
+
+#[derive(Clone, JSTraceable, MallocSizeOf)]
+#[unrooted_must_root_lint::must_root]
+pub struct VertexAttribData {
+ pub enabled_as_array: bool,
+ pub size: u8,
+ pub type_: u32,
+ bytes_per_vertex: u8,
+ pub normalized: bool,
+ pub stride: u8,
+ pub offset: u32,
+ pub buffer: Option<Dom<WebGLBuffer>>,
+ pub divisor: u32,
+}
+
+impl Default for VertexAttribData {
+ #[allow(unrooted_must_root)]
+ fn default() -> Self {
+ Self {
+ enabled_as_array: false,
+ size: 4,
+ type_: constants::FLOAT,
+ bytes_per_vertex: 16,
+ normalized: false,
+ stride: 0,
+ offset: 0,
+ buffer: None,
+ divisor: 0,
+ }
+ }
+}
+
+impl VertexAttribData {
+ pub fn buffer(&self) -> Option<&WebGLBuffer> {
+ self.buffer.as_ref().map(|b| &**b)
+ }
+
+ pub fn max_vertices(&self) -> u32 {
+ let capacity = (self.buffer().unwrap().capacity() as u32).saturating_sub(self.offset);
+ if capacity < self.bytes_per_vertex as u32 {
+ 0
+ } else if self.stride == 0 {
+ capacity / self.bytes_per_vertex as u32
+ } else if self.stride < self.bytes_per_vertex {
+ (capacity - (self.bytes_per_vertex - self.stride) as u32) / self.stride as u32
+ } else {
+ let mut max = capacity / self.stride as u32;
+ if capacity % self.stride as u32 >= self.bytes_per_vertex as u32 {
+ max += 1;
+ }
+ max
+ }
+ }
+}
diff --git a/components/script/dom/vrdisplay.rs b/components/script/dom/vrdisplay.rs
index f595952b07a..4b3f7426dda 100644
--- a/components/script/dom/vrdisplay.rs
+++ b/components/script/dom/vrdisplay.rs
@@ -23,7 +23,6 @@ use crate::dom::bindings::root::{DomRoot, MutDom, MutNullableDom};
use crate::dom::bindings::str::DOMString;
use crate::dom::event::Event;
use crate::dom::eventtarget::EventTarget;
-use crate::dom::globalscope::GlobalScope;
use crate::dom::promise::Promise;
use crate::dom::vrdisplaycapabilities::VRDisplayCapabilities;
use crate::dom::vrdisplayevent::VRDisplayEvent;
@@ -32,6 +31,7 @@ use crate::dom::vrframedata::VRFrameData;
use crate::dom::vrpose::VRPose;
use crate::dom::vrstageparameters::VRStageParameters;
use crate::dom::webglrenderingcontext::{WebGLMessageSender, WebGLRenderingContext};
+use crate::dom::window::Window;
use crate::realms::InRealm;
use crate::script_runtime::CommonScriptMsg;
use crate::script_runtime::ScriptThreadEventCategory::WebVREvent;
@@ -40,6 +40,7 @@ use canvas_traits::webgl::{webgl_channel, WebGLReceiver, WebVRCommand};
use crossbeam_channel::{unbounded, Sender};
use dom_struct::dom_struct;
use ipc_channel::ipc::IpcSender;
+use msg::constellation_msg::PipelineId;
use profile_traits::ipc;
use std::cell::Cell;
use std::mem;
@@ -82,6 +83,9 @@ pub struct VRDisplay {
running_display_raf: Cell<bool>,
paused: Cell<bool>,
stopped_on_pause: Cell<bool>,
+ #[ignore_malloc_size_of = "channels are hard"]
+ webvr_thread: IpcSender<WebVRMsg>,
+ pipeline: PipelineId,
}
unsafe_no_jsmanaged_fields!(WebVRDisplayData);
@@ -110,7 +114,7 @@ struct VRRAFUpdate {
type VRRAFUpdateSender = Sender<Result<VRRAFUpdate, ()>>;
impl VRDisplay {
- fn new_inherited(global: &GlobalScope, display: WebVRDisplayData) -> VRDisplay {
+ fn new_inherited(global: &Window, display: WebVRDisplayData) -> VRDisplay {
let stage = match display.stage_parameters {
Some(ref params) => Some(VRStageParameters::new(params.clone(), &global)),
None => None,
@@ -152,10 +156,12 @@ impl VRDisplay {
// This flag is set when the Display was presenting when it received a VR Pause event.
// When the VR Resume event is received and the flag is set, VR presentation automatically restarts.
stopped_on_pause: Cell::new(false),
+ webvr_thread: global.webvr_thread().expect("webvr is disabled"),
+ pipeline: global.pipeline_id(),
}
}
- pub fn new(global: &GlobalScope, display: WebVRDisplayData) -> DomRoot<VRDisplay> {
+ pub fn new(global: &Window, display: WebVRDisplayData) -> DomRoot<VRDisplay> {
reflect_dom_object(
Box::new(VRDisplay::new_inherited(&global, display)),
global,
@@ -229,7 +235,7 @@ impl VRDisplayMethods for VRDisplay {
// If not presenting we fetch inmediante VRFrameData
let (sender, receiver) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
- self.webvr_thread()
+ self.webvr_thread
.send(WebVRMsg::GetFrameData(
self.global().pipeline_id(),
self.DisplayId(),
@@ -258,7 +264,7 @@ impl VRDisplayMethods for VRDisplay {
// https://w3c.github.io/webvr/#dom-vrdisplay-resetpose
fn ResetPose(&self) {
let (sender, receiver) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
- self.webvr_thread()
+ self.webvr_thread
.send(WebVRMsg::ResetPose(
self.global().pipeline_id(),
self.DisplayId(),
@@ -398,7 +404,7 @@ impl VRDisplayMethods for VRDisplay {
// Exit present
let (sender, receiver) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
- self.webvr_thread()
+ self.webvr_thread
.send(WebVRMsg::ExitPresent(
self.global().pipeline_id(),
self.display.borrow().display_id,
@@ -452,18 +458,14 @@ impl VRDisplayMethods for VRDisplay {
}
impl VRDisplay {
- fn webvr_thread(&self) -> IpcSender<WebVRMsg> {
- self.global()
- .as_window()
- .webvr_thread()
- .expect("Shouldn't arrive here with WebVR disabled")
- }
-
pub fn update_display(&self, display: &WebVRDisplayData) {
*self.display.borrow_mut() = display.clone();
if let Some(ref stage) = display.stage_parameters {
if self.stage_params.get().is_none() {
- let params = Some(VRStageParameters::new(stage.clone(), &self.global()));
+ let params = Some(VRStageParameters::new(
+ stage.clone(),
+ &self.global().as_window(),
+ ));
self.stage_params.set(params.as_deref());
} else {
self.stage_params.get().unwrap().update(&stage);
@@ -484,7 +486,7 @@ impl VRDisplay {
{
// Request Present
let (sender, receiver) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
- self.webvr_thread()
+ self.webvr_thread
.send(WebVRMsg::RequestPresent(
self.global().pipeline_id(),
self.display.borrow().display_id,
@@ -730,7 +732,7 @@ impl VRDisplay {
// Only called when the JSContext is destroyed while presenting.
// In this case we don't want to wait for WebVR Thread response.
fn force_stop_present(&self) {
- self.webvr_thread()
+ self.webvr_thread
.send(WebVRMsg::ExitPresent(
self.global().pipeline_id(),
self.display.borrow().display_id,
diff --git a/components/script/dom/vrdisplaycapabilities.rs b/components/script/dom/vrdisplaycapabilities.rs
index 858c40978a7..214ee617e1c 100644
--- a/components/script/dom/vrdisplaycapabilities.rs
+++ b/components/script/dom/vrdisplaycapabilities.rs
@@ -7,7 +7,7 @@ use crate::dom::bindings::codegen::Bindings::VRDisplayCapabilitiesBinding;
use crate::dom::bindings::codegen::Bindings::VRDisplayCapabilitiesBinding::VRDisplayCapabilitiesMethods;
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
use crate::dom::bindings::root::DomRoot;
-use crate::dom::globalscope::GlobalScope;
+use crate::dom::window::Window;
use dom_struct::dom_struct;
use webvr_traits::WebVRDisplayCapabilities;
@@ -30,7 +30,7 @@ impl VRDisplayCapabilities {
pub fn new(
capabilities: WebVRDisplayCapabilities,
- global: &GlobalScope,
+ global: &Window,
) -> DomRoot<VRDisplayCapabilities> {
reflect_dom_object(
Box::new(VRDisplayCapabilities::new_inherited(capabilities)),
diff --git a/components/script/dom/vreyeparameters.rs b/components/script/dom/vreyeparameters.rs
index a7463c34a28..c908b23540d 100644
--- a/components/script/dom/vreyeparameters.rs
+++ b/components/script/dom/vreyeparameters.rs
@@ -7,8 +7,8 @@ use crate::dom::bindings::codegen::Bindings::VREyeParametersBinding;
use crate::dom::bindings::codegen::Bindings::VREyeParametersBinding::VREyeParametersMethods;
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
use crate::dom::bindings::root::{Dom, DomRoot};
-use crate::dom::globalscope::GlobalScope;
use crate::dom::vrfieldofview::VRFieldOfView;
+use crate::dom::window::Window;
use crate::script_runtime::JSContext;
use dom_struct::dom_struct;
use js::jsapi::{Heap, JSObject};
@@ -41,7 +41,7 @@ impl VREyeParameters {
}
#[allow(unsafe_code)]
- pub fn new(parameters: WebVREyeParameters, global: &GlobalScope) -> DomRoot<VREyeParameters> {
+ pub fn new(parameters: WebVREyeParameters, global: &Window) -> DomRoot<VREyeParameters> {
let fov = VRFieldOfView::new(&global, parameters.field_of_view.clone());
let cx = global.get_cx();
diff --git a/components/script/dom/vrfieldofview.rs b/components/script/dom/vrfieldofview.rs
index 25a01daaf16..8009f6a2461 100644
--- a/components/script/dom/vrfieldofview.rs
+++ b/components/script/dom/vrfieldofview.rs
@@ -8,7 +8,7 @@ use crate::dom::bindings::codegen::Bindings::VRFieldOfViewBinding::VRFieldOfView
use crate::dom::bindings::num::Finite;
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
use crate::dom::bindings::root::DomRoot;
-use crate::dom::globalscope::GlobalScope;
+use crate::dom::window::Window;
use dom_struct::dom_struct;
use webvr_traits::WebVRFieldOfView;
@@ -29,7 +29,7 @@ impl VRFieldOfView {
}
}
- pub fn new(global: &GlobalScope, fov: WebVRFieldOfView) -> DomRoot<VRFieldOfView> {
+ pub fn new(global: &Window, fov: WebVRFieldOfView) -> DomRoot<VRFieldOfView> {
reflect_dom_object(
Box::new(VRFieldOfView::new_inherited(fov)),
global,
diff --git a/components/script/dom/vrstageparameters.rs b/components/script/dom/vrstageparameters.rs
index 747608763e9..e9df89364c4 100644
--- a/components/script/dom/vrstageparameters.rs
+++ b/components/script/dom/vrstageparameters.rs
@@ -8,7 +8,7 @@ use crate::dom::bindings::codegen::Bindings::VRStageParametersBinding::VRStagePa
use crate::dom::bindings::num::Finite;
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
use crate::dom::bindings::root::DomRoot;
-use crate::dom::globalscope::GlobalScope;
+use crate::dom::window::Window;
use crate::script_runtime::JSContext;
use dom_struct::dom_struct;
use js::jsapi::{Heap, JSObject};
@@ -38,10 +38,7 @@ impl VRStageParameters {
}
#[allow(unsafe_code)]
- pub fn new(
- parameters: WebVRStageParameters,
- global: &GlobalScope,
- ) -> DomRoot<VRStageParameters> {
+ pub fn new(parameters: WebVRStageParameters, global: &Window) -> DomRoot<VRStageParameters> {
let cx = global.get_cx();
rooted!(in (*cx) let mut array = ptr::null_mut::<JSObject>());
unsafe {
diff --git a/components/script/dom/vttcue.rs b/components/script/dom/vttcue.rs
new file mode 100644
index 00000000000..82ffb36c473
--- /dev/null
+++ b/components/script/dom/vttcue.rs
@@ -0,0 +1,232 @@
+/* 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::VTTCueBinding::{
+ self, AlignSetting, AutoKeyword, DirectionSetting, LineAlignSetting, PositionAlignSetting,
+ VTTCueMethods,
+};
+use crate::dom::bindings::error::{Error, ErrorResult};
+use crate::dom::bindings::num::Finite;
+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::documentfragment::DocumentFragment;
+use crate::dom::globalscope::GlobalScope;
+use crate::dom::texttrackcue::TextTrackCue;
+use crate::dom::vttregion::VTTRegion;
+use crate::dom::window::Window;
+use dom_struct::dom_struct;
+use std::cell::Cell;
+
+#[dom_struct]
+pub struct VTTCue {
+ texttrackcue: TextTrackCue,
+ region: DomRefCell<Option<Dom<VTTRegion>>>,
+ vertical: Cell<DirectionSetting>,
+ snap_to_lines: Cell<bool>,
+ line: DomRefCell<LineAndPositionSetting>,
+ line_align: Cell<LineAlignSetting>,
+ position: DomRefCell<LineAndPositionSetting>,
+ position_align: Cell<PositionAlignSetting>,
+ size: Cell<f64>,
+ align: Cell<AlignSetting>,
+ text: DomRefCell<DOMString>,
+}
+
+impl VTTCue {
+ pub fn new_inherited(start_time: f64, end_time: f64, text: DOMString) -> Self {
+ VTTCue {
+ texttrackcue: TextTrackCue::new_inherited(
+ DOMString::default(),
+ start_time,
+ end_time,
+ None,
+ ),
+ region: DomRefCell::new(None),
+ vertical: Cell::new(DirectionSetting::default()),
+ snap_to_lines: Cell::new(true),
+ line: DomRefCell::new(LineAndPositionSetting::Auto),
+ line_align: Cell::new(LineAlignSetting::Start),
+ position: DomRefCell::new(LineAndPositionSetting::Auto),
+ position_align: Cell::new(PositionAlignSetting::Auto),
+ size: Cell::new(100_f64),
+ align: Cell::new(AlignSetting::Center),
+ text: DomRefCell::new(text),
+ }
+ }
+
+ pub fn new(
+ global: &GlobalScope,
+ start_time: f64,
+ end_time: f64,
+ text: DOMString,
+ ) -> DomRoot<Self> {
+ reflect_dom_object(
+ Box::new(Self::new_inherited(start_time, end_time, text)),
+ global,
+ VTTCueBinding::Wrap,
+ )
+ }
+
+ #[allow(non_snake_case)]
+ pub fn Constructor(
+ window: &Window,
+ start_time: Finite<f64>,
+ end_time: Finite<f64>,
+ text: DOMString,
+ ) -> DomRoot<Self> {
+ VTTCue::new(&window.global(), *start_time, *end_time, text)
+ }
+}
+
+impl VTTCueMethods for VTTCue {
+ // https://w3c.github.io/webvtt/#dom-vttcue-region
+ fn GetRegion(&self) -> Option<DomRoot<VTTRegion>> {
+ self.region
+ .borrow()
+ .as_ref()
+ .map(|r| DomRoot::from_ref(&**r))
+ }
+
+ // https://w3c.github.io/webvtt/#dom-vttcue-region
+ fn SetRegion(&self, value: Option<&VTTRegion>) {
+ *self.region.borrow_mut() = value.map(|r| Dom::from_ref(r))
+ }
+
+ // https://w3c.github.io/webvtt/#dom-vttcue-vertical
+ fn Vertical(&self) -> DirectionSetting {
+ self.vertical.get()
+ }
+
+ // https://w3c.github.io/webvtt/#dom-vttcue-vertical
+ fn SetVertical(&self, value: DirectionSetting) {
+ self.vertical.set(value);
+ }
+
+ // https://w3c.github.io/webvtt/#dom-vttcue-snaptolines
+ fn SnapToLines(&self) -> bool {
+ self.snap_to_lines.get()
+ }
+
+ // https://w3c.github.io/webvtt/#dom-vttcue-snaptolines
+ fn SetSnapToLines(&self, value: bool) {
+ self.snap_to_lines.set(value)
+ }
+
+ // https://w3c.github.io/webvtt/#dom-vttcue-line
+ fn Line(&self) -> VTTCueBinding::LineAndPositionSetting {
+ VTTCueBinding::LineAndPositionSetting::from(self.line.borrow().clone())
+ }
+
+ // https://w3c.github.io/webvtt/#dom-vttcue-line
+ fn SetLine(&self, value: VTTCueBinding::LineAndPositionSetting) {
+ *self.line.borrow_mut() = value.into();
+ }
+
+ // https://w3c.github.io/webvtt/#dom-vttcue-linealign
+ fn LineAlign(&self) -> LineAlignSetting {
+ self.line_align.get()
+ }
+
+ // https://w3c.github.io/webvtt/#dom-vttcue-linealign
+ fn SetLineAlign(&self, value: LineAlignSetting) {
+ self.line_align.set(value);
+ }
+
+ // https://w3c.github.io/webvtt/#dom-vttcue-position
+ fn Position(&self) -> VTTCueBinding::LineAndPositionSetting {
+ VTTCueBinding::LineAndPositionSetting::from(self.position.borrow().clone())
+ }
+
+ // https://w3c.github.io/webvtt/#dom-vttcue-position
+ fn SetPosition(&self, value: VTTCueBinding::LineAndPositionSetting) -> ErrorResult {
+ if let VTTCueBinding::LineAndPositionSetting::Double(x) = value {
+ if *x < 0_f64 || *x > 100_f64 {
+ return Err(Error::IndexSize);
+ }
+ }
+
+ *self.position.borrow_mut() = value.into();
+ Ok(())
+ }
+
+ // https://w3c.github.io/webvtt/#dom-vttcue-positionalign
+ fn PositionAlign(&self) -> PositionAlignSetting {
+ self.position_align.get()
+ }
+
+ // https://w3c.github.io/webvtt/#dom-vttcue-positionalign
+ fn SetPositionAlign(&self, value: PositionAlignSetting) {
+ self.position_align.set(value);
+ }
+
+ // https://w3c.github.io/webvtt/#dom-vttcue-size
+ fn Size(&self) -> Finite<f64> {
+ Finite::wrap(self.size.get())
+ }
+
+ // https://w3c.github.io/webvtt/#dom-vttcue-size
+ fn SetSize(&self, value: Finite<f64>) -> ErrorResult {
+ if *value < 0_f64 || *value > 100_f64 {
+ return Err(Error::IndexSize);
+ }
+
+ self.size.set(*value);
+ Ok(())
+ }
+
+ // https://w3c.github.io/webvtt/#dom-vttcue-align
+ fn Align(&self) -> AlignSetting {
+ self.align.get()
+ }
+
+ // https://w3c.github.io/webvtt/#dom-vttcue-align
+ fn SetAlign(&self, value: AlignSetting) {
+ self.align.set(value);
+ }
+
+ // https://w3c.github.io/webvtt/#dom-vttcue-text
+ fn Text(&self) -> DOMString {
+ self.text.borrow().clone()
+ }
+
+ // https://w3c.github.io/webvtt/#dom-vttcue-text
+ fn SetText(&self, value: DOMString) {
+ *self.text.borrow_mut() = value;
+ }
+
+ // https://w3c.github.io/webvtt/#dom-vttcue-getcueashtml
+ fn GetCueAsHTML(&self) -> DomRoot<DocumentFragment> {
+ todo!()
+ }
+}
+
+#[derive(Clone, JSTraceable, MallocSizeOf)]
+enum LineAndPositionSetting {
+ Double(f64),
+ Auto,
+}
+
+impl From<VTTCueBinding::LineAndPositionSetting> for LineAndPositionSetting {
+ fn from(value: VTTCueBinding::LineAndPositionSetting) -> Self {
+ match value {
+ VTTCueBinding::LineAndPositionSetting::Double(x) => LineAndPositionSetting::Double(*x),
+ VTTCueBinding::LineAndPositionSetting::AutoKeyword(_) => LineAndPositionSetting::Auto,
+ }
+ }
+}
+
+impl From<LineAndPositionSetting> for VTTCueBinding::LineAndPositionSetting {
+ fn from(value: LineAndPositionSetting) -> Self {
+ match value {
+ LineAndPositionSetting::Double(x) => {
+ VTTCueBinding::LineAndPositionSetting::Double(Finite::wrap(x))
+ },
+ LineAndPositionSetting::Auto => {
+ VTTCueBinding::LineAndPositionSetting::AutoKeyword(AutoKeyword::Auto)
+ },
+ }
+ }
+}
diff --git a/components/script/dom/vttregion.rs b/components/script/dom/vttregion.rs
new file mode 100644
index 00000000000..167e9fa37bf
--- /dev/null
+++ b/components/script/dom/vttregion.rs
@@ -0,0 +1,167 @@
+/* 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::VTTRegionBinding::{
+ self, ScrollSetting, VTTRegionMethods,
+};
+use crate::dom::bindings::error::{Error, ErrorResult, Fallible};
+use crate::dom::bindings::num::Finite;
+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::window::Window;
+use dom_struct::dom_struct;
+use std::cell::Cell;
+
+#[dom_struct]
+pub struct VTTRegion {
+ reflector_: Reflector,
+ id: DomRefCell<DOMString>,
+ width: Cell<f64>,
+ lines: Cell<u32>,
+ region_anchor_x: Cell<f64>,
+ region_anchor_y: Cell<f64>,
+ viewport_anchor_x: Cell<f64>,
+ viewport_anchor_y: Cell<f64>,
+ scroll: Cell<ScrollSetting>,
+}
+
+impl VTTRegion {
+ pub fn new_inherited() -> Self {
+ VTTRegion {
+ reflector_: Reflector::new(),
+ id: DomRefCell::new(DOMString::default()),
+ width: Cell::new(100_f64),
+ lines: Cell::new(3),
+ region_anchor_x: Cell::new(0_f64),
+ region_anchor_y: Cell::new(100_f64),
+ viewport_anchor_x: Cell::new(0_f64),
+ viewport_anchor_y: Cell::new(100_f64),
+ scroll: Cell::new(Default::default()),
+ }
+ }
+
+ pub fn new(global: &GlobalScope) -> DomRoot<Self> {
+ reflect_dom_object(
+ Box::new(Self::new_inherited()),
+ global,
+ VTTRegionBinding::Wrap,
+ )
+ }
+
+ #[allow(non_snake_case)]
+ pub fn Constructor(window: &Window) -> Fallible<DomRoot<Self>> {
+ Ok(VTTRegion::new(&window.global()))
+ }
+}
+
+impl VTTRegionMethods for VTTRegion {
+ // https://w3c.github.io/webvtt/#dom-vttregion-id
+ fn Id(&self) -> DOMString {
+ self.id.borrow().clone()
+ }
+
+ // https://w3c.github.io/webvtt/#dom-vttregion-id
+ fn SetId(&self, value: DOMString) {
+ *self.id.borrow_mut() = value;
+ }
+
+ // https://w3c.github.io/webvtt/#dom-vttregion-width
+ fn Width(&self) -> Finite<f64> {
+ Finite::wrap(self.width.get())
+ }
+
+ // https://w3c.github.io/webvtt/#dom-vttregion-width
+ fn SetWidth(&self, value: Finite<f64>) -> ErrorResult {
+ if *value < 0_f64 || *value > 100_f64 {
+ return Err(Error::IndexSize);
+ }
+
+ self.width.set(*value);
+ Ok(())
+ }
+
+ // https://w3c.github.io/webvtt/#dom-vttregion-lines
+ fn Lines(&self) -> u32 {
+ self.lines.get()
+ }
+
+ // https://w3c.github.io/webvtt/#dom-vttregion-lines
+ fn SetLines(&self, value: u32) -> ErrorResult {
+ self.lines.set(value);
+ Ok(())
+ }
+
+ // https://w3c.github.io/webvtt/#dom-vttregion-regionanchorx
+ fn RegionAnchorX(&self) -> Finite<f64> {
+ Finite::wrap(self.region_anchor_x.get())
+ }
+
+ // https://w3c.github.io/webvtt/#dom-vttregion-regionanchorx
+ fn SetRegionAnchorX(&self, value: Finite<f64>) -> ErrorResult {
+ if *value < 0_f64 || *value > 100_f64 {
+ return Err(Error::IndexSize);
+ }
+
+ self.region_anchor_x.set(*value);
+ Ok(())
+ }
+
+ // https://w3c.github.io/webvtt/#dom-vttregion-regionanchory
+ fn RegionAnchorY(&self) -> Finite<f64> {
+ Finite::wrap(self.region_anchor_y.get())
+ }
+
+ // https://w3c.github.io/webvtt/#dom-vttregion-regionanchory
+ fn SetRegionAnchorY(&self, value: Finite<f64>) -> ErrorResult {
+ if *value < 0_f64 || *value > 100_f64 {
+ return Err(Error::IndexSize);
+ }
+
+ self.region_anchor_y.set(*value);
+ Ok(())
+ }
+
+ // https://w3c.github.io/webvtt/#dom-vttregion-viewportanchorx
+ fn ViewportAnchorX(&self) -> Finite<f64> {
+ Finite::wrap(self.viewport_anchor_x.get())
+ }
+
+ // https://w3c.github.io/webvtt/#dom-vttregion-viewportanchorx
+ fn SetViewportAnchorX(&self, value: Finite<f64>) -> ErrorResult {
+ if *value < 0_f64 || *value > 100_f64 {
+ return Err(Error::IndexSize);
+ }
+
+ self.viewport_anchor_x.set(*value);
+ Ok(())
+ }
+
+ // https://w3c.github.io/webvtt/#dom-vttregion-viewportanchory
+ fn ViewportAnchorY(&self) -> Finite<f64> {
+ Finite::wrap(self.viewport_anchor_y.get())
+ }
+
+ // https://w3c.github.io/webvtt/#dom-vttregion-viewportanchory
+ fn SetViewportAnchorY(&self, value: Finite<f64>) -> ErrorResult {
+ if *value < 0_f64 || *value > 100_f64 {
+ return Err(Error::IndexSize);
+ }
+
+ self.viewport_anchor_y.set(*value);
+ Ok(())
+ }
+
+ // https://w3c.github.io/webvtt/#dom-vttregion-scroll
+ fn Scroll(&self) -> ScrollSetting {
+ self.scroll.get()
+ }
+
+ // https://w3c.github.io/webvtt/#dom-vttregion-scroll
+ fn SetScroll(&self, value: ScrollSetting) {
+ self.scroll.set(value);
+ }
+}
diff --git a/components/script/dom/webgl2renderingcontext.rs b/components/script/dom/webgl2renderingcontext.rs
index cc735f36e41..7b1a68b475a 100644
--- a/components/script/dom/webgl2renderingcontext.rs
+++ b/components/script/dom/webgl2renderingcontext.rs
@@ -36,12 +36,14 @@ use crate::dom::webglsync::WebGLSync;
use crate::dom::webgltexture::WebGLTexture;
use crate::dom::webgltransformfeedback::WebGLTransformFeedback;
use crate::dom::webgluniformlocation::WebGLUniformLocation;
+use crate::dom::webglvertexarrayobject::WebGLVertexArrayObject;
use crate::dom::window::Window;
use crate::js::conversions::ToJSValConvertible;
use crate::script_runtime::JSContext;
use canvas_traits::webgl::WebGLError::*;
use canvas_traits::webgl::{
- webgl_channel, GLContextAttributes, WebGLCommand, WebGLResult, WebGLVersion,
+ webgl_channel, GLContextAttributes, InternalFormatParameter, WebGLCommand, WebGLResult,
+ WebGLVersion,
};
use dom_struct::dom_struct;
use euclid::default::{Point2D, Rect, Size2D};
@@ -50,12 +52,30 @@ use js::jsapi::{JSObject, Type};
use js::jsval::{BooleanValue, DoubleValue, Int32Value, UInt32Value};
use js::jsval::{JSVal, NullValue, ObjectValue, UndefinedValue};
use js::rust::CustomAutoRooterGuard;
-use js::typedarray::{ArrayBufferView, CreateWith, Float32, Uint32, Uint32Array};
+use js::typedarray::{ArrayBufferView, CreateWith, Float32, Int32Array, Uint32, Uint32Array};
use script_layout_interface::HTMLCanvasDataSource;
use std::cell::Cell;
use std::cmp;
use std::ptr::{self, NonNull};
+#[unrooted_must_root_lint::must_root]
+#[derive(JSTraceable, MallocSizeOf)]
+struct IndexedBinding {
+ buffer: MutNullableDom<WebGLBuffer>,
+ start: Cell<i64>,
+ size: Cell<i64>,
+}
+
+impl IndexedBinding {
+ fn new() -> IndexedBinding {
+ IndexedBinding {
+ buffer: MutNullableDom::new(None),
+ start: Cell::new(0),
+ size: Cell::new(0),
+ }
+ }
+}
+
#[dom_struct]
pub struct WebGL2RenderingContext {
reflector_: Reflector,
@@ -69,11 +89,15 @@ pub struct WebGL2RenderingContext {
bound_pixel_unpack_buffer: MutNullableDom<WebGLBuffer>,
bound_transform_feedback_buffer: MutNullableDom<WebGLBuffer>,
bound_uniform_buffer: MutNullableDom<WebGLBuffer>,
+ indexed_uniform_buffer_bindings: Box<[IndexedBinding]>,
+ indexed_transform_feedback_buffer_bindings: Box<[IndexedBinding]>,
current_transform_feedback: MutNullableDom<WebGLTransformFeedback>,
texture_pack_row_length: Cell<usize>,
texture_pack_skip_pixels: Cell<usize>,
texture_pack_skip_rows: Cell<usize>,
enable_rasterizer_discard: Cell<bool>,
+ default_fb_readbuffer: Cell<u32>,
+ default_fb_drawbuffer: Cell<u32>,
}
fn typedarray_elem_size(typeid: Type) -> usize {
@@ -82,6 +106,7 @@ fn typedarray_elem_size(typeid: Type) -> usize {
Type::Int16 | Type::Uint16 => 2,
Type::Int32 | Type::Uint32 | Type::Float32 => 4,
Type::Int64 | Type::Float64 => 8,
+ Type::BigInt64 | Type::BigUint64 => 8,
Type::MaxTypedArrayViewType => unreachable!(),
}
}
@@ -110,6 +135,15 @@ impl WebGL2RenderingContext {
.map(|_| Default::default())
.collect::<Vec<_>>()
.into();
+ let indexed_uniform_buffer_bindings = (0..base.limits().max_uniform_buffer_bindings)
+ .map(|_| IndexedBinding::new())
+ .collect::<Vec<_>>()
+ .into();
+ let indexed_transform_feedback_buffer_bindings =
+ (0..base.limits().max_transform_feedback_separate_attribs)
+ .map(|_| IndexedBinding::new())
+ .collect::<Vec<_>>()
+ .into();
Some(WebGL2RenderingContext {
reflector_: Reflector::new(),
@@ -123,11 +157,15 @@ impl WebGL2RenderingContext {
bound_pixel_unpack_buffer: MutNullableDom::new(None),
bound_transform_feedback_buffer: MutNullableDom::new(None),
bound_uniform_buffer: MutNullableDom::new(None),
+ indexed_uniform_buffer_bindings,
+ indexed_transform_feedback_buffer_bindings,
current_transform_feedback: MutNullableDom::new(None),
texture_pack_row_length: Cell::new(0),
texture_pack_skip_pixels: Cell::new(0),
texture_pack_skip_rows: Cell::new(0),
enable_rasterizer_discard: Cell::new(false),
+ default_fb_readbuffer: Cell::new(constants::BACK),
+ default_fb_drawbuffer: Cell::new(constants::BACK),
})
}
@@ -149,6 +187,10 @@ impl WebGL2RenderingContext {
self.base.recreate(size)
}
+ pub fn current_vao(&self) -> DomRoot<WebGLVertexArrayObject> {
+ self.base.current_vao_webgl2()
+ }
+
pub fn base_context(&self) -> DomRoot<WebGLRenderingContext> {
DomRoot::from_ref(&*self.base)
}
@@ -161,6 +203,7 @@ impl WebGL2RenderingContext {
constants::PIXEL_UNPACK_BUFFER => Ok(self.bound_pixel_unpack_buffer.get()),
constants::TRANSFORM_FEEDBACK_BUFFER => Ok(self.bound_transform_feedback_buffer.get()),
constants::UNIFORM_BUFFER => Ok(self.bound_uniform_buffer.get()),
+ constants::ELEMENT_ARRAY_BUFFER => Ok(self.current_vao().element_array_buffer().get()),
_ => self.base.bound_buffer(target),
}
}
@@ -305,6 +348,15 @@ impl WebGL2RenderingContext {
return self.base.webgl_error(InvalidOperation);
}
+ let fb_slot = self.base.get_draw_framebuffer_slot();
+ let fb_readbuffer_valid = match fb_slot.get() {
+ Some(fb) => fb.attachment(fb.read_buffer()).is_some(),
+ None => self.default_fb_readbuffer.get() != constants::NONE,
+ };
+ if !fb_readbuffer_valid {
+ return self.base.webgl_error(InvalidOperation);
+ }
+
let dst_byte_offset = {
let dst_elem_size = typedarray_elem_size(dst.get_array_type());
dst_elem_offset as usize * dst_elem_size
@@ -603,6 +655,51 @@ impl WebGL2RenderingContext {
self.base.send_command(msg(buffer, draw_buffer, array));
}
+
+ fn valid_fb_attachment_values(&self, target: u32, attachments: &[u32]) -> bool {
+ let fb_slot = match target {
+ constants::FRAMEBUFFER | constants::DRAW_FRAMEBUFFER => {
+ self.base.get_draw_framebuffer_slot()
+ },
+ constants::READ_FRAMEBUFFER => self.base.get_read_framebuffer_slot(),
+ _ => {
+ self.base.webgl_error(InvalidEnum);
+ return false;
+ },
+ };
+
+ if let Some(fb) = fb_slot.get() {
+ if fb.check_status() != constants::FRAMEBUFFER_COMPLETE {
+ return false;
+ }
+
+ for &attachment in attachments {
+ match attachment {
+ constants::DEPTH_ATTACHMENT |
+ constants::STENCIL_ATTACHMENT |
+ constants::DEPTH_STENCIL_ATTACHMENT => {},
+ constants::COLOR_ATTACHMENT0..=constants::COLOR_ATTACHMENT15 => {
+ let last_slot = constants::COLOR_ATTACHMENT0 +
+ self.base.limits().max_color_attachments -
+ 1;
+ if last_slot < attachment {
+ return false;
+ }
+ },
+ _ => return false,
+ }
+ }
+ } else {
+ for &attachment in attachments {
+ match attachment {
+ constants::COLOR | constants::DEPTH | constants::STENCIL => {},
+ _ => return false,
+ }
+ }
+ }
+
+ true
+ }
}
impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
@@ -700,6 +797,15 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
self.current_transform_feedback.get()
);
},
+ constants::ELEMENT_ARRAY_BUFFER_BINDING => unsafe {
+ let buffer = self.current_vao().element_array_buffer().get();
+ return optional_root_object_to_js_or_null!(*cx, buffer);
+ },
+ constants::VERTEX_ARRAY_BINDING => unsafe {
+ let vao = self.current_vao();
+ let vao = vao.id().map(|_| &*vao);
+ return optional_root_object_to_js_or_null!(*cx, vao);
+ },
// NOTE: DRAW_FRAMEBUFFER_BINDING is the same as FRAMEBUFFER_BINDING, handled on the WebGL1 side
constants::READ_FRAMEBUFFER_BINDING => unsafe {
return optional_root_object_to_js_or_null!(
@@ -707,6 +813,26 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
&self.base.get_read_framebuffer_slot().get()
);
},
+ constants::READ_BUFFER => {
+ let buffer = match self.base.get_read_framebuffer_slot().get() {
+ Some(fb) => fb.read_buffer(),
+ None => self.default_fb_readbuffer.get(),
+ };
+ return UInt32Value(buffer);
+ },
+ constants::DRAW_BUFFER0..=constants::DRAW_BUFFER15 => {
+ let buffer = match self.base.get_read_framebuffer_slot().get() {
+ Some(fb) => {
+ let idx = parameter - constants::DRAW_BUFFER0;
+ fb.draw_buffer_i(idx as usize)
+ },
+ None if parameter == constants::DRAW_BUFFER0 => {
+ self.default_fb_readbuffer.get()
+ },
+ None => constants::NONE,
+ };
+ return UInt32Value(buffer);
+ },
_ => {},
}
@@ -865,6 +991,7 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
/// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.2
fn BindBuffer(&self, target: u32, buffer: Option<&WebGLBuffer>) {
+ let current_vao;
let slot = match target {
constants::COPY_READ_BUFFER => &self.bound_copy_read_buffer,
constants::COPY_WRITE_BUFFER => &self.bound_copy_write_buffer,
@@ -872,6 +999,10 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
constants::PIXEL_UNPACK_BUFFER => &self.bound_pixel_unpack_buffer,
constants::TRANSFORM_FEEDBACK_BUFFER => &self.bound_transform_feedback_buffer,
constants::UNIFORM_BUFFER => &self.bound_uniform_buffer,
+ constants::ELEMENT_ARRAY_BUFFER => {
+ current_vao = self.current_vao();
+ current_vao.element_array_buffer()
+ },
_ => return self.base.BindBuffer(target, buffer),
};
self.base.bind_buffer_maybe(&slot, target, buffer);
@@ -1332,6 +1463,11 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
self.base.CreateShader(shader_type)
}
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.17
+ fn CreateVertexArray(&self) -> Option<DomRoot<WebGLVertexArrayObject>> {
+ self.base.create_vertex_array_webgl2()
+ }
+
/// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5
fn DeleteBuffer(&self, buffer: Option<&WebGLBuffer>) {
let buffer = match buffer {
@@ -1342,7 +1478,7 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
if buffer.is_marked_for_deletion() {
return;
}
- self.base.current_vao().unbind_buffer(buffer);
+ self.current_vao().unbind_buffer(buffer);
self.unbind_from(&self.base.array_buffer_slot(), &buffer);
self.unbind_from(&self.bound_copy_read_buffer, &buffer);
self.unbind_from(&self.bound_copy_write_buffer, &buffer);
@@ -1350,6 +1486,14 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
self.unbind_from(&self.bound_pixel_unpack_buffer, &buffer);
self.unbind_from(&self.bound_transform_feedback_buffer, &buffer);
self.unbind_from(&self.bound_uniform_buffer, &buffer);
+
+ for binding in self.indexed_uniform_buffer_bindings.iter() {
+ self.unbind_from(&binding.buffer, &buffer);
+ }
+ for binding in self.indexed_transform_feedback_buffer_bindings.iter() {
+ self.unbind_from(&binding.buffer, &buffer);
+ }
+
buffer.mark_for_deletion(false);
}
@@ -1378,6 +1522,11 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
self.base.DeleteShader(shader)
}
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.17
+ fn DeleteVertexArray(&self, vertex_array: Option<&WebGLVertexArrayObject>) {
+ self.base.delete_vertex_array_webgl2(vertex_array);
+ }
+
/// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.11
fn DrawArrays(&self, mode: u32, first: i32, count: i32) {
self.base.DrawArrays(mode, first, count)
@@ -1421,6 +1570,12 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
self.base.GetAttribLocation(program, name)
}
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.7
+ fn GetFragDataLocation(&self, program: &WebGLProgram, name: DOMString) -> i32 {
+ handle_potential_webgl_error!(self.base, self.base.validate_ownership(program), return -1);
+ handle_potential_webgl_error!(self.base, program.get_frag_data_location(name), -1)
+ }
+
/// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9
fn GetProgramInfoLog(&self, program: &WebGLProgram) -> Option<DOMString> {
self.base.GetProgramInfoLog(program)
@@ -1468,6 +1623,46 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
.GetShaderPrecisionFormat(shader_type, precision_type)
}
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.2
+ #[allow(unsafe_code)]
+ fn GetIndexedParameter(&self, cx: JSContext, target: u32, index: u32) -> JSVal {
+ let bindings = match target {
+ constants::TRANSFORM_FEEDBACK_BUFFER_BINDING |
+ constants::TRANSFORM_FEEDBACK_BUFFER_SIZE |
+ constants::TRANSFORM_FEEDBACK_BUFFER_START => {
+ &self.indexed_transform_feedback_buffer_bindings
+ },
+ constants::UNIFORM_BUFFER_BINDING |
+ constants::UNIFORM_BUFFER_SIZE |
+ constants::UNIFORM_BUFFER_START => &self.indexed_uniform_buffer_bindings,
+ _ => {
+ self.base.webgl_error(InvalidEnum);
+ return NullValue();
+ },
+ };
+
+ let binding = match bindings.get(index as usize) {
+ Some(binding) => binding,
+ None => {
+ self.base.webgl_error(InvalidValue);
+ return NullValue();
+ },
+ };
+
+ match target {
+ constants::TRANSFORM_FEEDBACK_BUFFER_BINDING | constants::UNIFORM_BUFFER_BINDING => unsafe {
+ optional_root_object_to_js_or_null!(*cx, binding.buffer.get())
+ },
+ constants::TRANSFORM_FEEDBACK_BUFFER_START | constants::UNIFORM_BUFFER_START => {
+ Int32Value(binding.start.get() as _)
+ },
+ constants::TRANSFORM_FEEDBACK_BUFFER_SIZE | constants::UNIFORM_BUFFER_SIZE => {
+ Int32Value(binding.size.get() as _)
+ },
+ _ => unreachable!(),
+ }
+ }
+
/// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
fn GetUniformLocation(
&self,
@@ -1531,6 +1726,11 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
self.base.IsTexture(texture)
}
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.17
+ fn IsVertexArray(&self, vertex_array: Option<&WebGLVertexArrayObject>) -> bool {
+ self.base.is_vertex_array_webgl2(vertex_array)
+ }
+
/// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3
fn LineWidth(&self, width: f32) {
self.base.LineWidth(width)
@@ -2293,6 +2493,9 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
&uniform_get(triple, WebGLCommand::GetUniformFloat4x3),
)
},
+ constants::SAMPLER_3D | constants::SAMPLER_2D_ARRAY => {
+ Int32Value(uniform_get(triple, WebGLCommand::GetUniformInt))
+ },
_ => self.base.GetUniform(cx, program, location),
}
}
@@ -2911,6 +3114,11 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
}
}
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.17
+ fn BindVertexArray(&self, array: Option<&WebGLVertexArrayObject>) {
+ self.base.bind_vertex_array_webgl2(array);
+ }
+
/// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.13
fn SamplerParameteri(&self, sampler: &WebGLSampler, pname: u32, param: i32) {
handle_potential_webgl_error!(self.base, self.base.validate_ownership(sampler), return);
@@ -3160,20 +3368,21 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
/// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.16
fn BindBufferBase(&self, target: u32, index: u32, buffer: Option<&WebGLBuffer>) {
- let (bind_limit, slot) = match target {
+ let (generic_slot, indexed_bindings) = match target {
constants::TRANSFORM_FEEDBACK_BUFFER => (
- self.base.limits().max_transform_feedback_separate_attribs,
&self.bound_transform_feedback_buffer,
+ &self.indexed_transform_feedback_buffer_bindings,
),
constants::UNIFORM_BUFFER => (
- self.base.limits().max_uniform_buffer_bindings,
&self.bound_uniform_buffer,
+ &self.indexed_uniform_buffer_bindings,
),
_ => return self.base.webgl_error(InvalidEnum),
};
- if index >= bind_limit {
- return self.base.webgl_error(InvalidValue);
- }
+ let indexed_binding = match indexed_bindings.get(index as usize) {
+ Some(slot) => slot,
+ None => return self.base.webgl_error(InvalidValue),
+ };
if let Some(buffer) = buffer {
handle_potential_webgl_error!(self.base, self.base.validate_ownership(buffer), return);
@@ -3182,6 +3391,9 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
return self.base.webgl_error(InvalidOperation);
}
handle_potential_webgl_error!(self.base, buffer.set_target_maybe(target), return);
+
+ // for both the generic and the indexed bindings
+ buffer.increment_attached_counter();
buffer.increment_attached_counter();
}
@@ -3190,11 +3402,15 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
index,
buffer.map(|b| b.id()),
));
- if let Some(old) = slot.get() {
- old.decrement_attached_counter();
- }
- slot.set(buffer);
+ for slot in &[&generic_slot, &indexed_binding.buffer] {
+ if let Some(old) = slot.get() {
+ old.decrement_attached_counter();
+ }
+ slot.set(buffer);
+ }
+ indexed_binding.start.set(0);
+ indexed_binding.size.set(0);
}
/// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.16
@@ -3206,20 +3422,21 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
offset: i64,
size: i64,
) {
- let (bind_limit, slot) = match target {
+ let (generic_slot, indexed_bindings) = match target {
constants::TRANSFORM_FEEDBACK_BUFFER => (
- self.base.limits().max_transform_feedback_separate_attribs,
&self.bound_transform_feedback_buffer,
+ &self.indexed_transform_feedback_buffer_bindings,
),
constants::UNIFORM_BUFFER => (
- self.base.limits().max_uniform_buffer_bindings,
&self.bound_uniform_buffer,
+ &self.indexed_uniform_buffer_bindings,
),
_ => return self.base.webgl_error(InvalidEnum),
};
- if index >= bind_limit {
- return self.base.webgl_error(InvalidValue);
- }
+ let indexed_binding = match indexed_bindings.get(index as usize) {
+ Some(slot) => slot,
+ None => return self.base.webgl_error(InvalidValue),
+ };
if offset < 0 || size < 0 {
return self.base.webgl_error(InvalidValue);
@@ -3250,6 +3467,9 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
return self.base.webgl_error(InvalidOperation);
}
handle_potential_webgl_error!(self.base, buffer.set_target_maybe(target), return);
+
+ // for both the generic and the indexed bindings
+ buffer.increment_attached_counter();
buffer.increment_attached_counter();
}
@@ -3260,11 +3480,15 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
offset,
size,
));
- if let Some(old) = slot.get() {
- old.decrement_attached_counter();
- }
- slot.set(buffer);
+ for slot in &[&generic_slot, &indexed_binding.buffer] {
+ if let Some(old) = slot.get() {
+ old.decrement_attached_counter();
+ }
+ slot.set(buffer);
+ }
+ indexed_binding.start.set(offset);
+ indexed_binding.size.set(size);
}
/// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.16
@@ -3497,6 +3721,169 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
stencil,
));
}
+
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.4
+ fn InvalidateFramebuffer(&self, target: u32, attachments: Vec<u32>) {
+ if !self.valid_fb_attachment_values(target, &attachments) {
+ return;
+ }
+
+ self.base
+ .send_command(WebGLCommand::InvalidateFramebuffer(target, attachments))
+ }
+
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.4
+ fn InvalidateSubFramebuffer(
+ &self,
+ target: u32,
+ attachments: Vec<u32>,
+ x: i32,
+ y: i32,
+ width: i32,
+ height: i32,
+ ) {
+ if !self.valid_fb_attachment_values(target, &attachments) {
+ return;
+ }
+
+ if width < 0 || height < 0 {
+ return;
+ }
+
+ self.base
+ .send_command(WebGLCommand::InvalidateSubFramebuffer(
+ target,
+ attachments,
+ x,
+ y,
+ width,
+ height,
+ ))
+ }
+
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.4
+ fn FramebufferTextureLayer(
+ &self,
+ target: u32,
+ attachment: u32,
+ texture: Option<&WebGLTexture>,
+ level: i32,
+ layer: i32,
+ ) {
+ if let Some(tex) = texture {
+ handle_potential_webgl_error!(self.base, self.base.validate_ownership(tex), return);
+ }
+
+ let fb_slot = match target {
+ constants::FRAMEBUFFER | constants::DRAW_FRAMEBUFFER => {
+ self.base.get_draw_framebuffer_slot()
+ },
+ constants::READ_FRAMEBUFFER => self.base.get_read_framebuffer_slot(),
+ _ => return self.base.webgl_error(InvalidEnum),
+ };
+
+ match fb_slot.get() {
+ Some(fb) => handle_potential_webgl_error!(
+ self.base,
+ fb.texture_layer(attachment, texture, level, layer)
+ ),
+ None => self.base.webgl_error(InvalidOperation),
+ }
+ }
+
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.5
+ #[allow(unsafe_code)]
+ fn GetInternalformatParameter(
+ &self,
+ cx: JSContext,
+ target: u32,
+ internal_format: u32,
+ pname: u32,
+ ) -> JSVal {
+ if target != constants::RENDERBUFFER {
+ self.base.webgl_error(InvalidEnum);
+ return NullValue();
+ }
+
+ match handle_potential_webgl_error!(
+ self.base,
+ InternalFormatParameter::from_u32(pname),
+ return NullValue()
+ ) {
+ InternalFormatParameter::IntVec(param) => unsafe {
+ let (sender, receiver) = webgl_channel().unwrap();
+ self.base
+ .send_command(WebGLCommand::GetInternalFormatIntVec(
+ target,
+ internal_format,
+ param,
+ sender,
+ ));
+
+ rooted!(in(*cx) let mut rval = ptr::null_mut::<JSObject>());
+ let _ = Int32Array::create(
+ *cx,
+ CreateWith::Slice(&receiver.recv().unwrap()),
+ rval.handle_mut(),
+ )
+ .unwrap();
+ ObjectValue(rval.get())
+ },
+ }
+ }
+
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.5
+ fn RenderbufferStorageMultisample(
+ &self,
+ target: u32,
+ samples: i32,
+ internal_format: u32,
+ width: i32,
+ height: i32,
+ ) {
+ self.base
+ .renderbuffer_storage(target, samples, internal_format, width, height)
+ }
+
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.4
+ fn ReadBuffer(&self, src: u32) {
+ match src {
+ constants::BACK | constants::NONE => {},
+ _ if self.base.valid_color_attachment_enum(src) => {},
+ _ => return self.base.webgl_error(InvalidEnum),
+ }
+
+ if let Some(fb) = self.base.get_read_framebuffer_slot().get() {
+ handle_potential_webgl_error!(self.base, fb.set_read_buffer(src), return)
+ } else {
+ match src {
+ constants::NONE | constants::BACK => {},
+ _ => return self.base.webgl_error(InvalidOperation),
+ }
+
+ self.default_fb_readbuffer.set(src);
+ self.base.send_command(WebGLCommand::ReadBuffer(src));
+ }
+ }
+
+ /// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.11
+ fn DrawBuffers(&self, buffers: Vec<u32>) {
+ if let Some(fb) = self.base.get_draw_framebuffer_slot().get() {
+ handle_potential_webgl_error!(self.base, fb.set_draw_buffers(buffers), return)
+ } else {
+ if buffers.len() != 1 {
+ return self.base.webgl_error(InvalidOperation);
+ }
+
+ match buffers[0] {
+ constants::NONE | constants::BACK => {},
+ _ => return self.base.webgl_error(InvalidOperation),
+ }
+
+ self.default_fb_drawbuffer.set(buffers[0]);
+ self.base.send_command(WebGLCommand::DrawBuffers(buffers));
+ }
+ }
}
impl LayoutCanvasWebGLRenderingContextHelpers for LayoutDom<WebGL2RenderingContext> {
diff --git a/components/script/dom/webglframebuffer.rs b/components/script/dom/webglframebuffer.rs
index c2eb10fcd60..f3f6e939f4f 100644
--- a/components/script/dom/webglframebuffer.rs
+++ b/components/script/dom/webglframebuffer.rs
@@ -101,6 +101,8 @@ pub struct WebGLFramebuffer {
depth: DomRefCell<Option<WebGLFramebufferAttachment>>,
stencil: DomRefCell<Option<WebGLFramebufferAttachment>>,
depthstencil: DomRefCell<Option<WebGLFramebufferAttachment>>,
+ color_read_buffer: DomRefCell<u32>,
+ color_draw_buffers: DomRefCell<Vec<u32>>,
is_initialized: Cell<bool>,
// Framebuffers for XR keep a reference to the XR session.
// https://github.com/immersive-web/webxr/issues/856
@@ -121,6 +123,8 @@ impl WebGLFramebuffer {
depth: DomRefCell::new(None),
stencil: DomRefCell::new(None),
depthstencil: DomRefCell::new(None),
+ color_read_buffer: DomRefCell::new(constants::COLOR_ATTACHMENT0),
+ color_draw_buffers: DomRefCell::new(vec![constants::COLOR_ATTACHMENT0]),
is_initialized: Cell::new(false),
xr_session: Default::default(),
}
@@ -142,9 +146,11 @@ impl WebGLFramebuffer {
size: Size2D<i32, Viewport>,
) -> Option<(WebXRSwapChainId, DomRoot<Self>)> {
let (sender, receiver) = webgl_channel().unwrap();
- let _ = context
- .webgl_sender()
- .send_create_webxr_swap_chain(size.to_untyped(), sender);
+ let _ = context.webgl_sender().send_create_webxr_swap_chain(
+ size.to_untyped(),
+ sender,
+ session.session_id(),
+ );
let swap_chain_id = receiver.recv().unwrap()?;
let framebuffer_id =
WebGLFramebufferId::Opaque(WebGLOpaqueFramebufferId::WebXR(swap_chain_id));
@@ -219,10 +225,10 @@ impl WebGLFramebuffer {
self.size.get()
}
- fn check_attachment_constraints(
+ fn check_attachment_constraints<'a>(
&self,
attachment: &Option<WebGLFramebufferAttachment>,
- constraints: &[u32],
+ mut constraints: impl Iterator<Item = &'a u32>,
fb_size: &mut Option<(i32, i32)>,
) -> Result<(), u32> {
// Get the size of this attachment.
@@ -254,7 +260,7 @@ impl WebGLFramebuffer {
}
if let Some(format) = format {
- if constraints.iter().all(|c| *c != format) {
+ if constraints.all(|c| *c != format) {
return Err(constants::FRAMEBUFFER_INCOMPLETE_ATTACHMENT);
}
}
@@ -269,22 +275,6 @@ impl WebGLFramebuffer {
let has_z = z.is_some();
let has_s = s.is_some();
let has_zs = zs.is_some();
- let attachments = [&*z, &*s, &*zs];
- let attachment_constraints = [
- &[
- constants::DEPTH_COMPONENT16,
- constants::DEPTH_COMPONENT24,
- constants::DEPTH_COMPONENT32F,
- constants::DEPTH24_STENCIL8,
- constants::DEPTH32F_STENCIL8,
- ][..],
- &[
- constants::STENCIL_INDEX8,
- constants::DEPTH24_STENCIL8,
- constants::DEPTH32F_STENCIL8,
- ][..],
- &[constants::DEPTH_STENCIL][..],
- ];
let is_supported = match self.webgl_version {
// From the WebGL 1.0 spec, 6.6 ("Framebuffer Object Attachments"):
@@ -326,7 +316,38 @@ impl WebGLFramebuffer {
let mut fb_size = None;
- for (attachment, constraints) in attachments.iter().zip(&attachment_constraints) {
+ let attachments = [&*z, &*s, &*zs];
+ let webgl1_attachment_constraints = &[
+ &[
+ constants::DEPTH_COMPONENT16,
+ constants::DEPTH_COMPONENT24,
+ constants::DEPTH_COMPONENT32F,
+ constants::DEPTH24_STENCIL8,
+ constants::DEPTH32F_STENCIL8,
+ ][..],
+ &[
+ constants::STENCIL_INDEX8,
+ constants::DEPTH24_STENCIL8,
+ constants::DEPTH32F_STENCIL8,
+ ][..],
+ &[constants::DEPTH_STENCIL][..],
+ ];
+ let webgl2_attachment_constraints = &[
+ &[constants::DEPTH_STENCIL][..],
+ &[constants::DEPTH_STENCIL][..],
+ &[][..],
+ ];
+ let empty_attachment_constrains = &[&[][..], &[][..], &[][..]];
+ let extra_attachment_constraints = match self.webgl_version {
+ WebGLVersion::WebGL1 => empty_attachment_constrains,
+ WebGLVersion::WebGL2 => webgl2_attachment_constraints,
+ };
+ let attachment_constraints = webgl1_attachment_constraints
+ .iter()
+ .zip(extra_attachment_constraints.iter())
+ .map(|(a, b)| a.iter().chain(b.iter()));
+
+ for (attachment, constraints) in attachments.iter().zip(attachment_constraints) {
if let Err(errnum) =
self.check_attachment_constraints(attachment, constraints, &mut fb_size)
{
@@ -334,18 +355,79 @@ impl WebGLFramebuffer {
}
}
- let color_constraints = &[
- constants::RGBA4,
- constants::RGB5_A1,
+ let webgl1_color_constraints = &[
+ constants::RGB,
constants::RGB565,
+ constants::RGB5_A1,
constants::RGBA,
- constants::RGB,
+ constants::RGBA4,
][..];
+ let webgl2_color_constraints = &[
+ constants::ALPHA,
+ constants::LUMINANCE,
+ constants::LUMINANCE_ALPHA,
+ constants::R11F_G11F_B10F,
+ constants::R16F,
+ constants::R16I,
+ constants::R16UI,
+ constants::R32F,
+ constants::R32I,
+ constants::R32UI,
+ constants::R8,
+ constants::R8_SNORM,
+ constants::R8I,
+ constants::R8UI,
+ constants::RG16F,
+ constants::RG16I,
+ constants::RG16UI,
+ constants::RG32F,
+ constants::RG32I,
+ constants::RG32UI,
+ constants::RG8,
+ constants::RG8_SNORM,
+ constants::RG8I,
+ constants::RG8UI,
+ constants::RGB10_A2,
+ constants::RGB10_A2UI,
+ constants::RGB16F,
+ constants::RGB16I,
+ constants::RGB16UI,
+ constants::RGB32F,
+ constants::RGB32I,
+ constants::RGB32UI,
+ constants::RGB8,
+ constants::RGB8_SNORM,
+ constants::RGB8I,
+ constants::RGB8UI,
+ constants::RGB9_E5,
+ constants::RGBA16F,
+ constants::RGBA16I,
+ constants::RGBA16UI,
+ constants::RGBA32F,
+ constants::RGBA32I,
+ constants::RGBA32UI,
+ constants::RGBA8,
+ constants::RGBA8_SNORM,
+ constants::RGBA8I,
+ constants::RGBA8UI,
+ constants::SRGB8,
+ constants::SRGB8_ALPHA8,
+ ][..];
+ let empty_color_constrains = &[][..];
+ let extra_color_constraints = match self.webgl_version {
+ WebGLVersion::WebGL1 => empty_color_constrains,
+ WebGLVersion::WebGL2 => webgl2_color_constraints,
+ };
+ let color_constraints = webgl1_color_constraints
+ .iter()
+ .chain(extra_color_constraints.iter());
+
let has_c = self.colors.iter().any(|att| att.borrow().is_some());
for attachment in self.colors.iter() {
let attachment = attachment.borrow();
+ let constraints = color_constraints.clone();
if let Err(errnum) =
- self.check_attachment_constraints(&*attachment, color_constraints, &mut fb_size)
+ self.check_attachment_constraints(&*attachment, constraints, &mut fb_size)
{
return self.status.set(errnum);
}
@@ -392,7 +474,7 @@ impl WebGLFramebuffer {
return CompleteForRendering::Complete;
}
- if self.colors.iter().any(|att| att.borrow().is_none()) {
+ if self.colors.iter().all(|att| att.borrow().is_none()) {
return CompleteForRendering::MissingColorAttachment;
}
@@ -651,6 +733,61 @@ impl WebGLFramebuffer {
Ok(())
}
+ pub fn texture_layer(
+ &self,
+ attachment: u32,
+ texture: Option<&WebGLTexture>,
+ level: i32,
+ layer: i32,
+ ) -> WebGLResult<()> {
+ let binding = self
+ .attachment_binding(attachment)
+ .ok_or(WebGLError::InvalidEnum)?;
+
+ let context = self.upcast::<WebGLObject>().context();
+
+ let tex_id = match texture {
+ Some(texture) => {
+ let (max_level, max_layer) = match texture.target() {
+ Some(constants::TEXTURE_3D) => (
+ log2(context.limits().max_3d_texture_size),
+ context.limits().max_3d_texture_size - 1,
+ ),
+ Some(constants::TEXTURE_2D) => (
+ log2(context.limits().max_tex_size),
+ context.limits().max_array_texture_layers - 1,
+ ),
+ _ => return Err(WebGLError::InvalidOperation),
+ };
+
+ if level < 0 || level as u32 >= max_level {
+ return Err(WebGLError::InvalidValue);
+ }
+ if layer < 0 || layer as u32 >= max_layer {
+ return Err(WebGLError::InvalidValue);
+ }
+
+ *binding.borrow_mut() = Some(WebGLFramebufferAttachment::Texture {
+ texture: Dom::from_ref(texture),
+ level: level,
+ });
+ texture.attach_to_framebuffer(self);
+
+ Some(texture.id())
+ },
+ _ => None,
+ };
+
+ context.send_command(WebGLCommand::FramebufferTextureLayer(
+ self.target.get().unwrap(),
+ attachment,
+ tex_id,
+ level,
+ layer,
+ ));
+ Ok(())
+ }
+
fn with_matching_renderbuffers<F>(&self, rb: &WebGLRenderbuffer, mut closure: F)
where
F: FnMut(&DomRefCell<Option<WebGLFramebufferAttachment>>, u32),
@@ -781,6 +918,55 @@ impl WebGLFramebuffer {
});
}
+ pub fn set_read_buffer(&self, buffer: u32) -> WebGLResult<()> {
+ let context = self.upcast::<WebGLObject>().context();
+
+ match buffer {
+ constants::NONE => {},
+ _ if context.valid_color_attachment_enum(buffer) => {},
+ _ => return Err(WebGLError::InvalidOperation),
+ };
+
+ *self.color_read_buffer.borrow_mut() = buffer;
+ context.send_command(WebGLCommand::ReadBuffer(buffer));
+ Ok(())
+ }
+
+ pub fn set_draw_buffers(&self, buffers: Vec<u32>) -> WebGLResult<()> {
+ let context = self.upcast::<WebGLObject>().context();
+
+ if buffers.len() > context.limits().max_draw_buffers as usize {
+ return Err(WebGLError::InvalidValue);
+ }
+
+ let enums_valid = buffers
+ .iter()
+ .all(|&val| val == constants::NONE || context.valid_color_attachment_enum(val));
+ if !enums_valid {
+ return Err(WebGLError::InvalidEnum);
+ }
+
+ let values_valid = buffers.iter().enumerate().all(|(i, &val)| {
+ val == constants::NONE || val == (constants::COLOR_ATTACHMENT0 + i as u32)
+ });
+ if !values_valid {
+ return Err(WebGLError::InvalidOperation);
+ }
+
+ *self.color_draw_buffers.borrow_mut() = buffers.clone();
+ context.send_command(WebGLCommand::DrawBuffers(buffers));
+ Ok(())
+ }
+
+ pub fn read_buffer(&self) -> u32 {
+ *self.color_read_buffer.borrow()
+ }
+
+ pub fn draw_buffer_i(&self, index: usize) -> u32 {
+ let buffers = &*self.color_draw_buffers.borrow();
+ *buffers.get(index).unwrap_or(&constants::NONE)
+ }
+
pub fn target(&self) -> Option<u32> {
self.target.get()
}
diff --git a/components/script/dom/webglprogram.rs b/components/script/dom/webglprogram.rs
index 556573aae2e..4bb59fb1428 100644
--- a/components/script/dom/webglprogram.rs
+++ b/components/script/dom/webglprogram.rs
@@ -365,6 +365,30 @@ impl WebGLProgram {
Ok(location)
}
+ /// glGetFragDataLocation
+ pub fn get_frag_data_location(&self, name: DOMString) -> WebGLResult<i32> {
+ if !self.is_linked() || self.is_deleted() {
+ return Err(WebGLError::InvalidOperation);
+ }
+
+ if !validate_glsl_name(&name)? {
+ return Ok(-1);
+ }
+ if name.starts_with("gl_") {
+ return Ok(-1);
+ }
+
+ let (sender, receiver) = webgl_channel().unwrap();
+ self.upcast::<WebGLObject>()
+ .context()
+ .send_command(WebGLCommand::GetFragDataLocation(
+ self.id,
+ name.into(),
+ sender,
+ ));
+ Ok(receiver.recv().unwrap())
+ }
+
/// glGetUniformLocation
pub fn get_uniform_location(
&self,
diff --git a/components/script/dom/webglrenderbuffer.rs b/components/script/dom/webglrenderbuffer.rs
index 9c173d20241..71e56bac1d3 100644
--- a/components/script/dom/webglrenderbuffer.rs
+++ b/components/script/dom/webglrenderbuffer.rs
@@ -14,7 +14,8 @@ use crate::dom::webglframebuffer::WebGLFramebuffer;
use crate::dom::webglobject::WebGLObject;
use crate::dom::webglrenderingcontext::WebGLRenderingContext;
use canvas_traits::webgl::{
- webgl_channel, GlType, WebGLCommand, WebGLError, WebGLRenderbufferId, WebGLResult, WebGLVersion,
+ webgl_channel, GlType, InternalFormatIntVec, WebGLCommand, WebGLError, WebGLRenderbufferId,
+ WebGLResult, WebGLVersion,
};
use dom_struct::dom_struct;
use std::cell::Cell;
@@ -133,11 +134,13 @@ impl WebGLRenderbuffer {
pub fn storage(
&self,
api_type: GlType,
+ sample_count: i32,
internal_format: u32,
width: i32,
height: i32,
) -> WebGLResult<()> {
let is_gles = api_type == GlType::Gles;
+ let webgl_version = self.upcast().context().webgl_version();
// Validate the internal_format, and save it for completeness
// validation.
@@ -145,10 +148,35 @@ impl WebGLRenderbuffer {
constants::RGBA4 | constants::DEPTH_COMPONENT16 | constants::STENCIL_INDEX8 => {
internal_format
},
+ constants::R8 |
+ constants::R8UI |
+ constants::R8I |
+ constants::R16UI |
+ constants::R16I |
+ constants::R32UI |
+ constants::R32I |
+ constants::RG8 |
+ constants::RG8UI |
+ constants::RG8I |
+ constants::RG16UI |
+ constants::RG16I |
+ constants::RG32UI |
+ constants::RG32I |
+ constants::RGB8 |
+ constants::RGBA8 |
+ constants::SRGB8_ALPHA8 |
+ constants::RGB10_A2 |
+ constants::RGBA8UI |
+ constants::RGBA8I |
+ constants::RGB10_A2UI |
+ constants::RGBA16UI |
+ constants::RGBA16I |
+ constants::RGBA32I |
+ constants::RGBA32UI |
constants::DEPTH_COMPONENT24 |
constants::DEPTH_COMPONENT32F |
constants::DEPTH24_STENCIL8 |
- constants::DEPTH32F_STENCIL8 => match self.upcast().context().webgl_version() {
+ constants::DEPTH32F_STENCIL8 => match webgl_version {
WebGLVersion::WebGL1 => return Err(WebGLError::InvalidEnum),
_ => internal_format,
},
@@ -196,6 +224,22 @@ impl WebGLRenderbuffer {
_ => return Err(WebGLError::InvalidEnum),
};
+ if webgl_version != WebGLVersion::WebGL1 {
+ let (sender, receiver) = webgl_channel().unwrap();
+ self.upcast::<WebGLObject>().context().send_command(
+ WebGLCommand::GetInternalFormatIntVec(
+ constants::RENDERBUFFER,
+ internal_format,
+ InternalFormatIntVec::Samples,
+ sender,
+ ),
+ );
+ let samples = receiver.recv().unwrap();
+ if sample_count < 0 || sample_count as usize > samples.len() {
+ return Err(WebGLError::InvalidOperation);
+ }
+ }
+
self.internal_format.set(Some(internal_format));
self.is_initialized.set(false);
@@ -203,17 +247,24 @@ impl WebGLRenderbuffer {
fb.update_status();
}
- self.upcast::<WebGLObject>()
- .context()
- .send_command(WebGLCommand::RenderbufferStorage(
+ let command = match sample_count {
+ 0 => WebGLCommand::RenderbufferStorage(
constants::RENDERBUFFER,
actual_format,
width,
height,
- ));
+ ),
+ _ => WebGLCommand::RenderbufferStorageMultisample(
+ constants::RENDERBUFFER,
+ sample_count,
+ actual_format,
+ width,
+ height,
+ ),
+ };
+ self.upcast::<WebGLObject>().context().send_command(command);
self.size.set(Some((width, height)));
-
Ok(())
}
diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs
index ca5c08b25e3..25e5bf4baa1 100644
--- a/components/script/dom/webglrenderingcontext.rs
+++ b/components/script/dom/webglrenderingcontext.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::Ref;
use crate::dom::bindings::codegen::Bindings::ANGLEInstancedArraysBinding::ANGLEInstancedArraysConstants;
use crate::dom::bindings::codegen::Bindings::EXTBlendMinmaxBinding::EXTBlendMinmaxConstants;
use crate::dom::bindings::codegen::Bindings::OESVertexArrayObjectBinding::OESVertexArrayObjectConstants;
@@ -26,6 +27,7 @@ use crate::dom::htmlcanvaselement::HTMLCanvasElement;
use crate::dom::htmliframeelement::HTMLIFrameElement;
use crate::dom::node::{document_from_node, window_from_node, Node, NodeDamage};
use crate::dom::promise::Promise;
+use crate::dom::vertexarrayobject::VertexAttribData;
use crate::dom::webgl_extensions::WebGLExtensions;
use crate::dom::webgl_validations::tex_image_2d::{
CommonCompressedTexImage2DValidatorResult, CommonTexImage2DValidator,
@@ -47,6 +49,7 @@ use crate::dom::webglshader::WebGLShader;
use crate::dom::webglshaderprecisionformat::WebGLShaderPrecisionFormat;
use crate::dom::webgltexture::{TexParameterValue, WebGLTexture};
use crate::dom::webgluniformlocation::WebGLUniformLocation;
+use crate::dom::webglvertexarrayobject::WebGLVertexArrayObject;
use crate::dom::webglvertexarrayobjectoes::WebGLVertexArrayObjectOES;
use crate::dom::window::Window;
use crate::script_runtime::JSContext as SafeJSContext;
@@ -81,6 +84,7 @@ use std::cell::Cell;
use std::cmp;
use std::ptr::{self, NonNull};
use std::rc::Rc;
+use webxr_api::SessionId;
use webxr_api::SwapChainId as WebXRSwapChainId;
// From the GLES 2.0.25 spec, page 85:
@@ -182,6 +186,8 @@ pub struct WebGLRenderingContext {
capabilities: Capabilities,
default_vao: DomOnceCell<WebGLVertexArrayObjectOES>,
current_vao: MutNullableDom<WebGLVertexArrayObjectOES>,
+ default_vao_webgl2: DomOnceCell<WebGLVertexArrayObject>,
+ current_vao_webgl2: MutNullableDom<WebGLVertexArrayObject>,
textures: Textures,
api_type: GlType,
}
@@ -241,6 +247,8 @@ impl WebGLRenderingContext {
capabilities: Default::default(),
default_vao: Default::default(),
current_vao: Default::default(),
+ default_vao_webgl2: Default::default(),
+ current_vao_webgl2: Default::default(),
textures: Textures::new(max_combined_texture_image_units),
api_type: ctx_data.api_type,
}
@@ -293,6 +301,15 @@ impl WebGLRenderingContext {
})
}
+ pub fn current_vao_webgl2(&self) -> DomRoot<WebGLVertexArrayObject> {
+ self.current_vao_webgl2.or_init(|| {
+ DomRoot::from_ref(
+ self.default_vao_webgl2
+ .init_once(|| WebGLVertexArrayObject::new(self, None)),
+ )
+ })
+ }
+
pub fn recreate(&self, size: Size2D<u32>) {
let (sender, receiver) = webgl_channel().unwrap();
self.webgl_sender.send_resize(size, sender).unwrap();
@@ -888,11 +905,18 @@ impl WebGLRenderingContext {
0
};
- self.current_vao().validate_for_draw(
- required_len,
- primcount as u32,
- &current_program.active_attribs(),
- )?;
+ match self.webgl_version() {
+ WebGLVersion::WebGL1 => self.current_vao().validate_for_draw(
+ required_len,
+ primcount as u32,
+ &current_program.active_attribs(),
+ )?,
+ WebGLVersion::WebGL2 => self.current_vao_webgl2().validate_for_draw(
+ required_len,
+ primcount as u32,
+ &current_program.active_attribs(),
+ )?,
+ };
self.validate_framebuffer()?;
@@ -949,11 +973,11 @@ impl WebGLRenderingContext {
}
let current_program = self.current_program.get().ok_or(InvalidOperation)?;
- let array_buffer = self
- .current_vao()
- .element_array_buffer()
- .get()
- .ok_or(InvalidOperation)?;
+ let array_buffer = match self.webgl_version() {
+ WebGLVersion::WebGL1 => self.current_vao().element_array_buffer().get(),
+ WebGLVersion::WebGL2 => self.current_vao_webgl2().element_array_buffer().get(),
+ }
+ .ok_or(InvalidOperation)?;
if count > 0 && primcount > 0 {
// This operation cannot overflow in u64 and we know all those values are nonnegative.
@@ -964,11 +988,18 @@ impl WebGLRenderingContext {
}
// TODO(nox): Pass the correct number of vertices required.
- self.current_vao().validate_for_draw(
- 0,
- primcount as u32,
- &current_program.active_attribs(),
- )?;
+ match self.webgl_version() {
+ WebGLVersion::WebGL1 => self.current_vao().validate_for_draw(
+ 0,
+ primcount as u32,
+ &current_program.active_attribs(),
+ )?,
+ WebGLVersion::WebGL2 => self.current_vao_webgl2().validate_for_draw(
+ 0,
+ primcount as u32,
+ &current_program.active_attribs(),
+ )?,
+ };
self.validate_framebuffer()?;
@@ -1002,7 +1033,12 @@ impl WebGLRenderingContext {
return self.webgl_error(InvalidValue);
}
- self.current_vao().vertex_attrib_divisor(index, divisor);
+ match self.webgl_version() {
+ WebGLVersion::WebGL1 => self.current_vao().vertex_attrib_divisor(index, divisor),
+ WebGLVersion::WebGL2 => self
+ .current_vao_webgl2()
+ .vertex_attrib_divisor(index, divisor),
+ };
self.send_command(WebGLCommand::VertexAttribDivisor { index, divisor });
}
@@ -1065,6 +1101,15 @@ impl WebGLRenderingContext {
.map(|id| WebGLVertexArrayObjectOES::new(self, Some(id)))
}
+ pub fn create_vertex_array_webgl2(&self) -> Option<DomRoot<WebGLVertexArrayObject>> {
+ let (sender, receiver) = webgl_channel().unwrap();
+ self.send_command(WebGLCommand::CreateVertexArray(sender));
+ receiver
+ .recv()
+ .unwrap()
+ .map(|id| WebGLVertexArrayObject::new(self, Some(id)))
+ }
+
pub fn delete_vertex_array(&self, vao: Option<&WebGLVertexArrayObjectOES>) {
if let Some(vao) = vao {
handle_potential_webgl_error!(self, self.validate_ownership(vao), return);
@@ -1083,6 +1128,24 @@ impl WebGLRenderingContext {
}
}
+ pub fn delete_vertex_array_webgl2(&self, vao: Option<&WebGLVertexArrayObject>) {
+ if let Some(vao) = vao {
+ handle_potential_webgl_error!(self, self.validate_ownership(vao), return);
+ // The default vertex array has no id and should never be passed around.
+ assert!(vao.id().is_some());
+ if vao.is_deleted() {
+ return;
+ }
+ if vao == &*self.current_vao_webgl2() {
+ // Setting it to None will make self.current_vao() reset it to the default one
+ // next time it is called.
+ self.current_vao_webgl2.set(None);
+ self.send_command(WebGLCommand::BindVertexArray(None));
+ }
+ vao.delete(false);
+ }
+ }
+
pub fn is_vertex_array(&self, vao: Option<&WebGLVertexArrayObjectOES>) -> bool {
vao.map_or(false, |vao| {
// The default vertex array has no id and should never be passed around.
@@ -1091,6 +1154,14 @@ impl WebGLRenderingContext {
})
}
+ pub fn is_vertex_array_webgl2(&self, vao: Option<&WebGLVertexArrayObject>) -> bool {
+ vao.map_or(false, |vao| {
+ // The default vertex array has no id and should never be passed around.
+ assert!(vao.id().is_some());
+ self.validate_ownership(vao).is_ok() && vao.ever_bound() && !vao.is_deleted()
+ })
+ }
+
pub fn bind_vertex_array(&self, vao: Option<&WebGLVertexArrayObjectOES>) {
if let Some(vao) = vao {
// The default vertex array has no id and should never be passed around.
@@ -1107,6 +1178,22 @@ impl WebGLRenderingContext {
self.current_vao.set(vao);
}
+ pub fn bind_vertex_array_webgl2(&self, vao: Option<&WebGLVertexArrayObject>) {
+ if let Some(vao) = vao {
+ // The default vertex array has no id and should never be passed around.
+ assert!(vao.id().is_some());
+ handle_potential_webgl_error!(self, self.validate_ownership(vao), return);
+ if vao.is_deleted() {
+ return self.webgl_error(InvalidOperation);
+ }
+ vao.set_ever_bound();
+ }
+ self.send_command(WebGLCommand::BindVertexArray(vao.and_then(|vao| vao.id())));
+ // Setting it to None will make self.current_vao() reset it to the default one
+ // next time it is called.
+ self.current_vao_webgl2.set(vao);
+ }
+
fn validate_blend_mode(&self, mode: u32) -> WebGLResult<()> {
match mode {
constants::FUNC_ADD | constants::FUNC_SUBTRACT | constants::FUNC_REVERSE_SUBTRACT => {
@@ -1389,6 +1476,45 @@ impl WebGLRenderingContext {
}
slot.set(framebuffer);
}
+
+ pub fn renderbuffer_storage(
+ &self,
+ target: u32,
+ samples: i32,
+ internal_format: u32,
+ width: i32,
+ height: i32,
+ ) {
+ if target != constants::RENDERBUFFER {
+ return self.webgl_error(InvalidEnum);
+ }
+
+ let max = self.limits.max_renderbuffer_size;
+
+ if samples < 0 || width < 0 || width as u32 > max || height < 0 || height as u32 > max {
+ return self.webgl_error(InvalidValue);
+ }
+
+ let rb = handle_potential_webgl_error!(
+ self,
+ self.bound_renderbuffer.get().ok_or(InvalidOperation),
+ return
+ );
+ handle_potential_webgl_error!(
+ self,
+ rb.storage(self.api_type, samples, internal_format, width, height)
+ );
+ if let Some(fb) = self.bound_draw_framebuffer.get() {
+ fb.invalidate_renderbuffer(&*rb);
+ }
+
+ // FIXME: https://github.com/servo/servo/issues/13710
+ }
+
+ pub fn valid_color_attachment_enum(&self, attachment: u32) -> bool {
+ let last_slot = constants::COLOR_ATTACHMENT0 + self.limits().max_color_attachments - 1;
+ constants::COLOR_ATTACHMENT0 <= attachment && attachment <= last_slot
+ }
}
#[cfg(not(feature = "webgl_backtrace"))]
@@ -2551,9 +2677,14 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
if attrib_id >= self.limits.max_vertex_attribs {
return self.webgl_error(InvalidValue);
}
-
- self.current_vao()
- .enabled_vertex_attrib_array(attrib_id, true);
+ match self.webgl_version() {
+ WebGLVersion::WebGL1 => self
+ .current_vao()
+ .enabled_vertex_attrib_array(attrib_id, true),
+ WebGLVersion::WebGL2 => self
+ .current_vao_webgl2()
+ .enabled_vertex_attrib_array(attrib_id, true),
+ };
self.send_command(WebGLCommand::EnableVertexAttribArray(attrib_id));
}
@@ -2562,9 +2693,14 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
if attrib_id >= self.limits.max_vertex_attribs {
return self.webgl_error(InvalidValue);
}
-
- self.current_vao()
- .enabled_vertex_attrib_array(attrib_id, false);
+ match self.webgl_version() {
+ WebGLVersion::WebGL1 => self
+ .current_vao()
+ .enabled_vertex_attrib_array(attrib_id, false),
+ WebGLVersion::WebGL2 => self
+ .current_vao_webgl2()
+ .enabled_vertex_attrib_array(attrib_id, false),
+ };
self.send_command(WebGLCommand::DisableVertexAttribArray(attrib_id));
}
@@ -2889,56 +3025,73 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
#[allow(unsafe_code)]
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9
fn GetVertexAttrib(&self, cx: SafeJSContext, index: u32, param: u32) -> JSVal {
- let current_vao = self.current_vao();
- let data = handle_potential_webgl_error!(
- self,
- current_vao.get_vertex_attrib(index).ok_or(InvalidValue),
- return NullValue()
- );
- if param == constants::CURRENT_VERTEX_ATTRIB {
- let value = if index == 0 {
- let (x, y, z, w) = self.current_vertex_attrib_0.get();
- [x, y, z, w]
- } else {
- let (sender, receiver) = webgl_channel().unwrap();
- self.send_command(WebGLCommand::GetCurrentVertexAttrib(index, sender));
- receiver.recv().unwrap()
- };
- unsafe {
- rooted!(in(*cx) let mut result = ptr::null_mut::<JSObject>());
- let _ = Float32Array::create(*cx, CreateWith::Slice(&value), result.handle_mut())
- .unwrap();
- return ObjectValue(result.get());
+ let get_attrib = |data: Ref<VertexAttribData>| -> JSVal {
+ if param == constants::CURRENT_VERTEX_ATTRIB {
+ let value = if index == 0 {
+ let (x, y, z, w) = self.current_vertex_attrib_0.get();
+ [x, y, z, w]
+ } else {
+ let (sender, receiver) = webgl_channel().unwrap();
+ self.send_command(WebGLCommand::GetCurrentVertexAttrib(index, sender));
+ receiver.recv().unwrap()
+ };
+ unsafe {
+ rooted!(in(*cx) let mut result = ptr::null_mut::<JSObject>());
+ let _ =
+ Float32Array::create(*cx, CreateWith::Slice(&value), result.handle_mut())
+ .unwrap();
+ return ObjectValue(result.get());
+ }
+ }
+ if !self
+ .extension_manager
+ .is_get_vertex_attrib_name_enabled(param)
+ {
+ self.webgl_error(WebGLError::InvalidEnum);
+ return NullValue();
}
- }
- if !self
- .extension_manager
- .is_get_vertex_attrib_name_enabled(param)
- {
- self.webgl_error(WebGLError::InvalidEnum);
- return NullValue();
- }
+ match param {
+ constants::VERTEX_ATTRIB_ARRAY_ENABLED => BooleanValue(data.enabled_as_array),
+ constants::VERTEX_ATTRIB_ARRAY_SIZE => Int32Value(data.size as i32),
+ constants::VERTEX_ATTRIB_ARRAY_TYPE => Int32Value(data.type_ as i32),
+ constants::VERTEX_ATTRIB_ARRAY_NORMALIZED => BooleanValue(data.normalized),
+ constants::VERTEX_ATTRIB_ARRAY_STRIDE => Int32Value(data.stride as i32),
+ constants::VERTEX_ATTRIB_ARRAY_BUFFER_BINDING => unsafe {
+ rooted!(in(*cx) let mut jsval = NullValue());
+ if let Some(buffer) = data.buffer() {
+ buffer.to_jsval(*cx, jsval.handle_mut());
+ }
+ jsval.get()
+ },
+ ANGLEInstancedArraysConstants::VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE => {
+ UInt32Value(data.divisor)
+ },
+ _ => {
+ self.webgl_error(InvalidEnum);
+ NullValue()
+ },
+ }
+ };
- match param {
- constants::VERTEX_ATTRIB_ARRAY_ENABLED => BooleanValue(data.enabled_as_array),
- constants::VERTEX_ATTRIB_ARRAY_SIZE => Int32Value(data.size as i32),
- constants::VERTEX_ATTRIB_ARRAY_TYPE => Int32Value(data.type_ as i32),
- constants::VERTEX_ATTRIB_ARRAY_NORMALIZED => BooleanValue(data.normalized),
- constants::VERTEX_ATTRIB_ARRAY_STRIDE => Int32Value(data.stride as i32),
- constants::VERTEX_ATTRIB_ARRAY_BUFFER_BINDING => unsafe {
- rooted!(in(*cx) let mut jsval = NullValue());
- if let Some(buffer) = data.buffer() {
- buffer.to_jsval(*cx, jsval.handle_mut());
- }
- jsval.get()
- },
- ANGLEInstancedArraysConstants::VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE => {
- UInt32Value(data.divisor)
+ match self.webgl_version() {
+ WebGLVersion::WebGL1 => {
+ let current_vao = self.current_vao();
+ let data = handle_potential_webgl_error!(
+ self,
+ current_vao.get_vertex_attrib(index).ok_or(InvalidValue),
+ return NullValue()
+ );
+ get_attrib(data)
},
- _ => {
- self.webgl_error(InvalidEnum);
- NullValue()
+ WebGLVersion::WebGL2 => {
+ let current_vao = self.current_vao_webgl2();
+ let data = handle_potential_webgl_error!(
+ self,
+ current_vao.get_vertex_attrib(index).ok_or(InvalidValue),
+ return NullValue()
+ );
+ get_attrib(data)
},
}
}
@@ -2949,13 +3102,26 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
self.webgl_error(InvalidEnum);
return 0;
}
- let vao = self.current_vao();
- let data = handle_potential_webgl_error!(
- self,
- vao.get_vertex_attrib(index).ok_or(InvalidValue),
- return 0
- );
- data.offset as i64
+ match self.webgl_version() {
+ WebGLVersion::WebGL1 => {
+ let current_vao = self.current_vao();
+ let data = handle_potential_webgl_error!(
+ self,
+ current_vao.get_vertex_attrib(index).ok_or(InvalidValue),
+ return 0
+ );
+ data.offset as i64
+ },
+ WebGLVersion::WebGL2 => {
+ let current_vao = self.current_vao_webgl2();
+ let data = handle_potential_webgl_error!(
+ self,
+ current_vao.get_vertex_attrib(index).ok_or(InvalidValue),
+ return 0
+ );
+ data.offset as i64
+ },
+ }
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3
@@ -3818,11 +3984,15 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
stride: i32,
offset: i64,
) {
- handle_potential_webgl_error!(
- self,
- self.current_vao()
- .vertex_attrib_pointer(index, size, type_, normalized, stride, offset)
- );
+ let res = match self.webgl_version() {
+ WebGLVersion::WebGL1 => self
+ .current_vao()
+ .vertex_attrib_pointer(index, size, type_, normalized, stride, offset),
+ WebGLVersion::WebGL2 => self
+ .current_vao_webgl2()
+ .vertex_attrib_pointer(index, size, type_, normalized, stride, offset),
+ };
+ handle_potential_webgl_error!(self, res);
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.4
@@ -4205,30 +4375,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.7
fn RenderbufferStorage(&self, target: u32, internal_format: u32, width: i32, height: i32) {
- if target != constants::RENDERBUFFER {
- return self.webgl_error(InvalidEnum);
- }
-
- let max = self.limits.max_renderbuffer_size;
-
- if width < 0 || width as u32 > max || height < 0 || height as u32 > max {
- return self.webgl_error(InvalidValue);
- }
-
- let rb = handle_potential_webgl_error!(
- self,
- self.bound_renderbuffer.get().ok_or(InvalidOperation),
- return
- );
- handle_potential_webgl_error!(
- self,
- rb.storage(self.api_type, internal_format, width, height)
- );
- if let Some(fb) = self.bound_draw_framebuffer.get() {
- fb.invalidate_renderbuffer(&*rb);
- }
-
- // FIXME: https://github.com/servo/servo/issues/13710
+ self.renderbuffer_storage(target, 0, internal_format, width, height)
}
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.6
@@ -4576,8 +4723,9 @@ impl WebGLMessageSender {
&self,
size: Size2D<i32>,
sender: WebGLSender<Option<WebXRSwapChainId>>,
+ id: SessionId,
) -> WebGLSendResult {
- self.wake_after_send(|| self.sender.send_create_webxr_swap_chain(size, sender))
+ self.wake_after_send(|| self.sender.send_create_webxr_swap_chain(size, sender, id))
}
pub fn send_resize(
diff --git a/components/script/dom/webglvertexarrayobject.rs b/components/script/dom/webglvertexarrayobject.rs
new file mode 100644
index 00000000000..48355d05557
--- /dev/null
+++ b/components/script/dom/webglvertexarrayobject.rs
@@ -0,0 +1,100 @@
+/* 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::Ref;
+use crate::dom::bindings::codegen::Bindings::WebGLVertexArrayObjectBinding;
+use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
+use crate::dom::bindings::root::{DomRoot, MutNullableDom};
+use crate::dom::vertexarrayobject::{VertexArrayObject, VertexAttribData};
+use crate::dom::webglbuffer::WebGLBuffer;
+use crate::dom::webglobject::WebGLObject;
+use crate::dom::webglrenderingcontext::WebGLRenderingContext;
+use canvas_traits::webgl::{ActiveAttribInfo, WebGLResult, WebGLVertexArrayId};
+use dom_struct::dom_struct;
+
+#[dom_struct]
+pub struct WebGLVertexArrayObject {
+ webgl_object_: WebGLObject,
+ array_object: VertexArrayObject,
+}
+
+impl WebGLVertexArrayObject {
+ fn new_inherited(context: &WebGLRenderingContext, id: Option<WebGLVertexArrayId>) -> Self {
+ Self {
+ webgl_object_: WebGLObject::new_inherited(context),
+ array_object: VertexArrayObject::new(context, id),
+ }
+ }
+
+ pub fn new(context: &WebGLRenderingContext, id: Option<WebGLVertexArrayId>) -> DomRoot<Self> {
+ reflect_dom_object(
+ Box::new(WebGLVertexArrayObject::new_inherited(context, id)),
+ &*context.global(),
+ WebGLVertexArrayObjectBinding::Wrap,
+ )
+ }
+
+ pub fn id(&self) -> Option<WebGLVertexArrayId> {
+ self.array_object.id()
+ }
+
+ pub fn is_deleted(&self) -> bool {
+ self.array_object.is_deleted()
+ }
+
+ pub fn delete(&self, fallible: bool) {
+ self.array_object.delete(fallible);
+ }
+
+ pub fn ever_bound(&self) -> bool {
+ self.array_object.ever_bound()
+ }
+
+ pub fn set_ever_bound(&self) {
+ self.array_object.set_ever_bound();
+ }
+
+ pub fn element_array_buffer(&self) -> &MutNullableDom<WebGLBuffer> {
+ self.array_object.element_array_buffer()
+ }
+
+ pub fn get_vertex_attrib(&self, index: u32) -> Option<Ref<VertexAttribData>> {
+ self.array_object.get_vertex_attrib(index)
+ }
+
+ pub fn vertex_attrib_pointer(
+ &self,
+ index: u32,
+ size: i32,
+ type_: u32,
+ normalized: bool,
+ stride: i32,
+ offset: i64,
+ ) -> WebGLResult<()> {
+ self.array_object
+ .vertex_attrib_pointer(index, size, type_, normalized, stride, offset)
+ }
+
+ pub fn vertex_attrib_divisor(&self, index: u32, value: u32) {
+ self.array_object.vertex_attrib_divisor(index, value);
+ }
+
+ pub fn enabled_vertex_attrib_array(&self, index: u32, value: bool) {
+ self.array_object.enabled_vertex_attrib_array(index, value);
+ }
+
+ pub fn unbind_buffer(&self, buffer: &WebGLBuffer) {
+ self.array_object.unbind_buffer(buffer);
+ }
+
+ pub fn validate_for_draw(
+ &self,
+ required_len: u32,
+ instance_count: u32,
+ active_attribs: &[ActiveAttribInfo],
+ ) -> WebGLResult<()> {
+ self.array_object
+ .validate_for_draw(required_len, instance_count, active_attribs)
+ }
+}
diff --git a/components/script/dom/webglvertexarrayobjectoes.rs b/components/script/dom/webglvertexarrayobjectoes.rs
index 1d802968ae1..2c03f084031 100644
--- a/components/script/dom/webglvertexarrayobjectoes.rs
+++ b/components/script/dom/webglvertexarrayobjectoes.rs
@@ -2,41 +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::cell::{ref_filter_map, DomRefCell, Ref};
-use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants;
+use crate::dom::bindings::cell::Ref;
use crate::dom::bindings::codegen::Bindings::WebGLVertexArrayObjectOESBinding;
-use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
-use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
+use crate::dom::bindings::root::{DomRoot, MutNullableDom};
+use crate::dom::vertexarrayobject::{VertexArrayObject, VertexAttribData};
use crate::dom::webglbuffer::WebGLBuffer;
use crate::dom::webglobject::WebGLObject;
use crate::dom::webglrenderingcontext::WebGLRenderingContext;
-use canvas_traits::webgl::{
- ActiveAttribInfo, WebGLCommand, WebGLError, WebGLResult, WebGLVertexArrayId,
-};
+use canvas_traits::webgl::{ActiveAttribInfo, WebGLResult, WebGLVertexArrayId};
use dom_struct::dom_struct;
-use std::cell::Cell;
#[dom_struct]
pub struct WebGLVertexArrayObjectOES {
webgl_object_: WebGLObject,
- id: Option<WebGLVertexArrayId>,
- ever_bound: Cell<bool>,
- is_deleted: Cell<bool>,
- vertex_attribs: DomRefCell<Box<[VertexAttribData]>>,
- element_array_buffer: MutNullableDom<WebGLBuffer>,
+ array_object: VertexArrayObject,
}
impl WebGLVertexArrayObjectOES {
fn new_inherited(context: &WebGLRenderingContext, id: Option<WebGLVertexArrayId>) -> Self {
- let max_vertex_attribs = context.limits().max_vertex_attribs as usize;
Self {
webgl_object_: WebGLObject::new_inherited(context),
- id,
- ever_bound: Default::default(),
- is_deleted: Default::default(),
- vertex_attribs: DomRefCell::new(vec![Default::default(); max_vertex_attribs].into()),
- element_array_buffer: Default::default(),
+ array_object: VertexArrayObject::new(context, id),
}
}
@@ -49,54 +36,31 @@ impl WebGLVertexArrayObjectOES {
}
pub fn id(&self) -> Option<WebGLVertexArrayId> {
- self.id
+ self.array_object.id()
}
pub fn is_deleted(&self) -> bool {
- self.is_deleted.get()
+ self.array_object.is_deleted()
}
pub fn delete(&self, fallible: bool) {
- assert!(self.id.is_some());
- if self.is_deleted.get() {
- return;
- }
- self.is_deleted.set(true);
-
- let context = self.upcast::<WebGLObject>().context();
- let cmd = WebGLCommand::DeleteVertexArray(self.id.unwrap());
- if fallible {
- context.send_command_ignored(cmd);
- } else {
- context.send_command(cmd);
- }
-
- for attrib_data in &**self.vertex_attribs.borrow() {
- if let Some(buffer) = attrib_data.buffer() {
- buffer.decrement_attached_counter();
- }
- }
- if let Some(buffer) = self.element_array_buffer.get() {
- buffer.decrement_attached_counter();
- }
+ self.array_object.delete(fallible);
}
pub fn ever_bound(&self) -> bool {
- return self.ever_bound.get();
+ self.array_object.ever_bound()
}
pub fn set_ever_bound(&self) {
- self.ever_bound.set(true);
+ self.array_object.set_ever_bound();
}
pub fn element_array_buffer(&self) -> &MutNullableDom<WebGLBuffer> {
- &self.element_array_buffer
+ self.array_object.element_array_buffer()
}
pub fn get_vertex_attrib(&self, index: u32) -> Option<Ref<VertexAttribData>> {
- ref_filter_map(self.vertex_attribs.borrow(), |attribs| {
- attribs.get(index as usize)
- })
+ self.array_object.get_vertex_attrib(index)
}
pub fn vertex_attrib_pointer(
@@ -108,93 +72,20 @@ impl WebGLVertexArrayObjectOES {
stride: i32,
offset: i64,
) -> WebGLResult<()> {
- let mut attribs = self.vertex_attribs.borrow_mut();
- let data = attribs
- .get_mut(index as usize)
- .ok_or(WebGLError::InvalidValue)?;
-
- if size < 1 || size > 4 {
- return Err(WebGLError::InvalidValue);
- }
-
- // https://www.khronos.org/registry/webgl/specs/latest/1.0/#BUFFER_OFFSET_AND_STRIDE
- // https://www.khronos.org/registry/webgl/specs/latest/1.0/#VERTEX_STRIDE
- if stride < 0 || stride > 255 || offset < 0 {
- return Err(WebGLError::InvalidValue);
- }
- let bytes_per_component: i32 = match type_ {
- constants::BYTE | constants::UNSIGNED_BYTE => 1,
- constants::SHORT | constants::UNSIGNED_SHORT => 2,
- constants::FLOAT => 4,
- _ => return Err(WebGLError::InvalidEnum),
- };
- if offset % bytes_per_component as i64 > 0 || stride % bytes_per_component > 0 {
- return Err(WebGLError::InvalidOperation);
- }
-
- let context = self.upcast::<WebGLObject>().context();
- let buffer = context.array_buffer();
- match buffer {
- Some(ref buffer) => buffer.increment_attached_counter(),
- None if offset != 0 => {
- // https://github.com/KhronosGroup/WebGL/pull/2228
- return Err(WebGLError::InvalidOperation);
- },
- _ => {},
- }
- context.send_command(WebGLCommand::VertexAttribPointer(
- index,
- size,
- type_,
- normalized,
- stride,
- offset as u32,
- ));
- if let Some(old) = data.buffer() {
- old.decrement_attached_counter();
- }
-
- *data = VertexAttribData {
- enabled_as_array: data.enabled_as_array,
- size: size as u8,
- type_,
- bytes_per_vertex: size as u8 * bytes_per_component as u8,
- normalized,
- stride: stride as u8,
- offset: offset as u32,
- buffer: buffer.map(|b| Dom::from_ref(&*b)),
- divisor: data.divisor,
- };
-
- Ok(())
+ self.array_object
+ .vertex_attrib_pointer(index, size, type_, normalized, stride, offset)
}
pub fn vertex_attrib_divisor(&self, index: u32, value: u32) {
- self.vertex_attribs.borrow_mut()[index as usize].divisor = value;
+ self.array_object.vertex_attrib_divisor(index, value);
}
pub fn enabled_vertex_attrib_array(&self, index: u32, value: bool) {
- self.vertex_attribs.borrow_mut()[index as usize].enabled_as_array = value;
+ self.array_object.enabled_vertex_attrib_array(index, value);
}
pub fn unbind_buffer(&self, buffer: &WebGLBuffer) {
- for attrib in &mut **self.vertex_attribs.borrow_mut() {
- if let Some(b) = attrib.buffer() {
- if b.id() != buffer.id() {
- continue;
- }
- b.decrement_attached_counter();
- }
- attrib.buffer = None;
- }
- if self
- .element_array_buffer
- .get()
- .map_or(false, |b| buffer == &*b)
- {
- buffer.decrement_attached_counter();
- self.element_array_buffer.set(None);
- }
+ self.array_object.unbind_buffer(buffer);
}
pub fn validate_for_draw(
@@ -203,109 +94,7 @@ impl WebGLVertexArrayObjectOES {
instance_count: u32,
active_attribs: &[ActiveAttribInfo],
) -> WebGLResult<()> {
- // TODO(nox): Cache limits per VAO.
- let attribs = self.vertex_attribs.borrow();
- // https://www.khronos.org/registry/webgl/specs/latest/1.0/#6.2
- if attribs
- .iter()
- .any(|data| data.enabled_as_array && data.buffer.is_none())
- {
- return Err(WebGLError::InvalidOperation);
- }
- let mut has_active_attrib = false;
- let mut has_divisor_0 = false;
- for active_info in active_attribs {
- if active_info.location < 0 {
- continue;
- }
- has_active_attrib = true;
- let attrib = &attribs[active_info.location as usize];
- if attrib.divisor == 0 {
- has_divisor_0 = true;
- }
- if !attrib.enabled_as_array {
- continue;
- }
- // https://www.khronos.org/registry/webgl/specs/latest/1.0/#6.6
- if required_len > 0 && instance_count > 0 {
- let max_vertices = attrib.max_vertices();
- if attrib.divisor == 0 {
- if max_vertices < required_len {
- return Err(WebGLError::InvalidOperation);
- }
- } else if max_vertices
- .checked_mul(attrib.divisor)
- .map_or(false, |v| v < instance_count)
- {
- return Err(WebGLError::InvalidOperation);
- }
- }
- }
- if has_active_attrib && !has_divisor_0 {
- return Err(WebGLError::InvalidOperation);
- }
- Ok(())
- }
-}
-
-impl Drop for WebGLVertexArrayObjectOES {
- fn drop(&mut self) {
- if self.id.is_some() {
- self.delete(true);
- }
- }
-}
-
-#[derive(Clone, JSTraceable, MallocSizeOf)]
-#[unrooted_must_root_lint::must_root]
-pub struct VertexAttribData {
- pub enabled_as_array: bool,
- pub size: u8,
- pub type_: u32,
- bytes_per_vertex: u8,
- pub normalized: bool,
- pub stride: u8,
- pub offset: u32,
- pub buffer: Option<Dom<WebGLBuffer>>,
- pub divisor: u32,
-}
-
-impl Default for VertexAttribData {
- #[allow(unrooted_must_root)]
- fn default() -> Self {
- Self {
- enabled_as_array: false,
- size: 4,
- type_: constants::FLOAT,
- bytes_per_vertex: 16,
- normalized: false,
- stride: 0,
- offset: 0,
- buffer: None,
- divisor: 0,
- }
- }
-}
-
-impl VertexAttribData {
- pub fn buffer(&self) -> Option<&WebGLBuffer> {
- self.buffer.as_ref().map(|b| &**b)
- }
-
- fn max_vertices(&self) -> u32 {
- let capacity = (self.buffer().unwrap().capacity() as u32).saturating_sub(self.offset);
- if capacity < self.bytes_per_vertex as u32 {
- 0
- } else if self.stride == 0 {
- capacity / self.bytes_per_vertex as u32
- } else if self.stride < self.bytes_per_vertex {
- (capacity - (self.bytes_per_vertex - self.stride) as u32) / self.stride as u32
- } else {
- let mut max = capacity / self.stride as u32;
- if capacity % self.stride as u32 >= self.bytes_per_vertex as u32 {
- max += 1;
- }
- max
- }
+ self.array_object
+ .validate_for_draw(required_len, instance_count, active_attribs)
}
}
diff --git a/components/script/dom/webidls/BroadcastChannel.webidl b/components/script/dom/webidls/BroadcastChannel.webidl
new file mode 100644
index 00000000000..6d72f3997cf
--- /dev/null
+++ b/components/script/dom/webidls/BroadcastChannel.webidl
@@ -0,0 +1,18 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * The origin of this IDL file is:
+ * https://html.spec.whatwg.org/multipage/#broadcastchannel
+ */
+
+[Exposed=(Window,Worker)]
+interface BroadcastChannel : EventTarget {
+ constructor(DOMString name);
+
+ readonly attribute DOMString name;
+ [Throws] void postMessage(any message);
+ void close();
+ attribute EventHandler onmessage;
+ attribute EventHandler onmessageerror;
+};
diff --git a/components/script/dom/webidls/GPUBuffer.webidl b/components/script/dom/webidls/GPUBuffer.webidl
index 0b327bdcbd2..1688060b514 100644
--- a/components/script/dom/webidls/GPUBuffer.webidl
+++ b/components/script/dom/webidls/GPUBuffer.webidl
@@ -5,7 +5,7 @@
// https://gpuweb.github.io/gpuweb/#gpubuffer
[Exposed=(Window, DedicatedWorker), Serializable, Pref="dom.webgpu.enabled"]
interface GPUBuffer {
- // Promise<ArrayBuffer> mapReadAsync();
+ Promise<ArrayBuffer> mapReadAsync();
// Promise<ArrayBuffer> mapWriteAsync();
void unmap();
diff --git a/components/script/dom/webidls/HTMLElement.webidl b/components/script/dom/webidls/HTMLElement.webidl
index ef529dc80af..c743c0a7129 100644
--- a/components/script/dom/webidls/HTMLElement.webidl
+++ b/components/script/dom/webidls/HTMLElement.webidl
@@ -14,8 +14,8 @@ interface HTMLElement : Element {
attribute DOMString lang;
[CEReactions]
attribute boolean translate;
- // [CEReactions]
- // attribute DOMString dir;
+ [CEReactions]
+ attribute DOMString dir;
readonly attribute DOMStringMap dataset;
// microdata
diff --git a/components/script/dom/webidls/HTMLTextAreaElement.webidl b/components/script/dom/webidls/HTMLTextAreaElement.webidl
index 99cf18e0c10..b09200f1dc5 100644
--- a/components/script/dom/webidls/HTMLTextAreaElement.webidl
+++ b/components/script/dom/webidls/HTMLTextAreaElement.webidl
@@ -13,8 +13,8 @@ interface HTMLTextAreaElement : HTMLElement {
// attribute boolean autofocus;
[CEReactions, SetterThrows]
attribute unsigned long cols;
- // [CEReactions]
- // attribute DOMString dirName;
+ [CEReactions]
+ attribute DOMString dirName;
[CEReactions]
attribute boolean disabled;
readonly attribute HTMLFormElement? form;
diff --git a/components/script/dom/webidls/VTTCue.webidl b/components/script/dom/webidls/VTTCue.webidl
new file mode 100644
index 00000000000..073aa12f79b
--- /dev/null
+++ b/components/script/dom/webidls/VTTCue.webidl
@@ -0,0 +1,30 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+// https://w3c.github.io/webvtt/#the-vttcue-interface
+
+enum AutoKeyword { "auto"};
+typedef (double or AutoKeyword) LineAndPositionSetting;
+enum DirectionSetting { "" /* horizontal */, "rl", "lr" };
+enum LineAlignSetting { "start", "center", "end" };
+enum PositionAlignSetting { "line-left", "center", "line-right", "auto" };
+enum AlignSetting { "start", "center", "end", "left", "right" };
+
+[Pref="dom.webvtt.enabled", Exposed=Window]
+interface VTTCue : TextTrackCue {
+ constructor(double startTime, double endTime, DOMString text);
+ attribute VTTRegion? region;
+ attribute DirectionSetting vertical;
+ attribute boolean snapToLines;
+ attribute LineAndPositionSetting line;
+ attribute LineAlignSetting lineAlign;
+ [SetterThrows]
+ attribute LineAndPositionSetting position;
+ attribute PositionAlignSetting positionAlign;
+ [SetterThrows]
+ attribute double size;
+ attribute AlignSetting align;
+ attribute DOMString text;
+ DocumentFragment getCueAsHTML();
+};
diff --git a/components/script/dom/webidls/VTTRegion.webidl b/components/script/dom/webidls/VTTRegion.webidl
new file mode 100644
index 00000000000..12fbe16170b
--- /dev/null
+++ b/components/script/dom/webidls/VTTRegion.webidl
@@ -0,0 +1,26 @@
+/* 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://w3c.github.io/webvtt/#the-vttregion-interface
+
+enum ScrollSetting { "" /* none */, "up"};
+
+[Pref="dom.webvtt.enabled", Exposed=Window]
+interface VTTRegion {
+ [Throws] constructor();
+ attribute DOMString id;
+ [SetterThrows]
+ attribute double width;
+ [SetterThrows]
+ attribute unsigned long lines;
+ [SetterThrows]
+ attribute double regionAnchorX;
+ [SetterThrows]
+ attribute double regionAnchorY;
+ [SetterThrows]
+ attribute double viewportAnchorX;
+ [SetterThrows]
+ attribute double viewportAnchorY;
+ attribute ScrollSetting scroll;
+};
diff --git a/components/script/dom/webidls/WebGL2RenderingContext.webidl b/components/script/dom/webidls/WebGL2RenderingContext.webidl
index 23686adb211..dca86da39fe 100644
--- a/components/script/dom/webidls/WebGL2RenderingContext.webidl
+++ b/components/script/dom/webidls/WebGL2RenderingContext.webidl
@@ -11,10 +11,6 @@
typedef long long GLint64;
typedef unsigned long long GLuint64;
-
-// interface WebGLVertexArrayObject : WebGLObject {
-// };
-
typedef (/*[AllowShared]*/ Uint32Array or sequence<GLuint>) Uint32List;
interface mixin WebGL2RenderingContextBase
@@ -312,17 +308,17 @@ interface mixin WebGL2RenderingContextBase
/* Framebuffer objects */
// void blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0,
// GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
- // void framebufferTextureLayer(GLenum target, GLenum attachment, WebGLTexture? texture, GLint level,
- // GLint layer);
- // void invalidateFramebuffer(GLenum target, sequence<GLenum> attachments);
- // void invalidateSubFramebuffer(GLenum target, sequence<GLenum> attachments,
- // GLint x, GLint y, GLsizei width, GLsizei height);
- // void readBuffer(GLenum src);
+ void framebufferTextureLayer(GLenum target, GLenum attachment, WebGLTexture? texture, GLint level,
+ GLint layer);
+ void invalidateFramebuffer(GLenum target, sequence<GLenum> attachments);
+ void invalidateSubFramebuffer(GLenum target, sequence<GLenum> attachments,
+ GLint x, GLint y, GLsizei width, GLsizei height);
+ void readBuffer(GLenum src);
/* Renderbuffer objects */
- // any getInternalformatParameter(GLenum target, GLenum internalformat, GLenum pname);
- // void renderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat,
- // GLsizei width, GLsizei height);
+ any getInternalformatParameter(GLenum target, GLenum internalformat, GLenum pname);
+ void renderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat,
+ GLsizei width, GLsizei height);
/* Texture objects */
// void texStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width,
@@ -422,7 +418,7 @@ interface mixin WebGL2RenderingContextBase
// optional GLuint srcLengthOverride = 0);
/* Programs and shaders */
- // [WebGLHandlesContextLoss] GLint getFragDataLocation(WebGLProgram program, DOMString name);
+ [WebGLHandlesContextLoss] GLint getFragDataLocation(WebGLProgram program, DOMString name);
/* Uniforms */
void uniform1ui(WebGLUniformLocation? location, GLuint v0);
@@ -479,7 +475,7 @@ interface mixin WebGL2RenderingContextBase
/*[AllowShared]*/ ArrayBufferView dstData, GLuint dstOffset);
/* Multiple Render Targets */
- // void drawBuffers(sequence<GLenum> buffers);
+ void drawBuffers(sequence<GLenum> buffers);
void clearBufferfv(GLenum buffer, GLint drawbuffer, Float32List values,
optional GLuint srcOffset = 0);
@@ -531,7 +527,7 @@ interface mixin WebGL2RenderingContextBase
/* Uniform Buffer Objects and Transform Feedback Buffers */
void bindBufferBase(GLenum target, GLuint index, WebGLBuffer? buffer);
void bindBufferRange(GLenum target, GLuint index, WebGLBuffer? buffer, GLintptr offset, GLsizeiptr size);
- // any getIndexedParameter(GLenum target, GLuint index);
+ any getIndexedParameter(GLenum target, GLuint index);
sequence<GLuint>? getUniformIndices(WebGLProgram program, sequence<DOMString> uniformNames);
any getActiveUniforms(WebGLProgram program, sequence<GLuint> uniformIndices, GLenum pname);
GLuint getUniformBlockIndex(WebGLProgram program, DOMString uniformBlockName);
@@ -540,10 +536,10 @@ interface mixin WebGL2RenderingContextBase
void uniformBlockBinding(WebGLProgram program, GLuint uniformBlockIndex, GLuint uniformBlockBinding);
/* Vertex Array Objects */
- /*WebGLVertexArrayObject? createVertexArray();
+ WebGLVertexArrayObject? createVertexArray();
void deleteVertexArray(WebGLVertexArrayObject? vertexArray);
[WebGLHandlesContextLoss] GLboolean isVertexArray(WebGLVertexArrayObject? vertexArray);
- void bindVertexArray(WebGLVertexArrayObject? array);*/
+ void bindVertexArray(WebGLVertexArrayObject? array);
};
[Exposed=Window, Pref="dom.webgl2.enabled"]
diff --git a/components/script/dom/webidls/WebGLVertexArrayObject.webidl b/components/script/dom/webidls/WebGLVertexArrayObject.webidl
new file mode 100644
index 00000000000..a42d8cbe051
--- /dev/null
+++ b/components/script/dom/webidls/WebGLVertexArrayObject.webidl
@@ -0,0 +1,11 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+//
+// WebGL IDL definitions scraped from the Khronos specification:
+// https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.17
+//
+
+[Exposed=(Window), Pref="dom.webgl2.enabled"]
+interface WebGLVertexArrayObject : WebGLObject {
+};
diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs
index ce290caabf7..6b3b51f9a79 100644
--- a/components/script/dom/window.rs
+++ b/components/script/dom/window.rs
@@ -8,7 +8,6 @@ use crate::dom::bindings::codegen::Bindings::DocumentBinding::{
};
use crate::dom::bindings::codegen::Bindings::HistoryBinding::HistoryBinding::HistoryMethods;
use crate::dom::bindings::codegen::Bindings::MediaQueryListBinding::MediaQueryListBinding::MediaQueryListMethods;
-use crate::dom::bindings::codegen::Bindings::PermissionStatusBinding::PermissionState;
use crate::dom::bindings::codegen::Bindings::RequestBinding::RequestInit;
use crate::dom::bindings::codegen::Bindings::VoidFunctionBinding::VoidFunction;
use crate::dom::bindings::codegen::Bindings::WindowBinding::{
@@ -275,9 +274,6 @@ pub struct Window {
#[ignore_malloc_size_of = "defined in webxr"]
webxr_registry: webxr_api::Registry,
- /// A map for storing the previous permission state read results.
- permission_state_invocation_results: DomRefCell<HashMap<String, PermissionState>>,
-
/// All of the elements that have an outstanding image request that was
/// initiated by layout during a reflow. They are stored in the script thread
/// to ensure that the element can be marked dirty when the image data becomes
@@ -336,6 +332,8 @@ pub struct Window {
/// A mechanism to force the compositor to process events.
#[ignore_malloc_size_of = "traits are cumbersome"]
event_loop_waker: Option<Box<dyn EventLoopWaker>>,
+
+ visible: Cell<bool>,
}
impl Window {
@@ -476,12 +474,6 @@ impl Window {
Worklet::new(self, WorkletGlobalScopeType::Paint)
}
- pub fn permission_state_invocation_results(
- &self,
- ) -> &DomRefCell<HashMap<String, PermissionState>> {
- &self.permission_state_invocation_results
- }
-
pub fn pending_image_notification(&self, response: PendingImageResponse) {
//XXXjdm could be more efficient to send the responses to the layout thread,
// rather than making the layout thread talk to the image cache to
@@ -1403,10 +1395,12 @@ impl Window {
// We tear down the active document, which causes all the attached
// nodes to dispose of their layout data. This messages the layout
// thread, informing it that it can safely free the memory.
- self.Document().upcast::<Node>().teardown();
+ self.Document()
+ .upcast::<Node>()
+ .teardown(self.layout_chan());
- // Tell the constellation to drop the sender to our message-port router, if there is any.
- self.upcast::<GlobalScope>().remove_message_ports_router();
+ // Remove the infra for managing messageports and broadcast channels.
+ self.upcast::<GlobalScope>().remove_web_messaging_infra();
// Clean up any active promises
// https://github.com/servo/servo/issues/15318
@@ -1987,7 +1981,7 @@ impl Window {
.task_canceller(TaskSourceName::DOMManipulation)
.wrap_task(task),
),
- self.pipeline_id(),
+ Some(self.pipeline_id()),
TaskSourceName::DOMManipulation,
));
doc.set_url(load_data.url.clone());
@@ -2193,6 +2187,7 @@ impl Window {
/// Slow down/speed up timers based on visibility.
pub fn alter_resource_utilization(&self, visible: bool) {
+ self.visible.set(visible);
if visible {
self.upcast::<GlobalScope>().speed_up_timers();
} else {
@@ -2200,6 +2195,10 @@ impl Window {
}
}
+ pub fn visible(&self) -> bool {
+ self.visible.get()
+ }
+
pub fn unminified_js_dir(&self) -> Option<String> {
self.unminified_js_dir.borrow().clone()
}
@@ -2331,7 +2330,6 @@ impl Window {
webgl_chan,
webvr_chan,
webxr_registry,
- permission_state_invocation_results: Default::default(),
pending_layout_images: Default::default(),
unminified_js_dir: Default::default(),
test_worklet: Default::default(),
@@ -2348,13 +2346,14 @@ impl Window {
replace_surrogates,
player_context,
event_loop_waker,
+ visible: Cell::new(true),
});
unsafe { WindowBinding::Wrap(JSContext::from_ptr(runtime.cx()), win) }
}
- pub fn pipeline_id(&self) -> Option<PipelineId> {
- Some(self.upcast::<GlobalScope>().pipeline_id())
+ pub fn pipeline_id(&self) -> PipelineId {
+ self.upcast::<GlobalScope>().pipeline_id()
}
}
@@ -2485,7 +2484,7 @@ impl Window {
.task_canceller(TaskSourceName::DOMManipulation)
.wrap_task(task),
),
- self.pipeline_id(),
+ Some(self.pipeline_id()),
TaskSourceName::DOMManipulation,
));
}
diff --git a/components/script/dom/windowproxy.rs b/components/script/dom/windowproxy.rs
index 8abbbb480d6..4155d3626a2 100644
--- a/components/script/dom/windowproxy.rs
+++ b/components/script/dom/windowproxy.rs
@@ -166,7 +166,7 @@ impl WindowProxy {
// Create a new browsing context.
let current = Some(window.global().pipeline_id());
- let mut window_proxy = Box::new(WindowProxy::new_inherited(
+ let window_proxy = Box::new(WindowProxy::new_inherited(
browsing_context_id,
top_level_browsing_context_id,
current,
@@ -212,7 +212,7 @@ impl WindowProxy {
let cx = global_to_clone_from.get_cx();
// Create a new browsing context.
- let mut window_proxy = Box::new(WindowProxy::new_inherited(
+ let window_proxy = Box::new(WindowProxy::new_inherited(
browsing_context_id,
top_level_browsing_context_id,
None,
diff --git a/components/script/dom/xrsession.rs b/components/script/dom/xrsession.rs
index ec51c910a17..ed111fb3c02 100644
--- a/components/script/dom/xrsession.rs
+++ b/components/script/dom/xrsession.rs
@@ -5,7 +5,6 @@
use crate::dom::bindings::callback::ExceptionHandling;
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::XRReferenceSpaceBinding::XRReferenceSpaceType;
use crate::dom::bindings::codegen::Bindings::XRRenderStateBinding::XRRenderStateInit;
@@ -16,7 +15,6 @@ use crate::dom::bindings::codegen::Bindings::XRSessionBinding::XRFrameRequestCal
use crate::dom::bindings::codegen::Bindings::XRSessionBinding::XRSessionMethods;
use crate::dom::bindings::codegen::Bindings::XRSessionBinding::XRVisibilityState;
use crate::dom::bindings::codegen::Bindings::XRSystemBinding::XRSessionMode;
-use crate::dom::bindings::codegen::Bindings::XRWebGLLayerBinding::XRWebGLLayerMethods;
use crate::dom::bindings::error::{Error, ErrorResult};
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::refcounted::Trusted;
@@ -25,8 +23,6 @@ use crate::dom::bindings::root::{Dom, DomRoot, MutDom, MutNullableDom};
use crate::dom::event::Event;
use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope;
-use crate::dom::node::Node;
-use crate::dom::node::NodeDamage;
use crate::dom::performance::reduce_timing_resolution;
use crate::dom::promise::Promise;
use crate::dom::xrframe::XRFrame;
@@ -51,7 +47,7 @@ use std::mem;
use std::rc::Rc;
use webxr_api::{
self, util, Display, EnvironmentBlendMode, Event as XREvent, Frame, SelectEvent, SelectKind,
- Session, View, Viewer, Visibility,
+ Session, SessionId, View, Viewer, Visibility,
};
#[dom_struct]
@@ -412,14 +408,6 @@ impl XRSession {
"WEBXR PROFILING [raf execute]:\t{}ms",
(time::precise_time_ns() - raf_start) as f64 / 1_000_000.
);
-
- // If the canvas element is attached to the DOM, it is now dirty,
- // and we need to trigger a reflow.
- base_layer
- .Context()
- .Canvas()
- .upcast::<Node>()
- .dirty(NodeDamage::OtherNodeDamage);
}
fn update_inline_projection_matrix(&self) {
@@ -462,38 +450,42 @@ impl XRSession {
viewport: Rect::from_size(size.to_i32()),
}
}
+
+ pub fn session_id(&self) -> SessionId {
+ self.session.borrow().id()
+ }
}
impl XRSessionMethods for XRSession {
- /// https://immersive-web.github.io/webxr/#eventdef-xrsession-end
+ // https://immersive-web.github.io/webxr/#eventdef-xrsession-end
event_handler!(end, GetOnend, SetOnend);
- /// https://immersive-web.github.io/webxr/#eventdef-xrsession-select
+ // https://immersive-web.github.io/webxr/#eventdef-xrsession-select
event_handler!(select, GetOnselect, SetOnselect);
- /// https://immersive-web.github.io/webxr/#eventdef-xrsession-selectstart
+ // https://immersive-web.github.io/webxr/#eventdef-xrsession-selectstart
event_handler!(selectstart, GetOnselectstart, SetOnselectstart);
- /// https://immersive-web.github.io/webxr/#eventdef-xrsession-selectend
+ // https://immersive-web.github.io/webxr/#eventdef-xrsession-selectend
event_handler!(selectend, GetOnselectend, SetOnselectend);
- /// https://immersive-web.github.io/webxr/#eventdef-xrsession-squeeze
+ // https://immersive-web.github.io/webxr/#eventdef-xrsession-squeeze
event_handler!(squeeze, GetOnsqueeze, SetOnsqueeze);
- /// https://immersive-web.github.io/webxr/#eventdef-xrsession-squeezestart
+ // https://immersive-web.github.io/webxr/#eventdef-xrsession-squeezestart
event_handler!(squeezestart, GetOnsqueezestart, SetOnsqueezestart);
- /// https://immersive-web.github.io/webxr/#eventdef-xrsession-squeezeend
+ // https://immersive-web.github.io/webxr/#eventdef-xrsession-squeezeend
event_handler!(squeezeend, GetOnsqueezeend, SetOnsqueezeend);
- /// https://immersive-web.github.io/webxr/#eventdef-xrsession-visibilitychange
+ // https://immersive-web.github.io/webxr/#eventdef-xrsession-visibilitychange
event_handler!(
visibilitychange,
GetOnvisibilitychange,
SetOnvisibilitychange
);
- /// https://immersive-web.github.io/webxr/#eventdef-xrsession-inputsourceschange
+ // https://immersive-web.github.io/webxr/#eventdef-xrsession-inputsourceschange
event_handler!(
inputsourceschange,
GetOninputsourceschange,
diff --git a/components/script/dom/xrsystem.rs b/components/script/dom/xrsystem.rs
index e397a4fc0b2..8a8f109722b 100644
--- a/components/script/dom/xrsystem.rs
+++ b/components/script/dom/xrsystem.rs
@@ -18,10 +18,10 @@ use crate::dom::event::Event;
use crate::dom::eventtarget::EventTarget;
use crate::dom::gamepad::Gamepad;
use crate::dom::gamepadevent::GamepadEventType;
-use crate::dom::globalscope::GlobalScope;
use crate::dom::promise::Promise;
use crate::dom::vrdisplay::VRDisplay;
use crate::dom::vrdisplayevent::VRDisplayEvent;
+use crate::dom::window::Window;
use crate::dom::xrsession::XRSession;
use crate::dom::xrtest::XRTest;
use crate::realms::InRealm;
@@ -30,6 +30,7 @@ use crate::task_source::TaskSource;
use dom_struct::dom_struct;
use ipc_channel::ipc::{self as ipc_crate, IpcReceiver, IpcSender};
use ipc_channel::router::ROUTER;
+use msg::constellation_msg::PipelineId;
use profile_traits::ipc;
use std::cell::Cell;
use std::rc::Rc;
@@ -46,10 +47,13 @@ pub struct XRSystem {
active_immersive_session: MutNullableDom<XRSession>,
active_inline_sessions: DomRefCell<Vec<Dom<XRSession>>>,
test: MutNullableDom<XRTest>,
+ pipeline: PipelineId,
+ #[ignore_malloc_size_of = "channels are hard"]
+ webvr_thread: Option<IpcSender<WebVRMsg>>,
}
impl XRSystem {
- fn new_inherited() -> XRSystem {
+ fn new_inherited(pipeline: PipelineId, webvr_thread: Option<IpcSender<WebVRMsg>>) -> XRSystem {
XRSystem {
eventtarget: EventTarget::new_inherited(),
displays: DomRefCell::new(Vec::new()),
@@ -58,13 +62,18 @@ impl XRSystem {
active_immersive_session: Default::default(),
active_inline_sessions: DomRefCell::new(Vec::new()),
test: Default::default(),
+ pipeline,
+ webvr_thread,
}
}
- pub fn new(global: &GlobalScope) -> DomRoot<XRSystem> {
+ pub fn new(window: &Window) -> DomRoot<XRSystem> {
let root = reflect_dom_object(
- Box::new(XRSystem::new_inherited()),
- global,
+ Box::new(XRSystem::new_inherited(
+ window.pipeline_id(),
+ window.webvr_thread(),
+ )),
+ window,
XRSystemBinding::Wrap,
);
root.register();
@@ -304,7 +313,7 @@ impl XRSystem {
}
pub fn get_displays(&self) -> Result<Vec<DomRoot<VRDisplay>>, ()> {
- if let Some(webvr_thread) = self.webvr_thread() {
+ if let Some(ref webvr_thread) = self.webvr_thread {
let (sender, receiver) =
ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
webvr_thread.send(WebVRMsg::GetDisplays(sender)).unwrap();
@@ -333,10 +342,6 @@ impl XRSystem {
.collect())
}
- fn webvr_thread(&self) -> Option<IpcSender<WebVRMsg>> {
- self.global().as_window().webvr_thread()
- }
-
fn find_display(&self, display_id: u32) -> Option<DomRoot<VRDisplay>> {
self.displays
.borrow()
@@ -346,15 +351,15 @@ impl XRSystem {
}
fn register(&self) {
- if let Some(webvr_thread) = self.webvr_thread() {
+ if let Some(ref webvr_thread) = self.webvr_thread {
let msg = WebVRMsg::RegisterContext(self.global().pipeline_id());
webvr_thread.send(msg).unwrap();
}
}
fn unregister(&self) {
- if let Some(webvr_thread) = self.webvr_thread() {
- let msg = WebVRMsg::UnregisterContext(self.global().pipeline_id());
+ if let Some(ref webvr_thread) = self.webvr_thread {
+ let msg = WebVRMsg::UnregisterContext(self.pipeline);
webvr_thread.send(msg).unwrap();
}
}
@@ -364,7 +369,7 @@ impl XRSystem {
existing.update_display(&display);
existing
} else {
- let root = VRDisplay::new(&self.global(), display.clone());
+ let root = VRDisplay::new(&self.global().as_window(), display.clone());
self.displays.borrow_mut().push(Dom::from_ref(&*root));
root
}
@@ -474,7 +479,7 @@ impl XRSystem {
// guarantees that the gamepads always have a valid state and can be very useful for
// motion capture or drawing applications.
pub fn get_gamepads(&self) -> Vec<DomRoot<Gamepad>> {
- if let Some(wevbr_sender) = self.webvr_thread() {
+ if let Some(ref wevbr_sender) = self.webvr_thread {
let (sender, receiver) =
ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
let synced_ids = self