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