Ejemplo n.º 1
0
/**
 * Retrieves the final matrix that a transform needs to apply to its source coords.
 */
static SkMatrix get_transform_matrix(const GrPendingFragmentStage& stage,
                                     bool useExplicitLocalCoords,
                                     int transformIdx) {
    const GrCoordTransform& coordTransform = stage.getProcessor()->coordTransform(transformIdx);
    SkMatrix combined;

    if (kLocal_GrCoordSet == coordTransform.sourceCoords()) {
        // If we have explicit local coords then we shouldn't need a coord change.
        const SkMatrix& ccm =
                useExplicitLocalCoords ? SkMatrix::I() : stage.getCoordChangeMatrix();
        combined.setConcat(coordTransform.getMatrix(), ccm);
    } else {
        combined = coordTransform.getMatrix();
    }
    if (coordTransform.reverseY()) {
        // combined.postScale(1,-1);
        // combined.postTranslate(0,1);
        combined.set(SkMatrix::kMSkewY,
            combined[SkMatrix::kMPersp0] - combined[SkMatrix::kMSkewY]);
        combined.set(SkMatrix::kMScaleY,
            combined[SkMatrix::kMPersp1] - combined[SkMatrix::kMScaleY]);
        combined.set(SkMatrix::kMTransY,
            combined[SkMatrix::kMPersp2] - combined[SkMatrix::kMTransY]);
    }
    return combined;
}
SkMatrix readMatrix(SkStream *stream)
{
    SkMatrix matrix;
    for (int i = 0; i < 9; i++)
        matrix.set(i, stream->readScalar());
    return matrix;
}
SkMatrix GrGLSLPrimitiveProcessor::GetTransformMatrix(const SkMatrix& localMatrix,
                                                      const GrCoordTransform& coordTransform) {
    SkMatrix combined;
    combined.setConcat(coordTransform.getMatrix(), localMatrix);
    if (coordTransform.normalize()) {
        combined.postIDiv(coordTransform.peekTexture()->width(),
                          coordTransform.peekTexture()->height());
    }

    if (coordTransform.reverseY()) {
        // combined.postScale(1,-1);
        // combined.postTranslate(0,1);
        combined.set(SkMatrix::kMSkewY,
            combined[SkMatrix::kMPersp0] - combined[SkMatrix::kMSkewY]);
        combined.set(SkMatrix::kMScaleY,
            combined[SkMatrix::kMPersp1] - combined[SkMatrix::kMScaleY]);
        combined.set(SkMatrix::kMTransY,
            combined[SkMatrix::kMPersp2] - combined[SkMatrix::kMTransY]);
    }
    return combined;
}
static inline SkMatrix
matrix_to_sk (const cairo_matrix_t& mat)
{
    SkMatrix skm;

    skm.reset ();
    skm.set (SkMatrix::kMScaleX, SkFloatToScalar (mat.xx));
    skm.set (SkMatrix::kMSkewX,  SkFloatToScalar (mat.xy));
    skm.set (SkMatrix::kMTransX, SkFloatToScalar (mat.x0));
    skm.set (SkMatrix::kMSkewY,  SkFloatToScalar (mat.yx));
    skm.set (SkMatrix::kMScaleY, SkFloatToScalar (mat.yy));
    skm.set (SkMatrix::kMTransY, SkFloatToScalar (mat.y0));

    /*
    skm[6] = SkFloatToScalar (0.0);
    skm[7] = SkFloatToScalar (0.0);
    skm[8] = SkFloatToScalar (1.0); -- this isn't right, it wants a magic value in there that it'll set itself.  It wants Sk_Fract1 (2.30), not Sk_Scalar1
    */

    return skm;
}
Ejemplo n.º 5
0
void SkCamera3D::doUpdate() const
{
    SkUnit3D    axis, zenith, cross;

    fAxis.normalize(&axis);

    {
        SkScalar dot = SkUnit3D::Dot(*(const SkUnit3D*)(const void*)&fZenith, axis);

        zenith.fX = fZenith.fX - SkUnitScalarMul(dot, axis.fX);
        zenith.fY = fZenith.fY - SkUnitScalarMul(dot, axis.fY);
        zenith.fZ = fZenith.fZ - SkUnitScalarMul(dot, axis.fZ);

        (void)((SkPoint3D*)(void*)&zenith)->normalize(&zenith);
    }

    SkUnit3D::Cross(axis, zenith, &cross);

    {
        SkMatrix* orien = &fOrientation;
        SkScalar x = fObserver.fX;
        SkScalar y = fObserver.fY;
        SkScalar z = fObserver.fZ;

        orien->set(SkMatrix::kMScaleX, SkUnitScalarMul(x, axis.fX) - SkUnitScalarMul(z, cross.fX));
        orien->set(SkMatrix::kMSkewX,  SkUnitScalarMul(x, axis.fY) - SkUnitScalarMul(z, cross.fY));
        orien->set(SkMatrix::kMTransX, SkUnitScalarMul(x, axis.fZ) - SkUnitScalarMul(z, cross.fZ));
        orien->set(SkMatrix::kMSkewY,  SkUnitScalarMul(y, axis.fX) - SkUnitScalarMul(z, zenith.fX));
        orien->set(SkMatrix::kMScaleY, SkUnitScalarMul(y, axis.fY) - SkUnitScalarMul(z, zenith.fY));
        orien->set(SkMatrix::kMTransY, SkUnitScalarMul(y, axis.fZ) - SkUnitScalarMul(z, zenith.fZ));
        orien->set(SkMatrix::kMPersp0, axis.fX);
        orien->set(SkMatrix::kMPersp1, axis.fY);
        orien->set(SkMatrix::kMPersp2, axis.fZ);
    }
}
Ejemplo n.º 6
0
    static void setValues(JNIEnv* env, jobject clazz, jlong matrixHandle, jfloatArray values) {
        SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
        AutoJavaFloatArray autoValues(env, values, 9, kRO_JNIAccess);
        const float* src = autoValues.ptr();

#ifdef SK_SCALAR_IS_FLOAT
        for (int i = 0; i < 9; i++) {
            matrix->set(i, src[i]);
        }
#else
        SkASSERT(false);
#endif
    }
