mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-06 07:17:30 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
791
dom/bindings/Configuration.py
Normal file
791
dom/bindings/Configuration.py
Normal file
|
|
@ -0,0 +1,791 @@
|
|||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
from WebIDL import IDLImplementsStatement
|
||||
import os
|
||||
from collections import defaultdict
|
||||
|
||||
autogenerated_comment = "/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n"
|
||||
|
||||
|
||||
class DescriptorProvider:
|
||||
"""
|
||||
A way of getting descriptors for interface names. Subclasses must
|
||||
have a getDescriptor method callable with the interface name only.
|
||||
"""
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
|
||||
class Configuration(DescriptorProvider):
|
||||
"""
|
||||
Represents global configuration state based on IDL parse data and
|
||||
the configuration file.
|
||||
"""
|
||||
def __init__(self, filename, parseData, generatedEvents=[]):
|
||||
DescriptorProvider.__init__(self)
|
||||
|
||||
# Read the configuration file.
|
||||
glbl = {}
|
||||
execfile(filename, glbl)
|
||||
config = glbl['DOMInterfaces']
|
||||
|
||||
# Build descriptors for all the interfaces we have in the parse data.
|
||||
# This allows callers to specify a subset of interfaces by filtering
|
||||
# |parseData|.
|
||||
self.descriptors = []
|
||||
self.interfaces = {}
|
||||
self.descriptorsByName = {}
|
||||
self.optimizedOutDescriptorNames = set()
|
||||
self.generatedEvents = generatedEvents
|
||||
self.maxProtoChainLength = 0
|
||||
for thing in parseData:
|
||||
if isinstance(thing, IDLImplementsStatement):
|
||||
# Our build system doesn't support dep build involving
|
||||
# addition/removal of "implements" statements that appear in a
|
||||
# different .webidl file than their LHS interface. Make sure we
|
||||
# don't have any of those.
|
||||
#
|
||||
# But whitelist a RHS that is LegacyQueryInterface,
|
||||
# since people shouldn't be adding any of those.
|
||||
if (thing.implementor.filename() != thing.filename() and
|
||||
thing.implementee.identifier.name != "LegacyQueryInterface"):
|
||||
raise TypeError(
|
||||
"The binding build system doesn't really support "
|
||||
"'implements' statements which don't appear in the "
|
||||
"file in which the left-hand side of the statement is "
|
||||
"defined. Don't do this unless your right-hand side "
|
||||
"is LegacyQueryInterface.\n"
|
||||
"%s\n"
|
||||
"%s" %
|
||||
(thing.location, thing.implementor.location))
|
||||
|
||||
assert not thing.isType()
|
||||
|
||||
if not thing.isInterface() and not thing.isNamespace():
|
||||
continue
|
||||
iface = thing
|
||||
self.interfaces[iface.identifier.name] = iface
|
||||
if iface.identifier.name not in config:
|
||||
# Completely skip consequential interfaces with no descriptor
|
||||
# if they have no interface object because chances are we
|
||||
# don't need to do anything interesting with them.
|
||||
if iface.isConsequential() and not iface.hasInterfaceObject():
|
||||
self.optimizedOutDescriptorNames.add(iface.identifier.name)
|
||||
continue
|
||||
entry = {}
|
||||
else:
|
||||
entry = config[iface.identifier.name]
|
||||
assert not isinstance(entry, list)
|
||||
desc = Descriptor(self, iface, entry)
|
||||
self.descriptors.append(desc)
|
||||
# Setting up descriptorsByName while iterating through interfaces
|
||||
# means we can get the nativeType of iterable interfaces without
|
||||
# having to do multiple loops.
|
||||
assert desc.interface.identifier.name not in self.descriptorsByName
|
||||
self.descriptorsByName[desc.interface.identifier.name] = desc
|
||||
|
||||
# Keep the descriptor list sorted for determinism.
|
||||
self.descriptors.sort(lambda x, y: cmp(x.name, y.name))
|
||||
|
||||
|
||||
self.descriptorsByFile = {}
|
||||
for d in self.descriptors:
|
||||
self.descriptorsByFile.setdefault(d.interface.filename(),
|
||||
[]).append(d)
|
||||
|
||||
self.enums = [e for e in parseData if e.isEnum()]
|
||||
|
||||
self.dictionaries = [d for d in parseData if d.isDictionary()]
|
||||
self.callbacks = [c for c in parseData if
|
||||
c.isCallback() and not c.isInterface()]
|
||||
|
||||
# Dictionary mapping from a union type name to a set of filenames where
|
||||
# union types with that name are used.
|
||||
self.filenamesPerUnion = defaultdict(set)
|
||||
|
||||
# Dictionary mapping from a filename to a list of types for
|
||||
# the union types used in that file. If a union type is used
|
||||
# in multiple files then it will be added to the list for the
|
||||
# None key. Note that the list contains a type for every use
|
||||
# of a union type, so there can be multiple entries with union
|
||||
# types that have the same name.
|
||||
self.unionsPerFilename = defaultdict(list)
|
||||
|
||||
for (t, _) in getAllTypes(self.descriptors, self.dictionaries, self.callbacks):
|
||||
while True:
|
||||
if t.isMozMap():
|
||||
t = t.inner
|
||||
elif t.unroll() != t:
|
||||
t = t.unroll()
|
||||
elif t.isPromise():
|
||||
t = t.promiseInnerType()
|
||||
else:
|
||||
break
|
||||
if t.isUnion():
|
||||
filenamesForUnion = self.filenamesPerUnion[t.name]
|
||||
if t.filename() not in filenamesForUnion:
|
||||
# We have a to be a bit careful: some of our built-in
|
||||
# typedefs are for unions, and those unions end up with
|
||||
# "<unknown>" as the filename. If that happens, we don't
|
||||
# want to try associating this union with one particular
|
||||
# filename, since there isn't one to associate it with,
|
||||
# really.
|
||||
if t.filename() == "<unknown>":
|
||||
uniqueFilenameForUnion = None
|
||||
elif len(filenamesForUnion) == 0:
|
||||
# This is the first file that we found a union with this
|
||||
# name in, record the union as part of the file.
|
||||
uniqueFilenameForUnion = t.filename()
|
||||
else:
|
||||
# We already found a file that contains a union with
|
||||
# this name.
|
||||
if len(filenamesForUnion) == 1:
|
||||
# This is the first time we found a union with this
|
||||
# name in another file.
|
||||
for f in filenamesForUnion:
|
||||
# Filter out unions with this name from the
|
||||
# unions for the file where we previously found
|
||||
# them.
|
||||
unionsForFilename = self.unionsPerFilename[f]
|
||||
unionsForFilename = filter(lambda u: u.name != t.name,
|
||||
unionsForFilename)
|
||||
if len(unionsForFilename) == 0:
|
||||
del self.unionsPerFilename[f]
|
||||
else:
|
||||
self.unionsPerFilename[f] = unionsForFilename
|
||||
# Unions with this name appear in multiple files, record
|
||||
# the filename as None, so that we can detect that.
|
||||
uniqueFilenameForUnion = None
|
||||
self.unionsPerFilename[uniqueFilenameForUnion].append(t)
|
||||
filenamesForUnion.add(t.filename())
|
||||
|
||||
def getInterface(self, ifname):
|
||||
return self.interfaces[ifname]
|
||||
|
||||
def getDescriptors(self, **filters):
|
||||
"""Gets the descriptors that match the given filters."""
|
||||
curr = self.descriptors
|
||||
# Collect up our filters, because we may have a webIDLFile filter that
|
||||
# we always want to apply first.
|
||||
tofilter = []
|
||||
for key, val in filters.iteritems():
|
||||
if key == 'webIDLFile':
|
||||
# Special-case this part to make it fast, since most of our
|
||||
# getDescriptors calls are conditioned on a webIDLFile. We may
|
||||
# not have this key, in which case we have no descriptors
|
||||
# either.
|
||||
curr = self.descriptorsByFile.get(val, [])
|
||||
continue
|
||||
elif key == 'hasInterfaceObject':
|
||||
getter = lambda x: (not x.interface.isExternal() and
|
||||
x.interface.hasInterfaceObject())
|
||||
elif key == 'hasInterfacePrototypeObject':
|
||||
getter = lambda x: (not x.interface.isExternal() and
|
||||
x.interface.hasInterfacePrototypeObject())
|
||||
elif key == 'hasInterfaceOrInterfacePrototypeObject':
|
||||
getter = lambda x: x.hasInterfaceOrInterfacePrototypeObject()
|
||||
elif key == 'isCallback':
|
||||
getter = lambda x: x.interface.isCallback()
|
||||
elif key == 'isExternal':
|
||||
getter = lambda x: x.interface.isExternal()
|
||||
elif key == 'isJSImplemented':
|
||||
getter = lambda x: x.interface.isJSImplemented()
|
||||
elif key == 'isNavigatorProperty':
|
||||
getter = lambda x: x.interface.isNavigatorProperty()
|
||||
elif key == 'isExposedInAnyWorker':
|
||||
getter = lambda x: x.interface.isExposedInAnyWorker()
|
||||
elif key == 'isExposedInWorkerDebugger':
|
||||
getter = lambda x: x.interface.isExposedInWorkerDebugger()
|
||||
elif key == 'isExposedInAnyWorklet':
|
||||
getter = lambda x: x.interface.isExposedInAnyWorklet()
|
||||
elif key == 'isExposedInSystemGlobals':
|
||||
getter = lambda x: x.interface.isExposedInSystemGlobals()
|
||||
elif key == 'isExposedInWindow':
|
||||
getter = lambda x: x.interface.isExposedInWindow()
|
||||
else:
|
||||
# Have to watch out: just closing over "key" is not enough,
|
||||
# since we're about to mutate its value
|
||||
getter = (lambda attrName: lambda x: getattr(x, attrName))(key)
|
||||
tofilter.append((getter, val))
|
||||
for f in tofilter:
|
||||
curr = filter(lambda x: f[0](x) == f[1], curr)
|
||||
return curr
|
||||
|
||||
def getEnums(self, webIDLFile):
|
||||
return filter(lambda e: e.filename() == webIDLFile, self.enums)
|
||||
|
||||
def getDictionaries(self, webIDLFile):
|
||||
return filter(lambda d: d.filename() == webIDLFile, self.dictionaries)
|
||||
|
||||
def getCallbacks(self, webIDLFile):
|
||||
return filter(lambda c: c.filename() == webIDLFile, self.callbacks)
|
||||
|
||||
def getDescriptor(self, interfaceName):
|
||||
"""
|
||||
Gets the appropriate descriptor for the given interface name.
|
||||
"""
|
||||
# We may have optimized out this descriptor, but the chances of anyone
|
||||
# asking about it are then slim. Put the check for that _after_ we've
|
||||
# done our normal lookup. But that means we have to do our normal
|
||||
# lookup in a way that will not throw if it fails.
|
||||
d = self.descriptorsByName.get(interfaceName, None)
|
||||
if d:
|
||||
return d
|
||||
|
||||
if interfaceName in self.optimizedOutDescriptorNames:
|
||||
raise NoSuchDescriptorError(
|
||||
"No descriptor for '%s', which is a mixin ([NoInterfaceObject] "
|
||||
"and a consequential interface) without an explicit "
|
||||
"Bindings.conf annotation." % interfaceName)
|
||||
|
||||
raise NoSuchDescriptorError("For " + interfaceName + " found no matches")
|
||||
|
||||
|
||||
class NoSuchDescriptorError(TypeError):
|
||||
def __init__(self, str):
|
||||
TypeError.__init__(self, str)
|
||||
|
||||
|
||||
def methodReturnsJSObject(method):
|
||||
assert method.isMethod()
|
||||
if method.returnsPromise():
|
||||
return True
|
||||
|
||||
for signature in method.signatures():
|
||||
returnType = signature[0]
|
||||
if returnType.isObject() or returnType.isSpiderMonkeyInterface():
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def MemberIsUnforgeable(member, descriptor):
|
||||
# Note: "or" and "and" return either their LHS or RHS, not
|
||||
# necessarily booleans. Make sure to return a boolean from this
|
||||
# method, because callers will compare its return value to
|
||||
# booleans.
|
||||
return bool((member.isAttr() or member.isMethod()) and
|
||||
not member.isStatic() and
|
||||
(member.isUnforgeable() or
|
||||
descriptor.interface.getExtendedAttribute("Unforgeable")))
|
||||
|
||||
|
||||
class Descriptor(DescriptorProvider):
|
||||
"""
|
||||
Represents a single descriptor for an interface. See Bindings.conf.
|
||||
"""
|
||||
def __init__(self, config, interface, desc):
|
||||
DescriptorProvider.__init__(self)
|
||||
self.config = config
|
||||
self.interface = interface
|
||||
|
||||
self.wantsXrays = (not interface.isExternal() and
|
||||
interface.isExposedInWindow())
|
||||
|
||||
if self.wantsXrays:
|
||||
# We could try to restrict self.wantsXrayExpandoClass further. For
|
||||
# example, we could set it to false if all of our slots store
|
||||
# Gecko-interface-typed things, because we don't use Xray expando
|
||||
# slots for those. But note that we would need to check the types
|
||||
# of not only the members of "interface" but also of all its
|
||||
# ancestors, because those can have members living in our slots too.
|
||||
# For now, do the simple thing.
|
||||
self.wantsXrayExpandoClass = (interface.totalMembersInSlots != 0)
|
||||
|
||||
# Read the desc, and fill in the relevant defaults.
|
||||
ifaceName = self.interface.identifier.name
|
||||
# For generated iterator interfaces for other iterable interfaces, we
|
||||
# just use IterableIterator as the native type, templated on the
|
||||
# nativeType of the iterable interface. That way we can have a
|
||||
# templated implementation for all the duplicated iterator
|
||||
# functionality.
|
||||
if self.interface.isIteratorInterface():
|
||||
itrName = self.interface.iterableInterface.identifier.name
|
||||
itrDesc = self.getDescriptor(itrName)
|
||||
nativeTypeDefault = iteratorNativeType(itrDesc)
|
||||
|
||||
elif self.interface.isExternal():
|
||||
nativeTypeDefault = "nsIDOM" + ifaceName
|
||||
else:
|
||||
nativeTypeDefault = "mozilla::dom::" + ifaceName
|
||||
|
||||
self.nativeType = desc.get('nativeType', nativeTypeDefault)
|
||||
# Now create a version of nativeType that doesn't have extra
|
||||
# mozilla::dom:: at the beginning.
|
||||
prettyNativeType = self.nativeType.split("::")
|
||||
if prettyNativeType[0] == "mozilla":
|
||||
prettyNativeType.pop(0)
|
||||
if prettyNativeType[0] == "dom":
|
||||
prettyNativeType.pop(0)
|
||||
self.prettyNativeType = "::".join(prettyNativeType)
|
||||
|
||||
self.jsImplParent = desc.get('jsImplParent', self.nativeType)
|
||||
|
||||
# Do something sane for JSObject
|
||||
if self.nativeType == "JSObject":
|
||||
headerDefault = "js/TypeDecls.h"
|
||||
elif self.interface.isCallback() or self.interface.isJSImplemented():
|
||||
# A copy of CGHeaders.getDeclarationFilename; we can't
|
||||
# import it here, sadly.
|
||||
# Use our local version of the header, not the exported one, so that
|
||||
# test bindings, which don't export, will work correctly.
|
||||
basename = os.path.basename(self.interface.filename())
|
||||
headerDefault = basename.replace('.webidl', 'Binding.h')
|
||||
else:
|
||||
if not self.interface.isExternal() and self.interface.getExtendedAttribute("HeaderFile"):
|
||||
headerDefault = self.interface.getExtendedAttribute("HeaderFile")[0]
|
||||
elif self.interface.isIteratorInterface():
|
||||
headerDefault = "mozilla/dom/IterableIterator.h"
|
||||
else:
|
||||
headerDefault = self.nativeType
|
||||
headerDefault = headerDefault.replace("::", "/") + ".h"
|
||||
self.headerFile = desc.get('headerFile', headerDefault)
|
||||
self.headerIsDefault = self.headerFile == headerDefault
|
||||
if self.jsImplParent == self.nativeType:
|
||||
self.jsImplParentHeader = self.headerFile
|
||||
else:
|
||||
self.jsImplParentHeader = self.jsImplParent.replace("::", "/") + ".h"
|
||||
|
||||
self.notflattened = desc.get('notflattened', False)
|
||||
self.register = desc.get('register', True)
|
||||
|
||||
self.hasXPConnectImpls = desc.get('hasXPConnectImpls', False)
|
||||
|
||||
# If we're concrete, we need to crawl our ancestor interfaces and mark
|
||||
# them as having a concrete descendant.
|
||||
self.concrete = (not self.interface.isExternal() and
|
||||
not self.interface.isCallback() and
|
||||
not self.interface.isNamespace() and
|
||||
desc.get('concrete', True))
|
||||
self.hasUnforgeableMembers = (self.concrete and
|
||||
any(MemberIsUnforgeable(m, self) for m in
|
||||
self.interface.members))
|
||||
self.operations = {
|
||||
'IndexedGetter': None,
|
||||
'IndexedSetter': None,
|
||||
'IndexedCreator': None,
|
||||
'IndexedDeleter': None,
|
||||
'NamedGetter': None,
|
||||
'NamedSetter': None,
|
||||
'NamedCreator': None,
|
||||
'NamedDeleter': None,
|
||||
'Stringifier': None,
|
||||
'LegacyCaller': None,
|
||||
'Jsonifier': None
|
||||
}
|
||||
|
||||
# Stringifiers and jsonifiers need to be set up whether an interface is
|
||||
# concrete or not, because they're actually prototype methods and hence
|
||||
# can apply to instances of descendant interfaces. Legacy callers and
|
||||
# named/indexed operations only need to be set up on concrete
|
||||
# interfaces, since they affect the JSClass we end up using, not the
|
||||
# prototype object.
|
||||
def addOperation(operation, m):
|
||||
if not self.operations[operation]:
|
||||
self.operations[operation] = m
|
||||
|
||||
# Since stringifiers go on the prototype, we only need to worry
|
||||
# about our own stringifier, not those of our ancestor interfaces.
|
||||
if not self.interface.isExternal():
|
||||
for m in self.interface.members:
|
||||
if m.isMethod() and m.isStringifier():
|
||||
addOperation('Stringifier', m)
|
||||
if m.isMethod() and m.isJsonifier():
|
||||
addOperation('Jsonifier', m)
|
||||
|
||||
if self.concrete:
|
||||
self.proxy = False
|
||||
iface = self.interface
|
||||
for m in iface.members:
|
||||
# Don't worry about inheriting legacycallers either: in
|
||||
# practice these are on most-derived prototypes.
|
||||
if m.isMethod() and m.isLegacycaller():
|
||||
if not m.isIdentifierLess():
|
||||
raise TypeError("We don't support legacycaller with "
|
||||
"identifier.\n%s" % m.location)
|
||||
if len(m.signatures()) != 1:
|
||||
raise TypeError("We don't support overloaded "
|
||||
"legacycaller.\n%s" % m.location)
|
||||
addOperation('LegacyCaller', m)
|
||||
while iface:
|
||||
for m in iface.members:
|
||||
if not m.isMethod():
|
||||
continue
|
||||
|
||||
def addIndexedOrNamedOperation(operation, m):
|
||||
if m.isIndexed():
|
||||
operation = 'Indexed' + operation
|
||||
else:
|
||||
assert m.isNamed()
|
||||
operation = 'Named' + operation
|
||||
addOperation(operation, m)
|
||||
|
||||
if m.isGetter():
|
||||
addIndexedOrNamedOperation('Getter', m)
|
||||
if m.isSetter():
|
||||
addIndexedOrNamedOperation('Setter', m)
|
||||
if m.isCreator():
|
||||
addIndexedOrNamedOperation('Creator', m)
|
||||
if m.isDeleter():
|
||||
addIndexedOrNamedOperation('Deleter', m)
|
||||
if m.isLegacycaller() and iface != self.interface:
|
||||
raise TypeError("We don't support legacycaller on "
|
||||
"non-leaf interface %s.\n%s" %
|
||||
(iface, iface.location))
|
||||
|
||||
iface.setUserData('hasConcreteDescendant', True)
|
||||
iface = iface.parent
|
||||
|
||||
self.proxy = (self.supportsIndexedProperties() or
|
||||
(self.supportsNamedProperties() and
|
||||
not self.hasNamedPropertiesObject) or
|
||||
self.hasNonOrdinaryGetPrototypeOf())
|
||||
|
||||
if self.proxy:
|
||||
if (not self.operations['IndexedGetter'] and
|
||||
(self.operations['IndexedSetter'] or
|
||||
self.operations['IndexedDeleter'] or
|
||||
self.operations['IndexedCreator'])):
|
||||
raise SyntaxError("%s supports indexed properties but does "
|
||||
"not have an indexed getter.\n%s" %
|
||||
(self.interface, self.interface.location))
|
||||
if (not self.operations['NamedGetter'] and
|
||||
(self.operations['NamedSetter'] or
|
||||
self.operations['NamedDeleter'] or
|
||||
self.operations['NamedCreator'])):
|
||||
raise SyntaxError("%s supports named properties but does "
|
||||
"not have a named getter.\n%s" %
|
||||
(self.interface, self.interface.location))
|
||||
iface = self.interface
|
||||
while iface:
|
||||
iface.setUserData('hasProxyDescendant', True)
|
||||
iface = iface.parent
|
||||
|
||||
if desc.get('wantsQI', None) is not None:
|
||||
self._wantsQI = desc.get('wantsQI', None)
|
||||
self.wrapperCache = (not self.interface.isCallback() and
|
||||
not self.interface.isIteratorInterface() and
|
||||
desc.get('wrapperCache', True))
|
||||
# Nasty temporary hack for supporting both DOM and SpiderMonkey promises
|
||||
# without too much pain
|
||||
if self.interface.identifier.name == "Promise":
|
||||
assert self.wrapperCache
|
||||
# But really, we're only wrappercached if we have an interface
|
||||
# object (that is, when we're not using SpiderMonkey promises).
|
||||
self.wrapperCache = self.interface.hasInterfaceObject()
|
||||
|
||||
self.name = interface.identifier.name
|
||||
|
||||
# self.extendedAttributes is a dict of dicts, keyed on
|
||||
# all/getterOnly/setterOnly and then on member name. Values are an
|
||||
# array of extended attributes.
|
||||
self.extendedAttributes = {'all': {}, 'getterOnly': {}, 'setterOnly': {}}
|
||||
|
||||
def addExtendedAttribute(attribute, config):
|
||||
def add(key, members, attribute):
|
||||
for member in members:
|
||||
self.extendedAttributes[key].setdefault(member, []).append(attribute)
|
||||
|
||||
if isinstance(config, dict):
|
||||
for key in ['all', 'getterOnly', 'setterOnly']:
|
||||
add(key, config.get(key, []), attribute)
|
||||
elif isinstance(config, list):
|
||||
add('all', config, attribute)
|
||||
else:
|
||||
assert isinstance(config, str)
|
||||
if config == '*':
|
||||
iface = self.interface
|
||||
while iface:
|
||||
add('all', map(lambda m: m.name, iface.members), attribute)
|
||||
iface = iface.parent
|
||||
else:
|
||||
add('all', [config], attribute)
|
||||
|
||||
if self.interface.isJSImplemented():
|
||||
addExtendedAttribute('implicitJSContext', ['constructor'])
|
||||
else:
|
||||
for attribute in ['implicitJSContext']:
|
||||
addExtendedAttribute(attribute, desc.get(attribute, {}))
|
||||
|
||||
if self.interface.identifier.name == 'Navigator':
|
||||
for m in self.interface.members:
|
||||
if m.isAttr() and m.navigatorObjectGetter:
|
||||
# These getters call ConstructNavigatorObject to construct
|
||||
# the value, and ConstructNavigatorObject needs a JSContext.
|
||||
self.extendedAttributes['all'].setdefault(m.identifier.name, []).append('implicitJSContext')
|
||||
|
||||
self._binaryNames = desc.get('binaryNames', {})
|
||||
self._binaryNames.setdefault('__legacycaller', 'LegacyCall')
|
||||
self._binaryNames.setdefault('__stringifier', 'Stringify')
|
||||
|
||||
if not self.interface.isExternal():
|
||||
def isTestInterface(iface):
|
||||
return (iface.identifier.name in ["TestInterface",
|
||||
"TestJSImplInterface",
|
||||
"TestRenamedInterface"])
|
||||
|
||||
for member in self.interface.members:
|
||||
if not member.isAttr() and not member.isMethod():
|
||||
continue
|
||||
binaryName = member.getExtendedAttribute("BinaryName")
|
||||
if binaryName:
|
||||
assert isinstance(binaryName, list)
|
||||
assert len(binaryName) == 1
|
||||
self._binaryNames.setdefault(member.identifier.name,
|
||||
binaryName[0])
|
||||
|
||||
# Build the prototype chain.
|
||||
self.prototypeChain = []
|
||||
parent = interface
|
||||
while parent:
|
||||
self.prototypeChain.insert(0, parent.identifier.name)
|
||||
parent = parent.parent
|
||||
config.maxProtoChainLength = max(config.maxProtoChainLength,
|
||||
len(self.prototypeChain))
|
||||
|
||||
def binaryNameFor(self, name):
|
||||
return self._binaryNames.get(name, name)
|
||||
|
||||
@property
|
||||
def prototypeNameChain(self):
|
||||
return map(lambda p: self.getDescriptor(p).name, self.prototypeChain)
|
||||
|
||||
@property
|
||||
def parentPrototypeName(self):
|
||||
if len(self.prototypeChain) == 1:
|
||||
return None
|
||||
return self.getDescriptor(self.prototypeChain[-2]).name
|
||||
|
||||
def hasInterfaceOrInterfacePrototypeObject(self):
|
||||
|
||||
# Forward-declared interfaces don't need either interface object or
|
||||
# interface prototype object as they're going to use QI.
|
||||
if self.interface.isExternal():
|
||||
return False
|
||||
|
||||
return self.interface.hasInterfaceObject() or self.interface.hasInterfacePrototypeObject()
|
||||
|
||||
@property
|
||||
def hasNamedPropertiesObject(self):
|
||||
if self.interface.isExternal():
|
||||
return False
|
||||
|
||||
return self.isGlobal() and self.supportsNamedProperties()
|
||||
|
||||
def getExtendedAttributes(self, member, getter=False, setter=False):
|
||||
def ensureValidThrowsExtendedAttribute(attr):
|
||||
if (attr is not None and attr is not True):
|
||||
raise TypeError("Unknown value for 'Throws': " + attr[0])
|
||||
|
||||
def maybeAppendInfallibleToAttrs(attrs, throws):
|
||||
ensureValidThrowsExtendedAttribute(throws)
|
||||
if throws is None:
|
||||
attrs.append("infallible")
|
||||
|
||||
name = member.identifier.name
|
||||
throws = self.interface.isJSImplemented() or member.getExtendedAttribute("Throws")
|
||||
if member.isMethod():
|
||||
# JSObject-returning [NewObject] methods must be fallible,
|
||||
# since they have to (fallibly) allocate the new JSObject.
|
||||
if (member.getExtendedAttribute("NewObject") and
|
||||
methodReturnsJSObject(member)):
|
||||
throws = True
|
||||
attrs = self.extendedAttributes['all'].get(name, [])
|
||||
maybeAppendInfallibleToAttrs(attrs, throws)
|
||||
return attrs
|
||||
|
||||
assert member.isAttr()
|
||||
assert bool(getter) != bool(setter)
|
||||
key = 'getterOnly' if getter else 'setterOnly'
|
||||
attrs = self.extendedAttributes['all'].get(name, []) + self.extendedAttributes[key].get(name, [])
|
||||
if throws is None:
|
||||
throwsAttr = "GetterThrows" if getter else "SetterThrows"
|
||||
throws = member.getExtendedAttribute(throwsAttr)
|
||||
maybeAppendInfallibleToAttrs(attrs, throws)
|
||||
return attrs
|
||||
|
||||
def supportsIndexedProperties(self):
|
||||
return self.operations['IndexedGetter'] is not None
|
||||
|
||||
def supportsNamedProperties(self):
|
||||
return self.operations['NamedGetter'] is not None
|
||||
|
||||
def hasNonOrdinaryGetPrototypeOf(self):
|
||||
return self.interface.getExtendedAttribute("NonOrdinaryGetPrototypeOf")
|
||||
|
||||
def needsHeaderInclude(self):
|
||||
"""
|
||||
An interface doesn't need a header file if it is not concrete, not
|
||||
pref-controlled, has no prototype object, has no static methods or
|
||||
attributes and has no parent. The parent matters because we assert
|
||||
things about refcounting that depend on the actual underlying type if we
|
||||
have a parent.
|
||||
|
||||
"""
|
||||
return (self.interface.isExternal() or self.concrete or
|
||||
self.interface.hasInterfacePrototypeObject() or
|
||||
any((m.isAttr() or m.isMethod()) and m.isStatic() for m in self.interface.members) or
|
||||
self.interface.parent)
|
||||
|
||||
def hasThreadChecks(self):
|
||||
# isExposedConditionally does not necessarily imply thread checks
|
||||
# (since at least [SecureContext] is independent of them), but we're
|
||||
# only used to decide whether to include nsThreadUtils.h, so we don't
|
||||
# worry about that.
|
||||
return ((self.isExposedConditionally() and
|
||||
not self.interface.isExposedInWindow()) or
|
||||
self.interface.isExposedInSomeButNotAllWorkers())
|
||||
|
||||
def isExposedConditionally(self):
|
||||
return (self.interface.isExposedConditionally() or
|
||||
self.interface.isExposedInSomeButNotAllWorkers())
|
||||
|
||||
def needsXrayResolveHooks(self):
|
||||
"""
|
||||
Generally, any interface with NeedResolve needs Xray
|
||||
resolveOwnProperty and enumerateOwnProperties hooks. But for
|
||||
the special case of plugin-loading elements, we do NOT want
|
||||
those, because we don't want to instantiate plug-ins simply
|
||||
due to chrome touching them and that's all those hooks do on
|
||||
those elements. So we special-case those here.
|
||||
"""
|
||||
return (self.interface.getExtendedAttribute("NeedResolve") and
|
||||
self.interface.identifier.name not in ["HTMLObjectElement",
|
||||
"HTMLEmbedElement",
|
||||
"HTMLAppletElement"])
|
||||
def needsXrayNamedDeleterHook(self):
|
||||
return self.operations["NamedDeleter"] is not None
|
||||
|
||||
def needsSpecialGenericOps(self):
|
||||
"""
|
||||
Returns true if this descriptor requires generic ops other than
|
||||
GenericBindingMethod/GenericBindingGetter/GenericBindingSetter.
|
||||
|
||||
In practice we need to do this if our this value might be an XPConnect
|
||||
object or if we need to coerce null/undefined to the global.
|
||||
"""
|
||||
return self.hasXPConnectImpls or self.interface.isOnGlobalProtoChain()
|
||||
|
||||
def isGlobal(self):
|
||||
"""
|
||||
Returns true if this is the primary interface for a global object
|
||||
of some sort.
|
||||
"""
|
||||
return (self.interface.getExtendedAttribute("Global") or
|
||||
self.interface.getExtendedAttribute("PrimaryGlobal"))
|
||||
|
||||
@property
|
||||
def namedPropertiesEnumerable(self):
|
||||
"""
|
||||
Returns whether this interface should have enumerable named properties
|
||||
"""
|
||||
assert self.proxy
|
||||
assert self.supportsNamedProperties()
|
||||
iface = self.interface
|
||||
while iface:
|
||||
if iface.getExtendedAttribute("LegacyUnenumerableNamedProperties"):
|
||||
return False
|
||||
iface = iface.parent
|
||||
return True
|
||||
|
||||
@property
|
||||
def registersGlobalNamesOnWindow(self):
|
||||
return (not self.interface.isExternal() and
|
||||
self.interface.hasInterfaceObject() and
|
||||
self.interface.isExposedInWindow() and
|
||||
self.register)
|
||||
|
||||
def getDescriptor(self, interfaceName):
|
||||
"""
|
||||
Gets the appropriate descriptor for the given interface name.
|
||||
"""
|
||||
return self.config.getDescriptor(interfaceName)
|
||||
|
||||
|
||||
# Some utility methods
|
||||
def getTypesFromDescriptor(descriptor):
|
||||
"""
|
||||
Get all argument and return types for all members of the descriptor
|
||||
"""
|
||||
members = [m for m in descriptor.interface.members]
|
||||
if descriptor.interface.ctor():
|
||||
members.append(descriptor.interface.ctor())
|
||||
members.extend(descriptor.interface.namedConstructors)
|
||||
signatures = [s for m in members if m.isMethod() for s in m.signatures()]
|
||||
types = []
|
||||
for s in signatures:
|
||||
assert len(s) == 2
|
||||
(returnType, arguments) = s
|
||||
types.append(returnType)
|
||||
types.extend(a.type for a in arguments)
|
||||
|
||||
types.extend(a.type for a in members if a.isAttr())
|
||||
|
||||
if descriptor.interface.maplikeOrSetlikeOrIterable:
|
||||
maplikeOrSetlikeOrIterable = descriptor.interface.maplikeOrSetlikeOrIterable
|
||||
if maplikeOrSetlikeOrIterable.hasKeyType():
|
||||
types.append(maplikeOrSetlikeOrIterable.keyType)
|
||||
if maplikeOrSetlikeOrIterable.hasValueType():
|
||||
types.append(maplikeOrSetlikeOrIterable.valueType)
|
||||
return types
|
||||
|
||||
|
||||
def getFlatTypes(types):
|
||||
retval = set()
|
||||
for type in types:
|
||||
type = type.unroll()
|
||||
if type.isUnion():
|
||||
retval |= set(type.flatMemberTypes)
|
||||
else:
|
||||
retval.add(type)
|
||||
return retval
|
||||
|
||||
|
||||
def getTypesFromDictionary(dictionary):
|
||||
"""
|
||||
Get all member types for this dictionary
|
||||
"""
|
||||
types = []
|
||||
curDict = dictionary
|
||||
while curDict:
|
||||
types.extend([m.type for m in curDict.members])
|
||||
curDict = curDict.parent
|
||||
return types
|
||||
|
||||
|
||||
def getTypesFromCallback(callback):
|
||||
"""
|
||||
Get the types this callback depends on: its return type and the
|
||||
types of its arguments.
|
||||
"""
|
||||
sig = callback.signatures()[0]
|
||||
types = [sig[0]] # Return type
|
||||
types.extend(arg.type for arg in sig[1]) # Arguments
|
||||
return types
|
||||
|
||||
|
||||
def getAllTypes(descriptors, dictionaries, callbacks):
|
||||
"""
|
||||
Generate all the types we're dealing with. For each type, a tuple
|
||||
containing type, dictionary is yielded. The dictionary can be None if the
|
||||
type does not come from a dictionary.
|
||||
"""
|
||||
for d in descriptors:
|
||||
if d.interface.isExternal():
|
||||
continue
|
||||
for t in getTypesFromDescriptor(d):
|
||||
yield (t, None)
|
||||
for dictionary in dictionaries:
|
||||
for t in getTypesFromDictionary(dictionary):
|
||||
yield (t, dictionary)
|
||||
for callback in callbacks:
|
||||
for t in getTypesFromCallback(callback):
|
||||
yield (t, None)
|
||||
|
||||
def iteratorNativeType(descriptor):
|
||||
assert descriptor.interface.isIterable()
|
||||
iterableDecl = descriptor.interface.maplikeOrSetlikeOrIterable
|
||||
assert iterableDecl.isPairIterator()
|
||||
return "mozilla::dom::IterableIterator<%s>" % descriptor.nativeType
|
||||
Loading…
Add table
Add a link
Reference in a new issue