window_occlusion_tracker.h 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. // Copyright 2017 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef UI_AURA_WINDOW_OCCLUSION_TRACKER_H_
  5. #define UI_AURA_WINDOW_OCCLUSION_TRACKER_H_
  6. #include <memory>
  7. #include <utility>
  8. #include "base/callback.h"
  9. #include "base/containers/flat_map.h"
  10. #include "base/containers/flat_set.h"
  11. #include "base/memory/raw_ptr.h"
  12. #include "base/scoped_multi_source_observation.h"
  13. #include "third_party/skia/include/core/SkRegion.h"
  14. #include "ui/aura/aura_export.h"
  15. #include "ui/aura/window.h"
  16. #include "ui/aura/window_observer.h"
  17. #include "ui/aura/window_tree_host_observer.h"
  18. #include "ui/compositor/layer_animation_observer.h"
  19. struct SkIRect;
  20. namespace gfx {
  21. class Transform;
  22. }
  23. namespace aura {
  24. namespace test {
  25. class WindowOcclusionTrackerTestApi;
  26. }
  27. class WindowOcclusionChangeBuilder;
  28. // Notifies tracked Windows when their occlusion state change.
  29. //
  30. // To start tracking the occlusion state of a Window, call
  31. // aura::Window::TrackOcclusionState()
  32. //
  33. // A Window is occluded if its bounds and transform are not animated and one of
  34. // these conditions is true:
  35. // - The Window is hidden (Window::IsVisible() is true).
  36. // - The bounds of the Window are completely covered by opaque and axis-aligned
  37. // Windows whose bounds and transform are not animated.
  38. // Note that an occluded window may be drawn on the screen by window switching
  39. // features such as "Alt-Tab" or "Overview".
  40. class AURA_EXPORT WindowOcclusionTracker : public ui::LayerAnimationObserver,
  41. public WindowObserver,
  42. public WindowTreeHostObserver {
  43. public:
  44. // Prevents window occlusion state computations within its scope. If an event
  45. // that could cause window occlusion states to change occurs within the scope
  46. // of a ScopedPause, window occlusion state computations are delayed until all
  47. // ScopedPause objects have been destroyed.
  48. class AURA_EXPORT ScopedPause {
  49. public:
  50. ScopedPause();
  51. ScopedPause(const ScopedPause&) = delete;
  52. ScopedPause& operator=(const ScopedPause&) = delete;
  53. ~ScopedPause();
  54. };
  55. // Used to exclude a window and all descendants from occlusion calculation.
  56. // The occlusion state of the window and all descendants is set from the
  57. // the drawn state of the window, *not* based on what windows may be stacked
  58. // above them. Further, ignores the window that is excluded and its
  59. // descendants when computing the occlusion state of other windows in the
  60. // tree.
  61. //
  62. // This is useful for a window being dragged or resized to avoid unnecessary
  63. // occlusion state change triggered by these operation, because the window
  64. // bounds are temporary until it is finished.
  65. //
  66. // Note that this is intended to be used by window manager, such as Ash.
  67. class AURA_EXPORT ScopedExclude : public WindowObserver {
  68. public:
  69. explicit ScopedExclude(Window* window);
  70. ScopedExclude(const ScopedExclude&) = delete;
  71. ScopedExclude& operator=(const ScopedExclude&) = delete;
  72. ~ScopedExclude() override;
  73. Window* window() { return window_; }
  74. private:
  75. // WindowObserver:
  76. void OnWindowDestroying(Window* window) override;
  77. void Shutdown();
  78. raw_ptr<Window> window_;
  79. };
  80. // Forces the occlusion state of a window to VISIBLE regardless of the drawn
  81. // state of the window. Causes the occlusion state of descendants of the
  82. // window that is forced VISIBLE to be computed as if they were in an
  83. // isolated tree with a root that is drawn. Ignores the window that is forced
  84. // VISIBLE and its descendants when computing the occlusion state of other
  85. // windows in the tree.
  86. //
  87. // This function is primarily useful for situations that show the contents of
  88. // a hidden window, such as overview mode on ChromeOS.
  89. class AURA_EXPORT ScopedForceVisible : public WindowObserver {
  90. public:
  91. explicit ScopedForceVisible(Window* window);
  92. ScopedForceVisible(const ScopedForceVisible&) = delete;
  93. ScopedForceVisible& operator=(const ScopedForceVisible&) = delete;
  94. ~ScopedForceVisible() override;
  95. private:
  96. // WindowObserver:
  97. void OnWindowDestroying(Window* window) override;
  98. void Shutdown();
  99. raw_ptr<Window> window_;
  100. };
  101. // Holds occlusion related information for tracked windows.
  102. struct OcclusionData {
  103. // Occlusion state for a tracked window.
  104. Window::OcclusionState occlusion_state = Window::OcclusionState::UNKNOWN;
  105. // Region in root window coordinates that is occluded.
  106. SkRegion occluded_region;
  107. };
  108. WindowOcclusionTracker(const WindowOcclusionTracker&) = delete;
  109. WindowOcclusionTracker& operator=(const WindowOcclusionTracker&) = delete;
  110. // Start tracking the occlusion state of |window|.
  111. void Track(Window* window);
  112. // Compute the occlusion state and occluded region that |window| will have
  113. // once all bounds, transform, opacity, and visibility animations have
  114. // completed. |window| must be a window that has its occlusion state tracked.
  115. OcclusionData ComputeTargetOcclusionForWindow(Window* window);
  116. // Returns true if there are ignored animating windows.
  117. bool HasIgnoredAnimatingWindows() const { return !animated_windows_.empty(); }
  118. // Set a callback to determine whether a window has content to draw in
  119. // addition to layer type check (window layer type != ui::LAYER_NOT_DRAWN).
  120. using WindowHasContentCallback = base::RepeatingCallback<bool(const Window*)>;
  121. void set_window_has_content_callback(WindowHasContentCallback callback) {
  122. window_has_content_callback_ = std::move(callback);
  123. }
  124. // Set the factory to create WindowOcclusionChangeBuilder.
  125. using OcclusionChangeBuilderFactory =
  126. base::RepeatingCallback<std::unique_ptr<WindowOcclusionChangeBuilder>()>;
  127. void set_occlusion_change_builder_factory(
  128. OcclusionChangeBuilderFactory factory) {
  129. occlusion_change_builder_factory_ = std::move(factory);
  130. }
  131. bool IsPaused() const { return num_pause_occlusion_tracking_; }
  132. private:
  133. friend class test::WindowOcclusionTrackerTestApi;
  134. friend class Env;
  135. friend std::unique_ptr<WindowOcclusionTracker>::deleter_type;
  136. struct RootWindowState {
  137. // Number of Windows whose occlusion state is tracked under this root
  138. // Window.
  139. int num_tracked_windows = 0;
  140. // Whether the occlusion state of tracked Windows under this root is stale.
  141. bool dirty = false;
  142. // The occlusion state of the root window's host.
  143. Window::OcclusionState occlusion_state = Window::OcclusionState::UNKNOWN;
  144. SkRegion occluded_region;
  145. };
  146. WindowOcclusionTracker();
  147. ~WindowOcclusionTracker() override;
  148. // Returns true iff the occlusion states in |tracked_windows| match those
  149. // returned by Window::GetOcclusionState().
  150. static bool OcclusionStatesMatch(
  151. const base::flat_map<Window*, OcclusionData>& tracked_windows);
  152. // Recomputes the occlusion state of tracked windows under roots marked as
  153. // dirty in |root_windows_| if there are no active ScopedPause instance.
  154. void MaybeComputeOcclusion();
  155. // Recomputes the occlusion state of |window| and its descendants.
  156. // |parent_transform_relative_to_root| is the transform of |window->parent()|
  157. // relative to the root window. |clipped_bounds| is an optional mask for the
  158. // bounds of |window| and its descendants. |occluded_region| is a region
  159. // covered by windows which are on top of |window|. Returns true if at least
  160. // one window in the hierarchy starting at |window| is NOT_OCCLUDED.
  161. bool RecomputeOcclusionImpl(
  162. Window* window,
  163. const gfx::Transform& parent_transform_relative_to_root,
  164. const SkIRect* clipped_bounds,
  165. SkRegion* occluded_region);
  166. // Returns true if |window| can occlude other windows (e.g. because it is
  167. // not transparent or has opaque regions for occlusion).
  168. // |window| must be visible.
  169. bool VisibleWindowCanOccludeOtherWindows(Window* window) const;
  170. // Returns true if |window| has content.
  171. bool WindowHasContent(Window* window) const;
  172. // Removes windows whose bounds and transform are not animated from
  173. // |animated_windows_|. Marks the root of those windows as dirty.
  174. void CleanupAnimatedWindows();
  175. // If the bounds or transform of |window| are animated and |window| is not in
  176. // |animated_windows_|, adds |window| to |animated_windows_| and returns true.
  177. bool MaybeObserveAnimatedWindow(Window* window);
  178. // Calls SetOccluded() with |is_occluded| as argument for |window| and its
  179. // descendants. |is_parent_visible| is true if the parent is visible.
  180. void SetWindowAndDescendantsAreOccluded(Window* window,
  181. bool is_occluded,
  182. bool is_parent_visible);
  183. // Updates the occlusion state of |window| in |tracked_windows_|, based on
  184. // |is_occluded| and window->IsVisible(). Updates the occluded region of
  185. // |window| using |occluded_region|. No-op if |window| is not in
  186. // |tracked_windows_|.
  187. void SetOccluded(Window* window,
  188. bool is_occluded,
  189. bool is_parent_visible,
  190. const SkRegion& occluded_region);
  191. // Returns true if |window| is in |tracked_windows_|.
  192. bool WindowIsTracked(Window* window) const;
  193. // Returns true if |window| is in |animated_windows_|.
  194. bool WindowIsAnimated(Window* window) const;
  195. // Returns true if |window| is in |excluded_windows_|.
  196. bool WindowIsExcluded(Window* window) const;
  197. // Returns true if |window| is considered visible. Use this over IsVisible()
  198. // to ensure forced visible windows are considered.
  199. bool WindowIsVisible(Window* window) const;
  200. // Returns true if |window| is forced visible. This does *not* recurse and
  201. // only checks |window|. Use WindowIsVisible() to consider parents.
  202. bool WindowIsForcedVisible(Window* window) const;
  203. // If the root of |window| is not dirty and |predicate| is true, marks the
  204. // root of |window| as dirty. Then, calls MaybeComputeOcclusion().
  205. // |predicate| is not evaluated if the root of |window| is already dirty when
  206. // this is called.
  207. template <typename Predicate>
  208. void MarkRootWindowAsDirtyAndMaybeComputeOcclusionIf(Window* window,
  209. Predicate predicate);
  210. // Marks |root_window_state| as dirty.
  211. void MarkRootWindowStateAsDirty(RootWindowState* root_window_state);
  212. // Marks |root_window| as dirty. Returns false if none of the descendent
  213. // windows in |root_window| are tracked.
  214. bool MarkRootWindowAsDirty(Window* root_window);
  215. // Returns true if |window| or one of its parents is in |animated_windows_|.
  216. bool WindowOrParentIsAnimated(Window* window) const;
  217. // Returns true if |window| or one of its descendants is in
  218. // |tracked_windows_| and visible.
  219. bool WindowOrDescendantIsTrackedAndVisible(Window* window) const;
  220. // Returns true if |window| or one of its descendants is visible, has some
  221. // opaque region and is not in |animated_windows_|. If |assume_parent_opaque|
  222. // is true, the function assumes that the combined opacity of window->parent()
  223. // is 1.0f. If |assume_window_opaque|, the function assumes that the opacity
  224. // of |window| is 1.0f.
  225. bool WindowOrDescendantCanOccludeOtherWindows(
  226. Window* window,
  227. bool assume_parent_opaque = false,
  228. bool assume_window_opaque = false) const;
  229. // Returns true if changing the opacity or alpha state of |window| could
  230. // affect the occlusion state of a tracked window.
  231. bool WindowOpacityChangeMayAffectOcclusionStates(Window* window) const;
  232. // Returns true if changing the transform, bounds or stacking order of
  233. // |window| could affect the occlusion state of a tracked window.
  234. bool WindowMoveMayAffectOcclusionStates(Window* window) const;
  235. // Called when a tracked |window| is added to a root window.
  236. void TrackedWindowAddedToRoot(Window* window);
  237. // Called when a tracked |window| is removed from a root window.
  238. void TrackedWindowRemovedFromRoot(Window* window);
  239. // Removes |this| from the observer list of |window| and its descendants,
  240. // except if they are in |tracked_windows_| or |windows_being_destroyed_|.
  241. void RemoveObserverFromWindowAndDescendants(Window* window);
  242. // Add |this| to the observer list of |window| and its descendants.
  243. void AddObserverToWindowAndDescendants(Window* window);
  244. // Pauses/unpauses the occlusion state computation.
  245. void Pause();
  246. void Unpause();
  247. // Exclude/Unexclude a window from occlusion tracking. See comment on
  248. // ScopedExclude.
  249. void Exclude(Window* window);
  250. void Unexclude(Window* window);
  251. // Called from ScopedForceVisible.
  252. void ForceWindowVisible(Window* window);
  253. void RemoveForceWindowVisible(Window* window);
  254. // Returns true if the occlusion tracker should use target bounds, opacity
  255. // transform, and visibility for occlusion computation. This will be true
  256. // if the target occlusion state of a window is being computed via
  257. // |ComputeTargetOcclusionForWindow|.
  258. bool ShouldUseTargetValues() const;
  259. // ui::LayerAnimationObserver:
  260. void OnLayerAnimationEnded(ui::LayerAnimationSequence* sequence) override;
  261. void OnLayerAnimationAborted(ui::LayerAnimationSequence* sequence) override;
  262. void OnLayerAnimationScheduled(ui::LayerAnimationSequence* sequence) override;
  263. // WindowObserver:
  264. void OnWindowHierarchyChanged(const HierarchyChangeParams& params) override;
  265. void OnWindowAdded(Window* window) override;
  266. void OnWillRemoveWindow(Window* window) override;
  267. void OnWindowVisibilityChanged(Window* window, bool visible) override;
  268. void OnWindowBoundsChanged(Window* window,
  269. const gfx::Rect& old_bounds,
  270. const gfx::Rect& new_bounds,
  271. ui::PropertyChangeReason reason) override;
  272. void OnWindowOpacitySet(Window* window,
  273. ui::PropertyChangeReason reason) override;
  274. void OnWindowAlphaShapeSet(Window* window) override;
  275. void OnWindowTransparentChanged(Window* window,
  276. ui::PropertyChangeReason reason) override;
  277. void OnWindowTransformed(Window* window,
  278. ui::PropertyChangeReason reason) override;
  279. void OnWindowStackingChanged(Window* window) override;
  280. void OnWindowDestroyed(Window* window) override;
  281. void OnWindowAddedToRootWindow(Window* window) override;
  282. void OnWindowRemovingFromRootWindow(Window* window,
  283. Window* new_root) override;
  284. void OnWindowLayerRecreated(Window* window) override;
  285. void OnWindowOpaqueRegionsForOcclusionChanged(Window* window) override;
  286. // WindowTreeHostObserver
  287. void OnOcclusionStateChanged(WindowTreeHost* host,
  288. Window::OcclusionState new_state,
  289. const SkRegion& occluded_region) override;
  290. // Windows whose occlusion data is tracked.
  291. base::flat_map<Window*, OcclusionData> tracked_windows_;
  292. // Windows whose target visibility is forced to true.
  293. base::flat_map<Window*, size_t> forced_visible_count_map_;
  294. // Windows whose bounds or transform are animated.
  295. //
  296. // To reduce the overhead of the WindowOcclusionTracker, windows in this set
  297. // and their descendants are considered non-occluded and cannot occlude other
  298. // windows. A window is added to this set the first time that occlusion is
  299. // computed after it was animated. It is removed when the animation ends or is
  300. // aborted.
  301. base::flat_set<Window*> animated_windows_;
  302. // Windows that are excluded from occlustion tracking. See comment on
  303. // ScopedExclude.
  304. base::flat_set<Window*> excluded_windows_;
  305. // Root Windows of Windows in |tracked_windows_|.
  306. base::flat_map<Window*, RootWindowState> root_windows_;
  307. // Number of times that occlusion has been recomputed in this process. We keep
  308. // track of this for tests.
  309. int num_times_occlusion_recomputed_ = 0;
  310. // Number of times that the current call to MaybeComputeOcclusion() has
  311. // recomputed occlusion states. Always 0 when not in MaybeComputeOcclusion().
  312. int num_times_occlusion_recomputed_in_current_step_ = 0;
  313. // Counter of the current occlusion tracking pause.
  314. int num_pause_occlusion_tracking_ = 0;
  315. // Tracks the observed windows.
  316. base::ScopedMultiSourceObservation<Window, WindowObserver>
  317. window_observations_{this};
  318. // Callback to be invoked for additional window has content check.
  319. WindowHasContentCallback window_has_content_callback_;
  320. // Optional factory to create occlusion change builder.
  321. OcclusionChangeBuilderFactory occlusion_change_builder_factory_;
  322. // Stores the window for which the occlusion tracker is computing the
  323. // occlusion based on target bounds, opacity, transform, and visibility
  324. // values. If the occlusion tracker is not computing for a specific window
  325. // (most of the time it is not), this will be nullptr.
  326. Window* target_occlusion_window_ = nullptr;
  327. };
  328. } // namespace aura
  329. #endif // UI_AURA_WINDOW_OCCLUSION_TRACKER_H_