Bug 1245650 - remove JavaScript-navigator-property category support. r=bz.

Generate normal properties with getters for things marked as NavigatorProperty,
instead of defining these from a resolve hook.
This commit is contained in:
Peter Van der Beken 2016-02-05 20:20:08 +01:00
parent d0fbe5c8f1
commit f781f02ccd
21 changed files with 199 additions and 469 deletions

View File

@ -20,19 +20,10 @@ if (SpecialPowers.hasPermission("alarms", document)) {
} else {
SpecialPowers.pushPrefEnv({"set": [["dom.mozAlarms.enabled", true]]}, function() {
SpecialPowers.removePermission("alarms", document);
// mozAlarms is installed on all platforms except Android for the moment.
if (navigator.appVersion.indexOf("Android") != -1) {
ok(!('mozAlarms' in navigator),
"navigator.mozAlarms should not exist without permission");
ok(!('AlarmsManager' in window),
"Interface AlarmsManager should not exist");
} else {
ok(!('mozAlarms' in navigator),
"navigator.mozAlarms should not exist without permission");
ok(!('AlarmsManager' in window),
"Interface AlarmsManager should not exist without permission");
}
ok(!('mozAlarms' in navigator),
"navigator.mozAlarms should not exist without permission");
ok(!('AlarmsManager' in window),
"Interface AlarmsManager should not exist without permission");
SpecialPowers.addPermission("alarms", true, document);
SimpleTest.finish();
});

View File

@ -20,7 +20,6 @@ SpecialPowers.pushPrefEnv({"set": [["dom.mozAlarms.enabled", true]]}, function()
// mozAlarms is installed on all platforms except Android for the moment.
if (navigator.appVersion.indexOf("Android") != -1) {
ok('AlarmsManager' in window, "Interface AlarmsManager should exist");
try {
todo('mozAlarms' in navigator,
"mozAlarms is not allowed on Android for now. TODO Bug 863557.");
@ -30,6 +29,7 @@ SpecialPowers.pushPrefEnv({"set": [["dom.mozAlarms.enabled", true]]}, function()
"Caught exception: " + e);
}
} else {
ok('AlarmsManager' in window, "Interface AlarmsManager should exist");
ok('mozAlarms' in navigator, "navigator.mozAlarms should exist");
ok(navigator.mozAlarms instanceof AlarmsManager,
"navigator.mozAlarms should be an instance of AlarmsManager");

View File

@ -183,7 +183,6 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(Navigator)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Navigator)
tmp->Invalidate();
NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCachedResolveResults)
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
@ -220,7 +219,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Navigator)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mServiceWorkerContainer)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCachedResolveResults)
#ifdef MOZ_EME
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaKeySystemAccessManager)
#endif
@ -1668,11 +1666,6 @@ Navigator::HasFeature(const nsAString& aName, ErrorResult& aRv)
return p.forget();
}
if (featureName.EqualsLiteral("Navigator.mozContacts")) {
p->MaybeResolve(true);
return p.forget();
}
if (featureName.EqualsLiteral("Navigator.getDeviceStorage")) {
p->MaybeResolve(Preferences::GetBool("device.storage.enabled"));
return p.forget();
@ -2256,206 +2249,6 @@ Navigator::GetMozAudioChannelManager(ErrorResult& aRv)
}
#endif
bool
Navigator::DoResolve(JSContext* aCx, JS::Handle<JSObject*> aObject,
JS::Handle<jsid> aId,
JS::MutableHandle<JS::PropertyDescriptor> aDesc)
{
// Note: Keep this in sync with MayResolve.
if (!JSID_IS_STRING(aId)) {
return true;
}
nsScriptNameSpaceManager* nameSpaceManager = GetNameSpaceManager();
if (!nameSpaceManager) {
return Throw(aCx, NS_ERROR_NOT_INITIALIZED);
}
nsAutoJSString name;
if (!name.init(aCx, JSID_TO_STRING(aId))) {
return false;
}
const nsGlobalNameStruct* name_struct =
nameSpaceManager->LookupNavigatorName(name);
if (!name_struct) {
return true;
}
JS::Rooted<JSObject*> naviObj(aCx,
js::CheckedUnwrap(aObject,
/* stopAtWindowProxy = */ false));
if (!naviObj) {
return Throw(aCx, NS_ERROR_DOM_SECURITY_ERR);
}
if (name_struct->mType == nsGlobalNameStruct::eTypeNewDOMBinding) {
ConstructNavigatorProperty construct = name_struct->mConstructNavigatorProperty;
MOZ_ASSERT(construct);
JS::Rooted<JSObject*> domObject(aCx);
{
// Make sure to do the creation of our object in the compartment
// of naviObj, especially since we plan to cache that object.
JSAutoCompartment ac(aCx, naviObj);
// Check whether our constructor is enabled after we unwrap Xrays, since
// we don't want to define an interface on the Xray if it's disabled in
// the target global, even if it's enabled in the Xray's global.
if (name_struct->mConstructorEnabled &&
!(*name_struct->mConstructorEnabled)(aCx, naviObj)) {
return true;
}
if (name.EqualsLiteral("mozSettings")) {
bool hasPermission = CheckPermission("settings-api-read") ||
CheckPermission("settings-api-write");
if (!hasPermission) {
FillPropertyDescriptor(aDesc, aObject, JS::NullValue(), false);
return true;
}
}
if (name.EqualsLiteral("mozDownloadManager")) {
if (!CheckPermission("downloads")) {
FillPropertyDescriptor(aDesc, aObject, JS::NullValue(), false);
return true;
}
}
nsISupports* existingObject = mCachedResolveResults.GetWeak(name);
if (existingObject) {
// We know all of our WebIDL objects here are wrappercached, so just go
// ahead and WrapObject() them. We can't use GetOrCreateDOMReflector,
// because we don't have the concrete type.
JS::Rooted<JS::Value> wrapped(aCx);
if (!dom::WrapObject(aCx, existingObject, &wrapped)) {
return false;
}
domObject = &wrapped.toObject();
} else {
domObject = construct(aCx, naviObj);
if (!domObject) {
return Throw(aCx, NS_ERROR_FAILURE);
}
// Store the value in our cache
nsISupports* native = UnwrapDOMObjectToISupports(domObject);
MOZ_ASSERT(native);
mCachedResolveResults.Put(name, native);
}
}
if (!JS_WrapObject(aCx, &domObject)) {
return false;
}
FillPropertyDescriptor(aDesc, aObject, JS::ObjectValue(*domObject), false);
return true;
}
NS_ASSERTION(name_struct->mType == nsGlobalNameStruct::eTypeNavigatorProperty,
"unexpected type");
nsresult rv = NS_OK;
nsCOMPtr<nsISupports> native;
bool hadCachedNative = mCachedResolveResults.Get(name, getter_AddRefs(native));
bool okToUseNative;
JS::Rooted<JS::Value> prop_val(aCx);
if (hadCachedNative) {
okToUseNative = true;
} else {
native = do_CreateInstance(name_struct->mCID, &rv);
if (NS_FAILED(rv)) {
return Throw(aCx, rv);
}
nsCOMPtr<nsIDOMGlobalPropertyInitializer> gpi(do_QueryInterface(native));
if (gpi) {
if (!mWindow) {
return Throw(aCx, NS_ERROR_UNEXPECTED);
}
rv = gpi->Init(mWindow, &prop_val);
if (NS_FAILED(rv)) {
return Throw(aCx, rv);
}
}
okToUseNative = !prop_val.isObjectOrNull();
}
if (okToUseNative) {
// Make sure to do the creation of our object in the compartment
// of naviObj, especially since we plan to cache that object.
JSAutoCompartment ac(aCx, naviObj);
rv = nsContentUtils::WrapNative(aCx, native, &prop_val);
if (NS_FAILED(rv)) {
return Throw(aCx, rv);
}
// Now that we know we managed to wrap this thing properly, go ahead and
// cache it as needed.
if (!hadCachedNative) {
mCachedResolveResults.Put(name, native);
}
}
if (!JS_WrapValue(aCx, &prop_val)) {
return Throw(aCx, NS_ERROR_UNEXPECTED);
}
FillPropertyDescriptor(aDesc, aObject, prop_val, false);
return true;
}
/* static */
bool
Navigator::MayResolve(jsid aId)
{
// Note: This function does not fail and may not have any side-effects.
// Note: Keep this in sync with DoResolve.
if (!JSID_IS_STRING(aId)) {
return false;
}
nsScriptNameSpaceManager *nameSpaceManager = PeekNameSpaceManager();
if (!nameSpaceManager) {
// Really shouldn't happen here. Fail safe.
return true;
}
nsAutoString name;
AssignJSFlatString(name, JSID_TO_FLAT_STRING(aId));
return nameSpaceManager->LookupNavigatorName(name);
}
void
Navigator::GetOwnPropertyNames(JSContext* aCx, nsTArray<nsString>& aNames,
ErrorResult& aRv)
{
nsScriptNameSpaceManager *nameSpaceManager = GetNameSpaceManager();
if (!nameSpaceManager) {
NS_ERROR("Can't get namespace manager.");
aRv.Throw(NS_ERROR_UNEXPECTED);
return;
}
JS::Rooted<JSObject*> wrapper(aCx, GetWrapper());
for (auto i = nameSpaceManager->NavigatorNameIter(); !i.Done(); i.Next()) {
const GlobalNameMapEntry* entry = i.Get();
if (!entry->mGlobalName.mConstructorEnabled ||
entry->mGlobalName.mConstructorEnabled(aCx, wrapper)) {
aNames.AppendElement(entry->mKey);
}
}
}
JSObject*
Navigator::WrapObject(JSContext* cx, JS::Handle<JSObject*> aGivenProto)
{

View File

@ -309,14 +309,6 @@ public:
already_AddRefed<ServiceWorkerContainer> ServiceWorker();
bool DoResolve(JSContext* aCx, JS::Handle<JSObject*> aObject,
JS::Handle<jsid> aId,
JS::MutableHandle<JS::PropertyDescriptor> aDesc);
// The return value is whether DoResolve might end up resolving the given id.
// If in doubt, return true.
static bool MayResolve(jsid aId);
void GetOwnPropertyNames(JSContext* aCx, nsTArray<nsString>& aNames,
ErrorResult& aRv);
void GetLanguages(nsTArray<nsString>& aLanguages);
bool MozE10sEnabled();
@ -422,13 +414,6 @@ private:
RefPtr<DeviceStorageAreaListener> mDeviceStorageAreaListener;
RefPtr<Presentation> mPresentation;
// Hashtable for saving cached objects DoResolve created, so we don't create
// the object twice if asked for it twice, whether due to use of "delete" or
// due to Xrays. We could probably use a nsJSThingHashtable here, but then
// we'd need to figure out exactly how to trace that, and that seems to be
// rocket science. :(
nsInterfaceHashtable<nsStringHashKey, nsISupports> mCachedResolveResults;
nsTArray<RefPtr<Promise> > mVRGetDevicesPromises;
};

