add get9 and set9 to matrix, to aid in making keys
authorreed <reed@chromium.org>
Sat, 13 Dec 2014 16:46:48 +0000 (08:46 -0800)
committerCommit bot <commit-bot@chromium.org>
Sat, 13 Dec 2014 16:46:49 +0000 (08:46 -0800)
BUG=skia:
TBR=
NOTREECHECKS=True

Review URL: https://codereview.chromium.org/806543002

include/core/SkMatrix.h
src/core/SkMatrix.cpp
tests/MatrixTest.cpp

index d98830f8379f86b11b21d8d44a10628073b7eb2c..fbf8308290d07500137cf2276a4b6152dac53558 100644 (file)
@@ -174,6 +174,23 @@ public:
         this->setTypeMask(kUnknown_Mask);
     }
 
+    /**
+     *  Copy the 9 scalars for this matrix into buffer, in the same order as the kMScaleX
+     *  enum... scalex, skewx, transx, skewy, scaley, transy, persp0, persp1, persp2
+     */
+    void get9(SkScalar buffer[9]) const {
+        memcpy(buffer, fMat, 9 * sizeof(SkScalar));
+    }
+
+    /**
+     *  Set this matrix to the 9 scalars from the buffer, in the same order as the kMScaleX
+     *  enum... scalex, skewx, transx, skewy, scaley, transy, persp0, persp1, persp2
+     *
+     *  Note: calling set9 followed by get9 may not return the exact same values. Since the matrix
+     *  is used to map non-homogeneous coordinates, it is free to rescale the 9 values as needed.
+     */
+    void set9(const SkScalar buffer[9]);
+
     /** Set the matrix to identity
     */
     void reset();
@@ -372,7 +389,12 @@ public:
         and does not change the passed array.
         @param affine  The array to fill with affine values. Ignored if NULL.
     */
