| OLD | NEW | 
 | (Empty) | 
|     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 <stddef.h> |  | 
|     8 #include <utility> |  | 
|     9  |  | 
|    10 #include "base/bind.h" |  | 
|    11 #include "base/command_line.h" |  | 
|    12 #include "base/logging.h" |  | 
|    13 #include "base/macros.h" |  | 
|    14 #include "base/sys_info.h" |  | 
|    15 #include "base/time/time.h" |  | 
|    16 #include "ui/display/chromeos/apply_content_protection_task.h" |  | 
|    17 #include "ui/display/chromeos/display_layout_manager.h" |  | 
|    18 #include "ui/display/chromeos/display_snapshot_virtual.h" |  | 
|    19 #include "ui/display/chromeos/display_util.h" |  | 
|    20 #include "ui/display/chromeos/update_display_configuration_task.h" |  | 
|    21 #include "ui/display/display.h" |  | 
|    22 #include "ui/display/display_switches.h" |  | 
|    23 #include "ui/display/types/display_mode.h" |  | 
|    24 #include "ui/display/types/display_snapshot.h" |  | 
|    25 #include "ui/display/types/native_display_delegate.h" |  | 
|    26 #include "ui/display/util/display_util.h" |  | 
|    27  |  | 
|    28 namespace ui { |  | 
|    29  |  | 
|    30 namespace { |  | 
|    31  |  | 
|    32 typedef std::vector<const DisplayMode*> DisplayModeList; |  | 
|    33  |  | 
|    34 // The EDID specification marks the top bit of the manufacturer id as reserved. |  | 
|    35 const int16_t kReservedManufacturerID = static_cast<int16_t>(1 << 15); |  | 
|    36  |  | 
|    37 struct DisplayState { |  | 
|    38   DisplaySnapshot* display = nullptr;  // Not owned. |  | 
|    39  |  | 
|    40   // User-selected mode for the display. |  | 
|    41   const DisplayMode* selected_mode = nullptr; |  | 
|    42  |  | 
|    43   // Mode used when displaying the same desktop on multiple displays. |  | 
|    44   const DisplayMode* mirror_mode = nullptr; |  | 
|    45 }; |  | 
|    46  |  | 
|    47 void DoNothing(bool status) { |  | 
|    48 } |  | 
|    49  |  | 
|    50 }  // namespace |  | 
|    51  |  | 
|    52 const int DisplayConfigurator::kSetDisplayPowerNoFlags = 0; |  | 
|    53 const int DisplayConfigurator::kSetDisplayPowerForceProbe = 1 << 0; |  | 
|    54 const int |  | 
|    55 DisplayConfigurator::kSetDisplayPowerOnlyIfSingleInternalDisplay = 1 << 1; |  | 
|    56  |  | 
|    57 bool DisplayConfigurator::TestApi::TriggerConfigureTimeout() { |  | 
|    58   if (configurator_->configure_timer_.IsRunning()) { |  | 
|    59     configurator_->configure_timer_.user_task().Run(); |  | 
|    60     configurator_->configure_timer_.Stop(); |  | 
|    61     return true; |  | 
|    62   } else { |  | 
|    63     return false; |  | 
|    64   } |  | 
|    65 } |  | 
|    66  |  | 
|    67 base::TimeDelta DisplayConfigurator::TestApi::GetConfigureDelay() const { |  | 
|    68   return configurator_->configure_timer_.IsRunning() |  | 
|    69              ? configurator_->configure_timer_.GetCurrentDelay() |  | 
|    70              : base::TimeDelta(); |  | 
|    71 } |  | 
|    72  |  | 
|    73 //////////////////////////////////////////////////////////////////////////////// |  | 
|    74 // DisplayConfigurator::DisplayLayoutManagerImpl implementation |  | 
|    75  |  | 
|    76 class DisplayConfigurator::DisplayLayoutManagerImpl |  | 
|    77     : public DisplayLayoutManager { |  | 
|    78  public: |  | 
|    79   DisplayLayoutManagerImpl(DisplayConfigurator* configurator); |  | 
|    80   ~DisplayLayoutManagerImpl() override; |  | 
|    81  |  | 
|    82   // DisplayConfigurator::DisplayLayoutManager: |  | 
|    83   SoftwareMirroringController* GetSoftwareMirroringController() const override; |  | 
|    84   StateController* GetStateController() const override; |  | 
|    85   MultipleDisplayState GetDisplayState() const override; |  | 
|    86   chromeos::DisplayPowerState GetPowerState() const override; |  | 
|    87   bool GetDisplayLayout(const std::vector<DisplaySnapshot*>& displays, |  | 
|    88                         MultipleDisplayState new_display_state, |  | 
|    89                         chromeos::DisplayPowerState new_power_state, |  | 
|    90                         std::vector<DisplayConfigureRequest>* requests, |  | 
|    91                         gfx::Size* framebuffer_size) const override; |  | 
|    92   DisplayStateList GetDisplayStates() const override; |  | 
|    93   bool IsMirroring() const override; |  | 
|    94  |  | 
|    95  private: |  | 
|    96   // Parses the |displays| into a list of DisplayStates. This effectively adds |  | 
|    97   // |mirror_mode| and |selected_mode| to the returned results. |  | 
|    98   // TODO(dnicoara): Break this into GetSelectedMode() and GetMirrorMode() and |  | 
|    99   // remove DisplayState. |  | 
|   100   std::vector<DisplayState> ParseDisplays( |  | 
|   101       const std::vector<DisplaySnapshot*>& displays) const; |  | 
|   102  |  | 
|   103   const DisplayMode* GetUserSelectedMode(const DisplaySnapshot& display) const; |  | 
|   104  |  | 
|   105   // Helper method for ParseDisplays() that initializes the passed-in |  | 
|   106   // displays' |mirror_mode| fields by looking for a mode in |internal_display| |  | 
|   107   // and |external_display| having the same resolution. Returns false if a |  | 
|   108   // shared mode wasn't found or created. |  | 
|   109   // |  | 
|   110   // |try_panel_fitting| allows creating a panel-fitting mode for |  | 
|   111   // |internal_display| instead of only searching for a matching mode (note that |  | 
|   112   // it may lead to a crash if |internal_display| is not capable of panel |  | 
|   113   // fitting). |  | 
|   114   // |  | 
|   115   // |preserve_aspect| limits the search/creation only to the modes having the |  | 
|   116   // native aspect ratio of |external_display|. |  | 
|   117   bool FindMirrorMode(DisplayState* internal_display, |  | 
|   118                       DisplayState* external_display, |  | 
|   119                       bool try_panel_fitting, |  | 
|   120                       bool preserve_aspect) const; |  | 
|   121  |  | 
|   122   DisplayConfigurator* configurator_;  // Not owned. |  | 
|   123  |  | 
|   124   DISALLOW_COPY_AND_ASSIGN(DisplayLayoutManagerImpl); |  | 
|   125 }; |  | 
|   126  |  | 
|   127 DisplayConfigurator::DisplayLayoutManagerImpl::DisplayLayoutManagerImpl( |  | 
|   128     DisplayConfigurator* configurator) |  | 
|   129     : configurator_(configurator) { |  | 
|   130 } |  | 
|   131  |  | 
|   132 DisplayConfigurator::DisplayLayoutManagerImpl::~DisplayLayoutManagerImpl() { |  | 
|   133 } |  | 
|   134  |  | 
|   135 DisplayConfigurator::SoftwareMirroringController* |  | 
|   136 DisplayConfigurator::DisplayLayoutManagerImpl::GetSoftwareMirroringController() |  | 
|   137     const { |  | 
|   138   return configurator_->mirroring_controller_; |  | 
|   139 } |  | 
|   140  |  | 
|   141 DisplayConfigurator::StateController* |  | 
|   142 DisplayConfigurator::DisplayLayoutManagerImpl::GetStateController() const { |  | 
|   143   return configurator_->state_controller_; |  | 
|   144 } |  | 
|   145  |  | 
|   146 MultipleDisplayState |  | 
|   147 DisplayConfigurator::DisplayLayoutManagerImpl::GetDisplayState() const { |  | 
|   148   return configurator_->current_display_state_; |  | 
|   149 } |  | 
|   150  |  | 
|   151 chromeos::DisplayPowerState |  | 
|   152 DisplayConfigurator::DisplayLayoutManagerImpl::GetPowerState() const { |  | 
|   153   return configurator_->current_power_state_; |  | 
|   154 } |  | 
|   155  |  | 
|   156 std::vector<DisplayState> |  | 
|   157 DisplayConfigurator::DisplayLayoutManagerImpl::ParseDisplays( |  | 
|   158     const std::vector<DisplaySnapshot*>& snapshots) const { |  | 
|   159   std::vector<DisplayState> cached_displays; |  | 
|   160   for (auto* snapshot : snapshots) { |  | 
|   161     DisplayState display_state; |  | 
|   162     display_state.display = snapshot; |  | 
|   163     display_state.selected_mode = GetUserSelectedMode(*snapshot); |  | 
|   164     cached_displays.push_back(display_state); |  | 
|   165   } |  | 
|   166  |  | 
|   167   // Set |mirror_mode| fields. |  | 
|   168   if (cached_displays.size() == 2) { |  | 
|   169     bool one_is_internal = |  | 
|   170         cached_displays[0].display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL; |  | 
|   171     bool two_is_internal = |  | 
|   172         cached_displays[1].display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL; |  | 
|   173     int internal_displays = |  | 
|   174         (one_is_internal ? 1 : 0) + (two_is_internal ? 1 : 0); |  | 
|   175     DCHECK_LT(internal_displays, 2); |  | 
|   176     LOG_IF(WARNING, internal_displays >= 2) |  | 
|   177         << "At least two internal displays detected."; |  | 
|   178  |  | 
|   179     bool can_mirror = false; |  | 
|   180     for (int attempt = 0; !can_mirror && attempt < 2; ++attempt) { |  | 
|   181       // Try preserving external display's aspect ratio on the first attempt. |  | 
|   182       // If that fails, fall back to the highest matching resolution. |  | 
|   183       bool preserve_aspect = attempt == 0; |  | 
|   184  |  | 
|   185       if (internal_displays == 1) { |  | 
|   186         can_mirror = FindMirrorMode(&cached_displays[one_is_internal ? 0 : 1], |  | 
|   187                                     &cached_displays[one_is_internal ? 1 : 0], |  | 
|   188                                     configurator_->is_panel_fitting_enabled_, |  | 
|   189                                     preserve_aspect); |  | 
|   190       } else {  // if (internal_displays == 0) |  | 
|   191         // No panel fitting for external displays, so fall back to exact match. |  | 
|   192         can_mirror = FindMirrorMode(&cached_displays[0], &cached_displays[1], |  | 
|   193                                     false, preserve_aspect); |  | 
|   194         if (!can_mirror && preserve_aspect) { |  | 
|   195           // FindMirrorMode() will try to preserve aspect ratio of what it |  | 
|   196           // thinks is external display, so if it didn't succeed with one, maybe |  | 
|   197           // it will succeed with the other.  This way we will have the correct |  | 
|   198           // aspect ratio on at least one of them. |  | 
|   199           can_mirror = FindMirrorMode(&cached_displays[1], &cached_displays[0], |  | 
|   200                                       false, preserve_aspect); |  | 
|   201         } |  | 
|   202       } |  | 
|   203     } |  | 
|   204   } |  | 
|   205  |  | 
|   206   return cached_displays; |  | 
|   207 } |  | 
|   208  |  | 
|   209 bool DisplayConfigurator::DisplayLayoutManagerImpl::GetDisplayLayout( |  | 
|   210     const std::vector<DisplaySnapshot*>& displays, |  | 
|   211     MultipleDisplayState new_display_state, |  | 
|   212     chromeos::DisplayPowerState new_power_state, |  | 
|   213     std::vector<DisplayConfigureRequest>* requests, |  | 
|   214     gfx::Size* framebuffer_size) const { |  | 
|   215   std::vector<DisplayState> states = ParseDisplays(displays); |  | 
|   216   std::vector<bool> display_power; |  | 
|   217   int num_on_displays = |  | 
|   218       GetDisplayPower(displays, new_power_state, &display_power); |  | 
|   219   VLOG(1) << "EnterState: display=" |  | 
|   220           << MultipleDisplayStateToString(new_display_state) |  | 
|   221           << " power=" << DisplayPowerStateToString(new_power_state); |  | 
|   222  |  | 
|   223   // Framebuffer dimensions. |  | 
|   224   gfx::Size size; |  | 
|   225  |  | 
|   226   for (size_t i = 0; i < displays.size(); ++i) { |  | 
|   227     requests->push_back(DisplayConfigureRequest( |  | 
|   228         displays[i], displays[i]->current_mode(), gfx::Point())); |  | 
|   229   } |  | 
|   230  |  | 
|   231   switch (new_display_state) { |  | 
|   232     case MULTIPLE_DISPLAY_STATE_INVALID: |  | 
|   233       NOTREACHED() << "Ignoring request to enter invalid state with " |  | 
|   234                    << displays.size() << " connected display(s)"; |  | 
|   235       return false; |  | 
|   236     case MULTIPLE_DISPLAY_STATE_HEADLESS: |  | 
|   237       if (displays.size() != 0) { |  | 
|   238         LOG(WARNING) << "Ignoring request to enter headless mode with " |  | 
|   239                      << displays.size() << " connected display(s)"; |  | 
|   240         return false; |  | 
|   241       } |  | 
|   242       break; |  | 
|   243     case MULTIPLE_DISPLAY_STATE_SINGLE: { |  | 
|   244       // If there are multiple displays connected, only one should be turned on. |  | 
|   245       if (displays.size() != 1 && num_on_displays != 1) { |  | 
|   246         LOG(WARNING) << "Ignoring request to enter single mode with " |  | 
|   247                      << displays.size() << " connected displays and " |  | 
|   248                      << num_on_displays << " turned on"; |  | 
|   249         return false; |  | 
|   250       } |  | 
|   251  |  | 
|   252       for (size_t i = 0; i < states.size(); ++i) { |  | 
|   253         const DisplayState* state = &states[i]; |  | 
|   254         (*requests)[i].mode = display_power[i] ? state->selected_mode : NULL; |  | 
|   255  |  | 
|   256         if (display_power[i] || states.size() == 1) { |  | 
|   257           const DisplayMode* mode_info = state->selected_mode; |  | 
|   258           if (!mode_info) { |  | 
|   259             LOG(WARNING) << "No selected mode when configuring display: " |  | 
|   260                          << state->display->ToString(); |  | 
|   261             return false; |  | 
|   262           } |  | 
|   263           if (mode_info->size() == gfx::Size(1024, 768)) { |  | 
|   264             VLOG(1) << "Potentially misdetecting display(1024x768):" |  | 
|   265                     << " displays size=" << states.size() |  | 
|   266                     << ", num_on_displays=" << num_on_displays |  | 
|   267                     << ", current size:" << size.width() << "x" << size.height() |  | 
|   268                     << ", i=" << i << ", display=" << state->display->ToString() |  | 
|   269                     << ", display_mode=" << mode_info->ToString(); |  | 
|   270           } |  | 
|   271           size = mode_info->size(); |  | 
|   272         } |  | 
|   273       } |  | 
|   274       break; |  | 
|   275     } |  | 
|   276     case MULTIPLE_DISPLAY_STATE_DUAL_MIRROR: { |  | 
|   277       if (states.size() != 2 || |  | 
|   278           (num_on_displays != 0 && num_on_displays != 2)) { |  | 
|   279         LOG(WARNING) << "Ignoring request to enter mirrored mode with " |  | 
|   280                      << states.size() << " connected display(s) and " |  | 
|   281                      << num_on_displays << " turned on"; |  | 
|   282         return false; |  | 
|   283       } |  | 
|   284  |  | 
|   285       const DisplayMode* mode_info = states[0].mirror_mode; |  | 
|   286       if (!mode_info) { |  | 
|   287         LOG(WARNING) << "No mirror mode when configuring display: " |  | 
|   288                      << states[0].display->ToString(); |  | 
|   289         return false; |  | 
|   290       } |  | 
|   291       size = mode_info->size(); |  | 
|   292  |  | 
|   293       for (size_t i = 0; i < states.size(); ++i) { |  | 
|   294         const DisplayState* state = &states[i]; |  | 
|   295         (*requests)[i].mode = display_power[i] ? state->mirror_mode : NULL; |  | 
|   296       } |  | 
|   297       break; |  | 
|   298     } |  | 
|   299     case MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED: |  | 
|   300     case MULTIPLE_DISPLAY_STATE_MULTI_EXTENDED: { |  | 
|   301       // In docked mode (with internal display + 2 external displays) the state |  | 
|   302       // will be DUAL_EXTENDED with internal display turned off and the 2 |  | 
|   303       // external displays turned on. |  | 
|   304       if (new_display_state == MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED && |  | 
|   305           states.size() != 2 && num_on_displays != 2) { |  | 
|   306         LOG(WARNING) << "Ignoring request to enter extended mode with " |  | 
|   307                      << states.size() << " connected display(s) and " |  | 
|   308                      << num_on_displays << " turned on"; |  | 
|   309         return false; |  | 
|   310       } |  | 
|   311  |  | 
|   312       for (size_t i = 0; i < states.size(); ++i) { |  | 
|   313         const DisplayState* state = &states[i]; |  | 
|   314         (*requests)[i].origin.set_y(size.height() ? size.height() + kVerticalGap |  | 
|   315                                                   : 0); |  | 
|   316         (*requests)[i].mode = display_power[i] ? state->selected_mode : NULL; |  | 
|   317  |  | 
|   318         // Retain the full screen size even if all displays are off so the |  | 
|   319         // same desktop configuration can be restored when the displays are |  | 
|   320         // turned back on. |  | 
|   321         const DisplayMode* mode_info = states[i].selected_mode; |  | 
|   322         if (!mode_info) { |  | 
|   323           LOG(WARNING) << "No selected mode when configuring display: " |  | 
|   324                        << state->display->ToString(); |  | 
|   325           return false; |  | 
|   326         } |  | 
|   327  |  | 
|   328         size.set_width(std::max<int>(size.width(), mode_info->size().width())); |  | 
|   329         size.set_height(size.height() + (size.height() ? kVerticalGap : 0) + |  | 
|   330                         mode_info->size().height()); |  | 
|   331       } |  | 
|   332       break; |  | 
|   333     } |  | 
|   334   } |  | 
|   335   DCHECK(new_display_state == MULTIPLE_DISPLAY_STATE_HEADLESS || |  | 
|   336          !size.IsEmpty()); |  | 
|   337   *framebuffer_size = size; |  | 
|   338   return true; |  | 
|   339 } |  | 
|   340  |  | 
|   341 DisplayConfigurator::DisplayStateList |  | 
|   342 DisplayConfigurator::DisplayLayoutManagerImpl::GetDisplayStates() const { |  | 
|   343   return configurator_->cached_displays(); |  | 
|   344 } |  | 
|   345  |  | 
|   346 bool DisplayConfigurator::DisplayLayoutManagerImpl::IsMirroring() const { |  | 
|   347   if (GetDisplayState() == MULTIPLE_DISPLAY_STATE_DUAL_MIRROR) |  | 
|   348     return true; |  | 
|   349  |  | 
|   350   return GetSoftwareMirroringController() && |  | 
|   351          GetSoftwareMirroringController()->SoftwareMirroringEnabled(); |  | 
|   352 } |  | 
|   353  |  | 
|   354 const DisplayMode* |  | 
|   355 DisplayConfigurator::DisplayLayoutManagerImpl::GetUserSelectedMode( |  | 
|   356     const DisplaySnapshot& display) const { |  | 
|   357   gfx::Size size; |  | 
|   358   const DisplayMode* selected_mode = nullptr; |  | 
|   359   if (GetStateController() && |  | 
|   360       GetStateController()->GetResolutionForDisplayId(display.display_id(), |  | 
|   361                                                       &size)) { |  | 
|   362     selected_mode = FindDisplayModeMatchingSize(display, size); |  | 
|   363   } |  | 
|   364  |  | 
|   365   // Fall back to native mode. |  | 
|   366   return selected_mode ? selected_mode : display.native_mode(); |  | 
|   367 } |  | 
|   368  |  | 
|   369 bool DisplayConfigurator::DisplayLayoutManagerImpl::FindMirrorMode( |  | 
|   370     DisplayState* internal_display, |  | 
|   371     DisplayState* external_display, |  | 
|   372     bool try_panel_fitting, |  | 
|   373     bool preserve_aspect) const { |  | 
|   374   const DisplayMode* internal_native_info = |  | 
|   375       internal_display->display->native_mode(); |  | 
|   376   const DisplayMode* external_native_info = |  | 
|   377       external_display->display->native_mode(); |  | 
|   378   if (!internal_native_info || !external_native_info) |  | 
|   379     return false; |  | 
|   380  |  | 
|   381   // Check if some external display resolution can be mirrored on internal. |  | 
|   382   // Prefer the modes in the order they're present in DisplaySnapshot, assuming |  | 
|   383   // this is the order in which they look better on the monitor. |  | 
|   384   for (const auto& external_mode : external_display->display->modes()) { |  | 
|   385     bool is_native_aspect_ratio = |  | 
|   386         external_native_info->size().width() * external_mode->size().height() == |  | 
|   387         external_native_info->size().height() * external_mode->size().width(); |  | 
|   388     if (preserve_aspect && !is_native_aspect_ratio) |  | 
|   389       continue;  // Allow only aspect ratio preserving modes for mirroring. |  | 
|   390  |  | 
|   391     // Try finding an exact match. |  | 
|   392     for (const auto& internal_mode : internal_display->display->modes()) { |  | 
|   393       if (internal_mode->size() == external_mode->size() && |  | 
|   394           internal_mode->is_interlaced() == external_mode->is_interlaced()) { |  | 
|   395         internal_display->mirror_mode = internal_mode.get(); |  | 
|   396         external_display->mirror_mode = external_mode.get(); |  | 
|   397         return true;  // Mirror mode found. |  | 
|   398       } |  | 
|   399     } |  | 
|   400  |  | 
|   401     // Try to create a matching internal display mode by panel fitting. |  | 
|   402     if (try_panel_fitting) { |  | 
|   403       // We can downscale by 1.125, and upscale indefinitely. Downscaling looks |  | 
|   404       // ugly, so, can fit == can upscale. Also, internal panels don't support |  | 
|   405       // fitting interlaced modes. |  | 
|   406       bool can_fit = internal_native_info->size().width() >= |  | 
|   407                          external_mode->size().width() && |  | 
|   408                      internal_native_info->size().height() >= |  | 
|   409                          external_mode->size().height() && |  | 
|   410                      !external_mode->is_interlaced(); |  | 
|   411       if (can_fit) { |  | 
|   412         configurator_->native_display_delegate_->AddMode( |  | 
|   413             *internal_display->display, external_mode.get()); |  | 
|   414         internal_display->display->add_mode(external_mode.get()); |  | 
|   415         internal_display->mirror_mode = |  | 
|   416           internal_display->display->modes().back().get(); |  | 
|   417         external_display->mirror_mode = external_mode.get(); |  | 
|   418         return true;  // Mirror mode created. |  | 
|   419       } |  | 
|   420     } |  | 
|   421   } |  | 
|   422  |  | 
|   423   return false; |  | 
|   424 } |  | 
|   425  |  | 
|   426 //////////////////////////////////////////////////////////////////////////////// |  | 
|   427 // DisplayConfigurator implementation |  | 
|   428  |  | 
|   429 // static |  | 
|   430 const DisplayMode* DisplayConfigurator::FindDisplayModeMatchingSize( |  | 
|   431     const DisplaySnapshot& display, |  | 
|   432     const gfx::Size& size) { |  | 
|   433   const DisplayMode* best_mode = NULL; |  | 
|   434   for (const std::unique_ptr<const DisplayMode>& mode : display.modes()) { |  | 
|   435     if (mode->size() != size) |  | 
|   436       continue; |  | 
|   437  |  | 
|   438     if (mode.get() == display.native_mode()) { |  | 
|   439       best_mode = mode.get(); |  | 
|   440       break; |  | 
|   441     } |  | 
|   442  |  | 
|   443     if (!best_mode) { |  | 
|   444       best_mode = mode.get(); |  | 
|   445       continue; |  | 
|   446     } |  | 
|   447  |  | 
|   448     if (mode->is_interlaced()) { |  | 
|   449       if (!best_mode->is_interlaced()) |  | 
|   450         continue; |  | 
|   451     } else { |  | 
|   452       // Reset the best rate if the non interlaced is |  | 
|   453       // found the first time. |  | 
|   454       if (best_mode->is_interlaced()) { |  | 
|   455         best_mode = mode.get(); |  | 
|   456         continue; |  | 
|   457       } |  | 
|   458     } |  | 
|   459     if (mode->refresh_rate() < best_mode->refresh_rate()) |  | 
|   460       continue; |  | 
|   461  |  | 
|   462     best_mode = mode.get(); |  | 
|   463   } |  | 
|   464  |  | 
|   465   return best_mode; |  | 
|   466 } |  | 
|   467  |  | 
|   468 DisplayConfigurator::DisplayConfigurator() |  | 
|   469     : state_controller_(NULL), |  | 
|   470       mirroring_controller_(NULL), |  | 
|   471       is_panel_fitting_enabled_(false), |  | 
|   472       configure_display_(base::SysInfo::IsRunningOnChromeOS()), |  | 
|   473       current_display_state_(MULTIPLE_DISPLAY_STATE_INVALID), |  | 
|   474       current_power_state_(chromeos::DISPLAY_POWER_ALL_ON), |  | 
|   475       requested_display_state_(MULTIPLE_DISPLAY_STATE_INVALID), |  | 
|   476       requested_power_state_(chromeos::DISPLAY_POWER_ALL_ON), |  | 
|   477       pending_power_state_(chromeos::DISPLAY_POWER_ALL_ON), |  | 
|   478       has_pending_power_state_(false), |  | 
|   479       pending_power_flags_(kSetDisplayPowerNoFlags), |  | 
|   480       force_configure_(false), |  | 
|   481       next_display_protection_client_id_(1), |  | 
|   482       display_externally_controlled_(false), |  | 
|   483       display_control_changing_(false), |  | 
|   484       displays_suspended_(false), |  | 
|   485       layout_manager_(new DisplayLayoutManagerImpl(this)), |  | 
|   486       weak_ptr_factory_(this) { |  | 
|   487 } |  | 
|   488  |  | 
|   489 DisplayConfigurator::~DisplayConfigurator() { |  | 
|   490   if (native_display_delegate_) |  | 
|   491     native_display_delegate_->RemoveObserver(this); |  | 
|   492  |  | 
|   493   CallAndClearInProgressCallbacks(false); |  | 
|   494   CallAndClearQueuedCallbacks(false); |  | 
|   495  |  | 
|   496   while (!query_protection_callbacks_.empty()) { |  | 
|   497     query_protection_callbacks_.front().Run(QueryProtectionResponse()); |  | 
|   498     query_protection_callbacks_.pop(); |  | 
|   499   } |  | 
|   500  |  | 
|   501   while (!enable_protection_callbacks_.empty()) { |  | 
|   502     enable_protection_callbacks_.front().Run(false); |  | 
|   503     enable_protection_callbacks_.pop(); |  | 
|   504   } |  | 
|   505 } |  | 
|   506  |  | 
|   507 void DisplayConfigurator::SetDelegateForTesting( |  | 
|   508     std::unique_ptr<NativeDisplayDelegate> display_delegate) { |  | 
|   509   DCHECK(!native_display_delegate_); |  | 
|   510  |  | 
|   511   native_display_delegate_ = std::move(display_delegate); |  | 
|   512   configure_display_ = true; |  | 
|   513 } |  | 
|   514  |  | 
|   515 void DisplayConfigurator::SetInitialDisplayPower( |  | 
|   516     chromeos::DisplayPowerState power_state) { |  | 
|   517   DCHECK_EQ(current_display_state_, MULTIPLE_DISPLAY_STATE_INVALID); |  | 
|   518   requested_power_state_ = current_power_state_ = power_state; |  | 
|   519   NotifyPowerStateObservers(); |  | 
|   520 } |  | 
|   521  |  | 
|   522 void DisplayConfigurator::Init( |  | 
|   523     std::unique_ptr<NativeDisplayDelegate> display_delegate, |  | 
|   524     bool is_panel_fitting_enabled) { |  | 
|   525   is_panel_fitting_enabled_ = is_panel_fitting_enabled; |  | 
|   526   if (!configure_display_ || display_externally_controlled_) |  | 
|   527     return; |  | 
|   528  |  | 
|   529   // If the delegate is already initialized don't update it (For example, tests |  | 
|   530   // set their own delegates). |  | 
|   531   if (!native_display_delegate_) { |  | 
|   532     native_display_delegate_ = std::move(display_delegate); |  | 
|   533     native_display_delegate_->AddObserver(this); |  | 
|   534   } |  | 
|   535 } |  | 
|   536  |  | 
|   537 void DisplayConfigurator::TakeControl(const DisplayControlCallback& callback) { |  | 
|   538   if (display_control_changing_) { |  | 
|   539     callback.Run(false); |  | 
|   540     return; |  | 
|   541   } |  | 
|   542  |  | 
|   543   if (!display_externally_controlled_) { |  | 
|   544     callback.Run(true); |  | 
|   545     return; |  | 
|   546   } |  | 
|   547  |  | 
|   548   display_control_changing_ = true; |  | 
|   549   native_display_delegate_->TakeDisplayControl( |  | 
|   550       base::Bind(&DisplayConfigurator::OnDisplayControlTaken, |  | 
|   551                  weak_ptr_factory_.GetWeakPtr(), callback)); |  | 
|   552 } |  | 
|   553  |  | 
|   554 void DisplayConfigurator::OnDisplayControlTaken( |  | 
|   555     const DisplayControlCallback& callback, |  | 
|   556     bool success) { |  | 
|   557   display_control_changing_ = false; |  | 
|   558   display_externally_controlled_ = !success; |  | 
|   559   if (success) { |  | 
|   560     // Force a configuration since the display configuration may have changed. |  | 
|   561     force_configure_ = true; |  | 
|   562     // Restore the last power state used before releasing control. |  | 
|   563     SetDisplayPower(requested_power_state_, kSetDisplayPowerNoFlags, |  | 
|   564                     base::Bind(&DoNothing)); |  | 
|   565   } |  | 
|   566  |  | 
|   567   callback.Run(success); |  | 
|   568 } |  | 
|   569  |  | 
|   570 void DisplayConfigurator::RelinquishControl( |  | 
|   571     const DisplayControlCallback& callback) { |  | 
|   572   if (display_control_changing_) { |  | 
|   573     callback.Run(false); |  | 
|   574     return; |  | 
|   575   } |  | 
|   576  |  | 
|   577   if (display_externally_controlled_) { |  | 
|   578     callback.Run(true); |  | 
|   579     return; |  | 
|   580   } |  | 
|   581  |  | 
|   582   // For simplicity, just fail if in the middle of a display configuration. |  | 
|   583   if (configuration_task_) { |  | 
|   584     callback.Run(false); |  | 
|   585     return; |  | 
|   586   } |  | 
|   587  |  | 
|   588   display_control_changing_ = true; |  | 
|   589  |  | 
|   590   // Turn off the displays before releasing control since we're no longer using |  | 
|   591   // them for output. |  | 
|   592   SetDisplayPowerInternal( |  | 
|   593       chromeos::DISPLAY_POWER_ALL_OFF, kSetDisplayPowerNoFlags, |  | 
|   594       base::Bind(&DisplayConfigurator::SendRelinquishDisplayControl, |  | 
|   595                  weak_ptr_factory_.GetWeakPtr(), callback)); |  | 
|   596 } |  | 
|   597  |  | 
|   598 void DisplayConfigurator::SendRelinquishDisplayControl( |  | 
|   599     const DisplayControlCallback& callback, bool success) { |  | 
|   600   if (success) { |  | 
|   601     // Set the flag early such that an incoming configuration event won't start |  | 
|   602     // while we're releasing control of the displays. |  | 
|   603     display_externally_controlled_ = true; |  | 
|   604     native_display_delegate_->RelinquishDisplayControl( |  | 
|   605         base::Bind(&DisplayConfigurator::OnDisplayControlRelinquished, |  | 
|   606                    weak_ptr_factory_.GetWeakPtr(), callback)); |  | 
|   607   } else { |  | 
|   608     display_control_changing_ = false; |  | 
|   609     callback.Run(false); |  | 
|   610   } |  | 
|   611 } |  | 
|   612  |  | 
|   613 void DisplayConfigurator::OnDisplayControlRelinquished( |  | 
|   614     const DisplayControlCallback& callback, |  | 
|   615     bool success) { |  | 
|   616   display_control_changing_ = false; |  | 
|   617   display_externally_controlled_ = success; |  | 
|   618   if (!success) { |  | 
|   619     force_configure_ = true; |  | 
|   620     RunPendingConfiguration(); |  | 
|   621   } |  | 
|   622  |  | 
|   623   callback.Run(success); |  | 
|   624 } |  | 
|   625  |  | 
|   626 void DisplayConfigurator::ForceInitialConfigure( |  | 
|   627     uint32_t background_color_argb) { |  | 
|   628   if (!configure_display_ || display_externally_controlled_) |  | 
|   629     return; |  | 
|   630  |  | 
|   631   DCHECK(native_display_delegate_); |  | 
|   632   native_display_delegate_->Initialize(); |  | 
|   633  |  | 
|   634   // ForceInitialConfigure should be the first configuration so there shouldn't |  | 
|   635   // be anything scheduled. |  | 
|   636   DCHECK(!configuration_task_); |  | 
|   637  |  | 
|   638   configuration_task_.reset(new UpdateDisplayConfigurationTask( |  | 
|   639       native_display_delegate_.get(), layout_manager_.get(), |  | 
|   640       requested_display_state_, requested_power_state_, |  | 
|   641       kSetDisplayPowerForceProbe, background_color_argb, true, |  | 
|   642       base::Bind(&DisplayConfigurator::OnConfigured, |  | 
|   643                  weak_ptr_factory_.GetWeakPtr()))); |  | 
|   644   configuration_task_->Run(); |  | 
|   645 } |  | 
|   646  |  | 
|   647 DisplayConfigurator::ContentProtectionClientId |  | 
|   648 DisplayConfigurator::RegisterContentProtectionClient() { |  | 
|   649   if (!configure_display_ || display_externally_controlled_) |  | 
|   650     return kInvalidClientId; |  | 
|   651  |  | 
|   652   return next_display_protection_client_id_++; |  | 
|   653 } |  | 
|   654  |  | 
|   655 void DisplayConfigurator::UnregisterContentProtectionClient( |  | 
|   656     ContentProtectionClientId client_id) { |  | 
|   657   client_protection_requests_.erase(client_id); |  | 
|   658  |  | 
|   659   ContentProtections protections; |  | 
|   660   for (const auto& requests_pair : client_protection_requests_) { |  | 
|   661     for (const auto& protections_pair : requests_pair.second) { |  | 
|   662       protections[protections_pair.first] |= protections_pair.second; |  | 
|   663     } |  | 
|   664   } |  | 
|   665  |  | 
|   666   enable_protection_callbacks_.push(base::Bind(&DoNothing)); |  | 
|   667   ApplyContentProtectionTask* task = new ApplyContentProtectionTask( |  | 
|   668       layout_manager_.get(), native_display_delegate_.get(), protections, |  | 
|   669       base::Bind(&DisplayConfigurator::OnContentProtectionClientUnregistered, |  | 
|   670                  weak_ptr_factory_.GetWeakPtr())); |  | 
|   671   content_protection_tasks_.push( |  | 
|   672       base::Bind(&ApplyContentProtectionTask::Run, base::Owned(task))); |  | 
|   673  |  | 
|   674   if (content_protection_tasks_.size() == 1) |  | 
|   675     content_protection_tasks_.front().Run(); |  | 
|   676 } |  | 
|   677  |  | 
|   678 void DisplayConfigurator::OnContentProtectionClientUnregistered(bool success) { |  | 
|   679   DCHECK(!content_protection_tasks_.empty()); |  | 
|   680   content_protection_tasks_.pop(); |  | 
|   681  |  | 
|   682   DCHECK(!enable_protection_callbacks_.empty()); |  | 
|   683   EnableProtectionCallback callback = enable_protection_callbacks_.front(); |  | 
|   684   enable_protection_callbacks_.pop(); |  | 
|   685  |  | 
|   686   if (!content_protection_tasks_.empty()) |  | 
|   687     content_protection_tasks_.front().Run(); |  | 
|   688 } |  | 
|   689  |  | 
|   690 void DisplayConfigurator::QueryContentProtectionStatus( |  | 
|   691     ContentProtectionClientId client_id, |  | 
|   692     int64_t display_id, |  | 
|   693     const QueryProtectionCallback& callback) { |  | 
|   694   // Exclude virtual displays so that protected content will not be recaptured |  | 
|   695   // through the cast stream. |  | 
|   696   for (const DisplaySnapshot* display : cached_displays_) { |  | 
|   697     if (display->display_id() == display_id && |  | 
|   698         !IsPhysicalDisplayType(display->type())) { |  | 
|   699       callback.Run(QueryProtectionResponse()); |  | 
|   700       return; |  | 
|   701     } |  | 
|   702   } |  | 
|   703  |  | 
|   704   if (!configure_display_ || display_externally_controlled_) { |  | 
|   705     callback.Run(QueryProtectionResponse()); |  | 
|   706     return; |  | 
|   707   } |  | 
|   708  |  | 
|   709   query_protection_callbacks_.push(callback); |  | 
|   710   QueryContentProtectionTask* task = new QueryContentProtectionTask( |  | 
|   711       layout_manager_.get(), native_display_delegate_.get(), display_id, |  | 
|   712       base::Bind(&DisplayConfigurator::OnContentProtectionQueried, |  | 
|   713                  weak_ptr_factory_.GetWeakPtr(), client_id, display_id)); |  | 
|   714   content_protection_tasks_.push( |  | 
|   715       base::Bind(&QueryContentProtectionTask::Run, base::Owned(task))); |  | 
|   716   if (content_protection_tasks_.size() == 1) |  | 
|   717     content_protection_tasks_.front().Run(); |  | 
|   718 } |  | 
|   719  |  | 
|   720 void DisplayConfigurator::OnContentProtectionQueried( |  | 
|   721     ContentProtectionClientId client_id, |  | 
|   722     int64_t display_id, |  | 
|   723     QueryContentProtectionTask::Response task_response) { |  | 
|   724   QueryProtectionResponse response; |  | 
|   725   response.success = task_response.success; |  | 
|   726   response.link_mask = task_response.link_mask; |  | 
|   727  |  | 
|   728   // Don't reveal protections requested by other clients. |  | 
|   729   ProtectionRequests::iterator it = client_protection_requests_.find(client_id); |  | 
|   730   if (response.success && it != client_protection_requests_.end()) { |  | 
|   731     uint32_t requested_mask = 0; |  | 
|   732     if (it->second.find(display_id) != it->second.end()) |  | 
|   733       requested_mask = it->second[display_id]; |  | 
|   734     response.protection_mask = |  | 
|   735         task_response.enabled & ~task_response.unfulfilled & requested_mask; |  | 
|   736   } |  | 
|   737  |  | 
|   738   DCHECK(!content_protection_tasks_.empty()); |  | 
|   739   content_protection_tasks_.pop(); |  | 
|   740  |  | 
|   741   DCHECK(!query_protection_callbacks_.empty()); |  | 
|   742   QueryProtectionCallback callback = query_protection_callbacks_.front(); |  | 
|   743   query_protection_callbacks_.pop(); |  | 
|   744   callback.Run(response); |  | 
|   745  |  | 
|   746   if (!content_protection_tasks_.empty()) |  | 
|   747     content_protection_tasks_.front().Run(); |  | 
|   748 } |  | 
|   749  |  | 
|   750 void DisplayConfigurator::EnableContentProtection( |  | 
|   751     ContentProtectionClientId client_id, |  | 
|   752     int64_t display_id, |  | 
|   753     uint32_t desired_method_mask, |  | 
|   754     const EnableProtectionCallback& callback) { |  | 
|   755   if (!configure_display_ || display_externally_controlled_) { |  | 
|   756     callback.Run(false); |  | 
|   757     return; |  | 
|   758   } |  | 
|   759  |  | 
|   760   ContentProtections protections; |  | 
|   761   for (const auto& requests_pair : client_protection_requests_) { |  | 
|   762     for (const auto& protections_pair : requests_pair.second) { |  | 
|   763       if (requests_pair.first == client_id && |  | 
|   764           protections_pair.first == display_id) |  | 
|   765         continue; |  | 
|   766  |  | 
|   767       protections[protections_pair.first] |= protections_pair.second; |  | 
|   768     } |  | 
|   769   } |  | 
|   770   protections[display_id] |= desired_method_mask; |  | 
|   771  |  | 
|   772   enable_protection_callbacks_.push(callback); |  | 
|   773   ApplyContentProtectionTask* task = new ApplyContentProtectionTask( |  | 
|   774       layout_manager_.get(), native_display_delegate_.get(), protections, |  | 
|   775       base::Bind(&DisplayConfigurator::OnContentProtectionEnabled, |  | 
|   776                  weak_ptr_factory_.GetWeakPtr(), client_id, display_id, |  | 
|   777                  desired_method_mask)); |  | 
|   778   content_protection_tasks_.push( |  | 
|   779       base::Bind(&ApplyContentProtectionTask::Run, base::Owned(task))); |  | 
|   780   if (content_protection_tasks_.size() == 1) |  | 
|   781     content_protection_tasks_.front().Run(); |  | 
|   782 } |  | 
|   783  |  | 
|   784 void DisplayConfigurator::OnContentProtectionEnabled( |  | 
|   785     ContentProtectionClientId client_id, |  | 
|   786     int64_t display_id, |  | 
|   787     uint32_t desired_method_mask, |  | 
|   788     bool success) { |  | 
|   789   DCHECK(!content_protection_tasks_.empty()); |  | 
|   790   content_protection_tasks_.pop(); |  | 
|   791  |  | 
|   792   DCHECK(!enable_protection_callbacks_.empty()); |  | 
|   793   EnableProtectionCallback callback = enable_protection_callbacks_.front(); |  | 
|   794   enable_protection_callbacks_.pop(); |  | 
|   795  |  | 
|   796   if (!success) { |  | 
|   797     callback.Run(false); |  | 
|   798     return; |  | 
|   799   } |  | 
|   800  |  | 
|   801   if (desired_method_mask == CONTENT_PROTECTION_METHOD_NONE) { |  | 
|   802     if (client_protection_requests_.find(client_id) != |  | 
|   803         client_protection_requests_.end()) { |  | 
|   804       client_protection_requests_[client_id].erase(display_id); |  | 
|   805       if (client_protection_requests_[client_id].size() == 0) |  | 
|   806         client_protection_requests_.erase(client_id); |  | 
|   807     } |  | 
|   808   } else { |  | 
|   809     client_protection_requests_[client_id][display_id] = desired_method_mask; |  | 
|   810   } |  | 
|   811  |  | 
|   812   callback.Run(true); |  | 
|   813   if (!content_protection_tasks_.empty()) |  | 
|   814     content_protection_tasks_.front().Run(); |  | 
|   815 } |  | 
|   816  |  | 
|   817 std::vector<ui::ColorCalibrationProfile> |  | 
|   818 DisplayConfigurator::GetAvailableColorCalibrationProfiles(int64_t display_id) { |  | 
|   819   if (!base::CommandLine::ForCurrentProcess()->HasSwitch( |  | 
|   820           switches::kDisableDisplayColorCalibration)) { |  | 
|   821     for (const DisplaySnapshot* display : cached_displays_) { |  | 
|   822       if (display->display_id() == display_id && |  | 
|   823           IsPhysicalDisplayType(display->type())) { |  | 
|   824         return native_display_delegate_->GetAvailableColorCalibrationProfiles( |  | 
|   825             *display); |  | 
|   826       } |  | 
|   827     } |  | 
|   828   } |  | 
|   829  |  | 
|   830   return std::vector<ui::ColorCalibrationProfile>(); |  | 
|   831 } |  | 
|   832  |  | 
|   833 bool DisplayConfigurator::SetColorCalibrationProfile( |  | 
|   834     int64_t display_id, |  | 
|   835     ui::ColorCalibrationProfile new_profile) { |  | 
|   836   for (const DisplaySnapshot* display : cached_displays_) { |  | 
|   837     if (display->display_id() == display_id && |  | 
|   838         IsPhysicalDisplayType(display->type())) { |  | 
|   839       return native_display_delegate_->SetColorCalibrationProfile(*display, |  | 
|   840                                                                   new_profile); |  | 
|   841     } |  | 
|   842   } |  | 
|   843  |  | 
|   844   return false; |  | 
|   845 } |  | 
|   846  |  | 
|   847 bool DisplayConfigurator::SetColorCorrection( |  | 
|   848     int64_t display_id, |  | 
|   849     const std::vector<GammaRampRGBEntry>& degamma_lut, |  | 
|   850     const std::vector<GammaRampRGBEntry>& gamma_lut, |  | 
|   851     const std::vector<float>& correction_matrix) { |  | 
|   852   for (const DisplaySnapshot* display : cached_displays_) { |  | 
|   853     if (display->display_id() == display_id) |  | 
|   854       return native_display_delegate_->SetColorCorrection( |  | 
|   855           *display, degamma_lut, gamma_lut, correction_matrix); |  | 
|   856   } |  | 
|   857  |  | 
|   858   return false; |  | 
|   859 } |  | 
|   860  |  | 
|   861 void DisplayConfigurator::PrepareForExit() { |  | 
|   862   configure_display_ = false; |  | 
|   863 } |  | 
|   864  |  | 
|   865 void DisplayConfigurator::SetDisplayPowerInternal( |  | 
|   866     chromeos::DisplayPowerState power_state, |  | 
|   867     int flags, |  | 
|   868     const ConfigurationCallback& callback) { |  | 
|   869   // Only skip if the current power state is the same and the latest requested |  | 
|   870   // power state is the same. If |pending_power_state_ != current_power_state_| |  | 
|   871   // then there is a current task pending or the last configuration failed. In |  | 
|   872   // either case request a new configuration to make sure the state is |  | 
|   873   // consistent with the expectations. |  | 
|   874   if (power_state == current_power_state_ && |  | 
|   875       power_state == pending_power_state_ && |  | 
|   876       !(flags & kSetDisplayPowerForceProbe)) { |  | 
|   877     callback.Run(true); |  | 
|   878     return; |  | 
|   879   } |  | 
|   880  |  | 
|   881   pending_power_state_ = power_state; |  | 
|   882   has_pending_power_state_ = true; |  | 
|   883   pending_power_flags_ = flags; |  | 
|   884   queued_configuration_callbacks_.push_back(callback); |  | 
|   885  |  | 
|   886   if (configure_timer_.IsRunning()) { |  | 
|   887     // If there is a configuration task scheduled, avoid performing |  | 
|   888     // configuration immediately. Instead reset the timer to wait for things to |  | 
|   889     // settle. |  | 
|   890     configure_timer_.Reset(); |  | 
|   891     return; |  | 
|   892   } |  | 
|   893  |  | 
|   894   RunPendingConfiguration(); |  | 
|   895 } |  | 
|   896  |  | 
|   897 void DisplayConfigurator::SetDisplayPower( |  | 
|   898     chromeos::DisplayPowerState power_state, |  | 
|   899     int flags, |  | 
|   900     const ConfigurationCallback& callback) { |  | 
|   901   if (!configure_display_ || display_externally_controlled_) { |  | 
|   902     callback.Run(false); |  | 
|   903     return; |  | 
|   904   } |  | 
|   905  |  | 
|   906   VLOG(1) << "SetDisplayPower: power_state=" |  | 
|   907           << DisplayPowerStateToString(power_state) << " flags=" << flags |  | 
|   908           << ", configure timer=" |  | 
|   909           << (configure_timer_.IsRunning() ? "Running" : "Stopped"); |  | 
|   910  |  | 
|   911   requested_power_state_ = power_state; |  | 
|   912   SetDisplayPowerInternal(requested_power_state_, flags, callback); |  | 
|   913 } |  | 
|   914  |  | 
|   915 void DisplayConfigurator::SetDisplayMode(MultipleDisplayState new_state) { |  | 
|   916   if (!configure_display_ || display_externally_controlled_) |  | 
|   917     return; |  | 
|   918  |  | 
|   919   VLOG(1) << "SetDisplayMode: state=" |  | 
|   920           << MultipleDisplayStateToString(new_state); |  | 
|   921   if (current_display_state_ == new_state) { |  | 
|   922     // Cancel software mirroring if the state is moving from |  | 
|   923     // MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED to |  | 
|   924     // MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED. |  | 
|   925     if (mirroring_controller_ && |  | 
|   926         new_state == MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED) |  | 
|   927       mirroring_controller_->SetSoftwareMirroring(false); |  | 
|   928     NotifyDisplayStateObservers(true, new_state); |  | 
|   929     return; |  | 
|   930   } |  | 
|   931  |  | 
|   932   requested_display_state_ = new_state; |  | 
|   933  |  | 
|   934   RunPendingConfiguration(); |  | 
|   935 } |  | 
|   936  |  | 
|   937 void DisplayConfigurator::OnConfigurationChanged() { |  | 
|   938   // Don't do anything if the displays are currently suspended.  Instead we will |  | 
|   939   // probe and reconfigure the displays if necessary in ResumeDisplays(). |  | 
|   940   if (displays_suspended_) { |  | 
|   941     VLOG(1) << "Displays are currently suspended.  Not attempting to " |  | 
|   942             << "reconfigure them."; |  | 
|   943     return; |  | 
|   944   } |  | 
|   945  |  | 
|   946   // Configure displays with |kConfigureDelayMs| delay, |  | 
|   947   // so that time-consuming ConfigureDisplays() won't be called multiple times. |  | 
|   948   configure_timer_.Start(FROM_HERE, |  | 
|   949                          base::TimeDelta::FromMilliseconds(kConfigureDelayMs), |  | 
|   950                          this, &DisplayConfigurator::ConfigureDisplays); |  | 
|   951 } |  | 
|   952  |  | 
|   953 void DisplayConfigurator::AddObserver(Observer* observer) { |  | 
|   954   observers_.AddObserver(observer); |  | 
|   955 } |  | 
|   956  |  | 
|   957 void DisplayConfigurator::RemoveObserver(Observer* observer) { |  | 
|   958   observers_.RemoveObserver(observer); |  | 
|   959 } |  | 
|   960  |  | 
|   961 void DisplayConfigurator::SuspendDisplays( |  | 
|   962     const ConfigurationCallback& callback) { |  | 
|   963   if (!configure_display_ || display_externally_controlled_) { |  | 
|   964     callback.Run(false); |  | 
|   965     return; |  | 
|   966   } |  | 
|   967  |  | 
|   968   displays_suspended_ = true; |  | 
|   969  |  | 
|   970   // Stop |configure_timer_| because we will force probe and configure all the |  | 
|   971   // displays at resume time anyway. |  | 
|   972   configure_timer_.Stop(); |  | 
|   973  |  | 
|   974   // Turn off the displays for suspend. This way, if we wake up for lucid sleep, |  | 
|   975   // the displays will not turn on (all displays should be off for lucid sleep |  | 
|   976   // unless explicitly requested by lucid sleep code). Use |  | 
|   977   // SetDisplayPowerInternal so requested_power_state_ is maintained. |  | 
|   978   SetDisplayPowerInternal(chromeos::DISPLAY_POWER_ALL_OFF, |  | 
|   979                           kSetDisplayPowerNoFlags, callback); |  | 
|   980  |  | 
|   981   // We need to make sure that the monitor configuration we just did actually |  | 
|   982   // completes before we return. |  | 
|   983   native_display_delegate_->SyncWithServer(); |  | 
|   984 } |  | 
|   985  |  | 
|   986 void DisplayConfigurator::ResumeDisplays() { |  | 
|   987   if (!configure_display_ || display_externally_controlled_) |  | 
|   988     return; |  | 
|   989  |  | 
|   990   displays_suspended_ = false; |  | 
|   991  |  | 
|   992   if (current_display_state_ == MULTIPLE_DISPLAY_STATE_DUAL_MIRROR || |  | 
|   993       current_display_state_ == MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED || |  | 
|   994       current_display_state_ == MULTIPLE_DISPLAY_STATE_MULTI_EXTENDED) { |  | 
|   995     // When waking up from suspend while being in a multi display mode, we |  | 
|   996     // schedule a delayed forced configuration, which will make |  | 
|   997     // SetDisplayPowerInternal() avoid performing the configuration immediately. |  | 
|   998     // This gives a chance to wait for all displays to be added and detected |  | 
|   999     // before configuration is performed, so we won't immediately resize the |  | 
|  1000     // desktops and the windows on it to fit on a single display. |  | 
|  1001     configure_timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds( |  | 
|  1002                                           kResumeConfigureMultiDisplayDelayMs), |  | 
|  1003                            this, &DisplayConfigurator::ConfigureDisplays); |  | 
|  1004   } |  | 
|  1005  |  | 
|  1006   // If requested_power_state_ is ALL_OFF due to idle suspend, powerd will turn |  | 
|  1007   // the display power on when it enables the backlight. |  | 
|  1008   SetDisplayPower(requested_power_state_, kSetDisplayPowerNoFlags, |  | 
|  1009                   base::Bind(&DoNothing)); |  | 
|  1010 } |  | 
|  1011  |  | 
|  1012 void DisplayConfigurator::ConfigureDisplays() { |  | 
|  1013   if (!configure_display_ || display_externally_controlled_) |  | 
|  1014     return; |  | 
|  1015  |  | 
|  1016   force_configure_ = true; |  | 
|  1017   RunPendingConfiguration(); |  | 
|  1018 } |  | 
|  1019  |  | 
|  1020 void DisplayConfigurator::RunPendingConfiguration() { |  | 
|  1021   // Configuration task is currently running. Do not start a second |  | 
|  1022   // configuration. |  | 
|  1023   if (configuration_task_) |  | 
|  1024     return; |  | 
|  1025  |  | 
|  1026   if (!ShouldRunConfigurationTask()) { |  | 
|  1027     LOG(ERROR) << "Called RunPendingConfiguration without any changes" |  | 
|  1028                   " requested"; |  | 
|  1029     CallAndClearQueuedCallbacks(true); |  | 
|  1030     return; |  | 
|  1031   } |  | 
|  1032  |  | 
|  1033   configuration_task_.reset(new UpdateDisplayConfigurationTask( |  | 
|  1034       native_display_delegate_.get(), layout_manager_.get(), |  | 
|  1035       requested_display_state_, pending_power_state_, pending_power_flags_, |  | 
|  1036       0, force_configure_, base::Bind(&DisplayConfigurator::OnConfigured, |  | 
|  1037                                       weak_ptr_factory_.GetWeakPtr()))); |  | 
|  1038   configuration_task_->set_virtual_display_snapshots( |  | 
|  1039       virtual_display_snapshots_.get()); |  | 
|  1040  |  | 
|  1041   // Reset the flags before running the task; otherwise it may end up scheduling |  | 
|  1042   // another configuration. |  | 
|  1043   force_configure_ = false; |  | 
|  1044   pending_power_flags_ = kSetDisplayPowerNoFlags; |  | 
|  1045   has_pending_power_state_ = false; |  | 
|  1046   requested_display_state_ = MULTIPLE_DISPLAY_STATE_INVALID; |  | 
|  1047  |  | 
|  1048   DCHECK(in_progress_configuration_callbacks_.empty()); |  | 
|  1049   in_progress_configuration_callbacks_.swap(queued_configuration_callbacks_); |  | 
|  1050  |  | 
|  1051   configuration_task_->Run(); |  | 
|  1052 } |  | 
|  1053  |  | 
|  1054 void DisplayConfigurator::OnConfigured( |  | 
|  1055     bool success, |  | 
|  1056     const std::vector<DisplaySnapshot*>& displays, |  | 
|  1057     const gfx::Size& framebuffer_size, |  | 
|  1058     MultipleDisplayState new_display_state, |  | 
|  1059     chromeos::DisplayPowerState new_power_state) { |  | 
|  1060   VLOG(1) << "OnConfigured: success=" << success << " new_display_state=" |  | 
|  1061           << MultipleDisplayStateToString(new_display_state) |  | 
|  1062           << " new_power_state=" << DisplayPowerStateToString(new_power_state); |  | 
|  1063  |  | 
|  1064   cached_displays_ = displays; |  | 
|  1065   if (success) { |  | 
|  1066     chromeos::DisplayPowerState old_power_state = current_power_state_; |  | 
|  1067     current_display_state_ = new_display_state; |  | 
|  1068     current_power_state_ = new_power_state; |  | 
|  1069  |  | 
|  1070     // |framebuffer_size| is empty in software mirroring mode, headless mode, |  | 
|  1071     // or all displays are off. |  | 
|  1072     DCHECK(!framebuffer_size.IsEmpty() || |  | 
|  1073            (mirroring_controller_ && |  | 
|  1074             mirroring_controller_->SoftwareMirroringEnabled()) || |  | 
|  1075            new_display_state == MULTIPLE_DISPLAY_STATE_HEADLESS || |  | 
|  1076            new_power_state == chromeos::DISPLAY_POWER_ALL_OFF); |  | 
|  1077  |  | 
|  1078     if (!framebuffer_size.IsEmpty()) |  | 
|  1079       framebuffer_size_ = framebuffer_size; |  | 
|  1080  |  | 
|  1081     // If the pending power state hasn't changed then make sure that value |  | 
|  1082     // gets updated as well since the last requested value may have been |  | 
|  1083     // dependent on certain conditions (ie: if only the internal monitor was |  | 
|  1084     // present). |  | 
|  1085     if (!has_pending_power_state_) |  | 
|  1086       pending_power_state_ = new_power_state; |  | 
|  1087  |  | 
|  1088     if (old_power_state != current_power_state_) |  | 
|  1089       NotifyPowerStateObservers(); |  | 
|  1090   } |  | 
|  1091  |  | 
|  1092   configuration_task_.reset(); |  | 
|  1093   NotifyDisplayStateObservers(success, new_display_state); |  | 
|  1094   CallAndClearInProgressCallbacks(success); |  | 
|  1095  |  | 
|  1096   if (success && !configure_timer_.IsRunning() && |  | 
|  1097       ShouldRunConfigurationTask()) { |  | 
|  1098     configure_timer_.Start(FROM_HERE, |  | 
|  1099                            base::TimeDelta::FromMilliseconds(kConfigureDelayMs), |  | 
|  1100                            this, &DisplayConfigurator::RunPendingConfiguration); |  | 
|  1101   } else { |  | 
|  1102     // If a new configuration task isn't scheduled respond to all queued |  | 
|  1103     // callbacks (for example if requested state is current state). |  | 
|  1104     if (!configure_timer_.IsRunning()) |  | 
|  1105       CallAndClearQueuedCallbacks(success); |  | 
|  1106   } |  | 
|  1107 } |  | 
|  1108  |  | 
|  1109 bool DisplayConfigurator::ShouldRunConfigurationTask() const { |  | 
|  1110   if (force_configure_) |  | 
|  1111     return true; |  | 
|  1112  |  | 
|  1113   // Schedule if there is a request to change the display state. |  | 
|  1114   if (requested_display_state_ != current_display_state_ && |  | 
|  1115       requested_display_state_ != MULTIPLE_DISPLAY_STATE_INVALID) |  | 
|  1116     return true; |  | 
|  1117  |  | 
|  1118   // Schedule if there is a request to change the power state. |  | 
|  1119   if (has_pending_power_state_) |  | 
|  1120     return true; |  | 
|  1121  |  | 
|  1122   return false; |  | 
|  1123 } |  | 
|  1124  |  | 
|  1125 void DisplayConfigurator::CallAndClearInProgressCallbacks(bool success) { |  | 
|  1126   for (const auto& callback : in_progress_configuration_callbacks_) |  | 
|  1127     callback.Run(success); |  | 
|  1128  |  | 
|  1129   in_progress_configuration_callbacks_.clear(); |  | 
|  1130 } |  | 
|  1131  |  | 
|  1132 void DisplayConfigurator::CallAndClearQueuedCallbacks(bool success) { |  | 
|  1133   for (const auto& callback : queued_configuration_callbacks_) |  | 
|  1134     callback.Run(success); |  | 
|  1135  |  | 
|  1136   queued_configuration_callbacks_.clear(); |  | 
|  1137 } |  | 
|  1138  |  | 
|  1139 void DisplayConfigurator::NotifyDisplayStateObservers( |  | 
|  1140     bool success, |  | 
|  1141     MultipleDisplayState attempted_state) { |  | 
|  1142   if (success) { |  | 
|  1143     for (Observer& observer : observers_) |  | 
|  1144       observer.OnDisplayModeChanged(cached_displays_); |  | 
|  1145   } else { |  | 
|  1146     for (Observer& observer : observers_) |  | 
|  1147       observer.OnDisplayModeChangeFailed(cached_displays_, attempted_state); |  | 
|  1148   } |  | 
|  1149 } |  | 
|  1150  |  | 
|  1151 void DisplayConfigurator::NotifyPowerStateObservers() { |  | 
|  1152   for (Observer& observer : observers_) |  | 
|  1153     observer.OnPowerStateChanged(current_power_state_); |  | 
|  1154 } |  | 
|  1155  |  | 
|  1156 int64_t DisplayConfigurator::AddVirtualDisplay(const gfx::Size& display_size) { |  | 
|  1157   if (last_virtual_display_id_ == 0xff) { |  | 
|  1158     LOG(WARNING) << "Exceeded virtual display id limit"; |  | 
|  1159     return display::kInvalidDisplayId; |  | 
|  1160   } |  | 
|  1161  |  | 
|  1162   DisplaySnapshotVirtual* virtual_snapshot = new DisplaySnapshotVirtual( |  | 
|  1163       display::GenerateDisplayID(kReservedManufacturerID, 0x0, |  | 
|  1164                                  ++last_virtual_display_id_), |  | 
|  1165       display_size); |  | 
|  1166   virtual_display_snapshots_.push_back(virtual_snapshot); |  | 
|  1167   ConfigureDisplays(); |  | 
|  1168  |  | 
|  1169   return virtual_snapshot->display_id(); |  | 
|  1170 } |  | 
|  1171  |  | 
|  1172 bool DisplayConfigurator::RemoveVirtualDisplay(int64_t display_id) { |  | 
|  1173   bool display_found = false; |  | 
|  1174   for (auto it = virtual_display_snapshots_.begin(); |  | 
|  1175        it != virtual_display_snapshots_.end(); ++it) { |  | 
|  1176     if ((*it)->display_id() == display_id) { |  | 
|  1177       virtual_display_snapshots_.erase(it); |  | 
|  1178       ConfigureDisplays(); |  | 
|  1179       display_found = true; |  | 
|  1180       break; |  | 
|  1181     } |  | 
|  1182   } |  | 
|  1183  |  | 
|  1184   if (!display_found) |  | 
|  1185     return false; |  | 
|  1186  |  | 
|  1187   int64_t max_display_id = 0; |  | 
|  1188   for (auto* display : virtual_display_snapshots_) |  | 
|  1189     max_display_id = std::max(max_display_id, display->display_id()); |  | 
|  1190   last_virtual_display_id_ = max_display_id & 0xff; |  | 
|  1191  |  | 
|  1192   return true; |  | 
|  1193 } |  | 
|  1194  |  | 
|  1195 bool DisplayConfigurator::IsDisplayOn() const { |  | 
|  1196   return current_power_state_ != chromeos::DISPLAY_POWER_ALL_OFF; |  | 
|  1197 } |  | 
|  1198  |  | 
|  1199 }  // namespace ui |  | 
| OLD | NEW |