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