namespace {
static base::StaticAtomicSequenceNumber s_layer_tree_host_sequence_number;
}

namespace cc {

LayerTreeHostInProcess::InitParams::InitParams() {}

LayerTreeHostInProcess::InitParams::~InitParams() {}

std::unique_ptr<LayerTreeHostInProcess> LayerTreeHostInProcess::CreateThreaded(
    scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner,
    InitParams* params) {
  DCHECK(params->main_task_runner.get());
  DCHECK(impl_task_runner.get());
  DCHECK(params->settings);
  std::unique_ptr<LayerTreeHostInProcess> layer_tree_host(
      new LayerTreeHostInProcess(params, CompositorMode::THREADED));
  layer_tree_host->InitializeThreaded(params->main_task_runner,
                                      impl_task_runner);
  return layer_tree_host;
}

std::unique_ptr<LayerTreeHostInProcess>
LayerTreeHostInProcess::CreateSingleThreaded(
    LayerTreeHostSingleThreadClient* single_thread_client,
    InitParams* params) {
  DCHECK(params->settings);
  std::unique_ptr<LayerTreeHostInProcess> layer_tree_host(
      new LayerTreeHostInProcess(params, CompositorMode::SINGLE_THREADED));
  layer_tree_host->InitializeSingleThreaded(single_thread_client,
                                            params->main_task_runner);
  return layer_tree_host;
}

LayerTreeHostInProcess::LayerTreeHostInProcess(InitParams* params,
                                               CompositorMode mode)
    : LayerTreeHostInProcess(
          params,
          mode,
          base::MakeUnique<LayerTree>(params->mutator_host, this)) {}

LayerTreeHostInProcess::LayerTreeHostInProcess(
    InitParams* params,
    CompositorMode mode,
    std::unique_ptr<LayerTree> layer_tree)
    : micro_benchmark_controller_(this),
      layer_tree_(std::move(layer_tree)),
      compositor_mode_(mode),
      ui_resource_manager_(base::MakeUnique<UIResourceManager>()),
      client_(params->client),
      source_frame_number_(0),
      rendering_stats_instrumentation_(RenderingStatsInstrumentation::Create()),
      settings_(*params->settings),
      debug_state_(settings_.initial_debug_state),
      visible_(false),
      has_gpu_rasterization_trigger_(false),
      content_is_suitable_for_gpu_rasterization_(true),
      gpu_rasterization_histogram_recorded_(false),
      did_complete_scale_animation_(false),
      id_(s_layer_tree_host_sequence_number.GetNext() + 1),
      task_graph_runner_(params->task_graph_runner),
      image_serialization_processor_(params->image_serialization_processor),
      image_worker_task_runner_(params->image_worker_task_runner) {
  DCHECK(task_graph_runner_);
  DCHECK(layer_tree_);
  DCHECK_NE(compositor_mode_, CompositorMode::REMOTE);

  rendering_stats_instrumentation_->set_record_rendering_stats(
      debug_state_.RecordRenderingStats());
}

void LayerTreeHostInProcess::InitializeThreaded(
    scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
    scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner) {
  task_runner_provider_ =
      TaskRunnerProvider::Create(main_task_runner, impl_task_runner);
  std::unique_ptr<ProxyMain> proxy_main =
      base::MakeUnique<ProxyMain>(this, task_runner_provider_.get());
  InitializeProxy(std::move(proxy_main));
}

void LayerTreeHostInProcess::InitializeSingleThreaded(
    LayerTreeHostSingleThreadClient* single_thread_client,
    scoped_refptr<base::SingleThreadTaskRunner> main_task_runner) {
  task_runner_provider_ = TaskRunnerProvider::Create(main_task_runner, nullptr);
  InitializeProxy(SingleThreadProxy::Create(this, single_thread_client,
                                            task_runner_provider_.get()));
}

void LayerTreeHostInProcess::InitializeForTesting(
    std::unique_ptr<TaskRunnerProvider> task_runner_provider,
    std::unique_ptr<Proxy> proxy_for_testing) {
  task_runner_provider_ = std::move(task_runner_provider);

  InitializePictureCacheForTesting();

  InitializeProxy(std::move(proxy_for_testing));
}

void LayerTreeHostInProcess::InitializePictureCacheForTesting() {
  if (!image_serialization_processor_)
    return;

  // Initialize both engine and client cache to ensure serialization tests
  // with a single LayerTreeHostInProcess can work correctly.
  engine_picture_cache_ =
      image_serialization_processor_->CreateEnginePictureCache();
  layer_tree_->set_engine_picture_cache(engine_picture_cache_.get());
  client_picture_cache_ =
      image_serialization_processor_->CreateClientPictureCache();
  layer_tree_->set_client_picture_cache(client_picture_cache_.get());
}

void LayerTreeHostInProcess::SetTaskRunnerProviderForTesting(
    std::unique_ptr<TaskRunnerProvider> task_runner_provider) {
  DCHECK(!task_runner_provider_);
  task_runner_provider_ = std::move(task_runner_provider);
}

void LayerTreeHostInProcess::SetUIResourceManagerForTesting(
    std::unique_ptr<UIResourceManager> ui_resource_manager) {
  ui_resource_manager_ = std::move(ui_resource_manager);
}

void LayerTreeHostInProcess::InitializeProxy(std::unique_ptr<Proxy> proxy) {
  TRACE_EVENT0("cc", "LayerTreeHostInProcess::InitializeForReal");
  DCHECK(task_runner_provider_);

  proxy_ = std::move(proxy);
  proxy_->Start();

  layer_tree_->mutator_host()->SetSupportsScrollAnimations(
      proxy_->SupportsImplScrolling());
}

LayerTreeHostInProcess::~LayerTreeHostInProcess() {
  // Track when we're inside a main frame to see if compositor is being
  // destroyed midway which causes a crash. crbug.com/654672
  CHECK(!inside_main_frame_);
  TRACE_EVENT0("cc", "LayerTreeHostInProcess::~LayerTreeHostInProcess");

  // Clear any references into the LayerTreeHostInProcess.
  layer_tree_.reset();

  if (proxy_) {
    DCHECK(task_runner_provider_->IsMainThread());
    proxy_->Stop();

    // Proxy must be destroyed before the Task Runner Provider.
    proxy_ = nullptr;
  }
}

int LayerTreeHostInProcess::GetId() const {
  return id_;
}

int LayerTreeHostInProcess::SourceFrameNumber() const {
  return source_frame_number_;
}

LayerTree* LayerTreeHostInProcess::GetLayerTree() {
  return layer_tree_.get();
}

const LayerTree* LayerTreeHostInProcess::GetLayerTree() const {
  return layer_tree_.get();
}

UIResourceManager* LayerTreeHostInProcess::GetUIResourceManager() const {
  return ui_resource_manager_.get();
}

TaskRunnerProvider* LayerTreeHostInProcess::GetTaskRunnerProvider() const {
  return task_runner_provider_.get();
}

SwapPromiseManager* LayerTreeHostInProcess::GetSwapPromiseManager() {
  return &swap_promise_manager_;
}

const LayerTreeSettings& LayerTreeHostInProcess::GetSettings() const {
  return settings_;
}

void LayerTreeHostInProcess::SetFrameSinkId(const FrameSinkId& frame_sink_id) {
  surface_sequence_generator_.set_frame_sink_id(frame_sink_id);
}

void LayerTreeHostInProcess::QueueSwapPromise(
    std::unique_ptr<SwapPromise> swap_promise) {
  swap_promise_manager_.QueueSwapPromise(std::move(swap_promise));
}

SurfaceSequenceGenerator*
LayerTreeHostInProcess::GetSurfaceSequenceGenerator() {
  return &surface_sequence_generator_;
}

void LayerTreeHostInProcess::WillBeginMainFrame() {
  inside_main_frame_ = true;
  devtools_instrumentation::WillBeginMainThreadFrame(GetId(),
                                                     SourceFrameNumber());
  client_->WillBeginMainFrame();
}

void LayerTreeHostInProcess::DidBeginMainFrame() {
  inside_main_frame_ = false;
  client_->DidBeginMainFrame();
}

void LayerTreeHostInProcess::BeginMainFrameNotExpectedSoon() {
  client_->BeginMainFrameNotExpectedSoon();
}

void LayerTreeHostInProcess::BeginMainFrame(const BeginFrameArgs& args) {
  client_->BeginMainFrame(args);
}

void LayerTreeHostInProcess::DidStopFlinging() {
  proxy_->MainThreadHasStoppedFlinging();
}

const LayerTreeDebugState& LayerTreeHostInProcess::GetDebugState() const {
  return debug_state_;
}

void LayerTreeHostInProcess::RequestMainFrameUpdate() {
  client_->UpdateLayerTreeHost();
}

// This function commits the LayerTreeHost to an impl tree. When modifying
// this function, keep in mind that the function *runs* on the impl thread! Any
// code that is logically a main thread operation, e.g. deletion of a Layer,
// should be delayed until the LayerTreeHostInProcess::CommitComplete, which
// will run after the commit, but on the main thread.
void LayerTreeHostInProcess::FinishCommitOnImplThread(
    LayerTreeHostImpl* host_impl) {
  DCHECK(task_runner_provider_->IsImplThread());

  bool is_new_trace;
  TRACE_EVENT_IS_NEW_TRACE(&is_new_trace);
  if (is_new_trace &&
      frame_viewer_instrumentation::IsTracingLayerTreeSnapshots() &&
      layer_tree_->root_layer()) {
    LayerTreeHostCommon::CallFunctionForEveryLayer(
        layer_tree_.get(), [](Layer* layer) { layer->DidBeginTracing(); });
  }

  LayerTreeImpl* sync_tree = host_impl->sync_tree();

  if (next_commit_forces_redraw_) {
    sync_tree->ForceRedrawNextActivation();
    next_commit_forces_redraw_ = false;
  }
  if (next_commit_forces_recalculate_raster_scales_) {
    sync_tree->ForceRecalculateRasterScales();
    next_commit_forces_recalculate_raster_scales_ = false;
  }

  sync_tree->set_source_frame_number(SourceFrameNumber());

  if (layer_tree_->needs_full_tree_sync())
    TreeSynchronizer::SynchronizeTrees(layer_tree_->root_layer(), sync_tree);

  float page_scale_delta = 1.f;
  if (reflected_main_frame_state_)
    page_scale_delta = reflected_main_frame_state_->page_scale_delta;
  layer_tree_->PushPropertiesTo(sync_tree, page_scale_delta);

  sync_tree->PassSwapPromises(swap_promise_manager_.TakeSwapPromises());

  host_impl->SetHasGpuRasterizationTrigger(has_gpu_rasterization_trigger_);
  host_impl->SetContentIsSuitableForGpuRasterization(
      content_is_suitable_for_gpu_rasterization_);
  RecordGpuRasterizationHistogram();

  host_impl->SetViewportSize(layer_tree_->device_viewport_size());
  sync_tree->SetDeviceScaleFactor(layer_tree_->device_scale_factor());
  host_impl->SetDebugState(debug_state_);

  sync_tree->set_ui_resource_request_queue(
      ui_resource_manager_->TakeUIResourcesRequests());

  {
    TRACE_EVENT0("cc", "LayerTreeHostInProcess::PushProperties");

    TreeSynchronizer::PushLayerProperties(layer_tree_.get(), sync_tree);

    if (reflected_main_frame_state_) {
      for (const auto& scroll_update : reflected_main_frame_state_->scrolls) {
        int layer_id = scroll_update.layer_id;
        gfx::Vector2dF scroll_delta = scroll_update.scroll_delta;

        PropertyTrees* property_trees = layer_tree_->property_trees();
        property_trees->scroll_tree.SetScrollOffset(
            layer_id, gfx::ScrollOffsetWithDelta(
                          layer_tree_->LayerById(layer_id)->scroll_offset(),
                          scroll_delta));
      }
    }

    // This must happen after synchronizing property trees and after pushing
    // properties, which updates the clobber_active_value flag.
    sync_tree->property_trees()->scroll_tree.PushScrollUpdatesFromMainThread(
        layer_tree_->property_trees(), sync_tree);

    // This must happen after synchronizing property trees and after push
    // properties, which updates property tree indices, but before animation
    // host pushes properties as animation host push properties can change
    // Animation::InEffect and we want the old InEffect value for updating
    // property tree scrolling and animation.
    sync_tree->UpdatePropertyTreeScrollingAndAnimationFromMainThread();

    TRACE_EVENT0("cc", "LayerTreeHostInProcess::AnimationHost::PushProperties");
    DCHECK(host_impl->mutator_host());
    layer_tree_->mutator_host()->PushPropertiesTo(host_impl->mutator_host());
  }

  micro_benchmark_controller_.ScheduleImplBenchmarks(host_impl);
  layer_tree_->property_trees()->ResetAllChangeTracking();
  reflected_main_frame_state_ = nullptr;
}

void LayerTreeHostInProcess::WillCommit() {
  swap_promise_manager_.WillCommit();
  client_->WillCommit();
}

void LayerTreeHostInProcess::UpdateHudLayer() {}

void LayerTreeHostInProcess::CommitComplete() {
  source_frame_number_++;
  client_->DidCommit();
  if (did_complete_scale_animation_) {
    client_->DidCompletePageScaleAnimation();
    did_complete_scale_animation_ = false;
  }
}

void LayerTreeHostInProcess::SetCompositorFrameSink(
    std::unique_ptr<CompositorFrameSink> surface) {
  TRACE_EVENT0("cc", "LayerTreeHostInProcess::SetCompositorFrameSink");
  DCHECK(surface);

  DCHECK(!new_compositor_frame_sink_);
  new_compositor_frame_sink_ = std::move(surface);
  proxy_->SetCompositorFrameSink(new_compositor_frame_sink_.get());
}

std::unique_ptr<CompositorFrameSink>
LayerTreeHostInProcess::ReleaseCompositorFrameSink() {
  DCHECK(!visible_);

  DidLoseCompositorFrameSink();
  proxy_->ReleaseCompositorFrameSink();
  return std::move(current_compositor_frame_sink_);
}

void LayerTreeHostInProcess::RequestNewCompositorFrameSink() {
  client_->RequestNewCompositorFrameSink();
}

void LayerTreeHostInProcess::DidInitializeCompositorFrameSink() {
  DCHECK(new_compositor_frame_sink_);
  current_compositor_frame_sink_ = std::move(new_compositor_frame_sink_);
  client_->DidInitializeCompositorFrameSink();
}

void LayerTreeHostInProcess::DidFailToInitializeCompositorFrameSink() {
  DCHECK(new_compositor_frame_sink_);
  // Note: It is safe to drop all output surface references here as
  // LayerTreeHostImpl will not keep a pointer to either the old or
  // new CompositorFrameSink after failing to initialize the new one.
  current_compositor_frame_sink_ = nullptr;
  new_compositor_frame_sink_ = nullptr;
  client_->DidFailToInitializeCompositorFrameSink();
}

std::unique_ptr<LayerTreeHostImpl>
LayerTreeHostInProcess::CreateLayerTreeHostImpl(
    LayerTreeHostImplClient* client) {
  DCHECK(task_runner_provider_->IsImplThread());

  const bool supports_impl_scrolling = task_runner_provider_->HasImplThread();
  std::unique_ptr<MutatorHost> mutator_host_impl =
      layer_tree_->mutator_host()->CreateImplInstance(supports_impl_scrolling);

  std::unique_ptr<LayerTreeHostImpl> host_impl = LayerTreeHostImpl::Create(
      settings_, client, task_runner_provider_.get(),
      rendering_stats_instrumentation_.get(), task_graph_runner_,
      std::move(mutator_host_impl), id_, std::move(image_worker_task_runner_));
  host_impl->SetHasGpuRasterizationTrigger(has_gpu_rasterization_trigger_);
  host_impl->SetContentIsSuitableForGpuRasterization(
      content_is_suitable_for_gpu_rasterization_);
  task_graph_runner_ = NULL;
  input_handler_weak_ptr_ = host_impl->AsWeakPtr();
  return host_impl;
}

void LayerTreeHostInProcess::DidLoseCompositorFrameSink() {
  TRACE_EVENT0("cc", "LayerTreeHostInProcess::DidLoseCompositorFrameSink");
  DCHECK(task_runner_provider_->IsMainThread());
  SetNeedsCommit();
}

void LayerTreeHostInProcess::SetDeferCommits(bool defer_commits) {
  proxy_->SetDeferCommits(defer_commits);
}

DISABLE_CFI_PERF
void LayerTreeHostInProcess::SetNeedsAnimate() {
  proxy_->SetNeedsAnimate();
  swap_promise_manager_.NotifySwapPromiseMonitorsOfSetNeedsCommit();
}

DISABLE_CFI_PERF
void LayerTreeHostInProcess::SetNeedsUpdateLayers() {
  proxy_->SetNeedsUpdateLayers();
  swap_promise_manager_.NotifySwapPromiseMonitorsOfSetNeedsCommit();
}

void LayerTreeHostInProcess::SetNeedsCommit() {
  proxy_->SetNeedsCommit();
  swap_promise_manager_.NotifySwapPromiseMonitorsOfSetNeedsCommit();
}

void LayerTreeHostInProcess::SetNeedsRecalculateRasterScales() {
  next_commit_forces_recalculate_raster_scales_ = true;
  proxy_->SetNeedsCommit();
}

void LayerTreeHostInProcess::SetNeedsRedrawRect(const gfx::Rect& damage_rect) {
  proxy_->SetNeedsRedraw(damage_rect);
}

bool LayerTreeHostInProcess::CommitRequested() const {
  return proxy_->CommitRequested();
}

bool LayerTreeHostInProcess::BeginMainFrameRequested() const {
  return proxy_->BeginMainFrameRequested();
}

void LayerTreeHostInProcess::SetNextCommitWaitsForActivation() {
  proxy_->SetNextCommitWaitsForActivation();
}

void LayerTreeHostInProcess::SetNextCommitForcesRedraw() {
  next_commit_forces_redraw_ = true;
  proxy_->SetNeedsUpdateLayers();
}

void LayerTreeHostInProcess::SetAnimationEvents(
    std::unique_ptr<MutatorEvents> events) {
  DCHECK(task_runner_provider_->IsMainThread());
  layer_tree_->mutator_host()->SetAnimationEvents(std::move(events));
}

void LayerTreeHostInProcess::SetDebugState(
    const LayerTreeDebugState& debug_state) {
  LayerTreeDebugState new_debug_state =
      LayerTreeDebugState::Unite(settings_.initial_debug_state, debug_state);

  if (LayerTreeDebugState::Equal(debug_state_, new_debug_state))
    return;

  debug_state_ = new_debug_state;

  rendering_stats_instrumentation_->set_record_rendering_stats(
      debug_state_.RecordRenderingStats());

  SetNeedsCommit();
}

void LayerTreeHostInProcess::ResetGpuRasterizationTracking() {
  content_is_suitable_for_gpu_rasterization_ = true;
  gpu_rasterization_histogram_recorded_ = false;
}

void LayerTreeHostInProcess::SetHasGpuRasterizationTrigger(bool has_trigger) {
  if (has_trigger == has_gpu_rasterization_trigger_)
    return;

  has_gpu_rasterization_trigger_ = has_trigger;
  TRACE_EVENT_INSTANT1(
      "cc", "LayerTreeHostInProcess::SetHasGpuRasterizationTrigger",
      TRACE_EVENT_SCOPE_THREAD, "has_trigger", has_gpu_rasterization_trigger_);
}

void LayerTreeHostInProcess::ApplyPageScaleDeltaFromImplSide(
    float page_scale_delta) {
  DCHECK(CommitRequested());
  if (page_scale_delta == 1.f)
    return;
  float page_scale = layer_tree_->page_scale_factor() * page_scale_delta;
  layer_tree_->SetPageScaleFromImplSide(page_scale);
}

void LayerTreeHostInProcess::SetVisible(bool visible) {
  if (visible_ == visible)
    return;
  visible_ = visible;
  proxy_->SetVisible(visible);
}

bool LayerTreeHostInProcess::IsVisible() const {
  return visible_;
}

void LayerTreeHostInProcess::NotifyInputThrottledUntilCommit() {
  proxy_->NotifyInputThrottledUntilCommit();
}

void LayerTreeHostInProcess::LayoutAndUpdateLayers() {
  DCHECK(IsSingleThreaded());
  // This function is only valid when not using the scheduler.
  DCHECK(!settings_.single_thread_proxy_scheduler);
  RequestMainFrameUpdate();
  UpdateLayers();
}

void LayerTreeHostInProcess::Composite(base::TimeTicks frame_begin_time) {
  DCHECK(IsSingleThreaded());
  // This function is only valid when not using the scheduler.
  DCHECK(!settings_.single_thread_proxy_scheduler);
  SingleThreadProxy* proxy = static_cast<SingleThreadProxy*>(proxy_.get());

  proxy->CompositeImmediately(frame_begin_time);
}

static int GetLayersUpdateTimeHistogramBucket(size_t numLayers) {
  // We uses the following exponential (ratio 2) bucketization:
  // [0, 10), [10, 30), [30, 70), [70, 150), [150, infinity)
  if (numLayers < 10)
    return 0;
  if (numLayers < 30)
    return 1;
  if (numLayers < 70)
    return 2;
  if (numLayers < 150)
    return 3;
  return 4;
}

bool LayerTreeHostInProcess::UpdateLayers() {
  if (!layer_tree_->root_layer()) {
    layer_tree_->property_trees()->clear();
    return false;
  }
  DCHECK(!layer_tree_->root_layer()->parent());
  base::ElapsedTimer timer;

  bool result = DoUpdateLayers(layer_tree_->root_layer());
  micro_benchmark_controller_.DidUpdateLayers();

  if (const char* client_name = GetClientNameForMetrics()) {
    std::string histogram_name = base::StringPrintf(
        "Compositing.%s.LayersUpdateTime.%d", client_name,
        GetLayersUpdateTimeHistogramBucket(layer_tree_->NumLayers()));
    base::Histogram::FactoryGet(histogram_name, 0, 10000000, 50,
                                base::HistogramBase::kUmaTargetedHistogramFlag)
        ->Add(timer.Elapsed().InMicroseconds());
  }

  return result || next_commit_forces_redraw_;
}

void LayerTreeHostInProcess::DidCompletePageScaleAnimation() {
  did_complete_scale_animation_ = true;
}

void LayerTreeHostInProcess::RecordGpuRasterizationHistogram() {
  // Gpu rasterization is only supported for Renderer compositors.
  // Checking for IsSingleThreaded() to exclude Browser compositors.
  if (gpu_rasterization_histogram_recorded_ || IsSingleThreaded())
    return;

  // Record how widely gpu rasterization is enabled.
  // This number takes device/gpu whitelisting/backlisting into account.
  // Note that we do not consider the forced gpu rasterization mode, which is
  // mostly used for debugging purposes.
  UMA_HISTOGRAM_BOOLEAN("Renderer4.GpuRasterizationEnabled",
                        settings_.gpu_rasterization_enabled);
  if (settings_.gpu_rasterization_enabled) {
    UMA_HISTOGRAM_BOOLEAN("Renderer4.GpuRasterizationTriggered",
                          has_gpu_rasterization_trigger_);
    UMA_HISTOGRAM_BOOLEAN("Renderer4.GpuRasterizationSuitableContent",
                          content_is_suitable_for_gpu_rasterization_);
    // Record how many pages actually get gpu rasterization when enabled.
    UMA_HISTOGRAM_BOOLEAN("Renderer4.GpuRasterizationUsed",
                          (has_gpu_rasterization_trigger_ &&
                           content_is_suitable_for_gpu_rasterization_));
  }

  gpu_rasterization_histogram_recorded_ = true;
}

bool LayerTreeHostInProcess::DoUpdateLayers(Layer* root_layer) {
  TRACE_EVENT1("cc", "LayerTreeHostInProcess::DoUpdateLayers",
               "source_frame_number", SourceFrameNumber());

  layer_tree_->UpdateHudLayer(debug_state_.ShowHudInfo());
  UpdateHudLayer();

  Layer* root_scroll =
      PropertyTreeBuilder::FindFirstScrollableLayer(root_layer);
  Layer* page_scale_layer = layer_tree_->page_scale_layer();
  if (!page_scale_layer && root_scroll)
    page_scale_layer = root_scroll->parent();

  if (layer_tree_->hud_layer()) {
    layer_tree_->hud_layer()->PrepareForCalculateDrawProperties(
        layer_tree_->device_viewport_size(),
        layer_tree_->device_scale_factor());
  }

  gfx::Transform identity_transform;
  LayerList update_layer_list;

  {
    TRACE_EVENT0("cc",
                 "LayerTreeHostInProcess::UpdateLayers::BuildPropertyTrees");
    TRACE_EVENT0(
        TRACE_DISABLED_BY_DEFAULT("cc.debug.cdp-perf"),
        "LayerTreeHostInProcessCommon::ComputeVisibleRectsWithPropertyTrees");
    PropertyTreeBuilder::PreCalculateMetaInformation(root_layer);
    bool can_render_to_separate_surface = true;
    PropertyTrees* property_trees = layer_tree_->property_trees();
    if (!settings_.use_layer_lists) {
      // If use_layer_lists is set, then the property trees should have been
      // built by the client already.
      PropertyTreeBuilder::BuildPropertyTrees(
          root_layer, page_scale_layer,
          layer_tree_->inner_viewport_scroll_layer(),
          layer_tree_->outer_viewport_scroll_layer(),
          layer_tree_->overscroll_elasticity_layer(),
          layer_tree_->elastic_overscroll(), layer_tree_->page_scale_factor(),
          layer_tree_->device_scale_factor(),
          gfx::Rect(layer_tree_->device_viewport_size()), identity_transform,
          property_trees);
      TRACE_EVENT_INSTANT1(
          "cc", "LayerTreeHostInProcess::UpdateLayers_BuiltPropertyTrees",
          TRACE_EVENT_SCOPE_THREAD, "property_trees",
          property_trees->AsTracedValue());
    } else {
      TRACE_EVENT_INSTANT1(
          "cc", "LayerTreeHostInProcess::UpdateLayers_ReceivedPropertyTrees",
          TRACE_EVENT_SCOPE_THREAD, "property_trees",
          property_trees->AsTracedValue());
    }
    draw_property_utils::UpdatePropertyTrees(property_trees,
                                             can_render_to_separate_surface);
    draw_property_utils::FindLayersThatNeedUpdates(
        layer_tree_.get(), property_trees, &update_layer_list);
  }

  for (const auto& layer : update_layer_list)
    layer->SavePaintProperties();

  bool content_is_suitable_for_gpu = true;
  bool did_paint_content = layer_tree_->UpdateLayers(
      update_layer_list, &content_is_suitable_for_gpu);

  if (content_is_suitable_for_gpu) {
    ++num_consecutive_frames_suitable_for_gpu_;
    if (num_consecutive_frames_suitable_for_gpu_ >=
        kNumFramesToConsiderBeforeGpuRasterization) {
      content_is_suitable_for_gpu_rasterization_ = true;
    }
  } else {
    num_consecutive_frames_suitable_for_gpu_ = 0;
    content_is_suitable_for_gpu_rasterization_ = false;
  }
  return did_paint_content;
}

void LayerTreeHostInProcess::ApplyViewportDeltas(ScrollAndScaleSet* info) {
  gfx::Vector2dF inner_viewport_scroll_delta;
  if (info->inner_viewport_scroll.layer_id != Layer::INVALID_ID)
    inner_viewport_scroll_delta = info->inner_viewport_scroll.scroll_delta;

  if (inner_viewport_scroll_delta.IsZero() && info->page_scale_delta == 1.f &&
      info->elastic_overscroll_delta.IsZero() && !info->top_controls_delta)
    return;

  // Preemptively apply the scroll offset and scale delta here before sending
  // it to the client.  If the client comes back and sets it to the same
  // value, then the layer can early out without needing a full commit.
  if (layer_tree_->inner_viewport_scroll_layer()) {
    layer_tree_->inner_viewport_scroll_layer()->SetScrollOffsetFromImplSide(
        gfx::ScrollOffsetWithDelta(
            layer_tree_->inner_viewport_scroll_layer()->scroll_offset(),
            inner_viewport_scroll_delta));
  }

  ApplyPageScaleDeltaFromImplSide(info->page_scale_delta);
  layer_tree_->SetElasticOverscrollFromImplSide(
      layer_tree_->elastic_overscroll() + info->elastic_overscroll_delta);
  // TODO(ccameron): pass the elastic overscroll here so that input events
  // may be translated appropriately.
  client_->ApplyViewportDeltas(inner_viewport_scroll_delta, gfx::Vector2dF(),
                               info->elastic_overscroll_delta,
                               info->page_scale_delta,
                               info->top_controls_delta);
  SetNeedsUpdateLayers();
}

void LayerTreeHostInProcess::ApplyScrollAndScale(ScrollAndScaleSet* info) {
  for (auto& swap_promise : info->swap_promises) {
    TRACE_EVENT_WITH_FLOW1("input,benchmark", "LatencyInfo.Flow",
                           TRACE_ID_DONT_MANGLE(swap_promise->TraceId()),
                           TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
                           "step", "Main thread scroll update");
    swap_promise_manager_.QueueSwapPromise(std::move(swap_promise));
  }

  if (layer_tree_->root_layer()) {
    for (size_t i = 0; i < info->scrolls.size(); ++i) {
      Layer* layer = layer_tree_->LayerById(info->scrolls[i].layer_id);
      if (!layer)
        continue;
      layer->SetScrollOffsetFromImplSide(gfx::ScrollOffsetWithDelta(
          layer->scroll_offset(), info->scrolls[i].scroll_delta));
      SetNeedsUpdateLayers();
    }
    for (size_t i = 0; i < info->scrollbars.size(); ++i) {
      Layer* layer = layer_tree_->LayerById(info->scrollbars[i].layer_id);
      if (!layer)
        continue;
      layer->SetScrollbarsHiddenFromImplSide(info->scrollbars[i].hidden);
    }
  }

  // This needs to happen after scroll deltas have been sent to prevent top
  // controls from clamping the layout viewport both on the compositor and
  // on the main thread.
  ApplyViewportDeltas(info);
}

void LayerTreeHostInProcess::SetReflectedMainFrameState(
    std::unique_ptr<ReflectedMainFrameState> reflected_main_frame_state) {
  DCHECK(IsThreaded());

  reflected_main_frame_state_ = std::move(reflected_main_frame_state);
  SetNeedsCommit();
}

const base::WeakPtr<InputHandler>& LayerTreeHostInProcess::GetInputHandler()
    const {
  return input_handler_weak_ptr_;
}

void LayerTreeHostInProcess::UpdateBrowserControlsState(
    BrowserControlsState constraints,
    BrowserControlsState current,
    bool animate) {
  // Browser controls are only used in threaded mode.
  DCHECK(IsThreaded());
  proxy_->UpdateBrowserControlsState(constraints, current, animate);
}

void LayerTreeHostInProcess::AnimateLayers(base::TimeTicks monotonic_time) {
  MutatorHost* mutator_host = layer_tree_->mutator_host();
  std::unique_ptr<MutatorEvents> events = mutator_host->CreateEvents();

  if (mutator_host->TickAnimations(monotonic_time))
    mutator_host->UpdateAnimationState(true, events.get());

  if (!events->IsEmpty())
    layer_tree_->property_trees()->needs_rebuild = true;
}

int LayerTreeHostInProcess::ScheduleMicroBenchmark(
    const std::string& benchmark_name,
    std::unique_ptr<base::Value> value,
    const MicroBenchmark::DoneCallback& callback) {
  return micro_benchmark_controller_.ScheduleRun(benchmark_name,
                                                 std::move(value), callback);
}

bool LayerTreeHostInProcess::SendMessageToMicroBenchmark(
    int id,
    std::unique_ptr<base::Value> value) {
  return micro_benchmark_controller_.SendMessage(id, std::move(value));
}

void LayerTreeHostInProcess::SetLayerTreeMutator(
    std::unique_ptr<LayerTreeMutator> mutator) {
  proxy_->SetMutator(std::move(mutator));
}

bool LayerTreeHostInProcess::IsSingleThreaded() const {
  DCHECK(compositor_mode_ != CompositorMode::SINGLE_THREADED ||
         !task_runner_provider_->HasImplThread());
  return compositor_mode_ == CompositorMode::SINGLE_THREADED;
}

bool LayerTreeHostInProcess::IsThreaded() const {
  DCHECK(compositor_mode_ != CompositorMode::THREADED ||
         task_runner_provider_->HasImplThread());
  return compositor_mode_ == CompositorMode::THREADED;
}

}  // namespace cc
