Use out parameter for generated methods returning JSVal (#34087)

* Make generated bindings that return a WebIDL `any` value use out parameters.

Returning raw JSVal values makes it easier to create GC hazards in code
that calls these methods. Accepting a MutableHandle argument instead
ensures that the values are rooted by the caller.

Signed-off-by: Josh Matthews <josh@joshmatthews.net>

* Update mozjs.

Signed-off-by: Josh Matthews <josh@joshmatthews.net>

* Fix clippy warnings.

Signed-off-by: Josh Matthews <josh@joshmatthews.net>

---------

Signed-off-by: Josh Matthews <josh@joshmatthews.net>
This commit is contained in:
Josh Matthews 2024-11-05 03:29:08 -05:00 committed by GitHub
parent 537958a3cc
commit 25a0764a37
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
38 changed files with 763 additions and 515 deletions

6
Cargo.lock generated
View file

@ -4500,7 +4500,7 @@ dependencies = [
[[package]] [[package]]
name = "mozjs" name = "mozjs"
version = "0.14.1" version = "0.14.1"
source = "git+https://github.com/servo/mozjs#118aae2bcdb39617473b2cfe9fc680274ebbb9fc" source = "git+https://github.com/servo/mozjs#8526195dce129d2ccd83e7e1e5d03a954c11fafe"
dependencies = [ dependencies = [
"bindgen", "bindgen",
"cc", "cc",
@ -4512,8 +4512,8 @@ dependencies = [
[[package]] [[package]]
name = "mozjs_sys" name = "mozjs_sys"
version = "0.128.3-1" version = "0.128.3-4"
source = "git+https://github.com/servo/mozjs#118aae2bcdb39617473b2cfe9fc680274ebbb9fc" source = "git+https://github.com/servo/mozjs#8526195dce129d2ccd83e7e1e5d03a954c11fafe"
dependencies = [ dependencies = [
"bindgen", "bindgen",
"cc", "cc",

View file

@ -1415,6 +1415,18 @@ def typeNeedsCx(type, retVal=False):
return type.isAny() or type.isObject() return type.isAny() or type.isObject()
def returnTypeNeedsOutparam(type):
if type.nullable():
type = type.inner
return type.isAny()
def outparamTypeFromReturnType(type):
if type.isAny():
return "MutableHandleValue"
raise f"Don't know how to handle {type} as an outparam"
# Returns a conversion behavior suitable for a type # Returns a conversion behavior suitable for a type
def getConversionConfigForType(type, isEnforceRange, isClamp, treatNullAs): def getConversionConfigForType(type, isEnforceRange, isClamp, treatNullAs):
if type.isSequence() or type.isRecord(): if type.isSequence() or type.isRecord():
@ -1502,8 +1514,6 @@ def getRetvalDeclarationForType(returnType, descriptorProvider):
if returnType.nullable(): if returnType.nullable():
result = CGWrapper(result, pre="Option<", post=">") result = CGWrapper(result, pre="Option<", post=">")
return result return result
# TODO: Return the value through a MutableHandleValue outparam
# https://github.com/servo/servo/issues/6307
if returnType.isAny(): if returnType.isAny():
return CGGeneric("JSVal") return CGGeneric("JSVal")
if returnType.isObject() or returnType.isSpiderMonkeyInterface(): if returnType.isObject() or returnType.isSpiderMonkeyInterface():
@ -3705,6 +3715,12 @@ class CGCallGenerator(CGThing):
isFallible = errorResult is not None isFallible = errorResult is not None
result = getRetvalDeclarationForType(returnType, descriptor) result = getRetvalDeclarationForType(returnType, descriptor)
if returnType and returnTypeNeedsOutparam(returnType):
rootType = result
result = CGGeneric("()")
else:
rootType = None
if isFallible: if isFallible:
result = CGWrapper(result, pre="Result<", post=", Error>") result = CGWrapper(result, pre="Result<", post=", Error>")
@ -3723,10 +3739,19 @@ class CGCallGenerator(CGThing):
args.append(CGGeneric("InRealm::already(&AlreadyInRealm::assert_for_cx(cx))")) args.append(CGGeneric("InRealm::already(&AlreadyInRealm::assert_for_cx(cx))"))
if nativeMethodName in descriptor.canGcMethods: if nativeMethodName in descriptor.canGcMethods:
args.append(CGGeneric("CanGc::note()")) args.append(CGGeneric("CanGc::note()"))
if rootType:
args.append(CGGeneric("retval.handle_mut()"))
# Build up our actual call # Build up our actual call
self.cgRoot = CGList([], "\n") self.cgRoot = CGList([], "\n")
if rootType:
self.cgRoot.append(CGList([
CGGeneric("rooted!(in(*cx) let mut retval: "),
rootType,
CGGeneric(");"),
]))
call = CGGeneric(nativeMethodName) call = CGGeneric(nativeMethodName)
if static: if static:
call = CGWrapper(call, pre=f"{MakeNativeName(descriptor.interface.identifier.name)}::") call = CGWrapper(call, pre=f"{MakeNativeName(descriptor.interface.identifier.name)}::")
@ -3846,7 +3871,18 @@ class CGPerSignatureCall(CGThing):
return 'infallible' not in self.extendedAttributes return 'infallible' not in self.extendedAttributes
def wrap_return_value(self): def wrap_return_value(self):
return wrapForType('MutableHandleValue::from_raw(args.rval())', successCode='return true;') resultName = "result"
# Maplike methods have `any` return values in WebIDL, but our internal bindings
# use stronger types so we need to exclude them from being handled like other
# generated code.
if returnTypeNeedsOutparam(self.returnType) and (
not (self.idlNode.isMethod() and self.idlNode.isMaplikeOrSetlikeOrIterableMethod())):
resultName = "retval"
return wrapForType(
'MutableHandleValue::from_raw(args.rval())',
result=resultName,
successCode='return true;',
)
def define(self): def define(self):
return f"{self.cgRoot.define()}\n{self.wrap_return_value()}" return f"{self.cgRoot.define()}\n{self.wrap_return_value()}"
@ -6303,8 +6339,8 @@ class CGInterfaceTrait(CGThing):
def __init__(self, descriptor, descriptorProvider): def __init__(self, descriptor, descriptorProvider):
CGThing.__init__(self) CGThing.__init__(self)
def attribute_arguments(needCx, argument=None, inRealm=False, canGc=False): def attribute_arguments(attribute_type, argument=None, inRealm=False, canGc=False, retval=False):
if needCx: if typeNeedsCx(attribute_type, retval):
yield "cx", "SafeJSContext" yield "cx", "SafeJSContext"
if argument: if argument:
@ -6316,6 +6352,9 @@ class CGInterfaceTrait(CGThing):
if canGc: if canGc:
yield "_can_gc", "CanGc" yield "_can_gc", "CanGc"
if retval and returnTypeNeedsOutparam(attribute_type):
yield "retval", outparamTypeFromReturnType(attribute_type)
def members(): def members():
for m in descriptor.interface.members: for m in descriptor.interface.members:
if (m.isMethod() if (m.isMethod()
@ -6335,9 +6374,10 @@ class CGInterfaceTrait(CGThing):
infallible = 'infallible' in descriptor.getExtendedAttributes(m, getter=True) infallible = 'infallible' in descriptor.getExtendedAttributes(m, getter=True)
yield (name, yield (name,
attribute_arguments( attribute_arguments(
typeNeedsCx(m.type, True), m.type,
inRealm=name in descriptor.inRealmMethods, inRealm=name in descriptor.inRealmMethods,
canGc=name in descriptor.canGcMethods canGc=name in descriptor.canGcMethods,
retval=True
), ),
return_type(descriptor, m.type, infallible), return_type(descriptor, m.type, infallible),
m.isStatic()) m.isStatic())
@ -6351,10 +6391,11 @@ class CGInterfaceTrait(CGThing):
rettype = "ErrorResult" rettype = "ErrorResult"
yield (name, yield (name,
attribute_arguments( attribute_arguments(
typeNeedsCx(m.type, False), m.type,
m.type, m.type,
inRealm=name in descriptor.inRealmMethods, inRealm=name in descriptor.inRealmMethods,
canGc=name in descriptor.canGcMethods canGc=name in descriptor.canGcMethods,
retval=False,
), ),
rettype, rettype,
m.isStatic()) m.isStatic())
@ -7240,9 +7281,14 @@ def method_arguments(descriptorProvider, returnType, arguments, passJSBits=True,
if canGc: if canGc:
yield "_can_gc", "CanGc" yield "_can_gc", "CanGc"
if returnTypeNeedsOutparam(returnType):
yield "rval", outparamTypeFromReturnType(returnType),
def return_type(descriptorProvider, rettype, infallible): def return_type(descriptorProvider, rettype, infallible):
result = getRetvalDeclarationForType(rettype, descriptorProvider) result = getRetvalDeclarationForType(rettype, descriptorProvider)
if rettype and returnTypeNeedsOutparam(rettype):
result = CGGeneric("()")
if not infallible: if not infallible:
result = CGWrapper(result, pre="Fallible<", post=">") result = CGWrapper(result, pre="Fallible<", post=">")
return result.define() return result.define()
@ -7466,6 +7512,7 @@ class CallbackMember(CGNativeMember):
f"{self.argCount - 1} + {lastArg.identifier.name}.len()").removeprefix("0 + ") f"{self.argCount - 1} + {lastArg.identifier.name}.len()").removeprefix("0 + ")
else: else:
self.argCountStr = f"{self.argCount}" self.argCountStr = f"{self.argCount}"
self.usingOutparam = returnTypeNeedsOutparam(self.retvalType)
self.needThisHandling = needThisHandling self.needThisHandling = needThisHandling
# If needThisHandling, we generate ourselves as private and the caller # If needThisHandling, we generate ourselves as private and the caller
# will handle generating public versions that handle the "this" stuff. # will handle generating public versions that handle the "this" stuff.
@ -7518,15 +7565,16 @@ class CallbackMember(CGNativeMember):
template = info.template template = info.template
declType = info.declType declType = info.declType
convertType = instantiateJSToNativeConversionTemplate( if self.usingOutparam:
template, replacements, declType, "rvalDecl") convertType = CGGeneric("")
if self.retvalType is None or self.retvalType.isUndefined():
retval = "()"
elif self.retvalType.isAny():
retval = "rvalDecl.get()"
else: else:
retval = "rvalDecl" convertType = instantiateJSToNativeConversionTemplate(
template, replacements, declType, "retval")
if self.retvalType is None or self.retvalType.isUndefined() or self.usingOutparam:
retval = "()"
else:
retval = "retval"
return f"{convertType.define()}\nOk({retval})\n" return f"{convertType.define()}\nOk({retval})\n"
@ -7633,7 +7681,10 @@ class CallbackMethod(CallbackMember):
needThisHandling) needThisHandling)
def getRvalDecl(self): def getRvalDecl(self):
return "rooted!(in(*cx) let mut rval = UndefinedValue());\n" if self.usingOutparam:
return ""
else:
return "rooted!(in(*cx) let mut rval = UndefinedValue());\n"
def getCall(self): def getCall(self):
if self.argCount > 0: if self.argCount > 0:
@ -7642,6 +7693,7 @@ class CallbackMethod(CallbackMember):
else: else:
argv = "ptr::null_mut()" argv = "ptr::null_mut()"
argc = "0" argc = "0"
suffix = "" if self.usingOutparam else ".handle_mut()"
return (f"{self.getCallableDecl()}" return (f"{self.getCallableDecl()}"
f"rooted!(in(*cx) let rootedThis = {self.getThisObj()});\n" f"rooted!(in(*cx) let rootedThis = {self.getThisObj()});\n"
f"let ok = {self.getCallGuard()}JS_CallFunctionValue(\n" f"let ok = {self.getCallGuard()}JS_CallFunctionValue(\n"
@ -7649,7 +7701,7 @@ class CallbackMethod(CallbackMember):
" &HandleValueArray {\n" " &HandleValueArray {\n"
f" length_: {argc} as ::libc::size_t,\n" f" length_: {argc} as ::libc::size_t,\n"
f" elements_: {argv}\n" f" elements_: {argv}\n"
" }, rval.handle_mut());\n" f" }}, rval{suffix});\n"
"maybe_resume_unwind();\n" "maybe_resume_unwind();\n"
"if !ok {\n" "if !ok {\n"
" return Err(JSFailed);\n" " return Err(JSFailed);\n"

View file

@ -117,13 +117,15 @@ impl Clone for DOMJSClass {
unsafe impl Sync for DOMJSClass {} unsafe impl Sync for DOMJSClass {}
/// Returns a JSVal representing the frozen JavaScript array /// Returns a JSVal representing the frozen JavaScript array
pub fn to_frozen_array<T: ToJSValConvertible>(convertibles: &[T], cx: SafeJSContext) -> JSVal { pub fn to_frozen_array<T: ToJSValConvertible>(
rooted!(in(*cx) let mut ports = UndefinedValue()); convertibles: &[T],
unsafe { convertibles.to_jsval(*cx, ports.handle_mut()) }; cx: SafeJSContext,
rval: MutableHandleValue,
) {
unsafe { convertibles.to_jsval(*cx, rval) };
rooted!(in(*cx) let obj = ports.to_object()); rooted!(in(*cx) let obj = rval.to_object());
unsafe { JS_FreezeObject(*cx, RawHandleObject::from(obj.handle())) }; unsafe { JS_FreezeObject(*cx, RawHandleObject::from(obj.handle())) };
*ports
} }
/// Returns the ProtoOrIfaceArray for the given global object. /// Returns the ProtoOrIfaceArray for the given global object.

View file

@ -3,7 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use dom_struct::dom_struct; use dom_struct::dom_struct;
use js::jsval::JSVal; use js::rust::MutableHandleValue;
use servo_arc::Arc; use servo_arc::Arc;
use style::shared_lock::ToCssWithGuard; use style::shared_lock::ToCssWithGuard;
use style::stylesheets::{CssRuleType, LayerStatementRule}; use style::stylesheets::{CssRuleType, LayerStatementRule};
@ -67,13 +67,13 @@ impl SpecificCSSRule for CSSLayerStatementRule {
impl CSSLayerStatementRuleMethods for CSSLayerStatementRule { impl CSSLayerStatementRuleMethods for CSSLayerStatementRule {
/// <https://drafts.csswg.org/css-cascade-5/#dom-csslayerstatementrule-namelist> /// <https://drafts.csswg.org/css-cascade-5/#dom-csslayerstatementrule-namelist>
fn NameList(&self, cx: SafeJSContext) -> JSVal { fn NameList(&self, cx: SafeJSContext, retval: MutableHandleValue) {
let names: Vec<DOMString> = self let names: Vec<DOMString> = self
.layerstatementrule .layerstatementrule
.names .names
.iter() .iter()
.map(|name| DOMString::from_string(name.to_css_string())) .map(|name| DOMString::from_string(name.to_css_string()))
.collect(); .collect();
to_frozen_array(names.as_slice(), cx) to_frozen_array(names.as_slice(), cx, retval)
} }
} }

View file

@ -548,16 +548,12 @@ impl CustomElementRegistryMethods for CustomElementRegistry {
/// <https://html.spec.whatwg.org/multipage/#dom-customelementregistry-get> /// <https://html.spec.whatwg.org/multipage/#dom-customelementregistry-get>
#[allow(unsafe_code)] #[allow(unsafe_code)]
fn Get(&self, cx: JSContext, name: DOMString) -> JSVal { fn Get(&self, cx: JSContext, name: DOMString, mut retval: MutableHandleValue) {
match self.definitions.borrow().get(&LocalName::from(&*name)) { match self.definitions.borrow().get(&LocalName::from(&*name)) {
Some(definition) => unsafe { Some(definition) => unsafe {
rooted!(in(*cx) let mut constructor = UndefinedValue()); definition.constructor.to_jsval(*cx, retval);
definition
.constructor
.to_jsval(*cx, constructor.handle_mut());
constructor.get()
}, },
None => UndefinedValue(), None => retval.set(UndefinedValue()),
} }
} }
@ -994,7 +990,13 @@ impl CustomElementReaction {
.iter() .iter()
.map(|arg| unsafe { HandleValue::from_raw(arg.handle()) }) .map(|arg| unsafe { HandleValue::from_raw(arg.handle()) })
.collect(); .collect();
let _ = callback.Call_(element, arguments, ExceptionHandling::Report); rooted!(in(*GlobalScope::get_cx()) let mut value: JSVal);
let _ = callback.Call_(
element,
arguments,
value.handle_mut(),
ExceptionHandling::Report,
);
}, },
} }
} }

View file

@ -5,7 +5,7 @@
use dom_struct::dom_struct; use dom_struct::dom_struct;
use js::jsapi::Heap; use js::jsapi::Heap;
use js::jsval::JSVal; use js::jsval::JSVal;
use js::rust::{HandleObject, HandleValue}; use js::rust::{HandleObject, HandleValue, MutableHandleValue};
use servo_atoms::Atom; use servo_atoms::Atom;
use crate::dom::bindings::codegen::Bindings::CustomEventBinding; use crate::dom::bindings::codegen::Bindings::CustomEventBinding;
@ -105,8 +105,8 @@ impl CustomEventMethods for CustomEvent {
} }
// https://dom.spec.whatwg.org/#dom-customevent-detail // https://dom.spec.whatwg.org/#dom-customevent-detail
fn Detail(&self, _cx: JSContext) -> JSVal { fn Detail(&self, _cx: JSContext, mut retval: MutableHandleValue) {
self.detail.get() retval.set(self.detail.get())
} }
// https://dom.spec.whatwg.org/#dom-customevent-initcustomevent // https://dom.spec.whatwg.org/#dom-customevent-initcustomevent

View file

@ -5,8 +5,8 @@
use base::id::PipelineId; use base::id::PipelineId;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use js::jsapi::{Heap, JSObject}; use js::jsapi::{Heap, JSObject};
use js::jsval::{JSVal, UndefinedValue}; use js::jsval::UndefinedValue;
use js::rust::{CustomAutoRooter, CustomAutoRooterGuard, HandleValue}; use js::rust::{CustomAutoRooter, CustomAutoRooterGuard, HandleValue, MutableHandleValue};
use script_traits::{ScriptMsg, StructuredSerializedData}; use script_traits::{ScriptMsg, StructuredSerializedData};
use servo_url::ServoUrl; use servo_url::ServoUrl;
@ -167,9 +167,9 @@ impl DissimilarOriginWindowMethods for DissimilarOriginWindow {
} }
// https://html.spec.whatwg.org/multipage/#dom-opener // https://html.spec.whatwg.org/multipage/#dom-opener
fn Opener(&self, _: JSContext) -> JSVal { fn Opener(&self, _: JSContext, mut retval: MutableHandleValue) {
// TODO: Implement x-origin opener // TODO: Implement x-origin opener
UndefinedValue() retval.set(UndefinedValue());
} }
// https://html.spec.whatwg.org/multipage/#dom-opener // https://html.spec.whatwg.org/multipage/#dom-opener

View file

@ -7,7 +7,7 @@ use std::cell::Cell;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use js::jsapi::Heap; use js::jsapi::Heap;
use js::jsval::JSVal; use js::jsval::JSVal;
use js::rust::{HandleObject, HandleValue}; use js::rust::{HandleObject, HandleValue, MutableHandleValue};
use servo_atoms::Atom; use servo_atoms::Atom;
use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::cell::DomRefCell;
@ -166,8 +166,8 @@ impl ErrorEventMethods for ErrorEvent {
} }
// https://html.spec.whatwg.org/multipage/#dom-errorevent-error // https://html.spec.whatwg.org/multipage/#dom-errorevent-error
fn Error(&self, _cx: JSContext) -> JSVal { fn Error(&self, _cx: JSContext, mut retval: MutableHandleValue) {
self.error.get() retval.set(self.error.get());
} }
// https://dom.spec.whatwg.org/#dom-event-istrusted // https://dom.spec.whatwg.org/#dom-event-istrusted

View file

@ -15,6 +15,7 @@ use deny_public_fields::DenyPublicFields;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use fnv::FnvHasher; use fnv::FnvHasher;
use js::jsapi::JS_GetFunctionObject; use js::jsapi::JS_GetFunctionObject;
use js::jsval::JSVal;
use js::rust::wrappers::CompileFunction; use js::rust::wrappers::CompileFunction;
use js::rust::{ use js::rust::{
transform_u16_to_source_text, CompileOptionsWrapper, HandleObject, RootedObjectVectorWrapper, transform_u16_to_source_text, CompileOptionsWrapper, HandleObject, RootedObjectVectorWrapper,
@ -194,7 +195,9 @@ impl CompiledEventListener {
if let Some(event) = event.downcast::<ErrorEvent>() { if let Some(event) = event.downcast::<ErrorEvent>() {
if object.is::<Window>() || object.is::<WorkerGlobalScope>() { if object.is::<Window>() || object.is::<WorkerGlobalScope>() {
let cx = GlobalScope::get_cx(); let cx = GlobalScope::get_cx();
rooted!(in(*cx) let error = event.Error(cx)); rooted!(in(*cx) let mut error: JSVal);
event.Error(cx, error.handle_mut());
rooted!(in(*cx) let mut rooted_return_value: JSVal);
let return_value = handler.Call_( let return_value = handler.Call_(
object, object,
EventOrString::String(event.Message()), EventOrString::String(event.Message()),
@ -202,13 +205,13 @@ impl CompiledEventListener {
Some(event.Lineno()), Some(event.Lineno()),
Some(event.Colno()), Some(event.Colno()),
Some(error.handle()), Some(error.handle()),
rooted_return_value.handle_mut(),
exception_handle, exception_handle,
); );
// Step 4 // Step 4
if let Ok(return_value) = return_value { if let Ok(()) = return_value {
rooted!(in(*cx) let return_value = return_value); if rooted_return_value.handle().is_boolean() &&
if return_value.handle().is_boolean() && rooted_return_value.handle().to_boolean()
return_value.handle().to_boolean()
{ {
event.upcast::<Event>().PreventDefault(); event.upcast::<Event>().PreventDefault();
} }
@ -217,6 +220,7 @@ impl CompiledEventListener {
} }
} }
rooted!(in(*GlobalScope::get_cx()) let mut rooted_return_value: JSVal);
let _ = handler.Call_( let _ = handler.Call_(
object, object,
EventOrString::Event(DomRoot::from_ref(event)), EventOrString::Event(DomRoot::from_ref(event)),
@ -224,6 +228,7 @@ impl CompiledEventListener {
None, None,
None, None,
None, None,
rooted_return_value.handle_mut(),
exception_handle, exception_handle,
); );
}, },
@ -250,10 +255,15 @@ impl CompiledEventListener {
}, },
CommonEventHandler::EventHandler(ref handler) => { CommonEventHandler::EventHandler(ref handler) => {
if let Ok(value) = handler.Call_(object, event, exception_handle) { let cx = GlobalScope::get_cx();
let cx = GlobalScope::get_cx(); rooted!(in(*cx) let mut rooted_return_value: JSVal);
rooted!(in(*cx) let value = value); if let Ok(()) = handler.Call_(
let value = value.handle(); object,
event,
rooted_return_value.handle_mut(),
exception_handle,
) {
let value = rooted_return_value.handle();
//Step 5 //Step 5
let should_cancel = value.is_boolean() && !value.to_boolean(); let should_cancel = value.is_boolean() && !value.to_boolean();

View file

@ -5,7 +5,7 @@
use dom_struct::dom_struct; use dom_struct::dom_struct;
use js::jsapi::Heap; use js::jsapi::Heap;
use js::jsval::JSVal; use js::jsval::JSVal;
use js::rust::{HandleObject, HandleValue}; use js::rust::{HandleObject, HandleValue, MutableHandleValue};
use servo_atoms::Atom; use servo_atoms::Atom;
use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::cell::DomRefCell;
@ -188,8 +188,8 @@ impl ExtendableMessageEventMethods for ExtendableMessageEvent {
} }
/// <https://w3c.github.io/ServiceWorker/#dom-extendablemessageevent-data> /// <https://w3c.github.io/ServiceWorker/#dom-extendablemessageevent-data>
fn Data(&self, _cx: JSContext) -> JSVal { fn Data(&self, _cx: JSContext, mut retval: MutableHandleValue) {
self.data.get() retval.set(self.data.get())
} }
/// <https://w3c.github.io/ServiceWorker/#dom-extendablemessageevent-origin> /// <https://w3c.github.io/ServiceWorker/#dom-extendablemessageevent-origin>
@ -208,9 +208,10 @@ impl ExtendableMessageEventMethods for ExtendableMessageEvent {
} }
/// <https://w3c.github.io/ServiceWorker/#extendablemessage-event-ports> /// <https://w3c.github.io/ServiceWorker/#extendablemessage-event-ports>
fn Ports(&self, cx: JSContext) -> JSVal { fn Ports(&self, cx: JSContext, mut retval: MutableHandleValue) {
if let Some(ports) = &*self.frozen_ports.borrow() { if let Some(ports) = &*self.frozen_ports.borrow() {
return ports.get(); retval.set(ports.get());
return;
} }
let ports: Vec<DomRoot<MessagePort>> = self let ports: Vec<DomRoot<MessagePort>> = self
@ -218,7 +219,7 @@ impl ExtendableMessageEventMethods for ExtendableMessageEvent {
.iter() .iter()
.map(|port| DomRoot::from_ref(&**port)) .map(|port| DomRoot::from_ref(&**port))
.collect(); .collect();
let frozen_ports = to_frozen_array(ports.as_slice(), cx); to_frozen_array(ports.as_slice(), cx, retval);
// Safety: need to create the Heap value in its final memory location before setting it. // Safety: need to create the Heap value in its final memory location before setting it.
*self.frozen_ports.borrow_mut() = Some(Heap::default()); *self.frozen_ports.borrow_mut() = Some(Heap::default());
@ -226,8 +227,6 @@ impl ExtendableMessageEventMethods for ExtendableMessageEvent {
.borrow() .borrow()
.as_ref() .as_ref()
.unwrap() .unwrap()
.set(frozen_ports); .set(retval.get());
frozen_ports
} }
} }

View file

@ -9,7 +9,7 @@ use dom_struct::dom_struct;
use embedder_traits::{DualRumbleEffectParams, EmbedderMsg}; use embedder_traits::{DualRumbleEffectParams, EmbedderMsg};
use ipc_channel::ipc; use ipc_channel::ipc;
use ipc_channel::router::ROUTER; use ipc_channel::router::ROUTER;
use js::jsval::JSVal; use js::rust::MutableHandleValue;
use script_traits::GamepadSupportedHapticEffects; use script_traits::GamepadSupportedHapticEffects;
use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::cell::DomRefCell;
@ -134,8 +134,8 @@ impl GamepadHapticActuator {
impl GamepadHapticActuatorMethods for GamepadHapticActuator { impl GamepadHapticActuatorMethods for GamepadHapticActuator {
/// <https://www.w3.org/TR/gamepad/#dom-gamepadhapticactuator-effects> /// <https://www.w3.org/TR/gamepad/#dom-gamepadhapticactuator-effects>
fn Effects(&self, cx: JSContext) -> JSVal { fn Effects(&self, cx: JSContext, retval: MutableHandleValue) {
to_frozen_array(self.effects.as_slice(), cx) to_frozen_array(self.effects.as_slice(), cx, retval)
} }
/// <https://www.w3.org/TR/gamepad/#dom-gamepadhapticactuator-playeffect> /// <https://www.w3.org/TR/gamepad/#dom-gamepadhapticactuator-playeffect>

View file

@ -3072,16 +3072,21 @@ impl GlobalScope {
} }
/// <https://w3c.github.io/performance-timeline/#supportedentrytypes-attribute> /// <https://w3c.github.io/performance-timeline/#supportedentrytypes-attribute>
pub fn supported_performance_entry_types(&self, cx: SafeJSContext) -> JSVal { pub fn supported_performance_entry_types(
&self,
cx: SafeJSContext,
mut retval: MutableHandleValue,
) {
if let Some(types) = &*self.frozen_supported_performance_entry_types.borrow() { if let Some(types) = &*self.frozen_supported_performance_entry_types.borrow() {
return types.get(); retval.set(types.get());
return;
} }
let types: Vec<DOMString> = VALID_ENTRY_TYPES let types: Vec<DOMString> = VALID_ENTRY_TYPES
.iter() .iter()
.map(|t| DOMString::from(t.to_string())) .map(|t| DOMString::from(t.to_string()))
.collect(); .collect();
let frozen_types = to_frozen_array(types.as_slice(), cx); to_frozen_array(types.as_slice(), cx, retval);
// Safety: need to create the Heap value in its final memory location before setting it. // Safety: need to create the Heap value in its final memory location before setting it.
*self.frozen_supported_performance_entry_types.borrow_mut() = Some(Heap::default()); *self.frozen_supported_performance_entry_types.borrow_mut() = Some(Heap::default());
@ -3089,9 +3094,7 @@ impl GlobalScope {
.borrow() .borrow()
.as_ref() .as_ref()
.unwrap() .unwrap()
.set(frozen_types); .set(retval.get());
frozen_types
} }
pub fn is_headless(&self) -> bool { pub fn is_headless(&self) -> bool {
@ -3372,7 +3375,8 @@ impl GlobalScope {
cx: SafeJSContext, cx: SafeJSContext,
value: HandleValue, value: HandleValue,
options: RootedTraceableBox<StructuredSerializeOptions>, options: RootedTraceableBox<StructuredSerializeOptions>,
) -> Fallible<js::jsval::JSVal> { retval: MutableHandleValue,
) -> Fallible<()> {
let mut rooted = CustomAutoRooter::new( let mut rooted = CustomAutoRooter::new(
options options
.transfer .transfer
@ -3384,12 +3388,9 @@ impl GlobalScope {
let data = structuredclone::write(cx, value, Some(guard))?; let data = structuredclone::write(cx, value, Some(guard))?;
rooted!(in(*cx) let mut message_clone = UndefinedValue()); structuredclone::read(self, data, retval).map_err(|_| Error::DataClone)?;
structuredclone::read(self, data, message_clone.handle_mut()) Ok(())
.map_err(|_| Error::DataClone)?;
Ok(message_clone.get())
} }
pub(crate) fn fetch<Listener: FetchResponseListener + PreInvoke + Send + 'static>( pub(crate) fn fetch<Listener: FetchResponseListener + PreInvoke + Send + 'static>(

View file

@ -3,7 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use dom_struct::dom_struct; use dom_struct::dom_struct;
use js::jsval::JSVal; use js::rust::MutableHandleValue;
use webgpu::ShaderCompilationInfo; use webgpu::ShaderCompilationInfo;
use super::bindings::codegen::Bindings::WebGPUBinding::GPUCompilationInfoMethods; use super::bindings::codegen::Bindings::WebGPUBinding::GPUCompilationInfoMethods;
@ -58,7 +58,7 @@ impl GPUCompilationInfo {
impl GPUCompilationInfoMethods for GPUCompilationInfo { impl GPUCompilationInfoMethods for GPUCompilationInfo {
/// <https://gpuweb.github.io/gpuweb/#dom-gpucompilationinfo-messages> /// <https://gpuweb.github.io/gpuweb/#dom-gpucompilationinfo-messages>
fn Messages(&self, cx: JSContext) -> JSVal { fn Messages(&self, cx: JSContext, retval: MutableHandleValue) {
to_frozen_array(self.msg.as_slice(), cx) to_frozen_array(self.msg.as_slice(), cx, retval)
} }
} }

View file

@ -9,7 +9,7 @@ use base::id::HistoryStateId;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use js::jsapi::Heap; use js::jsapi::Heap;
use js::jsval::{JSVal, NullValue, UndefinedValue}; use js::jsval::{JSVal, NullValue, UndefinedValue};
use js::rust::HandleValue; use js::rust::{HandleValue, MutableHandleValue};
use net_traits::{CoreResourceMsg, IpcSend}; use net_traits::{CoreResourceMsg, IpcSend};
use profile_traits::ipc; use profile_traits::ipc;
use profile_traits::ipc::channel; use profile_traits::ipc::channel;
@ -289,11 +289,12 @@ impl History {
impl HistoryMethods for History { impl HistoryMethods for History {
/// <https://html.spec.whatwg.org/multipage/#dom-history-state> /// <https://html.spec.whatwg.org/multipage/#dom-history-state>
fn GetState(&self, _cx: JSContext) -> Fallible<JSVal> { fn GetState(&self, _cx: JSContext, mut retval: MutableHandleValue) -> Fallible<()> {
if !self.window.Document().is_fully_active() { if !self.window.Document().is_fully_active() {
return Err(Error::Security); return Err(Error::Security);
} }
Ok(self.state.get()) retval.set(self.state.get());
Ok(())
} }
/// <https://html.spec.whatwg.org/multipage/#dom-history-length> /// <https://html.spec.whatwg.org/multipage/#dom-history-length>

View file

@ -5,8 +5,7 @@
use std::rc::Rc; use std::rc::Rc;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use js::jsval::{JSVal, NullValue}; use js::rust::{HandleObject, MutableHandleValue};
use js::rust::HandleObject;
use super::bindings::codegen::Bindings::IntersectionObserverBinding::{ use super::bindings::codegen::Bindings::IntersectionObserverBinding::{
IntersectionObserverCallback, IntersectionObserverMethods, IntersectionObserverCallback, IntersectionObserverMethods,
@ -93,9 +92,7 @@ impl IntersectionObserverMethods for IntersectionObserver {
/// > constructor, or the sequence is empty, the value of this attribute will be [0]. /// > constructor, or the sequence is empty, the value of this attribute will be [0].
/// ///
/// <https://w3c.github.io/IntersectionObserver/#dom-intersectionobserver-thresholds> /// <https://w3c.github.io/IntersectionObserver/#dom-intersectionobserver-thresholds>
fn Thresholds(&self, _context: JSContext) -> JSVal { fn Thresholds(&self, _context: JSContext, _retval: MutableHandleValue) {}
NullValue()
}
/// > A number indicating the minimum delay in milliseconds between notifications from /// > A number indicating the minimum delay in milliseconds between notifications from
/// > this observer for a given target. /// > this observer for a given target.

View file

@ -666,14 +666,3 @@ macro_rules! impl_rare_data (
} }
); );
); );
#[macro_export]
macro_rules! optional_root_object_to_js_or_null {
($cx: expr, $binding:expr) => {{
rooted!(in($cx) let mut rval = NullValue());
if let Some(object) = $binding {
object.to_jsval($cx, rval.handle_mut());
}
rval.get()
}};
}

View file

@ -5,7 +5,7 @@
use dom_struct::dom_struct; use dom_struct::dom_struct;
use js::jsapi::Heap; use js::jsapi::Heap;
use js::jsval::JSVal; use js::jsval::JSVal;
use js::rust::{HandleObject, HandleValue}; use js::rust::{HandleObject, HandleValue, MutableHandleValue};
use servo_atoms::Atom; use servo_atoms::Atom;
use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::cell::DomRefCell;
@ -266,8 +266,8 @@ impl MessageEventMethods for MessageEvent {
} }
/// <https://html.spec.whatwg.org/multipage/#dom-messageevent-data> /// <https://html.spec.whatwg.org/multipage/#dom-messageevent-data>
fn Data(&self, _cx: JSContext) -> JSVal { fn Data(&self, _cx: JSContext, mut retval: MutableHandleValue) {
self.data.get() retval.set(self.data.get())
} }
/// <https://html.spec.whatwg.org/multipage/#dom-messageevent-origin> /// <https://html.spec.whatwg.org/multipage/#dom-messageevent-origin>
@ -302,9 +302,10 @@ impl MessageEventMethods for MessageEvent {
} }
/// <https://html.spec.whatwg.org/multipage/#dom-messageevent-ports> /// <https://html.spec.whatwg.org/multipage/#dom-messageevent-ports>
fn Ports(&self, cx: JSContext) -> JSVal { fn Ports(&self, cx: JSContext, mut retval: MutableHandleValue) {
if let Some(ports) = &*self.frozen_ports.borrow() { if let Some(ports) = &*self.frozen_ports.borrow() {
return ports.get(); retval.set(ports.get());
return;
} }
let ports: Vec<DomRoot<MessagePort>> = self let ports: Vec<DomRoot<MessagePort>> = self
@ -313,7 +314,7 @@ impl MessageEventMethods for MessageEvent {
.iter() .iter()
.map(|port| DomRoot::from_ref(&**port)) .map(|port| DomRoot::from_ref(&**port))
.collect(); .collect();
let frozen_ports = to_frozen_array(ports.as_slice(), cx); to_frozen_array(ports.as_slice(), cx, retval);
// Safety: need to create the Heap value in its final memory location before setting it. // Safety: need to create the Heap value in its final memory location before setting it.
*self.frozen_ports.borrow_mut() = Some(Heap::default()); *self.frozen_ports.borrow_mut() = Some(Heap::default());
@ -321,9 +322,7 @@ impl MessageEventMethods for MessageEvent {
.borrow() .borrow()
.as_ref() .as_ref()
.unwrap() .unwrap()
.set(frozen_ports); .set(retval.get());
frozen_ports
} }
/// <https://html.spec.whatwg.org/multipage/#dom-messageevent-initmessageevent> /// <https://html.spec.whatwg.org/multipage/#dom-messageevent-initmessageevent>

View file

@ -7,7 +7,7 @@ use std::convert::TryInto;
use std::sync::LazyLock; use std::sync::LazyLock;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use js::jsval::JSVal; use js::rust::MutableHandleValue;
use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::NavigatorBinding::NavigatorMethods; use crate::dom::bindings::codegen::Bindings::NavigatorBinding::NavigatorMethods;
@ -199,8 +199,8 @@ impl NavigatorMethods for Navigator {
// https://html.spec.whatwg.org/multipage/#dom-navigator-languages // https://html.spec.whatwg.org/multipage/#dom-navigator-languages
#[allow(unsafe_code)] #[allow(unsafe_code)]
fn Languages(&self, cx: JSContext) -> JSVal { fn Languages(&self, cx: JSContext, retval: MutableHandleValue) {
to_frozen_array(&[self.Language()], cx) to_frozen_array(&[self.Language()], cx, retval)
} }
// https://html.spec.whatwg.org/multipage/#dom-navigator-plugins // https://html.spec.whatwg.org/multipage/#dom-navigator-plugins

View file

@ -6,8 +6,7 @@ use std::cell::Cell;
use std::rc::Rc; use std::rc::Rc;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use js::jsval::JSVal; use js::rust::{HandleObject, MutableHandleValue};
use js::rust::HandleObject;
use crate::dom::bindings::callback::ExceptionHandling; use crate::dom::bindings::callback::ExceptionHandling;
use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::cell::DomRefCell;
@ -137,10 +136,10 @@ impl PerformanceObserverMethods for PerformanceObserver {
} }
// https://w3c.github.io/performance-timeline/#supportedentrytypes-attribute // https://w3c.github.io/performance-timeline/#supportedentrytypes-attribute
fn SupportedEntryTypes(cx: JSContext, global: &GlobalScope) -> JSVal { fn SupportedEntryTypes(cx: JSContext, global: &GlobalScope, retval: MutableHandleValue) {
// While this is exposed through a method of PerformanceObserver, // While this is exposed through a method of PerformanceObserver,
// it is specified as associated with the global scope. // it is specified as associated with the global scope.
global.supported_performance_entry_types(cx) global.supported_performance_entry_types(cx, retval)
} }
// https://w3c.github.io/performance-timeline/#dom-performanceobserver-observe() // https://w3c.github.io/performance-timeline/#dom-performanceobserver-observe()

View file

@ -5,7 +5,7 @@
use dom_struct::dom_struct; use dom_struct::dom_struct;
use js::jsapi::Heap; use js::jsapi::Heap;
use js::jsval::JSVal; use js::jsval::JSVal;
use js::rust::{HandleObject, HandleValue}; use js::rust::{HandleObject, HandleValue, MutableHandleValue};
use servo_atoms::Atom; use servo_atoms::Atom;
use crate::dom::bindings::codegen::Bindings::EventBinding::EventMethods; use crate::dom::bindings::codegen::Bindings::EventBinding::EventMethods;
@ -102,8 +102,8 @@ impl PopStateEventMethods for PopStateEvent {
} }
// https://html.spec.whatwg.org/multipage/#dom-popstateevent-state // https://html.spec.whatwg.org/multipage/#dom-popstateevent-state
fn State(&self, _cx: JSContext) -> JSVal { fn State(&self, _cx: JSContext, mut retval: MutableHandleValue) {
self.state.get() retval.set(self.state.get())
} }
// https://dom.spec.whatwg.org/#dom-event-istrusted // https://dom.spec.whatwg.org/#dom-event-istrusted

View file

@ -8,7 +8,7 @@ use std::rc::Rc;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use js::jsapi::{Heap, JSObject}; use js::jsapi::{Heap, JSObject};
use js::jsval::JSVal; use js::jsval::JSVal;
use js::rust::{HandleObject, HandleValue}; use js::rust::{HandleObject, HandleValue, MutableHandleValue};
use servo_atoms::Atom; use servo_atoms::Atom;
use crate::dom::bindings::codegen::Bindings::EventBinding::EventMethods; use crate::dom::bindings::codegen::Bindings::EventBinding::EventMethods;
@ -127,8 +127,8 @@ impl PromiseRejectionEventMethods for PromiseRejectionEvent {
} }
// https://html.spec.whatwg.org/multipage/#dom-promiserejectionevent-reason // https://html.spec.whatwg.org/multipage/#dom-promiserejectionevent-reason
fn Reason(&self, _cx: JSContext) -> JSVal { fn Reason(&self, _cx: JSContext, mut retval: MutableHandleValue) {
self.reason.get() retval.set(self.reason.get())
} }
// https://dom.spec.whatwg.org/#dom-event-istrusted // https://dom.spec.whatwg.org/#dom-event-istrusted

View file

@ -3,7 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use dom_struct::dom_struct; use dom_struct::dom_struct;
use js::jsval::JSVal; use js::rust::MutableHandleValue;
use crate::dom::bindings::codegen::Bindings::ResizeObserverEntryBinding::ResizeObserverEntryMethods; use crate::dom::bindings::codegen::Bindings::ResizeObserverEntryBinding::ResizeObserverEntryMethods;
use crate::dom::bindings::reflector::{reflect_dom_object_with_proto, Reflector}; use crate::dom::bindings::reflector::{reflect_dom_object_with_proto, Reflector};
@ -90,32 +90,32 @@ impl ResizeObserverEntryMethods for ResizeObserverEntry {
} }
/// <https://drafts.csswg.org/resize-observer/#dom-resizeobserverentry-borderboxsize> /// <https://drafts.csswg.org/resize-observer/#dom-resizeobserverentry-borderboxsize>
fn BorderBoxSize(&self, cx: SafeJSContext) -> JSVal { fn BorderBoxSize(&self, cx: SafeJSContext, retval: MutableHandleValue) {
let sizes: Vec<DomRoot<ResizeObserverSize>> = self let sizes: Vec<DomRoot<ResizeObserverSize>> = self
.border_box_size .border_box_size
.iter() .iter()
.map(|size| DomRoot::from_ref(&**size)) .map(|size| DomRoot::from_ref(&**size))
.collect(); .collect();
to_frozen_array(sizes.as_slice(), cx) to_frozen_array(sizes.as_slice(), cx, retval)
} }
/// <https://drafts.csswg.org/resize-observer/#dom-resizeobserverentry-contentboxsize> /// <https://drafts.csswg.org/resize-observer/#dom-resizeobserverentry-contentboxsize>
fn ContentBoxSize(&self, cx: SafeJSContext) -> JSVal { fn ContentBoxSize(&self, cx: SafeJSContext, retval: MutableHandleValue) {
let sizes: Vec<DomRoot<ResizeObserverSize>> = self let sizes: Vec<DomRoot<ResizeObserverSize>> = self
.content_box_size .content_box_size
.iter() .iter()
.map(|size| DomRoot::from_ref(&**size)) .map(|size| DomRoot::from_ref(&**size))
.collect(); .collect();
to_frozen_array(sizes.as_slice(), cx) to_frozen_array(sizes.as_slice(), cx, retval);
} }
/// <https://drafts.csswg.org/resize-observer/#dom-resizeobserverentry-devicepixelcontentboxsize> /// <https://drafts.csswg.org/resize-observer/#dom-resizeobserverentry-devicepixelcontentboxsize>
fn DevicePixelContentBoxSize(&self, cx: SafeJSContext) -> JSVal { fn DevicePixelContentBoxSize(&self, cx: SafeJSContext, retval: MutableHandleValue) {
let sizes: Vec<DomRoot<ResizeObserverSize>> = self let sizes: Vec<DomRoot<ResizeObserverSize>> = self
.device_pixel_content_box_size .device_pixel_content_box_size
.iter() .iter()
.map(|size| DomRoot::from_ref(&**size)) .map(|size| DomRoot::from_ref(&**size))
.collect(); .collect();
to_frozen_array(sizes.as_slice(), cx) to_frozen_array(sizes.as_slice(), cx, retval);
} }
} }

View file

@ -11,8 +11,8 @@ use std::time::Duration;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use js::jsapi::{Heap, JSObject, JS_NewPlainObject}; use js::jsapi::{Heap, JSObject, JS_NewPlainObject};
use js::jsval::{JSVal, NullValue}; use js::jsval::JSVal;
use js::rust::{CustomAutoRooterGuard, HandleObject, HandleValue}; use js::rust::{CustomAutoRooterGuard, HandleObject, HandleValue, MutableHandleValue};
use js::typedarray::{self, Uint8ClampedArray}; use js::typedarray::{self, Uint8ClampedArray};
use script_traits::serializable::BlobImpl; use script_traits::serializable::BlobImpl;
use servo_config::prefs; use servo_config::prefs;
@ -229,9 +229,7 @@ impl TestBindingMethods for TestBinding {
create_buffer_source(cx, &data, array.handle_mut()) create_buffer_source(cx, &data, array.handle_mut())
.expect("Creating ClampedU8 array should never fail") .expect("Creating ClampedU8 array should never fail")
} }
fn AnyAttribute(&self, _: SafeJSContext) -> JSVal { fn AnyAttribute(&self, _: SafeJSContext, _: MutableHandleValue) {}
NullValue()
}
fn SetAnyAttribute(&self, _: SafeJSContext, _: HandleValue) {} fn SetAnyAttribute(&self, _: SafeJSContext, _: HandleValue) {}
#[allow(unsafe_code)] #[allow(unsafe_code)]
fn ObjectAttribute(&self, cx: SafeJSContext) -> NonNull<JSObject> { fn ObjectAttribute(&self, cx: SafeJSContext) -> NonNull<JSObject> {
@ -426,9 +424,7 @@ impl TestBindingMethods for TestBinding {
can_gc, can_gc,
) )
} }
fn ReceiveAny(&self, _: SafeJSContext) -> JSVal { fn ReceiveAny(&self, _: SafeJSContext, _: MutableHandleValue) {}
NullValue()
}
fn ReceiveObject(&self, cx: SafeJSContext) -> NonNull<JSObject> { fn ReceiveObject(&self, cx: SafeJSContext) -> NonNull<JSObject> {
self.ObjectAttribute(cx) self.ObjectAttribute(cx)
} }

View file

@ -16,11 +16,8 @@ use dom_struct::dom_struct;
use euclid::default::{Point2D, Rect, Size2D}; use euclid::default::{Point2D, Rect, Size2D};
use ipc_channel::ipc::{self, IpcSharedMemory}; use ipc_channel::ipc::{self, IpcSharedMemory};
use js::jsapi::{JSObject, Type}; use js::jsapi::{JSObject, Type};
use js::jsval::{ use js::jsval::{BooleanValue, DoubleValue, Int32Value, NullValue, ObjectValue, UInt32Value};
BooleanValue, DoubleValue, Int32Value, JSVal, NullValue, ObjectValue, UInt32Value, use js::rust::{CustomAutoRooterGuard, HandleObject, MutableHandleValue};
UndefinedValue,
};
use js::rust::{CustomAutoRooterGuard, HandleObject};
use js::typedarray::{ArrayBufferView, CreateWith, Float32, Int32Array, Uint32, Uint32Array}; use js::typedarray::{ArrayBufferView, CreateWith, Float32, Int32Array, Uint32, Uint32Array};
use script_layout_interface::HTMLCanvasDataSource; use script_layout_interface::HTMLCanvasDataSource;
use servo_config::pref; use servo_config::pref;
@ -591,14 +588,20 @@ impl WebGL2RenderingContext {
} }
#[allow(unsafe_code)] #[allow(unsafe_code)]
fn get_default_fb_attachment_param(&self, attachment: u32, pname: u32) -> WebGLResult<JSVal> { fn get_default_fb_attachment_param(
&self,
attachment: u32,
pname: u32,
mut retval: MutableHandleValue,
) -> WebGLResult<()> {
match attachment { match attachment {
constants::BACK | constants::DEPTH | constants::STENCIL => {}, constants::BACK | constants::DEPTH | constants::STENCIL => {},
_ => return Err(InvalidEnum), _ => return Err(InvalidEnum),
} }
if pname == constants::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME { if pname == constants::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME {
return Ok(NullValue()); retval.set(NullValue());
return Ok(());
} }
let attrs = self let attrs = self
@ -646,7 +649,8 @@ impl WebGL2RenderingContext {
}, },
_ => return Err(InvalidEnum), _ => return Err(InvalidEnum),
}; };
Ok(Int32Value(intval)) retval.set(Int32Value(intval));
Ok(())
} }
#[allow(unsafe_code)] #[allow(unsafe_code)]
@ -657,7 +661,8 @@ impl WebGL2RenderingContext {
target: u32, target: u32,
attachment: u32, attachment: u32,
pname: u32, pname: u32,
) -> WebGLResult<JSVal> { mut rval: MutableHandleValue,
) -> WebGLResult<()> {
use crate::dom::webglframebuffer::WebGLFramebufferAttachmentRoot::{Renderbuffer, Texture}; use crate::dom::webglframebuffer::WebGLFramebufferAttachmentRoot::{Renderbuffer, Texture};
match attachment { match attachment {
@ -692,17 +697,16 @@ impl WebGL2RenderingContext {
}; };
if pname == constants::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME { if pname == constants::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME {
rooted!(in(*cx) let mut rval = NullValue());
match fb.attachment(attachment) { match fb.attachment(attachment) {
Some(Renderbuffer(rb)) => unsafe { Some(Renderbuffer(rb)) => unsafe {
rb.to_jsval(*cx, rval.handle_mut()); rb.to_jsval(*cx, rval);
}, },
Some(Texture(texture)) => unsafe { Some(Texture(texture)) => unsafe {
texture.to_jsval(*cx, rval.handle_mut()); texture.to_jsval(*cx, rval);
}, },
_ => {}, _ => rval.set(NullValue()),
} }
return Ok(rval.get()); return Ok(());
} }
match pname { match pname {
@ -738,7 +742,8 @@ impl WebGL2RenderingContext {
)); ));
let retval = receiver.recv().unwrap(); let retval = receiver.recv().unwrap();
Ok(Int32Value(retval)) rval.set(Int32Value(retval));
Ok(())
} }
fn clearbuffer_array_size(&self, buffer: u32, draw_buffer: i32) -> WebGLResult<usize> { fn clearbuffer_array_size(&self, buffer: u32, draw_buffer: i32) -> WebGLResult<usize> {
@ -931,101 +936,108 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
} }
/// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5> /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5>
fn GetBufferParameter(&self, _cx: JSContext, target: u32, parameter: u32) -> JSVal { fn GetBufferParameter(
let buffer = &self,
handle_potential_webgl_error!(self.base, self.bound_buffer(target), return NullValue()); _cx: JSContext,
self.base.get_buffer_param(buffer, parameter) target: u32,
parameter: u32,
mut retval: MutableHandleValue,
) {
let buffer = handle_potential_webgl_error!(
self.base,
self.bound_buffer(target),
return retval.set(NullValue())
);
self.base.get_buffer_param(buffer, parameter, retval)
} }
#[allow(unsafe_code)] #[allow(unsafe_code)]
/// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3> /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
fn GetParameter(&self, cx: JSContext, parameter: u32) -> JSVal { fn GetParameter(&self, cx: JSContext, parameter: u32, mut rval: MutableHandleValue) {
match parameter { match parameter {
constants::VERSION => unsafe { constants::VERSION => unsafe {
rooted!(in(*cx) let mut rval = UndefinedValue()); "WebGL 2.0".to_jsval(*cx, rval);
"WebGL 2.0".to_jsval(*cx, rval.handle_mut()); return;
return rval.get();
}, },
constants::SHADING_LANGUAGE_VERSION => unsafe { constants::SHADING_LANGUAGE_VERSION => unsafe {
rooted!(in(*cx) let mut rval = UndefinedValue()); "WebGL GLSL ES 3.00".to_jsval(*cx, rval);
"WebGL GLSL ES 3.00".to_jsval(*cx, rval.handle_mut()); return;
return rval.get();
}, },
constants::MAX_CLIENT_WAIT_TIMEOUT_WEBGL => { constants::MAX_CLIENT_WAIT_TIMEOUT_WEBGL => {
return DoubleValue( rval.set(DoubleValue(
self.base.limits().max_client_wait_timeout_webgl.as_nanos() as f64 self.base.limits().max_client_wait_timeout_webgl.as_nanos() as f64,
); ));
return;
}, },
constants::MAX_SERVER_WAIT_TIMEOUT => { constants::MAX_SERVER_WAIT_TIMEOUT => {
return DoubleValue(self.base.limits().max_server_wait_timeout.as_nanos() as f64); rval.set(DoubleValue(
self.base.limits().max_server_wait_timeout.as_nanos() as f64,
));
return;
}, },
constants::SAMPLER_BINDING => unsafe { constants::SAMPLER_BINDING => unsafe {
let idx = (self.base.textures().active_unit_enum() - constants::TEXTURE0) as usize; let idx = (self.base.textures().active_unit_enum() - constants::TEXTURE0) as usize;
assert!(idx < self.samplers.len()); assert!(idx < self.samplers.len());
let sampler = self.samplers[idx].get(); let sampler = self.samplers[idx].get();
return optional_root_object_to_js_or_null!(*cx, sampler); sampler.to_jsval(*cx, rval);
return;
}, },
constants::COPY_READ_BUFFER_BINDING => unsafe { constants::COPY_READ_BUFFER_BINDING => unsafe {
return optional_root_object_to_js_or_null!( self.bound_copy_read_buffer.get().to_jsval(*cx, rval);
*cx, return;
&self.bound_copy_read_buffer.get()
);
}, },
constants::COPY_WRITE_BUFFER_BINDING => unsafe { constants::COPY_WRITE_BUFFER_BINDING => unsafe {
return optional_root_object_to_js_or_null!( self.bound_copy_write_buffer.get().to_jsval(*cx, rval);
*cx, return;
&self.bound_copy_write_buffer.get()
);
}, },
constants::PIXEL_PACK_BUFFER_BINDING => unsafe { constants::PIXEL_PACK_BUFFER_BINDING => unsafe {
return optional_root_object_to_js_or_null!( self.bound_pixel_pack_buffer.get().to_jsval(*cx, rval);
*cx, return;
&self.bound_pixel_pack_buffer.get()
);
}, },
constants::PIXEL_UNPACK_BUFFER_BINDING => unsafe { constants::PIXEL_UNPACK_BUFFER_BINDING => unsafe {
return optional_root_object_to_js_or_null!( self.bound_pixel_unpack_buffer.get().to_jsval(*cx, rval);
*cx, return;
&self.bound_pixel_unpack_buffer.get()
);
}, },
constants::TRANSFORM_FEEDBACK_BUFFER_BINDING => unsafe { constants::TRANSFORM_FEEDBACK_BUFFER_BINDING => unsafe {
return optional_root_object_to_js_or_null!( self.bound_transform_feedback_buffer
*cx, .get()
&self.bound_transform_feedback_buffer.get() .to_jsval(*cx, rval);
); return;
}, },
constants::UNIFORM_BUFFER_BINDING => unsafe { constants::UNIFORM_BUFFER_BINDING => unsafe {
return optional_root_object_to_js_or_null!(*cx, &self.bound_uniform_buffer.get()); self.bound_uniform_buffer.get().to_jsval(*cx, rval);
return;
}, },
constants::TRANSFORM_FEEDBACK_BINDING => unsafe { constants::TRANSFORM_FEEDBACK_BINDING => unsafe {
return optional_root_object_to_js_or_null!( self.current_transform_feedback.get().to_jsval(*cx, rval);
*cx, return;
self.current_transform_feedback.get()
);
}, },
constants::ELEMENT_ARRAY_BUFFER_BINDING => unsafe { constants::ELEMENT_ARRAY_BUFFER_BINDING => unsafe {
let buffer = self.current_vao().element_array_buffer().get(); let buffer = self.current_vao().element_array_buffer().get();
return optional_root_object_to_js_or_null!(*cx, buffer); buffer.to_jsval(*cx, rval);
return;
}, },
constants::VERTEX_ARRAY_BINDING => unsafe { constants::VERTEX_ARRAY_BINDING => unsafe {
let vao = self.current_vao(); let vao = self.current_vao();
let vao = vao.id().map(|_| &*vao); let vao = vao.id().map(|_| &*vao);
return optional_root_object_to_js_or_null!(*cx, vao); vao.to_jsval(*cx, rval);
return;
}, },
// NOTE: DRAW_FRAMEBUFFER_BINDING is the same as FRAMEBUFFER_BINDING, handled on the WebGL1 side // NOTE: DRAW_FRAMEBUFFER_BINDING is the same as FRAMEBUFFER_BINDING, handled on the WebGL1 side
constants::READ_FRAMEBUFFER_BINDING => unsafe { constants::READ_FRAMEBUFFER_BINDING => unsafe {
return optional_root_object_to_js_or_null!( self.base
*cx, .get_read_framebuffer_slot()
&self.base.get_read_framebuffer_slot().get() .get()
); .to_jsval(*cx, rval);
return;
}, },
constants::READ_BUFFER => { constants::READ_BUFFER => {
let buffer = match self.base.get_read_framebuffer_slot().get() { let buffer = match self.base.get_read_framebuffer_slot().get() {
Some(fb) => fb.read_buffer(), Some(fb) => fb.read_buffer(),
None => self.default_fb_readbuffer.get(), None => self.default_fb_readbuffer.get(),
}; };
return UInt32Value(buffer); rval.set(UInt32Value(buffer));
return;
}, },
constants::DRAW_BUFFER0..=constants::DRAW_BUFFER15 => { constants::DRAW_BUFFER0..=constants::DRAW_BUFFER15 => {
let buffer = match self.base.get_read_framebuffer_slot().get() { let buffer = match self.base.get_read_framebuffer_slot().get() {
@ -1038,29 +1050,38 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
}, },
None => constants::NONE, None => constants::NONE,
}; };
return UInt32Value(buffer); rval.set(UInt32Value(buffer));
return;
}, },
constants::MAX_TEXTURE_LOD_BIAS => { constants::MAX_TEXTURE_LOD_BIAS => {
return DoubleValue(self.base.limits().max_texture_lod_bias as f64) rval.set(DoubleValue(self.base.limits().max_texture_lod_bias as f64));
return;
}, },
constants::MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS => { constants::MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS => {
return DoubleValue( rval.set(DoubleValue(
self.base.limits().max_combined_fragment_uniform_components as f64, self.base.limits().max_combined_fragment_uniform_components as f64,
) ));
return;
}, },
constants::MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS => { constants::MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS => {
return DoubleValue( rval.set(DoubleValue(
self.base.limits().max_combined_vertex_uniform_components as f64, self.base.limits().max_combined_vertex_uniform_components as f64,
) ));
return;
}, },
constants::MAX_ELEMENT_INDEX => { constants::MAX_ELEMENT_INDEX => {
return DoubleValue(self.base.limits().max_element_index as f64) rval.set(DoubleValue(self.base.limits().max_element_index as f64));
return;
}, },
constants::MAX_UNIFORM_BLOCK_SIZE => { constants::MAX_UNIFORM_BLOCK_SIZE => {
return DoubleValue(self.base.limits().max_uniform_block_size as f64) rval.set(DoubleValue(
self.base.limits().max_uniform_block_size as f64,
));
return;
}, },
constants::MIN_PROGRAM_TEXEL_OFFSET => { constants::MIN_PROGRAM_TEXEL_OFFSET => {
return Int32Value(self.base.limits().min_program_texel_offset) rval.set(Int32Value(self.base.limits().min_program_texel_offset));
return;
}, },
_ => {}, _ => {},
} }
@ -1109,15 +1130,16 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
_ => None, _ => None,
}; };
if let Some(limit) = limit { if let Some(limit) = limit {
return UInt32Value(limit); rval.set(UInt32Value(limit));
return;
} }
self.base.GetParameter(cx, parameter) self.base.GetParameter(cx, parameter, rval)
} }
/// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8> /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8>
fn GetTexParameter(&self, cx: JSContext, target: u32, pname: u32) -> JSVal { fn GetTexParameter(&self, cx: JSContext, target: u32, pname: u32, retval: MutableHandleValue) {
self.base.GetTexParameter(cx, target, pname) self.base.GetTexParameter(cx, target, pname, retval)
} }
/// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3> /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
@ -1152,7 +1174,8 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
target: u32, target: u32,
attachment: u32, attachment: u32,
pname: u32, pname: u32,
) -> JSVal { mut rval: MutableHandleValue,
) {
let fb_slot = match target { let fb_slot = match target {
constants::FRAMEBUFFER | constants::DRAW_FRAMEBUFFER => { constants::FRAMEBUFFER | constants::DRAW_FRAMEBUFFER => {
self.base.get_draw_framebuffer_slot() self.base.get_draw_framebuffer_slot()
@ -1160,31 +1183,43 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
constants::READ_FRAMEBUFFER => self.base.get_read_framebuffer_slot(), constants::READ_FRAMEBUFFER => self.base.get_read_framebuffer_slot(),
_ => { _ => {
self.base.webgl_error(InvalidEnum); self.base.webgl_error(InvalidEnum);
return NullValue(); rval.set(NullValue());
return;
}, },
}; };
if let Some(fb) = fb_slot.get() { if let Some(fb) = fb_slot.get() {
// A selected framebuffer is bound to the target // A selected framebuffer is bound to the target
handle_potential_webgl_error!(self.base, fb.validate_transparent(), return NullValue());
handle_potential_webgl_error!( handle_potential_webgl_error!(
self.base, self.base,
self.get_specific_fb_attachment_param(cx, &fb, target, attachment, pname), fb.validate_transparent(),
NullValue() return rval.set(NullValue())
);
handle_potential_webgl_error!(
self.base,
self.get_specific_fb_attachment_param(cx, &fb, target, attachment, pname, rval),
rval.set(NullValue())
) )
} else { } else {
// The default framebuffer is bound to the target // The default framebuffer is bound to the target
handle_potential_webgl_error!( handle_potential_webgl_error!(
self.base, self.base,
self.get_default_fb_attachment_param(attachment, pname), self.get_default_fb_attachment_param(attachment, pname, rval),
NullValue() rval.set(NullValue())
) )
} }
} }
/// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.7> /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.7>
fn GetRenderbufferParameter(&self, cx: JSContext, target: u32, pname: u32) -> JSVal { fn GetRenderbufferParameter(
self.base.GetRenderbufferParameter(cx, target, pname) &self,
cx: JSContext,
target: u32,
pname: u32,
retval: MutableHandleValue,
) {
self.base
.GetRenderbufferParameter(cx, target, pname, retval)
} }
/// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3> /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3>
@ -1856,24 +1891,30 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
} }
/// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9> /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9>
fn GetProgramParameter(&self, cx: JSContext, program: &WebGLProgram, param_id: u32) -> JSVal { fn GetProgramParameter(
&self,
cx: JSContext,
program: &WebGLProgram,
param_id: u32,
mut retval: MutableHandleValue,
) {
handle_potential_webgl_error!( handle_potential_webgl_error!(
self.base, self.base,
self.base.validate_ownership(program), self.base.validate_ownership(program),
return NullValue() return retval.set(NullValue())
); );
if program.is_deleted() { if program.is_deleted() {
self.base.webgl_error(InvalidOperation); self.base.webgl_error(InvalidOperation);
return NullValue(); return retval.set(NullValue());
} }
match param_id { match param_id {
constants::TRANSFORM_FEEDBACK_VARYINGS => { constants::TRANSFORM_FEEDBACK_VARYINGS => {
Int32Value(program.transform_feedback_varyings_length()) retval.set(Int32Value(program.transform_feedback_varyings_length()))
}, },
constants::TRANSFORM_FEEDBACK_BUFFER_MODE => { constants::TRANSFORM_FEEDBACK_BUFFER_MODE => {
Int32Value(program.transform_feedback_buffer_mode()) retval.set(Int32Value(program.transform_feedback_buffer_mode()))
}, },
_ => self.base.GetProgramParameter(cx, program, param_id), _ => self.base.GetProgramParameter(cx, program, param_id, retval),
} }
} }
@ -1883,8 +1924,14 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
} }
/// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9> /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9>
fn GetShaderParameter(&self, cx: JSContext, shader: &WebGLShader, param_id: u32) -> JSVal { fn GetShaderParameter(
self.base.GetShaderParameter(cx, shader, param_id) &self,
cx: JSContext,
shader: &WebGLShader,
param_id: u32,
retval: MutableHandleValue,
) {
self.base.GetShaderParameter(cx, shader, param_id, retval)
} }
/// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9> /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9>
@ -1899,7 +1946,13 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
/// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.2> /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.2>
#[allow(unsafe_code)] #[allow(unsafe_code)]
fn GetIndexedParameter(&self, cx: JSContext, target: u32, index: u32) -> JSVal { fn GetIndexedParameter(
&self,
cx: JSContext,
target: u32,
index: u32,
mut retval: MutableHandleValue,
) {
let bindings = match target { let bindings = match target {
constants::TRANSFORM_FEEDBACK_BUFFER_BINDING | constants::TRANSFORM_FEEDBACK_BUFFER_BINDING |
constants::TRANSFORM_FEEDBACK_BUFFER_SIZE | constants::TRANSFORM_FEEDBACK_BUFFER_SIZE |
@ -1911,7 +1964,7 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
constants::UNIFORM_BUFFER_START => &self.indexed_uniform_buffer_bindings, constants::UNIFORM_BUFFER_START => &self.indexed_uniform_buffer_bindings,
_ => { _ => {
self.base.webgl_error(InvalidEnum); self.base.webgl_error(InvalidEnum);
return NullValue(); return retval.set(NullValue());
}, },
}; };
@ -1919,19 +1972,19 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
Some(binding) => binding, Some(binding) => binding,
None => { None => {
self.base.webgl_error(InvalidValue); self.base.webgl_error(InvalidValue);
return NullValue(); return retval.set(NullValue());
}, },
}; };
match target { match target {
constants::TRANSFORM_FEEDBACK_BUFFER_BINDING | constants::UNIFORM_BUFFER_BINDING => unsafe { constants::TRANSFORM_FEEDBACK_BUFFER_BINDING | constants::UNIFORM_BUFFER_BINDING => unsafe {
optional_root_object_to_js_or_null!(*cx, binding.buffer.get()) binding.buffer.get().to_jsval(*cx, retval)
}, },
constants::TRANSFORM_FEEDBACK_BUFFER_START | constants::UNIFORM_BUFFER_START => { constants::TRANSFORM_FEEDBACK_BUFFER_START | constants::UNIFORM_BUFFER_START => {
Int32Value(binding.start.get() as _) retval.set(Int32Value(binding.start.get() as _))
}, },
constants::TRANSFORM_FEEDBACK_BUFFER_SIZE | constants::UNIFORM_BUFFER_SIZE => { constants::TRANSFORM_FEEDBACK_BUFFER_SIZE | constants::UNIFORM_BUFFER_SIZE => {
Int32Value(binding.size.get() as _) retval.set(Int32Value(binding.size.get() as _))
}, },
_ => unreachable!(), _ => unreachable!(),
} }
@ -1947,8 +2000,8 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
} }
/// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9> /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9>
fn GetVertexAttrib(&self, cx: JSContext, index: u32, pname: u32) -> JSVal { fn GetVertexAttrib(&self, cx: JSContext, index: u32, pname: u32, retval: MutableHandleValue) {
self.base.GetVertexAttrib(cx, index, pname) self.base.GetVertexAttrib(cx, index, pname, retval)
} }
/// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10> /// <https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10>
@ -2709,68 +2762,88 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
cx: JSContext, cx: JSContext,
program: &WebGLProgram, program: &WebGLProgram,
location: &WebGLUniformLocation, location: &WebGLUniformLocation,
) -> JSVal { mut retval: MutableHandleValue,
) {
handle_potential_webgl_error!( handle_potential_webgl_error!(
self.base, self.base,
self.base.uniform_check_program(program, location), self.base.uniform_check_program(program, location),
return NullValue() return retval.set(NullValue())
); );
let triple = (&*self.base, program.id(), location.id()); let triple = (&*self.base, program.id(), location.id());
match location.type_() { match location.type_() {
constants::UNSIGNED_INT => { constants::UNSIGNED_INT => retval.set(UInt32Value(uniform_get(
UInt32Value(uniform_get(triple, WebGLCommand::GetUniformUint)) triple,
}, WebGLCommand::GetUniformUint,
))),
constants::UNSIGNED_INT_VEC2 => unsafe { constants::UNSIGNED_INT_VEC2 => unsafe {
uniform_typed::<Uint32>(*cx, &uniform_get(triple, WebGLCommand::GetUniformUint2)) uniform_typed::<Uint32>(
*cx,
&uniform_get(triple, WebGLCommand::GetUniformUint2),
retval,
)
}, },
constants::UNSIGNED_INT_VEC3 => unsafe { constants::UNSIGNED_INT_VEC3 => unsafe {
uniform_typed::<Uint32>(*cx, &uniform_get(triple, WebGLCommand::GetUniformUint3)) uniform_typed::<Uint32>(
*cx,
&uniform_get(triple, WebGLCommand::GetUniformUint3),
retval,
)
}, },
constants::UNSIGNED_INT_VEC4 => unsafe { constants::UNSIGNED_INT_VEC4 => unsafe {
uniform_typed::<Uint32>(*cx, &uniform_get(triple, WebGLCommand::GetUniformUint4)) uniform_typed::<Uint32>(
*cx,
&uniform_get(triple, WebGLCommand::GetUniformUint4),
retval,
)
}, },
constants::FLOAT_MAT2x3 => unsafe { constants::FLOAT_MAT2x3 => unsafe {
uniform_typed::<Float32>( uniform_typed::<Float32>(
*cx, *cx,
&uniform_get(triple, WebGLCommand::GetUniformFloat2x3), &uniform_get(triple, WebGLCommand::GetUniformFloat2x3),
retval,
) )
}, },
constants::FLOAT_MAT2x4 => unsafe { constants::FLOAT_MAT2x4 => unsafe {
uniform_typed::<Float32>( uniform_typed::<Float32>(
*cx, *cx,
&uniform_get(triple, WebGLCommand::GetUniformFloat2x4), &uniform_get(triple, WebGLCommand::GetUniformFloat2x4),
retval,
) )
}, },
constants::FLOAT_MAT3x2 => unsafe { constants::FLOAT_MAT3x2 => unsafe {
uniform_typed::<Float32>( uniform_typed::<Float32>(
*cx, *cx,
&uniform_get(triple, WebGLCommand::GetUniformFloat3x2), &uniform_get(triple, WebGLCommand::GetUniformFloat3x2),
retval,
) )
}, },
constants::FLOAT_MAT3x4 => unsafe { constants::FLOAT_MAT3x4 => unsafe {
uniform_typed::<Float32>( uniform_typed::<Float32>(
*cx, *cx,
&uniform_get(triple, WebGLCommand::GetUniformFloat3x4), &uniform_get(triple, WebGLCommand::GetUniformFloat3x4),
retval,
) )
}, },
constants::FLOAT_MAT4x2 => unsafe { constants::FLOAT_MAT4x2 => unsafe {
uniform_typed::<Float32>( uniform_typed::<Float32>(
*cx, *cx,
&uniform_get(triple, WebGLCommand::GetUniformFloat4x2), &uniform_get(triple, WebGLCommand::GetUniformFloat4x2),
retval,
) )
}, },
constants::FLOAT_MAT4x3 => unsafe { constants::FLOAT_MAT4x3 => unsafe {
uniform_typed::<Float32>( uniform_typed::<Float32>(
*cx, *cx,
&uniform_get(triple, WebGLCommand::GetUniformFloat4x3), &uniform_get(triple, WebGLCommand::GetUniformFloat4x3),
retval,
) )
}, },
constants::SAMPLER_3D | constants::SAMPLER_2D_ARRAY => { constants::SAMPLER_3D | constants::SAMPLER_2D_ARRAY => {
Int32Value(uniform_get(triple, WebGLCommand::GetUniformInt)) retval.set(Int32Value(uniform_get(triple, WebGLCommand::GetUniformInt)))
}, },
_ => self.base.GetUniform(cx, program, location), _ => self.base.GetUniform(cx, program, location, retval),
} }
} }
@ -3530,21 +3603,21 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
/// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.12> /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.12>
#[rustfmt::skip] #[rustfmt::skip]
fn GetQueryParameter(&self, _cx: JSContext, query: &WebGLQuery, pname: u32) -> JSVal { fn GetQueryParameter(&self, _cx: JSContext, query: &WebGLQuery, pname: u32, mut retval: MutableHandleValue) {
handle_potential_webgl_error!( handle_potential_webgl_error!(
self.base, self.base,
self.base.validate_ownership(query), self.base.validate_ownership(query),
return NullValue() return retval.set(NullValue())
); );
match query.get_parameter(&self.base, pname) { match query.get_parameter(&self.base, pname) {
Ok(value) => match pname { Ok(value) => match pname {
constants::QUERY_RESULT => UInt32Value(value), constants::QUERY_RESULT => retval.set(UInt32Value(value)),
constants::QUERY_RESULT_AVAILABLE => BooleanValue(value != 0), constants::QUERY_RESULT_AVAILABLE => retval.set(BooleanValue(value != 0)),
_ => unreachable!(), _ => unreachable!(),
}, },
Err(error) => { Err(error) => {
self.base.webgl_error(error); self.base.webgl_error(error);
NullValue() retval.set(NullValue())
}, },
} }
} }
@ -3631,30 +3704,36 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
} }
/// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.14> /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.14>
fn GetSyncParameter(&self, _cx: JSContext, sync: &WebGLSync, pname: u32) -> JSVal { fn GetSyncParameter(
&self,
_cx: JSContext,
sync: &WebGLSync,
pname: u32,
mut retval: MutableHandleValue,
) {
if !sync.is_valid() { if !sync.is_valid() {
self.base.webgl_error(InvalidOperation); self.base.webgl_error(InvalidOperation);
return NullValue(); return retval.set(NullValue());
} }
handle_potential_webgl_error!( handle_potential_webgl_error!(
self.base, self.base,
self.base.validate_ownership(sync), self.base.validate_ownership(sync),
return NullValue() return retval.set(NullValue())
); );
match pname { match pname {
constants::OBJECT_TYPE | constants::SYNC_CONDITION | constants::SYNC_FLAGS => { constants::OBJECT_TYPE | constants::SYNC_CONDITION | constants::SYNC_FLAGS => {
let (sender, receiver) = webgl_channel().unwrap(); let (sender, receiver) = webgl_channel().unwrap();
self.base self.base
.send_command(WebGLCommand::GetSyncParameter(sync.id(), pname, sender)); .send_command(WebGLCommand::GetSyncParameter(sync.id(), pname, sender));
UInt32Value(receiver.recv().unwrap()) retval.set(UInt32Value(receiver.recv().unwrap()))
}, },
constants::SYNC_STATUS => match sync.get_sync_status(pname, &self.base) { constants::SYNC_STATUS => match sync.get_sync_status(pname, &self.base) {
Some(status) => UInt32Value(status), Some(status) => retval.set(UInt32Value(status)),
None => UInt32Value(constants::UNSIGNALED), None => retval.set(UInt32Value(constants::UNSIGNALED)),
}, },
_ => { _ => {
self.base.webgl_error(InvalidEnum); self.base.webgl_error(InvalidEnum);
NullValue() retval.set(NullValue())
}, },
} }
} }
@ -3711,20 +3790,26 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
} }
/// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.13> /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.13>
fn GetSamplerParameter(&self, _cx: JSContext, sampler: &WebGLSampler, pname: u32) -> JSVal { fn GetSamplerParameter(
&self,
_cx: JSContext,
sampler: &WebGLSampler,
pname: u32,
mut retval: MutableHandleValue,
) {
handle_potential_webgl_error!( handle_potential_webgl_error!(
self.base, self.base,
self.base.validate_ownership(sampler), self.base.validate_ownership(sampler),
return NullValue() return retval.set(NullValue())
); );
match sampler.get_parameter(&self.base, pname) { match sampler.get_parameter(&self.base, pname) {
Ok(value) => match value { Ok(value) => match value {
WebGLSamplerValue::GLenum(value) => UInt32Value(value), WebGLSamplerValue::GLenum(value) => retval.set(UInt32Value(value)),
WebGLSamplerValue::Float(value) => DoubleValue(value as f64), WebGLSamplerValue::Float(value) => retval.set(DoubleValue(value as f64)),
}, },
Err(error) => { Err(error) => {
self.base.webgl_error(error); self.base.webgl_error(error);
NullValue() retval.set(NullValue())
}, },
} }
} }
@ -4085,19 +4170,19 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
program: &WebGLProgram, program: &WebGLProgram,
indices: Vec<u32>, indices: Vec<u32>,
pname: u32, pname: u32,
) -> JSVal { mut rval: MutableHandleValue,
) {
handle_potential_webgl_error!( handle_potential_webgl_error!(
self.base, self.base,
self.base.validate_ownership(program), self.base.validate_ownership(program),
return NullValue() return rval.set(NullValue())
); );
let values = handle_potential_webgl_error!( let values = handle_potential_webgl_error!(
self.base, self.base,
program.get_active_uniforms(indices, pname), program.get_active_uniforms(indices, pname),
return NullValue() return rval.set(NullValue())
); );
rooted!(in(*cx) let mut rval = UndefinedValue());
match pname { match pname {
constants::UNIFORM_SIZE | constants::UNIFORM_SIZE |
constants::UNIFORM_TYPE | constants::UNIFORM_TYPE |
@ -4105,15 +4190,14 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
constants::UNIFORM_OFFSET | constants::UNIFORM_OFFSET |
constants::UNIFORM_ARRAY_STRIDE | constants::UNIFORM_ARRAY_STRIDE |
constants::UNIFORM_MATRIX_STRIDE => unsafe { constants::UNIFORM_MATRIX_STRIDE => unsafe {
values.to_jsval(*cx, rval.handle_mut()); values.to_jsval(*cx, rval);
}, },
constants::UNIFORM_IS_ROW_MAJOR => unsafe { constants::UNIFORM_IS_ROW_MAJOR => unsafe {
let values = values.iter().map(|&v| v != 0).collect::<Vec<_>>(); let values = values.iter().map(|&v| v != 0).collect::<Vec<_>>();
values.to_jsval(*cx, rval.handle_mut()); values.to_jsval(*cx, rval);
}, },
_ => unreachable!(), _ => unreachable!(),
} }
rval.get()
} }
/// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.16> /// <https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.16>
@ -4138,34 +4222,35 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
program: &WebGLProgram, program: &WebGLProgram,
block_index: u32, block_index: u32,
pname: u32, pname: u32,
) -> JSVal { mut retval: MutableHandleValue,
) {
handle_potential_webgl_error!( handle_potential_webgl_error!(
self.base, self.base,
self.base.validate_ownership(program), self.base.validate_ownership(program),
return NullValue() return retval.set(NullValue())
); );
let values = handle_potential_webgl_error!( let values = handle_potential_webgl_error!(
self.base, self.base,
program.get_active_uniform_block_parameter(block_index, pname), program.get_active_uniform_block_parameter(block_index, pname),
return NullValue() return retval.set(NullValue())
); );
match pname { match pname {
constants::UNIFORM_BLOCK_BINDING | constants::UNIFORM_BLOCK_BINDING |
constants::UNIFORM_BLOCK_DATA_SIZE | constants::UNIFORM_BLOCK_DATA_SIZE |
constants::UNIFORM_BLOCK_ACTIVE_UNIFORMS => { constants::UNIFORM_BLOCK_ACTIVE_UNIFORMS => {
assert!(values.len() == 1); assert!(values.len() == 1);
UInt32Value(values[0] as u32) retval.set(UInt32Value(values[0] as u32))
}, },
constants::UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES => unsafe { constants::UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES => unsafe {
let values = values.iter().map(|&v| v as u32).collect::<Vec<_>>(); let values = values.iter().map(|&v| v as u32).collect::<Vec<_>>();
rooted!(in(*cx) let mut result = ptr::null_mut::<JSObject>()); rooted!(in(*cx) let mut result = ptr::null_mut::<JSObject>());
Uint32Array::create(*cx, CreateWith::Slice(&values), result.handle_mut()).unwrap(); Uint32Array::create(*cx, CreateWith::Slice(&values), result.handle_mut()).unwrap();
ObjectValue(result.get()) retval.set(ObjectValue(result.get()))
}, },
constants::UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER | constants::UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER |
constants::UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER => { constants::UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER => {
assert!(values.len() == 1); assert!(values.len() == 1);
BooleanValue(values[0] != 0) retval.set(BooleanValue(values[0] != 0))
}, },
_ => unreachable!(), _ => unreachable!(),
} }
@ -4367,16 +4452,17 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
target: u32, target: u32,
internal_format: u32, internal_format: u32,
pname: u32, pname: u32,
) -> JSVal { mut retval: MutableHandleValue,
) {
if target != constants::RENDERBUFFER { if target != constants::RENDERBUFFER {
self.base.webgl_error(InvalidEnum); self.base.webgl_error(InvalidEnum);
return NullValue(); return retval.set(NullValue());
} }
match handle_potential_webgl_error!( match handle_potential_webgl_error!(
self.base, self.base,
InternalFormatParameter::from_u32(pname), InternalFormatParameter::from_u32(pname),
return NullValue() return retval.set(NullValue())
) { ) {
InternalFormatParameter::IntVec(param) => unsafe { InternalFormatParameter::IntVec(param) => unsafe {
let (sender, receiver) = webgl_channel().unwrap(); let (sender, receiver) = webgl_channel().unwrap();
@ -4395,7 +4481,7 @@ impl WebGL2RenderingContextMethods for WebGL2RenderingContext {
rval.handle_mut(), rval.handle_mut(),
) )
.unwrap(); .unwrap();
ObjectValue(rval.get()) retval.set(ObjectValue(rval.get()))
}, },
} }
} }

