Bug 910138 - clean-up of arc math. r=me
authorLee Salzman <lsalzman@mozilla.com>
Sat, 19 Mar 2016 00:29:13 -0400
changeset 289451 f38b9ee425e11e8db9aa74ec4c901efe70464e0b
parent 289450 5bee898930bc8a69bcfba2e9cd7da8380f1c5434
child 289452 c41ffc5b9b3cdd1723fa0f852c19e0e797e62a91
push id30102
push userryanvm@gmail.com
push dateSat, 19 Mar 2016 15:23:17 +0000
treeherdermozilla-central@720fb3d55e28 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersme
bugs910138
milestone48.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
Bug 910138 - clean-up of arc math. r=me
gfx/2d/PathHelpers.h
--- a/gfx/2d/PathHelpers.h
+++ b/gfx/2d/PathHelpers.h
@@ -26,56 +26,48 @@ inline Float ComputeKappaFactor(Float aA
 }
 
 /**
  * Draws a partial arc <= 90 degrees given exact start and end points.
  * Assumes that it is continuing from an already specified start point.
  */
 template <typename T>
 inline void PartialArcToBezier(T* aSink,
-                               const Size& aRadius,
-                               const Point& aStartPoint, const Point& aEndPoint,
                                const Point& aStartOffset, const Point& aEndOffset,
-                               Float aKappaFactor = kKappaFactor,
-                               const Matrix& aTransform = Matrix())
+                               const Matrix& aTransform,
+                               Float aKappaFactor = kKappaFactor)
 {
-  Float kappaX = aKappaFactor * aRadius.width;
-  Float kappaY = aKappaFactor * aRadius.height;
-
   Point cp1 =
-    aStartPoint + Point(-aStartOffset.y * kappaX, aStartOffset.x * kappaY);
+    aStartOffset + Point(-aStartOffset.y, aStartOffset.x) * aKappaFactor;
 
   Point cp2 =
-    aEndPoint + Point(aEndOffset.y * kappaX, -aEndOffset.x * kappaY);
+    aEndOffset + Point(aEndOffset.y, -aEndOffset.x) * aKappaFactor;
 
-  aSink->BezierTo(aTransform * cp1, aTransform * cp2, aTransform * aEndPoint);
+  aSink->BezierTo(aTransform * cp1, aTransform * cp2, aTransform * aEndOffset);
 }
 
 /**
  * Draws an acute arc (<= 90 degrees) given exact start and end points.
  * Specialized version avoiding kappa calculation.
  */
 template <typename T>
 inline void AcuteArcToBezier(T* aSink,
                              const Point& aOrigin, const Size& aRadius,
                              const Point& aStartPoint, const Point& aEndPoint,
                              Float aKappaFactor = kKappaFactor)
 {
   aSink->LineTo(aStartPoint);
   if (!aRadius.IsEmpty()) {
+    Float kappaX = aKappaFactor * aRadius.width / aRadius.height;
+    Float kappaY = aKappaFactor * aRadius.height / aRadius.width;
     Point startOffset = aStartPoint - aOrigin;
-    startOffset.x /= aRadius.width;
-    startOffset.y /= aRadius.height;
     Point endOffset = aEndPoint - aOrigin;
-    endOffset.x /= aRadius.width;
-    endOffset.y /= aRadius.height;
-    PartialArcToBezier(aSink, aRadius,
-                       aStartPoint, aEndPoint,
-                       startOffset, endOffset,
-                       aKappaFactor);
+    aSink->BezierTo(aStartPoint + Point(-startOffset.y * kappaX, startOffset.x * kappaY),
+                    aEndPoint + Point(endOffset.y * kappaX, -endOffset.x * kappaY),
+                    aEndPoint);
   } else if (aEndPoint != aStartPoint) {
     aSink->LineTo(aEndPoint);
   }
 }
 
 /**
  * Draws an acute arc (<= 90 degrees) given exact start and end points.
  */
