Chromium Code Reviews| 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 | |
| 67 const bool axis_aligned_with_respect_to_parent = Are2DAxisAligned( | |
| 68 *data_from_ancestor.transform_tree, layer->transform_tree_index(), | |
| 69 parent->data.transform_id); | |
| 70 | |
| 71 // TODO(vollick): once Andrew refactors the surface determinations out of | |
|
enne (OOO)
2014/12/10 23:45:59
What's the status on this work?
Ian Vollick
2014/12/12 03:01:47
Andrew's got a patch up for review. Ball's in Dana
| |
| 72 // CDP, the the layer->render_surface() check will be invalid. | |
| 73 const bool has_unclipped_surface = | |
| 74 layer->render_surface() && | |
| 75 layer->render_surface()->clip_rect().IsEmpty() && | |
| 76 layer->num_unclipped_descendants() == 0; | |
| 77 | |
| 78 if (has_unclipped_surface) | |
| 79 parent_id = 0; | |
| 80 | |
| 81 if (!RequiresClipNode(layer, axis_aligned_with_respect_to_parent)) { | |
| 82 // Unclipped surfaces reset the clip rect. | |
| 83 data_for_children->clip_tree_parent = parent_id; | |
| 84 } else if (layer->parent()) { | |
| 85 // Note the root clip gets handled elsewhere. | |
| 86 Layer* transform_parent = GetTransformParent(*data_for_children, layer); | |
| 87 ClipNode node; | |
| 88 node.data.clip = gfx::RectF( | |
| 89 gfx::PointF() + layer->offset_to_transform_parent(), layer->bounds()); | |
| 90 node.data.transform_id = transform_parent->transform_tree_index(); | |
| 91 node.data.target_id = | |
| 92 data_from_ancestor.render_target->transform_tree_index(); | |
| 93 | |
| 94 data_for_children->clip_tree_parent = | |
| 95 data_for_children->clip_tree->Insert(node, parent_id); | |
| 96 } | |
| 97 | |
| 98 layer->set_clip_tree_index( | |
| 99 has_unclipped_surface ? 0 : data_for_children->clip_tree_parent); | |
| 100 | |
| 101 // TODO(awoloszyn): Right now when we hit a node with a replica, we reset the | |
| 102 // clip for all children since we may need to draw. We need to figure out a | |
| 103 // better way, since we will need both the clipped and unclipped versions. | |
| 104 } | |
| 105 | |
| 106 void AddTransformNodeIfNeeded(const DataForRecursion& data_from_ancestor, | |
| 107 Layer* layer, | |
| 108 DataForRecursion* data_for_children) { | |
| 109 const bool is_root = !layer->parent(); | |
| 110 const bool is_page_scale_application_layer = | |
| 111 layer->parent() && layer->parent() == data_from_ancestor.page_scale_layer; | |
| 112 const bool is_scrollable = layer->scrollable(); | |
| 113 const bool is_fixed = layer->position_constraint().is_fixed_position(); | |
| 114 | |
| 115 const bool has_significant_transform = | |
| 116 !layer->transform().IsIdentityOr2DTranslation(); | |
| 117 | |
| 118 const bool has_animated_transform = | |
| 119 layer->layer_animation_controller()->IsAnimatingProperty( | |
| 120 Animation::Transform); | |
| 121 | |
| 122 const bool has_transform_origin = layer->transform_origin() != gfx::Point3F(); | |
| 123 | |
| 124 const bool has_surface = layer->render_surface(); | |
| 125 | |
| 126 const bool flattening_change = layer->parent() && | |
| 127 layer->should_flatten_transform() && | |
| 128 !layer->parent()->should_flatten_transform(); | |
| 129 | |
| 130 bool requires_node = is_root || is_scrollable || is_fixed || | |
| 131 has_significant_transform || has_animated_transform || | |
| 132 is_page_scale_application_layer || flattening_change || | |
| 133 has_transform_origin || has_surface; | |
| 134 | |
| 135 Layer* transform_parent = GetTransformParent(data_from_ancestor, layer); | |
| 136 | |
| 137 // May be non-zero if layer is fixed or has a scroll parent. | |
| 138 gfx::Vector2dF parent_offset; | |
| 139 if (transform_parent) { | |
| 140 // TODO(vollick): This is to mimic bugs in current CDP. Need to log a bug | |
|
enne (OOO)
2014/12/10 23:45:59
!!!
Ian Vollick
2014/12/12 03:01:47
Yeah :( I've logged the bug and referenced it in t
| |
| 141 // about this and reference it here. | |
| 142 if (!is_fixed) | |
| 143 parent_offset = transform_parent->offset_to_transform_parent(); | |
| 144 | |
| 145 gfx::Transform to_parent; | |
| 146 Layer* source = data_from_ancestor.transform_tree_parent; | |
| 147 if (layer->scroll_parent()) { | |
| 148 source = layer->parent(); | |
| 149 parent_offset += layer->parent()->offset_to_transform_parent(); | |
| 150 } | |
| 151 | |
| 152 ComputeTransform(*data_from_ancestor.transform_tree, | |
| 153 source->transform_tree_index(), | |
| 154 transform_parent->transform_tree_index(), &to_parent); | |
| 155 | |
| 156 parent_offset += to_parent.To2dTranslation(); | |
| 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 gfx::Vector2dF local_offset = layer->position().OffsetFromOrigin() + | |
| 165 layer->transform().To2dTranslation(); | |
| 166 layer->set_offset_to_transform_parent(parent_offset + local_offset); | |
| 167 layer->set_transform_tree_index(transform_parent->transform_tree_index()); | |
| 168 return; | |
| 169 } | |
| 170 | |
| 171 if (!is_root) { | |
| 172 data_for_children->transform_tree->Insert( | |
| 173 TransformNode(), transform_parent->transform_tree_index()); | |
| 174 } | |
| 175 | |
| 176 TransformNode* node = data_for_children->transform_tree->back(); | |
| 177 | |
| 178 node->data.flattens = layer->should_flatten_transform(); | |
| 179 node->data.target_id = | |
| 180 data_from_ancestor.render_target->transform_tree_index(); | |
| 181 | |
| 182 gfx::Transform transform; | |
| 183 float device_and_page_scale_factors = 1.0f; | |
| 184 if (is_root) | |
| 185 device_and_page_scale_factors = data_from_ancestor.device_scale_factor; | |
| 186 if (is_page_scale_application_layer) | |
| 187 device_and_page_scale_factors *= data_from_ancestor.page_scale_factor; | |
| 188 | |
| 189 transform.Scale(device_and_page_scale_factors, device_and_page_scale_factors); | |
| 190 | |
| 191 // NB: We've accounted for the scroll offset here but we haven't taken into | |
| 192 // account snapping to screen space pixels (since we haven't computed any | |
| 193 // screen space transforms). For the purposes of computing rects we need to | |
| 194 // record, this should be fine (the visible rects we compute may be slightly | |
| 195 // different than what we'd compute with snapping, but since we significantly | |
| 196 // expand the visible rect when determining what to record, the slight | |
| 197 // difference should be inconsequential). | |
| 198 gfx::Vector2dF position = layer->position().OffsetFromOrigin(); | |
| 199 if (!layer->scroll_parent()) { | |
| 200 position -= gfx::Vector2dF(layer->TotalScrollOffset().x(), | |
| 201 layer->TotalScrollOffset().y()); | |
| 202 } | |
| 203 | |
| 204 position += parent_offset; | |
| 205 | |
| 206 transform.Translate3d(position.x() + layer->transform_origin().x(), | |
| 207 position.y() + layer->transform_origin().y(), | |
| 208 layer->transform_origin().z()); | |
| 209 transform.PreconcatTransform(layer->transform()); | |
| 210 transform.Translate3d(-layer->transform_origin().x(), | |
| 211 -layer->transform_origin().y(), | |
| 212 -layer->transform_origin().z()); | |
| 213 | |
| 214 node->data.to_parent = transform; | |
| 215 node->data.is_invertible = transform.GetInverse(&node->data.from_parent); | |
| 216 | |
| 217 UpdateScreenSpaceTransform(data_from_ancestor.transform_tree, node->id); | |
| 218 | |
| 219 layer->set_offset_to_transform_parent(gfx::Vector2dF()); | |
| 220 layer->set_transform_tree_index(node->id); | |
| 221 } | |
| 222 | |
| 223 void BuildPropertyTreesInternal(Layer* layer, | |
| 224 const DataForRecursion& data_from_parent) { | |
| 225 DataForRecursion data_for_children(data_from_parent); | |
| 226 if (layer->render_surface()) | |
| 227 data_for_children.render_target = layer; | |
| 228 | |
| 229 AddTransformNodeIfNeeded(data_from_parent, layer, &data_for_children); | |
| 230 AddClipNodeIfNeeded(data_from_parent, layer, &data_for_children); | |
| 231 | |
| 232 for (size_t i = 0; i < layer->children().size(); ++i) { | |
| 233 if (!layer->children()[i]->scroll_parent()) | |
| 234 BuildPropertyTreesInternal(layer->children()[i].get(), data_for_children); | |
| 235 } | |
| 236 | |
| 237 if (layer->scroll_children()) { | |
| 238 for (Layer* scroll_child : *layer->scroll_children()) { | |
| 239 BuildPropertyTreesInternal(scroll_child, data_for_children); | |
| 240 } | |
| 241 } | |
| 242 | |
| 243 if (layer->has_replica()) | |
| 244 BuildPropertyTreesInternal(layer->replica_layer(), data_for_children); | |
| 245 } | |
| 246 | |
| 247 } // namespace | |
| 248 | |
| 249 void PropertyTreeBuilder::BuildPropertyTrees( | |
| 250 Layer* root_layer, | |
| 251 const Layer* page_scale_layer, | |
| 252 float page_scale_factor, | |
| 253 float device_scale_factor, | |
| 254 const gfx::Rect& viewport, | |
| 255 const gfx::Transform& device_transform, | |
| 256 TransformTree* transform_tree, | |
| 257 ClipTree* clip_tree) { | |
| 258 DataForRecursion data_for_recursion; | |
| 259 data_for_recursion.transform_tree = transform_tree; | |
| 260 data_for_recursion.clip_tree = clip_tree; | |
| 261 data_for_recursion.transform_tree_parent = nullptr; | |
| 262 data_for_recursion.transform_fixed_parent = nullptr; | |
| 263 data_for_recursion.render_target = root_layer; | |
| 264 data_for_recursion.clip_tree_parent = 0; | |
| 265 data_for_recursion.page_scale_layer = page_scale_layer; | |
| 266 data_for_recursion.page_scale_factor = page_scale_factor; | |
| 267 data_for_recursion.device_scale_factor = device_scale_factor; | |
| 268 | |
| 269 int transform_root_id = 0; | |
| 270 int clip_root_id = 0; | |
| 271 | |
| 272 // We only need to clip the root if we have a non-empty viewport. The root of | |
|
enne (OOO)
2014/12/10 23:46:00
When is the viewport empty?
Ian Vollick
2014/12/12 03:01:47
This happens in unit tests and the assumption ther
enne (OOO)
2014/12/12 19:05:49
Can you leave a comment saying that empty viewport
Ian Vollick
2014/12/15 21:45:17
This is now unnecessary due to hush's patch. Remov
| |
| 273 // the clip tree does not clip, so we need to add another node in this case. | |
| 274 if (!viewport.IsEmpty()) { | |
| 275 data_for_recursion.clip_tree_parent = clip_tree->Insert(ClipNode(), 0); | |
| 276 clip_root_id = data_for_recursion.clip_tree_parent; | |
| 277 } | |
| 278 | |
| 279 BuildPropertyTreesInternal(root_layer, data_for_recursion); | |
| 280 | |
| 281 TransformNode* transform_root = transform_tree->Node(transform_root_id); | |
| 282 ClipNode* clip_root = clip_tree->Node(clip_root_id); | |
| 283 | |
| 284 gfx::Transform combined_transform = | |
| 285 device_transform * transform_root->data.to_parent; | |
|
enne (OOO)
2014/12/10 23:45:59
Is this ever not identity? Doesn't the transform r
Ian Vollick
2014/12/12 03:01:47
The dsf (and device transform) are applied to the
Ian Vollick
2014/12/15 21:45:17
I've added an extra "super root" to the transform
| |
| 286 | |
| 287 transform_root->data.set_to_parent(combined_transform); | |
| 288 gfx::RectF transformed_viewport = viewport; | |
| 289 | |
| 290 if (!combined_transform.IsIdentity()) { | |
| 291 gfx::Transform inverse_transform; | |
| 292 if (!combined_transform.GetInverse(&inverse_transform)) { | |
| 293 // If we have an univertible transform, then we clip off the entire | |
| 294 // subtree. | |
| 295 transformed_viewport = gfx::RectF(); | |
| 296 } else { | |
| 297 transformed_viewport = | |
| 298 MathUtil::ProjectClippedRect(inverse_transform, viewport); | |
| 299 } | |
| 300 } | |
| 301 | |
| 302 clip_root->data.clip = transformed_viewport; | |
|
enne (OOO)
2014/12/10 23:46:00
Why do you need to inverse transform the viewport
Ian Vollick
2014/12/12 03:01:47
To get to screen space (where this clip is applied
enne (OOO)
2014/12/12 19:05:49
Hmm. Maybe I just figured that this function woul
Ian Vollick
2014/12/15 21:45:17
Now that we have the super root, we don't need to
| |
| 303 clip_root->data.transform_id = transform_root->id; | |
| 304 } | |
| 305 | |
| 306 } // namespace cc | |
| OLD | NEW |