aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom/bindings/codegen
diff options
context:
space:
mode:
Diffstat (limited to 'components/script/dom/bindings/codegen')
-rw-r--r--components/script/dom/bindings/codegen/CodegenRust.py179
-rw-r--r--components/script/dom/bindings/codegen/Configuration.py8
-rw-r--r--components/script/dom/bindings/codegen/GlobalGen.py30
-rw-r--r--components/script/dom/bindings/codegen/api.html.template6
-rw-r--r--components/script/dom/bindings/codegen/apis.html.template35
-rw-r--r--components/script/dom/bindings/codegen/interface.html.template1
-rw-r--r--components/script/dom/bindings/codegen/parser/WebIDL.py809
-rw-r--r--components/script/dom/bindings/codegen/parser/abstract.patch12
-rw-r--r--components/script/dom/bindings/codegen/parser/debug.patch20
-rw-r--r--components/script/dom/bindings/codegen/parser/pref-main-thread.patch28
-rw-r--r--components/script/dom/bindings/codegen/parser/tests/test_conditional_dictionary_member.py110
-rw-r--r--components/script/dom/bindings/codegen/parser/tests/test_namespace.py223
-rw-r--r--components/script/dom/bindings/codegen/parser/tests/test_securecontext_extended_attribute.py318
-rwxr-xr-xcomponents/script/dom/bindings/codegen/parser/update.sh3
-rw-r--r--components/script/dom/bindings/codegen/property.html.template3
15 files changed, 1396 insertions, 389 deletions
diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py
index e6e95ab1cb8..8360dfc322a 100644
--- a/components/script/dom/bindings/codegen/CodegenRust.py
+++ b/components/script/dom/bindings/codegen/CodegenRust.py
@@ -8,6 +8,7 @@ from collections import defaultdict
from itertools import groupby
import operator
+import os
import re
import string
import textwrap
@@ -87,6 +88,11 @@ def stripTrailingWhitespace(text):
return '\n'.join(lines) + tail
+def innerSequenceType(type):
+ assert type.isSequence()
+ return type.inner.inner if type.nullable() else type.inner
+
+
def MakeNativeName(name):
return name[0].upper() + name[1:]
@@ -713,7 +719,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
raise TypeError("Can't handle array arguments yet")
if type.isSequence():
- innerInfo = getJSToNativeConversionInfo(type.unroll(), descriptorProvider)
+ innerInfo = getJSToNativeConversionInfo(innerSequenceType(type), descriptorProvider)
declType = CGWrapper(innerInfo.declType, pre="Vec<", post=">")
config = getConversionConfigForType(type, isEnforceRange, isClamp, treatNullAs)
@@ -1302,8 +1308,7 @@ def getRetvalDeclarationForType(returnType, descriptorProvider):
if returnType.isObject() or returnType.isSpiderMonkeyInterface():
return CGGeneric("*mut JSObject")
if returnType.isSequence():
- inner = returnType.unroll()
- result = getRetvalDeclarationForType(inner, descriptorProvider)
+ result = getRetvalDeclarationForType(innerSequenceType(returnType), descriptorProvider)
result = CGWrapper(result, pre="Vec<", post=">")
if returnType.nullable():
result = CGWrapper(result, pre="Option<", post=">")
@@ -1817,20 +1822,25 @@ def DOMClassTypeId(desc):
def DOMClass(descriptor):
- protoList = ['PrototypeList::ID::' + proto for proto in descriptor.prototypeChain]
- # Pad out the list to the right length with ID::Last so we
- # guarantee that all the lists are the same length. ID::Last
- # is never the ID of any prototype, so it's safe to use as
- # padding.
- protoList.extend(['PrototypeList::ID::Last'] * (descriptor.config.maxProtoChainLength - len(protoList)))
- prototypeChainString = ', '.join(protoList)
- heapSizeOf = 'heap_size_of_raw_self_and_children::<%s>' % descriptor.interface.identifier.name
- return """\
+ protoList = ['PrototypeList::ID::' + proto for proto in descriptor.prototypeChain]
+ # Pad out the list to the right length with ID::Last so we
+ # guarantee that all the lists are the same length. ID::Last
+ # is never the ID of any prototype, so it's safe to use as
+ # padding.
+ protoList.extend(['PrototypeList::ID::Last'] * (descriptor.config.maxProtoChainLength - len(protoList)))
+ prototypeChainString = ', '.join(protoList)
+ heapSizeOf = 'heap_size_of_raw_self_and_children::<%s>' % descriptor.interface.identifier.name
+ if descriptor.isGlobal():
+ globals_ = camel_to_upper_snake(descriptor.name)
+ else:
+ globals_ = 'EMPTY'
+ return """\
DOMClass {
interface_chain: [ %s ],
type_id: %s,
heap_size_of: %s as unsafe fn(_) -> _,
-}""" % (prototypeChainString, DOMClassTypeId(descriptor), heapSizeOf)
+ global: InterfaceObjectMap::%s,
+}""" % (prototypeChainString, DOMClassTypeId(descriptor), heapSizeOf, globals_)
class CGDOMJSClass(CGThing):
@@ -2067,7 +2077,7 @@ def UnionTypes(descriptors, dictionaries, callbacks, config):
'dom::bindings::conversions::root_from_handlevalue',
'dom::bindings::error::throw_not_in_union',
'dom::bindings::js::Root',
- 'dom::bindings::str::{DOMString, USVString}',
+ 'dom::bindings::str::{ByteString, DOMString, USVString}',
'dom::types::*',
'js::jsapi::JSContext',
'js::jsapi::{HandleValue, MutableHandleValue}',
@@ -2143,8 +2153,8 @@ class CGAbstractMethod(CGThing):
docs is None or documentation for the method in a string.
"""
def __init__(self, descriptor, name, returnType, args, inline=False,
- alwaysInline=False, extern=False, pub=False, templateArgs=None,
- unsafe=False, docs=None, doesNotPanic=False):
+ alwaysInline=False, extern=False, unsafe_fn=False, pub=False,
+ templateArgs=None, unsafe=False, docs=None, doesNotPanic=False):
CGThing.__init__(self)
self.descriptor = descriptor
self.name = name
@@ -2152,6 +2162,7 @@ class CGAbstractMethod(CGThing):
self.args = args
self.alwaysInline = alwaysInline
self.extern = extern
+ self.unsafe_fn = extern or unsafe_fn
self.templateArgs = templateArgs
self.pub = pub
self.unsafe = unsafe
@@ -2178,13 +2189,15 @@ class CGAbstractMethod(CGThing):
if self.alwaysInline:
decorators.append('#[inline]')
- if self.extern:
- decorators.append('unsafe')
- decorators.append('extern')
-
if self.pub:
decorators.append('pub')
+ if self.unsafe_fn:
+ decorators.append('unsafe')
+
+ if self.extern:
+ decorators.append('extern')
+
if not decorators:
return ''
return ' '.join(decorators) + ' '
@@ -2230,45 +2243,37 @@ match result {
class CGConstructorEnabled(CGAbstractMethod):
"""
- A method for testing whether we should be exposing this interface
- object or navigator property. This can perform various tests
- depending on what conditions are specified on the interface.
+ A method for testing whether we should be exposing this interface object.
+ This can perform various tests depending on what conditions are specified
+ on the interface.
"""
def __init__(self, descriptor):
CGAbstractMethod.__init__(self, descriptor,
'ConstructorEnabled', 'bool',
[Argument("*mut JSContext", "aCx"),
- Argument("HandleObject", "aObj")])
+ Argument("HandleObject", "aObj")],
+ unsafe_fn=True)
def definition_body(self):
- body = CGList([], "\n")
-
conditions = []
iface = self.descriptor.interface
+ bits = " | ".join(sorted(
+ "InterfaceObjectMap::" + camel_to_upper_snake(i) for i in iface.exposureSet
+ ))
+ conditions.append("is_exposed_in(aObj, %s)" % bits)
+
pref = iface.getExtendedAttribute("Pref")
if pref:
assert isinstance(pref, list) and len(pref) == 1
conditions.append('PREFS.get("%s").as_boolean().unwrap_or(false)' % pref[0])
+
func = iface.getExtendedAttribute("Func")
if func:
assert isinstance(func, list) and len(func) == 1
conditions.append("%s(aCx, aObj)" % func[0])
- # We should really have some conditions
- assert len(body) or len(conditions)
-
- conditionsWrapper = ""
- if len(conditions):
- conditionsWrapper = CGWrapper(CGList((CGGeneric(cond) for cond in conditions),
- " &&\n"),
- pre="return ",
- post=";\n",
- reindent=True)
- else:
- conditionsWrapper = CGGeneric("return true;\n")
- body.append(conditionsWrapper)
- return body
+ return CGList((CGGeneric(cond) for cond in conditions), " &&\n")
def CreateBindingJSObject(descriptor, parent=None):
@@ -2806,27 +2811,27 @@ class CGDefineDOMInterfaceMethod(CGAbstractMethod):
Argument('*mut JSContext', 'cx'),
Argument('HandleObject', 'global'),
]
- CGAbstractMethod.__init__(self, descriptor, 'DefineDOMInterface', 'void', args, pub=True)
+ CGAbstractMethod.__init__(self, descriptor, 'DefineDOMInterface',
+ 'void', args, pub=True, unsafe_fn=True)
def define(self):
return CGAbstractMethod.define(self)
def definition_body(self):
- def getCheck(desc):
- if not desc.isExposedConditionally():
- return ""
- else:
- return "if !ConstructorEnabled(cx, global) { return; }"
if self.descriptor.interface.isCallback():
function = "GetConstructorObject"
else:
function = "GetProtoObject"
return CGGeneric("""\
assert!(!global.get().is_null());
-%s
+
+if !ConstructorEnabled(cx, global) {
+ return;
+}
+
rooted!(in(cx) let mut proto = ptr::null_mut());
%s(cx, global, proto.handle_mut());
-assert!(!proto.is_null());""" % (getCheck(self.descriptor), function))
+assert!(!proto.is_null());""" % (function,))
def needCx(returnType, arguments, considerTypes):
@@ -3743,12 +3748,15 @@ def getUnionTypeTemplateVars(type, descriptorProvider):
typeName = name
elif type.isSequence():
name = type.name
- inner = getUnionTypeTemplateVars(type.unroll(), descriptorProvider)
+ inner = getUnionTypeTemplateVars(innerSequenceType(type), descriptorProvider)
typeName = "Vec<" + inner["typeName"] + ">"
elif type.isArray():
name = str(type)
# XXXjdm dunno about typeName here
typeName = "/*" + type.name + "*/"
+ elif type.isByteString():
+ name = type.name
+ typeName = "ByteString"
elif type.isDOMString():
name = type.name
typeName = "DOMString"
@@ -5140,8 +5148,7 @@ class CGDescriptor(CGThing):
if descriptor.interface.hasInterfaceObject():
cgThings.append(CGDefineDOMInterfaceMethod(descriptor))
- if descriptor.isExposedConditionally():
- cgThings.append(CGConstructorEnabled(descriptor))
+ cgThings.append(CGConstructorEnabled(descriptor))
if descriptor.proxy:
cgThings.append(CGDefineProxyHandler(descriptor))
@@ -5534,17 +5541,17 @@ class CGBindingRoot(CGThing):
'js::jsapi::{JSJitInfo_AliasSet, JSJitInfo_ArgType, AutoIdVector, CallArgs, FreeOp}',
'js::jsapi::{JSITER_SYMBOLS, JSPROP_ENUMERATE, JSPROP_PERMANENT, JSPROP_READONLY, JSPROP_SHARED}',
'js::jsapi::{JSCLASS_RESERVED_SLOTS_SHIFT, JSITER_HIDDEN, JSITER_OWNONLY}',
- 'js::jsapi::{GetGlobalForObjectCrossCompartment , GetPropertyKeys, Handle}',
+ 'js::jsapi::{GetPropertyKeys, Handle}',
'js::jsapi::{HandleId, HandleObject, HandleValue, HandleValueArray}',
'js::jsapi::{INTERNED_STRING_TO_JSID, IsCallable, JS_CallFunctionValue}',
- 'js::jsapi::{JS_ComputeThis, JS_CopyPropertiesFrom, JS_ForwardGetPropertyTo}',
+ 'js::jsapi::{JS_CopyPropertiesFrom, JS_ForwardGetPropertyTo}',
'js::jsapi::{JS_GetClass, JS_GetErrorPrototype, JS_GetFunctionPrototype}',
'js::jsapi::{JS_GetGlobalForObject, JS_GetObjectPrototype, JS_GetProperty}',
'js::jsapi::{JS_GetPropertyById, JS_GetPropertyDescriptorById, JS_GetReservedSlot}',
'js::jsapi::{JS_HasProperty, JS_HasPropertyById, JS_InitializePropertiesFromCompatibleNativeObject}',
- 'js::jsapi::{JS_AtomizeAndPinString, JS_IsExceptionPending, JS_NewObject, JS_NewObjectWithGivenProto}',
- 'js::jsapi::{JS_NewObjectWithoutMetadata, JS_NewStringCopyZ, JS_SetProperty}',
- 'js::jsapi::{JS_SetPrototype, JS_SetReservedSlot, JS_WrapValue, JSAutoCompartment}',
+ 'js::jsapi::{JS_AtomizeAndPinString, JS_NewObject, JS_NewObjectWithGivenProto}',
+ 'js::jsapi::{JS_NewObjectWithoutMetadata, JS_SetProperty}',
+ 'js::jsapi::{JS_SetPrototype, JS_SetReservedSlot, JSAutoCompartment}',
'js::jsapi::{JSContext, JSClass, JSFreeOp, JSFunctionSpec}',
'js::jsapi::{JSJitGetterCallArgs, JSJitInfo, JSJitMethodCallArgs, JSJitSetterCallArgs}',
'js::jsapi::{JSNative, JSObject, JSNativeWrapper, JSPropertySpec}',
@@ -5557,11 +5564,11 @@ class CGBindingRoot(CGThing):
'js::jsval::{NullValue, UndefinedValue}',
'js::glue::{CallJitMethodOp, CallJitGetterOp, CallJitSetterOp, CreateProxyHandler}',
'js::glue::{GetProxyPrivate, NewProxyObject, ProxyTraps}',
- 'js::glue::{RUST_FUNCTION_VALUE_TO_JITINFO}',
- 'js::glue::{RUST_JS_NumberValue, RUST_JSID_IS_STRING, int_to_jsid}',
+ 'js::glue::{RUST_JSID_IS_STRING, int_to_jsid}',
'js::glue::AppendToAutoIdVector',
'js::rust::{GCMethods, define_methods, define_properties}',
'dom::bindings',
+ 'dom::bindings::codegen::InterfaceObjectMap',
'dom::bindings::global::{GlobalRef, global_root_from_object, global_root_from_reflector}',
'dom::bindings::interface::{InterfaceConstructorBehavior, NonCallbackInterfaceObjectClass}',
'dom::bindings::interface::{create_callback_interface_object, create_interface_prototype_object}',
@@ -5569,6 +5576,7 @@ class CGBindingRoot(CGThing):
'dom::bindings::interface::{define_guarded_methods, define_guarded_properties}',
'dom::bindings::interface::{ConstantSpec, NonNullJSNative}',
'dom::bindings::interface::ConstantVal::{IntVal, UintVal}',
+ 'dom::bindings::interface::is_exposed_in',
'dom::bindings::js::{JS, Root, RootedReference}',
'dom::bindings::js::{OptionalRootedReference}',
'dom::bindings::reflector::{Reflectable}',
@@ -6222,6 +6230,10 @@ class CallbackSetter(CallbackMember):
return None
+def camel_to_upper_snake(s):
+ return "_".join(m.group(0).upper() for m in re.finditer("[A-Z][a-z]*", s))
+
+
class GlobalGenRoots():
"""
Roots for global codegen.
@@ -6239,6 +6251,18 @@ class GlobalGenRoots():
]
imports = CGList([CGGeneric("use %s;" % mod) for mod in mods], "\n")
+ global_descriptors = config.getDescriptors(isGlobal=True)
+ flags = [("EMPTY", 0)]
+ flags.extend(
+ (camel_to_upper_snake(d.name), 2 ** idx)
+ for (idx, d) in enumerate(global_descriptors)
+ )
+ global_flags = CGWrapper(CGIndenter(CGList([
+ CGGeneric("const %s = %#x," % args)
+ for args in flags
+ ], "\n")), pre="pub flags Globals: u8 {\n", post="\n}")
+ globals_ = CGWrapper(CGIndenter(global_flags), pre="bitflags! {\n", post="\n}")
+
pairs = []
for d in config.getDescriptors(hasInterfaceObject=True):
binding = toBindingNamespace(d.name)
@@ -6247,10 +6271,10 @@ class GlobalGenRoots():
pairs.append((ctor.identifier.name, binding))
pairs.sort(key=operator.itemgetter(0))
mappings = [
- CGGeneric('b"%s" => codegen::Bindings::%s::DefineDOMInterface as fn(_, _),' % pair)
+ CGGeneric('b"%s" => codegen::Bindings::%s::DefineDOMInterface as unsafe fn(_, _),' % pair)
for pair in pairs
]
- mapType = "phf::Map<&'static [u8], fn(*mut JSContext, HandleObject)>"
+ mapType = "phf::Map<&'static [u8], unsafe fn(*mut JSContext, HandleObject)>"
phf = CGWrapper(
CGIndenter(CGList(mappings, "\n")),
pre="pub static MAP: %s = phf_map! {\n" % mapType,
@@ -6258,7 +6282,7 @@ class GlobalGenRoots():
return CGList([
CGGeneric(AUTOGENERATED_WARNING_COMMENT),
- CGList([imports, phf], "\n\n")
+ CGList([imports, globals_, phf], "\n\n")
])
@staticmethod
@@ -6421,3 +6445,36 @@ impl %(base)s {
# Done.
return curr
+
+ @staticmethod
+ def SupportedDomApis(config):
+ descriptors = config.getDescriptors(isExposedConditionally=False)
+
+ base_path = os.path.join('dom', 'bindings', 'codegen')
+ with open(os.path.join(base_path, 'apis.html.template')) as f:
+ base_template = f.read()
+ with open(os.path.join(base_path, 'api.html.template')) as f:
+ api_template = f.read()
+ with open(os.path.join(base_path, 'property.html.template')) as f:
+ property_template = f.read()
+ with open(os.path.join(base_path, 'interface.html.template')) as f:
+ interface_template = f.read()
+
+ apis = []
+ interfaces = []
+ for descriptor in descriptors:
+ props = []
+ for m in descriptor.interface.members:
+ if PropertyDefiner.getStringAttr(m, 'Pref') or \
+ PropertyDefiner.getStringAttr(m, 'Func') or \
+ (m.isMethod() and m.isIdentifierLess()):
+ continue
+ display = m.identifier.name + ('()' if m.isMethod() else '')
+ props += [property_template.replace('${name}', display)]
+ name = descriptor.interface.identifier.name
+ apis += [(api_template.replace('${interface}', name)
+ .replace('${properties}', '\n'.join(props)))]
+ interfaces += [interface_template.replace('${interface}', name)]
+
+ return CGGeneric((base_template.replace('${apis}', '\n'.join(apis))
+ .replace('${interfaces}', '\n'.join(interfaces))))
diff --git a/components/script/dom/bindings/codegen/Configuration.py b/components/script/dom/bindings/codegen/Configuration.py
index 7aad0f75f75..4074736a462 100644
--- a/components/script/dom/bindings/codegen/Configuration.py
+++ b/components/script/dom/bindings/codegen/Configuration.py
@@ -85,6 +85,10 @@ class Configuration:
getter = lambda x: x.interface.isCallback()
elif key == 'isJSImplemented':
getter = lambda x: x.interface.isJSImplemented()
+ elif key == 'isGlobal':
+ getter = lambda x: x.isGlobal()
+ elif key == 'isExposedConditionally':
+ getter = lambda x: x.interface.isExposedConditionally()
else:
getter = lambda x: getattr(x, key)
curr = filter(lambda x: getter(x) == val, curr)
@@ -367,8 +371,8 @@ class Descriptor(DescriptorProvider):
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"))
+ return bool(self.interface.getExtendedAttribute("Global") or
+ self.interface.getExtendedAttribute("PrimaryGlobal"))
# Some utility methods
diff --git a/components/script/dom/bindings/codegen/GlobalGen.py b/components/script/dom/bindings/codegen/GlobalGen.py
index 72a2faa71e4..23779d9e6d5 100644
--- a/components/script/dom/bindings/codegen/GlobalGen.py
+++ b/components/script/dom/bindings/codegen/GlobalGen.py
@@ -32,6 +32,8 @@ def main():
o = OptionParser(usage=usageString)
o.add_option("--cachedir", dest='cachedir', default=None,
help="Directory in which to cache lex/parse tables.")
+ o.add_option("--only-html", dest='only_html', action="store_true",
+ help="Only generate HTML from WebIDL inputs")
(options, args) = o.parse_args()
if len(args) < 2:
@@ -51,24 +53,30 @@ def main():
parser.parse(''.join(lines), fullPath)
parserResults = parser.finish()
- # Write the parser results out to a pickle.
- resultsPath = os.path.join(outputdir, 'ParserResults.pkl')
- with open(resultsPath, 'wb') as resultsFile:
- cPickle.dump(parserResults, resultsFile, -1)
+ if not options.only_html:
+ # Write the parser results out to a pickle.
+ resultsPath = os.path.join(outputdir, 'ParserResults.pkl')
+ with open(resultsPath, 'wb') as resultsFile:
+ cPickle.dump(parserResults, resultsFile, -1)
# Load the configuration.
config = Configuration(configFile, parserResults)
to_generate = [
- ('PrototypeList', 'PrototypeList.rs'),
- ('RegisterBindings', 'RegisterBindings.rs'),
- ('InterfaceObjectMap', 'InterfaceObjectMap.rs'),
- ('InterfaceTypes', 'InterfaceTypes.rs'),
- ('InheritTypes', 'InheritTypes.rs'),
- ('Bindings', os.path.join('Bindings', 'mod.rs')),
- ('UnionTypes', 'UnionTypes.rs'),
+ ('SupportedDomApis', 'apis.html'),
]
+ if not options.only_html:
+ to_generate = [
+ ('PrototypeList', 'PrototypeList.rs'),
+ ('RegisterBindings', 'RegisterBindings.rs'),
+ ('InterfaceObjectMap', 'InterfaceObjectMap.rs'),
+ ('InterfaceTypes', 'InterfaceTypes.rs'),
+ ('InheritTypes', 'InheritTypes.rs'),
+ ('Bindings', os.path.join('Bindings', 'mod.rs')),
+ ('UnionTypes', 'UnionTypes.rs'),
+ ]
+
for name, filename in to_generate:
generate_file(config, name, os.path.join(outputdir, filename))
diff --git a/components/script/dom/bindings/codegen/api.html.template b/components/script/dom/bindings/codegen/api.html.template
new file mode 100644
index 00000000000..807392693a4
--- /dev/null
+++ b/components/script/dom/bindings/codegen/api.html.template
@@ -0,0 +1,6 @@
+<table id="${interface}">
+<tr>
+<th>${interface}</th>
+</tr>
+${properties}
+</table>
diff --git a/components/script/dom/bindings/codegen/apis.html.template b/components/script/dom/bindings/codegen/apis.html.template
new file mode 100644
index 00000000000..a6f1e59d4ab
--- /dev/null
+++ b/components/script/dom/bindings/codegen/apis.html.template
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="generator" content="rustdoc">
+ <meta name="description" content="API documentation for the Rust `servo` crate.">
+ <meta name="keywords" content="rust, rustlang, rust-lang, servo">
+ <title>Supported DOM APIs - servo - Rust</title>
+ <link rel="stylesheet" type="text/css" href="../rustdoc.css">
+ <link rel="stylesheet" type="text/css" href="../main.css">
+</head>
+<body class="rustdoc">
+ <!--[if lte IE 8]>
+ <div class="warning">
+ This old browser is unsupported and will most likely display funky
+ things.
+ </div>
+ <![endif]-->
+ <nav class='sidebar'>
+ <div class='block crate'>
+ <h3>Interfaces</h3>
+ <ul>
+ ${interfaces}
+ </ul>
+ </div>
+ </nav>
+ <section id='main' class="content mod">
+ <h1 class='fqn'><span class='in-band'>DOM APIs currently supported in <a class='mod' href=''>Servo</a></span></h1>
+ <div id='properties' class='docblock'>
+ ${apis}
+ </div>
+ </section>
+</body>
+</html>
diff --git a/components/script/dom/bindings/codegen/interface.html.template b/components/script/dom/bindings/codegen/interface.html.template
new file mode 100644
index 00000000000..92b023165e2
--- /dev/null
+++ b/components/script/dom/bindings/codegen/interface.html.template
@@ -0,0 +1 @@
+<li><a href="#${interface}">${interface}</a></li>
diff --git a/components/script/dom/bindings/codegen/parser/WebIDL.py b/components/script/dom/bindings/codegen/parser/WebIDL.py
index 5795f9db767..da32340dda6 100644
--- a/components/script/dom/bindings/codegen/parser/WebIDL.py
+++ b/components/script/dom/bindings/codegen/parser/WebIDL.py
@@ -158,6 +158,9 @@ class IDLObject(object):
def isInterface(self):
return False
+ def isNamespace(self):
+ return False
+
def isEnum(self):
return False
@@ -585,8 +588,8 @@ class IDLExternalInterface(IDLObjectWithIdentifier, IDLExposureMixins):
return set()
-class IDLPartialInterface(IDLObject):
- def __init__(self, location, name, members, nonPartialInterface):
+class IDLPartialInterfaceOrNamespace(IDLObject):
+ def __init__(self, location, name, members, nonPartialInterfaceOrNamespace):
assert isinstance(name, IDLUnresolvedIdentifier)
IDLObject.__init__(self, location)
@@ -595,9 +598,10 @@ class IDLPartialInterface(IDLObject):
# propagatedExtendedAttrs are the ones that should get
# propagated to our non-partial interface.
self.propagatedExtendedAttrs = []
- self._nonPartialInterface = nonPartialInterface
+ self._haveSecureContextExtendedAttribute = False
+ self._nonPartialInterfaceOrNamespace = nonPartialInterfaceOrNamespace
self._finished = False
- nonPartialInterface.addPartialInterface(self)
+ nonPartialInterfaceOrNamespace.addPartialInterface(self)
def addExtendedAttributes(self, attrs):
for attr in attrs:
@@ -605,6 +609,16 @@ class IDLPartialInterface(IDLObject):
if identifier in ["Constructor", "NamedConstructor"]:
self.propagatedExtendedAttrs.append(attr)
+ elif identifier == "SecureContext":
+ self._haveSecureContextExtendedAttribute = True
+ # This gets propagated to all our members.
+ for member in self.members:
+ if member.getExtendedAttribute("SecureContext"):
+ raise WebIDLError("[SecureContext] specified on both a "
+ "partial interface member and on the "
+ "partial interface itself",
+ [member.location, attr.location])
+ member.addExtendedAttributes([attr])
elif identifier == "Exposed":
# This just gets propagated to all our members.
for member in self.members:
@@ -623,9 +637,23 @@ class IDLPartialInterface(IDLObject):
if self._finished:
return
self._finished = True
- # Need to make sure our non-partial interface gets finished so it can
- # report cases when we only have partial interfaces.
- self._nonPartialInterface.finish(scope)
+ if (not self._haveSecureContextExtendedAttribute and
+ self._nonPartialInterfaceOrNamespace.getExtendedAttribute("SecureContext")):
+ # This gets propagated to all our members.
+ for member in self.members:
+ if member.getExtendedAttribute("SecureContext"):
+ raise WebIDLError("[SecureContext] specified on both a "
+ "partial interface member and on the "
+ "non-partial interface",
+ [member.location,
+ self._nonPartialInterfaceOrNamespace.location])
+ member.addExtendedAttributes(
+ [IDLExtendedAttribute(self._nonPartialInterfaceOrNamespace.location,
+ ("SecureContext",))])
+ # Need to make sure our non-partial interface or namespace gets
+ # finished so it can report cases when we only have partial
+ # interfaces/namespaces.
+ self._nonPartialInterfaceOrNamespace.finish(scope)
def validate(self):
pass
@@ -645,7 +673,7 @@ def globalNameSetToExposureSet(globalScope, nameSet, exposureSet):
exposureSet.update(globalScope.globalNameMapping[name])
-class IDLInterface(IDLObjectWithScope, IDLExposureMixins):
+class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins):
def __init__(self, location, parentScope, name, parent, members,
isKnownNonPartial):
assert isinstance(parentScope, IDLScope)
@@ -691,9 +719,6 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins):
if isKnownNonPartial:
self.setNonPartial(location, parent, members)
- def __str__(self):
- return "Interface '%s'" % self.identifier.name
-
def ctor(self):
identifier = IDLUnresolvedIdentifier(self.location, "constructor",
allowForbidden=True)
@@ -789,6 +814,20 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins):
assert iter(self.members)
+ if self.isNamespace():
+ assert not self.parent
+ for m in self.members:
+ if m.isAttr() or m.isMethod():
+ if m.isStatic():
+ raise WebIDLError("Don't mark things explicitly static "
+ "in namespaces",
+ [self.location, m.location])
+ # Just mark all our methods/attributes as static. The other
+ # option is to duplicate the relevant InterfaceMembers
+ # production bits but modified to produce static stuff to
+ # start with, but that sounds annoying.
+ m.forceStatic()
+
if self.parent:
self.parent.finish(scope)
self.parent._hasChildInterfaces = True
@@ -843,6 +882,17 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins):
self.parent.identifier.name),
[self.location, self.parent.location])
+ # Interfaces that are not [SecureContext] can't inherit
+ # from [SecureContext] interfaces.
+ if (self.parent.getExtendedAttribute("SecureContext") and
+ not self.getExtendedAttribute("SecureContext")):
+ raise WebIDLError("Interface %s does not have "
+ "[SecureContext] but inherits from "
+ "interface %s which does" %
+ (self.identifier.name,
+ self.parent.identifier.name),
+ [self.location, self.parent.location])
+
for iface in self.implementedInterfaces:
iface.finish(scope)
@@ -1211,6 +1261,7 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins):
member.getExtendedAttribute("ChromeOnly") or
member.getExtendedAttribute("Pref") or
member.getExtendedAttribute("Func") or
+ member.getExtendedAttribute("SecureContext") or
member.getExtendedAttribute("AvailableIn") or
member.getExtendedAttribute("CheckAnyPermissions") or
member.getExtendedAttribute("CheckAllPermissions")):
@@ -1239,12 +1290,6 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins):
alias,
[member.location, m.location])
- 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,
- [self.location])
-
for attribute in ["CheckAnyPermissions", "CheckAllPermissions"]:
if (self.getExtendedAttribute(attribute) and
self._exposureGlobalNames != set([self.parentScope.primaryGlobalName])):
@@ -1291,9 +1336,6 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins):
[self.location, iterableDecl.location,
indexedGetter.location])
- def isInterface(self):
- return True
-
def isExternal(self):
return False
@@ -1344,7 +1386,172 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins):
return not hasattr(self, "_noInterfaceObject")
def hasInterfacePrototypeObject(self):
- return not self.isCallback() and self.getUserData('hasConcreteDescendant', False)
+ return (not self.isCallback() and not self.isNamespace()
+ and self.getUserData('hasConcreteDescendant', False))
+
+ def addImplementedInterface(self, implementedInterface):
+ assert(isinstance(implementedInterface, IDLInterface))
+ self.implementedInterfaces.add(implementedInterface)
+
+ def getInheritedInterfaces(self):
+ """
+ Returns a list of the interfaces this interface inherits from
+ (not including this interface itself). The list is in order
+ from most derived to least derived.
+ """
+ assert(self._finished)
+ if not self.parent:
+ return []
+ parentInterfaces = self.parent.getInheritedInterfaces()
+ parentInterfaces.insert(0, self.parent)
+ return parentInterfaces
+
+ def getConsequentialInterfaces(self):
+ assert(self._finished)
+ # The interfaces we implement directly
+ consequentialInterfaces = set(self.implementedInterfaces)
+
+ # And their inherited interfaces
+ for iface in self.implementedInterfaces:
+ consequentialInterfaces |= set(iface.getInheritedInterfaces())
+
+ # And now collect up the consequential interfaces of all of those
+ temp = set()
+ for iface in consequentialInterfaces:
+ temp |= iface.getConsequentialInterfaces()
+
+ return consequentialInterfaces | temp
+
+ def findInterfaceLoopPoint(self, otherInterface):
+ """
+ Finds an interface, amongst our ancestors and consequential interfaces,
+ that inherits from otherInterface or implements otherInterface
+ directly. If there is no such interface, returns None.
+ """
+ if self.parent:
+ if self.parent == otherInterface:
+ return self
+ loopPoint = self.parent.findInterfaceLoopPoint(otherInterface)
+ if loopPoint:
+ return loopPoint
+ if otherInterface in self.implementedInterfaces:
+ return self
+ for iface in self.implementedInterfaces:
+ loopPoint = iface.findInterfaceLoopPoint(otherInterface)
+ if loopPoint:
+ return loopPoint
+ return None
+
+ def getExtendedAttribute(self, name):
+ return self._extendedAttrDict.get(name, None)
+
+ def setNonPartial(self, location, parent, members):
+ assert not parent or isinstance(parent, IDLIdentifierPlaceholder)
+ if self._isKnownNonPartial:
+ raise WebIDLError("Two non-partial definitions for the "
+ "same %s" %
+ ("interface" if self.isInterface()
+ else "namespace"),
+ [location, self.location])
+ self._isKnownNonPartial = True
+ # Now make it look like we were parsed at this new location, since
+ # that's the place where the interface is "really" defined
+ self.location = location
+ assert not self.parent
+ self.parent = parent
+ # Put the new members at the beginning
+ self.members = members + self.members
+
+ def addPartialInterface(self, partial):
+ assert self.identifier.name == partial.identifier.name
+ self._partialInterfaces.append(partial)
+
+ def getJSImplementation(self):
+ classId = self.getExtendedAttribute("JSImplementation")
+ if not classId:
+ return classId
+ assert isinstance(classId, list)
+ assert len(classId) == 1
+ return classId[0]
+
+ def isJSImplemented(self):
+ return bool(self.getJSImplementation())
+
+ def isProbablyShortLivingObject(self):
+ current = self
+ while current:
+ if current.getExtendedAttribute("ProbablyShortLivingObject"):
+ return True
+ current = current.parent
+ return False
+
+ def isNavigatorProperty(self):
+ naviProp = self.getExtendedAttribute("NavigatorProperty")
+ if not naviProp:
+ return False
+ assert len(naviProp) == 1
+ assert isinstance(naviProp, list)
+ assert len(naviProp[0]) != 0
+ return True
+
+ def getNavigatorProperty(self):
+ naviProp = self.getExtendedAttribute("NavigatorProperty")
+ if not naviProp:
+ return None
+ assert len(naviProp) == 1
+ assert isinstance(naviProp, list)
+ assert len(naviProp[0]) != 0
+ conditionExtendedAttributes = self._extendedAttrDict.viewkeys() & IDLInterfaceOrNamespace.conditionExtendedAttributes
+ attr = IDLAttribute(self.location,
+ IDLUnresolvedIdentifier(BuiltinLocation("<auto-generated-identifier>"), naviProp[0]),
+ IDLUnresolvedType(self.location, IDLUnresolvedIdentifier(self.location, self.identifier.name)),
+ True,
+ extendedAttrDict={ a: self._extendedAttrDict[a] for a in conditionExtendedAttributes },
+ navigatorObjectGetter=True)
+ attr._exposureGlobalNames = self._exposureGlobalNames
+ # We're abusing Constant a little bit here, because we need Cached. The
+ # getter will create a new object every time, but we're never going to
+ # clear the cached value.
+ extendedAttrs = [ IDLExtendedAttribute(self.location, ("Throws", )),
+ IDLExtendedAttribute(self.location, ("Cached", )),
+ IDLExtendedAttribute(self.location, ("Constant", )) ]
+ attr.addExtendedAttributes(extendedAttrs)
+ return attr
+
+ def hasChildInterfaces(self):
+ return self._hasChildInterfaces
+
+ def isOnGlobalProtoChain(self):
+ return self._isOnGlobalProtoChain
+
+ def _getDependentObjects(self):
+ deps = set(self.members)
+ deps.update(self.implementedInterfaces)
+ if self.parent:
+ deps.add(self.parent)
+ return deps
+
+ def hasMembersInSlots(self):
+ return self._ownMembersInSlots != 0
+
+ conditionExtendedAttributes = [ "Pref", "ChromeOnly", "Func", "AvailableIn",
+ "SecureContext",
+ "CheckAnyPermissions",
+ "CheckAllPermissions" ]
+ def isExposedConditionally(self):
+ return any(self.getExtendedAttribute(a) for a in self.conditionExtendedAttributes)
+
+class IDLInterface(IDLInterfaceOrNamespace):
+ def __init__(self, location, parentScope, name, parent, members,
+ isKnownNonPartial):
+ IDLInterfaceOrNamespace.__init__(self, location, parentScope, name,
+ parent, members, isKnownNonPartial)
+
+ def __str__(self):
+ return "Interface '%s'" % self.identifier.name
+
+ def isInterface(self):
+ return True
def addExtendedAttributes(self, attrs):
for attr in attrs:
@@ -1475,6 +1682,18 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins):
self.parentScope.globalNames.add(self.identifier.name)
self.parentScope.globalNameMapping[self.identifier.name].add(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"):
+ raise WebIDLError("[SecureContext] specified on both "
+ "an interface member and on the "
+ "interface itself",
+ [member.location, attr.location])
+ member.addExtendedAttributes([attr])
elif (identifier == "NeedResolve" or
identifier == "OverrideBuiltins" or
identifier == "ChromeOnly" or
@@ -1512,154 +1731,46 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins):
attrlist = attr.listValue()
self._extendedAttrDict[identifier] = attrlist if len(attrlist) else True
- def addImplementedInterface(self, implementedInterface):
- assert(isinstance(implementedInterface, IDLInterface))
- self.implementedInterfaces.add(implementedInterface)
-
- def getInheritedInterfaces(self):
- """
- Returns a list of the interfaces this interface inherits from
- (not including this interface itself). The list is in order
- from most derived to least derived.
- """
- assert(self._finished)
- if not self.parent:
- return []
- parentInterfaces = self.parent.getInheritedInterfaces()
- parentInterfaces.insert(0, self.parent)
- return parentInterfaces
-
- def getConsequentialInterfaces(self):
- assert(self._finished)
- # The interfaces we implement directly
- consequentialInterfaces = set(self.implementedInterfaces)
-
- # And their inherited interfaces
- for iface in self.implementedInterfaces:
- consequentialInterfaces |= set(iface.getInheritedInterfaces())
-
- # And now collect up the consequential interfaces of all of those
- temp = set()
- for iface in consequentialInterfaces:
- temp |= iface.getConsequentialInterfaces()
-
- return consequentialInterfaces | temp
-
- def findInterfaceLoopPoint(self, otherInterface):
- """
- Finds an interface, amongst our ancestors and consequential interfaces,
- that inherits from otherInterface or implements otherInterface
- directly. If there is no such interface, returns None.
- """
- if self.parent:
- if self.parent == otherInterface:
- return self
- loopPoint = self.parent.findInterfaceLoopPoint(otherInterface)
- if loopPoint:
- return loopPoint
- if otherInterface in self.implementedInterfaces:
- return self
- for iface in self.implementedInterfaces:
- loopPoint = iface.findInterfaceLoopPoint(otherInterface)
- if loopPoint:
- return loopPoint
- return None
-
- def getExtendedAttribute(self, name):
- return self._extendedAttrDict.get(name, None)
-
- def setNonPartial(self, location, parent, members):
- assert not parent or isinstance(parent, IDLIdentifierPlaceholder)
- if self._isKnownNonPartial:
- raise WebIDLError("Two non-partial definitions for the "
- "same interface",
- [location, self.location])
- self._isKnownNonPartial = True
- # Now make it look like we were parsed at this new location, since
- # that's the place where the interface is "really" defined
- self.location = location
- assert not self.parent
- self.parent = parent
- # Put the new members at the beginning
- self.members = members + self.members
-
- def addPartialInterface(self, partial):
- assert self.identifier.name == partial.identifier.name
- self._partialInterfaces.append(partial)
- def getJSImplementation(self):
- classId = self.getExtendedAttribute("JSImplementation")
- if not classId:
- return classId
- assert isinstance(classId, list)
- assert len(classId) == 1
- return classId[0]
-
- def isJSImplemented(self):
- return bool(self.getJSImplementation())
+class IDLNamespace(IDLInterfaceOrNamespace):
+ def __init__(self, location, parentScope, name, members, isKnownNonPartial):
+ IDLInterfaceOrNamespace.__init__(self, location, parentScope, name,
+ None, members, isKnownNonPartial)
- def isProbablyShortLivingObject(self):
- current = self
- while current:
- if current.getExtendedAttribute("ProbablyShortLivingObject"):
- return True
- current = current.parent
- return False
+ def __str__(self):
+ return "Namespace '%s'" % self.identifier.name
- def isNavigatorProperty(self):
- naviProp = self.getExtendedAttribute("NavigatorProperty")
- if not naviProp:
- return False
- assert len(naviProp) == 1
- assert isinstance(naviProp, list)
- assert len(naviProp[0]) != 0
+ def isNamespace(self):
return True
- def getNavigatorProperty(self):
- naviProp = self.getExtendedAttribute("NavigatorProperty")
- if not naviProp:
- return None
- assert len(naviProp) == 1
- assert isinstance(naviProp, list)
- assert len(naviProp[0]) != 0
- conditionExtendedAttributes = self._extendedAttrDict.viewkeys() & IDLInterface.conditionExtendedAttributes
- attr = IDLAttribute(self.location,
- IDLUnresolvedIdentifier(BuiltinLocation("<auto-generated-identifier>"), naviProp[0]),
- IDLUnresolvedType(self.location, IDLUnresolvedIdentifier(self.location, self.identifier.name)),
- True,
- extendedAttrDict={ a: self._extendedAttrDict[a] for a in conditionExtendedAttributes },
- navigatorObjectGetter=True)
- attr._exposureGlobalNames = self._exposureGlobalNames
- # We're abusing Constant a little bit here, because we need Cached. The
- # getter will create a new object every time, but we're never going to
- # clear the cached value.
- extendedAttrs = [ IDLExtendedAttribute(self.location, ("Throws", )),
- IDLExtendedAttribute(self.location, ("Cached", )),
- IDLExtendedAttribute(self.location, ("Constant", )) ]
- attr.addExtendedAttributes(extendedAttrs)
- return attr
-
- def hasChildInterfaces(self):
- return self._hasChildInterfaces
-
- def isOnGlobalProtoChain(self):
- return self._isOnGlobalProtoChain
-
- def _getDependentObjects(self):
- deps = set(self.members)
- deps.update(self.implementedInterfaces)
- if self.parent:
- deps.add(self.parent)
- return deps
+ def addExtendedAttributes(self, attrs):
+ # The set of things namespaces support is small enough it's simpler
+ # to factor out into a separate method than it is to sprinkle
+ # isNamespace() checks all through
+ # IDLInterfaceOrNamespace.addExtendedAttributes.
+ for attr in attrs:
+ identifier = attr.identifier()
- def hasMembersInSlots(self):
- return self._ownMembersInSlots != 0
+ if identifier == "Exposed":
+ convertExposedAttrToGlobalNameSet(attr,
+ self._exposureGlobalNames)
+ elif identifier == "ClassString":
+ # Takes a string value to override the default "Object" if
+ # desired.
+ if not attr.hasValue():
+ raise WebIDLError("[%s] must have a value" % identifier,
+ [attr.location])
+ elif identifier == "ProtoObjectHack":
+ if not attr.noArguments():
+ raise WebIDLError("[%s] must not have arguments" % identifier,
+ [attr.location])
+ else:
+ raise WebIDLError("Unknown extended attribute %s on namespace" %
+ identifier,
+ [attr.location])
- conditionExtendedAttributes = [ "Pref", "ChromeOnly", "Func", "AvailableIn",
- "CheckAnyPermissions",
- "CheckAllPermissions" ]
- def isExposedConditionally(self):
- return any(self.getExtendedAttribute(a) for a in self.conditionExtendedAttributes)
+ attrlist = attr.listValue()
+ self._extendedAttrDict[identifier] = attrlist if len(attrlist) else True
class IDLDictionary(IDLObjectWithScope):
@@ -2072,7 +2183,30 @@ class IDLUnresolvedType(IDLType):
"distinguishable from other things")
-class IDLNullableType(IDLType):
+class IDLParameterizedType(IDLType):
+ def __init__(self, location, name, innerType):
+ IDLType.__init__(self, location, name)
+ self.builtin = False
+ self.inner = innerType
+
+ def includesRestrictedFloat(self):
+ return self.inner.includesRestrictedFloat()
+
+ def resolveType(self, parentScope):
+ assert isinstance(parentScope, IDLScope)
+ self.inner.resolveType(parentScope)
+
+ def isComplete(self):
+ return self.inner.isComplete()
+
+ def unroll(self):
+ return self.inner.unroll()
+
+ def _getDependentObjects(self):
+ return self.inner._getDependentObjects()
+
+
+class IDLNullableType(IDLParameterizedType):
def __init__(self, location, innerType):
assert not innerType.isVoid()
assert not innerType == BuiltinTypes[IDLBuiltinType.Types.any]
@@ -2080,9 +2214,7 @@ class IDLNullableType(IDLType):
name = innerType.name
if innerType.isComplete():
name += "OrNull"
- IDLType.__init__(self, location, name)
- self.inner = innerType
- self.builtin = False
+ IDLParameterizedType.__init__(self, location, name, innerType)
def __eq__(self, other):
return isinstance(other, IDLNullableType) and self.inner == other.inner
@@ -2123,9 +2255,6 @@ class IDLNullableType(IDLType):
def isUnrestricted(self):
return self.inner.isUnrestricted()
- def includesRestrictedFloat(self):
- return self.inner.includesRestrictedFloat()
-
def isInteger(self):
return self.inner.isInteger()
@@ -2180,13 +2309,6 @@ class IDLNullableType(IDLType):
def tag(self):
return self.inner.tag()
- def resolveType(self, parentScope):
- assert isinstance(parentScope, IDLScope)
- self.inner.resolveType(parentScope)
-
- def isComplete(self):
- return self.inner.isComplete()
-
def complete(self, scope):
self.inner = self.inner.complete(scope)
if self.inner.nullable():
@@ -2202,9 +2324,6 @@ class IDLNullableType(IDLType):
self.name = self.inner.name + "OrNull"
return self
- def unroll(self):
- return self.inner.unroll()
-
def isDistinguishableFrom(self, other):
if (other.nullable() or (other.isUnion() and other.hasNullableType) or
other.isDictionary()):
@@ -2212,17 +2331,12 @@ class IDLNullableType(IDLType):
return False
return self.inner.isDistinguishableFrom(other)
- def _getDependentObjects(self):
- return self.inner._getDependentObjects()
-
-class IDLSequenceType(IDLType):
+class IDLSequenceType(IDLParameterizedType):
def __init__(self, location, parameterType):
assert not parameterType.isVoid()
- IDLType.__init__(self, location, parameterType.name)
- self.inner = parameterType
- self.builtin = False
+ IDLParameterizedType.__init__(self, location, parameterType.name, parameterType)
# Need to set self.name up front if our inner type is already complete,
# since in that case our .complete() won't be called.
if self.inner.isComplete():
@@ -2273,27 +2387,14 @@ class IDLSequenceType(IDLType):
def isSerializable(self):
return self.inner.isSerializable()
- def includesRestrictedFloat(self):
- return self.inner.includesRestrictedFloat()
-
def tag(self):
return IDLType.Tags.sequence
- def resolveType(self, parentScope):
- assert isinstance(parentScope, IDLScope)
- self.inner.resolveType(parentScope)
-
- def isComplete(self):
- return self.inner.isComplete()
-
def complete(self, scope):
self.inner = self.inner.complete(scope)
self.name = self.inner.name + "Sequence"
return self
- def unroll(self):
- return self.inner.unroll()
-
def isDistinguishableFrom(self, other):
if other.isPromise():
return False
@@ -2305,20 +2406,12 @@ class IDLSequenceType(IDLType):
other.isDictionary() or
other.isCallback() or other.isMozMap())
- def _getDependentObjects(self):
- return self.inner._getDependentObjects()
-
-class IDLMozMapType(IDLType):
- # XXXbz This is pretty similar to IDLSequenceType in various ways.
- # And maybe to IDLNullableType. Should we have a superclass for
- # "type containing this other type"? Bug 1015318.
+class IDLMozMapType(IDLParameterizedType):
def __init__(self, location, parameterType):
assert not parameterType.isVoid()
- IDLType.__init__(self, location, parameterType.name)
- self.inner = parameterType
- self.builtin = False
+ IDLParameterizedType.__init__(self, location, parameterType.name, parameterType)
# Need to set self.name up front if our inner type is already complete,
# since in that case our .complete() won't be called.
if self.inner.isComplete():
@@ -2333,19 +2426,9 @@ class IDLMozMapType(IDLType):
def isMozMap(self):
return True
- def includesRestrictedFloat(self):
- return self.inner.includesRestrictedFloat()
-
def tag(self):
return IDLType.Tags.mozmap
- def resolveType(self, parentScope):
- assert isinstance(parentScope, IDLScope)
- self.inner.resolveType(parentScope)
-
- def isComplete(self):
- return self.inner.isComplete()
-
def complete(self, scope):
self.inner = self.inner.complete(scope)
self.name = self.inner.name + "MozMap"
@@ -2369,9 +2452,6 @@ class IDLMozMapType(IDLType):
def isExposedInAllOf(self, exposureSet):
return self.inner.unroll().isExposedInAllOf(exposureSet)
- def _getDependentObjects(self):
- return self.inner._getDependentObjects()
-
class IDLUnionType(IDLType):
def __init__(self, location, memberTypes):
@@ -3459,12 +3539,6 @@ class IDLInterfaceMember(IDLObjectWithIdentifier, IDLExposureMixins):
IDLExposureMixins.finish(self, scope)
def validate(self):
- if (self.getExtendedAttribute("Pref") and
- self.exposureSet != set([self._globalScope.primaryGlobalName])):
- raise WebIDLError("[Pref] used on an interface member that is not "
- "%s-only" % self._globalScope.primaryGlobalName,
- [self.location])
-
for attribute in ["CheckAnyPermissions", "CheckAllPermissions"]:
if (self.getExtendedAttribute(attribute) and
self.exposureSet != set([self._globalScope.primaryGlobalName])):
@@ -3889,6 +3963,7 @@ class IDLConst(IDLInterfaceMember):
elif (identifier == "Pref" or
identifier == "ChromeOnly" or
identifier == "Func" or
+ identifier == "SecureContext" or
identifier == "AvailableIn" or
identifier == "CheckAnyPermissions" or
identifier == "CheckAllPermissions"):
@@ -3915,7 +3990,7 @@ class IDLAttribute(IDLInterfaceMember):
self.type = type
self.readonly = readonly
self.inherit = inherit
- self.static = static
+ self._static = static
self.lenientThis = False
self._unforgeable = False
self.stringifier = stringifier
@@ -3937,7 +4012,10 @@ class IDLAttribute(IDLInterfaceMember):
[self.location])
def isStatic(self):
- return self.static
+ return self._static
+
+ def forceStatic(self):
+ self._static = True
def __str__(self):
return "'%s' attribute '%s'" % (self.type, self.identifier)
@@ -3991,16 +4069,53 @@ class IDLAttribute(IDLInterfaceMember):
"interface type as its type", [self.location])
def validate(self):
+ def typeContainsChromeOnlyDictionaryMember(type):
+ if (type.nullable() or
+ type.isSequence() or
+ type.isMozMap()):
+ return typeContainsChromeOnlyDictionaryMember(type.inner)
+
+ if type.isUnion():
+ for memberType in type.flatMemberTypes:
+ (contains, location) = typeContainsChromeOnlyDictionaryMember(memberType)
+ if contains:
+ return (True, location)
+
+ if type.isDictionary():
+ dictionary = type.inner
+ while dictionary:
+ (contains, location) = dictionaryContainsChromeOnlyMember(dictionary)
+ if contains:
+ return (True, location)
+ dictionary = dictionary.parent
+
+ return (False, None)
+
+ def dictionaryContainsChromeOnlyMember(dictionary):
+ for member in dictionary.members:
+ if member.getExtendedAttribute("ChromeOnly"):
+ return (True, member.location)
+ (contains, location) = typeContainsChromeOnlyDictionaryMember(member.type)
+ if contains:
+ return (True, location)
+ return (False, None)
+
IDLInterfaceMember.validate(self)
- if ((self.getExtendedAttribute("Cached") or
- self.getExtendedAttribute("StoreInSlot")) and
- not self.affects == "Nothing"):
- raise WebIDLError("Cached attributes and attributes stored in "
- "slots must be Constant or Pure or "
- "Affects=Nothing, since the getter won't always "
- "be called.",
- [self.location])
+ if (self.getExtendedAttribute("Cached") or
+ self.getExtendedAttribute("StoreInSlot")):
+ if not self.affects == "Nothing":
+ raise WebIDLError("Cached attributes and attributes stored in "
+ "slots must be Constant or Pure or "
+ "Affects=Nothing, since the getter won't always "
+ "be called.",
+ [self.location])
+ (contains, location) = typeContainsChromeOnlyDictionaryMember(self.type)
+ if contains:
+ raise WebIDLError("[Cached] and [StoreInSlot] must not be used "
+ "on an attribute whose type contains a "
+ "[ChromeOnly] dictionary member",
+ [self.location, location])
if self.getExtendedAttribute("Frozen"):
if (not self.type.isSequence() and not self.type.isDictionary() and
not self.type.isMozMap()):
@@ -4189,6 +4304,7 @@ class IDLAttribute(IDLInterfaceMember):
identifier == "GetterThrows" or
identifier == "ChromeOnly" or
identifier == "Func" or
+ identifier == "SecureContext" or
identifier == "Frozen" or
identifier == "AvailableIn" or
identifier == "NewObject" or
@@ -4245,6 +4361,7 @@ class IDLArgument(IDLObjectWithIdentifier):
self.enforceRange = False
self.clamp = False
self._allowTreatNonCallableAsNull = False
+ self._extendedAttrDict = {}
assert not variadic or optional
assert not variadic or not defaultValue
@@ -4274,11 +4391,22 @@ class IDLArgument(IDLObjectWithIdentifier):
self.enforceRange = True
elif identifier == "TreatNonCallableAsNull":
self._allowTreatNonCallableAsNull = True
+ elif (self.dictionaryMember and
+ (identifier == "ChromeOnly" or identifier == "Func")):
+ if not self.optional:
+ raise WebIDLError("[%s] must not be used on a required "
+ "dictionary member" % identifier,
+ [attribute.location])
else:
raise WebIDLError("Unhandled extended attribute on %s" %
("a dictionary member" if self.dictionaryMember else
"an argument"),
[attribute.location])
+ attrlist = attribute.listValue()
+ self._extendedAttrDict[identifier] = attrlist if len(attrlist) else True
+
+ def getExtendedAttribute(self, name):
+ return self._extendedAttrDict.get(name, None)
def isComplete(self):
return self._isComplete
@@ -4549,6 +4677,9 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
def isStatic(self):
return self._static
+ def forceStatic(self):
+ self._static = True
+
def isGetter(self):
return self._getter
@@ -4900,6 +5031,7 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
identifier == "Pref" or
identifier == "Deprecated" or
identifier == "Func" or
+ identifier == "SecureContext" or
identifier == "AvailableIn" or
identifier == "CheckAnyPermissions" or
identifier == "CheckAllPermissions" or
@@ -5127,7 +5259,8 @@ class Tokenizer(object):
"or": "OR",
"maplike": "MAPLIKE",
"setlike": "SETLIKE",
- "iterable": "ITERABLE"
+ "iterable": "ITERABLE",
+ "namespace": "NAMESPACE"
}
tokens.extend(keywords.values())
@@ -5224,7 +5357,8 @@ class Parser(Tokenizer):
def p_Definition(self, p):
"""
Definition : CallbackOrInterface
- | PartialInterface
+ | Namespace
+ | Partial
| Dictionary
| Exception
| Enum
@@ -5258,33 +5392,54 @@ class Parser(Tokenizer):
assert p[1]
p[0] = p[1]
- def p_Interface(self, p):
+ def handleNonPartialObject(self, location, identifier, constructor,
+ constructorArgs, nonPartialArgs):
"""
- Interface : INTERFACE IDENTIFIER Inheritance LBRACE InterfaceMembers RBRACE SEMICOLON
+ This handles non-partial objects (interfaces and namespaces) by
+ checking for an existing partial object, and promoting it to
+ non-partial as needed. The return value is the non-partial object.
+
+ constructorArgs are all the args for the constructor except the last
+ one: isKnownNonPartial.
+
+ nonPartialArgs are the args for the setNonPartial call.
"""
- location = self.getLocation(p, 1)
- identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2])
- members = p[5]
- parent = p[3]
+ # The name of the class starts with "IDL", so strip that off.
+ # Also, starts with a capital letter after that, so nix that
+ # as well.
+ prettyname = constructor.__name__[3:].lower()
try:
existingObj = self.globalScope()._lookupIdentifier(identifier)
if existingObj:
- p[0] = existingObj
- if not isinstance(p[0], IDLInterface):
- raise WebIDLError("Interface has the same name as "
- "non-interface object",
- [location, p[0].location])
- p[0].setNonPartial(location, parent, members)
- return
+ if not isinstance(existingObj, constructor):
+ raise WebIDLError("%s has the same name as "
+ "non-%s object" %
+ (prettyname.capitalize(), prettyname),
+ [location, existingObj.location])
+ existingObj.setNonPartial(*nonPartialArgs)
+ return existingObj
except Exception, ex:
if isinstance(ex, WebIDLError):
raise ex
pass
- iface = IDLInterface(location, self.globalScope(), identifier, parent,
- members, isKnownNonPartial=True)
- p[0] = iface
+ # True for isKnownNonPartial
+ return constructor(*(constructorArgs + [True]))
+
+ def p_Interface(self, p):
+ """
+ Interface : INTERFACE IDENTIFIER Inheritance LBRACE InterfaceMembers RBRACE SEMICOLON
+ """
+ location = self.getLocation(p, 1)
+ identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2])
+ members = p[5]
+ parent = p[3]
+
+ p[0] = self.handleNonPartialObject(
+ location, identifier, IDLInterface,
+ [location, self.globalScope(), identifier, parent, members],
+ [location, parent, members])
def p_InterfaceForwardDecl(self, p):
"""
@@ -5309,34 +5464,100 @@ class Parser(Tokenizer):
p[0] = IDLExternalInterface(location, self.globalScope(), identifier)
- def p_PartialInterface(self, p):
+ def p_Namespace(self, p):
"""
- PartialInterface : PARTIAL INTERFACE IDENTIFIER LBRACE InterfaceMembers RBRACE SEMICOLON
+ Namespace : NAMESPACE IDENTIFIER LBRACE InterfaceMembers RBRACE SEMICOLON
"""
- location = self.getLocation(p, 2)
- identifier = IDLUnresolvedIdentifier(self.getLocation(p, 3), p[3])
- members = p[5]
+ location = self.getLocation(p, 1)
+ identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2])
+ members = p[4]
+
+ p[0] = self.handleNonPartialObject(
+ location, identifier, IDLNamespace,
+ [location, self.globalScope(), identifier, members],
+ [location, None, members])
+
+ def p_Partial(self, p):
+ """
+ Partial : PARTIAL PartialDefinition
+ """
+ p[0] = p[2]
+
+ def p_PartialDefinition(self, p):
+ """
+ PartialDefinition : PartialInterface
+ | PartialNamespace
+ """
+ p[0] = p[1]
+
+ def handlePartialObject(self, location, identifier, nonPartialConstructor,
+ nonPartialConstructorArgs,
+ partialConstructorArgs):
+ """
+ This handles partial objects (interfaces and namespaces) by checking for
+ an existing non-partial object, and adding ourselves to it as needed.
+ The return value is our partial object. For now we just use
+ IDLPartialInterfaceOrNamespace for partial objects.
+
+ nonPartialConstructorArgs are all the args for the non-partial
+ constructor except the last two: members and isKnownNonPartial.
+
+ partialConstructorArgs are the arguments for the
+ IDLPartialInterfaceOrNamespace constructor, except the last one (the
+ non-partial object).
+ """
+ # The name of the class starts with "IDL", so strip that off.
+ # Also, starts with a capital letter after that, so nix that
+ # as well.
+ prettyname = nonPartialConstructor.__name__[3:].lower()
- nonPartialInterface = None
+ nonPartialObject = None
try:
- nonPartialInterface = self.globalScope()._lookupIdentifier(identifier)
- if nonPartialInterface:
- if not isinstance(nonPartialInterface, IDLInterface):
- raise WebIDLError("Partial interface has the same name as "
- "non-interface object",
- [location, nonPartialInterface.location])
+ nonPartialObject = self.globalScope()._lookupIdentifier(identifier)
+ if nonPartialObject:
+ if not isinstance(nonPartialObject, nonPartialConstructor):
+ raise WebIDLError("Partial %s has the same name as "
+ "non-%s object" %
+ (prettyname, prettyname),
+ [location, nonPartialObject.location])
except Exception, ex:
if isinstance(ex, WebIDLError):
raise ex
pass
- if not nonPartialInterface:
- nonPartialInterface = IDLInterface(location, self.globalScope(),
- identifier, None,
- [], isKnownNonPartial=False)
- partialInterface = IDLPartialInterface(location, identifier, members,
- nonPartialInterface)
- p[0] = partialInterface
+ if not nonPartialObject:
+ nonPartialObject = nonPartialConstructor(
+ # No members, False for isKnownNonPartial
+ *(nonPartialConstructorArgs + [[], False]))
+ partialInterface = IDLPartialInterfaceOrNamespace(
+ *(partialConstructorArgs + [nonPartialObject]))
+ return partialInterface
+
+ def p_PartialInterface(self, p):
+ """
+ PartialInterface : INTERFACE IDENTIFIER LBRACE InterfaceMembers RBRACE SEMICOLON
+ """
+ location = self.getLocation(p, 1)
+ identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2])
+ members = p[4]
+
+ p[0] = self.handlePartialObject(
+ location, identifier, IDLInterface,
+ [location, self.globalScope(), identifier, None],
+ [location, identifier, members])
+
+ def p_PartialNamespace(self, p):
+ """
+ PartialNamespace : NAMESPACE IDENTIFIER LBRACE InterfaceMembers RBRACE SEMICOLON
+ """
+ location = self.getLocation(p, 1)
+ identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2])
+ members = p[4]
+
+ p[0] = self.handlePartialObject(
+ location, identifier, IDLNamespace,
+ [location, self.globalScope(), identifier],
+ [location, identifier, members])
def p_Inheritance(self, p):
"""
@@ -5997,6 +6218,7 @@ class Parser(Tokenizer):
| JSONIFIER
| TYPEDEF
| UNRESTRICTED
+ | NAMESPACE
"""
p[0] = p[1]
@@ -6597,19 +6819,21 @@ class Parser(Tokenizer):
Tokenizer.__init__(self, outputdir, lexer)
logger = SqueakyCleanLogger()
- self.parser = yacc.yacc(module=self,
- outputdir=outputdir,
- tabmodule='webidlyacc',
- errorlog=logger,
- debug=False
- # Pickling the grammar is a speedup in
- # some cases (older Python?) but a
- # significant slowdown in others.
- # We're not pickling for now, until it
- # becomes a speedup again.
- # , picklefile='WebIDLGrammar.pkl'
- )
- logger.reportGrammarErrors()
+ try:
+ self.parser = yacc.yacc(module=self,
+ outputdir=outputdir,
+ tabmodule='webidlyacc',
+ errorlog=logger,
+ debug=False
+ # Pickling the grammar is a speedup in
+ # some cases (older Python?) but a
+ # significant slowdown in others.
+ # 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.
@@ -6680,10 +6904,11 @@ class Parser(Tokenizer):
# We're generating a partial interface to add a readonly
# property to the Navigator interface for every interface
# annotated with NavigatorProperty.
- partialInterface = IDLPartialInterface(iface.location,
- IDLUnresolvedIdentifier(iface.location, "Navigator"),
- [ navigatorProperty ],
- navigatorInterface)
+ partialInterface = IDLPartialInterfaceOrNamespace(
+ iface.location,
+ IDLUnresolvedIdentifier(iface.location, "Navigator"),
+ [ navigatorProperty ],
+ navigatorInterface)
self._productions.append(partialInterface)
iterable = None
diff --git a/components/script/dom/bindings/codegen/parser/abstract.patch b/components/script/dom/bindings/codegen/parser/abstract.patch
deleted file mode 100644
index a8e2ddcf759..00000000000
--- a/components/script/dom/bindings/codegen/parser/abstract.patch
+++ /dev/null
@@ -1,12 +0,0 @@
---- WebIDL.py
-+++ WebIDL.py
-@@ -1416,7 +1416,8 @@
- identifier == "LegacyEventInit" or
- identifier == "ProbablyShortLivingObject" or
- identifier == "LegacyUnenumerableNamedProperties" or
-- identifier == "NonOrdinaryGetPrototypeOf"):
-+ identifier == "NonOrdinaryGetPrototypeOf" or
-+ identifier == "Abstract"):
- # Known extended attributes that do not take values
- if not attr.noArguments():
- raise WebIDLError("[%s] must take no arguments" % identifier,
diff --git a/components/script/dom/bindings/codegen/parser/debug.patch b/components/script/dom/bindings/codegen/parser/debug.patch
index 85075dea490..ca391c38273 100644
--- a/components/script/dom/bindings/codegen/parser/debug.patch
+++ b/components/script/dom/bindings/codegen/parser/debug.patch
@@ -1,12 +1,12 @@
--- WebIDL.py
+++ WebIDL.py
-@@ -6438,7 +6438,8 @@ class Parser(Tokenizer):
- self.parser = yacc.yacc(module=self,
- outputdir=outputdir,
- tabmodule='webidlyacc',
-- errorlog=logger
-+ errorlog=logger,
-+ debug=False
- # Pickling the grammar is a speedup in
- # some cases (older Python?) but a
- # significant slowdown in others.
+@@ -6823,7 +6823,8 @@ class Parser(Tokenizer):
+ self.parser = yacc.yacc(module=self,
+ outputdir=outputdir,
+ tabmodule='webidlyacc',
+- errorlog=logger
++ errorlog=logger,
++ debug=False
+ # Pickling the grammar is a speedup in
+ # some cases (older Python?) but a
+ # significant slowdown in others.
diff --git a/components/script/dom/bindings/codegen/parser/pref-main-thread.patch b/components/script/dom/bindings/codegen/parser/pref-main-thread.patch
new file mode 100644
index 00000000000..4e4f8945f60
--- /dev/null
+++ b/components/script/dom/bindings/codegen/parser/pref-main-thread.patch
@@ -0,0 +1,28 @@
+--- WebIDL.py
++++ WebIDL.py
+@@ -1239,12 +1239,6 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins):
+ alias,
+ [member.location, m.location])
+
+- 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,
+- [self.location])
+-
+ for attribute in ["CheckAnyPermissions", "CheckAllPermissions"]:
+ if (self.getExtendedAttribute(attribute) and
+ self._exposureGlobalNames != set([self.parentScope.primaryGlobalName])):
+@@ -3459,12 +3453,6 @@ class IDLInterfaceMember(IDLObjectWithIdentifier, IDLExposureMixins):
+ IDLExposureMixins.finish(self, scope)
+
+ def validate(self):
+- if (self.getExtendedAttribute("Pref") and
+- self.exposureSet != set([self._globalScope.primaryGlobalName])):
+- raise WebIDLError("[Pref] used on an interface member that is not "
+- "%s-only" % self._globalScope.primaryGlobalName,
+- [self.location])
+-
+ for attribute in ["CheckAnyPermissions", "CheckAllPermissions"]:
+ if (self.getExtendedAttribute(attribute) and
+ self.exposureSet != set([self._globalScope.primaryGlobalName])):
diff --git a/components/script/dom/bindings/codegen/parser/tests/test_conditional_dictionary_member.py b/components/script/dom/bindings/codegen/parser/tests/test_conditional_dictionary_member.py
new file mode 100644
index 00000000000..433b7e501a4
--- /dev/null
+++ b/components/script/dom/bindings/codegen/parser/tests/test_conditional_dictionary_member.py
@@ -0,0 +1,110 @@
+def WebIDLTest(parser, harness):
+ parser.parse("""
+ dictionary Dict {
+ any foo;
+ [ChromeOnly] any bar;
+ };
+ """)
+ results = parser.finish()
+ harness.check(len(results), 1, "Should have a dictionary")
+ members = results[0].members;
+ harness.check(len(members), 2, "Should have two members")
+ # Note that members are ordered lexicographically, so "bar" comes
+ # before "foo".
+ harness.ok(members[0].getExtendedAttribute("ChromeOnly"),
+ "First member is not ChromeOnly")
+ harness.ok(not members[1].getExtendedAttribute("ChromeOnly"),
+ "Second member is ChromeOnly")
+
+ parser = parser.reset()
+ parser.parse("""
+ dictionary Dict {
+ any foo;
+ any bar;
+ };
+
+ interface Iface {
+ [Constant, Cached] readonly attribute Dict dict;
+ };
+ """)
+ results = parser.finish()
+ harness.check(len(results), 2, "Should have a dictionary and an interface")
+
+ parser = parser.reset()
+ exception = None
+ try:
+ parser.parse("""
+ dictionary Dict {
+ any foo;
+ [ChromeOnly] any bar;
+ };
+
+ interface Iface {
+ [Constant, Cached] readonly attribute Dict dict;
+ };
+ """)
+ results = parser.finish()
+ except Exception, exception:
+ pass
+
+ harness.ok(exception, "Should have thrown.")
+ harness.check(exception.message,
+ "[Cached] and [StoreInSlot] must not be used on an attribute "
+ "whose type contains a [ChromeOnly] dictionary member",
+ "Should have thrown the right exception")
+
+ parser = parser.reset()
+ exception = None
+ try:
+ parser.parse("""
+ dictionary ParentDict {
+ [ChromeOnly] any bar;
+ };
+
+ dictionary Dict : ParentDict {
+ any foo;
+ };
+
+ interface Iface {
+ [Constant, Cached] readonly attribute Dict dict;
+ };
+ """)
+ results = parser.finish()
+ except Exception, exception:
+ pass
+
+ harness.ok(exception, "Should have thrown (2).")
+ harness.check(exception.message,
+ "[Cached] and [StoreInSlot] must not be used on an attribute "
+ "whose type contains a [ChromeOnly] dictionary member",
+ "Should have thrown the right exception (2)")
+
+ parser = parser.reset()
+ exception = None
+ try:
+ parser.parse("""
+ dictionary GrandParentDict {
+ [ChromeOnly] any baz;
+ };
+
+ dictionary ParentDict : GrandParentDict {
+ any bar;
+ };
+
+ dictionary Dict : ParentDict {
+ any foo;
+ };
+
+ interface Iface {
+ [Constant, Cached] readonly attribute Dict dict;
+ };
+ """)
+ results = parser.finish()
+ except Exception, exception:
+ pass
+
+ harness.ok(exception, "Should have thrown (3).")
+ harness.check(exception.message,
+ "[Cached] and [StoreInSlot] must not be used on an attribute "
+ "whose type contains a [ChromeOnly] dictionary member",
+ "Should have thrown the right exception (3)")
diff --git a/components/script/dom/bindings/codegen/parser/tests/test_namespace.py b/components/script/dom/bindings/codegen/parser/tests/test_namespace.py
new file mode 100644
index 00000000000..74533a1770e
--- /dev/null
+++ b/components/script/dom/bindings/codegen/parser/tests/test_namespace.py
@@ -0,0 +1,223 @@
+def WebIDLTest(parser, harness):
+ parser.parse(
+ """
+ namespace MyNamespace {
+ attribute any foo;
+ any bar();
+ };
+ """)
+
+ results = parser.finish()
+ harness.check(len(results), 1, "Should have a thing.")
+ harness.ok(results[0].isNamespace(), "Our thing should be a namespace");
+ harness.check(len(results[0].members), 2,
+ "Should have two things in our namespace")
+ harness.ok(results[0].members[0].isAttr(), "First member is attribute")
+ harness.ok(results[0].members[0].isStatic(), "Attribute should be static")
+ harness.ok(results[0].members[1].isMethod(), "Second member is method")
+ harness.ok(results[0].members[1].isStatic(), "Operation should be static")
+
+ parser = parser.reset()
+ parser.parse(
+ """
+ namespace MyNamespace {
+ attribute any foo;
+ };
+ partial namespace MyNamespace {
+ any bar();
+ };
+ """)
+
+ results = parser.finish()
+ harness.check(len(results), 2, "Should have things.")
+ harness.ok(results[0].isNamespace(), "Our thing should be a namespace");
+ harness.check(len(results[0].members), 2,
+ "Should have two things in our namespace")
+ harness.ok(results[0].members[0].isAttr(), "First member is attribute")
+ harness.ok(results[0].members[0].isStatic(), "Attribute should be static");
+ harness.ok(results[0].members[1].isMethod(), "Second member is method")
+ harness.ok(results[0].members[1].isStatic(), "Operation should be static");
+
+ parser = parser.reset()
+ parser.parse(
+ """
+ partial namespace MyNamespace {
+ any bar();
+ };
+ namespace MyNamespace {
+ attribute any foo;
+ };
+ """)
+
+ results = parser.finish()
+ harness.check(len(results), 2, "Should have things.")
+ harness.ok(results[1].isNamespace(), "Our thing should be a namespace");
+ harness.check(len(results[1].members), 2,
+ "Should have two things in our namespace")
+ harness.ok(results[1].members[0].isAttr(), "First member is attribute")
+ harness.ok(results[1].members[0].isStatic(), "Attribute should be static");
+ harness.ok(results[1].members[1].isMethod(), "Second member is method")
+ harness.ok(results[1].members[1].isStatic(), "Operation should be static");
+
+ parser = parser.reset()
+ threw = False
+ try:
+ parser.parse(
+ """
+ namespace MyNamespace {
+ static attribute any foo;
+ };
+ """)
+
+ results = parser.finish()
+ except Exception, x:
+ threw = True
+ harness.ok(threw, "Should have thrown.")
+
+ parser = parser.reset()
+ threw = False
+ try:
+ parser.parse(
+ """
+ namespace MyNamespace {
+ static any bar();
+ };
+ """)
+
+ results = parser.finish()
+ except Exception, x:
+ threw = True
+ harness.ok(threw, "Should have thrown.")
+
+ parser = parser.reset()
+ threw = False
+ try:
+ parser.parse(
+ """
+ namespace MyNamespace {
+ any bar();
+ };
+
+ interface MyNamespace {
+ any baz();
+ };
+ """)
+
+ results = parser.finish()
+ except Exception, x:
+ threw = True
+ harness.ok(threw, "Should have thrown.")
+
+ parser = parser.reset()
+ threw = False
+ try:
+ parser.parse(
+ """
+ interface MyNamespace {
+ any baz();
+ };
+
+ namespace MyNamespace {
+ any bar();
+ };
+ """)
+
+ results = parser.finish()
+ except Exception, x:
+ threw = True
+ harness.ok(threw, "Should have thrown.")
+
+ parser = parser.reset()
+ threw = False
+ try:
+ parser.parse(
+ """
+ namespace MyNamespace {
+ any baz();
+ };
+
+ namespace MyNamespace {
+ any bar();
+ };
+ """)
+
+ results = parser.finish()
+ except Exception, x:
+ threw = True
+ harness.ok(threw, "Should have thrown.")
+
+ parser = parser.reset()
+ threw = False
+ try:
+ parser.parse(
+ """
+ partial namespace MyNamespace {
+ any baz();
+ };
+
+ interface MyNamespace {
+ any bar();
+ };
+ """)
+
+ results = parser.finish()
+ except Exception, x:
+ threw = True
+ harness.ok(threw, "Should have thrown.")
+
+ parser = parser.reset()
+ threw = False
+ try:
+ parser.parse(
+ """
+ namespace MyNamespace {
+ any bar();
+ };
+
+ partial interface MyNamespace {
+ any baz();
+ };
+ """)
+
+ results = parser.finish()
+ except Exception, x:
+ threw = True
+ harness.ok(threw, "Should have thrown.")
+
+ parser = parser.reset()
+ threw = False
+ try:
+ parser.parse(
+ """
+ partial interface MyNamespace {
+ any baz();
+ };
+
+ namespace MyNamespace {
+ any bar();
+ };
+ """)
+
+ results = parser.finish()
+ except Exception, x:
+ threw = True
+ harness.ok(threw, "Should have thrown.")
+
+ parser = parser.reset()
+ threw = False
+ try:
+ parser.parse(
+ """
+ interface MyNamespace {
+ any bar();
+ };
+
+ partial namespace MyNamespace {
+ any baz();
+ };
+ """)
+
+ results = parser.finish()
+ except Exception, x:
+ threw = True
+ harness.ok(threw, "Should have thrown.")
diff --git a/components/script/dom/bindings/codegen/parser/tests/test_securecontext_extended_attribute.py b/components/script/dom/bindings/codegen/parser/tests/test_securecontext_extended_attribute.py
new file mode 100644
index 00000000000..d907d08449f
--- /dev/null
+++ b/components/script/dom/bindings/codegen/parser/tests/test_securecontext_extended_attribute.py
@@ -0,0 +1,318 @@
+import WebIDL
+
+def WebIDLTest(parser, harness):
+ parser.parse("""
+ [SecureContext]
+ interface TestSecureContextOnInterface {
+ const octet TEST_CONSTANT = 0;
+ readonly attribute byte testAttribute;
+ void testMethod(byte foo);
+ };
+ partial interface TestSecureContextOnInterface {
+ const octet TEST_CONSTANT_2 = 0;
+ readonly attribute byte testAttribute2;
+ void testMethod2(byte foo);
+ };
+ """)
+ results = parser.finish()
+ harness.check(len(results[0].members), 6, "TestSecureContextOnInterface should have six members")
+ harness.ok(results[0].getExtendedAttribute("SecureContext"),
+ "Interface should have [SecureContext] extended attribute")
+ harness.ok(results[0].members[0].getExtendedAttribute("SecureContext"),
+ "[SecureContext] should propagate from interface to constant members")
+ harness.ok(results[0].members[1].getExtendedAttribute("SecureContext"),
+ "[SecureContext] should propagate from interface to attribute members")
+ harness.ok(results[0].members[2].getExtendedAttribute("SecureContext"),
+ "[SecureContext] should propagate from interface to method members")
+ harness.ok(results[0].members[3].getExtendedAttribute("SecureContext"),
+ "[SecureContext] should propagate from interface to constant members from partial interface")
+ harness.ok(results[0].members[4].getExtendedAttribute("SecureContext"),
+ "[SecureContext] should propagate from interface to attribute members from partial interface")
+ harness.ok(results[0].members[5].getExtendedAttribute("SecureContext"),
+ "[SecureContext] should propagate from interface to method members from partial interface")
+
+ # Same thing, but with the partial interface specified first:
+ parser = parser.reset()
+ parser.parse("""
+ partial interface TestSecureContextOnInterfaceAfterPartialInterface {
+ const octet TEST_CONSTANT_2 = 0;
+ readonly attribute byte testAttribute2;
+ void testMethod2(byte foo);
+ };
+ [SecureContext]
+ interface TestSecureContextOnInterfaceAfterPartialInterface {
+ const octet TEST_CONSTANT = 0;
+ readonly attribute byte testAttribute;
+ void testMethod(byte foo);
+ };
+ """)
+ results = parser.finish()
+ harness.check(len(results[1].members), 6, "TestSecureContextOnInterfaceAfterPartialInterface should have six members")
+ harness.ok(results[1].getExtendedAttribute("SecureContext"),
+ "Interface should have [SecureContext] extended attribute")
+ harness.ok(results[1].members[0].getExtendedAttribute("SecureContext"),
+ "[SecureContext] should propagate from interface to constant members")
+ harness.ok(results[1].members[1].getExtendedAttribute("SecureContext"),
+ "[SecureContext] should propagate from interface to attribute members")
+ harness.ok(results[1].members[2].getExtendedAttribute("SecureContext"),
+ "[SecureContext] should propagate from interface to method members")
+ harness.ok(results[1].members[3].getExtendedAttribute("SecureContext"),
+ "[SecureContext] should propagate from interface to constant members from partial interface")
+ harness.ok(results[1].members[4].getExtendedAttribute("SecureContext"),
+ "[SecureContext] should propagate from interface to attribute members from partial interface")
+ harness.ok(results[1].members[5].getExtendedAttribute("SecureContext"),
+ "[SecureContext] should propagate from interface to method members from partial interface")
+
+ parser = parser.reset()
+ parser.parse("""
+ interface TestSecureContextOnPartialInterface {
+ const octet TEST_CONSTANT = 0;
+ readonly attribute byte testAttribute;
+ void testMethod(byte foo);
+ };
+ [SecureContext]
+ partial interface TestSecureContextOnPartialInterface {
+ const octet TEST_CONSTANT_2 = 0;
+ readonly attribute byte testAttribute2;
+ void testMethod2(byte foo);
+ };
+ """)
+ results = parser.finish()
+ harness.check(len(results[0].members), 6, "TestSecureContextOnPartialInterface should have six members")
+ harness.ok(results[0].getExtendedAttribute("SecureContext") is None,
+ "[SecureContext] should not propagate from a partial interface to the interface")
+ harness.ok(results[0].members[0].getExtendedAttribute("SecureContext") is None,
+ "[SecureContext] should not propagate from a partial interface to the interface's constant members")
+ harness.ok(results[0].members[1].getExtendedAttribute("SecureContext") is None,
+ "[SecureContext] should not propagate from a partial interface to the interface's attribute members")
+ harness.ok(results[0].members[2].getExtendedAttribute("SecureContext") is None,
+ "[SecureContext] should not propagate from a partial interface to the interface's method members")
+ harness.ok(results[0].members[3].getExtendedAttribute("SecureContext"),
+ "Constant members from [SecureContext] partial interface should be [SecureContext]")
+ harness.ok(results[0].members[4].getExtendedAttribute("SecureContext"),
+ "Attribute members from [SecureContext] partial interface should be [SecureContext]")
+ harness.ok(results[0].members[5].getExtendedAttribute("SecureContext"),
+ "Method members from [SecureContext] partial interface should be [SecureContext]")
+
+ parser = parser.reset()
+ parser.parse("""
+ interface TestSecureContextOnInterfaceMembers {
+ const octet TEST_NON_SECURE_CONSTANT_1 = 0;
+ [SecureContext]
+ const octet TEST_SECURE_CONSTANT = 1;
+ const octet TEST_NON_SECURE_CONSTANT_2 = 2;
+ readonly attribute byte testNonSecureAttribute1;
+ [SecureContext]
+ readonly attribute byte testSecureAttribute;
+ readonly attribute byte testNonSecureAttribute2;
+ void testNonSecureMethod1(byte foo);
+ [SecureContext]
+ void testSecureMethod(byte foo);
+ void testNonSecureMethod2(byte foo);
+ };
+ """)
+ results = parser.finish()
+ harness.check(len(results[0].members), 9, "TestSecureContextOnInterfaceMembers should have nine members")
+ harness.ok(results[0].getExtendedAttribute("SecureContext") is None,
+ "[SecureContext] on members should not propagate up to the interface")
+ harness.ok(results[0].members[0].getExtendedAttribute("SecureContext") is None,
+ "Constant should not have [SecureContext] extended attribute")
+ harness.ok(results[0].members[1].getExtendedAttribute("SecureContext"),
+ "Constant should have [SecureContext] extended attribute")
+ harness.ok(results[0].members[2].getExtendedAttribute("SecureContext") is None,
+ "Constant should not have [SecureContext] extended attribute")
+ harness.ok(results[0].members[3].getExtendedAttribute("SecureContext") is None,
+ "Attribute should not have [SecureContext] extended attribute")
+ harness.ok(results[0].members[4].getExtendedAttribute("SecureContext"),
+ "Attribute should have [SecureContext] extended attribute")
+ harness.ok(results[0].members[5].getExtendedAttribute("SecureContext") is None,
+ "Attribute should not have [SecureContext] extended attribute")
+ harness.ok(results[0].members[6].getExtendedAttribute("SecureContext") is None,
+ "Method should not have [SecureContext] extended attribute")
+ harness.ok(results[0].members[7].getExtendedAttribute("SecureContext"),
+ "Method should have [SecureContext] extended attribute")
+ harness.ok(results[0].members[8].getExtendedAttribute("SecureContext") is None,
+ "Method should not have [SecureContext] extended attribute")
+
+ parser = parser.reset()
+ parser.parse("""
+ interface TestSecureContextOnPartialInterfaceMembers {
+ };
+ partial interface TestSecureContextOnPartialInterfaceMembers {
+ const octet TEST_NON_SECURE_CONSTANT_1 = 0;
+ [SecureContext]
+ const octet TEST_SECURE_CONSTANT = 1;
+ const octet TEST_NON_SECURE_CONSTANT_2 = 2;
+ readonly attribute byte testNonSecureAttribute1;
+ [SecureContext]
+ readonly attribute byte testSecureAttribute;
+ readonly attribute byte testNonSecureAttribute2;
+ void testNonSecureMethod1(byte foo);
+ [SecureContext]
+ void testSecureMethod(byte foo);
+ void testNonSecureMethod2(byte foo);
+ };
+ """)
+ results = parser.finish()
+ harness.check(len(results[0].members), 9, "TestSecureContextOnPartialInterfaceMembers should have nine members")
+ harness.ok(results[0].members[0].getExtendedAttribute("SecureContext") is None,
+ "Constant from partial interface should not have [SecureContext] extended attribute")
+ harness.ok(results[0].members[1].getExtendedAttribute("SecureContext"),
+ "Constant from partial interface should have [SecureContext] extended attribute")
+ harness.ok(results[0].members[2].getExtendedAttribute("SecureContext") is None,
+ "Constant from partial interface should not have [SecureContext] extended attribute")
+ harness.ok(results[0].members[3].getExtendedAttribute("SecureContext") is None,
+ "Attribute from partial interface should not have [SecureContext] extended attribute")
+ harness.ok(results[0].members[4].getExtendedAttribute("SecureContext"),
+ "Attribute from partial interface should have [SecureContext] extended attribute")
+ harness.ok(results[0].members[5].getExtendedAttribute("SecureContext") is None,
+ "Attribute from partial interface should not have [SecureContext] extended attribute")
+ harness.ok(results[0].members[6].getExtendedAttribute("SecureContext") is None,
+ "Method from partial interface should not have [SecureContext] extended attribute")
+ harness.ok(results[0].members[7].getExtendedAttribute("SecureContext"),
+ "Method from partial interface should have [SecureContext] extended attribute")
+ harness.ok(results[0].members[8].getExtendedAttribute("SecureContext") is None,
+ "Method from partial interface should not have [SecureContext] extended attribute")
+
+ parser = parser.reset()
+ threw = False
+ try:
+ parser.parse("""
+ [SecureContext=something]
+ interface TestSecureContextTakesNoValue1 {
+ const octet TEST_SECURE_CONSTANT = 0;
+ };
+ """)
+ results = parser.finish()
+ except:
+ threw = True
+ harness.ok(threw, "[SecureContext] must take no arguments (testing on interface)")
+
+ parser = parser.reset()
+ threw = False
+ try:
+ parser.parse("""
+ interface TestSecureContextForOverloads1 {
+ [SecureContext]
+ void testSecureMethod(byte foo);
+ };
+ partial interface TestSecureContextForOverloads1 {
+ void testSecureMethod(byte foo, byte bar);
+ };
+ """)
+ results = parser.finish()
+ except:
+ threw = True
+ harness.ok(threw, "If [SecureContext] appears on an overloaded operation, then it MUST appear on all overloads")
+
+ parser = parser.reset()
+ threw = False
+ try:
+ parser.parse("""
+ interface TestSecureContextForOverloads2 {
+ [SecureContext]
+ void testSecureMethod(byte foo);
+ };
+ partial interface TestSecureContextForOverloads2 {
+ [SecureContext]
+ void testSecureMethod(byte foo, byte bar);
+ };
+ """)
+ results = parser.finish()
+ except:
+ threw = True
+ harness.ok(not threw, "[SecureContext] can appear on an overloaded operation if it appears on all overloads")
+
+ parser = parser.reset()
+ threw = False
+ try:
+ parser.parse("""
+ [SecureContext]
+ interface TestSecureContextOnInterfaceAndMember {
+ [SecureContext]
+ void testSecureMethod(byte foo);
+ };
+ """)
+ results = parser.finish()
+ except:
+ threw = True
+ harness.ok(threw, "[SecureContext] must not appear on an interface and interface member")
+
+ parser = parser.reset()
+ threw = False
+ try:
+ parser.parse("""
+ interface TestSecureContextOnPartialInterfaceAndMember {
+ };
+ [SecureContext]
+ partial interface TestSecureContextOnPartialInterfaceAndMember {
+ [SecureContext]
+ void testSecureMethod(byte foo);
+ };
+ """)
+ results = parser.finish()
+ except:
+ threw = True
+ harness.ok(threw, "[SecureContext] must not appear on a partial interface and one of the partial interface's member's")
+
+ parser = parser.reset()
+ threw = False
+ try:
+ parser.parse("""
+ [SecureContext]
+ interface TestSecureContextOnInterfaceAndPartialInterfaceMember {
+ };
+ partial interface TestSecureContextOnInterfaceAndPartialInterfaceMember {
+ [SecureContext]
+ void testSecureMethod(byte foo);
+ };
+ """)
+ results = parser.finish()
+ except:
+ threw = True
+ harness.ok(threw, "[SecureContext] must not appear on an interface and one of its partial interface's member's")
+
+ parser = parser.reset()
+ threw = False
+ try:
+ parser.parse("""
+ [SecureContext]
+ interface TestSecureContextOnInheritedInterface {
+ };
+ interface TestSecureContextNotOnInheritingInterface : TestSecureContextOnInheritedInterface {
+ void testSecureMethod(byte foo);
+ };
+ """)
+ results = parser.finish()
+ except:
+ threw = True
+ harness.ok(threw, "[SecureContext] must appear on interfaces that inherit from another [SecureContext] interface")
+
+ # Test 'implements'. The behavior tested here may have to change depending
+ # on the resolution of https://github.com/heycam/webidl/issues/118
+ parser = parser.reset()
+ parser.parse("""
+ [SecureContext]
+ interface TestSecureContextInterfaceThatImplementsNonSecureContextInterface {
+ const octet TEST_CONSTANT = 0;
+ };
+ interface TestNonSecureContextInterface {
+ const octet TEST_CONSTANT_2 = 0;
+ readonly attribute byte testAttribute2;
+ void testMethod2(byte foo);
+ };
+ TestSecureContextInterfaceThatImplementsNonSecureContextInterface implements TestNonSecureContextInterface;
+ """)
+ results = parser.finish()
+ harness.check(len(results[0].members), 4, "TestSecureContextInterfaceThatImplementsNonSecureContextInterface should have two members")
+ harness.ok(results[0].getExtendedAttribute("SecureContext"),
+ "Interface should have [SecureContext] extended attribute")
+ harness.ok(results[0].members[0].getExtendedAttribute("SecureContext"),
+ "[SecureContext] should propagate from interface to constant members even when other members are copied from a non-[SecureContext] interface")
+ harness.ok(results[0].members[1].getExtendedAttribute("SecureContext") is None,
+ "Constants copied from non-[SecureContext] interface should not be [SecureContext]")
+ harness.ok(results[0].members[2].getExtendedAttribute("SecureContext") is None,
+ "Attributes copied from non-[SecureContext] interface should not be [SecureContext]")
+ harness.ok(results[0].members[3].getExtendedAttribute("SecureContext") is None,
+ "Methods copied from non-[SecureContext] interface should not be [SecureContext]")
+
diff --git a/components/script/dom/bindings/codegen/parser/update.sh b/components/script/dom/bindings/codegen/parser/update.sh
index 43f873beb67..76a99d9cecb 100755
--- a/components/script/dom/bindings/codegen/parser/update.sh
+++ b/components/script/dom/bindings/codegen/parser/update.sh
@@ -1,6 +1,7 @@
-wget https://mxr.mozilla.org/mozilla-central/source/dom/bindings/parser/WebIDL.py?raw=1 -O WebIDL.py
+wget https://hg.mozilla.org/mozilla-central/raw-file/tip/dom/bindings/parser/WebIDL.py -O WebIDL.py
patch < abstract.patch
patch < debug.patch
+patch < pref-main-thread.patch
wget https://hg.mozilla.org/mozilla-central/archive/tip.tar.gz/dom/bindings/parser/tests/ -O tests.tar.gz
rm -r tests
diff --git a/components/script/dom/bindings/codegen/property.html.template b/components/script/dom/bindings/codegen/property.html.template
new file mode 100644
index 00000000000..7b16aa78d0f
--- /dev/null
+++ b/components/script/dom/bindings/codegen/property.html.template
@@ -0,0 +1,3 @@
+<tr>
+ <td>${name}</td>
+</tr>