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/display.h"
16 #include "ui/gfx/geometry/point.h"
17 #include "ui/gfx/geometry/rect.h"
18 #include "ui/gfx/geometry/size_conversions.h"
19 #include "ui/wm/core/coordinate_conversion.h"
21 #if defined(OS_CHROMEOS)
22 #include "base/sys_info.h"
28 // List of value UI Scale values. Scales for 2x are equivalent to 640,
29 // 800, 1024, 1280, 1440, 1600 and 1920 pixel width respectively on
30 // 2560 pixel width 2x density display. Please see crbug.com/233375
31 // for the full list of resolutions.
32 const float kUIScalesFor2x
[] =
33 {0.5f
, 0.625f
, 0.8f
, 1.0f
, 1.125f
, 1.25f
, 1.5f
, 2.0f
};
34 const float kUIScalesFor1_25x
[] = {0.5f
, 0.625f
, 0.8f
, 1.0f
, 1.25f
};
35 const float kUIScalesFor1280
[] = {0.5f
, 0.625f
, 0.8f
, 1.0f
, 1.125f
};
36 const float kUIScalesFor1366
[] = {0.5f
, 0.6f
, 0.75f
, 1.0f
, 1.125f
};
38 std::vector
<float> GetScalesForDisplay(const DisplayMode
& native_mode
) {
39 #define ASSIGN_ARRAY(v, a) v.assign(a, a + arraysize(a))
41 std::vector
<float> ret
;
42 if (native_mode
.device_scale_factor
== 2.0f
) {
43 ASSIGN_ARRAY(ret
, kUIScalesFor2x
);
45 } else if (native_mode
.device_scale_factor
== 1.25f
) {
46 ASSIGN_ARRAY(ret
, kUIScalesFor1_25x
);
49 switch (native_mode
.size
.width()) {
51 ASSIGN_ARRAY(ret
, kUIScalesFor1280
);
54 ASSIGN_ARRAY(ret
, kUIScalesFor1366
);
57 ASSIGN_ARRAY(ret
, kUIScalesFor1280
);
58 #if defined(OS_CHROMEOS)
59 if (base::SysInfo::IsRunningOnChromeOS())
60 NOTREACHED() << "Unknown resolution:" << native_mode
.size
.ToString();
66 struct ScaleComparator
{
67 explicit ScaleComparator(float s
) : scale(s
) {}
69 bool operator()(const DisplayMode
& mode
) const {
70 const float kEpsilon
= 0.0001f
;
71 return std::abs(scale
- mode
.ui_scale
) < kEpsilon
;
76 void ConvertPointFromScreenToNative(aura::WindowTreeHost
* host
,
78 ::wm::ConvertPointFromScreen(host
->window(), point
);
79 host
->ConvertPointToNativeScreen(point
);
82 bool GetDisplayModeForUIScale(const DisplayInfo
& info
,
85 const std::vector
<DisplayMode
>& modes
= info
.display_modes();
86 auto iter
= std::find_if(modes
.begin(), modes
.end(),
87 [ui_scale
](const DisplayMode
& mode
) {
88 return mode
.ui_scale
== ui_scale
;
90 if (iter
== modes
.end())
96 void FindNextMode(std::vector
<DisplayMode
>::const_iterator
& iter
,
97 const std::vector
<DisplayMode
>& modes
,
100 DCHECK(iter
!= modes
.end());
101 if (up
&& (iter
+ 1) != modes
.end())
103 else if (!up
&& iter
!= modes
.begin())
111 std::vector
<DisplayMode
> CreateInternalDisplayModeList(
112 const DisplayMode
& native_mode
) {
113 std::vector
<DisplayMode
> display_mode_list
;
115 float native_ui_scale
= (native_mode
.device_scale_factor
== 1.25f
)
117 : native_mode
.device_scale_factor
;
118 for (float ui_scale
: GetScalesForDisplay(native_mode
)) {
119 DisplayMode mode
= native_mode
;
120 mode
.ui_scale
= ui_scale
;
121 mode
.native
= (ui_scale
== native_ui_scale
);
122 display_mode_list
.push_back(mode
);
124 return display_mode_list
;
127 std::vector
<DisplayMode
> CreateUnifiedDisplayModeList(
128 const DisplayMode
& native_mode
,
129 const std::set
<std::pair
<float, float>>& dsf_scale_list
) {
130 std::vector
<DisplayMode
> display_mode_list
;
132 for (auto& pair
: dsf_scale_list
) {
133 DisplayMode mode
= native_mode
;
134 mode
.device_scale_factor
= pair
.first
;
135 gfx::SizeF
scaled_size(native_mode
.size
);
136 scaled_size
.Scale(pair
.second
);
137 mode
.size
= gfx::ToFlooredSize(scaled_size
);
139 display_mode_list
.push_back(mode
);
141 // Sort the mode by the size in DIP.
142 std::sort(display_mode_list
.begin(), display_mode_list
.end(),
143 [](const DisplayMode
& a
, const DisplayMode
& b
) {
144 return a
.GetSizeInDIP(false).GetArea() <
145 b
.GetSizeInDIP(false).GetArea();
147 return display_mode_list
;
150 bool GetDisplayModeForResolution(const DisplayInfo
& info
,
151 const gfx::Size
& resolution
,
153 if (gfx::Display::IsInternalDisplayId(info
.id()))
156 const std::vector
<DisplayMode
>& modes
= info
.display_modes();
157 DCHECK_NE(0u, modes
.size());
158 DisplayMode target_mode
;
159 target_mode
.size
= resolution
;
160 std::vector
<DisplayMode
>::const_iterator iter
= std::find_if(
161 modes
.begin(), modes
.end(), [resolution
](const DisplayMode
& mode
) {
162 return mode
.size
== resolution
;
164 if (iter
== modes
.end()) {
165 LOG(WARNING
) << "Unsupported resolution was requested:"
166 << resolution
.ToString();
173 bool GetDisplayModeForNextUIScale(const DisplayInfo
& info
,
176 if (!gfx::Display::IsInternalDisplayId(info
.id()))
178 const std::vector
<DisplayMode
>& modes
= info
.display_modes();
179 ScaleComparator
comparator(info
.configured_ui_scale());
180 auto iter
= std::find_if(modes
.begin(), modes
.end(), comparator
);
181 FindNextMode(iter
, modes
, up
, out
);
185 bool GetDisplayModeForNextResolution(const DisplayInfo
& info
,
188 if (gfx::Display::IsInternalDisplayId(info
.id()))
190 const std::vector
<DisplayMode
>& modes
= info
.display_modes();
191 DisplayMode
tmp(info
.size_in_pixel(), 0.0f
, false, false);
192 tmp
.device_scale_factor
= info
.device_scale_factor();
193 gfx::Size resolution
= tmp
.GetSizeInDIP(false);
194 auto iter
= std::find_if(modes
.begin(), modes
.end(),
195 [resolution
](const DisplayMode
& mode
) {
196 return mode
.GetSizeInDIP(false) == resolution
;
198 FindNextMode(iter
, modes
, up
, out
);
202 bool SetDisplayUIScale(int64 id
, float ui_scale
) {
203 DisplayManager
* display_manager
= Shell::GetInstance()->display_manager();
204 const DisplayInfo
& info
= display_manager
->GetDisplayInfo(id
);
206 if (!GetDisplayModeForUIScale(info
, ui_scale
, &mode
))
208 return display_manager
->SetDisplayMode(id
, mode
);
211 bool HasDisplayModeForUIScale(const DisplayInfo
& info
, float ui_scale
) {
212 ScaleComparator
comparator(ui_scale
);
213 const std::vector
<DisplayMode
>& modes
= info
.display_modes();
214 return std::find_if(modes
.begin(), modes
.end(), comparator
) != modes
.end();
217 void ComputeBoundary(const gfx::Display
& primary_display
,
218 const gfx::Display
& secondary_display
,
219 DisplayLayout::Position position
,
220 gfx::Rect
* primary_edge_in_screen
,
221 gfx::Rect
* secondary_edge_in_screen
) {
222 const gfx::Rect
& primary
= primary_display
.bounds();
223 const gfx::Rect
& secondary
= secondary_display
.bounds();
225 case DisplayLayout::TOP
:
226 case DisplayLayout::BOTTOM
: {
227 int left
= std::max(primary
.x(), secondary
.x());
228 int right
= std::min(primary
.right(), secondary
.right());
229 if (position
== DisplayLayout::TOP
) {
230 primary_edge_in_screen
->SetRect(left
, primary
.y(), right
- left
, 1);
231 secondary_edge_in_screen
->SetRect(left
, secondary
.bottom() - 1,
234 primary_edge_in_screen
->SetRect(left
, primary
.bottom() - 1,
236 secondary_edge_in_screen
->SetRect(left
, secondary
.y(), right
- left
, 1);
240 case DisplayLayout::LEFT
:
241 case DisplayLayout::RIGHT
: {
242 int top
= std::max(primary
.y(), secondary
.y());
243 int bottom
= std::min(primary
.bottom(), secondary
.bottom());
244 if (position
== DisplayLayout::LEFT
) {
245 primary_edge_in_screen
->SetRect(primary
.x(), top
, 1, bottom
- top
);
246 secondary_edge_in_screen
->SetRect(secondary
.right() - 1, top
, 1,
249 primary_edge_in_screen
->SetRect(primary
.right() - 1, top
, 1,
251 secondary_edge_in_screen
->SetRect(secondary
.y(), top
, 1, bottom
- top
);
258 gfx::Rect
GetNativeEdgeBounds(AshWindowTreeHost
* ash_host
,
259 const gfx::Rect
& bounds_in_screen
) {
260 aura::WindowTreeHost
* host
= ash_host
->AsWindowTreeHost();
261 gfx::Rect native_bounds
= host
->GetBounds();
262 native_bounds
.Inset(ash_host
->GetHostInsets());
263 gfx::Point start_in_native
= bounds_in_screen
.origin();
264 gfx::Point end_in_native
= bounds_in_screen
.bottom_right();
266 ConvertPointFromScreenToNative(host
, &start_in_native
);
267 ConvertPointFromScreenToNative(host
, &end_in_native
);
269 if (std::abs(start_in_native
.x() - end_in_native
.x()) <
270 std::abs(start_in_native
.y() - end_in_native
.y())) {
271 // vertical in native
272 int x
= std::abs(native_bounds
.x() - start_in_native
.x()) <
273 std::abs(native_bounds
.right() - start_in_native
.x())
275 : native_bounds
.right() - 1;
276 return gfx::Rect(x
, std::min(start_in_native
.y(), end_in_native
.y()), 1,
277 std::abs(end_in_native
.y() - start_in_native
.y()));
279 // horizontal in native
280 int y
= std::abs(native_bounds
.y() - start_in_native
.y()) <
281 std::abs(native_bounds
.bottom() - start_in_native
.y())
283 : native_bounds
.bottom() - 1;
284 return gfx::Rect(std::min(start_in_native
.x(), end_in_native
.x()), y
,
285 std::abs(end_in_native
.x() - start_in_native
.x()), 1);
289 // Moves the cursor to the point inside the root that is closest to
290 // the point_in_screen, which is outside of the root window.
291 void MoveCursorTo(AshWindowTreeHost
* ash_host
,
292 const gfx::Point
& point_in_screen
,
293 bool update_last_location_now
) {
294 aura::WindowTreeHost
* host
= ash_host
->AsWindowTreeHost();
295 gfx::Point point_in_native
= point_in_screen
;
296 ::wm::ConvertPointFromScreen(host
->window(), &point_in_native
);
297 host
->ConvertPointToNativeScreen(&point_in_native
);
299 // now fit the point inside the native bounds.
300 gfx::Rect native_bounds
= host
->GetBounds();
301 gfx::Point native_origin
= native_bounds
.origin();
302 native_bounds
.Inset(ash_host
->GetHostInsets());
303 // Shrink further so that the mouse doesn't warp on the
304 // edge. The right/bottom needs to be shrink by 2 to subtract
305 // the 1 px from width/height value.
306 native_bounds
.Inset(1, 1, 2, 2);
308 // Ensure that |point_in_native| is inside the |native_bounds|.
309 point_in_native
.SetToMax(native_bounds
.origin());
310 point_in_native
.SetToMin(native_bounds
.bottom_right());
312 gfx::Point point_in_host
= point_in_native
;
314 point_in_host
.Offset(-native_origin
.x(), -native_origin
.y());
315 host
->MoveCursorToHostLocation(point_in_host
);
317 if (update_last_location_now
) {
318 gfx::Point new_point_in_screen
;
319 if (Shell::GetInstance()->display_manager()->IsInUnifiedMode()) {
320 new_point_in_screen
= point_in_host
;
321 // First convert to the unified host.
322 host
->ConvertPointFromHost(&new_point_in_screen
);
323 // Then convert to the unified screen.
324 Shell::GetPrimaryRootWindow()->GetHost()->ConvertPointFromHost(
325 &new_point_in_screen
);
327 new_point_in_screen
= point_in_native
;
328 host
->ConvertPointFromNativeScreen(&new_point_in_screen
);
329 ::wm::ConvertPointToScreen(host
->window(), &new_point_in_screen
);
331 aura::Env::GetInstance()->set_last_mouse_location(new_point_in_screen
);
335 int FindDisplayIndexContainingPoint(const std::vector
<gfx::Display
>& displays
,
336 const gfx::Point
& point_in_screen
) {
337 auto iter
= std::find_if(displays
.begin(), displays
.end(),
338 [point_in_screen
](const gfx::Display
& display
) {
339 return display
.bounds().Contains(point_in_screen
);
341 return iter
== displays
.end() ? -1 : (iter
- displays
.begin());
344 DisplayIdPair
CreateDisplayIdPair(int64 id1
, int64 id2
) {
345 return CompareDisplayIds(id1
, id2
) ? std::make_pair(id1
, id2
)
346 : std::make_pair(id2
, id1
);
349 bool CompareDisplayIds(int64 id1
, int64 id2
) {
351 // Output index is stored in the first 8 bits. See GetDisplayIdFromEDID
352 // in edid_parser.cc.
353 int index_1
= id1
& 0xFF;
354 int index_2
= id2
& 0xFF;
355 DCHECK_NE(index_1
, index_2
) << id1
<< " and " << id2
;
356 return gfx::Display::IsInternalDisplayId(id1
) ||
357 (index_1
< index_2
&& !gfx::Display::IsInternalDisplayId(id2
));