blob: 3c61a034d1571d3eb8774a2172f26b9af3a99020 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "core/timing/PerformanceObserver.h"
#include <algorithm>
#include "bindings/core/v8/ExceptionMessages.h"
#include "bindings/core/v8/ExceptionState.h"
#include "bindings/core/v8/V8BindingForCore.h"
#include "bindings/core/v8/v8_performance_observer_callback.h"
#include "core/dom/ExecutionContext.h"
#include "core/frame/LocalDOMWindow.h"
#include "core/frame/UseCounter.h"
#include "core/timing/DOMWindowPerformance.h"
#include "core/timing/Performance.h"
#include "core/timing/PerformanceEntry.h"
#include "core/timing/PerformanceObserverEntryList.h"
#include "core/timing/PerformanceObserverInit.h"
#include "core/timing/WorkerGlobalScopePerformance.h"
#include "core/workers/WorkerGlobalScope.h"
#include "platform/Timer.h"
namespace blink {
PerformanceObserver* PerformanceObserver::Create(
ScriptState* script_state,
V8PerformanceObserverCallback* callback) {
LocalDOMWindow* window = ToLocalDOMWindow(script_state->GetContext());
ExecutionContext* context = ExecutionContext::From(script_state);
if (window) {
UseCounter::Count(context, WebFeature::kPerformanceObserverForWindow);
return new PerformanceObserver(
context, DOMWindowPerformance::performance(*window), callback);
}
if (context->IsWorkerGlobalScope()) {
UseCounter::Count(context, WebFeature::kPerformanceObserverForWorker);
return new PerformanceObserver(context,
WorkerGlobalScopePerformance::performance(
*ToWorkerGlobalScope(context)),
callback);
}
V8ThrowException::ThrowTypeError(
script_state->GetIsolate(),
ExceptionMessages::FailedToConstruct(
"PerformanceObserver",
"No 'worker' or 'window' in current context."));
return nullptr;
}
PerformanceObserver::PerformanceObserver(
ExecutionContext* execution_context,
PerformanceBase* performance,
V8PerformanceObserverCallback* callback)
: ContextClient(execution_context),
execution_context_(execution_context),
callback_(callback),
performance_(performance),
filter_options_(PerformanceEntry::kInvalid),
is_registered_(false) {
DCHECK(performance_);
}
void PerformanceObserver::observe(const PerformanceObserverInit& observer_init,
ExceptionState& exception_state) {
if (!performance_) {
exception_state.ThrowTypeError(
"Window/worker may be destroyed? Performance target is invalid.");
return;
}
PerformanceEntryTypeMask entry_types = PerformanceEntry::kInvalid;
if (observer_init.hasEntryTypes() && observer_init.entryTypes().size()) {
const Vector<String>& sequence = observer_init.entryTypes();
for (const auto& entry_type_string : sequence)
entry_types |= PerformanceEntry::ToEntryTypeEnum(entry_type_string);
}
if (entry_types == PerformanceEntry::kInvalid) {
exception_state.ThrowTypeError(
"A Performance Observer MUST have at least one valid entryType in its "
"entryTypes attribute.");
return;
}
filter_options_ = entry_types;
if (is_registered_)
performance_->UpdatePerformanceObserverFilterOptions();
else
performance_->RegisterPerformanceObserver(*this);
is_registered_ = true;
}
void PerformanceObserver::disconnect() {
performance_entries_.clear();
if (performance_)
performance_->UnregisterPerformanceObserver(*this);
is_registered_ = false;
}
PerformanceEntryVector PerformanceObserver::takeRecords() {
PerformanceEntryVector performance_entries;
performance_entries.swap(performance_entries_);
return performance_entries;
}
void PerformanceObserver::EnqueuePerformanceEntry(PerformanceEntry& entry) {
performance_entries_.push_back(&entry);
if (performance_)
performance_->ActivateObserver(*this);
}
bool PerformanceObserver::HasPendingActivity() const {
return is_registered_;
}
bool PerformanceObserver::ShouldBeSuspended() const {
return execution_context_->IsContextPaused();
}
void PerformanceObserver::Deliver() {
DCHECK(!ShouldBeSuspended());
if (!GetExecutionContext())
return;
if (performance_entries_.IsEmpty())
return;
PerformanceEntryVector performance_entries;
performance_entries.swap(performance_entries_);
PerformanceObserverEntryList* entry_list =
new PerformanceObserverEntryList(performance_entries);
callback_->InvokeAndReportException(this, entry_list, this);
}
void PerformanceObserver::Trace(blink::Visitor* visitor) {
visitor->Trace(execution_context_);
visitor->Trace(callback_);
visitor->Trace(performance_);
visitor->Trace(performance_entries_);
ScriptWrappable::Trace(visitor);
ContextClient::Trace(visitor);
}
void PerformanceObserver::TraceWrappers(
const ScriptWrappableVisitor* visitor) const {
visitor->TraceWrappers(callback_);
ScriptWrappable::TraceWrappers(visitor);
}
} // namespace blink