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