File: matrix44.h

package info (click to toggle)
chromium 138.0.7204.183-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,908 kB
  • sloc: cpp: 34,937,088; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (208 lines) | stat: -rw-r--r-- 7,327 bytes parent folder | download | duplicates (4)
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
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/354829279): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif

#ifndef UI_GFX_GEOMETRY_MATRIX44_H_
#define UI_GFX_GEOMETRY_MATRIX44_H_

#include <optional>

#include "base/check_op.h"
#include "base/component_export.h"
#include "base/containers/span.h"
#include "ui/gfx/geometry/double4.h"

namespace gfx {

struct DecomposedTransform;

// This is the underlying data structure of Transform. Don't use this type
// directly.
//
// Throughout this class, we will be speaking in column vector convention.
// i.e. Applying a transform T to vector V is T * V.
// The components of the matrix and the vector look like:
//    \  col
// r   \     0        1        2        3
// o  0 | scale_x  skew_xy  skew_xz  trans_x |   | x |
// w  1 | skew_yx  scale_y  skew_yz  trans_y | * | y |
//    2 | skew_zx  skew_zy  scale_z  trans_z |   | z |
//    3 | persp_x  persp_y  persp_z  persp_w |   | w |
//
// Note that the names are just for remembering and don't have the exact
// meanings when other components exist.
//
// The components correspond to the DOMMatrix mij (i,j = 1..4) components:
//   i = col + 1
//   j = row + 1
class COMPONENT_EXPORT(GEOMETRY_SKIA) Matrix44 {
 public:
  enum UninitializedTag { kUninitialized };

  explicit Matrix44(UninitializedTag) {}

  constexpr Matrix44()
      : matrix_{{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}} {}

  // The parameters are in col-major order.
  // clang-format off
  constexpr Matrix44(double r0c0, double r1c0, double r2c0, double r3c0,
                     double r0c1, double r1c1, double r2c1, double r3c1,
                     double r0c2, double r1c2, double r2c2, double r3c2,
                     double r0c3, double r1c3, double r2c3, double r3c3)
      // matrix_ is indexed by [col][row] (i.e. col-major).
      : matrix_{{r0c0, r1c0, r2c0, r3c0},
                {r0c1, r1c1, r2c1, r3c1},
                {r0c2, r1c2, r2c2, r3c2},
                {r0c3, r1c3, r2c3, r3c3}} {}
  // clang-format on

  bool operator==(const Matrix44& other) const {
    return AllTrue(Col(0) == other.Col(0)) && AllTrue(Col(1) == other.Col(1)) &&
           AllTrue(Col(2) == other.Col(2)) && AllTrue(Col(3) == other.Col(3));
  }
  // Returns true if the matrix is identity.
  bool IsIdentity() const { return *this == Matrix44(); }

  // Returns true if the matrix contains translate or is identity.
  bool IsIdentityOrTranslation() const {
    return AllTrue(Col(0) == Double4{1, 0, 0, 0}) &&
           AllTrue(Col(1) == Double4{0, 1, 0, 0}) &&
           AllTrue(Col(2) == Double4{0, 0, 1, 0}) && matrix_[3][3] == 1;
  }

  // Returns true if the matrix only contains scale or translate or is identity.
  bool IsScaleOrTranslation() const {
    return AllTrue(Double4{matrix_[0][1], matrix_[0][2], matrix_[0][3],
                           matrix_[1][0]} == Double4{0, 0, 0, 0}) &&
           AllTrue(Double4{matrix_[1][2], matrix_[1][3], matrix_[2][0],
                           matrix_[2][1]} == Double4{0, 0, 0, 0}) &&
           matrix_[2][3] == 0 && matrix_[3][3] == 1;
  }

  // Returns true if the matrix only contains scale or is identity.
  bool IsScale() const {
    return IsScaleOrTranslation() && AllTrue(Col(3) == Double4{0, 0, 0, 1});
  }

