forked from mirrors/gecko-dev
		
	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
							
								
									4a6f4b7aa1
								
							
						
					
					
						commit
						36003fd793
					
				
					 8 changed files with 722 additions and 105 deletions
				
			
		|  | @ -2125,3 +2125,31 @@ addExternalIface('nsISessionStoreRestoreData', | ||||||
|                  headerFile='nsISessionStoreRestoreData.h', notflattened=True) |                  headerFile='nsISessionStoreRestoreData.h', notflattened=True) | ||||||
| addExternalIface('nsIScreen', nativeType='nsIScreen', | addExternalIface('nsIScreen', nativeType='nsIScreen', | ||||||
|                  headerFile='nsIScreen.h', notflattened=True) |                  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( |             prologue += indent( | ||||||
|                 fill( |                 fill( | ||||||
|                     """ |                     """ | ||||||
|                 BindingCallContext ${cxname}(cx_, "${label}"); |                 BindingCallContext ${cxname}(cx_, ${label}); | ||||||
|                 """, |                 """, | ||||||
|                     cxname=cxname, |                     cxname=cxname, | ||||||
|                     label=error_reporting_label, |                     label=error_reporting_label, | ||||||
|  | @ -8991,6 +8991,14 @@ class CGPerSignatureCall(CGThing): | ||||||
|     dontSetSlot should be set to True if the value should not be cached in a |     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 |     slot (even if the attribute is marked as StoreInSlot or Cached in the | ||||||
|     WebIDL). |     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 |     # XXXbz For now each entry in the argument list is either an | ||||||
|  | @ -9015,6 +9023,8 @@ class CGPerSignatureCall(CGThing): | ||||||
|         objectName="obj", |         objectName="obj", | ||||||
|         dontSetSlot=False, |         dontSetSlot=False, | ||||||
|         extendedAttributes=None, |         extendedAttributes=None, | ||||||
|  |         errorReportingLabel=None, | ||||||
|  |         additionalArgsPre=[], | ||||||
|     ): |     ): | ||||||
|         assert idlNode.isMethod() == (not getter and not setter) |         assert idlNode.isMethod() == (not getter and not setter) | ||||||
|         assert idlNode.isAttr() == (getter or setter) |         assert idlNode.isAttr() == (getter or setter) | ||||||
|  | @ -9324,14 +9334,17 @@ class CGPerSignatureCall(CGThing): | ||||||
|             assert setter |             assert setter | ||||||
|             cgThings.append(CGObservableArraySetterGenerator(descriptor, idlNode)) |             cgThings.append(CGObservableArraySetterGenerator(descriptor, idlNode)) | ||||||
|         else: |         else: | ||||||
|             context = GetLabelForErrorReporting(descriptor, idlNode, isConstructor) |             if errorReportingLabel is None: | ||||||
|             if getter: |                 context = GetLabelForErrorReporting(descriptor, idlNode, isConstructor) | ||||||
|                 context = context + " getter" |                 if getter: | ||||||
|             elif setter: |                     context = context + " getter" | ||||||
|                 context = context + " setter" |                 elif setter: | ||||||
|             # Callee expects a quoted string for the context if |                     context = context + " setter" | ||||||
|             # there's a context. |                 # Callee expects a quoted string for the context if | ||||||
|             context = '"%s"' % context |                 # there's a context. | ||||||
|  |                 context = '"%s"' % context | ||||||
|  |             else: | ||||||
|  |                 context = errorReportingLabel | ||||||
| 
 | 
 | ||||||
|             if idlNode.isMethod() and idlNode.getExtendedAttribute("WebExtensionStub"): |             if idlNode.isMethod() and idlNode.getExtendedAttribute("WebExtensionStub"): | ||||||
|                 [ |                 [ | ||||||
|  | @ -9348,7 +9361,7 @@ class CGPerSignatureCall(CGThing): | ||||||
|                     needsCallerType(idlNode), |                     needsCallerType(idlNode), | ||||||
|                     isChromeOnly(idlNode), |                     isChromeOnly(idlNode), | ||||||
|                     args, |                     args, | ||||||
|                     argsPre, |                     argsPre + additionalArgsPre, | ||||||
|                     returnType, |                     returnType, | ||||||
|                     self.extendedAttributes, |                     self.extendedAttributes, | ||||||
|                     descriptor, |                     descriptor, | ||||||
|  | @ -10227,6 +10240,8 @@ class CGGetterCall(CGPerSignatureCall): | ||||||
|         nativeMethodName, |         nativeMethodName, | ||||||
|         descriptor, |         descriptor, | ||||||
|         attr, |         attr, | ||||||
|  |         errorReportingLabel=None, | ||||||
|  |         argsPre=[], | ||||||
|         dontSetSlot=False, |         dontSetSlot=False, | ||||||
|         extendedAttributes=None, |         extendedAttributes=None, | ||||||
|     ): |     ): | ||||||
|  | @ -10251,6 +10266,8 @@ class CGGetterCall(CGPerSignatureCall): | ||||||
|             useCounterName=useCounterName, |             useCounterName=useCounterName, | ||||||
|             dontSetSlot=dontSetSlot, |             dontSetSlot=dontSetSlot, | ||||||
|             extendedAttributes=extendedAttributes, |             extendedAttributes=extendedAttributes, | ||||||
|  |             errorReportingLabel=errorReportingLabel, | ||||||
|  |             additionalArgsPre=argsPre, | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -10287,7 +10304,15 @@ class CGSetterCall(CGPerSignatureCall): | ||||||
|     setter. |     setter. | ||||||
|     """ |     """ | ||||||
| 
 | 
 | ||||||
|     def __init__(self, argType, nativeMethodName, descriptor, attr): |     def __init__( | ||||||
|  |         self, | ||||||
|  |         argType, | ||||||
|  |         nativeMethodName, | ||||||
|  |         descriptor, | ||||||
|  |         attr, | ||||||
|  |         errorReportingLabel=None, | ||||||
|  |         argsPre=[], | ||||||
|  |     ): | ||||||
|         if attr.getExtendedAttribute("UseCounter"): |         if attr.getExtendedAttribute("UseCounter"): | ||||||
|             useCounterName = "%s_%s_setter" % ( |             useCounterName = "%s_%s_setter" % ( | ||||||
|                 descriptor.interface.identifier.name, |                 descriptor.interface.identifier.name, | ||||||
|  | @ -10307,6 +10332,8 @@ class CGSetterCall(CGPerSignatureCall): | ||||||
|             attr, |             attr, | ||||||
|             setter=True, |             setter=True, | ||||||
|             useCounterName=useCounterName, |             useCounterName=useCounterName, | ||||||
|  |             errorReportingLabel=errorReportingLabel, | ||||||
|  |             additionalArgsPre=argsPre, | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|     def wrap_return_value(self): |     def wrap_return_value(self): | ||||||
|  | @ -10588,7 +10615,7 @@ class CGSpecializedMethod(CGAbstractStaticMethod): | ||||||
|             descriptor, idlMethod |             descriptor, idlMethod | ||||||
|         ): |         ): | ||||||
|             return None |             return None | ||||||
|         return GetLabelForErrorReporting(descriptor, idlMethod, isConstructor) |         return '"%s"' % GetLabelForErrorReporting(descriptor, idlMethod, isConstructor) | ||||||
| 
 | 
 | ||||||
|     def error_reporting_label(self): |     def error_reporting_label(self): | ||||||
|         return CGSpecializedMethod.error_reporting_label_helper( |         return CGSpecializedMethod.error_reporting_label_helper( | ||||||
|  | @ -10598,7 +10625,9 @@ class CGSpecializedMethod(CGAbstractStaticMethod): | ||||||
|     @staticmethod |     @staticmethod | ||||||
|     def makeNativeName(descriptor, method): |     def makeNativeName(descriptor, method): | ||||||
|         if method.underlyingAttr: |         if method.underlyingAttr: | ||||||
|             return CGSpecializedGetter.makeNativeName(descriptor, method.underlyingAttr) |             return CGSpecializedGetterCommon.makeNativeName( | ||||||
|  |                 descriptor, method.underlyingAttr | ||||||
|  |             ) | ||||||
|         name = method.identifier.name |         name = method.identifier.name | ||||||
|         return MakeNativeName(descriptor.binaryNameFor(name, method.isStatic())) |         return MakeNativeName(descriptor.binaryNameFor(name, method.isStatic())) | ||||||
| 
 | 
 | ||||||
|  | @ -10991,21 +11020,25 @@ class CGStaticMethod(CGAbstractStaticBindingMethod): | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class CGSpecializedGetter(CGAbstractStaticMethod): | class CGSpecializedGetterCommon(CGAbstractStaticMethod): | ||||||
|     """ |     """ | ||||||
|     A class for generating the code for a specialized attribute getter |     A class for generating the code for a specialized attribute getter | ||||||
|     that the JIT can call with lower overhead. |     that the JIT can call with lower overhead. | ||||||
|     """ |     """ | ||||||
| 
 | 
 | ||||||
|     def __init__(self, descriptor, attr): |     def __init__( | ||||||
|         self.attr = attr |         self, | ||||||
|         name = "get_" + IDLToCIdentifier(attr.identifier.name) |         descriptor, | ||||||
|         args = [ |         name, | ||||||
|             Argument("JSContext*", "cx"), |         nativeName, | ||||||
|             Argument("JS::Handle<JSObject*>", "obj"), |         attr, | ||||||
|             Argument("void*", "void_self"), |         args, | ||||||
|             Argument("JSJitGetterCallArgs", "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 |         # StoreInSlot attributes have their getters called from Wrap().  We | ||||||
|         # really hope they can't run script, and don't want to annotate Wrap() |         # 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 |         # methods as doing that anyway, so let's not annotate them as | ||||||
|  | @ -11015,7 +11048,7 @@ class CGSpecializedGetter(CGAbstractStaticMethod): | ||||||
|             descriptor, |             descriptor, | ||||||
|             name, |             name, | ||||||
|             "bool", |             "bool", | ||||||
|             args, |             args + self.additionalArgs, | ||||||
|             canRunScript=not attr.getExtendedAttribute("StoreInSlot"), |             canRunScript=not attr.getExtendedAttribute("StoreInSlot"), | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|  | @ -11043,7 +11076,13 @@ class CGSpecializedGetter(CGAbstractStaticMethod): | ||||||
|             # backing object from the slot, this requires its own generator. |             # backing object from the slot, this requires its own generator. | ||||||
|             return prefix + getObservableArrayGetterBody(self.descriptor, self.attr) |             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 |         type = self.attr.type | ||||||
|         if self.attr.getExtendedAttribute("CrossOriginReadable"): |         if self.attr.getExtendedAttribute("CrossOriginReadable"): | ||||||
|             remoteType = type |             remoteType = type | ||||||
|  | @ -11076,6 +11115,8 @@ class CGSpecializedGetter(CGAbstractStaticMethod): | ||||||
|                         nativeName, |                         nativeName, | ||||||
|                         self.descriptor, |                         self.descriptor, | ||||||
|                         self.attr, |                         self.attr, | ||||||
|  |                         self.errorReportingLabel, | ||||||
|  |                         argsPre=[a.name for a in self.additionalArgs], | ||||||
|                         dontSetSlot=True, |                         dontSetSlot=True, | ||||||
|                         extendedAttributes=extendedAttributes, |                         extendedAttributes=extendedAttributes, | ||||||
|                     ).define(), |                     ).define(), | ||||||
|  | @ -11146,21 +11187,30 @@ class CGSpecializedGetter(CGAbstractStaticMethod): | ||||||
|             ) |             ) | ||||||
| 
 | 
 | ||||||
|         return ( |         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 |         interface_name = self.descriptor.interface.identifier.name | ||||||
|         attr_name = self.attr.identifier.name |  | ||||||
|         return fill( |         return fill( | ||||||
|             """ |             """ | ||||||
|             AUTO_PROFILER_LABEL_DYNAMIC_FAST( |             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::STRING_TEMPLATE_GETTER) | | ||||||
|               uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); |               uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); | ||||||
|             """, |             """, | ||||||
|             interface_name=interface_name, |             interface_name=interface_name, | ||||||
|             attr_name=attr_name, |             attr_name=profilerLabel, | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|     def error_reporting_label(self): |     def error_reporting_label(self): | ||||||
|  | @ -11179,6 +11229,112 @@ class CGSpecializedGetter(CGAbstractStaticMethod): | ||||||
|         return nativeName |         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): | class CGGetterPromiseWrapper(CGAbstractStaticMethod): | ||||||
|     """ |     """ | ||||||
|     A class for generating a wrapper around another getter that will |     A class for generating a wrapper around another getter that will | ||||||
|  | @ -11222,7 +11378,9 @@ class CGStaticGetter(CGAbstractStaticBindingMethod): | ||||||
|         CGAbstractStaticBindingMethod.__init__(self, descriptor, name) |         CGAbstractStaticBindingMethod.__init__(self, descriptor, name) | ||||||
| 
 | 
 | ||||||
|     def generate_code(self): |     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) |         return CGGetterCall(self.attr.type, nativeName, self.descriptor, self.attr) | ||||||
| 
 | 
 | ||||||
|     def auto_profiler_label(self): |     def auto_profiler_label(self): | ||||||
|  | @ -11244,29 +11402,44 @@ class CGStaticGetter(CGAbstractStaticBindingMethod): | ||||||
|         return None |         return None | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class CGSpecializedSetter(CGAbstractStaticMethod): | class CGSpecializedSetterCommon(CGAbstractStaticMethod): | ||||||
|     """ |     """ | ||||||
|     A class for generating the code for a specialized attribute setter |     A class for generating the code for a specialized attribute setter | ||||||
|     that the JIT can call with lower overhead. |     that the JIT can call with lower overhead. | ||||||
|     """ |     """ | ||||||
| 
 | 
 | ||||||
|     def __init__(self, descriptor, attr): |     def __init__( | ||||||
|         self.attr = attr |         self, | ||||||
|         name = "set_" + IDLToCIdentifier(attr.identifier.name) |         descriptor, | ||||||
|         args = [ |         name, | ||||||
|             Argument("JSContext*", "cx"), |         nativeName, | ||||||
|             Argument("JS::Handle<JSObject*>", "obj"), |         attr, | ||||||
|             Argument("void*", "void_self"), |         args, | ||||||
|             Argument("JSJitSetterCallArgs", "args"), |         errorReportingLabel=None, | ||||||
|         ] |         additionalArg=None, | ||||||
|  |     ): | ||||||
|  |         self.nativeName = nativeName | ||||||
|  |         self.errorReportingLabel = errorReportingLabel | ||||||
|  |         self.additionalArgs = [] if additionalArg is None else [additionalArg] | ||||||
|         CGAbstractStaticMethod.__init__( |         CGAbstractStaticMethod.__init__( | ||||||
|             self, descriptor, name, "bool", args, canRunScript=True |             self, | ||||||
|  |             descriptor, | ||||||
|  |             name, | ||||||
|  |             "bool", | ||||||
|  |             args + self.additionalArgs, | ||||||
|  |             canRunScript=True, | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|     def definition_body(self): |     def definition_body(self): | ||||||
|         nativeName = CGSpecializedSetter.makeNativeName(self.descriptor, self.attr) |  | ||||||
|         type = self.attr.type |         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 = "" |         prefix = "" | ||||||
|         if self.attr.getExtendedAttribute("CrossOriginWritable"): |         if self.attr.getExtendedAttribute("CrossOriginWritable"): | ||||||
|             if type.isGeckoInterface() and not type.unroll().inner.isExternal(): |             if type.isGeckoInterface() and not type.unroll().inner.isExternal(): | ||||||
|  | @ -11300,18 +11473,19 @@ class CGSpecializedSetter(CGAbstractStaticMethod): | ||||||
|             call=call, |             call=call, | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|     def auto_profiler_label(self): |     def auto_profiler_label(self, profilerLabel=None): | ||||||
|         interface_name = self.descriptor.interface.identifier.name |         interface_name = self.descriptor.interface.identifier.name | ||||||
|         attr_name = self.attr.identifier.name |         if profilerLabel is None: | ||||||
|  |             profilerLabel = '"' + self.attr.identifier.name + '"' | ||||||
|         return fill( |         return fill( | ||||||
|             """ |             """ | ||||||
|             AUTO_PROFILER_LABEL_DYNAMIC_FAST( |             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::STRING_TEMPLATE_SETTER) | | ||||||
|               uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); |               uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); | ||||||
|             """, |             """, | ||||||
|             interface_name=interface_name, |             interface_name=interface_name, | ||||||
|             attr_name=attr_name, |             attr_name=profilerLabel, | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|     @staticmethod |     @staticmethod | ||||||
|  | @ -11322,14 +11496,19 @@ class CGSpecializedSetter(CGAbstractStaticMethod): | ||||||
|             attr.type, descriptor, allowTreatNonCallableAsNull=True |             attr.type, descriptor, allowTreatNonCallableAsNull=True | ||||||
|         ): |         ): | ||||||
|             return None |             return None | ||||||
|         return ( |         return '"%s"' % ( | ||||||
|             GetLabelForErrorReporting(descriptor, attr, isConstructor=False) + " setter" |             GetLabelForErrorReporting(descriptor, attr, isConstructor=False) + " setter" | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|     def error_reporting_label(self): |     def error_reporting_label(self): | ||||||
|         return CGSpecializedSetter.error_reporting_label_helper( |         errorReportingLabel = CGSpecializedSetterCommon.error_reporting_label_helper( | ||||||
|             self.descriptor, self.attr |             self.descriptor, self.attr | ||||||
|         ) |         ) | ||||||
|  |         if errorReportingLabel is None: | ||||||
|  |             return None | ||||||
|  |         if self.errorReportingLabel: | ||||||
|  |             return self.errorReportingLabel | ||||||
|  |         return errorReportingLabel | ||||||
| 
 | 
 | ||||||
|     @staticmethod |     @staticmethod | ||||||
|     def makeNativeName(descriptor, attr): |     def makeNativeName(descriptor, attr): | ||||||
|  | @ -11337,6 +11516,114 @@ class CGSpecializedSetter(CGAbstractStaticMethod): | ||||||
|         return "Set" + MakeNativeName(descriptor.binaryNameFor(name, attr.isStatic())) |         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): | class CGStaticSetter(CGAbstractStaticBindingMethod): | ||||||
|     """ |     """ | ||||||
|     A class for generating the C++ code for an IDL static attribute setter. |     A class for generating the C++ code for an IDL static attribute setter. | ||||||
|  | @ -11348,7 +11635,9 @@ class CGStaticSetter(CGAbstractStaticBindingMethod): | ||||||
|         CGAbstractStaticBindingMethod.__init__(self, descriptor, name) |         CGAbstractStaticBindingMethod.__init__(self, descriptor, name) | ||||||
| 
 | 
 | ||||||
|     def generate_code(self): |     def generate_code(self): | ||||||
|         nativeName = CGSpecializedSetter.makeNativeName(self.descriptor, self.attr) |         nativeName = CGSpecializedSetterCommon.makeNativeName( | ||||||
|  |             self.descriptor, self.attr | ||||||
|  |         ) | ||||||
|         checkForArg = CGGeneric( |         checkForArg = CGGeneric( | ||||||
|             fill( |             fill( | ||||||
|                 """ |                 """ | ||||||
|  | @ -11377,7 +11666,7 @@ class CGStaticSetter(CGAbstractStaticBindingMethod): | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|     def error_reporting_label(self): |     def error_reporting_label(self): | ||||||
|         return CGSpecializedSetter.error_reporting_label_helper( |         return CGSpecializedSetterCommon.error_reporting_label_helper( | ||||||
|             self.descriptor, self.attr |             self.descriptor, self.attr | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|  | @ -11418,7 +11707,7 @@ class CGSpecializedForwardingSetter(CGSpecializedSetter): | ||||||
| 
 | 
 | ||||||
|     def error_reporting_label(self): |     def error_reporting_label(self): | ||||||
|         # We always need to be able to throw. |         # We always need to be able to throw. | ||||||
|         return ( |         return '"%s"' % ( | ||||||
|             GetLabelForErrorReporting(self.descriptor, self.attr, isConstructor=False) |             GetLabelForErrorReporting(self.descriptor, self.attr, isConstructor=False) | ||||||
|             + " setter" |             + " setter" | ||||||
|         ) |         ) | ||||||
|  | @ -14833,7 +15122,7 @@ class CGDOMJSProxyHandler_defineProperty(ClassMethod): | ||||||
|             if error_label: |             if error_label: | ||||||
|                 cxDecl = fill( |                 cxDecl = fill( | ||||||
|                     """ |                     """ | ||||||
|                     BindingCallContext cx(cx_, "${error_label}"); |                     BindingCallContext cx(cx_, ${error_label}); | ||||||
|                     """, |                     """, | ||||||
|                     error_label=error_label, |                     error_label=error_label, | ||||||
|                 ) |                 ) | ||||||
|  | @ -14885,7 +15174,7 @@ class CGDOMJSProxyHandler_defineProperty(ClassMethod): | ||||||
|             if error_label: |             if error_label: | ||||||
|                 set += fill( |                 set += fill( | ||||||
|                     """ |                     """ | ||||||
|                     BindingCallContext cx(cx_, "${error_label}"); |                     BindingCallContext cx(cx_, ${error_label}); | ||||||
|                     """, |                     """, | ||||||
|                     error_label=error_label, |                     error_label=error_label, | ||||||
|                 ) |                 ) | ||||||
|  | @ -15646,7 +15935,7 @@ class CGDOMJSProxyHandler_setCustom(ClassMethod): | ||||||
|             if error_label: |             if error_label: | ||||||
|                 cxDecl = fill( |                 cxDecl = fill( | ||||||
|                     """ |                     """ | ||||||
|                     BindingCallContext cx(cx_, "${error_label}"); |                     BindingCallContext cx(cx_, ${error_label}); | ||||||
|                     """, |                     """, | ||||||
|                     error_label=error_label, |                     error_label=error_label, | ||||||
|                 ) |                 ) | ||||||
|  | @ -15679,7 +15968,7 @@ class CGDOMJSProxyHandler_setCustom(ClassMethod): | ||||||
|             if error_label: |             if error_label: | ||||||
|                 cxDecl = fill( |                 cxDecl = fill( | ||||||
|                     """ |                     """ | ||||||
|                     BindingCallContext cx(cx_, "${error_label}"); |                     BindingCallContext cx(cx_, ${error_label}); | ||||||
|                     """, |                     """, | ||||||
|                     error_label=error_label, |                     error_label=error_label, | ||||||
|                 ) |                 ) | ||||||
|  | @ -16313,7 +16602,7 @@ def memberProperties(m, descriptor): | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class CGDescriptor(CGThing): | class CGDescriptor(CGThing): | ||||||
|     def __init__(self, descriptor): |     def __init__(self, descriptor, attributeTemplates): | ||||||
|         CGThing.__init__(self) |         CGThing.__init__(self) | ||||||
| 
 | 
 | ||||||
|         assert ( |         assert ( | ||||||
|  | @ -16373,10 +16662,23 @@ class CGDescriptor(CGThing): | ||||||
|         defaultToJSONMethod = None |         defaultToJSONMethod = None | ||||||
|         needCrossOriginPropertyArrays = False |         needCrossOriginPropertyArrays = False | ||||||
|         unscopableNames = list() |         unscopableNames = list() | ||||||
|  | 
 | ||||||
|         for n in descriptor.interface.legacyFactoryFunctions: |         for n in descriptor.interface.legacyFactoryFunctions: | ||||||
|             cgThings.append( |             cgThings.append( | ||||||
|                 CGClassConstructor(descriptor, n, LegacyFactoryFunctionName(n)) |                 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: |         for m in descriptor.interface.members: | ||||||
|             if m.isMethod() and m.identifier.name == "QueryInterface": |             if m.isMethod() and m.identifier.name == "QueryInterface": | ||||||
|                 continue |                 continue | ||||||
|  | @ -16425,7 +16727,28 @@ class CGDescriptor(CGThing): | ||||||
|                     assert descriptor.interface.hasInterfaceObject() |                     assert descriptor.interface.hasInterfaceObject() | ||||||
|                     cgThings.append(CGStaticGetter(descriptor, m)) |                     cgThings.append(CGStaticGetter(descriptor, m)) | ||||||
|                 elif descriptor.interface.hasInterfacePrototypeObject(): |                 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) |                     cgThings.append(specializedGetter) | ||||||
|                     if m.type.isPromise(): |                     if m.type.isPromise(): | ||||||
|                         cgThings.append( |                         cgThings.append( | ||||||
|  | @ -16438,7 +16761,21 @@ class CGDescriptor(CGThing): | ||||||
|                         assert descriptor.interface.hasInterfaceObject() |                         assert descriptor.interface.hasInterfaceObject() | ||||||
|                         cgThings.append(CGStaticSetter(descriptor, m)) |                         cgThings.append(CGStaticSetter(descriptor, m)) | ||||||
|                     elif descriptor.interface.hasInterfacePrototypeObject(): |                     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: |                         if props.isCrossOriginSetter: | ||||||
|                             needCrossOriginPropertyArrays = True |                             needCrossOriginPropertyArrays = True | ||||||
|                 elif m.getExtendedAttribute("PutForwards"): |                 elif m.getExtendedAttribute("PutForwards"): | ||||||
|  | @ -18716,7 +19053,9 @@ class CGBindingRoot(CGThing): | ||||||
|                 cgthings.append(CGNamespace("binding_detail", CGFastCallback(t))) |                 cgthings.append(CGNamespace("binding_detail", CGFastCallback(t))) | ||||||
| 
 | 
 | ||||||
|         # Do codegen for all the descriptors |         # 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. |         # Do codegen for all the callback interfaces. | ||||||
|         cgthings.extend([CGCallbackInterface(x) for x in callbackDescriptors]) |         cgthings.extend([CGCallbackInterface(x) for x in callbackDescriptors]) | ||||||
|  | @ -19332,7 +19671,7 @@ class CGExampleGetter(CGNativeMember): | ||||||
|             self, |             self, | ||||||
|             descriptor, |             descriptor, | ||||||
|             attr, |             attr, | ||||||
|             CGSpecializedGetter.makeNativeName(descriptor, attr), |             CGSpecializedGetterCommon.makeNativeName(descriptor, attr), | ||||||
|             (attr.type, []), |             (attr.type, []), | ||||||
|             descriptor.getExtendedAttributes(attr, getter=True), |             descriptor.getExtendedAttributes(attr, getter=True), | ||||||
|         ) |         ) | ||||||
|  | @ -19357,7 +19696,7 @@ class CGExampleSetter(CGNativeMember): | ||||||
|             self, |             self, | ||||||
|             descriptor, |             descriptor, | ||||||
|             attr, |             attr, | ||||||
|             CGSpecializedSetter.makeNativeName(descriptor, attr), |             CGSpecializedSetterCommon.makeNativeName(descriptor, attr), | ||||||
|             ( |             ( | ||||||
|                 BuiltinTypes[IDLBuiltinType.Types.undefined], |                 BuiltinTypes[IDLBuiltinType.Types.undefined], | ||||||
|                 [FakeArgument(attr.type)], |                 [FakeArgument(attr.type)], | ||||||
|  | @ -19480,7 +19819,7 @@ class CGBindingImplClass(CGClass): | ||||||
|                 m |                 m | ||||||
|                 for m in iface.members |                 for m in iface.members | ||||||
|                 if m.isAttr() |                 if m.isAttr() | ||||||
|                 and CGSpecializedGetter.makeNativeName(descriptor, m) == "Length" |                 and CGSpecializedGetterCommon.makeNativeName(descriptor, m) == "Length" | ||||||
|             ) |             ) | ||||||
|             if not haveLengthAttr: |             if not haveLengthAttr: | ||||||
|                 self.methodDecls.append( |                 self.methodDecls.append( | ||||||
|  | @ -20031,7 +20370,7 @@ class CGJSImplGetter(CGJSImplMember): | ||||||
|             self, |             self, | ||||||
|             descriptor, |             descriptor, | ||||||
|             attr, |             attr, | ||||||
|             CGSpecializedGetter.makeNativeName(descriptor, attr), |             CGSpecializedGetterCommon.makeNativeName(descriptor, attr), | ||||||
|             (attr.type, []), |             (attr.type, []), | ||||||
|             descriptor.getExtendedAttributes(attr, getter=True), |             descriptor.getExtendedAttributes(attr, getter=True), | ||||||
|             passJSBitsAsNeeded=False, |             passJSBitsAsNeeded=False, | ||||||
|  | @ -20056,7 +20395,7 @@ class CGJSImplSetter(CGJSImplMember): | ||||||
|             self, |             self, | ||||||
|             descriptor, |             descriptor, | ||||||
|             attr, |             attr, | ||||||
|             CGSpecializedSetter.makeNativeName(descriptor, attr), |             CGSpecializedSetterCommon.makeNativeName(descriptor, attr), | ||||||
|             ( |             ( | ||||||
|                 BuiltinTypes[IDLBuiltinType.Types.undefined], |                 BuiltinTypes[IDLBuiltinType.Types.undefined], | ||||||
|                 [FakeArgument(attr.type)], |                 [FakeArgument(attr.type)], | ||||||
|  | @ -23600,7 +23939,7 @@ class CGEventGetter(CGNativeMember): | ||||||
|             self, |             self, | ||||||
|             descriptor, |             descriptor, | ||||||
|             attr, |             attr, | ||||||
|             CGSpecializedGetter.makeNativeName(descriptor, attr), |             CGSpecializedGetterCommon.makeNativeName(descriptor, attr), | ||||||
|             (attr.type, []), |             (attr.type, []), | ||||||
|             ea, |             ea, | ||||||
|             resultNotAddRefed=not attr.type.isSequence(), |             resultNotAddRefed=not attr.type.isSequence(), | ||||||
|  | @ -23940,7 +24279,7 @@ class CGEventClass(CGBindingImplClass): | ||||||
|                     # either. |                     # either. | ||||||
|                     extraMethods.append( |                     extraMethods.append( | ||||||
|                         ClassMethod( |                         ClassMethod( | ||||||
|                             CGSpecializedGetter.makeNativeName(descriptor, m), |                             CGSpecializedGetterCommon.makeNativeName(descriptor, m), | ||||||
|                             "void", |                             "void", | ||||||
|                             [Argument("JS::MutableHandle<JS::Value>", "aRetVal")], |                             [Argument("JS::MutableHandle<JS::Value>", "aRetVal")], | ||||||
|                             const=True, |                             const=True, | ||||||
|  |  | ||||||
|  | @ -52,6 +52,31 @@ class Configuration(DescriptorProvider): | ||||||
|         exec(io.open(filename, encoding="utf-8").read(), glbl) |         exec(io.open(filename, encoding="utf-8").read(), glbl) | ||||||
|         config = glbl["DOMInterfaces"] |         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)) |         webRoots = tuple(map(os.path.normpath, webRoots)) | ||||||
| 
 | 
 | ||||||
|         def isInWebIDLRoot(path): |         def isInWebIDLRoot(path): | ||||||
|  | @ -137,7 +162,12 @@ class Configuration(DescriptorProvider): | ||||||
|             entry = config.get(iface.identifier.name, {}) |             entry = config.get(iface.identifier.name, {}) | ||||||
|             assert not isinstance(entry, list) |             assert not isinstance(entry, list) | ||||||
| 
 | 
 | ||||||
|             desc = Descriptor(self, iface, entry) |             desc = Descriptor( | ||||||
|  |                 self, | ||||||
|  |                 iface, | ||||||
|  |                 entry, | ||||||
|  |                 attributeTemplatesByInterface.get(iface.identifier.name), | ||||||
|  |             ) | ||||||
|             self.descriptors.append(desc) |             self.descriptors.append(desc) | ||||||
|             # Setting up descriptorsByName while iterating through interfaces |             # Setting up descriptorsByName while iterating through interfaces | ||||||
|             # means we can get the nativeType of iterable interfaces without |             # 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) |         offsets = accumulate(map(lambda n: len(n) + 1, names), initial=0) | ||||||
|         self.namesStringOffsets = list(zip(names, offsets)) |         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: | ||||||
|  |                 print("Template %s is unused, please remove it." % name) | ||||||
|  | 
 | ||||||
|     def getInterface(self, ifname): |     def getInterface(self, ifname): | ||||||
|         return self.interfaces[ifname] |         return self.interfaces[ifname] | ||||||
| 
 | 
 | ||||||
|  | @ -427,10 +634,14 @@ class Descriptor(DescriptorProvider): | ||||||
|     Represents a single descriptor for an interface. See Bindings.conf. |     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) |         DescriptorProvider.__init__(self) | ||||||
|         self.config = config |         self.config = config | ||||||
|         self.interface = interface |         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() |         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.
 |   // hopefully it's all temporary until we sort out the EME bits.
 | ||||||
|   friend class dom::Promise; |   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: |  private: | ||||||
| #ifdef DEBUG | #ifdef DEBUG | ||||||
|   enum UnionState { |   enum UnionState { | ||||||
|  | @ -567,11 +572,6 @@ class TErrorResult { | ||||||
|   // touching the union anymore.
 |   // touching the union anymore.
 | ||||||
|   void ClearUnionData(); |   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
 |   // Methods for setting various specific kinds of pending exceptions.  See
 | ||||||
|   // documentation of MaybeSetPendingException for the "context" argument.
 |   // documentation of MaybeSetPendingException for the "context" argument.
 | ||||||
|   void SetPendingExceptionWithMessage(JSContext* cx, const char* context); |   void SetPendingExceptionWithMessage(JSContext* cx, const char* context); | ||||||
|  | @ -828,13 +828,47 @@ class CopyableErrorResult | ||||||
| inline ErrorResult::ErrorResult(CopyableErrorResult&& aRHS) | inline ErrorResult::ErrorResult(CopyableErrorResult&& aRHS) | ||||||
|     : ErrorResult(reinterpret_cast<ErrorResult&&>(aRHS)) {} |     : ErrorResult(reinterpret_cast<ErrorResult&&>(aRHS)) {} | ||||||
| 
 | 
 | ||||||
| namespace dom { | namespace dom::binding_detail { | ||||||
| namespace 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< | class FastErrorResult : public mozilla::binding_danger::TErrorResult< | ||||||
|                             mozilla::binding_danger::JustAssertCleanupPolicy> { |                             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:
 | // 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. |                 # We already added this as a BindingAlias for the original prop. | ||||||
|                 continue |                 continue | ||||||
| 
 | 
 | ||||||
|  |             propId = p.prop_id | ||||||
|  |         else: | ||||||
|  |             propId = p.id | ||||||
|         # Unfortunately, even some of the getters here are fallible |         # Unfortunately, even some of the getters here are fallible | ||||||
|         # (e.g. on nsComputedDOMStyle). |         # (e.g. on nsComputedDOMStyle). | ||||||
|         extendedAttrs = [ |         extendedAttrs = [ | ||||||
|  |             "BindingTemplate=(CSS2Property, eCSSProperty_%s)" % propId, | ||||||
|             "CEReactions", |             "CEReactions", | ||||||
|             "Throws", |             "Throws", | ||||||
|             "SetterNeedsSubjectPrincipal=NonSystem", |             "SetterNeedsSubjectPrincipal=NonSystem", | ||||||
|  |  | ||||||
|  | @ -5725,6 +5725,7 @@ class IDLAttribute(IDLInterfaceMember): | ||||||
|             or identifier == "ReturnValueNeedsContainsHack" |             or identifier == "ReturnValueNeedsContainsHack" | ||||||
|             or identifier == "BinaryName" |             or identifier == "BinaryName" | ||||||
|             or identifier == "NonEnumerable" |             or identifier == "NonEnumerable" | ||||||
|  |             or identifier == "BindingTemplate" | ||||||
|         ): |         ): | ||||||
|             # Known attributes that we don't need to do anything with here |             # Known attributes that we don't need to do anything with here | ||||||
|             pass |             pass | ||||||
|  | @ -5735,6 +5736,9 @@ class IDLAttribute(IDLInterfaceMember): | ||||||
|             ) |             ) | ||||||
|         IDLInterfaceMember.handleExtendedAttribute(self, attr) |         IDLInterfaceMember.handleExtendedAttribute(self, attr) | ||||||
| 
 | 
 | ||||||
|  |     def getExtendedAttributes(self): | ||||||
|  |         return self._extendedAttrDict | ||||||
|  | 
 | ||||||
|     def resolve(self, parentScope): |     def resolve(self, parentScope): | ||||||
|         assert isinstance(parentScope, IDLScope) |         assert isinstance(parentScope, IDLScope) | ||||||
|         self.type.resolveType(parentScope) |         self.type.resolveType(parentScope) | ||||||
|  |  | ||||||
|  | @ -1390,6 +1390,25 @@ implementing `MyInterface`. | ||||||
| Multiple `[BindingAlias]` extended attributes can be used on a single | Multiple `[BindingAlias]` extended attributes can be used on a single | ||||||
| attribute. | 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]` | ### `[ChromeOnly]` | ||||||
| 
 | 
 | ||||||
| This extended attribute can be specified on any method, attribute, or | 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, |   virtual nsresult GetPropertyValue(const nsCSSPropertyID aPropID, | ||||||
|                                     nsACString& aValue); |                                     nsACString& aValue); | ||||||
|  |   void GetPropertyValue(const nsCSSPropertyID aPropID, nsACString& aValue, | ||||||
|  |                         mozilla::ErrorResult& aRv) { | ||||||
|  |     aRv = GetPropertyValue(aPropID, aValue); | ||||||
|  |   } | ||||||
| 
 | 
 | ||||||
|   /**
 |   /**
 | ||||||
|    * Method analogous to CSSStyleDeclaration::SetProperty.  This |    * Method analogous to CSSStyleDeclaration::SetProperty.  This | ||||||
|  | @ -93,32 +97,6 @@ class nsDOMCSSDeclaration : public nsICSSDeclaration { | ||||||
|   uint32_t Length() override; |   uint32_t Length() override; | ||||||
| 
 | 
 | ||||||
|   // WebIDL interface for CSS2Properties
 |   // 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, |   virtual void IndexedGetter(uint32_t aIndex, bool& aFound, | ||||||
|                              nsACString& aPropName) override; |                              nsACString& aPropName) override; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Peter Van der Beken
						Peter Van der Beken