Bug 1936278 - Prevent search mode chiclet from being dismissed when clicking in page...
[gecko.git] / dom / bindings / Configuration.py
blob10762b24e713f48a1a6908d021b8259161e5e248
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 import io
6 import itertools
7 import os
8 from collections import defaultdict
10 from WebIDL import IDLIncludesStatement
12 autogenerated_comment = "/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n"
15 def toStringBool(arg):
16 """
17 Converts IDL/Python Boolean (True/False) to C++ Boolean (true/false)
18 """
19 return str(not not arg).lower()
22 class DescriptorProvider:
23 """
24 A way of getting descriptors for interface names. Subclasses must
25 have a getDescriptor method callable with the interface name only.
27 Subclasses must also have a getConfig() method that returns a
28 Configuration.
29 """
31 def __init__(self):
32 pass
35 def isChildPath(path, basePath):
36 path = os.path.normpath(path)
37 return os.path.commonprefix((path, basePath)) == basePath
40 class Configuration(DescriptorProvider):
41 """
42 Represents global configuration state based on IDL parse data and
43 the configuration file.
44 """
46 class IDLAttrGetterOrSetterTemplate:
47 class TemplateAdditionalArg:
48 def __init__(self, type, name, value=None):
49 self.type = type
50 self.name = name
51 self.value = value
53 def __init__(self, template, getter, setter, argument, attrName):
54 self.descriptor = None
55 self.usedInOtherInterfaces = False
56 self.getter = getter
57 self.setter = setter
58 self.argument = (
59 Configuration.IDLAttrGetterOrSetterTemplate.TemplateAdditionalArg(
60 *argument
63 self.attrNameString = attrName
64 self.attr = None
66 class TemplateIDLAttribute:
67 def __init__(self, attr):
68 assert attr.isAttr()
69 assert not attr.isMaplikeOrSetlikeAttr()
70 assert not attr.slotIndices
72 self.identifier = attr.identifier
73 self.type = attr.type
74 self.extendedAttributes = attr.getExtendedAttributes()
75 self.slotIndices = None
77 def getExtendedAttribute(self, name):
78 return self.extendedAttributes.get(name)
80 def isAttr(self):
81 return True
83 def isMaplikeOrSetlikeAttr(self):
84 return False
86 def isMethod(self):
87 return False
89 def isStatic(self):
90 return False
92 def __init__(self, filename, webRoots, parseData, generatedEvents=[]):
93 DescriptorProvider.__init__(self)
95 # Read the configuration file.
96 glbl = {}
97 exec(io.open(filename, encoding="utf-8").read(), glbl)
98 config = glbl["DOMInterfaces"]
100 self.attributeTemplates = dict()
101 attributeTemplatesByInterface = dict()
102 for interface, templates in glbl["TemplatedAttributes"].items():
103 for template in templates:
104 name = template.get("template")
105 t = Configuration.IDLAttrGetterOrSetterTemplate(**template)
106 self.attributeTemplates[name] = t
107 attributeTemplatesByInterface.setdefault(interface, list()).append(t)
109 webRoots = tuple(map(os.path.normpath, webRoots))
111 def isInWebIDLRoot(path):
112 return any(isChildPath(path, root) for root in webRoots)
114 # Build descriptors for all the interfaces we have in the parse data.
115 # This allows callers to specify a subset of interfaces by filtering
116 # |parseData|.
117 self.descriptors = []
118 self.interfaces = {}
119 self.descriptorsByName = {}
120 self.dictionariesByName = {}
121 self.generatedEvents = generatedEvents
122 self.maxProtoChainLength = 0
123 for thing in parseData:
124 if isinstance(thing, IDLIncludesStatement):
125 # Our build system doesn't support dep build involving
126 # addition/removal of "includes" statements that appear in a
127 # different .webidl file than their LHS interface. Make sure we
128 # don't have any of those. See similar block below for partial
129 # interfaces!
130 if thing.interface.filename != thing.filename:
131 raise TypeError(
132 "The binding build system doesn't really support "
133 "'includes' statements which don't appear in the "
134 "file in which the left-hand side of the statement is "
135 "defined.\n"
136 "%s\n"
137 "%s" % (thing.location, thing.interface.location)
140 assert not thing.isType()
142 if (
143 not thing.isInterface()
144 and not thing.isNamespace()
145 and not thing.isInterfaceMixin()
147 continue
148 # Our build system doesn't support dep builds involving
149 # addition/removal of partial interfaces/namespaces/mixins that
150 # appear in a different .webidl file than the
151 # interface/namespace/mixin they are extending. Make sure we don't
152 # have any of those. See similar block above for "includes"
153 # statements!
154 if not thing.isExternal():
155 for partial in thing.getPartials():
156 if partial.filename != thing.filename:
157 raise TypeError(
158 "The binding build system doesn't really support "
159 "partial interfaces/namespaces/mixins which don't "
160 "appear in the file in which the "
161 "interface/namespace/mixin they are extending is "
162 "defined. Don't do this.\n"
163 "%s\n"
164 "%s" % (partial.location, thing.location)
167 # The rest of the logic doesn't apply to mixins.
168 if thing.isInterfaceMixin():
169 continue
171 iface = thing
172 if not iface.isExternal():
173 if not (
174 iface.getExtendedAttribute("ChromeOnly")
175 or iface.getExtendedAttribute("Func")
176 == ["nsContentUtils::IsCallerChromeOrFuzzingEnabled"]
177 or not iface.hasInterfaceObject()
178 or isInWebIDLRoot(iface.filename)
180 raise TypeError(
181 "Interfaces which are exposed to the web may only be "
182 "defined in a DOM WebIDL root %r. Consider marking "
183 "the interface [ChromeOnly] or "
184 "[Func='nsContentUtils::IsCallerChromeOrFuzzingEnabled'] "
185 "if you do not want it exposed to the web.\n"
186 "%s" % (webRoots, iface.location)
189 self.interfaces[iface.identifier.name] = iface
191 entry = config.pop(iface.identifier.name, {})
192 assert not isinstance(entry, list)
194 desc = Descriptor(
195 self,
196 iface,
197 entry,
198 attributeTemplatesByInterface.get(iface.identifier.name),
200 self.descriptors.append(desc)
201 # Setting up descriptorsByName while iterating through interfaces
202 # means we can get the nativeType of iterable interfaces without
203 # having to do multiple loops.
204 assert desc.interface.identifier.name not in self.descriptorsByName
205 self.descriptorsByName[desc.interface.identifier.name] = desc
207 if len(config) > 0:
208 raise NoSuchDescriptorError(
209 "Bindings.conf contains entries for "
210 + str(list(config))
211 + " that aren't declared as interfaces in the .webidl files."
214 # Keep the descriptor list sorted for determinism.
215 self.descriptors.sort(key=lambda x: x.name)
217 self.descriptorsByFile = {}
218 for d in self.descriptors:
219 self.descriptorsByFile.setdefault(d.interface.filename, []).append(d)
221 self.enums = [e for e in parseData if e.isEnum()]
223 self.dictionaries = [d for d in parseData if d.isDictionary()]
224 self.dictionariesByName = {d.identifier.name: d for d in self.dictionaries}
226 self.callbacks = [
227 c for c in parseData if c.isCallback() and not c.isInterface()
230 # Dictionary mapping from a union type name to a set of filenames where
231 # union types with that name are used.
232 self.filenamesPerUnion = defaultdict(set)
234 # Dictionary mapping from a filename to a list of types for
235 # the union types used in that file. If a union type is used
236 # in multiple files then it will be added to the list for the
237 # None key. Note that the list contains a type for every use
238 # of a union type, so there can be multiple entries with union
239 # types that have the same name.
240 self.unionsPerFilename = defaultdict(list)
242 def addUnion(t):
243 filenamesForUnion = self.filenamesPerUnion[t.name]
244 if t.filename not in filenamesForUnion:
245 # We have a to be a bit careful: some of our built-in
246 # typedefs are for unions, and those unions end up with
247 # "<unknown>" as the filename. If that happens, we don't
248 # want to try associating this union with one particular
249 # filename, since there isn't one to associate it with,
250 # really.
251 if t.filename == "<unknown>":
252 uniqueFilenameForUnion = None
253 elif len(filenamesForUnion) == 0:
254 # This is the first file that we found a union with this
255 # name in, record the union as part of the file.
256 uniqueFilenameForUnion = t.filename
257 else:
258 # We already found a file that contains a union with
259 # this name.
260 if len(filenamesForUnion) == 1:
261 # This is the first time we found a union with this
262 # name in another file.
263 for f in filenamesForUnion:
264 # Filter out unions with this name from the
265 # unions for the file where we previously found
266 # them.
267 unionsForFilename = [
268 u for u in self.unionsPerFilename[f] if u.name != t.name
270 if len(unionsForFilename) == 0:
271 del self.unionsPerFilename[f]
272 else:
273 self.unionsPerFilename[f] = unionsForFilename
274 # Unions with this name appear in multiple files, record
275 # the filename as None, so that we can detect that.
276 uniqueFilenameForUnion = None
277 self.unionsPerFilename[uniqueFilenameForUnion].append(t)
278 filenamesForUnion.add(t.filename)
280 def addUnions(t):
281 t = findInnermostType(t)
282 if t.isUnion():
283 addUnion(t)
284 for m in t.flatMemberTypes:
285 addUnions(m)
287 for t, _ in getAllTypes(self.descriptors, self.dictionaries, self.callbacks):
288 addUnions(t)
290 for d in getDictionariesConvertedToJS(
291 self.descriptors, self.dictionaries, self.callbacks
293 d.needsConversionToJS = True
295 for d in getDictionariesConvertedFromJS(
296 self.descriptors, self.dictionaries, self.callbacks
298 d.needsConversionFromJS = True
300 # Collect all the global names exposed on a Window object (to implement
301 # the hash for looking up these names when resolving a property).
302 self.windowGlobalNames = []
303 for desc in self.getDescriptors(registersGlobalNamesOnWindow=True):
304 self.windowGlobalNames.append((desc.name, desc))
305 self.windowGlobalNames.extend(
306 (n.identifier.name, desc) for n in desc.interface.legacyFactoryFunctions
308 self.windowGlobalNames.extend(
309 (n, desc) for n in desc.interface.legacyWindowAliases
312 # Collect a sorted list of strings that we want to concatenate into
313 # one big string and a dict mapping each string to its offset in the
314 # concatenated string.
316 # We want the names of all the interfaces with a prototype (for
317 # implementing @@toStringTag).
318 names = set(
319 d.interface.getClassName()
320 for d in self.getDescriptors(hasInterfaceOrInterfacePrototypeObject=True)
322 names.update(
323 d.interface.getClassName()
324 for d in self.getDescriptors(hasOrdinaryObjectPrototype=True)
327 # Now also add the names from windowGlobalNames, we need them for the
328 # perfect hash that we build for these.
329 names.update(n[0] for n in self.windowGlobalNames)
331 # Sorting is not strictly necessary, but makes the generated code a bit
332 # more readable.
333 names = sorted(names)
335 # We can't rely on being able to pass initial=0 to itertools.accumulate
336 # because it was only added in version 3.8, so define an accumulate
337 # function that chains the initial value into the iterator.
338 def accumulate(iterable, initial):
339 return itertools.accumulate(itertools.chain([initial], iterable))
341 # Calculate the offset of each name in the concatenated string. Note that
342 # we need to add 1 to the length to account for the null terminating each
343 # name.
344 offsets = accumulate(map(lambda n: len(n) + 1, names), initial=0)
345 self.namesStringOffsets = list(zip(names, offsets))
347 allTemplatedAttributes = (
348 (m, d)
349 for d in self.descriptors
350 if not d.interface.isExternal()
351 for m in d.interface.members
352 if m.isAttr() and m.getExtendedAttribute("BindingTemplate") is not None
354 # attributesPerTemplate will have the template names as keys, and a
355 # list of tuples as values. Every tuple contains an IDLAttribute and a
356 # descriptor.
357 attributesPerTemplate = dict()
358 for m, d in allTemplatedAttributes:
359 t = m.getExtendedAttribute("BindingTemplate")
360 if isinstance(t[0], list):
361 t = t[0]
362 l = attributesPerTemplate.setdefault(t[0], list())
363 # We want the readonly attributes last, because we use the first
364 # attribute in the list as the canonical attribute for the
365 # template, and if there are any writable attributes the
366 # template should have support for that.
367 if not m.readonly:
368 l.insert(0, (m, d))
369 else:
370 l.append((m, d))
372 for name, attributes in attributesPerTemplate.items():
373 # We use the first attribute to generate a canonical implementation
374 # of getter and setter.
375 firstAttribute, firstDescriptor = attributes[0]
376 template = self.attributeTemplates.get(name)
377 if template is None:
378 raise TypeError(
379 "Unknown BindingTemplate with name %s for %s on %s"
381 name,
382 firstAttribute.identifier.name,
383 firstDescriptor.interface.identifier.name,
387 # This mimics a real IDL attribute for templated bindings.
389 template.attr = Configuration.TemplateIDLAttribute(firstAttribute)
391 def filterExtendedAttributes(extendedAttributes):
392 # These are the extended attributes that we allow to have
393 # different values among all attributes that use the same
394 # template.
395 ignoredAttributes = {
396 "BindingTemplate",
397 "BindingAlias",
398 "ChromeOnly",
399 "Pure",
400 "Pref",
401 "Func",
402 "Throws",
403 "GetterThrows",
404 "SetterThrows",
406 return dict(
407 filter(
408 lambda i: i[0] not in ignoredAttributes,
409 extendedAttributes.items(),
413 firstExtAttrs = filterExtendedAttributes(
414 firstAttribute.getExtendedAttributes()
417 for a, d in attributes:
418 # We want to make sure all getters or setters grouped by a
419 # template have the same WebIDL signatures, so make sure
420 # their types are the same.
421 if template.attr.type != a.type:
422 raise TypeError(
423 "%s on %s and %s on %s have different type, but they're using the same template %s."
425 firstAttribute.identifier.name,
426 firstDescriptor.interface.identifier.name,
427 a.identifier.name,
428 d.interface.identifier.name,
429 name,
433 extAttrs = filterExtendedAttributes(a.getExtendedAttributes())
434 if template.attr.extendedAttributes != extAttrs:
435 for k in extAttrs.keys() - firstExtAttrs.keys():
436 raise TypeError(
437 "%s on %s has extended attribute %s and %s on %s does not, but they're using the same template %s."
439 a.identifier.name,
440 d.interface.identifier.name,
442 firstAttribute.identifier.name,
443 firstDescriptor.interface.identifier.name,
444 name,
447 for k in firstExtAttrs.keys() - extAttrs.keys():
448 raise TypeError(
449 "%s on %s has extended attribute %s and %s on %s does not, but they're using the same template %s."
451 firstAttribute.identifier.name,
452 firstDescriptor.interface.identifier.name,
454 a.identifier.name,
455 d.interface.identifier.name,
456 name,
459 for k, v in firstExtAttrs.items():
460 if extAttrs[k] != v:
461 raise TypeError(
462 "%s on %s and %s on %s have different values for extended attribute %s, but they're using the same template %s."
464 firstAttribute.identifier.name,
465 firstDescriptor.interface.identifier.name,
466 a.identifier.name,
467 d.interface.identifier.name,
469 name,
473 def sameThrows(getter=False, setter=False):
474 extAttrs1 = firstDescriptor.getExtendedAttributes(
475 firstAttribute, getter=getter, setter=setter
477 extAttrs2 = d.getExtendedAttributes(a, getter=getter, setter=setter)
478 return ("needsErrorResult" in extAttrs1) == (
479 "needsErrorResult" in extAttrs2
482 if not sameThrows(getter=True) or (
483 not a.readonly and not sameThrows(setter=True)
485 raise TypeError(
486 "%s on %s and %s on %s have different annotations about throwing, but they're using the same template %s."
488 firstAttribute.identifier.name,
489 firstDescriptor.interface.identifier.name,
490 a.identifier.name,
491 d.interface.identifier.name,
492 name,
496 for name, template in self.attributeTemplates.items():
497 if template.attr is None:
498 print("Template %s is unused, please remove it." % name)
500 def getInterface(self, ifname):
501 return self.interfaces[ifname]
503 def getDescriptors(self, **filters):
504 """Gets the descriptors that match the given filters."""
505 curr = self.descriptors
506 # Collect up our filters, because we may have a webIDLFile filter that
507 # we always want to apply first.
508 tofilter = [(lambda x: x.interface.isExternal(), False)]
509 for key, val in filters.items():
510 if key == "webIDLFile":
511 # Special-case this part to make it fast, since most of our
512 # getDescriptors calls are conditioned on a webIDLFile. We may
513 # not have this key, in which case we have no descriptors
514 # either.
515 curr = self.descriptorsByFile.get(val, [])
516 continue
517 elif key == "hasInterfaceObject":
519 def getter(x):
520 return x.interface.hasInterfaceObject()
522 elif key == "hasInterfacePrototypeObject":
524 def getter(x):
525 return x.interface.hasInterfacePrototypeObject()
527 elif key == "hasInterfaceOrInterfacePrototypeObject":
529 def getter(x):
530 return x.hasInterfaceOrInterfacePrototypeObject()
532 elif key == "hasOrdinaryObjectPrototype":
534 def getter(x):
535 return x.hasOrdinaryObjectPrototype()
537 elif key == "isCallback":
539 def getter(x):
540 return x.interface.isCallback()
542 elif key == "isJSImplemented":
544 def getter(x):
545 return x.interface.isJSImplemented()
547 elif key == "isExposedInAnyWorker":
549 def getter(x):
550 return x.interface.isExposedInAnyWorker()
552 elif key == "isExposedInWorkerDebugger":
554 def getter(x):
555 return x.interface.isExposedInWorkerDebugger()
557 elif key == "isExposedInAnyWorklet":
559 def getter(x):
560 return x.interface.isExposedInAnyWorklet()
562 elif key == "isExposedInWindow":
564 def getter(x):
565 return x.interface.isExposedInWindow()
567 elif key == "isExposedInShadowRealms":
569 def getter(x):
570 return x.interface.isExposedInShadowRealms()
572 elif key == "isSerializable":
574 def getter(x):
575 return x.interface.isSerializable()
577 else:
578 # Have to watch out: just closing over "key" is not enough,
579 # since we're about to mutate its value
580 getter = (lambda attrName: lambda x: getattr(x, attrName))(key)
581 tofilter.append((getter, val))
582 for f in tofilter:
583 curr = [x for x in curr if f[0](x) == f[1]]
584 return curr
586 def getEnums(self, webIDLFile):
587 return [e for e in self.enums if e.filename == webIDLFile]
589 def getDictionaries(self, webIDLFile):
590 return [d for d in self.dictionaries if d.filename == webIDLFile]
592 def getCallbacks(self, webIDLFile):
593 return [c for c in self.callbacks if c.filename == webIDLFile]
595 def getDescriptor(self, interfaceName):
597 Gets the appropriate descriptor for the given interface name.
599 # We may have optimized out this descriptor, but the chances of anyone
600 # asking about it are then slim. Put the check for that _after_ we've
601 # done our normal lookup. But that means we have to do our normal
602 # lookup in a way that will not throw if it fails.
603 d = self.descriptorsByName.get(interfaceName, None)
604 if d:
605 return d
607 raise NoSuchDescriptorError("For " + interfaceName + " found no matches")
609 def getConfig(self):
610 return self
612 def getDictionariesConvertibleToJS(self):
613 return [d for d in self.dictionaries if d.needsConversionToJS]
615 def getDictionariesConvertibleFromJS(self):
616 return [d for d in self.dictionaries if d.needsConversionFromJS]
618 def getDictionaryIfExists(self, dictionaryName):
619 return self.dictionariesByName.get(dictionaryName, None)
622 class NoSuchDescriptorError(TypeError):
623 def __init__(self, str):
624 TypeError.__init__(self, str)
627 def methodReturnsJSObject(method):
628 assert method.isMethod()
630 for signature in method.signatures():
631 returnType = signature[0]
632 if returnType.isObject() or returnType.isSpiderMonkeyInterface():
633 return True
635 return False
638 def MemberIsLegacyUnforgeable(member, descriptor):
639 # Note: "or" and "and" return either their LHS or RHS, not
640 # necessarily booleans. Make sure to return a boolean from this
641 # method, because callers will compare its return value to
642 # booleans.
643 return bool(
644 (member.isAttr() or member.isMethod())
645 and not member.isStatic()
646 and (
647 member.isLegacyUnforgeable()
648 or descriptor.interface.getExtendedAttribute("LegacyUnforgeable")
653 class Descriptor(DescriptorProvider):
655 Represents a single descriptor for an interface. See Bindings.conf.
658 def __init__(self, config, interface, desc, attributeTemplates):
659 DescriptorProvider.__init__(self)
660 self.config = config
661 self.interface = interface
662 self.attributeTemplates = attributeTemplates
663 if self.attributeTemplates is not None:
664 for t in self.attributeTemplates:
665 t.descriptor = self
667 self.wantsXrays = not interface.isExternal() and interface.isExposedInWindow()
669 if self.wantsXrays:
670 # We could try to restrict self.wantsXrayExpandoClass further. For
671 # example, we could set it to false if all of our slots store
672 # Gecko-interface-typed things, because we don't use Xray expando
673 # slots for those. But note that we would need to check the types
674 # of not only the members of "interface" but also of all its
675 # ancestors, because those can have members living in our slots too.
676 # For now, do the simple thing.
677 self.wantsXrayExpandoClass = interface.totalMembersInSlots != 0
679 # Read the desc, and fill in the relevant defaults.
680 ifaceName = self.interface.identifier.name
681 # For generated iterator interfaces for other iterable interfaces, we
682 # just use IterableIterator as the native type, templated on the
683 # nativeType of the iterable interface. That way we can have a
684 # templated implementation for all the duplicated iterator
685 # functionality.
686 if self.interface.isIteratorInterface():
687 itrName = self.interface.iterableInterface.identifier.name
688 itrDesc = self.getDescriptor(itrName)
689 nativeTypeDefault = iteratorNativeType(itrDesc)
690 elif self.interface.isAsyncIteratorInterface():
691 itrName = self.interface.asyncIterableInterface.identifier.name
692 itrDesc = self.getDescriptor(itrName)
693 nativeTypeDefault = iteratorNativeType(itrDesc)
695 elif self.interface.isExternal():
696 nativeTypeDefault = "nsIDOM" + ifaceName
697 else:
698 nativeTypeDefault = "mozilla::dom::" + ifaceName
700 self.nativeType = desc.get("nativeType", nativeTypeDefault)
701 # Now create a version of nativeType that doesn't have extra
702 # mozilla::dom:: at the beginning.
703 prettyNativeType = self.nativeType.split("::")
704 if prettyNativeType[0] == "mozilla":
705 prettyNativeType.pop(0)
706 if prettyNativeType[0] == "dom":
707 prettyNativeType.pop(0)
708 self.prettyNativeType = "::".join(prettyNativeType)
710 self.jsImplParent = desc.get("jsImplParent", self.nativeType)
712 # Do something sane for JSObject
713 if self.nativeType == "JSObject":
714 headerDefault = "js/TypeDecls.h"
715 elif self.interface.isCallback() or self.interface.isJSImplemented():
716 # A copy of CGHeaders.getDeclarationFilename; we can't
717 # import it here, sadly.
718 # Use our local version of the header, not the exported one, so that
719 # test bindings, which don't export, will work correctly.
720 basename = os.path.basename(self.interface.filename)
721 headerDefault = basename.replace(".webidl", "Binding.h")
722 else:
723 if not self.interface.isExternal() and self.interface.getExtendedAttribute(
724 "HeaderFile"
726 headerDefault = self.interface.getExtendedAttribute("HeaderFile")[0]
727 elif (
728 self.interface.isIteratorInterface()
729 or self.interface.isAsyncIteratorInterface()
731 headerDefault = "mozilla/dom/IterableIterator.h"
732 else:
733 headerDefault = self.nativeType
734 headerDefault = headerDefault.replace("::", "/") + ".h"
735 self.headerFile = desc.get("headerFile", headerDefault)
736 self.headerIsDefault = self.headerFile == headerDefault
737 if self.jsImplParent == self.nativeType:
738 self.jsImplParentHeader = self.headerFile
739 else:
740 self.jsImplParentHeader = self.jsImplParent.replace("::", "/") + ".h"
742 self.notflattened = desc.get("notflattened", False)
743 self.register = desc.get("register", True)
745 # If we're concrete, we need to crawl our ancestor interfaces and mark
746 # them as having a concrete descendant.
747 concreteDefault = (
748 not self.interface.isExternal()
749 and not self.interface.isCallback()
750 and not self.interface.isNamespace()
752 # We're going to assume that leaf interfaces are
753 # concrete; otherwise what's the point? Also
754 # interfaces with constructors had better be
755 # concrete; otherwise how can you construct them?
757 not self.interface.hasChildInterfaces()
758 or self.interface.ctor() is not None
762 self.concrete = desc.get("concrete", concreteDefault)
763 self.hasLegacyUnforgeableMembers = self.concrete and any(
764 MemberIsLegacyUnforgeable(m, self) for m in self.interface.members
766 self.operations = {
767 "IndexedGetter": None,
768 "IndexedSetter": None,
769 "IndexedDeleter": None,
770 "NamedGetter": None,
771 "NamedSetter": None,
772 "NamedDeleter": None,
773 "Stringifier": None,
774 "LegacyCaller": None,
777 self.hasDefaultToJSON = False
779 # Stringifiers need to be set up whether an interface is
780 # concrete or not, because they're actually prototype methods and hence
781 # can apply to instances of descendant interfaces. Legacy callers and
782 # named/indexed operations only need to be set up on concrete
783 # interfaces, since they affect the JSClass we end up using, not the
784 # prototype object.
785 def addOperation(operation, m):
786 if not self.operations[operation]:
787 self.operations[operation] = m
789 # Since stringifiers go on the prototype, we only need to worry
790 # about our own stringifier, not those of our ancestor interfaces.
791 if not self.interface.isExternal():
792 for m in self.interface.members:
793 if m.isMethod() and m.isStringifier():
794 addOperation("Stringifier", m)
795 if m.isMethod() and m.isDefaultToJSON():
796 self.hasDefaultToJSON = True
798 # We keep track of instrumente props for all non-external interfaces.
799 self.instrumentedProps = []
800 instrumentedProps = self.interface.getExtendedAttribute("InstrumentedProps")
801 if instrumentedProps:
802 # It's actually a one-element list, with the list
803 # we want as the only element.
804 self.instrumentedProps = instrumentedProps[0]
806 # Check that we don't have duplicated instrumented props.
807 uniqueInstrumentedProps = set(self.instrumentedProps)
808 if len(uniqueInstrumentedProps) != len(self.instrumentedProps):
809 duplicates = [
811 for p in uniqueInstrumentedProps
812 if self.instrumentedProps.count(p) > 1
814 raise TypeError(
815 "Duplicated instrumented properties: %s.\n%s"
816 % (duplicates, self.interface.location)
819 if self.concrete:
820 self.proxy = False
821 iface = self.interface
822 for m in iface.members:
823 # Don't worry about inheriting legacycallers either: in
824 # practice these are on most-derived prototypes.
825 if m.isMethod() and m.isLegacycaller():
826 if not m.isIdentifierLess():
827 raise TypeError(
828 "We don't support legacycaller with "
829 "identifier.\n%s" % m.location
831 if len(m.signatures()) != 1:
832 raise TypeError(
833 "We don't support overloaded "
834 "legacycaller.\n%s" % m.location
836 addOperation("LegacyCaller", m)
838 if desc.get("hasOrdinaryObjectPrototype", False):
839 iface.setUserData("hasOrdinaryObjectPrototype", True)
841 while iface:
842 for m in iface.members:
843 if not m.isMethod():
844 continue
846 def addIndexedOrNamedOperation(operation, m):
847 if m.isIndexed():
848 operation = "Indexed" + operation
849 else:
850 assert m.isNamed()
851 operation = "Named" + operation
852 addOperation(operation, m)
854 if m.isGetter():
855 addIndexedOrNamedOperation("Getter", m)
856 if m.isSetter():
857 addIndexedOrNamedOperation("Setter", m)
858 if m.isDeleter():
859 addIndexedOrNamedOperation("Deleter", m)
860 if m.isLegacycaller() and iface != self.interface:
861 raise TypeError(
862 "We don't support legacycaller on "
863 "non-leaf interface %s.\n%s" % (iface, iface.location)
866 iface.setUserData("hasConcreteDescendant", True)
867 iface = iface.parent
869 self.proxy = (
870 self.supportsIndexedProperties()
871 or (
872 self.supportsNamedProperties() and not self.hasNamedPropertiesObject
874 or self.isMaybeCrossOriginObject()
877 if self.proxy:
878 if self.isMaybeCrossOriginObject() and (
879 self.supportsIndexedProperties() or self.supportsNamedProperties()
881 raise TypeError(
882 "We don't support named or indexed "
883 "properties on maybe-cross-origin objects. "
884 "This lets us assume that their proxy "
885 "hooks are never called via Xrays. "
886 "Fix %s.\n%s" % (self.interface, self.interface.location)
889 if not self.operations["IndexedGetter"] and (
890 self.operations["IndexedSetter"]
891 or self.operations["IndexedDeleter"]
893 raise SyntaxError(
894 "%s supports indexed properties but does "
895 "not have an indexed getter.\n%s"
896 % (self.interface, self.interface.location)
898 if not self.operations["NamedGetter"] and (
899 self.operations["NamedSetter"] or self.operations["NamedDeleter"]
901 raise SyntaxError(
902 "%s supports named properties but does "
903 "not have a named getter.\n%s"
904 % (self.interface, self.interface.location)
906 iface = self.interface
907 while iface:
908 iface.setUserData("hasProxyDescendant", True)
909 iface = iface.parent
911 if desc.get("wantsQI", None) is not None:
912 self._wantsQI = desc.get("wantsQI", None)
913 self.wrapperCache = (
914 not self.interface.isCallback()
915 and not self.interface.isIteratorInterface()
916 and not self.interface.isAsyncIteratorInterface()
917 and desc.get("wrapperCache", True)
920 self.name = interface.identifier.name
922 # self.implicitJSContext is a list of names of methods and attributes
923 # that need a JSContext.
924 if self.interface.isJSImplemented():
925 self.implicitJSContext = ["constructor"]
926 else:
927 self.implicitJSContext = desc.get("implicitJSContext", [])
928 assert isinstance(self.implicitJSContext, list)
930 self._binaryNames = {}
932 if not self.interface.isExternal():
934 def maybeAddBinaryName(member):
935 binaryName = member.getExtendedAttribute("BinaryName")
936 if binaryName:
937 assert isinstance(binaryName, list)
938 assert len(binaryName) == 1
939 self._binaryNames.setdefault(
940 (member.identifier.name, member.isStatic()), binaryName[0]
943 for member in self.interface.members:
944 if not member.isAttr() and not member.isMethod():
945 continue
946 maybeAddBinaryName(member)
948 ctor = self.interface.ctor()
949 if ctor:
950 maybeAddBinaryName(ctor)
952 # Some default binary names for cases when nothing else got set.
953 self._binaryNames.setdefault(("__legacycaller", False), "LegacyCall")
954 self._binaryNames.setdefault(("__stringifier", False), "Stringify")
956 # Build the prototype chain.
957 self.prototypeChain = []
958 self.needsMissingPropUseCounters = False
959 parent = interface
960 while parent:
961 self.needsMissingPropUseCounters = (
962 self.needsMissingPropUseCounters
963 or parent.getExtendedAttribute("InstrumentedProps")
965 self.prototypeChain.insert(0, parent.identifier.name)
966 parent = parent.parent
967 config.maxProtoChainLength = max(
968 config.maxProtoChainLength, len(self.prototypeChain)
971 def binaryNameFor(self, name, isStatic):
972 return self._binaryNames.get((name, isStatic), name)
974 @property
975 def prototypeNameChain(self):
976 return [self.getDescriptor(p).name for p in self.prototypeChain]
978 @property
979 def parentPrototypeName(self):
980 if len(self.prototypeChain) == 1:
981 return None
982 return self.getDescriptor(self.prototypeChain[-2]).name
984 def hasInterfaceOrInterfacePrototypeObject(self):
985 return (
986 self.interface.hasInterfaceObject()
987 or self.interface.hasInterfacePrototypeObject()
990 def hasOrdinaryObjectPrototype(self):
991 return self.interface.getUserData("hasOrdinaryObjectPrototype", False)
993 @property
994 def hasNamedPropertiesObject(self):
995 return self.isGlobal() and self.supportsNamedProperties()
997 def getExtendedAttributes(self, member, getter=False, setter=False):
998 def ensureValidBoolExtendedAttribute(attr, name):
999 if attr is not None and attr is not True:
1000 raise TypeError("Unknown value for '%s': %s" % (name, attr[0]))
1002 def ensureValidThrowsExtendedAttribute(attr):
1003 ensureValidBoolExtendedAttribute(attr, "Throws")
1005 def ensureValidCanOOMExtendedAttribute(attr):
1006 ensureValidBoolExtendedAttribute(attr, "CanOOM")
1008 def maybeAppendNeedsErrorResultToAttrs(attrs, throws):
1009 ensureValidThrowsExtendedAttribute(throws)
1010 if throws is not None:
1011 attrs.append("needsErrorResult")
1013 def maybeAppendCanOOMToAttrs(attrs, canOOM):
1014 ensureValidCanOOMExtendedAttribute(canOOM)
1015 if canOOM is not None:
1016 attrs.append("canOOM")
1018 def maybeAppendNeedsSubjectPrincipalToAttrs(attrs, needsSubjectPrincipal):
1019 if (
1020 needsSubjectPrincipal is not None
1021 and needsSubjectPrincipal is not True
1022 and needsSubjectPrincipal != ["NonSystem"]
1024 raise TypeError(
1025 "Unknown value for 'NeedsSubjectPrincipal': %s"
1026 % needsSubjectPrincipal[0]
1029 if needsSubjectPrincipal is not None:
1030 attrs.append("needsSubjectPrincipal")
1031 if needsSubjectPrincipal == ["NonSystem"]:
1032 attrs.append("needsNonSystemSubjectPrincipal")
1034 name = member.identifier.name
1035 throws = self.interface.isJSImplemented() or member.getExtendedAttribute(
1036 "Throws"
1038 canOOM = member.getExtendedAttribute("CanOOM")
1039 needsSubjectPrincipal = member.getExtendedAttribute("NeedsSubjectPrincipal")
1040 attrs = []
1041 if name in self.implicitJSContext:
1042 attrs.append("implicitJSContext")
1043 if member.isMethod():
1044 if self.interface.isAsyncIteratorInterface() and name == "next":
1045 attrs.append("implicitJSContext")
1046 # JSObject-returning [NewObject] methods must be fallible,
1047 # since they have to (fallibly) allocate the new JSObject.
1048 if member.getExtendedAttribute("NewObject"):
1049 if member.returnsPromise():
1050 throws = True
1051 elif methodReturnsJSObject(member):
1052 canOOM = True
1053 maybeAppendNeedsErrorResultToAttrs(attrs, throws)
1054 maybeAppendCanOOMToAttrs(attrs, canOOM)
1055 maybeAppendNeedsSubjectPrincipalToAttrs(attrs, needsSubjectPrincipal)
1056 return attrs
1058 assert member.isAttr()
1059 assert bool(getter) != bool(setter)
1060 if throws is None:
1061 throwsAttr = "GetterThrows" if getter else "SetterThrows"
1062 throws = member.getExtendedAttribute(throwsAttr)
1063 maybeAppendNeedsErrorResultToAttrs(attrs, throws)
1064 if canOOM is None:
1065 canOOMAttr = "GetterCanOOM" if getter else "SetterCanOOM"
1066 canOOM = member.getExtendedAttribute(canOOMAttr)
1067 maybeAppendCanOOMToAttrs(attrs, canOOM)
1068 if needsSubjectPrincipal is None:
1069 needsSubjectPrincipalAttr = (
1070 "GetterNeedsSubjectPrincipal"
1071 if getter
1072 else "SetterNeedsSubjectPrincipal"
1074 needsSubjectPrincipal = member.getExtendedAttribute(
1075 needsSubjectPrincipalAttr
1077 maybeAppendNeedsSubjectPrincipalToAttrs(attrs, needsSubjectPrincipal)
1078 return attrs
1080 def supportsIndexedProperties(self):
1081 return self.operations["IndexedGetter"] is not None
1083 def lengthNeedsCallerType(self):
1085 Determine whether our length getter needs a caller type; this is needed
1086 in some indexed-getter proxy algorithms. The idea is that if our
1087 indexed getter needs a caller type, our automatically-generated Length()
1088 calls need one too.
1090 assert self.supportsIndexedProperties()
1091 indexedGetter = self.operations["IndexedGetter"]
1092 return indexedGetter.getExtendedAttribute("NeedsCallerType")
1094 def supportsNamedProperties(self):
1095 return self.operations["NamedGetter"] is not None
1097 def supportedNamesNeedCallerType(self):
1099 Determine whether our GetSupportedNames call needs a caller type. The
1100 idea is that if your named getter needs a caller type, then so does
1101 GetSupportedNames.
1103 assert self.supportsNamedProperties()
1104 namedGetter = self.operations["NamedGetter"]
1105 return namedGetter.getExtendedAttribute("NeedsCallerType")
1107 def isMaybeCrossOriginObject(self):
1108 # If we're isGlobal and have cross-origin members, we're a Window, and
1109 # that's not a cross-origin object. The WindowProxy is.
1110 return (
1111 self.concrete
1112 and self.interface.hasCrossOriginMembers
1113 and not self.isGlobal()
1116 def needsHeaderInclude(self):
1118 An interface doesn't need a header file if it is not concrete, not
1119 pref-controlled, has no prototype object, has no static methods or
1120 attributes and has no parent. The parent matters because we assert
1121 things about refcounting that depend on the actual underlying type if we
1122 have a parent.
1125 return (
1126 self.interface.isExternal()
1127 or self.concrete
1128 or self.interface.hasInterfacePrototypeObject()
1129 or any(
1130 (m.isAttr() or m.isMethod()) and m.isStatic()
1131 for m in self.interface.members
1133 or self.interface.parent
1136 def hasThreadChecks(self):
1137 # isExposedConditionally does not necessarily imply thread checks
1138 # (since at least [SecureContext] is independent of them), but we're
1139 # only used to decide whether to include nsThreadUtils.h, so we don't
1140 # worry about that.
1141 return (
1142 self.isExposedConditionally() and not self.interface.isExposedInWindow()
1143 ) or self.interface.isExposedInSomeButNotAllWorkers()
1145 def hasCEReactions(self):
1146 return any(
1147 m.getExtendedAttribute("CEReactions") for m in self.interface.members
1150 def isExposedConditionally(self):
1151 return (
1152 self.interface.isExposedConditionally()
1153 or self.interface.isExposedInSomeButNotAllWorkers()
1156 def needsXrayResolveHooks(self):
1158 Generally, any interface with NeedResolve needs Xray
1159 resolveOwnProperty and enumerateOwnProperties hooks. But for
1160 the special case of plugin-loading elements, we do NOT want
1161 those, because we don't want to instantiate plug-ins simply
1162 due to chrome touching them and that's all those hooks do on
1163 those elements. So we special-case those here.
1165 return self.interface.getExtendedAttribute(
1166 "NeedResolve"
1167 ) and self.interface.identifier.name not in [
1168 "HTMLObjectElement",
1169 "HTMLEmbedElement",
1172 def needsXrayNamedDeleterHook(self):
1173 return self.operations["NamedDeleter"] is not None
1175 def isGlobal(self):
1177 Returns true if this is the primary interface for a global object
1178 of some sort.
1180 return self.interface.getExtendedAttribute("Global")
1182 @property
1183 def namedPropertiesEnumerable(self):
1185 Returns whether this interface should have enumerable named properties
1187 assert self.proxy
1188 assert self.supportsNamedProperties()
1189 iface = self.interface
1190 while iface:
1191 if iface.getExtendedAttribute("LegacyUnenumerableNamedProperties"):
1192 return False
1193 iface = iface.parent
1194 return True
1196 @property
1197 def registersGlobalNamesOnWindow(self):
1198 return (
1199 self.interface.hasInterfaceObject()
1200 and self.interface.isExposedInWindow()
1201 and self.register
1204 def getDescriptor(self, interfaceName):
1206 Gets the appropriate descriptor for the given interface name.
1208 return self.config.getDescriptor(interfaceName)
1210 def getConfig(self):
1211 return self.config
1214 # Some utility methods
1215 def getTypesFromDescriptor(descriptor, includeArgs=True, includeReturns=True):
1217 Get argument and/or return types for all members of the descriptor. By
1218 default returns all argument types (which includes types of writable
1219 attributes) and all return types (which includes types of all attributes).
1221 assert includeArgs or includeReturns # Must want _something_.
1222 members = [m for m in descriptor.interface.members]
1223 if descriptor.interface.ctor():
1224 members.append(descriptor.interface.ctor())
1225 members.extend(descriptor.interface.legacyFactoryFunctions)
1226 signatures = [s for m in members if m.isMethod() for s in m.signatures()]
1227 types = []
1228 for s in signatures:
1229 assert len(s) == 2
1230 (returnType, arguments) = s
1231 if includeReturns:
1232 types.append(returnType)
1233 if includeArgs:
1234 types.extend(a.type for a in arguments)
1236 types.extend(
1237 a.type
1238 for a in members
1239 if (a.isAttr() and (includeReturns or (includeArgs and not a.readonly)))
1242 if descriptor.interface.maplikeOrSetlikeOrIterable:
1243 maplikeOrSetlikeOrIterable = descriptor.interface.maplikeOrSetlikeOrIterable
1244 if maplikeOrSetlikeOrIterable.isMaplike():
1245 # The things we expand into may or may not correctly indicate in
1246 # their formal IDL types what things we have as return values. For
1247 # example, "keys" returns the moral equivalent of sequence<keyType>
1248 # but just claims to return "object". Similarly, "values" returns
1249 # the moral equivalent of sequence<valueType> but claims to return
1250 # "object". And due to bug 1155340, "get" claims to return "any"
1251 # instead of the right type. So let's just manually work around
1252 # that lack of specificity. For our arguments, we already enforce
1253 # the right types at the IDL level, so those will get picked up
1254 # correctly.
1255 assert maplikeOrSetlikeOrIterable.hasKeyType()
1256 assert maplikeOrSetlikeOrIterable.hasValueType()
1257 if includeReturns:
1258 types.append(maplikeOrSetlikeOrIterable.keyType)
1259 types.append(maplikeOrSetlikeOrIterable.valueType)
1260 elif maplikeOrSetlikeOrIterable.isSetlike():
1261 assert maplikeOrSetlikeOrIterable.hasKeyType()
1262 assert maplikeOrSetlikeOrIterable.hasValueType()
1263 assert (
1264 maplikeOrSetlikeOrIterable.keyType
1265 == maplikeOrSetlikeOrIterable.valueType
1267 # As in the maplike case, we don't always declare our return values
1268 # quite correctly.
1269 if includeReturns:
1270 types.append(maplikeOrSetlikeOrIterable.keyType)
1271 else:
1272 assert (
1273 maplikeOrSetlikeOrIterable.isIterable()
1274 or maplikeOrSetlikeOrIterable.isAsyncIterable()
1276 # As in the maplike/setlike cases we don't do a good job of
1277 # declaring our actual return types, while our argument types, if
1278 # any, are declared fine.
1279 if includeReturns:
1280 if maplikeOrSetlikeOrIterable.hasKeyType():
1281 types.append(maplikeOrSetlikeOrIterable.keyType)
1282 if maplikeOrSetlikeOrIterable.hasValueType():
1283 types.append(maplikeOrSetlikeOrIterable.valueType)
1285 return types
1288 def getTypesFromDictionary(dictionary):
1290 Get all member types for this dictionary
1292 return [m.type for m in dictionary.members]
1295 def getTypesFromCallback(callback):
1297 Get the types this callback depends on: its return type and the
1298 types of its arguments.
1300 sig = callback.signatures()[0]
1301 types = [sig[0]] # Return type
1302 types.extend(arg.type for arg in sig[1]) # Arguments
1303 return types
1306 def getAllTypes(descriptors, dictionaries, callbacks):
1308 Generate all the types we're dealing with. For each type, a tuple
1309 containing type, dictionary is yielded. The dictionary can be None if the
1310 type does not come from a dictionary.
1312 for d in descriptors:
1313 if d.interface.isExternal():
1314 continue
1315 for t in getTypesFromDescriptor(d):
1316 yield (t, None)
1317 for dictionary in dictionaries:
1318 for t in getTypesFromDictionary(dictionary):
1319 yield (t, dictionary)
1320 for callback in callbacks:
1321 for t in getTypesFromCallback(callback):
1322 yield (t, callback)
1325 # For sync value iterators, we use default array implementation, for async
1326 # iterators and sync pair iterators, we use AsyncIterableIterator or
1327 # IterableIterator instead.
1328 def iteratorNativeType(descriptor):
1329 assert descriptor.interface.isIterable() or descriptor.interface.isAsyncIterable()
1330 iterableDecl = descriptor.interface.maplikeOrSetlikeOrIterable
1331 assert iterableDecl.isPairIterator() or descriptor.interface.isAsyncIterable()
1332 if descriptor.interface.isIterable():
1333 return "mozilla::dom::IterableIterator<%s>" % descriptor.nativeType
1334 needReturnMethod = toStringBool(
1335 descriptor.interface.maplikeOrSetlikeOrIterable.getExtendedAttribute(
1336 "GenerateReturnMethod"
1338 is not None
1340 return "mozilla::dom::binding_detail::AsyncIterableIteratorNative<%s, %s>" % (
1341 descriptor.nativeType,
1342 needReturnMethod,
1346 def findInnermostType(t):
1348 Find the innermost type of the given type, unwrapping Promise and Record
1349 types, as well as everything that unroll() unwraps.
1351 while True:
1352 if t.isRecord():
1353 t = t.inner
1354 elif t.unroll() != t:
1355 t = t.unroll()
1356 elif t.isPromise():
1357 t = t.promiseInnerType()
1358 else:
1359 return t
1362 def getDependentDictionariesFromDictionary(d):
1364 Find all the dictionaries contained in the given dictionary, as ancestors or
1365 members. This returns a generator.
1367 while d:
1368 yield d
1369 for member in d.members:
1370 for next in getDictionariesFromType(member.type):
1371 yield next
1372 d = d.parent
1375 def getDictionariesFromType(type):
1377 Find all the dictionaries contained in type. This can be used to find
1378 dictionaries that need conversion to JS (by looking at types that get
1379 converted to JS) or dictionaries that need conversion from JS (by looking at
1380 types that get converted from JS).
1382 This returns a generator.
1384 type = findInnermostType(type)
1385 if type.isUnion():
1386 # Look for dictionaries in all the member types
1387 for t in type.flatMemberTypes:
1388 for next in getDictionariesFromType(t):
1389 yield next
1390 elif type.isDictionary():
1391 # Find the dictionaries that are itself, any of its ancestors, or
1392 # contained in any of its member types.
1393 for d in getDependentDictionariesFromDictionary(type.inner):
1394 yield d
1397 def getDictionariesConvertedToJS(descriptors, dictionaries, callbacks):
1398 for desc in descriptors:
1399 if desc.interface.isExternal():
1400 continue
1402 if desc.interface.isJSImplemented():
1403 # For a JS-implemented interface, we need to-JS
1404 # conversions for all the types involved.
1405 for t in getTypesFromDescriptor(desc):
1406 for d in getDictionariesFromType(t):
1407 yield d
1408 elif desc.interface.isCallback():
1409 # For callbacks we only want to include the arguments, since that's
1410 # where the to-JS conversion happens.
1411 for t in getTypesFromDescriptor(desc, includeReturns=False):
1412 for d in getDictionariesFromType(t):
1413 yield d
1414 else:
1415 # For normal interfaces, we only want to include return values,
1416 # since that's where to-JS conversion happens.
1417 for t in getTypesFromDescriptor(desc, includeArgs=False):
1418 for d in getDictionariesFromType(t):
1419 yield d
1421 for callback in callbacks:
1422 # We only want to look at the arguments
1423 sig = callback.signatures()[0]
1424 for arg in sig[1]:
1425 for d in getDictionariesFromType(arg.type):
1426 yield d
1428 for dictionary in dictionaries:
1429 if dictionary.needsConversionToJS:
1430 # It's explicitly flagged as needing to-JS conversion, and all its
1431 # dependent dictionaries will need to-JS conversion too.
1432 for d in getDependentDictionariesFromDictionary(dictionary):
1433 yield d
1436 def getDictionariesConvertedFromJS(descriptors, dictionaries, callbacks):
1437 for desc in descriptors:
1438 if desc.interface.isExternal():
1439 continue
1441 if desc.interface.isJSImplemented():
1442 # For a JS-implemented interface, we need from-JS conversions for
1443 # all the types involved.
1444 for t in getTypesFromDescriptor(desc):
1445 for d in getDictionariesFromType(t):
1446 yield d
1447 elif desc.interface.isCallback():
1448 # For callbacks we only want to include the return value, since
1449 # that's where teh from-JS conversion happens.
1450 for t in getTypesFromDescriptor(desc, includeArgs=False):
1451 for d in getDictionariesFromType(t):
1452 yield d
1453 else:
1454 # For normal interfaces, we only want to include arguments values,
1455 # since that's where from-JS conversion happens.
1456 for t in getTypesFromDescriptor(desc, includeReturns=False):
1457 for d in getDictionariesFromType(t):
1458 yield d
1460 for callback in callbacks:
1461 # We only want to look at the return value
1462 sig = callback.signatures()[0]
1463 for d in getDictionariesFromType(sig[0]):
1464 yield d
1466 for dictionary in dictionaries:
1467 if dictionary.needsConversionFromJS:
1468 # It's explicitly flagged as needing from-JS conversion, and all its
1469 # dependent dictionaries will need from-JS conversion too.
1470 for d in getDependentDictionariesFromDictionary(dictionary):
1471 yield d