1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ppapi/tests/test_fullscreen.h"
11 #include "ppapi/c/dev/ppb_testing_dev.h"
12 #include "ppapi/c/ppb_fullscreen.h"
13 #include "ppapi/cpp/image_data.h"
14 #include "ppapi/cpp/input_event.h"
15 #include "ppapi/cpp/instance.h"
16 #include "ppapi/cpp/module.h"
17 #include "ppapi/cpp/point.h"
18 #include "ppapi/tests/test_utils.h"
19 #include "ppapi/tests/testing_instance.h"
21 REGISTER_TEST_CASE(Fullscreen
);
25 const ColorPremul kOpaqueWhite
= { 0xFF, 0xFF, 0xFF, 0xFF };
26 const ColorPremul kSheerRed
= { 0x88, 0x88, 0x00, 0x00 };
27 const ColorPremul kSheerBlue
= { 0x88, 0x00, 0x00, 0x88 };
28 const ColorPremul kOpaqueYellow
= { 0xFF, 0xFF, 0xFF, 0x00 };
29 const int kBytesPerPixel
= sizeof(uint32_t); // 4 bytes for BGRA or RGBA.
31 uint32_t FormatColor(PP_ImageDataFormat format
, ColorPremul color
) {
32 if (format
== PP_IMAGEDATAFORMAT_BGRA_PREMUL
)
33 return (color
.A
<< 24) | (color
.R
<< 16) | (color
.G
<< 8) | (color
.B
);
34 else if (format
== PP_IMAGEDATAFORMAT_RGBA_PREMUL
)
35 return (color
.A
<< 24) | (color
.B
<< 16) | (color
.G
<< 8) | (color
.R
);
40 bool HasMidScreen(const pp::Rect
& position
, const pp::Size
& screen_size
) {
41 static int32_t mid_x
= screen_size
.width() / 2;
42 static int32_t mid_y
= screen_size
.height() / 2;
43 return (position
.Contains(mid_x
, mid_y
));
46 void FlushCallbackCheckImageData(void* data
, int32_t result
) {
47 static_cast<TestFullscreen
*>(data
)->CheckPluginPaint();
52 TestFullscreen::TestFullscreen(TestingInstance
* instance
)
55 screen_mode_(instance
),
57 fullscreen_pending_(false),
58 normal_pending_(false),
59 fullscreen_event_(instance
->pp_instance()),
60 normal_event_(instance
->pp_instance()) {
61 screen_mode_
.GetScreenSize(&screen_size_
);
64 bool TestFullscreen::Init() {
65 if (screen_size_
.IsEmpty()) {
66 instance_
->AppendError("Failed to initialize screen_size_");
69 graphics2d_
= pp::Graphics2D(instance_
, screen_size_
, true);
70 if (!instance_
->BindGraphics(graphics2d_
)) {
71 instance_
->AppendError("Failed to initialize graphics2d_");
74 return CheckTestingInterface();
77 void TestFullscreen::RunTests(const std::string
& filter
) {
78 RUN_TEST(GetScreenSize
, filter
);
79 RUN_TEST(NormalToFullscreenToNormal
, filter
);
82 bool TestFullscreen::GotError() {
83 return !error_
.empty();
86 std::string
TestFullscreen::Error() {
87 std::string last_error
= error_
;
92 // TODO(polina): consider adding custom logic to JS for this test to
93 // get screen.width and screen.height and postMessage those to this code,
94 // so the dimensions can be checked exactly.
95 std::string
TestFullscreen::TestGetScreenSize() {
96 if (screen_size_
.width() < 320 || screen_size_
.width() > 2560)
97 return ReportError("screen_size.width()", screen_size_
.width());
98 if (screen_size_
.height() < 200 || screen_size_
.height() > 2048)
99 return ReportError("screen_size.height()", screen_size_
.height());
103 std::string
TestFullscreen::TestNormalToFullscreenToNormal() {
104 // 0. Start in normal mode.
105 if (screen_mode_
.IsFullscreen())
106 return ReportError("IsFullscreen() at start", true);
108 // 1. Switch to fullscreen.
109 // This is only allowed within a context of a user gesture (e.g. mouse click).
110 if (screen_mode_
.SetFullscreen(true))
111 return ReportError("SetFullscreen(true) outside of user gesture", true);
112 // Trigger another call to SetFullscreen(true) from HandleInputEvent().
113 // The transition is asynchronous and ends at the next DidChangeView().
114 instance_
->RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE
);
115 SimulateUserGesture();
116 // DidChangeView() will call the callback once in fullscreen mode.
117 fullscreen_event_
.Wait();
120 if (fullscreen_pending_
)
121 return "fullscreen_pending_ has not been reset";
122 if (!screen_mode_
.IsFullscreen())
123 return ReportError("IsFullscreen() in fullscreen", false);
125 // 2. Stay in fullscreen. No change.
126 if (screen_mode_
.SetFullscreen(true))
127 return ReportError("SetFullscreen(true) in fullscreen", true);
128 if (!screen_mode_
.IsFullscreen())
129 return ReportError("IsFullscreen() in fullscreen^2", false);
131 // 3. Switch to normal.
132 // The transition is asynchronous and ends at DidChangeView().
133 // No graphics devices can be bound while in transition.
134 normal_pending_
= true;
135 if (!screen_mode_
.SetFullscreen(false))
136 return ReportError("SetFullscreen(false) in fullscreen", false);
137 // DidChangeView() will signal once out of fullscreen mode.
138 normal_event_
.Wait();
142 return "normal_pending_ has not been reset";
143 if (screen_mode_
.IsFullscreen())
144 return ReportError("IsFullscreen() in normal", true);
146 // 4. Stay in normal. No change.
147 if (screen_mode_
.SetFullscreen(false))
148 return ReportError("SetFullscreen(false) in normal", true);
149 if (screen_mode_
.IsFullscreen())
150 return ReportError("IsFullscreen() in normal^2", true);
155 void TestFullscreen::SimulateUserGesture() {
156 pp::Point
plugin_center(
157 normal_position_
.x() + normal_position_
.width() / 2,
158 normal_position_
.y() + normal_position_
.height() / 2);
159 pp::Point mouse_movement
;
160 pp::MouseInputEvent
input_event(
162 PP_INPUTEVENT_TYPE_MOUSEDOWN
,
165 PP_INPUTEVENT_MOUSEBUTTON_LEFT
,
170 testing_interface_
->SimulateInputEvent(instance_
->pp_instance(),
171 input_event
.pp_resource());
174 void TestFullscreen::FailFullscreenTest(const std::string
& error
) {
176 fullscreen_event_
.Signal();
179 void TestFullscreen::FailNormalTest(const std::string
& error
) {
181 normal_event_
.Signal();
184 void TestFullscreen::PassFullscreenTest() {
185 fullscreen_event_
.Signal();
188 void TestFullscreen::PassNormalTest() {
189 normal_event_
.Signal();
192 // Transition to fullscreen can only happen when processing a user gesture.
193 bool TestFullscreen::HandleInputEvent(const pp::InputEvent
& event
) {
194 // We only let mouse events through and only mouse clicks count.
195 if (event
.GetType() != PP_INPUTEVENT_TYPE_MOUSEDOWN
&&
196 event
.GetType() != PP_INPUTEVENT_TYPE_MOUSEUP
)
198 // We got the gesture. No need to handle any more events.
199 instance_
->ClearInputEventRequest(PP_INPUTEVENT_CLASS_MOUSE
);
200 if (screen_mode_
.IsFullscreen()) {
202 ReportError("IsFullscreen() before fullscreen transition", true));
205 fullscreen_pending_
= true;
206 if (!screen_mode_
.SetFullscreen(true)) {
207 FailFullscreenTest(ReportError("SetFullscreen(true) in normal", false));
210 // DidChangeView() will complete the transition to fullscreen.
214 bool TestFullscreen::PaintPlugin(pp::Size size
, ColorPremul color
) {
215 painted_size_
= size
;
216 PP_ImageDataFormat image_format
= pp::ImageData::GetNativeImageDataFormat();
217 painted_color_
= FormatColor(image_format
, color
);
218 if (painted_color_
== 0)
220 pp::Point
origin(0, 0);
222 pp::ImageData
image(instance_
, image_format
, size
, false);
225 uint32_t* pixels
= static_cast<uint32_t*>(image
.data());
226 int num_pixels
= image
.stride() / kBytesPerPixel
* image
.size().height();
227 for (int i
= 0; i
< num_pixels
; i
++)
228 pixels
[i
] = painted_color_
;
229 graphics2d_
.PaintImageData(image
, origin
);
230 pp::CompletionCallback
cc(FlushCallbackCheckImageData
, this);
231 if (graphics2d_
.Flush(cc
) != PP_OK_COMPLETIONPENDING
)
237 void TestFullscreen::CheckPluginPaint() {
238 PP_ImageDataFormat image_format
= pp::ImageData::GetNativeImageDataFormat();
239 pp::ImageData
readback(instance_
, image_format
, painted_size_
, false);
240 pp::Point
origin(0, 0);
241 if (readback
.is_null() ||
242 PP_TRUE
!= testing_interface_
->ReadImageData(graphics2d_
.pp_resource(),
243 readback
.pp_resource(),
244 &origin
.pp_point())) {
245 error_
= "Can't read plugin image";
248 for (int y
= 0; y
< painted_size_
.height(); y
++) {
249 for (int x
= 0; x
< painted_size_
.width(); x
++) {
250 uint32_t* readback_color
= readback
.GetAddr32(pp::Point(x
, y
));
251 if (painted_color_
!= *readback_color
) {
252 error_
= "Plugin image contains incorrect pixel value";
257 if (screen_mode_
.IsFullscreen())
258 PassFullscreenTest();
263 // Transitions to/from fullscreen is asynchronous ending at DidChangeView.
264 // The number of calls to DidChangeView during fullscreen / normal transitions
265 // isn't specified by the API. The test waits until it the screen has
266 // transitioned to the desired state.
268 // WebKit does not change the plugin size, but Pepper does explicitly set
269 // it to screen width and height when SetFullscreen(true) is called and
270 // resets it back when ViewChanged is received indicating that we exited
273 // NOTE: The number of DidChangeView calls for <object> might be different.
274 // TODO(bbudge) Figure out how to test that the plugin positon eventually
275 // changes to normal_position_.
276 void TestFullscreen::DidChangeView(const pp::View
& view
) {
277 pp::Rect position
= view
.GetRect();
278 pp::Rect clip
= view
.GetClipRect();
280 if (normal_position_
.IsEmpty())
281 normal_position_
= position
;
283 bool is_fullscreen
= screen_mode_
.IsFullscreen();
284 if (fullscreen_pending_
&& is_fullscreen
) {
285 fullscreen_pending_
= false;
286 if (!HasMidScreen(position
, screen_size_
))
287 FailFullscreenTest("DidChangeView is not in the middle of the screen");
288 else if (position
.size() != screen_size_
)
289 FailFullscreenTest("DidChangeView does not have screen size");
290 // NOTE: we cannot reliably test for clip size being equal to the screen
291 // because it might be affected by JS console, info bars, etc.
292 else if (!instance_
->BindGraphics(graphics2d_
))
293 FailFullscreenTest("Failed to BindGraphics() in fullscreen");
294 else if (!PaintPlugin(position
.size(), kOpaqueYellow
))
295 FailFullscreenTest("Failed to paint plugin image in fullscreen");
296 } else if (normal_pending_
&& !is_fullscreen
) {
297 normal_pending_
= false;
298 if (screen_mode_
.IsFullscreen())
299 FailNormalTest("DidChangeview is in fullscreen");
300 else if (!instance_
->BindGraphics(graphics2d_
))
301 FailNormalTest("Failed to BindGraphics() in normal");
302 else if (!PaintPlugin(position
.size(), kSheerBlue
))
303 FailNormalTest("Failed to paint plugin image in normal");