diff options
Diffstat (limited to 'components/script/dom')
48 files changed, 1153 insertions, 1106 deletions
diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 711f44b4cd4..7c6b2fe3718 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -462,8 +462,7 @@ class CGMethodCall(CGThing): pickFirstSignature("%s.get().is_object() && is_array_like(cx, %s)" % (distinguishingArg, distinguishingArg), lambda s: - (s[1][distinguishingIndex].type.isArray() or - s[1][distinguishingIndex].type.isSequence() or + (s[1][distinguishingIndex].type.isSequence() or s[1][distinguishingIndex].type.isObject())) # Check for Date objects @@ -537,9 +536,6 @@ def typeIsSequenceOrHasSequenceMember(type): type = type.inner if type.isSequence(): return True - if type.isArray(): - elementType = type.inner - return typeIsSequenceOrHasSequenceMember(elementType) if type.isDictionary(): return dictionaryHasSequenceMember(type.inner) if type.isUnion(): @@ -732,9 +728,6 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, assert not (isEnforceRange and isClamp) # These are mutually exclusive - if type.isArray(): - raise TypeError("Can't handle array arguments yet") - if type.isSequence() or type.isMozMap(): innerInfo = getJSToNativeConversionInfo(innerContainerType(type), descriptorProvider, @@ -1309,7 +1302,7 @@ def typeNeedsCx(type, retVal=False): return False if type.nullable(): type = type.inner - if type.isSequence() or type.isArray(): + if type.isSequence(): type = type.inner if type.isUnion(): return any(typeNeedsCx(t) for t in type.unroll().flatMemberTypes) @@ -1612,7 +1605,7 @@ class MethodDefiner(PropertyDefiner): "name": "forEach", "methodInfo": False, "selfHostedName": "ArrayForEach", - "length": 0, + "length": 1, "condition": PropertyDefiner.getControllingCondition(m, descriptor) }) @@ -3809,9 +3802,6 @@ class CGMemberJITInfo(CGThing): if t.isVoid(): # No return, every time return "JSVAL_TYPE_UNDEFINED" - if t.isArray(): - # No idea yet - assert False if t.isSequence(): return "JSVAL_TYPE_OBJECT" if t.isMozMap(): @@ -3887,9 +3877,6 @@ class CGMemberJITInfo(CGThing): if t.nullable(): # Sometimes it might return null, sometimes not return "JSJitInfo_ArgType::Null as i32 | %s" % CGMemberJITInfo.getJSArgType(t.inner) - if t.isArray(): - # No idea yet - assert False if t.isSequence(): return "JSJitInfo_ArgType::Object as i32" if t.isGeckoInterface(): @@ -4153,7 +4140,7 @@ class CGUnionConversionStruct(CGThing): else: interfaceObject = None - arrayObjectMemberTypes = filter(lambda t: t.isArray() or t.isSequence(), memberTypes) + arrayObjectMemberTypes = filter(lambda t: t.isSequence(), memberTypes) if len(arrayObjectMemberTypes) > 0: assert len(arrayObjectMemberTypes) == 1 typeName = arrayObjectMemberTypes[0].name @@ -4767,7 +4754,7 @@ class CGDOMJSProxyHandler_getOwnPropertyDescriptor(CGAbstractExternMethod): def __init__(self, descriptor): args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'proxy'), Argument('HandleId', 'id'), - Argument('MutableHandle<PropertyDescriptor>', 'desc', mutable=True)] + Argument('MutableHandle<PropertyDescriptor>', 'desc')] CGAbstractExternMethod.__init__(self, descriptor, "getOwnPropertyDescriptor", "bool", args) self.descriptor = descriptor @@ -4786,7 +4773,7 @@ class CGDOMJSProxyHandler_getOwnPropertyDescriptor(CGAbstractExternMethod): attrs += " | JSPROP_READONLY" # FIXME(#11868) Should assign to desc.value, desc.get() is a copy. fillDescriptor = ("desc.get().value = result_root.get();\n" - "fill_property_descriptor(&mut desc, proxy.get(), %s);\n" + "fill_property_descriptor(desc, proxy.get(), %s);\n" "return true;" % attrs) templateValues = { 'jsvalRef': 'result_root.handle_mut()', @@ -4812,7 +4799,7 @@ class CGDOMJSProxyHandler_getOwnPropertyDescriptor(CGAbstractExternMethod): attrs = "0" # FIXME(#11868) Should assign to desc.value, desc.get() is a copy. fillDescriptor = ("desc.get().value = result_root.get();\n" - "fill_property_descriptor(&mut desc, proxy.get(), %s);\n" + "fill_property_descriptor(desc, proxy.get(), %s);\n" "return true;" % attrs) templateValues = { 'jsvalRef': 'result_root.handle_mut()', @@ -5641,13 +5628,6 @@ class CGDescriptor(CGThing): return name cgThings = [] - if not descriptor.interface.isCallback() and not descriptor.interface.isNamespace(): - cgThings.append(CGGetProtoObjectMethod(descriptor)) - reexports.append('GetProtoObject') - if (descriptor.interface.hasInterfaceObject() and - descriptor.shouldHaveGetConstructorObjectMethod()): - cgThings.append(CGGetConstructorObjectMethod(descriptor)) - reexports.append('GetConstructorObject') unscopableNames = [] for m in descriptor.interface.members: @@ -5694,17 +5674,6 @@ class CGDescriptor(CGThing): cgThings.append(CGClassFinalizeHook(descriptor)) cgThings.append(CGClassTraceHook(descriptor)) - if descriptor.interface.hasInterfaceObject(): - if descriptor.interface.ctor(): - cgThings.append(CGClassConstructHook(descriptor)) - for ctor in descriptor.interface.namedConstructors: - cgThings.append(CGClassConstructHook(descriptor, ctor)) - if not descriptor.interface.isCallback(): - cgThings.append(CGInterfaceObjectJSClass(descriptor)) - - if not descriptor.interface.isCallback() and not descriptor.interface.isNamespace(): - cgThings.append(CGPrototypeJSClass(descriptor)) - # If there are no constant members, don't make a module for constants constMembers = [m for m in descriptor.interface.members if m.isConst()] if constMembers: @@ -5713,11 +5682,6 @@ class CGDescriptor(CGThing): public=True)) reexports.append(descriptor.name + 'Constants') - if descriptor.interface.hasInterfaceObject() and descriptor.register: - cgThings.append(CGDefineDOMInterfaceMethod(descriptor)) - reexports.append('DefineDOMInterface') - cgThings.append(CGConstructorEnabled(descriptor)) - if descriptor.proxy: cgThings.append(CGDefineProxyHandler(descriptor)) @@ -5779,6 +5743,25 @@ class CGDescriptor(CGThing): cgThings.append(CGWeakReferenceableTrait(descriptor)) cgThings.append(CGGeneric(str(properties))) + + if not descriptor.interface.isCallback() and not descriptor.interface.isNamespace(): + cgThings.append(CGGetProtoObjectMethod(descriptor)) + reexports.append('GetProtoObject') + cgThings.append(CGPrototypeJSClass(descriptor)) + if descriptor.interface.hasInterfaceObject(): + if descriptor.interface.ctor(): + cgThings.append(CGClassConstructHook(descriptor)) + for ctor in descriptor.interface.namedConstructors: + cgThings.append(CGClassConstructHook(descriptor, ctor)) + if not descriptor.interface.isCallback(): + cgThings.append(CGInterfaceObjectJSClass(descriptor)) + if descriptor.shouldHaveGetConstructorObjectMethod(): + cgThings.append(CGGetConstructorObjectMethod(descriptor)) + reexports.append('GetConstructorObject') + if descriptor.register: + cgThings.append(CGDefineDOMInterfaceMethod(descriptor)) + reexports.append('DefineDOMInterface') + cgThings.append(CGConstructorEnabled(descriptor)) cgThings.append(CGCreateInterfaceObjectsMethod(descriptor, properties, haveUnscopables)) cgThings = generate_imports(config, CGList(cgThings, '\n'), [descriptor]) diff --git a/components/script/dom/bindings/codegen/parser/WebIDL.py b/components/script/dom/bindings/codegen/parser/WebIDL.py index 878c221f01c..2894bbeb82e 100644 --- a/components/script/dom/bindings/codegen/parser/WebIDL.py +++ b/components/script/dom/bindings/codegen/parser/WebIDL.py @@ -9,6 +9,7 @@ import re import os import traceback import math +import string from collections import defaultdict # Machinery @@ -1850,7 +1851,6 @@ class IDLDictionary(IDLObjectWithScope): """ if (memberType.nullable() or - memberType.isArray() or memberType.isSequence() or memberType.isMozMap()): return typeContainsDictionary(memberType.inner, dictionary) @@ -1973,8 +1973,7 @@ class IDLType(IDLObject): 'callback', 'union', 'sequence', - 'mozmap', - 'array' + 'mozmap' ) def __init__(self, location, name): @@ -2027,9 +2026,6 @@ class IDLType(IDLObject): def isMozMap(self): return False - def isArray(self): - return False - def isArrayBuffer(self): return False @@ -2255,9 +2251,6 @@ class IDLNullableType(IDLParameterizedType): def isMozMap(self): return self.inner.isMozMap() - def isArray(self): - return self.inner.isArray() - def isArrayBuffer(self): return self.inner.isArrayBuffer() @@ -2360,9 +2353,6 @@ class IDLSequenceType(IDLParameterizedType): def isSequence(self): return True - def isArray(self): - return False - def isDictionary(self): return False @@ -2575,106 +2565,6 @@ class IDLUnionType(IDLType): return set(self.memberTypes) -class IDLArrayType(IDLType): - def __init__(self, location, parameterType): - assert not parameterType.isVoid() - if parameterType.isSequence(): - raise WebIDLError("Array type cannot parameterize over a sequence type", - [location]) - if parameterType.isMozMap(): - raise WebIDLError("Array type cannot parameterize over a MozMap type", - [location]) - if parameterType.isDictionary(): - raise WebIDLError("Array type cannot parameterize over a dictionary type", - [location]) - - IDLType.__init__(self, location, parameterType.name) - self.inner = parameterType - self.builtin = False - - def __eq__(self, other): - return isinstance(other, IDLArrayType) and self.inner == other.inner - - def __str__(self): - return self.inner.__str__() + "Array" - - def nullable(self): - return False - - def isPrimitive(self): - return False - - def isString(self): - return False - - def isByteString(self): - return False - - def isDOMString(self): - return False - - def isUSVString(self): - return False - - def isVoid(self): - return False - - def isSequence(self): - assert not self.inner.isSequence() - return False - - def isArray(self): - return True - - def isDictionary(self): - assert not self.inner.isDictionary() - return False - - def isInterface(self): - return False - - def isEnum(self): - return False - - def tag(self): - return IDLType.Tags.array - - def resolveType(self, parentScope): - assert isinstance(parentScope, IDLScope) - self.inner.resolveType(parentScope) - - def isComplete(self): - return self.inner.isComplete() - - def complete(self, scope): - self.inner = self.inner.complete(scope) - self.name = self.inner.name - - if self.inner.isDictionary(): - raise WebIDLError("Array type must not contain " - "dictionary as element type.", - [self.inner.location]) - - assert not self.inner.isSequence() - - return self - - def unroll(self): - return self.inner.unroll() - - def isDistinguishableFrom(self, other): - if other.isPromise(): - return False - if other.isUnion(): - # Just forward to the union; it'll deal - return other.isDistinguishableFrom(self) - return (other.isPrimitive() or other.isString() or other.isEnum() or - other.isDate() or other.isNonCallbackInterface()) - - def _getDependentObjects(self): - return self.inner._getDependentObjects() - - class IDLTypedefType(IDLType): def __init__(self, location, innerType, name): IDLType.__init__(self, location, name) @@ -2720,9 +2610,6 @@ class IDLTypedefType(IDLType): def isMozMap(self): return self.inner.isMozMap() - def isArray(self): - return self.inner.isArray() - def isDictionary(self): return self.inner.isDictionary() @@ -2838,9 +2725,6 @@ class IDLWrapperType(IDLType): def isSequence(self): return False - def isArray(self): - return False - def isDictionary(self): return isinstance(self.inner, IDLDictionary) @@ -2907,8 +2791,7 @@ class IDLWrapperType(IDLType): if self.isEnum(): return (other.isPrimitive() or other.isInterface() or other.isObject() or other.isCallback() or other.isDictionary() or - other.isSequence() or other.isMozMap() or other.isArray() or - other.isDate()) + other.isSequence() or other.isMozMap() or other.isDate()) if self.isDictionary() and other.nullable(): return False if (other.isPrimitive() or other.isString() or other.isEnum() or @@ -2930,7 +2813,7 @@ class IDLWrapperType(IDLType): (self.isNonCallbackInterface() or other.isNonCallbackInterface())) if (other.isDictionary() or other.isCallback() or - other.isMozMap() or other.isArray()): + other.isMozMap()): return self.isNonCallbackInterface() # Not much else |other| can be @@ -3140,20 +3023,17 @@ class IDLBuiltinType(IDLType): return (other.isNumeric() or other.isString() or other.isEnum() or other.isInterface() or other.isObject() or other.isCallback() or other.isDictionary() or - other.isSequence() or other.isMozMap() or other.isArray() or - other.isDate()) + other.isSequence() or other.isMozMap() or other.isDate()) if self.isNumeric(): return (other.isBoolean() or other.isString() or other.isEnum() or other.isInterface() or other.isObject() or other.isCallback() or other.isDictionary() or - other.isSequence() or other.isMozMap() or other.isArray() or - other.isDate()) + other.isSequence() or other.isMozMap() or other.isDate()) if self.isString(): return (other.isPrimitive() or other.isInterface() or other.isObject() or other.isCallback() or other.isDictionary() or - other.isSequence() or other.isMozMap() or other.isArray() or - other.isDate()) + other.isSequence() or other.isMozMap() or other.isDate()) if self.isAny(): # Can't tell "any" apart from anything return False @@ -3163,7 +3043,7 @@ class IDLBuiltinType(IDLType): return (other.isPrimitive() or other.isString() or other.isEnum() or other.isInterface() or other.isCallback() or other.isDictionary() or other.isSequence() or - other.isMozMap() or other.isArray()) + other.isMozMap()) if self.isVoid(): return not other.isVoid() # Not much else we could be! @@ -3171,8 +3051,7 @@ class IDLBuiltinType(IDLType): # Like interfaces, but we know we're not a callback return (other.isPrimitive() or other.isString() or other.isEnum() or other.isCallback() or other.isDictionary() or - other.isSequence() or other.isMozMap() or other.isArray() or - other.isDate() or + other.isSequence() or other.isMozMap() or other.isDate() or (other.isInterface() and ( # ArrayBuffer is distinguishable from everything # that's not an ArrayBuffer or a callback interface @@ -3311,6 +3190,11 @@ def matchIntegerValueToType(value): return None +class NoCoercionFoundError(WebIDLError): + """ + A class we use to indicate generic coercion failures because none of the + types worked out in IDLValue.coerceToType. + """ class IDLValue(IDLObject): def __init__(self, location, type, value): @@ -3338,8 +3222,18 @@ class IDLValue(IDLObject): # use the value's type when it is a default value of a # union, and the union cares about the exact float type. return IDLValue(self.location, subtype, coercedValue.value) - except: - pass + except Exception as e: + # Make sure to propagate out WebIDLErrors that are not the + # generic "hey, we could not coerce to this type at all" + # exception, because those are specific "coercion failed for + # reason X" exceptions. Note that we want to swallow + # non-WebIDLErrors here, because those can just happen if + # "type" is not something that can have a default value at + # all. + if (isinstance(e, WebIDLError) and + not isinstance(e, NoCoercionFoundError)): + raise e + # If the type allows null, rerun this matching on the inner type, except # nullable enums. We handle those specially, because we want our # default string values to stay strings even when assigned to a nullable @@ -3388,12 +3282,21 @@ class IDLValue(IDLObject): assert self.type.isDOMString() return self elif self.type.isString() and type.isByteString(): - # Allow ByteStrings to use default value just like - # DOMString. No coercion is required here. - assert self.type.isDOMString() - return self - raise WebIDLError("Cannot coerce type %s to type %s." % - (self.type, type), [location]) + # Allow ByteStrings to use a default value like DOMString. + # No coercion is required as Codegen.py will handle the + # extra steps. We want to make sure that our string contains + # only valid characters, so we check that here. + valid_ascii_lit = " " + string.ascii_letters + string.digits + string.punctuation + for idx, c in enumerate(self.value): + if c not in valid_ascii_lit: + raise WebIDLError("Coercing this string literal %s to a ByteString is not supported yet. " + "Coercion failed due to an unsupported byte %d at index %d." + % (self.value.__repr__(), ord(c), idx), [location]) + + return IDLValue(self.location, type, self.value) + + raise NoCoercionFoundError("Cannot coerce type %s to type %s." % + (self.type, type), [location]) def _getDependentObjects(self): return set() @@ -4568,12 +4471,6 @@ class IDLMethod(IDLInterfaceMember, IDLScope): base=IDLInterfaceMember.Special ) - TypeSuffixModifier = enum( - 'None', - 'QMark', - 'Brackets' - ) - NamedOrIndexed = enum( 'Neither', 'Named', @@ -5743,14 +5640,6 @@ class Parser(Tokenizer): booleanType = BuiltinTypes[IDLBuiltinType.Types.boolean] p[0] = IDLValue(location, booleanType, p[1]) - def p_ConstValueByteString(self, p): - """ - ConstValue : BYTESTRING - """ - location = self.getLocation(p, 1) - bytestringType = BuiltinTypes[IDLBuiltinType.Types.bytestring] - p[0] = IDLValue(location, bytestringType, p[1]) - def p_ConstValueInteger(self, p): """ ConstValue : INTEGER @@ -6383,9 +6272,9 @@ class Parser(Tokenizer): def p_TypeUnionType(self, p): """ - Type : UnionType TypeSuffix + Type : UnionType Null """ - p[0] = self.handleModifiers(p[1], p[2]) + p[0] = self.handleNullable(p[1], p[2]) def p_SingleTypeNonAnyType(self, p): """ @@ -6395,9 +6284,9 @@ class Parser(Tokenizer): def p_SingleTypeAnyType(self, p): """ - SingleType : ANY TypeSuffixStartingWithArray + SingleType : ANY """ - p[0] = self.handleModifiers(BuiltinTypes[IDLBuiltinType.Types.any], p[2]) + p[0] = BuiltinTypes[IDLBuiltinType.Types.any] def p_UnionType(self, p): """ @@ -6413,19 +6302,11 @@ class Parser(Tokenizer): """ p[0] = p[1] - def p_UnionMemberTypeArrayOfAny(self, p): - """ - UnionMemberTypeArrayOfAny : ANY LBRACKET RBRACKET - """ - p[0] = IDLArrayType(self.getLocation(p, 2), - BuiltinTypes[IDLBuiltinType.Types.any]) - def p_UnionMemberType(self, p): """ - UnionMemberType : UnionType TypeSuffix - | UnionMemberTypeArrayOfAny TypeSuffix + UnionMemberType : UnionType Null """ - p[0] = self.handleModifiers(p[1], p[2]) + p[0] = self.handleNullable(p[1], p[2]) def p_UnionMemberTypes(self, p): """ @@ -6442,10 +6323,10 @@ class Parser(Tokenizer): def p_NonAnyType(self, p): """ - NonAnyType : PrimitiveOrStringType TypeSuffix - | ARRAYBUFFER TypeSuffix - | SHAREDARRAYBUFFER TypeSuffix - | OBJECT TypeSuffix + NonAnyType : PrimitiveOrStringType Null + | ARRAYBUFFER Null + | SHAREDARRAYBUFFER Null + | OBJECT Null """ if p[1] == "object": type = BuiltinTypes[IDLBuiltinType.Types.object] @@ -6456,7 +6337,7 @@ class Parser(Tokenizer): else: type = BuiltinTypes[p[1]] - p[0] = self.handleModifiers(type, p[2]) + p[0] = self.handleNullable(type, p[2]) def p_NonAnyTypeSequenceType(self, p): """ @@ -6464,9 +6345,7 @@ class Parser(Tokenizer): """ innerType = p[3] type = IDLSequenceType(self.getLocation(p, 1), innerType) - if p[5]: - type = IDLNullableType(self.getLocation(p, 5), type) - p[0] = type + p[0] = self.handleNullable(type, p[5]) # Note: Promise<void> is allowed, so we want to parametrize on # ReturnType, not Type. Also, we want this to end up picking up @@ -6478,9 +6357,7 @@ class Parser(Tokenizer): innerType = p[3] promiseIdent = IDLUnresolvedIdentifier(self.getLocation(p, 1), "Promise") type = IDLUnresolvedType(self.getLocation(p, 1), promiseIdent, p[3]) - if p[5]: - type = IDLNullableType(self.getLocation(p, 5), type) - p[0] = type + p[0] = self.handleNullable(type, p[5]) def p_NonAnyTypeMozMapType(self, p): """ @@ -6488,13 +6365,11 @@ class Parser(Tokenizer): """ innerType = p[3] type = IDLMozMapType(self.getLocation(p, 1), innerType) - if p[5]: - type = IDLNullableType(self.getLocation(p, 5), type) - p[0] = type + p[0] = self.handleNullable(type, p[5]) def p_NonAnyTypeScopedName(self, p): """ - NonAnyType : ScopedName TypeSuffix + NonAnyType : ScopedName Null """ assert isinstance(p[1], IDLUnresolvedIdentifier) @@ -6516,29 +6391,27 @@ class Parser(Tokenizer): type = IDLCallbackType(obj.location, obj) else: type = IDLWrapperType(self.getLocation(p, 1), p[1]) - p[0] = self.handleModifiers(type, p[2]) + p[0] = self.handleNullable(type, p[2]) return except: pass type = IDLUnresolvedType(self.getLocation(p, 1), p[1]) - p[0] = self.handleModifiers(type, p[2]) + p[0] = self.handleNullable(type, p[2]) def p_NonAnyTypeDate(self, p): """ - NonAnyType : DATE TypeSuffix + NonAnyType : DATE Null """ - p[0] = self.handleModifiers(BuiltinTypes[IDLBuiltinType.Types.date], - p[2]) + p[0] = self.handleNullable(BuiltinTypes[IDLBuiltinType.Types.date], + p[2]) def p_ConstType(self, p): """ ConstType : PrimitiveOrStringType Null """ type = BuiltinTypes[p[1]] - if p[2]: - type = IDLNullableType(self.getLocation(p, 1), type) - p[0] = type + p[0] = self.handleNullable(type, p[2]) def p_ConstTypeIdentifier(self, p): """ @@ -6547,9 +6420,7 @@ class Parser(Tokenizer): identifier = IDLUnresolvedIdentifier(self.getLocation(p, 1), p[1]) type = IDLUnresolvedType(self.getLocation(p, 1), identifier) - if p[2]: - type = IDLNullableType(self.getLocation(p, 1), type) - p[0] = type + p[0] = self.handleNullable(type, p[2]) def p_PrimitiveOrStringTypeUint(self, p): """ @@ -6657,48 +6528,15 @@ class Parser(Tokenizer): """ p[0] = False - def p_TypeSuffixBrackets(self, p): - """ - TypeSuffix : LBRACKET RBRACKET TypeSuffix - """ - p[0] = [(IDLMethod.TypeSuffixModifier.Brackets, self.getLocation(p, 1))] - p[0].extend(p[3]) - - def p_TypeSuffixQMark(self, p): - """ - TypeSuffix : QUESTIONMARK TypeSuffixStartingWithArray - """ - p[0] = [(IDLMethod.TypeSuffixModifier.QMark, self.getLocation(p, 1))] - p[0].extend(p[2]) - - def p_TypeSuffixEmpty(self, p): - """ - TypeSuffix : - """ - p[0] = [] - - def p_TypeSuffixStartingWithArray(self, p): - """ - TypeSuffixStartingWithArray : LBRACKET RBRACKET TypeSuffix - """ - p[0] = [(IDLMethod.TypeSuffixModifier.Brackets, self.getLocation(p, 1))] - p[0].extend(p[3]) - - def p_TypeSuffixStartingWithArrayEmpty(self, p): - """ - TypeSuffixStartingWithArray : - """ - p[0] = [] - def p_Null(self, p): """ Null : QUESTIONMARK | """ if len(p) > 1: - p[0] = True + p[0] = self.getLocation(p, 1) else: - p[0] = False + p[0] = None def p_ReturnTypeType(self, p): """ @@ -6857,15 +6695,9 @@ class Parser(Tokenizer): typedef = IDLTypedef(BuiltinLocation("<builtin type>"), scope, builtin, name) @ staticmethod - def handleModifiers(type, modifiers): - for (modifier, modifierLocation) in modifiers: - assert (modifier == IDLMethod.TypeSuffixModifier.QMark or - modifier == IDLMethod.TypeSuffixModifier.Brackets) - - if modifier == IDLMethod.TypeSuffixModifier.QMark: - type = IDLNullableType(modifierLocation, type) - elif modifier == IDLMethod.TypeSuffixModifier.Brackets: - type = IDLArrayType(modifierLocation, type) + def handleNullable(type, questionMarkLocation): + if questionMarkLocation is not None: + type = IDLNullableType(questionMarkLocation, type) return type diff --git a/components/script/dom/bindings/codegen/parser/bytestring.patch b/components/script/dom/bindings/codegen/parser/bytestring.patch deleted file mode 100644 index 823f14cf996..00000000000 --- a/components/script/dom/bindings/codegen/parser/bytestring.patch +++ /dev/null @@ -1,29 +0,0 @@ ---- WebIDL.py -+++ WebIDL.py -@@ -3391,6 +3391,11 @@ class IDLValue(IDLObject): - # extra normalization step. - assert self.type.isDOMString() - return self -+ elif self.type.isString() and type.isByteString(): -+ # Allow ByteStrings to use default value just like -+ # DOMString. No coercion is required here. -+ assert self.type.isDOMString() -+ return self - raise WebIDLError("Cannot coerce type %s to type %s." % - (self.type, type), [location]) - -@@ -5759,6 +5764,14 @@ class Parser(Tokenizer): - booleanType = BuiltinTypes[IDLBuiltinType.Types.boolean] - p[0] = IDLValue(location, booleanType, p[1]) - -+ def p_ConstValueByteString(self, p): -+ """ -+ ConstValue : BYTESTRING -+ """ -+ location = self.getLocation(p, 1) -+ bytestringType = BuiltinTypes[IDLBuiltinType.Types.bytestring] -+ p[0] = IDLValue(location, bytestringType, p[1]) -+ - def p_ConstValueInteger(self, p): - """ - ConstValue : INTEGER diff --git a/components/script/dom/bindings/codegen/parser/tests/test_array.py b/components/script/dom/bindings/codegen/parser/tests/test_array.py deleted file mode 100644 index 8f9e9c96854..00000000000 --- a/components/script/dom/bindings/codegen/parser/tests/test_array.py +++ /dev/null @@ -1,18 +0,0 @@ -def WebIDLTest(parser, harness): - threw = False - try: - parser.parse(""" - dictionary Foo { - short a; - }; - - dictionary Foo1 { - Foo[] b; - }; - """) - results = parser.finish() - except: - threw = True - - harness.ok(threw, "Array must not contain dictionary " - "as element type.") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_array_of_interface.py b/components/script/dom/bindings/codegen/parser/tests/test_array_of_interface.py deleted file mode 100644 index 26528984595..00000000000 --- a/components/script/dom/bindings/codegen/parser/tests/test_array_of_interface.py +++ /dev/null @@ -1,13 +0,0 @@ -import WebIDL - -def WebIDLTest(parser, harness): - parser.parse(""" - interface A { - attribute long a; - }; - - interface B { - attribute A[] b; - }; - """); - parser.finish() diff --git a/components/script/dom/bindings/codegen/parser/tests/test_arraybuffer.py b/components/script/dom/bindings/codegen/parser/tests/test_arraybuffer.py index 5b8e56f86ca..4a96c0ff512 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_arraybuffer.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_arraybuffer.py @@ -4,37 +4,37 @@ def WebIDLTest(parser, harness): parser.parse(""" interface TestArrayBuffer { attribute ArrayBuffer bufferAttr; - void bufferMethod(ArrayBuffer arg1, ArrayBuffer? arg2, ArrayBuffer[] arg3, sequence<ArrayBuffer> arg4); + void bufferMethod(ArrayBuffer arg1, ArrayBuffer? arg2, sequence<ArrayBuffer> arg3); attribute ArrayBufferView viewAttr; - void viewMethod(ArrayBufferView arg1, ArrayBufferView? arg2, ArrayBufferView[] arg3, sequence<ArrayBufferView> arg4); + void viewMethod(ArrayBufferView arg1, ArrayBufferView? arg2, sequence<ArrayBufferView> arg3); attribute Int8Array int8ArrayAttr; - void int8ArrayMethod(Int8Array arg1, Int8Array? arg2, Int8Array[] arg3, sequence<Int8Array> arg4); + void int8ArrayMethod(Int8Array arg1, Int8Array? arg2, sequence<Int8Array> arg3); attribute Uint8Array uint8ArrayAttr; - void uint8ArrayMethod(Uint8Array arg1, Uint8Array? arg2, Uint8Array[] arg3, sequence<Uint8Array> arg4); + void uint8ArrayMethod(Uint8Array arg1, Uint8Array? arg2, sequence<Uint8Array> arg3); attribute Uint8ClampedArray uint8ClampedArrayAttr; - void uint8ClampedArrayMethod(Uint8ClampedArray arg1, Uint8ClampedArray? arg2, Uint8ClampedArray[] arg3, sequence<Uint8ClampedArray> arg4); + void uint8ClampedArrayMethod(Uint8ClampedArray arg1, Uint8ClampedArray? arg2, sequence<Uint8ClampedArray> arg3); attribute Int16Array int16ArrayAttr; - void int16ArrayMethod(Int16Array arg1, Int16Array? arg2, Int16Array[] arg3, sequence<Int16Array> arg4); + void int16ArrayMethod(Int16Array arg1, Int16Array? arg2, sequence<Int16Array> arg3); attribute Uint16Array uint16ArrayAttr; - void uint16ArrayMethod(Uint16Array arg1, Uint16Array? arg2, Uint16Array[] arg3, sequence<Uint16Array> arg4); + void uint16ArrayMethod(Uint16Array arg1, Uint16Array? arg2, sequence<Uint16Array> arg3); attribute Int32Array int32ArrayAttr; - void int32ArrayMethod(Int32Array arg1, Int32Array? arg2, Int32Array[] arg3, sequence<Int32Array> arg4); + void int32ArrayMethod(Int32Array arg1, Int32Array? arg2, sequence<Int32Array> arg3); attribute Uint32Array uint32ArrayAttr; - void uint32ArrayMethod(Uint32Array arg1, Uint32Array? arg2, Uint32Array[] arg3, sequence<Uint32Array> arg4); + void uint32ArrayMethod(Uint32Array arg1, Uint32Array? arg2, sequence<Uint32Array> arg3); attribute Float32Array float32ArrayAttr; - void float32ArrayMethod(Float32Array arg1, Float32Array? arg2, Float32Array[] arg3, sequence<Float32Array> arg4); + void float32ArrayMethod(Float32Array arg1, Float32Array? arg2, sequence<Float32Array> arg3); attribute Float64Array float64ArrayAttr; - void float64ArrayMethod(Float64Array arg1, Float64Array? arg2, Float64Array[] arg3, sequence<Float64Array> arg4); + void float64ArrayMethod(Float64Array arg1, Float64Array? arg2, sequence<Float64Array> arg3); }; """) @@ -56,7 +56,7 @@ def WebIDLTest(parser, harness): (retType, arguments) = method.signatures()[0] harness.ok(retType.isVoid(), "Should have a void return type") - harness.check(len(arguments), 4, "Expect 4 arguments") + harness.check(len(arguments), 3, "Expect 3 arguments") harness.check(str(arguments[0].type), t, "Expect an ArrayBuffer type") harness.ok(arguments[0].type.isSpiderMonkeyInterface(), "Should test as a js interface") @@ -64,12 +64,9 @@ def WebIDLTest(parser, harness): harness.check(str(arguments[1].type), t + "OrNull", "Expect an ArrayBuffer type") harness.ok(arguments[1].type.inner.isSpiderMonkeyInterface(), "Should test as a js interface") - harness.check(str(arguments[2].type), t + "Array", "Expect an ArrayBuffer type") + harness.check(str(arguments[2].type), t + "Sequence", "Expect an ArrayBuffer type") harness.ok(arguments[2].type.inner.isSpiderMonkeyInterface(), "Should test as a js interface") - harness.check(str(arguments[3].type), t + "Sequence", "Expect an ArrayBuffer type") - harness.ok(arguments[3].type.inner.isSpiderMonkeyInterface(), "Should test as a js interface") - checkStuff(members[0], members[1], "ArrayBuffer") checkStuff(members[2], members[3], "ArrayBufferView") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_attr.py b/components/script/dom/bindings/codegen/parser/tests/test_attr.py index fb0c9196460..ad7aabc1918 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_attr.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_attr.py @@ -77,110 +77,6 @@ def WebIDLTest(parser, harness): attribute float? f; readonly attribute float? rf; }; - - interface TestAttrArray { - attribute byte[] b; - readonly attribute byte[] rb; - attribute octet[] o; - readonly attribute octet[] ro; - attribute short[] s; - readonly attribute short[] rs; - attribute unsigned short[] us; - readonly attribute unsigned short[] rus; - attribute long[] l; - readonly attribute long[] rl; - attribute unsigned long[] ul; - readonly attribute unsigned long[] rul; - attribute long long[] ll; - readonly attribute long long[] rll; - attribute unsigned long long[] ull; - readonly attribute unsigned long long[] rull; - attribute DOMString[] str; - readonly attribute DOMString[] rstr; - attribute object[] obj; - readonly attribute object[] robj; - attribute object[] _object; - attribute float[] f; - readonly attribute float[] rf; - }; - - interface TestAttrNullableArray { - attribute byte[]? b; - readonly attribute byte[]? rb; - attribute octet[]? o; - readonly attribute octet[]? ro; - attribute short[]? s; - readonly attribute short[]? rs; - attribute unsigned short[]? us; - readonly attribute unsigned short[]? rus; - attribute long[]? l; - readonly attribute long[]? rl; - attribute unsigned long[]? ul; - readonly attribute unsigned long[]? rul; - attribute long long[]? ll; - readonly attribute long long[]? rll; - attribute unsigned long long[]? ull; - readonly attribute unsigned long long[]? rull; - attribute DOMString[]? str; - readonly attribute DOMString[]? rstr; - attribute object[]? obj; - readonly attribute object[]? robj; - attribute object[]? _object; - attribute float[]? f; - readonly attribute float[]? rf; - }; - - interface TestAttrArrayOfNullableTypes { - attribute byte?[] b; - readonly attribute byte?[] rb; - attribute octet?[] o; - readonly attribute octet?[] ro; - attribute short?[] s; - readonly attribute short?[] rs; - attribute unsigned short?[] us; - readonly attribute unsigned short?[] rus; - attribute long?[] l; - readonly attribute long?[] rl; - attribute unsigned long?[] ul; - readonly attribute unsigned long?[] rul; - attribute long long?[] ll; - readonly attribute long long?[] rll; - attribute unsigned long long?[] ull; - readonly attribute unsigned long long?[] rull; - attribute DOMString?[] str; - readonly attribute DOMString?[] rstr; - attribute object?[] obj; - readonly attribute object?[] robj; - attribute object?[] _object; - attribute float?[] f; - readonly attribute float?[] rf; - }; - - interface TestAttrNullableArrayOfNullableTypes { - attribute byte?[]? b; - readonly attribute byte?[]? rb; - attribute octet?[]? o; - readonly attribute octet?[]? ro; - attribute short?[]? s; - readonly attribute short?[]? rs; - attribute unsigned short?[]? us; - readonly attribute unsigned short?[]? rus; - attribute long?[]? l; - readonly attribute long?[]? rl; - attribute unsigned long?[]? ul; - readonly attribute unsigned long?[]? rul; - attribute long long?[]? ll; - readonly attribute long long?[]? rll; - attribute unsigned long long?[]? ull; - readonly attribute unsigned long long?[]? rull; - attribute DOMString?[]? str; - readonly attribute DOMString?[]? rstr; - attribute object?[]? obj; - readonly attribute object?[]? robj; - attribute object?[]? _object; - attribute float?[]? f; - readonly attribute float?[]? rf; - }; """) results = parser.finish() @@ -197,7 +93,7 @@ def WebIDLTest(parser, harness): harness.check(attr.readonly, readonly, "Attr's readonly state is correct") harness.ok(True, "TestAttr interface parsed without error.") - harness.check(len(results), 6, "Should be six productions.") + harness.check(len(results), 2, "Should be two productions.") iface = results[0] harness.ok(isinstance(iface, WebIDL.IDLInterface), "Should be an IDLInterface") @@ -228,66 +124,6 @@ def WebIDLTest(parser, harness): (QName, name, type, readonly) = data checkAttr(attr, QName % "Nullable", name, type % "OrNull", readonly) - iface = results[2] - harness.ok(isinstance(iface, WebIDL.IDLInterface), - "Should be an IDLInterface") - harness.check(iface.identifier.QName(), "::TestAttrArray", "Interface has the right QName") - harness.check(iface.identifier.name, "TestAttrArray", "Interface has the right name") - harness.check(len(iface.members), len(testData), "Expect %s members" % len(testData)) - - attrs = iface.members - - for i in range(len(attrs)): - data = testData[i] - attr = attrs[i] - (QName, name, type, readonly) = data - checkAttr(attr, QName % "Array", name, type % "Array", readonly) - - iface = results[3] - harness.ok(isinstance(iface, WebIDL.IDLInterface), - "Should be an IDLInterface") - harness.check(iface.identifier.QName(), "::TestAttrNullableArray", "Interface has the right QName") - harness.check(iface.identifier.name, "TestAttrNullableArray", "Interface has the right name") - harness.check(len(iface.members), len(testData), "Expect %s members" % len(testData)) - - attrs = iface.members - - for i in range(len(attrs)): - data = testData[i] - attr = attrs[i] - (QName, name, type, readonly) = data - checkAttr(attr, QName % "NullableArray", name, type % "ArrayOrNull", readonly) - - iface = results[4] - harness.ok(isinstance(iface, WebIDL.IDLInterface), - "Should be an IDLInterface") - harness.check(iface.identifier.QName(), "::TestAttrArrayOfNullableTypes", "Interface has the right QName") - harness.check(iface.identifier.name, "TestAttrArrayOfNullableTypes", "Interface has the right name") - harness.check(len(iface.members), len(testData), "Expect %s members" % len(testData)) - - attrs = iface.members - - for i in range(len(attrs)): - data = testData[i] - attr = attrs[i] - (QName, name, type, readonly) = data - checkAttr(attr, QName % "ArrayOfNullableTypes", name, type % "OrNullArray", readonly) - - iface = results[5] - harness.ok(isinstance(iface, WebIDL.IDLInterface), - "Should be an IDLInterface") - harness.check(iface.identifier.QName(), "::TestAttrNullableArrayOfNullableTypes", "Interface has the right QName") - harness.check(iface.identifier.name, "TestAttrNullableArrayOfNullableTypes", "Interface has the right name") - harness.check(len(iface.members), len(testData), "Expect %s members" % len(testData)) - - attrs = iface.members - - for i in range(len(attrs)): - data = testData[i] - attr = attrs[i] - (QName, name, type, readonly) = data - checkAttr(attr, QName % "NullableArrayOfNullableTypes", name, type % "OrNullArrayOrNull", readonly) - parser = parser.reset() threw = False try: diff --git a/components/script/dom/bindings/codegen/parser/tests/test_bytestring.py b/components/script/dom/bindings/codegen/parser/tests/test_bytestring.py index d73455f8812..fa83e9e2d57 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_bytestring.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_bytestring.py @@ -13,7 +13,7 @@ def WebIDLTest(parser, harness): results = parser.finish(); harness.ok(True, "TestByteString interface parsed without error.") - + harness.check(len(results), 1, "Should be one production") harness.ok(isinstance(results[0], WebIDL.IDLInterface), "Should be an IDLInterface") @@ -54,10 +54,9 @@ def WebIDLTest(parser, harness): """) except WebIDL.WebIDLError: threw = True - harness.ok(threw, "Should have thrown a WebIDL error") + harness.ok(threw, "Should have thrown a WebIDL error for ByteString default in interface") - # Cannot have optional ByteStrings with default values - threw = False + # Can have optional ByteStrings with default values try: parser.parse(""" interface OptionalByteString { @@ -65,8 +64,36 @@ def WebIDLTest(parser, harness): }; """) results2 = parser.finish(); - except WebIDL.WebIDLError: - threw = True + except WebIDL.WebIDLError as e: + harness.ok(False, + "Should not have thrown a WebIDL error for ByteString " + "default in dictionary. " + str(e)) - harness.ok(threw, "Should have thrown a WebIDL error") + # Can have a default ByteString value in a dictionary + try: + parser.parse(""" + dictionary OptionalByteStringDict { + ByteString item = "some string"; + }; + """) + results3 = parser.finish(); + except WebIDL.WebIDLError as e: + harness.ok(False, + "Should not have thrown a WebIDL error for ByteString " + "default in dictionary. " + str(e)) + + # Don't allow control characters in ByteString literals + threw = False + try: + parser.parse(""" + dictionary OptionalByteStringDict2 { + ByteString item = "\x03"; + }; + """) + results4 = parser.finish() + except WebIDL.WebIDLError as e: + threw = True + harness.ok(threw, + "Should have thrown a WebIDL error for invalid ByteString " + "default in dictionary") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_distinguishability.py b/components/script/dom/bindings/codegen/parser/tests/test_distinguishability.py index 866816f2e0c..d7780c1ffa1 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_distinguishability.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_distinguishability.py @@ -159,7 +159,7 @@ def WebIDLTest(parser, harness): "object", "Callback", "Callback2", "optional Dict", "optional Dict2", "sequence<long>", "sequence<short>", "MozMap<object>", "MozMap<Dict>", "MozMap<long>", - "long[]", "short[]", "Date", "Date?", "any", + "Date", "Date?", "any", "Promise<any>", "Promise<any>?", "USVString", "ArrayBuffer", "ArrayBufferView", "SharedArrayBuffer", "Uint8Array", "Uint16Array" ] @@ -187,7 +187,6 @@ def WebIDLTest(parser, harness): "Date?", "any", "Promise<any>?"] dates = [ "Date", "Date?" ] sequences = [ "sequence<long>", "sequence<short>" ] - arrays = [ "long[]", "short[]" ] nonUserObjects = nonObjects + interfaces + dates + sequences otherObjects = allBut(argTypes, nonUserObjects + ["object"]) notRelatedInterfaces = (nonObjects + ["UnrelatedInterface"] + @@ -229,14 +228,12 @@ def WebIDLTest(parser, harness): setDistinguishable("optional Dict", allBut(nonUserObjects, nullables)) setDistinguishable("optional Dict2", allBut(nonUserObjects, nullables)) setDistinguishable("sequence<long>", - allBut(argTypes, sequences + arrays + ["object"])) + allBut(argTypes, sequences + ["object"])) setDistinguishable("sequence<short>", - allBut(argTypes, sequences + arrays + ["object"])) + allBut(argTypes, sequences + ["object"])) setDistinguishable("MozMap<object>", nonUserObjects) setDistinguishable("MozMap<Dict>", nonUserObjects) setDistinguishable("MozMap<long>", nonUserObjects) - setDistinguishable("long[]", allBut(nonUserObjects, sequences)) - setDistinguishable("short[]", allBut(nonUserObjects, sequences)) setDistinguishable("Date", allBut(argTypes, dates + ["object"])) setDistinguishable("Date?", allBut(argTypes, dates + nullables + ["object"])) setDistinguishable("any", []) diff --git a/components/script/dom/bindings/codegen/parser/tests/test_method.py b/components/script/dom/bindings/codegen/parser/tests/test_method.py index f6f54c33ab6..cf7f1b40d76 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_method.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_method.py @@ -11,7 +11,6 @@ def WebIDLTest(parser, harness): boolean basicBooleanWithSimpleArgs(boolean arg1, byte arg2, unsigned long arg3); void optionalArg(optional byte? arg1, optional sequence<byte> arg2); void variadicArg(byte?... arg1); - void crazyTypes(sequence<long?[]>? arg1, boolean?[][]? arg2); object getObject(); void setObject(object arg1); void setAny(any arg1); @@ -28,7 +27,7 @@ def WebIDLTest(parser, harness): "Should be an IDLInterface") harness.check(iface.identifier.QName(), "::TestMethods", "Interface has the right QName") harness.check(iface.identifier.name, "TestMethods", "Interface has the right name") - harness.check(len(iface.members), 13, "Expect 13 members") + harness.check(len(iface.members), 12, "Expect 12 members") methods = iface.members @@ -98,22 +97,17 @@ def WebIDLTest(parser, harness): "variadicArg", [("Void", [("::TestMethods::variadicArg::arg1", "arg1", "ByteOrNull", True, True)])]) - checkMethod(methods[8], "::TestMethods::crazyTypes", - "crazyTypes", - [("Void", - [("::TestMethods::crazyTypes::arg1", "arg1", "LongOrNullArraySequenceOrNull", False, False), - ("::TestMethods::crazyTypes::arg2", "arg2", "BooleanOrNullArrayArrayOrNull", False, False)])]) - checkMethod(methods[9], "::TestMethods::getObject", + checkMethod(methods[8], "::TestMethods::getObject", "getObject", [("Object", [])]) - checkMethod(methods[10], "::TestMethods::setObject", + checkMethod(methods[9], "::TestMethods::setObject", "setObject", [("Void", [("::TestMethods::setObject::arg1", "arg1", "Object", False, False)])]) - checkMethod(methods[11], "::TestMethods::setAny", + checkMethod(methods[10], "::TestMethods::setAny", "setAny", [("Void", [("::TestMethods::setAny::arg1", "arg1", "Any", False, False)])]) - checkMethod(methods[12], "::TestMethods::doFloats", + checkMethod(methods[11], "::TestMethods::doFloats", "doFloats", [("Float", [("::TestMethods::doFloats::arg1", "arg1", "Float", False, False)])]) diff --git a/components/script/dom/bindings/codegen/parser/tests/test_nullable_equivalency.py b/components/script/dom/bindings/codegen/parser/tests/test_nullable_equivalency.py index 1f72b2c6e67..2b48b615dd4 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_nullable_equivalency.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_nullable_equivalency.py @@ -53,16 +53,6 @@ def WebIDLTest(parser, harness): attribute object a; attribute object? b; }; - - interface TestNullableEquivalency11 { - attribute double[] a; - attribute double[]? b; - }; - - interface TestNullableEquivalency12 { - attribute TestNullableEquivalency9[] a; - attribute TestNullableEquivalency9[]? b; - }; """) for decl in parser.finish(): diff --git a/components/script/dom/bindings/codegen/parser/tests/test_union.py b/components/script/dom/bindings/codegen/parser/tests/test_union.py index 36cacf3ccf4..9c4f2a56ab6 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_union.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_union.py @@ -139,9 +139,6 @@ def WebIDLTest(parser, harness): void method${i}(${type} arg); ${type} returnMethod${i}(); attribute ${type} attr${i}; - void arrayMethod${i}(${type}[] arg); - ${type}[] arrayReturnMethod${i}(); - attribute ${type}[] arrayAttr${i}; void optionalMethod${i}(${type}? arg); """).substitute(i=i, type=type) interface += """ diff --git a/components/script/dom/bindings/codegen/parser/union-typedef.patch b/components/script/dom/bindings/codegen/parser/union-typedef.patch new file mode 100644 index 00000000000..3021e14193f --- /dev/null +++ b/components/script/dom/bindings/codegen/parser/union-typedef.patch @@ -0,0 +1,22 @@ +--- WebIDL.py ++++ WebIDL.py +@@ -2481,10 +2481,18 @@ class IDLUnionType(IDLType): + return type.name + + for (i, type) in enumerate(self.memberTypes): ++ # Exclude typedefs because if given "typedef (B or C) test", ++ # we want AOrTest, not AOrBOrC ++ if not type.isComplete() and not isinstance(type, IDLTypedefType): ++ self.memberTypes[i] = type.complete(scope) ++ ++ self.name = "Or".join(typeName(type) for type in self.memberTypes) ++ ++ # We do this again to complete the typedef types ++ for (i, type) in enumerate(self.memberTypes): + if not type.isComplete(): + self.memberTypes[i] = type.complete(scope) + +- self.name = "Or".join(typeName(type) for type in self.memberTypes) + self.flatMemberTypes = list(self.memberTypes) + i = 0 + while i < len(self.flatMemberTypes): diff --git a/components/script/dom/bindings/codegen/parser/update.sh b/components/script/dom/bindings/codegen/parser/update.sh index ef1da728b13..6bf56cead30 100755 --- a/components/script/dom/bindings/codegen/parser/update.sh +++ b/components/script/dom/bindings/codegen/parser/update.sh @@ -3,7 +3,7 @@ patch < abstract.patch patch < debug.patch patch < pref-main-thread.patch patch < callback-location.patch -patch < bytestring.patch +patch < union-typedef.patch wget https://hg.mozilla.org/mozilla-central/archive/tip.tar.gz/dom/bindings/parser/tests/ -O tests.tar.gz rm -r tests diff --git a/components/script/dom/bindings/global.rs b/components/script/dom/bindings/global.rs index 9b4125bdc6a..5d679cce2e9 100644 --- a/components/script/dom/bindings/global.rs +++ b/components/script/dom/bindings/global.rs @@ -10,25 +10,29 @@ use devtools_traits::{ScriptToDevtoolsControlMsg, WorkerId}; use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; use dom::bindings::conversions::root_from_object; -use dom::bindings::error::ErrorInfo; +use dom::bindings::error::{ErrorInfo, report_pending_exception}; use dom::bindings::js::Root; use dom::bindings::reflector::{Reflectable, Reflector}; use dom::console::TimerSet; -use dom::window::{self, ScriptHelpers}; +use dom::window; use dom::workerglobalscope::WorkerGlobalScope; use ipc_channel::ipc::IpcSender; use js::{JSCLASS_IS_DOMJSCLASS, JSCLASS_IS_GLOBAL}; use js::glue::{IsWrapper, UnwrapObject}; -use js::jsapi::{CurrentGlobalOrNull, GetGlobalForObjectCrossCompartment}; -use js::jsapi::{JSContext, JSObject, JS_GetClass, MutableHandleValue}; -use js::jsapi::HandleValue; +use js::jsapi::{CurrentGlobalOrNull, Evaluate2, GetGlobalForObjectCrossCompartment}; +use js::jsapi::{HandleValue, JS_GetClass, JSAutoCompartment, JSContext}; +use js::jsapi::{JSObject, MutableHandleValue}; +use js::rust::CompileOptionsWrapper; +use libc; use msg::constellation_msg::PipelineId; use net_traits::{CoreResourceThread, IpcSend, ResourceThreads}; use profile_traits::{mem, time}; -use script_runtime::{CommonScriptMsg, ScriptChan, ScriptPort, EnqueuedPromiseCallback}; +use script_runtime::{CommonScriptMsg, EnqueuedPromiseCallback, ScriptChan}; +use script_runtime::{ScriptPort, maybe_take_panic_result}; use script_thread::{MainThreadScriptChan, RunnableWrapper, ScriptThread}; use script_traits::{MsDuration, ScriptMsg as ConstellationMsg, TimerEventRequest}; -use task_source::dom_manipulation::DOMManipulationTaskSource; +use std::ffi::CString; +use std::panic; use task_source::file_reading::FileReadingTaskSource; use timers::{OneshotTimerCallback, OneshotTimerHandle}; use url::Url; @@ -181,15 +185,6 @@ impl<'a> GlobalRef<'a> { } } - /// `TaskSource` used to queue DOM manipulation messages to the event loop of this global's - /// thread. - pub fn dom_manipulation_task_source(&self) -> DOMManipulationTaskSource { - match *self { - GlobalRef::Window(ref window) => window.dom_manipulation_task_source(), - GlobalRef::Worker(_) => unimplemented!(), - } - } - /// `ScriptChan` used to send messages to the event loop of this global's /// thread. pub fn networking_task_source(&self) -> Box<ScriptChan + Send> { @@ -201,15 +196,6 @@ impl<'a> GlobalRef<'a> { /// `ScriptChan` used to send messages to the event loop of this global's /// thread. - pub fn history_traversal_task_source(&self) -> Box<ScriptChan + Send> { - match *self { - GlobalRef::Window(ref window) => window.history_traversal_task_source(), - GlobalRef::Worker(ref worker) => worker.script_chan(), - } - } - - /// `ScriptChan` used to send messages to the event loop of this global's - /// thread. pub fn file_reading_task_source(&self) -> FileReadingTaskSource { match *self { GlobalRef::Window(ref window) => window.file_reading_task_source(), @@ -236,12 +222,51 @@ impl<'a> GlobalRef<'a> { } } - /// Evaluate the JS messages on the `RootedValue` of this global - pub fn evaluate_js_on_global_with_result(&self, code: &str, rval: MutableHandleValue) { - match *self { - GlobalRef::Window(window) => window.evaluate_js_on_global_with_result(code, rval), - GlobalRef::Worker(worker) => worker.evaluate_js_on_global_with_result(code, rval), - } + /// Evaluate JS code on this global. + pub fn evaluate_js_on_global_with_result( + &self, code: &str, rval: MutableHandleValue) { + self.evaluate_script_on_global_with_result(code, "", rval) + } + + /// Evaluate a JS script on this global. + #[allow(unsafe_code)] + pub fn evaluate_script_on_global_with_result( + &self, code: &str, filename: &str, rval: MutableHandleValue) { + let metadata = time::TimerMetadata { + url: if filename.is_empty() { + self.get_url().as_str().into() + } else { + filename.into() + }, + iframe: time::TimerMetadataFrameType::RootWindow, + incremental: time::TimerMetadataReflowType::FirstReflow, + }; + time::profile( + time::ProfilerCategory::ScriptEvaluate, + Some(metadata), + self.time_profiler_chan().clone(), + || { + let cx = self.get_cx(); + let globalhandle = self.reflector().get_jsobject(); + let code: Vec<u16> = code.encode_utf16().collect(); + let filename = CString::new(filename).unwrap(); + + let _ac = JSAutoCompartment::new(cx, globalhandle.get()); + let options = CompileOptionsWrapper::new(cx, filename.as_ptr(), 1); + unsafe { + if !Evaluate2(cx, options.ptr, code.as_ptr(), + code.len() as libc::size_t, + rval) { + debug!("error evaluating JS string"); + report_pending_exception(cx, true); + } + } + + if let Some(error) = maybe_take_panic_result() { + panic::resume_unwind(error); + } + } + ) } /// Set the `bool` value to indicate whether developer tools has requested diff --git a/components/script/dom/bindings/proxyhandler.rs b/components/script/dom/bindings/proxyhandler.rs index cacac064376..b5230b1b81a 100644 --- a/components/script/dom/bindings/proxyhandler.rs +++ b/components/script/dom/bindings/proxyhandler.rs @@ -186,7 +186,7 @@ pub fn ensure_expando_object(cx: *mut JSContext, obj: HandleObject) -> *mut JSOb /// Set the property descriptor's object to `obj` and set it to enumerable, /// and writable if `readonly` is true. -pub fn fill_property_descriptor(desc: &mut PropertyDescriptor, +pub fn fill_property_descriptor(mut desc: MutableHandle<PropertyDescriptor>, obj: *mut JSObject, attrs: u32) { desc.obj = obj; diff --git a/components/script/dom/bluetooth.rs b/components/script/dom/bluetooth.rs index 2940a211bf3..42ad4c2730a 100644 --- a/components/script/dom/bluetooth.rs +++ b/components/script/dom/bluetooth.rs @@ -15,10 +15,13 @@ use dom::bindings::str::DOMString; use dom::bluetoothadvertisingdata::BluetoothAdvertisingData; use dom::bluetoothdevice::BluetoothDevice; use dom::bluetoothuuid::{BluetoothServiceUUID, BluetoothUUID}; +use dom::promise::Promise; use ipc_channel::ipc::{self, IpcSender}; +use js::conversions::ToJSValConvertible; use net_traits::bluetooth_scanfilter::{BluetoothScanfilter, BluetoothScanfilterSequence}; use net_traits::bluetooth_scanfilter::{RequestDeviceoptions, ServiceUUIDSequence}; use net_traits::bluetooth_thread::{BluetoothError, BluetoothMethodMsg}; +use std::rc::Rc; const FILTER_EMPTY_ERROR: &'static str = "'filters' member, if present, must be nonempty to find any devices."; const FILTER_ERROR: &'static str = "A filter must restrict the devices in some way."; @@ -61,6 +64,22 @@ impl Bluetooth { global_ref.as_window().bluetooth_thread() } + fn request_device(&self, option: &RequestDeviceOptions) -> Fallible<Root<BluetoothDevice>> { + // Step 1. + // TODO(#4282): Reject promise. + if (option.filters.is_some() && option.acceptAllDevices) || + (option.filters.is_none() && !option.acceptAllDevices) { + return Err(Type(OPTIONS_ERROR.to_owned())); + } + // Step 2. + if !option.acceptAllDevices { + return self.request_bluetooth_devices(&option.filters, &option.optionalServices); + } + + self.request_bluetooth_devices(&None, &option.optionalServices) + // TODO(#4282): Step 3-5: Reject and resolve promise. + } + // https://webbluetoothcg.github.io/web-bluetooth/#request-bluetooth-devices fn request_bluetooth_devices(&self, filters: &Option<Vec<BluetoothRequestDeviceFilter>>, @@ -69,7 +88,7 @@ impl Bluetooth { // TODO: Step 1: Triggered by user activation. // Step 2. - let option = try!(convert_request_device_options(self.global().r(), filters, optional_services)); + let option = try!(convert_request_device_options(filters, optional_services)); // TODO: Step 3-5: Implement the permission API. @@ -104,8 +123,7 @@ impl Bluetooth { } // https://webbluetoothcg.github.io/web-bluetooth/#request-bluetooth-devices -fn convert_request_device_options(global: GlobalRef, - filters: &Option<Vec<BluetoothRequestDeviceFilter>>, +fn convert_request_device_options(filters: &Option<Vec<BluetoothRequestDeviceFilter>>, optional_services: &Option<Vec<BluetoothServiceUUID>>) -> Fallible<RequestDeviceoptions> { // Step 2.2: There is no requiredServiceUUIDS, we scan for all devices. @@ -122,7 +140,7 @@ fn convert_request_device_options(global: GlobalRef, // Step 2.4. for filter in filters { // Step 2.4.8. - uuid_filters.push(try!(canonicalize_filter(&filter, global))); + uuid_filters.push(try!(canonicalize_filter(&filter))); } } @@ -130,7 +148,7 @@ fn convert_request_device_options(global: GlobalRef, if let &Some(ref opt_services) = optional_services { for opt_service in opt_services { // Step 2.5 - 2.6. - let uuid = try!(BluetoothUUID::GetService(global, opt_service.clone())).to_string(); + let uuid = try!(BluetoothUUID::service(opt_service.clone())).to_string(); // Step 2.7. // Note: What we are doing here is adding the not blacklisted UUIDs to the result vector, @@ -146,7 +164,7 @@ fn convert_request_device_options(global: GlobalRef, } // https://webbluetoothcg.github.io/web-bluetooth/#request-bluetooth-devices -fn canonicalize_filter(filter: &BluetoothRequestDeviceFilter, global: GlobalRef) -> Fallible<BluetoothScanfilter> { +fn canonicalize_filter(filter: &BluetoothRequestDeviceFilter) -> Fallible<BluetoothScanfilter> { // Step 2.4.1. if filter.services.is_none() && filter.name.is_none() && @@ -171,7 +189,7 @@ fn canonicalize_filter(filter: &BluetoothRequestDeviceFilter, global: GlobalRef) for service in services { // Step 2.4.3.2 - 2.4.3.3. - let uuid = try!(BluetoothUUID::GetService(global, service.clone())).to_string(); + let uuid = try!(BluetoothUUID::service(service.clone())).to_string(); // Step 2.4.3.4. if uuid_is_blacklisted(uuid.as_ref(), Blacklist::All) { @@ -232,7 +250,7 @@ fn canonicalize_filter(filter: &BluetoothRequestDeviceFilter, global: GlobalRef) let service_data_uuid = match filter.serviceDataUUID { Some(ref service_data_uuid) => { // Step 2.4.7.1 - 2.4.7.2. - let uuid = try!(BluetoothUUID::GetService(global, service_data_uuid.clone())).to_string(); + let uuid = try!(BluetoothUUID::service(service_data_uuid.clone())).to_string(); // Step 2.4.7.3. if uuid_is_blacklisted(uuid.as_ref(), Blacklist::All) { @@ -252,6 +270,18 @@ fn canonicalize_filter(filter: &BluetoothRequestDeviceFilter, global: GlobalRef) service_data_uuid)) } +#[allow(unrooted_must_root)] +pub fn result_to_promise<T: ToJSValConvertible>(global_ref: GlobalRef, + bluetooth_result: Fallible<T>) + -> Rc<Promise> { + let p = Promise::new(global_ref); + match bluetooth_result { + Ok(v) => p.resolve_native(p.global().r().get_cx(), &v), + Err(e) => p.reject_error(p.global().r().get_cx(), e), + } + p +} + impl From<BluetoothError> for Error { fn from(error: BluetoothError) -> Self { match error { @@ -265,20 +295,9 @@ impl From<BluetoothError> for Error { } impl BluetoothMethods for Bluetooth { + #[allow(unrooted_must_root)] // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetooth-requestdevice - fn RequestDevice(&self, option: &RequestDeviceOptions) -> Fallible<Root<BluetoothDevice>> { - // Step 1. - // TODO(#4282): Reject promise. - if (option.filters.is_some() && option.acceptAllDevices) || - (option.filters.is_none() && !option.acceptAllDevices) { - return Err(Type(OPTIONS_ERROR.to_owned())); - } - // Step 2. - if !option.acceptAllDevices { - return self.request_bluetooth_devices(&option.filters, &option.optionalServices); - } - - self.request_bluetooth_devices(&None, &option.optionalServices) - // TODO(#4282): Step 3-5: Reject and resolve promise. + fn RequestDevice(&self, option: &RequestDeviceOptions) -> Rc<Promise> { + result_to_promise(self.global().r(), self.request_device(option)) } } diff --git a/components/script/dom/bluetoothremotegattcharacteristic.rs b/components/script/dom/bluetoothremotegattcharacteristic.rs index 15ca7af2235..6b7ba1dcfad 100644 --- a/components/script/dom/bluetoothremotegattcharacteristic.rs +++ b/components/script/dom/bluetoothremotegattcharacteristic.rs @@ -18,12 +18,15 @@ use dom::bindings::global::GlobalRef; use dom::bindings::js::{JS, MutHeap, Root}; use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object}; use dom::bindings::str::{ByteString, DOMString}; +use dom::bluetooth::result_to_promise; use dom::bluetoothcharacteristicproperties::BluetoothCharacteristicProperties; use dom::bluetoothremotegattdescriptor::BluetoothRemoteGATTDescriptor; use dom::bluetoothremotegattservice::BluetoothRemoteGATTService; use dom::bluetoothuuid::{BluetoothDescriptorUUID, BluetoothUUID}; +use dom::promise::Promise; use ipc_channel::ipc::{self, IpcSender}; use net_traits::bluetooth_thread::BluetoothMethodMsg; +use std::rc::Rc; // Maximum length of an attribute value. // https://www.bluetooth.org/DocMan/handlers/DownloadDoc.ashx?doc_id=286439 (Vol. 3, page 2169) @@ -79,27 +82,10 @@ impl BluetoothRemoteGATTCharacteristic { fn get_instance_id(&self) -> String { self.instance_id.clone() } -} - -impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteristic { - // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-properties - fn Properties(&self) -> Root<BluetoothCharacteristicProperties> { - self.properties.get() - } - - // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-service - fn Service(&self) -> Root<BluetoothRemoteGATTService> { - self.service.get() - } - - // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-uuid - fn Uuid(&self) -> DOMString { - self.uuid.clone() - } // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-getdescriptor - fn GetDescriptor(&self, descriptor: BluetoothDescriptorUUID) -> Fallible<Root<BluetoothRemoteGATTDescriptor>> { - let uuid = try!(BluetoothUUID::GetDescriptor(self.global().r(), descriptor)).to_string(); + fn get_descriptor(&self, descriptor: BluetoothDescriptorUUID) -> Fallible<Root<BluetoothRemoteGATTDescriptor>> { + let uuid = try!(BluetoothUUID::descriptor(descriptor)).to_string(); if uuid_is_blacklisted(uuid.as_ref(), Blacklist::All) { return Err(Security) } @@ -121,12 +107,12 @@ impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteris } // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-getdescriptors - fn GetDescriptors(&self, - descriptor: Option<BluetoothDescriptorUUID>) - -> Fallible<Vec<Root<BluetoothRemoteGATTDescriptor>>> { + fn get_descriptors(&self, + descriptor: Option<BluetoothDescriptorUUID>) + -> Fallible<Vec<Root<BluetoothRemoteGATTDescriptor>>> { let mut uuid: Option<String> = None; if let Some(d) = descriptor { - uuid = Some(try!(BluetoothUUID::GetDescriptor(self.global().r(), d)).to_string()); + uuid = Some(try!(BluetoothUUID::descriptor(d)).to_string()); if let Some(ref uuid) = uuid { if uuid_is_blacklisted(uuid.as_ref(), Blacklist::All) { return Err(Security) @@ -152,13 +138,8 @@ impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteris } } - // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-value - fn GetValue(&self) -> Option<ByteString> { - self.value.borrow().clone() - } - // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-readvalue - fn ReadValue(&self) -> Fallible<ByteString> { + fn read_value(&self) -> Fallible<ByteString> { if uuid_is_blacklisted(self.uuid.as_ref(), Blacklist::Reads) { return Err(Security) } @@ -185,7 +166,7 @@ impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteris } // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-writevalue - fn WriteValue(&self, value: Vec<u8>) -> ErrorResult { + fn write_value(&self, value: Vec<u8>) -> ErrorResult { if uuid_is_blacklisted(self.uuid.as_ref(), Blacklist::Writes) { return Err(Security) } @@ -213,3 +194,51 @@ impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteris } } } + +impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteristic { + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-properties + fn Properties(&self) -> Root<BluetoothCharacteristicProperties> { + self.properties.get() + } + + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-service + fn Service(&self) -> Root<BluetoothRemoteGATTService> { + self.service.get() + } + + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-uuid + fn Uuid(&self) -> DOMString { + self.uuid.clone() + } + + #[allow(unrooted_must_root)] + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-getdescriptor + fn GetDescriptor(&self, descriptor: BluetoothDescriptorUUID) -> Rc<Promise> { + result_to_promise(self.global().r(), self.get_descriptor(descriptor)) + } + + #[allow(unrooted_must_root)] + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-getdescriptors + fn GetDescriptors(&self, + descriptor: Option<BluetoothDescriptorUUID>) + -> Rc<Promise> { + result_to_promise(self.global().r(), self.get_descriptors(descriptor)) + } + + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-value + fn GetValue(&self) -> Option<ByteString> { + self.value.borrow().clone() + } + + #[allow(unrooted_must_root)] + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-readvalue + fn ReadValue(&self) -> Rc<Promise> { + result_to_promise(self.global().r(), self.read_value()) + } + + #[allow(unrooted_must_root)] + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-writevalue + fn WriteValue(&self, value: Vec<u8>) -> Rc<Promise> { + result_to_promise(self.global().r(), self.write_value(value)) + } +} diff --git a/components/script/dom/bluetoothremotegattdescriptor.rs b/components/script/dom/bluetoothremotegattdescriptor.rs index 99065a9aec0..d036f8bd9ea 100644 --- a/components/script/dom/bluetoothremotegattdescriptor.rs +++ b/components/script/dom/bluetoothremotegattdescriptor.rs @@ -17,9 +17,12 @@ use dom::bindings::global::GlobalRef; use dom::bindings::js::{JS, MutHeap, Root}; use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object}; use dom::bindings::str::{ByteString, DOMString}; +use dom::bluetooth::result_to_promise; use dom::bluetoothremotegattcharacteristic::{BluetoothRemoteGATTCharacteristic, MAXIMUM_ATTRIBUTE_LENGTH}; +use dom::promise::Promise; use ipc_channel::ipc::{self, IpcSender}; use net_traits::bluetooth_thread::BluetoothMethodMsg; +use std::rc::Rc; // http://webbluetoothcg.github.io/web-bluetooth/#bluetoothremotegattdescriptor #[dom_struct] @@ -66,26 +69,9 @@ impl BluetoothRemoteGATTDescriptor { fn get_instance_id(&self) -> String { self.instance_id.clone() } -} - -impl BluetoothRemoteGATTDescriptorMethods for BluetoothRemoteGATTDescriptor { - // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-characteristic - fn Characteristic(&self) -> Root<BluetoothRemoteGATTCharacteristic> { - self.characteristic.get() - } - - // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-uuid - fn Uuid(&self) -> DOMString { - self.uuid.clone() - } - - // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-value - fn GetValue(&self) -> Option<ByteString> { - self.value.borrow().clone() - } // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-readvalue - fn ReadValue(&self) -> Fallible<ByteString> { + fn read_value(&self) -> Fallible<ByteString> { if uuid_is_blacklisted(self.uuid.as_ref(), Blacklist::Reads) { return Err(Security) } @@ -109,7 +95,7 @@ impl BluetoothRemoteGATTDescriptorMethods for BluetoothRemoteGATTDescriptor { } // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-writevalue - fn WriteValue(&self, value: Vec<u8>) -> ErrorResult { + fn write_value(&self, value: Vec<u8>) -> ErrorResult { if uuid_is_blacklisted(self.uuid.as_ref(), Blacklist::Writes) { return Err(Security) } @@ -131,3 +117,32 @@ impl BluetoothRemoteGATTDescriptorMethods for BluetoothRemoteGATTDescriptor { } } } + +impl BluetoothRemoteGATTDescriptorMethods for BluetoothRemoteGATTDescriptor { + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-characteristic + fn Characteristic(&self) -> Root<BluetoothRemoteGATTCharacteristic> { + self.characteristic.get() + } + + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-uuid + fn Uuid(&self) -> DOMString { + self.uuid.clone() + } + + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-value + fn GetValue(&self) -> Option<ByteString> { + self.value.borrow().clone() + } + + #[allow(unrooted_must_root)] + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-readvalue + fn ReadValue(&self) -> Rc<Promise> { + result_to_promise(self.global().r(), self.read_value()) + } + + #[allow(unrooted_must_root)] + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-writevalue + fn WriteValue(&self, value: Vec<u8>) -> Rc<Promise> { + result_to_promise(self.global().r(), self.write_value(value)) + } +} diff --git a/components/script/dom/bluetoothremotegattserver.rs b/components/script/dom/bluetoothremotegattserver.rs index 615094623e9..3439ba53350 100644 --- a/components/script/dom/bluetoothremotegattserver.rs +++ b/components/script/dom/bluetoothremotegattserver.rs @@ -12,12 +12,15 @@ use dom::bindings::global::GlobalRef; use dom::bindings::js::{JS, MutHeap, Root}; use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object}; use dom::bindings::str::DOMString; +use dom::bluetooth::result_to_promise; use dom::bluetoothdevice::BluetoothDevice; use dom::bluetoothremotegattservice::BluetoothRemoteGATTService; use dom::bluetoothuuid::{BluetoothServiceUUID, BluetoothUUID}; +use dom::promise::Promise; use ipc_channel::ipc::{self, IpcSender}; use net_traits::bluetooth_thread::BluetoothMethodMsg; use std::cell::Cell; +use std::rc::Rc; // https://webbluetoothcg.github.io/web-bluetooth/#bluetoothremotegattserver #[dom_struct] @@ -47,21 +50,9 @@ impl BluetoothRemoteGATTServer { let global_ref = global_root.r(); global_ref.as_window().bluetooth_thread() } -} - -impl BluetoothRemoteGATTServerMethods for BluetoothRemoteGATTServer { - // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-device - fn Device(&self) -> Root<BluetoothDevice> { - self.device.get() - } - - // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-connected - fn Connected(&self) -> bool { - self.connected.get() - } // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-connect - fn Connect(&self) -> Fallible<Root<BluetoothRemoteGATTServer>> { + fn connect(&self) -> Fallible<Root<BluetoothRemoteGATTServer>> { let (sender, receiver) = ipc::channel().unwrap(); self.get_bluetooth_thread().send( BluetoothMethodMsg::GATTServerConnect(String::from(self.Device().Id()), sender)).unwrap(); @@ -77,26 +68,9 @@ impl BluetoothRemoteGATTServerMethods for BluetoothRemoteGATTServer { } } - // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-disconnect - fn Disconnect(&self) -> ErrorResult { - let (sender, receiver) = ipc::channel().unwrap(); - self.get_bluetooth_thread().send( - BluetoothMethodMsg::GATTServerDisconnect(String::from(self.Device().Id()), sender)).unwrap(); - let server = receiver.recv().unwrap(); - match server { - Ok(connected) => { - self.connected.set(connected); - Ok(()) - }, - Err(error) => { - Err(Error::from(error)) - }, - } - } - // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-getprimaryservice - fn GetPrimaryService(&self, service: BluetoothServiceUUID) -> Fallible<Root<BluetoothRemoteGATTService>> { - let uuid = try!(BluetoothUUID::GetService(self.global().r(), service)).to_string(); + fn get_primary_service(&self, service: BluetoothServiceUUID) -> Fallible<Root<BluetoothRemoteGATTService>> { + let uuid = try!(BluetoothUUID::service(service)).to_string(); if uuid_is_blacklisted(uuid.as_ref(), Blacklist::All) { return Err(Security) } @@ -119,12 +93,12 @@ impl BluetoothRemoteGATTServerMethods for BluetoothRemoteGATTServer { } // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-getprimaryservices - fn GetPrimaryServices(&self, - service: Option<BluetoothServiceUUID>) - -> Fallible<Vec<Root<BluetoothRemoteGATTService>>> { + fn get_primary_services(&self, + service: Option<BluetoothServiceUUID>) + -> Fallible<Vec<Root<BluetoothRemoteGATTService>>> { let mut uuid: Option<String> = None; if let Some(s) = service { - uuid = Some(try!(BluetoothUUID::GetService(self.global().r(), s)).to_string()); + uuid = Some(try!(BluetoothUUID::service(s)).to_string()); if let Some(ref uuid) = uuid { if uuid_is_blacklisted(uuid.as_ref(), Blacklist::All) { return Err(Security) @@ -151,3 +125,52 @@ impl BluetoothRemoteGATTServerMethods for BluetoothRemoteGATTServer { } } } + +impl BluetoothRemoteGATTServerMethods for BluetoothRemoteGATTServer { + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-device + fn Device(&self) -> Root<BluetoothDevice> { + self.device.get() + } + + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-connected + fn Connected(&self) -> bool { + self.connected.get() + } + + #[allow(unrooted_must_root)] + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-connect + fn Connect(&self) -> Rc<Promise> { + result_to_promise(self.global().r(), self.connect()) + } + + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-disconnect + fn Disconnect(&self) -> ErrorResult { + let (sender, receiver) = ipc::channel().unwrap(); + self.get_bluetooth_thread().send( + BluetoothMethodMsg::GATTServerDisconnect(String::from(self.Device().Id()), sender)).unwrap(); + let server = receiver.recv().unwrap(); + match server { + Ok(connected) => { + self.connected.set(connected); + Ok(()) + }, + Err(error) => { + Err(Error::from(error)) + }, + } + } + + #[allow(unrooted_must_root)] + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-getprimaryservice + fn GetPrimaryService(&self, service: BluetoothServiceUUID) -> Rc<Promise> { + result_to_promise(self.global().r(), self.get_primary_service(service)) + } + + #[allow(unrooted_must_root)] + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-getprimaryservices + fn GetPrimaryServices(&self, + service: Option<BluetoothServiceUUID>) + -> Rc<Promise> { + result_to_promise(self.global().r(), self.get_primary_services(service)) + } +} diff --git a/components/script/dom/bluetoothremotegattservice.rs b/components/script/dom/bluetoothremotegattservice.rs index a39bb4fdfd5..3ece2507cd3 100644 --- a/components/script/dom/bluetoothremotegattservice.rs +++ b/components/script/dom/bluetoothremotegattservice.rs @@ -11,12 +11,15 @@ use dom::bindings::global::GlobalRef; use dom::bindings::js::{JS, MutHeap, Root}; use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object}; use dom::bindings::str::DOMString; +use dom::bluetooth::result_to_promise; use dom::bluetoothcharacteristicproperties::BluetoothCharacteristicProperties; use dom::bluetoothdevice::BluetoothDevice; use dom::bluetoothremotegattcharacteristic::BluetoothRemoteGATTCharacteristic; use dom::bluetoothuuid::{BluetoothCharacteristicUUID, BluetoothServiceUUID, BluetoothUUID}; +use dom::promise::Promise; use ipc_channel::ipc::{self, IpcSender}; use net_traits::bluetooth_thread::BluetoothMethodMsg; +use std::rc::Rc; // https://webbluetoothcg.github.io/web-bluetooth/#bluetoothremotegattservice #[dom_struct] @@ -66,29 +69,12 @@ impl BluetoothRemoteGATTService { fn get_instance_id(&self) -> String { self.instance_id.clone() } -} - -impl BluetoothRemoteGATTServiceMethods for BluetoothRemoteGATTService { - // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-device - fn Device(&self) -> Root<BluetoothDevice> { - self.device.get() - } - - // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-isprimary - fn IsPrimary(&self) -> bool { - self.is_primary - } - - // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-uuid - fn Uuid(&self) -> DOMString { - self.uuid.clone() - } // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getcharacteristic - fn GetCharacteristic(&self, - characteristic: BluetoothCharacteristicUUID) - -> Fallible<Root<BluetoothRemoteGATTCharacteristic>> { - let uuid = try!(BluetoothUUID::GetCharacteristic(self.global().r(), characteristic)).to_string(); + fn get_characteristic(&self, + characteristic: BluetoothCharacteristicUUID) + -> Fallible<Root<BluetoothRemoteGATTCharacteristic>> { + let uuid = try!(BluetoothUUID::characteristic(characteristic)).to_string(); if uuid_is_blacklisted(uuid.as_ref(), Blacklist::All) { return Err(Security) } @@ -121,12 +107,12 @@ impl BluetoothRemoteGATTServiceMethods for BluetoothRemoteGATTService { } // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getcharacteristics - fn GetCharacteristics(&self, - characteristic: Option<BluetoothCharacteristicUUID>) - -> Fallible<Vec<Root<BluetoothRemoteGATTCharacteristic>>> { + fn get_characteristics(&self, + characteristic: Option<BluetoothCharacteristicUUID>) + -> Fallible<Vec<Root<BluetoothRemoteGATTCharacteristic>>> { let mut uuid: Option<String> = None; if let Some(c) = characteristic { - uuid = Some(try!(BluetoothUUID::GetCharacteristic(self.global().r(), c)).to_string()); + uuid = Some(try!(BluetoothUUID::characteristic(c)).to_string()); if let Some(ref uuid) = uuid { if uuid_is_blacklisted(uuid.as_ref(), Blacklist::All) { return Err(Security) @@ -166,10 +152,10 @@ impl BluetoothRemoteGATTServiceMethods for BluetoothRemoteGATTService { } // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getincludedservice - fn GetIncludedService(&self, - service: BluetoothServiceUUID) - -> Fallible<Root<BluetoothRemoteGATTService>> { - let uuid = try!(BluetoothUUID::GetService(self.global().r(), service)).to_string(); + fn get_included_service(&self, + service: BluetoothServiceUUID) + -> Fallible<Root<BluetoothRemoteGATTService>> { + let uuid = try!(BluetoothUUID::service(service)).to_string(); if uuid_is_blacklisted(uuid.as_ref(), Blacklist::All) { return Err(Security) } @@ -194,12 +180,12 @@ impl BluetoothRemoteGATTServiceMethods for BluetoothRemoteGATTService { } // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getincludedservices - fn GetIncludedServices(&self, - service: Option<BluetoothServiceUUID>) - -> Fallible<Vec<Root<BluetoothRemoteGATTService>>> { + fn get_included_services(&self, + service: Option<BluetoothServiceUUID>) + -> Fallible<Vec<Root<BluetoothRemoteGATTService>>> { let mut uuid: Option<String> = None; if let Some(s) = service { - uuid = Some(try!(BluetoothUUID::GetService(self.global().r(), s)).to_string()); + uuid = Some(try!(BluetoothUUID::service(s)).to_string()); if let Some(ref uuid) = uuid { if uuid_is_blacklisted(uuid.as_ref(), Blacklist::All) { return Err(Security) @@ -228,3 +214,52 @@ impl BluetoothRemoteGATTServiceMethods for BluetoothRemoteGATTService { } } } + +impl BluetoothRemoteGATTServiceMethods for BluetoothRemoteGATTService { + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-device + fn Device(&self) -> Root<BluetoothDevice> { + self.device.get() + } + + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-isprimary + fn IsPrimary(&self) -> bool { + self.is_primary + } + + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-uuid + fn Uuid(&self) -> DOMString { + self.uuid.clone() + } + + #[allow(unrooted_must_root)] + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getcharacteristic + fn GetCharacteristic(&self, + characteristic: BluetoothCharacteristicUUID) + -> Rc<Promise> { + result_to_promise(self.global().r(), self.get_characteristic(characteristic)) + } + + #[allow(unrooted_must_root)] + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getcharacteristics + fn GetCharacteristics(&self, + characteristic: Option<BluetoothCharacteristicUUID>) + -> Rc<Promise> { + result_to_promise(self.global().r(), self.get_characteristics(characteristic)) + } + + #[allow(unrooted_must_root)] + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getincludedservice + fn GetIncludedService(&self, + service: BluetoothServiceUUID) + -> Rc<Promise> { + result_to_promise(self.global().r(), self.get_included_service(service)) + } + + #[allow(unrooted_must_root)] + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getincludedservices + fn GetIncludedServices(&self, + service: Option<BluetoothServiceUUID>) + -> Rc<Promise> { + result_to_promise(self.global().r(), self.get_included_services(service)) + } +} diff --git a/components/script/dom/bluetoothuuid.rs b/components/script/dom/bluetoothuuid.rs index dafda71a12b..e9669cc8acb 100644 --- a/components/script/dom/bluetoothuuid.rs +++ b/components/script/dom/bluetoothuuid.rs @@ -272,60 +272,36 @@ const VALID_UUID_REGEX: &'static str = "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0- impl BluetoothUUID { // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothuuid-canonicaluuid pub fn CanonicalUUID(_: GlobalRef, alias: u32) -> UUID { - DOMString::from(format!("{:08x}", &alias) + BASE_UUID) + canonical_uuid(alias) } // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothuuid-getservice - pub fn GetService(globalref: GlobalRef, name: BluetoothServiceUUID) -> Fallible<UUID> { - BluetoothUUID::resolve_uuid_name(globalref, - name, - BLUETOOTH_ASSIGNED_SERVICES, - DOMString::from(SERVICE_PREFIX)) + pub fn GetService(_: GlobalRef, name: BluetoothServiceUUID) -> Fallible<UUID> { + Self::service(name) } // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothuuid-getcharacteristic - pub fn GetCharacteristic(globalref: GlobalRef, name: BluetoothCharacteristicUUID) -> Fallible<UUID> { - BluetoothUUID::resolve_uuid_name(globalref, - name, - BLUETOOTH_ASSIGNED_CHARCTERISTICS, - DOMString::from(CHARACTERISTIC_PREFIX)) + pub fn GetCharacteristic(_: GlobalRef, name: BluetoothCharacteristicUUID) -> Fallible<UUID> { + Self::characteristic(name) } // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothuuid-getdescriptor - pub fn GetDescriptor(globalref: GlobalRef, name: BluetoothDescriptorUUID) -> Fallible<UUID> { - BluetoothUUID::resolve_uuid_name(globalref, - name, - BLUETOOTH_ASSIGNED_DESCRIPTORS, - DOMString::from(DESCRIPTOR_PREFIX)) + pub fn GetDescriptor(_: GlobalRef, name: BluetoothDescriptorUUID) -> Fallible<UUID> { + Self::descriptor(name) } +} - // https://webbluetoothcg.github.io/web-bluetooth/#resolveuuidname - pub fn resolve_uuid_name(globalref: GlobalRef, - name: StringOrUnsignedLong, - assigned_numbers_table: &'static [(&'static str, u32)], - prefix: DOMString) - -> Fallible<DOMString> { - match name { - // Step 1 - StringOrUnsignedLong::UnsignedLong(unsigned32) => { - Ok(BluetoothUUID::CanonicalUUID(globalref, unsigned32)) - }, - StringOrUnsignedLong::String(dstring) => { - // Step 2 - let regex = Regex::new(VALID_UUID_REGEX).unwrap(); - if regex.is_match(&*dstring) { - Ok(dstring) - } else { - // Step 3 - let concatenated = format!("{}.{}", prefix, dstring); - let is_in_table = assigned_numbers_table.iter().find(|p| p.0 == concatenated); - match is_in_table { - Some(&(_, alias)) => Ok(BluetoothUUID::CanonicalUUID(globalref, alias)), - None => Err(Syntax), - } - } - }, - } +impl BluetoothUUID { + pub fn service(name: BluetoothServiceUUID) -> Fallible<UUID> { + resolve_uuid_name(name, BLUETOOTH_ASSIGNED_SERVICES, SERVICE_PREFIX) + } + + pub fn characteristic(name: BluetoothServiceUUID) -> Fallible<UUID> { + resolve_uuid_name(name, BLUETOOTH_ASSIGNED_CHARCTERISTICS, CHARACTERISTIC_PREFIX) + } + + pub fn descriptor(name: BluetoothDescriptorUUID) -> Fallible<UUID> { + resolve_uuid_name(name, BLUETOOTH_ASSIGNED_DESCRIPTORS, DESCRIPTOR_PREFIX) } } @@ -337,3 +313,36 @@ impl Clone for StringOrUnsignedLong { } } } + +fn canonical_uuid(alias: u32) -> UUID { + UUID::from(format!("{:08x}", &alias) + BASE_UUID) +} + +// https://webbluetoothcg.github.io/web-bluetooth/#resolveuuidname +fn resolve_uuid_name( + name: StringOrUnsignedLong, + assigned_numbers_table: &'static [(&'static str, u32)], + prefix: &str) + -> Fallible<DOMString> { + match name { + // Step 1 + StringOrUnsignedLong::UnsignedLong(unsigned32) => { + Ok(canonical_uuid(unsigned32)) + }, + StringOrUnsignedLong::String(dstring) => { + // Step 2 + let regex = Regex::new(VALID_UUID_REGEX).unwrap(); + if regex.is_match(&*dstring) { + Ok(dstring) + } else { + // Step 3 + let concatenated = format!("{}.{}", prefix, dstring); + let is_in_table = assigned_numbers_table.iter().find(|p| p.0 == concatenated); + match is_in_table { + Some(&(_, alias)) => Ok(canonical_uuid(alias)), + None => Err(Syntax), + } + } + }, + } +} diff --git a/components/script/dom/browsingcontext.rs b/components/script/dom/browsingcontext.rs index 02d153296ae..36179279967 100644 --- a/components/script/dom/browsingcontext.rs +++ b/components/script/dom/browsingcontext.rs @@ -256,7 +256,7 @@ unsafe extern "C" fn getOwnPropertyDescriptor(cx: *mut JSContext, rooted!(in(cx) let mut val = UndefinedValue()); window.to_jsval(cx, val.handle_mut()); desc.value = val.get(); - fill_property_descriptor(&mut desc, proxy.get(), JSPROP_READONLY); + fill_property_descriptor(desc, proxy.get(), JSPROP_READONLY); return true; } diff --git a/components/script/dom/dedicatedworkerglobalscope.rs b/components/script/dom/dedicatedworkerglobalscope.rs index c425c38b86b..49a46b88575 100644 --- a/components/script/dom/dedicatedworkerglobalscope.rs +++ b/components/script/dom/dedicatedworkerglobalscope.rs @@ -17,10 +17,6 @@ use dom::bindings::js::{Root, RootCollection}; use dom::bindings::reflector::Reflectable; use dom::bindings::str::DOMString; use dom::bindings::structuredclone::StructuredCloneData; -use dom::errorevent::ErrorEvent; -use dom::event::{Event, EventBubbles, EventCancelable}; -use dom::eventdispatcher::EventStatus; -use dom::eventtarget::EventTarget; use dom::messageevent::MessageEvent; use dom::worker::{TrustedWorkerAddress, WorkerErrorHandler, WorkerMessageHandler}; use dom::workerglobalscope::WorkerGlobalScope; @@ -36,7 +32,6 @@ use rand::random; use script_runtime::{CommonScriptMsg, ScriptChan, ScriptPort, StackRootTLS, get_reports, new_rt_and_cx}; use script_runtime::ScriptThreadEventCategory::WorkerEvent; use script_traits::{TimerEvent, TimerSource, WorkerGlobalScopeInit, WorkerScriptLoadOrigin}; -use std::cell::Cell; use std::mem::replace; use std::sync::{Arc, Mutex}; use std::sync::atomic::AtomicBool; @@ -81,7 +76,6 @@ enum MixedMessage { #[dom_struct] pub struct DedicatedWorkerGlobalScope { workerglobalscope: WorkerGlobalScope, - id: PipelineId, #[ignore_heap_size_of = "Defined in std"] receiver: Receiver<(TrustedWorkerAddress, WorkerScriptMsg)>, #[ignore_heap_size_of = "Defined in std"] @@ -93,14 +87,11 @@ pub struct DedicatedWorkerGlobalScope { #[ignore_heap_size_of = "Can't measure trait objects"] /// Sender to the parent thread. parent_sender: Box<ScriptChan + Send>, - /// https://html.spec.whatwg.org/multipage/#in-error-reporting-mode - in_error_reporting_mode: Cell<bool> } impl DedicatedWorkerGlobalScope { fn new_inherited(init: WorkerGlobalScopeInit, worker_url: Url, - id: PipelineId, from_devtools_receiver: Receiver<DevtoolScriptControlMsg>, runtime: Runtime, parent_sender: Box<ScriptChan + Send>, @@ -117,19 +108,16 @@ impl DedicatedWorkerGlobalScope { from_devtools_receiver, timer_event_chan, Some(closing)), - id: id, receiver: receiver, own_sender: own_sender, timer_event_port: timer_event_port, parent_sender: parent_sender, worker: DOMRefCell::new(None), - in_error_reporting_mode: Cell::new(false), } } pub fn new(init: WorkerGlobalScopeInit, worker_url: Url, - id: PipelineId, from_devtools_receiver: Receiver<DevtoolScriptControlMsg>, runtime: Runtime, parent_sender: Box<ScriptChan + Send>, @@ -142,7 +130,6 @@ impl DedicatedWorkerGlobalScope { let cx = runtime.cx(); let scope = box DedicatedWorkerGlobalScope::new_inherited(init, worker_url, - id, from_devtools_receiver, runtime, parent_sender, @@ -157,7 +144,6 @@ impl DedicatedWorkerGlobalScope { #[allow(unsafe_code)] pub fn run_worker_scope(init: WorkerGlobalScopeInit, worker_url: Url, - id: PipelineId, from_devtools_receiver: IpcReceiver<DevtoolScriptControlMsg>, worker_rt_for_mainthread: Arc<Mutex<Option<SharedRt>>>, worker: TrustedWorkerAddress, @@ -170,7 +156,7 @@ impl DedicatedWorkerGlobalScope { let name = format!("WebWorker for {}", serialized_worker_url); spawn_named(name, move || { thread_state::initialize(thread_state::SCRIPT | thread_state::IN_WORKER); - PipelineId::install(id); + PipelineId::install(init.pipeline_id); let roots = RootCollection::new(); let _stack_roots_tls = StackRootTLS::new(&roots); @@ -204,7 +190,7 @@ impl DedicatedWorkerGlobalScope { }); let global = DedicatedWorkerGlobalScope::new( - init, url, id, devtools_mpsc_port, runtime, + init, url, devtools_mpsc_port, runtime, parent_sender.clone(), own_sender, receiver, timer_ipc_chan, timer_rx, closing); // FIXME(njn): workers currently don't have a unique ID suitable for using in reporter @@ -244,10 +230,6 @@ impl DedicatedWorkerGlobalScope { } } - pub fn pipeline_id(&self) -> PipelineId { - self.id - } - pub fn new_script_pair(&self) -> (Box<ScriptChan + Send>, Box<ScriptPort + Send>) { let (tx, rx) = channel(); let chan = box SendableWorkerScriptChan { @@ -348,43 +330,13 @@ impl DedicatedWorkerGlobalScope { } } - /// https://html.spec.whatwg.org/multipage/#report-the-error - pub fn report_an_error(&self, error_info: ErrorInfo, value: HandleValue) { - // Step 1. - if self.in_error_reporting_mode.get() { - return; - } - - // Step 2. - self.in_error_reporting_mode.set(true); - - // Steps 3-12. - // FIXME(#13195): muted errors. - let event = ErrorEvent::new(GlobalRef::Worker(self.upcast()), - atom!("error"), - EventBubbles::DoesNotBubble, - EventCancelable::Cancelable, - error_info.message.as_str().into(), - error_info.filename.as_str().into(), - error_info.lineno, - error_info.column, - value); - - // Step 13. - let event_status = event.upcast::<Event>().fire(self.upcast::<EventTarget>()); - - // Step 15 - if event_status == EventStatus::NotCanceled { - let worker = self.worker.borrow().as_ref().unwrap().clone(); - // TODO: Should use the DOM manipulation task source. - self.parent_sender - .send(CommonScriptMsg::RunnableMsg(WorkerEvent, - box WorkerErrorHandler::new(worker, error_info))) - .unwrap(); - } - - // Step 14 - self.in_error_reporting_mode.set(false); + pub fn forward_error_to_worker_object(&self, error_info: ErrorInfo) { + let worker = self.worker.borrow().as_ref().unwrap().clone(); + // TODO: Should use the DOM manipulation task source. + self.parent_sender + .send(CommonScriptMsg::RunnableMsg(WorkerEvent, + box WorkerErrorHandler::new(worker, error_info))) + .unwrap(); } } diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 1b91e743a78..f8238d645e1 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -96,7 +96,7 @@ use js::jsapi::JS_GetRuntime; use msg::constellation_msg::{ALT, CONTROL, SHIFT, SUPER}; use msg::constellation_msg::{Key, KeyModifiers, KeyState}; use msg::constellation_msg::{PipelineId, ReferrerPolicy}; -use net_traits::{AsyncResponseTarget, FetchResponseMsg, IpcSend, PendingAsyncLoad}; +use net_traits::{AsyncResponseTarget, FetchResponseMsg, IpcSend}; use net_traits::CookieSource::NonHTTP; use net_traits::CoreResourceMsg::{GetCookiesForUrl, SetCookiesForUrl}; use net_traits::request::RequestInit; @@ -1423,17 +1423,6 @@ impl Document { ReflowReason::RequestAnimationFrame); } - /// Add a load to the list of loads blocking this document's load. - pub fn add_blocking_load(&self, load: LoadType) { - let mut loader = self.loader.borrow_mut(); - loader.add_blocking_load(load) - } - - pub fn prepare_async_load(&self, load: LoadType, referrer_policy: Option<ReferrerPolicy>) -> PendingAsyncLoad { - let mut loader = self.loader.borrow_mut(); - loader.prepare_async_load(load, self, referrer_policy) - } - pub fn load_async(&self, load: LoadType, listener: AsyncResponseTarget, referrer_policy: Option<ReferrerPolicy>) { let mut loader = self.loader.borrow_mut(); loader.load_async(load, listener, self, referrer_policy); @@ -1441,10 +1430,9 @@ impl Document { pub fn fetch_async(&self, load: LoadType, request: RequestInit, - fetch_target: IpcSender<FetchResponseMsg>, - referrer_policy: Option<ReferrerPolicy>) { + fetch_target: IpcSender<FetchResponseMsg>) { let mut loader = self.loader.borrow_mut(); - loader.fetch_async(load, request, fetch_target, self, referrer_policy); + loader.fetch_async(load, request, fetch_target); } pub fn finish_load(&self, load: LoadType) { diff --git a/components/script/dom/headers.rs b/components/script/dom/headers.rs index 4b832121654..7f43dd6b07a 100644 --- a/components/script/dom/headers.rs +++ b/components/script/dom/headers.rs @@ -229,6 +229,10 @@ impl Headers { *self.header_list.borrow_mut() = HyperHeaders::new(); } + pub fn set_headers(&self, hyper_headers: HyperHeaders) { + *self.header_list.borrow_mut() = hyper_headers; + } + // https://fetch.spec.whatwg.org/#concept-header-extract-mime-type pub fn extract_mime_type(&self) -> Vec<u8> { self.header_list.borrow().get_raw("content-type").map_or(vec![], |v| v[0].clone()) diff --git a/components/script/dom/htmllinkelement.rs b/components/script/dom/htmllinkelement.rs index 1c84fbba784..7c6cabd345e 100644 --- a/components/script/dom/htmllinkelement.rs +++ b/components/script/dom/htmllinkelement.rs @@ -154,7 +154,9 @@ impl VirtualMethods for HTMLLinkElement { }, &atom!("media") => { if string_is_stylesheet(&rel) { - self.handle_stylesheet_url(&attr.value()); + if let Some(href) = self.upcast::<Element>().get_attribute(&ns!(), &atom!("href")) { + self.handle_stylesheet_url(&href.value()); + } } }, _ => {}, @@ -195,62 +197,69 @@ impl VirtualMethods for HTMLLinkElement { impl HTMLLinkElement { + /// https://html.spec.whatwg.org/multipage/#concept-link-obtain fn handle_stylesheet_url(&self, href: &str) { let document = document_from_node(self); if document.browsing_context().is_none() { return; } - match document.base_url().join(href) { - Ok(url) => { - let element = self.upcast::<Element>(); - - let mq_attribute = element.get_attribute(&ns!(), &atom!("media")); - let value = mq_attribute.r().map(|a| a.value()); - let mq_str = match value { - Some(ref value) => &***value, - None => "", - }; - let mut css_parser = CssParser::new(&mq_str); - let media = parse_media_query_list(&mut css_parser); - - // TODO: #8085 - Don't load external stylesheets if the node's mq doesn't match. - let elem = Trusted::new(self); - - let context = Arc::new(Mutex::new(StylesheetContext { - elem: elem, - media: Some(media), - data: vec!(), - metadata: None, - url: url.clone(), - })); - - let (action_sender, action_receiver) = ipc::channel().unwrap(); - let listener = NetworkListener { - context: context, - script_chan: document.window().networking_task_source(), - wrapper: Some(document.window().get_runnable_wrapper()), - }; - let response_target = AsyncResponseTarget { - sender: action_sender, - }; - ROUTER.add_route(action_receiver.to_opaque(), box move |message| { - listener.notify_action(message.to().unwrap()); - }); + // Step 1. + if href.is_empty() { + return; + } - if self.parser_inserted.get() { - document.increment_script_blocking_stylesheet_count(); - } + // Step 2. + let url = match document.base_url().join(href) { + Err(e) => return debug!("Parsing url {} failed: {}", href, e), + Ok(url) => url, + }; + + let element = self.upcast::<Element>(); + + let mq_attribute = element.get_attribute(&ns!(), &atom!("media")); + let value = mq_attribute.r().map(|a| a.value()); + let mq_str = match value { + Some(ref value) => &***value, + None => "", + }; + let mut css_parser = CssParser::new(&mq_str); + let media = parse_media_query_list(&mut css_parser); + + // TODO: #8085 - Don't load external stylesheets if the node's mq doesn't match. + let elem = Trusted::new(self); + + let context = Arc::new(Mutex::new(StylesheetContext { + elem: elem, + media: Some(media), + data: vec!(), + metadata: None, + url: url.clone(), + })); + + let (action_sender, action_receiver) = ipc::channel().unwrap(); + let listener = NetworkListener { + context: context, + script_chan: document.window().networking_task_source(), + wrapper: Some(document.window().get_runnable_wrapper()), + }; + let response_target = AsyncResponseTarget { + sender: action_sender, + }; + ROUTER.add_route(action_receiver.to_opaque(), box move |message| { + listener.notify_action(message.to().unwrap()); + }); + + if self.parser_inserted.get() { + document.increment_script_blocking_stylesheet_count(); + } - let referrer_policy = match self.RelList().Contains("noreferrer".into()) { - true => Some(ReferrerPolicy::NoReferrer), - false => None, - }; + let referrer_policy = match self.RelList().Contains("noreferrer".into()) { + true => Some(ReferrerPolicy::NoReferrer), + false => None, + }; - document.load_async(LoadType::Stylesheet(url), response_target, referrer_policy); - } - Err(e) => debug!("Parsing url {} failed: {}", href, e) - } + document.load_async(LoadType::Stylesheet(url), response_target, referrer_policy); } fn handle_favicon_url(&self, rel: &str, href: &str, sizes: &Option<String>) { diff --git a/components/script/dom/htmlscriptelement.rs b/components/script/dom/htmlscriptelement.rs index 4b16908968f..e96ceb6d834 100644 --- a/components/script/dom/htmlscriptelement.rs +++ b/components/script/dom/htmlscriptelement.rs @@ -25,7 +25,6 @@ use dom::htmlelement::HTMLElement; use dom::node::{ChildrenMutation, CloneChildrenFlag, Node}; use dom::node::{document_from_node, window_from_node}; use dom::virtualmethods::VirtualMethods; -use dom::window::ScriptHelpers; use encoding::label::encoding_from_whatwg_label; use encoding::types::{DecoderTrap, EncodingRef}; use html5ever::tree_builder::NextParserState; @@ -244,8 +243,6 @@ fn fetch_a_classic_script(script: &HTMLScriptElement, }, origin: doc.url().clone(), pipeline_id: Some(script.global().r().pipeline_id()), - // FIXME: Set to true for now, discussion in https://github.com/whatwg/fetch/issues/381 - same_origin_data: true, referrer_url: Some(doc.url().clone()), referrer_policy: doc.get_referrer_policy(), .. RequestInit::default() @@ -262,8 +259,6 @@ fn fetch_a_classic_script(script: &HTMLScriptElement, status: Ok(()) })); - let doc = document_from_node(script); - let (action_sender, action_receiver) = ipc::channel().unwrap(); let listener = NetworkListener { context: context, @@ -274,7 +269,7 @@ fn fetch_a_classic_script(script: &HTMLScriptElement, ROUTER.add_route(action_receiver.to_opaque(), box move |message| { listener.notify_fetch(message.to().unwrap()); }); - doc.fetch_async(LoadType::Script(url), request, action_sender, None); + doc.fetch_async(LoadType::Script(url), request, action_sender); } impl HTMLScriptElement { @@ -509,9 +504,8 @@ impl HTMLScriptElement { // Step 5.a.2. let window = window_from_node(self); rooted!(in(window.get_cx()) let mut rval = UndefinedValue()); - window.evaluate_script_on_global_with_result(&script.text, - script.url.as_str(), - rval.handle_mut()); + GlobalRef::Window(&window).evaluate_script_on_global_with_result( + &script.text, script.url.as_str(), rval.handle_mut()); // Step 6. document.set_current_script(old_script.r()); diff --git a/components/script/dom/request.rs b/components/script/dom/request.rs index 149c61c96ee..ba15f565c27 100644 --- a/components/script/dom/request.rs +++ b/components/script/dom/request.rs @@ -2,8 +2,9 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +use body::{BodyOperations, BodyType, consume_body}; use dom::bindings::cell::DOMRefCell; -use dom::bindings::codegen::Bindings::HeadersBinding::HeadersInit; +use dom::bindings::codegen::Bindings::HeadersBinding::{HeadersInit, HeadersMethods}; use dom::bindings::codegen::Bindings::RequestBinding; use dom::bindings::codegen::Bindings::RequestBinding::ReferrerPolicy; use dom::bindings::codegen::Bindings::RequestBinding::RequestCache; @@ -21,7 +22,9 @@ use dom::bindings::js::{JS, MutNullableHeap, Root}; use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object}; use dom::bindings::str::{ByteString, DOMString, USVString}; use dom::headers::{Guard, Headers}; -use hyper; +use dom::promise::Promise; +use dom::xmlhttprequest::Extractable; +use hyper::method::Method as HttpMethod; use msg::constellation_msg::ReferrerPolicy as MsgReferrerPolicy; use net_traits::request::{Origin, Window}; use net_traits::request::CacheMode as NetTraitsRequestCache; @@ -33,6 +36,9 @@ use net_traits::request::Request as NetTraitsRequest; use net_traits::request::RequestMode as NetTraitsRequestMode; use net_traits::request::Type as NetTraitsRequestType; use std::cell::Cell; +use std::mem; +use std::rc::Rc; +use style::refcell::Ref; use url::Url; #[dom_struct] @@ -153,7 +159,6 @@ impl Request { // TODO: `entry settings object` is not implemented in Servo yet. *request.origin.borrow_mut() = Origin::Client; request.omit_origin_header = temporary_request.omit_origin_header; - request.same_origin_data.set(true); request.referrer = temporary_request.referrer; request.referrer_policy = temporary_request.referrer_policy; request.mode = temporary_request.mode; @@ -340,7 +345,7 @@ impl Request { try!(r.Headers().fill(Some(HeadersInit::Headers(headers_copy)))); // Step 32 - let input_body = if let RequestInfo::Request(ref input_request) = input { + let mut input_body = if let RequestInfo::Request(ref input_request) = input { let input_request_request = input_request.request.borrow(); let body = input_request_request.body.borrow(); body.clone() @@ -354,9 +359,9 @@ impl Request { let req = r.request.borrow(); let req_method = req.method.borrow(); match &*req_method { - &hyper::method::Method::Get => return Err(Error::Type( + &HttpMethod::Get => return Err(Error::Type( "Init's body is non-null, and request method is GET".to_string())), - &hyper::method::Method::Head => return Err(Error::Type( + &HttpMethod::Head => return Err(Error::Type( "Init's body is non-null, and request method is HEAD".to_string())), _ => {}, } @@ -365,6 +370,20 @@ impl Request { // Step 34 // TODO: `ReadableStream` object is not implemented in Servo yet. + if let Some(Some(ref init_body)) = init.body { + // Step 34.2 + let extracted_body_tmp = init_body.extract(); + input_body = Some(extracted_body_tmp.0); + let content_type = extracted_body_tmp.1; + + // Step 34.3 + if let Some(contents) = content_type { + if !r.Headers().Has(ByteString::new(b"Content-Type".to_vec())).unwrap() { + try!(r.Headers().Append(ByteString::new(b"Content-Type".to_vec()), + ByteString::new(contents.as_bytes().to_vec()))); + } + } + } // Step 35 { @@ -382,6 +401,13 @@ impl Request { // Step 38 Ok(r) } + + // https://fetch.spec.whatwg.org/#concept-body-locked + fn locked(&self) -> bool { + // TODO: ReadableStream is unimplemented. Just return false + // for now. + false + } } impl Request { @@ -418,6 +444,10 @@ impl Request { r_clone.Headers().set_guard(headers_guard); r_clone } + + pub fn get_request(&self) -> NetTraitsRequest { + self.request.borrow().clone() + } } fn net_request_from_global(global: GlobalRef, @@ -431,15 +461,15 @@ fn net_request_from_global(global: GlobalRef, Some(pipeline_id)) } -fn normalized_method_to_typed_method(m: &str) -> hyper::method::Method { +fn normalized_method_to_typed_method(m: &str) -> HttpMethod { match m { - "DELETE" => hyper::method::Method::Delete, - "GET" => hyper::method::Method::Get, - "HEAD" => hyper::method::Method::Head, - "OPTIONS" => hyper::method::Method::Options, - "POST" => hyper::method::Method::Post, - "PUT" => hyper::method::Method::Put, - a => hyper::method::Method::Extension(a.to_string()) + "DELETE" => HttpMethod::Delete, + "GET" => HttpMethod::Get, + "HEAD" => HttpMethod::Head, + "OPTIONS" => HttpMethod::Options, + "POST" => HttpMethod::Post, + "PUT" => HttpMethod::Put, + a => HttpMethod::Extension(a.to_string()) } } @@ -482,10 +512,10 @@ fn is_forbidden_method(m: &ByteString) -> bool { } // https://fetch.spec.whatwg.org/#cors-safelisted-method -fn is_cors_safelisted_method(m: &hyper::method::Method) -> bool { - m == &hyper::method::Method::Get || - m == &hyper::method::Method::Head || - m == &hyper::method::Method::Post +fn is_cors_safelisted_method(m: &HttpMethod) -> bool { + m == &HttpMethod::Get || + m == &HttpMethod::Head || + m == &HttpMethod::Post } // https://url.spec.whatwg.org/#include-credentials @@ -602,6 +632,56 @@ impl RequestMethods for Request { // Step 2 Ok(Request::clone_from(self)) } + + #[allow(unrooted_must_root)] + // https://fetch.spec.whatwg.org/#dom-body-text + fn Text(&self) -> Rc<Promise> { + consume_body(self, BodyType::Text) + } + + #[allow(unrooted_must_root)] + // https://fetch.spec.whatwg.org/#dom-body-blob + fn Blob(&self) -> Rc<Promise> { + consume_body(self, BodyType::Blob) + } + + #[allow(unrooted_must_root)] + // https://fetch.spec.whatwg.org/#dom-body-formdata + fn FormData(&self) -> Rc<Promise> { + consume_body(self, BodyType::FormData) + } + + #[allow(unrooted_must_root)] + // https://fetch.spec.whatwg.org/#dom-body-json + fn Json(&self) -> Rc<Promise> { + consume_body(self, BodyType::Json) + } +} + +impl BodyOperations for Request { + fn get_body_used(&self) -> bool { + self.BodyUsed() + } + + fn is_locked(&self) -> bool { + self.locked() + } + + fn take_body(&self) -> Option<Vec<u8>> { + let ref mut net_traits_req = *self.request.borrow_mut(); + let body: Option<Vec<u8>> = mem::replace(&mut *net_traits_req.body.borrow_mut(), None); + match body { + Some(_) => { + self.body_used.set(true); + body + }, + _ => None, + } + } + + fn get_mime_type(&self) -> Ref<Vec<u8>> { + self.mime_type.borrow() + } } impl Into<NetTraitsRequestCache> for RequestCache { diff --git a/components/script/dom/response.rs b/components/script/dom/response.rs index acfc181283a..b8eeb81fb66 100644 --- a/components/script/dom/response.rs +++ b/components/script/dom/response.rs @@ -2,11 +2,13 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +use body::{BodyOperations, BodyType, consume_body}; use core::cell::Cell; use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::HeadersBinding::HeadersMethods; use dom::bindings::codegen::Bindings::ResponseBinding; use dom::bindings::codegen::Bindings::ResponseBinding::{ResponseMethods, ResponseType as DOMResponseType}; +use dom::bindings::codegen::Bindings::XMLHttpRequestBinding::BodyInit; use dom::bindings::error::{Error, Fallible}; use dom::bindings::global::GlobalRef; use dom::bindings::js::{JS, MutNullableHeap, Root}; @@ -14,9 +16,16 @@ use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object}; use dom::bindings::str::{ByteString, USVString}; use dom::headers::{Headers, Guard}; use dom::headers::{is_vchar, is_obs_text}; +use dom::promise::Promise; +use dom::xmlhttprequest::Extractable; +use hyper::header::Headers as HyperHeaders; use hyper::status::StatusCode; +use hyper_serde::Serde; use net_traits::response::{ResponseBody as NetTraitsResponseBody}; +use std::mem; +use std::rc::Rc; use std::str::FromStr; +use style::refcell::Ref; use url::Position; use url::Url; @@ -33,8 +42,7 @@ pub struct Response { response_type: DOMRefCell<DOMResponseType>, url: DOMRefCell<Option<Url>>, url_list: DOMRefCell<Vec<Url>>, - // For now use the existing NetTraitsResponseBody enum, until body - // is implemented. + // For now use the existing NetTraitsResponseBody enum body: DOMRefCell<NetTraitsResponseBody>, } @@ -59,7 +67,7 @@ impl Response { reflect_dom_object(box Response::new_inherited(), global, ResponseBinding::Wrap) } - pub fn Constructor(global: GlobalRef, _body: Option<USVString>, init: &ResponseBinding::ResponseInit) + pub fn Constructor(global: GlobalRef, body: Option<BodyInit>, init: &ResponseBinding::ResponseInit) -> Fallible<Root<Response>> { // Step 1 if init.status < 200 || init.status > 599 { @@ -86,11 +94,6 @@ impl Response { // Step 6 if let Some(ref headers_member) = init.headers { // Step 6.1 - // TODO: Figure out how/if we should make r's response's - // header list and r's Headers object the same thing. For - // now just working with r's Headers object. Also, the - // header list should already be empty so this step may be - // unnecessary. r.Headers().empty_header_list(); // Step 6.2 @@ -98,23 +101,22 @@ impl Response { } // Step 7 - if let Some(_) = _body { + if let Some(ref body) = body { // Step 7.1 if is_null_body_status(init.status) { return Err(Error::Type( "Body is non-null but init's status member is a null body status".to_string())); }; - // Step 7.2 - let content_type: Option<ByteString> = None; - // Step 7.3 - // TODO: Extract body and implement step 7.3. + let (extracted_body, content_type) = body.extract(); + *r.body.borrow_mut() = NetTraitsResponseBody::Done(extracted_body); // Step 7.4 if let Some(content_type_contents) = content_type { if !r.Headers().Has(ByteString::new(b"Content-Type".to_vec())).unwrap() { - try!(r.Headers().Append(ByteString::new(b"Content-Type".to_vec()), content_type_contents)); + try!(r.Headers().Append(ByteString::new(b"Content-Type".to_vec()), + ByteString::new(content_type_contents.as_bytes().to_vec()))); } }; } @@ -178,6 +180,38 @@ impl Response { // Step 7 Ok(r) } + + // https://fetch.spec.whatwg.org/#concept-body-locked + fn locked(&self) -> bool { + // TODO: ReadableStream is unimplemented. Just return false + // for now. + false + } +} + +impl BodyOperations for Response { + fn get_body_used(&self) -> bool { + self.BodyUsed() + } + + fn is_locked(&self) -> bool { + self.locked() + } + + fn take_body(&self) -> Option<Vec<u8>> { + let body: NetTraitsResponseBody = mem::replace(&mut *self.body.borrow_mut(), NetTraitsResponseBody::Empty); + match body { + NetTraitsResponseBody::Done(bytes) | NetTraitsResponseBody::Receiving(bytes) => { + self.body_used.set(true); + Some(bytes) + }, + _ => None, + } + } + + fn get_mime_type(&self) -> Ref<Vec<u8>> { + self.mime_type.borrow() + } } // https://fetch.spec.whatwg.org/#redirect-status @@ -283,8 +317,53 @@ impl ResponseMethods for Response { fn BodyUsed(&self) -> bool { self.body_used.get() } + + #[allow(unrooted_must_root)] + // https://fetch.spec.whatwg.org/#dom-body-text + fn Text(&self) -> Rc<Promise> { + consume_body(self, BodyType::Text) + } + + #[allow(unrooted_must_root)] + // https://fetch.spec.whatwg.org/#dom-body-blob + fn Blob(&self) -> Rc<Promise> { + consume_body(self, BodyType::Blob) + } + + #[allow(unrooted_must_root)] + // https://fetch.spec.whatwg.org/#dom-body-formdata + fn FormData(&self) -> Rc<Promise> { + consume_body(self, BodyType::FormData) + } + + #[allow(unrooted_must_root)] + // https://fetch.spec.whatwg.org/#dom-body-json + fn Json(&self) -> Rc<Promise> { + consume_body(self, BodyType::Json) + } } fn serialize_without_fragment(url: &Url) -> &str { &url[..Position::AfterQuery] } + +impl Response { + pub fn set_type(&self, new_response_type: DOMResponseType) { + *self.response_type.borrow_mut() = new_response_type; + } + + pub fn set_headers(&self, option_hyper_headers: Option<Serde<HyperHeaders>>) { + self.Headers().set_headers(match option_hyper_headers { + Some(hyper_headers) => hyper_headers.into_inner(), + None => HyperHeaders::new(), + }); + } + + pub fn set_raw_status(&self, status: Option<(u16, Vec<u8>)>) { + *self.raw_status.borrow_mut() = status; + } + + pub fn set_final_url(&self, final_url: Url) { + *self.url.borrow_mut() = Some(final_url); + } +} diff --git a/components/script/dom/serviceworkerglobalscope.rs b/components/script/dom/serviceworkerglobalscope.rs index f6208b63586..6efd555c909 100644 --- a/components/script/dom/serviceworkerglobalscope.rs +++ b/components/script/dom/serviceworkerglobalscope.rs @@ -23,7 +23,6 @@ use ipc_channel::router::ROUTER; use js::jsapi::{JS_SetInterruptCallback, JSAutoCompartment, JSContext}; use js::jsval::UndefinedValue; use js::rust::Runtime; -use msg::constellation_msg::PipelineId; use net_traits::{LoadContext, load_whole_resource, IpcSend, CustomResponseMediator}; use rand::random; use script_runtime::{CommonScriptMsg, StackRootTLS, get_reports, new_rt_and_cx, ScriptChan}; @@ -72,7 +71,6 @@ impl ScriptChan for ServiceWorkerChan { #[dom_struct] pub struct ServiceWorkerGlobalScope { workerglobalscope: WorkerGlobalScope, - id: PipelineId, #[ignore_heap_size_of = "Defined in std"] receiver: Receiver<ServiceWorkerScriptMsg>, #[ignore_heap_size_of = "Defined in std"] @@ -87,7 +85,6 @@ pub struct ServiceWorkerGlobalScope { impl ServiceWorkerGlobalScope { fn new_inherited(init: WorkerGlobalScopeInit, worker_url: Url, - id: PipelineId, from_devtools_receiver: Receiver<DevtoolScriptControlMsg>, runtime: Runtime, own_sender: Sender<ServiceWorkerScriptMsg>, @@ -104,7 +101,6 @@ impl ServiceWorkerGlobalScope { from_devtools_receiver, timer_event_chan, None), - id: id, receiver: receiver, timer_event_port: timer_event_port, own_sender: own_sender, @@ -115,7 +111,6 @@ impl ServiceWorkerGlobalScope { pub fn new(init: WorkerGlobalScopeInit, worker_url: Url, - id: PipelineId, from_devtools_receiver: Receiver<DevtoolScriptControlMsg>, runtime: Runtime, own_sender: Sender<ServiceWorkerScriptMsg>, @@ -128,7 +123,6 @@ impl ServiceWorkerGlobalScope { let cx = runtime.cx(); let scope = box ServiceWorkerGlobalScope::new_inherited(init, worker_url, - id, from_devtools_receiver, runtime, own_sender, @@ -148,7 +142,6 @@ impl ServiceWorkerGlobalScope { swmanager_sender: IpcSender<ServiceWorkerMsg>, scope_url: Url) { let ScopeThings { script_url, - pipeline_id, init, worker_load_origin, .. } = scope_things; @@ -179,7 +172,7 @@ impl ServiceWorkerGlobalScope { let (timer_ipc_chan, _timer_ipc_port) = ipc::channel().unwrap(); let (timer_chan, timer_port) = channel(); let global = ServiceWorkerGlobalScope::new( - init, url, pipeline_id, devtools_mpsc_port, runtime, + init, url, devtools_mpsc_port, runtime, own_sender, receiver, timer_ipc_chan, timer_port, swmanager_sender, scope_url); let scope = global.upcast::<WorkerGlobalScope>(); @@ -298,10 +291,6 @@ impl ServiceWorkerGlobalScope { } } - pub fn pipeline_id(&self) -> PipelineId { - self.id - } - pub fn process_event(&self, msg: CommonScriptMsg) { self.handle_script_event(ServiceWorkerScriptMsg::CommonWorker(WorkerScriptMsg::Common(msg))); } diff --git a/components/script/dom/webglprogram.rs b/components/script/dom/webglprogram.rs index 9ac3f4e1ad4..6382897efb3 100644 --- a/components/script/dom/webglprogram.rs +++ b/components/script/dom/webglprogram.rs @@ -24,6 +24,7 @@ pub struct WebGLProgram { webgl_object: WebGLObject, id: WebGLProgramId, is_deleted: Cell<bool>, + link_called: Cell<bool>, linked: Cell<bool>, fragment_shader: MutNullableHeap<JS<WebGLShader>>, vertex_shader: MutNullableHeap<JS<WebGLShader>>, @@ -39,6 +40,7 @@ impl WebGLProgram { webgl_object: WebGLObject::new_inherited(), id: id, is_deleted: Cell::new(false), + link_called: Cell::new(false), linked: Cell::new(false), fragment_shader: Default::default(), vertex_shader: Default::default(), @@ -91,27 +93,38 @@ impl WebGLProgram { self.is_deleted.get() } + pub fn is_linked(&self) -> bool { + self.linked.get() + } + /// glLinkProgram - pub fn link(&self) { + pub fn link(&self) -> WebGLResult<()> { + if self.is_deleted() { + return Err(WebGLError::InvalidOperation); + } self.linked.set(false); + self.link_called.set(true); match self.fragment_shader.get() { Some(ref shader) if shader.successfully_compiled() => {}, - _ => return, + _ => return Ok(()), // callers use gl.LINK_STATUS to check link errors } match self.vertex_shader.get() { Some(ref shader) if shader.successfully_compiled() => {}, - _ => return, + _ => return Ok(()), // callers use gl.LINK_STATUS to check link errors } self.linked.set(true); - self.renderer.send(CanvasMsg::WebGL(WebGLCommand::LinkProgram(self.id))).unwrap(); + Ok(()) } /// glUseProgram pub fn use_program(&self) -> WebGLResult<()> { + if self.is_deleted() { + return Err(WebGLError::InvalidOperation); + } if !self.linked.get() { return Err(WebGLError::InvalidOperation); } @@ -120,8 +133,20 @@ impl WebGLProgram { Ok(()) } + /// glValidateProgram + pub fn validate(&self) -> WebGLResult<()> { + if self.is_deleted() { + return Err(WebGLError::InvalidOperation); + } + self.renderer.send(CanvasMsg::WebGL(WebGLCommand::ValidateProgram(self.id))).unwrap(); + Ok(()) + } + /// glAttachShader pub fn attach_shader(&self, shader: &WebGLShader) -> WebGLResult<()> { + if self.is_deleted() || shader.is_deleted() { + return Err(WebGLError::InvalidOperation); + } let shader_slot = match shader.gl_type() { constants::FRAGMENT_SHADER => &self.fragment_shader, constants::VERTEX_SHADER => &self.vertex_shader, @@ -147,6 +172,9 @@ impl WebGLProgram { /// glDetachShader pub fn detach_shader(&self, shader: &WebGLShader) -> WebGLResult<()> { + if self.is_deleted() { + return Err(WebGLError::InvalidOperation); + } let shader_slot = match shader.gl_type() { constants::FRAGMENT_SHADER => &self.fragment_shader, constants::VERTEX_SHADER => &self.vertex_shader, @@ -174,6 +202,9 @@ impl WebGLProgram { /// glBindAttribLocation pub fn bind_attrib_location(&self, index: u32, name: DOMString) -> WebGLResult<()> { + if self.is_deleted() { + return Err(WebGLError::InvalidOperation); + } if name.len() > MAX_UNIFORM_AND_ATTRIBUTE_LEN { return Err(WebGLError::InvalidValue); } @@ -190,6 +221,9 @@ impl WebGLProgram { } pub fn get_active_uniform(&self, index: u32) -> WebGLResult<Root<WebGLActiveInfo>> { + if self.is_deleted() { + return Err(WebGLError::InvalidValue); + } let (sender, receiver) = ipc::channel().unwrap(); self.renderer .send(CanvasMsg::WebGL(WebGLCommand::GetActiveUniform(self.id, index, sender))) @@ -201,6 +235,9 @@ impl WebGLProgram { /// glGetActiveAttrib pub fn get_active_attrib(&self, index: u32) -> WebGLResult<Root<WebGLActiveInfo>> { + if self.is_deleted() { + return Err(WebGLError::InvalidValue); + } let (sender, receiver) = ipc::channel().unwrap(); self.renderer .send(CanvasMsg::WebGL(WebGLCommand::GetActiveAttrib(self.id, index, sender))) @@ -212,6 +249,9 @@ impl WebGLProgram { /// glGetAttribLocation pub fn get_attrib_location(&self, name: DOMString) -> WebGLResult<Option<i32>> { + if !self.is_linked() || self.is_deleted() { + return Err(WebGLError::InvalidOperation); + } if name.len() > MAX_UNIFORM_AND_ATTRIBUTE_LEN { return Err(WebGLError::InvalidValue); } @@ -234,6 +274,9 @@ impl WebGLProgram { /// glGetUniformLocation pub fn get_uniform_location(&self, name: DOMString) -> WebGLResult<Option<i32>> { + if !self.is_linked() || self.is_deleted() { + return Err(WebGLError::InvalidOperation); + } if name.len() > MAX_UNIFORM_AND_ATTRIBUTE_LEN { return Err(WebGLError::InvalidValue); } @@ -250,6 +293,25 @@ impl WebGLProgram { Ok(receiver.recv().unwrap()) } + /// glGetProgramInfoLog + pub fn get_info_log(&self) -> WebGLResult<String> { + if self.is_deleted() { + return Err(WebGLError::InvalidOperation); + } + if self.link_called.get() { + let shaders_compiled = match (self.fragment_shader.get(), self.vertex_shader.get()) { + (Some(fs), Some(vs)) => fs.successfully_compiled() && vs.successfully_compiled(), + _ => false + }; + if !shaders_compiled { + return Ok("One or more shaders failed to compile".to_string()); + } + } + let (sender, receiver) = ipc::channel().unwrap(); + self.renderer.send(CanvasMsg::WebGL(WebGLCommand::GetProgramInfoLog(self.id, sender))).unwrap(); + Ok(receiver.recv().unwrap()) + } + /// glGetProgramParameter pub fn parameter(&self, param_id: u32) -> WebGLResult<WebGLParameter> { let (sender, receiver) = ipc::channel().unwrap(); diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index d1342190f73..b69f11146fd 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -1281,15 +1281,36 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { return self.webgl_error(InvalidOperation); } - if count <= 0 { - return self.webgl_error(InvalidOperation); + if count < 0 { + return self.webgl_error(InvalidValue); } if offset < 0 { return self.webgl_error(InvalidValue); } - if self.current_program.get().is_none() || self.bound_buffer_element_array.get().is_none() { + if self.current_program.get().is_none() { + // From the WebGL spec + // + // If the CURRENT_PROGRAM is null, an INVALID_OPERATION error will be generated. + // WebGL performs additional error checking beyond that specified + // in OpenGL ES 2.0 during calls to drawArrays and drawElements. + // + return self.webgl_error(InvalidOperation); + } + + if let Some(array_buffer) = self.bound_buffer_element_array.get() { + // WebGL Spec: check buffer overflows, must be a valid multiple of the size. + let val = offset as u64 + (count as u64 * type_size as u64); + if val > array_buffer.capacity() as u64 { + return self.webgl_error(InvalidOperation); + } + } else { + // From the WebGL spec + // + // a non-null WebGLBuffer must be bound to the ELEMENT_ARRAY_BUFFER binding point + // or an INVALID_OPERATION error will be generated. + // return self.webgl_error(InvalidOperation); } @@ -1323,25 +1344,68 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 + fn DisableVertexAttribArray(&self, attrib_id: u32) { + if attrib_id > self.limits.max_vertex_attribs { + return self.webgl_error(InvalidValue); + } + + self.ipc_renderer + .send(CanvasMsg::WebGL(WebGLCommand::DisableVertexAttribArray(attrib_id))) + .unwrap() + } + + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 fn GetActiveUniform(&self, program: Option<&WebGLProgram>, index: u32) -> Option<Root<WebGLActiveInfo>> { - program.and_then(|p| match p.get_active_uniform(index) { + let program = match program { + Some(program) => program, + None => { + // Reasons to generate InvalidValue error + // From the GLES 2.0 spec + // + // "INVALID_VALUE is generated if index is greater than or equal + // to the number of active uniform variables in program" + // + // A null program has no uniforms so any index is always greater than the active uniforms + // WebGl conformance expects error with null programs. Check tests in get-active-test.html + self.webgl_error(InvalidValue); + return None; + } + }; + + match program.get_active_uniform(index) { Ok(ret) => Some(ret), - Err(error) => { - self.webgl_error(error); - None - }, - }) + Err(e) => { + self.webgl_error(e); + return None; + } + } } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 fn GetActiveAttrib(&self, program: Option<&WebGLProgram>, index: u32) -> Option<Root<WebGLActiveInfo>> { - program.and_then(|p| match p.get_active_attrib(index) { + let program = match program { + Some(program) => program, + None => { + // Reasons to generate InvalidValue error + // From the GLES 2.0 spec + // + // "INVALID_VALUE is generated if index is greater than or equal + // to the number of active attribute variables in program" + // + // A null program has no attributes so any index is always greater than the active uniforms + // WebGl conformance expects error with null programs. Check tests in get-active-test.html + self.webgl_error(InvalidValue); + return None; + } + }; + + match program.get_active_attrib(index) { Ok(ret) => Some(ret), - Err(error) => { - self.webgl_error(error); - None - }, - }) + Err(e) => { + self.webgl_error(e); + return None; + } + } } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 @@ -1354,6 +1418,22 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9 + fn GetProgramInfoLog(&self, program: Option<&WebGLProgram>) -> Option<DOMString> { + if let Some(program) = program { + match program.get_info_log() { + Ok(value) => Some(DOMString::from(value)), + Err(e) => { + self.webgl_error(e); + None + } + } + } else { + self.webgl_error(WebGLError::InvalidValue); + None + } + } + + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9 fn GetProgramParameter(&self, _: *mut JSContext, program: Option<&WebGLProgram>, param_id: u32) -> JSVal { if let Some(program) = program { match handle_potential_webgl_error!(self, program.parameter(param_id), WebGLParameter::Invalid) { @@ -1699,7 +1779,9 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9 fn LinkProgram(&self, program: Option<&WebGLProgram>) { if let Some(program) = program { - program.link() + if let Err(e) = program.link() { + self.webgl_error(e); + } } } @@ -1940,6 +2022,15 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { } } + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9 + fn ValidateProgram(&self, program: Option<&WebGLProgram>) { + if let Some(program) = program { + if let Err(e) = program.validate() { + self.webgl_error(e); + } + } + } + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 fn VertexAttrib1f(&self, indx: u32, x: f32) { self.vertex_attrib(indx, x, 0f32, 0f32, 1f32) @@ -2016,13 +2107,38 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { return self.webgl_error(InvalidValue); } - if let constants::FLOAT = data_type { - let msg = CanvasMsg::WebGL( - WebGLCommand::VertexAttribPointer2f(attrib_id, size, normalized, stride, offset as u32)); - self.ipc_renderer.send(msg).unwrap() - } else { - panic!("VertexAttribPointer: Data Type not supported") + // GLES spec: If offset or stride is negative, an INVALID_VALUE error will be generated + // WebGL spec: the maximum supported stride is 255 + if stride < 0 || stride > 255 || offset < 0 { + return self.webgl_error(InvalidValue); + } + if size < 1 || size > 4 { + return self.webgl_error(InvalidValue); + } + if self.bound_buffer_array.get().is_none() { + return self.webgl_error(InvalidOperation); + } + + // stride and offset must be multiple of data_type + match data_type { + constants::BYTE | constants::UNSIGNED_BYTE => {}, + constants::SHORT | constants::UNSIGNED_SHORT => { + if offset % 2 > 0 || stride % 2 > 0 { + return self.webgl_error(InvalidOperation); + } + }, + constants::FLOAT => { + if offset % 4 > 0 || stride % 4 > 0 { + return self.webgl_error(InvalidOperation); + } + }, + _ => return self.webgl_error(InvalidEnum), + } + + let msg = CanvasMsg::WebGL( + WebGLCommand::VertexAttribPointer(attrib_id, size, data_type, normalized, stride, offset as u32)); + self.ipc_renderer.send(msg).unwrap() } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.4 diff --git a/components/script/dom/webidls/Bluetooth.webidl b/components/script/dom/webidls/Bluetooth.webidl index 6c575db150c..16c30c770d4 100644 --- a/components/script/dom/webidls/Bluetooth.webidl +++ b/components/script/dom/webidls/Bluetooth.webidl @@ -23,9 +23,7 @@ interface Bluetooth { // [SecureContext] // readonly attribute BluetoothDevice? referringDevice; // [SecureContext] -// Promise<BluetoothDevice> requestDevice(RequestDeviceOptions options); - [Throws] - BluetoothDevice requestDevice(optional RequestDeviceOptions options); + Promise<BluetoothDevice> requestDevice(optional RequestDeviceOptions options); }; // Bluetooth implements EventTarget; diff --git a/components/script/dom/webidls/BluetoothRemoteGATTCharacteristic.webidl b/components/script/dom/webidls/BluetoothRemoteGATTCharacteristic.webidl index fdb3afa8b9a..293ac7f742c 100644 --- a/components/script/dom/webidls/BluetoothRemoteGATTCharacteristic.webidl +++ b/components/script/dom/webidls/BluetoothRemoteGATTCharacteristic.webidl @@ -10,18 +10,12 @@ interface BluetoothRemoteGATTCharacteristic { readonly attribute DOMString uuid; readonly attribute BluetoothCharacteristicProperties properties; readonly attribute ByteString? value; - [Throws] - BluetoothRemoteGATTDescriptor getDescriptor(BluetoothDescriptorUUID descriptor); - [Throws] - sequence<BluetoothRemoteGATTDescriptor> getDescriptors(optional BluetoothDescriptorUUID descriptor); - //Promise<BluetoothRemoteGATTDescriptor> getDescriptor(BluetoothDescriptorUUID descriptor); - //Promise<sequence<BluetoothRemoteGATTDescriptor>> - //getDescriptors(optional BluetoothDescriptorUUID descriptor); - [Throws] - ByteString readValue(); + Promise<BluetoothRemoteGATTDescriptor> getDescriptor(BluetoothDescriptorUUID descriptor); + Promise<sequence<BluetoothRemoteGATTDescriptor>> + getDescriptors(optional BluetoothDescriptorUUID descriptor); + Promise<ByteString> readValue(); //Promise<DataView> readValue(); - [Throws] - void writeValue(sequence<octet> value); + Promise<void> writeValue(sequence<octet> value); //Promise<void> writeValue(BufferSource value); //Promise<void> startNotifications(); //Promise<void> stopNotifications(); diff --git a/components/script/dom/webidls/BluetoothRemoteGATTDescriptor.webidl b/components/script/dom/webidls/BluetoothRemoteGATTDescriptor.webidl index 8c744929542..7ffd3f2ebb5 100644 --- a/components/script/dom/webidls/BluetoothRemoteGATTDescriptor.webidl +++ b/components/script/dom/webidls/BluetoothRemoteGATTDescriptor.webidl @@ -9,10 +9,8 @@ interface BluetoothRemoteGATTDescriptor { readonly attribute BluetoothRemoteGATTCharacteristic characteristic; readonly attribute DOMString uuid; readonly attribute ByteString? value; - [Throws] - ByteString readValue(); + Promise<ByteString> readValue(); //Promise<DataView> readValue(); - [Throws] - void writeValue(sequence<octet> value); + Promise<void> writeValue(sequence<octet> value); //Promise<void> writeValue(BufferSource value); }; diff --git a/components/script/dom/webidls/BluetoothRemoteGATTServer.webidl b/components/script/dom/webidls/BluetoothRemoteGATTServer.webidl index 13314d7c6e1..45e3df198fe 100644 --- a/components/script/dom/webidls/BluetoothRemoteGATTServer.webidl +++ b/components/script/dom/webidls/BluetoothRemoteGATTServer.webidl @@ -8,15 +8,9 @@ interface BluetoothRemoteGATTServer { readonly attribute BluetoothDevice device; readonly attribute boolean connected; - [Throws] - BluetoothRemoteGATTServer connect(); + Promise<BluetoothRemoteGATTServer> connect(); [Throws] void disconnect(); - [Throws] - BluetoothRemoteGATTService getPrimaryService(BluetoothServiceUUID service); - [Throws] - sequence<BluetoothRemoteGATTService> getPrimaryServices(optional BluetoothServiceUUID service); - //Promise<BluetoothRemoteGATTService> getPrimaryService(BluetoothServiceUUID service); - //Promise<sequence<BluetoothRemoteGATTService>>getPrimaryServices(optional BluetoothServiceUUID service); - //Promise<BluetoothRemoteGATTServer> connect(); + Promise<BluetoothRemoteGATTService> getPrimaryService(BluetoothServiceUUID service); + Promise<sequence<BluetoothRemoteGATTService>> getPrimaryServices(optional BluetoothServiceUUID service); }; diff --git a/components/script/dom/webidls/BluetoothRemoteGATTService.webidl b/components/script/dom/webidls/BluetoothRemoteGATTService.webidl index a7ee941232a..a484ae64f80 100644 --- a/components/script/dom/webidls/BluetoothRemoteGATTService.webidl +++ b/components/script/dom/webidls/BluetoothRemoteGATTService.webidl @@ -9,18 +9,9 @@ interface BluetoothRemoteGATTService { readonly attribute BluetoothDevice device; readonly attribute DOMString uuid; readonly attribute boolean isPrimary; - [Throws] - BluetoothRemoteGATTCharacteristic getCharacteristic(BluetoothCharacteristicUUID characteristic); - [Throws] - sequence<BluetoothRemoteGATTCharacteristic> getCharacteristics - (optional BluetoothCharacteristicUUID characteristic); - //Promise<BluetoothRemoteGATTCharacteristic>getCharacteristic(BluetoothCharacteristicUUID characteristic); - //Promise<sequence<BluetoothRemoteGATTCharacteristic>> - //getCharacteristics(optional BluetoothCharacteristicUUID characteristic); - [Throws] - BluetoothRemoteGATTService getIncludedService(BluetoothServiceUUID service); - [Throws] - sequence<BluetoothRemoteGATTService> getIncludedServices(optional BluetoothServiceUUID service); - //Promise<BluetoothRemoteGATTService>getIncludedService(BluetoothServiceUUID service); - //Promise<sequence<BluetoothRemoteGATTService>>getIncludedServices(optional BluetoothServiceUUID service); + Promise<BluetoothRemoteGATTCharacteristic> getCharacteristic(BluetoothCharacteristicUUID characteristic); + Promise<sequence<BluetoothRemoteGATTCharacteristic>> + getCharacteristics(optional BluetoothCharacteristicUUID characteristic); + Promise<BluetoothRemoteGATTService> getIncludedService(BluetoothServiceUUID service); + Promise<sequence<BluetoothRemoteGATTService>> getIncludedServices(optional BluetoothServiceUUID service); }; diff --git a/components/script/dom/webidls/Body.webidl b/components/script/dom/webidls/Body.webidl index a020228a01d..bb7aa5c6859 100644 --- a/components/script/dom/webidls/Body.webidl +++ b/components/script/dom/webidls/Body.webidl @@ -10,10 +10,9 @@ interface Body { readonly attribute boolean bodyUsed; - // Servo does not support Promise at this moment. // [NewObject] Promise<ArrayBuffer> arrayBuffer(); - // [NewObject] Promise<Blob> blob(); - // [NewObject] Promise<FormData> formData(); - // [NewObject] Promise<JSON> json(); - // [NewObject] Promise<USVString> text(); + [NewObject] Promise<Blob> blob(); + [NewObject] Promise<FormData> formData(); + [NewObject] Promise<any> json(); + [NewObject] Promise<USVString> text(); }; diff --git a/components/script/dom/webidls/EventSource.webidl b/components/script/dom/webidls/EventSource.webidl index 11c30e959d4..b9cf82d6a3e 100644 --- a/components/script/dom/webidls/EventSource.webidl +++ b/components/script/dom/webidls/EventSource.webidl @@ -7,7 +7,8 @@ */ [Constructor(DOMString url, optional EventSourceInit eventSourceInitDict), - Exposed=(Window,Worker)] + Exposed=(Window,Worker), + Pref="dom.eventsource.enabled"] interface EventSource : EventTarget { readonly attribute DOMString url; readonly attribute boolean withCredentials; diff --git a/components/script/dom/webidls/Fetch.webidl b/components/script/dom/webidls/Fetch.webidl new file mode 100644 index 00000000000..fe062994598 --- /dev/null +++ b/components/script/dom/webidls/Fetch.webidl @@ -0,0 +1,11 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// https://fetch.spec.whatwg.org/#fetch-method + +[Exposed=(Window,Worker)] + +partial interface WindowOrWorkerGlobalScope { + [NewObject] Promise<Response> fetch(RequestInfo input, optional RequestInit init); +}; diff --git a/components/script/dom/webidls/Response.webidl b/components/script/dom/webidls/Response.webidl index 2052f5c6371..a1b3cf7dd9a 100644 --- a/components/script/dom/webidls/Response.webidl +++ b/components/script/dom/webidls/Response.webidl @@ -4,8 +4,7 @@ // https://fetch.spec.whatwg.org/#response-class -// TODO: pass 'optional ResponseBodyInit? body = null' to constructor in place of USVString - [Constructor(optional USVString? body = null, optional ResponseInit init), + [Constructor(optional BodyInit? body = null, optional ResponseInit init), Exposed=(Window,Worker)] interface Response { [NewObject] static Response error(); diff --git a/components/script/dom/webidls/WebGLRenderingContext.webidl b/components/script/dom/webidls/WebGLRenderingContext.webidl index 06727b3a536..19e5f029168 100644 --- a/components/script/dom/webidls/WebGLRenderingContext.webidl +++ b/components/script/dom/webidls/WebGLRenderingContext.webidl @@ -552,7 +552,7 @@ interface WebGLRenderingContextBase void depthRange(GLclampf zNear, GLclampf zFar); void detachShader(WebGLProgram? program, WebGLShader? shader); void disable(GLenum cap); - //void disableVertexAttribArray(GLuint index); + void disableVertexAttribArray(GLuint index); void drawArrays(GLenum mode, GLint first, GLsizei count); void drawElements(GLenum mode, GLsizei count, GLenum type, GLintptr offset); @@ -583,7 +583,7 @@ interface WebGLRenderingContextBase //any getFramebufferAttachmentParameter(GLenum target, GLenum attachment, // GLenum pname); any getProgramParameter(WebGLProgram? program, GLenum pname); - //DOMString? getProgramInfoLog(WebGLProgram? program); + DOMString? getProgramInfoLog(WebGLProgram? program); //any getRenderbufferParameter(GLenum target, GLenum pname); any getShaderParameter(WebGLShader? shader, GLenum pname); //WebGLShaderPrecisionFormat? getShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype); @@ -704,7 +704,7 @@ interface WebGLRenderingContextBase // sequence<GLfloat> value); void useProgram(WebGLProgram? program); - //void validateProgram(WebGLProgram? program); + void validateProgram(WebGLProgram? program); // FIXME(dmarcos) // The code generator doesn't handle Float32Array so we're using 'object' diff --git a/components/script/dom/webidls/WindowOrWorkerGlobalScope.webidl b/components/script/dom/webidls/WindowOrWorkerGlobalScope.webidl new file mode 100644 index 00000000000..f0b8218fbe2 --- /dev/null +++ b/components/script/dom/webidls/WindowOrWorkerGlobalScope.webidl @@ -0,0 +1,30 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// https://html.spec.whatwg.org/multipage/#windoworworkerglobalscope + +// typedef (DOMString or Function) TimerHandler; + +[NoInterfaceObject, Exposed=(Window,Worker)] +interface WindowOrWorkerGlobalScope { + // [Replaceable] readonly attribute USVString origin; + + // base64 utility methods + // DOMString btoa(DOMString data); + // DOMString atob(DOMString data); + + // timers + // long setTimeout(TimerHandler handler, optional long timeout = 0, any... arguments); + // void clearTimeout(optional long handle = 0); + // long setInterval(TimerHandler handler, optional long timeout = 0, any... arguments); + // void clearInterval(optional long handle = 0); + + // ImageBitmap + // Promise<ImageBitmap> createImageBitmap(ImageBitmapSource image, optional ImageBitmapOptions options); + // Promise<ImageBitmap> createImageBitmap( + // ImageBitmapSource image, long sx, long sy, long sw, long sh, optional ImageBitmapOptions options); +}; + +Window implements WindowOrWorkerGlobalScope; +WorkerGlobalScope implements WindowOrWorkerGlobalScope; diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 3e841116acd..3ac5c4e37f9 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -12,9 +12,11 @@ use dom::bindings::codegen::Bindings::EventHandlerBinding::OnBeforeUnloadEventHa use dom::bindings::codegen::Bindings::EventHandlerBinding::OnErrorEventHandlerNonNull; use dom::bindings::codegen::Bindings::FunctionBinding::Function; use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; +use dom::bindings::codegen::Bindings::RequestBinding::RequestInit; use dom::bindings::codegen::Bindings::WindowBinding::{self, FrameRequestCallback, WindowMethods}; use dom::bindings::codegen::Bindings::WindowBinding::{ScrollBehavior, ScrollToOptions}; -use dom::bindings::error::{Error, ErrorInfo, ErrorResult, Fallible, report_pending_exception}; +use dom::bindings::codegen::UnionTypes::RequestOrUSVString; +use dom::bindings::error::{Error, ErrorInfo, ErrorResult, Fallible}; use dom::bindings::global::{GlobalRef, global_root_from_object}; use dom::bindings::inheritance::Castable; use dom::bindings::js::{JS, MutNullableHeap, Root}; @@ -40,17 +42,17 @@ use dom::messageevent::MessageEvent; use dom::navigator::Navigator; use dom::node::{Node, from_untrusted_node_address, window_from_node}; use dom::performance::Performance; +use dom::promise::Promise; use dom::screen::Screen; use dom::storage::Storage; use euclid::{Point2D, Rect, Size2D}; +use fetch; use gfx_traits::LayerId; use ipc_channel::ipc::{self, IpcSender}; -use js::jsapi::{Evaluate2, HandleObject, HandleValue, JSAutoCompartment, JSContext}; -use js::jsapi::{JS_GC, JS_GetRuntime, MutableHandleValue, SetWindowProxy}; +use js::jsapi::{HandleObject, HandleValue, JSAutoCompartment, JSContext}; +use js::jsapi::{JS_GC, JS_GetRuntime, SetWindowProxy}; use js::jsval::UndefinedValue; -use js::rust::CompileOptionsWrapper; use js::rust::Runtime; -use libc; use msg::constellation_msg::{FrameType, LoadData, PipelineId, ReferrerPolicy, WindowSizeType}; use net_traits::ResourceThreads; use net_traits::bluetooth_thread::BluetoothMethodMsg; @@ -60,15 +62,14 @@ use num_traits::ToPrimitive; use open; use origin::Origin; use profile_traits::mem; -use profile_traits::time::{ProfilerCategory, TimerMetadata, TimerMetadataFrameType}; -use profile_traits::time::{ProfilerChan, TimerMetadataReflowType, profile}; +use profile_traits::time::ProfilerChan; use rustc_serialize::base64::{FromBase64, STANDARD, ToBase64}; use script_layout_interface::TrustedNodeAddress; use script_layout_interface::message::{Msg, Reflow, ReflowQueryType, ScriptReflow}; use script_layout_interface::reporter::CSSErrorReporter; use script_layout_interface::rpc::{ContentBoxResponse, ContentBoxesResponse, LayoutRPC}; use script_layout_interface::rpc::{MarginStyleResponse, ResolvedStyleResponse}; -use script_runtime::{CommonScriptMsg, ScriptChan, ScriptPort, ScriptThreadEventCategory, maybe_take_panic_result}; +use script_runtime::{CommonScriptMsg, ScriptChan, ScriptPort, ScriptThreadEventCategory}; use script_thread::{MainThreadScriptChan, MainThreadScriptMsg, Runnable, RunnableWrapper}; use script_thread::SendableMainThreadScriptChan; use script_traits::{ConstellationControlMsg, MozBrowserEvent, UntrustedNodeAddress}; @@ -80,9 +81,7 @@ use std::borrow::ToOwned; use std::cell::Cell; use std::collections::{HashMap, HashSet}; use std::default::Default; -use std::ffi::CString; use std::io::{Write, stderr, stdout}; -use std::panic; use std::rc::Rc; use std::sync::{Arc, Mutex}; use std::sync::atomic::{AtomicBool, Ordering}; @@ -191,7 +190,6 @@ pub struct Window { devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>, /// For sending timeline markers. Will be ignored if /// no devtools server - #[ignore_heap_size_of = "TODO(#6909) need to measure HashSet"] devtools_markers: DOMRefCell<HashSet<TimelineMarkerType>>, #[ignore_heap_size_of = "channels are hard"] devtools_marker_sender: DOMRefCell<Option<IpcSender<TimelineMarker>>>, @@ -902,60 +900,11 @@ impl WindowMethods for Window { Err(e) => Err(Error::Type(format!("Couldn't open URL: {}", e))), } } -} - -pub trait ScriptHelpers { - fn evaluate_js_on_global_with_result(self, code: &str, - rval: MutableHandleValue); - fn evaluate_script_on_global_with_result(self, code: &str, filename: &str, - rval: MutableHandleValue); -} - -impl<'a, T: Reflectable> ScriptHelpers for &'a T { - fn evaluate_js_on_global_with_result(self, code: &str, - rval: MutableHandleValue) { - self.evaluate_script_on_global_with_result(code, "", rval) - } - - #[allow(unsafe_code)] - fn evaluate_script_on_global_with_result(self, code: &str, filename: &str, - rval: MutableHandleValue) { - let global = self.global(); - let metadata = TimerMetadata { - url: if filename.is_empty() { - global.r().get_url().as_str().into() - } else { - filename.into() - }, - iframe: TimerMetadataFrameType::RootWindow, - incremental: TimerMetadataReflowType::FirstReflow, - }; - profile( - ProfilerCategory::ScriptEvaluate, - Some(metadata), - global.r().time_profiler_chan().clone(), - || { - let cx = global.r().get_cx(); - let globalhandle = global.r().reflector().get_jsobject(); - let code: Vec<u16> = code.encode_utf16().collect(); - let filename = CString::new(filename).unwrap(); - - let _ac = JSAutoCompartment::new(cx, globalhandle.get()); - let options = CompileOptionsWrapper::new(cx, filename.as_ptr(), 1); - unsafe { - if !Evaluate2(cx, options.ptr, code.as_ptr(), - code.len() as libc::size_t, - rval) { - debug!("error evaluating JS string"); - report_pending_exception(cx, true); - } - } - if let Some(error) = maybe_take_panic_result() { - panic::resume_unwind(error); - } - } - ) + #[allow(unrooted_must_root)] + // https://fetch.spec.whatwg.org/#fetch-method + fn Fetch(&self, input: RequestOrUSVString, init: &RequestInit) -> Rc<Promise> { + fetch::Fetch(self.global().r(), input, init) } } diff --git a/components/script/dom/worker.rs b/components/script/dom/worker.rs index 1821b2d2dee..fb6b170ab1d 100644 --- a/components/script/dom/worker.rs +++ b/components/script/dom/worker.rs @@ -106,7 +106,7 @@ impl Worker { let init = prepare_workerscope_init(global, Some(devtools_sender)); DedicatedWorkerGlobalScope::run_worker_scope( - init, worker_url, global.pipeline_id(), devtools_receiver, worker.runtime.clone(), worker_ref, + init, worker_url, devtools_receiver, worker.runtime.clone(), worker_ref, global.script_chan(), sender, receiver, worker_load_origin, closing); Ok(worker) diff --git a/components/script/dom/workerglobalscope.rs b/components/script/dom/workerglobalscope.rs index 2520f57dbac..9c7768ce5e7 100644 --- a/components/script/dom/workerglobalscope.rs +++ b/components/script/dom/workerglobalscope.rs @@ -5,8 +5,10 @@ use devtools_traits::{DevtoolScriptControlMsg, ScriptToDevtoolsControlMsg, WorkerId}; use dom::bindings::codegen::Bindings::EventHandlerBinding::OnErrorEventHandlerNonNull; use dom::bindings::codegen::Bindings::FunctionBinding::Function; +use dom::bindings::codegen::Bindings::RequestBinding::RequestInit; use dom::bindings::codegen::Bindings::WorkerGlobalScopeBinding::WorkerGlobalScopeMethods; -use dom::bindings::error::{Error, ErrorResult, Fallible, report_pending_exception, ErrorInfo}; +use dom::bindings::codegen::UnionTypes::RequestOrUSVString; +use dom::bindings::error::{Error, ErrorInfo, ErrorResult, Fallible, report_pending_exception}; use dom::bindings::global::{GlobalRef, GlobalRoot}; use dom::bindings::inheritance::Castable; use dom::bindings::js::{JS, MutNullableHeap, Root}; @@ -16,11 +18,16 @@ use dom::bindings::str::DOMString; use dom::console::TimerSet; use dom::crypto::Crypto; use dom::dedicatedworkerglobalscope::DedicatedWorkerGlobalScope; +use dom::errorevent::ErrorEvent; +use dom::event::{Event, EventBubbles, EventCancelable}; +use dom::eventdispatcher::EventStatus; use dom::eventtarget::EventTarget; +use dom::promise::Promise; use dom::serviceworkerglobalscope::ServiceWorkerGlobalScope; use dom::window::{base64_atob, base64_btoa}; use dom::workerlocation::WorkerLocation; use dom::workernavigator::WorkerNavigator; +use fetch; use ipc_channel::ipc::IpcSender; use js::jsapi::{HandleValue, JSAutoCompartment, JSContext, JSRuntime}; use js::jsval::UndefinedValue; @@ -62,7 +69,8 @@ pub fn prepare_workerscope_init(global: GlobalRef, from_devtools_sender: devtools_sender, constellation_chan: global.constellation_chan().clone(), scheduler_chan: global.scheduler_chan().clone(), - worker_id: worker_id + worker_id: worker_id, + pipeline_id: global.pipeline_id(), }; init @@ -73,6 +81,7 @@ pub fn prepare_workerscope_init(global: GlobalRef, pub struct WorkerGlobalScope { eventtarget: EventTarget, worker_id: WorkerId, + pipeline_id: PipelineId, worker_url: Url, closing: Option<Arc<AtomicBool>>, #[ignore_heap_size_of = "Defined in js"] @@ -116,6 +125,9 @@ pub struct WorkerGlobalScope { console_timers: TimerSet, promise_job_queue: PromiseJobQueue, + + /// https://html.spec.whatwg.org/multipage/#in-error-reporting-mode + in_error_reporting_mode: Cell<bool> } impl WorkerGlobalScope { @@ -130,6 +142,7 @@ impl WorkerGlobalScope { eventtarget: EventTarget::new_inherited(), next_worker_id: Cell::new(WorkerId(0)), worker_id: init.worker_id, + pipeline_id: init.pipeline_id, worker_url: worker_url, closing: closing, runtime: runtime, @@ -148,6 +161,7 @@ impl WorkerGlobalScope { scheduler_chan: init.scheduler_chan, console_timers: TimerSet::new(), promise_job_queue: PromiseJobQueue::new(), + in_error_reporting_mode: Default::default(), } } @@ -393,6 +407,12 @@ impl WorkerGlobalScopeMethods for WorkerGlobalScope { fn ClearInterval(&self, handle: i32) { self.ClearTimeout(handle); } + + #[allow(unrooted_must_root)] + // https://fetch.spec.whatwg.org/#fetch-method + fn Fetch(&self, input: RequestOrUSVString, init: &RequestInit) -> Rc<Promise> { + fetch::Fetch(self.global().r(), input, init) + } } @@ -437,15 +457,7 @@ impl WorkerGlobalScope { } pub fn pipeline_id(&self) -> PipelineId { - let dedicated = self.downcast::<DedicatedWorkerGlobalScope>(); - let service_worker = self.downcast::<ServiceWorkerGlobalScope>(); - if let Some(dedicated) = dedicated { - return dedicated.pipeline_id(); - } else if let Some(service_worker) = service_worker { - return service_worker.pipeline_id(); - } else { - panic!("need to implement a sender for SharedWorker") - } + self.pipeline_id } pub fn new_script_pair(&self) -> (Box<ScriptChan + Send>, Box<ScriptPort + Send>) { @@ -485,9 +497,38 @@ impl WorkerGlobalScope { /// https://html.spec.whatwg.org/multipage/#report-the-error pub fn report_an_error(&self, error_info: ErrorInfo, value: HandleValue) { - self.downcast::<DedicatedWorkerGlobalScope>() - .expect("Should implement report_an_error for this worker") - .report_an_error(error_info, value); + // Step 1. + if self.in_error_reporting_mode.get() { + return; + } + + // Step 2. + self.in_error_reporting_mode.set(true); + + // Steps 3-12. + // FIXME(#13195): muted errors. + let event = ErrorEvent::new(GlobalRef::Worker(self), + atom!("error"), + EventBubbles::DoesNotBubble, + EventCancelable::Cancelable, + error_info.message.as_str().into(), + error_info.filename.as_str().into(), + error_info.lineno, + error_info.column, + value); + + // Step 13. + let event_status = event.upcast::<Event>().fire(self.upcast::<EventTarget>()); + + // Step 15 + if event_status == EventStatus::NotCanceled { + if let Some(dedicated) = self.downcast::<DedicatedWorkerGlobalScope>() { + dedicated.forward_error_to_worker_object(error_info); + } + } + + // Step 14 + self.in_error_reporting_mode.set(false); } } diff --git a/components/script/dom/xmlhttprequest.rs b/components/script/dom/xmlhttprequest.rs index 0d21f9026fc..caebbddd09e 100644 --- a/components/script/dom/xmlhttprequest.rs +++ b/components/script/dom/xmlhttprequest.rs @@ -587,7 +587,6 @@ impl XMLHttpRequestMethods for XMLHttpRequest { url: self.request_url.borrow().clone().unwrap(), headers: (*self.request_headers.borrow()).clone(), unsafe_request: true, - same_origin_data: true, // XXXManishearth figure out how to avoid this clone body: extracted.as_ref().map(|e| e.0.clone()), // XXXManishearth actually "subresource", but it doesn't exist @@ -1371,7 +1370,7 @@ impl XHRTimeoutCallback { } } -trait Extractable { +pub trait Extractable { fn extract(&self) -> (Vec<u8>, Option<DOMString>); } impl Extractable for BodyInit { |