Home | History | Annotate | Download | only in page
      1 /*
      2  * Copyright (C) 2008, 2009 Apple Inc. All Rights Reserved.
      3  * Copyright (C) 2009 Torch Mobile, Inc.
      4  * Copyright 2010, The Android Open Source Project
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
     16  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     18  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
     19  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     22  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     23  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     25  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 
     28 #include "config.h"
     29 #include "Geolocation.h"
     30 
     31 #if ENABLE(GEOLOCATION)
     32 
     33 #include "Chrome.h"
     34 #include "Frame.h"
     35 #include "Page.h"
     36 #if PLATFORM(ANDROID)
     37 #include "PlatformBridge.h"
     38 #endif
     39 #include <wtf/CurrentTime.h>
     40 
     41 #if ENABLE(CLIENT_BASED_GEOLOCATION)
     42 #include "Coordinates.h"
     43 #include "GeolocationController.h"
     44 #include "GeolocationError.h"
     45 #include "GeolocationPosition.h"
     46 #include "PositionError.h"
     47 #endif
     48 
     49 namespace WebCore {
     50 
     51 static const char permissionDeniedErrorMessage[] = "User denied Geolocation";
     52 static const char failedToStartServiceErrorMessage[] = "Failed to start Geolocation service";
     53 static const char framelessDocumentErrorMessage[] = "Geolocation cannot be used in frameless documents";
     54 
     55 static const int firstAvailableWatchId = 1;
     56 
     57 #if ENABLE(CLIENT_BASED_GEOLOCATION)
     58 
     59 static PassRefPtr<Geoposition> createGeoposition(GeolocationPosition* position)
     60 {
     61     if (!position)
     62         return 0;
     63 
     64     RefPtr<Coordinates> coordinates = Coordinates::create(position->latitude(), position->longitude(), position->canProvideAltitude(), position->altitude(),
     65                                                           position->accuracy(), position->canProvideAltitudeAccuracy(), position->altitudeAccuracy(),
     66                                                           position->canProvideHeading(), position->heading(), position->canProvideSpeed(), position->speed());
     67     return Geoposition::create(coordinates.release(), convertSecondsToDOMTimeStamp(position->timestamp()));
     68 }
     69 
     70 static PassRefPtr<PositionError> createPositionError(GeolocationError* error)
     71 {
     72     PositionError::ErrorCode code = PositionError::POSITION_UNAVAILABLE;
     73     switch (error->code()) {
     74     case GeolocationError::PermissionDenied:
     75         code = PositionError::PERMISSION_DENIED;
     76         break;
     77     case GeolocationError::PositionUnavailable:
     78         code = PositionError::POSITION_UNAVAILABLE;
     79         break;
     80     }
     81 
     82     return PositionError::create(code, error->message());
     83 }
     84 #endif
     85 
     86 Geolocation::GeoNotifier::GeoNotifier(Geolocation* geolocation, PassRefPtr<PositionCallback> successCallback, PassRefPtr<PositionErrorCallback> errorCallback, PassRefPtr<PositionOptions> options)
     87     : m_geolocation(geolocation)
     88     , m_successCallback(successCallback)
     89     , m_errorCallback(errorCallback)
     90     , m_options(options)
     91     , m_timer(this, &Geolocation::GeoNotifier::timerFired)
     92     , m_useCachedPosition(false)
     93 {
     94     ASSERT(m_geolocation);
     95     ASSERT(m_successCallback);
     96     // If no options were supplied from JS, we should have created a default set
     97     // of options in JSGeolocationCustom.cpp.
     98     ASSERT(m_options);
     99 }
    100 
    101 void Geolocation::GeoNotifier::setFatalError(PassRefPtr<PositionError> error)
    102 {
    103     // If a fatal error has already been set, stick with it. This makes sure that
    104     // when permission is denied, this is the error reported, as required by the
    105     // spec.
    106     if (m_fatalError)
    107         return;
    108 
    109     m_fatalError = error;
    110     // An existing timer may not have a zero timeout.
    111     m_timer.stop();
    112     m_timer.startOneShot(0);
    113 }
    114 
    115 void Geolocation::GeoNotifier::setUseCachedPosition()
    116 {
    117     m_useCachedPosition = true;
    118     m_timer.startOneShot(0);
    119 }
    120 
    121 bool Geolocation::GeoNotifier::hasZeroTimeout() const
    122 {
    123     return m_options->hasTimeout() && m_options->timeout() == 0;
    124 }
    125 
    126 void Geolocation::GeoNotifier::runSuccessCallback(Geoposition* position)
    127 {
    128     m_successCallback->handleEvent(position);
    129 }
    130 
    131 void Geolocation::GeoNotifier::startTimerIfNeeded()
    132 {
    133     if (m_options->hasTimeout())
    134         m_timer.startOneShot(m_options->timeout() / 1000.0);
    135 }
    136 
    137 void Geolocation::GeoNotifier::timerFired(Timer<GeoNotifier>*)
    138 {
    139     m_timer.stop();
    140 
    141     // Protect this GeoNotifier object, since it
    142     // could be deleted by a call to clearWatch in a callback.
    143     RefPtr<GeoNotifier> protect(this);
    144 
    145     // Test for fatal error first. This is required for the case where the Frame is
    146     // disconnected and requests are cancelled.
    147     if (m_fatalError) {
    148         if (m_errorCallback)
    149             m_errorCallback->handleEvent(m_fatalError.get());
    150         // This will cause this notifier to be deleted.
    151         m_geolocation->fatalErrorOccurred(this);
    152         return;
    153     }
    154 
    155     if (m_useCachedPosition) {
    156         // Clear the cached position flag in case this is a watch request, which
    157         // will continue to run.
    158         m_useCachedPosition = false;
    159         m_geolocation->requestUsesCachedPosition(this);
    160         return;
    161     }
    162 
    163     if (m_errorCallback) {
    164         RefPtr<PositionError> error = PositionError::create(PositionError::TIMEOUT, "Timeout expired");
    165         m_errorCallback->handleEvent(error.get());
    166     }
    167     m_geolocation->requestTimedOut(this);
    168 }
    169 
    170 void Geolocation::Watchers::set(int id, PassRefPtr<GeoNotifier> prpNotifier)
    171 {
    172     ASSERT(id > 0);
    173     RefPtr<GeoNotifier> notifier = prpNotifier;
    174 
    175     m_idToNotifierMap.set(id, notifier.get());
    176     m_notifierToIdMap.set(notifier.release(), id);
    177 }
    178 
    179 void Geolocation::Watchers::remove(int id)
    180 {
    181     ASSERT(id > 0);
    182     IdToNotifierMap::iterator iter = m_idToNotifierMap.find(id);
    183     if (iter == m_idToNotifierMap.end())
    184         return;
    185     m_notifierToIdMap.remove(iter->second);
    186     m_idToNotifierMap.remove(iter);
    187 }
    188 
    189 void Geolocation::Watchers::remove(GeoNotifier* notifier)
    190 {
    191     NotifierToIdMap::iterator iter = m_notifierToIdMap.find(notifier);
    192     if (iter == m_notifierToIdMap.end())
    193         return;
    194     m_idToNotifierMap.remove(iter->second);
    195     m_notifierToIdMap.remove(iter);
    196 }
    197 
    198 bool Geolocation::Watchers::contains(GeoNotifier* notifier) const
    199 {
    200     return m_notifierToIdMap.contains(notifier);
    201 }
    202 
    203 void Geolocation::Watchers::clear()
    204 {
    205     m_idToNotifierMap.clear();
    206     m_notifierToIdMap.clear();
    207 }
    208 
    209 bool Geolocation::Watchers::isEmpty() const
    210 {
    211     return m_idToNotifierMap.isEmpty();
    212 }
    213 
    214 void Geolocation::Watchers::getNotifiersVector(GeoNotifierVector& copy) const
    215 {
    216     copyValuesToVector(m_idToNotifierMap, copy);
    217 }
    218 
    219 Geolocation::Geolocation(Frame* frame)
    220     : m_frame(frame)
    221 #if !ENABLE(CLIENT_BASED_GEOLOCATION)
    222     , m_service(GeolocationService::create(this))
    223 #endif
    224     , m_allowGeolocation(Unknown)
    225 {
    226     if (!m_frame)
    227         return;
    228     ASSERT(m_frame->document());
    229     m_frame->document()->setUsingGeolocation(true);
    230 }
    231 
    232 Geolocation::~Geolocation()
    233 {
    234     ASSERT(m_allowGeolocation != InProgress);
    235     ASSERT(!m_frame);
    236 }
    237 
    238 Page* Geolocation::page() const
    239 {
    240     return m_frame ? m_frame->page() : 0;
    241 }
    242 
    243 void Geolocation::reset()
    244 {
    245     Page* page = this->page();
    246     if (page && m_allowGeolocation == InProgress) {
    247 #if ENABLE(CLIENT_BASED_GEOLOCATION)
    248         page->geolocationController()->cancelPermissionRequest(this);
    249 #else
    250         page->chrome()->cancelGeolocationPermissionRequestForFrame(m_frame, this);
    251 #endif
    252     }
    253     // The frame may be moving to a new page and we want to get the permissions from the new page's client.
    254     m_allowGeolocation = Unknown;
    255     cancelAllRequests();
    256     stopUpdating();
    257 }
    258 
    259 void Geolocation::disconnectFrame()
    260 {
    261     // Once we are disconnected from the Frame, it is no longer possible to perform any operations.
    262     reset();
    263     if (m_frame && m_frame->document())
    264         m_frame->document()->setUsingGeolocation(false);
    265     m_frame = 0;
    266 }
    267 
    268 Geoposition* Geolocation::lastPosition()
    269 {
    270 #if ENABLE(CLIENT_BASED_GEOLOCATION)
    271     Page* page = this->page();
    272     if (!page)
    273         return 0;
    274 
    275     m_lastPosition = createGeoposition(page->geolocationController()->lastPosition());
    276 #else
    277     m_lastPosition = m_service->lastPosition();
    278 #endif
    279 
    280     return m_lastPosition.get();
    281 }
    282 
    283 void Geolocation::getCurrentPosition(PassRefPtr<PositionCallback> successCallback, PassRefPtr<PositionErrorCallback> errorCallback, PassRefPtr<PositionOptions> options)
    284 {
    285     if (!m_frame)
    286         return;
    287 
    288     RefPtr<GeoNotifier> notifier = startRequest(successCallback, errorCallback, options);
    289     ASSERT(notifier);
    290 
    291     m_oneShots.add(notifier);
    292 }
    293 
    294 int Geolocation::watchPosition(PassRefPtr<PositionCallback> successCallback, PassRefPtr<PositionErrorCallback> errorCallback, PassRefPtr<PositionOptions> options)
    295 {
    296     if (!m_frame)
    297         return 0;
    298 
    299     RefPtr<GeoNotifier> notifier = startRequest(successCallback, errorCallback, options);
    300     ASSERT(notifier);
    301 
    302     static int nextAvailableWatchId = firstAvailableWatchId;
    303     // In case of overflow, make sure the ID remains positive, but reuse the ID values.
    304     if (nextAvailableWatchId < 1)
    305         nextAvailableWatchId = 1;
    306     m_watchers.set(nextAvailableWatchId, notifier.release());
    307     return nextAvailableWatchId++;
    308 }
    309 
    310 PassRefPtr<Geolocation::GeoNotifier> Geolocation::startRequest(PassRefPtr<PositionCallback> successCallback, PassRefPtr<PositionErrorCallback> errorCallback, PassRefPtr<PositionOptions> options)
    311 {
    312     RefPtr<GeoNotifier> notifier = GeoNotifier::create(this, successCallback, errorCallback, options);
    313 
    314     // Check whether permissions have already been denied. Note that if this is the case,
    315     // the permission state can not change again in the lifetime of this page.
    316     if (isDenied())
    317         notifier->setFatalError(PositionError::create(PositionError::PERMISSION_DENIED, permissionDeniedErrorMessage));
    318     else if (haveSuitableCachedPosition(notifier->m_options.get()))
    319         notifier->setUseCachedPosition();
    320     else if (notifier->hasZeroTimeout())
    321         notifier->startTimerIfNeeded();
    322 #if USE(PREEMPT_GEOLOCATION_PERMISSION)
    323     else if (!isAllowed()) {
    324         // if we don't yet have permission, request for permission before calling startUpdating()
    325         m_pendingForPermissionNotifiers.add(notifier);
    326         requestPermission();
    327     }
    328 #endif
    329     else if (startUpdating(notifier.get()))
    330         notifier->startTimerIfNeeded();
    331     else
    332         notifier->setFatalError(PositionError::create(PositionError::POSITION_UNAVAILABLE, failedToStartServiceErrorMessage));
    333 
    334     return notifier.release();
    335 }
    336 
    337 void Geolocation::fatalErrorOccurred(Geolocation::GeoNotifier* notifier)
    338 {
    339     // This request has failed fatally. Remove it from our lists.
    340     m_oneShots.remove(notifier);
    341     m_watchers.remove(notifier);
    342 
    343     if (!hasListeners())
    344         stopUpdating();
    345 }
    346 
    347 void Geolocation::requestUsesCachedPosition(GeoNotifier* notifier)
    348 {
    349     // This is called asynchronously, so the permissions could have been denied
    350     // since we last checked in startRequest.
    351     if (isDenied()) {
    352         notifier->setFatalError(PositionError::create(PositionError::PERMISSION_DENIED, permissionDeniedErrorMessage));
    353         return;
    354     }
    355 
    356     m_requestsAwaitingCachedPosition.add(notifier);
    357 
    358     // If permissions are allowed, make the callback
    359     if (isAllowed()) {
    360         makeCachedPositionCallbacks();
    361         return;
    362     }
    363 
    364     // Request permissions, which may be synchronous or asynchronous.
    365     requestPermission();
    366 }
    367 
    368 void Geolocation::makeCachedPositionCallbacks()
    369 {
    370     // All modifications to m_requestsAwaitingCachedPosition are done
    371     // asynchronously, so we don't need to worry about it being modified from
    372     // the callbacks.
    373     GeoNotifierSet::const_iterator end = m_requestsAwaitingCachedPosition.end();
    374     for (GeoNotifierSet::const_iterator iter = m_requestsAwaitingCachedPosition.begin(); iter != end; ++iter) {
    375         GeoNotifier* notifier = iter->get();
    376         notifier->runSuccessCallback(m_positionCache.cachedPosition());
    377 
    378         // If this is a one-shot request, stop it. Otherwise, if the watch still
    379         // exists, start the service to get updates.
    380         if (m_oneShots.contains(notifier))
    381             m_oneShots.remove(notifier);
    382         else if (m_watchers.contains(notifier)) {
    383             if (notifier->hasZeroTimeout() || startUpdating(notifier))
    384                 notifier->startTimerIfNeeded();
    385             else
    386                 notifier->setFatalError(PositionError::create(PositionError::POSITION_UNAVAILABLE, failedToStartServiceErrorMessage));
    387         }
    388     }
    389 
    390     m_requestsAwaitingCachedPosition.clear();
    391 
    392     if (!hasListeners())
    393         stopUpdating();
    394 }
    395 
    396 void Geolocation::requestTimedOut(GeoNotifier* notifier)
    397 {
    398     // If this is a one-shot request, stop it.
    399     m_oneShots.remove(notifier);
    400 
    401     if (!hasListeners())
    402         stopUpdating();
    403 }
    404 
    405 bool Geolocation::haveSuitableCachedPosition(PositionOptions* options)
    406 {
    407     if (!m_positionCache.cachedPosition())
    408         return false;
    409     if (!options->hasMaximumAge())
    410         return true;
    411     if (!options->maximumAge())
    412         return false;
    413     DOMTimeStamp currentTimeMillis = convertSecondsToDOMTimeStamp(currentTime());
    414     return m_positionCache.cachedPosition()->timestamp() > currentTimeMillis - options->maximumAge();
    415 }
    416 
    417 void Geolocation::clearWatch(int watchId)
    418 {
    419     if (watchId < firstAvailableWatchId)
    420         return;
    421 
    422     m_watchers.remove(watchId);
    423 
    424     if (!hasListeners())
    425         stopUpdating();
    426 }
    427 
    428 void Geolocation::suspend()
    429 {
    430 #if !ENABLE(CLIENT_BASED_GEOLOCATION)
    431     if (hasListeners())
    432         m_service->suspend();
    433 #endif
    434 }
    435 
    436 void Geolocation::resume()
    437 {
    438 #if !ENABLE(CLIENT_BASED_GEOLOCATION)
    439     if (hasListeners())
    440         m_service->resume();
    441 #endif
    442 }
    443 
    444 void Geolocation::setIsAllowed(bool allowed)
    445 {
    446     // This may be due to either a new position from the service, or a cached
    447     // position.
    448     m_allowGeolocation = allowed ? Yes : No;
    449 
    450 #if USE(PREEMPT_GEOLOCATION_PERMISSION)
    451     // Permission request was made during the startRequest process
    452     if (!m_pendingForPermissionNotifiers.isEmpty()) {
    453         handlePendingPermissionNotifiers();
    454         m_pendingForPermissionNotifiers.clear();
    455         return;
    456     }
    457 #endif
    458 
    459     if (!isAllowed()) {
    460         RefPtr<PositionError> error = PositionError::create(PositionError::PERMISSION_DENIED, permissionDeniedErrorMessage);
    461         error->setIsFatal(true);
    462         handleError(error.get());
    463         m_requestsAwaitingCachedPosition.clear();
    464         return;
    465     }
    466 
    467     // If the service has a last position, use it to call back for all requests.
    468     // If any of the requests are waiting for permission for a cached position,
    469     // the position from the service will be at least as fresh.
    470     if (lastPosition())
    471         makeSuccessCallbacks();
    472     else
    473         makeCachedPositionCallbacks();
    474 }
    475 
    476 void Geolocation::sendError(GeoNotifierVector& notifiers, PositionError* error)
    477 {
    478      GeoNotifierVector::const_iterator end = notifiers.end();
    479      for (GeoNotifierVector::const_iterator it = notifiers.begin(); it != end; ++it) {
    480          RefPtr<GeoNotifier> notifier = *it;
    481 
    482          if (notifier->m_errorCallback)
    483              notifier->m_errorCallback->handleEvent(error);
    484      }
    485 }
    486 
    487 void Geolocation::sendPosition(GeoNotifierVector& notifiers, Geoposition* position)
    488 {
    489     GeoNotifierVector::const_iterator end = notifiers.end();
    490     for (GeoNotifierVector::const_iterator it = notifiers.begin(); it != end; ++it) {
    491         RefPtr<GeoNotifier> notifier = *it;
    492         ASSERT(notifier->m_successCallback);
    493 
    494         notifier->m_successCallback->handleEvent(position);
    495     }
    496 }
    497 
    498 void Geolocation::stopTimer(GeoNotifierVector& notifiers)
    499 {
    500     GeoNotifierVector::const_iterator end = notifiers.end();
    501     for (GeoNotifierVector::const_iterator it = notifiers.begin(); it != end; ++it) {
    502         RefPtr<GeoNotifier> notifier = *it;
    503         notifier->m_timer.stop();
    504     }
    505 }
    506 
    507 void Geolocation::stopTimersForOneShots()
    508 {
    509     GeoNotifierVector copy;
    510     copyToVector(m_oneShots, copy);
    511 
    512     stopTimer(copy);
    513 }
    514 
    515 void Geolocation::stopTimersForWatchers()
    516 {
    517     GeoNotifierVector copy;
    518     m_watchers.getNotifiersVector(copy);
    519 
    520     stopTimer(copy);
    521 }
    522 
    523 void Geolocation::stopTimers()
    524 {
    525     stopTimersForOneShots();
    526     stopTimersForWatchers();
    527 }
    528 
    529 void Geolocation::cancelRequests(GeoNotifierVector& notifiers)
    530 {
    531     GeoNotifierVector::const_iterator end = notifiers.end();
    532     for (GeoNotifierVector::const_iterator it = notifiers.begin(); it != end; ++it)
    533         (*it)->setFatalError(PositionError::create(PositionError::POSITION_UNAVAILABLE, framelessDocumentErrorMessage));
    534 }
    535 
    536 void Geolocation::cancelAllRequests()
    537 {
    538     GeoNotifierVector copy;
    539     copyToVector(m_oneShots, copy);
    540     cancelRequests(copy);
    541     m_watchers.getNotifiersVector(copy);
    542     cancelRequests(copy);
    543 }
    544 
    545 void Geolocation::extractNotifiersWithCachedPosition(GeoNotifierVector& notifiers, GeoNotifierVector* cached)
    546 {
    547     GeoNotifierVector nonCached;
    548     GeoNotifierVector::iterator end = notifiers.end();
    549     for (GeoNotifierVector::const_iterator it = notifiers.begin(); it != end; ++it) {
    550         GeoNotifier* notifier = it->get();
    551         if (notifier->m_useCachedPosition) {
    552             if (cached)
    553                 cached->append(notifier);
    554         } else
    555             nonCached.append(notifier);
    556     }
    557     notifiers.swap(nonCached);
    558 }
    559 
    560 void Geolocation::copyToSet(const GeoNotifierVector& src, GeoNotifierSet& dest)
    561 {
    562      GeoNotifierVector::const_iterator end = src.end();
    563      for (GeoNotifierVector::const_iterator it = src.begin(); it != end; ++it) {
    564          GeoNotifier* notifier = it->get();
    565          dest.add(notifier);
    566      }
    567 }
    568 
    569 void Geolocation::handleError(PositionError* error)
    570 {
    571     ASSERT(error);
    572 
    573     GeoNotifierVector oneShotsCopy;
    574     copyToVector(m_oneShots, oneShotsCopy);
    575 
    576     GeoNotifierVector watchersCopy;
    577     m_watchers.getNotifiersVector(watchersCopy);
    578 
    579     // Clear the lists before we make the callbacks, to avoid clearing notifiers
    580     // added by calls to Geolocation methods from the callbacks, and to prevent
    581     // further callbacks to these notifiers.
    582     GeoNotifierVector oneShotsWithCachedPosition;
    583     m_oneShots.clear();
    584     if (error->isFatal())
    585         m_watchers.clear();
    586     else {
    587         // Don't send non-fatal errors to notifiers due to receive a cached position.
    588         extractNotifiersWithCachedPosition(oneShotsCopy, &oneShotsWithCachedPosition);
    589         extractNotifiersWithCachedPosition(watchersCopy, 0);
    590     }
    591 
    592     sendError(oneShotsCopy, error);
    593     sendError(watchersCopy, error);
    594 
    595     // hasListeners() doesn't distinguish between notifiers due to receive a
    596     // cached position and those requiring a fresh position. Perform the check
    597     // before restoring the notifiers below.
    598     if (!hasListeners())
    599         stopUpdating();
    600 
    601     // Maintain a reference to the cached notifiers until their timer fires.
    602     copyToSet(oneShotsWithCachedPosition, m_oneShots);
    603 }
    604 
    605 void Geolocation::requestPermission()
    606 {
    607     if (m_allowGeolocation > Unknown)
    608         return;
    609 
    610     Page* page = this->page();
    611     if (!page)
    612         return;
    613 
    614     m_allowGeolocation = InProgress;
    615 
    616     // Ask the embedder: it maintains the geolocation challenge policy itself.
    617 #if ENABLE(CLIENT_BASED_GEOLOCATION)
    618     page->geolocationController()->requestPermission(this);
    619 #else
    620     page->chrome()->requestGeolocationPermissionForFrame(m_frame, this);
    621 #endif
    622 }
    623 
    624 void Geolocation::positionChangedInternal()
    625 {
    626     m_positionCache.setCachedPosition(lastPosition());
    627 
    628     // Stop all currently running timers.
    629     stopTimers();
    630 
    631     if (!isAllowed()) {
    632         // requestPermission() will ask the chrome for permission. This may be
    633         // implemented synchronously or asynchronously. In both cases,
    634         // makeSuccessCallbacks() will be called if permission is granted, so
    635         // there's nothing more to do here.
    636         requestPermission();
    637         return;
    638     }
    639 
    640     makeSuccessCallbacks();
    641 }
    642 
    643 void Geolocation::makeSuccessCallbacks()
    644 {
    645     ASSERT(lastPosition());
    646     ASSERT(isAllowed());
    647 
    648     GeoNotifierVector oneShotsCopy;
    649     copyToVector(m_oneShots, oneShotsCopy);
    650 
    651     GeoNotifierVector watchersCopy;
    652     m_watchers.getNotifiersVector(watchersCopy);
    653 
    654     // Clear the lists before we make the callbacks, to avoid clearing notifiers
    655     // added by calls to Geolocation methods from the callbacks, and to prevent
    656     // further callbacks to these notifiers.
    657     m_oneShots.clear();
    658 
    659     sendPosition(oneShotsCopy, lastPosition());
    660     sendPosition(watchersCopy, lastPosition());
    661 
    662     if (!hasListeners())
    663         stopUpdating();
    664 }
    665 
    666 #if ENABLE(CLIENT_BASED_GEOLOCATION)
    667 
    668 void Geolocation::positionChanged()
    669 {
    670     positionChangedInternal();
    671 }
    672 
    673 void Geolocation::setError(GeolocationError* error)
    674 {
    675     RefPtr<PositionError> positionError = createPositionError(error);
    676     handleError(positionError.get());
    677 }
    678 
    679 #else
    680 
    681 void Geolocation::geolocationServicePositionChanged(GeolocationService* service)
    682 {
    683     ASSERT_UNUSED(service, service == m_service);
    684     ASSERT(m_service->lastPosition());
    685 
    686     positionChangedInternal();
    687 }
    688 
    689 void Geolocation::geolocationServiceErrorOccurred(GeolocationService* service)
    690 {
    691     ASSERT(service->lastError());
    692 
    693     // Note that we do not stop timers here. For one-shots, the request is
    694     // cleared in handleError. For watchers, the spec requires that the timer is
    695     // not cleared.
    696     handleError(service->lastError());
    697 }
    698 
    699 #endif
    700 
    701 bool Geolocation::startUpdating(GeoNotifier* notifier)
    702 {
    703 #if ENABLE(CLIENT_BASED_GEOLOCATION)
    704     Page* page = this->page();
    705     if (!page)
    706         return false;
    707 
    708     page->geolocationController()->addObserver(this, notifier->m_options->enableHighAccuracy());
    709     return true;
    710 #else
    711     return m_service->startUpdating(notifier->m_options.get());
    712 #endif
    713 }
    714 
    715 void Geolocation::stopUpdating()
    716 {
    717 #if ENABLE(CLIENT_BASED_GEOLOCATION)
    718     Page* page = this->page();
    719     if (!page)
    720         return;
    721 
    722     page->geolocationController()->removeObserver(this);
    723 #else
    724     m_service->stopUpdating();
    725 #endif
    726 
    727 }
    728 
    729 #if USE(PREEMPT_GEOLOCATION_PERMISSION)
    730 void Geolocation::handlePendingPermissionNotifiers()
    731 {
    732     // While we iterate through the list, we need not worry about list being modified as the permission
    733     // is already set to Yes/No and no new listeners will be added to the pending list
    734     GeoNotifierSet::const_iterator end = m_pendingForPermissionNotifiers.end();
    735     for (GeoNotifierSet::const_iterator iter = m_pendingForPermissionNotifiers.begin(); iter != end; ++iter) {
    736         GeoNotifier* notifier = iter->get();
    737 
    738         if (isAllowed()) {
    739             // start all pending notification requests as permission granted.
    740             // The notifier is always ref'ed by m_oneShots or m_watchers.
    741             if (startUpdating(notifier))
    742                 notifier->startTimerIfNeeded();
    743             else
    744                 notifier->setFatalError(PositionError::create(PositionError::POSITION_UNAVAILABLE, failedToStartServiceErrorMessage));
    745         } else
    746             notifier->setFatalError(PositionError::create(PositionError::PERMISSION_DENIED, permissionDeniedErrorMessage));
    747     }
    748 }
    749 #endif
    750 
    751 } // namespace WebCore
    752 
    753 #else
    754 
    755 namespace WebCore {
    756 
    757 void Geolocation::clearWatch(int) {}
    758 
    759 void Geolocation::reset() {}
    760 
    761 void Geolocation::disconnectFrame() {}
    762 
    763 Geolocation::Geolocation(Frame*) {}
    764 
    765 Geolocation::~Geolocation() {}
    766 
    767 void Geolocation::setIsAllowed(bool) {}
    768 
    769 }
    770 
    771 #endif // ENABLE(GEOLOCATION)
    772