1 // Copyright 2019 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 
5 #ifndef ASH_WM_COLLISION_DETECTION_COLLISION_DETECTION_UTILS_H_
6 #define ASH_WM_COLLISION_DETECTION_COLLISION_DETECTION_UTILS_H_
7 
8 #include "ash/ash_export.h"
9 #include "ui/aura/window.h"
10 #include "ui/display/display.h"
11 #include "ui/gfx/geometry/rect.h"
12 
13 namespace ash {
14 
15 // The inset into the work area for a window's resting position. Visible for
16 // testing.
17 const static int kCollisionWindowWorkAreaInsetsDp = 8;
18 
19 // Provides utility functions to compute resting positions for windows which
20 // wish to avoid other system windows, for example, the PIP and the Automatic
21 // Clicks bubble menu.
22 class ASH_EXPORT CollisionDetectionUtils {
23  public:
24   enum class Gravity {
25     kGravityLeft,
26     kGravityRight,
27     kGravityTop,
28     kGravityBottom,
29   };
30 
31   // Ordered list of windows which do collision detection. Higher numbers take
32   // higher priority, i.e. the higher RelativePriority of two windows will not
33   // move when the windows are in conflict. For example, the Picture in Picture
34   // window will move out of the way for the Automatic Clicks menu, and both
35   // will move out of the way for the Automatic Clicks scroll menu, and all
36   // will move for default system windows. Windows with the same relative
37   // priority will not affect collision with each other. kDefault is used for
38   // "everything else", and should not be an input to GetRestingPosition or
39   // AvoidObstacles.
40   // TODO(crbug.com/955512): Ensure calculations take place from high to low
41   // priority to reduce number of collision computations.
42   enum class RelativePriority {
43     kPictureInPicture = 0,
44     kSwitchAccessMenu = 1,
45     kAutomaticClicksMenu = 2,
46     kAutomaticClicksScrollMenu = 3,
47     kDefault = 4,
48   };
49 
50   CollisionDetectionUtils() = delete;
51   ~CollisionDetectionUtils() = delete;
52 
53   // Returns the area that the window can be positioned inside for a given
54   // display |display|.
55   static gfx::Rect GetMovementArea(const display::Display& display);
56 
57   // Returns the result of adjusting |bounds_in_screen| according to gravity
58   // inside the movement area of |display| without taking obstacles into
59   // account.
60   static gfx::Rect AdjustToFitMovementAreaByGravity(
61       const display::Display& display,
62       const gfx::Rect& bounds_in_screen);
63 
64   // Returns the position the window should come to rest at. For example,
65   // this will be at a screen edge, not in the middle of the screen.
66   // TODO(edcourtney): This should consider drag velocity for fling as well.
67   static gfx::Rect GetRestingPosition(const display::Display& display,
68                                       const gfx::Rect& bounds_in_screen,
69                                       RelativePriority priority);
70 
71   // Mark a window as ignored for collision detection.
72   static void IgnoreWindowForCollisionDetection(aura::Window* window);
73 
74   // Allows the windows which use CollisionDetectionUtils to mark their relative
75   // priority when they come in position conflict.
76   static void MarkWindowPriorityForCollisionDetection(
77       aura::Window* window,
78       RelativePriority priority);
79 
80   // Moves |bounds| such that it does not intersect with system ui areas, such
81   // as the unified system tray or the floating keyboard.
82   static gfx::Rect AvoidObstacles(const display::Display& display,
83                                   const gfx::Rect& bounds_in_screen,
84                                   RelativePriority priority);
85 
86   // Returns the result of adjusting |bounds| according to |gravity| inside
87   // |region|.
88   static gfx::Rect GetAdjustedBoundsByGravity(const gfx::Rect& bounds,
89                                               const gfx::Rect& region,
90                                               Gravity gravity);
91 
92   // Returns the gravity that would make |bounds| fall to the closest edge of
93   // |region|. If |bounds| is outside of |region| then it will return the
94   // gravity as if |bounds| had fallen outside of |region|. See the below
95   // diagram for what the gravity regions look like for a point.
96   //  \  TOP /
97   //   \____/ R
98   // L |\  /| I
99   // E | \/ | G
100   // F | /\ | H
101   // T |/__\| T
102   //   /    \
103   //  /BOTTOM
104   static Gravity GetGravityToClosestEdge(const gfx::Rect& bounds,
105                                          const gfx::Rect& region);
106 
107  private:
108   friend class CollisionDetectionUtilsDisplayTest;
109   friend class CollisionDetectionUtilsLogicTest;
110 
111   // Internal method for collision resolution. Returns a gfx::Rect with the
112   // same size as |bounds|. That rectangle will not intersect any of the
113   // rectangles in |rects| and will be completely inside |work_area|. If such a
114   // rectangle does not exist, returns |bounds|. Otherwise, it will be the
115   // closest such rectangle to |bounds|.
116   static gfx::Rect AvoidObstaclesInternal(const gfx::Rect& work_area,
117                                           const std::vector<gfx::Rect>& rects,
118                                           const gfx::Rect& bounds_in_screen,
119                                           RelativePriority priority);
120 
121   DISALLOW_COPY_AND_ASSIGN(CollisionDetectionUtils);
122 };
123 
124 }  // namespace ash
125 
126 #endif  // ASH_WM_COLLISION_DETECTION_COLLISION_DETECTION_UTILS_H_
127