Auto merge of #21711 - servo:webgl, r=jdm

Some fixes to canvas stuff

<!-- Reviewable:start -->
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/21711)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2018-09-14 21:09:05 -04:00 committed by GitHub
commit 0ecd671f52
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 404 additions and 262 deletions

View file

@ -729,7 +729,7 @@ fn crop_image(
/// smoothing_enabled: It determines if smoothing is applied to the image result /// smoothing_enabled: It determines if smoothing is applied to the image result
fn write_image( fn write_image(
draw_target: &DrawTarget, draw_target: &DrawTarget,
mut image_data: Vec<u8>, image_data: Vec<u8>,
image_size: Size2D<f64>, image_size: Size2D<f64>,
dest_rect: Rect<f64>, dest_rect: Rect<f64>,
smoothing_enabled: bool, smoothing_enabled: bool,
@ -740,8 +740,6 @@ fn write_image(
return return
} }
let image_rect = Rect::new(Point2D::zero(), image_size); let image_rect = Rect::new(Point2D::zero(), image_size);
// rgba -> bgra
byte_swap(&mut image_data);
// From spec https://html.spec.whatwg.org/multipage/#dom-context-2d-drawimage // From spec https://html.spec.whatwg.org/multipage/#dom-context-2d-drawimage
// When scaling up, if the imageSmoothingEnabled attribute is set to true, the user agent should attempt // When scaling up, if the imageSmoothingEnabled attribute is set to true, the user agent should attempt

View file

@ -132,12 +132,13 @@ impl<'a> CanvasPaintThread <'a> {
self.canvas(canvas_id).is_point_in_path(x, y, fill_rule, chan) self.canvas(canvas_id).is_point_in_path(x, y, fill_rule, chan)
}, },
Canvas2dMsg::DrawImage( Canvas2dMsg::DrawImage(
imagedata, mut imagedata,
image_size, image_size,
dest_rect, dest_rect,
source_rect, source_rect,
smoothing_enabled, smoothing_enabled,
) => { ) => {
byte_swap(&mut imagedata);
self.canvas(canvas_id).draw_image( self.canvas(canvas_id).draw_image(
imagedata.into(), imagedata.into(),
image_size, image_size,
@ -169,8 +170,6 @@ impl<'a> CanvasPaintThread <'a> {
let mut image_data = self.canvas(canvas_id).read_pixels( let mut image_data = self.canvas(canvas_id).read_pixels(
source_rect.to_i32(), source_rect.to_i32(),
image_size); image_size);
// TODO: avoid double byte_swap.
byte_swap(&mut image_data);
self.canvas(other_canvas_id).draw_image( self.canvas(other_canvas_id).draw_image(
image_data.into(), image_data.into(),
source_rect.size, source_rect.size,

View file

@ -684,7 +684,7 @@ def globalNameSetToExposureSet(globalScope, nameSet, exposureSet):
class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins):
def __init__(self, location, parentScope, name, parent, members, def __init__(self, location, parentScope, name, parent, members,
isKnownNonPartial): isKnownNonPartial, toStringTag):
assert isinstance(parentScope, IDLScope) assert isinstance(parentScope, IDLScope)
assert isinstance(name, IDLUnresolvedIdentifier) assert isinstance(name, IDLUnresolvedIdentifier)
assert isKnownNonPartial or not parent assert isKnownNonPartial or not parent
@ -722,6 +722,8 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins):
# interface we're iterating for in order to get its nativeType. # interface we're iterating for in order to get its nativeType.
self.iterableInterface = None self.iterableInterface = None
self.toStringTag = toStringTag
IDLObjectWithScope.__init__(self, location, parentScope, name) IDLObjectWithScope.__init__(self, location, parentScope, name)
IDLExposureMixins.__init__(self, location) IDLExposureMixins.__init__(self, location)
@ -1017,10 +1019,9 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins):
[self.location]) [self.location])
for m in self.members: for m in self.members:
if ((m.isMethod() and m.isJsonifier()) or if m.identifier.name == "toJSON":
m.identifier.name == "toJSON"):
raise WebIDLError("Unforgeable interface %s has a " 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, "one ourselves" % self.identifier.name,
[self.location, m.location]) [self.location, m.location])
@ -1044,6 +1045,12 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins):
(member.getExtendedAttribute("StoreInSlot") or (member.getExtendedAttribute("StoreInSlot") or
member.getExtendedAttribute("Cached"))) or member.getExtendedAttribute("Cached"))) or
member.isMaplikeOrSetlike()): 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: if member.slotIndices is None:
member.slotIndices = dict() member.slotIndices = dict()
member.slotIndices[self.identifier.name] = self.totalMembersInSlots member.slotIndices[self.identifier.name] = self.totalMembersInSlots
@ -1115,15 +1122,12 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins):
memberType = "deleters" memberType = "deleters"
elif member.isStringifier(): elif member.isStringifier():
memberType = "stringifiers" memberType = "stringifiers"
elif member.isJsonifier():
memberType = "jsonifiers"
elif member.isLegacycaller(): elif member.isLegacycaller():
memberType = "legacycallers" memberType = "legacycallers"
else: else:
continue continue
if (memberType != "stringifiers" and memberType != "legacycallers" and if (memberType != "stringifiers" and memberType != "legacycallers"):
memberType != "jsonifiers"):
if member.isNamed(): if member.isNamed():
memberType = "named " + memberType memberType = "named " + memberType
else: else:
@ -1573,9 +1577,12 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins):
class IDLInterface(IDLInterfaceOrNamespace): class IDLInterface(IDLInterfaceOrNamespace):
def __init__(self, location, parentScope, name, parent, members, def __init__(self, location, parentScope, name, parent, members,
isKnownNonPartial): isKnownNonPartial, classNameOverride=None,
toStringTag=None):
IDLInterfaceOrNamespace.__init__(self, location, parentScope, name, IDLInterfaceOrNamespace.__init__(self, location, parentScope, name,
parent, members, isKnownNonPartial) parent, members, isKnownNonPartial,
toStringTag)
self.classNameOverride = classNameOverride
def __str__(self): def __str__(self):
return "Interface '%s'" % self.identifier.name return "Interface '%s'" % self.identifier.name
@ -1583,6 +1590,11 @@ class IDLInterface(IDLInterfaceOrNamespace):
def isInterface(self): def isInterface(self):
return True return True
def getClassName(self):
if self.classNameOverride:
return self.classNameOverride
return self.identifier.name
def addExtendedAttributes(self, attrs): def addExtendedAttributes(self, attrs):
for attr in attrs: for attr in attrs:
identifier = attr.identifier() identifier = attr.identifier()
@ -1677,14 +1689,6 @@ class IDLInterface(IDLInterfaceOrNamespace):
elif newMethod not in self.namedConstructors: elif newMethod not in self.namedConstructors:
raise WebIDLError("NamedConstructor conflicts with a NamedConstructor of a different interface", raise WebIDLError("NamedConstructor conflicts with a NamedConstructor of a different interface",
[method.location, newMethod.location]) [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"): elif (identifier == "ExceptionClass"):
if not attr.noArguments(): if not attr.noArguments():
raise WebIDLError("[ExceptionClass] must take no arguments", raise WebIDLError("[ExceptionClass] must take no arguments",
@ -1738,6 +1742,7 @@ class IDLInterface(IDLInterfaceOrNamespace):
identifier == "ProbablyShortLivingWrapper" or identifier == "ProbablyShortLivingWrapper" or
identifier == "LegacyUnenumerableNamedProperties" or identifier == "LegacyUnenumerableNamedProperties" or
identifier == "RunConstructorInCallerCompartment" or identifier == "RunConstructorInCallerCompartment" or
identifier == "WantsEventListenerHooks" or
identifier == "NonOrdinaryGetPrototypeOf" or identifier == "NonOrdinaryGetPrototypeOf" or
identifier == "Abstract" or identifier == "Abstract" or
identifier == "Inline"): identifier == "Inline"):
@ -1769,7 +1774,8 @@ class IDLInterface(IDLInterfaceOrNamespace):
class IDLNamespace(IDLInterfaceOrNamespace): class IDLNamespace(IDLInterfaceOrNamespace):
def __init__(self, location, parentScope, name, members, isKnownNonPartial): def __init__(self, location, parentScope, name, members, isKnownNonPartial):
IDLInterfaceOrNamespace.__init__(self, location, parentScope, name, IDLInterfaceOrNamespace.__init__(self, location, parentScope, name,
None, members, isKnownNonPartial) None, members, isKnownNonPartial,
toStringTag=None)
def __str__(self): def __str__(self):
return "Namespace '%s'" % self.identifier.name return "Namespace '%s'" % self.identifier.name
@ -2152,7 +2158,7 @@ class IDLType(IDLObject):
# Should only call this on float types # Should only call this on float types
assert self.isFloat() assert self.isFloat()
def isSerializable(self): def isJSONType(self):
return False return False
def tag(self): def tag(self):
@ -2350,8 +2356,8 @@ class IDLNullableType(IDLParametrizedType):
def isUnion(self): def isUnion(self):
return self.inner.isUnion() return self.inner.isUnion()
def isSerializable(self): def isJSONType(self):
return self.inner.isSerializable() return self.inner.isJSONType()
def tag(self): def tag(self):
return self.inner.tag() return self.inner.tag()
@ -2430,8 +2436,8 @@ class IDLSequenceType(IDLParametrizedType):
def isEnum(self): def isEnum(self):
return False return False
def isSerializable(self): def isJSONType(self):
return self.inner.isSerializable() return self.inner.isJSONType()
def tag(self): def tag(self):
return IDLType.Tags.sequence return IDLType.Tags.sequence
@ -2476,6 +2482,9 @@ class IDLRecordType(IDLParametrizedType):
def isRecord(self): def isRecord(self):
return True return True
def isJSONType(self):
return self.inner.isJSONType()
def tag(self): def tag(self):
return IDLType.Tags.record return IDLType.Tags.record
@ -2525,8 +2534,8 @@ class IDLUnionType(IDLType):
def isUnion(self): def isUnion(self):
return True return True
def isSerializable(self): def isJSONType(self):
return all(m.isSerializable() for m in self.memberTypes) return all(m.isJSONType() for m in self.memberTypes)
def includesRestrictedFloat(self): def includesRestrictedFloat(self):
return any(t.includesRestrictedFloat() for t in self.memberTypes) return any(t.includesRestrictedFloat() for t in self.memberTypes)
@ -2676,6 +2685,9 @@ class IDLTypedefType(IDLType):
def isVoid(self): def isVoid(self):
return self.inner.isVoid() return self.inner.isVoid()
def isJSONType(self):
return self.inner.isJSONType()
def isSequence(self): def isSequence(self):
return self.inner.isSequence() return self.inner.isSequence()
@ -2817,15 +2829,25 @@ class IDLWrapperType(IDLType):
def isEnum(self): def isEnum(self):
return isinstance(self.inner, IDLEnum) return isinstance(self.inner, IDLEnum)
def isSerializable(self): def isJSONType(self):
if self.isInterface(): if self.isInterface():
if self.inner.isExternal(): if self.inner.isExternal():
return False 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(): elif self.isEnum():
return True return True
elif self.isDictionary(): 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: else:
raise WebIDLError("IDLWrapperType wraps type %s that we don't know if " raise WebIDLError("IDLWrapperType wraps type %s that we don't know if "
"is serializable" % type(self.inner), [self.location]) "is serializable" % type(self.inner), [self.location])
@ -3111,8 +3133,8 @@ class IDLBuiltinType(IDLType):
return (self._typeTag == IDLBuiltinType.Types.unrestricted_float or return (self._typeTag == IDLBuiltinType.Types.unrestricted_float or
self._typeTag == IDLBuiltinType.Types.unrestricted_double) self._typeTag == IDLBuiltinType.Types.unrestricted_double)
def isSerializable(self): def isJSONType(self):
return self.isPrimitive() or self.isString() or self.isDate() return self.isPrimitive() or self.isString() or self.isObject()
def includesRestrictedFloat(self): def includesRestrictedFloat(self):
return self.isFloat() and not self.isUnrestricted() return self.isFloat() and not self.isUnrestricted()
@ -4665,7 +4687,7 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
def __init__(self, location, identifier, returnType, arguments, def __init__(self, location, identifier, returnType, arguments,
static=False, getter=False, setter=False, static=False, getter=False, setter=False,
deleter=False, specialType=NamedOrIndexed.Neither, deleter=False, specialType=NamedOrIndexed.Neither,
legacycaller=False, stringifier=False, jsonifier=False, legacycaller=False, stringifier=False,
maplikeOrSetlikeOrIterable=None, htmlConstructor=False): maplikeOrSetlikeOrIterable=None, htmlConstructor=False):
# REVIEW: specialType is NamedOrIndexed -- wow, this is messed up. # REVIEW: specialType is NamedOrIndexed -- wow, this is messed up.
IDLInterfaceMember.__init__(self, location, identifier, IDLInterfaceMember.__init__(self, location, identifier,
@ -4690,8 +4712,6 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
self._legacycaller = legacycaller self._legacycaller = legacycaller
assert isinstance(stringifier, bool) assert isinstance(stringifier, bool)
self._stringifier = stringifier self._stringifier = stringifier
assert isinstance(jsonifier, bool)
self._jsonifier = jsonifier
assert maplikeOrSetlikeOrIterable is None or isinstance(maplikeOrSetlikeOrIterable, IDLMaplikeOrSetlikeOrIterableBase) assert maplikeOrSetlikeOrIterable is None or isinstance(maplikeOrSetlikeOrIterable, IDLMaplikeOrSetlikeOrIterableBase)
self.maplikeOrSetlikeOrIterable = maplikeOrSetlikeOrIterable self.maplikeOrSetlikeOrIterable = maplikeOrSetlikeOrIterable
assert isinstance(htmlConstructor, bool) assert isinstance(htmlConstructor, bool)
@ -4739,12 +4759,6 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
assert len(overload.arguments) == 0 assert len(overload.arguments) == 0
assert overload.returnType == BuiltinTypes[IDLBuiltinType.Types.domstring] 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): def isStatic(self):
return self._static return self._static
@ -4776,8 +4790,11 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
def isStringifier(self): def isStringifier(self):
return self._stringifier return self._stringifier
def isJsonifier(self): def isToJSON(self):
return self._jsonifier return self.identifier.name == "toJSON"
def isDefaultToJSON(self):
return self.isToJSON() and self.getExtendedAttribute("Default")
def isMaplikeOrSetlikeOrIterableMethod(self): def isMaplikeOrSetlikeOrIterableMethod(self):
""" """
@ -4791,8 +4808,7 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
self.isSetter() or self.isSetter() or
self.isDeleter() or self.isDeleter() or
self.isLegacycaller() or self.isLegacycaller() or
self.isStringifier() or self.isStringifier())
self.isJsonifier())
def isHTMLConstructor(self): def isHTMLConstructor(self):
return self._htmlConstructor return self._htmlConstructor
@ -4848,8 +4864,6 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
assert not method.isDeleter() assert not method.isDeleter()
assert not self.isStringifier() assert not self.isStringifier()
assert not method.isStringifier() assert not method.isStringifier()
assert not self.isJsonifier()
assert not method.isJsonifier()
assert not self.isHTMLConstructor() assert not self.isHTMLConstructor()
assert not method.isHTMLConstructor() assert not method.isHTMLConstructor()
@ -4972,6 +4986,19 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
" methods on JS-implemented classes only.", " methods on JS-implemented classes only.",
[self.location]) [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): def overloadsForArgCount(self, argc):
return [overload for overload in self._overloads if return [overload for overload in self._overloads if
len(overload.arguments) == argc or len(overload.arguments) == argc or
@ -5105,6 +5132,19 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
raise WebIDLError("[CEReactions] is only allowed on operation, " raise WebIDLError("[CEReactions] is only allowed on operation, "
"attribute, setter, and deleter", "attribute, setter, and deleter",
[attr.location, self.location]) [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 elif (identifier == "Throws" or
identifier == "CanOOM" or identifier == "CanOOM" or
identifier == "NewObject" or identifier == "NewObject" or
@ -5292,7 +5332,6 @@ class Tokenizer(object):
"false": "FALSE", "false": "FALSE",
"serializer": "SERIALIZER", "serializer": "SERIALIZER",
"stringifier": "STRINGIFIER", "stringifier": "STRINGIFIER",
"jsonifier": "JSONIFIER",
"unrestricted": "UNRESTRICTED", "unrestricted": "UNRESTRICTED",
"attribute": "ATTRIBUTE", "attribute": "ATTRIBUTE",
"readonly": "READONLY", "readonly": "READONLY",
@ -6123,19 +6162,6 @@ class Parser(Tokenizer):
stringifier=True) stringifier=True)
p[0] = method 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): def p_QualifierStatic(self, p):
""" """
Qualifier : STATIC Qualifier : STATIC
@ -6289,7 +6315,6 @@ class Parser(Tokenizer):
| SETTER | SETTER
| STATIC | STATIC
| STRINGIFIER | STRINGIFIER
| JSONIFIER
| TYPEDEF | TYPEDEF
| UNRESTRICTED | UNRESTRICTED
| NAMESPACE | NAMESPACE
@ -6441,7 +6466,6 @@ class Parser(Tokenizer):
| SHORT | SHORT
| STATIC | STATIC
| STRINGIFIER | STRINGIFIER
| JSONIFIER
| TRUE | TRUE
| TYPEDEF | TYPEDEF
| UNSIGNED | UNSIGNED
@ -6958,9 +6982,12 @@ class Parser(Tokenizer):
nextMethod.addExtendedAttributes([simpleExtendedAttr("Throws")]) nextMethod.addExtendedAttributes([simpleExtendedAttr("Throws")])
itr_ident = IDLUnresolvedIdentifier(iface.location, itr_ident = IDLUnresolvedIdentifier(iface.location,
iface.identifier.name + "Iterator") iface.identifier.name + "Iterator")
toStringTag = iface.identifier.name + " Iterator"
itr_iface = IDLInterface(iface.location, self.globalScope(), itr_iface = IDLInterface(iface.location, self.globalScope(),
itr_ident, None, [nextMethod], itr_ident, None, [nextMethod],
isKnownNonPartial=True) isKnownNonPartial=True,
classNameOverride=toStringTag,
toStringTag=toStringTag)
itr_iface.addExtendedAttributes([simpleExtendedAttr("NoInterfaceObject")]) itr_iface.addExtendedAttributes([simpleExtendedAttr("NoInterfaceObject")])
# Make sure the exposure set for the iterator interface is the # Make sure the exposure set for the iterator interface is the
# same as the exposure set for the iterable interface, because # same as the exposure set for the iterable interface, because

View file

@ -1,9 +1,9 @@
--- WebIDL.py --- WebIDL.py
+++ WebIDL.py +++ WebIDL.py
@@ -1744,7 +1744,8 @@ @@ -1744,7 +1744,8 @@
identifier == "ProbablyShortLivingWrapper" or
identifier == "LegacyUnenumerableNamedProperties" or identifier == "LegacyUnenumerableNamedProperties" or
identifier == "RunConstructorInCallerCompartment" or identifier == "RunConstructorInCallerCompartment" or
identifier == "WantsEventListenerHooks" or
- identifier == "NonOrdinaryGetPrototypeOf"): - identifier == "NonOrdinaryGetPrototypeOf"):
+ identifier == "NonOrdinaryGetPrototypeOf" or + identifier == "NonOrdinaryGetPrototypeOf" or
+ identifier == "Abstract"): + identifier == "Abstract"):

