chromium/ash/style/system_shadow_on_texture_layer.cc

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

#include "ash/style/system_shadow_on_texture_layer.h"

#include "ash/style/style_util.h"
#include "ui/color/color_provider.h"
#include "ui/compositor/paint_recorder.h"
#include "ui/gfx/skia_paint_util.h"

namespace ash {

SystemShadowOnTextureLayer::SystemShadowOnTextureLayer(SystemShadow::Type type)
    : type_(type),
      shadow_values_(gfx::ShadowValue::MakeChromeOSSystemUIShadowValues(
          SystemShadow::GetElevationFromType(type))) {
  layer_.SetFillsBoundsOpaquely(false);
  layer_.set_delegate(this);
  layer_.SetBounds(GetLayerBounds());
}

SystemShadowOnTextureLayer::~SystemShadowOnTextureLayer() = default;

void SystemShadowOnTextureLayer::SetType(SystemShadow::Type type) {
  type_ = type;
  UpdateShadowValues();
  UpdateLayer();
}

void SystemShadowOnTextureLayer::SetContentBounds(const gfx::Rect& bounds) {
  content_bounds_ = bounds;
  layer_.SetBounds(GetLayerBounds());
  UpdateLayer();
}

void SystemShadowOnTextureLayer::SetRoundedCornerRadius(int corner_radius) {
  SetRoundedCorners(gfx::RoundedCornersF(corner_radius));
}

void SystemShadowOnTextureLayer::SetRoundedCorners(
    const gfx::RoundedCornersF& rounded_corners) {
  if (rounded_corners_ == rounded_corners) {
    return;
  }

  rounded_corners_ = rounded_corners;
  UpdateLayer();
}

const gfx::Rect& SystemShadowOnTextureLayer::GetContentBounds() {
  return content_bounds_;
}

ui::Layer* SystemShadowOnTextureLayer::GetLayer() {
  return &layer_;
}

ui::Layer* SystemShadowOnTextureLayer::GetNinePatchLayer() {
  return nullptr;
}

gfx::Rect SystemShadowOnTextureLayer::GetLayerBounds() const {
  gfx::Rect layer_bounds = content_bounds_;
  layer_bounds.Inset(gfx::ShadowValue::GetMargin(shadow_values_));
  return layer_bounds;
}

const gfx::ShadowValues SystemShadowOnTextureLayer::GetShadowValuesForTesting()
    const {
  return shadow_values_;
}

void SystemShadowOnTextureLayer::UpdateLayer() {
  layer_.SchedulePaint(GetLayerBounds());
}

void SystemShadowOnTextureLayer::UpdateShadowValues() {
  const int elevation = SystemShadow::GetElevationFromType(type_);
  auto iter = colors_map_.find(elevation);
  if (iter == colors_map_.end()) {
    shadow_values_ =
        gfx::ShadowValue::MakeChromeOSSystemUIShadowValues(elevation);
  } else {
    shadow_values_ = gfx::ShadowValue::MakeChromeOSSystemUIShadowValues(
        elevation, /*key_shadow_color=*/iter->second.first,
        /*second_color=*/iter->second.second);
  }
}

void SystemShadowOnTextureLayer::OnPaintLayer(const ui::PaintContext& context) {
  // Create a rounded rect of content area.
  const gfx::Rect r_rect_bounds =
      content_bounds_ - GetLayerBounds().OffsetFromOrigin();
  SkRRect r_rect;
  float upper_left = rounded_corners_.upper_left();
  float upper_right = rounded_corners_.upper_right();
  float lower_right = rounded_corners_.lower_right();
  float lower_left = rounded_corners_.lower_left();
  SkVector radii[4] = {{upper_left, upper_left},
                       {upper_right, upper_right},
                       {lower_right, lower_right},
                       {lower_left, lower_left}};
  r_rect.setRectRadii(gfx::RectToSkRect(r_rect_bounds), radii);

  // Clip out the center.
  ui::PaintRecorder recorder(context, content_bounds_.size());
  recorder.canvas()->sk_canvas()->clipRRect(r_rect, SkClipOp::kDifference,
                                            true);
  // Paint shadow.
  cc::PaintFlags shadow_flags;
  shadow_flags.setAntiAlias(true);
  shadow_flags.setLooper(gfx::CreateShadowDrawLooper(shadow_values_));
  // Due to anti alias, we should fill transparent color to the rounded corner
  // area.
  shadow_flags.setColor(SK_ColorTRANSPARENT);
  recorder.canvas()->sk_canvas()->drawRRect(r_rect, shadow_flags);
}

void SystemShadowOnTextureLayer::OnDeviceScaleFactorChanged(
    float old_device_scale_factor,
    float new_device_scale_factor) {}

void SystemShadowOnTextureLayer::UpdateShadowColors(
    const ui::ColorProvider* color_provider) {
  colors_map_ = StyleUtil::CreateShadowElevationToColorsMap(color_provider);
  UpdateShadowValues();
  UpdateLayer();
}

}  // namespace ash