View file

@ -22,11 +22,8 @@ use dom_struct::dom_struct;
use euclid::default::{Point2D, Rect, Size2D}; use euclid::default::{Point2D, Rect, Size2D};
use ipc_channel::ipc::{self, IpcSharedMemory}; use ipc_channel::ipc::{self, IpcSharedMemory};
use js::jsapi::{JSContext, JSObject, Type}; use js::jsapi::{JSContext, JSObject, Type};
use js::jsval::{ use js::jsval::{BooleanValue, DoubleValue, Int32Value, NullValue, ObjectValue, UInt32Value};
BooleanValue, DoubleValue, Int32Value, JSVal, NullValue, ObjectValue, UInt32Value, use js::rust::{CustomAutoRooterGuard, MutableHandleValue};
UndefinedValue,
};
use js::rust::CustomAutoRooterGuard;
use js::typedarray::{ use js::typedarray::{
ArrayBufferView, CreateWith, Float32, Float32Array, Int32, Int32Array, TypedArray, ArrayBufferView, CreateWith, Float32, Float32Array, Int32, Int32Array, TypedArray,
TypedArrayElementCreator, Uint32Array, TypedArrayElementCreator, Uint32Array,
@ -131,14 +128,17 @@ where
} }
#[allow(unsafe_code)] #[allow(unsafe_code)]
pub unsafe fn uniform_typed<T>(cx: *mut JSContext, value: &[T::Element]) -> JSVal pub unsafe fn uniform_typed<T>(
where cx: *mut JSContext,
value: &[T::Element],
mut retval: MutableHandleValue,
) where
T: TypedArrayElementCreator, T: TypedArrayElementCreator,
{ {
rooted!(in(cx) let mut rval = ptr::null_mut::<JSObject>()); rooted!(in(cx) let mut rval = ptr::null_mut::<JSObject>());
<TypedArray<T, *mut JSObject>>::create(cx, CreateWith::Slice(value), rval.handle_mut()) <TypedArray<T, *mut JSObject>>::create(cx, CreateWith::Slice(value), rval.handle_mut())
.unwrap(); .unwrap();
ObjectValue(rval.get()) retval.set(ObjectValue(rval.get()));
} }
/// Set of bitflags for texture unpacking (texImage2d, etc...) /// Set of bitflags for texture unpacking (texImage2d, etc...)
@ -1946,18 +1946,26 @@ impl WebGLRenderingContext {
}); });
} }
pub fn get_buffer_param(&self, buffer: Option<DomRoot<WebGLBuffer>>, parameter: u32) -> JSVal { pub fn get_buffer_param(
let buffer = &self,
handle_potential_webgl_error!(self, buffer.ok_or(InvalidOperation), return NullValue()); buffer: Option<DomRoot<WebGLBuffer>>,
parameter: u32,
mut retval: MutableHandleValue,
) {
let buffer = handle_potential_webgl_error!(
self,
buffer.ok_or(InvalidOperation),
return retval.set(NullValue())
);
match parameter { retval.set(match parameter {
constants::BUFFER_SIZE => Int32Value(buffer.capacity() as i32), constants::BUFFER_SIZE => Int32Value(buffer.capacity() as i32),
constants::BUFFER_USAGE => Int32Value(buffer.usage() as i32), constants::BUFFER_USAGE => Int32Value(buffer.usage() as i32),
_ => { _ => {
self.webgl_error(InvalidEnum); self.webgl_error(InvalidEnum);
NullValue() NullValue()
}, },
} })
} }
} }
@ -2019,42 +2027,53 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
} }
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5 // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5
fn GetBufferParameter(&self, _cx: SafeJSContext, target: u32, parameter: u32) -> JSVal { fn GetBufferParameter(
let buffer = &self,
handle_potential_webgl_error!(self, self.bound_buffer(target), return NullValue()); _cx: SafeJSContext,
self.get_buffer_param(buffer, parameter) target: u32,
parameter: u32,
mut retval: MutableHandleValue,
) {
let buffer = handle_potential_webgl_error!(
self,
self.bound_buffer(target),
return retval.set(NullValue())
);
self.get_buffer_param(buffer, parameter, retval)
} }
#[allow(unsafe_code)] #[allow(unsafe_code)]
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3 // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3
fn GetParameter(&self, cx: SafeJSContext, parameter: u32) -> JSVal { fn GetParameter(&self, cx: SafeJSContext, parameter: u32, mut retval: MutableHandleValue) {
if !self if !self
.extension_manager .extension_manager
.is_get_parameter_name_enabled(parameter) .is_get_parameter_name_enabled(parameter)
{ {
self.webgl_error(WebGLError::InvalidEnum); self.webgl_error(WebGLError::InvalidEnum);
return NullValue(); return retval.set(NullValue());
} }
match parameter { match parameter {
constants::ARRAY_BUFFER_BINDING => unsafe { constants::ARRAY_BUFFER_BINDING => unsafe {
return optional_root_object_to_js_or_null!(*cx, &self.bound_buffer_array.get()); self.bound_buffer_array.get().to_jsval(*cx, retval);
return;
}, },
constants::CURRENT_PROGRAM => unsafe { constants::CURRENT_PROGRAM => unsafe {
return optional_root_object_to_js_or_null!(*cx, &self.current_program.get()); self.current_program.get().to_jsval(*cx, retval);
return;
}, },
constants::ELEMENT_ARRAY_BUFFER_BINDING => unsafe { constants::ELEMENT_ARRAY_BUFFER_BINDING => unsafe {
let buffer = self.current_vao().element_array_buffer().get(); let buffer = self.current_vao().element_array_buffer().get();
return optional_root_object_to_js_or_null!(*cx, buffer); buffer.to_jsval(*cx, retval);
return;
}, },
constants::FRAMEBUFFER_BINDING => unsafe { constants::FRAMEBUFFER_BINDING => unsafe {
return optional_root_object_to_js_or_null!( self.bound_draw_framebuffer.get().to_jsval(*cx, retval);
*cx, return;
&self.bound_draw_framebuffer.get()
);
}, },
constants::RENDERBUFFER_BINDING => unsafe { constants::RENDERBUFFER_BINDING => unsafe {
return optional_root_object_to_js_or_null!(*cx, &self.bound_renderbuffer.get()); self.bound_renderbuffer.get().to_jsval(*cx, retval);
return;
}, },
constants::TEXTURE_BINDING_2D => unsafe { constants::TEXTURE_BINDING_2D => unsafe {
let texture = self let texture = self
@ -2062,7 +2081,8 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
.active_texture_slot(constants::TEXTURE_2D, self.webgl_version()) .active_texture_slot(constants::TEXTURE_2D, self.webgl_version())
.unwrap() .unwrap()
.get(); .get();
return optional_root_object_to_js_or_null!(*cx, texture); texture.to_jsval(*cx, retval);
return;
}, },
constants::TEXTURE_BINDING_CUBE_MAP => unsafe { constants::TEXTURE_BINDING_CUBE_MAP => unsafe {
let texture = self let texture = self
@ -2070,11 +2090,13 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
.active_texture_slot(constants::TEXTURE_CUBE_MAP, self.webgl_version()) .active_texture_slot(constants::TEXTURE_CUBE_MAP, self.webgl_version())
.unwrap() .unwrap()
.get(); .get();
return optional_root_object_to_js_or_null!(*cx, texture); texture.to_jsval(*cx, retval);
return;
}, },
OESVertexArrayObjectConstants::VERTEX_ARRAY_BINDING_OES => unsafe { OESVertexArrayObjectConstants::VERTEX_ARRAY_BINDING_OES => unsafe {
let vao = self.current_vao.get().filter(|vao| vao.id().is_some()); let vao = self.current_vao.get().filter(|vao| vao.id().is_some());
return optional_root_object_to_js_or_null!(*cx, vao); vao.to_jsval(*cx, retval);
return;
}, },
// In readPixels we currently support RGBA/UBYTE only. If // In readPixels we currently support RGBA/UBYTE only. If
// we wanted to support other formats, we could ask the // we wanted to support other formats, we could ask the
@ -2084,16 +2106,16 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
constants::IMPLEMENTATION_COLOR_READ_FORMAT => { constants::IMPLEMENTATION_COLOR_READ_FORMAT => {
if self.validate_framebuffer().is_err() { if self.validate_framebuffer().is_err() {
self.webgl_error(InvalidOperation); self.webgl_error(InvalidOperation);
return NullValue(); return retval.set(NullValue());
} }
return Int32Value(constants::RGBA as i32); return retval.set(Int32Value(constants::RGBA as i32));
}, },
constants::IMPLEMENTATION_COLOR_READ_TYPE => { constants::IMPLEMENTATION_COLOR_READ_TYPE => {
if self.validate_framebuffer().is_err() { if self.validate_framebuffer().is_err() {
self.webgl_error(InvalidOperation); self.webgl_error(InvalidOperation);
return NullValue(); return retval.set(NullValue());
} }
return Int32Value(constants::UNSIGNED_BYTE as i32); return retval.set(Int32Value(constants::UNSIGNED_BYTE as i32));
}, },
constants::COMPRESSED_TEXTURE_FORMATS => unsafe { constants::COMPRESSED_TEXTURE_FORMATS => unsafe {
let format_ids = self.extension_manager.get_tex_compression_ids(); let format_ids = self.extension_manager.get_tex_compression_ids();
@ -2101,44 +2123,50 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
rooted!(in(*cx) let mut rval = ptr::null_mut::<JSObject>()); rooted!(in(*cx) let mut rval = ptr::null_mut::<JSObject>());
Uint32Array::create(*cx, CreateWith::Slice(&format_ids), rval.handle_mut()) Uint32Array::create(*cx, CreateWith::Slice(&format_ids), rval.handle_mut())
.unwrap(); .unwrap();
return ObjectValue(rval.get()); return retval.set(ObjectValue(rval.get()));
}, },
constants::VERSION => unsafe { constants::VERSION => unsafe {
rooted!(in(*cx) let mut rval = UndefinedValue()); "WebGL 1.0".to_jsval(*cx, retval);
"WebGL 1.0".to_jsval(*cx, rval.handle_mut()); return;
return rval.get();
}, },
constants::RENDERER | constants::VENDOR => unsafe { constants::RENDERER | constants::VENDOR => unsafe {
rooted!(in(*cx) let mut rval = UndefinedValue()); "Mozilla/Servo".to_jsval(*cx, retval);
"Mozilla/Servo".to_jsval(*cx, rval.handle_mut()); return;
return rval.get();
}, },
constants::SHADING_LANGUAGE_VERSION => unsafe { constants::SHADING_LANGUAGE_VERSION => unsafe {
rooted!(in(*cx) let mut rval = UndefinedValue()); "WebGL GLSL ES 1.0".to_jsval(*cx, retval);
"WebGL GLSL ES 1.0".to_jsval(*cx, rval.handle_mut()); return;
return rval.get();
}, },
constants::UNPACK_FLIP_Y_WEBGL => { constants::UNPACK_FLIP_Y_WEBGL => {
let unpack = self.texture_unpacking_settings.get(); let unpack = self.texture_unpacking_settings.get();
return BooleanValue(unpack.contains(TextureUnpacking::FLIP_Y_AXIS)); retval.set(BooleanValue(unpack.contains(TextureUnpacking::FLIP_Y_AXIS)));
return;
}, },
constants::UNPACK_PREMULTIPLY_ALPHA_WEBGL => { constants::UNPACK_PREMULTIPLY_ALPHA_WEBGL => {
let unpack = self.texture_unpacking_settings.get(); let unpack = self.texture_unpacking_settings.get();
return BooleanValue(unpack.contains(TextureUnpacking::PREMULTIPLY_ALPHA)); retval.set(BooleanValue(
unpack.contains(TextureUnpacking::PREMULTIPLY_ALPHA),
));
return;
}, },
constants::PACK_ALIGNMENT => { constants::PACK_ALIGNMENT => {
return UInt32Value(self.texture_packing_alignment.get() as u32); retval.set(UInt32Value(self.texture_packing_alignment.get() as u32));
return;
}, },
constants::UNPACK_ALIGNMENT => { constants::UNPACK_ALIGNMENT => {
return UInt32Value(self.texture_unpacking_alignment.get()); retval.set(UInt32Value(self.texture_unpacking_alignment.get()));
return;
}, },
constants::UNPACK_COLORSPACE_CONVERSION_WEBGL => { constants::UNPACK_COLORSPACE_CONVERSION_WEBGL => {
let unpack = self.texture_unpacking_settings.get(); let unpack = self.texture_unpacking_settings.get();
return UInt32Value(if unpack.contains(TextureUnpacking::CONVERT_COLORSPACE) { retval.set(UInt32Value(
constants::BROWSER_DEFAULT_WEBGL if unpack.contains(TextureUnpacking::CONVERT_COLORSPACE) {
} else { constants::BROWSER_DEFAULT_WEBGL
constants::NONE } else {
}); constants::NONE
},
));
return;
}, },
_ => {}, _ => {},
} }
@ -2165,34 +2193,34 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
_ => None, _ => None,
}; };
if let Some(limit) = limit { if let Some(limit) = limit {
return UInt32Value(limit); retval.set(UInt32Value(limit));
return;
} }
if let Ok(value) = self.capabilities.is_enabled(parameter) { if let Ok(value) = self.capabilities.is_enabled(parameter) {
return BooleanValue(value); retval.set(BooleanValue(value));
return;
} }
match handle_potential_webgl_error!( match handle_potential_webgl_error!(
self, self,
Parameter::from_u32(parameter), Parameter::from_u32(parameter),
return NullValue() return retval.set(NullValue())
) { ) {
Parameter::Bool(param) => { Parameter::Bool(param) => {
let (sender, receiver) = webgl_channel().unwrap(); let (sender, receiver) = webgl_channel().unwrap();
self.send_command(WebGLCommand::GetParameterBool(param, sender)); self.send_command(WebGLCommand::GetParameterBool(param, sender));
BooleanValue(receiver.recv().unwrap()) retval.set(BooleanValue(receiver.recv().unwrap()))
}, },
Parameter::Bool4(param) => unsafe { Parameter::Bool4(param) => unsafe {
let (sender, receiver) = webgl_channel().unwrap(); let (sender, receiver) = webgl_channel().unwrap();
self.send_command(WebGLCommand::GetParameterBool4(param, sender)); self.send_command(WebGLCommand::GetParameterBool4(param, sender));
rooted!(in(*cx) let mut rval = UndefinedValue()); receiver.recv().unwrap().to_jsval(*cx, retval);
receiver.recv().unwrap().to_jsval(*cx, rval.handle_mut());
rval.get()
}, },
Parameter::Int(param) => { Parameter::Int(param) => {
let (sender, receiver) = webgl_channel().unwrap(); let (sender, receiver) = webgl_channel().unwrap();
self.send_command(WebGLCommand::GetParameterInt(param, sender)); self.send_command(WebGLCommand::GetParameterInt(param, sender));
Int32Value(receiver.recv().unwrap()) retval.set(Int32Value(receiver.recv().unwrap()))
}, },
Parameter::Int2(param) => unsafe { Parameter::Int2(param) => unsafe {
let (sender, receiver) = webgl_channel().unwrap(); let (sender, receiver) = webgl_channel().unwrap();
@ -2204,7 +2232,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
rval.handle_mut(), rval.handle_mut(),
) )
.unwrap(); .unwrap();
ObjectValue(rval.get()) retval.set(ObjectValue(rval.get()))
}, },
Parameter::Int4(param) => unsafe { Parameter::Int4(param) => unsafe {
let (sender, receiver) = webgl_channel().unwrap(); let (sender, receiver) = webgl_channel().unwrap();
@ -2216,12 +2244,12 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
rval.handle_mut(), rval.handle_mut(),
) )
.unwrap(); .unwrap();
ObjectValue(rval.get()) retval.set(ObjectValue(rval.get()))
}, },
Parameter::Float(param) => { Parameter::Float(param) => {
let (sender, receiver) = webgl_channel().unwrap(); let (sender, receiver) = webgl_channel().unwrap();
self.send_command(WebGLCommand::GetParameterFloat(param, sender)); self.send_command(WebGLCommand::GetParameterFloat(param, sender));
DoubleValue(receiver.recv().unwrap() as f64) retval.set(DoubleValue(receiver.recv().unwrap() as f64))
}, },
Parameter::Float2(param) => unsafe { Parameter::Float2(param) => unsafe {
let (sender, receiver) = webgl_channel().unwrap(); let (sender, receiver) = webgl_channel().unwrap();
@ -2233,7 +2261,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
rval.handle_mut(), rval.handle_mut(),
) )
.unwrap(); .unwrap();
ObjectValue(rval.get()) retval.set(ObjectValue(rval.get()))
}, },
Parameter::Float4(param) => unsafe { Parameter::Float4(param) => unsafe {
let (sender, receiver) = webgl_channel().unwrap(); let (sender, receiver) = webgl_channel().unwrap();
@ -2245,23 +2273,29 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
rval.handle_mut(), rval.handle_mut(),
) )
.unwrap(); .unwrap();
ObjectValue(rval.get()) retval.set(ObjectValue(rval.get()))
}, },
} }
} }
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8 // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8
fn GetTexParameter(&self, _cx: SafeJSContext, target: u32, pname: u32) -> JSVal { fn GetTexParameter(
&self,
_cx: SafeJSContext,
target: u32,
pname: u32,
mut retval: MutableHandleValue,
) {
let texture_slot = handle_potential_webgl_error!( let texture_slot = handle_potential_webgl_error!(
self, self,
self.textures self.textures
.active_texture_slot(target, self.webgl_version()), .active_texture_slot(target, self.webgl_version()),
return NullValue() return retval.set(NullValue())
); );
let texture = handle_potential_webgl_error!( let texture = handle_potential_webgl_error!(
self, self,
texture_slot.get().ok_or(InvalidOperation), texture_slot.get().ok_or(InvalidOperation),
return NullValue() return retval.set(NullValue())
); );
if !self if !self
@ -2269,45 +2303,49 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
.is_get_tex_parameter_name_enabled(pname) .is_get_tex_parameter_name_enabled(pname)
{ {
self.webgl_error(InvalidEnum); self.webgl_error(InvalidEnum);
return NullValue(); return retval.set(NullValue());
} }
match pname { match pname {
constants::TEXTURE_MAG_FILTER => return UInt32Value(texture.mag_filter()), constants::TEXTURE_MAG_FILTER => return retval.set(UInt32Value(texture.mag_filter())),
constants::TEXTURE_MIN_FILTER => return UInt32Value(texture.min_filter()), constants::TEXTURE_MIN_FILTER => return retval.set(UInt32Value(texture.min_filter())),
_ => {}, _ => {},
} }
let texparam = let texparam = handle_potential_webgl_error!(
handle_potential_webgl_error!(self, TexParameter::from_u32(pname), return NullValue()); self,
TexParameter::from_u32(pname),
return retval.set(NullValue())
);
if self.webgl_version() < texparam.required_webgl_version() { if self.webgl_version() < texparam.required_webgl_version() {
self.webgl_error(InvalidEnum); self.webgl_error(InvalidEnum);
return NullValue(); return retval.set(NullValue());
} }
if let Some(value) = texture.maybe_get_tex_parameter(texparam) { if let Some(value) = texture.maybe_get_tex_parameter(texparam) {
match value { match value {
TexParameterValue::Float(v) => return DoubleValue(v as f64), TexParameterValue::Float(v) => retval.set(DoubleValue(v as f64)),
TexParameterValue::Int(v) => return Int32Value(v), TexParameterValue::Int(v) => retval.set(Int32Value(v)),
TexParameterValue::Bool(v) => return BooleanValue(v), TexParameterValue::Bool(v) => retval.set(BooleanValue(v)),
} }
return;
} }
match texparam { match texparam {
TexParameter::Float(param) => { TexParameter::Float(param) => {
let (sender, receiver) = webgl_channel().unwrap(); let (sender, receiver) = webgl_channel().unwrap();
self.send_command(WebGLCommand::GetTexParameterFloat(target, param, sender)); self.send_command(WebGLCommand::GetTexParameterFloat(target, param, sender));
DoubleValue(receiver.recv().unwrap() as f64) retval.set(DoubleValue(receiver.recv().unwrap() as f64))
}, },
TexParameter::Int(param) => { TexParameter::Int(param) => {
let (sender, receiver) = webgl_channel().unwrap(); let (sender, receiver) = webgl_channel().unwrap();
self.send_command(WebGLCommand::GetTexParameterInt(target, param, sender)); self.send_command(WebGLCommand::GetTexParameterInt(target, param, sender));
Int32Value(receiver.recv().unwrap()) retval.set(Int32Value(receiver.recv().unwrap()))
}, },
TexParameter::Bool(param) => { TexParameter::Bool(param) => {
let (sender, receiver) = webgl_channel().unwrap(); let (sender, receiver) = webgl_channel().unwrap();
self.send_command(WebGLCommand::GetTexParameterBool(target, param, sender)); self.send_command(WebGLCommand::GetTexParameterBool(target, param, sender));
BooleanValue(receiver.recv().unwrap()) retval.set(BooleanValue(receiver.recv().unwrap()))
}, },
} }
} }
@ -3123,15 +3161,20 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
target: u32, target: u32,
attachment: u32, attachment: u32,
pname: u32, pname: u32,
) -> JSVal { mut retval: MutableHandleValue,
) {
// Check if currently bound framebuffer is non-zero as per spec. // Check if currently bound framebuffer is non-zero as per spec.
if let Some(fb) = self.bound_draw_framebuffer.get() { if let Some(fb) = self.bound_draw_framebuffer.get() {
// Opaque framebuffers cannot have their attachments inspected // Opaque framebuffers cannot have their attachments inspected
// https://immersive-web.github.io/webxr/#opaque-framebuffer // https://immersive-web.github.io/webxr/#opaque-framebuffer
handle_potential_webgl_error!(self, fb.validate_transparent(), return NullValue()); handle_potential_webgl_error!(
self,
fb.validate_transparent(),
return retval.set(NullValue())
);
} else { } else {
self.webgl_error(InvalidOperation); self.webgl_error(InvalidOperation);
return NullValue(); return retval.set(NullValue());
} }
// Note: commented out stuff is for the WebGL2 standard. // Note: commented out stuff is for the WebGL2 standard.
@ -3192,7 +3235,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
if !target_matches || !attachment_matches || !pname_matches || !bound_attachment_matches { if !target_matches || !attachment_matches || !pname_matches || !bound_attachment_matches {
self.webgl_error(InvalidEnum); self.webgl_error(InvalidEnum);
return NullValue(); return retval.set(NullValue());
} }
// From the GLES2 spec: // From the GLES2 spec:
@ -3208,19 +3251,17 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
if let Some(webgl_attachment) = fb.attachment(attachment) { if let Some(webgl_attachment) = fb.attachment(attachment) {
match webgl_attachment { match webgl_attachment {
WebGLFramebufferAttachmentRoot::Renderbuffer(rb) => unsafe { WebGLFramebufferAttachmentRoot::Renderbuffer(rb) => unsafe {
rooted!(in(*cx) let mut rval = NullValue()); rb.to_jsval(*cx, retval);
rb.to_jsval(*cx, rval.handle_mut()); return;
return rval.get();
}, },
WebGLFramebufferAttachmentRoot::Texture(texture) => unsafe { WebGLFramebufferAttachmentRoot::Texture(texture) => unsafe {
rooted!(in(*cx) let mut rval = NullValue()); texture.to_jsval(*cx, retval);
texture.to_jsval(*cx, rval.handle_mut()); return;
return rval.get();
}, },
} }
} }
self.webgl_error(InvalidEnum); self.webgl_error(InvalidEnum);
return NullValue(); return retval.set(NullValue());
} }
let (sender, receiver) = webgl_channel().unwrap(); let (sender, receiver) = webgl_channel().unwrap();
@ -3228,11 +3269,17 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
target, attachment, pname, sender, target, attachment, pname, sender,
)); ));
Int32Value(receiver.recv().unwrap()) retval.set(Int32Value(receiver.recv().unwrap()))
} }
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.7 // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.7
fn GetRenderbufferParameter(&self, _cx: SafeJSContext, target: u32, pname: u32) -> JSVal { fn GetRenderbufferParameter(
&self,
_cx: SafeJSContext,
target: u32,
pname: u32,
mut retval: MutableHandleValue,
) {
// We do not check to see if the renderbuffer came from an opaque framebuffer // We do not check to see if the renderbuffer came from an opaque framebuffer
// https://github.com/immersive-web/webxr/issues/862 // https://github.com/immersive-web/webxr/issues/862
let target_matches = target == constants::RENDERBUFFER; let target_matches = target == constants::RENDERBUFFER;
@ -3252,12 +3299,12 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
if !target_matches || !pname_matches { if !target_matches || !pname_matches {
self.webgl_error(InvalidEnum); self.webgl_error(InvalidEnum);
return NullValue(); return retval.set(NullValue());
} }
if self.bound_renderbuffer.get().is_none() { if self.bound_renderbuffer.get().is_none() {
self.webgl_error(InvalidOperation); self.webgl_error(InvalidOperation);
return NullValue(); return retval.set(NullValue());
} }
let result = if pname == constants::RENDERBUFFER_INTERNAL_FORMAT { let result = if pname == constants::RENDERBUFFER_INTERNAL_FORMAT {
@ -3271,7 +3318,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
receiver.recv().unwrap() receiver.recv().unwrap()
}; };
Int32Value(result) retval.set(Int32Value(result))
} }
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9 // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9
@ -3287,13 +3334,23 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
} }
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9 // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9
fn GetProgramParameter(&self, _: SafeJSContext, program: &WebGLProgram, param: u32) -> JSVal { fn GetProgramParameter(
handle_potential_webgl_error!(self, self.validate_ownership(program), return NullValue()); &self,
_: SafeJSContext,
program: &WebGLProgram,
param: u32,
mut retval: MutableHandleValue,
) {
handle_potential_webgl_error!(
self,
self.validate_ownership(program),
return retval.set(NullValue())
);
if program.is_deleted() { if program.is_deleted() {
self.webgl_error(InvalidOperation); self.webgl_error(InvalidOperation);
return NullValue(); return retval.set(NullValue());
} }
match param { retval.set(match param {
constants::DELETE_STATUS => BooleanValue(program.is_marked_for_deletion()), constants::DELETE_STATUS => BooleanValue(program.is_marked_for_deletion()),
constants::LINK_STATUS => BooleanValue(program.is_linked()), constants::LINK_STATUS => BooleanValue(program.is_linked()),
constants::VALIDATE_STATUS => { constants::VALIDATE_STATUS => {
@ -3318,7 +3375,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
self.webgl_error(InvalidEnum); self.webgl_error(InvalidEnum);
NullValue() NullValue()
}, },
} })
} }
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9 // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9
@ -3328,13 +3385,23 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
} }
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9 // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9
fn GetShaderParameter(&self, _: SafeJSContext, shader: &WebGLShader, param: u32) -> JSVal { fn GetShaderParameter(
handle_potential_webgl_error!(self, self.validate_ownership(shader), return NullValue()); &self,
_: SafeJSContext,
shader: &WebGLShader,
param: u32,
mut retval: MutableHandleValue,
) {
handle_potential_webgl_error!(
self,
self.validate_ownership(shader),
return retval.set(NullValue())
);
if shader.is_deleted() { if shader.is_deleted() {
self.webgl_error(InvalidValue); self.webgl_error(InvalidValue);
return NullValue(); return retval.set(NullValue());
} }
match param { retval.set(match param {
constants::DELETE_STATUS => BooleanValue(shader.is_marked_for_deletion()), constants::DELETE_STATUS => BooleanValue(shader.is_marked_for_deletion()),
constants::COMPILE_STATUS => BooleanValue(shader.successfully_compiled()), constants::COMPILE_STATUS => BooleanValue(shader.successfully_compiled()),
constants::SHADER_TYPE => UInt32Value(shader.gl_type()), constants::SHADER_TYPE => UInt32Value(shader.gl_type()),
@ -3342,7 +3409,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
self.webgl_error(InvalidEnum); self.webgl_error(InvalidEnum);
NullValue() NullValue()
}, },
} })
} }
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9 // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9
@ -3400,8 +3467,14 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
#[allow(unsafe_code)] #[allow(unsafe_code)]
// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9 // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9
fn GetVertexAttrib(&self, cx: SafeJSContext, index: u32, param: u32) -> JSVal { fn GetVertexAttrib(
let get_attrib = |data: Ref<VertexAttribData>| -> JSVal { &self,
cx: SafeJSContext,
index: u32,
param: u32,
mut retval: MutableHandleValue,
) {
let mut get_attrib = |data: Ref<VertexAttribData>| {
if param == constants::CURRENT_VERTEX_ATTRIB { if param == constants::CURRENT_VERTEX_ATTRIB {
let attrib = self.current_vertex_attribs.borrow()[index as usize]; let attrib = self.current_vertex_attribs.borrow()[index as usize];
match attrib { match attrib {
@ -3415,7 +3488,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
result.handle_mut(), result.handle_mut(),
) )
.unwrap(); .unwrap();
return ObjectValue(result.get()); return retval.set(ObjectValue(result.get()));
} }
}, },
VertexAttrib::Int(x, y, z, w) => { VertexAttrib::Int(x, y, z, w) => {
@ -3424,7 +3497,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
rooted!(in(*cx) let mut result = ptr::null_mut::<JSObject>()); rooted!(in(*cx) let mut result = ptr::null_mut::<JSObject>());
Int32Array::create(*cx, CreateWith::Slice(&value), result.handle_mut()) Int32Array::create(*cx, CreateWith::Slice(&value), result.handle_mut())
.unwrap(); .unwrap();
return ObjectValue(result.get()); return retval.set(ObjectValue(result.get()));
} }
}, },
VertexAttrib::Uint(x, y, z, w) => { VertexAttrib::Uint(x, y, z, w) => {
@ -3437,7 +3510,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
result.handle_mut(), result.handle_mut(),
) )
.unwrap(); .unwrap();
return ObjectValue(result.get()); return retval.set(ObjectValue(result.get()));
} }
}, },
}; };
@ -3447,28 +3520,32 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
.is_get_vertex_attrib_name_enabled(param) .is_get_vertex_attrib_name_enabled(param)
{ {
self.webgl_error(WebGLError::InvalidEnum); self.webgl_error(WebGLError::InvalidEnum);
return NullValue(); return retval.set(NullValue());
} }
match param { match param {
constants::VERTEX_ATTRIB_ARRAY_ENABLED => BooleanValue(data.enabled_as_array), constants::VERTEX_ATTRIB_ARRAY_ENABLED => {
constants::VERTEX_ATTRIB_ARRAY_SIZE => Int32Value(data.size as i32), retval.set(BooleanValue(data.enabled_as_array))
constants::VERTEX_ATTRIB_ARRAY_TYPE => Int32Value(data.type_ as i32), },
constants::VERTEX_ATTRIB_ARRAY_NORMALIZED => BooleanValue(data.normalized), constants::VERTEX_ATTRIB_ARRAY_SIZE => retval.set(Int32Value(data.size as i32)),
constants::VERTEX_ATTRIB_ARRAY_STRIDE => Int32Value(data.stride as i32), constants::VERTEX_ATTRIB_ARRAY_TYPE => retval.set(Int32Value(data.type_ as i32)),
constants::VERTEX_ATTRIB_ARRAY_NORMALIZED => {
retval.set(BooleanValue(data.normalized))
},
constants::VERTEX_ATTRIB_ARRAY_STRIDE => retval.set(Int32Value(data.stride as i32)),
constants::VERTEX_ATTRIB_ARRAY_BUFFER_BINDING => unsafe { constants::VERTEX_ATTRIB_ARRAY_BUFFER_BINDING => unsafe {
rooted!(in(*cx) let mut jsval = NullValue());
if let Some(buffer) = data.buffer() { if let Some(buffer) = data.buffer() {
buffer.to_jsval(*cx, jsval.handle_mut()); buffer.to_jsval(*cx, retval);
} else {
retval.set(NullValue());
} }
jsval.get()
}, },
ANGLEInstancedArraysConstants::VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE => { ANGLEInstancedArraysConstants::VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE => {
UInt32Value(data.divisor) retval.set(UInt32Value(data.divisor))
}, },
_ => { _ => {
self.webgl_error(InvalidEnum); self.webgl_error(InvalidEnum);
NullValue() retval.set(NullValue())
}, },
} }
}; };
@ -3479,7 +3556,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
let data = handle_potential_webgl_error!( let data = handle_potential_webgl_error!(
self, self,
current_vao.get_vertex_attrib(index).ok_or(InvalidValue), current_vao.get_vertex_attrib(index).ok_or(InvalidValue),
return NullValue() return retval.set(NullValue())
); );
get_attrib(data) get_attrib(data)
}, },
@ -3488,7 +3565,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
let data = handle_potential_webgl_error!( let data = handle_potential_webgl_error!(
self, self,
current_vao.get_vertex_attrib(index).ok_or(InvalidValue), current_vao.get_vertex_attrib(index).ok_or(InvalidValue),
return NullValue() return retval.set(NullValue())
); );
get_attrib(data) get_attrib(data)
}, },
@ -4062,61 +4139,92 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
cx: SafeJSContext, cx: SafeJSContext,
program: &WebGLProgram, program: &WebGLProgram,
location: &WebGLUniformLocation, location: &WebGLUniformLocation,
) -> JSVal { mut rval: MutableHandleValue,
) {
handle_potential_webgl_error!( handle_potential_webgl_error!(
self, self,
self.uniform_check_program(program, location), self.uniform_check_program(program, location),
return NullValue() return rval.set(NullValue())
); );
let triple = (self, program.id(), location.id()); let triple = (self, program.id(), location.id());
match location.type_() { match location.type_() {
constants::BOOL => BooleanValue(uniform_get(triple, WebGLCommand::GetUniformBool)), constants::BOOL => rval.set(BooleanValue(uniform_get(
triple,
WebGLCommand::GetUniformBool,
))),
constants::BOOL_VEC2 => unsafe { constants::BOOL_VEC2 => unsafe {
rooted!(in(*cx) let mut rval = NullValue()); uniform_get(triple, WebGLCommand::GetUniformBool2).to_jsval(*cx, rval);
uniform_get(triple, WebGLCommand::GetUniformBool2).to_jsval(*cx, rval.handle_mut());
rval.get()
}, },
constants::BOOL_VEC3 => unsafe { constants::BOOL_VEC3 => unsafe {
rooted!(in(*cx) let mut rval = NullValue()); uniform_get(triple, WebGLCommand::GetUniformBool3).to_jsval(*cx, rval);
uniform_get(triple, WebGLCommand::GetUniformBool3).to_jsval(*cx, rval.handle_mut());
rval.get()
}, },
constants::BOOL_VEC4 => unsafe { constants::BOOL_VEC4 => unsafe {
rooted!(in(*cx) let mut rval = NullValue()); uniform_get(triple, WebGLCommand::GetUniformBool4).to_jsval(*cx, rval);
uniform_get(triple, WebGLCommand::GetUniformBool4).to_jsval(*cx, rval.handle_mut());
rval.get()
}, },
constants::INT | constants::SAMPLER_2D | constants::SAMPLER_CUBE => { constants::INT | constants::SAMPLER_2D | constants::SAMPLER_CUBE => {
Int32Value(uniform_get(triple, WebGLCommand::GetUniformInt)) rval.set(Int32Value(uniform_get(triple, WebGLCommand::GetUniformInt)))
}, },
constants::INT_VEC2 => unsafe { constants::INT_VEC2 => unsafe {
uniform_typed::<Int32>(*cx, &uniform_get(triple, WebGLCommand::GetUniformInt2)) uniform_typed::<Int32>(
*cx,
&uniform_get(triple, WebGLCommand::GetUniformInt2),
rval,
)
}, },
constants::INT_VEC3 => unsafe { constants::INT_VEC3 => unsafe {
uniform_typed::<Int32>(*cx, &uniform_get(triple, WebGLCommand::GetUniformInt3)) uniform_typed::<Int32>(
*cx,
&uniform_get(triple, WebGLCommand::GetUniformInt3),
rval,
)
}, },
constants::INT_VEC4 => unsafe { constants::INT_VEC4 => unsafe {
uniform_typed::<Int32>(*cx, &uniform_get(triple, WebGLCommand::GetUniformInt4)) uniform_typed::<Int32>(
}, *cx,
constants::FLOAT => { &uniform_get(triple, WebGLCommand::GetUniformInt4),
DoubleValue(uniform_get(triple, WebGLCommand::GetUniformFloat) as f64) rval,
)
}, },
constants::FLOAT => rval
.set(DoubleValue(
uniform_get(triple, WebGLCommand::GetUniformFloat) as f64,
)),
constants::FLOAT_VEC2 => unsafe { constants::FLOAT_VEC2 => unsafe {
uniform_typed::<Float32>(*cx, &uniform_get(triple, WebGLCommand::GetUniformFloat2)) uniform_typed::<Float32>(
*cx,
&uniform_get(triple, WebGLCommand::GetUniformFloat2),
rval,
)
}, },
constants::FLOAT_VEC3 => unsafe { constants::FLOAT_VEC3 => unsafe {
uniform_typed::<Float32>(*cx, &uniform_get(triple, WebGLCommand::GetUniformFloat3)) uniform_typed::<Float32>(
*cx,
&uniform_get(triple, WebGLCommand::GetUniformFloat3),
rval,
)
}, },
constants::FLOAT_VEC4 | constants::FLOAT_MAT2 => unsafe { constants::FLOAT_VEC4 | constants::FLOAT_MAT2 => unsafe {
uniform_typed::<Float32>(*cx, &uniform_get(triple, WebGLCommand::GetUniformFloat4)) uniform_typed::<Float32>(
*cx,
&uniform_get(triple, WebGLCommand::GetUniformFloat4),
rval,
)
}, },
constants::FLOAT_MAT3 => unsafe { constants::FLOAT_MAT3 => unsafe {
uniform_typed::<Float32>(*cx, &uniform_get(triple, WebGLCommand::GetUniformFloat9)) uniform_typed::<Float32>(
*cx,
&uniform_get(triple, WebGLCommand::GetUniformFloat9),
rval,
)
}, },
constants::FLOAT_MAT4 => unsafe { constants::FLOAT_MAT4 => unsafe {
uniform_typed::<Float32>(*cx, &uniform_get(triple, WebGLCommand::GetUniformFloat16)) uniform_typed::<Float32>(
*cx,
&uniform_get(triple, WebGLCommand::GetUniformFloat16),
rval,
)
}, },
_ => panic!("wrong uniform type"), _ => panic!("wrong uniform type"),
} }

View file

@ -33,10 +33,11 @@ use ipc_channel::ipc::{self, IpcSender};
use ipc_channel::router::ROUTER; use ipc_channel::router::ROUTER;
use js::conversions::ToJSValConvertible; use js::conversions::ToJSValConvertible;
use js::jsapi::{GCReason, Heap, JSAutoRealm, JSObject, StackFormat, JSPROP_ENUMERATE, JS_GC}; use js::jsapi::{GCReason, Heap, JSAutoRealm, JSObject, StackFormat, JSPROP_ENUMERATE, JS_GC};
use js::jsval::{JSVal, NullValue, UndefinedValue}; use js::jsval::{NullValue, UndefinedValue};
use js::rust::wrappers::JS_DefineProperty; use js::rust::wrappers::JS_DefineProperty;
use js::rust::{ use js::rust::{
CustomAutoRooter, CustomAutoRooterGuard, HandleObject, HandleValue, MutableHandleObject, CustomAutoRooter, CustomAutoRooterGuard, HandleObject, HandleValue, MutableHandleObject,
MutableHandleValue,
}; };
use malloc_size_of::MallocSizeOf; use malloc_size_of::MallocSizeOf;
use media::WindowGLContext; use media::WindowGLContext;
@ -697,22 +698,32 @@ impl WindowMethods for Window {
} }
// https://html.spec.whatwg.org/multipage/#dom-opener // https://html.spec.whatwg.org/multipage/#dom-opener
fn GetOpener(&self, cx: JSContext, in_realm_proof: InRealm) -> Fallible<JSVal> { fn GetOpener(
&self,
cx: JSContext,
in_realm_proof: InRealm,
mut retval: MutableHandleValue,
) -> Fallible<()> {
// Step 1, Let current be this Window object's browsing context. // Step 1, Let current be this Window object's browsing context.
let current = match self.window_proxy.get() { let current = match self.window_proxy.get() {
Some(proxy) => proxy, Some(proxy) => proxy,
// Step 2, If current is null, then return null. // Step 2, If current is null, then return null.
None => return Ok(NullValue()), None => {
retval.set(NullValue());
return Ok(());
},
}; };
// Still step 2, since the window's BC is the associated doc's BC, // Still step 2, since the window's BC is the associated doc's BC,
// see https://html.spec.whatwg.org/multipage/#window-bc // see https://html.spec.whatwg.org/multipage/#window-bc
// and a doc's BC is null if it has been discarded. // and a doc's BC is null if it has been discarded.
// see https://html.spec.whatwg.org/multipage/#concept-document-bc // see https://html.spec.whatwg.org/multipage/#concept-document-bc
if current.is_browsing_context_discarded() { if current.is_browsing_context_discarded() {
return Ok(NullValue()); retval.set(NullValue());
return Ok(());
} }
// Step 3 to 5. // Step 3 to 5.
Ok(current.opener(*cx, in_realm_proof)) current.opener(*cx, in_realm_proof, retval);
Ok(())
} }
#[allow(unsafe_code)] #[allow(unsafe_code)]
@ -1388,17 +1399,12 @@ impl WindowMethods for Window {
// https://dom.spec.whatwg.org/#dom-window-event // https://dom.spec.whatwg.org/#dom-window-event
#[allow(unsafe_code)] #[allow(unsafe_code)]
fn Event(&self, cx: JSContext) -> JSVal { fn Event(&self, cx: JSContext, rval: MutableHandleValue) {
rooted!(in(*cx) let mut rval = UndefinedValue());
if let Some(ref event) = *self.current_event.borrow() { if let Some(ref event) = *self.current_event.borrow() {
unsafe { unsafe {
event event.reflector().get_jsobject().to_jsval(*cx, rval);
.reflector()
.get_jsobject()
.to_jsval(*cx, rval.handle_mut());
} }
} }
rval.get()
} }
fn IsSecureContext(&self) -> bool { fn IsSecureContext(&self) -> bool {
@ -1571,9 +1577,10 @@ impl WindowMethods for Window {
cx: JSContext, cx: JSContext,
value: HandleValue, value: HandleValue,
options: RootedTraceableBox<StructuredSerializeOptions>, options: RootedTraceableBox<StructuredSerializeOptions>,
) -> Fallible<js::jsval::JSVal> { retval: MutableHandleValue,
) -> Fallible<()> {
self.upcast::<GlobalScope>() self.upcast::<GlobalScope>()
.structured_clone(cx, value, options) .structured_clone(cx, value, options, retval)
} }
} }

