1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
|
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/modules/geolocation/geo_notifier.h"
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_position_options.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/modules/geolocation/geolocation.h"
#include "third_party/blink/renderer/modules/geolocation/geolocation_position_error.h"
namespace blink {
GeoNotifier::GeoNotifier(Geolocation* geolocation,
V8PositionCallback* success_callback,
V8PositionErrorCallback* error_callback,
const PositionOptions* options)
: geolocation_(geolocation),
success_callback_(success_callback),
error_callback_(error_callback),
options_(options),
timer_(MakeGarbageCollected<Timer>(
geolocation->DomWindow()->GetTaskRunner(TaskType::kMiscPlatformAPI),
this,
&GeoNotifier::TimerFired)),
use_cached_position_(false) {
DCHECK(geolocation_);
DCHECK(success_callback_);
}
void GeoNotifier::Trace(Visitor* visitor) const {
visitor->Trace(geolocation_);
visitor->Trace(options_);
visitor->Trace(success_callback_);
visitor->Trace(error_callback_);
visitor->Trace(timer_);
visitor->Trace(fatal_error_);
}
void GeoNotifier::SetFatalError(GeolocationPositionError* error) {
// If a fatal error has already been set, stick with it. This makes sure that
// when permission is denied, this is the error reported, as required by the
// spec.
if (fatal_error_)
return;
fatal_error_ = error;
// An existing timer may not have a zero timeout.
timer_->Stop();
timer_->StartOneShot(base::TimeDelta(), FROM_HERE);
}
void GeoNotifier::SetUseCachedPosition() {
use_cached_position_ = true;
timer_->StartOneShot(base::TimeDelta(), FROM_HERE);
}
void GeoNotifier::RunSuccessCallback(Geoposition* position) {
LocalDOMWindow* win = geolocation_->DomWindow();
UseCounter::Count(win, WebFeature::kGeolocationSucceeded);
if (called_with_ad_script_in_stack_) {
UseCounter::Count(win,
WebFeature::kGeolocationWouldSucceedWhenAdScriptInStack);
}
if (!win->IsInjectionMitigatedContext()) {
UseCounter::Count(
win, WebFeature::kGeolocationSucceededWithoutInjectionMitigation);
}
success_callback_->InvokeAndReportException(nullptr, position);
}
void GeoNotifier::RunErrorCallback(GeolocationPositionError* error) {
if (error_callback_)
error_callback_->InvokeAndReportException(nullptr, error);
}
void GeoNotifier::StartTimer() {
timer_->StartOneShot(base::Milliseconds(options_->timeout()), FROM_HERE);
}
void GeoNotifier::StopTimer() {
timer_->Stop();
}
bool GeoNotifier::IsTimerActive() const {
return timer_->IsActive();
}
void GeoNotifier::Timer::Trace(Visitor* visitor) const {
visitor->Trace(timer_);
visitor->Trace(notifier_);
}
void GeoNotifier::Timer::StartOneShot(base::TimeDelta interval,
const base::Location& caller) {
DCHECK(notifier_->geolocation_->DoesOwnNotifier(notifier_));
timer_.StartOneShot(interval, caller);
}
void GeoNotifier::Timer::Stop() {
DCHECK(notifier_->geolocation_->DoesOwnNotifier(notifier_));
timer_.Stop();
}
void GeoNotifier::TimerFired(TimerBase*) {
timer_->Stop();
// As the timer fires asynchronously, it's possible that the execution context
// has already gone. Check it first.
if (!geolocation_->GetExecutionContext()) {
return; // Do not invoke anything because of no execution context.
}
// TODO(yukishiino): Remove this check once we understand the cause.
// https://crbug.com/792604
CHECK(!geolocation_->GetExecutionContext()->IsContextDestroyed());
CHECK(geolocation_->DoesOwnNotifier(this));
// Test for fatal error first. This is required for the case where the
// LocalFrame is disconnected and requests are cancelled.
if (fatal_error_) {
RunErrorCallback(fatal_error_);
// This will cause this notifier to be deleted.
geolocation_->FatalErrorOccurred(this);
return;
}
if (use_cached_position_) {
// Clear the cached position flag in case this is a watch request, which
// will continue to run.
use_cached_position_ = false;
geolocation_->RequestUsesCachedPosition(this);
return;
}
if (error_callback_) {
error_callback_->InvokeAndReportException(
nullptr, MakeGarbageCollected<GeolocationPositionError>(
GeolocationPositionError::kTimeout, "Timeout expired"));
}
geolocation_->RequestTimedOut(this);
}
} // namespace blink
|