Updating XTBs based on .GRDs from branch master
[chromium-blink-merge.git] / ash / display / display_util.cc
blob4c4bf7cdd747b05e9c0a6843a18ee4a52c09b2d8
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"
7 #include <algorithm>
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"
23 #endif
25 namespace ash {
26 namespace {
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);
44 return ret;
45 } else if (native_mode.device_scale_factor == 1.25f) {
46 ASSIGN_ARRAY(ret, kUIScalesFor1_25x);
47 return ret;
49 switch (native_mode.size.width()) {
50 case 1280:
51 ASSIGN_ARRAY(ret, kUIScalesFor1280);
52 break;
53 case 1366:
54 ASSIGN_ARRAY(ret, kUIScalesFor1366);
55 break;
56 default:
57 ASSIGN_ARRAY(ret, kUIScalesFor1280);
58 #if defined(OS_CHROMEOS)
59 if (base::SysInfo::IsRunningOnChromeOS())
60 NOTREACHED() << "Unknown resolution:" << native_mode.size.ToString();
61 #endif
63 return ret;
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;
73 float scale;
76 void ConvertPointFromScreenToNative(aura::WindowTreeHost* host,
77 gfx::Point* point) {
78 ::wm::ConvertPointFromScreen(host->window(), point);
79 host->ConvertPointToNativeScreen(point);
82 bool GetDisplayModeForUIScale(const DisplayInfo& info,
83 float ui_scale,
84 DisplayMode* out) {
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;
89 });
90 if (iter == modes.end())
91 return false;
92 *out = *iter;
93 return true;
96 void FindNextMode(std::vector<DisplayMode>::const_iterator& iter,
97 const std::vector<DisplayMode>& modes,
98 bool up,
99 DisplayMode* out) {
100 DCHECK(iter != modes.end());
101 if (up && (iter + 1) != modes.end())
102 *out = *(iter + 1);
103 else if (!up && iter != modes.begin())
104 *out = *(iter - 1);
105 else
106 *out = *iter;
109 } // namespace
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)
116 ? 1.0f
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);
138 mode.native = false;
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,
152 DisplayMode* out) {
153 if (gfx::Display::IsInternalDisplayId(info.id()))
154 return false;
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();
167 return false;
169 *out = *iter;
170 return true;
173 bool GetDisplayModeForNextUIScale(const DisplayInfo& info,
174 bool up,
175 DisplayMode* out) {
176 if (!gfx::Display::IsInternalDisplayId(info.id()))
177 return false;
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);
182 return true;
185 bool GetDisplayModeForNextResolution(const DisplayInfo& info,
186 bool up,
187 DisplayMode* out) {
188 if (gfx::Display::IsInternalDisplayId(info.id()))
189 return false;
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);
199 return true;
202 bool SetDisplayUIScale(int64 id, float ui_scale) {
203 DisplayManager* display_manager = Shell::GetInstance()->display_manager();
204 const DisplayInfo& info = display_manager->GetDisplayInfo(id);
205 DisplayMode mode;
206 if (!GetDisplayModeForUIScale(info, ui_scale, &mode))
207 return false;
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();
224 switch (position) {
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,
232 right - left, 1);
233 } else {
234 primary_edge_in_screen->SetRect(left, primary.bottom() - 1,
235 right - left, 1);
236 secondary_edge_in_screen->SetRect(left, secondary.y(), right - left, 1);
238 break;
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,
247 bottom - top);
248 } else {
249 primary_edge_in_screen->SetRect(primary.right() - 1, top, 1,
250 bottom - top);
251 secondary_edge_in_screen->SetRect(secondary.y(), top, 1, bottom - top);
253 break;
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())
274 ? native_bounds.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()));
278 } else {
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())
282 ? native_bounds.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);
326 } else {
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) {
350 DCHECK_NE(id1, 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));
360 } // namespace ash