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