chromium/ash/wm/raster_scale/raster_scale_layer_observer.h

// Copyright 2023 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_WM_RASTER_SCALE_RASTER_SCALE_LAYER_OBSERVER_H_
#define ASH_WM_RASTER_SCALE_RASTER_SCALE_LAYER_OBSERVER_H_

#include "ash/ash_export.h"
#include "ash/wm/raster_scale/raster_scale_controller.h"
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "ui/aura/client/transient_window_client_observer.h"
#include "ui/aura/window_observer.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_animation_observer.h"
#include "ui/compositor/layer_animator.h"
#include "ui/compositor/layer_observer.h"

namespace ash {
class RasterScaleLayerObserver;
class ScopedSetRasterScale;

// Lock which will prevent `RasterScaleLayerObserver` from deleting itself
// while it is in scope. This is used to decide when to apply raster scale
// semantics, e.g. in overview mode.
class ScopedRasterScaleLayerObserverLock {
 public:
  explicit ScopedRasterScaleLayerObserverLock(
      base::WeakPtr<RasterScaleLayerObserver> observer);

  ScopedRasterScaleLayerObserverLock(ScopedRasterScaleLayerObserverLock&&);
  ScopedRasterScaleLayerObserverLock& operator=(
      ScopedRasterScaleLayerObserverLock&&);

  ScopedRasterScaleLayerObserverLock(
      const ScopedRasterScaleLayerObserverLock&) = delete;
  ScopedRasterScaleLayerObserverLock& operator=(
      const ScopedRasterScaleLayerObserverLock&) = delete;

  ~ScopedRasterScaleLayerObserverLock();

 private:
  base::WeakPtr<RasterScaleLayerObserver> observer_;
};

// This class dynamically updates raster scale based on the scale of the given
// window. The scale is observed by looking at changes in layer animations and
// window properties. This is used, for example, in overview mode to dynamically
// reduce the raster scale of lacros windows. Check the comments on member
// variables of this class for more details.
class RasterScaleLayerObserver
    : public ui::LayerAnimationObserver,
      public aura::WindowObserver,
      public aura::client::TransientWindowClientObserver,
      public ui::LayerObserver {
 public:
  explicit RasterScaleLayerObserver(aura::Window* observe_window,
                                    ui::Layer* observe_layer,
                                    aura::Window* apply_window);

  RasterScaleLayerObserver(const RasterScaleLayerObserver&) = delete;
  RasterScaleLayerObserver& operator=(const RasterScaleLayerObserver&) = delete;

  ~RasterScaleLayerObserver() override;

  ScopedRasterScaleLayerObserverLock Lock() {
    return ScopedRasterScaleLayerObserverLock(weak_ptr_factory_.GetWeakPtr());
  }

  // ui::LayerAnimationObserver
  void OnLayerAnimationStarted(ui::LayerAnimationSequence* sequence) override;

  void OnLayerAnimationEnded(ui::LayerAnimationSequence* sequence) override;

  void OnLayerAnimationWillRepeat(
      ui::LayerAnimationSequence* sequence) override;

  void OnLayerAnimationAborted(ui::LayerAnimationSequence* sequence) override;

  void OnLayerAnimationScheduled(ui::LayerAnimationSequence* sequence) override;

  // aura::WindowObserver:
  void OnWindowVisibilityChanged(aura::Window* window, bool visible) override;

  void OnWindowDestroying(aura::Window* window) override;

  void OnWindowBoundsChanged(aura::Window* window,
                             const gfx::Rect& old_bounds,
                             const gfx::Rect& new_bounds,
                             ui::PropertyChangeReason reason) override;

  void OnWindowTransformed(aura::Window* window,
                           ui::PropertyChangeReason reason) override;

  void OnWindowLayerRecreated(aura::Window* window) override;

  // ui::LayerObserver:
  void LayerDestroyed(ui::Layer* layer) override;

  // aura::client::TransientWindowClientObserver:
  void OnTransientChildWindowAdded(aura::Window* parent,
                                   aura::Window* transient_child) override;
  void OnTransientChildWindowRemoved(aura::Window* parent,
                                     aura::Window* transient_child) override;

 private:
  friend class ScopedRasterScaleLayerObserverLock;

  void SetRasterScales(float raster_scale);

  void UpdateRasterScaleFromTransform(const gfx::Transform& transform);

  void IncrementRefCount();
  void DecrementRefCount();

  //  be careful if this is not the last call in the function.
  void MaybeShutdown();

  // Window to observe window property changes on. This is
  // different to `apply_window_` to handle mirror windows. We want to observe
  // the mirrored window, but apply raster scale changes to the original window.
  raw_ptr<aura::Window> observe_window_ = nullptr;

  // Layer to observe layer animations on. This is not `observe_window_`'s layer
  // in the case of mirrored windows. In that case, it is the mirrored layer,
  // which is not the same as the layer corresponding to `observe_window_`.
  raw_ptr<ui::Layer> observe_layer_ = nullptr;

  // Window to apply raster scale changes to. This is the same as
  // `observe_window_` if there is no window mirroring occurring. This should
  // correspond to a window which can update the underlying raster scale for its
  // content.
  raw_ptr<aura::Window> apply_window_ = nullptr;

  // We need to hold onto transient windows to apply the same raster scale to
  // them as the main `apply_window_`, and to unapply them when they are done.
  // The raster scale locks for transient windows are held in `raster_scales_`.
  base::flat_set<raw_ptr<aura::Window, CtnExperimental>> transient_windows_;

  // Holds raster scale locks for windows. This will be `apply_window_` plus any
  // transient children windows.
  base::flat_map<aura::Window*, std::unique_ptr<ScopedSetRasterScale>>
      raster_scales_;

  // `RasterScaleLayerObserver` has complicated lifetime semantics. It will stay
  // alive (not be deleted) until there are no
  // `ScopedRasterScaleLayerObserverLock` locks and there are no animations
  // referencing `observe_layer_`. If neither of these conditions is true, it
  // will delete itself. The reason for the lock so we only create
  // `RasterScaleLayerObserver` when it is necessary (e.g. overview mode) to
  // avoid introducing a long tail of unknown situations to raster scale
  // updates. The reason for counting animations is that animations may continue
  // after locks are destroyed. For example, exiting overview will immediately
  // destroy locks, but we need to keep the raster scales until the animation
  // finishes.
  int animation_count_ = 0;
  int ref_count_ = 0;

  base::ScopedMultiSourceObservation<aura::Window, aura::WindowObserver>
      windows_observation_{this};

  base::WeakPtrFactory<RasterScaleLayerObserver> weak_ptr_factory_{this};
};

}  // namespace ash

#endif  // ASH_WM_RASTER_SCALE_RASTER_SCALE_LAYER_OBSERVER_H_