diff --git a/dom/base/nsDeprecatedOperationList.h b/dom/base/nsDeprecatedOperationList.h index 5a86484b0701..65b20fed82eb 100644 --- a/dom/base/nsDeprecatedOperationList.h +++ b/dom/base/nsDeprecatedOperationList.h @@ -44,3 +44,4 @@ DEPRECATED_OPERATION(NavigatorGetUserMedia) DEPRECATED_OPERATION(WebrtcDeprecatedPrefix) DEPRECATED_OPERATION(AppCache) DEPRECATED_OPERATION(PrefixedFullscreenAPI) +DEPRECATED_OPERATION(LenientSetter) diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 2f3086cc1aa9..f5628683d42d 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -2548,7 +2548,8 @@ class AttrDefiner(PropertyDefiner): def setter(attr): if (attr.readonly and attr.getExtendedAttribute("PutForwards") is None and - attr.getExtendedAttribute("Replaceable") is None): + attr.getExtendedAttribute("Replaceable") is None and + attr.getExtendedAttribute("LenientSetter") is None): return "JSNATIVE_WRAPPER(nullptr)" if self.static: accessor = 'set_' + IDLToCIdentifier(attr.identifier.name) @@ -8832,6 +8833,24 @@ class CGSpecializedReplaceableSetter(CGSpecializedSetter): attrName) +class CGSpecializedLenientSetter(CGSpecializedSetter): + """ + A class for generating the code for a specialized attribute setter with + LenientSetter that the JIT can call with lower overhead. + """ + def __init__(self, descriptor, attr): + CGSpecializedSetter.__init__(self, descriptor, attr) + + def definition_body(self): + attrName = self.attr.identifier.name + # JS_DefineProperty can only deal with ASCII + assert all(ord(c) < 128 for c in attrName) + return dedent(""" + DeprecationWarning(cx, obj, nsIDocument::eLenientSetter); + return true; + """) + + def memberReturnsNewObject(member): return member.getExtendedAttribute("NewObject") is not None @@ -8969,7 +8988,8 @@ class CGMemberJITInfo(CGThing): [self.member.type], None) if (not self.member.readonly or self.member.getExtendedAttribute("PutForwards") is not None or - self.member.getExtendedAttribute("Replaceable") is not None): + self.member.getExtendedAttribute("Replaceable") is not None or + self.member.getExtendedAttribute("LenientSetter") is not None): setterinfo = ("%s_setterinfo" % IDLToCIdentifier(self.member.identifier.name)) # Actually a JSJitSetterOp, but JSJitGetterOp is first in the @@ -11838,7 +11858,8 @@ def memberProperties(m, descriptor): props.isCrossOriginSetter = True elif descriptor.needsSpecialGenericOps(): props.isGenericSetter = True - elif m.getExtendedAttribute("Replaceable"): + elif (m.getExtendedAttribute("Replaceable") or + m.getExtendedAttribute("LenientSetter")): if descriptor.needsSpecialGenericOps(): props.isGenericSetter = True @@ -11950,6 +11971,8 @@ class CGDescriptor(CGThing): crossOriginSetters.add(m.identifier.name) elif m.getExtendedAttribute("Replaceable"): cgThings.append(CGSpecializedReplaceableSetter(descriptor, m)) + elif m.getExtendedAttribute("LenientSetter"): + cgThings.append(CGSpecializedLenientSetter(descriptor, m)) if (not m.isStatic() and descriptor.interface.hasInterfacePrototypeObject()): cgThings.append(CGMemberJITInfo(descriptor, m)) diff --git a/dom/bindings/parser/WebIDL.py b/dom/bindings/parser/WebIDL.py index 26cf1cb7bee8..115dd1a1f35c 100644 --- a/dom/bindings/parser/WebIDL.py +++ b/dom/bindings/parser/WebIDL.py @@ -4080,6 +4080,24 @@ class IDLAttribute(IDLInterfaceMember): raise WebIDLError("[PutForwards] and [Replaceable] can't both " "appear on the same attribute", [attr.location, self.location]) + elif identifier == "LenientSetter": + if not attr.noArguments(): + raise WebIDLError("[LenientSetter] must take no arguments", + [attr.location]) + if not self.readonly: + raise WebIDLError("[LenientSetter] is only allowed on readonly " + "attributes", [attr.location, self.location]) + if self.isStatic(): + raise WebIDLError("[LenientSetter] is only allowed on non-static " + "attributes", [attr.location, self.location]) + if self.getExtendedAttribute("PutForwards") is not None: + raise WebIDLError("[LenientSetter] and [PutForwards] can't both " + "appear on the same attribute", + [attr.location, self.location]) + if self.getExtendedAttribute("Replaceable") is not None: + raise WebIDLError("[LenientSetter] and [Replaceable] can't both " + "appear on the same attribute", + [attr.location, self.location]) elif identifier == "LenientFloat": if self.readonly: raise WebIDLError("[LenientFloat] used on a readonly attribute", @@ -4818,6 +4836,9 @@ class IDLMethod(IDLInterfaceMember, IDLScope): elif identifier == "PutForwards": raise WebIDLError("Only attributes support [PutForwards]", [attr.location, self.location]) + elif identifier == "LenientSetter": + raise WebIDLError("Only attributes support [LenientSetter]", + [attr.location, self.location]) elif identifier == "LenientFloat": # This is called before we've done overload resolution assert len(self.signatures()) == 1 diff --git a/dom/bindings/parser/tests/test_lenientSetter.py b/dom/bindings/parser/tests/test_lenientSetter.py new file mode 100644 index 000000000000..78a9ffe9eaa6 --- /dev/null +++ b/dom/bindings/parser/tests/test_lenientSetter.py @@ -0,0 +1,58 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +def should_throw(parser, harness, message, code): + parser = parser.reset(); + threw = False + try: + parser.parse(code) + parser.finish() + except: + threw = True + + harness.ok(threw, "Should have thrown: %s" % message) + + +def WebIDLTest(parser, harness): + # The [LenientSetter] extended attribute MUST take no arguments. + should_throw(parser, harness, "no arguments", """ + interface I { + [LenientSetter=X] readonly attribute long A; + }; + """) + + # An attribute with the [LenientSetter] extended attribute MUST NOT + # also be declared with the [PutForwards] extended attribute. + should_throw(parser, harness, "PutForwards", """ + interface I { + [PutForwards=B, LenientSetter] readonly attribute J A; + }; + interface J { + attribute long B; + }; + """) + + # An attribute with the [LenientSetter] extended attribute MUST NOT + # also be declared with the [Replaceable] extended attribute. + should_throw(parser, harness, "Replaceable", """ + interface I { + [Replaceable, LenientSetter] readonly attribute J A; + }; + """) + + # The [LenientSetter] extended attribute MUST NOT be used on an + # attribute that is not read only. + should_throw(parser, harness, "writable attribute", """ + interface I { + [LenientSetter] attribute long A; + }; + """) + + # The [LenientSetter] extended attribute MUST NOT be used on a + # static attribute. + should_throw(parser, harness, "static attribute", """ + interface I { + [LenientSetter] static readonly attribute long A; + }; + """)