• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <limits>
6 
7 #include "ui/gfx/rect_base.h"
8 
9 #include "base/logging.h"
10 #include "base/strings/stringprintf.h"
11 
12 // This file provides the implementation for RectBaese template and
13 // used to instantiate the base class for Rect and RectF classes.
14 #if !defined(GFX_IMPLEMENTATION)
15 #error "This file is intended for UI implementation only"
16 #endif
17 
18 namespace {
19 
20 template<typename Type>
AdjustAlongAxis(Type dst_origin,Type dst_size,Type * origin,Type * size)21 void AdjustAlongAxis(Type dst_origin, Type dst_size, Type* origin, Type* size) {
22   *size = std::min(dst_size, *size);
23   if (*origin < dst_origin)
24     *origin = dst_origin;
25   else
26     *origin = std::min(dst_origin + dst_size, *origin + *size) - *size;
27 }
28 
29 } // namespace
30 
31 namespace gfx {
32 
33 template<typename Class,
34          typename PointClass,
35          typename SizeClass,
36          typename InsetsClass,
37          typename VectorClass,
38          typename Type>
39 void RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
SetRect(Type x,Type y,Type width,Type height)40     SetRect(Type x, Type y, Type width, Type height) {
41   origin_.SetPoint(x, y);
42   set_width(width);
43   set_height(height);
44 }
45 
46 template<typename Class,
47          typename PointClass,
48          typename SizeClass,
49          typename InsetsClass,
50          typename VectorClass,
51          typename Type>
52 void RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
Inset(const InsetsClass & insets)53     Inset(const InsetsClass& insets) {
54   Inset(insets.left(), insets.top(), insets.right(), insets.bottom());
55 }
56 
57 template<typename Class,
58          typename PointClass,
59          typename SizeClass,
60          typename InsetsClass,
61          typename VectorClass,
62          typename Type>
63 void RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
Inset(Type left,Type top,Type right,Type bottom)64     Inset(Type left, Type top, Type right, Type bottom) {
65   origin_ += VectorClass(left, top);
66   set_width(std::max(width() - left - right, static_cast<Type>(0)));
67   set_height(std::max(height() - top - bottom, static_cast<Type>(0)));
68 }
69 
70 template<typename Class,
71          typename PointClass,
72          typename SizeClass,
73          typename InsetsClass,
74          typename VectorClass,
75          typename Type>
76 void RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
Offset(Type horizontal,Type vertical)77     Offset(Type horizontal, Type vertical) {
78   origin_ += VectorClass(horizontal, vertical);
79 }
80 
81 template<typename Class,
82          typename PointClass,
83          typename SizeClass,
84          typename InsetsClass,
85          typename VectorClass,
86          typename Type>
87 void RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
88     operator+=(const VectorClass& offset) {
89   origin_ += offset;
90 }
91 
92 template<typename Class,
93          typename PointClass,
94          typename SizeClass,
95          typename InsetsClass,
96          typename VectorClass,
97          typename Type>
98 void RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
99     operator-=(const VectorClass& offset) {
100   origin_ -= offset;
101 }
102 
103 template<typename Class,
104          typename PointClass,
105          typename SizeClass,
106          typename InsetsClass,
107          typename VectorClass,
108          typename Type>
109 bool RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
110     operator<(const Class& other) const {
111   if (origin_ == other.origin_) {
112     if (width() == other.width()) {
113       return height() < other.height();
114     } else {
115       return width() < other.width();
116     }
117   } else {
118     return origin_ < other.origin_;
119   }
120 }
121 
122 template<typename Class,
123          typename PointClass,
124          typename SizeClass,
125          typename InsetsClass,
126          typename VectorClass,
127          typename Type>
128 bool RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
Contains(Type point_x,Type point_y)129     Contains(Type point_x, Type point_y) const {
130   return (point_x >= x()) && (point_x < right()) &&
131          (point_y >= y()) && (point_y < bottom());
132 }
133 
134 template<typename Class,
135          typename PointClass,
136          typename SizeClass,
137          typename InsetsClass,
138          typename VectorClass,
139          typename Type>
140 bool RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
Contains(const Class & rect)141     Contains(const Class& rect) const {
142   return (rect.x() >= x() && rect.right() <= right() &&
143           rect.y() >= y() && rect.bottom() <= bottom());
144 }
145 
146 template<typename Class,
147          typename PointClass,
148          typename SizeClass,
149          typename InsetsClass,
150          typename VectorClass,
151          typename Type>
152 bool RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
Intersects(const Class & rect)153     Intersects(const Class& rect) const {
154   return !(IsEmpty() || rect.IsEmpty() ||
155            rect.x() >= right() || rect.right() <= x() ||
156            rect.y() >= bottom() || rect.bottom() <= y());
157 }
158 
159 template<typename Class,
160          typename PointClass,
161          typename SizeClass,
162          typename InsetsClass,
163          typename VectorClass,
164          typename Type>
165 void RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
Intersect(const Class & rect)166     Intersect(const Class& rect) {
167   if (IsEmpty() || rect.IsEmpty()) {
168     SetRect(0, 0, 0, 0);
169     return;
170   }
171 
172   Type rx = std::max(x(), rect.x());
173   Type ry = std::max(y(), rect.y());
174   Type rr = std::min(right(), rect.right());
175   Type rb = std::min(bottom(), rect.bottom());
176 
177   if (rx >= rr || ry >= rb)
178     rx = ry = rr = rb = 0;  // non-intersecting
179 
180   SetRect(rx, ry, rr - rx, rb - ry);
181 }
182 
183 template<typename Class,
184          typename PointClass,
185          typename SizeClass,
186          typename InsetsClass,
187          typename VectorClass,
188          typename Type>
189 void RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
Union(const Class & rect)190     Union(const Class& rect) {
191   if (IsEmpty()) {
192     *this = rect;
193     return;
194   }
195   if (rect.IsEmpty())
196     return;
197 
198   Type rx = std::min(x(), rect.x());
199   Type ry = std::min(y(), rect.y());
200   Type rr = std::max(right(), rect.right());
201   Type rb = std::max(bottom(), rect.bottom());
202 
203   SetRect(rx, ry, rr - rx, rb - ry);
204 }
205 
206 template<typename Class,
207          typename PointClass,
208          typename SizeClass,
209          typename InsetsClass,
210          typename VectorClass,
211          typename Type>
212 void RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
Subtract(const Class & rect)213     Subtract(const Class& rect) {
214   if (!Intersects(rect))
215     return;
216   if (rect.Contains(*static_cast<const Class*>(this))) {
217     SetRect(0, 0, 0, 0);
218     return;
219   }
220 
221   Type rx = x();
222   Type ry = y();
223   Type rr = right();
224   Type rb = bottom();
225 
226   if (rect.y() <= y() && rect.bottom() >= bottom()) {
227     // complete intersection in the y-direction
228     if (rect.x() <= x()) {
229       rx = rect.right();
230     } else if (rect.right() >= right()) {
231       rr = rect.x();
232     }
233   } else if (rect.x() <= x() && rect.right() >= right()) {
234     // complete intersection in the x-direction
235     if (rect.y() <= y()) {
236       ry = rect.bottom();
237     } else if (rect.bottom() >= bottom()) {
238       rb = rect.y();
239     }
240   }
241   SetRect(rx, ry, rr - rx, rb - ry);
242 }
243 
244 template<typename Class,
245          typename PointClass,
246          typename SizeClass,
247          typename InsetsClass,
248          typename VectorClass,
249          typename Type>
250 void RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
AdjustToFit(const Class & rect)251     AdjustToFit(const Class& rect) {
252   Type new_x = x();
253   Type new_y = y();
254   Type new_width = width();
255   Type new_height = height();
256   AdjustAlongAxis(rect.x(), rect.width(), &new_x, &new_width);
257   AdjustAlongAxis(rect.y(), rect.height(), &new_y, &new_height);
258   SetRect(new_x, new_y, new_width, new_height);
259 }
260 
261 template<typename Class,
262          typename PointClass,
263          typename SizeClass,
264          typename InsetsClass,
265          typename VectorClass,
266          typename Type>
267 PointClass RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass,
CenterPoint()268     Type>::CenterPoint() const {
269   return PointClass(x() + width() / 2, y() + height() / 2);
270 }
271 
272 template<typename Class,
273          typename PointClass,
274          typename SizeClass,
275          typename InsetsClass,
276          typename VectorClass,
277          typename Type>
278 void RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
ClampToCenteredSize(const SizeClass & size)279     ClampToCenteredSize(const SizeClass& size) {
280   Type new_width = std::min(width(), size.width());
281   Type new_height = std::min(height(), size.height());
282   Type new_x = x() + (width() - new_width) / 2;
283   Type new_y = y() + (height() - new_height) / 2;
284   SetRect(new_x, new_y, new_width, new_height);
285 }
286 
287 template<typename Class,
288          typename PointClass,
289          typename SizeClass,
290          typename InsetsClass,
291          typename VectorClass,
292          typename Type>
293 void RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
SplitVertically(Class * left_half,Class * right_half)294     SplitVertically(Class* left_half, Class* right_half) const {
295   DCHECK(left_half);
296   DCHECK(right_half);
297 
298   left_half->SetRect(x(), y(), width() / 2, height());
299   right_half->SetRect(left_half->right(),
300                       y(),
301                       width() - left_half->width(),
302                       height());
303 }
304 
305 template<typename Class,
306          typename PointClass,
307          typename SizeClass,
308          typename InsetsClass,
309          typename VectorClass,
310          typename Type>
311 bool RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
SharesEdgeWith(const Class & rect)312     SharesEdgeWith(const Class& rect) const {
313   return (y() == rect.y() && height() == rect.height() &&
314              (x() == rect.right() || right() == rect.x())) ||
315          (x() == rect.x() && width() == rect.width() &&
316              (y() == rect.bottom() || bottom() == rect.y()));
317 }
318 
319 template<typename Class,
320          typename PointClass,
321          typename SizeClass,
322          typename InsetsClass,
323          typename VectorClass,
324          typename Type>
325 Type RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
ManhattanDistanceToPoint(const PointClass & point)326     ManhattanDistanceToPoint(const PointClass& point) const {
327   Type x_distance = std::max<Type>(0, std::max(
328       x() - point.x(), point.x() - right()));
329   Type y_distance = std::max<Type>(0, std::max(
330       y() - point.y(), point.y() - bottom()));
331 
332   return x_distance + y_distance;
333 }
334 
335 template<typename Class,
336          typename PointClass,
337          typename SizeClass,
338          typename InsetsClass,
339          typename VectorClass,
340          typename Type>
341 Type RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
ManhattanInternalDistance(const Class & rect)342     ManhattanInternalDistance(const Class& rect) const {
343   Class c(x(), y(), width(), height());
344   c.Union(rect);
345 
346   static const Type kEpsilon = std::numeric_limits<Type>::is_integer
347                                    ? 1
348                                    : std::numeric_limits<Type>::epsilon();
349 
350   Type x = std::max<Type>(0, c.width() - width() - rect.width() + kEpsilon);
351   Type y = std::max<Type>(0, c.height() - height() - rect.height() + kEpsilon);
352   return x + y;
353 }
354 
355 }  // namespace gfx
356