View file

@ -24,9 +24,9 @@ use js::jsapi::{
MutableHandleObject as RawMutableHandleObject, MutableHandleValue as RawMutableHandleValue, MutableHandleObject as RawMutableHandleObject, MutableHandleValue as RawMutableHandleValue,
ObjectOpResult, PropertyDescriptor, JSPROP_ENUMERATE, JSPROP_READONLY, ObjectOpResult, PropertyDescriptor, JSPROP_ENUMERATE, JSPROP_READONLY,
}; };
use js::jsval::{JSVal, NullValue, PrivateValue, UndefinedValue}; use js::jsval::{NullValue, PrivateValue, UndefinedValue};
use js::rust::wrappers::{JS_TransplantObject, NewWindowProxy, SetWindowProxy}; use js::rust::wrappers::{JS_TransplantObject, NewWindowProxy, SetWindowProxy};
use js::rust::{get_object_class, Handle, MutableHandle}; use js::rust::{get_object_class, Handle, MutableHandle, MutableHandleValue};
use js::JSCLASS_IS_GLOBAL; use js::JSCLASS_IS_GLOBAL;
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
use net_traits::request::Referrer; use net_traits::request::Referrer;
@ -416,13 +416,18 @@ impl WindowProxy {
#[allow(unsafe_code)] #[allow(unsafe_code)]
// https://html.spec.whatwg.org/multipage/#dom-opener // https://html.spec.whatwg.org/multipage/#dom-opener
pub fn opener(&self, cx: *mut JSContext, in_realm_proof: InRealm) -> JSVal { pub fn opener(
&self,
cx: *mut JSContext,
in_realm_proof: InRealm,
mut retval: MutableHandleValue,
) {
if self.disowned.get() { if self.disowned.get() {
return NullValue(); return retval.set(NullValue());
} }
let opener_id = match self.opener { let opener_id = match self.opener {
Some(opener_browsing_context_id) => opener_browsing_context_id, Some(opener_browsing_context_id) => opener_browsing_context_id,
None => return NullValue(), None => return retval.set(NullValue()),
}; };
let parent_browsing_context = self.parent.as_deref(); let parent_browsing_context = self.parent.as_deref();
let opener_proxy = match ScriptThread::find_window_proxy(opener_id) { let opener_proxy = match ScriptThread::find_window_proxy(opener_id) {
@ -447,16 +452,14 @@ impl WindowProxy {
creator, creator,
) )
}, },
None => return NullValue(), None => return retval.set(NullValue()),
} }
}, },
}; };
if opener_proxy.is_browsing_context_discarded() { if opener_proxy.is_browsing_context_discarded() {
return NullValue(); return retval.set(NullValue());
} }
rooted!(in(cx) let mut val = UndefinedValue()); unsafe { opener_proxy.to_jsval(cx, retval) };
unsafe { opener_proxy.to_jsval(cx, val.handle_mut()) };
val.get()
} }
// https://html.spec.whatwg.org/multipage/#window-open-steps // https://html.spec.whatwg.org/multipage/#window-open-steps

