summaryrefslogtreecommitdiffstats
path: root/WebCore/page/Geolocation.cpp
diff options
context:
space:
mode:
authorIain Merrick <husky@google.com>2010-08-19 17:55:56 +0100
committerIain Merrick <husky@google.com>2010-08-23 11:05:40 +0100
commitf486d19d62f1bc33246748b14b14a9dfa617b57f (patch)
tree195485454c93125455a30e553a73981c3816144d /WebCore/page/Geolocation.cpp
parent6ba0b43722d16bc295606bec39f396f596e4fef1 (diff)
downloadexternal_webkit-f486d19d62f1bc33246748b14b14a9dfa617b57f.zip
external_webkit-f486d19d62f1bc33246748b14b14a9dfa617b57f.tar.gz
external_webkit-f486d19d62f1bc33246748b14b14a9dfa617b57f.tar.bz2
Merge WebKit at r65615 : Initial merge by git.
Change-Id: Ifbf384f4531e3b58475a662e38195c2d9152ae79
Diffstat (limited to 'WebCore/page/Geolocation.cpp')
-rw-r--r--WebCore/page/Geolocation.cpp131
1 files changed, 92 insertions, 39 deletions
diff --git a/WebCore/page/Geolocation.cpp b/WebCore/page/Geolocation.cpp
index 523c21d..0847769 100644
--- a/WebCore/page/Geolocation.cpp
+++ b/WebCore/page/Geolocation.cpp
@@ -50,6 +50,9 @@ namespace WebCore {
static const char permissionDeniedErrorMessage[] = "User denied Geolocation";
static const char failedToStartServiceErrorMessage[] = "Failed to start Geolocation service";
+static const char framelessDocumentErrorMessage[] = "Geolocation cannot be used in frameless documents";
+
+static const int firstAvailableWatchId = 1;
#if ENABLE(CLIENT_BASED_GEOLOCATION)
@@ -97,9 +100,15 @@ Geolocation::GeoNotifier::GeoNotifier(Geolocation* geolocation, PassRefPtr<Posit
void Geolocation::GeoNotifier::setFatalError(PassRefPtr<PositionError> error)
{
- // This method is called at most once on a given GeoNotifier object.
- ASSERT(!m_fatalError);
+ // If a fatal error has already been set, stick with it. This makes sure that
+ // when permission is denied, this is the error reported, as required by the
+ // spec.
+ if (m_fatalError)
+ return;
+
m_fatalError = error;
+ // An existing timer may not have a zero timeout.
+ m_timer.stop();
m_timer.startOneShot(0);
}
@@ -133,6 +142,8 @@ void Geolocation::GeoNotifier::timerFired(Timer<GeoNotifier>*)
// could be deleted by a call to clearWatch in a callback.
RefPtr<GeoNotifier> protect(this);
+ // Test for fatal error first. This is required for the case where the Frame is
+ // disconnected and requests are cancelled.
if (m_fatalError) {
if (m_errorCallback)
m_errorCallback->handleEvent(m_fatalError.get());
@@ -158,6 +169,7 @@ void Geolocation::GeoNotifier::timerFired(Timer<GeoNotifier>*)
void Geolocation::Watchers::set(int id, PassRefPtr<GeoNotifier> prpNotifier)
{
+ ASSERT(id > 0);
RefPtr<GeoNotifier> notifier = prpNotifier;
m_idToNotifierMap.set(id, notifier.get());
@@ -166,6 +178,7 @@ void Geolocation::Watchers::set(int id, PassRefPtr<GeoNotifier> prpNotifier)
void Geolocation::Watchers::remove(int id)
{
+ ASSERT(id > 0);
IdToNotifierMap::iterator iter = m_idToNotifierMap.find(id);
if (iter == m_idToNotifierMap.end())
return;
@@ -234,10 +247,14 @@ void Geolocation::disconnectFrame()
{
if (m_frame && m_frame->page() && m_allowGeolocation == InProgress)
m_frame->page()->chrome()->cancelGeolocationPermissionRequestForFrame(m_frame, this);
+<<<<<<< HEAD
#if PLATFORM(ANDROID)
// See Geolocation::stop()
#else
stopTimers();
+=======
+ cancelAllRequests();
+>>>>>>> WebKit at r65615
stopUpdating();
#endif // PLATFORM(ANDROID)
if (m_frame && m_frame->document())
@@ -265,6 +282,9 @@ Geoposition* Geolocation::lastPosition()
void Geolocation::getCurrentPosition(PassRefPtr<PositionCallback> successCallback, PassRefPtr<PositionErrorCallback> errorCallback, PassRefPtr<PositionOptions> options)
{
+ if (!m_frame)
+ return;
+
RefPtr<GeoNotifier> notifier = startRequest(successCallback, errorCallback, options);
ASSERT(notifier);
@@ -273,10 +293,13 @@ void Geolocation::getCurrentPosition(PassRefPtr<PositionCallback> successCallbac
int Geolocation::watchPosition(PassRefPtr<PositionCallback> successCallback, PassRefPtr<PositionErrorCallback> errorCallback, PassRefPtr<PositionOptions> options)
{
+ if (!m_frame)
+ return 0;
+
RefPtr<GeoNotifier> notifier = startRequest(successCallback, errorCallback, options);
ASSERT(notifier);
- static int nextAvailableWatchId = 1;
+ static int nextAvailableWatchId = firstAvailableWatchId;
// In case of overflow, make sure the ID remains positive, but reuse the ID values.
if (nextAvailableWatchId < 1)
nextAvailableWatchId = 1;
@@ -294,13 +317,18 @@ PassRefPtr<Geolocation::GeoNotifier> Geolocation::startRequest(PassRefPtr<Positi
notifier->setFatalError(PositionError::create(PositionError::PERMISSION_DENIED, permissionDeniedErrorMessage));
else if (haveSuitableCachedPosition(notifier->m_options.get()))
notifier->setUseCachedPosition();
- else if (notifier->hasZeroTimeout() || startUpdating(notifier.get())) {
+ else if (notifier->hasZeroTimeout())
+ notifier->startTimerIfNeeded();
#if USE(PREEMPT_GEOLOCATION_PERMISSION)
- // Only start timer if we're not waiting for user permission.
- if (!m_startRequestPermissionNotifier)
-#endif
- notifier->startTimerIfNeeded();
- } else
+ else if (!isAllowed()) {
+ // if we don't yet have permission, request for permission before calling startUpdating()
+ m_pendingForPermissionNotifiers.add(notifier);
+ requestPermission();
+ }
+#endif
+ else if (startUpdating(notifier.get()))
+ notifier->startTimerIfNeeded();
+ else
notifier->setFatalError(PositionError::create(PositionError::POSITION_UNAVAILABLE, failedToStartServiceErrorMessage));
return notifier.release();
@@ -388,6 +416,9 @@ bool Geolocation::haveSuitableCachedPosition(PositionOptions* options)
void Geolocation::clearWatch(int watchId)
{
+ if (watchId < firstAvailableWatchId)
+ return;
+
m_watchers.remove(watchId);
if (!hasListeners())
@@ -417,28 +448,10 @@ void Geolocation::setIsAllowed(bool allowed)
m_allowGeolocation = allowed ? Yes : No;
#if USE(PREEMPT_GEOLOCATION_PERMISSION)
- if (m_startRequestPermissionNotifier) {
- if (isAllowed()) {
- // Permission request was made during the startUpdating process
- m_startRequestPermissionNotifier->startTimerIfNeeded();
- // The notifier is always ref'ed by m_oneShots or m_watchers.
- GeoNotifier* notifier = m_startRequestPermissionNotifier.get();
- m_startRequestPermissionNotifier = 0;
-#if ENABLE(CLIENT_BASED_GEOLOCATION)
- if (!m_frame)
- return;
- Page* page = m_frame->page();
- if (!page)
- return;
- page->geolocationController()->addObserver(this, notifier->m_options->enableHighAccuracy());
-#else
- // TODO: Handle startUpdate() for non-client based implementations using pre-emptive policy
-#endif
- } else {
- m_startRequestPermissionNotifier->setFatalError(PositionError::create(PositionError::PERMISSION_DENIED, permissionDeniedErrorMessage));
- m_oneShots.add(m_startRequestPermissionNotifier);
- m_startRequestPermissionNotifier = 0;
- }
+ // Permission request was made during the startRequest process
+ if (!m_pendingForPermissionNotifiers.isEmpty()) {
+ handlePendingPermissionNotifiers();
+ m_pendingForPermissionNotifiers.clear();
return;
}
#endif
@@ -513,6 +526,22 @@ void Geolocation::stopTimers()
stopTimersForWatchers();
}
+void Geolocation::cancelRequests(Vector<RefPtr<GeoNotifier> >& notifiers)
+{
+ Vector<RefPtr<GeoNotifier> >::const_iterator end = notifiers.end();
+ for (Vector<RefPtr<GeoNotifier> >::const_iterator it = notifiers.begin(); it != end; ++it)
+ (*it)->setFatalError(PositionError::create(PositionError::POSITION_UNAVAILABLE, framelessDocumentErrorMessage));
+}
+
+void Geolocation::cancelAllRequests()
+{
+ Vector<RefPtr<GeoNotifier> > copy;
+ copyToVector(m_oneShots, copy);
+ cancelRequests(copy);
+ m_watchers.getNotifiersVector(copy);
+ cancelRequests(copy);
+}
+
void Geolocation::handleError(PositionError* error)
{
ASSERT(error);
@@ -634,14 +663,6 @@ void Geolocation::geolocationServiceErrorOccurred(GeolocationService* service)
bool Geolocation::startUpdating(GeoNotifier* notifier)
{
-#if USE(PREEMPT_GEOLOCATION_PERMISSION)
- if (!isAllowed()) {
- m_startRequestPermissionNotifier = notifier;
- requestPermission();
- return true;
- }
-#endif
-
#if ENABLE(CLIENT_BASED_GEOLOCATION)
if (!m_frame)
return false;
@@ -686,6 +707,38 @@ void Geolocation::stopUpdating()
}
+#if USE(PREEMPT_GEOLOCATION_PERMISSION)
+void Geolocation::handlePendingPermissionNotifiers()
+{
+#if ENABLE(CLIENT_BASED_GEOLOCATION)
+ if (!m_frame)
+ return;
+ Page* page = m_frame->page();
+ if (!page)
+ return;
+#endif
+
+ // While we iterate through the list, we need not worry about list being modified as the permission
+ // is already set to Yes/No and no new listeners will be added to the pending list
+ GeoNotifierSet::const_iterator end = m_pendingForPermissionNotifiers.end();
+ for (GeoNotifierSet::const_iterator iter = m_pendingForPermissionNotifiers.begin(); iter != end; ++iter) {
+ GeoNotifier* notifier = iter->get();
+
+ if (isAllowed()) {
+ // start all pending notification requests as permission granted.
+ // The notifier is always ref'ed by m_oneShots or m_watchers.
+#if ENABLE(CLIENT_BASED_GEOLOCATION)
+ notifier->startTimerIfNeeded();
+ page->geolocationController()->addObserver(this, notifier->m_options->enableHighAccuracy());
+#else
+ // TODO: Handle startUpdate() for non-client based implementations using pre-emptive policy
+#endif
+ } else
+ notifier->setFatalError(PositionError::create(PositionError::PERMISSION_DENIED, permissionDeniedErrorMessage));
+ }
+}
+#endif
+
} // namespace WebCore
#else