Home | History | Annotate | Download | only in base
      1 // Copyright (c) 2012 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/base/layout.h"
      6 
      7 #include <algorithm>
      8 #include <cmath>
      9 #include <limits>
     10 
     11 #include "base/basictypes.h"
     12 #include "base/command_line.h"
     13 #include "base/logging.h"
     14 #include "build/build_config.h"
     15 #include "ui/base/touch/touch_device.h"
     16 #include "ui/base/ui_base_switches.h"
     17 #include "ui/gfx/display.h"
     18 #include "ui/gfx/screen.h"
     19 
     20 #if defined(OS_MACOSX) && !defined(OS_IOS)
     21 #include "base/mac/mac_util.h"
     22 #endif
     23 
     24 #if defined(OS_WIN)
     25 #include "base/win/metro.h"
     26 #include "ui/base/win/dpi.h"
     27 #include <Windows.h>
     28 #endif  // defined(OS_WIN)
     29 
     30 #if defined(OS_CHROMEOS)
     31 #include "ui/base/resource/resource_bundle.h"
     32 #endif
     33 
     34 namespace ui {
     35 
     36 namespace {
     37 
     38 bool ScaleFactorComparator(const ScaleFactor& lhs, const ScaleFactor& rhs){
     39   return GetScaleFactorScale(lhs) < GetScaleFactorScale(rhs);
     40 }
     41 
     42 #if defined(OS_WIN)
     43 // Helper function that determines whether we want to optimize the UI for touch.
     44 bool UseTouchOptimizedUI() {
     45   // If --touch-optimized-ui is specified and not set to "auto", then override
     46   // the hardware-determined setting (eg. for testing purposes).
     47   static bool has_touch_optimized_ui = CommandLine::ForCurrentProcess()->
     48       HasSwitch(switches::kTouchOptimizedUI);
     49   if (has_touch_optimized_ui) {
     50     const std::string switch_value = CommandLine::ForCurrentProcess()->
     51         GetSwitchValueASCII(switches::kTouchOptimizedUI);
     52 
     53     // Note that simply specifying the switch is the same as enabled.
     54     if (switch_value.empty() ||
     55         switch_value == switches::kTouchOptimizedUIEnabled) {
     56       return true;
     57     } else if (switch_value == switches::kTouchOptimizedUIDisabled) {
     58       return false;
     59     } else if (switch_value != switches::kTouchOptimizedUIAuto) {
     60       LOG(ERROR) << "Invalid --touch-optimized-ui option: " << switch_value;
     61     }
     62   }
     63 
     64   // We use the touch layout only when we are running in Metro mode.
     65   return base::win::IsMetroProcess() && ui::IsTouchDevicePresent();
     66 }
     67 #endif  // defined(OS_WIN)
     68 
     69 const float kScaleFactorScales[] = {1.0f, 1.0f, 1.33f, 1.4f, 1.5f, 1.8f, 2.0f};
     70 COMPILE_ASSERT(NUM_SCALE_FACTORS == arraysize(kScaleFactorScales),
     71                kScaleFactorScales_incorrect_size);
     72 const size_t kScaleFactorScalesLength = arraysize(kScaleFactorScales);
     73 
     74 namespace {
     75 
     76 // Returns the scale factor closest to |scale| from the full list of factors.
     77 // Note that it does NOT rely on the list of supported scale factors.
     78 // Finding the closest match is inefficient and shouldn't be done frequently.
     79 ScaleFactor FindClosestScaleFactorUnsafe(float scale) {
     80   float smallest_diff =  std::numeric_limits<float>::max();
     81   ScaleFactor closest_match = SCALE_FACTOR_100P;
     82   for (int i = SCALE_FACTOR_100P; i < NUM_SCALE_FACTORS; ++i) {
     83     const ScaleFactor scale_factor = static_cast<ScaleFactor>(i);
     84     float diff = std::abs(kScaleFactorScales[scale_factor] - scale);
     85     if (diff < smallest_diff) {
     86       closest_match = scale_factor;
     87       smallest_diff = diff;
     88     }
     89   }
     90   return closest_match;
     91 }
     92 
     93 }  // namespace
     94 
     95 std::vector<ScaleFactor>& GetSupportedScaleFactorsInternal() {
     96   static std::vector<ScaleFactor>* supported_scale_factors =
     97       new std::vector<ScaleFactor>();
     98   if (supported_scale_factors->empty()) {
     99 #if !defined(OS_IOS)
    100     // On platforms other than iOS, 100P is always a supported scale factor.
    101     supported_scale_factors->push_back(SCALE_FACTOR_100P);
    102 #endif
    103 
    104 #if defined(OS_ANDROID)
    105     const gfx::Display display =
    106         gfx::Screen::GetNativeScreen()->GetPrimaryDisplay();
    107     const float display_density = display.device_scale_factor();
    108     const ScaleFactor closest = FindClosestScaleFactorUnsafe(display_density);
    109     if (closest != SCALE_FACTOR_100P)
    110       supported_scale_factors->push_back(closest);
    111 #elif defined(OS_IOS)
    112     gfx::Display display = gfx::Screen::GetNativeScreen()->GetPrimaryDisplay();
    113     if (display.device_scale_factor() > 1.0) {
    114       DCHECK_EQ(2.0, display.device_scale_factor());
    115       supported_scale_factors->push_back(SCALE_FACTOR_200P);
    116     } else {
    117       supported_scale_factors->push_back(SCALE_FACTOR_100P);
    118     }
    119 #elif defined(OS_MACOSX)
    120     if (base::mac::IsOSLionOrLater())
    121       supported_scale_factors->push_back(SCALE_FACTOR_200P);
    122 #elif defined(OS_WIN)
    123     // Have high-DPI resources for 140% and 180% scaling on Windows based on
    124     // default scaling for Metro mode.  Round to nearest supported scale in
    125     // all cases.
    126     if (ui::IsInHighDPIMode()) {
    127       supported_scale_factors->push_back(SCALE_FACTOR_140P);
    128       supported_scale_factors->push_back(SCALE_FACTOR_180P);
    129     }
    130 #elif defined(OS_CHROMEOS)
    131     // TODO(oshima): Include 200P only if the device support 200P
    132     supported_scale_factors->push_back(SCALE_FACTOR_200P);
    133 #endif
    134     std::sort(supported_scale_factors->begin(),
    135               supported_scale_factors->end(),
    136               ScaleFactorComparator);
    137   }
    138   return *supported_scale_factors;
    139 }
    140 
    141 }  // namespace
    142 
    143 DisplayLayout GetDisplayLayout() {
    144 #if defined(OS_WIN)
    145   if (UseTouchOptimizedUI())
    146     return LAYOUT_TOUCH;
    147 #endif
    148   return LAYOUT_DESKTOP;
    149 }
    150 
    151 ScaleFactor GetScaleFactorFromScale(float scale) {
    152   ScaleFactor closest_match = SCALE_FACTOR_100P;
    153   float smallest_diff =  std::numeric_limits<float>::max();
    154   const std::vector<ScaleFactor>& supported =
    155       GetSupportedScaleFactorsInternal();
    156   for (size_t i = 0; i < supported.size(); ++i) {
    157     ScaleFactor scale_factor = supported[i];
    158     float diff = std::abs(kScaleFactorScales[scale_factor] - scale);
    159     if (diff < smallest_diff) {
    160       closest_match = scale_factor;
    161       smallest_diff = diff;
    162     }
    163   }
    164   DCHECK_NE(closest_match, SCALE_FACTOR_NONE);
    165   return closest_match;
    166 }
    167 
    168 float GetScaleFactorScale(ScaleFactor scale_factor) {
    169   return kScaleFactorScales[scale_factor];
    170 }
    171 
    172 ScaleFactor GetMaxScaleFactor() {
    173 #if defined(OS_CHROMEOS)
    174   return ResourceBundle::GetSharedInstance().max_scale_factor();
    175 #else
    176   return GetSupportedScaleFactorsInternal().back();
    177 #endif
    178 }
    179 
    180 std::vector<ScaleFactor> GetSupportedScaleFactors() {
    181   return GetSupportedScaleFactorsInternal();
    182 }
    183 
    184 bool IsScaleFactorSupported(ScaleFactor scale_factor) {
    185   const std::vector<ScaleFactor>& supported =
    186       GetSupportedScaleFactorsInternal();
    187   return std::find(supported.begin(), supported.end(), scale_factor) !=
    188       supported.end();
    189 }
    190 
    191 namespace test {
    192 
    193 void SetSupportedScaleFactors(
    194     const std::vector<ui::ScaleFactor>& scale_factors) {
    195   std::vector<ui::ScaleFactor>& supported_scale_factors =
    196       GetSupportedScaleFactorsInternal();
    197   supported_scale_factors = scale_factors;
    198   std::sort(supported_scale_factors.begin(),
    199             supported_scale_factors.end(),
    200             ScaleFactorComparator);
    201 }
    202 
    203 ScopedSetSupportedScaleFactors::ScopedSetSupportedScaleFactors(
    204     const std::vector<ui::ScaleFactor>& new_scale_factors)
    205     : original_scale_factors_(GetSupportedScaleFactors()) {
    206   SetSupportedScaleFactors(new_scale_factors);
    207 }
    208 
    209 ScopedSetSupportedScaleFactors::~ScopedSetSupportedScaleFactors() {
    210   SetSupportedScaleFactors(original_scale_factors_);
    211 }
    212 
    213 }  // namespace test
    214 
    215 #if !defined(OS_MACOSX)
    216 ScaleFactor GetScaleFactorForNativeView(gfx::NativeView view) {
    217   gfx::Screen* screen = gfx::Screen::GetScreenFor(view);
    218   if (screen->IsDIPEnabled()) {
    219     gfx::Display display = screen->GetDisplayNearestWindow(view);
    220     return GetScaleFactorFromScale(display.device_scale_factor());
    221   }
    222   return ui::SCALE_FACTOR_100P;
    223 }
    224 #endif  // !defined(OS_MACOSX)
    225 
    226 }  // namespace ui
    227