Home | History | Annotate | Download | only in renderer
      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/extension_helper.h"
      6 
      7 #include "content/public/renderer/render_view.h"
      8 #include "content/public/renderer/render_view_visitor.h"
      9 #include "extensions/common/api/messaging/message.h"
     10 #include "extensions/common/constants.h"
     11 #include "extensions/common/extension_messages.h"
     12 #include "extensions/renderer/console.h"
     13 #include "extensions/renderer/dispatcher.h"
     14 #include "extensions/renderer/messaging_bindings.h"
     15 #include "third_party/WebKit/public/platform/WebURLRequest.h"
     16 #include "third_party/WebKit/public/web/WebConsoleMessage.h"
     17 #include "third_party/WebKit/public/web/WebDocument.h"
     18 #include "third_party/WebKit/public/web/WebLocalFrame.h"
     19 #include "third_party/WebKit/public/web/WebView.h"
     20 
     21 using content::ConsoleMessageLevel;
     22 using blink::WebConsoleMessage;
     23 using blink::WebDataSource;
     24 using blink::WebFrame;
     25 using blink::WebLocalFrame;
     26 using blink::WebURLRequest;
     27 using blink::WebView;
     28 
     29 namespace extensions {
     30 
     31 namespace {
     32 
     33 // A RenderViewVisitor class that iterates through the set of available
     34 // views, looking for a view of the given type, in the given browser window
     35 // and within the given extension.
     36 // Used to accumulate the list of views associated with an extension.
     37 class ViewAccumulator : public content::RenderViewVisitor {
     38  public:
     39   ViewAccumulator(const std::string& extension_id,
     40                   int browser_window_id,
     41                   ViewType view_type)
     42       : extension_id_(extension_id),
     43         browser_window_id_(browser_window_id),
     44         view_type_(view_type) {
     45   }
     46 
     47   std::vector<content::RenderView*> views() { return views_; }
     48 
     49   // Returns false to terminate the iteration.
     50   virtual bool Visit(content::RenderView* render_view) OVERRIDE {
     51     ExtensionHelper* helper = ExtensionHelper::Get(render_view);
     52     if (!ViewTypeMatches(helper->view_type(), view_type_))
     53       return true;
     54 
     55     GURL url = render_view->GetWebView()->mainFrame()->document().url();
     56     if (!url.SchemeIs(kExtensionScheme))
     57       return true;
     58     const std::string& extension_id = url.host();
     59     if (extension_id != extension_id_)
     60       return true;
     61 
     62     if (browser_window_id_ != extension_misc::kUnknownWindowId &&
     63         helper->browser_window_id() != browser_window_id_) {
     64       return true;
     65     }
     66 
     67     views_.push_back(render_view);
     68 
     69     if (view_type_ == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE)
     70       return false;  // There can be only one...
     71     return true;
     72   }
     73 
     74  private:
     75   // Returns true if |type| "isa" |match|.
     76   static bool ViewTypeMatches(ViewType type, ViewType match) {
     77     if (type == match)
     78       return true;
     79 
     80     // INVALID means match all.
     81     if (match == VIEW_TYPE_INVALID)
     82       return true;
     83 
     84     return false;
     85   }
     86 
     87   std::string extension_id_;
     88   int browser_window_id_;
     89   ViewType view_type_;
     90   std::vector<content::RenderView*> views_;
     91 };
     92 
     93 }  // namespace
     94 
     95 // static
     96 std::vector<content::RenderView*> ExtensionHelper::GetExtensionViews(
     97     const std::string& extension_id,
     98     int browser_window_id,
     99     ViewType view_type) {
    100   ViewAccumulator accumulator(extension_id, browser_window_id, view_type);
    101   content::RenderView::ForEach(&accumulator);
    102   return accumulator.views();
    103 }
    104 
    105 // static
    106 content::RenderView* ExtensionHelper::GetBackgroundPage(
    107     const std::string& extension_id) {
    108   ViewAccumulator accumulator(extension_id, extension_misc::kUnknownWindowId,
    109                               VIEW_TYPE_EXTENSION_BACKGROUND_PAGE);
    110   content::RenderView::ForEach(&accumulator);
    111   CHECK_LE(accumulator.views().size(), 1u);
    112   if (accumulator.views().size() == 0)
    113     return NULL;
    114   return accumulator.views()[0];
    115 }
    116 
    117 ExtensionHelper::ExtensionHelper(content::RenderView* render_view,
    118                                  Dispatcher* dispatcher)
    119     : content::RenderViewObserver(render_view),
    120       content::RenderViewObserverTracker<ExtensionHelper>(render_view),
    121       dispatcher_(dispatcher),
    122       view_type_(VIEW_TYPE_INVALID),
    123       tab_id_(-1),
    124       browser_window_id_(-1) {
    125 }
    126 
    127 ExtensionHelper::~ExtensionHelper() {
    128 }
    129 
    130 bool ExtensionHelper::OnMessageReceived(const IPC::Message& message) {
    131   bool handled = true;
    132   IPC_BEGIN_MESSAGE_MAP(ExtensionHelper, message)
    133     IPC_MESSAGE_HANDLER(ExtensionMsg_Response, OnExtensionResponse)
    134     IPC_MESSAGE_HANDLER(ExtensionMsg_MessageInvoke, OnExtensionMessageInvoke)
    135     IPC_MESSAGE_HANDLER(ExtensionMsg_DispatchOnConnect,
    136                         OnExtensionDispatchOnConnect)
    137     IPC_MESSAGE_HANDLER(ExtensionMsg_DeliverMessage, OnExtensionDeliverMessage)
    138     IPC_MESSAGE_HANDLER(ExtensionMsg_DispatchOnDisconnect,
    139                         OnExtensionDispatchOnDisconnect)
    140     IPC_MESSAGE_HANDLER(ExtensionMsg_SetFrameName, OnSetFrameName)
    141     IPC_MESSAGE_HANDLER(ExtensionMsg_SetTabId, OnSetTabId)
    142     IPC_MESSAGE_HANDLER(ExtensionMsg_UpdateBrowserWindowId,
    143                         OnUpdateBrowserWindowId)
    144     IPC_MESSAGE_HANDLER(ExtensionMsg_NotifyRenderViewType,
    145                         OnNotifyRendererViewType)
    146     IPC_MESSAGE_HANDLER(ExtensionMsg_AddMessageToConsole,
    147                         OnAddMessageToConsole)
    148     IPC_MESSAGE_HANDLER(ExtensionMsg_AppWindowClosed,
    149                         OnAppWindowClosed)
    150     IPC_MESSAGE_UNHANDLED(handled = false)
    151   IPC_END_MESSAGE_MAP()
    152   return handled;
    153 }
    154 
    155 void ExtensionHelper::DidCreateDocumentElement(WebLocalFrame* frame) {
    156   dispatcher_->DidCreateDocumentElement(frame);
    157 }
    158 
    159 void ExtensionHelper::DraggableRegionsChanged(blink::WebFrame* frame) {
    160   blink::WebVector<blink::WebDraggableRegion> webregions =
    161       frame->document().draggableRegions();
    162   std::vector<DraggableRegion> regions;
    163   for (size_t i = 0; i < webregions.size(); ++i) {
    164     DraggableRegion region;
    165     region.bounds = webregions[i].bounds;
    166     region.draggable = webregions[i].draggable;
    167     regions.push_back(region);
    168   }
    169   Send(new ExtensionHostMsg_UpdateDraggableRegions(routing_id(), regions));
    170 }
    171 
    172 void ExtensionHelper::DidMatchCSS(
    173     blink::WebLocalFrame* frame,
    174     const blink::WebVector<blink::WebString>& newly_matching_selectors,
    175     const blink::WebVector<blink::WebString>& stopped_matching_selectors) {
    176   dispatcher_->DidMatchCSS(
    177       frame, newly_matching_selectors, stopped_matching_selectors);
    178 }
    179 
    180 void ExtensionHelper::OnExtensionResponse(int request_id,
    181                                           bool success,
    182                                           const base::ListValue& response,
    183                                           const std::string& error) {
    184   dispatcher_->OnExtensionResponse(request_id,
    185                                    success,
    186                                    response,
    187                                    error);
    188 }
    189 
    190 void ExtensionHelper::OnExtensionMessageInvoke(const std::string& extension_id,
    191                                                const std::string& module_name,
    192                                                const std::string& function_name,
    193                                                const base::ListValue& args,
    194                                                bool user_gesture) {
    195   dispatcher_->InvokeModuleSystemMethod(
    196       render_view(), extension_id, module_name, function_name, args,
    197       user_gesture);
    198 }
    199 
    200 void ExtensionHelper::OnExtensionDispatchOnConnect(
    201     int target_port_id,
    202     const std::string& channel_name,
    203     const base::DictionaryValue& source_tab,
    204     const ExtensionMsg_ExternalConnectionInfo& info,
    205     const std::string& tls_channel_id) {
    206   MessagingBindings::DispatchOnConnect(dispatcher_->script_context_set(),
    207                                        target_port_id,
    208                                        channel_name,
    209                                        source_tab,
    210                                        info,
    211                                        tls_channel_id,
    212                                        render_view());
    213 }
    214 
    215 void ExtensionHelper::OnExtensionDeliverMessage(int target_id,
    216                                                 const Message& message) {
    217   MessagingBindings::DeliverMessage(
    218       dispatcher_->script_context_set(), target_id, message, render_view());
    219 }
    220 
    221 void ExtensionHelper::OnExtensionDispatchOnDisconnect(
    222     int port_id,
    223     const std::string& error_message) {
    224   MessagingBindings::DispatchOnDisconnect(
    225       dispatcher_->script_context_set(), port_id, error_message, render_view());
    226 }
    227 
    228 void ExtensionHelper::OnNotifyRendererViewType(ViewType type) {
    229   view_type_ = type;
    230 }
    231 
    232 void ExtensionHelper::OnSetFrameName(const std::string& name) {
    233   blink::WebView* web_view = render_view()->GetWebView();
    234   if (web_view)
    235     web_view->mainFrame()->setName(blink::WebString::fromUTF8(name));
    236 }
    237 
    238 void ExtensionHelper::OnSetTabId(int init_tab_id) {
    239   CHECK_EQ(tab_id_, -1);
    240   CHECK_GE(init_tab_id, 0);
    241   tab_id_ = init_tab_id;
    242 }
    243 
    244 void ExtensionHelper::OnUpdateBrowserWindowId(int window_id) {
    245   browser_window_id_ = window_id;
    246 }
    247 
    248 void ExtensionHelper::OnAddMessageToConsole(ConsoleMessageLevel level,
    249                                             const std::string& message) {
    250   console::AddMessage(render_view(), level, message);
    251 }
    252 
    253 void ExtensionHelper::OnAppWindowClosed() {
    254   v8::HandleScope scope(v8::Isolate::GetCurrent());
    255   v8::Handle<v8::Context> v8_context =
    256       render_view()->GetWebView()->mainFrame()->mainWorldScriptContext();
    257   ScriptContext* script_context =
    258       dispatcher_->script_context_set().GetByV8Context(v8_context);
    259   if (!script_context)
    260     return;
    261   script_context->module_system()->CallModuleMethod("app.window",
    262                                                     "onAppWindowClosed");
    263 }
    264 
    265 }  // namespace extensions
    266