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 a9828a715908959d43b45f56b3db11f329d21524..9feae1721f493bf00b0b60c0dc05a9146a58c5a5 100644 |
--- a/cc/trees/layer_tree_host_common.cc |
+++ b/cc/trees/layer_tree_host_common.cc |
@@ -63,6 +63,12 @@ static gfx::Vector2dF GetEffectiveTotalScrollOffset(LayerType* layer) { |
return offset; |
} |
+template <typename LayerType> |
+static inline bool LayerCanAcceptInput(LayerType* layer) { |
+ return !layer->touch_event_handler_region().IsEmpty() || |
+ layer->have_wheel_event_handlers(); |
+} |
+ |
inline gfx::Rect CalculateVisibleRectWithCachedLayerRect( |
gfx::Rect target_surface_rect, |
gfx::Rect layer_bound_rect, |
@@ -430,10 +436,21 @@ static inline bool TransformToScreenIsKnown(Layer* layer) { |
return !layer->screen_space_transform_is_animating(); |
} |
+static inline bool LayerDrawOpacityIsZero(Layer* layer) { |
+ return !layer->draw_opacity() && !layer->draw_opacity_is_animating(); |
+} |
+ |
+static inline bool LayerDrawOpacityIsZero(LayerImpl* layer) { |
+ return !layer->draw_opacity(); |
+} |
+ |
template <typename LayerType> |
static bool LayerShouldBeSkipped(LayerType* layer, |
- bool layer_is_visible) { |
+ bool layer_is_visible, |
+ bool layer_has_zero_opacity) { |
// Layers can be skipped if any of these conditions are met. |
+ // - an ancestor node has zero opacity, and there are no event handlers in |
+ // the subtree rooted at |layer|. |
// - is not visible due to it or one of its ancestors being hidden. |
// - has empty bounds |
// - the layer is not double-sided, but its back face is visible. |
@@ -446,8 +463,14 @@ static bool LayerShouldBeSkipped(LayerType* layer, |
// - 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. |
+ // transparent, then we do not skip the entire subtree only if there is an |
+ // event handler in the subtree. So if the layer is fully transparent, then |
+ // skip the layer if its subtree doesn't have any event handler. |
+ |
+ if (layer_has_zero_opacity && |
+ !layer->draw_properties().layer_or_descendant_has_event_handler) { |
+ return true; |
+ } |
if (!layer_is_visible) |
return true; |
@@ -469,18 +492,27 @@ static bool LayerShouldBeSkipped(LayerType* layer, |
IsLayerBackFaceVisible(backface_test_layer)) |
return true; |
- // The layer is visible to events. If it's subject to hit testing, then |
- // we can't skip it. |
- bool can_accept_input = !layer->touch_event_handler_region().IsEmpty() || |
- layer->have_wheel_event_handlers(); |
- if (!layer->DrawsContent() && !can_accept_input) |
+ // A layer cannot be skipped if it is subject to hit-testing. |
+ if (LayerCanAcceptInput(layer)) |
+ return false; |
+ |
+ if (!layer->DrawsContent()) |
+ return true; |
+ |
+ if (LayerDrawOpacityIsZero(layer)) |
return true; |
return false; |
} |
static inline bool SubtreeShouldBeSkipped(LayerImpl* layer, |
- bool layer_is_visible) { |
+ bool layer_is_visible, |
+ bool *layer_has_zero_opacity) { |
+ if (*layer_has_zero_opacity && |
+ !layer->draw_properties().layer_or_descendant_has_event_handler) { |
+ 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) |
@@ -496,15 +528,30 @@ static inline bool SubtreeShouldBeSkipped(LayerImpl* layer, |
if (layer->layer_tree_impl()->IsPendingTree() && layer->OpacityIsAnimating()) |
return false; |
+ bool skip_if_no_event_handler = !layer->opacity(); |
+ |
+ // If the layer (or any of its descendant) is subject to hit-testing, then the |
+ // subtree cannot be skipped. |
+ if (layer->draw_properties().layer_or_descendant_has_event_handler) { |
+ if (skip_if_no_event_handler) |
+ *layer_has_zero_opacity = true; |
+ 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. |
- // TODO(sad): Don't skip layers used for hit testing crbug.com/295295. |
- return !layer->opacity(); |
+ return skip_if_no_event_handler; |
} |
static inline bool SubtreeShouldBeSkipped(Layer* layer, |
- bool layer_is_visible) { |
+ bool layer_is_visible, |
+ bool* layer_has_zero_opacity) { |
+ if (*layer_has_zero_opacity && |
+ !layer->draw_properties().layer_or_descendant_has_event_handler) { |
+ 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) |
@@ -520,9 +567,19 @@ static inline bool SubtreeShouldBeSkipped(Layer* layer, |
// 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. |
- // TODO(sad): Don't skip layers used for hit testing crbug.com/295295. |
- return !layer->opacity() && !layer->OpacityIsAnimating() && |
- !layer->OpacityCanAnimateOnImplThread(); |
+ bool skip_if_no_event_handler = |
+ !layer->opacity() && !layer->OpacityIsAnimating() && |
+ !layer->OpacityCanAnimateOnImplThread(); |
+ |
+ // If the layer (or any of its descendant) is subject to hit-testing, then the |
+ // subtree cannot be skipped. |
+ if (layer->draw_properties().layer_or_descendant_has_event_handler) { |
+ if (skip_if_no_event_handler) |
+ *layer_has_zero_opacity = true; |
+ return false; |
+ } |
+ |
+ return skip_if_no_event_handler; |
} |
// Called on each layer that could be drawn after all information from |
@@ -1031,15 +1088,19 @@ static inline void RemoveSurfaceForEarlyExit( |
struct PreCalculateMetaInformationRecursiveData { |
bool layer_or_descendant_has_copy_request; |
+ bool layer_or_descendant_has_event_handler; |
int num_unclipped_descendants; |
PreCalculateMetaInformationRecursiveData() |
: layer_or_descendant_has_copy_request(false), |
+ layer_or_descendant_has_event_handler(false), |
num_unclipped_descendants(0) {} |
void Merge(const PreCalculateMetaInformationRecursiveData& data) { |
layer_or_descendant_has_copy_request |= |
data.layer_or_descendant_has_copy_request; |
+ layer_or_descendant_has_event_handler |= |
+ data.layer_or_descendant_has_event_handler; |
num_unclipped_descendants += |
data.num_unclipped_descendants; |
} |
@@ -1090,12 +1151,17 @@ static void PreCalculateMetaInformation( |
if (layer->HasCopyRequest()) |
recursive_data->layer_or_descendant_has_copy_request = true; |
+ if (LayerCanAcceptInput(layer)) |
+ recursive_data->layer_or_descendant_has_event_handler = true; |
+ |
layer->draw_properties().num_descendants_that_draw_content = |
num_descendants_that_draw_content; |
layer->draw_properties().num_unclipped_descendants = |
recursive_data->num_unclipped_descendants; |
layer->draw_properties().layer_or_descendant_has_copy_request = |
recursive_data->layer_or_descendant_has_copy_request; |
+ layer->draw_properties().layer_or_descendant_has_event_handler = |
+ recursive_data->layer_or_descendant_has_event_handler; |
} |
static void RoundTranslationComponents(gfx::Transform* transform) { |
@@ -1151,6 +1217,8 @@ struct DataForRecursion { |
bool in_subtree_of_page_scale_application_layer; |
bool subtree_can_use_lcd_text; |
bool subtree_is_visible_from_ancestor; |
+ |
+ bool layer_has_zero_opacity; |
}; |
template <typename LayerType> |
@@ -1420,12 +1488,17 @@ static void CalculateDrawPropertiesInternal( |
if (layer->HasCopyRequest()) |
layer_is_visible = true; |
+ bool layer_has_zero_opacity = |
+ data_from_ancestor.layer_has_zero_opacity; |
// The root layer cannot skip CalcDrawProperties. |
- if (!IsRootLayer(layer) && SubtreeShouldBeSkipped(layer, layer_is_visible)) { |
+ if (!IsRootLayer(layer) && |
+ SubtreeShouldBeSkipped(layer, layer_is_visible, |
+ &layer_has_zero_opacity)) { |
if (layer->render_surface()) |
layer->ClearRenderSurface(); |
return; |
} |
+ data_for_children.layer_has_zero_opacity = layer_has_zero_opacity; |
// We need to circumvent the normal recursive flow of information for clip |
// children (they don't inherit their direct ancestor's clip information). |
@@ -1843,7 +1916,8 @@ static void CalculateDrawPropertiesInternal( |
// and should be included in the sorting process. |
size_t sorting_start_index = descendants.size(); |
- if (!LayerShouldBeSkipped(layer, layer_is_visible)) |
+ if (!LayerShouldBeSkipped(layer, layer_is_visible, |
+ data_from_ancestor.layer_has_zero_opacity)) |
descendants.push_back(layer); |
if (!layer->children().empty()) { |
@@ -2147,6 +2221,7 @@ void LayerTreeHostCommon::CalculateDrawProperties( |
data_for_recursion.in_subtree_of_page_scale_application_layer = false; |
data_for_recursion.subtree_can_use_lcd_text = inputs->can_use_lcd_text; |
data_for_recursion.subtree_is_visible_from_ancestor = true; |
+ data_for_recursion.layer_has_zero_opacity = false; |
PreCalculateMetaInformationRecursiveData recursive_data; |
PreCalculateMetaInformation(inputs->root_layer, &recursive_data); |
@@ -2206,6 +2281,7 @@ void LayerTreeHostCommon::CalculateDrawProperties( |
data_for_recursion.in_subtree_of_page_scale_application_layer = false; |
data_for_recursion.subtree_can_use_lcd_text = inputs->can_use_lcd_text; |
data_for_recursion.subtree_is_visible_from_ancestor = true; |
+ data_for_recursion.layer_has_zero_opacity = false; |
PreCalculateMetaInformationRecursiveData recursive_data; |
PreCalculateMetaInformation(inputs->root_layer, &recursive_data); |