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/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 Layer* transform_tree_parent; |
| 25 Layer* transform_fixed_parent; |
| 26 Layer* render_target; |
| 27 int clip_tree_parent; |
| 28 gfx::Vector2dF offset_to_transform_tree_parent; |
| 29 gfx::Vector2dF offset_to_transform_fixed_parent; |
| 30 const Layer* page_scale_layer; |
| 31 float page_scale_factor; |
| 32 float device_scale_factor; |
| 33 }; |
| 34 |
| 35 static Layer* GetTransformParent(const DataForRecursion& data, Layer* layer) { |
| 36 return layer->position_constraint().is_fixed_position() |
| 37 ? data.transform_fixed_parent |
| 38 : data.transform_tree_parent; |
| 39 } |
| 40 |
| 41 static ClipNode* GetClipParent(const DataForRecursion& data, Layer* layer) { |
| 42 const bool inherits_clip = !layer->parent() || !layer->clip_parent(); |
| 43 const int id = inherits_clip ? data.clip_tree_parent |
| 44 : layer->clip_parent()->clip_tree_index(); |
| 45 return data.clip_tree->Node(id); |
| 46 } |
| 47 |
| 48 static bool RequiresClipNode(Layer* layer, |
| 49 bool axis_aligned_with_respect_to_parent) { |
| 50 const bool render_surface_applies_non_axis_aligned_clip = |
| 51 layer->render_surface() && !axis_aligned_with_respect_to_parent && |
| 52 layer->is_clipped(); |
| 53 const bool render_surface_may_grow_due_to_clip_children = |
| 54 layer->render_surface() && layer->num_unclipped_descendants() > 0; |
| 55 |
| 56 return !layer->parent() || layer->masks_to_bounds() || layer->mask_layer() || |
| 57 render_surface_applies_non_axis_aligned_clip || |
| 58 render_surface_may_grow_due_to_clip_children; |
| 59 } |
| 60 |
| 61 void AddClipNodeIfNeeded(const DataForRecursion& data_from_ancestor, |
| 62 Layer* layer, |
| 63 DataForRecursion* data_for_children) { |
| 64 ClipNode* parent = GetClipParent(data_from_ancestor, layer); |
| 65 int parent_id = parent->id; |
| 66 const bool axis_aligned_with_respect_to_parent = |
| 67 data_from_ancestor.transform_tree->Are2DAxisAligned( |
| 68 layer->transform_tree_index(), parent->data.transform_id); |
| 69 |
| 70 // TODO(vollick): once Andrew refactors the surface determinations out of |
| 71 // CDP, the the layer->render_surface() check will be invalid. |
| 72 const bool has_unclipped_surface = |
| 73 layer->render_surface() && |
| 74 !layer->render_surface()->is_clipped() && |
| 75 layer->num_unclipped_descendants() == 0; |
| 76 |
| 77 if (has_unclipped_surface) |
| 78 parent_id = 0; |
| 79 |
| 80 if (!RequiresClipNode(layer, axis_aligned_with_respect_to_parent)) { |
| 81 // Unclipped surfaces reset the clip rect. |
| 82 data_for_children->clip_tree_parent = parent_id; |
| 83 } else if (layer->parent()) { |
| 84 // Note the root clip gets handled elsewhere. |
| 85 Layer* transform_parent = GetTransformParent(*data_for_children, layer); |
| 86 ClipNode node; |
| 87 node.data.clip = gfx::RectF( |
| 88 gfx::PointF() + layer->offset_to_transform_parent(), layer->bounds()); |
| 89 node.data.transform_id = transform_parent->transform_tree_index(); |
| 90 node.data.target_id = |
| 91 data_from_ancestor.render_target->transform_tree_index(); |
| 92 |
| 93 data_for_children->clip_tree_parent = |
| 94 data_for_children->clip_tree->Insert(node, parent_id); |
| 95 } |
| 96 |
| 97 layer->set_clip_tree_index( |
| 98 has_unclipped_surface ? 0 : data_for_children->clip_tree_parent); |
| 99 |
| 100 // TODO(awoloszyn): Right now when we hit a node with a replica, we reset the |
| 101 // clip for all children since we may need to draw. We need to figure out a |
| 102 // better way, since we will need both the clipped and unclipped versions. |
| 103 } |
| 104 |
| 105 void AddTransformNodeIfNeeded(const DataForRecursion& data_from_ancestor, |
| 106 Layer* layer, |
| 107 DataForRecursion* data_for_children) { |
| 108 const bool is_root = !layer->parent(); |
| 109 const bool is_page_scale_application_layer = |
| 110 layer->parent() && layer->parent() == data_from_ancestor.page_scale_layer; |
| 111 const bool is_scrollable = layer->scrollable(); |
| 112 const bool is_fixed = layer->position_constraint().is_fixed_position(); |
| 113 |
| 114 const bool has_significant_transform = |
| 115 !layer->transform().IsIdentityOrTranslation(); |
| 116 |
| 117 const bool has_animated_transform = |
| 118 layer->layer_animation_controller()->IsAnimatingProperty( |
| 119 Animation::Transform); |
| 120 |
| 121 const bool has_transform_origin = layer->transform_origin() != gfx::Point3F(); |
| 122 |
| 123 const bool has_surface = !!layer->render_surface(); |
| 124 |
| 125 const bool flattening_change = layer->parent() && |
| 126 layer->should_flatten_transform() && |
| 127 !layer->parent()->should_flatten_transform(); |
| 128 |
| 129 bool requires_node = is_root || is_scrollable || is_fixed || |
| 130 has_significant_transform || has_animated_transform || |
| 131 is_page_scale_application_layer || flattening_change || |
| 132 has_transform_origin || has_surface; |
| 133 |
| 134 Layer* transform_parent = GetTransformParent(data_from_ancestor, layer); |
| 135 |
| 136 // May be non-zero if layer is fixed or has a scroll parent. |
| 137 gfx::Vector2dF parent_offset; |
| 138 if (transform_parent) { |
| 139 // TODO(vollick): This is to mimic existing bugs (crbug.com/441447). |
| 140 if (!is_fixed) |
| 141 parent_offset = transform_parent->offset_to_transform_parent(); |
| 142 |
| 143 gfx::Transform to_parent; |
| 144 Layer* source = data_from_ancestor.transform_tree_parent; |
| 145 if (layer->scroll_parent()) { |
| 146 source = layer->parent(); |
| 147 parent_offset += layer->parent()->offset_to_transform_parent(); |
| 148 } |
| 149 data_from_ancestor.transform_tree->ComputeTransform( |
| 150 source->transform_tree_index(), |
| 151 transform_parent->transform_tree_index(), &to_parent); |
| 152 |
| 153 parent_offset += to_parent.To2dTranslation(); |
| 154 } |
| 155 |
| 156 if (layer->IsContainerForFixedPositionLayers() || is_root) |
| 157 data_for_children->transform_fixed_parent = layer; |
| 158 data_for_children->transform_tree_parent = layer; |
| 159 |
| 160 if (!requires_node) { |
| 161 gfx::Vector2dF local_offset = layer->position().OffsetFromOrigin() + |
| 162 layer->transform().To2dTranslation(); |
| 163 layer->set_offset_to_transform_parent(parent_offset + local_offset); |
| 164 layer->set_transform_tree_index(transform_parent->transform_tree_index()); |
| 165 return; |
| 166 } |
| 167 |
| 168 if (!is_root) { |
| 169 data_for_children->transform_tree->Insert( |
| 170 TransformNode(), transform_parent->transform_tree_index()); |
| 171 } |
| 172 |
| 173 TransformNode* node = data_for_children->transform_tree->back(); |
| 174 |
| 175 node->data.flattens = layer->should_flatten_transform(); |
| 176 node->data.target_id = |
| 177 data_from_ancestor.render_target->transform_tree_index(); |
| 178 node->data.is_animated = layer->TransformIsAnimating(); |
| 179 |
| 180 gfx::Transform transform; |
| 181 float device_and_page_scale_factors = 1.0f; |
| 182 if (is_root) |
| 183 device_and_page_scale_factors = data_from_ancestor.device_scale_factor; |
| 184 if (is_page_scale_application_layer) |
| 185 device_and_page_scale_factors *= data_from_ancestor.page_scale_factor; |
| 186 |
| 187 transform.Scale(device_and_page_scale_factors, device_and_page_scale_factors); |
| 188 |
| 189 // TODO(vollick): We've accounted for the scroll offset here but we haven't |
| 190 // taken into account snapping to screen space pixels. For the purposes of |
| 191 // computing rects we need to record, this should be fine (the visible rects |
| 192 // we compute may be slightly different than what we'd compute with snapping, |
| 193 // but since we significantly expand the visible rect when determining what to |
| 194 // record, the slight difference should be inconsequential). |
| 195 gfx::Vector2dF position = layer->position().OffsetFromOrigin(); |
| 196 if (!layer->scroll_parent()) { |
| 197 position -= gfx::Vector2dF(layer->TotalScrollOffset().x(), |
| 198 layer->TotalScrollOffset().y()); |
| 199 } |
| 200 |
| 201 position += parent_offset; |
| 202 |
| 203 transform.Translate3d(position.x() + layer->transform_origin().x(), |
| 204 position.y() + layer->transform_origin().y(), |
| 205 layer->transform_origin().z()); |
| 206 transform.PreconcatTransform(layer->transform()); |
| 207 transform.Translate3d(-layer->transform_origin().x(), |
| 208 -layer->transform_origin().y(), |
| 209 -layer->transform_origin().z()); |
| 210 |
| 211 node->data.to_parent = transform; |
| 212 node->data.is_invertible = transform.GetInverse(&node->data.from_parent); |
| 213 |
| 214 data_from_ancestor.transform_tree->UpdateScreenSpaceTransform(node->id); |
| 215 |
| 216 layer->set_offset_to_transform_parent(gfx::Vector2dF()); |
| 217 layer->set_transform_tree_index(node->id); |
| 218 } |
| 219 |
| 220 void BuildPropertyTreesInternal(Layer* layer, |
| 221 const DataForRecursion& data_from_parent) { |
| 222 DataForRecursion data_for_children(data_from_parent); |
| 223 if (layer->render_surface()) |
| 224 data_for_children.render_target = layer; |
| 225 |
| 226 AddTransformNodeIfNeeded(data_from_parent, layer, &data_for_children); |
| 227 AddClipNodeIfNeeded(data_from_parent, layer, &data_for_children); |
| 228 |
| 229 for (size_t i = 0; i < layer->children().size(); ++i) { |
| 230 if (!layer->children()[i]->scroll_parent()) |
| 231 BuildPropertyTreesInternal(layer->children()[i].get(), data_for_children); |
| 232 } |
| 233 |
| 234 if (layer->scroll_children()) { |
| 235 for (Layer* scroll_child : *layer->scroll_children()) { |
| 236 BuildPropertyTreesInternal(scroll_child, data_for_children); |
| 237 } |
| 238 } |
| 239 |
| 240 if (layer->has_replica()) |
| 241 BuildPropertyTreesInternal(layer->replica_layer(), data_for_children); |
| 242 } |
| 243 |
| 244 } // namespace |
| 245 |
| 246 void PropertyTreeBuilder::BuildPropertyTrees( |
| 247 Layer* root_layer, |
| 248 const Layer* page_scale_layer, |
| 249 float page_scale_factor, |
| 250 float device_scale_factor, |
| 251 const gfx::Rect& viewport, |
| 252 const gfx::Transform& device_transform, |
| 253 TransformTree* transform_tree, |
| 254 ClipTree* clip_tree) { |
| 255 DataForRecursion data_for_recursion; |
| 256 data_for_recursion.transform_tree = transform_tree; |
| 257 data_for_recursion.clip_tree = clip_tree; |
| 258 data_for_recursion.transform_tree_parent = nullptr; |
| 259 data_for_recursion.transform_fixed_parent = nullptr; |
| 260 data_for_recursion.render_target = root_layer; |
| 261 data_for_recursion.clip_tree_parent = 0; |
| 262 data_for_recursion.page_scale_layer = page_scale_layer; |
| 263 data_for_recursion.page_scale_factor = page_scale_factor; |
| 264 data_for_recursion.device_scale_factor = device_scale_factor; |
| 265 |
| 266 int transform_root_id = transform_tree->Insert(TransformNode(), 0); |
| 267 |
| 268 ClipNode root_clip; |
| 269 root_clip.data.clip = viewport; |
| 270 root_clip.data.transform_id = 0; |
| 271 data_for_recursion.clip_tree_parent = clip_tree->Insert(root_clip, 0); |
| 272 |
| 273 BuildPropertyTreesInternal(root_layer, data_for_recursion); |
| 274 |
| 275 TransformNode* transform_root = transform_tree->Node(transform_root_id); |
| 276 transform_root->data.set_to_parent(device_transform * |
| 277 transform_root->data.to_parent); |
| 278 } |
| 279 |
| 280 } // namespace cc |
OLD | NEW |