View file

@ -131,17 +131,3 @@ def WebIDLTest(parser, harness):
harness.ok(threw, harness.ok(threw,
"Should have thrown for [CEReactions] used on a stringifier") "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")

View file

@ -374,32 +374,3 @@ def WebIDLTest(parser, harness):
threw = True threw = True
harness.ok(threw, harness.ok(threw,
"Should not allow unknown extended attributes on interfaces") "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")

View file

@ -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")

View file

@ -246,8 +246,6 @@ impl CanvasRenderingContext2D {
CanvasImageSource::HTMLCanvasElement(canvas) => { CanvasImageSource::HTMLCanvasElement(canvas) => {
canvas.origin_is_clean() canvas.origin_is_clean()
} }
CanvasImageSource::CanvasRenderingContext2D(image) =>
image.origin_is_clean(),
CanvasImageSource::HTMLImageElement(image) => { CanvasImageSource::HTMLImageElement(image) => {
let image_origin = image.get_origin().expect("Image's origin is missing"); let image_origin = image.get_origin().expect("Image's origin is missing");
image_origin.same_origin(GlobalScope::entry().origin()) image_origin.same_origin(GlobalScope::entry().origin())
@ -294,11 +292,6 @@ impl CanvasRenderingContext2D {
sx, sy, sw, sh, sx, sy, sw, sh,
dx, dy, dw, dh) 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) => { CanvasImageSource::HTMLImageElement(ref image) => {
// https://html.spec.whatwg.org/multipage/#img-error // https://html.spec.whatwg.org/multipage/#img-error
// If the image argument is an HTMLImageElement object that is in the broken state, // 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)? 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) => { CanvasImageSource::CSSStyleValue(ref value) => {
value.get_url(self.base_url.clone()) value.get_url(self.base_url.clone())
.and_then(|url| self.fetch_image_data(url)) .and_then(|url| self.fetch_image_data(url))

View file

@ -17,7 +17,7 @@ use dom::bindings::inheritance::Castable;
use dom::bindings::num::Finite; use dom::bindings::num::Finite;
use dom::bindings::reflector::DomObject; use dom::bindings::reflector::DomObject;
use dom::bindings::root::{Dom, DomRoot, LayoutDom}; 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::canvasrenderingcontext2d::{CanvasRenderingContext2D, LayoutCanvasRenderingContext2DHelpers};
use dom::document::Document; use dom::document::Document;
use dom::element::{AttributeMutation, Element, RawLayoutElementHelpers}; use dom::element::{AttributeMutation, Element, RawLayoutElementHelpers};
@ -191,12 +191,12 @@ impl HTMLCanvasElement {
pub fn get_or_init_webgl_context( pub fn get_or_init_webgl_context(
&self, &self,
cx: *mut JSContext, cx: *mut JSContext,
attrs: Option<HandleValue> options: HandleValue,
) -> Option<DomRoot<WebGLRenderingContext>> { ) -> Option<DomRoot<WebGLRenderingContext>> {
if self.context.borrow().is_none() { if self.context.borrow().is_none() {
let window = window_from_node(self); let window = window_from_node(self);
let size = self.get_size(); 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); 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))); *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( pub fn get_or_init_webgl2_context(
&self, &self,
cx: *mut JSContext, cx: *mut JSContext,
attrs: Option<HandleValue> options: HandleValue,
) -> Option<DomRoot<WebGL2RenderingContext>> { ) -> Option<DomRoot<WebGL2RenderingContext>> {
if !PREFS.is_webgl2_enabled() { if !PREFS.is_webgl2_enabled() {
return None return None
@ -220,7 +220,7 @@ impl HTMLCanvasElement {
if self.context.borrow().is_none() { if self.context.borrow().is_none() {
let window = window_from_node(self); let window = window_from_node(self);
let size = self.get_size(); 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); let maybe_ctx = WebGL2RenderingContext::new(&window, self, size, attrs);
*self.context.borrow_mut() = maybe_ctx.map( |ctx| CanvasContext::WebGL2(Dom::from_ref(&*ctx))); *self.context.borrow_mut() = maybe_ctx.map( |ctx| CanvasContext::WebGL2(Dom::from_ref(&*ctx)));
@ -243,12 +243,8 @@ impl HTMLCanvasElement {
} }
#[allow(unsafe_code)] #[allow(unsafe_code)]
fn get_gl_attributes(cx: *mut JSContext, attrs: Option<HandleValue>) -> Option<GLContextAttributes> { fn get_gl_attributes(cx: *mut JSContext, options: HandleValue) -> Option<GLContextAttributes> {
let webgl_attributes = match attrs { match unsafe { WebGLContextAttributes::new(cx, options) } {
Some(attrs) => attrs,
None => return Some(GLContextAttributes::default()),
};
match unsafe { WebGLContextAttributes::new(cx, webgl_attributes) } {
Ok(ConversionResult::Success(ref attrs)) => Some(From::from(attrs)), Ok(ConversionResult::Success(ref attrs)) => Some(From::from(attrs)),
Ok(ConversionResult::Failure(ref error)) => { Ok(ConversionResult::Failure(ref error)) => {
unsafe { throw_type_error(cx, &error); } unsafe { throw_type_error(cx, &error); }
@ -310,36 +306,39 @@ impl HTMLCanvasElementMethods for HTMLCanvasElement {
// https://html.spec.whatwg.org/multipage/#dom-canvas-height // https://html.spec.whatwg.org/multipage/#dom-canvas-height
make_uint_setter!(SetHeight, "height", DEFAULT_HEIGHT); make_uint_setter!(SetHeight, "height", DEFAULT_HEIGHT);
#[allow(unsafe_code)]
// https://html.spec.whatwg.org/multipage/#dom-canvas-getcontext // https://html.spec.whatwg.org/multipage/#dom-canvas-getcontext
unsafe fn GetContext(&self, #[allow(unsafe_code)]
cx: *mut JSContext, unsafe fn GetContext(
id: DOMString, &self,
attributes: Vec<HandleValue>) cx: *mut JSContext,
-> Option<RenderingContext> { id: DOMString,
options: HandleValue,
) -> Option<RenderingContext> {
match &*id { match &*id {
"2d" => { "2d" => {
self.get_or_init_2d_context() self.get_or_init_2d_context()
.map(RenderingContext::CanvasRenderingContext2D) .map(RenderingContext::CanvasRenderingContext2D)
} }
"webgl" | "experimental-webgl" => { "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) .map(RenderingContext::WebGLRenderingContext)
} }
"webgl2" | "experimental-webgl2" => { "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) .map(RenderingContext::WebGL2RenderingContext)
} }
_ => None _ => None
} }
} }
#[allow(unsafe_code)]
// https://html.spec.whatwg.org/multipage/#dom-canvas-todataurl // https://html.spec.whatwg.org/multipage/#dom-canvas-todataurl
unsafe fn ToDataURL(&self, #[allow(unsafe_code)]
_context: *mut JSContext, unsafe fn ToDataURL(
_mime_type: Option<DOMString>, &self,
_arguments: Vec<HandleValue>) -> Fallible<DOMString> { _context: *mut JSContext,
_mime_type: Option<DOMString>,
_quality: HandleValue,
) -> Fallible<USVString> {
// Step 1. // Step 1.
if let Some(CanvasContext::Context2d(ref context)) = *self.context.borrow() { if let Some(CanvasContext::Context2d(ref context)) = *self.context.borrow() {
if !context.origin_is_clean() { if !context.origin_is_clean() {
@ -349,7 +348,7 @@ impl HTMLCanvasElementMethods for HTMLCanvasElement {
// Step 2. // Step 2.
if self.Width() == 0 || self.Height() == 0 { if self.Width() == 0 || self.Height() == 0 {
return Ok(DOMString::from("data:,")); return Ok(USVString("data:,".into()));
} }
// Step 3. // Step 3.
@ -363,13 +362,13 @@ impl HTMLCanvasElementMethods for HTMLCanvasElement {
Some(CanvasContext::WebGL(ref context)) => { Some(CanvasContext::WebGL(ref context)) => {
match context.get_image_data(self.Width(), self.Height()) { match context.get_image_data(self.Width(), self.Height()) {
Some(data) => data, Some(data) => data,
None => return Ok("data:,".into()), None => return Ok(USVString("data:,".into())),
} }
} }
Some(CanvasContext::WebGL2(ref context)) => { Some(CanvasContext::WebGL2(ref context)) => {
match context.base_context().get_image_data(self.Width(), self.Height()) { match context.base_context().get_image_data(self.Width(), self.Height()) {
Some(data) => data, Some(data) => data,
None => return Ok("data:,".into()), None => return Ok(USVString("data:,".into())),
} }
} }
None => { None => {
@ -388,7 +387,7 @@ impl HTMLCanvasElementMethods for HTMLCanvasElement {
} }
let encoded = base64::encode(&encoded); let encoded = base64::encode(&encoded);
Ok(DOMString::from(format!("data:{};base64,{}", mime_type, encoded))) Ok(USVString(format!("data:{};base64,{}", mime_type, encoded)))
} }
} }

View file

@ -6,12 +6,12 @@ use canvas_traits::canvas::CanvasImageData;
use canvas_traits::canvas::CanvasMsg; use canvas_traits::canvas::CanvasMsg;
use canvas_traits::canvas::FromLayoutMsg; use canvas_traits::canvas::FromLayoutMsg;
use dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasFillRule; 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::CanvasLineCap;
use dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasLineJoin; use dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasLineJoin;
use dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasRenderingContext2DMethods; use dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasRenderingContext2DMethods;
use dom::bindings::codegen::Bindings::PaintRenderingContext2DBinding; use dom::bindings::codegen::Bindings::PaintRenderingContext2DBinding;
use dom::bindings::codegen::Bindings::PaintRenderingContext2DBinding::PaintRenderingContext2DMethods; use dom::bindings::codegen::Bindings::PaintRenderingContext2DBinding::PaintRenderingContext2DMethods;
use dom::bindings::codegen::UnionTypes::HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2DOrCSSStyleValue;
use dom::bindings::codegen::UnionTypes::StringOrCanvasGradientOrCanvasPattern; use dom::bindings::codegen::UnionTypes::StringOrCanvasGradientOrCanvasPattern;
use dom::bindings::error::ErrorResult; use dom::bindings::error::ErrorResult;
use dom::bindings::error::Fallible; use dom::bindings::error::Fallible;
@ -194,37 +194,40 @@ impl PaintRenderingContext2DMethods for PaintRenderingContext2D {
} }
// https://html.spec.whatwg.org/multipage/#dom-context-2d-drawimage // https://html.spec.whatwg.org/multipage/#dom-context-2d-drawimage
fn DrawImage(&self, fn DrawImage(
image: HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2DOrCSSStyleValue, &self,
dx: f64, image: CanvasImageSource,
dy: f64) dx: f64,
-> ErrorResult { dy: f64,
) -> ErrorResult {
self.context.DrawImage(image, dx, dy) self.context.DrawImage(image, dx, dy)
} }
// https://html.spec.whatwg.org/multipage/#dom-context-2d-drawimage // https://html.spec.whatwg.org/multipage/#dom-context-2d-drawimage
fn DrawImage_(&self, fn DrawImage_(
image: HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2DOrCSSStyleValue, &self,
dx: f64, image: CanvasImageSource,
dy: f64, dx: f64,
dw: f64, dy: f64,
dh: f64) dw: f64,
-> ErrorResult { dh: f64,
) -> ErrorResult {
self.context.DrawImage_(image, dx, dy, dw, dh) self.context.DrawImage_(image, dx, dy, dw, dh)
} }
// https://html.spec.whatwg.org/multipage/#dom-context-2d-drawimage // https://html.spec.whatwg.org/multipage/#dom-context-2d-drawimage
fn DrawImage__(&self, fn DrawImage__(
image: HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2DOrCSSStyleValue, &self,
sx: f64, image: CanvasImageSource,
sy: f64, sx: f64,
sw: f64, sy: f64,
sh: f64, sw: f64,
dx: f64, sh: f64,
dy: f64, dx: f64,
dw: f64, dy: f64,
dh: f64) dw: f64,
-> ErrorResult { dh: f64,
) -> ErrorResult {
self.context.DrawImage__(image, sx, sy, sw, sh, dx, dy, dw, dh) 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 // https://html.spec.whatwg.org/multipage/#dom-context-2d-createpattern
fn CreatePattern(&self, fn CreatePattern(
image: HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2DOrCSSStyleValue, &self,
repetition: DOMString) image: CanvasImageSource,
-> Fallible<DomRoot<CanvasPattern>> { repetition: DOMString,
) -> Fallible<DomRoot<CanvasPattern>> {
self.context.CreatePattern(image, repetition) self.context.CreatePattern(image, repetition)
} }

View file

@ -540,8 +540,10 @@ impl WebGLRenderingContext {
return Err(()); return Err(());
} }
}, },
ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement::HTMLVideoElement(_rooted_video) ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement::HTMLVideoElement(_) => {
=> unimplemented!(), // TODO: https://github.com/servo/servo/issues/6711
return Err(());
}
}; };
return Ok((pixels, size, premultiplied)); return Ok((pixels, size, premultiplied));

View file

@ -2,30 +2,25 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// https://html.spec.whatwg.org/multipage/#2dcontext
// typedef (HTMLImageElement or
// SVGImageElement) HTMLOrSVGImageElement;
typedef HTMLImageElement HTMLOrSVGImageElement;
typedef (HTMLOrSVGImageElement or
/*HTMLVideoElement or*/
HTMLCanvasElement or
/*ImageBitmap or*/
/*OffscreenCanvas or*/
/*CSSImageValue*/ CSSStyleValue) CanvasImageSource;
enum CanvasFillRule { "nonzero", "evenodd" }; enum CanvasFillRule { "nonzero", "evenodd" };
// https://html.spec.whatwg.org/multipage/#2dcontext [Exposed=Window]
typedef (HTMLImageElement 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;
//[Constructor(optional unsigned long width, unsigned long height)]
interface CanvasRenderingContext2D { interface CanvasRenderingContext2D {
// back-reference to the canvas // back-reference to the canvas
readonly attribute HTMLCanvasElement 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 CanvasState;
CanvasRenderingContext2D implements CanvasTransform; CanvasRenderingContext2D implements CanvasTransform;
@ -33,25 +28,25 @@ CanvasRenderingContext2D implements CanvasCompositing;
CanvasRenderingContext2D implements CanvasImageSmoothing; CanvasRenderingContext2D implements CanvasImageSmoothing;
CanvasRenderingContext2D implements CanvasFillStrokeStyles; CanvasRenderingContext2D implements CanvasFillStrokeStyles;
CanvasRenderingContext2D implements CanvasShadowStyles; CanvasRenderingContext2D implements CanvasShadowStyles;
CanvasRenderingContext2D implements CanvasFilters;
CanvasRenderingContext2D implements CanvasRect; CanvasRenderingContext2D implements CanvasRect;
CanvasRenderingContext2D implements CanvasDrawPath; CanvasRenderingContext2D implements CanvasDrawPath;
CanvasRenderingContext2D implements CanvasUserInterface; CanvasRenderingContext2D implements CanvasUserInterface;
CanvasRenderingContext2D implements CanvasText; CanvasRenderingContext2D implements CanvasText;
CanvasRenderingContext2D implements CanvasDrawImage; CanvasRenderingContext2D implements CanvasDrawImage;
CanvasRenderingContext2D implements CanvasHitRegion;
CanvasRenderingContext2D implements CanvasImageData; CanvasRenderingContext2D implements CanvasImageData;
CanvasRenderingContext2D implements CanvasPathDrawingStyles; CanvasRenderingContext2D implements CanvasPathDrawingStyles;
CanvasRenderingContext2D implements CanvasTextDrawingStyles; CanvasRenderingContext2D implements CanvasTextDrawingStyles;
CanvasRenderingContext2D implements CanvasPath; CanvasRenderingContext2D implements CanvasPath;
[NoInterfaceObject, Exposed=(Window, PaintWorklet)] [Exposed=(PaintWorklet, Window), NoInterfaceObject]
interface CanvasState { interface CanvasState {
// state // state
void save(); // push state on state stack void save(); // push state on state stack
void restore(); // pop state stack and restore state void restore(); // pop state stack and restore state
}; };
[NoInterfaceObject, Exposed=(Window, PaintWorklet)] [Exposed=(PaintWorklet, Window), NoInterfaceObject]
interface CanvasTransform { interface CanvasTransform {
// transformations (default transform is the identity matrix) // transformations (default transform is the identity matrix)
void scale(unrestricted double x, unrestricted double y); void scale(unrestricted double x, unrestricted double y);
@ -75,23 +70,22 @@ interface CanvasTransform {
void resetTransform(); void resetTransform();
}; };
[NoInterfaceObject, Exposed=(Window, PaintWorklet)] [Exposed=(PaintWorklet, Window), NoInterfaceObject]
interface CanvasCompositing { interface CanvasCompositing {
// compositing // compositing
attribute unrestricted double globalAlpha; // (default 1.0) attribute unrestricted double globalAlpha; // (default 1.0)
attribute DOMString globalCompositeOperation; // (default source-over) attribute DOMString globalCompositeOperation; // (default source-over)
}; };
[NoInterfaceObject, Exposed=(Window, PaintWorklet)] [Exposed=(PaintWorklet, Window), NoInterfaceObject]
interface CanvasImageSmoothing { interface CanvasImageSmoothing {
// image smoothing // image smoothing
attribute boolean imageSmoothingEnabled; // (default true) attribute boolean imageSmoothingEnabled; // (default true)
// attribute ImageSmoothingQuality imageSmoothingQuality; // (default low) // attribute ImageSmoothingQuality imageSmoothingQuality; // (default low)
}; };
[NoInterfaceObject, Exposed=(Window, PaintWorklet)] [Exposed=(PaintWorklet, Window), NoInterfaceObject]
interface CanvasFillStrokeStyles { interface CanvasFillStrokeStyles {
// colours and styles (see also the CanvasDrawingStyles interface) // colours and styles (see also the CanvasDrawingStyles interface)
attribute (DOMString or CanvasGradient or CanvasPattern) strokeStyle; // (default black) attribute (DOMString or CanvasGradient or CanvasPattern) strokeStyle; // (default black)
attribute (DOMString or CanvasGradient or CanvasPattern) fillStyle; // (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); CanvasPattern createPattern(CanvasImageSource image, [TreatNullAs=EmptyString] DOMString repetition);
}; };
[NoInterfaceObject, Exposed=(Window, PaintWorklet)] [Exposed=(PaintWorklet, Window), NoInterfaceObject]
interface CanvasShadowStyles { interface CanvasShadowStyles {
// shadows // shadows
attribute unrestricted double shadowOffsetX; // (default 0) attribute unrestricted double shadowOffsetX; // (default 0)
@ -111,32 +105,30 @@ interface CanvasShadowStyles {
attribute DOMString shadowColor; // (default transparent black) 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 { interface CanvasRect {
// rects // rects
//[LenientFloat]
void clearRect(unrestricted double x, unrestricted double y, unrestricted double w, unrestricted double h); 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); 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); void strokeRect(unrestricted double x, unrestricted double y, unrestricted double w, unrestricted double h);
}; };
[NoInterfaceObject, Exposed=(Window, PaintWorklet)] [Exposed=(PaintWorklet, Window), NoInterfaceObject]
interface CanvasDrawPath { interface CanvasDrawPath {
// path API (see also CanvasPathMethods) // path API (see also CanvasPath)
void beginPath(); void beginPath();
void fill(optional CanvasFillRule fillRule = "nonzero"); void fill(optional CanvasFillRule fillRule = "nonzero");
//void fill(Path2D path, optional CanvasFillRule fillRule = "nonzero"); //void fill(Path2D path, optional CanvasFillRule fillRule = "nonzero");
void stroke(); void stroke();
//void stroke(Path2D path); //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(optional CanvasFillRule fillRule = "nonzero");
//void clip(Path2D path, optional CanvasFillRule fillRule = "nonzero"); //void clip(Path2D path, optional CanvasFillRule fillRule = "nonzero");
//void resetClip();
boolean isPointInPath(unrestricted double x, unrestricted double y, boolean isPointInPath(unrestricted double x, unrestricted double y,
optional CanvasFillRule fillRule = "nonzero"); optional CanvasFillRule fillRule = "nonzero");
//boolean isPointInPath(Path2D path, unrestricted double x, unrestricted double y, //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); //boolean isPointInStroke(Path2D path, unrestricted double x, unrestricted double y);
}; };
[NoInterfaceObject] [Exposed=(PaintWorklet, Window), NoInterfaceObject]
interface CanvasUserInterface { 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 { interface CanvasText {
// text (see also the CanvasDrawingStyles interface) // text (see also the CanvasPathDrawingStyles and CanvasTextDrawingStyles interfaces)
[Pref="dom.canvas-text.enabled"] [Pref="dom.canvas-text.enabled"]
void fillText(DOMString text, unrestricted double x, unrestricted double y, void fillText(DOMString text, unrestricted double x, unrestricted double y,
optional unrestricted double maxWidth); optional unrestricted double maxWidth);
@ -161,7 +156,7 @@ interface CanvasText {
//TextMetrics measureText(DOMString text); //TextMetrics measureText(DOMString text);
}; };
[NoInterfaceObject, Exposed=(Window, PaintWorklet)] [Exposed=(PaintWorklet, Window), NoInterfaceObject]
interface CanvasDrawImage { interface CanvasDrawImage {
// drawing images // drawing images
[Throws] [Throws]
@ -176,15 +171,7 @@ interface CanvasDrawImage {
unrestricted double dw, unrestricted double dh); unrestricted double dw, unrestricted double dh);
}; };
[NoInterfaceObject] [Exposed=Window, NoInterfaceObject]
interface CanvasHitRegion {
// hit regions
//void addHitRegion(optional HitRegionOptions options);
//void removeHitRegion(DOMString id);
//void clearHitRegions();
};
[NoInterfaceObject]
interface CanvasImageData { interface CanvasImageData {
// pixel manipulation // pixel manipulation
[Throws] [Throws]
@ -199,9 +186,6 @@ interface CanvasImageData {
double dirtyX, double dirtyY, double dirtyX, double dirtyY,
double dirtyWidth, double dirtyHeight); double dirtyWidth, double dirtyHeight);
}; };
CanvasRenderingContext2D implements CanvasPathDrawingStyles;
CanvasRenderingContext2D implements CanvasTextDrawingStyles;
CanvasRenderingContext2D implements CanvasPath;
enum CanvasLineCap { "butt", "round", "square" }; enum CanvasLineCap { "butt", "round", "square" };
enum CanvasLineJoin { "round", "bevel", "miter"}; 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 CanvasTextBaseline { "top", "hanging", "middle", "alphabetic", "ideographic", "bottom" };
enum CanvasDirection { "ltr", "rtl", "inherit" }; enum CanvasDirection { "ltr", "rtl", "inherit" };
[NoInterfaceObject, Exposed=(Window, PaintWorklet)] [Exposed=(PaintWorklet, Window), NoInterfaceObject]
interface CanvasPathDrawingStyles { interface CanvasPathDrawingStyles {
// line caps/joins // line caps/joins
attribute unrestricted double lineWidth; // (default 1) attribute unrestricted double lineWidth; // (default 1)
attribute CanvasLineCap lineCap; // "butt", "round", "square" (default "butt") attribute CanvasLineCap lineCap; // (default "butt")
attribute CanvasLineJoin lineJoin; // "round", "bevel", "miter" (default "miter") attribute CanvasLineJoin lineJoin; // (default "miter")
attribute unrestricted double miterLimit; // (default 10) attribute unrestricted double miterLimit; // (default 10)
// dashed lines // dashed lines
@ -223,7 +207,7 @@ interface CanvasPathDrawingStyles {
//attribute unrestricted double lineDashOffset; //attribute unrestricted double lineDashOffset;
}; };
[NoInterfaceObject] [Exposed=(PaintWorklet, Window), NoInterfaceObject]
interface CanvasTextDrawingStyles { interface CanvasTextDrawingStyles {
// text // text
//attribute DOMString font; // (default 10px sans-serif) //attribute DOMString font; // (default 10px sans-serif)
@ -233,7 +217,7 @@ interface CanvasTextDrawingStyles {
//attribute CanvasDirection direction; // "ltr", "rtl", "inherit" (default: "inherit") //attribute CanvasDirection direction; // "ltr", "rtl", "inherit" (default: "inherit")
}; };
[NoInterfaceObject, Exposed=(Window, Worker, PaintWorklet)] [Exposed=(PaintWorklet, Window), NoInterfaceObject]
interface CanvasPath { interface CanvasPath {
// shared path API methods // shared path API methods
void closePath(); void closePath();
@ -253,17 +237,12 @@ interface CanvasPath {
void arcTo(unrestricted double x1, unrestricted double y1, void arcTo(unrestricted double x1, unrestricted double y1,
unrestricted double x2, unrestricted double y2, unrestricted double x2, unrestricted double y2,
unrestricted double radius); 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); void rect(unrestricted double x, unrestricted double y, unrestricted double w, unrestricted double h);
[Throws] [Throws]
void arc(unrestricted double x, unrestricted double y, unrestricted double radius, void arc(unrestricted double x, unrestricted double y, unrestricted double radius,
unrestricted double startAngle, unrestricted double endAngle, optional boolean anticlockwise = false); 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] [Throws]
void ellipse(unrestricted double x, unrestricted double y, unrestricted double radius_x, void ellipse(unrestricted double x, unrestricted double y, unrestricted double radius_x,

View file

@ -5,20 +5,18 @@
// https://html.spec.whatwg.org/multipage/#htmlcanvaselement // https://html.spec.whatwg.org/multipage/#htmlcanvaselement
typedef (CanvasRenderingContext2D or WebGLRenderingContext or WebGL2RenderingContext) RenderingContext; typedef (CanvasRenderingContext2D or WebGLRenderingContext or WebGL2RenderingContext) RenderingContext;
[HTMLConstructor] [Exposed=Window,
HTMLConstructor]
interface HTMLCanvasElement : HTMLElement { interface HTMLCanvasElement : HTMLElement {
[CEReactions, Pure] [CEReactions, Pure] attribute unsigned long width;
attribute unsigned long width; [CEReactions, Pure] attribute unsigned long height;
[CEReactions, Pure]
attribute unsigned long height;
RenderingContext? getContext(DOMString contextId, any... arguments); RenderingContext? getContext(DOMString contextId, optional any options = null);
//boolean probablySupportsContext(DOMString contextId, any... arguments);
//void setContext(RenderingContext context);
//CanvasProxy transferControlToProxy();
[Throws] [Throws]
DOMString toDataURL(optional DOMString type, any... arguments); USVString toDataURL(optional DOMString type, optional any quality);
//void toBlob(FileCallback? _callback, optional DOMString type, any... arguments); //void toBlob(BlobCallback _callback, optional DOMString type, optional any quality);
//OffscreenCanvas transferControlToOffscreen();
}; };
//callback BlobCallback = void (Blob? blob);