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> 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>:: 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>:: 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>:: 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>:: 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>:: 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>:: 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>:: 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>:: 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>:: 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>:: 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>:: 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, 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>:: 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>:: 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>:: 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>:: 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>:: 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