Bug 1489301 - Part 1: Expose Window interfaces on System by default, r=bzbarsky
☠☠ backed out by 77f4c84bebf0 ☠ ☠
authorNika Layzell <nika@thelayzells.com>
Sat, 20 Oct 2018 18:10:07 -0400
changeset 490727 ff8fb091198ee6f4c86ffd4625089dd9751630a0
parent 490726 bbb8bac97270807cf396a7d0c33a777e6a57d4d0
child 490728 19ca10fa37725e9b1a52d05bf2ed479e2a8d4a73
push id247
push userfmarier@mozilla.com
push dateSat, 27 Oct 2018 01:06:44 +0000
reviewersbzbarsky
bugs1489301
milestone65.0a1
Bug 1489301 - Part 1: Expose Window interfaces on System by default, r=bzbarsky This is done by adding BackstagePass the exposure set of Window. Differential Revision: https://phabricator.services.mozilla.com/D9398
dom/bindings/parser/WebIDL.py
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -322,16 +322,23 @@ class IDLScope(IDLObject):
     def _lookupIdentifier(self, identifier):
         return self._dict[identifier.name]
 
     def lookupIdentifier(self, identifier):
         assert isinstance(identifier, IDLIdentifier)
         assert identifier.scope == self
         return self._lookupIdentifier(identifier)
 
+    def addIfaceGlobalNames(self, interfaceName, globalNames):
+        """Record the global names (from |globalNames|) that can be used in
+        [Exposed] to expose things in a global named |interfaceName|"""
+        self.globalNames.update(globalNames)
+        for name in globalNames:
+            self.globalNameMapping[name].add(interfaceName)
+
 
 class IDLIdentifier(IDLObject):
     def __init__(self, location, scope, name):
         IDLObject.__init__(self, location)
 
         self.name = name
         assert isinstance(scope, IDLScope)
         self.scope = scope
@@ -499,18 +506,20 @@ class IDLExposureMixins():
 
         globalNameSetToExposureSet(scope, self._exposureGlobalNames,
                                    self.exposureSet)
 
     def isExposedInWindow(self):
         return 'Window' in self.exposureSet
 
     def isExposedOnMainThread(self):
-        return (self.isExposedInWindow() or
-                self.isExposedInSystemGlobals())
+        return bool(self.exposureSet & {'Window', 'BackstagePass'})
+
+    def isExposedOffMainThread(self):
+        return bool(self.exposureSet - {'Window', 'BackstagePass'})
 
     def isExposedInAnyWorker(self):
         return len(self.getWorkerExposureSet()) > 0
 
     def isExposedInWorkerDebugger(self):
         return len(self.getWorkerDebuggerExposureSet()) > 0
 
     def isExposedInAnyWorklet(self):
