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.
5 #include "extensions/renderer/script_context_set.h"
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"
13 namespace extensions
{
15 ScriptContextSet::ScriptContextSet() {
17 ScriptContextSet::~ScriptContextSet() {
20 int ScriptContextSet::size() const {
21 return static_cast<int>(contexts_
.size());
24 void ScriptContextSet::Add(ScriptContext
* context
) {
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();
30 ScriptContext
* candidate
= *iter
;
31 if (candidate
!= context
)
32 DCHECK(candidate
->v8_context() != context
->v8_context());
35 contexts_
.insert(context
);
38 void ScriptContextSet::Remove(ScriptContext
* context
) {
39 if (contexts_
.erase(context
)) {
40 context
->Invalidate();
41 base::MessageLoop::current()->DeleteSoon(FROM_HERE
, context
);
45 ScriptContextSet::ContextSet
ScriptContextSet::GetAll() const {
49 ScriptContext
* ScriptContextSet::GetCurrent() const {
50 v8::Isolate
* isolate
= v8::Isolate::GetCurrent();
51 return isolate
->InContext() ? GetByV8Context(isolate
->GetCurrentContext())
55 ScriptContext
* 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
);
61 ScriptContext
* ScriptContextSet::GetByV8Context(
62 v8::Handle
<v8::Context
> v8_context
) const {
63 for (ContextSet::const_iterator iter
= contexts_
.begin();
64 iter
!= contexts_
.end();
66 if ((*iter
)->v8_context() == v8_context
)
73 void 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
79 ContextSet contexts
= GetAll();
81 for (ContextSet::iterator it
= contexts
.begin(); it
!= contexts
.end(); ++it
) {
82 ScriptContext
* context
= *it
;
84 // For the same reason as above, contexts may become invalid while we run.
85 if (!context
->is_valid())
88 if (!extension_id
.empty()) {
89 const Extension
* extension
= context
->extension();
90 if (!extension
|| (extension_id
!= extension
->id()))
94 content::RenderView
* context_render_view
= context
->GetRenderView();
95 if (!context_render_view
)
98 if (render_view
&& render_view
!= context_render_view
)
101 callback
.Run(context
);
105 ScriptContextSet::ContextSet
ScriptContextSet::OnExtensionUnloaded(
106 const std::string
& extension_id
) {
107 ContextSet contexts
= GetAll();
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();
124 } // namespace extensions