1 # This Source Code Form is subject to the terms of the Mozilla Public
2 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 # You can obtain one at http://mozilla.org/MPL/2.0/.
5 from WebIDL
import IDLInterface
, IDLExternalInterface
, IDLImplementsStatement
7 from collections
import defaultdict
9 autogenerated_comment
= "/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n"
13 Represents global configuration state based on IDL parse data and
14 the configuration file.
16 def __init__(self
, filename
, parseData
, generatedEvents
=[]):
18 # Read the configuration file.
20 execfile(filename
, glbl
)
21 config
= glbl
['DOMInterfaces']
23 # Build descriptors for all the interfaces we have in the parse data.
24 # This allows callers to specify a subset of interfaces by filtering
28 self
.generatedEvents
= generatedEvents
;
29 self
.maxProtoChainLength
= 0;
30 for thing
in parseData
:
31 if isinstance(thing
, IDLImplementsStatement
):
32 # Our build system doesn't support dep build involving
33 # addition/removal of "implements" statements that appear in a
34 # different .webidl file than their LHS interface. Make sure we
35 # don't have any of those.
37 # But whitelist a RHS that is LegacyQueryInterface,
38 # since people shouldn't be adding any of those.
39 if (thing
.implementor
.filename() != thing
.filename() and
40 thing
.implementee
.identifier
.name
!= "LegacyQueryInterface"):
42 "The binding build system doesn't really support "
43 "'implements' statements which don't appear in the "
44 "file in which the left-hand side of the statement is "
45 "defined. Don't do this unless your right-hand side "
46 "is LegacyQueryInterface.\n"
49 (thing
.location
, thing
.implementor
.location
))
50 # Some toplevel things are sadly types, and those have an
51 # isInterface that doesn't mean the same thing as IDLObject's
53 if (not isinstance(thing
, IDLInterface
) and
54 not isinstance(thing
, IDLExternalInterface
)):
57 self
.interfaces
[iface
.identifier
.name
] = iface
58 if iface
.identifier
.name
not in config
:
59 # Completely skip consequential interfaces with no descriptor
60 # if they have no interface object because chances are we
61 # don't need to do anything interesting with them.
62 if iface
.isConsequential() and not iface
.hasInterfaceObject():
66 entry
= config
[iface
.identifier
.name
]
67 if not isinstance(entry
, list):
68 assert isinstance(entry
, dict)
71 if entry
[0].get("workers", False):
72 # List with only a workers descriptor means we should
73 # infer a mainthread descriptor. If you want only
74 # workers bindings, don't use a list here.
77 raise TypeError("Don't use a single-element list for "
78 "non-worker-only interface " + iface
.identifier
.name
+
81 if entry
[0].get("workers", False) == entry
[1].get("workers", False):
82 raise TypeError("The two entries for interface " + iface
.identifier
.name
+
83 " in Bindings.conf should not have the same value for 'workers'")
85 raise TypeError("Interface " + iface
.identifier
.name
+
86 " should have no more than two entries in Bindings.conf")
87 self
.descriptors
.extend([Descriptor(self
, iface
, x
) for x
in entry
])
89 # Keep the descriptor list sorted for determinism.
90 self
.descriptors
.sort(lambda x
,y
: cmp(x
.name
, y
.name
))
92 self
.descriptorsByName
= {}
93 for d
in self
.descriptors
:
94 self
.descriptorsByName
.setdefault(d
.interface
.identifier
.name
,
97 self
.descriptorsByFile
= {}
98 for d
in self
.descriptors
:
99 self
.descriptorsByFile
.setdefault(d
.interface
.filename(),
102 self
.enums
= [e
for e
in parseData
if e
.isEnum()]
104 # Figure out what our main-thread and worker dictionaries and callbacks
107 for descriptor
in ([self
.getDescriptor("DummyInterface", workers
=False)] +
108 self
.getDescriptors(workers
=False, isExternal
=False, skipGen
=False)):
109 mainTypes |
= set(getFlatTypes(getTypesFromDescriptor(descriptor
)))
110 (mainCallbacks
, mainDictionaries
) = findCallbacksAndDictionaries(mainTypes
)
113 for descriptor
in ([self
.getDescriptor("DummyInterfaceWorkers", workers
=True)] +
114 self
.getDescriptors(workers
=True, isExternal
=False, skipGen
=False)):
115 workerTypes |
= set(getFlatTypes(getTypesFromDescriptor(descriptor
)))
116 (workerCallbacks
, workerDictionaries
) = findCallbacksAndDictionaries(workerTypes
)
118 self
.dictionaries
= [d
for d
in parseData
if d
.isDictionary()]
119 self
.callbacks
= [c
for c
in parseData
if
120 c
.isCallback() and not c
.isInterface()]
122 # Dictionary mapping from a union type name to a set of filenames where
123 # union types with that name are used.
124 self
.filenamesPerUnion
= defaultdict(set)
126 # Dictionary mapping from a filename to a list of tuples containing a
127 # type and descriptor for the union types used in that file. If a union
128 # type is used in multiple files then it will be added to the list
129 # for the None key. Note that the list contains a tuple for every use of
130 # a union type, so there can be multiple tuples with union types that
131 # have the same name.
132 self
.unionsPerFilename
= defaultdict(list)
134 for (t
, descriptor
, _
) in getAllTypes(self
.descriptors
, self
.dictionaries
, self
.callbacks
):
139 filenamesForUnion
= self
.filenamesPerUnion
[t
.name
]
140 if t
.filename() not in filenamesForUnion
:
141 if len(filenamesForUnion
) == 0:
142 # This is the first file that we found a union with this
143 # name in, record the union as part of the file.
144 uniqueFilenameForUnion
= t
.filename()
146 # We already found a file that contains a union with
148 if len(filenamesForUnion
) == 1:
149 # This is the first time we found a union with this
150 # name in another file.
151 for f
in filenamesForUnion
:
152 # Filter out unions with this name from the
153 # unions for the file where we previously found
155 unionsForFilename
= self
.unionsPerFilename
[f
]
156 unionsForFilename
= filter(lambda u
: u
[0].name
!= t
.name
,
158 if len(unionsForFilename
) == 0:
159 del self
.unionsPerFilename
[f
]
161 self
.unionsPerFilename
[f
] = unionsForFilename
162 # Unions with this name appear in multiple files, record
163 # the filename as None, so that we can detect that.
164 uniqueFilenameForUnion
= None
165 self
.unionsPerFilename
[uniqueFilenameForUnion
].append((t
, descriptor
))
166 filenamesForUnion
.add(t
.filename())
168 def flagWorkerOrMainThread(items
, main
, worker
):
171 item
.setUserData("mainThread", True)
173 item
.setUserData("workers", True)
174 flagWorkerOrMainThread(self
.callbacks
, mainCallbacks
, workerCallbacks
)
176 def getInterface(self
, ifname
):
177 return self
.interfaces
[ifname
]
178 def getDescriptors(self
, **filters
):
179 """Gets the descriptors that match the given filters."""
180 curr
= self
.descriptors
181 # Collect up our filters, because we may have a webIDLFile filter that
182 # we always want to apply first.
184 for key
, val
in filters
.iteritems():
185 if key
== 'webIDLFile':
186 # Special-case this part to make it fast, since most of our
187 # getDescriptors calls are conditioned on a webIDLFile. We may
188 # not have this key, in which case we have no descriptors
190 curr
= self
.descriptorsByFile
.get(val
, [])
192 elif key
== 'hasInterfaceObject':
193 getter
= lambda x
: (not x
.interface
.isExternal() and
194 x
.interface
.hasInterfaceObject())
195 elif key
== 'hasInterfacePrototypeObject':
196 getter
= lambda x
: (not x
.interface
.isExternal() and
197 x
.interface
.hasInterfacePrototypeObject())
198 elif key
== 'hasInterfaceOrInterfacePrototypeObject':
199 getter
= lambda x
: x
.hasInterfaceOrInterfacePrototypeObject()
200 elif key
== 'isCallback':
201 getter
= lambda x
: x
.interface
.isCallback()
202 elif key
== 'isExternal':
203 getter
= lambda x
: x
.interface
.isExternal()
204 elif key
== 'isJSImplemented':
205 getter
= lambda x
: x
.interface
.isJSImplemented()
206 elif key
== 'isNavigatorProperty':
207 getter
= lambda x
: x
.interface
.getNavigatorProperty() != None
208 elif key
== 'isExposedInAnyWorker':
209 getter
= lambda x
: (not x
.interface
.isExternal() and
210 x
.interface
.isExposedInAnyWorker())
211 elif key
== 'isExposedInSystemGlobals':
212 getter
= lambda x
: (not x
.interface
.isExternal() and
213 x
.interface
.isExposedInSystemGlobals())
214 elif key
== 'isExposedInWindow':
215 getter
= lambda x
: (not x
.interface
.isExternal() and
216 x
.interface
.isExposedInWindow())
218 # Have to watch out: just closing over "key" is not enough,
219 # since we're about to mutate its value
220 getter
= (lambda attrName
: lambda x
: getattr(x
, attrName
))(key
)
221 tofilter
.append((getter
, val
))
223 curr
= filter(lambda x
: f
[0](x
) == f
[1], curr
)
225 def getEnums(self
, webIDLFile
):
226 return filter(lambda e
: e
.filename() == webIDLFile
, self
.enums
)
229 def _filterForFileAndWorkers(items
, filters
):
230 """Gets the items that match the given filters."""
231 for key
, val
in filters
.iteritems():
232 if key
== 'webIDLFile':
233 items
= filter(lambda x
: x
.filename() == val
, items
)
234 elif key
== 'workers':
236 items
= filter(lambda x
: x
.getUserData("workers", False), items
)
238 items
= filter(lambda x
: x
.getUserData("mainThread", False), items
)
240 assert(0) # Unknown key
242 def getDictionaries(self
, **filters
):
243 return self
._filterForFileAndWorkers
(self
.dictionaries
, filters
)
244 def getCallbacks(self
, **filters
):
245 return self
._filterForFileAndWorkers
(self
.callbacks
, filters
)
247 def getDescriptor(self
, interfaceName
, workers
):
249 Gets the appropriate descriptor for the given interface name
250 and the given workers boolean.
252 for d
in self
.descriptorsByName
[interfaceName
]:
253 if d
.workers
== workers
:
257 for d
in self
.descriptorsByName
[interfaceName
]:
260 raise NoSuchDescriptorError("For " + interfaceName
+ " found no matches");
261 def getDescriptorProvider(self
, workers
):
263 Gets a descriptor provider that can provide descriptors as needed,
264 for the given workers boolean
266 return DescriptorProvider(self
, workers
)
268 class NoSuchDescriptorError(TypeError):
269 def __init__(self
, str):
270 TypeError.__init
__(self
, str)
272 class DescriptorProvider
:
274 A way of getting descriptors for interface names
276 def __init__(self
, config
, workers
):
278 self
.workers
= workers
280 def getDescriptor(self
, interfaceName
):
282 Gets the appropriate descriptor for the given interface name given the
283 context of the current descriptor. This selects the appropriate
284 implementation for cases like workers.
286 return self
.config
.getDescriptor(interfaceName
, self
.workers
)
288 def methodReturnsJSObject(method
):
289 assert method
.isMethod()
290 if method
.returnsPromise():
293 for signature
in method
.signatures():
294 returnType
= signature
[0]
295 if returnType
.isObject() or returnType
.isSpiderMonkeyInterface():
300 class Descriptor(DescriptorProvider
):
302 Represents a single descriptor for an interface. See Bindings.conf.
304 def __init__(self
, config
, interface
, desc
):
305 DescriptorProvider
.__init
__(self
, config
, desc
.get('workers', False))
306 self
.interface
= interface
308 # Read the desc, and fill in the relevant defaults.
309 ifaceName
= self
.interface
.identifier
.name
310 if self
.interface
.isExternal():
312 nativeTypeDefault
= "JSObject"
314 nativeTypeDefault
= "nsIDOM" + ifaceName
315 elif self
.interface
.isCallback():
316 nativeTypeDefault
= "mozilla::dom::" + ifaceName
319 nativeTypeDefault
= "mozilla::dom::workers::" + ifaceName
321 nativeTypeDefault
= "mozilla::dom::" + ifaceName
323 self
.nativeType
= desc
.get('nativeType', nativeTypeDefault
)
324 # Now create a version of nativeType that doesn't have extra
325 # mozilla::dom:: at the beginning.
326 prettyNativeType
= self
.nativeType
.split("::")
327 if prettyNativeType
[0] == "mozilla":
328 prettyNativeType
.pop(0)
329 if prettyNativeType
[0] == "dom":
330 prettyNativeType
.pop(0)
331 self
.prettyNativeType
= "::".join(prettyNativeType
)
333 self
.jsImplParent
= desc
.get('jsImplParent', self
.nativeType
)
335 # Do something sane for JSObject
336 if self
.nativeType
== "JSObject":
337 headerDefault
= "js/TypeDecls.h"
338 elif self
.interface
.isCallback() or self
.interface
.isJSImplemented():
339 # A copy of CGHeaders.getDeclarationFilename; we can't
340 # import it here, sadly.
341 # Use our local version of the header, not the exported one, so that
342 # test bindings, which don't export, will work correctly.
343 basename
= os
.path
.basename(self
.interface
.filename())
344 headerDefault
= basename
.replace('.webidl', 'Binding.h')
347 headerDefault
= "mozilla/dom/workers/bindings/%s.h" % ifaceName
348 elif not self
.interface
.isExternal() and self
.interface
.getExtendedAttribute("HeaderFile"):
349 headerDefault
= self
.interface
.getExtendedAttribute("HeaderFile")[0]
351 headerDefault
= self
.nativeType
352 headerDefault
= headerDefault
.replace("::", "/") + ".h"
353 self
.headerFile
= desc
.get('headerFile', headerDefault
)
354 self
.headerIsDefault
= self
.headerFile
== headerDefault
355 if self
.jsImplParent
== self
.nativeType
:
356 self
.jsImplParentHeader
= self
.headerFile
358 self
.jsImplParentHeader
= self
.jsImplParent
.replace("::", "/") + ".h"
360 self
.skipGen
= desc
.get('skipGen', False)
362 self
.notflattened
= desc
.get('notflattened', False)
363 self
.register
= desc
.get('register', True)
365 self
.hasXPConnectImpls
= desc
.get('hasXPConnectImpls', False)
367 # If we're concrete, we need to crawl our ancestor interfaces and mark
368 # them as having a concrete descendant.
369 self
.concrete
= (not self
.interface
.isExternal() and
370 not self
.interface
.isCallback() and
371 desc
.get('concrete', True))
373 'IndexedGetter': None,
374 'IndexedSetter': None,
375 'IndexedCreator': None,
376 'IndexedDeleter': None,
379 'NamedCreator': None,
380 'NamedDeleter': None,
382 'LegacyCaller': None,
385 # Stringifiers and jsonifiers need to be set up whether an interface is
386 # concrete or not, because they're actually prototype methods and hence
387 # can apply to instances of descendant interfaces. Legacy callers and
388 # named/indexed operations only need to be set up on concrete
389 # interfaces, since they affect the JSClass we end up using, not the
391 def addOperation(operation
, m
):
392 if not self
.operations
[operation
]:
393 self
.operations
[operation
] = m
395 # Since stringifiers go on the prototype, we only need to worry
396 # about our own stringifier, not those of our ancestor interfaces.
397 if not self
.interface
.isExternal():
398 for m
in self
.interface
.members
:
399 if m
.isMethod() and m
.isStringifier():
400 addOperation('Stringifier', m
)
401 if m
.isMethod() and m
.isJsonifier():
402 addOperation('Jsonifier', m
)
406 iface
= self
.interface
407 for m
in iface
.members
:
408 # Don't worry about inheriting legacycallers either: in
409 # practice these are on most-derived prototypes.
410 if m
.isMethod() and m
.isLegacycaller():
411 if not m
.isIdentifierLess():
412 raise TypeError("We don't support legacycaller with "
413 "identifier.\n%s" % m
.location
);
414 if len(m
.signatures()) != 1:
415 raise TypeError("We don't support overloaded "
416 "legacycaller.\n%s" % m
.location
)
417 addOperation('LegacyCaller', m
)
419 for m
in iface
.members
:
423 def addIndexedOrNamedOperation(operation
, m
):
425 operation
= 'Indexed' + operation
428 operation
= 'Named' + operation
429 addOperation(operation
, m
)
432 addIndexedOrNamedOperation('Getter', m
)
434 addIndexedOrNamedOperation('Setter', m
)
436 addIndexedOrNamedOperation('Creator', m
)
438 addIndexedOrNamedOperation('Deleter', m
)
439 if m
.isLegacycaller() and iface
!= self
.interface
:
440 raise TypeError("We don't support legacycaller on "
441 "non-leaf interface %s.\n%s" %
442 (iface
, iface
.location
))
444 iface
.setUserData('hasConcreteDescendant', True)
447 self
.proxy
= (self
.supportsIndexedProperties() or
448 (self
.supportsNamedProperties() and
449 not self
.hasNamedPropertiesObject
))
452 if (not self
.operations
['IndexedGetter'] and
453 (self
.operations
['IndexedSetter'] or
454 self
.operations
['IndexedDeleter'] or
455 self
.operations
['IndexedCreator'])):
456 raise SyntaxError("%s supports indexed properties but does "
457 "not have an indexed getter.\n%s" %
458 (self
.interface
, self
.interface
.location
))
459 if (not self
.operations
['NamedGetter'] and
460 (self
.operations
['NamedSetter'] or
461 self
.operations
['NamedDeleter'] or
462 self
.operations
['NamedCreator'])):
463 raise SyntaxError("%s supports named properties but does "
464 "not have a named getter.\n%s" %
465 (self
.interface
, self
.interface
.location
))
466 iface
= self
.interface
468 iface
.setUserData('hasProxyDescendant', True)
471 self
.nativeOwnership
= desc
.get('nativeOwnership', 'refcounted')
472 if not self
.nativeOwnership
in ('owned', 'refcounted'):
473 raise TypeError("Descriptor for %s has unrecognized value (%s) "
474 "for nativeOwnership" %
475 (self
.interface
.identifier
.name
, self
.nativeOwnership
))
476 if desc
.get('wantsQI', None) != None:
477 self
._wantsQI
= desc
.get('wantsQI', None)
478 self
.wrapperCache
= (not self
.interface
.isCallback() and
479 (self
.nativeOwnership
!= 'owned' and
480 desc
.get('wrapperCache', True)))
483 return name
+ "_workers" if self
.workers
else name
484 self
.name
= make_name(interface
.identifier
.name
)
486 # self.extendedAttributes is a dict of dicts, keyed on
487 # all/getterOnly/setterOnly and then on member name. Values are an
488 # array of extended attributes.
489 self
.extendedAttributes
= { 'all': {}, 'getterOnly': {}, 'setterOnly': {} }
491 def addExtendedAttribute(attribute
, config
):
492 def add(key
, members
, attribute
):
493 for member
in members
:
494 self
.extendedAttributes
[key
].setdefault(member
, []).append(attribute
)
496 if isinstance(config
, dict):
497 for key
in ['all', 'getterOnly', 'setterOnly']:
498 add(key
, config
.get(key
, []), attribute
)
499 elif isinstance(config
, list):
500 add('all', config
, attribute
)
502 assert isinstance(config
, str)
504 iface
= self
.interface
506 add('all', map(lambda m
: m
.name
, iface
.members
), attribute
)
509 add('all', [config
], attribute
)
511 if self
.interface
.isJSImplemented():
512 addExtendedAttribute('implicitJSContext', ['constructor'])
514 for attribute
in ['implicitJSContext']:
515 addExtendedAttribute(attribute
, desc
.get(attribute
, {}))
517 self
._binaryNames
= desc
.get('binaryNames', {})
518 self
._binaryNames
.setdefault('__legacycaller', 'LegacyCall')
519 self
._binaryNames
.setdefault('__stringifier', 'Stringify')
521 if not self
.interface
.isExternal():
522 self
.permissions
= dict()
524 # Adds a permission list to this descriptor and returns the index to use.
525 def addPermissions(ifaceOrMember
):
526 checkPermissions
= ifaceOrMember
.getExtendedAttribute("CheckPermissions")
527 if checkPermissions
is None:
530 # It's a list of whitespace-separated strings
531 assert(len(checkPermissions
) is 1)
532 assert(checkPermissions
[0] is not None)
533 checkPermissions
= checkPermissions
[0]
534 permissionsList
= checkPermissions
.split()
535 if len(permissionsList
) == 0:
536 raise TypeError("Need at least one permission name for CheckPermissions")
538 permissionsList
= tuple(sorted(set(permissionsList
)))
539 return self
.permissions
.setdefault(permissionsList
, len(self
.permissions
))
541 self
.checkPermissionsIndex
= addPermissions(self
.interface
)
542 self
.checkPermissionsIndicesForMembers
= dict()
543 for m
in self
.interface
.members
:
544 permissionsIndex
= addPermissions(m
)
545 if permissionsIndex
is not None:
546 self
.checkPermissionsIndicesForMembers
[m
.identifier
.name
] = permissionsIndex
548 def isTestInterface(iface
):
549 return (iface
.identifier
.name
in ["TestInterface",
550 "TestJSImplInterface",
551 "TestRenamedInterface"])
553 self
.featureDetectibleThings
= set()
554 if not isTestInterface(self
.interface
):
555 if (self
.interface
.getExtendedAttribute("CheckPermissions") or
556 self
.interface
.getExtendedAttribute("AvailableIn") == "PrivilegedApps"):
557 if self
.interface
.getNavigatorProperty():
558 self
.featureDetectibleThings
.add("Navigator.%s" % self
.interface
.getNavigatorProperty())
560 iface
= self
.interface
.identifier
.name
561 self
.featureDetectibleThings
.add(iface
)
562 for m
in self
.interface
.members
:
563 self
.featureDetectibleThings
.add("%s.%s" % (iface
, m
.identifier
.name
))
565 for m
in self
.interface
.members
:
566 if (m
.getExtendedAttribute("CheckPermissions") or
567 m
.getExtendedAttribute("AvailableIn") == "PrivilegedApps"):
568 self
.featureDetectibleThings
.add("%s.%s" % (self
.interface
.identifier
.name
, m
.identifier
.name
))
570 for member
in self
.interface
.members
:
571 if not member
.isAttr() and not member
.isMethod():
573 binaryName
= member
.getExtendedAttribute("BinaryName")
575 assert isinstance(binaryName
, list)
576 assert len(binaryName
) == 1
577 self
._binaryNames
.setdefault(member
.identifier
.name
,
580 # Build the prototype chain.
581 self
.prototypeChain
= []
584 self
.prototypeChain
.insert(0, parent
.identifier
.name
)
585 parent
= parent
.parent
586 config
.maxProtoChainLength
= max(config
.maxProtoChainLength
,
587 len(self
.prototypeChain
))
589 def binaryNameFor(self
, name
):
590 return self
._binaryNames
.get(name
, name
)
593 def prototypeNameChain(self
):
594 return map(lambda p
: self
.getDescriptor(p
).name
, self
.prototypeChain
)
597 def parentPrototypeName(self
):
598 if len(self
.prototypeChain
) == 1:
600 return self
.getDescriptor(self
.prototypeChain
[-2]).name
602 def hasInterfaceOrInterfacePrototypeObject(self
):
604 # Forward-declared interfaces don't need either interface object or
605 # interface prototype object as they're going to use QI (on main thread)
606 # or be passed as a JSObject (on worker threads).
607 if self
.interface
.isExternal():
610 return self
.interface
.hasInterfaceObject() or self
.interface
.hasInterfacePrototypeObject()
613 def hasNamedPropertiesObject(self
):
614 if self
.interface
.isExternal():
617 return self
.isGlobal() and self
.supportsNamedProperties()
619 def getExtendedAttributes(self
, member
, getter
=False, setter
=False):
620 def ensureValidThrowsExtendedAttribute(attr
):
621 assert(attr
is None or attr
is True or len(attr
) == 1)
622 if (attr
is not None and attr
is not True and
623 'Workers' not in attr
and 'MainThread' not in attr
):
624 raise TypeError("Unknown value for 'Throws': " + attr
[0])
626 def maybeAppendInfallibleToAttrs(attrs
, throws
):
627 ensureValidThrowsExtendedAttribute(throws
)
628 if (throws
is None or
629 (throws
is not True and
630 ('Workers' not in throws
or not self
.workers
) and
631 ('MainThread' not in throws
or self
.workers
))):
632 attrs
.append("infallible")
634 name
= member
.identifier
.name
635 throws
= self
.interface
.isJSImplemented() or member
.getExtendedAttribute("Throws")
636 if member
.isMethod():
637 # JSObject-returning [NewObject] methods must be fallible,
638 # since they have to (fallibly) allocate the new JSObject.
639 if (member
.getExtendedAttribute("NewObject") and
640 methodReturnsJSObject(member
)):
642 attrs
= self
.extendedAttributes
['all'].get(name
, [])
643 maybeAppendInfallibleToAttrs(attrs
, throws
)
646 assert member
.isAttr()
647 assert bool(getter
) != bool(setter
)
648 key
= 'getterOnly' if getter
else 'setterOnly'
649 attrs
= self
.extendedAttributes
['all'].get(name
, []) + self
.extendedAttributes
[key
].get(name
, [])
651 throwsAttr
= "GetterThrows" if getter
else "SetterThrows"
652 throws
= member
.getExtendedAttribute(throwsAttr
)
653 maybeAppendInfallibleToAttrs(attrs
, throws
)
656 def supportsIndexedProperties(self
):
657 return self
.operations
['IndexedGetter'] is not None
659 def supportsNamedProperties(self
):
660 return self
.operations
['NamedGetter'] is not None
662 def needsConstructHookHolder(self
):
663 assert self
.interface
.hasInterfaceObject()
666 def needsHeaderInclude(self
):
668 An interface doesn't need a header file if it is not concrete,
669 not pref-controlled, has no prototype object, and has no
670 static methods or attributes.
672 return (self
.interface
.isExternal() or self
.concrete
or
673 self
.interface
.hasInterfacePrototypeObject() or
674 any((m
.isAttr() or m
.isMethod()) and m
.isStatic() for m
675 in self
.interface
.members
))
677 def hasThreadChecks(self
):
678 return ((self
.isExposedConditionally() and
679 not self
.interface
.isExposedInWindow()) or
680 self
.interface
.isExposedInSomeButNotAllWorkers())
682 def isExposedConditionally(self
):
683 return (self
.interface
.isExposedConditionally() or
684 self
.interface
.isExposedInSomeButNotAllWorkers())
686 def needsXrayResolveHooks(self
):
688 Generally, any interface with NeedResolve needs Xray
689 resolveOwnProperty and enumerateOwnProperties hooks. But for
690 the special case of plugin-loading elements, we do NOT want
691 those, because we don't want to instantiate plug-ins simply
692 due to chrome touching them and that's all those hooks do on
693 those elements. So we special-case those here.
695 return (self
.interface
.getExtendedAttribute("NeedResolve") and
696 self
.interface
.identifier
.name
not in ["HTMLObjectElement",
698 "HTMLAppletElement"])
700 def needsSpecialGenericOps(self
):
702 Returns true if this descriptor requires generic ops other than
703 GenericBindingMethod/GenericBindingGetter/GenericBindingSetter.
705 In practice we need to do this if our this value might be an XPConnect
706 object or if we need to coerce null/undefined to the global.
708 return self
.hasXPConnectImpls
or self
.interface
.isOnGlobalProtoChain()
712 Returns true if this is the primary interface for a global object
715 return (self
.interface
.getExtendedAttribute("Global") or
716 self
.interface
.getExtendedAttribute("PrimaryGlobal"))
718 # Some utility methods
719 def getTypesFromDescriptor(descriptor
):
721 Get all argument and return types for all members of the descriptor
723 members
= [m
for m
in descriptor
.interface
.members
]
724 if descriptor
.interface
.ctor():
725 members
.append(descriptor
.interface
.ctor())
726 members
.extend(descriptor
.interface
.namedConstructors
)
727 signatures
= [s
for m
in members
if m
.isMethod() for s
in m
.signatures()]
731 (returnType
, arguments
) = s
732 types
.append(returnType
)
733 types
.extend(a
.type for a
in arguments
)
735 types
.extend(a
.type for a
in members
if a
.isAttr())
738 def getFlatTypes(types
):
743 retval |
= set(type.flatMemberTypes
)
748 def getTypesFromDictionary(dictionary
):
750 Get all member types for this dictionary
755 types
.extend([m
.type for m
in curDict
.members
])
756 curDict
= curDict
.parent
759 def getTypesFromCallback(callback
):
761 Get the types this callback depends on: its return type and the
762 types of its arguments.
764 sig
= callback
.signatures()[0]
765 types
= [sig
[0]] # Return type
766 types
.extend(arg
.type for arg
in sig
[1]) # Arguments
769 def findCallbacksAndDictionaries(inputTypes
):
771 Ensure that all callbacks and dictionaries reachable from types end up in
772 the returned callbacks and dictionaries sets.
774 Note that we assume that our initial invocation already includes all types
775 reachable via descriptors in "types", so we only have to deal with things
776 that are themeselves reachable via callbacks and dictionaries.
778 def doFindCallbacksAndDictionaries(types
, callbacks
, dictionaries
):
779 unhandledTypes
= set()
781 if type.isCallback() and type not in callbacks
:
782 unhandledTypes |
= getFlatTypes(getTypesFromCallback(type))
784 elif type.isDictionary() and type.inner
not in dictionaries
:
786 unhandledTypes |
= getFlatTypes(getTypesFromDictionary(d
))
790 if len(unhandledTypes
) != 0:
791 doFindCallbacksAndDictionaries(unhandledTypes
, callbacks
, dictionaries
)
794 retDictionaries
= set()
795 doFindCallbacksAndDictionaries(inputTypes
, retCallbacks
, retDictionaries
)
796 return (retCallbacks
, retDictionaries
)
798 def getAllTypes(descriptors
, dictionaries
, callbacks
):
800 Generate all the types we're dealing with. For each type, a tuple
801 containing type, descriptor, dictionary is yielded. The
802 descriptor and dictionary can be None if the type does not come
803 from a descriptor or dictionary; they will never both be non-None.
805 for d
in descriptors
:
806 if d
.interface
.isExternal():
808 for t
in getTypesFromDescriptor(d
):
810 for dictionary
in dictionaries
:
811 for t
in getTypesFromDictionary(dictionary
):
812 yield (t
, None, dictionary
)
813 for callback
in callbacks
:
814 for t
in getTypesFromCallback(callback
):
815 yield (t
, None, None)