Skip to content

Commit

Permalink
Bug 1009645 - Implement [FeatureDetectible] extended attribute and ho…
Browse files Browse the repository at this point in the history
…ok it up to navigator.getFeature. r=bz
  • Loading branch information
reuben committed Jul 14, 2014
1 parent 60b9736 commit 9078116
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 2 deletions.
14 changes: 14 additions & 0 deletions dom/base/Navigator.cpp
Expand Up @@ -106,6 +106,8 @@
#endif
#include "mozilla/dom/ContentChild.h"

#include "mozilla/dom/FeatureList.h"

namespace mozilla {
namespace dom {

Expand Down Expand Up @@ -1534,6 +1536,18 @@ Navigator::GetFeature(const nsAString& aName)
}
}

NS_NAMED_LITERAL_STRING(apiWindowPrefix, "api.window.");
if (StringBeginsWith(aName, apiWindowPrefix)) {
const nsAString& featureName = Substring(aName, apiWindowPrefix.Length(), aName.Length()-apiWindowPrefix.Length());
printf_stderr("apiWindowPrefix.Length(): %d, aName.Length(): %d\n", apiWindowPrefix.Length(), aName.Length());
if (IsFeatureDetectible(featureName)) {
p->MaybeResolve(true);
} else {
p->MaybeResolve(JS::UndefinedHandleValue);
}
return p.forget();
}

// resolve with <undefined> because the feature name is not supported
p->MaybeResolve(JS::UndefinedHandleValue);

Expand Down
30 changes: 30 additions & 0 deletions dom/bindings/Codegen.py
Expand Up @@ -13667,6 +13667,36 @@ def UnionConversions(config):
# Done.
return curr

@staticmethod
def FeatureList(config):
things = set()
for d in config.getDescriptors():
if not d.interface.isExternal() and d.featureDetectibleThings is not None:
things.update(d.featureDetectibleThings)
things = CGList((CGGeneric(declare='"%s",' % t) for t in sorted(things)), joiner="\n")
things.append(CGGeneric(declare="nullptr"))
things = CGWrapper(CGIndenter(things), pre="static const char* const FeatureList[] = {\n",
post="\n};\n")

helper = CGWrapper(CGIndenter(things), pre="bool IsFeatureDetectible(const nsAString& aFeature) {\n",
post=dedent("""
const char* const* feature = FeatureList;
while (*feature) {
if (aFeature.EqualsASCII(*feature)) {
return true;
}
++feature;
}

return false;
}
"""))

curr = CGNamespace.build(['mozilla', 'dom'], helper)
curr = CGHeaders([], [], [], [], ["nsString.h"], [], 'FeatureList', curr)
curr = CGIncludeGuard('FeatureList', curr)

return curr

# Code generator for simple events
class CGEventGetter(CGNativeMember):
Expand Down
12 changes: 12 additions & 0 deletions dom/bindings/Configuration.py
Expand Up @@ -445,6 +445,18 @@ def addPermissions(ifaceOrMember):
if permissionsIndex is not None:
self.checkPermissionsIndicesForMembers[m.identifier.name] = permissionsIndex

self.featureDetectibleThings = set()
if self.interface.getExtendedAttribute("FeatureDetectible") is not None:
if self.interface.getNavigatorProperty():
self.featureDetectibleThings.add("Navigator.%s" % self.interface.getNavigatorProperty())
else:
assert(self.interface.ctor() is not None)
self.featureDetectibleThings.add(self.interface.identifier.name)

for m in self.interface.members:
if m.getExtendedAttribute("FeatureDetectible") is not None:
self.featureDetectibleThings.add("%s.%s" % (self.interface.identifier.name, m.identifier.name))

# Build the prototype chain.
self.prototypeChain = []
parent = interface
Expand Down
1 change: 1 addition & 0 deletions dom/bindings/mozwebidlcodegen/__init__.py
Expand Up @@ -127,6 +127,7 @@ class WebIDLCodegenManager(LoggingMixin):

