OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2008, 2009, 2010, 2011 Apple Inc. All Rights Reserved. | 2 * Copyright (C) 2008, 2009, 2010, 2011 Apple Inc. All Rights Reserved. |
3 * Copyright (C) 2009 Torch Mobile, Inc. | 3 * Copyright (C) 2009 Torch Mobile, Inc. |
4 * Copyright 2010, The Android Open Source Project | 4 * Copyright 2010, The Android Open Source Project |
5 * | 5 * |
6 * Redistribution and use in source and binary forms, with or without | 6 * Redistribution and use in source and binary forms, with or without |
7 * modification, are permitted provided that the following conditions | 7 * modification, are permitted provided that the following conditions |
8 * are met: | 8 * are met: |
9 * 1. Redistributions of source code must retain the above copyright | 9 * 1. Redistributions of source code must retain the above copyright |
10 * notice, this list of conditions and the following disclaimer. | 10 * notice, this list of conditions and the following disclaimer. |
(...skipping 11 matching lines...) Expand all Loading... |
22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | 22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
23 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 23 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 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. | 25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 */ | 26 */ |
27 | 27 |
28 #include "config.h" | 28 #include "config.h" |
29 #include "modules/geolocation/Geolocation.h" | 29 #include "modules/geolocation/Geolocation.h" |
30 | 30 |
31 #include "core/dom/Document.h" | 31 #include "core/dom/Document.h" |
32 #include "wtf/CurrentTime.h" | |
33 | |
34 #include "modules/geolocation/Coordinates.h" | 32 #include "modules/geolocation/Coordinates.h" |
35 #include "modules/geolocation/GeolocationController.h" | 33 #include "modules/geolocation/GeolocationController.h" |
36 #include "modules/geolocation/GeolocationError.h" | 34 #include "modules/geolocation/GeolocationError.h" |
37 #include "modules/geolocation/GeolocationPosition.h" | 35 #include "modules/geolocation/GeolocationPosition.h" |
| 36 #include "wtf/CurrentTime.h" |
38 | 37 |
39 namespace WebCore { | 38 namespace WebCore { |
40 | 39 |
41 static const char permissionDeniedErrorMessage[] = "User denied Geolocation"; | 40 static const char permissionDeniedErrorMessage[] = "User denied Geolocation"; |
42 static const char failedToStartServiceErrorMessage[] = "Failed to start Geolocat
ion service"; | 41 static const char failedToStartServiceErrorMessage[] = "Failed to start Geolocat
ion service"; |
43 static const char framelessDocumentErrorMessage[] = "Geolocation cannot be used
in frameless documents"; | 42 static const char framelessDocumentErrorMessage[] = "Geolocation cannot be used
in frameless documents"; |
44 | 43 |
45 static PassRefPtrWillBeRawPtr<Geoposition> createGeoposition(GeolocationPosition
* position) | 44 static Geoposition* createGeoposition(GeolocationPosition* position) |
46 { | 45 { |
47 if (!position) | 46 if (!position) |
48 return nullptr; | 47 return nullptr; |
49 | 48 |
50 RefPtrWillBeRawPtr<Coordinates> coordinates = Coordinates::create( | 49 Coordinates* coordinates = Coordinates::create( |
51 position->latitude(), | 50 position->latitude(), |
52 position->longitude(), | 51 position->longitude(), |
53 position->canProvideAltitude(), | 52 position->canProvideAltitude(), |
54 position->altitude(), | 53 position->altitude(), |
55 position->accuracy(), | 54 position->accuracy(), |
56 position->canProvideAltitudeAccuracy(), | 55 position->canProvideAltitudeAccuracy(), |
57 position->altitudeAccuracy(), | 56 position->altitudeAccuracy(), |
58 position->canProvideHeading(), | 57 position->canProvideHeading(), |
59 position->heading(), | 58 position->heading(), |
60 position->canProvideSpeed(), | 59 position->canProvideSpeed(), |
61 position->speed()); | 60 position->speed()); |
62 return Geoposition::create(coordinates.release(), convertSecondsToDOMTimeSta
mp(position->timestamp())); | 61 return Geoposition::create(coordinates, convertSecondsToDOMTimeStamp(positio
n->timestamp())); |
63 } | 62 } |
64 | 63 |
65 static PassRefPtrWillBeRawPtr<PositionError> createPositionError(GeolocationErro
r* error) | 64 static PositionError* createPositionError(GeolocationError* error) |
66 { | 65 { |
67 PositionError::ErrorCode code = PositionError::POSITION_UNAVAILABLE; | 66 PositionError::ErrorCode code = PositionError::POSITION_UNAVAILABLE; |
68 switch (error->code()) { | 67 switch (error->code()) { |
69 case GeolocationError::PermissionDenied: | 68 case GeolocationError::PermissionDenied: |
70 code = PositionError::PERMISSION_DENIED; | 69 code = PositionError::PERMISSION_DENIED; |
71 break; | 70 break; |
72 case GeolocationError::PositionUnavailable: | 71 case GeolocationError::PositionUnavailable: |
73 code = PositionError::POSITION_UNAVAILABLE; | 72 code = PositionError::POSITION_UNAVAILABLE; |
74 break; | 73 break; |
75 } | 74 } |
76 | 75 |
77 return PositionError::create(code, error->message()); | 76 return PositionError::create(code, error->message()); |
78 } | 77 } |
79 | 78 |
80 Geolocation::GeoNotifier::GeoNotifier(Geolocation* geolocation, PassOwnPtr<Posit
ionCallback> successCallback, PassOwnPtr<PositionErrorCallback> errorCallback, P
assRefPtrWillBeRawPtr<PositionOptions> options) | 79 Geolocation::GeoNotifier::GeoNotifier(Geolocation* geolocation, PassOwnPtr<Posit
ionCallback> successCallback, PassOwnPtr<PositionErrorCallback> errorCallback, P
ositionOptions* options) |
81 : m_geolocation(geolocation) | 80 : m_geolocation(geolocation) |
82 , m_successCallback(successCallback) | 81 , m_successCallback(successCallback) |
83 , m_errorCallback(errorCallback) | 82 , m_errorCallback(errorCallback) |
84 , m_options(options) | 83 , m_options(options) |
85 , m_timer(this, &Geolocation::GeoNotifier::timerFired) | 84 , m_timer(this, &Geolocation::GeoNotifier::timerFired) |
86 , m_useCachedPosition(false) | 85 , m_useCachedPosition(false) |
87 { | 86 { |
88 ASSERT(m_geolocation); | 87 ASSERT(m_geolocation); |
89 ASSERT(m_successCallback); | 88 ASSERT(m_successCallback); |
90 // If no options were supplied from JS, we should have created a default set | 89 // If no options were supplied from JS, we should have created a default set |
91 // of options in JSGeolocationCustom.cpp. | 90 // of options in JSGeolocationCustom.cpp. |
92 ASSERT(m_options); | 91 ASSERT(m_options); |
93 } | 92 } |
94 | 93 |
95 void Geolocation::GeoNotifier::trace(Visitor* visitor) | 94 void Geolocation::GeoNotifier::trace(Visitor* visitor) |
96 { | 95 { |
97 visitor->trace(m_geolocation); | 96 visitor->trace(m_geolocation); |
98 visitor->trace(m_options); | 97 visitor->trace(m_options); |
99 visitor->trace(m_fatalError); | 98 visitor->trace(m_fatalError); |
100 } | 99 } |
101 | 100 |
102 void Geolocation::GeoNotifier::setFatalError(PassRefPtrWillBeRawPtr<PositionErro
r> error) | 101 void Geolocation::GeoNotifier::setFatalError(PositionError* error) |
103 { | 102 { |
104 // If a fatal error has already been set, stick with it. This makes sure tha
t | 103 // If a fatal error has already been set, stick with it. This makes sure tha
t |
105 // when permission is denied, this is the error reported, as required by the | 104 // when permission is denied, this is the error reported, as required by the |
106 // spec. | 105 // spec. |
107 if (m_fatalError) | 106 if (m_fatalError) |
108 return; | 107 return; |
109 | 108 |
110 m_fatalError = error; | 109 m_fatalError = error; |
111 // An existing timer may not have a zero timeout. | 110 // An existing timer may not have a zero timeout. |
112 m_timer.stop(); | 111 m_timer.stop(); |
(...skipping 29 matching lines...) Expand all Loading... |
142 | 141 |
143 void Geolocation::GeoNotifier::stopTimer() | 142 void Geolocation::GeoNotifier::stopTimer() |
144 { | 143 { |
145 m_timer.stop(); | 144 m_timer.stop(); |
146 } | 145 } |
147 | 146 |
148 void Geolocation::GeoNotifier::timerFired(Timer<GeoNotifier>*) | 147 void Geolocation::GeoNotifier::timerFired(Timer<GeoNotifier>*) |
149 { | 148 { |
150 m_timer.stop(); | 149 m_timer.stop(); |
151 | 150 |
152 // Protect this GeoNotifier object, since it | |
153 // could be deleted by a call to clearWatch in a callback. | |
154 RefPtrWillBeRawPtr<GeoNotifier> protect(this); | |
155 | |
156 // Test for fatal error first. This is required for the case where the Local
Frame is | 151 // Test for fatal error first. This is required for the case where the Local
Frame is |
157 // disconnected and requests are cancelled. | 152 // disconnected and requests are cancelled. |
158 if (m_fatalError) { | 153 if (m_fatalError) { |
159 runErrorCallback(m_fatalError.get()); | 154 runErrorCallback(m_fatalError.get()); |
160 // This will cause this notifier to be deleted. | 155 // This will cause this notifier to be deleted. |
161 m_geolocation->fatalErrorOccurred(this); | 156 m_geolocation->fatalErrorOccurred(this); |
162 return; | 157 return; |
163 } | 158 } |
164 | 159 |
165 if (m_useCachedPosition) { | 160 if (m_useCachedPosition) { |
166 // Clear the cached position flag in case this is a watch request, which | 161 // Clear the cached position flag in case this is a watch request, which |
167 // will continue to run. | 162 // will continue to run. |
168 m_useCachedPosition = false; | 163 m_useCachedPosition = false; |
169 m_geolocation->requestUsesCachedPosition(this); | 164 m_geolocation->requestUsesCachedPosition(this); |
170 return; | 165 return; |
171 } | 166 } |
172 | 167 |
173 if (m_errorCallback) { | 168 if (m_errorCallback) |
174 RefPtrWillBeRawPtr<PositionError> error = PositionError::create(Position
Error::TIMEOUT, "Timeout expired"); | 169 m_errorCallback->handleEvent(PositionError::create(PositionError::TIMEOU
T, "Timeout expired")); |
175 m_errorCallback->handleEvent(error.get()); | |
176 } | |
177 m_geolocation->requestTimedOut(this); | 170 m_geolocation->requestTimedOut(this); |
178 } | 171 } |
179 | 172 |
180 void Geolocation::Watchers::trace(Visitor* visitor) | 173 void Geolocation::Watchers::trace(Visitor* visitor) |
181 { | 174 { |
182 visitor->trace(m_idToNotifierMap); | 175 visitor->trace(m_idToNotifierMap); |
183 visitor->trace(m_notifierToIdMap); | 176 visitor->trace(m_notifierToIdMap); |
184 } | 177 } |
185 | 178 |
186 bool Geolocation::Watchers::add(int id, PassRefPtrWillBeRawPtr<GeoNotifier> prpN
otifier) | 179 bool Geolocation::Watchers::add(int id, GeoNotifier* notifier) |
187 { | 180 { |
188 ASSERT(id > 0); | 181 ASSERT(id > 0); |
189 RefPtrWillBeRawPtr<GeoNotifier> notifier = prpNotifier; | 182 if (!m_idToNotifierMap.add(id, notifier).isNewEntry) |
190 | |
191 if (!m_idToNotifierMap.add(id, notifier.get()).isNewEntry) | |
192 return false; | 183 return false; |
193 m_notifierToIdMap.set(notifier.release(), id); | 184 m_notifierToIdMap.set(notifier, id); |
194 return true; | 185 return true; |
195 } | 186 } |
196 | 187 |
197 Geolocation::GeoNotifier* Geolocation::Watchers::find(int id) | 188 Geolocation::GeoNotifier* Geolocation::Watchers::find(int id) |
198 { | 189 { |
199 ASSERT(id > 0); | 190 ASSERT(id > 0); |
200 IdToNotifierMap::iterator iter = m_idToNotifierMap.find(id); | 191 IdToNotifierMap::iterator iter = m_idToNotifierMap.find(id); |
201 if (iter == m_idToNotifierMap.end()) | 192 if (iter == m_idToNotifierMap.end()) |
202 return 0; | 193 return 0; |
203 return iter->value.get(); | 194 return iter->value.get(); |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
236 bool Geolocation::Watchers::isEmpty() const | 227 bool Geolocation::Watchers::isEmpty() const |
237 { | 228 { |
238 return m_idToNotifierMap.isEmpty(); | 229 return m_idToNotifierMap.isEmpty(); |
239 } | 230 } |
240 | 231 |
241 void Geolocation::Watchers::getNotifiersVector(GeoNotifierVector& copy) const | 232 void Geolocation::Watchers::getNotifiersVector(GeoNotifierVector& copy) const |
242 { | 233 { |
243 copyValuesToVector(m_idToNotifierMap, copy); | 234 copyValuesToVector(m_idToNotifierMap, copy); |
244 } | 235 } |
245 | 236 |
246 PassRefPtrWillBeRawPtr<Geolocation> Geolocation::create(ExecutionContext* contex
t) | 237 Geolocation* Geolocation::create(ExecutionContext* context) |
247 { | 238 { |
248 RefPtrWillBeRawPtr<Geolocation> geolocation = adoptRefWillBeNoop(new Geoloca
tion(context)); | 239 Geolocation* geolocation = new Geolocation(context); |
249 geolocation->suspendIfNeeded(); | 240 geolocation->suspendIfNeeded(); |
250 return geolocation.release(); | 241 return geolocation; |
251 } | 242 } |
252 | 243 |
253 Geolocation::Geolocation(ExecutionContext* context) | 244 Geolocation::Geolocation(ExecutionContext* context) |
254 : ActiveDOMObject(context) | 245 : ActiveDOMObject(context) |
255 , m_allowGeolocation(Unknown) | 246 , m_allowGeolocation(Unknown) |
256 { | 247 { |
257 ScriptWrappable::init(this); | 248 ScriptWrappable::init(this); |
258 } | 249 } |
259 | 250 |
260 Geolocation::~Geolocation() | 251 Geolocation::~Geolocation() |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
297 { | 288 { |
298 LocalFrame* frame = this->frame(); | 289 LocalFrame* frame = this->frame(); |
299 if (!frame) | 290 if (!frame) |
300 return 0; | 291 return 0; |
301 | 292 |
302 m_lastPosition = createGeoposition(GeolocationController::from(frame)->lastP
osition()); | 293 m_lastPosition = createGeoposition(GeolocationController::from(frame)->lastP
osition()); |
303 | 294 |
304 return m_lastPosition.get(); | 295 return m_lastPosition.get(); |
305 } | 296 } |
306 | 297 |
307 void Geolocation::getCurrentPosition(PassOwnPtr<PositionCallback> successCallbac
k, PassOwnPtr<PositionErrorCallback> errorCallback, PassRefPtrWillBeRawPtr<Posit
ionOptions> options) | 298 void Geolocation::getCurrentPosition(PassOwnPtr<PositionCallback> successCallbac
k, PassOwnPtr<PositionErrorCallback> errorCallback, PositionOptions* options) |
308 { | 299 { |
309 if (!frame()) | 300 if (!frame()) |
310 return; | 301 return; |
311 | 302 |
312 RefPtrWillBeRawPtr<GeoNotifier> notifier = GeoNotifier::create(this, success
Callback, errorCallback, options); | 303 GeoNotifier* notifier = GeoNotifier::create(this, successCallback, errorCall
back, options); |
313 startRequest(notifier.get()); | 304 startRequest(notifier); |
314 | 305 |
315 m_oneShots.add(notifier); | 306 m_oneShots.add(notifier); |
316 } | 307 } |
317 | 308 |
318 int Geolocation::watchPosition(PassOwnPtr<PositionCallback> successCallback, Pas
sOwnPtr<PositionErrorCallback> errorCallback, PassRefPtrWillBeRawPtr<PositionOpt
ions> options) | 309 int Geolocation::watchPosition(PassOwnPtr<PositionCallback> successCallback, Pas
sOwnPtr<PositionErrorCallback> errorCallback, PositionOptions* options) |
319 { | 310 { |
320 if (!frame()) | 311 if (!frame()) |
321 return 0; | 312 return 0; |
322 | 313 |
323 RefPtrWillBeRawPtr<GeoNotifier> notifier = GeoNotifier::create(this, success
Callback, errorCallback, options); | 314 GeoNotifier* notifier = GeoNotifier::create(this, successCallback, errorCall
back, options); |
324 startRequest(notifier.get()); | 315 startRequest(notifier); |
325 | 316 |
326 int watchID; | 317 int watchID; |
327 // Keep asking for the next id until we're given one that we don't already h
ave. | 318 // Keep asking for the next id until we're given one that we don't already h
ave. |
328 do { | 319 do { |
329 watchID = executionContext()->circularSequentialID(); | 320 watchID = executionContext()->circularSequentialID(); |
330 } while (!m_watchers.add(watchID, notifier)); | 321 } while (!m_watchers.add(watchID, notifier)); |
331 return watchID; | 322 return watchID; |
332 } | 323 } |
333 | 324 |
334 void Geolocation::startRequest(GeoNotifier *notifier) | 325 void Geolocation::startRequest(GeoNotifier *notifier) |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
438 if (GeoNotifier* notifier = m_watchers.find(watchID)) | 429 if (GeoNotifier* notifier = m_watchers.find(watchID)) |
439 m_pendingForPermissionNotifiers.remove(notifier); | 430 m_pendingForPermissionNotifiers.remove(notifier); |
440 m_watchers.remove(watchID); | 431 m_watchers.remove(watchID); |
441 | 432 |
442 if (!hasListeners()) | 433 if (!hasListeners()) |
443 stopUpdating(); | 434 stopUpdating(); |
444 } | 435 } |
445 | 436 |
446 void Geolocation::setIsAllowed(bool allowed) | 437 void Geolocation::setIsAllowed(bool allowed) |
447 { | 438 { |
448 // Protect the Geolocation object from garbage collection during a callback. | |
449 RefPtrWillBeRawPtr<Geolocation> protect(this); | |
450 | |
451 // This may be due to either a new position from the service, or a cached | 439 // This may be due to either a new position from the service, or a cached |
452 // position. | 440 // position. |
453 m_allowGeolocation = allowed ? Yes : No; | 441 m_allowGeolocation = allowed ? Yes : No; |
454 | 442 |
455 // Permission request was made during the startRequest process | 443 // Permission request was made during the startRequest process |
456 if (!m_pendingForPermissionNotifiers.isEmpty()) { | 444 if (!m_pendingForPermissionNotifiers.isEmpty()) { |
457 handlePendingPermissionNotifiers(); | 445 handlePendingPermissionNotifiers(); |
458 m_pendingForPermissionNotifiers.clear(); | 446 m_pendingForPermissionNotifiers.clear(); |
459 return; | 447 return; |
460 } | 448 } |
461 | 449 |
462 if (!isAllowed()) { | 450 if (!isAllowed()) { |
463 RefPtrWillBeRawPtr<PositionError> error = PositionError::create(Position
Error::PERMISSION_DENIED, permissionDeniedErrorMessage); | 451 PositionError* error = PositionError::create(PositionError::PERMISSION_D
ENIED, permissionDeniedErrorMessage); |
464 error->setIsFatal(true); | 452 error->setIsFatal(true); |
465 handleError(error.get()); | 453 handleError(error); |
466 m_requestsAwaitingCachedPosition.clear(); | 454 m_requestsAwaitingCachedPosition.clear(); |
467 return; | 455 return; |
468 } | 456 } |
469 | 457 |
470 // If the service has a last position, use it to call back for all requests. | 458 // If the service has a last position, use it to call back for all requests. |
471 // If any of the requests are waiting for permission for a cached position, | 459 // If any of the requests are waiting for permission for a cached position, |
472 // the position from the service will be at least as fresh. | 460 // the position from the service will be at least as fresh. |
473 if (lastPosition()) | 461 if (lastPosition()) |
474 makeSuccessCallbacks(); | 462 makeSuccessCallbacks(); |
475 else | 463 else |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
643 ASSERT(isAllowed()); | 631 ASSERT(isAllowed()); |
644 | 632 |
645 // Stop all currently running timers. | 633 // Stop all currently running timers. |
646 stopTimers(); | 634 stopTimers(); |
647 | 635 |
648 makeSuccessCallbacks(); | 636 makeSuccessCallbacks(); |
649 } | 637 } |
650 | 638 |
651 void Geolocation::setError(GeolocationError* error) | 639 void Geolocation::setError(GeolocationError* error) |
652 { | 640 { |
653 RefPtrWillBeRawPtr<PositionError> positionError = createPositionError(error)
; | 641 handleError(createPositionError(error)); |
654 handleError(positionError.get()); | |
655 } | 642 } |
656 | 643 |
657 bool Geolocation::startUpdating(GeoNotifier* notifier) | 644 bool Geolocation::startUpdating(GeoNotifier* notifier) |
658 { | 645 { |
659 LocalFrame* frame = this->frame(); | 646 LocalFrame* frame = this->frame(); |
660 if (!frame) | 647 if (!frame) |
661 return false; | 648 return false; |
662 | 649 |
663 GeolocationController::from(frame)->addObserver(this, notifier->options()->e
nableHighAccuracy()); | 650 GeolocationController::from(frame)->addObserver(this, notifier->options()->e
nableHighAccuracy()); |
664 return true; | 651 return true; |
(...skipping 23 matching lines...) Expand all Loading... |
688 notifier->startTimer(); | 675 notifier->startTimer(); |
689 else | 676 else |
690 notifier->setFatalError(PositionError::create(PositionError::POS
ITION_UNAVAILABLE, failedToStartServiceErrorMessage)); | 677 notifier->setFatalError(PositionError::create(PositionError::POS
ITION_UNAVAILABLE, failedToStartServiceErrorMessage)); |
691 } else { | 678 } else { |
692 notifier->setFatalError(PositionError::create(PositionError::PERMISS
ION_DENIED, permissionDeniedErrorMessage)); | 679 notifier->setFatalError(PositionError::create(PositionError::PERMISS
ION_DENIED, permissionDeniedErrorMessage)); |
693 } | 680 } |
694 } | 681 } |
695 } | 682 } |
696 | 683 |
697 } // namespace WebCore | 684 } // namespace WebCore |
OLD | NEW |