Add chrome.usb.getConfiguration and expose extra descriptors.
[chromium-blink-merge.git] / extensions / browser / guest_view / guest_view_base.cc
blob1b0effef18fdab97b0221b2e49f8327ea738895f
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/render_frame_host.h"
10 #include "content/public/browser/render_process_host.h"
11 #include "content/public/browser/render_view_host.h"
12 #include "content/public/browser/web_contents.h"
13 #include "content/public/common/url_constants.h"
14 #include "extensions/browser/api/extensions_api_client.h"
15 #include "extensions/browser/event_router.h"
16 #include "extensions/browser/extension_registry.h"
17 #include "extensions/browser/guest_view/app_view/app_view_guest.h"
18 #include "extensions/browser/guest_view/extension_options/extension_options_guest.h"
19 #include "extensions/browser/guest_view/guest_view_constants.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/features/feature.h"
25 #include "extensions/common/features/feature_provider.h"
26 #include "third_party/WebKit/public/web/WebInputEvent.h"
28 using content::WebContents;
30 namespace extensions {
32 namespace {
34 typedef std::map<std::string, GuestViewBase::GuestCreationCallback>
35 GuestViewCreationMap;
36 static base::LazyInstance<GuestViewCreationMap> guest_view_registry =
37 LAZY_INSTANCE_INITIALIZER;
39 typedef std::map<WebContents*, GuestViewBase*> WebContentsGuestViewMap;
40 static base::LazyInstance<WebContentsGuestViewMap> webcontents_guestview_map =
41 LAZY_INSTANCE_INITIALIZER;
43 } // namespace
45 GuestViewBase::Event::Event(const std::string& name,
46 scoped_ptr<base::DictionaryValue> args)
47 : name_(name), args_(args.Pass()) {
50 GuestViewBase::Event::~Event() {
53 scoped_ptr<base::DictionaryValue> GuestViewBase::Event::GetArguments() {
54 return args_.Pass();
57 // This observer ensures that the GuestViewBase destroys itself when its
58 // embedder goes away.
59 class GuestViewBase::EmbedderWebContentsObserver : public WebContentsObserver {
60 public:
61 explicit EmbedderWebContentsObserver(GuestViewBase* guest)
62 : WebContentsObserver(guest->embedder_web_contents()),
63 destroyed_(false),
64 guest_(guest) {
67 virtual ~EmbedderWebContentsObserver() {
70 // WebContentsObserver implementation.
71 virtual void WebContentsDestroyed() OVERRIDE {
72 Destroy();
75 virtual void RenderViewHostChanged(
76 content::RenderViewHost* old_host,
77 content::RenderViewHost* new_host) OVERRIDE {
78 Destroy();
81 virtual void RenderProcessGone(base::TerminationStatus status) OVERRIDE {
82 Destroy();
85 private:
86 bool destroyed_;
87 GuestViewBase* guest_;
89 void Destroy() {
90 if (destroyed_)
91 return;
92 destroyed_ = true;
93 guest_->embedder_web_contents_ = NULL;
94 guest_->EmbedderDestroyed();
95 guest_->Destroy();
98 DISALLOW_COPY_AND_ASSIGN(EmbedderWebContentsObserver);
101 GuestViewBase::GuestViewBase(content::BrowserContext* browser_context,
102 int guest_instance_id)
103 : embedder_web_contents_(NULL),
104 embedder_render_process_id_(0),
105 browser_context_(browser_context),
106 guest_instance_id_(guest_instance_id),
107 view_instance_id_(guestview::kInstanceIDNone),
108 initialized_(false),
109 auto_size_enabled_(false),
110 weak_ptr_factory_(this) {
113 void GuestViewBase::Init(const std::string& embedder_extension_id,
114 content::WebContents* embedder_web_contents,
115 const base::DictionaryValue& create_params,
116 const WebContentsCreatedCallback& callback) {
117 if (initialized_)
118 return;
119 initialized_ = true;
121 Feature* feature = FeatureProvider::GetAPIFeatures()->GetFeature(
122 GetAPINamespace());
123 CHECK(feature);
125 ProcessMap* process_map = ProcessMap::Get(browser_context());
126 CHECK(process_map);
128 const Extension* embedder_extension = ExtensionRegistry::Get(browser_context_)
129 ->enabled_extensions()
130 .GetByID(embedder_extension_id);
131 // Ok for |embedder_extension| to be NULL, the embedder might be WebUI.
133 CHECK(embedder_web_contents);
134 int embedder_process_id =
135 embedder_web_contents->GetRenderProcessHost()->GetID();
137 Feature::Availability availability = feature->IsAvailableToContext(
138 embedder_extension,
139 process_map->GetMostLikelyContextType(embedder_extension,
140 embedder_process_id),
141 embedder_web_contents->GetLastCommittedURL());
142 if (!availability.is_available()) {
143 callback.Run(NULL);
144 return;
147 CreateWebContents(embedder_extension_id,
148 embedder_process_id,
149 create_params,
150 base::Bind(&GuestViewBase::CompleteInit,
151 AsWeakPtr(),
152 embedder_extension_id,
153 embedder_process_id,
154 callback));
157 void GuestViewBase::InitWithWebContents(
158 const std::string& embedder_extension_id,
159 int embedder_render_process_id,
160 content::WebContents* guest_web_contents) {
161 DCHECK(guest_web_contents);
162 content::RenderProcessHost* embedder_render_process_host =
163 content::RenderProcessHost::FromID(embedder_render_process_id);
165 embedder_extension_id_ = embedder_extension_id;
166 embedder_render_process_id_ = embedder_render_process_host->GetID();
167 embedder_render_process_host->AddObserver(this);
169 WebContentsObserver::Observe(guest_web_contents);
170 guest_web_contents->SetDelegate(this);
171 webcontents_guestview_map.Get().insert(
172 std::make_pair(guest_web_contents, this));
173 GuestViewManager::FromBrowserContext(browser_context_)->
174 AddGuest(guest_instance_id_, guest_web_contents);
176 // Give the derived class an opportunity to perform additional initialization.
177 DidInitialize();
180 void GuestViewBase::SetAutoSize(bool enabled,
181 const gfx::Size& min_size,
182 const gfx::Size& max_size) {
183 min_auto_size_ = min_size;
184 min_auto_size_.SetToMin(max_size);
185 max_auto_size_ = max_size;
186 max_auto_size_.SetToMax(min_size);
188 enabled &= !min_auto_size_.IsEmpty() && !max_auto_size_.IsEmpty() &&
189 IsAutoSizeSupported();
190 if (!enabled && !auto_size_enabled_)
191 return;
193 auto_size_enabled_ = enabled;
195 if (!attached())
196 return;
198 content::RenderViewHost* rvh = web_contents()->GetRenderViewHost();
199 if (auto_size_enabled_) {
200 rvh->EnableAutoResize(min_auto_size_, max_auto_size_);
201 } else {
202 rvh->DisableAutoResize(element_size_);
203 guest_size_ = element_size_;
204 GuestSizeChangedDueToAutoSize(guest_size_, element_size_);
208 // static
209 void GuestViewBase::RegisterGuestViewType(
210 const std::string& view_type,
211 const GuestCreationCallback& callback) {
212 GuestViewCreationMap::iterator it =
213 guest_view_registry.Get().find(view_type);
214 DCHECK(it == guest_view_registry.Get().end());
215 guest_view_registry.Get()[view_type] = callback;
218 // static
219 GuestViewBase* GuestViewBase::Create(
220 content::BrowserContext* browser_context,
221 int guest_instance_id,
222 const std::string& view_type) {
223 if (guest_view_registry.Get().empty())
224 RegisterGuestViewTypes();
226 GuestViewCreationMap::iterator it =
227 guest_view_registry.Get().find(view_type);
228 if (it == guest_view_registry.Get().end()) {
229 NOTREACHED();
230 return NULL;
232 return it->second.Run(browser_context, guest_instance_id);
235 // static
236 GuestViewBase* GuestViewBase::FromWebContents(WebContents* web_contents) {
237 WebContentsGuestViewMap* guest_map = webcontents_guestview_map.Pointer();
238 WebContentsGuestViewMap::iterator it = guest_map->find(web_contents);
239 return it == guest_map->end() ? NULL : it->second;
242 // static
243 GuestViewBase* GuestViewBase::From(int embedder_process_id,
244 int guest_instance_id) {
245 content::RenderProcessHost* host =
246 content::RenderProcessHost::FromID(embedder_process_id);
247 if (!host)
248 return NULL;
250 content::WebContents* guest_web_contents =
251 GuestViewManager::FromBrowserContext(host->GetBrowserContext())->
252 GetGuestByInstanceIDSafely(guest_instance_id, embedder_process_id);
253 if (!guest_web_contents)
254 return NULL;
256 return GuestViewBase::FromWebContents(guest_web_contents);
259 // static
260 bool GuestViewBase::IsGuest(WebContents* web_contents) {
261 return !!GuestViewBase::FromWebContents(web_contents);
264 base::WeakPtr<GuestViewBase> GuestViewBase::AsWeakPtr() {
265 return weak_ptr_factory_.GetWeakPtr();
268 bool GuestViewBase::IsAutoSizeSupported() const {
269 return false;
272 bool GuestViewBase::IsDragAndDropEnabled() const {
273 return false;
276 void GuestViewBase::RenderProcessExited(content::RenderProcessHost* host,
277 base::ProcessHandle handle,
278 base::TerminationStatus status,
279 int exit_code) {
280 // GuestViewBase tracks the lifetime of its embedder render process until it
281 // is attached to a particular embedder WebContents. At that point, its
282 // lifetime is restricted in scope to the lifetime of its embedder
283 // WebContents.
284 CHECK(!attached());
285 CHECK_EQ(host->GetID(), embedder_render_process_id());
287 // This code path may be reached if the embedder WebContents is killed for
288 // whatever reason immediately after a called to GuestViewInternal.createGuest
289 // and before attaching the new guest to a frame.
290 Destroy();
293 void GuestViewBase::Destroy() {
294 DCHECK(web_contents());
295 content::RenderProcessHost* host =
296 content::RenderProcessHost::FromID(embedder_render_process_id());
297 if (host)
298 host->RemoveObserver(this);
299 WillDestroy();
300 if (!destruction_callback_.is_null())
301 destruction_callback_.Run();
303 webcontents_guestview_map.Get().erase(web_contents());
304 GuestViewManager::FromBrowserContext(browser_context_)->
305 RemoveGuest(guest_instance_id_);
306 pending_events_.clear();
308 delete web_contents();
311 void GuestViewBase::DidAttach() {
312 // Give the derived class an opportunity to perform some actions.
313 DidAttachToEmbedder();
315 SendQueuedEvents();
318 void GuestViewBase::ElementSizeChanged(const gfx::Size& old_size,
319 const gfx::Size& new_size) {
320 element_size_ = new_size;
323 void GuestViewBase::GuestSizeChanged(const gfx::Size& old_size,
324 const gfx::Size& new_size) {
325 if (!auto_size_enabled_)
326 return;
327 guest_size_ = new_size;
328 GuestSizeChangedDueToAutoSize(old_size, new_size);
331 void GuestViewBase::SetAttachParams(const base::DictionaryValue& params) {
332 attach_params_.reset(params.DeepCopy());
333 attach_params_->GetInteger(guestview::kParameterInstanceId,
334 &view_instance_id_);
337 void GuestViewBase::SetOpener(GuestViewBase* guest) {
338 if (guest && guest->IsViewType(GetViewType())) {
339 opener_ = guest->AsWeakPtr();
340 return;
342 opener_ = base::WeakPtr<GuestViewBase>();
345 void GuestViewBase::RegisterDestructionCallback(
346 const DestructionCallback& callback) {
347 destruction_callback_ = callback;
350 void GuestViewBase::WillAttach(content::WebContents* embedder_web_contents) {
351 // After attachment, this GuestViewBase's lifetime is restricted to the
352 // lifetime of its embedder WebContents. Observing the RenderProcessHost
353 // of the embedder is no longer necessary.
354 embedder_web_contents->GetRenderProcessHost()->RemoveObserver(this);
355 embedder_web_contents_ = embedder_web_contents;
356 embedder_web_contents_observer_.reset(
357 new EmbedderWebContentsObserver(this));
359 WillAttachToEmbedder();
362 void GuestViewBase::DidStopLoading(content::RenderViewHost* render_view_host) {
363 if (!IsDragAndDropEnabled()) {
364 const char script[] = "window.addEventListener('dragstart', function() { "
365 " window.event.preventDefault(); "
366 "});";
367 render_view_host->GetMainFrame()->ExecuteJavaScript(
368 base::ASCIIToUTF16(script));
370 DidStopLoading();
373 void GuestViewBase::RenderViewReady() {
374 GuestReady();
375 content::RenderViewHost* rvh = web_contents()->GetRenderViewHost();
376 if (auto_size_enabled_) {
377 rvh->EnableAutoResize(min_auto_size_, max_auto_size_);
378 } else {
379 rvh->DisableAutoResize(element_size_);
383 void GuestViewBase::WebContentsDestroyed() {
384 GuestDestroyed();
385 delete this;
388 void GuestViewBase::ActivateContents(WebContents* web_contents) {
389 if (!attached() || !embedder_web_contents()->GetDelegate())
390 return;
392 embedder_web_contents()->GetDelegate()->ActivateContents(
393 embedder_web_contents());
396 void GuestViewBase::DeactivateContents(WebContents* web_contents) {
397 if (!attached() || !embedder_web_contents()->GetDelegate())
398 return;
400 embedder_web_contents()->GetDelegate()->DeactivateContents(
401 embedder_web_contents());
404 void GuestViewBase::RunFileChooser(WebContents* web_contents,
405 const content::FileChooserParams& params) {
406 if (!attached() || !embedder_web_contents()->GetDelegate())
407 return;
409 embedder_web_contents()->GetDelegate()->RunFileChooser(web_contents, params);
412 bool GuestViewBase::ShouldFocusPageAfterCrash() {
413 // Focus is managed elsewhere.
414 return false;
417 bool GuestViewBase::PreHandleGestureEvent(content::WebContents* source,
418 const blink::WebGestureEvent& event) {
419 return event.type == blink::WebGestureEvent::GesturePinchBegin ||
420 event.type == blink::WebGestureEvent::GesturePinchUpdate ||
421 event.type == blink::WebGestureEvent::GesturePinchEnd;
424 GuestViewBase::~GuestViewBase() {
427 void GuestViewBase::DispatchEventToEmbedder(Event* event) {
428 scoped_ptr<Event> event_ptr(event);
430 if (!attached()) {
431 pending_events_.push_back(linked_ptr<Event>(event_ptr.release()));
432 return;
435 EventFilteringInfo info;
436 info.SetInstanceID(view_instance_id_);
437 scoped_ptr<base::ListValue> args(new base::ListValue());
438 args->Append(event->GetArguments().release());
440 EventRouter::DispatchEvent(
441 embedder_web_contents_,
442 browser_context_,
443 embedder_extension_id_,
444 event->name(),
445 args.Pass(),
446 EventRouter::USER_GESTURE_UNKNOWN,
447 info);
450 void GuestViewBase::SendQueuedEvents() {
451 if (!attached())
452 return;
453 while (!pending_events_.empty()) {
454 linked_ptr<Event> event_ptr = pending_events_.front();
455 pending_events_.pop_front();
456 DispatchEventToEmbedder(event_ptr.release());
460 void GuestViewBase::CompleteInit(const std::string& embedder_extension_id,
461 int embedder_render_process_id,
462 const WebContentsCreatedCallback& callback,
463 content::WebContents* guest_web_contents) {
464 if (!guest_web_contents) {
465 // The derived class did not create a WebContents so this class serves no
466 // purpose. Let's self-destruct.
467 delete this;
468 callback.Run(NULL);
469 return;
471 InitWithWebContents(embedder_extension_id,
472 embedder_render_process_id,
473 guest_web_contents);
474 callback.Run(guest_web_contents);
477 // static
478 void GuestViewBase::RegisterGuestViewTypes() {
479 AppViewGuest::Register();
480 ExtensionOptionsGuest::Register();
481 MimeHandlerViewGuest::Register();
482 WebViewGuest::Register();
485 } // namespace extensions