3 * Copyright 2006 The Android Open Source Project
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
10 #ifndef SkMatrix_DEFINED
11 #define SkMatrix_DEFINED
13 #include "SkDynamicAnnotations.h"
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)
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.).
30 class SK_API SkMatrix {
32 /** Enum of bit fields for the mask return by getType().
33 Use this to identify the complexity of the matrix.
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
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
49 TypeMask getType() const {
50 if (fTypeMask & kUnknown_Mask) {
51 fTypeMask = this->computeTypeMask();
53 // only return the public masks
54 return (TypeMask)(fTypeMask & 0xF);
57 /** Returns true if the matrix is identity.
59 bool isIdentity() const {
60 return this->getType() == 0;
63 bool isScaleTranslate() const {
64 return !(this->getType() & ~(kScale_Mask | kTranslate_Mask));
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
71 bool rectStaysRect() const {
72 if (fTypeMask & kUnknown_Mask) {
73 fTypeMask = this->computeTypeMask();
75 return (fTypeMask & kRectStaysRect_Mask) != 0;
77 // alias for rectStaysRect()
78 bool preservesAxisAlignment() const { return this->rectStaysRect(); }
81 * Returns true if the matrix contains perspective elements.
83 bool hasPerspective() const {
84 return SkToBool(this->getPerspectiveTypeMaskOnly() &
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
91 bool isSimilarity(SkScalar tol = SK_ScalarNearlyZero) const;
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
97 bool preservesRightAngles(SkScalar tol = SK_ScalarNearlyZero) const;
111 /** Affine arrays are in column major order
112 because that's how PDF and XPS like it.
123 SkScalar operator[](int index) const {
124 SkASSERT((unsigned)index < 9);
128 SkScalar get(int index) const {
129 SkASSERT((unsigned)index < 9);
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]; }
142 SkScalar& operator[](int index) {
143 SkASSERT((unsigned)index < 9);
144 this->setTypeMask(kUnknown_Mask);
148 void set(int index, SkScalar value) {
149 SkASSERT((unsigned)index < 9);
151 this->setTypeMask(kUnknown_Mask);
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); }
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);
178 /** Set the matrix to identity
182 void setIdentity() { this->reset(); }
184 /** Set the matrix to translate by (dx, dy).
186 void setTranslate(SkScalar dx, SkScalar dy);
187 void setTranslate(const SkVector& v) { this->setTranslate(v.fX, v.fY); }
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.
193 void setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py);
194 /** Set the matrix to scale by sx and sy.
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.
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.
205 void setRotate(SkScalar degrees, SkScalar px, SkScalar py);
206 /** Set the matrix to rotate about (0,0) by the specified number of degrees.
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.
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.
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.
222 void setSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py);
223 /** Set the matrix to skew by sx and sy.
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.
230 void setConcat(const SkMatrix& a, const SkMatrix& b);
232 /** Preconcats the matrix with the specified translation.
235 void preTranslate(SkScalar dx, SkScalar dy);
236 /** Preconcats the matrix with the specified scale.
237 M' = M * S(sx, sy, px, py)
239 void preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py);
240 /** Preconcats the matrix with the specified scale.
243 void preScale(SkScalar sx, SkScalar sy);
244 /** Preconcats the matrix with the specified rotation.
245 M' = M * R(degrees, px, py)
247 void preRotate(SkScalar degrees, SkScalar px, SkScalar py);
248 /** Preconcats the matrix with the specified rotation.
251 void preRotate(SkScalar degrees);
252 /** Preconcats the matrix with the specified skew.
253 M' = M * K(kx, ky, px, py)
255 void preSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py);
256 /** Preconcats the matrix with the specified skew.
259 void preSkew(SkScalar kx, SkScalar ky);
260 /** Preconcats the matrix with the specified matrix.
263 void preConcat(const SkMatrix& other);
265 /** Postconcats the matrix with the specified translation.
268 void postTranslate(SkScalar dx, SkScalar dy);
269 /** Postconcats the matrix with the specified scale.
270 M' = S(sx, sy, px, py) * M
272 void postScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py);
273 /** Postconcats the matrix with the specified scale.
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
280 bool postIDiv(int divx, int divy);
281 /** Postconcats the matrix with the specified rotation.
282 M' = R(degrees, px, py) * M
284 void postRotate(SkScalar degrees, SkScalar px, SkScalar py);
285 /** Postconcats the matrix with the specified rotation.
288 void postRotate(SkScalar degrees);
289 /** Postconcats the matrix with the specified skew.
290 M' = K(kx, ky, px, py) * M
292 void postSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py);
293 /** Postconcats the matrix with the specified skew.
296 void postSkew(SkScalar kx, SkScalar ky);
297 /** Postconcats the matrix with the specified matrix.
300 void postConcat(const SkMatrix& other);
304 * Scale in X and Y independently, so that src matches dst exactly.
305 * This may change the aspect ratio of the src.
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.
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.
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.
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
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.
338 bool setRectToRect(const SkRect& src, const SkRect& dst, ScaleToFit stf);
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
347 bool setPolyToPoly(const SkPoint src[], const SkPoint dst[], int count);
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
353 bool SK_WARN_UNUSED_RESULT invert(SkMatrix* inverse) const {
354 // Allow the trivial case to be inlined.
355 if (this->isIdentity()) {
361 return this->invertNonIdentity(inverse);
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.
369 static void SetAffineIdentity(SkScalar affine[6]);
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.
376 bool asAffine(SkScalar affine[6]) const;
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.
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
388 void mapPoints(SkPoint dst[], const SkPoint src[], int count) const;
390 /** Apply this matrix to the array of points, overwriting it with the
393 @param pts The points to be transformed. It must contain at least
395 @param count The number of points in pts.
397 void mapPoints(SkPoint pts[], int count) const {
398 this->mapPoints(pts, pts, count);
401 /** Like mapPoints but with custom byte stride between the points. Stride
402 * should be a multiple of sizeof(SkScalar).
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);
413 /** Like mapPoints but with custom byte stride between the points.
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);
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.
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.
437 void mapHomogeneousPoints(SkScalar dst[], const SkScalar src[], int count) const;
439 void mapXY(SkScalar x, SkScalar y, SkPoint* result) const {
441 this->getMapXYProc()(*this, x, y, result);
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
454 void mapVectors(SkVector dst[], const SkVector src[], int count) const;
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
461 @param count The number of vectors in vecs.
463 void mapVectors(SkVector vecs[], int count) const {
464 this->mapVectors(vecs, vecs, count);
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()
474 bool mapRect(SkRect* dst, const SkRect& src) const;
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()
482 bool mapRect(SkRect* rect) const {
483 return this->mapRect(rect, *rect);
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.
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.
495 this->mapPoints(dst, 4);
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.
502 SkScalar mapRadius(SkScalar radius) const;
504 typedef void (*MapXYProc)(const SkMatrix& mat, SkScalar x, SkScalar y,
507 static MapXYProc GetMapXYProc(TypeMask mask) {
508 SkASSERT((mask & ~kAllMasks) == 0);
509 return gMapXYProcs[mask & kAllMasks];
512 MapXYProc getMapXYProc() const {
513 return GetMapXYProc(this->getType());
516 typedef void (*MapPtsProc)(const SkMatrix& mat, SkPoint dst[],
517 const SkPoint src[], int count);
519 static MapPtsProc GetMapPtsProc(TypeMask mask) {
520 SkASSERT((mask & ~kAllMasks) == 0);
521 return gMapPtsProcs[mask & kAllMasks];
524 MapPtsProc getMapPtsProc() const {
525 return GetMapPtsProc(this->getType());
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.
532 bool fixedStepInX(SkScalar y, SkFixed* stepX, SkFixed* stepY) const;
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.
542 bool cheapEqualTo(const SkMatrix& m) const {
543 return 0 == memcmp(fMat, m.fMat, sizeof(fMat));
546 friend SK_API bool operator==(const SkMatrix& a, const SkMatrix& b);
547 friend SK_API bool operator!=(const SkMatrix& a, const SkMatrix& b) {
552 // writeTo/readFromMemory will never return a value larger than this
553 kMaxFlattenSize = 9 * sizeof(SkScalar) + sizeof(uint32_t)
555 // return the number of bytes written, whether or not buffer is null
556 size_t writeToMemory(void* buffer) const;
558 * Reads data from the buffer parameter
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
565 size_t readFromMemory(const void* buffer, size_t length);
568 void toString(SkString*) const;
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.
574 * @return minumum scale factor
576 SkScalar getMinScale() const;
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.
582 * @return maximum scale factor
584 SkScalar getMaxScale() const;
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
591 bool getMinMaxScales(SkScalar scaleFactors[2]) const;
594 * Return a reference to a const identity matrix
596 static const SkMatrix& I();
599 * Return a reference to a const matrix that is "invalid", one that could
602 static const SkMatrix& InvalidMatrix();
605 * Return the concatenation of two matrices, a * b.
607 static SkMatrix Concat(const SkMatrix& a, const SkMatrix& b) {
609 result.setConcat(a, b);
614 * Testing routine; the matrix's type cache should never need to be
615 * manually invalidated during normal use.
617 void dirtyMatrixTypeCache() {
618 this->setTypeMask(kUnknown_Mask);
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
627 This bit will be set on identity matrices
629 kRectStaysRect_Mask = 0x10,
631 /** Set if the perspective bit is valid even though the rest of
632 the matrix is Unknown.
634 kOnlyPerspectiveValid_Mask = 0x40,
636 kUnknown_Mask = 0x80,
638 kORableMasks = kTranslate_Mask |
643 kAllMasks = kTranslate_Mask |
651 mutable SkTRacy<uint32_t> fTypeMask;
653 void setScaleTranslate(SkScalar sx, SkScalar sy, SkScalar tx, SkScalar ty) {
667 if (sx != 1 || sy != 1) {
671 mask |= kTranslate_Mask;
673 this->setTypeMask(mask | kRectStaysRect_Mask);
676 uint8_t computeTypeMask() const;
677 uint8_t computePerspectiveTypeMask() const;
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);
687 void orTypeMask(int mask) {
688 SkASSERT((mask & kORableMasks) == mask);
689 fTypeMask = SkToU8(fTypeMask | mask);
692 void clearTypeMask(int mask) {
693 // only allow a valid mask
694 SkASSERT((mask & kAllMasks) == mask);
695 fTypeMask = fTypeMask & ~mask;
698 TypeMask getPerspectiveTypeMaskOnly() const {
699 if ((fTypeMask & kUnknown_Mask) &&
700 !(fTypeMask & kOnlyPerspectiveValid_Mask)) {
701 fTypeMask = this->computePerspectiveTypeMask();
703 return (TypeMask)(fTypeMask & 0xF);
706 /** Returns true if we already know that the matrix is identity;
709 bool isTriviallyIdentity() const {
710 if (fTypeMask & kUnknown_Mask) {
713 return ((fTypeMask & 0xF) == 0);
716 bool SK_WARN_UNUSED_RESULT invertNonIdentity(SkMatrix* inverse) const;
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);
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*);
730 static const MapXYProc gMapXYProcs[];
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[],
737 static void Rot_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int);
738 static void RotTrans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[],
740 static void Persp_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int);
742 static const MapPtsProc gMapPtsProcs[];
744 friend class SkPerspIter;