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();
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.
#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
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,
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));
}
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;
test_matrix_recttorect(reporter);
test_matrix_decomposition(reporter);
test_matrix_homogeneous(reporter);
+ test_set9(reporter);
}
DEF_TEST(Matrix_Concat, r) {