Delete chrome.mediaGalleriesPrivate because the functionality unique to it has since...
[chromium-blink-merge.git] / extensions / browser / guest_view / guest_view_base.cc
blob05600725652ebc6756628264b501d731294c3067
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 "components/ui/zoom/page_zoom.h"
10 #include "components/ui/zoom/zoom_controller.h"
11 #include "content/public/browser/navigation_details.h"
12 #include "content/public/browser/render_frame_host.h"
13 #include "content/public/browser/render_process_host.h"
14 #include "content/public/browser/render_view_host.h"
15 #include "content/public/browser/web_contents.h"
16 #include "content/public/common/page_zoom.h"
17 #include "content/public/common/url_constants.h"
18 #include "extensions/browser/api/extensions_api_client.h"
19 #include "extensions/browser/event_router.h"
20 #include "extensions/browser/extension_registry.h"
21 #include "extensions/browser/guest_view/app_view/app_view_guest.h"
22 #include "extensions/browser/guest_view/extension_options/extension_options_guest.h"
23 #include "extensions/browser/guest_view/guest_view_manager.h"
24 #include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h"
25 #include "extensions/browser/guest_view/surface_worker/surface_worker_guest.h"
26 #include "extensions/browser/guest_view/web_view/web_view_guest.h"
27 #include "extensions/browser/process_manager.h"
28 #include "extensions/browser/process_map.h"
29 #include "extensions/common/extension_messages.h"
30 #include "extensions/common/features/feature.h"
31 #include "extensions/common/features/feature_provider.h"
32 #include "extensions/common/guest_view/guest_view_constants.h"
33 #include "third_party/WebKit/public/web/WebInputEvent.h"
35 using content::WebContents;
37 namespace content {
38 struct FrameNavigateParams;
41 namespace extensions {
43 namespace {
45 using GuestViewCreationMap =
46 std::map<std::string, GuestViewBase::GuestCreationCallback>;
47 static base::LazyInstance<GuestViewCreationMap> guest_view_registry =
48 LAZY_INSTANCE_INITIALIZER;
50 using WebContentsGuestViewMap = std::map<WebContents*, GuestViewBase*>;
51 static base::LazyInstance<WebContentsGuestViewMap> webcontents_guestview_map =
52 LAZY_INSTANCE_INITIALIZER;
54 } // namespace
56 GuestViewBase::Event::Event(const std::string& name,
57 scoped_ptr<base::DictionaryValue> args)
58 : name_(name), args_(args.Pass()) {
61 GuestViewBase::Event::~Event() {
64 scoped_ptr<base::DictionaryValue> GuestViewBase::Event::GetArguments() {
65 return args_.Pass();
68 // This observer ensures that the GuestViewBase destroys itself when its
69 // embedder goes away.
70 class GuestViewBase::OwnerLifetimeObserver : public WebContentsObserver {
71 public:
72 OwnerLifetimeObserver(GuestViewBase* guest,
73 content::WebContents* embedder_web_contents)
74 : WebContentsObserver(embedder_web_contents),
75 destroyed_(false),
76 guest_(guest) {}
78 ~OwnerLifetimeObserver() override {}
80 // WebContentsObserver implementation.
81 void WebContentsDestroyed() override {
82 // If the embedder is destroyed then destroy the guest.
83 Destroy();
86 void DidNavigateMainFrame(
87 const content::LoadCommittedDetails& details,
88 const content::FrameNavigateParams& params) override {
89 // If the embedder navigates to a different page then destroy the guest.
90 if (details.is_navigation_to_different_page())
91 Destroy();
94 void RenderProcessGone(base::TerminationStatus status) override {
95 // If the embedder crashes, then destroy the guest.
96 Destroy();
99 private:
100 bool destroyed_;
101 GuestViewBase* guest_;
103 void Destroy() {
104 if (destroyed_)
105 return;
107 destroyed_ = true;
108 guest_->EmbedderWillBeDestroyed();
109 guest_->Destroy();
112 DISALLOW_COPY_AND_ASSIGN(OwnerLifetimeObserver);
115 // This observer ensures that the GuestViewBase destroys itself when its
116 // embedder goes away.
117 class GuestViewBase::OpenerLifetimeObserver : public WebContentsObserver {
118 public:
119 OpenerLifetimeObserver(GuestViewBase* guest)
120 : WebContentsObserver(guest->GetOpener()->web_contents()),
121 guest_(guest) {}
123 ~OpenerLifetimeObserver() override {}
125 // WebContentsObserver implementation.
126 void WebContentsDestroyed() override {
127 if (guest_->attached())
128 return;
130 // If the opener is destroyed then destroy the guest.
131 guest_->Destroy();
134 private:
135 GuestViewBase* guest_;
137 DISALLOW_COPY_AND_ASSIGN(OpenerLifetimeObserver);
140 GuestViewBase::GuestViewBase(content::WebContents* owner_web_contents,
141 int guest_instance_id)
142 : owner_web_contents_(owner_web_contents),
143 browser_context_(owner_web_contents->GetBrowserContext()),
144 guest_instance_id_(guest_instance_id),
145 view_instance_id_(guestview::kInstanceIDNone),
146 element_instance_id_(guestview::kInstanceIDNone),
147 initialized_(false),
148 is_being_destroyed_(false),
149 guest_sizer_(nullptr),
150 auto_size_enabled_(false),
151 is_full_page_plugin_(false),
152 weak_ptr_factory_(this) {
155 void GuestViewBase::Init(const base::DictionaryValue& create_params,
156 const WebContentsCreatedCallback& callback) {
157 if (initialized_)
158 return;
159 initialized_ = true;
161 const Feature* feature = FeatureProvider::GetAPIFeature(GetAPINamespace());
162 CHECK(feature);
164 ProcessMap* process_map = ProcessMap::Get(browser_context());
165 CHECK(process_map);
167 const Extension* owner_extension =
168 ProcessManager::Get(owner_web_contents()->GetBrowserContext())->
169 GetExtensionForRenderViewHost(
170 owner_web_contents()->GetRenderViewHost());
171 owner_extension_id_ = owner_extension ? owner_extension->id() : std::string();
173 // Ok for |owner_extension| to be nullptr, the embedder might be WebUI.
174 Feature::Availability availability = feature->IsAvailableToContext(
175 owner_extension,
176 process_map->GetMostLikelyContextType(
177 owner_extension,
178 owner_web_contents()->GetRenderProcessHost()->GetID()),
179 GetOwnerSiteURL());
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(nullptr);
185 return;
188 scoped_ptr<base::DictionaryValue> params(create_params.DeepCopy());
189 CreateWebContents(create_params,
190 base::Bind(&GuestViewBase::CompleteInit,
191 weak_ptr_factory_.GetWeakPtr(),
192 base::Passed(&params),
193 callback));
196 void GuestViewBase::InitWithWebContents(
197 const base::DictionaryValue& create_params,
198 content::WebContents* guest_web_contents) {
199 DCHECK(guest_web_contents);
201 // At this point, we have just created the guest WebContents, we need to add
202 // an observer to the owner WebContents. This observer will be responsible
203 // for destroying the guest WebContents if the owner goes away.
204 owner_lifetime_observer_.reset(
205 new OwnerLifetimeObserver(this, owner_web_contents_));
207 WebContentsObserver::Observe(guest_web_contents);
208 guest_web_contents->SetDelegate(this);
209 webcontents_guestview_map.Get().insert(
210 std::make_pair(guest_web_contents, this));
211 GuestViewManager::FromBrowserContext(browser_context_)->
212 AddGuest(guest_instance_id_, guest_web_contents);
214 // Create a ZoomController to allow the guest's contents to be zoomed.
215 ui_zoom::ZoomController::CreateForWebContents(guest_web_contents);
217 // Populate the view instance ID if we have it on creation.
218 create_params.GetInteger(guestview::kParameterInstanceId,
219 &view_instance_id_);
221 if (CanRunInDetachedState())
222 SetUpAutoSize(create_params);
224 // Give the derived class an opportunity to perform additional initialization.
225 DidInitialize(create_params);
228 void GuestViewBase::DispatchOnResizeEvent(const gfx::Size& old_size,
229 const gfx::Size& new_size) {
230 if (new_size == old_size)
231 return;
233 // Dispatch the onResize event.
234 scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue());
235 args->SetInteger(guestview::kOldWidth, old_size.width());
236 args->SetInteger(guestview::kOldHeight, old_size.height());
237 args->SetInteger(guestview::kNewWidth, new_size.width());
238 args->SetInteger(guestview::kNewHeight, new_size.height());
239 DispatchEventToGuestProxy(new Event(guestview::kEventResize, args.Pass()));
242 void GuestViewBase::SetAutoSize(bool enabled,
243 const gfx::Size& min_size,
244 const gfx::Size& max_size) {
245 min_auto_size_ = min_size;
246 min_auto_size_.SetToMin(max_size);
247 max_auto_size_ = max_size;
248 max_auto_size_.SetToMax(min_size);
250 enabled &= !min_auto_size_.IsEmpty() && !max_auto_size_.IsEmpty() &&
251 IsAutoSizeSupported();
252 if (!enabled && !auto_size_enabled_)
253 return;
255 auto_size_enabled_ = enabled;
257 if (!attached() && !CanRunInDetachedState())
258 return;
260 content::RenderViewHost* rvh = web_contents()->GetRenderViewHost();
261 if (auto_size_enabled_) {
262 rvh->EnableAutoResize(min_auto_size_, max_auto_size_);
263 } else {
264 rvh->DisableAutoResize(element_size_);
265 DispatchOnResizeEvent(guest_size_, element_size_);
266 GuestSizeChangedDueToAutoSize(guest_size_, element_size_);
267 guest_size_ = element_size_;
271 // static
272 void GuestViewBase::RegisterGuestViewType(
273 const std::string& view_type,
274 const GuestCreationCallback& callback) {
275 auto it = guest_view_registry.Get().find(view_type);
276 DCHECK(it == guest_view_registry.Get().end());
277 guest_view_registry.Get()[view_type] = callback;
280 // static
281 GuestViewBase* GuestViewBase::Create(
282 content::WebContents* owner_web_contents,
283 int guest_instance_id,
284 const std::string& view_type) {
285 if (guest_view_registry.Get().empty())
286 RegisterGuestViewTypes();
288 auto it = guest_view_registry.Get().find(view_type);
289 if (it == guest_view_registry.Get().end()) {
290 NOTREACHED();
291 return nullptr;
293 return it->second.Run(owner_web_contents, guest_instance_id);
296 // static
297 GuestViewBase* GuestViewBase::FromWebContents(WebContents* web_contents) {
298 WebContentsGuestViewMap* guest_map = webcontents_guestview_map.Pointer();
299 auto it = guest_map->find(web_contents);
300 return it == guest_map->end() ? nullptr : it->second;
303 // static
304 GuestViewBase* GuestViewBase::From(int owner_process_id,
305 int guest_instance_id) {
306 auto host = content::RenderProcessHost::FromID(owner_process_id);
307 if (!host)
308 return nullptr;
310 content::WebContents* guest_web_contents =
311 GuestViewManager::FromBrowserContext(host->GetBrowserContext())->
312 GetGuestByInstanceIDSafely(guest_instance_id, owner_process_id);
313 if (!guest_web_contents)
314 return nullptr;
316 return GuestViewBase::FromWebContents(guest_web_contents);
319 // static
320 bool GuestViewBase::IsGuest(WebContents* web_contents) {
321 return !!GuestViewBase::FromWebContents(web_contents);
324 bool GuestViewBase::IsAutoSizeSupported() const {
325 return false;
328 bool GuestViewBase::IsPreferredSizeModeEnabled() const {
329 return false;
332 bool GuestViewBase::IsDragAndDropEnabled() const {
333 return false;
336 bool GuestViewBase::ZoomPropagatesFromEmbedderToGuest() const {
337 return true;
340 content::WebContents* GuestViewBase::CreateNewGuestWindow(
341 const content::WebContents::CreateParams& create_params) {
342 auto guest_manager = GuestViewManager::FromBrowserContext(browser_context());
343 return guest_manager->CreateGuestWithWebContentsParams(
344 GetViewType(),
345 owner_web_contents(),
346 create_params);
349 void GuestViewBase::DidAttach(int guest_proxy_routing_id) {
350 opener_lifetime_observer_.reset();
352 SetUpAutoSize(*attach_params());
354 // Give the derived class an opportunity to perform some actions.
355 DidAttachToEmbedder();
357 // Inform the associated GuestViewContainer that the contentWindow is ready.
358 embedder_web_contents()->Send(new ExtensionMsg_GuestAttached(
359 element_instance_id_,
360 guest_proxy_routing_id));
362 SendQueuedEvents();
365 void GuestViewBase::DidDetach() {
366 GuestViewManager::FromBrowserContext(browser_context_)->DetachGuest(
367 this, element_instance_id_);
368 StopTrackingEmbedderZoomLevel();
369 owner_web_contents()->Send(new ExtensionMsg_GuestDetached(
370 element_instance_id_));
371 element_instance_id_ = guestview::kInstanceIDNone;
374 void GuestViewBase::ElementSizeChanged(const gfx::Size& size) {
375 element_size_ = size;
377 // Only resize if needed.
378 if (!size.IsEmpty()) {
379 guest_sizer_->SizeContents(size);
380 guest_size_ = size;
384 WebContents* GuestViewBase::GetOwnerWebContents() const {
385 return owner_web_contents_;
388 void GuestViewBase::GuestSizeChanged(const gfx::Size& old_size,
389 const gfx::Size& new_size) {
390 DispatchOnResizeEvent(old_size, new_size);
391 if (!auto_size_enabled_)
392 return;
393 guest_size_ = new_size;
394 GuestSizeChangedDueToAutoSize(old_size, new_size);
397 const GURL& GuestViewBase::GetOwnerSiteURL() const {
398 return owner_web_contents()->GetLastCommittedURL();
401 void GuestViewBase::Destroy() {
402 if (is_being_destroyed_)
403 return;
405 is_being_destroyed_ = true;
407 guest_sizer_ = nullptr;
409 // It is important to clear owner_web_contents_ after the call to
410 // StopTrackingEmbedderZoomLevel(), but before the rest of
411 // the statements in this function.
412 StopTrackingEmbedderZoomLevel();
413 owner_web_contents_ = nullptr;
415 DCHECK(web_contents());
417 // Give the derived class an opportunity to perform some cleanup.
418 WillDestroy();
420 // Invalidate weak pointers now so that bound callbacks cannot be called late
421 // into destruction. We must call this after WillDestroy because derived types
422 // may wish to access their openers.
423 weak_ptr_factory_.InvalidateWeakPtrs();
425 // Give the content module an opportunity to perform some cleanup.
426 if (!destruction_callback_.is_null())
427 destruction_callback_.Run();
429 webcontents_guestview_map.Get().erase(web_contents());
430 GuestViewManager::FromBrowserContext(browser_context_)->
431 RemoveGuest(guest_instance_id_);
432 pending_events_.clear();
434 delete web_contents();
437 void GuestViewBase::SetAttachParams(const base::DictionaryValue& params) {
438 attach_params_.reset(params.DeepCopy());
439 attach_params_->GetInteger(guestview::kParameterInstanceId,
440 &view_instance_id_);
443 void GuestViewBase::SetOpener(GuestViewBase* guest) {
444 if (guest && guest->IsViewType(GetViewType())) {
445 opener_ = guest->weak_ptr_factory_.GetWeakPtr();
446 if (!attached())
447 opener_lifetime_observer_.reset(new OpenerLifetimeObserver(this));
448 return;
450 opener_ = base::WeakPtr<GuestViewBase>();
451 opener_lifetime_observer_.reset();
454 void GuestViewBase::RegisterDestructionCallback(
455 const DestructionCallback& callback) {
456 destruction_callback_ = callback;
459 void GuestViewBase::SetGuestSizer(content::GuestSizer* guest_sizer) {
460 guest_sizer_ = guest_sizer;
463 void GuestViewBase::WillAttach(content::WebContents* embedder_web_contents,
464 int element_instance_id,
465 bool is_full_page_plugin) {
466 if (owner_web_contents_ != embedder_web_contents) {
467 DCHECK_EQ(owner_lifetime_observer_->web_contents(), owner_web_contents_);
468 // Stop tracking the old embedder's zoom level.
469 StopTrackingEmbedderZoomLevel();
470 owner_web_contents_ = embedder_web_contents;
471 owner_lifetime_observer_.reset(
472 new OwnerLifetimeObserver(this, embedder_web_contents));
475 // Start tracking the new embedder's zoom level.
476 StartTrackingEmbedderZoomLevel();
477 element_instance_id_ = element_instance_id;
478 is_full_page_plugin_ = is_full_page_plugin;
480 WillAttachToEmbedder();
483 void GuestViewBase::DidStopLoading(content::RenderViewHost* render_view_host) {
484 if (IsPreferredSizeModeEnabled()) {
485 render_view_host->EnablePreferredSizeMode();
487 if (!IsDragAndDropEnabled()) {
488 const char script[] = "window.addEventListener('dragstart', function() { "
489 " window.event.preventDefault(); "
490 "});";
491 render_view_host->GetMainFrame()->ExecuteJavaScript(
492 base::ASCIIToUTF16(script));
494 DidStopLoading();
497 void GuestViewBase::RenderViewReady() {
498 GuestReady();
501 void GuestViewBase::WebContentsDestroyed() {
502 // Let the derived class know that its WebContents is in the process of
503 // being destroyed. web_contents() is still valid at this point.
504 // TODO(fsamuel): This allows for reentrant code into WebContents during
505 // destruction. This could potentially lead to bugs. Perhaps we should get rid
506 // of this?
507 GuestDestroyed();
509 // Self-destruct.
510 delete this;
513 void GuestViewBase::ActivateContents(WebContents* web_contents) {
514 if (!attached() || !embedder_web_contents()->GetDelegate())
515 return;
517 embedder_web_contents()->GetDelegate()->ActivateContents(
518 embedder_web_contents());
521 void GuestViewBase::DeactivateContents(WebContents* web_contents) {
522 if (!attached() || !embedder_web_contents()->GetDelegate())
523 return;
525 embedder_web_contents()->GetDelegate()->DeactivateContents(
526 embedder_web_contents());
529 void GuestViewBase::ContentsZoomChange(bool zoom_in) {
530 ui_zoom::PageZoom::Zoom(
531 embedder_web_contents(),
532 zoom_in ? content::PAGE_ZOOM_IN : content::PAGE_ZOOM_OUT);
535 void GuestViewBase::HandleKeyboardEvent(
536 WebContents* source,
537 const content::NativeWebKeyboardEvent& event) {
538 if (!attached())
539 return;
541 // Send the keyboard events back to the embedder to reprocess them.
542 embedder_web_contents()->GetDelegate()->HandleKeyboardEvent(web_contents(),
543 event);
546 void GuestViewBase::RunFileChooser(WebContents* web_contents,
547 const content::FileChooserParams& params) {
548 if (!attached() || !embedder_web_contents()->GetDelegate())
549 return;
551 embedder_web_contents()->GetDelegate()->RunFileChooser(web_contents, params);
554 bool GuestViewBase::ShouldFocusPageAfterCrash() {
555 // Focus is managed elsewhere.
556 return false;
559 bool GuestViewBase::PreHandleGestureEvent(content::WebContents* source,
560 const blink::WebGestureEvent& event) {
561 return event.type == blink::WebGestureEvent::GesturePinchBegin ||
562 event.type == blink::WebGestureEvent::GesturePinchUpdate ||
563 event.type == blink::WebGestureEvent::GesturePinchEnd;
566 void GuestViewBase::UpdatePreferredSize(
567 content::WebContents* target_web_contents,
568 const gfx::Size& pref_size) {
569 // In theory it's not necessary to check IsPreferredSizeModeEnabled() because
570 // there will only be events if it was enabled in the first place. However,
571 // something else may have turned on preferred size mode, so double check.
572 DCHECK_EQ(web_contents(), target_web_contents);
573 if (IsPreferredSizeModeEnabled()) {
574 OnPreferredSizeChanged(pref_size);
578 GuestViewBase::~GuestViewBase() {
581 void GuestViewBase::OnZoomChanged(
582 const ui_zoom::ZoomController::ZoomChangedEventData& data) {
583 auto guest_zoom_controller =
584 ui_zoom::ZoomController::FromWebContents(web_contents());
585 if (content::ZoomValuesEqual(data.new_zoom_level,
586 guest_zoom_controller->GetZoomLevel())) {
587 return;
589 // When the embedder's zoom level doesn't match the guest's, then update the
590 // guest's zoom level to match.
591 guest_zoom_controller->SetZoomLevel(data.new_zoom_level);
594 void GuestViewBase::DispatchEventToGuestProxy(Event* event) {
595 DispatchEvent(event, guest_instance_id_);
598 void GuestViewBase::DispatchEventToView(Event* event) {
599 if (!attached() &&
600 (!CanRunInDetachedState() || !can_owner_receive_events())) {
601 pending_events_.push_back(linked_ptr<Event>(event));
602 return;
605 DispatchEvent(event, view_instance_id_);
608 void GuestViewBase::DispatchEvent(Event* event, int instance_id) {
609 scoped_ptr<Event> event_ptr(event);
611 EventFilteringInfo info;
612 info.SetInstanceID(instance_id);
613 scoped_ptr<base::ListValue> args(new base::ListValue());
614 args->Append(event->GetArguments().release());
616 EventRouter::DispatchEvent(
617 owner_web_contents_,
618 browser_context_,
619 owner_extension_id_,
620 event->name(),
621 args.Pass(),
622 EventRouter::USER_GESTURE_UNKNOWN,
623 info);
626 void GuestViewBase::SendQueuedEvents() {
627 if (!attached())
628 return;
629 while (!pending_events_.empty()) {
630 linked_ptr<Event> event_ptr = pending_events_.front();
631 pending_events_.pop_front();
632 DispatchEvent(event_ptr.release(), view_instance_id_);
636 void GuestViewBase::CompleteInit(
637 scoped_ptr<base::DictionaryValue> create_params,
638 const WebContentsCreatedCallback& callback,
639 content::WebContents* guest_web_contents) {
640 if (!guest_web_contents) {
641 // The derived class did not create a WebContents so this class serves no
642 // purpose. Let's self-destruct.
643 delete this;
644 callback.Run(nullptr);
645 return;
647 InitWithWebContents(*create_params, guest_web_contents);
648 callback.Run(guest_web_contents);
651 void GuestViewBase::SetUpAutoSize(const base::DictionaryValue& params) {
652 // Read the autosize parameters passed in from the embedder.
653 bool auto_size_enabled = false;
654 params.GetBoolean(guestview::kAttributeAutoSize, &auto_size_enabled);
656 int max_height = 0;
657 int max_width = 0;
658 params.GetInteger(guestview::kAttributeMaxHeight, &max_height);
659 params.GetInteger(guestview::kAttributeMaxWidth, &max_width);
661 int min_height = 0;
662 int min_width = 0;
663 params.GetInteger(guestview::kAttributeMinHeight, &min_height);
664 params.GetInteger(guestview::kAttributeMinWidth, &min_width);
666 // Call SetAutoSize to apply all the appropriate validation and clipping of
667 // values.
668 SetAutoSize(auto_size_enabled,
669 gfx::Size(min_width, min_height),
670 gfx::Size(max_width, max_height));
673 void GuestViewBase::StartTrackingEmbedderZoomLevel() {
674 if (!ZoomPropagatesFromEmbedderToGuest())
675 return;
677 auto embedder_zoom_controller =
678 ui_zoom::ZoomController::FromWebContents(owner_web_contents());
679 // Chrome Apps do not have a ZoomController.
680 if (!embedder_zoom_controller)
681 return;
682 // Listen to the embedder's zoom changes.
683 embedder_zoom_controller->AddObserver(this);
684 // Set the guest's initial zoom level to be equal to the embedder's.
685 ui_zoom::ZoomController::FromWebContents(web_contents())
686 ->SetZoomLevel(embedder_zoom_controller->GetZoomLevel());
689 void GuestViewBase::StopTrackingEmbedderZoomLevel() {
690 if (!attached() || !ZoomPropagatesFromEmbedderToGuest())
691 return;
693 auto embedder_zoom_controller =
694 ui_zoom::ZoomController::FromWebContents(owner_web_contents());
695 // Chrome Apps do not have a ZoomController.
696 if (!embedder_zoom_controller)
697 return;
698 embedder_zoom_controller->RemoveObserver(this);
701 // static
702 void GuestViewBase::RegisterGuestViewTypes() {
703 AppViewGuest::Register();
704 ExtensionOptionsGuest::Register();
705 MimeHandlerViewGuest::Register();
706 SurfaceWorkerGuest::Register();
707 WebViewGuest::Register();
710 } // namespace extensions