Ejemplo n.º 7
0
void Matrix4::copyTo(SkMatrix& v) const {
    v.reset();

    v.set(SkMatrix::kMScaleX, data[kScaleX]);
    v.set(SkMatrix::kMSkewX,  data[kSkewX]);
    v.set(SkMatrix::kMTransX, data[kTranslateX]);

    v.set(SkMatrix::kMSkewY,  data[kSkewY]);
    v.set(SkMatrix::kMScaleY, data[kScaleY]);
    v.set(SkMatrix::kMTransY, data[kTranslateY]);

    v.set(SkMatrix::kMPersp0, data[kPerspective0]);
    v.set(SkMatrix::kMPersp1, data[kPerspective1]);
    v.set(SkMatrix::kMPersp2, data[kPerspective2]);
}
Ejemplo n.º 8
0
void Matrix::NativeSetValues(
    /* [in] */ Int64 matrixHandle,
    /* [in] */ ArrayOf<Float>* values)
{
    SkASSERT(values->GetLength() >= 9);
    SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
    // AutoJavaFloatArray autoValues(env, values, 9, kRO_JNIAccess);
    const float* src = values->GetPayload();

#ifdef SK_SCALAR_IS_FLOAT
    for (int i = 0; i < 9; i++) {
        matrix->set(i, src[i]);
    }
#else
    SkASSERT(FALSE);
#endif
}
Ejemplo n.º 9
0
void draw(SkCanvas* canvas) {
    SkMatrix m;
    m.setIdentity();
    m.set(SkMatrix::kMPersp0, -0.004f);
    SkAutoCanvasRestore autoRestore(canvas, true);
    canvas->translate(22, 144);
    SkPaint black;
    black.setAntiAlias(true);
    black.setTextSize(24);
    SkPaint gray = black;
    gray.setColor(0xFF9f9f9f);
    SkString string;
    string.appendScalar(m.getPerspX());
    canvas->drawString(string, 0, -72, gray);
    canvas->concat(m);
    canvas->drawString(string, 0, 0, black);
}
Ejemplo n.º 10
0
SkMatrix affineTransformToSkMatrix(const AffineTransform& source)
{
    SkMatrix result;

    result.setScaleX(WebCoreDoubleToSkScalar(source.a()));
    result.setSkewX(WebCoreDoubleToSkScalar(source.c()));
    result.setTranslateX(WebCoreDoubleToSkScalar(source.e()));

    result.setScaleY(WebCoreDoubleToSkScalar(source.d()));
    result.setSkewY(WebCoreDoubleToSkScalar(source.b()));
    result.setTranslateY(WebCoreDoubleToSkScalar(source.f()));

    // FIXME: Set perspective properly.
    result.setPerspX(0);
    result.setPerspY(0);
    result.set(SkMatrix::kMPersp2, SK_Scalar1);

    return result;
}
AffineTransform::operator SkMatrix() const
{
    SkMatrix result;

    result.setScaleX(WebCoreDoubleToSkScalar(a()));
    result.setSkewX(WebCoreDoubleToSkScalar(c()));
    result.setTranslateX(WebCoreDoubleToSkScalar(e()));

    result.setScaleY(WebCoreDoubleToSkScalar(d()));
    result.setSkewY(WebCoreDoubleToSkScalar(b()));
    result.setTranslateY(WebCoreDoubleToSkScalar(f()));

    // FIXME: Set perspective properly.
    result.setPerspX(0);
    result.setPerspY(0);
    result.set(SkMatrix::kMPersp2, SK_Scalar1);

    return result;
}
Ejemplo n.º 12
0
static void setup_canvas_from_MC_state(const SkMCState& state, SkCanvas* canvas) {
    // reconstruct the matrix
    SkMatrix matrix;
    for (int i = 0; i < 9; i++) {
        matrix.set(i, state.matrix[i]);
    }

    // reconstruct the clip
    SkRegion clip;
    for (int i = 0; i < state.clipRectCount; ++i) {
        clip.op(SkIRect::MakeLTRB(state.clipRects[i].left,
                                  state.clipRects[i].top,
                                  state.clipRects[i].right,
                                  state.clipRects[i].bottom),
                SkRegion::kUnion_Op);
    }

    canvas->setMatrix(matrix);
    canvas->setClipRegion(clip);
}
Ejemplo n.º 13
0
void draw(SkCanvas* canvas) {
    SkPaint black;
    black.setAntiAlias(true);
    black.setTextSize(48);
    SkPaint gray = black;
    gray.setColor(0xFF9f9f9f);
    SkScalar offset[] = { 1.5f, 1.5f, 20,   1.5f, 1.5f, 20,   .03f, .01f, 2 };
    for (int i : { SkMatrix::kMScaleX, SkMatrix::kMSkewX,  SkMatrix::kMTransX,
                   SkMatrix::kMSkewY,  SkMatrix::kMScaleY, SkMatrix::kMTransY,
                   SkMatrix::kMPersp0, SkMatrix::kMPersp1, SkMatrix::kMPersp2 } ) {
        SkMatrix m;
        m.setIdentity();
        m.set(i, offset[i]);
        SkAutoCanvasRestore autoRestore(canvas, true);
        canvas->translate(22 + (i % 3) * 88, 44 + (i / 3) * 88);
        canvas->drawString("&", 0, 0, gray);
        canvas->concat(m);
        canvas->drawString("&", 0, 0, black);
    }
}
Ejemplo n.º 14
0
static void DrawRoundRect() {
#ifdef SK_SCALAR_IS_FIXED
    bool ret = false;
    SkPaint  paint;
    SkBitmap bitmap;
    SkCanvas canvas;
    SkMatrix matrix;
    matrix.reset();

    bitmap.setConfig(SkBitmap::kARGB_8888_Config, 1370, 812);
    bitmap.allocPixels();
    canvas.setBitmapDevice(bitmap);

    // set up clipper
    SkRect skclip;
    skclip.set(SkIntToFixed(284), SkIntToFixed(40), SkIntToFixed(1370), SkIntToFixed(708));

    ret = canvas.clipRect(skclip);
    SkASSERT(ret);

    matrix.set(SkMatrix::kMTransX, SkFloatToFixed(-1153.28));
    matrix.set(SkMatrix::kMTransY, SkFloatToFixed(1180.50));

    matrix.set(SkMatrix::kMScaleX, SkFloatToFixed(0.177171));
    matrix.set(SkMatrix::kMScaleY, SkFloatToFixed(0.177043));

    matrix.set(SkMatrix::kMSkewX, SkFloatToFixed(0.126968));
    matrix.set(SkMatrix::kMSkewY, SkFloatToFixed(-0.126876));

    matrix.set(SkMatrix::kMPersp0, SkFloatToFixed(0.0));
    matrix.set(SkMatrix::kMPersp1, SkFloatToFixed(0.0));

    ret = canvas.concat(matrix);

    paint.setAntiAlias(true);
    paint.setColor(0xb2202020);
    paint.setStyle(SkPaint::kStroke_Style);
    paint.setStrokeWidth(SkFloatToFixed(68.13));

    SkRect r;
    r.set(SkFloatToFixed(-313.714417), SkFloatToFixed(-4.826389), SkFloatToFixed(18014.447266), SkFloatToFixed(1858.154541));
    canvas.drawRoundRect(r, SkFloatToFixed(91.756363), SkFloatToFixed(91.756363), paint);
#endif
}
Ejemplo n.º 15
0
static void DrawRoundRect(SkCanvas& canvas) {
   bool ret = false;
   SkPaint  paint;
   SkBitmap bitmap;
   SkMatrix matrix;
   matrix.reset();

   bitmap.setConfig(SkBitmap::kARGB_8888_Config, 1370, 812);
   bitmap.allocPixels();
#if 0
    SkCanvas canvas;
    canvas.setBitmapDevice(bitmap);
#endif

   // set up clipper
   SkRect skclip;
   skclip.set(SkIntToScalar(284), SkIntToScalar(40), SkIntToScalar(1370), SkIntToScalar(708));

//   ret = canvas.clipRect(skclip);
//   SkASSERT(ret);

   matrix.set(SkMatrix::kMTransX, SkFloatToScalar(-1153.28f));
   matrix.set(SkMatrix::kMTransY, SkFloatToScalar(1180.50f));

   matrix.set(SkMatrix::kMScaleX, SkFloatToScalar(0.177171f));
   matrix.set(SkMatrix::kMScaleY, SkFloatToScalar(0.177043f));

   matrix.set(SkMatrix::kMSkewX, SkFloatToScalar(0.126968f));
   matrix.set(SkMatrix::kMSkewY, SkFloatToScalar(-0.126876f));

   matrix.set(SkMatrix::kMPersp0, SkFloatToScalar(0.0f));
   matrix.set(SkMatrix::kMPersp1, SkFloatToScalar(0.0f));

   ret = canvas.concat(matrix);

   paint.setAntiAlias(true);
   paint.setColor(0xb2202020);
   paint.setStyle(SkPaint::kStroke_Style);
   paint.setStrokeWidth(SkFloatToScalar(68.13f));

   SkRect r;
   r.set(SkFloatToScalar(-313.714417f), SkFloatToScalar(-4.826389f), SkFloatToScalar(18014.447266f), SkFloatToScalar(1858.154541f));
   canvas.drawRoundRect(r, SkFloatToScalar(91.756363f), SkFloatToScalar(91.756363f), paint);
}
Ejemplo n.º 16
0
DEF_TEST(Matrix, reporter) {
    SkMatrix    mat, inverse, iden1, iden2;

    mat.reset();
    mat.setTranslate(SK_Scalar1, SK_Scalar1);
    REPORTER_ASSERT(reporter, mat.invert(&inverse));
    iden1.setConcat(mat, inverse);
    REPORTER_ASSERT(reporter, is_identity(iden1));

    mat.setScale(SkIntToScalar(2), SkIntToScalar(4));
    REPORTER_ASSERT(reporter, mat.invert(&inverse));
    iden1.setConcat(mat, inverse);
    REPORTER_ASSERT(reporter, is_identity(iden1));
    test_flatten(reporter, mat);

    mat.setScale(SK_Scalar1/2, SkIntToScalar(2));
    REPORTER_ASSERT(reporter, mat.invert(&inverse));
    iden1.setConcat(mat, inverse);
    REPORTER_ASSERT(reporter, is_identity(iden1));
    test_flatten(reporter, mat);

    mat.setScale(SkIntToScalar(3), SkIntToScalar(5), SkIntToScalar(20), 0);
    mat.postRotate(SkIntToScalar(25));
    REPORTER_ASSERT(reporter, mat.invert(NULL));
    REPORTER_ASSERT(reporter, mat.invert(&inverse));
    iden1.setConcat(mat, inverse);
    REPORTER_ASSERT(reporter, is_identity(iden1));
    iden2.setConcat(inverse, mat);
    REPORTER_ASSERT(reporter, is_identity(iden2));
    test_flatten(reporter, mat);
    test_flatten(reporter, iden2);

    mat.setScale(0, SK_Scalar1);
    REPORTER_ASSERT(reporter, !mat.invert(NULL));
    REPORTER_ASSERT(reporter, !mat.invert(&inverse));
    mat.setScale(SK_Scalar1, 0);
    REPORTER_ASSERT(reporter, !mat.invert(NULL));
    REPORTER_ASSERT(reporter, !mat.invert(&inverse));

    // rectStaysRect test
    {
        static const struct {
            SkScalar    m00, m01, m10, m11;
            bool        mStaysRect;
        }
        gRectStaysRectSamples[] = {
            {          0,          0,          0,           0, false },
            {          0,          0,          0,  SK_Scalar1, false },
            {          0,          0, SK_Scalar1,           0, false },
            {          0,          0, SK_Scalar1,  SK_Scalar1, false },
            {          0, SK_Scalar1,          0,           0, false },
            {          0, SK_Scalar1,          0,  SK_Scalar1, false },
            {          0, SK_Scalar1, SK_Scalar1,           0, true },
            {          0, SK_Scalar1, SK_Scalar1,  SK_Scalar1, false },
            { SK_Scalar1,          0,          0,           0, false },
            { SK_Scalar1,          0,          0,  SK_Scalar1, true },
            { SK_Scalar1,          0, SK_Scalar1,           0, false },
            { SK_Scalar1,          0, SK_Scalar1,  SK_Scalar1, false },
            { SK_Scalar1, SK_Scalar1,          0,           0, false },
            { SK_Scalar1, SK_Scalar1,          0,  SK_Scalar1, false },
            { SK_Scalar1, SK_Scalar1, SK_Scalar1,           0, false },
            { SK_Scalar1, SK_Scalar1, SK_Scalar1,  SK_Scalar1, false }
        };

        for (size_t i = 0; i < SK_ARRAY_COUNT(gRectStaysRectSamples); i++) {
            SkMatrix    m;

            m.reset();
            m.set(SkMatrix::kMScaleX, gRectStaysRectSamples[i].m00);
            m.set(SkMatrix::kMSkewX,  gRectStaysRectSamples[i].m01);
            m.set(SkMatrix::kMSkewY,  gRectStaysRectSamples[i].m10);
            m.set(SkMatrix::kMScaleY, gRectStaysRectSamples[i].m11);
            REPORTER_ASSERT(reporter,
                    m.rectStaysRect() == gRectStaysRectSamples[i].mStaysRect);
        }
    }

    mat.reset();
    mat.set(SkMatrix::kMScaleX, SkIntToScalar(1));
    mat.set(SkMatrix::kMSkewX,  SkIntToScalar(2));
    mat.set(SkMatrix::kMTransX, SkIntToScalar(3));
    mat.set(SkMatrix::kMSkewY,  SkIntToScalar(4));
    mat.set(SkMatrix::kMScaleY, SkIntToScalar(5));
    mat.set(SkMatrix::kMTransY, SkIntToScalar(6));
    SkScalar affine[6];
    REPORTER_ASSERT(reporter, mat.asAffine(affine));

    #define affineEqual(e) affine[SkMatrix::kA##e] == mat.get(SkMatrix::kM##e)
    REPORTER_ASSERT(reporter, affineEqual(ScaleX));
    REPORTER_ASSERT(reporter, affineEqual(SkewY));
    REPORTER_ASSERT(reporter, affineEqual(SkewX));
    REPORTER_ASSERT(reporter, affineEqual(ScaleY));
    REPORTER_ASSERT(reporter, affineEqual(TransX));
    REPORTER_ASSERT(reporter, affineEqual(TransY));
    #undef affineEqual

    mat.set(SkMatrix::kMPersp1, SkScalarToPersp(SK_Scalar1 / 2));
    REPORTER_ASSERT(reporter, !mat.asAffine(affine));

    SkMatrix mat2;
    mat2.reset();
    mat.reset();
    SkScalar zero = 0;
    mat.set(SkMatrix::kMSkewX, -zero);
    REPORTER_ASSERT(reporter, are_equal(reporter, mat, mat2));

    mat2.reset();
    mat.reset();
    mat.set(SkMatrix::kMSkewX, SK_ScalarNaN);
    mat2.set(SkMatrix::kMSkewX, SK_ScalarNaN);
    REPORTER_ASSERT(reporter, !are_equal(reporter, mat, mat2));

    test_matrix_min_max_scale(reporter);
    test_matrix_is_similarity(reporter);
    test_matrix_recttorect(reporter);
    test_matrix_decomposition(reporter);
    test_matrix_homogeneous(reporter);
}
Ejemplo n.º 17
0
void TestMatrix(skiatest::Reporter* reporter) {
    SkMatrix    mat, inverse, iden1, iden2;

    mat.reset();
    mat.setTranslate(SK_Scalar1, SK_Scalar1);
    mat.invert(&inverse);
    iden1.setConcat(mat, inverse);
    REPORTER_ASSERT(reporter, is_identity(iden1));

    mat.setScale(SkIntToScalar(2), SkIntToScalar(2));
    mat.invert(&inverse);
    iden1.setConcat(mat, inverse);
    REPORTER_ASSERT(reporter, is_identity(iden1));
    test_flatten(reporter, mat);

    mat.setScale(SK_Scalar1/2, SK_Scalar1/2);
    mat.invert(&inverse);
    iden1.setConcat(mat, inverse);
    REPORTER_ASSERT(reporter, is_identity(iden1));
    test_flatten(reporter, mat);

    mat.setScale(SkIntToScalar(3), SkIntToScalar(5), SkIntToScalar(20), 0);
    mat.postRotate(SkIntToScalar(25));
    REPORTER_ASSERT(reporter, mat.invert(NULL));
    mat.invert(&inverse);
    iden1.setConcat(mat, inverse);
    REPORTER_ASSERT(reporter, is_identity(iden1));
    iden2.setConcat(inverse, mat);
    REPORTER_ASSERT(reporter, is_identity(iden2));
    test_flatten(reporter, mat);
    test_flatten(reporter, iden2);

    // rectStaysRect test
    {
        static const struct {
            SkScalar    m00, m01, m10, m11;
            bool        mStaysRect;
        }
        gRectStaysRectSamples[] = {
            {          0,          0,          0,           0, false },
            {          0,          0,          0,  SK_Scalar1, false },
            {          0,          0, SK_Scalar1,           0, false },
            {          0,          0, SK_Scalar1,  SK_Scalar1, false },
            {          0, SK_Scalar1,          0,           0, false },
            {          0, SK_Scalar1,          0,  SK_Scalar1, false },
            {          0, SK_Scalar1, SK_Scalar1,           0, true },
            {          0, SK_Scalar1, SK_Scalar1,  SK_Scalar1, false },
            { SK_Scalar1,          0,          0,           0, false },
            { SK_Scalar1,          0,          0,  SK_Scalar1, true },
            { SK_Scalar1,          0, SK_Scalar1,           0, false },
            { SK_Scalar1,          0, SK_Scalar1,  SK_Scalar1, false },
            { SK_Scalar1, SK_Scalar1,          0,           0, false },
            { SK_Scalar1, SK_Scalar1,          0,  SK_Scalar1, false },
            { SK_Scalar1, SK_Scalar1, SK_Scalar1,           0, false },
            { SK_Scalar1, SK_Scalar1, SK_Scalar1,  SK_Scalar1, false }
        };

        for (size_t i = 0; i < SK_ARRAY_COUNT(gRectStaysRectSamples); i++) {
            SkMatrix    m;

            m.reset();
            m.set(SkMatrix::kMScaleX, gRectStaysRectSamples[i].m00);
            m.set(SkMatrix::kMSkewX,  gRectStaysRectSamples[i].m01);
            m.set(SkMatrix::kMSkewY,  gRectStaysRectSamples[i].m10);
            m.set(SkMatrix::kMScaleY, gRectStaysRectSamples[i].m11);
            REPORTER_ASSERT(reporter,
                    m.rectStaysRect() == gRectStaysRectSamples[i].mStaysRect);
        }
    }

    mat.reset();
    mat.set(SkMatrix::kMScaleX, SkIntToScalar(1));
    mat.set(SkMatrix::kMSkewX,  SkIntToScalar(2));
    mat.set(SkMatrix::kMTransX, SkIntToScalar(3));
    mat.set(SkMatrix::kMSkewY,  SkIntToScalar(4));
    mat.set(SkMatrix::kMScaleY, SkIntToScalar(5));
    mat.set(SkMatrix::kMTransY, SkIntToScalar(6));
    SkScalar affine[6];
    REPORTER_ASSERT(reporter, mat.asAffine(affine));

    #define affineEqual(e) affine[SkMatrix::kA##e] == mat.get(SkMatrix::kM##e)
    REPORTER_ASSERT(reporter, affineEqual(ScaleX));
    REPORTER_ASSERT(reporter, affineEqual(SkewY));
    REPORTER_ASSERT(reporter, affineEqual(SkewX));
    REPORTER_ASSERT(reporter, affineEqual(ScaleY));
    REPORTER_ASSERT(reporter, affineEqual(TransX));
    REPORTER_ASSERT(reporter, affineEqual(TransY));
    #undef affineEqual

    mat.set(SkMatrix::kMPersp1, SkScalarToPersp(SK_Scalar1 / 2));
    REPORTER_ASSERT(reporter, !mat.asAffine(affine));

    SkMatrix mat2;
    mat2.reset();
    mat.reset();
    SkScalar zero = 0;
    mat.set(SkMatrix::kMSkewX, -zero);
    REPORTER_ASSERT(reporter, are_equal(reporter, mat, mat2));

    mat2.reset();
    mat.reset();
    mat.set(SkMatrix::kMSkewX, SK_ScalarNaN);
    mat2.set(SkMatrix::kMSkewX, SK_ScalarNaN);
    // fixed pt doesn't have the property that NaN does not equal itself.
#ifdef SK_SCALAR_IS_FIXED
    REPORTER_ASSERT(reporter, are_equal(reporter, mat, mat2));
#else
    REPORTER_ASSERT(reporter, !are_equal(reporter, mat, mat2));
#endif

    test_matrix_max_stretch(reporter);
}
void TestMatrix(skiatest::Reporter* reporter) {
    SkMatrix    mat, inverse, iden1, iden2;

    mat.reset();
    mat.setTranslate(SK_Scalar1, SK_Scalar1);
    mat.invert(&inverse);
    iden1.setConcat(mat, inverse);
    REPORTER_ASSERT(reporter, is_identity(iden1));

    mat.setScale(SkIntToScalar(2), SkIntToScalar(2));
    mat.invert(&inverse);
    iden1.setConcat(mat, inverse);
    REPORTER_ASSERT(reporter, is_identity(iden1));
    test_flatten(reporter, mat);

    mat.setScale(SK_Scalar1/2, SK_Scalar1/2);
    mat.invert(&inverse);
    iden1.setConcat(mat, inverse);
    REPORTER_ASSERT(reporter, is_identity(iden1));
    test_flatten(reporter, mat);

    mat.setScale(SkIntToScalar(3), SkIntToScalar(5), SkIntToScalar(20), 0);
    mat.postRotate(SkIntToScalar(25));
    REPORTER_ASSERT(reporter, mat.invert(NULL));
    mat.invert(&inverse);
    iden1.setConcat(mat, inverse);
    REPORTER_ASSERT(reporter, is_identity(iden1));
    iden2.setConcat(inverse, mat);
    REPORTER_ASSERT(reporter, is_identity(iden2));
    test_flatten(reporter, mat);
    test_flatten(reporter, iden2);

    // rectStaysRect test
    {
        static const struct {
            SkScalar    m00, m01, m10, m11;
            bool        mStaysRect;
        }
        gRectStaysRectSamples[] = {
            {          0,          0,          0,           0, false },
            {          0,          0,          0,  SK_Scalar1, false },
            {          0,          0, SK_Scalar1,           0, false },
            {          0,          0, SK_Scalar1,  SK_Scalar1, false },
            {          0, SK_Scalar1,          0,           0, false },
            {          0, SK_Scalar1,          0,  SK_Scalar1, false },
            {          0, SK_Scalar1, SK_Scalar1,           0, true },
            {          0, SK_Scalar1, SK_Scalar1,  SK_Scalar1, false },
            { SK_Scalar1,          0,          0,           0, false },
            { SK_Scalar1,          0,          0,  SK_Scalar1, true },
            { SK_Scalar1,          0, SK_Scalar1,           0, false },
            { SK_Scalar1,          0, SK_Scalar1,  SK_Scalar1, false },
            { SK_Scalar1, SK_Scalar1,          0,           0, false },
            { SK_Scalar1, SK_Scalar1,          0,  SK_Scalar1, false },
            { SK_Scalar1, SK_Scalar1, SK_Scalar1,           0, false },
            { SK_Scalar1, SK_Scalar1, SK_Scalar1,  SK_Scalar1, false }
        };

        for (size_t i = 0; i < SK_ARRAY_COUNT(gRectStaysRectSamples); i++) {
            SkMatrix    m;

            m.reset();
            m.set(SkMatrix::kMScaleX, gRectStaysRectSamples[i].m00);
            m.set(SkMatrix::kMSkewX,  gRectStaysRectSamples[i].m01);
            m.set(SkMatrix::kMSkewY,  gRectStaysRectSamples[i].m10);
            m.set(SkMatrix::kMScaleY, gRectStaysRectSamples[i].m11);
            REPORTER_ASSERT(reporter,
                    m.rectStaysRect() == gRectStaysRectSamples[i].mStaysRect);
        }
    }
}