@@ -1318,20 +1327,19 @@ class IDLInterfaceOrNamespace(IDLObjectW
 
             # Check that the name of a [BindingAlias] doesn't conflict with an
             # interface member.
             if member.isAttr():
                 for bindingAlias in member.bindingAliases:
                     checkDuplicateNames(member, bindingAlias, "BindingAlias")
 
 
-        if (self.getExtendedAttribute("Pref") and
-            self._exposureGlobalNames != set([self.parentScope.primaryGlobalName])):
-            raise WebIDLError("[Pref] used on an interface that is not %s-only" %
-                              self.parentScope.primaryGlobalName,
+        if self.getExtendedAttribute("Pref") and self.isExposedOffMainThread():
+            raise WebIDLError("[Pref] used on an interface that is not "
+                              "main-thread-only",
                               [self.location])
 
         # Conditional exposure makes no sense for interfaces with no
         # interface object, unless they're navigator properties.
         # And SecureContext makes sense for interfaces with no interface object,
         # since it is also propagated to interface members.
         if (self.isExposedConditionally(exclusions=["SecureContext"]) and
             not self.hasInterfaceObject() and
@@ -1705,33 +1713,32 @@ class IDLInterface(IDLInterfaceOrNamespa
                                       [attr.location, self.location])
             elif identifier == "Global":
                 if attr.hasValue():
                     self.globalNames = [attr.value()]
                 elif attr.hasArgs():
                     self.globalNames = attr.args()
                 else:
                     self.globalNames = [self.identifier.name]
-                self.parentScope.globalNames.update(self.globalNames)
-                for globalName in self.globalNames:
-                    self.parentScope.globalNameMapping[globalName].add(self.identifier.name)
+                self.parentScope.addIfaceGlobalNames(self.identifier.name,
+                                                     self.globalNames)
                 self._isOnGlobalProtoChain = True
             elif identifier == "PrimaryGlobal":
                 if not attr.noArguments():
                     raise WebIDLError("[PrimaryGlobal] must take no arguments",
                                       [attr.location])
                 if self.parentScope.primaryGlobalAttr is not None:
                     raise WebIDLError(
                         "[PrimaryGlobal] specified twice",
                         [attr.location,
                          self.parentScope.primaryGlobalAttr.location])
                 self.parentScope.primaryGlobalAttr = attr
                 self.parentScope.primaryGlobalName = self.identifier.name
-                self.parentScope.globalNames.add(self.identifier.name)
-                self.parentScope.globalNameMapping[self.identifier.name].add(self.identifier.name)
+                self.parentScope.addIfaceGlobalNames(self.identifier.name,
+                                                     [self.identifier.name])
                 self._isOnGlobalProtoChain = True
             elif identifier == "SecureContext":
                 if not attr.noArguments():
                     raise WebIDLError("[%s] must take no arguments" % identifier,
                                       [attr.location])
                 # This gets propagated to all our members.
                 for member in self.members:
                     if member.getExtendedAttribute("SecureContext"):
@@ -3567,20 +3574,19 @@ class IDLInterfaceMember(IDLObjectWithId
     def finish(self, scope):
         # We better be exposed _somewhere_.
         if (len(self._exposureGlobalNames) == 0):
             print self.identifier.name
         assert len(self._exposureGlobalNames) != 0
         IDLExposureMixins.finish(self, scope)
 
     def validate(self):
-        if (self.getExtendedAttribute("Pref") and
-            self.exposureSet != set([self._globalScope.primaryGlobalName])):
+        if self.getExtendedAttribute("Pref") and self.isExposedOffMainThread():
             raise WebIDLError("[Pref] used on an interface member that is not "
-                              "%s-only" % self._globalScope.primaryGlobalName,
+                              "main-thread-only",
                               [self.location])
 
         if self.isAttr() or self.isMethod():
             if self.affects == "Everything" and self.dependsOn != "Everything":
                 raise WebIDLError("Interface member is flagged as affecting "
                                   "everything but not depending on everything. "
                                   "That seems rather unlikely.",
                                   [self.location])
@@ -6891,26 +6897,29 @@ class Parser(Tokenizer):
                                     # We're not pickling for now, until it
                                     # becomes a speedup again.
                                     # , picklefile='WebIDLGrammar.pkl'
             )
         finally:
             logger.reportGrammarErrors()
 
         self._globalScope = IDLScope(BuiltinLocation("<Global Scope>"), None, None)
+
         # To make our test harness work, pretend like we have a primary global already.
         # Note that we _don't_ set _globalScope.primaryGlobalAttr,
         # so we'll still be able to detect multiple PrimaryGlobal extended attributes.
         self._globalScope.primaryGlobalName = "FakeTestPrimaryGlobal"
-        self._globalScope.globalNames.add("FakeTestPrimaryGlobal")
-        self._globalScope.globalNameMapping["FakeTestPrimaryGlobal"].add("FakeTestPrimaryGlobal")
-        # And we add the special-cased "System" global name, which
-        # doesn't have any corresponding interfaces.
-        self._globalScope.globalNames.add("System")
-        self._globalScope.globalNameMapping["System"].add("BackstagePass")
+        self._globalScope.addIfaceGlobalNames("FakeTestPrimaryGlobal", ["FakeTestPrimaryGlobal"])
+
+        # We also add global names for "BackstagePass", which doesn't have any
+        # corresponding interfaces. Expose all Window interfaces, as Chrome
+        # code should be able to access them, as well as System-only
+        # interfaces.
+        self._globalScope.addIfaceGlobalNames("BackstagePass", ["Window", "System"])
+
         self._installBuiltins(self._globalScope)
         self._productions = []
 
         self._filename = "<builtin>"
         self.lexer.input(Parser._builtins)
         self._filename = None
 
         self.parser.parse(lexer=self.lexer, tracking=True)