1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
|
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_GEOMETRY_INSETS_H_
#define UI_GFX_GEOMETRY_INSETS_H_
#include <string>
#include "base/numerics/clamped_math.h"
#include "ui/gfx/geometry/geometry_export.h"
#include "ui/gfx/geometry/insets_f.h"
#include "ui/gfx/geometry/size.h"
namespace gfx {
class Vector2d;
// Represents the widths of the four borders or margins of an unspecified
// rectangle. An Insets stores the thickness of the top, left, bottom and right
// edges, without storing the actual size and position of the rectangle itself.
//
// This can be used to represent a space within a rectangle, by "shrinking" the
// rectangle by the inset amount on all four sides. Alternatively, it can
// represent a border that has a different thickness on each side.
class GEOMETRY_EXPORT Insets {
public:
constexpr Insets() : top_(0), left_(0), bottom_(0), right_(0) {}
constexpr explicit Insets(int all)
: top_(all),
left_(all),
bottom_(GetClampedValue(all, all)),
right_(GetClampedValue(all, all)) {}
constexpr explicit Insets(int vertical, int horizontal)
: top_(vertical),
left_(horizontal),
bottom_(GetClampedValue(vertical, vertical)),
right_(GetClampedValue(horizontal, horizontal)) {}
constexpr Insets(int top, int left, int bottom, int right)
: top_(top),
left_(left),
bottom_(GetClampedValue(top, bottom)),
right_(GetClampedValue(left, right)) {}
constexpr int top() const { return top_; }
constexpr int left() const { return left_; }
constexpr int bottom() const { return bottom_; }
constexpr int right() const { return right_; }
// Returns the total width taken up by the insets, which is the sum of the
// left and right insets.
constexpr int width() const { return left_ + right_; }
// Returns the total height taken up by the insets, which is the sum of the
// top and bottom insets.
constexpr int height() const { return top_ + bottom_; }
// Returns the sum of the left and right insets as the width, the sum of the
// top and bottom insets as the height.
constexpr Size size() const { return Size(width(), height()); }
// Returns true if the insets are empty.
bool IsEmpty() const { return width() == 0 && height() == 0; }
void set_top(int top) {
top_ = top;
bottom_ = GetClampedValue(top_, bottom_);
}
void set_left(int left) {
left_ = left;
right_ = GetClampedValue(left_, right_);
}
void set_bottom(int bottom) { bottom_ = GetClampedValue(top_, bottom); }
void set_right(int right) { right_ = GetClampedValue(left_, right); }
void Set(int top, int left, int bottom, int right) {
top_ = top;
left_ = left;
bottom_ = GetClampedValue(top_, bottom);
right_ = GetClampedValue(left_, right);
}
bool operator==(const Insets& insets) const {
return top_ == insets.top_ && left_ == insets.left_ &&
bottom_ == insets.bottom_ && right_ == insets.right_;
}
bool operator!=(const Insets& insets) const {
return !(*this == insets);
}
void operator+=(const Insets& insets) {
top_ = base::ClampAdd(top_, insets.top_);
left_ = base::ClampAdd(left_, insets.left_);
bottom_ = GetClampedValue(top_, base::ClampAdd(bottom_, insets.bottom_));
right_ = GetClampedValue(left_, base::ClampAdd(right_, insets.right_));
}
void operator-=(const Insets& insets) {
top_ = base::ClampSub(top_, insets.top_);
left_ = base::ClampSub(left_, insets.left_);
bottom_ = GetClampedValue(top_, base::ClampSub(bottom_, insets.bottom_));
right_ = GetClampedValue(left_, base::ClampSub(right_, insets.right_));
}
Insets operator-() const {
return Insets(-base::MakeClampedNum(top_), -base::MakeClampedNum(left_),
-base::MakeClampedNum(bottom_),
-base::MakeClampedNum(right_));
}
// Adjusts the vertical and horizontal dimensions by the values described in
// |vector|. Offsetting insets before applying to a rectangle would be
// equivalent to offseting the rectangle then applying the insets.
Insets Offset(const gfx::Vector2d& vector) const;
operator InsetsF() const {
return InsetsF(static_cast<float>(top()), static_cast<float>(left()),
static_cast<float>(bottom()), static_cast<float>(right()));
}
// Returns a string representation of the insets.
std::string ToString() const;
private:
int top_;
int left_;
int bottom_;
int right_;
// See ui/gfx/geometry/rect.h
// Returns true iff a+b would overflow max int.
static constexpr bool AddWouldOverflow(int a, int b) {
// In this function, GCC tries to make optimizations that would only work if
// max - a wouldn't overflow but it isn't smart enough to notice that a > 0.
// So cast everything to unsigned to avoid this. As it is guaranteed that
// max - a and b are both already positive, the cast is a noop.
//
// This is intended to be: a > 0 && max - a < b
return a > 0 && b > 0 &&
static_cast<unsigned>(std::numeric_limits<int>::max() - a) <
static_cast<unsigned>(b);
}
// Returns true iff a+b would underflow min int.
static constexpr bool AddWouldUnderflow(int a, int b) {
return a < 0 && b < 0 && std::numeric_limits<int>::min() - a > b;
}
// Clamp the right/bottom to avoid integer over/underflow in width() and
// height(). This returns the right/bottom given a top_or_left and a
// bottom_or_right.
// TODO(enne): this should probably use base::ClampAdd, but that
// function is not a constexpr.
static constexpr int GetClampedValue(int top_or_left, int bottom_or_right) {
if (AddWouldOverflow(top_or_left, bottom_or_right)) {
return std::numeric_limits<int>::max() - top_or_left;
} else if (AddWouldUnderflow(top_or_left, bottom_or_right)) {
// If |top_or_left| and |bottom_or_right| are both negative,
// adds |top_or_left| to prevent underflow by subtracting it.
return std::numeric_limits<int>::min() - top_or_left;
} else {
return bottom_or_right;
}
}
};
// This is declared here for use in gtest-based unit tests but is defined in
// the //ui/gfx:test_support target. Depend on that to use this in your unit
// test. This should not be used in production code - call ToString() instead.
void PrintTo(const Insets& point, ::std::ostream* os);
inline Insets operator+(Insets lhs, const Insets& rhs) {
lhs += rhs;
return lhs;
}
inline Insets operator-(Insets lhs, const Insets& rhs) {
lhs -= rhs;
return lhs;
}
// Helper methods to scale a gfx::Insets to a new gfx::Insets.
GEOMETRY_EXPORT Insets ScaleToCeiledInsets(const Insets& insets,
float x_scale,
float y_scale);
GEOMETRY_EXPORT Insets ScaleToCeiledInsets(const Insets& insets, float scale);
GEOMETRY_EXPORT Insets ScaleToFlooredInsets(const Insets& insets,
float x_scale,
float y_scale);
GEOMETRY_EXPORT Insets ScaleToFlooredInsets(const Insets& insets, float scale);
GEOMETRY_EXPORT Insets ScaleToRoundedInsets(const Insets& insets,
float x_scale,
float y_scale);
GEOMETRY_EXPORT Insets ScaleToRoundedInsets(const Insets& insets, float scale);
} // namespace gfx
#endif // UI_GFX_GEOMETRY_INSETS_H_
|