blink_test_plugin.cc 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. // Copyright 2015 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 <stdarg.h>
  5. #include <stdint.h>
  6. #include <string.h>
  7. #include <sstream>
  8. #include <utility>
  9. #include "base/strings/stringprintf.h"
  10. #include "ppapi/cpp/completion_callback.h"
  11. #include "ppapi/cpp/graphics_2d.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. namespace {
  17. void DummyCompletionCallback(void*, int32_t) {}
  18. // This is a simple C++ Pepper plugin for Blink layout tests.
  19. //
  20. // Layout tests can instantiate this plugin by requesting the mime type
  21. // application/x-blink-test-plugin. When possible, tests should use the
  22. // startAfterLoadAndFinish() helper in resources/plugin.js to perform work
  23. // after the plugin has loaded.
  24. //
  25. // The plugin also exposes several other features for testing convenience:
  26. // - On first paint, the plugin posts a 'loaded' message to its owner element.
  27. // - On subsequent paints, the plugin posts a 'painted' message instead.
  28. // - Keyboard and mouse input events are logged to the console.
  29. class BlinkTestInstance : public pp::Instance {
  30. public:
  31. explicit BlinkTestInstance(PP_Instance instance)
  32. : pp::Instance(instance), first_paint_(true) {}
  33. ~BlinkTestInstance() override {}
  34. bool Init(uint32_t argc, const char* argn[], const char* argv[]) override {
  35. // It's hard / impossible for some layout tests to listen for a message from
  36. // the plugin. For example, a plugin in PluginDocuments is unreachable from
  37. // a cross-origin parent frame, since the actual plugin element is in a
  38. // different Document. To help with this case, the plugin logs a message
  39. // that can be captured indirectly in test expectations.
  40. LogMessage("initializing");
  41. // Used by layout tests that want to inspect the args the plugin is
  42. // instantiated with.
  43. for (uint32_t i = 0; i < argc; ++i) {
  44. if (!strcmp(argn[i], "logargs")) {
  45. LogMessage("plugin args:");
  46. for (uint32_t j = 0; j < argc; ++j)
  47. LogMessage(" name = %s, value = %s", argn[j], argv[j]);
  48. }
  49. }
  50. return RequestFilteringInputEvents(PP_INPUTEVENT_CLASS_MOUSE |
  51. PP_INPUTEVENT_CLASS_KEYBOARD) == PP_OK;
  52. }
  53. void DidChangeView(const pp::View& view) override {
  54. view_ = view;
  55. device_context_ = pp::Graphics2D(this, view_.GetRect().size(), true);
  56. if (!BindGraphics(device_context_))
  57. return;
  58. // Since we draw a static image, we only need to make a new frame when
  59. // the device is initialized or the view size changes.
  60. Paint();
  61. }
  62. void DidChangeFocus(bool has_focus) override {
  63. LogMessage("DidChangeFocus(%s)", has_focus ? "true" : "false");
  64. }
  65. bool HandleInputEvent(const pp::InputEvent& event) override {
  66. switch (event.GetType()) {
  67. case PP_INPUTEVENT_TYPE_MOUSEDOWN:
  68. LogMouseEvent("Down", event);
  69. break;
  70. case PP_INPUTEVENT_TYPE_MOUSEUP:
  71. LogMouseEvent("Up", event);
  72. break;
  73. case PP_INPUTEVENT_TYPE_KEYDOWN:
  74. LogKeyboardEvent("Down", event);
  75. break;
  76. case PP_INPUTEVENT_TYPE_KEYUP:
  77. LogKeyboardEvent("Up", event);
  78. break;
  79. case PP_INPUTEVENT_TYPE_MOUSEMOVE:
  80. case PP_INPUTEVENT_TYPE_MOUSEENTER:
  81. case PP_INPUTEVENT_TYPE_MOUSELEAVE:
  82. case PP_INPUTEVENT_TYPE_RAWKEYDOWN:
  83. case PP_INPUTEVENT_TYPE_CHAR:
  84. // Just swallow these events without any logging.
  85. return true;
  86. default:
  87. LogMessage("Unexpected input event with type = %d", event.GetType());
  88. return false;
  89. }
  90. return true;
  91. }
  92. private:
  93. void Paint() {
  94. pp::ImageData image(this, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
  95. view_.GetRect().size(), true);
  96. if (image.is_null())
  97. return;
  98. // Draw blue and green checkerboard pattern to show "interesting" keyframe.
  99. const int kSquareSizePixels = 8;
  100. for (int y = 0; y < view_.GetRect().size().height(); ++y) {
  101. for (int x = 0; x < view_.GetRect().size().width(); ++x) {
  102. int x_square = x / kSquareSizePixels;
  103. int y_square = y / kSquareSizePixels;
  104. uint32_t color = ((x_square + y_square) % 2) ? 0xFF0000FF : 0xFF00FF00;
  105. *image.GetAddr32(pp::Point(x, y)) = color;
  106. }
  107. }
  108. device_context_.ReplaceContents(&image);
  109. device_context_.Flush(
  110. pp::CompletionCallback(&DummyCompletionCallback, nullptr));
  111. // TODO(dcheng): In theory, this should wait for the flush to complete
  112. // before claiming that it's painted. In practice, this is difficult: when
  113. // running layout tests, a frame is typically only generated at the end of
  114. // the layout test. Sending the completion message in the callback results
  115. // in a deadlock: the test wants to wait for the plugin to paint, but the
  116. // plugin won't paint until the test completes. This seems to be Good
  117. // Enough™ for now.
  118. if (first_paint_) {
  119. first_paint_ = false;
  120. PostMessage(pp::Var("loaded"));
  121. } else {
  122. PostMessage(pp::Var("painted"));
  123. }
  124. }
  125. void LogMouseEvent(const char* type, const pp::InputEvent& event) {
  126. pp::MouseInputEvent mouse_event(event);
  127. pp::Point mouse_position = mouse_event.GetPosition();
  128. LogMessage("Mouse%s at (%d,%d)", type, mouse_position.x(),
  129. mouse_position.y());
  130. }
  131. void LogKeyboardEvent(const char* type, const pp::InputEvent& event) {
  132. pp::KeyboardInputEvent keyboard_event(event);
  133. LogMessage("Key%s '%s'", type, keyboard_event.GetCode().AsString().c_str());
  134. }
  135. void LogMessage(const char* format...) {
  136. va_list args;
  137. va_start(args, format);
  138. LogToConsoleWithSource(PP_LOGLEVEL_LOG, pp::Var("Blink Test Plugin"),
  139. pp::Var(base::StringPrintV(format, args)));
  140. va_end(args);
  141. }
  142. bool first_paint_;
  143. pp::View view_;
  144. pp::Graphics2D device_context_;
  145. };
  146. class BlinkTestModule : public pp::Module {
  147. public:
  148. BlinkTestModule() {}
  149. virtual ~BlinkTestModule() {}
  150. virtual pp::Instance* CreateInstance(PP_Instance instance) {
  151. return new BlinkTestInstance(instance);
  152. }
  153. };
  154. } // namespace
  155. namespace pp {
  156. Module* CreateModule() {
  157. return new BlinkTestModule();
  158. }
  159. } // namespace pp