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