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 <stddef.h>
6 
7 #include <algorithm>
8 #include <set>
9 #include <string>
10 #include <utility>
11 #include <vector>
12 
13 #include "base/check_op.h"
14 #include "base/memory/ptr_util.h"
15 #include "base/numerics/checked_math.h"
16 #include "base/numerics/safe_conversions.h"
17 #include "base/trace_event/traced_value.h"
18 #include "cc/trees/clip_node.h"
19 #include "cc/trees/compositor_commit_data.h"
20 #include "cc/trees/effect_node.h"
21 #include "cc/trees/layer_tree_impl.h"
22 #include "cc/trees/property_tree.h"
23 #include "cc/trees/scroll_node.h"
24 #include "cc/trees/transform_node.h"
25 #include "components/viz/common/frame_sinks/copy_output_request.h"
26 #include "ui/gfx/geometry/vector2d_conversions.h"
27 
28 namespace cc {
29 
30 template <typename T>
PropertyTree()31 PropertyTree<T>::PropertyTree() : needs_update_(false) {
32   nodes_.push_back(T());
33   back()->id = kRootNodeId;
34   back()->parent_id = kInvalidNodeId;
35 }
36 
37 // Equivalent to
38 // PropertyTree<T>::~PropertyTree() = default;
39 // but due to a gcc bug the generated destructor will have wrong symbol
40 // visibility in component build.
41 template <typename T>
42 PropertyTree<T>::~PropertyTree() = default;
43 
44 template <typename T>
45 PropertyTree<T>& PropertyTree<T>::operator=(const PropertyTree<T>&) = default;
46 
47 #define DCHECK_NODE_EXISTENCE(check_node_existence, state, property,           \
48                               needs_rebuild)                                   \
49   DCHECK(!check_node_existence || ((!state.currently_running[property] &&      \
50                                     !state.potentially_animating[property]) || \
51                                    needs_rebuild))
52 
TransformTree()53 TransformTree::TransformTree()
54     : page_scale_factor_(1.f),
55       device_scale_factor_(1.f),
56       device_transform_scale_factor_(1.f) {
57   cached_data_.push_back(TransformCachedNodeData());
58 }
59 
60 TransformTree::~TransformTree() = default;
61 TransformTree& TransformTree::operator=(const TransformTree&) = default;
62 
63 template <typename T>
Insert(const T & tree_node,int parent_id)64 int PropertyTree<T>::Insert(const T& tree_node, int parent_id) {
65   DCHECK_GT(nodes_.size(), 0u);
66   nodes_.push_back(tree_node);
67   T& node = nodes_.back();
68   node.parent_id = parent_id;
69   node.id = static_cast<int>(nodes_.size()) - 1;
70   return node.id;
71 }
72 
73 template <typename T>
clear()74 void PropertyTree<T>::clear() {
75   needs_update_ = false;
76   nodes_.clear();
77   nodes_.push_back(T());
78   back()->id = kRootNodeId;
79   back()->parent_id = kInvalidNodeId;
80 
81 #if DCHECK_IS_ON()
82   PropertyTree<T> tree;
83   DCHECK(tree == *this);
84 #endif
85 }
86 
87 #if DCHECK_IS_ON()
88 template <typename T>
operator ==(const PropertyTree<T> & other) const89 bool PropertyTree<T>::operator==(const PropertyTree<T>& other) const {
90   return nodes_ == other.nodes() && needs_update_ == other.needs_update();
91 }
92 #endif
93 
94 template <typename T>
AsValueInto(base::trace_event::TracedValue * value) const95 void PropertyTree<T>::AsValueInto(base::trace_event::TracedValue* value) const {
96   value->BeginArray("nodes");
97   for (const auto& node : nodes_) {
98     value->BeginDictionary();
99     node.AsValueInto(value);
100     value->EndDictionary();
101   }
102   value->EndArray();
103 }
104 
105 template class PropertyTree<TransformNode>;
106 template class PropertyTree<ClipNode>;
107 template class PropertyTree<EffectNode>;
108 template class PropertyTree<ScrollNode>;
109 
Insert(const TransformNode & tree_node,int parent_id)110 int TransformTree::Insert(const TransformNode& tree_node, int parent_id) {
111   int node_id = PropertyTree<TransformNode>::Insert(tree_node, parent_id);
112   DCHECK_EQ(node_id, static_cast<int>(cached_data_.size()));
113 
114   cached_data_.push_back(TransformCachedNodeData());
115   return node_id;
116 }
117 
clear()118 void TransformTree::clear() {
119   PropertyTree<TransformNode>::clear();
120 
121   page_scale_factor_ = 1.f;
122   device_scale_factor_ = 1.f;
123   device_transform_scale_factor_ = 1.f;
124   nodes_affected_by_outer_viewport_bounds_delta_.clear();
125   cached_data_.clear();
126   cached_data_.push_back(TransformCachedNodeData());
127   sticky_position_data_.clear();
128 
129 #if DCHECK_IS_ON()
130   DCHECK(TransformTree() == *this);
131 #endif
132 }
133 
set_needs_update(bool needs_update)134 void TransformTree::set_needs_update(bool needs_update) {
135   if (needs_update && !PropertyTree<TransformNode>::needs_update())
136     property_trees()->UpdateTransformTreeUpdateNumber();
137   PropertyTree<TransformNode>::set_needs_update(needs_update);
138 }
139 
FindNodeFromElementId(ElementId id)140 TransformNode* TransformTree::FindNodeFromElementId(ElementId id) {
141   auto iterator = property_trees()->element_id_to_transform_node_index.find(id);
142   if (iterator == property_trees()->element_id_to_transform_node_index.end())
143     return nullptr;
144 
145   return Node(iterator->second);
146 }
147 
OnTransformAnimated(ElementId element_id,const gfx::Transform & transform)148 bool TransformTree::OnTransformAnimated(ElementId element_id,
149                                         const gfx::Transform& transform) {
150   TransformNode* node = FindNodeFromElementId(element_id);
151   DCHECK(node);
152   if (node->local == transform)
153     return false;
154   node->local = transform;
155   node->needs_local_transform_update = true;
156   node->transform_changed = true;
157   property_trees()->changed = true;
158   set_needs_update(true);
159   return true;
160 }
161 
ResetChangeTracking()162 void TransformTree::ResetChangeTracking() {
163   for (int id = TransformTree::kContentsRootNodeId;
164        id < static_cast<int>(size()); ++id) {
165     TransformNode* node = Node(id);
166     node->transform_changed = false;
167   }
168 }
169 
UpdateTransforms(int id)170 void TransformTree::UpdateTransforms(int id) {
171   TransformNode* node = Node(id);
172   TransformNode* parent_node = parent(node);
173   DCHECK(parent_node);
174   // TODO(flackr): Only dirty when scroll offset changes.
175   if (node->sticky_position_constraint_id >= 0 ||
176       node->needs_local_transform_update) {
177     UpdateLocalTransform(node);
178   } else {
179     UndoSnapping(node);
180   }
181   UpdateScreenSpaceTransform(node, parent_node);
182   UpdateAnimationProperties(node, parent_node);
183   UpdateSnapping(node);
184   UpdateTransformChanged(node, parent_node);
185   UpdateNodeAndAncestorsAreAnimatedOrInvertible(node, parent_node);
186   UpdateNodeOrAncestorsWillChangeTransform(node, parent_node);
187 
188   DCHECK(!node->needs_local_transform_update);
189 }
190 
IsDescendant(int desc_id,int source_id) const191 bool TransformTree::IsDescendant(int desc_id, int source_id) const {
192   while (desc_id != source_id) {
193     if (desc_id == kInvalidNodeId)
194       return false;
195     desc_id = Node(desc_id)->parent_id;
196   }
197   return true;
198 }
199 
CombineTransformsBetween(int source_id,int dest_id,gfx::Transform * transform) const200 void TransformTree::CombineTransformsBetween(int source_id,
201                                              int dest_id,
202                                              gfx::Transform* transform) const {
203   DCHECK(source_id > dest_id);
204   const TransformNode* current = Node(source_id);
205   const TransformNode* dest = Node(dest_id);
206   // Combine transforms to and from the screen when possible. Since flattening
207   // is a non-linear operation, we cannot use this approach when there is
208   // non-trivial flattening between the source and destination nodes. For
209   // example, consider the tree R->A->B->C, where B flattens its inherited
210   // transform, and A has a non-flat transform. Suppose C is the source and A is
211   // the destination. The expected result is C * B. But C's to_screen
212   // transform is C * B * flattened(A * R), and A's from_screen transform is
213   // R^{-1} * A^{-1}. If at least one of A and R isn't flat, the inverse of
214   // flattened(A * R) won't be R^{-1} * A{-1}, so multiplying C's to_screen and
215   // A's from_screen will not produce the correct result.
216   if (!dest ||
217       (dest->ancestors_are_invertible && dest->node_and_ancestors_are_flat)) {
218     transform->ConcatTransform(ToScreen(current->id));
219     if (dest)
220       transform->ConcatTransform(FromScreen(dest->id));
221     return;
222   }
223 
224   // Flattening is defined in a way that requires it to be applied while
225   // traversing downward in the tree. We first identify nodes that are on the
226   // path from the source to the destination (this is traversing upward), and
227   // then we visit these nodes in reverse order, flattening as needed. We
228   // early-out if we get to a node whose target node is the destination, since
229   // we can then re-use the target space transform stored at that node. However,
230   // we cannot re-use a stored target space transform if the destination has a
231   // zero surface contents scale, since stored target space transforms have
232   // surface contents scale baked in, but we need to compute an unscaled
233   // transform.
234   std::vector<int> source_to_destination;
235   source_to_destination.push_back(current->id);
236   current = parent(current);
237   for (; current && current->id > dest_id; current = parent(current))
238     source_to_destination.push_back(current->id);
239 
240   gfx::Transform combined_transform;
241   if (current->id < dest_id) {
242     // We have reached the lowest common ancestor of the source and destination
243     // nodes. This case can occur when we are transforming between a node
244     // corresponding to a fixed-position layer (or its descendant) and the node
245     // corresponding to the layer's render target. For example, consider the
246     // layer tree R->T->S->F where F is fixed-position, S owns a render surface,
247     // and T has a significant transform. This will yield the following
248     // transform tree:
249     //    R
250     //    |
251     //    T
252     //   /|
253     //  S F
254     // In this example, T will have id 2, S will have id 3, and F will have id
255     // 4. When walking up the ancestor chain from F, the first node with a
256     // smaller id than S will be T, the lowest common ancestor of these nodes.
257     // We compute the transform from T to S here, and then from F to T in the
258     // loop below.
259     DCHECK(IsDescendant(dest_id, current->id));
260     CombineInversesBetween(current->id, dest_id, &combined_transform);
261     DCHECK(combined_transform.IsApproximatelyIdentityOrTranslation(
262         SkDoubleToScalar(1e-4)));
263   }
264 
265   size_t source_to_destination_size = source_to_destination.size();
266   for (size_t i = 0; i < source_to_destination_size; ++i) {
267     size_t index = source_to_destination_size - 1 - i;
268     const TransformNode* node = Node(source_to_destination[index]);
269     if (node->flattens_inherited_transform)
270       combined_transform.FlattenTo2d();
271     combined_transform.PreconcatTransform(node->to_parent);
272   }
273 
274   transform->ConcatTransform(combined_transform);
275 }
276 
CombineInversesBetween(int source_id,int dest_id,gfx::Transform * transform) const277 bool TransformTree::CombineInversesBetween(int source_id,
278                                            int dest_id,
279                                            gfx::Transform* transform) const {
280   DCHECK(source_id < dest_id);
281   const TransformNode* current = Node(dest_id);
282   const TransformNode* dest = Node(source_id);
283   // Just as in CombineTransformsBetween, we can use screen space transforms in
284   // this computation only when there isn't any non-trivial flattening
285   // involved.
286   if (current->ancestors_are_invertible &&
287       current->node_and_ancestors_are_flat) {
288     transform->PreconcatTransform(FromScreen(current->id));
289     if (dest)
290       transform->PreconcatTransform(ToScreen(dest->id));
291     return true;
292   }
293 
294   // Inverting a flattening is not equivalent to flattening an inverse. This
295   // means we cannot, for example, use the inverse of each node's to_parent
296   // transform, flattening where needed. Instead, we must compute the transform
297   // from the destination to the source, with flattening, and then invert the
298   // result.
299   gfx::Transform dest_to_source;
300   CombineTransformsBetween(dest_id, source_id, &dest_to_source);
301   gfx::Transform source_to_dest;
302   bool all_are_invertible = dest_to_source.GetInverse(&source_to_dest);
303   transform->PreconcatTransform(source_to_dest);
304   return all_are_invertible;
305 }
306 
307 // This function should match the offset we set for sticky position layer in
308 // blink::LayoutBoxModelObject::StickyPositionOffset.
StickyPositionOffset(TransformNode * node)309 gfx::Vector2dF TransformTree::StickyPositionOffset(TransformNode* node) {
310   StickyPositionNodeData* sticky_data = MutableStickyPositionData(node->id);
311   if (!sticky_data)
312     return gfx::Vector2dF();
313   const StickyPositionConstraint& constraint = sticky_data->constraints;
314   ScrollNode* scroll_node =
315       property_trees()->scroll_tree.Node(sticky_data->scroll_ancestor);
316   TransformNode* transform_node = Node(scroll_node->transform_id);
317   const auto& scroll_offset = transform_node->scroll_offset;
318   DCHECK(property_trees()->scroll_tree.current_scroll_offset(
319              scroll_node->element_id) == scroll_offset);
320   gfx::PointF scroll_position(scroll_offset.x(), scroll_offset.y());
321   if (transform_node->scrolls) {
322     // The scroll position does not include snapping which shifts the scroll
323     // offset to align to a pixel boundary, we need to manually include it here.
324     // In this case, snapping is caused by a scroll.
325     scroll_position -= transform_node->snap_amount;
326   }
327 
328   gfx::RectF clip = constraint.constraint_box_rect;
329   clip.Offset(scroll_position.x(), scroll_position.y());
330 
331   // The clip region may need to be offset by the outer viewport bounds, e.g. if
332   // the top bar hides/shows. Position sticky should never attach to the inner
333   // viewport since it shouldn't be affected by pinch-zoom.
334   DCHECK(!scroll_node->scrolls_inner_viewport);
335   if (scroll_node->scrolls_outer_viewport) {
336     clip.set_width(
337         clip.width() +
338         property_trees()->outer_viewport_container_bounds_delta().x());
339     clip.set_height(
340         clip.height() +
341         property_trees()->outer_viewport_container_bounds_delta().y());
342   }
343 
344   gfx::Vector2dF ancestor_sticky_box_offset;
345   if (sticky_data->nearest_node_shifting_sticky_box !=
346       TransformTree::kInvalidNodeId) {
347     // TODO(crbug.com/1128479): Investigate why there would be an invalid index
348     // passed in. Early return for now.
349     if (sticky_data->nearest_node_shifting_sticky_box >=
350         static_cast<int>(property_trees()->transform_tree.size()))
351       return gfx::Vector2dF();
352     const StickyPositionNodeData* ancestor_sticky_data =
353         GetStickyPositionData(sticky_data->nearest_node_shifting_sticky_box);
354     DCHECK(ancestor_sticky_data);
355     ancestor_sticky_box_offset =
356         ancestor_sticky_data->total_sticky_box_sticky_offset;
357   }
358 
359   gfx::Vector2dF ancestor_containing_block_offset;
360   if (sticky_data->nearest_node_shifting_containing_block !=
361       TransformTree::kInvalidNodeId) {
362     // TODO(crbug.com/1128479): Investigate why there would be an invalid index
363     // passed in. Early return for now.
364     if (sticky_data->nearest_node_shifting_containing_block >=
365         static_cast<int>(property_trees()->transform_tree.size()))
366       return gfx::Vector2dF();
367     const StickyPositionNodeData* ancestor_sticky_data = GetStickyPositionData(
368         sticky_data->nearest_node_shifting_containing_block);
369     DCHECK(ancestor_sticky_data);
370     ancestor_containing_block_offset =
371         ancestor_sticky_data->total_containing_block_sticky_offset;
372   }
373 
374   // Compute the current position of the constraint rects based on the original
375   // positions and the offsets from ancestor sticky elements.
376   gfx::RectF sticky_box_rect =
377       gfx::RectF(constraint.scroll_container_relative_sticky_box_rect) +
378       ancestor_sticky_box_offset + ancestor_containing_block_offset;
379   gfx::RectF containing_block_rect =
380       gfx::RectF(constraint.scroll_container_relative_containing_block_rect) +
381       ancestor_containing_block_offset;
382 
383   gfx::Vector2dF sticky_offset;
384 
385   // In each of the following cases, we measure the limit which is the point
386   // that the element should stick to, clamping on one side to 0 (because sticky
387   // only pushes elements in one direction). Then we clamp to how far we can
388   // push the element in that direction without being pushed outside of its
389   // containing block.
390   //
391   // Note: The order of applying the sticky constraints is applied such that
392   // left offset takes precedence over right offset, and top takes precedence
393   // over bottom offset.
394   if (constraint.is_anchored_right) {
395     float right_limit = clip.right() - constraint.right_offset;
396     float right_delta =
397         std::min<float>(0, right_limit - sticky_box_rect.right());
398     float available_space =
399         std::min<float>(0, containing_block_rect.x() - sticky_box_rect.x());
400     if (right_delta < available_space)
401       right_delta = available_space;
402     sticky_offset.set_x(sticky_offset.x() + right_delta);
403   }
404   if (constraint.is_anchored_left) {
405     float left_limit = clip.x() + constraint.left_offset;
406     float left_delta = std::max<float>(0, left_limit - sticky_box_rect.x());
407     float available_space = std::max<float>(
408         0, containing_block_rect.right() - sticky_box_rect.right());
409     if (left_delta > available_space)
410       left_delta = available_space;
411     sticky_offset.set_x(sticky_offset.x() + left_delta);
412   }
413   if (constraint.is_anchored_bottom) {
414     float bottom_limit = clip.bottom() - constraint.bottom_offset;
415     float bottom_delta =
416         std::min<float>(0, bottom_limit - sticky_box_rect.bottom());
417     float available_space =
418         std::min<float>(0, containing_block_rect.y() - sticky_box_rect.y());
419     if (bottom_delta < available_space)
420       bottom_delta = available_space;
421     sticky_offset.set_y(sticky_offset.y() + bottom_delta);
422   }
423   if (constraint.is_anchored_top) {
424     float top_limit = clip.y() + constraint.top_offset;
425     float top_delta = std::max<float>(0, top_limit - sticky_box_rect.y());
426     float available_space = std::max<float>(
427         0, containing_block_rect.bottom() - sticky_box_rect.bottom());
428     if (top_delta > available_space)
429       top_delta = available_space;
430     sticky_offset.set_y(sticky_offset.y() + top_delta);
431   }
432 
433   sticky_data->total_sticky_box_sticky_offset =
434       ancestor_sticky_box_offset + sticky_offset;
435   sticky_data->total_containing_block_sticky_offset =
436       ancestor_sticky_box_offset + ancestor_containing_block_offset +
437       sticky_offset;
438 
439   // return
440   return gfx::Vector2dF(roundf(sticky_offset.x()), roundf(sticky_offset.y()));
441 }
442 
UpdateLocalTransform(TransformNode * node)443 void TransformTree::UpdateLocalTransform(TransformNode* node) {
444   gfx::Transform transform;
445   transform.Translate3d(node->post_translation.x() + node->origin.x(),
446                         node->post_translation.y() + node->origin.y(),
447                         node->origin.z());
448 
449   float fixed_position_adjustment = 0;
450   if (node->moved_by_outer_viewport_bounds_delta_y) {
451     fixed_position_adjustment =
452         property_trees()->outer_viewport_container_bounds_delta().y();
453   }
454 
455   transform.Translate(-node->scroll_offset.x(),
456                       -node->scroll_offset.y() + fixed_position_adjustment);
457   transform.Translate(StickyPositionOffset(node));
458   transform.PreconcatTransform(node->local);
459   transform.Translate3d(gfx::Point3F() - node->origin);
460 
461   node->set_to_parent(transform);
462   node->needs_local_transform_update = false;
463 }
464 
UpdateScreenSpaceTransform(TransformNode * node,TransformNode * parent_node)465 void TransformTree::UpdateScreenSpaceTransform(TransformNode* node,
466                                                TransformNode* parent_node) {
467   DCHECK(parent_node);
468   gfx::Transform to_screen_space_transform = ToScreen(parent_node->id);
469   if (node->flattens_inherited_transform)
470     to_screen_space_transform.FlattenTo2d();
471   to_screen_space_transform.PreconcatTransform(node->to_parent);
472   node->ancestors_are_invertible = parent_node->ancestors_are_invertible;
473   node->node_and_ancestors_are_flat =
474       parent_node->node_and_ancestors_are_flat && node->to_parent.IsFlat();
475   SetToScreen(node->id, to_screen_space_transform);
476 
477   gfx::Transform from_screen;
478   if (!ToScreen(node->id).GetInverse(&from_screen))
479     node->ancestors_are_invertible = false;
480   SetFromScreen(node->id, from_screen);
481 }
482 
UpdateAnimationProperties(TransformNode * node,TransformNode * parent_node)483 void TransformTree::UpdateAnimationProperties(TransformNode* node,
484                                               TransformNode* parent_node) {
485   DCHECK(parent_node);
486   bool ancestor_is_animating = false;
487   ancestor_is_animating = parent_node->to_screen_is_potentially_animated;
488   node->to_screen_is_potentially_animated =
489       node->has_potential_animation || ancestor_is_animating;
490 }
491 
UndoSnapping(TransformNode * node)492 void TransformTree::UndoSnapping(TransformNode* node) {
493   // to_parent transform has snapping from previous frame baked in.
494   // We need to undo it and use the un-snapped transform to compute current
495   // target and screen space transforms.
496   node->to_parent.Translate(-node->snap_amount.x(), -node->snap_amount.y());
497 }
498 
UpdateSnapping(TransformNode * node)499 void TransformTree::UpdateSnapping(TransformNode* node) {
500   if (!node->should_be_snapped || node->to_screen_is_potentially_animated ||
501       !ToScreen(node->id).IsScaleOrTranslation() ||
502       !node->ancestors_are_invertible) {
503     return;
504   }
505 
506   // Snapping must be done in target space (the pixels we care about) and then
507   // the render pass should also be snapped if necessary. But, we do it in
508   // screen space because it is easier and works most of the time if there is
509   // no intermediate render pass with a snap-destrying transform. If ST is the
510   // screen space transform and ST' is ST with its translation components
511   // rounded, then what we're after is the scroll delta X, where ST * X = ST'.
512   // I.e., we want a transform that will realize our snap. It follows that
513   // X = ST^-1 * ST'. We cache ST and ST^-1 to make this more efficient.
514   DCHECK_LT(node->id, static_cast<int>(cached_data_.size()));
515   gfx::Transform& to_screen = cached_data_[node->id].to_screen;
516   to_screen.RoundTranslationComponents();
517   gfx::Transform& from_screen = cached_data_[node->id].from_screen;
518   gfx::Transform delta = from_screen;
519   delta *= to_screen;
520 
521   constexpr float kTolerance = 1e-4f;
522   DCHECK(delta.IsApproximatelyIdentityOrTranslation(kTolerance))
523       << delta.ToString();
524 
525   gfx::Vector2dF translation = delta.To2dTranslation();
526   node->snap_amount = translation;
527   if (translation.IsZero())
528     return;
529 
530   from_screen.matrix().postTranslate(-translation.x(), -translation.y(), 0);
531   node->to_parent.Translate(translation.x(), translation.y());
532   // Avoid accumulation of errors in to_parent.
533   if (node->to_parent.IsApproximatelyIdentityOrIntegerTranslation(kTolerance))
534     node->to_parent.RoundTranslationComponents();
535 }
536 
UpdateTransformChanged(TransformNode * node,TransformNode * parent_node)537 void TransformTree::UpdateTransformChanged(TransformNode* node,
538                                            TransformNode* parent_node) {
539   DCHECK(parent_node);
540   if (parent_node->transform_changed)
541     node->transform_changed = true;
542 }
543 
UpdateNodeAndAncestorsAreAnimatedOrInvertible(TransformNode * node,TransformNode * parent_node)544 void TransformTree::UpdateNodeAndAncestorsAreAnimatedOrInvertible(
545     TransformNode* node,
546     TransformNode* parent_node) {
547   DCHECK(parent_node);
548   if (!parent_node->node_and_ancestors_are_animated_or_invertible) {
549     node->node_and_ancestors_are_animated_or_invertible = false;
550     return;
551   }
552   bool is_invertible = node->is_invertible;
553   // Even when the current node's transform and the parent's screen space
554   // transform are invertible, the current node's screen space transform can
555   // become uninvertible due to floating-point arithmetic.
556   if (!node->ancestors_are_invertible && parent_node->ancestors_are_invertible)
557     is_invertible = false;
558   node->node_and_ancestors_are_animated_or_invertible =
559       node->has_potential_animation || is_invertible;
560 }
561 
UpdateNodeOrAncestorsWillChangeTransform(TransformNode * node,TransformNode * parent_node)562 void TransformTree::UpdateNodeOrAncestorsWillChangeTransform(
563     TransformNode* node,
564     TransformNode* parent_node) {
565   node->node_or_ancestors_will_change_transform = node->will_change_transform;
566   if (parent_node) {
567     node->node_or_ancestors_will_change_transform |=
568         parent_node->node_or_ancestors_will_change_transform;
569   }
570 }
571 
SetRootScaleAndTransform(float device_scale_factor,const gfx::Transform & device_transform)572 void TransformTree::SetRootScaleAndTransform(
573     float device_scale_factor,
574     const gfx::Transform& device_transform) {
575   device_scale_factor_ = device_scale_factor;
576   gfx::Vector2dF device_transform_scale_components =
577       MathUtil::ComputeTransform2dScaleComponents(device_transform, 1.f);
578 
579   // Not handling the rare case of different x and y device scale.
580   device_transform_scale_factor_ =
581       std::max(device_transform_scale_components.x(),
582                device_transform_scale_components.y());
583 
584   // Let DT be the device transform and DSF be the matrix scaled by (device
585   // scale factor * page scale factor for root). Let Screen Space Scale(SSS) =
586   // scale component of DT*DSF. The screen space transform of the root
587   // transform node is set to SSS and the post local transform of the contents
588   // root node is set to SSS^-1*DT*DSF.
589   gfx::Transform transform = device_transform;
590   transform.Scale(device_scale_factor, device_scale_factor);
591   gfx::Vector2dF screen_space_scale =
592       MathUtil::ComputeTransform2dScaleComponents(transform,
593                                                   device_scale_factor);
594   DCHECK_NE(screen_space_scale.x(), 0.f);
595   DCHECK_NE(screen_space_scale.y(), 0.f);
596 
597   gfx::Transform root_to_screen;
598   root_to_screen.Scale(screen_space_scale.x(), screen_space_scale.y());
599   gfx::Transform root_from_screen;
600   bool invertible = root_to_screen.GetInverse(&root_from_screen);
601   DCHECK(invertible);
602   if (root_to_screen != ToScreen(kRootNodeId)) {
603     SetToScreen(kRootNodeId, root_to_screen);
604     SetFromScreen(kRootNodeId, root_from_screen);
605     set_needs_update(true);
606   }
607 
608   transform.ConcatTransform(root_from_screen);
609   TransformNode* contents_root_node = Node(kContentsRootNodeId);
610   if (contents_root_node->local != transform) {
611     contents_root_node->local = transform;
612     contents_root_node->needs_local_transform_update = true;
613     set_needs_update(true);
614   }
615 }
616 
UpdateOuterViewportContainerBoundsDelta()617 void TransformTree::UpdateOuterViewportContainerBoundsDelta() {
618   if (nodes_affected_by_outer_viewport_bounds_delta_.empty())
619     return;
620 
621   set_needs_update(true);
622   for (int i : nodes_affected_by_outer_viewport_bounds_delta_)
623     Node(i)->needs_local_transform_update = true;
624 }
625 
AddNodeAffectedByOuterViewportBoundsDelta(int node_id)626 void TransformTree::AddNodeAffectedByOuterViewportBoundsDelta(int node_id) {
627   nodes_affected_by_outer_viewport_bounds_delta_.push_back(node_id);
628 }
629 
HasNodesAffectedByOuterViewportBoundsDelta() const630 bool TransformTree::HasNodesAffectedByOuterViewportBoundsDelta() const {
631   return !nodes_affected_by_outer_viewport_bounds_delta_.empty();
632 }
633 
FromScreen(int node_id) const634 const gfx::Transform& TransformTree::FromScreen(int node_id) const {
635   DCHECK(static_cast<int>(cached_data_.size()) > node_id);
636   return cached_data_[node_id].from_screen;
637 }
638 
SetFromScreen(int node_id,const gfx::Transform & transform)639 void TransformTree::SetFromScreen(int node_id,
640                                   const gfx::Transform& transform) {
641   DCHECK(static_cast<int>(cached_data_.size()) > node_id);
642   cached_data_[node_id].from_screen = transform;
643 }
644 
ToScreen(int node_id) const645 const gfx::Transform& TransformTree::ToScreen(int node_id) const {
646   DCHECK(static_cast<int>(cached_data_.size()) > node_id);
647   return cached_data_[node_id].to_screen;
648 }
649 
SetToScreen(int node_id,const gfx::Transform & transform)650 void TransformTree::SetToScreen(int node_id, const gfx::Transform& transform) {
651   DCHECK(static_cast<int>(cached_data_.size()) > node_id);
652   cached_data_[node_id].to_screen = transform;
653   cached_data_[node_id].is_showing_backface = transform.IsBackFaceVisible();
654 }
655 
656 #if DCHECK_IS_ON()
operator ==(const TransformTree & other) const657 bool TransformTree::operator==(const TransformTree& other) const {
658   return PropertyTree::operator==(other) &&
659          page_scale_factor_ == other.page_scale_factor() &&
660          device_scale_factor_ == other.device_scale_factor() &&
661          device_transform_scale_factor_ ==
662              other.device_transform_scale_factor() &&
663          nodes_affected_by_outer_viewport_bounds_delta_ ==
664              other.nodes_affected_by_outer_viewport_bounds_delta() &&
665          cached_data_ == other.cached_data();
666 }
667 #endif
668 
MutableStickyPositionData(int node_id)669 StickyPositionNodeData* TransformTree::MutableStickyPositionData(int node_id) {
670   const TransformNode* node = Node(node_id);
671   if (node->sticky_position_constraint_id == -1)
672     return nullptr;
673   return &sticky_position_data_[node->sticky_position_constraint_id];
674 }
675 
EnsureStickyPositionData(int node_id)676 StickyPositionNodeData& TransformTree::EnsureStickyPositionData(int node_id) {
677   TransformNode* node = Node(node_id);
678   if (node->sticky_position_constraint_id == -1) {
679     node->sticky_position_constraint_id = sticky_position_data_.size();
680     sticky_position_data_.push_back(StickyPositionNodeData());
681   }
682   return sticky_position_data_[node->sticky_position_constraint_id];
683 }
684 
EffectTree()685 EffectTree::EffectTree() {
686   render_surfaces_.push_back(nullptr);
687 }
688 
689 EffectTree::~EffectTree() = default;
690 
Insert(const EffectNode & tree_node,int parent_id)691 int EffectTree::Insert(const EffectNode& tree_node, int parent_id) {
692   int node_id = PropertyTree<EffectNode>::Insert(tree_node, parent_id);
693   DCHECK_EQ(node_id, static_cast<int>(render_surfaces_.size()));
694 
695   render_surfaces_.push_back(nullptr);
696   return node_id;
697 }
698 
clear()699 void EffectTree::clear() {
700   PropertyTree<EffectNode>::clear();
701   render_surfaces_.clear();
702   render_surfaces_.push_back(nullptr);
703 
704 #if DCHECK_IS_ON()
705   EffectTree tree;
706   DCHECK(tree == *this);
707 #endif
708 }
709 
EffectiveOpacity(const EffectNode * node) const710 float EffectTree::EffectiveOpacity(const EffectNode* node) const {
711   return node->subtree_hidden ? 0.f : node->opacity;
712 }
713 
UpdateOpacities(EffectNode * node,EffectNode * parent_node)714 void EffectTree::UpdateOpacities(EffectNode* node, EffectNode* parent_node) {
715   node->screen_space_opacity = EffectiveOpacity(node);
716 
717   if (parent_node)
718     node->screen_space_opacity *= parent_node->screen_space_opacity;
719 }
720 
UpdateSubtreeHidden(EffectNode * node,EffectNode * parent_node)721 void EffectTree::UpdateSubtreeHidden(EffectNode* node,
722                                      EffectNode* parent_node) {
723   if (parent_node)
724     node->subtree_hidden |= parent_node->subtree_hidden;
725 }
726 
UpdateIsDrawn(EffectNode * node,EffectNode * parent_node)727 void EffectTree::UpdateIsDrawn(EffectNode* node, EffectNode* parent_node) {
728   // Nodes that have screen space opacity 0 are hidden. So they are not drawn.
729   // Exceptions:
730   // 1) Nodes that contribute to copy requests, whether hidden or not, must be
731   //    drawn.
732   // 2) Nodes that have a backdrop filter.
733   // 3) Nodes with animating screen space opacity on main thread or pending tree
734   //    are drawn if their parent is drawn irrespective of their opacity.
735   if (node->has_copy_request || node->cache_render_surface)
736     node->is_drawn = true;
737   else if (EffectiveOpacity(node) == 0.f &&
738            (!node->has_potential_opacity_animation ||
739             property_trees()->is_active) &&
740            node->backdrop_filters.IsEmpty())
741     node->is_drawn = false;
742   else if (parent_node)
743     node->is_drawn = parent_node->is_drawn;
744   else
745     node->is_drawn = true;
746 }
747 
UpdateEffectChanged(EffectNode * node,EffectNode * parent_node)748 void EffectTree::UpdateEffectChanged(EffectNode* node,
749                                      EffectNode* parent_node) {
750   if (parent_node && parent_node->effect_changed) {
751     node->effect_changed = true;
752   }
753 }
754 
UpdateHasFilters(EffectNode * node,EffectNode * parent_node)755 void EffectTree::UpdateHasFilters(EffectNode* node, EffectNode* parent_node) {
756   node->node_or_ancestor_has_filters =
757       !node->filters.IsEmpty() || node->has_potential_filter_animation;
758   if (parent_node) {
759     node->node_or_ancestor_has_filters |=
760         parent_node->node_or_ancestor_has_filters;
761   }
762 }
763 
UpdateBackfaceVisibility(EffectNode * node,EffectNode * parent_node)764 void EffectTree::UpdateBackfaceVisibility(EffectNode* node,
765                                           EffectNode* parent_node) {
766   if (parent_node && parent_node->hidden_by_backface_visibility) {
767     node->hidden_by_backface_visibility = true;
768     return;
769   }
770   if (node->double_sided) {
771     node->hidden_by_backface_visibility = false;
772     return;
773   }
774   node->hidden_by_backface_visibility =
775       property_trees()
776           ->transform_tree.cached_data()[node->transform_id]
777           .is_showing_backface;
778 }
779 
UpdateHasMaskingChild(EffectNode * node,EffectNode * parent_node)780 void EffectTree::UpdateHasMaskingChild(EffectNode* node,
781                                        EffectNode* parent_node) {
782   // Reset to false when a node is first met. We'll set the bit later
783   // when we actually encounter a masking child.
784   node->has_masking_child = false;
785   if (node->blend_mode == SkBlendMode::kDstIn) {
786     parent_node->has_masking_child = true;
787   }
788 }
789 
UpdateOnlyDrawsVisibleContent(EffectNode * node,EffectNode * parent_node)790 void EffectTree::UpdateOnlyDrawsVisibleContent(EffectNode* node,
791                                                EffectNode* parent_node) {
792   node->only_draws_visible_content = !node->has_copy_request;
793   if (parent_node)
794     node->only_draws_visible_content &= parent_node->only_draws_visible_content;
795   if (!node->backdrop_filters.IsEmpty()) {
796     node->only_draws_visible_content &=
797         !node->backdrop_filters.HasFilterOfType(FilterOperation::ZOOM);
798   }
799 }
800 
UpdateSurfaceContentsScale(EffectNode * effect_node)801 void EffectTree::UpdateSurfaceContentsScale(EffectNode* effect_node) {
802   if (!effect_node->HasRenderSurface()) {
803     effect_node->surface_contents_scale = gfx::Vector2dF(1.0f, 1.0f);
804     return;
805   }
806 
807   TransformTree& transform_tree = property_trees()->transform_tree;
808   float layer_scale_factor = transform_tree.device_scale_factor() *
809                              transform_tree.device_transform_scale_factor();
810   TransformNode* transform_node =
811       transform_tree.Node(effect_node->transform_id);
812   if (transform_node->in_subtree_of_page_scale_layer)
813     layer_scale_factor *= transform_tree.page_scale_factor();
814 
815   const gfx::Vector2dF old_scale = effect_node->surface_contents_scale;
816   effect_node->surface_contents_scale =
817       MathUtil::ComputeTransform2dScaleComponents(
818           transform_tree.ToScreen(transform_node->id), layer_scale_factor);
819 
820   // If surface contents scale changes, draw transforms are no longer valid.
821   // Invalidates the draw transform cache and updates the clip for the surface.
822   if (old_scale != effect_node->surface_contents_scale) {
823     property_trees()->clip_tree.set_needs_update(true);
824     property_trees()->UpdateTransformTreeUpdateNumber();
825   }
826 }
827 
FindNodeFromElementId(ElementId id)828 EffectNode* EffectTree::FindNodeFromElementId(ElementId id) {
829   auto iterator = property_trees()->element_id_to_effect_node_index.find(id);
830   if (iterator == property_trees()->element_id_to_effect_node_index.end())
831     return nullptr;
832 
833   return Node(iterator->second);
834 }
835 
OnOpacityAnimated(ElementId id,float opacity)836 bool EffectTree::OnOpacityAnimated(ElementId id, float opacity) {
837   EffectNode* node = FindNodeFromElementId(id);
838   DCHECK(node);
839   if (node->opacity == opacity)
840     return false;
841   node->opacity = opacity;
842   node->effect_changed = true;
843   property_trees()->changed = true;
844   property_trees()->effect_tree.set_needs_update(true);
845   return true;
846 }
847 
OnFilterAnimated(ElementId id,const FilterOperations & filters)848 bool EffectTree::OnFilterAnimated(ElementId id,
849                                   const FilterOperations& filters) {
850   EffectNode* node = FindNodeFromElementId(id);
851   DCHECK(node);
852   if (node->filters == filters)
853     return false;
854   node->filters = filters;
855   node->effect_changed = true;
856   property_trees()->changed = true;
857   property_trees()->effect_tree.set_needs_update(true);
858   return true;
859 }
860 
OnBackdropFilterAnimated(ElementId id,const FilterOperations & backdrop_filters)861 bool EffectTree::OnBackdropFilterAnimated(
862     ElementId id,
863     const FilterOperations& backdrop_filters) {
864   EffectNode* node = FindNodeFromElementId(id);
865   DCHECK(node);
866   if (node->backdrop_filters == backdrop_filters)
867     return false;
868   node->backdrop_filters = backdrop_filters;
869   node->effect_changed = true;
870   property_trees()->changed = true;
871   property_trees()->effect_tree.set_needs_update(true);
872   return true;
873 }
874 
UpdateEffects(int id)875 void EffectTree::UpdateEffects(int id) {
876   EffectNode* node = Node(id);
877   EffectNode* parent_node = parent(node);
878 
879   UpdateOpacities(node, parent_node);
880   UpdateSubtreeHidden(node, parent_node);
881   UpdateIsDrawn(node, parent_node);
882   UpdateEffectChanged(node, parent_node);
883   UpdateHasFilters(node, parent_node);
884   UpdateBackfaceVisibility(node, parent_node);
885   UpdateHasMaskingChild(node, parent_node);
886   UpdateOnlyDrawsVisibleContent(node, parent_node);
887   UpdateSurfaceContentsScale(node);
888 }
889 
AddCopyRequest(int node_id,std::unique_ptr<viz::CopyOutputRequest> request)890 void EffectTree::AddCopyRequest(
891     int node_id,
892     std::unique_ptr<viz::CopyOutputRequest> request) {
893   copy_requests_.insert(std::make_pair(node_id, std::move(request)));
894 }
895 
PushCopyRequestsTo(EffectTree * other_tree)896 void EffectTree::PushCopyRequestsTo(EffectTree* other_tree) {
897   // If other_tree still has copy requests, this means there was a commit
898   // without a draw. This only happens in some edge cases during lost context or
899   // visibility changes, so don't try to handle preserving these output
900   // requests.
901   if (!other_tree->copy_requests_.empty()) {
902     // Destroying these copy requests will abort them.
903     other_tree->copy_requests_.clear();
904   }
905 
906   if (copy_requests_.empty())
907     return;
908 
909   for (auto& request : copy_requests_) {
910     other_tree->copy_requests_.insert(
911         std::make_pair(request.first, std::move(request.second)));
912   }
913   copy_requests_.clear();
914 
915   // Property trees need to get rebuilt since effect nodes (and render surfaces)
916   // that were created only for the copy requests we just pushed are no longer
917   // needed.
918   if (property_trees()->is_main_thread)
919     property_trees()->needs_rebuild = true;
920 }
921 
TakeCopyRequestsAndTransformToSurface(int node_id,std::vector<std::unique_ptr<viz::CopyOutputRequest>> * requests)922 void EffectTree::TakeCopyRequestsAndTransformToSurface(
923     int node_id,
924     std::vector<std::unique_ptr<viz::CopyOutputRequest>>* requests) {
925   EffectNode* effect_node = Node(node_id);
926   DCHECK(effect_node->HasRenderSurface());
927   DCHECK(effect_node->has_copy_request);
928 
929   // The area needs to be transformed from the space of content that draws to
930   // the surface to the space of the surface itself.
931   int destination_id = effect_node->transform_id;
932   int source_id;
933   if (effect_node->parent_id != EffectTree::kInvalidNodeId) {
934     // For non-root surfaces, transform only by sub-layer scale.
935     source_id = destination_id;
936   } else {
937     // The root surface doesn't have the notion of sub-layer scale, but instead
938     // has a similar notion of transforming from the space of the root layer to
939     // the space of the screen.
940     DCHECK_EQ(kRootNodeId, destination_id);
941     source_id = TransformTree::kContentsRootNodeId;
942   }
943   gfx::Transform transform;
944   property_trees()->GetToTarget(source_id, node_id, &transform);
945 
946   // Move each CopyOutputRequest out of |copy_requests_| and into |requests|,
947   // adjusting the source area and scale ratio of each. If the transform is
948   // something other than a straightforward translate+scale, the copy requests
949   // will be dropped.
950   auto range = copy_requests_.equal_range(node_id);
951   if (transform.IsPositiveScaleOrTranslation()) {
952     // Transform a vector in content space to surface space to determine how the
953     // scale ratio of each CopyOutputRequest should be adjusted. Since the scale
954     // ratios are provided integer coordinates, the basis vector determines the
955     // precision w.r.t. the fractional part of the Transform's scale factors.
956     constexpr gfx::Vector2d kContentVector(1024, 1024);
957     gfx::RectF surface_rect(0, 0, kContentVector.x(), kContentVector.y());
958     transform.TransformRect(&surface_rect);
959 
960     for (auto it = range.first; it != range.second; ++it) {
961       viz::CopyOutputRequest* const request = it->second.get();
962       if (request->has_area()) {
963         // Avoid creating bigger copy area which may contain unnecessary
964         // area if the error margin is tiny.
965         constexpr float kEpsilon = 0.001f;
966         request->set_area(MathUtil::MapEnclosingClippedRectIgnoringError(
967             transform, request->area(), kEpsilon));
968       }
969 
970       // Only adjust the scale ratio if the request specifies one, or if it
971       // specifies a result selection. Otherwise, the requestor is expecting a
972       // copy of the exact source pixels. If the adjustment to the scale ratio
973       // would produce out-of-range values, drop the copy request.
974       if (request->is_scaled() || request->has_result_selection()) {
975         float scale_from_x_f = request->scale_from().x() * surface_rect.width();
976         float scale_from_y_f =
977             request->scale_from().y() * surface_rect.height();
978         if (std::isnan(scale_from_x_f) ||
979             !base::IsValueInRangeForNumericType<int>(scale_from_x_f) ||
980             std::isnan(scale_from_y_f) ||
981             !base::IsValueInRangeForNumericType<int>(scale_from_y_f)) {
982           continue;
983         }
984         int scale_to_x = request->scale_to().x();
985         int scale_to_y = request->scale_to().y();
986         if (!base::CheckMul(scale_to_x, kContentVector.x())
987                  .AssignIfValid(&scale_to_x) ||
988             !base::CheckMul(scale_to_y, kContentVector.y())
989                  .AssignIfValid(&scale_to_y)) {
990           continue;
991         }
992         int scale_from_x = base::ClampRound(scale_from_x_f);
993         int scale_from_y = base::ClampRound(scale_from_y_f);
994         if (scale_from_x <= 0 || scale_from_y <= 0 || scale_to_x <= 0 ||
995             scale_to_y <= 0) {
996           // Transformed scaling ratio became illegal. Drop the request to
997           // provide an empty response.
998           continue;
999         }
1000         request->SetScaleRatio(gfx::Vector2d(scale_from_x, scale_from_y),
1001                                gfx::Vector2d(scale_to_x, scale_to_y));
1002       }
1003 
1004       requests->push_back(std::move(it->second));
1005     }
1006   }
1007   copy_requests_.erase(range.first, range.second);
1008 }
1009 
HasCopyRequests() const1010 bool EffectTree::HasCopyRequests() const {
1011   return !copy_requests_.empty();
1012 }
1013 
ClearCopyRequests()1014 void EffectTree::ClearCopyRequests() {
1015   for (auto& node : nodes()) {
1016     node.subtree_has_copy_request = false;
1017     node.has_copy_request = false;
1018     node.closest_ancestor_with_copy_request_id = EffectTree::kInvalidNodeId;
1019   }
1020 
1021   // Any copy requests that are still left will be aborted (sending an empty
1022   // result) on destruction.
1023   copy_requests_.clear();
1024   set_needs_update(true);
1025 }
1026 
LowestCommonAncestorWithRenderSurface(int id_1,int id_2) const1027 int EffectTree::LowestCommonAncestorWithRenderSurface(int id_1,
1028                                                       int id_2) const {
1029   DCHECK(GetRenderSurface(id_1));
1030   DCHECK(GetRenderSurface(id_2));
1031   while (id_1 != id_2) {
1032     if (id_1 < id_2)
1033       id_2 = Node(id_2)->target_id;
1034     else
1035       id_1 = Node(id_1)->target_id;
1036   }
1037 
1038   return id_1;
1039 }
1040 
ContributesToDrawnSurface(int id)1041 bool EffectTree::ContributesToDrawnSurface(int id) {
1042   // All drawn nodes contribute to drawn surface.
1043   // Exception : Nodes that are hidden and are drawn only for the sake of
1044   // copy requests.
1045   EffectNode* node = Node(id);
1046   EffectNode* parent_node = parent(node);
1047   return node->is_drawn && (!parent_node || parent_node->is_drawn);
1048 }
1049 
ResetChangeTracking()1050 void EffectTree::ResetChangeTracking() {
1051   for (int id = EffectTree::kContentsRootNodeId; id < static_cast<int>(size());
1052        ++id) {
1053     Node(id)->effect_changed = false;
1054     if (render_surfaces_[id])
1055       render_surfaces_[id]->ResetPropertyChangedFlags();
1056   }
1057 }
1058 
TakeRenderSurfaces(std::vector<std::unique_ptr<RenderSurfaceImpl>> * render_surfaces)1059 void EffectTree::TakeRenderSurfaces(
1060     std::vector<std::unique_ptr<RenderSurfaceImpl>>* render_surfaces) {
1061   for (int id = kContentsRootNodeId; id < static_cast<int>(size()); ++id) {
1062     if (render_surfaces_[id]) {
1063       render_surfaces->push_back(std::move(render_surfaces_[id]));
1064     }
1065   }
1066 }
1067 
CreateOrReuseRenderSurfaces(std::vector<std::unique_ptr<RenderSurfaceImpl>> * old_render_surfaces,LayerTreeImpl * layer_tree_impl)1068 bool EffectTree::CreateOrReuseRenderSurfaces(
1069     std::vector<std::unique_ptr<RenderSurfaceImpl>>* old_render_surfaces,
1070     LayerTreeImpl* layer_tree_impl) {
1071   // Make a list of {stable id, node id} pairs for nodes that are supposed to
1072   // have surfaces.
1073   std::vector<std::pair<uint64_t, int>> stable_id_node_id_list;
1074   for (int id = kContentsRootNodeId; id < static_cast<int>(size()); ++id) {
1075     EffectNode* node = Node(id);
1076     if (node->HasRenderSurface()) {
1077       stable_id_node_id_list.push_back(
1078           std::make_pair(node->stable_id, node->id));
1079     }
1080   }
1081 
1082   // Sort by stable id so that we can process the two lists cosequentially.
1083   std::sort(stable_id_node_id_list.begin(), stable_id_node_id_list.end());
1084   std::sort(old_render_surfaces->begin(), old_render_surfaces->end(),
1085             [](const std::unique_ptr<RenderSurfaceImpl>& a,
1086                const std::unique_ptr<RenderSurfaceImpl>& b) {
1087               return a->id() < b->id();
1088             });
1089 
1090   bool render_surfaces_changed = false;
1091   auto surfaces_list_it = old_render_surfaces->begin();
1092   auto id_list_it = stable_id_node_id_list.begin();
1093   while (surfaces_list_it != old_render_surfaces->end() &&
1094          id_list_it != stable_id_node_id_list.end()) {
1095     if ((*surfaces_list_it)->id() == id_list_it->first) {
1096       int new_node_id = id_list_it->second;
1097       render_surfaces_[new_node_id] = std::move(*surfaces_list_it);
1098       render_surfaces_[new_node_id]->set_effect_tree_index(new_node_id);
1099       surfaces_list_it++;
1100       id_list_it++;
1101       continue;
1102     }
1103 
1104     render_surfaces_changed = true;
1105 
1106     if ((*surfaces_list_it)->id() > id_list_it->first) {
1107       int new_node_id = id_list_it->second;
1108       render_surfaces_[new_node_id] = std::make_unique<RenderSurfaceImpl>(
1109           layer_tree_impl, id_list_it->first);
1110       render_surfaces_[new_node_id]->set_effect_tree_index(new_node_id);
1111       id_list_it++;
1112     } else {
1113       surfaces_list_it++;
1114     }
1115   }
1116 
1117   if (surfaces_list_it != old_render_surfaces->end() ||
1118       id_list_it != stable_id_node_id_list.end()) {
1119     render_surfaces_changed = true;
1120   }
1121 
1122   while (id_list_it != stable_id_node_id_list.end()) {
1123     int new_node_id = id_list_it->second;
1124     render_surfaces_[new_node_id] =
1125         std::make_unique<RenderSurfaceImpl>(layer_tree_impl, id_list_it->first);
1126     render_surfaces_[new_node_id]->set_effect_tree_index(new_node_id);
1127     id_list_it++;
1128   }
1129 
1130   return render_surfaces_changed;
1131 }
1132 
ClippedHitTestRegionIsRectangle(int effect_id) const1133 bool EffectTree::ClippedHitTestRegionIsRectangle(int effect_id) const {
1134   const EffectNode* effect_node = Node(effect_id);
1135   for (; effect_node->id != kContentsRootNodeId;
1136        effect_node = Node(effect_node->target_id)) {
1137     gfx::Transform to_target;
1138     if (!property_trees()->GetToTarget(effect_node->transform_id,
1139                                        effect_node->target_id, &to_target) ||
1140         !to_target.Preserves2dAxisAlignment())
1141       return false;
1142   }
1143   return true;
1144 }
1145 
HitTestMayBeAffectedByMask(int effect_id) const1146 bool EffectTree::HitTestMayBeAffectedByMask(int effect_id) const {
1147   const EffectNode* effect_node = Node(effect_id);
1148   for (; effect_node->id != kContentsRootNodeId;
1149        effect_node = Node(effect_node->parent_id)) {
1150     if (!effect_node->mask_filter_info.IsEmpty() ||
1151         effect_node->has_masking_child)
1152       return true;
1153   }
1154   return false;
1155 }
1156 
SetViewportClip(gfx::RectF viewport_rect)1157 void ClipTree::SetViewportClip(gfx::RectF viewport_rect) {
1158   if (size() < 2)
1159     return;
1160   ClipNode* node = Node(1);
1161   if (viewport_rect == node->clip)
1162     return;
1163   node->clip = viewport_rect;
1164   set_needs_update(true);
1165 }
1166 
ViewportClip() const1167 gfx::RectF ClipTree::ViewportClip() const {
1168   const size_t min_size = 1;
1169   DCHECK_GT(size(), min_size);
1170   return Node(kViewportNodeId)->clip;
1171 }
1172 
1173 #if DCHECK_IS_ON()
operator ==(const ClipTree & other) const1174 bool ClipTree::operator==(const ClipTree& other) const {
1175   return PropertyTree::operator==(other);
1176 }
1177 #endif
1178 
operator =(const EffectTree & from)1179 EffectTree& EffectTree::operator=(const EffectTree& from) {
1180   PropertyTree::operator=(from);
1181   render_surfaces_.resize(size());
1182   // copy_requests_ are omitted here, since these need to be moved rather
1183   // than copied or assigned.
1184 
1185   return *this;
1186 }
1187 
1188 #if DCHECK_IS_ON()
operator ==(const EffectTree & other) const1189 bool EffectTree::operator==(const EffectTree& other) const {
1190   return PropertyTree::operator==(other);
1191 }
1192 #endif
1193 
ScrollTree()1194 ScrollTree::ScrollTree()
1195     : currently_scrolling_node_id_(kInvalidNodeId),
1196       scroll_offset_map_(ScrollTree::ScrollOffsetMap()) {}
1197 
1198 ScrollTree::~ScrollTree() = default;
1199 
operator =(const ScrollTree & from)1200 ScrollTree& ScrollTree::operator=(const ScrollTree& from) {
1201   PropertyTree::operator=(from);
1202   currently_scrolling_node_id_ = kInvalidNodeId;
1203   // Maps for ScrollOffsets/SyncedScrollOffsets are intentionally omitted here
1204   // since we can not directly copy them. Pushing of these updates from main
1205   // currently depends on Layer properties for scroll offset animation changes
1206   // (setting clobber_active_value for scroll offset animations interrupted on
1207   // the main thread) being pushed to impl first.
1208   // |callbacks_| is omitted because it's for the main thread only.
1209   return *this;
1210 }
1211 
1212 #if DCHECK_IS_ON()
operator ==(const ScrollTree & other) const1213 bool ScrollTree::operator==(const ScrollTree& other) const {
1214   if (scroll_offset_map_ != other.scroll_offset_map_)
1215     return false;
1216   if (synced_scroll_offset_map_ != other.synced_scroll_offset_map_)
1217     return false;
1218   if (callbacks_.get() != other.callbacks_.get())
1219     return false;
1220 
1221   bool is_currently_scrolling_node_equal =
1222       currently_scrolling_node_id_ == other.currently_scrolling_node_id_;
1223 
1224   return PropertyTree::operator==(other) && is_currently_scrolling_node_equal;
1225 }
1226 
CopyCompleteTreeState(const ScrollTree & other)1227 void ScrollTree::CopyCompleteTreeState(const ScrollTree& other) {
1228   currently_scrolling_node_id_ = other.currently_scrolling_node_id_;
1229   scroll_offset_map_ = other.scroll_offset_map_;
1230   synced_scroll_offset_map_ = other.synced_scroll_offset_map_;
1231   callbacks_ = other.callbacks_;
1232 }
1233 #endif  // DCHECK_IS_ON()
1234 
FindNodeFromElementId(ElementId id)1235 ScrollNode* ScrollTree::FindNodeFromElementId(ElementId id) {
1236   if (!id)
1237     return nullptr;
1238   auto iterator = property_trees()->element_id_to_scroll_node_index.find(id);
1239   if (iterator == property_trees()->element_id_to_scroll_node_index.end())
1240     return nullptr;
1241 
1242   return Node(iterator->second);
1243 }
1244 
FindNodeFromElementId(ElementId id) const1245 const ScrollNode* ScrollTree::FindNodeFromElementId(ElementId id) const {
1246   if (!id)
1247     return nullptr;
1248   auto iterator = property_trees()->element_id_to_scroll_node_index.find(id);
1249   if (iterator == property_trees()->element_id_to_scroll_node_index.end())
1250     return nullptr;
1251 
1252   return Node(iterator->second);
1253 }
1254 
IsComposited(const ScrollNode & node) const1255 bool ScrollTree::IsComposited(const ScrollNode& node) const {
1256   return node.is_composited;
1257 }
1258 
clear()1259 void ScrollTree::clear() {
1260   PropertyTree<ScrollNode>::clear();
1261 
1262   if (property_trees()->is_main_thread) {
1263     currently_scrolling_node_id_ = kInvalidNodeId;
1264     scroll_offset_map_.clear();
1265   }
1266 
1267 #if DCHECK_IS_ON()
1268   ScrollTree tree;
1269   if (property_trees()->is_main_thread) {
1270     tree.callbacks_ = callbacks_;
1271   } else {
1272     DCHECK(scroll_offset_map_.empty());
1273     tree.currently_scrolling_node_id_ = currently_scrolling_node_id_;
1274     tree.synced_scroll_offset_map_ = synced_scroll_offset_map_;
1275   }
1276   DCHECK(tree == *this);
1277 #endif
1278 }
1279 
MaxScrollOffset(int scroll_node_id) const1280 gfx::ScrollOffset ScrollTree::MaxScrollOffset(int scroll_node_id) const {
1281   const ScrollNode* scroll_node = Node(scroll_node_id);
1282   gfx::SizeF scroll_bounds = this->scroll_bounds(scroll_node_id);
1283 
1284   if (!scroll_node->scrollable || scroll_bounds.IsEmpty())
1285     return gfx::ScrollOffset();
1286 
1287   TransformTree& transform_tree = property_trees()->transform_tree;
1288   float scale_factor = 1.f;
1289   if (scroll_node->max_scroll_offset_affected_by_page_scale)
1290     scale_factor = transform_tree.page_scale_factor();
1291 
1292   gfx::SizeF scaled_scroll_bounds = gfx::ScaleSize(scroll_bounds, scale_factor);
1293   scaled_scroll_bounds.SetSize(std::floor(scaled_scroll_bounds.width()),
1294                                std::floor(scaled_scroll_bounds.height()));
1295 
1296   gfx::Size clip_layer_bounds = container_bounds(scroll_node->id);
1297 
1298   gfx::ScrollOffset _max_offset(
1299       scaled_scroll_bounds.width() - clip_layer_bounds.width(),
1300       scaled_scroll_bounds.height() - clip_layer_bounds.height());
1301 
1302   _max_offset.Scale(1 / scale_factor);
1303   _max_offset.SetToMax(gfx::ScrollOffset());
1304   return _max_offset;
1305 }
1306 
scroll_bounds(int scroll_node_id) const1307 gfx::SizeF ScrollTree::scroll_bounds(int scroll_node_id) const {
1308   const ScrollNode* scroll_node = Node(scroll_node_id);
1309   gfx::SizeF bounds(scroll_node->bounds);
1310   if (scroll_node->scrolls_inner_viewport) {
1311     const auto& delta = property_trees()->inner_viewport_scroll_bounds_delta();
1312     bounds.Enlarge(delta.x(), delta.y());
1313   }
1314   return bounds;
1315 }
1316 
OnScrollOffsetAnimated(ElementId id,int scroll_tree_index,const gfx::ScrollOffset & scroll_offset,LayerTreeImpl * layer_tree_impl)1317 void ScrollTree::OnScrollOffsetAnimated(ElementId id,
1318                                         int scroll_tree_index,
1319                                         const gfx::ScrollOffset& scroll_offset,
1320                                         LayerTreeImpl* layer_tree_impl) {
1321   // Only active tree needs to be updated, pending tree will find out about
1322   // these changes as a result of the shared SyncedProperty.
1323   if (!property_trees()->is_active)
1324     return;
1325 
1326   TRACE_EVENT2("cc", "ScrollTree::OnScrollOffsetAnimated", "x",
1327                scroll_offset.x(), "y", scroll_offset.y());
1328   ScrollNode* scroll_node = Node(scroll_tree_index);
1329   if (SetScrollOffset(id,
1330                       ClampScrollOffsetToLimits(scroll_offset, *scroll_node)))
1331     layer_tree_impl->DidUpdateScrollOffset(id);
1332   layer_tree_impl->DidAnimateScrollOffset();
1333 }
1334 
container_bounds(int scroll_node_id) const1335 gfx::Size ScrollTree::container_bounds(int scroll_node_id) const {
1336   const ScrollNode* scroll_node = Node(scroll_node_id);
1337   gfx::Size container_bounds = scroll_node->container_bounds;
1338 
1339   gfx::Vector2dF container_bounds_delta;
1340   if (scroll_node->scrolls_inner_viewport) {
1341     container_bounds_delta.Add(
1342         property_trees()->inner_viewport_container_bounds_delta());
1343   } else if (scroll_node->scrolls_outer_viewport) {
1344     container_bounds_delta.Add(
1345         property_trees()->outer_viewport_container_bounds_delta());
1346   }
1347 
1348   gfx::Vector2d delta = gfx::ToCeiledVector2d(container_bounds_delta);
1349   container_bounds.Enlarge(delta.x(), delta.y());
1350 
1351   return container_bounds;
1352 }
1353 
CurrentlyScrollingNode()1354 ScrollNode* ScrollTree::CurrentlyScrollingNode() {
1355   ScrollNode* scroll_node = Node(currently_scrolling_node_id_);
1356   return scroll_node;
1357 }
1358 
CurrentlyScrollingNode() const1359 const ScrollNode* ScrollTree::CurrentlyScrollingNode() const {
1360   const ScrollNode* scroll_node = Node(currently_scrolling_node_id_);
1361   return scroll_node;
1362 }
1363 
1364 #if DCHECK_IS_ON()
CurrentlyScrollingNodeId() const1365 int ScrollTree::CurrentlyScrollingNodeId() const {
1366   return currently_scrolling_node_id_;
1367 }
1368 #endif
1369 
set_currently_scrolling_node(int scroll_node_id)1370 void ScrollTree::set_currently_scrolling_node(int scroll_node_id) {
1371   currently_scrolling_node_id_ = scroll_node_id;
1372 }
1373 
ScreenSpaceTransform(int scroll_node_id) const1374 gfx::Transform ScrollTree::ScreenSpaceTransform(int scroll_node_id) const {
1375   const ScrollNode* scroll_node = Node(scroll_node_id);
1376   const TransformTree& transform_tree = property_trees()->transform_tree;
1377   const TransformNode* transform_node =
1378       transform_tree.Node(scroll_node->transform_id);
1379   gfx::Transform screen_space_transform(
1380       1, 0, 0, 1, scroll_node->offset_to_transform_parent.x(),
1381       scroll_node->offset_to_transform_parent.y());
1382   screen_space_transform.ConcatTransform(
1383       transform_tree.ToScreen(transform_node->id));
1384   if (scroll_node->should_flatten)
1385     screen_space_transform.FlattenTo2d();
1386   return screen_space_transform;
1387 }
1388 
GetOrCreateSyncedScrollOffset(ElementId id)1389 SyncedScrollOffset* ScrollTree::GetOrCreateSyncedScrollOffset(ElementId id) {
1390   DCHECK(!property_trees()->is_main_thread);
1391   if (synced_scroll_offset_map_.find(id) == synced_scroll_offset_map_.end()) {
1392     synced_scroll_offset_map_[id] = new SyncedScrollOffset;
1393   }
1394   return synced_scroll_offset_map_[id].get();
1395 }
1396 
GetSyncedScrollOffset(ElementId id) const1397 const SyncedScrollOffset* ScrollTree::GetSyncedScrollOffset(
1398     ElementId id) const {
1399   DCHECK(!property_trees()->is_main_thread);
1400   auto it = synced_scroll_offset_map_.find(id);
1401   return it != synced_scroll_offset_map_.end() ? it->second.get() : nullptr;
1402 }
1403 
ClampScrollToMaxScrollOffset(const ScrollNode & node,LayerTreeImpl * layer_tree_impl)1404 gfx::Vector2dF ScrollTree::ClampScrollToMaxScrollOffset(
1405     const ScrollNode& node,
1406     LayerTreeImpl* layer_tree_impl) {
1407   gfx::ScrollOffset old_offset = current_scroll_offset(node.element_id);
1408   gfx::ScrollOffset clamped_offset =
1409       ClampScrollOffsetToLimits(old_offset, node);
1410   gfx::Vector2dF delta = clamped_offset.DeltaFrom(old_offset);
1411   if (!delta.IsZero())
1412     ScrollBy(node, delta, layer_tree_impl);
1413   return delta;
1414 }
1415 
current_scroll_offset(ElementId id) const1416 const gfx::ScrollOffset ScrollTree::current_scroll_offset(ElementId id) const {
1417   if (property_trees()->is_main_thread) {
1418     auto it = scroll_offset_map_.find(id);
1419     return it != scroll_offset_map_.end() ? it->second : gfx::ScrollOffset();
1420   }
1421   return GetSyncedScrollOffset(id)
1422              ? GetSyncedScrollOffset(id)->Current(property_trees()->is_active)
1423              : gfx::ScrollOffset();
1424 }
1425 
GetPixelSnappedScrollOffset(int scroll_node_id) const1426 const gfx::ScrollOffset ScrollTree::GetPixelSnappedScrollOffset(
1427     int scroll_node_id) const {
1428   const ScrollNode* scroll_node = Node(scroll_node_id);
1429   DCHECK(scroll_node);
1430   gfx::ScrollOffset offset = current_scroll_offset(scroll_node->element_id);
1431 
1432   const TransformNode* transform_node =
1433       property_trees()->transform_tree.Node(scroll_node->transform_id);
1434   DCHECK(offset == transform_node->scroll_offset)
1435       << "Transform node scroll offset does not match the actual offset, this "
1436          "means the snapped_amount calculation will be incorrect";
1437 
1438   if (transform_node->scrolls) {
1439     // If necessary perform a update for this node to ensure snap amount is
1440     // accurate. This method is used by scroll timeline, so it is possible for
1441     // it to get called before transform tree has gone through a full update
1442     // cycle so this node snap amount may be stale.
1443     if (transform_node->needs_local_transform_update)
1444       property_trees()->transform_tree.UpdateTransforms(transform_node->id);
1445 
1446     // The calculated pixel snap amount can be slightly larger than the actual
1447     // snapping needed, due to floating point precision errors. In general this
1448     // is fine, but we never want to report a negative scroll offset so avoid
1449     // that case here.
1450     // TODO(crbug.com/1076878): Remove the clamping when scroll timeline effects
1451     // always match the snapping.
1452     offset = ClampScrollOffsetToLimits(
1453         offset - gfx::ScrollOffset(transform_node->snap_amount), *scroll_node);
1454   }
1455 
1456   return offset;
1457 }
1458 
PullDeltaForMainThread(SyncedScrollOffset * scroll_offset,bool use_fractional_deltas)1459 gfx::ScrollOffset ScrollTree::PullDeltaForMainThread(
1460     SyncedScrollOffset* scroll_offset,
1461     bool use_fractional_deltas) {
1462   DCHECK(property_trees()->is_active);
1463 
1464   // Once this setting is enabled, all the complicated rounding logic below can
1465   // go away.
1466   if (use_fractional_deltas)
1467     return scroll_offset->PullDeltaForMainThread();
1468 
1469   // TODO(flackr): We should pass the fractional scroll deltas when Blink fully
1470   // supports fractional scrolls. crbug.com/414283.
1471   // TODO(flackr): We should ideally round the fractional scrolls in the same
1472   // direction as the scroll will be snapped but for common cases this is
1473   // equivalent to rounding to the nearest integer offset.
1474   gfx::ScrollOffset current_offset =
1475       scroll_offset->Current(/* is_active_tree */ true);
1476   gfx::ScrollOffset rounded_offset =
1477       gfx::ScrollOffset(roundf(current_offset.x()), roundf(current_offset.y()));
1478   // The calculation of the difference from the rounded active base is to
1479   // represent the integer delta that the main thread should know about.
1480   gfx::ScrollOffset active_base = scroll_offset->ActiveBase();
1481   gfx::ScrollOffset diff_active_base =
1482       gfx::ScrollOffset(active_base.x() - roundf(active_base.x()),
1483                         active_base.y() - roundf(active_base.y()));
1484   scroll_offset->SetCurrent(rounded_offset + diff_active_base);
1485   gfx::ScrollOffset delta = scroll_offset->PullDeltaForMainThread();
1486   scroll_offset->SetCurrent(current_offset);
1487   return delta;
1488 }
1489 
CollectScrollDeltas(CompositorCommitData * commit_data,ElementId inner_viewport_scroll_element_id,bool use_fractional_deltas,const base::flat_set<ElementId> & snapped_elements)1490 void ScrollTree::CollectScrollDeltas(
1491     CompositorCommitData* commit_data,
1492     ElementId inner_viewport_scroll_element_id,
1493     bool use_fractional_deltas,
1494     const base::flat_set<ElementId>& snapped_elements) {
1495   DCHECK(!property_trees()->is_main_thread);
1496   TRACE_EVENT0("cc", "ScrollTree::CollectScrollDeltas");
1497   for (auto map_entry : synced_scroll_offset_map_) {
1498     gfx::ScrollOffset scroll_delta =
1499         PullDeltaForMainThread(map_entry.second.get(), use_fractional_deltas);
1500 
1501     ElementId id = map_entry.first;
1502 
1503     base::Optional<TargetSnapAreaElementIds> snap_target_ids;
1504     if (snapped_elements.find(id) != snapped_elements.end()) {
1505       ScrollNode* scroll_node = FindNodeFromElementId(id);
1506       if (scroll_node && scroll_node->snap_container_data) {
1507         snap_target_ids = scroll_node->snap_container_data.value()
1508                               .GetTargetSnapAreaElementIds();
1509       }
1510     }
1511 
1512     // Snap targets are set at the end of scroll offset animations (i.e when the
1513     // animation state is updated to FINISHED). The state can be updated after
1514     // the compositor's draw stage, which means the next attempt to push the
1515     // snap targets is during the next frame. This makes it possible for the
1516     // scroll delta to be zero.
1517     if (!scroll_delta.IsZero() || snap_target_ids) {
1518       TRACE_EVENT_INSTANT2("cc", "CollectScrollDeltas",
1519                            TRACE_EVENT_SCOPE_THREAD, "x", scroll_delta.x(), "y",
1520                            scroll_delta.y());
1521       CompositorCommitData::ScrollUpdateInfo update(id, scroll_delta,
1522                                                     snap_target_ids);
1523       if (id == inner_viewport_scroll_element_id) {
1524         // Inner (visual) viewport is stored separately.
1525         commit_data->inner_viewport_scroll = std::move(update);
1526       } else {
1527         commit_data->scrolls.push_back(std::move(update));
1528       }
1529     }
1530   }
1531 }
1532 
CollectScrollDeltasForTesting()1533 void ScrollTree::CollectScrollDeltasForTesting() {
1534   LayerTreeSettings settings;
1535   bool use_fractional_deltas = settings.commit_fractional_scroll_deltas;
1536 
1537   for (auto map_entry : synced_scroll_offset_map_) {
1538     PullDeltaForMainThread(map_entry.second.get(), use_fractional_deltas);
1539   }
1540 }
1541 
PushScrollUpdatesFromMainThread(PropertyTrees * main_property_trees,LayerTreeImpl * sync_tree)1542 void ScrollTree::PushScrollUpdatesFromMainThread(
1543     PropertyTrees* main_property_trees,
1544     LayerTreeImpl* sync_tree) {
1545   DCHECK(!property_trees()->is_main_thread);
1546   const ScrollOffsetMap& main_scroll_offset_map =
1547       main_property_trees->scroll_tree.scroll_offset_map_;
1548 
1549   // We first want to clear SyncedProperty instances for layers which were
1550   // destroyed or became non-scrollable on the main thread.
1551   for (auto map_entry = synced_scroll_offset_map_.begin();
1552        map_entry != synced_scroll_offset_map_.end();) {
1553     ElementId id = map_entry->first;
1554     if (main_scroll_offset_map.find(id) == main_scroll_offset_map.end())
1555       map_entry = synced_scroll_offset_map_.erase(map_entry);
1556     else
1557       map_entry++;
1558   }
1559 
1560   for (auto map_entry : main_scroll_offset_map) {
1561     ElementId id = map_entry.first;
1562     SyncedScrollOffset* synced_scroll_offset =
1563         GetOrCreateSyncedScrollOffset(id);
1564 
1565     // If the value on the main thread differs from the value on the pending
1566     // tree after state sync, we need to update the scroll state on the newly
1567     // committed PropertyTrees.
1568     bool needs_scroll_update =
1569         synced_scroll_offset->PushMainToPending(map_entry.second);
1570 
1571     // If we are committing directly to the active tree, push pending to active
1572     // here. If the value differs between the pending and active trees, we need
1573     // to update the scroll state on the newly activated PropertyTrees.
1574     // In the case of pushing to the active tree, even if the pending and active
1575     // tree state match but the value on the active tree changed, we need to
1576     // update the scrollbar geometries.
1577     if (property_trees()->is_active)
1578       needs_scroll_update |= synced_scroll_offset->PushPendingToActive();
1579 
1580     if (needs_scroll_update)
1581       sync_tree->DidUpdateScrollOffset(id);
1582   }
1583 }
1584 
PushScrollUpdatesFromPendingTree(PropertyTrees * pending_property_trees,LayerTreeImpl * active_tree)1585 void ScrollTree::PushScrollUpdatesFromPendingTree(
1586     PropertyTrees* pending_property_trees,
1587     LayerTreeImpl* active_tree) {
1588   DCHECK(property_trees()->is_active);
1589   DCHECK(!pending_property_trees->is_main_thread);
1590   DCHECK(!pending_property_trees->is_active);
1591 
1592   // When pushing to the active tree, we can simply copy over the map from the
1593   // pending tree. The pending and active tree hold a reference to the same
1594   // SyncedProperty instances.
1595   synced_scroll_offset_map_.clear();
1596   for (auto map_entry :
1597        pending_property_trees->scroll_tree.synced_scroll_offset_map_) {
1598     synced_scroll_offset_map_[map_entry.first] = map_entry.second;
1599     if (map_entry.second->PushPendingToActive())
1600       active_tree->DidUpdateScrollOffset(map_entry.first);
1601   }
1602 }
1603 
ApplySentScrollDeltasFromAbortedCommit()1604 void ScrollTree::ApplySentScrollDeltasFromAbortedCommit() {
1605   DCHECK(property_trees()->is_active);
1606   for (auto& map_entry : synced_scroll_offset_map_)
1607     map_entry.second->AbortCommit();
1608 }
1609 
SetBaseScrollOffset(ElementId id,const gfx::ScrollOffset & scroll_offset)1610 void ScrollTree::SetBaseScrollOffset(ElementId id,
1611                                      const gfx::ScrollOffset& scroll_offset) {
1612   if (property_trees()->is_main_thread) {
1613     scroll_offset_map_[id] = scroll_offset;
1614     return;
1615   }
1616 
1617   // Scroll offset updates on the impl thread should only be for layers which
1618   // were created on the main thread. But this method is called when we build
1619   // PropertyTrees on the impl thread from LayerTreeImpl.
1620   GetOrCreateSyncedScrollOffset(id)->PushMainToPending(scroll_offset);
1621 }
1622 
SetScrollOffset(ElementId id,const gfx::ScrollOffset & scroll_offset)1623 bool ScrollTree::SetScrollOffset(ElementId id,
1624                                  const gfx::ScrollOffset& scroll_offset) {
1625   // TODO(crbug.com/1087088): Remove TRACE_EVENT call when the bug is fixed
1626   TRACE_EVENT2("cc", "ScrollTree::SetScrollOffset", "x", scroll_offset.x(), "y",
1627                scroll_offset.y());
1628   if (property_trees()->is_main_thread) {
1629     if (scroll_offset_map_[id] == scroll_offset)
1630       return false;
1631     scroll_offset_map_[id] = scroll_offset;
1632     return true;
1633   }
1634 
1635   if (property_trees()->is_active) {
1636     return GetOrCreateSyncedScrollOffset(id)->SetCurrent(scroll_offset);
1637   }
1638 
1639   return false;
1640 }
1641 
UpdateScrollOffsetBaseForTesting(ElementId id,const gfx::ScrollOffset & offset)1642 bool ScrollTree::UpdateScrollOffsetBaseForTesting(
1643     ElementId id,
1644     const gfx::ScrollOffset& offset) {
1645   DCHECK(!property_trees()->is_main_thread);
1646   SyncedScrollOffset* synced_scroll_offset = GetOrCreateSyncedScrollOffset(id);
1647   bool changed = synced_scroll_offset->PushMainToPending(offset);
1648   if (property_trees()->is_active)
1649     changed |= synced_scroll_offset->PushPendingToActive();
1650   return changed;
1651 }
1652 
SetScrollOffsetDeltaForTesting(ElementId id,const gfx::Vector2dF & delta)1653 bool ScrollTree::SetScrollOffsetDeltaForTesting(ElementId id,
1654                                                 const gfx::Vector2dF& delta) {
1655   return GetOrCreateSyncedScrollOffset(id)->SetCurrent(
1656       GetOrCreateSyncedScrollOffset(id)->ActiveBase() +
1657       gfx::ScrollOffset(delta));
1658 }
1659 
GetScrollOffsetBaseForTesting(ElementId id) const1660 const gfx::ScrollOffset ScrollTree::GetScrollOffsetBaseForTesting(
1661     ElementId id) const {
1662   DCHECK(!property_trees()->is_main_thread);
1663   if (GetSyncedScrollOffset(id))
1664     return property_trees()->is_active
1665                ? GetSyncedScrollOffset(id)->ActiveBase()
1666                : GetSyncedScrollOffset(id)->PendingBase();
1667   else
1668     return gfx::ScrollOffset();
1669 }
1670 
GetScrollOffsetDeltaForTesting(ElementId id) const1671 const gfx::ScrollOffset ScrollTree::GetScrollOffsetDeltaForTesting(
1672     ElementId id) const {
1673   DCHECK(!property_trees()->is_main_thread);
1674   if (GetSyncedScrollOffset(id))
1675     return property_trees()->is_active
1676                ? GetSyncedScrollOffset(id)->Delta()
1677                : GetSyncedScrollOffset(id)->PendingDelta().get();
1678   else
1679     return gfx::ScrollOffset();
1680 }
1681 
ScrollBy(const ScrollNode & scroll_node,const gfx::Vector2dF & scroll,LayerTreeImpl * layer_tree_impl)1682 gfx::Vector2dF ScrollTree::ScrollBy(const ScrollNode& scroll_node,
1683                                     const gfx::Vector2dF& scroll,
1684                                     LayerTreeImpl* layer_tree_impl) {
1685   gfx::ScrollOffset adjusted_scroll(scroll);
1686   if (!scroll_node.user_scrollable_horizontal)
1687     adjusted_scroll.set_x(0);
1688   if (!scroll_node.user_scrollable_vertical)
1689     adjusted_scroll.set_y(0);
1690   DCHECK(scroll_node.scrollable);
1691   gfx::ScrollOffset old_offset = current_scroll_offset(scroll_node.element_id);
1692   gfx::ScrollOffset new_offset =
1693       ClampScrollOffsetToLimits(old_offset + adjusted_scroll, scroll_node);
1694   if (SetScrollOffset(scroll_node.element_id, new_offset))
1695     layer_tree_impl->DidUpdateScrollOffset(scroll_node.element_id);
1696 
1697   gfx::ScrollOffset unscrolled =
1698       old_offset + gfx::ScrollOffset(scroll) - new_offset;
1699   return gfx::Vector2dF(unscrolled.x(), unscrolled.y());
1700 }
1701 
ClampScrollOffsetToLimits(gfx::ScrollOffset offset,const ScrollNode & scroll_node) const1702 gfx::ScrollOffset ScrollTree::ClampScrollOffsetToLimits(
1703     gfx::ScrollOffset offset,
1704     const ScrollNode& scroll_node) const {
1705   offset.SetToMin(MaxScrollOffset(scroll_node.id));
1706   offset.SetToMax(gfx::ScrollOffset());
1707   return offset;
1708 }
1709 
SetScrollCallbacks(base::WeakPtr<ScrollCallbacks> callbacks)1710 void ScrollTree::SetScrollCallbacks(base::WeakPtr<ScrollCallbacks> callbacks) {
1711   DCHECK(property_trees()->is_main_thread);
1712   callbacks_ = std::move(callbacks);
1713 }
1714 
NotifyDidScroll(ElementId scroll_element_id,const gfx::ScrollOffset & scroll_offset,const base::Optional<TargetSnapAreaElementIds> & snap_target_ids)1715 void ScrollTree::NotifyDidScroll(
1716     ElementId scroll_element_id,
1717     const gfx::ScrollOffset& scroll_offset,
1718     const base::Optional<TargetSnapAreaElementIds>& snap_target_ids) {
1719   DCHECK(property_trees()->is_main_thread);
1720   if (callbacks_)
1721     callbacks_->DidScroll(scroll_element_id, scroll_offset, snap_target_ids);
1722 }
1723 
NotifyDidChangeScrollbarsHidden(ElementId scroll_element_id,bool hidden)1724 void ScrollTree::NotifyDidChangeScrollbarsHidden(ElementId scroll_element_id,
1725                                                  bool hidden) {
1726   DCHECK(property_trees()->is_main_thread);
1727   if (callbacks_)
1728     callbacks_->DidChangeScrollbarsHidden(scroll_element_id, hidden);
1729 }
1730 
PropertyTreesCachedData()1731 PropertyTreesCachedData::PropertyTreesCachedData()
1732     : transform_tree_update_number(0) {
1733   animation_scales.clear();
1734 }
1735 
1736 PropertyTreesCachedData::~PropertyTreesCachedData() = default;
1737 
PropertyTrees()1738 PropertyTrees::PropertyTrees()
1739     : needs_rebuild(true),
1740       changed(false),
1741       full_tree_damaged(false),
1742       sequence_number(0),
1743       is_main_thread(true),
1744       is_active(false) {
1745   transform_tree.SetPropertyTrees(this);
1746   effect_tree.SetPropertyTrees(this);
1747   clip_tree.SetPropertyTrees(this);
1748   scroll_tree.SetPropertyTrees(this);
1749 }
1750 
1751 PropertyTrees::~PropertyTrees() = default;
1752 
1753 #if DCHECK_IS_ON()
operator ==(const PropertyTrees & other) const1754 bool PropertyTrees::operator==(const PropertyTrees& other) const {
1755   return transform_tree == other.transform_tree &&
1756          effect_tree == other.effect_tree && clip_tree == other.clip_tree &&
1757          scroll_tree == other.scroll_tree &&
1758          element_id_to_effect_node_index ==
1759              other.element_id_to_effect_node_index &&
1760          element_id_to_scroll_node_index ==
1761              other.element_id_to_scroll_node_index &&
1762          element_id_to_transform_node_index ==
1763              other.element_id_to_transform_node_index &&
1764          needs_rebuild == other.needs_rebuild && changed == other.changed &&
1765          full_tree_damaged == other.full_tree_damaged &&
1766          is_main_thread == other.is_main_thread &&
1767          is_active == other.is_active &&
1768          sequence_number == other.sequence_number;
1769 }
1770 #endif
1771 
operator =(const PropertyTrees & from)1772 PropertyTrees& PropertyTrees::operator=(const PropertyTrees& from) {
1773   transform_tree = from.transform_tree;
1774   effect_tree = from.effect_tree;
1775   clip_tree = from.clip_tree;
1776   scroll_tree = from.scroll_tree;
1777   element_id_to_effect_node_index = from.element_id_to_effect_node_index;
1778   element_id_to_scroll_node_index = from.element_id_to_scroll_node_index;
1779   element_id_to_transform_node_index = from.element_id_to_transform_node_index;
1780   needs_rebuild = from.needs_rebuild;
1781   changed = from.changed;
1782   full_tree_damaged = from.full_tree_damaged;
1783   sequence_number = from.sequence_number;
1784   is_main_thread = from.is_main_thread;
1785   is_active = from.is_active;
1786   inner_viewport_container_bounds_delta_ =
1787       from.inner_viewport_container_bounds_delta();
1788   outer_viewport_container_bounds_delta_ =
1789       from.outer_viewport_container_bounds_delta();
1790   transform_tree.SetPropertyTrees(this);
1791   effect_tree.SetPropertyTrees(this);
1792   clip_tree.SetPropertyTrees(this);
1793   scroll_tree.SetPropertyTrees(this);
1794   ResetCachedData();
1795   return *this;
1796 }
1797 
clear()1798 void PropertyTrees::clear() {
1799   transform_tree.clear();
1800   clip_tree.clear();
1801   effect_tree.clear();
1802   scroll_tree.clear();
1803   element_id_to_effect_node_index.clear();
1804   element_id_to_scroll_node_index.clear();
1805   element_id_to_transform_node_index.clear();
1806 
1807   needs_rebuild = true;
1808   full_tree_damaged = false;
1809   changed = false;
1810   sequence_number++;
1811 
1812 #if DCHECK_IS_ON()
1813   PropertyTrees tree;
1814   tree.transform_tree = transform_tree;
1815   tree.effect_tree = effect_tree;
1816   tree.clip_tree = clip_tree;
1817   tree.scroll_tree = scroll_tree;
1818   tree.scroll_tree.CopyCompleteTreeState(scroll_tree);
1819 
1820   tree.sequence_number = sequence_number;
1821   tree.is_main_thread = is_main_thread;
1822   tree.is_active = is_active;
1823   DCHECK(tree == *this);
1824 #endif
1825 }
1826 
SetInnerViewportContainerBoundsDelta(gfx::Vector2dF bounds_delta)1827 void PropertyTrees::SetInnerViewportContainerBoundsDelta(
1828     gfx::Vector2dF bounds_delta) {
1829   if (inner_viewport_container_bounds_delta_ == bounds_delta)
1830     return;
1831 
1832   inner_viewport_container_bounds_delta_ = bounds_delta;
1833 }
1834 
SetOuterViewportContainerBoundsDelta(gfx::Vector2dF bounds_delta)1835 void PropertyTrees::SetOuterViewportContainerBoundsDelta(
1836     gfx::Vector2dF bounds_delta) {
1837   if (outer_viewport_container_bounds_delta_ == bounds_delta)
1838     return;
1839 
1840   outer_viewport_container_bounds_delta_ = bounds_delta;
1841   transform_tree.UpdateOuterViewportContainerBoundsDelta();
1842 }
1843 
ElementIsAnimatingChanged(const PropertyToElementIdMap & element_id_map,const PropertyAnimationState & mask,const PropertyAnimationState & state,bool check_node_existence)1844 bool PropertyTrees::ElementIsAnimatingChanged(
1845     const PropertyToElementIdMap& element_id_map,
1846     const PropertyAnimationState& mask,
1847     const PropertyAnimationState& state,
1848     bool check_node_existence) {
1849   bool updated_transform = false;
1850   for (int property = TargetProperty::FIRST_TARGET_PROPERTY;
1851        property <= TargetProperty::LAST_TARGET_PROPERTY; ++property) {
1852     if (!mask.currently_running[property] &&
1853         !mask.potentially_animating[property])
1854       continue;
1855 
1856     // The mask represents which properties have had their state changed. This
1857     // can include properties for which there are no longer any animations, in
1858     // which case there will not be an entry in the map.
1859     //
1860     // It is unclear whether this is desirable; it may be that we are missing
1861     // updates to property nodes here because we no longer have the required
1862     // ElementId to look them up. See http://crbug.com/912574 for context around
1863     // why this code was rewritten.
1864     auto it = element_id_map.find(static_cast<TargetProperty::Type>(property));
1865     if (it == element_id_map.end())
1866       continue;
1867 
1868     const ElementId element_id = it->second;
1869     switch (property) {
1870       case TargetProperty::TRANSFORM:
1871         if (TransformNode* transform_node =
1872                 transform_tree.FindNodeFromElementId(element_id)) {
1873           if (mask.currently_running[property])
1874             transform_node->is_currently_animating =
1875                 state.currently_running[property];
1876           if (mask.potentially_animating[property]) {
1877             transform_node->has_potential_animation =
1878                 state.potentially_animating[property];
1879             transform_tree.set_needs_update(true);
1880             // We track transform updates specifically, whereas we
1881             // don't do so for opacity/filter, because whether a
1882             // transform is animating can change what layer(s) we
1883             // draw.
1884             updated_transform = true;
1885           }
1886         } else {
1887           DCHECK_NODE_EXISTENCE(check_node_existence, state, property,
1888                                 needs_rebuild)
1889               << "Attempting to animate non existent transform node";
1890         }
1891         break;
1892       case TargetProperty::OPACITY:
1893         if (EffectNode* effect_node =
1894                 effect_tree.FindNodeFromElementId(element_id)) {
1895           if (mask.currently_running[property])
1896             effect_node->is_currently_animating_opacity =
1897                 state.currently_running[property];
1898           if (mask.potentially_animating[property]) {
1899             effect_node->has_potential_opacity_animation =
1900                 state.potentially_animating[property];
1901             // We may need to propagate things like screen space opacity.
1902             effect_tree.set_needs_update(true);
1903           }
1904         } else {
1905           DCHECK_NODE_EXISTENCE(check_node_existence, state, property,
1906                                 needs_rebuild)
1907               << "Attempting to animate opacity on non existent effect node";
1908         }
1909         break;
1910       case TargetProperty::FILTER:
1911         if (EffectNode* effect_node =
1912                 effect_tree.FindNodeFromElementId(element_id)) {
1913           if (mask.currently_running[property])
1914             effect_node->is_currently_animating_filter =
1915                 state.currently_running[property];
1916           if (mask.potentially_animating[property])
1917             effect_node->has_potential_filter_animation =
1918                 state.potentially_animating[property];
1919           // Filter animation changes only the node, and the subtree does not
1920           // care, thus there is no need to request property tree update.
1921         } else {
1922           DCHECK_NODE_EXISTENCE(check_node_existence, state, property,
1923                                 needs_rebuild)
1924               << "Attempting to animate filter on non existent effect node";
1925         }
1926         break;
1927       case TargetProperty::BACKDROP_FILTER:
1928         if (EffectNode* effect_node =
1929                 effect_tree.FindNodeFromElementId(element_id)) {
1930           if (mask.currently_running[property])
1931             effect_node->is_currently_animating_backdrop_filter =
1932                 state.currently_running[property];
1933           if (mask.potentially_animating[property])
1934             effect_node->has_potential_backdrop_filter_animation =
1935                 state.potentially_animating[property];
1936           // Backdrop-filter animation changes only the node, and the subtree
1937           // does not care, thus there is no need to request property tree
1938           // update.
1939         } else {
1940           DCHECK_NODE_EXISTENCE(check_node_existence, state, property,
1941                                 needs_rebuild)
1942               << "Attempting to animate filter on non existent effect node";
1943         }
1944         break;
1945       default:
1946         break;
1947     }
1948   }
1949   return updated_transform;
1950 }
1951 
AnimationScalesChanged(ElementId element_id,float maximum_scale,float starting_scale)1952 void PropertyTrees::AnimationScalesChanged(ElementId element_id,
1953                                            float maximum_scale,
1954                                            float starting_scale) {
1955   if (TransformNode* transform_node =
1956           transform_tree.FindNodeFromElementId(element_id)) {
1957     transform_node->maximum_animation_scale = maximum_scale;
1958     transform_node->starting_animation_scale = starting_scale;
1959     UpdateTransformTreeUpdateNumber();
1960   }
1961 }
1962 
UpdateChangeTracking()1963 void PropertyTrees::UpdateChangeTracking() {
1964   for (int id = EffectTree::kContentsRootNodeId;
1965        id < static_cast<int>(effect_tree.size()); ++id) {
1966     EffectNode* node = effect_tree.Node(id);
1967     EffectNode* parent_node = effect_tree.parent(node);
1968     effect_tree.UpdateEffectChanged(node, parent_node);
1969   }
1970   for (int i = TransformTree::kContentsRootNodeId;
1971        i < static_cast<int>(transform_tree.size()); ++i) {
1972     TransformNode* node = transform_tree.Node(i);
1973     TransformNode* parent_node = transform_tree.parent(node);
1974     transform_tree.UpdateTransformChanged(node, parent_node);
1975   }
1976 }
1977 
PushChangeTrackingTo(PropertyTrees * tree)1978 void PropertyTrees::PushChangeTrackingTo(PropertyTrees* tree) {
1979   for (int id = EffectTree::kContentsRootNodeId;
1980        id < static_cast<int>(effect_tree.size()); ++id) {
1981     EffectNode* node = effect_tree.Node(id);
1982     if (node->effect_changed) {
1983       EffectNode* target_node = tree->effect_tree.Node(node->id);
1984       target_node->effect_changed = true;
1985     }
1986   }
1987   for (int id = TransformTree::kContentsRootNodeId;
1988        id < static_cast<int>(transform_tree.size()); ++id) {
1989     TransformNode* node = transform_tree.Node(id);
1990     if (node->transform_changed) {
1991       TransformNode* target_node = tree->transform_tree.Node(node->id);
1992       target_node->transform_changed = true;
1993     }
1994   }
1995   // Ensure that change tracking is updated even if property trees don't have
1996   // other reasons to get updated.
1997   tree->UpdateChangeTracking();
1998   tree->full_tree_damaged = full_tree_damaged;
1999 }
2000 
ResetAllChangeTracking()2001 void PropertyTrees::ResetAllChangeTracking() {
2002   transform_tree.ResetChangeTracking();
2003   effect_tree.ResetChangeTracking();
2004   changed = false;
2005   full_tree_damaged = false;
2006 }
2007 
AsTracedValue() const2008 std::unique_ptr<base::trace_event::TracedValue> PropertyTrees::AsTracedValue()
2009     const {
2010   auto value = base::WrapUnique(new base::trace_event::TracedValue);
2011   AsValueInto(value.get());
2012   return value;
2013 }
2014 
AsValueInto(base::trace_event::TracedValue * value) const2015 void PropertyTrees::AsValueInto(base::trace_event::TracedValue* value) const {
2016   value->SetInteger("sequence_number", sequence_number);
2017 
2018   value->BeginDictionary("transform_tree");
2019   transform_tree.AsValueInto(value);
2020   value->EndDictionary();
2021 
2022   value->BeginDictionary("effect_tree");
2023   effect_tree.AsValueInto(value);
2024   value->EndDictionary();
2025 
2026   value->BeginDictionary("clip_tree");
2027   clip_tree.AsValueInto(value);
2028   value->EndDictionary();
2029 
2030   value->BeginDictionary("scroll_tree");
2031   scroll_tree.AsValueInto(value);
2032   value->EndDictionary();
2033 }
2034 
ToString() const2035 std::string PropertyTrees::ToString() const {
2036   base::trace_event::TracedValueJSON value;
2037   AsValueInto(&value);
2038   return value.ToFormattedJSON();
2039 }
2040 
GetAnimationScales(int transform_node_id,LayerTreeImpl * layer_tree_impl)2041 CombinedAnimationScale PropertyTrees::GetAnimationScales(
2042     int transform_node_id,
2043     LayerTreeImpl* layer_tree_impl) {
2044   AnimationScaleData* animation_scales =
2045       &cached_data_.animation_scales[transform_node_id];
2046   if (animation_scales->update_number !=
2047       cached_data_.transform_tree_update_number) {
2048     TransformNode* node = transform_tree.Node(transform_node_id);
2049     TransformNode* parent_node = transform_tree.parent(node);
2050     bool ancestor_is_animating_scale = false;
2051     float ancestor_maximum_target_scale = kNotScaled;
2052     float ancestor_starting_animation_scale = kNotScaled;
2053     if (parent_node) {
2054       CombinedAnimationScale combined_animation_scale =
2055           GetAnimationScales(parent_node->id, layer_tree_impl);
2056       ancestor_maximum_target_scale =
2057           combined_animation_scale.maximum_animation_scale;
2058       ancestor_starting_animation_scale =
2059           combined_animation_scale.starting_animation_scale;
2060       ancestor_is_animating_scale =
2061           cached_data_.animation_scales[parent_node->id]
2062               .to_screen_has_scale_animation;
2063     }
2064 
2065     bool node_is_animating_scale =
2066         node->maximum_animation_scale != kNotScaled &&
2067         node->starting_animation_scale != kNotScaled;
2068 
2069     animation_scales->to_screen_has_scale_animation =
2070         node_is_animating_scale || ancestor_is_animating_scale;
2071 
2072     // Once we've failed to compute a maximum animated scale at an ancestor, we
2073     // continue to fail.
2074     bool failed_at_ancestor = ancestor_is_animating_scale &&
2075                               ancestor_maximum_target_scale == kNotScaled;
2076 
2077     // Computing maximum animated scale in the presence of non-scale/translation
2078     // transforms isn't supported.
2079     bool failed_for_non_scale_or_translation =
2080         !node->to_parent.IsScaleOrTranslation();
2081 
2082     // We don't attempt to accumulate animation scale from multiple nodes with
2083     // scale animations, because of the risk of significant overestimation. For
2084     // example, one node might be increasing scale from 1 to 10 at the same time
2085     // as another node is decreasing scale from 10 to 1. Naively combining these
2086     // scales would produce a scale of 100.
2087     bool failed_for_multiple_scale_animations =
2088         ancestor_is_animating_scale && node_is_animating_scale;
2089 
2090     if (failed_at_ancestor || failed_for_non_scale_or_translation ||
2091         failed_for_multiple_scale_animations) {
2092       // This ensures that descendants know we've failed to compute a maximum
2093       // animated scale.
2094       animation_scales->to_screen_has_scale_animation = true;
2095       animation_scales->combined_maximum_animation_target_scale = kNotScaled;
2096       animation_scales->combined_starting_animation_scale = kNotScaled;
2097     } else if (!animation_scales->to_screen_has_scale_animation) {
2098       animation_scales->combined_maximum_animation_target_scale = kNotScaled;
2099       animation_scales->combined_starting_animation_scale = kNotScaled;
2100     } else if (!node_is_animating_scale) {
2101       // An ancestor is animating scale.
2102       gfx::Vector2dF local_scales =
2103           MathUtil::ComputeTransform2dScaleComponents(node->local, kNotScaled);
2104       float max_local_scale = std::max(local_scales.x(), local_scales.y());
2105       animation_scales->combined_maximum_animation_target_scale =
2106           max_local_scale * ancestor_maximum_target_scale;
2107       animation_scales->combined_starting_animation_scale =
2108           max_local_scale * ancestor_starting_animation_scale;
2109     } else {
2110       gfx::Vector2dF ancestor_scales =
2111           parent_node
2112               ? MathUtil::ComputeTransform2dScaleComponents(
2113                     transform_tree.ToScreen(parent_node->id), kNotScaled)
2114               : gfx::Vector2dF(1.f, 1.f);
2115 
2116       float max_ancestor_scale =
2117           std::max(ancestor_scales.x(), ancestor_scales.y());
2118       animation_scales->combined_maximum_animation_target_scale =
2119           max_ancestor_scale * node->maximum_animation_scale;
2120       animation_scales->combined_starting_animation_scale =
2121           max_ancestor_scale * node->starting_animation_scale;
2122     }
2123     animation_scales->update_number = cached_data_.transform_tree_update_number;
2124   }
2125   return CombinedAnimationScale(
2126       animation_scales->combined_maximum_animation_target_scale,
2127       animation_scales->combined_starting_animation_scale);
2128 }
2129 
SetAnimationScalesForTesting(int transform_id,float maximum_animation_scale,float starting_animation_scale)2130 void PropertyTrees::SetAnimationScalesForTesting(
2131     int transform_id,
2132     float maximum_animation_scale,
2133     float starting_animation_scale) {
2134   cached_data_.animation_scales[transform_id]
2135       .combined_maximum_animation_target_scale = maximum_animation_scale;
2136   cached_data_.animation_scales[transform_id]
2137       .combined_starting_animation_scale = starting_animation_scale;
2138   cached_data_.animation_scales[transform_id].update_number =
2139       cached_data_.transform_tree_update_number;
2140 }
2141 
GetToTarget(int transform_id,int effect_id,gfx::Transform * to_target) const2142 bool PropertyTrees::GetToTarget(int transform_id,
2143                                 int effect_id,
2144                                 gfx::Transform* to_target) const {
2145   if (effect_id == EffectTree::kContentsRootNodeId) {
2146     *to_target = transform_tree.ToScreen(transform_id);
2147     return true;
2148   }
2149   DrawTransforms& transforms = GetDrawTransforms(transform_id, effect_id);
2150   if (transforms.to_valid) {
2151     *to_target = transforms.to_target;
2152     return true;
2153   } else if (!transforms.might_be_invertible) {
2154     return false;
2155   } else {
2156     transforms.might_be_invertible =
2157         transforms.from_target.GetInverse(to_target);
2158     transforms.to_valid = transforms.might_be_invertible;
2159     transforms.to_target = *to_target;
2160     return transforms.to_valid;
2161   }
2162 }
2163 
GetFromTarget(int transform_id,int effect_id,gfx::Transform * from_target) const2164 bool PropertyTrees::GetFromTarget(int transform_id,
2165                                   int effect_id,
2166                                   gfx::Transform* from_target) const {
2167   const TransformNode* node = transform_tree.Node(transform_id);
2168   if (node->ancestors_are_invertible &&
2169       effect_id == EffectTree::kContentsRootNodeId) {
2170     *from_target = transform_tree.FromScreen(transform_id);
2171     return true;
2172   }
2173   DrawTransforms& transforms = GetDrawTransforms(transform_id, effect_id);
2174   if (transforms.from_valid) {
2175     *from_target = transforms.from_target;
2176     return true;
2177   } else if (!transforms.might_be_invertible) {
2178     return false;
2179   } else {
2180     transforms.might_be_invertible =
2181         transforms.to_target.GetInverse(from_target);
2182     transforms.from_valid = transforms.might_be_invertible;
2183     transforms.from_target = *from_target;
2184     return transforms.from_valid;
2185   }
2186 }
2187 
FetchDrawTransformsDataFromCache(int transform_id,int dest_id) const2188 DrawTransformData& PropertyTrees::FetchDrawTransformsDataFromCache(
2189     int transform_id,
2190     int dest_id) const {
2191   for (auto& transform_data : cached_data_.draw_transforms[transform_id]) {
2192     // We initialize draw_transforms with 1 element vectors when
2193     // ResetCachedData, so if we hit an invalid target id, it means it's the
2194     // first time we compute draw transforms after reset.
2195     if (transform_data.target_id == dest_id ||
2196         transform_data.target_id == EffectTree::kInvalidNodeId) {
2197       return transform_data;
2198     }
2199   }
2200   // Add an entry to the cache.
2201   cached_data_.draw_transforms[transform_id].push_back(DrawTransformData());
2202   DrawTransformData& data = cached_data_.draw_transforms[transform_id].back();
2203   data.update_number = -1;
2204   data.target_id = dest_id;
2205   return data;
2206 }
2207 
FetchClipRectFromCache(int clip_id,int target_id)2208 ClipRectData* PropertyTrees::FetchClipRectFromCache(int clip_id,
2209                                                     int target_id) {
2210   ClipNode* clip_node = clip_tree.Node(clip_id);
2211   for (size_t i = 0; i < clip_node->cached_clip_rects->size(); ++i) {
2212     auto& data = clip_node->cached_clip_rects[i];
2213     if (data.target_id == target_id || data.target_id == -1)
2214       return &data;
2215   }
2216   clip_node->cached_clip_rects->emplace_back();
2217   return &clip_node->cached_clip_rects->back();
2218 }
2219 
HasElement(ElementId element_id) const2220 bool PropertyTrees::HasElement(ElementId element_id) const {
2221   if (!element_id)
2222     return false;
2223   return element_id_to_effect_node_index.contains(element_id) ||
2224          element_id_to_scroll_node_index.contains(element_id) ||
2225          element_id_to_transform_node_index.contains(element_id);
2226 }
2227 
GetDrawTransforms(int transform_id,int effect_id) const2228 DrawTransforms& PropertyTrees::GetDrawTransforms(int transform_id,
2229                                                  int effect_id) const {
2230   const EffectNode* effect_node = effect_tree.Node(effect_id);
2231   int dest_id = effect_node->transform_id;
2232 
2233   DrawTransformData& data =
2234       FetchDrawTransformsDataFromCache(transform_id, dest_id);
2235 
2236   DCHECK(data.update_number != cached_data_.transform_tree_update_number ||
2237          data.target_id != EffectTree::kInvalidNodeId);
2238   if (data.update_number == cached_data_.transform_tree_update_number)
2239     return data.transforms;
2240 
2241   // Cache miss.
2242   gfx::Transform target_space_transform;
2243   gfx::Transform from_target;
2244   bool already_computed_inverse = false;
2245   if (transform_id == dest_id) {
2246     target_space_transform.Scale(effect_node->surface_contents_scale.x(),
2247                                  effect_node->surface_contents_scale.y());
2248     data.transforms.to_valid = true;
2249     data.transforms.from_valid = false;
2250   } else if (transform_id > dest_id) {
2251     transform_tree.CombineTransformsBetween(transform_id, dest_id,
2252                                             &target_space_transform);
2253     target_space_transform.matrix().postScale(
2254         effect_node->surface_contents_scale.x(),
2255         effect_node->surface_contents_scale.y(), 1.f);
2256     data.transforms.to_valid = true;
2257     data.transforms.from_valid = false;
2258     data.transforms.might_be_invertible = true;
2259   } else {
2260     gfx::Transform combined_transform;
2261     transform_tree.CombineTransformsBetween(dest_id, transform_id,
2262                                             &combined_transform);
2263     if (effect_node->surface_contents_scale.x() != 0.f &&
2264         effect_node->surface_contents_scale.y() != 0.f)
2265       combined_transform.Scale(1.0f / effect_node->surface_contents_scale.x(),
2266                                1.0f / effect_node->surface_contents_scale.y());
2267     bool invertible = combined_transform.GetInverse(&target_space_transform);
2268     data.transforms.might_be_invertible = invertible;
2269     data.transforms.to_valid = invertible;
2270     data.transforms.from_valid = true;
2271     from_target = combined_transform;
2272     already_computed_inverse = true;
2273   }
2274 
2275   if (!already_computed_inverse)
2276     data.transforms.to_valid = true;
2277   data.update_number = cached_data_.transform_tree_update_number;
2278   data.target_id = dest_id;
2279   data.transforms.from_target = from_target;
2280   data.transforms.to_target = target_space_transform;
2281   return data.transforms;
2282 }
2283 
ResetCachedData()2284 void PropertyTrees::ResetCachedData() {
2285   cached_data_.transform_tree_update_number = 0;
2286   const auto transform_count = transform_tree.nodes().size();
2287   cached_data_.animation_scales.resize(transform_count);
2288   for (auto& animation_scale : cached_data_.animation_scales)
2289     animation_scale.update_number = -1;
2290 
2291   cached_data_.draw_transforms.resize(transform_count,
2292                                       std::vector<DrawTransformData>(1));
2293   for (auto& draw_transforms_for_id : cached_data_.draw_transforms) {
2294     draw_transforms_for_id.resize(1);
2295     draw_transforms_for_id[0].update_number = -1;
2296     draw_transforms_for_id[0].target_id = EffectTree::kInvalidNodeId;
2297   }
2298 }
2299 
UpdateTransformTreeUpdateNumber()2300 void PropertyTrees::UpdateTransformTreeUpdateNumber() {
2301   cached_data_.transform_tree_update_number++;
2302 }
2303 
ToScreenSpaceTransformWithoutSurfaceContentsScale(int transform_id,int effect_id) const2304 gfx::Transform PropertyTrees::ToScreenSpaceTransformWithoutSurfaceContentsScale(
2305     int transform_id,
2306     int effect_id) const {
2307   if (transform_id == TransformTree::kRootNodeId) {
2308     return gfx::Transform();
2309   }
2310   gfx::Transform screen_space_transform = transform_tree.ToScreen(transform_id);
2311   const EffectNode* effect_node = effect_tree.Node(effect_id);
2312 
2313   if (effect_node->surface_contents_scale.x() != 0.0 &&
2314       effect_node->surface_contents_scale.y() != 0.0)
2315     screen_space_transform.Scale(1.0 / effect_node->surface_contents_scale.x(),
2316                                  1.0 / effect_node->surface_contents_scale.y());
2317   return screen_space_transform;
2318 }
2319 
2320 }  // namespace cc
2321