diff --git a/docshell/base/BrowsingContext.cpp b/docshell/base/BrowsingContext.cpp index 73fd65eaf09e..4470a2edf012 100644 --- a/docshell/base/BrowsingContext.cpp +++ b/docshell/base/BrowsingContext.cpp @@ -3255,6 +3255,11 @@ void BrowsingContext::SetGeolocationServiceOverride( } mGeolocationServiceOverride->Update(aGeolocationOverride.Value()); } else { + // Create an original service and move the locators. + RefPtr service = + nsGeolocationService::GetGeolocationService(); + mGeolocationServiceOverride->MoveLocators(service); + mGeolocationServiceOverride = nullptr; } } diff --git a/dom/geolocation/Geolocation.cpp b/dom/geolocation/Geolocation.cpp index d55afbadd7a8..533bc77cdc45 100644 --- a/dom/geolocation/Geolocation.cpp +++ b/dom/geolocation/Geolocation.cpp @@ -1003,6 +1003,12 @@ void nsGeolocationService::RemoveLocator(Geolocation* aLocator) { mGeolocators.RemoveElement(aLocator); } +void nsGeolocationService::MoveLocators(nsGeolocationService* aService) { + for (uint32_t i = 0; i < mGeolocators.Length(); i++) { + aService->AddLocator(mGeolocators[i]); + } +} + //////////////////////////////////////////////////// // Geolocation //////////////////////////////////////////////////// @@ -1074,23 +1080,12 @@ nsresult Geolocation::Init(nsPIDOMWindowInner* aContentDom) { // If no aContentDom was passed into us, we are being used // by chrome/c++ and have no mOwner, no mPrincipal, and no need // to prompt. - RefPtr service = - nsGeolocationService::GetGeolocationService(mBrowsingContext); - if (service != nsGeolocationService::sService.get()) { - mService = nsGeolocationService::GetGeolocationService(); - mServiceOverride = service; - } else { - mService = service; - } + mService = nsGeolocationService::GetGeolocationService(mBrowsingContext); if (mService) { mService->AddLocator(this); } - if (mServiceOverride) { - mServiceOverride->AddLocator(this); - } - return NS_OK; } @@ -1104,12 +1099,7 @@ void Geolocation::Shutdown() { mService->UpdateAccuracy(); } - if (mServiceOverride) { - mServiceOverride->RemoveLocator(this); - } - mService = nullptr; - mServiceOverride = nullptr; mPrincipal = nullptr; } diff --git a/dom/geolocation/Geolocation.h b/dom/geolocation/Geolocation.h index 0f3c14645820..0a2ef251dabc 100644 --- a/dom/geolocation/Geolocation.h +++ b/dom/geolocation/Geolocation.h @@ -70,8 +70,11 @@ class nsGeolocationService final : public nsIGeolocationUpdate, nsresult Init(); // Management of the Geolocation objects - void AddLocator(mozilla::dom::Geolocation* locator); - void RemoveLocator(mozilla::dom::Geolocation* locator); + void AddLocator(mozilla::dom::Geolocation* aLocator); + void RemoveLocator(mozilla::dom::Geolocation* aLocator); + + // Move locators from service override to the original service. + void MoveLocators(nsGeolocationService* aService); void SetCachedPosition(nsIDOMGeoPosition* aPosition); CachedPositionAndAccuracy GetCachedPosition(); diff --git a/dom/geolocation/test/browser/browser_geolocation_override.js b/dom/geolocation/test/browser/browser_geolocation_override.js index 60e2b9dbe4b2..b23935a34eb8 100644 --- a/dom/geolocation/test/browser/browser_geolocation_override.js +++ b/dom/geolocation/test/browser/browser_geolocation_override.js @@ -356,3 +356,87 @@ add_task(async function test_tab_reload() { BrowserTestUtils.removeTab(tab); }); + +add_task(async function test_amount_of_updates_for_watchPosition() { + await SpecialPowers.pushPrefEnv({ + set: required_preferences, + }); + + let pageLoaded; + let browser; + const tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + () => { + gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, PAGE_URL); + browser = gBrowser.selectedBrowser; + pageLoaded = BrowserTestUtils.browserLoaded(browser, true); + }, + false + ); + await pageLoaded; + + await SpecialPowers.spawn(browser, [], async () => { + await SpecialPowers.pushPermissions([ + { + type: "geo", + allow: SpecialPowers.Services.perms.ALLOW_ACTION, + context: content.document, + }, + ]); + + const browsingContext = content.browsingContext; + + // Set the initial override before the watchPosition is started. + browsingContext.setGeolocationServiceOverride({ + coords: { + latitude: 0, + longitude: 0, + accuracy: 0, + altitude: NaN, + altitudeAccuracy: NaN, + heading: NaN, + speed: NaN, + }, + timestamp: Date.now(), + }); + + const watchID = content.window.navigator.geolocation.watchPosition( + result => { + const event = new content.window.CustomEvent("watchPosition", { + detail: result.coords.toJSON(), + }); + + content.document.dispatchEvent(event); + } + ); + const events = []; + + info("Override the geolocation"); + + content.document.addEventListener("watchPosition", e => { + content.window.console.log("test"); + events.push(e.detail); + }); + + browsingContext.setGeolocationServiceOverride({ + coords: { + latitude: 10, + longitude: 10, + accuracy: 5, + altitude: NaN, + altitudeAccuracy: NaN, + heading: NaN, + speed: NaN, + }, + timestamp: Date.now(), + }); + + await ContentTaskUtils.waitForCondition(() => !!events.length); + + is(events.length, 1, "Only one event should come after override is set"); + + content.window.navigator.geolocation.clearWatch(watchID); + }); + + BrowserTestUtils.removeTab(tab); +});