File: matrix44.h

package info (click to toggle)
qt6-webengine 6.4.2-final%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 3,090,536 kB
  • sloc: cpp: 17,808,031; ansic: 5,245,139; javascript: 3,178,881; python: 1,361,176; asm: 648,577; xml: 571,140; java: 196,952; sh: 96,408; objc: 88,289; perl: 70,982; cs: 39,145; fortran: 24,137; makefile: 20,242; pascal: 12,634; sql: 10,875; yacc: 9,671; tcl: 8,385; php: 6,188; lisp: 2,848; lex: 2,263; ada: 727; ruby: 623; awk: 339; sed: 37
file content (330 lines) | stat: -rw-r--r-- 11,094 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
// Copyright 2022 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef UI_GFX_GEOMETRY_MATRIX44_H_
#define UI_GFX_GEOMETRY_MATRIX44_H_

#include <atomic>
#include <cstring>

#include "build/build_config.h"
#include "third_party/skia/include/core/SkMatrix.h"
#include "ui/gfx/geometry/geometry_skia_export.h"

#if BUILDFLAG(IS_MAC)
struct CATransform3D;
#endif

namespace gfx {

struct Vector4 {
  SkScalar fData[4];

  Vector4() { this->set(0, 0, 0, 1); }
  Vector4(const Vector4& src) { memcpy(fData, src.fData, sizeof(fData)); }
  Vector4(SkScalar x, SkScalar y, SkScalar z, SkScalar w = SK_Scalar1) {
    fData[0] = x;
    fData[1] = y;
    fData[2] = z;
    fData[3] = w;
  }

  Vector4& operator=(const Vector4& src) {
    memcpy(fData, src.fData, sizeof(fData));
    return *this;
  }

  bool operator==(const Vector4& v) const {
    return fData[0] == v.fData[0] && fData[1] == v.fData[1] &&
           fData[2] == v.fData[2] && fData[3] == v.fData[3];
  }
  bool operator!=(const Vector4& v) const { return !(*this == v); }
  bool equals(SkScalar x, SkScalar y, SkScalar z, SkScalar w = SK_Scalar1) {
    return fData[0] == x && fData[1] == y && fData[2] == z && fData[3] == w;
  }

  void set(SkScalar x, SkScalar y, SkScalar z, SkScalar w = SK_Scalar1) {
    fData[0] = x;
    fData[1] = y;
    fData[2] = z;
    fData[3] = w;
  }
};

// This is the underlying data structure of Transform. Don't use this type
// directly. The public methods can be called through Transform::matrix().
class GEOMETRY_SKIA_EXPORT Matrix44 {
 public:
  enum Uninitialized_Constructor { kUninitialized_Constructor };

  explicit Matrix44(Uninitialized_Constructor) {}

  constexpr Matrix44()
      : fMat{{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}},
        fTypeMask(kIdentity_Mask) {}

  // The parameters are in row-major order.
  Matrix44(SkScalar col1row1,
           SkScalar col2row1,
           SkScalar col3row1,
           SkScalar col4row1,
           SkScalar col1row2,
           SkScalar col2row2,
           SkScalar col3row2,
           SkScalar col4row2,
           SkScalar col1row3,
           SkScalar col2row3,
           SkScalar col3row3,
           SkScalar col4row3,
           SkScalar col1row4,
           SkScalar col2row4,
           SkScalar col3row4,
           SkScalar col4row4)
      // fMat is indexed by [col][row] (i.e. col-major).
      : fMat{{col1row1, col1row2, col1row3, col1row4},
             {col2row1, col2row2, col2row3, col2row4},
             {col3row1, col3row2, col3row3, col3row4},
             {col4row1, col4row2, col4row3, col4row4}} {
    recomputeTypeMask();
  }

  Matrix44(const Matrix44& a, const Matrix44& b) { this->setConcat(a, b); }

  bool operator==(const Matrix44& other) const;
  bool operator!=(const Matrix44& other) const { return !(other == *this); }

  /* When converting from Matrix44 to SkMatrix, the third row and
   * column is dropped.  When converting from SkMatrix to Matrix44
   * the third row and column remain as identity:
   * [ a b c ]      [ a b 0 c ]
   * [ d e f ]  ->  [ d e 0 f ]
   * [ g h i ]      [ 0 0 1 0 ]
   *                [ g h 0 i ]
   */
  explicit Matrix44(const SkMatrix&);

