Home | History | Annotate | Download | only in chromeos
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "ui/display/chromeos/display_configurator.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/command_line.h"
      9 #include "base/logging.h"
     10 #include "base/strings/string_number_conversions.h"
     11 #include "base/strings/stringprintf.h"
     12 #include "base/sys_info.h"
     13 #include "base/time/time.h"
     14 #include "ui/display/display_switches.h"
     15 #include "ui/display/types/display_mode.h"
     16 #include "ui/display/types/display_snapshot.h"
     17 #include "ui/display/types/native_display_delegate.h"
     18 
     19 namespace ui {
     20 
     21 namespace {
     22 
     23 typedef std::vector<const DisplayMode*> DisplayModeList;
     24 
     25 // The delay to perform configuration after RRNotify. See the comment for
     26 // |configure_timer_|.
     27 const int kConfigureDelayMs = 500;
     28 
     29 // The delay spent before reading the display configuration after coming out of
     30 // suspend. While coming out of suspend the display state may be updating. This
     31 // is used to wait until the hardware had a chance to update the display state
     32 // such that we read an up to date state.
     33 const int kResumeDelayMs = 500;
     34 
     35 // Returns a string describing |state|.
     36 std::string DisplayPowerStateToString(chromeos::DisplayPowerState state) {
     37   switch (state) {
     38     case chromeos::DISPLAY_POWER_ALL_ON:
     39       return "ALL_ON";
     40     case chromeos::DISPLAY_POWER_ALL_OFF:
     41       return "ALL_OFF";
     42     case chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON:
     43       return "INTERNAL_OFF_EXTERNAL_ON";
     44     case chromeos::DISPLAY_POWER_INTERNAL_ON_EXTERNAL_OFF:
     45       return "INTERNAL_ON_EXTERNAL_OFF";
     46     default:
     47       return "unknown (" + base::IntToString(state) + ")";
     48   }
     49 }
     50 
     51 // Returns a string describing |state|.
     52 std::string DisplayStateToString(MultipleDisplayState state) {
     53   switch (state) {
     54     case MULTIPLE_DISPLAY_STATE_INVALID:
     55       return "INVALID";
     56     case MULTIPLE_DISPLAY_STATE_HEADLESS:
     57       return "HEADLESS";
     58     case MULTIPLE_DISPLAY_STATE_SINGLE:
     59       return "SINGLE";
     60     case MULTIPLE_DISPLAY_STATE_DUAL_MIRROR:
     61       return "DUAL_MIRROR";
     62     case MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED:
     63       return "DUAL_EXTENDED";
     64   }
     65   NOTREACHED() << "Unknown state " << state;
     66   return "INVALID";
     67 }
     68 
     69 // Returns the number of displays in |displays| that should be turned on, per
     70 // |state|.  If |display_power| is non-NULL, it is updated to contain the
     71 // on/off state of each corresponding entry in |displays|.
     72 int GetDisplayPower(
     73     const std::vector<DisplayConfigurator::DisplayState>& display_states,
     74     chromeos::DisplayPowerState state,
     75     std::vector<bool>* display_power) {
     76   int num_on_displays = 0;
     77   if (display_power)
     78     display_power->resize(display_states.size());
     79 
     80   for (size_t i = 0; i < display_states.size(); ++i) {
     81     bool internal =
     82         display_states[i].display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL;
     83     bool on =
     84         state == chromeos::DISPLAY_POWER_ALL_ON ||
     85         (state == chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON &&
     86          !internal) ||
     87         (state == chromeos::DISPLAY_POWER_INTERNAL_ON_EXTERNAL_OFF && internal);
     88     if (display_power)
     89       (*display_power)[i] = on;
     90     if (on)
     91       num_on_displays++;
     92   }
     93   return num_on_displays;
     94 }
     95 
     96 }  // namespace
     97 
     98 
     99 const int DisplayConfigurator::kSetDisplayPowerNoFlags = 0;
    100 const int DisplayConfigurator::kSetDisplayPowerForceProbe = 1 << 0;
    101 const int
    102 DisplayConfigurator::kSetDisplayPowerOnlyIfSingleInternalDisplay = 1 << 1;
    103 
    104 DisplayConfigurator::DisplayState::DisplayState()
    105     : display(NULL),
    106       selected_mode(NULL),
    107       mirror_mode(NULL) {}
    108 
    109 bool DisplayConfigurator::TestApi::TriggerConfigureTimeout() {
    110   if (configurator_->configure_timer_.IsRunning()) {
    111     configurator_->configure_timer_.user_task().Run();
    112     configurator_->configure_timer_.Stop();
    113     return true;
    114   } else {
    115     return false;
    116   }
    117 }
    118 
    119 // static
    120 const DisplayMode* DisplayConfigurator::FindDisplayModeMatchingSize(
    121     const DisplaySnapshot& display,
    122     const gfx::Size& size) {
    123   const DisplayMode* best_mode = NULL;
    124   for (DisplayModeList::const_iterator it = display.modes().begin();
    125        it != display.modes().end();
    126        ++it) {
    127     const DisplayMode* mode = *it;
    128 
    129     if (mode->size() != size)
    130       continue;
    131 
    132     if (!best_mode) {
    133       best_mode = mode;
    134       continue;
    135     }
    136 
    137     if (mode->is_interlaced()) {
    138       if (!best_mode->is_interlaced())
    139         continue;
    140     } else {
    141       // Reset the best rate if the non interlaced is
    142       // found the first time.
    143       if (best_mode->is_interlaced()) {
    144         best_mode = mode;
    145         continue;
    146       }
    147     }
    148     if (mode->refresh_rate() < best_mode->refresh_rate())
    149       continue;
    150 
    151     best_mode = mode;
    152   }
    153 
    154   return best_mode;
    155 }
    156 
    157 DisplayConfigurator::DisplayConfigurator()
    158     : state_controller_(NULL),
    159       mirroring_controller_(NULL),
    160       is_panel_fitting_enabled_(false),
    161       configure_display_(base::SysInfo::IsRunningOnChromeOS()),
    162       display_state_(MULTIPLE_DISPLAY_STATE_INVALID),
    163       requested_power_state_(chromeos::DISPLAY_POWER_ALL_ON),
    164       current_power_state_(chromeos::DISPLAY_POWER_ALL_ON),
    165       next_display_protection_client_id_(1) {}
    166 
    167 DisplayConfigurator::~DisplayConfigurator() {
    168   if (native_display_delegate_)
    169     native_display_delegate_->RemoveObserver(this);
    170 }
    171 
    172 void DisplayConfigurator::SetDelegateForTesting(
    173     scoped_ptr<NativeDisplayDelegate> display_delegate) {
    174   DCHECK(!native_display_delegate_);
    175 
    176   native_display_delegate_ = display_delegate.Pass();
    177   configure_display_ = true;
    178 }
    179 
    180 void DisplayConfigurator::SetInitialDisplayPower(
    181     chromeos::DisplayPowerState power_state) {
    182   DCHECK_EQ(display_state_, MULTIPLE_DISPLAY_STATE_INVALID);
    183   requested_power_state_ = current_power_state_ = power_state;
    184 }
    185 
    186 void DisplayConfigurator::Init(bool is_panel_fitting_enabled) {
    187   is_panel_fitting_enabled_ = is_panel_fitting_enabled;
    188   if (!configure_display_)
    189     return;
    190 
    191   // If the delegate is already initialized don't update it (For example, tests
    192   // set their own delegates).
    193   if (!native_display_delegate_) {
    194     native_display_delegate_ = CreatePlatformNativeDisplayDelegate();
    195     native_display_delegate_->AddObserver(this);
    196   }
    197 }
    198 
    199 void DisplayConfigurator::ForceInitialConfigure(
    200     uint32_t background_color_argb) {
    201   if (!configure_display_)
    202     return;
    203 
    204   native_display_delegate_->GrabServer();
    205   native_display_delegate_->Initialize();
    206 
    207   UpdateCachedDisplays();
    208   if (cached_displays_.size() > 1 && background_color_argb)
    209     native_display_delegate_->SetBackgroundColor(background_color_argb);
    210   const MultipleDisplayState new_state = ChooseDisplayState(
    211       requested_power_state_);
    212   const bool success = EnterStateOrFallBackToSoftwareMirroring(
    213       new_state, requested_power_state_);
    214 
    215   // Force the DPMS on chrome startup as the driver doesn't always detect
    216   // that all displays are on when signing out.
    217   native_display_delegate_->ForceDPMSOn();
    218   native_display_delegate_->UngrabServer();
    219   NotifyObservers(success, new_state);
    220 }
    221 
    222 bool DisplayConfigurator::IsMirroring() const {
    223   return display_state_ == MULTIPLE_DISPLAY_STATE_DUAL_MIRROR ||
    224       (mirroring_controller_ &&
    225        mirroring_controller_->SoftwareMirroringEnabled());
    226 }
    227 
    228 bool DisplayConfigurator::ApplyProtections(const ContentProtections& requests) {
    229   for (DisplayStateList::const_iterator it = cached_displays_.begin();
    230        it != cached_displays_.end();
    231        ++it) {
    232     uint32_t all_desired = 0;
    233 
    234     // In mirror mode, protection request of all displays need to be fulfilled.
    235     // In non-mirror mode, only request of client's display needs to be
    236     // fulfilled.
    237     ContentProtections::const_iterator request_it;
    238     if (IsMirroring()) {
    239       for (request_it = requests.begin();
    240            request_it != requests.end();
    241            ++request_it)
    242         all_desired |= request_it->second;
    243     } else {
    244       request_it = requests.find(it->display->display_id());
    245       if (request_it != requests.end())
    246         all_desired = request_it->second;
    247     }
    248 
    249     switch (it->display->type()) {
    250       case DISPLAY_CONNECTION_TYPE_UNKNOWN:
    251         return false;
    252       // DisplayPort, DVI, and HDMI all support HDCP.
    253       case DISPLAY_CONNECTION_TYPE_DISPLAYPORT:
    254       case DISPLAY_CONNECTION_TYPE_DVI:
    255       case DISPLAY_CONNECTION_TYPE_HDMI: {
    256         HDCPState current_state;
    257         // Need to poll the driver for updates since other applications may
    258         // have updated the state.
    259         if (!native_display_delegate_->GetHDCPState(*it->display,
    260                                                     &current_state))
    261           return false;
    262         bool current_desired = (current_state != HDCP_STATE_UNDESIRED);
    263         bool new_desired = (all_desired & CONTENT_PROTECTION_METHOD_HDCP);
    264         // Don't enable again if HDCP is already active. Some buggy drivers
    265         // may disable and enable if setting "desired" in active state.
    266         if (current_desired != new_desired) {
    267           HDCPState new_state =
    268               new_desired ? HDCP_STATE_DESIRED : HDCP_STATE_UNDESIRED;
    269           if (!native_display_delegate_->SetHDCPState(*it->display, new_state))
    270             return false;
    271         }
    272         break;
    273       }
    274       case DISPLAY_CONNECTION_TYPE_INTERNAL:
    275       case DISPLAY_CONNECTION_TYPE_VGA:
    276       case DISPLAY_CONNECTION_TYPE_NETWORK:
    277         // No protections for these types. Do nothing.
    278         break;
    279       case DISPLAY_CONNECTION_TYPE_NONE:
    280         NOTREACHED();
    281         break;
    282     }
    283   }
    284 
    285   return true;
    286 }
    287 
    288 DisplayConfigurator::ContentProtectionClientId
    289 DisplayConfigurator::RegisterContentProtectionClient() {
    290   if (!configure_display_)
    291     return kInvalidClientId;
    292 
    293   return next_display_protection_client_id_++;
    294 }
    295 
    296 void DisplayConfigurator::UnregisterContentProtectionClient(
    297     ContentProtectionClientId client_id) {
    298   client_protection_requests_.erase(client_id);
    299 
    300   ContentProtections protections;
    301   for (ProtectionRequests::const_iterator it =
    302            client_protection_requests_.begin();
    303        it != client_protection_requests_.end();
    304        ++it) {
    305     for (ContentProtections::const_iterator it2 = it->second.begin();
    306          it2 != it->second.end();
    307          ++it2) {
    308       protections[it2->first] |= it2->second;
    309     }
    310   }
    311 
    312   ApplyProtections(protections);
    313 }
    314 
    315 bool DisplayConfigurator::QueryContentProtectionStatus(
    316     ContentProtectionClientId client_id,
    317     int64_t display_id,
    318     uint32_t* link_mask,
    319     uint32_t* protection_mask) {
    320   if (!configure_display_)
    321     return false;
    322 
    323   uint32_t enabled = 0;
    324   uint32_t unfulfilled = 0;
    325   *link_mask = 0;
    326   for (DisplayStateList::const_iterator it = cached_displays_.begin();
    327        it != cached_displays_.end();
    328        ++it) {
    329     // Query display if it is in mirror mode or client on the same display.
    330     if (!IsMirroring() && it->display->display_id() != display_id)
    331       continue;
    332 
    333     *link_mask |= it->display->type();
    334     switch (it->display->type()) {
    335       case DISPLAY_CONNECTION_TYPE_UNKNOWN:
    336         return false;
    337       // DisplayPort, DVI, and HDMI all support HDCP.
    338       case DISPLAY_CONNECTION_TYPE_DISPLAYPORT:
    339       case DISPLAY_CONNECTION_TYPE_DVI:
    340       case DISPLAY_CONNECTION_TYPE_HDMI: {
    341         HDCPState state;
    342         if (!native_display_delegate_->GetHDCPState(*it->display, &state))
    343           return false;
    344         if (state == HDCP_STATE_ENABLED)
    345           enabled |= CONTENT_PROTECTION_METHOD_HDCP;
    346         else
    347           unfulfilled |= CONTENT_PROTECTION_METHOD_HDCP;
    348         break;
    349       }
    350       case DISPLAY_CONNECTION_TYPE_INTERNAL:
    351       case DISPLAY_CONNECTION_TYPE_VGA:
    352       case DISPLAY_CONNECTION_TYPE_NETWORK:
    353         // No protections for these types. Do nothing.
    354         break;
    355       case DISPLAY_CONNECTION_TYPE_NONE:
    356         NOTREACHED();
    357         break;
    358     }
    359   }
    360 
    361   // Don't reveal protections requested by other clients.
    362   ProtectionRequests::iterator it = client_protection_requests_.find(client_id);
    363   if (it != client_protection_requests_.end()) {
    364     uint32_t requested_mask = 0;
    365     if (it->second.find(display_id) != it->second.end())
    366       requested_mask = it->second[display_id];
    367     *protection_mask = enabled & ~unfulfilled & requested_mask;
    368   } else {
    369     *protection_mask = 0;
    370   }
    371   return true;
    372 }
    373 
    374 bool DisplayConfigurator::EnableContentProtection(
    375     ContentProtectionClientId client_id,
    376     int64_t display_id,
    377     uint32_t desired_method_mask) {
    378   if (!configure_display_)
    379     return false;
    380 
    381   ContentProtections protections;
    382   for (ProtectionRequests::const_iterator it =
    383            client_protection_requests_.begin();
    384        it != client_protection_requests_.end();
    385        ++it) {
    386     for (ContentProtections::const_iterator it2 = it->second.begin();
    387          it2 != it->second.end();
    388          ++it2) {
    389       if (it->first == client_id && it2->first == display_id)
    390         continue;
    391       protections[it2->first] |= it2->second;
    392     }
    393   }
    394   protections[display_id] |= desired_method_mask;
    395 
    396   if (!ApplyProtections(protections))
    397     return false;
    398 
    399   if (desired_method_mask == CONTENT_PROTECTION_METHOD_NONE) {
    400     if (client_protection_requests_.find(client_id) !=
    401         client_protection_requests_.end()) {
    402       client_protection_requests_[client_id].erase(display_id);
    403       if (client_protection_requests_[client_id].size() == 0)
    404         client_protection_requests_.erase(client_id);
    405     }
    406   } else {
    407     client_protection_requests_[client_id][display_id] = desired_method_mask;
    408   }
    409 
    410   return true;
    411 }
    412 
    413 std::vector<ui::ColorCalibrationProfile>
    414 DisplayConfigurator::GetAvailableColorCalibrationProfiles(int64_t display_id) {
    415   if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
    416           switches::kDisableDisplayColorCalibration)) {
    417     for (size_t i = 0; i < cached_displays_.size(); ++i) {
    418       if (cached_displays_[i].display &&
    419           cached_displays_[i].display->display_id() == display_id) {
    420         return native_display_delegate_->GetAvailableColorCalibrationProfiles(
    421             *cached_displays_[i].display);
    422       }
    423     }
    424   }
    425 
    426   return std::vector<ui::ColorCalibrationProfile>();
    427 }
    428 
    429 bool DisplayConfigurator::SetColorCalibrationProfile(
    430     int64_t display_id,
    431     ui::ColorCalibrationProfile new_profile) {
    432   for (size_t i = 0; i < cached_displays_.size(); ++i) {
    433     if (cached_displays_[i].display &&
    434         cached_displays_[i].display->display_id() == display_id) {
    435       return native_display_delegate_->SetColorCalibrationProfile(
    436           *cached_displays_[i].display, new_profile);
    437     }
    438   }
    439 
    440   return false;
    441 }
    442 
    443 void DisplayConfigurator::PrepareForExit() {
    444   configure_display_ = false;
    445 }
    446 
    447 bool DisplayConfigurator::SetDisplayPower(
    448     chromeos::DisplayPowerState power_state,
    449     int flags) {
    450   if (!configure_display_)
    451     return false;
    452 
    453   VLOG(1) << "SetDisplayPower: power_state="
    454           << DisplayPowerStateToString(power_state) << " flags=" << flags
    455           << ", configure timer="
    456           << (configure_timer_.IsRunning() ? "Running" : "Stopped");
    457   if (power_state == current_power_state_ &&
    458       !(flags & kSetDisplayPowerForceProbe))
    459     return true;
    460 
    461   native_display_delegate_->GrabServer();
    462   UpdateCachedDisplays();
    463 
    464   const MultipleDisplayState new_state = ChooseDisplayState(power_state);
    465   bool attempted_change = false;
    466   bool success = false;
    467 
    468   bool only_if_single_internal_display =
    469       flags & kSetDisplayPowerOnlyIfSingleInternalDisplay;
    470   bool single_internal_display =
    471       cached_displays_.size() == 1 &&
    472       cached_displays_[0].display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL;
    473   if (single_internal_display || !only_if_single_internal_display) {
    474     success = EnterStateOrFallBackToSoftwareMirroring(new_state, power_state);
    475     attempted_change = true;
    476 
    477     // Force the DPMS on since the driver doesn't always detect that it
    478     // should turn on. This is needed when coming back from idle suspend.
    479     if (success && power_state != chromeos::DISPLAY_POWER_ALL_OFF)
    480       native_display_delegate_->ForceDPMSOn();
    481   }
    482 
    483   native_display_delegate_->UngrabServer();
    484   if (attempted_change)
    485     NotifyObservers(success, new_state);
    486   return success;
    487 }
    488 
    489 bool DisplayConfigurator::SetDisplayMode(MultipleDisplayState new_state) {
    490   if (!configure_display_)
    491     return false;
    492 
    493   VLOG(1) << "SetDisplayMode: state=" << DisplayStateToString(new_state);
    494   if (display_state_ == new_state) {
    495     // Cancel software mirroring if the state is moving from
    496     // MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED to
    497     // MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED.
    498     if (mirroring_controller_ &&
    499         new_state == MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED)
    500       mirroring_controller_->SetSoftwareMirroring(false);
    501     NotifyObservers(true, new_state);
    502     return true;
    503   }
    504 
    505   native_display_delegate_->GrabServer();
    506   UpdateCachedDisplays();
    507   const bool success = EnterStateOrFallBackToSoftwareMirroring(
    508       new_state, requested_power_state_);
    509   native_display_delegate_->UngrabServer();
    510 
    511   NotifyObservers(success, new_state);
    512   return success;
    513 }
    514 
    515 void DisplayConfigurator::OnConfigurationChanged() {
    516   // Configure displays with |kConfigureDelayMs| delay,
    517   // so that time-consuming ConfigureDisplays() won't be called multiple times.
    518   if (configure_timer_.IsRunning()) {
    519     // Note: when the timer is running it is possible that a different task
    520     // (SetDisplayPower()) is scheduled. In these cases, prefer the already
    521     // scheduled task to ConfigureDisplays() since ConfigureDisplays() performs
    522     // only basic configuration while SetDisplayPower() will perform additional
    523     // operations.
    524     configure_timer_.Reset();
    525   } else {
    526     configure_timer_.Start(
    527         FROM_HERE,
    528         base::TimeDelta::FromMilliseconds(kConfigureDelayMs),
    529         this,
    530         &DisplayConfigurator::ConfigureDisplays);
    531   }
    532 }
    533 
    534 void DisplayConfigurator::AddObserver(Observer* observer) {
    535   observers_.AddObserver(observer);
    536 }
    537 
    538 void DisplayConfigurator::RemoveObserver(Observer* observer) {
    539   observers_.RemoveObserver(observer);
    540 }
    541 
    542 void DisplayConfigurator::SuspendDisplays() {
    543   // If the display is off due to user inactivity and there's only a single
    544   // internal display connected, switch to the all-on state before
    545   // suspending.  This shouldn't be very noticeable to the user since the
    546   // backlight is off at this point, and doing this lets us resume directly
    547   // into the "on" state, which greatly reduces resume times.
    548   if (requested_power_state_ == chromeos::DISPLAY_POWER_ALL_OFF) {
    549     SetDisplayPower(chromeos::DISPLAY_POWER_ALL_ON,
    550                     kSetDisplayPowerOnlyIfSingleInternalDisplay);
    551 
    552     // We need to make sure that the monitor configuration we just did actually
    553     // completes before we return, because otherwise the X message could be
    554     // racing with the HandleSuspendReadiness message.
    555     native_display_delegate_->SyncWithServer();
    556   }
    557 }
    558 
    559 void DisplayConfigurator::ResumeDisplays() {
    560   // Force probing to ensure that we pick up any changes that were made
    561   // while the system was suspended.
    562   configure_timer_.Start(
    563       FROM_HERE,
    564       base::TimeDelta::FromMilliseconds(kResumeDelayMs),
    565       base::Bind(base::IgnoreResult(&DisplayConfigurator::SetDisplayPower),
    566                  base::Unretained(this),
    567                  requested_power_state_,
    568                  kSetDisplayPowerForceProbe));
    569 }
    570 
    571 void DisplayConfigurator::UpdateCachedDisplays() {
    572   std::vector<DisplaySnapshot*> snapshots =
    573       native_display_delegate_->GetDisplays();
    574 
    575   cached_displays_.clear();
    576   for (size_t i = 0; i < snapshots.size(); ++i) {
    577     DisplayState display_state;
    578     display_state.display = snapshots[i];
    579     cached_displays_.push_back(display_state);
    580   }
    581 
    582   // Set |selected_mode| fields.
    583   for (size_t i = 0; i < cached_displays_.size(); ++i) {
    584     DisplayState* display_state = &cached_displays_[i];
    585     if (display_state->display->has_proper_display_id()) {
    586       gfx::Size size;
    587       if (state_controller_ &&
    588           state_controller_->GetResolutionForDisplayId(
    589               display_state->display->display_id(), &size)) {
    590         display_state->selected_mode =
    591             FindDisplayModeMatchingSize(*display_state->display, size);
    592       }
    593     }
    594     // Fall back to native mode.
    595     if (!display_state->selected_mode)
    596       display_state->selected_mode = display_state->display->native_mode();
    597   }
    598 
    599   // Set |mirror_mode| fields.
    600   if (cached_displays_.size() == 2) {
    601     bool one_is_internal =
    602         cached_displays_[0].display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL;
    603     bool two_is_internal =
    604         cached_displays_[1].display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL;
    605     int internal_displays =
    606         (one_is_internal ? 1 : 0) + (two_is_internal ? 1 : 0);
    607     DCHECK_LT(internal_displays, 2);
    608     LOG_IF(WARNING, internal_displays == 2)
    609         << "Two internal displays detected.";
    610 
    611     bool can_mirror = false;
    612     for (int attempt = 0; !can_mirror && attempt < 2; ++attempt) {
    613       // Try preserving external display's aspect ratio on the first attempt.
    614       // If that fails, fall back to the highest matching resolution.
    615       bool preserve_aspect = attempt == 0;
    616 
    617       if (internal_displays == 1) {
    618         if (one_is_internal) {
    619           can_mirror = FindMirrorMode(&cached_displays_[0],
    620                                       &cached_displays_[1],
    621                                       is_panel_fitting_enabled_,
    622                                       preserve_aspect);
    623         } else {
    624           DCHECK(two_is_internal);
    625           can_mirror = FindMirrorMode(&cached_displays_[1],
    626                                       &cached_displays_[0],
    627                                       is_panel_fitting_enabled_,
    628                                       preserve_aspect);
    629         }
    630       } else {  // if (internal_displays == 0)
    631         // No panel fitting for external displays, so fall back to exact match.
    632         can_mirror = FindMirrorMode(
    633             &cached_displays_[0], &cached_displays_[1], false, preserve_aspect);
    634         if (!can_mirror && preserve_aspect) {
    635           // FindMirrorMode() will try to preserve aspect ratio of what it
    636           // thinks is external display, so if it didn't succeed with one, maybe
    637           // it will succeed with the other.  This way we will have the correct
    638           // aspect ratio on at least one of them.
    639           can_mirror = FindMirrorMode(&cached_displays_[1],
    640                                       &cached_displays_[0],
    641                                       false,
    642                                       preserve_aspect);
    643         }
    644       }
    645     }
    646   }
    647 }
    648 
    649 bool DisplayConfigurator::FindMirrorMode(DisplayState* internal_display,
    650                                          DisplayState* external_display,
    651                                          bool try_panel_fitting,
    652                                          bool preserve_aspect) {
    653   const DisplayMode* internal_native_info =
    654       internal_display->display->native_mode();
    655   const DisplayMode* external_native_info =
    656       external_display->display->native_mode();
    657   if (!internal_native_info || !external_native_info)
    658     return false;
    659 
    660   // Check if some external display resolution can be mirrored on internal.
    661   // Prefer the modes in the order they're present in DisplaySnapshot, assuming
    662   // this is the order in which they look better on the monitor.
    663   for (DisplayModeList::const_iterator external_it =
    664            external_display->display->modes().begin();
    665        external_it != external_display->display->modes().end();
    666        ++external_it) {
    667     const DisplayMode& external_info = **external_it;
    668     bool is_native_aspect_ratio =
    669         external_native_info->size().width() * external_info.size().height() ==
    670         external_native_info->size().height() * external_info.size().width();
    671     if (preserve_aspect && !is_native_aspect_ratio)
    672       continue;  // Allow only aspect ratio preserving modes for mirroring.
    673 
    674     // Try finding an exact match.
    675     for (DisplayModeList::const_iterator internal_it =
    676              internal_display->display->modes().begin();
    677          internal_it != internal_display->display->modes().end();
    678          ++internal_it) {
    679       const DisplayMode& internal_info = **internal_it;
    680       if (internal_info.size().width() == external_info.size().width() &&
    681           internal_info.size().height() == external_info.size().height() &&
    682           internal_info.is_interlaced() == external_info.is_interlaced()) {
    683         internal_display->mirror_mode = *internal_it;
    684         external_display->mirror_mode = *external_it;
    685         return true;  // Mirror mode found.
    686       }
    687     }
    688 
    689     // Try to create a matching internal display mode by panel fitting.
    690     if (try_panel_fitting) {
    691       // We can downscale by 1.125, and upscale indefinitely. Downscaling looks
    692       // ugly, so, can fit == can upscale. Also, internal panels don't support
    693       // fitting interlaced modes.
    694       bool can_fit = internal_native_info->size().width() >=
    695                          external_info.size().width() &&
    696                      internal_native_info->size().height() >=
    697                          external_info.size().height() &&
    698                      !external_info.is_interlaced();
    699       if (can_fit) {
    700         native_display_delegate_->AddMode(*internal_display->display,
    701                                           *external_it);
    702         internal_display->display->add_mode(*external_it);
    703         internal_display->mirror_mode = *external_it;
    704         external_display->mirror_mode = *external_it;
    705         return true;  // Mirror mode created.
    706       }
    707     }
    708   }
    709 
    710   return false;
    711 }
    712 
    713 void DisplayConfigurator::ConfigureDisplays() {
    714   if (!configure_display_)
    715     return;
    716 
    717   native_display_delegate_->GrabServer();
    718   UpdateCachedDisplays();
    719   const MultipleDisplayState new_state = ChooseDisplayState(
    720       requested_power_state_);
    721   const bool success = EnterStateOrFallBackToSoftwareMirroring(
    722       new_state, requested_power_state_);
    723   native_display_delegate_->UngrabServer();
    724 
    725   NotifyObservers(success, new_state);
    726 }
    727 
    728 void DisplayConfigurator::NotifyObservers(
    729     bool success,
    730     MultipleDisplayState attempted_state) {
    731   if (success) {
    732     FOR_EACH_OBSERVER(
    733         Observer, observers_, OnDisplayModeChanged(cached_displays_));
    734   } else {
    735     FOR_EACH_OBSERVER(
    736         Observer, observers_, OnDisplayModeChangeFailed(attempted_state));
    737   }
    738 }
    739 
    740 bool DisplayConfigurator::EnterStateOrFallBackToSoftwareMirroring(
    741     MultipleDisplayState display_state,
    742     chromeos::DisplayPowerState power_state) {
    743   bool success = EnterState(display_state, power_state);
    744   if (mirroring_controller_) {
    745     bool enable_software_mirroring = false;
    746     if (!success && display_state == MULTIPLE_DISPLAY_STATE_DUAL_MIRROR) {
    747       if (display_state_ != MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED ||
    748           current_power_state_ != power_state)
    749         EnterState(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED, power_state);
    750       enable_software_mirroring = success =
    751           display_state_ == MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED;
    752     }
    753     mirroring_controller_->SetSoftwareMirroring(enable_software_mirroring);
    754   }
    755   return success;
    756 }
    757 
    758 bool DisplayConfigurator::EnterState(MultipleDisplayState display_state,
    759                                      chromeos::DisplayPowerState power_state) {
    760   std::vector<bool> display_power;
    761   int num_on_displays =
    762       GetDisplayPower(cached_displays_, power_state, &display_power);
    763   VLOG(1) << "EnterState: display=" << DisplayStateToString(display_state)
    764           << " power=" << DisplayPowerStateToString(power_state);
    765 
    766   // Save the requested state so we'll try to use it next time even if we fail.
    767   requested_power_state_ = power_state;
    768 
    769   // Framebuffer dimensions.
    770   gfx::Size size;
    771 
    772   std::vector<gfx::Point> new_origins(cached_displays_.size(), gfx::Point());
    773   std::vector<const DisplayMode*> new_mode;
    774   for (size_t i = 0; i < cached_displays_.size(); ++i)
    775     new_mode.push_back(cached_displays_[i].display->current_mode());
    776 
    777   switch (display_state) {
    778     case MULTIPLE_DISPLAY_STATE_INVALID:
    779       NOTREACHED() << "Ignoring request to enter invalid state with "
    780                    << cached_displays_.size() << " connected display(s)";
    781       return false;
    782     case MULTIPLE_DISPLAY_STATE_HEADLESS:
    783       if (cached_displays_.size() != 0) {
    784         LOG(WARNING) << "Ignoring request to enter headless mode with "
    785                      << cached_displays_.size() << " connected display(s)";
    786         return false;
    787       }
    788       break;
    789     case MULTIPLE_DISPLAY_STATE_SINGLE: {
    790       // If there are multiple displays connected, only one should be turned on.
    791       if (cached_displays_.size() != 1 && num_on_displays != 1) {
    792         LOG(WARNING) << "Ignoring request to enter single mode with "
    793                      << cached_displays_.size() << " connected displays and "
    794                      << num_on_displays << " turned on";
    795         return false;
    796       }
    797 
    798       for (size_t i = 0; i < cached_displays_.size(); ++i) {
    799         DisplayState* state = &cached_displays_[i];
    800         new_mode[i] = display_power[i] ? state->selected_mode : NULL;
    801 
    802         if (display_power[i] || cached_displays_.size() == 1) {
    803           const DisplayMode* mode_info = state->selected_mode;
    804           if (!mode_info) {
    805             LOG(WARNING) << "No selected mode when configuring display: "
    806                          << state->display->ToString();
    807             return false;
    808           }
    809           if (mode_info->size() == gfx::Size(1024, 768)) {
    810             VLOG(1) << "Potentially misdetecting display(1024x768):"
    811                     << " displays size=" << cached_displays_.size()
    812                     << ", num_on_displays=" << num_on_displays
    813                     << ", current size:" << size.width() << "x" << size.height()
    814                     << ", i=" << i << ", display=" << state->display->ToString()
    815                     << ", display_mode=" << mode_info->ToString();
    816           }
    817           size = mode_info->size();
    818         }
    819       }
    820       break;
    821     }
    822     case MULTIPLE_DISPLAY_STATE_DUAL_MIRROR: {
    823       if (cached_displays_.size() != 2 ||
    824           (num_on_displays != 0 && num_on_displays != 2)) {
    825         LOG(WARNING) << "Ignoring request to enter mirrored mode with "
    826                      << cached_displays_.size() << " connected display(s) and "
    827                      << num_on_displays << " turned on";
    828         return false;
    829       }
    830 
    831       const DisplayMode* mode_info = cached_displays_[0].mirror_mode;
    832       if (!mode_info) {
    833         LOG(WARNING) << "No mirror mode when configuring display: "
    834                      << cached_displays_[0].display->ToString();
    835         return false;
    836       }
    837       size = mode_info->size();
    838 
    839       for (size_t i = 0; i < cached_displays_.size(); ++i) {
    840         DisplayState* state = &cached_displays_[i];
    841         new_mode[i] = display_power[i] ? state->mirror_mode : NULL;
    842       }
    843       break;
    844     }
    845     case MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED: {
    846       if (cached_displays_.size() != 2 ||
    847           (num_on_displays != 0 && num_on_displays != 2)) {
    848         LOG(WARNING) << "Ignoring request to enter extended mode with "
    849                      << cached_displays_.size() << " connected display(s) and "
    850                      << num_on_displays << " turned on";
    851         return false;
    852       }
    853 
    854       for (size_t i = 0; i < cached_displays_.size(); ++i) {
    855         DisplayState* state = &cached_displays_[i];
    856         new_origins[i].set_y(size.height() ? size.height() + kVerticalGap : 0);
    857         new_mode[i] = display_power[i] ? state->selected_mode : NULL;
    858 
    859         // Retain the full screen size even if all displays are off so the
    860         // same desktop configuration can be restored when the displays are
    861         // turned back on.
    862         const DisplayMode* mode_info = cached_displays_[i].selected_mode;
    863         if (!mode_info) {
    864           LOG(WARNING) << "No selected mode when configuring display: "
    865                        << state->display->ToString();
    866           return false;
    867         }
    868 
    869         size.set_width(std::max<int>(size.width(), mode_info->size().width()));
    870         size.set_height(size.height() + (size.height() ? kVerticalGap : 0) +
    871                         mode_info->size().height());
    872       }
    873       break;
    874     }
    875   }
    876 
    877   // Finally, apply the desired changes.
    878   bool all_succeeded = true;
    879   if (!cached_displays_.empty()) {
    880     native_display_delegate_->CreateFrameBuffer(size);
    881     for (size_t i = 0; i < cached_displays_.size(); ++i) {
    882       const DisplayState& state = cached_displays_[i];
    883       bool configure_succeeded = false;
    884 
    885       while (true) {
    886         if (native_display_delegate_->Configure(
    887                 *state.display, new_mode[i], new_origins[i])) {
    888           state.display->set_current_mode(new_mode[i]);
    889           state.display->set_origin(new_origins[i]);
    890 
    891           configure_succeeded = true;
    892           break;
    893         }
    894 
    895         const DisplayMode* mode_info = new_mode[i];
    896         if (!mode_info)
    897           break;
    898 
    899         // Find the mode with the next-best resolution and see if that can
    900         // be set.
    901         int best_mode_pixels = 0;
    902 
    903         int current_mode_pixels = mode_info->size().GetArea();
    904         for (DisplayModeList::const_iterator it =
    905                  state.display->modes().begin();
    906              it != state.display->modes().end();
    907              it++) {
    908           int pixel_count = (*it)->size().GetArea();
    909           if ((pixel_count < current_mode_pixels) &&
    910               (pixel_count > best_mode_pixels)) {
    911             new_mode[i] = *it;
    912             best_mode_pixels = pixel_count;
    913           }
    914         }
    915 
    916         if (best_mode_pixels == 0)
    917           break;
    918       }
    919 
    920       if (!configure_succeeded)
    921         all_succeeded = false;
    922 
    923       // If we are trying to set mirror mode and one of the modesets fails,
    924       // then the two monitors will be mis-matched.  In this case, return
    925       // false to let the observers be aware.
    926       if (display_state == MULTIPLE_DISPLAY_STATE_DUAL_MIRROR &&
    927           display_power[i] &&
    928           state.display->current_mode() != state.mirror_mode)
    929         all_succeeded = false;
    930     }
    931   }
    932 
    933   if (all_succeeded) {
    934     display_state_ = display_state;
    935     current_power_state_ = power_state;
    936     framebuffer_size_ = size;
    937   }
    938   return all_succeeded;
    939 }
    940 
    941 MultipleDisplayState DisplayConfigurator::ChooseDisplayState(
    942     chromeos::DisplayPowerState power_state) const {
    943   int num_on_displays = GetDisplayPower(cached_displays_, power_state, NULL);
    944   switch (cached_displays_.size()) {
    945     case 0:
    946       return MULTIPLE_DISPLAY_STATE_HEADLESS;
    947     case 1:
    948       return MULTIPLE_DISPLAY_STATE_SINGLE;
    949     case 2: {
    950       if (num_on_displays == 1) {
    951         // If only one display is currently turned on, return the "single"
    952         // state so that its native mode will be used.
    953         return MULTIPLE_DISPLAY_STATE_SINGLE;
    954       } else {
    955         if (!state_controller_)
    956           return MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED;
    957         // With either both displays on or both displays off, use one of the
    958         // dual modes.
    959         std::vector<int64_t> display_ids;
    960         for (size_t i = 0; i < cached_displays_.size(); ++i) {
    961           // If display id isn't available, switch to extended mode.
    962           if (!cached_displays_[i].display->has_proper_display_id())
    963             return MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED;
    964           display_ids.push_back(cached_displays_[i].display->display_id());
    965         }
    966         return state_controller_->GetStateForDisplayIds(display_ids);
    967       }
    968     }
    969     default:
    970       NOTREACHED();
    971   }
    972   return MULTIPLE_DISPLAY_STATE_INVALID;
    973 }
    974 
    975 }  // namespace ui
    976