blob: d2e52a90552f1a5bb2b1158d17b5a29ddc54c68d [file] [log] [blame]
// 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/test/property_tree_test_utils.h"
#include "cc/trees/draw_property_utils.h"
#include "cc/trees/layer_tree_impl.h"
#include "cc/trees/property_tree_builder.h"
#include "components/viz/common/quads/compositor_render_pass.h"
#include "components/viz/common/quads/draw_quad.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_conversions.h"
namespace cc {
// Align with expected and actual output.
static const char* kQuadString = " 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.
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 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))
<< kQuadString << iter.index() << " rect: " << rect.ToString()
<< " quad: " << quad_rect.ToString();
EXPECT_TRUE(remaining.Contains(quad_rect))
<< kQuadString << iter.index() << " remaining: " << remaining.ToString()
<< " quad: " << quad_rect.ToString();
remaining.Subtract(quad_rect);
}
EXPECT_TRUE(remaining.IsEmpty());
}
// static
void 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);
}
}
}
void PrepareForUpdateDrawProperties(LayerTreeImpl* layer_tree_impl) {
if (!layer_tree_impl->settings().use_layer_lists)
return;
// TODO(wangxianzhu): We should DCHECK(!needs_rebuild) after we remove all
// unnecessary setting of the flag in layer list mode.
auto* property_trees = layer_tree_impl->property_trees();
property_trees->needs_rebuild = false;
// The following are needed for tests that modify impl-side property trees.
// In production code impl-side property trees are pushed from the main
// thread and the following are done in other ways.
std::vector<std::unique_ptr<RenderSurfaceImpl>> old_render_surfaces;
property_trees->effect_tree.TakeRenderSurfaces(&old_render_surfaces);
property_trees->effect_tree.CreateOrReuseRenderSurfaces(&old_render_surfaces,
layer_tree_impl);
layer_tree_impl->MoveChangeTrackingToLayers();
property_trees->ResetCachedData();
}
void UpdateDrawProperties(LayerTreeImpl* layer_tree_impl,
LayerImplList* output_update_layer_list) {
PrepareForUpdateDrawProperties(layer_tree_impl);
layer_tree_impl->UpdateDrawProperties(
/*update_image_animation_controller*/ true, output_update_layer_list);
}
void UpdateDrawProperties(LayerTreeHost* layer_tree_host,
LayerList* output_update_layer_list) {
LayerList update_layer_list;
if (layer_tree_host->IsUsingLayerLists()) {
// TODO(wangxianzhu): We should DCHECK(!needs_rebuild) after we remove all
// unnecessary setting of the flag in layer list mode.
layer_tree_host->property_trees()->needs_rebuild = false;
} else {
PropertyTreeBuilder::BuildPropertyTrees(layer_tree_host);
}
draw_property_utils::UpdatePropertyTrees(layer_tree_host);
draw_property_utils::FindLayersThatNeedUpdates(layer_tree_host,
&update_layer_list);
if (output_update_layer_list)
*output_update_layer_list = std::move(update_layer_list);
}
void SetDeviceScaleAndUpdateViewportRect(LayerTreeImpl* layer_tree_impl,
float device_scale_factor) {
layer_tree_impl->SetDeviceScaleFactor(device_scale_factor);
gfx::Size root_bounds = layer_tree_impl->root_layer()->bounds();
layer_tree_impl->SetDeviceViewportRect(
gfx::Rect(root_bounds.width() * device_scale_factor,
root_bounds.height() * device_scale_factor));
}
void SetDeviceScaleAndUpdateViewportRect(LayerTreeHost* layer_tree_host,
float device_scale_factor) {
gfx::Size root_bounds = layer_tree_host->root_layer()->bounds();
gfx::Rect viewport_rect(root_bounds.width() * device_scale_factor,
root_bounds.height() * device_scale_factor);
layer_tree_host->SetViewportRectAndScale(viewport_rect, device_scale_factor,
viz::LocalSurfaceId());
}
} // namespace cc