Bug 843840 part 1. Add a way to ask DOM proxies with a named getter whether a property is enumerable or not and use that information in getOwnPropertyDescriptor. r=peterv

This commit is contained in:
Boris Zbarsky 2014-04-15 22:58:44 -04:00
parent cbc5d1a912
commit b730833389
22 changed files with 127 additions and 9 deletions

View File

@ -217,6 +217,12 @@ nsDOMAttributeMap::NamedGetter(const nsAString& aAttrName, bool& aFound)
return GetAttribute(ni, false);
}
bool
nsDOMAttributeMap::NameIsEnumerable(const nsAString& aName)
{
return true;
}
Attr*
nsDOMAttributeMap::GetNamedItem(const nsAString& aAttrName)
{

View File

@ -146,6 +146,7 @@ public:
// WebIDL
Attr* GetNamedItem(const nsAString& aAttrName);
Attr* NamedGetter(const nsAString& aAttrName, bool& aFound);
bool NameIsEnumerable(const nsAString& aName);
already_AddRefed<Attr>
SetNamedItem(Attr& aAttr, ErrorResult& aError)
{

View File

@ -69,6 +69,10 @@ public:
{
return GetFirstNamedElement(aName, aFound);
}
bool NameIsEnumerable(const nsAString& aName)
{
return false;
}
virtual mozilla::dom::Element*
GetFirstNamedElement(const nsAString& aName, bool& aFound) = 0;

View File

@ -1434,6 +1434,12 @@ HTMLFormElement::NamedGetter(const nsAString& aName, bool &aFound)
return nullptr;
}
bool
HTMLFormElement::NameIsEnumerable(const nsAString& aName)
{
return true;
}
void
HTMLFormElement::GetSupportedNames(nsTArray<nsString >& aRetval)
{

View File

@ -395,6 +395,8 @@ public:
already_AddRefed<nsISupports>
NamedGetter(const nsAString& aName, bool &aFound);
bool NameIsEnumerable(const nsAString& aName);
void GetSupportedNames(nsTArray<nsString >& aRetval);
static int32_t

View File

@ -86,6 +86,10 @@ public:
aFound = IsSupportedNamedProperty(aName);
return aFound ? NamedItem(aName) : nullptr;
}
bool NameIsEnumerable(const nsAString& aName)
{
return true;
}
DOMStringList* Names()
{
EnsureFresh();

View File

@ -91,6 +91,12 @@ nsDOMStringMap::NamedGetter(const nsAString& aProp, bool& found,
found = mElement->GetAttr(attr, aResult);
}
bool
nsDOMStringMap::NameIsEnumerable(const nsAString& aName)
{
return true;
}
void
nsDOMStringMap::NamedSetter(const nsAString& aProp,
const nsAString& aValue,

View File

@ -42,6 +42,7 @@ public:
void NamedSetter(const nsAString& aProp, const nsAString& aValue,
mozilla::ErrorResult& rv);
void NamedDeleter(const nsAString& aProp, bool &found);
bool NameIsEnumerable(const nsAString& aName);
void GetSupportedNames(nsTArray<nsString>& aNames);
js::ExpandoAndGeneration mExpandoAndGeneration;

View File

@ -2264,6 +2264,12 @@ nsHTMLDocument::NamedGetter(JSContext* cx, const nsAString& aName, bool& aFound,
return &val.toObject();
}
bool
nsHTMLDocument::NameIsEnumerable(const nsAString& aName)
{
return true;
}
static PLDHashOperator
IdentifierMapEntryAddNames(nsIdentifierMapEntry* aEntry, void* aArg)
{

View File

@ -174,6 +174,7 @@ public:
void SetCookie(const nsAString& aCookie, mozilla::ErrorResult& rv);
JSObject* NamedGetter(JSContext* cx, const nsAString& aName, bool& aFound,
mozilla::ErrorResult& rv);
bool NameIsEnumerable(const nsAString& aName);
void GetSupportedNames(nsTArray<nsString>& aNames);
nsGenericHTMLElement *GetBody();
void SetBody(nsGenericHTMLElement* aBody, mozilla::ErrorResult& rv);

View File

@ -173,6 +173,12 @@ nsMimeTypeArray::NamedGetter(const nsAString& aName, bool &aFound)
return mt;
}
bool
nsMimeTypeArray::NameIsEnumerable(const nsAString& aName)
{
return true;
}
uint32_t
nsMimeTypeArray::Length()
{

View File

@ -36,6 +36,7 @@ public:
nsMimeType* NamedItem(const nsAString& name);
nsMimeType* IndexedGetter(uint32_t index, bool &found);
nsMimeType* NamedGetter(const nsAString& name, bool &found);
bool NameIsEnumerable(const nsAString& name);
uint32_t Length();
void GetSupportedNames(nsTArray< nsString >& retval);

View File

@ -222,6 +222,12 @@ nsPluginArray::NamedGetter(const nsAString& aName, bool &aFound)
return plugin;
}
bool
nsPluginArray::NameIsEnumerable(const nsAString& aName)
{
return true;
}
uint32_t
nsPluginArray::Length()
{
@ -440,6 +446,12 @@ nsPluginElement::NamedGetter(const nsAString& aName, bool &aFound)
return nullptr;
}
bool
nsPluginElement::NameIsEnumerable(const nsAString& aName)
{
return true;
}
uint32_t
nsPluginElement::Length()
{

View File

@ -52,6 +52,7 @@ public:
void Refresh(bool aReloadDocuments);
nsPluginElement* IndexedGetter(uint32_t aIndex, bool &aFound);
nsPluginElement* NamedGetter(const nsAString& aName, bool &aFound);
bool NameIsEnumerable(const nsAString& aName);
uint32_t Length();
void GetSupportedNames(nsTArray< nsString >& aRetval);
@ -101,6 +102,7 @@ public:
nsMimeType* NamedItem(const nsAString& name);
nsMimeType* IndexedGetter(uint32_t index, bool &found);
nsMimeType* NamedGetter(const nsAString& name, bool &found);
bool NameIsEnumerable(const nsAString& aName);
uint32_t Length();
void GetSupportedNames(nsTArray< nsString >& retval);

View File

@ -8847,8 +8847,17 @@ MOZ_ASSERT_IF(desc.object(), desc.object() == ${holder});"""
setOrIndexedGet += getUnforgeable
if self.descriptor.supportsNamedProperties():
readonly = toStringBool(self.descriptor.operations['NamedSetter'] is None)
fillDescriptor = "FillPropertyDescriptor(desc, proxy, %s);\nreturn true;" % readonly
operations = self.descriptor.operations
readonly = toStringBool(operations['NamedSetter'] is None)
enumerable = (
"self->NameIsEnumerable(Constify(%s))" %
# First [0] means first (and only) signature, [1] means
# "arguments" as opposed to return type, [0] means first (and
# only) argument.
operations['NamedGetter'].signatures()[0][1][0].identifier.name)
fillDescriptor = (
"FillPropertyDescriptor(desc, proxy, %s, %s);\n"
"return true;" % (readonly, enumerable))
templateValues = {'jsvalRef': 'desc.value()', 'jsvalHandle': 'desc.value()',
'obj': 'proxy', 'successCode': fillDescriptor}
condition = "!HasPropertyOnPrototype(cx, proxy, id)"
@ -11121,7 +11130,7 @@ class CGBindingImplClass(CGClass):
[]),
{"infallible": True}))
# And if we support named properties we need to be able to
# enumerate the supported names.
# enumerate the supported names and test whether they're enumerable.
if descriptor.supportsNamedProperties():
self.methodDecls.append(
CGNativeMember(
@ -11131,6 +11140,15 @@ class CGBindingImplClass(CGClass):
BuiltinTypes[IDLBuiltinType.Types.domstring]),
[]),
{"infallible": True}))
self.methodDecls.append(
CGNativeMember(
descriptor, FakeMember(),
"NameIsEnumerable",
(BuiltinTypes[IDLBuiltinType.Types.boolean],
[FakeArgument(BuiltinTypes[IDLBuiltinType.Types.domstring],
FakeMember(),
name="aName")]),
{ "infallible": True }))
wrapArgs = [Argument('JSContext*', 'aCx')]
self.methodDecls.insert(0,

View File

@ -139,20 +139,23 @@ IsArrayIndex(int32_t index)
}
inline void
FillPropertyDescriptor(JS::MutableHandle<JSPropertyDescriptor> desc, JSObject* obj, bool readonly)
FillPropertyDescriptor(JS::MutableHandle<JSPropertyDescriptor> desc,
JSObject* obj, bool readonly, bool enumerable = true)
{
desc.object().set(obj);
desc.setAttributes((readonly ? JSPROP_READONLY : 0) | JSPROP_ENUMERATE);
desc.setAttributes((readonly ? JSPROP_READONLY : 0) |
(enumerable ? JSPROP_ENUMERATE : 0));
desc.setGetter(nullptr);
desc.setSetter(nullptr);
}
inline void
FillPropertyDescriptor(JS::MutableHandle<JSPropertyDescriptor> desc, JSObject* obj, JS::Value v,
bool readonly)
FillPropertyDescriptor(JS::MutableHandle<JSPropertyDescriptor> desc,
JSObject* obj, JS::Value v,
bool readonly, bool enumerable = true)
{
desc.value().set(v);
FillPropertyDescriptor(desc, obj, readonly);
FillPropertyDescriptor(desc, obj, readonly, enumerable);
}
inline void

View File

@ -989,6 +989,7 @@ public:
virtual nsISupports* GetParentObject();
void NamedGetter(const nsAString&, bool&, nsAString&);
bool NameIsEnumerable(const nsAString&);
void GetSupportedNames(nsTArray<nsString>&);
};
@ -1002,6 +1003,7 @@ public:
virtual nsISupports* GetParentObject();
void NamedGetter(const nsAString&, bool&, nsAString&);
bool NameIsEnumerable(const nsAString&);
void GetSupportedNames(nsTArray<nsString>&);
int32_t IndexedGetter(uint32_t, bool&);
void IndexedSetter(uint32_t, int32_t);
@ -1019,6 +1021,7 @@ public:
uint32_t IndexedGetter(uint32_t, bool&);
void NamedGetter(const nsAString&, bool&, nsAString&);
bool NameIsEnumerable(const nsAString&);
void NamedItem(const nsAString&, nsAString&);
uint32_t Length();
void GetSupportedNames(nsTArray<nsString>&);
@ -1050,6 +1053,7 @@ public:
void NamedSetter(const nsAString&, TestIndexedSetterInterface&);
TestIndexedSetterInterface* NamedGetter(const nsAString&, bool&);
bool NameIsEnumerable(const nsAString&);
void GetSupportedNames(nsTArray<nsString>&);
};
@ -1067,6 +1071,7 @@ public:
uint32_t Length();
void NamedSetter(const nsAString&, TestIndexedSetterInterface&);
TestIndexedSetterInterface* NamedGetter(const nsAString&, bool&);
bool NameIsEnumerable(const nsAString&);
void SetNamedItem(const nsAString&, TestIndexedSetterInterface&);
void GetSupportedNames(nsTArray<nsString>&);
};
@ -1077,6 +1082,7 @@ public:
uint32_t IndexedGetter(uint32_t, bool&);
uint32_t Item(uint32_t);
void NamedGetter(const nsAString&, bool&, nsAString&);
bool NameIsEnumerable(const nsAString&);
void NamedItem(const nsAString&, nsAString&);
void IndexedSetter(uint32_t, int32_t&);
void IndexedSetter(uint32_t, const nsAString&) MOZ_DELETE;
@ -1145,6 +1151,7 @@ public:
void NamedDeleter(const nsAString&, bool&);
long NamedGetter(const nsAString&, bool&);
bool NameIsEnumerable(const nsAString&);
void GetSupportedNames(nsTArray<nsString>&);
};
@ -1160,6 +1167,7 @@ public:
bool NamedDeleter(const nsAString&, bool&);
bool NamedDeleter(const nsAString&) MOZ_DELETE;
long NamedGetter(const nsAString&, bool&);
bool NameIsEnumerable(const nsAString&);
bool DelNamedItem(const nsAString&);
bool DelNamedItem(const nsAString&, bool&) MOZ_DELETE;
void GetSupportedNames(nsTArray<nsString>&);
@ -1181,6 +1189,7 @@ public:
void NamedDeleter(const nsAString&, bool&);
void NamedDeleter(const nsAString&) MOZ_DELETE;
long NamedGetter(const nsAString&, bool&);
bool NameIsEnumerable(const nsAString&);
void DelNamedItem(const nsAString&);
void DelNamedItem(const nsAString&, bool&) MOZ_DELETE;
void GetSupportedNames(nsTArray<nsString>&);

View File

@ -35,6 +35,7 @@ skip-if = (toolkit == 'gonk' && debug) #debug-only failure; bug 926547
[test_lenientThis.html]
[test_lookupGetter.html]
[test_namedNoIndexed.html]
[test_named_getter_enumerability.html]
[test_Object.prototype_props.html]
[test_queryInterface.html]
[test_sequence_wrapping.html]

View File

@ -0,0 +1,17 @@
<!DOCTYPE html>
<meta charset=utf-8>
<title>Test for named getter enumerability</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id="log"></div>
<script>
test(function() {
var list = document.getElementsByTagName("div");
var desc = Object.getOwnPropertyDescriptor(list, "0");
assert_equals(typeof desc, "object", "Should have a '0' property");
assert_true(desc.enumerable, "'0' property should be enumerable");
desc = Object.getOwnPropertyDescriptor(list, "log");
assert_equals(typeof desc, "object", "Should have a 'log' property");
assert_false(desc.enumerable, "'log' property should not be enumerable");
}, "Correct getOwnPropertyDescriptor behavior");
</script>

View File

@ -64,10 +64,15 @@ test(function() {
assert_array_equals(Object.getOwnPropertyNames(list).sort(), ["0", "x"]);
var desc = Object.getOwnPropertyDescriptor(list, 'x');
var desc = Object.getOwnPropertyDescriptor(list, '0');
assert_equals(typeof desc, "object", "descriptor should be an object");
assert_true(desc.enumerable, "desc.enumerable");
assert_true(desc.configurable, "desc.configurable");
desc = Object.getOwnPropertyDescriptor(list, 'x');
assert_equals(typeof desc, "object", "descriptor should be an object");
assert_false(desc.enumerable, "desc.enumerable");
assert_true(desc.configurable, "desc.configurable");
}, "hasOwnProperty, getOwnPropertyDescriptor, getOwnPropertyNames")
test(function() {

View File

@ -559,6 +559,12 @@ nsTreeColumns::NamedGetter(const nsAString& aId, bool& aFound)
return nullptr;
}
bool
nsTreeColumns::NameIsEnumerable(const nsAString& aName)
{
return true;
}
nsTreeColumn*
nsTreeColumns::GetNamedColumn(const nsAString& aId)
{

View File

@ -157,6 +157,7 @@ public:
nsTreeColumn* IndexedGetter(uint32_t aIndex, bool& aFound);
nsTreeColumn* GetColumnAt(uint32_t aIndex);
nsTreeColumn* NamedGetter(const nsAString& aId, bool& aFound);
bool NameIsEnumerable(const nsAString& aName);
nsTreeColumn* GetNamedColumn(const nsAString& aId);
void GetSupportedNames(nsTArray<nsString>& aNames);