View file

@ -16,7 +16,7 @@ use dom_struct::dom_struct;
use ipc_channel::ipc::IpcSender; use ipc_channel::ipc::IpcSender;
use js::jsval::UndefinedValue; use js::jsval::UndefinedValue;
use js::panic::maybe_resume_unwind; use js::panic::maybe_resume_unwind;
use js::rust::{HandleValue, ParentRuntime}; use js::rust::{HandleValue, MutableHandleValue, ParentRuntime};
use net_traits::request::{ use net_traits::request::{
CredentialsMode, Destination, ParserMetadata, RequestBuilder as NetRequestInit, CredentialsMode, Destination, ParserMetadata, RequestBuilder as NetRequestInit,
}; };
@ -439,9 +439,10 @@ impl WorkerGlobalScopeMethods for WorkerGlobalScope {
cx: JSContext, cx: JSContext,
value: HandleValue, value: HandleValue,
options: RootedTraceableBox<StructuredSerializeOptions>, options: RootedTraceableBox<StructuredSerializeOptions>,
) -> Fallible<js::jsval::JSVal> { retval: MutableHandleValue,
) -> Fallible<()> {
self.upcast::<GlobalScope>() self.upcast::<GlobalScope>()
.structured_clone(cx, value, options) .structured_clone(cx, value, options, retval)
} }
} }

