WebCore/ChangeLog

 12009-10-06 Steve Block <steveblock@google.com>
 2
 3 Reviewed by NOBODY (OOPS!).
 4
 5 Geolocation should be refactored to use a single map to store all notifiers.
 6 https://bugs.webkit.org/show_bug.cgi?id=29178
 7
 8 * page/Geolocation.cpp: Modified.
 9 (WebCore::Geolocation::GeoNotifier::GeoNotifier): Modified. Takes request ID as argument.
 10 (WebCore::Geolocation::GeoNotifier::timerFired): Modified. Uses request ID as argument to requestTimedOut.
 11 (WebCore::Geolocation::getCurrentPosition): Modified. Moved common logic to startRequest.
 12 (WebCore::Geolocation::watchPosition): Modified. Moved common logic to startRequest.
 13 (WebCore::Geolocation::startRequest): Added. Starts a one-shot or watch request.
 14 (WebCore::Geolocation::requestTimedOut): Modified. Takes request ID as argument.
 15 (WebCore::Geolocation::clearWatch): Modified. Uses single map for all requests.
 16 (WebCore::Geolocation::stopTimers): Modified. Uses single map for all requests.
 17 (WebCore::Geolocation::handleError): Modified. Uses single map for all requests.
 18 (WebCore::Geolocation::makeSuccessCallbacks): Modified. Uses single map for all requests.
 19 (WebCore::Geolocation::clearOneShots): Added. Removes one-shot requests.
 20 (WebCore::Geolocation::isOneShotRequest): Added. Determines whether a request ID refers to a one-shot request.
 21 * page/Geolocation.h: Modified.
 22 (WebCore::Geolocation::GeoNotifier::create): Modified. Takes request ID as argument.
 23 (WebCore::Geolocation::hasListeners): Modified. Uses single map for all requests.
 24
1252009-10-06 Antti Koivisto <antti@apple.com>
226
327 Reviewed by Dave Kilzer.
49203

WebCore/page/Geolocation.cpp

3535
3636namespace WebCore {
3737
38 Geolocation::GeoNotifier::GeoNotifier(Geolocation* geolocation, PassRefPtr<PositionCallback> successCallback, PassRefPtr<PositionErrorCallback> errorCallback, PassRefPtr<PositionOptions> options)
39  : m_geolocation(geolocation)
 38static const int firstOneShotId = 1 << 30;
 39static const int firstWatchId = 1;
 40
 41Geolocation::GeoNotifier::GeoNotifier(int requestId, Geolocation* geolocation, PassRefPtr<PositionCallback> successCallback, PassRefPtr<PositionErrorCallback> errorCallback, PassRefPtr<PositionOptions> options)
 42 : m_requestId(requestId)
 43 , m_geolocation(geolocation)
4044 , m_successCallback(successCallback)
4145 , m_errorCallback(errorCallback)
4246 , m_options(options)

@@void Geolocation::GeoNotifier::timerFire
6771 RefPtr<PositionError> error = PositionError::create(PositionError::TIMEOUT, "Timeout expired");
6872 m_errorCallback->handleEvent(error.get());
6973 }
70  m_geolocation->requestTimedOut(this);
 74 m_geolocation->requestTimedOut(m_requestId);
7175}
7276
7377Geolocation::Geolocation(Frame* frame)

