mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-17 07:15:46 +00:00
Bug 874996 - Part 1 - Simplify handling of geolocation requests. r=jdm
Requests are now only put in the pending/watching requests arrays after they have been allowed, and are removed after being passed a single position (for getCurrentPosition) or cleared (for watchPosition). getCurrentPosition requests that are fulfilled by the cache aren't even added to the list.
This commit is contained in:
parent
b7a0d6e56a
commit
9a9b715411
@ -184,23 +184,15 @@ private:
|
||||
class RequestSendLocationEvent : public nsRunnable
|
||||
{
|
||||
public:
|
||||
// a bit funky. if locator is passed, that means this
|
||||
// event should remove the request from it. If we ever
|
||||
// have to do more, then we can change this around.
|
||||
RequestSendLocationEvent(nsIDOMGeoPosition* aPosition,
|
||||
nsGeolocationRequest* aRequest,
|
||||
Geolocation* aLocator)
|
||||
nsGeolocationRequest* aRequest)
|
||||
: mPosition(aPosition),
|
||||
mRequest(aRequest),
|
||||
mLocator(aLocator)
|
||||
mRequest(aRequest)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() {
|
||||
mRequest->SendLocation(mPosition);
|
||||
if (mLocator) {
|
||||
mLocator->RemoveRequest(mRequest);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -303,14 +295,13 @@ nsGeolocationRequest::nsGeolocationRequest(Geolocation* aLocator,
|
||||
mozilla::idl::GeoPositionOptions* aOptions,
|
||||
bool aWatchPositionRequest,
|
||||
int32_t aWatchId)
|
||||
: mAllowed(false),
|
||||
mCleared(false),
|
||||
mIsWatchPositionRequest(aWatchPositionRequest),
|
||||
: mIsWatchPositionRequest(aWatchPositionRequest),
|
||||
mCallback(aCallback),
|
||||
mErrorCallback(aErrorCallback),
|
||||
mOptions(aOptions),
|
||||
mLocator(aLocator),
|
||||
mWatchId(aWatchId)
|
||||
mWatchId(aWatchId),
|
||||
mShutdown(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -347,19 +338,13 @@ nsGeolocationRequest::NotifyError(int16_t errorCode)
|
||||
NS_IMETHODIMP
|
||||
nsGeolocationRequest::Notify(nsITimer* aTimer)
|
||||
{
|
||||
if (mCleared) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// If we haven't gotten an answer from the geolocation
|
||||
// provider yet, fire a TIMEOUT error and reset the timer.
|
||||
if (!mIsWatchPositionRequest) {
|
||||
mLocator->RemoveRequest(this);
|
||||
}
|
||||
MOZ_ASSERT(!mShutdown, "timeout after shutdown");
|
||||
|
||||
NotifyError(nsIDOMGeoPositionError::TIMEOUT);
|
||||
|
||||
if (mIsWatchPositionRequest) {
|
||||
if (!mIsWatchPositionRequest) {
|
||||
Shutdown();
|
||||
mLocator->RemoveRequest(this);
|
||||
} else if (!mShutdown) {
|
||||
SetTimeoutTimer();
|
||||
}
|
||||
|
||||
@ -413,9 +398,6 @@ nsGeolocationRequest::GetElement(nsIDOMElement * *aRequestingElement)
|
||||
NS_IMETHODIMP
|
||||
nsGeolocationRequest::Cancel()
|
||||
{
|
||||
// remove ourselves from the locators callback lists.
|
||||
mLocator->RemoveRequest(this);
|
||||
|
||||
NotifyError(nsIDOMGeoPositionError::PERMISSION_DENIED);
|
||||
return NS_OK;
|
||||
}
|
||||
@ -460,22 +442,25 @@ nsGeolocationRequest::Allow()
|
||||
}
|
||||
gs->SetHigherAccuracy(mOptions && mOptions->enableHighAccuracy);
|
||||
|
||||
if (lastPosition && maximumAge > 0 &&
|
||||
( PRTime(PR_Now() / PR_USEC_PER_MSEC) - maximumAge <=
|
||||
PRTime(cachedPositionTime) )) {
|
||||
bool canUseCache = lastPosition && maximumAge > 0 &&
|
||||
(PRTime(PR_Now() / PR_USEC_PER_MSEC) - maximumAge <=
|
||||
PRTime(cachedPositionTime));
|
||||
|
||||
if (canUseCache) {
|
||||
// okay, we can return a cached position
|
||||
mAllowed = true;
|
||||
// getCurrentPosition requests serviced by the cache
|
||||
// will now be owned by the RequestSendLocationEvent
|
||||
Update(lastPosition);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIRunnable> ev =
|
||||
new RequestSendLocationEvent(
|
||||
lastPosition, this, mIsWatchPositionRequest ? nullptr : mLocator);
|
||||
|
||||
NS_DispatchToMainThread(ev);
|
||||
if (mIsWatchPositionRequest || !canUseCache) {
|
||||
// let the locator know we're pending
|
||||
// we will now be owned by the locator
|
||||
mLocator->NotifyAllowedRequest(this);
|
||||
}
|
||||
|
||||
SetTimeoutTimer();
|
||||
|
||||
mAllowed = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -501,28 +486,14 @@ nsGeolocationRequest::SetTimeoutTimer()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsGeolocationRequest::MarkCleared()
|
||||
{
|
||||
if (mTimeoutTimer) {
|
||||
mTimeoutTimer->Cancel();
|
||||
mTimeoutTimer = nullptr;
|
||||
}
|
||||
mCleared = true;
|
||||
}
|
||||
|
||||
void
|
||||
nsGeolocationRequest::SendLocation(nsIDOMGeoPosition* aPosition)
|
||||
{
|
||||
if (mCleared || !mAllowed) {
|
||||
if (mShutdown) {
|
||||
// Ignore SendLocationEvents issued before we were cleared.
|
||||
return;
|
||||
}
|
||||
|
||||
if (mTimeoutTimer) {
|
||||
mTimeoutTimer->Cancel();
|
||||
mTimeoutTimer = nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<Position> wrapped, cachedWrapper = mLocator->GetCachedPosition();
|
||||
if (cachedWrapper && aPosition == cachedWrapper->GetWrappedGeoPosition()) {
|
||||
wrapped = cachedWrapper;
|
||||
@ -558,7 +529,9 @@ nsGeolocationRequest::SendLocation(nsIDOMGeoPosition* aPosition)
|
||||
callback->HandleEvent(aPosition);
|
||||
}
|
||||
|
||||
if (mIsWatchPositionRequest) {
|
||||
if (!mIsWatchPositionRequest) {
|
||||
Shutdown();
|
||||
} else if (!mShutdown) { // The handler may have called clearWatch
|
||||
SetTimeoutTimer();
|
||||
}
|
||||
}
|
||||
@ -572,28 +545,23 @@ nsGeolocationRequest::GetPrincipal()
|
||||
return mLocator->GetPrincipal();
|
||||
}
|
||||
|
||||
bool
|
||||
void
|
||||
nsGeolocationRequest::Update(nsIDOMGeoPosition* aPosition)
|
||||
{
|
||||
if (!mAllowed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIRunnable> ev = new RequestSendLocationEvent(aPosition,
|
||||
this,
|
||||
mIsWatchPositionRequest ? nullptr : mLocator);
|
||||
nsCOMPtr<nsIRunnable> ev = new RequestSendLocationEvent(aPosition, this);
|
||||
NS_DispatchToMainThread(ev);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
nsGeolocationRequest::Shutdown()
|
||||
{
|
||||
MOZ_ASSERT(!mShutdown, "request shutdown twice");
|
||||
mShutdown = true;
|
||||
|
||||
if (mTimeoutTimer) {
|
||||
mTimeoutTimer->Cancel();
|
||||
mTimeoutTimer = nullptr;
|
||||
}
|
||||
mCleared = true;
|
||||
|
||||
// This should happen last, to ensure that this request isn't taken into consideration
|
||||
// when deciding whether existing requests still require high accuracy.
|
||||
@ -1054,13 +1022,8 @@ Geolocation::Init(nsIDOMWindow* aContentDom)
|
||||
void
|
||||
Geolocation::Shutdown()
|
||||
{
|
||||
// Shutdown and release all callbacks
|
||||
for (uint32_t i = 0; i< mPendingCallbacks.Length(); i++)
|
||||
mPendingCallbacks[i]->Shutdown();
|
||||
// Release all callbacks
|
||||
mPendingCallbacks.Clear();
|
||||
|
||||
for (uint32_t i = 0; i< mWatchingCallbacks.Length(); i++)
|
||||
mWatchingCallbacks[i]->Shutdown();
|
||||
mWatchingCallbacks.Clear();
|
||||
|
||||
if (mService) {
|
||||
@ -1080,28 +1043,20 @@ Geolocation::GetParentObject() const {
|
||||
bool
|
||||
Geolocation::HasActiveCallbacks()
|
||||
{
|
||||
for (uint32_t i = 0; i < mWatchingCallbacks.Length(); i++) {
|
||||
if (mWatchingCallbacks[i]->IsActive()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return mPendingCallbacks.Length() != 0;
|
||||
return mPendingCallbacks.Length() || mWatchingCallbacks.Length();
|
||||
}
|
||||
|
||||
bool
|
||||
Geolocation::HighAccuracyRequested()
|
||||
{
|
||||
for (uint32_t i = 0; i < mWatchingCallbacks.Length(); i++) {
|
||||
if (mWatchingCallbacks[i]->IsActive() &&
|
||||
mWatchingCallbacks[i]->WantsHighAccuracy()) {
|
||||
if (mWatchingCallbacks[i]->WantsHighAccuracy()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < mPendingCallbacks.Length(); i++) {
|
||||
if (mPendingCallbacks[i]->IsActive() &&
|
||||
mPendingCallbacks[i]->WantsHighAccuracy()) {
|
||||
if (mPendingCallbacks[i]->WantsHighAccuracy()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -1112,15 +1067,13 @@ Geolocation::HighAccuracyRequested()
|
||||
void
|
||||
Geolocation::RemoveRequest(nsGeolocationRequest* aRequest)
|
||||
{
|
||||
mPendingCallbacks.RemoveElement(aRequest);
|
||||
bool requestWasKnown =
|
||||
(mPendingCallbacks.RemoveElement(aRequest) !=
|
||||
mWatchingCallbacks.RemoveElement(aRequest));
|
||||
|
||||
// if it is in the mWatchingCallbacks, we can't do much
|
||||
// since we passed back the position in the array to who
|
||||
// ever called WatchPosition() and we do not want to mess
|
||||
// around with the ordering of the array. Instead, just
|
||||
// mark the request as "cleared".
|
||||
|
||||
aRequest->MarkCleared();
|
||||
// request must have been in one of the lists
|
||||
MOZ_ASSERT(requestWasKnown);
|
||||
unused << requestWasKnown;
|
||||
}
|
||||
|
||||
void
|
||||
@ -1130,10 +1083,9 @@ Geolocation::Update(nsIDOMGeoPosition *aSomewhere)
|
||||
return Shutdown();
|
||||
}
|
||||
|
||||
for (uint32_t i = mPendingCallbacks.Length(); i> 0; i--) {
|
||||
if (mPendingCallbacks[i-1]->Update(aSomewhere)) {
|
||||
mPendingCallbacks.RemoveElementAt(i-1);
|
||||
}
|
||||
for (uint32_t i = mPendingCallbacks.Length(); i > 0; i--) {
|
||||
mPendingCallbacks[i-1]->Update(aSomewhere);
|
||||
RemoveRequest(mPendingCallbacks[i-1]);
|
||||
}
|
||||
|
||||
// notify everyone that is watching
|
||||
@ -1212,8 +1164,6 @@ Geolocation::GetCurrentPosition(GeoPositionCallback& callback,
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mPendingCallbacks.AppendElement(request);
|
||||
|
||||
if (sGeoInitPending) {
|
||||
PendingRequest req = { request, PendingRequest::GetCurrentPosition };
|
||||
mPendingRequests.AppendElement(req);
|
||||
@ -1301,10 +1251,6 @@ Geolocation::WatchPosition(GeoPositionCallback& aCallback,
|
||||
|
||||
if (!sGeoEnabled) {
|
||||
nsCOMPtr<nsIRunnable> ev = new RequestAllowEvent(false, request);
|
||||
|
||||
// need to hand back an index/reference.
|
||||
mWatchingCallbacks.AppendElement(request);
|
||||
|
||||
NS_DispatchToMainThread(ev);
|
||||
return NS_OK;
|
||||
}
|
||||
@ -1313,8 +1259,6 @@ Geolocation::WatchPosition(GeoPositionCallback& aCallback,
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mWatchingCallbacks.AppendElement(request);
|
||||
|
||||
if (sGeoInitPending) {
|
||||
PendingRequest req = { request, PendingRequest::WatchPosition };
|
||||
mPendingRequests.AppendElement(req);
|
||||
@ -1352,7 +1296,8 @@ Geolocation::ClearWatch(int32_t aWatchId)
|
||||
|
||||
for (uint32_t i = 0, length = mWatchingCallbacks.Length(); i < length; ++i) {
|
||||
if (mWatchingCallbacks[i]->WatchId() == aWatchId) {
|
||||
mWatchingCallbacks[i]->MarkCleared();
|
||||
mWatchingCallbacks[i]->Shutdown();
|
||||
RemoveRequest(mWatchingCallbacks[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1406,6 +1351,16 @@ Geolocation::WindowOwnerStillExists()
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
Geolocation::NotifyAllowedRequest(nsGeolocationRequest* aRequest)
|
||||
{
|
||||
if (aRequest->IsWatch()) {
|
||||
mWatchingCallbacks.AppendElement(aRequest);
|
||||
} else {
|
||||
mPendingCallbacks.AppendElement(aRequest);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Geolocation::RegisterRequestWithPrompt(nsGeolocationRequest* request)
|
||||
{
|
||||
|
@ -72,13 +72,10 @@ class nsGeolocationRequest
|
||||
void Shutdown();
|
||||
|
||||
// Called by the geolocation device to notify that a location has changed.
|
||||
bool Update(nsIDOMGeoPosition* aPosition);
|
||||
void Update(nsIDOMGeoPosition* aPosition);
|
||||
|
||||
void SendLocation(nsIDOMGeoPosition* location);
|
||||
void MarkCleared();
|
||||
bool WantsHighAccuracy() {return mOptions && mOptions->enableHighAccuracy;}
|
||||
bool IsActive() {return !mCleared;}
|
||||
bool Allowed() {return mAllowed;}
|
||||
void SetTimeoutTimer();
|
||||
nsIPrincipal* GetPrincipal();
|
||||
|
||||
@ -87,12 +84,11 @@ class nsGeolocationRequest
|
||||
virtual bool Recv__delete__(const bool& allow) MOZ_OVERRIDE;
|
||||
virtual void IPDLRelease() MOZ_OVERRIDE { Release(); }
|
||||
|
||||
bool IsWatch() { return mIsWatchPositionRequest; }
|
||||
int32_t WatchId() { return mWatchId; }
|
||||
private:
|
||||
|
||||
void NotifyError(int16_t errorCode);
|
||||
bool mAllowed;
|
||||
bool mCleared;
|
||||
bool mIsWatchPositionRequest;
|
||||
|
||||
nsCOMPtr<nsITimer> mTimeoutTimer;
|
||||
@ -103,6 +99,7 @@ class nsGeolocationRequest
|
||||
nsRefPtr<mozilla::dom::Geolocation> mLocator;
|
||||
|
||||
int32_t mWatchId;
|
||||
bool mShutdown;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -208,6 +205,9 @@ public:
|
||||
// Returns true if any of the callbacks are repeating
|
||||
bool HasActiveCallbacks();
|
||||
|
||||
// Register an allowed request
|
||||
void NotifyAllowedRequest(nsGeolocationRequest* aRequest);
|
||||
|
||||
// Remove request from all callbacks arrays
|
||||
void RemoveRequest(nsGeolocationRequest* request);
|
||||
|
||||
@ -245,7 +245,8 @@ private:
|
||||
// Two callback arrays. The first |mPendingCallbacks| holds objects for only
|
||||
// one callback and then they are released/removed from the array. The second
|
||||
// |mWatchingCallbacks| holds objects until the object is explictly removed or
|
||||
// there is a page change.
|
||||
// there is a page change. All requests held by either array are active, that
|
||||
// is, they have been allowed and expect to be fulfilled.
|
||||
|
||||
nsTArray<nsRefPtr<nsGeolocationRequest> > mPendingCallbacks;
|
||||
nsTArray<nsRefPtr<nsGeolocationRequest> > mWatchingCallbacks;
|
||||
|
Loading…
Reference in New Issue
Block a user