blink_deprecated_test_plugin.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  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. //
  5. // A simple C++ Pepper plugin for exercising deprecated PPAPI interfaces in
  6. // Blink layout tests.
  7. //
  8. // Most layout tests should prefer to use the normal Blink test plugin, with the
  9. // MIME type application/x-blink-test-plugin. For layout tests that absolutely
  10. // need to test deprecated synchronous scripting interfaces, this plugin can be
  11. // instantiated using the application/x-blink-deprecated-test-plugin MIME type.
  12. //
  13. // The plugin exposes the following interface:
  14. //
  15. // Attributes:
  16. // testwindowopen: if set, the plugin will synchronously attempt to open a
  17. // window from DidCreateInstance, and log a message if successful.
  18. //
  19. // keydownscript: if set, the plugin will execute the value of the attribute as
  20. // a script on a key down.
  21. //
  22. // mousedownscript: if set, the plugin will execute the value of the attribute
  23. // as a script on a mouse button down.
  24. //
  25. //
  26. // Functions:
  27. // * plugin.normalize(): synchronously calls window.pluginCallback.
  28. //
  29. // * plugin.remember(value): keeps a reference on |value| in the plugin.
  30. //
  31. // * plugin.testCloneObject(): creates and returns another instance of the
  32. // plugin object.
  33. //
  34. // * plugin.testCreateTestObject(): creates and returns a new TestObject
  35. // instance (see below).
  36. //
  37. // * plugin.testExecuteScript(script): synchronously evaluates |script| and
  38. // returns the result.
  39. //
  40. // * plugin.testGetProperty(property): returns the property named |property|
  41. // from the window object.
  42. //
  43. // * plugin.testPassTestObject(function, object): synchronously calls the
  44. // function named |function| on the window object, passing it |object| as a
  45. // parameter, and returns its result.
  46. //
  47. // * plugin.testScriptObjectInvoke(function, value): synchronously calls the
  48. // function named |function| on the window object, passing it |value| as a
  49. // parameter, and returns its result.
  50. //
  51. //
  52. // Properties:
  53. // * plugin.testObject (read-only): a TestObject instance (see below).
  54. //
  55. // * plugin.testObjectCount (read-only): the number of TestObject instance
  56. // created.
  57. //
  58. // * plugin.testGetUndefined (read-only): returns undefined.
  59. //
  60. //
  61. // TestObject exposes the following interface:
  62. // Properties:
  63. // * object.testObject (read-only: another TestObject instance.
  64. #include <stdint.h>
  65. #include <map>
  66. #include <sstream>
  67. #include <unordered_map>
  68. #include <utility>
  69. #include "base/bind.h"
  70. #include "base/callback.h"
  71. #include "base/callback_helpers.h"
  72. #include "base/strings/stringprintf.h"
  73. #include "ppapi/cpp/dev/scriptable_object_deprecated.h"
  74. #include "ppapi/cpp/input_event.h"
  75. #include "ppapi/cpp/module.h"
  76. #include "ppapi/cpp/private/instance_private.h"
  77. #include "ppapi/cpp/private/var_private.h"
  78. #include "ppapi/cpp/var.h"
  79. namespace {
  80. class ScriptableBase : public pp::deprecated::ScriptableObject {
  81. public:
  82. explicit ScriptableBase(pp::InstancePrivate* instance)
  83. : instance_(instance) {}
  84. ~ScriptableBase() override {}
  85. // pp::deprecated::ScriptableObject overrides:
  86. bool HasMethod(const pp::Var& name, pp::Var* exception) override {
  87. return FindMethod(name) != methods_.end();
  88. }
  89. bool HasProperty(const pp::Var& name, pp::Var* exception) override {
  90. return FindProperty(name) != properties_.end();
  91. }
  92. pp::Var Call(const pp::Var& method_name,
  93. const std::vector<pp::Var>& args,
  94. pp::Var* exception) override {
  95. auto method = FindMethod(method_name);
  96. if (method != methods_.end()) {
  97. return method->second.Run(args, exception);
  98. }
  99. return ScriptableObject::Call(method_name, args, exception);
  100. }
  101. pp::Var GetProperty(const pp::Var& name, pp::Var* exception) override {
  102. auto accessor = FindProperty(name);
  103. if (accessor != properties_.end()) {
  104. pp::Var value;
  105. accessor->second.Run(false, &value);
  106. return value;
  107. }
  108. return ScriptableObject::GetProperty(name, exception);
  109. }
  110. void SetProperty(const pp::Var& name,
  111. const pp::Var& value,
  112. pp::Var* exception) override {
  113. auto accessor = FindProperty(name);
  114. if (accessor != properties_.end())
  115. accessor->second.Run(true, const_cast<pp::Var*>(&value));
  116. else
  117. ScriptableObject::SetProperty(name, value, exception);
  118. }
  119. protected:
  120. using MethodMap = std::map<
  121. std::string,
  122. base::RepeatingCallback<pp::Var(const std::vector<pp::Var>&, pp::Var*)>>;
  123. using PropertyMap =
  124. std::map<std::string, base::RepeatingCallback<void(bool, pp::Var*)>>;
  125. MethodMap::iterator FindMethod(const pp::Var& name) {
  126. if (!name.is_string())
  127. return methods_.end();
  128. return methods_.find(name.AsString());
  129. }
  130. PropertyMap::iterator FindProperty(const pp::Var& name) {
  131. if (!name.is_string())
  132. return properties_.end();
  133. return properties_.find(name.AsString());
  134. }
  135. pp::InstancePrivate* const instance_;
  136. MethodMap methods_;
  137. PropertyMap properties_;
  138. };
  139. class TestObjectSO : public ScriptableBase {
  140. public:
  141. explicit TestObjectSO(pp::InstancePrivate* instance)
  142. : ScriptableBase(instance) {
  143. ++count_;
  144. properties_.insert(std::make_pair(
  145. "testObject", base::BindRepeating(&TestObjectSO::TestObjectAccessor,
  146. base::Unretained(this))));
  147. }
  148. ~TestObjectSO() override {
  149. --count_;
  150. }
  151. static int32_t count() { return count_; }
  152. private:
  153. void TestObjectAccessor(bool set, pp::Var* var) {
  154. if (set)
  155. return;
  156. if (test_object_.is_undefined())
  157. test_object_ = pp::VarPrivate(instance_, new TestObjectSO(instance_));
  158. *var = test_object_;
  159. }
  160. static int32_t count_;
  161. pp::VarPrivate test_object_;
  162. };
  163. int32_t TestObjectSO::count_ = 0;
  164. class InstanceSO : public ScriptableBase {
  165. public:
  166. explicit InstanceSO(pp::InstancePrivate* instance)
  167. : ScriptableBase(instance) {
  168. methods_.insert(std::make_pair(
  169. "normalize",
  170. base::BindRepeating(&InstanceSO::Normalize, base::Unretained(this))));
  171. methods_.insert(std::make_pair(
  172. "remember",
  173. base::BindRepeating(&InstanceSO::Remember, base::Unretained(this))));
  174. methods_.insert(std::make_pair(
  175. "testCloneObject", base::BindRepeating(&InstanceSO::TestCloneObject,
  176. base::Unretained(this))));
  177. methods_.insert(
  178. std::make_pair("testCreateTestObject",
  179. base::BindRepeating(&InstanceSO::TestCreateTestObject,
  180. base::Unretained(this))));
  181. methods_.insert(std::make_pair(
  182. "testExecuteScript", base::BindRepeating(&InstanceSO::TestExecuteScript,
  183. base::Unretained(this))));
  184. methods_.insert(std::make_pair(
  185. "testGetProperty", base::BindRepeating(&InstanceSO::TestGetProperty,
  186. base::Unretained(this))));
  187. methods_.insert(
  188. std::make_pair("testPassTestObject",
  189. base::BindRepeating(&InstanceSO::TestPassTestObject,
  190. base::Unretained(this))));
  191. // Note: the semantics of testScriptObjectInvoke are identical to the
  192. // semantics of testPassTestObject: call args[0] with args[1] as a
  193. // parameter.
  194. methods_.insert(
  195. std::make_pair("testScriptObjectInvoke",
  196. base::BindRepeating(&InstanceSO::TestPassTestObject,
  197. base::Unretained(this))));
  198. properties_.insert(std::make_pair(
  199. "testObject", base::BindRepeating(&InstanceSO::TestObjectAccessor,
  200. base::Unretained(this))));
  201. properties_.insert(
  202. std::make_pair("testObjectCount",
  203. base::BindRepeating(&InstanceSO::TestObjectCountAccessor,
  204. base::Unretained(this))));
  205. properties_.insert(std::make_pair(
  206. "testGetUndefined",
  207. base::BindRepeating(&InstanceSO::TestGetUndefinedAccessor,
  208. base::Unretained(this))));
  209. }
  210. ~InstanceSO() override = default;
  211. private:
  212. // Requires no argument.
  213. pp::Var Normalize(const std::vector<pp::Var>& args, pp::Var* exception) {
  214. pp::VarPrivate object = instance_->GetWindowObject();
  215. return object.Call(pp::Var("pluginCallback"), exception);
  216. }
  217. // Requires 1 argument. The argument is retained into remembered_
  218. pp::Var Remember(const std::vector<pp::Var>& args, pp::Var* exception) {
  219. if (args.size() != 1) {
  220. *exception = pp::Var("remember requires one argument");
  221. return pp::Var();
  222. }
  223. remembered_ = args[0];
  224. return pp::Var();
  225. }
  226. // Requires no argument.
  227. pp::Var TestCloneObject(const std::vector<pp::Var>& args,
  228. pp::Var* exception) {
  229. return pp::VarPrivate(instance_, new InstanceSO(instance_));
  230. }
  231. // Requires no argument.
  232. pp::Var TestCreateTestObject(const std::vector<pp::Var>& args,
  233. pp::Var* exception) {
  234. return pp::VarPrivate(instance_, new TestObjectSO(instance_));
  235. }
  236. // Requires one argument. The argument is passed through as-is to
  237. // pp::InstancePrivate::ExecuteScript().
  238. pp::Var TestExecuteScript(const std::vector<pp::Var>& args,
  239. pp::Var* exception) {
  240. if (args.size() != 1) {
  241. *exception = pp::Var("testExecuteScript requires one argument");
  242. return pp::Var();
  243. }
  244. return instance_->ExecuteScript(args[0], exception);
  245. }
  246. // Requires one or more arguments. Roughly analogous to NPN_GetProperty.
  247. // The arguments are the chain of properties to traverse, starting with the
  248. // global context.
  249. pp::Var TestGetProperty(const std::vector<pp::Var>& args,
  250. pp::Var* exception) {
  251. if (args.size() < 1) {
  252. *exception = pp::Var("testGetProperty requires at least one argument");
  253. return pp::Var();
  254. }
  255. pp::VarPrivate object = instance_->GetWindowObject();
  256. for (const auto& arg : args) {
  257. if (!object.HasProperty(arg, exception))
  258. return pp::Var();
  259. object = object.GetProperty(arg, exception);
  260. }
  261. return object;
  262. }
  263. // Requires 2 or more arguments. The first argument is the name of a function
  264. // to invoke, and the second argument is a value to pass to that function.
  265. pp::Var TestPassTestObject(const std::vector<pp::Var>& args,
  266. pp::Var* exception) {
  267. if (args.size() < 2) {
  268. *exception = pp::Var("testPassTestObject requires at least 2 arguments");
  269. return pp::Var();
  270. }
  271. pp::VarPrivate object = instance_->GetWindowObject();
  272. return object.Call(args[0], args[1], exception);
  273. }
  274. void TestObjectAccessor(bool set, pp::Var* var) {
  275. if (set)
  276. return;
  277. if (test_object_.is_undefined())
  278. test_object_ = pp::VarPrivate(instance_, new TestObjectSO(instance_));
  279. *var = test_object_;
  280. }
  281. void TestObjectCountAccessor(bool set, pp::Var* var) {
  282. if (set)
  283. return;
  284. *var = pp::Var(TestObjectSO::count());
  285. }
  286. void TestGetUndefinedAccessor(bool set, pp::Var* var) {
  287. if (set)
  288. return;
  289. *var = pp::Var();
  290. }
  291. pp::VarPrivate test_object_;
  292. pp::Var remembered_;
  293. };
  294. class BlinkDeprecatedTestInstance : public pp::InstancePrivate {
  295. public:
  296. explicit BlinkDeprecatedTestInstance(PP_Instance instance)
  297. : pp::InstancePrivate(instance) {}
  298. ~BlinkDeprecatedTestInstance() override {
  299. LogMessage("%s", "Destroying");
  300. }
  301. // pp::Instance overrides
  302. bool Init(uint32_t argc, const char* argn[], const char* argv[]) override {
  303. for (uint32_t i = 0; i < argc; ++i)
  304. attributes_[argn[i]] = argv[i];
  305. if (HasAttribute("testwindowopen"))
  306. return TestWindowOpen();
  307. if (HasAttribute("initscript"))
  308. ExecuteScript(attributes_["initscript"]);
  309. uint32_t event_classes = 0;
  310. if (HasAttribute("keydownscript"))
  311. event_classes |= PP_INPUTEVENT_CLASS_KEYBOARD;
  312. if (HasAttribute("mousedownscript"))
  313. event_classes |= PP_INPUTEVENT_CLASS_MOUSE;
  314. RequestFilteringInputEvents(event_classes);
  315. return true;
  316. }
  317. virtual bool HandleInputEvent(const pp::InputEvent& event) override {
  318. switch (event.GetType()) {
  319. case PP_INPUTEVENT_TYPE_MOUSEDOWN:
  320. if (HasAttribute("mousedownscript"))
  321. ExecuteScript(attributes_["mousedownscript"]);
  322. return true;
  323. case PP_INPUTEVENT_TYPE_KEYDOWN:
  324. if (HasAttribute("keydownscript"))
  325. ExecuteScript(attributes_["keydownscript"]);
  326. return true;
  327. default:
  328. return false;
  329. }
  330. }
  331. // pp::InstancePrivate overrides:
  332. pp::Var GetInstanceObject() override {
  333. if (instance_var_.is_undefined()) {
  334. instance_so_ = new InstanceSO(this);
  335. instance_var_ = pp::VarPrivate(this, instance_so_);
  336. }
  337. return instance_var_;
  338. }
  339. void NotifyTestCompletion() {
  340. ExecuteScript("window.testRunner.notifyDone()");
  341. }
  342. bool TestWindowOpen() {
  343. pp::Var result = GetWindowObject().Call(
  344. pp::Var("open"), pp::Var("about:blank"), pp::Var("_blank"));
  345. if (result.is_object())
  346. LogMessage("PLUGIN: WINDOW OPEN SUCCESS");
  347. NotifyTestCompletion();
  348. return true;
  349. }
  350. void LogMessage(const char* format...) {
  351. va_list args;
  352. va_start(args, format);
  353. LogToConsoleWithSource(PP_LOGLEVEL_LOG,
  354. pp::Var("Blink Deprecated Test Plugin"),
  355. pp::Var(base::StringPrintV(format, args)));
  356. va_end(args);
  357. }
  358. private:
  359. bool HasAttribute(const std::string& name) {
  360. return attributes_.find(name) != attributes_.end();
  361. }
  362. std::unordered_map<std::string, std::string> attributes_;
  363. pp::VarPrivate instance_var_;
  364. // Owned by |instance_var_|.
  365. InstanceSO* instance_so_;
  366. };
  367. class BlinkDeprecatedTestModule : public pp::Module {
  368. public:
  369. BlinkDeprecatedTestModule() {}
  370. ~BlinkDeprecatedTestModule() override {}
  371. pp::Instance* CreateInstance(PP_Instance instance) override {
  372. return new BlinkDeprecatedTestInstance(instance);
  373. }
  374. };
  375. } // namespace
  376. namespace pp {
  377. Module* CreateModule() {
  378. return new BlinkDeprecatedTestModule();
  379. }
  380. } // namespace pp