@@void Geolocation::disconnectFrame()
9296
9397void Geolocation::getCurrentPosition(PassRefPtr<PositionCallback> successCallback, PassRefPtr<PositionErrorCallback> errorCallback, PassRefPtr<PositionOptions> options)
9498{
95  RefPtr<GeoNotifier> notifier = GeoNotifier::create(this, successCallback, errorCallback, options);
 99 static int nextAvailableOneShotId = firstOneShotId;
 100 // Handle wrap-around.
 101 if (!isOneShotRequest(nextAvailableOneShotId))
 102 nextAvailableOneShotId = firstOneShotId;
96103
97  if (notifier->hasZeroTimeout() || m_service->startUpdating(notifier->m_options.get()))
98  notifier->startTimerIfNeeded();
99  else {
100  if (notifier->m_errorCallback) {
101  RefPtr<PositionError> error = PositionError::create(PositionError::PERMISSION_DENIED, "Unable to Start");
102  notifier->m_errorCallback->handleEvent(error.get());
103  }
 104 RefPtr<GeoNotifier> notifier = startRequest(nextAvailableOneShotId, successCallback, errorCallback, options);
 105 if (!notifier)
104106 return;
105  }
106107
107  m_oneShots.add(notifier);
 108 m_notifiers.set(nextAvailableOneShotId, notifier);
 109 nextAvailableOneShotId++;
108110}
109111
110112int Geolocation::watchPosition(PassRefPtr<PositionCallback> successCallback, PassRefPtr<PositionErrorCallback> errorCallback, PassRefPtr<PositionOptions> options)
111113{
112  RefPtr<GeoNotifier> notifier = GeoNotifier::create(this, successCallback, errorCallback, options);
 114 static int nextAvailableWatchId = firstWatchId;
 115 // Handle wrap-around.
 116 if (isOneShotRequest(nextAvailableWatchId))
 117 nextAvailableWatchId = firstWatchId;
 118
 119 RefPtr<GeoNotifier> notifier = startRequest(nextAvailableWatchId, successCallback, errorCallback, options);
 120 if (!notifier)
 121 return 0;
 122
 123 m_notifiers.set(nextAvailableWatchId, notifier);
 124 return nextAvailableWatchId++;
 125}
 126
 127PassRefPtr<Geolocation::GeoNotifier> Geolocation::startRequest(int requestId, PassRefPtr<PositionCallback> successCallback, PassRefPtr<PositionErrorCallback> errorCallback, PassRefPtr<PositionOptions> options)
 128{
 129 RefPtr<GeoNotifier> notifier = GeoNotifier::create(requestId, this, successCallback, errorCallback, options);
113130
114131 if (notifier->hasZeroTimeout() || m_service->startUpdating(notifier->m_options.get()))
115132 notifier->startTimerIfNeeded();

@@int Geolocation::watchPosition(PassRefPt
120137 }
121138 return 0;
122139 }
123 
124  static int sIdentifier = 0;
125 
126  m_watchers.set(++sIdentifier, notifier);
127140
128  return sIdentifier;
 141 return notifier.release();
129142}
130143
131 void Geolocation::requestTimedOut(GeoNotifier* notifier)
 144void Geolocation::requestTimedOut(int requestId)
132145{
 146 ASSERT(m_notifiers.contains(requestId));
 147
133148 // If this is a one-shot request, stop it.
134  m_oneShots.remove(notifier);
 149 if (!isOneShotRequest(requestId))
 150 return;
135151
 152 m_notifiers.remove(requestId);
136153 if (!hasListeners())
137154 m_service->stopUpdating();
138155}
139156
140157void Geolocation::clearWatch(int watchId)
141158{
142  m_watchers.remove(watchId);
143 
 159 if (isOneShotRequest(watchId))
 160 return;
 161
 162 m_notifiers.remove(watchId);
144163 if (!hasListeners())
145164 m_service->stopUpdating();
146165}

@@void Geolocation::setIsAllowed(bool allo
170189 }
171190}
172191
173 void Geolocation::sendError(Vector<RefPtr<GeoNotifier> >& notifiers, PositionError* error)
 192bool Geolocation::isOneShotRequest(int requestId)
174193{
175  Vector<RefPtr<GeoNotifier> >::const_iterator end = notifiers.end();
176  for (Vector<RefPtr<GeoNotifier> >::const_iterator it = notifiers.begin(); it != end; ++it) {
177  RefPtr<GeoNotifier> notifier = *it;
178 
179  if (notifier->m_errorCallback)
180  notifier->m_errorCallback->handleEvent(error);
181  }
 194 // This relies on the fact that one-shot request IDs are greater than watch IDs.
 195 return requestId >= firstOneShotId;
182196}
183197
184 void Geolocation::sendPosition(Vector<RefPtr<GeoNotifier> >& notifiers, Geoposition* position)
 198void Geolocation::sendError(Vector<RefPtr<GeoNotifier> >& notifiers, PositionError* error)
185199{
186200 Vector<RefPtr<GeoNotifier> >::const_iterator end = notifiers.end();
187201 for (Vector<RefPtr<GeoNotifier> >::const_iterator it = notifiers.begin(); it != end; ++it) {
188202 RefPtr<GeoNotifier> notifier = *it;
189  ASSERT(notifier->m_successCallback);
190 
191  notifier->m_successCallback->handleEvent(position);
 203
 204 if (notifier->m_errorCallback)
 205 notifier->m_errorCallback->handleEvent(error);
192206 }
193207}
194208
195 void Geolocation::stopTimer(Vector<RefPtr<GeoNotifier> >& notifiers)
 209void Geolocation::sendPosition(Vector<RefPtr<GeoNotifier> >& notifiers, Geoposition* position)
