matrix44.h 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. // Copyright 2022 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef UI_GFX_GEOMETRY_MATRIX44_H_
  5. #define UI_GFX_GEOMETRY_MATRIX44_H_
  6. #include <atomic>
  7. #include <cstring>
  8. #include "build/build_config.h"
  9. #include "third_party/skia/include/core/SkMatrix.h"
  10. #include "ui/gfx/geometry/geometry_skia_export.h"
  11. #if BUILDFLAG(IS_MAC)
  12. struct CATransform3D;
  13. #endif
  14. namespace gfx {
  15. // This is the underlying data structure of Transform. Don't use this type
  16. // directly. The public methods can be called through Transform::matrix().
  17. class GEOMETRY_SKIA_EXPORT Matrix44 {
  18. public:
  19. enum Uninitialized_Constructor { kUninitialized_Constructor };
  20. explicit Matrix44(Uninitialized_Constructor) {}
  21. constexpr Matrix44()
  22. : fMat{{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}},
  23. fTypeMask(kIdentity_Mask) {}
  24. // The parameters are in row-major order.
  25. Matrix44(SkScalar col1row1,
  26. SkScalar col2row1,
  27. SkScalar col3row1,
  28. SkScalar col4row1,
  29. SkScalar col1row2,
  30. SkScalar col2row2,
  31. SkScalar col3row2,
  32. SkScalar col4row2,
  33. SkScalar col1row3,
  34. SkScalar col2row3,
  35. SkScalar col3row3,
  36. SkScalar col4row3,
  37. SkScalar col1row4,
  38. SkScalar col2row4,
  39. SkScalar col3row4,
  40. SkScalar col4row4)
  41. // fMat is indexed by [col][row] (i.e. col-major).
  42. : fMat{{col1row1, col1row2, col1row3, col1row4},
  43. {col2row1, col2row2, col2row3, col2row4},
  44. {col3row1, col3row2, col3row3, col3row4},
  45. {col4row1, col4row2, col4row3, col4row4}} {
  46. recomputeTypeMask();
  47. }
  48. Matrix44(const Matrix44& a, const Matrix44& b) { this->setConcat(a, b); }
  49. bool operator==(const Matrix44& other) const;
  50. bool operator!=(const Matrix44& other) const { return !(other == *this); }
  51. /* When converting from Matrix44 to SkMatrix, the third row and
  52. * column is dropped. When converting from SkMatrix to Matrix44
  53. * the third row and column remain as identity:
  54. * [ a b c ] [ a b 0 c ]
  55. * [ d e f ] -> [ d e 0 f ]
  56. * [ g h i ] [ 0 0 1 0 ]
  57. * [ g h 0 i ]
  58. */
  59. explicit Matrix44(const SkMatrix&);
  60. // Inverse conversion of the above.
  61. SkMatrix asM33() const;
  62. using TypeMask = uint8_t;
  63. enum : TypeMask {
  64. kIdentity_Mask = 0,
  65. kTranslate_Mask = 1 << 0, //!< set if the matrix has translation
  66. kScale_Mask = 1 << 1, //!< set if the matrix has any scale != 1
  67. kAffine_Mask = 1 << 2, //!< set if the matrix skews or rotates
  68. kPerspective_Mask = 1 << 3, //!< set if the matrix is in perspective
  69. };
  70. /**
  71. * Returns a bitfield describing the transformations the matrix may
  72. * perform. The bitfield is computed conservatively, so it may include
  73. * false positives. For example, when kPerspective_Mask is true, all
  74. * other bits may be set to true even in the case of a pure perspective
  75. * transform.
  76. */
  77. inline TypeMask getType() const { return fTypeMask; }
  78. /**
  79. * Return true if the matrix is identity.
  80. */
  81. inline bool isIdentity() const { return kIdentity_Mask == this->getType(); }
  82. /**
  83. * Return true if the matrix contains translate or is identity.
  84. */
  85. inline bool isTranslate() const {
  86. return !(this->getType() & ~kTranslate_Mask);
  87. }
  88. /**
  89. * Return true if the matrix only contains scale or translate or is identity.
  90. */
  91. inline bool isScaleTranslate() const {
  92. return !(this->getType() & ~(kScale_Mask | kTranslate_Mask));
  93. }
  94. /**
  95. * Returns true if the matrix only contains scale or is identity.
  96. */
  97. inline bool isScale() const { return !(this->getType() & ~kScale_Mask); }
  98. inline bool hasPerspective() const {
  99. return SkToBool(this->getType() & kPerspective_Mask);
  100. }
  101. void setIdentity();
  102. /**
  103. * get a value from the matrix. The row,col parameters work as follows:
  104. * (0, 0) scale-x
  105. * (0, 3) translate-x
  106. * (3, 0) perspective-x
  107. */
  108. inline SkScalar rc(int row, int col) const {
  109. SkASSERT((unsigned)row <= 3);
  110. SkASSERT((unsigned)col <= 3);
  111. return fMat[col][row];
  112. }
  113. /**
  114. * set a value in the matrix. The row,col parameters work as follows:
  115. * (0, 0) scale-x
  116. * (0, 3) translate-x
  117. * (3, 0) perspective-x
  118. */
  119. inline void setRC(int row, int col, SkScalar value) {
  120. SkASSERT((unsigned)row <= 3);
  121. SkASSERT((unsigned)col <= 3);
  122. fMat[col][row] = value;
  123. this->recomputeTypeMask();
  124. }
  125. /** These methods allow one to efficiently read matrix entries into an
  126. * array. The given array must have room for exactly 16 entries. Whenever
  127. * possible, they will try to use memcpy rather than an entry-by-entry
  128. * copy.
  129. *
  130. * Col major indicates that consecutive elements of columns will be stored
  131. * contiguously in memory. Row major indicates that consecutive elements
  132. * of rows will be stored contiguously in memory.
  133. */
  134. void getColMajor(float[]) const;
  135. void getRowMajor(float[]) const;
  136. /** These methods allow one to efficiently set all matrix entries from an
  137. * array. The given array must have room for exactly 16 entries. Whenever
  138. * possible, they will try to use memcpy rather than an entry-by-entry
  139. * copy.
  140. *
  141. * Col major indicates that input memory will be treated as if consecutive
  142. * elements of columns are stored contiguously in memory. Row major
  143. * indicates that input memory will be treated as if consecutive elements
  144. * of rows are stored contiguously in memory.
  145. */
  146. void setColMajor(const float[]);
  147. void setRowMajor(const float[]);
  148. #if BUILDFLAG(IS_MAC)
  149. CATransform3D ToCATransform3D() const;
  150. #endif
  151. Matrix44& setTranslate(SkScalar dx, SkScalar dy, SkScalar dz);
  152. Matrix44& preTranslate(SkScalar dx, SkScalar dy, SkScalar dz);
  153. Matrix44& postTranslate(SkScalar dx, SkScalar dy, SkScalar dz);
  154. Matrix44& setScale(SkScalar sx, SkScalar sy, SkScalar sz);
  155. Matrix44& preScale(SkScalar sx, SkScalar sy, SkScalar sz);
  156. Matrix44& postScale(SkScalar sx, SkScalar sy, SkScalar sz);
  157. // Sets this matrix to rotate about the specified unit-length axis vector,
  158. // by an angle specified by its sin() and cos(). This does not attempt to
  159. // verify that axis(x, y, z).length() == 1 or that the sin, cos values are
  160. // correct.
  161. void setRotateUnitSinCos(SkScalar x,
  162. SkScalar y,
  163. SkScalar z,
  164. SkScalar sin_angle,
  165. SkScalar cos_angle);
  166. // Special case for x, y or z axis of the above function.
  167. void setRotateAboutXAxisSinCos(SkScalar sin_angle, SkScalar cos_angle);
  168. void setRotateAboutYAxisSinCos(SkScalar sin_angle, SkScalar cos_angle);
  169. void setRotateAboutZAxisSinCos(SkScalar sin_angle, SkScalar cos_angle);
  170. void setConcat(const Matrix44& a, const Matrix44& b);
  171. inline void preConcat(const Matrix44& m) { this->setConcat(*this, m); }
  172. inline void postConcat(const Matrix44& m) { this->setConcat(m, *this); }
  173. friend Matrix44 operator*(const Matrix44& a, const Matrix44& b) {
  174. return Matrix44(a, b);
  175. }
  176. /** If this is invertible, return that in inverse and return true. If it is
  177. not invertible, return false and leave the inverse parameter in an
  178. unspecified state.
  179. */
  180. bool invert(Matrix44* inverse) const;
  181. /** Transpose this matrix in place. */
  182. void transpose();
  183. /** Apply the matrix to the src vector, returning the new vector in dst.
  184. It is legal for src and dst to point to the same memory.
  185. */
  186. void mapScalars(const SkScalar src[4], SkScalar dst[4]) const;
  187. inline void mapScalars(SkScalar vec[4]) const { this->mapScalars(vec, vec); }
  188. /**
  189. * map an array of [x, y, 0, 1] through the matrix, returning an array
  190. * of [x', y', z', w'].
  191. *
  192. * @param src2 array of [x, y] pairs, with implied z=0 and w=1
  193. * @param count number of [x, y] pairs in src2
  194. * @param dst4 array of [x', y', z', w'] quads as the output.
  195. */
  196. void map2(const float src2[], int count, float dst4[]) const;
  197. double determinant() const;
  198. void FlattenTo2d();
  199. private:
  200. /* This is indexed by [col][row]. */
  201. SkScalar fMat[4][4];
  202. TypeMask fTypeMask;
  203. static constexpr int kAllPublic_Masks = 0xF;
  204. SkScalar transX() const { return fMat[3][0]; }
  205. SkScalar transY() const { return fMat[3][1]; }
  206. SkScalar transZ() const { return fMat[3][2]; }
  207. SkScalar scaleX() const { return fMat[0][0]; }
  208. SkScalar scaleY() const { return fMat[1][1]; }
  209. SkScalar scaleZ() const { return fMat[2][2]; }
  210. SkScalar perspX() const { return fMat[0][3]; }
  211. SkScalar perspY() const { return fMat[1][3]; }
  212. SkScalar perspZ() const { return fMat[2][3]; }
  213. void recomputeTypeMask();
  214. inline void setTypeMask(TypeMask mask) {
  215. SkASSERT(0 == (~kAllPublic_Masks & mask));
  216. fTypeMask = mask;
  217. }
  218. };
  219. } // namespace gfx
  220. #endif // UI_GFX_GEOMETRY_MATRIX44_H_