#include "ash/display/display_manager.h"
+#include <algorithm>
#include <cmath>
#include <set>
#include <string>
#include "ui/base/layout.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/display.h"
+#include "ui/gfx/display_observer.h"
+#include "ui/gfx/font_render_params.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/screen.h"
#include "ui/gfx/size_conversions.h"
// for the full list of resolutions.
const float kUIScalesFor2x[] =
{0.5f, 0.625f, 0.8f, 1.0f, 1.125f, 1.25f, 1.5f, 2.0f};
+const float kUIScalesFor1_25x[] = {0.5f, 0.625f, 0.8f, 1.0f, 1.25f };
const float kUIScalesFor1280[] = {0.5f, 0.625f, 0.8f, 1.0f, 1.125f };
const float kUIScalesFor1366[] = {0.5f, 0.6f, 0.75f, 1.0f, 1.125f };
};
struct DisplayModeMatcher {
- DisplayModeMatcher(const gfx::Size& size) : size(size) {}
- bool operator()(const DisplayMode& mode) { return mode.size == size; }
- gfx::Size size;
+ DisplayModeMatcher(const DisplayMode& target_mode)
+ : target_mode(target_mode) {}
+ bool operator()(const DisplayMode& mode) {
+ return target_mode.IsEquivalent(mode);
+ }
+ DisplayMode target_mode;
};
struct ScaleComparator {
}
DisplayManager::~DisplayManager() {
+#if defined(OS_CHROMEOS)
+ // Reset the font params.
+ gfx::SetFontRenderParamsDeviceScaleFactor(1.0f);
+#endif
}
// static
std::vector<float> DisplayManager::GetScalesForDisplay(
const DisplayInfo& info) {
+
+#define ASSIGN_ARRAY(v, a) v.assign(a, a + arraysize(a))
+
std::vector<float> ret;
if (info.device_scale_factor() == 2.0f) {
- ret.assign(kUIScalesFor2x, kUIScalesFor2x + arraysize(kUIScalesFor2x));
+ ASSIGN_ARRAY(ret, kUIScalesFor2x);
+ return ret;
+ } else if (info.device_scale_factor() == 1.25f) {
+ ASSIGN_ARRAY(ret, kUIScalesFor1_25x);
return ret;
}
switch (info.bounds_in_native().width()) {
case 1280:
- ret.assign(kUIScalesFor1280,
- kUIScalesFor1280 + arraysize(kUIScalesFor1280));
+ ASSIGN_ARRAY(ret, kUIScalesFor1280);
break;
case 1366:
- ret.assign(kUIScalesFor1366,
- kUIScalesFor1366 + arraysize(kUIScalesFor1366));
+ ASSIGN_ARRAY(ret, kUIScalesFor1366);
break;
default:
- ret.assign(kUIScalesFor1280,
- kUIScalesFor1280 + arraysize(kUIScalesFor1280));
+ ASSIGN_ARRAY(ret, kUIScalesFor1280);
#if defined(OS_CHROMEOS)
if (base::SysInfo::IsRunningOnChromeOS())
NOTREACHED() << "Unknown resolution:" << info.ToString();
OnNativeDisplaysChanged(info_list);
}
+void DisplayManager::InitFontParams() {
+#if defined(OS_CHROMEOS)
+ if (!HasInternalDisplay())
+ return;
+ const DisplayInfo& display_info =
+ GetDisplayInfo(gfx::Display::InternalDisplayId());
+ gfx::SetFontRenderParamsDeviceScaleFactor(
+ display_info.device_scale_factor());
+#endif // OS_CHROMEOS
+}
+
// static
void DisplayManager::UpdateDisplayBoundsForLayoutById(
const DisplayLayout& layout,
// Primary's bounds stay the same. Just notify bounds change
// on the secondary.
- screen_ash_->NotifyBoundsChanged(
- ScreenUtil::GetSecondaryDisplay());
+ screen_ash_->NotifyMetricsChanged(
+ ScreenUtil::GetSecondaryDisplay(),
+ gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS |
+ gfx::DisplayObserver::DISPLAY_METRIC_WORK_AREA);
if (delegate_)
delegate_->PostDisplayConfigurationChange();
}
return;
}
+ // TODO(mukai): merge this implementation into SetDisplayMode().
DisplayInfoList display_info_list;
for (DisplayList::const_iterator iter = displays_.begin();
iter != displays_.end(); ++iter) {
const DisplayInfo& display_info = GetDisplayInfo(display_id);
const std::vector<DisplayMode>& modes = display_info.display_modes();
DCHECK_NE(0u, modes.size());
+ DisplayMode target_mode;
+ target_mode.size = resolution;
std::vector<DisplayMode>::const_iterator iter =
- std::find_if(modes.begin(), modes.end(), DisplayModeMatcher(resolution));
+ std::find_if(modes.begin(), modes.end(), DisplayModeMatcher(target_mode));
if (iter == modes.end()) {
LOG(WARNING) << "Unsupported resolution was requested:"
<< resolution.ToString();
#endif
}
+bool DisplayManager::SetDisplayMode(int64 display_id,
+ const DisplayMode& display_mode) {
+ if (IsInternalDisplayId(display_id)) {
+ SetDisplayUIScale(display_id, display_mode.ui_scale);
+ return false;
+ }
+
+ DisplayInfoList display_info_list;
+ bool display_property_changed = false;
+ bool resolution_changed = false;
+ for (DisplayList::const_iterator iter = displays_.begin();
+ iter != displays_.end(); ++iter) {
+ DisplayInfo info = GetDisplayInfo(iter->id());
+ if (info.id() == display_id) {
+ const std::vector<DisplayMode>& modes = info.display_modes();
+ std::vector<DisplayMode>::const_iterator iter =
+ std::find_if(modes.begin(),
+ modes.end(),
+ DisplayModeMatcher(display_mode));
+ if (iter == modes.end()) {
+ LOG(WARNING) << "Unsupported resolution was requested:"
+ << display_mode.size.ToString();
+ return false;
+ }
+ display_modes_[display_id] = *iter;
+ if (info.bounds_in_native().size() != display_mode.size)
+ resolution_changed = true;
+ if (info.device_scale_factor() != display_mode.device_scale_factor) {
+ info.set_device_scale_factor(display_mode.device_scale_factor);
+ display_property_changed = true;
+ }
+ }
+ display_info_list.push_back(info);
+ }
+ if (display_property_changed) {
+ AddMirrorDisplayInfoIfAny(&display_info_list);
+ UpdateDisplays(display_info_list);
+ }
+#if defined(OS_CHROMEOS)
+ if (resolution_changed && base::SysInfo::IsRunningOnChromeOS())
+ Shell::GetInstance()->display_configurator()->OnConfigurationChanged();
+#endif
+ return resolution_changed;
+}
+
void DisplayManager::RegisterDisplayProperty(
int64 display_id,
gfx::Display::Rotation rotation,
float ui_scale,
const gfx::Insets* overscan_insets,
const gfx::Size& resolution_in_pixels,
+ float device_scale_factor,
ui::ColorCalibrationProfile color_profile) {
if (display_info_.find(display_id) == display_info_.end())
display_info_[display_id] = DisplayInfo(display_id, std::string(), false);
display_info_[display_id].set_rotation(rotation);
display_info_[display_id].SetColorProfile(color_profile);
// Just in case the preference file was corrupted.
+ // TODO(mukai): register |display_modes_| here as well, so the lookup for the
+ // default mode in GetActiveModeForDisplayId() gets much simpler.
if (0.5f <= ui_scale && ui_scale <= 2.0f)
display_info_[display_id].set_configured_ui_scale(ui_scale);
if (overscan_insets)
display_info_[display_id].SetOverscanInsets(*overscan_insets);
if (!resolution_in_pixels.IsEmpty()) {
+ DCHECK(!IsInternalDisplayId(display_id));
// Default refresh rate, until OnNativeDisplaysChanged() updates us with the
// actual display info, is 60 Hz.
- display_modes_[display_id] =
- DisplayMode(resolution_in_pixels, 60.0f, false, false);
+ DisplayMode mode(resolution_in_pixels, 60.0f, false, false);
+ mode.device_scale_factor = device_scale_factor;
+ display_modes_[display_id] = mode;
+ }
+}
+
+DisplayMode DisplayManager::GetActiveModeForDisplayId(int64 display_id) const {
+ DisplayMode selected_mode;
+ if (GetSelectedModeForDisplayId(display_id, &selected_mode))
+ return selected_mode;
+
+ // If 'selected' mode is empty, it should return the default mode. This means
+ // the native mode for the external display. Unfortunately this is not true
+ // for the internal display because restoring UI-scale doesn't register the
+ // restored mode to |display_mode_|, so it needs to look up the mode whose
+ // UI-scale value matches. See the TODO in RegisterDisplayProperty().
+ const DisplayInfo& info = GetDisplayInfo(display_id);
+ const std::vector<DisplayMode>& display_modes = info.display_modes();
+
+ if (IsInternalDisplayId(display_id)) {
+ for (size_t i = 0; i < display_modes.size(); ++i) {
+ if (info.configured_ui_scale() == display_modes[i].ui_scale)
+ return display_modes[i];
+ }
+ } else {
+ for (size_t i = 0; i < display_modes.size(); ++i) {
+ if (display_modes[i].native)
+ return display_modes[i];
+ }
}
+ return selected_mode;
}
bool DisplayManager::GetSelectedModeForDisplayId(int64 id,
new_display_info_list.push_back(*iter);
}
- const gfx::Size& resolution = iter->bounds_in_native().size();
+ DisplayMode new_mode;
+ new_mode.size = iter->bounds_in_native().size();
+ new_mode.device_scale_factor = iter->device_scale_factor();
+ new_mode.ui_scale = iter->configured_ui_scale();
const std::vector<DisplayMode>& display_modes = iter->display_modes();
// This is empty the displays are initialized from InitFromCommandLine.
if (!display_modes.size())
std::vector<DisplayMode>::const_iterator display_modes_iter =
std::find_if(display_modes.begin(),
display_modes.end(),
- DisplayModeMatcher(resolution));
+ DisplayModeMatcher(new_mode));
// Update the actual resolution selected as the resolution request may fail.
if (display_modes_iter == display_modes.end())
display_modes_.erase(iter->id());
void DisplayManager::UpdateDisplays(
const std::vector<DisplayInfo>& updated_display_info_list) {
#if defined(OS_WIN)
- if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
- DCHECK_EQ(1u, updated_display_info_list.size()) <<
- "Multiple display test does not work on Win8 bots. Please "
- "skip (don't disable) the test using SupportsMultipleDisplays()";
- }
+ DCHECK_EQ(1u, updated_display_info_list.size()) <<
+ ": Multiple display test does not work on Windows bots. Please "
+ "skip (don't disable) the test using SupportsMultipleDisplays()";
#endif
DisplayInfoList new_display_info_list = updated_display_info_list;
new_display_info_list.end(),
DisplayInfoSortFunctor());
DisplayList removed_displays;
- std::vector<size_t> changed_display_indices;
+ std::map<size_t, uint32_t> display_changes;
std::vector<size_t> added_display_indices;
DisplayList::iterator curr_iter = displays_.begin();
CreateDisplayFromDisplayInfoById(new_info_iter->id());
const DisplayInfo& new_display_info = GetDisplayInfo(new_display.id());
- bool host_window_bounds_changed =
- current_display_info.bounds_in_native() !=
- new_display_info.bounds_in_native();
+ uint32_t metrics = gfx::DisplayObserver::DISPLAY_METRIC_NONE;
- if (force_bounds_changed_ ||
- host_window_bounds_changed ||
- (current_display.device_scale_factor() !=
- new_display.device_scale_factor()) ||
+ // At that point the new Display objects we have are not entirely updated,
+ // they are missing the translation related to the Display disposition in
+ // the layout.
+ // Using display.bounds() and display.work_area() would fail most of the
+ // time.
+ if (force_bounds_changed_ || (current_display_info.bounds_in_native() !=
+ new_display_info.bounds_in_native()) ||
(current_display_info.size_in_pixel() !=
- new_display.GetSizeInPixel()) ||
- (current_display.rotation() != new_display.rotation())) {
- changed_display_indices.push_back(new_displays.size());
+ new_display.GetSizeInPixel())) {
+ metrics |= gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS |
+ gfx::DisplayObserver::DISPLAY_METRIC_WORK_AREA;
+ }
+
+ if (current_display.device_scale_factor() !=
+ new_display.device_scale_factor()) {
+ metrics |= gfx::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR;
+ }
+
+ if (current_display.rotation() != new_display.rotation())
+ metrics |= gfx::DisplayObserver::DISPLAY_METRIC_ROTATION;
+
+ if (metrics != gfx::DisplayObserver::DISPLAY_METRIC_NONE) {
+ display_changes.insert(
+ std::pair<size_t, uint32_t>(new_displays.size(), metrics));
}
new_display.UpdateWorkAreaFromInsets(current_display.GetWorkAreaInsets());
// Do not update |displays_| if there's nothing to be updated. Without this,
// it will not update the display layout, which causes the bug
// http://crbug.com/155948.
- if (changed_display_indices.empty() && added_display_indices.empty() &&
+ if (display_changes.empty() && added_display_indices.empty() &&
removed_displays.empty()) {
return;
}
if (UpdateSecondaryDisplayBoundsForLayout(&new_displays, &updated_index) &&
std::find(added_display_indices.begin(),
added_display_indices.end(),
- updated_index) == added_display_indices.end() &&
- std::find(changed_display_indices.begin(),
- changed_display_indices.end(),
- updated_index) == changed_display_indices.end()) {
- changed_display_indices.push_back(updated_index);
+ updated_index) == added_display_indices.end()) {
+ uint32_t metrics = gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS |
+ gfx::DisplayObserver::DISPLAY_METRIC_WORK_AREA;
+ if (display_changes.find(updated_index) != display_changes.end())
+ metrics |= display_changes[updated_index];
+
+ display_changes[updated_index] = metrics;
}
displays_ = new_displays;
// it can mirror the display newly added. This can happen when switching
// from dock mode to software mirror mode.
non_desktop_display_updater.reset();
- for (std::vector<size_t>::iterator iter = changed_display_indices.begin();
- iter != changed_display_indices.end(); ++iter) {
- screen_ash_->NotifyBoundsChanged(displays_[*iter]);
+ for (std::map<size_t, uint32_t>::iterator iter = display_changes.begin();
+ iter != display_changes.end();
+ ++iter) {
+ screen_ash_->NotifyMetricsChanged(displays_[iter->first], iter->second);
}
if (delegate_)
delegate_->PostDisplayConfigurationChange();
#if defined(USE_X11) && defined(OS_CHROMEOS)
- if (!changed_display_indices.empty() && base::SysInfo::IsRunningOnChromeOS())
+ if (!display_changes.empty() && base::SysInfo::IsRunningOnChromeOS())
ui::ClearX11DefaultRootWindow();
#endif
}
return;
SetSecondDisplayMode(enabled ? MIRRORING : EXTENDED);
}
+
+bool DisplayManager::SoftwareMirroringEnabled() const {
+ return software_mirroring_enabled();
+}
#endif
void DisplayManager::SetSecondDisplayMode(SecondDisplayMode mode) {
return false;
gfx::Display* display = FindDisplayForId(display_id);
display->SetSize(display_info_[display_id].size_in_pixel());
- screen_ash_->NotifyBoundsChanged(*display);
+ screen_ash_->NotifyMetricsChanged(
+ *display, gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS);
return true;
}
return false;