Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright (C) 2006 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #ifndef SkMatrix_DEFINED
     18 #define SkMatrix_DEFINED
     19 
     20 #include "SkRect.h"
     21 
     22 class SkString;
     23 
     24 /** \class SkMatrix
     25 
     26     The SkMatrix class holds a 3x3 matrix for transforming coordinates.
     27     SkMatrix does not have a constructor, so it must be explicitly initialized
     28     using either reset() - to construct an identity matrix, or one of the set
     29     functions (e.g. setTranslate, setRotate, etc.).
     30 */
     31 class SkMatrix {
     32 public:
     33     /** Enum of bit fields for the mask return by getType().
     34         Use this to identify the complexity of the matrix.
     35     */
     36     enum TypeMask {
     37         kIdentity_Mask      = 0,
     38         kTranslate_Mask     = 0x01,  //!< set if the matrix has translation
     39         kScale_Mask         = 0x02,  //!< set if the matrix has X or Y scale
     40         kAffine_Mask        = 0x04,  //!< set if the matrix skews or rotates
     41         kPerspective_Mask   = 0x08   //!< set if the matrix is in perspective
     42     };
     43 
     44     /** Returns a mask bitfield describing the types of transformations
     45         that the matrix will perform. This information is used by routines
     46         like mapPoints, to optimize its inner loops to only perform as much
     47         arithmetic as is necessary.
     48     */
     49     TypeMask getType() const {
     50         if (fTypeMask & kUnknown_Mask) {
     51             fTypeMask = this->computeTypeMask();
     52         }
     53         // only return the public masks
     54         return (TypeMask)(fTypeMask & 0xF);
     55     }
     56 
     57     /** Returns true if the matrix is identity.
     58     */
     59     bool isIdentity() const {
     60         return this->getType() == 0;
     61     }
     62 
     63     /** Returns true if will map a rectangle to another rectangle. This can be
     64         true if the matrix is identity, scale-only, or rotates a multiple of
     65         90 degrees.
     66     */
     67     bool rectStaysRect() const {
     68         if (fTypeMask & kUnknown_Mask) {
     69             fTypeMask = this->computeTypeMask();
     70         }
     71         return (fTypeMask & kRectStaysRect_Mask) != 0;
     72     }
     73 
     74     enum {
     75         kMScaleX,
     76         kMSkewX,
     77         kMTransX,
     78         kMSkewY,
     79         kMScaleY,
     80         kMTransY,
     81         kMPersp0,
     82         kMPersp1,
     83         kMPersp2
     84     };
     85 
     86     SkScalar operator[](int index) const {
     87         SkASSERT((unsigned)index < 9);
     88         return fMat[index];
     89     }
     90 
     91     SkScalar get(int index) const {
     92         SkASSERT((unsigned)index < 9);
     93         return fMat[index];
     94     }
     95 
     96     SkScalar getScaleX() const { return fMat[kMScaleX]; }
     97     SkScalar getScaleY() const { return fMat[kMScaleY]; }
     98     SkScalar getSkewY() const { return fMat[kMSkewY]; }
     99     SkScalar getSkewX() const { return fMat[kMSkewX]; }
    100     SkScalar getTranslateX() const { return fMat[kMTransX]; }
    101     SkScalar getTranslateY() const { return fMat[kMTransY]; }
    102     SkScalar getPerspX() const { return fMat[kMPersp0]; }
    103     SkScalar getPerspY() const { return fMat[kMPersp1]; }
    104 
    105     SkScalar& operator[](int index) {
    106         SkASSERT((unsigned)index < 9);
    107         this->setTypeMask(kUnknown_Mask);
    108         return fMat[index];
    109     }
    110 
    111     void set(int index, SkScalar value) {
    112         SkASSERT((unsigned)index < 9);
    113         fMat[index] = value;
    114         this->setTypeMask(kUnknown_Mask);
    115     }
    116 
    117     void setScaleX(SkScalar v) { this->set(kMScaleX, v); }
    118     void setScaleY(SkScalar v) { this->set(kMScaleY, v); }
    119     void setSkewY(SkScalar v) { this->set(kMSkewY, v); }
    120     void setSkewX(SkScalar v) { this->set(kMSkewX, v); }
    121     void setTranslateX(SkScalar v) { this->set(kMTransX, v); }
    122     void setTranslateY(SkScalar v) { this->set(kMTransY, v); }
    123     void setPerspX(SkScalar v) { this->set(kMPersp0, v); }
    124     void setPerspY(SkScalar v) { this->set(kMPersp1, v); }
    125 
    126     /** Set the matrix to identity
    127     */
    128     void reset();
    129 
    130     /** Set the matrix to translate by (dx, dy).
    131     */
    132     void setTranslate(SkScalar dx, SkScalar dy);
    133     /** Set the matrix to scale by sx and sy, with a pivot point at (px, py).
    134         The pivot point is the coordinate that should remain unchanged by the
    135         specified transformation.
    136     */
    137     void setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py);
    138     /** Set the matrix to scale by sx and sy.
    139     */
    140     void setScale(SkScalar sx, SkScalar sy);
    141     /** Set the matrix to rotate by the specified number of degrees, with a
    142         pivot point at (px, py). The pivot point is the coordinate that should
    143         remain unchanged by the specified transformation.
    144     */
    145     void setRotate(SkScalar degrees, SkScalar px, SkScalar py);
    146     /** Set the matrix to rotate about (0,0) by the specified number of degrees.
    147     */
    148     void setRotate(SkScalar degrees);
    149     /** Set the matrix to rotate by the specified sine and cosine values, with
    150         a pivot point at (px, py). The pivot point is the coordinate that
    151         should remain unchanged by the specified transformation.
    152     */
    153     void setSinCos(SkScalar sinValue, SkScalar cosValue,
    154                    SkScalar px, SkScalar py);
    155     /** Set the matrix to rotate by the specified sine and cosine values.
    156     */
    157     void setSinCos(SkScalar sinValue, SkScalar cosValue);
    158     /** Set the matrix to skew by sx and sy, with a pivot point at (px, py).
    159         The pivot point is the coordinate that should remain unchanged by the
    160         specified transformation.
    161     */
    162     void setSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py);
    163     /** Set the matrix to skew by sx and sy.
    164     */
    165     void setSkew(SkScalar kx, SkScalar ky);
    166     /** Set the matrix to the concatenation of the two specified matrices,
    167         returning true if the the result can be represented. Either of the
    168         two matrices may also be the target matrix. *this = a * b;
    169     */
    170     bool setConcat(const SkMatrix& a, const SkMatrix& b);
    171 
    172     /** Preconcats the matrix with the specified translation.
    173         M' = M * T(dx, dy)
    174     */
    175     bool preTranslate(SkScalar dx, SkScalar dy);
    176     /** Preconcats the matrix with the specified scale.
    177         M' = M * S(sx, sy, px, py)
    178     */
    179     bool preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py);
    180     /** Preconcats the matrix with the specified scale.
    181         M' = M * S(sx, sy)
    182     */
    183     bool preScale(SkScalar sx, SkScalar sy);
    184     /** Preconcats the matrix with the specified rotation.
    185         M' = M * R(degrees, px, py)
    186     */
    187     bool preRotate(SkScalar degrees, SkScalar px, SkScalar py);
    188     /** Preconcats the matrix with the specified rotation.
    189         M' = M * R(degrees)
    190     */
    191     bool preRotate(SkScalar degrees);
    192     /** Preconcats the matrix with the specified skew.
    193         M' = M * K(kx, ky, px, py)
    194     */
    195     bool preSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py);
    196     /** Preconcats the matrix with the specified skew.
    197         M' = M * K(kx, ky)
    198     */
    199     bool preSkew(SkScalar kx, SkScalar ky);
    200     /** Preconcats the matrix with the specified matrix.
    201         M' = M * other
    202     */
    203     bool preConcat(const SkMatrix& other);
    204 
    205     /** Postconcats the matrix with the specified translation.
    206         M' = T(dx, dy) * M
    207     */
    208     bool postTranslate(SkScalar dx, SkScalar dy);
    209     /** Postconcats the matrix with the specified scale.
    210         M' = S(sx, sy, px, py) * M
    211     */
    212     bool postScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py);
    213     /** Postconcats the matrix with the specified scale.
    214         M' = S(sx, sy) * M
    215     */
    216     bool postScale(SkScalar sx, SkScalar sy);
    217     /** Postconcats the matrix by dividing it by the specified integers.
    218         M' = S(1/divx, 1/divy, 0, 0) * M
    219     */
    220     bool postIDiv(int divx, int divy);
    221     /** Postconcats the matrix with the specified rotation.
    222         M' = R(degrees, px, py) * M
    223     */
    224     bool postRotate(SkScalar degrees, SkScalar px, SkScalar py);
    225     /** Postconcats the matrix with the specified rotation.
    226         M' = R(degrees) * M
    227     */
    228     bool postRotate(SkScalar degrees);
    229     /** Postconcats the matrix with the specified skew.
    230         M' = K(kx, ky, px, py) * M
    231     */
    232     bool postSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py);
    233     /** Postconcats the matrix with the specified skew.
    234         M' = K(kx, ky) * M
    235     */
    236     bool postSkew(SkScalar kx, SkScalar ky);
    237     /** Postconcats the matrix with the specified matrix.
    238         M' = other * M
    239     */
    240     bool postConcat(const SkMatrix& other);
    241 
    242     enum ScaleToFit {
    243         /**
    244          * Scale in X and Y independently, so that src matches dst exactly.
    245          * This may change the aspect ratio of the src.
    246          */
    247         kFill_ScaleToFit,
    248         /**
    249          * Compute a scale that will maintain the original src aspect ratio,
    250          * but will also ensure that src fits entirely inside dst. At least one
    251          * axis (X or Y) will fit exactly. kStart aligns the result to the
    252          * left and top edges of dst.
    253          */
    254         kStart_ScaleToFit,
    255         /**
    256          * Compute a scale that will maintain the original src aspect ratio,
    257          * but will also ensure that src fits entirely inside dst. At least one
    258          * axis (X or Y) will fit exactly. The result is centered inside dst.
    259          */
    260         kCenter_ScaleToFit,
    261         /**
    262          * Compute a scale that will maintain the original src aspect ratio,
    263          * but will also ensure that src fits entirely inside dst. At least one
    264          * axis (X or Y) will fit exactly. kEnd aligns the result to the
    265          * right and bottom edges of dst.
    266          */
    267         kEnd_ScaleToFit
    268     };
    269 
    270     /** Set the matrix to the scale and translate values that map the source
    271         rectangle to the destination rectangle, returning true if the the result
    272         can be represented.
    273         @param src the source rectangle to map from.
    274         @param dst the destination rectangle to map to.
    275         @param stf the ScaleToFit option
    276         @return true if the matrix can be represented by the rectangle mapping.
    277     */
    278     bool setRectToRect(const SkRect& src, const SkRect& dst, ScaleToFit stf);
    279 
    280     /** Set the matrix such that the specified src points would map to the
    281         specified dst points. count must be within [0..4].
    282         @param src  The array of src points
    283         @param dst  The array of dst points
    284         @param count The number of points to use for the transformation
    285         @return true if the matrix was set to the specified transformation
    286     */
    287     bool setPolyToPoly(const SkPoint src[], const SkPoint dst[], int count);
    288 
    289     /** If this matrix can be inverted, return true and if inverse is not null,
    290         set inverse to be the inverse of this matrix. If this matrix cannot be
    291         inverted, ignore inverse and return false
    292     */
    293     bool invert(SkMatrix* inverse) const;
    294 
    295     /** Apply this matrix to the array of points specified by src, and write
    296         the transformed points into the array of points specified by dst.
    297         dst[] = M * src[]
    298         @param dst  Where the transformed coordinates are written. It must
    299                     contain at least count entries
    300         @param src  The original coordinates that are to be transformed. It
    301                     must contain at least count entries
    302         @param count The number of points in src to read, and then transform
    303                      into dst.
    304     */
    305     void mapPoints(SkPoint dst[], const SkPoint src[], int count) const;
    306 
    307     /** Apply this matrix to the array of points, overwriting it with the
    308         transformed values.
    309         dst[] = M * pts[]
    310         @param pts  The points to be transformed. It must contain at least
    311                     count entries
    312         @param count The number of points in pts.
    313     */
    314     void mapPoints(SkPoint pts[], int count) const {
    315         this->mapPoints(pts, pts, count);
    316     }
    317 
    318     void mapXY(SkScalar x, SkScalar y, SkPoint* result) const {
    319         SkASSERT(result);
    320         this->getMapXYProc()(*this, x, y, result);
    321     }
    322 
    323     /** Apply this matrix to the array of vectors specified by src, and write
    324         the transformed vectors into the array of vectors specified by dst.
    325         This is similar to mapPoints, but ignores any translation in the matrix.
    326         @param dst  Where the transformed coordinates are written. It must
    327                     contain at least count entries
    328         @param src  The original coordinates that are to be transformed. It
    329                     must contain at least count entries
    330         @param count The number of vectors in src to read, and then transform
    331                      into dst.
    332     */
    333     void mapVectors(SkVector dst[], const SkVector src[], int count) const;
    334 
    335     /** Apply this matrix to the array of vectors specified by src, and write
    336         the transformed vectors into the array of vectors specified by dst.
    337         This is similar to mapPoints, but ignores any translation in the matrix.
    338         @param vecs The vectors to be transformed. It must contain at least
    339                     count entries
    340         @param count The number of vectors in vecs.
    341     */
    342     void mapVectors(SkVector vecs[], int count) const {
    343         this->mapVectors(vecs, vecs, count);
    344     }
    345 
    346     /** Apply this matrix to the src rectangle, and write the transformed
    347         rectangle into dst. This is accomplished by transforming the 4 corners
    348         of src, and then setting dst to the bounds of those points.
    349         @param dst  Where the transformed rectangle is written.
    350         @param src  The original rectangle to be transformed.
    351         @return the result of calling rectStaysRect()
    352     */
    353     bool mapRect(SkRect* dst, const SkRect& src) const;
    354 
    355     /** Apply this matrix to the rectangle, and write the transformed rectangle
    356         back into it. This is accomplished by transforming the 4 corners of
    357         rect, and then setting it to the bounds of those points
    358         @param rect The rectangle to transform.
    359         @return the result of calling rectStaysRect()
    360     */
    361     bool mapRect(SkRect* rect) const {
    362         return this->mapRect(rect, *rect);
    363     }
    364 
    365     /** Return the mean radius of a circle after it has been mapped by
    366         this matrix. NOTE: in perspective this value assumes the circle
    367         has its center at the origin.
    368     */
    369     SkScalar mapRadius(SkScalar radius) const;
    370 
    371     typedef void (*MapXYProc)(const SkMatrix& mat, SkScalar x, SkScalar y,
    372                                  SkPoint* result);
    373 
    374     static MapXYProc GetMapXYProc(TypeMask mask) {
    375         SkASSERT((mask & ~kAllMasks) == 0);
    376         return gMapXYProcs[mask & kAllMasks];
    377     }
    378 
    379     MapXYProc getMapXYProc() const {
    380         return GetMapXYProc(this->getType());
    381     }
    382 
    383     typedef void (*MapPtsProc)(const SkMatrix& mat, SkPoint dst[],
    384                                   const SkPoint src[], int count);
    385 
    386     static MapPtsProc GetMapPtsProc(TypeMask mask) {
    387         SkASSERT((mask & ~kAllMasks) == 0);
    388         return gMapPtsProcs[mask & kAllMasks];
    389     }
    390 
    391     MapPtsProc getMapPtsProc() const {
    392         return GetMapPtsProc(this->getType());
    393     }
    394 
    395     /** If the matrix can be stepped in X (not complex perspective)
    396         then return true and if step[XY] is not null, return the step[XY] value.
    397         If it cannot, return false and ignore step.
    398     */
    399     bool fixedStepInX(SkScalar y, SkFixed* stepX, SkFixed* stepY) const;
    400 
    401     friend bool operator==(const SkMatrix& a, const SkMatrix& b) {
    402         return memcmp(a.fMat, b.fMat, sizeof(a.fMat)) == 0;
    403     }
    404 
    405     friend bool operator!=(const SkMatrix& a, const SkMatrix& b) {
    406         return memcmp(a.fMat, b.fMat, sizeof(a.fMat)) != 0;
    407     }
    408 
    409     enum {
    410         // flatten/unflatten will never return a value larger than this
    411         kMaxFlattenSize = 9 * sizeof(SkScalar) + sizeof(uint32_t)
    412     };
    413     // return the number of bytes written, whether or not buffer is null
    414     uint32_t flatten(void* buffer) const;
    415     // return the number of bytes read
    416     uint32_t unflatten(const void* buffer);
    417 
    418     void dump() const;
    419     void toDumpString(SkString*) const;
    420 
    421 private:
    422     enum {
    423         /** Set if the matrix will map a rectangle to another rectangle. This
    424             can be true if the matrix is scale-only, or rotates a multiple of
    425             90 degrees. This bit is not set if the matrix is identity.
    426 
    427             This bit will be set on identity matrices
    428         */
    429         kRectStaysRect_Mask = 0x10,
    430 
    431         kUnknown_Mask = 0x80,
    432 
    433         kAllMasks = kTranslate_Mask |
    434                     kScale_Mask |
    435                     kAffine_Mask |
    436                     kPerspective_Mask |
    437                     kRectStaysRect_Mask
    438     };
    439 
    440     SkScalar        fMat[9];
    441     mutable uint8_t fTypeMask;
    442 
    443     uint8_t computeTypeMask() const;
    444 
    445     void setTypeMask(int mask) {
    446         // allow kUnknown or a valid mask
    447         SkASSERT(kUnknown_Mask == mask || (mask & kAllMasks) == mask);
    448         fTypeMask = SkToU8(mask);
    449     }
    450 
    451     void clearTypeMask(int mask) {
    452         // only allow a valid mask
    453         SkASSERT((mask & kAllMasks) == mask);
    454         fTypeMask &= ~mask;
    455     }
    456 
    457     static bool Poly2Proc(const SkPoint[], SkMatrix*, const SkPoint& scale);
    458     static bool Poly3Proc(const SkPoint[], SkMatrix*, const SkPoint& scale);
    459     static bool Poly4Proc(const SkPoint[], SkMatrix*, const SkPoint& scale);
    460 
    461     static void Identity_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
    462     static void Trans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
    463     static void Scale_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
    464     static void ScaleTrans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
    465     static void Rot_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
    466     static void RotTrans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
    467     static void Persp_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
    468 
    469     static const MapXYProc gMapXYProcs[];
    470 
    471     static void Identity_pts(const SkMatrix&, SkPoint[], const SkPoint[], int);
    472     static void Trans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int);
    473     static void Scale_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int);
    474     static void ScaleTrans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[],
    475                                int count);
    476     static void Rot_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int);
    477     static void RotTrans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[],
    478                              int count);
    479     static void Persp_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int);
    480 
    481     static const MapPtsProc gMapPtsProcs[];
    482 
    483     friend class SkPerspIter;
    484 };
    485 
    486 #endif
    487 
    488