View file

@ -3,7 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use dom_struct::dom_struct; use dom_struct::dom_struct;
use js::jsval::JSVal; use js::rust::MutableHandleValue;
use crate::dom::bindings::codegen::Bindings::WorkerNavigatorBinding::WorkerNavigatorMethods; use crate::dom::bindings::codegen::Bindings::WorkerNavigatorBinding::WorkerNavigatorMethods;
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector}; use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
@ -97,8 +97,8 @@ impl WorkerNavigatorMethods for WorkerNavigator {
// https://html.spec.whatwg.org/multipage/#dom-navigator-languages // https://html.spec.whatwg.org/multipage/#dom-navigator-languages
#[allow(unsafe_code)] #[allow(unsafe_code)]
fn Languages(&self, cx: JSContext) -> JSVal { fn Languages(&self, cx: JSContext, retval: MutableHandleValue) {
to_frozen_array(&[self.Language()], cx) to_frozen_array(&[self.Language()], cx, retval)
} }
// https://w3c.github.io/permissions/#navigator-and-workernavigator-extension // https://w3c.github.io/permissions/#navigator-and-workernavigator-extension

View file

@ -20,9 +20,9 @@ use http::Method;
use hyper_serde::Serde; use hyper_serde::Serde;
use ipc_channel::ipc; use ipc_channel::ipc;
use js::jsapi::{Heap, JS_ClearPendingException}; use js::jsapi::{Heap, JS_ClearPendingException};
use js::jsval::{JSVal, NullValue, UndefinedValue}; use js::jsval::{JSVal, NullValue};
use js::rust::wrappers::JS_ParseJSON; use js::rust::wrappers::JS_ParseJSON;
use js::rust::HandleObject; use js::rust::{HandleObject, MutableHandleValue};
use js::typedarray::{ArrayBuffer, ArrayBufferU8}; use js::typedarray::{ArrayBuffer, ArrayBufferU8};
use mime::{self, Mime, Name}; use mime::{self, Mime, Name};
use net_traits::http_status::HttpStatus; use net_traits::http_status::HttpStatus;
@ -935,8 +935,7 @@ impl XMLHttpRequestMethods for XMLHttpRequest {
#[allow(unsafe_code)] #[allow(unsafe_code)]
/// <https://xhr.spec.whatwg.org/#the-response-attribute> /// <https://xhr.spec.whatwg.org/#the-response-attribute>
fn Response(&self, cx: JSContext, can_gc: CanGc) -> JSVal { fn Response(&self, cx: JSContext, can_gc: CanGc, mut rval: MutableHandleValue) {
rooted!(in(*cx) let mut rval = UndefinedValue());
match self.response_type.get() { match self.response_type.get() {
XMLHttpRequestResponseType::_empty | XMLHttpRequestResponseType::Text => unsafe { XMLHttpRequestResponseType::_empty | XMLHttpRequestResponseType::Text => unsafe {
let ready_state = self.ready_state.get(); let ready_state = self.ready_state.get();
@ -944,33 +943,29 @@ impl XMLHttpRequestMethods for XMLHttpRequest {
if ready_state == XMLHttpRequestState::Done || if ready_state == XMLHttpRequestState::Done ||
ready_state == XMLHttpRequestState::Loading ready_state == XMLHttpRequestState::Loading
{ {
self.text_response().to_jsval(*cx, rval.handle_mut()); self.text_response().to_jsval(*cx, rval);
} else { } else {
// Step 1 // Step 1
"".to_jsval(*cx, rval.handle_mut()); "".to_jsval(*cx, rval);
} }
}, },
// Step 1 // Step 1
_ if self.ready_state.get() != XMLHttpRequestState::Done => { _ if self.ready_state.get() != XMLHttpRequestState::Done => {
return NullValue(); rval.set(NullValue());
}, },
// Step 2 // Step 2
XMLHttpRequestResponseType::Document => unsafe { XMLHttpRequestResponseType::Document => unsafe {
self.document_response(can_gc) self.document_response(can_gc).to_jsval(*cx, rval);
.to_jsval(*cx, rval.handle_mut());
},
XMLHttpRequestResponseType::Json => unsafe {
self.json_response(cx).to_jsval(*cx, rval.handle_mut());
}, },
XMLHttpRequestResponseType::Json => self.json_response(cx, rval),
XMLHttpRequestResponseType::Blob => unsafe { XMLHttpRequestResponseType::Blob => unsafe {
self.blob_response(can_gc).to_jsval(*cx, rval.handle_mut()); self.blob_response(can_gc).to_jsval(*cx, rval);
}, },
XMLHttpRequestResponseType::Arraybuffer => match self.arraybuffer_response(cx) { XMLHttpRequestResponseType::Arraybuffer => match self.arraybuffer_response(cx) {
Some(array_buffer) => unsafe { array_buffer.to_jsval(*cx, rval.handle_mut()) }, Some(array_buffer) => unsafe { array_buffer.to_jsval(*cx, rval) },
None => return NullValue(), None => rval.set(NullValue()),
}, },
} }
rval.get()
} }
/// <https://xhr.spec.whatwg.org/#the-responsetext-attribute> /// <https://xhr.spec.whatwg.org/#the-responsetext-attribute>
@ -1447,17 +1442,17 @@ impl XMLHttpRequest {
#[allow(unsafe_code)] #[allow(unsafe_code)]
/// <https://xhr.spec.whatwg.org/#json-response> /// <https://xhr.spec.whatwg.org/#json-response>
fn json_response(&self, cx: JSContext) -> JSVal { fn json_response(&self, cx: JSContext, mut rval: MutableHandleValue) {
// Step 1 // Step 1
let response_json = self.response_json.get(); let response_json = self.response_json.get();
if !response_json.is_null_or_undefined() { if !response_json.is_null_or_undefined() {
return response_json; return rval.set(response_json);
} }
// Step 2 // Step 2
let bytes = self.response.borrow(); let bytes = self.response.borrow();
// Step 3 // Step 3
if bytes.len() == 0 { if bytes.len() == 0 {
return NullValue(); return rval.set(NullValue());
} }
// Step 4 // Step 4
fn decode_to_utf16_with_bom_removal(bytes: &[u8], encoding: &'static Encoding) -> Vec<u16> { fn decode_to_utf16_with_bom_removal(bytes: &[u8], encoding: &'static Encoding) -> Vec<u16> {
@ -1480,21 +1475,14 @@ impl XMLHttpRequest {
// if present, but UTF-16BE/LE BOM must not be honored. // if present, but UTF-16BE/LE BOM must not be honored.
let json_text = decode_to_utf16_with_bom_removal(&bytes, UTF_8); let json_text = decode_to_utf16_with_bom_removal(&bytes, UTF_8);
// Step 5 // Step 5
rooted!(in(*cx) let mut rval = UndefinedValue());
unsafe { unsafe {
if !JS_ParseJSON( if !JS_ParseJSON(*cx, json_text.as_ptr(), json_text.len() as u32, rval) {
*cx,
json_text.as_ptr(),
json_text.len() as u32,
rval.handle_mut(),
) {
JS_ClearPendingException(*cx); JS_ClearPendingException(*cx);
return NullValue(); return rval.set(NullValue());
} }
} }
// Step 6 // Step 6
self.response_json.set(rval.get()); self.response_json.set(rval.get());
self.response_json.get()
} }
fn document_text_html(&self, can_gc: CanGc) -> DomRoot<Document> { fn document_text_html(&self, can_gc: CanGc) -> DomRoot<Document> {

View file

@ -3,7 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use dom_struct::dom_struct; use dom_struct::dom_struct;
use js::jsval::JSVal; use js::rust::MutableHandleValue;
use crate::dom::bindings::codegen::Bindings::XRBoundedReferenceSpaceBinding::XRBoundedReferenceSpaceMethods; use crate::dom::bindings::codegen::Bindings::XRBoundedReferenceSpaceBinding::XRBoundedReferenceSpaceMethods;
use crate::dom::bindings::codegen::Bindings::XRReferenceSpaceBinding::XRReferenceSpaceType; use crate::dom::bindings::codegen::Bindings::XRReferenceSpaceBinding::XRReferenceSpaceType;
@ -67,7 +67,7 @@ impl XRBoundedReferenceSpace {
impl XRBoundedReferenceSpaceMethods for XRBoundedReferenceSpace { impl XRBoundedReferenceSpaceMethods for XRBoundedReferenceSpace {
/// <https://www.w3.org/TR/webxr/#dom-xrboundedreferencespace-boundsgeometry> /// <https://www.w3.org/TR/webxr/#dom-xrboundedreferencespace-boundsgeometry>
fn BoundsGeometry(&self, cx: JSContext, can_gc: CanGc) -> JSVal { fn BoundsGeometry(&self, cx: JSContext, can_gc: CanGc, retval: MutableHandleValue) {
if let Some(bounds) = self.reference_space.get_bounds() { if let Some(bounds) = self.reference_space.get_bounds() {
let points: Vec<DomRoot<DOMPointReadOnly>> = bounds let points: Vec<DomRoot<DOMPointReadOnly>> = bounds
.into_iter() .into_iter()
@ -83,9 +83,9 @@ impl XRBoundedReferenceSpaceMethods for XRBoundedReferenceSpace {
}) })
.collect(); .collect();
to_frozen_array(&points, cx) to_frozen_array(&points, cx, retval)
} else { } else {
to_frozen_array::<DomRoot<DOMPointReadOnly>>(&[], cx) to_frozen_array::<DomRoot<DOMPointReadOnly>>(&[], cx, retval)
} }
} }
} }

View file

@ -6,6 +6,7 @@ use dom_struct::dom_struct;
use js::conversions::ToJSValConvertible; use js::conversions::ToJSValConvertible;
use js::jsapi::Heap; use js::jsapi::Heap;
use js::jsval::{JSVal, UndefinedValue}; use js::jsval::{JSVal, UndefinedValue};
use js::rust::MutableHandleValue;
use script_traits::GamepadSupportedHapticEffects; use script_traits::GamepadSupportedHapticEffects;
use webxr_api::{Handedness, InputFrame, InputId, InputSource, TargetRayMode}; use webxr_api::{Handedness, InputFrame, InputId, InputSource, TargetRayMode};
@ -159,8 +160,8 @@ impl XRInputSourceMethods for XRInputSource {
} }
} }
// https://immersive-web.github.io/webxr/#dom-xrinputsource-profiles // https://immersive-web.github.io/webxr/#dom-xrinputsource-profiles
fn Profiles(&self, _cx: JSContext) -> JSVal { fn Profiles(&self, _cx: JSContext, mut retval: MutableHandleValue) {
self.profiles.get() retval.set(self.profiles.get())
} }
/// <https://www.w3.org/TR/webxr/#dom-xrinputsource-skiprendering> /// <https://www.w3.org/TR/webxr/#dom-xrinputsource-skiprendering>

View file

@ -5,7 +5,7 @@
use dom_struct::dom_struct; use dom_struct::dom_struct;
use js::jsapi::Heap; use js::jsapi::Heap;
use js::jsval::JSVal; use js::jsval::JSVal;
use js::rust::HandleObject; use js::rust::{HandleObject, MutableHandleValue};
use servo_atoms::Atom; use servo_atoms::Atom;
use crate::dom::bindings::codegen::Bindings::EventBinding::Event_Binding::EventMethods; use crate::dom::bindings::codegen::Bindings::EventBinding::Event_Binding::EventMethods;
@ -87,8 +87,11 @@ impl XRInputSourcesChangeEvent {
} }
let _ac = enter_realm(global); let _ac = enter_realm(global);
let cx = GlobalScope::get_cx(); let cx = GlobalScope::get_cx();
changeevent.added.set(to_frozen_array(added, cx)); rooted!(in(*cx) let mut frozen_val: JSVal);
changeevent.removed.set(to_frozen_array(removed, cx)); to_frozen_array(added, cx, frozen_val.handle_mut());
changeevent.added.set(*frozen_val);
to_frozen_array(removed, cx, frozen_val.handle_mut());
changeevent.removed.set(*frozen_val);
changeevent changeevent
} }
} }
@ -121,13 +124,13 @@ impl XRInputSourcesChangeEventMethods for XRInputSourcesChangeEvent {
} }
// https://immersive-web.github.io/webxr/#dom-xrinputsourceschangeevent-added // https://immersive-web.github.io/webxr/#dom-xrinputsourceschangeevent-added
fn Added(&self, _cx: JSContext) -> JSVal { fn Added(&self, _cx: JSContext, mut retval: MutableHandleValue) {
self.added.get() retval.set(self.added.get())
} }
// https://immersive-web.github.io/webxr/#dom-xrinputsourceschangeevent-removed // https://immersive-web.github.io/webxr/#dom-xrinputsourceschangeevent-removed
fn Removed(&self, _cx: JSContext) -> JSVal { fn Removed(&self, _cx: JSContext, mut retval: MutableHandleValue) {
self.removed.get() retval.set(self.removed.get())
} }
// https://dom.spec.whatwg.org/#dom-event-istrusted // https://dom.spec.whatwg.org/#dom-event-istrusted

