OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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 "chrome/renderer/extensions/messaging_bindings.h" | 5 #include "chrome/renderer/extensions/messaging_bindings.h" |
6 | 6 |
7 #include <map> | 7 #include <map> |
8 #include <string> | 8 #include <string> |
9 | 9 |
10 #include "base/basictypes.h" | 10 #include "base/basictypes.h" |
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
161 new ExtensionHostMsg_CloseChannel(port_id, std::string())); | 161 new ExtensionHostMsg_CloseChannel(port_id, std::string())); |
162 ClearPortData(port_id); | 162 ClearPortData(port_id); |
163 } | 163 } |
164 } | 164 } |
165 | 165 |
166 // Holds a |callback| to run sometime after |object| is GC'ed. |callback| will | 166 // Holds a |callback| to run sometime after |object| is GC'ed. |callback| will |
167 // not be executed re-entrantly to avoid running JS in an unexpected state. | 167 // not be executed re-entrantly to avoid running JS in an unexpected state. |
168 class GCCallback { | 168 class GCCallback { |
169 public: | 169 public: |
170 static void Bind(v8::Handle<v8::Object> object, | 170 static void Bind(v8::Handle<v8::Object> object, |
171 v8::Handle<v8::Function> callback) { | 171 v8::Handle<v8::Function> callback, |
172 GCCallback* cb = new GCCallback(object, callback); | 172 v8::Isolate* isolate) { |
| 173 GCCallback* cb = new GCCallback(object, callback, isolate); |
173 cb->object_.MakeWeak(cb, NearDeathCallback); | 174 cb->object_.MakeWeak(cb, NearDeathCallback); |
174 } | 175 } |
175 | 176 |
176 private: | 177 private: |
177 static void NearDeathCallback(v8::Isolate* isolate, | 178 static void NearDeathCallback(v8::Isolate* isolate, |
178 v8::Persistent<v8::Object>* object, | 179 v8::Persistent<v8::Object>* object, |
179 GCCallback* self) { | 180 GCCallback* self) { |
180 // v8 says we need to explicitly reset weak handles from their callbacks. | 181 // v8 says we need to explicitly reset weak handles from their callbacks. |
181 // It's not implicit as one might expect. | 182 // It's not implicit as one might expect. |
182 self->object_.reset(); | 183 self->object_.reset(); |
183 base::MessageLoop::current()->PostTask(FROM_HERE, | 184 base::MessageLoop::current()->PostTask(FROM_HERE, |
184 base::Bind(&GCCallback::RunCallback, base::Owned(self))); | 185 base::Bind(&GCCallback::RunCallback, base::Owned(self))); |
185 } | 186 } |
186 | 187 |
187 GCCallback(v8::Handle<v8::Object> object, v8::Handle<v8::Function> callback) | 188 GCCallback(v8::Handle<v8::Object> object, |
188 : object_(object), callback_(callback) { | 189 v8::Handle<v8::Function> callback, |
189 } | 190 v8::Isolate* isolate) |
| 191 : object_(object), callback_(callback), isolate_(isolate) {} |
190 | 192 |
191 void RunCallback() { | 193 void RunCallback() { |
192 v8::HandleScope handle_scope; | 194 v8::HandleScope handle_scope(isolate_); |
193 v8::Handle<v8::Context> context = callback_->CreationContext(); | 195 v8::Handle<v8::Context> context = callback_->CreationContext(); |
194 if (context.IsEmpty()) | 196 if (context.IsEmpty()) |
195 return; | 197 return; |
196 v8::Context::Scope context_scope(context); | 198 v8::Context::Scope context_scope(context); |
197 WebKit::WebScopedMicrotaskSuppression suppression; | 199 WebKit::WebScopedMicrotaskSuppression suppression; |
198 callback_->Call(context->Global(), 0, NULL); | 200 callback_->Call(context->Global(), 0, NULL); |
199 } | 201 } |
200 | 202 |
201 extensions::ScopedPersistent<v8::Object> object_; | 203 extensions::ScopedPersistent<v8::Object> object_; |
202 extensions::ScopedPersistent<v8::Function> callback_; | 204 extensions::ScopedPersistent<v8::Function> callback_; |
| 205 v8::Isolate* isolate_; |
203 | 206 |
204 DISALLOW_COPY_AND_ASSIGN(GCCallback); | 207 DISALLOW_COPY_AND_ASSIGN(GCCallback); |
205 }; | 208 }; |
206 | 209 |
207 // void BindToGC(object, callback) | 210 // void BindToGC(object, callback) |
208 // | 211 // |
209 // Binds |callback| to be invoked *sometime after* |object| is garbage | 212 // Binds |callback| to be invoked *sometime after* |object| is garbage |
210 // collected. We don't call the method re-entrantly so as to avoid executing | 213 // collected. We don't call the method re-entrantly so as to avoid executing |
211 // JS in some bizarro undefined mid-GC state. | 214 // JS in some bizarro undefined mid-GC state. |
212 void BindToGC(const v8::FunctionCallbackInfo<v8::Value>& args) { | 215 void BindToGC(const v8::FunctionCallbackInfo<v8::Value>& args) { |
213 CHECK(args.Length() == 2 && args[0]->IsObject() && args[1]->IsFunction()); | 216 CHECK(args.Length() == 2 && args[0]->IsObject() && args[1]->IsFunction()); |
214 GCCallback::Bind(args[0].As<v8::Object>(), args[1].As<v8::Function>()); | 217 GCCallback::Bind(args[0].As<v8::Object>(), |
| 218 args[1].As<v8::Function>(), |
| 219 args.GetIsolate()); |
215 } | 220 } |
216 }; | 221 }; |
217 | 222 |
218 } // namespace | 223 } // namespace |
219 | 224 |
220 namespace extensions { | 225 namespace extensions { |
221 | 226 |
222 ChromeV8Extension* MessagingBindings::Get( | 227 ChromeV8Extension* MessagingBindings::Get( |
223 Dispatcher* dispatcher, | 228 Dispatcher* dispatcher, |
224 ChromeV8Context* context) { | 229 ChromeV8Context* context) { |
225 return new ExtensionImpl(dispatcher, context); | 230 return new ExtensionImpl(dispatcher, context); |
226 } | 231 } |
227 | 232 |
228 // static | 233 // static |
229 void MessagingBindings::DispatchOnConnect( | 234 void MessagingBindings::DispatchOnConnect( |
230 const ChromeV8ContextSet::ContextSet& contexts, | 235 const ChromeV8ContextSet::ContextSet& contexts, |
231 int target_port_id, | 236 int target_port_id, |
232 const std::string& channel_name, | 237 const std::string& channel_name, |
233 const base::DictionaryValue& source_tab, | 238 const base::DictionaryValue& source_tab, |
234 const std::string& source_extension_id, | 239 const std::string& source_extension_id, |
235 const std::string& target_extension_id, | 240 const std::string& target_extension_id, |
236 const GURL& source_url, | 241 const GURL& source_url, |
237 content::RenderView* restrict_to_render_view) { | 242 content::RenderView* restrict_to_render_view) { |
238 v8::HandleScope handle_scope; | 243 v8::HandleScope handle_scope(v8::Isolate::GetCurrent()); |
239 | 244 |
240 scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create()); | 245 scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create()); |
241 | 246 |
242 bool port_created = false; | 247 bool port_created = false; |
243 std::string source_url_spec = source_url.spec(); | 248 std::string source_url_spec = source_url.spec(); |
244 | 249 |
245 // TODO(kalman): pass in the full ChromeV8ContextSet; call ForEach. | 250 // TODO(kalman): pass in the full ChromeV8ContextSet; call ForEach. |
246 for (ChromeV8ContextSet::ContextSet::const_iterator it = contexts.begin(); | 251 for (ChromeV8ContextSet::ContextSet::const_iterator it = contexts.begin(); |
247 it != contexts.end(); ++it) { | 252 it != contexts.end(); ++it) { |
248 if (restrict_to_render_view && | 253 if (restrict_to_render_view && |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
289 target_port_id, kReceivingEndDoesntExistError)); | 294 target_port_id, kReceivingEndDoesntExistError)); |
290 } | 295 } |
291 } | 296 } |
292 | 297 |
293 // static | 298 // static |
294 void MessagingBindings::DeliverMessage( | 299 void MessagingBindings::DeliverMessage( |
295 const ChromeV8ContextSet::ContextSet& contexts, | 300 const ChromeV8ContextSet::ContextSet& contexts, |
296 int target_port_id, | 301 int target_port_id, |
297 const std::string& message, | 302 const std::string& message, |
298 content::RenderView* restrict_to_render_view) { | 303 content::RenderView* restrict_to_render_view) { |
299 v8::HandleScope handle_scope; | 304 v8::HandleScope handle_scope(v8::Isolate::GetCurrent()); |
300 | 305 |
301 // TODO(kalman): pass in the full ChromeV8ContextSet; call ForEach. | 306 // TODO(kalman): pass in the full ChromeV8ContextSet; call ForEach. |
302 for (ChromeV8ContextSet::ContextSet::const_iterator it = contexts.begin(); | 307 for (ChromeV8ContextSet::ContextSet::const_iterator it = contexts.begin(); |
303 it != contexts.end(); ++it) { | 308 it != contexts.end(); ++it) { |
304 if (restrict_to_render_view && | 309 if (restrict_to_render_view && |
305 restrict_to_render_view != (*it)->GetRenderView()) { | 310 restrict_to_render_view != (*it)->GetRenderView()) { |
306 continue; | 311 continue; |
307 } | 312 } |
308 | 313 |
309 // TODO(kalman): remove when ContextSet::ForEach is available. | 314 // TODO(kalman): remove when ContextSet::ForEach is available. |
(...skipping 20 matching lines...) Expand all Loading... |
330 &arguments); | 335 &arguments); |
331 } | 336 } |
332 } | 337 } |
333 | 338 |
334 // static | 339 // static |
335 void MessagingBindings::DispatchOnDisconnect( | 340 void MessagingBindings::DispatchOnDisconnect( |
336 const ChromeV8ContextSet::ContextSet& contexts, | 341 const ChromeV8ContextSet::ContextSet& contexts, |
337 int port_id, | 342 int port_id, |
338 const std::string& error_message, | 343 const std::string& error_message, |
339 content::RenderView* restrict_to_render_view) { | 344 content::RenderView* restrict_to_render_view) { |
340 v8::HandleScope handle_scope; | 345 v8::HandleScope handle_scope(v8::Isolate::GetCurrent()); |
341 | 346 |
342 // TODO(kalman): pass in the full ChromeV8ContextSet; call ForEach. | 347 // TODO(kalman): pass in the full ChromeV8ContextSet; call ForEach. |
343 for (ChromeV8ContextSet::ContextSet::const_iterator it = contexts.begin(); | 348 for (ChromeV8ContextSet::ContextSet::const_iterator it = contexts.begin(); |
344 it != contexts.end(); ++it) { | 349 it != contexts.end(); ++it) { |
345 if (restrict_to_render_view && | 350 if (restrict_to_render_view && |
346 restrict_to_render_view != (*it)->GetRenderView()) { | 351 restrict_to_render_view != (*it)->GetRenderView()) { |
347 continue; | 352 continue; |
348 } | 353 } |
349 | 354 |
350 // TODO(kalman): remove when ContextSet::ForEach is available. | 355 // TODO(kalman): remove when ContextSet::ForEach is available. |
351 if ((*it)->v8_context().IsEmpty()) | 356 if ((*it)->v8_context().IsEmpty()) |
352 continue; | 357 continue; |
353 | 358 |
354 std::vector<v8::Handle<v8::Value> > arguments; | 359 std::vector<v8::Handle<v8::Value> > arguments; |
355 arguments.push_back(v8::Integer::New(port_id)); | 360 arguments.push_back(v8::Integer::New(port_id)); |
356 if (!error_message.empty()) { | 361 if (!error_message.empty()) { |
357 arguments.push_back(v8::String::New(error_message.c_str())); | 362 arguments.push_back(v8::String::New(error_message.c_str())); |
358 } else { | 363 } else { |
359 arguments.push_back(v8::Null()); | 364 arguments.push_back(v8::Null()); |
360 } | 365 } |
361 (*it)->module_system()->CallModuleMethod("messaging", | 366 (*it)->module_system()->CallModuleMethod("messaging", |
362 "dispatchOnDisconnect", | 367 "dispatchOnDisconnect", |
363 &arguments); | 368 &arguments); |
364 } | 369 } |
365 } | 370 } |
366 | 371 |
367 } // namespace extensions | 372 } // namespace extensions |
OLD | NEW |