diff options
Diffstat (limited to 'components/script')
12 files changed, 400 insertions, 255 deletions
diff --git a/components/script/dom/bindings/codegen/parser/WebIDL.py b/components/script/dom/bindings/codegen/parser/WebIDL.py index b2daa1bce20..b56a1765d57 100644 --- a/components/script/dom/bindings/codegen/parser/WebIDL.py +++ b/components/script/dom/bindings/codegen/parser/WebIDL.py @@ -684,7 +684,7 @@ def globalNameSetToExposureSet(globalScope, nameSet, exposureSet): class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): def __init__(self, location, parentScope, name, parent, members, - isKnownNonPartial): + isKnownNonPartial, toStringTag): assert isinstance(parentScope, IDLScope) assert isinstance(name, IDLUnresolvedIdentifier) assert isKnownNonPartial or not parent @@ -722,6 +722,8 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): # interface we're iterating for in order to get its nativeType. self.iterableInterface = None + self.toStringTag = toStringTag + IDLObjectWithScope.__init__(self, location, parentScope, name) IDLExposureMixins.__init__(self, location) @@ -1017,10 +1019,9 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): [self.location]) for m in self.members: - if ((m.isMethod() and m.isJsonifier()) or - m.identifier.name == "toJSON"): + if m.identifier.name == "toJSON": raise WebIDLError("Unforgeable interface %s has a " - "jsonifier so we won't be able to add " + "toJSON so we won't be able to add " "one ourselves" % self.identifier.name, [self.location, m.location]) @@ -1044,6 +1045,12 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): (member.getExtendedAttribute("StoreInSlot") or member.getExtendedAttribute("Cached"))) or member.isMaplikeOrSetlike()): + if self.isJSImplemented() and not member.isMaplikeOrSetlike(): + raise WebIDLError("Interface %s is JS-implemented and we " + "don't support [Cached] or [StoreInSlot] " + "on JS-implemented interfaces" % + self.identifier.name, + [self.location, member.location]) if member.slotIndices is None: member.slotIndices = dict() member.slotIndices[self.identifier.name] = self.totalMembersInSlots @@ -1115,15 +1122,12 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): memberType = "deleters" elif member.isStringifier(): memberType = "stringifiers" - elif member.isJsonifier(): - memberType = "jsonifiers" elif member.isLegacycaller(): memberType = "legacycallers" else: continue - if (memberType != "stringifiers" and memberType != "legacycallers" and - memberType != "jsonifiers"): + if (memberType != "stringifiers" and memberType != "legacycallers"): if member.isNamed(): memberType = "named " + memberType else: @@ -1573,9 +1577,12 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): class IDLInterface(IDLInterfaceOrNamespace): def __init__(self, location, parentScope, name, parent, members, - isKnownNonPartial): + isKnownNonPartial, classNameOverride=None, + toStringTag=None): IDLInterfaceOrNamespace.__init__(self, location, parentScope, name, - parent, members, isKnownNonPartial) + parent, members, isKnownNonPartial, + toStringTag) + self.classNameOverride = classNameOverride def __str__(self): return "Interface '%s'" % self.identifier.name @@ -1583,6 +1590,11 @@ class IDLInterface(IDLInterfaceOrNamespace): def isInterface(self): return True + def getClassName(self): + if self.classNameOverride: + return self.classNameOverride + return self.identifier.name + def addExtendedAttributes(self, attrs): for attr in attrs: identifier = attr.identifier() @@ -1677,14 +1689,6 @@ class IDLInterface(IDLInterfaceOrNamespace): elif newMethod not in self.namedConstructors: raise WebIDLError("NamedConstructor conflicts with a NamedConstructor of a different interface", [method.location, newMethod.location]) - elif (identifier == "ArrayClass"): - if not attr.noArguments(): - raise WebIDLError("[ArrayClass] must take no arguments", - [attr.location]) - if self.parent: - raise WebIDLError("[ArrayClass] must not be specified on " - "an interface with inherited interfaces", - [attr.location, self.location]) elif (identifier == "ExceptionClass"): if not attr.noArguments(): raise WebIDLError("[ExceptionClass] must take no arguments", @@ -1738,6 +1742,7 @@ class IDLInterface(IDLInterfaceOrNamespace): identifier == "ProbablyShortLivingWrapper" or identifier == "LegacyUnenumerableNamedProperties" or identifier == "RunConstructorInCallerCompartment" or + identifier == "WantsEventListenerHooks" or identifier == "NonOrdinaryGetPrototypeOf" or identifier == "Abstract" or identifier == "Inline"): @@ -1769,7 +1774,8 @@ class IDLInterface(IDLInterfaceOrNamespace): class IDLNamespace(IDLInterfaceOrNamespace): def __init__(self, location, parentScope, name, members, isKnownNonPartial): IDLInterfaceOrNamespace.__init__(self, location, parentScope, name, - None, members, isKnownNonPartial) + None, members, isKnownNonPartial, + toStringTag=None) def __str__(self): return "Namespace '%s'" % self.identifier.name @@ -2152,7 +2158,7 @@ class IDLType(IDLObject): # Should only call this on float types assert self.isFloat() - def isSerializable(self): + def isJSONType(self): return False def tag(self): @@ -2350,8 +2356,8 @@ class IDLNullableType(IDLParametrizedType): def isUnion(self): return self.inner.isUnion() - def isSerializable(self): - return self.inner.isSerializable() + def isJSONType(self): + return self.inner.isJSONType() def tag(self): return self.inner.tag() @@ -2430,8 +2436,8 @@ class IDLSequenceType(IDLParametrizedType): def isEnum(self): return False - def isSerializable(self): - return self.inner.isSerializable() + def isJSONType(self): + return self.inner.isJSONType() def tag(self): return IDLType.Tags.sequence @@ -2476,6 +2482,9 @@ class IDLRecordType(IDLParametrizedType): def isRecord(self): return True + def isJSONType(self): + return self.inner.isJSONType() + def tag(self): return IDLType.Tags.record @@ -2525,8 +2534,8 @@ class IDLUnionType(IDLType): def isUnion(self): return True - def isSerializable(self): - return all(m.isSerializable() for m in self.memberTypes) + def isJSONType(self): + return all(m.isJSONType() for m in self.memberTypes) def includesRestrictedFloat(self): return any(t.includesRestrictedFloat() for t in self.memberTypes) @@ -2676,6 +2685,9 @@ class IDLTypedefType(IDLType): def isVoid(self): return self.inner.isVoid() + def isJSONType(self): + return self.inner.isJSONType() + def isSequence(self): return self.inner.isSequence() @@ -2817,15 +2829,25 @@ class IDLWrapperType(IDLType): def isEnum(self): return isinstance(self.inner, IDLEnum) - def isSerializable(self): + def isJSONType(self): if self.isInterface(): if self.inner.isExternal(): return False - return any(m.isMethod() and m.isJsonifier() for m in self.inner.members) + iface = self.inner + while iface: + if any(m.isMethod() and m.isToJSON() for m in iface.members): + return True + iface = iface.parent + return False elif self.isEnum(): return True elif self.isDictionary(): - return all(m.type.isSerializable() for m in self.inner.members) + dictionary = self.inner + while dictionary: + if not all(m.type.isJSONType() for m in dictionary.members): + return False + dictionary = dictionary.parent + return True else: raise WebIDLError("IDLWrapperType wraps type %s that we don't know if " "is serializable" % type(self.inner), [self.location]) @@ -3111,8 +3133,8 @@ class IDLBuiltinType(IDLType): return (self._typeTag == IDLBuiltinType.Types.unrestricted_float or self._typeTag == IDLBuiltinType.Types.unrestricted_double) - def isSerializable(self): - return self.isPrimitive() or self.isString() or self.isDate() + def isJSONType(self): + return self.isPrimitive() or self.isString() or self.isObject() def includesRestrictedFloat(self): return self.isFloat() and not self.isUnrestricted() @@ -4665,7 +4687,7 @@ class IDLMethod(IDLInterfaceMember, IDLScope): def __init__(self, location, identifier, returnType, arguments, static=False, getter=False, setter=False, deleter=False, specialType=NamedOrIndexed.Neither, - legacycaller=False, stringifier=False, jsonifier=False, + legacycaller=False, stringifier=False, maplikeOrSetlikeOrIterable=None, htmlConstructor=False): # REVIEW: specialType is NamedOrIndexed -- wow, this is messed up. IDLInterfaceMember.__init__(self, location, identifier, @@ -4690,8 +4712,6 @@ class IDLMethod(IDLInterfaceMember, IDLScope): self._legacycaller = legacycaller assert isinstance(stringifier, bool) self._stringifier = stringifier - assert isinstance(jsonifier, bool) - self._jsonifier = jsonifier assert maplikeOrSetlikeOrIterable is None or isinstance(maplikeOrSetlikeOrIterable, IDLMaplikeOrSetlikeOrIterableBase) self.maplikeOrSetlikeOrIterable = maplikeOrSetlikeOrIterable assert isinstance(htmlConstructor, bool) @@ -4739,12 +4759,6 @@ class IDLMethod(IDLInterfaceMember, IDLScope): assert len(overload.arguments) == 0 assert overload.returnType == BuiltinTypes[IDLBuiltinType.Types.domstring] - if self._jsonifier: - assert len(self._overloads) == 1 - overload = self._overloads[0] - assert len(overload.arguments) == 0 - assert overload.returnType == BuiltinTypes[IDLBuiltinType.Types.object] - def isStatic(self): return self._static @@ -4776,8 +4790,11 @@ class IDLMethod(IDLInterfaceMember, IDLScope): def isStringifier(self): return self._stringifier - def isJsonifier(self): - return self._jsonifier + def isToJSON(self): + return self.identifier.name == "toJSON" + + def isDefaultToJSON(self): + return self.isToJSON() and self.getExtendedAttribute("Default") def isMaplikeOrSetlikeOrIterableMethod(self): """ @@ -4791,8 +4808,7 @@ class IDLMethod(IDLInterfaceMember, IDLScope): self.isSetter() or self.isDeleter() or self.isLegacycaller() or - self.isStringifier() or - self.isJsonifier()) + self.isStringifier()) def isHTMLConstructor(self): return self._htmlConstructor @@ -4848,8 +4864,6 @@ class IDLMethod(IDLInterfaceMember, IDLScope): assert not method.isDeleter() assert not self.isStringifier() assert not method.isStringifier() - assert not self.isJsonifier() - assert not method.isJsonifier() assert not self.isHTMLConstructor() assert not method.isHTMLConstructor() @@ -4972,6 +4986,19 @@ class IDLMethod(IDLInterfaceMember, IDLScope): " methods on JS-implemented classes only.", [self.location]) + # Ensure that toJSON methods satisfy the spec constraints on them. + if self.identifier.name == "toJSON": + if len(self.signatures()) != 1: + raise WebIDLError("toJSON method has multiple overloads", + [self._overloads[0].location, + self._overloads[1].location]) + if len(self.signatures()[0][1]) != 0: + raise WebIDLError("toJSON method has arguments", + [self.location]) + if not self.signatures()[0][0].isJSONType(): + raise WebIDLError("toJSON method has non-JSON return type", + [self.location]) + def overloadsForArgCount(self, argc): return [overload for overload in self._overloads if len(overload.arguments) == argc or @@ -5105,6 +5132,19 @@ class IDLMethod(IDLInterfaceMember, IDLScope): raise WebIDLError("[CEReactions] is only allowed on operation, " "attribute, setter, and deleter", [attr.location, self.location]) + elif identifier == "Default": + if not attr.noArguments(): + raise WebIDLError("[Default] must take no arguments", + [attr.location]) + + if not self.isToJSON(): + raise WebIDLError("[Default] is only allowed on toJSON operations", + [attr.location, self.location]) + + if self.signatures()[0][0] != BuiltinTypes[IDLBuiltinType.Types.object]: + raise WebIDLError("The return type of the default toJSON " + "operation must be 'object'", + [attr.location, self.location]); elif (identifier == "Throws" or identifier == "CanOOM" or identifier == "NewObject" or @@ -5292,7 +5332,6 @@ class Tokenizer(object): "false": "FALSE", "serializer": "SERIALIZER", "stringifier": "STRINGIFIER", - "jsonifier": "JSONIFIER", "unrestricted": "UNRESTRICTED", "attribute": "ATTRIBUTE", "readonly": "READONLY", @@ -6123,19 +6162,6 @@ class Parser(Tokenizer): stringifier=True) p[0] = method - def p_Jsonifier(self, p): - """ - Operation : JSONIFIER SEMICOLON - """ - identifier = IDLUnresolvedIdentifier(BuiltinLocation("<auto-generated-identifier>"), - "__jsonifier", allowDoubleUnderscore=True) - method = IDLMethod(self.getLocation(p, 1), - identifier, - returnType=BuiltinTypes[IDLBuiltinType.Types.object], - arguments=[], - jsonifier=True) - p[0] = method - def p_QualifierStatic(self, p): """ Qualifier : STATIC @@ -6289,7 +6315,6 @@ class Parser(Tokenizer): | SETTER | STATIC | STRINGIFIER - | JSONIFIER | TYPEDEF | UNRESTRICTED | NAMESPACE @@ -6441,7 +6466,6 @@ class Parser(Tokenizer): | SHORT | STATIC | STRINGIFIER - | JSONIFIER | TRUE | TYPEDEF | UNSIGNED @@ -6958,9 +6982,12 @@ class Parser(Tokenizer): nextMethod.addExtendedAttributes([simpleExtendedAttr("Throws")]) itr_ident = IDLUnresolvedIdentifier(iface.location, iface.identifier.name + "Iterator") + toStringTag = iface.identifier.name + " Iterator" itr_iface = IDLInterface(iface.location, self.globalScope(), itr_ident, None, [nextMethod], - isKnownNonPartial=True) + isKnownNonPartial=True, + classNameOverride=toStringTag, + toStringTag=toStringTag) itr_iface.addExtendedAttributes([simpleExtendedAttr("NoInterfaceObject")]) # Make sure the exposure set for the iterator interface is the # same as the exposure set for the iterable interface, because diff --git a/components/script/dom/bindings/codegen/parser/abstract.patch b/components/script/dom/bindings/codegen/parser/abstract.patch index e43d12eb988..cf4c89b84d0 100644 --- a/components/script/dom/bindings/codegen/parser/abstract.patch +++ b/components/script/dom/bindings/codegen/parser/abstract.patch @@ -1,9 +1,9 @@ --- WebIDL.py +++ WebIDL.py @@ -1744,7 +1744,8 @@ - identifier == "ProbablyShortLivingWrapper" or identifier == "LegacyUnenumerableNamedProperties" or identifier == "RunConstructorInCallerCompartment" or + identifier == "WantsEventListenerHooks" or - identifier == "NonOrdinaryGetPrototypeOf"): + identifier == "NonOrdinaryGetPrototypeOf" or + identifier == "Abstract"): diff --git a/components/script/dom/bindings/codegen/parser/inline.patch b/components/script/dom/bindings/codegen/parser/inline.patch index 5d1056d2b58..028fb9345d0 100644 --- a/components/script/dom/bindings/codegen/parser/inline.patch +++ b/components/script/dom/bindings/codegen/parser/inline.patch @@ -9,4 +9,4 @@ + identifier == "Inline"): # Known extended attributes that do not take values if not attr.noArguments(): - raise WebIDLError("[%s] must take no arguments" % identifier,
\ No newline at end of file + raise WebIDLError("[%s] must take no arguments" % identifier, diff --git a/components/script/dom/bindings/codegen/parser/tests/test_cereactions.py b/components/script/dom/bindings/codegen/parser/tests/test_cereactions.py index a1e5e78630f..dba16f53302 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_cereactions.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_cereactions.py @@ -131,17 +131,3 @@ def WebIDLTest(parser, harness): harness.ok(threw, "Should have thrown for [CEReactions] used on a stringifier") - parser = parser.reset() - threw = False - try: - parser.parse(""" - interface Foo { - [CEReactions] jsonifier; - }; - """) - - results = parser.finish() - except: - threw = True - - harness.ok(threw, "Should have thrown for [CEReactions] used on a jsonifier") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_interface.py b/components/script/dom/bindings/codegen/parser/tests/test_interface.py index e8ed67b54b3..a23243abe61 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_interface.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_interface.py @@ -374,32 +374,3 @@ def WebIDLTest(parser, harness): threw = True harness.ok(threw, "Should not allow unknown extended attributes on interfaces") - - parser = parser.reset() - threw = False - try: - parser.parse(""" - interface B {}; - [ArrayClass] - interface A : B { - }; - """) - results = parser.finish() - except: - threw = True - harness.ok(threw, - "Should not allow [ArrayClass] on interfaces with parents") - - parser = parser.reset() - threw = False - try: - parser.parse(""" - [ArrayClass] - interface A { - }; - """) - results = parser.finish() - except: - threw = True - harness.ok(not threw, - "Should allow [ArrayClass] on interfaces without parents") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_toJSON.py b/components/script/dom/bindings/codegen/parser/tests/test_toJSON.py new file mode 100644 index 00000000000..b8b4f796ccb --- /dev/null +++ b/components/script/dom/bindings/codegen/parser/tests/test_toJSON.py @@ -0,0 +1,192 @@ +def WebIDLTest(parser, harness): + threw = False + try: + parser.parse( + """ + interface Test { + object toJSON(); + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(not threw, "Should allow a toJSON method.") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + interface Test { + object toJSON(object arg); + object toJSON(long arg); + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, "Should not allow overloads of a toJSON method.") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + interface Test { + object toJSON(object arg); + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, "Should not allow a toJSON method with arguments.") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + interface Test { + long toJSON(); + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(not threw, "Should allow a toJSON method with 'long' as return type.") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + interface Test { + [Default] object toJSON(); + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(not threw, "Should allow a default toJSON method with 'object' as return type.") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + interface Test { + [Default] long toJSON(); + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, "Should not allow a default toJSON method with non-'object' as return type.") + + JsonTypes = [ "byte", "octet", "short", "unsigned short", "long", "unsigned long", "long long", + "unsigned long long", "float", "unrestricted float", "double", "unrestricted double", "boolean", + "DOMString", "ByteString", "USVString", "Enum", "InterfaceWithToJSON", "object" ] + + nonJsonTypes = [ "InterfaceWithoutToJSON", "any", "Int8Array", "Int16Array", "Int32Array","Uint8Array", + "Uint16Array", "Uint32Array", "Uint8ClampedArray", "Float32Array", "Float64Array", "ArrayBuffer" ] + + def doTest(testIDL, shouldThrow, description): + p = parser.reset() + threw = False + try: + p.parse(testIDL + + """ + enum Enum { "a", "b", "c" }; + interface InterfaceWithToJSON { long toJSON(); }; + interface InterfaceWithoutToJSON {}; + """); + p.finish(); + except Exception as x: + threw = True + harness.ok(x.message == "toJSON method has non-JSON return type", x) + harness.check(threw, shouldThrow, description) + + + for type in JsonTypes: + doTest("interface Test { %s toJSON(); };" % type, False, + "%s should be a JSON type" % type) + + doTest("interface Test { sequence<%s> toJSON(); };" % type, False, + "sequence<%s> should be a JSON type" % type) + + doTest("dictionary Foo { %s foo; }; " + "interface Test { Foo toJSON(); }; " % type, False, + "dictionary containing only JSON type (%s) should be a JSON type" % type) + + doTest("dictionary Foo { %s foo; }; dictionary Bar : Foo { }; " + "interface Test { Bar toJSON(); }; " % type, False, + "dictionary whose ancestors only contain JSON types should be a JSON type") + + doTest("dictionary Foo { any foo; }; dictionary Bar : Foo { %s bar; };" + "interface Test { Bar toJSON(); };" % type, True, + "dictionary whose ancestors contain non-JSON types should not be a JSON type") + + doTest("interface Test { record<DOMString, %s> toJSON(); };" % type, False, + "record<DOMString, %s> should be a JSON type" % type) + + doTest("interface Test { record<ByteString, %s> toJSON(); };" % type, False, + "record<ByteString, %s> should be a JSON type" % type) + + doTest("interface Test { record<USVString, %s> toJSON(); };" % type, False, + "record<USVString, %s> should be a JSON type" % type) + + otherUnionType = "Foo" if type != "object" else "long" + doTest("interface Foo { object toJSON(); };" + "interface Test { (%s or %s) toJSON(); };" % (otherUnionType, type), False, + "union containing only JSON types (%s or %s) should be a JSON type" %(otherUnionType, type)) + + doTest("interface test { %s? toJSON(); };" % type, False, + "Nullable type (%s) should be a JSON type" % type) + + doTest("interface Foo : InterfaceWithoutToJSON { %s toJSON(); };" + "interface Test { Foo toJSON(); };" % type, False, + "interface with toJSON should be a JSON type") + + doTest("interface Foo : InterfaceWithToJSON { };" + "interface Test { Foo toJSON(); };", False, + "inherited interface with toJSON should be a JSON type") + + for type in nonJsonTypes: + doTest("interface Test { %s toJSON(); };" % type, True, + "%s should not be a JSON type" % type) + + doTest("interface Test { sequence<%s> toJSON(); };" % type, True, + "sequence<%s> should not be a JSON type" % type) + + doTest("dictionary Foo { %s foo; }; " + "interface Test { Foo toJSON(); }; " % type, True, + "Dictionary containing a non-JSON type (%s) should not be a JSON type" % type) + + doTest("dictionary Foo { %s foo; }; dictionary Bar : Foo { }; " + "interface Test { Bar toJSON(); }; " % type, True, + "dictionary whose ancestors only contain non-JSON types should not be a JSON type") + + doTest("interface Test { record<DOMString, %s> toJSON(); };" % type, True, + "record<DOMString, %s> should not be a JSON type" % type) + + doTest("interface Test { record<ByteString, %s> toJSON(); };" % type, True, + "record<ByteString, %s> should not be a JSON type" % type) + + doTest("interface Test { record<USVString, %s> toJSON(); };" % type, True, + "record<USVString, %s> should not be a JSON type" % type) + + if type != "any": + doTest("interface Foo { object toJSON(); }; " + "interface Test { (Foo or %s) toJSON(); };" % type, True, + "union containing a non-JSON type (%s) should not be a JSON type" % type) + + doTest("interface test { %s? toJSON(); };" % type, True, + "Nullable type (%s) should not be a JSON type" % type) + + doTest("dictionary Foo { long foo; any bar; };" + "interface Test { Foo toJSON(); };", True, + "dictionary containing a non-JSON type should not be a JSON type") + + doTest("interface Foo : InterfaceWithoutToJSON { }; " + "interface Test { Foo toJSON(); };", True, + "interface without toJSON should not be a JSON type") diff --git a/components/script/dom/canvasrenderingcontext2d.rs b/components/script/dom/canvasrenderingcontext2d.rs index 5ee0a4c2204..24d6af0282d 100644 --- a/components/script/dom/canvasrenderingcontext2d.rs +++ b/components/script/dom/canvasrenderingcontext2d.rs @@ -246,8 +246,6 @@ impl CanvasRenderingContext2D { CanvasImageSource::HTMLCanvasElement(canvas) => { canvas.origin_is_clean() } - CanvasImageSource::CanvasRenderingContext2D(image) => - image.origin_is_clean(), CanvasImageSource::HTMLImageElement(image) => { let image_origin = image.get_origin().expect("Image's origin is missing"); image_origin.same_origin(GlobalScope::entry().origin()) @@ -294,11 +292,6 @@ impl CanvasRenderingContext2D { sx, sy, sw, sh, dx, dy, dw, dh) } - CanvasImageSource::CanvasRenderingContext2D(ref image) => { - self.draw_html_canvas_element(&image.Canvas(), - sx, sy, sw, sh, - dx, dy, dw, dh) - } CanvasImageSource::HTMLImageElement(ref image) => { // https://html.spec.whatwg.org/multipage/#img-error // If the image argument is an HTMLImageElement object that is in the broken state, @@ -1216,12 +1209,6 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D { canvas.fetch_all_data().ok_or(Error::InvalidState)? }, - CanvasImageSource::CanvasRenderingContext2D(ref context) => { - let canvas = context.Canvas(); - let _ = canvas.get_or_init_2d_context(); - - canvas.fetch_all_data().ok_or(Error::InvalidState)? - } CanvasImageSource::CSSStyleValue(ref value) => { value.get_url(self.base_url.clone()) .and_then(|url| self.fetch_image_data(url)) diff --git a/components/script/dom/htmlcanvaselement.rs b/components/script/dom/htmlcanvaselement.rs index 3854b29967b..cfc1ee9a3db 100644 --- a/components/script/dom/htmlcanvaselement.rs +++ b/components/script/dom/htmlcanvaselement.rs @@ -17,7 +17,7 @@ use dom::bindings::inheritance::Castable; use dom::bindings::num::Finite; use dom::bindings::reflector::DomObject; use dom::bindings::root::{Dom, DomRoot, LayoutDom}; -use dom::bindings::str::DOMString; +use dom::bindings::str::{DOMString, USVString}; use dom::canvasrenderingcontext2d::{CanvasRenderingContext2D, LayoutCanvasRenderingContext2DHelpers}; use dom::document::Document; use dom::element::{AttributeMutation, Element, RawLayoutElementHelpers}; @@ -191,12 +191,12 @@ impl HTMLCanvasElement { pub fn get_or_init_webgl_context( &self, cx: *mut JSContext, - attrs: Option<HandleValue> + options: HandleValue, ) -> Option<DomRoot<WebGLRenderingContext>> { if self.context.borrow().is_none() { let window = window_from_node(self); let size = self.get_size(); - let attrs = Self::get_gl_attributes(cx, attrs)?; + let attrs = Self::get_gl_attributes(cx, options)?; let maybe_ctx = WebGLRenderingContext::new(&window, self, WebGLVersion::WebGL1, size, attrs); *self.context.borrow_mut() = maybe_ctx.map( |ctx| CanvasContext::WebGL(Dom::from_ref(&*ctx))); @@ -212,7 +212,7 @@ impl HTMLCanvasElement { pub fn get_or_init_webgl2_context( &self, cx: *mut JSContext, - attrs: Option<HandleValue> + options: HandleValue, ) -> Option<DomRoot<WebGL2RenderingContext>> { if !PREFS.is_webgl2_enabled() { return None @@ -220,7 +220,7 @@ impl HTMLCanvasElement { if self.context.borrow().is_none() { let window = window_from_node(self); let size = self.get_size(); - let attrs = Self::get_gl_attributes(cx, attrs)?; + let attrs = Self::get_gl_attributes(cx, options)?; let maybe_ctx = WebGL2RenderingContext::new(&window, self, size, attrs); *self.context.borrow_mut() = maybe_ctx.map( |ctx| CanvasContext::WebGL2(Dom::from_ref(&*ctx))); @@ -243,12 +243,8 @@ impl HTMLCanvasElement { } #[allow(unsafe_code)] - fn get_gl_attributes(cx: *mut JSContext, attrs: Option<HandleValue>) -> Option<GLContextAttributes> { - let webgl_attributes = match attrs { - Some(attrs) => attrs, - None => return Some(GLContextAttributes::default()), - }; - match unsafe { WebGLContextAttributes::new(cx, webgl_attributes) } { + fn get_gl_attributes(cx: *mut JSContext, options: HandleValue) -> Option<GLContextAttributes> { + match unsafe { WebGLContextAttributes::new(cx, options) } { Ok(ConversionResult::Success(ref attrs)) => Some(From::from(attrs)), Ok(ConversionResult::Failure(ref error)) => { unsafe { throw_type_error(cx, &error); } @@ -310,36 +306,39 @@ impl HTMLCanvasElementMethods for HTMLCanvasElement { // https://html.spec.whatwg.org/multipage/#dom-canvas-height make_uint_setter!(SetHeight, "height", DEFAULT_HEIGHT); - #[allow(unsafe_code)] // https://html.spec.whatwg.org/multipage/#dom-canvas-getcontext - unsafe fn GetContext(&self, - cx: *mut JSContext, - id: DOMString, - attributes: Vec<HandleValue>) - -> Option<RenderingContext> { + #[allow(unsafe_code)] + unsafe fn GetContext( + &self, + cx: *mut JSContext, + id: DOMString, + options: HandleValue, + ) -> Option<RenderingContext> { match &*id { "2d" => { self.get_or_init_2d_context() .map(RenderingContext::CanvasRenderingContext2D) } "webgl" | "experimental-webgl" => { - self.get_or_init_webgl_context(cx, attributes.get(0).cloned()) + self.get_or_init_webgl_context(cx, options) .map(RenderingContext::WebGLRenderingContext) } "webgl2" | "experimental-webgl2" => { - self.get_or_init_webgl2_context(cx, attributes.get(0).cloned()) + self.get_or_init_webgl2_context(cx, options) .map(RenderingContext::WebGL2RenderingContext) } _ => None } } - #[allow(unsafe_code)] // https://html.spec.whatwg.org/multipage/#dom-canvas-todataurl - unsafe fn ToDataURL(&self, - _context: *mut JSContext, - _mime_type: Option<DOMString>, - _arguments: Vec<HandleValue>) -> Fallible<DOMString> { + #[allow(unsafe_code)] + unsafe fn ToDataURL( + &self, + _context: *mut JSContext, + _mime_type: Option<DOMString>, + _quality: HandleValue, + ) -> Fallible<USVString> { // Step 1. if let Some(CanvasContext::Context2d(ref context)) = *self.context.borrow() { if !context.origin_is_clean() { @@ -349,7 +348,7 @@ impl HTMLCanvasElementMethods for HTMLCanvasElement { // Step 2. if self.Width() == 0 || self.Height() == 0 { - return Ok(DOMString::from("data:,")); + return Ok(USVString("data:,".into())); } // Step 3. @@ -363,13 +362,13 @@ impl HTMLCanvasElementMethods for HTMLCanvasElement { Some(CanvasContext::WebGL(ref context)) => { match context.get_image_data(self.Width(), self.Height()) { Some(data) => data, - None => return Ok("data:,".into()), + None => return Ok(USVString("data:,".into())), } } Some(CanvasContext::WebGL2(ref context)) => { match context.base_context().get_image_data(self.Width(), self.Height()) { Some(data) => data, - None => return Ok("data:,".into()), + None => return Ok(USVString("data:,".into())), } } None => { @@ -388,7 +387,7 @@ impl HTMLCanvasElementMethods for HTMLCanvasElement { } let encoded = base64::encode(&encoded); - Ok(DOMString::from(format!("data:{};base64,{}", mime_type, encoded))) + Ok(USVString(format!("data:{};base64,{}", mime_type, encoded))) } } diff --git a/components/script/dom/paintrenderingcontext2d.rs b/components/script/dom/paintrenderingcontext2d.rs index 7413a37454e..49bf0da6024 100644 --- a/components/script/dom/paintrenderingcontext2d.rs +++ b/components/script/dom/paintrenderingcontext2d.rs @@ -6,12 +6,12 @@ use canvas_traits::canvas::CanvasImageData; use canvas_traits::canvas::CanvasMsg; use canvas_traits::canvas::FromLayoutMsg; use dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasFillRule; +use dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasImageSource; use dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasLineCap; use dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasLineJoin; use dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasRenderingContext2DMethods; use dom::bindings::codegen::Bindings::PaintRenderingContext2DBinding; use dom::bindings::codegen::Bindings::PaintRenderingContext2DBinding::PaintRenderingContext2DMethods; -use dom::bindings::codegen::UnionTypes::HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2DOrCSSStyleValue; use dom::bindings::codegen::UnionTypes::StringOrCanvasGradientOrCanvasPattern; use dom::bindings::error::ErrorResult; use dom::bindings::error::Fallible; @@ -194,37 +194,40 @@ impl PaintRenderingContext2DMethods for PaintRenderingContext2D { } // https://html.spec.whatwg.org/multipage/#dom-context-2d-drawimage - fn DrawImage(&self, - image: HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2DOrCSSStyleValue, - dx: f64, - dy: f64) - -> ErrorResult { + fn DrawImage( + &self, + image: CanvasImageSource, + dx: f64, + dy: f64, + ) -> ErrorResult { self.context.DrawImage(image, dx, dy) } // https://html.spec.whatwg.org/multipage/#dom-context-2d-drawimage - fn DrawImage_(&self, - image: HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2DOrCSSStyleValue, - dx: f64, - dy: f64, - dw: f64, - dh: f64) - -> ErrorResult { + fn DrawImage_( + &self, + image: CanvasImageSource, + dx: f64, + dy: f64, + dw: f64, + dh: f64, + ) -> ErrorResult { self.context.DrawImage_(image, dx, dy, dw, dh) } // https://html.spec.whatwg.org/multipage/#dom-context-2d-drawimage - fn DrawImage__(&self, - image: HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2DOrCSSStyleValue, - sx: f64, - sy: f64, - sw: f64, - sh: f64, - dx: f64, - dy: f64, - dw: f64, - dh: f64) - -> ErrorResult { + fn DrawImage__( + &self, + image: CanvasImageSource, + sx: f64, + sy: f64, + sw: f64, + sh: f64, + dx: f64, + dy: f64, + dw: f64, + dh: f64, + ) -> ErrorResult { self.context.DrawImage__(image, sx, sy, sw, sh, dx, dy, dw, dh) } @@ -321,10 +324,11 @@ impl PaintRenderingContext2DMethods for PaintRenderingContext2D { } // https://html.spec.whatwg.org/multipage/#dom-context-2d-createpattern - fn CreatePattern(&self, - image: HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2DOrCSSStyleValue, - repetition: DOMString) - -> Fallible<DomRoot<CanvasPattern>> { + fn CreatePattern( + &self, + image: CanvasImageSource, + repetition: DOMString, + ) -> Fallible<DomRoot<CanvasPattern>> { self.context.CreatePattern(image, repetition) } diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index eb7be0019e9..2f3df2adb7c 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -540,8 +540,10 @@ impl WebGLRenderingContext { return Err(()); } }, - ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement::HTMLVideoElement(_rooted_video) - => unimplemented!(), + ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement::HTMLVideoElement(_) => { + // TODO: https://github.com/servo/servo/issues/6711 + return Err(()); + } }; return Ok((pixels, size, premultiplied)); diff --git a/components/script/dom/webidls/CanvasRenderingContext2D.webidl b/components/script/dom/webidls/CanvasRenderingContext2D.webidl index ccf637865cb..a27cc600e40 100644 --- a/components/script/dom/webidls/CanvasRenderingContext2D.webidl +++ b/components/script/dom/webidls/CanvasRenderingContext2D.webidl @@ -2,30 +2,25 @@ * 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/. */ -enum CanvasFillRule { "nonzero", "evenodd" }; - // https://html.spec.whatwg.org/multipage/#2dcontext -typedef (HTMLImageElement or - /* HTMLVideoElement or */ + +// typedef (HTMLImageElement or +// SVGImageElement) HTMLOrSVGImageElement; +typedef HTMLImageElement HTMLOrSVGImageElement; + +typedef (HTMLOrSVGImageElement or + /*HTMLVideoElement or*/ HTMLCanvasElement or - CanvasRenderingContext2D or - /* ImageBitmap or */ - // This should probably be a CSSImageValue - // https://github.com/w3c/css-houdini-drafts/issues/416 - CSSStyleValue) CanvasImageSource; + /*ImageBitmap or*/ + /*OffscreenCanvas or*/ + /*CSSImageValue*/ CSSStyleValue) CanvasImageSource; -//[Constructor(optional unsigned long width, unsigned long height)] -interface CanvasRenderingContext2D { +enum CanvasFillRule { "nonzero", "evenodd" }; +[Exposed=Window] +interface CanvasRenderingContext2D { // back-reference to the canvas readonly attribute HTMLCanvasElement canvas; - - // canvas dimensions - // attribute unsigned long width; - // attribute unsigned long height; - - // for contexts that aren't directly fixed to a specific canvas - //void commit(); // push the image to the output bitmap }; CanvasRenderingContext2D implements CanvasState; CanvasRenderingContext2D implements CanvasTransform; @@ -33,25 +28,25 @@ CanvasRenderingContext2D implements CanvasCompositing; CanvasRenderingContext2D implements CanvasImageSmoothing; CanvasRenderingContext2D implements CanvasFillStrokeStyles; CanvasRenderingContext2D implements CanvasShadowStyles; +CanvasRenderingContext2D implements CanvasFilters; CanvasRenderingContext2D implements CanvasRect; CanvasRenderingContext2D implements CanvasDrawPath; CanvasRenderingContext2D implements CanvasUserInterface; CanvasRenderingContext2D implements CanvasText; CanvasRenderingContext2D implements CanvasDrawImage; -CanvasRenderingContext2D implements CanvasHitRegion; CanvasRenderingContext2D implements CanvasImageData; CanvasRenderingContext2D implements CanvasPathDrawingStyles; CanvasRenderingContext2D implements CanvasTextDrawingStyles; CanvasRenderingContext2D implements CanvasPath; -[NoInterfaceObject, Exposed=(Window, PaintWorklet)] +[Exposed=(PaintWorklet, Window), NoInterfaceObject] interface CanvasState { // state void save(); // push state on state stack void restore(); // pop state stack and restore state }; -[NoInterfaceObject, Exposed=(Window, PaintWorklet)] +[Exposed=(PaintWorklet, Window), NoInterfaceObject] interface CanvasTransform { // transformations (default transform is the identity matrix) void scale(unrestricted double x, unrestricted double y); @@ -75,23 +70,22 @@ interface CanvasTransform { void resetTransform(); }; -[NoInterfaceObject, Exposed=(Window, PaintWorklet)] +[Exposed=(PaintWorklet, Window), NoInterfaceObject] interface CanvasCompositing { // compositing attribute unrestricted double globalAlpha; // (default 1.0) attribute DOMString globalCompositeOperation; // (default source-over) }; -[NoInterfaceObject, Exposed=(Window, PaintWorklet)] +[Exposed=(PaintWorklet, Window), NoInterfaceObject] interface CanvasImageSmoothing { // image smoothing attribute boolean imageSmoothingEnabled; // (default true) // attribute ImageSmoothingQuality imageSmoothingQuality; // (default low) }; -[NoInterfaceObject, Exposed=(Window, PaintWorklet)] +[Exposed=(PaintWorklet, Window), NoInterfaceObject] interface CanvasFillStrokeStyles { - // colours and styles (see also the CanvasDrawingStyles interface) attribute (DOMString or CanvasGradient or CanvasPattern) strokeStyle; // (default black) attribute (DOMString or CanvasGradient or CanvasPattern) fillStyle; // (default black) @@ -102,7 +96,7 @@ interface CanvasFillStrokeStyles { CanvasPattern createPattern(CanvasImageSource image, [TreatNullAs=EmptyString] DOMString repetition); }; -[NoInterfaceObject, Exposed=(Window, PaintWorklet)] +[Exposed=(PaintWorklet, Window), NoInterfaceObject] interface CanvasShadowStyles { // shadows attribute unrestricted double shadowOffsetX; // (default 0) @@ -111,32 +105,30 @@ interface CanvasShadowStyles { attribute DOMString shadowColor; // (default transparent black) }; -[NoInterfaceObject, Exposed=(Window, PaintWorklet)] +[Exposed=(PaintWorklet, Window), NoInterfaceObject] +interface CanvasFilters { + // filters + //attribute DOMString filter; // (default "none") +}; + +[Exposed=(PaintWorklet, Window), NoInterfaceObject] interface CanvasRect { // rects - //[LenientFloat] void clearRect(unrestricted double x, unrestricted double y, unrestricted double w, unrestricted double h); - //[LenientFloat] void fillRect(unrestricted double x, unrestricted double y, unrestricted double w, unrestricted double h); - //[LenientFloat] void strokeRect(unrestricted double x, unrestricted double y, unrestricted double w, unrestricted double h); }; -[NoInterfaceObject, Exposed=(Window, PaintWorklet)] +[Exposed=(PaintWorklet, Window), NoInterfaceObject] interface CanvasDrawPath { - // path API (see also CanvasPathMethods) + // path API (see also CanvasPath) void beginPath(); void fill(optional CanvasFillRule fillRule = "nonzero"); //void fill(Path2D path, optional CanvasFillRule fillRule = "nonzero"); void stroke(); //void stroke(Path2D path); - //void drawFocusIfNeeded(Element element); - //void drawFocusIfNeeded(Path2D path, Element element); - //void scrollPathIntoView(); - //void scrollPathIntoView(Path2D path); void clip(optional CanvasFillRule fillRule = "nonzero"); //void clip(Path2D path, optional CanvasFillRule fillRule = "nonzero"); - //void resetClip(); boolean isPointInPath(unrestricted double x, unrestricted double y, optional CanvasFillRule fillRule = "nonzero"); //boolean isPointInPath(Path2D path, unrestricted double x, unrestricted double y, @@ -145,14 +137,17 @@ interface CanvasDrawPath { //boolean isPointInStroke(Path2D path, unrestricted double x, unrestricted double y); }; -[NoInterfaceObject] +[Exposed=(PaintWorklet, Window), NoInterfaceObject] interface CanvasUserInterface { - // TODO? + //void drawFocusIfNeeded(Element element); + //void drawFocusIfNeeded(Path2D path, Element element); + //void scrollPathIntoView(); + //void scrollPathIntoView(Path2D path); }; -[NoInterfaceObject] +[Exposed=(PaintWorklet, Window), NoInterfaceObject] interface CanvasText { - // text (see also the CanvasDrawingStyles interface) + // text (see also the CanvasPathDrawingStyles and CanvasTextDrawingStyles interfaces) [Pref="dom.canvas-text.enabled"] void fillText(DOMString text, unrestricted double x, unrestricted double y, optional unrestricted double maxWidth); @@ -161,7 +156,7 @@ interface CanvasText { //TextMetrics measureText(DOMString text); }; -[NoInterfaceObject, Exposed=(Window, PaintWorklet)] +[Exposed=(PaintWorklet, Window), NoInterfaceObject] interface CanvasDrawImage { // drawing images [Throws] @@ -176,15 +171,7 @@ interface CanvasDrawImage { unrestricted double dw, unrestricted double dh); }; -[NoInterfaceObject] -interface CanvasHitRegion { - // hit regions - //void addHitRegion(optional HitRegionOptions options); - //void removeHitRegion(DOMString id); - //void clearHitRegions(); -}; - -[NoInterfaceObject] +[Exposed=Window, NoInterfaceObject] interface CanvasImageData { // pixel manipulation [Throws] @@ -199,9 +186,6 @@ interface CanvasImageData { double dirtyX, double dirtyY, double dirtyWidth, double dirtyHeight); }; -CanvasRenderingContext2D implements CanvasPathDrawingStyles; -CanvasRenderingContext2D implements CanvasTextDrawingStyles; -CanvasRenderingContext2D implements CanvasPath; enum CanvasLineCap { "butt", "round", "square" }; enum CanvasLineJoin { "round", "bevel", "miter"}; @@ -209,12 +193,12 @@ enum CanvasTextAlign { "start", "end", "left", "right", "center" }; enum CanvasTextBaseline { "top", "hanging", "middle", "alphabetic", "ideographic", "bottom" }; enum CanvasDirection { "ltr", "rtl", "inherit" }; -[NoInterfaceObject, Exposed=(Window, PaintWorklet)] +[Exposed=(PaintWorklet, Window), NoInterfaceObject] interface CanvasPathDrawingStyles { // line caps/joins attribute unrestricted double lineWidth; // (default 1) - attribute CanvasLineCap lineCap; // "butt", "round", "square" (default "butt") - attribute CanvasLineJoin lineJoin; // "round", "bevel", "miter" (default "miter") + attribute CanvasLineCap lineCap; // (default "butt") + attribute CanvasLineJoin lineJoin; // (default "miter") attribute unrestricted double miterLimit; // (default 10) // dashed lines @@ -223,7 +207,7 @@ interface CanvasPathDrawingStyles { //attribute unrestricted double lineDashOffset; }; -[NoInterfaceObject] +[Exposed=(PaintWorklet, Window), NoInterfaceObject] interface CanvasTextDrawingStyles { // text //attribute DOMString font; // (default 10px sans-serif) @@ -233,7 +217,7 @@ interface CanvasTextDrawingStyles { //attribute CanvasDirection direction; // "ltr", "rtl", "inherit" (default: "inherit") }; -[NoInterfaceObject, Exposed=(Window, Worker, PaintWorklet)] +[Exposed=(PaintWorklet, Window), NoInterfaceObject] interface CanvasPath { // shared path API methods void closePath(); @@ -253,17 +237,12 @@ interface CanvasPath { void arcTo(unrestricted double x1, unrestricted double y1, unrestricted double x2, unrestricted double y2, unrestricted double radius); - // [LenientFloat] void arcTo(double x1, double y1, double x2, double y2, - // double radiusX, double radiusY, double rotation); void rect(unrestricted double x, unrestricted double y, unrestricted double w, unrestricted double h); [Throws] void arc(unrestricted double x, unrestricted double y, unrestricted double radius, unrestricted double startAngle, unrestricted double endAngle, optional boolean anticlockwise = false); - // [LenientFloat] void ellipse(double x, double y, double radiusX, double radiusY, - // double rotation, double startAngle, double endAngle, - // boolean anticlockwise); [Throws] void ellipse(unrestricted double x, unrestricted double y, unrestricted double radius_x, diff --git a/components/script/dom/webidls/HTMLCanvasElement.webidl b/components/script/dom/webidls/HTMLCanvasElement.webidl index f5826c34fd2..ea2bb737e95 100644 --- a/components/script/dom/webidls/HTMLCanvasElement.webidl +++ b/components/script/dom/webidls/HTMLCanvasElement.webidl @@ -5,20 +5,18 @@ // https://html.spec.whatwg.org/multipage/#htmlcanvaselement typedef (CanvasRenderingContext2D or WebGLRenderingContext or WebGL2RenderingContext) RenderingContext; -[HTMLConstructor] +[Exposed=Window, + HTMLConstructor] interface HTMLCanvasElement : HTMLElement { - [CEReactions, Pure] - attribute unsigned long width; - [CEReactions, Pure] - attribute unsigned long height; + [CEReactions, Pure] attribute unsigned long width; + [CEReactions, Pure] attribute unsigned long height; - RenderingContext? getContext(DOMString contextId, any... arguments); - //boolean probablySupportsContext(DOMString contextId, any... arguments); - - //void setContext(RenderingContext context); - //CanvasProxy transferControlToProxy(); + RenderingContext? getContext(DOMString contextId, optional any options = null); [Throws] - DOMString toDataURL(optional DOMString type, any... arguments); - //void toBlob(FileCallback? _callback, optional DOMString type, any... arguments); + USVString toDataURL(optional DOMString type, optional any quality); + //void toBlob(BlobCallback _callback, optional DOMString type, optional any quality); + //OffscreenCanvas transferControlToOffscreen(); }; + +//callback BlobCallback = void (Blob? blob); |