mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 13:21:05 +00:00
Bug 1803752 - Make CSS2Properties getters and setters use a common generated implementation. r=emilio
Differential Revision: https://phabricator.services.mozilla.com/D181106
This commit is contained in:
parent
87e05a8a95
commit
f1c25edf31
@ -2125,3 +2125,31 @@ addExternalIface('nsISessionStoreRestoreData',
|
||||
headerFile='nsISessionStoreRestoreData.h', notflattened=True)
|
||||
addExternalIface('nsIScreen', nativeType='nsIScreen',
|
||||
headerFile='nsIScreen.h', notflattened=True)
|
||||
|
||||
# The TemplatedAttributes dictionary has the interface name where the template
|
||||
# should be generated as the key. The values are lists of dictionaries, where
|
||||
# each dictionary corresponds to one template. The dictionary contains:
|
||||
#
|
||||
# template the template's name
|
||||
# getter the name for the native getter to call
|
||||
# setter the name for the native setter to call
|
||||
# argument a tuple for the additional argument that should be passed to the
|
||||
# native getter and setter, containing the type for the argument
|
||||
# and a name for the argument. The value will be supplied by the
|
||||
# [BindingTemplate] extended attribute.
|
||||
# attrName a string which in the generated C++ code would yield a
|
||||
# |const char*| that contains the attribute's name
|
||||
|
||||
TemplatedAttributes = {
|
||||
|
||||
'CSS2Properties': [
|
||||
{
|
||||
'template': 'CSS2Property',
|
||||
'getter': 'GetPropertyValue',
|
||||
'setter': 'SetPropertyValue',
|
||||
'argument': ('nsCSSPropertyID', 'id'),
|
||||
'attrName': 'nsCSSProps::PropertyIDLName(id)',
|
||||
},
|
||||
],
|
||||
|
||||
}
|
||||
|
@ -1927,7 +1927,7 @@ class CGAbstractMethod(CGThing):
|
||||
prologue += indent(
|
||||
fill(
|
||||
"""
|
||||
BindingCallContext ${cxname}(cx_, "${label}");
|
||||
BindingCallContext ${cxname}(cx_, ${label});
|
||||
""",
|
||||
cxname=cxname,
|
||||
label=error_reporting_label,
|
||||
@ -8989,6 +8989,14 @@ class CGPerSignatureCall(CGThing):
|
||||
dontSetSlot should be set to True if the value should not be cached in a
|
||||
slot (even if the attribute is marked as StoreInSlot or Cached in the
|
||||
WebIDL).
|
||||
|
||||
errorReportingLabel can contain a custom label to use for error reporting.
|
||||
It will be inserted as is in the code, so if it needs to be a literal
|
||||
string in C++ it should be quoted.
|
||||
|
||||
additionalArgsPre contains additional arguments that are added after the
|
||||
arguments that CGPerSignatureCall itself adds (JSContext, global, …), and
|
||||
before the actual arguments.
|
||||
"""
|
||||
|
||||
# XXXbz For now each entry in the argument list is either an
|
||||
@ -9013,6 +9021,8 @@ class CGPerSignatureCall(CGThing):
|
||||
objectName="obj",
|
||||
dontSetSlot=False,
|
||||
extendedAttributes=None,
|
||||
errorReportingLabel=None,
|
||||
additionalArgsPre=[],
|
||||
):
|
||||
assert idlNode.isMethod() == (not getter and not setter)
|
||||
assert idlNode.isAttr() == (getter or setter)
|
||||
@ -9322,14 +9332,17 @@ class CGPerSignatureCall(CGThing):
|
||||
assert setter
|
||||
cgThings.append(CGObservableArraySetterGenerator(descriptor, idlNode))
|
||||
else:
|
||||
context = GetLabelForErrorReporting(descriptor, idlNode, isConstructor)
|
||||
if getter:
|
||||
context = context + " getter"
|
||||
elif setter:
|
||||
context = context + " setter"
|
||||
# Callee expects a quoted string for the context if
|
||||
# there's a context.
|
||||
context = '"%s"' % context
|
||||
if errorReportingLabel is None:
|
||||
context = GetLabelForErrorReporting(descriptor, idlNode, isConstructor)
|
||||
if getter:
|
||||
context = context + " getter"
|
||||
elif setter:
|
||||
context = context + " setter"
|
||||
# Callee expects a quoted string for the context if
|
||||
# there's a context.
|
||||
context = '"%s"' % context
|
||||
else:
|
||||
context = errorReportingLabel
|
||||
|
||||
if idlNode.isMethod() and idlNode.getExtendedAttribute("WebExtensionStub"):
|
||||
[
|
||||
@ -9346,7 +9359,7 @@ class CGPerSignatureCall(CGThing):
|
||||
needsCallerType(idlNode),
|
||||
isChromeOnly(idlNode),
|
||||
args,
|
||||
argsPre,
|
||||
argsPre + additionalArgsPre,
|
||||
returnType,
|
||||
self.extendedAttributes,
|
||||
descriptor,
|
||||
@ -10225,6 +10238,8 @@ class CGGetterCall(CGPerSignatureCall):
|
||||
nativeMethodName,
|
||||
descriptor,
|
||||
attr,
|
||||
errorReportingLabel=None,
|
||||
argsPre=[],
|
||||
dontSetSlot=False,
|
||||
extendedAttributes=None,
|
||||
):
|
||||
@ -10249,6 +10264,8 @@ class CGGetterCall(CGPerSignatureCall):
|
||||
useCounterName=useCounterName,
|
||||
dontSetSlot=dontSetSlot,
|
||||
extendedAttributes=extendedAttributes,
|
||||
errorReportingLabel=errorReportingLabel,
|
||||
additionalArgsPre=argsPre,
|
||||
)
|
||||
|
||||
|
||||
@ -10285,7 +10302,15 @@ class CGSetterCall(CGPerSignatureCall):
|
||||
setter.
|
||||
"""
|
||||
|
||||
def __init__(self, argType, nativeMethodName, descriptor, attr):
|
||||
def __init__(
|
||||
self,
|
||||
argType,
|
||||
nativeMethodName,
|
||||
descriptor,
|
||||
attr,
|
||||
errorReportingLabel=None,
|
||||
argsPre=[],
|
||||
):
|
||||
if attr.getExtendedAttribute("UseCounter"):
|
||||
useCounterName = "%s_%s_setter" % (
|
||||
descriptor.interface.identifier.name,
|
||||
@ -10305,6 +10330,8 @@ class CGSetterCall(CGPerSignatureCall):
|
||||
attr,
|
||||
setter=True,
|
||||
useCounterName=useCounterName,
|
||||
errorReportingLabel=errorReportingLabel,
|
||||
additionalArgsPre=argsPre,
|
||||
)
|
||||
|
||||
def wrap_return_value(self):
|
||||
@ -10586,7 +10613,7 @@ class CGSpecializedMethod(CGAbstractStaticMethod):
|
||||
descriptor, idlMethod
|
||||
):
|
||||
return None
|
||||
return GetLabelForErrorReporting(descriptor, idlMethod, isConstructor)
|
||||
return '"%s"' % GetLabelForErrorReporting(descriptor, idlMethod, isConstructor)
|
||||
|
||||
def error_reporting_label(self):
|
||||
return CGSpecializedMethod.error_reporting_label_helper(
|
||||
@ -10596,7 +10623,9 @@ class CGSpecializedMethod(CGAbstractStaticMethod):
|
||||
@staticmethod
|
||||
def makeNativeName(descriptor, method):
|
||||
if method.underlyingAttr:
|
||||
return CGSpecializedGetter.makeNativeName(descriptor, method.underlyingAttr)
|
||||
return CGSpecializedGetterCommon.makeNativeName(
|
||||
descriptor, method.underlyingAttr
|
||||
)
|
||||
name = method.identifier.name
|
||||
return MakeNativeName(descriptor.binaryNameFor(name, method.isStatic()))
|
||||
|
||||
@ -10989,21 +11018,25 @@ class CGStaticMethod(CGAbstractStaticBindingMethod):
|
||||
)
|
||||
|
||||
|
||||
class CGSpecializedGetter(CGAbstractStaticMethod):
|
||||
class CGSpecializedGetterCommon(CGAbstractStaticMethod):
|
||||
"""
|
||||
A class for generating the code for a specialized attribute getter
|
||||
that the JIT can call with lower overhead.
|
||||
"""
|
||||
|
||||
def __init__(self, descriptor, attr):
|
||||
self.attr = attr
|
||||
name = "get_" + IDLToCIdentifier(attr.identifier.name)
|
||||
args = [
|
||||
Argument("JSContext*", "cx"),
|
||||
Argument("JS::Handle<JSObject*>", "obj"),
|
||||
Argument("void*", "void_self"),
|
||||
Argument("JSJitGetterCallArgs", "args"),
|
||||
]
|
||||
def __init__(
|
||||
self,
|
||||
descriptor,
|
||||
name,
|
||||
nativeName,
|
||||
attr,
|
||||
args,
|
||||
errorReportingLabel=None,
|
||||
additionalArg=None,
|
||||
):
|
||||
self.nativeName = nativeName
|
||||
self.errorReportingLabel = errorReportingLabel
|
||||
self.additionalArgs = [] if additionalArg is None else [additionalArg]
|
||||
# StoreInSlot attributes have their getters called from Wrap(). We
|
||||
# really hope they can't run script, and don't want to annotate Wrap()
|
||||
# methods as doing that anyway, so let's not annotate them as
|
||||
@ -11013,7 +11046,7 @@ class CGSpecializedGetter(CGAbstractStaticMethod):
|
||||
descriptor,
|
||||
name,
|
||||
"bool",
|
||||
args,
|
||||
args + self.additionalArgs,
|
||||
canRunScript=not attr.getExtendedAttribute("StoreInSlot"),
|
||||
)
|
||||
|
||||
@ -11041,7 +11074,13 @@ class CGSpecializedGetter(CGAbstractStaticMethod):
|
||||
# backing object from the slot, this requires its own generator.
|
||||
return prefix + getObservableArrayGetterBody(self.descriptor, self.attr)
|
||||
|
||||
nativeName = CGSpecializedGetter.makeNativeName(self.descriptor, self.attr)
|
||||
if self.nativeName is None:
|
||||
nativeName = CGSpecializedGetterCommon.makeNativeName(
|
||||
self.descriptor, self.attr
|
||||
)
|
||||
else:
|
||||
nativeName = self.nativeName
|
||||
|
||||
type = self.attr.type
|
||||
if self.attr.getExtendedAttribute("CrossOriginReadable"):
|
||||
remoteType = type
|
||||
@ -11074,6 +11113,8 @@ class CGSpecializedGetter(CGAbstractStaticMethod):
|
||||
nativeName,
|
||||
self.descriptor,
|
||||
self.attr,
|
||||
self.errorReportingLabel,
|
||||
argsPre=[a.name for a in self.additionalArgs],
|
||||
dontSetSlot=True,
|
||||
extendedAttributes=extendedAttributes,
|
||||
).define(),
|
||||
@ -11144,21 +11185,30 @@ class CGSpecializedGetter(CGAbstractStaticMethod):
|
||||
)
|
||||
|
||||
return (
|
||||
prefix + CGGetterCall(type, nativeName, self.descriptor, self.attr).define()
|
||||
prefix
|
||||
+ CGGetterCall(
|
||||
type,
|
||||
nativeName,
|
||||
self.descriptor,
|
||||
self.attr,
|
||||
self.errorReportingLabel,
|
||||
argsPre=[a.name for a in self.additionalArgs],
|
||||
).define()
|
||||
)
|
||||
|
||||
def auto_profiler_label(self):
|
||||
def auto_profiler_label(self, profilerLabel=None):
|
||||
if profilerLabel is None:
|
||||
profilerLabel = '"' + self.attr.identifier.name + '"'
|
||||
interface_name = self.descriptor.interface.identifier.name
|
||||
attr_name = self.attr.identifier.name
|
||||
return fill(
|
||||
"""
|
||||
AUTO_PROFILER_LABEL_DYNAMIC_FAST(
|
||||
"${interface_name}", "${attr_name}", DOM, cx,
|
||||
"${interface_name}", ${attr_name}, DOM, cx,
|
||||
uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) |
|
||||
uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS));
|
||||
""",
|
||||
interface_name=interface_name,
|
||||
attr_name=attr_name,
|
||||
attr_name=profilerLabel,
|
||||
)
|
||||
|
||||
def error_reporting_label(self):
|
||||
@ -11177,6 +11227,112 @@ class CGSpecializedGetter(CGAbstractStaticMethod):
|
||||
return nativeName
|
||||
|
||||
|
||||
class CGSpecializedGetter(CGSpecializedGetterCommon):
|
||||
"""
|
||||
A class for generating the code for a specialized attribute getter
|
||||
that the JIT can call with lower overhead.
|
||||
"""
|
||||
|
||||
def __init__(self, descriptor, attr):
|
||||
self.attr = attr
|
||||
name = "get_" + IDLToCIdentifier(attr.identifier.name)
|
||||
args = [
|
||||
Argument("JSContext*", "cx"),
|
||||
Argument("JS::Handle<JSObject*>", "obj"),
|
||||
Argument("void*", "void_self"),
|
||||
Argument("JSJitGetterCallArgs", "args"),
|
||||
]
|
||||
CGSpecializedGetterCommon.__init__(self, descriptor, name, None, attr, args)
|
||||
|
||||
|
||||
class CGTemplateForSpecializedGetter(CGSpecializedGetterCommon):
|
||||
"""
|
||||
A class for generating the code for a specialized attribute getter
|
||||
that can be used as the common getter that templated attribute
|
||||
getters can forward to.
|
||||
"""
|
||||
|
||||
def __init__(self, descriptor, template):
|
||||
self.attr = template.attr
|
||||
self.attrNameString = template.attrNameString
|
||||
args = [
|
||||
Argument("JSContext*", "cx"),
|
||||
Argument("JS::Handle<JSObject*>", "obj"),
|
||||
Argument("void*", "void_self"),
|
||||
Argument("JSJitGetterCallArgs", "args"),
|
||||
]
|
||||
errorDescription = (
|
||||
'ErrorDescriptionFor<ErrorFor::getter>{ "%s", attrName }'
|
||||
% descriptor.interface.identifier.name
|
||||
)
|
||||
CGSpecializedGetterCommon.__init__(
|
||||
self,
|
||||
descriptor,
|
||||
template.getter,
|
||||
template.getter,
|
||||
self.attr,
|
||||
args,
|
||||
errorReportingLabel=errorDescription,
|
||||
additionalArg=Argument(template.argument.type, template.argument.name),
|
||||
)
|
||||
|
||||
def auto_profiler_label(self):
|
||||
return (
|
||||
fill(
|
||||
"""
|
||||
const char* attrName = ${attrNameString};
|
||||
""",
|
||||
attrNameString=self.attrNameString,
|
||||
)
|
||||
+ CGSpecializedGetterCommon.auto_profiler_label(self, "attrName")
|
||||
)
|
||||
|
||||
|
||||
class CGSpecializedTemplatedGetter(CGAbstractStaticMethod):
|
||||
"""
|
||||
A class for generating the code for a specialized templated attribute
|
||||
getter that forwards to a common template getter.
|
||||
"""
|
||||
|
||||
def __init__(self, descriptor, attr, template, additionalArg):
|
||||
self.attr = attr
|
||||
self.template = template
|
||||
self.additionalArg = additionalArg
|
||||
name = "get_" + IDLToCIdentifier(attr.identifier.name)
|
||||
args = [
|
||||
Argument("JSContext*", "cx"),
|
||||
Argument("JS::Handle<JSObject*>", "obj"),
|
||||
Argument("void*", "void_self"),
|
||||
Argument("JSJitGetterCallArgs", "args"),
|
||||
]
|
||||
assert not attr.getExtendedAttribute("StoreInSlot")
|
||||
CGAbstractStaticMethod.__init__(
|
||||
self,
|
||||
descriptor,
|
||||
name,
|
||||
"bool",
|
||||
args,
|
||||
canRunScript=True,
|
||||
)
|
||||
|
||||
def definition_body(self):
|
||||
if self.additionalArg is None:
|
||||
additionalArg = self.attr.identifier.name
|
||||
else:
|
||||
additionalArg = self.additionalArg
|
||||
|
||||
return fill(
|
||||
"""
|
||||
return ${namespace}::${getter}(cx, obj, void_self, args, ${additionalArg});
|
||||
""",
|
||||
namespace=toBindingNamespace(
|
||||
self.template.descriptor.interface.identifier.name
|
||||
),
|
||||
getter=self.template.getter,
|
||||
additionalArg=additionalArg,
|
||||
)
|
||||
|
||||
|
||||
class CGGetterPromiseWrapper(CGAbstractStaticMethod):
|
||||
"""
|
||||
A class for generating a wrapper around another getter that will
|
||||
@ -11220,7 +11376,9 @@ class CGStaticGetter(CGAbstractStaticBindingMethod):
|
||||
CGAbstractStaticBindingMethod.__init__(self, descriptor, name)
|
||||
|
||||
def generate_code(self):
|
||||
nativeName = CGSpecializedGetter.makeNativeName(self.descriptor, self.attr)
|
||||
nativeName = CGSpecializedGetterCommon.makeNativeName(
|
||||
self.descriptor, self.attr
|
||||
)
|
||||
return CGGetterCall(self.attr.type, nativeName, self.descriptor, self.attr)
|
||||
|
||||
def auto_profiler_label(self):
|
||||
@ -11242,29 +11400,44 @@ class CGStaticGetter(CGAbstractStaticBindingMethod):
|
||||
return None
|
||||
|
||||
|
||||
class CGSpecializedSetter(CGAbstractStaticMethod):
|
||||
class CGSpecializedSetterCommon(CGAbstractStaticMethod):
|
||||
"""
|
||||
A class for generating the code for a specialized attribute setter
|
||||
that the JIT can call with lower overhead.
|
||||
"""
|
||||
|
||||
def __init__(self, descriptor, attr):
|
||||
self.attr = attr
|
||||
name = "set_" + IDLToCIdentifier(attr.identifier.name)
|
||||
args = [
|
||||
Argument("JSContext*", "cx"),
|
||||
Argument("JS::Handle<JSObject*>", "obj"),
|
||||
Argument("void*", "void_self"),
|
||||
Argument("JSJitSetterCallArgs", "args"),
|
||||
]
|
||||
def __init__(
|
||||
self,
|
||||
descriptor,
|
||||
name,
|
||||
nativeName,
|
||||
attr,
|
||||
args,
|
||||
errorReportingLabel=None,
|
||||
additionalArg=None,
|
||||
):
|
||||
self.nativeName = nativeName
|
||||
self.errorReportingLabel = errorReportingLabel
|
||||
self.additionalArgs = [] if additionalArg is None else [additionalArg]
|
||||
CGAbstractStaticMethod.__init__(
|
||||
self, descriptor, name, "bool", args, canRunScript=True
|
||||
self,
|
||||
descriptor,
|
||||
name,
|
||||
"bool",
|
||||
args + self.additionalArgs,
|
||||
canRunScript=True,
|
||||
)
|
||||
|
||||
def definition_body(self):
|
||||
nativeName = CGSpecializedSetter.makeNativeName(self.descriptor, self.attr)
|
||||
type = self.attr.type
|
||||
call = CGSetterCall(type, nativeName, self.descriptor, self.attr).define()
|
||||
call = CGSetterCall(
|
||||
type,
|
||||
self.nativeName,
|
||||
self.descriptor,
|
||||
self.attr,
|
||||
self.errorReportingLabel,
|
||||
[a.name for a in self.additionalArgs],
|
||||
).define()
|
||||
prefix = ""
|
||||
if self.attr.getExtendedAttribute("CrossOriginWritable"):
|
||||
if type.isGeckoInterface() and not type.unroll().inner.isExternal():
|
||||
@ -11298,18 +11471,19 @@ class CGSpecializedSetter(CGAbstractStaticMethod):
|
||||
call=call,
|
||||
)
|
||||
|
||||
def auto_profiler_label(self):
|
||||
def auto_profiler_label(self, profilerLabel=None):
|
||||
interface_name = self.descriptor.interface.identifier.name
|
||||
attr_name = self.attr.identifier.name
|
||||
if profilerLabel is None:
|
||||
profilerLabel = '"' + self.attr.identifier.name + '"'
|
||||
return fill(
|
||||
"""
|
||||
AUTO_PROFILER_LABEL_DYNAMIC_FAST(
|
||||
"${interface_name}", "${attr_name}", DOM, cx,
|
||||
"${interface_name}", ${attr_name}, DOM, cx,
|
||||
uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_SETTER) |
|
||||
uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS));
|
||||
""",
|
||||
interface_name=interface_name,
|
||||
attr_name=attr_name,
|
||||
attr_name=profilerLabel,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
@ -11320,14 +11494,19 @@ class CGSpecializedSetter(CGAbstractStaticMethod):
|
||||
attr.type, descriptor, allowTreatNonCallableAsNull=True
|
||||
):
|
||||
return None
|
||||
return (
|
||||
return '"%s"' % (
|
||||
GetLabelForErrorReporting(descriptor, attr, isConstructor=False) + " setter"
|
||||
)
|
||||
|
||||
def error_reporting_label(self):
|
||||
return CGSpecializedSetter.error_reporting_label_helper(
|
||||
errorReportingLabel = CGSpecializedSetterCommon.error_reporting_label_helper(
|
||||
self.descriptor, self.attr
|
||||
)
|
||||
if errorReportingLabel is None:
|
||||
return None
|
||||
if self.errorReportingLabel:
|
||||
return self.errorReportingLabel
|
||||
return errorReportingLabel
|
||||
|
||||
@staticmethod
|
||||
def makeNativeName(descriptor, attr):
|
||||
@ -11335,6 +11514,114 @@ class CGSpecializedSetter(CGAbstractStaticMethod):
|
||||
return "Set" + MakeNativeName(descriptor.binaryNameFor(name, attr.isStatic()))
|
||||
|
||||
|
||||
class CGSpecializedSetter(CGSpecializedSetterCommon):
|
||||
"""
|
||||
A class for generating the code for a specialized attribute setter
|
||||
that the JIT can call with lower overhead.
|
||||
"""
|
||||
|
||||
def __init__(self, descriptor, attr):
|
||||
self.attr = attr
|
||||
name = "set_" + IDLToCIdentifier(attr.identifier.name)
|
||||
args = [
|
||||
Argument("JSContext*", "cx"),
|
||||
Argument("JS::Handle<JSObject*>", "obj"),
|
||||
Argument("void*", "void_self"),
|
||||
Argument("JSJitSetterCallArgs", "args"),
|
||||
]
|
||||
CGSpecializedSetterCommon.__init__(
|
||||
self,
|
||||
descriptor,
|
||||
name,
|
||||
CGSpecializedSetterCommon.makeNativeName(descriptor, attr),
|
||||
attr,
|
||||
args,
|
||||
)
|
||||
|
||||
|
||||
class CGTemplateForSpecializedSetter(CGSpecializedSetterCommon):
|
||||
"""
|
||||
A class for generating the code for a specialized attribute setter
|
||||
that can be used as the common setter that templated attribute
|
||||
setters can forward to.
|
||||
"""
|
||||
|
||||
def __init__(self, descriptor, template):
|
||||
self.attr = template.attr
|
||||
self.attrNameString = template.attrNameString
|
||||
args = [
|
||||
Argument("JSContext*", "cx"),
|
||||
Argument("JS::Handle<JSObject*>", "obj"),
|
||||
Argument("void*", "void_self"),
|
||||
Argument("JSJitSetterCallArgs", "args"),
|
||||
]
|
||||
errorDescription = (
|
||||
'ErrorDescriptionFor<ErrorFor::setter>{ "%s", attrName }'
|
||||
% descriptor.interface.identifier.name
|
||||
)
|
||||
CGSpecializedSetterCommon.__init__(
|
||||
self,
|
||||
descriptor,
|
||||
template.setter,
|
||||
template.setter,
|
||||
self.attr,
|
||||
args,
|
||||
errorReportingLabel=errorDescription,
|
||||
additionalArg=Argument(template.argument.type, template.argument.name),
|
||||
)
|
||||
|
||||
def auto_profiler_label(self):
|
||||
return (
|
||||
fill(
|
||||
"""
|
||||
const char* attrName = ${attrNameString};
|
||||
""",
|
||||
attrNameString=self.attrNameString,
|
||||
)
|
||||
+ CGSpecializedSetterCommon.auto_profiler_label(self, "attrName")
|
||||
)
|
||||
|
||||
|
||||
class CGSpecializedTemplatedSetter(CGAbstractStaticMethod):
|
||||
"""
|
||||
A class for generating the code for a specialized templated attribute
|
||||
setter that forwards to a common template setter.
|
||||
"""
|
||||
|
||||
def __init__(self, descriptor, attr, template, additionalArg):
|
||||
self.attr = attr
|
||||
self.template = template
|
||||
self.additionalArg = additionalArg
|
||||
name = "set_" + IDLToCIdentifier(attr.identifier.name)
|
||||
args = [
|
||||
Argument("JSContext*", "cx"),
|
||||
Argument("JS::Handle<JSObject*>", "obj"),
|
||||
Argument("void*", "void_self"),
|
||||
Argument("JSJitSetterCallArgs", "args"),
|
||||
]
|
||||
CGAbstractStaticMethod.__init__(
|
||||
self, descriptor, name, "bool", args, canRunScript=True
|
||||
)
|
||||
|
||||
def definition_body(self):
|
||||
additionalArgs = []
|
||||
if self.additionalArg is None:
|
||||
additionalArgs.append(self.attr.identifier.name)
|
||||
else:
|
||||
additionalArgs.append(self.additionalArg)
|
||||
|
||||
return fill(
|
||||
"""
|
||||
return ${namespace}::${setter}(cx, obj, void_self, args, ${additionalArgs});
|
||||
""",
|
||||
namespace=toBindingNamespace(
|
||||
self.template.descriptor.interface.identifier.name
|
||||
),
|
||||
setter=self.template.setter,
|
||||
additionalArgs=", ".join(additionalArgs),
|
||||
)
|
||||
|
||||
|
||||
class CGStaticSetter(CGAbstractStaticBindingMethod):
|
||||
"""
|
||||
A class for generating the C++ code for an IDL static attribute setter.
|
||||
@ -11346,7 +11633,9 @@ class CGStaticSetter(CGAbstractStaticBindingMethod):
|
||||
CGAbstractStaticBindingMethod.__init__(self, descriptor, name)
|
||||
|
||||
def generate_code(self):
|
||||
nativeName = CGSpecializedSetter.makeNativeName(self.descriptor, self.attr)
|
||||
nativeName = CGSpecializedSetterCommon.makeNativeName(
|
||||
self.descriptor, self.attr
|
||||
)
|
||||
checkForArg = CGGeneric(
|
||||
fill(
|
||||
"""
|
||||
@ -11375,7 +11664,7 @@ class CGStaticSetter(CGAbstractStaticBindingMethod):
|
||||
)
|
||||
|
||||
def error_reporting_label(self):
|
||||
return CGSpecializedSetter.error_reporting_label_helper(
|
||||
return CGSpecializedSetterCommon.error_reporting_label_helper(
|
||||
self.descriptor, self.attr
|
||||
)
|
||||
|
||||
@ -11416,7 +11705,7 @@ class CGSpecializedForwardingSetter(CGSpecializedSetter):
|
||||
|
||||
def error_reporting_label(self):
|
||||
# We always need to be able to throw.
|
||||
return (
|
||||
return '"%s"' % (
|
||||
GetLabelForErrorReporting(self.descriptor, self.attr, isConstructor=False)
|
||||
+ " setter"
|
||||
)
|
||||
@ -14825,7 +15114,7 @@ class CGDOMJSProxyHandler_defineProperty(ClassMethod):
|
||||
if error_label:
|
||||
cxDecl = fill(
|
||||
"""
|
||||
BindingCallContext cx(cx_, "${error_label}");
|
||||
BindingCallContext cx(cx_, ${error_label});
|
||||
""",
|
||||
error_label=error_label,
|
||||
)
|
||||
@ -14877,7 +15166,7 @@ class CGDOMJSProxyHandler_defineProperty(ClassMethod):
|
||||
if error_label:
|
||||
set += fill(
|
||||
"""
|
||||
BindingCallContext cx(cx_, "${error_label}");
|
||||
BindingCallContext cx(cx_, ${error_label});
|
||||
""",
|
||||
error_label=error_label,
|
||||
)
|
||||
@ -15638,7 +15927,7 @@ class CGDOMJSProxyHandler_setCustom(ClassMethod):
|
||||
if error_label:
|
||||
cxDecl = fill(
|
||||
"""
|
||||
BindingCallContext cx(cx_, "${error_label}");
|
||||
BindingCallContext cx(cx_, ${error_label});
|
||||
""",
|
||||
error_label=error_label,
|
||||
)
|
||||
@ -15671,7 +15960,7 @@ class CGDOMJSProxyHandler_setCustom(ClassMethod):
|
||||
if error_label:
|
||||
cxDecl = fill(
|
||||
"""
|
||||
BindingCallContext cx(cx_, "${error_label}");
|
||||
BindingCallContext cx(cx_, ${error_label});
|
||||
""",
|
||||
error_label=error_label,
|
||||
)
|
||||
@ -16305,7 +16594,7 @@ def memberProperties(m, descriptor):
|
||||
|
||||
|
||||
class CGDescriptor(CGThing):
|
||||
def __init__(self, descriptor):
|
||||
def __init__(self, descriptor, attributeTemplates):
|
||||
CGThing.__init__(self)
|
||||
|
||||
assert (
|
||||
@ -16365,10 +16654,23 @@ class CGDescriptor(CGThing):
|
||||
defaultToJSONMethod = None
|
||||
needCrossOriginPropertyArrays = False
|
||||
unscopableNames = list()
|
||||
|
||||
for n in descriptor.interface.legacyFactoryFunctions:
|
||||
cgThings.append(
|
||||
CGClassConstructor(descriptor, n, LegacyFactoryFunctionName(n))
|
||||
)
|
||||
|
||||
if descriptor.attributeTemplates is not None:
|
||||
for template in descriptor.attributeTemplates:
|
||||
if template.getter is not None:
|
||||
cgThings.append(
|
||||
CGTemplateForSpecializedGetter(descriptor, template)
|
||||
)
|
||||
if template.setter is not None:
|
||||
cgThings.append(
|
||||
CGTemplateForSpecializedSetter(descriptor, template)
|
||||
)
|
||||
|
||||
for m in descriptor.interface.members:
|
||||
if m.isMethod() and m.identifier.name == "QueryInterface":
|
||||
continue
|
||||
@ -16417,7 +16719,28 @@ class CGDescriptor(CGThing):
|
||||
assert descriptor.interface.hasInterfaceObject()
|
||||
cgThings.append(CGStaticGetter(descriptor, m))
|
||||
elif descriptor.interface.hasInterfacePrototypeObject():
|
||||
specializedGetter = CGSpecializedGetter(descriptor, m)
|
||||
template = m.getExtendedAttribute("BindingTemplate")
|
||||
if template is not None:
|
||||
templateName = template[0][0]
|
||||
additionalArg = template[0][1]
|
||||
if not (m.type.isPrimitive() or m.type.isString()):
|
||||
raise TypeError(
|
||||
"We only support primitives or strings on templated attributes. "
|
||||
"Attribute '%s' on interface '%s' has type '%s' but tries to "
|
||||
"use template '%s'"
|
||||
% (
|
||||
m.identifier.name,
|
||||
descriptor.interface.identifier.name,
|
||||
m.type,
|
||||
templateName,
|
||||
)
|
||||
)
|
||||
template = attributeTemplates.get(templateName)
|
||||
specializedGetter = CGSpecializedTemplatedGetter(
|
||||
descriptor, m, template, additionalArg
|
||||
)
|
||||
else:
|
||||
specializedGetter = CGSpecializedGetter(descriptor, m)
|
||||
cgThings.append(specializedGetter)
|
||||
if m.type.isPromise():
|
||||
cgThings.append(
|
||||
@ -16430,7 +16753,21 @@ class CGDescriptor(CGThing):
|
||||
assert descriptor.interface.hasInterfaceObject()
|
||||
cgThings.append(CGStaticSetter(descriptor, m))
|
||||
elif descriptor.interface.hasInterfacePrototypeObject():
|
||||
cgThings.append(CGSpecializedSetter(descriptor, m))
|
||||
template = m.getExtendedAttribute("BindingTemplate")
|
||||
if template is not None:
|
||||
if isinstance(template[0], list):
|
||||
templateName = template[0][0]
|
||||
additionalArg = template[0][1]
|
||||
else:
|
||||
templateName = template[0]
|
||||
additionalArg = None
|
||||
template = attributeTemplates.get(templateName)
|
||||
specializedSetter = CGSpecializedTemplatedSetter(
|
||||
descriptor, m, template, additionalArg
|
||||
)
|
||||
else:
|
||||
specializedSetter = CGSpecializedSetter(descriptor, m)
|
||||
cgThings.append(specializedSetter)
|
||||
if props.isCrossOriginSetter:
|
||||
needCrossOriginPropertyArrays = True
|
||||
elif m.getExtendedAttribute("PutForwards"):
|
||||
@ -18708,7 +19045,9 @@ class CGBindingRoot(CGThing):
|
||||
cgthings.append(CGNamespace("binding_detail", CGFastCallback(t)))
|
||||
|
||||
# Do codegen for all the descriptors
|
||||
cgthings.extend([CGDescriptor(x) for x in descriptors])
|
||||
cgthings.extend(
|
||||
[CGDescriptor(x, config.attributeTemplates) for x in descriptors]
|
||||
)
|
||||
|
||||
# Do codegen for all the callback interfaces.
|
||||
cgthings.extend([CGCallbackInterface(x) for x in callbackDescriptors])
|
||||
@ -19324,7 +19663,7 @@ class CGExampleGetter(CGNativeMember):
|
||||
self,
|
||||
descriptor,
|
||||
attr,
|
||||
CGSpecializedGetter.makeNativeName(descriptor, attr),
|
||||
CGSpecializedGetterCommon.makeNativeName(descriptor, attr),
|
||||
(attr.type, []),
|
||||
descriptor.getExtendedAttributes(attr, getter=True),
|
||||
)
|
||||
@ -19349,7 +19688,7 @@ class CGExampleSetter(CGNativeMember):
|
||||
self,
|
||||
descriptor,
|
||||
attr,
|
||||
CGSpecializedSetter.makeNativeName(descriptor, attr),
|
||||
CGSpecializedSetterCommon.makeNativeName(descriptor, attr),
|
||||
(
|
||||
BuiltinTypes[IDLBuiltinType.Types.undefined],
|
||||
[FakeArgument(attr.type)],
|
||||
@ -19472,7 +19811,7 @@ class CGBindingImplClass(CGClass):
|
||||
m
|
||||
for m in iface.members
|
||||
if m.isAttr()
|
||||
and CGSpecializedGetter.makeNativeName(descriptor, m) == "Length"
|
||||
and CGSpecializedGetterCommon.makeNativeName(descriptor, m) == "Length"
|
||||
)
|
||||
if not haveLengthAttr:
|
||||
self.methodDecls.append(
|
||||
@ -20023,7 +20362,7 @@ class CGJSImplGetter(CGJSImplMember):
|
||||
self,
|
||||
descriptor,
|
||||
attr,
|
||||
CGSpecializedGetter.makeNativeName(descriptor, attr),
|
||||
CGSpecializedGetterCommon.makeNativeName(descriptor, attr),
|
||||
(attr.type, []),
|
||||
descriptor.getExtendedAttributes(attr, getter=True),
|
||||
passJSBitsAsNeeded=False,
|
||||
@ -20048,7 +20387,7 @@ class CGJSImplSetter(CGJSImplMember):
|
||||
self,
|
||||
descriptor,
|
||||
attr,
|
||||
CGSpecializedSetter.makeNativeName(descriptor, attr),
|
||||
CGSpecializedSetterCommon.makeNativeName(descriptor, attr),
|
||||
(
|
||||
BuiltinTypes[IDLBuiltinType.Types.undefined],
|
||||
[FakeArgument(attr.type)],
|
||||
@ -23592,7 +23931,7 @@ class CGEventGetter(CGNativeMember):
|
||||
self,
|
||||
descriptor,
|
||||
attr,
|
||||
CGSpecializedGetter.makeNativeName(descriptor, attr),
|
||||
CGSpecializedGetterCommon.makeNativeName(descriptor, attr),
|
||||
(attr.type, []),
|
||||
ea,
|
||||
resultNotAddRefed=not attr.type.isSequence(),
|
||||
@ -23932,7 +24271,7 @@ class CGEventClass(CGBindingImplClass):
|
||||
# either.
|
||||
extraMethods.append(
|
||||
ClassMethod(
|
||||
CGSpecializedGetter.makeNativeName(descriptor, m),
|
||||
CGSpecializedGetterCommon.makeNativeName(descriptor, m),
|
||||
"void",
|
||||
[Argument("JS::MutableHandle<JS::Value>", "aRetVal")],
|
||||
const=True,
|
||||
|
@ -52,6 +52,31 @@ class Configuration(DescriptorProvider):
|
||||
exec(io.open(filename, encoding="utf-8").read(), glbl)
|
||||
config = glbl["DOMInterfaces"]
|
||||
|
||||
class IDLAttrGetterOrSetterTemplate:
|
||||
def __init__(self, template, getter, setter, argument, attrName):
|
||||
class TemplateAdditionalArg:
|
||||
def __init__(self, type, name, value=None):
|
||||
self.type = type
|
||||
self.name = name
|
||||
self.value = value
|
||||
|
||||
self.descriptor = None
|
||||
self.usedInOtherInterfaces = False
|
||||
self.getter = getter
|
||||
self.setter = setter
|
||||
self.argument = TemplateAdditionalArg(*argument)
|
||||
self.attrNameString = attrName
|
||||
self.attr = None
|
||||
|
||||
self.attributeTemplates = dict()
|
||||
attributeTemplatesByInterface = dict()
|
||||
for interface, templates in glbl["TemplatedAttributes"].items():
|
||||
for template in templates:
|
||||
name = template.get("template")
|
||||
t = IDLAttrGetterOrSetterTemplate(**template)
|
||||
self.attributeTemplates[name] = t
|
||||
attributeTemplatesByInterface.setdefault(interface, list()).append(t)
|
||||
|
||||
webRoots = tuple(map(os.path.normpath, webRoots))
|
||||
|
||||
def isInWebIDLRoot(path):
|
||||
@ -137,7 +162,12 @@ class Configuration(DescriptorProvider):
|
||||
entry = config.get(iface.identifier.name, {})
|
||||
assert not isinstance(entry, list)
|
||||
|
||||
desc = Descriptor(self, iface, entry)
|
||||
desc = Descriptor(
|
||||
self,
|
||||
iface,
|
||||
entry,
|
||||
attributeTemplatesByInterface.get(iface.identifier.name),
|
||||
)
|
||||
self.descriptors.append(desc)
|
||||
# Setting up descriptorsByName while iterating through interfaces
|
||||
# means we can get the nativeType of iterable interfaces without
|
||||
@ -274,6 +304,183 @@ class Configuration(DescriptorProvider):
|
||||
offsets = accumulate(map(lambda n: len(n) + 1, names), initial=0)
|
||||
self.namesStringOffsets = list(zip(names, offsets))
|
||||
|
||||
allTemplatedAttributes = (
|
||||
(m, d)
|
||||
for d in self.descriptors
|
||||
if not d.interface.isExternal()
|
||||
for m in d.interface.members
|
||||
if m.isAttr() and m.getExtendedAttribute("BindingTemplate") is not None
|
||||
)
|
||||
# attributesPerTemplate will have the template names as keys, and a
|
||||
# list of tuples as values. Every tuple contains an IDLAttribute and a
|
||||
# descriptor.
|
||||
attributesPerTemplate = dict()
|
||||
for m, d in allTemplatedAttributes:
|
||||
t = m.getExtendedAttribute("BindingTemplate")
|
||||
if isinstance(t[0], list):
|
||||
t = t[0]
|
||||
l = attributesPerTemplate.setdefault(t[0], list())
|
||||
# We want the readonly attributes last, because we use the first
|
||||
# attribute in the list as the canonical attribute for the
|
||||
# template, and if there are any writable attributes the
|
||||
# template should have support for that.
|
||||
if not m.readonly:
|
||||
l.insert(0, (m, d))
|
||||
else:
|
||||
l.append((m, d))
|
||||
|
||||
for name, attributes in attributesPerTemplate.items():
|
||||
# We use the first attribute to generate a canonical implementation
|
||||
# of getter and setter.
|
||||
firstAttribute, firstDescriptor = attributes[0]
|
||||
template = self.attributeTemplates.get(name)
|
||||
if template is None:
|
||||
raise TypeError(
|
||||
"Unknown BindingTemplate with name %s for %s on %s"
|
||||
% (
|
||||
name,
|
||||
firstAttribute.identifier.name,
|
||||
firstDescriptor.interface.identifier.name,
|
||||
)
|
||||
)
|
||||
|
||||
# This mimics a real IDL attribute for templated bindings.
|
||||
class TemplateIDLAttribute:
|
||||
def __init__(self, attr):
|
||||
assert attr.isAttr()
|
||||
assert not attr.isMaplikeOrSetlikeAttr()
|
||||
assert not attr.slotIndices
|
||||
|
||||
self.identifier = attr.identifier
|
||||
self.type = attr.type
|
||||
self.extendedAttributes = attr.getExtendedAttributes()
|
||||
self.slotIndices = None
|
||||
|
||||
def getExtendedAttribute(self, name):
|
||||
return self.extendedAttributes.get(name)
|
||||
|
||||
def isAttr(self):
|
||||
return True
|
||||
|
||||
def isMaplikeOrSetlikeAttr(self):
|
||||
return False
|
||||
|
||||
def isMethod(self):
|
||||
return False
|
||||
|
||||
def isStatic(self):
|
||||
return False
|
||||
|
||||
template.attr = TemplateIDLAttribute(firstAttribute)
|
||||
|
||||
def filterExtendedAttributes(extendedAttributes):
|
||||
# These are the extended attributes that we allow to have
|
||||
# different values among all atributes that use the same
|
||||
# template.
|
||||
ignoredAttributes = {
|
||||
"BindingTemplate",
|
||||
"BindingAlias",
|
||||
"Pure",
|
||||
"Pref",
|
||||
"Func",
|
||||
"Throws",
|
||||
"GetterThrows",
|
||||
"SetterThrows",
|
||||
}
|
||||
return dict(
|
||||
filter(
|
||||
lambda i: i[0] not in ignoredAttributes,
|
||||
extendedAttributes.items(),
|
||||
)
|
||||
)
|
||||
|
||||
firstExtAttrs = filterExtendedAttributes(
|
||||
firstAttribute.getExtendedAttributes()
|
||||
)
|
||||
|
||||
for a, d in attributes:
|
||||
# We want to make sure all getters or setters grouped by a
|
||||
# template have the same WebIDL signatures, so make sure
|
||||
# their types are the same.
|
||||
if template.attr.type != a.type:
|
||||
raise TypeError(
|
||||
"%s on %s and %s on %s have different type, but they're using the same template %s."
|
||||
% (
|
||||
firstAttribute.identifier.name,
|
||||
firstDescriptor.interface.identifier.name,
|
||||
a.identifier.name,
|
||||
d.interface.identifier.name,
|
||||
name,
|
||||
)
|
||||
)
|
||||
|
||||
extAttrs = filterExtendedAttributes(a.getExtendedAttributes())
|
||||
if template.attr.extendedAttributes != extAttrs:
|
||||
for k in extAttrs.keys() - firstExtAttrs.keys():
|
||||
raise TypeError(
|
||||
"%s on %s has extended attribute %s and %s on %s does not, but they're using the same template %s."
|
||||
% (
|
||||
a.identifier.name,
|
||||
d.interface.identifier.name,
|
||||
k,
|
||||
firstAttribute.identifier.name,
|
||||
firstDescriptor.interface.identifier.name,
|
||||
name,
|
||||
)
|
||||
)
|
||||
for k in firstExtAttrs.keys() - extAttrs.keys():
|
||||
raise TypeError(
|
||||
"%s on %s has extended attribute %s and %s on %s does not, but they're using the same template %s."
|
||||
% (
|
||||
firstAttribute.identifier.name,
|
||||
firstDescriptor.interface.identifier.name,
|
||||
k,
|
||||
a.identifier.name,
|
||||
d.interface.identifier.name,
|
||||
name,
|
||||
)
|
||||
)
|
||||
for (k, v) in firstExtAttrs.items():
|
||||
if extAttrs[k] != v:
|
||||
raise TypeError(
|
||||
"%s on %s and %s on %s have different values for extended attribute %s, but they're using the same template %s."
|
||||
% (
|
||||
firstAttribute.identifier.name,
|
||||
firstDescriptor.interface.identifier.name,
|
||||
a.identifier.name,
|
||||
d.interface.identifier.name,
|
||||
k,
|
||||
name,
|
||||
)
|
||||
)
|
||||
|
||||
def sameThrows(getter=False, setter=False):
|
||||
extAttrs1 = firstDescriptor.getExtendedAttributes(
|
||||
firstAttribute, getter=getter, setter=setter
|
||||
)
|
||||
extAttrs2 = d.getExtendedAttributes(a, getter=getter, setter=setter)
|
||||
return ("needsErrorResult" in extAttrs1) == (
|
||||
"needsErrorResult" in extAttrs2
|
||||
)
|
||||
|
||||
if not sameThrows(getter=True) or (
|
||||
not a.readonly and not sameThrows(setter=True)
|
||||
):
|
||||
raise TypeError(
|
||||
"%s on %s and %s on %s have different annotations about throwing, but they're using the same template %s."
|
||||
% (
|
||||
firstAttribute.identifier.name,
|
||||
firstDescriptor.interface.identifier.name,
|
||||
a.identifier.name,
|
||||
d.interface.identifier.name,
|
||||
name,
|
||||
)
|
||||
)
|
||||
|
||||
for name, template in self.attributeTemplates.items():
|
||||
if template.attr is None:
|
||||
raise TypeError("Template %s is unused, please remove it." % name)
|
||||
|
||||
def getInterface(self, ifname):
|
||||
return self.interfaces[ifname]
|
||||
|
||||
@ -427,10 +634,14 @@ class Descriptor(DescriptorProvider):
|
||||
Represents a single descriptor for an interface. See Bindings.conf.
|
||||
"""
|
||||
|
||||
def __init__(self, config, interface, desc):
|
||||
def __init__(self, config, interface, desc, attributeTemplates):
|
||||
DescriptorProvider.__init__(self)
|
||||
self.config = config
|
||||
self.interface = interface
|
||||
self.attributeTemplates = attributeTemplates
|
||||
if self.attributeTemplates is not None:
|
||||
for t in self.attributeTemplates:
|
||||
t.descriptor = self
|
||||
|
||||
self.wantsXrays = not interface.isExternal() and interface.isExposedInWindow()
|
||||
|
||||
|
@ -464,6 +464,11 @@ class TErrorResult {
|
||||
// hopefully it's all temporary until we sort out the EME bits.
|
||||
friend class dom::Promise;
|
||||
|
||||
// Implementation of MaybeSetPendingException for the case when we're a
|
||||
// failure result. See documentation of MaybeSetPendingException for the
|
||||
// "context" argument.
|
||||
void SetPendingException(JSContext* cx, const char* context);
|
||||
|
||||
private:
|
||||
#ifdef DEBUG
|
||||
enum UnionState {
|
||||
@ -567,11 +572,6 @@ class TErrorResult {
|
||||
// touching the union anymore.
|
||||
void ClearUnionData();
|
||||
|
||||
// Implementation of MaybeSetPendingException for the case when we're a
|
||||
// failure result. See documentation of MaybeSetPendingException for the
|
||||
// "context" argument.
|
||||
void SetPendingException(JSContext* cx, const char* context);
|
||||
|
||||
// Methods for setting various specific kinds of pending exceptions. See
|
||||
// documentation of MaybeSetPendingException for the "context" argument.
|
||||
void SetPendingExceptionWithMessage(JSContext* cx, const char* context);
|
||||
@ -828,13 +828,47 @@ class CopyableErrorResult
|
||||
inline ErrorResult::ErrorResult(CopyableErrorResult&& aRHS)
|
||||
: ErrorResult(reinterpret_cast<ErrorResult&&>(aRHS)) {}
|
||||
|
||||
namespace dom {
|
||||
namespace binding_detail {
|
||||
namespace dom::binding_detail {
|
||||
|
||||
enum class ErrorFor {
|
||||
getter,
|
||||
setter,
|
||||
};
|
||||
|
||||
template <ErrorFor ErrorType>
|
||||
struct ErrorDescriptionFor {
|
||||
const char* mInterface;
|
||||
const char* mMember;
|
||||
};
|
||||
|
||||
class FastErrorResult : public mozilla::binding_danger::TErrorResult<
|
||||
mozilla::binding_danger::JustAssertCleanupPolicy> {
|
||||
public:
|
||||
using TErrorResult::MaybeSetPendingException;
|
||||
|
||||
template <ErrorFor ErrorType>
|
||||
[[nodiscard]] bool MaybeSetPendingException(
|
||||
JSContext* aCx, const ErrorDescriptionFor<ErrorType>& aDescription) {
|
||||
WouldReportJSException();
|
||||
if (!Failed()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsAutoCString description(aDescription.mInterface);
|
||||
description.Append('.');
|
||||
description.Append(aDescription.mMember);
|
||||
if constexpr (ErrorType == ErrorFor::getter) {
|
||||
description.AppendLiteral(" getter");
|
||||
} else {
|
||||
static_assert(ErrorType == ErrorFor::setter);
|
||||
description.AppendLiteral(" setter");
|
||||
}
|
||||
SetPendingException(aCx, description.get());
|
||||
return true;
|
||||
}
|
||||
};
|
||||
} // namespace binding_detail
|
||||
} // namespace dom
|
||||
|
||||
} // namespace dom::binding_detail
|
||||
|
||||
// We want an OOMReporter class that has the following properties:
|
||||
//
|
||||
|
@ -35,9 +35,13 @@ def generate(output, idlFilename, dataFile):
|
||||
# We already added this as a BindingAlias for the original prop.
|
||||
continue
|
||||
|
||||
propId = p.prop_id
|
||||
else:
|
||||
propId = p.id
|
||||
# Unfortunately, even some of the getters here are fallible
|
||||
# (e.g. on nsComputedDOMStyle).
|
||||
extendedAttrs = [
|
||||
"BindingTemplate=(CSS2Property, eCSSProperty_%s)" % propId,
|
||||
"CEReactions",
|
||||
"Throws",
|
||||
"SetterNeedsSubjectPrincipal=NonSystem",
|
||||
|
@ -5725,6 +5725,7 @@ class IDLAttribute(IDLInterfaceMember):
|
||||
or identifier == "ReturnValueNeedsContainsHack"
|
||||
or identifier == "BinaryName"
|
||||
or identifier == "NonEnumerable"
|
||||
or identifier == "BindingTemplate"
|
||||
):
|
||||
# Known attributes that we don't need to do anything with here
|
||||
pass
|
||||
@ -5735,6 +5736,9 @@ class IDLAttribute(IDLInterfaceMember):
|
||||
)
|
||||
IDLInterfaceMember.handleExtendedAttribute(self, attr)
|
||||
|
||||
def getExtendedAttributes(self):
|
||||
return self._extendedAttrDict
|
||||
|
||||
def resolve(self, parentScope):
|
||||
assert isinstance(parentScope, IDLScope)
|
||||
self.type.resolveType(parentScope)
|
||||
|
@ -1390,6 +1390,25 @@ implementing `MyInterface`.
|
||||
Multiple `[BindingAlias]` extended attributes can be used on a single
|
||||
attribute.
|
||||
|
||||
### `[BindingTemplate=(name, value)]`
|
||||
|
||||
This extended attribute can be specified on an attribute, and causes the getter
|
||||
and setter for this attribute to forward to a common generated implementation,
|
||||
shared with all other attributes that have a `[BindingTemplate]` with the same
|
||||
value for the `name` argument. The `TemplatedAttributes` dictionary in
|
||||
Bindings.conf needs to contain a definition for the template with the name
|
||||
`name`. The `value` will be passed as an argument when calling the common
|
||||
generated implementation.
|
||||
|
||||
This is aimed at very specialized use cases where an interface has a
|
||||
large number of attributes that all have the same type, and for which we have a
|
||||
native implementation that's common to all these attributes, and typically uses
|
||||
some id based on the attribute's name in the implementation. All the attributes
|
||||
that use the same template need to mostly have the same extended attributes,
|
||||
except form a small number that are allowed to differ (`[BindingTemplate]`,
|
||||
`[BindingAlias]`, `[Pure]`, [`Pref`] and [`Func`], and the annotations for
|
||||
whether the getter and setter throws exceptions).
|
||||
|
||||
### `[ChromeOnly]`
|
||||
|
||||
This extended attribute can be specified on any method, attribute, or
|
||||
|
@ -65,6 +65,10 @@ class nsDOMCSSDeclaration : public nsICSSDeclaration {
|
||||
*/
|
||||
virtual nsresult GetPropertyValue(const nsCSSPropertyID aPropID,
|
||||
nsACString& aValue);
|
||||
void GetPropertyValue(const nsCSSPropertyID aPropID, nsACString& aValue,
|
||||
mozilla::ErrorResult& aRv) {
|
||||
aRv = GetPropertyValue(aPropID, aValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method analogous to CSSStyleDeclaration::SetProperty. This
|
||||
@ -93,32 +97,6 @@ class nsDOMCSSDeclaration : public nsICSSDeclaration {
|
||||
uint32_t Length() override;
|
||||
|
||||
// WebIDL interface for CSS2Properties
|
||||
#define CSS_PROP_PUBLIC_OR_PRIVATE(publicname_, privatename_) publicname_
|
||||
#define CSS_PROP(id_, method_) \
|
||||
void Get##method_(nsACString& aValue, mozilla::ErrorResult& rv) { \
|
||||
rv = GetPropertyValue(eCSSProperty_##id_, aValue); \
|
||||
} \
|
||||
\
|
||||
void Set##method_(const nsACString& aValue, nsIPrincipal* aSubjectPrincipal, \
|
||||
mozilla::ErrorResult& aRv) { \
|
||||
SetPropertyValue(eCSSProperty_##id_, aValue, aSubjectPrincipal, aRv); \
|
||||
}
|
||||
|
||||
#define CSS_PROP_LIST_EXCLUDE_INTERNAL
|
||||
#define CSS_PROP_LIST_EXCLUDE_NOT_IN_STYLE
|
||||
#define CSS_PROP_LONGHAND(name_, id_, method_, ...) CSS_PROP(id_, method_)
|
||||
#define CSS_PROP_SHORTHAND(name_, id_, method_, ...) CSS_PROP(id_, method_)
|
||||
#define CSS_PROP_ALIAS(name_, aliasid_, id_, method_, ...) \
|
||||
CSS_PROP(id_, method_)
|
||||
#include "mozilla/ServoCSSPropList.h"
|
||||
#undef CSS_PROP_ALIAS
|
||||
#undef CSS_PROP_SHORTHAND
|
||||
#undef CSS_PROP_LONGHAND
|
||||
#undef CSS_PROP_LIST_EXCLUDE_INTERNAL
|
||||
#undef CSS_PROP_LIST_EXCLUDE_NOT_IN_STYLE
|
||||
#undef CSS_PROP
|
||||
#undef CSS_PROP_PUBLIC_OR_PRIVATE
|
||||
|
||||
virtual void IndexedGetter(uint32_t aIndex, bool& aFound,
|
||||
nsACString& aPropName) override;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user