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