Home | History | Annotate | Download | only in display
      1 // Copyright (c) 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 <stdio.h>
      6 #include <string>
      7 #include <vector>
      8 
      9 #include "ash/display/display_info.h"
     10 #include "base/logging.h"
     11 #include "base/strings/string_number_conversions.h"
     12 #include "base/strings/string_util.h"
     13 #include "base/strings/stringprintf.h"
     14 #include "ui/gfx/display.h"
     15 #include "ui/gfx/size_conversions.h"
     16 #include "ui/gfx/size_f.h"
     17 
     18 #if defined(OS_WIN)
     19 #include "ui/aura/window_tree_host.h"
     20 #endif
     21 
     22 namespace ash {
     23 namespace internal {
     24 
     25 Resolution::Resolution(const gfx::Size& size, bool interlaced)
     26     : size(size),
     27       interlaced(interlaced) {
     28 }
     29 
     30 // satic
     31 DisplayInfo DisplayInfo::CreateFromSpec(const std::string& spec) {
     32   return CreateFromSpecWithID(spec, gfx::Display::kInvalidDisplayID);
     33 }
     34 
     35 // static
     36 DisplayInfo DisplayInfo::CreateFromSpecWithID(const std::string& spec,
     37                                               int64 id) {
     38   // Default bounds for a display.
     39   const int kDefaultHostWindowX = 200;
     40   const int kDefaultHostWindowY = 200;
     41   const int kDefaultHostWindowWidth = 1366;
     42   const int kDefaultHostWindowHeight = 768;
     43 
     44   // Use larger than max int to catch overflow early.
     45   static int64 synthesized_display_id = 2200000000LL;
     46 
     47 #if defined(OS_WIN)
     48   gfx::Rect bounds_in_native(aura::RootWindowHost::GetNativeScreenSize());
     49 #else
     50   gfx::Rect bounds_in_native(kDefaultHostWindowX, kDefaultHostWindowY,
     51                              kDefaultHostWindowWidth, kDefaultHostWindowHeight);
     52 #endif
     53   std::string main_spec = spec;
     54 
     55   float ui_scale = 1.0f;
     56   std::vector<std::string> parts;
     57   if (Tokenize(main_spec, "@", &parts) == 2) {
     58     double scale_in_double = 0;
     59     if (base::StringToDouble(parts[1], &scale_in_double))
     60       ui_scale = scale_in_double;
     61     main_spec = parts[0];
     62   }
     63 
     64   size_t count = Tokenize(main_spec, "/", &parts);
     65   gfx::Display::Rotation rotation(gfx::Display::ROTATE_0);
     66   bool has_overscan = false;
     67   if (count) {
     68     main_spec = parts[0];
     69     if (count >= 2) {
     70       std::string options = parts[1];
     71       for (size_t i = 0; i < options.size(); ++i) {
     72         char c = options[i];
     73         switch (c) {
     74           case 'o':
     75             has_overscan = true;
     76             break;
     77           case 'r':  // rotate 90 degrees to 'right'.
     78             rotation = gfx::Display::ROTATE_90;
     79             break;
     80           case 'u':  // 180 degrees, 'u'pside-down.
     81             rotation = gfx::Display::ROTATE_180;
     82             break;
     83           case 'l':  // rotate 90 degrees to 'left'.
     84             rotation = gfx::Display::ROTATE_270;
     85             break;
     86         }
     87       }
     88     }
     89   }
     90 
     91   int x = 0, y = 0, width, height;
     92   float device_scale_factor = 1.0f;
     93   if (sscanf(main_spec.c_str(), "%dx%d*%f",
     94              &width, &height, &device_scale_factor) >= 2 ||
     95       sscanf(main_spec.c_str(), "%d+%d-%dx%d*%f", &x, &y, &width, &height,
     96              &device_scale_factor) >= 4) {
     97     bounds_in_native.SetRect(x, y, width, height);
     98   }
     99 
    100   std::vector<Resolution> resolutions;
    101   if (Tokenize(main_spec, "#", &parts) == 2) {
    102     main_spec = parts[0];
    103     std::string resolution_list = parts[1];
    104     count = Tokenize(resolution_list, "|", &parts);
    105     for (size_t i = 0; i < count; ++i) {
    106       std::string resolution = parts[i];
    107       int width, height;
    108       if (sscanf(resolution.c_str(), "%dx%d", &width, &height) == 2)
    109         resolutions.push_back(Resolution(gfx::Size(width, height), false));
    110     }
    111   }
    112 
    113   if (id == gfx::Display::kInvalidDisplayID)
    114     id = synthesized_display_id++;
    115   DisplayInfo display_info(
    116       id, base::StringPrintf("Display-%d", static_cast<int>(id)), has_overscan);
    117   display_info.set_device_scale_factor(device_scale_factor);
    118   display_info.set_rotation(rotation);
    119   display_info.set_configured_ui_scale(ui_scale);
    120   display_info.SetBounds(bounds_in_native);
    121   display_info.set_resolutions(resolutions);
    122 
    123   // To test the overscan, it creates the default 5% overscan.
    124   if (has_overscan) {
    125     int width = bounds_in_native.width() / device_scale_factor / 40;
    126     int height = bounds_in_native.height() / device_scale_factor / 40;
    127     display_info.SetOverscanInsets(gfx::Insets(height, width, height, width));
    128     display_info.UpdateDisplaySize();
    129   }
    130 
    131   DVLOG(1) << "DisplayInfoFromSpec info=" << display_info.ToString()
    132            << ", spec=" << spec;
    133   return display_info;
    134 }
    135 
    136 DisplayInfo::DisplayInfo()
    137     : id_(gfx::Display::kInvalidDisplayID),
    138       has_overscan_(false),
    139       rotation_(gfx::Display::ROTATE_0),
    140       touch_support_(gfx::Display::TOUCH_SUPPORT_UNKNOWN),
    141       device_scale_factor_(1.0f),
    142       overscan_insets_in_dip_(0, 0, 0, 0),
    143       configured_ui_scale_(1.0f),
    144       native_(false) {
    145 }
    146 
    147 DisplayInfo::DisplayInfo(int64 id,
    148                          const std::string& name,
    149                          bool has_overscan)
    150     : id_(id),
    151       name_(name),
    152       has_overscan_(has_overscan),
    153       rotation_(gfx::Display::ROTATE_0),
    154       touch_support_(gfx::Display::TOUCH_SUPPORT_UNKNOWN),
    155       device_scale_factor_(1.0f),
    156       overscan_insets_in_dip_(0, 0, 0, 0),
    157       configured_ui_scale_(1.0f),
    158       native_(false) {
    159 }
    160 
    161 DisplayInfo::~DisplayInfo() {
    162 }
    163 
    164 void DisplayInfo::Copy(const DisplayInfo& native_info) {
    165   DCHECK(id_ == native_info.id_);
    166   name_ = native_info.name_;
    167   has_overscan_ = native_info.has_overscan_;
    168 
    169   DCHECK(!native_info.bounds_in_native_.IsEmpty());
    170   bounds_in_native_ = native_info.bounds_in_native_;
    171   size_in_pixel_ = native_info.size_in_pixel_;
    172   device_scale_factor_ = native_info.device_scale_factor_;
    173   resolutions_ = native_info.resolutions_;
    174   touch_support_ = native_info.touch_support_;
    175 
    176   // Copy overscan_insets_in_dip_ if it's not empty. This is for test
    177   // cases which use "/o" annotation which sets the overscan inset
    178   // to native, and that overscan has to be propagated. This does not
    179   // happen on the real environment.
    180   if (!native_info.overscan_insets_in_dip_.empty())
    181     overscan_insets_in_dip_ = native_info.overscan_insets_in_dip_;
    182 
    183   // Rotation_ and ui_scale_ are given by preference, or unit
    184   // tests. Don't copy if this native_info came from
    185   // DisplayChangeObserver.
    186   if (!native_info.native()) {
    187     rotation_ = native_info.rotation_;
    188     configured_ui_scale_ = native_info.configured_ui_scale_;
    189   }
    190   // Don't copy insets as it may be given by preference.  |rotation_|
    191   // is treated as a native so that it can be specified in
    192   // |CreateFromSpec|.
    193 }
    194 
    195 void DisplayInfo::SetBounds(const gfx::Rect& new_bounds_in_native) {
    196   bounds_in_native_ = new_bounds_in_native;
    197   size_in_pixel_ = new_bounds_in_native.size();
    198   UpdateDisplaySize();
    199 }
    200 
    201 float DisplayInfo::GetEffectiveUIScale() const {
    202   if (device_scale_factor_ == 2.0f && configured_ui_scale_ == 2.0f)
    203     return 1.0f;
    204   return configured_ui_scale_;
    205 }
    206 
    207 void DisplayInfo::UpdateDisplaySize() {
    208   size_in_pixel_ = bounds_in_native_.size();
    209   if (!overscan_insets_in_dip_.empty()) {
    210     gfx::Insets insets_in_pixel =
    211         overscan_insets_in_dip_.Scale(device_scale_factor_);
    212     size_in_pixel_.Enlarge(-insets_in_pixel.width(), -insets_in_pixel.height());
    213   } else {
    214     overscan_insets_in_dip_.Set(0, 0, 0, 0);
    215   }
    216 
    217   if (rotation_ == gfx::Display::ROTATE_90 ||
    218       rotation_ == gfx::Display::ROTATE_270)
    219     size_in_pixel_.SetSize(size_in_pixel_.height(), size_in_pixel_.width());
    220   gfx::SizeF size_f(size_in_pixel_);
    221   size_f.Scale(GetEffectiveUIScale());
    222   size_in_pixel_ = gfx::ToFlooredSize(size_f);
    223 }
    224 
    225 void DisplayInfo::SetOverscanInsets(const gfx::Insets& insets_in_dip) {
    226   overscan_insets_in_dip_ = insets_in_dip;
    227 }
    228 
    229 gfx::Insets DisplayInfo::GetOverscanInsetsInPixel() const {
    230   return overscan_insets_in_dip_.Scale(device_scale_factor_);
    231 }
    232 
    233 std::string DisplayInfo::ToString() const {
    234   int rotation_degree = static_cast<int>(rotation_) * 90;
    235   return base::StringPrintf(
    236       "DisplayInfo[%lld] native bounds=%s, size=%s, scale=%f, "
    237       "overscan=%s, rotation=%d, ui-scale=%f, touchscreen=%s",
    238       static_cast<long long int>(id_),
    239       bounds_in_native_.ToString().c_str(),
    240       size_in_pixel_.ToString().c_str(),
    241       device_scale_factor_,
    242       overscan_insets_in_dip_.ToString().c_str(),
    243       rotation_degree,
    244       configured_ui_scale_,
    245       touch_support_ == gfx::Display::TOUCH_SUPPORT_AVAILABLE ? "yes" :
    246       touch_support_ == gfx::Display::TOUCH_SUPPORT_UNAVAILABLE ? "no" :
    247       "unknown");
    248 }
    249 
    250 std::string DisplayInfo::ToFullString() const {
    251   std::string resolutions_str;
    252   std::vector<Resolution>::const_iterator iter = resolutions_.begin();
    253   for (; iter != resolutions_.end(); ++iter) {
    254     if (!resolutions_str.empty())
    255       resolutions_str += ",";
    256     resolutions_str += iter->size.ToString();
    257     if (iter->interlaced)
    258       resolutions_str += "(i)";
    259   }
    260   return ToString() + ", resolutions=" + resolutions_str;
    261 }
    262 
    263 }  // namespace internal
    264 }  // namespace ash
    265