chromium/android_webview/browser/gfx/begin_frame_source_webview.cc

// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "android_webview/browser/gfx/begin_frame_source_webview.h"

#include "base/auto_reset.h"
#include "base/memory/raw_ptr.h"
#include "base/no_destructor.h"
#include "base/trace_event/trace_event.h"

// Must come after all headers that specialize FromJniType() / ToJniType().
#include "android_webview/browser_jni_headers/RootBeginFrameSourceWebView_jni.h"

namespace android_webview {

class BeginFrameSourceWebView::BeginFrameObserver
    : public viz::BeginFrameObserver {
 public:
  BeginFrameObserver(BeginFrameSourceWebView* owner) : owner_(owner) {}

  void OnBeginFrame(const viz::BeginFrameArgs& args) override {
    last_used_begin_frame_args_ = args;
    owner_->SendBeginFrame(args);
  }

  const viz::BeginFrameArgs& LastUsedBeginFrameArgs() const override {
    return last_used_begin_frame_args_;
  }

  void OnBeginFrameSourcePausedChanged(bool paused) override {
    owner_->OnSetBeginFrameSourcePaused(paused);
  }

  bool WantsAnimateOnlyBeginFrames() const override { return true; }

 private:
  const raw_ptr<BeginFrameSourceWebView> owner_;
  viz::BeginFrameArgs last_used_begin_frame_args_;
};

BeginFrameSourceWebView::BeginFrameSourceClient::BeginFrameSourceClient(
    android_webview::BeginFrameSourceWebView* owner)
    : owner_(owner) {}

BeginFrameSourceWebView::BeginFrameSourceClient::~BeginFrameSourceClient() =
    default;
void BeginFrameSourceWebView::BeginFrameSourceClient::OnNeedsBeginFrames(
    bool needs_begin_frames) {
  owner_->OnNeedsBeginFrames(needs_begin_frames);
}

BeginFrameSourceWebView::BeginFrameSourceWebView()
    : ExternalBeginFrameSource(&bfs_client_),
      bfs_client_(this),
      parent_observer_(std::make_unique<BeginFrameObserver>(this)) {
  OnSetBeginFrameSourcePaused(true);
}

BeginFrameSourceWebView::~BeginFrameSourceWebView() {
  if (observed_begin_frame_source_ && !observers_.empty())
    observed_begin_frame_source_->RemoveObserver(parent_observer_.get());
}

void BeginFrameSourceWebView::SetParentSource(BeginFrameSourceWebView* parent) {
  parent_ = parent;
  ObserveBeginFrameSource(parent);
}

void BeginFrameSourceWebView::ObserveBeginFrameSource(
    viz::BeginFrameSource* begin_frame_source) {
  if (observed_begin_frame_source_ == begin_frame_source)
    return;

  if (observed_begin_frame_source_ && !observers_.empty())
    observed_begin_frame_source_->RemoveObserver(parent_observer_.get());

  observed_begin_frame_source_ = begin_frame_source;

  if (observed_begin_frame_source_) {
    if (!observers_.empty())
      observed_begin_frame_source_->AddObserver(parent_observer_.get());
  } else {
    OnSetBeginFrameSourcePaused(true);
  };
}

void BeginFrameSourceWebView::OnNeedsBeginFrames(bool needs_begin_frames) {
  if (needs_begin_frames) {
    TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("cc,benchmark", "NeedsBeginFrames", this);
    if (observed_begin_frame_source_)
      observed_begin_frame_source_->AddObserver(parent_observer_.get());
  } else {
    TRACE_EVENT_NESTABLE_ASYNC_END0("cc,benchmark", "NeedsBeginFrames", this);
    if (observed_begin_frame_source_)
      observed_begin_frame_source_->RemoveObserver(parent_observer_.get());
  }
}

void BeginFrameSourceWebView::SendBeginFrame(const viz::BeginFrameArgs& args) {
  DCHECK(!inside_begin_frame_);
  base::AutoReset<bool> inside_bf(&inside_begin_frame_, true);
  OnBeginFrame(args);
  AfterBeginFrame();
}

void BeginFrameSourceWebView::AddBeginFrameCompletionCallback(
    base::OnceClosure callback) {
  DCHECK(parent_);
  DCHECK(inside_begin_frame_);
  parent_->AddBeginFrameCompletionCallback(std::move(callback));
}

const viz::BeginFrameArgs&
BeginFrameSourceWebView::LastDispatchedBeginFrameArgs() {
  return parent_observer_->LastUsedBeginFrameArgs();
}

// static
RootBeginFrameSourceWebView* RootBeginFrameSourceWebView::GetInstance() {
  static base::NoDestructor<RootBeginFrameSourceWebView> instance;
  return instance.get();
}

RootBeginFrameSourceWebView::RootBeginFrameSourceWebView()
    : begin_frame_source_(kNotRestartableId,
                          60.0f,
                          /*requires_align_with_java=*/true),
      j_object_(Java_RootBeginFrameSourceWebView_Constructor(
          jni_zero::AttachCurrentThread(),
          reinterpret_cast<jlong>(this))) {
  ObserveBeginFrameSource(&begin_frame_source_);
}

RootBeginFrameSourceWebView::~RootBeginFrameSourceWebView() = default;

void RootBeginFrameSourceWebView::OnUpdateRefreshRate(
    JNIEnv* env,
    const base::android::JavaParamRef<jobject>& obj,
    float refresh_rate) {
  begin_frame_source_.UpdateRefreshRate(refresh_rate);
}

void RootBeginFrameSourceWebView::AfterBeginFrame() {
  // ScopedClosureRunner runs callback in the destructor unless it's cancelled.
  // So this will run all callbacks scheduled to run after BeginFrame completed.
  after_begin_frame_callbacks_.clear();
}

void RootBeginFrameSourceWebView::AddBeginFrameCompletionCallback(
    base::OnceClosure callback) {
  DCHECK(inside_begin_frame());
  after_begin_frame_callbacks_.emplace_back(std::move(callback));
}

}  // namespace android_webview