--- a/b2g/components/ContentPermissionPrompt.js
+++ b/b2g/components/ContentPermissionPrompt.js
@@ -217,21 +217,30 @@ ContentPermissionPrompt.prototype = {
let typesInfo = [];
let perms = request.types.QueryInterface(Ci.nsIArray);
for (let idx = 0; idx < perms.length; idx++) {
let perm = perms.queryElementAt(idx, Ci.nsIContentPermissionType);
let tmp = {
permission: perm.type,
access: (perm.access && perm.access !== "unused") ?
perm.type + "-" + perm.access : perm.type,
+ options: [],
deny: true,
action: Ci.nsIPermissionManager.UNKNOWN_ACTION
};
+
+ // Append available options, if any.
+ let options = perm.options.QueryInterface(Ci.nsIArray);
+ for (let i = 0; i < options.length; i++) {
+ let option = options.queryElementAt(i, Ci.nsISupportsString).data;
+ tmp.options.push(option);
+ }
typesInfo.push(tmp);
}
+
if (typesInfo.length == 0) {
request.cancel();
return;
}
if(!this.checkMultipleRequest(typesInfo)) {
request.cancel();
return;
@@ -304,23 +313,23 @@ ContentPermissionPrompt.prototype = {
cancelPrompt: function(request, requestId, typesInfo) {
this.sendToBrowserWindow("cancel-permission-prompt", request, requestId,
typesInfo);
},
delegatePrompt: function(request, requestId, typesInfo, callback) {
this.sendToBrowserWindow("permission-prompt", request, requestId, typesInfo,
- function(type, remember) {
+ function(type, remember, choices) {
if (type == "permission-allow") {
rememberPermission(typesInfo, request.principal, !remember);
if (callback) {
callback();
}
- request.allow();
+ request.allow(choices);
return;
}
let addDenyPermission = function(type) {
debug("add " + type.permission +
" to permission manager with DENY_ACTION");
if (remember) {
Services.perms.addFromPrincipal(request.principal, type.access,
@@ -349,30 +358,30 @@ ContentPermissionPrompt.prototype = {
if (callback) {
content.addEventListener("mozContentEvent", function contentEvent(evt) {
let detail = evt.detail;
if (detail.id != requestId)
return;
evt.target.removeEventListener(evt.type, contentEvent);
- callback(detail.type, detail.remember);
+ callback(detail.type, detail.remember, detail.choices);
})
}
let principal = request.principal;
let isApp = principal.appStatus != Ci.nsIPrincipal.APP_STATUS_NOT_INSTALLED;
let remember = (principal.appStatus == Ci.nsIPrincipal.APP_STATUS_PRIVILEGED ||
principal.appStatus == Ci.nsIPrincipal.APP_STATUS_CERTIFIED)
? true
: request.remember;
let permissions = {};
for (let i in typesInfo) {
debug("prompt " + typesInfo[i].permission);
- permissions[typesInfo[i].permission] = [];
+ permissions[typesInfo[i].permission] = typesInfo[i].options;
}
let details = {
type: type,
permissions: permissions,
id: requestId,
origin: principal.origin,
isApp: isApp,
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -11313,17 +11313,17 @@ public:
nsDocument* doc = static_cast<nsDocument*>(d.get());
if (doc->mAsyncFullscreenPending ||
(doc->mHasFullscreenApprovedObserver && !doc->mIsApprovedForFullscreen)) {
// We're still waiting for approval.
return NS_OK;
}
if (doc->mIsApprovedForFullscreen || doc->mAllowRelocking) {
- Allow();
+ Allow(JS::UndefinedHandleValue);
return NS_OK;
}
// In non-fullscreen mode user input (or chrome caller) is required!
// Also, don't let the page to try to get the permission too many times.
if (!mUserInputOrChromeCaller ||
doc->mCancelledPointerLockRequests > 2) {
Handled();
@@ -11358,18 +11358,20 @@ public:
NS_IMPL_ISUPPORTS_INHERITED1(nsPointerLockPermissionRequest,
nsRunnable,
nsIContentPermissionRequest)
NS_IMETHODIMP
nsPointerLockPermissionRequest::GetTypes(nsIArray** aTypes)
{
+ nsTArray<nsString> emptyOptions;
return CreatePermissionArray(NS_LITERAL_CSTRING("pointerLock"),
NS_LITERAL_CSTRING("unused"),
+ emptyOptions,
aTypes);
}
NS_IMETHODIMP
nsPointerLockPermissionRequest::GetPrincipal(nsIPrincipal** aPrincipal)
{
nsCOMPtr<nsIDocument> d = do_QueryReferent(mDocument);
if (d) {
@@ -11404,18 +11406,20 @@ nsPointerLockPermissionRequest::Cancel()
if (d) {
static_cast<nsDocument*>(d.get())->mCancelledPointerLockRequests++;
DispatchPointerLockError(d);
}
return NS_OK;
}
NS_IMETHODIMP
-nsPointerLockPermissionRequest::Allow()
-{
+nsPointerLockPermissionRequest::Allow(JS::HandleValue aChoices)
+{
+ MOZ_ASSERT(aChoices.isUndefined());
+
nsCOMPtr<Element> e = do_QueryReferent(mElement);
nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument);
nsDocument* d = static_cast<nsDocument*>(doc.get());
if (!e || !d || gPendingPointerLockRequest != this ||
e->GetCurrentDoc() != d ||
(!mUserInputOrChromeCaller && !d->mIsApprovedForFullscreen)) {
Handled();
DispatchPointerLockError(d);
--- a/dom/base/nsContentPermissionHelper.cpp
+++ b/dom/base/nsContentPermissionHelper.cpp
@@ -14,16 +14,19 @@
#include "mozilla/dom/PermissionMessageUtils.h"
#include "mozilla/dom/PContentPermissionRequestParent.h"
#include "mozilla/dom/TabParent.h"
#include "mozilla/unused.h"
#include "nsComponentManagerUtils.h"
#include "nsArrayUtils.h"
#include "nsIMutableArray.h"
#include "nsContentPermissionHelper.h"
+#include "nsCxPusher.h"
+#include "nsJSUtils.h"
+#include "nsISupportsPrimitives.h"
using mozilla::unused; // <snicker>
using namespace mozilla::dom;
using namespace mozilla;
namespace mozilla {
namespace dom {
@@ -89,20 +92,22 @@ ContentPermissionRequestParent::IsBeingD
// to send out any message now.
TabParent* tabParent = static_cast<TabParent*>(Manager());
return tabParent->IsDestroyed();
}
NS_IMPL_ISUPPORTS1(ContentPermissionType, nsIContentPermissionType)
ContentPermissionType::ContentPermissionType(const nsACString& aType,
- const nsACString& aAccess)
+ const nsACString& aAccess,
+ const nsTArray<nsString>& aOptions)
{
mType = aType;
mAccess = aAccess;
+ mOptions = aOptions;
}
ContentPermissionType::~ContentPermissionType()
{
}
NS_IMETHODIMP
ContentPermissionType::GetType(nsACString& aType)
@@ -113,37 +118,70 @@ ContentPermissionType::GetType(nsACStrin
NS_IMETHODIMP
ContentPermissionType::GetAccess(nsACString& aAccess)
{
aAccess = mAccess;
return NS_OK;
}
+NS_IMETHODIMP
+ContentPermissionType::GetOptions(nsIArray** aOptions)
+{
+ NS_ENSURE_ARG_POINTER(aOptions);
+
+ *aOptions = nullptr;
+
+ nsresult rv;
+ nsCOMPtr<nsIMutableArray> options =
+ do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // copy options into JS array
+ for (uint32_t i = 0; i < mOptions.Length(); ++i) {
+ nsCOMPtr<nsISupportsString> isupportsString =
+ do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = isupportsString->SetData(mOptions[i]);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = options->AppendElement(isupportsString, false);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ NS_ADDREF(*aOptions = options);
+ return NS_OK;
+}
+
uint32_t
ConvertPermissionRequestToArray(nsTArray<PermissionRequest>& aSrcArray,
nsIMutableArray* aDesArray)
{
uint32_t len = aSrcArray.Length();
for (uint32_t i = 0; i < len; i++) {
nsRefPtr<ContentPermissionType> cpt =
- new ContentPermissionType(aSrcArray[i].type(), aSrcArray[i].access());
+ new ContentPermissionType(aSrcArray[i].type(),
+ aSrcArray[i].access(),
+ aSrcArray[i].options());
aDesArray->AppendElement(cpt, false);
}
return len;
}
nsresult
CreatePermissionArray(const nsACString& aType,
const nsACString& aAccess,
+ const nsTArray<nsString>& aOptions,
nsIArray** aTypesArray)
{
nsCOMPtr<nsIMutableArray> types = do_CreateInstance(NS_ARRAY_CONTRACTID);
nsRefPtr<ContentPermissionType> permType = new ContentPermissionType(aType,
- aAccess);
+ aAccess,
+ aOptions);
types->AppendElement(permType, false);
types.forget(aTypesArray);
return NS_OK;
}
PContentPermissionRequestParent*
CreateContentPermissionRequestParent(const nsTArray<PermissionRequest>& aRequests,
@@ -243,23 +281,25 @@ nsContentPermissionRequestProxy::Cancel(
}
// Don't send out the delete message when the managing protocol (PBrowser) is
// being destroyed and PContentPermissionRequest will soon be.
if (mParent->IsBeingDestroyed()) {
return NS_ERROR_FAILURE;
}
- unused << ContentPermissionRequestParent::Send__delete__(mParent, false);
+ nsTArray<PermissionChoice> emptyChoices;
+
+ unused << ContentPermissionRequestParent::Send__delete__(mParent, false, emptyChoices);
mParent = nullptr;
return NS_OK;
}
NS_IMETHODIMP
-nsContentPermissionRequestProxy::Allow()
+nsContentPermissionRequestProxy::Allow(JS::HandleValue aChoices)
{
if (mParent == nullptr) {
return NS_ERROR_FAILURE;
}
// Don't send out the delete message when the managing protocol (PBrowser) is
// being destroyed and PContentPermissionRequest will soon be.
if (mParent->IsBeingDestroyed()) {
@@ -277,12 +317,42 @@ nsContentPermissionRequestProxy::Allow()
if (mPermissionRequests[i].type().Equals("video-capture")) {
GonkPermissionService::GetInstance()->addGrantInfo(
"android.permission.CAMERA",
static_cast<TabParent*>(mParent->Manager())->Manager()->Pid());
}
}
#endif
- unused << ContentPermissionRequestParent::Send__delete__(mParent, true);
+ nsTArray<PermissionChoice> choices;
+ if (aChoices.isNullOrUndefined()) {
+ // No choice is specified.
+ } else if (aChoices.isObject()) {
+ // Iterate through all permission types.
+ for (uint32_t i = 0; i < mPermissionRequests.Length(); ++i) {
+ nsCString type = mPermissionRequests[i].type();
+
+ mozilla::AutoSafeJSContext cx;
+ JS::Rooted<JSObject*> obj(cx, &aChoices.toObject());
+ JSAutoCompartment ac(cx, obj);
+
+ JS::Rooted<JS::Value> val(cx);
+
+ if (!JS_GetProperty(cx, obj, type.BeginReading(), &val) ||
+ !val.isString()) {
+ // no setting for the permission type, skip it
+ } else {
+ nsDependentJSString choice;
+ if (!choice.init(cx, val)) {
+ return NS_ERROR_FAILURE;
+ }
+ choices.AppendElement(PermissionChoice(type, choice));
+ }
+ }
+ } else {
+ MOZ_ASSERT(false, "SelectedChoices should be undefined or an JS object");
+ return NS_ERROR_FAILURE;
+ }
+
+ unused << ContentPermissionRequestParent::Send__delete__(mParent, true, choices);
mParent = nullptr;
return NS_OK;
}
--- a/dom/base/nsContentPermissionHelper.h
+++ b/dom/base/nsContentPermissionHelper.h
@@ -30,29 +30,33 @@ class ContentPermissionRequestParent;
class PContentPermissionRequestParent;
class ContentPermissionType : public nsIContentPermissionType
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSICONTENTPERMISSIONTYPE
- ContentPermissionType(const nsACString& aType, const nsACString& aAccess);
+ ContentPermissionType(const nsACString& aType,
+ const nsACString& aAccess,
+ const nsTArray<nsString>& aOptions);
virtual ~ContentPermissionType();
protected:
nsCString mType;
nsCString mAccess;
+ nsTArray<nsString> mOptions;
};
uint32_t ConvertPermissionRequestToArray(nsTArray<PermissionRequest>& aSrcArray,
nsIMutableArray* aDesArray);
nsresult CreatePermissionArray(const nsACString& aType,
const nsACString& aAccess,
+ const nsTArray<nsString>& aOptions,
nsIArray** aTypesArray);
PContentPermissionRequestParent*
CreateContentPermissionRequestParent(const nsTArray<PermissionRequest>& aRequests,
Element* element,
const IPC::Principal& principal);
} // namespace dom
--- a/dom/devicestorage/nsDeviceStorage.cpp
+++ b/dom/devicestorage/nsDeviceStorage.cpp
@@ -1569,20 +1569,22 @@ public:
NS_FORWARD_NSICONTENTPERMISSIONREQUEST(mCursor->);
DeviceStorageCursorRequest(nsDOMDeviceStorageCursor* aCursor)
: mCursor(aCursor) { }
~DeviceStorageCursorRequest() {}
- bool Recv__delete__(const bool& allow)
+ bool Recv__delete__(const bool& allow,
+ const InfallibleTArray<PermissionChoice>& choices)
{
+ MOZ_ASSERT(choices.IsEmpty(), "DeviceStorageCursor doesn't support permission choice");
if (allow) {
- Allow();
+ Allow(JS::UndefinedHandleValue);
}
else {
Cancel();
}
return true;
}
void IPDLRelease()
@@ -1808,17 +1810,21 @@ nsDOMDeviceStorageCursor::GetStorageType
NS_IMETHODIMP
nsDOMDeviceStorageCursor::GetTypes(nsIArray** aTypes)
{
nsCString type;
nsresult rv =
DeviceStorageTypeChecker::GetPermissionForType(mFile->mStorageType, type);
NS_ENSURE_SUCCESS(rv, rv);
- return CreatePermissionArray(type, NS_LITERAL_CSTRING("read"), aTypes);
+ nsTArray<nsString> emptyOptions;
+ return CreatePermissionArray(type,
+ NS_LITERAL_CSTRING("read"),
+ emptyOptions,
+ aTypes);
}
NS_IMETHODIMP
nsDOMDeviceStorageCursor::GetPrincipal(nsIPrincipal * *aRequestingPrincipal)
{
NS_IF_ADDREF(*aRequestingPrincipal = mPrincipal);
return NS_OK;
}
@@ -1841,18 +1847,20 @@ NS_IMETHODIMP
nsDOMDeviceStorageCursor::Cancel()
{
nsCOMPtr<PostErrorEvent> event
= new PostErrorEvent(this, POST_ERROR_EVENT_PERMISSION_DENIED);
return NS_DispatchToMainThread(event);
}
NS_IMETHODIMP
-nsDOMDeviceStorageCursor::Allow()
+nsDOMDeviceStorageCursor::Allow(JS::HandleValue aChoices)
{
+ MOZ_ASSERT(aChoices.isUndefined());
+
if (!mFile->IsSafePath()) {
nsCOMPtr<nsIRunnable> r
= new PostErrorEvent(this, POST_ERROR_EVENT_PERMISSION_DENIED);
return NS_DispatchToMainThread(r);
}
if (XRE_GetProcessType() != GeckoProcessType_Default) {
PDeviceStorageRequestChild* child
@@ -1892,20 +1900,23 @@ nsDOMDeviceStorageCursor::Continue(Error
nsCOMPtr<ContinueCursorEvent> event = new ContinueCursorEvent(this);
event->Continue();
mOkToCallContinue = false;
}
bool
-nsDOMDeviceStorageCursor::Recv__delete__(const bool& allow)
+nsDOMDeviceStorageCursor::Recv__delete__(const bool& allow,
+ const InfallibleTArray<PermissionChoice>& choices)
{
+ MOZ_ASSERT(choices.IsEmpty(), "DeviceStorageCursor doesn't support permission choice");
+
if (allow) {
- Allow();
+ Allow(JS::UndefinedHandleValue);
}
else {
Cancel();
}
return true;
}
void
@@ -2417,17 +2428,17 @@ public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(DeviceStorageRequest,
nsIContentPermissionRequest)
NS_IMETHOD Run() {
MOZ_ASSERT(NS_IsMainThread());
if (mozilla::Preferences::GetBool("device.storage.prompt.testing", false)) {
- Allow();
+ Allow(JS::UndefinedHandleValue);
return NS_OK;
}
if (XRE_GetProcessType() == GeckoProcessType_Content) {
// because owner implements nsITabChild, we can assume that it is
// the one and only TabChild.
TabChild* child = TabChild::GetFrom(mWindow->GetDocShell());
@@ -2448,17 +2459,18 @@ public:
}
nsCString access;
rv = DeviceStorageTypeChecker::GetAccessForRequest(
DeviceStorageRequestType(mRequestType), access);
if (NS_FAILED(rv)) {
return rv;
}
nsTArray<PermissionRequest> permArray;
- permArray.AppendElement(PermissionRequest(type, access));
+ nsTArray<nsString> emptyOptions;
+ permArray.AppendElement(PermissionRequest(type, access, emptyOptions));
child->SendPContentPermissionRequestConstructor(
this, permArray, IPC::Principal(mPrincipal));
Sendprompt();
return NS_OK;
}
nsCOMPtr<nsIContentPermissionPrompt> prompt
@@ -2480,17 +2492,18 @@ public:
nsCString access;
rv = DeviceStorageTypeChecker::GetAccessForRequest(
DeviceStorageRequestType(mRequestType), access);
if (NS_FAILED(rv)) {
return rv;
}
- return CreatePermissionArray(type, access, aTypes);
+ nsTArray<nsString> emptyOptions;
+ return CreatePermissionArray(type, access, emptyOptions, aTypes);
}
NS_IMETHOD GetPrincipal(nsIPrincipal * *aRequestingPrincipal)
{
NS_IF_ADDREF(*aRequestingPrincipal = mPrincipal);
return NS_OK;
}
@@ -2509,19 +2522,20 @@ public:
NS_IMETHOD Cancel()
{
nsCOMPtr<PostErrorEvent> event
= new PostErrorEvent(mRequest.forget(),
POST_ERROR_EVENT_PERMISSION_DENIED);
return NS_DispatchToMainThread(event);
}
- NS_IMETHOD Allow()
+ NS_IMETHOD Allow(JS::HandleValue aChoices)
{
MOZ_ASSERT(NS_IsMainThread());
+ MOZ_ASSERT(aChoices.isUndefined());
if (!mRequest) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIRunnable> r;
switch(mRequestType) {
@@ -2767,20 +2781,23 @@ public:
= do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
MOZ_ASSERT(target);
target->Dispatch(r, NS_DISPATCH_NORMAL);
}
return NS_OK;
}
- bool Recv__delete__(const bool& allow)
+ bool Recv__delete__(const bool& allow,
+ const InfallibleTArray<PermissionChoice>& choices)
{
+ MOZ_ASSERT(choices.IsEmpty(), "DeviceStorage doesn't support permission choice");
+
if (allow) {
- Allow();
+ Allow(JS::UndefinedHandleValue);
}
else {
Cancel();
}
return true;
}
void IPDLRelease()
@@ -3636,17 +3653,17 @@ nsDOMDeviceStorage::EnumerateInternal(co
dsf->SetEditable(aEditable);
nsRefPtr<nsDOMDeviceStorageCursor> cursor
= new nsDOMDeviceStorageCursor(win, mPrincipal, dsf, since);
nsRefPtr<DeviceStorageCursorRequest> r
= new DeviceStorageCursorRequest(cursor);
if (mozilla::Preferences::GetBool("device.storage.prompt.testing", false)) {
- r->Allow();
+ r->Allow(JS::UndefinedHandleValue);
return cursor.forget();
}
if (XRE_GetProcessType() == GeckoProcessType_Content) {
// because owner implements nsITabChild, we can assume that it is
// the one and only TabChild.
TabChild* child = TabChild::GetFrom(win->GetDocShell());
if (!child) {
@@ -3658,17 +3675,20 @@ nsDOMDeviceStorage::EnumerateInternal(co
r->AddRef();
nsCString type;
aRv = DeviceStorageTypeChecker::GetPermissionForType(mStorageType, type);
if (aRv.Failed()) {
return nullptr;
}
nsTArray<PermissionRequest> permArray;
- permArray.AppendElement(PermissionRequest(type, NS_LITERAL_CSTRING("read")));
+ nsTArray<nsString> emptyOptions;
+ permArray.AppendElement(PermissionRequest(type,
+ NS_LITERAL_CSTRING("read"),
+ emptyOptions));
child->SendPContentPermissionRequestConstructor(r,
permArray,
IPC::Principal(mPrincipal));
r->Sendprompt();
return cursor.forget();
}
--- a/dom/devicestorage/nsDeviceStorage.h
+++ b/dom/devicestorage/nsDeviceStorage.h
@@ -199,17 +199,18 @@ public:
DeviceStorageFile* aFile,
PRTime aSince);
nsTArray<nsRefPtr<DeviceStorageFile> > mFiles;
bool mOkToCallContinue;
PRTime mSince;
- virtual bool Recv__delete__(const bool& allow) MOZ_OVERRIDE;
+ virtual bool Recv__delete__(const bool& allow,
+ const InfallibleTArray<PermissionChoice>& choices) MOZ_OVERRIDE;
virtual void IPDLRelease() MOZ_OVERRIDE;
void GetStorageType(nsAString & aType);
void RequestComplete() MOZ_OVERRIDE;
private:
~nsDOMDeviceStorageCursor();
--- a/dom/interfaces/base/nsIContentPermissionPrompt.idl
+++ b/dom/interfaces/base/nsIContentPermissionPrompt.idl
@@ -7,29 +7,34 @@
interface nsIPrincipal;
interface nsIDOMWindow;
interface nsIDOMElement;
interface nsIArray;
/**
* Interface provides the request type and its access.
*/
-[scriptable, uuid(384b6cc4-a66b-4bea-98e0-eb10562a9ba4)]
+[scriptable, uuid(ef4db3b8-ca9c-4b1d-8f81-fd88ec32af13)]
interface nsIContentPermissionType : nsISupports {
/**
* The type of the permission request, such as
* "geolocation".
*/
readonly attribute ACString type;
/**
* The access of the permission request, such as
* "read".
*/
readonly attribute ACString access;
+
+ /**
+ * The array of available options.
+ */
+ readonly attribute nsIArray options; // ["choice1", "choice2"]
};
/**
* Interface allows access to a content to request
* permission to perform a privileged operation such as
* geolocation.
*/
[scriptable, uuid(69a39d88-d1c4-4ba9-9b19-bafc7a1bb783)]
@@ -54,17 +59,17 @@ interface nsIContentPermissionRequest :
readonly attribute nsIDOMWindow window;
readonly attribute nsIDOMElement element;
/**
* allow or cancel the request
*/
void cancel();
- void allow();
+ void allow([optional] in jsval choices); // {"type1": "choice1", "type2": "choiceA"}
};
/**
* Interface provides a way for the application to handle
* the UI prompts associated with geo position.
*/
[scriptable, function, uuid(F72DE90D-E954-4E69-9A61-917303029301)]
interface nsIContentPermissionPrompt : nsISupports {
--- a/dom/ipc/PContentPermission.ipdlh
+++ b/dom/ipc/PContentPermission.ipdlh
@@ -3,12 +3,18 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
namespace mozilla {
namespace dom {
struct PermissionRequest {
nsCString type;
nsCString access;
+ nsString[] options;
+};
+
+struct PermissionChoice {
+ nsCString type;
+ nsString choice;
};
} // namespace dom
} // namespace mozilla
--- a/dom/ipc/PContentPermissionRequest.ipdl
+++ b/dom/ipc/PContentPermissionRequest.ipdl
@@ -1,23 +1,24 @@
/* 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/. */
include protocol PBrowser;
+include PContentPermission;
namespace mozilla {
namespace dom {
protocol PContentPermissionRequest
{
manager PBrowser;
parent:
prompt();
child:
- __delete__(bool allow);
+ __delete__(bool allow, PermissionChoice[] choices);
};
} // namespace dom
} // namespace mozilla
--- a/dom/permission/PermissionPromptHelper.jsm
+++ b/dom/permission/PermissionPromptHelper.jsm
@@ -69,20 +69,30 @@ this.PermissionPromptHelper = {
if (permValue == Ci.nsIPermissionManager.DENY_ACTION ||
permValue == Ci.nsIPermissionManager.UNKNOWN_ACTION) {
aCallbacks.cancel();
return;
}
if (permValue == Ci.nsIPermissionManager.PROMPT_ACTION) {
+
+ // create the options from permission request.
+ let options = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
+ if (msg.options) {
+ for (let option of options) {
+ options.appendElement(option);
+ }
+ }
+
// create an array with a nsIContentPermissionType element
let type = {
type: msg.type,
access: msg.access ? msg.access : "unused",
+ options: options,
QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionType])
};
let typeArray = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
typeArray.appendElement(type, false);
// create a nsIContentPermissionRequest
let request = {
types: typeArray,
@@ -117,19 +127,20 @@ this.PermissionPromptHelper = {
let result;
if (aMessage.name == "PermissionPromptHelper:AskPermission") {
this.askPermission(aMessage, {
cancel: function() {
mm.sendAsyncMessage("PermissionPromptHelper:AskPermission:OK",
{ result: Ci.nsIPermissionManager.DENY_ACTION,
requestID: msg.requestID });
},
- allow: function() {
+ allow: function(aChoice) {
mm.sendAsyncMessage("PermissionPromptHelper:AskPermission:OK",
{ result: Ci.nsIPermissionManager.ALLOW_ACTION,
+ choice: aChoice,
requestID: msg.requestID });
}
});
}
}
}
PermissionPromptHelper.init();
--- a/dom/src/geolocation/nsGeolocation.cpp
+++ b/dom/src/geolocation/nsGeolocation.cpp
@@ -81,17 +81,18 @@ class nsGeolocationRequest
bool WantsHighAccuracy() {return !mShutdown && mOptions && mOptions->mEnableHighAccuracy;}
void SetTimeoutTimer();
void StopTimeoutTimer();
void NotifyErrorAndShutdown(uint16_t);
nsIPrincipal* GetPrincipal();
~nsGeolocationRequest();
- virtual bool Recv__delete__(const bool& allow) MOZ_OVERRIDE;
+ virtual bool Recv__delete__(const bool& allow,
+ const InfallibleTArray<PermissionChoice>& choices) MOZ_OVERRIDE;
virtual void IPDLRelease() MOZ_OVERRIDE { Release(); }
bool IsWatch() { return mIsWatchPositionRequest; }
int32_t WatchId() { return mWatchId; }
private:
bool mIsWatchPositionRequest;
nsCOMPtr<nsITimer> mTimeoutTimer;
@@ -190,17 +191,17 @@ public:
RequestAllowEvent(int allow, nsGeolocationRequest* request)
: mAllow(allow),
mRequest(request)
{
}
NS_IMETHOD Run() {
if (mAllow) {
- mRequest->Allow();
+ mRequest->Allow(JS::UndefinedHandleValue);
} else {
mRequest->Cancel();
}
return NS_OK;
}
private:
bool mAllow;
@@ -376,18 +377,20 @@ nsGeolocationRequest::GetPrincipal(nsIPr
principal.forget(aRequestingPrincipal);
return NS_OK;
}
NS_IMETHODIMP
nsGeolocationRequest::GetTypes(nsIArray** aTypes)
{
+ nsTArray<nsString> emptyOptions;
return CreatePermissionArray(NS_LITERAL_CSTRING("geolocation"),
NS_LITERAL_CSTRING("unused"),
+ emptyOptions,
aTypes);
}
NS_IMETHODIMP
nsGeolocationRequest::GetWindow(nsIDOMWindow * *aRequestingWindow)
{
NS_ENSURE_ARG_POINTER(aRequestingWindow);
@@ -408,18 +411,20 @@ nsGeolocationRequest::GetElement(nsIDOME
NS_IMETHODIMP
nsGeolocationRequest::Cancel()
{
NotifyError(nsIDOMGeoPositionError::PERMISSION_DENIED);
return NS_OK;
}
NS_IMETHODIMP
-nsGeolocationRequest::Allow()
+nsGeolocationRequest::Allow(JS::HandleValue aChoices)
{
+ MOZ_ASSERT(aChoices.isUndefined());
+
// Kick off the geo device, if it isn't already running
nsRefPtr<nsGeolocationService> gs = nsGeolocationService::GetGeolocationService();
nsresult rv = gs->StartDevice(GetPrincipal());
if (NS_FAILED(rv)) {
// Location provider error
NotifyError(nsIDOMGeoPositionError::POSITION_UNAVAILABLE);
return NS_OK;
@@ -595,20 +600,23 @@ nsGeolocationRequest::Shutdown()
if (mOptions && mOptions->mEnableHighAccuracy) {
nsRefPtr<nsGeolocationService> gs = nsGeolocationService::GetGeolocationService();
if (gs) {
gs->UpdateAccuracy();
}
}
}
-bool nsGeolocationRequest::Recv__delete__(const bool& allow)
+bool nsGeolocationRequest::Recv__delete__(const bool& allow,
+ const InfallibleTArray<PermissionChoice>& choices)
{
+ MOZ_ASSERT(choices.IsEmpty(), "Geolocation doesn't support permission choice");
+
if (allow) {
- (void) Allow();
+ (void) Allow(JS::UndefinedHandleValue);
} else {
(void) Cancel();
}
return true;
}
////////////////////////////////////////////////////
// nsGeolocationService
////////////////////////////////////////////////////
@@ -1356,17 +1364,17 @@ Geolocation::WatchPositionReady(nsGeoloc
return NS_OK;
}
if (!nsContentUtils::IsCallerChrome()) {
return NS_ERROR_FAILURE;
}
- aRequest->Allow();
+ aRequest->Allow(JS::UndefinedHandleValue);
return NS_OK;
}
NS_IMETHODIMP
Geolocation::ClearWatch(int32_t aWatchId)
{
if (aWatchId < 0) {
@@ -1467,18 +1475,20 @@ Geolocation::RegisterRequestWithPrompt(n
// because owner implements nsITabChild, we can assume that it is
// the one and only TabChild.
TabChild* child = TabChild::GetFrom(window->GetDocShell());
if (!child) {
return false;
}
nsTArray<PermissionRequest> permArray;
+ nsTArray<nsString> emptyOptions;
permArray.AppendElement(PermissionRequest(NS_LITERAL_CSTRING("geolocation"),
- NS_LITERAL_CSTRING("unused")));
+ NS_LITERAL_CSTRING("unused"),
+ emptyOptions));
// Retain a reference so the object isn't deleted without IPDL's knowledge.
// Corresponding release occurs in DeallocPContentPermissionRequest.
request->AddRef();
child->SendPContentPermissionRequestConstructor(request,
permArray,
IPC::Principal(mPrincipal));
--- a/dom/src/notification/DesktopNotification.cpp
+++ b/dom/src/notification/DesktopNotification.cpp
@@ -44,20 +44,22 @@ public:
}
return NS_OK;
}
~DesktopNotificationRequest()
{
}
- virtual bool Recv__delete__(const bool& aAllow) MOZ_OVERRIDE
+ virtual bool Recv__delete__(const bool& aAllow,
+ const InfallibleTArray<PermissionChoice>& choices) MOZ_OVERRIDE
{
+ MOZ_ASSERT(choices.IsEmpty(), "DesktopNotification doesn't support permission choice");
if (aAllow) {
- (void) Allow();
+ (void) Allow(JS::UndefinedHandleValue);
} else {
(void) Cancel();
}
return true;
}
virtual void IPDLRelease() MOZ_OVERRIDE { Release(); }
nsRefPtr<DesktopNotification> mDesktopNotification;
@@ -174,19 +176,21 @@ DesktopNotification::Init()
// the one and only TabChild for this docshell.
TabChild* child = TabChild::GetFrom(GetOwner()->GetDocShell());
// Retain a reference so the object isn't deleted without IPDL's knowledge.
// Corresponding release occurs in DeallocPContentPermissionRequest.
nsRefPtr<DesktopNotificationRequest> copy = request;
nsTArray<PermissionRequest> permArray;
+ nsTArray<nsString> emptyOptions;
permArray.AppendElement(PermissionRequest(
NS_LITERAL_CSTRING("desktop-notification"),
- NS_LITERAL_CSTRING("unused")));
+ NS_LITERAL_CSTRING("unused"),
+ emptyOptions));
child->SendPContentPermissionRequestConstructor(copy.forget().get(),
permArray,
IPC::Principal(mPrincipal));
request->Sendprompt();
return;
}
@@ -342,25 +346,28 @@ NS_IMETHODIMP
DesktopNotificationRequest::Cancel()
{
nsresult rv = mDesktopNotification->SetAllow(false);
mDesktopNotification = nullptr;
return rv;
}
NS_IMETHODIMP
-DesktopNotificationRequest::Allow()
+DesktopNotificationRequest::Allow(JS::HandleValue aChoices)
{
+ MOZ_ASSERT(aChoices.isUndefined());
nsresult rv = mDesktopNotification->SetAllow(true);
mDesktopNotification = nullptr;
return rv;
}
NS_IMETHODIMP
DesktopNotificationRequest::GetTypes(nsIArray** aTypes)
{
+ nsTArray<nsString> emptyOptions;
return CreatePermissionArray(NS_LITERAL_CSTRING("desktop-notification"),
NS_LITERAL_CSTRING("unused"),
+ emptyOptions,
aTypes);
}
} // namespace dom
} // namespace mozilla
--- a/dom/src/notification/Notification.cpp
+++ b/dom/src/notification/Notification.cpp
@@ -158,17 +158,18 @@ public:
NotificationPermissionRequest(nsIPrincipal* aPrincipal, nsPIDOMWindow* aWindow,
NotificationPermissionCallback* aCallback)
: mPrincipal(aPrincipal), mWindow(aWindow),
mPermission(NotificationPermission::Default),
mCallback(aCallback) {}
virtual ~NotificationPermissionRequest() {}
- bool Recv__delete__(const bool& aAllow);
+ bool Recv__delete__(const bool& aAllow,
+ const InfallibleTArray<PermissionChoice>& choices);
void IPDLRelease() { Release(); }
protected:
nsresult CallCallback();
nsresult DispatchCallback();
nsCOMPtr<nsIPrincipal> mPrincipal;
nsCOMPtr<nsPIDOMWindow> mWindow;
NotificationPermission mPermission;
@@ -264,19 +265,21 @@ NotificationPermissionRequest::Run()
return NS_ERROR_NOT_AVAILABLE;
}
// Retain a reference so the object isn't deleted without IPDL's knowledge.
// Corresponding release occurs in DeallocPContentPermissionRequest.
AddRef();
nsTArray<PermissionRequest> permArray;
+ nsTArray<nsString> emptyOptions;
permArray.AppendElement(PermissionRequest(
NS_LITERAL_CSTRING("desktop-notification"),
- NS_LITERAL_CSTRING("unused")));
+ NS_LITERAL_CSTRING("unused"),
+ emptyOptions));
child->SendPContentPermissionRequestConstructor(this, permArray,
IPC::Principal(mPrincipal));
Sendprompt();
return NS_OK;
}
nsCOMPtr<nsIContentPermissionPrompt> prompt =
@@ -313,18 +316,20 @@ NotificationPermissionRequest::GetElemen
NS_IMETHODIMP
NotificationPermissionRequest::Cancel()
{
mPermission = NotificationPermission::Denied;
return DispatchCallback();
}
NS_IMETHODIMP
-NotificationPermissionRequest::Allow()
+NotificationPermissionRequest::Allow(JS::HandleValue aChoices)
{
+ MOZ_ASSERT(aChoices.isUndefined());
+
mPermission = NotificationPermission::Granted;
return DispatchCallback();
}
inline nsresult
NotificationPermissionRequest::DispatchCallback()
{
if (!mCallback) {
@@ -342,26 +347,31 @@ NotificationPermissionRequest::CallCallb
ErrorResult rv;
mCallback->Call(mPermission, rv);
return rv.ErrorCode();
}
NS_IMETHODIMP
NotificationPermissionRequest::GetTypes(nsIArray** aTypes)
{
+ nsTArray<nsString> emptyOptions;
return CreatePermissionArray(NS_LITERAL_CSTRING("desktop-notification"),
NS_LITERAL_CSTRING("unused"),
+ emptyOptions,
aTypes);
}
bool
-NotificationPermissionRequest::Recv__delete__(const bool& aAllow)
+NotificationPermissionRequest::Recv__delete__(const bool& aAllow,
+ const InfallibleTArray<PermissionChoice>& choices)
{
+ MOZ_ASSERT(choices.IsEmpty(), "Notification doesn't support permission choice");
+
if (aAllow) {
- (void) Allow();
+ (void) Allow(JS::UndefinedHandleValue);
} else {
(void) Cancel();
}
return true;
}
NS_IMPL_ISUPPORTS1(NotificationTask, nsIRunnable)