summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsadrul@chromium.org <sadrul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-05 02:07:46 +0000
committersadrul@chromium.org <sadrul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-05 02:07:46 +0000
commitbcfef7a01ded80ae37e697c12e5e35f3d337ec0c (patch)
tree9b1082251d5d108b3023b5d06baaf5f0bfac3ceb
parentf9df530b76176476ba0d6f67e1b8b2cb17bc34bb (diff)
downloadchromium_src-bcfef7a01ded80ae37e697c12e5e35f3d337ec0c.zip
chromium_src-bcfef7a01ded80ae37e697c12e5e35f3d337ec0c.tar.gz
chromium_src-bcfef7a01ded80ae37e697c12e5e35f3d337ec0c.tar.bz2
cc: Fix hit-testing in zero-opacity layers.
If a layer that accepts touch or wheel events, but the layer (or one of its ancestor layers) has zero opacity, then make sure the layer hit-tests correctly. BUG=295295 R=enne@chromium.org, rbyers@google.com Review URL: https://codereview.chromium.org/26112002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@232881 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--cc/layers/draw_properties.h9
-rw-r--r--cc/test/fake_picture_layer_impl.cc13
-rw-r--r--cc/test/fake_picture_layer_impl.h5
-rw-r--r--cc/trees/layer_tree_host.cc2
-rw-r--r--cc/trees/layer_tree_host_common.cc50
-rw-r--r--cc/trees/layer_tree_host_common_unittest.cc167
-rw-r--r--cc/trees/layer_tree_host_impl.cc3
-rw-r--r--cc/trees/layer_tree_host_unittest.cc74
-rw-r--r--cc/trees/layer_tree_host_unittest_picture.cc74
-rw-r--r--cc/trees/layer_tree_impl.cc6
-rw-r--r--cc/trees/occlusion_tracker.cc2
-rw-r--r--cc/trees/occlusion_tracker_unittest.cc32
12 files changed, 404 insertions, 33 deletions
diff --git a/cc/layers/draw_properties.h b/cc/layers/draw_properties.h
index 990b4c97..fffb5a9 100644
--- a/cc/layers/draw_properties.h
+++ b/cc/layers/draw_properties.h
@@ -35,7 +35,8 @@ struct CC_EXPORT DrawProperties {
index_of_first_descendants_addition(0),
num_descendants_added(0),
index_of_first_render_surface_layer_list_addition(0),
- num_render_surfaces_added(0) {}
+ num_render_surfaces_added(0),
+ skip_drawing(false) {}
// Transforms objects from content space to target surface space, where
// this layer would be drawn.
@@ -121,6 +122,12 @@ struct CC_EXPORT DrawProperties {
size_t num_descendants_added;
size_t index_of_first_render_surface_layer_list_addition;
size_t num_render_surfaces_added;
+
+ // If the layer is part of a [sub]tree that has a touch/wheel event handler,
+ // then the layer is not skipped during CalculateDrawPropertiesInternal, even
+ // if it does not actually have anything to draw (e.g. zero opacity, or empty
+ // content). This flag is used to keep track of such layers.
+ bool skip_drawing;
};
} // namespace cc
diff --git a/cc/test/fake_picture_layer_impl.cc b/cc/test/fake_picture_layer_impl.cc
index bdf40a5..a65db0d 100644
--- a/cc/test/fake_picture_layer_impl.cc
+++ b/cc/test/fake_picture_layer_impl.cc
@@ -11,13 +11,17 @@ FakePictureLayerImpl::FakePictureLayerImpl(
int id,
scoped_refptr<PicturePileImpl> pile)
: PictureLayerImpl(tree_impl, id),
- append_quads_count_(0) {
+ append_quads_count_(0),
+ update_tile_priorities_count_(0) {
pile_ = pile;
SetBounds(pile_->size());
}
FakePictureLayerImpl::FakePictureLayerImpl(LayerTreeImpl* tree_impl, int id)
- : PictureLayerImpl(tree_impl, id), append_quads_count_(0) {}
+ : PictureLayerImpl(tree_impl, id),
+ append_quads_count_(0),
+ update_tile_priorities_count_(0) {
+}
scoped_ptr<LayerImpl> FakePictureLayerImpl::CreateLayerImpl(
LayerTreeImpl* tree_impl) {
@@ -31,6 +35,11 @@ void FakePictureLayerImpl::AppendQuads(QuadSink* quad_sink,
++append_quads_count_;
}
+void FakePictureLayerImpl::UpdateTilePriorities() {
+ PictureLayerImpl::UpdateTilePriorities();
+ ++update_tile_priorities_count_;
+}
+
gfx::Size FakePictureLayerImpl::CalculateTileSize(
gfx::Size content_bounds) const {
if (fixed_tile_size_.IsEmpty()) {
diff --git a/cc/test/fake_picture_layer_impl.h b/cc/test/fake_picture_layer_impl.h
index 759ceeb..9e49147 100644
--- a/cc/test/fake_picture_layer_impl.h
+++ b/cc/test/fake_picture_layer_impl.h
@@ -26,6 +26,7 @@ class FakePictureLayerImpl : public PictureLayerImpl {
OVERRIDE;
virtual void AppendQuads(QuadSink* quad_sink,
AppendQuadsData* append_quads_data) OVERRIDE;
+ virtual void UpdateTilePriorities() OVERRIDE;
virtual gfx::Size CalculateTileSize(gfx::Size content_bounds) const OVERRIDE;
using PictureLayerImpl::AddTiling;
@@ -49,6 +50,9 @@ class FakePictureLayerImpl : public PictureLayerImpl {
PictureLayerTilingSet* tilings() { return tilings_.get(); }
PicturePileImpl* pile() { return pile_.get(); }
size_t append_quads_count() { return append_quads_count_; }
+ size_t update_tile_priorities_count() const {
+ return update_tile_priorities_count_;
+ }
const Region& invalidation() const { return invalidation_; }
void set_invalidation(const Region& region) { invalidation_ = region; }
@@ -66,6 +70,7 @@ class FakePictureLayerImpl : public PictureLayerImpl {
gfx::Size fixed_tile_size_;
size_t append_quads_count_;
+ size_t update_tile_priorities_count_;
};
} // namespace cc
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index d93e3d5..bd6d15c 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -1057,7 +1057,7 @@ void LayerTreeHost::PaintLayerContents(
if (it.represents_target_render_surface()) {
PaintMasksForRenderSurface(
*it, queue, did_paint_content, need_more_updates);
- } else if (it.represents_itself() && it->DrawsContent()) {
+ } else if (it.represents_itself() && !it->draw_properties().skip_drawing) {
devtools_instrumentation::ScopedLayerTreeTask
update_layer(devtools_instrumentation::kUpdateLayer, it->id(), id());
DCHECK(!it->paint_properties().bounds.IsEmpty());
diff --git a/cc/trees/layer_tree_host_common.cc b/cc/trees/layer_tree_host_common.cc
index 4095900..0f31038 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 LayerHasEventHandler(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,
@@ -440,7 +446,7 @@ static bool LayerShouldBeSkipped(LayerType* layer,
// - has empty bounds
// - the layer is not double-sided, but its back face is visible.
// - is transparent
- // - does not draw content and does not participate in hit testing.
+ // - does not draw content
//
// Some additional conditions need to be computed at a later point after the
// recursion is finished.
@@ -471,11 +477,7 @@ 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)
+ if (!layer->DrawsContent())
return true;
return false;
@@ -501,7 +503,6 @@ static inline bool SubtreeShouldBeSkipped(LayerImpl* layer,
// 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();
}
@@ -522,7 +523,6 @@ 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();
}
@@ -1018,15 +1018,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;
}
@@ -1080,6 +1084,9 @@ static void PreCalculateMetaInformation(
if (layer->HasCopyRequest())
recursive_data->layer_or_descendant_has_copy_request = true;
+ if (LayerHasEventHandler(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 =
@@ -1102,6 +1109,7 @@ struct SubtreeGlobals {
const LayerType* page_scale_application_layer;
bool can_adjust_raster_scales;
bool can_render_to_separate_surface;
+ bool tree_has_event_handler;
};
template<typename LayerType>
@@ -1142,6 +1150,7 @@ struct DataForRecursion {
bool in_subtree_of_page_scale_application_layer;
bool subtree_can_use_lcd_text;
bool subtree_is_visible_from_ancestor;
+ bool subtree_should_be_skipped_for_drawing;
};
template <typename LayerType>
@@ -1408,6 +1417,8 @@ static void CalculateDrawPropertiesInternal(
data_from_ancestor.in_subtree_of_page_scale_application_layer;
data_for_children.subtree_can_use_lcd_text =
data_from_ancestor.subtree_can_use_lcd_text;
+ data_for_children.subtree_should_be_skipped_for_drawing =
+ data_from_ancestor.subtree_should_be_skipped_for_drawing;
// Layers with a copy request are always visible, as well as un-hiding their
// subtree. Otherise, layers that are marked as hidden will hide themselves
@@ -1419,10 +1430,14 @@ static void CalculateDrawPropertiesInternal(
layer_is_visible = true;
// The root layer cannot skip CalcDrawProperties.
- if (!IsRootLayer(layer) && SubtreeShouldBeSkipped(layer, layer_is_visible)) {
- if (layer->render_surface())
- layer->ClearRenderSurface();
- return;
+ if (!IsRootLayer(layer) &&
+ SubtreeShouldBeSkipped(layer, layer_is_visible)) {
+ if (!globals.tree_has_event_handler) {
+ if (layer->render_surface())
+ layer->ClearRenderSurface();
+ return;
+ }
+ data_for_children.subtree_should_be_skipped_for_drawing = true;
}
// We need to circumvent the normal recursive flow of information for clip
@@ -1847,8 +1862,11 @@ static void CalculateDrawPropertiesInternal(
// and should be included in the sorting process.
size_t sorting_start_index = descendants.size();
- if (!LayerShouldBeSkipped(layer, layer_is_visible))
+ bool skip_layer = LayerShouldBeSkipped(layer, layer_is_visible);
+ if (globals.tree_has_event_handler || !skip_layer)
descendants.push_back(layer);
+ layer_draw_properties.skip_drawing = skip_layer ||
+ data_for_children.subtree_should_be_skipped_for_drawing;
// Any layers that are appended after this point may need to be sorted if we
// visit the children out of order.
@@ -2142,9 +2160,12 @@ 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.subtree_should_be_skipped_for_drawing = false;
PreCalculateMetaInformationRecursiveData recursive_data;
PreCalculateMetaInformation(inputs->root_layer, &recursive_data);
+ globals.tree_has_event_handler =
+ recursive_data.layer_or_descendant_has_event_handler;
std::vector<AccumulatedSurfaceState<Layer> > accumulated_surface_state;
CalculateDrawPropertiesInternal<Layer>(inputs->root_layer,
globals,
@@ -2200,9 +2221,12 @@ 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.subtree_should_be_skipped_for_drawing = false;
PreCalculateMetaInformationRecursiveData recursive_data;
PreCalculateMetaInformation(inputs->root_layer, &recursive_data);
+ globals.tree_has_event_handler =
+ recursive_data.layer_or_descendant_has_event_handler;
std::vector<AccumulatedSurfaceState<LayerImpl> >
accumulated_surface_state;
CalculateDrawPropertiesInternal<LayerImpl>(inputs->root_layer,
diff --git a/cc/trees/layer_tree_host_common_unittest.cc b/cc/trees/layer_tree_host_common_unittest.cc
index 58d82ce..0f9d83e 100644
--- a/cc/trees/layer_tree_host_common_unittest.cc
+++ b/cc/trees/layer_tree_host_common_unittest.cc
@@ -5388,10 +5388,11 @@ TEST_F(LayerTreeHostCommonTest, HitTestingForEmptyLayers) {
// (but not the empty layer without a touch handler) are in the RSSL.
ASSERT_EQ(1u, render_surface_layer_list.size());
EXPECT_EQ(1, render_surface_layer_list[0]->id());
- ASSERT_EQ(3u, root->render_surface()->layer_list().size());
+ ASSERT_EQ(4u, root->render_surface()->layer_list().size());
EXPECT_EQ(1, root->render_surface()->layer_list().at(0)->id());
- EXPECT_EQ(3, root->render_surface()->layer_list().at(1)->id());
- EXPECT_EQ(4, root->render_surface()->layer_list().at(2)->id());
+ EXPECT_EQ(2, root->render_surface()->layer_list().at(1)->id());
+ EXPECT_EQ(3, root->render_surface()->layer_list().at(2)->id());
+ EXPECT_EQ(4, root->render_surface()->layer_list().at(3)->id());
// Hit testing for a point inside the empty no-handlers layer should return
// the root layer.
@@ -5399,7 +5400,7 @@ TEST_F(LayerTreeHostCommonTest, HitTestingForEmptyLayers) {
LayerImpl* result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
test_point, render_surface_layer_list);
ASSERT_TRUE(result_layer);
- EXPECT_EQ(1, result_layer->id());
+ EXPECT_EQ(2, result_layer->id());
// Hit testing for a point inside the touch handler layer should return it.
test_point = gfx::Point(15, 75);
@@ -5416,6 +5417,147 @@ TEST_F(LayerTreeHostCommonTest, HitTestingForEmptyLayers) {
EXPECT_EQ(4, result_layer->id());
}
+TEST_F(LayerTreeHostCommonTest, HitTestForZeroOpacityLayers) {
+ FakeImplProxy proxy;
+ FakeLayerTreeHostImpl host_impl(&proxy);
+ const int kRootId = 1;
+ const int kTouchHandlerId = 2;
+ const int kWheelHandlerId = 3;
+ const int kNoHandlerId = 4;
+ const int kGrandChildWithEventId = 5;
+
+ scoped_ptr<LayerImpl> root =
+ LayerImpl::Create(host_impl.active_tree(), 1);
+ gfx::Transform identity_matrix;
+ gfx::PointF anchor;
+ gfx::PointF position;
+ gfx::Size bounds(100, 100);
+ SetLayerPropertiesForTesting(root.get(),
+ identity_matrix,
+ identity_matrix,
+ anchor,
+ position,
+ bounds,
+ false);
+ root->SetDrawsContent(true);
+
+ {
+ // Child 1 - Zero opacity, without any event handler.
+ gfx::PointF position(10.f, 10.f);
+ gfx::Size bounds(30, 30);
+ scoped_ptr<LayerImpl> child =
+ LayerImpl::Create(host_impl.active_tree(), kNoHandlerId);
+ SetLayerPropertiesForTesting(child.get(),
+ identity_matrix,
+ identity_matrix,
+ anchor,
+ position,
+ bounds,
+ false);
+ child->SetOpacity(0.f);
+
+ // Grandchild - with a wheel handler.
+ scoped_ptr<LayerImpl> grand_child =
+ LayerImpl::Create(host_impl.active_tree(), kGrandChildWithEventId);
+ SetLayerPropertiesForTesting(grand_child.get(),
+ identity_matrix,
+ identity_matrix,
+ gfx::PointF(),
+ gfx::PointF(10, 10),
+ gfx::Size(10, 10),
+ false);
+ grand_child->SetHaveWheelEventHandlers(true);
+ child->AddChild(grand_child.Pass());
+ root->AddChild(child.Pass());
+ }
+
+ {
+ // Child 2 - Zero opacity, with touch event handler.
+ gfx::PointF position(70.f, 10.f);
+ gfx::Size bounds(30, 30);
+ scoped_ptr<LayerImpl> child =
+ LayerImpl::Create(host_impl.active_tree(), kTouchHandlerId);
+ SetLayerPropertiesForTesting(child.get(),
+ identity_matrix,
+ identity_matrix,
+ anchor,
+ position,
+ bounds,
+ false);
+ child->SetOpacity(0.f);
+ child->SetTouchEventHandlerRegion(gfx::Rect(10, 10, 10, 10));
+ root->AddChild(child.Pass());
+ }
+
+ {
+ // Child 3 - Zero opacity, with wheel event handler.
+ gfx::PointF position(10.f, 50.f);
+ gfx::Size bounds(30, 30);
+ scoped_ptr<LayerImpl> child =
+ LayerImpl::Create(host_impl.active_tree(), kWheelHandlerId);
+ SetLayerPropertiesForTesting(child.get(),
+ identity_matrix,
+ identity_matrix,
+ anchor,
+ position,
+ bounds,
+ false);
+ child->SetOpacity(0.f);
+ child->SetHaveWheelEventHandlers(true);
+ root->AddChild(child.Pass());
+ }
+
+ LayerImplList render_surface_layer_list;
+ LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
+ root.get(), root->bounds(), &render_surface_layer_list);
+ inputs.can_adjust_raster_scales = true;
+ LayerTreeHostCommon::CalculateDrawProperties(&inputs);
+
+ // Verify that the root layer and zero-opacity layers with touch/wheel
+ // handlers (but not the zero-opacity layer without a touch handler) are in
+ // the RSSL.
+ ASSERT_EQ(1u, render_surface_layer_list.size());
+ EXPECT_EQ(kRootId, render_surface_layer_list[0]->id());
+ ASSERT_EQ(5u, root->render_surface()->layer_list().size());
+ EXPECT_EQ(kRootId, root->render_surface()->layer_list().at(0)->id());
+ EXPECT_EQ(kNoHandlerId, root->render_surface()->layer_list().at(1)->id());
+ EXPECT_EQ(kGrandChildWithEventId,
+ root->render_surface()->layer_list().at(2)->id());
+ EXPECT_EQ(kTouchHandlerId, root->render_surface()->layer_list().at(3)->id());
+ EXPECT_EQ(kWheelHandlerId, root->render_surface()->layer_list().at(4)->id());
+
+ // Hit testing for a point inside the zero-opacity no-handler layer should
+ // return the root layer.
+ gfx::Point test_point = gfx::Point(15, 15);
+ LayerImpl* result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
+ test_point, render_surface_layer_list);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(kNoHandlerId, result_layer->id());
+
+ // Hit testing for a point inside the child of the zero-opacity no-handler
+ // layer should return the child layer, since that layer has mousewheel
+ // handler.
+ test_point = gfx::Point(25, 25);
+ result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
+ test_point, render_surface_layer_list);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(kGrandChildWithEventId, result_layer->id());
+
+ // Hit testing for a point inside the touch handler layer should return it.
+ test_point = gfx::Point(85, 25);
+ result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
+ test_point, render_surface_layer_list);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(kTouchHandlerId, result_layer->id());
+
+ // Hit testing for a point inside the mousewheel layer should return it.
+ test_point = gfx::Point(15, 55);
+ result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
+ test_point, render_surface_layer_list);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(kWheelHandlerId, result_layer->id());
+}
+
TEST_F(LayerTreeHostCommonTest,
HitCheckingTouchHandlerRegionsForEmptyLayerList) {
// Hit checking on an empty render_surface_layer_list should return a null
@@ -5741,7 +5883,7 @@ TEST_F(LayerTreeHostCommonTest,
LayerImpl* test_layer = root->children()[0];
EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100), test_layer->visible_content_rect());
ASSERT_EQ(1u, render_surface_layer_list.size());
- ASSERT_EQ(1u, root->render_surface()->layer_list().size());
+ ASSERT_EQ(2u, root->render_surface()->layer_list().size());
// Hit checking for a point outside the layer should return a null pointer
// (the root layer does not draw content, so it will not be tested either).
@@ -5851,7 +5993,7 @@ TEST_F(LayerTreeHostCommonTest,
// its layout size is 50x50, positioned at 25x25.
LayerImpl* test_layer = root->children()[0];
ASSERT_EQ(1u, render_surface_layer_list.size());
- ASSERT_EQ(1u, root->render_surface()->layer_list().size());
+ ASSERT_EQ(2u, root->render_surface()->layer_list().size());
// Check whether the child layer fits into the root after scaled.
EXPECT_RECT_EQ(gfx::Rect(test_layer->content_bounds()),
@@ -5982,8 +6124,10 @@ TEST_F(LayerTreeHostCommonTest,
// Sanity check the scenario we just created.
ASSERT_EQ(1u, render_surface_layer_list.size());
- ASSERT_EQ(1u, root->render_surface()->layer_list().size());
- ASSERT_EQ(456, root->render_surface()->layer_list().at(0)->id());
+ ASSERT_EQ(3u, root->render_surface()->layer_list().size());
+ ASSERT_EQ(1, root->render_surface()->layer_list().at(0)->id());
+ ASSERT_EQ(123, root->render_surface()->layer_list().at(1)->id());
+ ASSERT_EQ(456, root->render_surface()->layer_list().at(2)->id());
// Hit checking for a point outside the layer should return a null pointer.
// Despite the child layer being very large, it should be clipped to the root
@@ -6085,9 +6229,10 @@ TEST_F(LayerTreeHostCommonTest,
// Sanity check the scenario we just created.
ASSERT_EQ(1u, render_surface_layer_list.size());
- ASSERT_EQ(2u, root->render_surface()->layer_list().size());
- ASSERT_EQ(123, root->render_surface()->layer_list().at(0)->id());
- ASSERT_EQ(1234, root->render_surface()->layer_list().at(1)->id());
+ ASSERT_EQ(3u, root->render_surface()->layer_list().size());
+ ASSERT_EQ(1, root->render_surface()->layer_list().at(0)->id());
+ ASSERT_EQ(123, root->render_surface()->layer_list().at(1)->id());
+ ASSERT_EQ(1234, root->render_surface()->layer_list().at(2)->id());
gfx::Point test_point(35, 35);
LayerImpl* result_layer =
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 0815f35..d43ea35 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -755,7 +755,8 @@ bool LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) {
contributing_render_pass,
occlusion_tracker,
&append_quads_data);
- } else if (it.represents_itself() && it->DrawsContent() &&
+ } else if (it.represents_itself() &&
+ !it->draw_properties().skip_drawing &&
!it->visible_content_rect().IsEmpty()) {
bool impl_draw_transform_is_unknown = false;
bool occluded = occlusion_tracker.Occluded(
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index 0b2598b..59bad2e 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -5089,7 +5089,6 @@ SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestOffscreenContext_WithContext);
class LayerTreeHostTestNoQuadsForEmptyLayer : public LayerTreeHostTest {
protected:
virtual void SetupTree() OVERRIDE {
- LayerTreeHostTest::SetupTree();
root_layer_ = FakeContentLayer::Create(&client_);
root_layer_->SetBounds(gfx::Size(10, 10));
root_layer_->SetIsDrawable(false);
@@ -5123,6 +5122,79 @@ class LayerTreeHostTestNoQuadsForEmptyLayer : public LayerTreeHostTest {
SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestNoQuadsForEmptyLayer);
+class LayerTreeHostTestNoQuadsForZeroOpacityLayer : public LayerTreeHostTest {
+ protected:
+ virtual void SetupTree() OVERRIDE {
+ parent_layer_ = FakeContentLayer::Create(&parent_client_);
+ parent_layer_->SetBounds(gfx::Size(40, 40));
+ parent_layer_->SetOpacity(0.f);
+ parent_layer_->SetIsDrawable(true);
+
+ scoped_refptr<Layer> root = SolidColorLayer::Create();
+ root->SetBounds(gfx::Size(60, 60));
+ root->SetOpacity(1.f);
+ root->SetIsDrawable(true);
+ root->AddChild(parent_layer_);
+ layer_tree_host()->SetRootLayer(root);
+
+ wheel_handler_ = FakeContentLayer::Create(NULL);
+ wheel_handler_->SetBounds(gfx::Size(10, 10));
+ wheel_handler_->SetHaveWheelEventHandlers(true);
+ wheel_handler_->SetIsDrawable(true);
+ parent_layer_->AddChild(wheel_handler_);
+
+ sibling_ = FakeContentLayer::Create(NULL);
+ sibling_->SetBounds(gfx::Size(30, 30));
+ sibling_->SetPosition(gfx::Point(10, 0));
+ sibling_->SetIsDrawable(true);
+ parent_layer_->AddChild(sibling_);
+
+ LayerTreeHostTest::SetupTree();
+ }
+
+ virtual void BeginTest() OVERRIDE {
+ PostSetNeedsCommitToMainThread();
+ }
+
+ virtual void DrawLayersOnThread(LayerTreeHostImpl* impl) OVERRIDE {
+ LayerTreeHostTest::DrawLayersOnThread(impl);
+ FakeContentLayerImpl* parent =
+ static_cast<FakeContentLayerImpl*>(impl->RootLayer()->children()[0]);
+ EXPECT_TRUE(parent->DrawsContent());
+ EXPECT_FALSE(parent->opacity());
+ EXPECT_EQ(0u, parent->append_quads_count());
+ ASSERT_EQ(2u, parent->children().size());
+
+ FakeContentLayerImpl* child =
+ static_cast<FakeContentLayerImpl*>(parent->children()[0]);
+ EXPECT_TRUE(child->opacity());
+ EXPECT_EQ(0u, child->append_quads_count());
+
+ child = static_cast<FakeContentLayerImpl*>(parent->children()[1]);
+ EXPECT_TRUE(child->opacity());
+ EXPECT_EQ(0u, child->append_quads_count());
+ }
+
+ virtual void DidCommit() OVERRIDE {
+ // The layer is transparent, so it should not be updated.
+ EXPECT_EQ(0u, parent_layer_->update_count());
+ ASSERT_EQ(2u, parent_layer_->children().size());
+
+ EXPECT_EQ(0u, wheel_handler_->update_count());
+ EXPECT_EQ(0u, sibling_->update_count());
+
+ EndTest();
+ }
+ virtual void AfterTest() OVERRIDE {}
+
+ private:
+ FakeContentLayerClient parent_client_;
+ scoped_refptr<FakeContentLayer> parent_layer_;
+ scoped_refptr<FakeContentLayer> wheel_handler_;
+ scoped_refptr<FakeContentLayer> sibling_;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestNoQuadsForZeroOpacityLayer);
} // namespace
diff --git a/cc/trees/layer_tree_host_unittest_picture.cc b/cc/trees/layer_tree_host_unittest_picture.cc
index 731f6921..f290989 100644
--- a/cc/trees/layer_tree_host_unittest_picture.cc
+++ b/cc/trees/layer_tree_host_unittest_picture.cc
@@ -4,7 +4,10 @@
#include "cc/trees/layer_tree_host.h"
+#include "cc/layers/solid_color_layer.h"
+#include "cc/test/fake_content_layer.h"
#include "cc/test/fake_content_layer_client.h"
+#include "cc/test/fake_content_layer_impl.h"
#include "cc/test/fake_picture_layer.h"
#include "cc/test/fake_picture_layer_impl.h"
#include "cc/test/layer_tree_test.h"
@@ -115,5 +118,76 @@ class LayerTreeHostPictureTestTwinLayer
MULTI_THREAD_TEST_F(LayerTreeHostPictureTestTwinLayer);
+class LayerTreeHostPictureNoUpdateTileProprityForZeroOpacityLayer
+ : public LayerTreeHostPictureTest {
+ protected:
+ virtual void SetupTree() OVERRIDE {
+ parent_layer_ = FakeContentLayer::Create(&parent_client_);
+ parent_layer_->SetBounds(gfx::Size(40, 40));
+ parent_layer_->SetOpacity(0.f);
+ parent_layer_->SetIsDrawable(true);
+
+ scoped_refptr<Layer> root = SolidColorLayer::Create();
+ root->SetBounds(gfx::Size(60, 60));
+ root->SetOpacity(1.f);
+ root->SetIsDrawable(true);
+ root->AddChild(parent_layer_);
+ layer_tree_host()->SetRootLayer(root);
+
+ wheel_handler_ = FakeContentLayer::Create(NULL);
+ wheel_handler_->SetBounds(gfx::Size(10, 10));
+ wheel_handler_->SetHaveWheelEventHandlers(true);
+ wheel_handler_->SetIsDrawable(true);
+ parent_layer_->AddChild(wheel_handler_);
+
+ picture_ = FakePictureLayer::Create(&picture_client_);
+ picture_->SetBounds(gfx::Size(30, 30));
+ picture_->SetPosition(gfx::Point(10, 0));
+ picture_->SetIsDrawable(true);
+ parent_layer_->AddChild(picture_);
+
+ LayerTreeHostPictureTest::SetupTree();
+ }
+
+ virtual void BeginTest() OVERRIDE {
+ PostSetNeedsCommitToMainThread();
+ }
+
+ virtual void DrawLayersOnThread(LayerTreeHostImpl* impl) OVERRIDE {
+ LayerTreeHostPictureTest::DrawLayersOnThread(impl);
+ FakeContentLayerImpl* parent =
+ static_cast<FakeContentLayerImpl*>(impl->RootLayer()->children()[0]);
+ EXPECT_TRUE(parent->DrawsContent());
+ EXPECT_FALSE(parent->opacity());
+ EXPECT_EQ(0u, parent->append_quads_count());
+ ASSERT_EQ(2u, parent->children().size());
+
+ FakeContentLayerImpl* child =
+ static_cast<FakeContentLayerImpl*>(parent->children()[0]);
+ EXPECT_TRUE(child->opacity());
+ EXPECT_EQ(0u, child->append_quads_count());
+
+ FakePictureLayerImpl* picimpl =
+ static_cast<FakePictureLayerImpl*>(parent->children()[1]);
+ EXPECT_TRUE(picimpl->opacity());
+ EXPECT_EQ(0u, picimpl->append_quads_count());
+ EXPECT_EQ(0u, picimpl->update_tile_priorities_count());
+
+ EndTest();
+ }
+
+ virtual void AfterTest() OVERRIDE {}
+
+ private:
+ FakeContentLayerClient parent_client_;
+ FakeContentLayerClient picture_client_;
+ scoped_refptr<FakeContentLayer> parent_layer_;
+ scoped_refptr<FakeContentLayer> wheel_handler_;
+ scoped_refptr<FakePictureLayer> picture_;
+};
+
+MULTI_THREAD_TEST_F(
+ LayerTreeHostPictureNoUpdateTileProprityForZeroOpacityLayer);
+
} // namespace
} // namespace cc
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc
index 4604043..512f5c47 100644
--- a/cc/trees/layer_tree_impl.cc
+++ b/cc/trees/layer_tree_impl.cc
@@ -342,8 +342,8 @@ void LayerTreeImpl::UpdateDrawProperties() {
UpdateRootScrollLayerSizeDelta();
if (IsActiveTree() &&
- RootContainerLayer()
- && !RootContainerLayer()->masks_to_bounds()) {
+ RootContainerLayer() &&
+ !RootContainerLayer()->masks_to_bounds()) {
UpdateSolidColorScrollbars();
}
@@ -405,6 +405,8 @@ void LayerTreeImpl::UpdateDrawProperties() {
if (!it.represents_itself())
continue;
LayerImpl* layer = *it;
+ if (layer->draw_properties().skip_drawing)
+ continue;
layer->UpdateTilePriorities();
if (layer->mask_layer())
diff --git a/cc/trees/occlusion_tracker.cc b/cc/trees/occlusion_tracker.cc
index 8f98c27..5a27d7b 100644
--- a/cc/trees/occlusion_tracker.cc
+++ b/cc/trees/occlusion_tracker.cc
@@ -408,7 +408,7 @@ void OcclusionTrackerBase<LayerType, RenderSurfaceType>::
if (stack_.empty())
return;
- if (!layer->DrawsContent())
+ if (layer->draw_properties().skip_drawing)
return;
if (!LayerOpacityKnown(layer) || layer->draw_opacity() < 1)
diff --git a/cc/trees/occlusion_tracker_unittest.cc b/cc/trees/occlusion_tracker_unittest.cc
index 0e8b5d4..90f7fb4 100644
--- a/cc/trees/occlusion_tracker_unittest.cc
+++ b/cc/trees/occlusion_tracker_unittest.cc
@@ -4006,5 +4006,37 @@ class OcclusionTrackerTestEmptyEventLayerDoesNotOcclude
ALL_OCCLUSIONTRACKER_TEST(OcclusionTrackerTestEmptyEventLayerDoesNotOcclude)
+template <class Types>
+class OcclusionTrackerTestZeroOpacityLayerDoesNotOcclude
+ : public OcclusionTrackerTest<Types> {
+ protected:
+ explicit OcclusionTrackerTestZeroOpacityLayerDoesNotOcclude(bool opaque)
+ : OcclusionTrackerTest<Types>(opaque) {}
+ void RunMyTest() {
+ typename Types::ContentLayerType* root = this->CreateRoot(
+ this->identity_matrix, gfx::Point(), gfx::Size(400, 400));
+ typename Types::ContentLayerType* zero_opacity_layer =
+ this->CreateDrawingLayer(root, this->identity_matrix, gfx::Point(),
+ gfx::Size(200, 200), true);
+ this->SetDrawsContent(zero_opacity_layer, false);
+ zero_opacity_layer->SetTouchEventHandlerRegion(gfx::Rect(10, 10, 10, 10));
+
+ this->CalcDrawEtc(root);
+
+ TestOcclusionTrackerWithClip<typename Types::LayerType,
+ typename Types::RenderSurfaceType> occlusion(
+ gfx::Rect(0, 0, 1000, 1000), false);
+
+ this->VisitLayer(zero_opacity_layer, &occlusion);
+
+ EXPECT_EQ(gfx::Rect().ToString(),
+ occlusion.occlusion_from_outside_target().ToString());
+ EXPECT_EQ(gfx::Rect().ToString(),
+ occlusion.occlusion_from_inside_target().ToString());
+ }
+};
+
+ALL_OCCLUSIONTRACKER_TEST(OcclusionTrackerTestZeroOpacityLayerDoesNotOcclude);
+
} // namespace
} // namespace cc