Update to latest Mozilla SpecialPowers code for Proxy.create
This fixes the "Proxy.create is not a function" errors during PDF metadata retrieval in Firefox 48 after the old Proxy API removal, but it still throws "doc.location is null". Addresses #1076
This commit is contained in:
parent
a0571a9a17
commit
a0843f3171
1 changed files with 181 additions and 248 deletions
|
@ -37,10 +37,12 @@ const BOMs = {
|
||||||
Components.utils.import("resource://gre/modules/NetUtil.jsm");
|
Components.utils.import("resource://gre/modules/NetUtil.jsm");
|
||||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||||
|
|
||||||
Zotero.Translate.DOMWrapper = new function() {
|
Zotero.Translate.DOMWrapper = new function() {
|
||||||
|
var Cu = Components.utils;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* BEGIN SPECIAL POWERS WRAPPING CODE
|
* BEGIN SPECIAL POWERS WRAPPING CODE
|
||||||
* https://mxr.mozilla.org/mozilla-central/source/testing/mochitest/tests/SimpleTest/specialpowersAPI.js?raw=1
|
* https://dxr.mozilla.org/mozilla-central/source/testing/specialpowers/content/specialpowersAPI.js
|
||||||
*/
|
*/
|
||||||
function isWrappable(x) {
|
function isWrappable(x) {
|
||||||
if (typeof x === "object")
|
if (typeof x === "object")
|
||||||
|
@ -49,30 +51,75 @@ Zotero.Translate.DOMWrapper = new function() {
|
||||||
};
|
};
|
||||||
|
|
||||||
function isWrapper(x) {
|
function isWrapper(x) {
|
||||||
return isWrappable(x) && (typeof x.__wrappedObject !== "undefined");
|
return isWrappable(x) && (typeof x.SpecialPowers_wrappedObject !== "undefined");
|
||||||
};
|
};
|
||||||
|
|
||||||
function unwrapIfWrapped(x) {
|
function unwrapIfWrapped(x) {
|
||||||
return isWrapper(x) ? unwrapPrivileged(x) : x;
|
return isWrapper(x) ? unwrapPrivileged(x) : x;
|
||||||
};
|
};
|
||||||
|
|
||||||
function isXrayWrapper(x) {
|
function wrapIfUnwrapped(x) {
|
||||||
try {
|
return isWrapper(x) ? x : wrapPrivileged(x);
|
||||||
return x.toString().indexOf("XrayWrapper") !== -1;
|
}
|
||||||
} catch(e) {
|
|
||||||
// The toString() implementation could theoretically throw. But it never
|
function isObjectOrArray(obj) {
|
||||||
// throws for Xray, so we can just assume non-xray in that case.
|
if (Object(obj) !== obj)
|
||||||
return false;
|
return false;
|
||||||
}
|
let arrayClasses = ['Object', 'Array', 'Int8Array', 'Uint8Array',
|
||||||
|
'Int16Array', 'Uint16Array', 'Int32Array',
|
||||||
|
'Uint32Array', 'Float32Array', 'Float64Array',
|
||||||
|
'Uint8ClampedArray'];
|
||||||
|
let className = Cu.getClassName(obj, true);
|
||||||
|
return arrayClasses.indexOf(className) != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// In general, we want Xray wrappers for content DOM objects, because waiving
|
||||||
|
// Xray gives us Xray waiver wrappers that clamp the principal when we cross
|
||||||
|
// compartment boundaries. However, there are some exceptions where we want
|
||||||
|
// to use a waiver:
|
||||||
|
//
|
||||||
|
// * Xray adds some gunk to toString(), which has the potential to confuse
|
||||||
|
// consumers that aren't expecting Xray wrappers. Since toString() is a
|
||||||
|
// non-privileged method that returns only strings, we can just waive Xray
|
||||||
|
// for that case.
|
||||||
|
//
|
||||||
|
// * We implement Xrays to pure JS [[Object]] and [[Array]] instances that
|
||||||
|
// filter out tricky things like callables. This is the right thing for
|
||||||
|
// security in general, but tends to break tests that try to pass object
|
||||||
|
// literals into SpecialPowers. So we waive [[Object]] and [[Array]]
|
||||||
|
// instances before inspecting properties.
|
||||||
|
//
|
||||||
|
// * When we don't have meaningful Xray semantics, we create an Opaque
|
||||||
|
// XrayWrapper for security reasons. For test code, we generally want to see
|
||||||
|
// through that sort of thing.
|
||||||
|
function waiveXraysIfAppropriate(obj, propName) {
|
||||||
|
if (propName == 'toString' || isObjectOrArray(obj) ||
|
||||||
|
/Opaque/.test(Object.prototype.toString.call(obj)))
|
||||||
|
{
|
||||||
|
return XPCNativeWrapper.unwrap(obj);
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We can't call apply() directy on Xray-wrapped functions, so we have to be
|
// We can't call apply() directy on Xray-wrapped functions, so we have to be
|
||||||
// clever.
|
// clever.
|
||||||
function doApply(fun, invocant, args) {
|
function doApply(fun, invocant, args) {
|
||||||
return Function.prototype.apply.call(fun, invocant, args);
|
// We implement Xrays to pure JS [[Object]] instances that filter out tricky
|
||||||
|
// things like callables. This is the right thing for security in general,
|
||||||
|
// but tends to break tests that try to pass object literals into
|
||||||
|
// SpecialPowers. So we waive [[Object]] instances when they're passed to a
|
||||||
|
// SpecialPowers-wrapped callable.
|
||||||
|
//
|
||||||
|
// Note that the transitive nature of Xray waivers means that any property
|
||||||
|
// pulled off such an object will also be waived, and so we'll get principal
|
||||||
|
// clamping for Xrayed DOM objects reached from literals, so passing things
|
||||||
|
// like {l : xoWin.location} won't work. Hopefully the rabbit hole doesn't
|
||||||
|
// go that deep.
|
||||||
|
args = args.map(x => isObjectOrArray(x) ? Cu.waiveXrays(x) : x);
|
||||||
|
return Reflect.apply(fun, invocant, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
function wrapPrivileged(obj, overrides) {
|
function wrapPrivileged(obj) {
|
||||||
|
|
||||||
// Primitives pass straight through.
|
// Primitives pass straight through.
|
||||||
if (!isWrappable(obj))
|
if (!isWrappable(obj))
|
||||||
|
@ -82,38 +129,13 @@ Zotero.Translate.DOMWrapper = new function() {
|
||||||
if (isWrapper(obj))
|
if (isWrapper(obj))
|
||||||
throw "Trying to double-wrap object!";
|
throw "Trying to double-wrap object!";
|
||||||
|
|
||||||
// Make our core wrapper object.
|
let dummy;
|
||||||
var handler = new SpecialPowersHandler(obj, overrides);
|
if (typeof obj === "function")
|
||||||
|
dummy = function() {};
|
||||||
|
else
|
||||||
|
dummy = Object.create(null);
|
||||||
|
|
||||||
// If the object is callable, make a function proxy.
|
return new Proxy(dummy, new SpecialPowersHandler(obj));
|
||||||
if (typeof obj === "function") {
|
|
||||||
var callTrap = function() {
|
|
||||||
// The invocant and arguments may or may not be wrappers. Unwrap them if necessary.
|
|
||||||
var invocant = unwrapIfWrapped(this);
|
|
||||||
var unwrappedArgs = Array.prototype.slice.call(arguments).map(unwrapIfWrapped);
|
|
||||||
|
|
||||||
return wrapPrivileged(doApply(obj, invocant, unwrappedArgs));
|
|
||||||
};
|
|
||||||
var constructTrap = function() {
|
|
||||||
// The arguments may or may not be wrappers. Unwrap them if necessary.
|
|
||||||
var unwrappedArgs = Array.prototype.slice.call(arguments).map(unwrapIfWrapped);
|
|
||||||
|
|
||||||
// Constructors are tricky, because we can't easily call apply on them.
|
|
||||||
// As a workaround, we create a wrapper constructor with the same
|
|
||||||
// |prototype| property.
|
|
||||||
var FakeConstructor = function() {
|
|
||||||
doApply(obj, this, unwrappedArgs);
|
|
||||||
};
|
|
||||||
FakeConstructor.prototype = obj.prototype;
|
|
||||||
|
|
||||||
return wrapPrivileged(new FakeConstructor());
|
|
||||||
};
|
|
||||||
|
|
||||||
return Proxy.createFunction(handler, callTrap, constructTrap);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, just make a regular object proxy.
|
|
||||||
return Proxy.create(handler);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function unwrapPrivileged(x) {
|
function unwrapPrivileged(x) {
|
||||||
|
@ -129,219 +151,130 @@ Zotero.Translate.DOMWrapper = new function() {
|
||||||
if (!isWrapper(x))
|
if (!isWrapper(x))
|
||||||
throw "Trying to unwrap a non-wrapped object!";
|
throw "Trying to unwrap a non-wrapped object!";
|
||||||
|
|
||||||
// Unwrap.
|
var obj = x.SpecialPowers_wrappedObject;
|
||||||
return x.__wrappedObject;
|
// unwrapped.
|
||||||
|
return obj;
|
||||||
};
|
};
|
||||||
|
|
||||||
function crawlProtoChain(obj, fn) {
|
function SpecialPowersHandler(wrappedObject) {
|
||||||
var rv = fn(obj);
|
this.wrappedObject = wrappedObject;
|
||||||
if (rv !== undefined)
|
|
||||||
return rv;
|
|
||||||
if (Object.getPrototypeOf(obj))
|
|
||||||
return crawlProtoChain(Object.getPrototypeOf(obj), fn);
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We want to waive the __exposedProps__ security check for SpecialPowers-wrapped
|
|
||||||
* objects. We do this by creating a proxy singleton that just always returns 'rw'
|
|
||||||
* for any property name.
|
|
||||||
*/
|
|
||||||
function ExposedPropsWaiverHandler() {
|
|
||||||
// NB: XPConnect denies access if the relevant member of __exposedProps__ is not
|
|
||||||
// enumerable.
|
|
||||||
var _permit = { value: 'rw', writable: false, configurable: false, enumerable: true };
|
|
||||||
return {
|
|
||||||
getOwnPropertyDescriptor: function(name) { return _permit; },
|
|
||||||
ownKeys: function() { throw Error("Can't enumerate ExposedPropsWaiver"); },
|
|
||||||
enumerate: function() { throw Error("Can't enumerate ExposedPropsWaiver"); },
|
|
||||||
defineProperty: function(name) { throw Error("Can't define props on ExposedPropsWaiver"); },
|
|
||||||
deleteProperty: function(name) { throw Error("Can't delete props from ExposedPropsWaiver"); }
|
|
||||||
};
|
|
||||||
};
|
|
||||||
ExposedPropsWaiver = new Proxy({}, ExposedPropsWaiverHandler());
|
|
||||||
|
|
||||||
function SpecialPowersHandler(obj, overrides) {
|
|
||||||
this.wrappedObject = obj;
|
|
||||||
this.overrides = overrides ? overrides : {};
|
|
||||||
};
|
|
||||||
|
|
||||||
// Allow us to transitively maintain the membrane by wrapping descriptors
|
|
||||||
// we return.
|
|
||||||
SpecialPowersHandler.prototype.doGetPropertyDescriptor = function(name, own) {
|
|
||||||
|
|
||||||
// Handle our special API.
|
|
||||||
if (name == "__wrappedObject")
|
|
||||||
return { value: this.wrappedObject, writeable: false, configurable: false, enumerable: false };
|
|
||||||
if (name == "__wrapperOverrides")
|
|
||||||
return { value: this.overrides, writeable: false, configurable: false, enumerable: false };
|
|
||||||
// Handle __exposedProps__.
|
|
||||||
if (name == "__exposedProps__")
|
|
||||||
return { value: ExposedPropsWaiver, writable: false, configurable: false, enumerable: false };
|
|
||||||
|
|
||||||
// In general, we want Xray wrappers for content DOM objects, because waiving
|
|
||||||
// Xray gives us Xray waiver wrappers that clamp the principal when we cross
|
|
||||||
// compartment boundaries. However, Xray adds some gunk to toString(), which
|
|
||||||
// has the potential to confuse consumers that aren't expecting Xray wrappers.
|
|
||||||
// Since toString() is a non-privileged method that returns only strings, we
|
|
||||||
// can just waive Xray for that case.
|
|
||||||
var obj = name == 'toString' ? XPCNativeWrapper.unwrap(this.wrappedObject)
|
|
||||||
: this.wrappedObject;
|
|
||||||
|
|
||||||
//
|
|
||||||
// Call through to the wrapped object.
|
|
||||||
//
|
|
||||||
// Note that we have several cases here, each of which requires special handling.
|
|
||||||
//
|
|
||||||
var desc;
|
|
||||||
|
|
||||||
// Hack for overriding some properties
|
|
||||||
if (this.overrides.hasOwnProperty(name))
|
|
||||||
return { "enumerable": true, "value": this.overrides[name] };
|
|
||||||
// Case 1: Own Properties.
|
|
||||||
//
|
|
||||||
// This one is easy, thanks to Object.getOwnPropertyDescriptor().
|
|
||||||
else if (own)
|
|
||||||
desc = Object.getOwnPropertyDescriptor(obj, name);
|
|
||||||
|
|
||||||
// Case 2: Not own, not Xray-wrapped.
|
|
||||||
//
|
|
||||||
// Here, we can just crawl the prototype chain, calling
|
|
||||||
// Object.getOwnPropertyDescriptor until we find what we want.
|
|
||||||
//
|
|
||||||
// NB: Make sure to check this.wrappedObject here, rather than obj, because
|
|
||||||
// we may have waived Xray on obj above.
|
|
||||||
else if (!isXrayWrapper(this.wrappedObject))
|
|
||||||
try {
|
|
||||||
desc = crawlProtoChain(obj, function(o) {return Object.getOwnPropertyDescriptor(o, name);});
|
|
||||||
} catch(e) {
|
|
||||||
// we hit bug 560072 if DOM is not wrapped
|
|
||||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=560072
|
|
||||||
if (name in obj) {
|
|
||||||
// same guess as below
|
|
||||||
desc = {value: obj[name], writable: false, configurable: true, enumerable: true};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Case 3: Not own, Xray-wrapped.
|
|
||||||
//
|
|
||||||
// This one is harder, because we Xray wrappers are flattened and don't have
|
|
||||||
// a prototype. Xray wrappers are proxies themselves, so we'd love to just call
|
|
||||||
// through to XrayWrapper<Base>::getPropertyDescriptor(). Unfortunately though,
|
|
||||||
// we don't have any way to do that. :-(
|
|
||||||
//
|
|
||||||
// So we first try with a call to getOwnPropertyDescriptor(). If that fails,
|
|
||||||
// we make up a descriptor, using some assumptions about what kinds of things
|
|
||||||
// tend to live on the prototypes of Xray-wrapped objects.
|
|
||||||
else {
|
|
||||||
desc = Object.getOwnPropertyDescriptor(obj, name);
|
|
||||||
if (!desc) {
|
|
||||||
var getter = Object.prototype.__lookupGetter__.call(obj, name);
|
|
||||||
var setter = Object.prototype.__lookupSetter__.call(obj, name);
|
|
||||||
if (getter || setter)
|
|
||||||
desc = {get: getter, set: setter, configurable: true, enumerable: true};
|
|
||||||
else if (name in obj)
|
|
||||||
desc = {value: obj[name], writable: false, configurable: true, enumerable: true};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bail if we've got nothing.
|
|
||||||
if (typeof desc === 'undefined')
|
|
||||||
return undefined;
|
|
||||||
|
|
||||||
// When accessors are implemented as JSPropertyOps rather than JSNatives (ie,
|
|
||||||
// QuickStubs), the js engine does the wrong thing and treats it as a value
|
|
||||||
// descriptor rather than an accessor descriptor. Jorendorff suggested this
|
|
||||||
// little hack to work around it. See bug 520882.
|
|
||||||
if (desc && 'value' in desc && desc.value === undefined)
|
|
||||||
desc.value = obj[name];
|
|
||||||
|
|
||||||
// A trapping proxy's properties must always be configurable, but sometimes
|
|
||||||
// this we get non-configurable properties from Object.getOwnPropertyDescriptor().
|
|
||||||
// Tell a white lie.
|
|
||||||
desc.configurable = true;
|
|
||||||
|
|
||||||
// Transitively maintain the wrapper membrane.
|
|
||||||
function wrapIfExists(key) { if (key in desc) desc[key] = wrapPrivileged(desc[key]); };
|
|
||||||
wrapIfExists('value');
|
|
||||||
wrapIfExists('get');
|
|
||||||
wrapIfExists('set');
|
|
||||||
|
|
||||||
return desc;
|
|
||||||
};
|
|
||||||
|
|
||||||
SpecialPowersHandler.prototype.getOwnPropertyDescriptor = function(name) {
|
|
||||||
return this.doGetPropertyDescriptor(name, true);
|
|
||||||
};
|
|
||||||
|
|
||||||
SpecialPowersHandler.prototype.getPropertyDescriptor = function(name) {
|
|
||||||
return this.doGetPropertyDescriptor(name, false);
|
|
||||||
};
|
|
||||||
|
|
||||||
function doGetOwnPropertyNames(obj, props) {
|
|
||||||
|
|
||||||
// Insert our special API. It's not enumerable, but getPropertyNames()
|
|
||||||
// includes non-enumerable properties.
|
|
||||||
var specialAPI = '__wrappedObject';
|
|
||||||
if (props.indexOf(specialAPI) == -1)
|
|
||||||
props.push(specialAPI);
|
|
||||||
|
|
||||||
|
|
||||||
// Do the normal thing.
|
|
||||||
var flt = function(a) { return props.indexOf(a) == -1; };
|
|
||||||
props = props.concat(Object.getOwnPropertyNames(obj).filter(flt));
|
|
||||||
|
|
||||||
// If we've got an Xray wrapper, include the expandos as well.
|
|
||||||
if ('wrappedJSObject' in obj)
|
|
||||||
props = props.concat(Object.getOwnPropertyNames(obj.wrappedJSObject)
|
|
||||||
.filter(flt));
|
|
||||||
|
|
||||||
return props;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SpecialPowersHandler.prototype.getOwnPropertyNames = function() {
|
SpecialPowersHandler.prototype = {
|
||||||
return doGetOwnPropertyNames(this.wrappedObject, []);
|
construct(target, args) {
|
||||||
};
|
// The arguments may or may not be wrappers. Unwrap them if necessary.
|
||||||
|
var unwrappedArgs = Array.prototype.slice.call(args).map(unwrapIfWrapped);
|
||||||
|
|
||||||
SpecialPowersHandler.prototype.getPropertyNames = function() {
|
// We want to invoke "obj" as a constructor, but using unwrappedArgs as
|
||||||
|
// the arguments. Make sure to wrap and re-throw exceptions!
|
||||||
|
try {
|
||||||
|
return wrapIfUnwrapped(Reflect.construct(this.wrappedObject, unwrappedArgs));
|
||||||
|
} catch (e) {
|
||||||
|
throw wrapIfUnwrapped(e);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
// Manually walk the prototype chain, making sure to add only property names
|
apply(target, thisValue, args) {
|
||||||
// that haven't been overridden.
|
// The invocant and arguments may or may not be wrappers. Unwrap
|
||||||
//
|
// them if necessary.
|
||||||
// There's some trickiness here with Xray wrappers. Xray wrappers don't have
|
var invocant = unwrapIfWrapped(thisValue);
|
||||||
// a prototype, so we need to unwrap them if we want to get all of the names
|
var unwrappedArgs = Array.prototype.slice.call(args).map(unwrapIfWrapped);
|
||||||
// with Object.getOwnPropertyNames(). But we don't really want to unwrap the
|
|
||||||
// base object, because that will include expandos that are inaccessible via
|
try {
|
||||||
// our implementation of get{,Own}PropertyDescriptor(). So we unwrap just
|
return wrapIfUnwrapped(doApply(this.wrappedObject, invocant, unwrappedArgs));
|
||||||
// before accessing the prototype. This ensures that we get Xray vision on
|
} catch (e) {
|
||||||
// the base object, and no Xray vision for the rest of the way up.
|
// Wrap exceptions and re-throw them.
|
||||||
var obj = this.wrappedObject;
|
throw wrapIfUnwrapped(e);
|
||||||
var props = [];
|
}
|
||||||
props = doGetOwnPropertyNames(this.overrides, props);
|
},
|
||||||
while (obj) {
|
|
||||||
props = doGetOwnPropertyNames(obj, props);
|
has(target, prop) {
|
||||||
obj = Object.getPrototypeOf(XPCNativeWrapper.unwrap(obj));
|
if (prop === "SpecialPowers_wrappedObject")
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return Reflect.has(this.wrappedObject, prop);
|
||||||
|
},
|
||||||
|
|
||||||
|
get(target, prop, receiver) {
|
||||||
|
if (prop === "SpecialPowers_wrappedObject")
|
||||||
|
return this.wrappedObject;
|
||||||
|
|
||||||
|
let obj = waiveXraysIfAppropriate(this.wrappedObject, prop);
|
||||||
|
return wrapIfUnwrapped(Reflect.get(obj, prop));
|
||||||
|
},
|
||||||
|
|
||||||
|
set(target, prop, val, receiver) {
|
||||||
|
if (prop === "SpecialPowers_wrappedObject")
|
||||||
|
return false;
|
||||||
|
|
||||||
|
let obj = waiveXraysIfAppropriate(this.wrappedObject, prop);
|
||||||
|
return Reflect.set(obj, prop, unwrapIfWrapped(val));
|
||||||
|
},
|
||||||
|
|
||||||
|
delete(target, prop) {
|
||||||
|
if (prop === "SpecialPowers_wrappedObject")
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return Reflect.deleteProperty(this.wrappedObject, prop);
|
||||||
|
},
|
||||||
|
|
||||||
|
defineProperty(target, prop, descriptor) {
|
||||||
|
throw "Can't call defineProperty on SpecialPowers wrapped object";
|
||||||
|
},
|
||||||
|
|
||||||
|
getOwnPropertyDescriptor(target, prop) {
|
||||||
|
// Handle our special API.
|
||||||
|
if (prop === "SpecialPowers_wrappedObject") {
|
||||||
|
return { value: this.wrappedObject, writeable: true,
|
||||||
|
configurable: true, enumerable: false };
|
||||||
|
}
|
||||||
|
|
||||||
|
let obj = waiveXraysIfAppropriate(this.wrappedObject, prop);
|
||||||
|
let desc = Reflect.getOwnPropertyDescriptor(obj, prop);
|
||||||
|
|
||||||
|
if (desc === undefined)
|
||||||
|
return undefined;
|
||||||
|
|
||||||
|
// Transitively maintain the wrapper membrane.
|
||||||
|
function wrapIfExists(key) {
|
||||||
|
if (key in desc)
|
||||||
|
desc[key] = wrapIfUnwrapped(desc[key]);
|
||||||
|
};
|
||||||
|
|
||||||
|
wrapIfExists('value');
|
||||||
|
wrapIfExists('get');
|
||||||
|
wrapIfExists('set');
|
||||||
|
|
||||||
|
// A trapping proxy's properties must always be configurable, but sometimes
|
||||||
|
// we come across non-configurable properties. Tell a white lie.
|
||||||
|
desc.configurable = true;
|
||||||
|
|
||||||
|
return desc;
|
||||||
|
},
|
||||||
|
|
||||||
|
ownKeys(target) {
|
||||||
|
// Insert our special API. It's not enumerable, but ownKeys()
|
||||||
|
// includes non-enumerable properties.
|
||||||
|
let props = ['SpecialPowers_wrappedObject'];
|
||||||
|
|
||||||
|
// Do the normal thing.
|
||||||
|
let flt = (a) => !props.includes(a);
|
||||||
|
props = props.concat(Reflect.ownKeys(this.wrappedObject).filter(flt));
|
||||||
|
|
||||||
|
// If we've got an Xray wrapper, include the expandos as well.
|
||||||
|
if ('wrappedJSObject' in this.wrappedObject) {
|
||||||
|
props = props.concat(Reflect.ownKeys(this.wrappedObject.wrappedJSObject)
|
||||||
|
.filter(flt));
|
||||||
|
}
|
||||||
|
|
||||||
|
return props;
|
||||||
|
},
|
||||||
|
|
||||||
|
preventExtensions(target) {
|
||||||
|
throw "Can't call preventExtensions on SpecialPowers wrapped object";
|
||||||
}
|
}
|
||||||
return props;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
SpecialPowersHandler.prototype.defineProperty = function(name, desc) {
|
|
||||||
return Object.defineProperty(this.wrappedObject, name, desc);
|
|
||||||
};
|
|
||||||
|
|
||||||
SpecialPowersHandler.prototype.delete = function(name) {
|
|
||||||
return delete this.wrappedObject[name];
|
|
||||||
};
|
|
||||||
|
|
||||||
SpecialPowersHandler.prototype.fix = function() { return undefined; /* Throws a TypeError. */ };
|
|
||||||
|
|
||||||
// Per the ES5 spec this is a derived trap, but it's fundamental in spidermonkey
|
|
||||||
// for some reason. See bug 665198.
|
|
||||||
SpecialPowersHandler.prototype.enumerate = function() {
|
|
||||||
var t = this;
|
|
||||||
var filt = function(name) { return t.getPropertyDescriptor(name).enumerable; };
|
|
||||||
return this.getPropertyNames().filter(filt);
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* END SPECIAL POWERS WRAPPING CODE
|
* END SPECIAL POWERS WRAPPING CODE
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in a new issue