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