summaryrefslogtreecommitdiffstats
path: root/chrome/renderer/extensions/chrome_v8_context_set.cc
blob: 49c93978d666fb33272ac1a0d6662fd3f75bf5f0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/renderer/extensions/chrome_v8_context_set.h"

#include "base/logging.h"
#include "base/message_loop/message_loop.h"
#include "base/tracked_objects.h"
#include "base/values.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/url_constants.h"
#include "chrome/renderer/extensions/chrome_v8_context.h"
#include "content/public/renderer/render_thread.h"
#include "content/public/renderer/render_view.h"
#include "extensions/common/constants.h"
#include "third_party/WebKit/public/platform/WebURL.h"
#include "third_party/WebKit/public/platform/WebURLRequest.h"
#include "third_party/WebKit/public/web/WebDocument.h"
#include "third_party/WebKit/public/web/WebFrame.h"
#include "third_party/WebKit/public/web/WebView.h"
#include "v8/include/v8.h"

using content::RenderThread;

namespace extensions {

ChromeV8ContextSet::ChromeV8ContextSet() {
}
ChromeV8ContextSet::~ChromeV8ContextSet() {
}

int ChromeV8ContextSet::size() const {
  return static_cast<int>(contexts_.size());
}

void ChromeV8ContextSet::Add(ChromeV8Context* context) {
  if (DCHECK_IS_ON()) {
    // It's OK to insert the same context twice, but we should only ever have
    // one ChromeV8Context per v8::Context.
    for (ContextSet::iterator iter = contexts_.begin(); iter != contexts_.end();
        ++iter) {
      ChromeV8Context* candidate = *iter;
      if (candidate != context)
        DCHECK(candidate->v8_context() != context->v8_context());
    }
  }
  contexts_.insert(context);
}

void ChromeV8ContextSet::Remove(ChromeV8Context* context) {
  if (contexts_.erase(context)) {
    context->Invalidate();
    base::MessageLoop::current()->DeleteSoon(FROM_HERE, context);
  }
}

ChromeV8ContextSet::ContextSet ChromeV8ContextSet::GetAll() const {
  return contexts_;
}

ChromeV8Context* ChromeV8ContextSet::GetCurrent() const {
  return v8::Context::InContext() ?
      GetByV8Context(v8::Context::GetCurrent()) : NULL;
}

ChromeV8Context* ChromeV8ContextSet::GetCalling() const {
  v8::Local<v8::Context> calling = v8::Context::GetCalling();
  return calling.IsEmpty() ? NULL : GetByV8Context(calling);
}

ChromeV8Context* ChromeV8ContextSet::GetByV8Context(
    v8::Handle<v8::Context> v8_context) const {
  for (ContextSet::const_iterator iter = contexts_.begin();
       iter != contexts_.end(); ++iter) {
    if ((*iter)->v8_context() == v8_context)
      return *iter;
  }

  return NULL;
}

void ChromeV8ContextSet::ForEach(
    const std::string& extension_id,
    content::RenderView* render_view,
    const base::Callback<void(ChromeV8Context*)>& callback) const {
  // We copy the context list, because calling into javascript may modify it
  // out from under us.
  ContextSet contexts = GetAll();

  for (ContextSet::iterator it = contexts.begin(); it != contexts.end();
       ++it) {
    ChromeV8Context* context = *it;

    // For the same reason as above, contexts may become invalid while we run.
    if (!context->is_valid())
      continue;

    if (!extension_id.empty()) {
      const Extension* extension = context->extension();
      if (!extension || (extension_id != extension->id()))
        continue;
    }

    content::RenderView* context_render_view = context->GetRenderView();
    if (!context_render_view)
      continue;

    if (render_view && render_view != context_render_view)
      continue;

    callback.Run(context);
  }
}

ChromeV8ContextSet::ContextSet ChromeV8ContextSet::OnExtensionUnloaded(
    const std::string& extension_id) {
  ContextSet contexts = GetAll();
  ContextSet removed;

  // Clean up contexts belonging to the unloaded extension. This is done so
  // that content scripts (which remain injected into the page) don't continue
  // receiving events and sending messages.
  for (ContextSet::iterator it = contexts.begin(); it != contexts.end();
       ++it) {
    if ((*it)->extension() && (*it)->extension()->id() == extension_id) {
      (*it)->DispatchOnUnloadEvent();
      removed.insert(*it);
      Remove(*it);
    }
  }

  return removed;
}

}  // namespace extensions