15bb6825f10d64834ad1d1d967f590aebae285360epoger@google.com
2f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com/*
35bb6825f10d64834ad1d1d967f590aebae285360epoger@google.com * Copyright 2006 The Android Open Source Project
4f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com *
55bb6825f10d64834ad1d1d967f590aebae285360epoger@google.com * Use of this source code is governed by a BSD-style license that can be
65bb6825f10d64834ad1d1d967f590aebae285360epoger@google.com * found in the LICENSE file.
7f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com */
8f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com
95bb6825f10d64834ad1d1d967f590aebae285360epoger@google.com
10f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com#ifndef SkMatrix_DEFINED
11f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com#define SkMatrix_DEFINED
12f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com
13f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com#include "SkRect.h"
14f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com
15f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.comclass SkString;
16f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com
1733b76b59d1840fc7731985460404de45fbe26e2bbungeman@google.com#ifdef SK_SCALAR_IS_FLOAT
1833b76b59d1840fc7731985460404de45fbe26e2bbungeman@google.com    typedef SkScalar SkPersp;
1933b76b59d1840fc7731985460404de45fbe26e2bbungeman@google.com    #define SkScalarToPersp(x) (x)
2033b76b59d1840fc7731985460404de45fbe26e2bbungeman@google.com    #define SkPerspToScalar(x) (x)
2133b76b59d1840fc7731985460404de45fbe26e2bbungeman@google.com#else
2233b76b59d1840fc7731985460404de45fbe26e2bbungeman@google.com    typedef SkFract SkPersp;
2333b76b59d1840fc7731985460404de45fbe26e2bbungeman@google.com    #define SkScalarToPersp(x) SkFixedToFract(x)
2433b76b59d1840fc7731985460404de45fbe26e2bbungeman@google.com    #define SkPerspToScalar(x) SkFractToFixed(x)
2533b76b59d1840fc7731985460404de45fbe26e2bbungeman@google.com#endif
2633b76b59d1840fc7731985460404de45fbe26e2bbungeman@google.com
27f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com/** \class SkMatrix
28f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com
29f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    The SkMatrix class holds a 3x3 matrix for transforming coordinates.
30f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    SkMatrix does not have a constructor, so it must be explicitly initialized
31f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    using either reset() - to construct an identity matrix, or one of the set
32f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    functions (e.g. setTranslate, setRotate, etc.).
33f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com*/
342083387d719b933797044ad07efd3bb67f99a5c5ctguil@chromium.orgclass SK_API SkMatrix {
35f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.compublic:
36f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    /** Enum of bit fields for the mask return by getType().
37f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        Use this to identify the complexity of the matrix.
38f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    */
39f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    enum TypeMask {
40f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        kIdentity_Mask      = 0,
41f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        kTranslate_Mask     = 0x01,  //!< set if the matrix has translation
42f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        kScale_Mask         = 0x02,  //!< set if the matrix has X or Y scale
43f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        kAffine_Mask        = 0x04,  //!< set if the matrix skews or rotates
44f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        kPerspective_Mask   = 0x08   //!< set if the matrix is in perspective
45f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    };
46f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com
471fde19f3b72345b473a1a9bd64729237a388813frmistry@google.com    /** Returns a bitfield describing the transformations the matrix may
481de8c88f781c346b3dd92b3a882d1eb3ae1f7e70bsalomon@google.com        perform. The bitfield is computed conservatively, so it may include
491fde19f3b72345b473a1a9bd64729237a388813frmistry@google.com        false positives. For example, when kPerspective_Mask is true, all
501de8c88f781c346b3dd92b3a882d1eb3ae1f7e70bsalomon@google.com        other bits may be set to true even in the case of a pure perspective
511de8c88f781c346b3dd92b3a882d1eb3ae1f7e70bsalomon@google.com        transform.
521ebef13e8530b48413b9439f1595075d04ab1dcdjunov@chromium.org   */
53f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    TypeMask getType() const {
54f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        if (fTypeMask & kUnknown_Mask) {
55f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com            fTypeMask = this->computeTypeMask();
56f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        }
57f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        // only return the public masks
58f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        return (TypeMask)(fTypeMask & 0xF);
59f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    }
60f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com
61f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    /** Returns true if the matrix is identity.
62f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    */
63f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    bool isIdentity() const {
64f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        return this->getType() == 0;
65f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    }
66f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com
67f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    /** Returns true if will map a rectangle to another rectangle. This can be
68f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        true if the matrix is identity, scale-only, or rotates a multiple of
69f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        90 degrees.
70f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    */
71f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    bool rectStaysRect() const {
72f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        if (fTypeMask & kUnknown_Mask) {
73f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com            fTypeMask = this->computeTypeMask();
74f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        }
75f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        return (fTypeMask & kRectStaysRect_Mask) != 0;
76f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    }
77104de7640deeaf4453fed3830ea31b63c29e425ebsalomon@google.com    // alias for rectStaysRect()
78104de7640deeaf4453fed3830ea31b63c29e425ebsalomon@google.com    bool preservesAxisAlignment() const { return this->rectStaysRect(); }
79104de7640deeaf4453fed3830ea31b63c29e425ebsalomon@google.com
80104de7640deeaf4453fed3830ea31b63c29e425ebsalomon@google.com    /**
81b4ca308fe54ba1285a5be3869e595908fbd76e7dtomhudson@google.com     *  Returns true if the matrix contains perspective elements.
82104de7640deeaf4453fed3830ea31b63c29e425ebsalomon@google.com     */
83104de7640deeaf4453fed3830ea31b63c29e425ebsalomon@google.com    bool hasPerspective() const {
84b4ca308fe54ba1285a5be3869e595908fbd76e7dtomhudson@google.com        return SkToBool(this->getPerspectiveTypeMaskOnly() &
85b4ca308fe54ba1285a5be3869e595908fbd76e7dtomhudson@google.com                        kPerspective_Mask);
86104de7640deeaf4453fed3830ea31b63c29e425ebsalomon@google.com    }
87f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com
889f4434e38b0718796d97d6746265f076546dd19cjvanverth@google.com    /** Returns true if the matrix contains only translation, rotation or uniform scale
899f4434e38b0718796d97d6746265f076546dd19cjvanverth@google.com        Returns false if other transformation types are included or is degenerate
909f4434e38b0718796d97d6746265f076546dd19cjvanverth@google.com     */
919f4434e38b0718796d97d6746265f076546dd19cjvanverth@google.com    bool isSimilarity(SkScalar tol = SK_ScalarNearlyZero) const;
929f4434e38b0718796d97d6746265f076546dd19cjvanverth@google.com
93d23e4f39124243f8624e83ef9777f88154427e63robertphillips@google.com    /** Returns true if the matrix contains only translation, rotation or scale
94d23e4f39124243f8624e83ef9777f88154427e63robertphillips@google.com        (non-uniform scale is allowed).
95d23e4f39124243f8624e83ef9777f88154427e63robertphillips@google.com        Returns false if other transformation types are included or is degenerate
96d23e4f39124243f8624e83ef9777f88154427e63robertphillips@google.com     */
97d23e4f39124243f8624e83ef9777f88154427e63robertphillips@google.com    bool preservesRightAngles(SkScalar tol = SK_ScalarNearlyZero) const;
98d23e4f39124243f8624e83ef9777f88154427e63robertphillips@google.com
99f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    enum {
100f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        kMScaleX,
101f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        kMSkewX,
102f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        kMTransX,
103f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        kMSkewY,
104f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        kMScaleY,
105f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        kMTransY,
106f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        kMPersp0,
107f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        kMPersp1,
108f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        kMPersp2
109f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    };
1101fde19f3b72345b473a1a9bd64729237a388813frmistry@google.com
111f5fdad15a20383dafce6acb4024261be76b90988bungeman@google.com    /** Affine arrays are in column major order
112f5fdad15a20383dafce6acb4024261be76b90988bungeman@google.com        because that's how PDF and XPS like it.
113f5fdad15a20383dafce6acb4024261be76b90988bungeman@google.com     */
114f5fdad15a20383dafce6acb4024261be76b90988bungeman@google.com    enum {
115f5fdad15a20383dafce6acb4024261be76b90988bungeman@google.com        kAScaleX,
116f5fdad15a20383dafce6acb4024261be76b90988bungeman@google.com        kASkewY,
117f5fdad15a20383dafce6acb4024261be76b90988bungeman@google.com        kASkewX,
118f5fdad15a20383dafce6acb4024261be76b90988bungeman@google.com        kAScaleY,
119f5fdad15a20383dafce6acb4024261be76b90988bungeman@google.com        kATransX,
120f5fdad15a20383dafce6acb4024261be76b90988bungeman@google.com        kATransY
121f5fdad15a20383dafce6acb4024261be76b90988bungeman@google.com    };
122f5fdad15a20383dafce6acb4024261be76b90988bungeman@google.com
123f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    SkScalar operator[](int index) const {
124f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        SkASSERT((unsigned)index < 9);
125f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        return fMat[index];
126f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    }
1271fde19f3b72345b473a1a9bd64729237a388813frmistry@google.com
128f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    SkScalar get(int index) const {
129f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        SkASSERT((unsigned)index < 9);
130f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        return fMat[index];
131f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    }
1321fde19f3b72345b473a1a9bd64729237a388813frmistry@google.com
133f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    SkScalar getScaleX() const { return fMat[kMScaleX]; }
134f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    SkScalar getScaleY() const { return fMat[kMScaleY]; }
135f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    SkScalar getSkewY() const { return fMat[kMSkewY]; }
136f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    SkScalar getSkewX() const { return fMat[kMSkewX]; }
137f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    SkScalar getTranslateX() const { return fMat[kMTransX]; }
138f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    SkScalar getTranslateY() const { return fMat[kMTransY]; }
13933b76b59d1840fc7731985460404de45fbe26e2bbungeman@google.com    SkPersp getPerspX() const { return fMat[kMPersp0]; }
14033b76b59d1840fc7731985460404de45fbe26e2bbungeman@google.com    SkPersp getPerspY() const { return fMat[kMPersp1]; }
141f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com
14252f5479f914697415df3e7cc6a04f2e751bc564creed@android.com    SkScalar& operator[](int index) {
14352f5479f914697415df3e7cc6a04f2e751bc564creed@android.com        SkASSERT((unsigned)index < 9);
14452f5479f914697415df3e7cc6a04f2e751bc564creed@android.com        this->setTypeMask(kUnknown_Mask);
14552f5479f914697415df3e7cc6a04f2e751bc564creed@android.com        return fMat[index];
14652f5479f914697415df3e7cc6a04f2e751bc564creed@android.com    }
14752f5479f914697415df3e7cc6a04f2e751bc564creed@android.com
148f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    void set(int index, SkScalar value) {
149f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        SkASSERT((unsigned)index < 9);
150f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        fMat[index] = value;
151f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        this->setTypeMask(kUnknown_Mask);
152f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    }
153f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com
154f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    void setScaleX(SkScalar v) { this->set(kMScaleX, v); }
155f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    void setScaleY(SkScalar v) { this->set(kMScaleY, v); }
156f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    void setSkewY(SkScalar v) { this->set(kMSkewY, v); }
157f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    void setSkewX(SkScalar v) { this->set(kMSkewX, v); }
158f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    void setTranslateX(SkScalar v) { this->set(kMTransX, v); }
159f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    void setTranslateY(SkScalar v) { this->set(kMTransY, v); }
16033b76b59d1840fc7731985460404de45fbe26e2bbungeman@google.com    void setPerspX(SkPersp v) { this->set(kMPersp0, v); }
16133b76b59d1840fc7731985460404de45fbe26e2bbungeman@google.com    void setPerspY(SkPersp v) { this->set(kMPersp1, v); }
162f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com
163104de7640deeaf4453fed3830ea31b63c29e425ebsalomon@google.com    void setAll(SkScalar scaleX, SkScalar skewX, SkScalar transX,
164104de7640deeaf4453fed3830ea31b63c29e425ebsalomon@google.com                SkScalar skewY, SkScalar scaleY, SkScalar transY,
16533b76b59d1840fc7731985460404de45fbe26e2bbungeman@google.com                SkPersp persp0, SkPersp persp1, SkPersp persp2) {
166104de7640deeaf4453fed3830ea31b63c29e425ebsalomon@google.com        fMat[kMScaleX] = scaleX;
167104de7640deeaf4453fed3830ea31b63c29e425ebsalomon@google.com        fMat[kMSkewX]  = skewX;
168104de7640deeaf4453fed3830ea31b63c29e425ebsalomon@google.com        fMat[kMTransX] = transX;
169104de7640deeaf4453fed3830ea31b63c29e425ebsalomon@google.com        fMat[kMSkewY]  = skewY;
170104de7640deeaf4453fed3830ea31b63c29e425ebsalomon@google.com        fMat[kMScaleY] = scaleY;
171104de7640deeaf4453fed3830ea31b63c29e425ebsalomon@google.com        fMat[kMTransY] = transY;
172104de7640deeaf4453fed3830ea31b63c29e425ebsalomon@google.com        fMat[kMPersp0] = persp0;
173104de7640deeaf4453fed3830ea31b63c29e425ebsalomon@google.com        fMat[kMPersp1] = persp1;
174104de7640deeaf4453fed3830ea31b63c29e425ebsalomon@google.com        fMat[kMPersp2] = persp2;
175104de7640deeaf4453fed3830ea31b63c29e425ebsalomon@google.com        this->setTypeMask(kUnknown_Mask);
176104de7640deeaf4453fed3830ea31b63c29e425ebsalomon@google.com    }
1771fde19f3b72345b473a1a9bd64729237a388813frmistry@google.com
178f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    /** Set the matrix to identity
179f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    */
180f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    void reset();
181104de7640deeaf4453fed3830ea31b63c29e425ebsalomon@google.com    // alias for reset()
182104de7640deeaf4453fed3830ea31b63c29e425ebsalomon@google.com    void setIdentity() { this->reset(); }
183104de7640deeaf4453fed3830ea31b63c29e425ebsalomon@google.com
184f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    /** Set the matrix to translate by (dx, dy).
185f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    */
186f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    void setTranslate(SkScalar dx, SkScalar dy);
1879613767e1f1d08ce627c665e8c0098cb59b10931bsalomon@google.com    void setTranslate(const SkVector& v) { this->setTranslate(v.fX, v.fY); }
1889613767e1f1d08ce627c665e8c0098cb59b10931bsalomon@google.com
189f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    /** Set the matrix to scale by sx and sy, with a pivot point at (px, py).
190f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        The pivot point is the coordinate that should remain unchanged by the
191f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        specified transformation.
192f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    */
193f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    void setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py);
194f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    /** Set the matrix to scale by sx and sy.
195f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    */
196f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    void setScale(SkScalar sx, SkScalar sy);
19790b26fa6e1082ee8d22aac0702012e7502daecbfbsalomon@google.com    /** Set the matrix to scale by 1/divx and 1/divy. Returns false and doesn't
19890b26fa6e1082ee8d22aac0702012e7502daecbfbsalomon@google.com        touch the matrix if either divx or divy is zero.
19990b26fa6e1082ee8d22aac0702012e7502daecbfbsalomon@google.com    */
20090b26fa6e1082ee8d22aac0702012e7502daecbfbsalomon@google.com    bool setIDiv(int divx, int divy);
201f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    /** Set the matrix to rotate by the specified number of degrees, with a
202f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        pivot point at (px, py). The pivot point is the coordinate that should
203f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        remain unchanged by the specified transformation.
204f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    */
205f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    void setRotate(SkScalar degrees, SkScalar px, SkScalar py);
206f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    /** Set the matrix to rotate about (0,0) by the specified number of degrees.
207f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    */
208f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    void setRotate(SkScalar degrees);
209f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    /** Set the matrix to rotate by the specified sine and cosine values, with
210f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        a pivot point at (px, py). The pivot point is the coordinate that
211f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        should remain unchanged by the specified transformation.
212f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    */
213f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    void setSinCos(SkScalar sinValue, SkScalar cosValue,
214f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com                   SkScalar px, SkScalar py);
215f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    /** Set the matrix to rotate by the specified sine and cosine values.
216f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    */
217f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    void setSinCos(SkScalar sinValue, SkScalar cosValue);
218f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    /** Set the matrix to skew by sx and sy, with a pivot point at (px, py).
219f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        The pivot point is the coordinate that should remain unchanged by the
220f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        specified transformation.
221f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    */
222f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    void setSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py);
223f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    /** Set the matrix to skew by sx and sy.
224f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    */
225f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    void setSkew(SkScalar kx, SkScalar ky);
226f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    /** Set the matrix to the concatenation of the two specified matrices,
227f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        returning true if the the result can be represented. Either of the
228f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        two matrices may also be the target matrix. *this = a * b;
229f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    */
230f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    bool setConcat(const SkMatrix& a, const SkMatrix& b);
231f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com
232f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    /** Preconcats the matrix with the specified translation.
233f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        M' = M * T(dx, dy)
234f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    */
235f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    bool preTranslate(SkScalar dx, SkScalar dy);
236f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    /** Preconcats the matrix with the specified scale.
237f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        M' = M * S(sx, sy, px, py)
238f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    */
239f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    bool preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py);
240f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    /** Preconcats the matrix with the specified scale.
241f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        M' = M * S(sx, sy)
242f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    */
243f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    bool preScale(SkScalar sx, SkScalar sy);
244f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    /** Preconcats the matrix with the specified rotation.
245f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        M' = M * R(degrees, px, py)
246f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    */
247f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    bool preRotate(SkScalar degrees, SkScalar px, SkScalar py);
248f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    /** Preconcats the matrix with the specified rotation.
249f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        M' = M * R(degrees)
250f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    */
251f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    bool preRotate(SkScalar degrees);
252f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    /** Preconcats the matrix with the specified skew.
253f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        M' = M * K(kx, ky, px, py)
254f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    */
255f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    bool preSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py);
256f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    /** Preconcats the matrix with the specified skew.
257f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        M' = M * K(kx, ky)
258f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    */
259f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    bool preSkew(SkScalar kx, SkScalar ky);
260f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    /** Preconcats the matrix with the specified matrix.
261f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        M' = M * other
262f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    */
263f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    bool preConcat(const SkMatrix& other);
264f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com
265f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    /** Postconcats the matrix with the specified translation.
266f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        M' = T(dx, dy) * M
267f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    */
268f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    bool postTranslate(SkScalar dx, SkScalar dy);
269f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    /** Postconcats the matrix with the specified scale.
270f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        M' = S(sx, sy, px, py) * M
271f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    */
272f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    bool postScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py);
273f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    /** Postconcats the matrix with the specified scale.
274f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        M' = S(sx, sy) * M
275f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    */
276f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    bool postScale(SkScalar sx, SkScalar sy);
277f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    /** Postconcats the matrix by dividing it by the specified integers.
278f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        M' = S(1/divx, 1/divy, 0, 0) * M
279f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    */
280f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    bool postIDiv(int divx, int divy);
281f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    /** Postconcats the matrix with the specified rotation.
282f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        M' = R(degrees, px, py) * M
283f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    */
284f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    bool postRotate(SkScalar degrees, SkScalar px, SkScalar py);
285f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    /** Postconcats the matrix with the specified rotation.
286f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        M' = R(degrees) * M
287f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    */
288f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    bool postRotate(SkScalar degrees);
289f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    /** Postconcats the matrix with the specified skew.
290f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        M' = K(kx, ky, px, py) * M
291f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    */
292f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    bool postSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py);
293f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    /** Postconcats the matrix with the specified skew.
294f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        M' = K(kx, ky) * M
295f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    */
296f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    bool postSkew(SkScalar kx, SkScalar ky);
297f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    /** Postconcats the matrix with the specified matrix.
298f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        M' = other * M
299f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    */
300f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    bool postConcat(const SkMatrix& other);
301f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com
302f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    enum ScaleToFit {
303f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        /**
304f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com         * Scale in X and Y independently, so that src matches dst exactly.
305f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com         * This may change the aspect ratio of the src.
306f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com         */
307f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        kFill_ScaleToFit,
308f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        /**
309f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com         * Compute a scale that will maintain the original src aspect ratio,
310f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com         * but will also ensure that src fits entirely inside dst. At least one
311f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com         * axis (X or Y) will fit exactly. kStart aligns the result to the
312f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com         * left and top edges of dst.
313f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com         */
314f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        kStart_ScaleToFit,
315f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        /**
316f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com         * Compute a scale that will maintain the original src aspect ratio,
317f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com         * but will also ensure that src fits entirely inside dst. At least one
318f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com         * axis (X or Y) will fit exactly. The result is centered inside dst.
319f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com         */
320f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        kCenter_ScaleToFit,
321f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        /**
322f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com         * Compute a scale that will maintain the original src aspect ratio,
323f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com         * but will also ensure that src fits entirely inside dst. At least one
324f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com         * axis (X or Y) will fit exactly. kEnd aligns the result to the
325f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com         * right and bottom edges of dst.
326f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com         */
327f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        kEnd_ScaleToFit
328f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    };
329f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com
330f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    /** Set the matrix to the scale and translate values that map the source
331f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        rectangle to the destination rectangle, returning true if the the result
332f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        can be represented.
333f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        @param src the source rectangle to map from.
334f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        @param dst the destination rectangle to map to.
335f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        @param stf the ScaleToFit option
336f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        @return true if the matrix can be represented by the rectangle mapping.
337f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    */
338f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    bool setRectToRect(const SkRect& src, const SkRect& dst, ScaleToFit stf);
3391fde19f3b72345b473a1a9bd64729237a388813frmistry@google.com
340f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    /** Set the matrix such that the specified src points would map to the
341f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        specified dst points. count must be within [0..4].
342f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        @param src  The array of src points
343f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        @param dst  The array of dst points
344f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        @param count The number of points to use for the transformation
345f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        @return true if the matrix was set to the specified transformation
346f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    */
347f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    bool setPolyToPoly(const SkPoint src[], const SkPoint dst[], int count);
348f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com
349f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    /** If this matrix can be inverted, return true and if inverse is not null,
350f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        set inverse to be the inverse of this matrix. If this matrix cannot be
351f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        inverted, ignore inverse and return false
352f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    */
353f60feb19198cf47e7497f62af197538d018fdf3dbsalomon@google.com    bool SK_WARN_UNUSED_RESULT invert(SkMatrix* inverse) const {
354f60feb19198cf47e7497f62af197538d018fdf3dbsalomon@google.com        // Allow the trivial case to be inlined.
355f60feb19198cf47e7497f62af197538d018fdf3dbsalomon@google.com        if (this->isIdentity()) {
356f60feb19198cf47e7497f62af197538d018fdf3dbsalomon@google.com            if (NULL != inverse) {
357f60feb19198cf47e7497f62af197538d018fdf3dbsalomon@google.com                inverse->reset();
358f60feb19198cf47e7497f62af197538d018fdf3dbsalomon@google.com            }
359f60feb19198cf47e7497f62af197538d018fdf3dbsalomon@google.com            return true;
360f60feb19198cf47e7497f62af197538d018fdf3dbsalomon@google.com        }
361f60feb19198cf47e7497f62af197538d018fdf3dbsalomon@google.com        return this->invertNonIdentity(inverse);
362f60feb19198cf47e7497f62af197538d018fdf3dbsalomon@google.com    }
363f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com
364f5fdad15a20383dafce6acb4024261be76b90988bungeman@google.com    /** Fills the passed array with affine identity values
365f5fdad15a20383dafce6acb4024261be76b90988bungeman@google.com        in column major order.
366f5fdad15a20383dafce6acb4024261be76b90988bungeman@google.com        @param affine  The array to fill with affine identity values.
367f5fdad15a20383dafce6acb4024261be76b90988bungeman@google.com        Must not be NULL.
368f5fdad15a20383dafce6acb4024261be76b90988bungeman@google.com    */
369f5fdad15a20383dafce6acb4024261be76b90988bungeman@google.com    static void SetAffineIdentity(SkScalar affine[6]);
370f5fdad15a20383dafce6acb4024261be76b90988bungeman@google.com
371f5fdad15a20383dafce6acb4024261be76b90988bungeman@google.com    /** Fills the passed array with the affine values in column major order.
372f5fdad15a20383dafce6acb4024261be76b90988bungeman@google.com        If the matrix is a perspective transform, returns false
373f5fdad15a20383dafce6acb4024261be76b90988bungeman@google.com        and does not change the passed array.
374f5fdad15a20383dafce6acb4024261be76b90988bungeman@google.com        @param affine  The array to fill with affine values. Ignored if NULL.
375b5c881444329c8c4b6bfda0d8babd33b6927a9advandebo@chromium.org    */
376f5fdad15a20383dafce6acb4024261be76b90988bungeman@google.com    bool asAffine(SkScalar affine[6]) const;
377b5c881444329c8c4b6bfda0d8babd33b6927a9advandebo@chromium.org
378f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    /** Apply this matrix to the array of points specified by src, and write
379f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        the transformed points into the array of points specified by dst.
380f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        dst[] = M * src[]
381f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        @param dst  Where the transformed coordinates are written. It must
382f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com                    contain at least count entries
383f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        @param src  The original coordinates that are to be transformed. It
384f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com                    must contain at least count entries
385f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        @param count The number of points in src to read, and then transform
386f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com                     into dst.
387f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    */
388f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    void mapPoints(SkPoint dst[], const SkPoint src[], int count) const;
389f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com
390f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    /** Apply this matrix to the array of points, overwriting it with the
391f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        transformed values.
392f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        dst[] = M * pts[]
393f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        @param pts  The points to be transformed. It must contain at least
394f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com                    count entries
395f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        @param count The number of points in pts.
396f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    */
397f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    void mapPoints(SkPoint pts[], int count) const {
398f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        this->mapPoints(pts, pts, count);
399f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    }
4001fde19f3b72345b473a1a9bd64729237a388813frmistry@google.com
401a244157250c91c9cb57a3e6ca7b64e0d35daebcbbsalomon@google.com    /** Like mapPoints but with custom byte stride between the points. Stride
402a244157250c91c9cb57a3e6ca7b64e0d35daebcbbsalomon@google.com     *  should be a multiple of sizeof(SkScalar).
403a244157250c91c9cb57a3e6ca7b64e0d35daebcbbsalomon@google.com     */
404a244157250c91c9cb57a3e6ca7b64e0d35daebcbbsalomon@google.com    void mapPointsWithStride(SkPoint pts[], size_t stride, int count) const {
405a244157250c91c9cb57a3e6ca7b64e0d35daebcbbsalomon@google.com        SkASSERT(stride >= sizeof(SkPoint));
406a244157250c91c9cb57a3e6ca7b64e0d35daebcbbsalomon@google.com        SkASSERT(0 == stride % sizeof(SkScalar));
407a244157250c91c9cb57a3e6ca7b64e0d35daebcbbsalomon@google.com        for (int i = 0; i < count; ++i) {
408a244157250c91c9cb57a3e6ca7b64e0d35daebcbbsalomon@google.com            this->mapPoints(pts, pts, 1);
409a244157250c91c9cb57a3e6ca7b64e0d35daebcbbsalomon@google.com            pts = (SkPoint*)((intptr_t)pts + stride);
410a244157250c91c9cb57a3e6ca7b64e0d35daebcbbsalomon@google.com        }
411a244157250c91c9cb57a3e6ca7b64e0d35daebcbbsalomon@google.com    }
412a244157250c91c9cb57a3e6ca7b64e0d35daebcbbsalomon@google.com
413a244157250c91c9cb57a3e6ca7b64e0d35daebcbbsalomon@google.com    /** Like mapPoints but with custom byte stride between the points.
414a244157250c91c9cb57a3e6ca7b64e0d35daebcbbsalomon@google.com    */
415a244157250c91c9cb57a3e6ca7b64e0d35daebcbbsalomon@google.com    void mapPointsWithStride(SkPoint dst[], SkPoint src[],
416a244157250c91c9cb57a3e6ca7b64e0d35daebcbbsalomon@google.com                             size_t stride, int count) const {
417a244157250c91c9cb57a3e6ca7b64e0d35daebcbbsalomon@google.com        SkASSERT(stride >= sizeof(SkPoint));
418a244157250c91c9cb57a3e6ca7b64e0d35daebcbbsalomon@google.com        SkASSERT(0 == stride % sizeof(SkScalar));
419a244157250c91c9cb57a3e6ca7b64e0d35daebcbbsalomon@google.com        for (int i = 0; i < count; ++i) {
420a244157250c91c9cb57a3e6ca7b64e0d35daebcbbsalomon@google.com            this->mapPoints(dst, src, 1);
421a244157250c91c9cb57a3e6ca7b64e0d35daebcbbsalomon@google.com            src = (SkPoint*)((intptr_t)src + stride);
422a244157250c91c9cb57a3e6ca7b64e0d35daebcbbsalomon@google.com            dst = (SkPoint*)((intptr_t)dst + stride);
423a244157250c91c9cb57a3e6ca7b64e0d35daebcbbsalomon@google.com        }
424a244157250c91c9cb57a3e6ca7b64e0d35daebcbbsalomon@google.com    }
425a244157250c91c9cb57a3e6ca7b64e0d35daebcbbsalomon@google.com
4267d3f2c3e843e51740e5d8551f2673997c849fb20egdaniel@google.com    /** Apply this matrix to the array of homogeneous points, specified by src,
4277d3f2c3e843e51740e5d8551f2673997c849fb20egdaniel@google.com        where a homogeneous point is defined by 3 contiguous scalar values,
4287d3f2c3e843e51740e5d8551f2673997c849fb20egdaniel@google.com        and write the transformed points into the array of scalars specified by dst.
4297d3f2c3e843e51740e5d8551f2673997c849fb20egdaniel@google.com        dst[] = M * src[]
4307d3f2c3e843e51740e5d8551f2673997c849fb20egdaniel@google.com        @param dst  Where the transformed coordinates are written. It must
4317d3f2c3e843e51740e5d8551f2673997c849fb20egdaniel@google.com                    contain at least 3 * count entries
4327d3f2c3e843e51740e5d8551f2673997c849fb20egdaniel@google.com        @param src  The original coordinates that are to be transformed. It
4337d3f2c3e843e51740e5d8551f2673997c849fb20egdaniel@google.com                    must contain at least 3 * count entries
4347d3f2c3e843e51740e5d8551f2673997c849fb20egdaniel@google.com        @param count The number of triples (homogeneous points) in src to read,
4357d3f2c3e843e51740e5d8551f2673997c849fb20egdaniel@google.com                     and then transform into dst.
4367d3f2c3e843e51740e5d8551f2673997c849fb20egdaniel@google.com    */
4377d3f2c3e843e51740e5d8551f2673997c849fb20egdaniel@google.com    void mapHomogeneousPoints(SkScalar dst[], const SkScalar src[], int count) const;
4387d3f2c3e843e51740e5d8551f2673997c849fb20egdaniel@google.com
439f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    void mapXY(SkScalar x, SkScalar y, SkPoint* result) const {
440f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        SkASSERT(result);
441f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        this->getMapXYProc()(*this, x, y, result);
442f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    }
443f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com
444f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    /** Apply this matrix to the array of vectors specified by src, and write
445f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        the transformed vectors into the array of vectors specified by dst.
446f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        This is similar to mapPoints, but ignores any translation in the matrix.
447f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        @param dst  Where the transformed coordinates are written. It must
448f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com                    contain at least count entries
449f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        @param src  The original coordinates that are to be transformed. It
450f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com                    must contain at least count entries
451f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        @param count The number of vectors in src to read, and then transform
452f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com                     into dst.
453f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    */
454f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    void mapVectors(SkVector dst[], const SkVector src[], int count) const;
455f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com
456f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    /** Apply this matrix to the array of vectors specified by src, and write
457f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        the transformed vectors into the array of vectors specified by dst.
458f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        This is similar to mapPoints, but ignores any translation in the matrix.
459f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        @param vecs The vectors to be transformed. It must contain at least
460f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com                    count entries
461f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        @param count The number of vectors in vecs.
462f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    */
463f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    void mapVectors(SkVector vecs[], int count) const {
464f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        this->mapVectors(vecs, vecs, count);
465f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    }
466f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com
467f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    /** Apply this matrix to the src rectangle, and write the transformed
468f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        rectangle into dst. This is accomplished by transforming the 4 corners
469f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        of src, and then setting dst to the bounds of those points.
470f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        @param dst  Where the transformed rectangle is written.
471f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        @param src  The original rectangle to be transformed.
472f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        @return the result of calling rectStaysRect()
473f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    */
474f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    bool mapRect(SkRect* dst, const SkRect& src) const;
475f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com
476f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    /** Apply this matrix to the rectangle, and write the transformed rectangle
477f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        back into it. This is accomplished by transforming the 4 corners of
478f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        rect, and then setting it to the bounds of those points
479f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        @param rect The rectangle to transform.
480f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        @return the result of calling rectStaysRect()
481f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    */
482f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    bool mapRect(SkRect* rect) const {
483f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        return this->mapRect(rect, *rect);
484f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    }
485f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com
4863069ef5a55b98779152b939822dd609849273fb6commit-bot@chromium.org    /** Apply this matrix to the src rectangle, and write the four transformed
4873069ef5a55b98779152b939822dd609849273fb6commit-bot@chromium.org        points into dst. The points written to dst will be the original top-left, top-right,
4883069ef5a55b98779152b939822dd609849273fb6commit-bot@chromium.org        bottom-right, and bottom-left points transformed by the matrix.
4893069ef5a55b98779152b939822dd609849273fb6commit-bot@chromium.org        @param dst  Where the transformed quad is written.
4903069ef5a55b98779152b939822dd609849273fb6commit-bot@chromium.org        @param rect The original rectangle to be transformed.
4913069ef5a55b98779152b939822dd609849273fb6commit-bot@chromium.org    */
4923069ef5a55b98779152b939822dd609849273fb6commit-bot@chromium.org    void mapRectToQuad(SkPoint dst[4], const SkRect& rect) const {
4933069ef5a55b98779152b939822dd609849273fb6commit-bot@chromium.org        // This could potentially be faster if we only transformed each x and y of the rect once.
4943069ef5a55b98779152b939822dd609849273fb6commit-bot@chromium.org        rect.toQuad(dst);
4953069ef5a55b98779152b939822dd609849273fb6commit-bot@chromium.org        this->mapPoints(dst, 4);
4963069ef5a55b98779152b939822dd609849273fb6commit-bot@chromium.org    }
4973069ef5a55b98779152b939822dd609849273fb6commit-bot@chromium.org
498f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    /** Return the mean radius of a circle after it has been mapped by
499f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        this matrix. NOTE: in perspective this value assumes the circle
500f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        has its center at the origin.
501f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    */
502f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    SkScalar mapRadius(SkScalar radius) const;
503f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com
504f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    typedef void (*MapXYProc)(const SkMatrix& mat, SkScalar x, SkScalar y,
505f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com                                 SkPoint* result);
506f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com
507f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    static MapXYProc GetMapXYProc(TypeMask mask) {
508f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        SkASSERT((mask & ~kAllMasks) == 0);
509f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        return gMapXYProcs[mask & kAllMasks];
510f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    }
5111fde19f3b72345b473a1a9bd64729237a388813frmistry@google.com
512f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    MapXYProc getMapXYProc() const {
513f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        return GetMapXYProc(this->getType());
514f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    }
515f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com
516f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    typedef void (*MapPtsProc)(const SkMatrix& mat, SkPoint dst[],
517f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com                                  const SkPoint src[], int count);
518f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com
519f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    static MapPtsProc GetMapPtsProc(TypeMask mask) {
520f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        SkASSERT((mask & ~kAllMasks) == 0);
521f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        return gMapPtsProcs[mask & kAllMasks];
522f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    }
5231fde19f3b72345b473a1a9bd64729237a388813frmistry@google.com
524f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    MapPtsProc getMapPtsProc() const {
525f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        return GetMapPtsProc(this->getType());
526f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    }
527f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com
528f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    /** If the matrix can be stepped in X (not complex perspective)
529f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        then return true and if step[XY] is not null, return the step[XY] value.
530f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        If it cannot, return false and ignore step.
531f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    */
532f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    bool fixedStepInX(SkScalar y, SkFixed* stepX, SkFixed* stepY) const;
533f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com
5341b0d6300fe68e2a9cae4fbc3b5b6ad47aaab2f0ebsalomon@google.com    /** Efficient comparison of two matrices. It distinguishes between zero and
5351b0d6300fe68e2a9cae4fbc3b5b6ad47aaab2f0ebsalomon@google.com     *  negative zero. It will return false when the sign of zero values is the
5361b0d6300fe68e2a9cae4fbc3b5b6ad47aaab2f0ebsalomon@google.com     *  only difference between the two matrices. It considers NaN values to be
5371b0d6300fe68e2a9cae4fbc3b5b6ad47aaab2f0ebsalomon@google.com     *  equal to themselves. So a matrix full of NaNs is "cheap equal" to
5381b0d6300fe68e2a9cae4fbc3b5b6ad47aaab2f0ebsalomon@google.com     *  another matrix full of NaNs iff the NaN values are bitwise identical
5391b0d6300fe68e2a9cae4fbc3b5b6ad47aaab2f0ebsalomon@google.com     *  while according to strict the strict == test a matrix with a NaN value
5401b0d6300fe68e2a9cae4fbc3b5b6ad47aaab2f0ebsalomon@google.com     *  is equal to nothing, including itself.
5411b0d6300fe68e2a9cae4fbc3b5b6ad47aaab2f0ebsalomon@google.com     */
5421b0d6300fe68e2a9cae4fbc3b5b6ad47aaab2f0ebsalomon@google.com    bool cheapEqualTo(const SkMatrix& m) const {
5431b0d6300fe68e2a9cae4fbc3b5b6ad47aaab2f0ebsalomon@google.com        return 0 == memcmp(fMat, m.fMat, sizeof(fMat));
544f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    }
545f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com
5461b0d6300fe68e2a9cae4fbc3b5b6ad47aaab2f0ebsalomon@google.com#ifdef SK_SCALAR_IS_FIXED
5471b0d6300fe68e2a9cae4fbc3b5b6ad47aaab2f0ebsalomon@google.com    friend bool operator==(const SkMatrix& a, const SkMatrix& b) {
548afcde3a5a6d66f0f269f0a537ffd9f5684aa2bcabsalomon@google.com        return a.cheapEqualTo(b);
549f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    }
550d5ef4a9f01459c372b8841816a9b1662ea51fef6reed@google.com#else
5511b0d6300fe68e2a9cae4fbc3b5b6ad47aaab2f0ebsalomon@google.com    friend bool operator==(const SkMatrix& a, const SkMatrix& b);
5521b0d6300fe68e2a9cae4fbc3b5b6ad47aaab2f0ebsalomon@google.com#endif
553d5ef4a9f01459c372b8841816a9b1662ea51fef6reed@google.com    friend bool operator!=(const SkMatrix& a, const SkMatrix& b) {
554d5ef4a9f01459c372b8841816a9b1662ea51fef6reed@google.com        return !(a == b);
555d5ef4a9f01459c372b8841816a9b1662ea51fef6reed@google.com    }
5568bd93bf4de826b5a2343e5b88338d4d636c98bb2reed@android.com
557e48af74e37973fb2b70d00fa74bd774c2662f353reed@android.com    enum {
558e8a47507732bffb3ee045727ea9477a067f224d7djsollen@google.com        // writeTo/readFromMemory will never return a value larger than this
559e48af74e37973fb2b70d00fa74bd774c2662f353reed@android.com        kMaxFlattenSize = 9 * sizeof(SkScalar) + sizeof(uint32_t)
560e48af74e37973fb2b70d00fa74bd774c2662f353reed@android.com    };
5618bd93bf4de826b5a2343e5b88338d4d636c98bb2reed@android.com    // return the number of bytes written, whether or not buffer is null
5623a7d93ce0ea5bbd43a8c998681bebfe3615b3480commit-bot@chromium.org    size_t writeToMemory(void* buffer) const;
5633a7d93ce0ea5bbd43a8c998681bebfe3615b3480commit-bot@chromium.org    /**
5643a7d93ce0ea5bbd43a8c998681bebfe3615b3480commit-bot@chromium.org     * Reads data from the buffer parameter
5653a7d93ce0ea5bbd43a8c998681bebfe3615b3480commit-bot@chromium.org     *
5663a7d93ce0ea5bbd43a8c998681bebfe3615b3480commit-bot@chromium.org     * @param buffer Memory to read from
5673a7d93ce0ea5bbd43a8c998681bebfe3615b3480commit-bot@chromium.org     * @param length Amount of memory available in the buffer
5683a7d93ce0ea5bbd43a8c998681bebfe3615b3480commit-bot@chromium.org     * @return number of bytes read (must be a multiple of 4) or
5693a7d93ce0ea5bbd43a8c998681bebfe3615b3480commit-bot@chromium.org     *         0 if there was not enough memory available
5703a7d93ce0ea5bbd43a8c998681bebfe3615b3480commit-bot@chromium.org     */
5713a7d93ce0ea5bbd43a8c998681bebfe3615b3480commit-bot@chromium.org    size_t readFromMemory(const void* buffer, size_t length);
5721fde19f3b72345b473a1a9bd64729237a388813frmistry@google.com
5736b10a0e65b4e9b82605b6236a2cec9e7c2404898robertphillips@google.com    SkDEVCODE(void dump() const;)
5746b10a0e65b4e9b82605b6236a2cec9e7c2404898robertphillips@google.com    SkDEVCODE(void toString(SkString*) const;)
575f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com
576104de7640deeaf4453fed3830ea31b63c29e425ebsalomon@google.com    /**
577b4ca22eb0c93165edae74ae2544ffc56b98eb0dfcommit-bot@chromium.org     * Calculates the minimum stretching factor of the matrix. If the matrix has
578b4ca22eb0c93165edae74ae2544ffc56b98eb0dfcommit-bot@chromium.org     * perspective -1 is returned.
579b4ca22eb0c93165edae74ae2544ffc56b98eb0dfcommit-bot@chromium.org     *
580b4ca22eb0c93165edae74ae2544ffc56b98eb0dfcommit-bot@chromium.org     * @return minumum strecthing factor
581b4ca22eb0c93165edae74ae2544ffc56b98eb0dfcommit-bot@chromium.org     */
582b4ca22eb0c93165edae74ae2544ffc56b98eb0dfcommit-bot@chromium.org    SkScalar getMinStretch() const;
583b4ca22eb0c93165edae74ae2544ffc56b98eb0dfcommit-bot@chromium.org
584b4ca22eb0c93165edae74ae2544ffc56b98eb0dfcommit-bot@chromium.org    /**
585da882f21588ddc33be0617b8c1afe8cac04b6237bsalomon@google.com     * Calculates the maximum stretching factor of the matrix. If the matrix has
586862b2f7eef0eac4925188aa0f98d1f15124c41b8bsalomon@google.com     * perspective -1 is returned.
587104de7640deeaf4453fed3830ea31b63c29e425ebsalomon@google.com     *
588862b2f7eef0eac4925188aa0f98d1f15124c41b8bsalomon@google.com     * @return maximum strecthing factor
589104de7640deeaf4453fed3830ea31b63c29e425ebsalomon@google.com     */
590104de7640deeaf4453fed3830ea31b63c29e425ebsalomon@google.com    SkScalar getMaxStretch() const;
591104de7640deeaf4453fed3830ea31b63c29e425ebsalomon@google.com
592104de7640deeaf4453fed3830ea31b63c29e425ebsalomon@google.com    /**
593104de7640deeaf4453fed3830ea31b63c29e425ebsalomon@google.com     *  Return a reference to a const identity matrix
594104de7640deeaf4453fed3830ea31b63c29e425ebsalomon@google.com     */
595104de7640deeaf4453fed3830ea31b63c29e425ebsalomon@google.com    static const SkMatrix& I();
596104de7640deeaf4453fed3830ea31b63c29e425ebsalomon@google.com
597104de7640deeaf4453fed3830ea31b63c29e425ebsalomon@google.com    /**
598104de7640deeaf4453fed3830ea31b63c29e425ebsalomon@google.com     *  Return a reference to a const matrix that is "invalid", one that could
599104de7640deeaf4453fed3830ea31b63c29e425ebsalomon@google.com     *  never be used.
600104de7640deeaf4453fed3830ea31b63c29e425ebsalomon@google.com     */
601104de7640deeaf4453fed3830ea31b63c29e425ebsalomon@google.com    static const SkMatrix& InvalidMatrix();
602104de7640deeaf4453fed3830ea31b63c29e425ebsalomon@google.com
603b2f432c2cffc82221b2138db05b1663a27fce69dtomhudson@google.com    /**
604b2f432c2cffc82221b2138db05b1663a27fce69dtomhudson@google.com     * Testing routine; the matrix's type cache should never need to be
605b2f432c2cffc82221b2138db05b1663a27fce69dtomhudson@google.com     * manually invalidated during normal use.
606b2f432c2cffc82221b2138db05b1663a27fce69dtomhudson@google.com     */
607b2f432c2cffc82221b2138db05b1663a27fce69dtomhudson@google.com    void dirtyMatrixTypeCache() {
608b2f432c2cffc82221b2138db05b1663a27fce69dtomhudson@google.com        this->setTypeMask(kUnknown_Mask);
609b2f432c2cffc82221b2138db05b1663a27fce69dtomhudson@google.com    }
610b2f432c2cffc82221b2138db05b1663a27fce69dtomhudson@google.com
611f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.comprivate:
612f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    enum {
613f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        /** Set if the matrix will map a rectangle to another rectangle. This
614f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com            can be true if the matrix is scale-only, or rotates a multiple of
6154f4d33c778d64e8b641d5374d00051c6b7946bcbbsalomon@google.com            90 degrees.
6161fde19f3b72345b473a1a9bd64729237a388813frmistry@google.com
617f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com            This bit will be set on identity matrices
618f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        */
619f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        kRectStaysRect_Mask = 0x10,
620f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com
621b4ca308fe54ba1285a5be3869e595908fbd76e7dtomhudson@google.com        /** Set if the perspective bit is valid even though the rest of
622b4ca308fe54ba1285a5be3869e595908fbd76e7dtomhudson@google.com            the matrix is Unknown.
623b4ca308fe54ba1285a5be3869e595908fbd76e7dtomhudson@google.com        */
624b4ca308fe54ba1285a5be3869e595908fbd76e7dtomhudson@google.com        kOnlyPerspectiveValid_Mask = 0x40,
625b4ca308fe54ba1285a5be3869e595908fbd76e7dtomhudson@google.com
626f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        kUnknown_Mask = 0x80,
627d5ef4a9f01459c372b8841816a9b1662ea51fef6reed@google.com
628d5ef4a9f01459c372b8841816a9b1662ea51fef6reed@google.com        kORableMasks =  kTranslate_Mask |
629d5ef4a9f01459c372b8841816a9b1662ea51fef6reed@google.com                        kScale_Mask |
630d5ef4a9f01459c372b8841816a9b1662ea51fef6reed@google.com                        kAffine_Mask |
631d5ef4a9f01459c372b8841816a9b1662ea51fef6reed@google.com                        kPerspective_Mask,
632d5ef4a9f01459c372b8841816a9b1662ea51fef6reed@google.com
633f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        kAllMasks = kTranslate_Mask |
634f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com                    kScale_Mask |
635f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com                    kAffine_Mask |
636f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com                    kPerspective_Mask |
637f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com                    kRectStaysRect_Mask
638f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    };
639f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com
640f12f2b4331d3c04cedd94a430a09bdcd266ffe98tomhudson@google.com    SkScalar         fMat[9];
641f12f2b4331d3c04cedd94a430a09bdcd266ffe98tomhudson@google.com    mutable uint32_t fTypeMask;
642f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com
643f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    uint8_t computeTypeMask() const;
644b4ca308fe54ba1285a5be3869e595908fbd76e7dtomhudson@google.com    uint8_t computePerspectiveTypeMask() const;
645f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com
646f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    void setTypeMask(int mask) {
647f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        // allow kUnknown or a valid mask
648b4ca308fe54ba1285a5be3869e595908fbd76e7dtomhudson@google.com        SkASSERT(kUnknown_Mask == mask || (mask & kAllMasks) == mask ||
649478c604fea898131572621fc3825b56481adfd96junov@chromium.org                 ((kUnknown_Mask | kOnlyPerspectiveValid_Mask) & mask)
650478c604fea898131572621fc3825b56481adfd96junov@chromium.org                 == (kUnknown_Mask | kOnlyPerspectiveValid_Mask));
651f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        fTypeMask = SkToU8(mask);
652f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    }
653d5ef4a9f01459c372b8841816a9b1662ea51fef6reed@google.com
654d5ef4a9f01459c372b8841816a9b1662ea51fef6reed@google.com    void orTypeMask(int mask) {
655d5ef4a9f01459c372b8841816a9b1662ea51fef6reed@google.com        SkASSERT((mask & kORableMasks) == mask);
656d5ef4a9f01459c372b8841816a9b1662ea51fef6reed@google.com        fTypeMask = SkToU8(fTypeMask | mask);
657d5ef4a9f01459c372b8841816a9b1662ea51fef6reed@google.com    }
658d5ef4a9f01459c372b8841816a9b1662ea51fef6reed@google.com
659f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    void clearTypeMask(int mask) {
660f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        // only allow a valid mask
661f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        SkASSERT((mask & kAllMasks) == mask);
662f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com        fTypeMask &= ~mask;
663f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    }
664b4ca308fe54ba1285a5be3869e595908fbd76e7dtomhudson@google.com
665b4ca308fe54ba1285a5be3869e595908fbd76e7dtomhudson@google.com    TypeMask getPerspectiveTypeMaskOnly() const {
666b4ca308fe54ba1285a5be3869e595908fbd76e7dtomhudson@google.com        if ((fTypeMask & kUnknown_Mask) &&
667b4ca308fe54ba1285a5be3869e595908fbd76e7dtomhudson@google.com            !(fTypeMask & kOnlyPerspectiveValid_Mask)) {
668b4ca308fe54ba1285a5be3869e595908fbd76e7dtomhudson@google.com            fTypeMask = this->computePerspectiveTypeMask();
669b4ca308fe54ba1285a5be3869e595908fbd76e7dtomhudson@google.com        }
670b4ca308fe54ba1285a5be3869e595908fbd76e7dtomhudson@google.com        return (TypeMask)(fTypeMask & 0xF);
671b4ca308fe54ba1285a5be3869e595908fbd76e7dtomhudson@google.com    }
672b4ca308fe54ba1285a5be3869e595908fbd76e7dtomhudson@google.com
673b4ca308fe54ba1285a5be3869e595908fbd76e7dtomhudson@google.com    /** Returns true if we already know that the matrix is identity;
674b4ca308fe54ba1285a5be3869e595908fbd76e7dtomhudson@google.com        false otherwise.
675b4ca308fe54ba1285a5be3869e595908fbd76e7dtomhudson@google.com    */
676b4ca308fe54ba1285a5be3869e595908fbd76e7dtomhudson@google.com    bool isTriviallyIdentity() const {
677b4ca308fe54ba1285a5be3869e595908fbd76e7dtomhudson@google.com        if (fTypeMask & kUnknown_Mask) {
678b4ca308fe54ba1285a5be3869e595908fbd76e7dtomhudson@google.com            return false;
679b4ca308fe54ba1285a5be3869e595908fbd76e7dtomhudson@google.com        }
680b4ca308fe54ba1285a5be3869e595908fbd76e7dtomhudson@google.com        return ((fTypeMask & 0xF) == 0);
681b4ca308fe54ba1285a5be3869e595908fbd76e7dtomhudson@google.com    }
6821fde19f3b72345b473a1a9bd64729237a388813frmistry@google.com
683f60feb19198cf47e7497f62af197538d018fdf3dbsalomon@google.com    bool SK_WARN_UNUSED_RESULT invertNonIdentity(SkMatrix* inverse) const;
684f60feb19198cf47e7497f62af197538d018fdf3dbsalomon@google.com
685f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    static bool Poly2Proc(const SkPoint[], SkMatrix*, const SkPoint& scale);
686f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    static bool Poly3Proc(const SkPoint[], SkMatrix*, const SkPoint& scale);
687f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    static bool Poly4Proc(const SkPoint[], SkMatrix*, const SkPoint& scale);
688f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com
689f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    static void Identity_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
690f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    static void Trans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
691f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    static void Scale_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
692f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    static void ScaleTrans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
693f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    static void Rot_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
694f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    static void RotTrans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
695f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    static void Persp_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
6961fde19f3b72345b473a1a9bd64729237a388813frmistry@google.com
697f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    static const MapXYProc gMapXYProcs[];
6981fde19f3b72345b473a1a9bd64729237a388813frmistry@google.com
699f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    static void Identity_pts(const SkMatrix&, SkPoint[], const SkPoint[], int);
700f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    static void Trans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int);
701f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    static void Scale_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int);
702f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    static void ScaleTrans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[],
703f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com                               int count);
704f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    static void Rot_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int);
705f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    static void RotTrans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[],
706f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com                             int count);
707f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    static void Persp_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int);
7081fde19f3b72345b473a1a9bd64729237a388813frmistry@google.com
709f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    static const MapPtsProc gMapPtsProcs[];
710f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com
711f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com    friend class SkPerspIter;
712f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com};
713f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com
714f0d6bf5df07d5ce620678074da0c05aacc28e44reed@android.com#endif
715