Home | History | Annotate | Download | only in core
      1 
      2 /*
      3  * Copyright 2006 The Android Open Source Project
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 
      9 
     10 #ifndef SkMatrix_DEFINED
     11 #define SkMatrix_DEFINED
     12 
     13 #include "SkRect.h"
     14 
     15 class SkString;
     16 
     17 #ifdef SK_SCALAR_IS_FLOAT
     18     typedef SkScalar SkPersp;
     19     #define SkScalarToPersp(x) (x)
     20     #define SkPerspToScalar(x) (x)
     21 #else
     22     typedef SkFract SkPersp;
     23     #define SkScalarToPersp(x) SkFixedToFract(x)
     24     #define SkPerspToScalar(x) SkFractToFixed(x)
     25 #endif
     26 
     27 /** \class SkMatrix
     28 
     29     The SkMatrix class holds a 3x3 matrix for transforming coordinates.
     30     SkMatrix does not have a constructor, so it must be explicitly initialized
     31     using either reset() - to construct an identity matrix, or one of the set
     32     functions (e.g. setTranslate, setRotate, etc.).
     33 */
     34 class SK_API SkMatrix {
     35 public:
     36     /** Enum of bit fields for the mask return by getType().
     37         Use this to identify the complexity of the matrix.
     38     */
     39     enum TypeMask {
     40         kIdentity_Mask      = 0,
     41         kTranslate_Mask     = 0x01,  //!< set if the matrix has translation
     42         kScale_Mask         = 0x02,  //!< set if the matrix has X or Y scale
     43         kAffine_Mask        = 0x04,  //!< set if the matrix skews or rotates
     44         kPerspective_Mask   = 0x08   //!< set if the matrix is in perspective
     45     };
     46 
     47     /** Returns a bitfield describing the transformations the matrix may
     48         perform. The bitfield is computed conservatively, so it may include
     49         false positives. For example, when kPerspective_Mask is true, all
     50         other bits may be set to true even in the case of a pure perspective
     51         transform.
     52    */
     53     TypeMask getType() const {
     54         if (fTypeMask & kUnknown_Mask) {
     55             fTypeMask = this->computeTypeMask();
     56         }
     57         // only return the public masks
     58         return (TypeMask)(fTypeMask & 0xF);
     59     }
     60 
     61     /** Returns true if the matrix is identity.
     62     */
     63     bool isIdentity() const {
     64         return this->getType() == 0;
     65     }
     66 
     67     /** Returns true if will map a rectangle to another rectangle. This can be
     68         true if the matrix is identity, scale-only, or rotates a multiple of
     69         90 degrees.
     70     */
     71     bool rectStaysRect() const {
     72         if (fTypeMask & kUnknown_Mask) {
     73             fTypeMask = this->computeTypeMask();
     74         }
     75         return (fTypeMask & kRectStaysRect_Mask) != 0;
     76     }
     77     // alias for rectStaysRect()
     78     bool preservesAxisAlignment() const { return this->rectStaysRect(); }
     79 
     80     /**
     81      *  Returns true if the matrix contains perspective elements.
     82      */
     83     bool hasPerspective() const {
     84         return SkToBool(this->getPerspectiveTypeMaskOnly() &
     85                         kPerspective_Mask);
     86     }
     87 
     88     /** Returns true if the matrix contains only translation, rotation or uniform scale
     89         Returns false if other transformation types are included or is degenerate
     90      */
     91     bool isSimilarity(SkScalar tol = SK_ScalarNearlyZero) const;
     92 
     93     /** Returns true if the matrix contains only translation, rotation or scale
     94         (non-uniform scale is allowed).
     95         Returns false if other transformation types are included or is degenerate
     96      */
     97     bool preservesRightAngles(SkScalar tol = SK_ScalarNearlyZero) const;
     98 
     99     enum {
    100         kMScaleX,
    101         kMSkewX,
    102         kMTransX,
    103         kMSkewY,
    104         kMScaleY,
    105         kMTransY,
    106         kMPersp0,
    107         kMPersp1,
    108         kMPersp2
    109     };
    110 
    111     /** Affine arrays are in column major order
    112         because that's how PDF and XPS like it.
    113      */
    114     enum {
    115         kAScaleX,
    116         kASkewY,
    117         kASkewX,
    118         kAScaleY,
    119         kATransX,
    120         kATransY
    121     };
    122 
    123     SkScalar operator[](int index) const {
    124         SkASSERT((unsigned)index < 9);
    125         return fMat[index];
    126     }
    127 
    128     SkScalar get(int index) const {
    129         SkASSERT((unsigned)index < 9);
    130         return fMat[index];
    131     }
    132 
    133     SkScalar getScaleX() const { return fMat[kMScaleX]; }
    134     SkScalar getScaleY() const { return fMat[kMScaleY]; }
    135     SkScalar getSkewY() const { return fMat[kMSkewY]; }
    136     SkScalar getSkewX() const { return fMat[kMSkewX]; }
    137     SkScalar getTranslateX() const { return fMat[kMTransX]; }
    138     SkScalar getTranslateY() const { return fMat[kMTransY]; }
    139     SkPersp getPerspX() const { return fMat[kMPersp0]; }
    140     SkPersp getPerspY() const { return fMat[kMPersp1]; }
    141 
    142     SkScalar& operator[](int index) {
    143         SkASSERT((unsigned)index < 9);
    144         this->setTypeMask(kUnknown_Mask);
    145         return fMat[index];
    146     }
    147 
    148     void set(int index, SkScalar value) {
    149         SkASSERT((unsigned)index < 9);
    150         fMat[index] = value;
    151         this->setTypeMask(kUnknown_Mask);
    152     }
    153 
    154     void setScaleX(SkScalar v) { this->set(kMScaleX, v); }
    155     void setScaleY(SkScalar v) { this->set(kMScaleY, v); }
    156     void setSkewY(SkScalar v) { this->set(kMSkewY, v); }
    157     void setSkewX(SkScalar v) { this->set(kMSkewX, v); }
    158     void setTranslateX(SkScalar v) { this->set(kMTransX, v); }
    159     void setTranslateY(SkScalar v) { this->set(kMTransY, v); }
    160     void setPerspX(SkPersp v) { this->set(kMPersp0, v); }
    161     void setPerspY(SkPersp v) { this->set(kMPersp1, v); }
    162 
    163     void setAll(SkScalar scaleX, SkScalar skewX, SkScalar transX,
    164                 SkScalar skewY, SkScalar scaleY, SkScalar transY,
    165                 SkPersp persp0, SkPersp persp1, SkPersp persp2) {
    166         fMat[kMScaleX] = scaleX;
    167         fMat[kMSkewX]  = skewX;
    168         fMat[kMTransX] = transX;
    169         fMat[kMSkewY]  = skewY;
    170         fMat[kMScaleY] = scaleY;
    171         fMat[kMTransY] = transY;
    172         fMat[kMPersp0] = persp0;
    173         fMat[kMPersp1] = persp1;
    174         fMat[kMPersp2] = persp2;
    175         this->setTypeMask(kUnknown_Mask);
    176     }
    177 
    178     /** Set the matrix to identity
    179     */
    180     void reset();
    181     // alias for reset()
    182     void setIdentity() { this->reset(); }
    183 
    184     /** Set the matrix to translate by (dx, dy).
    185     */
    186     void setTranslate(SkScalar dx, SkScalar dy);
    187     void setTranslate(const SkVector& v) { this->setTranslate(v.fX, v.fY); }
    188 
    189     /** Set the matrix to scale by sx and sy, with a pivot point at (px, py).
    190         The pivot point is the coordinate that should remain unchanged by the
    191         specified transformation.
    192     */
    193     void setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py);
    194     /** Set the matrix to scale by sx and sy.
    195     */
    196     void setScale(SkScalar sx, SkScalar sy);
    197     /** Set the matrix to scale by 1/divx and 1/divy. Returns false and doesn't
    198         touch the matrix if either divx or divy is zero.
    199     */
    200     bool setIDiv(int divx, int divy);
    201     /** Set the matrix to rotate by the specified number of degrees, with a
    202         pivot point at (px, py). The pivot point is the coordinate that should
    203         remain unchanged by the specified transformation.
    204     */
    205     void setRotate(SkScalar degrees, SkScalar px, SkScalar py);
    206     /** Set the matrix to rotate about (0,0) by the specified number of degrees.
    207     */
    208     void setRotate(SkScalar degrees);
    209     /** Set the matrix to rotate by the specified sine and cosine values, with
    210         a pivot point at (px, py). The pivot point is the coordinate that
    211         should remain unchanged by the specified transformation.
    212     */
    213     void setSinCos(SkScalar sinValue, SkScalar cosValue,
    214                    SkScalar px, SkScalar py);
    215     /** Set the matrix to rotate by the specified sine and cosine values.
    216     */
    217     void setSinCos(SkScalar sinValue, SkScalar cosValue);
    218     /** Set the matrix to skew by sx and sy, with a pivot point at (px, py).
    219         The pivot point is the coordinate that should remain unchanged by the
    220         specified transformation.
    221     */
    222     void setSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py);
    223     /** Set the matrix to skew by sx and sy.
    224     */
    225     void setSkew(SkScalar kx, SkScalar ky);
    226     /** Set the matrix to the concatenation of the two specified matrices,
    227         returning true if the the result can be represented. Either of the
    228         two matrices may also be the target matrix. *this = a * b;
    229     */
    230     bool setConcat(const SkMatrix& a, const SkMatrix& b);
    231 
    232     /** Preconcats the matrix with the specified translation.
    233         M' = M * T(dx, dy)
    234     */
    235     bool preTranslate(SkScalar dx, SkScalar dy);
    236     /** Preconcats the matrix with the specified scale.
    237         M' = M * S(sx, sy, px, py)
    238     */
    239     bool preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py);
    240     /** Preconcats the matrix with the specified scale.
    241         M' = M * S(sx, sy)
    242     */
    243     bool preScale(SkScalar sx, SkScalar sy);
    244     /** Preconcats the matrix with the specified rotation.
    245         M' = M * R(degrees, px, py)
    246     */
    247     bool preRotate(SkScalar degrees, SkScalar px, SkScalar py);
    248     /** Preconcats the matrix with the specified rotation.
    249         M' = M * R(degrees)
    250     */
    251     bool preRotate(SkScalar degrees);
    252     /** Preconcats the matrix with the specified skew.
    253         M' = M * K(kx, ky, px, py)
    254     */
    255     bool preSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py);
    256     /** Preconcats the matrix with the specified skew.
    257         M' = M * K(kx, ky)
    258     */
    259     bool preSkew(SkScalar kx, SkScalar ky);
    260     /** Preconcats the matrix with the specified matrix.
    261         M' = M * other
    262     */
    263     bool preConcat(const SkMatrix& other);
    264 
    265     /** Postconcats the matrix with the specified translation.
    266         M' = T(dx, dy) * M
    267     */
    268     bool postTranslate(SkScalar dx, SkScalar dy);
    269     /** Postconcats the matrix with the specified scale.
    270         M' = S(sx, sy, px, py) * M
    271     */
    272     bool postScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py);
    273     /** Postconcats the matrix with the specified scale.
    274         M' = S(sx, sy) * M
    275     */
    276     bool postScale(SkScalar sx, SkScalar sy);
    277     /** Postconcats the matrix by dividing it by the specified integers.
    278         M' = S(1/divx, 1/divy, 0, 0) * M
    279     */
    280     bool postIDiv(int divx, int divy);
    281     /** Postconcats the matrix with the specified rotation.
    282         M' = R(degrees, px, py) * M
    283     */
    284     bool postRotate(SkScalar degrees, SkScalar px, SkScalar py);
    285     /** Postconcats the matrix with the specified rotation.
    286         M' = R(degrees) * M
    287     */
    288     bool postRotate(SkScalar degrees);
    289     /** Postconcats the matrix with the specified skew.
    290         M' = K(kx, ky, px, py) * M
    291     */
    292     bool postSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py);
    293     /** Postconcats the matrix with the specified skew.
    294         M' = K(kx, ky) * M
    295     */
    296     bool postSkew(SkScalar kx, SkScalar ky);
    297     /** Postconcats the matrix with the specified matrix.
    298         M' = other * M
    299     */
    300     bool postConcat(const SkMatrix& other);
    301 
    302     enum ScaleToFit {
    303         /**
    304          * Scale in X and Y independently, so that src matches dst exactly.
    305          * This may change the aspect ratio of the src.
    306          */
    307         kFill_ScaleToFit,
    308         /**
    309          * Compute a scale that will maintain the original src aspect ratio,
    310          * but will also ensure that src fits entirely inside dst. At least one
    311          * axis (X or Y) will fit exactly. kStart aligns the result to the
    312          * left and top edges of dst.
    313          */
    314         kStart_ScaleToFit,
    315         /**
    316          * Compute a scale that will maintain the original src aspect ratio,
    317          * but will also ensure that src fits entirely inside dst. At least one
    318          * axis (X or Y) will fit exactly. The result is centered inside dst.
    319          */
    320         kCenter_ScaleToFit,
    321         /**
    322          * Compute a scale that will maintain the original src aspect ratio,
    323          * but will also ensure that src fits entirely inside dst. At least one
    324          * axis (X or Y) will fit exactly. kEnd aligns the result to the
    325          * right and bottom edges of dst.
    326          */
    327         kEnd_ScaleToFit
    328     };
    329 
    330     /** Set the matrix to the scale and translate values that map the source
    331         rectangle to the destination rectangle, returning true if the the result
    332         can be represented.
    333         @param src the source rectangle to map from.
    334         @param dst the destination rectangle to map to.
    335         @param stf the ScaleToFit option
    336         @return true if the matrix can be represented by the rectangle mapping.
    337     */
    338     bool setRectToRect(const SkRect& src, const SkRect& dst, ScaleToFit stf);
    339 
    340     /** Set the matrix such that the specified src points would map to the
    341         specified dst points. count must be within [0..4].
    342         @param src  The array of src points
    343         @param dst  The array of dst points
    344         @param count The number of points to use for the transformation
    345         @return true if the matrix was set to the specified transformation
    346     */
    347     bool setPolyToPoly(const SkPoint src[], const SkPoint dst[], int count);
    348 
    349     /** If this matrix can be inverted, return true and if inverse is not null,
    350         set inverse to be the inverse of this matrix. If this matrix cannot be
    351         inverted, ignore inverse and return false
    352     */
    353     bool SK_WARN_UNUSED_RESULT invert(SkMatrix* inverse) const {
    354         // Allow the trivial case to be inlined.
    355         if (this->isIdentity()) {
    356             if (NULL != inverse) {
    357                 inverse->reset();
    358             }
    359             return true;
    360         }
    361         return this->invertNonIdentity(inverse);
    362     }
    363 
    364     /** Fills the passed array with affine identity values
    365         in column major order.
    366         @param affine  The array to fill with affine identity values.
    367         Must not be NULL.
    368     */
    369     static void SetAffineIdentity(SkScalar affine[6]);
    370 
    371     /** Fills the passed array with the affine values in column major order.
    372         If the matrix is a perspective transform, returns false
    373         and does not change the passed array.
    374         @param affine  The array to fill with affine values. Ignored if NULL.
    375     */
    376     bool asAffine(SkScalar affine[6]) const;
    377 
    378     /** Apply this matrix to the array of points specified by src, and write
    379         the transformed points into the array of points specified by dst.
    380         dst[] = M * src[]
    381         @param dst  Where the transformed coordinates are written. It must
    382                     contain at least count entries
    383         @param src  The original coordinates that are to be transformed. It
    384                     must contain at least count entries
    385         @param count The number of points in src to read, and then transform
    386                      into dst.
    387     */
    388     void mapPoints(SkPoint dst[], const SkPoint src[], int count) const;
    389 
    390     /** Apply this matrix to the array of points, overwriting it with the
    391         transformed values.
    392         dst[] = M * pts[]
    393         @param pts  The points to be transformed. It must contain at least
    394                     count entries
    395         @param count The number of points in pts.
    396     */
    397     void mapPoints(SkPoint pts[], int count) const {
    398         this->mapPoints(pts, pts, count);
    399     }
    400 
    401     /** Like mapPoints but with custom byte stride between the points. Stride
    402      *  should be a multiple of sizeof(SkScalar).
    403      */
    404     void mapPointsWithStride(SkPoint pts[], size_t stride, int count) const {
    405         SkASSERT(stride >= sizeof(SkPoint));
    406         SkASSERT(0 == stride % sizeof(SkScalar));
    407         for (int i = 0; i < count; ++i) {
    408             this->mapPoints(pts, pts, 1);
    409             pts = (SkPoint*)((intptr_t)pts + stride);
    410         }
    411     }
    412 
    413     /** Like mapPoints but with custom byte stride between the points.
    414     */
    415     void mapPointsWithStride(SkPoint dst[], SkPoint src[],
    416                              size_t stride, int count) const {
    417         SkASSERT(stride >= sizeof(SkPoint));
    418         SkASSERT(0 == stride % sizeof(SkScalar));
    419         for (int i = 0; i < count; ++i) {
    420             this->mapPoints(dst, src, 1);
    421             src = (SkPoint*)((intptr_t)src + stride);
    422             dst = (SkPoint*)((intptr_t)dst + stride);
    423         }
    424     }
    425 
    426     void mapXY(SkScalar x, SkScalar y, SkPoint* result) const {
    427         SkASSERT(result);
    428         this->getMapXYProc()(*this, x, y, result);
    429     }
    430 
    431     /** Apply this matrix to the array of vectors specified by src, and write
    432         the transformed vectors into the array of vectors specified by dst.
    433         This is similar to mapPoints, but ignores any translation in the matrix.
    434         @param dst  Where the transformed coordinates are written. It must
    435                     contain at least count entries
    436         @param src  The original coordinates that are to be transformed. It
    437                     must contain at least count entries
    438         @param count The number of vectors in src to read, and then transform
    439                      into dst.
    440     */
    441     void mapVectors(SkVector dst[], const SkVector src[], int count) const;
    442 
    443     /** Apply this matrix to the array of vectors specified by src, and write
    444         the transformed vectors into the array of vectors specified by dst.
    445         This is similar to mapPoints, but ignores any translation in the matrix.
    446         @param vecs The vectors to be transformed. It must contain at least
    447                     count entries
    448         @param count The number of vectors in vecs.
    449     */
    450     void mapVectors(SkVector vecs[], int count) const {
    451         this->mapVectors(vecs, vecs, count);
    452     }
    453 
    454     /** Apply this matrix to the src rectangle, and write the transformed
    455         rectangle into dst. This is accomplished by transforming the 4 corners
    456         of src, and then setting dst to the bounds of those points.
    457         @param dst  Where the transformed rectangle is written.
    458         @param src  The original rectangle to be transformed.
    459         @return the result of calling rectStaysRect()
    460     */
    461     bool mapRect(SkRect* dst, const SkRect& src) const;
    462 
    463     /** Apply this matrix to the rectangle, and write the transformed rectangle
    464         back into it. This is accomplished by transforming the 4 corners of
    465         rect, and then setting it to the bounds of those points
    466         @param rect The rectangle to transform.
    467         @return the result of calling rectStaysRect()
    468     */
    469     bool mapRect(SkRect* rect) const {
    470         return this->mapRect(rect, *rect);
    471     }
    472 
    473     /** Return the mean radius of a circle after it has been mapped by
    474         this matrix. NOTE: in perspective this value assumes the circle
    475         has its center at the origin.
    476     */
    477     SkScalar mapRadius(SkScalar radius) const;
    478 
    479     typedef void (*MapXYProc)(const SkMatrix& mat, SkScalar x, SkScalar y,
    480                                  SkPoint* result);
    481 
    482     static MapXYProc GetMapXYProc(TypeMask mask) {
    483         SkASSERT((mask & ~kAllMasks) == 0);
    484         return gMapXYProcs[mask & kAllMasks];
    485     }
    486 
    487     MapXYProc getMapXYProc() const {
    488         return GetMapXYProc(this->getType());
    489     }
    490 
    491     typedef void (*MapPtsProc)(const SkMatrix& mat, SkPoint dst[],
    492                                   const SkPoint src[], int count);
    493 
    494     static MapPtsProc GetMapPtsProc(TypeMask mask) {
    495         SkASSERT((mask & ~kAllMasks) == 0);
    496         return gMapPtsProcs[mask & kAllMasks];
    497     }
    498 
    499     MapPtsProc getMapPtsProc() const {
    500         return GetMapPtsProc(this->getType());
    501     }
    502 
    503     /** If the matrix can be stepped in X (not complex perspective)
    504         then return true and if step[XY] is not null, return the step[XY] value.
    505         If it cannot, return false and ignore step.
    506     */
    507     bool fixedStepInX(SkScalar y, SkFixed* stepX, SkFixed* stepY) const;
    508 
    509     /** Efficient comparison of two matrices. It distinguishes between zero and
    510      *  negative zero. It will return false when the sign of zero values is the
    511      *  only difference between the two matrices. It considers NaN values to be
    512      *  equal to themselves. So a matrix full of NaNs is "cheap equal" to
    513      *  another matrix full of NaNs iff the NaN values are bitwise identical
    514      *  while according to strict the strict == test a matrix with a NaN value
    515      *  is equal to nothing, including itself.
    516      */
    517     bool cheapEqualTo(const SkMatrix& m) const {
    518         return 0 == memcmp(fMat, m.fMat, sizeof(fMat));
    519     }
    520 
    521 #ifdef SK_SCALAR_IS_FIXED
    522     friend bool operator==(const SkMatrix& a, const SkMatrix& b) {
    523         return a.cheapEqualTo(b);
    524     }
    525 #else
    526     friend bool operator==(const SkMatrix& a, const SkMatrix& b);
    527 #endif
    528     friend bool operator!=(const SkMatrix& a, const SkMatrix& b) {
    529         return !(a == b);
    530     }
    531 
    532     enum {
    533         // writeTo/readFromMemory will never return a value larger than this
    534         kMaxFlattenSize = 9 * sizeof(SkScalar) + sizeof(uint32_t)
    535     };
    536     // return the number of bytes written, whether or not buffer is null
    537     uint32_t writeToMemory(void* buffer) const;
    538     // return the number of bytes read
    539     uint32_t readFromMemory(const void* buffer);
    540 
    541     SkDEVCODE(void dump() const;)
    542     SkDEVCODE(void toString(SkString*) const;)
    543 
    544     /**
    545      * Calculates the maximum stretching factor of the matrix. If the matrix has
    546      * perspective -1 is returned.
    547      *
    548      * @return maximum strecthing factor
    549      */
    550     SkScalar getMaxStretch() const;
    551 
    552     /**
    553      *  Return a reference to a const identity matrix
    554      */
    555     static const SkMatrix& I();
    556 
    557     /**
    558      *  Return a reference to a const matrix that is "invalid", one that could
    559      *  never be used.
    560      */
    561     static const SkMatrix& InvalidMatrix();
    562 
    563     /**
    564      * Testing routine; the matrix's type cache should never need to be
    565      * manually invalidated during normal use.
    566      */
    567     void dirtyMatrixTypeCache() {
    568         this->setTypeMask(kUnknown_Mask);
    569     }
    570 
    571 private:
    572     enum {
    573         /** Set if the matrix will map a rectangle to another rectangle. This
    574             can be true if the matrix is scale-only, or rotates a multiple of
    575             90 degrees.
    576 
    577             This bit will be set on identity matrices
    578         */
    579         kRectStaysRect_Mask = 0x10,
    580 
    581         /** Set if the perspective bit is valid even though the rest of
    582             the matrix is Unknown.
    583         */
    584         kOnlyPerspectiveValid_Mask = 0x40,
    585 
    586         kUnknown_Mask = 0x80,
    587 
    588         kORableMasks =  kTranslate_Mask |
    589                         kScale_Mask |
    590                         kAffine_Mask |
    591                         kPerspective_Mask,
    592 
    593         kAllMasks = kTranslate_Mask |
    594                     kScale_Mask |
    595                     kAffine_Mask |
    596                     kPerspective_Mask |
    597                     kRectStaysRect_Mask
    598     };
    599 
    600     SkScalar         fMat[9];
    601     mutable uint32_t fTypeMask;
    602 
    603     uint8_t computeTypeMask() const;
    604     uint8_t computePerspectiveTypeMask() const;
    605 
    606     void setTypeMask(int mask) {
    607         // allow kUnknown or a valid mask
    608         SkASSERT(kUnknown_Mask == mask || (mask & kAllMasks) == mask ||
    609                  ((kUnknown_Mask | kOnlyPerspectiveValid_Mask) & mask)
    610                  == (kUnknown_Mask | kOnlyPerspectiveValid_Mask));
    611         fTypeMask = SkToU8(mask);
    612     }
    613 
    614     void orTypeMask(int mask) {
    615         SkASSERT((mask & kORableMasks) == mask);
    616         fTypeMask = SkToU8(fTypeMask | mask);
    617     }
    618 
    619     void clearTypeMask(int mask) {
    620         // only allow a valid mask
    621         SkASSERT((mask & kAllMasks) == mask);
    622         fTypeMask &= ~mask;
    623     }
    624 
    625     TypeMask getPerspectiveTypeMaskOnly() const {
    626         if ((fTypeMask & kUnknown_Mask) &&
    627             !(fTypeMask & kOnlyPerspectiveValid_Mask)) {
    628             fTypeMask = this->computePerspectiveTypeMask();
    629         }
    630         return (TypeMask)(fTypeMask & 0xF);
    631     }
    632 
    633     /** Returns true if we already know that the matrix is identity;
    634         false otherwise.
    635     */
    636     bool isTriviallyIdentity() const {
    637         if (fTypeMask & kUnknown_Mask) {
    638             return false;
    639         }
    640         return ((fTypeMask & 0xF) == 0);
    641     }
    642 
    643     bool SK_WARN_UNUSED_RESULT invertNonIdentity(SkMatrix* inverse) const;
    644 
    645     static bool Poly2Proc(const SkPoint[], SkMatrix*, const SkPoint& scale);
    646     static bool Poly3Proc(const SkPoint[], SkMatrix*, const SkPoint& scale);
    647     static bool Poly4Proc(const SkPoint[], SkMatrix*, const SkPoint& scale);
    648 
    649     static void Identity_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
    650     static void Trans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
    651     static void Scale_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
    652     static void ScaleTrans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
    653     static void Rot_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
    654     static void RotTrans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
    655     static void Persp_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
    656 
    657     static const MapXYProc gMapXYProcs[];
    658 
    659     static void Identity_pts(const SkMatrix&, SkPoint[], const SkPoint[], int);
    660     static void Trans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int);
    661     static void Scale_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int);
    662     static void ScaleTrans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[],
    663                                int count);
    664     static void Rot_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int);
    665     static void RotTrans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[],
    666                              int count);
    667     static void Persp_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int);
    668 
    669     static const MapPtsProc gMapPtsProcs[];
    670 
    671     friend class SkPerspIter;
    672 };
    673 
    674 #endif
    675