• 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 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 
74     enum {
75         kMScaleX,
76         kMSkewX,
77         kMTransX,
78         kMSkewY,
79         kMScaleY,
80         kMTransY,
81         kMPersp0,
82         kMPersp1,
83         kMPersp2
84     };
85 
86     SkScalar operator[](int index) const {
87         SkASSERT((unsigned)index < 9);
88         return fMat[index];
89     }
90 
get(int index)91     SkScalar get(int index) const {
92         SkASSERT((unsigned)index < 9);
93         return fMat[index];
94     }
95 
getScaleX()96     SkScalar getScaleX() const { return fMat[kMScaleX]; }
getScaleY()97     SkScalar getScaleY() const { return fMat[kMScaleY]; }
getSkewY()98     SkScalar getSkewY() const { return fMat[kMSkewY]; }
getSkewX()99     SkScalar getSkewX() const { return fMat[kMSkewX]; }
getTranslateX()100     SkScalar getTranslateX() const { return fMat[kMTransX]; }
getTranslateY()101     SkScalar getTranslateY() const { return fMat[kMTransY]; }
getPerspX()102     SkScalar getPerspX() const { return fMat[kMPersp0]; }
getPerspY()103     SkScalar getPerspY() const { return fMat[kMPersp1]; }
104 
105     SkScalar& operator[](int index) {
106         SkASSERT((unsigned)index < 9);
107         this->setTypeMask(kUnknown_Mask);
108         return fMat[index];
109     }
110 
set(int index,SkScalar value)111     void set(int index, SkScalar value) {
112         SkASSERT((unsigned)index < 9);
113         fMat[index] = value;
114         this->setTypeMask(kUnknown_Mask);
115     }
116 
setScaleX(SkScalar v)117     void setScaleX(SkScalar v) { this->set(kMScaleX, v); }
setScaleY(SkScalar v)118     void setScaleY(SkScalar v) { this->set(kMScaleY, v); }
setSkewY(SkScalar v)119     void setSkewY(SkScalar v) { this->set(kMSkewY, v); }
setSkewX(SkScalar v)120     void setSkewX(SkScalar v) { this->set(kMSkewX, v); }
setTranslateX(SkScalar v)121     void setTranslateX(SkScalar v) { this->set(kMTransX, v); }
setTranslateY(SkScalar v)122     void setTranslateY(SkScalar v) { this->set(kMTransY, v); }
setPerspX(SkScalar v)123     void setPerspX(SkScalar v) { this->set(kMPersp0, v); }
setPerspY(SkScalar v)124     void setPerspY(SkScalar v) { this->set(kMPersp1, v); }
125 
126     /** Set the matrix to identity
127     */
128     void reset();
129 
130     /** Set the matrix to translate by (dx, dy).
131     */
132     void setTranslate(SkScalar dx, SkScalar dy);
133     /** Set the matrix to scale by sx and sy, with a pivot point at (px, py).
134         The pivot point is the coordinate that should remain unchanged by the
135         specified transformation.
136     */
137     void setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py);
138     /** Set the matrix to scale by sx and sy.
139     */
140     void setScale(SkScalar sx, SkScalar sy);
141     /** Set the matrix to rotate by the specified number of degrees, with a
142         pivot point at (px, py). The pivot point is the coordinate that should
143         remain unchanged by the specified transformation.
144     */
145     void setRotate(SkScalar degrees, SkScalar px, SkScalar py);
146     /** Set the matrix to rotate about (0,0) by the specified number of degrees.
147     */
148     void setRotate(SkScalar degrees);
149     /** Set the matrix to rotate by the specified sine and cosine values, with
150         a pivot point at (px, py). The pivot point is the coordinate that
151         should remain unchanged by the specified transformation.
152     */
153     void setSinCos(SkScalar sinValue, SkScalar cosValue,
154                    SkScalar px, SkScalar py);
155     /** Set the matrix to rotate by the specified sine and cosine values.
156     */
157     void setSinCos(SkScalar sinValue, SkScalar cosValue);
158     /** Set the matrix to skew by sx and sy, with a pivot point at (px, py).
159         The pivot point is the coordinate that should remain unchanged by the
160         specified transformation.
161     */
162     void setSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py);
163     /** Set the matrix to skew by sx and sy.
164     */
165     void setSkew(SkScalar kx, SkScalar ky);
166     /** Set the matrix to the concatenation of the two specified matrices,
167         returning true if the the result can be represented. Either of the
168         two matrices may also be the target matrix. *this = a * b;
169     */
170     bool setConcat(const SkMatrix& a, const SkMatrix& b);
171 
172     /** Preconcats the matrix with the specified translation.
173         M' = M * T(dx, dy)
174     */
175     bool preTranslate(SkScalar dx, SkScalar dy);
176     /** Preconcats the matrix with the specified scale.
177         M' = M * S(sx, sy, px, py)
178     */
179     bool preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py);
180     /** Preconcats the matrix with the specified scale.
181         M' = M * S(sx, sy)
182     */
183     bool preScale(SkScalar sx, SkScalar sy);
184     /** Preconcats the matrix with the specified rotation.
185         M' = M * R(degrees, px, py)
186     */
187     bool preRotate(SkScalar degrees, SkScalar px, SkScalar py);
188     /** Preconcats the matrix with the specified rotation.
189         M' = M * R(degrees)
190     */
191     bool preRotate(SkScalar degrees);
192     /** Preconcats the matrix with the specified skew.
193         M' = M * K(kx, ky, px, py)
194     */
195     bool preSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py);
196     /** Preconcats the matrix with the specified skew.
197         M' = M * K(kx, ky)
198     */
199     bool preSkew(SkScalar kx, SkScalar ky);
200     /** Preconcats the matrix with the specified matrix.
201         M' = M * other
202     */
203     bool preConcat(const SkMatrix& other);
204 
205     /** Postconcats the matrix with the specified translation.
206         M' = T(dx, dy) * M
207     */
208     bool postTranslate(SkScalar dx, SkScalar dy);
209     /** Postconcats the matrix with the specified scale.
210         M' = S(sx, sy, px, py) * M
211     */
212     bool postScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py);
213     /** Postconcats the matrix with the specified scale.
214         M' = S(sx, sy) * M
215     */
216     bool postScale(SkScalar sx, SkScalar sy);
217     /** Postconcats the matrix by dividing it by the specified integers.
218         M' = S(1/divx, 1/divy, 0, 0) * M
219     */
220     bool postIDiv(int divx, int divy);
221     /** Postconcats the matrix with the specified rotation.
222         M' = R(degrees, px, py) * M
223     */
224     bool postRotate(SkScalar degrees, SkScalar px, SkScalar py);
225     /** Postconcats the matrix with the specified rotation.
226         M' = R(degrees) * M
227     */
228     bool postRotate(SkScalar degrees);
229     /** Postconcats the matrix with the specified skew.
230         M' = K(kx, ky, px, py) * M
231     */
232     bool postSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py);
233     /** Postconcats the matrix with the specified skew.
234         M' = K(kx, ky) * M
235     */
236     bool postSkew(SkScalar kx, SkScalar ky);
237     /** Postconcats the matrix with the specified matrix.
238         M' = other * M
239     */
240     bool postConcat(const SkMatrix& other);
241 
242     enum ScaleToFit {
243         /**
244          * Scale in X and Y independently, so that src matches dst exactly.
245          * This may change the aspect ratio of the src.
246          */
247         kFill_ScaleToFit,
248         /**
249          * Compute a scale that will maintain the original src aspect ratio,
250          * but will also ensure that src fits entirely inside dst. At least one
251          * axis (X or Y) will fit exactly. kStart aligns the result to the
252          * left and top edges of dst.
253          */
254         kStart_ScaleToFit,
255         /**
256          * Compute a scale that will maintain the original src aspect ratio,
257          * but will also ensure that src fits entirely inside dst. At least one
258          * axis (X or Y) will fit exactly. The result is centered inside dst.
259          */
260         kCenter_ScaleToFit,
261         /**
262          * Compute a scale that will maintain the original src aspect ratio,
263          * but will also ensure that src fits entirely inside dst. At least one
264          * axis (X or Y) will fit exactly. kEnd aligns the result to the
265          * right and bottom edges of dst.
266          */
267         kEnd_ScaleToFit
268     };
269 
270     /** Set the matrix to the scale and translate values that map the source
271         rectangle to the destination rectangle, returning true if the the result
272         can be represented.
273         @param src the source rectangle to map from.
274         @param dst the destination rectangle to map to.
275         @param stf the ScaleToFit option
276         @return true if the matrix can be represented by the rectangle mapping.
277     */
278     bool setRectToRect(const SkRect& src, const SkRect& dst, ScaleToFit stf);
279 
280     /** Set the matrix such that the specified src points would map to the
281         specified dst points. count must be within [0..4].
282         @param src  The array of src points
283         @param dst  The array of dst points
284         @param count The number of points to use for the transformation
285         @return true if the matrix was set to the specified transformation
286     */
287     bool setPolyToPoly(const SkPoint src[], const SkPoint dst[], int count);
288 
289     /** If this matrix can be inverted, return true and if inverse is not null,
290         set inverse to be the inverse of this matrix. If this matrix cannot be
291         inverted, ignore inverse and return false
292     */
293     bool invert(SkMatrix* inverse) const;
294 
295     /** Apply this matrix to the array of points specified by src, and write
296         the transformed points into the array of points specified by dst.
297         dst[] = M * src[]
298         @param dst  Where the transformed coordinates are written. It must
299                     contain at least count entries
300         @param src  The original coordinates that are to be transformed. It
301                     must contain at least count entries
302         @param count The number of points in src to read, and then transform
303                      into dst.
304     */
305     void mapPoints(SkPoint dst[], const SkPoint src[], int count) const;
306 
307     /** Apply this matrix to the array of points, overwriting it with the
308         transformed values.
309         dst[] = M * pts[]
310         @param pts  The points to be transformed. It must contain at least
311                     count entries
312         @param count The number of points in pts.
313     */
mapPoints(SkPoint pts[],int count)314     void mapPoints(SkPoint pts[], int count) const {
315         this->mapPoints(pts, pts, count);
316     }
317 
mapXY(SkScalar x,SkScalar y,SkPoint * result)318     void mapXY(SkScalar x, SkScalar y, SkPoint* result) const {
319         SkASSERT(result);
320         this->getMapXYProc()(*this, x, y, result);
321     }
322 
323     /** Apply this matrix to the array of vectors specified by src, and write
324         the transformed vectors into the array of vectors specified by dst.
325         This is similar to mapPoints, but ignores any translation in the matrix.
326         @param dst  Where the transformed coordinates are written. It must
327                     contain at least count entries
328         @param src  The original coordinates that are to be transformed. It
329                     must contain at least count entries
330         @param count The number of vectors in src to read, and then transform
331                      into dst.
332     */
333     void mapVectors(SkVector dst[], const SkVector src[], int count) const;
334 
335     /** Apply this matrix to the array of vectors specified by src, and write
336         the transformed vectors into the array of vectors specified by dst.
337         This is similar to mapPoints, but ignores any translation in the matrix.
338         @param vecs The vectors to be transformed. It must contain at least
339                     count entries
340         @param count The number of vectors in vecs.
341     */
mapVectors(SkVector vecs[],int count)342     void mapVectors(SkVector vecs[], int count) const {
343         this->mapVectors(vecs, vecs, count);
344     }
345 
346     /** Apply this matrix to the src rectangle, and write the transformed
347         rectangle into dst. This is accomplished by transforming the 4 corners
348         of src, and then setting dst to the bounds of those points.
349         @param dst  Where the transformed rectangle is written.
350         @param src  The original rectangle to be transformed.
351         @return the result of calling rectStaysRect()
352     */
353     bool mapRect(SkRect* dst, const SkRect& src) const;
354 
355     /** Apply this matrix to the rectangle, and write the transformed rectangle
356         back into it. This is accomplished by transforming the 4 corners of
357         rect, and then setting it to the bounds of those points
358         @param rect The rectangle to transform.
359         @return the result of calling rectStaysRect()
360     */
mapRect(SkRect * rect)361     bool mapRect(SkRect* rect) const {
362         return this->mapRect(rect, *rect);
363     }
364 
365     /** Return the mean radius of a circle after it has been mapped by
366         this matrix. NOTE: in perspective this value assumes the circle
367         has its center at the origin.
368     */
369     SkScalar mapRadius(SkScalar radius) const;
370 
371     typedef void (*MapXYProc)(const SkMatrix& mat, SkScalar x, SkScalar y,
372                                  SkPoint* result);
373 
GetMapXYProc(TypeMask mask)374     static MapXYProc GetMapXYProc(TypeMask mask) {
375         SkASSERT((mask & ~kAllMasks) == 0);
376         return gMapXYProcs[mask & kAllMasks];
377     }
378 
getMapXYProc()379     MapXYProc getMapXYProc() const {
380         return GetMapXYProc(this->getType());
381     }
382 
383     typedef void (*MapPtsProc)(const SkMatrix& mat, SkPoint dst[],
384                                   const SkPoint src[], int count);
385 
GetMapPtsProc(TypeMask mask)386     static MapPtsProc GetMapPtsProc(TypeMask mask) {
387         SkASSERT((mask & ~kAllMasks) == 0);
388         return gMapPtsProcs[mask & kAllMasks];
389     }
390 
getMapPtsProc()391     MapPtsProc getMapPtsProc() const {
392         return GetMapPtsProc(this->getType());
393     }
394 
395     /** If the matrix can be stepped in X (not complex perspective)
396         then return true and if step[XY] is not null, return the step[XY] value.
397         If it cannot, return false and ignore step.
398     */
399     bool fixedStepInX(SkScalar y, SkFixed* stepX, SkFixed* stepY) const;
400 
401     friend bool operator==(const SkMatrix& a, const SkMatrix& b) {
402         return memcmp(a.fMat, b.fMat, sizeof(a.fMat)) == 0;
403     }
404 
405     friend bool operator!=(const SkMatrix& a, const SkMatrix& b) {
406         return memcmp(a.fMat, b.fMat, sizeof(a.fMat)) != 0;
407     }
408 
409     enum {
410         // flatten/unflatten will never return a value larger than this
411         kMaxFlattenSize = 9 * sizeof(SkScalar) + sizeof(uint32_t)
412     };
413     // return the number of bytes written, whether or not buffer is null
414     uint32_t flatten(void* buffer) const;
415     // return the number of bytes read
416     uint32_t unflatten(const void* buffer);
417 
418     void dump() const;
419     void toDumpString(SkString*) const;
420 
421 private:
422     enum {
423         /** Set if the matrix will map a rectangle to another rectangle. This
424             can be true if the matrix is scale-only, or rotates a multiple of
425             90 degrees. This bit is not set if the matrix is identity.
426 
427             This bit will be set on identity matrices
428         */
429         kRectStaysRect_Mask = 0x10,
430 
431         kUnknown_Mask = 0x80,
432 
433         kAllMasks = kTranslate_Mask |
434                     kScale_Mask |
435                     kAffine_Mask |
436                     kPerspective_Mask |
437                     kRectStaysRect_Mask
438     };
439 
440     SkScalar        fMat[9];
441     mutable uint8_t fTypeMask;
442 
443     uint8_t computeTypeMask() const;
444 
setTypeMask(int mask)445     void setTypeMask(int mask) {
446         // allow kUnknown or a valid mask
447         SkASSERT(kUnknown_Mask == mask || (mask & kAllMasks) == mask);
448         fTypeMask = SkToU8(mask);
449     }
450 
clearTypeMask(int mask)451     void clearTypeMask(int mask) {
452         // only allow a valid mask
453         SkASSERT((mask & kAllMasks) == mask);
454         fTypeMask &= ~mask;
455     }
456 
457     static bool Poly2Proc(const SkPoint[], SkMatrix*, const SkPoint& scale);
458     static bool Poly3Proc(const SkPoint[], SkMatrix*, const SkPoint& scale);
459     static bool Poly4Proc(const SkPoint[], SkMatrix*, const SkPoint& scale);
460 
461     static void Identity_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
462     static void Trans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
463     static void Scale_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
464     static void ScaleTrans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
465     static void Rot_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
466     static void RotTrans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
467     static void Persp_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
468 
469     static const MapXYProc gMapXYProcs[];
470 
471     static void Identity_pts(const SkMatrix&, SkPoint[], const SkPoint[], int);
472     static void Trans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int);
473     static void Scale_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int);
474     static void ScaleTrans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[],
475                                int count);
476     static void Rot_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int);
477     static void RotTrans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[],
478                              int count);
479     static void Persp_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int);
480 
481     static const MapPtsProc gMapPtsProcs[];
482 
483     friend class SkPerspIter;
484 };
485 
486 #endif
487 
488