diff options
author | Iain Merrick <husky@google.com> | 2010-08-19 17:55:56 +0100 |
---|---|---|
committer | Iain Merrick <husky@google.com> | 2010-08-23 11:05:40 +0100 |
commit | f486d19d62f1bc33246748b14b14a9dfa617b57f (patch) | |
tree | 195485454c93125455a30e553a73981c3816144d /WebCore/page/Geolocation.cpp | |
parent | 6ba0b43722d16bc295606bec39f396f596e4fef1 (diff) | |
download | external_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.cpp | 131 |
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 |