2
* Copyright Ā© 2013-2014 Canonical Ltd.
4
* This program is free software: you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License version 3 as
6
* published by the Free Software Foundation.
8
* This program is distributed in the hope that it will be useful,
9
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
* GNU General Public License for more details.
13
* You should have received a copy of the GNU General Public License
14
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16
* Authored by: Kevin DuBois <kevin.dubois@canonical.com>
19
#include "src/server/scene/basic_surface.h"
21
#include "mir/geometry/rectangle.h"
23
#include "mir_test_doubles/mock_buffer_stream.h"
24
#include "mir_test/fake_shared.h"
26
#include "src/server/report/null_report_factory.h"
29
#include <gtest/gtest.h>
30
#include <gmock/gmock.h>
32
namespace mc = mir::compositor;
33
namespace mi = mir::input;
34
namespace mr = mir::report;
35
namespace ms = mir::scene;
36
namespace mt = mir::test;
37
namespace mtd = mt::doubles;
38
namespace geom = mir::geometry;
45
MOCK_METHOD0(call, void());
48
struct BasicSurfaceTest : public testing::Test
52
name = std::string("aa");
53
top_left = geom::Point{geom::X{4}, geom::Y{7}};
54
size = geom::Size{5, 9};
55
rect = geom::Rectangle{top_left, size};
56
null_change_cb = []{};
57
mock_change_cb = std::bind(&MockCallback::call, &mock_callback);
64
testing::NiceMock<MockCallback> mock_callback;
65
std::function<void()> null_change_cb;
66
std::function<void()> mock_change_cb;
67
std::shared_ptr<testing::NiceMock<mtd::MockBufferStream>> mock_buffer_stream =
68
std::make_shared<testing::NiceMock<mtd::MockBufferStream>>();
69
std::shared_ptr<ms::SceneReport> const report = mr::null_scene_report();
74
TEST_F(BasicSurfaceTest, basics)
76
ms::BasicSurface data{
82
std::shared_ptr<mi::InputChannel>(),
85
EXPECT_EQ(name, data.name());
86
EXPECT_EQ(rect.size, data.size());
87
EXPECT_EQ(rect.top_left, data.top_left());
88
EXPECT_FALSE(data.shaped());
91
TEST_F(BasicSurfaceTest, update_top_left)
93
EXPECT_CALL(mock_callback, call())
96
ms::BasicSurface storage{
102
std::shared_ptr<mi::InputChannel>(),
105
EXPECT_EQ(rect.top_left, storage.top_left());
107
auto new_top_left = geom::Point{geom::X{6}, geom::Y{10}};
108
storage.move_to(new_top_left);
109
EXPECT_EQ(new_top_left, storage.top_left());
112
TEST_F(BasicSurfaceTest, update_size)
114
geom::Size const new_size{34, 56};
116
EXPECT_CALL(mock_callback, call())
119
ms::BasicSurface storage{
125
std::shared_ptr<mi::InputChannel>(),
128
EXPECT_EQ(rect.size, storage.size());
129
EXPECT_NE(new_size, storage.size());
131
auto old_transformation = storage.transformation();
133
storage.resize(new_size);
134
EXPECT_EQ(new_size, storage.size());
135
EXPECT_NE(old_transformation, storage.transformation());
138
TEST_F(BasicSurfaceTest, test_surface_set_rotation_updates_transform)
140
EXPECT_CALL(mock_callback, call())
143
ms::BasicSurface storage{
149
std::shared_ptr<mi::InputChannel>(),
152
auto original_transformation = storage.transformation();
154
storage.set_rotation(60.0f, glm::vec3{0.0f, 0.0f, 1.0f});
155
auto rotated_transformation = storage.transformation();
156
EXPECT_NE(original_transformation, rotated_transformation);
159
TEST_F(BasicSurfaceTest, test_surface_transformation_cache_refreshes)
161
using namespace testing;
163
const geom::Size sz{geom::Width{85}, geom::Height{43}};
164
const geom::Rectangle origin{geom::Point{geom::X{77}, geom::Y{88}}, sz};
165
const geom::Rectangle moved_pt{geom::Point{geom::X{55}, geom::Y{66}}, sz};
166
ms::BasicSurface storage{
172
std::shared_ptr<mi::InputChannel>(),
175
glm::mat4 t0 = storage.transformation();
176
storage.move_to(moved_pt.top_left);
177
EXPECT_NE(t0, storage.transformation());
178
storage.move_to(origin.top_left);
179
EXPECT_EQ(t0, storage.transformation());
181
storage.set_rotation(60.0f, glm::vec3{0.0f, 0.0f, 1.0f});
182
glm::mat4 t1 = storage.transformation();
186
TEST_F(BasicSurfaceTest, test_surface_set_alpha_notifies_changes)
188
using namespace testing;
189
EXPECT_CALL(mock_callback, call())
192
ms::BasicSurface surface_state{
198
std::shared_ptr<mi::InputChannel>(),
202
surface_state.set_alpha(0.5f);
203
EXPECT_THAT(alpha, FloatEq(surface_state.alpha()));
206
TEST_F(BasicSurfaceTest, test_surface_is_opaque_by_default)
208
using namespace testing;
209
ms::BasicSurface surface_state{
215
std::shared_ptr<mi::InputChannel>(),
218
EXPECT_THAT(1.0f, FloatEq(surface_state.alpha()));
219
EXPECT_FALSE(surface_state.shaped());
222
TEST_F(BasicSurfaceTest, test_surface_apply_rotation)
224
EXPECT_CALL(mock_callback, call())
227
ms::BasicSurface surface_state{
233
std::shared_ptr<mi::InputChannel>(),
236
surface_state.set_rotation(60.0f, glm::vec3{0.0f, 0.0f, 1.0f});
239
TEST_F(BasicSurfaceTest, test_surface_should_be_rendered_in)
241
ms::BasicSurface surface_state{
247
std::shared_ptr<mi::InputChannel>(),
250
geom::Rectangle output_rect{geom::Point{0,0}, geom::Size{100, 100}};
252
//not renderable by default
253
EXPECT_FALSE(surface_state.should_be_rendered_in(rect));
255
surface_state.set_hidden(false);
256
//not renderable if no first frame has been posted by client, regardless of hide state
257
EXPECT_FALSE(surface_state.should_be_rendered_in(output_rect));
258
surface_state.set_hidden(true);
259
EXPECT_FALSE(surface_state.should_be_rendered_in(output_rect));
261
surface_state.frame_posted();
262
EXPECT_FALSE(surface_state.should_be_rendered_in(output_rect));
264
surface_state.set_hidden(false);
265
EXPECT_TRUE(surface_state.should_be_rendered_in(output_rect));
267
// Not renderable if not overlapping with supplied rect
268
geom::Rectangle output_rect1{geom::Point{100,100}, geom::Size{100, 100}};
269
EXPECT_FALSE(surface_state.should_be_rendered_in(output_rect1));
272
TEST_F(BasicSurfaceTest, test_surface_hidden_notifies_changes)
274
using namespace testing;
275
EXPECT_CALL(mock_callback, call())
278
ms::BasicSurface surface_state{
284
std::shared_ptr<mi::InputChannel>(),
287
surface_state.set_hidden(true);
290
TEST_F(BasicSurfaceTest, test_surface_frame_posted_notifies_changes)
292
using namespace testing;
293
EXPECT_CALL(mock_callback, call())
296
ms::BasicSurface surface_state{
302
std::shared_ptr<mi::InputChannel>(),
305
surface_state.frame_posted();
308
// a 1x1 window at (1,1) will get events at (1,1)
309
TEST_F(BasicSurfaceTest, default_region_is_surface_rectangle)
312
geom::Size one_by_one{geom::Width{1}, geom::Height{1}};
313
ms::BasicSurface surface_state{
315
geom::Rectangle{pt, one_by_one},
319
std::shared_ptr<mi::InputChannel>(),
322
std::vector<geom::Point> contained_pt
324
geom::Point{geom::X{1}, geom::Y{1}}
327
for(auto x = 0; x <= 3; x++)
329
for(auto y = 0; y <= 3; y++)
331
auto test_pt = geom::Point{x, y};
332
auto contains = surface_state.contains(test_pt);
333
if (std::find(contained_pt.begin(), contained_pt.end(), test_pt) != contained_pt.end())
335
EXPECT_TRUE(contains);
339
EXPECT_FALSE(contains);
345
TEST_F(BasicSurfaceTest, set_input_region)
347
std::vector<geom::Rectangle> const rectangles = {
348
{{geom::X{0}, geom::Y{0}}, {geom::Width{1}, geom::Height{1}}}, //region0
349
{{geom::X{1}, geom::Y{1}}, {geom::Width{1}, geom::Height{1}}} //region1
352
ms::BasicSurface surface_state{
358
std::shared_ptr<mi::InputChannel>(),
361
surface_state.set_input_region(rectangles);
363
std::vector<geom::Point> contained_pt
366
geom::Point{geom::X{0}, geom::Y{0}},
368
geom::Point{geom::X{1}, geom::Y{1}},
371
for(auto x = 0; x <= 3; x++)
373
for(auto y = 0; y <= 3; y++)
375
auto test_pt = geom::Point{x, y};
376
auto contains = surface_state.contains(test_pt);
377
if (std::find(contained_pt.begin(), contained_pt.end(), test_pt) != contained_pt.end())
379
EXPECT_TRUE(contains);
383
EXPECT_FALSE(contains);