Home | History | Annotate | Download | only in display
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "ash/display/display_change_observer_chromeos.h"
      6 
      7 #include <algorithm>
      8 #include <map>
      9 #include <set>
     10 #include <vector>
     11 
     12 #include "ash/ash_switches.h"
     13 #include "ash/display/display_info.h"
     14 #include "ash/display/display_layout_store.h"
     15 #include "ash/display/display_manager.h"
     16 #include "ash/shell.h"
     17 #include "ash/touch/touchscreen_util.h"
     18 #include "base/command_line.h"
     19 #include "base/logging.h"
     20 #include "grit/ash_strings.h"
     21 #include "ui/base/l10n/l10n_util.h"
     22 #include "ui/compositor/dip_util.h"
     23 #include "ui/display/types/display_mode.h"
     24 #include "ui/display/types/display_snapshot.h"
     25 #include "ui/display/util/display_util.h"
     26 #include "ui/events/device_data_manager.h"
     27 #include "ui/events/touchscreen_device.h"
     28 #include "ui/gfx/display.h"
     29 #include "ui/wm/core/user_activity_detector.h"
     30 
     31 namespace ash {
     32 
     33 using ui::DisplayConfigurator;
     34 
     35 namespace {
     36 
     37 // The DPI threshold to determine the device scale factor.
     38 // DPI higher than |dpi| will use |device_scale_factor|.
     39 struct DeviceScaleFactorDPIThreshold {
     40   float dpi;
     41   float device_scale_factor;
     42 };
     43 
     44 const DeviceScaleFactorDPIThreshold kThresholdTable[] = {
     45   {180.0f, 2.0f},
     46   {150.0f, 1.25f},
     47   {0.0f, 1.0f},
     48 };
     49 
     50 // 1 inch in mm.
     51 const float kInchInMm = 25.4f;
     52 
     53 // The minimum pixel width whose monitor can be called as '4K'.
     54 const int kMinimumWidthFor4K = 3840;
     55 
     56 // The list of device scale factors (in addition to 1.0f) which is
     57 // available in extrenal large monitors.
     58 const float kAdditionalDeviceScaleFactorsFor4k[] = {1.25f, 2.0f};
     59 
     60 // Display mode list is sorted by:
     61 //  * the area in pixels in ascending order
     62 //  * refresh rate in descending order
     63 struct DisplayModeSorter {
     64   bool operator()(const DisplayMode& a, const DisplayMode& b) {
     65     gfx::Size size_a_dip = a.GetSizeInDIP();
     66     gfx::Size size_b_dip = b.GetSizeInDIP();
     67     if (size_a_dip.GetArea() == size_b_dip.GetArea())
     68       return (a.refresh_rate > b.refresh_rate);
     69     return (size_a_dip.GetArea() < size_b_dip.GetArea());
     70   }
     71 };
     72 
     73 }  // namespace
     74 
     75 // static
     76 std::vector<DisplayMode> DisplayChangeObserver::GetInternalDisplayModeList(
     77     const DisplayInfo& display_info,
     78     const DisplayConfigurator::DisplayState& output) {
     79   std::vector<DisplayMode> display_mode_list;
     80   const ui::DisplayMode* ui_native_mode = output.display->native_mode();
     81   DisplayMode native_mode(ui_native_mode->size(),
     82                           ui_native_mode->refresh_rate(),
     83                           ui_native_mode->is_interlaced(),
     84                           true);
     85   native_mode.device_scale_factor = display_info.device_scale_factor();
     86   std::vector<float> ui_scales =
     87       DisplayManager::GetScalesForDisplay(display_info);
     88   float native_ui_scale = (display_info.device_scale_factor() == 1.25f) ?
     89       1.0f : display_info.device_scale_factor();
     90   for (size_t i = 0; i < ui_scales.size(); ++i) {
     91     DisplayMode mode = native_mode;
     92     mode.ui_scale = ui_scales[i];
     93     mode.native = (ui_scales[i] == native_ui_scale);
     94     display_mode_list.push_back(mode);
     95   }
     96 
     97   std::sort(
     98       display_mode_list.begin(), display_mode_list.end(), DisplayModeSorter());
     99   return display_mode_list;
    100 }
    101 
    102 // static
    103 std::vector<DisplayMode> DisplayChangeObserver::GetExternalDisplayModeList(
    104     const DisplayConfigurator::DisplayState& output) {
    105   typedef std::map<std::pair<int, int>, DisplayMode> DisplayModeMap;
    106   DisplayModeMap display_mode_map;
    107 
    108   DisplayMode native_mode;
    109   for (std::vector<const ui::DisplayMode*>::const_iterator it =
    110            output.display->modes().begin();
    111        it != output.display->modes().end();
    112        ++it) {
    113     const ui::DisplayMode& mode_info = **it;
    114     const std::pair<int, int> size(mode_info.size().width(),
    115                                    mode_info.size().height());
    116     const DisplayMode display_mode(mode_info.size(),
    117                                    mode_info.refresh_rate(),
    118                                    mode_info.is_interlaced(),
    119                                    output.display->native_mode() == *it);
    120     if (display_mode.native)
    121       native_mode = display_mode;
    122 
    123     // Add the display mode if it isn't already present and override interlaced
    124     // display modes with non-interlaced ones.
    125     DisplayModeMap::iterator display_mode_it = display_mode_map.find(size);
    126     if (display_mode_it == display_mode_map.end())
    127       display_mode_map.insert(std::make_pair(size, display_mode));
    128     else if (display_mode_it->second.interlaced && !display_mode.interlaced)
    129       display_mode_it->second = display_mode;
    130   }
    131 
    132   std::vector<DisplayMode> display_mode_list;
    133   for (DisplayModeMap::const_iterator iter = display_mode_map.begin();
    134        iter != display_mode_map.end();
    135        ++iter) {
    136     display_mode_list.push_back(iter->second);
    137   }
    138 
    139   if (native_mode.size.width() >= kMinimumWidthFor4K) {
    140     for (size_t i = 0; i < arraysize(kAdditionalDeviceScaleFactorsFor4k);
    141          ++i) {
    142       DisplayMode mode = native_mode;
    143       mode.device_scale_factor = kAdditionalDeviceScaleFactorsFor4k[i];
    144       mode.native = false;
    145       display_mode_list.push_back(mode);
    146     }
    147   }
    148 
    149   std::sort(
    150       display_mode_list.begin(), display_mode_list.end(), DisplayModeSorter());
    151   return display_mode_list;
    152 }
    153 
    154 DisplayChangeObserver::DisplayChangeObserver() {
    155   Shell::GetInstance()->AddShellObserver(this);
    156   ui::DeviceDataManager::GetInstance()->AddObserver(this);
    157 }
    158 
    159 DisplayChangeObserver::~DisplayChangeObserver() {
    160   ui::DeviceDataManager::GetInstance()->RemoveObserver(this);
    161   Shell::GetInstance()->RemoveShellObserver(this);
    162 }
    163 
    164 ui::MultipleDisplayState DisplayChangeObserver::GetStateForDisplayIds(
    165     const std::vector<int64>& display_ids) const {
    166   CHECK_EQ(2U, display_ids.size());
    167   DisplayIdPair pair = std::make_pair(display_ids[0], display_ids[1]);
    168   DisplayLayout layout = Shell::GetInstance()->display_manager()->
    169       layout_store()->GetRegisteredDisplayLayout(pair);
    170   return layout.mirrored ? ui::MULTIPLE_DISPLAY_STATE_DUAL_MIRROR :
    171                            ui::MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED;
    172 }
    173 
    174 bool DisplayChangeObserver::GetResolutionForDisplayId(int64 display_id,
    175                                                       gfx::Size* size) const {
    176   DisplayMode mode;
    177   if (!Shell::GetInstance()->display_manager()->GetSelectedModeForDisplayId(
    178            display_id, &mode))
    179     return false;
    180 
    181   *size = mode.size;
    182   return true;
    183 }
    184 
    185 void DisplayChangeObserver::OnDisplayModeChanged(
    186     const std::vector<DisplayConfigurator::DisplayState>& display_states) {
    187   std::vector<DisplayInfo> displays;
    188   std::set<int64> ids;
    189   for (size_t i = 0; i < display_states.size(); ++i) {
    190     const DisplayConfigurator::DisplayState& state = display_states[i];
    191 
    192     if (state.display->type() == ui::DISPLAY_CONNECTION_TYPE_INTERNAL &&
    193         gfx::Display::InternalDisplayId() == gfx::Display::kInvalidDisplayID) {
    194       gfx::Display::SetInternalDisplayId(state.display->display_id());
    195     }
    196 
    197     const ui::DisplayMode* mode_info = state.display->current_mode();
    198     if (!mode_info)
    199       continue;
    200 
    201     float device_scale_factor = 1.0f;
    202     if (state.display->type() == ui::DISPLAY_CONNECTION_TYPE_INTERNAL) {
    203       if (!ui::IsDisplaySizeBlackListed(state.display->physical_size())) {
    204         device_scale_factor =
    205             FindDeviceScaleFactor((kInchInMm * mode_info->size().width() /
    206                                    state.display->physical_size().width()));
    207       }
    208     } else {
    209       DisplayMode mode;
    210       if (Shell::GetInstance()->display_manager()->GetSelectedModeForDisplayId(
    211               state.display->display_id(), &mode)) {
    212         device_scale_factor = mode.device_scale_factor;
    213       }
    214     }
    215     gfx::Rect display_bounds(state.display->origin(), mode_info->size());
    216 
    217     std::string name =
    218         state.display->type() == ui::DISPLAY_CONNECTION_TYPE_INTERNAL ?
    219             l10n_util::GetStringUTF8(IDS_ASH_INTERNAL_DISPLAY_NAME) :
    220             state.display->display_name();
    221     if (name.empty())
    222       name = l10n_util::GetStringUTF8(IDS_ASH_STATUS_TRAY_UNKNOWN_DISPLAY_NAME);
    223 
    224     bool has_overscan = state.display->has_overscan();
    225     int64 id = state.display->display_id();
    226     ids.insert(id);
    227 
    228     displays.push_back(DisplayInfo(id, name, has_overscan));
    229     DisplayInfo& new_info = displays.back();
    230     new_info.set_device_scale_factor(device_scale_factor);
    231     new_info.SetBounds(display_bounds);
    232     new_info.set_native(true);
    233     new_info.set_is_aspect_preserving_scaling(
    234         state.display->is_aspect_preserving_scaling());
    235 
    236     std::vector<DisplayMode> display_modes =
    237         (state.display->type() == ui::DISPLAY_CONNECTION_TYPE_INTERNAL) ?
    238         GetInternalDisplayModeList(new_info, state) :
    239         GetExternalDisplayModeList(state);
    240     new_info.set_display_modes(display_modes);
    241 
    242     new_info.set_available_color_profiles(
    243         Shell::GetInstance()
    244             ->display_configurator()
    245             ->GetAvailableColorCalibrationProfiles(id));
    246   }
    247 
    248   AssociateTouchscreens(
    249       &displays, ui::DeviceDataManager::GetInstance()->touchscreen_devices());
    250   // DisplayManager can be null during the boot.
    251   Shell::GetInstance()->display_manager()->OnNativeDisplaysChanged(displays);
    252 
    253   // For the purposes of user activity detection, ignore synthetic mouse events
    254   // that are triggered by screen resizes: http://crbug.com/360634
    255   ::wm::UserActivityDetector* user_activity_detector =
    256       Shell::GetInstance()->user_activity_detector();
    257   if (user_activity_detector)
    258     user_activity_detector->OnDisplayPowerChanging();
    259 }
    260 
    261 void DisplayChangeObserver::OnAppTerminating() {
    262 #if defined(USE_ASH)
    263   // Stop handling display configuration events once the shutdown
    264   // process starts. crbug.com/177014.
    265   Shell::GetInstance()->display_configurator()->PrepareForExit();
    266 #endif
    267 }
    268 
    269 // static
    270 float DisplayChangeObserver::FindDeviceScaleFactor(float dpi) {
    271   for (size_t i = 0; i < arraysize(kThresholdTable); ++i) {
    272     if (dpi > kThresholdTable[i].dpi)
    273       return kThresholdTable[i].device_scale_factor;
    274   }
    275   return 1.0f;
    276 }
    277 
    278 void DisplayChangeObserver::OnInputDeviceConfigurationChanged() {
    279   OnDisplayModeChanged(
    280       Shell::GetInstance()->display_configurator()->cached_displays());
    281 }
    282 
    283 }  // namespace ash
    284