Home | History | Annotate | Download | only in geometry
      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