1 // Copyright 2017 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 5 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_PAINT_GEOMETRY_MAPPER_TRANSFORM_CACHE_H_ 6 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_PAINT_GEOMETRY_MAPPER_TRANSFORM_CACHE_H_ 7 8 #include "third_party/blink/renderer/platform/platform_export.h" 9 10 #include "third_party/blink/renderer/platform/transforms/transformation_matrix.h" 11 12 namespace blink { 13 14 class TransformPaintPropertyNode; 15 16 // A GeometryMapperTransformCache hangs off a TransformPaintPropertyNode. 17 // It stores useful intermediate results such as screen matrix for geometry 18 // queries. 19 class PLATFORM_EXPORT GeometryMapperTransformCache { 20 USING_FAST_MALLOC(GeometryMapperTransformCache); 21 public: 22 GeometryMapperTransformCache() = default; 23 24 static void ClearCache(); 25 bool IsValid() const; 26 UpdateIfNeeded(const TransformPaintPropertyNode & node)27 void UpdateIfNeeded(const TransformPaintPropertyNode& node) { 28 if (cache_generation_ != s_global_generation) 29 Update(node); 30 DCHECK_EQ(cache_generation_, s_global_generation); 31 } 32 to_2d_translation_root()33 const FloatSize& to_2d_translation_root() const { 34 return to_2d_translation_root_; 35 } root_of_2d_translation()36 const TransformPaintPropertyNode* root_of_2d_translation() const { 37 return root_of_2d_translation_; 38 } 39 40 // As screen transform data are used rarely, they are updated only when 41 // needed. This method must be called before calling any screen transform 42 // related getters. 43 void UpdateScreenTransform(const TransformPaintPropertyNode&); 44 45 // These getters must be called after UpdateScreenTransform() when screen 46 // transform data is really needed. to_screen()47 const TransformationMatrix& to_screen() const { 48 DCHECK(screen_transform_); 49 return screen_transform_->to_screen; 50 } projection_from_screen()51 const TransformationMatrix& projection_from_screen() const { 52 DCHECK(screen_transform_); 53 return screen_transform_->projection_from_screen; 54 } projection_from_screen_is_valid()55 bool projection_from_screen_is_valid() const { 56 #if DCHECK_IS_ON() 57 CheckScreenTransformUpdated(); 58 #endif 59 return LIKELY(!screen_transform_) || 60 screen_transform_->projection_from_screen_is_valid; 61 } ApplyToScreen(TransformationMatrix & m)62 void ApplyToScreen(TransformationMatrix& m) const { 63 if (UNLIKELY(screen_transform_)) 64 m.Multiply(to_screen()); 65 else 66 ApplyToPlaneRoot(m); 67 } ApplyProjectionFromScreen(TransformationMatrix & m)68 void ApplyProjectionFromScreen(TransformationMatrix& m) const { 69 if (UNLIKELY(screen_transform_)) 70 m.Multiply(projection_from_screen()); 71 else 72 ApplyFromPlaneRoot(m); 73 } has_animation_to_screen()74 bool has_animation_to_screen() const { 75 #if DCHECK_IS_ON() 76 CheckScreenTransformUpdated(); 77 #endif 78 return UNLIKELY(screen_transform_) ? screen_transform_->has_animation 79 : has_animation_to_plane_root(); 80 } 81 to_plane_root()82 const TransformationMatrix& to_plane_root() const { 83 DCHECK(plane_root_transform_); 84 return plane_root_transform_->to_plane_root; 85 } from_plane_root()86 const TransformationMatrix& from_plane_root() const { 87 DCHECK(plane_root_transform_); 88 return plane_root_transform_->from_plane_root; 89 } ApplyToPlaneRoot(TransformationMatrix & m)90 void ApplyToPlaneRoot(TransformationMatrix& m) const { 91 if (UNLIKELY(plane_root_transform_)) { 92 m.Multiply(to_plane_root()); 93 } else { 94 m.Translate(to_2d_translation_root_.Width(), 95 to_2d_translation_root_.Height()); 96 } 97 } ApplyFromPlaneRoot(TransformationMatrix & m)98 void ApplyFromPlaneRoot(TransformationMatrix& m) const { 99 if (UNLIKELY(plane_root_transform_)) { 100 m.Multiply(from_plane_root()); 101 } else { 102 m.Translate(-to_2d_translation_root_.Width(), 103 -to_2d_translation_root_.Height()); 104 } 105 } plane_root()106 const TransformPaintPropertyNode* plane_root() const { 107 return UNLIKELY(plane_root_transform_) ? plane_root_transform_->plane_root 108 : root_of_2d_translation(); 109 } has_animation_to_plane_root()110 bool has_animation_to_plane_root() const { 111 return UNLIKELY(plane_root_transform_) && 112 plane_root_transform_->has_animation; 113 } 114 115 private: 116 friend class GeometryMapperTransformCacheTest; 117 118 #if DCHECK_IS_ON() 119 void CheckScreenTransformUpdated() const; 120 #endif 121 122 void Update(const TransformPaintPropertyNode&); 123 124 static unsigned s_global_generation; 125 126 // The accumulated 2d translation to root_of_2d_translation(). 127 FloatSize to_2d_translation_root_; 128 129 // The parent of the root of consecutive identity or 2d translations from the 130 // transform node, or the root of the tree if the whole path from the 131 // transform node to the root contains identity or 2d translations only. 132 const TransformPaintPropertyNode* root_of_2d_translation_; 133 134 // The cached values here can be categorized in two logical groups: 135 // 136 // [ Screen Transform ] 137 // to_screen : The screen matrix of the node, as defined by: 138 // to_screen = (flattens_inherited_transform ? 139 // flatten(parent.to_screen) : parent.to_screen) * local 140 // projection_from_screen : Back projection from screen. 141 // projection_from_screen = flatten(to_screen) ^ -1 142 // Undefined if the inverse projection doesn't exist. 143 // Guaranteed to be flat. 144 // projection_from_screen_is_valid : Whether projection_from_screen 145 // is defined. 146 // 147 // [ Plane Root Transform ] 148 // plane_root : The oldest ancestor node such that every intermediate node 149 // in the ancestor chain has a flat and invertible local matrix. In other 150 // words, a node inherits its parent's plane_root if its local matrix is 151 // flat and invertible. Otherwise, it becomes its own plane root. 152 // For example: 153 // <xfrm id="A" matrix="rotateY(10deg)"> 154 // <xfrm id="B" flatten_inherited matrix="translateX(10px)"/> 155 // <xfrm id="C" matrix="scaleX(0)"> 156 // <xfrm id="D" matrix="scaleX(2)"/> 157 // <xfrm id="E" matrix="rotate(30deg)"/> 158 // </xfrm> 159 // <xfrm id="F" matrix="scaleZ(0)"/> 160 // </xfrm> 161 // A is the plane root of itself because its local matrix is 3D. 162 // B's plane root is A because its local matrix is flat. 163 // C is the plane root of itself because its local matrix is non-invertible. 164 // D and E's plane root is C because their local matrix is flat. 165 // F is the plane root of itself because its local matrix is 3D and 166 // non-invertible. 167 // to_plane_root : The accumulated matrix between this node and plane_root. 168 // to_plane_root = (plane_root == this) ? I : parent.to_plane_root * local 169 // Guaranteed to be flat. 170 // from_plane_root : 171 // from_plane_root = to_plane_root ^ -1 172 // Guaranteed to exist because each local matrices are invertible. 173 // Guaranteed to be flat. 174 // An important invariant is that 175 // flatten(to_screen) = flatten(plane_root.to_screen) * to_plane_root 176 // Proof by induction: 177 // If plane_root == this, 178 // flatten(plane_root.to_screen) * to_plane_root = flatten(to_screen) * I 179 // = flatten(to_screen) 180 // Otherwise, 181 // flatten(to_screen) = flatten((flattens_inherited_transform ? 182 // flatten(parent.to_screen) : parent.to_screen) * local) 183 // Because local is known to be flat, 184 // = flatten((flattens_inherited_transform ? 185 // flatten(parent.to_screen) : parent.to_screen) * flatten(local)) 186 // Then by flatten lemma (https://goo.gl/DNKyOc), 187 // = flatten(parent.to_screen) * local 188 // = flatten(parent.plane_root.to_screen) * parent.to_plane_root * local 189 // = flatten(plane_root.to_screen) * to_plane_root 190 struct PlaneRootTransform { 191 TransformationMatrix to_plane_root; 192 TransformationMatrix from_plane_root; 193 const TransformPaintPropertyNode* plane_root; 194 bool has_animation; 195 }; 196 std::unique_ptr<PlaneRootTransform> plane_root_transform_; 197 198 struct ScreenTransform { 199 TransformationMatrix to_screen; 200 TransformationMatrix projection_from_screen; 201 bool projection_from_screen_is_valid; 202 bool has_animation; 203 }; 204 std::unique_ptr<ScreenTransform> screen_transform_; 205 206 unsigned cache_generation_ = s_global_generation - 1; 207 DISALLOW_COPY_AND_ASSIGN(GeometryMapperTransformCache); 208 }; 209 210 } // namespace blink 211 212 #endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_PAINT_GEOMETRY_MAPPER_TRANSFORM_CACHE_H_ 213