| // 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 <stddef.h> |
| |
| #include "cc/animation/animation.h" |
| #include "cc/animation/animation_host.h" |
| #include "cc/animation/animation_id_provider.h" |
| #include "cc/base/math_util.h" |
| #include "cc/base/region.h" |
| #include "cc/layers/append_quads_data.h" |
| #include "cc/test/animation_test_common.h" |
| #include "cc/test/fake_layer_tree_frame_sink.h" |
| #include "cc/test/mock_occlusion_tracker.h" |
| #include "cc/trees/layer_tree_host_common.h" |
| #include "components/viz/common/frame_sinks/copy_output_request.h" |
| #include "components/viz/common/frame_sinks/copy_output_result.h" |
| #include "components/viz/common/quads/draw_quad.h" |
| #include "components/viz/common/quads/render_pass.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "ui/gfx/geometry/point_conversions.h" |
| #include "ui/gfx/geometry/rect.h" |
| #include "ui/gfx/geometry/rect_conversions.h" |
| #include "ui/gfx/geometry/size_conversions.h" |
| |
| namespace cc { |
| |
| // Align with expected and actual output. |
| const char* LayerTestCommon::quad_string = " Quad: "; |
| |
| RenderSurfaceImpl* GetRenderSurface(LayerImpl* layer_impl) { |
| EffectTree& effect_tree = |
| layer_impl->layer_tree_impl()->property_trees()->effect_tree; |
| |
| if (RenderSurfaceImpl* surface = |
| effect_tree.GetRenderSurface(layer_impl->effect_tree_index())) |
| return surface; |
| |
| return effect_tree.GetRenderSurface( |
| effect_tree.Node(layer_impl->effect_tree_index())->target_id); |
| } |
| |
| 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. |
| gfx::RectF floored_rect(std::floor(r.x()), std::floor(r.y()), |
| std::floor(r.width()), std::floor(r.height())); |
| return floored_rect == r; |
| } |
| |
| void LayerTestCommon::VerifyQuadsExactlyCoverRect(const viz::QuadList& quads, |
| const gfx::Rect& rect) { |
| Region remaining = rect; |
| |
| for (auto iter = quads.cbegin(); iter != quads.cend(); ++iter) { |
| EXPECT_TRUE(iter->rect.Contains(iter->visible_rect)); |
| |
| gfx::RectF quad_rectf = MathUtil::MapClippedRect( |
| iter->shared_quad_state->quad_to_target_transform, |
| gfx::RectF(iter->visible_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 << iter.index() |
| << " rect: " << rect.ToString() |
| << " quad: " << quad_rect.ToString(); |
| EXPECT_TRUE(remaining.Contains(quad_rect)) |
| << quad_string << iter.index() << " remaining: " << remaining.ToString() |
| << " quad: " << quad_rect.ToString(); |
| remaining.Subtract(quad_rect); |
| } |
| |
| EXPECT_TRUE(remaining.IsEmpty()); |
| } |
| |
| // static |
| void LayerTestCommon::VerifyQuadsAreOccluded(const viz::QuadList& quads, |
| const gfx::Rect& occluded, |
| size_t* partially_occluded_count) { |
| // No quad should exist if it's fully occluded. |
| for (auto* quad : quads) { |
| gfx::Rect target_visible_rect = MathUtil::MapEnclosingClippedRect( |
| quad->shared_quad_state->quad_to_target_transform, quad->visible_rect); |
| EXPECT_FALSE(occluded.Contains(target_visible_rect)); |
| } |
| |
| // Quads that are fully occluded on one axis only should be shrunken. |
| for (auto* quad : quads) { |
| gfx::Rect target_rect = MathUtil::MapEnclosingClippedRect( |
| quad->shared_quad_state->quad_to_target_transform, quad->rect); |
| if (!quad->shared_quad_state->quad_to_target_transform |
| .IsIdentityOrIntegerTranslation()) { |
| DCHECK(quad->shared_quad_state->quad_to_target_transform |
| .IsPositiveScaleOrTranslation()) |
| << quad->shared_quad_state->quad_to_target_transform.ToString(); |
| gfx::RectF target_rectf = MathUtil::MapClippedRect( |
| quad->shared_quad_state->quad_to_target_transform, |
| gfx::RectF(quad->rect)); |
| // Scale transforms allowed, as long as the final transformed rect |
| // ends up on integer boundaries for ease of testing. |
| ASSERT_EQ(target_rectf, gfx::RectF(target_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() |
| : LayerImplTest(LayerTreeSettings()) {} |
| |
| LayerTestCommon::LayerImplTest::LayerImplTest( |
| std::unique_ptr<LayerTreeFrameSink> layer_tree_frame_sink) |
| : LayerImplTest(LayerTreeSettings(), std::move(layer_tree_frame_sink)) {} |
| |
| LayerTestCommon::LayerImplTest::LayerImplTest(const LayerTreeSettings& settings) |
| : LayerImplTest(settings, FakeLayerTreeFrameSink::Create3d()) {} |
| |
| LayerTestCommon::LayerImplTest::LayerImplTest( |
| const LayerTreeSettings& settings, |
| std::unique_ptr<LayerTreeFrameSink> layer_tree_frame_sink) |
| : layer_tree_frame_sink_(std::move(layer_tree_frame_sink)), |
| animation_host_(AnimationHost::CreateForTesting(ThreadInstance::MAIN)), |
| host_(FakeLayerTreeHost::Create(&client_, |
| &task_graph_runner_, |
| animation_host_.get(), |
| settings)), |
| render_pass_(viz::RenderPass::Create()), |
| layer_impl_id_(2) { |
| std::unique_ptr<LayerImpl> root = |
| LayerImpl::Create(host_->host_impl()->active_tree(), 1); |
| host_->host_impl()->active_tree()->SetRootLayerForTesting(std::move(root)); |
| host_->host_impl()->SetVisible(true); |
| EXPECT_TRUE( |
| host_->host_impl()->InitializeFrameSink(layer_tree_frame_sink_.get())); |
| |
| const int timeline_id = AnimationIdProvider::NextTimelineId(); |
| timeline_ = AnimationTimeline::Create(timeline_id); |
| animation_host_->AddAnimationTimeline(timeline_); |
| // Create impl-side instance. |
| animation_host_->PushPropertiesTo(host_->host_impl()->animation_host()); |
| timeline_impl_ = |
| host_->host_impl()->animation_host()->GetTimelineById(timeline_id); |
| } |
| |
| LayerTestCommon::LayerImplTest::~LayerImplTest() { |
| animation_host_->RemoveAnimationTimeline(timeline_); |
| timeline_ = nullptr; |
| host_->host_impl()->ReleaseLayerTreeFrameSink(); |
| } |
| |
| void LayerTestCommon::LayerImplTest::CalcDrawProps( |
| const gfx::Size& viewport_size) { |
| RenderSurfaceList render_surface_list; |
| LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs( |
| root_layer_for_testing(), viewport_size, &render_surface_list); |
| LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&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 occlusion(layer_impl->DrawTransform(), |
| SimpleEnclosedRegion(occluded), SimpleEnclosedRegion()); |
| layer_impl->draw_properties().occlusion_in_content_space = occlusion; |
| |
| if (layer_impl->WillDraw(DRAW_MODE_HARDWARE, resource_provider())) { |
| layer_impl->AppendQuads(render_pass_.get(), &data); |
| layer_impl->DidDraw(resource_provider()); |
| } |
| } |
| |
| void LayerTestCommon::LayerImplTest::AppendQuadsForPassWithOcclusion( |
| LayerImpl* layer_impl, |
| viz::RenderPass* given_render_pass, |
| const gfx::Rect& occluded) { |
| AppendQuadsData data; |
| |
| given_render_pass->quad_list.clear(); |
| given_render_pass->shared_quad_state_list.clear(); |
| |
| Occlusion occlusion(layer_impl->DrawTransform(), |
| SimpleEnclosedRegion(occluded), SimpleEnclosedRegion()); |
| layer_impl->draw_properties().occlusion_in_content_space = occlusion; |
| |
| layer_impl->WillDraw(DRAW_MODE_HARDWARE, resource_provider()); |
| layer_impl->AppendQuads(given_render_pass, &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(); |
| |
| surface_impl->set_occlusion_in_content_space( |
| Occlusion(gfx::Transform(), SimpleEnclosedRegion(occluded), |
| SimpleEnclosedRegion())); |
| surface_impl->AppendQuads(DRAW_MODE_HARDWARE, render_pass_.get(), &data); |
| } |
| |
| void LayerTestCommon::LayerImplTest::RequestCopyOfOutput() { |
| root_layer_for_testing()->test_properties()->copy_requests.push_back( |
| viz::CopyOutputRequest::CreateStubForTesting()); |
| } |
| |
| void LayerTestCommon::SetupBrowserControlsAndScrollLayerWithVirtualViewport( |
| LayerTreeHostImpl* host_impl, |
| LayerTreeImpl* tree_impl, |
| float top_controls_height, |
| const gfx::Size& inner_viewport_size, |
| const gfx::Size& outer_viewport_size, |
| const gfx::Size& scroll_layer_size) { |
| tree_impl->SetRootLayerForTesting(nullptr); |
| tree_impl->set_browser_controls_shrink_blink_size(true); |
| tree_impl->SetTopControlsHeight(top_controls_height); |
| tree_impl->SetCurrentBrowserControlsShownRatio(1.f); |
| tree_impl->PushPageScaleFromMainThread(1.f, 1.f, 1.f); |
| host_impl->DidChangeBrowserControlsPosition(); |
| |
| std::unique_ptr<LayerImpl> root = LayerImpl::Create(tree_impl, 1); |
| std::unique_ptr<LayerImpl> root_clip = LayerImpl::Create(tree_impl, 2); |
| std::unique_ptr<LayerImpl> page_scale = LayerImpl::Create(tree_impl, 3); |
| |
| std::unique_ptr<LayerImpl> outer_scroll = LayerImpl::Create(tree_impl, 4); |
| std::unique_ptr<LayerImpl> outer_clip = LayerImpl::Create(tree_impl, 5); |
| |
| root_clip->SetBounds(inner_viewport_size); |
| root->SetScrollable(inner_viewport_size); |
| root->SetElementId(LayerIdToElementIdForTesting(root->id())); |
| root->SetBounds(outer_viewport_size); |
| root->SetDrawsContent(false); |
| root_clip->test_properties()->force_render_surface = true; |
| root->test_properties()->is_container_for_fixed_position_layers = true; |
| outer_clip->SetBounds(outer_viewport_size); |
| outer_scroll->SetScrollable(outer_viewport_size); |
| outer_scroll->SetElementId(LayerIdToElementIdForTesting(outer_scroll->id())); |
| outer_scroll->SetBounds(scroll_layer_size); |
| outer_scroll->SetDrawsContent(false); |
| outer_scroll->test_properties()->is_container_for_fixed_position_layers = |
| true; |
| |
| int inner_viewport_container_layer_id = root_clip->id(); |
| int outer_viewport_container_layer_id = outer_clip->id(); |
| int inner_viewport_scroll_layer_id = root->id(); |
| int outer_viewport_scroll_layer_id = outer_scroll->id(); |
| int page_scale_layer_id = page_scale->id(); |
| |
| outer_clip->test_properties()->AddChild(std::move(outer_scroll)); |
| root->test_properties()->AddChild(std::move(outer_clip)); |
| page_scale->test_properties()->AddChild(std::move(root)); |
| root_clip->test_properties()->AddChild(std::move(page_scale)); |
| |
| tree_impl->SetRootLayerForTesting(std::move(root_clip)); |
| LayerTreeImpl::ViewportLayerIds viewport_ids; |
| viewport_ids.page_scale = page_scale_layer_id; |
| viewport_ids.inner_viewport_container = inner_viewport_container_layer_id; |
| viewport_ids.outer_viewport_container = outer_viewport_container_layer_id; |
| viewport_ids.inner_viewport_scroll = inner_viewport_scroll_layer_id; |
| viewport_ids.outer_viewport_scroll = outer_viewport_scroll_layer_id; |
| tree_impl->SetViewportLayersFromIds(viewport_ids); |
| tree_impl->BuildPropertyTreesForTesting(); |
| |
| tree_impl->SetDeviceViewportSize(inner_viewport_size); |
| LayerImpl* root_clip_ptr = tree_impl->root_layer_for_testing(); |
| EXPECT_EQ(inner_viewport_size, root_clip_ptr->bounds()); |
| } |
| |
| } // namespace cc |