  bool IsFlat() const {
    return AllTrue(Col(2) == Double4{0, 0, 1, 0}) &&
           AllTrue(Double4{matrix_[0][2], matrix_[1][2], 0, matrix_[3][2]} ==
                   Double4{0, 0, 0, 0});
  }

  bool HasPerspective() const {
    return !AllTrue(Double4{matrix_[0][3], matrix_[1][3], matrix_[2][3],
                            matrix_[3][3]} == Double4{0, 0, 0, 1});
  }

  bool Is2dTransform() const { return IsFlat() && !HasPerspective(); }

  // Gets a value at |row|, |col| from the matrix.
  constexpr double rc(int row, int col) const {
    DCHECK_LE(static_cast<unsigned>(row), 3u);
    DCHECK_LE(static_cast<unsigned>(col), 3u);
    return matrix_[col][row];
  }

  // Set a value in the matrix at |row|, |col|.
  void set_rc(int row, int col, double value) {
    DCHECK_LE(static_cast<unsigned>(row), 3u);
    DCHECK_LE(static_cast<unsigned>(col), 3u);
    matrix_[col][row] = value;
  }

  void GetColMajor(double[16]) const;
  void GetColMajorF(float[16]) const;

  // this = this * translation.
  void PreTranslate(double dx, double dy);
  void PreTranslate3d(double dx, double dy, double dz);
  // this = translation * this.
  void PostTranslate(double dx, double dy);
  void PostTranslate3d(double dx, double dy, double dz);

  // this = this * scale.
  void PreScale(double sx, double sy);
  void PreScale3d(double sx, double sy, double sz);
  // this = scale * this.
  void PostScale(double sx, double sy);
  void PostScale3d(double sx, double sy, double sz);

  // Rotates this matrix 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. this = this * rotation.
  void RotateUnitSinCos(double x,
                        double y,
                        double z,
                        double sin_angle,
                        double cos_angle);

  // Special case for x, y or z axis of the above function.
  void RotateAboutXAxisSinCos(double sin_angle, double cos_angle);
  void RotateAboutYAxisSinCos(double sin_angle, double cos_angle);
  void RotateAboutZAxisSinCos(double sin_angle, double cos_angle);

  // this = this * skew.
  void Skew(double tan_skew_x, double tan_skew_y);

  //               |1 skew[0] skew[1] 0|
  // this = this * |0    1    skew[2] 0|
  //               |0    0      1     0|
  //               |0    0      0     1|
  void ApplyDecomposedSkews(base::span<const double, 3> skews);

  // this = this * perspective.
  void ApplyPerspectiveDepth(double perspective);

  // this = this * m.
  void PreConcat(const Matrix44& m) { SetConcat(*this, m); }
  // this = m * this.
  void PostConcat(const Matrix44& m) { SetConcat(m, *this); }
  // this = a * b.
  void SetConcat(const Matrix44& a, const Matrix44& b);

  // Returns true and set |inverse| to the inverted matrix if this matrix
  // is invertible. Otherwise return false and leave the |inverse| parameter
  // unchanged.
  bool GetInverse(Matrix44& inverse) const;

  bool IsInvertible() const;
  double Determinant() const;

  // Transposes this matrix in place.
  void Transpose();

  // See Transform::Zoom().
  void Zoom(double zoom_factor);

  // Applies the matrix to the vector in place.
  void MapVector4(double vec[4]) const;

  // Same as above, but assumes the vec[2] is 0 and vec[3] is 1, discards
  // vec[2], and returns vec[3].
  double MapVector2(double vec[2]) const;

  void Flatten();

  std::optional<DecomposedTransform> Decompose() const;

 private:
  std::optional<DecomposedTransform> Decompose2d() const;

  ALWAYS_INLINE Double4 Col(int i) const { return LoadDouble4(matrix_[i]); }
  ALWAYS_INLINE void SetCol(int i, Double4 v) { StoreDouble4(v, matrix_[i]); }

  // This is indexed by [col][row].
  double matrix_[4][4];
};

}  // namespace gfx

#endif  // UI_GFX_GEOMETRY_MATRIX44_H_