Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / ash / display / display_manager.cc
index fa86330..4cec2ea 100644 (file)
@@ -4,6 +4,7 @@
 
 #include "ash/display/display_manager.h"
 
+#include <algorithm>
 #include <cmath>
 #include <set>
 #include <string>
@@ -17,6 +18,7 @@
 #include "base/auto_reset.h"
 #include "base/command_line.h"
 #include "base/logging.h"
+#include "base/metrics/histogram.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/strings/stringprintf.h"
@@ -24,6 +26,8 @@
 #include "grit/ash_strings.h"
 #include "ui/base/l10n/l10n_util.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"
@@ -33,9 +37,8 @@
 #endif
 
 #if defined(OS_CHROMEOS)
-#include "ash/display/output_configurator_animation.h"
+#include "ash/display/display_configurator_animation.h"
 #include "base/sys_info.h"
-#include "chromeos/display/output_configurator.h"
 #endif
 
 #if defined(OS_WIN)
@@ -43,7 +46,6 @@
 #endif
 
 namespace ash {
-namespace internal {
 typedef std::vector<gfx::Display> DisplayList;
 typedef std::vector<DisplayInfo> DisplayInfoList;
 
@@ -63,6 +65,7 @@ const int kMinimumOverlapForInvalidOffset = 100;
 // 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 };
 
@@ -78,16 +81,17 @@ struct DisplayInfoSortFunctor {
   }
 };
 
-struct ResolutionMatcher {
-  ResolutionMatcher(const gfx::Size& size) : size(size) {}
-  bool operator()(const Resolution& resolution) {
-    return resolution.size == size;
+struct DisplayModeMatcher {
+  DisplayModeMatcher(const DisplayMode& target_mode)
+      : target_mode(target_mode) {}
+  bool operator()(const DisplayMode& mode) {
+    return target_mode.IsEquivalent(mode);
   }
-  gfx::Size size;
+  DisplayMode target_mode;
 };
 
 struct ScaleComparator {
-  ScaleComparator(float s) : scale(s) {}
+  explicit ScaleComparator(float s) : scale(s) {}
 
   bool operator()(float s) const {
     const float kEpsilon = 0.0001f;
@@ -156,8 +160,15 @@ DisplayManager::DisplayManager()
       force_bounds_changed_(false),
       change_display_upon_host_resize_(false),
       second_display_mode_(EXTENDED),
-      mirrored_display_id_(gfx::Display::kInvalidDisplayID) {
+      mirrored_display_id_(gfx::Display::kInvalidDisplayID),
+      registered_internal_display_rotation_lock_(false),
+      registered_internal_display_rotation_(gfx::Display::ROTATE_0) {
+
 #if defined(OS_CHROMEOS)
+  // Enable only on the device so that DisplayManagerFontTest passes.
+  if (base::SysInfo::IsRunningOnChromeOS())
+    DisplayInfo::SetUse125DSFForUIScaling(true);
+
   change_display_upon_host_resize_ = !base::SysInfo::IsRunningOnChromeOS();
 #endif
   gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_ALTERNATE,
@@ -174,28 +185,35 @@ DisplayManager::DisplayManager()
 }
 
 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();
@@ -233,6 +251,7 @@ bool DisplayManager::InitFromCommandLine() {
   for (vector<string>::const_iterator iter = parts.begin();
        iter != parts.end(); ++iter) {
     info_list.push_back(DisplayInfo::CreateFromSpec(*iter));
+    info_list.back().set_native(true);
   }
   MaybeInitInternalDisplay(info_list[0].id());
   if (info_list.size() > 1 &&
@@ -246,10 +265,22 @@ bool DisplayManager::InitFromCommandLine() {
 void DisplayManager::InitDefaultDisplay() {
   DisplayInfoList info_list;
   info_list.push_back(DisplayInfo::CreateFromSpec(std::string()));
+  info_list.back().set_native(true);
   MaybeInitInternalDisplay(info_list[0].id());
   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.GetEffectiveDeviceScaleFactor());
+#endif  // OS_CHROMEOS
+}
+
 // static
 void DisplayManager::UpdateDisplayBoundsForLayoutById(
     const DisplayLayout& layout,
@@ -344,8 +375,10 @@ void DisplayManager::SetLayoutForCurrentDisplays(
 
     // 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();
   }
@@ -403,12 +436,6 @@ void DisplayManager::SetDisplayRotation(int64 display_id,
     display_info_list.push_back(info);
   }
   AddMirrorDisplayInfoIfAny(&display_info_list);
-  if (virtual_keyboard_root_window_enabled() &&
-      display_id == non_desktop_display_.id()) {
-    DisplayInfo info = GetDisplayInfo(display_id);
-    info.set_rotation(rotation);
-    display_info_list.push_back(info);
-  }
   UpdateDisplays(display_info_list);
 }
 
@@ -419,6 +446,7 @@ void DisplayManager::SetDisplayUIScale(int64 display_id,
     return;
   }
 
+  // TODO(mukai): merge this implementation into SetDisplayMode().
   DisplayInfoList display_info_list;
   for (DisplayList::const_iterator iter = displays_.begin();
        iter != displays_.end(); ++iter) {
@@ -446,26 +474,67 @@ void DisplayManager::SetDisplayResolution(int64 display_id,
   if (gfx::Display::InternalDisplayId() == display_id)
     return;
   const DisplayInfo& display_info = GetDisplayInfo(display_id);
-  const std::vector<Resolution>& resolutions = display_info.resolutions();
-  DCHECK_NE(0u, resolutions.size());
-  std::vector<Resolution>::const_iterator iter =
-      std::find_if(resolutions.begin(),
-                   resolutions.end(),
-                   ResolutionMatcher(resolution));
-  if (iter == resolutions.end()) {
+  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(target_mode));
+  if (iter == modes.end()) {
     LOG(WARNING) << "Unsupported resolution was requested:"
                  << resolution.ToString();
     return;
-  } else if (iter == resolutions.begin()) {
-    // The best resolution was set, so forget it.
-    resolutions_.erase(display_id);
-  } else {
-    resolutions_[display_id] = resolution;
   }
-#if defined(OS_CHROMEOS) && defined(USE_X11)
+  display_modes_[display_id] = *iter;
+#if defined(OS_CHROMEOS)
   if (base::SysInfo::IsRunningOnChromeOS())
-    Shell::GetInstance()->output_configurator()->ScheduleConfigureOutputs();
+    Shell::GetInstance()->display_configurator()->OnConfigurationChanged();
+#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(
@@ -473,30 +542,74 @@ void DisplayManager::RegisterDisplayProperty(
     gfx::Display::Rotation rotation,
     float ui_scale,
     const gfx::Insets* overscan_insets,
-    const gfx::Size& resolution_in_pixels) {
-  if (display_info_.find(display_id) == display_info_.end()) {
-    display_info_[display_id] =
-        DisplayInfo(display_id, std::string(""), false);
-  }
+    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())
-    resolutions_[display_id] = resolution_in_pixels;
+  if (!resolution_in_pixels.IsEmpty()) {
+    DCHECK(!IsInternalDisplayId(display_id));
+    // Default refresh rate, until OnNativeDisplaysChanged() updates us with the
+    // actual display info, is 60 Hz.
+    DisplayMode mode(resolution_in_pixels, 60.0f, false, false);
+    mode.device_scale_factor = device_scale_factor;
+    display_modes_[display_id] = mode;
+  }
 }
 
-bool DisplayManager::GetSelectedResolutionForDisplayId(
-    int64 id,
-    gfx::Size* resolution_out) const {
-  std::map<int64, gfx::Size>::const_iterator iter =
-      resolutions_.find(id);
-  if (iter == resolutions_.end())
+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;
+}
+
+void DisplayManager::RegisterDisplayRotationProperties(bool rotation_lock,
+    gfx::Display::Rotation rotation) {
+  if (delegate_)
+    delegate_->PreDisplayConfigurationChange(false);
+  registered_internal_display_rotation_lock_ = rotation_lock;
+  registered_internal_display_rotation_ = rotation;
+  if (delegate_)
+    delegate_->PostDisplayConfigurationChange();
+}
+
+bool DisplayManager::GetSelectedModeForDisplayId(int64 id,
+                                                 DisplayMode* mode_out) const {
+  std::map<int64, DisplayMode>::const_iterator iter = display_modes_.find(id);
+  if (iter == display_modes_.end())
     return false;
-  *resolution_out = iter->second;
+  *mode_out = iter->second;
   return true;
 }
 
@@ -511,10 +624,32 @@ gfx::Insets DisplayManager::GetOverscanInsets(int64 display_id) const {
       it->second.overscan_insets_in_dip() : gfx::Insets();
 }
 
+void DisplayManager::SetColorCalibrationProfile(
+    int64 display_id,
+    ui::ColorCalibrationProfile profile) {
+#if defined(OS_CHROMEOS)
+  if (!display_info_[display_id].IsColorProfileAvailable(profile))
+    return;
+
+  if (delegate_)
+    delegate_->PreDisplayConfigurationChange(false);
+  // Just sets color profile if it's not running on ChromeOS (like tests).
+  if (!base::SysInfo::IsRunningOnChromeOS() ||
+      Shell::GetInstance()->display_configurator()->SetColorCalibrationProfile(
+          display_id, profile)) {
+    display_info_[display_id].SetColorProfile(profile);
+    UMA_HISTOGRAM_ENUMERATION(
+        "ChromeOS.Display.ColorProfile", profile, ui::NUM_COLOR_PROFILES);
+  }
+  if (delegate_)
+    delegate_->PostDisplayConfigurationChange();
+#endif
+}
+
 void DisplayManager::OnNativeDisplaysChanged(
     const std::vector<DisplayInfo>& updated_displays) {
   if (updated_displays.empty()) {
-    VLOG(1) << "OnNativeDisplayChanged(0): # of current displays="
+    VLOG(1) << "OnNativeDisplaysChanged(0): # of current displays="
             << displays_.size();
     // If the device is booted without display, or chrome is started
     // without --ash-host-window-bounds on linux desktop, use the
@@ -569,20 +704,23 @@ void DisplayManager::OnNativeDisplaysChanged(
       new_display_info_list.push_back(*iter);
     }
 
-    const gfx::Size& resolution = iter->bounds_in_native().size();
-    const std::vector<Resolution>& resolutions = iter->resolutions();
+    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 (!resolutions.size())
+    if (!display_modes.size())
       continue;
-    std::vector<Resolution>::const_iterator resolution_iter =
-        std::find_if(resolutions.begin(),
-                     resolutions.end(),
-                     ResolutionMatcher(resolution));
+    std::vector<DisplayMode>::const_iterator display_modes_iter =
+        std::find_if(display_modes.begin(),
+                     display_modes.end(),
+                     DisplayModeMatcher(new_mode));
     // Update the actual resolution selected as the resolution request may fail.
-    if (resolution_iter == resolutions.begin())
-      resolutions_.erase(iter->id());
-    else if (resolutions_.find(iter->id()) != resolutions_.end())
-      resolutions_[iter->id()] = resolution;
+    if (display_modes_iter == display_modes.end())
+      display_modes_.erase(iter->id());
+    else if (display_modes_.find(iter->id()) != display_modes_.end())
+      display_modes_[iter->id()] = *display_modes_iter;
   }
   if (HasInternalDisplay() &&
       !internal_display_connected &&
@@ -611,11 +749,9 @@ void DisplayManager::UpdateDisplays() {
 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;
@@ -624,7 +760,7 @@ void DisplayManager::UpdateDisplays(
             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();
@@ -663,7 +799,7 @@ void DisplayManager::UpdateDisplays(
       non_desktop_display_ =
           CreateDisplayFromDisplayInfoById(non_desktop_display_id);
       ++new_info_iter;
-      // Remove existing external dispaly if it is going to be used as
+      // Remove existing external display if it is going to be used as
       // non desktop.
       if (curr_iter != displays_.end() &&
           curr_iter->id() == non_desktop_display_id) {
@@ -694,19 +830,32 @@ void DisplayManager::UpdateDisplays(
           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())) {
+           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;
 
-        changed_display_indices.push_back(new_displays.size());
+      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());
@@ -730,13 +879,6 @@ void DisplayManager::UpdateDisplays(
   scoped_ptr<NonDesktopDisplayUpdater> non_desktop_display_updater(
       new NonDesktopDisplayUpdater(this, delegate_));
 
-  // 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() &&
-      removed_displays.empty()) {
-    return;
-  }
   // Clear focus if the display has been removed, but don't clear focus if
   // the destkop has been moved from one display to another
   // (mirror -> docked, docked -> single internal).
@@ -746,15 +888,33 @@ void DisplayManager::UpdateDisplays(
   if (delegate_)
     delegate_->PreDisplayConfigurationChange(clear_focus);
 
+  // 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 (display_changes.empty() && added_display_indices.empty() &&
+      removed_displays.empty()) {
+    // When changing from software mirroring mode to sinlge display mode, it
+    // is possible there is no need to update |displays_| and we early out
+    // here. But we still want to run the PostDisplayConfigurationChange()
+    // cause there are some clients need to act on this, e.g.
+    // TouchTransformerController needs to adjust the TouchTransformer when
+    // switching from dual displays to single display.
+    if (delegate_)
+      delegate_->PostDisplayConfigurationChange();
+    return;
+  }
+
   size_t updated_index;
   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;
@@ -783,15 +943,16 @@ void DisplayManager::UpdateDisplays(
   // 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
 }
@@ -818,6 +979,8 @@ bool DisplayManager::IsMirrored() const {
 }
 
 const DisplayInfo& DisplayManager::GetDisplayInfo(int64 display_id) const {
+  DCHECK_NE(gfx::Display::kInvalidDisplayID, display_id);
+
   std::map<int64, DisplayInfo>::const_iterator iter =
       display_info_.find(display_id);
   CHECK(iter != display_info_.end()) << display_id;
@@ -850,9 +1013,10 @@ void DisplayManager::SetMirrorMode(bool mirrored) {
 
 #if defined(OS_CHROMEOS)
   if (base::SysInfo::IsRunningOnChromeOS()) {
-    chromeos::OutputState new_state = mirrored ?
-        chromeos::STATE_DUAL_MIRROR : chromeos::STATE_DUAL_EXTENDED;
-    Shell::GetInstance()->output_configurator()->SetDisplayMode(new_state);
+    ui::MultipleDisplayState new_state =
+        mirrored ? ui::MULTIPLE_DISPLAY_STATE_DUAL_MIRROR :
+                   ui::MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED;
+    Shell::GetInstance()->display_configurator()->SetDisplayMode(new_state);
     return;
   }
 #endif
@@ -867,8 +1031,8 @@ void DisplayManager::SetMirrorMode(bool mirrored) {
   }
   UpdateDisplays(display_info_list);
 #if defined(OS_CHROMEOS)
-  if (Shell::GetInstance()->output_configurator_animation()) {
-    Shell::GetInstance()->output_configurator_animation()->
+  if (Shell::GetInstance()->display_configurator_animation()) {
+    Shell::GetInstance()->display_configurator_animation()->
         StartFadeInAnimation();
   }
 #endif
@@ -909,12 +1073,12 @@ void DisplayManager::ToggleDisplayScaleFactor() {
 
 #if defined(OS_CHROMEOS)
 void DisplayManager::SetSoftwareMirroring(bool enabled) {
-  // TODO(oshima|bshe): Support external display on the system
-  // that has virtual keyboard display.
-  if (second_display_mode_ == VIRTUAL_KEYBOARD)
-    return;
   SetSecondDisplayMode(enabled ? MIRRORING : EXTENDED);
 }
+
+bool DisplayManager::SoftwareMirroringEnabled() const {
+  return software_mirroring_enabled();
+}
 #endif
 
 void DisplayManager::SetSecondDisplayMode(SecondDisplayMode mode) {
@@ -932,7 +1096,8 @@ bool DisplayManager::UpdateDisplayBounds(int64 display_id,
       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;
@@ -975,13 +1140,25 @@ void DisplayManager::AddMirrorDisplayInfoIfAny(
 void DisplayManager::InsertAndUpdateDisplayInfo(const DisplayInfo& new_info) {
   std::map<int64, DisplayInfo>::iterator info =
       display_info_.find(new_info.id());
-  if (info != display_info_.end())
+  if (info != display_info_.end()) {
     info->second.Copy(new_info);
-  else {
+  else {
     display_info_[new_info.id()] = new_info;
     display_info_[new_info.id()].set_native(false);
   }
   display_info_[new_info.id()].UpdateDisplaySize();
+
+  OnDisplayInfoUpdated(display_info_[new_info.id()]);
+}
+
+void DisplayManager::OnDisplayInfoUpdated(const DisplayInfo& display_info) {
+#if defined(OS_CHROMEOS)
+  ui::ColorCalibrationProfile color_profile = display_info.color_profile();
+  if (color_profile != ui::COLOR_PROFILE_STANDARD) {
+    Shell::GetInstance()->display_configurator()->SetColorCalibrationProfile(
+        display_info.id(), color_profile);
+  }
+#endif
 }
 
 gfx::Display DisplayManager::CreateDisplayFromDisplayInfoById(int64 id) {
@@ -990,9 +1167,7 @@ gfx::Display DisplayManager::CreateDisplayFromDisplayInfoById(int64 id) {
 
   gfx::Display new_display(display_info.id());
   gfx::Rect bounds_in_native(display_info.size_in_pixel());
-  float device_scale_factor = display_info.device_scale_factor();
-  if (device_scale_factor == 2.0f && display_info.configured_ui_scale() == 2.0f)
-    device_scale_factor = 1.0f;
+  float device_scale_factor = display_info.GetEffectiveDeviceScaleFactor();
 
   // Simply set the origin to (0,0).  The primary display's origin is
   // always (0,0) and the secondary display's bounds will be updated
@@ -1015,7 +1190,7 @@ bool DisplayManager::UpdateSecondaryDisplayBoundsForLayout(
       (id_at_zero == first_display_id_ ||
        id_at_zero == gfx::Display::InternalDisplayId()) ?
       std::make_pair(id_at_zero, displays->at(1).id()) :
-      std::make_pair(displays->at(1).id(), id_at_zero) ;
+      std::make_pair(displays->at(1).id(), id_at_zero);
   DisplayLayout layout =
       layout_store_->ComputeDisplayLayoutForDisplayIdPair(pair);
 
@@ -1090,5 +1265,4 @@ void DisplayManager::UpdateDisplayBoundsForLayout(
   secondary_display->UpdateWorkAreaFromInsets(insets);
 }
 
-}  // namespace internal
 }  // namespace ash