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