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