tor-browser

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

Rect.h (20629B)


      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_H_
      8 #define MOZILLA_GFX_RECT_H_
      9 
     10 #include "BaseRect.h"
     11 #include "BaseMargin.h"
     12 #include "NumericTools.h"
     13 #include "Point.h"
     14 #include "Tools.h"
     15 #include "mozilla/Maybe.h"
     16 
     17 #include <cmath>
     18 #include <cstdint>
     19 
     20 namespace mozilla {
     21 
     22 template <typename>
     23 struct IsPixel;
     24 
     25 namespace gfx {
     26 
     27 template <class Units, class F>
     28 struct RectTyped;
     29 
     30 template <class Units>
     31 struct MOZ_EMPTY_BASES IntMarginTyped
     32    : public BaseMargin<int32_t, IntMarginTyped<Units>, IntCoordTyped<Units> >,
     33      public Units {
     34  static_assert(IsPixel<Units>::value,
     35                "'Units' must be a coordinate system tag");
     36 
     37  typedef IntCoordTyped<Units> Coord;
     38  typedef BaseMargin<int32_t, IntMarginTyped<Units>, Coord> Super;
     39 
     40  IntMarginTyped() : Super() {
     41    static_assert(sizeof(IntMarginTyped) == sizeof(int32_t) * 4,
     42                  "Would be unfortunate otherwise!");
     43  }
     44  constexpr IntMarginTyped(Coord aTop, Coord aRight, Coord aBottom, Coord aLeft)
     45      : Super(aTop, aRight, aBottom, aLeft) {}
     46 
     47  // XXX When all of the code is ported, the following functions to convert
     48  // to and from unknown types should be removed.
     49 
     50  static IntMarginTyped<Units> FromUnknownMargin(
     51      const IntMarginTyped<UnknownUnits>& aMargin) {
     52    return IntMarginTyped<Units>(aMargin.top.value, aMargin.right.value,
     53                                 aMargin.bottom.value, aMargin.left.value);
     54  }
     55 
     56  IntMarginTyped<UnknownUnits> ToUnknownMargin() const {
     57    return IntMarginTyped<UnknownUnits>(this->top, this->right, this->bottom,
     58                                        this->left);
     59  }
     60 };
     61 typedef IntMarginTyped<UnknownUnits> IntMargin;
     62 
     63 template <class Units, class F = Float>
     64 struct MarginTyped
     65    : public BaseMargin<F, MarginTyped<Units, F>, CoordTyped<Units, F> >,
     66      public Units {
     67  static_assert(IsPixel<Units>::value,
     68                "'Units' must be a coordinate system tag");
     69 
     70  typedef CoordTyped<Units, F> Coord;
     71  typedef BaseMargin<F, MarginTyped<Units, F>, Coord> Super;
     72 
     73  MarginTyped() : Super() {}
     74  MarginTyped(Coord aTop, Coord aRight, Coord aBottom, Coord aLeft)
     75      : Super(aTop, aRight, aBottom, aLeft) {}
     76  explicit MarginTyped(const IntMarginTyped<Units>& aMargin)
     77      : Super(F(aMargin.top), F(aMargin.right), F(aMargin.bottom),
     78              F(aMargin.left)) {}
     79 
     80  bool WithinEpsilonOf(const MarginTyped& aOther, F aEpsilon) const {
     81    return fabs(this->left - aOther.left) < aEpsilon &&
     82           fabs(this->top - aOther.top) < aEpsilon &&
     83           fabs(this->right - aOther.right) < aEpsilon &&
     84           fabs(this->bottom - aOther.bottom) < aEpsilon;
     85  }
     86 
     87  IntMarginTyped<Units> Rounded() const {
     88    return IntMarginTyped<Units>(int32_t(std::floor(this->top + 0.5f)),
     89                                 int32_t(std::floor(this->right + 0.5f)),
     90                                 int32_t(std::floor(this->bottom + 0.5f)),
     91                                 int32_t(std::floor(this->left + 0.5f)));
     92  }
     93 
     94  MarginTyped<UnknownUnits, F> ToUnknownMargin() const {
     95    return MarginTyped<UnknownUnits, F>(this->top.value, this->right.value,
     96                                        this->bottom.value, this->left.value);
     97  }
     98 };
     99 typedef MarginTyped<UnknownUnits> Margin;
    100 typedef MarginTyped<UnknownUnits, double> MarginDouble;
    101 
    102 template <class Units>
    103 IntMarginTyped<Units> RoundedToInt(const MarginTyped<Units>& aMargin) {
    104  return aMargin.Rounded();
    105 }
    106 
    107 template <class Units>
    108 struct MOZ_EMPTY_BASES IntRectTyped
    109    : public BaseRect<int32_t, IntRectTyped<Units>, IntPointTyped<Units>,
    110                      IntSizeTyped<Units>, IntMarginTyped<Units> >,
    111      public Units {
    112  static_assert(IsPixel<Units>::value,
    113                "'Units' must be a coordinate system tag");
    114 
    115  typedef BaseRect<int32_t, IntRectTyped<Units>, IntPointTyped<Units>,
    116                   IntSizeTyped<Units>, IntMarginTyped<Units> >
    117      Super;
    118  typedef IntRectTyped<Units> Self;
    119  typedef IntParam<int32_t> ToInt;
    120 
    121  IntRectTyped() : Super() {
    122    static_assert(sizeof(IntRectTyped) == sizeof(int32_t) * 4,
    123                  "Would be unfortunate otherwise!");
    124  }
    125  IntRectTyped(const IntPointTyped<Units>& aPos,
    126               const IntSizeTyped<Units>& aSize)
    127      : Super(aPos, aSize) {}
    128 
    129  IntRectTyped(ToInt aX, ToInt aY, ToInt aWidth, ToInt aHeight)
    130      : Super(aX.value, aY.value, aWidth.value, aHeight.value) {}
    131 
    132  static IntRectTyped<Units> RoundIn(float aX, float aY, float aW, float aH) {
    133    return IntRectTyped<Units>::RoundIn(
    134        RectTyped<Units, float>(aX, aY, aW, aH));
    135  }
    136 
    137  static IntRectTyped<Units> RoundOut(float aX, float aY, float aW, float aH) {
    138    return IntRectTyped<Units>::RoundOut(
    139        RectTyped<Units, float>(aX, aY, aW, aH));
    140  }
    141 
    142  static IntRectTyped<Units> Round(float aX, float aY, float aW, float aH) {
    143    return IntRectTyped<Units>::Round(RectTyped<Units, float>(aX, aY, aW, aH));
    144  }
    145 
    146  static IntRectTyped<Units> Truncate(float aX, float aY, float aW, float aH) {
    147    return IntRectTyped<Units>(IntPointTyped<Units>::Truncate(aX, aY),
    148                               IntSizeTyped<Units>::Truncate(aW, aH));
    149  }
    150 
    151  static IntRectTyped<Units> RoundIn(const RectTyped<Units, float>& aRect) {
    152    auto tmp(aRect);
    153    tmp.RoundIn();
    154    return IntRectTyped(int32_t(tmp.X()), int32_t(tmp.Y()),
    155                        int32_t(tmp.Width()), int32_t(tmp.Height()));
    156  }
    157 
    158  static IntRectTyped<Units> RoundOut(const RectTyped<Units, float>& aRect) {
    159    auto tmp(aRect);
    160    tmp.RoundOut();
    161    return IntRectTyped(int32_t(tmp.X()), int32_t(tmp.Y()),
    162                        int32_t(tmp.Width()), int32_t(tmp.Height()));
    163  }
    164 
    165  static IntRectTyped<Units> Round(const RectTyped<Units, float>& aRect) {
    166    auto tmp(aRect);
    167    tmp.Round();
    168    return IntRectTyped(int32_t(tmp.X()), int32_t(tmp.Y()),
    169                        int32_t(tmp.Width()), int32_t(tmp.Height()));
    170  }
    171 
    172  static IntRectTyped<Units> Truncate(const RectTyped<Units, float>& aRect) {
    173    return IntRectTyped::Truncate(aRect.X(), aRect.Y(), aRect.Width(),
    174                                  aRect.Height());
    175  }
    176 
    177  // Rounding isn't meaningful on an integer rectangle.
    178  void Round() {}
    179  void RoundIn() {}
    180  void RoundOut() {}
    181 
    182  // XXX When all of the code is ported, the following functions to convert
    183  // to and from unknown types should be removed.
    184 
    185  static IntRectTyped<Units> FromUnknownRect(
    186      const IntRectTyped<UnknownUnits>& rect) {
    187    return IntRectTyped<Units>(rect.X(), rect.Y(), rect.Width(), rect.Height());
    188  }
    189 
    190  IntRectTyped<UnknownUnits> ToUnknownRect() const {
    191    return IntRectTyped<UnknownUnits>(this->X(), this->Y(), this->Width(),
    192                                      this->Height());
    193  }
    194 
    195  bool Overflows() const {
    196    CheckedInt<int32_t> xMost = this->X();
    197    xMost += this->Width();
    198    CheckedInt<int32_t> yMost = this->Y();
    199    yMost += this->Height();
    200    return !xMost.isValid() || !yMost.isValid();
    201  }
    202 
    203  // Same as Union(), but in the cases where aRect is non-empty, the union is
    204  // done while guarding against overflow. If an overflow is detected, Nothing
    205  // is returned.
    206  [[nodiscard]] Maybe<Self> SafeUnion(const Self& aRect) const {
    207    if (this->IsEmpty()) {
    208      return aRect.Overflows() ? Nothing() : Some(aRect);
    209    } else if (aRect.IsEmpty()) {
    210      return Some(*static_cast<const Self*>(this));
    211    } else {
    212      return this->SafeUnionEdges(aRect);
    213    }
    214  }
    215 
    216  // Same as UnionEdges, but guards against overflow. If an overflow is
    217  // detected, Nothing is returned.
    218  [[nodiscard]] Maybe<Self> SafeUnionEdges(const Self& aRect) const {
    219    if (this->Overflows() || aRect.Overflows()) {
    220      return Nothing();
    221    }
    222    // If neither |this| nor |aRect| overflow, then their XMost/YMost values
    223    // should be safe to use.
    224    CheckedInt<int32_t> newX = std::min(this->x, aRect.x);
    225    CheckedInt<int32_t> newY = std::min(this->y, aRect.y);
    226    CheckedInt<int32_t> newXMost = std::max(this->XMost(), aRect.XMost());
    227    CheckedInt<int32_t> newYMost = std::max(this->YMost(), aRect.YMost());
    228    CheckedInt<int32_t> newW = newXMost - newX;
    229    CheckedInt<int32_t> newH = newYMost - newY;
    230    if (!newW.isValid() || !newH.isValid()) {
    231      return Nothing();
    232    }
    233    return Some(Self(newX.value(), newY.value(), newW.value(), newH.value()));
    234  }
    235 
    236  // This is here only to keep IPDL-generated code happy. DO NOT USE.
    237  bool operator==(const IntRectTyped<Units>& aRect) const {
    238    return IntRectTyped<Units>::IsEqualEdges(aRect);
    239  }
    240 
    241  void InflateToMultiple(const IntSizeTyped<Units>& aTileSize) {
    242    if (this->IsEmpty()) {
    243      return;
    244    }
    245 
    246    int32_t yMost = this->YMost();
    247    int32_t xMost = this->XMost();
    248 
    249    this->x = mozilla::RoundDownToMultiple(this->x, aTileSize.width);
    250    this->y = mozilla::RoundDownToMultiple(this->y, aTileSize.height);
    251    xMost = mozilla::RoundUpToMultiple(xMost, aTileSize.width);
    252    yMost = mozilla::RoundUpToMultiple(yMost, aTileSize.height);
    253 
    254    this->SetWidth(xMost - this->x);
    255    this->SetHeight(yMost - this->y);
    256  }
    257 };
    258 typedef IntRectTyped<UnknownUnits> IntRect;
    259 
    260 template <class Units, class F = Float>
    261 struct MOZ_EMPTY_BASES RectTyped
    262    : public BaseRect<F, RectTyped<Units, F>, PointTyped<Units, F>,
    263                      SizeTyped<Units, F>, MarginTyped<Units, F> >,
    264      public Units {
    265  static_assert(IsPixel<Units>::value,
    266                "'Units' must be a coordinate system tag");
    267 
    268  typedef BaseRect<F, RectTyped<Units, F>, PointTyped<Units, F>,
    269                   SizeTyped<Units, F>, MarginTyped<Units, F> >
    270      Super;
    271 
    272  RectTyped() : Super() {
    273    static_assert(sizeof(RectTyped) == sizeof(F) * 4,
    274                  "Would be unfortunate otherwise!");
    275  }
    276  RectTyped(const PointTyped<Units, F>& aPos, const SizeTyped<Units, F>& aSize)
    277      : Super(aPos, aSize) {}
    278  RectTyped(F _x, F _y, F _width, F _height) : Super(_x, _y, _width, _height) {}
    279  explicit RectTyped(const IntRectTyped<Units>& rect)
    280      : Super(F(rect.X()), F(rect.Y()), F(rect.Width()), F(rect.Height())) {}
    281 
    282  void NudgeToIntegers() {
    283    NudgeToInteger(&(this->x));
    284    NudgeToInteger(&(this->y));
    285    NudgeToInteger(&(this->width));
    286    NudgeToInteger(&(this->height));
    287  }
    288 
    289  bool ToIntRect(IntRectTyped<Units>* aOut) const {
    290    *aOut =
    291        IntRectTyped<Units>(int32_t(this->X()), int32_t(this->Y()),
    292                            int32_t(this->Width()), int32_t(this->Height()));
    293    return RectTyped<Units, F>(F(aOut->X()), F(aOut->Y()), F(aOut->Width()),
    294                               F(aOut->Height()))
    295        .IsEqualEdges(*this);
    296  }
    297 
    298  // XXX When all of the code is ported, the following functions to convert to
    299  // and from unknown types should be removed.
    300 
    301  static RectTyped<Units, F> FromUnknownRect(
    302      const RectTyped<UnknownUnits, F>& rect) {
    303    return RectTyped<Units, F>(rect.X(), rect.Y(), rect.Width(), rect.Height());
    304  }
    305 
    306  RectTyped<UnknownUnits, F> ToUnknownRect() const {
    307    return RectTyped<UnknownUnits, F>(this->X(), this->Y(), this->Width(),
    308                                      this->Height());
    309  }
    310 
    311  // This is here only to keep IPDL-generated code happy. DO NOT USE.
    312  bool operator==(const RectTyped<Units, F>& aRect) const {
    313    return RectTyped<Units, F>::IsEqualEdges(aRect);
    314  }
    315 
    316  bool WithinEpsilonOf(const RectTyped& aOther, F aEpsilon) const {
    317    return fabs(this->x - aOther.x) < aEpsilon &&
    318           fabs(this->y - aOther.y) < aEpsilon &&
    319           fabs(this->width - aOther.width) < aEpsilon &&
    320           fabs(this->height - aOther.height) < aEpsilon;
    321  }
    322 };
    323 typedef RectTyped<UnknownUnits> Rect;
    324 typedef RectTyped<UnknownUnits, double> RectDouble;
    325 
    326 template <class Units, class D>
    327 RectTyped<Units> NarrowToFloat(const RectTyped<Units, D>& aRect) {
    328  return RectTyped<Units>(float(aRect.x), float(aRect.y), float(aRect.width),
    329                          float(aRect.height));
    330 }
    331 
    332 template <class Units, class F>
    333 RectTyped<Units, double> WidenToDouble(const RectTyped<Units, F>& aRect) {
    334  return RectTyped<Units, double>(double(aRect.x), double(aRect.y),
    335                                  double(aRect.width), double(aRect.height));
    336 }
    337 
    338 template <class Units>
    339 IntRectTyped<Units> RoundedToInt(const RectTyped<Units>& aRect) {
    340  RectTyped<Units> copy(aRect);
    341  copy.Round();
    342  return IntRectTyped<Units>(int32_t(copy.X()), int32_t(copy.Y()),
    343                             int32_t(copy.Width()), int32_t(copy.Height()));
    344 }
    345 
    346 template <class Units>
    347 bool RectIsInt32Safe(const RectTyped<Units>& aRect) {
    348  float min = (float)std::numeric_limits<std::int32_t>::min();
    349  float max = (float)std::numeric_limits<std::int32_t>::max();
    350  return aRect.x > min && aRect.y > min && aRect.width < max &&
    351         aRect.height < max && aRect.XMost() < max && aRect.YMost() < max;
    352 }
    353 
    354 template <class Units>
    355 IntRectTyped<Units> RoundedIn(const RectTyped<Units>& aRect) {
    356  return IntRectTyped<Units>::RoundIn(aRect);
    357 }
    358 
    359 template <class Units>
    360 IntRectTyped<Units> RoundedOut(const RectTyped<Units>& aRect) {
    361  return IntRectTyped<Units>::RoundOut(aRect);
    362 }
    363 
    364 template <class Units>
    365 IntRectTyped<Units> TruncatedToInt(const RectTyped<Units>& aRect) {
    366  return IntRectTyped<Units>::Truncate(aRect);
    367 }
    368 
    369 template <class Units>
    370 RectTyped<Units> IntRectToRect(const IntRectTyped<Units>& aRect) {
    371  return RectTyped<Units>(aRect.X(), aRect.Y(), aRect.Width(), aRect.Height());
    372 }
    373 
    374 // Convenience functions for intersecting and unioning two rectangles wrapped in
    375 // Maybes.
    376 template <typename Rect>
    377 Maybe<Rect> IntersectMaybeRects(const Maybe<Rect>& a, const Maybe<Rect>& b) {
    378  if (!a) {
    379    return b;
    380  } else if (!b) {
    381    return a;
    382  } else {
    383    return Some(a->Intersect(*b));
    384  }
    385 }
    386 template <typename Rect>
    387 Maybe<Rect> UnionMaybeRects(const Maybe<Rect>& a, const Maybe<Rect>& b) {
    388  if (!a) {
    389    return b;
    390  } else if (!b) {
    391    return a;
    392  } else {
    393    return Some(a->Union(*b));
    394  }
    395 }
    396 
    397 template <typename Coord, typename Size, typename Margin>
    398 struct BaseRectCornerRadii {
    399  Size radii[eCornerCount];
    400 
    401  BaseRectCornerRadii() = default;
    402 
    403  explicit BaseRectCornerRadii(Coord radius) {
    404    for (const auto i : mozilla::AllPhysicalCorners()) {
    405      radii[i].SizeTo(radius, radius);
    406    }
    407  }
    408 
    409  BaseRectCornerRadii(Coord radiusX, Coord radiusY) {
    410    for (const auto i : mozilla::AllPhysicalCorners()) {
    411      radii[i].SizeTo(radiusX, radiusY);
    412    }
    413  }
    414 
    415  BaseRectCornerRadii(Coord tl, Coord tr, Coord br, Coord bl) {
    416    radii[eCornerTopLeft].SizeTo(tl, tl);
    417    radii[eCornerTopRight].SizeTo(tr, tr);
    418    radii[eCornerBottomRight].SizeTo(br, br);
    419    radii[eCornerBottomLeft].SizeTo(bl, bl);
    420  }
    421 
    422  BaseRectCornerRadii(const Size& tl, const Size& tr, const Size& br,
    423                      const Size& bl) {
    424    radii[eCornerTopLeft] = tl;
    425    radii[eCornerTopRight] = tr;
    426    radii[eCornerBottomRight] = br;
    427    radii[eCornerBottomLeft] = bl;
    428  }
    429 
    430  const Size& operator[](Corner aCorner) const { return radii[aCorner]; }
    431  Size& operator[](Corner aCorner) { return radii[aCorner]; }
    432 
    433  const Coord& operator[](HalfCorner aCorner) const {
    434    return reinterpret_cast<const Coord*>(&radii)[aCorner];
    435  }
    436  Coord& operator[](HalfCorner aCorner) {
    437    return reinterpret_cast<Coord*>(&radii)[aCorner];
    438  }
    439 
    440  bool operator!=(const BaseRectCornerRadii& aOther) const {
    441    return !(*this == aOther);
    442  }
    443 
    444  bool operator==(const BaseRectCornerRadii& aOther) const {
    445    return TopLeft() == aOther.TopLeft() && TopRight() == aOther.TopRight() &&
    446           BottomRight() == aOther.BottomRight() &&
    447           BottomLeft() == aOther.BottomLeft();
    448  }
    449 
    450  bool AreRadiiSame() const {
    451    return TopLeft() == TopRight() && TopLeft() == BottomRight() &&
    452           TopLeft() == BottomLeft();
    453  }
    454 
    455  void Scale(Float aXScale, Float aYScale) {
    456    for (auto& corner : radii) {
    457      corner.Scale(aXScale, aYScale);
    458    }
    459  }
    460 
    461  const Size& TopLeft() const { return radii[eCornerTopLeft]; }
    462  Size& TopLeft() { return radii[eCornerTopLeft]; }
    463 
    464  const Size& TopRight() const { return radii[eCornerTopRight]; }
    465  Size& TopRight() { return radii[eCornerTopRight]; }
    466 
    467  const Size& BottomRight() const { return radii[eCornerBottomRight]; }
    468  Size& BottomRight() { return radii[eCornerBottomRight]; }
    469 
    470  const Size& BottomLeft() const { return radii[eCornerBottomLeft]; }
    471  Size& BottomLeft() { return radii[eCornerBottomLeft]; }
    472 
    473  bool IsEmpty() const {
    474    return TopLeft().IsEmpty() && TopRight().IsEmpty() &&
    475           BottomRight().IsEmpty() && BottomLeft().IsEmpty();
    476  }
    477 
    478  void AdjustOutwards(const Margin& aMargin) { return Adjust<true>(aMargin); }
    479  void AdjustInwards(const Margin& aMargin) { return Adjust<false>(-aMargin); }
    480 
    481 private:
    482  template <bool aOut>
    483  void Adjust(const Margin& aMargin) {
    484    constexpr Coord kZero(0);
    485    constexpr auto C_TL = eCornerTopLeft;
    486    constexpr auto C_TR = eCornerTopRight;
    487    constexpr auto C_BL = eCornerBottomLeft;
    488    constexpr auto C_BR = eCornerBottomRight;
    489    // round the edges that have radii > 0.0 to start with
    490    if (!aOut || (radii[C_TL].width > kZero && radii[C_TL].height > kZero)) {
    491      radii[C_TL].width = std::max(kZero, radii[C_TL].width + aMargin.left);
    492      radii[C_TL].height = std::max(kZero, radii[C_TL].height + aMargin.top);
    493    }
    494 
    495    if (!aOut || (radii[C_TR].width > kZero && radii[C_TR].height > kZero)) {
    496      radii[C_TR].width = std::max(kZero, radii[C_TR].width + aMargin.right);
    497      radii[C_TR].height = std::max(kZero, radii[C_TR].height + aMargin.top);
    498    }
    499 
    500    if (!aOut || (radii[C_BR].width > kZero && radii[C_BR].height > kZero)) {
    501      radii[C_BR].width = std::max(kZero, radii[C_BR].width + aMargin.right);
    502      radii[C_BR].height = std::max(kZero, radii[C_BR].height + aMargin.bottom);
    503    }
    504 
    505    if (!aOut || (radii[C_BL].width > kZero && radii[C_BL].height > kZero)) {
    506      radii[C_BL].width = std::max(kZero, radii[C_BL].width + aMargin.left);
    507      radii[C_BL].height = std::max(kZero, radii[C_BL].height + aMargin.bottom);
    508    }
    509  }
    510 };
    511 
    512 struct RectCornerRadii final : public BaseRectCornerRadii<Float, Size, Margin> {
    513  using BaseRectCornerRadii::BaseRectCornerRadii;
    514 };
    515 
    516 /* A rounded rectangle abstraction.
    517 *
    518 * This can represent a rectangle with a different pair of radii on each corner.
    519 *
    520 * Note: CoreGraphics and Direct2D only support rounded rectangle with the same
    521 * radii on all corners. However, supporting CSS's border-radius requires the
    522 * extra flexibility. */
    523 struct RoundedRect {
    524  typedef mozilla::gfx::RectCornerRadii RectCornerRadii;
    525 
    526  RoundedRect() = default;
    527 
    528  RoundedRect(const Rect& aRect, const RectCornerRadii& aCorners)
    529      : rect(aRect), corners(aCorners) {}
    530 
    531  void Deflate(const Margin& aMargin) {
    532    Deflate(aMargin.top, aMargin.bottom, aMargin.left, aMargin.right);
    533  }
    534 
    535  void Deflate(Float aTopWidth, Float aBottomWidth, Float aLeftWidth,
    536               Float aRightWidth) {
    537    // deflate the internal rect
    538    rect.SetRect(rect.X() + aLeftWidth, rect.Y() + aTopWidth,
    539                 std::max(0.f, rect.Width() - aLeftWidth - aRightWidth),
    540                 std::max(0.f, rect.Height() - aTopWidth - aBottomWidth));
    541 
    542    corners.radii[mozilla::eCornerTopLeft].width = std::max(
    543        0.f, corners.radii[mozilla::eCornerTopLeft].width - aLeftWidth);
    544    corners.radii[mozilla::eCornerTopLeft].height = std::max(
    545        0.f, corners.radii[mozilla::eCornerTopLeft].height - aTopWidth);
    546 
    547    corners.radii[mozilla::eCornerTopRight].width = std::max(
    548        0.f, corners.radii[mozilla::eCornerTopRight].width - aRightWidth);
    549    corners.radii[mozilla::eCornerTopRight].height = std::max(
    550        0.f, corners.radii[mozilla::eCornerTopRight].height - aTopWidth);
    551 
    552    corners.radii[mozilla::eCornerBottomLeft].width = std::max(
    553        0.f, corners.radii[mozilla::eCornerBottomLeft].width - aLeftWidth);
    554    corners.radii[mozilla::eCornerBottomLeft].height = std::max(
    555        0.f, corners.radii[mozilla::eCornerBottomLeft].height - aBottomWidth);
    556 
    557    corners.radii[mozilla::eCornerBottomRight].width = std::max(
    558        0.f, corners.radii[mozilla::eCornerBottomRight].width - aRightWidth);
    559    corners.radii[mozilla::eCornerBottomRight].height = std::max(
    560        0.f, corners.radii[mozilla::eCornerBottomRight].height - aBottomWidth);
    561  }
    562 
    563  bool operator==(const RoundedRect& aOther) const {
    564    return rect == aOther.rect && corners == aOther.corners;
    565  }
    566 
    567  Rect rect;
    568  RectCornerRadii corners;
    569 };
    570 
    571 }  // namespace gfx
    572 }  // namespace mozilla
    573 
    574 #endif /* MOZILLA_GFX_RECT_H_ */