Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / components / guest_view / browser / guest_view_base.cc
blobc6172cb6ab131b814b2cb335ba69caed2b8ad628
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/lazy_instance.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "components/guest_view/browser/guest_view_event.h"
10 #include "components/guest_view/browser/guest_view_manager.h"
11 #include "components/guest_view/common/guest_view_constants.h"
12 #include "components/guest_view/common/guest_view_messages.h"
13 #include "components/ui/zoom/page_zoom.h"
14 #include "components/ui/zoom/zoom_controller.h"
15 #include "content/public/browser/navigation_details.h"
16 #include "content/public/browser/render_frame_host.h"
17 #include "content/public/browser/render_process_host.h"
18 #include "content/public/browser/render_view_host.h"
19 #include "content/public/browser/render_widget_host_view.h"
20 #include "content/public/browser/web_contents.h"
21 #include "content/public/common/browser_plugin_guest_mode.h"
22 #include "content/public/common/page_zoom.h"
23 #include "content/public/common/url_constants.h"
24 #include "third_party/WebKit/public/web/WebInputEvent.h"
26 using content::WebContents;
28 namespace content {
29 struct FrameNavigateParams;
32 namespace guest_view {
34 namespace {
36 using WebContentsGuestViewMap = std::map<const WebContents*, GuestViewBase*>;
37 static base::LazyInstance<WebContentsGuestViewMap> webcontents_guestview_map =
38 LAZY_INSTANCE_INITIALIZER;
40 } // namespace
42 SetSizeParams::SetSizeParams() {
44 SetSizeParams::~SetSizeParams() {
47 // This observer ensures that the GuestViewBase destroys itself when its
48 // embedder goes away. It also tracks when the embedder's fullscreen is
49 // toggled so the guest can change itself accordingly.
50 class GuestViewBase::OwnerContentsObserver : public WebContentsObserver {
51 public:
52 OwnerContentsObserver(GuestViewBase* guest,
53 WebContents* embedder_web_contents)
54 : WebContentsObserver(embedder_web_contents),
55 is_fullscreen_(false),
56 destroyed_(false),
57 guest_(guest) {}
59 ~OwnerContentsObserver() override {}
61 // WebContentsObserver implementation.
62 void WebContentsDestroyed() override {
63 // If the embedder is destroyed then destroy the guest.
64 Destroy();
67 void DidNavigateMainFrame(
68 const content::LoadCommittedDetails& details,
69 const content::FrameNavigateParams& params) override {
70 // If the embedder navigates to a different page then destroy the guest.
71 if (details.is_navigation_to_different_page())
72 Destroy();
75 void RenderProcessGone(base::TerminationStatus status) override {
76 if (destroyed_)
77 return;
78 // If the embedder process is destroyed, then destroy the guest.
79 Destroy();
82 void DidToggleFullscreenModeForTab(bool entered_fullscreen) override {
83 if (destroyed_)
84 return;
86 is_fullscreen_ = entered_fullscreen;
87 guest_->EmbedderFullscreenToggled(is_fullscreen_);
90 void MainFrameWasResized(bool width_changed) override {
91 if (destroyed_ || !web_contents()->GetDelegate())
92 return;
94 bool current_fullscreen =
95 web_contents()->GetDelegate()->IsFullscreenForTabOrPending(
96 web_contents());
97 if (is_fullscreen_ && !current_fullscreen) {
98 is_fullscreen_ = false;
99 guest_->EmbedderFullscreenToggled(is_fullscreen_);
103 private:
104 bool is_fullscreen_;
105 bool destroyed_;
106 GuestViewBase* guest_;
108 void Destroy() {
109 if (destroyed_)
110 return;
111 destroyed_ = true;
112 guest_->Destroy();
115 DISALLOW_COPY_AND_ASSIGN(OwnerContentsObserver);
118 // This observer ensures that the GuestViewBase destroys itself if its opener
119 // WebContents goes away before the GuestViewBase is attached.
120 class GuestViewBase::OpenerLifetimeObserver : public WebContentsObserver {
121 public:
122 OpenerLifetimeObserver(GuestViewBase* guest)
123 : WebContentsObserver(guest->GetOpener()->web_contents()),
124 guest_(guest) {}
126 ~OpenerLifetimeObserver() override {}
128 // WebContentsObserver implementation.
129 void WebContentsDestroyed() override {
130 if (guest_->attached())
131 return;
133 // If the opener is destroyed then destroy the guest.
134 guest_->Destroy();
137 private:
138 GuestViewBase* guest_;
140 DISALLOW_COPY_AND_ASSIGN(OpenerLifetimeObserver);
143 GuestViewBase::GuestViewBase(WebContents* owner_web_contents)
144 : owner_web_contents_(owner_web_contents),
145 browser_context_(owner_web_contents->GetBrowserContext()),
146 guest_instance_id_(GuestViewManager::FromBrowserContext(browser_context_)
147 ->GetNextInstanceID()),
148 view_instance_id_(kInstanceIDNone),
149 element_instance_id_(kInstanceIDNone),
150 initialized_(false),
151 is_being_destroyed_(false),
152 guest_host_(nullptr),
153 auto_size_enabled_(false),
154 is_full_page_plugin_(false),
155 guest_proxy_routing_id_(MSG_ROUTING_NONE),
156 weak_ptr_factory_(this) {
157 owner_host_ = GuestViewManager::FromBrowserContext(browser_context_)->
158 IsOwnedByExtension(this) ?
159 owner_web_contents->GetLastCommittedURL().host() : std::string();
162 void GuestViewBase::Init(const base::DictionaryValue& create_params,
163 const WebContentsCreatedCallback& callback) {
164 if (initialized_)
165 return;
166 initialized_ = true;
168 if (!GuestViewManager::FromBrowserContext(browser_context_)->
169 IsGuestAvailableToContext(this)) {
170 // The derived class did not create a WebContents so this class serves no
171 // purpose. Let's self-destruct.
172 delete this;
173 callback.Run(nullptr);
174 return;
177 scoped_ptr<base::DictionaryValue> params(create_params.DeepCopy());
178 CreateWebContents(create_params,
179 base::Bind(&GuestViewBase::CompleteInit,
180 weak_ptr_factory_.GetWeakPtr(),
181 base::Passed(&params),
182 callback));
185 void GuestViewBase::InitWithWebContents(
186 const base::DictionaryValue& create_params,
187 WebContents* guest_web_contents) {
188 DCHECK(guest_web_contents);
190 // Create a ZoomController to allow the guest's contents to be zoomed.
191 // Do this before adding the GuestView as a WebContents Observer so that
192 // the GuestView and its derived classes can re-configure the ZoomController
193 // after the latter has handled WebContentsObserver events (observers are
194 // notified of events in the same order they are added as observers). For
195 // example, GuestViewBase may wish to put its guest into isolated zoom mode
196 // in DidNavigateMainFrame, but since ZoomController always resets to default
197 // zoom mode on this event, GuestViewBase would need to do so after
198 // ZoomController::DidNavigateMainFrame has completed.
199 ui_zoom::ZoomController::CreateForWebContents(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_contents_observer_.reset(
205 new OwnerContentsObserver(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 // Populate the view instance ID if we have it on creation.
215 create_params.GetInteger(kParameterInstanceId, &view_instance_id_);
217 if (CanRunInDetachedState())
218 SetUpSizing(create_params);
220 // Observe guest zoom changes.
221 auto zoom_controller =
222 ui_zoom::ZoomController::FromWebContents(web_contents());
223 zoom_controller->AddObserver(this);
225 // Give the derived class an opportunity to perform additional initialization.
226 DidInitialize(create_params);
229 void GuestViewBase::LoadURLWithParams(
230 const content::NavigationController::LoadURLParams& load_params) {
231 int guest_proxy_routing_id = host()->LoadURLWithParams(load_params);
232 DCHECK(guest_proxy_routing_id_ == MSG_ROUTING_NONE ||
233 guest_proxy_routing_id == guest_proxy_routing_id_);
234 guest_proxy_routing_id_ = guest_proxy_routing_id;
237 void GuestViewBase::DispatchOnResizeEvent(const gfx::Size& old_size,
238 const gfx::Size& new_size) {
239 if (new_size == old_size)
240 return;
242 // Dispatch the onResize event.
243 scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue());
244 args->SetInteger(kOldWidth, old_size.width());
245 args->SetInteger(kOldHeight, old_size.height());
246 args->SetInteger(kNewWidth, new_size.width());
247 args->SetInteger(kNewHeight, new_size.height());
248 DispatchEventToGuestProxy(new GuestViewEvent(kEventResize, args.Pass()));
251 gfx::Size GuestViewBase::GetDefaultSize() const {
252 if (is_full_page_plugin()) {
253 // Full page plugins default to the size of the owner's viewport.
254 return owner_web_contents()
255 ->GetRenderWidgetHostView()
256 ->GetVisibleViewportSize();
257 } else {
258 return gfx::Size(kDefaultWidth, kDefaultHeight);
262 void GuestViewBase::SetSize(const SetSizeParams& params) {
263 bool enable_auto_size =
264 params.enable_auto_size ? *params.enable_auto_size : auto_size_enabled_;
265 gfx::Size min_size = params.min_size ? *params.min_size : min_auto_size_;
266 gfx::Size max_size = params.max_size ? *params.max_size : max_auto_size_;
268 if (params.normal_size)
269 normal_size_ = *params.normal_size;
271 min_auto_size_ = min_size;
272 min_auto_size_.SetToMin(max_size);
273 max_auto_size_ = max_size;
274 max_auto_size_.SetToMax(min_size);
276 enable_auto_size &= !min_auto_size_.IsEmpty() && !max_auto_size_.IsEmpty() &&
277 IsAutoSizeSupported();
279 content::RenderViewHost* rvh = web_contents()->GetRenderViewHost();
280 if (enable_auto_size) {
281 // Autosize is being enabled.
282 rvh->EnableAutoResize(min_auto_size_, max_auto_size_);
283 normal_size_.SetSize(0, 0);
284 } else {
285 // Autosize is being disabled.
286 // Use default width/height if missing from partially defined normal size.
287 if (normal_size_.width() && !normal_size_.height())
288 normal_size_.set_height(GetDefaultSize().height());
289 if (!normal_size_.width() && normal_size_.height())
290 normal_size_.set_width(GetDefaultSize().width());
292 gfx::Size new_size;
293 if (!normal_size_.IsEmpty()) {
294 new_size = normal_size_;
295 } else if (!guest_size_.IsEmpty()) {
296 new_size = guest_size_;
297 } else {
298 new_size = GetDefaultSize();
301 bool changed_due_to_auto_resize = false;
302 if (auto_size_enabled_) {
303 // Autosize was previously enabled.
304 rvh->DisableAutoResize(new_size);
305 changed_due_to_auto_resize = true;
306 } else {
307 // Autosize was already disabled.
308 guest_host_->SizeContents(new_size);
311 UpdateGuestSize(new_size, changed_due_to_auto_resize);
314 auto_size_enabled_ = enable_auto_size;
317 // static
318 void GuestViewBase::CleanUp(content::BrowserContext* browser_context,
319 int embedder_process_id,
320 int view_instance_id) {
321 // TODO(paulmeyer): Add in any general GuestView cleanup work here.
324 // static
325 GuestViewBase* GuestViewBase::FromWebContents(const WebContents* web_contents) {
326 WebContentsGuestViewMap* guest_map = webcontents_guestview_map.Pointer();
327 auto it = guest_map->find(web_contents);
328 return it == guest_map->end() ? nullptr : it->second;
331 // static
332 GuestViewBase* GuestViewBase::From(int owner_process_id,
333 int guest_instance_id) {
334 auto host = content::RenderProcessHost::FromID(owner_process_id);
335 if (!host)
336 return nullptr;
338 WebContents* guest_web_contents =
339 GuestViewManager::FromBrowserContext(host->GetBrowserContext())
340 ->GetGuestByInstanceIDSafely(guest_instance_id, owner_process_id);
341 if (!guest_web_contents)
342 return nullptr;
344 return GuestViewBase::FromWebContents(guest_web_contents);
347 // static
348 WebContents* GuestViewBase::GetTopLevelWebContents(WebContents* web_contents) {
349 while (GuestViewBase* guest = FromWebContents(web_contents))
350 web_contents = guest->owner_web_contents();
351 return web_contents;
354 // static
355 bool GuestViewBase::IsGuest(WebContents* web_contents) {
356 return !!GuestViewBase::FromWebContents(web_contents);
359 bool GuestViewBase::IsAutoSizeSupported() const {
360 return false;
363 bool GuestViewBase::IsPreferredSizeModeEnabled() const {
364 return false;
367 bool GuestViewBase::ZoomPropagatesFromEmbedderToGuest() const {
368 return true;
371 void GuestViewBase::SetContextMenuPosition(const gfx::Point& position) {}
373 WebContents* GuestViewBase::CreateNewGuestWindow(
374 const WebContents::CreateParams& create_params) {
375 auto guest_manager = GuestViewManager::FromBrowserContext(browser_context());
376 return guest_manager->CreateGuestWithWebContentsParams(
377 GetViewType(),
378 owner_web_contents(),
379 create_params);
382 void GuestViewBase::DidAttach(int guest_proxy_routing_id) {
383 DCHECK(guest_proxy_routing_id_ == MSG_ROUTING_NONE ||
384 guest_proxy_routing_id == guest_proxy_routing_id_);
385 guest_proxy_routing_id_ = guest_proxy_routing_id;
387 opener_lifetime_observer_.reset();
389 SetUpSizing(*attach_params());
391 // Give the derived class an opportunity to perform some actions.
392 DidAttachToEmbedder();
394 // Inform the associated GuestViewContainer that the contentWindow is ready.
395 embedder_web_contents()->Send(new GuestViewMsg_GuestAttached(
396 element_instance_id_,
397 guest_proxy_routing_id));
399 SendQueuedEvents();
402 void GuestViewBase::DidDetach() {
403 GuestViewManager::FromBrowserContext(browser_context_)->DetachGuest(this);
404 StopTrackingEmbedderZoomLevel();
405 owner_web_contents()->Send(new GuestViewMsg_GuestDetached(
406 element_instance_id_));
407 element_instance_id_ = kInstanceIDNone;
410 bool GuestViewBase::Find(int request_id,
411 const base::string16& search_text,
412 const blink::WebFindOptions& options) {
413 if (ShouldHandleFindRequestsForEmbedder()) {
414 web_contents()->Find(request_id, search_text, options);
415 return true;
417 return false;
420 bool GuestViewBase::StopFinding(content::StopFindAction action) {
421 if (ShouldHandleFindRequestsForEmbedder()) {
422 web_contents()->StopFinding(action);
423 return true;
425 return false;
428 WebContents* GuestViewBase::GetOwnerWebContents() const {
429 return owner_web_contents_;
432 void GuestViewBase::GuestSizeChanged(const gfx::Size& new_size) {
433 UpdateGuestSize(new_size, auto_size_enabled_);
436 const GURL& GuestViewBase::GetOwnerSiteURL() const {
437 return owner_web_contents()->GetLastCommittedURL();
440 void GuestViewBase::Destroy() {
441 if (is_being_destroyed_)
442 return;
444 is_being_destroyed_ = true;
446 // It is important to clear owner_web_contents_ after the call to
447 // StopTrackingEmbedderZoomLevel(), but before the rest of
448 // the statements in this function.
449 StopTrackingEmbedderZoomLevel();
450 owner_web_contents_ = nullptr;
452 DCHECK(web_contents());
454 // Give the derived class an opportunity to perform some cleanup.
455 WillDestroy();
457 // Invalidate weak pointers now so that bound callbacks cannot be called late
458 // into destruction. We must call this after WillDestroy because derived types
459 // may wish to access their openers.
460 weak_ptr_factory_.InvalidateWeakPtrs();
462 // Give the content module an opportunity to perform some cleanup.
463 guest_host_->WillDestroy();
464 guest_host_ = nullptr;
466 webcontents_guestview_map.Get().erase(web_contents());
467 GuestViewManager::FromBrowserContext(browser_context_)->
468 RemoveGuest(guest_instance_id_);
469 pending_events_.clear();
471 delete web_contents();
474 void GuestViewBase::SetAttachParams(const base::DictionaryValue& params) {
475 attach_params_.reset(params.DeepCopy());
476 attach_params_->GetInteger(kParameterInstanceId, &view_instance_id_);
479 void GuestViewBase::SetOpener(GuestViewBase* guest) {
480 if (guest && guest->IsViewType(GetViewType())) {
481 opener_ = guest->weak_ptr_factory_.GetWeakPtr();
482 if (!attached())
483 opener_lifetime_observer_.reset(new OpenerLifetimeObserver(this));
484 return;
486 opener_ = base::WeakPtr<GuestViewBase>();
487 opener_lifetime_observer_.reset();
490 void GuestViewBase::SetGuestHost(content::GuestHost* guest_host) {
491 guest_host_ = guest_host;
494 void GuestViewBase::WillAttach(WebContents* embedder_web_contents,
495 int element_instance_id,
496 bool is_full_page_plugin,
497 const base::Closure& callback) {
498 // Stop tracking the old embedder's zoom level.
499 if (owner_web_contents())
500 StopTrackingEmbedderZoomLevel();
502 if (owner_web_contents_ != embedder_web_contents) {
503 DCHECK_EQ(owner_contents_observer_->web_contents(), owner_web_contents_);
504 owner_web_contents_ = embedder_web_contents;
505 owner_contents_observer_.reset(
506 new OwnerContentsObserver(this, embedder_web_contents));
507 owner_host_ = GuestViewManager::FromBrowserContext(browser_context_)->
508 IsOwnedByExtension(this) ?
509 owner_web_contents()->GetLastCommittedURL().host() : std::string();
512 // Start tracking the new embedder's zoom level.
513 StartTrackingEmbedderZoomLevel();
514 element_instance_id_ = element_instance_id;
515 is_full_page_plugin_ = is_full_page_plugin;
517 WillAttachToEmbedder();
519 // Completing attachment will resume suspended resource loads and then send
520 // queued events.
521 SignalWhenReady(callback);
524 void GuestViewBase::SignalWhenReady(const base::Closure& callback) {
525 // The default behavior is to call the |callback| immediately. Derived classes
526 // can implement an alternative signal for readiness.
527 callback.Run();
530 bool GuestViewBase::ShouldHandleFindRequestsForEmbedder() const {
531 return false;
534 int GuestViewBase::LogicalPixelsToPhysicalPixels(double logical_pixels) const {
535 DCHECK(logical_pixels >= 0);
536 double zoom_factor = GetEmbedderZoomFactor();
537 return lround(logical_pixels * zoom_factor);
540 double GuestViewBase::PhysicalPixelsToLogicalPixels(int physical_pixels) const {
541 DCHECK(physical_pixels >= 0);
542 double zoom_factor = GetEmbedderZoomFactor();
543 return physical_pixels / zoom_factor;
546 void GuestViewBase::DidStopLoading() {
547 content::RenderViewHost* rvh = web_contents()->GetRenderViewHost();
549 if (IsPreferredSizeModeEnabled())
550 rvh->EnablePreferredSizeMode();
551 GuestViewDidStopLoading();
554 void GuestViewBase::RenderViewReady() {
555 GuestReady();
558 void GuestViewBase::WebContentsDestroyed() {
559 // Let the derived class know that its WebContents is in the process of
560 // being destroyed. web_contents() is still valid at this point.
561 // TODO(fsamuel): This allows for reentrant code into WebContents during
562 // destruction. This could potentially lead to bugs. Perhaps we should get rid
563 // of this?
564 GuestDestroyed();
566 // Self-destruct.
567 delete this;
570 void GuestViewBase::DidNavigateMainFrame(
571 const content::LoadCommittedDetails& details,
572 const content::FrameNavigateParams& params) {
573 if (attached() && ZoomPropagatesFromEmbedderToGuest())
574 SetGuestZoomLevelToMatchEmbedder();
576 // TODO(lazyboy): This breaks guest visibility in --site-per-process because
577 // we do not take the widget's visibility into account. We need to also
578 // stay hidden during "visibility:none" state.
579 if (content::BrowserPluginGuestMode::UseCrossProcessFramesForGuests()) {
580 web_contents()->WasShown();
584 void GuestViewBase::ActivateContents(WebContents* web_contents) {
585 if (!attached() || !embedder_web_contents()->GetDelegate())
586 return;
588 embedder_web_contents()->GetDelegate()->ActivateContents(
589 embedder_web_contents());
592 void GuestViewBase::DeactivateContents(WebContents* web_contents) {
593 if (!attached() || !embedder_web_contents()->GetDelegate())
594 return;
596 embedder_web_contents()->GetDelegate()->DeactivateContents(
597 embedder_web_contents());
600 void GuestViewBase::ContentsMouseEvent(WebContents* source,
601 const gfx::Point& location,
602 bool motion) {
603 if (!attached() || !embedder_web_contents()->GetDelegate())
604 return;
606 embedder_web_contents()->GetDelegate()->ContentsMouseEvent(
607 embedder_web_contents(), location, motion);
610 void GuestViewBase::ContentsZoomChange(bool zoom_in) {
611 ui_zoom::PageZoom::Zoom(
612 embedder_web_contents(),
613 zoom_in ? content::PAGE_ZOOM_IN : content::PAGE_ZOOM_OUT);
616 void GuestViewBase::HandleKeyboardEvent(
617 WebContents* source,
618 const content::NativeWebKeyboardEvent& event) {
619 if (!attached())
620 return;
622 // Send the keyboard events back to the embedder to reprocess them.
623 embedder_web_contents()->GetDelegate()->
624 HandleKeyboardEvent(embedder_web_contents(), event);
627 void GuestViewBase::LoadingStateChanged(WebContents* source,
628 bool to_different_document) {
629 if (!attached() || !embedder_web_contents()->GetDelegate())
630 return;
632 embedder_web_contents()->GetDelegate()->LoadingStateChanged(
633 embedder_web_contents(), to_different_document);
636 content::ColorChooser* GuestViewBase::OpenColorChooser(
637 WebContents* web_contents,
638 SkColor color,
639 const std::vector<content::ColorSuggestion>& suggestions) {
640 if (!attached() || !embedder_web_contents()->GetDelegate())
641 return nullptr;
643 return embedder_web_contents()->GetDelegate()->OpenColorChooser(
644 web_contents, color, suggestions);
647 void GuestViewBase::ResizeDueToAutoResize(WebContents* web_contents,
648 const gfx::Size& new_size) {
649 guest_host_->GuestResizeDueToAutoResize(new_size);
652 void GuestViewBase::RunFileChooser(WebContents* web_contents,
653 const content::FileChooserParams& params) {
654 if (!attached() || !embedder_web_contents()->GetDelegate())
655 return;
657 embedder_web_contents()->GetDelegate()->RunFileChooser(web_contents, params);
660 bool GuestViewBase::ShouldFocusPageAfterCrash() {
661 // Focus is managed elsewhere.
662 return false;
665 bool GuestViewBase::PreHandleGestureEvent(WebContents* source,
666 const blink::WebGestureEvent& event) {
667 return event.type == blink::WebGestureEvent::GesturePinchBegin ||
668 event.type == blink::WebGestureEvent::GesturePinchUpdate ||
669 event.type == blink::WebGestureEvent::GesturePinchEnd;
672 void GuestViewBase::UpdatePreferredSize(WebContents* target_web_contents,
673 const gfx::Size& pref_size) {
674 // In theory it's not necessary to check IsPreferredSizeModeEnabled() because
675 // there will only be events if it was enabled in the first place. However,
676 // something else may have turned on preferred size mode, so double check.
677 DCHECK_EQ(web_contents(), target_web_contents);
678 if (IsPreferredSizeModeEnabled()) {
679 OnPreferredSizeChanged(pref_size);
683 void GuestViewBase::UpdateTargetURL(WebContents* source, const GURL& url) {
684 if (!attached() || !embedder_web_contents()->GetDelegate())
685 return;
687 embedder_web_contents()->GetDelegate()->UpdateTargetURL(
688 embedder_web_contents(), url);
691 bool GuestViewBase::ShouldResumeRequestsForCreatedWindow() {
692 return false;
695 void GuestViewBase::FindReply(WebContents* source,
696 int request_id,
697 int number_of_matches,
698 const gfx::Rect& selection_rect,
699 int active_match_ordinal,
700 bool final_update) {
701 if (ShouldHandleFindRequestsForEmbedder() &&
702 attached() && embedder_web_contents()->GetDelegate()) {
703 embedder_web_contents()->GetDelegate()->FindReply(embedder_web_contents(),
704 request_id,
705 number_of_matches,
706 selection_rect,
707 active_match_ordinal,
708 final_update);
712 GuestViewBase::~GuestViewBase() {
715 void GuestViewBase::OnZoomChanged(
716 const ui_zoom::ZoomController::ZoomChangedEventData& data) {
717 if (data.web_contents == embedder_web_contents()) {
718 // The embedder's zoom level has changed.
719 auto guest_zoom_controller =
720 ui_zoom::ZoomController::FromWebContents(web_contents());
721 if (content::ZoomValuesEqual(data.new_zoom_level,
722 guest_zoom_controller->GetZoomLevel())) {
723 return;
725 // When the embedder's zoom level doesn't match the guest's, then update the
726 // guest's zoom level to match.
727 guest_zoom_controller->SetZoomLevel(data.new_zoom_level);
729 EmbedderZoomChanged(data.old_zoom_level, data.new_zoom_level);
730 return;
733 if (data.web_contents == web_contents()) {
734 // The guest's zoom level has changed.
735 GuestZoomChanged(data.old_zoom_level, data.new_zoom_level);
739 void GuestViewBase::DispatchEventToGuestProxy(GuestViewEvent* event) {
740 event->Dispatch(this, guest_instance_id_);
743 void GuestViewBase::DispatchEventToView(GuestViewEvent* event) {
744 if (!attached() &&
745 (!CanRunInDetachedState() || !can_owner_receive_events())) {
746 pending_events_.push_back(linked_ptr<GuestViewEvent>(event));
747 return;
750 event->Dispatch(this, view_instance_id_);
753 void GuestViewBase::SendQueuedEvents() {
754 if (!attached())
755 return;
756 while (!pending_events_.empty()) {
757 linked_ptr<GuestViewEvent> event_ptr = pending_events_.front();
758 pending_events_.pop_front();
759 event_ptr.release()->Dispatch(this, view_instance_id_);
763 void GuestViewBase::CompleteInit(
764 scoped_ptr<base::DictionaryValue> create_params,
765 const WebContentsCreatedCallback& callback,
766 WebContents* guest_web_contents) {
767 if (!guest_web_contents) {
768 // The derived class did not create a WebContents so this class serves no
769 // purpose. Let's self-destruct.
770 delete this;
771 callback.Run(nullptr);
772 return;
774 InitWithWebContents(*create_params, guest_web_contents);
775 callback.Run(guest_web_contents);
778 double GuestViewBase::GetEmbedderZoomFactor() const {
779 if (!embedder_web_contents())
780 return 1.0;
782 return content::ZoomLevelToZoomFactor(
783 ui_zoom::ZoomController::GetZoomLevelForWebContents(
784 embedder_web_contents()));
787 void GuestViewBase::SetUpSizing(const base::DictionaryValue& params) {
788 // Read the autosize parameters passed in from the embedder.
789 bool auto_size_enabled = auto_size_enabled_;
790 params.GetBoolean(kAttributeAutoSize, &auto_size_enabled);
792 int max_height = max_auto_size_.height();
793 int max_width = max_auto_size_.width();
794 params.GetInteger(kAttributeMaxHeight, &max_height);
795 params.GetInteger(kAttributeMaxWidth, &max_width);
797 int min_height = min_auto_size_.height();
798 int min_width = min_auto_size_.width();
799 params.GetInteger(kAttributeMinHeight, &min_height);
800 params.GetInteger(kAttributeMinWidth, &min_width);
802 double element_height = 0.0;
803 double element_width = 0.0;
804 params.GetDouble(kElementHeight, &element_height);
805 params.GetDouble(kElementWidth, &element_width);
807 // Set the normal size to the element size so that the guestview will fit
808 // the element initially if autosize is disabled.
809 int normal_height = normal_size_.height();
810 int normal_width = normal_size_.width();
811 // If the element size was provided in logical units (versus physical), then
812 // it will be converted to physical units.
813 bool element_size_is_logical = false;
814 params.GetBoolean(kElementSizeIsLogical, &element_size_is_logical);
815 if (element_size_is_logical) {
816 // Convert the element size from logical pixels to physical pixels.
817 normal_height = LogicalPixelsToPhysicalPixels(element_height);
818 normal_width = LogicalPixelsToPhysicalPixels(element_width);
819 } else {
820 normal_height = lround(element_height);
821 normal_width = lround(element_width);
824 SetSizeParams set_size_params;
825 set_size_params.enable_auto_size.reset(new bool(auto_size_enabled));
826 set_size_params.min_size.reset(new gfx::Size(min_width, min_height));
827 set_size_params.max_size.reset(new gfx::Size(max_width, max_height));
828 set_size_params.normal_size.reset(new gfx::Size(normal_width, normal_height));
830 // Call SetSize to apply all the appropriate validation and clipping of
831 // values.
832 SetSize(set_size_params);
835 void GuestViewBase::SetGuestZoomLevelToMatchEmbedder() {
836 auto embedder_zoom_controller =
837 ui_zoom::ZoomController::FromWebContents(owner_web_contents());
838 if (!embedder_zoom_controller)
839 return;
841 ui_zoom::ZoomController::FromWebContents(web_contents())
842 ->SetZoomLevel(embedder_zoom_controller->GetZoomLevel());
845 void GuestViewBase::StartTrackingEmbedderZoomLevel() {
846 if (!ZoomPropagatesFromEmbedderToGuest())
847 return;
849 auto embedder_zoom_controller =
850 ui_zoom::ZoomController::FromWebContents(owner_web_contents());
851 // Chrome Apps do not have a ZoomController.
852 if (!embedder_zoom_controller)
853 return;
854 // Listen to the embedder's zoom changes.
855 embedder_zoom_controller->AddObserver(this);
857 // Set the guest's initial zoom level to be equal to the embedder's.
858 SetGuestZoomLevelToMatchEmbedder();
861 void GuestViewBase::StopTrackingEmbedderZoomLevel() {
862 if (!attached() || !ZoomPropagatesFromEmbedderToGuest())
863 return;
865 auto embedder_zoom_controller =
866 ui_zoom::ZoomController::FromWebContents(owner_web_contents());
867 // Chrome Apps do not have a ZoomController.
868 if (!embedder_zoom_controller)
869 return;
870 embedder_zoom_controller->RemoveObserver(this);
873 void GuestViewBase::UpdateGuestSize(const gfx::Size& new_size,
874 bool due_to_auto_resize) {
875 if (due_to_auto_resize)
876 GuestSizeChangedDueToAutoSize(guest_size_, new_size);
877 DispatchOnResizeEvent(guest_size_, new_size);
878 guest_size_ = new_size;
881 } // namespace guest_view