// Copyright 2013 The Flutter 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 "flutter/flow/testing/mock_raster_cache.h"

#include "flutter/flow/layers/display_list_raster_cache_item.h"
#include "flutter/flow/layers/layer.h"
#include "flutter/flow/raster_cache.h"
#include "flutter/flow/raster_cache_item.h"
#include "include/core/SkMatrix.h"

namespace flutter {
namespace testing {

MockRasterCacheResult::MockRasterCacheResult(SkRect device_rect)
    : RasterCacheResult(nullptr, SkRect::MakeEmpty(), "RasterCacheFlow::test"),
      device_rect_(device_rect) {}

void MockRasterCache::AddMockLayer(int width, int height) {
  SkMatrix ctm = SkMatrix::I();
  SkPath path;
  path.addRect(100, 100, 100 + width, 100 + height);
  int layer_cached_threshold = 1;
  MockCacheableLayer layer =
      MockCacheableLayer(path, DlPaint(), layer_cached_threshold);
  layer.Preroll(&preroll_context_);
  layer.raster_cache_item()->TryToPrepareRasterCache(paint_context_);
  RasterCache::Context r_context = {
      // clang-format off
      .gr_context         = preroll_context_.gr_context,
      .dst_color_space    = preroll_context_.dst_color_space,
      .matrix             = ctm,
      .logical_rect       = layer.paint_bounds(),
      // clang-format on
  };
  UpdateCacheEntry(
      RasterCacheKeyID(layer.unique_id(), RasterCacheKeyType::kLayer),
      r_context, [&](DlCanvas* canvas) {
        SkRect cache_rect = RasterCacheUtil::GetDeviceBounds(
            r_context.logical_rect, r_context.matrix);
        return std::make_unique<MockRasterCacheResult>(cache_rect);
      });
}

void MockRasterCache::AddMockPicture(int width, int height) {
  FML_DCHECK(access_threshold() > 0);
  SkMatrix ctm = SkMatrix::I();
  DisplayListBuilder builder(SkRect::MakeLTRB(0, 0, 200 + width, 200 + height));
  SkPath path;
  path.addRect(100, 100, 100 + width, 100 + height);
  builder.DrawPath(path, DlPaint());
  sk_sp<DisplayList> display_list = builder.Build();

  FixedRefreshRateStopwatch raster_time;
  FixedRefreshRateStopwatch ui_time;
  LayerStateStack state_stack;
  PaintContextHolder holder =
      GetSamplePaintContextHolder(state_stack, this, &raster_time, &ui_time);
  holder.paint_context.dst_color_space = color_space_.get();

  DisplayListRasterCacheItem display_list_item(display_list, SkPoint(), true,
                                               false);
  for (size_t i = 0; i < access_threshold(); i++) {
    display_list_item.PrerollSetup(&preroll_context_, ctm);
    display_list_item.PrerollFinalize(&preroll_context_, ctm);
  }
  RasterCache::Context r_context = {
      // clang-format off
      .gr_context         = preroll_context_.gr_context,
      .dst_color_space    = preroll_context_.dst_color_space,
      .matrix             = ctm,
      .logical_rect       = display_list->bounds(),
      // clang-format on
  };
  UpdateCacheEntry(RasterCacheKeyID(display_list->unique_id(),
                                    RasterCacheKeyType::kDisplayList),
                   r_context, [&](DlCanvas* canvas) {
                     SkRect cache_rect = RasterCacheUtil::GetDeviceBounds(
                         r_context.logical_rect, r_context.matrix);
                     return std::make_unique<MockRasterCacheResult>(cache_rect);
                   });
}

PrerollContextHolder GetSamplePrerollContextHolder(
    LayerStateStack& state_stack,
    RasterCache* raster_cache,
    FixedRefreshRateStopwatch* raster_time,
    FixedRefreshRateStopwatch* ui_time) {
  sk_sp<SkColorSpace> srgb = SkColorSpace::MakeSRGB();

  PrerollContextHolder holder = {
      {
          // clang-format off
          .raster_cache                  = raster_cache,
          .gr_context                    = nullptr,
          .view_embedder                 = nullptr,
          .state_stack                   = state_stack,
          .dst_color_space               = srgb.get(),
          .surface_needs_readback        = false,
          .raster_time                   = *raster_time,
          .ui_time                       = *ui_time,
          .texture_registry              = nullptr,
          .has_platform_view             = false,
          .has_texture_layer             = false,
          .raster_cached_entries         = &raster_cache_items_,
          // clang-format on
      },
      srgb};

  return holder;
}

PaintContextHolder GetSamplePaintContextHolder(
    LayerStateStack& state_stack,
    RasterCache* raster_cache,
    FixedRefreshRateStopwatch* raster_time,
    FixedRefreshRateStopwatch* ui_time) {
  sk_sp<SkColorSpace> srgb = SkColorSpace::MakeSRGB();
  PaintContextHolder holder = {// clang-format off
    {
        .state_stack                   = state_stack,
        .canvas                        = nullptr,
        .gr_context                    = nullptr,
        .dst_color_space               = srgb.get(),
        .view_embedder                 = nullptr,
        .raster_time                   = *raster_time,
        .ui_time                       = *ui_time,
        .texture_registry              = nullptr,
        .raster_cache                  = raster_cache,
    },
                               // clang-format on
                               srgb};

  return holder;
}

bool RasterCacheItemPrerollAndTryToRasterCache(
    DisplayListRasterCacheItem& display_list_item,
    PrerollContext& context,
    PaintContext& paint_context,
    const SkMatrix& matrix) {
  RasterCacheItemPreroll(display_list_item, context, matrix);
  context.raster_cache->EvictUnusedCacheEntries();
  return RasterCacheItemTryToRasterCache(display_list_item, paint_context);
}

void RasterCacheItemPreroll(DisplayListRasterCacheItem& display_list_item,
                            PrerollContext& context,
                            const SkMatrix& matrix) {
  display_list_item.PrerollSetup(&context, matrix);
  display_list_item.PrerollFinalize(&context, matrix);
}

bool RasterCacheItemTryToRasterCache(
    DisplayListRasterCacheItem& display_list_item,
    PaintContext& paint_context) {
  if (display_list_item.cache_state() ==
      RasterCacheItem::CacheState::kCurrent) {
    return display_list_item.TryToPrepareRasterCache(paint_context);
  }
  return false;
}

}  // namespace testing
}  // namespace flutter
