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