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