Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1065)

Unified Diff: cc/trees/layer_tree_host_common.cc

Issue 548963002: Generalize scroll parent work in CalculateDrawProperties Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: . Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « cc/trees/layer_tree_host_common.h ('k') | cc/trees/layer_tree_host_common_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: cc/trees/layer_tree_host_common.cc
diff --git a/cc/trees/layer_tree_host_common.cc b/cc/trees/layer_tree_host_common.cc
index 4e80fc603f68d70407780aad0d883a0d92ef543b..87a0837b59c9d571560a8d9092a68d453c9e7a8a 100644
--- a/cc/trees/layer_tree_host_common.cc
+++ b/cc/trees/layer_tree_host_common.cc
@@ -125,26 +125,28 @@ static LayerType* NextTargetSurface(LayerType* layer) {
// ancestor and descendant. These transforms must be 2D translations, and this
// requirement is enforced at every step.
template <typename LayerType>
-static gfx::Vector2dF ComputeChangeOfBasisTranslation(
- const LayerType& ancestor_layer,
- const LayerType& descendant_layer) {
+static bool ComputeChangeOfBasisTranslation(const LayerType& ancestor_layer,
+ const LayerType& descendant_layer,
+ gfx::Vector2dF* translation) {
DCHECK(descendant_layer.HasAncestor(&ancestor_layer));
+ if (!descendant_layer.HasAncestor(&ancestor_layer))
+ return false;
const LayerType* descendant_target = descendant_layer.render_target();
DCHECK(descendant_target);
const LayerType* ancestor_target = ancestor_layer.render_target();
DCHECK(ancestor_target);
- gfx::Vector2dF translation;
for (const LayerType* target = descendant_target; target != ancestor_target;
target = NextTargetSurface(target)) {
const gfx::Transform& trans = target->render_surface()->draw_transform();
// Ensure that this translation is truly 2d.
- DCHECK(trans.IsIdentityOrTranslation());
+ if (!trans.IsIdentityOrTranslation())
+ return false;
DCHECK_EQ(0.f, trans.matrix().get(2, 3));
- translation += trans.To2dTranslation();
+ *translation += trans.To2dTranslation();
}
- return translation;
+ return true;
}
enum TranslateRectDirection {
@@ -153,16 +155,100 @@ enum TranslateRectDirection {
};
template <typename LayerType>
-static gfx::Rect TranslateRectToTargetSpace(const LayerType& ancestor_layer,
- const LayerType& descendant_layer,
- const gfx::Rect& rect,
- TranslateRectDirection direction) {
- gfx::Vector2dF translation = ComputeChangeOfBasisTranslation<LayerType>(
- ancestor_layer, descendant_layer);
+static bool TranslateRectToTargetSpace(const LayerType& ancestor_layer,
+ const LayerType& descendant_layer,
+ const gfx::Rect& rect,
+ TranslateRectDirection direction,
+ gfx::Rect* translated) {
+ gfx::Vector2dF translation;
+ if (!ComputeChangeOfBasisTranslation<LayerType>(
+ ancestor_layer, descendant_layer, &translation)) {
+ return false;
+ }
if (direction == TranslateRectDirectionToDescendant)
translation.Scale(-1.f);
- return gfx::ToEnclosingRect(
+ *translated = gfx::ToEnclosingRect(
gfx::RectF(rect.origin() + translation, rect.size()));
+ return true;
+}
+
+template <typename LayerType>
+static inline bool HaveVisited(LayerType* layer, int sequence_number) {
+ return layer->draw_properties().sequence_number == sequence_number;
+}
+
+template <typename LayerType>
+static inline bool HaveAssignedSortWeight(LayerType* layer,
+ int sequence_number) {
+ return layer->draw_properties().sort_weight_sequence_number ==
+ sequence_number;
+}
+
+template <typename LayerType>
+static inline LayerType* HighestScrollParentAncestorNotOnChildAncestorChain(
+ int sequence_number,
+ LayerType* scroll_child,
+ LayerType* scroll_parent) {
+ // Say we have the following tree.
+ //
+ // a
+ // +-b
+ // | +-c
+ // | +-scroll_child
+ // +-d
+ // +-e
+ // +-scroll_parent
+ //
+ // This function aims to find find the highest ancestor of |scroll_parent|
+ // that's not on |scroll_child|'s ancestor chain. d, in this case.
+ //
+ // Fortunately, we have some hints that make finding the lowest common
+ // ancestor a bit easier than usual. We know if we've visited a layer, and for
+ // those layers that we've visited, we know their depth in the tree.
+ if (!HaveVisited(scroll_parent, sequence_number)) {
+ DCHECK(scroll_parent->parent());
+ // This case is easy. Since we walk the tree in DFS order, if we haven't
+ // visited the scroll parent, we just have to walk up to the first visited
+ // layer, which will be the LCA.
+ while (!HaveVisited(scroll_parent->parent(), sequence_number))
+ scroll_parent = scroll_parent->parent();
+ // This would mean that |scroll_parent| is a descendant of |scroll_child|,
+ // which is an error.
+ DCHECK_NE(scroll_child, scroll_parent->parent());
+ } else {
+ // In this case, we've visited both the scroll_parent and scroll_child, so
+ // it's not as easy as walking to the first visited ancestor of the scroll
+ // parent. But since we've visited the layers, we know their depths, and we
+ // can efficiently find the LCA by walking up nodes at the same height.
+
+ // First, walk up from the deeper layer until we reach two layers at the
+ // same depth in the tree.
+ while (scroll_child->draw_properties().depth !=
+ scroll_parent->draw_properties().depth) {
+ int child_is_deeper = scroll_child->draw_properties().depth >
+ scroll_parent->draw_properties().depth;
+ if (child_is_deeper)
+ scroll_child = scroll_child->parent();
+ else
+ scroll_parent = scroll_parent->parent();
+ }
+
+ // This would only happen if |scroll_child| and |scroll_parent| were on the
+ // same ancestor chain, which is an error. We only ever set up scroll parent
+ // scroll child relationships if scroll child is not a descendant of the
+ // scroll parent and will therefore not scroll with it naturally and needs
+ // special treatment by the compositor.
+ DCHECK_NE(scroll_child, scroll_parent);
+
+ // Now that scroll_child and scroll_parent are at the same depth, we can
+ // walk up in tandem to find the LCA.
+ while (scroll_child->parent() != scroll_parent->parent()) {
+ scroll_child = scroll_child->parent();
+ scroll_parent = scroll_parent->parent();
+ }
+ }
+
+ return scroll_parent;
}
// Attempts to update the clip rects for the given layer. If the layer has a
@@ -196,22 +282,38 @@ static void UpdateClipRectsForClipChild(
// wanted to. But more importantly, this matches the expectations of
// CalculateDrawPropertiesInternal. If we, say, create a render surface, these
// clip rects will want to be in its target space, not ours.
- if (clip_parent == layer->clip_parent()) {
- *clip_rect_in_parent_target_space = TranslateRectToTargetSpace<LayerType>(
- *clip_parent,
- *layer->parent(),
- *clip_rect_in_parent_target_space,
- TranslateRectDirectionToDescendant);
+ // if (layer->HasAncestor(clip_parent)) {
+ if (layer->HasAncestor(clip_parent)) {
+ TranslateRectToTargetSpace<LayerType>(*clip_parent,
+ *layer->parent(),
+ *clip_rect_in_parent_target_space,
+ TranslateRectDirectionToDescendant,
+ clip_rect_in_parent_target_space);
} else {
// If we're being clipped by our scroll parent, we must translate through
- // our common ancestor. This happens to be our parent, so it is sufficent to
- // translate from our clip parent's space to the space of its ancestor (our
- // parent).
- *clip_rect_in_parent_target_space =
- TranslateRectToTargetSpace<LayerType>(*layer->parent(),
+ // our common ancestor.
+ const LayerType* lca =
+ HighestScrollParentAncestorNotOnChildAncestorChain(
+ layer->draw_properties().sequence_number, layer, clip_parent)
+ ->parent();
+
+ bool did_translate_rect =
+ TranslateRectToTargetSpace<LayerType>(*lca,
*clip_parent,
*clip_rect_in_parent_target_space,
- TranslateRectDirectionToAncestor);
+ TranslateRectDirectionToAncestor,
+ clip_rect_in_parent_target_space);
+
+ // The lowest common ancestor is usually, but not always, our parent. We
+ // must check if we need to transform from the lca's space to our parent's.
+ // TODO(vollick): crbug.com/424684.
+ if (did_translate_rect && lca != layer->parent()) {
+ TranslateRectToTargetSpace<LayerType>(*lca,
+ *layer->parent(),
+ *clip_rect_in_parent_target_space,
+ TranslateRectDirectionToDescendant,
+ clip_rect_in_parent_target_space);
+ }
}
}
@@ -271,12 +373,42 @@ void UpdateAccumulatedSurfaceState(
gfx::Rect clip_rect = render_target->clip_rect();
// If the layer has a clip parent, the clip rect may be in the wrong space,
// so we'll need to transform it before it is applied.
- if (layer->clip_parent()) {
- clip_rect = TranslateRectToTargetSpace<LayerType>(
- *layer->clip_parent(),
- *layer,
- clip_rect,
- TranslateRectDirectionToDescendant);
+ if (LayerType* clip_parent = layer->clip_parent()) {
+ if (layer->HasAncestor(clip_parent)) {
+ TranslateRectToTargetSpace<LayerType>(
+ *clip_parent,
+ *layer,
+ clip_rect,
+ TranslateRectDirectionToDescendant,
+ &clip_rect);
+ } else {
+ // If we're being clipped by our scroll parent, we must translate
+ // through
+ // our common ancestor.
+ const LayerType* lca =
+ HighestScrollParentAncestorNotOnChildAncestorChain(
+ layer->draw_properties().sequence_number, layer, clip_parent)
+ ->parent();
+
+ TranslateRectToTargetSpace<LayerType>(*lca,
+ *clip_parent,
+ clip_rect,
+ TranslateRectDirectionToAncestor,
+ &clip_rect);
+
+ // The lowest common ancestor is usually, but not always, our
+ // parent. We
+ // must check if we need to transform from the lca's space to our
+ // parent's.
+ if (lca != layer->parent()) {
+ TranslateRectToTargetSpace<LayerType>(
+ *lca,
+ *layer->parent(),
+ clip_rect,
+ TranslateRectDirectionToDescendant,
+ &clip_rect);
+ }
+ }
}
target_rect.Intersect(clip_rect);
}
@@ -1155,7 +1287,6 @@ static inline void MarkLayerListWithRenderSurfaceLayerListId(
current_render_surface_layer_list_id);
}
}
-
template <typename LayerType>
static inline void RemoveSurfaceForEarlyExit(
LayerType* layer_to_remove,
@@ -1203,15 +1334,93 @@ struct PreCalculateMetaInformationRecursiveData {
}
};
+static int next_sort_weight(int* last_sort_weight) {
+ return ++(*last_sort_weight);
+}
+
+template <typename LayerType>
+static inline void AssignSortWeights(LayerType* layer,
+ int sequence_number,
+ int* last_sort_weight) {
+ // Give |layer| the highest sort weight in the tree so far.
+ if (!HaveAssignedSortWeight(layer, sequence_number)) {
+ layer->draw_properties().sort_weight = next_sort_weight(last_sort_weight);
+ layer->draw_properties().sort_weight_sequence_number = sequence_number;
+ }
+
+ if (LayerType* scroll_parent = layer->scroll_parent()) {
+ // It's important to note where we need to take care of ordering so that
+ // scroll parents are visited before scroll children; it's at their lowest
+ // common ancestor.
+ //
+ // LCA
+ // +-scroll_parent_ancestor
+ // | +- ...
+ // | + scroll_parent
+ // |
+ // +-scroll_child_ancestor
+ // +- ..
+ // + scroll_child
+ //
+ // So given the above tree, we need to guarentee that scroll_parent_ancestor
+ // is processed before scroll_child. We ensure that by assigning it the
+ // lowest sort weight in the tree. We also want to flag LCA if we need to do
+ // any funny business with sort weights so that it knows to do special
+ // sorting of its descendants.
+ LayerType* scroll_parent_ancestor =
+ HighestScrollParentAncestorNotOnChildAncestorChain(
+ sequence_number, layer, scroll_parent);
+
+ // We know we need to reorder if we haven't yet assigned
+ // |scroll_parent_ancestor| a sort weight. Sort weights are monotonically
+ // increasing, so unless we intervene, it will be given a higher sort weight
+ // than |layer|.
+ bool need_to_reorder =
+ !HaveAssignedSortWeight(scroll_parent_ancestor, sequence_number);
+
+ LayerType* lca = scroll_parent_ancestor->parent();
+
+ // We also might need to reorder if scroll_parent_ancestor has been visited
+ // and has an unacceptable sort weight.
+ if (!need_to_reorder) {
+ LayerType* scroll_child_ancestor = layer;
+ while (scroll_child_ancestor->parent() &&
+ scroll_child_ancestor->parent() != lca) {
+ scroll_child_ancestor = scroll_child_ancestor->parent();
+ }
+ // We must have assigned a sort weight to this layer since its on our
+ // ancestor chain.
+ DCHECK(HaveAssignedSortWeight(scroll_child_ancestor, sequence_number));
+ if (scroll_child_ancestor->draw_properties().sort_weight <
+ scroll_parent_ancestor->draw_properties().sort_weight)
+ need_to_reorder = true;
+ }
+
+ if (need_to_reorder) {
+ // Give |scroll_parent_ancestor| the lowest weight in the tree so far.
+ scroll_parent_ancestor->draw_properties().sort_weight =
+ -next_sort_weight(last_sort_weight);
+ scroll_parent_ancestor->draw_properties().sort_weight_sequence_number =
+ sequence_number;
+
+ // Mark the LCA as needing to sort.
+ lca->draw_properties().children_need_sorting = true;
+ }
+ }
+}
+
// Recursively walks the layer tree to compute any information that is needed
// before doing the main recursion.
template <typename LayerType>
static void PreCalculateMetaInformation(
LayerType* layer,
- PreCalculateMetaInformationRecursiveData* recursive_data) {
-
- layer->draw_properties().sorted_for_recursion = false;
- layer->draw_properties().has_child_with_a_scroll_parent = false;
+ PreCalculateMetaInformationRecursiveData* recursive_data,
+ int depth,
+ int sequence_number,
+ int* last_sort_weight) {
+ layer->draw_properties().children_need_sorting = false;
+ layer->draw_properties().depth = depth;
+ layer->draw_properties().sequence_number = sequence_number;
if (!HasInvertibleOrAnimatedTransform(layer)) {
// Layers with singular transforms should not be drawn, the whole subtree
@@ -1222,22 +1431,25 @@ static void PreCalculateMetaInformation(
if (layer->clip_parent())
recursive_data->num_unclipped_descendants++;
+ AssignSortWeights(layer, sequence_number, last_sort_weight);
+
for (size_t i = 0; i < layer->children().size(); ++i) {
LayerType* child_layer =
LayerTreeHostCommon::get_layer_as_raw_ptr(layer->children(), i);
-
PreCalculateMetaInformationRecursiveData data_for_child;
- PreCalculateMetaInformation(child_layer, &data_for_child);
-
- if (child_layer->scroll_parent())
- layer->draw_properties().has_child_with_a_scroll_parent = true;
+ PreCalculateMetaInformation(child_layer,
+ &data_for_child,
+ depth + 1,
+ sequence_number,
+ last_sort_weight);
recursive_data->Merge(data_for_child);
}
if (layer->clip_children()) {
int num_clip_children = layer->clip_children()->size();
- DCHECK_GE(recursive_data->num_unclipped_descendants, num_clip_children);
recursive_data->num_unclipped_descendants -= num_clip_children;
+ if (recursive_data->num_unclipped_descendants < 0)
+ recursive_data->num_unclipped_descendants = 0;
}
if (layer->HasCopyRequest())
@@ -1317,77 +1529,23 @@ struct DataForRecursion {
};
template <typename LayerType>
-static LayerType* GetChildContainingLayer(const LayerType& parent,
- LayerType* layer) {
- for (LayerType* ancestor = layer; ancestor; ancestor = ancestor->parent()) {
- if (ancestor->parent() == &parent)
- return ancestor;
+struct AscendingScrollWeightComparator {
+ bool operator()(LayerType* lhs, LayerType* rhs) {
+ return lhs->draw_properties().sort_weight <
+ rhs->draw_properties().sort_weight;
}
- NOTREACHED();
- return 0;
-}
-
-template <typename LayerType>
-static void AddScrollParentChain(std::vector<LayerType*>* out,
- const LayerType& parent,
- LayerType* layer) {
- // At a high level, this function walks up the chain of scroll parents
- // recursively, and once we reach the end of the chain, we add the child
- // of |parent| containing each scroll ancestor as we unwind. The result is
- // an ordering of parent's children that ensures that scroll parents are
- // visited before their descendants.
- // Take for example this layer tree:
- //
- // + stacking_context
- // + scroll_child (1)
- // + scroll_parent_graphics_layer (*)
- // | + scroll_parent_scrolling_layer
- // | + scroll_parent_scrolling_content_layer (2)
- // + scroll_grandparent_graphics_layer (**)
- // + scroll_grandparent_scrolling_layer
- // + scroll_grandparent_scrolling_content_layer (3)
- //
- // The scroll child is (1), its scroll parent is (2) and its scroll
- // grandparent is (3). Note, this doesn't mean that (2)'s scroll parent is
- // (3), it means that (*)'s scroll parent is (3). We don't want our list to
- // look like [ (3), (2), (1) ], even though that does have the ancestor chain
- // in the right order. Instead, we want [ (**), (*), (1) ]. That is, only want
- // (1)'s siblings in the list, but we want them to appear in such an order
- // that the scroll ancestors get visited in the correct order.
- //
- // So our first task at this step of the recursion is to determine the layer
- // that we will potentionally add to the list. That is, the child of parent
- // containing |layer|.
- LayerType* child = GetChildContainingLayer(parent, layer);
- if (child->draw_properties().sorted_for_recursion)
- return;
-
- if (LayerType* scroll_parent = child->scroll_parent())
- AddScrollParentChain(out, parent, scroll_parent);
-
- out->push_back(child);
- child->draw_properties().sorted_for_recursion = true;
-}
+};
template <typename LayerType>
-static bool SortChildrenForRecursion(std::vector<LayerType*>* out,
+static void SortChildrenForRecursion(std::vector<LayerType*>* out,
const LayerType& parent) {
- out->reserve(parent.children().size());
- bool order_changed = false;
- for (size_t i = 0; i < parent.children().size(); ++i) {
- LayerType* current =
- LayerTreeHostCommon::get_layer_as_raw_ptr(parent.children(), i);
-
- if (current->draw_properties().sorted_for_recursion) {
- order_changed = true;
- continue;
- }
+ out->resize(parent.children().size());
+ for (size_t i = 0; i < parent.children().size(); ++i)
+ (*out)[i] = LayerTreeHostCommon::get_layer_as_raw_ptr(parent.children(), i);
- AddScrollParentChain(out, parent, current);
- }
-
- DCHECK_EQ(parent.children().size(), out->size());
- return order_changed;
+ // Ensures the children are sorted in ascending sort weight.
+ std::sort(
+ out->begin(), out->end(), AscendingScrollWeightComparator<LayerType>());
}
template <typename LayerType>
@@ -2117,9 +2275,8 @@ static void CalculateDrawPropertiesInternal(
}
std::vector<LayerType*> sorted_children;
- bool child_order_changed = false;
- if (layer_draw_properties.has_child_with_a_scroll_parent)
- child_order_changed = SortChildrenForRecursion(&sorted_children, *layer);
+ if (layer_draw_properties.children_need_sorting)
+ SortChildrenForRecursion(&sorted_children, *layer);
for (size_t i = 0; i < layer->children().size(); ++i) {
// If one of layer's children has a scroll parent, then we may have to
@@ -2127,7 +2284,7 @@ static void CalculateDrawPropertiesInternal(
// sorted_children. Otherwise, we'll grab the child directly from the
// layer's list of children.
LayerType* child =
- layer_draw_properties.has_child_with_a_scroll_parent
+ layer_draw_properties.children_need_sorting
? sorted_children[i]
: LayerTreeHostCommon::get_layer_as_raw_ptr(layer->children(), i);
@@ -2165,7 +2322,7 @@ static void CalculateDrawPropertiesInternal(
}
// Add the unsorted layer list contributions, if necessary.
- if (child_order_changed) {
+ if (layer_draw_properties.children_need_sorting) {
SortLayerListContributions(
*layer,
GetLayerListForSorting(render_surface_layer_list),
@@ -2396,8 +2553,15 @@ void LayerTreeHostCommon::CalculateDrawProperties(
DataForRecursion<Layer> data_for_recursion;
ProcessCalcDrawPropsInputs(*inputs, &globals, &data_for_recursion);
+ // This is used as a global throughout the precalculate recursion.
+ int last_sort_weight = 0;
PreCalculateMetaInformationRecursiveData recursive_data;
- PreCalculateMetaInformation(inputs->root_layer, &recursive_data);
+ PreCalculateMetaInformation(inputs->root_layer,
+ &recursive_data,
+ 0,
+ inputs->current_render_surface_layer_list_id,
+ &last_sort_weight);
+
std::vector<AccumulatedSurfaceState<Layer>> accumulated_surface_state;
CalculateDrawPropertiesInternal<Layer>(
inputs->root_layer,
@@ -2425,8 +2589,15 @@ void LayerTreeHostCommon::CalculateDrawProperties(
LayerSorter layer_sorter;
globals.layer_sorter = &layer_sorter;
+ // This is used as a global throughout the precalculate recursion.
+ int last_sort_weight = 0;
PreCalculateMetaInformationRecursiveData recursive_data;
- PreCalculateMetaInformation(inputs->root_layer, &recursive_data);
+ PreCalculateMetaInformation(inputs->root_layer,
+ &recursive_data,
+ 0,
+ inputs->current_render_surface_layer_list_id,
+ &last_sort_weight);
+
std::vector<AccumulatedSurfaceState<LayerImpl>> accumulated_surface_state;
CalculateDrawPropertiesInternal<LayerImpl>(
inputs->root_layer,
« no previous file with comments | « cc/trees/layer_tree_host_common.h ('k') | cc/trees/layer_tree_host_common_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698