1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
28a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/*
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2006 The Android Open Source Project
48a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
78a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com */
88a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifndef SkMatrix_DEFINED
118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define SkMatrix_DEFINED
128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
130b544ae222aab1c5d9122a8dfe2800451b31d979mtklein#include "SkDynamicAnnotations.h"
148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkRect.h"
158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comclass SkString;
178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
188f4d2306fa866a26f9448048ff63f692b2ba43aareed@google.com// TODO: can we remove these 3 (need to check chrome/android)
198f4d2306fa866a26f9448048ff63f692b2ba43aareed@google.comtypedef SkScalar SkPersp;
208f4d2306fa866a26f9448048ff63f692b2ba43aareed@google.com#define SkScalarToPersp(x) (x)
218f4d2306fa866a26f9448048ff63f692b2ba43aareed@google.com#define SkPerspToScalar(x) (x)
2207faed110275048c83a55ae39042da2c9d916108bungeman@google.com
238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/** \class SkMatrix
248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    The SkMatrix class holds a 3x3 matrix for transforming coordinates.
268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkMatrix does not have a constructor, so it must be explicitly initialized
278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    using either reset() - to construct an identity matrix, or one of the set
288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    functions (e.g. setTranslate, setRotate, etc.).
298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com*/
307ffb1b21abcc7bbed5a0fc711f6dd7b9dbb4f577ctguil@chromium.orgclass SK_API SkMatrix {
318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic:
328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** Enum of bit fields for the mask return by getType().
338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        Use this to identify the complexity of the matrix.
348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    enum TypeMask {
368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        kIdentity_Mask      = 0,
378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        kTranslate_Mask     = 0x01,  //!< set if the matrix has translation
388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        kScale_Mask         = 0x02,  //!< set if the matrix has X or Y scale
398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        kAffine_Mask        = 0x04,  //!< set if the matrix skews or rotates
408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        kPerspective_Mask   = 0x08   //!< set if the matrix is in perspective
418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    };
428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
43fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com    /** Returns a bitfield describing the transformations the matrix may
44fd4c00eb36c9164487bf9e1cea39eaca64a9be91bsalomon@google.com        perform. The bitfield is computed conservatively, so it may include
45fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com        false positives. For example, when kPerspective_Mask is true, all
46fd4c00eb36c9164487bf9e1cea39eaca64a9be91bsalomon@google.com        other bits may be set to true even in the case of a pure perspective
47fd4c00eb36c9164487bf9e1cea39eaca64a9be91bsalomon@google.com        transform.
486fc5699e777c27c4eea9587a131aecf6e92a677ajunov@chromium.org   */
498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    TypeMask getType() const {
508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (fTypeMask & kUnknown_Mask) {
518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fTypeMask = this->computeTypeMask();
528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // only return the public masks
548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return (TypeMask)(fTypeMask & 0xF);
558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** Returns true if the matrix is identity.
588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bool isIdentity() const {
608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return this->getType() == 0;
618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
63e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips    bool isScaleTranslate() const {
64e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips        return !(this->getType() & ~(kScale_Mask | kTranslate_Mask));
65e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips    }
66e12770148a7d170e4845ebfae75ac38ae9cf4f32Robert Phillips
678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** Returns true if will map a rectangle to another rectangle. This can be
688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        true if the matrix is identity, scale-only, or rotates a multiple of
698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        90 degrees.
708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bool rectStaysRect() const {
728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (fTypeMask & kUnknown_Mask) {
738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fTypeMask = this->computeTypeMask();
748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return (fTypeMask & kRectStaysRect_Mask) != 0;
768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
77cc4dac3dac215dc0dd56f7b30d07cc304671b033bsalomon@google.com    // alias for rectStaysRect()
78cc4dac3dac215dc0dd56f7b30d07cc304671b033bsalomon@google.com    bool preservesAxisAlignment() const { return this->rectStaysRect(); }
79cc4dac3dac215dc0dd56f7b30d07cc304671b033bsalomon@google.com
80cc4dac3dac215dc0dd56f7b30d07cc304671b033bsalomon@google.com    /**
81dd5f7442f65813c1023a59c3380f4446583ccd5dtomhudson@google.com     *  Returns true if the matrix contains perspective elements.
82cc4dac3dac215dc0dd56f7b30d07cc304671b033bsalomon@google.com     */
83cc4dac3dac215dc0dd56f7b30d07cc304671b033bsalomon@google.com    bool hasPerspective() const {
84dd5f7442f65813c1023a59c3380f4446583ccd5dtomhudson@google.com        return SkToBool(this->getPerspectiveTypeMaskOnly() &
85dd5f7442f65813c1023a59c3380f4446583ccd5dtomhudson@google.com                        kPerspective_Mask);
86cc4dac3dac215dc0dd56f7b30d07cc304671b033bsalomon@google.com    }
878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8817a845f76094eb3b5ac464556fced2a60dd0f088jvanverth    /** Returns true if the matrix contains only translation, rotation/reflection or uniform scale
8946d3d39e65e0b3ea2ad7c91c176ccafb4df0fa24jvanverth@google.com        Returns false if other transformation types are included or is degenerate
9046d3d39e65e0b3ea2ad7c91c176ccafb4df0fa24jvanverth@google.com     */
9146d3d39e65e0b3ea2ad7c91c176ccafb4df0fa24jvanverth@google.com    bool isSimilarity(SkScalar tol = SK_ScalarNearlyZero) const;
9246d3d39e65e0b3ea2ad7c91c176ccafb4df0fa24jvanverth@google.com
9317a845f76094eb3b5ac464556fced2a60dd0f088jvanverth    /** Returns true if the matrix contains only translation, rotation/reflection or scale
94df3695e5c72b3b4401e71ff259827d87bfe8a06frobertphillips@google.com        (non-uniform scale is allowed).
95df3695e5c72b3b4401e71ff259827d87bfe8a06frobertphillips@google.com        Returns false if other transformation types are included or is degenerate
96df3695e5c72b3b4401e71ff259827d87bfe8a06frobertphillips@google.com     */
97df3695e5c72b3b4401e71ff259827d87bfe8a06frobertphillips@google.com    bool preservesRightAngles(SkScalar tol = SK_ScalarNearlyZero) const;
98df3695e5c72b3b4401e71ff259827d87bfe8a06frobertphillips@google.com
998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    enum {
1008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        kMScaleX,
1018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        kMSkewX,
1028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        kMTransX,
1038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        kMSkewY,
1048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        kMScaleY,
1058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        kMTransY,
1068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        kMPersp0,
1078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        kMPersp1,
1088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        kMPersp2
1098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    };
110fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
1111ddd7c39289b7dd18537fdac4b630e378cd78842bungeman@google.com    /** Affine arrays are in column major order
1121ddd7c39289b7dd18537fdac4b630e378cd78842bungeman@google.com        because that's how PDF and XPS like it.
1131ddd7c39289b7dd18537fdac4b630e378cd78842bungeman@google.com     */
1141ddd7c39289b7dd18537fdac4b630e378cd78842bungeman@google.com    enum {
1151ddd7c39289b7dd18537fdac4b630e378cd78842bungeman@google.com        kAScaleX,
1161ddd7c39289b7dd18537fdac4b630e378cd78842bungeman@google.com        kASkewY,
1171ddd7c39289b7dd18537fdac4b630e378cd78842bungeman@google.com        kASkewX,
1181ddd7c39289b7dd18537fdac4b630e378cd78842bungeman@google.com        kAScaleY,
1191ddd7c39289b7dd18537fdac4b630e378cd78842bungeman@google.com        kATransX,
1201ddd7c39289b7dd18537fdac4b630e378cd78842bungeman@google.com        kATransY
1211ddd7c39289b7dd18537fdac4b630e378cd78842bungeman@google.com    };
1221ddd7c39289b7dd18537fdac4b630e378cd78842bungeman@google.com
1238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkScalar operator[](int index) const {
1248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT((unsigned)index < 9);
1258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return fMat[index];
1268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
127fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
1288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkScalar get(int index) const {
1298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT((unsigned)index < 9);
1308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return fMat[index];
1318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
132fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
1338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkScalar getScaleX() const { return fMat[kMScaleX]; }
1348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkScalar getScaleY() const { return fMat[kMScaleY]; }
1358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkScalar getSkewY() const { return fMat[kMSkewY]; }
1368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkScalar getSkewX() const { return fMat[kMSkewX]; }
1378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkScalar getTranslateX() const { return fMat[kMTransX]; }
1388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkScalar getTranslateY() const { return fMat[kMTransY]; }
13907faed110275048c83a55ae39042da2c9d916108bungeman@google.com    SkPersp getPerspX() const { return fMat[kMPersp0]; }
14007faed110275048c83a55ae39042da2c9d916108bungeman@google.com    SkPersp getPerspY() const { return fMat[kMPersp1]; }
1418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
142d055c1fde2128514167b315f4d104b177e04a3dereed@android.com    SkScalar& operator[](int index) {
143d055c1fde2128514167b315f4d104b177e04a3dereed@android.com        SkASSERT((unsigned)index < 9);
144d055c1fde2128514167b315f4d104b177e04a3dereed@android.com        this->setTypeMask(kUnknown_Mask);
145d055c1fde2128514167b315f4d104b177e04a3dereed@android.com        return fMat[index];
146d055c1fde2128514167b315f4d104b177e04a3dereed@android.com    }
147d055c1fde2128514167b315f4d104b177e04a3dereed@android.com
1488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void set(int index, SkScalar value) {
1498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT((unsigned)index < 9);
1508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fMat[index] = value;
1518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        this->setTypeMask(kUnknown_Mask);
1528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void setScaleX(SkScalar v) { this->set(kMScaleX, v); }
1558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void setScaleY(SkScalar v) { this->set(kMScaleY, v); }
1568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void setSkewY(SkScalar v) { this->set(kMSkewY, v); }
1578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void setSkewX(SkScalar v) { this->set(kMSkewX, v); }
1588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void setTranslateX(SkScalar v) { this->set(kMTransX, v); }
1598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void setTranslateY(SkScalar v) { this->set(kMTransY, v); }
16007faed110275048c83a55ae39042da2c9d916108bungeman@google.com    void setPerspX(SkPersp v) { this->set(kMPersp0, v); }
16107faed110275048c83a55ae39042da2c9d916108bungeman@google.com    void setPerspY(SkPersp v) { this->set(kMPersp1, v); }
1628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
163cc4dac3dac215dc0dd56f7b30d07cc304671b033bsalomon@google.com    void setAll(SkScalar scaleX, SkScalar skewX, SkScalar transX,
164cc4dac3dac215dc0dd56f7b30d07cc304671b033bsalomon@google.com                SkScalar skewY, SkScalar scaleY, SkScalar transY,
16507faed110275048c83a55ae39042da2c9d916108bungeman@google.com                SkPersp persp0, SkPersp persp1, SkPersp persp2) {
166cc4dac3dac215dc0dd56f7b30d07cc304671b033bsalomon@google.com        fMat[kMScaleX] = scaleX;
167cc4dac3dac215dc0dd56f7b30d07cc304671b033bsalomon@google.com        fMat[kMSkewX]  = skewX;
168cc4dac3dac215dc0dd56f7b30d07cc304671b033bsalomon@google.com        fMat[kMTransX] = transX;
169cc4dac3dac215dc0dd56f7b30d07cc304671b033bsalomon@google.com        fMat[kMSkewY]  = skewY;
170cc4dac3dac215dc0dd56f7b30d07cc304671b033bsalomon@google.com        fMat[kMScaleY] = scaleY;
171cc4dac3dac215dc0dd56f7b30d07cc304671b033bsalomon@google.com        fMat[kMTransY] = transY;
172cc4dac3dac215dc0dd56f7b30d07cc304671b033bsalomon@google.com        fMat[kMPersp0] = persp0;
173cc4dac3dac215dc0dd56f7b30d07cc304671b033bsalomon@google.com        fMat[kMPersp1] = persp1;
174cc4dac3dac215dc0dd56f7b30d07cc304671b033bsalomon@google.com        fMat[kMPersp2] = persp2;
175cc4dac3dac215dc0dd56f7b30d07cc304671b033bsalomon@google.com        this->setTypeMask(kUnknown_Mask);
176cc4dac3dac215dc0dd56f7b30d07cc304671b033bsalomon@google.com    }
177fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
1788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** Set the matrix to identity
1798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
1808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void reset();
181cc4dac3dac215dc0dd56f7b30d07cc304671b033bsalomon@google.com    // alias for reset()
182cc4dac3dac215dc0dd56f7b30d07cc304671b033bsalomon@google.com    void setIdentity() { this->reset(); }
183cc4dac3dac215dc0dd56f7b30d07cc304671b033bsalomon@google.com
1848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** Set the matrix to translate by (dx, dy).
1858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
1868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void setTranslate(SkScalar dx, SkScalar dy);
1877b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com    void setTranslate(const SkVector& v) { this->setTranslate(v.fX, v.fY); }
1887b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com
1898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** Set the matrix to scale by sx and sy, with a pivot point at (px, py).
1908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        The pivot point is the coordinate that should remain unchanged by the
1918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        specified transformation.
1928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
1938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py);
1948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** Set the matrix to scale by sx and sy.
1958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
1968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void setScale(SkScalar sx, SkScalar sy);
1975c63865b529eb5714e41419dfa23c70d26ff6e4ebsalomon@google.com    /** Set the matrix to scale by 1/divx and 1/divy. Returns false and doesn't
1985c63865b529eb5714e41419dfa23c70d26ff6e4ebsalomon@google.com        touch the matrix if either divx or divy is zero.
1995c63865b529eb5714e41419dfa23c70d26ff6e4ebsalomon@google.com    */
2005c63865b529eb5714e41419dfa23c70d26ff6e4ebsalomon@google.com    bool setIDiv(int divx, int divy);
2018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** Set the matrix to rotate by the specified number of degrees, with a
2028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        pivot point at (px, py). The pivot point is the coordinate that should
2038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        remain unchanged by the specified transformation.
2048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
2058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void setRotate(SkScalar degrees, SkScalar px, SkScalar py);
2068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** Set the matrix to rotate about (0,0) by the specified number of degrees.
2078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
2088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void setRotate(SkScalar degrees);
2098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** Set the matrix to rotate by the specified sine and cosine values, with
2108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        a pivot point at (px, py). The pivot point is the coordinate that
2118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        should remain unchanged by the specified transformation.
2128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
2138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void setSinCos(SkScalar sinValue, SkScalar cosValue,
2148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                   SkScalar px, SkScalar py);
2158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** Set the matrix to rotate by the specified sine and cosine values.
2168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
2178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void setSinCos(SkScalar sinValue, SkScalar cosValue);
2188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** Set the matrix to skew by sx and sy, with a pivot point at (px, py).
2198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        The pivot point is the coordinate that should remain unchanged by the
2208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        specified transformation.
2218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
2228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void setSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py);
2238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** Set the matrix to skew by sx and sy.
2248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
2258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void setSkew(SkScalar kx, SkScalar ky);
22692362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org    /** Set the matrix to the concatenation of the two specified matrices.
22792362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org        Either of the two matrices may also be the target matrix.
22892362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org        *this = a * b;
2298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
23092362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org    void setConcat(const SkMatrix& a, const SkMatrix& b);
2318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** Preconcats the matrix with the specified translation.
2338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        M' = M * T(dx, dy)
2348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
23592362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org    void preTranslate(SkScalar dx, SkScalar dy);
2368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** Preconcats the matrix with the specified scale.
2378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        M' = M * S(sx, sy, px, py)
2388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
23992362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org    void preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py);
2408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** Preconcats the matrix with the specified scale.
2418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        M' = M * S(sx, sy)
2428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
24392362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org    void preScale(SkScalar sx, SkScalar sy);
2448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** Preconcats the matrix with the specified rotation.
2458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        M' = M * R(degrees, px, py)
2468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
24792362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org    void preRotate(SkScalar degrees, SkScalar px, SkScalar py);
2488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** Preconcats the matrix with the specified rotation.
2498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        M' = M * R(degrees)
2508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
25192362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org    void preRotate(SkScalar degrees);
2528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** Preconcats the matrix with the specified skew.
2538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        M' = M * K(kx, ky, px, py)
2548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
25592362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org    void preSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py);
2568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** Preconcats the matrix with the specified skew.
2578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        M' = M * K(kx, ky)
2588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
25992362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org    void preSkew(SkScalar kx, SkScalar ky);
2608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** Preconcats the matrix with the specified matrix.
2618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        M' = M * other
2628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
26392362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org    void preConcat(const SkMatrix& other);
2648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** Postconcats the matrix with the specified translation.
2668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        M' = T(dx, dy) * M
2678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
26892362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org    void postTranslate(SkScalar dx, SkScalar dy);
2698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** Postconcats the matrix with the specified scale.
2708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        M' = S(sx, sy, px, py) * M
2718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
27292362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org    void postScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py);
2738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** Postconcats the matrix with the specified scale.
2748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        M' = S(sx, sy) * M
2758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
27692362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org    void postScale(SkScalar sx, SkScalar sy);
2778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** Postconcats the matrix by dividing it by the specified integers.
2788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        M' = S(1/divx, 1/divy, 0, 0) * M
2798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
2808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bool postIDiv(int divx, int divy);
2818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** Postconcats the matrix with the specified rotation.
2828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        M' = R(degrees, px, py) * M
2838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
28492362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org    void postRotate(SkScalar degrees, SkScalar px, SkScalar py);
2858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** Postconcats the matrix with the specified rotation.
2868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        M' = R(degrees) * M
2878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
28892362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org    void postRotate(SkScalar degrees);
2898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** Postconcats the matrix with the specified skew.
2908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        M' = K(kx, ky, px, py) * M
2918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
29292362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org    void postSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py);
2938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** Postconcats the matrix with the specified skew.
2948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        M' = K(kx, ky) * M
2958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
29692362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org    void postSkew(SkScalar kx, SkScalar ky);
2978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** Postconcats the matrix with the specified matrix.
2988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        M' = other * M
2998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
30092362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org    void postConcat(const SkMatrix& other);
3018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    enum ScaleToFit {
3038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        /**
3048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         * Scale in X and Y independently, so that src matches dst exactly.
3058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         * This may change the aspect ratio of the src.
3068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         */
3078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        kFill_ScaleToFit,
3088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        /**
3098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         * Compute a scale that will maintain the original src aspect ratio,
3108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         * but will also ensure that src fits entirely inside dst. At least one
3118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         * axis (X or Y) will fit exactly. kStart aligns the result to the
3128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         * left and top edges of dst.
3138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         */
3148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        kStart_ScaleToFit,
3158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        /**
3168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         * Compute a scale that will maintain the original src aspect ratio,
3178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         * but will also ensure that src fits entirely inside dst. At least one
3188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         * axis (X or Y) will fit exactly. The result is centered inside dst.
3198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         */
3208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        kCenter_ScaleToFit,
3218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        /**
3228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         * Compute a scale that will maintain the original src aspect ratio,
3238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         * but will also ensure that src fits entirely inside dst. At least one
3248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         * axis (X or Y) will fit exactly. kEnd aligns the result to the
3258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         * right and bottom edges of dst.
3268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         */
3278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        kEnd_ScaleToFit
3288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    };
3298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** Set the matrix to the scale and translate values that map the source
3318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        rectangle to the destination rectangle, returning true if the the result
3328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        can be represented.
3338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        @param src the source rectangle to map from.
3348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        @param dst the destination rectangle to map to.
3358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        @param stf the ScaleToFit option
3368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        @return true if the matrix can be represented by the rectangle mapping.
3378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
3388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bool setRectToRect(const SkRect& src, const SkRect& dst, ScaleToFit stf);
339fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
3408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** Set the matrix such that the specified src points would map to the
3418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        specified dst points. count must be within [0..4].
3428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        @param src  The array of src points
3438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        @param dst  The array of dst points
3448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        @param count The number of points to use for the transformation
3458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        @return true if the matrix was set to the specified transformation
3468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
3478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bool setPolyToPoly(const SkPoint src[], const SkPoint dst[], int count);
3488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** If this matrix can be inverted, return true and if inverse is not null,
3508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        set inverse to be the inverse of this matrix. If this matrix cannot be
3518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        inverted, ignore inverse and return false
3528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
353683c3c76cfd2cc71621e570889a16548f8cc88c6bsalomon@google.com    bool SK_WARN_UNUSED_RESULT invert(SkMatrix* inverse) const {
354683c3c76cfd2cc71621e570889a16548f8cc88c6bsalomon@google.com        // Allow the trivial case to be inlined.
355683c3c76cfd2cc71621e570889a16548f8cc88c6bsalomon@google.com        if (this->isIdentity()) {
35649f085dddff10473b6ebf832a974288300224e60bsalomon            if (inverse) {
357683c3c76cfd2cc71621e570889a16548f8cc88c6bsalomon@google.com                inverse->reset();
358683c3c76cfd2cc71621e570889a16548f8cc88c6bsalomon@google.com            }
359683c3c76cfd2cc71621e570889a16548f8cc88c6bsalomon@google.com            return true;
360683c3c76cfd2cc71621e570889a16548f8cc88c6bsalomon@google.com        }
361683c3c76cfd2cc71621e570889a16548f8cc88c6bsalomon@google.com        return this->invertNonIdentity(inverse);
362683c3c76cfd2cc71621e570889a16548f8cc88c6bsalomon@google.com    }
3638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3641ddd7c39289b7dd18537fdac4b630e378cd78842bungeman@google.com    /** Fills the passed array with affine identity values
3651ddd7c39289b7dd18537fdac4b630e378cd78842bungeman@google.com        in column major order.
3661ddd7c39289b7dd18537fdac4b630e378cd78842bungeman@google.com        @param affine  The array to fill with affine identity values.
3671ddd7c39289b7dd18537fdac4b630e378cd78842bungeman@google.com        Must not be NULL.
3681ddd7c39289b7dd18537fdac4b630e378cd78842bungeman@google.com    */
3691ddd7c39289b7dd18537fdac4b630e378cd78842bungeman@google.com    static void SetAffineIdentity(SkScalar affine[6]);
3701ddd7c39289b7dd18537fdac4b630e378cd78842bungeman@google.com
3711ddd7c39289b7dd18537fdac4b630e378cd78842bungeman@google.com    /** Fills the passed array with the affine values in column major order.
3721ddd7c39289b7dd18537fdac4b630e378cd78842bungeman@google.com        If the matrix is a perspective transform, returns false
3731ddd7c39289b7dd18537fdac4b630e378cd78842bungeman@google.com        and does not change the passed array.
3741ddd7c39289b7dd18537fdac4b630e378cd78842bungeman@google.com        @param affine  The array to fill with affine values. Ignored if NULL.
375ddbbd805b5b453e12cda0b3300e5655d8fb2bc19vandebo@chromium.org    */
3761ddd7c39289b7dd18537fdac4b630e378cd78842bungeman@google.com    bool asAffine(SkScalar affine[6]) const;
377ddbbd805b5b453e12cda0b3300e5655d8fb2bc19vandebo@chromium.org
3788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** Apply this matrix to the array of points specified by src, and write
3798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        the transformed points into the array of points specified by dst.
3808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        dst[] = M * src[]
3818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        @param dst  Where the transformed coordinates are written. It must
3828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    contain at least count entries
3838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        @param src  The original coordinates that are to be transformed. It
3848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    must contain at least count entries
3858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        @param count The number of points in src to read, and then transform
3868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                     into dst.
3878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
3888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void mapPoints(SkPoint dst[], const SkPoint src[], int count) const;
3898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** Apply this matrix to the array of points, overwriting it with the
3918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        transformed values.
3928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        dst[] = M * pts[]
3938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        @param pts  The points to be transformed. It must contain at least
3948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    count entries
3958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        @param count The number of points in pts.
3968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
3978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void mapPoints(SkPoint pts[], int count) const {
3988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        this->mapPoints(pts, pts, count);
3998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
400fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
401647a804c3dd53b6743091ec97dd12111f90efec3bsalomon@google.com    /** Like mapPoints but with custom byte stride between the points. Stride
402647a804c3dd53b6743091ec97dd12111f90efec3bsalomon@google.com     *  should be a multiple of sizeof(SkScalar).
403647a804c3dd53b6743091ec97dd12111f90efec3bsalomon@google.com     */
404647a804c3dd53b6743091ec97dd12111f90efec3bsalomon@google.com    void mapPointsWithStride(SkPoint pts[], size_t stride, int count) const {
405647a804c3dd53b6743091ec97dd12111f90efec3bsalomon@google.com        SkASSERT(stride >= sizeof(SkPoint));
406647a804c3dd53b6743091ec97dd12111f90efec3bsalomon@google.com        SkASSERT(0 == stride % sizeof(SkScalar));
407647a804c3dd53b6743091ec97dd12111f90efec3bsalomon@google.com        for (int i = 0; i < count; ++i) {
408647a804c3dd53b6743091ec97dd12111f90efec3bsalomon@google.com            this->mapPoints(pts, pts, 1);
409647a804c3dd53b6743091ec97dd12111f90efec3bsalomon@google.com            pts = (SkPoint*)((intptr_t)pts + stride);
410647a804c3dd53b6743091ec97dd12111f90efec3bsalomon@google.com        }
411647a804c3dd53b6743091ec97dd12111f90efec3bsalomon@google.com    }
412647a804c3dd53b6743091ec97dd12111f90efec3bsalomon@google.com
413647a804c3dd53b6743091ec97dd12111f90efec3bsalomon@google.com    /** Like mapPoints but with custom byte stride between the points.
414647a804c3dd53b6743091ec97dd12111f90efec3bsalomon@google.com    */
415647a804c3dd53b6743091ec97dd12111f90efec3bsalomon@google.com    void mapPointsWithStride(SkPoint dst[], SkPoint src[],
416647a804c3dd53b6743091ec97dd12111f90efec3bsalomon@google.com                             size_t stride, int count) const {
417647a804c3dd53b6743091ec97dd12111f90efec3bsalomon@google.com        SkASSERT(stride >= sizeof(SkPoint));
418647a804c3dd53b6743091ec97dd12111f90efec3bsalomon@google.com        SkASSERT(0 == stride % sizeof(SkScalar));
419647a804c3dd53b6743091ec97dd12111f90efec3bsalomon@google.com        for (int i = 0; i < count; ++i) {
420647a804c3dd53b6743091ec97dd12111f90efec3bsalomon@google.com            this->mapPoints(dst, src, 1);
421647a804c3dd53b6743091ec97dd12111f90efec3bsalomon@google.com            src = (SkPoint*)((intptr_t)src + stride);
422647a804c3dd53b6743091ec97dd12111f90efec3bsalomon@google.com            dst = (SkPoint*)((intptr_t)dst + stride);
423647a804c3dd53b6743091ec97dd12111f90efec3bsalomon@google.com        }
424647a804c3dd53b6743091ec97dd12111f90efec3bsalomon@google.com    }
425647a804c3dd53b6743091ec97dd12111f90efec3bsalomon@google.com
426259fbaf7a464827bc560517988daeb5836e11e98egdaniel@google.com    /** Apply this matrix to the array of homogeneous points, specified by src,
427259fbaf7a464827bc560517988daeb5836e11e98egdaniel@google.com        where a homogeneous point is defined by 3 contiguous scalar values,
428259fbaf7a464827bc560517988daeb5836e11e98egdaniel@google.com        and write the transformed points into the array of scalars specified by dst.
429259fbaf7a464827bc560517988daeb5836e11e98egdaniel@google.com        dst[] = M * src[]
430259fbaf7a464827bc560517988daeb5836e11e98egdaniel@google.com        @param dst  Where the transformed coordinates are written. It must
431259fbaf7a464827bc560517988daeb5836e11e98egdaniel@google.com                    contain at least 3 * count entries
432259fbaf7a464827bc560517988daeb5836e11e98egdaniel@google.com        @param src  The original coordinates that are to be transformed. It
433259fbaf7a464827bc560517988daeb5836e11e98egdaniel@google.com                    must contain at least 3 * count entries
434259fbaf7a464827bc560517988daeb5836e11e98egdaniel@google.com        @param count The number of triples (homogeneous points) in src to read,
435259fbaf7a464827bc560517988daeb5836e11e98egdaniel@google.com                     and then transform into dst.
436259fbaf7a464827bc560517988daeb5836e11e98egdaniel@google.com    */
437259fbaf7a464827bc560517988daeb5836e11e98egdaniel@google.com    void mapHomogeneousPoints(SkScalar dst[], const SkScalar src[], int count) const;
438259fbaf7a464827bc560517988daeb5836e11e98egdaniel@google.com
4398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void mapXY(SkScalar x, SkScalar y, SkPoint* result) const {
4408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(result);
4418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        this->getMapXYProc()(*this, x, y, result);
4428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
4438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** Apply this matrix to the array of vectors specified by src, and write
4458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        the transformed vectors into the array of vectors specified by dst.
4468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        This is similar to mapPoints, but ignores any translation in the matrix.
4478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        @param dst  Where the transformed coordinates are written. It must
4488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    contain at least count entries
4498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        @param src  The original coordinates that are to be transformed. It
4508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    must contain at least count entries
4518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        @param count The number of vectors in src to read, and then transform
4528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                     into dst.
4538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
4548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void mapVectors(SkVector dst[], const SkVector src[], int count) const;
4558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** Apply this matrix to the array of vectors specified by src, and write
4578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        the transformed vectors into the array of vectors specified by dst.
4588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        This is similar to mapPoints, but ignores any translation in the matrix.
4598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        @param vecs The vectors to be transformed. It must contain at least
4608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    count entries
4618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        @param count The number of vectors in vecs.
4628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
4638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void mapVectors(SkVector vecs[], int count) const {
4648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        this->mapVectors(vecs, vecs, count);
4658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
4668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** Apply this matrix to the src rectangle, and write the transformed
4688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        rectangle into dst. This is accomplished by transforming the 4 corners
4698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        of src, and then setting dst to the bounds of those points.
4708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        @param dst  Where the transformed rectangle is written.
4718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        @param src  The original rectangle to be transformed.
4728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        @return the result of calling rectStaysRect()
4738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
4748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bool mapRect(SkRect* dst, const SkRect& src) const;
4758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** Apply this matrix to the rectangle, and write the transformed rectangle
4778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        back into it. This is accomplished by transforming the 4 corners of
4788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        rect, and then setting it to the bounds of those points
4798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        @param rect The rectangle to transform.
4808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        @return the result of calling rectStaysRect()
4818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
4828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bool mapRect(SkRect* rect) const {
4838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return this->mapRect(rect, *rect);
4848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
4858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
48624ab3b0ce50b3428f063849b6160e468f047487ccommit-bot@chromium.org    /** Apply this matrix to the src rectangle, and write the four transformed
48724ab3b0ce50b3428f063849b6160e468f047487ccommit-bot@chromium.org        points into dst. The points written to dst will be the original top-left, top-right,
48824ab3b0ce50b3428f063849b6160e468f047487ccommit-bot@chromium.org        bottom-right, and bottom-left points transformed by the matrix.
48924ab3b0ce50b3428f063849b6160e468f047487ccommit-bot@chromium.org        @param dst  Where the transformed quad is written.
49024ab3b0ce50b3428f063849b6160e468f047487ccommit-bot@chromium.org        @param rect The original rectangle to be transformed.
49124ab3b0ce50b3428f063849b6160e468f047487ccommit-bot@chromium.org    */
49224ab3b0ce50b3428f063849b6160e468f047487ccommit-bot@chromium.org    void mapRectToQuad(SkPoint dst[4], const SkRect& rect) const {
49324ab3b0ce50b3428f063849b6160e468f047487ccommit-bot@chromium.org        // This could potentially be faster if we only transformed each x and y of the rect once.
49424ab3b0ce50b3428f063849b6160e468f047487ccommit-bot@chromium.org        rect.toQuad(dst);
49524ab3b0ce50b3428f063849b6160e468f047487ccommit-bot@chromium.org        this->mapPoints(dst, 4);
49624ab3b0ce50b3428f063849b6160e468f047487ccommit-bot@chromium.org    }
49724ab3b0ce50b3428f063849b6160e468f047487ccommit-bot@chromium.org
4988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** Return the mean radius of a circle after it has been mapped by
4998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        this matrix. NOTE: in perspective this value assumes the circle
5008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        has its center at the origin.
5018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
5028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkScalar mapRadius(SkScalar radius) const;
5038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    typedef void (*MapXYProc)(const SkMatrix& mat, SkScalar x, SkScalar y,
5058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                 SkPoint* result);
5068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    static MapXYProc GetMapXYProc(TypeMask mask) {
5088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT((mask & ~kAllMasks) == 0);
5098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return gMapXYProcs[mask & kAllMasks];
5108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
511fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
5128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    MapXYProc getMapXYProc() const {
5138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return GetMapXYProc(this->getType());
5148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
5158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    typedef void (*MapPtsProc)(const SkMatrix& mat, SkPoint dst[],
5178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                  const SkPoint src[], int count);
5188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    static MapPtsProc GetMapPtsProc(TypeMask mask) {
5208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT((mask & ~kAllMasks) == 0);
5218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return gMapPtsProcs[mask & kAllMasks];
5228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
523fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
5248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    MapPtsProc getMapPtsProc() const {
5258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return GetMapPtsProc(this->getType());
5268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
5278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** If the matrix can be stepped in X (not complex perspective)
5298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        then return true and if step[XY] is not null, return the step[XY] value.
5308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        If it cannot, return false and ignore step.
5318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
5328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bool fixedStepInX(SkScalar y, SkFixed* stepX, SkFixed* stepY) const;
5338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5348fe84b53a64b5d92f3aabdd8e7fc7b2ee15c0a75bsalomon@google.com    /** Efficient comparison of two matrices. It distinguishes between zero and
5358fe84b53a64b5d92f3aabdd8e7fc7b2ee15c0a75bsalomon@google.com     *  negative zero. It will return false when the sign of zero values is the
5368fe84b53a64b5d92f3aabdd8e7fc7b2ee15c0a75bsalomon@google.com     *  only difference between the two matrices. It considers NaN values to be
5378fe84b53a64b5d92f3aabdd8e7fc7b2ee15c0a75bsalomon@google.com     *  equal to themselves. So a matrix full of NaNs is "cheap equal" to
5388fe84b53a64b5d92f3aabdd8e7fc7b2ee15c0a75bsalomon@google.com     *  another matrix full of NaNs iff the NaN values are bitwise identical
5398fe84b53a64b5d92f3aabdd8e7fc7b2ee15c0a75bsalomon@google.com     *  while according to strict the strict == test a matrix with a NaN value
5408fe84b53a64b5d92f3aabdd8e7fc7b2ee15c0a75bsalomon@google.com     *  is equal to nothing, including itself.
5418fe84b53a64b5d92f3aabdd8e7fc7b2ee15c0a75bsalomon@google.com     */
5428fe84b53a64b5d92f3aabdd8e7fc7b2ee15c0a75bsalomon@google.com    bool cheapEqualTo(const SkMatrix& m) const {
5438fe84b53a64b5d92f3aabdd8e7fc7b2ee15c0a75bsalomon@google.com        return 0 == memcmp(fMat, m.fMat, sizeof(fMat));
5448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
5458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5468fe84b53a64b5d92f3aabdd8e7fc7b2ee15c0a75bsalomon@google.com    friend bool operator==(const SkMatrix& a, const SkMatrix& b);
5473fb5187647397e056843c1f41a508992be22175dreed@google.com    friend bool operator!=(const SkMatrix& a, const SkMatrix& b) {
5483fb5187647397e056843c1f41a508992be22175dreed@google.com        return !(a == b);
5493fb5187647397e056843c1f41a508992be22175dreed@google.com    }
5500ad336f8c6f6f0325eee309c9cd501ea432cc33ereed@android.com
5514b7577b042966657c776fd95c67f9363af57945freed@android.com    enum {
55294e75ee46a569cbcdf61fb7f04ee3a69d3ca0896djsollen@google.com        // writeTo/readFromMemory will never return a value larger than this
5534b7577b042966657c776fd95c67f9363af57945freed@android.com        kMaxFlattenSize = 9 * sizeof(SkScalar) + sizeof(uint32_t)
5544b7577b042966657c776fd95c67f9363af57945freed@android.com    };
5550ad336f8c6f6f0325eee309c9cd501ea432cc33ereed@android.com    // return the number of bytes written, whether or not buffer is null
5564faa869cdabbdcf4867118b4a1272296baaeeb52commit-bot@chromium.org    size_t writeToMemory(void* buffer) const;
5574faa869cdabbdcf4867118b4a1272296baaeeb52commit-bot@chromium.org    /**
5584faa869cdabbdcf4867118b4a1272296baaeeb52commit-bot@chromium.org     * Reads data from the buffer parameter
5594faa869cdabbdcf4867118b4a1272296baaeeb52commit-bot@chromium.org     *
5604faa869cdabbdcf4867118b4a1272296baaeeb52commit-bot@chromium.org     * @param buffer Memory to read from
5614faa869cdabbdcf4867118b4a1272296baaeeb52commit-bot@chromium.org     * @param length Amount of memory available in the buffer
5624faa869cdabbdcf4867118b4a1272296baaeeb52commit-bot@chromium.org     * @return number of bytes read (must be a multiple of 4) or
5634faa869cdabbdcf4867118b4a1272296baaeeb52commit-bot@chromium.org     *         0 if there was not enough memory available
5644faa869cdabbdcf4867118b4a1272296baaeeb52commit-bot@chromium.org     */
5654faa869cdabbdcf4867118b4a1272296baaeeb52commit-bot@chromium.org    size_t readFromMemory(const void* buffer, size_t length);
566fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
56776f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com    SkDEVCODE(void dump() const;)
5680f10f7bf1fb43ca6346dc220a076773b1f19a367commit-bot@chromium.org    SK_TO_STRING_NONVIRT()
5698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
570cc4dac3dac215dc0dd56f7b30d07cc304671b033bsalomon@google.com    /**
571311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org     * Calculates the minimum scaling factor of the matrix as computed from the SVD of the upper
572311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org     * left 2x2. If the matrix has perspective -1 is returned.
573cea9abb001b07eaf4340a78db708bfac9e8c68c2commit-bot@chromium.org     *
5741878651990d7c9da72cf43481432232bbef3550dcommit-bot@chromium.org     * @return minumum scale factor
575cea9abb001b07eaf4340a78db708bfac9e8c68c2commit-bot@chromium.org     */
5761878651990d7c9da72cf43481432232bbef3550dcommit-bot@chromium.org    SkScalar getMinScale() const;
577cea9abb001b07eaf4340a78db708bfac9e8c68c2commit-bot@chromium.org
578cea9abb001b07eaf4340a78db708bfac9e8c68c2commit-bot@chromium.org    /**
579311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org     * Calculates the maximum scaling factor of the matrix as computed from the SVD of the upper
580311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org     * left 2x2. If the matrix has perspective -1 is returned.
581cc4dac3dac215dc0dd56f7b30d07cc304671b033bsalomon@google.com     *
5821878651990d7c9da72cf43481432232bbef3550dcommit-bot@chromium.org     * @return maximum scale factor
583cc4dac3dac215dc0dd56f7b30d07cc304671b033bsalomon@google.com     */
5841878651990d7c9da72cf43481432232bbef3550dcommit-bot@chromium.org    SkScalar getMaxScale() const;
585cc4dac3dac215dc0dd56f7b30d07cc304671b033bsalomon@google.com
586cc4dac3dac215dc0dd56f7b30d07cc304671b033bsalomon@google.com    /**
587311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org     * Gets both the min and max scale factors. The min scale factor is scaleFactors[0] and the max
588311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org     * is scaleFactors[1]. If the matrix has perspective false will be returned and scaleFactors
589311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org     * will be unchanged.
590311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org     */
591311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org    bool getMinMaxScales(SkScalar scaleFactors[2]) const;
59229de433b06aa4886d75508c1aa28ee7911737760skia.committer@gmail.com
593311a3cda9457d50cc7c2a0fc9f153a9ce2c8cb8ecommit-bot@chromium.org    /**
594cc4dac3dac215dc0dd56f7b30d07cc304671b033bsalomon@google.com     *  Return a reference to a const identity matrix
595cc4dac3dac215dc0dd56f7b30d07cc304671b033bsalomon@google.com     */
596cc4dac3dac215dc0dd56f7b30d07cc304671b033bsalomon@google.com    static const SkMatrix& I();
597cc4dac3dac215dc0dd56f7b30d07cc304671b033bsalomon@google.com
598cc4dac3dac215dc0dd56f7b30d07cc304671b033bsalomon@google.com    /**
599cc4dac3dac215dc0dd56f7b30d07cc304671b033bsalomon@google.com     *  Return a reference to a const matrix that is "invalid", one that could
600cc4dac3dac215dc0dd56f7b30d07cc304671b033bsalomon@google.com     *  never be used.
601cc4dac3dac215dc0dd56f7b30d07cc304671b033bsalomon@google.com     */
602cc4dac3dac215dc0dd56f7b30d07cc304671b033bsalomon@google.com    static const SkMatrix& InvalidMatrix();
603cc4dac3dac215dc0dd56f7b30d07cc304671b033bsalomon@google.com
604317d540409bc1d246a272b7f61ffba0097c4bd29tomhudson@google.com    /**
60599bd7d817471ec903a7fe364b4e1d4477b1372b5commit-bot@chromium.org     * Return the concatenation of two matrices, a * b.
60699bd7d817471ec903a7fe364b4e1d4477b1372b5commit-bot@chromium.org     */
60799bd7d817471ec903a7fe364b4e1d4477b1372b5commit-bot@chromium.org    static SkMatrix Concat(const SkMatrix& a, const SkMatrix& b) {
60899bd7d817471ec903a7fe364b4e1d4477b1372b5commit-bot@chromium.org        SkMatrix result;
60999bd7d817471ec903a7fe364b4e1d4477b1372b5commit-bot@chromium.org        result.setConcat(a, b);
61099bd7d817471ec903a7fe364b4e1d4477b1372b5commit-bot@chromium.org        return result;
61199bd7d817471ec903a7fe364b4e1d4477b1372b5commit-bot@chromium.org    }
61299bd7d817471ec903a7fe364b4e1d4477b1372b5commit-bot@chromium.org
61399bd7d817471ec903a7fe364b4e1d4477b1372b5commit-bot@chromium.org    /**
614317d540409bc1d246a272b7f61ffba0097c4bd29tomhudson@google.com     * Testing routine; the matrix's type cache should never need to be
615317d540409bc1d246a272b7f61ffba0097c4bd29tomhudson@google.com     * manually invalidated during normal use.
616317d540409bc1d246a272b7f61ffba0097c4bd29tomhudson@google.com     */
617317d540409bc1d246a272b7f61ffba0097c4bd29tomhudson@google.com    void dirtyMatrixTypeCache() {
618317d540409bc1d246a272b7f61ffba0097c4bd29tomhudson@google.com        this->setTypeMask(kUnknown_Mask);
619317d540409bc1d246a272b7f61ffba0097c4bd29tomhudson@google.com    }
620317d540409bc1d246a272b7f61ffba0097c4bd29tomhudson@google.com
6218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comprivate:
6228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    enum {
6238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        /** Set if the matrix will map a rectangle to another rectangle. This
6248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            can be true if the matrix is scale-only, or rotates a multiple of
6250e5104c1570de4709e04720e62d80a0ca8970260bsalomon@google.com            90 degrees.
626fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
6278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            This bit will be set on identity matrices
6288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        */
6298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        kRectStaysRect_Mask = 0x10,
6308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
631dd5f7442f65813c1023a59c3380f4446583ccd5dtomhudson@google.com        /** Set if the perspective bit is valid even though the rest of
632dd5f7442f65813c1023a59c3380f4446583ccd5dtomhudson@google.com            the matrix is Unknown.
633dd5f7442f65813c1023a59c3380f4446583ccd5dtomhudson@google.com        */
634dd5f7442f65813c1023a59c3380f4446583ccd5dtomhudson@google.com        kOnlyPerspectiveValid_Mask = 0x40,
635dd5f7442f65813c1023a59c3380f4446583ccd5dtomhudson@google.com
6368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        kUnknown_Mask = 0x80,
6373fb5187647397e056843c1f41a508992be22175dreed@google.com
6383fb5187647397e056843c1f41a508992be22175dreed@google.com        kORableMasks =  kTranslate_Mask |
6393fb5187647397e056843c1f41a508992be22175dreed@google.com                        kScale_Mask |
6403fb5187647397e056843c1f41a508992be22175dreed@google.com                        kAffine_Mask |
6413fb5187647397e056843c1f41a508992be22175dreed@google.com                        kPerspective_Mask,
6423fb5187647397e056843c1f41a508992be22175dreed@google.com
6438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        kAllMasks = kTranslate_Mask |
6448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    kScale_Mask |
6458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    kAffine_Mask |
6468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    kPerspective_Mask |
6478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    kRectStaysRect_Mask
6488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    };
6498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
650601d312bd4a894cb6e981a9dfdc644288f3a4d47tomhudson@google.com    SkScalar         fMat[9];
6510b544ae222aab1c5d9122a8dfe2800451b31d979mtklein    mutable SkTRacy<uint32_t> fTypeMask;
6528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    uint8_t computeTypeMask() const;
654dd5f7442f65813c1023a59c3380f4446583ccd5dtomhudson@google.com    uint8_t computePerspectiveTypeMask() const;
6558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void setTypeMask(int mask) {
6578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // allow kUnknown or a valid mask
658dd5f7442f65813c1023a59c3380f4446583ccd5dtomhudson@google.com        SkASSERT(kUnknown_Mask == mask || (mask & kAllMasks) == mask ||
65902662b7febb826752a1c55cda243ad48b2b85adbjunov@chromium.org                 ((kUnknown_Mask | kOnlyPerspectiveValid_Mask) & mask)
66002662b7febb826752a1c55cda243ad48b2b85adbjunov@chromium.org                 == (kUnknown_Mask | kOnlyPerspectiveValid_Mask));
6618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fTypeMask = SkToU8(mask);
6628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
6633fb5187647397e056843c1f41a508992be22175dreed@google.com
6643fb5187647397e056843c1f41a508992be22175dreed@google.com    void orTypeMask(int mask) {
6653fb5187647397e056843c1f41a508992be22175dreed@google.com        SkASSERT((mask & kORableMasks) == mask);
6663fb5187647397e056843c1f41a508992be22175dreed@google.com        fTypeMask = SkToU8(fTypeMask | mask);
6673fb5187647397e056843c1f41a508992be22175dreed@google.com    }
6683fb5187647397e056843c1f41a508992be22175dreed@google.com
6698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void clearTypeMask(int mask) {
6708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // only allow a valid mask
6718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT((mask & kAllMasks) == mask);
6720b544ae222aab1c5d9122a8dfe2800451b31d979mtklein        fTypeMask = fTypeMask & ~mask;
6738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
674dd5f7442f65813c1023a59c3380f4446583ccd5dtomhudson@google.com
675dd5f7442f65813c1023a59c3380f4446583ccd5dtomhudson@google.com    TypeMask getPerspectiveTypeMaskOnly() const {
676dd5f7442f65813c1023a59c3380f4446583ccd5dtomhudson@google.com        if ((fTypeMask & kUnknown_Mask) &&
677dd5f7442f65813c1023a59c3380f4446583ccd5dtomhudson@google.com            !(fTypeMask & kOnlyPerspectiveValid_Mask)) {
678dd5f7442f65813c1023a59c3380f4446583ccd5dtomhudson@google.com            fTypeMask = this->computePerspectiveTypeMask();
679dd5f7442f65813c1023a59c3380f4446583ccd5dtomhudson@google.com        }
680dd5f7442f65813c1023a59c3380f4446583ccd5dtomhudson@google.com        return (TypeMask)(fTypeMask & 0xF);
681dd5f7442f65813c1023a59c3380f4446583ccd5dtomhudson@google.com    }
682dd5f7442f65813c1023a59c3380f4446583ccd5dtomhudson@google.com
683dd5f7442f65813c1023a59c3380f4446583ccd5dtomhudson@google.com    /** Returns true if we already know that the matrix is identity;
684dd5f7442f65813c1023a59c3380f4446583ccd5dtomhudson@google.com        false otherwise.
685dd5f7442f65813c1023a59c3380f4446583ccd5dtomhudson@google.com    */
686dd5f7442f65813c1023a59c3380f4446583ccd5dtomhudson@google.com    bool isTriviallyIdentity() const {
687dd5f7442f65813c1023a59c3380f4446583ccd5dtomhudson@google.com        if (fTypeMask & kUnknown_Mask) {
688dd5f7442f65813c1023a59c3380f4446583ccd5dtomhudson@google.com            return false;
689dd5f7442f65813c1023a59c3380f4446583ccd5dtomhudson@google.com        }
690dd5f7442f65813c1023a59c3380f4446583ccd5dtomhudson@google.com        return ((fTypeMask & 0xF) == 0);
691dd5f7442f65813c1023a59c3380f4446583ccd5dtomhudson@google.com    }
692fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
693683c3c76cfd2cc71621e570889a16548f8cc88c6bsalomon@google.com    bool SK_WARN_UNUSED_RESULT invertNonIdentity(SkMatrix* inverse) const;
694683c3c76cfd2cc71621e570889a16548f8cc88c6bsalomon@google.com
6958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    static bool Poly2Proc(const SkPoint[], SkMatrix*, const SkPoint& scale);
6968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    static bool Poly3Proc(const SkPoint[], SkMatrix*, const SkPoint& scale);
6978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    static bool Poly4Proc(const SkPoint[], SkMatrix*, const SkPoint& scale);
6988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    static void Identity_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
7008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    static void Trans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
7018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    static void Scale_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
7028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    static void ScaleTrans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
7038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    static void Rot_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
7048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    static void RotTrans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
7058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    static void Persp_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
706fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
7078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    static const MapXYProc gMapXYProcs[];
708fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
7098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    static void Identity_pts(const SkMatrix&, SkPoint[], const SkPoint[], int);
7108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    static void Trans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int);
7118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    static void Scale_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int);
7128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    static void ScaleTrans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[],
7138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                               int count);
7148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    static void Rot_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int);
7158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    static void RotTrans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[],
7168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                             int count);
7178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    static void Persp_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int);
718fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
7198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    static const MapPtsProc gMapPtsProcs[];
7208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    friend class SkPerspIter;
7228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
7238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
725