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 SK_API 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     // alias for rectStaysRect()
     74     bool preservesAxisAlignment() const { return this->rectStaysRect(); }
     75 
     76     /**
     77      *  Returns true if the perspective contains perspective elements.
     78      */
     79     bool hasPerspective() const {
     80         return SkToBool(this->getType() & kPerspective_Mask);
     81     }
     82 
     83     enum {
     84         kMScaleX,
     85         kMSkewX,
     86         kMTransX,
     87         kMSkewY,
     88         kMScaleY,
     89         kMTransY,
     90         kMPersp0,
     91         kMPersp1,
     92         kMPersp2
     93     };
     94 
     95     SkScalar operator[](int index) const {
     96         SkASSERT((unsigned)index < 9);
     97         return fMat[index];
     98     }
     99 
    100     SkScalar get(int index) const {
    101         SkASSERT((unsigned)index < 9);
    102         return fMat[index];
    103     }
    104 
    105     SkScalar getScaleX() const { return fMat[kMScaleX]; }
    106     SkScalar getScaleY() const { return fMat[kMScaleY]; }
    107     SkScalar getSkewY() const { return fMat[kMSkewY]; }
    108     SkScalar getSkewX() const { return fMat[kMSkewX]; }
    109     SkScalar getTranslateX() const { return fMat[kMTransX]; }
    110     SkScalar getTranslateY() const { return fMat[kMTransY]; }
    111     SkScalar getPerspX() const { return fMat[kMPersp0]; }
    112     SkScalar getPerspY() const { return fMat[kMPersp1]; }
    113 
    114     SkScalar& operator[](int index) {
    115         SkASSERT((unsigned)index < 9);
    116         this->setTypeMask(kUnknown_Mask);
    117         return fMat[index];
    118     }
    119 
    120     void set(int index, SkScalar value) {
    121         SkASSERT((unsigned)index < 9);
    122         fMat[index] = value;
    123         this->setTypeMask(kUnknown_Mask);
    124     }
    125 
    126     void setScaleX(SkScalar v) { this->set(kMScaleX, v); }
    127     void setScaleY(SkScalar v) { this->set(kMScaleY, v); }
    128     void setSkewY(SkScalar v) { this->set(kMSkewY, v); }
    129     void setSkewX(SkScalar v) { this->set(kMSkewX, v); }
    130     void setTranslateX(SkScalar v) { this->set(kMTransX, v); }
    131     void setTranslateY(SkScalar v) { this->set(kMTransY, v); }
    132     void setPerspX(SkScalar v) { this->set(kMPersp0, v); }
    133     void setPerspY(SkScalar v) { this->set(kMPersp1, v); }
    134 
    135     void setAll(SkScalar scaleX, SkScalar skewX, SkScalar transX,
    136                 SkScalar skewY, SkScalar scaleY, SkScalar transY,
    137                 SkScalar persp0, SkScalar persp1, SkScalar persp2) {
    138         fMat[kMScaleX] = scaleX;
    139         fMat[kMSkewX]  = skewX;
    140         fMat[kMTransX] = transX;
    141         fMat[kMSkewY]  = skewY;
    142         fMat[kMScaleY] = scaleY;
    143         fMat[kMTransY] = transY;
    144         fMat[kMPersp0] = persp0;
    145         fMat[kMPersp1] = persp1;
    146         fMat[kMPersp2] = persp2;
    147         this->setTypeMask(kUnknown_Mask);
    148     }
    149 
    150     /** Set the matrix to identity
    151     */
    152     void reset();
    153     // alias for reset()
    154     void setIdentity() { this->reset(); }
    155 
    156     /** Set the matrix to translate by (dx, dy).
    157     */
    158     void setTranslate(SkScalar dx, SkScalar dy);
    159     /** Set the matrix to scale by sx and sy, with a pivot point at (px, py).
    160         The pivot point is the coordinate that should remain unchanged by the
    161         specified transformation.
    162     */
    163     void setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py);
    164     /** Set the matrix to scale by sx and sy.
    165     */
    166     void setScale(SkScalar sx, SkScalar sy);
    167     /** Set the matrix to rotate by the specified number of degrees, with a
    168         pivot point at (px, py). The pivot point is the coordinate that should
    169         remain unchanged by the specified transformation.
    170     */
    171     void setRotate(SkScalar degrees, SkScalar px, SkScalar py);
    172     /** Set the matrix to rotate about (0,0) by the specified number of degrees.
    173     */
    174     void setRotate(SkScalar degrees);
    175     /** Set the matrix to rotate by the specified sine and cosine values, with
    176         a pivot point at (px, py). The pivot point is the coordinate that
    177         should remain unchanged by the specified transformation.
    178     */
    179     void setSinCos(SkScalar sinValue, SkScalar cosValue,
    180                    SkScalar px, SkScalar py);
    181     /** Set the matrix to rotate by the specified sine and cosine values.
    182     */
    183     void setSinCos(SkScalar sinValue, SkScalar cosValue);
    184     /** Set the matrix to skew by sx and sy, with a pivot point at (px, py).
    185         The pivot point is the coordinate that should remain unchanged by the
    186         specified transformation.
    187     */
    188     void setSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py);
    189     /** Set the matrix to skew by sx and sy.
    190     */
    191     void setSkew(SkScalar kx, SkScalar ky);
    192     /** Set the matrix to the concatenation of the two specified matrices,
    193         returning true if the the result can be represented. Either of the
    194         two matrices may also be the target matrix. *this = a * b;
    195     */
    196     bool setConcat(const SkMatrix& a, const SkMatrix& b);
    197 
    198     /** Preconcats the matrix with the specified translation.
    199         M' = M * T(dx, dy)
    200     */
    201     bool preTranslate(SkScalar dx, SkScalar dy);
    202     /** Preconcats the matrix with the specified scale.
    203         M' = M * S(sx, sy, px, py)
    204     */
    205     bool preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py);
    206     /** Preconcats the matrix with the specified scale.
    207         M' = M * S(sx, sy)
    208     */
    209     bool preScale(SkScalar sx, SkScalar sy);
    210     /** Preconcats the matrix with the specified rotation.
    211         M' = M * R(degrees, px, py)
    212     */
    213     bool preRotate(SkScalar degrees, SkScalar px, SkScalar py);
    214     /** Preconcats the matrix with the specified rotation.
    215         M' = M * R(degrees)
    216     */
    217     bool preRotate(SkScalar degrees);
    218     /** Preconcats the matrix with the specified skew.
    219         M' = M * K(kx, ky, px, py)
    220     */
    221     bool preSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py);
    222     /** Preconcats the matrix with the specified skew.
    223         M' = M * K(kx, ky)
    224     */
    225     bool preSkew(SkScalar kx, SkScalar ky);
    226     /** Preconcats the matrix with the specified matrix.
    227         M' = M * other
    228     */
    229     bool preConcat(const SkMatrix& other);
    230 
    231     /** Postconcats the matrix with the specified translation.
    232         M' = T(dx, dy) * M
    233     */
    234     bool postTranslate(SkScalar dx, SkScalar dy);
    235     /** Postconcats the matrix with the specified scale.
    236         M' = S(sx, sy, px, py) * M
    237     */
    238     bool postScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py);
    239     /** Postconcats the matrix with the specified scale.
    240         M' = S(sx, sy) * M
    241     */
    242     bool postScale(SkScalar sx, SkScalar sy);
    243     /** Postconcats the matrix by dividing it by the specified integers.
    244         M' = S(1/divx, 1/divy, 0, 0) * M
    245     */
    246     bool postIDiv(int divx, int divy);
    247     /** Postconcats the matrix with the specified rotation.
    248         M' = R(degrees, px, py) * M
    249     */
    250     bool postRotate(SkScalar degrees, SkScalar px, SkScalar py);
    251     /** Postconcats the matrix with the specified rotation.
    252         M' = R(degrees) * M
    253     */
    254     bool postRotate(SkScalar degrees);
    255     /** Postconcats the matrix with the specified skew.
    256         M' = K(kx, ky, px, py) * M
    257     */
    258     bool postSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py);
    259     /** Postconcats the matrix with the specified skew.
    260         M' = K(kx, ky) * M
    261     */
    262     bool postSkew(SkScalar kx, SkScalar ky);
    263     /** Postconcats the matrix with the specified matrix.
    264         M' = other * M
    265     */
    266     bool postConcat(const SkMatrix& other);
    267 
    268     enum ScaleToFit {
    269         /**
    270          * Scale in X and Y independently, so that src matches dst exactly.
    271          * This may change the aspect ratio of the src.
    272          */
    273         kFill_ScaleToFit,
    274         /**
    275          * Compute a scale that will maintain the original src aspect ratio,
    276          * but will also ensure that src fits entirely inside dst. At least one
    277          * axis (X or Y) will fit exactly. kStart aligns the result to the
    278          * left and top edges of dst.
    279          */
    280         kStart_ScaleToFit,
    281         /**
    282          * Compute a scale that will maintain the original src aspect ratio,
    283          * but will also ensure that src fits entirely inside dst. At least one
    284          * axis (X or Y) will fit exactly. The result is centered inside dst.
    285          */
    286         kCenter_ScaleToFit,
    287         /**
    288          * Compute a scale that will maintain the original src aspect ratio,
    289          * but will also ensure that src fits entirely inside dst. At least one
    290          * axis (X or Y) will fit exactly. kEnd aligns the result to the
    291          * right and bottom edges of dst.
    292          */
    293         kEnd_ScaleToFit
    294     };
    295 
    296     /** Set the matrix to the scale and translate values that map the source
    297         rectangle to the destination rectangle, returning true if the the result
    298         can be represented.
    299         @param src the source rectangle to map from.
    300         @param dst the destination rectangle to map to.
    301         @param stf the ScaleToFit option
    302         @return true if the matrix can be represented by the rectangle mapping.
    303     */
    304     bool setRectToRect(const SkRect& src, const SkRect& dst, ScaleToFit stf);
    305 
    306     /** Set the matrix such that the specified src points would map to the
    307         specified dst points. count must be within [0..4].
    308         @param src  The array of src points
    309         @param dst  The array of dst points
    310         @param count The number of points to use for the transformation
    311         @return true if the matrix was set to the specified transformation
    312     */
    313     bool setPolyToPoly(const SkPoint src[], const SkPoint dst[], int count);
    314 
    315     /** If this matrix can be inverted, return true and if inverse is not null,
    316         set inverse to be the inverse of this matrix. If this matrix cannot be
    317         inverted, ignore inverse and return false
    318     */
    319     bool invert(SkMatrix* inverse) const;
    320 
    321     /** Fills the passed array with the tranform values in the right order
    322         for PDFs.  If the matrix is a perspective transform, returns false
    323         and fills the array with an identity transform.
    324         @param transform  The array to fill in.
    325     */
    326     bool pdfTransform(SkScalar transform[6]) const;
    327 
    328     /** Apply this matrix to the array of points specified by src, and write
    329         the transformed points into the array of points specified by dst.
    330         dst[] = M * src[]
    331         @param dst  Where the transformed coordinates are written. It must
    332                     contain at least count entries
    333         @param src  The original coordinates that are to be transformed. It
    334                     must contain at least count entries
    335         @param count The number of points in src to read, and then transform
    336                      into dst.
    337     */
    338     void mapPoints(SkPoint dst[], const SkPoint src[], int count) const;
    339 
    340     /** Apply this matrix to the array of points, overwriting it with the
    341         transformed values.
    342         dst[] = M * pts[]
    343         @param pts  The points to be transformed. It must contain at least
    344                     count entries
    345         @param count The number of points in pts.
    346     */
    347     void mapPoints(SkPoint pts[], int count) const {
    348         this->mapPoints(pts, pts, count);
    349     }
    350 
    351     void mapXY(SkScalar x, SkScalar y, SkPoint* result) const {
    352         SkASSERT(result);
    353         this->getMapXYProc()(*this, x, y, result);
    354     }
    355 
    356     /** Apply this matrix to the array of vectors specified by src, and write
    357         the transformed vectors into the array of vectors specified by dst.
    358         This is similar to mapPoints, but ignores any translation in the matrix.
    359         @param dst  Where the transformed coordinates are written. It must
    360                     contain at least count entries
    361         @param src  The original coordinates that are to be transformed. It
    362                     must contain at least count entries
    363         @param count The number of vectors in src to read, and then transform
    364                      into dst.
    365     */
    366     void mapVectors(SkVector dst[], const SkVector src[], int count) const;
    367 
    368     /** Apply this matrix to the array of vectors specified by src, and write
    369         the transformed vectors into the array of vectors specified by dst.
    370         This is similar to mapPoints, but ignores any translation in the matrix.
    371         @param vecs The vectors to be transformed. It must contain at least
    372                     count entries
    373         @param count The number of vectors in vecs.
    374     */
    375     void mapVectors(SkVector vecs[], int count) const {
    376         this->mapVectors(vecs, vecs, count);
    377     }
    378 
    379     /** Apply this matrix to the src rectangle, and write the transformed
    380         rectangle into dst. This is accomplished by transforming the 4 corners
    381         of src, and then setting dst to the bounds of those points.
    382         @param dst  Where the transformed rectangle is written.
    383         @param src  The original rectangle to be transformed.
    384         @return the result of calling rectStaysRect()
    385     */
    386     bool mapRect(SkRect* dst, const SkRect& src) const;
    387 
    388     /** Apply this matrix to the rectangle, and write the transformed rectangle
    389         back into it. This is accomplished by transforming the 4 corners of
    390         rect, and then setting it to the bounds of those points
    391         @param rect The rectangle to transform.
    392         @return the result of calling rectStaysRect()
    393     */
    394     bool mapRect(SkRect* rect) const {
    395         return this->mapRect(rect, *rect);
    396     }
    397 
    398     void mapPointsWithStride(SkPoint pts[], size_t stride, int count) const {
    399         for (int i = 0; i < count; ++i) {
    400             this->mapPoints(pts, pts, 1);
    401             pts = (SkPoint*)((intptr_t)pts + stride);
    402         }
    403     }
    404 
    405     /** Return the mean radius of a circle after it has been mapped by
    406         this matrix. NOTE: in perspective this value assumes the circle
    407         has its center at the origin.
    408     */
    409     SkScalar mapRadius(SkScalar radius) const;
    410 
    411     typedef void (*MapXYProc)(const SkMatrix& mat, SkScalar x, SkScalar y,
    412                                  SkPoint* result);
    413 
    414     static MapXYProc GetMapXYProc(TypeMask mask) {
    415         SkASSERT((mask & ~kAllMasks) == 0);
    416         return gMapXYProcs[mask & kAllMasks];
    417     }
    418 
    419     MapXYProc getMapXYProc() const {
    420         return GetMapXYProc(this->getType());
    421     }
    422 
    423     typedef void (*MapPtsProc)(const SkMatrix& mat, SkPoint dst[],
    424                                   const SkPoint src[], int count);
    425 
    426     static MapPtsProc GetMapPtsProc(TypeMask mask) {
    427         SkASSERT((mask & ~kAllMasks) == 0);
    428         return gMapPtsProcs[mask & kAllMasks];
    429     }
    430 
    431     MapPtsProc getMapPtsProc() const {
    432         return GetMapPtsProc(this->getType());
    433     }
    434 
    435     /** If the matrix can be stepped in X (not complex perspective)
    436         then return true and if step[XY] is not null, return the step[XY] value.
    437         If it cannot, return false and ignore step.
    438     */
    439     bool fixedStepInX(SkScalar y, SkFixed* stepX, SkFixed* stepY) const;
    440 
    441 #ifdef SK_SCALAR_IS_FIXED
    442     friend bool operator==(const SkMatrix& a, const SkMatrix& b) {
    443         return memcmp(a.fMat, b.fMat, sizeof(a.fMat)) == 0;
    444     }
    445 
    446     friend bool operator!=(const SkMatrix& a, const SkMatrix& b) {
    447         return memcmp(a.fMat, b.fMat, sizeof(a.fMat)) != 0;
    448     }
    449 #else
    450     friend bool operator==(const SkMatrix& a, const SkMatrix& b);
    451     friend bool operator!=(const SkMatrix& a, const SkMatrix& b) {
    452         return !(a == b);
    453     }
    454 #endif
    455 
    456     enum {
    457         // flatten/unflatten will never return a value larger than this
    458         kMaxFlattenSize = 9 * sizeof(SkScalar) + sizeof(uint32_t)
    459     };
    460     // return the number of bytes written, whether or not buffer is null
    461     uint32_t flatten(void* buffer) const;
    462     // return the number of bytes read
    463     uint32_t unflatten(const void* buffer);
    464 
    465     void dump() const;
    466     void toDumpString(SkString*) const;
    467 
    468     /**
    469      * Calculates the maximum stretching factor of the matrix. Only defined if
    470      * the matrix does not have perspective.
    471      *
    472      * @return maximum strecthing factor or negative if matrix has perspective.
    473      */
    474     SkScalar getMaxStretch() const;
    475 
    476     /**
    477      *  Return a reference to a const identity matrix
    478      */
    479     static const SkMatrix& I();
    480 
    481     /**
    482      *  Return a reference to a const matrix that is "invalid", one that could
    483      *  never be used.
    484      */
    485     static const SkMatrix& InvalidMatrix();
    486 
    487 private:
    488     enum {
    489         /** Set if the matrix will map a rectangle to another rectangle. This
    490             can be true if the matrix is scale-only, or rotates a multiple of
    491             90 degrees. This bit is not set if the matrix is identity.
    492 
    493             This bit will be set on identity matrices
    494         */
    495         kRectStaysRect_Mask = 0x10,
    496 
    497         kUnknown_Mask = 0x80,
    498 
    499         kORableMasks =  kTranslate_Mask |
    500                         kScale_Mask |
    501                         kAffine_Mask |
    502                         kPerspective_Mask,
    503 
    504         kAllMasks = kTranslate_Mask |
    505                     kScale_Mask |
    506                     kAffine_Mask |
    507                     kPerspective_Mask |
    508                     kRectStaysRect_Mask
    509     };
    510 
    511     SkScalar        fMat[9];
    512     mutable uint8_t fTypeMask;
    513 
    514     uint8_t computeTypeMask() const;
    515 
    516     void setTypeMask(int mask) {
    517         // allow kUnknown or a valid mask
    518         SkASSERT(kUnknown_Mask == mask || (mask & kAllMasks) == mask);
    519         fTypeMask = SkToU8(mask);
    520     }
    521 
    522     void orTypeMask(int mask) {
    523         SkASSERT((mask & kORableMasks) == mask);
    524         fTypeMask = SkToU8(fTypeMask | mask);
    525     }
    526 
    527     void clearTypeMask(int mask) {
    528         // only allow a valid mask
    529         SkASSERT((mask & kAllMasks) == mask);
    530         fTypeMask &= ~mask;
    531     }
    532 
    533     static bool Poly2Proc(const SkPoint[], SkMatrix*, const SkPoint& scale);
    534     static bool Poly3Proc(const SkPoint[], SkMatrix*, const SkPoint& scale);
    535     static bool Poly4Proc(const SkPoint[], SkMatrix*, const SkPoint& scale);
    536 
    537     static void Identity_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
    538     static void Trans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
    539     static void Scale_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
    540     static void ScaleTrans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
    541     static void Rot_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
    542     static void RotTrans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
    543     static void Persp_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
    544 
    545     static const MapXYProc gMapXYProcs[];
    546 
    547     static void Identity_pts(const SkMatrix&, SkPoint[], const SkPoint[], int);
    548     static void Trans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int);
    549     static void Scale_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int);
    550     static void ScaleTrans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[],
    551                                int count);
    552     static void Rot_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int);
    553     static void RotTrans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[],
    554                              int count);
    555     static void Persp_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int);
    556 
    557     static const MapPtsProc gMapPtsProcs[];
    558 
    559     friend class SkPerspIter;
    560 };
    561 
    562 #endif
    563 
    564