File: transform_operations.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 (141 lines) | stat: -rw-r--r-- 5,765 bytes parent folder | download | duplicates (5)
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
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef UI_GFX_GEOMETRY_TRANSFORM_OPERATIONS_H_
#define UI_GFX_GEOMETRY_TRANSFORM_OPERATIONS_H_

#include <memory>
#include <optional>
#include <unordered_map>
#include <vector>

#include "base/check_op.h"
#include "base/component_export.h"
#include "base/gtest_prod_util.h"
#include "ui/gfx/geometry/transform.h"
#include "ui/gfx/geometry/transform_operation.h"

namespace gfx {

class BoxF;
struct DecomposedTransform;

// Transform operations are a decomposed transformation matrix. It can be
// applied to obtain a Transform at any time, and can be blended
// intelligently with other transform operations, so long as they represent the
// same decomposition. For example, if we have a transform that is made up of
// a rotation followed by skew, it can be blended intelligently with another
// transform made up of a rotation followed by a skew. Blending is possible if
// we have two dissimilar sets of transform operations, but the effect may not
// be what was intended. For more information, see the comments for the blend
// function below.
class COMPONENT_EXPORT(GEOMETRY_SKIA) TransformOperations {
 public:
  TransformOperations();
  TransformOperations(const TransformOperations& other);
  ~TransformOperations();

  TransformOperations& operator=(const TransformOperations& other);

  // Returns a transformation matrix representing these transform operations.
  Transform Apply() const;

  // Returns a transformation matrix representing the set of transform
  // operations from index |start| to the end of the list.
  Transform ApplyRemaining(size_t start) const;

  // Given another set of transform operations and a progress in the range
  // [0, 1], returns a transformation matrix representing the intermediate
  // value. If this->MatchesTypes(from), then each of the operations are
  // blended separately and then combined. Otherwise, the two sets of
  // transforms are baked to matrices (using apply), and the matrices are
  // then decomposed and interpolated. For more information, see
  // http://www.w3.org/TR/2011/WD-css3-2d-transforms-20111215/#matrix-decomposition.
  //
  // If either of the matrices are non-decomposable for the blend, Blend applies
  // discrete interpolation between them based on the progress value.
  TransformOperations Blend(const TransformOperations& from,
                            SkScalar progress) const;

  // Sets |bounds| be the bounding box for the region within which |box| will
  // exist when it is transformed by the result of calling Blend on |from| and
  // with progress in the range [min_progress, max_progress]. If this region
  // cannot be computed, returns false.
  bool BlendedBoundsForBox(const BoxF& box,
                           const TransformOperations& from,
                           SkScalar min_progress,
                           SkScalar max_progress,
                           BoxF* bounds) const;

  // Returns true if these operations are only translations.
  bool IsTranslation() const;

  // Returns false if the operations affect 2d axis alignment.
  bool PreservesAxisAlignment() const;

  // Returns true if this operation and its descendants have the same types
  // as other and its descendants.
  bool MatchesTypes(const TransformOperations& other) const;

  // Returns the number of matching transform operations at the start of the
  // transform lists. If one list is shorter but pairwise compatible, it will be
  // extended with matching identity operators per spec
  // (https://drafts.csswg.org/css-transforms/#interpolation-of-transforms).
  size_t MatchingPrefixLength(const TransformOperations& other) const;

  // Returns true if these operations can be blended. It will only return
  // false if we must resort to matrix interpolation, and matrix interpolation
  // fails (this can happen if either matrix cannot be decomposed).
  bool CanBlendWith(const TransformOperations& other) const;

  // If none of these operations have a perspective component, sets |scale| to
  // be the product of the scale component of every operation. Otherwise,
  // returns false.
  bool ScaleComponent(SkScalar* scale) const;

  void AppendTranslate(SkScalar x, SkScalar y, SkScalar z);
  void AppendRotate(SkScalar x, SkScalar y, SkScalar z, SkScalar degrees);
  void AppendScale(SkScalar x, SkScalar y, SkScalar z);
  void AppendSkewX(SkScalar x);
  void AppendSkewY(SkScalar y);
  void AppendSkew(SkScalar x, SkScalar y);
  void AppendPerspective(std::optional<SkScalar> depth);
  void AppendMatrix(const Transform& matrix);
  void AppendIdentity();
  void Append(const TransformOperation& operation);
  bool IsIdentity() const;

  size_t size() const { return operations_.size(); }

  const TransformOperation& at(size_t index) const {
    DCHECK_LT(index, size());
    return operations_[index];
  }
  TransformOperation& at(size_t index) {
    DCHECK_LT(index, size());
    return operations_[index];
  }

  bool ApproximatelyEqual(const TransformOperations& other,
                          SkScalar tolerance) const;

 private:
  FRIEND_TEST_ALL_PREFIXES(TransformOperationsTest, TestDecompositionCache);

  bool BlendInternal(const TransformOperations& from,
                     SkScalar progress,
                     TransformOperations* result) const;

  std::vector<TransformOperation> operations_;

  bool ComputeDecomposedTransform(size_t start_offset) const;

  // For efficiency, we cache the decomposed transforms.
  mutable std::unordered_map<size_t, std::unique_ptr<DecomposedTransform>>
      decomposed_transforms_;
};

}  // namespace gfx

#endif  // UI_GFX_GEOMETRY_TRANSFORM_OPERATIONS_H_