tor-browser

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

nsRect.h (19713B)


      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 NSRECT_H
      8 #define NSRECT_H
      9 
     10 #include <stdint.h>          // for int32_t, int64_t
     11 #include <algorithm>         // for min/max
     12 #include "mozilla/Likely.h"  // for MOZ_UNLIKELY
     13 #include "mozilla/gfx/BaseRect.h"
     14 #include "mozilla/gfx/Rect.h"
     15 #include "nsCoord.h"      // for nscoord, etc
     16 #include "nsISupports.h"  // for MOZ_COUNT_CTOR, etc
     17 #include "nsPoint.h"      // for nsIntPoint, nsPoint
     18 #include "nsSize.h"       // for IntSize, nsSize
     19 #if !defined(ANDROID) && (defined(__SSE2__) || defined(_M_X64) || \
     20                          (defined(_M_IX86_FP) && _M_IX86_FP >= 2))
     21 #  if defined(_MSC_VER) && !defined(__clang__)
     22 #    include "smmintrin.h"
     23 #  else
     24 #    include "emmintrin.h"
     25 #  endif
     26 #endif
     27 
     28 struct nsMargin;
     29 
     30 typedef mozilla::gfx::IntRect nsIntRect;
     31 
     32 struct nsRect : public mozilla::gfx::BaseRect<nscoord, nsRect, nsPoint, nsSize,
     33                                              nsMargin> {
     34  typedef mozilla::gfx::BaseRect<nscoord, nsRect, nsPoint, nsSize, nsMargin>
     35      Super;
     36 
     37  // Constructors
     38  nsRect() { MOZ_COUNT_CTOR(nsRect); }
     39  nsRect(const nsRect& aRect) : Super(aRect) { MOZ_COUNT_CTOR(nsRect); }
     40  nsRect(const nsPoint& aOrigin, const nsSize& aSize) : Super(aOrigin, aSize) {
     41    MOZ_COUNT_CTOR(nsRect);
     42  }
     43  nsRect(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight)
     44      : Super(aX, aY, aWidth, aHeight) {
     45    MOZ_COUNT_CTOR(nsRect);
     46  }
     47  nsRect& operator=(const nsRect&) = default;
     48 
     49  MOZ_COUNTED_DTOR(nsRect)
     50 
     51  // We have saturating versions of all the Union methods. These avoid
     52  // overflowing nscoord values in the 'width' and 'height' fields by
     53  // clamping the width and height values to nscoord_MAX if necessary.
     54 
     55  // Returns the smallest rectangle that contains both the area of both
     56  // this and aRect. Thus, empty input rectangles are ignored.
     57  // Note: if both rectangles are empty, returns aRect.
     58  [[nodiscard]] nsRect SaturatingUnion(const nsRect& aRect) const {
     59    if (IsEmpty()) {
     60      return aRect;
     61    } else if (aRect.IsEmpty()) {
     62      return *static_cast<const nsRect*>(this);
     63    } else {
     64      return SaturatingUnionEdges(aRect);
     65    }
     66  }
     67 
     68  [[nodiscard]] nsRect SaturatingUnionEdges(const nsRect& aRect) const {
     69    nscoord resultX = std::min(aRect.X(), x);
     70    int64_t w =
     71        std::max(int64_t(aRect.X()) + aRect.Width(), int64_t(x) + width) -
     72        resultX;
     73    if (MOZ_UNLIKELY(w > nscoord_MAX)) {
     74      // Clamp huge negative x to nscoord_MIN / 2 and try again.
     75      resultX = std::max(resultX, nscoord_MIN / 2);
     76      w = std::max(int64_t(aRect.X()) + aRect.Width(), int64_t(x) + width) -
     77          resultX;
     78      if (MOZ_UNLIKELY(w > nscoord_MAX)) {
     79        w = nscoord_MAX;
     80      }
     81    }
     82 
     83    nscoord resultY = std::min(aRect.y, y);
     84    int64_t h =
     85        std::max(int64_t(aRect.Y()) + aRect.Height(), int64_t(y) + height) -
     86        resultY;
     87    if (MOZ_UNLIKELY(h > nscoord_MAX)) {
     88      // Clamp huge negative y to nscoord_MIN / 2 and try again.
     89      resultY = std::max(resultY, nscoord_MIN / 2);
     90      h = std::max(int64_t(aRect.Y()) + aRect.Height(), int64_t(y) + height) -
     91          resultY;
     92      if (MOZ_UNLIKELY(h > nscoord_MAX)) {
     93        h = nscoord_MAX;
     94      }
     95    }
     96    return nsRect(resultX, resultY, nscoord(w), nscoord(h));
     97  }
     98 
     99  // Make all nsRect Union methods be saturating.
    100  [[nodiscard]] nsRect UnionEdges(const nsRect& aRect) const {
    101    return SaturatingUnionEdges(aRect);
    102  }
    103  [[nodiscard]] nsRect Union(const nsRect& aRect) const {
    104    return SaturatingUnion(aRect);
    105  }
    106  [[nodiscard]] nsRect UnsafeUnion(const nsRect& aRect) const {
    107    return Super::Union(aRect);
    108  }
    109  void UnionRect(const nsRect& aRect1, const nsRect& aRect2) {
    110    *this = aRect1.Union(aRect2);
    111  }
    112 
    113 #if defined(_MSC_VER) && !defined(__clang__) && \
    114    (defined(_M_X64) || defined(_M_IX86))
    115  // Only MSVC supports inlining intrinsics for archs you're not compiling for.
    116  [[nodiscard]] nsRect Intersect(const nsRect& aRect) const {
    117    nsRect result;
    118    if (mozilla::gfx::Factory::HasSSE4()) {
    119      __m128i rect1 = _mm_loadu_si128((__m128i*)&aRect);  // x1, y1, w1, h1
    120      __m128i rect2 = _mm_loadu_si128((__m128i*)this);    // x2, y2, w2, h2
    121 
    122      __m128i resultRect = _mm_max_epi32(rect1, rect2);  // xr, yr, zz, zz
    123 
    124      // result.width = std::min<int32_t>(x - result.x + width,
    125      //                                  aRect.x - result.x + aRect.width);
    126      // result.height = std::min<int32_t>(y - result.y + height,
    127      //                                   aRect.y - result.y + aRect.height);
    128      __m128i widthheight = _mm_min_epi32(
    129          _mm_add_epi32(_mm_sub_epi32(rect1, resultRect),
    130                        _mm_srli_si128(rect1, 8)),
    131          _mm_add_epi32(_mm_sub_epi32(rect2, resultRect),
    132                        _mm_srli_si128(rect2, 8)));  // w, h, zz, zz
    133      widthheight = _mm_slli_si128(widthheight, 8);  // 00, 00, wr, hr
    134 
    135      resultRect =
    136          _mm_blend_epi16(resultRect, widthheight, 0xF0);  // xr, yr, wr, hr
    137 
    138      if ((_mm_movemask_ps(_mm_castsi128_ps(
    139               _mm_cmplt_epi32(resultRect, _mm_setzero_si128()))) &
    140           0xC) != 0) {
    141        // It's potentially more efficient to store all 0s. But the non SSE4
    142        // code leaves x/y intact so let's do the same here.
    143        resultRect = _mm_and_si128(resultRect,
    144                                   _mm_set_epi32(0, 0, 0xFFFFFFFF, 0xFFFFFFFF));
    145      }
    146 
    147      _mm_storeu_si128((__m128i*)&result, resultRect);
    148 
    149      return result;
    150    }
    151 
    152    result.x = std::max<int32_t>(x, aRect.x);
    153    result.y = std::max<int32_t>(y, aRect.y);
    154    result.width = std::min<int32_t>(x - result.x + width,
    155                                     aRect.x - result.x + aRect.width);
    156    result.height = std::min<int32_t>(y - result.y + height,
    157                                      aRect.y - result.y + aRect.height);
    158    if (result.width < 0 || result.height < 0) {
    159      result.SizeTo(0, 0);
    160    }
    161    return result;
    162  }
    163 
    164  bool IntersectRect(const nsRect& aRect1, const nsRect& aRect2) {
    165    if (mozilla::gfx::Factory::HasSSE4()) {
    166      __m128i rect1 = _mm_loadu_si128((__m128i*)&aRect1);  // x1, y1, w1, h1
    167      __m128i rect2 = _mm_loadu_si128((__m128i*)&aRect2);  // x2, y2, w2, h2
    168 
    169      __m128i resultRect = _mm_max_epi32(rect1, rect2);  // xr, yr, zz, zz
    170      // result.width = std::min<int32_t>(x - result.x + width,
    171      //                                  aRect.x - result.x + aRect.width);
    172      // result.height = std::min<int32_t>(y - result.y + height,
    173      //                                   aRect.y - result.y + aRect.height);
    174      __m128i widthheight = _mm_min_epi32(
    175          _mm_add_epi32(_mm_sub_epi32(rect1, resultRect),
    176                        _mm_srli_si128(rect1, 8)),
    177          _mm_add_epi32(_mm_sub_epi32(rect2, resultRect),
    178                        _mm_srli_si128(rect2, 8)));  // w, h, zz, zz
    179      widthheight = _mm_slli_si128(widthheight, 8);  // 00, 00, wr, hr
    180 
    181      resultRect =
    182          _mm_blend_epi16(resultRect, widthheight, 0xF0);  // xr, yr, wr, hr
    183 
    184      if ((_mm_movemask_ps(_mm_castsi128_ps(
    185               _mm_cmpgt_epi32(resultRect, _mm_setzero_si128()))) &
    186           0xC) != 0xC) {
    187        // It's potentially more efficient to store all 0s. But the non SSE4
    188        // code leaves x/y intact so let's do the same here.
    189        resultRect = _mm_and_si128(resultRect,
    190                                   _mm_set_epi32(0, 0, 0xFFFFFFFF, 0xFFFFFFFF));
    191        _mm_storeu_si128((__m128i*)this, resultRect);
    192        return false;
    193      }
    194 
    195      _mm_storeu_si128((__m128i*)this, resultRect);
    196 
    197      return true;
    198    }
    199 
    200    int32_t newX = std::max<int32_t>(aRect1.x, aRect2.x);
    201    int32_t newY = std::max<int32_t>(aRect1.y, aRect2.y);
    202    width = std::min<int32_t>(aRect1.x - newX + aRect1.width,
    203                              aRect2.x - newX + aRect2.width);
    204    height = std::min<int32_t>(aRect1.y - newY + aRect1.height,
    205                               aRect2.y - newY + aRect2.height);
    206    x = newX;
    207    y = newY;
    208    if (width <= 0 || height <= 0) {
    209      SizeTo(0, 0);
    210      return false;
    211    }
    212    return true;
    213  }
    214 #endif
    215 
    216  // Return whether this rect's right or bottom edge overflow int32.
    217  bool Overflows() const;
    218 
    219  /**
    220   * Return this rect scaled to a different appunits per pixel (APP) ratio.
    221   * In the RoundOut version we make the rect the smallest rect containing the
    222   * unrounded result. In the RoundIn version we make the rect the largest rect
    223   * contained in the unrounded result.
    224   * @param aFromAPP the APP to scale from
    225   * @param aToAPP the APP to scale to
    226   * @note this can turn an empty rectangle into a non-empty rectangle
    227   */
    228  [[nodiscard]] inline nsRect ScaleToOtherAppUnitsRoundOut(
    229      int32_t aFromAPP, int32_t aToAPP) const;
    230  [[nodiscard]] inline nsRect ScaleToOtherAppUnitsRoundIn(int32_t aFromAPP,
    231                                                          int32_t aToAPP) const;
    232 
    233  [[nodiscard]] inline mozilla::gfx::IntRect ScaleToNearestPixels(
    234      float aXScale, float aYScale, nscoord aAppUnitsPerPixel) const;
    235 
    236  [[nodiscard]] inline mozilla::gfx::IntRect ToNearestPixels(
    237      nscoord aAppUnitsPerPixel) const;
    238 
    239  // Note: this can turn an empty rectangle into a non-empty rectangle
    240  [[nodiscard]] inline mozilla::gfx::IntRect ScaleToOutsidePixels(
    241      float aXScale, float aYScale, nscoord aAppUnitsPerPixel) const;
    242 
    243  // Note: this can turn an empty rectangle into a non-empty rectangle
    244  [[nodiscard]] inline mozilla::gfx::IntRect ToOutsidePixels(
    245      nscoord aAppUnitsPerPixel) const;
    246 
    247  [[nodiscard]] inline mozilla::gfx::IntRect ScaleToInsidePixels(
    248      float aXScale, float aYScale, nscoord aAppUnitsPerPixel) const;
    249 
    250  [[nodiscard]] inline mozilla::gfx::IntRect ToInsidePixels(
    251      nscoord aAppUnitsPerPixel) const;
    252 
    253  // This is here only to keep IPDL-generated code happy. DO NOT USE.
    254  bool operator==(const nsRect& aRect) const { return IsEqualEdges(aRect); }
    255 
    256  [[nodiscard]] inline nsRect RemoveResolution(const float aResolution) const;
    257 
    258  [[nodiscard]] mozilla::Maybe<nsRect> EdgeInclusiveIntersection(
    259      const nsRect& aOther) const {
    260    nscoord left = std::max(x, aOther.x);
    261    nscoord top = std::max(y, aOther.y);
    262    nscoord right = std::min(XMost(), aOther.XMost());
    263    nscoord bottom = std::min(YMost(), aOther.YMost());
    264    if (left > right || top > bottom) {
    265      return mozilla::Nothing();
    266    }
    267    return mozilla::Some(nsRect(left, top, right - left, bottom - top));
    268  }
    269 };
    270 
    271 /*
    272 * App Unit/Pixel conversions
    273 */
    274 
    275 inline nsRect nsRect::ScaleToOtherAppUnitsRoundOut(int32_t aFromAPP,
    276                                                   int32_t aToAPP) const {
    277  if (aFromAPP == aToAPP) {
    278    return *this;
    279  }
    280 
    281  nsRect rect;
    282  rect.SetBox(NSToCoordFloor(NSCoordScale(x, aFromAPP, aToAPP)),
    283              NSToCoordFloor(NSCoordScale(y, aFromAPP, aToAPP)),
    284              NSToCoordCeil(NSCoordScale(XMost(), aFromAPP, aToAPP)),
    285              NSToCoordCeil(NSCoordScale(YMost(), aFromAPP, aToAPP)));
    286  return rect;
    287 }
    288 
    289 inline nsRect nsRect::ScaleToOtherAppUnitsRoundIn(int32_t aFromAPP,
    290                                                  int32_t aToAPP) const {
    291  if (aFromAPP == aToAPP) {
    292    return *this;
    293  }
    294 
    295  nsRect rect;
    296  rect.SetBox(NSToCoordCeil(NSCoordScale(x, aFromAPP, aToAPP)),
    297              NSToCoordCeil(NSCoordScale(y, aFromAPP, aToAPP)),
    298              NSToCoordFloor(NSCoordScale(XMost(), aFromAPP, aToAPP)),
    299              NSToCoordFloor(NSCoordScale(YMost(), aFromAPP, aToAPP)));
    300  return rect;
    301 }
    302 
    303 #if !defined(ANDROID) && (defined(__SSE2__) || defined(_M_X64) || \
    304                          (defined(_M_IX86_FP) && _M_IX86_FP >= 2))
    305 // Life would be so much better if we had SSE4 here.
    306 static MOZ_ALWAYS_INLINE __m128i floor_ps2epi32(__m128 x) {
    307  __m128 one = _mm_set_ps(1.0f, 1.0f, 1.0f, 1.0f);
    308 
    309  __m128 t = _mm_cvtepi32_ps(_mm_cvttps_epi32(x));
    310  __m128 r = _mm_sub_ps(t, _mm_and_ps(_mm_cmplt_ps(x, t), one));
    311 
    312  return _mm_cvttps_epi32(r);
    313 }
    314 
    315 static MOZ_ALWAYS_INLINE __m128i ceil_ps2epi32(__m128 x) {
    316  __m128 t = _mm_sub_ps(_mm_setzero_ps(), x);
    317  __m128i r = _mm_sub_epi32(_mm_setzero_si128(), floor_ps2epi32(t));
    318 
    319  return r;
    320 }
    321 #endif
    322 
    323 // scale the rect but round to preserve centers
    324 inline mozilla::gfx::IntRect nsRect::ScaleToNearestPixels(
    325    float aXScale, float aYScale, nscoord aAppUnitsPerPixel) const {
    326  mozilla::gfx::IntRect rect;
    327  // Android x86 builds have bindgen issues.
    328 #if !defined(ANDROID) && (defined(__SSE2__) || defined(_M_X64) || \
    329                          (defined(_M_IX86_FP) && _M_IX86_FP >= 2))
    330  __m128 appUnitsPacked = _mm_set_ps(aAppUnitsPerPixel, aAppUnitsPerPixel,
    331                                     aAppUnitsPerPixel, aAppUnitsPerPixel);
    332  __m128 scalesPacked = _mm_set_ps(aYScale, aXScale, aYScale, aXScale);
    333  __m128 biasesPacked = _mm_set_ps(0.5f, 0.5f, 0.5f, 0.5f);
    334 
    335  __m128i rectPacked = _mm_loadu_si128((__m128i*)this);
    336  __m128i topLeft = _mm_slli_si128(rectPacked, 8);
    337 
    338  rectPacked = _mm_add_epi32(rectPacked, topLeft);  // X, Y, XMost(), YMost()
    339 
    340  __m128 rectFloat = _mm_cvtepi32_ps(rectPacked);
    341 
    342  // Scale, i.e. ([ x y xmost ymost ] / aAppUnitsPerPixel) * [ aXScale aYScale
    343  // aXScale aYScale ]
    344  rectFloat = _mm_mul_ps(_mm_div_ps(rectFloat, appUnitsPacked), scalesPacked);
    345 
    346  // Floor
    347  // Executed with bias and roundmode down, since round-nearest rounds 0.5
    348  // downward half the time.
    349  rectFloat = _mm_add_ps(rectFloat, biasesPacked);
    350  rectPacked = floor_ps2epi32(rectFloat);
    351 
    352  topLeft = _mm_slli_si128(rectPacked, 8);
    353  rectPacked = _mm_sub_epi32(rectPacked, topLeft);  // X, Y, Width, Height
    354 
    355  // Avoid negative width/height due to overflow.
    356  __m128i mask = _mm_or_si128(_mm_cmpgt_epi32(rectPacked, _mm_setzero_si128()),
    357                              _mm_set_epi32(0, 0, 0xFFFFFFFF, 0xFFFFFFFF));
    358  // Mask will now contain [ 0xFFFFFFFF 0xFFFFFFFF (width <= 0 ? 0 : 0xFFFFFFFF)
    359  // (height <= 0 ? 0 : 0xFFFFFFFF) ]
    360  rectPacked = _mm_and_si128(rectPacked, mask);
    361 
    362  _mm_storeu_si128((__m128i*)&rect, rectPacked);
    363 #else
    364  rect.SetNonEmptyBox(
    365      NSToIntRoundUp(NSAppUnitsToFloatPixels(x, aAppUnitsPerPixel) * aXScale),
    366      NSToIntRoundUp(NSAppUnitsToFloatPixels(y, aAppUnitsPerPixel) * aYScale),
    367      NSToIntRoundUp(NSAppUnitsToFloatPixels(XMost(), aAppUnitsPerPixel) *
    368                     aXScale),
    369      NSToIntRoundUp(NSAppUnitsToFloatPixels(YMost(), aAppUnitsPerPixel) *
    370                     aYScale));
    371 #endif
    372  return rect;
    373 }
    374 
    375 // scale the rect but round to smallest containing rect
    376 inline mozilla::gfx::IntRect nsRect::ScaleToOutsidePixels(
    377    float aXScale, float aYScale, nscoord aAppUnitsPerPixel) const {
    378  mozilla::gfx::IntRect rect;
    379  // Android x86 builds have bindgen issues.
    380 #if !defined(ANDROID) && (defined(__SSE2__) || defined(_M_X64) || \
    381                          (defined(_M_IX86_FP) && _M_IX86_FP >= 2))
    382  __m128 appUnitsPacked = _mm_set_ps(aAppUnitsPerPixel, aAppUnitsPerPixel,
    383                                     aAppUnitsPerPixel, aAppUnitsPerPixel);
    384  __m128 scalesPacked = _mm_set_ps(aYScale, aXScale, aYScale, aXScale);
    385 
    386  __m128i rectPacked = _mm_loadu_si128((__m128i*)this);  // x, y, w, h
    387  __m128i topLeft = _mm_slli_si128(rectPacked, 8);       // 0, 0, x, y
    388 
    389  rectPacked = _mm_add_epi32(rectPacked, topLeft);  // X, Y, XMost(), YMost()
    390 
    391  __m128 rectFloat = _mm_cvtepi32_ps(rectPacked);
    392 
    393  // Scale i.e. ([ x y xmost ymost ] / aAppUnitsPerPixel) *
    394  //             [ aXScale aYScale aXScale aYScale ]
    395  rectFloat = _mm_mul_ps(_mm_div_ps(rectFloat, appUnitsPacked), scalesPacked);
    396  rectPacked = ceil_ps2epi32(rectFloat);    // xx, xx, XMost(), YMost()
    397  __m128i tmp = floor_ps2epi32(rectFloat);  // x, y, xx, xx
    398 
    399  // _mm_move_sd is 1 cycle method of getting the blending we want.
    400  rectPacked = _mm_castpd_si128(
    401      _mm_move_sd(_mm_castsi128_pd(rectPacked),
    402                  _mm_castsi128_pd(tmp)));  // x, y, XMost(), YMost()
    403 
    404  topLeft = _mm_slli_si128(rectPacked, 8);          // 0, 0, r.x, r.y
    405  rectPacked = _mm_sub_epi32(rectPacked, topLeft);  // r.x, r.y, r.w, r.h
    406 
    407  // Avoid negative width/height due to overflow.
    408  __m128i mask = _mm_or_si128(_mm_cmpgt_epi32(rectPacked, _mm_setzero_si128()),
    409                              _mm_set_epi32(0, 0, 0xFFFFFFFF, 0xFFFFFFFF));
    410  // clang-format off
    411  // Mask will now contain [ 0xFFFFFFFF 0xFFFFFFFF (width <= 0 ? 0 : 0xFFFFFFFF) (height <= 0 ? 0 : 0xFFFFFFFF) ]
    412  // clang-format on
    413  rectPacked = _mm_and_si128(rectPacked, mask);
    414 
    415  _mm_storeu_si128((__m128i*)&rect, rectPacked);
    416 #else
    417  rect.SetNonEmptyBox(
    418      NSToIntFloor(NSAppUnitsToFloatPixels(x, float(aAppUnitsPerPixel)) *
    419                   aXScale),
    420      NSToIntFloor(NSAppUnitsToFloatPixels(y, float(aAppUnitsPerPixel)) *
    421                   aYScale),
    422      NSToIntCeil(NSAppUnitsToFloatPixels(XMost(), float(aAppUnitsPerPixel)) *
    423                  aXScale),
    424      NSToIntCeil(NSAppUnitsToFloatPixels(YMost(), float(aAppUnitsPerPixel)) *
    425                  aYScale));
    426 #endif
    427  return rect;
    428 }
    429 
    430 // scale the rect but round to largest contained rect
    431 inline mozilla::gfx::IntRect nsRect::ScaleToInsidePixels(
    432    float aXScale, float aYScale, nscoord aAppUnitsPerPixel) const {
    433  mozilla::gfx::IntRect rect;
    434  rect.SetNonEmptyBox(
    435      NSToIntCeil(NSAppUnitsToFloatPixels(x, float(aAppUnitsPerPixel)) *
    436                  aXScale),
    437      NSToIntCeil(NSAppUnitsToFloatPixels(y, float(aAppUnitsPerPixel)) *
    438                  aYScale),
    439      NSToIntFloor(NSAppUnitsToFloatPixels(XMost(), float(aAppUnitsPerPixel)) *
    440                   aXScale),
    441      NSToIntFloor(NSAppUnitsToFloatPixels(YMost(), float(aAppUnitsPerPixel)) *
    442                   aYScale));
    443  return rect;
    444 }
    445 
    446 inline mozilla::gfx::IntRect nsRect::ToNearestPixels(
    447    nscoord aAppUnitsPerPixel) const {
    448  return ScaleToNearestPixels(1.0f, 1.0f, aAppUnitsPerPixel);
    449 }
    450 
    451 inline mozilla::gfx::IntRect nsRect::ToOutsidePixels(
    452    nscoord aAppUnitsPerPixel) const {
    453  return ScaleToOutsidePixels(1.0f, 1.0f, aAppUnitsPerPixel);
    454 }
    455 
    456 inline mozilla::gfx::IntRect nsRect::ToInsidePixels(
    457    nscoord aAppUnitsPerPixel) const {
    458  return ScaleToInsidePixels(1.0f, 1.0f, aAppUnitsPerPixel);
    459 }
    460 
    461 inline nsRect nsRect::RemoveResolution(const float aResolution) const {
    462  MOZ_ASSERT(aResolution > 0.0f);
    463  nsRect rect;
    464  rect.MoveTo(NSToCoordRound(NSCoordToFloat(x) / aResolution),
    465              NSToCoordRound(NSCoordToFloat(y) / aResolution));
    466  // A 1x1 rect indicates we are just hit testing a point, so pass down a 1x1
    467  // rect as well instead of possibly rounding the width or height to zero.
    468  if (width == 1 && height == 1) {
    469    rect.SizeTo(1, 1);
    470  } else {
    471    rect.SizeTo(NSToCoordCeil(NSCoordToFloat(width) / aResolution),
    472                NSToCoordCeil(NSCoordToFloat(height) / aResolution));
    473  }
    474 
    475  return rect;
    476 }
    477 
    478 const mozilla::gfx::IntRect& GetMaxSizedIntRect();
    479 
    480 // app units are integer multiples of pixels, so no rounding needed
    481 template <class units>
    482 nsRect ToAppUnits(const mozilla::gfx::IntRectTyped<units>& aRect,
    483                  nscoord aAppUnitsPerPixel) {
    484  return nsRect(NSIntPixelsToAppUnits(aRect.X(), aAppUnitsPerPixel),
    485                NSIntPixelsToAppUnits(aRect.Y(), aAppUnitsPerPixel),
    486                NSIntPixelsToAppUnits(aRect.Width(), aAppUnitsPerPixel),
    487                NSIntPixelsToAppUnits(aRect.Height(), aAppUnitsPerPixel));
    488 }
    489 
    490 struct nsRectCornerRadii final
    491    : public mozilla::gfx::BaseRectCornerRadii<nscoord, nsSize, nsMargin> {
    492  using BaseRectCornerRadii::BaseRectCornerRadii;
    493 };
    494 
    495 #endif /* NSRECT_H */