diff options
Diffstat (limited to 'src/3rdparty/webkit/WebCore/page/Geolocation.cpp')
-rw-r--r-- | src/3rdparty/webkit/WebCore/page/Geolocation.cpp | 128 |
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 |