View File

@ -4239,13 +4239,7 @@ nsGlobalWindow::MayResolve(jsid aId)
nsAutoString name;
AssignJSFlatString(name, JSID_TO_FLAT_STRING(aId));
const nsGlobalNameStruct *name_struct =
nameSpaceManager->LookupName(name);
// LookupName only returns structs for the global.
MOZ_ASSERT_IF(name_struct,
name_struct->mType != nsGlobalNameStruct::eTypeNavigatorProperty);
return name_struct;
return nameSpaceManager->LookupName(name);
}
void

View File

@ -17,7 +17,4 @@
#define JAVASCRIPT_GLOBAL_PRIVILEGED_PROPERTY_CATEGORY \
"JavaScript-global-privileged-property"
#define JAVASCRIPT_NAVIGATOR_PROPERTY_CATEGORY \
"JavaScript-navigator-property"
#endif /* nsIScriptNameSpaceManager_h__ */

View File

@ -100,8 +100,6 @@ static const PLDHashTableOps hash_table_ops =
nsScriptNameSpaceManager::nsScriptNameSpaceManager()
: mGlobalNames(&hash_table_ops, sizeof(GlobalNameMapEntry),
GLOBALNAME_HASHTABLE_INITIAL_LENGTH)
, mNavigatorNames(&hash_table_ops, sizeof(GlobalNameMapEntry),
GLOBALNAME_HASHTABLE_INITIAL_LENGTH)
{
MOZ_COUNT_CTOR(nsScriptNameSpaceManager);
}
@ -113,10 +111,10 @@ nsScriptNameSpaceManager::~nsScriptNameSpaceManager()
}
nsGlobalNameStruct *
nsScriptNameSpaceManager::AddToHash(PLDHashTable *aTable, const nsAString *aKey,
nsScriptNameSpaceManager::AddToHash(const nsAString *aKey,
const char16_t **aClassName)
{
auto entry = static_cast<GlobalNameMapEntry*>(aTable->Add(aKey, fallible));
auto entry = static_cast<GlobalNameMapEntry*>(mGlobalNames.Add(aKey, fallible));
if (!entry) {
return nullptr;
}
@ -129,10 +127,9 @@ nsScriptNameSpaceManager::AddToHash(PLDHashTable *aTable, const nsAString *aKey,
}
void
nsScriptNameSpaceManager::RemoveFromHash(PLDHashTable *aTable,
const nsAString *aKey)
nsScriptNameSpaceManager::RemoveFromHash(const nsAString *aKey)
{
aTable->Remove(aKey);
mGlobalNames.Remove(aKey);
}
nsresult
@ -176,9 +173,6 @@ nsScriptNameSpaceManager::Init()
rv = FillHash(cm, JAVASCRIPT_GLOBAL_PRIVILEGED_PROPERTY_CATEGORY);
NS_ENSURE_SUCCESS(rv, rv);
rv = FillHash(cm, JAVASCRIPT_NAVIGATOR_PROPERTY_CATEGORY);
NS_ENSURE_SUCCESS(rv, rv);
// Initial filling of the has table has been done.
// Now, listen for changes.
nsCOMPtr<nsIObserverService> serv =
@ -192,9 +186,9 @@ nsScriptNameSpaceManager::Init()
return NS_OK;
}
nsGlobalNameStruct*
nsScriptNameSpaceManager::LookupNameInternal(const nsAString& aName,
const char16_t **aClassName)
const nsGlobalNameStruct*
nsScriptNameSpaceManager::LookupName(const nsAString& aName,
const char16_t **aClassName)
{
auto entry = static_cast<GlobalNameMapEntry*>(mGlobalNames.Search(&aName));
@ -211,14 +205,6 @@ nsScriptNameSpaceManager::LookupNameInternal(const nsAString& aName,
return nullptr;
}
const nsGlobalNameStruct*
nsScriptNameSpaceManager::LookupNavigatorName(const nsAString& aName)
{
auto entry = static_cast<GlobalNameMapEntry*>(mNavigatorNames.Search(&aName));
return entry ? &entry->mGlobalName : nullptr;
}
nsresult
nsScriptNameSpaceManager::RegisterClassName(const char *aClassName,
int32_t aDOMClassInfoID,
@ -230,7 +216,7 @@ nsScriptNameSpaceManager::RegisterClassName(const char *aClassName,
NS_ERROR("Trying to register a non-ASCII class name");
return NS_OK;
}
nsGlobalNameStruct *s = AddToHash(&mGlobalNames, aClassName, aResult);
nsGlobalNameStruct *s = AddToHash(aClassName, aResult);
NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
if (s->mType == nsGlobalNameStruct::eTypeClassConstructor) {
@ -265,7 +251,7 @@ nsScriptNameSpaceManager::RegisterClassProto(const char *aClassName,
*aFoundOld = false;
nsGlobalNameStruct *s = AddToHash(&mGlobalNames, aClassName);
nsGlobalNameStruct *s = AddToHash(aClassName);
NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
if (s->mType != nsGlobalNameStruct::eTypeNotInitialized &&
@ -298,8 +284,6 @@ nsScriptNameSpaceManager::OperateCategoryEntryHash(nsICategoryManager* aCategory
} else if (strcmp(aCategory, JAVASCRIPT_GLOBAL_PROPERTY_CATEGORY) == 0 ||
strcmp(aCategory, JAVASCRIPT_GLOBAL_PRIVILEGED_PROPERTY_CATEGORY) == 0) {
type = nsGlobalNameStruct::eTypeProperty;
} else if (strcmp(aCategory, JAVASCRIPT_NAVIGATOR_PROPERTY_CATEGORY) == 0) {
type = nsGlobalNameStruct::eTypeNavigatorProperty;
} else {
return NS_OK;
}
@ -315,28 +299,19 @@ nsScriptNameSpaceManager::OperateCategoryEntryHash(nsICategoryManager* aCategory
nsresult rv = strWrapper->GetData(categoryEntry);
NS_ENSURE_SUCCESS(rv, rv);
PLDHashTable *table;
if (type == nsGlobalNameStruct::eTypeNavigatorProperty) {
table = &mNavigatorNames;
} else {
table = &mGlobalNames;
}
// We need to handle removal before calling GetCategoryEntry
// because the category entry is already removed before we are
// notified.
if (aRemove) {
NS_ConvertASCIItoUTF16 entry(categoryEntry);
const nsGlobalNameStruct *s =
type == nsGlobalNameStruct::eTypeNavigatorProperty ?
LookupNavigatorName(entry) : LookupNameInternal(entry);
const nsGlobalNameStruct *s = LookupName(entry);
// Verify mType so that this API doesn't remove names
// registered by others.
if (!s || s->mType != type) {
return NS_OK;
}
RemoveFromHash(table, &entry);
RemoveFromHash(&entry);
return NS_OK;
}
@ -345,11 +320,8 @@ nsScriptNameSpaceManager::OperateCategoryEntryHash(nsICategoryManager* aCategory
getter_Copies(contractId));
NS_ENSURE_SUCCESS(rv, rv);
if (type == nsGlobalNameStruct::eTypeNavigatorProperty ||
type == nsGlobalNameStruct::eTypeExternalConstructor) {
bool isNavProperty = type == nsGlobalNameStruct::eTypeNavigatorProperty;
nsPrintfCString prefName("dom.%s.disable.%s",
isNavProperty ? "navigator-property" : "global-constructor",
if (type == nsGlobalNameStruct::eTypeExternalConstructor) {
nsPrintfCString prefName("dom.global-constructor.disable.%s",
categoryEntry.get());
if (Preferences::GetType(prefName.get()) == nsIPrefBranch::PREF_BOOL &&
Preferences::GetBool(prefName.get(), false)) {
@ -374,7 +346,7 @@ nsScriptNameSpaceManager::OperateCategoryEntryHash(nsICategoryManager* aCategory
nsCID cid = *cidPtr;
free(cidPtr);
nsGlobalNameStruct *s = AddToHash(table, categoryEntry.get());
nsGlobalNameStruct *s = AddToHash(categoryEntry.get());
NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
if (s->mType == nsGlobalNameStruct::eTypeNotInitialized ||
@ -447,7 +419,7 @@ nsScriptNameSpaceManager::RegisterDefineDOMInterface(const nsAFlatString& aName,
mozilla::dom::DefineInterface aDefineDOMInterface,
mozilla::dom::ConstructorEnabled* aConstructorEnabled)
{
nsGlobalNameStruct *s = AddToHash(&mGlobalNames, &aName);
nsGlobalNameStruct *s = AddToHash(&aName);
if (s) {
if (s->mType == nsGlobalNameStruct::eTypeNotInitialized) {
s->mType = nsGlobalNameStruct::eTypeNewDOMBinding;
@ -457,22 +429,6 @@ nsScriptNameSpaceManager::RegisterDefineDOMInterface(const nsAFlatString& aName,
}
}
void
nsScriptNameSpaceManager::RegisterNavigatorDOMConstructor(
const nsAFlatString& aName,
mozilla::dom::ConstructNavigatorProperty aNavConstructor,
mozilla::dom::ConstructorEnabled* aConstructorEnabled)
{
nsGlobalNameStruct *s = AddToHash(&mNavigatorNames, &aName);
if (s) {
if (s->mType == nsGlobalNameStruct::eTypeNotInitialized) {
s->mType = nsGlobalNameStruct::eTypeNewDOMBinding;
}
s->mConstructNavigatorProperty = aNavConstructor;
s->mConstructorEnabled = aConstructorEnabled;
}
}
MOZ_DEFINE_MALLOC_SIZE_OF(ScriptNameSpaceManagerMallocSizeOf)
NS_IMETHODIMP
@ -497,11 +453,5 @@ nsScriptNameSpaceManager::SizeOfIncludingThis(
n += entry->SizeOfExcludingThis(aMallocSizeOf);
}
n += mNavigatorNames.ShallowSizeOfExcludingThis(aMallocSizeOf);
for (auto iter = mNavigatorNames.ConstIter(); !iter.Done(); iter.Next()) {
auto entry = static_cast<GlobalNameMapEntry*>(iter.Get());
n += entry->SizeOfExcludingThis(aMallocSizeOf);
}
return n;
}

View File

@ -40,7 +40,6 @@ struct nsGlobalNameStruct
eTypeNotInitialized,
eTypeNewDOMBinding,
eTypeProperty,
eTypeNavigatorProperty,
eTypeExternalConstructor,
eTypeClassConstructor,
eTypeClassProto,
@ -59,10 +58,8 @@ struct nsGlobalNameStruct
};
// For new style DOM bindings.
union {
mozilla::dom::DefineInterface mDefineDOMInterface; // for window
mozilla::dom::ConstructNavigatorProperty mConstructNavigatorProperty; // for navigator
};
mozilla::dom::DefineInterface mDefineDOMInterface;
// May be null if enabled unconditionally
mozilla::dom::ConstructorEnabled* mConstructorEnabled;
};
@ -103,16 +100,7 @@ public:
// It also returns a pointer to the string buffer of the classname
// in the nsGlobalNameStruct.
const nsGlobalNameStruct* LookupName(const nsAString& aName,
const char16_t **aClassName = nullptr)
{
return LookupNameInternal(aName, aClassName);
}
// Returns a nsGlobalNameStruct for the navigator property aName, or
// null if one is not found. The returned nsGlobalNameStruct is only
// guaranteed to be valid until the next call to any of the methods
// in this class.
const nsGlobalNameStruct* LookupNavigatorName(const nsAString& aName);
const char16_t **aClassName = nullptr);
nsresult RegisterClassName(const char *aClassName,
int32_t aDOMClassInfoID,
@ -137,19 +125,6 @@ public:
aConstructorEnabled);
}
void RegisterNavigatorDOMConstructor(const nsAFlatString& aName,
mozilla::dom::ConstructNavigatorProperty aNavConstructor,
mozilla::dom::ConstructorEnabled* aConstructorEnabled);
template<size_t N>
void RegisterNavigatorDOMConstructor(const char16_t (&aKey)[N],
mozilla::dom::ConstructNavigatorProperty aNavConstructor,
mozilla::dom::ConstructorEnabled* aConstructorEnabled)
{
nsLiteralString key(aKey);
return RegisterNavigatorDOMConstructor(key, aNavConstructor,
aConstructorEnabled);
}
class NameIterator : public PLDHashTable::Iterator
{
public:
@ -170,7 +145,6 @@ public:
};
NameIterator GlobalNameIter() { return NameIterator(&mGlobalNames); }
NameIterator NavigatorNameIter() { return NameIterator(&mNavigatorNames); }
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
@ -181,16 +155,16 @@ private:
// that aKey will be mapped to. If mType in the returned
// nsGlobalNameStruct is != eTypeNotInitialized, an entry for aKey
// already existed.
nsGlobalNameStruct *AddToHash(PLDHashTable *aTable, const nsAString *aKey,
nsGlobalNameStruct *AddToHash(const nsAString *aKey,
const char16_t **aClassName = nullptr);
nsGlobalNameStruct *AddToHash(PLDHashTable *aTable, const char *aKey,
nsGlobalNameStruct *AddToHash(const char *aKey,
const char16_t **aClassName = nullptr)
{
NS_ConvertASCIItoUTF16 key(aKey);
return AddToHash(aTable, &key, aClassName);
return AddToHash(&key, aClassName);
}
// Removes an existing entry from the hash.
void RemoveFromHash(PLDHashTable *aTable, const nsAString *aKey);
void RemoveFromHash(const nsAString *aKey);
nsresult FillHash(nsICategoryManager *aCategoryManager,
const char *aCategory);
@ -229,11 +203,7 @@ private:
nsISupports* aEntry,
bool aRemove);
nsGlobalNameStruct* LookupNameInternal(const nsAString& aName,
const char16_t **aClassName = nullptr);
PLDHashTable mGlobalNames;
PLDHashTable mNavigatorNames;
};
#endif /* nsScriptNameSpaceManager_h__ */

View File

@ -1663,57 +1663,31 @@ class CGClassConstructor(CGAbstractStaticMethod):
# Encapsulate the constructor in a helper method to share genConstructorBody with CGJSImplMethod.
class CGConstructNavigatorObjectHelper(CGAbstractStaticMethod):
class CGConstructNavigatorObject(CGAbstractMethod):
"""
Construct a new JS-implemented WebIDL DOM object, for use on navigator.
"""
def __init__(self, descriptor):
name = "ConstructNavigatorObjectHelper"
args = [Argument('JSContext*', 'cx'),
Argument('GlobalObject&', 'global'),
Argument('JS::Handle<JSObject*>', 'obj'),
Argument('ErrorResult&', 'aRv')]
rtype = 'already_AddRefed<%s>' % descriptor.name
CGAbstractStaticMethod.__init__(self, descriptor, name, rtype, args)
def definition_body(self):
return genConstructorBody(self.descriptor)
class CGConstructNavigatorObject(CGAbstractMethod):
"""
Wrap a JS-implemented WebIDL object into a JS value, for use on navigator.
"""
def __init__(self, descriptor):
name = 'ConstructNavigatorObject'
args = [Argument('JSContext*', 'aCx'), Argument('JS::Handle<JSObject*>', 'aObj')]
CGAbstractMethod.__init__(self, descriptor, name, 'JSObject*', args)
CGAbstractMethod.__init__(self, descriptor, "ConstructNavigatorObject",
rtype, args)
def definition_body(self):
if not self.descriptor.interface.isJSImplemented():
raise TypeError("Only JS-implemented classes are currently supported "
"on navigator. See bug 856820.")
return fill(
return dedent(
"""
GlobalObject global(aCx, aObj);
GlobalObject global(cx, obj);
if (global.Failed()) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
ErrorResult rv;
JS::Rooted<JS::Value> v(aCx);
{ // Scope to make sure |result| goes out of scope while |v| is rooted
RefPtr<mozilla::dom::${descriptorName}> result = ConstructNavigatorObjectHelper(aCx, global, rv);
if (rv.MaybeSetPendingException(aCx)) {
return nullptr;
}
if (!GetOrCreateDOMReflector(aCx, result, &v)) {
//XXX Assertion disabled for now, see bug 991271.
MOZ_ASSERT(true || JS_IsExceptionPending(aCx));
return nullptr;
}
}
return &v.toObject();
""",
descriptorName=self.descriptor.name)
""") + genConstructorBody(self.descriptor)
class CGClassConstructHookHolder(CGGeneric):
@ -2501,6 +2475,9 @@ def IsCrossOriginWritable(attr, descriptor):
len(crossOriginWritable) == 1)
return crossOriginWritable[0] == descriptor.interface.identifier.name
def isNonExposedNavigatorObjectGetter(attr, descriptor):
return (attr.navigatorObjectGetter and
not descriptor.getDescriptor(attr.type.inner.identifier.name).register)
class AttrDefiner(PropertyDefiner):
def __init__(self, descriptor, name, static, unforgeable=False):
@ -2512,7 +2489,8 @@ class AttrDefiner(PropertyDefiner):
attributes = [m for m in descriptor.interface.members if
m.isAttr() and m.isStatic() == static and
MemberIsUnforgeable(m, descriptor) == unforgeable and
isMaybeExposedIn(m, descriptor)]
isMaybeExposedIn(m, descriptor) and
not isNonExposedNavigatorObjectGetter(m, descriptor)]
else:
attributes = []
self.chrome = [m for m in attributes if isChromeOnly(m)]
@ -7123,7 +7101,9 @@ class CGPerSignatureCall(CGThing):
IDLType if there's an IDL type involved (including |void|).
2) An argument list, which is allowed to be empty.
3) A name of a native method to call.
4) Whether or not this method is static.
4) Whether or not this method is static. Note that this only controls how
the method is called (|self->nativeMethodName(...)| vs
|nativeMethodName(...)|).
We also need to know whether this is a method or a getter/setter
to do error reporting correctly.
@ -7175,7 +7155,7 @@ class CGPerSignatureCall(CGThing):
""")))
deprecated = (idlNode.getExtendedAttribute("Deprecated") or
(static and descriptor.interface.getExtendedAttribute("Deprecated")))
(idlNode.isStatic() and descriptor.interface.getExtendedAttribute("Deprecated")))
if deprecated:
cgThings.append(CGGeneric(dedent(
"""
@ -7191,12 +7171,7 @@ class CGPerSignatureCall(CGThing):
"return true;\n")
argsPre = []
if static:
nativeType = descriptor.nativeType
staticTypeOverride = PropertyDefiner.getStringAttr(idlNode, "StaticClassOverride")
if (staticTypeOverride):
nativeType = staticTypeOverride
nativeMethodName = "%s::%s" % (nativeType, nativeMethodName)
if idlNode.isStatic():
# If we're a constructor, "obj" may not be a function, so calling
# XrayAwareCalleeGlobal() on it is not safe. Of course in the
# constructor case either "obj" is an Xray or we're already in the
@ -7227,7 +7202,7 @@ class CGPerSignatureCall(CGThing):
argsPre.append("cx")
# Hack for making Promise.prototype.then work well over Xrays.
if (not static and
if (not idlNode.isStatic() and
descriptor.name == "Promise" and
idlNode.isMethod() and
idlNode.identifier.name == "then"):
@ -7290,7 +7265,7 @@ class CGPerSignatureCall(CGThing):
needsUnwrappedVar = True
argsPre.append("unwrappedObj ? *unwrappedObj : obj")
if static and not isConstructor and descriptor.name == "Promise":
if idlNode.isStatic() and not isConstructor and descriptor.name == "Promise":
# Hack for Promise for now: pass in the "this" value to
# Promise static methods.
argsPre.append("args.thisv()")
@ -7394,7 +7369,8 @@ class CGPerSignatureCall(CGThing):
cgThings.append(CGCallGenerator(
self.isFallible(),
self.getArguments(), argsPre, returnType,
self.extendedAttributes, descriptor, nativeMethodName,
self.extendedAttributes, descriptor,
nativeMethodName,
static, argsPost=argsPost, resultVar=resultVar))
if useCounterName:
@ -7568,6 +7544,13 @@ class CGMethodCall(CGThing):
else:
useCounterName = None
if method.isStatic():
nativeType = descriptor.nativeType
staticTypeOverride = PropertyDefiner.getStringAttr(method, "StaticClassOverride")
if (staticTypeOverride):
nativeType = staticTypeOverride
nativeMethodName = "%s::%s" % (nativeType, nativeMethodName)
def requiredArgCount(signature):
arguments = signature[1]
if len(arguments) == 0:
@ -7993,11 +7976,27 @@ class CGGetterCall(CGPerSignatureCall):
attr.identifier.name)
else:
useCounterName = None
if attr.isStatic():
nativeMethodName = "%s::%s" % (descriptor.nativeType, nativeMethodName)
CGPerSignatureCall.__init__(self, returnType, [], nativeMethodName,
attr.isStatic(), descriptor, attr,
getter=True, useCounterName=useCounterName)
class CGNavigatorGetterCall(CGPerSignatureCall):
"""
A class to generate a native object getter call for an IDL getter for a
property generated by NavigatorProperty.
"""
def __init__(self, returnType, _, descriptor, attr):
nativeMethodName = "%s::ConstructNavigatorObject" % (toBindingNamespace(returnType.inner.identifier.name))
CGPerSignatureCall.__init__(self, returnType, [], nativeMethodName,
True, descriptor, attr, getter=True)
def getArguments(self):
return [(FakeArgument(BuiltinTypes[IDLBuiltinType.Types.object], self.idlNode), "reflector")]
class FakeIdentifier():
def __init__(self, name):
self.name = name
@ -8047,6 +8046,8 @@ class CGSetterCall(CGPerSignatureCall):
attr.identifier.name)
else:
useCounterName = None
if attr.isStatic():
nativeMethodName = "%s::%s" % (descriptor.nativeType, nativeMethodName)
CGPerSignatureCall.__init__(self, None,
[FakeArgument(argType, attr, allowTreatNonCallableAsNull=True)],
nativeMethodName, attr.isStatic(),
@ -8632,8 +8633,12 @@ class CGSpecializedGetter(CGAbstractStaticMethod):
else:
prefix = ""
if self.attr.navigatorObjectGetter:
cgGetterCall = CGNavigatorGetterCall
else:
cgGetterCall = CGGetterCall
return (prefix +
CGGetterCall(self.attr.type, nativeName,
cgGetterCall(self.attr.type, nativeName,
self.descriptor, self.attr).define())
@staticmethod
@ -11893,6 +11898,8 @@ class CGDescriptor(CGThing):
assert descriptor.interface.hasInterfaceObject()
cgThings.append(CGStaticGetter(descriptor, m))
elif descriptor.interface.hasInterfacePrototypeObject():
if isNonExposedNavigatorObjectGetter(m, descriptor):
continue
cgThings.append(CGSpecializedGetter(descriptor, m))
if props.isCrossOriginGetter:
crossOriginGetters.add(m.identifier.name)
@ -11948,8 +11955,7 @@ class CGDescriptor(CGThing):
cgThings.append(CGGenericSetter(descriptor,
allowCrossOriginThis=True))
if descriptor.interface.getNavigatorProperty():
cgThings.append(CGConstructNavigatorObjectHelper(descriptor))
if descriptor.interface.isNavigatorProperty():
cgThings.append(CGConstructNavigatorObject(descriptor))
if descriptor.concrete and not descriptor.proxy:
@ -12020,7 +12026,7 @@ class CGDescriptor(CGThing):
if descriptor.interface.hasInterfaceObject():
cgThings.append(CGDefineDOMInterfaceMethod(descriptor))
if ((descriptor.interface.hasInterfaceObject() or descriptor.interface.getNavigatorProperty()) and
if ((descriptor.interface.hasInterfaceObject() or descriptor.interface.isNavigatorProperty()) and
not descriptor.interface.isExternal() and
descriptor.isExposedConditionally()):
cgThings.append(CGConstructorEnabled(descriptor))
@ -13029,15 +13035,12 @@ class CGRegisterProtos(CGAbstractMethod):
aNameSpaceManager->RegisterDefineDOMInterface(MOZ_UTF16(#_dom_class), _dom_class##Binding::DefineDOMInterface, _ctor_check);
#define REGISTER_CONSTRUCTOR(_dom_constructor, _dom_class, _ctor_check) \\
aNameSpaceManager->RegisterDefineDOMInterface(MOZ_UTF16(#_dom_constructor), _dom_class##Binding::DefineDOMInterface, _ctor_check);
#define REGISTER_NAVIGATOR_CONSTRUCTOR(_prop, _dom_class, _ctor_check) \\
aNameSpaceManager->RegisterNavigatorDOMConstructor(MOZ_UTF16(_prop), _dom_class##Binding::ConstructNavigatorObject, _ctor_check);
""")
def _undefineMacro(self):
return dedent("""
#undef REGISTER_CONSTRUCTOR
#undef REGISTER_PROTO
#undef REGISTER_NAVIGATOR_CONSTRUCTOR
""")
def _registerProtos(self):
@ -13054,10 +13057,6 @@ class CGRegisterProtos(CGAbstractMethod):
lines.append("REGISTER_PROTO(%s, %s);\n" % (desc.name, getCheck(desc)))
lines.extend("REGISTER_CONSTRUCTOR(%s, %s, %s);\n" % (n.identifier.name, desc.name, getCheck(desc))
for n in desc.interface.namedConstructors)
for desc in self.config.getDescriptors(isNavigatorProperty=True, register=True):
propName = desc.interface.getNavigatorProperty()
assert propName
lines.append('REGISTER_NAVIGATOR_CONSTRUCTOR("%s", %s, %s);\n' % (propName, desc.name, getCheck(desc)))
return ''.join(lines)
def indent_body(self, body):

View File

@ -225,7 +225,7 @@ class Configuration:
elif key == 'isJSImplemented':
getter = lambda x: x.interface.isJSImplemented()
elif key == 'isNavigatorProperty':
getter = lambda x: x.interface.getNavigatorProperty() is not None
getter = lambda x: x.interface.isNavigatorProperty()
elif key == 'isExposedInAnyWorker':
getter = lambda x: x.interface.isExposedInAnyWorker()
elif key == 'isExposedInWorkerDebugger':
@ -585,6 +585,13 @@ class Descriptor(DescriptorProvider):
for attribute in ['implicitJSContext']:
addExtendedAttribute(attribute, desc.get(attribute, {}))
if self.interface.identifier.name == 'Navigator':
for m in self.interface.members:
if m.isAttr() and m.navigatorObjectGetter:
# These getters call ConstructNavigatorObject to construct
# the value, and ConstructNavigatorObject needs a JSContext.
self.extendedAttributes['all'].setdefault(m.identifier.name, []).append('implicitJSContext')
self._binaryNames = desc.get('binaryNames', {})
self._binaryNames.setdefault('__legacycaller', 'LegacyCall')
self._binaryNames.setdefault('__stringifier', 'Stringify')
@ -637,13 +644,10 @@ class Descriptor(DescriptorProvider):
if (self.interface.getExtendedAttribute("CheckAnyPermissions") or
self.interface.getExtendedAttribute("CheckAllPermissions") or
self.interface.getExtendedAttribute("AvailableIn") == "PrivilegedApps"):
if self.interface.getNavigatorProperty():
self.featureDetectibleThings.add("Navigator.%s" % self.interface.getNavigatorProperty())
else:
iface = self.interface.identifier.name
self.featureDetectibleThings.add(iface)
for m in self.interface.members:
self.featureDetectibleThings.add("%s.%s" % (iface, m.identifier.name))
iface = self.interface.identifier.name
self.featureDetectibleThings.add(iface)
for m in self.interface.members:
self.featureDetectibleThings.add("%s.%s" % (iface, m.identifier.name))
for m in self.interface.members:
if (m.getExtendedAttribute("CheckAnyPermissions") or

View File

@ -578,8 +578,8 @@ class IDLExternalInterface(IDLObjectWithIdentifier, IDLExposureMixins):
def isProbablyShortLivingObject(self):
return False
def getNavigatorProperty(self):
return None
def isNavigatorProperty(self):
return False
def _getDependentObjects(self):
return set()
@ -1240,7 +1240,7 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins):
# interface object, unless they're navigator properties.
if (self.isExposedConditionally() and
not self.hasInterfaceObject() and
not self.getNavigatorProperty()):
not self.isNavigatorProperty()):
raise WebIDLError("Interface with no interface object is "
"exposed conditionally",
[self.location])
@ -1586,6 +1586,15 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins):
current = current.parent
return False
def isNavigatorProperty(self):
naviProp = self.getExtendedAttribute("NavigatorProperty")
if not naviProp:
return False
assert len(naviProp) == 1
assert isinstance(naviProp, list)
assert len(naviProp[0]) != 0
return True
def getNavigatorProperty(self):
naviProp = self.getExtendedAttribute("NavigatorProperty")
if not naviProp:
@ -1593,7 +1602,22 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins):
assert len(naviProp) == 1
assert isinstance(naviProp, list)
assert len(naviProp[0]) != 0
return naviProp[0]
conditionExtendedAttributes = self._extendedAttrDict.viewkeys() & IDLInterface.conditionExtendedAttributes
attr = IDLAttribute(self.location,
IDLUnresolvedIdentifier(BuiltinLocation("<auto-generated-identifier>"), naviProp[0]),
IDLUnresolvedType(self.location, IDLUnresolvedIdentifier(self.location, self.identifier.name)),
True,
extendedAttrDict={ a: self._extendedAttrDict[a] for a in conditionExtendedAttributes },
navigatorObjectGetter=True)
attr._exposureGlobalNames = self._exposureGlobalNames
# We're abusing Constant a little bit here, because we need Cached. The
# getter will create a new object every time, but we're never going to
# clear the cached value.
extendedAttrs = [ IDLExtendedAttribute(self.location, ("Throws", )),
IDLExtendedAttribute(self.location, ("Cached", )),
IDLExtendedAttribute(self.location, ("Constant", )) ]
attr.addExtendedAttributes(extendedAttrs)
return attr
def hasChildInterfaces(self):
return self._hasChildInterfaces
@ -1611,13 +1635,11 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins):
def hasMembersInSlots(self):
return self._ownMembersInSlots != 0
conditionExtendedAttributes = [ "Pref", "ChromeOnly", "Func", "AvailableIn",
"CheckAnyPermissions",
"CheckAllPermissions" ]
def isExposedConditionally(self):
return (self.getExtendedAttribute("Pref") or
self.getExtendedAttribute("ChromeOnly") or
self.getExtendedAttribute("Func") or
self.getExtendedAttribute("AvailableIn") or
self.getExtendedAttribute("CheckAnyPermissions") or
self.getExtendedAttribute("CheckAllPermissions"))
return any(self.getExtendedAttribute(a) for a in self.conditionExtendedAttributes)
class IDLDictionary(IDLObjectWithScope):
@ -3372,11 +3394,14 @@ class IDLInterfaceMember(IDLObjectWithIdentifier, IDLExposureMixins):
AffectsValues = ("Nothing", "Everything")
DependsOnValues = ("Nothing", "DOMState", "DeviceState", "Everything")
def __init__(self, location, identifier, tag):
def __init__(self, location, identifier, tag, extendedAttrDict=None):
IDLObjectWithIdentifier.__init__(self, location, None, identifier)
IDLExposureMixins.__init__(self, location)
self.tag = tag
self._extendedAttrDict = {}
if extendedAttrDict is None:
self._extendedAttrDict = {}
else:
self._extendedAttrDict = extendedAttrDict
def isMethod(self):
return self.tag == IDLInterfaceMember.Tags.Method
@ -3860,9 +3885,11 @@ class IDLConst(IDLInterfaceMember):
class IDLAttribute(IDLInterfaceMember):
def __init__(self, location, identifier, type, readonly, inherit=False,
static=False, stringifier=False, maplikeOrSetlike=None):
static=False, stringifier=False, maplikeOrSetlike=None,
extendedAttrDict=None, navigatorObjectGetter=False):
IDLInterfaceMember.__init__(self, location, identifier,
IDLInterfaceMember.Tags.Attr)
IDLInterfaceMember.Tags.Attr,
extendedAttrDict=extendedAttrDict)
assert isinstance(type, IDLType)
self.type = type
@ -3879,6 +3906,7 @@ class IDLAttribute(IDLInterfaceMember):
self.maplikeOrSetlike = maplikeOrSetlike
self.dependsOn = "Everything"
self.affects = "Everything"
self.navigatorObjectGetter = navigatorObjectGetter
if static and identifier.name == "prototype":
raise WebIDLError("The identifier of a static attribute must not be 'prototype'",
@ -6595,11 +6623,26 @@ class Parser(Tokenizer):
def finish(self):
# If we have interfaces that are iterable, create their
# iterator interfaces and add them to the productions array.
interfaceStatements = [p for p in self._productions if
isinstance(p, IDLInterface)]
interfaceStatements = []
for p in self._productions:
if isinstance(p, IDLInterface):
interfaceStatements.append(p)
if p.identifier.name == "Navigator":
navigatorInterface = p
iterableIteratorIface = None
for iface in interfaceStatements:
navigatorProperty = iface.getNavigatorProperty()
if navigatorProperty:
# We're generating a partial interface to add a readonly
# property to the Navigator interface for every interface
# annotated with NavigatorProperty.
partialInterface = IDLPartialInterface(iface.location,
IDLUnresolvedIdentifier(iface.location, "Navigator"),
[ navigatorProperty ],
navigatorInterface)
self._productions.append(partialInterface)
iterable = None
# We haven't run finish() on the interface yet, so we don't know
# whether our interface is maplike/setlike/iterable or not. This

View File

@ -15,7 +15,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=707564
var isnot = parent.isnot;
addLoadEvent(function() {
var props = Object.getOwnPropertyNames(frames[0].navigator);
var props = Object.getOwnPropertyNames(Object.getPrototypeOf(frames[0].navigator));
isnot(props.indexOf("mozContacts"), -1,
"Should enumerate a mozContacts property on navigator");

View File

@ -25,7 +25,7 @@ function test()
var nav = document.getElementById("t1").contentWindow.navigator;
is(nav.foopy, undefined, "We should have an Xray now");
is(nav.wrappedJSObject.foopy, 5, "We should have the right navigator object");
var props = Object.getOwnPropertyNames(nav);
var props = Object.getOwnPropertyNames(Object.getPrototypeOf(nav));
isnot(props.indexOf("mozContacts"), -1,
"Should enumerate a mozContacts property on navigator xray");

View File

@ -9,34 +9,48 @@
<body>
<script type="application/javascript;version=1.7">
function makeIframe() {
var iframe = document.createElement('iframe');
return document.body.appendChild(iframe);
}
function destroyIframe(iframe) {
iframe.remove();
}
function test_no_interface() {
ok(!("sync" in navigator), "navigator.sync should not exist without permissions");
ok(!("syncManager" in navigator), "navigator.syncManager should not exist without permissions");
var iframe = makeIframe();
ok(!("sync" in iframe.contentWindow.navigator), "navigator.sync should not exist without permissions");
ok(!("syncManager" in iframe.contentWindow.navigator), "navigator.syncManager should not exist without permissions");
destroyIframe(iframe);
runTests();
}
function test_sync() {
ok("register" in navigator.sync, "navigator.sync.register exists");
ok("unregister" in navigator.sync, "navigator.sync.unregister exists");
ok("registrations" in navigator.sync, "navigator.sync.registrations exists");
ok("registration" in navigator.sync, "navigator.sync.registration exists");
function test_sync(win) {
ok("register" in win.navigator.sync, "navigator.sync.register exists");
ok("unregister" in win.navigator.sync, "navigator.sync.unregister exists");
ok("registrations" in win.navigator.sync, "navigator.sync.registrations exists");
ok("registration" in win.navigator.sync, "navigator.sync.registration exists");
}
function test_sync_interface() {
ok("sync" in navigator, "navigator.sync should exist with permissions");
ok(!("syncManager" in navigator), "navigator.syncManager should not exist without permissions");
var iframe = makeIframe();
ok("sync" in iframe.contentWindow.navigator, "navigator.sync should exist with permissions");
ok(!("syncManager" in iframe.contentWindow.navigator), "navigator.syncManager should not exist without permissions");
test_sync();
test_sync(iframe.contentWindow);
destroyIframe(iframe);
runTests();
}
function test_sync_manager_interface() {
ok("sync" in navigator, "navigator.sync should exist with permissions");
ok("syncManager" in navigator, "navigator.syncManager should exist with permissions");
var iframe = makeIframe();
ok("sync" in iframe.contentWindow.navigator, "navigator.sync should exist with permissions");
ok("syncManager" in iframe.contentWindow.navigator, "navigator.syncManager should exist with permissions");
test_sync();
test_sync(iframe.contentWindow);
ok("registrations" in navigator.syncManager, "navigator.syncManager.registrations exists");
ok("registrations" in iframe.contentWindow.navigator.syncManager, "navigator.syncManager.registrations exists");
destroyIframe(iframe);
runTests();
}

View File

@ -37,7 +37,7 @@ SpecialPowers.pushPermissions([
{type: "settings-api-write", allow: 0, context: document},
{type: "settings-clear", allow: 0, context: document}
], function() {
is(frames[0].navigator.mozSettings, null, "navigator.mozSettings is null when the page doesn't have permissions");
is(frames[0].navigator.mozSettings, undefined, "navigator.mozSettings is undefined when the page doesn't have permissions");
testPref();
});
</script>

View File

@ -22,8 +22,6 @@ SimpleTest.waitForExplicitFinish();
var contractId = "@mozilla.org/xmlextras/xmlhttprequest;1";
var categoryEntries = [
{category: "JavaScript-global-property", entry: "randomname", contractId: contractId},
{category: "JavaScript-navigator-property", entry: "randomname1", contractId: contractId},
{category: "JavaScript-navigator-property", entry: "randomname2", contractId: contractId},
];
function addCategoryEntries(func) {
@ -43,14 +41,10 @@ function removeCategoryEntries(func) {
function checkNamesPresent() {
ok(window.randomname, "window.randomname should return an object");
is(typeof(window.navigator.randomname1), 'object', "navigator.randomname1 should return an object");
is(typeof(window.navigator.randomname2), 'object', "navigator.randomname1 should return an object");
}
function checkNamesAbsent() {
ok(!window.randomname, "window.randomname should return undefined");
is(typeof(window.navigator.randomname1), 'undefined', "navigator.randomname1 should return undefined");
is(typeof(window.navigator.randomname2), 'undefined', "navigator.randomname1 should return undefined");
}
// Ensure the initial state
@ -58,12 +52,8 @@ checkNamesAbsent();
addCategoryEntries(function test1() {
ok(window.randomname, "window.randomname should return an object");
is(typeof(window.navigator.randomname1), 'object', "navigator.randomname1 should return an object");
is(typeof(window.navigator.randomname2), 'object', "navigator.randomname1 should return an object");
delete window.randomname;
delete window.navigator.randomname1;
delete window.navigator.randomname2;
// The delete opertor should have no effect as long as the category entry is registered.
checkNamesPresent();
@ -76,8 +66,6 @@ function test2() {
checkNamesPresent();
delete window.randomname;
delete window.navigator.randomname1;
delete window.navigator.randomname2;
// Now the delete opertor should have the effect.
checkNamesAbsent();

View File

@ -1026,7 +1026,8 @@ var interfaceNamesInGlobalScope =
// IMPORTANT: Do not change this list without review from a DOM peer!
"SettingsLock",
// IMPORTANT: Do not change this list without review from a DOM peer!
"SettingsManager",
{name: "SettingsManager",
permission: ["settings-read", "settings-write"]},
// IMPORTANT: Do not change this list without review from a DOM peer!
"ShadowRoot", // Bogus, but the test harness forces it on. See bug 1159768.
// IMPORTANT: Do not change this list without review from a DOM peer!

View File

@ -17,15 +17,11 @@ enum DownloadState {
"finalized"
};
//
// XXXTODO: When we have a generic way to do feature detection in marketplace
// we will *STOP* using the pref and use CheckAnyPermissions like
// DOMDownload and DownloadEvent.
//
[NoInterfaceObject,
NavigatorProperty="mozDownloadManager",
JSImplementation="@mozilla.org/downloads/manager;1",
Pref="dom.mozDownloads.enabled"]
Pref="dom.mozDownloads.enabled",
CheckAnyPermissions="downloads"]
interface DOMDownloadManager : EventTarget {
// This promise returns an array of downloads with all the current
// download objects.

View File

@ -20,7 +20,7 @@
*/
// http://www.whatwg.org/specs/web-apps/current-work/#the-navigator-object
[HeaderFile="Navigator.h", NeedResolve]
[HeaderFile="Navigator.h"]
interface Navigator {
// objects implementing this interface also implement the interfaces given below
};

View File

@ -30,7 +30,8 @@ callback SettingChangeCallback = void (SettingChange setting);
[JSImplementation="@mozilla.org/settingsManager;1",
NavigatorProperty="mozSettings",
Pref="dom.mozSettings.enabled"]
Pref="dom.mozSettings.enabled",
CheckAnyPermissions="settings-api-read settings-api-write"]
interface SettingsManager : EventTarget {
SettingsLock createLock();

View File

@ -20,7 +20,6 @@ PREPROCESSED_WEBIDL_FILES = [
WEBIDL_FILES = [
'AbstractWorker.webidl',
'ActivityRequestHandler.webidl',
'AlarmsManager.webidl',
'AnalyserNode.webidl',
'Animatable.webidl',
'Animation.webidl',
@ -927,3 +926,8 @@ if CONFIG['MOZ_B2G']:
GENERATED_EVENTS_WEBIDL_FILES += [
'MozApplicationEvent.webidl'
]
if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'android':
WEBIDL_FILES += [
'AlarmsManager.webidl',
]