1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
|
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/rounded_display/rounded_display_provider.h"
#include <algorithm>
#include <memory>
#include <string>
#include <vector>
#include "ash/rounded_display/rounded_display_gutter.h"
#include "ash/rounded_display/rounded_display_provider_test_api.h"
#include "ash/shell.h"
#include "ash/test/ash_test_base.h"
#include "base/test/gtest_util.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/display/display.h"
#include "ui/display/manager/display_manager.h"
#include "ui/gfx/geometry/rounded_corners_f.h"
namespace ash {
namespace {
using Gutters = std::vector<RoundedDisplayGutter*>;
using RoundedCorner = RoundedDisplayGutter::RoundedCorner;
using RoundedCornerPosition = RoundedDisplayGutter::RoundedCorner::Position;
using ProviderStrategy = RoundedDisplayProvider::Strategy;
constexpr ProviderStrategy kDefaultTestStrategy = ProviderStrategy::kScanout;
gfx::RoundedCornersF CreateHorizontallyUniformRadii(int radius_a,
int radius_b) {
return gfx::RoundedCornersF(radius_a, radius_a, radius_b, radius_b);
}
// The matcher matches a RoundedDisplayGutter that has the rounded corners of
// `positions`.
template <typename... Matchers>
auto GutterWithMatchingCorners(Matchers&&... positions) {
return testing::ResultOf(
"positions",
[](const RoundedDisplayGutter* gutter) {
std::vector<RoundedCornerPosition> positions;
const std::vector<RoundedCorner>& corners = gutter->GetGutterCorners();
base::ranges::transform(
corners.begin(), corners.end(), std::back_inserter(positions),
[](const RoundedCorner& corner) { return corner.position(); });
return positions;
},
testing::UnorderedElementsAre(positions...));
}
class RoundedDisplayProviderTest : public AshTestBase {
public:
RoundedDisplayProviderTest() = default;
RoundedDisplayProviderTest(const RoundedDisplayProviderTest&) = delete;
RoundedDisplayProviderTest& operator=(const RoundedDisplayProviderTest&) =
delete;
~RoundedDisplayProviderTest() override = default;
void SetUp() override {
AshTestBase::SetUp();
// Create the rounded display provider for the primary display.
provider_ = RoundedDisplayProvider::Create(GetPrimaryDisplay().id());
}
void TearDown() override {
provider_.reset();
AshTestBase::TearDown();
}
protected:
const display::Display& GetDisplay(int64_t display_id) {
return display_manager()->GetDisplayForId(display_id);
}
std::unique_ptr<RoundedDisplayProvider> provider_;
};
TEST_F(RoundedDisplayProviderTest, InitializeWithNonUniformRadii) {
RoundedDisplayProviderTestApi test_api(provider_.get());
const gfx::RoundedCornersF not_valid_radii(10, 11, 12, 12);
EXPECT_DCHECK_DEATH(
{ provider_->Init(not_valid_radii, kDefaultTestStrategy); });
}
TEST_F(RoundedDisplayProviderTest, CorrectNumberOfGuttersAreProvided) {
RoundedDisplayProviderTestApi test_api(provider_.get());
const gfx::RoundedCornersF radii = CreateHorizontallyUniformRadii(10, 12);
// We expect 2 overlay gutters to be created.
provider_->Init(radii, kDefaultTestStrategy);
EXPECT_EQ(test_api.GetGutters().size(), 2u);
}
TEST_F(RoundedDisplayProviderTest,
CorrectGutterCreatedForStrategy_ScanoutDirection) {
RoundedDisplayProviderTestApi test_api(provider_.get());
const gfx::RoundedCornersF radii = CreateHorizontallyUniformRadii(10, 12);
provider_->Init(radii, ProviderStrategy::kScanout);
const auto& gutters = test_api.GetGutters();
EXPECT_EQ(gutters.size(), 2u);
// Check that we have two overlay gutters that in the scanout direction.
EXPECT_THAT(gutters, testing::Contains(GutterWithMatchingCorners(
RoundedCornerPosition::kUpperLeft,
RoundedCornerPosition::kUpperRight)));
EXPECT_THAT(gutters, testing::Contains(GutterWithMatchingCorners(
RoundedCornerPosition::kLowerLeft,
RoundedCornerPosition::kLowerRight)));
}
TEST_F(RoundedDisplayProviderTest,
CorrectGutterCreatedForStrategy_OtherDirection) {
RoundedDisplayProviderTestApi test_api(provider_.get());
const gfx::RoundedCornersF radii = CreateHorizontallyUniformRadii(10, 12);
provider_->Init(radii, ProviderStrategy::kOther);
const auto& gutters = test_api.GetGutters();
EXPECT_EQ(gutters.size(), 2u);
// Check that we have two overlay gutters that in the scanout direction.
EXPECT_THAT(gutters, testing::Contains(GutterWithMatchingCorners(
RoundedCornerPosition::kUpperLeft,
RoundedCornerPosition::kLowerLeft)));
// Right overlay gutter.
EXPECT_THAT(gutters, testing::Contains(GutterWithMatchingCorners(
RoundedCornerPosition::kUpperRight,
RoundedCornerPosition::kLowerRight)));
}
class RoundedDisplayProviderSurfaceUpdateTest
: public RoundedDisplayProviderTest,
public ::testing::WithParamInterface<
std::tuple<std::string, std::string, bool>> {
public:
RoundedDisplayProviderSurfaceUpdateTest()
: initial_display_spec_(std::get<0>(GetParam())),
updated_display_spec_(std::get<1>(GetParam())),
expect_update_(std::get<2>(GetParam())) {}
RoundedDisplayProviderSurfaceUpdateTest(
const RoundedDisplayProviderSurfaceUpdateTest&) = delete;
RoundedDisplayProviderSurfaceUpdateTest& operator=(
const RoundedDisplayProviderSurfaceUpdateTest&) = delete;
~RoundedDisplayProviderSurfaceUpdateTest() override = default;
protected:
std::string initial_display_spec_;
std::string updated_display_spec_;
bool expect_update_;
};
TEST_P(RoundedDisplayProviderSurfaceUpdateTest,
UpdatesSurfaceOnlyWhenNecessary) {
RoundedDisplayProviderTestApi test_api(provider_.get());
display::Display primary_display =
display::Screen::GetScreen()->GetPrimaryDisplay();
auto display_id = primary_display.id();
UpdateDisplay(initial_display_spec_);
gfx::RoundedCornersF radii =
display_manager()->GetDisplayInfo(display_id).panel_corners_radii();
provider_->Init(radii, kDefaultTestStrategy);
ASSERT_TRUE(provider_->UpdateRoundedDisplaySurface());
UpdateDisplay(updated_display_spec_);
Gutters before_update_gutters = test_api.GetGutters();
ASSERT_EQ(provider_->UpdateRoundedDisplaySurface(), expect_update_);
Gutters after_update_gutters = test_api.GetGutters();
// Confirm that we did not change gutters.
EXPECT_EQ(before_update_gutters, after_update_gutters);
}
const std::string kInitialDisplaySpec = "500x400~15";
const std::string kInitialDisplaySpecWithRotation = "500x400/r~15";
INSTANTIATE_TEST_SUITE_P(
/* no prefix */,
RoundedDisplayProviderSurfaceUpdateTest,
testing::Values(
// If nothing changes, we should skip surface update.
std::make_tuple(kInitialDisplaySpec,
"500x400~15",
/*expect_update=*/false),
// Change in device scale factor, should only cause a surface update.
std::make_tuple(kInitialDisplaySpec,
"500x400*2~15",
/*expect_update=*/true),
// Further display rotation, should only cause a surface update.
std::make_tuple(kInitialDisplaySpecWithRotation,
"500x400/u~15",
/*expect_update=*/true),
// Multiple spec changes, should appropriately cause a surface update.
std::make_tuple(kInitialDisplaySpec,
"500x400*2~15",
/*expect_update=*/true)));
} // namespace
} // namespace ash
|