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