1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/*
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2006 The Android Open Source Project
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com *
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com */
7ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
88a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkMatrix.h"
98a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkFloatBits.h"
108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkString.h"
118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12ada3635c8e83739f45cd52459d3e052783d1a40emtklein#include <stddef.h>
13ada3635c8e83739f45cd52459d3e052783d1a40emtklein
140b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org// In a few places, we performed the following
150b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org//      a * b + c * d + e
160b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org// as
170b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org//      a * b + (c * d + e)
180b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org//
190b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org// sdot and scross are indended to capture these compound operations into a
200b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org// function, with an eye toward considering upscaling the intermediates to
210b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org// doubles for more precision (as we do in concat and invert).
220b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org//
230b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org// However, these few lines that performed the last add before the "dot", cause
240b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org// tiny image differences, so we guard that change until we see the impact on
250b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org// chrome's layouttests.
260b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org//
270b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org#define SK_LEGACY_MATRIX_MATH_ORDER
28ab7ac026d25fcb6e10c042e933f03e5f806c9097reed@android.com
298f4d2306fa866a26f9448048ff63f692b2ba43aareed@google.comstatic inline float SkDoubleToFloat(double x) {
308f4d2306fa866a26f9448048ff63f692b2ba43aareed@google.com    return static_cast<float>(x);
318f4d2306fa866a26f9448048ff63f692b2ba43aareed@google.com}
328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/*      [scale-x    skew-x      trans-x]   [X]   [X']
348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        [skew-y     scale-y     trans-y] * [Y] = [Y']
358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        [persp-0    persp-1     persp-2]   [1]   [1 ]
368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com*/
378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkMatrix::reset() {
390b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    fMat[kMScaleX] = fMat[kMScaleY] = fMat[kMPersp2] = 1;
40fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com    fMat[kMSkewX]  = fMat[kMSkewY] =
418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMat[kMTransX] = fMat[kMTransY] =
428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMat[kMPersp0] = fMat[kMPersp1] = 0;
438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    this->setTypeMask(kIdentity_Mask | kRectStaysRect_Mask);
458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// this guy aligns with the masks, so we can compute a mask from a varaible 0/1
488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comenum {
498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    kTranslate_Shift,
508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    kScale_Shift,
518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    kAffine_Shift,
528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    kPerspective_Shift,
538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    kRectStaysRect_Shift
548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
568f4d2306fa866a26f9448048ff63f692b2ba43aareed@google.comstatic const int32_t kScalar1Int = 0x3f800000;
578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
58dd5f7442f65813c1023a59c3380f4446583ccd5dtomhudson@google.comuint8_t SkMatrix::computePerspectiveTypeMask() const {
596fc5699e777c27c4eea9587a131aecf6e92a677ajunov@chromium.org    // Benchmarking suggests that replacing this set of SkScalarAs2sCompliment
606fc5699e777c27c4eea9587a131aecf6e92a677ajunov@chromium.org    // is a win, but replacing those below is not. We don't yet understand
616fc5699e777c27c4eea9587a131aecf6e92a677ajunov@chromium.org    // that result.
620b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    if (fMat[kMPersp0] != 0 || fMat[kMPersp1] != 0 || fMat[kMPersp2] != 1) {
63fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com        // If this is a perspective transform, we return true for all other
6419263b1e67b31590f9ecb50a1c5bcb6b331c8ef7bsalomon@google.com        // transform flags - this does not disable any optimizations, respects
65fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com        // the rule that the type mask must be conservative, and speeds up
666fc5699e777c27c4eea9587a131aecf6e92a677ajunov@chromium.org        // type mask computation.
676fc5699e777c27c4eea9587a131aecf6e92a677ajunov@chromium.org        return SkToU8(kORableMasks);
68dd5f7442f65813c1023a59c3380f4446583ccd5dtomhudson@google.com    }
69dd5f7442f65813c1023a59c3380f4446583ccd5dtomhudson@google.com
706fc5699e777c27c4eea9587a131aecf6e92a677ajunov@chromium.org    return SkToU8(kOnlyPerspectiveValid_Mask | kUnknown_Mask);
71dd5f7442f65813c1023a59c3380f4446583ccd5dtomhudson@google.com}
72dd5f7442f65813c1023a59c3380f4446583ccd5dtomhudson@google.com
738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comuint8_t SkMatrix::computeTypeMask() const {
748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    unsigned mask = 0;
758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
760b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    if (fMat[kMPersp0] != 0 || fMat[kMPersp1] != 0 || fMat[kMPersp2] != 1) {
776fc5699e777c27c4eea9587a131aecf6e92a677ajunov@chromium.org        // Once it is determined that that this is a perspective transform,
786fc5699e777c27c4eea9587a131aecf6e92a677ajunov@chromium.org        // all other flags are moot as far as optimizations are concerned.
796fc5699e777c27c4eea9587a131aecf6e92a677ajunov@chromium.org        return SkToU8(kORableMasks);
80ac3852571e4079e7dee8fb576e31048d596c8c17tomhudson@google.com    }
81ac3852571e4079e7dee8fb576e31048d596c8c17tomhudson@google.com
82ac3852571e4079e7dee8fb576e31048d596c8c17tomhudson@google.com    if (fMat[kMTransX] != 0 || fMat[kMTransY] != 0) {
83ac3852571e4079e7dee8fb576e31048d596c8c17tomhudson@google.com        mask |= kTranslate_Mask;
84ac3852571e4079e7dee8fb576e31048d596c8c17tomhudson@google.com    }
858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int m00 = SkScalarAs2sCompliment(fMat[SkMatrix::kMScaleX]);
878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int m01 = SkScalarAs2sCompliment(fMat[SkMatrix::kMSkewX]);
888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int m10 = SkScalarAs2sCompliment(fMat[SkMatrix::kMSkewY]);
898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int m11 = SkScalarAs2sCompliment(fMat[SkMatrix::kMScaleY]);
90ac3852571e4079e7dee8fb576e31048d596c8c17tomhudson@google.com
918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (m01 | m10) {
926fc5699e777c27c4eea9587a131aecf6e92a677ajunov@chromium.org        // The skew components may be scale-inducing, unless we are dealing
936fc5699e777c27c4eea9587a131aecf6e92a677ajunov@chromium.org        // with a pure rotation.  Testing for a pure rotation is expensive,
946fc5699e777c27c4eea9587a131aecf6e92a677ajunov@chromium.org        // so we opt for being conservative by always setting the scale bit.
956fc5699e777c27c4eea9587a131aecf6e92a677ajunov@chromium.org        // along with affine.
966fc5699e777c27c4eea9587a131aecf6e92a677ajunov@chromium.org        // By doing this, we are also ensuring that matrices have the same
976fc5699e777c27c4eea9587a131aecf6e92a677ajunov@chromium.org        // type masks as their inverses.
986fc5699e777c27c4eea9587a131aecf6e92a677ajunov@chromium.org        mask |= kAffine_Mask | kScale_Mask;
996fc5699e777c27c4eea9587a131aecf6e92a677ajunov@chromium.org
1006fc5699e777c27c4eea9587a131aecf6e92a677ajunov@chromium.org        // For rectStaysRect, in the affine case, we only need check that
1016fc5699e777c27c4eea9587a131aecf6e92a677ajunov@chromium.org        // the primary diagonal is all zeros and that the secondary diagonal
1026fc5699e777c27c4eea9587a131aecf6e92a677ajunov@chromium.org        // is all non-zero.
1038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // map non-zero to 1
1058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        m01 = m01 != 0;
1068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        m10 = m10 != 0;
107ac3852571e4079e7dee8fb576e31048d596c8c17tomhudson@google.com
1086fc5699e777c27c4eea9587a131aecf6e92a677ajunov@chromium.org        int dp0 = 0 == (m00 | m11) ;  // true if both are 0
1098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int ds1 = m01 & m10;        // true if both are 1
110ac3852571e4079e7dee8fb576e31048d596c8c17tomhudson@google.com
1116fc5699e777c27c4eea9587a131aecf6e92a677ajunov@chromium.org        mask |= (dp0 & ds1) << kRectStaysRect_Shift;
1126fc5699e777c27c4eea9587a131aecf6e92a677ajunov@chromium.org    } else {
1136fc5699e777c27c4eea9587a131aecf6e92a677ajunov@chromium.org        // Only test for scale explicitly if not affine, since affine sets the
1146fc5699e777c27c4eea9587a131aecf6e92a677ajunov@chromium.org        // scale bit.
1156fc5699e777c27c4eea9587a131aecf6e92a677ajunov@chromium.org        if ((m00 - kScalar1Int) | (m11 - kScalar1Int)) {
1166fc5699e777c27c4eea9587a131aecf6e92a677ajunov@chromium.org            mask |= kScale_Mask;
1176fc5699e777c27c4eea9587a131aecf6e92a677ajunov@chromium.org        }
1186fc5699e777c27c4eea9587a131aecf6e92a677ajunov@chromium.org
119fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com        // Not affine, therefore we already know secondary diagonal is
1206fc5699e777c27c4eea9587a131aecf6e92a677ajunov@chromium.org        // all zeros, so we just need to check that primary diagonal is
1216fc5699e777c27c4eea9587a131aecf6e92a677ajunov@chromium.org        // all non-zero.
1226fc5699e777c27c4eea9587a131aecf6e92a677ajunov@chromium.org
1236fc5699e777c27c4eea9587a131aecf6e92a677ajunov@chromium.org        // map non-zero to 1
1246fc5699e777c27c4eea9587a131aecf6e92a677ajunov@chromium.org        m00 = m00 != 0;
1256fc5699e777c27c4eea9587a131aecf6e92a677ajunov@chromium.org        m11 = m11 != 0;
1266fc5699e777c27c4eea9587a131aecf6e92a677ajunov@chromium.org
1276fc5699e777c27c4eea9587a131aecf6e92a677ajunov@chromium.org        // record if the (p)rimary diagonal is all non-zero
1286fc5699e777c27c4eea9587a131aecf6e92a677ajunov@chromium.org        mask |= (m00 & m11) << kRectStaysRect_Shift;
1298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return SkToU8(mask);
1328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com///////////////////////////////////////////////////////////////////////////////
1358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1363fb5187647397e056843c1f41a508992be22175dreed@google.combool operator==(const SkMatrix& a, const SkMatrix& b) {
1373fb5187647397e056843c1f41a508992be22175dreed@google.com    const SkScalar* SK_RESTRICT ma = a.fMat;
1383fb5187647397e056843c1f41a508992be22175dreed@google.com    const SkScalar* SK_RESTRICT mb = b.fMat;
1393fb5187647397e056843c1f41a508992be22175dreed@google.com
1403fb5187647397e056843c1f41a508992be22175dreed@google.com    return  ma[0] == mb[0] && ma[1] == mb[1] && ma[2] == mb[2] &&
1413fb5187647397e056843c1f41a508992be22175dreed@google.com            ma[3] == mb[3] && ma[4] == mb[4] && ma[5] == mb[5] &&
1423fb5187647397e056843c1f41a508992be22175dreed@google.com            ma[6] == mb[6] && ma[7] == mb[7] && ma[8] == mb[8];
1433fb5187647397e056843c1f41a508992be22175dreed@google.com}
1443fb5187647397e056843c1f41a508992be22175dreed@google.com
1453fb5187647397e056843c1f41a508992be22175dreed@google.com///////////////////////////////////////////////////////////////////////////////
1463fb5187647397e056843c1f41a508992be22175dreed@google.com
1474dcd062803fef457899add1df56e9defb667ce8dcommit-bot@chromium.org// helper function to determine if upper-left 2x2 of matrix is degenerate
14816d53aac9c78635b25d930f1c20d677e8fdd29c3skia.committer@gmail.comstatic inline bool is_degenerate_2x2(SkScalar scaleX, SkScalar skewX,
1494dcd062803fef457899add1df56e9defb667ce8dcommit-bot@chromium.org                                     SkScalar skewY,  SkScalar scaleY) {
1504dcd062803fef457899add1df56e9defb667ce8dcommit-bot@chromium.org    SkScalar perp_dot = scaleX*scaleY - skewX*skewY;
1514dcd062803fef457899add1df56e9defb667ce8dcommit-bot@chromium.org    return SkScalarNearlyZero(perp_dot, SK_ScalarNearlyZero*SK_ScalarNearlyZero);
1524dcd062803fef457899add1df56e9defb667ce8dcommit-bot@chromium.org}
1534dcd062803fef457899add1df56e9defb667ce8dcommit-bot@chromium.org
1544dcd062803fef457899add1df56e9defb667ce8dcommit-bot@chromium.org///////////////////////////////////////////////////////////////////////////////
1554dcd062803fef457899add1df56e9defb667ce8dcommit-bot@chromium.org
15646d3d39e65e0b3ea2ad7c91c176ccafb4df0fa24jvanverth@google.combool SkMatrix::isSimilarity(SkScalar tol) const {
15746d3d39e65e0b3ea2ad7c91c176ccafb4df0fa24jvanverth@google.com    // if identity or translate matrix
15846d3d39e65e0b3ea2ad7c91c176ccafb4df0fa24jvanverth@google.com    TypeMask mask = this->getType();
15946d3d39e65e0b3ea2ad7c91c176ccafb4df0fa24jvanverth@google.com    if (mask <= kTranslate_Mask) {
16046d3d39e65e0b3ea2ad7c91c176ccafb4df0fa24jvanverth@google.com        return true;
16146d3d39e65e0b3ea2ad7c91c176ccafb4df0fa24jvanverth@google.com    }
16246d3d39e65e0b3ea2ad7c91c176ccafb4df0fa24jvanverth@google.com    if (mask & kPerspective_Mask) {
16346d3d39e65e0b3ea2ad7c91c176ccafb4df0fa24jvanverth@google.com        return false;
16446d3d39e65e0b3ea2ad7c91c176ccafb4df0fa24jvanverth@google.com    }
16546d3d39e65e0b3ea2ad7c91c176ccafb4df0fa24jvanverth@google.com
16646d3d39e65e0b3ea2ad7c91c176ccafb4df0fa24jvanverth@google.com    SkScalar mx = fMat[kMScaleX];
16746d3d39e65e0b3ea2ad7c91c176ccafb4df0fa24jvanverth@google.com    SkScalar my = fMat[kMScaleY];
16846d3d39e65e0b3ea2ad7c91c176ccafb4df0fa24jvanverth@google.com    // if no skew, can just compare scale factors
16946d3d39e65e0b3ea2ad7c91c176ccafb4df0fa24jvanverth@google.com    if (!(mask & kAffine_Mask)) {
17046d3d39e65e0b3ea2ad7c91c176ccafb4df0fa24jvanverth@google.com        return !SkScalarNearlyZero(mx) && SkScalarNearlyEqual(SkScalarAbs(mx), SkScalarAbs(my));
17146d3d39e65e0b3ea2ad7c91c176ccafb4df0fa24jvanverth@google.com    }
17246d3d39e65e0b3ea2ad7c91c176ccafb4df0fa24jvanverth@google.com    SkScalar sx = fMat[kMSkewX];
17346d3d39e65e0b3ea2ad7c91c176ccafb4df0fa24jvanverth@google.com    SkScalar sy = fMat[kMSkewY];
17446d3d39e65e0b3ea2ad7c91c176ccafb4df0fa24jvanverth@google.com
1754dcd062803fef457899add1df56e9defb667ce8dcommit-bot@chromium.org    if (is_degenerate_2x2(mx, sx, sy, my)) {
17646d3d39e65e0b3ea2ad7c91c176ccafb4df0fa24jvanverth@google.com        return false;
17746d3d39e65e0b3ea2ad7c91c176ccafb4df0fa24jvanverth@google.com    }
17846d3d39e65e0b3ea2ad7c91c176ccafb4df0fa24jvanverth@google.com
17946d3d39e65e0b3ea2ad7c91c176ccafb4df0fa24jvanverth@google.com    // it has scales and skews, but it could also be rotation, check it out.
18046d3d39e65e0b3ea2ad7c91c176ccafb4df0fa24jvanverth@google.com    SkVector vec[2];
18146d3d39e65e0b3ea2ad7c91c176ccafb4df0fa24jvanverth@google.com    vec[0].set(mx, sx);
18246d3d39e65e0b3ea2ad7c91c176ccafb4df0fa24jvanverth@google.com    vec[1].set(sy, my);
18346d3d39e65e0b3ea2ad7c91c176ccafb4df0fa24jvanverth@google.com
18446d3d39e65e0b3ea2ad7c91c176ccafb4df0fa24jvanverth@google.com    return SkScalarNearlyZero(vec[0].dot(vec[1]), SkScalarSquare(tol)) &&
18546d3d39e65e0b3ea2ad7c91c176ccafb4df0fa24jvanverth@google.com           SkScalarNearlyEqual(vec[0].lengthSqd(), vec[1].lengthSqd(),
186df3695e5c72b3b4401e71ff259827d87bfe8a06frobertphillips@google.com                               SkScalarSquare(tol));
187df3695e5c72b3b4401e71ff259827d87bfe8a06frobertphillips@google.com}
188df3695e5c72b3b4401e71ff259827d87bfe8a06frobertphillips@google.com
189df3695e5c72b3b4401e71ff259827d87bfe8a06frobertphillips@google.combool SkMatrix::preservesRightAngles(SkScalar tol) const {
190df3695e5c72b3b4401e71ff259827d87bfe8a06frobertphillips@google.com    TypeMask mask = this->getType();
19107d3a6575b86845ded0d4bd785aec8f4c2cc99dcskia.committer@gmail.com
192df3695e5c72b3b4401e71ff259827d87bfe8a06frobertphillips@google.com    if (mask <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
193df3695e5c72b3b4401e71ff259827d87bfe8a06frobertphillips@google.com        // identity, translate and/or scale
194df3695e5c72b3b4401e71ff259827d87bfe8a06frobertphillips@google.com        return true;
195df3695e5c72b3b4401e71ff259827d87bfe8a06frobertphillips@google.com    }
196df3695e5c72b3b4401e71ff259827d87bfe8a06frobertphillips@google.com    if (mask & kPerspective_Mask) {
197df3695e5c72b3b4401e71ff259827d87bfe8a06frobertphillips@google.com        return false;
198df3695e5c72b3b4401e71ff259827d87bfe8a06frobertphillips@google.com    }
199df3695e5c72b3b4401e71ff259827d87bfe8a06frobertphillips@google.com
200df3695e5c72b3b4401e71ff259827d87bfe8a06frobertphillips@google.com    SkASSERT(mask & kAffine_Mask);
201df3695e5c72b3b4401e71ff259827d87bfe8a06frobertphillips@google.com
202df3695e5c72b3b4401e71ff259827d87bfe8a06frobertphillips@google.com    SkScalar mx = fMat[kMScaleX];
203df3695e5c72b3b4401e71ff259827d87bfe8a06frobertphillips@google.com    SkScalar my = fMat[kMScaleY];
204df3695e5c72b3b4401e71ff259827d87bfe8a06frobertphillips@google.com    SkScalar sx = fMat[kMSkewX];
205df3695e5c72b3b4401e71ff259827d87bfe8a06frobertphillips@google.com    SkScalar sy = fMat[kMSkewY];
206df3695e5c72b3b4401e71ff259827d87bfe8a06frobertphillips@google.com
2074dcd062803fef457899add1df56e9defb667ce8dcommit-bot@chromium.org    if (is_degenerate_2x2(mx, sx, sy, my)) {
208df3695e5c72b3b4401e71ff259827d87bfe8a06frobertphillips@google.com        return false;
209df3695e5c72b3b4401e71ff259827d87bfe8a06frobertphillips@google.com    }
210df3695e5c72b3b4401e71ff259827d87bfe8a06frobertphillips@google.com
211df3695e5c72b3b4401e71ff259827d87bfe8a06frobertphillips@google.com    // it has scales and skews, but it could also be rotation, check it out.
212df3695e5c72b3b4401e71ff259827d87bfe8a06frobertphillips@google.com    SkVector vec[2];
213df3695e5c72b3b4401e71ff259827d87bfe8a06frobertphillips@google.com    vec[0].set(mx, sx);
214df3695e5c72b3b4401e71ff259827d87bfe8a06frobertphillips@google.com    vec[1].set(sy, my);
215df3695e5c72b3b4401e71ff259827d87bfe8a06frobertphillips@google.com
216df3695e5c72b3b4401e71ff259827d87bfe8a06frobertphillips@google.com    return SkScalarNearlyZero(vec[0].dot(vec[1]), SkScalarSquare(tol)) &&
217df3695e5c72b3b4401e71ff259827d87bfe8a06frobertphillips@google.com           SkScalarNearlyEqual(vec[0].lengthSqd(), vec[1].lengthSqd(),
218df3695e5c72b3b4401e71ff259827d87bfe8a06frobertphillips@google.com                               SkScalarSquare(tol));
21946d3d39e65e0b3ea2ad7c91c176ccafb4df0fa24jvanverth@google.com}
22046d3d39e65e0b3ea2ad7c91c176ccafb4df0fa24jvanverth@google.com
22146d3d39e65e0b3ea2ad7c91c176ccafb4df0fa24jvanverth@google.com///////////////////////////////////////////////////////////////////////////////
22246d3d39e65e0b3ea2ad7c91c176ccafb4df0fa24jvanverth@google.com
2230b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.orgstatic inline SkScalar sdot(SkScalar a, SkScalar b, SkScalar c, SkScalar d) {
2240b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    return a * b + c * d;
2250b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org}
2260b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org
2270b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.orgstatic inline SkScalar sdot(SkScalar a, SkScalar b, SkScalar c, SkScalar d,
2280b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org                             SkScalar e, SkScalar f) {
2290b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    return a * b + c * d + e * f;
2300b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org}
2310b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org
2320b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.orgstatic inline SkScalar scross(SkScalar a, SkScalar b, SkScalar c, SkScalar d) {
2330b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    return a * b - c * d;
2340b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org}
2350b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org
2368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkMatrix::setTranslate(SkScalar dx, SkScalar dy) {
237c0784dbd408596aff13a5d97448f7a9e5d3cf7d9reed@google.com    if (dx || dy) {
2388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fMat[kMTransX] = dx;
2398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fMat[kMTransY] = dy;
2408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2410b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org        fMat[kMScaleX] = fMat[kMScaleY] = fMat[kMPersp2] = 1;
242fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com        fMat[kMSkewX]  = fMat[kMSkewY] =
2438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fMat[kMPersp0] = fMat[kMPersp1] = 0;
2448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        this->setTypeMask(kTranslate_Mask | kRectStaysRect_Mask);
2468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } else {
2478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        this->reset();
2488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
2498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
2508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
25192362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.orgvoid SkMatrix::preTranslate(SkScalar dx, SkScalar dy) {
25292362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org    if (!dx && !dy) {
25392362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org        return;
25492362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org    }
25592362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org
2568d430185e08d2067584837a76b7193b803fee7a0tomhudson@google.com    if (this->hasPerspective()) {
2578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkMatrix    m;
2588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        m.setTranslate(dx, dy);
25992362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org        this->preConcat(m);
26092362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org    } else {
2610b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org        fMat[kMTransX] += sdot(fMat[kMScaleX], dx, fMat[kMSkewX], dy);
2620b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org        fMat[kMTransY] += sdot(fMat[kMSkewY], dx, fMat[kMScaleY], dy);
263dd5f7442f65813c1023a59c3380f4446583ccd5dtomhudson@google.com        this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
2648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
2658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
2668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
26792362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.orgvoid SkMatrix::postTranslate(SkScalar dx, SkScalar dy) {
26892362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org    if (!dx && !dy) {
26992362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org        return;
27092362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org    }
27192362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org
2728d430185e08d2067584837a76b7193b803fee7a0tomhudson@google.com    if (this->hasPerspective()) {
2738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkMatrix    m;
2748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        m.setTranslate(dx, dy);
27592362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org        this->postConcat(m);
27692362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org    } else {
2778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fMat[kMTransX] += dx;
2788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fMat[kMTransY] += dy;
279dd5f7442f65813c1023a59c3380f4446583ccd5dtomhudson@google.com        this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
2808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
2818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
2828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com///////////////////////////////////////////////////////////////////////////////
2848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkMatrix::setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
2860b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    if (1 == sx && 1 == sy) {
287f244f901a9b76b75447e74cefd077ccf16eb8f40reed@google.com        this->reset();
288f244f901a9b76b75447e74cefd077ccf16eb8f40reed@google.com    } else {
289f244f901a9b76b75447e74cefd077ccf16eb8f40reed@google.com        fMat[kMScaleX] = sx;
290f244f901a9b76b75447e74cefd077ccf16eb8f40reed@google.com        fMat[kMScaleY] = sy;
2910b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org        fMat[kMTransX] = px - sx * px;
2920b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org        fMat[kMTransY] = py - sy * py;
2930b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org        fMat[kMPersp2] = 1;
2948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
295fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com        fMat[kMSkewX]  = fMat[kMSkewY] =
296f244f901a9b76b75447e74cefd077ccf16eb8f40reed@google.com        fMat[kMPersp0] = fMat[kMPersp1] = 0;
297fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
298f244f901a9b76b75447e74cefd077ccf16eb8f40reed@google.com        this->setTypeMask(kScale_Mask | kTranslate_Mask | kRectStaysRect_Mask);
299f244f901a9b76b75447e74cefd077ccf16eb8f40reed@google.com    }
3008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
3018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkMatrix::setScale(SkScalar sx, SkScalar sy) {
3030b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    if (1 == sx && 1 == sy) {
304f244f901a9b76b75447e74cefd077ccf16eb8f40reed@google.com        this->reset();
305f244f901a9b76b75447e74cefd077ccf16eb8f40reed@google.com    } else {
306f244f901a9b76b75447e74cefd077ccf16eb8f40reed@google.com        fMat[kMScaleX] = sx;
307f244f901a9b76b75447e74cefd077ccf16eb8f40reed@google.com        fMat[kMScaleY] = sy;
3080b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org        fMat[kMPersp2] = 1;
3098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
310f244f901a9b76b75447e74cefd077ccf16eb8f40reed@google.com        fMat[kMTransX] = fMat[kMTransY] =
311fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com        fMat[kMSkewX]  = fMat[kMSkewY] =
312f244f901a9b76b75447e74cefd077ccf16eb8f40reed@google.com        fMat[kMPersp0] = fMat[kMPersp1] = 0;
3138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
314f244f901a9b76b75447e74cefd077ccf16eb8f40reed@google.com        this->setTypeMask(kScale_Mask | kRectStaysRect_Mask);
315f244f901a9b76b75447e74cefd077ccf16eb8f40reed@google.com    }
3168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
3178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3185c63865b529eb5714e41419dfa23c70d26ff6e4ebsalomon@google.combool SkMatrix::setIDiv(int divx, int divy) {
3195c63865b529eb5714e41419dfa23c70d26ff6e4ebsalomon@google.com    if (!divx || !divy) {
3205c63865b529eb5714e41419dfa23c70d26ff6e4ebsalomon@google.com        return false;
3215c63865b529eb5714e41419dfa23c70d26ff6e4ebsalomon@google.com    }
3220b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    this->setScale(SkScalarInvert(divx), SkScalarInvert(divy));
3235c63865b529eb5714e41419dfa23c70d26ff6e4ebsalomon@google.com    return true;
3245c63865b529eb5714e41419dfa23c70d26ff6e4ebsalomon@google.com}
3255c63865b529eb5714e41419dfa23c70d26ff6e4ebsalomon@google.com
32692362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.orgvoid SkMatrix::preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
32792362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org    if (1 == sx && 1 == sy) {
32892362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org        return;
32992362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org    }
33092362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org
3318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkMatrix    m;
3328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    m.setScale(sx, sy, px, py);
33392362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org    this->preConcat(m);
3348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
3358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
33692362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.orgvoid SkMatrix::preScale(SkScalar sx, SkScalar sy) {
3370b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    if (1 == sx && 1 == sy) {
33892362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org        return;
339f244f901a9b76b75447e74cefd077ccf16eb8f40reed@google.com    }
340f244f901a9b76b75447e74cefd077ccf16eb8f40reed@google.com
3413fb5187647397e056843c1f41a508992be22175dreed@google.com    // the assumption is that these multiplies are very cheap, and that
3423fb5187647397e056843c1f41a508992be22175dreed@google.com    // a full concat and/or just computing the matrix type is more expensive.
3433fb5187647397e056843c1f41a508992be22175dreed@google.com    // Also, the fixed-point case checks for overflow, but the float doesn't,
3443fb5187647397e056843c1f41a508992be22175dreed@google.com    // so we can get away with these blind multiplies.
3453fb5187647397e056843c1f41a508992be22175dreed@google.com
3460b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    fMat[kMScaleX] *= sx;
3470b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    fMat[kMSkewY]  *= sx;
3480b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    fMat[kMPersp0] *= sx;
3493fb5187647397e056843c1f41a508992be22175dreed@google.com
3500b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    fMat[kMSkewX]  *= sy;
3510b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    fMat[kMScaleY] *= sy;
3520b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    fMat[kMPersp1] *= sy;
3533fb5187647397e056843c1f41a508992be22175dreed@google.com
3543fb5187647397e056843c1f41a508992be22175dreed@google.com    this->orTypeMask(kScale_Mask);
3558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
3568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
35792362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.orgvoid SkMatrix::postScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
3580b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    if (1 == sx && 1 == sy) {
35992362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org        return;
360f244f901a9b76b75447e74cefd077ccf16eb8f40reed@google.com    }
3618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkMatrix    m;
3628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    m.setScale(sx, sy, px, py);
36392362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org    this->postConcat(m);
3648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
3658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
36692362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.orgvoid SkMatrix::postScale(SkScalar sx, SkScalar sy) {
3670b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    if (1 == sx && 1 == sy) {
36892362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org        return;
369f244f901a9b76b75447e74cefd077ccf16eb8f40reed@google.com    }
3708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkMatrix    m;
3718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    m.setScale(sx, sy);
37292362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org    this->postConcat(m);
3738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
3748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// this guy perhaps can go away, if we have a fract/high-precision way to
3768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// scale matrices
3778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkMatrix::postIDiv(int divx, int divy) {
3788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (divx == 0 || divy == 0) {
3798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
3808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
3818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const float invX = 1.f / divx;
3838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const float invY = 1.f / divy;
3848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMat[kMScaleX] *= invX;
3868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMat[kMSkewX]  *= invX;
3878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMat[kMTransX] *= invX;
388fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
3898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMat[kMScaleY] *= invY;
3908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMat[kMSkewY]  *= invY;
3918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMat[kMTransY] *= invY;
3928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    this->setTypeMask(kUnknown_Mask);
3948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return true;
3958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
3968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com////////////////////////////////////////////////////////////////////////////////////
3988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkMatrix::setSinCos(SkScalar sinV, SkScalar cosV,
4008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                         SkScalar px, SkScalar py) {
4010b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    const SkScalar oneMinusCosV = 1 - cosV;
4028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMat[kMScaleX]  = cosV;
4048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMat[kMSkewX]   = -sinV;
4050b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    fMat[kMTransX]  = sdot(sinV, py, oneMinusCosV, px);
4068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMat[kMSkewY]   = sinV;
4088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMat[kMScaleY]  = cosV;
4090b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    fMat[kMTransY]  = sdot(-sinV, px, oneMinusCosV, py);
4108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMat[kMPersp0] = fMat[kMPersp1] = 0;
4120b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    fMat[kMPersp2] = 1;
413fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
414dd5f7442f65813c1023a59c3380f4446583ccd5dtomhudson@google.com    this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
4158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkMatrix::setSinCos(SkScalar sinV, SkScalar cosV) {
4188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMat[kMScaleX]  = cosV;
4198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMat[kMSkewX]   = -sinV;
4208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMat[kMTransX]  = 0;
4218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMat[kMSkewY]   = sinV;
4238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMat[kMScaleY]  = cosV;
4248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMat[kMTransY]  = 0;
4258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMat[kMPersp0] = fMat[kMPersp1] = 0;
4270b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    fMat[kMPersp2] = 1;
4288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
429dd5f7442f65813c1023a59c3380f4446583ccd5dtomhudson@google.com    this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
4308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkMatrix::setRotate(SkScalar degrees, SkScalar px, SkScalar py) {
4338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkScalar sinV, cosV;
4348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    sinV = SkScalarSinCos(SkDegreesToRadians(degrees), &cosV);
4358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    this->setSinCos(sinV, cosV, px, py);
4368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkMatrix::setRotate(SkScalar degrees) {
4398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkScalar sinV, cosV;
4408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    sinV = SkScalarSinCos(SkDegreesToRadians(degrees), &cosV);
4418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    this->setSinCos(sinV, cosV);
4428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
44492362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.orgvoid SkMatrix::preRotate(SkScalar degrees, SkScalar px, SkScalar py) {
4458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkMatrix    m;
4468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    m.setRotate(degrees, px, py);
44792362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org    this->preConcat(m);
4488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
45092362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.orgvoid SkMatrix::preRotate(SkScalar degrees) {
4518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkMatrix    m;
4528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    m.setRotate(degrees);
45392362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org    this->preConcat(m);
4548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
45692362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.orgvoid SkMatrix::postRotate(SkScalar degrees, SkScalar px, SkScalar py) {
4578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkMatrix    m;
4588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    m.setRotate(degrees, px, py);
45992362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org    this->postConcat(m);
4608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
46292362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.orgvoid SkMatrix::postRotate(SkScalar degrees) {
4638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkMatrix    m;
4648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    m.setRotate(degrees);
46592362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org    this->postConcat(m);
4668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com////////////////////////////////////////////////////////////////////////////////////
4698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkMatrix::setSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
4710b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    fMat[kMScaleX]  = 1;
4728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMat[kMSkewX]   = sx;
4730b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    fMat[kMTransX]  = -sx * py;
4748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMat[kMSkewY]   = sy;
4760b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    fMat[kMScaleY]  = 1;
4770b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    fMat[kMTransY]  = -sy * px;
4788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMat[kMPersp0] = fMat[kMPersp1] = 0;
4800b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    fMat[kMPersp2] = 1;
4818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
482dd5f7442f65813c1023a59c3380f4446583ccd5dtomhudson@google.com    this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
4838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkMatrix::setSkew(SkScalar sx, SkScalar sy) {
4860b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    fMat[kMScaleX]  = 1;
4878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMat[kMSkewX]   = sx;
4888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMat[kMTransX]  = 0;
4898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMat[kMSkewY]   = sy;
4910b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    fMat[kMScaleY]  = 1;
4928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMat[kMTransY]  = 0;
4938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMat[kMPersp0] = fMat[kMPersp1] = 0;
4950b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    fMat[kMPersp2] = 1;
4968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
497dd5f7442f65813c1023a59c3380f4446583ccd5dtomhudson@google.com    this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
4988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
50092362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.orgvoid SkMatrix::preSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
5018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkMatrix    m;
5028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    m.setSkew(sx, sy, px, py);
50392362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org    this->preConcat(m);
5048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
5058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
50692362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.orgvoid SkMatrix::preSkew(SkScalar sx, SkScalar sy) {
5078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkMatrix    m;
5088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    m.setSkew(sx, sy);
50992362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org    this->preConcat(m);
5108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
5118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
51292362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.orgvoid SkMatrix::postSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
5138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkMatrix    m;
5148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    m.setSkew(sx, sy, px, py);
51592362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org    this->postConcat(m);
5168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
5178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
51892362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.orgvoid SkMatrix::postSkew(SkScalar sx, SkScalar sy) {
5198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkMatrix    m;
5208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    m.setSkew(sx, sy);
52192362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org    this->postConcat(m);
5228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
5238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com///////////////////////////////////////////////////////////////////////////////
5258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkMatrix::setRectToRect(const SkRect& src, const SkRect& dst,
5278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                             ScaleToFit align)
5288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
5298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (src.isEmpty()) {
5308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        this->reset();
5318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
5328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
5338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (dst.isEmpty()) {
5354516f4786f5dda1b86a8f825b9e8e910d9c2363creed@android.com        sk_bzero(fMat, 8 * sizeof(SkScalar));
5368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        this->setTypeMask(kScale_Mask | kRectStaysRect_Mask);
5378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } else {
5380b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org        SkScalar    tx, sx = dst.width() / src.width();
5390b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org        SkScalar    ty, sy = dst.height() / src.height();
5408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        bool        xLarger = false;
5418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (align != kFill_ScaleToFit) {
5438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (sx > sy) {
5448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                xLarger = true;
5458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                sx = sy;
5468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            } else {
5478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                sy = sx;
5488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
5498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
5508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5510b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org        tx = dst.fLeft - src.fLeft * sx;
5520b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org        ty = dst.fTop - src.fTop * sy;
5538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (align == kCenter_ScaleToFit || align == kEnd_ScaleToFit) {
5548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkScalar diff;
5558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (xLarger) {
5570b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org                diff = dst.width() - src.width() * sy;
5588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            } else {
5590b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org                diff = dst.height() - src.height() * sy;
5608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
561fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
5628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (align == kCenter_ScaleToFit) {
5638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                diff = SkScalarHalf(diff);
5648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
5658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (xLarger) {
5678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                tx += diff;
5688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            } else {
5698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                ty += diff;
5708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
5718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
5728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fMat[kMScaleX] = sx;
5748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fMat[kMScaleY] = sy;
5758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fMat[kMTransX] = tx;
5768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fMat[kMTransY] = ty;
577fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com        fMat[kMSkewX]  = fMat[kMSkewY] =
5788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fMat[kMPersp0] = fMat[kMPersp1] = 0;
5798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
58097cd69ca23b27d88e08727366c29c1147eb564dereed@google.com        unsigned mask = kRectStaysRect_Mask;
5810b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org        if (sx != 1 || sy != 1) {
58297cd69ca23b27d88e08727366c29c1147eb564dereed@google.com            mask |= kScale_Mask;
58397cd69ca23b27d88e08727366c29c1147eb564dereed@google.com        }
58497cd69ca23b27d88e08727366c29c1147eb564dereed@google.com        if (tx || ty) {
58597cd69ca23b27d88e08727366c29c1147eb564dereed@google.com            mask |= kTranslate_Mask;
58697cd69ca23b27d88e08727366c29c1147eb564dereed@google.com        }
58797cd69ca23b27d88e08727366c29c1147eb564dereed@google.com        this->setTypeMask(mask);
5888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
5898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // shared cleanup
5900b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    fMat[kMPersp2] = 1;
5918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return true;
5928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
5938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com///////////////////////////////////////////////////////////////////////////////
5958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
59692362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.orgstatic inline float muladdmul(float a, float b, float c, float d) {
59792362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org    return SkDoubleToFloat((double)a * b + (double)c * d);
5988f4d2306fa866a26f9448048ff63f692b2ba43aareed@google.com}
5998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
60092362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.orgstatic inline float rowcol3(const float row[], const float col[]) {
60192362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org    return row[0] * col[0] + row[1] * col[3] + row[2] * col[6];
6028f4d2306fa866a26f9448048ff63f692b2ba43aareed@google.com}
6038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void normalize_perspective(SkScalar mat[9]) {
6050b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    if (SkScalarAbs(mat[SkMatrix::kMPersp2]) > 1) {
6068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        for (int i = 0; i < 9; i++)
6078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            mat[i] = SkScalarHalf(mat[i]);
6088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
6098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
6108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
61192362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.orgvoid SkMatrix::setConcat(const SkMatrix& a, const SkMatrix& b) {
612dd5f7442f65813c1023a59c3380f4446583ccd5dtomhudson@google.com    TypeMask aType = a.getPerspectiveTypeMaskOnly();
613dd5f7442f65813c1023a59c3380f4446583ccd5dtomhudson@google.com    TypeMask bType = b.getPerspectiveTypeMaskOnly();
6148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
615dd5f7442f65813c1023a59c3380f4446583ccd5dtomhudson@google.com    if (a.isTriviallyIdentity()) {
6168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        *this = b;
617dd5f7442f65813c1023a59c3380f4446583ccd5dtomhudson@google.com    } else if (b.isTriviallyIdentity()) {
6188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        *this = a;
6198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } else {
6208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkMatrix tmp;
6218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if ((aType | bType) & kPerspective_Mask) {
62392362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org            tmp.fMat[kMScaleX] = rowcol3(&a.fMat[0], &b.fMat[0]);
62492362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org            tmp.fMat[kMSkewX]  = rowcol3(&a.fMat[0], &b.fMat[1]);
62592362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org            tmp.fMat[kMTransX] = rowcol3(&a.fMat[0], &b.fMat[2]);
62692362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org            tmp.fMat[kMSkewY]  = rowcol3(&a.fMat[3], &b.fMat[0]);
62792362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org            tmp.fMat[kMScaleY] = rowcol3(&a.fMat[3], &b.fMat[1]);
62892362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org            tmp.fMat[kMTransY] = rowcol3(&a.fMat[3], &b.fMat[2]);
62992362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org            tmp.fMat[kMPersp0] = rowcol3(&a.fMat[6], &b.fMat[0]);
63092362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org            tmp.fMat[kMPersp1] = rowcol3(&a.fMat[6], &b.fMat[1]);
63192362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org            tmp.fMat[kMPersp2] = rowcol3(&a.fMat[6], &b.fMat[2]);
6328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            normalize_perspective(tmp.fMat);
634dd5f7442f65813c1023a59c3380f4446583ccd5dtomhudson@google.com            tmp.setTypeMask(kUnknown_Mask);
6358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        } else {    // not perspective
63692362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org            tmp.fMat[kMScaleX] = muladdmul(a.fMat[kMScaleX],
63792362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org                                           b.fMat[kMScaleX],
63892362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org                                           a.fMat[kMSkewX],
63992362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org                                           b.fMat[kMSkewY]);
64092362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org
64192362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org            tmp.fMat[kMSkewX]  = muladdmul(a.fMat[kMScaleX],
64292362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org                                           b.fMat[kMSkewX],
64392362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org                                           a.fMat[kMSkewX],
64492362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org                                           b.fMat[kMScaleY]);
64592362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org
64692362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org            tmp.fMat[kMTransX] = muladdmul(a.fMat[kMScaleX],
64792362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org                                           b.fMat[kMTransX],
64892362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org                                           a.fMat[kMSkewX],
64992362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org                                           b.fMat[kMTransY]);
65092362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org
65192362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org            tmp.fMat[kMTransX] += a.fMat[kMTransX];
65292362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org
65392362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org            tmp.fMat[kMSkewY]  = muladdmul(a.fMat[kMSkewY],
65492362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org                                           b.fMat[kMScaleX],
65592362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org                                           a.fMat[kMScaleY],
65692362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org                                           b.fMat[kMSkewY]);
65792362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org
65892362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org            tmp.fMat[kMScaleY] = muladdmul(a.fMat[kMSkewY],
65992362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org                                           b.fMat[kMSkewX],
66092362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org                                           a.fMat[kMScaleY],
66192362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org                                           b.fMat[kMScaleY]);
66292362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org
66392362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org            tmp.fMat[kMTransY] = muladdmul(a.fMat[kMSkewY],
66492362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org                                           b.fMat[kMTransX],
66592362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org                                           a.fMat[kMScaleY],
66692362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org                                           b.fMat[kMTransY]);
66792362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org
66892362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org            tmp.fMat[kMTransY] += a.fMat[kMTransY];
6698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            tmp.fMat[kMPersp0] = tmp.fMat[kMPersp1] = 0;
6700b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org            tmp.fMat[kMPersp2] = 1;
671dd5f7442f65813c1023a59c3380f4446583ccd5dtomhudson@google.com            //SkDebugf("Concat mat non-persp type: %d\n", tmp.getType());
672dd5f7442f65813c1023a59c3380f4446583ccd5dtomhudson@google.com            //SkASSERT(!(tmp.getType() & kPerspective_Mask));
673dd5f7442f65813c1023a59c3380f4446583ccd5dtomhudson@google.com            tmp.setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
6748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
6758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        *this = tmp;
6768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
6778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
6788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
67992362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.orgvoid SkMatrix::preConcat(const SkMatrix& mat) {
6808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // check for identity first, so we don't do a needless copy of ourselves
6818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // to ourselves inside setConcat()
68292362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org    if(!mat.isIdentity()) {
68392362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org        this->setConcat(*this, mat);
68492362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org    }
6858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
6868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
68792362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.orgvoid SkMatrix::postConcat(const SkMatrix& mat) {
6888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // check for identity first, so we don't do a needless copy of ourselves
6898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // to ourselves inside setConcat()
69092362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org    if (!mat.isIdentity()) {
69192362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org        this->setConcat(mat, *this);
69292362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org    }
6938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
6948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com///////////////////////////////////////////////////////////////////////////////
6968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6970b9e2dbf2f51ac41439db2052cf80704d60932f4reed@android.com/*  Matrix inversion is very expensive, but also the place where keeping
6980b9e2dbf2f51ac41439db2052cf80704d60932f4reed@android.com    precision may be most important (here and matrix concat). Hence to avoid
6990b9e2dbf2f51ac41439db2052cf80704d60932f4reed@android.com    bitmap blitting artifacts when walking the inverse, we use doubles for
7000b9e2dbf2f51ac41439db2052cf80704d60932f4reed@android.com    the intermediate math, even though we know that is more expensive.
7010b9e2dbf2f51ac41439db2052cf80704d60932f4reed@android.com */
7020b9e2dbf2f51ac41439db2052cf80704d60932f4reed@android.com
7030b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.orgstatic inline SkScalar scross_dscale(SkScalar a, SkScalar b,
7040b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org                                     SkScalar c, SkScalar d, double scale) {
7050b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    return SkDoubleToScalar(scross(a, b, c, d) * scale);
7060b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org}
7070b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org
7080b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.orgstatic inline double dcross(double a, double b, double c, double d) {
7090b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    return a * b - c * d;
7100b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org}
7110b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org
7120b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.orgstatic inline SkScalar dcross_dscale(double a, double b,
7130b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org                                     double c, double d, double scale) {
7140b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    return SkDoubleToScalar(dcross(a, b, c, d) * scale);
7150b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org}
7160b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org
7170b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.orgstatic double sk_inv_determinant(const float mat[9], int isPerspective) {
7188f4d2306fa866a26f9448048ff63f692b2ba43aareed@google.com    double det;
7198f4d2306fa866a26f9448048ff63f692b2ba43aareed@google.com
7208f4d2306fa866a26f9448048ff63f692b2ba43aareed@google.com    if (isPerspective) {
7210b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org        det = mat[SkMatrix::kMScaleX] *
7220b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org              dcross(mat[SkMatrix::kMScaleY], mat[SkMatrix::kMPersp2],
7230b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org                     mat[SkMatrix::kMTransY], mat[SkMatrix::kMPersp1])
7240b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org              +
7250b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org              mat[SkMatrix::kMSkewX]  *
7260b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org              dcross(mat[SkMatrix::kMTransY], mat[SkMatrix::kMPersp0],
7270b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org                     mat[SkMatrix::kMSkewY],  mat[SkMatrix::kMPersp2])
7280b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org              +
7290b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org              mat[SkMatrix::kMTransX] *
7300b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org              dcross(mat[SkMatrix::kMSkewY],  mat[SkMatrix::kMPersp1],
7310b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org                     mat[SkMatrix::kMScaleY], mat[SkMatrix::kMPersp0]);
7328f4d2306fa866a26f9448048ff63f692b2ba43aareed@google.com    } else {
7330b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org        det = dcross(mat[SkMatrix::kMScaleX], mat[SkMatrix::kMScaleY],
7340b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org                     mat[SkMatrix::kMSkewX], mat[SkMatrix::kMSkewY]);
7358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
7368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7378f4d2306fa866a26f9448048ff63f692b2ba43aareed@google.com    // Since the determinant is on the order of the cube of the matrix members,
7388f4d2306fa866a26f9448048ff63f692b2ba43aareed@google.com    // compare to the cube of the default nearly-zero constant (although an
7398f4d2306fa866a26f9448048ff63f692b2ba43aareed@google.com    // estimate of the condition number would be better if it wasn't so expensive).
7408f4d2306fa866a26f9448048ff63f692b2ba43aareed@google.com    if (SkScalarNearlyZero((float)det, SK_ScalarNearlyZero * SK_ScalarNearlyZero * SK_ScalarNearlyZero)) {
7418f4d2306fa866a26f9448048ff63f692b2ba43aareed@google.com        return 0;
7428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
7438f4d2306fa866a26f9448048ff63f692b2ba43aareed@google.com    return 1.0 / det;
7448f4d2306fa866a26f9448048ff63f692b2ba43aareed@google.com}
7458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7461ddd7c39289b7dd18537fdac4b630e378cd78842bungeman@google.comvoid SkMatrix::SetAffineIdentity(SkScalar affine[6]) {
7470b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    affine[kAScaleX] = 1;
7481ddd7c39289b7dd18537fdac4b630e378cd78842bungeman@google.com    affine[kASkewY] = 0;
7491ddd7c39289b7dd18537fdac4b630e378cd78842bungeman@google.com    affine[kASkewX] = 0;
7500b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    affine[kAScaleY] = 1;
7511ddd7c39289b7dd18537fdac4b630e378cd78842bungeman@google.com    affine[kATransX] = 0;
7521ddd7c39289b7dd18537fdac4b630e378cd78842bungeman@google.com    affine[kATransY] = 0;
7531ddd7c39289b7dd18537fdac4b630e378cd78842bungeman@google.com}
7541ddd7c39289b7dd18537fdac4b630e378cd78842bungeman@google.com
7551ddd7c39289b7dd18537fdac4b630e378cd78842bungeman@google.combool SkMatrix::asAffine(SkScalar affine[6]) const {
7568d430185e08d2067584837a76b7193b803fee7a0tomhudson@google.com    if (this->hasPerspective()) {
7571ddd7c39289b7dd18537fdac4b630e378cd78842bungeman@google.com        return false;
7581ddd7c39289b7dd18537fdac4b630e378cd78842bungeman@google.com    }
7591ddd7c39289b7dd18537fdac4b630e378cd78842bungeman@google.com    if (affine) {
7601ddd7c39289b7dd18537fdac4b630e378cd78842bungeman@google.com        affine[kAScaleX] = this->fMat[kMScaleX];
7611ddd7c39289b7dd18537fdac4b630e378cd78842bungeman@google.com        affine[kASkewY] = this->fMat[kMSkewY];
7621ddd7c39289b7dd18537fdac4b630e378cd78842bungeman@google.com        affine[kASkewX] = this->fMat[kMSkewX];
7631ddd7c39289b7dd18537fdac4b630e378cd78842bungeman@google.com        affine[kAScaleY] = this->fMat[kMScaleY];
7641ddd7c39289b7dd18537fdac4b630e378cd78842bungeman@google.com        affine[kATransX] = this->fMat[kMTransX];
7651ddd7c39289b7dd18537fdac4b630e378cd78842bungeman@google.com        affine[kATransY] = this->fMat[kMTransY];
7661ddd7c39289b7dd18537fdac4b630e378cd78842bungeman@google.com    }
767ddbbd805b5b453e12cda0b3300e5655d8fb2bc19vandebo@chromium.org    return true;
768ddbbd805b5b453e12cda0b3300e5655d8fb2bc19vandebo@chromium.org}
769ddbbd805b5b453e12cda0b3300e5655d8fb2bc19vandebo@chromium.org
770683c3c76cfd2cc71621e570889a16548f8cc88c6bsalomon@google.combool SkMatrix::invertNonIdentity(SkMatrix* inv) const {
771683c3c76cfd2cc71621e570889a16548f8cc88c6bsalomon@google.com    SkASSERT(!this->isIdentity());
7722fb96cc5d713451216bd63d5dc8d19abc8550730reed@google.com
7732fb96cc5d713451216bd63d5dc8d19abc8550730reed@google.com    TypeMask mask = this->getType();
7742fb96cc5d713451216bd63d5dc8d19abc8550730reed@google.com
7752fb96cc5d713451216bd63d5dc8d19abc8550730reed@google.com    if (0 == (mask & ~(kScale_Mask | kTranslate_Mask))) {
776e40591d5484762067f976d979c506f126c7779e1reed@google.com        bool invertible = true;
7772fb96cc5d713451216bd63d5dc8d19abc8550730reed@google.com        if (inv) {
7782fb96cc5d713451216bd63d5dc8d19abc8550730reed@google.com            if (mask & kScale_Mask) {
7792fb96cc5d713451216bd63d5dc8d19abc8550730reed@google.com                SkScalar invX = fMat[kMScaleX];
7802fb96cc5d713451216bd63d5dc8d19abc8550730reed@google.com                SkScalar invY = fMat[kMScaleY];
7812fb96cc5d713451216bd63d5dc8d19abc8550730reed@google.com                if (0 == invX || 0 == invY) {
7822fb96cc5d713451216bd63d5dc8d19abc8550730reed@google.com                    return false;
7832fb96cc5d713451216bd63d5dc8d19abc8550730reed@google.com                }
7842fb96cc5d713451216bd63d5dc8d19abc8550730reed@google.com                invX = SkScalarInvert(invX);
7852fb96cc5d713451216bd63d5dc8d19abc8550730reed@google.com                invY = SkScalarInvert(invY);
7862fb96cc5d713451216bd63d5dc8d19abc8550730reed@google.com
7872fb96cc5d713451216bd63d5dc8d19abc8550730reed@google.com                // Must be careful when writing to inv, since it may be the
7882fb96cc5d713451216bd63d5dc8d19abc8550730reed@google.com                // same memory as this.
7892fb96cc5d713451216bd63d5dc8d19abc8550730reed@google.com
7902fb96cc5d713451216bd63d5dc8d19abc8550730reed@google.com                inv->fMat[kMSkewX] = inv->fMat[kMSkewY] =
7912fb96cc5d713451216bd63d5dc8d19abc8550730reed@google.com                inv->fMat[kMPersp0] = inv->fMat[kMPersp1] = 0;
7922fb96cc5d713451216bd63d5dc8d19abc8550730reed@google.com
7932fb96cc5d713451216bd63d5dc8d19abc8550730reed@google.com                inv->fMat[kMScaleX] = invX;
7942fb96cc5d713451216bd63d5dc8d19abc8550730reed@google.com                inv->fMat[kMScaleY] = invY;
7950b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org                inv->fMat[kMPersp2] = 1;
7960b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org                inv->fMat[kMTransX] = -fMat[kMTransX] * invX;
7970b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org                inv->fMat[kMTransY] = -fMat[kMTransY] * invY;
7982fb96cc5d713451216bd63d5dc8d19abc8550730reed@google.com
7992fb96cc5d713451216bd63d5dc8d19abc8550730reed@google.com                inv->setTypeMask(mask | kRectStaysRect_Mask);
8002fb96cc5d713451216bd63d5dc8d19abc8550730reed@google.com            } else {
8012fb96cc5d713451216bd63d5dc8d19abc8550730reed@google.com                // translate only
8022fb96cc5d713451216bd63d5dc8d19abc8550730reed@google.com                inv->setTranslate(-fMat[kMTransX], -fMat[kMTransY]);
8032fb96cc5d713451216bd63d5dc8d19abc8550730reed@google.com            }
804e40591d5484762067f976d979c506f126c7779e1reed@google.com        } else {    // inv is NULL, just check if we're invertible
805e40591d5484762067f976d979c506f126c7779e1reed@google.com            if (!fMat[kMScaleX] || !fMat[kMScaleY]) {
806e40591d5484762067f976d979c506f126c7779e1reed@google.com                invertible = false;
807e40591d5484762067f976d979c506f126c7779e1reed@google.com            }
8082fb96cc5d713451216bd63d5dc8d19abc8550730reed@google.com        }
809e40591d5484762067f976d979c506f126c7779e1reed@google.com        return invertible;
8102fb96cc5d713451216bd63d5dc8d19abc8550730reed@google.com    }
8114a1362a3c91ae9461a54bf1b04c250b0aa145db4reed@google.com
8120b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    int    isPersp = mask & kPerspective_Mask;
8130b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    double scale = sk_inv_determinant(fMat, isPersp);
8148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (scale == 0) { // underflow
8168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
8178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
8188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (inv) {
8208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkMatrix tmp;
821cf9b7505f22aedde30612655e16f330f19ba2470bsalomon@google.com        if (inv == this) {
8228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            inv = &tmp;
823cf9b7505f22aedde30612655e16f330f19ba2470bsalomon@google.com        }
8248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (isPersp) {
8260b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org            inv->fMat[kMScaleX] = scross_dscale(fMat[kMScaleY], fMat[kMPersp2], fMat[kMTransY], fMat[kMPersp1], scale);
8270b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org            inv->fMat[kMSkewX]  = scross_dscale(fMat[kMTransX], fMat[kMPersp1], fMat[kMSkewX],  fMat[kMPersp2], scale);
8280b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org            inv->fMat[kMTransX] = scross_dscale(fMat[kMSkewX],  fMat[kMTransY], fMat[kMTransX], fMat[kMScaleY], scale);
8290b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org
8300b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org            inv->fMat[kMSkewY]  = scross_dscale(fMat[kMTransY], fMat[kMPersp0], fMat[kMSkewY],  fMat[kMPersp2], scale);
8310b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org            inv->fMat[kMScaleY] = scross_dscale(fMat[kMScaleX], fMat[kMPersp2], fMat[kMTransX], fMat[kMPersp0], scale);
8320b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org            inv->fMat[kMTransY] = scross_dscale(fMat[kMTransX], fMat[kMSkewY],  fMat[kMScaleX], fMat[kMTransY], scale);
8330b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org
8340b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org            inv->fMat[kMPersp0] = scross_dscale(fMat[kMSkewY],  fMat[kMPersp1], fMat[kMScaleY], fMat[kMPersp0], scale);
8350b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org            inv->fMat[kMPersp1] = scross_dscale(fMat[kMSkewX],  fMat[kMPersp0], fMat[kMScaleX], fMat[kMPersp1], scale);
8360b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org            inv->fMat[kMPersp2] = scross_dscale(fMat[kMScaleX], fMat[kMScaleY], fMat[kMSkewX],  fMat[kMSkewY],  scale);
8378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        } else {   // not perspective
8380b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org            inv->fMat[kMScaleX] = SkDoubleToScalar(fMat[kMScaleY] * scale);
8390b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org            inv->fMat[kMSkewX]  = SkDoubleToScalar(-fMat[kMSkewX] * scale);
8400b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org            inv->fMat[kMTransX] = dcross_dscale(fMat[kMSkewX], fMat[kMTransY], fMat[kMScaleY], fMat[kMTransX], scale);
841fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
8420b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org            inv->fMat[kMSkewY]  = SkDoubleToScalar(-fMat[kMSkewY] * scale);
8430b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org            inv->fMat[kMScaleY] = SkDoubleToScalar(fMat[kMScaleX] * scale);
8440b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org            inv->fMat[kMTransY] = dcross_dscale(fMat[kMSkewY], fMat[kMTransX], fMat[kMScaleX], fMat[kMTransY], scale);
84583c6a2252555a974be4054aaca3a294e76efc32areed@google.com
8468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            inv->fMat[kMPersp0] = 0;
8478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            inv->fMat[kMPersp1] = 0;
8480b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org            inv->fMat[kMPersp2] = 1;
8498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
8508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8516fc5699e777c27c4eea9587a131aecf6e92a677ajunov@chromium.org        inv->setTypeMask(fTypeMask);
8526fc5699e777c27c4eea9587a131aecf6e92a677ajunov@chromium.org
8538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (inv == &tmp) {
8548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            *(SkMatrix*)this = tmp;
8558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
8568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
8578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return true;
8588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
8598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com///////////////////////////////////////////////////////////////////////////////
8618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkMatrix::Identity_pts(const SkMatrix& m, SkPoint dst[],
8638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                            const SkPoint src[], int count) {
8648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(m.getType() == 0);
8658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (dst != src && count > 0)
8678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        memcpy(dst, src, count * sizeof(SkPoint));
8688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
8698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkMatrix::Trans_pts(const SkMatrix& m, SkPoint dst[],
8718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                         const SkPoint src[], int count) {
8728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(m.getType() == kTranslate_Mask);
8738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (count > 0) {
8758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkScalar tx = m.fMat[kMTransX];
8768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkScalar ty = m.fMat[kMTransY];
8778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        do {
8788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            dst->fY = src->fY + ty;
8798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            dst->fX = src->fX + tx;
8808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            src += 1;
8818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            dst += 1;
8828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        } while (--count);
8838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
8848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
8858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkMatrix::Scale_pts(const SkMatrix& m, SkPoint dst[],
8878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                         const SkPoint src[], int count) {
8888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(m.getType() == kScale_Mask);
8898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (count > 0) {
8918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkScalar mx = m.fMat[kMScaleX];
8928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkScalar my = m.fMat[kMScaleY];
8938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        do {
8940b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org            dst->fY = src->fY * my;
8950b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org            dst->fX = src->fX * mx;
8968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            src += 1;
8978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            dst += 1;
8988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        } while (--count);
8998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
9008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
9018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkMatrix::ScaleTrans_pts(const SkMatrix& m, SkPoint dst[],
9038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                              const SkPoint src[], int count) {
9048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(m.getType() == (kScale_Mask | kTranslate_Mask));
9058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (count > 0) {
9078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkScalar mx = m.fMat[kMScaleX];
9088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkScalar my = m.fMat[kMScaleY];
9098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkScalar tx = m.fMat[kMTransX];
9108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkScalar ty = m.fMat[kMTransY];
9118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        do {
9120b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org            dst->fY = src->fY * my + ty;
9130b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org            dst->fX = src->fX * mx + tx;
9148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            src += 1;
9158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            dst += 1;
9168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        } while (--count);
9178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
9188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
9198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkMatrix::Rot_pts(const SkMatrix& m, SkPoint dst[],
9218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                       const SkPoint src[], int count) {
9228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT((m.getType() & (kPerspective_Mask | kTranslate_Mask)) == 0);
9238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (count > 0) {
9258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkScalar mx = m.fMat[kMScaleX];
9268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkScalar my = m.fMat[kMScaleY];
9278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkScalar kx = m.fMat[kMSkewX];
9288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkScalar ky = m.fMat[kMSkewY];
9298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        do {
9308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkScalar sy = src->fY;
9318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkScalar sx = src->fX;
9328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            src += 1;
9330b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org            dst->fY = sdot(sx, ky, sy, my);
9340b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org            dst->fX = sdot(sx, mx, sy, kx);
9358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            dst += 1;
9368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        } while (--count);
9378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
9388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
9398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkMatrix::RotTrans_pts(const SkMatrix& m, SkPoint dst[],
9418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                            const SkPoint src[], int count) {
9428d430185e08d2067584837a76b7193b803fee7a0tomhudson@google.com    SkASSERT(!m.hasPerspective());
9438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (count > 0) {
9458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkScalar mx = m.fMat[kMScaleX];
9468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkScalar my = m.fMat[kMScaleY];
9478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkScalar kx = m.fMat[kMSkewX];
9488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkScalar ky = m.fMat[kMSkewY];
9498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkScalar tx = m.fMat[kMTransX];
9508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkScalar ty = m.fMat[kMTransY];
9518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        do {
9528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkScalar sy = src->fY;
9538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkScalar sx = src->fX;
9548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            src += 1;
9550b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org#ifdef SK_LEGACY_MATRIX_MATH_ORDER
9560b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org            dst->fY = sx * ky + (sy * my + ty);
9570b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org            dst->fX = sx * mx + (sy * kx + tx);
9580b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org#else
9590b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org            dst->fY = sdot(sx, ky, sy, my) + ty;
9600b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org            dst->fX = sdot(sx, mx, sy, kx) + tx;
9610b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org#endif
9628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            dst += 1;
9638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        } while (--count);
9648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
9658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
9668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkMatrix::Persp_pts(const SkMatrix& m, SkPoint dst[],
9688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                         const SkPoint src[], int count) {
9698d430185e08d2067584837a76b7193b803fee7a0tomhudson@google.com    SkASSERT(m.hasPerspective());
9708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (count > 0) {
9728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        do {
9738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkScalar sy = src->fY;
9748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkScalar sx = src->fX;
9758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            src += 1;
9768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9770b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org            SkScalar x = sdot(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX])  + m.fMat[kMTransX];
9780b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org            SkScalar y = sdot(sx, m.fMat[kMSkewY],  sy, m.fMat[kMScaleY]) + m.fMat[kMTransY];
9790b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org#ifdef SK_LEGACY_MATRIX_MATH_ORDER
9800b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org            SkScalar z = sx * m.fMat[kMPersp0] + (sy * m.fMat[kMPersp1] + m.fMat[kMPersp2]);
9810b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org#else
9820b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org            SkScalar z = sdot(sx, m.fMat[kMPersp0], sy, m.fMat[kMPersp1]) + m.fMat[kMPersp2];
9830b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org#endif
9848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (z) {
9858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                z = SkScalarFastInvert(z);
9868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
9878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9880b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org            dst->fY = y * z;
9890b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org            dst->fX = x * z;
9908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            dst += 1;
9918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        } while (--count);
9928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
9938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
9948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comconst SkMatrix::MapPtsProc SkMatrix::gMapPtsProcs[] = {
9968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkMatrix::Identity_pts, SkMatrix::Trans_pts,
9978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkMatrix::Scale_pts,    SkMatrix::ScaleTrans_pts,
9988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkMatrix::Rot_pts,      SkMatrix::RotTrans_pts,
9998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkMatrix::Rot_pts,      SkMatrix::RotTrans_pts,
10008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // repeat the persp proc 8 times
10018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkMatrix::Persp_pts,    SkMatrix::Persp_pts,
10028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkMatrix::Persp_pts,    SkMatrix::Persp_pts,
10038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkMatrix::Persp_pts,    SkMatrix::Persp_pts,
10048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkMatrix::Persp_pts,    SkMatrix::Persp_pts
10058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
10068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
10078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkMatrix::mapPoints(SkPoint dst[], const SkPoint src[], int count) const {
1008259fbaf7a464827bc560517988daeb5836e11e98egdaniel@google.com    SkASSERT((dst && src && count > 0) || 0 == count);
10098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // no partial overlap
10103dc82c44706b017877880160ad6af284ec3997e3bungeman@google.com    SkASSERT(src == dst || &dst[count] <= &src[0] || &src[count] <= &dst[0]);
10118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
10128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    this->getMapPtsProc()(*this, dst, src, count);
10138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
10148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
10158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com///////////////////////////////////////////////////////////////////////////////
10168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1017259fbaf7a464827bc560517988daeb5836e11e98egdaniel@google.comvoid SkMatrix::mapHomogeneousPoints(SkScalar dst[], const SkScalar src[], int count) const {
1018259fbaf7a464827bc560517988daeb5836e11e98egdaniel@google.com    SkASSERT((dst && src && count > 0) || 0 == count);
1019259fbaf7a464827bc560517988daeb5836e11e98egdaniel@google.com    // no partial overlap
1020259fbaf7a464827bc560517988daeb5836e11e98egdaniel@google.com    SkASSERT(src == dst || SkAbs32((int32_t)(src - dst)) >= 3*count);
1021259fbaf7a464827bc560517988daeb5836e11e98egdaniel@google.com
1022259fbaf7a464827bc560517988daeb5836e11e98egdaniel@google.com    if (count > 0) {
1023259fbaf7a464827bc560517988daeb5836e11e98egdaniel@google.com        if (this->isIdentity()) {
1024259fbaf7a464827bc560517988daeb5836e11e98egdaniel@google.com            memcpy(dst, src, 3*count*sizeof(SkScalar));
1025259fbaf7a464827bc560517988daeb5836e11e98egdaniel@google.com            return;
1026259fbaf7a464827bc560517988daeb5836e11e98egdaniel@google.com        }
1027259fbaf7a464827bc560517988daeb5836e11e98egdaniel@google.com        do {
1028259fbaf7a464827bc560517988daeb5836e11e98egdaniel@google.com            SkScalar sx = src[0];
1029259fbaf7a464827bc560517988daeb5836e11e98egdaniel@google.com            SkScalar sy = src[1];
1030259fbaf7a464827bc560517988daeb5836e11e98egdaniel@google.com            SkScalar sw = src[2];
1031259fbaf7a464827bc560517988daeb5836e11e98egdaniel@google.com            src += 3;
1032259fbaf7a464827bc560517988daeb5836e11e98egdaniel@google.com
10330b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org            SkScalar x = sdot(sx, fMat[kMScaleX], sy, fMat[kMSkewX],  sw, fMat[kMTransX]);
10340b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org            SkScalar y = sdot(sx, fMat[kMSkewY],  sy, fMat[kMScaleY], sw, fMat[kMTransY]);
10350b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org            SkScalar w = sdot(sx, fMat[kMPersp0], sy, fMat[kMPersp1], sw, fMat[kMPersp2]);
1036259fbaf7a464827bc560517988daeb5836e11e98egdaniel@google.com
1037259fbaf7a464827bc560517988daeb5836e11e98egdaniel@google.com            dst[0] = x;
1038259fbaf7a464827bc560517988daeb5836e11e98egdaniel@google.com            dst[1] = y;
1039259fbaf7a464827bc560517988daeb5836e11e98egdaniel@google.com            dst[2] = w;
1040259fbaf7a464827bc560517988daeb5836e11e98egdaniel@google.com            dst += 3;
1041259fbaf7a464827bc560517988daeb5836e11e98egdaniel@google.com        } while (--count);
1042259fbaf7a464827bc560517988daeb5836e11e98egdaniel@google.com    }
1043259fbaf7a464827bc560517988daeb5836e11e98egdaniel@google.com}
1044259fbaf7a464827bc560517988daeb5836e11e98egdaniel@google.com
1045259fbaf7a464827bc560517988daeb5836e11e98egdaniel@google.com///////////////////////////////////////////////////////////////////////////////
1046259fbaf7a464827bc560517988daeb5836e11e98egdaniel@google.com
10478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkMatrix::mapVectors(SkPoint dst[], const SkPoint src[], int count) const {
10488d430185e08d2067584837a76b7193b803fee7a0tomhudson@google.com    if (this->hasPerspective()) {
10498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkPoint origin;
10508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
10518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        MapXYProc proc = this->getMapXYProc();
10528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        proc(*this, 0, 0, &origin);
10538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
10548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        for (int i = count - 1; i >= 0; --i) {
10558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkPoint tmp;
10568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
10578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            proc(*this, src[i].fX, src[i].fY, &tmp);
10588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            dst[i].set(tmp.fX - origin.fX, tmp.fY - origin.fY);
10598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
10608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } else {
10618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkMatrix tmp = *this;
10628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
10638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        tmp.fMat[kMTransX] = tmp.fMat[kMTransY] = 0;
10648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        tmp.clearTypeMask(kTranslate_Mask);
10658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        tmp.mapPoints(dst, src, count);
10668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
10678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
10688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
10698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkMatrix::mapRect(SkRect* dst, const SkRect& src) const {
10708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(dst && &src);
10718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
10728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (this->rectStaysRect()) {
10738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        this->mapPoints((SkPoint*)dst, (const SkPoint*)&src, 2);
10748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        dst->sort();
10758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return true;
10768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } else {
10778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkPoint quad[4];
10788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
10798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        src.toQuad(quad);
10808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        this->mapPoints(quad, quad, 4);
10818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        dst->set(quad, 4);
10828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
10838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
10848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
10858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
10868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkScalar SkMatrix::mapRadius(SkScalar radius) const {
10878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkVector    vec[2];
10888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
10898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    vec[0].set(radius, 0);
10908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    vec[1].set(0, radius);
10918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    this->mapVectors(vec, 2);
10928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
10938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkScalar d0 = vec[0].length();
10948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkScalar d1 = vec[1].length();
10958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
10966e252d49c9bb6b805478560dd99b83ff1d1411dereed@google.com    // return geometric mean
10976e252d49c9bb6b805478560dd99b83ff1d1411dereed@google.com    return SkScalarSqrt(d0 * d1);
10988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
10998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
11008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com///////////////////////////////////////////////////////////////////////////////
11018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
11028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkMatrix::Persp_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
11038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                        SkPoint* pt) {
11048d430185e08d2067584837a76b7193b803fee7a0tomhudson@google.com    SkASSERT(m.hasPerspective());
11058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
11060b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    SkScalar x = sdot(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX])  + m.fMat[kMTransX];
11070b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    SkScalar y = sdot(sx, m.fMat[kMSkewY],  sy, m.fMat[kMScaleY]) + m.fMat[kMTransY];
11080b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    SkScalar z = sdot(sx, m.fMat[kMPersp0], sy, m.fMat[kMPersp1]) + m.fMat[kMPersp2];
11098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (z) {
11108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        z = SkScalarFastInvert(z);
11118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
11120b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    pt->fX = x * z;
11130b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    pt->fY = y * z;
11148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
11158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
11168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkMatrix::RotTrans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
11178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                           SkPoint* pt) {
11188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT((m.getType() & (kAffine_Mask | kPerspective_Mask)) == kAffine_Mask);
1119fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
11200b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org#ifdef SK_LEGACY_MATRIX_MATH_ORDER
11210b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    pt->fX = sx * m.fMat[kMScaleX] + (sy * m.fMat[kMSkewX]  +  m.fMat[kMTransX]);
11220b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    pt->fY = sx * m.fMat[kMSkewY]  + (sy * m.fMat[kMScaleY] + m.fMat[kMTransY]);
11230b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org#else
11240b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    pt->fX = sdot(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX])  + m.fMat[kMTransX];
11250b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    pt->fY = sdot(sx, m.fMat[kMSkewY],  sy, m.fMat[kMScaleY]) + m.fMat[kMTransY];
11260b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org#endif
11278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
11288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
11298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkMatrix::Rot_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
11308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                      SkPoint* pt) {
11318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT((m.getType() & (kAffine_Mask | kPerspective_Mask))== kAffine_Mask);
11328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(0 == m.fMat[kMTransX]);
11338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(0 == m.fMat[kMTransY]);
11348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
11350b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org#ifdef SK_LEGACY_MATRIX_MATH_ORDER
11360b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    pt->fX = sx * m.fMat[kMScaleX] + (sy * m.fMat[kMSkewX]  + m.fMat[kMTransX]);
11370b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    pt->fY = sx * m.fMat[kMSkewY]  + (sy * m.fMat[kMScaleY] + m.fMat[kMTransY]);
11380b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org#else
11390b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    pt->fX = sdot(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX])  + m.fMat[kMTransX];
11400b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    pt->fY = sdot(sx, m.fMat[kMSkewY],  sy, m.fMat[kMScaleY]) + m.fMat[kMTransY];
11410b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org#endif
11428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
11438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
11448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkMatrix::ScaleTrans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
11458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                             SkPoint* pt) {
11468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT((m.getType() & (kScale_Mask | kAffine_Mask | kPerspective_Mask))
11478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com             == kScale_Mask);
1148fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
11490b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    pt->fX = sx * m.fMat[kMScaleX] + m.fMat[kMTransX];
11500b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    pt->fY = sy * m.fMat[kMScaleY] + m.fMat[kMTransY];
11518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
11528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
11538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkMatrix::Scale_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
11548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                        SkPoint* pt) {
11558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT((m.getType() & (kScale_Mask | kAffine_Mask | kPerspective_Mask))
11568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com             == kScale_Mask);
11578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(0 == m.fMat[kMTransX]);
11588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(0 == m.fMat[kMTransY]);
11598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
11600b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    pt->fX = sx * m.fMat[kMScaleX];
11610b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    pt->fY = sy * m.fMat[kMScaleY];
11628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
11638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
11648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkMatrix::Trans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
11658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                        SkPoint* pt) {
11668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(m.getType() == kTranslate_Mask);
11678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
11688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    pt->fX = sx + m.fMat[kMTransX];
11698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    pt->fY = sy + m.fMat[kMTransY];
11708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
11718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
11728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkMatrix::Identity_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
11738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                           SkPoint* pt) {
11748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(0 == m.getType());
11758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
11768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    pt->fX = sx;
11778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    pt->fY = sy;
11788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
11798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
11808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comconst SkMatrix::MapXYProc SkMatrix::gMapXYProcs[] = {
11818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkMatrix::Identity_xy, SkMatrix::Trans_xy,
11828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkMatrix::Scale_xy,    SkMatrix::ScaleTrans_xy,
11838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkMatrix::Rot_xy,      SkMatrix::RotTrans_xy,
11848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkMatrix::Rot_xy,      SkMatrix::RotTrans_xy,
11858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // repeat the persp proc 8 times
11868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkMatrix::Persp_xy,    SkMatrix::Persp_xy,
11878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkMatrix::Persp_xy,    SkMatrix::Persp_xy,
11888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkMatrix::Persp_xy,    SkMatrix::Persp_xy,
11898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkMatrix::Persp_xy,    SkMatrix::Persp_xy
11908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
11918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
11928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com///////////////////////////////////////////////////////////////////////////////
11938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
11948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// if its nearly zero (just made up 26, perhaps it should be bigger or smaller)
119583c6a2252555a974be4054aaca3a294e76efc32areed@google.com#define PerspNearlyZero(x)  SkScalarNearlyZero(x, (1.0f / (1 << 26)))
11968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
11978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkMatrix::fixedStepInX(SkScalar y, SkFixed* stepX, SkFixed* stepY) const {
11988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (PerspNearlyZero(fMat[kMPersp0])) {
11998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (stepX || stepY) {
12008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (PerspNearlyZero(fMat[kMPersp1]) &&
12010b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org                    PerspNearlyZero(fMat[kMPersp2] - 1)) {
12028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                if (stepX) {
12038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    *stepX = SkScalarToFixed(fMat[kMScaleX]);
12048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                }
12058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                if (stepY) {
12068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    *stepY = SkScalarToFixed(fMat[kMSkewY]);
12078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                }
12088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            } else {
120983c6a2252555a974be4054aaca3a294e76efc32areed@google.com                SkScalar z = y * fMat[kMPersp1] + fMat[kMPersp2];
12108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                if (stepX) {
12110b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org                    *stepX = SkScalarToFixed(fMat[kMScaleX] / z);
12128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                }
12138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                if (stepY) {
12140b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org                    *stepY = SkScalarToFixed(fMat[kMSkewY] / z);
12158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                }
12168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
12178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
12188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return true;
12198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
12208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return false;
12218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
12228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com///////////////////////////////////////////////////////////////////////////////
12248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkPerspIter.h"
12268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkPerspIter::SkPerspIter(const SkMatrix& m, SkScalar x0, SkScalar y0, int count)
12288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        : fMatrix(m), fSX(x0), fSY(y0), fCount(count) {
12298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPoint pt;
12308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkMatrix::Persp_xy(m, x0, y0, &pt);
12328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fX = SkScalarToFixed(pt.fX);
12338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fY = SkScalarToFixed(pt.fY);
12348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
12358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comint SkPerspIter::next() {
12378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int n = fCount;
1238fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
12398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (0 == n) {
12408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return 0;
12418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
12428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPoint pt;
12438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkFixed x = fX;
12448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkFixed y = fY;
12458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkFixed dx, dy;
12468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (n >= kCount) {
12488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        n = kCount;
12498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fSX += SkIntToScalar(kCount);
12508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkMatrix::Persp_xy(fMatrix, fSX, fSY, &pt);
12518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fX = SkScalarToFixed(pt.fX);
12528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fY = SkScalarToFixed(pt.fY);
12538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        dx = (fX - x) >> kShift;
12548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        dy = (fY - y) >> kShift;
12558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } else {
12568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fSX += SkIntToScalar(n);
12578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkMatrix::Persp_xy(fMatrix, fSX, fSY, &pt);
12588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fX = SkScalarToFixed(pt.fX);
12598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fY = SkScalarToFixed(pt.fY);
12608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        dx = (fX - x) / n;
12618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        dy = (fY - y) / n;
12628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
12638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkFixed* p = fStorage;
12658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    for (int i = 0; i < n; i++) {
12668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        *p++ = x; x += dx;
12678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        *p++ = y; y += dy;
12688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1269fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
12708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fCount -= n;
12718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return n;
12728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
12738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com///////////////////////////////////////////////////////////////////////////////
12758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic inline bool checkForZero(float x) {
12778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return x*x == 0;
12788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
12798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic inline bool poly_to_point(SkPoint* pt, const SkPoint poly[], int count) {
12818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    float   x = 1, y = 1;
12828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPoint pt1, pt2;
12838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (count > 1) {
12858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        pt1.fX = poly[1].fX - poly[0].fX;
12868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        pt1.fY = poly[1].fY - poly[0].fY;
12878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        y = SkPoint::Length(pt1.fX, pt1.fY);
12888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (checkForZero(y)) {
12898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            return false;
12908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
12918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        switch (count) {
12928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            case 2:
12938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                break;
12948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            case 3:
12958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                pt2.fX = poly[0].fY - poly[2].fY;
12968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                pt2.fY = poly[2].fX - poly[0].fX;
12978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                goto CALC_X;
12988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            default:
12998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                pt2.fX = poly[0].fY - poly[3].fY;
13008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                pt2.fY = poly[3].fX - poly[0].fX;
13018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            CALC_X:
13020b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org                x = sdot(pt1.fX, pt2.fX, pt1.fY, pt2.fY) / y;
13038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                break;
13048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
13058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
13068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    pt->set(x, y);
13078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return true;
13088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
13098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
13108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkMatrix::Poly2Proc(const SkPoint srcPt[], SkMatrix* dst,
13118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                         const SkPoint& scale) {
13128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    float invScale = 1 / scale.fY;
13138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
13148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    dst->fMat[kMScaleX] = (srcPt[1].fY - srcPt[0].fY) * invScale;
13158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    dst->fMat[kMSkewY] = (srcPt[0].fX - srcPt[1].fX) * invScale;
13168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    dst->fMat[kMPersp0] = 0;
13178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    dst->fMat[kMSkewX] = (srcPt[1].fX - srcPt[0].fX) * invScale;
13188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    dst->fMat[kMScaleY] = (srcPt[1].fY - srcPt[0].fY) * invScale;
13198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    dst->fMat[kMPersp1] = 0;
13208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    dst->fMat[kMTransX] = srcPt[0].fX;
13218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    dst->fMat[kMTransY] = srcPt[0].fY;
13228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    dst->fMat[kMPersp2] = 1;
13238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    dst->setTypeMask(kUnknown_Mask);
13248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return true;
13258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
13268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
13278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkMatrix::Poly3Proc(const SkPoint srcPt[], SkMatrix* dst,
13288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                         const SkPoint& scale) {
13298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    float invScale = 1 / scale.fX;
13308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    dst->fMat[kMScaleX] = (srcPt[2].fX - srcPt[0].fX) * invScale;
13318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    dst->fMat[kMSkewY] = (srcPt[2].fY - srcPt[0].fY) * invScale;
13328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    dst->fMat[kMPersp0] = 0;
13338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
13348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    invScale = 1 / scale.fY;
13358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    dst->fMat[kMSkewX] = (srcPt[1].fX - srcPt[0].fX) * invScale;
13368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    dst->fMat[kMScaleY] = (srcPt[1].fY - srcPt[0].fY) * invScale;
13378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    dst->fMat[kMPersp1] = 0;
13388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
13398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    dst->fMat[kMTransX] = srcPt[0].fX;
13408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    dst->fMat[kMTransY] = srcPt[0].fY;
13418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    dst->fMat[kMPersp2] = 1;
13428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    dst->setTypeMask(kUnknown_Mask);
13438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return true;
13448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
13458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
13468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkMatrix::Poly4Proc(const SkPoint srcPt[], SkMatrix* dst,
13478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                         const SkPoint& scale) {
13488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    float   a1, a2;
13498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    float   x0, y0, x1, y1, x2, y2;
13508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
13518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    x0 = srcPt[2].fX - srcPt[0].fX;
13528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    y0 = srcPt[2].fY - srcPt[0].fY;
13538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    x1 = srcPt[2].fX - srcPt[1].fX;
13548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    y1 = srcPt[2].fY - srcPt[1].fY;
13558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    x2 = srcPt[2].fX - srcPt[3].fX;
13568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    y2 = srcPt[2].fY - srcPt[3].fY;
13578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
13588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /* check if abs(x2) > abs(y2) */
13598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if ( x2 > 0 ? y2 > 0 ? x2 > y2 : x2 > -y2 : y2 > 0 ? -x2 > y2 : x2 < y2) {
13608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        float denom = SkScalarMulDiv(x1, y2, x2) - y1;
13618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (checkForZero(denom)) {
13628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            return false;
13638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
13640b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org        a1 = (SkScalarMulDiv(x0 - x1, y2, x2) - y0 + y1) / denom;
13658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } else {
13668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        float denom = x1 - SkScalarMulDiv(y1, x2, y2);
13678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (checkForZero(denom)) {
13688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            return false;
13698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
13700b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org        a1 = (x0 - x1 - SkScalarMulDiv(y0 - y1, x2, y2)) / denom;
13718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
13728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
13738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /* check if abs(x1) > abs(y1) */
13748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if ( x1 > 0 ? y1 > 0 ? x1 > y1 : x1 > -y1 : y1 > 0 ? -x1 > y1 : x1 < y1) {
13758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        float denom = y2 - SkScalarMulDiv(x2, y1, x1);
13768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (checkForZero(denom)) {
13778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            return false;
13788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
13790b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org        a2 = (y0 - y2 - SkScalarMulDiv(x0 - x2, y1, x1)) / denom;
13808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } else {
13818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        float denom = SkScalarMulDiv(y2, x1, y1) - x2;
13828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (checkForZero(denom)) {
13838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            return false;
13848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
13850b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org        a2 = (SkScalarMulDiv(y0 - y2, x1, y1) - x0 + x2) / denom;
13868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
13878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
13880b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    float invScale = SkScalarInvert(scale.fX);
13890b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    dst->fMat[kMScaleX] = (a2 * srcPt[3].fX + srcPt[3].fX - srcPt[0].fX) * invScale;
13900b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    dst->fMat[kMSkewY]  = (a2 * srcPt[3].fY + srcPt[3].fY - srcPt[0].fY) * invScale;
13910b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    dst->fMat[kMPersp0] = a2 * invScale;
13920b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org
13930b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    invScale = SkScalarInvert(scale.fY);
13940b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    dst->fMat[kMSkewX]  = (a1 * srcPt[1].fX + srcPt[1].fX - srcPt[0].fX) * invScale;
13950b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    dst->fMat[kMScaleY] = (a1 * srcPt[1].fY + srcPt[1].fY - srcPt[0].fY) * invScale;
13960b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    dst->fMat[kMPersp1] = a1 * invScale;
13970b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org
13988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    dst->fMat[kMTransX] = srcPt[0].fX;
13998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    dst->fMat[kMTransY] = srcPt[0].fY;
14008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    dst->fMat[kMPersp2] = 1;
14018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    dst->setTypeMask(kUnknown_Mask);
14028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return true;
14038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
14048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
14058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comtypedef bool (*PolyMapProc)(const SkPoint[], SkMatrix*, const SkPoint&);
14068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
14078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/*  Taken from Rob Johnson's original sample code in QuickDraw GX
14088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com*/
14098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkMatrix::setPolyToPoly(const SkPoint src[], const SkPoint dst[],
14108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                             int count) {
14118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if ((unsigned)count > 4) {
14128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkDebugf("--- SkMatrix::setPolyToPoly count out of range %d\n", count);
14138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
14148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
14158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
14168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (0 == count) {
14178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        this->reset();
14188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return true;
14198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
14208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (1 == count) {
14218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        this->setTranslate(dst[0].fX - src[0].fX, dst[0].fY - src[0].fY);
14228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return true;
14238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
14248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
14258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPoint scale;
14268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (!poly_to_point(&scale, src, count) ||
14278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkScalarNearlyZero(scale.fX) ||
14288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkScalarNearlyZero(scale.fY)) {
14298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
14308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
14318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
14328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    static const PolyMapProc gPolyMapProcs[] = {
14338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkMatrix::Poly2Proc, SkMatrix::Poly3Proc, SkMatrix::Poly4Proc
14348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    };
14358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    PolyMapProc proc = gPolyMapProcs[count - 2];
14368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
14378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkMatrix tempMap, result;
14388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    tempMap.setTypeMask(kUnknown_Mask);
14398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
14408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (!proc(src, &tempMap, scale)) {
14418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
14428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
14438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (!tempMap.invert(&result)) {
14448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
14458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
14468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (!proc(dst, &tempMap, scale)) {
14478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
14488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
144992362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org    this->setConcat(tempMap, result);
14508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return true;
14518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
14528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
14538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com///////////////////////////////////////////////////////////////////////////////
14548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1455311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.orgenum MinMaxOrBoth {
1456311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org    kMin_MinMaxOrBoth,
1457311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org    kMax_MinMaxOrBoth,
1458311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org    kBoth_MinMaxOrBoth
1459cea9abb001b07eaf4340a78db708bfac9e8c68c2commit-bot@chromium.org};
1460cc4dac3dac215dc0dd56f7b30d07cc304671b033bsalomon@google.com
1461311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.orgtemplate <MinMaxOrBoth MIN_MAX_OR_BOTH> bool get_scale_factor(SkMatrix::TypeMask typeMask,
1462311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org                                                              const SkScalar m[9],
1463311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org                                                              SkScalar results[/*1 or 2*/]) {
1464cea9abb001b07eaf4340a78db708bfac9e8c68c2commit-bot@chromium.org    if (typeMask & SkMatrix::kPerspective_Mask) {
1465311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org        return false;
1466383963280ddd13030331765fe88d2aefa3e32130bsalomon@google.com    }
1467cea9abb001b07eaf4340a78db708bfac9e8c68c2commit-bot@chromium.org    if (SkMatrix::kIdentity_Mask == typeMask) {
1468311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org        results[0] = SK_Scalar1;
1469311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org        if (kBoth_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1470311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org            results[1] = SK_Scalar1;
1471311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org        }
1472311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org        return true;
1473383963280ddd13030331765fe88d2aefa3e32130bsalomon@google.com    }
1474cea9abb001b07eaf4340a78db708bfac9e8c68c2commit-bot@chromium.org    if (!(typeMask & SkMatrix::kAffine_Mask)) {
1475311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org        if (kMin_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1476311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org             results[0] = SkMinScalar(SkScalarAbs(m[SkMatrix::kMScaleX]),
1477311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org                                      SkScalarAbs(m[SkMatrix::kMScaleY]));
1478311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org        } else if (kMax_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1479311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org             results[0] = SkMaxScalar(SkScalarAbs(m[SkMatrix::kMScaleX]),
1480311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org                                      SkScalarAbs(m[SkMatrix::kMScaleY]));
1481cea9abb001b07eaf4340a78db708bfac9e8c68c2commit-bot@chromium.org        } else {
1482311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org            results[0] = SkScalarAbs(m[SkMatrix::kMScaleX]);
1483311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org            results[1] = SkScalarAbs(m[SkMatrix::kMScaleY]);
1484311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org             if (results[0] > results[1]) {
1485311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org                 SkTSwap(results[0], results[1]);
1486311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org             }
1487cea9abb001b07eaf4340a78db708bfac9e8c68c2commit-bot@chromium.org        }
1488311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org        return true;
1489383963280ddd13030331765fe88d2aefa3e32130bsalomon@google.com    }
1490383963280ddd13030331765fe88d2aefa3e32130bsalomon@google.com    // ignore the translation part of the matrix, just look at 2x2 portion.
1491cea9abb001b07eaf4340a78db708bfac9e8c68c2commit-bot@chromium.org    // compute singular values, take largest or smallest abs value.
1492383963280ddd13030331765fe88d2aefa3e32130bsalomon@google.com    // [a b; b c] = A^T*A
14930b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    SkScalar a = sdot(m[SkMatrix::kMScaleX], m[SkMatrix::kMScaleX],
14940b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org                      m[SkMatrix::kMSkewY],  m[SkMatrix::kMSkewY]);
14950b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    SkScalar b = sdot(m[SkMatrix::kMScaleX], m[SkMatrix::kMSkewX],
14960b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org                      m[SkMatrix::kMScaleY], m[SkMatrix::kMSkewY]);
14970b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    SkScalar c = sdot(m[SkMatrix::kMSkewX],  m[SkMatrix::kMSkewX],
14980b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org                      m[SkMatrix::kMScaleY], m[SkMatrix::kMScaleY]);
1499383963280ddd13030331765fe88d2aefa3e32130bsalomon@google.com    // eigenvalues of A^T*A are the squared singular values of A.
1500383963280ddd13030331765fe88d2aefa3e32130bsalomon@google.com    // characteristic equation is det((A^T*A) - l*I) = 0
1501383963280ddd13030331765fe88d2aefa3e32130bsalomon@google.com    // l^2 - (a + c)l + (ac-b^2)
1502383963280ddd13030331765fe88d2aefa3e32130bsalomon@google.com    // solve using quadratic equation (divisor is non-zero since l^2 has 1 coeff
1503cea9abb001b07eaf4340a78db708bfac9e8c68c2commit-bot@chromium.org    // and roots are guaranteed to be pos and real).
15040b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org    SkScalar bSqd = b * b;
1505383963280ddd13030331765fe88d2aefa3e32130bsalomon@google.com    // if upper left 2x2 is orthogonal save some math
1506c490f801b063a0837501feab3d12b73d71f46312jvanverth@google.com    if (bSqd <= SK_ScalarNearlyZero*SK_ScalarNearlyZero) {
1507311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org        if (kMin_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1508311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org            results[0] = SkMinScalar(a, c);
1509311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org        } else if (kMax_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1510311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org            results[0] = SkMaxScalar(a, c);
1511cea9abb001b07eaf4340a78db708bfac9e8c68c2commit-bot@chromium.org        } else {
1512311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org            results[0] = a;
1513311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org            results[1] = c;
1514311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org            if (results[0] > results[1]) {
1515311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org                SkTSwap(results[0], results[1]);
1516311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org            }
1517cea9abb001b07eaf4340a78db708bfac9e8c68c2commit-bot@chromium.org        }
1518cc4dac3dac215dc0dd56f7b30d07cc304671b033bsalomon@google.com    } else {
1519383963280ddd13030331765fe88d2aefa3e32130bsalomon@google.com        SkScalar aminusc = a - c;
1520383963280ddd13030331765fe88d2aefa3e32130bsalomon@google.com        SkScalar apluscdiv2 = SkScalarHalf(a + c);
15210b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org        SkScalar x = SkScalarHalf(SkScalarSqrt(aminusc * aminusc + 4 * bSqd));
1522311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org        if (kMin_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1523311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org            results[0] = apluscdiv2 - x;
1524311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org        } else if (kMax_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1525311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org            results[0] = apluscdiv2 + x;
1526cea9abb001b07eaf4340a78db708bfac9e8c68c2commit-bot@chromium.org        } else {
1527311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org            results[0] = apluscdiv2 - x;
1528311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org            results[1] = apluscdiv2 + x;
1529cea9abb001b07eaf4340a78db708bfac9e8c68c2commit-bot@chromium.org        }
1530cc4dac3dac215dc0dd56f7b30d07cc304671b033bsalomon@google.com    }
1531311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org    SkASSERT(results[0] >= 0);
1532311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org    results[0] = SkScalarSqrt(results[0]);
1533311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org    if (kBoth_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1534311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org        SkASSERT(results[1] >= 0);
1535311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org        results[1] = SkScalarSqrt(results[1]);
1536311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org    }
1537311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org    return true;
1538cea9abb001b07eaf4340a78db708bfac9e8c68c2commit-bot@chromium.org}
1539cea9abb001b07eaf4340a78db708bfac9e8c68c2commit-bot@chromium.org
15401878651990d7c9da72cf43481432232bbef3550dcommit-bot@chromium.orgSkScalar SkMatrix::getMinScale() const {
1541311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org    SkScalar factor;
1542311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org    if (get_scale_factor<kMin_MinMaxOrBoth>(this->getType(), fMat, &factor)) {
1543311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org        return factor;
1544311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org    } else {
1545311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org        return -1;
1546311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org    }
1547cea9abb001b07eaf4340a78db708bfac9e8c68c2commit-bot@chromium.org}
1548cea9abb001b07eaf4340a78db708bfac9e8c68c2commit-bot@chromium.org
15491878651990d7c9da72cf43481432232bbef3550dcommit-bot@chromium.orgSkScalar SkMatrix::getMaxScale() const {
1550311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org    SkScalar factor;
1551311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org    if (get_scale_factor<kMax_MinMaxOrBoth>(this->getType(), fMat, &factor)) {
1552311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org        return factor;
1553311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org    } else {
1554311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org        return -1;
1555311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org    }
1556311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org}
1557311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org
1558311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.orgbool SkMatrix::getMinMaxScales(SkScalar scaleFactors[2]) const {
1559311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org    return get_scale_factor<kBoth_MinMaxOrBoth>(this->getType(), fMat, scaleFactors);
1560cc4dac3dac215dc0dd56f7b30d07cc304671b033bsalomon@google.com}
1561cc4dac3dac215dc0dd56f7b30d07cc304671b033bsalomon@google.com
156278358bf624c7e7c09ffccf638c50870808d884d6mtkleinnamespace {
156378358bf624c7e7c09ffccf638c50870808d884d6mtklein
1564ada3635c8e83739f45cd52459d3e052783d1a40emtkleinstruct PODMatrix {
1565ada3635c8e83739f45cd52459d3e052783d1a40emtklein    SkScalar matrix[9];
1566ada3635c8e83739f45cd52459d3e052783d1a40emtklein    uint32_t typemask;
156778358bf624c7e7c09ffccf638c50870808d884d6mtklein
1568ada3635c8e83739f45cd52459d3e052783d1a40emtklein    const SkMatrix& asSkMatrix() const { return *reinterpret_cast<const SkMatrix*>(this); }
1569ada3635c8e83739f45cd52459d3e052783d1a40emtklein};
1570ada3635c8e83739f45cd52459d3e052783d1a40emtkleinSK_COMPILE_ASSERT(sizeof(PODMatrix) == sizeof(SkMatrix), PODMatrixSizeMismatch);
157121a705d2ebdf0319d45970784950886f62a77141commit-bot@chromium.org
157278358bf624c7e7c09ffccf638c50870808d884d6mtklein}  // namespace
157378358bf624c7e7c09ffccf638c50870808d884d6mtklein
1574cc4dac3dac215dc0dd56f7b30d07cc304671b033bsalomon@google.comconst SkMatrix& SkMatrix::I() {
1575ada3635c8e83739f45cd52459d3e052783d1a40emtklein    SK_COMPILE_ASSERT(offsetof(SkMatrix, fMat)      == offsetof(PODMatrix, matrix),   BadfMat);
1576ada3635c8e83739f45cd52459d3e052783d1a40emtklein    SK_COMPILE_ASSERT(offsetof(SkMatrix, fTypeMask) == offsetof(PODMatrix, typemask), BadfTypeMask);
1577ada3635c8e83739f45cd52459d3e052783d1a40emtklein
1578ada3635c8e83739f45cd52459d3e052783d1a40emtklein    static const PODMatrix identity = { {SK_Scalar1, 0, 0,
1579ada3635c8e83739f45cd52459d3e052783d1a40emtklein                                         0, SK_Scalar1, 0,
1580ada3635c8e83739f45cd52459d3e052783d1a40emtklein                                         0, 0, SK_Scalar1 },
1581ada3635c8e83739f45cd52459d3e052783d1a40emtklein                                       kIdentity_Mask | kRectStaysRect_Mask};
1582ada3635c8e83739f45cd52459d3e052783d1a40emtklein    SkASSERT(identity.asSkMatrix().isIdentity());
1583ada3635c8e83739f45cd52459d3e052783d1a40emtklein    return identity.asSkMatrix();
15841f90287df3129cb267422e482c52ebeca6a8990ftomhudson@google.com}
1585cc4dac3dac215dc0dd56f7b30d07cc304671b033bsalomon@google.com
1586cc4dac3dac215dc0dd56f7b30d07cc304671b033bsalomon@google.comconst SkMatrix& SkMatrix::InvalidMatrix() {
1587ada3635c8e83739f45cd52459d3e052783d1a40emtklein    SK_COMPILE_ASSERT(offsetof(SkMatrix, fMat)      == offsetof(PODMatrix, matrix),   BadfMat);
1588ada3635c8e83739f45cd52459d3e052783d1a40emtklein    SK_COMPILE_ASSERT(offsetof(SkMatrix, fTypeMask) == offsetof(PODMatrix, typemask), BadfTypeMask);
1589ada3635c8e83739f45cd52459d3e052783d1a40emtklein
1590ada3635c8e83739f45cd52459d3e052783d1a40emtklein    static const PODMatrix invalid =
1591ada3635c8e83739f45cd52459d3e052783d1a40emtklein        { {SK_ScalarMax, SK_ScalarMax, SK_ScalarMax,
1592ada3635c8e83739f45cd52459d3e052783d1a40emtklein           SK_ScalarMax, SK_ScalarMax, SK_ScalarMax,
1593ada3635c8e83739f45cd52459d3e052783d1a40emtklein           SK_ScalarMax, SK_ScalarMax, SK_ScalarMax },
1594ada3635c8e83739f45cd52459d3e052783d1a40emtklein         kTranslate_Mask | kScale_Mask | kAffine_Mask | kPerspective_Mask };
1595ada3635c8e83739f45cd52459d3e052783d1a40emtklein    return invalid.asSkMatrix();
1596cc4dac3dac215dc0dd56f7b30d07cc304671b033bsalomon@google.com}
1597cc4dac3dac215dc0dd56f7b30d07cc304671b033bsalomon@google.com
1598cc4dac3dac215dc0dd56f7b30d07cc304671b033bsalomon@google.com///////////////////////////////////////////////////////////////////////////////
1599cc4dac3dac215dc0dd56f7b30d07cc304671b033bsalomon@google.com
16004faa869cdabbdcf4867118b4a1272296baaeeb52commit-bot@chromium.orgsize_t SkMatrix::writeToMemory(void* buffer) const {
16010ad336f8c6f6f0325eee309c9cd501ea432cc33ereed@android.com    // TODO write less for simple matrices
16024faa869cdabbdcf4867118b4a1272296baaeeb52commit-bot@chromium.org    static const size_t sizeInMemory = 9 * sizeof(SkScalar);
16030ad336f8c6f6f0325eee309c9cd501ea432cc33ereed@android.com    if (buffer) {
16044faa869cdabbdcf4867118b4a1272296baaeeb52commit-bot@chromium.org        memcpy(buffer, fMat, sizeInMemory);
16050ad336f8c6f6f0325eee309c9cd501ea432cc33ereed@android.com    }
16064faa869cdabbdcf4867118b4a1272296baaeeb52commit-bot@chromium.org    return sizeInMemory;
16070ad336f8c6f6f0325eee309c9cd501ea432cc33ereed@android.com}
16080ad336f8c6f6f0325eee309c9cd501ea432cc33ereed@android.com
16094faa869cdabbdcf4867118b4a1272296baaeeb52commit-bot@chromium.orgsize_t SkMatrix::readFromMemory(const void* buffer, size_t length) {
16104faa869cdabbdcf4867118b4a1272296baaeeb52commit-bot@chromium.org    static const size_t sizeInMemory = 9 * sizeof(SkScalar);
16114faa869cdabbdcf4867118b4a1272296baaeeb52commit-bot@chromium.org    if (length < sizeInMemory) {
16124faa869cdabbdcf4867118b4a1272296baaeeb52commit-bot@chromium.org        return 0;
16134faa869cdabbdcf4867118b4a1272296baaeeb52commit-bot@chromium.org    }
1614f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com    if (buffer) {
16154faa869cdabbdcf4867118b4a1272296baaeeb52commit-bot@chromium.org        memcpy(fMat, buffer, sizeInMemory);
1616f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com        this->setTypeMask(kUnknown_Mask);
1617f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com    }
16184faa869cdabbdcf4867118b4a1272296baaeeb52commit-bot@chromium.org    return sizeInMemory;
16190ad336f8c6f6f0325eee309c9cd501ea432cc33ereed@android.com}
16200ad336f8c6f6f0325eee309c9cd501ea432cc33ereed@android.com
162176f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com#ifdef SK_DEVELOPER
16228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkMatrix::dump() const {
16238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkString str;
162476f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com    this->toString(&str);
16258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkDebugf("%s\n", str.c_str());
16268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
16270f10f7bf1fb43ca6346dc220a076773b1f19a367commit-bot@chromium.org#endif
16288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
16290f10f7bf1fb43ca6346dc220a076773b1f19a367commit-bot@chromium.org#ifndef SK_IGNORE_TO_STRING
163076f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.comvoid SkMatrix::toString(SkString* str) const {
163176f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com    str->appendf("[%8.4f %8.4f %8.4f][%8.4f %8.4f %8.4f][%8.4f %8.4f %8.4f]",
16328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com             fMat[0], fMat[1], fMat[2], fMat[3], fMat[4], fMat[5],
16338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com             fMat[6], fMat[7], fMat[8]);
16348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
163576f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com#endif
1636ad514302158887002e83625a837f9ecbe540d1d3reed@google.com
1637ad514302158887002e83625a837f9ecbe540d1d3reed@google.com///////////////////////////////////////////////////////////////////////////////
1638ad514302158887002e83625a837f9ecbe540d1d3reed@google.com
1639ad514302158887002e83625a837f9ecbe540d1d3reed@google.com#include "SkMatrixUtils.h"
1640ad514302158887002e83625a837f9ecbe540d1d3reed@google.com
1641ae57358447bac678e3fc458fa2857a349a6a7081reed@google.combool SkTreatAsSprite(const SkMatrix& mat, int width, int height,
1642ad514302158887002e83625a837f9ecbe540d1d3reed@google.com                     unsigned subpixelBits) {
1643ae57358447bac678e3fc458fa2857a349a6a7081reed@google.com    // quick reject on affine or perspective
1644ad514302158887002e83625a837f9ecbe540d1d3reed@google.com    if (mat.getType() & ~(SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)) {
1645ad514302158887002e83625a837f9ecbe540d1d3reed@google.com        return false;
1646ad514302158887002e83625a837f9ecbe540d1d3reed@google.com    }
1647422188f3c6286d2991a029027958387b070e4dc6skia.committer@gmail.com
1648ad514302158887002e83625a837f9ecbe540d1d3reed@google.com    // quick success check
1649ad514302158887002e83625a837f9ecbe540d1d3reed@google.com    if (!subpixelBits && !(mat.getType() & ~SkMatrix::kTranslate_Mask)) {
1650ad514302158887002e83625a837f9ecbe540d1d3reed@google.com        return true;
1651ad514302158887002e83625a837f9ecbe540d1d3reed@google.com    }
1652422188f3c6286d2991a029027958387b070e4dc6skia.committer@gmail.com
1653ad514302158887002e83625a837f9ecbe540d1d3reed@google.com    // mapRect supports negative scales, so we eliminate those first
1654ad514302158887002e83625a837f9ecbe540d1d3reed@google.com    if (mat.getScaleX() < 0 || mat.getScaleY() < 0) {
1655ad514302158887002e83625a837f9ecbe540d1d3reed@google.com        return false;
1656ad514302158887002e83625a837f9ecbe540d1d3reed@google.com    }
1657422188f3c6286d2991a029027958387b070e4dc6skia.committer@gmail.com
1658ad514302158887002e83625a837f9ecbe540d1d3reed@google.com    SkRect dst;
1659ae57358447bac678e3fc458fa2857a349a6a7081reed@google.com    SkIRect isrc = { 0, 0, width, height };
1660d9f65e3df45c9b4994c70f6bf13d29985afd2f65skia.committer@gmail.com
1661ad514302158887002e83625a837f9ecbe540d1d3reed@google.com    {
1662ae57358447bac678e3fc458fa2857a349a6a7081reed@google.com        SkRect src;
1663ae57358447bac678e3fc458fa2857a349a6a7081reed@google.com        src.set(isrc);
1664ae57358447bac678e3fc458fa2857a349a6a7081reed@google.com        mat.mapRect(&dst, src);
1665ad514302158887002e83625a837f9ecbe540d1d3reed@google.com    }
1666422188f3c6286d2991a029027958387b070e4dc6skia.committer@gmail.com
1667ae57358447bac678e3fc458fa2857a349a6a7081reed@google.com    // just apply the translate to isrc
1668ae57358447bac678e3fc458fa2857a349a6a7081reed@google.com    isrc.offset(SkScalarRoundToInt(mat.getTranslateX()),
1669ae57358447bac678e3fc458fa2857a349a6a7081reed@google.com                SkScalarRoundToInt(mat.getTranslateY()));
1670ae57358447bac678e3fc458fa2857a349a6a7081reed@google.com
1671ad514302158887002e83625a837f9ecbe540d1d3reed@google.com    if (subpixelBits) {
1672ad514302158887002e83625a837f9ecbe540d1d3reed@google.com        isrc.fLeft <<= subpixelBits;
1673ad514302158887002e83625a837f9ecbe540d1d3reed@google.com        isrc.fTop <<= subpixelBits;
1674ad514302158887002e83625a837f9ecbe540d1d3reed@google.com        isrc.fRight <<= subpixelBits;
1675ad514302158887002e83625a837f9ecbe540d1d3reed@google.com        isrc.fBottom <<= subpixelBits;
1676422188f3c6286d2991a029027958387b070e4dc6skia.committer@gmail.com
1677ad514302158887002e83625a837f9ecbe540d1d3reed@google.com        const float scale = 1 << subpixelBits;
1678ad514302158887002e83625a837f9ecbe540d1d3reed@google.com        dst.fLeft *= scale;
1679ad514302158887002e83625a837f9ecbe540d1d3reed@google.com        dst.fTop *= scale;
1680ad514302158887002e83625a837f9ecbe540d1d3reed@google.com        dst.fRight *= scale;
1681ad514302158887002e83625a837f9ecbe540d1d3reed@google.com        dst.fBottom *= scale;
1682ad514302158887002e83625a837f9ecbe540d1d3reed@google.com    }
1683422188f3c6286d2991a029027958387b070e4dc6skia.committer@gmail.com
1684ae57358447bac678e3fc458fa2857a349a6a7081reed@google.com    SkIRect idst;
1685ad514302158887002e83625a837f9ecbe540d1d3reed@google.com    dst.round(&idst);
1686ad514302158887002e83625a837f9ecbe540d1d3reed@google.com    return isrc == idst;
1687ad514302158887002e83625a837f9ecbe540d1d3reed@google.com}
168808284e4d2421fb6c1978e68038a3568711cd9877commit-bot@chromium.org
16895b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org// A square matrix M can be decomposed (via polar decomposition) into two matrices --
16905b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org// an orthogonal matrix Q and a symmetric matrix S. In turn we can decompose S into U*W*U^T,
16915b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org// where U is another orthogonal matrix and W is a scale matrix. These can be recombined
16925b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org// to give M = (Q*U)*W*U^T, i.e., the product of two orthogonal matrices and a scale matrix.
16935b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org//
16945b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org// The one wrinkle is that traditionally Q may contain a reflection -- the
16955b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org// calculation has been rejiggered to put that reflection into W.
169608284e4d2421fb6c1978e68038a3568711cd9877commit-bot@chromium.orgbool SkDecomposeUpper2x2(const SkMatrix& matrix,
16975b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org                         SkPoint* rotation1,
16985b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org                         SkPoint* scale,
16995b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org                         SkPoint* rotation2) {
170008284e4d2421fb6c1978e68038a3568711cd9877commit-bot@chromium.org
170108284e4d2421fb6c1978e68038a3568711cd9877commit-bot@chromium.org    SkScalar A = matrix[SkMatrix::kMScaleX];
170208284e4d2421fb6c1978e68038a3568711cd9877commit-bot@chromium.org    SkScalar B = matrix[SkMatrix::kMSkewX];
170308284e4d2421fb6c1978e68038a3568711cd9877commit-bot@chromium.org    SkScalar C = matrix[SkMatrix::kMSkewY];
170408284e4d2421fb6c1978e68038a3568711cd9877commit-bot@chromium.org    SkScalar D = matrix[SkMatrix::kMScaleY];
170508284e4d2421fb6c1978e68038a3568711cd9877commit-bot@chromium.org
17064dcd062803fef457899add1df56e9defb667ce8dcommit-bot@chromium.org    if (is_degenerate_2x2(A, B, C, D)) {
17074dcd062803fef457899add1df56e9defb667ce8dcommit-bot@chromium.org        return false;
17084dcd062803fef457899add1df56e9defb667ce8dcommit-bot@chromium.org    }
17094dcd062803fef457899add1df56e9defb667ce8dcommit-bot@chromium.org
17105b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org    double w1, w2;
17115b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org    SkScalar cos1, sin1;
17125b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org    SkScalar cos2, sin2;
171308284e4d2421fb6c1978e68038a3568711cd9877commit-bot@chromium.org
17145b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org    // do polar decomposition (M = Q*S)
17155b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org    SkScalar cosQ, sinQ;
17165b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org    double Sa, Sb, Sd;
17175b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org    // if M is already symmetric (i.e., M = I*S)
17185b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org    if (SkScalarNearlyEqual(B, C)) {
17190b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org        cosQ = 1;
17205b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org        sinQ = 0;
172108284e4d2421fb6c1978e68038a3568711cd9877commit-bot@chromium.org
17225b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org        Sa = A;
17235b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org        Sb = B;
17245b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org        Sd = D;
172508284e4d2421fb6c1978e68038a3568711cd9877commit-bot@chromium.org    } else {
17265b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org        cosQ = A + D;
17275b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org        sinQ = C - B;
17280b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org        SkScalar reciplen = SkScalarInvert(SkScalarSqrt(cosQ*cosQ + sinQ*sinQ));
17295b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org        cosQ *= reciplen;
17305b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org        sinQ *= reciplen;
17315b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org
17325b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org        // S = Q^-1*M
17335b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org        // we don't calc Sc since it's symmetric
17345b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org        Sa = A*cosQ + C*sinQ;
17355b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org        Sb = B*cosQ + D*sinQ;
17365b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org        Sd = -B*sinQ + D*cosQ;
17375b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org    }
17385b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org
17395b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org    // Now we need to compute eigenvalues of S (our scale factors)
17405b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org    // and eigenvectors (bases for our rotation)
17415b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org    // From this, should be able to reconstruct S as U*W*U^T
174225f72ed03485f58998846d80858d64b5a3c40c7fjvanverth@google.com    if (SkScalarNearlyZero(SkDoubleToScalar(Sb))) {
17435b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org        // already diagonalized
17440b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org        cos1 = 1;
17455b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org        sin1 = 0;
17465b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org        w1 = Sa;
17475b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org        w2 = Sd;
17485b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org        cos2 = cosQ;
17495b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org        sin2 = sinQ;
175085092f05c406ed5a0c65ff576816924c1a6b903bskia.committer@gmail.com    } else {
17515b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org        double diff = Sa - Sd;
17525b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org        double discriminant = sqrt(diff*diff + 4.0*Sb*Sb);
17535b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org        double trace = Sa + Sd;
17545b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org        if (diff > 0) {
17555b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org            w1 = 0.5*(trace + discriminant);
17565b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org            w2 = 0.5*(trace - discriminant);
17575b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org        } else {
17585b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org            w1 = 0.5*(trace - discriminant);
17595b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org            w2 = 0.5*(trace + discriminant);
176008284e4d2421fb6c1978e68038a3568711cd9877commit-bot@chromium.org        }
176185092f05c406ed5a0c65ff576816924c1a6b903bskia.committer@gmail.com
176225f72ed03485f58998846d80858d64b5a3c40c7fjvanverth@google.com        cos1 = SkDoubleToScalar(Sb); sin1 = SkDoubleToScalar(w1 - Sa);
17630b9ada1318acf7d5fe90c57331c2a4548aad8b98commit-bot@chromium.org        SkScalar reciplen = SkScalarInvert(SkScalarSqrt(cos1*cos1 + sin1*sin1));
17645b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org        cos1 *= reciplen;
17655b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org        sin1 *= reciplen;
176685092f05c406ed5a0c65ff576816924c1a6b903bskia.committer@gmail.com
17675b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org        // rotation 2 is composition of Q and U
17685b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org        cos2 = cos1*cosQ - sin1*sinQ;
17695b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org        sin2 = sin1*cosQ + cos1*sinQ;
177085092f05c406ed5a0c65ff576816924c1a6b903bskia.committer@gmail.com
17715b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org        // rotation 1 is U^T
17725b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org        sin1 = -sin1;
17735b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org    }
17745b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org
17755b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org    if (NULL != scale) {
177625f72ed03485f58998846d80858d64b5a3c40c7fjvanverth@google.com        scale->fX = SkDoubleToScalar(w1);
177725f72ed03485f58998846d80858d64b5a3c40c7fjvanverth@google.com        scale->fY = SkDoubleToScalar(w2);
177808284e4d2421fb6c1978e68038a3568711cd9877commit-bot@chromium.org    }
177908284e4d2421fb6c1978e68038a3568711cd9877commit-bot@chromium.org    if (NULL != rotation1) {
17805b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org        rotation1->fX = cos1;
17815b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org        rotation1->fY = sin1;
17825b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org    }
17835b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org    if (NULL != rotation2) {
17845b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org        rotation2->fX = cos2;
17855b2e2640ed345c4670b99b349f62eb6f9446ec1ecommit-bot@chromium.org        rotation2->fY = sin2;
178608284e4d2421fb6c1978e68038a3568711cd9877commit-bot@chromium.org    }
178708284e4d2421fb6c1978e68038a3568711cd9877commit-bot@chromium.org
178808284e4d2421fb6c1978e68038a3568711cd9877commit-bot@chromium.org    return true;
178908284e4d2421fb6c1978e68038a3568711cd9877commit-bot@chromium.org}
1790