Home | History | Annotate | Download | only in geolocation
      1 /*
      2  * Copyright (C) 2008, 2009, 2010, 2011 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 "modules/geolocation/Geolocation.h"
     30 
     31 #include "core/dom/Document.h"
     32 #include "wtf/CurrentTime.h"
     33 
     34 #include "modules/geolocation/Coordinates.h"
     35 #include "modules/geolocation/GeolocationController.h"
     36 #include "modules/geolocation/GeolocationError.h"
     37 #include "modules/geolocation/GeolocationPosition.h"
     38 
     39 namespace WebCore {
     40 
     41 static const char permissionDeniedErrorMessage[] = "User denied Geolocation";
     42 static const char failedToStartServiceErrorMessage[] = "Failed to start Geolocation service";
     43 static const char framelessDocumentErrorMessage[] = "Geolocation cannot be used in frameless documents";
     44 
     45 static PassRefPtr<Geoposition> createGeoposition(GeolocationPosition* position)
     46 {
     47     if (!position)
     48         return 0;
     49 
     50     RefPtr<Coordinates> coordinates = Coordinates::create(position->latitude(), position->longitude(), position->canProvideAltitude(), position->altitude(),
     51                                                           position->accuracy(), position->canProvideAltitudeAccuracy(), position->altitudeAccuracy(),
     52                                                           position->canProvideHeading(), position->heading(), position->canProvideSpeed(), position->speed());
     53     return Geoposition::create(coordinates.release(), convertSecondsToDOMTimeStamp(position->timestamp()));
     54 }
     55 
     56 static PassRefPtr<PositionError> createPositionError(GeolocationError* error)
     57 {
     58     PositionError::ErrorCode code = PositionError::POSITION_UNAVAILABLE;
     59     switch (error->code()) {
     60     case GeolocationError::PermissionDenied:
     61         code = PositionError::PERMISSION_DENIED;
     62         break;
     63     case GeolocationError::PositionUnavailable:
     64         code = PositionError::POSITION_UNAVAILABLE;
     65         break;
     66     }
     67 
     68     return PositionError::create(code, error->message());
     69 }
     70 
     71 Geolocation::GeoNotifier::GeoNotifier(Geolocation* geolocation, PassOwnPtr<PositionCallback> successCallback, PassOwnPtr<PositionErrorCallback> errorCallback, PassRefPtr<PositionOptions> options)
     72     : m_geolocation(geolocation)
     73     , m_successCallback(successCallback)
     74     , m_errorCallback(errorCallback)
     75     , m_options(options)
     76     , m_timer(this, &Geolocation::GeoNotifier::timerFired)
     77     , m_useCachedPosition(false)
     78 {
     79     ASSERT(m_geolocation);
     80     ASSERT(m_successCallback);
     81     // If no options were supplied from JS, we should have created a default set
     82     // of options in JSGeolocationCustom.cpp.
     83     ASSERT(m_options);
     84 }
     85 
     86 void Geolocation::GeoNotifier::setFatalError(PassRefPtr<PositionError> error)
     87 {
     88     // If a fatal error has already been set, stick with it. This makes sure that
     89     // when permission is denied, this is the error reported, as required by the
     90     // spec.
     91     if (m_fatalError)
     92         return;
     93 
     94     m_fatalError = error;
     95     // An existing timer may not have a zero timeout.
     96     m_timer.stop();
     97     m_timer.startOneShot(0);
     98 }
     99 
    100 void Geolocation::GeoNotifier::setUseCachedPosition()
    101 {
    102     m_useCachedPosition = true;
    103     m_timer.startOneShot(0);
    104 }
    105 
    106 bool Geolocation::GeoNotifier::hasZeroTimeout() const
    107 {
    108     return m_options->hasTimeout() && m_options->timeout() == 0;
    109 }
    110 
    111 void Geolocation::GeoNotifier::runSuccessCallback(Geoposition* position)
    112 {
    113     // If we are here and the Geolocation permission is not approved, something has
    114     // gone horribly wrong.
    115     if (!m_geolocation->isAllowed())
    116         CRASH();
    117 
    118     m_successCallback->handleEvent(position);
    119 }
    120 
    121 void Geolocation::GeoNotifier::runErrorCallback(PositionError* error)
    122 {
    123     if (m_errorCallback)
    124         m_errorCallback->handleEvent(error);
    125 }
    126 
    127 void Geolocation::GeoNotifier::startTimerIfNeeded()
    128 {
    129     if (m_options->hasTimeout())
    130         m_timer.startOneShot(m_options->timeout() / 1000.0);
    131 }
    132 
    133 void Geolocation::GeoNotifier::stopTimer()
    134 {
    135     m_timer.stop();
    136 }
    137 
    138 void Geolocation::GeoNotifier::timerFired(Timer<GeoNotifier>*)
    139 {
    140     m_timer.stop();
    141 
    142     // Protect this GeoNotifier object, since it
    143     // could be deleted by a call to clearWatch in a callback.
    144     RefPtr<GeoNotifier> protect(this);
    145 
    146     // Test for fatal error first. This is required for the case where the Frame is
    147     // disconnected and requests are cancelled.
    148     if (m_fatalError) {
    149         runErrorCallback(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 bool Geolocation::Watchers::add(int id, PassRefPtr<GeoNotifier> prpNotifier)
    171 {
    172     ASSERT(id > 0);
    173     RefPtr<GeoNotifier> notifier = prpNotifier;
    174 
    175     if (!m_idToNotifierMap.add(id, notifier.get()).isNewEntry)
    176         return false;
    177     m_notifierToIdMap.set(notifier.release(), id);
    178     return true;
    179 }
    180 
    181 Geolocation::GeoNotifier* Geolocation::Watchers::find(int id)
    182 {
    183     ASSERT(id > 0);
    184     IdToNotifierMap::iterator iter = m_idToNotifierMap.find(id);
    185     if (iter == m_idToNotifierMap.end())
    186         return 0;
    187     return iter->value.get();
    188 }
    189 
    190 void Geolocation::Watchers::remove(int id)
    191 {
    192     ASSERT(id > 0);
    193     IdToNotifierMap::iterator iter = m_idToNotifierMap.find(id);
    194     if (iter == m_idToNotifierMap.end())
    195         return;
    196     m_notifierToIdMap.remove(iter->value);
    197     m_idToNotifierMap.remove(iter);
    198 }
    199 
    200 void Geolocation::Watchers::remove(GeoNotifier* notifier)
    201 {
    202     NotifierToIdMap::iterator iter = m_notifierToIdMap.find(notifier);
    203     if (iter == m_notifierToIdMap.end())
    204         return;
    205     m_idToNotifierMap.remove(iter->value);
    206     m_notifierToIdMap.remove(iter);
    207 }
    208 
    209 bool Geolocation::Watchers::contains(GeoNotifier* notifier) const
    210 {
    211     return m_notifierToIdMap.contains(notifier);
    212 }
    213 
    214 void Geolocation::Watchers::clear()
    215 {
    216     m_idToNotifierMap.clear();
    217     m_notifierToIdMap.clear();
    218 }
    219 
    220 bool Geolocation::Watchers::isEmpty() const
    221 {
    222     return m_idToNotifierMap.isEmpty();
    223 }
    224 
    225 void Geolocation::Watchers::getNotifiersVector(GeoNotifierVector& copy) const
    226 {
    227     copyValuesToVector(m_idToNotifierMap, copy);
    228 }
    229 
    230 PassRefPtr<Geolocation> Geolocation::create(ExecutionContext* context)
    231 {
    232     RefPtr<Geolocation> geolocation = adoptRef(new Geolocation(context));
    233     geolocation->suspendIfNeeded();
    234     return geolocation.release();
    235 }
    236 
    237 Geolocation::Geolocation(ExecutionContext* context)
    238     : ActiveDOMObject(context)
    239     , m_allowGeolocation(Unknown)
    240 {
    241     ScriptWrappable::init(this);
    242 }
    243 
    244 Geolocation::~Geolocation()
    245 {
    246     ASSERT(m_allowGeolocation != InProgress);
    247 }
    248 
    249 Document* Geolocation::document() const
    250 {
    251     return toDocument(executionContext());
    252 }
    253 
    254 Frame* Geolocation::frame() const
    255 {
    256     return document() ? document()->frame() : 0;
    257 }
    258 
    259 Page* Geolocation::page() const
    260 {
    261     return document() ? document()->page() : 0;
    262 }
    263 
    264 void Geolocation::stop()
    265 {
    266     Page* page = this->page();
    267     if (page && m_allowGeolocation == InProgress)
    268         GeolocationController::from(page)->cancelPermissionRequest(this);
    269     // The frame may be moving to a new page and we want to get the permissions from the new page's client.
    270     m_allowGeolocation = Unknown;
    271     cancelAllRequests();
    272     stopUpdating();
    273     m_pendingForPermissionNotifiers.clear();
    274 }
    275 
    276 Geoposition* Geolocation::lastPosition()
    277 {
    278     Page* page = this->page();
    279     if (!page)
    280         return 0;
    281 
    282     m_lastPosition = createGeoposition(GeolocationController::from(page)->lastPosition());
    283 
    284     return m_lastPosition.get();
    285 }
    286 
    287 void Geolocation::getCurrentPosition(PassOwnPtr<PositionCallback> successCallback, PassOwnPtr<PositionErrorCallback> errorCallback, PassRefPtr<PositionOptions> options)
    288 {
    289     if (!frame())
    290         return;
    291 
    292     RefPtr<GeoNotifier> notifier = GeoNotifier::create(this, successCallback, errorCallback, options);
    293     startRequest(notifier.get());
    294 
    295     m_oneShots.add(notifier);
    296 }
    297 
    298 int Geolocation::watchPosition(PassOwnPtr<PositionCallback> successCallback, PassOwnPtr<PositionErrorCallback> errorCallback, PassRefPtr<PositionOptions> options)
    299 {
    300     if (!frame())
    301         return 0;
    302 
    303     RefPtr<GeoNotifier> notifier = GeoNotifier::create(this, successCallback, errorCallback, options);
    304     startRequest(notifier.get());
    305 
    306     int watchID;
    307     // Keep asking for the next id until we're given one that we don't already have.
    308     do {
    309         watchID = executionContext()->circularSequentialID();
    310     } while (!m_watchers.add(watchID, notifier));
    311     return watchID;
    312 }
    313 
    314 void Geolocation::startRequest(GeoNotifier *notifier)
    315 {
    316     // Check whether permissions have already been denied. Note that if this is the case,
    317     // the permission state can not change again in the lifetime of this page.
    318     if (isDenied())
    319         notifier->setFatalError(PositionError::create(PositionError::PERMISSION_DENIED, permissionDeniedErrorMessage));
    320     else if (haveSuitableCachedPosition(notifier->options()))
    321         notifier->setUseCachedPosition();
    322     else if (notifier->hasZeroTimeout())
    323         notifier->startTimerIfNeeded();
    324     else if (!isAllowed()) {
    325         // if we don't yet have permission, request for permission before calling startUpdating()
    326         m_pendingForPermissionNotifiers.add(notifier);
    327         requestPermission();
    328     } else if (startUpdating(notifier))
    329         notifier->startTimerIfNeeded();
    330     else
    331         notifier->setFatalError(PositionError::create(PositionError::POSITION_UNAVAILABLE, failedToStartServiceErrorMessage));
    332 }
    333 
    334 void Geolocation::fatalErrorOccurred(Geolocation::GeoNotifier* notifier)
    335 {
    336     // This request has failed fatally. Remove it from our lists.
    337     m_oneShots.remove(notifier);
    338     m_watchers.remove(notifier);
    339 
    340     if (!hasListeners())
    341         stopUpdating();
    342 }
    343 
    344 void Geolocation::requestUsesCachedPosition(GeoNotifier* notifier)
    345 {
    346     // This is called asynchronously, so the permissions could have been denied
    347     // since we last checked in startRequest.
    348     if (isDenied()) {
    349         notifier->setFatalError(PositionError::create(PositionError::PERMISSION_DENIED, permissionDeniedErrorMessage));
    350         return;
    351     }
    352 
    353     m_requestsAwaitingCachedPosition.add(notifier);
    354 
    355     // If permissions are allowed, make the callback
    356     if (isAllowed()) {
    357         makeCachedPositionCallbacks();
    358         return;
    359     }
    360 
    361     // Request permissions, which may be synchronous or asynchronous.
    362     requestPermission();
    363 }
    364 
    365 void Geolocation::makeCachedPositionCallbacks()
    366 {
    367     // All modifications to m_requestsAwaitingCachedPosition are done
    368     // asynchronously, so we don't need to worry about it being modified from
    369     // the callbacks.
    370     GeoNotifierSet::const_iterator end = m_requestsAwaitingCachedPosition.end();
    371     for (GeoNotifierSet::const_iterator iter = m_requestsAwaitingCachedPosition.begin(); iter != end; ++iter) {
    372         GeoNotifier* notifier = iter->get();
    373         notifier->runSuccessCallback(lastPosition());
    374 
    375         // If this is a one-shot request, stop it. Otherwise, if the watch still
    376         // exists, start the service to get updates.
    377         if (m_oneShots.contains(notifier))
    378             m_oneShots.remove(notifier);
    379         else if (m_watchers.contains(notifier)) {
    380             if (notifier->hasZeroTimeout() || startUpdating(notifier))
    381                 notifier->startTimerIfNeeded();
    382             else
    383                 notifier->setFatalError(PositionError::create(PositionError::POSITION_UNAVAILABLE, failedToStartServiceErrorMessage));
    384         }
    385     }
    386 
    387     m_requestsAwaitingCachedPosition.clear();
    388 
    389     if (!hasListeners())
    390         stopUpdating();
    391 }
    392 
    393 void Geolocation::requestTimedOut(GeoNotifier* notifier)
    394 {
    395     // If this is a one-shot request, stop it.
    396     m_oneShots.remove(notifier);
    397 
    398     if (!hasListeners())
    399         stopUpdating();
    400 }
    401 
    402 bool Geolocation::haveSuitableCachedPosition(PositionOptions* options)
    403 {
    404     Geoposition* cachedPosition = lastPosition();
    405     if (!cachedPosition)
    406         return false;
    407     if (!options->hasMaximumAge())
    408         return true;
    409     if (!options->maximumAge())
    410         return false;
    411     DOMTimeStamp currentTimeMillis = convertSecondsToDOMTimeStamp(currentTime());
    412     return cachedPosition->timestamp() > currentTimeMillis - options->maximumAge();
    413 }
    414 
    415 void Geolocation::clearWatch(int watchID)
    416 {
    417     if (watchID <= 0)
    418         return;
    419 
    420     if (GeoNotifier* notifier = m_watchers.find(watchID))
    421         m_pendingForPermissionNotifiers.remove(notifier);
    422     m_watchers.remove(watchID);
    423 
    424     if (!hasListeners())
    425         stopUpdating();
    426 }
    427 
    428 void Geolocation::setIsAllowed(bool allowed)
    429 {
    430     // Protect the Geolocation object from garbage collection during a callback.
    431     RefPtr<Geolocation> protect(this);
    432 
    433     // This may be due to either a new position from the service, or a cached
    434     // position.
    435     m_allowGeolocation = allowed ? Yes : No;
    436 
    437     // Permission request was made during the startRequest process
    438     if (!m_pendingForPermissionNotifiers.isEmpty()) {
    439         handlePendingPermissionNotifiers();
    440         m_pendingForPermissionNotifiers.clear();
    441         return;
    442     }
    443 
    444     if (!isAllowed()) {
    445         RefPtr<PositionError> error = PositionError::create(PositionError::PERMISSION_DENIED, permissionDeniedErrorMessage);
    446         error->setIsFatal(true);
    447         handleError(error.get());
    448         m_requestsAwaitingCachedPosition.clear();
    449         return;
    450     }
    451 
    452     // If the service has a last position, use it to call back for all requests.
    453     // If any of the requests are waiting for permission for a cached position,
    454     // the position from the service will be at least as fresh.
    455     if (lastPosition())
    456         makeSuccessCallbacks();
    457     else
    458         makeCachedPositionCallbacks();
    459 }
    460 
    461 void Geolocation::sendError(GeoNotifierVector& notifiers, PositionError* error)
    462 {
    463      GeoNotifierVector::const_iterator end = notifiers.end();
    464      for (GeoNotifierVector::const_iterator it = notifiers.begin(); it != end; ++it) {
    465          RefPtr<GeoNotifier> notifier = *it;
    466 
    467          notifier->runErrorCallback(error);
    468      }
    469 }
    470 
    471 void Geolocation::sendPosition(GeoNotifierVector& notifiers, Geoposition* position)
    472 {
    473     GeoNotifierVector::const_iterator end = notifiers.end();
    474     for (GeoNotifierVector::const_iterator it = notifiers.begin(); it != end; ++it)
    475         (*it)->runSuccessCallback(position);
    476 }
    477 
    478 void Geolocation::stopTimer(GeoNotifierVector& notifiers)
    479 {
    480     GeoNotifierVector::const_iterator end = notifiers.end();
    481     for (GeoNotifierVector::const_iterator it = notifiers.begin(); it != end; ++it)
    482         (*it)->stopTimer();
    483 }
    484 
    485 void Geolocation::stopTimersForOneShots()
    486 {
    487     GeoNotifierVector copy;
    488     copyToVector(m_oneShots, copy);
    489 
    490     stopTimer(copy);
    491 }
    492 
    493 void Geolocation::stopTimersForWatchers()
    494 {
    495     GeoNotifierVector copy;
    496     m_watchers.getNotifiersVector(copy);
    497 
    498     stopTimer(copy);
    499 }
    500 
    501 void Geolocation::stopTimers()
    502 {
    503     stopTimersForOneShots();
    504     stopTimersForWatchers();
    505 }
    506 
    507 void Geolocation::cancelRequests(GeoNotifierVector& notifiers)
    508 {
    509     GeoNotifierVector::const_iterator end = notifiers.end();
    510     for (GeoNotifierVector::const_iterator it = notifiers.begin(); it != end; ++it)
    511         (*it)->setFatalError(PositionError::create(PositionError::POSITION_UNAVAILABLE, framelessDocumentErrorMessage));
    512 }
    513 
    514 void Geolocation::cancelAllRequests()
    515 {
    516     GeoNotifierVector copy;
    517     copyToVector(m_oneShots, copy);
    518     cancelRequests(copy);
    519     m_watchers.getNotifiersVector(copy);
    520     cancelRequests(copy);
    521 }
    522 
    523 void Geolocation::extractNotifiersWithCachedPosition(GeoNotifierVector& notifiers, GeoNotifierVector* cached)
    524 {
    525     GeoNotifierVector nonCached;
    526     GeoNotifierVector::iterator end = notifiers.end();
    527     for (GeoNotifierVector::const_iterator it = notifiers.begin(); it != end; ++it) {
    528         GeoNotifier* notifier = it->get();
    529         if (notifier->useCachedPosition()) {
    530             if (cached)
    531                 cached->append(notifier);
    532         } else
    533             nonCached.append(notifier);
    534     }
    535     notifiers.swap(nonCached);
    536 }
    537 
    538 void Geolocation::copyToSet(const GeoNotifierVector& src, GeoNotifierSet& dest)
    539 {
    540      GeoNotifierVector::const_iterator end = src.end();
    541      for (GeoNotifierVector::const_iterator it = src.begin(); it != end; ++it) {
    542          GeoNotifier* notifier = it->get();
    543          dest.add(notifier);
    544      }
    545 }
    546 
    547 void Geolocation::handleError(PositionError* error)
    548 {
    549     ASSERT(error);
    550 
    551     GeoNotifierVector oneShotsCopy;
    552     copyToVector(m_oneShots, oneShotsCopy);
    553 
    554     GeoNotifierVector watchersCopy;
    555     m_watchers.getNotifiersVector(watchersCopy);
    556 
    557     // Clear the lists before we make the callbacks, to avoid clearing notifiers
    558     // added by calls to Geolocation methods from the callbacks, and to prevent
    559     // further callbacks to these notifiers.
    560     GeoNotifierVector oneShotsWithCachedPosition;
    561     m_oneShots.clear();
    562     if (error->isFatal())
    563         m_watchers.clear();
    564     else {
    565         // Don't send non-fatal errors to notifiers due to receive a cached position.
    566         extractNotifiersWithCachedPosition(oneShotsCopy, &oneShotsWithCachedPosition);
    567         extractNotifiersWithCachedPosition(watchersCopy, 0);
    568     }
    569 
    570     sendError(oneShotsCopy, error);
    571     sendError(watchersCopy, error);
    572 
    573     // hasListeners() doesn't distinguish between notifiers due to receive a
    574     // cached position and those requiring a fresh position. Perform the check
    575     // before restoring the notifiers below.
    576     if (!hasListeners())
    577         stopUpdating();
    578 
    579     // Maintain a reference to the cached notifiers until their timer fires.
    580     copyToSet(oneShotsWithCachedPosition, m_oneShots);
    581 }
    582 
    583 void Geolocation::requestPermission()
    584 {
    585     if (m_allowGeolocation > Unknown)
    586         return;
    587 
    588     Page* page = this->page();
    589     if (!page)
    590         return;
    591 
    592     m_allowGeolocation = InProgress;
    593 
    594     // Ask the embedder: it maintains the geolocation challenge policy itself.
    595     GeolocationController::from(page)->requestPermission(this);
    596 }
    597 
    598 void Geolocation::makeSuccessCallbacks()
    599 {
    600     ASSERT(lastPosition());
    601     ASSERT(isAllowed());
    602 
    603     GeoNotifierVector oneShotsCopy;
    604     copyToVector(m_oneShots, oneShotsCopy);
    605 
    606     GeoNotifierVector watchersCopy;
    607     m_watchers.getNotifiersVector(watchersCopy);
    608 
    609     // Clear the lists before we make the callbacks, to avoid clearing notifiers
    610     // added by calls to Geolocation methods from the callbacks, and to prevent
    611     // further callbacks to these notifiers.
    612     m_oneShots.clear();
    613 
    614     // Also clear the set of notifiers waiting for a cached position. All the
    615     // oneshots and watchers will receive a position now, and if they happen to
    616     // be lingering in that set, avoid this bug: http://crbug.com/311876 .
    617     m_requestsAwaitingCachedPosition.clear();
    618 
    619     sendPosition(oneShotsCopy, lastPosition());
    620     sendPosition(watchersCopy, lastPosition());
    621 
    622     if (!hasListeners())
    623         stopUpdating();
    624 }
    625 
    626 void Geolocation::positionChanged()
    627 {
    628     ASSERT(isAllowed());
    629 
    630     // Stop all currently running timers.
    631     stopTimers();
    632 
    633     makeSuccessCallbacks();
    634 }
    635 
    636 void Geolocation::setError(GeolocationError* error)
    637 {
    638     RefPtr<PositionError> positionError = createPositionError(error);
    639     handleError(positionError.get());
    640 }
    641 
    642 bool Geolocation::startUpdating(GeoNotifier* notifier)
    643 {
    644     Page* page = this->page();
    645     if (!page)
    646         return false;
    647 
    648     GeolocationController::from(page)->addObserver(this, notifier->options()->enableHighAccuracy());
    649     return true;
    650 }
    651 
    652 void Geolocation::stopUpdating()
    653 {
    654     Page* page = this->page();
    655     if (!page)
    656         return;
    657 
    658     GeolocationController::from(page)->removeObserver(this);
    659 }
    660 
    661 void Geolocation::handlePendingPermissionNotifiers()
    662 {
    663     // While we iterate through the list, we need not worry about list being modified as the permission
    664     // is already set to Yes/No and no new listeners will be added to the pending list
    665     GeoNotifierSet::const_iterator end = m_pendingForPermissionNotifiers.end();
    666     for (GeoNotifierSet::const_iterator iter = m_pendingForPermissionNotifiers.begin(); iter != end; ++iter) {
    667         GeoNotifier* notifier = iter->get();
    668 
    669         if (isAllowed()) {
    670             // start all pending notification requests as permission granted.
    671             // The notifier is always ref'ed by m_oneShots or m_watchers.
    672             if (startUpdating(notifier))
    673                 notifier->startTimerIfNeeded();
    674             else
    675                 notifier->setFatalError(PositionError::create(PositionError::POSITION_UNAVAILABLE, failedToStartServiceErrorMessage));
    676         } else {
    677             notifier->setFatalError(PositionError::create(PositionError::PERMISSION_DENIED, permissionDeniedErrorMessage));
    678         }
    679     }
    680 }
    681 
    682 } // namespace WebCore
    683