| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 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 #include "cc/trees/property_tree_builder.h" | |
| 6 | |
| 7 #include <map> | |
| 8 #include <set> | |
| 9 | |
| 10 #include "cc/base/math_util.h" | |
| 11 #include "cc/layers/layer.h" | |
| 12 #include "cc/trees/layer_tree_host.h" | |
| 13 #include "ui/gfx/geometry/point_f.h" | |
| 14 | |
| 15 namespace cc { | |
| 16 | |
| 17 class LayerTreeHost; | |
| 18 | |
| 19 namespace { | |
| 20 | |
| 21 struct DataForRecursion { | |
| 22 TransformTree* transform_tree; | |
| 23 ClipTree* clip_tree; | |
| 24 OpacityTree* opacity_tree; | |
| 25 Layer* transform_tree_parent; | |
| 26 Layer* transform_fixed_parent; | |
| 27 Layer* render_target; | |
| 28 int clip_tree_parent; | |
| 29 int opacity_tree_parent; | |
| 30 const Layer* page_scale_layer; | |
| 31 float page_scale_factor; | |
| 32 float device_scale_factor; | |
| 33 bool in_subtree_of_page_scale_application_layer; | |
| 34 bool should_flatten; | |
| 35 const gfx::Transform* device_transform; | |
| 36 }; | |
| 37 | |
| 38 static Layer* GetTransformParent(const DataForRecursion& data, Layer* layer) { | |
| 39 return layer->position_constraint().is_fixed_position() | |
| 40 ? data.transform_fixed_parent | |
| 41 : data.transform_tree_parent; | |
| 42 } | |
| 43 | |
| 44 static ClipNode* GetClipParent(const DataForRecursion& data, Layer* layer) { | |
| 45 const bool inherits_clip = !layer->parent() || !layer->clip_parent(); | |
| 46 const int id = inherits_clip ? data.clip_tree_parent | |
| 47 : layer->clip_parent()->clip_tree_index(); | |
| 48 return data.clip_tree->Node(id); | |
| 49 } | |
| 50 | |
| 51 static bool RequiresClipNode(Layer* layer, | |
| 52 bool axis_aligned_with_respect_to_parent) { | |
| 53 const bool render_surface_applies_non_axis_aligned_clip = | |
| 54 layer->render_surface() && !axis_aligned_with_respect_to_parent && | |
| 55 layer->is_clipped(); | |
| 56 const bool render_surface_may_grow_due_to_clip_children = | |
| 57 layer->render_surface() && layer->num_unclipped_descendants() > 0; | |
| 58 | |
| 59 return !layer->parent() || layer->masks_to_bounds() || layer->mask_layer() || | |
| 60 render_surface_applies_non_axis_aligned_clip || | |
| 61 render_surface_may_grow_due_to_clip_children; | |
| 62 } | |
| 63 | |
| 64 void AddClipNodeIfNeeded(const DataForRecursion& data_from_ancestor, | |
| 65 Layer* layer, | |
| 66 DataForRecursion* data_for_children) { | |
| 67 ClipNode* parent = GetClipParent(data_from_ancestor, layer); | |
| 68 int parent_id = parent->id; | |
| 69 const bool axis_aligned_with_respect_to_parent = | |
| 70 data_from_ancestor.transform_tree->Are2DAxisAligned( | |
| 71 layer->transform_tree_index(), parent->data.transform_id); | |
| 72 | |
| 73 // TODO(vollick): once Andrew refactors the surface determinations out of | |
| 74 // CDP, the the layer->render_surface() check will be invalid. | |
| 75 const bool has_unclipped_surface = | |
| 76 layer->render_surface() && | |
| 77 !layer->render_surface()->is_clipped() && | |
| 78 layer->num_unclipped_descendants() == 0; | |
| 79 | |
| 80 if (has_unclipped_surface) | |
| 81 parent_id = 0; | |
| 82 | |
| 83 if (!RequiresClipNode(layer, axis_aligned_with_respect_to_parent)) { | |
| 84 // Unclipped surfaces reset the clip rect. | |
| 85 data_for_children->clip_tree_parent = parent_id; | |
| 86 } else if (layer->parent()) { | |
| 87 // Note the root clip gets handled elsewhere. | |
| 88 Layer* transform_parent = GetTransformParent(*data_for_children, layer); | |
| 89 ClipNode node; | |
| 90 node.data.clip = gfx::RectF( | |
| 91 gfx::PointF() + layer->offset_to_transform_parent(), layer->bounds()); | |
| 92 node.data.transform_id = transform_parent->transform_tree_index(); | |
| 93 node.data.target_id = | |
| 94 data_from_ancestor.render_target->transform_tree_index(); | |
| 95 | |
| 96 data_for_children->clip_tree_parent = | |
| 97 data_for_children->clip_tree->Insert(node, parent_id); | |
| 98 } | |
| 99 | |
| 100 layer->set_clip_tree_index( | |
| 101 has_unclipped_surface ? 0 : data_for_children->clip_tree_parent); | |
| 102 | |
| 103 // TODO(awoloszyn): Right now when we hit a node with a replica, we reset the | |
| 104 // clip for all children since we may need to draw. We need to figure out a | |
| 105 // better way, since we will need both the clipped and unclipped versions. | |
| 106 } | |
| 107 | |
| 108 void AddTransformNodeIfNeeded(const DataForRecursion& data_from_ancestor, | |
| 109 Layer* layer, | |
| 110 DataForRecursion* data_for_children) { | |
| 111 const bool is_root = !layer->parent(); | |
| 112 const bool is_page_scale_application_layer = | |
| 113 layer->parent() && layer->parent() == data_from_ancestor.page_scale_layer; | |
| 114 const bool is_scrollable = layer->scrollable(); | |
| 115 const bool is_fixed = layer->position_constraint().is_fixed_position(); | |
| 116 | |
| 117 const bool has_significant_transform = | |
| 118 !layer->transform().IsIdentityOr2DTranslation(); | |
| 119 | |
| 120 const bool has_animated_transform = | |
| 121 layer->layer_animation_controller()->IsAnimatingProperty( | |
| 122 Animation::TRANSFORM); | |
| 123 | |
| 124 const bool has_surface = !!layer->render_surface(); | |
| 125 | |
| 126 bool requires_node = is_root || is_scrollable || has_significant_transform || | |
| 127 has_animated_transform || has_surface || | |
| 128 is_page_scale_application_layer; | |
| 129 | |
| 130 Layer* transform_parent = GetTransformParent(data_from_ancestor, layer); | |
| 131 | |
| 132 gfx::Vector2dF parent_offset; | |
| 133 if (transform_parent) { | |
| 134 if (layer->scroll_parent()) { | |
| 135 gfx::Transform to_parent; | |
| 136 Layer* source = layer->parent(); | |
| 137 parent_offset += source->offset_to_transform_parent(); | |
| 138 data_from_ancestor.transform_tree->ComputeTransform( | |
| 139 source->transform_tree_index(), | |
| 140 transform_parent->transform_tree_index(), &to_parent); | |
| 141 parent_offset += to_parent.To2dTranslation(); | |
| 142 } else if (!is_fixed) { | |
| 143 parent_offset = transform_parent->offset_to_transform_parent(); | |
| 144 } else if (data_from_ancestor.transform_tree_parent != | |
| 145 data_from_ancestor.transform_fixed_parent) { | |
| 146 gfx::Vector2dF fixed_offset = data_from_ancestor.transform_tree_parent | |
| 147 ->offset_to_transform_parent(); | |
| 148 gfx::Transform parent_to_parent; | |
| 149 data_from_ancestor.transform_tree->ComputeTransform( | |
| 150 data_from_ancestor.transform_tree_parent->transform_tree_index(), | |
| 151 data_from_ancestor.transform_fixed_parent->transform_tree_index(), | |
| 152 &parent_to_parent); | |
| 153 | |
| 154 fixed_offset += parent_to_parent.To2dTranslation(); | |
| 155 parent_offset += fixed_offset; | |
| 156 } | |
| 157 } | |
| 158 | |
| 159 if (layer->IsContainerForFixedPositionLayers() || is_root) | |
| 160 data_for_children->transform_fixed_parent = layer; | |
| 161 data_for_children->transform_tree_parent = layer; | |
| 162 | |
| 163 if (!requires_node) { | |
| 164 data_for_children->should_flatten |= layer->should_flatten_transform(); | |
| 165 gfx::Vector2dF local_offset = layer->position().OffsetFromOrigin() + | |
| 166 layer->transform().To2dTranslation(); | |
| 167 layer->set_offset_to_transform_parent(parent_offset + local_offset); | |
| 168 layer->set_should_flatten_transform_from_property_tree( | |
| 169 data_from_ancestor.should_flatten); | |
| 170 layer->set_transform_tree_index(transform_parent->transform_tree_index()); | |
| 171 return; | |
| 172 } | |
| 173 | |
| 174 int parent_index = 0; | |
| 175 if (transform_parent) | |
| 176 parent_index = transform_parent->transform_tree_index(); | |
| 177 | |
| 178 data_for_children->transform_tree->Insert(TransformNode(), parent_index); | |
| 179 | |
| 180 TransformNode* node = data_for_children->transform_tree->back(); | |
| 181 layer->set_transform_tree_index(node->id); | |
| 182 | |
| 183 node->data.scrolls = is_scrollable; | |
| 184 node->data.flattens_inherited_transform = data_for_children->should_flatten; | |
| 185 | |
| 186 // Surfaces inherently flatten transforms. | |
| 187 data_for_children->should_flatten = | |
| 188 layer->should_flatten_transform() || has_surface; | |
| 189 node->data.target_id = | |
| 190 data_from_ancestor.render_target->transform_tree_index(); | |
| 191 node->data.content_target_id = | |
| 192 data_for_children->render_target->transform_tree_index(); | |
| 193 DCHECK_NE(node->data.target_id, -1); | |
| 194 node->data.is_animated = layer->TransformIsAnimating(); | |
| 195 | |
| 196 float scale_factors = 1.0f; | |
| 197 if (is_root) { | |
| 198 node->data.post_local = *data_from_ancestor.device_transform; | |
| 199 scale_factors = data_from_ancestor.device_scale_factor; | |
| 200 } | |
| 201 | |
| 202 if (is_page_scale_application_layer) | |
| 203 scale_factors *= data_from_ancestor.page_scale_factor; | |
| 204 | |
| 205 if (has_surface && !is_root) { | |
| 206 node->data.needs_sublayer_scale = true; | |
| 207 node->data.layer_scale_factor = data_from_ancestor.device_scale_factor; | |
| 208 if (data_from_ancestor.in_subtree_of_page_scale_application_layer) | |
| 209 node->data.layer_scale_factor *= data_from_ancestor.page_scale_factor; | |
| 210 } | |
| 211 | |
| 212 node->data.post_local.Scale(scale_factors, scale_factors); | |
| 213 node->data.post_local.Translate3d( | |
| 214 layer->position().x() + parent_offset.x() + layer->transform_origin().x(), | |
| 215 layer->position().y() + parent_offset.y() + layer->transform_origin().y(), | |
| 216 layer->transform_origin().z()); | |
| 217 | |
| 218 if (!layer->scroll_parent()) { | |
| 219 node->data.scroll_offset = | |
| 220 gfx::ScrollOffsetToVector2dF(layer->CurrentScrollOffset()); | |
| 221 } | |
| 222 | |
| 223 node->data.local = layer->transform(); | |
| 224 node->data.pre_local.Translate3d(-layer->transform_origin().x(), | |
| 225 -layer->transform_origin().y(), | |
| 226 -layer->transform_origin().z()); | |
| 227 | |
| 228 node->data.needs_local_transform_update = true; | |
| 229 data_from_ancestor.transform_tree->UpdateTransforms(node->id); | |
| 230 | |
| 231 layer->set_offset_to_transform_parent(gfx::Vector2dF()); | |
| 232 | |
| 233 // Flattening (if needed) will be handled by |node|. | |
| 234 layer->set_should_flatten_transform_from_property_tree(false); | |
| 235 } | |
| 236 | |
| 237 void AddOpacityNodeIfNeeded(const DataForRecursion& data_from_ancestor, | |
| 238 Layer* layer, | |
| 239 DataForRecursion* data_for_children) { | |
| 240 const bool is_root = !layer->parent(); | |
| 241 const bool has_transparency = layer->opacity() != 1.f; | |
| 242 const bool has_animated_opacity = | |
| 243 layer->layer_animation_controller()->IsAnimatingProperty( | |
| 244 Animation::OPACITY) || | |
| 245 layer->OpacityCanAnimateOnImplThread(); | |
| 246 bool requires_node = is_root || has_transparency || has_animated_opacity; | |
| 247 | |
| 248 int parent_id = data_from_ancestor.opacity_tree_parent; | |
| 249 | |
| 250 if (!requires_node) { | |
| 251 layer->set_opacity_tree_index(parent_id); | |
| 252 data_for_children->opacity_tree_parent = parent_id; | |
| 253 return; | |
| 254 } | |
| 255 | |
| 256 OpacityNode node; | |
| 257 node.data = layer->opacity(); | |
| 258 data_for_children->opacity_tree_parent = | |
| 259 data_for_children->opacity_tree->Insert(node, parent_id); | |
| 260 layer->set_opacity_tree_index(data_for_children->opacity_tree_parent); | |
| 261 } | |
| 262 | |
| 263 void BuildPropertyTreesInternal(Layer* layer, | |
| 264 const DataForRecursion& data_from_parent) { | |
| 265 DataForRecursion data_for_children(data_from_parent); | |
| 266 if (layer->render_surface()) | |
| 267 data_for_children.render_target = layer; | |
| 268 | |
| 269 AddTransformNodeIfNeeded(data_from_parent, layer, &data_for_children); | |
| 270 AddClipNodeIfNeeded(data_from_parent, layer, &data_for_children); | |
| 271 | |
| 272 if (data_from_parent.opacity_tree) | |
| 273 AddOpacityNodeIfNeeded(data_from_parent, layer, &data_for_children); | |
| 274 | |
| 275 if (layer == data_from_parent.page_scale_layer) | |
| 276 data_for_children.in_subtree_of_page_scale_application_layer = true; | |
| 277 | |
| 278 for (size_t i = 0; i < layer->children().size(); ++i) { | |
| 279 if (!layer->children()[i]->scroll_parent()) | |
| 280 BuildPropertyTreesInternal(layer->children()[i].get(), data_for_children); | |
| 281 } | |
| 282 | |
| 283 if (layer->scroll_children()) { | |
| 284 for (Layer* scroll_child : *layer->scroll_children()) { | |
| 285 BuildPropertyTreesInternal(scroll_child, data_for_children); | |
| 286 } | |
| 287 } | |
| 288 | |
| 289 if (layer->has_replica()) | |
| 290 BuildPropertyTreesInternal(layer->replica_layer(), data_for_children); | |
| 291 } | |
| 292 | |
| 293 } // namespace | |
| 294 | |
| 295 void PropertyTreeBuilder::BuildPropertyTrees( | |
| 296 Layer* root_layer, | |
| 297 const Layer* page_scale_layer, | |
| 298 float page_scale_factor, | |
| 299 float device_scale_factor, | |
| 300 const gfx::Rect& viewport, | |
| 301 const gfx::Transform& device_transform, | |
| 302 TransformTree* transform_tree, | |
| 303 ClipTree* clip_tree, | |
| 304 OpacityTree* opacity_tree) { | |
| 305 DataForRecursion data_for_recursion; | |
| 306 data_for_recursion.transform_tree = transform_tree; | |
| 307 data_for_recursion.clip_tree = clip_tree; | |
| 308 data_for_recursion.opacity_tree = opacity_tree; | |
| 309 data_for_recursion.transform_tree_parent = nullptr; | |
| 310 data_for_recursion.transform_fixed_parent = nullptr; | |
| 311 data_for_recursion.render_target = root_layer; | |
| 312 data_for_recursion.clip_tree_parent = 0; | |
| 313 data_for_recursion.opacity_tree_parent = -1; | |
| 314 data_for_recursion.page_scale_layer = page_scale_layer; | |
| 315 data_for_recursion.page_scale_factor = page_scale_factor; | |
| 316 data_for_recursion.device_scale_factor = device_scale_factor; | |
| 317 data_for_recursion.in_subtree_of_page_scale_application_layer = false; | |
| 318 data_for_recursion.should_flatten = false; | |
| 319 data_for_recursion.device_transform = &device_transform; | |
| 320 | |
| 321 ClipNode root_clip; | |
| 322 root_clip.data.clip = viewport; | |
| 323 root_clip.data.transform_id = 0; | |
| 324 data_for_recursion.clip_tree_parent = clip_tree->Insert(root_clip, 0); | |
| 325 BuildPropertyTreesInternal(root_layer, data_for_recursion); | |
| 326 } | |
| 327 | |
| 328 } // namespace cc | |
| OLD | NEW |