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