nsGeolocation.cpp 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include "nsXULAppAPI.h"
  6. #include "mozilla/dom/ContentChild.h"
  7. #include "mozilla/UniquePtr.h"
  8. #include "nsGeolocation.h"
  9. #include "nsDOMClassInfoID.h"
  10. #include "nsComponentManagerUtils.h"
  11. #include "nsServiceManagerUtils.h"
  12. #include "nsContentUtils.h"
  13. #include "nsContentPermissionHelper.h"
  14. #include "nsIDocument.h"
  15. #include "nsIObserverService.h"
  16. #include "nsPIDOMWindow.h"
  17. #include "nsThreadUtils.h"
  18. #include "mozilla/Services.h"
  19. #include "mozilla/Unused.h"
  20. #include "mozilla/Preferences.h"
  21. #include "mozilla/ClearOnShutdown.h"
  22. #include "mozilla/WeakPtr.h"
  23. #include "mozilla/dom/PermissionMessageUtils.h"
  24. class nsIPrincipal;
  25. #ifdef MOZ_GPSD
  26. #include "GpsdLocationProvider.h"
  27. #endif
  28. #ifdef MOZ_WIDGET_COCOA
  29. #include "CoreLocationLocationProvider.h"
  30. #endif
  31. #ifdef XP_WIN
  32. #include "WindowsLocationProvider.h"
  33. #include "mozilla/WindowsVersion.h"
  34. #endif
  35. // Some limit to the number of get or watch geolocation requests
  36. // that a window can make.
  37. #define MAX_GEO_REQUESTS_PER_WINDOW 1500
  38. using mozilla::Unused; // <snicker>
  39. using namespace mozilla;
  40. using namespace mozilla::dom;
  41. class nsGeolocationRequest final
  42. : public nsIContentPermissionRequest
  43. , public nsIGeolocationUpdate
  44. , public SupportsWeakPtr<nsGeolocationRequest>
  45. {
  46. public:
  47. NS_DECL_CYCLE_COLLECTING_ISUPPORTS
  48. NS_DECL_NSICONTENTPERMISSIONREQUEST
  49. NS_DECL_NSIGEOLOCATIONUPDATE
  50. NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsGeolocationRequest, nsIContentPermissionRequest)
  51. nsGeolocationRequest(Geolocation* aLocator,
  52. GeoPositionCallback aCallback,
  53. GeoPositionErrorCallback aErrorCallback,
  54. UniquePtr<PositionOptions>&& aOptions,
  55. bool aWatchPositionRequest = false,
  56. int32_t aWatchId = 0);
  57. MOZ_DECLARE_WEAKREFERENCE_TYPENAME(nsGeolocationRequest)
  58. void Shutdown();
  59. void SendLocation(nsIDOMGeoPosition* aLocation);
  60. bool WantsHighAccuracy() {return !mShutdown && mOptions && mOptions->mEnableHighAccuracy;}
  61. void SetTimeoutTimer();
  62. void StopTimeoutTimer();
  63. void NotifyErrorAndShutdown(uint16_t);
  64. nsIPrincipal* GetPrincipal();
  65. bool IsWatch() { return mIsWatchPositionRequest; }
  66. int32_t WatchId() { return mWatchId; }
  67. private:
  68. virtual ~nsGeolocationRequest();
  69. class TimerCallbackHolder final : public nsITimerCallback
  70. {
  71. public:
  72. NS_DECL_ISUPPORTS
  73. NS_DECL_NSITIMERCALLBACK
  74. explicit TimerCallbackHolder(nsGeolocationRequest* aRequest)
  75. : mRequest(aRequest)
  76. {}
  77. private:
  78. ~TimerCallbackHolder() {}
  79. WeakPtr<nsGeolocationRequest> mRequest;
  80. };
  81. void Notify();
  82. bool mIsWatchPositionRequest;
  83. nsCOMPtr<nsITimer> mTimeoutTimer;
  84. GeoPositionCallback mCallback;
  85. GeoPositionErrorCallback mErrorCallback;
  86. UniquePtr<PositionOptions> mOptions;
  87. RefPtr<Geolocation> mLocator;
  88. int32_t mWatchId;
  89. bool mShutdown;
  90. nsCOMPtr<nsIContentPermissionRequester> mRequester;
  91. };
  92. static UniquePtr<PositionOptions>
  93. CreatePositionOptionsCopy(const PositionOptions& aOptions)
  94. {
  95. UniquePtr<PositionOptions> geoOptions = MakeUnique<PositionOptions>();
  96. geoOptions->mEnableHighAccuracy = aOptions.mEnableHighAccuracy;
  97. geoOptions->mMaximumAge = aOptions.mMaximumAge;
  98. geoOptions->mTimeout = aOptions.mTimeout;
  99. return geoOptions;
  100. }
  101. class RequestPromptEvent : public Runnable
  102. {
  103. public:
  104. RequestPromptEvent(nsGeolocationRequest* aRequest, nsWeakPtr aWindow)
  105. : mRequest(aRequest)
  106. , mWindow(aWindow)
  107. {
  108. }
  109. NS_IMETHOD Run() override
  110. {
  111. nsCOMPtr<nsPIDOMWindowInner> window = do_QueryReferent(mWindow);
  112. nsContentPermissionUtils::AskPermission(mRequest, window);
  113. return NS_OK;
  114. }
  115. private:
  116. RefPtr<nsGeolocationRequest> mRequest;
  117. nsWeakPtr mWindow;
  118. };
  119. class RequestAllowEvent : public Runnable
  120. {
  121. public:
  122. RequestAllowEvent(int allow, nsGeolocationRequest* request)
  123. : mAllow(allow),
  124. mRequest(request)
  125. {
  126. }
  127. NS_IMETHOD Run() override {
  128. if (mAllow) {
  129. mRequest->Allow(JS::UndefinedHandleValue);
  130. } else {
  131. mRequest->Cancel();
  132. }
  133. return NS_OK;
  134. }
  135. private:
  136. bool mAllow;
  137. RefPtr<nsGeolocationRequest> mRequest;
  138. };
  139. class RequestSendLocationEvent : public Runnable
  140. {
  141. public:
  142. RequestSendLocationEvent(nsIDOMGeoPosition* aPosition,
  143. nsGeolocationRequest* aRequest)
  144. : mPosition(aPosition),
  145. mRequest(aRequest)
  146. {
  147. }
  148. NS_IMETHOD Run() override {
  149. mRequest->SendLocation(mPosition);
  150. return NS_OK;
  151. }
  152. private:
  153. nsCOMPtr<nsIDOMGeoPosition> mPosition;
  154. RefPtr<nsGeolocationRequest> mRequest;
  155. RefPtr<Geolocation> mLocator;
  156. };
  157. ////////////////////////////////////////////////////
  158. // PositionError
  159. ////////////////////////////////////////////////////
  160. NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PositionError)
  161. NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
  162. NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMGeoPositionError)
  163. NS_INTERFACE_MAP_ENTRY(nsIDOMGeoPositionError)
  164. NS_INTERFACE_MAP_END
  165. NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PositionError, mParent)
  166. NS_IMPL_CYCLE_COLLECTING_ADDREF(PositionError)
  167. NS_IMPL_CYCLE_COLLECTING_RELEASE(PositionError)
  168. PositionError::PositionError(Geolocation* aParent, int16_t aCode)
  169. : mCode(aCode)
  170. , mParent(aParent)
  171. {
  172. }
  173. PositionError::~PositionError(){}
  174. NS_IMETHODIMP
  175. PositionError::GetCode(int16_t *aCode)
  176. {
  177. NS_ENSURE_ARG_POINTER(aCode);
  178. *aCode = Code();
  179. return NS_OK;
  180. }
  181. NS_IMETHODIMP
  182. PositionError::GetMessage(nsAString& aMessage)
  183. {
  184. switch (mCode)
  185. {
  186. case nsIDOMGeoPositionError::PERMISSION_DENIED:
  187. aMessage = NS_LITERAL_STRING("User denied geolocation prompt");
  188. break;
  189. case nsIDOMGeoPositionError::POSITION_UNAVAILABLE:
  190. aMessage = NS_LITERAL_STRING("Unknown error acquiring position");
  191. break;
  192. case nsIDOMGeoPositionError::TIMEOUT:
  193. aMessage = NS_LITERAL_STRING("Position acquisition timed out");
  194. break;
  195. default:
  196. break;
  197. }
  198. return NS_OK;
  199. }
  200. Geolocation*
  201. PositionError::GetParentObject() const
  202. {
  203. return mParent;
  204. }
  205. JSObject*
  206. PositionError::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
  207. {
  208. return PositionErrorBinding::Wrap(aCx, this, aGivenProto);
  209. }
  210. void
  211. PositionError::NotifyCallback(const GeoPositionErrorCallback& aCallback)
  212. {
  213. nsAutoMicroTask mt;
  214. if (aCallback.HasWebIDLCallback()) {
  215. PositionErrorCallback* callback = aCallback.GetWebIDLCallback();
  216. if (callback) {
  217. callback->Call(*this);
  218. }
  219. } else {
  220. nsIDOMGeoPositionErrorCallback* callback = aCallback.GetXPCOMCallback();
  221. if (callback) {
  222. callback->HandleEvent(this);
  223. }
  224. }
  225. }
  226. ////////////////////////////////////////////////////
  227. // nsGeolocationRequest
  228. ////////////////////////////////////////////////////
  229. nsGeolocationRequest::nsGeolocationRequest(Geolocation* aLocator,
  230. GeoPositionCallback aCallback,
  231. GeoPositionErrorCallback aErrorCallback,
  232. UniquePtr<PositionOptions>&& aOptions,
  233. bool aWatchPositionRequest,
  234. int32_t aWatchId)
  235. : mIsWatchPositionRequest(aWatchPositionRequest),
  236. mCallback(Move(aCallback)),
  237. mErrorCallback(Move(aErrorCallback)),
  238. mOptions(Move(aOptions)),
  239. mLocator(aLocator),
  240. mWatchId(aWatchId),
  241. mShutdown(false)
  242. {
  243. if (nsCOMPtr<nsPIDOMWindowInner> win =
  244. do_QueryReferent(mLocator->GetOwner())) {
  245. mRequester = new nsContentPermissionRequester(win);
  246. }
  247. }
  248. nsGeolocationRequest::~nsGeolocationRequest()
  249. {
  250. StopTimeoutTimer();
  251. }
  252. NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsGeolocationRequest)
  253. NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContentPermissionRequest)
  254. NS_INTERFACE_MAP_ENTRY(nsIContentPermissionRequest)
  255. NS_INTERFACE_MAP_ENTRY(nsIGeolocationUpdate)
  256. NS_INTERFACE_MAP_END
  257. NS_IMPL_CYCLE_COLLECTING_ADDREF(nsGeolocationRequest)
  258. NS_IMPL_CYCLE_COLLECTING_RELEASE(nsGeolocationRequest)
  259. NS_IMPL_CYCLE_COLLECTION(nsGeolocationRequest, mCallback, mErrorCallback, mLocator)
  260. void
  261. nsGeolocationRequest::Notify()
  262. {
  263. SetTimeoutTimer();
  264. NotifyErrorAndShutdown(nsIDOMGeoPositionError::TIMEOUT);
  265. }
  266. void
  267. nsGeolocationRequest::NotifyErrorAndShutdown(uint16_t aErrorCode)
  268. {
  269. MOZ_ASSERT(!mShutdown, "timeout after shutdown");
  270. if (!mIsWatchPositionRequest) {
  271. Shutdown();
  272. mLocator->RemoveRequest(this);
  273. }
  274. NotifyError(aErrorCode);
  275. }
  276. NS_IMETHODIMP
  277. nsGeolocationRequest::GetPrincipal(nsIPrincipal * *aRequestingPrincipal)
  278. {
  279. NS_ENSURE_ARG_POINTER(aRequestingPrincipal);
  280. nsCOMPtr<nsIPrincipal> principal = mLocator->GetPrincipal();
  281. principal.forget(aRequestingPrincipal);
  282. return NS_OK;
  283. }
  284. NS_IMETHODIMP
  285. nsGeolocationRequest::GetTypes(nsIArray** aTypes)
  286. {
  287. nsTArray<nsString> emptyOptions;
  288. return nsContentPermissionUtils::CreatePermissionArray(NS_LITERAL_CSTRING("geolocation"),
  289. NS_LITERAL_CSTRING("unused"),
  290. emptyOptions,
  291. aTypes);
  292. }
  293. NS_IMETHODIMP
  294. nsGeolocationRequest::GetWindow(mozIDOMWindow** aRequestingWindow)
  295. {
  296. NS_ENSURE_ARG_POINTER(aRequestingWindow);
  297. nsCOMPtr<nsPIDOMWindowInner> window = do_QueryReferent(mLocator->GetOwner());
  298. window.forget(aRequestingWindow);
  299. return NS_OK;
  300. }
  301. NS_IMETHODIMP
  302. nsGeolocationRequest::GetElement(nsIDOMElement * *aRequestingElement)
  303. {
  304. NS_ENSURE_ARG_POINTER(aRequestingElement);
  305. *aRequestingElement = nullptr;
  306. return NS_OK;
  307. }
  308. NS_IMETHODIMP
  309. nsGeolocationRequest::Cancel()
  310. {
  311. if (mLocator->ClearPendingRequest(this)) {
  312. return NS_OK;
  313. }
  314. NotifyError(nsIDOMGeoPositionError::PERMISSION_DENIED);
  315. return NS_OK;
  316. }
  317. NS_IMETHODIMP
  318. nsGeolocationRequest::Allow(JS::HandleValue aChoices)
  319. {
  320. MOZ_ASSERT(aChoices.isUndefined());
  321. if (mLocator->ClearPendingRequest(this)) {
  322. return NS_OK;
  323. }
  324. RefPtr<nsGeolocationService> gs = nsGeolocationService::GetGeolocationService();
  325. bool canUseCache = false;
  326. CachedPositionAndAccuracy lastPosition = gs->GetCachedPosition();
  327. if (lastPosition.position) {
  328. DOMTimeStamp cachedPositionTime_ms;
  329. lastPosition.position->GetTimestamp(&cachedPositionTime_ms);
  330. // check to see if we can use a cached value
  331. // if the user has specified a maximumAge, return a cached value.
  332. if (mOptions && mOptions->mMaximumAge > 0) {
  333. uint32_t maximumAge_ms = mOptions->mMaximumAge;
  334. bool isCachedWithinRequestedAccuracy = WantsHighAccuracy() <= lastPosition.isHighAccuracy;
  335. bool isCachedWithinRequestedTime =
  336. DOMTimeStamp(PR_Now() / PR_USEC_PER_MSEC - maximumAge_ms) <= cachedPositionTime_ms;
  337. canUseCache = isCachedWithinRequestedAccuracy && isCachedWithinRequestedTime;
  338. }
  339. }
  340. gs->UpdateAccuracy(WantsHighAccuracy());
  341. if (canUseCache) {
  342. // okay, we can return a cached position
  343. // getCurrentPosition requests serviced by the cache
  344. // will now be owned by the RequestSendLocationEvent
  345. Update(lastPosition.position);
  346. // After Update is called, getCurrentPosition finishes it's job.
  347. if (!mIsWatchPositionRequest) {
  348. return NS_OK;
  349. }
  350. } else {
  351. // if it is not a watch request and timeout is 0,
  352. // invoke the errorCallback (if present) with TIMEOUT code
  353. if (mOptions && mOptions->mTimeout == 0 && !mIsWatchPositionRequest) {
  354. NotifyError(nsIDOMGeoPositionError::TIMEOUT);
  355. return NS_OK;
  356. }
  357. }
  358. // Kick off the geo device, if it isn't already running
  359. nsresult rv = gs->StartDevice(GetPrincipal());
  360. if (NS_FAILED(rv)) {
  361. // Location provider error
  362. NotifyError(nsIDOMGeoPositionError::POSITION_UNAVAILABLE);
  363. return NS_OK;
  364. }
  365. if (mIsWatchPositionRequest || !canUseCache) {
  366. // let the locator know we're pending
  367. // we will now be owned by the locator
  368. mLocator->NotifyAllowedRequest(this);
  369. }
  370. SetTimeoutTimer();
  371. return NS_OK;
  372. }
  373. NS_IMETHODIMP
  374. nsGeolocationRequest::GetRequester(nsIContentPermissionRequester** aRequester)
  375. {
  376. NS_ENSURE_ARG_POINTER(aRequester);
  377. nsCOMPtr<nsIContentPermissionRequester> requester = mRequester;
  378. requester.forget(aRequester);
  379. return NS_OK;
  380. }
  381. void
  382. nsGeolocationRequest::SetTimeoutTimer()
  383. {
  384. MOZ_ASSERT(!mShutdown, "set timeout after shutdown");
  385. StopTimeoutTimer();
  386. if (mOptions && mOptions->mTimeout != 0 && mOptions->mTimeout != 0x7fffffff) {
  387. mTimeoutTimer = do_CreateInstance("@mozilla.org/timer;1");
  388. RefPtr<TimerCallbackHolder> holder = new TimerCallbackHolder(this);
  389. mTimeoutTimer->InitWithCallback(holder, mOptions->mTimeout, nsITimer::TYPE_ONE_SHOT);
  390. }
  391. }
  392. void
  393. nsGeolocationRequest::StopTimeoutTimer()
  394. {
  395. if (mTimeoutTimer) {
  396. mTimeoutTimer->Cancel();
  397. mTimeoutTimer = nullptr;
  398. }
  399. }
  400. void
  401. nsGeolocationRequest::SendLocation(nsIDOMGeoPosition* aPosition)
  402. {
  403. if (mShutdown) {
  404. // Ignore SendLocationEvents issued before we were cleared.
  405. return;
  406. }
  407. if (mOptions && mOptions->mMaximumAge > 0) {
  408. DOMTimeStamp positionTime_ms;
  409. aPosition->GetTimestamp(&positionTime_ms);
  410. const uint32_t maximumAge_ms = mOptions->mMaximumAge;
  411. const bool isTooOld =
  412. DOMTimeStamp(PR_Now() / PR_USEC_PER_MSEC - maximumAge_ms) > positionTime_ms;
  413. if (isTooOld) {
  414. return;
  415. }
  416. }
  417. RefPtr<Position> wrapped;
  418. if (aPosition) {
  419. nsCOMPtr<nsIDOMGeoPositionCoords> coords;
  420. aPosition->GetCoords(getter_AddRefs(coords));
  421. if (coords) {
  422. wrapped = new Position(ToSupports(mLocator), aPosition);
  423. }
  424. }
  425. if (!wrapped) {
  426. NotifyError(nsIDOMGeoPositionError::POSITION_UNAVAILABLE);
  427. return;
  428. }
  429. if (!mIsWatchPositionRequest) {
  430. // Cancel timer and position updates in case the position
  431. // callback spins the event loop
  432. Shutdown();
  433. }
  434. nsAutoMicroTask mt;
  435. if (mCallback.HasWebIDLCallback()) {
  436. PositionCallback* callback = mCallback.GetWebIDLCallback();
  437. MOZ_ASSERT(callback);
  438. callback->Call(*wrapped);
  439. } else {
  440. nsIDOMGeoPositionCallback* callback = mCallback.GetXPCOMCallback();
  441. MOZ_ASSERT(callback);
  442. callback->HandleEvent(aPosition);
  443. }
  444. if (mIsWatchPositionRequest && !mShutdown) {
  445. SetTimeoutTimer();
  446. }
  447. MOZ_ASSERT(mShutdown || mIsWatchPositionRequest,
  448. "non-shutdown getCurrentPosition request after callback!");
  449. }
  450. nsIPrincipal*
  451. nsGeolocationRequest::GetPrincipal()
  452. {
  453. if (!mLocator) {
  454. return nullptr;
  455. }
  456. return mLocator->GetPrincipal();
  457. }
  458. NS_IMETHODIMP
  459. nsGeolocationRequest::Update(nsIDOMGeoPosition* aPosition)
  460. {
  461. nsCOMPtr<nsIRunnable> ev = new RequestSendLocationEvent(aPosition, this);
  462. NS_DispatchToMainThread(ev);
  463. return NS_OK;
  464. }
  465. NS_IMETHODIMP
  466. nsGeolocationRequest::NotifyError(uint16_t aErrorCode)
  467. {
  468. MOZ_ASSERT(NS_IsMainThread());
  469. RefPtr<PositionError> positionError = new PositionError(mLocator, aErrorCode);
  470. positionError->NotifyCallback(mErrorCallback);
  471. return NS_OK;
  472. }
  473. void
  474. nsGeolocationRequest::Shutdown()
  475. {
  476. MOZ_ASSERT(!mShutdown, "request shutdown twice");
  477. mShutdown = true;
  478. StopTimeoutTimer();
  479. // If there are no other high accuracy requests, the geolocation service will
  480. // notify the provider to switch to the default accuracy.
  481. if (mOptions && mOptions->mEnableHighAccuracy) {
  482. RefPtr<nsGeolocationService> gs = nsGeolocationService::GetGeolocationService();
  483. if (gs) {
  484. gs->UpdateAccuracy();
  485. }
  486. }
  487. }
  488. ////////////////////////////////////////////////////
  489. // nsGeolocationRequest::TimerCallbackHolder
  490. ////////////////////////////////////////////////////
  491. NS_IMPL_ISUPPORTS(nsGeolocationRequest::TimerCallbackHolder, nsISupports, nsITimerCallback)
  492. NS_IMETHODIMP
  493. nsGeolocationRequest::TimerCallbackHolder::Notify(nsITimer*)
  494. {
  495. if (mRequest && mRequest->mLocator) {
  496. RefPtr<nsGeolocationRequest> request(mRequest);
  497. request->Notify();
  498. }
  499. return NS_OK;
  500. }
  501. ////////////////////////////////////////////////////
  502. // nsGeolocationService
  503. ////////////////////////////////////////////////////
  504. NS_INTERFACE_MAP_BEGIN(nsGeolocationService)
  505. NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIGeolocationUpdate)
  506. NS_INTERFACE_MAP_ENTRY(nsIGeolocationUpdate)
  507. NS_INTERFACE_MAP_ENTRY(nsIObserver)
  508. NS_INTERFACE_MAP_END
  509. NS_IMPL_ADDREF(nsGeolocationService)
  510. NS_IMPL_RELEASE(nsGeolocationService)
  511. static bool sGeoEnabled = true;
  512. static int32_t sProviderTimeout = 6000; // Time, in milliseconds, to wait for the location provider to spin up.
  513. nsresult nsGeolocationService::Init()
  514. {
  515. Preferences::AddIntVarCache(&sProviderTimeout, "geo.timeout", sProviderTimeout);
  516. Preferences::AddBoolVarCache(&sGeoEnabled, "geo.enabled", sGeoEnabled);
  517. if (!sGeoEnabled) {
  518. return NS_ERROR_FAILURE;
  519. }
  520. if (XRE_IsContentProcess()) {
  521. return NS_OK;
  522. }
  523. // geolocation service can be enabled -> now register observer
  524. nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
  525. if (!obs) {
  526. return NS_ERROR_FAILURE;
  527. }
  528. obs->AddObserver(this, "xpcom-shutdown", false);
  529. #ifdef MOZ_WIDGET_GTK
  530. #ifdef MOZ_GPSD
  531. if (Preferences::GetBool("geo.provider.use_gpsd", false)) {
  532. mProvider = new GpsdLocationProvider();
  533. }
  534. #endif
  535. #endif
  536. #ifdef MOZ_WIDGET_COCOA
  537. if (Preferences::GetBool("geo.provider.use_corelocation", true)) {
  538. mProvider = new CoreLocationLocationProvider();
  539. }
  540. #endif
  541. #ifdef XP_WIN
  542. if (Preferences::GetBool("geo.provider.ms-windows-location", false) &&
  543. IsWin8OrLater()) {
  544. mProvider = new WindowsLocationProvider();
  545. }
  546. #endif
  547. if (Preferences::GetBool("geo.provider.use_mls", false)) {
  548. mProvider = do_CreateInstance("@mozilla.org/geolocation/mls-provider;1");
  549. }
  550. // Override platform-specific providers with the default (network)
  551. // provider while testing. Our tests are currently not meant to exercise
  552. // the provider, and some tests rely on the network provider being used.
  553. // "geo.provider.testing" is always set for all plain and browser chrome
  554. // mochitests, and also for xpcshell tests.
  555. if (!mProvider || Preferences::GetBool("geo.provider.testing", false)) {
  556. nsCOMPtr<nsIGeolocationProvider> override =
  557. do_GetService(NS_GEOLOCATION_PROVIDER_CONTRACTID);
  558. if (override) {
  559. mProvider = override;
  560. }
  561. }
  562. return NS_OK;
  563. }
  564. nsGeolocationService::~nsGeolocationService()
  565. {
  566. }
  567. NS_IMETHODIMP
  568. nsGeolocationService::Observe(nsISupports* aSubject,
  569. const char* aTopic,
  570. const char16_t* aData)
  571. {
  572. if (!strcmp("xpcom-shutdown", aTopic)) {
  573. nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
  574. if (obs) {
  575. obs->RemoveObserver(this, "xpcom-shutdown");
  576. }
  577. for (uint32_t i = 0; i< mGeolocators.Length(); i++) {
  578. mGeolocators[i]->Shutdown();
  579. }
  580. StopDevice();
  581. return NS_OK;
  582. }
  583. if (!strcmp("timer-callback", aTopic)) {
  584. // decide if we can close down the service.
  585. for (uint32_t i = 0; i< mGeolocators.Length(); i++)
  586. if (mGeolocators[i]->HasActiveCallbacks()) {
  587. SetDisconnectTimer();
  588. return NS_OK;
  589. }
  590. // okay to close up.
  591. StopDevice();
  592. Update(nullptr);
  593. return NS_OK;
  594. }
  595. return NS_ERROR_FAILURE;
  596. }
  597. NS_IMETHODIMP
  598. nsGeolocationService::Update(nsIDOMGeoPosition *aSomewhere)
  599. {
  600. if (aSomewhere) {
  601. SetCachedPosition(aSomewhere);
  602. }
  603. for (uint32_t i = 0; i< mGeolocators.Length(); i++) {
  604. mGeolocators[i]->Update(aSomewhere);
  605. }
  606. return NS_OK;
  607. }
  608. NS_IMETHODIMP
  609. nsGeolocationService::NotifyError(uint16_t aErrorCode)
  610. {
  611. for (uint32_t i = 0; i < mGeolocators.Length(); i++) {
  612. mGeolocators[i]->NotifyError(aErrorCode);
  613. }
  614. return NS_OK;
  615. }
  616. void
  617. nsGeolocationService::SetCachedPosition(nsIDOMGeoPosition* aPosition)
  618. {
  619. mLastPosition.position = aPosition;
  620. mLastPosition.isHighAccuracy = mHigherAccuracy;
  621. }
  622. CachedPositionAndAccuracy
  623. nsGeolocationService::GetCachedPosition()
  624. {
  625. return mLastPosition;
  626. }
  627. nsresult
  628. nsGeolocationService::StartDevice(nsIPrincipal *aPrincipal)
  629. {
  630. if (!sGeoEnabled) {
  631. return NS_ERROR_NOT_AVAILABLE;
  632. }
  633. // We do not want to keep the geolocation devices online
  634. // indefinitely.
  635. // Close them down after a reasonable period of inactivivity.
  636. SetDisconnectTimer();
  637. if (XRE_IsContentProcess()) {
  638. ContentChild* cpc = ContentChild::GetSingleton();
  639. cpc->SendAddGeolocationListener(IPC::Principal(aPrincipal),
  640. HighAccuracyRequested());
  641. return NS_OK;
  642. }
  643. // Start them up!
  644. nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
  645. if (!obs) {
  646. return NS_ERROR_FAILURE;
  647. }
  648. if (!mProvider) {
  649. return NS_ERROR_FAILURE;
  650. }
  651. nsresult rv;
  652. if (NS_FAILED(rv = mProvider->Startup()) ||
  653. NS_FAILED(rv = mProvider->Watch(this))) {
  654. NotifyError(nsIDOMGeoPositionError::POSITION_UNAVAILABLE);
  655. return rv;
  656. }
  657. obs->NotifyObservers(mProvider,
  658. "geolocation-device-events",
  659. u"starting");
  660. return NS_OK;
  661. }
  662. void
  663. nsGeolocationService::SetDisconnectTimer()
  664. {
  665. if (!mDisconnectTimer) {
  666. mDisconnectTimer = do_CreateInstance("@mozilla.org/timer;1");
  667. } else {
  668. mDisconnectTimer->Cancel();
  669. }
  670. mDisconnectTimer->Init(this,
  671. sProviderTimeout,
  672. nsITimer::TYPE_ONE_SHOT);
  673. }
  674. bool
  675. nsGeolocationService::HighAccuracyRequested()
  676. {
  677. for (uint32_t i = 0; i < mGeolocators.Length(); i++) {
  678. if (mGeolocators[i]->HighAccuracyRequested()) {
  679. return true;
  680. }
  681. }
  682. return false;
  683. }
  684. void
  685. nsGeolocationService::UpdateAccuracy(bool aForceHigh)
  686. {
  687. bool highRequired = aForceHigh || HighAccuracyRequested();
  688. if (XRE_IsContentProcess()) {
  689. ContentChild* cpc = ContentChild::GetSingleton();
  690. if (cpc->IsAlive()) {
  691. cpc->SendSetGeolocationHigherAccuracy(highRequired);
  692. }
  693. return;
  694. }
  695. mProvider->SetHighAccuracy(!mHigherAccuracy && highRequired);
  696. mHigherAccuracy = highRequired;
  697. }
  698. void
  699. nsGeolocationService::StopDevice()
  700. {
  701. if (mDisconnectTimer) {
  702. mDisconnectTimer->Cancel();
  703. mDisconnectTimer = nullptr;
  704. }
  705. if (XRE_IsContentProcess()) {
  706. ContentChild* cpc = ContentChild::GetSingleton();
  707. cpc->SendRemoveGeolocationListener();
  708. return; // bail early
  709. }
  710. nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
  711. if (!obs) {
  712. return;
  713. }
  714. if (!mProvider) {
  715. return;
  716. }
  717. mHigherAccuracy = false;
  718. mProvider->Shutdown();
  719. obs->NotifyObservers(mProvider,
  720. "geolocation-device-events",
  721. u"shutdown");
  722. }
  723. StaticRefPtr<nsGeolocationService> nsGeolocationService::sService;
  724. already_AddRefed<nsGeolocationService>
  725. nsGeolocationService::GetGeolocationService()
  726. {
  727. RefPtr<nsGeolocationService> result;
  728. if (nsGeolocationService::sService) {
  729. result = nsGeolocationService::sService;
  730. return result.forget();
  731. }
  732. result = new nsGeolocationService();
  733. if (NS_FAILED(result->Init())) {
  734. return nullptr;
  735. }
  736. ClearOnShutdown(&nsGeolocationService::sService);
  737. nsGeolocationService::sService = result;
  738. return result.forget();
  739. }
  740. void
  741. nsGeolocationService::AddLocator(Geolocation* aLocator)
  742. {
  743. mGeolocators.AppendElement(aLocator);
  744. }
  745. void
  746. nsGeolocationService::RemoveLocator(Geolocation* aLocator)
  747. {
  748. mGeolocators.RemoveElement(aLocator);
  749. }
  750. ////////////////////////////////////////////////////
  751. // Geolocation
  752. ////////////////////////////////////////////////////
  753. NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Geolocation)
  754. NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
  755. NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMGeoGeolocation)
  756. NS_INTERFACE_MAP_ENTRY(nsIDOMGeoGeolocation)
  757. NS_INTERFACE_MAP_ENTRY(nsIGeolocationUpdate)
  758. NS_INTERFACE_MAP_END
  759. NS_IMPL_CYCLE_COLLECTING_ADDREF(Geolocation)
  760. NS_IMPL_CYCLE_COLLECTING_RELEASE(Geolocation)
  761. NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Geolocation,
  762. mPendingCallbacks,
  763. mWatchingCallbacks,
  764. mPendingRequests)
  765. Geolocation::Geolocation()
  766. : mLastWatchId(0)
  767. {
  768. }
  769. Geolocation::~Geolocation()
  770. {
  771. if (mService) {
  772. Shutdown();
  773. }
  774. }
  775. nsresult
  776. Geolocation::Init(nsPIDOMWindowInner* aContentDom)
  777. {
  778. // Remember the window
  779. if (aContentDom) {
  780. mOwner = do_GetWeakReference(aContentDom);
  781. if (!mOwner) {
  782. return NS_ERROR_FAILURE;
  783. }
  784. // Grab the principal of the document
  785. nsCOMPtr<nsIDocument> doc = aContentDom->GetDoc();
  786. if (!doc) {
  787. return NS_ERROR_FAILURE;
  788. }
  789. mPrincipal = doc->NodePrincipal();
  790. nsCOMPtr<nsIURI> uri;
  791. nsresult rv = mPrincipal->GetURI(getter_AddRefs(uri));
  792. NS_ENSURE_SUCCESS(rv, rv);
  793. }
  794. // If no aContentDom was passed into us, we are being used
  795. // by chrome/c++ and have no mOwner, no mPrincipal, and no need
  796. // to prompt.
  797. mService = nsGeolocationService::GetGeolocationService();
  798. if (mService) {
  799. mService->AddLocator(this);
  800. }
  801. return NS_OK;
  802. }
  803. void
  804. Geolocation::Shutdown()
  805. {
  806. // Release all callbacks
  807. mPendingCallbacks.Clear();
  808. mWatchingCallbacks.Clear();
  809. if (mService) {
  810. mService->RemoveLocator(this);
  811. mService->UpdateAccuracy();
  812. }
  813. mService = nullptr;
  814. mPrincipal = nullptr;
  815. }
  816. nsPIDOMWindowInner*
  817. Geolocation::GetParentObject() const {
  818. nsCOMPtr<nsPIDOMWindowInner> window = do_QueryReferent(mOwner);
  819. return window.get();
  820. }
  821. bool
  822. Geolocation::HasActiveCallbacks()
  823. {
  824. return mPendingCallbacks.Length() || mWatchingCallbacks.Length();
  825. }
  826. bool
  827. Geolocation::HighAccuracyRequested()
  828. {
  829. for (uint32_t i = 0; i < mWatchingCallbacks.Length(); i++) {
  830. if (mWatchingCallbacks[i]->WantsHighAccuracy()) {
  831. return true;
  832. }
  833. }
  834. for (uint32_t i = 0; i < mPendingCallbacks.Length(); i++) {
  835. if (mPendingCallbacks[i]->WantsHighAccuracy()) {
  836. return true;
  837. }
  838. }
  839. return false;
  840. }
  841. void
  842. Geolocation::RemoveRequest(nsGeolocationRequest* aRequest)
  843. {
  844. bool requestWasKnown =
  845. (mPendingCallbacks.RemoveElement(aRequest) !=
  846. mWatchingCallbacks.RemoveElement(aRequest));
  847. Unused << requestWasKnown;
  848. }
  849. NS_IMETHODIMP
  850. Geolocation::Update(nsIDOMGeoPosition *aSomewhere)
  851. {
  852. if (!WindowOwnerStillExists()) {
  853. Shutdown();
  854. return NS_OK;
  855. }
  856. if (aSomewhere) {
  857. nsCOMPtr<nsIDOMGeoPositionCoords> coords;
  858. aSomewhere->GetCoords(getter_AddRefs(coords));
  859. if (coords) {
  860. double accuracy = -1;
  861. coords->GetAccuracy(&accuracy);
  862. }
  863. }
  864. for (uint32_t i = mPendingCallbacks.Length(); i > 0; i--) {
  865. mPendingCallbacks[i-1]->Update(aSomewhere);
  866. RemoveRequest(mPendingCallbacks[i-1]);
  867. }
  868. // notify everyone that is watching
  869. for (uint32_t i = 0; i < mWatchingCallbacks.Length(); i++) {
  870. mWatchingCallbacks[i]->Update(aSomewhere);
  871. }
  872. return NS_OK;
  873. }
  874. NS_IMETHODIMP
  875. Geolocation::NotifyError(uint16_t aErrorCode)
  876. {
  877. if (!WindowOwnerStillExists()) {
  878. Shutdown();
  879. return NS_OK;
  880. }
  881. for (uint32_t i = mPendingCallbacks.Length(); i > 0; i--) {
  882. mPendingCallbacks[i-1]->NotifyErrorAndShutdown(aErrorCode);
  883. //NotifyErrorAndShutdown() removes the request from the array
  884. }
  885. // notify everyone that is watching
  886. for (uint32_t i = 0; i < mWatchingCallbacks.Length(); i++) {
  887. mWatchingCallbacks[i]->NotifyErrorAndShutdown(aErrorCode);
  888. }
  889. return NS_OK;
  890. }
  891. bool
  892. Geolocation::IsAlreadyCleared(nsGeolocationRequest* aRequest)
  893. {
  894. for (uint32_t i = 0, length = mClearedWatchIDs.Length(); i < length; ++i) {
  895. if (mClearedWatchIDs[i] == aRequest->WatchId()) {
  896. return true;
  897. }
  898. }
  899. return false;
  900. }
  901. bool
  902. Geolocation::ClearPendingRequest(nsGeolocationRequest* aRequest)
  903. {
  904. if (aRequest->IsWatch() && this->IsAlreadyCleared(aRequest)) {
  905. this->NotifyAllowedRequest(aRequest);
  906. this->ClearWatch(aRequest->WatchId());
  907. return true;
  908. }
  909. return false;
  910. }
  911. void
  912. Geolocation::GetCurrentPosition(PositionCallback& aCallback,
  913. PositionErrorCallback* aErrorCallback,
  914. const PositionOptions& aOptions,
  915. ErrorResult& aRv)
  916. {
  917. nsresult rv = GetCurrentPosition(GeoPositionCallback(&aCallback),
  918. GeoPositionErrorCallback(aErrorCallback),
  919. Move(CreatePositionOptionsCopy(aOptions)));
  920. if (NS_FAILED(rv)) {
  921. aRv.Throw(rv);
  922. }
  923. return;
  924. }
  925. NS_IMETHODIMP
  926. Geolocation::GetCurrentPosition(nsIDOMGeoPositionCallback* aCallback,
  927. nsIDOMGeoPositionErrorCallback* aErrorCallback,
  928. UniquePtr<PositionOptions>&& aOptions)
  929. {
  930. NS_ENSURE_ARG_POINTER(aCallback);
  931. return GetCurrentPosition(GeoPositionCallback(aCallback),
  932. GeoPositionErrorCallback(aErrorCallback),
  933. Move(aOptions));
  934. }
  935. nsresult
  936. Geolocation::GetCurrentPosition(GeoPositionCallback callback,
  937. GeoPositionErrorCallback errorCallback,
  938. UniquePtr<PositionOptions>&& options)
  939. {
  940. if (mPendingCallbacks.Length() > MAX_GEO_REQUESTS_PER_WINDOW) {
  941. return NS_ERROR_NOT_AVAILABLE;
  942. }
  943. // After this we hand over ownership of options to our nsGeolocationRequest.
  944. RefPtr<nsGeolocationRequest> request =
  945. new nsGeolocationRequest(this, Move(callback), Move(errorCallback),
  946. Move(options),
  947. false);
  948. if (!sGeoEnabled) {
  949. nsCOMPtr<nsIRunnable> ev = new RequestAllowEvent(false, request);
  950. NS_DispatchToMainThread(ev);
  951. return NS_OK;
  952. }
  953. if (!mOwner && !nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
  954. return NS_ERROR_FAILURE;
  955. }
  956. if (mOwner) {
  957. if (!RegisterRequestWithPrompt(request)) {
  958. return NS_ERROR_NOT_AVAILABLE;
  959. }
  960. return NS_OK;
  961. }
  962. if (!nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
  963. return NS_ERROR_FAILURE;
  964. }
  965. nsCOMPtr<nsIRunnable> ev = new RequestAllowEvent(true, request);
  966. NS_DispatchToMainThread(ev);
  967. return NS_OK;
  968. }
  969. int32_t
  970. Geolocation::WatchPosition(PositionCallback& aCallback,
  971. PositionErrorCallback* aErrorCallback,
  972. const PositionOptions& aOptions,
  973. ErrorResult& aRv)
  974. {
  975. int32_t ret = 0;
  976. nsresult rv = WatchPosition(GeoPositionCallback(&aCallback),
  977. GeoPositionErrorCallback(aErrorCallback),
  978. Move(CreatePositionOptionsCopy(aOptions)), &ret);
  979. if (NS_FAILED(rv)) {
  980. aRv.Throw(rv);
  981. }
  982. return ret;
  983. }
  984. NS_IMETHODIMP
  985. Geolocation::WatchPosition(nsIDOMGeoPositionCallback *aCallback,
  986. nsIDOMGeoPositionErrorCallback *aErrorCallback,
  987. UniquePtr<PositionOptions>&& aOptions,
  988. int32_t* aRv)
  989. {
  990. NS_ENSURE_ARG_POINTER(aCallback);
  991. return WatchPosition(GeoPositionCallback(aCallback),
  992. GeoPositionErrorCallback(aErrorCallback),
  993. Move(aOptions), aRv);
  994. }
  995. nsresult
  996. Geolocation::WatchPosition(GeoPositionCallback aCallback,
  997. GeoPositionErrorCallback aErrorCallback,
  998. UniquePtr<PositionOptions>&& aOptions,
  999. int32_t* aRv)
  1000. {
  1001. if (mWatchingCallbacks.Length() > MAX_GEO_REQUESTS_PER_WINDOW) {
  1002. return NS_ERROR_NOT_AVAILABLE;
  1003. }
  1004. // The watch ID:
  1005. *aRv = mLastWatchId++;
  1006. RefPtr<nsGeolocationRequest> request =
  1007. new nsGeolocationRequest(this, Move(aCallback), Move(aErrorCallback),
  1008. Move(aOptions),
  1009. true, *aRv);
  1010. if (!sGeoEnabled) {
  1011. nsCOMPtr<nsIRunnable> ev = new RequestAllowEvent(false, request);
  1012. NS_DispatchToMainThread(ev);
  1013. return NS_OK;
  1014. }
  1015. if (!mOwner && !nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
  1016. return NS_ERROR_FAILURE;
  1017. }
  1018. if (mOwner) {
  1019. if (!RegisterRequestWithPrompt(request))
  1020. return NS_ERROR_NOT_AVAILABLE;
  1021. return NS_OK;
  1022. }
  1023. if (!nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
  1024. return NS_ERROR_FAILURE;
  1025. }
  1026. request->Allow(JS::UndefinedHandleValue);
  1027. return NS_OK;
  1028. }
  1029. NS_IMETHODIMP
  1030. Geolocation::ClearWatch(int32_t aWatchId)
  1031. {
  1032. if (aWatchId < 0) {
  1033. return NS_OK;
  1034. }
  1035. if (!mClearedWatchIDs.Contains(aWatchId)) {
  1036. mClearedWatchIDs.AppendElement(aWatchId);
  1037. }
  1038. for (uint32_t i = 0, length = mWatchingCallbacks.Length(); i < length; ++i) {
  1039. if (mWatchingCallbacks[i]->WatchId() == aWatchId) {
  1040. mWatchingCallbacks[i]->Shutdown();
  1041. RemoveRequest(mWatchingCallbacks[i]);
  1042. mClearedWatchIDs.RemoveElement(aWatchId);
  1043. break;
  1044. }
  1045. }
  1046. // make sure we also search through the pending requests lists for
  1047. // watches to clear...
  1048. for (uint32_t i = 0, length = mPendingRequests.Length(); i < length; ++i) {
  1049. if (mPendingRequests[i]->IsWatch() &&
  1050. (mPendingRequests[i]->WatchId() == aWatchId)) {
  1051. mPendingRequests[i]->Shutdown();
  1052. mPendingRequests.RemoveElementAt(i);
  1053. break;
  1054. }
  1055. }
  1056. return NS_OK;
  1057. }
  1058. bool
  1059. Geolocation::WindowOwnerStillExists()
  1060. {
  1061. // an owner was never set when Geolocation
  1062. // was created, which means that this object
  1063. // is being used without a window.
  1064. if (mOwner == nullptr) {
  1065. return true;
  1066. }
  1067. nsCOMPtr<nsPIDOMWindowInner> window = do_QueryReferent(mOwner);
  1068. if (window) {
  1069. nsPIDOMWindowOuter* outer = window->GetOuterWindow();
  1070. if (!outer || outer->GetCurrentInnerWindow() != window ||
  1071. outer->Closed()) {
  1072. return false;
  1073. }
  1074. }
  1075. return true;
  1076. }
  1077. void
  1078. Geolocation::NotifyAllowedRequest(nsGeolocationRequest* aRequest)
  1079. {
  1080. if (aRequest->IsWatch()) {
  1081. mWatchingCallbacks.AppendElement(aRequest);
  1082. } else {
  1083. mPendingCallbacks.AppendElement(aRequest);
  1084. }
  1085. }
  1086. bool
  1087. Geolocation::RegisterRequestWithPrompt(nsGeolocationRequest* request)
  1088. {
  1089. if (Preferences::GetBool("geo.prompt.testing", false)) {
  1090. bool allow = Preferences::GetBool("geo.prompt.testing.allow", false);
  1091. nsCOMPtr<nsIRunnable> ev = new RequestAllowEvent(allow, request);
  1092. NS_DispatchToMainThread(ev);
  1093. return true;
  1094. }
  1095. nsCOMPtr<nsIRunnable> ev = new RequestPromptEvent(request, mOwner);
  1096. NS_DispatchToMainThread(ev);
  1097. return true;
  1098. }
  1099. JSObject*
  1100. Geolocation::WrapObject(JSContext *aCtx, JS::Handle<JSObject*> aGivenProto)
  1101. {
  1102. return GeolocationBinding::Wrap(aCtx, this, aGivenProto);
  1103. }