OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "extensions/renderer/api_binding_hooks.h" | 5 #include "extensions/renderer/api_binding_hooks.h" |
6 | 6 |
7 #include "base/memory/ptr_util.h" | 7 #include "base/memory/ptr_util.h" |
8 #include "base/strings/stringprintf.h" | 8 #include "base/strings/stringprintf.h" |
9 #include "base/supports_user_data.h" | 9 #include "base/supports_user_data.h" |
10 #include "gin/arguments.h" | 10 #include "gin/arguments.h" |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
77 } | 77 } |
78 | 78 |
79 v8::Isolate* isolate; | 79 v8::Isolate* isolate; |
80 | 80 |
81 std::map<std::string, v8::Global<v8::Object>> hook_interfaces; | 81 std::map<std::string, v8::Global<v8::Object>> hook_interfaces; |
82 }; | 82 }; |
83 | 83 |
84 gin::WrapperInfo JSHookInterface::kWrapperInfo = | 84 gin::WrapperInfo JSHookInterface::kWrapperInfo = |
85 {gin::kEmbedderNativeGin}; | 85 {gin::kEmbedderNativeGin}; |
86 | 86 |
87 // Creates and returns JS object for the hook interface to allow for | |
88 // registering custom hooks from JS. | |
89 v8::Local<v8::Object> CreateJSHookInterface(const std::string& api_name, | |
90 v8::Local<v8::Context> context) { | |
91 gin::PerContextData* per_context_data = gin::PerContextData::From(context); | |
92 DCHECK(per_context_data); | |
93 APIHooksPerContextData* data = static_cast<APIHooksPerContextData*>( | |
94 per_context_data->GetUserData(kExtensionAPIHooksPerContextKey)); | |
95 if (!data) { | |
96 auto api_data = | |
97 base::MakeUnique<APIHooksPerContextData>(context->GetIsolate()); | |
98 data = api_data.get(); | |
99 per_context_data->SetUserData(kExtensionAPIHooksPerContextKey, | |
100 api_data.release()); | |
101 } | |
102 | |
103 DCHECK(data->hook_interfaces.find(api_name) == data->hook_interfaces.end()); | |
104 | |
105 gin::Handle<JSHookInterface> hooks = | |
106 gin::CreateHandle(context->GetIsolate(), new JSHookInterface(api_name)); | |
107 CHECK(!hooks.IsEmpty()); | |
108 v8::Local<v8::Object> hooks_object = hooks.ToV8().As<v8::Object>(); | |
109 data->hook_interfaces[api_name].Reset(context->GetIsolate(), hooks_object); | |
110 | |
111 return hooks_object; | |
112 } | |
113 | |
114 } // namespace | 87 } // namespace |
115 | 88 |
116 APIBindingHooks::APIBindingHooks(const binding::RunJSFunction& run_js) | 89 APIBindingHooks::APIBindingHooks(const binding::RunJSFunction& run_js) |
117 : run_js_(run_js) {} | 90 : run_js_(run_js) {} |
118 APIBindingHooks::~APIBindingHooks() {} | 91 APIBindingHooks::~APIBindingHooks() {} |
119 | 92 |
120 void APIBindingHooks::RegisterHandleRequest(const std::string& method_name, | 93 void APIBindingHooks::RegisterHandleRequest(const std::string& method_name, |
121 const HandleRequestHook& hook) { | 94 const HandleRequestHook& hook) { |
122 DCHECK(!hooks_used_) << "Hooks must be registered before the first use!"; | 95 DCHECK(!hooks_used_) << "Hooks must be registered before the first use!"; |
123 request_hooks_[method_name] = hook; | 96 request_hooks_[method_name] = hook; |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
161 CHECK(hook_interface); | 134 CHECK(hook_interface); |
162 | 135 |
163 auto js_hook_iter = hook_interface->js_hooks()->find(method_name); | 136 auto js_hook_iter = hook_interface->js_hooks()->find(method_name); |
164 if (js_hook_iter == hook_interface->js_hooks()->end()) | 137 if (js_hook_iter == hook_interface->js_hooks()->end()) |
165 return false; | 138 return false; |
166 | 139 |
167 // Found a JS handler. | 140 // Found a JS handler. |
168 std::vector<v8::Local<v8::Value>> v8_args; | 141 std::vector<v8::Local<v8::Value>> v8_args; |
169 // TODO(devlin): Right now, this doesn't support exceptions or return values, | 142 // TODO(devlin): Right now, this doesn't support exceptions or return values, |
170 // which we will need to at some point. | 143 // which we will need to at some point. |
171 if (arguments->GetRemaining(&v8_args)) { | 144 if (arguments->Length() == 0 || arguments->GetRemaining(&v8_args)) { |
172 v8::Local<v8::Function> handler = | 145 v8::Local<v8::Function> handler = |
173 js_hook_iter->second.Get(context->GetIsolate()); | 146 js_hook_iter->second.Get(context->GetIsolate()); |
174 run_js_.Run(handler, context, v8_args.size(), v8_args.data()); | 147 run_js_.Run(handler, context, v8_args.size(), v8_args.data()); |
175 } | 148 } |
176 | 149 |
177 return true; | 150 return true; |
178 } | 151 } |
179 | 152 |
180 void APIBindingHooks::InitializeInContext( | 153 void APIBindingHooks::InitializeInContext( |
181 v8::Local<v8::Context> context, | 154 v8::Local<v8::Context> context, |
182 const std::string& api_name) { | 155 const std::string& api_name) { |
183 if (js_hooks_source_.IsEmpty()) | 156 if (js_hooks_source_.IsEmpty()) |
184 return; | 157 return; |
185 | 158 |
186 v8::Local<v8::String> source = js_hooks_source_.Get(context->GetIsolate()); | 159 v8::Local<v8::String> source = js_hooks_source_.Get(context->GetIsolate()); |
187 v8::Local<v8::String> resource_name = | 160 v8::Local<v8::String> resource_name = |
188 js_resource_name_.Get(context->GetIsolate()); | 161 js_resource_name_.Get(context->GetIsolate()); |
189 v8::Local<v8::Script> script; | 162 v8::Local<v8::Script> script; |
190 v8::ScriptOrigin origin(resource_name); | 163 v8::ScriptOrigin origin(resource_name); |
191 if (!v8::Script::Compile(context, source, &origin).ToLocal(&script)) | 164 if (!v8::Script::Compile(context, source, &origin).ToLocal(&script)) |
192 return; | 165 return; |
193 v8::Local<v8::Value> func_as_value = script->Run(); | 166 v8::Local<v8::Value> func_as_value = script->Run(); |
194 v8::Local<v8::Function> function; | 167 v8::Local<v8::Function> function; |
195 if (!gin::ConvertFromV8(context->GetIsolate(), func_as_value, &function)) | 168 if (!gin::ConvertFromV8(context->GetIsolate(), func_as_value, &function)) |
196 return; | 169 return; |
197 v8::Local<v8::Object> api_hooks = CreateJSHookInterface(api_name, context); | 170 v8::Local<v8::Value> api_hooks = GetJSHookInterface(api_name, context); |
198 v8::Local<v8::Value> args[] = {api_hooks}; | 171 v8::Local<v8::Value> args[] = {api_hooks}; |
199 run_js_.Run(function, context, arraysize(args), args); | 172 run_js_.Run(function, context, arraysize(args), args); |
200 } | 173 } |
201 | 174 |
| 175 v8::Local<v8::Object> APIBindingHooks::GetJSHookInterface( |
| 176 const std::string& api_name, |
| 177 v8::Local<v8::Context> context) { |
| 178 gin::PerContextData* per_context_data = gin::PerContextData::From(context); |
| 179 DCHECK(per_context_data); |
| 180 APIHooksPerContextData* data = static_cast<APIHooksPerContextData*>( |
| 181 per_context_data->GetUserData(kExtensionAPIHooksPerContextKey)); |
| 182 if (!data) { |
| 183 auto api_data = |
| 184 base::MakeUnique<APIHooksPerContextData>(context->GetIsolate()); |
| 185 data = api_data.get(); |
| 186 per_context_data->SetUserData(kExtensionAPIHooksPerContextKey, |
| 187 api_data.release()); |
| 188 } |
| 189 |
| 190 auto iter = data->hook_interfaces.find(api_name); |
| 191 if (iter != data->hook_interfaces.end()) |
| 192 return iter->second.Get(context->GetIsolate()); |
| 193 |
| 194 gin::Handle<JSHookInterface> hooks = |
| 195 gin::CreateHandle(context->GetIsolate(), new JSHookInterface(api_name)); |
| 196 CHECK(!hooks.IsEmpty()); |
| 197 v8::Local<v8::Object> hooks_object = hooks.ToV8().As<v8::Object>(); |
| 198 data->hook_interfaces[api_name].Reset(context->GetIsolate(), hooks_object); |
| 199 |
| 200 return hooks_object; |
| 201 } |
| 202 |
202 } // namespace extensions | 203 } // namespace extensions |
OLD | NEW |