Explicitly add python-numpy dependency to install-build-deps.
[chromium-blink-merge.git] / extensions / browser / guest_view / guest_view_base.cc
blob64d1ac14c50eb6499afa3e4822aaab7ddb542e19
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.
5 #include "extensions/browser/guest_view/guest_view_base.h"
7 #include "base/lazy_instance.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "content/public/browser/navigation_details.h"
10 #include "content/public/browser/render_frame_host.h"
11 #include "content/public/browser/render_process_host.h"
12 #include "content/public/browser/render_view_host.h"
13 #include "content/public/browser/web_contents.h"
14 #include "content/public/common/url_constants.h"
15 #include "extensions/browser/api/extensions_api_client.h"
16 #include "extensions/browser/event_router.h"
17 #include "extensions/browser/extension_registry.h"
18 #include "extensions/browser/guest_view/app_view/app_view_guest.h"
19 #include "extensions/browser/guest_view/extension_options/extension_options_guest.h"
20 #include "extensions/browser/guest_view/guest_view_manager.h"
21 #include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h"
22 #include "extensions/browser/guest_view/web_view/web_view_guest.h"
23 #include "extensions/browser/process_map.h"
24 #include "extensions/common/extension_messages.h"
25 #include "extensions/common/features/feature.h"
26 #include "extensions/common/features/feature_provider.h"
27 #include "extensions/common/guest_view/guest_view_constants.h"
28 #include "third_party/WebKit/public/web/WebInputEvent.h"
30 using content::WebContents;
32 namespace content {
33 struct FrameNavigateParams;
36 namespace extensions {
38 namespace {
40 typedef std::map<std::string, GuestViewBase::GuestCreationCallback>
41 GuestViewCreationMap;
42 static base::LazyInstance<GuestViewCreationMap> guest_view_registry =
43 LAZY_INSTANCE_INITIALIZER;
45 typedef std::map<WebContents*, GuestViewBase*> WebContentsGuestViewMap;
46 static base::LazyInstance<WebContentsGuestViewMap> webcontents_guestview_map =
47 LAZY_INSTANCE_INITIALIZER;
49 } // namespace
51 GuestViewBase::Event::Event(const std::string& name,
52 scoped_ptr<base::DictionaryValue> args)
53 : name_(name), args_(args.Pass()) {
56 GuestViewBase::Event::~Event() {
59 scoped_ptr<base::DictionaryValue> GuestViewBase::Event::GetArguments() {
60 return args_.Pass();
63 // This observer ensures that the GuestViewBase destroys itself when its
64 // embedder goes away.
65 class GuestViewBase::EmbedderLifetimeObserver : public WebContentsObserver {
66 public:
67 EmbedderLifetimeObserver(GuestViewBase* guest,
68 content::WebContents* embedder_web_contents)
69 : WebContentsObserver(embedder_web_contents),
70 destroyed_(false),
71 guest_(guest) {}
73 ~EmbedderLifetimeObserver() override {}
75 // WebContentsObserver implementation.
76 void WebContentsDestroyed() override {
77 // If the embedder is destroyed then destroy the guest.
78 Destroy();
81 void DidNavigateMainFrame(
82 const content::LoadCommittedDetails& details,
83 const content::FrameNavigateParams& params) override {
84 // If the embedder navigates to a different page then destroy the guest.
85 if (details.is_navigation_to_different_page())
86 Destroy();
89 void RenderProcessGone(base::TerminationStatus status) override {
90 // If the embedder crashes, then destroy the guest.
91 Destroy();
94 private:
95 bool destroyed_;
96 GuestViewBase* guest_;
98 void Destroy() {
99 if (destroyed_)
100 return;
102 destroyed_ = true;
103 guest_->EmbedderWillBeDestroyed();
104 guest_->embedder_web_contents_ = NULL;
105 guest_->Destroy();
108 DISALLOW_COPY_AND_ASSIGN(EmbedderLifetimeObserver);
111 // This observer ensures that the GuestViewBase destroys itself when its
112 // embedder goes away.
113 class GuestViewBase::OpenerLifetimeObserver : public WebContentsObserver {
114 public:
115 OpenerLifetimeObserver(GuestViewBase* guest)
116 : WebContentsObserver(guest->GetOpener()->web_contents()),
117 guest_(guest) {}
119 ~OpenerLifetimeObserver() override {}
121 // WebContentsObserver implementation.
122 void WebContentsDestroyed() override {
123 if (guest_->attached())
124 return;
126 // If the opener is destroyed then destroy the guest.
127 guest_->Destroy();
130 private:
131 GuestViewBase* guest_;
133 DISALLOW_COPY_AND_ASSIGN(OpenerLifetimeObserver);
136 GuestViewBase::GuestViewBase(content::BrowserContext* browser_context,
137 int guest_instance_id)
138 : embedder_web_contents_(NULL),
139 embedder_render_process_id_(0),
140 browser_context_(browser_context),
141 guest_instance_id_(guest_instance_id),
142 view_instance_id_(guestview::kInstanceIDNone),
143 element_instance_id_(guestview::kInstanceIDNone),
144 initialized_(false),
145 is_being_destroyed_(false),
146 auto_size_enabled_(false),
147 weak_ptr_factory_(this) {
150 void GuestViewBase::Init(const std::string& embedder_extension_id,
151 content::WebContents* embedder_web_contents,
152 const base::DictionaryValue& create_params,
153 const WebContentsCreatedCallback& callback) {
154 if (initialized_)
155 return;
156 initialized_ = true;
158 Feature* feature = FeatureProvider::GetAPIFeatures()->GetFeature(
159 GetAPINamespace());
160 CHECK(feature);
162 ProcessMap* process_map = ProcessMap::Get(browser_context());
163 CHECK(process_map);
165 const Extension* embedder_extension = ExtensionRegistry::Get(browser_context_)
166 ->enabled_extensions()
167 .GetByID(embedder_extension_id);
168 // Ok for |embedder_extension| to be NULL, the embedder might be WebUI.
170 CHECK(embedder_web_contents);
171 int embedder_process_id =
172 embedder_web_contents->GetRenderProcessHost()->GetID();
174 const GURL& embedder_site_url = embedder_web_contents->GetLastCommittedURL();
175 Feature::Availability availability = feature->IsAvailableToContext(
176 embedder_extension,
177 process_map->GetMostLikelyContextType(embedder_extension,
178 embedder_process_id),
179 embedder_site_url);
180 if (!availability.is_available()) {
181 // The derived class did not create a WebContents so this class serves no
182 // purpose. Let's self-destruct.
183 delete this;
184 callback.Run(NULL);
185 return;
188 CreateWebContents(embedder_extension_id,
189 embedder_process_id,
190 embedder_site_url,
191 create_params,
192 base::Bind(&GuestViewBase::CompleteInit,
193 weak_ptr_factory_.GetWeakPtr(),
194 embedder_extension_id,
195 embedder_web_contents,
196 callback));
199 void GuestViewBase::InitWithWebContents(
200 const std::string& embedder_extension_id,
201 content::WebContents* embedder_web_contents,
202 content::WebContents* guest_web_contents) {
203 DCHECK(guest_web_contents);
204 DCHECK(embedder_web_contents);
205 int embedder_render_process_id =
206 embedder_web_contents->GetRenderProcessHost()->GetID();
207 content::RenderProcessHost* embedder_render_process_host =
208 content::RenderProcessHost::FromID(embedder_render_process_id);
210 embedder_extension_id_ = embedder_extension_id;
211 embedder_render_process_id_ = embedder_render_process_host->GetID();
213 // At this point, we have just created the guest WebContents, we need to add
214 // an observer to the embedder WebContents. This observer will be responsible
215 // for destroying the guest WebContents if the embedder goes away.
216 embedder_lifetime_observer_.reset(
217 new EmbedderLifetimeObserver(this, embedder_web_contents));
219 WebContentsObserver::Observe(guest_web_contents);
220 guest_web_contents->SetDelegate(this);
221 webcontents_guestview_map.Get().insert(
222 std::make_pair(guest_web_contents, this));
223 GuestViewManager::FromBrowserContext(browser_context_)->
224 AddGuest(guest_instance_id_, guest_web_contents);
226 // Give the derived class an opportunity to perform additional initialization.
227 DidInitialize();
230 void GuestViewBase::SetAutoSize(bool enabled,
231 const gfx::Size& min_size,
232 const gfx::Size& max_size) {
233 min_auto_size_ = min_size;
234 min_auto_size_.SetToMin(max_size);
235 max_auto_size_ = max_size;
236 max_auto_size_.SetToMax(min_size);
238 enabled &= !min_auto_size_.IsEmpty() && !max_auto_size_.IsEmpty() &&
239 IsAutoSizeSupported();
240 if (!enabled && !auto_size_enabled_)
241 return;
243 auto_size_enabled_ = enabled;
245 if (!attached())
246 return;
248 content::RenderViewHost* rvh = web_contents()->GetRenderViewHost();
249 if (auto_size_enabled_) {
250 rvh->EnableAutoResize(min_auto_size_, max_auto_size_);
251 } else {
252 rvh->DisableAutoResize(element_size_);
253 guest_size_ = element_size_;
254 GuestSizeChangedDueToAutoSize(guest_size_, element_size_);
258 // static
259 void GuestViewBase::RegisterGuestViewType(
260 const std::string& view_type,
261 const GuestCreationCallback& callback) {
262 GuestViewCreationMap::iterator it =
263 guest_view_registry.Get().find(view_type);
264 DCHECK(it == guest_view_registry.Get().end());
265 guest_view_registry.Get()[view_type] = callback;
268 // static
269 GuestViewBase* GuestViewBase::Create(
270 content::BrowserContext* browser_context,
271 int guest_instance_id,
272 const std::string& view_type) {
273 if (guest_view_registry.Get().empty())
274 RegisterGuestViewTypes();
276 GuestViewCreationMap::iterator it =
277 guest_view_registry.Get().find(view_type);
278 if (it == guest_view_registry.Get().end()) {
279 NOTREACHED();
280 return NULL;
282 return it->second.Run(browser_context, guest_instance_id);
285 // static
286 GuestViewBase* GuestViewBase::FromWebContents(WebContents* web_contents) {
287 WebContentsGuestViewMap* guest_map = webcontents_guestview_map.Pointer();
288 WebContentsGuestViewMap::iterator it = guest_map->find(web_contents);
289 return it == guest_map->end() ? NULL : it->second;
292 // static
293 GuestViewBase* GuestViewBase::From(int embedder_process_id,
294 int guest_instance_id) {
295 content::RenderProcessHost* host =
296 content::RenderProcessHost::FromID(embedder_process_id);
297 if (!host)
298 return NULL;
300 content::WebContents* guest_web_contents =
301 GuestViewManager::FromBrowserContext(host->GetBrowserContext())->
302 GetGuestByInstanceIDSafely(guest_instance_id, embedder_process_id);
303 if (!guest_web_contents)
304 return NULL;
306 return GuestViewBase::FromWebContents(guest_web_contents);
309 // static
310 bool GuestViewBase::IsGuest(WebContents* web_contents) {
311 return !!GuestViewBase::FromWebContents(web_contents);
314 bool GuestViewBase::IsAutoSizeSupported() const {
315 return false;
318 bool GuestViewBase::IsDragAndDropEnabled() const {
319 return false;
322 void GuestViewBase::DidAttach(int guest_proxy_routing_id) {
323 opener_lifetime_observer_.reset();
325 // Give the derived class an opportunity to perform some actions.
326 DidAttachToEmbedder();
328 // Inform the associated GuestViewContainer that the contentWindow is ready.
329 embedder_web_contents()->Send(new ExtensionMsg_GuestAttached(
330 embedder_web_contents()->GetMainFrame()->GetRoutingID(),
331 element_instance_id_,
332 guest_proxy_routing_id));
334 SendQueuedEvents();
337 void GuestViewBase::ElementSizeChanged(const gfx::Size& old_size,
338 const gfx::Size& new_size) {
339 element_size_ = new_size;
342 void GuestViewBase::GuestSizeChanged(const gfx::Size& old_size,
343 const gfx::Size& new_size) {
344 if (!auto_size_enabled_)
345 return;
346 guest_size_ = new_size;
347 GuestSizeChangedDueToAutoSize(old_size, new_size);
350 void GuestViewBase::Destroy() {
351 if (is_being_destroyed_)
352 return;
354 is_being_destroyed_ = true;
356 DCHECK(web_contents());
358 // Give the derived class an opportunity to perform some cleanup.
359 WillDestroy();
361 // Invalidate weak pointers now so that bound callbacks cannot be called late
362 // into destruction. We must call this after WillDestroy because derived types
363 // may wish to access their openers.
364 weak_ptr_factory_.InvalidateWeakPtrs();
366 // Give the content module an opportunity to perform some cleanup.
367 if (!destruction_callback_.is_null())
368 destruction_callback_.Run();
370 webcontents_guestview_map.Get().erase(web_contents());
371 GuestViewManager::FromBrowserContext(browser_context_)->
372 RemoveGuest(guest_instance_id_);
373 pending_events_.clear();
375 delete web_contents();
378 void GuestViewBase::SetAttachParams(const base::DictionaryValue& params) {
379 attach_params_.reset(params.DeepCopy());
380 attach_params_->GetInteger(guestview::kParameterInstanceId,
381 &view_instance_id_);
384 void GuestViewBase::SetOpener(GuestViewBase* guest) {
385 if (guest && guest->IsViewType(GetViewType())) {
386 opener_ = guest->weak_ptr_factory_.GetWeakPtr();
387 if (!attached())
388 opener_lifetime_observer_.reset(new OpenerLifetimeObserver(this));
389 return;
391 opener_ = base::WeakPtr<GuestViewBase>();
392 opener_lifetime_observer_.reset();
395 void GuestViewBase::RegisterDestructionCallback(
396 const DestructionCallback& callback) {
397 destruction_callback_ = callback;
400 void GuestViewBase::WillAttach(content::WebContents* embedder_web_contents,
401 int element_instance_id) {
402 embedder_web_contents_ = embedder_web_contents;
404 // If we are attaching to a different WebContents than the one that created
405 // the guest, we need to create a new LifetimeObserver.
406 if (embedder_web_contents != embedder_lifetime_observer_->web_contents()) {
407 embedder_lifetime_observer_.reset(
408 new EmbedderLifetimeObserver(this, embedder_web_contents));
411 element_instance_id_ = element_instance_id;
413 WillAttachToEmbedder();
416 void GuestViewBase::DidStopLoading(content::RenderViewHost* render_view_host) {
417 if (!IsDragAndDropEnabled()) {
418 const char script[] = "window.addEventListener('dragstart', function() { "
419 " window.event.preventDefault(); "
420 "});";
421 render_view_host->GetMainFrame()->ExecuteJavaScript(
422 base::ASCIIToUTF16(script));
424 DidStopLoading();
427 void GuestViewBase::RenderViewReady() {
428 GuestReady();
431 void GuestViewBase::WebContentsDestroyed() {
432 // Let the derived class know that its WebContents is in the process of
433 // being destroyed. web_contents() is still valid at this point.
434 // TODO(fsamuel): This allows for reentrant code into WebContents during
435 // destruction. This could potentially lead to bugs. Perhaps we should get rid
436 // of this?
437 GuestDestroyed();
439 // Self-destruct.
440 delete this;
443 void GuestViewBase::ActivateContents(WebContents* web_contents) {
444 if (!attached() || !embedder_web_contents()->GetDelegate())
445 return;
447 embedder_web_contents()->GetDelegate()->ActivateContents(
448 embedder_web_contents());
451 void GuestViewBase::DeactivateContents(WebContents* web_contents) {
452 if (!attached() || !embedder_web_contents()->GetDelegate())
453 return;
455 embedder_web_contents()->GetDelegate()->DeactivateContents(
456 embedder_web_contents());
459 void GuestViewBase::RunFileChooser(WebContents* web_contents,
460 const content::FileChooserParams& params) {
461 if (!attached() || !embedder_web_contents()->GetDelegate())
462 return;
464 embedder_web_contents()->GetDelegate()->RunFileChooser(web_contents, params);
467 bool GuestViewBase::ShouldFocusPageAfterCrash() {
468 // Focus is managed elsewhere.
469 return false;
472 bool GuestViewBase::PreHandleGestureEvent(content::WebContents* source,
473 const blink::WebGestureEvent& event) {
474 return event.type == blink::WebGestureEvent::GesturePinchBegin ||
475 event.type == blink::WebGestureEvent::GesturePinchUpdate ||
476 event.type == blink::WebGestureEvent::GesturePinchEnd;
479 GuestViewBase::~GuestViewBase() {
482 void GuestViewBase::DispatchEventToEmbedder(Event* event) {
483 scoped_ptr<Event> event_ptr(event);
485 if (!attached()) {
486 pending_events_.push_back(linked_ptr<Event>(event_ptr.release()));
487 return;
490 EventFilteringInfo info;
491 info.SetInstanceID(view_instance_id_);
492 scoped_ptr<base::ListValue> args(new base::ListValue());
493 args->Append(event->GetArguments().release());
495 EventRouter::DispatchEvent(
496 embedder_web_contents_,
497 browser_context_,
498 embedder_extension_id_,
499 event->name(),
500 args.Pass(),
501 EventRouter::USER_GESTURE_UNKNOWN,
502 info);
505 void GuestViewBase::SendQueuedEvents() {
506 if (!attached())
507 return;
508 while (!pending_events_.empty()) {
509 linked_ptr<Event> event_ptr = pending_events_.front();
510 pending_events_.pop_front();
511 DispatchEventToEmbedder(event_ptr.release());
515 void GuestViewBase::CompleteInit(const std::string& embedder_extension_id,
516 content::WebContents* embedder_web_contents,
517 const WebContentsCreatedCallback& callback,
518 content::WebContents* guest_web_contents) {
519 if (!guest_web_contents) {
520 // The derived class did not create a WebContents so this class serves no
521 // purpose. Let's self-destruct.
522 delete this;
523 callback.Run(NULL);
524 return;
526 InitWithWebContents(
527 embedder_extension_id, embedder_web_contents, guest_web_contents);
528 callback.Run(guest_web_contents);
531 // static
532 void GuestViewBase::RegisterGuestViewTypes() {
533 AppViewGuest::Register();
534 ExtensionOptionsGuest::Register();
535 MimeHandlerViewGuest::Register();
536 WebViewGuest::Register();
539 } // namespace extensions