blob: 52e5091cf993d57e25c7197c8cddc6f3876bedd3 [file] [log] [blame]
// 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/permissions/permission_status.h"
#include "third_party/blink/public/mojom/frame/lifecycle.mojom-shared.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_permission_state.h"
#include "third_party/blink/renderer/core/dom/events/event.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/modules/event_target_modules_names.h"
#include "third_party/blink/renderer/modules/permissions/permission_status_listener.h"
namespace blink {
// static
PermissionStatus* PermissionStatus::Take(PermissionStatusListener* listener,
ScriptPromiseResolverBase* resolver) {
ExecutionContext* execution_context = resolver->GetExecutionContext();
PermissionStatus* permission_status =
MakeGarbageCollected<PermissionStatus>(listener, execution_context);
permission_status->UpdateStateIfNeeded();
permission_status->StartListening();
return permission_status;
}
PermissionStatus::PermissionStatus(PermissionStatusListener* listener,
ExecutionContext* execution_context)
: ActiveScriptWrappable<PermissionStatus>({}),
ExecutionContextLifecycleStateObserver(execution_context),
listener_(listener) {}
PermissionStatus::~PermissionStatus() = default;
const AtomicString& PermissionStatus::InterfaceName() const {
return event_target_names::kPermissionStatus;
}
ExecutionContext* PermissionStatus::GetExecutionContext() const {
return ExecutionContextLifecycleStateObserver::GetExecutionContext();
}
void PermissionStatus::AddedEventListener(
const AtomicString& event_type,
RegisteredEventListener& registered_listener) {
EventTarget::AddedEventListener(event_type, registered_listener);
if (!listener_)
return;
if (event_type == event_type_names::kChange) {
listener_->AddedEventListener(event_type);
}
}
void PermissionStatus::RemovedEventListener(
const AtomicString& event_type,
const RegisteredEventListener& registered_listener) {
EventTarget::RemovedEventListener(event_type, registered_listener);
if (!listener_)
return;
// Permission `change` event listener can be set via two independent JS-API.
// We should remove an internal listener only if none of the two JS-based
// event listeners exist. Without checking it, the internal listener will be
// removed while there could be an alive JS listener.
if (!HasJSBasedEventListeners(event_type_names::kChange)) {
listener_->RemovedEventListener(event_type);
}
}
bool PermissionStatus::HasPendingActivity() const {
if (!listener_)
return false;
return listener_->HasPendingActivity();
}
void PermissionStatus::ContextLifecycleStateChanged(
mojom::FrameLifecycleState state) {
if (state == mojom::FrameLifecycleState::kRunning)
StartListening();
else
StopListening();
}
V8PermissionState PermissionStatus::state() const {
if (!listener_) {
return V8PermissionState(V8PermissionState::Enum::kDenied);
}
return listener_->state();
}
String PermissionStatus::name() const {
if (!listener_)
return String();
return listener_->name();
}
void PermissionStatus::StartListening() {
if (!listener_)
return;
listener_->AddObserver(this);
}
void PermissionStatus::StopListening() {
if (!listener_)
return;
listener_->RemoveObserver(this);
}
void PermissionStatus::OnPermissionStatusChange(MojoPermissionStatus status) {
// https://www.w3.org/TR/permissions/#onchange-attribute
// 1. If this's relevant global object is a Window object, then:
// - Let document be status's relevant global object's associated Document.
// - If document is null or document is not fully active, terminate this
// algorithm.
if (auto* window = DynamicTo<LocalDOMWindow>(GetExecutionContext())) {
auto* document = window->document();
if (!document || !document->IsActive()) {
// Note: if the event is dropped out while in BFCache, one single change
// event might be dispatched later when the page is restored from BFCache.
return;
}
}
DispatchEvent(*Event::Create(event_type_names::kChange));
}
void PermissionStatus::Trace(Visitor* visitor) const {
visitor->Trace(listener_);
EventTarget::Trace(visitor);
ExecutionContextLifecycleStateObserver::Trace(visitor);
PermissionStatusListener::Observer::Trace(visitor);
}
} // namespace blink