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