• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "chrome/browser/guest_view/guest_view_base.h"
6 
7 #include "base/lazy_instance.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "chrome/browser/guest_view/guest_view_constants.h"
10 #include "chrome/browser/guest_view/guest_view_manager.h"
11 #include "chrome/browser/guest_view/web_view/web_view_guest.h"
12 #include "chrome/browser/profiles/profile.h"
13 #include "chrome/common/content_settings.h"
14 #include "content/public/browser/render_frame_host.h"
15 #include "content/public/browser/render_process_host.h"
16 #include "content/public/browser/render_view_host.h"
17 #include "content/public/browser/web_contents.h"
18 #include "content/public/common/url_constants.h"
19 #include "extensions/browser/event_router.h"
20 #include "third_party/WebKit/public/web/WebInputEvent.h"
21 
22 using content::WebContents;
23 
24 namespace {
25 
26 typedef std::map<WebContents*, GuestViewBase*> WebContentsGuestViewMap;
27 static base::LazyInstance<WebContentsGuestViewMap> webcontents_guestview_map =
28     LAZY_INSTANCE_INITIALIZER;
29 
30 }  // namespace
31 
Event(const std::string & name,scoped_ptr<base::DictionaryValue> args)32 GuestViewBase::Event::Event(const std::string& name,
33                             scoped_ptr<base::DictionaryValue> args)
34     : name_(name), args_(args.Pass()) {
35 }
36 
~Event()37 GuestViewBase::Event::~Event() {
38 }
39 
GetArguments()40 scoped_ptr<base::DictionaryValue> GuestViewBase::Event::GetArguments() {
41   return args_.Pass();
42 }
43 
44 // This observer ensures that the GuestViewBase destroys itself when its
45 // embedder goes away.
46 class GuestViewBase::EmbedderWebContentsObserver : public WebContentsObserver {
47  public:
EmbedderWebContentsObserver(GuestViewBase * guest)48   explicit EmbedderWebContentsObserver(GuestViewBase* guest)
49       : WebContentsObserver(guest->embedder_web_contents()),
50         guest_(guest) {
51   }
52 
~EmbedderWebContentsObserver()53   virtual ~EmbedderWebContentsObserver() {
54   }
55 
56   // WebContentsObserver implementation.
WebContentsDestroyed()57   virtual void WebContentsDestroyed() OVERRIDE {
58     guest_->embedder_web_contents_ = NULL;
59     guest_->EmbedderDestroyed();
60     guest_->Destroy();
61   }
62 
63  private:
64   GuestViewBase* guest_;
65 
66   DISALLOW_COPY_AND_ASSIGN(EmbedderWebContentsObserver);
67 };
68 
GuestViewBase(int guest_instance_id)69 GuestViewBase::GuestViewBase(int guest_instance_id)
70     : embedder_web_contents_(NULL),
71       embedder_render_process_id_(0),
72       browser_context_(NULL),
73       guest_instance_id_(guest_instance_id),
74       view_instance_id_(guestview::kInstanceIDNone),
75       initialized_(false),
76       weak_ptr_factory_(this) {
77 }
78 
Init(WebContents * guest_web_contents,const std::string & embedder_extension_id)79 void GuestViewBase::Init(WebContents* guest_web_contents,
80                          const std::string& embedder_extension_id) {
81   if (initialized_)
82     return;
83   initialized_ = true;
84   browser_context_ = guest_web_contents->GetBrowserContext();
85   embedder_extension_id_ = embedder_extension_id;
86 
87   WebContentsObserver::Observe(guest_web_contents);
88   guest_web_contents->SetDelegate(this);
89   webcontents_guestview_map.Get().insert(
90       std::make_pair(guest_web_contents, this));
91   GuestViewManager::FromBrowserContext(browser_context_)->
92       AddGuest(guest_instance_id_, guest_web_contents);
93 }
94 
95 // static
Create(int guest_instance_id,WebContents * guest_web_contents,const std::string & embedder_extension_id,const std::string & view_type)96 GuestViewBase* GuestViewBase::Create(
97     int guest_instance_id,
98     WebContents* guest_web_contents,
99     const std::string& embedder_extension_id,
100     const std::string& view_type) {
101   if (view_type == "webview") {
102     return new WebViewGuest(guest_instance_id,
103                             guest_web_contents,
104                             embedder_extension_id);
105   }
106   NOTREACHED();
107   return NULL;
108 }
109 
110 // static
FromWebContents(WebContents * web_contents)111 GuestViewBase* GuestViewBase::FromWebContents(WebContents* web_contents) {
112   WebContentsGuestViewMap* guest_map = webcontents_guestview_map.Pointer();
113   WebContentsGuestViewMap::iterator it = guest_map->find(web_contents);
114   return it == guest_map->end() ? NULL : it->second;
115 }
116 
117 // static
From(int embedder_process_id,int guest_instance_id)118 GuestViewBase* GuestViewBase::From(int embedder_process_id,
119                                    int guest_instance_id) {
120   content::RenderProcessHost* host =
121       content::RenderProcessHost::FromID(embedder_process_id);
122   if (!host)
123     return NULL;
124 
125   content::WebContents* guest_web_contents =
126       GuestViewManager::FromBrowserContext(host->GetBrowserContext())->
127           GetGuestByInstanceIDSafely(guest_instance_id, embedder_process_id);
128   if (!guest_web_contents)
129     return NULL;
130 
131   return GuestViewBase::FromWebContents(guest_web_contents);
132 }
133 
134 // static
IsGuest(WebContents * web_contents)135 bool GuestViewBase::IsGuest(WebContents* web_contents) {
136   return !!GuestViewBase::FromWebContents(web_contents);
137 }
138 
139 // static
GetDefaultContentSettingRules(RendererContentSettingRules * rules,bool incognito)140 void GuestViewBase::GetDefaultContentSettingRules(
141     RendererContentSettingRules* rules,
142     bool incognito) {
143   rules->image_rules.push_back(
144       ContentSettingPatternSource(ContentSettingsPattern::Wildcard(),
145                                   ContentSettingsPattern::Wildcard(),
146                                   CONTENT_SETTING_ALLOW,
147                                   std::string(),
148                                   incognito));
149 
150   rules->script_rules.push_back(
151       ContentSettingPatternSource(ContentSettingsPattern::Wildcard(),
152                                   ContentSettingsPattern::Wildcard(),
153                                   CONTENT_SETTING_ALLOW,
154                                   std::string(),
155                                   incognito));
156 }
157 
AsWeakPtr()158 base::WeakPtr<GuestViewBase> GuestViewBase::AsWeakPtr() {
159   return weak_ptr_factory_.GetWeakPtr();
160 }
161 
IsDragAndDropEnabled() const162 bool GuestViewBase::IsDragAndDropEnabled() const {
163   return false;
164 }
165 
Destroy()166 void GuestViewBase::Destroy() {
167   WillDestroy();
168   if (!destruction_callback_.is_null())
169     destruction_callback_.Run();
170   delete guest_web_contents();
171 }
172 
DidAttach()173 void GuestViewBase::DidAttach() {
174   // Give the derived class an opportunity to perform some actions.
175   DidAttachToEmbedder();
176 
177   SendQueuedEvents();
178 }
179 
SetOpener(GuestViewBase * guest)180 void GuestViewBase::SetOpener(GuestViewBase* guest) {
181   if (guest && guest->IsViewType(GetViewType())) {
182     opener_ = guest->AsWeakPtr();
183     return;
184   }
185   opener_ = base::WeakPtr<GuestViewBase>();
186 }
187 
RegisterDestructionCallback(const DestructionCallback & callback)188 void GuestViewBase::RegisterDestructionCallback(
189     const DestructionCallback& callback) {
190   destruction_callback_ = callback;
191 }
192 
WillAttach(content::WebContents * embedder_web_contents,const base::DictionaryValue & extra_params)193 void GuestViewBase::WillAttach(content::WebContents* embedder_web_contents,
194                                const base::DictionaryValue& extra_params) {
195   embedder_web_contents_ = embedder_web_contents;
196   embedder_web_contents_observer_.reset(
197       new EmbedderWebContentsObserver(this));
198   embedder_render_process_id_ =
199       embedder_web_contents->GetRenderProcessHost()->GetID();
200   extra_params.GetInteger(guestview::kParameterInstanceId, &view_instance_id_);
201   extra_params_.reset(extra_params.DeepCopy());
202 
203   WillAttachToEmbedder();
204 }
205 
DidStopLoading(content::RenderViewHost * render_view_host)206 void GuestViewBase::DidStopLoading(content::RenderViewHost* render_view_host) {
207   if (!IsDragAndDropEnabled()) {
208     const char script[] = "window.addEventListener('dragstart', function() { "
209                           "  window.event.preventDefault(); "
210                           "});";
211     render_view_host->GetMainFrame()->ExecuteJavaScript(
212         base::ASCIIToUTF16(script));
213   }
214   DidStopLoading();
215 }
216 
WebContentsDestroyed()217 void GuestViewBase::WebContentsDestroyed() {
218   GuestDestroyed();
219   delete this;
220 }
221 
ShouldFocusPageAfterCrash()222 bool GuestViewBase::ShouldFocusPageAfterCrash() {
223   // Focus is managed elsewhere.
224   return false;
225 }
226 
PreHandleGestureEvent(content::WebContents * source,const blink::WebGestureEvent & event)227 bool GuestViewBase::PreHandleGestureEvent(content::WebContents* source,
228                                          const blink::WebGestureEvent& event) {
229   return event.type == blink::WebGestureEvent::GesturePinchBegin ||
230       event.type == blink::WebGestureEvent::GesturePinchUpdate ||
231       event.type == blink::WebGestureEvent::GesturePinchEnd;
232 }
233 
~GuestViewBase()234 GuestViewBase::~GuestViewBase() {
235   std::pair<int, int> key(embedder_render_process_id_, guest_instance_id_);
236 
237   webcontents_guestview_map.Get().erase(guest_web_contents());
238 
239   GuestViewManager::FromBrowserContext(browser_context_)->
240       RemoveGuest(guest_instance_id_);
241 
242   pending_events_.clear();
243 }
244 
DispatchEvent(Event * event)245 void GuestViewBase::DispatchEvent(Event* event) {
246   scoped_ptr<Event> event_ptr(event);
247   if (!in_extension()) {
248     NOTREACHED();
249     return;
250   }
251 
252   if (!attached()) {
253     pending_events_.push_back(linked_ptr<Event>(event_ptr.release()));
254     return;
255   }
256 
257   Profile* profile = Profile::FromBrowserContext(browser_context_);
258 
259   extensions::EventFilteringInfo info;
260   info.SetInstanceID(view_instance_id_);
261   scoped_ptr<base::ListValue> args(new base::ListValue());
262   args->Append(event->GetArguments().release());
263 
264   extensions::EventRouter::DispatchEvent(
265       embedder_web_contents_,
266       profile,
267       embedder_extension_id_,
268       event->name(),
269       args.Pass(),
270       extensions::EventRouter::USER_GESTURE_UNKNOWN,
271       info);
272 }
273 
SendQueuedEvents()274 void GuestViewBase::SendQueuedEvents() {
275   if (!attached())
276     return;
277   while (!pending_events_.empty()) {
278     linked_ptr<Event> event_ptr = pending_events_.front();
279     pending_events_.pop_front();
280     DispatchEvent(event_ptr.release());
281   }
282 }
283