author | Jonathan Watt <jwatt@jwatt.org> |
Thu, 30 Oct 2014 09:34:09 +0000 | |
changeset 213072 | 8fff7a04f3221954330139121bb9b3a7513724a6 |
parent 213071 | 32a7f74c5c10f0c53ca47b4a73fe4d61fbcafd04 |
child 213073 | 71cf4fde05c6bc27ca61d541d7419e9bf27e6789 |
push id | 27738 |
push user | cbook@mozilla.com |
push date | Thu, 30 Oct 2014 13:46:07 +0000 |
treeherder | mozilla-central@1aa1b23d799e [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | mattwoodrow |
bugs | 1090494 |
milestone | 36.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
gfx/2d/PathHelpers.cpp | file | annotate | diff | comparison | revisions | |
gfx/2d/PathHelpers.h | file | annotate | diff | comparison | revisions |
--- a/gfx/2d/PathHelpers.cpp +++ b/gfx/2d/PathHelpers.cpp @@ -8,18 +8,17 @@ namespace mozilla { namespace gfx { 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: // // ...******0** 1 C // **** // *** 2 // ** @@ -101,70 +100,67 @@ AppendRoundedRectToPath(PathBuilder* aPa twoFloats *cornerMults = aDrawClockwise ? cwCornerMults : ccwCornerMults; Point cornerCoords[] = { aRect.TopLeft(), aRect.TopRight(), aRect.BottomRight(), aRect.BottomLeft() }; 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())); } for (int i = 0; i < 4; ++i) { // the corner index -- either 1 2 3 0 (cw) or 0 3 2 1 (ccw) int c = aDrawClockwise ? ((i+1) % 4) : ((4-i) % 4); // i+2 and i+3 respectively. These are used to index into the corner // multiplier table, and were deduced by calculating out the long form // of each corner and finding a pattern in the signs and values. int i2 = (i+2) % 4; int i3 = (i+3) % 4; 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); } else { aPathBuilder->LineTo(pc); } } aPathBuilder->Close(); } void 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); } bool SnapLineToDevicePixelsForStroking(Point& aP1, Point& aP2, const DrawTarget& aDrawTarget) {
--- a/gfx/2d/PathHelpers.h +++ b/gfx/2d/PathHelpers.h @@ -3,16 +3,17 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef MOZILLA_GFX_PATHHELPERS_H_ #define MOZILLA_GFX_PATHHELPERS_H_ #include "2D.h" #include "mozilla/Constants.h" +#include "mozilla/TypedEnum.h" #include "UserData.h" namespace mozilla { namespace gfx { template <typename T> void ArcToBezier(T* aSink, const Point &aOrigin, const Size &aRadius, float aStartAngle, float aEndAngle, bool aAntiClockwise) @@ -124,41 +125,133 @@ void EllipseToBezier(T* aSink, const Poi // cos(x+pi/2) == -sin(x) // sin(x+pi/2) == cos(x) Float tmp = cosStartAngle; cosStartAngle = -sinStartAngle; sinStartAngle = tmp; } } +// 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. * * aRect The rectangle to append. * aCornerRadii Contains the radii of the top-left, top-right, bottom-right * and bottom-left corners, in that order. * aDrawClockwise If set to true, the path will start at the left of the top * left edge and draw clockwise. If set to false the path will * start at the right of the top left edge and draw counter- * clockwise. */ GFX2D_API void AppendRoundedRectToPath(PathBuilder* aPathBuilder, const Rect& aRect, - const Size(& aCornerRadii)[4], + const RectCornerRadii& aRadii, bool aDrawClockwise = true); inline TemporaryRef<Path> MakePathForRoundedRect(const DrawTarget& aDrawTarget, const Rect& aRect, + const RectCornerRadii& aRadii, + bool aDrawClockwise = true) +{ + RefPtr<PathBuilder> builder = aDrawTarget.CreatePathBuilder(); + 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<Path> MakePathForRoundedRect(const DrawTarget& aDrawTarget, + const Rect& aRect, const Size(& aCornerRadii)[4], - bool aDrawClockwise = true) -{ - RefPtr<PathBuilder> builder = aDrawTarget.CreatePathBuilder(); - AppendRoundedRectToPath(builder, aRect, aCornerRadii, aDrawClockwise); - return builder->Finish(); + 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. * * The ellipse extends aDimensions.width / 2.0 in the horizontal direction * from aCenter, and aDimensions.height / 2.0 in the vertical direction.