Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / gpu / GrPathUtils.cpp
index d412b8c..5fead5d 100644 (file)
@@ -34,9 +34,9 @@ SkScalar GrPathUtils::scaleToleranceToSrc(SkScalar devTol,
 }
 
 static const int MAX_POINTS_PER_CURVE = 1 << 10;
-static const SkScalar gMinCurveTol = SkFloatToScalar(0.0001f);
+static const SkScalar gMinCurveTol = 0.0001f;
 
-uint32_t GrPathUtils::quadraticPointCount(const GrPoint points[],
+uint32_t GrPathUtils::quadraticPointCount(const SkPoint points[],
                                           SkScalar tol) {
     if (tol < gMinCurveTol) {
         tol = gMinCurveTol;
@@ -51,7 +51,7 @@ uint32_t GrPathUtils::quadraticPointCount(const GrPoint points[],
         // subdivide x = log4(d/tol) times. x subdivisions creates 2^(x)
         // points.
         // 2^(log4(x)) = sqrt(x);
-        int temp = SkScalarCeil(SkScalarSqrt(SkScalarDiv(d, tol)));
+        int temp = SkScalarCeilToInt(SkScalarSqrt(SkScalarDiv(d, tol)));
         int pow2 = GrNextPow2(temp);
         // Because of NaNs & INFs we can wind up with a degenerate temp
         // such that pow2 comes out negative. Also, our point generator
@@ -59,15 +59,15 @@ uint32_t GrPathUtils::quadraticPointCount(const GrPoint points[],
         if (pow2 < 1) {
             pow2 = 1;
         }
-        return GrMin(pow2, MAX_POINTS_PER_CURVE);
+        return SkTMin(pow2, MAX_POINTS_PER_CURVE);
     }
 }
 
-uint32_t GrPathUtils::generateQuadraticPoints(const GrPoint& p0,
-                                              const GrPoint& p1,
-                                              const GrPoint& p2,
+uint32_t GrPathUtils::generateQuadraticPoints(const SkPoint& p0,
+                                              const SkPoint& p1,
+                                              const SkPoint& p2,
                                               SkScalar tolSqd,
-                                              GrPoint** points,
+                                              SkPoint** points,
                                               uint32_t pointsLeft) {
     if (pointsLeft < 2 ||
         (p1.distanceToLineSegmentBetweenSqd(p0, p2)) < tolSqd) {
@@ -76,11 +76,11 @@ uint32_t GrPathUtils::generateQuadraticPoints(const GrPoint& p0,
         return 1;
     }
 
-    GrPoint q[] = {
+    SkPoint q[] = {
         { SkScalarAve(p0.fX, p1.fX), SkScalarAve(p0.fY, p1.fY) },
         { SkScalarAve(p1.fX, p2.fX), SkScalarAve(p1.fY, p2.fY) },
     };
-    GrPoint r = { SkScalarAve(q[0].fX, q[1].fX), SkScalarAve(q[0].fY, q[1].fY) };
+    SkPoint r = { SkScalarAve(q[0].fX, q[1].fX), SkScalarAve(q[0].fY, q[1].fY) };
 
     pointsLeft >>= 1;
     uint32_t a = generateQuadraticPoints(p0, q[0], r, tolSqd, points, pointsLeft);
@@ -88,21 +88,21 @@ uint32_t GrPathUtils::generateQuadraticPoints(const GrPoint& p0,
     return a + b;
 }
 
-uint32_t GrPathUtils::cubicPointCount(const GrPoint points[],
+uint32_t GrPathUtils::cubicPointCount(const SkPoint points[],
                                            SkScalar tol) {
     if (tol < gMinCurveTol) {
         tol = gMinCurveTol;
     }
     SkASSERT(tol > 0);
 
-    SkScalar d = GrMax(
+    SkScalar d = SkTMax(
         points[1].distanceToLineSegmentBetweenSqd(points[0], points[3]),
         points[2].distanceToLineSegmentBetweenSqd(points[0], points[3]));
     d = SkScalarSqrt(d);
     if (d <= tol) {
         return 1;
     } else {
-        int temp = SkScalarCeil(SkScalarSqrt(SkScalarDiv(d, tol)));
+        int temp = SkScalarCeilToInt(SkScalarSqrt(SkScalarDiv(d, tol)));
         int pow2 = GrNextPow2(temp);
         // Because of NaNs & INFs we can wind up with a degenerate temp
         // such that pow2 comes out negative. Also, our point generator
@@ -110,16 +110,16 @@ uint32_t GrPathUtils::cubicPointCount(const GrPoint points[],
         if (pow2 < 1) {
             pow2 = 1;
         }
-        return GrMin(pow2, MAX_POINTS_PER_CURVE);
+        return SkTMin(pow2, MAX_POINTS_PER_CURVE);
     }
 }
 
-uint32_t GrPathUtils::generateCubicPoints(const GrPoint& p0,
-                                          const GrPoint& p1,
-                                          const GrPoint& p2,
-                                          const GrPoint& p3,
+uint32_t GrPathUtils::generateCubicPoints(const SkPoint& p0,
+                                          const SkPoint& p1,
+                                          const SkPoint& p2,
+                                          const SkPoint& p3,
                                           SkScalar tolSqd,
-                                          GrPoint** points,
+                                          SkPoint** points,
                                           uint32_t pointsLeft) {
     if (pointsLeft < 2 ||
         (p1.distanceToLineSegmentBetweenSqd(p0, p3) < tolSqd &&
@@ -128,16 +128,16 @@ uint32_t GrPathUtils::generateCubicPoints(const GrPoint& p0,
             *points += 1;
             return 1;
         }
-    GrPoint q[] = {
+    SkPoint q[] = {
         { SkScalarAve(p0.fX, p1.fX), SkScalarAve(p0.fY, p1.fY) },
         { SkScalarAve(p1.fX, p2.fX), SkScalarAve(p1.fY, p2.fY) },
         { SkScalarAve(p2.fX, p3.fX), SkScalarAve(p2.fY, p3.fY) }
     };
-    GrPoint r[] = {
+    SkPoint r[] = {
         { SkScalarAve(q[0].fX, q[1].fX), SkScalarAve(q[0].fY, q[1].fY) },
         { SkScalarAve(q[1].fX, q[2].fX), SkScalarAve(q[1].fY, q[2].fY) }
     };
-    GrPoint s = { SkScalarAve(r[0].fX, r[1].fX), SkScalarAve(r[0].fY, r[1].fY) };
+    SkPoint s = { SkScalarAve(r[0].fX, r[1].fX), SkScalarAve(r[0].fY, r[1].fY) };
     pointsLeft >>= 1;
     uint32_t a = generateCubicPoints(p0, q[0], r[0], s, tolSqd, points, pointsLeft);
     uint32_t b = generateCubicPoints(s, r[1], q[2], p3, tolSqd, points, pointsLeft);
@@ -159,7 +159,7 @@ int GrPathUtils::worstCasePointCount(const SkPath& path, int* subpaths,
     SkPath::Iter iter(path, false);
     SkPath::Verb verb;
 
-    GrPoint pts[4];
+    SkPoint pts[4];
     while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
 
         switch (verb) {
@@ -186,29 +186,29 @@ int GrPathUtils::worstCasePointCount(const SkPath& path, int* subpaths,
     return pointCount;
 }
 
-void GrPathUtils::QuadUVMatrix::set(const GrPoint qPts[3]) {
-    // can't make this static, no cons :(
-    SkMatrix UVpts;
-#ifndef SK_SCALAR_IS_FLOAT
-    GrCrash("Expected scalar is float.");
-#endif
+void GrPathUtils::QuadUVMatrix::set(const SkPoint qPts[3]) {
     SkMatrix m;
     // We want M such that M * xy_pt = uv_pt
     // We know M * control_pts = [0  1/2 1]
     //                           [0  0   1]
     //                           [1  1   1]
+    // And control_pts = [x0 x1 x2]
+    //                   [y0 y1 y2]
+    //                   [1  1  1 ]
     // We invert the control pt matrix and post concat to both sides to get M.
-    UVpts.setAll(0,   SK_ScalarHalf,  SK_Scalar1,
-                 0,               0,  SK_Scalar1,
-                 SkScalarToPersp(SK_Scalar1),
-                 SkScalarToPersp(SK_Scalar1),
-                 SkScalarToPersp(SK_Scalar1));
-    m.setAll(qPts[0].fX, qPts[1].fX, qPts[2].fX,
-             qPts[0].fY, qPts[1].fY, qPts[2].fY,
-             SkScalarToPersp(SK_Scalar1),
-             SkScalarToPersp(SK_Scalar1),
-             SkScalarToPersp(SK_Scalar1));
-    if (!m.invert(&m)) {
+    // Using the known form of the control point matrix and the result, we can
+    // optimize and improve precision.
+
+    double x0 = qPts[0].fX;
+    double y0 = qPts[0].fY;
+    double x1 = qPts[1].fX;
+    double y1 = qPts[1].fY;
+    double x2 = qPts[2].fX;
+    double y2 = qPts[2].fY;
+    double det = x0*y1 - y0*x1 + x2*y0 - y2*x0 + x1*y2 - y1*x2;
+
+    if (!sk_float_isfinite(det)
+        || SkScalarNearlyZero((float)det, SK_ScalarNearlyZero * SK_ScalarNearlyZero)) {
         // The quad is degenerate. Hopefully this is rare. Find the pts that are
         // farthest apart to compute a line (unless it is really a pt).
         SkScalar maxD = qPts[0].distanceToSqd(qPts[1]);
@@ -226,11 +226,11 @@ void GrPathUtils::QuadUVMatrix::set(const GrPoint qPts[3]) {
         // We could have a tolerance here, not sure if it would improve anything
         if (maxD > 0) {
             // Set the matrix to give (u = 0, v = distance_to_line)
-            GrVec lineVec = qPts[(maxEdge + 1)%3] - qPts[maxEdge];
+            SkVector lineVec = qPts[(maxEdge + 1)%3] - qPts[maxEdge];
             // when looking from the point 0 down the line we want positive
             // distances to be to the left. This matches the non-degenerate
             // case.
-            lineVec.setOrthog(lineVec, GrPoint::kLeft_Side);
+            lineVec.setOrthog(lineVec, SkPoint::kLeft_Side);
             lineVec.dot(qPts[0]);
             // first row
             fM[0] = 0;
@@ -247,10 +247,38 @@ void GrPathUtils::QuadUVMatrix::set(const GrPoint qPts[3]) {
             fM[3] = 0; fM[4] = 0; fM[5] = 100.f;
         }
     } else {
-        m.postConcat(UVpts);
+        double scale = 1.0/det;
+
+        // compute adjugate matrix
+        double a0, a1, a2, a3, a4, a5, a6, a7, a8;
+        a0 = y1-y2;
+        a1 = x2-x1;
+        a2 = x1*y2-x2*y1;
+
+        a3 = y2-y0;
+        a4 = x0-x2;
+        a5 = x2*y0-x0*y2;
+
+        a6 = y0-y1;
+        a7 = x1-x0;
+        a8 = x0*y1-x1*y0;
+
+        // this performs the uv_pts*adjugate(control_pts) multiply,
+        // then does the scale by 1/det afterwards to improve precision
+        m[SkMatrix::kMScaleX] = (float)((0.5*a3 + a6)*scale);
+        m[SkMatrix::kMSkewX]  = (float)((0.5*a4 + a7)*scale);
+        m[SkMatrix::kMTransX] = (float)((0.5*a5 + a8)*scale);
+
+        m[SkMatrix::kMSkewY]  = (float)(a6*scale);
+        m[SkMatrix::kMScaleY] = (float)(a7*scale);
+        m[SkMatrix::kMTransY] = (float)(a8*scale);
+
+        m[SkMatrix::kMPersp0] = (float)((a0 + a3 + a6)*scale);
+        m[SkMatrix::kMPersp1] = (float)((a1 + a4 + a7)*scale);
+        m[SkMatrix::kMPersp2] = (float)((a2 + a5 + a8)*scale);
 
         // The matrix should not have perspective.
-        SkDEBUGCODE(static const SkScalar gTOL = SkFloatToScalar(1.f / 100.f));
+        SkDEBUGCODE(static const SkScalar gTOL = 1.f / 100.f);
         SkASSERT(SkScalarAbs(m.get(SkMatrix::kMPersp0)) < gTOL);
         SkASSERT(SkScalarAbs(m.get(SkMatrix::kMPersp1)) < gTOL);
 
@@ -491,7 +519,7 @@ void convert_noninflect_cubic_to_quads(const SkPoint p[4],
 }
 }
 
-void GrPathUtils::convertCubicToQuads(const GrPoint p[4],
+void GrPathUtils::convertCubicToQuads(const SkPoint p[4],
                                       SkScalar tolScale,
                                       bool constrainWithinTangents,
                                       SkPath::Direction dir,