author Peter Van der Beken <>
Fri, 30 Mar 2012 21:42:20 -0700
changeset 90770 1bdb337e3136c877e5d93b9c3ebac548bd7e4fff
child 94727 24f6cf7eece90529f71b3dfa33e2d375dae7a522
permissions -rw-r--r--
Fix for bug 740069 (Generate JS bindings in C++ with a python script for DOM objects on the main thread and in workers. Infrastructure and new bindings for XMLHttpRequest). Patch by bent/bz/bholley/jst/khuey/peterv, r=bent/bz/bholley/jlebar/khuey/peterv/sicking/smaug.

# 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

autogenerated_comment = "/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n"

class Configuration:
    Represents global configuration state based on IDL parse data and
    the configuration file.
    def __init__(self, filename, parseData):

        # 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.maxProtoChainLength = 0;
        for thing in parseData:
            if not thing.isInterface(): continue
            iface = thing
            if not in config: continue
            self.interfaces[] = iface
            entry = config[]
            if not isinstance(entry, list):
                assert isinstance(entry, dict)
                entry = [entry]
            self.descriptors.extend([Descriptor(self, iface, x) for x in entry])

        # Mark the descriptors for which only a single nativeType implements
        # an interface.
        for descriptor in self.descriptors:
            intefaceName =
            otherDescriptors = [d for d in self.descriptors
                                if == intefaceName]
            descriptor.uniqueImplementation = len(otherDescriptors) == 1

        self.enums = [e for e in parseData if e.isEnum()]

        # Keep the descriptor list sorted for determinism.
        self.descriptors.sort(lambda x,y: cmp(,

    def getInterface(self, ifname):
        return self.interfaces[ifname]
    def getDescriptors(self, **filters):
        """Gets the descriptors that match the given filters."""
        curr = self.descriptors
        for key, val in filters.iteritems():
            if key == 'webIDLFile':
                getter = lambda x: x.interface.filename()
            elif key == 'hasInterfaceObject':
                getter = lambda x: (not x.interface.isExternal() and
            elif key == 'hasInterfacePrototypeObject':
                getter = lambda x: (not x.interface.isExternal() and
            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()
                getter = lambda x: getattr(x, key)
            curr = filter(lambda x: getter(x) == val, curr)
        return curr
    def getEnums(self, webIDLFile):
        return filter(lambda e: e.filename() == webIDLFile, self.enums)

class Descriptor:
    Represents a single descriptor for an interface. See Bindings.conf.
    def __init__(self, config, interface, desc):
        self.config = config
        self.interface = interface

        # Read the desc, and fill in the relevant defaults.
        self.nativeType = desc['nativeType']
        self.hasInstanceInterface = desc.get('hasInstanceInterface', None)

        headerDefault = self.nativeType
        headerDefault = headerDefault.split("::")[-1] + ".h"
        self.headerFile = desc.get('headerFile', headerDefault)

        castableDefault = not self.interface.isCallback()
        self.castable = desc.get('castable', castableDefault)

        self.notflattened = desc.get('notflattened', False)

        # If we're concrete, we need to crawl our ancestor interfaces and mark
        # them as having a concrete descendant.
        self.concrete = desc.get('concrete', True)
        if self.concrete:
            iface = self.interface
            while iface:
                iface.setUserData('hasConcreteDescendant', True)
                iface = iface.parent

        self.prefable = desc.get('prefable', False)

        self.workers = desc.get('workers', False)
        self.nativeIsISupports = not self.workers
        self.customTrace = desc.get('customTrace', self.workers)
        self.customFinalize = desc.get('customFinalize', self.workers)

        def make_name(name):
            return name + "_workers" if self.workers else name = make_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)
                assert isinstance(config, string)
                add('all', [config], attribute)

        for attribute in ['infallible', 'implicitJSContext', 'resultNotAddRefed']:
            addExtendedAttribute(attribute, desc.get(attribute, {}))

        self.binaryNames = desc.get('binaryNames', {})

        # Build the prototype chain.
        self.prototypeChain = []
        parent = interface
        while parent:
            self.prototypeChain.insert(0, make_name(
            parent = parent.parent
        config.maxProtoChainLength = max(config.maxProtoChainLength,

    def hasInterfaceOrInterfacePrototypeObject(self):

        # Forward-declared interfaces don't need either interface object or
        # interface prototype object as they're going to use QI (on main thread)
        # or be passed as a JSObject (on worker threads).
        if self.interface.isExternal():
            return False

        return self.interface.hasInterfaceObject() or self.interface.hasInterfacePrototypeObject()

    def getDescriptor(self, interfaceName):
        Gets the appropriate descriptor for the given interface name given the
        context of the current descriptor. This selects the appropriate
        implementation for cases like workers.
        iface = self.config.getInterface(interfaceName)
        descriptors = self.config.getDescriptors(interface=iface)

        # The only filter we currently have is workers vs non-workers.
        matches = filter(lambda x: x.workers is self.workers, descriptors)

        # After filtering, we should have exactly one result.
        if len(matches) is not 1:
            raise TypeError("For " + interfaceName + " found " +
                            str(len(matches)) + " matches");
        return matches[0]

    def getExtendedAttributes(self, member, getter=False, setter=False):
        name =
        if member.isMethod():
            return self.extendedAttributes['all'].get(name, [])

        assert member.isAttr()
        assert bool(getter) != bool(setter)
        key = 'getterOnly' if getter else 'setterOnly'
        return self.extendedAttributes['all'].get(name, []) + self.extendedAttributes[key].get(name, [])