196210{
197211 Vector<RefPtr<GeoNotifier> >::const_iterator end = notifiers.end();
198212 for (Vector<RefPtr<GeoNotifier> >::const_iterator it = notifiers.begin(); it != end; ++it) {
199213 RefPtr<GeoNotifier> notifier = *it;
200  notifier->m_timer.stop();
 214 ASSERT(notifier->m_successCallback);
 215
 216 notifier->m_successCallback->handleEvent(position);
201217 }
202218}
203219
204 void Geolocation::stopTimersForOneShots()
205 {
206  Vector<RefPtr<GeoNotifier> > copy;
207  copyToVector(m_oneShots, copy);
208 
209  stopTimer(copy);
210 }
211 
212 void Geolocation::stopTimersForWatchers()
213 {
214  Vector<RefPtr<GeoNotifier> > copy;
215  copyValuesToVector(m_watchers, copy);
216 
217  stopTimer(copy);
218 }
219 
220220void Geolocation::stopTimers()
221221{
222  stopTimersForOneShots();
223  stopTimersForWatchers();
 222 GeoNotifierMap::const_iterator end = m_notifiers.end();
 223 for (GeoNotifierMap::const_iterator it = m_notifiers.begin(); it != end; ++it) {
 224 GeoNotifier* notifier = it->second.get();
 225 notifier->m_timer.stop();
 226 }
224227}
225228
226229void Geolocation::handleError(PositionError* error)
227230{
228231 ASSERT(error);
229232
230  Vector<RefPtr<GeoNotifier> > oneShotsCopy;
231  copyToVector(m_oneShots, oneShotsCopy);
232 
233  Vector<RefPtr<GeoNotifier> > watchersCopy;
234  copyValuesToVector(m_watchers, watchersCopy);
 233 Vector<RefPtr<GeoNotifier> > copy;
 234 copyValuesToVector(m_notifiers, copy);
235235
236  // Clear the lists before we make the callbacks, to avoid clearing notifiers
 236 // Clear the notifiers before we make the callbacks, to avoid clearing notifiers
237237 // added by calls to Geolocation methods from the callbacks, and to prevent
238238 // further callbacks to these notifiers.
239  m_oneShots.clear();
240239 if (error->isFatal())
241  m_watchers.clear();
 240 m_notifiers.clear();
 241 else
 242 clearOneShots();
242243
243  sendError(oneShotsCopy, error);
244  sendError(watchersCopy, error);
 244 sendError(copy, error);
245245
246246 if (!hasListeners())
247247 m_service->stopUpdating();

@@void Geolocation::makeSuccessCallbacks()
290290 ASSERT(m_service->lastPosition());
291291 ASSERT(isAllowed());
292292
293  Vector<RefPtr<GeoNotifier> > oneShotsCopy;
294  copyToVector(m_oneShots, oneShotsCopy);
295 
296  Vector<RefPtr<GeoNotifier> > watchersCopy;
297  copyValuesToVector(m_watchers, watchersCopy);
 293 Vector<RefPtr<GeoNotifier> > copy;
 294 copyValuesToVector(m_notifiers, copy);
298295
299  // Clear the lists before we make the callbacks, to avoid clearing notifiers
 296 // Clear the one-shots before we make the callbacks, to avoid clearing notifiers
300297 // added by calls to Geolocation methods from the callbacks, and to prevent
301298 // further callbacks to these notifiers.
302  m_oneShots.clear();
 299 clearOneShots();
303300
304  sendPosition(oneShotsCopy, m_service->lastPosition());
305  sendPosition(watchersCopy, m_service->lastPosition());
 301 sendPosition(copy, m_service->lastPosition());
306302
307303 if (!hasListeners())
308304 m_service->stopUpdating();

@@void Geolocation::geolocationServiceErro
315311 handleError(service->lastError());
316312}
317313
 314void Geolocation::clearOneShots()
 315{
 316 Vector<int> oneShotIds;
 317 GeoNotifierMap::const_iterator end = m_notifiers.end();
 318 for (GeoNotifierMap::const_iterator iter = m_notifiers.begin(); iter != end; ++iter) {
 319 if (isOneShotRequest(iter->first))
 320 oneShotIds.append(iter->first);
 321 }
 322 for (Vector<int>::const_iterator iter = oneShotIds.begin(); iter != oneShotIds.end(); iter++)
 323 m_notifiers.remove(*iter);
 324}
 325