@@ -108,70 +100,60 @@ void ArcToBezier(T* aSink, const Point &
     aStartAngle = aEndAngle - arcSweepLeft * sweepDirection;
   } else if (arcSweepLeft > Float(2.0f * M_PI)) {
     // Sweeping more than 2 * pi is a full circle.
     arcSweepLeft = Float(2.0f * M_PI);
   }
 
   Float currentStartAngle = aStartAngle;
   Point currentStartOffset(cosf(aStartAngle), sinf(aStartAngle));
-  Point currentStartPoint(currentStartOffset.x * aRadius.width,
-                          currentStartOffset.y * aRadius.height);
-  Matrix transform(cosf(aRotation), sinf(aRotation), -sinf(aRotation), cosf(aRotation), aOrigin.x, aOrigin.y);
-  aSink->LineTo(transform * currentStartPoint);
+  Matrix transform = Matrix::Scaling(aRadius.width, aRadius.height);
+  if (aRotation != 0.0f) {
+    transform *= Matrix::Rotation(aRotation);
+  }
+  transform.PostTranslate(aOrigin);
+  aSink->LineTo(transform * currentStartOffset);
 
   while (arcSweepLeft > 0) {
     Float currentEndAngle =
       currentStartAngle + std::min(arcSweepLeft, Float(M_PI / 2.0f)) * sweepDirection;
-
     Point currentEndOffset(cosf(currentEndAngle), sinf(currentEndAngle));
-    Point currentEndPoint(currentEndOffset.x * aRadius.width,
-                          currentEndOffset.y * aRadius.height);
 
-    PartialArcToBezier(aSink, aRadius,
-                       currentStartPoint, currentEndPoint,
-                       currentStartOffset, currentEndOffset,
-                       ComputeKappaFactor(currentEndAngle - currentStartAngle),
-                       transform);
+    PartialArcToBezier(aSink, currentStartOffset, currentEndOffset, transform,
+                       ComputeKappaFactor(currentEndAngle - currentStartAngle));
 
     // We guarantee here the current point is the start point of the next
     // curve segment.
     arcSweepLeft -= Float(M_PI / 2.0f);
     currentStartAngle = currentEndAngle;
     currentStartOffset = currentEndOffset;
-    currentStartPoint = currentEndPoint;
   }
 }
 
 /* This is basically the ArcToBezier with the parameters for drawing a circle
  * inlined which vastly simplifies it and avoids a bunch of transcedental function
  * calls which should make it faster. */
 template <typename T>
 void EllipseToBezier(T* aSink, const Point &aOrigin, const Size &aRadius)
 {
+  Matrix transform(aRadius.width, 0, 0, aRadius.height, aOrigin.x, aOrigin.y);
   Point currentStartOffset(1, 0);
-  Point currentStartPoint(aOrigin.x + aRadius.width, aOrigin.y);
 
-  aSink->LineTo(currentStartPoint);
+  aSink->LineTo(transform * currentStartOffset);
 
   for (int i = 0; i < 4; i++) {
     // cos(x+pi/2) == -sin(x)
     // sin(x+pi/2) == cos(x)
     Point currentEndOffset(-currentStartOffset.y, currentStartOffset.x);
-    Point currentEndPoint(aOrigin.x + currentEndOffset.x * aRadius.width,
-                          aOrigin.y + currentEndOffset.y * aRadius.height);
 
-    PartialArcToBezier(aSink, aRadius,
-                       currentStartPoint, currentEndPoint,
-                       currentStartOffset, currentEndOffset);
+    PartialArcToBezier(aSink, currentStartOffset, currentEndOffset, transform);
 
     // We guarantee here the current point is the start point of the next
     // curve segment.
     currentStartOffset = currentEndOffset;
-    currentStartPoint = currentEndPoint;
   }
 }
 
 /**
  * Appends a path represending a rectangle to the path being built by
  * aPathBuilder.
  *
  * aRect           The rectangle to append.