summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordanakj@chromium.org <danakj@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-07-26 13:25:42 +0000
committerdanakj@chromium.org <danakj@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-07-26 13:25:42 +0000
commit5b54b978c3c0b001f468e4712ed284452982d7b5 (patch)
tree2b50e4969758f3096d3fb90cd35ecabbcbbbc534
parent668d08d47b0b3d4dfde18a64f3f1c0b4d3ac158a (diff)
downloadchromium_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.cc12
-rw-r--r--cc/trees/occlusion_tracker_unittest.cc117
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