tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

RectAbsolute.h (11653B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef MOZILLA_GFX_RECT_ABSOLUTE_H_
      8 #define MOZILLA_GFX_RECT_ABSOLUTE_H_
      9 
     10 #include <algorithm>
     11 #include <cstdint>
     12 
     13 #include "mozilla/Attributes.h"
     14 #include "Point.h"
     15 #include "Rect.h"
     16 #include "Types.h"
     17 
     18 namespace mozilla {
     19 
     20 template <typename>
     21 struct IsPixel;
     22 
     23 namespace gfx {
     24 
     25 /**
     26 * A RectAbsolute is similar to a Rect (see BaseRect.h), but represented as
     27 * (x1, y1, x2, y2) instead of (x, y, width, height).
     28 *
     29 * Unless otherwise indicated, methods on this class correspond
     30 * to methods on BaseRect.
     31 *
     32 * The API is currently very bare-bones; it may be extended as needed.
     33 *
     34 * Do not use this class directly. Subclass it, pass that subclass as the
     35 * Sub parameter, and only use that subclass.
     36 */
     37 template <class T, class Sub, class Point, class Rect>
     38 struct BaseRectAbsolute {
     39 protected:
     40  T left, top, right, bottom;
     41 
     42 public:
     43  BaseRectAbsolute() : left(0), top(0), right(0), bottom(0) {}
     44  BaseRectAbsolute(T aLeft, T aTop, T aRight, T aBottom)
     45      : left(aLeft), top(aTop), right(aRight), bottom(aBottom) {}
     46 
     47  MOZ_ALWAYS_INLINE T X() const { return left; }
     48  MOZ_ALWAYS_INLINE T Y() const { return top; }
     49  MOZ_ALWAYS_INLINE T Width() const { return right - left; }
     50  MOZ_ALWAYS_INLINE T Height() const { return bottom - top; }
     51  MOZ_ALWAYS_INLINE T XMost() const { return right; }
     52  MOZ_ALWAYS_INLINE T YMost() const { return bottom; }
     53  MOZ_ALWAYS_INLINE const T& Left() const { return left; }
     54  MOZ_ALWAYS_INLINE const T& Right() const { return right; }
     55  MOZ_ALWAYS_INLINE const T& Top() const { return top; }
     56  MOZ_ALWAYS_INLINE const T& Bottom() const { return bottom; }
     57  MOZ_ALWAYS_INLINE T& Left() { return left; }
     58  MOZ_ALWAYS_INLINE T& Right() { return right; }
     59  MOZ_ALWAYS_INLINE T& Top() { return top; }
     60  MOZ_ALWAYS_INLINE T& Bottom() { return bottom; }
     61  T Area() const { return Width() * Height(); }
     62 
     63  void Inflate(T aD) { Inflate(aD, aD); }
     64  void Inflate(T aDx, T aDy) {
     65    left -= aDx;
     66    top -= aDy;
     67    right += aDx;
     68    bottom += aDy;
     69  }
     70 
     71  MOZ_ALWAYS_INLINE void SetBox(T aLeft, T aTop, T aRight, T aBottom) {
     72    left = aLeft;
     73    top = aTop;
     74    right = aRight;
     75    bottom = aBottom;
     76  }
     77  void SetLeftEdge(T aLeft) { left = aLeft; }
     78  void SetRightEdge(T aRight) { right = aRight; }
     79  void SetTopEdge(T aTop) { top = aTop; }
     80  void SetBottomEdge(T aBottom) { bottom = aBottom; }
     81 
     82  static Sub FromRect(const Rect& aRect) {
     83    if (aRect.Overflows()) {
     84      return Sub();
     85    }
     86    return Sub(aRect.x, aRect.y, aRect.XMost(), aRect.YMost());
     87  }
     88 
     89  [[nodiscard]] Sub Intersect(const Sub& aOther) const {
     90    Sub result;
     91    result.left = std::max<T>(left, aOther.left);
     92    result.top = std::max<T>(top, aOther.top);
     93    result.right = std::min<T>(right, aOther.right);
     94    result.bottom = std::min<T>(bottom, aOther.bottom);
     95    if (result.right < result.left || result.bottom < result.top) {
     96      result.SizeTo(0, 0);
     97    }
     98    return result;
     99  }
    100 
    101  bool IsEmpty() const { return right <= left || bottom <= top; }
    102 
    103  bool IsEqualEdges(const Sub& aOther) const {
    104    return left == aOther.left && top == aOther.top && right == aOther.right &&
    105           bottom == aOther.bottom;
    106  }
    107 
    108  bool IsEqualInterior(const Sub& aRect) const {
    109    return IsEqualEdges(aRect) || (IsEmpty() && aRect.IsEmpty());
    110  }
    111 
    112  MOZ_ALWAYS_INLINE void MoveBy(T aDx, T aDy) {
    113    left += aDx;
    114    right += aDx;
    115    top += aDy;
    116    bottom += aDy;
    117  }
    118  MOZ_ALWAYS_INLINE void MoveBy(const Point& aPoint) {
    119    left += aPoint.x;
    120    right += aPoint.x;
    121    top += aPoint.y;
    122    bottom += aPoint.y;
    123  }
    124  MOZ_ALWAYS_INLINE void SizeTo(T aWidth, T aHeight) {
    125    right = left + aWidth;
    126    bottom = top + aHeight;
    127  }
    128 
    129  bool Contains(const Sub& aRect) const {
    130    return aRect.IsEmpty() || (left <= aRect.left && aRect.right <= right &&
    131                               top <= aRect.top && aRect.bottom <= bottom);
    132  }
    133  bool Contains(T aX, T aY) const {
    134    return (left <= aX && aX < right && top <= aY && aY < bottom);
    135  }
    136 
    137  bool Intersects(const Sub& aRect) const {
    138    return !IsEmpty() && !aRect.IsEmpty() && left < aRect.right &&
    139           aRect.left < right && top < aRect.bottom && aRect.top < bottom;
    140  }
    141 
    142  void SetEmpty() { left = right = top = bottom = 0; }
    143 
    144  // Returns the smallest rectangle that contains both the area of both
    145  // this and aRect. Thus, empty input rectangles are ignored.
    146  // Note: if both rectangles are empty, returns aRect.
    147  // WARNING! This is not safe against overflow, prefer using SafeUnion instead
    148  // when dealing with int-based rects.
    149  [[nodiscard]] Sub Union(const Sub& aRect) const {
    150    if (IsEmpty()) {
    151      return aRect;
    152    } else if (aRect.IsEmpty()) {
    153      return *static_cast<const Sub*>(this);
    154    } else {
    155      return UnionEdges(aRect);
    156    }
    157  }
    158  // Returns the smallest rectangle that contains both the points (including
    159  // edges) of both aRect1 and aRect2.
    160  // Thus, empty input rectangles are allowed to affect the result.
    161  // WARNING! This is not safe against overflow, prefer using SafeUnionEdges
    162  // instead when dealing with int-based rects.
    163  [[nodiscard]] Sub UnionEdges(const Sub& aRect) const {
    164    Sub result;
    165    result.left = std::min(left, aRect.left);
    166    result.top = std::min(top, aRect.top);
    167    result.right = std::max(XMost(), aRect.XMost());
    168    result.bottom = std::max(YMost(), aRect.YMost());
    169    return result;
    170  }
    171 
    172  // Scale 'this' by aScale without doing any rounding.
    173  void Scale(T aScale) { Scale(aScale, aScale); }
    174  // Scale 'this' by aXScale and aYScale, without doing any rounding.
    175  void Scale(T aXScale, T aYScale) {
    176    right = XMost() * aXScale;
    177    bottom = YMost() * aYScale;
    178    left = left * aXScale;
    179    top = top * aYScale;
    180  }
    181  // Scale 'this' by aScale, converting coordinates to integers so that the
    182  // result is the smallest integer-coordinate rectangle containing the
    183  // unrounded result. Note: this can turn an empty rectangle into a non-empty
    184  // rectangle
    185  void ScaleRoundOut(double aScale) { ScaleRoundOut(aScale, aScale); }
    186  // Scale 'this' by aXScale and aYScale, converting coordinates to integers so
    187  // that the result is the smallest integer-coordinate rectangle containing the
    188  // unrounded result.
    189  // Note: this can turn an empty rectangle into a non-empty rectangle
    190  void ScaleRoundOut(double aXScale, double aYScale) {
    191    right = static_cast<T>(ceil(double(XMost()) * aXScale));
    192    bottom = static_cast<T>(ceil(double(YMost()) * aYScale));
    193    left = static_cast<T>(floor(double(left) * aXScale));
    194    top = static_cast<T>(floor(double(top) * aYScale));
    195  }
    196  // Scale 'this' by aScale, converting coordinates to integers so that the
    197  // result is the largest integer-coordinate rectangle contained by the
    198  // unrounded result.
    199  void ScaleRoundIn(double aScale) { ScaleRoundIn(aScale, aScale); }
    200  // Scale 'this' by aXScale and aYScale, converting coordinates to integers so
    201  // that the result is the largest integer-coordinate rectangle contained by
    202  // the unrounded result.
    203  void ScaleRoundIn(double aXScale, double aYScale) {
    204    right = static_cast<T>(floor(double(XMost()) * aXScale));
    205    bottom = static_cast<T>(floor(double(YMost()) * aYScale));
    206    left = static_cast<T>(ceil(double(left) * aXScale));
    207    top = static_cast<T>(ceil(double(top) * aYScale));
    208  }
    209  // Scale 'this' by 1/aScale, converting coordinates to integers so that the
    210  // result is the smallest integer-coordinate rectangle containing the
    211  // unrounded result. Note: this can turn an empty rectangle into a non-empty
    212  // rectangle
    213  void ScaleInverseRoundOut(double aScale) {
    214    ScaleInverseRoundOut(aScale, aScale);
    215  }
    216  // Scale 'this' by 1/aXScale and 1/aYScale, converting coordinates to integers
    217  // so that the result is the smallest integer-coordinate rectangle containing
    218  // the unrounded result. Note: this can turn an empty rectangle into a
    219  // non-empty rectangle
    220  void ScaleInverseRoundOut(double aXScale, double aYScale) {
    221    right = static_cast<T>(ceil(double(XMost()) / aXScale));
    222    bottom = static_cast<T>(ceil(double(YMost()) / aYScale));
    223    left = static_cast<T>(floor(double(left) / aXScale));
    224    top = static_cast<T>(floor(double(top) / aYScale));
    225  }
    226  // Scale 'this' by 1/aScale, converting coordinates to integers so that the
    227  // result is the largest integer-coordinate rectangle contained by the
    228  // unrounded result.
    229  void ScaleInverseRoundIn(double aScale) {
    230    ScaleInverseRoundIn(aScale, aScale);
    231  }
    232  // Scale 'this' by 1/aXScale and 1/aYScale, converting coordinates to integers
    233  // so that the result is the largest integer-coordinate rectangle contained by
    234  // the unrounded result.
    235  void ScaleInverseRoundIn(double aXScale, double aYScale) {
    236    right = static_cast<T>(floor(double(XMost()) / aXScale));
    237    bottom = static_cast<T>(floor(double(YMost()) / aYScale));
    238    left = static_cast<T>(ceil(double(left) / aXScale));
    239    top = static_cast<T>(ceil(double(top) / aYScale));
    240  }
    241 
    242  /**
    243   * Translate this rectangle to be inside aRect. If it doesn't fit inside
    244   * aRect then the dimensions that don't fit will be shrunk so that they
    245   * do fit. The resulting rect is returned.
    246   */
    247  [[nodiscard]] Sub MoveInsideAndClamp(const Sub& aRect) const {
    248    T newLeft = std::max(aRect.left, left);
    249    T newTop = std::max(aRect.top, top);
    250    T width = std::min(aRect.Width(), Width());
    251    T height = std::min(aRect.Height(), Height());
    252    Sub rect(newLeft, newTop, newLeft + width, newTop + height);
    253    newLeft = std::min(rect.right, aRect.right) - width;
    254    newTop = std::min(rect.bottom, aRect.bottom) - height;
    255    rect.MoveBy(newLeft - rect.left, newTop - rect.top);
    256    return rect;
    257  }
    258 
    259  friend std::ostream& operator<<(
    260      std::ostream& stream,
    261      const BaseRectAbsolute<T, Sub, Point, Rect>& aRect) {
    262    return stream << "(l=" << aRect.left << ", t=" << aRect.top
    263                  << ", r=" << aRect.right << ", b=" << aRect.bottom << ')';
    264  }
    265 };
    266 
    267 template <class Units>
    268 struct IntRectAbsoluteTyped
    269    : public BaseRectAbsolute<int32_t, IntRectAbsoluteTyped<Units>,
    270                              IntPointTyped<Units>, IntRectTyped<Units>>,
    271      public Units {
    272  static_assert(IsPixel<Units>::value,
    273                "'units' must be a coordinate system tag");
    274  typedef BaseRectAbsolute<int32_t, IntRectAbsoluteTyped<Units>,
    275                           IntPointTyped<Units>, IntRectTyped<Units>>
    276      Super;
    277  typedef IntParam<int32_t> ToInt;
    278 
    279  IntRectAbsoluteTyped() : Super() {}
    280  IntRectAbsoluteTyped(ToInt aLeft, ToInt aTop, ToInt aRight, ToInt aBottom)
    281      : Super(aLeft.value, aTop.value, aRight.value, aBottom.value) {}
    282 };
    283 
    284 template <class Units>
    285 struct RectAbsoluteTyped
    286    : public BaseRectAbsolute<Float, RectAbsoluteTyped<Units>,
    287                              PointTyped<Units>, RectTyped<Units>>,
    288      public Units {
    289  static_assert(IsPixel<Units>::value,
    290                "'units' must be a coordinate system tag");
    291  typedef BaseRectAbsolute<Float, RectAbsoluteTyped<Units>, PointTyped<Units>,
    292                           RectTyped<Units>>
    293      Super;
    294 
    295  RectAbsoluteTyped() : Super() {}
    296  RectAbsoluteTyped(Float aLeft, Float aTop, Float aRight, Float aBottom)
    297      : Super(aLeft, aTop, aRight, aBottom) {}
    298 };
    299 
    300 typedef IntRectAbsoluteTyped<UnknownUnits> IntRectAbsolute;
    301 
    302 }  // namespace gfx
    303 }  // namespace mozilla
    304 
    305 #endif /* MOZILLA_GFX_RECT_ABSOLUTE_H_ */