summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/webkit/WebCore/page/Geolocation.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/webkit/WebCore/page/Geolocation.cpp')
-rw-r--r--src/3rdparty/webkit/WebCore/page/Geolocation.cpp128
1 files changed, 102 insertions, 26 deletions
diff --git a/src/3rdparty/webkit/WebCore/page/Geolocation.cpp b/src/3rdparty/webkit/WebCore/page/Geolocation.cpp
index 86127d7..de4a9a1 100644
--- a/src/3rdparty/webkit/WebCore/page/Geolocation.cpp
+++ b/src/3rdparty/webkit/WebCore/page/Geolocation.cpp
@@ -31,10 +31,11 @@
#include "Document.h"
#include "Frame.h"
#include "Page.h"
-#include "PositionError.h"
namespace WebCore {
+static const char permissionDeniedErrorMessage[] = "User denied Geolocation";
+
Geolocation::GeoNotifier::GeoNotifier(Geolocation* geolocation, PassRefPtr<PositionCallback> successCallback, PassRefPtr<PositionErrorCallback> errorCallback, PassRefPtr<PositionOptions> options)
: m_geolocation(geolocation)
, m_successCallback(successCallback)
@@ -42,12 +43,21 @@ Geolocation::GeoNotifier::GeoNotifier(Geolocation* geolocation, PassRefPtr<Posit
, m_options(options)
, m_timer(this, &Geolocation::GeoNotifier::timerFired)
{
+ ASSERT(m_geolocation);
ASSERT(m_successCallback);
// If no options were supplied from JS, we should have created a default set
// of options in JSGeolocationCustom.cpp.
ASSERT(m_options);
}
+void Geolocation::GeoNotifier::setFatalError(PassRefPtr<PositionError> error)
+{
+ // This method is called at most once on a given GeoNotifier object.
+ ASSERT(!m_fatalError);
+ m_fatalError = error;
+ m_timer.startOneShot(0);
+}
+
bool Geolocation::GeoNotifier::hasZeroTimeout() const
{
return m_options->hasTimeout() && m_options->timeout() == 0;
@@ -63,6 +73,14 @@ void Geolocation::GeoNotifier::timerFired(Timer<GeoNotifier>*)
{
m_timer.stop();
+ if (m_fatalError) {
+ if (m_errorCallback)
+ m_errorCallback->handleEvent(m_fatalError.get());
+ // This will cause this notifier to be deleted.
+ m_geolocation->fatalErrorOccurred(this);
+ return;
+ }
+
if (m_errorCallback) {
RefPtr<PositionError> error = PositionError::create(PositionError::TIMEOUT, "Timeout expired");
m_errorCallback->handleEvent(error.get());
@@ -70,6 +88,46 @@ void Geolocation::GeoNotifier::timerFired(Timer<GeoNotifier>*)
m_geolocation->requestTimedOut(this);
}
+void Geolocation::Watchers::set(int id, PassRefPtr<GeoNotifier> notifier)
+{
+ m_idToNotifierMap.set(id, notifier);
+ m_notifierToIdMap.set(notifier, id);
+}
+
+void Geolocation::Watchers::remove(int id)
+{
+ IdToNotifierMap::iterator iter = m_idToNotifierMap.find(id);
+ if (iter == m_idToNotifierMap.end())
+ return;
+ m_notifierToIdMap.remove(iter->second);
+ m_idToNotifierMap.remove(iter);
+}
+
+void Geolocation::Watchers::remove(GeoNotifier* notifier)
+{
+ NotifierToIdMap::iterator iter = m_notifierToIdMap.find(notifier);
+ if (iter == m_notifierToIdMap.end())
+ return;
+ m_idToNotifierMap.remove(iter->second);
+ m_notifierToIdMap.remove(iter);
+}
+
+void Geolocation::Watchers::clear()
+{
+ m_idToNotifierMap.clear();
+ m_notifierToIdMap.clear();
+}
+
+bool Geolocation::Watchers::isEmpty() const
+{
+ return m_idToNotifierMap.isEmpty();
+}
+
+void Geolocation::Watchers::getNotifiersVector(Vector<RefPtr<GeoNotifier> >& copy) const
+{
+ copyValuesToVector(m_idToNotifierMap, copy);
+}
+
Geolocation::Geolocation(Frame* frame)
: m_frame(frame)
, m_service(GeolocationService::create(this))
@@ -92,40 +150,58 @@ void Geolocation::disconnectFrame()
void Geolocation::getCurrentPosition(PassRefPtr<PositionCallback> successCallback, PassRefPtr<PositionErrorCallback> errorCallback, PassRefPtr<PositionOptions> options)
{
- RefPtr<GeoNotifier> notifier = GeoNotifier::create(this, successCallback, errorCallback, options);
-
- if (notifier->hasZeroTimeout() || m_service->startUpdating(notifier->m_options.get()))
- notifier->startTimerIfNeeded();
- else {
- if (notifier->m_errorCallback) {
- RefPtr<PositionError> error = PositionError::create(PositionError::PERMISSION_DENIED, "Unable to Start");
- notifier->m_errorCallback->handleEvent(error.get());
- }
+ RefPtr<GeoNotifier> notifier = startRequest(successCallback, errorCallback, options);
+ if (!notifier)
return;
- }
m_oneShots.add(notifier);
}
int Geolocation::watchPosition(PassRefPtr<PositionCallback> successCallback, PassRefPtr<PositionErrorCallback> errorCallback, PassRefPtr<PositionOptions> options)
{
+ RefPtr<GeoNotifier> notifier = startRequest(successCallback, errorCallback, options);
+ if (!notifier)
+ return 0;
+
+ static int nextAvailableWatchId = 1;
+ // In case of overflow, make sure the ID remains positive, but reuse the ID values.
+ if (nextAvailableWatchId < 1)
+ nextAvailableWatchId = 1;
+ m_watchers.set(nextAvailableWatchId, notifier.release());
+ return nextAvailableWatchId++;
+}
+
+PassRefPtr<Geolocation::GeoNotifier> Geolocation::startRequest(PassRefPtr<PositionCallback> successCallback, PassRefPtr<PositionErrorCallback> errorCallback, PassRefPtr<PositionOptions> options)
+{
RefPtr<GeoNotifier> notifier = GeoNotifier::create(this, successCallback, errorCallback, options);
- if (notifier->hasZeroTimeout() || m_service->startUpdating(notifier->m_options.get()))
- notifier->startTimerIfNeeded();
+ // Check whether permissions have already been denied. Note that if this is the case,
+ // the permission state can not change again in the lifetime of this page.
+ if (isDenied())
+ notifier->setFatalError(PositionError::create(PositionError::PERMISSION_DENIED, permissionDeniedErrorMessage));
else {
- if (notifier->m_errorCallback) {
- RefPtr<PositionError> error = PositionError::create(PositionError::PERMISSION_DENIED, "Unable to Start");
- notifier->m_errorCallback->handleEvent(error.get());
+ if (notifier->hasZeroTimeout() || m_service->startUpdating(notifier->m_options.get()))
+ notifier->startTimerIfNeeded();
+ else {
+ if (notifier->m_errorCallback) {
+ RefPtr<PositionError> error = PositionError::create(PositionError::PERMISSION_DENIED, "Unable to Start");
+ notifier->m_errorCallback->handleEvent(error.get());
+ }
+ return 0;
}
- return 0;
}
-
- static int sIdentifier = 0;
-
- m_watchers.set(++sIdentifier, notifier);
- return sIdentifier;
+ return notifier.release();
+}
+
+void Geolocation::fatalErrorOccurred(Geolocation::GeoNotifier* notifier)
+{
+ // This request has failed fatally. Remove it from our lists.
+ m_oneShots.remove(notifier);
+ m_watchers.remove(notifier);
+
+ if (!hasListeners())
+ m_service->stopUpdating();
}
void Geolocation::requestTimedOut(GeoNotifier* notifier)
@@ -164,7 +240,7 @@ void Geolocation::setIsAllowed(bool allowed)
if (isAllowed())
makeSuccessCallbacks();
else {
- RefPtr<PositionError> error = PositionError::create(PositionError::PERMISSION_DENIED, "User disallowed Geolocation");
+ RefPtr<PositionError> error = PositionError::create(PositionError::PERMISSION_DENIED, permissionDeniedErrorMessage);
error->setIsFatal(true);
handleError(error.get());
}
@@ -212,7 +288,7 @@ void Geolocation::stopTimersForOneShots()
void Geolocation::stopTimersForWatchers()
{
Vector<RefPtr<GeoNotifier> > copy;
- copyValuesToVector(m_watchers, copy);
+ m_watchers.getNotifiersVector(copy);
stopTimer(copy);
}
@@ -231,7 +307,7 @@ void Geolocation::handleError(PositionError* error)
copyToVector(m_oneShots, oneShotsCopy);
Vector<RefPtr<GeoNotifier> > watchersCopy;
- copyValuesToVector(m_watchers, watchersCopy);
+ m_watchers.getNotifiersVector(watchersCopy);
// Clear the lists before we make the callbacks, to avoid clearing notifiers
// added by calls to Geolocation methods from the callbacks, and to prevent
@@ -294,7 +370,7 @@ void Geolocation::makeSuccessCallbacks()
copyToVector(m_oneShots, oneShotsCopy);
Vector<RefPtr<GeoNotifier> > watchersCopy;
- copyValuesToVector(m_watchers, watchersCopy);
+ m_watchers.getNotifiersVector(watchersCopy);
// Clear the lists before we make the callbacks, to avoid clearing notifiers
// added by calls to Geolocation methods from the callbacks, and to prevent