Upstream version 5.34.92.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / 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 "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