convert mapHomogeneousPoints to SkPoint3

SkMatrix::mapHomogeneousPoints takes an array of SkScalar,
but expects essentially SkPoint3, so make it so.


R: robertphillips@google.com, reed@google.com
Bug: skia:6898
Change-Id: Ibaf8b05c08b7df16c67d6a77d914667ace9a70da
Reviewed-on: https://skia-review.googlesource.com/58380
Commit-Queue: Cary Clark <caryclark@skia.org>
Commit-Queue: Cary Clark <caryclark@google.com>
Reviewed-by: Mike Reed <reed@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
diff --git a/gm/beziereffects.cpp b/gm/beziereffects.cpp
index bf53aa2..045f3fe 100644
--- a/gm/beziereffects.cpp
+++ b/gm/beziereffects.cpp
@@ -18,6 +18,7 @@
 #include "GrTest.h"
 #include "SkColorPriv.h"
 #include "SkGeometry.h"
+#include "SkPoint3.h"
 #include "effects/GrBezierEffect.h"
 #include "ops/GrMeshDrawOp.h"
 
@@ -270,8 +271,8 @@
         verts[0].fPosition.setRectTriStrip(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom,
                                            sizeof(Vertex));
         for (int v = 0; v < 4; ++v) {
-            SkScalar pt3[3] = {verts[v].fPosition.x(), verts[v].fPosition.y(), 1.f};
-            fKLM.mapHomogeneousPoints(verts[v].fKLM, pt3, 1);
+            SkPoint3 pt3 = {verts[v].fPosition.x(), verts[v].fPosition.y(), 1.f};
+            fKLM.mapHomogeneousPoints((SkPoint3* ) verts[v].fKLM, &pt3, 1);
         }
         helper.recordDraw(target, this->gp(), this->makePipeline(target));
     }
diff --git a/include/core/SkMatrix.h b/include/core/SkMatrix.h
index 2774737..7e45911 100644
--- a/include/core/SkMatrix.h
+++ b/include/core/SkMatrix.h
@@ -13,6 +13,7 @@
 #include "SkRect.h"
 
 struct SkRSXform;
+struct SkPoint3;
 class SkString;
 
 /** \class SkMatrix
@@ -475,13 +476,13 @@
         and write the transformed points into the array of scalars specified by dst.
         dst[] = M * src[]
         @param dst  Where the transformed coordinates are written. It must
-                    contain at least 3 * count entries
+                    contain at least count entries
         @param src  The original coordinates that are to be transformed. It
-                    must contain at least 3 * count entries
-        @param count The number of triples (homogeneous points) in src to read,
+                    must contain at least count entries
+        @param count The number of homogeneous points in src to read,
                      and then transform into dst.
     */
