1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169

ash / wm / raster_scale / raster_scale_layer_observer.h [blame]

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