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