chromium/content/browser/renderer_host/input/fling_scheduler_android.cc

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

#include "content/browser/renderer_host/input/fling_scheduler_android.h"

#include "base/feature_list.h"
#include "build/build_config.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/browser/renderer_host/render_widget_host_view_android.h"
#include "content/public/common/content_features.h"
#include "ui/android/view_android.h"

namespace content {

FlingSchedulerAndroid::FlingSchedulerAndroid(RenderWidgetHostImpl* host)
    : host_(host) {
  DCHECK(host);
}

FlingSchedulerAndroid::~FlingSchedulerAndroid() {
  RemoveCompositorTick();
}

void FlingSchedulerAndroid::ScheduleFlingProgress(
    base::WeakPtr<input::FlingController> fling_controller) {
  DCHECK(fling_controller);
  fling_controller_ = fling_controller;
  if (observed_compositor_)
    return;

  ui::WindowAndroid* window = GetRootWindow();
  if (!window)
    return;

  // If the root window does not have a Compositor (happens on Android
  // WebView), we'll never receive an OnAnimate call. In this case fall back
  // to BeginFrames coming from the host.
  if (!window->GetCompositor()) {
    auto* view = host_->GetView();
    if (view && !view->IsRenderWidgetHostViewChildFrame()) {
      static_cast<RenderWidgetHostViewAndroid*>(view)
          ->SetNeedsBeginFrameForFlingProgress();
    }
    return;
  }

  RequestCompositorTick();
}

void FlingSchedulerAndroid::DidStopFlingingOnBrowser(
    base::WeakPtr<input::FlingController> fling_controller) {
  DCHECK(fling_controller);
  RemoveCompositorTick();
  fling_controller_ = nullptr;
  host_->GetRenderInputRouter()->DidStopFlinging();
}

bool FlingSchedulerAndroid::NeedsBeginFrameForFlingProgress() {
  ui::WindowAndroid* window = GetRootWindow();
  // If the root window does not have a Compositor (happens on Android
  // WebView), we'll never receive an OnAnimate call. In this case fall back
  // to BeginFrames coming from the host.
  return !window || !window->GetCompositor();
}

bool FlingSchedulerAndroid::ShouldUseMobileFlingCurve() {
  return true;
}
gfx::Vector2dF FlingSchedulerAndroid::GetPixelsPerInch(
    const gfx::PointF& position_in_screen) {
  return gfx::Vector2dF(input::kDefaultPixelsPerInch,
                        input::kDefaultPixelsPerInch);
}

void FlingSchedulerAndroid::ProgressFlingOnBeginFrameIfneeded(
    base::TimeTicks current_time) {
  // If a WindowAndroid is being observed, there is no need for BeginFrames
  // coming from the host.
  if (observed_compositor_)
    return;
  if (!fling_controller_)
    return;
  fling_controller_->ProgressFling(current_time);
}

ui::WindowAndroid* FlingSchedulerAndroid::GetRootWindow() {
  if (!host_->GetView() || !host_->GetView()->GetNativeView())
    return nullptr;
  return host_->GetView()->GetNativeView()->GetWindowAndroid();
}

void FlingSchedulerAndroid::RequestCompositorTick() {
  if (!fling_controller_)
    return;

  if (observed_compositor_)
    return;

  if (!observed_view_ && host_->GetView()) {
    if (ui::ViewAndroid* native_view = host_->GetView()->GetNativeView()) {
      native_view->AddObserver(this);
      observed_view_ = native_view;
    }
  }

  ui::WindowAndroid* window = GetRootWindow();
  if (!window)
    return;

  if (!observed_window_) {
    window->AddObserver(this);
    observed_window_ = window;
  }

  CompositorImpl* compositor =
      static_cast<CompositorImpl*>(window->GetCompositor());
  if (!compositor)
    return;

  compositor->AddSimpleBeginFrameObserver(this);
  observed_compositor_ = compositor;
}

void FlingSchedulerAndroid::RemoveCompositorTick() {
  if (observed_view_) {
    observed_view_->RemoveObserver(this);
    observed_view_ = nullptr;
  }

  if (observed_window_) {
    observed_window_->RemoveObserver(this);
    observed_window_ = nullptr;
  }

  if (!observed_compositor_)
    return;
  observed_compositor_->RemoveSimpleBeginFrameObserver(this);
  observed_compositor_ = nullptr;
}

void FlingSchedulerAndroid::OnAttachCompositor() {
  RequestCompositorTick();
}

void FlingSchedulerAndroid::OnDetachCompositor() {
  RemoveCompositorTick();
}

void FlingSchedulerAndroid::OnAttachedToWindow() {
  RequestCompositorTick();
}

void FlingSchedulerAndroid::OnDetachedFromWindow() {
  RemoveCompositorTick();
}

void FlingSchedulerAndroid::OnViewAndroidDestroyed() {
  RemoveCompositorTick();
}

void FlingSchedulerAndroid::OnBeginFrame(base::TimeTicks frame_begin_time,
                                         base::TimeDelta frame_interval) {
  DCHECK(observed_compositor_);
  if (fling_controller_)
    fling_controller_->ProgressFling(frame_begin_time);
}

void FlingSchedulerAndroid::OnBeginFrameSourceShuttingDown() {
  if (observed_compositor_) {
    observed_compositor_->RemoveSimpleBeginFrameObserver(this);
    observed_compositor_ = nullptr;
  }
}

}  // namespace content