chromium/ash/style/system_shadow.h

// 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.

#ifndef ASH_STYLE_SYSTEM_SHADOW_H_
#define ASH_STYLE_SYSTEM_SHADOW_H_

#include "ash/ash_export.h"
#include "ui/color/color_provider_source_observer.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rounded_corners_f.h"
#include "ui/gfx/shadow_value.h"

namespace aura {
class Window;
}  // namespace aura

namespace ui {
class ColorProvider;
class Layer;
}  // namespace ui

namespace views {
class View;
}  // namespace views

namespace ash {

// SystemShadow is an interface to generate shadow with system shadow style for
// different types of UI surfaces.
class ASH_EXPORT SystemShadow : public ui::ColorProviderSourceObserver {
 public:
  // Shadow types of system UI components. The shadows with different elevations
  // have different appearance.
  enum class Type {
    kElevation4,   // corresponds to cros.sys.system-elevation1.
    kElevation12,  // corresponds to cros.sys.system-elevation3.
    kElevation24,  // corresponds to cros.sys.system-elevation5.
  };

  using LayerRecreatedCallback =
      base::RepeatingCallback<void(ui::Layer* /*old_layer*/,
                                   ui::Layer* /*new_layer*/)>;

  ~SystemShadow() override;

  // Create a system shadow based on `ui::Shadow` which paints shadow on a nine
  // patch layer. This shadow can be used for any UI surfaces. Usually, when
  // creating the shadow for a window, attach the shadow's layer at the bottom
  // of the window's layer; when creating the shadow for a view, attach the
  // shadow's layer at the bottom of the view's parent layer. The layer's
  // content bounds should be manually updated.
  static std::unique_ptr<SystemShadow> CreateShadowOnNinePatchLayer(
      Type shadow_type,
      const LayerRecreatedCallback& layer_recreated_callback);

  // Create a system shadow based on `ash::ViewShadow`. This shadow is used for
  // views. The shadow's layer is added to the `layers_beneath_` of the view and
  // its content bounds are adjusted with the bounds of view's layer. The shadow
  // does not need to manually update the content bounds but cannot be used when
  // the shadow's content bounds do not equal to the view bounds. For example,
  // `AppListFolderView` has a clip rect whose bounds should be the content
  // bounds of the shadow. In this case, please use
  // `CreateShadowOnNinePatchLayer` instead.
  static std::unique_ptr<SystemShadow> CreateShadowOnNinePatchLayerForView(
      views::View* view,
      Type shadow_type);

  // Create a system shadow based on `ui::Shadow`. The shadow's layer is added
  // to the bottom of the window's layer and its contents bounds are adjusted
  // with the window bounds. The shadow does not need to manually update the
  // content bounds but cannot be used when the shadow's contents bounds do not
  // equal to the window bounds. For example, the content bounds of
  // `OverviewItem` for wide and tall windows do not equal to the item bounds.
  // In this case, please use `CreateShadowOnNinePatchLayer` instead.
  static std::unique_ptr<SystemShadow> CreateShadowOnNinePatchLayerForWindow(
      aura::Window* window,
      Type shadow_type);

  // Create a system shadow painted on a texture layer. Painting shadow on a
  // texture layer is expensive so only use it when necessary. See
  // `SystemShadowOnTextureLayer` for more details.
  static std::unique_ptr<SystemShadow> CreateShadowOnTextureLayer(
      Type shadow_type);

  // Get shadow elevation according to the given type.
  static int GetElevationFromType(Type type);

  // Change shadow type and update shadow elevation and appearance. Note that to
  // avoid inconsistency of shadow type and elevation. Always change system
  // shadow elevation with `SetType`.
  virtual void SetType(Type type) = 0;

  virtual void SetContentBounds(const gfx::Rect& bounds) = 0;

  // TODO(http://b/307326019): Deprecate this method when all shadow
  // implementations use `gfx::RoundedCornersF`.
  virtual void SetRoundedCornerRadius(int corner_radius) = 0;

  // TODO(http://b/307326019): This is only used for
  // `SystemShadowOnTextureLayer` for now. Should be applied to
  // `SystemShadowOnNinePatchLayer` when `ui::Shadow` is able to use
  // `gfx::RoundedCornersF`.
  virtual void SetRoundedCorners(
      const gfx::RoundedCornersF& rounded_corners) = 0;

  virtual const gfx::Rect& GetContentBounds() = 0;

  // Return the layer of the shadow. This function can be used by any types of
  // shadow. The layer is commonly used for setting layer hierarchy, visibility,
  // and transformation.
  virtual ui::Layer* GetLayer() = 0;

  // Return the nine patch layer of the shadow. This function is only used by
  // ui::Shadow based implementations. The nine patch layer is a child layer of
  // the shadow's layer painted with the shadow image. Normally, set the
  // hierarchy, visibility and transformation on the shadow's layer instead of
  // the nine patch layer.
  virtual ui::Layer* GetNinePatchLayer() = 0;

  // Return the shadow values of the shadow for testing.
  virtual const gfx::ShadowValues GetShadowValuesForTesting() const = 0;

  // Observe the given color provider source to update the shadow colors.
  void ObserveColorProviderSource(
      ui::ColorProviderSource* color_provider_source);

  // ui::ColorProviderSourceObserver:
  void OnColorProviderChanged() override;

 private:
  // Update shadow colors with given color provider.
  virtual void UpdateShadowColors(const ui::ColorProvider* color_provider) = 0;
};

}  // namespace ash

#endif  // ASH_STYLE_SYSTEM_SHADOW_H_