# Global parser derived declaration files.
GLOBAL_DECLARE_FILES = {
'FeatureList.h',
'GeneratedAtomList.h',
'PrototypeList.h',
'RegisterBindings.h',
Expand Down
47 changes: 45 additions & 2 deletions dom/bindings/parser/WebIDL.py
Expand Up @@ -568,6 +568,16 @@ def finish(self, scope):
[self.location])
assert not parent or isinstance(parent, IDLInterface)

if self.getExtendedAttribute("FeatureDetectible"):
if self.getExtendedAttribute("NoInterfaceObject"):
raise WebIDLError("[FeatureDetectible] not allowed on interface "
" with [NoInterfaceObject]",
[self.location])
if self.getExtendedAttribute("Pref"):
raise WebIDLError("[FeatureDetectible] must not be specified "
"in combination with [Pref]",
[self.location])

self.parent = parent

assert iter(self.members)
Expand Down Expand Up @@ -1041,7 +1051,8 @@ def addExtendedAttributes(self, attrs):
identifier == "OverrideBuiltins" or
identifier == "ChromeOnly" or
identifier == "Unforgeable" or
identifier == "LegacyEventInit"):
identifier == "LegacyEventInit" or
identifier == "FeatureDetectible"):
# Known extended attributes that do not take values
if not attr.noArguments():
raise WebIDLError("[%s] must take no arguments" % identifier,
Expand Down Expand Up @@ -2890,6 +2901,18 @@ def finish(self, scope):
raise WebIDLError("An attribute with [SameObject] must have an "
"interface type as its type", [self.location])

if self.getExtendedAttribute("FeatureDetectible"):
if not (self.getExtendedAttribute("Func") or
self.getExtendedAttribute("AvailableIn") or
self.getExtendedAttribute("CheckPermissions")):
raise WebIDLError("[%s] is only allowed in combination with [Func], "
"[AvailableIn] or [CheckPermissions]" % identifier,
[attr.location, self.location])
if self.getExtendedAttribute("Pref"):
raise WebIDLError("[FeatureDetectible] must not be specified "
"in combination with [Pref]",
[self.location])

def validate(self):
if ((self.getExtendedAttribute("Cached") or
self.getExtendedAttribute("StoreInSlot")) and
Expand Down Expand Up @@ -3008,6 +3031,13 @@ def handleExtendedAttribute(self, attr):
raise WebIDLError("[LenientThis] is not allowed in combination "
"with [%s]" % identifier,
[attr.location, self.location])
elif identifier == "FeatureDetectible":
if not (self.getExtendedAttribute("Func") or
self.getExtendedAttribute("AvailableIn") or
self.getExtendedAttribute("CheckPermissions")):
raise WebIDLError("[%s] is only allowed in combination with [Func], "
"[AvailableIn] or [CheckPermissions]" % identifier,
[attr.location, self.location])
elif (identifier == "Pref" or
identifier == "SetterThrows" or
identifier == "Pure" or
Expand Down Expand Up @@ -3423,6 +3453,18 @@ def signatures(self):
self._overloads]

def finish(self, scope):
if self.getExtendedAttribute("FeatureDetectible"):
if not (self.getExtendedAttribute("Func") or
self.getExtendedAttribute("AvailableIn") or
self.getExtendedAttribute("CheckPermissions")):
raise WebIDLError("[FeatureDetectible] is only allowed in combination "
"with [Func], [AvailableIn] or [CheckPermissions]",
[self.location])
if self.getExtendedAttribute("Pref"):
raise WebIDLError("[FeatureDetectible] must not be specified "
"in combination with [Pref]",
[self.location])

overloadWithPromiseReturnType = None
overloadWithoutPromiseReturnType = None
for overload in self._overloads:
Expand Down Expand Up @@ -3593,7 +3635,8 @@ def handleExtendedAttribute(self, attr):
[attr.location, self.location])
elif (identifier == "Pure" or
identifier == "CrossOriginCallable" or
identifier == "WebGLHandlesContextLoss"):
identifier == "WebGLHandlesContextLoss" or
identifier == "FeatureDetectible"):
# Known no-argument attributes.
if not attr.noArguments():
raise WebIDLError("[%s] must take no arguments" % identifier,
Expand Down

0 comments on commit 9078116

Please sign in to comment.