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