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/render_widget_host_view.h"
16 #include "content/public/browser/web_contents.h"
17 #include "content/public/common/page_zoom.h"
18 #include "content/public/common/url_constants.h"
19 #include "extensions/browser/api/extensions_api_client.h"
20 #include "extensions/browser/event_router.h"
21 #include "extensions/browser/extension_registry.h"
22 #include "extensions/browser/guest_view/app_view/app_view_guest.h"
23 #include "extensions/browser/guest_view/extension_options/extension_options_guest.h"
24 #include "extensions/browser/guest_view/extension_view/extension_view_guest.h"
25 #include "extensions/browser/guest_view/guest_view_manager.h"
26 #include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h"
27 #include "extensions/browser/guest_view/surface_worker/surface_worker_guest.h"
28 #include "extensions/browser/guest_view/web_view/web_view_guest.h"
29 #include "extensions/browser/process_manager.h"
30 #include "extensions/browser/process_map.h"
31 #include "extensions/common/features/feature.h"
32 #include "extensions/common/features/feature_provider.h"
33 #include "extensions/common/guest_view/guest_view_constants.h"
34 #include "extensions/common/guest_view/guest_view_messages.h"
35 #include "third_party/WebKit/public/web/WebInputEvent.h"
37 using content::WebContents
;
40 struct FrameNavigateParams
;
43 namespace extensions
{
47 using GuestViewCreationMap
=
48 std::map
<std::string
, GuestViewBase::GuestCreationCallback
>;
49 static base::LazyInstance
<GuestViewCreationMap
> guest_view_registry
=
50 LAZY_INSTANCE_INITIALIZER
;
52 using WebContentsGuestViewMap
= std::map
<const WebContents
*, GuestViewBase
*>;
53 static base::LazyInstance
<WebContentsGuestViewMap
> webcontents_guestview_map
=
54 LAZY_INSTANCE_INITIALIZER
;
58 SetSizeParams::SetSizeParams() {
60 SetSizeParams::~SetSizeParams() {
63 GuestViewBase::Event::Event(const std::string
& name
,
64 scoped_ptr
<base::DictionaryValue
> args
)
65 : name_(name
), args_(args
.Pass()) {
68 GuestViewBase::Event::~Event() {
71 scoped_ptr
<base::DictionaryValue
> GuestViewBase::Event::GetArguments() {
75 // This observer ensures that the GuestViewBase destroys itself when its
76 // embedder goes away. It also tracks when the embedder's fullscreen is
77 // toggled so the guest can change itself accordingly.
78 class GuestViewBase::OwnerContentsObserver
: public WebContentsObserver
{
80 OwnerContentsObserver(GuestViewBase
* guest
,
81 content::WebContents
* embedder_web_contents
)
82 : WebContentsObserver(embedder_web_contents
),
83 is_fullscreen_(false),
87 ~OwnerContentsObserver() override
{}
89 // WebContentsObserver implementation.
90 void WebContentsDestroyed() override
{
91 // If the embedder is destroyed then destroy the guest.
95 void DidNavigateMainFrame(
96 const content::LoadCommittedDetails
& details
,
97 const content::FrameNavigateParams
& params
) override
{
98 // If the embedder navigates to a different page then destroy the guest.
99 if (details
.is_navigation_to_different_page())
103 void RenderProcessGone(base::TerminationStatus status
) override
{
104 // If the embedder crashes, then destroy the guest.
108 void DidToggleFullscreenModeForTab(bool entered_fullscreen
) override
{
112 is_fullscreen_
= entered_fullscreen
;
113 guest_
->EmbedderFullscreenToggled(is_fullscreen_
);
116 void MainFrameWasResized(bool width_changed
) override
{
120 if (!web_contents()->GetDelegate())
123 bool current_fullscreen
=
124 web_contents()->GetDelegate()->IsFullscreenForTabOrPending(
126 if (is_fullscreen_
&& !current_fullscreen
) {
127 is_fullscreen_
= false;
128 guest_
->EmbedderFullscreenToggled(is_fullscreen_
);
135 GuestViewBase
* guest_
;
142 guest_
->EmbedderWillBeDestroyed();
146 DISALLOW_COPY_AND_ASSIGN(OwnerContentsObserver
);
149 // This observer ensures that the GuestViewBase destroys itself when its
150 // embedder goes away.
151 class GuestViewBase::OpenerLifetimeObserver
: public WebContentsObserver
{
153 OpenerLifetimeObserver(GuestViewBase
* guest
)
154 : WebContentsObserver(guest
->GetOpener()->web_contents()),
157 ~OpenerLifetimeObserver() override
{}
159 // WebContentsObserver implementation.
160 void WebContentsDestroyed() override
{
161 if (guest_
->attached())
164 // If the opener is destroyed then destroy the guest.
169 GuestViewBase
* guest_
;
171 DISALLOW_COPY_AND_ASSIGN(OpenerLifetimeObserver
);
174 GuestViewBase::GuestViewBase(content::WebContents
* owner_web_contents
)
175 : owner_web_contents_(owner_web_contents
),
176 browser_context_(owner_web_contents
->GetBrowserContext()),
178 GuestViewManager::FromBrowserContext(browser_context_
)->
179 GetNextInstanceID()),
180 view_instance_id_(guestview::kInstanceIDNone
),
181 element_instance_id_(guestview::kInstanceIDNone
),
183 is_being_destroyed_(false),
184 guest_host_(nullptr),
185 auto_size_enabled_(false),
186 is_full_page_plugin_(false),
187 guest_proxy_routing_id_(MSG_ROUTING_NONE
),
188 weak_ptr_factory_(this) {
191 void GuestViewBase::Init(const base::DictionaryValue
& create_params
,
192 const WebContentsCreatedCallback
& callback
) {
197 const Feature
* feature
= FeatureProvider::GetAPIFeature(GetAPINamespace());
200 ProcessMap
* process_map
= ProcessMap::Get(browser_context());
203 const Extension
* owner_extension
=
204 ProcessManager::Get(owner_web_contents()->GetBrowserContext())->
205 GetExtensionForWebContents(owner_web_contents());
206 owner_extension_id_
= owner_extension
? owner_extension
->id() : std::string();
208 // Ok for |owner_extension| to be nullptr, the embedder might be WebUI.
209 Feature::Availability availability
= feature
->IsAvailableToContext(
211 process_map
->GetMostLikelyContextType(
213 owner_web_contents()->GetRenderProcessHost()->GetID()),
215 if (!availability
.is_available()) {
216 // The derived class did not create a WebContents so this class serves no
217 // purpose. Let's self-destruct.
219 callback
.Run(nullptr);
223 scoped_ptr
<base::DictionaryValue
> params(create_params
.DeepCopy());
224 CreateWebContents(create_params
,
225 base::Bind(&GuestViewBase::CompleteInit
,
226 weak_ptr_factory_
.GetWeakPtr(),
227 base::Passed(¶ms
),
231 void GuestViewBase::InitWithWebContents(
232 const base::DictionaryValue
& create_params
,
233 content::WebContents
* guest_web_contents
) {
234 DCHECK(guest_web_contents
);
236 // Create a ZoomController to allow the guest's contents to be zoomed.
237 // Do this before adding the GuestView as a WebContents Observer so that
238 // the GuestView and its derived classes can re-configure the ZoomController
239 // after the latter has handled WebContentsObserver events (observers are
240 // notified of events in the same order they are added as observers). For
241 // example, GuestViewBase may wish to put its guest into isolated zoom mode
242 // in DidNavigateMainFrame, but since ZoomController always resets to default
243 // zoom mode on this event, GuestViewBase would need to do so after
244 // ZoomController::DidNavigateMainFrame has completed.
245 ui_zoom::ZoomController::CreateForWebContents(guest_web_contents
);
247 // At this point, we have just created the guest WebContents, we need to add
248 // an observer to the owner WebContents. This observer will be responsible
249 // for destroying the guest WebContents if the owner goes away.
250 owner_contents_observer_
.reset(
251 new OwnerContentsObserver(this, owner_web_contents_
));
253 WebContentsObserver::Observe(guest_web_contents
);
254 guest_web_contents
->SetDelegate(this);
255 webcontents_guestview_map
.Get().insert(
256 std::make_pair(guest_web_contents
, this));
257 GuestViewManager::FromBrowserContext(browser_context_
)->
258 AddGuest(guest_instance_id_
, guest_web_contents
);
260 // Populate the view instance ID if we have it on creation.
261 create_params
.GetInteger(guestview::kParameterInstanceId
,
264 if (CanRunInDetachedState())
265 SetUpSizing(create_params
);
267 // Observe guest zoom changes.
268 auto zoom_controller
=
269 ui_zoom::ZoomController::FromWebContents(web_contents());
270 zoom_controller
->AddObserver(this);
272 // Give the derived class an opportunity to perform additional initialization.
273 DidInitialize(create_params
);
276 void GuestViewBase::LoadURLWithParams(
277 const content::NavigationController::LoadURLParams
& load_params
) {
278 int guest_proxy_routing_id
= host()->LoadURLWithParams(load_params
);
279 DCHECK(guest_proxy_routing_id_
== MSG_ROUTING_NONE
||
280 guest_proxy_routing_id
== guest_proxy_routing_id_
);
281 guest_proxy_routing_id_
= guest_proxy_routing_id
;
284 void GuestViewBase::DispatchOnResizeEvent(const gfx::Size
& old_size
,
285 const gfx::Size
& new_size
) {
286 if (new_size
== old_size
)
289 // Dispatch the onResize event.
290 scoped_ptr
<base::DictionaryValue
> args(new base::DictionaryValue());
291 args
->SetInteger(guestview::kOldWidth
, old_size
.width());
292 args
->SetInteger(guestview::kOldHeight
, old_size
.height());
293 args
->SetInteger(guestview::kNewWidth
, new_size
.width());
294 args
->SetInteger(guestview::kNewHeight
, new_size
.height());
295 DispatchEventToGuestProxy(new Event(guestview::kEventResize
, args
.Pass()));
298 void GuestViewBase::SetSize(const SetSizeParams
& params
) {
299 bool enable_auto_size
=
300 params
.enable_auto_size
? *params
.enable_auto_size
: auto_size_enabled_
;
301 gfx::Size min_size
= params
.min_size
? *params
.min_size
: min_auto_size_
;
302 gfx::Size max_size
= params
.max_size
? *params
.max_size
: max_auto_size_
;
304 if (params
.normal_size
)
305 normal_size_
= *params
.normal_size
;
307 min_auto_size_
= min_size
;
308 min_auto_size_
.SetToMin(max_size
);
309 max_auto_size_
= max_size
;
310 max_auto_size_
.SetToMax(min_size
);
312 enable_auto_size
&= !min_auto_size_
.IsEmpty() && !max_auto_size_
.IsEmpty() &&
313 IsAutoSizeSupported();
315 content::RenderViewHost
* rvh
= web_contents()->GetRenderViewHost();
316 if (enable_auto_size
) {
317 // Autosize is being enabled.
318 rvh
->EnableAutoResize(min_auto_size_
, max_auto_size_
);
319 normal_size_
.SetSize(0, 0);
321 // Autosize is being disabled.
322 // Use default width/height if missing from partially defined normal size.
323 if (normal_size_
.width() && !normal_size_
.height())
324 normal_size_
.set_height(guestview::kDefaultHeight
);
325 if (!normal_size_
.width() && normal_size_
.height())
326 normal_size_
.set_width(guestview::kDefaultWidth
);
329 if (!normal_size_
.IsEmpty()) {
330 new_size
= normal_size_
;
331 } else if (!guest_size_
.IsEmpty()) {
332 new_size
= guest_size_
;
334 new_size
= gfx::Size(guestview::kDefaultWidth
, guestview::kDefaultHeight
);
337 if (auto_size_enabled_
) {
338 // Autosize was previously enabled.
339 rvh
->DisableAutoResize(new_size
);
340 GuestSizeChangedDueToAutoSize(guest_size_
, new_size
);
342 // Autosize was already disabled.
343 guest_host_
->SizeContents(new_size
);
346 DispatchOnResizeEvent(guest_size_
, new_size
);
347 guest_size_
= new_size
;
350 auto_size_enabled_
= enable_auto_size
;
354 void GuestViewBase::RegisterGuestViewType(
355 const std::string
& view_type
,
356 const GuestCreationCallback
& callback
) {
357 auto it
= guest_view_registry
.Get().find(view_type
);
358 DCHECK(it
== guest_view_registry
.Get().end());
359 guest_view_registry
.Get()[view_type
] = callback
;
363 GuestViewBase
* GuestViewBase::Create(
364 content::WebContents
* owner_web_contents
,
365 const std::string
& view_type
) {
366 if (guest_view_registry
.Get().empty())
367 RegisterGuestViewTypes();
369 auto it
= guest_view_registry
.Get().find(view_type
);
370 if (it
== guest_view_registry
.Get().end()) {
374 return it
->second
.Run(owner_web_contents
);
378 GuestViewBase
* GuestViewBase::FromWebContents(const WebContents
* web_contents
) {
379 WebContentsGuestViewMap
* guest_map
= webcontents_guestview_map
.Pointer();
380 auto it
= guest_map
->find(web_contents
);
381 return it
== guest_map
->end() ? nullptr : it
->second
;
385 GuestViewBase
* GuestViewBase::From(int owner_process_id
,
386 int guest_instance_id
) {
387 auto host
= content::RenderProcessHost::FromID(owner_process_id
);
391 content::WebContents
* guest_web_contents
=
392 GuestViewManager::FromBrowserContext(host
->GetBrowserContext())->
393 GetGuestByInstanceIDSafely(guest_instance_id
, owner_process_id
);
394 if (!guest_web_contents
)
397 return GuestViewBase::FromWebContents(guest_web_contents
);
401 bool GuestViewBase::IsGuest(WebContents
* web_contents
) {
402 return !!GuestViewBase::FromWebContents(web_contents
);
405 bool GuestViewBase::IsAutoSizeSupported() const {
409 bool GuestViewBase::IsPreferredSizeModeEnabled() const {
413 bool GuestViewBase::IsDragAndDropEnabled() const {
417 bool GuestViewBase::ZoomPropagatesFromEmbedderToGuest() const {
421 content::WebContents
* GuestViewBase::CreateNewGuestWindow(
422 const content::WebContents::CreateParams
& create_params
) {
423 auto guest_manager
= GuestViewManager::FromBrowserContext(browser_context());
424 return guest_manager
->CreateGuestWithWebContentsParams(
426 owner_web_contents(),
430 void GuestViewBase::DidAttach(int guest_proxy_routing_id
) {
431 DCHECK(guest_proxy_routing_id_
== MSG_ROUTING_NONE
||
432 guest_proxy_routing_id
== guest_proxy_routing_id_
);
433 guest_proxy_routing_id_
= guest_proxy_routing_id
;
435 opener_lifetime_observer_
.reset();
437 SetUpSizing(*attach_params());
439 // Give the derived class an opportunity to perform some actions.
440 DidAttachToEmbedder();
442 // Inform the associated GuestViewContainer that the contentWindow is ready.
443 embedder_web_contents()->Send(new GuestViewMsg_GuestAttached(
444 element_instance_id_
,
445 guest_proxy_routing_id
));
450 void GuestViewBase::DidDetach() {
451 GuestViewManager::FromBrowserContext(browser_context_
)->DetachGuest(this);
452 StopTrackingEmbedderZoomLevel();
453 owner_web_contents()->Send(new GuestViewMsg_GuestDetached(
454 element_instance_id_
));
455 element_instance_id_
= guestview::kInstanceIDNone
;
458 WebContents
* GuestViewBase::GetOwnerWebContents() const {
459 return owner_web_contents_
;
462 void GuestViewBase::GuestSizeChanged(const gfx::Size
& new_size
) {
463 if (!auto_size_enabled_
)
465 GuestSizeChangedDueToAutoSize(guest_size_
, new_size
);
466 DispatchOnResizeEvent(guest_size_
, new_size
);
467 guest_size_
= new_size
;
470 const GURL
& GuestViewBase::GetOwnerSiteURL() const {
471 return owner_web_contents()->GetLastCommittedURL();
474 void GuestViewBase::Destroy() {
475 if (is_being_destroyed_
)
478 is_being_destroyed_
= true;
480 // It is important to clear owner_web_contents_ after the call to
481 // StopTrackingEmbedderZoomLevel(), but before the rest of
482 // the statements in this function.
483 StopTrackingEmbedderZoomLevel();
484 owner_web_contents_
= nullptr;
486 DCHECK(web_contents());
488 // Give the derived class an opportunity to perform some cleanup.
491 // Invalidate weak pointers now so that bound callbacks cannot be called late
492 // into destruction. We must call this after WillDestroy because derived types
493 // may wish to access their openers.
494 weak_ptr_factory_
.InvalidateWeakPtrs();
496 // Give the content module an opportunity to perform some cleanup.
497 guest_host_
->WillDestroy();
498 guest_host_
= nullptr;
500 webcontents_guestview_map
.Get().erase(web_contents());
501 GuestViewManager::FromBrowserContext(browser_context_
)->
502 RemoveGuest(guest_instance_id_
);
503 pending_events_
.clear();
505 delete web_contents();
508 void GuestViewBase::SetAttachParams(const base::DictionaryValue
& params
) {
509 attach_params_
.reset(params
.DeepCopy());
510 attach_params_
->GetInteger(guestview::kParameterInstanceId
,
514 void GuestViewBase::SetOpener(GuestViewBase
* guest
) {
515 if (guest
&& guest
->IsViewType(GetViewType())) {
516 opener_
= guest
->weak_ptr_factory_
.GetWeakPtr();
518 opener_lifetime_observer_
.reset(new OpenerLifetimeObserver(this));
521 opener_
= base::WeakPtr
<GuestViewBase
>();
522 opener_lifetime_observer_
.reset();
525 void GuestViewBase::SetGuestHost(content::GuestHost
* guest_host
) {
526 guest_host_
= guest_host
;
529 void GuestViewBase::WillAttach(content::WebContents
* embedder_web_contents
,
530 int element_instance_id
,
531 bool is_full_page_plugin
) {
532 if (owner_web_contents_
!= embedder_web_contents
) {
533 DCHECK_EQ(owner_contents_observer_
->web_contents(), owner_web_contents_
);
534 // Stop tracking the old embedder's zoom level.
535 StopTrackingEmbedderZoomLevel();
536 owner_web_contents_
= embedder_web_contents
;
537 owner_contents_observer_
.reset(
538 new OwnerContentsObserver(this, embedder_web_contents
));
541 // Start tracking the new embedder's zoom level.
542 StartTrackingEmbedderZoomLevel();
543 element_instance_id_
= element_instance_id
;
544 is_full_page_plugin_
= is_full_page_plugin
;
546 WillAttachToEmbedder();
549 int GuestViewBase::LogicalPixelsToPhysicalPixels(double logical_pixels
) {
550 DCHECK(logical_pixels
>= 0);
551 double zoom_factor
= GetEmbedderZoomFactor();
552 return lround(logical_pixels
* zoom_factor
);
555 double GuestViewBase::PhysicalPixelsToLogicalPixels(int physical_pixels
) {
556 DCHECK(physical_pixels
>= 0);
557 double zoom_factor
= GetEmbedderZoomFactor();
558 return physical_pixels
/ zoom_factor
;
561 void GuestViewBase::DidStopLoading() {
562 content::RenderViewHost
* rvh
= web_contents()->GetRenderViewHost();
564 if (IsPreferredSizeModeEnabled())
565 rvh
->EnablePreferredSizeMode();
566 if (!IsDragAndDropEnabled()) {
567 const char script
[] =
568 "window.addEventListener('dragstart', function() { "
569 " window.event.preventDefault(); "
571 rvh
->GetMainFrame()->ExecuteJavaScript(base::ASCIIToUTF16(script
));
573 GuestViewDidStopLoading();
576 void GuestViewBase::RenderViewReady() {
580 void GuestViewBase::WebContentsDestroyed() {
581 // Let the derived class know that its WebContents is in the process of
582 // being destroyed. web_contents() is still valid at this point.
583 // TODO(fsamuel): This allows for reentrant code into WebContents during
584 // destruction. This could potentially lead to bugs. Perhaps we should get rid
592 void GuestViewBase::DidNavigateMainFrame(
593 const content::LoadCommittedDetails
& details
,
594 const content::FrameNavigateParams
& params
) {
596 SetGuestZoomLevelToMatchEmbedder();
599 void GuestViewBase::ActivateContents(WebContents
* web_contents
) {
600 if (!attached() || !embedder_web_contents()->GetDelegate())
603 embedder_web_contents()->GetDelegate()->ActivateContents(
604 embedder_web_contents());
607 void GuestViewBase::DeactivateContents(WebContents
* web_contents
) {
608 if (!attached() || !embedder_web_contents()->GetDelegate())
611 embedder_web_contents()->GetDelegate()->DeactivateContents(
612 embedder_web_contents());
615 void GuestViewBase::ContentsMouseEvent(content::WebContents
* source
,
616 const gfx::Point
& location
,
618 if (!attached() || !embedder_web_contents()->GetDelegate())
621 embedder_web_contents()->GetDelegate()->ContentsMouseEvent(
622 embedder_web_contents(), location
, motion
);
625 void GuestViewBase::ContentsZoomChange(bool zoom_in
) {
626 ui_zoom::PageZoom::Zoom(
627 embedder_web_contents(),
628 zoom_in
? content::PAGE_ZOOM_IN
: content::PAGE_ZOOM_OUT
);
631 void GuestViewBase::HandleKeyboardEvent(
633 const content::NativeWebKeyboardEvent
& event
) {
637 // Send the keyboard events back to the embedder to reprocess them.
638 embedder_web_contents()->GetDelegate()->
639 HandleKeyboardEvent(embedder_web_contents(), event
);
642 void GuestViewBase::LoadingStateChanged(content::WebContents
* source
,
643 bool to_different_document
) {
644 if (!attached() || !embedder_web_contents()->GetDelegate())
647 embedder_web_contents()->GetDelegate()->LoadingStateChanged(
648 embedder_web_contents(), to_different_document
);
651 content::ColorChooser
* GuestViewBase::OpenColorChooser(
652 WebContents
* web_contents
,
654 const std::vector
<content::ColorSuggestion
>& suggestions
) {
655 if (!attached() || !embedder_web_contents()->GetDelegate())
658 return embedder_web_contents()->GetDelegate()->OpenColorChooser(
659 web_contents
, color
, suggestions
);
662 void GuestViewBase::RunFileChooser(WebContents
* web_contents
,
663 const content::FileChooserParams
& params
) {
664 if (!attached() || !embedder_web_contents()->GetDelegate())
667 embedder_web_contents()->GetDelegate()->RunFileChooser(web_contents
, params
);
670 bool GuestViewBase::ShouldFocusPageAfterCrash() {
671 // Focus is managed elsewhere.
675 bool GuestViewBase::PreHandleGestureEvent(content::WebContents
* source
,
676 const blink::WebGestureEvent
& event
) {
677 return event
.type
== blink::WebGestureEvent::GesturePinchBegin
||
678 event
.type
== blink::WebGestureEvent::GesturePinchUpdate
||
679 event
.type
== blink::WebGestureEvent::GesturePinchEnd
;
682 void GuestViewBase::UpdatePreferredSize(
683 content::WebContents
* target_web_contents
,
684 const gfx::Size
& pref_size
) {
685 // In theory it's not necessary to check IsPreferredSizeModeEnabled() because
686 // there will only be events if it was enabled in the first place. However,
687 // something else may have turned on preferred size mode, so double check.
688 DCHECK_EQ(web_contents(), target_web_contents
);
689 if (IsPreferredSizeModeEnabled()) {
690 OnPreferredSizeChanged(pref_size
);
694 void GuestViewBase::UpdateTargetURL(content::WebContents
* source
,
696 if (!attached() || !embedder_web_contents()->GetDelegate())
699 embedder_web_contents()->GetDelegate()->UpdateTargetURL(
700 embedder_web_contents(), url
);
703 GuestViewBase::~GuestViewBase() {
706 void GuestViewBase::OnZoomChanged(
707 const ui_zoom::ZoomController::ZoomChangedEventData
& data
) {
708 if (data
.web_contents
== embedder_web_contents()) {
709 // The embedder's zoom level has changed.
710 auto guest_zoom_controller
=
711 ui_zoom::ZoomController::FromWebContents(web_contents());
712 if (content::ZoomValuesEqual(data
.new_zoom_level
,
713 guest_zoom_controller
->GetZoomLevel())) {
716 // When the embedder's zoom level doesn't match the guest's, then update the
717 // guest's zoom level to match.
718 guest_zoom_controller
->SetZoomLevel(data
.new_zoom_level
);
720 EmbedderZoomChanged(data
.old_zoom_level
, data
.new_zoom_level
);
724 if (data
.web_contents
== web_contents()) {
725 // The guest's zoom level has changed.
726 GuestZoomChanged(data
.old_zoom_level
, data
.new_zoom_level
);
730 void GuestViewBase::DispatchEventToGuestProxy(Event
* event
) {
731 DispatchEvent(event
, guest_instance_id_
);
734 void GuestViewBase::DispatchEventToView(Event
* event
) {
736 (!CanRunInDetachedState() || !can_owner_receive_events())) {
737 pending_events_
.push_back(linked_ptr
<Event
>(event
));
741 DispatchEvent(event
, view_instance_id_
);
744 void GuestViewBase::DispatchEvent(Event
* event
, int instance_id
) {
745 scoped_ptr
<Event
> event_ptr(event
);
747 EventFilteringInfo info
;
748 info
.SetInstanceID(instance_id
);
749 scoped_ptr
<base::ListValue
> args(new base::ListValue());
750 args
->Append(event
->GetArguments().release());
752 EventRouter::DispatchEvent(
758 EventRouter::USER_GESTURE_UNKNOWN
,
762 void GuestViewBase::SendQueuedEvents() {
765 while (!pending_events_
.empty()) {
766 linked_ptr
<Event
> event_ptr
= pending_events_
.front();
767 pending_events_
.pop_front();
768 DispatchEvent(event_ptr
.release(), view_instance_id_
);
772 void GuestViewBase::CompleteInit(
773 scoped_ptr
<base::DictionaryValue
> create_params
,
774 const WebContentsCreatedCallback
& callback
,
775 content::WebContents
* guest_web_contents
) {
776 if (!guest_web_contents
) {
777 // The derived class did not create a WebContents so this class serves no
778 // purpose. Let's self-destruct.
780 callback
.Run(nullptr);
783 InitWithWebContents(*create_params
, guest_web_contents
);
784 callback
.Run(guest_web_contents
);
787 double GuestViewBase::GetEmbedderZoomFactor() {
788 if (!embedder_web_contents())
791 return content::ZoomLevelToZoomFactor(
792 ui_zoom::ZoomController::GetZoomLevelForWebContents(
793 embedder_web_contents()));
796 void GuestViewBase::SetUpSizing(const base::DictionaryValue
& params
) {
797 // Read the autosize parameters passed in from the embedder.
798 bool auto_size_enabled
= auto_size_enabled_
;
799 params
.GetBoolean(guestview::kAttributeAutoSize
, &auto_size_enabled
);
801 int max_height
= max_auto_size_
.height();
802 int max_width
= max_auto_size_
.width();
803 params
.GetInteger(guestview::kAttributeMaxHeight
, &max_height
);
804 params
.GetInteger(guestview::kAttributeMaxWidth
, &max_width
);
806 int min_height
= min_auto_size_
.height();
807 int min_width
= min_auto_size_
.width();
808 params
.GetInteger(guestview::kAttributeMinHeight
, &min_height
);
809 params
.GetInteger(guestview::kAttributeMinWidth
, &min_width
);
811 int normal_height
= normal_size_
.height();
812 int normal_width
= normal_size_
.width();
813 if (is_full_page_plugin()) {
814 // The initial size of a full page plugin should be set to fill the
815 // owner's visible viewport.
816 auto owner_size
= owner_web_contents()->GetRenderWidgetHostView()->
817 GetVisibleViewportSize();
818 normal_height
= owner_size
.height();
819 normal_width
= owner_size
.width();
821 // Set the normal size to the element size so that the guestview will fit
822 // the element initially if autosize is disabled.
823 double element_height
= 0.0;
824 double element_width
= 0.0;
825 params
.GetDouble(guestview::kElementHeight
, &element_height
);
826 params
.GetDouble(guestview::kElementWidth
, &element_width
);
828 // If the element size was provided in logical units (versus physical), then
829 // it will be converted to physical units.
830 bool element_size_is_logical
= false;
831 params
.GetBoolean(guestview::kElementSizeIsLogical
,
832 &element_size_is_logical
);
833 if (element_size_is_logical
) {
834 // Convert the element size from logical pixels to physical pixels.
835 normal_height
= LogicalPixelsToPhysicalPixels(element_height
);
836 normal_width
= LogicalPixelsToPhysicalPixels(element_width
);
838 normal_height
= lround(element_height
);
839 normal_width
= lround(element_width
);
843 SetSizeParams set_size_params
;
844 set_size_params
.enable_auto_size
.reset(new bool(auto_size_enabled
));
845 set_size_params
.min_size
.reset(new gfx::Size(min_width
, min_height
));
846 set_size_params
.max_size
.reset(new gfx::Size(max_width
, max_height
));
847 set_size_params
.normal_size
.reset(new gfx::Size(normal_width
, normal_height
));
849 // Call SetSize to apply all the appropriate validation and clipping of
851 SetSize(set_size_params
);
854 void GuestViewBase::SetGuestZoomLevelToMatchEmbedder() {
855 auto embedder_zoom_controller
=
856 ui_zoom::ZoomController::FromWebContents(owner_web_contents());
857 if (!embedder_zoom_controller
)
860 ui_zoom::ZoomController::FromWebContents(web_contents())
861 ->SetZoomLevel(embedder_zoom_controller
->GetZoomLevel());
864 void GuestViewBase::StartTrackingEmbedderZoomLevel() {
865 if (!ZoomPropagatesFromEmbedderToGuest())
868 auto embedder_zoom_controller
=
869 ui_zoom::ZoomController::FromWebContents(owner_web_contents());
870 // Chrome Apps do not have a ZoomController.
871 if (!embedder_zoom_controller
)
873 // Listen to the embedder's zoom changes.
874 embedder_zoom_controller
->AddObserver(this);
876 // Set the guest's initial zoom level to be equal to the embedder's.
877 SetGuestZoomLevelToMatchEmbedder();
880 void GuestViewBase::StopTrackingEmbedderZoomLevel() {
881 if (!attached() || !ZoomPropagatesFromEmbedderToGuest())
884 auto embedder_zoom_controller
=
885 ui_zoom::ZoomController::FromWebContents(owner_web_contents());
886 // Chrome Apps do not have a ZoomController.
887 if (!embedder_zoom_controller
)
889 embedder_zoom_controller
->RemoveObserver(this);
893 void GuestViewBase::RegisterGuestViewTypes() {
894 AppViewGuest::Register();
895 ExtensionOptionsGuest::Register();
896 ExtensionViewGuest::Register();
897 MimeHandlerViewGuest::Register();
898 SurfaceWorkerGuest::Register();
899 WebViewGuest::Register();
902 } // namespace extensions