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
ash / wm / raster_scale / raster_scale_controller.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_CONTROLLER_H_
#define ASH_WM_RASTER_SCALE_RASTER_SCALE_CONTROLLER_H_
#include <memory>
#include <vector>
#include "ash/ash_export.h"
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/memory/raw_ptr.h"
#include "base/scoped_multi_source_observation.h"
#include "ui/aura/window.h"
#include "ui/aura/window_observer.h"
namespace ash {
// ScopedPauseRasterScaleUpdates pauses any updates to all windows raster scales
// until it is destructed. Once it is destructed and there are no other
// ScopedPauseRasterScaleUpdates objects, windows that still exist will have
// their raster scales updated if they have changed.
class ASH_EXPORT ScopedPauseRasterScaleUpdates {
public:
ScopedPauseRasterScaleUpdates();
ScopedPauseRasterScaleUpdates(const ScopedPauseRasterScaleUpdates&) = delete;
ScopedPauseRasterScaleUpdates& operator=(
const ScopedPauseRasterScaleUpdates&) = delete;
~ScopedPauseRasterScaleUpdates();
};
// ScopedSetRasterScale keeps the raster scale property of the given window
// at or above the given value while in scope. This is necessary because,
// for example, if a window is shown both in overview mode and virtual desks
// preview, we don't want to reduce its raster scale to the tiny preview
// for the virtual desks preview. Instead, we want to use the raster scale
// for the largest preview of the window currently visible.
class ASH_EXPORT ScopedSetRasterScale : public aura::WindowObserver {
public:
ScopedSetRasterScale(aura::Window* window, float raster_scale);
ScopedSetRasterScale(const ScopedSetRasterScale&) = delete;
ScopedSetRasterScale& operator=(const ScopedSetRasterScale&) = delete;
~ScopedSetRasterScale() override;
float raster_scale() const { return raster_scale_; }
void UpdateScale(float raster_scale);
static void SetOrUpdateRasterScale(aura::Window* window,
float raster_scale,
std::unique_ptr<ScopedSetRasterScale>* p);
private:
void Shutdown();
// aura::WindowObserver:
void OnWindowDestroying(aura::Window* window) override;
raw_ptr<aura::Window> window_;
float raster_scale_;
};
// RasterScaleController keeps track of a list of raster scales for each window.
// It is necessary to do this, because we always want to raster each window at
// the largest scale it needs to be displayed at. For example, if a window is
// displayed in overview mode and previewed in a virtual desk, both of those may
// want different scale factors. But, since the window is displayed larger in
// overview mode, we want to make sure to raster it at the higher scale to avoid
// blurriness.
class ASH_EXPORT RasterScaleController : public aura::WindowObserver {
public:
RasterScaleController();
RasterScaleController(const RasterScaleController&) = delete;
RasterScaleController& operator=(const RasterScaleController&) = delete;
~RasterScaleController() override;
// With raster slop (see comment on `raster_scale_slop_`), there is degenerate
// exponential updating behaviour as raster scale tends towards 0. The
// `kMinimumRasterScale` value denotes a minimum value for raster scale. This
// is set such that the largest windows we expect (e.g. on 4k displays) can
// still have their raster scales reduced down so the width and height of
// their buffers is on the order of a few hundred pixels at most.
static inline constexpr float kMinimumRasterScale = 0.05;
// Computes the appropriate raster scale given a transform. Normally we expect
// x and y scaling to be the same, but in case they are not, this takes the
// larger of the two as the raster scale, to make sure that the scale along
// that axis is rasterised at a high enough scale.
static float RasterScaleFromTransform(const gfx::Transform& transform);
// Adds a raster scale to be tracked for a window. The kRasterScale property
// for this window will be set to the largest raster scale currently active,
// or 1.0 if there are no raster scales active.
//
// N.B. This relies on float equality. Currently, this is okay because all
// usages of this are from ScopedSetRasterScale which uses the same float
// value for push and pop. We will need to change the design if raster_scale
// is being recomputed between the push and pop.
void PushRasterScale(aura::Window* window, float raster_scale);
void PopRasterScale(aura::Window* window, float raster_scale);
float ComputeRasterScaleForWindow(aura::Window* window);
float raster_scale_slop_proportion() const {
return raster_scale_slop_proportion_;
}
void set_raster_scale_slop_proportion_for_testing(
float raster_scale_slop_proportion) {
raster_scale_slop_proportion_ = raster_scale_slop_proportion;
}
private:
friend class ScopedPauseRasterScaleUpdates;
void Pause();
void Unpause();
void MaybeSetRasterScale(aura::Window* window);
// aura::WindowObserver:
void OnWindowDestroying(aura::Window* window) override;
int pause_count_ = 0;
base::flat_map<aura::Window*, std::vector<float>> window_scales_;
// Holds a set of windows that have had their raster scales change while
// RasterScaleController is paused.
base::flat_set<raw_ptr<aura::Window, CtnExperimental>> pending_windows_;
// Raster scale won't be updated for a window unless the currently requested
// raster scale is more than `raster_scale_slop_proportion_` different by
// proportion to the currently set (via the raster scale window property)
// value. As a special case, requesting the raster scale to 1.0 will always
// update the raster scale window property. This is to prevent windows from
// getting stuck in non-1.0f raster scales when all `ScopedSetRasterScale`s
// are released. This value was determined by eyeballing the sharpness at a
// reduced raster scale. Once the difference in raster scale proportion starts
// exceeding around 15%, it starts becoming noticeable. Set this to 10% as a
// safe value.
float raster_scale_slop_proportion_ = 0.1;
base::ScopedMultiSourceObservation<aura::Window, aura::WindowObserver>
windows_observation_{this};
};
} // namespace ash
#endif // ASH_WM_RASTER_SCALE_RASTER_SCALE_CONTROLLER_H_