Bug 493615 - Allow Addons to use the DOM Geolocation API. r=smaug

--HG--
extra : rebase_source : a48f85c5940252a87bfef879663b2d50daed5686
This commit is contained in:
Doug Turner 2009-11-12 07:14:45 -08:00
parent f91be4b13e
commit 172e2f77f5
9 changed files with 258 additions and 66 deletions

View File

@ -9913,12 +9913,27 @@ nsNavigator::MozIsLocallyAvailable(const nsAString &aURI,
NS_IMETHODIMP nsNavigator::GetGeolocation(nsIDOMGeoGeolocation **_retval)
{
NS_ENSURE_ARG_POINTER(_retval);
*_retval = nsnull;
if (!mGeolocation && mDocShell) {
nsCOMPtr<nsIDOMWindow> contentDOMWindow(do_GetInterface(mDocShell));
mGeolocation = new nsGeolocation(contentDOMWindow);
if (mGeolocation) {
NS_ADDREF(*_retval = mGeolocation);
return NS_OK;
}
NS_IF_ADDREF(*_retval = mGeolocation);
return NS_OK;
if (!mDocShell)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMWindow> contentDOMWindow(do_GetInterface(mDocShell));
if (!contentDOMWindow)
return NS_ERROR_FAILURE;
mGeolocation = new nsGeolocation();
if (!mGeolocation)
return NS_ERROR_FAILURE;
if (NS_FAILED(mGeolocation->Init(contentDOMWindow)))
return NS_ERROR_FAILURE;
NS_ADDREF(*_retval = mGeolocation);
return NS_OK;
}

View File

@ -712,24 +712,9 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsGeolocation)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mWatchingCallbacks[i], nsIGeolocationRequest)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
nsGeolocation::nsGeolocation(nsIDOMWindow* aContentDom)
nsGeolocation::nsGeolocation()
: mUpdateInProgress(PR_FALSE)
{
// Remember the window
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aContentDom);
if (window)
mOwner = do_GetWeakReference(window->GetCurrentInnerWindow());
// Grab the uri of the document
nsCOMPtr<nsIDOMDocument> domdoc;
aContentDom->GetDocument(getter_AddRefs(domdoc));
nsCOMPtr<nsIDocument> doc = do_QueryInterface(domdoc);
if (doc)
doc->NodePrincipal()->GetURI(getter_AddRefs(mURI));
mService = nsGeolocationService::GetInstance();
if (mService)
mService->AddLocator(this);
}
nsGeolocation::~nsGeolocation()
@ -738,6 +723,40 @@ nsGeolocation::~nsGeolocation()
Shutdown();
}
nsresult
nsGeolocation::Init(nsIDOMWindow* aContentDom)
{
// Remember the window
if (aContentDom) {
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aContentDom);
if (!window)
return NS_ERROR_FAILURE;
mOwner = do_GetWeakReference(window->GetCurrentInnerWindow());
if (!mOwner)
return NS_ERROR_FAILURE;
// Grab the uri of the document
nsCOMPtr<nsIDOMDocument> domdoc;
aContentDom->GetDocument(getter_AddRefs(domdoc));
nsCOMPtr<nsIDocument> doc = do_QueryInterface(domdoc);
if (!doc)
return NS_ERROR_FAILURE;
doc->NodePrincipal()->GetURI(getter_AddRefs(mURI));
if (!mURI)
return NS_ERROR_FAILURE;
}
// If no aContentDom was passed into us, we are being used
// by chrome/c++ and have no mOwner, no mURI, and no need
// to prompt.
mService = nsGeolocationService::GetInstance();
if (mService)
mService->AddLocator(this);
}
void
nsGeolocation::Shutdown()
{
@ -791,7 +810,7 @@ nsGeolocation::Update(nsIDOMGeoPosition *aSomewhere)
mUpdateInProgress = PR_TRUE;
if (!OwnerStillExists())
if (!WindowOwnerStillExists())
{
Shutdown();
return;
@ -819,8 +838,48 @@ nsGeolocation::GetCurrentPosition(nsIDOMGeoPositionCallback *callback,
if (sGeoEnabled == PR_FALSE)
return NS_ERROR_NOT_AVAILABLE;
nsCOMPtr<nsIGeolocationPrompt> prompt = do_GetService(NS_GEOLOCATION_PROMPT_CONTRACTID);
if (prompt == nsnull)
if (mPendingCallbacks.Length() > MAX_GEO_REQUESTS_PER_WINDOW)
return NS_ERROR_NOT_AVAILABLE;
nsRefPtr<nsGeolocationRequest> request = new nsGeolocationRequest(this, callback, errorCallback, options);
if (!request)
return NS_ERROR_OUT_OF_MEMORY;
if (NS_FAILED(request->Init()))
return NS_ERROR_FAILURE; // this as OKAY. not sure why we wouldn't throw. xxx dft
if (mOwner) {
nsCOMPtr<nsIGeolocationPrompt> prompt = do_GetService(NS_GEOLOCATION_PROMPT_CONTRACTID);
if (prompt == nsnull)
return NS_ERROR_NOT_AVAILABLE;
prompt->Prompt(request);
mPendingCallbacks.AppendElement(request);
return NS_OK;
}
if (!nsContentUtils::IsCallerChrome())
return NS_ERROR_FAILURE;
request->Allow();
mPendingCallbacks.AppendElement(request);
return NS_OK;
}
NS_IMETHODIMP
nsGeolocation::WatchPosition(nsIDOMGeoPositionCallback *callback,
nsIDOMGeoPositionErrorCallback *errorCallback,
nsIDOMGeoPositionOptions *options,
PRInt32 *_retval NS_OUTPARAM)
{
NS_ENSURE_ARG_POINTER(callback);
if (sGeoEnabled == PR_FALSE)
return NS_ERROR_NOT_AVAILABLE;
if (mPendingCallbacks.Length() > MAX_GEO_REQUESTS_PER_WINDOW)
@ -831,45 +890,31 @@ nsGeolocation::GetCurrentPosition(nsIDOMGeoPositionCallback *callback,
return NS_ERROR_OUT_OF_MEMORY;
if (NS_FAILED(request->Init()))
return NS_ERROR_FAILURE; // this as OKAY. not sure why we wouldn't throw. xxx dft
if (mOwner) {
nsCOMPtr<nsIGeolocationPrompt> prompt = do_GetService(NS_GEOLOCATION_PROMPT_CONTRACTID);
if (prompt == nsnull)
return NS_ERROR_NOT_AVAILABLE;
prompt->Prompt(request);
// need to hand back an index/reference.
mWatchingCallbacks.AppendElement(request);
*_retval = mWatchingCallbacks.Length() - 1;
return NS_OK;
}
prompt->Prompt(request);
if (!nsContentUtils::IsCallerChrome())
return NS_ERROR_FAILURE;
// What if you have a location provider that only sends a location once, then stops.? fix.
mPendingCallbacks.AppendElement(request);
return NS_OK;
}
NS_IMETHODIMP
nsGeolocation::WatchPosition(nsIDOMGeoPositionCallback *aCallback,
nsIDOMGeoPositionErrorCallback *aErrorCallback,
nsIDOMGeoPositionOptions *aOptions,
PRInt32 *_retval NS_OUTPARAM)
{
NS_ENSURE_ARG_POINTER(aCallback);
if (sGeoEnabled == PR_FALSE)
return NS_ERROR_NOT_AVAILABLE;
nsCOMPtr<nsIGeolocationPrompt> prompt = do_GetService(NS_GEOLOCATION_PROMPT_CONTRACTID);
if (prompt == nsnull)
return NS_ERROR_NOT_AVAILABLE;
if (mWatchingCallbacks.Length() > MAX_GEO_REQUESTS_PER_WINDOW)
return NS_ERROR_NOT_AVAILABLE;
nsRefPtr<nsGeolocationRequest> request = new nsGeolocationRequest(this, aCallback, aErrorCallback, aOptions);
if (!request)
return NS_ERROR_OUT_OF_MEMORY;
if (NS_FAILED(request->Init()))
return NS_OK;
prompt->Prompt(request);
request->Allow();
// need to hand back an index/reference.
mWatchingCallbacks.AppendElement(request);
*_retval = mWatchingCallbacks.Length() - 1;
return NS_OK;
}
@ -885,12 +930,15 @@ nsGeolocation::ClearWatch(PRInt32 aWatchId)
}
PRBool
nsGeolocation::OwnerStillExists()
nsGeolocation::WindowOwnerStillExists()
{
nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mOwner);
// an owner was never set when nsGeolocation
// was created, which means that this object
// is being used without a window.
if (mOwner == nsnull)
return PR_TRUE;
if (!window)
return PR_FALSE;
nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mOwner);
if (window)
{
@ -898,11 +946,11 @@ nsGeolocation::OwnerStillExists()
window->GetClosed(&closed);
if (closed)
return PR_FALSE;
}
nsPIDOMWindow* outer = window->GetOuterWindow();
if (!outer || outer->GetCurrentInnerWindow() != window)
return PR_FALSE;
nsPIDOMWindow* outer = window->GetOuterWindow();
if (!outer || outer->GetCurrentInnerWindow() != window)
return PR_FALSE;
}
return PR_TRUE;
}

