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