Skia
2DGraphicsLibrary
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
SkMatrix.h
1 
2 /*
3  * Copyright 2006 The Android Open Source Project
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8 
9 
10 #ifndef SkMatrix_DEFINED
11 #define SkMatrix_DEFINED
12 
13 #include "SkRect.h"
14 
15 struct SkRSXform;
16 class SkString;
17 
27 SK_BEGIN_REQUIRE_DENSE
28 class SK_API SkMatrix {
29 public:
30  static SkMatrix SK_WARN_UNUSED_RESULT MakeScale(SkScalar sx, SkScalar sy) {
31  SkMatrix m;
32  m.setScale(sx, sy);
33  return m;
34  }
35 
36  static SkMatrix SK_WARN_UNUSED_RESULT MakeScale(SkScalar scale) {
37  SkMatrix m;
38  m.setScale(scale, scale);
39  return m;
40  }
41 
42  static SkMatrix SK_WARN_UNUSED_RESULT MakeTrans(SkScalar dx, SkScalar dy) {
43  SkMatrix m;
44  m.setTranslate(dx, dy);
45  return m;
46  }
47 
51  enum TypeMask {
52  kIdentity_Mask = 0,
53  kTranslate_Mask = 0x01,
54  kScale_Mask = 0x02,
55  kAffine_Mask = 0x04,
56  kPerspective_Mask = 0x08
57  };
58 
65  TypeMask getType() const {
66  if (fTypeMask & kUnknown_Mask) {
67  fTypeMask = this->computeTypeMask();
68  }
69  // only return the public masks
70  return (TypeMask)(fTypeMask & 0xF);
71  }
72 
75  bool isIdentity() const {
76  return this->getType() == 0;
77  }
78 
79  bool isScaleTranslate() const {
80  return !(this->getType() & ~(kScale_Mask | kTranslate_Mask));
81  }
82 
87  bool rectStaysRect() const {
88  if (fTypeMask & kUnknown_Mask) {
89  fTypeMask = this->computeTypeMask();
90  }
91  return (fTypeMask & kRectStaysRect_Mask) != 0;
92  }
93  // alias for rectStaysRect()
94  bool preservesAxisAlignment() const { return this->rectStaysRect(); }
95 
99  bool hasPerspective() const {
100  return SkToBool(this->getPerspectiveTypeMaskOnly() &
101  kPerspective_Mask);
102  }
103 
107  bool isSimilarity(SkScalar tol = SK_ScalarNearlyZero) const;
108 
113  bool preservesRightAngles(SkScalar tol = SK_ScalarNearlyZero) const;
114 
115  enum {
116  kMScaleX,
117  kMSkewX,
118  kMTransX,
119  kMSkewY,
120  kMScaleY,
121  kMTransY,
122  kMPersp0,
123  kMPersp1,
124  kMPersp2
125  };
126 
130  enum {
131  kAScaleX,
132  kASkewY,
133  kASkewX,
134  kAScaleY,
135  kATransX,
136  kATransY
137  };
138 
139  SkScalar operator[](int index) const {
140  SkASSERT((unsigned)index < 9);
141  return fMat[index];
142  }
143 
144  SkScalar get(int index) const {
145  SkASSERT((unsigned)index < 9);
146  return fMat[index];
147  }
148 
149  SkScalar getScaleX() const { return fMat[kMScaleX]; }
150  SkScalar getScaleY() const { return fMat[kMScaleY]; }
151  SkScalar getSkewY() const { return fMat[kMSkewY]; }
152  SkScalar getSkewX() const { return fMat[kMSkewX]; }
153  SkScalar getTranslateX() const { return fMat[kMTransX]; }
154  SkScalar getTranslateY() const { return fMat[kMTransY]; }
155  SkScalar getPerspX() const { return fMat[kMPersp0]; }
156  SkScalar getPerspY() const { return fMat[kMPersp1]; }
157 
158  SkScalar& operator[](int index) {
159  SkASSERT((unsigned)index < 9);
160  this->setTypeMask(kUnknown_Mask);
161  return fMat[index];
162  }
163 
164  void set(int index, SkScalar value) {
165  SkASSERT((unsigned)index < 9);
166  fMat[index] = value;
167  this->setTypeMask(kUnknown_Mask);
168  }
169 
170  void setScaleX(SkScalar v) { this->set(kMScaleX, v); }
171  void setScaleY(SkScalar v) { this->set(kMScaleY, v); }
172  void setSkewY(SkScalar v) { this->set(kMSkewY, v); }
173  void setSkewX(SkScalar v) { this->set(kMSkewX, v); }
174  void setTranslateX(SkScalar v) { this->set(kMTransX, v); }
175  void setTranslateY(SkScalar v) { this->set(kMTransY, v); }
176  void setPerspX(SkScalar v) { this->set(kMPersp0, v); }
177  void setPerspY(SkScalar v) { this->set(kMPersp1, v); }
178 
179  void setAll(SkScalar scaleX, SkScalar skewX, SkScalar transX,
180  SkScalar skewY, SkScalar scaleY, SkScalar transY,
181  SkScalar persp0, SkScalar persp1, SkScalar persp2) {
182  fMat[kMScaleX] = scaleX;
183  fMat[kMSkewX] = skewX;
184  fMat[kMTransX] = transX;
185  fMat[kMSkewY] = skewY;
186  fMat[kMScaleY] = scaleY;
187  fMat[kMTransY] = transY;
188  fMat[kMPersp0] = persp0;
189  fMat[kMPersp1] = persp1;
190  fMat[kMPersp2] = persp2;
191  this->setTypeMask(kUnknown_Mask);
192  }
193 
198  void get9(SkScalar buffer[9]) const {
199  memcpy(buffer, fMat, 9 * sizeof(SkScalar));
200  }
201 
209  void set9(const SkScalar buffer[9]);
210 
213  void reset();
214  // alias for reset()
215  void setIdentity() { this->reset(); }
216 
219  void setTranslate(SkScalar dx, SkScalar dy);
220  void setTranslate(const SkVector& v) { this->setTranslate(v.fX, v.fY); }
221 
226  void setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py);
229  void setScale(SkScalar sx, SkScalar sy);
233  bool setIDiv(int divx, int divy);
238  void setRotate(SkScalar degrees, SkScalar px, SkScalar py);
241  void setRotate(SkScalar degrees);
246  void setSinCos(SkScalar sinValue, SkScalar cosValue,
247  SkScalar px, SkScalar py);
250  void setSinCos(SkScalar sinValue, SkScalar cosValue);
251 
252  SkMatrix& setRSXform(const SkRSXform&);
253 
258  void setSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py);
261  void setSkew(SkScalar kx, SkScalar ky);
266  void setConcat(const SkMatrix& a, const SkMatrix& b);
267 
271  void preTranslate(SkScalar dx, SkScalar dy);
275  void preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py);
279  void preScale(SkScalar sx, SkScalar sy);
283  void preRotate(SkScalar degrees, SkScalar px, SkScalar py);
287  void preRotate(SkScalar degrees);
291  void preSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py);
295  void preSkew(SkScalar kx, SkScalar ky);
299  void preConcat(const SkMatrix& other);
300 
304  void postTranslate(SkScalar dx, SkScalar dy);
308  void postScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py);
312  void postScale(SkScalar sx, SkScalar sy);
316  bool postIDiv(int divx, int divy);
320  void postRotate(SkScalar degrees, SkScalar px, SkScalar py);
324  void postRotate(SkScalar degrees);
328  void postSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py);
332  void postSkew(SkScalar kx, SkScalar ky);
336  void postConcat(const SkMatrix& other);
337 
338  enum ScaleToFit {
363  kEnd_ScaleToFit
364  };
365 
374  bool setRectToRect(const SkRect& src, const SkRect& dst, ScaleToFit stf);
375  static SkMatrix MakeRectToRect(const SkRect& src, const SkRect& dst, ScaleToFit stf) {
376  SkMatrix m;
377  m.setRectToRect(src, dst, stf);
378  return m;
379  }
380 
388  bool setPolyToPoly(const SkPoint src[], const SkPoint dst[], int count);
389 
394  bool SK_WARN_UNUSED_RESULT invert(SkMatrix* inverse) const {
395  // Allow the trivial case to be inlined.
396  if (this->isIdentity()) {
397  if (inverse) {
398  inverse->reset();
399  }
400  return true;
401  }
402  return this->invertNonIdentity(inverse);
403  }
404 
410  static void SetAffineIdentity(SkScalar affine[6]);
411 
417  bool SK_WARN_UNUSED_RESULT asAffine(SkScalar affine[6]) const;
418 
422  void setAffine(const SkScalar affine[6]);
423 
434  void mapPoints(SkPoint dst[], const SkPoint src[], int count) const {
435  SkASSERT((dst && src && count > 0) || 0 == count);
436  // no partial overlap
437  SkASSERT(src == dst || &dst[count] <= &src[0] || &src[count] <= &dst[0]);
438  this->getMapPtsProc()(*this, dst, src, count);
439  }
440 
448  void mapPoints(SkPoint pts[], int count) const {
449  this->mapPoints(pts, pts, count);
450  }
451 
455  void mapPointsWithStride(SkPoint pts[], size_t stride, int count) const {
456  SkASSERT(stride >= sizeof(SkPoint));
457  SkASSERT(0 == stride % sizeof(SkScalar));
458  for (int i = 0; i < count; ++i) {
459  this->mapPoints(pts, pts, 1);
460  pts = (SkPoint*)((intptr_t)pts + stride);
461  }
462  }
463 
466  void mapPointsWithStride(SkPoint dst[], const SkPoint src[], size_t stride, int count) const {
467  SkASSERT(stride >= sizeof(SkPoint));
468  SkASSERT(0 == stride % sizeof(SkScalar));
469  for (int i = 0; i < count; ++i) {
470  this->mapPoints(dst, src, 1);
471  src = (SkPoint*)((intptr_t)src + stride);
472  dst = (SkPoint*)((intptr_t)dst + stride);
473  }
474  }
475 
487  void mapHomogeneousPoints(SkScalar dst[], const SkScalar src[], int count) const;
488 
489  void mapXY(SkScalar x, SkScalar y, SkPoint* result) const {
490  SkASSERT(result);
491  this->getMapXYProc()(*this, x, y, result);
492  }
493 
494  SkPoint mapXY(SkScalar x, SkScalar y) const {
495  SkPoint result;
496  this->getMapXYProc()(*this, x, y, &result);
497  return result;
498  }
499 
510  void mapVectors(SkVector dst[], const SkVector src[], int count) const;
511 
519  void mapVectors(SkVector vecs[], int count) const {
520  this->mapVectors(vecs, vecs, count);
521  }
522 
523  void mapVector(SkScalar dx, SkScalar dy, SkVector* result) const {
524  SkVector vec = { dx, dy };
525  this->mapVectors(result, &vec, 1);
526  }
527 
528  SkVector mapVector(SkScalar dx, SkScalar dy) const {
529  SkVector vec = { dx, dy };
530  this->mapVectors(&vec, &vec, 1);
531  return vec;
532  }
533 
541  bool mapRect(SkRect* dst, const SkRect& src) const;
542 
549  bool mapRect(SkRect* rect) const {
550  return this->mapRect(rect, *rect);
551  }
552 
559  void mapRectToQuad(SkPoint dst[4], const SkRect& rect) const {
560  // This could potentially be faster if we only transformed each x and y of the rect once.
561  rect.toQuad(dst);
562  this->mapPoints(dst, 4);
563  }
564 
569  void mapRectScaleTranslate(SkRect* dst, const SkRect& src) const;
570 
575  SkScalar mapRadius(SkScalar radius) const;
576 
577  typedef void (*MapXYProc)(const SkMatrix& mat, SkScalar x, SkScalar y,
578  SkPoint* result);
579 
580  static MapXYProc GetMapXYProc(TypeMask mask) {
581  SkASSERT((mask & ~kAllMasks) == 0);
582  return gMapXYProcs[mask & kAllMasks];
583  }
584 
585  MapXYProc getMapXYProc() const {
586  return GetMapXYProc(this->getType());
587  }
588 
589  typedef void (*MapPtsProc)(const SkMatrix& mat, SkPoint dst[],
590  const SkPoint src[], int count);
591 
592  static MapPtsProc GetMapPtsProc(TypeMask mask) {
593  SkASSERT((mask & ~kAllMasks) == 0);
594  return gMapPtsProcs[mask & kAllMasks];
595  }
596 
597  MapPtsProc getMapPtsProc() const {
598  return GetMapPtsProc(this->getType());
599  }
600 
604  bool isFixedStepInX() const;
605 
610  SkVector fixedStepInX(SkScalar y) const;
611 
620  bool cheapEqualTo(const SkMatrix& m) const {
621  return 0 == memcmp(fMat, m.fMat, sizeof(fMat));
622  }
623 
624  // mac chromium dbg requires SK_API to make operator== visible
625  friend SK_API bool operator==(const SkMatrix& a, const SkMatrix& b);
626  friend SK_API bool operator!=(const SkMatrix& a, const SkMatrix& b) {
627  return !(a == b);
628  }
629 
630  enum {
631  // writeTo/readFromMemory will never return a value larger than this
632  kMaxFlattenSize = 9 * sizeof(SkScalar) + sizeof(uint32_t)
633  };
634  // return the number of bytes written, whether or not buffer is null
635  size_t writeToMemory(void* buffer) const;
644  size_t readFromMemory(const void* buffer, size_t length);
645 
646  void dump() const;
647  void toString(SkString*) const;
648 
656  SkScalar getMinScale() const;
657 
665  SkScalar getMaxScale() const;
666 
672  bool SK_WARN_UNUSED_RESULT getMinMaxScales(SkScalar scaleFactors[2]) const;
673 
685  bool decomposeScale(SkSize* scale, SkMatrix* remaining = NULL) const;
686 
690  static const SkMatrix& I();
691 
696  static const SkMatrix& InvalidMatrix();
697 
701  static SkMatrix Concat(const SkMatrix& a, const SkMatrix& b) {
702  SkMatrix result;
703  result.setConcat(a, b);
704  return result;
705  }
706 
712  this->setTypeMask(kUnknown_Mask);
713  }
714 
718  void setScaleTranslate(SkScalar sx, SkScalar sy, SkScalar tx, SkScalar ty) {
719  fMat[kMScaleX] = sx;
720  fMat[kMSkewX] = 0;
721  fMat[kMTransX] = tx;
722 
723  fMat[kMSkewY] = 0;
724  fMat[kMScaleY] = sy;
725  fMat[kMTransY] = ty;
726 
727  fMat[kMPersp0] = 0;
728  fMat[kMPersp1] = 0;
729  fMat[kMPersp2] = 1;
730 
731  unsigned mask = 0;
732  if (sx != 1 || sy != 1) {
733  mask |= kScale_Mask;
734  }
735  if (tx || ty) {
736  mask |= kTranslate_Mask;
737  }
738  this->setTypeMask(mask | kRectStaysRect_Mask);
739  }
740 
744  bool isFinite() const { return SkScalarsAreFinite(fMat, 9); }
745 
746 private:
747  enum {
754  kRectStaysRect_Mask = 0x10,
755 
759  kOnlyPerspectiveValid_Mask = 0x40,
760 
761  kUnknown_Mask = 0x80,
762 
763  kORableMasks = kTranslate_Mask |
764  kScale_Mask |
765  kAffine_Mask |
766  kPerspective_Mask,
767 
768  kAllMasks = kTranslate_Mask |
769  kScale_Mask |
770  kAffine_Mask |
771  kPerspective_Mask |
772  kRectStaysRect_Mask
773  };
774 
775  SkScalar fMat[9];
776  mutable uint32_t fTypeMask;
777 
778  static void ComputeInv(SkScalar dst[9], const SkScalar src[9], double invDet, bool isPersp);
779 
780  uint8_t computeTypeMask() const;
781  uint8_t computePerspectiveTypeMask() const;
782 
783  void setTypeMask(int mask) {
784  // allow kUnknown or a valid mask
785  SkASSERT(kUnknown_Mask == mask || (mask & kAllMasks) == mask ||
786  ((kUnknown_Mask | kOnlyPerspectiveValid_Mask) & mask)
787  == (kUnknown_Mask | kOnlyPerspectiveValid_Mask));
788  fTypeMask = SkToU8(mask);
789  }
790 
791  void orTypeMask(int mask) {
792  SkASSERT((mask & kORableMasks) == mask);
793  fTypeMask = SkToU8(fTypeMask | mask);
794  }
795 
796  void clearTypeMask(int mask) {
797  // only allow a valid mask
798  SkASSERT((mask & kAllMasks) == mask);
799  fTypeMask = fTypeMask & ~mask;
800  }
801 
802  TypeMask getPerspectiveTypeMaskOnly() const {
803  if ((fTypeMask & kUnknown_Mask) &&
804  !(fTypeMask & kOnlyPerspectiveValid_Mask)) {
805  fTypeMask = this->computePerspectiveTypeMask();
806  }
807  return (TypeMask)(fTypeMask & 0xF);
808  }
809 
813  bool isTriviallyIdentity() const {
814  if (fTypeMask & kUnknown_Mask) {
815  return false;
816  }
817  return ((fTypeMask & 0xF) == 0);
818  }
819 
820  inline void updateTranslateMask() {
821  if ((fMat[kMTransX] != 0) | (fMat[kMTransY] != 0)) {
822  fTypeMask |= kTranslate_Mask;
823  } else {
824  fTypeMask &= ~kTranslate_Mask;
825  }
826  }
827 
828  bool SK_WARN_UNUSED_RESULT invertNonIdentity(SkMatrix* inverse) const;
829 
830  static bool Poly2Proc(const SkPoint[], SkMatrix*, const SkPoint& scale);
831  static bool Poly3Proc(const SkPoint[], SkMatrix*, const SkPoint& scale);
832  static bool Poly4Proc(const SkPoint[], SkMatrix*, const SkPoint& scale);
833 
834  static void Identity_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
835  static void Trans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
836  static void Scale_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
837  static void ScaleTrans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
838  static void Rot_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
839  static void RotTrans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
840  static void Persp_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
841 
842  static const MapXYProc gMapXYProcs[];
843 
844  static void Identity_pts(const SkMatrix&, SkPoint[], const SkPoint[], int);
845  static void Trans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int);
846  static void Scale_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int);
847  static void ScaleTrans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[],
848  int count);
849  static void Persp_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int);
850 
851  static void Affine_vpts(const SkMatrix&, SkPoint dst[], const SkPoint[], int);
852 
853  static const MapPtsProc gMapPtsProcs[];
854 
855  friend class SkPerspIter;
856  friend class SkMatrixPriv;
857 };
858 SK_END_REQUIRE_DENSE
859 
860 #endif
TypeMask
Enum of bit fields for the mask return by getType().
Definition: SkMatrix.h:51
bool isFinite() const
Are all elements of the matrix finite?
Definition: SkMatrix.h:744
ScaleToFit
Definition: SkMatrix.h:338
bool isIdentity() const
Returns true if the matrix is identity.
Definition: SkMatrix.h:75
void get9(SkScalar buffer[9]) const
Copy the 9 scalars for this matrix into buffer, in the same order as the kMScaleX enum...
Definition: SkMatrix.h:198
void setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py)
Set the matrix to scale by sx and sy, with a pivot point at (px, py).
void mapPoints(SkPoint dst[], const SkPoint src[], int count) const
Apply this matrix to the array of points specified by src, and write the transformed points into the ...
Definition: SkMatrix.h:434
void setConcat(const SkMatrix &a, const SkMatrix &b)
Set the matrix to the concatenation of the two specified matrices.
Definition: SkPoint.h:156
void dirtyMatrixTypeCache()
Testing routine; the matrix's type cache should never need to be manually invalidated during normal u...
Definition: SkMatrix.h:711
bool setRectToRect(const SkRect &src, const SkRect &dst, ScaleToFit stf)
Set the matrix to the scale and translate values that map the source rectangle to the destination rec...
void mapVectors(SkVector vecs[], int count) const
Apply this matrix to the array of vectors specified by src, and write the transformed vectors into th...
Definition: SkMatrix.h:519
The SkMatrix class holds a 3x3 matrix for transforming coordinates.
Definition: SkMatrix.h:28
void setTranslate(SkScalar dx, SkScalar dy)
Set the matrix to translate by (dx, dy).
void mapPointsWithStride(SkPoint dst[], const SkPoint src[], size_t stride, int count) const
Like mapPoints but with custom byte stride between the points.
Definition: SkMatrix.h:466
bool SK_WARN_UNUSED_RESULT invert(SkMatrix *inverse) const
If this matrix can be inverted, return true and if inverse is not null, set inverse to be the inverse...
Definition: SkMatrix.h:394
#define SkToBool(cond)
Returns 0 or 1 based on the condition.
Definition: SkTypes.h:227
A compressed form of a rotation+scale matrix.
Definition: SkRSXform.h:21
Compute a scale that will maintain the original src aspect ratio, but will also ensure that src fits ...
Definition: SkMatrix.h:356
void mapPoints(SkPoint pts[], int count) const
Apply this matrix to the array of points, overwriting it with the transformed values.
Definition: SkMatrix.h:448
Scale in X and Y independently, so that src matches dst exactly.
Definition: SkMatrix.h:343
TypeMask getType() const
Returns a bitfield describing the transformations the matrix may perform.
Definition: SkMatrix.h:65
bool mapRect(SkRect *rect) const
Apply this matrix to the rectangle, and write the transformed rectangle back into it...
Definition: SkMatrix.h:549
static SkMatrix Concat(const SkMatrix &a, const SkMatrix &b)
Return the concatenation of two matrices, a * b.
Definition: SkMatrix.h:701
void toQuad(SkPoint quad[4]) const
return the 4 points that enclose the rectangle (top-left, top-right, bottom-right, bottom-left).
void reset()
Set the matrix to identity.
bool isTriviallyIdentity() const
Returns true if we already know that the matrix is identity; false otherwise.
Definition: SkMatrix.h:813
bool hasPerspective() const
Returns true if the matrix contains perspective elements.
Definition: SkMatrix.h:99
void mapRectToQuad(SkPoint dst[4], const SkRect &rect) const
Apply this matrix to the src rectangle, and write the four transformed points into dst...
Definition: SkMatrix.h:559
bool cheapEqualTo(const SkMatrix &m) const
Efficient comparison of two matrices.
Definition: SkMatrix.h:620
Definition: SkRect.h:404
void setScaleTranslate(SkScalar sx, SkScalar sy, SkScalar tx, SkScalar ty)
Initialize the matrix to be scale + post-translate.
Definition: SkMatrix.h:718
Compute a scale that will maintain the original src aspect ratio, but will also ensure that src fits ...
Definition: SkMatrix.h:350
void mapPointsWithStride(SkPoint pts[], size_t stride, int count) const
Like mapPoints but with custom byte stride between the points.
Definition: SkMatrix.h:455
Definition: SkSize.h:47
Light weight class for managing strings.
Definition: SkString.h:121
bool rectStaysRect() const
Returns true if will map a rectangle to another rectangle.
Definition: SkMatrix.h:87