View File

@ -175,7 +175,9 @@ public:
NS_DECL_CYCLE_COLLECTION_CLASS(nsGeolocation)
nsGeolocation(nsIDOMWindow* contentDom);
nsGeolocation();
nsresult Init(nsIDOMWindow* contentDom=nsnull);
// Called by the geolocation device to notify that a location has changed.
void Update(nsIDOMGeoPosition* aPosition);
@ -196,7 +198,7 @@ public:
nsIWeakReference* GetOwner() { return mOwner; }
// Check to see if the widnow still exists
PRBool OwnerStillExists();
PRBool WindowOwnerStillExists();
private:

View File

@ -59,6 +59,7 @@ _TEST_FILES = \
test_focus.xul \
window_focus.xul \
test_focused_link_scroll.xul \
test_geolocation.xul \
$(NULL)
libs:: $(_TEST_FILES)

View File

@ -0,0 +1,39 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
<!--
Test for Geolocation in chrome
-->
<window id="sample-window" width="400" height="400"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript"
src="chrome://mochikit/content/MochiKit/packed.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script>
SimpleTest.waitForExplicitFinish();
const Ci = Components.interfaces;
const Cc = Components.classes;
var geolocation = Cc["@mozilla.org/geolocation;1"].getService(Ci.nsIDOMGeoGeolocation);
geolocation.getCurrentPosition(done, error);
function error(error)
{
ok(0, "error occured trying to get geolocation from chrome");
SimpleTest.finish();
newwindow.close();
}
function done(position)
{
ok(position, "geolocation was found from chrome");
SimpleTest.finish();
newwindow.close();
}
</script>
<body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/>
</window>

