Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / include / core / SkMatrix.h
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 "SkDynamicAnnotations.h"
14 #include "SkRect.h"
15
16 class SkString;
17
18 // TODO: can we remove these 3 (need to check chrome/android)
19 typedef SkScalar SkPersp;
20 #define SkScalarToPersp(x) (x)
21 #define SkPerspToScalar(x) (x)
22
23 /** \class SkMatrix
24
25     The SkMatrix class holds a 3x3 matrix for transforming coordinates.
26     SkMatrix does not have a constructor, so it must be explicitly initialized
27     using either reset() - to construct an identity matrix, or one of the set
28     functions (e.g. setTranslate, setRotate, etc.).
29 */
30 class SK_API SkMatrix {
31 public:
32     /** Enum of bit fields for the mask return by getType().
33         Use this to identify the complexity of the matrix.
34     */
35     enum TypeMask {
36         kIdentity_Mask      = 0,
37         kTranslate_Mask     = 0x01,  //!< set if the matrix has translation
38         kScale_Mask         = 0x02,  //!< set if the matrix has X or Y scale
39         kAffine_Mask        = 0x04,  //!< set if the matrix skews or rotates
40         kPerspective_Mask   = 0x08   //!< set if the matrix is in perspective
41     };
42
43     /** Returns a bitfield describing the transformations the matrix may
44         perform. The bitfield is computed conservatively, so it may include
45         false positives. For example, when kPerspective_Mask is true, all
46         other bits may be set to true even in the case of a pure perspective
47         transform.
48    */
49     TypeMask getType() const {
50         if (fTypeMask & kUnknown_Mask) {
51             fTypeMask = this->computeTypeMask();
52         }
53         // only return the public masks
54         return (TypeMask)(fTypeMask & 0xF);
55     }
56
57     /** Returns true if the matrix is identity.
58     */
59     bool isIdentity() const {
60         return this->getType() == 0;
61     }
62
63     bool isScaleTranslate() const {
64         return !(this->getType() & ~(kScale_Mask | kTranslate_Mask));
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/reflection 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/reflection 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         Either of the two matrices may also be the target matrix.
228         *this = a * b;
229     */
230     void setConcat(const SkMatrix& a, const SkMatrix& b);
231
232     /** Preconcats the matrix with the specified translation.
233         M' = M * T(dx, dy)
234     */
235     void preTranslate(SkScalar dx, SkScalar dy);
236     /** Preconcats the matrix with the specified scale.
237         M' = M * S(sx, sy, px, py)
238     */
239     void 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     void preScale(SkScalar sx, SkScalar sy);
244     /** Preconcats the matrix with the specified rotation.
245         M' = M * R(degrees, px, py)
246     */
247     void preRotate(SkScalar degrees, SkScalar px, SkScalar py);
248     /** Preconcats the matrix with the specified rotation.
249         M' = M * R(degrees)
250     */
251     void preRotate(SkScalar degrees);
252     /** Preconcats the matrix with the specified skew.
253         M' = M * K(kx, ky, px, py)
254     */
255     void 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     void preSkew(SkScalar kx, SkScalar ky);
260     /** Preconcats the matrix with the specified matrix.
261         M' = M * other
262     */
263     void preConcat(const SkMatrix& other);
264
265     /** Postconcats the matrix with the specified translation.
266         M' = T(dx, dy) * M
267     */
268     void postTranslate(SkScalar dx, SkScalar dy);
269     /** Postconcats the matrix with the specified scale.
270         M' = S(sx, sy, px, py) * M
271     */
272     void 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     void 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     void postRotate(SkScalar degrees, SkScalar px, SkScalar py);
285     /** Postconcats the matrix with the specified rotation.
286         M' = R(degrees) * M
287     */
288     void postRotate(SkScalar degrees);
289     /** Postconcats the matrix with the specified skew.
290         M' = K(kx, ky, px, py) * M
291     */
292     void 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     void postSkew(SkScalar kx, SkScalar ky);
297     /** Postconcats the matrix with the specified matrix.
298         M' = other * M
299     */
300     void 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 (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     friend SK_API bool operator==(const SkMatrix& a, const SkMatrix& b);
547     friend SK_API bool operator!=(const SkMatrix& a, const SkMatrix& b) {
548         return !(a == b);
549     }
550
551     enum {
552         // writeTo/readFromMemory will never return a value larger than this
553         kMaxFlattenSize = 9 * sizeof(SkScalar) + sizeof(uint32_t)
554     };
555     // return the number of bytes written, whether or not buffer is null
556     size_t writeToMemory(void* buffer) const;
557     /**
558      * Reads data from the buffer parameter
559      *
560      * @param buffer Memory to read from
561      * @param length Amount of memory available in the buffer
562      * @return number of bytes read (must be a multiple of 4) or
563      *         0 if there was not enough memory available
564      */
565     size_t readFromMemory(const void* buffer, size_t length);
566
567     void dump() const;
568     void toString(SkString*) const;
569
570     /**
571      * Calculates the minimum scaling factor of the matrix as computed from the SVD of the upper
572      * left 2x2. If the matrix has perspective -1 is returned.
573      *
574      * @return minumum scale factor
575      */
576     SkScalar getMinScale() const;
577
578     /**
579      * Calculates the maximum scaling factor of the matrix as computed from the SVD of the upper
580      * left 2x2. If the matrix has perspective -1 is returned.
581      *
582      * @return maximum scale factor
583      */
584     SkScalar getMaxScale() const;
585
586     /**
587      * Gets both the min and max scale factors. The min scale factor is scaleFactors[0] and the max
588      * is scaleFactors[1]. If the matrix has perspective false will be returned and scaleFactors
589      * will be unchanged.
590      */
591     bool getMinMaxScales(SkScalar scaleFactors[2]) const;
592
593     /**
594      *  Return a reference to a const identity matrix
595      */
596     static const SkMatrix& I();
597
598     /**
599      *  Return a reference to a const matrix that is "invalid", one that could
600      *  never be used.
601      */
602     static const SkMatrix& InvalidMatrix();
603
604     /**
605      * Return the concatenation of two matrices, a * b.
606      */
607     static SkMatrix Concat(const SkMatrix& a, const SkMatrix& b) {
608         SkMatrix result;
609         result.setConcat(a, b);
610         return result;
611     }
612
613     /**
614      * Testing routine; the matrix's type cache should never need to be
615      * manually invalidated during normal use.
616      */
617     void dirtyMatrixTypeCache() {
618         this->setTypeMask(kUnknown_Mask);
619     }
620
621 private:
622     enum {
623         /** Set if the matrix will map a rectangle to another rectangle. This
624             can be true if the matrix is scale-only, or rotates a multiple of
625             90 degrees.
626
627             This bit will be set on identity matrices
628         */
629         kRectStaysRect_Mask = 0x10,
630
631         /** Set if the perspective bit is valid even though the rest of
632             the matrix is Unknown.
633         */
634         kOnlyPerspectiveValid_Mask = 0x40,
635
636         kUnknown_Mask = 0x80,
637
638         kORableMasks =  kTranslate_Mask |
639                         kScale_Mask |
640                         kAffine_Mask |
641                         kPerspective_Mask,
642
643         kAllMasks = kTranslate_Mask |
644                     kScale_Mask |
645                     kAffine_Mask |
646                     kPerspective_Mask |
647                     kRectStaysRect_Mask
648     };
649
650     SkScalar         fMat[9];
651     mutable SkTRacy<uint32_t> fTypeMask;
652
653     void setScaleTranslate(SkScalar sx, SkScalar sy, SkScalar tx, SkScalar ty) {
654         fMat[kMScaleX] = sx;
655         fMat[kMSkewX]  = 0;
656         fMat[kMTransX] = tx;
657         
658         fMat[kMSkewY]  = 0;
659         fMat[kMScaleY] = sy;
660         fMat[kMTransY] = ty;
661         
662         fMat[kMPersp0] = 0;
663         fMat[kMPersp1] = 0;
664         fMat[kMPersp2] = 1;
665         
666         unsigned mask = 0;
667         if (sx != 1 || sy != 1) {
668             mask |= kScale_Mask;
669         }
670         if (tx || ty) {
671             mask |= kTranslate_Mask;
672         }
673         this->setTypeMask(mask | kRectStaysRect_Mask);
674     }
675
676     uint8_t computeTypeMask() const;
677     uint8_t computePerspectiveTypeMask() const;
678
679     void setTypeMask(int mask) {
680         // allow kUnknown or a valid mask
681         SkASSERT(kUnknown_Mask == mask || (mask & kAllMasks) == mask ||
682                  ((kUnknown_Mask | kOnlyPerspectiveValid_Mask) & mask)
683                  == (kUnknown_Mask | kOnlyPerspectiveValid_Mask));
684         fTypeMask = SkToU8(mask);
685     }
686
687     void orTypeMask(int mask) {
688         SkASSERT((mask & kORableMasks) == mask);
689         fTypeMask = SkToU8(fTypeMask | mask);
690     }
691
692     void clearTypeMask(int mask) {
693         // only allow a valid mask
694         SkASSERT((mask & kAllMasks) == mask);
695         fTypeMask = fTypeMask & ~mask;
696     }
697
698     TypeMask getPerspectiveTypeMaskOnly() const {
699         if ((fTypeMask & kUnknown_Mask) &&
700             !(fTypeMask & kOnlyPerspectiveValid_Mask)) {
701             fTypeMask = this->computePerspectiveTypeMask();
702         }
703         return (TypeMask)(fTypeMask & 0xF);
704     }
705
706     /** Returns true if we already know that the matrix is identity;
707         false otherwise.
708     */
709     bool isTriviallyIdentity() const {
710         if (fTypeMask & kUnknown_Mask) {
711             return false;
712         }
713         return ((fTypeMask & 0xF) == 0);
714     }
715
716     bool SK_WARN_UNUSED_RESULT invertNonIdentity(SkMatrix* inverse) const;
717
718     static bool Poly2Proc(const SkPoint[], SkMatrix*, const SkPoint& scale);
719     static bool Poly3Proc(const SkPoint[], SkMatrix*, const SkPoint& scale);
720     static bool Poly4Proc(const SkPoint[], SkMatrix*, const SkPoint& scale);
721
722     static void Identity_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
723     static void Trans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
724     static void Scale_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
725     static void ScaleTrans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
726     static void Rot_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
727     static void RotTrans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
728     static void Persp_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
729
730     static const MapXYProc gMapXYProcs[];
731
732     static void Identity_pts(const SkMatrix&, SkPoint[], const SkPoint[], int);
733     static void Trans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int);
734     static void Scale_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int);
735     static void ScaleTrans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[],
736                                int count);
737     static void Rot_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int);
738     static void RotTrans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[],
739                              int count);
740     static void Persp_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int);
741
742     static const MapPtsProc gMapPtsProcs[];
743
744     friend class SkPerspIter;
745 };
746
747 #endif