-    void mapHomogeneousPoints(SkScalar dst[], const SkScalar src[], int count) const;
+    void mapHomogeneousPoints(SkPoint3 dst[], const SkPoint3 src[], int count) const;
 
     void mapXY(SkScalar x, SkScalar y, SkPoint* result) const {
         SkASSERT(result);
diff --git a/include/core/SkPoint3.h b/include/core/SkPoint3.h
index 6f69f1c..d4a2023 100644
--- a/include/core/SkPoint3.h
+++ b/include/core/SkPoint3.h
@@ -8,7 +8,7 @@
 #ifndef SkPoint3_DEFINED
 #define SkPoint3_DEFINED
 
-#include "SkScalar.h"
+#include "SkPoint.h"
 
 struct SK_API SkPoint3 {
     SkScalar fX, fY, fZ;
diff --git a/src/core/SkGeometry.cpp b/src/core/SkGeometry.cpp
index 0b3eeda..6a5207b 100644
--- a/src/core/SkGeometry.cpp
+++ b/src/core/SkGeometry.cpp
@@ -8,6 +8,7 @@
 #include "SkGeometry.h"
 #include "SkMatrix.h"
 #include "SkNx.h"
+#include "SkPoint3.h"
 
 static SkVector to_vector(const Sk2s& x) {
     SkVector vector;
@@ -974,18 +975,6 @@
     return false;
 }
 
-struct SkP3D {
-    SkScalar fX, fY, fZ;
-
-    void set(SkScalar x, SkScalar y, SkScalar z) {
-        fX = x; fY = y; fZ = z;
-    }
-
-    void projectDown(SkPoint* dst) const {
-        dst->set(fX / fZ, fY / fZ);
-    }
-};
-
 // We only interpolate one dimension at a time (the first, at +0, +3, +6).
 static void p3d_interp(const SkScalar src[7], SkScalar dst[7], SkScalar t) {
     SkScalar ab = SkScalarInterp(src[0], src[3], t);
@@ -995,15 +984,19 @@
     dst[6] = bc;
 }
 
-static void ratquad_mapTo3D(const SkPoint src[3], SkScalar w, SkP3D dst[]) {
+static void ratquad_mapTo3D(const SkPoint src[3], SkScalar w, SkPoint3 dst[3]) {
     dst[0].set(src[0].fX * 1, src[0].fY * 1, 1);
     dst[1].set(src[1].fX * w, src[1].fY * w, w);
     dst[2].set(src[2].fX * 1, src[2].fY * 1, 1);
 }
 
+static SkPoint project_down(const SkPoint3& src) {
+    return {src.fX / src.fZ, src.fY / src.fZ};
+}
+
 // return false if infinity or NaN is generated; caller must check
 bool SkConic::chopAt(SkScalar t, SkConic dst[2]) const {
-    SkP3D tmp[3], tmp2[3];
+    SkPoint3 tmp[3], tmp2[3];
 
     ratquad_mapTo3D(fPts, fW, tmp);
 
@@ -1012,9 +1005,9 @@
     p3d_interp(&tmp[0].fZ, &tmp2[0].fZ, t);
 
     dst[0].fPts[0] = fPts[0];
-    tmp2[0].projectDown(&dst[0].fPts[1]);
-    tmp2[1].projectDown(&dst[0].fPts[2]); dst[1].fPts[0] = dst[0].fPts[2];
-    tmp2[2].projectDown(&dst[1].fPts[1]);
+    dst[0].fPts[1] = project_down(tmp2[0]);
+    dst[0].fPts[2] = project_down(tmp2[1]); dst[1].fPts[0] = dst[0].fPts[2];
+    dst[1].fPts[1] = project_down(tmp2[2]);
     dst[1].fPts[2] = fPts[2];
 
     // to put in "standard form", where w0 and w2 are both 1, we compute the
@@ -1341,11 +1334,11 @@
         return w;
     }
 
-    SkP3D src[3], dst[3];
+    SkPoint3 src[3], dst[3];
 
     ratquad_mapTo3D(pts, w, src);
 
-    matrix.mapHomogeneousPoints(&dst[0].fX, &src[0].fX, 3);
+    matrix.mapHomogeneousPoints(dst, src, 3);
 
     // w' = sqrt(w1*w1/w0*w2)
     SkScalar w0 = dst[0].fZ;
diff --git a/src/core/SkMatrix.cpp b/src/core/SkMatrix.cpp
index 5b1be84..89bde4b 100644
--- a/src/core/SkMatrix.cpp
+++ b/src/core/SkMatrix.cpp
@@ -9,6 +9,7 @@
 #include "SkMatrix.h"
 #include "SkNx.h"
 #include "SkPaint.h"
+#include "SkPoint3.h"
 #include "SkRSXform.h"
 #include "SkString.h"
 #include <stddef.h>
@@ -1036,30 +1037,28 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-void SkMatrix::mapHomogeneousPoints(SkScalar dst[], const SkScalar src[], int count) const {
+void SkMatrix::mapHomogeneousPoints(SkPoint3 dst[], const SkPoint3 src[], int count) const {
     SkASSERT((dst && src && count > 0) || 0 == count);
     // no partial overlap
-    SkASSERT(src == dst || &dst[3*count] <= &src[0] || &src[3*count] <= &dst[0]);
+    SkASSERT(src == dst || &dst[count] <= &src[0] || &src[count] <= &dst[0]);
 
     if (count > 0) {
         if (this->isIdentity()) {
-            memcpy(dst, src, 3*count*sizeof(SkScalar));
+            memcpy(dst, src, count * sizeof(SkPoint3));
             return;
         }
         do {
-            SkScalar sx = src[0];
-            SkScalar sy = src[1];
-            SkScalar sw = src[2];
-            src += 3;
+            SkScalar sx = src->fX;
+            SkScalar sy = src->fY;
+            SkScalar sw = src->fZ;
+            src++;
 
             SkScalar x = sdot(sx, fMat[kMScaleX], sy, fMat[kMSkewX],  sw, fMat[kMTransX]);
             SkScalar y = sdot(sx, fMat[kMSkewY],  sy, fMat[kMScaleY], sw, fMat[kMTransY]);
             SkScalar w = sdot(sx, fMat[kMPersp0], sy, fMat[kMPersp1], sw, fMat[kMPersp2]);
 
-            dst[0] = x;
-            dst[1] = y;
-            dst[2] = w;
-            dst += 3;
+            dst->set(x, y, w);
+            dst++;
         } while (--count);
     }
 }
diff --git a/src/gpu/ops/GrAAHairLinePathRenderer.cpp b/src/gpu/ops/GrAAHairLinePathRenderer.cpp
index 724f823..6dd5dc0 100644
--- a/src/gpu/ops/GrAAHairLinePathRenderer.cpp
+++ b/src/gpu/ops/GrAAHairLinePathRenderer.cpp
@@ -18,6 +18,7 @@
 #include "GrResourceProvider.h"
 #include "GrSimpleMeshDrawOpHelper.h"
 #include "SkGeometry.h"
+#include "SkPoint3.h"
 #include "SkStroke.h"
 #include "SkTemplates.h"
 #include "effects/GrBezierEffect.h"
@@ -597,8 +598,8 @@
     GrPathUtils::getConicKLM(p, weight, &klm);
 
     for (int i = 0; i < kQuadNumVertices; ++i) {
-        const SkScalar pt3[3] = {verts[i].fPos.x(), verts[i].fPos.y(), 1.f};
-        klm.mapHomogeneousPoints(verts[i].fConic.fKLM, pt3, 1);
+        const SkPoint3 pt3 = {verts[i].fPos.x(), verts[i].fPos.y(), 1.f};
+        klm.mapHomogeneousPoints((SkPoint3* ) verts[i].fConic.fKLM, &pt3, 1);
     }
 }
 
diff --git a/tests/Matrix44Test.cpp b/tests/Matrix44Test.cpp
index 382cd21..6a42a44 100644
--- a/tests/Matrix44Test.cpp
+++ b/tests/Matrix44Test.cpp
@@ -6,6 +6,7 @@
  */
 
 #include "SkMatrix44.h"
+#include "SkPoint3.h"
 #include "Test.h"
 
 static bool nearly_equal_double(double a, double b) {
@@ -554,17 +555,17 @@
 
     // Test that a point with a Z value of 0 is transformed the same way.
     SkScalar vec4[4] = { 2, 4, 0, 8 };
-    SkScalar vec3[3] = { 2, 4, 8 };
+    SkPoint3 vec3 = { 2, 4, 8 };
 
     SkScalar vec4transformed[4];
-    SkScalar vec3transformed[3];
+    SkPoint3 vec3transformed;
     SkScalar vec4transformed2[4];
     a44.mapScalars(vec4, vec4transformed);
-    a33.mapHomogeneousPoints(vec3transformed, vec3, 1);
+    a33.mapHomogeneousPoints(&vec3transformed, &vec3, 1);
     a44flattened.mapScalars(vec4, vec4transformed2);
-    REPORTER_ASSERT(reporter, nearly_equal_scalar(vec4transformed[0], vec3transformed[0]));
-    REPORTER_ASSERT(reporter, nearly_equal_scalar(vec4transformed[1], vec3transformed[1]));
-    REPORTER_ASSERT(reporter, nearly_equal_scalar(vec4transformed[3], vec3transformed[2]));
+    REPORTER_ASSERT(reporter, nearly_equal_scalar(vec4transformed[0], vec3transformed.fX));
+    REPORTER_ASSERT(reporter, nearly_equal_scalar(vec4transformed[1], vec3transformed.fY));
+    REPORTER_ASSERT(reporter, nearly_equal_scalar(vec4transformed[3], vec3transformed.fZ));
     REPORTER_ASSERT(reporter, nearly_equal_scalar(vec4transformed[0], vec4transformed2[0]));
     REPORTER_ASSERT(reporter, nearly_equal_scalar(vec4transformed[1], vec4transformed2[1]));
     REPORTER_ASSERT(reporter, !nearly_equal_scalar(vec4transformed[2], vec4transformed2[2]));
diff --git a/tests/MatrixTest.cpp b/tests/MatrixTest.cpp
index 6f7a14f..578e8b0 100644
--- a/tests/MatrixTest.cpp
+++ b/tests/MatrixTest.cpp
@@ -8,6 +8,7 @@
 #include "SkMath.h"
 #include "SkMatrix.h"
 #include "SkMatrixUtils.h"
+#include "SkPoint3.h"
 #include "SkRandom.h"
 #include "Test.h"
 
@@ -647,9 +648,15 @@
 }
 
 // For test_matrix_homogeneous, below.
-static bool scalar_array_nearly_equal_relative(const SkScalar a[], const SkScalar b[], int count) {
+static bool point3_array_nearly_equal_relative(const SkPoint3 a[], const SkPoint3 b[], int count) {
     for (int i = 0; i < count; ++i) {
-        if (!scalar_nearly_equal_relative(a[i], b[i])) {
+        if (!scalar_nearly_equal_relative(a[i].fX, b[i].fX)) {
+            return false;
+        }
+        if (!scalar_nearly_equal_relative(a[i].fY, b[i].fY)) {
+            return false;
+        }
+        if (!scalar_nearly_equal_relative(a[i].fZ, b[i].fZ)) {
             return false;
         }
     }
@@ -658,16 +665,16 @@
 
 // For test_matrix_homogeneous, below.
 // Maps a single triple in src using m and compares results to those in dst
-static bool naive_homogeneous_mapping(const SkMatrix& m, const SkScalar src[3],
-                                      const SkScalar dst[3]) {
-    SkScalar res[3];
+static bool naive_homogeneous_mapping(const SkMatrix& m, const SkPoint3& src,
+                                      const SkPoint3& dst) {
+    SkPoint3 res;
     SkScalar ms[9] = {m[0], m[1], m[2],
                       m[3], m[4], m[5],
                       m[6], m[7], m[8]};
-    res[0] = src[0] * ms[0] + src[1] * ms[1] + src[2] * ms[2];
-    res[1] = src[0] * ms[3] + src[1] * ms[4] + src[2] * ms[5];
-    res[2] = src[0] * ms[6] + src[1] * ms[7] + src[2] * ms[8];
-    return scalar_array_nearly_equal_relative(res, dst, 3);
+    res.fX = src.fX * ms[0] + src.fY * ms[1] + src.fZ * ms[2];
+    res.fY = src.fX * ms[3] + src.fY * ms[4] + src.fZ * ms[5];
+    res.fZ = src.fX * ms[6] + src.fY * ms[7] + src.fZ * ms[8];
+    return point3_array_nearly_equal_relative(&res, &dst, 1);
 }
 
 static void test_matrix_homogeneous(skiatest::Reporter* reporter) {
@@ -687,9 +694,11 @@
 #endif
     SkRandom rand;
 
-    SkScalar randTriples[3*kTripleCount];
-    for (int i = 0; i < 3*kTripleCount; ++i) {
-        randTriples[i] = rand.nextRangeF(-3000.f, 3000.f);
+    SkPoint3 randTriples[kTripleCount];
+    for (int i = 0; i < kTripleCount; ++i) {
+        randTriples[i].fX = rand.nextRangeF(-3000.f, 3000.f);
+        randTriples[i].fY = rand.nextRangeF(-3000.f, 3000.f);
+        randTriples[i].fZ = rand.nextRangeF(-3000.f, 3000.f);
     }
 
     SkMatrix mats[kMatrixCount];
@@ -702,29 +711,28 @@
     // identity
     {
     mat.reset();
-    SkScalar dst[3*kTripleCount];
+    SkPoint3 dst[kTripleCount];
     mat.mapHomogeneousPoints(dst, randTriples, kTripleCount);
-    REPORTER_ASSERT(reporter, scalar_array_nearly_equal_relative(randTriples, dst, kTripleCount*3));
+    REPORTER_ASSERT(reporter, point3_array_nearly_equal_relative(randTriples, dst, kTripleCount));
     }
 
+    const SkPoint3 zeros = {0.f, 0.f, 0.f};
     // zero matrix
     {
     mat.setAll(0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f);
-    SkScalar dst[3*kTripleCount];
+    SkPoint3 dst[kTripleCount];
     mat.mapHomogeneousPoints(dst, randTriples, kTripleCount);
-    SkScalar zeros[3] = {0.f, 0.f, 0.f};
     for (int i = 0; i < kTripleCount; ++i) {
-        REPORTER_ASSERT(reporter, scalar_array_nearly_equal_relative(&dst[i*3], zeros, 3));
+        REPORTER_ASSERT(reporter, point3_array_nearly_equal_relative(&dst[i], &zeros, 1));
     }
     }
 
     // zero point
     {
-    SkScalar zeros[3] = {0.f, 0.f, 0.f};
     for (int i = 0; i < kMatrixCount; ++i) {
-        SkScalar dst[3];
-        mats[i].mapHomogeneousPoints(dst, zeros, 1);
-        REPORTER_ASSERT(reporter, scalar_array_nearly_equal_relative(dst, zeros, 3));
+        SkPoint3 dst;
+        mats[i].mapHomogeneousPoints(&dst, &zeros, 1);
+        REPORTER_ASSERT(reporter, point3_array_nearly_equal_relative(&dst, &zeros, 1));
     }
     }
 
@@ -736,29 +744,29 @@
     // uniform scale of point
     {
     mat.setScale(kScale0, kScale0);
-    SkScalar dst[3];
-    SkScalar src[3] = {randTriples[0], randTriples[1], 1.f};
+    SkPoint3 dst;
+    SkPoint3 src = {randTriples[0].fX, randTriples[0].fY, 1.f};
     SkPoint pnt;
-    pnt.set(src[0], src[1]);
-    mat.mapHomogeneousPoints(dst, src, 1);
+    pnt.set(src.fX, src.fY);
+    mat.mapHomogeneousPoints(&dst, &src, 1);
     mat.mapPoints(&pnt, &pnt, 1);
-    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[0], pnt.fX));
-    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[1], pnt.fY));
-    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[2], SK_Scalar1));
+    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.fX, pnt.fX));
+    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.fY, pnt.fY));
+    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.fZ, SK_Scalar1));
     }
 
     // rotation of point
     {
     mat.setRotate(kRotation0);
-    SkScalar dst[3];
-    SkScalar src[3] = {randTriples[0], randTriples[1], 1.f};
+    SkPoint3 dst;
+    SkPoint3 src = {randTriples[0].fX, randTriples[0].fY, 1.f};
     SkPoint pnt;
-    pnt.set(src[0], src[1]);
-    mat.mapHomogeneousPoints(dst, src, 1);
+    pnt.set(src.fX, src.fY);
+    mat.mapHomogeneousPoints(&dst, &src, 1);
     mat.mapPoints(&pnt, &pnt, 1);
-    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[0], pnt.fX));
-    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[1], pnt.fY));
-    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[2], SK_Scalar1));
+    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.fX, pnt.fX));
+    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.fY, pnt.fY));
+    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.fZ, SK_Scalar1));
     }
 
     // rotation, scale, rotation of point
