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/root_window_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_pixel(aura::RootWindowHost::GetNativeScreenSize());
     49 #else
     50   gfx::Rect bounds_in_pixel(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_pixel.SetRect(x, y, width, height);
     98   }
     99   if (id == gfx::Display::kInvalidDisplayID)
    100     id = synthesized_display_id++;
    101   DisplayInfo display_info(
    102       id, base::StringPrintf("Display-%d", static_cast<int>(id)), has_overscan);
    103   display_info.set_device_scale_factor(device_scale_factor);
    104   display_info.set_rotation(rotation);
    105   display_info.set_ui_scale(ui_scale);
    106   display_info.SetBounds(bounds_in_pixel);
    107 
    108   // To test the overscan, it creates the default 5% overscan.
    109   if (has_overscan) {
    110     int width = bounds_in_pixel.width() / device_scale_factor / 40;
    111     int height = bounds_in_pixel.height() / device_scale_factor / 40;
    112     display_info.SetOverscanInsets(gfx::Insets(height, width, height, width));
    113     display_info.UpdateDisplaySize();
    114   }
    115 
    116   DVLOG(1) << "DisplayInfoFromSpec info=" << display_info.ToString()
    117            << ", spec=" << spec;
    118   return display_info;
    119 }
    120 
    121 DisplayInfo::DisplayInfo()
    122     : id_(gfx::Display::kInvalidDisplayID),
    123       has_overscan_(false),
    124       rotation_(gfx::Display::ROTATE_0),
    125       device_scale_factor_(1.0f),
    126       overscan_insets_in_dip_(0, 0, 0, 0),
    127       ui_scale_(1.0f),
    128       native_(false) {
    129 }
    130 
    131 DisplayInfo::DisplayInfo(int64 id,
    132                          const std::string& name,
    133                          bool has_overscan)
    134     : id_(id),
    135       name_(name),
    136       has_overscan_(has_overscan),
    137       rotation_(gfx::Display::ROTATE_0),
    138       device_scale_factor_(1.0f),
    139       overscan_insets_in_dip_(0, 0, 0, 0),
    140       ui_scale_(1.0f),
    141       native_(false) {
    142 }
    143 
    144 DisplayInfo::~DisplayInfo() {
    145 }
    146 
    147 void DisplayInfo::Copy(const DisplayInfo& native_info) {
    148   DCHECK(id_ == native_info.id_);
    149   name_ = native_info.name_;
    150   has_overscan_ = native_info.has_overscan_;
    151 
    152   DCHECK(!native_info.bounds_in_pixel_.IsEmpty());
    153   bounds_in_pixel_ = native_info.bounds_in_pixel_;
    154   size_in_pixel_ = native_info.size_in_pixel_;
    155   device_scale_factor_ = native_info.device_scale_factor_;
    156   resolutions_ = native_info.resolutions_;
    157 
    158   // Copy overscan_insets_in_dip_ if it's not empty. This is for test
    159   // cases which use "/o" annotation which sets the overscan inset
    160   // to native, and that overscan has to be propagated. This does not
    161   // happen on the real environment.
    162   if (!native_info.overscan_insets_in_dip_.empty())
    163     overscan_insets_in_dip_ = native_info.overscan_insets_in_dip_;
    164 
    165   // Rotation_ and ui_scale_ are given by preference, or unit
    166   // tests. Don't copy if this native_info came from
    167   // DisplayChangeObserverX11.
    168   if (!native_info.native()) {
    169     rotation_ = native_info.rotation_;
    170     ui_scale_ = native_info.ui_scale_;
    171   }
    172   // Don't copy insets as it may be given by preference.  |rotation_|
    173   // is treated as a native so that it can be specified in
    174   // |CreateFromSpec|.
    175 }
    176 
    177 void DisplayInfo::SetBounds(const gfx::Rect& new_bounds_in_pixel) {
    178   bounds_in_pixel_ = new_bounds_in_pixel;
    179   size_in_pixel_ = new_bounds_in_pixel.size();
    180   UpdateDisplaySize();
    181 }
    182 
    183 void DisplayInfo::UpdateDisplaySize() {
    184   size_in_pixel_ = bounds_in_pixel_.size();
    185   if (!overscan_insets_in_dip_.empty()) {
    186     gfx::Insets insets_in_pixel =
    187         overscan_insets_in_dip_.Scale(device_scale_factor_);
    188     size_in_pixel_.Enlarge(-insets_in_pixel.width(), -insets_in_pixel.height());
    189   } else {
    190     overscan_insets_in_dip_.Set(0, 0, 0, 0);
    191   }
    192 
    193   if (rotation_ == gfx::Display::ROTATE_90 ||
    194       rotation_ == gfx::Display::ROTATE_270)
    195     size_in_pixel_.SetSize(size_in_pixel_.height(), size_in_pixel_.width());
    196   gfx::SizeF size_f(size_in_pixel_);
    197   size_f.Scale(ui_scale_);
    198   size_in_pixel_ = gfx::ToFlooredSize(size_f);
    199 }
    200 
    201 void DisplayInfo::SetOverscanInsets(const gfx::Insets& insets_in_dip) {
    202   overscan_insets_in_dip_ = insets_in_dip;
    203 }
    204 
    205 gfx::Insets DisplayInfo::GetOverscanInsetsInPixel() const {
    206   return overscan_insets_in_dip_.Scale(device_scale_factor_);
    207 }
    208 
    209 std::string DisplayInfo::ToString() const {
    210   int rotation_degree = static_cast<int>(rotation_) * 90;
    211   return base::StringPrintf(
    212       "DisplayInfo[%lld] native bounds=%s, size=%s, scale=%f, "
    213       "overscan=%s, rotation=%d, ui-scale=%f",
    214       static_cast<long long int>(id_),
    215       bounds_in_pixel_.ToString().c_str(),
    216       size_in_pixel_.ToString().c_str(),
    217       device_scale_factor_,
    218       overscan_insets_in_dip_.ToString().c_str(),
    219       rotation_degree,
    220       ui_scale_);
    221 }
    222 
    223 std::string DisplayInfo::ToFullString() const {
    224   std::string resolutions_str;
    225   std::vector<Resolution>::const_iterator iter = resolutions_.begin();
    226   for (; iter != resolutions_.end(); ++iter) {
    227     if (!resolutions_str.empty())
    228       resolutions_str += ",";
    229     resolutions_str += iter->size.ToString();
    230     if (iter->interlaced)
    231       resolutions_str += "(i)";
    232   }
    233   return ToString() + ", resolutions=" + resolutions_str;
    234 }
    235 
    236 }  // namespace internal
    237 }  // namespace ash
    238