From ecfd6db484077ae54478b74ce3ca27009b25d124 Mon Sep 17 00:00:00 2001 From: Jonathan Watt Date: Thu, 30 Oct 2014 09:34:09 +0000 Subject: [PATCH] Bug 1090494, part 1 - Add a RectCornerRadii struct to Moz2D's PathHelpers.h and add variants of AppendRoundedRectToPath and MakePathForRoundedRect that use it. r=mattwoodrow --- gfx/2d/PathHelpers.cpp | 32 ++++++-------- gfx/2d/PathHelpers.h | 99 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 110 insertions(+), 21 deletions(-) diff --git a/gfx/2d/PathHelpers.cpp b/gfx/2d/PathHelpers.cpp index 9f7e10713c82..500b0482a9c2 100644 --- a/gfx/2d/PathHelpers.cpp +++ b/gfx/2d/PathHelpers.cpp @@ -13,8 +13,7 @@ UserDataKey sDisablePixelSnapping; void AppendRoundedRectToPath(PathBuilder* aPathBuilder, const Rect& aRect, - // paren's needed due to operator precedence: - const Size(& aCornerRadii)[4], + const RectCornerRadii& aRadii, bool aDrawClockwise) { // For CW drawing, this looks like: @@ -106,14 +105,11 @@ AppendRoundedRectToPath(PathBuilder* aPathBuilder, Point pc, p0, p1, p2, p3; - // The indexes of the corners: - const int kTopLeft = 0, kTopRight = 1; - if (aDrawClockwise) { - aPathBuilder->MoveTo(Point(aRect.X() + aCornerRadii[kTopLeft].width, + aPathBuilder->MoveTo(Point(aRect.X() + aRadii[RectCorner::TopLeft].width, aRect.Y())); } else { - aPathBuilder->MoveTo(Point(aRect.X() + aRect.Width() - aCornerRadii[kTopRight].width, + aPathBuilder->MoveTo(Point(aRect.X() + aRect.Width() - aRadii[RectCorner::TopRight].width, aRect.Y())); } @@ -129,18 +125,18 @@ AppendRoundedRectToPath(PathBuilder* aPathBuilder, pc = cornerCoords[c]; - if (aCornerRadii[c].width > 0.0 && aCornerRadii[c].height > 0.0) { - p0.x = pc.x + cornerMults[i].a * aCornerRadii[c].width; - p0.y = pc.y + cornerMults[i].b * aCornerRadii[c].height; + if (aRadii[c].width > 0.0 && aRadii[c].height > 0.0) { + p0.x = pc.x + cornerMults[i].a * aRadii[c].width; + p0.y = pc.y + cornerMults[i].b * aRadii[c].height; - p3.x = pc.x + cornerMults[i3].a * aCornerRadii[c].width; - p3.y = pc.y + cornerMults[i3].b * aCornerRadii[c].height; + p3.x = pc.x + cornerMults[i3].a * aRadii[c].width; + p3.y = pc.y + cornerMults[i3].b * aRadii[c].height; - p1.x = p0.x + alpha * cornerMults[i2].a * aCornerRadii[c].width; - p1.y = p0.y + alpha * cornerMults[i2].b * aCornerRadii[c].height; + p1.x = p0.x + alpha * cornerMults[i2].a * aRadii[c].width; + p1.y = p0.y + alpha * cornerMults[i2].b * aRadii[c].height; - p2.x = p3.x - alpha * cornerMults[i3].a * aCornerRadii[c].width; - p2.y = p3.y - alpha * cornerMults[i3].b * aCornerRadii[c].height; + p2.x = p3.x - alpha * cornerMults[i3].a * aRadii[c].width; + p2.y = p3.y - alpha * cornerMults[i3].b * aRadii[c].height; aPathBuilder->LineTo(p0); aPathBuilder->BezierTo(p1, p2, p3); @@ -157,9 +153,9 @@ AppendEllipseToPath(PathBuilder* aPathBuilder, const Point& aCenter, const Size& aDimensions) { - Size halfDim = aDimensions / 2.0; + Size halfDim = aDimensions / 2.f; Rect rect(aCenter - Point(halfDim.width, halfDim.height), aDimensions); - Size radii[] = { halfDim, halfDim, halfDim, halfDim }; + RectCornerRadii radii(halfDim.width, halfDim.height); AppendRoundedRectToPath(aPathBuilder, rect, radii); } diff --git a/gfx/2d/PathHelpers.h b/gfx/2d/PathHelpers.h index 1fa9f8e95f0b..3a473b53c55a 100644 --- a/gfx/2d/PathHelpers.h +++ b/gfx/2d/PathHelpers.h @@ -8,6 +8,7 @@ #include "2D.h" #include "mozilla/Constants.h" +#include "mozilla/TypedEnum.h" #include "UserData.h" namespace mozilla { @@ -129,6 +130,80 @@ void EllipseToBezier(T* aSink, const Point &aOrigin, const Size &aRadius) } } +// We can't use MOZ_BEGIN_ENUM_CLASS here because that prevents the enum +// values from being used for indexing. Wrapping the enum in a struct does at +// least gives us name scoping. +struct RectCorner { + enum { + // This order is important since AppendRoundedRectToPath and other code + // depends on it! + TopLeft = 0, + TopRight = 1, + BottomRight = 2, + BottomLeft = 3, + Count = 4 + }; +}; + +struct RectCornerRadii { + Size radii[RectCorner::Count]; + + RectCornerRadii() {} + + explicit RectCornerRadii(Float radius) { + for (int i = 0; i < RectCorner::Count; i++) { + radii[i].SizeTo(radius, radius); + } + } + + explicit RectCornerRadii(Float radiusX, Float radiusY) { + for (int i = 0; i < RectCorner::Count; i++) { + radii[i].SizeTo(radiusX, radiusY); + } + } + + RectCornerRadii(Float tl, Float tr, Float br, Float bl) { + radii[RectCorner::TopLeft].SizeTo(tl, tl); + radii[RectCorner::TopRight].SizeTo(tr, tr); + radii[RectCorner::BottomRight].SizeTo(br, br); + radii[RectCorner::BottomLeft].SizeTo(bl, bl); + } + + RectCornerRadii(const Size& tl, const Size& tr, + const Size& br, const Size& bl) { + radii[RectCorner::TopLeft] = tl; + radii[RectCorner::TopRight] = tr; + radii[RectCorner::BottomRight] = br; + radii[RectCorner::BottomLeft] = bl; + } + + const Size& operator[](size_t aCorner) const { + return radii[aCorner]; + } + + Size& operator[](size_t aCorner) { + return radii[aCorner]; + } + + void Scale(Float aXScale, Float aYScale) { + for (int i = 0; i < RectCorner::Count; i++) { + radii[i].Scale(aXScale, aYScale); + } + } + + const Size TopLeft() const { return radii[RectCorner::TopLeft]; } + Size& TopLeft() { return radii[RectCorner::TopLeft]; } + + const Size TopRight() const { return radii[RectCorner::TopRight]; } + Size& TopRight() { return radii[RectCorner::TopRight]; } + + const Size BottomRight() const { return radii[RectCorner::BottomRight]; } + Size& BottomRight() { return radii[RectCorner::BottomRight]; } + + const Size BottomLeft() const { return radii[RectCorner::BottomLeft]; } + Size& BottomLeft() { return radii[RectCorner::BottomLeft]; } +}; + /** * Appends a path represending a rounded rectangle to the path being built by * aPathBuilder. @@ -143,19 +218,37 @@ void EllipseToBezier(T* aSink, const Point &aOrigin, const Size &aRadius) */ GFX2D_API void AppendRoundedRectToPath(PathBuilder* aPathBuilder, const Rect& aRect, - const Size(& aCornerRadii)[4], + const RectCornerRadii& aRadii, bool aDrawClockwise = true); inline TemporaryRef MakePathForRoundedRect(const DrawTarget& aDrawTarget, const Rect& aRect, - const Size(& aCornerRadii)[4], + const RectCornerRadii& aRadii, bool aDrawClockwise = true) { RefPtr builder = aDrawTarget.CreatePathBuilder(); - AppendRoundedRectToPath(builder, aRect, aCornerRadii, aDrawClockwise); + AppendRoundedRectToPath(builder, aRect, aRadii, aDrawClockwise); return builder->Finish(); } +inline void AppendRoundedRectToPath(PathBuilder* aPathBuilder, + const Rect& aRect, + const Size(& aCornerRadii)[4], + bool aDrawClockwise = true) { + RectCornerRadii radii(aCornerRadii[0], aCornerRadii[1], + aCornerRadii[2], aCornerRadii[3]); + AppendRoundedRectToPath(aPathBuilder, aRect, radii, aDrawClockwise); +} + +inline TemporaryRef MakePathForRoundedRect(const DrawTarget& aDrawTarget, + const Rect& aRect, + const Size(& aCornerRadii)[4], + bool aDrawClockwise = true) { + RectCornerRadii radii(aCornerRadii[0], aCornerRadii[1], + aCornerRadii[2], aCornerRadii[3]); + return MakePathForRoundedRect(aDrawTarget, aRect, radii, aDrawClockwise); +} + /** * Appends a path represending an ellipse to the path being built by * aPathBuilder.