// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chromecast/media/base/video_plane_controller.h"
#include "base/task/single_thread_task_runner.h"
#include "base/test/task_environment.h"
#include "chromecast/public/cast_media_shlib.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/overlay_transform.h"
namespace chromecast {
namespace media {
namespace {
using ::testing::AllOf;
using ::testing::Field;
using ::testing::FloatEq;
using ::testing::Matcher;
using ::testing::NotNull;
// Returns a matcher that matches a chromecast::RectF's x, y, width, and height
// values.
auto RectFEquals(float x, float y, float width, float height) {
return AllOf(Field(&chromecast::RectF::x, FloatEq(x)),
Field(&chromecast::RectF::y, FloatEq(y)),
Field(&chromecast::RectF::width, FloatEq(width)),
Field(&chromecast::RectF::height, FloatEq(height)));
}
class MockVideoPlane : public VideoPlane {
public:
MockVideoPlane() : VideoPlane() {}
~MockVideoPlane() override = default;
MOCK_METHOD(void, SetGeometry, (const RectF&, Transform), (override));
};
MockVideoPlane* g_video_plane = nullptr;
VideoPlane::Coordinates g_video_plane_coordinates =
VideoPlane::Coordinates::kScreen;
} // namespace
// Static function definitions for CastMediaShlib and VideoPlane.
void CastMediaShlib::Initialize(const std::vector<std::string>& argv) {
CHECK(g_video_plane == nullptr);
g_video_plane = new MockVideoPlane;
}
VideoPlane* CastMediaShlib::GetVideoPlane() {
return g_video_plane;
}
void CastMediaShlib::Finalize() {
if (g_video_plane) {
delete g_video_plane;
g_video_plane = nullptr;
}
}
// Tests can set g_video_plane_coordinates to influence how VideoPlaneController
// should report coordinates (screen resolution vs graphics resolution).
VideoPlane::Coordinates VideoPlane::GetCoordinates() {
return g_video_plane_coordinates;
}
// End of static function definitions.
namespace {
const chromecast::Size kDefaultSize(1920, 1080);
// A test fixture is used to ensure that CastMediaShlib is
// initialized/finalized, and to control the lifetime of the
// SingleThreadTaskEnvironment.
class VideoPlaneControllerTest : public ::testing::Test {
protected:
VideoPlaneControllerTest() { CastMediaShlib::Initialize({}); }
~VideoPlaneControllerTest() override { CastMediaShlib::Finalize(); }
base::test::SingleThreadTaskEnvironment environment_;
};
TEST_F(VideoPlaneControllerTest, SetsGeometryOnVideoPlane) {
VideoPlaneController controller(
kDefaultSize, base::SingleThreadTaskRunner::GetCurrentDefault());
controller.SetScreenResolution(kDefaultSize);
const gfx::RectF video_geometry(1280, 720);
ASSERT_THAT(g_video_plane, NotNull());
EXPECT_CALL(*g_video_plane,
SetGeometry(RectFEquals(0, 0, 1280, 720),
VideoPlane::Transform::TRANSFORM_NONE))
.Times(1);
controller.SetGeometry(video_geometry,
gfx::OverlayTransform::OVERLAY_TRANSFORM_NONE);
base::RunLoop().RunUntilIdle();
}
TEST_F(VideoPlaneControllerTest,
SetsGeometryOnVideoPlaneAndTranslatesToScreenCoordinates) {
g_video_plane_coordinates = VideoPlane::Coordinates::kScreen;
const chromecast::Size kScreenResolution(3840, 2160);
const chromecast::Size kGraphicsResolution(1920, 1080);
VideoPlaneController controller(
kGraphicsResolution, base::SingleThreadTaskRunner::GetCurrentDefault());
controller.SetScreenResolution(kScreenResolution);
const gfx::RectF video_geometry(960, 0, 960, 1080);
ASSERT_THAT(g_video_plane, NotNull());
// Note that the expected rect is scaled to the physical screen resolution.
EXPECT_CALL(*g_video_plane,
SetGeometry(RectFEquals(1920, 0, 1920, 2160),
VideoPlane::Transform::TRANSFORM_NONE))
.Times(1);
controller.SetGeometry(video_geometry,
gfx::OverlayTransform::OVERLAY_TRANSFORM_NONE);
base::RunLoop().RunUntilIdle();
}
TEST_F(VideoPlaneControllerTest,
SetsGeometryOnVideoPlaneAndDoesNotScaleForGraphicsCoordinates) {
g_video_plane_coordinates = VideoPlane::Coordinates::kGraphics;
const chromecast::Size kScreenResolution(3840, 2160);
const chromecast::Size kGraphicsResolution(1920, 1080);
VideoPlaneController controller(
kGraphicsResolution, base::SingleThreadTaskRunner::GetCurrentDefault());
controller.SetScreenResolution(kScreenResolution);
const gfx::RectF video_geometry(960, 0, 960, 1080);
ASSERT_THAT(g_video_plane, NotNull());
// Note that the expected rect is NOT scaled to the physical screen
// resolution, due to the value of g_video_plane_coordinates.
EXPECT_CALL(*g_video_plane,
SetGeometry(RectFEquals(960, 0, 960, 1080),
VideoPlane::Transform::TRANSFORM_NONE))
.Times(1);
controller.SetGeometry(video_geometry,
gfx::OverlayTransform::OVERLAY_TRANSFORM_NONE);
base::RunLoop().RunUntilIdle();
}
} // namespace
} // namespace media
} // namespace chromecast