test_fullscreen.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  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.
  4. #include "ppapi/tests/test_fullscreen.h"
  5. #include <stdio.h>
  6. #include <string.h>
  7. #include <string>
  8. #include "ppapi/c/ppb_fullscreen.h"
  9. #include "ppapi/cpp/image_data.h"
  10. #include "ppapi/cpp/input_event.h"
  11. #include "ppapi/cpp/instance.h"
  12. #include "ppapi/cpp/module.h"
  13. #include "ppapi/cpp/point.h"
  14. #include "ppapi/tests/test_utils.h"
  15. #include "ppapi/tests/testing_instance.h"
  16. REGISTER_TEST_CASE(Fullscreen);
  17. namespace {
  18. const ColorPremul kSheerBlue = { 0x88, 0x00, 0x00, 0x88 };
  19. const ColorPremul kOpaqueYellow = { 0xFF, 0xFF, 0xFF, 0x00 };
  20. const int kBytesPerPixel = sizeof(uint32_t); // 4 bytes for BGRA or RGBA.
  21. uint32_t FormatColor(PP_ImageDataFormat format, ColorPremul color) {
  22. if (format == PP_IMAGEDATAFORMAT_BGRA_PREMUL)
  23. return (color.A << 24) | (color.R << 16) | (color.G << 8) | (color.B);
  24. else if (format == PP_IMAGEDATAFORMAT_RGBA_PREMUL)
  25. return (color.A << 24) | (color.B << 16) | (color.G << 8) | (color.R);
  26. else
  27. return 0;
  28. }
  29. bool HasMidScreen(const pp::Rect& position, const pp::Size& screen_size) {
  30. static int32_t mid_x = screen_size.width() / 2;
  31. static int32_t mid_y = screen_size.height() / 2;
  32. return (position.Contains(mid_x, mid_y));
  33. }
  34. void FlushCallbackCheckImageData(void* data, int32_t result) {
  35. static_cast<TestFullscreen*>(data)->CheckPluginPaint();
  36. }
  37. } // namespace
  38. TestFullscreen::TestFullscreen(TestingInstance* instance)
  39. : TestCase(instance),
  40. error_(),
  41. screen_mode_(instance),
  42. painted_color_(0),
  43. fullscreen_pending_(false),
  44. normal_pending_(false),
  45. fullscreen_event_(instance->pp_instance()),
  46. normal_event_(instance->pp_instance()) {
  47. screen_mode_.GetScreenSize(&screen_size_);
  48. }
  49. bool TestFullscreen::Init() {
  50. if (screen_size_.IsEmpty()) {
  51. instance_->AppendError("Failed to initialize screen_size_");
  52. return false;
  53. }
  54. graphics2d_ = pp::Graphics2D(instance_, screen_size_, true);
  55. if (!instance_->BindGraphics(graphics2d_)) {
  56. instance_->AppendError("Failed to initialize graphics2d_");
  57. return false;
  58. }
  59. return CheckTestingInterface();
  60. }
  61. void TestFullscreen::RunTests(const std::string& filter) {
  62. RUN_TEST(GetScreenSize, filter);
  63. RUN_TEST(NormalToFullscreenToNormal, filter);
  64. }
  65. bool TestFullscreen::GotError() {
  66. return !error_.empty();
  67. }
  68. std::string TestFullscreen::Error() {
  69. std::string last_error = error_;
  70. error_.clear();
  71. return last_error;
  72. }
  73. // TODO(polina): consider adding custom logic to JS for this test to
  74. // get screen.width and screen.height and postMessage those to this code,
  75. // so the dimensions can be checked exactly.
  76. std::string TestFullscreen::TestGetScreenSize() {
  77. if (screen_size_.width() < 320 || screen_size_.width() > 2560)
  78. return ReportError("screen_size.width()", screen_size_.width());
  79. if (screen_size_.height() < 200 || screen_size_.height() > 2048)
  80. return ReportError("screen_size.height()", screen_size_.height());
  81. PASS();
  82. }
  83. std::string TestFullscreen::TestNormalToFullscreenToNormal() {
  84. // 0. Start in normal mode.
  85. if (screen_mode_.IsFullscreen())
  86. return ReportError("IsFullscreen() at start", true);
  87. // 1. Switch to fullscreen.
  88. // This is only allowed within a context of a user gesture (e.g. mouse click).
  89. if (screen_mode_.SetFullscreen(true))
  90. return ReportError("SetFullscreen(true) outside of user gesture", true);
  91. // Trigger another call to SetFullscreen(true) from HandleInputEvent().
  92. // The transition is asynchronous and ends at the next DidChangeView().
  93. instance_->RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE);
  94. SimulateUserGesture();
  95. // DidChangeView() will call the callback once in fullscreen mode.
  96. fullscreen_event_.Wait();
  97. if (GotError())
  98. return Error();
  99. if (fullscreen_pending_)
  100. return "fullscreen_pending_ has not been reset";
  101. if (!screen_mode_.IsFullscreen())
  102. return ReportError("IsFullscreen() in fullscreen", false);
  103. // 2. Stay in fullscreen. No change.
  104. if (screen_mode_.SetFullscreen(true))
  105. return ReportError("SetFullscreen(true) in fullscreen", true);
  106. if (!screen_mode_.IsFullscreen())
  107. return ReportError("IsFullscreen() in fullscreen^2", false);
  108. // 3. Switch to normal.
  109. // The transition is asynchronous and ends at DidChangeView().
  110. // No graphics devices can be bound while in transition.
  111. normal_pending_ = true;
  112. if (!screen_mode_.SetFullscreen(false))
  113. return ReportError("SetFullscreen(false) in fullscreen", false);
  114. // DidChangeView() will signal once out of fullscreen mode.
  115. normal_event_.Wait();
  116. if (GotError())
  117. return Error();
  118. if (normal_pending_)
  119. return "normal_pending_ has not been reset";
  120. if (screen_mode_.IsFullscreen())
  121. return ReportError("IsFullscreen() in normal", true);
  122. // 4. Stay in normal. No change.
  123. if (screen_mode_.SetFullscreen(false))
  124. return ReportError("SetFullscreen(false) in normal", true);
  125. if (screen_mode_.IsFullscreen())
  126. return ReportError("IsFullscreen() in normal^2", true);
  127. PASS();
  128. }
  129. void TestFullscreen::SimulateUserGesture() {
  130. pp::Point plugin_center(
  131. normal_position_.x() + normal_position_.width() / 2,
  132. normal_position_.y() + normal_position_.height() / 2);
  133. pp::Point mouse_movement;
  134. pp::MouseInputEvent input_event(
  135. instance_,
  136. PP_INPUTEVENT_TYPE_MOUSEDOWN,
  137. NowInTimeTicks(), // time_stamp
  138. 0, // modifiers
  139. PP_INPUTEVENT_MOUSEBUTTON_LEFT,
  140. plugin_center,
  141. 1, // click_count
  142. mouse_movement);
  143. testing_interface_->SimulateInputEvent(instance_->pp_instance(),
  144. input_event.pp_resource());
  145. }
  146. void TestFullscreen::FailFullscreenTest(const std::string& error) {
  147. error_ = error;
  148. fullscreen_event_.Signal();
  149. }
  150. void TestFullscreen::FailNormalTest(const std::string& error) {
  151. error_ = error;
  152. normal_event_.Signal();
  153. }
  154. void TestFullscreen::PassFullscreenTest() {
  155. fullscreen_event_.Signal();
  156. }
  157. void TestFullscreen::PassNormalTest() {
  158. normal_event_.Signal();
  159. }
  160. // Transition to fullscreen can only happen when processing a user gesture.
  161. bool TestFullscreen::HandleInputEvent(const pp::InputEvent& event) {
  162. // We only let mouse events through and only mouse clicks count.
  163. if (event.GetType() != PP_INPUTEVENT_TYPE_MOUSEDOWN &&
  164. event.GetType() != PP_INPUTEVENT_TYPE_MOUSEUP)
  165. return false;
  166. // We got the gesture. No need to handle any more events.
  167. instance_->ClearInputEventRequest(PP_INPUTEVENT_CLASS_MOUSE);
  168. if (screen_mode_.IsFullscreen()) {
  169. FailFullscreenTest(
  170. ReportError("IsFullscreen() before fullscreen transition", true));
  171. return false;
  172. }
  173. fullscreen_pending_ = true;
  174. if (!screen_mode_.SetFullscreen(true)) {
  175. FailFullscreenTest(ReportError("SetFullscreen(true) in normal", false));
  176. return false;
  177. }
  178. // DidChangeView() will complete the transition to fullscreen.
  179. return false;
  180. }
  181. bool TestFullscreen::PaintPlugin(pp::Size size, ColorPremul color) {
  182. painted_size_ = size;
  183. PP_ImageDataFormat image_format = pp::ImageData::GetNativeImageDataFormat();
  184. painted_color_ = FormatColor(image_format, color);
  185. if (painted_color_ == 0)
  186. return false;
  187. pp::Point origin(0, 0);
  188. pp::ImageData image(instance_, image_format, size, false);
  189. if (image.is_null())
  190. return false;
  191. uint32_t* pixels = static_cast<uint32_t*>(image.data());
  192. int num_pixels = image.stride() / kBytesPerPixel * image.size().height();
  193. for (int i = 0; i < num_pixels; i++)
  194. pixels[i] = painted_color_;
  195. graphics2d_.PaintImageData(image, origin);
  196. pp::CompletionCallback cc(FlushCallbackCheckImageData, this);
  197. if (graphics2d_.Flush(cc) != PP_OK_COMPLETIONPENDING)
  198. return false;
  199. return true;
  200. }
  201. void TestFullscreen::CheckPluginPaint() {
  202. PP_ImageDataFormat image_format = pp::ImageData::GetNativeImageDataFormat();
  203. pp::ImageData readback(instance_, image_format, painted_size_, false);
  204. pp::Point origin(0, 0);
  205. if (readback.is_null() ||
  206. PP_TRUE != testing_interface_->ReadImageData(graphics2d_.pp_resource(),
  207. readback.pp_resource(),
  208. &origin.pp_point())) {
  209. error_ = "Can't read plugin image";
  210. return;
  211. }
  212. for (int y = 0; y < painted_size_.height(); y++) {
  213. for (int x = 0; x < painted_size_.width(); x++) {
  214. uint32_t* readback_color = readback.GetAddr32(pp::Point(x, y));
  215. if (painted_color_ != *readback_color) {
  216. error_ = "Plugin image contains incorrect pixel value";
  217. return;
  218. }
  219. }
  220. }
  221. if (screen_mode_.IsFullscreen())
  222. PassFullscreenTest();
  223. else
  224. PassNormalTest();
  225. }
  226. // Transitions to/from fullscreen is asynchronous ending at DidChangeView.
  227. // The number of calls to DidChangeView during fullscreen / normal transitions
  228. // isn't specified by the API. The test waits until it the screen has
  229. // transitioned to the desired state.
  230. //
  231. // WebKit does not change the plugin size, but Pepper does explicitly set
  232. // it to screen width and height when SetFullscreen(true) is called and
  233. // resets it back when ViewChanged is received indicating that we exited
  234. // fullscreen.
  235. //
  236. // NOTE: The number of DidChangeView calls for <object> might be different.
  237. // TODO(bbudge) Figure out how to test that the plugin positon eventually
  238. // changes to normal_position_.
  239. void TestFullscreen::DidChangeView(const pp::View& view) {
  240. pp::Rect position = view.GetRect();
  241. pp::Rect clip = view.GetClipRect();
  242. if (normal_position_.IsEmpty())
  243. normal_position_ = position;
  244. bool is_fullscreen = screen_mode_.IsFullscreen();
  245. if (fullscreen_pending_ && is_fullscreen) {
  246. fullscreen_pending_ = false;
  247. if (!HasMidScreen(position, screen_size_))
  248. FailFullscreenTest("DidChangeView is not in the middle of the screen");
  249. else if (position.size() != screen_size_)
  250. FailFullscreenTest("DidChangeView does not have screen size");
  251. // NOTE: we cannot reliably test for clip size being equal to the screen
  252. // because it might be affected by JS console, info bars, etc.
  253. else if (!instance_->BindGraphics(graphics2d_))
  254. FailFullscreenTest("Failed to BindGraphics() in fullscreen");
  255. else if (!PaintPlugin(position.size(), kOpaqueYellow))
  256. FailFullscreenTest("Failed to paint plugin image in fullscreen");
  257. } else if (normal_pending_ && !is_fullscreen) {
  258. normal_pending_ = false;
  259. if (screen_mode_.IsFullscreen())
  260. FailNormalTest("DidChangeview is in fullscreen");
  261. else if (!instance_->BindGraphics(graphics2d_))
  262. FailNormalTest("Failed to BindGraphics() in normal");
  263. else if (!PaintPlugin(position.size(), kSheerBlue))
  264. FailNormalTest("Failed to paint plugin image in normal");
  265. }
  266. }