318326} // namespace WebCore
49203

WebCore/page/Geolocation.h

3333#include "Timer.h"
3434#include <wtf/Platform.h>
3535#include <wtf/HashMap.h>
36 #include <wtf/HashSet.h>
3736#include <wtf/OwnPtr.h>
3837#include <wtf/PassRefPtr.h>
3938#include <wtf/RefCounted.h>

@@private:
7372
7473 class GeoNotifier : public RefCounted<GeoNotifier> {
7574 public:
76  static PassRefPtr<GeoNotifier> create(Geolocation* geolocation, PassRefPtr<PositionCallback> positionCallback, PassRefPtr<PositionErrorCallback> positionErrorCallback, PassRefPtr<PositionOptions> options) { return adoptRef(new GeoNotifier(geolocation, positionCallback, positionErrorCallback, options)); }
 75 static PassRefPtr<GeoNotifier> create(int requestId, Geolocation* geolocation, PassRefPtr<PositionCallback> positionCallback, PassRefPtr<PositionErrorCallback> positionErrorCallback, PassRefPtr<PositionOptions> options) { return adoptRef(new GeoNotifier(requestId, geolocation, positionCallback, positionErrorCallback, options)); }
7776
7877 bool hasZeroTimeout() const;
7978 void startTimerIfNeeded();
8079 void timerFired(Timer<GeoNotifier>*);
8180
 81 int m_requestId;
8282 Geolocation* m_geolocation;
8383 RefPtr<PositionCallback> m_successCallback;
8484 RefPtr<PositionErrorCallback> m_errorCallback;

@@private:
8686 Timer<GeoNotifier> m_timer;
8787
8888 private:
89  GeoNotifier(Geolocation*, PassRefPtr<PositionCallback>, PassRefPtr<PositionErrorCallback>, PassRefPtr<PositionOptions>);
 89 GeoNotifier(int requestId, Geolocation*, PassRefPtr<PositionCallback>, PassRefPtr<PositionErrorCallback>, PassRefPtr<PositionOptions>);
9090 };
9191
92  bool hasListeners() const { return !m_oneShots.isEmpty() || !m_watchers.isEmpty(); }
 92 PassRefPtr<GeoNotifier> startRequest(int requestId, PassRefPtr<PositionCallback>, PassRefPtr<PositionErrorCallback>, PassRefPtr<PositionOptions>);
 93
 94 bool hasListeners() const { return !m_notifiers.isEmpty(); }
 95
 96 static bool isOneShotRequest(int requestId);
9397
9498 void sendError(Vector<RefPtr<GeoNotifier> >&, PositionError*);
9599 void sendPosition(Vector<RefPtr<GeoNotifier> >&, Geoposition*);
96100
97  static void stopTimer(Vector<RefPtr<GeoNotifier> >&);
98  void stopTimersForOneShots();
99  void stopTimersForWatchers();
100101 void stopTimers();
101102
102103 void makeSuccessCallbacks();

@@private:
108109 virtual void geolocationServicePositionChanged(GeolocationService*);
109110 virtual void geolocationServiceErrorOccurred(GeolocationService*);
110111
111  void requestTimedOut(GeoNotifier*);
 112 void requestTimedOut(int requestId);
 113
 114 void clearOneShots();
112115
113  typedef HashSet<RefPtr<GeoNotifier> > GeoNotifierSet;
 116 // A map from notifier ID to notifier. We use positive IDs for watchers, and
 117 // negative IDs for one-shots. Only watcher IDs are exposed to JS.
114118 typedef HashMap<int, RefPtr<GeoNotifier> > GeoNotifierMap;
115 
116  GeoNotifierSet m_oneShots;
117  GeoNotifierMap m_watchers;
 119 GeoNotifierMap m_notifiers;
 120
118121 Frame* m_frame;
119122 OwnPtr<GeolocationService> m_service;
120123
49203