@@ -766,24 +774,24 @@
     mat.setRotate(kRotation1);
     mat.postScale(kScale0, kScale0);
     mat.postRotate(kRotation0);
-    SkScalar dst[3];
-    SkScalar src[3] = {randTriples[0], randTriples[1], 1.f};
+    SkPoint3 dst;
+    SkPoint3 src = {randTriples[0].fX, randTriples[0].fY, 1.f};
     SkPoint pnt;
-    pnt.set(src[0], src[1]);
-    mat.mapHomogeneousPoints(dst, src, 1);
+    pnt.set(src.fX, src.fY);
+    mat.mapHomogeneousPoints(&dst, &src, 1);
     mat.mapPoints(&pnt, &pnt, 1);
-    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[0], pnt.fX));
-    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[1], pnt.fY));
-    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst[2], SK_Scalar1));
+    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.fX, pnt.fX));
+    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.fY, pnt.fY));
+    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.fZ, SK_Scalar1));
     }
 
     // compare with naive approach
     {
     for (int i = 0; i < kMatrixCount; ++i) {
         for (int j = 0; j < kTripleCount; ++j) {
-            SkScalar dst[3];
-            mats[i].mapHomogeneousPoints(dst, &randTriples[j*3], 1);
-            REPORTER_ASSERT(reporter, naive_homogeneous_mapping(mats[i], &randTriples[j*3], dst));
+            SkPoint3 dst;
+            mats[i].mapHomogeneousPoints(&dst, &randTriples[j], 1);
+            REPORTER_ASSERT(reporter, naive_homogeneous_mapping(mats[i], randTriples[j], dst));
         }
     }
     }