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/gfx/display.h"
6
7#include <algorithm>
8
9#include "base/command_line.h"
10#include "base/logging.h"
11#include "base/strings/string_number_conversions.h"
12#include "base/strings/stringprintf.h"
13#include "ui/gfx/insets.h"
14#include "ui/gfx/point_conversions.h"
15#include "ui/gfx/point_f.h"
16#include "ui/gfx/size_conversions.h"
17#include "ui/gfx/switches.h"
18
19namespace gfx {
20namespace {
21
22bool HasForceDeviceScaleFactorImpl() {
23  return CommandLine::ForCurrentProcess()->HasSwitch(
24      switches::kForceDeviceScaleFactor);
25}
26
27float GetForcedDeviceScaleFactorImpl() {
28  double scale_in_double = 1.0;
29  if (HasForceDeviceScaleFactorImpl()) {
30    std::string value = CommandLine::ForCurrentProcess()->
31        GetSwitchValueASCII(switches::kForceDeviceScaleFactor);
32    if (!base::StringToDouble(value, &scale_in_double))
33      LOG(ERROR) << "Failed to parse the default device scale factor:" << value;
34  }
35  return static_cast<float>(scale_in_double);
36}
37
38int64 internal_display_id_ = -1;
39
40}  // namespace
41
42const int64 Display::kInvalidDisplayID = -1;
43
44// static
45float Display::GetForcedDeviceScaleFactor() {
46  static const float kForcedDeviceScaleFactor =
47      GetForcedDeviceScaleFactorImpl();
48  return kForcedDeviceScaleFactor;
49}
50
51//static
52bool Display::HasForceDeviceScaleFactor() {
53  static const bool kHasForceDeviceScaleFactor =
54      HasForceDeviceScaleFactorImpl();
55  return kHasForceDeviceScaleFactor;
56}
57
58Display::Display()
59    : id_(kInvalidDisplayID),
60      device_scale_factor_(GetForcedDeviceScaleFactor()),
61      rotation_(ROTATE_0),
62      touch_support_(TOUCH_SUPPORT_UNKNOWN) {
63}
64
65Display::Display(int64 id)
66    : id_(id),
67      device_scale_factor_(GetForcedDeviceScaleFactor()),
68      rotation_(ROTATE_0),
69      touch_support_(TOUCH_SUPPORT_UNKNOWN) {
70}
71
72Display::Display(int64 id, const gfx::Rect& bounds)
73    : id_(id),
74      bounds_(bounds),
75      work_area_(bounds),
76      device_scale_factor_(GetForcedDeviceScaleFactor()),
77      rotation_(ROTATE_0),
78      touch_support_(TOUCH_SUPPORT_UNKNOWN) {
79#if defined(USE_AURA)
80  SetScaleAndBounds(device_scale_factor_, bounds);
81#endif
82}
83
84Display::~Display() {
85}
86
87int Display::RotationAsDegree() const {
88  switch (rotation_) {
89    case ROTATE_0:
90      return 0;
91    case ROTATE_90:
92      return 90;
93    case ROTATE_180:
94      return 180;
95    case ROTATE_270:
96      return 270;
97  }
98
99  NOTREACHED();
100  return 0;
101}
102
103void Display::SetRotationAsDegree(int rotation) {
104  switch (rotation) {
105    case 0:
106      rotation_ = ROTATE_0;
107      break;
108    case 90:
109      rotation_ = ROTATE_90;
110      break;
111    case 180:
112      rotation_ = ROTATE_180;
113      break;
114    case 270:
115      rotation_ = ROTATE_270;
116      break;
117    default:
118      // We should not reach that but we will just ignore the call if we do.
119      NOTREACHED();
120  }
121}
122
123Insets Display::GetWorkAreaInsets() const {
124  return gfx::Insets(work_area_.y() - bounds_.y(),
125                     work_area_.x() - bounds_.x(),
126                     bounds_.bottom() - work_area_.bottom(),
127                     bounds_.right() - work_area_.right());
128}
129
130void Display::SetScaleAndBounds(
131    float device_scale_factor,
132    const gfx::Rect& bounds_in_pixel) {
133  Insets insets = bounds_.InsetsFrom(work_area_);
134  if (!HasForceDeviceScaleFactor()) {
135#if defined(OS_MACOSX)
136    // Unless an explicit scale factor was provided for testing, ensure the
137    // scale is integral.
138    device_scale_factor = static_cast<int>(device_scale_factor);
139#endif
140    device_scale_factor_ = device_scale_factor;
141  }
142  device_scale_factor_ = std::max(1.0f, device_scale_factor_);
143  bounds_ = gfx::Rect(
144      gfx::ToFlooredPoint(gfx::ScalePoint(bounds_in_pixel.origin(),
145                                          1.0f / device_scale_factor_)),
146      gfx::ToFlooredSize(gfx::ScaleSize(bounds_in_pixel.size(),
147                                        1.0f / device_scale_factor_)));
148  UpdateWorkAreaFromInsets(insets);
149}
150
151void Display::SetSize(const gfx::Size& size_in_pixel) {
152  gfx::Point origin = bounds_.origin();
153#if defined(USE_AURA)
154  gfx::PointF origin_f = origin;
155  origin_f.Scale(device_scale_factor_);
156  origin.SetPoint(origin_f.x(), origin_f.y());
157#endif
158  SetScaleAndBounds(device_scale_factor_, gfx::Rect(origin, size_in_pixel));
159}
160
161void Display::UpdateWorkAreaFromInsets(const gfx::Insets& insets) {
162  work_area_ = bounds_;
163  work_area_.Inset(insets);
164}
165
166gfx::Size Display::GetSizeInPixel() const {
167  return gfx::ToFlooredSize(gfx::ScaleSize(size(), device_scale_factor_));
168}
169
170std::string Display::ToString() const {
171  return base::StringPrintf(
172      "Display[%lld] bounds=%s, workarea=%s, scale=%f, %s",
173      static_cast<long long int>(id_),
174      bounds_.ToString().c_str(),
175      work_area_.ToString().c_str(),
176      device_scale_factor_,
177      IsInternal() ? "internal" : "external");
178}
179
180bool Display::IsInternal() const {
181  return is_valid() && (id_ == internal_display_id_);
182}
183
184int64 Display::InternalDisplayId() {
185  return internal_display_id_;
186}
187
188void Display::SetInternalDisplayId(int64 internal_display_id) {
189  internal_display_id_ = internal_display_id;
190}
191
192}  // namespace gfx
193