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

#include "components/viz/service/layers/layer_context_impl_base_unittest.h"

#include <utility>

#include "components/viz/service/layers/layer_context_impl.h"
#include "components/viz/service/layers/viz_layer_tree_host_impl.h"

namespace viz {

const gfx::Rect LayerContextImplTest::kDefaultDeviceViewportRect(100, 100);
const SkColor4f LayerContextImplTest::kDefaultBackgroundColor =
    SkColors::kTransparent;
const FrameSinkId LayerContextImplTest::kDefaultFrameSinkId = FrameSinkId(1, 1);
const LocalSurfaceId LayerContextImplTest::kDefaultLocalSurfaceId(
    1,
    base::UnguessableToken::CreateForTesting(2u, 3u));
const SurfaceId LayerContextImplTest::kDefaultSurfaceId(kDefaultFrameSinkId,
                                                        kDefaultLocalSurfaceId);
const SurfaceRange LayerContextImplTest::kDefaultSurfaceRange(
    std::nullopt,
    kDefaultSurfaceId);
const gfx::Size LayerContextImplTest::kDefaultLayerBounds(10, 10);
const gfx::PointF LayerContextImplTest::kDefaultUVTopLeft = gfx::PointF();
const gfx::PointF LayerContextImplTest::kDefaultUVBottomRight =
    gfx::PointF(1.f, 1.f);
const cc::ElementId LayerContextImplTest::kDefaultScrollElementId =
    cc::ElementId();
const SkColor4f LayerContextImplTest::kDefaultSolidColorScrollbarColor =
    SkColors::kTransparent;
const gfx::Size
    LayerContextImplTest::kDefaultNinePatchThumbScrollbarImageBounds =
        gfx::Size();
const gfx::Rect LayerContextImplTest::kDefaultNinePatchThumbScrollbarAperture =
    gfx::Rect();
const cc::UIResourceId
    LayerContextImplTest::kDefaultNinePatchThumbScrollbarThumbUIResourceId = 0;
const cc::UIResourceId LayerContextImplTest::
    kDefaultNinePatchThumbScrollbarTrackAndButtonsUIResourceId = 0;
const gfx::Size
    LayerContextImplTest::kDefaultPaintedScrollbarInternalContentBounds =
        gfx::Size();
const gfx::Rect LayerContextImplTest::kDefaultPaintedScrollbarBackButtonRect =
    gfx::Rect();
const gfx::Rect
    LayerContextImplTest::kDefaultPaintedScrollbarForwardButtonRect =
        gfx::Rect();
const gfx::Rect LayerContextImplTest::kDefaultPaintedScrollbarTrackRect =
    gfx::Rect();
const std::optional<SkColor4f>
    LayerContextImplTest::kDefaultPaintedScrollbarThumbColor = std::nullopt;
const gfx::Size
    LayerContextImplTest::kDefaultPaintedScrollbarTrackAndButtonsImageBounds =
        gfx::Size();
const gfx::Rect
    LayerContextImplTest::kDefaultPaintedScrollbarTrackAndButtonsAperture =
        gfx::Rect();
const ViewTransitionElementResourceId
    LayerContextImplTest::kDefaultViewTransitionContentLayerResourceId =
        ViewTransitionElementResourceId(blink::ViewTransitionToken(), 1, false);
const gfx::RectF
    LayerContextImplTest::kDefaultViewTransitionContentLayerMaxExtentsRect;
const std::optional<SkColor4f>
    LayerContextImplTest::kDefaultTileDisplaySolidColor = std::nullopt;

// Default UIResourceLayer property values
const gfx::Size LayerContextImplTest::kDefaultUIResourceImageBounds =
    gfx::Size();
const gfx::PointF LayerContextImplTest::kDefaultUIResourceUVTopLeft =
    gfx::PointF(0.0f, 0.0f);
const gfx::PointF LayerContextImplTest::kDefaultUIResourceUVBottomRight =
    gfx::PointF(1.0f, 1.0f);

// Default NinePatchLayer property values
const gfx::Size LayerContextImplTest::kDefaultNinePatchImageBounds =
    gfx::Size();
const gfx::PointF LayerContextImplTest::kDefaultNinePatchUVTopLeft =
    gfx::PointF(0.0f, 0.0f);
const gfx::PointF LayerContextImplTest::kDefaultNinePatchUVBottomRight =
    gfx::PointF(1.0f, 1.0f);

const gfx::Rect LayerContextImplTest::kDefaultNinePatchAperture = gfx::Rect();
const gfx::Rect LayerContextImplTest::kDefaultNinePatchBorder = gfx::Rect();
const gfx::Rect LayerContextImplTest::kDefaultNinePatchLayerOcclusion =
    gfx::Rect();

LayerContextImplTest::LayerContextImplTest()
    : frame_sink_manager_(FrameSinkManagerImpl::InitParams()) {}

LayerContextImplTest::~LayerContextImplTest() = default;

void LayerContextImplTest::SetUp() {
  compositor_frame_sink_support_ = std::make_unique<CompositorFrameSinkSupport>(
      &dummy_client_, &frame_sink_manager_, kDefaultFrameSinkId,
      /*is_root=*/true);
  auto settings = mojom::LayerContextSettings::New();
  settings->draw_mode_is_gpu = true;
  settings->enable_edge_anti_aliasing = true;
  layer_context_impl_ = LayerContextImpl::CreateForTesting(
      compositor_frame_sink_support_.get(), std::move(settings));
}

void LayerContextImplTest::RecreateLayerContextImplWithSettings(
    mojom::LayerContextSettingsPtr settings) {
  layer_context_impl_ = LayerContextImpl::CreateForTesting(
      compositor_frame_sink_support_.get(), std::move(settings));
}

void LayerContextImplTest::ResetTestState() {
  // Property tree node IDs and layers are reinitialized in
  // CreateDefaultUpdate if first_update_ is true.
  first_update_ = true;
}

mojom::LayerTreeUpdatePtr LayerContextImplTest::CreateDefaultUpdate() {
  auto update = mojom::LayerTreeUpdate::New();

  if (first_update_) {
    AddFirstTimeDefaultProperties(update.get());
    first_update_ = false;
  }
  AddDefaultPropertyUpdates(update.get());

  return update;
}

void LayerContextImplTest::AddDefaultPropertyUpdates(
    mojom::LayerTreeUpdate* update) {
  update->source_frame_number = 1;
  update->trace_id = 1;
  update->primary_main_frame_item_sequence_number = 1;
  update->device_viewport = kDefaultDeviceViewportRect;
  update->background_color = kDefaultBackgroundColor;

  // Valid scale factors by default
  update->page_scale_factor = kDefaultPageScaleFactor;
  update->min_page_scale_factor = kDefaultMinPageScaleFactor;
  update->max_page_scale_factor = kDefaultMaxPageScaleFactor;
  update->external_page_scale_factor = kDefaultExternalPageScaleFactor;
  update->device_scale_factor = kDefaultDeviceScaleFactor;
  update->painted_device_scale_factor = kDefaultPaintedDeviceScaleFactor;

  update->top_controls_shown_ratio =
      LayerContextImplTest::kDefaultTopControlsShownRatio;
  update->bottom_controls_shown_ratio = kDefaultBottomControlsShownRatio;

  update->num_transform_nodes = next_transform_id_;
  update->num_clip_nodes = next_clip_id_;
  update->num_effect_nodes = next_effect_id_;
  update->num_scroll_nodes = next_scroll_id_;

  // Viewport property IDs
  update->overscroll_elasticity_transform =
      viewport_property_ids.overscroll_elasticity_transform;
  update->page_scale_transform = viewport_property_ids.page_scale_transform;
  update->inner_scroll = viewport_property_ids.inner_scroll;
  update->outer_clip = viewport_property_ids.outer_clip;
  update->outer_scroll = viewport_property_ids.outer_scroll;

  // Other defaults
  update->display_color_spaces = gfx::DisplayColorSpaces();
  update->local_surface_id_from_parent = kDefaultLocalSurfaceId;
  update->current_local_surface_id = kDefaultLocalSurfaceId;
  update->next_frame_token = 1;

  base::TimeTicks now = base::TimeTicks::Now();
  base::TimeDelta interval = base::Milliseconds(16);
  update->begin_frame_args = BeginFrameArgs::Create(
      BEGINFRAME_FROM_HERE, BeginFrameArgs::kStartingSourceId,
      BeginFrameArgs::kStartingFrameNumber, now, now + interval, interval,
      BeginFrameArgs::NORMAL);
}

void LayerContextImplTest::AddFirstTimeDefaultProperties(
    mojom::LayerTreeUpdate* update) {
  // Set internal state to defaults.
  next_layer_id_ = 1;
  next_transform_id_ = 0;
  next_clip_id_ = 0;
  next_effect_id_ = 0;
  next_scroll_id_ = 0;
  layer_order_.clear();

  // Root & Secondary transform nodes are always expected 1st
  AddTransformNode(update, cc::kInvalidPropertyNodeId);
  AddTransformNode(update, cc::kRootPropertyNodeId);

  // Updating the page scale requires that a page_scale_transform node is
  // set up.
  viewport_property_ids.overscroll_elasticity_transform =
      AddTransformNode(update, cc::kSecondaryRootPropertyNodeId);
  viewport_property_ids.page_scale_transform = AddTransformNode(
      update, viewport_property_ids.overscroll_elasticity_transform);
  update->transform_nodes.back()->in_subtree_of_page_scale_layer = true;

  // Root & Secondary clip nodes are always expected
  AddClipNode(update, cc::kInvalidPropertyNodeId);
  AddClipNode(update, cc::kRootPropertyNodeId);

  // Root & Secondary effect nodes are always expected
  AddEffectNode(update, cc::kInvalidPropertyNodeId);
  AddEffectNode(update, cc::kRootPropertyNodeId);
  update->effect_nodes.back()->render_surface_reason =
      cc::RenderSurfaceReason::kRoot;
  update->effect_nodes.back()->element_id = cc::ElementId(1ULL);

  // Root & Secondary scroll nodes are always expected
  AddScrollNode(update, cc::kInvalidPropertyNodeId);
  viewport_property_ids.outer_scroll =
      AddScrollNode(update, cc::kRootPropertyNodeId);
  update->scroll_nodes.back()->element_id = cc::ElementId(1ULL);
  viewport_property_ids.inner_scroll =
      AddScrollNode(update, viewport_property_ids.outer_scroll);
  update->scroll_nodes.back()->element_id = cc::ElementId(1ULL);

  // Root layer
  AddDefaultLayerToUpdate(update);
}

int LayerContextImplTest::AddTransformNode(mojom::LayerTreeUpdate* update,
                                           int parent) {
  auto node = mojom::TransformNode::New();
  int id = next_transform_id_++;
  node->id = id;
  node->parent_id = parent;
  update->transform_nodes.push_back(std::move(node));
  update->num_transform_nodes = next_transform_id_;
  return id;
}

int LayerContextImplTest::AddClipNode(mojom::LayerTreeUpdate* update,
                                      int parent) {
  auto node = mojom::ClipNode::New();
  int id = next_clip_id_++;
  node->id = id;
  node->parent_id = parent;
  node->transform_id = viewport_property_ids.page_scale_transform;
  update->clip_nodes.push_back(std::move(node));
  update->num_clip_nodes = next_clip_id_;
  return id;
}

int LayerContextImplTest::AddEffectNode(mojom::LayerTreeUpdate* update,
                                        int parent) {
  auto node = mojom::EffectNode::New();
  int id = next_effect_id_++;
  node->id = id;
  node->parent_id = parent;
  node->transform_id = viewport_property_ids.page_scale_transform;
  node->clip_id = cc::kRootPropertyNodeId;
  node->target_id = cc::kRootPropertyNodeId;
  update->effect_nodes.push_back(std::move(node));
  update->num_effect_nodes = next_effect_id_;
  return id;
}

int LayerContextImplTest::AddScrollNode(mojom::LayerTreeUpdate* update,
                                        int parent) {
  auto node = mojom::ScrollNode::New();
  int id = next_scroll_id_++;
  node->id = id;
  node->parent_id = parent;
  node->transform_id = viewport_property_ids.page_scale_transform;
  update->scroll_nodes.push_back(std::move(node));
  update->num_scroll_nodes = next_scroll_id_;
  return id;
}

mojom::ScrollbarLayerBaseExtraPtr
LayerContextImplTest::CreateDefaultScrollbarBaseExtra() {
  auto base_extra = mojom::ScrollbarLayerBaseExtra::New();
  base_extra->scroll_element_id = kDefaultScrollElementId;
  base_extra->is_overlay_scrollbar = kDefaultIsOverlayScrollbar;
  base_extra->is_web_test = kDefaultIsWebTest;
  base_extra->thumb_thickness_scale_factor = kDefaultThumbThicknessScaleFactor;
  base_extra->current_pos = kDefaultCurrentPos;
  base_extra->clip_layer_length = kDefaultClipLayerLength;
  base_extra->scroll_layer_length = kDefaultScrollLayerLength;
  base_extra->vertical_adjust = kDefaultVerticalAdjust;
  base_extra->has_find_in_page_tickmarks = kDefaultHasFindInPageTickmarks;
  base_extra->is_horizontal_orientation = kDefaultIsHorizontalOrientation;
  base_extra->is_left_side_vertical_scrollbar =
      kDefaultIsLeftSideVerticalScrollbar;
  return base_extra;
}

mojom::LayerExtraPtr LayerContextImplTest::CreateDefaultLayerExtra(
    cc::mojom::LayerType type) {
  switch (type) {
    case cc::mojom::LayerType::kTexture: {
      auto extra = mojom::TextureLayerExtra::New();
      extra->blend_background_color = kDefaultBlendBackgroundColor;
      extra->force_texture_to_opaque = kDefaultForceTextureToOpaque;
      extra->uv_top_left = kDefaultUVTopLeft;
      extra->uv_bottom_right = kDefaultUVBottomRight;
      return mojom::LayerExtra::NewTextureLayerExtra(std::move(extra));
    }
    case cc::mojom::LayerType::kSurface: {
      auto extra = mojom::SurfaceLayerExtra::New();
      extra->surface_range = kDefaultSurfaceRange;
      extra->deadline_in_frames = kDefaultDeadlineInFrames;
      extra->stretch_content_to_fill_bounds =
          kDefaultStretchContentToFillBounds;
      extra->surface_hit_testable = kDefaultSurfaceHitTestable;
      extra->has_pointer_events_none = kDefaultHasPointerEventsNone;
      extra->is_reflection = kDefaultIsReflection;
      extra->will_draw_needs_reset = kDefaultWillDrawNeedsReset;
      extra->override_child_paint_flags = kDefaultOverrideChildPaintFlags;
      return mojom::LayerExtra::NewSurfaceLayerExtra(std::move(extra));
    }
    case cc::mojom::LayerType::kSolidColorScrollbar: {
      auto extra = mojom::SolidColorScrollbarLayerExtra::New();
      extra->scrollbar_base_extra = CreateDefaultScrollbarBaseExtra();
      extra->color = kDefaultSolidColorScrollbarColor;
      extra->thumb_thickness = kDefaultSolidColorScrollbarThumbThickness;
      extra->track_start = kDefaultSolidColorScrollbarTrackStart;
      return mojom::LayerExtra::NewSolidColorScrollbarLayerExtra(
          std::move(extra));
    }
    case cc::mojom::LayerType::kNinePatchThumbScrollbar: {
      auto extra = mojom::NinePatchThumbScrollbarLayerExtra::New();
      extra->scrollbar_base_extra = CreateDefaultScrollbarBaseExtra();
      extra->thumb_thickness = kDefaultNinePatchThumbScrollbarThumbThickness;
      extra->minimum_thumb_length = kDefaultNinePatchThumbScrollbarThumbLength;
      extra->track_start = kDefaultNinePatchThumbScrollbarTrackStart;
      extra->track_length = kDefaultNinePatchThumbScrollbarTrackLength;
      extra->image_bounds = kDefaultNinePatchThumbScrollbarImageBounds;
      extra->aperture = kDefaultNinePatchThumbScrollbarAperture;
      extra->thumb_ui_resource_id =
          kDefaultNinePatchThumbScrollbarThumbUIResourceId;
      extra->track_and_buttons_ui_resource_id =
          kDefaultNinePatchThumbScrollbarTrackAndButtonsUIResourceId;
      return mojom::LayerExtra::NewNinePatchThumbScrollbarLayerExtra(
          std::move(extra));
    }
    case cc::mojom::LayerType::kMirror: {
      auto extra = mojom::MirrorLayerExtra::New();
      extra->mirrored_layer_id = kDefaultMirrorLayerMirroredLayerId;
      return mojom::LayerExtra::NewMirrorLayerExtra(std::move(extra));
    }
    case cc::mojom::LayerType::kNinePatch: {
      auto extra = mojom::NinePatchLayerExtra::New();
      extra->image_aperture = kDefaultNinePatchAperture;
      extra->border = kDefaultNinePatchBorder;
      extra->layer_occlusion = kDefaultNinePatchLayerOcclusion;
      extra->fill_center = kDefaultNinePatchFillCenter;
      extra->ui_resource_id = kDefaultNinePatchUIResourceId;
      extra->image_bounds = kDefaultNinePatchImageBounds;
      extra->uv_top_left = kDefaultNinePatchUVTopLeft;
      extra->uv_bottom_right = kDefaultNinePatchUVBottomRight;
      return mojom::LayerExtra::NewNinePatchLayerExtra(std::move(extra));
    }
    case cc::mojom::LayerType::kPaintedScrollbar: {
      auto extra = mojom::PaintedScrollbarLayerExtra::New();
      extra->scrollbar_base_extra = CreateDefaultScrollbarBaseExtra();
      extra->internal_contents_scale =
          kDefaultPaintedScrollbarInternalContentsScale;
      extra->internal_content_bounds =
          kDefaultPaintedScrollbarInternalContentBounds;
      extra->jump_on_track_click = kDefaultPaintedScrollbarJumpOnTrackClick;
      extra->supports_drag_snap_back =
          kDefaultPaintedScrollbarSupportsDragSnapBack;
      extra->thumb_thickness = kDefaultPaintedScrollbarThumbThickness;
      extra->minimum_thumb_length = kDefaultPaintedScrollbarThumbLength;
      extra->track_and_buttons_ui_resource_id =
          kDefaultPaintedScrollbarTrackAndButtonsUIResourceId;
      extra->thumb_ui_resource_id = kDefaultPaintedScrollbarThumbUIResourceId;
      extra->uses_nine_patch_track_and_buttons =
          kDefaultPaintedScrollbarUsesNinePatchTrackAndButtons;
      extra->painted_opacity = kDefaultPaintedScrollbarPaintedOpacity;
      extra->thumb_color = kDefaultPaintedScrollbarThumbColor;
      extra->track_and_buttons_image_bounds =
          kDefaultPaintedScrollbarTrackAndButtonsImageBounds;
      extra->track_and_buttons_aperture =
          kDefaultPaintedScrollbarTrackAndButtonsAperture;
      return mojom::LayerExtra::NewPaintedScrollbarLayerExtra(std::move(extra));
    }
    case cc::mojom::LayerType::kViewTransitionContent: {
      auto extra = mojom::ViewTransitionContentLayerExtra::New();
      extra->resource_id = kDefaultViewTransitionContentLayerResourceId;
      extra->is_live_content_layer =
          kDefaultViewTransitionContentLayerIsLiveContentLayer;
      extra->max_extents_rect =
          kDefaultViewTransitionContentLayerMaxExtentsRect;
      return mojom::LayerExtra::NewViewTransitionContentLayerExtra(
          std::move(extra));
    }
    case cc::mojom::LayerType::kTileDisplay: {
      auto extra = mojom::TileDisplayLayerExtra::New();
      extra->solid_color = kDefaultTileDisplaySolidColor;
      extra->is_backdrop_filter_mask = kDefaultTileDisplayIsBackdropFilterMask;
      return mojom::LayerExtra::NewTileDisplayLayerExtra(std::move(extra));
    }
    case cc::mojom::LayerType::kUIResource: {
      auto extra = mojom::UIResourceLayerExtra::New();
      extra->ui_resource_id = kDefaultUIResourceId;
      extra->image_bounds = kDefaultUIResourceImageBounds;
      extra->uv_top_left = kDefaultUIResourceUVTopLeft;
      extra->uv_bottom_right = kDefaultUIResourceUVBottomRight;
      return mojom::LayerExtra::NewUiResourceLayerExtra(std::move(extra));
    }

    default:
      // TODO(vmiura): Add each layer type's initialization.
      return nullptr;
  }
}

// Helper to add a default layer to the update.
// Returns the ID of the added layer.
int LayerContextImplTest::AddDefaultLayerToUpdate(
    mojom::LayerTreeUpdate* update,
    cc::mojom::LayerType type,
    int id) {
  auto layer = mojom::Layer::New();
  if (id == -1) {
    id = next_layer_id_++;
  }
  SetLayerId(layer.get(), id);
  SetLayerType(layer.get(), type);
  SetLayerTransformTreeIndex(layer.get(), cc::kSecondaryRootPropertyNodeId);
  SetLayerClipTreeIndex(layer.get(), cc::kRootPropertyNodeId);
  SetLayerEffectTreeIndex(layer.get(), cc::kSecondaryRootPropertyNodeId);
  SetLayerBounds(layer.get(), kDefaultLayerBounds);
  SetLayerExtra(layer.get(), CreateDefaultLayerExtra(type));

  update->layers.push_back(std::move(layer));

  // Update the local layer order, and in the LayerTreeUpdate.
  layer_order_.push_back(id);
  update->layer_order = layer_order_;
  return id;
}

void LayerContextImplTest::RemoveLayerInUpdate(mojom::LayerTreeUpdate* update,
                                               int id) {
  // Remove the ID from the local list of layers if it exists.
  auto it = std::find(layer_order_.begin(), layer_order_.end(), id);
  if (it != layer_order_.end()) {
    layer_order_.erase(it);
  }

  // Update the layer order in the LayerTreeUpdate.
  update->layer_order = layer_order_;
}

TransferableResource LayerContextImplTest::MakeFakeResource(gfx::Size size) {
  auto sync_token =
      gpu::SyncToken(gpu::CommandBufferNamespace::GPU_IO,
                     gpu::CommandBufferId::FromUnsafeValue(0x234), 0x456);
  auto shared_image = gpu::ClientSharedImage::CreateForTesting(
      {SinglePlaneFormat::kRGBA_8888, size, gfx::ColorSpace(),
       kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType,
       gpu::SHARED_IMAGE_USAGE_DISPLAY_READ},
      GL_TEXTURE_2D);

  return TransferableResource::Make(
      shared_image, TransferableResource::ResourceSource::kTest, sync_token);
}

mojom::TransferableUIResourceRequestPtr
LayerContextImplTest::CreateUIResourceRequest(
    int uid,
    mojom::TransferableUIResourceRequest::Type type) {
  auto request = mojom::TransferableUIResourceRequest::New();
  request->uid = uid;
  request->type = type;
  if (type == mojom::TransferableUIResourceRequest::Type::kCreate) {
    // Add a minimal valid resource.
    request->transferable_resource = MakeFakeResource(gfx::Size(1, 1));
  }
  return request;
}

cc::LayerImpl* LayerContextImplTest::GetLayerFromActiveTree(int layer_id) {
  return layer_context_impl_->host_impl()->active_tree()->LayerById(layer_id);
}

mojom::LayerPtr LayerContextImplTest::CreateManualLayer(
    int id,
    cc::mojom::LayerType type,
    const gfx::Size& bounds,
    int transform_idx,
    int clip_idx,
    int effect_idx,
    int scroll_idx) {
  auto layer = mojom::Layer::New();
  SetLayerId(layer.get(), id);
  SetLayerType(layer.get(), type);
  SetLayerTransformTreeIndex(layer.get(), transform_idx);
  SetLayerClipTreeIndex(layer.get(), clip_idx);
  SetLayerEffectTreeIndex(layer.get(), effect_idx);
  SetLayerScrollTreeIndex(layer.get(), scroll_idx);
  SetLayerBounds(layer.get(), bounds);
  SetLayerExtra(layer.get(), CreateDefaultLayerExtra(type));
  return layer;
}

void LayerContextImplTest::EnsureGeneralProperties(mojom::Layer* layer) {
  if (layer->general_properties) {
    return;
  }
  layer->general_properties = mojom::LayerGeneralProperties::New();
}

void LayerContextImplTest::SetLayerExtra(mojom::Layer* layer,
                                         mojom::LayerExtraPtr extra) {
  EnsureGeneralProperties(layer);
  layer->general_properties->layer_extra = std::move(extra);
}

const mojom::LayerExtra* LayerContextImplTest::GetLayerExtra(
    const mojom::Layer* layer) {
  if (!layer->general_properties) {
    return nullptr;
  }
  return layer->general_properties->layer_extra.get();
}

mojom::LayerExtra* LayerContextImplTest::GetLayerExtra(mojom::Layer* layer) {
  if (!layer->general_properties) {
    return nullptr;
  }
  return layer->general_properties->layer_extra.get();
}

int LayerContextImplTest::GetLayerId(const mojom::Layer* layer) {
  return layer->id;
}

cc::mojom::LayerType LayerContextImplTest::GetLayerType(
    const mojom::Layer* layer) {
  return layer->type;
}

int LayerContextImplTest::GetLayerTransformTreeIndex(
    const mojom::Layer* layer) {
  return layer->transform_tree_index;
}

int LayerContextImplTest::GetLayerClipTreeIndex(const mojom::Layer* layer) {
  return layer->clip_tree_index;
}

int LayerContextImplTest::GetLayerEffectTreeIndex(const mojom::Layer* layer) {
  return layer->effect_tree_index;
}

int LayerContextImplTest::GetLayerScrollTreeIndex(const mojom::Layer* layer) {
  return layer->scroll_tree_index;
}

void LayerContextImplTest::SetLayerId(mojom::Layer* layer, int id) {
  layer->id = id;
}

void LayerContextImplTest::SetLayerType(mojom::Layer* layer,
                                        cc::mojom::LayerType type) {
  layer->type = type;
}

void LayerContextImplTest::SetLayerTransformTreeIndex(
    mojom::Layer* layer,
    int transform_tree_index) {
  layer->transform_tree_index = transform_tree_index;
}

void LayerContextImplTest::SetLayerClipTreeIndex(mojom::Layer* layer,
                                                 int clip_tree_index) {
  layer->clip_tree_index = clip_tree_index;
}

void LayerContextImplTest::SetLayerEffectTreeIndex(mojom::Layer* layer,
                                                   int effect_tree_index) {
  layer->effect_tree_index = effect_tree_index;
}

void LayerContextImplTest::SetLayerScrollTreeIndex(mojom::Layer* layer,
                                                   int scroll_tree_index) {
  layer->scroll_tree_index = scroll_tree_index;
}

void LayerContextImplTest::SetLayerBounds(mojom::Layer* layer,
                                          const gfx::Size& bounds) {
  EnsureGeneralProperties(layer);
  layer->general_properties->bounds = bounds;
}

void LayerContextImplTest::SetLayerContentsOpaque(mojom::Layer* layer,
                                                  bool opaque) {
  EnsureGeneralProperties(layer);
  layer->general_properties->contents_opaque = opaque;
}

void LayerContextImplTest::SetLayerContentsOpaqueForText(mojom::Layer* layer,
                                                         bool opaque) {
  EnsureGeneralProperties(layer);
  layer->general_properties->contents_opaque_for_text = opaque;
}

void LayerContextImplTest::SetLayerSafeOpaqueBackgroundColor(
    mojom::Layer* layer,
    SkColor4f color) {
  EnsureGeneralProperties(layer);
  layer->general_properties->safe_opaque_background_color = color;
}

void LayerContextImplTest::SetLayerBackgroundColor(mojom::Layer* layer,
                                                   SkColor4f color) {
  EnsureGeneralProperties(layer);
  layer->general_properties->background_color = color;
}

void LayerContextImplTest::SetLayerIsDrawable(mojom::Layer* layer,
                                              bool is_drawable) {
  EnsureGeneralProperties(layer);
  layer->general_properties->is_drawable = is_drawable;
}

void LayerContextImplTest::SetLayerHitTestOpaqueness(
    mojom::Layer* layer,
    cc::HitTestOpaqueness opaqueness) {
  EnsureGeneralProperties(layer);
  layer->general_properties->hit_test_opaqueness = opaqueness;
}

void LayerContextImplTest::SetLayerElementId(mojom::Layer* layer,
                                             cc::ElementId element_id) {
  EnsureGeneralProperties(layer);
  layer->general_properties->element_id = element_id;
}

void LayerContextImplTest::SetLayerOffsetToTransformParent(
    mojom::Layer* layer,
    const gfx::Vector2dF& offset) {
  EnsureGeneralProperties(layer);
  layer->general_properties->offset_to_transform_parent = offset;
}

void LayerContextImplTest::SetLayerShouldCheckBackfaceVisibility(
    mojom::Layer* layer,
    bool should_check) {
  EnsureGeneralProperties(layer);
  layer->general_properties->should_check_backface_visibility = should_check;
}

void LayerContextImplTest::SetLayerUpdateRect(mojom::Layer* layer,
                                              const gfx::Rect& rect) {
  EnsureGeneralProperties(layer);
  layer->general_properties->update_rect = rect;
}

void LayerContextImplTest::SetLayerRareProperties(
    mojom::Layer* layer,
    mojom::RarePropertiesPtr rare_properties) {
  EnsureGeneralProperties(layer);
  layer->general_properties->rare_properties = std::move(rare_properties);
}

void LayerContextImplTest::SetLayerPropertyChangedNotFromPropertyTrees(
    mojom::Layer* layer,
    bool changed) {
  EnsureGeneralProperties(layer);
  layer->general_properties->layer_property_changed_not_from_property_trees =
      changed;
}

void LayerContextImplTest::SetLayerPropertyChangedFromPropertyTrees(
    mojom::Layer* layer,
    bool changed) {
  EnsureGeneralProperties(layer);
  layer->general_properties->layer_property_changed_from_property_trees =
      changed;
}

}  // namespace viz