  // Inverse conversion of the above.
  SkMatrix asM33() const;

  using TypeMask = uint8_t;
  enum : TypeMask {
    kIdentity_Mask = 0,
    kTranslate_Mask = 1 << 0,    //!< set if the matrix has translation
    kScale_Mask = 1 << 1,        //!< set if the matrix has any scale != 1
    kAffine_Mask = 1 << 2,       //!< set if the matrix skews or rotates
    kPerspective_Mask = 1 << 3,  //!< set if the matrix is in perspective
  };

  /**
   *  Returns a bitfield describing the transformations the matrix may
   *  perform. The bitfield is computed conservatively, so it may include
   *  false positives. For example, when kPerspective_Mask is true, all
   *  other bits may be set to true even in the case of a pure perspective
   *  transform.
   */
  inline TypeMask getType() const { return fTypeMask; }

  /**
   *  Return true if the matrix is identity.
   */
  inline bool isIdentity() const { return kIdentity_Mask == this->getType(); }

  /**
   *  Return true if the matrix contains translate or is identity.
   */
  inline bool isTranslate() const {
    return !(this->getType() & ~kTranslate_Mask);
  }

  /**
   *  Return true if the matrix only contains scale or translate or is identity.
   */
  inline bool isScaleTranslate() const {
    return !(this->getType() & ~(kScale_Mask | kTranslate_Mask));
  }

  /**
   *  Returns true if the matrix only contains scale or is identity.
   */
  inline bool isScale() const { return !(this->getType() & ~kScale_Mask); }

  inline bool hasPerspective() const {
    return SkToBool(this->getType() & kPerspective_Mask);
  }

  void setIdentity();

  /**
   *  get a value from the matrix. The row,col parameters work as follows:
   *  (0, 0)  scale-x
   *  (0, 3)  translate-x
   *  (3, 0)  perspective-x
   */
  inline SkScalar rc(int row, int col) const {
    SkASSERT((unsigned)row <= 3);
    SkASSERT((unsigned)col <= 3);
    return fMat[col][row];
  }

  /**
   *  set a value in the matrix. The row,col parameters work as follows:
   *  (0, 0)  scale-x
   *  (0, 3)  translate-x
   *  (3, 0)  perspective-x
   */
  inline void setRC(int row, int col, SkScalar value) {
    SkASSERT((unsigned)row <= 3);
    SkASSERT((unsigned)col <= 3);
    fMat[col][row] = value;
    this->recomputeTypeMask();
  }

  /** These methods allow one to efficiently read matrix entries into an
   *  array. The given array must have room for exactly 16 entries. Whenever
   *  possible, they will try to use memcpy rather than an entry-by-entry
   *  copy.
   *
   *  Col major indicates that consecutive elements of columns will be stored
   *  contiguously in memory.  Row major indicates that consecutive elements
   *  of rows will be stored contiguously in memory.
   */
  void getColMajor(float[]) const;
  void getRowMajor(float[]) const;

  /** These methods allow one to efficiently set all matrix entries from an
   *  array. The given array must have room for exactly 16 entries. Whenever
   *  possible, they will try to use memcpy rather than an entry-by-entry
   *  copy.
   *
   *  Col major indicates that input memory will be treated as if consecutive
   *  elements of columns are stored contiguously in memory.  Row major
   *  indicates that input memory will be treated as if consecutive elements
   *  of rows are stored contiguously in memory.
   */
  void setColMajor(const float[]);
  void setRowMajor(const float[]);

#if BUILDFLAG(IS_MAC)
  CATransform3D ToCATransform3D() const;
#endif

  Matrix44& setTranslate(SkScalar dx, SkScalar dy, SkScalar dz);
  Matrix44& preTranslate(SkScalar dx, SkScalar dy, SkScalar dz);
  Matrix44& postTranslate(SkScalar dx, SkScalar dy, SkScalar dz);

  Matrix44& setScale(SkScalar sx, SkScalar sy, SkScalar sz);
  Matrix44& preScale(SkScalar sx, SkScalar sy, SkScalar sz);
  Matrix44& postScale(SkScalar sx, SkScalar sy, SkScalar sz);

