diff options
author | sadrul@chromium.org <sadrul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-11-05 02:07:46 +0000 |
---|---|---|
committer | sadrul@chromium.org <sadrul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-11-05 02:07:46 +0000 |
commit | bcfef7a01ded80ae37e697c12e5e35f3d337ec0c (patch) | |
tree | 9b1082251d5d108b3023b5d06baaf5f0bfac3ceb /cc | |
parent | f9df530b76176476ba0d6f67e1b8b2cb17bc34bb (diff) | |
download | chromium_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
Diffstat (limited to 'cc')
-rw-r--r-- | cc/layers/draw_properties.h | 9 | ||||
-rw-r--r-- | cc/test/fake_picture_layer_impl.cc | 13 | ||||
-rw-r--r-- | cc/test/fake_picture_layer_impl.h | 5 | ||||
-rw-r--r-- | cc/trees/layer_tree_host.cc | 2 | ||||
-rw-r--r-- | cc/trees/layer_tree_host_common.cc | 50 | ||||
-rw-r--r-- | cc/trees/layer_tree_host_common_unittest.cc | 167 | ||||
-rw-r--r-- | cc/trees/layer_tree_host_impl.cc | 3 | ||||
-rw-r--r-- | cc/trees/layer_tree_host_unittest.cc | 74 | ||||
-rw-r--r-- | cc/trees/layer_tree_host_unittest_picture.cc | 74 | ||||
-rw-r--r-- | cc/trees/layer_tree_impl.cc | 6 | ||||
-rw-r--r-- | cc/trees/occlusion_tracker.cc | 2 | ||||
-rw-r--r-- | cc/trees/occlusion_tracker_unittest.cc | 32 |
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 |