blob: 02b71b6619e3d5e33b2552708885bdfa84d6817e [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 "third_party/blink/renderer/core/dom/frame_request_callback_collection.h"
#include "third_party/blink/renderer/core/inspector/inspector_trace_events.h"
#include "third_party/blink/renderer/core/probe/core_probes.h"
namespace blink {
FrameRequestCallbackCollection::FrameRequestCallbackCollection(
ExecutionContext* context)
: context_(context) {}
FrameRequestCallbackCollection::CallbackId
FrameRequestCallbackCollection::RegisterCallback(FrameCallback* callback) {
FrameRequestCallbackCollection::CallbackId id = ++next_callback_id_;
callback->SetIsCancelled(false);
callback->SetId(id);
callbacks_.push_back(callback);
TRACE_EVENT_INSTANT1("devtools.timeline", "RequestAnimationFrame",
TRACE_EVENT_SCOPE_THREAD, "data",
inspector_animation_frame_event::Data(context_, id));
probe::AsyncTaskScheduledBreakable(context_, "requestAnimationFrame",
callback);
return id;
}
void FrameRequestCallbackCollection::CancelCallback(CallbackId id) {
for (wtf_size_t i = 0; i < callbacks_.size(); ++i) {
if (callbacks_[i]->Id() == id) {
probe::AsyncTaskCanceledBreakable(context_, "cancelAnimationFrame",
callbacks_[i]);
callbacks_.EraseAt(i);
TRACE_EVENT_INSTANT1("devtools.timeline", "CancelAnimationFrame",
TRACE_EVENT_SCOPE_THREAD, "data",
inspector_animation_frame_event::Data(context_, id));
return;
}
}
for (const auto& callback : callbacks_to_invoke_) {
if (callback->Id() == id) {
probe::AsyncTaskCanceledBreakable(context_, "cancelAnimationFrame",
callback);
TRACE_EVENT_INSTANT1("devtools.timeline", "CancelAnimationFrame",
TRACE_EVENT_SCOPE_THREAD, "data",
inspector_animation_frame_event::Data(context_, id));
callback->SetIsCancelled(true);
// will be removed at the end of executeCallbacks()
return;
}
}
}
void FrameRequestCallbackCollection::ExecuteCallbacks(
double high_res_now_ms,
double high_res_now_ms_legacy) {
// First, generate a list of callbacks to consider. Callbacks registered from
// this point on are considered only for the "next" frame, not this one.
DCHECK(callbacks_to_invoke_.IsEmpty());
swap(callbacks_to_invoke_, callbacks_);
for (const auto& callback : callbacks_to_invoke_) {
// When the ExecutionContext is destroyed (e.g. an iframe is detached),
// there is no path to perform wrapper tracing for the callbacks. In such a
// case, the callback functions may already have been collected by V8 GC.
// Since it's possible that a callback function being invoked detaches an
// iframe, we need to check the condition for each callback.
if (context_->IsContextDestroyed())
break;
if (!callback->IsCancelled()) {
TRACE_EVENT1(
"devtools.timeline", "FireAnimationFrame", "data",
inspector_animation_frame_event::Data(context_, callback->Id()));
probe::AsyncTask async_task(context_, callback);
probe::UserCallback probe(context_, "requestAnimationFrame",
AtomicString(), true);
if (callback->GetUseLegacyTimeBase())
callback->Invoke(high_res_now_ms_legacy);
else
callback->Invoke(high_res_now_ms);
}
}
callbacks_to_invoke_.clear();
}
void FrameRequestCallbackCollection::Trace(blink::Visitor* visitor) {
visitor->Trace(callbacks_);
visitor->Trace(callbacks_to_invoke_);
visitor->Trace(context_);
}
FrameRequestCallbackCollection::V8FrameCallback::V8FrameCallback(
V8FrameRequestCallback* callback)
: callback_(callback) {}
void FrameRequestCallbackCollection::V8FrameCallback::Trace(
blink::Visitor* visitor) {
visitor->Trace(callback_);
FrameRequestCallbackCollection::FrameCallback::Trace(visitor);
}
void FrameRequestCallbackCollection::V8FrameCallback::Invoke(
double highResTime) {
callback_->InvokeAndReportException(nullptr, highResTime);
}
} // namespace blink