Home | History | Annotate | Download | only in display
      1 // Copyright (c) 2012 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.
      4 
      5 #include "ash/display/display_manager.h"
      6 
      7 #include <cmath>
      8 #include <set>
      9 #include <string>
     10 #include <vector>
     11 
     12 #include "ash/ash_switches.h"
     13 #include "ash/display/display_layout_store.h"
     14 #include "ash/display/screen_ash.h"
     15 #include "ash/screen_util.h"
     16 #include "ash/shell.h"
     17 #include "base/auto_reset.h"
     18 #include "base/command_line.h"
     19 #include "base/logging.h"
     20 #include "base/metrics/histogram.h"
     21 #include "base/strings/string_number_conversions.h"
     22 #include "base/strings/string_split.h"
     23 #include "base/strings/stringprintf.h"
     24 #include "base/strings/utf_string_conversions.h"
     25 #include "grit/ash_strings.h"
     26 #include "ui/base/l10n/l10n_util.h"
     27 #include "ui/base/layout.h"
     28 #include "ui/base/resource/resource_bundle.h"
     29 #include "ui/gfx/display.h"
     30 #include "ui/gfx/display_observer.h"
     31 #include "ui/gfx/rect.h"
     32 #include "ui/gfx/screen.h"
     33 #include "ui/gfx/size_conversions.h"
     34 
     35 #if defined(USE_X11)
     36 #include "ui/base/x/x11_util.h"
     37 #endif
     38 
     39 #if defined(OS_CHROMEOS)
     40 #include "ash/display/display_configurator_animation.h"
     41 #include "base/sys_info.h"
     42 #endif
     43 
     44 #if defined(OS_WIN)
     45 #include "base/win/windows_version.h"
     46 #endif
     47 
     48 namespace ash {
     49 typedef std::vector<gfx::Display> DisplayList;
     50 typedef std::vector<DisplayInfo> DisplayInfoList;
     51 
     52 namespace {
     53 
     54 // We need to keep this in order for unittests to tell if
     55 // the object in gfx::Screen::GetScreenByType is for shutdown.
     56 gfx::Screen* screen_for_shutdown = NULL;
     57 
     58 // The number of pixels to overlap between the primary and secondary displays,
     59 // in case that the offset value is too large.
     60 const int kMinimumOverlapForInvalidOffset = 100;
     61 
     62 // List of value UI Scale values. Scales for 2x are equivalent to 640,
     63 // 800, 1024, 1280, 1440, 1600 and 1920 pixel width respectively on
     64 // 2560 pixel width 2x density display. Please see crbug.com/233375
     65 // for the full list of resolutions.
     66 const float kUIScalesFor2x[] =
     67     {0.5f, 0.625f, 0.8f, 1.0f, 1.125f, 1.25f, 1.5f, 2.0f};
     68 const float kUIScalesFor1280[] = {0.5f, 0.625f, 0.8f, 1.0f, 1.125f };
     69 const float kUIScalesFor1366[] = {0.5f, 0.6f, 0.75f, 1.0f, 1.125f };
     70 
     71 struct DisplaySortFunctor {
     72   bool operator()(const gfx::Display& a, const gfx::Display& b) {
     73     return a.id() < b.id();
     74   }
     75 };
     76 
     77 struct DisplayInfoSortFunctor {
     78   bool operator()(const DisplayInfo& a, const DisplayInfo& b) {
     79     return a.id() < b.id();
     80   }
     81 };
     82 
     83 struct DisplayModeMatcher {
     84   DisplayModeMatcher(const gfx::Size& size) : size(size) {}
     85   bool operator()(const DisplayMode& mode) { return mode.size == size; }
     86   gfx::Size size;
     87 };
     88 
     89 struct ScaleComparator {
     90   explicit ScaleComparator(float s) : scale(s) {}
     91 
     92   bool operator()(float s) const {
     93     const float kEpsilon = 0.0001f;
     94     return std::abs(scale - s) < kEpsilon;
     95   }
     96   float scale;
     97 };
     98 
     99 gfx::Display& GetInvalidDisplay() {
    100   static gfx::Display* invalid_display = new gfx::Display();
    101   return *invalid_display;
    102 }
    103 
    104 void MaybeInitInternalDisplay(int64 id) {
    105   CommandLine* command_line = CommandLine::ForCurrentProcess();
    106   if (command_line->HasSwitch(switches::kAshUseFirstDisplayAsInternal))
    107     gfx::Display::SetInternalDisplayId(id);
    108 }
    109 
    110 // Scoped objects used to either create or close the non desktop window
    111 // at specific timing.
    112 class NonDesktopDisplayUpdater {
    113  public:
    114   NonDesktopDisplayUpdater(DisplayManager* manager,
    115                            DisplayManager::Delegate* delegate)
    116       : manager_(manager),
    117         delegate_(delegate),
    118         enabled_(manager_->second_display_mode() != DisplayManager::EXTENDED &&
    119                  manager_->non_desktop_display().is_valid()) {
    120   }
    121 
    122   ~NonDesktopDisplayUpdater() {
    123     if (!delegate_)
    124       return;
    125 
    126     if (enabled_) {
    127       DisplayInfo display_info = manager_->GetDisplayInfo(
    128           manager_->non_desktop_display().id());
    129       delegate_->CreateOrUpdateNonDesktopDisplay(display_info);
    130     } else {
    131       delegate_->CloseNonDesktopDisplay();
    132     }
    133   }
    134 
    135   bool enabled() const { return enabled_; }
    136 
    137  private:
    138   DisplayManager* manager_;
    139   DisplayManager::Delegate* delegate_;
    140   bool enabled_;
    141   DISALLOW_COPY_AND_ASSIGN(NonDesktopDisplayUpdater);
    142 };
    143 
    144 }  // namespace
    145 
    146 using std::string;
    147 using std::vector;
    148 
    149 DisplayManager::DisplayManager()
    150     : delegate_(NULL),
    151       screen_ash_(new ScreenAsh),
    152       screen_(screen_ash_.get()),
    153       layout_store_(new DisplayLayoutStore),
    154       first_display_id_(gfx::Display::kInvalidDisplayID),
    155       num_connected_displays_(0),
    156       force_bounds_changed_(false),
    157       change_display_upon_host_resize_(false),
    158       second_display_mode_(EXTENDED),
    159       mirrored_display_id_(gfx::Display::kInvalidDisplayID) {
    160 #if defined(OS_CHROMEOS)
    161   change_display_upon_host_resize_ = !base::SysInfo::IsRunningOnChromeOS();
    162 #endif
    163   DisplayInfo::SetAllowUpgradeToHighDPI(
    164       ui::ResourceBundle::GetSharedInstance().GetMaxScaleFactor() ==
    165       ui::SCALE_FACTOR_200P);
    166 
    167   gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_ALTERNATE,
    168                                  screen_ash_.get());
    169   gfx::Screen* current_native =
    170       gfx::Screen::GetScreenByType(gfx::SCREEN_TYPE_NATIVE);
    171   // If there is no native, or the native was for shutdown,
    172   // use ash's screen.
    173   if (!current_native ||
    174       current_native == screen_for_shutdown) {
    175     gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE,
    176                                    screen_ash_.get());
    177   }
    178 }
    179 
    180 DisplayManager::~DisplayManager() {
    181 }
    182 
    183 // static
    184 std::vector<float> DisplayManager::GetScalesForDisplay(
    185     const DisplayInfo& info) {
    186   std::vector<float> ret;
    187   if (info.device_scale_factor() == 2.0f) {
    188     ret.assign(kUIScalesFor2x, kUIScalesFor2x + arraysize(kUIScalesFor2x));
    189     return ret;
    190   }
    191   switch (info.bounds_in_native().width()) {
    192     case 1280:
    193       ret.assign(kUIScalesFor1280,
    194                  kUIScalesFor1280 + arraysize(kUIScalesFor1280));
    195       break;
    196     case 1366:
    197       ret.assign(kUIScalesFor1366,
    198                  kUIScalesFor1366 + arraysize(kUIScalesFor1366));
    199       break;
    200     default:
    201       ret.assign(kUIScalesFor1280,
    202                  kUIScalesFor1280 + arraysize(kUIScalesFor1280));
    203 #if defined(OS_CHROMEOS)
    204       if (base::SysInfo::IsRunningOnChromeOS())
    205         NOTREACHED() << "Unknown resolution:" << info.ToString();
    206 #endif
    207   }
    208   return ret;
    209 }
    210 
    211 // static
    212 float DisplayManager::GetNextUIScale(const DisplayInfo& info, bool up) {
    213   float scale = info.configured_ui_scale();
    214   std::vector<float> scales = GetScalesForDisplay(info);
    215   for (size_t i = 0; i < scales.size(); ++i) {
    216     if (ScaleComparator(scales[i])(scale)) {
    217       if (up && i != scales.size() - 1)
    218         return scales[i + 1];
    219       if (!up && i != 0)
    220         return scales[i - 1];
    221       return scales[i];
    222     }
    223   }
    224   // Fallback to 1.0f if the |scale| wasn't in the list.
    225   return 1.0f;
    226 }
    227 
    228 bool DisplayManager::InitFromCommandLine() {
    229   DisplayInfoList info_list;
    230   CommandLine* command_line = CommandLine::ForCurrentProcess();
    231   if (!command_line->HasSwitch(switches::kAshHostWindowBounds))
    232     return false;
    233   const string size_str =
    234       command_line->GetSwitchValueASCII(switches::kAshHostWindowBounds);
    235   vector<string> parts;
    236   base::SplitString(size_str, ',', &parts);
    237   for (vector<string>::const_iterator iter = parts.begin();
    238        iter != parts.end(); ++iter) {
    239     info_list.push_back(DisplayInfo::CreateFromSpec(*iter));
    240   }
    241   MaybeInitInternalDisplay(info_list[0].id());
    242   if (info_list.size() > 1 &&
    243       command_line->HasSwitch(switches::kAshEnableSoftwareMirroring)) {
    244     SetSecondDisplayMode(MIRRORING);
    245   }
    246   OnNativeDisplaysChanged(info_list);
    247   return true;
    248 }
    249 
    250 void DisplayManager::InitDefaultDisplay() {
    251   DisplayInfoList info_list;
    252   info_list.push_back(DisplayInfo::CreateFromSpec(std::string()));
    253   MaybeInitInternalDisplay(info_list[0].id());
    254   OnNativeDisplaysChanged(info_list);
    255 }
    256 
    257 // static
    258 void DisplayManager::UpdateDisplayBoundsForLayoutById(
    259     const DisplayLayout& layout,
    260     const gfx::Display& primary_display,
    261     int64 secondary_display_id) {
    262   DCHECK_NE(gfx::Display::kInvalidDisplayID, secondary_display_id);
    263   UpdateDisplayBoundsForLayout(
    264       layout, primary_display,
    265       Shell::GetInstance()->display_manager()->
    266       FindDisplayForId(secondary_display_id));
    267 }
    268 
    269 bool DisplayManager::IsActiveDisplay(const gfx::Display& display) const {
    270   for (DisplayList::const_iterator iter = displays_.begin();
    271        iter != displays_.end(); ++iter) {
    272     if ((*iter).id() == display.id())
    273       return true;
    274   }
    275   return false;
    276 }
    277 
    278 bool DisplayManager::HasInternalDisplay() const {
    279   return gfx::Display::InternalDisplayId() != gfx::Display::kInvalidDisplayID;
    280 }
    281 
    282 bool DisplayManager::IsInternalDisplayId(int64 id) const {
    283   return gfx::Display::InternalDisplayId() == id;
    284 }
    285 
    286 DisplayLayout DisplayManager::GetCurrentDisplayLayout() {
    287   DCHECK_EQ(2U, num_connected_displays());
    288   // Invert if the primary was swapped.
    289   if (num_connected_displays() > 1) {
    290     DisplayIdPair pair = GetCurrentDisplayIdPair();
    291     return layout_store_->ComputeDisplayLayoutForDisplayIdPair(pair);
    292   }
    293   NOTREACHED() << "DisplayLayout is requested for single display";
    294   // On release build, just fallback to default instead of blowing up.
    295   DisplayLayout layout =
    296       layout_store_->default_display_layout();
    297   layout.primary_id = displays_[0].id();
    298   return layout;
    299 }
    300 
    301 DisplayIdPair DisplayManager::GetCurrentDisplayIdPair() const {
    302   if (IsMirrored()) {
    303     if (software_mirroring_enabled()) {
    304       CHECK_EQ(2u, num_connected_displays());
    305       // This comment is to make it easy to distinguish the crash
    306       // between two checks.
    307       CHECK_EQ(1u, displays_.size());
    308     }
    309     return std::make_pair(displays_[0].id(), mirrored_display_id_);
    310   } else {
    311     CHECK_GE(2u, displays_.size());
    312     int64 id_at_zero = displays_[0].id();
    313     if (id_at_zero == gfx::Display::InternalDisplayId() ||
    314         id_at_zero == first_display_id()) {
    315       return std::make_pair(id_at_zero, displays_[1].id());
    316     } else {
    317       return std::make_pair(displays_[1].id(), id_at_zero);
    318     }
    319   }
    320 }
    321 
    322 void DisplayManager::SetLayoutForCurrentDisplays(
    323     const DisplayLayout& layout_relative_to_primary) {
    324   DCHECK_EQ(2U, GetNumDisplays());
    325   if (GetNumDisplays() < 2)
    326     return;
    327   const gfx::Display& primary = screen_->GetPrimaryDisplay();
    328   const DisplayIdPair pair = GetCurrentDisplayIdPair();
    329   // Invert if the primary was swapped.
    330   DisplayLayout to_set = pair.first == primary.id() ?
    331       layout_relative_to_primary : layout_relative_to_primary.Invert();
    332 
    333   DisplayLayout current_layout =
    334       layout_store_->GetRegisteredDisplayLayout(pair);
    335   if (to_set.position != current_layout.position ||
    336       to_set.offset != current_layout.offset) {
    337     to_set.primary_id = primary.id();
    338     layout_store_->RegisterLayoutForDisplayIdPair(
    339         pair.first, pair.second, to_set);
    340     if (delegate_)
    341       delegate_->PreDisplayConfigurationChange(false);
    342     // PreDisplayConfigurationChange(false);
    343     // TODO(oshima): Call UpdateDisplays instead.
    344     const DisplayLayout layout = GetCurrentDisplayLayout();
    345     UpdateDisplayBoundsForLayoutById(
    346         layout, primary,
    347         ScreenUtil::GetSecondaryDisplay().id());
    348 
    349     // Primary's bounds stay the same. Just notify bounds change
    350     // on the secondary.
    351     screen_ash_->NotifyMetricsChanged(
    352         ScreenUtil::GetSecondaryDisplay(),
    353         gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS |
    354             gfx::DisplayObserver::DISPLAY_METRIC_WORK_AREA);
    355     if (delegate_)
    356       delegate_->PostDisplayConfigurationChange();
    357   }
    358 }
    359 
    360 const gfx::Display& DisplayManager::GetDisplayForId(int64 id) const {
    361   gfx::Display* display =
    362       const_cast<DisplayManager*>(this)->FindDisplayForId(id);
    363   return display ? *display : GetInvalidDisplay();
    364 }
    365 
    366 const gfx::Display& DisplayManager::FindDisplayContainingPoint(
    367     const gfx::Point& point_in_screen) const {
    368   for (DisplayList::const_iterator iter = displays_.begin();
    369        iter != displays_.end(); ++iter) {
    370     const gfx::Display& display = *iter;
    371     if (display.bounds().Contains(point_in_screen))
    372       return display;
    373   }
    374   return GetInvalidDisplay();
    375 }
    376 
    377 bool DisplayManager::UpdateWorkAreaOfDisplay(int64 display_id,
    378                                              const gfx::Insets& insets) {
    379   gfx::Display* display = FindDisplayForId(display_id);
    380   DCHECK(display);
    381   gfx::Rect old_work_area = display->work_area();
    382   display->UpdateWorkAreaFromInsets(insets);
    383   return old_work_area != display->work_area();
    384 }
    385 
    386 void DisplayManager::SetOverscanInsets(int64 display_id,
    387                                        const gfx::Insets& insets_in_dip) {
    388   display_info_[display_id].SetOverscanInsets(insets_in_dip);
    389   DisplayInfoList display_info_list;
    390   for (DisplayList::const_iterator iter = displays_.begin();
    391        iter != displays_.end(); ++iter) {
    392     display_info_list.push_back(GetDisplayInfo(iter->id()));
    393   }
    394   AddMirrorDisplayInfoIfAny(&display_info_list);
    395   UpdateDisplays(display_info_list);
    396 }
    397 
    398 void DisplayManager::SetDisplayRotation(int64 display_id,
    399                                         gfx::Display::Rotation rotation) {
    400   DisplayInfoList display_info_list;
    401   for (DisplayList::const_iterator iter = displays_.begin();
    402        iter != displays_.end(); ++iter) {
    403     DisplayInfo info = GetDisplayInfo(iter->id());
    404     if (info.id() == display_id) {
    405       if (info.rotation() == rotation)
    406         return;
    407       info.set_rotation(rotation);
    408     }
    409     display_info_list.push_back(info);
    410   }
    411   AddMirrorDisplayInfoIfAny(&display_info_list);
    412   if (virtual_keyboard_root_window_enabled() &&
    413       display_id == non_desktop_display_.id()) {
    414     DisplayInfo info = GetDisplayInfo(display_id);
    415     info.set_rotation(rotation);
    416     display_info_list.push_back(info);
    417   }
    418   UpdateDisplays(display_info_list);
    419 }
    420 
    421 void DisplayManager::SetDisplayUIScale(int64 display_id,
    422                                        float ui_scale) {
    423   if (!IsDisplayUIScalingEnabled() ||
    424       gfx::Display::InternalDisplayId() != display_id) {
    425     return;
    426   }
    427 
    428   DisplayInfoList display_info_list;
    429   for (DisplayList::const_iterator iter = displays_.begin();
    430        iter != displays_.end(); ++iter) {
    431     DisplayInfo info = GetDisplayInfo(iter->id());
    432     if (info.id() == display_id) {
    433       if (info.configured_ui_scale() == ui_scale)
    434         return;
    435       std::vector<float> scales = GetScalesForDisplay(info);
    436       ScaleComparator comparator(ui_scale);
    437       if (std::find_if(scales.begin(), scales.end(), comparator) ==
    438           scales.end()) {
    439         return;
    440       }
    441       info.set_configured_ui_scale(ui_scale);
    442     }
    443     display_info_list.push_back(info);
    444   }
    445   AddMirrorDisplayInfoIfAny(&display_info_list);
    446   UpdateDisplays(display_info_list);
    447 }
    448 
    449 void DisplayManager::SetDisplayResolution(int64 display_id,
    450                                           const gfx::Size& resolution) {
    451   DCHECK_NE(gfx::Display::InternalDisplayId(), display_id);
    452   if (gfx::Display::InternalDisplayId() == display_id)
    453     return;
    454   const DisplayInfo& display_info = GetDisplayInfo(display_id);
    455   const std::vector<DisplayMode>& modes = display_info.display_modes();
    456   DCHECK_NE(0u, modes.size());
    457   std::vector<DisplayMode>::const_iterator iter =
    458       std::find_if(modes.begin(), modes.end(), DisplayModeMatcher(resolution));
    459   if (iter == modes.end()) {
    460     LOG(WARNING) << "Unsupported resolution was requested:"
    461                  << resolution.ToString();
    462     return;
    463   }
    464   display_modes_[display_id] = *iter;
    465 #if defined(OS_CHROMEOS)
    466   if (base::SysInfo::IsRunningOnChromeOS())
    467     Shell::GetInstance()->display_configurator()->OnConfigurationChanged();
    468 #endif
    469 }
    470 
    471 void DisplayManager::RegisterDisplayProperty(
    472     int64 display_id,
    473     gfx::Display::Rotation rotation,
    474     float ui_scale,
    475     const gfx::Insets* overscan_insets,
    476     const gfx::Size& resolution_in_pixels,
    477     ui::ColorCalibrationProfile color_profile) {
    478   if (display_info_.find(display_id) == display_info_.end())
    479     display_info_[display_id] = DisplayInfo(display_id, std::string(), false);
    480 
    481   display_info_[display_id].set_rotation(rotation);
    482   display_info_[display_id].SetColorProfile(color_profile);
    483   // Just in case the preference file was corrupted.
    484   if (0.5f <= ui_scale && ui_scale <= 2.0f)
    485     display_info_[display_id].set_configured_ui_scale(ui_scale);
    486   if (overscan_insets)
    487     display_info_[display_id].SetOverscanInsets(*overscan_insets);
    488   if (!resolution_in_pixels.IsEmpty()) {
    489     // Default refresh rate, until OnNativeDisplaysChanged() updates us with the
    490     // actual display info, is 60 Hz.
    491     display_modes_[display_id] =
    492         DisplayMode(resolution_in_pixels, 60.0f, false, false);
    493   }
    494 }
    495 
    496 bool DisplayManager::GetSelectedModeForDisplayId(int64 id,
    497                                                  DisplayMode* mode_out) const {
    498   std::map<int64, DisplayMode>::const_iterator iter = display_modes_.find(id);
    499   if (iter == display_modes_.end())
    500     return false;
    501   *mode_out = iter->second;
    502   return true;
    503 }
    504 
    505 bool DisplayManager::IsDisplayUIScalingEnabled() const {
    506   return GetDisplayIdForUIScaling() != gfx::Display::kInvalidDisplayID;
    507 }
    508 
    509 gfx::Insets DisplayManager::GetOverscanInsets(int64 display_id) const {
    510   std::map<int64, DisplayInfo>::const_iterator it =
    511       display_info_.find(display_id);
    512   return (it != display_info_.end()) ?
    513       it->second.overscan_insets_in_dip() : gfx::Insets();
    514 }
    515 
    516 void DisplayManager::SetColorCalibrationProfile(
    517     int64 display_id,
    518     ui::ColorCalibrationProfile profile) {
    519 #if defined(OS_CHROMEOS)
    520   if (!display_info_[display_id].IsColorProfileAvailable(profile))
    521     return;
    522 
    523   if (delegate_)
    524     delegate_->PreDisplayConfigurationChange(false);
    525   // Just sets color profile if it's not running on ChromeOS (like tests).
    526   if (!base::SysInfo::IsRunningOnChromeOS() ||
    527       Shell::GetInstance()->display_configurator()->SetColorCalibrationProfile(
    528           display_id, profile)) {
    529     display_info_[display_id].SetColorProfile(profile);
    530     UMA_HISTOGRAM_ENUMERATION(
    531         "ChromeOS.Display.ColorProfile", profile, ui::NUM_COLOR_PROFILES);
    532   }
    533   if (delegate_)
    534     delegate_->PostDisplayConfigurationChange();
    535 #endif
    536 }
    537 
    538 void DisplayManager::OnNativeDisplaysChanged(
    539     const std::vector<DisplayInfo>& updated_displays) {
    540   if (updated_displays.empty()) {
    541     VLOG(1) << "OnNativeDisplayChanged(0): # of current displays="
    542             << displays_.size();
    543     // If the device is booted without display, or chrome is started
    544     // without --ash-host-window-bounds on linux desktop, use the
    545     // default display.
    546     if (displays_.empty()) {
    547       std::vector<DisplayInfo> init_displays;
    548       init_displays.push_back(DisplayInfo::CreateFromSpec(std::string()));
    549       MaybeInitInternalDisplay(init_displays[0].id());
    550       OnNativeDisplaysChanged(init_displays);
    551     } else {
    552       // Otherwise don't update the displays when all displays are disconnected.
    553       // This happens when:
    554       // - the device is idle and powerd requested to turn off all displays.
    555       // - the device is suspended. (kernel turns off all displays)
    556       // - the internal display's brightness is set to 0 and no external
    557       //   display is connected.
    558       // - the internal display's brightness is 0 and external display is
    559       //   disconnected.
    560       // The display will be updated when one of displays is turned on, and the
    561       // display list will be updated correctly.
    562     }
    563     return;
    564   }
    565   first_display_id_ = updated_displays[0].id();
    566   std::set<gfx::Point> origins;
    567 
    568   if (updated_displays.size() == 1) {
    569     VLOG(1) << "OnNativeDisplaysChanged(1):" << updated_displays[0].ToString();
    570   } else {
    571     VLOG(1) << "OnNativeDisplaysChanged(" << updated_displays.size()
    572             << ") [0]=" << updated_displays[0].ToString()
    573             << ", [1]=" << updated_displays[1].ToString();
    574   }
    575 
    576   bool internal_display_connected = false;
    577   num_connected_displays_ = updated_displays.size();
    578   mirrored_display_id_ = gfx::Display::kInvalidDisplayID;
    579   non_desktop_display_ = gfx::Display();
    580   DisplayInfoList new_display_info_list;
    581   for (DisplayInfoList::const_iterator iter = updated_displays.begin();
    582        iter != updated_displays.end();
    583        ++iter) {
    584     if (!internal_display_connected)
    585       internal_display_connected = IsInternalDisplayId(iter->id());
    586     // Mirrored monitors have the same origins.
    587     gfx::Point origin = iter->bounds_in_native().origin();
    588     if (origins.find(origin) != origins.end()) {
    589       InsertAndUpdateDisplayInfo(*iter);
    590       mirrored_display_id_ = iter->id();
    591     } else {
    592       origins.insert(origin);
    593       new_display_info_list.push_back(*iter);
    594     }
    595 
    596     const gfx::Size& resolution = iter->bounds_in_native().size();
    597     const std::vector<DisplayMode>& display_modes = iter->display_modes();
    598     // This is empty the displays are initialized from InitFromCommandLine.
    599     if (!display_modes.size())
    600       continue;
    601     std::vector<DisplayMode>::const_iterator display_modes_iter =
    602         std::find_if(display_modes.begin(),
    603                      display_modes.end(),
    604                      DisplayModeMatcher(resolution));
    605     // Update the actual resolution selected as the resolution request may fail.
    606     if (display_modes_iter == display_modes.end())
    607       display_modes_.erase(iter->id());
    608     else if (display_modes_.find(iter->id()) != display_modes_.end())
    609       display_modes_[iter->id()] = *display_modes_iter;
    610   }
    611   if (HasInternalDisplay() &&
    612       !internal_display_connected &&
    613       display_info_.find(gfx::Display::InternalDisplayId()) ==
    614       display_info_.end()) {
    615     DisplayInfo internal_display_info(
    616         gfx::Display::InternalDisplayId(),
    617         l10n_util::GetStringUTF8(IDS_ASH_INTERNAL_DISPLAY_NAME),
    618         false  /*Internal display must not have overscan */);
    619     internal_display_info.SetBounds(gfx::Rect(0, 0, 800, 600));
    620     display_info_[gfx::Display::InternalDisplayId()] = internal_display_info;
    621   }
    622   UpdateDisplays(new_display_info_list);
    623 }
    624 
    625 void DisplayManager::UpdateDisplays() {
    626   DisplayInfoList display_info_list;
    627   for (DisplayList::const_iterator iter = displays_.begin();
    628        iter != displays_.end(); ++iter) {
    629     display_info_list.push_back(GetDisplayInfo(iter->id()));
    630   }
    631   AddMirrorDisplayInfoIfAny(&display_info_list);
    632   UpdateDisplays(display_info_list);
    633 }
    634 
    635 void DisplayManager::UpdateDisplays(
    636     const std::vector<DisplayInfo>& updated_display_info_list) {
    637 #if defined(OS_WIN)
    638   DCHECK_EQ(1u, updated_display_info_list.size()) <<
    639       ": Multiple display test does not work on Windows bots. Please "
    640       "skip (don't disable) the test using SupportsMultipleDisplays()";
    641 #endif
    642 
    643   DisplayInfoList new_display_info_list = updated_display_info_list;
    644   std::sort(displays_.begin(), displays_.end(), DisplaySortFunctor());
    645   std::sort(new_display_info_list.begin(),
    646             new_display_info_list.end(),
    647             DisplayInfoSortFunctor());
    648   DisplayList removed_displays;
    649   std::map<size_t, uint32_t> display_changes;
    650   std::vector<size_t> added_display_indices;
    651 
    652   DisplayList::iterator curr_iter = displays_.begin();
    653   DisplayInfoList::const_iterator new_info_iter = new_display_info_list.begin();
    654 
    655   DisplayList new_displays;
    656 
    657   // Use the internal display or 1st as the mirror source, then scale
    658   // the root window so that it matches the external display's
    659   // resolution. This is necessary in order for scaling to work while
    660   // mirrored.
    661   int64 non_desktop_display_id = gfx::Display::kInvalidDisplayID;
    662 
    663   if (second_display_mode_ != EXTENDED && new_display_info_list.size() == 2) {
    664     bool zero_is_source =
    665         first_display_id_ == new_display_info_list[0].id() ||
    666         gfx::Display::InternalDisplayId() == new_display_info_list[0].id();
    667     if (second_display_mode_ == MIRRORING) {
    668       mirrored_display_id_ = new_display_info_list[zero_is_source ? 1 : 0].id();
    669       non_desktop_display_id = mirrored_display_id_;
    670     } else {
    671       // TODO(oshima|bshe): The virtual keyboard is currently assigned to
    672       // the 1st display.
    673       non_desktop_display_id =
    674           new_display_info_list[zero_is_source ? 0 : 1].id();
    675     }
    676   }
    677 
    678   while (curr_iter != displays_.end() ||
    679          new_info_iter != new_display_info_list.end()) {
    680     if (new_info_iter != new_display_info_list.end() &&
    681         non_desktop_display_id == new_info_iter->id()) {
    682       DisplayInfo info = *new_info_iter;
    683       info.SetOverscanInsets(gfx::Insets());
    684       InsertAndUpdateDisplayInfo(info);
    685       non_desktop_display_ =
    686           CreateDisplayFromDisplayInfoById(non_desktop_display_id);
    687       ++new_info_iter;
    688       // Remove existing external display if it is going to be used as
    689       // non desktop.
    690       if (curr_iter != displays_.end() &&
    691           curr_iter->id() == non_desktop_display_id) {
    692         removed_displays.push_back(*curr_iter);
    693         ++curr_iter;
    694       }
    695       continue;
    696     }
    697 
    698     if (curr_iter == displays_.end()) {
    699       // more displays in new list.
    700       added_display_indices.push_back(new_displays.size());
    701       InsertAndUpdateDisplayInfo(*new_info_iter);
    702       new_displays.push_back(
    703           CreateDisplayFromDisplayInfoById(new_info_iter->id()));
    704       ++new_info_iter;
    705     } else if (new_info_iter == new_display_info_list.end()) {
    706       // more displays in current list.
    707       removed_displays.push_back(*curr_iter);
    708       ++curr_iter;
    709     } else if (curr_iter->id() == new_info_iter->id()) {
    710       const gfx::Display& current_display = *curr_iter;
    711       // Copy the info because |CreateDisplayFromInfo| updates the instance.
    712       const DisplayInfo current_display_info =
    713           GetDisplayInfo(current_display.id());
    714       InsertAndUpdateDisplayInfo(*new_info_iter);
    715       gfx::Display new_display =
    716           CreateDisplayFromDisplayInfoById(new_info_iter->id());
    717       const DisplayInfo& new_display_info = GetDisplayInfo(new_display.id());
    718 
    719       uint32_t metrics = gfx::DisplayObserver::DISPLAY_METRIC_NONE;
    720 
    721       // At that point the new Display objects we have are not entirely updated,
    722       // they are missing the translation related to the Display disposition in
    723       // the layout.
    724       // Using display.bounds() and display.work_area() would fail most of the
    725       // time.
    726       if (force_bounds_changed_ || (current_display_info.bounds_in_native() !=
    727                                     new_display_info.bounds_in_native()) ||
    728           (current_display_info.size_in_pixel() !=
    729            new_display.GetSizeInPixel())) {
    730         metrics |= gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS |
    731                    gfx::DisplayObserver::DISPLAY_METRIC_WORK_AREA;
    732       }
    733 
    734       if (current_display.device_scale_factor() !=
    735           new_display.device_scale_factor()) {
    736         metrics |= gfx::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR;
    737       }
    738 
    739       if (current_display.rotation() != new_display.rotation())
    740         metrics |= gfx::DisplayObserver::DISPLAY_METRIC_ROTATION;
    741 
    742       if (metrics != gfx::DisplayObserver::DISPLAY_METRIC_NONE) {
    743         display_changes.insert(
    744             std::pair<size_t, uint32_t>(new_displays.size(), metrics));
    745       }
    746 
    747       new_display.UpdateWorkAreaFromInsets(current_display.GetWorkAreaInsets());
    748       new_displays.push_back(new_display);
    749       ++curr_iter;
    750       ++new_info_iter;
    751     } else if (curr_iter->id() < new_info_iter->id()) {
    752       // more displays in current list between ids, which means it is deleted.
    753       removed_displays.push_back(*curr_iter);
    754       ++curr_iter;
    755     } else {
    756       // more displays in new list between ids, which means it is added.
    757       added_display_indices.push_back(new_displays.size());
    758       InsertAndUpdateDisplayInfo(*new_info_iter);
    759       new_displays.push_back(
    760           CreateDisplayFromDisplayInfoById(new_info_iter->id()));
    761       ++new_info_iter;
    762     }
    763   }
    764 
    765   scoped_ptr<NonDesktopDisplayUpdater> non_desktop_display_updater(
    766       new NonDesktopDisplayUpdater(this, delegate_));
    767 
    768   // Do not update |displays_| if there's nothing to be updated. Without this,
    769   // it will not update the display layout, which causes the bug
    770   // http://crbug.com/155948.
    771   if (display_changes.empty() && added_display_indices.empty() &&
    772       removed_displays.empty()) {
    773     return;
    774   }
    775   // Clear focus if the display has been removed, but don't clear focus if
    776   // the destkop has been moved from one display to another
    777   // (mirror -> docked, docked -> single internal).
    778   bool clear_focus =
    779       !removed_displays.empty() &&
    780       !(removed_displays.size() == 1 && added_display_indices.size() == 1);
    781   if (delegate_)
    782     delegate_->PreDisplayConfigurationChange(clear_focus);
    783 
    784   size_t updated_index;
    785   if (UpdateSecondaryDisplayBoundsForLayout(&new_displays, &updated_index) &&
    786       std::find(added_display_indices.begin(),
    787                 added_display_indices.end(),
    788                 updated_index) == added_display_indices.end()) {
    789     uint32_t metrics = gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS |
    790                        gfx::DisplayObserver::DISPLAY_METRIC_WORK_AREA;
    791     if (display_changes.find(updated_index) != display_changes.end())
    792       metrics |= display_changes[updated_index];
    793 
    794     display_changes[updated_index] = metrics;
    795   }
    796 
    797   displays_ = new_displays;
    798 
    799   base::AutoReset<bool> resetter(&change_display_upon_host_resize_, false);
    800 
    801   // Temporarily add displays to be removed because display object
    802   // being removed are accessed during shutting down the root.
    803   displays_.insert(displays_.end(), removed_displays.begin(),
    804                    removed_displays.end());
    805 
    806   for (DisplayList::const_reverse_iterator iter = removed_displays.rbegin();
    807        iter != removed_displays.rend(); ++iter) {
    808     screen_ash_->NotifyDisplayRemoved(displays_.back());
    809     displays_.pop_back();
    810   }
    811   // Close the non desktop window here to avoid creating two compositor on
    812   // one display.
    813   if (!non_desktop_display_updater->enabled())
    814     non_desktop_display_updater.reset();
    815   for (std::vector<size_t>::iterator iter = added_display_indices.begin();
    816        iter != added_display_indices.end(); ++iter) {
    817     screen_ash_->NotifyDisplayAdded(displays_[*iter]);
    818   }
    819   // Create the non destkop window after all displays are added so that
    820   // it can mirror the display newly added. This can happen when switching
    821   // from dock mode to software mirror mode.
    822   non_desktop_display_updater.reset();
    823   for (std::map<size_t, uint32_t>::iterator iter = display_changes.begin();
    824        iter != display_changes.end();
    825        ++iter) {
    826     screen_ash_->NotifyMetricsChanged(displays_[iter->first], iter->second);
    827   }
    828   if (delegate_)
    829     delegate_->PostDisplayConfigurationChange();
    830 
    831 #if defined(USE_X11) && defined(OS_CHROMEOS)
    832   if (!display_changes.empty() && base::SysInfo::IsRunningOnChromeOS())
    833     ui::ClearX11DefaultRootWindow();
    834 #endif
    835 }
    836 
    837 const gfx::Display& DisplayManager::GetDisplayAt(size_t index) const {
    838   DCHECK_LT(index, displays_.size());
    839   return displays_[index];
    840 }
    841 
    842 const gfx::Display& DisplayManager::GetPrimaryDisplayCandidate() const {
    843   if (GetNumDisplays() == 1)
    844     return displays_[0];
    845   DisplayLayout layout = layout_store_->GetRegisteredDisplayLayout(
    846       GetCurrentDisplayIdPair());
    847   return GetDisplayForId(layout.primary_id);
    848 }
    849 
    850 size_t DisplayManager::GetNumDisplays() const {
    851   return displays_.size();
    852 }
    853 
    854 bool DisplayManager::IsMirrored() const {
    855   return mirrored_display_id_ != gfx::Display::kInvalidDisplayID;
    856 }
    857 
    858 const DisplayInfo& DisplayManager::GetDisplayInfo(int64 display_id) const {
    859   DCHECK_NE(gfx::Display::kInvalidDisplayID, display_id);
    860 
    861   std::map<int64, DisplayInfo>::const_iterator iter =
    862       display_info_.find(display_id);
    863   CHECK(iter != display_info_.end()) << display_id;
    864   return iter->second;
    865 }
    866 
    867 std::string DisplayManager::GetDisplayNameForId(int64 id) {
    868   if (id == gfx::Display::kInvalidDisplayID)
    869     return l10n_util::GetStringUTF8(IDS_ASH_STATUS_TRAY_UNKNOWN_DISPLAY_NAME);
    870 
    871   std::map<int64, DisplayInfo>::const_iterator iter = display_info_.find(id);
    872   if (iter != display_info_.end() && !iter->second.name().empty())
    873     return iter->second.name();
    874 
    875   return base::StringPrintf("Display %d", static_cast<int>(id));
    876 }
    877 
    878 int64 DisplayManager::GetDisplayIdForUIScaling() const {
    879   // UI Scaling is effective only on internal display.
    880   int64 display_id = gfx::Display::InternalDisplayId();
    881 #if defined(OS_WIN)
    882   display_id = first_display_id();
    883 #endif
    884   return display_id;
    885 }
    886 
    887 void DisplayManager::SetMirrorMode(bool mirrored) {
    888   if (num_connected_displays() <= 1)
    889     return;
    890 
    891 #if defined(OS_CHROMEOS)
    892   if (base::SysInfo::IsRunningOnChromeOS()) {
    893     ui::MultipleDisplayState new_state =
    894         mirrored ? ui::MULTIPLE_DISPLAY_STATE_DUAL_MIRROR :
    895                    ui::MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED;
    896     Shell::GetInstance()->display_configurator()->SetDisplayMode(new_state);
    897     return;
    898   }
    899 #endif
    900   // This is fallback path to emulate mirroroing on desktop.
    901   SetSecondDisplayMode(mirrored ? MIRRORING : EXTENDED);
    902   DisplayInfoList display_info_list;
    903   int count = 0;
    904   for (std::map<int64, DisplayInfo>::const_iterator iter =
    905            display_info_.begin();
    906        count < 2; ++iter, ++count) {
    907     display_info_list.push_back(GetDisplayInfo(iter->second.id()));
    908   }
    909   UpdateDisplays(display_info_list);
    910 #if defined(OS_CHROMEOS)
    911   if (Shell::GetInstance()->display_configurator_animation()) {
    912     Shell::GetInstance()->display_configurator_animation()->
    913         StartFadeInAnimation();
    914   }
    915 #endif
    916 }
    917 
    918 void DisplayManager::AddRemoveDisplay() {
    919   DCHECK(!displays_.empty());
    920   std::vector<DisplayInfo> new_display_info_list;
    921   const DisplayInfo& first_display = GetDisplayInfo(displays_[0].id());
    922   new_display_info_list.push_back(first_display);
    923   // Add if there is only one display connected.
    924   if (num_connected_displays() == 1) {
    925     // Layout the 2nd display below the primary as with the real device.
    926     gfx::Rect host_bounds = first_display.bounds_in_native();
    927     new_display_info_list.push_back(DisplayInfo::CreateFromSpec(
    928         base::StringPrintf(
    929             "%d+%d-500x400", host_bounds.x(), host_bounds.bottom())));
    930   }
    931   num_connected_displays_ = new_display_info_list.size();
    932   mirrored_display_id_ = gfx::Display::kInvalidDisplayID;
    933   non_desktop_display_ = gfx::Display();
    934   UpdateDisplays(new_display_info_list);
    935 }
    936 
    937 void DisplayManager::ToggleDisplayScaleFactor() {
    938   DCHECK(!displays_.empty());
    939   std::vector<DisplayInfo> new_display_info_list;
    940   for (DisplayList::const_iterator iter = displays_.begin();
    941        iter != displays_.end(); ++iter) {
    942     DisplayInfo display_info = GetDisplayInfo(iter->id());
    943     display_info.set_device_scale_factor(
    944         display_info.device_scale_factor() == 1.0f ? 2.0f : 1.0f);
    945     new_display_info_list.push_back(display_info);
    946   }
    947   AddMirrorDisplayInfoIfAny(&new_display_info_list);
    948   UpdateDisplays(new_display_info_list);
    949 }
    950 
    951 #if defined(OS_CHROMEOS)
    952 void DisplayManager::SetSoftwareMirroring(bool enabled) {
    953   // TODO(oshima|bshe): Support external display on the system
    954   // that has virtual keyboard display.
    955   if (second_display_mode_ == VIRTUAL_KEYBOARD)
    956     return;
    957   SetSecondDisplayMode(enabled ? MIRRORING : EXTENDED);
    958 }
    959 
    960 bool DisplayManager::SoftwareMirroringEnabled() const {
    961   return software_mirroring_enabled();
    962 }
    963 #endif
    964 
    965 void DisplayManager::SetSecondDisplayMode(SecondDisplayMode mode) {
    966   second_display_mode_ = mode;
    967   mirrored_display_id_ = gfx::Display::kInvalidDisplayID;
    968   non_desktop_display_ = gfx::Display();
    969 }
    970 
    971 bool DisplayManager::UpdateDisplayBounds(int64 display_id,
    972                                          const gfx::Rect& new_bounds) {
    973   if (change_display_upon_host_resize_) {
    974     display_info_[display_id].SetBounds(new_bounds);
    975     // Don't notify observers if the mirrored window has changed.
    976     if (software_mirroring_enabled() && mirrored_display_id_ == display_id)
    977       return false;
    978     gfx::Display* display = FindDisplayForId(display_id);
    979     display->SetSize(display_info_[display_id].size_in_pixel());
    980     screen_ash_->NotifyMetricsChanged(
    981         *display, gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS);
    982     return true;
    983   }
    984   return false;
    985 }
    986 
    987 void DisplayManager::CreateMirrorWindowIfAny() {
    988   NonDesktopDisplayUpdater updater(this, delegate_);
    989 }
    990 
    991 void DisplayManager::CreateScreenForShutdown() const {
    992   bool native_is_ash =
    993       gfx::Screen::GetScreenByType(gfx::SCREEN_TYPE_NATIVE) ==
    994       screen_ash_.get();
    995   delete screen_for_shutdown;
    996   screen_for_shutdown = screen_ash_->CloneForShutdown();
    997   gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_ALTERNATE,
    998                                  screen_for_shutdown);
    999   if (native_is_ash) {
   1000     gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE,
   1001                                    screen_for_shutdown);
   1002   }
   1003 }
   1004 
   1005 gfx::Display* DisplayManager::FindDisplayForId(int64 id) {
   1006   for (DisplayList::iterator iter = displays_.begin();
   1007        iter != displays_.end(); ++iter) {
   1008     if ((*iter).id() == id)
   1009       return &(*iter);
   1010   }
   1011   DLOG(WARNING) << "Could not find display:" << id;
   1012   return NULL;
   1013 }
   1014 
   1015 void DisplayManager::AddMirrorDisplayInfoIfAny(
   1016     std::vector<DisplayInfo>* display_info_list) {
   1017   if (software_mirroring_enabled() && IsMirrored())
   1018     display_info_list->push_back(GetDisplayInfo(mirrored_display_id_));
   1019 }
   1020 
   1021 void DisplayManager::InsertAndUpdateDisplayInfo(const DisplayInfo& new_info) {
   1022   std::map<int64, DisplayInfo>::iterator info =
   1023       display_info_.find(new_info.id());
   1024   if (info != display_info_.end()) {
   1025     info->second.Copy(new_info);
   1026   } else {
   1027     display_info_[new_info.id()] = new_info;
   1028     display_info_[new_info.id()].set_native(false);
   1029   }
   1030   display_info_[new_info.id()].UpdateDisplaySize();
   1031 
   1032   OnDisplayInfoUpdated(display_info_[new_info.id()]);
   1033 }
   1034 
   1035 void DisplayManager::OnDisplayInfoUpdated(const DisplayInfo& display_info) {
   1036 #if defined(OS_CHROMEOS)
   1037   ui::ColorCalibrationProfile color_profile = display_info.color_profile();
   1038   if (color_profile != ui::COLOR_PROFILE_STANDARD) {
   1039     Shell::GetInstance()->display_configurator()->SetColorCalibrationProfile(
   1040         display_info.id(), color_profile);
   1041   }
   1042 #endif
   1043 }
   1044 
   1045 gfx::Display DisplayManager::CreateDisplayFromDisplayInfoById(int64 id) {
   1046   DCHECK(display_info_.find(id) != display_info_.end());
   1047   const DisplayInfo& display_info = display_info_[id];
   1048 
   1049   gfx::Display new_display(display_info.id());
   1050   gfx::Rect bounds_in_native(display_info.size_in_pixel());
   1051   float device_scale_factor = display_info.GetEffectiveDeviceScaleFactor();
   1052 
   1053   // Simply set the origin to (0,0).  The primary display's origin is
   1054   // always (0,0) and the secondary display's bounds will be updated
   1055   // in |UpdateSecondaryDisplayBoundsForLayout| called in |UpdateDisplay|.
   1056   new_display.SetScaleAndBounds(
   1057       device_scale_factor, gfx::Rect(bounds_in_native.size()));
   1058   new_display.set_rotation(display_info.rotation());
   1059   new_display.set_touch_support(display_info.touch_support());
   1060   return new_display;
   1061 }
   1062 
   1063 bool DisplayManager::UpdateSecondaryDisplayBoundsForLayout(
   1064     DisplayList* displays,
   1065     size_t* updated_index) const {
   1066   if (displays->size() != 2U)
   1067     return false;
   1068 
   1069   int64 id_at_zero = displays->at(0).id();
   1070   DisplayIdPair pair =
   1071       (id_at_zero == first_display_id_ ||
   1072        id_at_zero == gfx::Display::InternalDisplayId()) ?
   1073       std::make_pair(id_at_zero, displays->at(1).id()) :
   1074       std::make_pair(displays->at(1).id(), id_at_zero);
   1075   DisplayLayout layout =
   1076       layout_store_->ComputeDisplayLayoutForDisplayIdPair(pair);
   1077 
   1078   // Ignore if a user has a old format (should be extremely rare)
   1079   // and this will be replaced with DCHECK.
   1080   if (layout.primary_id != gfx::Display::kInvalidDisplayID) {
   1081     size_t primary_index, secondary_index;
   1082     if (displays->at(0).id() == layout.primary_id) {
   1083       primary_index = 0;
   1084       secondary_index = 1;
   1085     } else {
   1086       primary_index = 1;
   1087       secondary_index = 0;
   1088     }
   1089     // This function may be called before the secondary display is
   1090     // registered. The bounds is empty in that case and will
   1091     // return true.
   1092     gfx::Rect bounds =
   1093         GetDisplayForId(displays->at(secondary_index).id()).bounds();
   1094     UpdateDisplayBoundsForLayout(
   1095         layout, displays->at(primary_index), &displays->at(secondary_index));
   1096     *updated_index = secondary_index;
   1097     return bounds != displays->at(secondary_index).bounds();
   1098   }
   1099   return false;
   1100 }
   1101 
   1102 // static
   1103 void DisplayManager::UpdateDisplayBoundsForLayout(
   1104     const DisplayLayout& layout,
   1105     const gfx::Display& primary_display,
   1106     gfx::Display* secondary_display) {
   1107   DCHECK_EQ("0,0", primary_display.bounds().origin().ToString());
   1108 
   1109   const gfx::Rect& primary_bounds = primary_display.bounds();
   1110   const gfx::Rect& secondary_bounds = secondary_display->bounds();
   1111   gfx::Point new_secondary_origin = primary_bounds.origin();
   1112 
   1113   DisplayLayout::Position position = layout.position;
   1114 
   1115   // Ignore the offset in case the secondary display doesn't share edges with
   1116   // the primary display.
   1117   int offset = layout.offset;
   1118   if (position == DisplayLayout::TOP || position == DisplayLayout::BOTTOM) {
   1119     offset = std::min(
   1120         offset, primary_bounds.width() - kMinimumOverlapForInvalidOffset);
   1121     offset = std::max(
   1122         offset, -secondary_bounds.width() + kMinimumOverlapForInvalidOffset);
   1123   } else {
   1124     offset = std::min(
   1125         offset, primary_bounds.height() - kMinimumOverlapForInvalidOffset);
   1126     offset = std::max(
   1127         offset, -secondary_bounds.height() + kMinimumOverlapForInvalidOffset);
   1128   }
   1129   switch (position) {
   1130     case DisplayLayout::TOP:
   1131       new_secondary_origin.Offset(offset, -secondary_bounds.height());
   1132       break;
   1133     case DisplayLayout::RIGHT:
   1134       new_secondary_origin.Offset(primary_bounds.width(), offset);
   1135       break;
   1136     case DisplayLayout::BOTTOM:
   1137       new_secondary_origin.Offset(offset, primary_bounds.height());
   1138       break;
   1139     case DisplayLayout::LEFT:
   1140       new_secondary_origin.Offset(-secondary_bounds.width(), offset);
   1141       break;
   1142   }
   1143   gfx::Insets insets = secondary_display->GetWorkAreaInsets();
   1144   secondary_display->set_bounds(
   1145       gfx::Rect(new_secondary_origin, secondary_bounds.size()));
   1146   secondary_display->UpdateWorkAreaFromInsets(insets);
   1147 }
   1148 
   1149 }  // namespace ash
   1150