2 * Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
18 // Both includes need to go first as otherwise they can conflict with EGL.h
19 // being included by the following includes.
20 #include <gmock/gmock.h>
21 #include <gtest/gtest.h>
23 #include "anbox/application/database.h"
24 #include "anbox/platform/base_platform.h"
25 #include "anbox/wm/multi_window_manager.h"
26 #include "anbox/wm/window_state.h"
28 #include "anbox/graphics/layer_composer.h"
29 #include "anbox/graphics/multi_window_composer_strategy.h"
31 using namespace ::testing;
34 class MockRenderer : public anbox::graphics::Renderer {
36 MOCK_METHOD3(draw, bool(EGLNativeWindowType, const anbox::graphics::Rect&,
37 const RenderableList&));
43 TEST(LayerComposer, FindsNoSuitableWindowForLayer) {
44 auto renderer = std::make_shared<MockRenderer>();
46 platform::Configuration config;
47 // The default policy will create a dumb window instance when requested
49 auto platform = platform::create(std::string(), nullptr, config);
50 auto app_db = std::make_shared<application::Database>();
51 auto wm = std::make_shared<wm::MultiWindowManager>(platform, nullptr, app_db);
53 auto single_window = wm::WindowState{
56 graphics::Rect{0, 0, 1024, 768},
59 wm::Stack::Id::Freeform,
62 wm->apply_window_state_update({single_window}, {});
64 LayerComposer composer(renderer, std::make_shared<MultiWindowComposerStrategy>(wm));
66 // A single renderable which has a different task id then the window we know
68 RenderableList renderables = {
69 {"org.anbox.surface.2", 0, 1.0f, {0, 0, 1024, 768}, {0, 0, 1024, 768}},
72 // The renderer should not be called for a layer which doesn't exist
73 EXPECT_CALL(*renderer, draw(_, _, _)).Times(0);
75 composer.submit_layers(renderables);
78 TEST(LayerComposer, MapsLayersToWindows) {
79 auto renderer = std::make_shared<MockRenderer>();
81 platform::Configuration config;
82 // The default policy will create a dumb window instance when requested
84 auto platform = platform::create(std::string(), nullptr, config);
85 auto app_db = std::make_shared<application::Database>();
86 auto wm = std::make_shared<wm::MultiWindowManager>(platform, nullptr, app_db);
88 auto first_window = wm::WindowState{
91 graphics::Rect{0, 0, 1024, 768},
94 wm::Stack::Id::Freeform,
97 auto second_window = wm::WindowState{
100 graphics::Rect{300, 400, 1324, 1168},
103 wm::Stack::Id::Freeform,
106 wm->apply_window_state_update({first_window, second_window}, {});
108 LayerComposer composer(renderer, std::make_shared<MultiWindowComposerStrategy>(wm));
110 // A single renderable which has a different task id then the window we know
112 RenderableList renderables = {
113 {"org.anbox.surface.1", 0, 1.0f, {0, 0, 1024, 768}, {0, 0, 1024, 768}},
114 {"org.anbox.surface.2", 1, 1.0f, {0, 0, 1024, 768}, {0, 0, 1024, 768}},
117 RenderableList first_window_renderables{
118 {"org.anbox.surface.1", 0, 1.0f, {0, 0, 1024, 768}, {0, 0, 1024, 768}},
121 RenderableList second_window_renderables{
122 {"org.anbox.surface.2", 1, 1.0f, {0, 0, 1024, 768}, {0, 0, 1024, 768}},
125 EXPECT_CALL(*renderer, draw(_, Rect{0, 0, first_window.frame().width(),
126 first_window.frame().height()},
127 first_window_renderables))
129 .WillOnce(Return(true));
130 EXPECT_CALL(*renderer, draw(_, Rect{0, 0, second_window.frame().width(),
131 second_window.frame().height()},
132 second_window_renderables))
134 .WillOnce(Return(true));
136 composer.submit_layers(renderables);
139 TEST(LayerComposer, WindowPartiallyOffscreen) {
140 auto renderer = std::make_shared<MockRenderer>();
142 platform::Configuration config;
143 // The default policy will create a dumb window instance when requested
145 auto platform = platform::create(std::string(), nullptr, config);
146 auto app_db = std::make_shared<application::Database>();
147 auto wm = std::make_shared<wm::MultiWindowManager>(platform, nullptr, app_db);
149 auto window = wm::WindowState{
152 graphics::Rect{-100, -100, 924, 668},
155 wm::Stack::Id::Freeform,
158 wm->apply_window_state_update({window}, {});
160 LayerComposer composer(renderer, std::make_shared<MultiWindowComposerStrategy>(wm));
162 // Window is build out of two layers where one is placed inside the other
163 // but the layer covering the whole window is placed with its top left
164 // origin outside of the visible display area.
165 RenderableList renderables = {
166 {"org.anbox.surface.1", 0, 1.0f, {-100, -100, 924, 668}, {0, 0, 1024, 768}},
167 {"org.anbox.surface.1", 1, 1.0f, {0, 0, 100, 200}, {0, 0, 100, 200}},
170 RenderableList expected_renderables{
171 {"org.anbox.surface.1", 0, 1.0f, {0, 0, 1024, 768}, {0, 0, 1024, 768}},
172 {"org.anbox.surface.1", 1, 1.0f, {100, 100, 200, 300}, {0, 0, 100, 200}},
175 EXPECT_CALL(*renderer, draw(_, Rect{0, 0,
176 window.frame().width(),
177 window.frame().height()},
178 expected_renderables))
180 .WillOnce(Return(true));
182 composer.submit_layers(renderables);
185 TEST(LayerComposer, PopupShouldNotCauseWindowLayerOffset) {
186 auto renderer = std::make_shared<MockRenderer>();
188 platform::Configuration config;
189 // The default policy will create a dumb window instance when requested
191 auto platform = platform::create(std::string(), nullptr, config);
192 auto app_db = std::make_shared<application::Database>();
193 auto wm = std::make_shared<wm::MultiWindowManager>(platform, nullptr, app_db);
195 auto window = wm::WindowState{
198 graphics::Rect{1120, 270, 2144, 1038},
201 wm::Stack::Id::Freeform,
204 wm->apply_window_state_update({window}, {});
206 LayerComposer composer(renderer, std::make_shared<MultiWindowComposerStrategy>(wm));
208 // Having two renderables where the second smaller one overlaps the bigger
209 // one and goes a bit offscreen. This should be still placed correctly and
210 // the small layer should go offscreen as it is supposed to. This typically
211 // happens when a popup window appears which has a shadow attached which goes
212 // out of the window area. In our case this is not possible as the area the
213 // window has available is static.
214 RenderableList renderables = {
215 {"org.anbox.surface.3", 0, 1.0f, {1120,270,2144,1038}, {0, 0, 1024, 768}},
216 {"org.anbox.surface.3", 1, 1.0f, {1904, 246, 2164, 406}, {0, 0, 260, 160}},
219 RenderableList expected_renderables{
220 {"org.anbox.surface.3", 0, 1.0f, {0, 0, 1024, 768}, {0, 0, 1024, 768}},
221 {"org.anbox.surface.3", 1, 1.0f, {784, -24, 1044, 136}, {0, 0, 260, 160}},
224 EXPECT_CALL(*renderer, draw(_, Rect{0, 0,
225 window.frame().width(),
226 window.frame().height()},
227 expected_renderables))
229 .WillOnce(Return(true));
231 composer.submit_layers(renderables);
234 } // namespace graphics