Don't preload rarely seen large images
[chromium-blink-merge.git] / components / guest_view / browser / guest_view_base.cc
blobcffdd572065685564bcb1029d6e9e468e985be4a
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 "components/guest_view/browser/guest_view_base.h"
7 #include "base/command_line.h"
8 #include "base/lazy_instance.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "components/guest_view/browser/guest_view_event.h"
11 #include "components/guest_view/browser/guest_view_manager.h"
12 #include "components/guest_view/common/guest_view_constants.h"
13 #include "components/guest_view/common/guest_view_messages.h"
14 #include "components/ui/zoom/page_zoom.h"
15 #include "components/ui/zoom/zoom_controller.h"
16 #include "content/public/browser/navigation_details.h"
17 #include "content/public/browser/render_frame_host.h"
18 #include "content/public/browser/render_process_host.h"
19 #include "content/public/browser/render_view_host.h"
20 #include "content/public/browser/render_widget_host_view.h"
21 #include "content/public/browser/web_contents.h"
22 #include "content/public/common/content_switches.h"
23 #include "content/public/common/page_zoom.h"
24 #include "content/public/common/url_constants.h"
25 #include "third_party/WebKit/public/web/WebInputEvent.h"
27 using content::WebContents;
29 namespace content {
30 struct FrameNavigateParams;
33 namespace guest_view {
35 namespace {
37 using WebContentsGuestViewMap = std::map<const WebContents*, GuestViewBase*>;
38 static base::LazyInstance<WebContentsGuestViewMap> webcontents_guestview_map =
39 LAZY_INSTANCE_INITIALIZER;
41 } // namespace
43 SetSizeParams::SetSizeParams() {
45 SetSizeParams::~SetSizeParams() {
48 // This observer ensures that the GuestViewBase destroys itself when its
49 // embedder goes away. It also tracks when the embedder's fullscreen is
50 // toggled so the guest can change itself accordingly.
51 class GuestViewBase::OwnerContentsObserver : public WebContentsObserver {
52 public:
53 OwnerContentsObserver(GuestViewBase* guest,
54 content::WebContents* embedder_web_contents)
55 : WebContentsObserver(embedder_web_contents),
56 is_fullscreen_(false),
57 destroyed_(false),
58 guest_(guest) {}
60 ~OwnerContentsObserver() override {}
62 // WebContentsObserver implementation.
63 void WebContentsDestroyed() override {
64 // If the embedder is destroyed then destroy the guest.
65 Destroy();
68 void DidNavigateMainFrame(
69 const content::LoadCommittedDetails& details,
70 const content::FrameNavigateParams& params) override {
71 // If the embedder navigates to a different page then destroy the guest.
72 if (details.is_navigation_to_different_page())
73 Destroy();
76 void RenderProcessGone(base::TerminationStatus status) override {
77 if (destroyed_)
78 return;
80 GuestViewManager::FromBrowserContext(web_contents()->GetBrowserContext())
81 ->EmbedderWillBeDestroyed(
82 web_contents()->GetRenderProcessHost()->GetID());
84 // If the embedder process is destroyed, then destroy the guest.
85 Destroy();
88 void DidToggleFullscreenModeForTab(bool entered_fullscreen) override {
89 if (destroyed_)
90 return;
92 is_fullscreen_ = entered_fullscreen;
93 guest_->EmbedderFullscreenToggled(is_fullscreen_);
96 void MainFrameWasResized(bool width_changed) override {
97 if (destroyed_ || !web_contents()->GetDelegate())
98 return;
100 bool current_fullscreen =
101 web_contents()->GetDelegate()->IsFullscreenForTabOrPending(
102 web_contents());
103 if (is_fullscreen_ && !current_fullscreen) {
104 is_fullscreen_ = false;
105 guest_->EmbedderFullscreenToggled(is_fullscreen_);
109 private:
110 bool is_fullscreen_;
111 bool destroyed_;
112 GuestViewBase* guest_;
114 void Destroy() {
115 if (destroyed_)
116 return;
117 destroyed_ = true;
118 guest_->Destroy();
121 DISALLOW_COPY_AND_ASSIGN(OwnerContentsObserver);
124 // This observer ensures that the GuestViewBase destroys itself if its opener
125 // WebContents goes away before the GuestViewBase is attached.
126 class GuestViewBase::OpenerLifetimeObserver : public WebContentsObserver {
127 public:
128 OpenerLifetimeObserver(GuestViewBase* guest)
129 : WebContentsObserver(guest->GetOpener()->web_contents()),
130 guest_(guest) {}
132 ~OpenerLifetimeObserver() override {}
134 // WebContentsObserver implementation.
135 void WebContentsDestroyed() override {
136 if (guest_->attached())
137 return;
139 // If the opener is destroyed then destroy the guest.
140 guest_->Destroy();
143 private:
144 GuestViewBase* guest_;
146 DISALLOW_COPY_AND_ASSIGN(OpenerLifetimeObserver);
149 GuestViewBase::GuestViewBase(content::WebContents* owner_web_contents)
150 : owner_web_contents_(owner_web_contents),
151 browser_context_(owner_web_contents->GetBrowserContext()),
152 guest_instance_id_(
153 GuestViewManager::FromBrowserContext(browser_context_)->
154 GetNextInstanceID()),
155 view_instance_id_(kInstanceIDNone),
156 element_instance_id_(kInstanceIDNone),
157 initialized_(false),
158 is_being_destroyed_(false),
159 guest_host_(nullptr),
160 auto_size_enabled_(false),
161 is_full_page_plugin_(false),
162 guest_proxy_routing_id_(MSG_ROUTING_NONE),
163 weak_ptr_factory_(this) {
164 owner_host_ = GuestViewManager::FromBrowserContext(browser_context_)->
165 IsOwnedByExtension(this) ?
166 owner_web_contents->GetLastCommittedURL().host() : std::string();
169 void GuestViewBase::Init(const base::DictionaryValue& create_params,
170 const WebContentsCreatedCallback& callback) {
171 if (initialized_)
172 return;
173 initialized_ = true;
175 if (!GuestViewManager::FromBrowserContext(browser_context_)->
176 IsGuestAvailableToContext(this)) {
177 // The derived class did not create a WebContents so this class serves no
178 // purpose. Let's self-destruct.
179 delete this;
180 callback.Run(nullptr);
181 return;
184 scoped_ptr<base::DictionaryValue> params(create_params.DeepCopy());
185 CreateWebContents(create_params,
186 base::Bind(&GuestViewBase::CompleteInit,
187 weak_ptr_factory_.GetWeakPtr(),
188 base::Passed(&params),
189 callback));
192 void GuestViewBase::InitWithWebContents(
193 const base::DictionaryValue& create_params,
194 content::WebContents* guest_web_contents) {
195 DCHECK(guest_web_contents);
197 // Create a ZoomController to allow the guest's contents to be zoomed.
198 // Do this before adding the GuestView as a WebContents Observer so that
199 // the GuestView and its derived classes can re-configure the ZoomController
200 // after the latter has handled WebContentsObserver events (observers are
201 // notified of events in the same order they are added as observers). For
202 // example, GuestViewBase may wish to put its guest into isolated zoom mode
203 // in DidNavigateMainFrame, but since ZoomController always resets to default
204 // zoom mode on this event, GuestViewBase would need to do so after
205 // ZoomController::DidNavigateMainFrame has completed.
206 ui_zoom::ZoomController::CreateForWebContents(guest_web_contents);
208 // At this point, we have just created the guest WebContents, we need to add
209 // an observer to the owner WebContents. This observer will be responsible
210 // for destroying the guest WebContents if the owner goes away.
211 owner_contents_observer_.reset(
212 new OwnerContentsObserver(this, owner_web_contents_));
214 WebContentsObserver::Observe(guest_web_contents);
215 guest_web_contents->SetDelegate(this);
216 webcontents_guestview_map.Get().insert(
217 std::make_pair(guest_web_contents, this));
218 GuestViewManager::FromBrowserContext(browser_context_)->
219 AddGuest(guest_instance_id_, guest_web_contents);
221 // Populate the view instance ID if we have it on creation.
222 create_params.GetInteger(kParameterInstanceId, &view_instance_id_);
224 if (CanRunInDetachedState())
225 SetUpSizing(create_params);
227 // Observe guest zoom changes.
228 auto zoom_controller =
229 ui_zoom::ZoomController::FromWebContents(web_contents());
230 zoom_controller->AddObserver(this);
232 // Give the derived class an opportunity to perform additional initialization.
233 DidInitialize(create_params);
236 void GuestViewBase::LoadURLWithParams(
237 const content::NavigationController::LoadURLParams& load_params) {
238 int guest_proxy_routing_id = host()->LoadURLWithParams(load_params);
239 DCHECK(guest_proxy_routing_id_ == MSG_ROUTING_NONE ||
240 guest_proxy_routing_id == guest_proxy_routing_id_);
241 guest_proxy_routing_id_ = guest_proxy_routing_id;
244 void GuestViewBase::DispatchOnResizeEvent(const gfx::Size& old_size,
245 const gfx::Size& new_size) {
246 if (new_size == old_size)
247 return;
249 // Dispatch the onResize event.
250 scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue());
251 args->SetInteger(kOldWidth, old_size.width());
252 args->SetInteger(kOldHeight, old_size.height());
253 args->SetInteger(kNewWidth, new_size.width());
254 args->SetInteger(kNewHeight, new_size.height());
255 DispatchEventToGuestProxy(new GuestViewEvent(kEventResize, args.Pass()));
258 gfx::Size GuestViewBase::GetDefaultSize() const {
259 if (is_full_page_plugin()) {
260 // Full page plugins default to the size of the owner's viewport.
261 return owner_web_contents()
262 ->GetRenderWidgetHostView()
263 ->GetVisibleViewportSize();
264 } else {
265 return gfx::Size(kDefaultWidth, kDefaultHeight);
269 void GuestViewBase::SetSize(const SetSizeParams& params) {
270 bool enable_auto_size =
271 params.enable_auto_size ? *params.enable_auto_size : auto_size_enabled_;
272 gfx::Size min_size = params.min_size ? *params.min_size : min_auto_size_;
273 gfx::Size max_size = params.max_size ? *params.max_size : max_auto_size_;
275 if (params.normal_size)
276 normal_size_ = *params.normal_size;
278 min_auto_size_ = min_size;
279 min_auto_size_.SetToMin(max_size);
280 max_auto_size_ = max_size;
281 max_auto_size_.SetToMax(min_size);
283 enable_auto_size &= !min_auto_size_.IsEmpty() && !max_auto_size_.IsEmpty() &&
284 IsAutoSizeSupported();
286 content::RenderViewHost* rvh = web_contents()->GetRenderViewHost();
287 if (enable_auto_size) {
288 // Autosize is being enabled.
289 rvh->EnableAutoResize(min_auto_size_, max_auto_size_);
290 normal_size_.SetSize(0, 0);
291 } else {
292 // Autosize is being disabled.
293 // Use default width/height if missing from partially defined normal size.
294 if (normal_size_.width() && !normal_size_.height())
295 normal_size_.set_height(GetDefaultSize().height());
296 if (!normal_size_.width() && normal_size_.height())
297 normal_size_.set_width(GetDefaultSize().width());
299 gfx::Size new_size;
300 if (!normal_size_.IsEmpty()) {
301 new_size = normal_size_;
302 } else if (!guest_size_.IsEmpty()) {
303 new_size = guest_size_;
304 } else {
305 new_size = GetDefaultSize();
308 if (auto_size_enabled_) {
309 // Autosize was previously enabled.
310 rvh->DisableAutoResize(new_size);
311 GuestSizeChangedDueToAutoSize(guest_size_, new_size);
312 } else {
313 // Autosize was already disabled.
314 guest_host_->SizeContents(new_size);
317 DispatchOnResizeEvent(guest_size_, new_size);
318 guest_size_ = new_size;
321 auto_size_enabled_ = enable_auto_size;
324 // static
325 void GuestViewBase::CleanUp(int embedder_process_id, int view_instance_id) {
326 // TODO(paulmeyer): Add in any general GuestView cleanup work here.
329 // static
330 GuestViewBase* GuestViewBase::FromWebContents(const WebContents* web_contents) {
331 WebContentsGuestViewMap* guest_map = webcontents_guestview_map.Pointer();
332 auto it = guest_map->find(web_contents);
333 return it == guest_map->end() ? nullptr : it->second;
336 // static
337 GuestViewBase* GuestViewBase::From(int owner_process_id,
338 int guest_instance_id) {
339 auto host = content::RenderProcessHost::FromID(owner_process_id);
340 if (!host)
341 return nullptr;
343 content::WebContents* guest_web_contents =
344 GuestViewManager::FromBrowserContext(
345 host->GetBrowserContext())->
346 GetGuestByInstanceIDSafely(guest_instance_id, owner_process_id);
347 if (!guest_web_contents)
348 return nullptr;
350 return GuestViewBase::FromWebContents(guest_web_contents);
353 // static
354 WebContents* GuestViewBase::GetTopLevelWebContents(WebContents* web_contents) {
355 while (GuestViewBase* guest = FromWebContents(web_contents))
356 web_contents = guest->owner_web_contents();
357 return web_contents;
360 // static
361 bool GuestViewBase::IsGuest(WebContents* web_contents) {
362 return !!GuestViewBase::FromWebContents(web_contents);
365 bool GuestViewBase::IsAutoSizeSupported() const {
366 return false;
369 bool GuestViewBase::IsPreferredSizeModeEnabled() const {
370 return false;
373 bool GuestViewBase::IsDragAndDropEnabled() const {
374 return false;
377 bool GuestViewBase::ZoomPropagatesFromEmbedderToGuest() const {
378 return true;
381 content::WebContents* GuestViewBase::CreateNewGuestWindow(
382 const content::WebContents::CreateParams& create_params) {
383 auto guest_manager = GuestViewManager::FromBrowserContext(browser_context());
384 return guest_manager->CreateGuestWithWebContentsParams(
385 GetViewType(),
386 owner_web_contents(),
387 create_params);
390 void GuestViewBase::DidAttach(int guest_proxy_routing_id) {
391 DCHECK(guest_proxy_routing_id_ == MSG_ROUTING_NONE ||
392 guest_proxy_routing_id == guest_proxy_routing_id_);
393 guest_proxy_routing_id_ = guest_proxy_routing_id;
395 opener_lifetime_observer_.reset();
397 SetUpSizing(*attach_params());
399 // Give the derived class an opportunity to perform some actions.
400 DidAttachToEmbedder();
402 // Inform the associated GuestViewContainer that the contentWindow is ready.
403 embedder_web_contents()->Send(new GuestViewMsg_GuestAttached(
404 element_instance_id_,
405 guest_proxy_routing_id));
407 SendQueuedEvents();
410 void GuestViewBase::DidDetach() {
411 GuestViewManager::FromBrowserContext(browser_context_)->DetachGuest(this);
412 StopTrackingEmbedderZoomLevel();
413 owner_web_contents()->Send(new GuestViewMsg_GuestDetached(
414 element_instance_id_));
415 element_instance_id_ = kInstanceIDNone;
418 WebContents* GuestViewBase::GetOwnerWebContents() const {
419 return owner_web_contents_;
422 void GuestViewBase::GuestSizeChanged(const gfx::Size& new_size) {
423 if (!auto_size_enabled_)
424 return;
425 GuestSizeChangedDueToAutoSize(guest_size_, new_size);
426 DispatchOnResizeEvent(guest_size_, new_size);
427 guest_size_ = new_size;
430 const GURL& GuestViewBase::GetOwnerSiteURL() const {
431 return owner_web_contents()->GetLastCommittedURL();
434 void GuestViewBase::Destroy() {
435 if (is_being_destroyed_)
436 return;
438 is_being_destroyed_ = true;
440 // It is important to clear owner_web_contents_ after the call to
441 // StopTrackingEmbedderZoomLevel(), but before the rest of
442 // the statements in this function.
443 StopTrackingEmbedderZoomLevel();
444 owner_web_contents_ = nullptr;
446 DCHECK(web_contents());
448 // Give the derived class an opportunity to perform some cleanup.
449 WillDestroy();
451 // Invalidate weak pointers now so that bound callbacks cannot be called late
452 // into destruction. We must call this after WillDestroy because derived types
453 // may wish to access their openers.
454 weak_ptr_factory_.InvalidateWeakPtrs();
456 // Give the content module an opportunity to perform some cleanup.
457 guest_host_->WillDestroy();
458 guest_host_ = nullptr;
460 webcontents_guestview_map.Get().erase(web_contents());
461 GuestViewManager::FromBrowserContext(browser_context_)->
462 RemoveGuest(guest_instance_id_);
463 pending_events_.clear();
465 delete web_contents();
468 void GuestViewBase::SetAttachParams(const base::DictionaryValue& params) {
469 attach_params_.reset(params.DeepCopy());
470 attach_params_->GetInteger(kParameterInstanceId, &view_instance_id_);
473 void GuestViewBase::SetOpener(GuestViewBase* guest) {
474 if (guest && guest->IsViewType(GetViewType())) {
475 opener_ = guest->weak_ptr_factory_.GetWeakPtr();
476 if (!attached())
477 opener_lifetime_observer_.reset(new OpenerLifetimeObserver(this));
478 return;
480 opener_ = base::WeakPtr<GuestViewBase>();
481 opener_lifetime_observer_.reset();
484 void GuestViewBase::SetGuestHost(content::GuestHost* guest_host) {
485 guest_host_ = guest_host;
488 void GuestViewBase::WillAttach(content::WebContents* embedder_web_contents,
489 int element_instance_id,
490 bool is_full_page_plugin,
491 const base::Closure& callback) {
492 if (owner_web_contents_ != embedder_web_contents) {
493 DCHECK_EQ(owner_contents_observer_->web_contents(), owner_web_contents_);
494 // Stop tracking the old embedder's zoom level.
495 StopTrackingEmbedderZoomLevel();
496 owner_web_contents_ = embedder_web_contents;
497 owner_contents_observer_.reset(
498 new OwnerContentsObserver(this, embedder_web_contents));
499 owner_host_ = GuestViewManager::FromBrowserContext(browser_context_)->
500 IsOwnedByExtension(this) ?
501 owner_web_contents()->GetLastCommittedURL().host() : std::string();
504 // Start tracking the new embedder's zoom level.
505 StartTrackingEmbedderZoomLevel();
506 element_instance_id_ = element_instance_id;
507 is_full_page_plugin_ = is_full_page_plugin;
509 WillAttachToEmbedder();
511 // Completing attachment will resume suspended resource loads and then send
512 // queued events.
513 SignalWhenReady(callback);
516 void GuestViewBase::SignalWhenReady(const base::Closure& callback) {
517 // The default behavior is to call the |callback| immediately. Derived classes
518 // can implement an alternative signal for readiness.
519 callback.Run();
522 int GuestViewBase::LogicalPixelsToPhysicalPixels(double logical_pixels) const {
523 DCHECK(logical_pixels >= 0);
524 double zoom_factor = GetEmbedderZoomFactor();
525 return lround(logical_pixels * zoom_factor);
528 double GuestViewBase::PhysicalPixelsToLogicalPixels(int physical_pixels) const {
529 DCHECK(physical_pixels >= 0);
530 double zoom_factor = GetEmbedderZoomFactor();
531 return physical_pixels / zoom_factor;
534 void GuestViewBase::DidStopLoading() {
535 content::RenderViewHost* rvh = web_contents()->GetRenderViewHost();
537 if (IsPreferredSizeModeEnabled())
538 rvh->EnablePreferredSizeMode();
539 if (!IsDragAndDropEnabled()) {
540 const char script[] =
541 "window.addEventListener('dragstart', function() { "
542 " window.event.preventDefault(); "
543 "});";
544 rvh->GetMainFrame()->ExecuteJavaScript(base::ASCIIToUTF16(script));
546 GuestViewDidStopLoading();
549 void GuestViewBase::RenderViewReady() {
550 GuestReady();
553 void GuestViewBase::WebContentsDestroyed() {
554 // Let the derived class know that its WebContents is in the process of
555 // being destroyed. web_contents() is still valid at this point.
556 // TODO(fsamuel): This allows for reentrant code into WebContents during
557 // destruction. This could potentially lead to bugs. Perhaps we should get rid
558 // of this?
559 GuestDestroyed();
561 // Self-destruct.
562 delete this;
565 void GuestViewBase::DidNavigateMainFrame(
566 const content::LoadCommittedDetails& details,
567 const content::FrameNavigateParams& params) {
568 if (attached() && ZoomPropagatesFromEmbedderToGuest())
569 SetGuestZoomLevelToMatchEmbedder();
571 // TODO(lazyboy): This breaks guest visibility in --site-per-process because
572 // we do not take the widget's visibility into account. We need to also
573 // stay hidden during "visibility:none" state.
574 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
575 switches::kSitePerProcess)) {
576 web_contents()->WasShown();
580 void GuestViewBase::ActivateContents(WebContents* web_contents) {
581 if (!attached() || !embedder_web_contents()->GetDelegate())
582 return;
584 embedder_web_contents()->GetDelegate()->ActivateContents(
585 embedder_web_contents());
588 void GuestViewBase::DeactivateContents(WebContents* web_contents) {
589 if (!attached() || !embedder_web_contents()->GetDelegate())
590 return;
592 embedder_web_contents()->GetDelegate()->DeactivateContents(
593 embedder_web_contents());
596 void GuestViewBase::ContentsMouseEvent(content::WebContents* source,
597 const gfx::Point& location,
598 bool motion) {
599 if (!attached() || !embedder_web_contents()->GetDelegate())
600 return;
602 embedder_web_contents()->GetDelegate()->ContentsMouseEvent(
603 embedder_web_contents(), location, motion);
606 void GuestViewBase::ContentsZoomChange(bool zoom_in) {
607 ui_zoom::PageZoom::Zoom(
608 embedder_web_contents(),
609 zoom_in ? content::PAGE_ZOOM_IN : content::PAGE_ZOOM_OUT);
612 void GuestViewBase::HandleKeyboardEvent(
613 WebContents* source,
614 const content::NativeWebKeyboardEvent& event) {
615 if (!attached())
616 return;
618 // Send the keyboard events back to the embedder to reprocess them.
619 embedder_web_contents()->GetDelegate()->
620 HandleKeyboardEvent(embedder_web_contents(), event);
623 void GuestViewBase::LoadingStateChanged(content::WebContents* source,
624 bool to_different_document) {
625 if (!attached() || !embedder_web_contents()->GetDelegate())
626 return;
628 embedder_web_contents()->GetDelegate()->LoadingStateChanged(
629 embedder_web_contents(), to_different_document);
632 content::ColorChooser* GuestViewBase::OpenColorChooser(
633 WebContents* web_contents,
634 SkColor color,
635 const std::vector<content::ColorSuggestion>& suggestions) {
636 if (!attached() || !embedder_web_contents()->GetDelegate())
637 return nullptr;
639 return embedder_web_contents()->GetDelegate()->OpenColorChooser(
640 web_contents, color, suggestions);
643 void GuestViewBase::RunFileChooser(WebContents* web_contents,
644 const content::FileChooserParams& params) {
645 if (!attached() || !embedder_web_contents()->GetDelegate())
646 return;
648 embedder_web_contents()->GetDelegate()->RunFileChooser(web_contents, params);
651 bool GuestViewBase::ShouldFocusPageAfterCrash() {
652 // Focus is managed elsewhere.
653 return false;
656 bool GuestViewBase::PreHandleGestureEvent(content::WebContents* source,
657 const blink::WebGestureEvent& event) {
658 return event.type == blink::WebGestureEvent::GesturePinchBegin ||
659 event.type == blink::WebGestureEvent::GesturePinchUpdate ||
660 event.type == blink::WebGestureEvent::GesturePinchEnd;
663 void GuestViewBase::UpdatePreferredSize(
664 content::WebContents* target_web_contents,
665 const gfx::Size& pref_size) {
666 // In theory it's not necessary to check IsPreferredSizeModeEnabled() because
667 // there will only be events if it was enabled in the first place. However,
668 // something else may have turned on preferred size mode, so double check.
669 DCHECK_EQ(web_contents(), target_web_contents);
670 if (IsPreferredSizeModeEnabled()) {
671 OnPreferredSizeChanged(pref_size);
675 void GuestViewBase::UpdateTargetURL(content::WebContents* source,
676 const GURL& url) {
677 if (!attached() || !embedder_web_contents()->GetDelegate())
678 return;
680 embedder_web_contents()->GetDelegate()->UpdateTargetURL(
681 embedder_web_contents(), url);
684 bool GuestViewBase::ShouldResumeRequestsForCreatedWindow() {
685 return false;
688 GuestViewBase::~GuestViewBase() {
691 void GuestViewBase::OnZoomChanged(
692 const ui_zoom::ZoomController::ZoomChangedEventData& data) {
693 if (data.web_contents == embedder_web_contents()) {
694 // The embedder's zoom level has changed.
695 auto guest_zoom_controller =
696 ui_zoom::ZoomController::FromWebContents(web_contents());
697 if (content::ZoomValuesEqual(data.new_zoom_level,
698 guest_zoom_controller->GetZoomLevel())) {
699 return;
701 // When the embedder's zoom level doesn't match the guest's, then update the
702 // guest's zoom level to match.
703 guest_zoom_controller->SetZoomLevel(data.new_zoom_level);
705 EmbedderZoomChanged(data.old_zoom_level, data.new_zoom_level);
706 return;
709 if (data.web_contents == web_contents()) {
710 // The guest's zoom level has changed.
711 GuestZoomChanged(data.old_zoom_level, data.new_zoom_level);
715 void GuestViewBase::DispatchEventToGuestProxy(GuestViewEvent* event) {
716 event->Dispatch(this, guest_instance_id_);
719 void GuestViewBase::DispatchEventToView(GuestViewEvent* event) {
720 if (!attached() &&
721 (!CanRunInDetachedState() || !can_owner_receive_events())) {
722 pending_events_.push_back(linked_ptr<GuestViewEvent>(event));
723 return;
726 event->Dispatch(this, view_instance_id_);
729 void GuestViewBase::SendQueuedEvents() {
730 if (!attached())
731 return;
732 while (!pending_events_.empty()) {
733 linked_ptr<GuestViewEvent> event_ptr = pending_events_.front();
734 pending_events_.pop_front();
735 event_ptr.release()->Dispatch(this, view_instance_id_);
739 void GuestViewBase::CompleteInit(
740 scoped_ptr<base::DictionaryValue> create_params,
741 const WebContentsCreatedCallback& callback,
742 content::WebContents* guest_web_contents) {
743 if (!guest_web_contents) {
744 // The derived class did not create a WebContents so this class serves no
745 // purpose. Let's self-destruct.
746 delete this;
747 callback.Run(nullptr);
748 return;
750 InitWithWebContents(*create_params, guest_web_contents);
751 callback.Run(guest_web_contents);
754 double GuestViewBase::GetEmbedderZoomFactor() const {
755 if (!embedder_web_contents())
756 return 1.0;
758 return content::ZoomLevelToZoomFactor(
759 ui_zoom::ZoomController::GetZoomLevelForWebContents(
760 embedder_web_contents()));
763 void GuestViewBase::SetUpSizing(const base::DictionaryValue& params) {
764 // Read the autosize parameters passed in from the embedder.
765 bool auto_size_enabled = auto_size_enabled_;
766 params.GetBoolean(kAttributeAutoSize, &auto_size_enabled);
768 int max_height = max_auto_size_.height();
769 int max_width = max_auto_size_.width();
770 params.GetInteger(kAttributeMaxHeight, &max_height);
771 params.GetInteger(kAttributeMaxWidth, &max_width);
773 int min_height = min_auto_size_.height();
774 int min_width = min_auto_size_.width();
775 params.GetInteger(kAttributeMinHeight, &min_height);
776 params.GetInteger(kAttributeMinWidth, &min_width);
778 double element_height = 0.0;
779 double element_width = 0.0;
780 params.GetDouble(kElementHeight, &element_height);
781 params.GetDouble(kElementWidth, &element_width);
783 // Set the normal size to the element size so that the guestview will fit
784 // the element initially if autosize is disabled.
785 int normal_height = normal_size_.height();
786 int normal_width = normal_size_.width();
787 // If the element size was provided in logical units (versus physical), then
788 // it will be converted to physical units.
789 bool element_size_is_logical = false;
790 params.GetBoolean(kElementSizeIsLogical, &element_size_is_logical);
791 if (element_size_is_logical) {
792 // Convert the element size from logical pixels to physical pixels.
793 normal_height = LogicalPixelsToPhysicalPixels(element_height);
794 normal_width = LogicalPixelsToPhysicalPixels(element_width);
795 } else {
796 normal_height = lround(element_height);
797 normal_width = lround(element_width);
800 SetSizeParams set_size_params;
801 set_size_params.enable_auto_size.reset(new bool(auto_size_enabled));
802 set_size_params.min_size.reset(new gfx::Size(min_width, min_height));
803 set_size_params.max_size.reset(new gfx::Size(max_width, max_height));
804 set_size_params.normal_size.reset(new gfx::Size(normal_width, normal_height));
806 // Call SetSize to apply all the appropriate validation and clipping of
807 // values.
808 SetSize(set_size_params);
811 void GuestViewBase::SetGuestZoomLevelToMatchEmbedder() {
812 auto embedder_zoom_controller =
813 ui_zoom::ZoomController::FromWebContents(owner_web_contents());
814 if (!embedder_zoom_controller)
815 return;
817 ui_zoom::ZoomController::FromWebContents(web_contents())
818 ->SetZoomLevel(embedder_zoom_controller->GetZoomLevel());
821 void GuestViewBase::StartTrackingEmbedderZoomLevel() {
822 if (!ZoomPropagatesFromEmbedderToGuest())
823 return;
825 auto embedder_zoom_controller =
826 ui_zoom::ZoomController::FromWebContents(owner_web_contents());
827 // Chrome Apps do not have a ZoomController.
828 if (!embedder_zoom_controller)
829 return;
830 // Listen to the embedder's zoom changes.
831 embedder_zoom_controller->AddObserver(this);
833 // Set the guest's initial zoom level to be equal to the embedder's.
834 SetGuestZoomLevelToMatchEmbedder();
837 void GuestViewBase::StopTrackingEmbedderZoomLevel() {
838 if (!attached() || !ZoomPropagatesFromEmbedderToGuest())
839 return;
841 auto embedder_zoom_controller =
842 ui_zoom::ZoomController::FromWebContents(owner_web_contents());
843 // Chrome Apps do not have a ZoomController.
844 if (!embedder_zoom_controller)
845 return;
846 embedder_zoom_controller->RemoveObserver(this);
849 } // namespace guest_view