dom/src/geolocation/nsGeolocation.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 #include "nsXULAppAPI.h"
     7 #include "mozilla/dom/ContentChild.h"
     8 #include "mozilla/dom/TabChild.h"
     9 #include "mozilla/Telemetry.h"
    11 #include "nsISettingsService.h"
    13 #include "nsGeolocation.h"
    14 #include "nsDOMClassInfoID.h"
    15 #include "nsComponentManagerUtils.h"
    16 #include "nsServiceManagerUtils.h"
    17 #include "nsContentUtils.h"
    18 #include "nsContentPermissionHelper.h"
    19 #include "nsIDocument.h"
    20 #include "nsIObserverService.h"
    21 #include "nsPIDOMWindow.h"
    22 #include "nsThreadUtils.h"
    23 #include "mozilla/Services.h"
    24 #include "mozilla/unused.h"
    25 #include "mozilla/Preferences.h"
    26 #include "mozilla/ClearOnShutdown.h"
    27 #include "PCOMContentPermissionRequestChild.h"
    28 #include "mozilla/dom/PermissionMessageUtils.h"
    30 class nsIPrincipal;
    32 #ifdef MOZ_ENABLE_QT5GEOPOSITION
    33 #include "QTMLocationProvider.h"
    34 #endif
    36 #ifdef MOZ_WIDGET_ANDROID
    37 #include "AndroidLocationProvider.h"
    38 #endif
    40 #ifdef MOZ_WIDGET_GONK
    41 #include "GonkGPSGeolocationProvider.h"
    42 #endif
    44 #ifdef MOZ_WIDGET_COCOA
    45 #include "CoreLocationLocationProvider.h"
    46 #endif
    48 // Some limit to the number of get or watch geolocation requests
    49 // that a window can make.
    50 #define MAX_GEO_REQUESTS_PER_WINDOW  1500
    52 // The settings key.
    53 #define GEO_SETINGS_ENABLED          "geolocation.enabled"
    55 using mozilla::unused;          // <snicker>
    56 using namespace mozilla;
    57 using namespace mozilla::dom;
    59 class nsGeolocationRequest
    60  : public nsIContentPermissionRequest
    61  , public nsITimerCallback
    62  , public nsIGeolocationUpdate
    63  , public PCOMContentPermissionRequestChild
    64 {
    65  public:
    66   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
    67   NS_DECL_NSICONTENTPERMISSIONREQUEST
    68   NS_DECL_NSITIMERCALLBACK
    69   NS_DECL_NSIGEOLOCATIONUPDATE
    71   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsGeolocationRequest, nsIContentPermissionRequest)
    73   nsGeolocationRequest(Geolocation* aLocator,
    74                        const GeoPositionCallback& aCallback,
    75                        const GeoPositionErrorCallback& aErrorCallback,
    76                        PositionOptions* aOptions,
    77                        bool aWatchPositionRequest = false,
    78                        int32_t aWatchId = 0);
    79   void Shutdown();
    81   void SendLocation(nsIDOMGeoPosition* location);
    82   bool WantsHighAccuracy() {return !mShutdown && mOptions && mOptions->mEnableHighAccuracy;}
    83   void SetTimeoutTimer();
    84   void StopTimeoutTimer();
    85   void NotifyErrorAndShutdown(uint16_t);
    86   nsIPrincipal* GetPrincipal();
    88   ~nsGeolocationRequest();
    90   virtual bool Recv__delete__(const bool& allow,
    91                               const InfallibleTArray<PermissionChoice>& choices) MOZ_OVERRIDE;
    92   virtual void IPDLRelease() MOZ_OVERRIDE { Release(); }
    94   bool IsWatch() { return mIsWatchPositionRequest; }
    95   int32_t WatchId() { return mWatchId; }
    96  private:
    97   bool mIsWatchPositionRequest;
    99   nsCOMPtr<nsITimer> mTimeoutTimer;
   100   GeoPositionCallback mCallback;
   101   GeoPositionErrorCallback mErrorCallback;
   102   nsAutoPtr<PositionOptions> mOptions;
   104   nsRefPtr<Geolocation> mLocator;
   106   int32_t mWatchId;
   107   bool mShutdown;
   108 };
   110 static PositionOptions*
   111 CreatePositionOptionsCopy(const PositionOptions& aOptions)
   112 {
   113   nsAutoPtr<PositionOptions> geoOptions(new PositionOptions());
   115   geoOptions->mEnableHighAccuracy = aOptions.mEnableHighAccuracy;
   116   geoOptions->mMaximumAge = aOptions.mMaximumAge;
   117   geoOptions->mTimeout = aOptions.mTimeout;
   119   return geoOptions.forget();
   120 }
   122 class GeolocationSettingsCallback : public nsISettingsServiceCallback
   123 {
   124 public:
   125   NS_DECL_ISUPPORTS
   127   GeolocationSettingsCallback() {
   128     MOZ_COUNT_CTOR(GeolocationSettingsCallback);
   129   }
   131   virtual ~GeolocationSettingsCallback() {
   132     MOZ_COUNT_DTOR(GeolocationSettingsCallback);
   133   }
   135   NS_IMETHOD Handle(const nsAString& aName, JS::Handle<JS::Value> aResult)
   136   {
   137     MOZ_ASSERT(NS_IsMainThread());
   139     // The geolocation is enabled by default:
   140     bool value = true;
   141     if (aResult.isBoolean()) {
   142       value = aResult.toBoolean();
   143     }
   145     MozSettingValue(value);
   146     return NS_OK;
   147   }
   149   NS_IMETHOD HandleError(const nsAString& aName)
   150   {
   151     NS_WARNING("Unable to get value for '" GEO_SETINGS_ENABLED "'");
   153     // Default it's enabled:
   154     MozSettingValue(true);
   155     return NS_OK;
   156   }
   158   void MozSettingValue(const bool aValue)
   159   {
   160     nsRefPtr<nsGeolocationService> gs = nsGeolocationService::GetGeolocationService();
   161     if (gs) {
   162       gs->HandleMozsettingValue(aValue);
   163     }
   164   }
   165 };
   167 NS_IMPL_ISUPPORTS(GeolocationSettingsCallback, nsISettingsServiceCallback)
   169 class RequestPromptEvent : public nsRunnable
   170 {
   171 public:
   172   RequestPromptEvent(nsGeolocationRequest* request)
   173     : mRequest(request)
   174   {
   175   }
   177   NS_IMETHOD Run() {
   178     nsCOMPtr<nsIContentPermissionPrompt> prompt = do_CreateInstance(NS_CONTENT_PERMISSION_PROMPT_CONTRACTID);
   179     if (prompt) {
   180       prompt->Prompt(mRequest);
   181     }
   182     return NS_OK;
   183   }
   185 private:
   186   nsRefPtr<nsGeolocationRequest> mRequest;
   187 };
   189 class RequestAllowEvent : public nsRunnable
   190 {
   191 public:
   192   RequestAllowEvent(int allow, nsGeolocationRequest* request)
   193     : mAllow(allow),
   194       mRequest(request)
   195   {
   196   }
   198   NS_IMETHOD Run() {
   199     if (mAllow) {
   200       mRequest->Allow(JS::UndefinedHandleValue);
   201     } else {
   202       mRequest->Cancel();
   203     }
   204     return NS_OK;
   205   }
   207 private:
   208   bool mAllow;
   209   nsRefPtr<nsGeolocationRequest> mRequest;
   210 };
   212 class RequestSendLocationEvent : public nsRunnable
   213 {
   214 public:
   215   RequestSendLocationEvent(nsIDOMGeoPosition* aPosition,
   216                            nsGeolocationRequest* aRequest)
   217     : mPosition(aPosition),
   218       mRequest(aRequest)
   219   {
   220   }
   222   NS_IMETHOD Run() {
   223     mRequest->SendLocation(mPosition);
   224     return NS_OK;
   225   }
   227 private:
   228   nsCOMPtr<nsIDOMGeoPosition> mPosition;
   229   nsRefPtr<nsGeolocationRequest> mRequest;
   230   nsRefPtr<Geolocation> mLocator;
   231 };
   233 ////////////////////////////////////////////////////
   234 // PositionError
   235 ////////////////////////////////////////////////////
   237 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PositionError)
   238   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   239   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMGeoPositionError)
   240   NS_INTERFACE_MAP_ENTRY(nsIDOMGeoPositionError)
   241 NS_INTERFACE_MAP_END
   243 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(PositionError, mParent)
   244 NS_IMPL_CYCLE_COLLECTING_ADDREF(PositionError)
   245 NS_IMPL_CYCLE_COLLECTING_RELEASE(PositionError)
   247 PositionError::PositionError(Geolocation* aParent, int16_t aCode)
   248   : mCode(aCode)
   249   , mParent(aParent)
   250 {
   251   SetIsDOMBinding();
   252 }
   254 PositionError::~PositionError(){}
   257 NS_IMETHODIMP
   258 PositionError::GetCode(int16_t *aCode)
   259 {
   260   NS_ENSURE_ARG_POINTER(aCode);
   261   *aCode = Code();
   262   return NS_OK;
   263 }
   265 NS_IMETHODIMP
   266 PositionError::GetMessage(nsAString& aMessage)
   267 {
   268   switch (mCode)
   269   {
   270     case nsIDOMGeoPositionError::PERMISSION_DENIED:
   271       aMessage = NS_LITERAL_STRING("User denied geolocation prompt");
   272       break;
   273     case nsIDOMGeoPositionError::POSITION_UNAVAILABLE:
   274       aMessage = NS_LITERAL_STRING("Unknown error acquiring position");
   275       break;
   276     case nsIDOMGeoPositionError::TIMEOUT:
   277       aMessage = NS_LITERAL_STRING("Position acquisition timed out");
   278       break;
   279     default:
   280       break;
   281   }
   282   return NS_OK;
   283 }
   285 Geolocation*
   286 PositionError::GetParentObject() const
   287 {
   288   return mParent;
   289 }
   291 JSObject*
   292 PositionError::WrapObject(JSContext* aCx)
   293 {
   294   return PositionErrorBinding::Wrap(aCx, this);
   295 }
   297 void
   298 PositionError::NotifyCallback(const GeoPositionErrorCallback& aCallback)
   299 {
   300   nsAutoMicroTask mt;
   301   if (aCallback.HasWebIDLCallback()) {
   302     PositionErrorCallback* callback = aCallback.GetWebIDLCallback();
   304     if (callback) {
   305       ErrorResult err;
   306       callback->Call(*this, err);
   307     }
   308   } else {
   309     nsIDOMGeoPositionErrorCallback* callback = aCallback.GetXPCOMCallback();
   310     if (callback) {
   311       callback->HandleEvent(this);
   312     }
   313   }
   314 }
   315 ////////////////////////////////////////////////////
   316 // nsGeolocationRequest
   317 ////////////////////////////////////////////////////
   319 nsGeolocationRequest::nsGeolocationRequest(Geolocation* aLocator,
   320                                            const GeoPositionCallback& aCallback,
   321                                            const GeoPositionErrorCallback& aErrorCallback,
   322                                            PositionOptions* aOptions,
   323                                            bool aWatchPositionRequest,
   324                                            int32_t aWatchId)
   325   : mIsWatchPositionRequest(aWatchPositionRequest),
   326     mCallback(aCallback),
   327     mErrorCallback(aErrorCallback),
   328     mOptions(aOptions),
   329     mLocator(aLocator),
   330     mWatchId(aWatchId),
   331     mShutdown(false)
   332 {
   333 }
   335 nsGeolocationRequest::~nsGeolocationRequest()
   336 {
   337 }
   339 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsGeolocationRequest)
   340   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContentPermissionRequest)
   341   NS_INTERFACE_MAP_ENTRY(nsIContentPermissionRequest)
   342   NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
   343   NS_INTERFACE_MAP_ENTRY(nsIGeolocationUpdate)
   344 NS_INTERFACE_MAP_END
   346 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsGeolocationRequest)
   347 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsGeolocationRequest)
   349 NS_IMPL_CYCLE_COLLECTION(nsGeolocationRequest, mCallback, mErrorCallback, mLocator)
   351 NS_IMETHODIMP
   352 nsGeolocationRequest::Notify(nsITimer* aTimer)
   353 {
   354   StopTimeoutTimer();
   355   NotifyErrorAndShutdown(nsIDOMGeoPositionError::TIMEOUT);
   356   return NS_OK;
   357 }
   359 void
   360 nsGeolocationRequest::NotifyErrorAndShutdown(uint16_t aErrorCode)
   361 {
   362   MOZ_ASSERT(!mShutdown, "timeout after shutdown");
   364   if (!mIsWatchPositionRequest) {
   365     Shutdown();
   366     mLocator->RemoveRequest(this);
   367   }
   369   NotifyError(aErrorCode);
   370 }
   372 NS_IMETHODIMP
   373 nsGeolocationRequest::GetPrincipal(nsIPrincipal * *aRequestingPrincipal)
   374 {
   375   NS_ENSURE_ARG_POINTER(aRequestingPrincipal);
   377   nsCOMPtr<nsIPrincipal> principal = mLocator->GetPrincipal();
   378   principal.forget(aRequestingPrincipal);
   380   return NS_OK;
   381 }
   383 NS_IMETHODIMP
   384 nsGeolocationRequest::GetTypes(nsIArray** aTypes)
   385 {
   386   nsTArray<nsString> emptyOptions;
   387   return CreatePermissionArray(NS_LITERAL_CSTRING("geolocation"),
   388                                NS_LITERAL_CSTRING("unused"),
   389                                emptyOptions,
   390                                aTypes);
   391 }
   393 NS_IMETHODIMP
   394 nsGeolocationRequest::GetWindow(nsIDOMWindow * *aRequestingWindow)
   395 {
   396   NS_ENSURE_ARG_POINTER(aRequestingWindow);
   398   nsCOMPtr<nsIDOMWindow> window = do_QueryReferent(mLocator->GetOwner());
   399   window.forget(aRequestingWindow);
   401   return NS_OK;
   402 }
   404 NS_IMETHODIMP
   405 nsGeolocationRequest::GetElement(nsIDOMElement * *aRequestingElement)
   406 {
   407   NS_ENSURE_ARG_POINTER(aRequestingElement);
   408   *aRequestingElement = nullptr;
   409   return NS_OK;
   410 }
   412 NS_IMETHODIMP
   413 nsGeolocationRequest::Cancel()
   414 {
   415   NotifyError(nsIDOMGeoPositionError::PERMISSION_DENIED);
   416   return NS_OK;
   417 }
   419 NS_IMETHODIMP
   420 nsGeolocationRequest::Allow(JS::HandleValue aChoices)
   421 {
   422   MOZ_ASSERT(aChoices.isUndefined());
   424   // Kick off the geo device, if it isn't already running
   425   nsRefPtr<nsGeolocationService> gs = nsGeolocationService::GetGeolocationService();
   426   nsresult rv = gs->StartDevice(GetPrincipal());
   428   if (NS_FAILED(rv)) {
   429     // Location provider error
   430     NotifyError(nsIDOMGeoPositionError::POSITION_UNAVAILABLE);
   431     return NS_OK;
   432   }
   434   nsCOMPtr<nsIDOMGeoPosition> lastPosition = gs->GetCachedPosition();
   435   DOMTimeStamp cachedPositionTime;
   436   if (lastPosition) {
   437     lastPosition->GetTimestamp(&cachedPositionTime);
   438   }
   440   // check to see if we can use a cached value
   441   // if the user has specified a maximumAge, return a cached value.
   443   uint32_t maximumAge = 0;
   444   if (mOptions) {
   445     if (mOptions->mMaximumAge > 0) {
   446       maximumAge = mOptions->mMaximumAge;
   447     }
   448   }
   449   gs->UpdateAccuracy(WantsHighAccuracy());
   451   bool canUseCache = lastPosition && maximumAge > 0 &&
   452     (PRTime(PR_Now() / PR_USEC_PER_MSEC) - maximumAge <=
   453     PRTime(cachedPositionTime));
   455   if (canUseCache) {
   456     // okay, we can return a cached position
   457     // getCurrentPosition requests serviced by the cache
   458     // will now be owned by the RequestSendLocationEvent
   459     Update(lastPosition);
   460   }
   462   if (mIsWatchPositionRequest || !canUseCache) {
   463     // let the locator know we're pending
   464     // we will now be owned by the locator
   465     mLocator->NotifyAllowedRequest(this);
   466   }
   468   SetTimeoutTimer();
   470   return NS_OK;
   471 }
   473 void
   474 nsGeolocationRequest::SetTimeoutTimer()
   475 {
   476   StopTimeoutTimer();
   478   int32_t timeout;
   479   if (mOptions && (timeout = mOptions->mTimeout) != 0) {
   481     if (timeout < 0) {
   482       timeout = 0;
   483     } else if (timeout < 10) {
   484       timeout = 10;
   485     }
   487     mTimeoutTimer = do_CreateInstance("@mozilla.org/timer;1");
   488     mTimeoutTimer->InitWithCallback(this, timeout, nsITimer::TYPE_ONE_SHOT);
   489   }
   490 }
   492 void
   493 nsGeolocationRequest::StopTimeoutTimer()
   494 {
   495   if (mTimeoutTimer) {
   496     mTimeoutTimer->Cancel();
   497     mTimeoutTimer = nullptr;
   498   }
   499 }
   501 void
   502 nsGeolocationRequest::SendLocation(nsIDOMGeoPosition* aPosition)
   503 {
   504   if (mShutdown) {
   505     // Ignore SendLocationEvents issued before we were cleared.
   506     return;
   507   }
   509   nsRefPtr<Position> wrapped, cachedWrapper = mLocator->GetCachedPosition();
   510   if (cachedWrapper && aPosition == cachedWrapper->GetWrappedGeoPosition()) {
   511     wrapped = cachedWrapper;
   512   } else if (aPosition) {
   513     nsCOMPtr<nsIDOMGeoPositionCoords> coords;
   514     aPosition->GetCoords(getter_AddRefs(coords));
   515     if (coords) {
   516       wrapped = new Position(ToSupports(mLocator), aPosition);
   517     }
   518   }
   520   if (!wrapped) {
   521     NotifyError(nsIDOMGeoPositionError::POSITION_UNAVAILABLE);
   522     return;
   523   }
   525   mLocator->SetCachedPosition(wrapped);
   526   if (!mIsWatchPositionRequest) {
   527     // Cancel timer and position updates in case the position
   528     // callback spins the event loop
   529     Shutdown();
   530   }
   532   nsAutoMicroTask mt;
   533   if (mCallback.HasWebIDLCallback()) {
   534     ErrorResult err;
   535     PositionCallback* callback = mCallback.GetWebIDLCallback();
   537     MOZ_ASSERT(callback);
   538     callback->Call(*wrapped, err);
   539   } else {
   540     nsIDOMGeoPositionCallback* callback = mCallback.GetXPCOMCallback();
   542     MOZ_ASSERT(callback);
   543     callback->HandleEvent(aPosition);
   544   }
   546   StopTimeoutTimer();
   547   MOZ_ASSERT(mShutdown || mIsWatchPositionRequest,
   548              "non-shutdown getCurrentPosition request after callback!");
   549 }
   551 nsIPrincipal*
   552 nsGeolocationRequest::GetPrincipal()
   553 {
   554   if (!mLocator) {
   555     return nullptr;
   556   }
   557   return mLocator->GetPrincipal();
   558 }
   560 NS_IMETHODIMP
   561 nsGeolocationRequest::Update(nsIDOMGeoPosition* aPosition)
   562 {
   563   nsCOMPtr<nsIRunnable> ev = new RequestSendLocationEvent(aPosition, this);
   564   NS_DispatchToMainThread(ev);
   565   return NS_OK;
   566 }
   568 NS_IMETHODIMP
   569 nsGeolocationRequest::LocationUpdatePending()
   570 {
   571   if (!mTimeoutTimer) {
   572     SetTimeoutTimer();
   573   }
   575   return NS_OK;
   576 }
   578 NS_IMETHODIMP
   579 nsGeolocationRequest::NotifyError(uint16_t aErrorCode)
   580 {
   581   MOZ_ASSERT(NS_IsMainThread());
   583   nsRefPtr<PositionError> positionError = new PositionError(mLocator, aErrorCode);
   584   positionError->NotifyCallback(mErrorCallback);
   585   return NS_OK;
   586 }
   588 void
   589 nsGeolocationRequest::Shutdown()
   590 {
   591   MOZ_ASSERT(!mShutdown, "request shutdown twice");
   592   mShutdown = true;
   594   if (mTimeoutTimer) {
   595     mTimeoutTimer->Cancel();
   596     mTimeoutTimer = nullptr;
   597   }
   599   // If there are no other high accuracy requests, the geolocation service will
   600   // notify the provider to switch to the default accuracy.
   601   if (mOptions && mOptions->mEnableHighAccuracy) {
   602     nsRefPtr<nsGeolocationService> gs = nsGeolocationService::GetGeolocationService();
   603     if (gs) {
   604       gs->UpdateAccuracy();
   605     }
   606   }
   607 }
   609 bool nsGeolocationRequest::Recv__delete__(const bool& allow,
   610                                           const InfallibleTArray<PermissionChoice>& choices)
   611 {
   612   MOZ_ASSERT(choices.IsEmpty(), "Geolocation doesn't support permission choice");
   614   if (allow) {
   615     (void) Allow(JS::UndefinedHandleValue);
   616   } else {
   617     (void) Cancel();
   618   }
   619   return true;
   620 }
   621 ////////////////////////////////////////////////////
   622 // nsGeolocationService
   623 ////////////////////////////////////////////////////
   624 NS_INTERFACE_MAP_BEGIN(nsGeolocationService)
   625   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIGeolocationUpdate)
   626   NS_INTERFACE_MAP_ENTRY(nsIGeolocationUpdate)
   627   NS_INTERFACE_MAP_ENTRY(nsIObserver)
   628 NS_INTERFACE_MAP_END
   630 NS_IMPL_ADDREF(nsGeolocationService)
   631 NS_IMPL_RELEASE(nsGeolocationService)
   634 static bool sGeoEnabled = true;
   635 static bool sGeoInitPending = true;
   636 static int32_t sProviderTimeout = 6000; // Time, in milliseconds, to wait for the location provider to spin up.
   638 nsresult nsGeolocationService::Init()
   639 {
   640   Preferences::AddIntVarCache(&sProviderTimeout, "geo.timeout", sProviderTimeout);
   641   Preferences::AddBoolVarCache(&sGeoEnabled, "geo.enabled", sGeoEnabled);
   643   if (!sGeoEnabled) {
   644     return NS_ERROR_FAILURE;
   645   }
   647   if (XRE_GetProcessType() == GeckoProcessType_Content) {
   648     sGeoInitPending = false;
   649     return NS_OK;
   650   }
   652   // check if the geolocation service is enable from settings
   653   nsCOMPtr<nsISettingsService> settings =
   654     do_GetService("@mozilla.org/settingsService;1");
   656   if (settings) {
   657     nsCOMPtr<nsISettingsServiceLock> settingsLock;
   658     nsresult rv = settings->CreateLock(nullptr, getter_AddRefs(settingsLock));
   659     NS_ENSURE_SUCCESS(rv, rv);
   661     nsRefPtr<GeolocationSettingsCallback> callback = new GeolocationSettingsCallback();
   662     rv = settingsLock->Get(GEO_SETINGS_ENABLED, callback);
   663     NS_ENSURE_SUCCESS(rv, rv);
   664   } else {
   665     // If we cannot obtain the settings service, we continue
   666     // assuming that the geolocation is enabled:
   667     sGeoInitPending = false;
   668   }
   670   // geolocation service can be enabled -> now register observer
   671   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
   672   if (!obs) {
   673     return NS_ERROR_FAILURE;
   674   }
   676   obs->AddObserver(this, "quit-application", false);
   677   obs->AddObserver(this, "mozsettings-changed", false);
   679 #ifdef MOZ_ENABLE_QT5GEOPOSITION
   680   mProvider = new QTMLocationProvider();
   681 #endif
   683 #ifdef MOZ_WIDGET_ANDROID
   684   mProvider = new AndroidLocationProvider();
   685 #endif
   687 #ifdef MOZ_WIDGET_GONK
   688   // GonkGPSGeolocationProvider can be started at boot up time for initialization reasons.
   689   // do_getService gets hold of the already initialized component and starts
   690   // processing location requests immediately.
   691   // do_Createinstance will create multiple instances of the provider which is not right.
   692   // bug 993041
   693   mProvider = do_GetService(GONK_GPS_GEOLOCATION_PROVIDER_CONTRACTID);
   694 #endif
   696 #ifdef MOZ_WIDGET_COCOA
   697   if (Preferences::GetBool("geo.provider.use_corelocation", false)) {
   698     mProvider = new CoreLocationLocationProvider();
   699   }
   700 #endif
   702   if (Preferences::GetBool("geo.provider.use_mls", false)) {
   703     mProvider = do_CreateInstance("@mozilla.org/geolocation/mls-provider;1");
   704   }
   706   // Override platform-specific providers with the default (network)
   707   // provider while testing. Our tests are currently not meant to exercise
   708   // the provider, and some tests rely on the network provider being used.
   709   // "geo.provider.testing" is always set for all plain and browser chrome
   710   // mochitests, and also for xpcshell tests.
   711   if (!mProvider || Preferences::GetBool("geo.provider.testing", false)) {
   712     nsCOMPtr<nsIGeolocationProvider> override =
   713       do_GetService(NS_GEOLOCATION_PROVIDER_CONTRACTID);
   715     if (override) {
   716       mProvider = override;
   717     }
   718   }
   720   return NS_OK;
   721 }
   723 nsGeolocationService::~nsGeolocationService()
   724 {
   725 }
   727 void
   728 nsGeolocationService::HandleMozsettingChanged(const char16_t* aData)
   729 {
   730     // The string that we're interested in will be a JSON string that looks like:
   731     //  {"key":"gelocation.enabled","value":true}
   733     AutoSafeJSContext cx;
   735     nsDependentString dataStr(aData);
   736     JS::Rooted<JS::Value> val(cx);
   737     if (!JS_ParseJSON(cx, dataStr.get(), dataStr.Length(), &val) || !val.isObject()) {
   738       return;
   739     }
   741     JS::Rooted<JSObject*> obj(cx, &val.toObject());
   742     JS::Rooted<JS::Value> key(cx);
   743     if (!JS_GetProperty(cx, obj, "key", &key) || !key.isString()) {
   744       return;
   745     }
   747     bool match;
   748     if (!JS_StringEqualsAscii(cx, key.toString(), GEO_SETINGS_ENABLED, &match) || !match) {
   749       return;
   750     }
   752     JS::Rooted<JS::Value> value(cx);
   753     if (!JS_GetProperty(cx, obj, "value", &value) || !value.isBoolean()) {
   754       return;
   755     }
   757     HandleMozsettingValue(value.toBoolean());
   758 }
   760 void
   761 nsGeolocationService::HandleMozsettingValue(const bool aValue)
   762 {
   763     if (!aValue) {
   764       // turn things off
   765       StopDevice();
   766       Update(nullptr);
   767       mLastPosition = nullptr;
   768       sGeoEnabled = false;
   769     } else {
   770       sGeoEnabled = true;
   771     }
   773     if (sGeoInitPending) {
   774       sGeoInitPending = false;
   775       for (uint32_t i = 0, length = mGeolocators.Length(); i < length; ++i) {
   776         mGeolocators[i]->ServiceReady();
   777       }
   778     }
   779 }
   781 NS_IMETHODIMP
   782 nsGeolocationService::Observe(nsISupports* aSubject,
   783                               const char* aTopic,
   784                               const char16_t* aData)
   785 {
   786   if (!strcmp("quit-application", aTopic)) {
   787     nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
   788     if (obs) {
   789       obs->RemoveObserver(this, "quit-application");
   790       obs->RemoveObserver(this, "mozsettings-changed");
   791     }
   793     for (uint32_t i = 0; i< mGeolocators.Length(); i++) {
   794       mGeolocators[i]->Shutdown();
   795     }
   796     StopDevice();
   798     return NS_OK;
   799   }
   801   if (!strcmp("mozsettings-changed", aTopic)) {
   802     HandleMozsettingChanged(aData);
   803     return NS_OK;
   804   }
   806   if (!strcmp("timer-callback", aTopic)) {
   807     // decide if we can close down the service.
   808     for (uint32_t i = 0; i< mGeolocators.Length(); i++)
   809       if (mGeolocators[i]->HasActiveCallbacks()) {
   810         SetDisconnectTimer();
   811         return NS_OK;
   812       }
   814     // okay to close up.
   815     StopDevice();
   816     Update(nullptr);
   817     return NS_OK;
   818   }
   820   return NS_ERROR_FAILURE;
   821 }
   823 NS_IMETHODIMP
   824 nsGeolocationService::Update(nsIDOMGeoPosition *aSomewhere)
   825 {
   826   SetCachedPosition(aSomewhere);
   828   for (uint32_t i = 0; i< mGeolocators.Length(); i++) {
   829     mGeolocators[i]->Update(aSomewhere);
   830   }
   831   return NS_OK;
   832 }
   834 NS_IMETHODIMP
   835 nsGeolocationService::LocationUpdatePending()
   836 {
   837   for (uint32_t i = 0; i< mGeolocators.Length(); i++) {
   838     mGeolocators[i]->LocationUpdatePending();
   839   }
   841   return NS_OK;
   842 }
   844 NS_IMETHODIMP
   845 nsGeolocationService::NotifyError(uint16_t aErrorCode)
   846 {
   847   for (uint32_t i = 0; i < mGeolocators.Length(); i++) {
   848     mGeolocators[i]->NotifyError(aErrorCode);
   849   }
   851   return NS_OK;
   852 }
   854 void
   855 nsGeolocationService::SetCachedPosition(nsIDOMGeoPosition* aPosition)
   856 {
   857   mLastPosition = aPosition;
   858 }
   860 nsIDOMGeoPosition*
   861 nsGeolocationService::GetCachedPosition()
   862 {
   863   return mLastPosition;
   864 }
   866 nsresult
   867 nsGeolocationService::StartDevice(nsIPrincipal *aPrincipal)
   868 {
   869   if (!sGeoEnabled || sGeoInitPending) {
   870     return NS_ERROR_NOT_AVAILABLE;
   871   }
   873   // we do not want to keep the geolocation devices online
   874   // indefinitely.  Close them down after a reasonable period of
   875   // inactivivity
   876   SetDisconnectTimer();
   878   if (XRE_GetProcessType() == GeckoProcessType_Content) {
   879     ContentChild* cpc = ContentChild::GetSingleton();
   880     cpc->SendAddGeolocationListener(IPC::Principal(aPrincipal),
   881                                     HighAccuracyRequested());
   882     return NS_OK;
   883   }
   885   // Start them up!
   886   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
   887   if (!obs) {
   888     return NS_ERROR_FAILURE;
   889   }
   891   if (!mProvider) {
   892     return NS_ERROR_FAILURE;
   893   }
   895   nsresult rv;
   897   if (NS_FAILED(rv = mProvider->Startup()) ||
   898       NS_FAILED(rv = mProvider->Watch(this))) {
   900     NotifyError(nsIDOMGeoPositionError::POSITION_UNAVAILABLE);
   901     return rv;
   902   }
   904   obs->NotifyObservers(mProvider,
   905                        "geolocation-device-events",
   906                        MOZ_UTF16("starting"));
   908   return NS_OK;
   909 }
   911 void
   912 nsGeolocationService::SetDisconnectTimer()
   913 {
   914   if (!mDisconnectTimer) {
   915     mDisconnectTimer = do_CreateInstance("@mozilla.org/timer;1");
   916   } else {
   917     mDisconnectTimer->Cancel();
   918   }
   920   mDisconnectTimer->Init(this,
   921                          sProviderTimeout,
   922                          nsITimer::TYPE_ONE_SHOT);
   923 }
   925 bool
   926 nsGeolocationService::HighAccuracyRequested()
   927 {
   928   for (uint32_t i = 0; i < mGeolocators.Length(); i++) {
   929     if (mGeolocators[i]->HighAccuracyRequested()) {
   930       return true;
   931     }
   932   }
   933   return false;
   934 }
   936 void
   937 nsGeolocationService::UpdateAccuracy(bool aForceHigh)
   938 {
   939   bool highRequired = aForceHigh || HighAccuracyRequested();
   941   if (XRE_GetProcessType() == GeckoProcessType_Content) {
   942     ContentChild* cpc = ContentChild::GetSingleton();
   943     cpc->SendSetGeolocationHigherAccuracy(highRequired);
   944     return;
   945   }
   947   if (!mHigherAccuracy && highRequired) {
   948       mProvider->SetHighAccuracy(true);
   949   }
   951   if (mHigherAccuracy && !highRequired) {
   952       mProvider->SetHighAccuracy(false);
   953   }
   955   mHigherAccuracy = highRequired;
   956 }
   958 void
   959 nsGeolocationService::StopDevice()
   960 {
   961   if(mDisconnectTimer) {
   962     mDisconnectTimer->Cancel();
   963     mDisconnectTimer = nullptr;
   964   }
   966   if (XRE_GetProcessType() == GeckoProcessType_Content) {
   967     ContentChild* cpc = ContentChild::GetSingleton();
   968     cpc->SendRemoveGeolocationListener();
   969     return; // bail early
   970   }
   972   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
   973   if (!obs) {
   974     return;
   975   }
   977   if (!mProvider) {
   978     return;
   979   }
   981   mHigherAccuracy = false;
   983   mProvider->Shutdown();
   984   obs->NotifyObservers(mProvider,
   985                        "geolocation-device-events",
   986                        MOZ_UTF16("shutdown"));
   987 }
   989 StaticRefPtr<nsGeolocationService> nsGeolocationService::sService;
   991 already_AddRefed<nsGeolocationService>
   992 nsGeolocationService::GetGeolocationService()
   993 {
   994   nsRefPtr<nsGeolocationService> result;
   995   if (nsGeolocationService::sService) {
   996     result = nsGeolocationService::sService;
   997     return result.forget();
   998   }
  1000   result = new nsGeolocationService();
  1001   if (NS_FAILED(result->Init())) {
  1002     return nullptr;
  1004   ClearOnShutdown(&nsGeolocationService::sService);
  1005   nsGeolocationService::sService = result;
  1006   return result.forget();
  1009 void
  1010 nsGeolocationService::AddLocator(Geolocation* aLocator)
  1012   mGeolocators.AppendElement(aLocator);
  1015 void
  1016 nsGeolocationService::RemoveLocator(Geolocation* aLocator)
  1018   mGeolocators.RemoveElement(aLocator);
  1021 ////////////////////////////////////////////////////
  1022 // Geolocation
  1023 ////////////////////////////////////////////////////
  1025 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Geolocation)
  1026   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
  1027   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMGeoGeolocation)
  1028   NS_INTERFACE_MAP_ENTRY(nsIDOMGeoGeolocation)
  1029   NS_INTERFACE_MAP_ENTRY(nsIGeolocationUpdate)
  1030 NS_INTERFACE_MAP_END
  1032 NS_IMPL_CYCLE_COLLECTING_ADDREF(Geolocation)
  1033 NS_IMPL_CYCLE_COLLECTING_RELEASE(Geolocation)
  1035 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_4(Geolocation,
  1036                                         mCachedPosition,
  1037                                         mPendingCallbacks,
  1038                                         mWatchingCallbacks,
  1039                                         mPendingRequests)
  1041 Geolocation::Geolocation()
  1042 : mLastWatchId(0)
  1044   SetIsDOMBinding();
  1047 Geolocation::~Geolocation()
  1049   if (mService) {
  1050     Shutdown();
  1054 nsresult
  1055 Geolocation::Init(nsIDOMWindow* aContentDom)
  1057   // Remember the window
  1058   if (aContentDom) {
  1059     nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aContentDom);
  1060     if (!window) {
  1061       return NS_ERROR_FAILURE;
  1064     mOwner = do_GetWeakReference(window->GetCurrentInnerWindow());
  1065     if (!mOwner) {
  1066       return NS_ERROR_FAILURE;
  1069     // Grab the principal of the document
  1070     nsCOMPtr<nsIDocument> doc = window->GetDoc();
  1071     if (!doc) {
  1072       return NS_ERROR_FAILURE;
  1075     mPrincipal = doc->NodePrincipal();
  1078   // If no aContentDom was passed into us, we are being used
  1079   // by chrome/c++ and have no mOwner, no mPrincipal, and no need
  1080   // to prompt.
  1081   mService = nsGeolocationService::GetGeolocationService();
  1082   if (mService) {
  1083     mService->AddLocator(this);
  1085   return NS_OK;
  1088 void
  1089 Geolocation::Shutdown()
  1091   // Release all callbacks
  1092   mPendingCallbacks.Clear();
  1093   mWatchingCallbacks.Clear();
  1095   if (mService) {
  1096     mService->RemoveLocator(this);
  1097     mService->UpdateAccuracy();
  1100   mService = nullptr;
  1101   mPrincipal = nullptr;
  1104 nsIDOMWindow*
  1105 Geolocation::GetParentObject() const {
  1106   nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mOwner);
  1107   return window.get();
  1110 bool
  1111 Geolocation::HasActiveCallbacks()
  1113   return mPendingCallbacks.Length() || mWatchingCallbacks.Length();
  1116 bool
  1117 Geolocation::HighAccuracyRequested()
  1119   for (uint32_t i = 0; i < mWatchingCallbacks.Length(); i++) {
  1120     if (mWatchingCallbacks[i]->WantsHighAccuracy()) {
  1121       return true;
  1125   for (uint32_t i = 0; i < mPendingCallbacks.Length(); i++) {
  1126     if (mPendingCallbacks[i]->WantsHighAccuracy()) {
  1127       return true;
  1131   return false;
  1134 void
  1135 Geolocation::RemoveRequest(nsGeolocationRequest* aRequest)
  1137   bool requestWasKnown =
  1138     (mPendingCallbacks.RemoveElement(aRequest) !=
  1139      mWatchingCallbacks.RemoveElement(aRequest));
  1141   unused << requestWasKnown;
  1144 NS_IMETHODIMP
  1145 Geolocation::Update(nsIDOMGeoPosition *aSomewhere)
  1147   if (!WindowOwnerStillExists()) {
  1148     Shutdown();
  1149     return NS_OK;
  1152   if (aSomewhere) {
  1153     nsCOMPtr<nsIDOMGeoPositionCoords> coords;
  1154     aSomewhere->GetCoords(getter_AddRefs(coords));
  1155     if (coords) {
  1156       double accuracy = -1;
  1157       coords->GetAccuracy(&accuracy);
  1158       mozilla::Telemetry::Accumulate(mozilla::Telemetry::GEOLOCATION_ACCURACY, accuracy);
  1162   for (uint32_t i = mPendingCallbacks.Length(); i > 0; i--) {
  1163     mPendingCallbacks[i-1]->Update(aSomewhere);
  1164     RemoveRequest(mPendingCallbacks[i-1]);
  1167   // notify everyone that is watching
  1168   for (uint32_t i = 0; i < mWatchingCallbacks.Length(); i++) {
  1169     mWatchingCallbacks[i]->Update(aSomewhere);
  1172   return NS_OK;
  1175 NS_IMETHODIMP
  1176 Geolocation::LocationUpdatePending()
  1178   // this event is only really interesting for watch callbacks
  1179   for (uint32_t i = 0; i < mWatchingCallbacks.Length(); i++) {
  1180     mWatchingCallbacks[i]->LocationUpdatePending();
  1183   return NS_OK;
  1186 NS_IMETHODIMP
  1187 Geolocation::NotifyError(uint16_t aErrorCode)
  1189   if (!WindowOwnerStillExists()) {
  1190     Shutdown();
  1191     return NS_OK;
  1194   mozilla::Telemetry::Accumulate(mozilla::Telemetry::GEOLOCATION_ERROR, true);
  1196   for (uint32_t i = mPendingCallbacks.Length(); i > 0; i--) {
  1197     mPendingCallbacks[i-1]->NotifyErrorAndShutdown(aErrorCode);
  1198     //NotifyErrorAndShutdown() removes the request from the array
  1201   // notify everyone that is watching
  1202   for (uint32_t i = 0; i < mWatchingCallbacks.Length(); i++) {
  1203     mWatchingCallbacks[i]->NotifyErrorAndShutdown(aErrorCode);
  1206   return NS_OK;
  1209 void
  1210 Geolocation::SetCachedPosition(Position* aPosition)
  1212   mCachedPosition = aPosition;
  1215 Position*
  1216 Geolocation::GetCachedPosition()
  1218   return mCachedPosition;
  1221 void
  1222 Geolocation::GetCurrentPosition(PositionCallback& aCallback,
  1223                                 PositionErrorCallback* aErrorCallback,
  1224                                 const PositionOptions& aOptions,
  1225                                 ErrorResult& aRv)
  1227   GeoPositionCallback successCallback(&aCallback);
  1228   GeoPositionErrorCallback errorCallback(aErrorCallback);
  1230   nsresult rv = GetCurrentPosition(successCallback, errorCallback,
  1231                                    CreatePositionOptionsCopy(aOptions));
  1233   if (NS_FAILED(rv)) {
  1234     aRv.Throw(rv);
  1237   return;
  1240 NS_IMETHODIMP
  1241 Geolocation::GetCurrentPosition(nsIDOMGeoPositionCallback* aCallback,
  1242                                 nsIDOMGeoPositionErrorCallback* aErrorCallback,
  1243                                 PositionOptions* aOptions)
  1245   NS_ENSURE_ARG_POINTER(aCallback);
  1247   GeoPositionCallback successCallback(aCallback);
  1248   GeoPositionErrorCallback errorCallback(aErrorCallback);
  1250   return GetCurrentPosition(successCallback, errorCallback, aOptions);
  1253 nsresult
  1254 Geolocation::GetCurrentPosition(GeoPositionCallback& callback,
  1255                                 GeoPositionErrorCallback& errorCallback,
  1256                                 PositionOptions *options)
  1258   if (mPendingCallbacks.Length() > MAX_GEO_REQUESTS_PER_WINDOW) {
  1259     return NS_ERROR_NOT_AVAILABLE;
  1262   nsRefPtr<nsGeolocationRequest> request = new nsGeolocationRequest(this,
  1263                                                                     callback,
  1264                                                                     errorCallback,
  1265                                                                     options,
  1266                                                                     false);
  1268   if (!sGeoEnabled) {
  1269     nsCOMPtr<nsIRunnable> ev = new RequestAllowEvent(false, request);
  1270     NS_DispatchToMainThread(ev);
  1271     return NS_OK;
  1274   if (!mOwner && !nsContentUtils::IsCallerChrome()) {
  1275     return NS_ERROR_FAILURE;
  1278   if (sGeoInitPending) {
  1279     mPendingRequests.AppendElement(request);
  1280     return NS_OK;
  1283   return GetCurrentPositionReady(request);
  1286 nsresult
  1287 Geolocation::GetCurrentPositionReady(nsGeolocationRequest* aRequest)
  1289   if (mOwner) {
  1290     if (!RegisterRequestWithPrompt(aRequest)) {
  1291       return NS_ERROR_NOT_AVAILABLE;
  1294     return NS_OK;
  1297   if (!nsContentUtils::IsCallerChrome()) {
  1298     return NS_ERROR_FAILURE;
  1301   nsCOMPtr<nsIRunnable> ev = new RequestAllowEvent(true, aRequest);
  1302   NS_DispatchToMainThread(ev);
  1304   return NS_OK;
  1307 int32_t
  1308 Geolocation::WatchPosition(PositionCallback& aCallback,
  1309                            PositionErrorCallback* aErrorCallback,
  1310                            const PositionOptions& aOptions,
  1311                            ErrorResult& aRv)
  1313   int32_t ret;
  1314   GeoPositionCallback successCallback(&aCallback);
  1315   GeoPositionErrorCallback errorCallback(aErrorCallback);
  1317   nsresult rv = WatchPosition(successCallback, errorCallback,
  1318                               CreatePositionOptionsCopy(aOptions), &ret);
  1320   if (NS_FAILED(rv)) {
  1321     aRv.Throw(rv);
  1324   return ret;
  1327 NS_IMETHODIMP
  1328 Geolocation::WatchPosition(nsIDOMGeoPositionCallback *aCallback,
  1329                            nsIDOMGeoPositionErrorCallback *aErrorCallback,
  1330                            PositionOptions *aOptions,
  1331                            int32_t* aRv)
  1333   NS_ENSURE_ARG_POINTER(aCallback);
  1335   GeoPositionCallback successCallback(aCallback);
  1336   GeoPositionErrorCallback errorCallback(aErrorCallback);
  1338   return WatchPosition(successCallback, errorCallback, aOptions, aRv);
  1341 nsresult
  1342 Geolocation::WatchPosition(GeoPositionCallback& aCallback,
  1343                            GeoPositionErrorCallback& aErrorCallback,
  1344                            PositionOptions* aOptions,
  1345                            int32_t* aRv)
  1347   if (mWatchingCallbacks.Length() > MAX_GEO_REQUESTS_PER_WINDOW) {
  1348     return NS_ERROR_NOT_AVAILABLE;
  1351   // The watch ID:
  1352   *aRv = mLastWatchId++;
  1354   nsRefPtr<nsGeolocationRequest> request = new nsGeolocationRequest(this,
  1355                                                                     aCallback,
  1356                                                                     aErrorCallback,
  1357                                                                     aOptions,
  1358                                                                     true,
  1359                                                                     *aRv);
  1361   if (!sGeoEnabled) {
  1362     nsCOMPtr<nsIRunnable> ev = new RequestAllowEvent(false, request);
  1363     NS_DispatchToMainThread(ev);
  1364     return NS_OK;
  1367   if (!mOwner && !nsContentUtils::IsCallerChrome()) {
  1368     return NS_ERROR_FAILURE;
  1371   if (sGeoInitPending) {
  1372     mPendingRequests.AppendElement(request);
  1373     return NS_OK;
  1376   return WatchPositionReady(request);
  1379 nsresult
  1380 Geolocation::WatchPositionReady(nsGeolocationRequest* aRequest)
  1382   if (mOwner) {
  1383     if (!RegisterRequestWithPrompt(aRequest))
  1384       return NS_ERROR_NOT_AVAILABLE;
  1386     return NS_OK;
  1389   if (!nsContentUtils::IsCallerChrome()) {
  1390     return NS_ERROR_FAILURE;
  1393   aRequest->Allow(JS::UndefinedHandleValue);
  1395   return NS_OK;
  1398 NS_IMETHODIMP
  1399 Geolocation::ClearWatch(int32_t aWatchId)
  1401   if (aWatchId < 0) {
  1402     return NS_OK;
  1405   for (uint32_t i = 0, length = mWatchingCallbacks.Length(); i < length; ++i) {
  1406     if (mWatchingCallbacks[i]->WatchId() == aWatchId) {
  1407       mWatchingCallbacks[i]->Shutdown();
  1408       RemoveRequest(mWatchingCallbacks[i]);
  1409       break;
  1413   // make sure we also search through the pending requests lists for
  1414   // watches to clear...
  1415   for (uint32_t i = 0, length = mPendingRequests.Length(); i < length; ++i) {
  1416     if (mPendingRequests[i]->IsWatch() &&
  1417         (mPendingRequests[i]->WatchId() == aWatchId)) {
  1418       mPendingRequests[i]->Shutdown();
  1419       mPendingRequests.RemoveElementAt(i);
  1420       break;
  1424   return NS_OK;
  1427 void
  1428 Geolocation::ServiceReady()
  1430   for (uint32_t length = mPendingRequests.Length(); length > 0; --length) {
  1431     if (mPendingRequests[0]->IsWatch()) {
  1432       WatchPositionReady(mPendingRequests[0]);
  1433     } else {
  1434       GetCurrentPositionReady(mPendingRequests[0]);
  1437     mPendingRequests.RemoveElementAt(0);
  1441 bool
  1442 Geolocation::WindowOwnerStillExists()
  1444   // an owner was never set when Geolocation
  1445   // was created, which means that this object
  1446   // is being used without a window.
  1447   if (mOwner == nullptr) {
  1448     return true;
  1451   nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mOwner);
  1453   if (window) {
  1454     bool closed = false;
  1455     window->GetClosed(&closed);
  1456     if (closed) {
  1457       return false;
  1460     nsPIDOMWindow* outer = window->GetOuterWindow();
  1461     if (!outer || outer->GetCurrentInnerWindow() != window) {
  1462       return false;
  1466   return true;
  1469 void
  1470 Geolocation::NotifyAllowedRequest(nsGeolocationRequest* aRequest)
  1472   if (aRequest->IsWatch()) {
  1473     mWatchingCallbacks.AppendElement(aRequest);
  1474   } else {
  1475     mPendingCallbacks.AppendElement(aRequest);
  1479 bool
  1480 Geolocation::RegisterRequestWithPrompt(nsGeolocationRequest* request)
  1482   if (Preferences::GetBool("geo.prompt.testing", false)) {
  1483     bool allow = Preferences::GetBool("geo.prompt.testing.allow", false);
  1484     nsCOMPtr<nsIRunnable> ev = new RequestAllowEvent(allow,
  1485 						     request);
  1486     NS_DispatchToMainThread(ev);
  1487     return true;
  1490   if (XRE_GetProcessType() == GeckoProcessType_Content) {
  1491     nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mOwner);
  1492     if (!window) {
  1493       return true;
  1496     // because owner implements nsITabChild, we can assume that it is
  1497     // the one and only TabChild.
  1498     TabChild* child = TabChild::GetFrom(window->GetDocShell());
  1499     if (!child) {
  1500       return false;
  1503     nsTArray<PermissionRequest> permArray;
  1504     nsTArray<nsString> emptyOptions;
  1505     permArray.AppendElement(PermissionRequest(NS_LITERAL_CSTRING("geolocation"),
  1506                                               NS_LITERAL_CSTRING("unused"),
  1507                                               emptyOptions));
  1509     // Retain a reference so the object isn't deleted without IPDL's knowledge.
  1510     // Corresponding release occurs in DeallocPContentPermissionRequest.
  1511     request->AddRef();
  1512     child->SendPContentPermissionRequestConstructor(request,
  1513                                                     permArray,
  1514                                                     IPC::Principal(mPrincipal));
  1516     request->Sendprompt();
  1517     return true;
  1520   nsCOMPtr<nsIRunnable> ev  = new RequestPromptEvent(request);
  1521   NS_DispatchToMainThread(ev);
  1522   return true;
  1525 JSObject*
  1526 Geolocation::WrapObject(JSContext *aCtx)
  1528   return GeolocationBinding::Wrap(aCtx, this);

mercurial