View File

@ -58,6 +58,8 @@ _TEST_FILES = \
test_clearWatch.html \
test_clearWatch_invalid.html \
test_timeoutWatch.html \
test_windowClose.html \
windowTest.html \
geolocation_common.js \
geolocation.html \
test_optional_api_params.html \

View File

@ -0,0 +1,35 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=493615
-->
<head>
<title>Test for geolocation in chrome </title>
<script type="text/javascript" src="/MochiKit/packed.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="geolocation_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=493615">Mozilla Bug 493615</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
function done() {
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
window.open("windowTest.html");
</script>
</pre>
</body>
</html>

View File

@ -0,0 +1,40 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=493615
-->
<head>
<title>Test for closing a window while it is doing a geolocation request </title>
<script type="text/javascript" src="/MochiKit/packed.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="geolocation_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=493615">Mozilla Bug 493615</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
function successCallback(position) {
var opener = window.opener;
window.close();
opener.wrappedJSObject.done();
}
function accept() {
clickNotificationButton(kAcceptButton);
}
navigator.geolocation.watchPosition(successCallback, null, null);
setTimeout(accept, 50);
</script>
</pre>
</body>
</html>

View File

@ -842,6 +842,11 @@ CreateWindowControllerWithSingletonCommandTable(nsISupports *aOuter,
NS_GENERIC_FACTORY_CONSTRUCTOR(nsDOMScriptObjectFactory)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsBaseDOMException)
#define NS_GEOLOCATION_CID \
{ 0x1E1C3FF, 0x94A, 0xD048, { 0x44, 0xB4, 0x62, 0xD2, 0x9C, 0x7B, 0x4F, 0x39 } }
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsGeolocation, Init)
#define NS_GEOLOCATION_SERVICE_CID \
{ 0x404d02a, 0x1CA, 0xAAAB, { 0x47, 0x62, 0x94, 0x4b, 0x1b, 0xf2, 0xf7, 0xb5 } }
@ -1452,6 +1457,11 @@ static const nsModuleComponentInfo gComponents[] = {
"@mozilla.org/geolocation/service;1",
nsGeolocationServiceConstructor },
{ "Geolocation",
NS_GEOLOCATION_CID,
"@mozilla.org/geolocation;1",
nsGeolocationConstructor },
{ "Focus Manager",
NS_FOCUSMANAGER_CID,
"@mozilla.org/focus-manager;1",