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 */