Bug 1309970. Add a way to return frozen arrays to chrome callers with a .contains defined on them, returning the same value as .includes. r=qdot

This commit is contained in:
Boris Zbarsky 2016-10-13 22:14:26 -04:00
parent a1e3490680
commit e158454b4e
4 changed files with 37 additions and 2 deletions

View File

@ -7205,6 +7205,10 @@ def wrapArgIntoCurrentCompartment(arg, value, isMember=True):
return wrap
def needsContainsHack(m):
return m.getExtendedAttribute("ReturnValueNeedsContainsHack")
class CGPerSignatureCall(CGThing):
"""
This class handles the guts of generating code for a particular
@ -7578,6 +7582,22 @@ class CGPerSignatureCall(CGThing):
# the compartment we do our conversion in but after we've finished
# the initial conversion into args.rval().
postConversionSteps = ""
if needsContainsHack(self.idlNode):
# Define a .contains on the object that has the same value as
# .includes; needed for backwards compat in extensions as we
# migrate some DOMStringLists to FrozenArray.
postConversionSteps += dedent(
"""
if (args.rval().isObject() && nsContentUtils::ThreadsafeIsCallerChrome()) {
JS::Rooted<JSObject*> rvalObj(cx, &args.rval().toObject());
JS::Rooted<JS::Value> includesVal(cx);
if (!JS_GetProperty(cx, rvalObj, "includes", &includesVal) ||
!JS_DefineProperty(cx, rvalObj, "contains", includesVal, JSPROP_ENUMERATE)) {
return false;
}
}
""")
if self.idlNode.getExtendedAttribute("Frozen"):
assert self.idlNode.type.isSequence() or self.idlNode.type.isDictionary()
freezeValue = CGGeneric(
@ -13568,7 +13588,8 @@ class CGBindingRoot(CGThing):
def descriptorHasChromeOnly(desc):
ctor = desc.interface.ctor()
return (any(isChromeOnly(a) for a in desc.interface.members) or
return (any(isChromeOnly(a) or needsContainsHack(a)
for a in desc.interface.members) or
desc.interface.getExtendedAttribute("ChromeOnly") is not None or
# JS-implemented interfaces with an interface object get a
# chromeonly _create method. And interfaces with an

View File

@ -4213,6 +4213,7 @@ class IDLAttribute(IDLInterfaceMember):
identifier == "NewObject" or
identifier == "UnsafeInPrerendering" or
identifier == "NeedsSubjectPrincipal" or
identifier == "ReturnValueNeedsContainsHack" or
identifier == "BinaryName"):
# Known attributes that we don't need to do anything with here
pass

View File

@ -184,6 +184,17 @@ function test()
isnot(languages1, languages2.wrappedJSObject,
"Must have distinct arrays no matter how we slice it");
// Check that DataTransfer's .types has the hack to alias contains()
// to includes().
var dataTransfer = new win.DataTransfer("foo", true);
is(dataTransfer.types.contains, dataTransfer.types.includes,
"Should have contains() set up as an alias to includes()");
// Waive Xrays on the dataTransfer itself, since the .types we get is
// different over Xrays vs not.
is(dataTransfer.wrappedJSObject.types.contains, undefined,
"Underlying object should not have contains() set up as an alias to " +
"includes()");
SimpleTest.finish();
}

View File

@ -17,7 +17,9 @@ interface DataTransfer {
[Throws]
void setDragImage(Element image, long x, long y);
[Pure, Cached, Frozen, NeedsSubjectPrincipal]
// ReturnValueNeedsContainsHack on .types because lots of extension
// code was expecting .contains() back when it was a DOMStringList.
[Pure, Cached, Frozen, NeedsSubjectPrincipal, ReturnValueNeedsContainsHack]
readonly attribute sequence<DOMString> types;
[Throws, NeedsSubjectPrincipal]
DOMString getData(DOMString format);