View file

@ -5,7 +5,7 @@
use std::cell::Cell; use std::cell::Cell;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use js::jsval::JSVal; use js::rust::MutableHandleValue;
use webxr_api::SubImages; use webxr_api::SubImages;
use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::cell::DomRefCell;
@ -146,10 +146,10 @@ impl XRRenderStateMethods for XRRenderState {
} }
/// <https://immersive-web.github.io/layers/#dom-xrrenderstate-layers> /// <https://immersive-web.github.io/layers/#dom-xrrenderstate-layers>
fn Layers(&self, cx: JSContext) -> JSVal { fn Layers(&self, cx: JSContext, retval: MutableHandleValue) {
// TODO: cache this array? // TODO: cache this array?
let layers = self.layers.borrow(); let layers = self.layers.borrow();
let layers: Vec<&XRLayer> = layers.iter().map(|x| &**x).collect(); let layers: Vec<&XRLayer> = layers.iter().map(|x| &**x).collect();
to_frozen_array(&layers[..], cx) to_frozen_array(&layers[..], cx, retval)
} }
} }

View file

@ -14,7 +14,7 @@ use euclid::{RigidTransform3D, Transform3D, Vector3D};
use ipc_channel::ipc::IpcReceiver; use ipc_channel::ipc::IpcReceiver;
use ipc_channel::router::ROUTER; use ipc_channel::router::ROUTER;
use js::jsapi::JSObject; use js::jsapi::JSObject;
use js::jsval::JSVal; use js::rust::MutableHandleValue;
use js::typedarray::Float32Array; use js::typedarray::Float32Array;
use profile_traits::ipc; use profile_traits::ipc;
use servo_atoms::Atom; use servo_atoms::Atom;
@ -1011,10 +1011,10 @@ impl XRSessionMethods for XRSession {
} }
/// <https://www.w3.org/TR/webxr/#dom-xrsession-enabledfeatures> /// <https://www.w3.org/TR/webxr/#dom-xrsession-enabledfeatures>
fn EnabledFeatures(&self, cx: JSContext) -> JSVal { fn EnabledFeatures(&self, cx: JSContext, retval: MutableHandleValue) {
let session = self.session.borrow(); let session = self.session.borrow();
let features = session.granted_features(); let features = session.granted_features();
to_frozen_array(features, cx) to_frozen_array(features, cx, retval)
} }
/// <https://www.w3.org/TR/webxr/#dom-xrsession-issystemkeyboardsupported> /// <https://www.w3.org/TR/webxr/#dom-xrsession-issystemkeyboardsupported>

