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