-    bool asAffine(SkScalar affine[6]) const;
+    bool SK_WARN_UNUSED_RESULT asAffine(SkScalar affine[6]) const;
+
+    /** Set the matrix to the specified affine values.
+     *  Note: these are passed in column major order.
+     */
+    void setAffine(const SkScalar affine[6]);
 
     /** Apply this matrix to the array of points specified by src, and write
         the transformed points into the array of points specified by dst.
index f770e0d5e5d24c57b975f3c49d5709312615f522..77036bc454c9430132bf71b1d686a14fdc6d03fe 100644 (file)
 
 #include <stddef.h>
 
+static void normalize_perspective(SkScalar mat[9]) {
+    // If it was interesting to never store the last element, we could divide all 8 other
+    // elements here by the 9th, making it 1.0...
+    //
+    // When SkScalar was SkFixed, we would sometimes rescale the entire matrix to keep its
+    // component values from getting too large. This is not a concern when using floats/doubles,
+    // so we do nothing now.
+
+    // Disable this for now, but it could be enabled.
+#if 0
+    if (0 == mat[SkMatrix::kMPersp0] && 0 == mat[SkMatrix::kMPersp1]) {
+        SkScalar p2 = mat[SkMatrix::kMPersp2];
+        if (p2 != 0 && p2 != 1) {
+            double inv = 1.0 / p2;
+            for (int i = 0; i < 6; ++i) {
+                mat[i] = SkDoubleToScalar(mat[i] * inv);
+            }
+            mat[SkMatrix::kMPersp2] = 1;
+        }
+    }
+#endif
+}
+
 // In a few places, we performed the following
 //      a * b + c * d + e
 // as
@@ -40,10 +63,28 @@ void SkMatrix::reset() {
     fMat[kMSkewX]  = fMat[kMSkewY] =
     fMat[kMTransX] = fMat[kMTransY] =
     fMat[kMPersp0] = fMat[kMPersp1] = 0;
-
     this->setTypeMask(kIdentity_Mask | kRectStaysRect_Mask);
 }
 
+void SkMatrix::set9(const SkScalar buffer[]) {
+    memcpy(fMat, buffer, 9 * sizeof(SkScalar));
+    normalize_perspective(fMat);
+    this->setTypeMask(kUnknown_Mask);
+}
+
+void SkMatrix::setAffine(const SkScalar buffer[]) {
+    fMat[kMScaleX] = buffer[kAScaleX];
+    fMat[kMSkewX]  = buffer[kASkewX];
+    fMat[kMTransX] = buffer[kATransX];
+    fMat[kMSkewY]  = buffer[kASkewY];
+    fMat[kMScaleY] = buffer[kAScaleY];
+    fMat[kMTransY] = buffer[kATransY];
+    fMat[kMPersp0] = 0;
+    fMat[kMPersp1] = 0;
+    fMat[kMPersp2] = 1;
+    this->setTypeMask(kUnknown_Mask);
+}
+
 // this guy aligns with the masks, so we can compute a mask from a varaible 0/1
 enum {
     kTranslate_Shift,
@@ -568,15 +609,6 @@ static inline float rowcol3(const float row[], const float col[]) {
     return row[0] * col[0] + row[1] * col[3] + row[2] * col[6];
 }
 
-static void normalize_perspective(SkScalar mat[9]) {
-    // If it was interesting to never store the last element, we could divide all 8 other
-    // elements here by the 9th, making it 1.0...
-    //
-    // When SkScalar was SkFixed, we would sometimes rescale the entire matrix to keep its
-    // component values from getting too large. This is not a concern when using floats/doubles,
-    // so we do nothing now.
-}
-
 static bool only_scale_and_translate(unsigned mask) {
     return 0 == (mask & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask));
 }
index fc7ac42a99690d1269d1f2c04f360a918011b25a..8a27a9eddfff380e0ccb7a8cee37d977ae700266 100644 (file)
@@ -71,6 +71,45 @@ static bool is_identity(const SkMatrix& m) {
     return nearly_equal(m, identity);
 }
 
+static void assert9(skiatest::Reporter* reporter, const SkMatrix& m,
+                    SkScalar a, SkScalar b, SkScalar c,
+                    SkScalar d, SkScalar e, SkScalar f,
+                    SkScalar g, SkScalar h, SkScalar i) {
+    SkScalar buffer[9];
+    m.get9(buffer);
+    REPORTER_ASSERT(reporter, buffer[0] == a);
+    REPORTER_ASSERT(reporter, buffer[1] == b);
+    REPORTER_ASSERT(reporter, buffer[2] == c);
+    REPORTER_ASSERT(reporter, buffer[3] == d);
+    REPORTER_ASSERT(reporter, buffer[4] == e);
+    REPORTER_ASSERT(reporter, buffer[5] == f);
+    REPORTER_ASSERT(reporter, buffer[6] == g);
+    REPORTER_ASSERT(reporter, buffer[7] == h);
+    REPORTER_ASSERT(reporter, buffer[8] == i);
+}
+
+static void test_set9(skiatest::Reporter* reporter) {
+
+    SkMatrix m;
+    m.reset();
+    assert9(reporter, m, 1, 0, 0, 0, 1, 0, 0, 0, 1);
+    
+    m.setScale(2, 3);
+    assert9(reporter, m, 2, 0, 0, 0, 3, 0, 0, 0, 1);
+    
+    m.postTranslate(4, 5);
+    assert9(reporter, m, 2, 0, 4, 0, 3, 5, 0, 0, 1);
+
+    SkScalar buffer[9];
+    sk_bzero(buffer, sizeof(buffer));
+    buffer[SkMatrix::kMScaleX] = 1;
+    buffer[SkMatrix::kMScaleY] = 1;
+    buffer[SkMatrix::kMPersp2] = 1;
+    REPORTER_ASSERT(reporter, !m.isIdentity());
+    m.set9(buffer);
+    REPORTER_ASSERT(reporter, m.isIdentity());
+}
+
 static void test_matrix_recttorect(skiatest::Reporter* reporter) {
     SkRect src, dst;
     SkMatrix matrix;
@@ -849,6 +888,7 @@ DEF_TEST(Matrix, reporter) {
     test_matrix_recttorect(reporter);
     test_matrix_decomposition(reporter);
     test_matrix_homogeneous(reporter);
+    test_set9(reporter);
 }
 
 DEF_TEST(Matrix_Concat, r) {