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