Home | History | Annotate | Download | only in guestview
      1 // Copyright 2013 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/browser/guestview/guestview.h"
      6 
      7 #include "base/lazy_instance.h"
      8 #include "chrome/browser/extensions/event_router.h"
      9 #include "chrome/browser/guestview/guestview_constants.h"
     10 #include "chrome/browser/profiles/profile.h"
     11 #include "content/public/browser/render_process_host.h"
     12 #include "content/public/browser/web_contents.h"
     13 
     14 using content::WebContents;
     15 
     16 namespace {
     17 
     18 // <embedder_process_id, guest_instance_id> => GuestView*
     19 typedef std::map<std::pair<int, int>, GuestView*> EmbedderGuestViewMap;
     20 static base::LazyInstance<EmbedderGuestViewMap> embedder_guestview_map =
     21     LAZY_INSTANCE_INITIALIZER;
     22 
     23 typedef std::map<WebContents*, GuestView*> WebContentsGuestViewMap;
     24 static base::LazyInstance<WebContentsGuestViewMap> webcontents_guestview_map =
     25     LAZY_INSTANCE_INITIALIZER;
     26 
     27 }  // namespace
     28 
     29 GuestView::Event::Event(const std::string& event_name,
     30                         scoped_ptr<DictionaryValue> args)
     31     : event_name_(event_name),
     32       args_(args.Pass()) {
     33 }
     34 
     35 GuestView::Event::~Event() {
     36 }
     37 
     38 scoped_ptr<DictionaryValue> GuestView::Event::GetArguments() {
     39   return args_.Pass();
     40 }
     41 
     42 GuestView::GuestView(WebContents* guest_web_contents)
     43     : guest_web_contents_(guest_web_contents),
     44       embedder_web_contents_(NULL),
     45       embedder_render_process_id_(0),
     46       browser_context_(guest_web_contents->GetBrowserContext()),
     47       guest_instance_id_(guest_web_contents->GetEmbeddedInstanceID()),
     48       view_instance_id_(guestview::kInstanceIDNone) {
     49   webcontents_guestview_map.Get().insert(
     50       std::make_pair(guest_web_contents, this));
     51 }
     52 
     53 // static
     54 GuestView* GuestView::FromWebContents(WebContents* web_contents) {
     55   WebContentsGuestViewMap* guest_map = webcontents_guestview_map.Pointer();
     56   WebContentsGuestViewMap::iterator it = guest_map->find(web_contents);
     57   return it == guest_map->end() ? NULL : it->second;
     58 }
     59 
     60 // static
     61 GuestView* GuestView::From(int embedder_process_id, int guest_instance_id) {
     62   EmbedderGuestViewMap* guest_map = embedder_guestview_map.Pointer();
     63   EmbedderGuestViewMap::iterator it = guest_map->find(
     64       std::make_pair(embedder_process_id, guest_instance_id));
     65   return it == guest_map->end() ? NULL : it->second;
     66 }
     67 
     68 void GuestView::Attach(content::WebContents* embedder_web_contents,
     69                        const std::string& extension_id,
     70                        const base::DictionaryValue& args) {
     71   embedder_web_contents_ = embedder_web_contents;
     72   embedder_render_process_id_ =
     73       embedder_web_contents->GetRenderProcessHost()->GetID();
     74   extension_id_ = extension_id;
     75   args.GetInteger(guestview::kParameterInstanceId, &view_instance_id_);
     76 
     77   std::pair<int, int> key(embedder_render_process_id_, guest_instance_id_);
     78   embedder_guestview_map.Get().insert(std::make_pair(key, this));
     79 
     80   // GuestView::Attach is called prior to initialization (and initial
     81   // navigation) of the guest in the content layer in order to permit mapping
     82   // the necessary associations between the <*view> element and its guest. This
     83   // is needed by the <webview> WebRequest API to allow intercepting resource
     84   // requests during navigation. However, queued events should be fired after
     85   // content layer initialization in order to ensure that load events (such as
     86   // 'loadstop') fire in embedder after the contentWindow is available.
     87   base::MessageLoop::current()->PostTask(
     88       FROM_HERE,
     89       base::Bind(&GuestView::SendQueuedEvents,
     90                   base::Unretained(this)));
     91 }
     92 
     93 GuestView::Type GuestView::GetViewType() const {
     94   return GuestView::UNKNOWN;
     95 }
     96 
     97 WebViewGuest* GuestView::AsWebView() {
     98   return NULL;
     99 }
    100 
    101 AdViewGuest* GuestView::AsAdView() {
    102   return NULL;
    103 }
    104 
    105 GuestView::~GuestView() {
    106   std::pair<int, int> key(embedder_render_process_id_, guest_instance_id_);
    107   embedder_guestview_map.Get().erase(key);
    108 
    109   webcontents_guestview_map.Get().erase(guest_web_contents());
    110 
    111   while (!pending_events_.empty()) {
    112     delete pending_events_.front();
    113     pending_events_.pop();
    114   }
    115 }
    116 
    117 void GuestView::DispatchEvent(Event* event) {
    118   if (!attached()) {
    119     pending_events_.push(event);
    120     return;
    121   }
    122 
    123   Profile* profile = Profile::FromBrowserContext(browser_context_);
    124 
    125   extensions::EventFilteringInfo info;
    126   info.SetURL(GURL());
    127   info.SetInstanceID(guest_instance_id_);
    128   scoped_ptr<ListValue> args(new ListValue());
    129   args->Append(event->GetArguments().release());
    130 
    131   extensions::EventRouter::DispatchEvent(
    132       embedder_web_contents_, profile, extension_id_,
    133       event->event_name(), args.Pass(),
    134       extensions::EventRouter::USER_GESTURE_UNKNOWN, info);
    135 
    136   delete event;
    137 }
    138 
    139 void GuestView::SendQueuedEvents() {
    140   if (!attached())
    141     return;
    142 
    143   while (!pending_events_.empty()) {
    144     Event* event = pending_events_.front();
    145     pending_events_.pop();
    146     DispatchEvent(event);
    147   }
    148 }
    149