1 // Copyright 2014 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.
5 #include "ash/display/display_util.h"
9 #include "ash/display/display_info.h"
10 #include "ash/display/display_manager.h"
11 #include "ash/host/ash_window_tree_host.h"
12 #include "ash/shell.h"
13 #include "ui/aura/env.h"
14 #include "ui/aura/window_tree_host.h"
15 #include "ui/gfx/geometry/point.h"
16 #include "ui/gfx/geometry/rect.h"
17 #include "ui/wm/core/coordinate_conversion.h"
19 #if defined(OS_CHROMEOS)
20 #include "base/sys_info.h"
26 // List of value UI Scale values. Scales for 2x are equivalent to 640,
27 // 800, 1024, 1280, 1440, 1600 and 1920 pixel width respectively on
28 // 2560 pixel width 2x density display. Please see crbug.com/233375
29 // for the full list of resolutions.
30 const float kUIScalesFor2x
[] =
31 {0.5f
, 0.625f
, 0.8f
, 1.0f
, 1.125f
, 1.25f
, 1.5f
, 2.0f
};
32 const float kUIScalesFor1_25x
[] = {0.5f
, 0.625f
, 0.8f
, 1.0f
, 1.25f
};
33 const float kUIScalesFor1280
[] = {0.5f
, 0.625f
, 0.8f
, 1.0f
, 1.125f
};
34 const float kUIScalesFor1366
[] = {0.5f
, 0.6f
, 0.75f
, 1.0f
, 1.125f
};
36 std::vector
<float> GetScalesForDisplay(const DisplayMode
& native_mode
) {
37 #define ASSIGN_ARRAY(v, a) v.assign(a, a + arraysize(a))
39 std::vector
<float> ret
;
40 if (native_mode
.device_scale_factor
== 2.0f
) {
41 ASSIGN_ARRAY(ret
, kUIScalesFor2x
);
43 } else if (native_mode
.device_scale_factor
== 1.25f
) {
44 ASSIGN_ARRAY(ret
, kUIScalesFor1_25x
);
47 switch (native_mode
.size
.width()) {
49 ASSIGN_ARRAY(ret
, kUIScalesFor1280
);
52 ASSIGN_ARRAY(ret
, kUIScalesFor1366
);
55 ASSIGN_ARRAY(ret
, kUIScalesFor1280
);
56 #if defined(OS_CHROMEOS)
57 if (base::SysInfo::IsRunningOnChromeOS())
58 NOTREACHED() << "Unknown resolution:" << native_mode
.size
.ToString();
64 struct ScaleComparator
{
65 explicit ScaleComparator(float s
) : scale(s
) {}
67 bool operator()(const DisplayMode
& mode
) const {
68 const float kEpsilon
= 0.0001f
;
69 return std::abs(scale
- mode
.ui_scale
) < kEpsilon
;
74 void ConvertPointFromScreenToNative(aura::WindowTreeHost
* host
,
76 ::wm::ConvertPointFromScreen(host
->window(), point
);
77 host
->ConvertPointToNativeScreen(point
);
82 std::vector
<DisplayMode
> CreateInternalDisplayModeList(
83 const DisplayMode
& native_mode
) {
84 std::vector
<DisplayMode
> display_mode_list
;
86 float native_ui_scale
= (native_mode
.device_scale_factor
== 1.25f
)
88 : native_mode
.device_scale_factor
;
89 for (float ui_scale
: GetScalesForDisplay(native_mode
)) {
90 DisplayMode mode
= native_mode
;
91 mode
.ui_scale
= ui_scale
;
92 mode
.native
= (ui_scale
== native_ui_scale
);
93 display_mode_list
.push_back(mode
);
95 return display_mode_list
;
98 std::vector
<DisplayMode
> CreateUnifiedDisplayModeList(
99 const DisplayMode
& native_mode
,
100 const std::set
<float>& scales
) {
101 std::vector
<DisplayMode
> display_mode_list
;
103 float native_ui_scale
= native_mode
.device_scale_factor
;
104 for (float ui_scale
: scales
) {
105 DisplayMode mode
= native_mode
;
106 mode
.ui_scale
= ui_scale
;
107 mode
.native
= (ui_scale
== native_ui_scale
);
108 display_mode_list
.push_back(mode
);
110 return display_mode_list
;
114 float GetNextUIScale(const DisplayInfo
& info
, bool up
) {
115 ScaleComparator
comparator(info
.configured_ui_scale());
116 const std::vector
<DisplayMode
>& modes
= info
.display_modes();
117 for (auto iter
= modes
.begin(); iter
!= modes
.end(); ++iter
) {
118 if (comparator(*iter
)) {
119 if (up
&& (iter
+ 1) != modes
.end())
120 return (iter
+ 1)->ui_scale
;
121 if (!up
&& iter
!= modes
.begin())
122 return (iter
- 1)->ui_scale
;
123 return info
.configured_ui_scale();
126 // Fallback to 1.0f if the |scale| wasn't in the list.
130 bool HasDisplayModeForUIScale(const DisplayInfo
& info
, float ui_scale
) {
131 ScaleComparator
comparator(ui_scale
);
132 const std::vector
<DisplayMode
>& modes
= info
.display_modes();
133 return std::find_if(modes
.begin(), modes
.end(), comparator
) != modes
.end();
136 void ComputeBoundary(const gfx::Display
& primary_display
,
137 const gfx::Display
& secondary_display
,
138 DisplayLayout::Position position
,
139 gfx::Rect
* primary_edge_in_screen
,
140 gfx::Rect
* secondary_edge_in_screen
) {
141 const gfx::Rect
& primary
= primary_display
.bounds();
142 const gfx::Rect
& secondary
= secondary_display
.bounds();
144 case DisplayLayout::TOP
:
145 case DisplayLayout::BOTTOM
: {
146 int left
= std::max(primary
.x(), secondary
.x());
147 int right
= std::min(primary
.right(), secondary
.right());
148 if (position
== DisplayLayout::TOP
) {
149 primary_edge_in_screen
->SetRect(left
, primary
.y(), right
- left
, 1);
150 secondary_edge_in_screen
->SetRect(left
, secondary
.bottom() - 1,
153 primary_edge_in_screen
->SetRect(left
, primary
.bottom() - 1,
155 secondary_edge_in_screen
->SetRect(left
, secondary
.y(), right
- left
, 1);
159 case DisplayLayout::LEFT
:
160 case DisplayLayout::RIGHT
: {
161 int top
= std::max(primary
.y(), secondary
.y());
162 int bottom
= std::min(primary
.bottom(), secondary
.bottom());
163 if (position
== DisplayLayout::LEFT
) {
164 primary_edge_in_screen
->SetRect(primary
.x(), top
, 1, bottom
- top
);
165 secondary_edge_in_screen
->SetRect(secondary
.right() - 1, top
, 1,
168 primary_edge_in_screen
->SetRect(primary
.right() - 1, top
, 1,
170 secondary_edge_in_screen
->SetRect(secondary
.y(), top
, 1, bottom
- top
);
177 gfx::Rect
GetNativeEdgeBounds(AshWindowTreeHost
* ash_host
,
178 const gfx::Rect
& bounds_in_screen
) {
179 aura::WindowTreeHost
* host
= ash_host
->AsWindowTreeHost();
180 gfx::Rect native_bounds
= host
->GetBounds();
181 native_bounds
.Inset(ash_host
->GetHostInsets());
182 gfx::Point start_in_native
= bounds_in_screen
.origin();
183 gfx::Point end_in_native
= bounds_in_screen
.bottom_right();
185 ConvertPointFromScreenToNative(host
, &start_in_native
);
186 ConvertPointFromScreenToNative(host
, &end_in_native
);
188 if (std::abs(start_in_native
.x() - end_in_native
.x()) <
189 std::abs(start_in_native
.y() - end_in_native
.y())) {
190 // vertical in native
191 int x
= std::abs(native_bounds
.x() - start_in_native
.x()) <
192 std::abs(native_bounds
.right() - start_in_native
.x())
194 : native_bounds
.right() - 1;
195 return gfx::Rect(x
, std::min(start_in_native
.y(), end_in_native
.y()), 1,
196 std::abs(end_in_native
.y() - start_in_native
.y()));
198 // horizontal in native
199 int y
= std::abs(native_bounds
.y() - start_in_native
.y()) <
200 std::abs(native_bounds
.bottom() - start_in_native
.y())
202 : native_bounds
.bottom() - 1;
203 return gfx::Rect(std::min(start_in_native
.x(), end_in_native
.x()), y
,
204 std::abs(end_in_native
.x() - start_in_native
.x()), 1);
208 // Moves the cursor to the point inside the root that is closest to
209 // the point_in_screen, which is outside of the root window.
210 void MoveCursorTo(AshWindowTreeHost
* ash_host
,
211 const gfx::Point
& point_in_screen
,
212 bool update_last_location_now
) {
213 aura::WindowTreeHost
* host
= ash_host
->AsWindowTreeHost();
214 gfx::Point point_in_native
= point_in_screen
;
215 ::wm::ConvertPointFromScreen(host
->window(), &point_in_native
);
216 host
->ConvertPointToNativeScreen(&point_in_native
);
218 // now fit the point inside the native bounds.
219 gfx::Rect native_bounds
= host
->GetBounds();
220 gfx::Point native_origin
= native_bounds
.origin();
221 native_bounds
.Inset(ash_host
->GetHostInsets());
222 // Shrink further so that the mouse doesn't warp on the
223 // edge. The right/bottom needs to be shrink by 2 to subtract
224 // the 1 px from width/height value.
225 native_bounds
.Inset(1, 1, 2, 2);
227 // Ensure that |point_in_native| is inside the |native_bounds|.
228 point_in_native
.SetToMax(native_bounds
.origin());
229 point_in_native
.SetToMin(native_bounds
.bottom_right());
231 gfx::Point point_in_host
= point_in_native
;
233 point_in_host
.Offset(-native_origin
.x(), -native_origin
.y());
234 host
->MoveCursorToHostLocation(point_in_host
);
236 if (update_last_location_now
) {
237 gfx::Point new_point_in_screen
= point_in_native
;
238 if (Shell::GetInstance()->display_manager()->IsInUnifiedMode()) {
239 // TODO(oshima): Do not use ConvertPointFromNativeScreen because
240 // the mirroring display has a transform that should not be applied here.
241 gfx::Point origin
= host
->GetBounds().origin();
242 new_point_in_screen
.Offset(-origin
.x(), -origin
.y());
244 host
->ConvertPointFromNativeScreen(&new_point_in_screen
);
246 ::wm::ConvertPointToScreen(host
->window(), &new_point_in_screen
);
247 aura::Env::GetInstance()->set_last_mouse_location(new_point_in_screen
);
251 int FindDisplayIndexContainingPoint(const std::vector
<gfx::Display
>& displays
,
252 const gfx::Point
& point_in_screen
) {
253 auto iter
= std::find_if(displays
.begin(), displays
.end(),
254 [point_in_screen
](const gfx::Display
& display
) {
255 return display
.bounds().Contains(point_in_screen
);
257 return iter
== displays
.end() ? -1 : (iter
- displays
.begin());