Index: cc/trees/draw_property_utils.cc |
diff --git a/cc/trees/draw_property_utils.cc b/cc/trees/draw_property_utils.cc |
index 83b91f4f36edef54da6d4633d5e5638f163dc0da..50b91cb37b1bd432cefb3cf3a4c3bbf2a1156c42 100644 |
--- a/cc/trees/draw_property_utils.cc |
+++ b/cc/trees/draw_property_utils.cc |
@@ -9,6 +9,7 @@ |
#include "cc/base/math_util.h" |
#include "cc/layers/layer.h" |
#include "cc/layers/layer_impl.h" |
+#include "cc/trees/layer_tree_impl.h" |
#include "cc/trees/property_tree.h" |
#include "cc/trees/property_tree_builder.h" |
#include "ui/gfx/geometry/rect_conversions.h" |
@@ -157,72 +158,154 @@ static bool TransformToScreenIsKnown(LayerType* layer, |
} |
template <typename LayerType> |
-static bool IsLayerBackFaceExposed(LayerType* layer, |
- const TransformTree& tree) { |
- if (!TransformToScreenIsKnown(layer, tree)) |
- return false; |
- if (LayerIsInExisting3DRenderingContext(layer)) |
- return DrawTransformFromPropertyTrees(layer, tree).IsBackFaceVisible(); |
- return layer->transform().IsBackFaceVisible(); |
+static bool HasSingularTransform(LayerType* layer, const TransformTree& tree) { |
+ const TransformNode* node = tree.Node(layer->transform_tree_index()); |
+ return !node->data.is_invertible || !node->data.ancestors_are_invertible; |
} |
template <typename LayerType> |
-static bool IsSurfaceBackFaceExposed(LayerType* layer, |
- const TransformTree& tree) { |
- if (!TransformToScreenIsKnown(layer, tree)) |
- return false; |
+static bool IsLayerBackFaceVisible(LayerType* layer, |
+ const TransformTree& tree) { |
+ // The current W3C spec on CSS transforms says that backface visibility should |
+ // be determined differently depending on whether the layer is in a "3d |
+ // rendering context" or not. For Chromium code, we can determine whether we |
+ // are in a 3d rendering context by checking if the parent preserves 3d. |
+ |
if (LayerIsInExisting3DRenderingContext(layer)) |
return DrawTransformFromPropertyTrees(layer, tree).IsBackFaceVisible(); |
- if (IsRootLayerOfNewRenderingContext(layer)) |
- return layer->transform().IsBackFaceVisible(); |
- |
- // If the render_surface is not part of a new or existing rendering context, |
- // then the layers that contribute to this surface will decide back-face |
- // visibility for themselves. |
- return false; |
+ // In this case, either the layer establishes a new 3d rendering context, or |
+ // is not in a 3d rendering context at all. |
+ return layer->transform().IsBackFaceVisible(); |
} |
template <typename LayerType> |
-static bool HasSingularTransform(LayerType* layer, const TransformTree& tree) { |
+static bool IsAnimatingTransformToScreen(LayerType* layer, |
+ const TransformTree& tree) { |
const TransformNode* node = tree.Node(layer->transform_tree_index()); |
- return !node->data.is_invertible || !node->data.ancestors_are_invertible; |
+ return node->data.to_screen_is_animated; |
} |
-template <typename LayerType> |
-static bool IsBackFaceInvisible(LayerType* layer, const TransformTree& tree) { |
- LayerType* backface_test_layer = layer; |
- if (layer->use_parent_backface_visibility()) { |
- DCHECK(layer->parent()); |
- DCHECK(!layer->parent()->use_parent_backface_visibility()); |
- backface_test_layer = layer->parent(); |
- } |
- return !backface_test_layer->double_sided() && |
- IsLayerBackFaceExposed(backface_test_layer, tree); |
+static inline bool TransformToScreenIsKnown(Layer* layer, |
+ const TransformTree& tree) { |
+ return !IsAnimatingTransformToScreen(layer, tree); |
} |
-template <typename LayerType> |
-static bool IsAnimatingTransformToScreen(LayerType* layer, |
- const TransformTree& tree) { |
- const TransformNode* node = tree.Node(layer->transform_tree_index()); |
- return node->data.to_screen_is_animated; |
+static inline bool TransformToScreenIsKnown(LayerImpl* layer, |
+ const TransformTree& tree) { |
+ return true; |
} |
template <typename LayerType> |
-static bool IsInvisibleDueToTransform(LayerType* layer, |
- const TransformTree& tree) { |
- if (IsAnimatingTransformToScreen(layer, tree)) |
+static bool HasInvertibleOrAnimatedTransform(LayerType* layer) { |
+ return layer->transform_is_invertible() || layer->TransformIsAnimating(); |
+} |
+ |
+static inline bool SubtreeShouldBeSkipped(LayerImpl* layer, |
+ bool layer_is_drawn) { |
+ // If the layer transform is not invertible, it should not be drawn. |
+ // TODO(ajuma): Correctly process subtrees with singular transform for the |
+ // case where we may animate to a non-singular transform and wish to |
+ // pre-raster. |
+ if (!HasInvertibleOrAnimatedTransform(layer)) |
+ return true; |
+ |
+ // When we need to do a readback/copy of a layer's output, we can not skip |
+ // it or any of its ancestors. |
+ if (layer->draw_properties().layer_or_descendant_has_copy_request) |
+ return false; |
+ |
+ // We cannot skip the the subtree if a descendant has a wheel or touch handler |
+ // or the hit testing code will break (it requires fresh transforms, etc). |
+ if (layer->draw_properties().layer_or_descendant_has_input_handler) |
return false; |
- return HasSingularTransform(layer, tree) || IsBackFaceInvisible(layer, tree); |
+ |
+ // If the layer is not drawn, then skip it and its subtree. |
+ if (!layer_is_drawn) |
+ return true; |
+ |
+ // If layer is on the pending tree and opacity is being animated then |
+ // this subtree can't be skipped as we need to create, prioritize and |
+ // include tiles for this layer when deciding if tree can be activated. |
+ if (layer->layer_tree_impl()->IsPendingTree() && layer->OpacityIsAnimating()) |
+ return false; |
+ |
+ // The opacity of a layer always applies to its children (either implicitly |
+ // via a render surface or explicitly if the parent preserves 3D), so the |
+ // entire subtree can be skipped if this layer is fully transparent. |
+ return !layer->opacity(); |
} |
-bool LayerIsInvisible(const Layer* layer) { |
+static inline bool SubtreeShouldBeSkipped(Layer* layer, bool layer_is_drawn) { |
+ // If the layer transform is not invertible, it should not be drawn. |
+ if (!layer->transform_is_invertible() && !layer->TransformIsAnimating()) |
+ return true; |
+ |
+ // When we need to do a readback/copy of a layer's output, we can not skip |
+ // it or any of its ancestors. |
+ if (layer->draw_properties().layer_or_descendant_has_copy_request) |
+ return false; |
+ |
+ // We cannot skip the the subtree if a descendant has a wheel or touch handler |
+ // or the hit testing code will break (it requires fresh transforms, etc). |
+ if (layer->draw_properties().layer_or_descendant_has_input_handler) |
+ return false; |
+ |
+ // If the layer is not drawn, then skip it and its subtree. |
+ if (!layer_is_drawn) |
+ return true; |
+ |
+ // If the opacity is being animated then the opacity on the main thread is |
+ // unreliable (since the impl thread may be using a different opacity), so it |
+ // should not be trusted. |
+ // In particular, it should not cause the subtree to be skipped. |
+ // Similarly, for layers that might animate opacity using an impl-only |
+ // animation, their subtree should also not be skipped. |
return !layer->opacity() && !layer->OpacityIsAnimating() && |
!layer->OpacityCanAnimateOnImplThread(); |
} |
-bool LayerIsInvisible(const LayerImpl* layer) { |
- return !layer->opacity() && !layer->OpacityIsAnimating(); |
+template <typename LayerType> |
+static bool LayerShouldBeSkipped(LayerType* layer, |
+ bool layer_is_drawn, |
+ const TransformTree& tree) { |
+ // Layers can be skipped if any of these conditions are met. |
+ // - is not drawn due to it or one of its ancestors being hidden (or having |
+ // no copy requests). |
+ // - does not draw content. |
+ // - is transparent. |
+ // - has empty bounds |
+ // - the layer is not double-sided, but its back face is visible. |
+ // |
+ // Some additional conditions need to be computed at a later point after the |
+ // recursion is finished. |
+ // - the intersection of render_surface content and layer clip_rect is empty |
+ // - the visible_content_rect is empty |
+ // |
+ // Note, if the layer should not have been drawn due to being fully |
+ // transparent, we would have skipped the entire subtree and never made it |
+ // into this function, so it is safe to omit this check here. |
+ if (!layer_is_drawn) |
+ return true; |
+ |
+ if (!layer->DrawsContent() || layer->bounds().IsEmpty()) |
+ return true; |
+ |
+ LayerType* backface_test_layer = layer; |
+ if (layer->use_parent_backface_visibility()) { |
+ DCHECK(layer->parent()); |
+ DCHECK(!layer->parent()->use_parent_backface_visibility()); |
+ backface_test_layer = layer->parent(); |
+ } |
+ |
+ // The layer should not be drawn if (1) it is not double-sided and (2) the |
+ // back of the layer is known to be facing the screen. |
+ if (!backface_test_layer->double_sided() && |
+ TransformToScreenIsKnown(backface_test_layer, tree) && |
+ IsLayerBackFaceVisible(backface_test_layer, tree)) |
+ return true; |
+ |
+ return false; |
} |
template <typename LayerType> |
@@ -230,24 +313,15 @@ void FindLayersThatNeedVisibleRects(LayerType* layer, |
const TransformTree& tree, |
bool subtree_is_visible_from_ancestor, |
std::vector<LayerType*>* layers_to_update) { |
- const bool layer_is_invisible = LayerIsInvisible(layer); |
- const bool layer_is_backfacing = |
- (layer->has_render_surface() && !layer->double_sided() && |
- IsSurfaceBackFaceExposed(layer, tree)); |
- |
- const bool subtree_is_invisble = layer_is_invisible || layer_is_backfacing; |
- if (subtree_is_invisble) |
- return; |
- |
bool layer_is_drawn = |
layer->HasCopyRequest() || |
(subtree_is_visible_from_ancestor && !layer->hide_layer_and_subtree()); |
- if (layer_is_drawn && layer->DrawsContent()) { |
- const bool visible = !IsInvisibleDueToTransform(layer, tree); |
- if (visible) |
- layers_to_update->push_back(layer); |
- } |
+ if (layer->parent() && SubtreeShouldBeSkipped(layer, layer_is_drawn)) |
+ return; |
+ |
+ if (!LayerShouldBeSkipped(layer, layer_is_drawn, tree)) |
+ layers_to_update->push_back(layer); |
for (size_t i = 0; i < layer->children().size(); ++i) { |
FindLayersThatNeedVisibleRects(layer->child_at(i), tree, layer_is_drawn, |