View file

@ -11,6 +11,7 @@ use std::rc::Rc;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use ipc_channel::ipc::IpcSender; use ipc_channel::ipc::IpcSender;
use ipc_channel::router::ROUTER; use ipc_channel::router::ROUTER;
use js::jsval::JSVal;
use profile_traits::ipc; use profile_traits::ipc;
use webxr_api::{self, Error as XRError, MockDeviceInit, MockDeviceMsg}; use webxr_api::{self, Error as XRError, MockDeviceInit, MockDeviceMsg};
@ -184,7 +185,8 @@ impl XRTestMethods for XRTest {
/// <https://github.com/immersive-web/webxr-test-api/blob/master/explainer.md> /// <https://github.com/immersive-web/webxr-test-api/blob/master/explainer.md>
fn SimulateUserActivation(&self, f: Rc<Function>) { fn SimulateUserActivation(&self, f: Rc<Function>) {
ScriptThread::set_user_interacting(true); ScriptThread::set_user_interacting(true);
let _ = f.Call__(vec![], ExceptionHandling::Rethrow); rooted!(in(*GlobalScope::get_cx()) let mut value: JSVal);
let _ = f.Call__(vec![], value.handle_mut(), ExceptionHandling::Rethrow);
ScriptThread::set_user_interacting(false); ScriptThread::set_user_interacting(false);
} }

View file

@ -7,6 +7,7 @@ use euclid::RigidTransform3D;
use js::conversions::ToJSValConvertible; use js::conversions::ToJSValConvertible;
use js::jsapi::Heap; use js::jsapi::Heap;
use js::jsval::{JSVal, UndefinedValue}; use js::jsval::{JSVal, UndefinedValue};
use js::rust::MutableHandleValue;
use webxr_api::{Viewer, ViewerPose, Views}; use webxr_api::{Viewer, ViewerPose, Views};
use crate::dom::bindings::codegen::Bindings::XRViewBinding::XREye; use crate::dom::bindings::codegen::Bindings::XRViewBinding::XREye;
@ -189,7 +190,7 @@ impl XRViewerPose {
impl XRViewerPoseMethods for XRViewerPose { impl XRViewerPoseMethods for XRViewerPose {
/// <https://immersive-web.github.io/webxr/#dom-xrviewerpose-views> /// <https://immersive-web.github.io/webxr/#dom-xrviewerpose-views>
fn Views(&self, _cx: JSContext) -> JSVal { fn Views(&self, _cx: JSContext, mut retval: MutableHandleValue) {
self.views.get() retval.set(self.views.get())
} }
} }

View file

@ -563,7 +563,8 @@ impl JsTimerTask {
}, },
InternalTimerCallback::FunctionTimerCallback(ref function, ref arguments) => { InternalTimerCallback::FunctionTimerCallback(ref function, ref arguments) => {
let arguments = self.collect_heap_args(arguments); let arguments = self.collect_heap_args(arguments);
let _ = function.Call_(this, arguments, Report); rooted!(in(*GlobalScope::get_cx()) let mut value: JSVal);
let _ = function.Call_(this, arguments, value.handle_mut(), Report);
}, },
}; };
ScriptThread::set_user_interacting(was_user_interacting); ScriptThread::set_user_interacting(was_user_interacting);