  inline Matrix44& setScale(SkScalar scale) {
    return this->setScale(scale, scale, scale);
  }
  inline Matrix44& preScale(SkScalar scale) {
    return this->preScale(scale, scale, scale);
  }
  inline Matrix44& postScale(SkScalar scale) {
    return this->postScale(scale, scale, scale);
  }

  // Sets this matrix to rotate about the specified unit-length axis vector,
  // by an angle specified by its sin() and cos(). This does not attempt to
  // verify that axis(x, y, z).length() == 1 or that the sin, cos values are
  // correct.
  void setRotateUnitSinCos(SkScalar x,
                           SkScalar y,
                           SkScalar z,
                           SkScalar sin_angle,
                           SkScalar cos_angle);

  // Special case for x, y or z axis of the above function.
  void setRotateAboutXAxisSinCos(SkScalar sin_angle, SkScalar cos_angle);
  void setRotateAboutYAxisSinCos(SkScalar sin_angle, SkScalar cos_angle);
  void setRotateAboutZAxisSinCos(SkScalar sin_angle, SkScalar cos_angle);

  void setConcat(const Matrix44& a, const Matrix44& b);
  inline void preConcat(const Matrix44& m) { this->setConcat(*this, m); }
  inline void postConcat(const Matrix44& m) { this->setConcat(m, *this); }

  friend Matrix44 operator*(const Matrix44& a, const Matrix44& b) {
    return Matrix44(a, b);
  }

  /** If this is invertible, return that in inverse and return true. If it is
      not invertible, return false and leave the inverse parameter in an
      unspecified state.
   */
  bool invert(Matrix44* inverse) const;

  /** Transpose this matrix in place. */
  void transpose();

  /** Apply the matrix to the src vector, returning the new vector in dst.
      It is legal for src and dst to point to the same memory.
   */
  void mapScalars(const SkScalar src[4], SkScalar dst[4]) const;
  inline void mapScalars(SkScalar vec[4]) const { this->mapScalars(vec, vec); }

  friend Vector4 operator*(const Matrix44& m, const Vector4& src) {
    Vector4 dst;
    m.mapScalars(src.fData, dst.fData);
    return dst;
  }

  /**
   *  map an array of [x, y, 0, 1] through the matrix, returning an array
   *  of [x', y', z', w'].
   *
   *  @param src2     array of [x, y] pairs, with implied z=0 and w=1
   *  @param count    number of [x, y] pairs in src2
   *  @param dst4     array of [x', y', z', w'] quads as the output.
   */
  void map2(const float src2[], int count, float dst4[]) const;
  void map2(const double src2[], int count, double dst4[]) const;

  /** Returns true if transformating an axis-aligned square in 2d by this matrix
      will produce another 2d axis-aligned square; typically means the matrix
      is a scale with perhaps a 90-degree rotation. A 3d rotation through 90
      degrees into a perpendicular plane collapses a square to a line, but
      is still considered to be axis-aligned.

      By default, tolerates very slight error due to float imprecisions;
      a 90-degree rotation can still end up with 10^-17 of
      "non-axis-aligned" result.
   */
  bool preserves2dAxisAlignment(SkScalar epsilon = SK_ScalarNearlyZero) const;

  double determinant() const;

  void FlattenTo2d();

 private:
  /* This is indexed by [col][row]. */
  SkScalar fMat[4][4];
  TypeMask fTypeMask;

  static constexpr int kAllPublic_Masks = 0xF;

  SkScalar transX() const { return fMat[3][0]; }
  SkScalar transY() const { return fMat[3][1]; }
  SkScalar transZ() const { return fMat[3][2]; }

  SkScalar scaleX() const { return fMat[0][0]; }
  SkScalar scaleY() const { return fMat[1][1]; }
  SkScalar scaleZ() const { return fMat[2][2]; }

  SkScalar perspX() const { return fMat[0][3]; }
  SkScalar perspY() const { return fMat[1][3]; }
  SkScalar perspZ() const { return fMat[2][3]; }

  void recomputeTypeMask();

  inline void setTypeMask(TypeMask mask) {
    SkASSERT(0 == (~kAllPublic_Masks & mask));
    fTypeMask = mask;
  }
};

}  // namespace gfx

#endif  // UI_GFX_GEOMETRY_MATRIX44_H_