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 5 #include "extensions/renderer/script_context_set.h" 6 7 #include "base/message_loop/message_loop.h" 8 #include "content/public/renderer/render_view.h" 9 #include "extensions/common/extension.h" 10 #include "extensions/renderer/script_context.h" 11 #include "v8/include/v8.h" 12 13 namespace extensions { 14 ScriptContextSet()15ScriptContextSet::ScriptContextSet() { 16 } ~ScriptContextSet()17ScriptContextSet::~ScriptContextSet() { 18 } 19 size() const20int ScriptContextSet::size() const { 21 return static_cast<int>(contexts_.size()); 22 } 23 Add(ScriptContext * context)24void ScriptContextSet::Add(ScriptContext* context) { 25 #if DCHECK_IS_ON 26 // It's OK to insert the same context twice, but we should only ever have 27 // one ScriptContext per v8::Context. 28 for (ContextSet::iterator iter = contexts_.begin(); iter != contexts_.end(); 29 ++iter) { 30 ScriptContext* candidate = *iter; 31 if (candidate != context) 32 DCHECK(candidate->v8_context() != context->v8_context()); 33 } 34 #endif 35 contexts_.insert(context); 36 } 37 Remove(ScriptContext * context)38void ScriptContextSet::Remove(ScriptContext* context) { 39 if (contexts_.erase(context)) { 40 context->Invalidate(); 41 base::MessageLoop::current()->DeleteSoon(FROM_HERE, context); 42 } 43 } 44 GetAll() const45ScriptContextSet::ContextSet ScriptContextSet::GetAll() const { 46 return contexts_; 47 } 48 GetCurrent() const49ScriptContext* ScriptContextSet::GetCurrent() const { 50 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 51 return isolate->InContext() ? GetByV8Context(isolate->GetCurrentContext()) 52 : NULL; 53 } 54 GetCalling() const55ScriptContext* ScriptContextSet::GetCalling() const { 56 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 57 v8::Local<v8::Context> calling = isolate->GetCallingContext(); 58 return calling.IsEmpty() ? NULL : GetByV8Context(calling); 59 } 60 GetByV8Context(v8::Handle<v8::Context> v8_context) const61ScriptContext* ScriptContextSet::GetByV8Context( 62 v8::Handle<v8::Context> v8_context) const { 63 for (ContextSet::const_iterator iter = contexts_.begin(); 64 iter != contexts_.end(); 65 ++iter) { 66 if ((*iter)->v8_context() == v8_context) 67 return *iter; 68 } 69 70 return NULL; 71 } 72 ForEach(const std::string & extension_id,content::RenderView * render_view,const base::Callback<void (ScriptContext *)> & callback) const73void ScriptContextSet::ForEach( 74 const std::string& extension_id, 75 content::RenderView* render_view, 76 const base::Callback<void(ScriptContext*)>& callback) const { 77 // We copy the context list, because calling into javascript may modify it 78 // out from under us. 79 ContextSet contexts = GetAll(); 80 81 for (ContextSet::iterator it = contexts.begin(); it != contexts.end(); ++it) { 82 ScriptContext* context = *it; 83 84 // For the same reason as above, contexts may become invalid while we run. 85 if (!context->is_valid()) 86 continue; 87 88 if (!extension_id.empty()) { 89 const Extension* extension = context->extension(); 90 if (!extension || (extension_id != extension->id())) 91 continue; 92 } 93 94 content::RenderView* context_render_view = context->GetRenderView(); 95 if (!context_render_view) 96 continue; 97 98 if (render_view && render_view != context_render_view) 99 continue; 100 101 callback.Run(context); 102 } 103 } 104 OnExtensionUnloaded(const std::string & extension_id)105ScriptContextSet::ContextSet ScriptContextSet::OnExtensionUnloaded( 106 const std::string& extension_id) { 107 ContextSet contexts = GetAll(); 108 ContextSet removed; 109 110 // Clean up contexts belonging to the unloaded extension. This is done so 111 // that content scripts (which remain injected into the page) don't continue 112 // receiving events and sending messages. 113 for (ContextSet::iterator it = contexts.begin(); it != contexts.end(); ++it) { 114 if ((*it)->extension() && (*it)->extension()->id() == extension_id) { 115 (*it)->DispatchOnUnloadEvent(); 116 removed.insert(*it); 117 Remove(*it); 118 } 119 } 120 121 return removed; 122 } 123 124 } // namespace extensions 125