// Copyright 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "cc/test/layer_test_common.h" #include "cc/base/math_util.h" #include "cc/base/region.h" #include "cc/layers/append_quads_data.h" #include "cc/quads/draw_quad.h" #include "cc/quads/render_pass.h" #include "cc/test/fake_output_surface.h" #include "cc/test/mock_occlusion_tracker.h" #include "cc/trees/layer_tree_host_common.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/gfx/point_conversions.h" #include "ui/gfx/rect.h" #include "ui/gfx/rect_conversions.h" #include "ui/gfx/size_conversions.h" namespace cc { // Align with expected and actual output. const char* LayerTestCommon::quad_string = " Quad: "; static bool CanRectFBeSafelyRoundedToRect(const gfx::RectF& r) { // Ensure that range of float values is not beyond integer range. if (!r.IsExpressibleAsRect()) return false; // Ensure that the values are actually integers. if (gfx::ToFlooredPoint(r.origin()) == r.origin() && gfx::ToFlooredSize(r.size()) == r.size()) return true; return false; } void LayerTestCommon::VerifyQuadsExactlyCoverRect(const QuadList& quads, const gfx::Rect& rect) { Region remaining = rect; for (size_t i = 0; i < quads.size(); ++i) { DrawQuad* quad = quads[i]; gfx::RectF quad_rectf = MathUtil::MapClippedRect(quad->quadTransform(), gfx::RectF(quad->rect)); // Before testing for exact coverage in the integer world, assert that // rounding will not round the rect incorrectly. ASSERT_TRUE(CanRectFBeSafelyRoundedToRect(quad_rectf)); gfx::Rect quad_rect = gfx::ToEnclosingRect(quad_rectf); EXPECT_TRUE(rect.Contains(quad_rect)) << quad_string << i << " rect: " << rect.ToString() << " quad: " << quad_rect.ToString(); EXPECT_TRUE(remaining.Contains(quad_rect)) << quad_string << i << " remaining: " << remaining.ToString() << " quad: " << quad_rect.ToString(); remaining.Subtract(quad_rect); } EXPECT_TRUE(remaining.IsEmpty()); } // static void LayerTestCommon::VerifyQuadsCoverRectWithOcclusion( const QuadList& quads, const gfx::Rect& rect, const gfx::Rect& occluded, size_t* partially_occluded_count) { // No quad should exist if it's fully occluded. for (size_t i = 0; i < quads.size(); ++i) { EXPECT_FALSE(occluded.Contains(quads[i]->visible_rect)); } // Quads that are fully occluded on one axis only should be shrunken. for (size_t i = 0; i < quads.size(); ++i) { DrawQuad* quad = quads[i]; DCHECK(quad->quadTransform().IsIdentityOrIntegerTranslation()); gfx::Rect target_rect = MathUtil::MapEnclosingClippedRect(quad->quadTransform(), quad->rect); gfx::Rect target_visible_rect = MathUtil::MapEnclosingClippedRect( quad->quadTransform(), quad->visible_rect); bool fully_occluded_horizontal = target_rect.x() >= occluded.x() && target_rect.right() <= occluded.right(); bool fully_occluded_vertical = target_rect.y() >= occluded.y() && target_rect.bottom() <= occluded.bottom(); bool should_be_occluded = target_rect.Intersects(occluded) && (fully_occluded_vertical || fully_occluded_horizontal); if (!should_be_occluded) { EXPECT_EQ(quad->rect.ToString(), quad->visible_rect.ToString()); } else { EXPECT_NE(quad->rect.ToString(), quad->visible_rect.ToString()); EXPECT_TRUE(quad->rect.Contains(quad->visible_rect)); ++(*partially_occluded_count); } } } LayerTestCommon::LayerImplTest::LayerImplTest() : host_(FakeLayerTreeHost::Create()), root_layer_impl_(LayerImpl::Create(host_->host_impl()->active_tree(), 1)), render_pass_(RenderPass::Create()) { scoped_ptr output_surface = FakeOutputSurface::Create3d(); host_->host_impl()->InitializeRenderer( output_surface.PassAs()); } LayerTestCommon::LayerImplTest::~LayerImplTest() {} void LayerTestCommon::LayerImplTest::CalcDrawProps( const gfx::Size& viewport_size) { LayerImplList layer_list; LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs( root_layer_impl_.get(), viewport_size, &layer_list); LayerTreeHostCommon::CalculateDrawProperties(&inputs); } void LayerTestCommon::LayerImplTest::AppendQuadsWithOcclusion( LayerImpl* layer_impl, const gfx::Rect& occluded) { AppendQuadsData data; render_pass_->quad_list.clear(); render_pass_->shared_quad_state_list.clear(); occlusion_tracker_.set_occluded_target_rect(occluded); layer_impl->WillDraw(DRAW_MODE_HARDWARE, resource_provider()); layer_impl->AppendQuads(render_pass_.get(), occlusion_tracker_, &data); layer_impl->DidDraw(resource_provider()); } void LayerTestCommon::LayerImplTest::AppendQuadsForPassWithOcclusion( LayerImpl* layer_impl, const RenderPassId& id, const gfx::Rect& occluded) { AppendQuadsData data(id); render_pass_->quad_list.clear(); render_pass_->shared_quad_state_list.clear(); occlusion_tracker_.set_occluded_target_rect(occluded); layer_impl->WillDraw(DRAW_MODE_HARDWARE, resource_provider()); layer_impl->AppendQuads(render_pass_.get(), occlusion_tracker_, &data); layer_impl->DidDraw(resource_provider()); } void LayerTestCommon::LayerImplTest::AppendSurfaceQuadsWithOcclusion( RenderSurfaceImpl* surface_impl, const gfx::Rect& occluded) { AppendQuadsData data; render_pass_->quad_list.clear(); render_pass_->shared_quad_state_list.clear(); occlusion_tracker_.set_occluded_target_rect_for_contributing_surface( occluded); bool for_replica = false; RenderPassId id(1, 1); surface_impl->AppendQuads( render_pass_.get(), occlusion_tracker_, &data, for_replica, id); } } // namespace cc