binding_generating_native_handler.cc 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. // Copyright 2014 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 "extensions/renderer/binding_generating_native_handler.h"
  5. #include "extensions/renderer/script_context.h"
  6. #include "extensions/renderer/v8_helpers.h"
  7. #include "gin/data_object_builder.h"
  8. #include "v8/include/v8-context.h"
  9. #include "v8/include/v8-function.h"
  10. #include "v8/include/v8-microtask-queue.h"
  11. namespace extensions {
  12. using v8_helpers::GetProperty;
  13. BindingGeneratingNativeHandler::BindingGeneratingNativeHandler(
  14. ScriptContext* context,
  15. const std::string& api_name,
  16. const std::string& bind_to)
  17. : context_(context), api_name_(api_name), bind_to_(bind_to) {}
  18. void BindingGeneratingNativeHandler::Initialize() {}
  19. bool BindingGeneratingNativeHandler::IsInitialized() {
  20. // There's no initialization to do, so just always return true.
  21. return true;
  22. }
  23. v8::Local<v8::Object> BindingGeneratingNativeHandler::NewInstance() {
  24. // This long sequence of commands effectively runs the JavaScript code,
  25. // such that result[bind_to] is the compiled schema for |api_name|:
  26. //
  27. // var result = {};
  28. // result[bind_to] = require('binding').Binding.create(api_name).generate();
  29. // return result;
  30. //
  31. // Unfortunately using the v8 APIs makes that quite verbose.
  32. // Each stage is marked with the code it executes.
  33. v8::Isolate* isolate = context_->isolate();
  34. v8::EscapableHandleScope scope(isolate);
  35. // Convert |api_name| and |bind_to| into their v8::Strings to pass
  36. // through the v8 APIs.
  37. v8::Local<v8::String> v8_api_name;
  38. if (!v8_helpers::ToV8String(isolate, api_name_, &v8_api_name)) {
  39. NOTREACHED();
  40. return v8::Local<v8::Object>();
  41. }
  42. v8::Local<v8::Context> v8_context = context_->v8_context();
  43. // require('binding');
  44. v8::Local<v8::Object> binding_module;
  45. if (!context_->module_system()->Require("binding").ToLocal(&binding_module)) {
  46. NOTREACHED();
  47. return v8::Local<v8::Object>();
  48. }
  49. // require('binding').Binding;
  50. v8::Local<v8::Value> binding_value;
  51. v8::Local<v8::Object> binding;
  52. if (!GetProperty(v8_context, binding_module, "Binding", &binding_value) ||
  53. !binding_value->ToObject(v8_context).ToLocal(&binding)) {
  54. NOTREACHED();
  55. return v8::Local<v8::Object>();
  56. }
  57. // require('binding').Binding.create;
  58. v8::Local<v8::Value> create_binding_value;
  59. if (!GetProperty(v8_context, binding, "create", &create_binding_value) ||
  60. !create_binding_value->IsFunction()) {
  61. NOTREACHED();
  62. return v8::Local<v8::Object>();
  63. }
  64. v8::Local<v8::Function> create_binding =
  65. create_binding_value.As<v8::Function>();
  66. // require('Binding').Binding.create(api_name);
  67. v8::Local<v8::Object> binding_instance;
  68. {
  69. v8::Local<v8::Value> argv[] = {v8_api_name};
  70. v8::Local<v8::Value> binding_instance_value;
  71. v8::MicrotasksScope microtasks_scope(
  72. v8_context->GetIsolate(), v8::MicrotasksScope::kDoNotRunMicrotasks);
  73. // TODO(devlin): We should not be using v8::Function::Call() directly here.
  74. // Instead, we should use JSRunner once it's used outside native bindings.
  75. if (!create_binding->Call(v8_context, binding, std::size(argv), argv)
  76. .ToLocal(&binding_instance_value) ||
  77. !binding_instance_value->ToObject(v8_context)
  78. .ToLocal(&binding_instance)) {
  79. NOTREACHED();
  80. return v8::Local<v8::Object>();
  81. }
  82. }
  83. // require('binding').Binding.create(api_name).generate;
  84. v8::Local<v8::Value> generate_value;
  85. if (!GetProperty(v8_context, binding_instance, "generate", &generate_value) ||
  86. !generate_value->IsFunction()) {
  87. NOTREACHED();
  88. return v8::Local<v8::Object>();
  89. }
  90. v8::Local<v8::Function> generate = generate_value.As<v8::Function>();
  91. // require('binding').Binding.create(api_name).generate();
  92. v8::Local<v8::Value> compiled_schema;
  93. {
  94. v8::MicrotasksScope microtasks_scope(
  95. v8_context->GetIsolate(), v8::MicrotasksScope::kDoNotRunMicrotasks);
  96. // TODO(devlin): We should not be using v8::Function::Call() directly here.
  97. // Instead, we should use JSRunner once it's used outside native bindings.
  98. if (!generate->Call(v8_context, binding_instance, 0, nullptr)
  99. .ToLocal(&compiled_schema)) {
  100. NOTREACHED();
  101. return v8::Local<v8::Object>();
  102. }
  103. }
  104. // var result = {};
  105. // result[bind_to] = ...;
  106. v8::Local<v8::Object> object =
  107. gin::DataObjectBuilder(isolate).Set(bind_to_, compiled_schema).Build();
  108. // return result;
  109. return scope.Escape(object);
  110. }
  111. } // namespace extensions