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