diff options
author | danakj@chromium.org <danakj@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-07-26 13:25:42 +0000 |
---|---|---|
committer | danakj@chromium.org <danakj@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-07-26 13:25:42 +0000 |
commit | 5b54b978c3c0b001f468e4712ed284452982d7b5 (patch) | |
tree | 2b50e4969758f3096d3fb90cd35ecabbcbbbc534 | |
parent | 668d08d47b0b3d4dfde18a64f3f1c0b4d3ac158a (diff) | |
download | chromium_src-5b54b978c3c0b001f468e4712ed284452982d7b5.zip chromium_src-5b54b978c3c0b001f468e4712ed284452982d7b5.tar.gz chromium_src-5b54b978c3c0b001f468e4712ed284452982d7b5.tar.bz2 |
cc: Hidden layers should not occlude non-hidden layers.
When we have a hidden subtree, and we do a CopyRequest inside it,
then we have to draw that subtree, but we should not occlude anything
outside of the subtree since it is hidden on the screen.
Tests:
OcclusionTrackerTestCopyRequestDoesOcclude
OcclusionTrackerTestHiddenCopyRequestDoesNotOcclude
R=enne, piman
BUG=263673
Review URL: https://chromiumcodereview.appspot.com/20121002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@213884 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | cc/trees/occlusion_tracker.cc | 12 | ||||
-rw-r--r-- | cc/trees/occlusion_tracker_unittest.cc | 117 |
2 files changed, 129 insertions, 0 deletions
diff --git a/cc/trees/occlusion_tracker.cc b/cc/trees/occlusion_tracker.cc index 08553a8..9fc26da 100644 --- a/cc/trees/occlusion_tracker.cc +++ b/cc/trees/occlusion_tracker.cc @@ -143,6 +143,12 @@ static inline bool LayerIsInUnsorted3dRenderingContext(const LayerImpl* layer) { return false; } +template <typename LayerType> +static inline bool LayerIsHidden(const LayerType* layer) { + return layer->hide_layer_and_subtree() || + (layer->parent() && LayerIsHidden(layer->parent())); +} + template <typename LayerType, typename RenderSurfaceType> void OcclusionTrackerBase<LayerType, RenderSurfaceType>::EnterRenderTarget( const LayerType* new_target) { @@ -220,6 +226,11 @@ void OcclusionTrackerBase<LayerType, RenderSurfaceType>::FinishedRenderTarget( RenderSurfaceType* surface = finished_target->render_surface(); + // Readbacks always happen on render targets so we only need to check + // for readbacks here. + bool target_is_only_for_copy_request = + finished_target->HasCopyRequest() && LayerIsHidden(finished_target); + // If the occlusion within the surface can not be applied to things outside of // the surface's subtree, then clear the occlusion here so it won't be used. // TODO(senorblanco): Make this smarter for SkImageFilter case: once @@ -227,6 +238,7 @@ void OcclusionTrackerBase<LayerType, RenderSurfaceType>::FinishedRenderTarget( if (finished_target->mask_layer() || !SurfaceOpacityKnown(surface) || surface->draw_opacity() < 1 || + target_is_only_for_copy_request || finished_target->filters().HasFilterThatAffectsOpacity() || finished_target->filter()) { stack_.back().occlusion_from_outside_target.Clear(); diff --git a/cc/trees/occlusion_tracker_unittest.cc b/cc/trees/occlusion_tracker_unittest.cc index db019c5..e91184a 100644 --- a/cc/trees/occlusion_tracker_unittest.cc +++ b/cc/trees/occlusion_tracker_unittest.cc @@ -9,6 +9,8 @@ #include "cc/debug/overdraw_metrics.h" #include "cc/layers/layer.h" #include "cc/layers/layer_impl.h" +#include "cc/output/copy_output_request.h" +#include "cc/output/copy_output_result.h" #include "cc/output/filter_operation.h" #include "cc/output/filter_operations.h" #include "cc/test/animation_test_common.h" @@ -307,6 +309,25 @@ template <typename Types> class OcclusionTrackerTest : public testing::Test { return layer; } + + void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) {} + + void AddCopyRequest(Layer* layer) { + layer->RequestCopyOfOutput( + CopyOutputRequest::CreateBitmapRequest(base::Bind( + &OcclusionTrackerTest<Types>::CopyOutputCallback, + base::Unretained(this)))); + } + + void AddCopyRequest(LayerImpl* layer) { + ScopedPtrVector<CopyOutputRequest> requests; + requests.push_back( + CopyOutputRequest::CreateBitmapRequest(base::Bind( + &OcclusionTrackerTest<Types>::CopyOutputCallback, + base::Unretained(this)))); + layer->PassCopyRequests(&requests); + } + void CalcDrawEtc(TestContentLayerImpl* root) { DCHECK(root == root_.get()); DCHECK(!root->render_surface()); @@ -4803,5 +4824,101 @@ class OcclusionTrackerTestScaledLayerInSurfaceIsClipped ALL_OCCLUSIONTRACKER_TEST(OcclusionTrackerTestScaledLayerInSurfaceIsClipped) +template <class Types> +class OcclusionTrackerTestCopyRequestDoesOcclude + : public OcclusionTrackerTest<Types> { + protected: + explicit OcclusionTrackerTestCopyRequestDoesOcclude(bool opaque_layers) + : OcclusionTrackerTest<Types>(opaque_layers) {} + void RunMyTest() { + typename Types::ContentLayerType* root = this->CreateRoot( + this->identity_matrix, gfx::Point(), gfx::Size(400, 400)); + typename Types::ContentLayerType* parent = this->CreateDrawingLayer( + root, this->identity_matrix, gfx::Point(), gfx::Size(400, 400), true); + typename Types::LayerType* copy = this->CreateLayer(parent, + this->identity_matrix, + gfx::Point(100, 0), + gfx::Size(200, 400)); + this->AddCopyRequest(copy); + typename Types::LayerType* copy_child = this->CreateDrawingLayer( + copy, + this->identity_matrix, + gfx::PointF(), + gfx::Size(200, 400), + true); + this->CalcDrawEtc(root); + + TestOcclusionTrackerWithClip<typename Types::LayerType, + typename Types::RenderSurfaceType> occlusion( + gfx::Rect(0, 0, 1000, 1000)); + + this->VisitLayer(copy_child, &occlusion); + EXPECT_EQ(gfx::Rect().ToString(), + occlusion.occlusion_from_outside_target().ToString()); + EXPECT_EQ(gfx::Rect(200, 400).ToString(), + occlusion.occlusion_from_inside_target().ToString()); + + // CopyRequests cause the layer to own a surface. + this->VisitContributingSurface(copy, &occlusion); + + // The occlusion from the copy should be kept. + EXPECT_EQ(gfx::Rect().ToString(), + occlusion.occlusion_from_outside_target().ToString()); + EXPECT_EQ(gfx::Rect(100, 0, 200, 400).ToString(), + occlusion.occlusion_from_inside_target().ToString()); + } +}; + +ALL_OCCLUSIONTRACKER_TEST(OcclusionTrackerTestCopyRequestDoesOcclude) + +template <class Types> +class OcclusionTrackerTestHiddenCopyRequestDoesNotOcclude + : public OcclusionTrackerTest<Types> { + protected: + explicit OcclusionTrackerTestHiddenCopyRequestDoesNotOcclude( + bool opaque_layers) + : OcclusionTrackerTest<Types>(opaque_layers) {} + void RunMyTest() { + typename Types::ContentLayerType* root = this->CreateRoot( + this->identity_matrix, gfx::Point(), gfx::Size(400, 400)); + typename Types::ContentLayerType* parent = this->CreateDrawingLayer( + root, this->identity_matrix, gfx::Point(), gfx::Size(400, 400), true); + typename Types::LayerType* hide = this->CreateLayer( + parent, this->identity_matrix, gfx::Point(), gfx::Size()); + typename Types::LayerType* copy = this->CreateLayer( + hide, this->identity_matrix, gfx::Point(100, 0), gfx::Size(200, 400)); + this->AddCopyRequest(copy); + typename Types::LayerType* copy_child = this->CreateDrawingLayer( + copy, this->identity_matrix, gfx::PointF(), gfx::Size(200, 400), true); + + // The |copy| layer is hidden but since it is being copied, it will be + // drawn. + hide->SetHideLayerAndSubtree(true); + + this->CalcDrawEtc(root); + + TestOcclusionTrackerWithClip<typename Types::LayerType, + typename Types::RenderSurfaceType> occlusion( + gfx::Rect(0, 0, 1000, 1000)); + + this->VisitLayer(copy_child, &occlusion); + EXPECT_EQ(gfx::Rect().ToString(), + occlusion.occlusion_from_outside_target().ToString()); + EXPECT_EQ(gfx::Rect(200, 400).ToString(), + occlusion.occlusion_from_inside_target().ToString()); + + // CopyRequests cause the layer to own a surface. + this->VisitContributingSurface(copy, &occlusion); + + // The occlusion from the copy should be dropped since it is hidden. + 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(OcclusionTrackerTestHiddenCopyRequestDoesNotOcclude) + } // namespace } // namespace cc |