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/ppb_fullscreen.h"
12 #include "ppapi/cpp/image_data.h"
13 #include "ppapi/cpp/input_event.h"
14 #include "ppapi/cpp/instance.h"
15 #include "ppapi/cpp/module.h"
16 #include "ppapi/cpp/point.h"
17 #include "ppapi/tests/test_utils.h"
18 #include "ppapi/tests/testing_instance.h"
20 REGISTER_TEST_CASE(Fullscreen
);
24 const ColorPremul kSheerBlue
= { 0x88, 0x00, 0x00, 0x88 };
25 const ColorPremul kOpaqueYellow
= { 0xFF, 0xFF, 0xFF, 0x00 };
26 const int kBytesPerPixel
= sizeof(uint32_t); // 4 bytes for BGRA or RGBA.
28 uint32_t FormatColor(PP_ImageDataFormat format
, ColorPremul color
) {
29 if (format
== PP_IMAGEDATAFORMAT_BGRA_PREMUL
)
30 return (color
.A
<< 24) | (color
.R
<< 16) | (color
.G
<< 8) | (color
.B
);
31 else if (format
== PP_IMAGEDATAFORMAT_RGBA_PREMUL
)
32 return (color
.A
<< 24) | (color
.B
<< 16) | (color
.G
<< 8) | (color
.R
);
37 bool HasMidScreen(const pp::Rect
& position
, const pp::Size
& screen_size
) {
38 static int32_t mid_x
= screen_size
.width() / 2;
39 static int32_t mid_y
= screen_size
.height() / 2;
40 return (position
.Contains(mid_x
, mid_y
));
43 void FlushCallbackCheckImageData(void* data
, int32_t result
) {
44 static_cast<TestFullscreen
*>(data
)->CheckPluginPaint();
49 TestFullscreen::TestFullscreen(TestingInstance
* instance
)
52 screen_mode_(instance
),
54 fullscreen_pending_(false),
55 normal_pending_(false),
56 fullscreen_event_(instance
->pp_instance()),
57 normal_event_(instance
->pp_instance()) {
58 screen_mode_
.GetScreenSize(&screen_size_
);
61 bool TestFullscreen::Init() {
62 if (screen_size_
.IsEmpty()) {
63 instance_
->AppendError("Failed to initialize screen_size_");
66 graphics2d_
= pp::Graphics2D(instance_
, screen_size_
, true);
67 if (!instance_
->BindGraphics(graphics2d_
)) {
68 instance_
->AppendError("Failed to initialize graphics2d_");
71 return CheckTestingInterface();
74 void TestFullscreen::RunTests(const std::string
& filter
) {
75 RUN_TEST(GetScreenSize
, filter
);
76 RUN_TEST(NormalToFullscreenToNormal
, filter
);
79 bool TestFullscreen::GotError() {
80 return !error_
.empty();
83 std::string
TestFullscreen::Error() {
84 std::string last_error
= error_
;
89 // TODO(polina): consider adding custom logic to JS for this test to
90 // get screen.width and screen.height and postMessage those to this code,
91 // so the dimensions can be checked exactly.
92 std::string
TestFullscreen::TestGetScreenSize() {
93 if (screen_size_
.width() < 320 || screen_size_
.width() > 2560)
94 return ReportError("screen_size.width()", screen_size_
.width());
95 if (screen_size_
.height() < 200 || screen_size_
.height() > 2048)
96 return ReportError("screen_size.height()", screen_size_
.height());
100 std::string
TestFullscreen::TestNormalToFullscreenToNormal() {
101 // 0. Start in normal mode.
102 if (screen_mode_
.IsFullscreen())
103 return ReportError("IsFullscreen() at start", true);
105 // 1. Switch to fullscreen.
106 // This is only allowed within a context of a user gesture (e.g. mouse click).
107 if (screen_mode_
.SetFullscreen(true))
108 return ReportError("SetFullscreen(true) outside of user gesture", true);
109 // Trigger another call to SetFullscreen(true) from HandleInputEvent().
110 // The transition is asynchronous and ends at the next DidChangeView().
111 instance_
->RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE
);
112 SimulateUserGesture();
113 // DidChangeView() will call the callback once in fullscreen mode.
114 fullscreen_event_
.Wait();
117 if (fullscreen_pending_
)
118 return "fullscreen_pending_ has not been reset";
119 if (!screen_mode_
.IsFullscreen())
120 return ReportError("IsFullscreen() in fullscreen", false);
122 // 2. Stay in fullscreen. No change.
123 if (screen_mode_
.SetFullscreen(true))
124 return ReportError("SetFullscreen(true) in fullscreen", true);
125 if (!screen_mode_
.IsFullscreen())
126 return ReportError("IsFullscreen() in fullscreen^2", false);
128 // 3. Switch to normal.
129 // The transition is asynchronous and ends at DidChangeView().
130 // No graphics devices can be bound while in transition.
131 normal_pending_
= true;
132 if (!screen_mode_
.SetFullscreen(false))
133 return ReportError("SetFullscreen(false) in fullscreen", false);
134 // DidChangeView() will signal once out of fullscreen mode.
135 normal_event_
.Wait();
139 return "normal_pending_ has not been reset";
140 if (screen_mode_
.IsFullscreen())
141 return ReportError("IsFullscreen() in normal", true);
143 // 4. Stay in normal. No change.
144 if (screen_mode_
.SetFullscreen(false))
145 return ReportError("SetFullscreen(false) in normal", true);
146 if (screen_mode_
.IsFullscreen())
147 return ReportError("IsFullscreen() in normal^2", true);
152 void TestFullscreen::SimulateUserGesture() {
153 pp::Point
plugin_center(
154 normal_position_
.x() + normal_position_
.width() / 2,
155 normal_position_
.y() + normal_position_
.height() / 2);
156 pp::Point mouse_movement
;
157 pp::MouseInputEvent
input_event(
159 PP_INPUTEVENT_TYPE_MOUSEDOWN
,
162 PP_INPUTEVENT_MOUSEBUTTON_LEFT
,
167 testing_interface_
->SimulateInputEvent(instance_
->pp_instance(),
168 input_event
.pp_resource());
171 void TestFullscreen::FailFullscreenTest(const std::string
& error
) {
173 fullscreen_event_
.Signal();
176 void TestFullscreen::FailNormalTest(const std::string
& error
) {
178 normal_event_
.Signal();
181 void TestFullscreen::PassFullscreenTest() {
182 fullscreen_event_
.Signal();
185 void TestFullscreen::PassNormalTest() {
186 normal_event_
.Signal();
189 // Transition to fullscreen can only happen when processing a user gesture.
190 bool TestFullscreen::HandleInputEvent(const pp::InputEvent
& event
) {
191 // We only let mouse events through and only mouse clicks count.
192 if (event
.GetType() != PP_INPUTEVENT_TYPE_MOUSEDOWN
&&
193 event
.GetType() != PP_INPUTEVENT_TYPE_MOUSEUP
)
195 // We got the gesture. No need to handle any more events.
196 instance_
->ClearInputEventRequest(PP_INPUTEVENT_CLASS_MOUSE
);
197 if (screen_mode_
.IsFullscreen()) {
199 ReportError("IsFullscreen() before fullscreen transition", true));
202 fullscreen_pending_
= true;
203 if (!screen_mode_
.SetFullscreen(true)) {
204 FailFullscreenTest(ReportError("SetFullscreen(true) in normal", false));
207 // DidChangeView() will complete the transition to fullscreen.
211 bool TestFullscreen::PaintPlugin(pp::Size size
, ColorPremul color
) {
212 painted_size_
= size
;
213 PP_ImageDataFormat image_format
= pp::ImageData::GetNativeImageDataFormat();
214 painted_color_
= FormatColor(image_format
, color
);
215 if (painted_color_
== 0)
217 pp::Point
origin(0, 0);
219 pp::ImageData
image(instance_
, image_format
, size
, false);
222 uint32_t* pixels
= static_cast<uint32_t*>(image
.data());
223 int num_pixels
= image
.stride() / kBytesPerPixel
* image
.size().height();
224 for (int i
= 0; i
< num_pixels
; i
++)
225 pixels
[i
] = painted_color_
;
226 graphics2d_
.PaintImageData(image
, origin
);
227 pp::CompletionCallback
cc(FlushCallbackCheckImageData
, this);
228 if (graphics2d_
.Flush(cc
) != PP_OK_COMPLETIONPENDING
)
234 void TestFullscreen::CheckPluginPaint() {
235 PP_ImageDataFormat image_format
= pp::ImageData::GetNativeImageDataFormat();
236 pp::ImageData
readback(instance_
, image_format
, painted_size_
, false);
237 pp::Point
origin(0, 0);
238 if (readback
.is_null() ||
239 PP_TRUE
!= testing_interface_
->ReadImageData(graphics2d_
.pp_resource(),
240 readback
.pp_resource(),
241 &origin
.pp_point())) {
242 error_
= "Can't read plugin image";
245 for (int y
= 0; y
< painted_size_
.height(); y
++) {
246 for (int x
= 0; x
< painted_size_
.width(); x
++) {
247 uint32_t* readback_color
= readback
.GetAddr32(pp::Point(x
, y
));
248 if (painted_color_
!= *readback_color
) {
249 error_
= "Plugin image contains incorrect pixel value";
254 if (screen_mode_
.IsFullscreen())
255 PassFullscreenTest();
260 // Transitions to/from fullscreen is asynchronous ending at DidChangeView.
261 // The number of calls to DidChangeView during fullscreen / normal transitions
262 // isn't specified by the API. The test waits until it the screen has
263 // transitioned to the desired state.
265 // WebKit does not change the plugin size, but Pepper does explicitly set
266 // it to screen width and height when SetFullscreen(true) is called and
267 // resets it back when ViewChanged is received indicating that we exited
270 // NOTE: The number of DidChangeView calls for <object> might be different.
271 // TODO(bbudge) Figure out how to test that the plugin positon eventually
272 // changes to normal_position_.
273 void TestFullscreen::DidChangeView(const pp::View
& view
) {
274 pp::Rect position
= view
.GetRect();
275 pp::Rect clip
= view
.GetClipRect();
277 if (normal_position_
.IsEmpty())
278 normal_position_
= position
;
280 bool is_fullscreen
= screen_mode_
.IsFullscreen();
281 if (fullscreen_pending_
&& is_fullscreen
) {
282 fullscreen_pending_
= false;
283 if (!HasMidScreen(position
, screen_size_
))
284 FailFullscreenTest("DidChangeView is not in the middle of the screen");
285 else if (position
.size() != screen_size_
)
286 FailFullscreenTest("DidChangeView does not have screen size");
287 // NOTE: we cannot reliably test for clip size being equal to the screen
288 // because it might be affected by JS console, info bars, etc.
289 else if (!instance_
->BindGraphics(graphics2d_
))
290 FailFullscreenTest("Failed to BindGraphics() in fullscreen");
291 else if (!PaintPlugin(position
.size(), kOpaqueYellow
))
292 FailFullscreenTest("Failed to paint plugin image in fullscreen");
293 } else if (normal_pending_
&& !is_fullscreen
) {
294 normal_pending_
= false;
295 if (screen_mode_
.IsFullscreen())
296 FailNormalTest("DidChangeview is in fullscreen");
297 else if (!instance_
->BindGraphics(graphics2d_
))
298 FailNormalTest("Failed to BindGraphics() in normal");
299 else if (!PaintPlugin(position
.size(), kSheerBlue
))
300 FailNormalTest("Failed to paint plugin image in normal");