mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 05:37:11 +00:00
e4c3e62beb
- Bug 1216751 part 1. Restrict value iterators to interfaces that have indexed properties and pair iterators to interfaces that do not have indexed properties. r=qdot (6519f3f8c5) - Bug 1216751 part 2. For value iterators, "entries", "keys", and "values" must just come from Array.prototype. r=qdot (c0859f945c) - Bug 1216751 part 3. For pair iterators, @@iterator should be an alias for "entries". Similarly for maplikes and "entries" and setlikes and "values". r=qdot (bbe7c04782) - Bug 1216751 part 4. Implement forEach for iterable interfaces. r=qdot (8fdba677a4) - Bug 1216751 part 5. Remove the now-unnecessary value iterator infrastructure, since it's entirely handled via the %ArrayPrototype% methods now. r=qdot (88d3911694) - Bug 1231333 - part 1, JS engine: only allow futexWait in workers. r=luke (28e16fd2f9) - Bug 1231333 - part 2, DOM: only allow futexWait in workers. r=khuey (6c4dc98037) - Bug 1148990 - Don't ship bagheeraclient.js or tokenserverclient.js on Android. r=gps (aa9b22699a) - Bug 1216749 - Land the Firefox Kinto.js client (r=rnewman) (ea8c74e2ea) - Bug 1230221 - Convert JS callsites to use asyncOpen2 within services/ (r=sicking) (07ac8751f1) - Bug 1242965 - Make services/common eslintable. r=rnewman (0c84562750) - Bug 1055616 - Skip addons addons without a sourceURI or from a non-secure domain rather than treating them as errors. r=rnewman (7b8b738be0) - Bug 1229986 - get Sync tps tests starting again. r=whimboo (8cd0bf4f7f) - Bug 1003204: Removed CommonUtils.exceptionStr() in services/sync r=makh r=gfritzsche (830c106a29) - Bug 1003204: Removed CommonUtils.exceptionStr() in services/common/ r=gfritzsche (2c7bd4f8b5) - Bug 1234734 - Replace CommonUtils.stackTrace() with Log.stackTrace(). r=markh (3f0e88f192) - Bug 1241715 - get Sync TPS tests working locally by tweaking observers listened for and the authentication setup. r=whimboo (529b2f3d44) - Bug 1203736 - Convert H264::DecodeSPS assert to error return. r=jya (41c8c34c42) - Bug 1186716: Error if SPS NAL parsing failed. r=rillian (6c158be51e) - Bug 1187076 - Warn at end of SPS buffers. r=jya (2a49671261) - fix broken files (a090aad200) - Bug 1218217: avoid buffersize overflow even if codec is unbounded in dimensions r=pkerr (356140c947) - Bug 1218217: bustage fix for static assert r=bustage (e86dc5bf3a) - Bug 1041882 - Remove Froyo-specific support from libcubeb. r=snorp, r=padenot (e1f2d5283f) - Bug 1073319 - Enable AVX2 for libvpx on linux (update.py). r=rillian (934fd0a896) - Bug 1245027 - Move LOCAL_INCLUDES to moz.build in media/libvpx. r=mshal (7e56797d0e) - parts of Bug 1151175 - Update libvpx update.py for 1.4.0. (0e3f4a470f) - bits of 1178215 (bab7592703) - Bug 1218124 - Add vpx_once patch to update script. r=gerald (7b72a43382) - Bug 1225221 - vpx: Allow 8k video in update.sh. r=kinetik (9ec59f7737) - Bug 1224363 - Upstream update patch - r=rillian (4772921a5f) - Bug 1224361 - Upstream update patch - r=rillian (36ad6f1de4) - Bug 1233983 - Make libvpx build with clang-cl; r=rillian (5d98a8d888) - Bug 1224371 - Upstream update patch. r=jya (25164ba856) - Bug 1237848 - Updated update.py patch - r=rillian (69646eb6dc) - Bug 1184226 - Suppressing received packets when disabled, r=ekr (c8dfdb1a56) - Bug 1184226 - Disabling write on shutdown, r=ekr (d5a810dbe5) - Bug 1184226 - Updating transportlayerdtls logging levels, r=ekr (f3bc4a9889) - Bug 1137932: Unwind the stack before starting the DTLS handshake. r=mt (69dce8243a) - Bug 1214269 - read multiple DTLS packets from NSS if present. r=mt rjesup (e57b1628f5) - Bug 1235235 - Fix -Wimplicit-fallthrough warning in media/mtransport/. r=ekr (d56c9d1244) - Bug 1115483 - Accept a match on any a=fingerprint value. r=ekr (4a58378c09) - Bug 1167274 - Do the right thing when accessing the proxyinfo fails for some reason. r=mt (3ea23173ea) - Bug 1125292 - Sending ALPN header field for WebRTC calls, r=bwc (16fda60c39) - Bug 1167443 - Fix verification of end-of-candidates in mochitests. r=mt (8d74546e68) - Bug 1192813 - update the default candidate as new candidates arrive. r=bwc (490ac80af2) - Bug 1206981 - prevent ICE TCP from being turned off under e10s. r=jesup (a38afd56b8) - Bug 1234578 - Assert if PCM is destroyed improperly. r=rjesup (f1aa0d7cbc) - Bug 1164564 - WorkerDebugger.initialize should not return failure when called more than once;r=khuey (c316c83af7) - Bug 1211903 - WorkerDebugger should live on the main thread;r=khuey (5586888e77) - Bug 1164581 - Adding an overload for NS_ProxyRelease that accepts already_AddRefed, and removing all the others. r=bobbyholley (bc70230689) - Bug 1186750 part 1 - Inlinize trivial constructors and destructors of events in DeviceStorageRequestParent. r=dhylands (0fc6b594b1) - Bug 1186750 part 2 - Remove some unused member fields in events in DeviceStorageRequestParent. r=dhylands (d4be7e7031) - Bug 1186750 part 3 - Abstract CancelableFileEvent in DeviceStorageReqeustParent and use already_AddRefed&& for passing DeviceStorageFile parameter. r=dhylands (cea4df4465) - Bug 1186750 part 4 - Clear runnable list in DeviceStorageRequestParent when being destroyed. r=dhylands (a4d6018ce6) - Bug 1196315 - Ensure MIME service is only accessed on the main thread. r=dhylands (20c07f4baf) - Bug 1186750 part 5 - Convert nsDOMDeviceStorage::CheckPermission to take already_AddRefed&&. r=dhylands (7b2d0b415e) - Bug 1186750 part 6 - Remove unused and unimplemented method nsDOMDeviceStorage::StorePermission. r=dhylands (e6772e7b51) - Bug 1186750 part 7 - Convert DispatchToOwningThread and DispatchOrAbandon to take already_AddRefed&&. r=dhylands (5925568a22) - Bug 1186750 part 8 - Convert DeviceStorageUsedSpaceCache::Dispatch to use already_AddRef&&. r=dhylands (660b44eec7) - Bug 1186750 part 9 - Use already_AddRefed&& to initialize mFile of device storage requests. r=dhylands (c94464f412) - Bug 1186750 part 10 - Simplify code in DeviceStorageRequestParent::Dispatch. r=dhylands (debcc219ca) - Bug 1186750 part 11 - Convert all usage of Dispatch/NS_DispatchToMainThread in dom/devicestorage to pass in either already_AddRefed or raw pointer. r=dhylands (753694d0b5) - Bug 1059469: Part 1 - Add a log module for dump() calls. r=bent (d94c677e49) - Bug 1059469: Part 2 - When rescheduling the interval timer, cancel it first, and refactor things so that actually does something. r=bent (1edc485b0f) - Bug 1243881 - patch 1 - unship performance.translateTime, r=bz (5a4afeea67) - Bug 1243881 - patch 2 - unship performance.translateTime, r=bz (5bf9557cd4) - Bug 1165722 - Replace JS_GetPropertyDescriptor usage in Xray code. r=bholley (e277cbcc78) - Bug 1243824. Add support for static functions and attributes on JSXrays. r=bholley (498d6c6034) - Bug 1228456 - SharedWorker should close the MessagePort in case the connecting runnable is not dispatched, r=smaug (c14a3e212f) - Bug 779707 - Add crashtest. (e86caca48e) - Bug 1228456 - add 'override' to the Cancel() method of a nsICancelableRunnable, rs=me (48db3b97e9) - Bug 1131323 - Enable SharedWorker loads to be intercepted through service workers; r=nsm (b2d972c5e3) - Bug 1173002 - Set worker system principal flag correctly when created from chrome, r=bz, a=kwierso. (ac9fc2980d) - bits of 1113429 backout (a862f16bb7) - bug 1206312 - add IndexedDatabaseManager include to IDBKeyRange. r=bz (bd6663f976) - Bug 1247117: De-namespace much of IndexedDB. r=baku (a996e3b443) - Bug 1196841: Update getAll/getAllKeys to match the spec and expose them. r=baku (7365769e04) - Bug 1196840: Make IDBTransaction::ObjectStoreNames const. r=baku (e7af2b0510) - Bug 1176165 - Fix the exception codes returned from functions that modify the IndexedDB schema, r=janv. (efa4e818d0) - Bug 935753 - Firefox displays the "This is a secure Firefox page" indicator on pages served by addons. r=MattN (77dced27ad) - Bug 925681 - Show identity block and reload icon in awesomebar in Australis' customization mode. ui-r=shorlander, r=Gijs (ffd1b2f6a4) - Bug 970382 - Add about:accounts to the list of chrome UIs with a special identity mode r=gavin (6d2817d087) - Bug 1051847 - Add trusted identity block to about:license and about:rights. r=dao (aa8dfe4d1d) - Bug 1094947 - The trusted identity block is not displayed for the about:downloads page. r=jaws (1c51faa077) - Bug 686281 - Implement CSS mask style; r=dbaron. (2f823c4a49) - Bug 686281 - Mask CSS parsing and Mask DOM API. r=dbaron (f9cc291131) - Bug 686281 - Mask CSS rendering; r=mstange (b26ba7ba7e) - Bug 686281 - Mask CSS animation; r=dbaron. (4ce1ba671e) - Bug 686281 - Mask CSS webkit-alias; r=dbaron. (c27f4023d6) - Bug 686281 - Mask mochitest; r=dbaron. (010fcdfd04) - Bug 686281 - Expands will-change of a shorthand prop to longhand ones; r=dbaron. (f8e4a6dcfd) - Bug 686281 - A static assertion to keep value correctness of NS_RULE_NODE_IS_ANIMATION_RULE; r=dbaron. (5ae87b576b) - Bug 686281 - Remove nsStyleSVGReset::mMask; r=dbaron (1e7a0dfb45) - Bug 686281 - mask-composite reftests; r=dbaron (7f769e196a) - Bug 686281 - Rename nsStyleSVGReset::mLayers to nsStyleSVGReset::mMask; Rename nsStyleBackground::mLayers to nsStyleBackground::mImage. r=dbaron (3bd4fc6e3b) - Bug 1241275 - Change the way -moz-window-dragging works. r=heycam,roc (5691f2dbf5) - Bug 1246892 - pass aCTF as a reference instead of value. r=roc (98b0e45063) - Bug 1234800 - Reinstate code that adjusts dirty rects for fixed-position frames in display ports. r=tn (44e55ebacb) - Bug 1234800 - Move this line to the right place. r=tn (1a86a7fc72) - Bug 1216832 - Handle preserve-3d visible regions during display list building by always transforming from the preserve-3d root each time. r=roc (1887af1172) - Bug 1231243 - In nsDisplayBackgroundImage::GetBoundsInternal(), take the union of the image bounds and the viewport bounds if APZ is enabled. r=mstange (87a1fa0ab4) - Bug 1246622 - Handle nested preserve-3d contexts when hit testing. r=roc (6eed51c734) - Bug 1235945 - Fix assertion error in some cases when running szip when debug flags are enabled for host tools. r=froydnj (3a0aa4f728) - Bug 1224798: Do not produce a clip mask if our context is entirely clipped out anyway. r=jrmuizel (3926a4ef7d) - Bug 1223604 - Disentangle nsSVGClipPathFrame::ApplyClipOrPaintClipMask and make the code easier to understand. r=Bas (c8c19a1b0d) - Bug 1204405: Don't access prefs off main thread in testing ProcessLink::Open(). r=khuey (301aa7259d) - Bug 1248896 - don't conditional compile on config ENABLE_TESTS in Nuwa. r=khuey (4f2fd275fd) - Bug 1232458 - use UniquePtr<T[]> instead of nsAutoArrayPtr<T> in WindowsDllBlocklist.cpp; r=aklotz (292071bdb5) - Bug 1247741 - Additional checks for pointer validity in LdrLoadDLL detour. r=aklotz (8ee48e8cf3) - Bug 1113930 - Move __libc_stack_end related code block from StackWalk.cpp in a non-OSX section. r=froydnj (4f0f9e2e66) - Bug 1113930 - Use the actual stack end address on x86 OSX and Android for the stack walker. r=froydnj (7371d9a508) - missing bit of Bug 1216681 (fdf69e362f) - Bug 1193593 - Test fingerprinting resistance for media queries in picture elements. r=heycam (6155b73c26) - Bug 1232829 - Detach obsolete DocumentTimeline from refresh driver when the document is reset; r=smaug (564680e2a0) - Bug 1075457, part 1 - Implement rendering for |clip-path:polygon()|. r=mstange, r=jwatt (76056caacd) - Bug 1075457, part 2 - Implement circle() and ellipse() for the |clip-path| property. r=mstange, r=jwatt (4b8b39c682) - Bug 1094571 - add unicode-range load tests. r=heycam (3358555411) - Bug 1216695 - Remove the Request.context specific bits from fetch-request-resources.https.html; r=bkelly (2315e50b97) - Bug 1193133 - Disable broken service worker wpt tests. r=bkelly (8f0205d5e7) - Bug 1199831: Fix a bunch of mixed-content violations in imported ServiceWorker WPTs. r=jdm (33f261ce91) - bit of Bug 603201 (325170577f) - Bug 1184798 - same origin, cors and no-cors load tests. r=bkelly (f8549dd0bb) - Bug 1210581: Test controlled worker loads (XHR, fetch, importScripts). r=ehsan (41a436df47) - Bug 1215196 - Fix web-platform-tests iframe scripts to avoid pulling in testharness.js in them; r=bkelly (a2edb0784c) - Bug 1242798 - Don't OSR into Ion on debuggee frames. (r=jandem) (21e17bdd9d) - Bug 1238658 - Allow setElem-accessor optimizations only for native baseHolder objects; r=efaust (12c9766a53) - Bug 1144630 - Follup: Fix review nit. (rs=evilpie) (67b5cc2c7f) - Bug 1182866 - Fix Baseline GETNAME stubs to check for uninitialized lexicals. (r=jandem) (dd47d2025a) - Bug 1189536 - Make fetch-request-xhr.https.html pass; r=bkelly (ce177226bf) - Bug 1188822 - Make service-workers/service-worker/fetch-request-resources.https.html pass. r=bkelly (3a5f3a6660)
905 lines
40 KiB
Python
905 lines
40 KiB
Python
# 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 IDLInterface, IDLExternalInterface, IDLImplementsStatement
|
|
import os
|
|
from collections import defaultdict
|
|
|
|
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, generatedEvents=[]):
|
|
|
|
# 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():
|
|
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]
|
|
if not isinstance(entry, list):
|
|
assert isinstance(entry, dict)
|
|
entry = [entry]
|
|
elif len(entry) == 1:
|
|
if entry[0].get("workers", False):
|
|
# List with only a workers descriptor means we should
|
|
# infer a mainthread descriptor. If you want only
|
|
# workers bindings, don't use a list here.
|
|
entry.append({})
|
|
else:
|
|
raise TypeError("Don't use a single-element list for "
|
|
"non-worker-only interface " + iface.identifier.name +
|
|
" in Bindings.conf")
|
|
elif len(entry) == 2:
|
|
if entry[0].get("workers", False) == entry[1].get("workers", False):
|
|
raise TypeError("The two entries for interface " + iface.identifier.name +
|
|
" in Bindings.conf should not have the same value for 'workers'")
|
|
else:
|
|
raise TypeError("Interface " + iface.identifier.name +
|
|
" should have no more than two entries in Bindings.conf")
|
|
descs = [Descriptor(self, iface, x) for x in entry]
|
|
self.descriptors.extend(descs)
|
|
# Setting up descriptorsByName while iterating through interfaces
|
|
# means we can get the nativeType of iterable interfaces without
|
|
# having to do multiple loops.
|
|
for d in descs:
|
|
self.descriptorsByName.setdefault(d.interface.identifier.name,
|
|
[]).append(d)
|
|
|
|
# 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()]
|
|
|
|
# Figure out what our main-thread and worker dictionaries and callbacks
|
|
# are.
|
|
mainTypes = set()
|
|
for descriptor in ([self.getDescriptor("DummyInterface", workers=False)] +
|
|
self.getDescriptors(workers=False, isExternal=False, skipGen=False)):
|
|
mainTypes |= set(getFlatTypes(getTypesFromDescriptor(descriptor)))
|
|
(mainCallbacks, mainDictionaries) = findCallbacksAndDictionaries(mainTypes)
|
|
|
|
workerTypes = set()
|
|
for descriptor in ([self.getDescriptor("DummyInterfaceWorkers", workers=True)] +
|
|
self.getDescriptors(workers=True, isExternal=False, skipGen=False)):
|
|
workerTypes |= set(getFlatTypes(getTypesFromDescriptor(descriptor)))
|
|
(workerCallbacks, workerDictionaries) = findCallbacksAndDictionaries(workerTypes)
|
|
|
|
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 tuples containing a
|
|
# type and descriptor 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 tuple for every use of
|
|
# a union type, so there can be multiple tuples with union types that
|
|
# have the same name.
|
|
self.unionsPerFilename = defaultdict(list)
|
|
|
|
for (t, descriptor, _) 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:
|
|
if 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[0].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, descriptor))
|
|
filenamesForUnion.add(t.filename())
|
|
|
|
def flagWorkerOrMainThread(items, main, worker):
|
|
for item in items:
|
|
if item in main:
|
|
item.setUserData("mainThread", True)
|
|
if item in worker:
|
|
item.setUserData("workers", True)
|
|
flagWorkerOrMainThread(self.callbacks, mainCallbacks, workerCallbacks)
|
|
|
|
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.getNavigatorProperty() is not None
|
|
elif key == 'isExposedInAnyWorker':
|
|
getter = lambda x: x.interface.isExposedInAnyWorker()
|
|
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)
|
|
|
|
@staticmethod
|
|
def _filterForFileAndWorkers(items, filters):
|
|
"""Gets the items that match the given filters."""
|
|
for key, val in filters.iteritems():
|
|
if key == 'webIDLFile':
|
|
items = filter(lambda x: x.filename() == val, items)
|
|
elif key == 'workers':
|
|
if val:
|
|
items = filter(lambda x: x.getUserData("workers", False), items)
|
|
else:
|
|
items = filter(lambda x: x.getUserData("mainThread", False), items)
|
|
else:
|
|
assert(0) # Unknown key
|
|
return items
|
|
|
|
def getDictionaries(self, **filters):
|
|
return self._filterForFileAndWorkers(self.dictionaries, filters)
|
|
|
|
def getCallbacks(self, **filters):
|
|
return self._filterForFileAndWorkers(self.callbacks, filters)
|
|
|
|
def getDescriptor(self, interfaceName, workers):
|
|
"""
|
|
Gets the appropriate descriptor for the given interface name
|
|
and the given workers boolean.
|
|
"""
|
|
# 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 lookups. But that means we have to do our normal
|
|
# lookups in a way that will not throw if they fail.
|
|
for d in self.descriptorsByName.get(interfaceName, []):
|
|
if d.workers == workers:
|
|
return d
|
|
|
|
if workers:
|
|
for d in self.descriptorsByName.get(interfaceName, []):
|
|
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")
|
|
|
|
def getDescriptorProvider(self, workers):
|
|
"""
|
|
Gets a descriptor provider that can provide descriptors as needed,
|
|
for the given workers boolean
|
|
"""
|
|
return DescriptorProvider(self, workers)
|
|
|
|
|
|
class NoSuchDescriptorError(TypeError):
|
|
def __init__(self, str):
|
|
TypeError.__init__(self, str)
|
|
|
|
|
|
class DescriptorProvider:
|
|
"""
|
|
A way of getting descriptors for interface names
|
|
"""
|
|
def __init__(self, config, workers):
|
|
self.config = config
|
|
self.workers = workers
|
|
|
|
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.
|
|
"""
|
|
return self.config.getDescriptor(interfaceName, self.workers)
|
|
|
|
|
|
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, config, desc.get('workers', False))
|
|
self.interface = interface
|
|
|
|
if self.workers:
|
|
assert 'wantsXrays' not in desc
|
|
self.wantsXrays = False
|
|
else:
|
|
self.wantsXrays = desc.get('wantsXrays', True)
|
|
|
|
# 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():
|
|
assert not self.workers
|
|
nativeTypeDefault = "nsIDOM" + ifaceName
|
|
elif self.interface.isCallback():
|
|
nativeTypeDefault = "mozilla::dom::" + ifaceName
|
|
else:
|
|
if self.workers:
|
|
nativeTypeDefault = "mozilla::dom::workers::" + 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 self.workers:
|
|
headerDefault = "mozilla/dom/workers/bindings/%s.h" % ifaceName
|
|
elif 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.skipGen = desc.get('skipGen', False)
|
|
|
|
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
|
|
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))
|
|
|
|
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()
|
|
|
|
def make_name(name):
|
|
return name + "_workers" if self.workers else name
|
|
self.name = make_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, {}))
|
|
|
|
self._binaryNames = desc.get('binaryNames', {})
|
|
self._binaryNames.setdefault('__legacycaller', 'LegacyCall')
|
|
self._binaryNames.setdefault('__stringifier', 'Stringify')
|
|
|
|
if not self.interface.isExternal():
|
|
self.anypermissions = dict()
|
|
self.allpermissions = dict()
|
|
|
|
# Adds a permission list to this descriptor and returns the index to use.
|
|
def addPermissions(ifaceOrMember, attribute):
|
|
if attribute == "CheckAllPermissions":
|
|
permissions = self.allpermissions
|
|
else:
|
|
permissions = self.anypermissions
|
|
|
|
checkPermissions = ifaceOrMember.getExtendedAttribute(attribute)
|
|
if checkPermissions is None:
|
|
return None
|
|
|
|
# It's a list of whitespace-separated strings
|
|
assert(len(checkPermissions) is 1)
|
|
assert(checkPermissions[0] is not None)
|
|
checkPermissions = checkPermissions[0]
|
|
permissionsList = checkPermissions.split()
|
|
if len(permissionsList) == 0:
|
|
raise TypeError("Need at least one permission name for %s" % attribute)
|
|
|
|
permissionsList = tuple(sorted(set(permissionsList)))
|
|
return permissions.setdefault(permissionsList, len(permissions))
|
|
|
|
self.checkAnyPermissionsIndex = addPermissions(self.interface, "CheckAnyPermissions")
|
|
self.checkAnyPermissionsIndicesForMembers = dict()
|
|
self.checkAllPermissionsIndex = addPermissions(self.interface, "CheckAllPermissions")
|
|
self.checkAllPermissionsIndicesForMembers = dict()
|
|
for m in self.interface.members:
|
|
permissionsIndex = addPermissions(m, "CheckAnyPermissions")
|
|
if permissionsIndex is not None:
|
|
self.checkAnyPermissionsIndicesForMembers[m.identifier.name] = permissionsIndex
|
|
allpermissionsIndex = addPermissions(m, "CheckAllPermissions")
|
|
if allpermissionsIndex is not None:
|
|
self.checkAllPermissionsIndicesForMembers[m.identifier.name] = allpermissionsIndex
|
|
|
|
def isTestInterface(iface):
|
|
return (iface.identifier.name in ["TestInterface",
|
|
"TestJSImplInterface",
|
|
"TestRenamedInterface"])
|
|
|
|
self.featureDetectibleThings = set()
|
|
if not isTestInterface(self.interface):
|
|
if (self.interface.getExtendedAttribute("CheckAnyPermissions") or
|
|
self.interface.getExtendedAttribute("CheckAllPermissions") or
|
|
self.interface.getExtendedAttribute("AvailableIn") == "PrivilegedApps"):
|
|
if self.interface.getNavigatorProperty():
|
|
self.featureDetectibleThings.add("Navigator.%s" % self.interface.getNavigatorProperty())
|
|
else:
|
|
iface = self.interface.identifier.name
|
|
self.featureDetectibleThings.add(iface)
|
|
for m in self.interface.members:
|
|
self.featureDetectibleThings.add("%s.%s" % (iface, m.identifier.name))
|
|
|
|
for m in self.interface.members:
|
|
if (m.getExtendedAttribute("CheckAnyPermissions") or
|
|
m.getExtendedAttribute("CheckAllPermissions") or
|
|
m.getExtendedAttribute("AvailableIn") == "PrivilegedApps"):
|
|
self.featureDetectibleThings.add("%s.%s" % (self.interface.identifier.name, m.identifier.name))
|
|
|
|
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 (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()
|
|
|
|
@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):
|
|
assert(attr is None or attr is True or len(attr) == 1)
|
|
if (attr is not None and attr is not True and
|
|
'Workers' not in attr and 'MainThread' not in attr):
|
|
raise TypeError("Unknown value for 'Throws': " + attr[0])
|
|
|
|
def maybeAppendInfallibleToAttrs(attrs, throws):
|
|
ensureValidThrowsExtendedAttribute(throws)
|
|
if (throws is None or
|
|
(throws is not True and
|
|
('Workers' not in throws or not self.workers) and
|
|
('MainThread' not in throws or self.workers))):
|
|
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 needsConstructHookHolder(self):
|
|
assert self.interface.hasInterfaceObject()
|
|
return False
|
|
|
|
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):
|
|
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 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"))
|
|
|
|
|
|
# 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())
|
|
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 findCallbacksAndDictionaries(inputTypes):
|
|
"""
|
|
Ensure that all callbacks and dictionaries reachable from types end up in
|
|
the returned callbacks and dictionaries sets.
|
|
|
|
Note that we assume that our initial invocation already includes all types
|
|
reachable via descriptors in "types", so we only have to deal with things
|
|
that are themeselves reachable via callbacks and dictionaries.
|
|
"""
|
|
def doFindCallbacksAndDictionaries(types, callbacks, dictionaries):
|
|
unhandledTypes = set()
|
|
for type in types:
|
|
if type.isCallback() and type.callback not in callbacks:
|
|
unhandledTypes |= getFlatTypes(getTypesFromCallback(type.callback))
|
|
callbacks.add(type.callback)
|
|
elif type.isDictionary() and type.inner not in dictionaries:
|
|
d = type.inner
|
|
unhandledTypes |= getFlatTypes(getTypesFromDictionary(d))
|
|
while d:
|
|
dictionaries.add(d)
|
|
d = d.parent
|
|
if len(unhandledTypes) != 0:
|
|
doFindCallbacksAndDictionaries(unhandledTypes, callbacks, dictionaries)
|
|
|
|
retCallbacks = set()
|
|
retDictionaries = set()
|
|
doFindCallbacksAndDictionaries(inputTypes, retCallbacks, retDictionaries)
|
|
return (retCallbacks, retDictionaries)
|
|
|
|
|
|
def getAllTypes(descriptors, dictionaries, callbacks):
|
|
"""
|
|
Generate all the types we're dealing with. For each type, a tuple
|
|
containing type, descriptor, dictionary is yielded. The
|
|
descriptor and dictionary can be None if the type does not come
|
|
from a descriptor or dictionary; they will never both be non-None.
|
|
"""
|
|
for d in descriptors:
|
|
if d.interface.isExternal():
|
|
continue
|
|
for t in getTypesFromDescriptor(d):
|
|
yield (t, d, None)
|
|
for dictionary in dictionaries:
|
|
for t in getTypesFromDictionary(dictionary):
|
|
yield (t, None, dictionary)
|
|
for callback in callbacks:
|
|
for t in getTypesFromCallback(callback):
|
|
yield (t, None, None)
|
|
|
|
def iteratorNativeType(descriptor):
|
|
assert descriptor.interface.isIterable()
|
|
iterableDecl = descriptor.interface.maplikeOrSetlikeOrIterable
|
|
assert iterableDecl.isPairIterator()
|
|
return "mozilla::dom::IterableIterator<%s>" % descriptor.nativeType
|