blob: 2b25dcada39459ee749d988870c1fd45e3e27f10 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
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
22class 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*/
31class SkMatrix {
32public:
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 */
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 /** 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 */
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
91 SkScalar get(int index) const {
92 SkASSERT((unsigned)index < 9);
93 return fMat[index];
94 }
95
96 SkScalar getScaleX() const { return fMat[kMScaleX]; }
97 SkScalar getScaleY() const { return fMat[kMScaleY]; }
98 SkScalar getSkewY() const { return fMat[kMSkewY]; }
99 SkScalar getSkewX() const { return fMat[kMSkewX]; }
100 SkScalar getTranslateX() const { return fMat[kMTransX]; }
101 SkScalar getTranslateY() const { return fMat[kMTransY]; }
102 SkScalar getPerspX() const { return fMat[kMPersp0]; }
103 SkScalar getPerspY() const { return fMat[kMPersp1]; }
104
105 void set(int index, SkScalar value) {
106 SkASSERT((unsigned)index < 9);
107 fMat[index] = value;
108 this->setTypeMask(kUnknown_Mask);
109 }
110
111 void setScaleX(SkScalar v) { this->set(kMScaleX, v); }
112 void setScaleY(SkScalar v) { this->set(kMScaleY, v); }
113 void setSkewY(SkScalar v) { this->set(kMSkewY, v); }
114 void setSkewX(SkScalar v) { this->set(kMSkewX, v); }
115 void setTranslateX(SkScalar v) { this->set(kMTransX, v); }
116 void setTranslateY(SkScalar v) { this->set(kMTransY, v); }
117 void setPerspX(SkScalar v) { this->set(kMPersp0, 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 */
308 void mapPoints(SkPoint pts[], int count) const {
309 this->mapPoints(pts, pts, count);
310 }
311
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 */
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 */
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
368 static MapXYProc GetMapXYProc(TypeMask mask) {
369 SkASSERT((mask & ~kAllMasks) == 0);
370 return gMapXYProcs[mask & kAllMasks];
371 }
372
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
380 static MapPtsProc GetMapPtsProc(TypeMask mask) {
381 SkASSERT((mask & ~kAllMasks) == 0);
382 return gMapPtsProcs[mask & kAllMasks];
383 }
384
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#ifdef SK_DEBUG
407 /** @cond UNIT_TEST */
408
409 static void UnitTest();
410 /** @endcond */
411#endif
412
413private:
414 enum {
415 /** Set if the matrix will map a rectangle to another rectangle. This
416 can be true if the matrix is scale-only, or rotates a multiple of
417 90 degrees. This bit is not set if the matrix is identity.
418
419 This bit will be set on identity matrices
420 */
421 kRectStaysRect_Mask = 0x10,
422
423 kUnknown_Mask = 0x80,
424
425 kAllMasks = kTranslate_Mask |
426 kScale_Mask |
427 kAffine_Mask |
428 kPerspective_Mask |
429 kRectStaysRect_Mask
430 };
431
432 SkScalar fMat[9];
433 mutable uint8_t fTypeMask;
434
435 uint8_t computeTypeMask() const;
436
437 void setTypeMask(int mask) {
438 // allow kUnknown or a valid mask
439 SkASSERT(kUnknown_Mask == mask || (mask & kAllMasks) == mask);
440 fTypeMask = SkToU8(mask);
441 }
442
443 void clearTypeMask(int mask) {
444 // only allow a valid mask
445 SkASSERT((mask & kAllMasks) == mask);
446 fTypeMask &= ~mask;
447 }
448
449 static bool Poly2Proc(const SkPoint[], SkMatrix*, const SkPoint& scale);
450 static bool Poly3Proc(const SkPoint[], SkMatrix*, const SkPoint& scale);
451 static bool Poly4Proc(const SkPoint[], SkMatrix*, const SkPoint& scale);
452
453 static void Identity_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
454 static void Trans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
455 static void Scale_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
456 static void ScaleTrans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
457 static void Rot_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
458 static void RotTrans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
459 static void Persp_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
460
461 static const MapXYProc gMapXYProcs[];
462
463 static void Identity_pts(const SkMatrix&, SkPoint[], const SkPoint[], int);
464 static void Trans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int);
465 static void Scale_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int);
466 static void ScaleTrans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[],
467 int count);
468 static void Rot_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int);
469 static void RotTrans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[],
470 int count);
471 static void Persp_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int);
472
473 static const MapPtsProc gMapPtsProcs[];
474
475 friend class SkPerspIter;
476};
477
478#endif
479