• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 Apple Inc. All Rights Reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 #include "config.h"
27 #include "Geolocation.h"
28 
29 #include "Document.h"
30 #include "Frame.h"
31 #include "PositionError.h"
32 
33 namespace WebCore {
34 
GeoNotifier(PassRefPtr<PositionCallback> successCallback,PassRefPtr<PositionErrorCallback> errorCallback,PositionOptions * options)35 Geolocation::GeoNotifier::GeoNotifier(PassRefPtr<PositionCallback> successCallback, PassRefPtr<PositionErrorCallback> errorCallback, PositionOptions* options)
36     : m_successCallback(successCallback)
37     , m_errorCallback(errorCallback)
38     , m_timer(this, &Geolocation::GeoNotifier::timerFired)
39 {
40     if (m_errorCallback && options)
41         m_timer.startOneShot(options->timeout() / 1000.0);
42 }
43 
timerFired(Timer<GeoNotifier> *)44 void Geolocation::GeoNotifier::timerFired(Timer<GeoNotifier>*)
45 {
46     ASSERT(m_errorCallback);
47 
48     m_timer.stop();
49 
50     RefPtr<PositionError> error = PositionError::create(PositionError::TIMEOUT, "Timed out");
51     m_errorCallback->handleEvent(error.get());
52 }
53 
Geolocation(Frame * frame)54 Geolocation::Geolocation(Frame* frame)
55     : m_frame(frame)
56     , m_service(GeolocationService::create(this))
57 {
58     ASSERT(m_frame->document());
59     m_frame->document()->setUsingGeolocation(true);
60 }
61 
disconnectFrame()62 void Geolocation::disconnectFrame()
63 {
64     m_service->stopUpdating();
65     if (m_frame->document())
66         m_frame->document()->setUsingGeolocation(false);
67     m_frame = 0;
68 }
69 
getCurrentPosition(PassRefPtr<PositionCallback> successCallback,PassRefPtr<PositionErrorCallback> errorCallback,PositionOptions * options)70 void Geolocation::getCurrentPosition(PassRefPtr<PositionCallback> successCallback, PassRefPtr<PositionErrorCallback> errorCallback, PositionOptions* options)
71 {
72     RefPtr<GeoNotifier> notifier = GeoNotifier::create(successCallback, errorCallback, options);
73 
74     if (!m_service->startUpdating(options)) {
75         if (notifier->m_errorCallback) {
76             RefPtr<PositionError> error = PositionError::create(PositionError::PERMISSION_DENIED, "Unable to Start");
77             notifier->m_errorCallback->handleEvent(error.get());
78         }
79         return;
80     }
81 
82     m_oneShots.add(notifier);
83 }
84 
watchPosition(PassRefPtr<PositionCallback> successCallback,PassRefPtr<PositionErrorCallback> errorCallback,PositionOptions * options)85 int Geolocation::watchPosition(PassRefPtr<PositionCallback> successCallback, PassRefPtr<PositionErrorCallback> errorCallback, PositionOptions* options)
86 {
87     RefPtr<GeoNotifier> notifier = GeoNotifier::create(successCallback, errorCallback, options);
88 
89     if (!m_service->startUpdating(options)) {
90         if (notifier->m_errorCallback) {
91             RefPtr<PositionError> error = PositionError::create(PositionError::PERMISSION_DENIED, "Unable to Start");
92             notifier->m_errorCallback->handleEvent(error.get());
93         }
94         return 0;
95     }
96 
97     static int sIdentifier = 0;
98 
99     m_watchers.set(++sIdentifier, notifier);
100 
101     return sIdentifier;
102 }
103 
clearWatch(int watchId)104 void Geolocation::clearWatch(int watchId)
105 {
106     m_watchers.remove(watchId);
107 
108     if (!hasListeners())
109         m_service->stopUpdating();
110 }
111 
suspend()112 void Geolocation::suspend()
113 {
114     if (hasListeners())
115         m_service->suspend();
116 }
117 
resume()118 void Geolocation::resume()
119 {
120     if (hasListeners())
121         m_service->resume();
122 }
123 
sendErrorToOneShots(PositionError * error)124 void Geolocation::sendErrorToOneShots(PositionError* error)
125 {
126     Vector<RefPtr<GeoNotifier> > copy;
127     copyToVector(m_oneShots, copy);
128 
129     Vector<RefPtr<GeoNotifier> >::const_iterator end = copy.end();
130     for (Vector<RefPtr<GeoNotifier> >::const_iterator it = copy.begin(); it != end; ++it) {
131         RefPtr<GeoNotifier> notifier = *it;
132 
133         if (notifier->m_errorCallback)
134             notifier->m_errorCallback->handleEvent(error);
135     }
136 }
137 
sendErrorToWatchers(PositionError * error)138 void Geolocation::sendErrorToWatchers(PositionError* error)
139 {
140     Vector<RefPtr<GeoNotifier> > copy;
141     copyValuesToVector(m_watchers, copy);
142 
143     Vector<RefPtr<GeoNotifier> >::const_iterator end = copy.end();
144     for (Vector<RefPtr<GeoNotifier> >::const_iterator it = copy.begin(); it != end; ++it) {
145         RefPtr<GeoNotifier> notifier = *it;
146 
147         if (notifier->m_errorCallback)
148             notifier->m_errorCallback->handleEvent(error);
149     }
150 }
151 
sendPositionToOneShots(Geoposition * position)152 void Geolocation::sendPositionToOneShots(Geoposition* position)
153 {
154     Vector<RefPtr<GeoNotifier> > copy;
155     copyToVector(m_oneShots, copy);
156 
157     Vector<RefPtr<GeoNotifier> >::const_iterator end = copy.end();
158     for (Vector<RefPtr<GeoNotifier> >::const_iterator it = copy.begin(); it != end; ++it) {
159         RefPtr<GeoNotifier> notifier = *it;
160         ASSERT(notifier->m_successCallback);
161 
162         notifier->m_timer.stop();
163         bool shouldCallErrorCallback = false;
164         notifier->m_successCallback->handleEvent(position, shouldCallErrorCallback);
165         if (shouldCallErrorCallback) {
166             RefPtr<PositionError> error = PositionError::create(PositionError::UNKNOWN_ERROR, "An exception was thrown");
167             handleError(error.get());
168         }
169     }
170 }
171 
sendPositionToWatchers(Geoposition * position)172 void Geolocation::sendPositionToWatchers(Geoposition* position)
173 {
174     Vector<RefPtr<GeoNotifier> > copy;
175     copyValuesToVector(m_watchers, copy);
176 
177     Vector<RefPtr<GeoNotifier> >::const_iterator end = copy.end();
178     for (Vector<RefPtr<GeoNotifier> >::const_iterator it = copy.begin(); it != end; ++it) {
179         RefPtr<GeoNotifier> notifier = *it;
180         ASSERT(notifier->m_successCallback);
181 
182         notifier->m_timer.stop();
183         bool shouldCallErrorCallback = false;
184         notifier->m_successCallback->handleEvent(position, shouldCallErrorCallback);
185         if (shouldCallErrorCallback) {
186             RefPtr<PositionError> error = PositionError::create(PositionError::UNKNOWN_ERROR, "An exception was thrown");
187             handleError(error.get());
188         }
189     }
190 }
191 
handleError(PositionError * error)192 void Geolocation::handleError(PositionError* error)
193 {
194     ASSERT(error);
195 
196     sendErrorToOneShots(error);
197     sendErrorToWatchers(error);
198 
199     m_oneShots.clear();
200 }
201 
geolocationServicePositionChanged(GeolocationService * service)202 void Geolocation::geolocationServicePositionChanged(GeolocationService* service)
203 {
204     ASSERT(service->lastPosition());
205 
206     sendPositionToOneShots(service->lastPosition());
207     sendPositionToWatchers(service->lastPosition());
208 
209     m_oneShots.clear();
210 
211     if (!hasListeners())
212         m_service->stopUpdating();
213 }
214 
geolocationServiceErrorOccurred(GeolocationService * service)215 void Geolocation::geolocationServiceErrorOccurred(GeolocationService* service)
216 {
217     ASSERT(service->lastError());
218 
219     handleError(service->lastError());
220 }
221 
222 } // namespace WebCore
223