diff options
author | fsamuel <fsamuel@chromium.org> | 2015-05-04 18:00:39 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-05-05 01:01:10 +0000 |
commit | 8dfa19acbffebaeafd38e8c3f4ef136c3fc83734 (patch) | |
tree | 9c62f75554ab826e9a49d0f2ee390b7d6cb2df1b /components | |
parent | ec5b7687d06564998e7f1b96465878a391edc723 (diff) | |
download | chromium_src-8dfa19acbffebaeafd38e8c3f4ef136c3fc83734.zip chromium_src-8dfa19acbffebaeafd38e8c3f4ef136c3fc83734.tar.gz chromium_src-8dfa19acbffebaeafd38e8c3f4ef136c3fc83734.tar.bz2 |
Move GuestView layer in browser to components
In addition to moving the browser-side of the GuestView layer into components, this CL also:
1. Replaces some loops to the top level web contents with GuestViewBase::GetTopLevelWebContents.
2. Installs the ExtensionsGuestViewMessageFilter in appshell.
3. Move some files out of extensions/common/guest_view to components/guest_view/common
BUG=444869
Review URL: https://codereview.chromium.org/1102173002
Cr-Commit-Position: refs/heads/master@{#328243}
Diffstat (limited to 'components')
33 files changed, 2837 insertions, 7 deletions
diff --git a/components/BUILD.gn b/components/BUILD.gn index 66864f0..7821039 100644 --- a/components/BUILD.gn +++ b/components/BUILD.gn @@ -48,6 +48,7 @@ group("all_components") { "//components/feedback", "//components/gcm_driver", "//components/google/core/browser", + "//components/guest_view:guest_view", "//components/history/content/browser", "//components/history/core/browser", "//components/history/core/common", diff --git a/components/components.gyp b/components/components.gyp index f8dee130..b59e82c 100644 --- a/components/components.gyp +++ b/components/components.gyp @@ -30,6 +30,7 @@ 'favicon_base.gypi', 'gcm_driver.gypi', 'google.gypi', + 'guest_view.gypi', 'handoff.gypi', 'history.gypi', 'infobars.gypi', diff --git a/components/components_tests.gyp b/components/components_tests.gyp index 26ef376..2ee73c9 100644 --- a/components/components_tests.gyp +++ b/components/components_tests.gyp @@ -217,6 +217,9 @@ 'google/core/browser/google_url_tracker_unittest.cc', 'google/core/browser/google_util_unittest.cc', ], + 'guest_view_unittest_sources': [ + 'guest_view/browser/guest_view_manager_unittest.cc' + ], 'history_unittest_sources': [ 'history/content/browser/content_history_backend_unittest.cc', 'history/core/browser/android/android_history_types_unittest.cc', @@ -755,6 +758,8 @@ 'components.gyp:gcm_driver', 'components.gyp:gcm_driver_test_support', 'components.gyp:google_core_browser', + 'components.gyp:guest_view', + 'components.gyp:guest_view_test_support', 'components.gyp:history_core_browser', 'components.gyp:history_core_common', 'components.gyp:history_core_test_support', @@ -844,6 +849,7 @@ 'sources': [ '<@(devtools_http_handler_unittest_sources)', '<@(error_page_unittest_sources)', + '<@(guest_view_unittest_sources)', '<@(navigation_interception_unittest_sources)', '<@(network_hints_unittest_sources)', '<@(power_unittest_sources)', diff --git a/components/constrained_window/BUILD.gn b/components/constrained_window/BUILD.gn index cbbb36f..55aae21 100644 --- a/components/constrained_window/BUILD.gn +++ b/components/constrained_window/BUILD.gn @@ -10,6 +10,7 @@ static_library("constrained_window") { ] deps = [ + "//components/guest_view:guest_view", "//components/web_modal", "//ui/views", "//skia", diff --git a/components/constrained_window/DEPS b/components/constrained_window/DEPS index 9f4c9d1..9ddd155 100644 --- a/components/constrained_window/DEPS +++ b/components/constrained_window/DEPS @@ -1,4 +1,5 @@ include_rules = [ + "+components/guest_view", "+components/web_modal", "+ui/base", "+ui/gfx", diff --git a/components/constrained_window/constrained_window_views.cc b/components/constrained_window/constrained_window_views.cc index 577ee03..2f3c3da 100644 --- a/components/constrained_window/constrained_window_views.cc +++ b/components/constrained_window/constrained_window_views.cc @@ -7,6 +7,7 @@ #include <algorithm> #include "components/constrained_window/constrained_window_views_client.h" +#include "components/guest_view/browser/guest_view_base.h" #include "components/web_modal/popup_manager.h" #include "components/web_modal/web_contents_modal_dialog_host.h" #include "ui/views/border.h" @@ -134,8 +135,8 @@ views::Widget* ShowWebModalDialogViews( DCHECK(constrained_window_views_client); // For embedded WebContents, use the embedder's WebContents for constrained // window. - content::WebContents* web_contents = constrained_window_views_client-> - GetEmbedderWebContents(initiator_web_contents); + content::WebContents* web_contents = + guest_view::GuestViewBase::GetTopLevelWebContents(initiator_web_contents); views::Widget* widget = CreateWebModalDialogViews(dialog, web_contents); web_modal::PopupManager* popup_manager = web_modal::PopupManager::FromWebContents(web_contents); diff --git a/components/constrained_window/constrained_window_views_client.h b/components/constrained_window/constrained_window_views_client.h index c5b1860..de58b2c 100644 --- a/components/constrained_window/constrained_window_views_client.h +++ b/components/constrained_window/constrained_window_views_client.h @@ -21,11 +21,6 @@ class ConstrainedWindowViewsClient { public: virtual ~ConstrainedWindowViewsClient() {} - // Returns the web contents that a constrained window should be modal to - // in the embedder's context. - virtual content::WebContents* GetEmbedderWebContents( - content::WebContents* initiator_web_contents) = 0; - // Returns the modal window host for the |parent| native window. virtual web_modal::ModalDialogHost* GetModalDialogHost( gfx::NativeWindow parent) = 0; diff --git a/components/guest_view.gypi b/components/guest_view.gypi new file mode 100644 index 0000000..dbbddcc --- /dev/null +++ b/components/guest_view.gypi @@ -0,0 +1,55 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +{ + 'targets': [ + { + 'target_name': 'guest_view', + 'type': 'static_library', + 'dependencies': [ + '../base/base.gyp:base', + '../content/content.gyp:content_browser', + '../content/content.gyp:content_common', + ], + 'include_dirs': [ + '..', + ], + 'sources': [ + 'guest_view/browser/guest_view.h', + 'guest_view/browser/guest_view_base.cc', + 'guest_view/browser/guest_view_base.h', + 'guest_view/browser/guest_view_event.cc', + 'guest_view/browser/guest_view_event.h', + 'guest_view/browser/guest_view_manager.cc', + 'guest_view/browser/guest_view_manager.h', + 'guest_view/browser/guest_view_manager_delegate.cc', + 'guest_view/browser/guest_view_manager_delegate.h', + 'guest_view/browser/guest_view_manager_factory.h', + 'guest_view/browser/guest_view_message_filter.cc', + 'guest_view/browser/guest_view_message_filter.h', + 'guest_view/common/guest_view_constants.cc', + 'guest_view/common/guest_view_constants.h', + 'guest_view/common/guest_view_message_generator.cc', + 'guest_view/common/guest_view_message_generator.h' + 'guest_view/common/guest_view_messages.h', + ], + }, + { + 'target_name': 'guest_view_test_support', + 'type': 'static_library', + 'dependencies': [ + '../base/base.gyp:base', + '../content/content.gyp:content_browser', + '../content/content.gyp:content_common', + '../content/content_shell_and_tests.gyp:test_support_content', + ], + 'include_dirs': [ + '..', + ], + 'sources': [ + 'guest_view/browser/test_guest_view_manager.h', + 'guest_view/browser/test_guest_view_manager.cc', + ], + } + ], +} diff --git a/components/guest_view/BUILD.gn b/components/guest_view/BUILD.gn new file mode 100644 index 0000000..0beda18 --- /dev/null +++ b/components/guest_view/BUILD.gn @@ -0,0 +1,46 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +static_library("guest_view") { + output_name = "guest_view" + sources = [ + "//components/guest_view/browser/guest_view.h", + "//components/guest_view/browser/guest_view_base.cc", + "//components/guest_view/browser/guest_view_base.h", + "//components/guest_view/browser/guest_view_event.cc", + "//components/guest_view/browser/guest_view_event.h", + "//components/guest_view/browser/guest_view_manager.cc", + "//components/guest_view/browser/guest_view_manager.h", + "//components/guest_view/browser/guest_view_manager_delegate.cc", + "//components/guest_view/browser/guest_view_manager_delegate.h", + "//components/guest_view/browser/guest_view_manager_factory.h", + "//components/guest_view/browser/guest_view_message_filter.cc", + "//components/guest_view/browser/guest_view_message_filter.h", + "//components/guest_view/common/guest_view_constants.cc", + "//components/guest_view/common/guest_view_constants.h", + "//components/guest_view/common/guest_view_message_generator.cc", + "//components/guest_view/common/guest_view_message_generator.h", + "//components/guest_view/common/guest_view_messages.h", + ] + + deps = [ + "//base", + "//content/public/browser", + "//content/public/common", + "//third_party/WebKit/public:blink", + ] +} + +static_library("test_support") { + testonly = true + sources = [ + "//components/guest_view/browser/test_guest_view_manager.cc", + "//components/guest_view/browser/test_guest_view_manager.h", + ] + + deps = [ + ":guest_view", + "//content/test:test_support", + ] +} diff --git a/components/guest_view/OWNERS b/components/guest_view/OWNERS new file mode 100644 index 0000000..f9575e8 --- /dev/null +++ b/components/guest_view/OWNERS @@ -0,0 +1,3 @@ +fsamuel@chromium.org +lazyboy@chromium.org +hanxi@chromium.org diff --git a/components/guest_view/browser/DEPS b/components/guest_view/browser/DEPS new file mode 100644 index 0000000..f0c51e4 --- /dev/null +++ b/components/guest_view/browser/DEPS @@ -0,0 +1,8 @@ +include_rules = [ + "+components/ui/zoom", + "+content/public/browser", + "+content/public/common", + "+content/public/test", + "+ipc", + '+third_party/WebKit/public/web/WebInputEvent.h', +] diff --git a/components/guest_view/browser/guest_view.h b/components/guest_view/browser/guest_view.h new file mode 100644 index 0000000..f99fe83 --- /dev/null +++ b/components/guest_view/browser/guest_view.h @@ -0,0 +1,70 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_GUEST_VIEW_BROWSER_GUEST_VIEW_H_ +#define COMPONENTS_GUEST_VIEW_BROWSER_GUEST_VIEW_H_ + +#include "components/guest_view/browser/guest_view_base.h" +#include "components/guest_view/browser/guest_view_manager.h" +#include "content/public/browser/render_frame_host.h" + +namespace guest_view { + +// A GuestView is the templated base class for out-of-process frames in the +// chrome layer. GuestView is templated on its derived type to allow for type- +// safe access. See GuestViewBase for more information. +template <typename T> +class GuestView : public GuestViewBase { + public: + static T* From(int embedder_process_id, int guest_instance_id) { + auto guest = GuestViewBase::From(embedder_process_id, guest_instance_id); + if (!guest) + return nullptr; + return guest->As<T>(); + } + + static T* FromWebContents(const content::WebContents* contents) { + auto guest = GuestViewBase::FromWebContents(contents); + return guest ? guest->As<T>() : nullptr; + } + + static T* FromFrameID(int render_process_id, int render_frame_id) { + auto render_frame_host = + content::RenderFrameHost::FromID(render_process_id, render_frame_id); + if (!render_frame_host) + return nullptr; + + auto web_contents = + content::WebContents::FromRenderFrameHost(render_frame_host); + return FromWebContents(web_contents); + } + + T* GetOpener() const { + GuestViewBase* guest = GuestViewBase::GetOpener(); + if (!guest) + return nullptr; + return guest->As<T>(); + } + + void SetOpener(T* opener) { + GuestViewBase::SetOpener(opener); + } + + // GuestViewBase implementation. + const char* GetViewType() const final { + return T::Type; + } + + protected: + explicit GuestView(content::WebContents* owner_web_contents) + : GuestViewBase(owner_web_contents) {} + ~GuestView() override {} + + private: + DISALLOW_COPY_AND_ASSIGN(GuestView); +}; + +} // namespace guest_view + +#endif // COMPONENTS_GUEST_VIEW_BROWSER_GUEST_VIEW_H_ diff --git a/components/guest_view/browser/guest_view_base.cc b/components/guest_view/browser/guest_view_base.cc new file mode 100644 index 0000000..1b1b5ed --- /dev/null +++ b/components/guest_view/browser/guest_view_base.cc @@ -0,0 +1,821 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/guest_view/browser/guest_view_base.h" + +#include "base/lazy_instance.h" +#include "base/strings/utf_string_conversions.h" +#include "components/guest_view/browser/guest_view_event.h" +#include "components/guest_view/browser/guest_view_manager.h" +#include "components/guest_view/common/guest_view_constants.h" +#include "components/guest_view/common/guest_view_messages.h" +#include "components/ui/zoom/page_zoom.h" +#include "components/ui/zoom/zoom_controller.h" +#include "content/public/browser/navigation_details.h" +#include "content/public/browser/render_frame_host.h" +#include "content/public/browser/render_process_host.h" +#include "content/public/browser/render_view_host.h" +#include "content/public/browser/render_widget_host_view.h" +#include "content/public/browser/web_contents.h" +#include "content/public/common/page_zoom.h" +#include "content/public/common/url_constants.h" +#include "third_party/WebKit/public/web/WebInputEvent.h" + +using content::WebContents; + +namespace content { +struct FrameNavigateParams; +} + +namespace guest_view { + +namespace { + +using WebContentsGuestViewMap = std::map<const WebContents*, GuestViewBase*>; +static base::LazyInstance<WebContentsGuestViewMap> webcontents_guestview_map = + LAZY_INSTANCE_INITIALIZER; + +} // namespace + +SetSizeParams::SetSizeParams() { +} +SetSizeParams::~SetSizeParams() { +} + +// This observer ensures that the GuestViewBase destroys itself when its +// embedder goes away. It also tracks when the embedder's fullscreen is +// toggled so the guest can change itself accordingly. +class GuestViewBase::OwnerContentsObserver : public WebContentsObserver { + public: + OwnerContentsObserver(GuestViewBase* guest, + content::WebContents* embedder_web_contents) + : WebContentsObserver(embedder_web_contents), + is_fullscreen_(false), + destroyed_(false), + guest_(guest) {} + + ~OwnerContentsObserver() override {} + + // WebContentsObserver implementation. + void WebContentsDestroyed() override { + // If the embedder is destroyed then destroy the guest. + Destroy(); + } + + void DidNavigateMainFrame( + const content::LoadCommittedDetails& details, + const content::FrameNavigateParams& params) override { + // If the embedder navigates to a different page then destroy the guest. + if (details.is_navigation_to_different_page()) + Destroy(); + } + + void RenderProcessGone(base::TerminationStatus status) override { + // If the embedder crashes, then destroy the guest. + Destroy(); + } + + void DidToggleFullscreenModeForTab(bool entered_fullscreen) override { + if (destroyed_) + return; + + is_fullscreen_ = entered_fullscreen; + guest_->EmbedderFullscreenToggled(is_fullscreen_); + } + + void MainFrameWasResized(bool width_changed) override { + if (destroyed_) + return; + + if (!web_contents()->GetDelegate()) + return; + + bool current_fullscreen = + web_contents()->GetDelegate()->IsFullscreenForTabOrPending( + web_contents()); + if (is_fullscreen_ && !current_fullscreen) { + is_fullscreen_ = false; + guest_->EmbedderFullscreenToggled(is_fullscreen_); + } + } + + private: + bool is_fullscreen_; + bool destroyed_; + GuestViewBase* guest_; + + void Destroy() { + if (destroyed_) + return; + + destroyed_ = true; + guest_->EmbedderWillBeDestroyed(); + guest_->Destroy(); + } + + DISALLOW_COPY_AND_ASSIGN(OwnerContentsObserver); +}; + +// This observer ensures that the GuestViewBase destroys itself when its +// embedder goes away. +class GuestViewBase::OpenerLifetimeObserver : public WebContentsObserver { + public: + OpenerLifetimeObserver(GuestViewBase* guest) + : WebContentsObserver(guest->GetOpener()->web_contents()), + guest_(guest) {} + + ~OpenerLifetimeObserver() override {} + + // WebContentsObserver implementation. + void WebContentsDestroyed() override { + if (guest_->attached()) + return; + + // If the opener is destroyed then destroy the guest. + guest_->Destroy(); + } + + private: + GuestViewBase* guest_; + + DISALLOW_COPY_AND_ASSIGN(OpenerLifetimeObserver); +}; + +GuestViewBase::GuestViewBase(content::WebContents* owner_web_contents) + : owner_web_contents_(owner_web_contents), + browser_context_(owner_web_contents->GetBrowserContext()), + guest_instance_id_( + GuestViewManager::FromBrowserContext(browser_context_)-> + GetNextInstanceID()), + view_instance_id_(kInstanceIDNone), + element_instance_id_(kInstanceIDNone), + initialized_(false), + is_being_destroyed_(false), + guest_host_(nullptr), + auto_size_enabled_(false), + is_full_page_plugin_(false), + guest_proxy_routing_id_(MSG_ROUTING_NONE), + weak_ptr_factory_(this) { + owner_host_ = GuestViewManager::FromBrowserContext(browser_context_)-> + IsOwnedByExtension(this) ? + owner_web_contents->GetLastCommittedURL().host() : std::string(); +} + +void GuestViewBase::Init(const base::DictionaryValue& create_params, + const WebContentsCreatedCallback& callback) { + if (initialized_) + return; + initialized_ = true; + + if (!GuestViewManager::FromBrowserContext(browser_context_)-> + IsGuestAvailableToContext(this)) { + // The derived class did not create a WebContents so this class serves no + // purpose. Let's self-destruct. + delete this; + callback.Run(nullptr); + return; + } + + scoped_ptr<base::DictionaryValue> params(create_params.DeepCopy()); + CreateWebContents(create_params, + base::Bind(&GuestViewBase::CompleteInit, + weak_ptr_factory_.GetWeakPtr(), + base::Passed(¶ms), + callback)); +} + +void GuestViewBase::InitWithWebContents( + const base::DictionaryValue& create_params, + content::WebContents* guest_web_contents) { + DCHECK(guest_web_contents); + + // Create a ZoomController to allow the guest's contents to be zoomed. + // Do this before adding the GuestView as a WebContents Observer so that + // the GuestView and its derived classes can re-configure the ZoomController + // after the latter has handled WebContentsObserver events (observers are + // notified of events in the same order they are added as observers). For + // example, GuestViewBase may wish to put its guest into isolated zoom mode + // in DidNavigateMainFrame, but since ZoomController always resets to default + // zoom mode on this event, GuestViewBase would need to do so after + // ZoomController::DidNavigateMainFrame has completed. + ui_zoom::ZoomController::CreateForWebContents(guest_web_contents); + + // At this point, we have just created the guest WebContents, we need to add + // an observer to the owner WebContents. This observer will be responsible + // for destroying the guest WebContents if the owner goes away. + owner_contents_observer_.reset( + new OwnerContentsObserver(this, owner_web_contents_)); + + WebContentsObserver::Observe(guest_web_contents); + guest_web_contents->SetDelegate(this); + webcontents_guestview_map.Get().insert( + std::make_pair(guest_web_contents, this)); + GuestViewManager::FromBrowserContext(browser_context_)-> + AddGuest(guest_instance_id_, guest_web_contents); + + // Populate the view instance ID if we have it on creation. + create_params.GetInteger(kParameterInstanceId, &view_instance_id_); + + if (CanRunInDetachedState()) + SetUpSizing(create_params); + + // Observe guest zoom changes. + auto zoom_controller = + ui_zoom::ZoomController::FromWebContents(web_contents()); + zoom_controller->AddObserver(this); + + // Give the derived class an opportunity to perform additional initialization. + DidInitialize(create_params); +} + +void GuestViewBase::LoadURLWithParams( + const content::NavigationController::LoadURLParams& load_params) { + int guest_proxy_routing_id = host()->LoadURLWithParams(load_params); + DCHECK(guest_proxy_routing_id_ == MSG_ROUTING_NONE || + guest_proxy_routing_id == guest_proxy_routing_id_); + guest_proxy_routing_id_ = guest_proxy_routing_id; +} + +void GuestViewBase::DispatchOnResizeEvent(const gfx::Size& old_size, + const gfx::Size& new_size) { + if (new_size == old_size) + return; + + // Dispatch the onResize event. + scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); + args->SetInteger(kOldWidth, old_size.width()); + args->SetInteger(kOldHeight, old_size.height()); + args->SetInteger(kNewWidth, new_size.width()); + args->SetInteger(kNewHeight, new_size.height()); + DispatchEventToGuestProxy(new GuestViewEvent(kEventResize, args.Pass())); +} + +gfx::Size GuestViewBase::GetDefaultSize() const { + if (is_full_page_plugin()) { + // Full page plugins default to the size of the owner's viewport. + return owner_web_contents() + ->GetRenderWidgetHostView() + ->GetVisibleViewportSize(); + } else { + return gfx::Size(kDefaultWidth, kDefaultHeight); + } +} + +void GuestViewBase::SetSize(const SetSizeParams& params) { + bool enable_auto_size = + params.enable_auto_size ? *params.enable_auto_size : auto_size_enabled_; + gfx::Size min_size = params.min_size ? *params.min_size : min_auto_size_; + gfx::Size max_size = params.max_size ? *params.max_size : max_auto_size_; + + if (params.normal_size) + normal_size_ = *params.normal_size; + + min_auto_size_ = min_size; + min_auto_size_.SetToMin(max_size); + max_auto_size_ = max_size; + max_auto_size_.SetToMax(min_size); + + enable_auto_size &= !min_auto_size_.IsEmpty() && !max_auto_size_.IsEmpty() && + IsAutoSizeSupported(); + + content::RenderViewHost* rvh = web_contents()->GetRenderViewHost(); + if (enable_auto_size) { + // Autosize is being enabled. + rvh->EnableAutoResize(min_auto_size_, max_auto_size_); + normal_size_.SetSize(0, 0); + } else { + // Autosize is being disabled. + // Use default width/height if missing from partially defined normal size. + if (normal_size_.width() && !normal_size_.height()) + normal_size_.set_height(GetDefaultSize().height()); + if (!normal_size_.width() && normal_size_.height()) + normal_size_.set_width(GetDefaultSize().width()); + + gfx::Size new_size; + if (!normal_size_.IsEmpty()) { + new_size = normal_size_; + } else if (!guest_size_.IsEmpty()) { + new_size = guest_size_; + } else { + new_size = GetDefaultSize(); + } + + if (auto_size_enabled_) { + // Autosize was previously enabled. + rvh->DisableAutoResize(new_size); + GuestSizeChangedDueToAutoSize(guest_size_, new_size); + } else { + // Autosize was already disabled. + guest_host_->SizeContents(new_size); + } + + DispatchOnResizeEvent(guest_size_, new_size); + guest_size_ = new_size; + } + + auto_size_enabled_ = enable_auto_size; +} + +// static +GuestViewBase* GuestViewBase::FromWebContents(const WebContents* web_contents) { + WebContentsGuestViewMap* guest_map = webcontents_guestview_map.Pointer(); + auto it = guest_map->find(web_contents); + return it == guest_map->end() ? nullptr : it->second; +} + +// static +GuestViewBase* GuestViewBase::From(int owner_process_id, + int guest_instance_id) { + auto host = content::RenderProcessHost::FromID(owner_process_id); + if (!host) + return nullptr; + + content::WebContents* guest_web_contents = + GuestViewManager::FromBrowserContext( + host->GetBrowserContext())-> + GetGuestByInstanceIDSafely(guest_instance_id, owner_process_id); + if (!guest_web_contents) + return nullptr; + + return GuestViewBase::FromWebContents(guest_web_contents); +} + +// static +WebContents* GuestViewBase::GetTopLevelWebContents(WebContents* web_contents) { + while (GuestViewBase* guest = FromWebContents(web_contents)) + web_contents = guest->owner_web_contents(); + return web_contents; +} + +// static +bool GuestViewBase::IsGuest(WebContents* web_contents) { + return !!GuestViewBase::FromWebContents(web_contents); +} + +bool GuestViewBase::IsAutoSizeSupported() const { + return false; +} + +bool GuestViewBase::IsPreferredSizeModeEnabled() const { + return false; +} + +bool GuestViewBase::IsDragAndDropEnabled() const { + return false; +} + +bool GuestViewBase::ZoomPropagatesFromEmbedderToGuest() const { + return true; +} + +content::WebContents* GuestViewBase::CreateNewGuestWindow( + const content::WebContents::CreateParams& create_params) { + auto guest_manager = GuestViewManager::FromBrowserContext(browser_context()); + return guest_manager->CreateGuestWithWebContentsParams( + GetViewType(), + owner_web_contents(), + create_params); +} + +void GuestViewBase::DidAttach(int guest_proxy_routing_id) { + DCHECK(guest_proxy_routing_id_ == MSG_ROUTING_NONE || + guest_proxy_routing_id == guest_proxy_routing_id_); + guest_proxy_routing_id_ = guest_proxy_routing_id; + + opener_lifetime_observer_.reset(); + + SetUpSizing(*attach_params()); + + // Give the derived class an opportunity to perform some actions. + DidAttachToEmbedder(); + + // Inform the associated GuestViewContainer that the contentWindow is ready. + embedder_web_contents()->Send(new GuestViewMsg_GuestAttached( + element_instance_id_, + guest_proxy_routing_id)); + + SendQueuedEvents(); +} + +void GuestViewBase::DidDetach() { + GuestViewManager::FromBrowserContext(browser_context_)->DetachGuest(this); + StopTrackingEmbedderZoomLevel(); + owner_web_contents()->Send(new GuestViewMsg_GuestDetached( + element_instance_id_)); + element_instance_id_ = kInstanceIDNone; +} + +WebContents* GuestViewBase::GetOwnerWebContents() const { + return owner_web_contents_; +} + +void GuestViewBase::GuestSizeChanged(const gfx::Size& new_size) { + if (!auto_size_enabled_) + return; + GuestSizeChangedDueToAutoSize(guest_size_, new_size); + DispatchOnResizeEvent(guest_size_, new_size); + guest_size_ = new_size; +} + +const GURL& GuestViewBase::GetOwnerSiteURL() const { + return owner_web_contents()->GetLastCommittedURL(); +} + +void GuestViewBase::Destroy() { + if (is_being_destroyed_) + return; + + is_being_destroyed_ = true; + + // It is important to clear owner_web_contents_ after the call to + // StopTrackingEmbedderZoomLevel(), but before the rest of + // the statements in this function. + StopTrackingEmbedderZoomLevel(); + owner_web_contents_ = nullptr; + + DCHECK(web_contents()); + + // Give the derived class an opportunity to perform some cleanup. + WillDestroy(); + + // Invalidate weak pointers now so that bound callbacks cannot be called late + // into destruction. We must call this after WillDestroy because derived types + // may wish to access their openers. + weak_ptr_factory_.InvalidateWeakPtrs(); + + // Give the content module an opportunity to perform some cleanup. + guest_host_->WillDestroy(); + guest_host_ = nullptr; + + webcontents_guestview_map.Get().erase(web_contents()); + GuestViewManager::FromBrowserContext(browser_context_)-> + RemoveGuest(guest_instance_id_); + pending_events_.clear(); + + delete web_contents(); +} + +void GuestViewBase::SetAttachParams(const base::DictionaryValue& params) { + attach_params_.reset(params.DeepCopy()); + attach_params_->GetInteger(kParameterInstanceId, &view_instance_id_); +} + +void GuestViewBase::SetOpener(GuestViewBase* guest) { + if (guest && guest->IsViewType(GetViewType())) { + opener_ = guest->weak_ptr_factory_.GetWeakPtr(); + if (!attached()) + opener_lifetime_observer_.reset(new OpenerLifetimeObserver(this)); + return; + } + opener_ = base::WeakPtr<GuestViewBase>(); + opener_lifetime_observer_.reset(); +} + +void GuestViewBase::SetGuestHost(content::GuestHost* guest_host) { + guest_host_ = guest_host; +} + +void GuestViewBase::WillAttach(content::WebContents* embedder_web_contents, + int element_instance_id, + bool is_full_page_plugin) { + if (owner_web_contents_ != embedder_web_contents) { + DCHECK_EQ(owner_contents_observer_->web_contents(), owner_web_contents_); + // Stop tracking the old embedder's zoom level. + StopTrackingEmbedderZoomLevel(); + owner_web_contents_ = embedder_web_contents; + owner_contents_observer_.reset( + new OwnerContentsObserver(this, embedder_web_contents)); + owner_host_ = GuestViewManager::FromBrowserContext(browser_context_)-> + IsOwnedByExtension(this) ? + owner_web_contents()->GetLastCommittedURL().host() : std::string(); + } + + // Start tracking the new embedder's zoom level. + StartTrackingEmbedderZoomLevel(); + element_instance_id_ = element_instance_id; + is_full_page_plugin_ = is_full_page_plugin; + + WillAttachToEmbedder(); +} + +int GuestViewBase::LogicalPixelsToPhysicalPixels(double logical_pixels) const { + DCHECK(logical_pixels >= 0); + double zoom_factor = GetEmbedderZoomFactor(); + return lround(logical_pixels * zoom_factor); +} + +double GuestViewBase::PhysicalPixelsToLogicalPixels(int physical_pixels) const { + DCHECK(physical_pixels >= 0); + double zoom_factor = GetEmbedderZoomFactor(); + return physical_pixels / zoom_factor; +} + +void GuestViewBase::DidStopLoading() { + content::RenderViewHost* rvh = web_contents()->GetRenderViewHost(); + + if (IsPreferredSizeModeEnabled()) + rvh->EnablePreferredSizeMode(); + if (!IsDragAndDropEnabled()) { + const char script[] = + "window.addEventListener('dragstart', function() { " + " window.event.preventDefault(); " + "});"; + rvh->GetMainFrame()->ExecuteJavaScript(base::ASCIIToUTF16(script)); + } + GuestViewDidStopLoading(); +} + +void GuestViewBase::RenderViewReady() { + GuestReady(); +} + +void GuestViewBase::WebContentsDestroyed() { + // Let the derived class know that its WebContents is in the process of + // being destroyed. web_contents() is still valid at this point. + // TODO(fsamuel): This allows for reentrant code into WebContents during + // destruction. This could potentially lead to bugs. Perhaps we should get rid + // of this? + GuestDestroyed(); + + // Self-destruct. + delete this; +} + +void GuestViewBase::DidNavigateMainFrame( + const content::LoadCommittedDetails& details, + const content::FrameNavigateParams& params) { + if (attached() && ZoomPropagatesFromEmbedderToGuest()) + SetGuestZoomLevelToMatchEmbedder(); +} + +void GuestViewBase::ActivateContents(WebContents* web_contents) { + if (!attached() || !embedder_web_contents()->GetDelegate()) + return; + + embedder_web_contents()->GetDelegate()->ActivateContents( + embedder_web_contents()); +} + +void GuestViewBase::DeactivateContents(WebContents* web_contents) { + if (!attached() || !embedder_web_contents()->GetDelegate()) + return; + + embedder_web_contents()->GetDelegate()->DeactivateContents( + embedder_web_contents()); +} + +void GuestViewBase::ContentsMouseEvent(content::WebContents* source, + const gfx::Point& location, + bool motion) { + if (!attached() || !embedder_web_contents()->GetDelegate()) + return; + + embedder_web_contents()->GetDelegate()->ContentsMouseEvent( + embedder_web_contents(), location, motion); +} + +void GuestViewBase::ContentsZoomChange(bool zoom_in) { + ui_zoom::PageZoom::Zoom( + embedder_web_contents(), + zoom_in ? content::PAGE_ZOOM_IN : content::PAGE_ZOOM_OUT); +} + +void GuestViewBase::HandleKeyboardEvent( + WebContents* source, + const content::NativeWebKeyboardEvent& event) { + if (!attached()) + return; + + // Send the keyboard events back to the embedder to reprocess them. + embedder_web_contents()->GetDelegate()-> + HandleKeyboardEvent(embedder_web_contents(), event); +} + +void GuestViewBase::LoadingStateChanged(content::WebContents* source, + bool to_different_document) { + if (!attached() || !embedder_web_contents()->GetDelegate()) + return; + + embedder_web_contents()->GetDelegate()->LoadingStateChanged( + embedder_web_contents(), to_different_document); +} + +content::ColorChooser* GuestViewBase::OpenColorChooser( + WebContents* web_contents, + SkColor color, + const std::vector<content::ColorSuggestion>& suggestions) { + if (!attached() || !embedder_web_contents()->GetDelegate()) + return nullptr; + + return embedder_web_contents()->GetDelegate()->OpenColorChooser( + web_contents, color, suggestions); +} + +void GuestViewBase::RunFileChooser(WebContents* web_contents, + const content::FileChooserParams& params) { + if (!attached() || !embedder_web_contents()->GetDelegate()) + return; + + embedder_web_contents()->GetDelegate()->RunFileChooser(web_contents, params); +} + +bool GuestViewBase::ShouldFocusPageAfterCrash() { + // Focus is managed elsewhere. + return false; +} + +bool GuestViewBase::PreHandleGestureEvent(content::WebContents* source, + const blink::WebGestureEvent& event) { + return event.type == blink::WebGestureEvent::GesturePinchBegin || + event.type == blink::WebGestureEvent::GesturePinchUpdate || + event.type == blink::WebGestureEvent::GesturePinchEnd; +} + +void GuestViewBase::UpdatePreferredSize( + content::WebContents* target_web_contents, + const gfx::Size& pref_size) { + // In theory it's not necessary to check IsPreferredSizeModeEnabled() because + // there will only be events if it was enabled in the first place. However, + // something else may have turned on preferred size mode, so double check. + DCHECK_EQ(web_contents(), target_web_contents); + if (IsPreferredSizeModeEnabled()) { + OnPreferredSizeChanged(pref_size); + } +} + +void GuestViewBase::UpdateTargetURL(content::WebContents* source, + const GURL& url) { + if (!attached() || !embedder_web_contents()->GetDelegate()) + return; + + embedder_web_contents()->GetDelegate()->UpdateTargetURL( + embedder_web_contents(), url); +} + +bool GuestViewBase::ShouldResumeRequestsForCreatedWindow() { + return false; +} + +GuestViewBase::~GuestViewBase() { +} + +void GuestViewBase::OnZoomChanged( + const ui_zoom::ZoomController::ZoomChangedEventData& data) { + if (data.web_contents == embedder_web_contents()) { + // The embedder's zoom level has changed. + auto guest_zoom_controller = + ui_zoom::ZoomController::FromWebContents(web_contents()); + if (content::ZoomValuesEqual(data.new_zoom_level, + guest_zoom_controller->GetZoomLevel())) { + return; + } + // When the embedder's zoom level doesn't match the guest's, then update the + // guest's zoom level to match. + guest_zoom_controller->SetZoomLevel(data.new_zoom_level); + + EmbedderZoomChanged(data.old_zoom_level, data.new_zoom_level); + return; + } + + if (data.web_contents == web_contents()) { + // The guest's zoom level has changed. + GuestZoomChanged(data.old_zoom_level, data.new_zoom_level); + } +} + +void GuestViewBase::DispatchEventToGuestProxy(GuestViewEvent* event) { + event->Dispatch(this, guest_instance_id_); +} + +void GuestViewBase::DispatchEventToView(GuestViewEvent* event) { + if (!attached() && + (!CanRunInDetachedState() || !can_owner_receive_events())) { + pending_events_.push_back(linked_ptr<GuestViewEvent>(event)); + return; + } + + event->Dispatch(this, view_instance_id_); +} + +void GuestViewBase::SendQueuedEvents() { + if (!attached()) + return; + while (!pending_events_.empty()) { + linked_ptr<GuestViewEvent> event_ptr = pending_events_.front(); + pending_events_.pop_front(); + event_ptr.release()->Dispatch(this, view_instance_id_); + } +} + +void GuestViewBase::CompleteInit( + scoped_ptr<base::DictionaryValue> create_params, + const WebContentsCreatedCallback& callback, + content::WebContents* guest_web_contents) { + if (!guest_web_contents) { + // The derived class did not create a WebContents so this class serves no + // purpose. Let's self-destruct. + delete this; + callback.Run(nullptr); + return; + } + InitWithWebContents(*create_params, guest_web_contents); + callback.Run(guest_web_contents); +} + +double GuestViewBase::GetEmbedderZoomFactor() const { + if (!embedder_web_contents()) + return 1.0; + + return content::ZoomLevelToZoomFactor( + ui_zoom::ZoomController::GetZoomLevelForWebContents( + embedder_web_contents())); +} + +void GuestViewBase::SetUpSizing(const base::DictionaryValue& params) { + // Read the autosize parameters passed in from the embedder. + bool auto_size_enabled = auto_size_enabled_; + params.GetBoolean(kAttributeAutoSize, &auto_size_enabled); + + int max_height = max_auto_size_.height(); + int max_width = max_auto_size_.width(); + params.GetInteger(kAttributeMaxHeight, &max_height); + params.GetInteger(kAttributeMaxWidth, &max_width); + + int min_height = min_auto_size_.height(); + int min_width = min_auto_size_.width(); + params.GetInteger(kAttributeMinHeight, &min_height); + params.GetInteger(kAttributeMinWidth, &min_width); + + double element_height = 0.0; + double element_width = 0.0; + params.GetDouble(kElementHeight, &element_height); + params.GetDouble(kElementWidth, &element_width); + + // Set the normal size to the element size so that the guestview will fit + // the element initially if autosize is disabled. + int normal_height = normal_size_.height(); + int normal_width = normal_size_.width(); + // If the element size was provided in logical units (versus physical), then + // it will be converted to physical units. + bool element_size_is_logical = false; + params.GetBoolean(kElementSizeIsLogical, &element_size_is_logical); + if (element_size_is_logical) { + // Convert the element size from logical pixels to physical pixels. + normal_height = LogicalPixelsToPhysicalPixels(element_height); + normal_width = LogicalPixelsToPhysicalPixels(element_width); + } else { + normal_height = lround(element_height); + normal_width = lround(element_width); + } + + SetSizeParams set_size_params; + set_size_params.enable_auto_size.reset(new bool(auto_size_enabled)); + set_size_params.min_size.reset(new gfx::Size(min_width, min_height)); + set_size_params.max_size.reset(new gfx::Size(max_width, max_height)); + set_size_params.normal_size.reset(new gfx::Size(normal_width, normal_height)); + + // Call SetSize to apply all the appropriate validation and clipping of + // values. + SetSize(set_size_params); +} + +void GuestViewBase::SetGuestZoomLevelToMatchEmbedder() { + auto embedder_zoom_controller = + ui_zoom::ZoomController::FromWebContents(owner_web_contents()); + if (!embedder_zoom_controller) + return; + + ui_zoom::ZoomController::FromWebContents(web_contents()) + ->SetZoomLevel(embedder_zoom_controller->GetZoomLevel()); +} + +void GuestViewBase::StartTrackingEmbedderZoomLevel() { + if (!ZoomPropagatesFromEmbedderToGuest()) + return; + + auto embedder_zoom_controller = + ui_zoom::ZoomController::FromWebContents(owner_web_contents()); + // Chrome Apps do not have a ZoomController. + if (!embedder_zoom_controller) + return; + // Listen to the embedder's zoom changes. + embedder_zoom_controller->AddObserver(this); + + // Set the guest's initial zoom level to be equal to the embedder's. + SetGuestZoomLevelToMatchEmbedder(); +} + +void GuestViewBase::StopTrackingEmbedderZoomLevel() { + if (!attached() || !ZoomPropagatesFromEmbedderToGuest()) + return; + + auto embedder_zoom_controller = + ui_zoom::ZoomController::FromWebContents(owner_web_contents()); + // Chrome Apps do not have a ZoomController. + if (!embedder_zoom_controller) + return; + embedder_zoom_controller->RemoveObserver(this); +} + +} // namespace guest_view diff --git a/components/guest_view/browser/guest_view_base.h b/components/guest_view/browser/guest_view_base.h new file mode 100644 index 0000000..74fb59c --- /dev/null +++ b/components/guest_view/browser/guest_view_base.h @@ -0,0 +1,458 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_GUEST_VIEW_BROWSER_GUEST_VIEW_BASE_H_ +#define COMPONENTS_GUEST_VIEW_BROWSER_GUEST_VIEW_BASE_H_ + +#include <queue> + +#include "base/memory/weak_ptr.h" +#include "base/values.h" +#include "components/guest_view/common/guest_view_constants.h" +#include "components/ui/zoom/zoom_observer.h" +#include "content/public/browser/browser_plugin_guest_delegate.h" +#include "content/public/browser/guest_host.h" +#include "content/public/browser/render_process_host_observer.h" +#include "content/public/browser/web_contents.h" +#include "content/public/browser/web_contents_delegate.h" +#include "content/public/browser/web_contents_observer.h" + +struct RendererContentSettingRules; + +namespace guest_view { + +class GuestViewEvent; + +// A struct of parameters for SetSize(). The parameters are all declared as +// scoped pointers since they are all optional. Null pointers indicate that the +// parameter has not been provided, and the last used value should be used. Note +// that when |enable_auto_size| is true, providing |normal_size| is not +// meaningful. This is because the normal size of the guestview is overridden +// whenever autosizing occurs. +struct SetSizeParams { + SetSizeParams(); + ~SetSizeParams(); + + scoped_ptr<bool> enable_auto_size; + scoped_ptr<gfx::Size> min_size; + scoped_ptr<gfx::Size> max_size; + scoped_ptr<gfx::Size> normal_size; +}; + +// A GuestViewBase is the base class browser-side API implementation for a +// <*view> tag. GuestViewBase maintains an association between a guest +// WebContents and an owner WebContents. It receives events issued from +// the guest and relays them to the owner. GuestViewBase tracks the lifetime +// of its owner. A GuestViewBase's owner is referred to as an embedder if +// it is attached to a container within the owner's WebContents. +class GuestViewBase : public content::BrowserPluginGuestDelegate, + public content::WebContentsDelegate, + public content::WebContentsObserver, + public ui_zoom::ZoomObserver { + public: + // Returns a *ViewGuest if this GuestView is of the given view type. + template <typename T> + T* As() { + if (IsViewType(T::Type)) + return static_cast<T*>(this); + + return nullptr; + } + + static GuestViewBase* FromWebContents( + const content::WebContents* web_contents); + + static GuestViewBase* From(int owner_process_id, int instance_id); + + // Given a |web_contents|, returns the top level owner WebContents. If + // |web_contents| does not belong to a GuestView, it will be returned + // unchanged. + static content::WebContents* GetTopLevelWebContents( + content::WebContents* web_contents); + + static bool IsGuest(content::WebContents* web_contents); + + virtual const char* GetViewType() const = 0; + + // This method is called after the guest has been attached to an embedder and + // suspended resource loads have been resumed. + // + // This method can be overriden by subclasses. This gives the derived class + // an opportunity to perform setup actions after attachment. + virtual void DidAttachToEmbedder() {} + + // This method is called after this GuestViewBase has been initiated. + // + // This gives the derived class an opportunity to perform additional + // initialization. + virtual void DidInitialize(const base::DictionaryValue& create_params) {} + + // This method is called when the initial set of frames within the page have + // completed loading. + virtual void GuestViewDidStopLoading() {} + + // This method is called before the embedder is destroyed. + // |owner_web_contents_| should still be valid during this call. This + // allows the derived class to perform some cleanup related to the embedder + // web contents. + virtual void EmbedderWillBeDestroyed() {} + + // This method is called when the embedder's zoom changes. + virtual void EmbedderZoomChanged(double old_zoom_level, + double new_zoom_level) {} + + // This method is called when the guest WebContents has been destroyed. This + // object will be destroyed after this call returns. + // + // This gives the derived class an opportunity to perform some cleanup. + virtual void GuestDestroyed() {} + + // This method is invoked when the guest RenderView is ready, e.g. because we + // recreated it after a crash or after reattachment. + // + // This gives the derived class an opportunity to perform some initialization + // work. + virtual void GuestReady() {} + + // This method is called when the guest's zoom changes. + virtual void GuestZoomChanged(double old_zoom_level, double new_zoom_level) {} + + // This method is called when embedder WebContents's fullscreen is toggled. + // + // If the guest asked the embedder to enter fullscreen, the guest uses this + // signal to exit fullscreen state. + virtual void EmbedderFullscreenToggled(bool entered_fullscreen) {} + + // This method is invoked when the contents auto-resized to give the container + // an opportunity to match it if it wishes. + // + // This gives the derived class an opportunity to inform its container element + // or perform other actions. + virtual void GuestSizeChangedDueToAutoSize(const gfx::Size& old_size, + const gfx::Size& new_size) {} + + // This method queries whether autosize is supported for this particular view. + // By default, autosize is not supported. Derived classes can override this + // behavior to support autosize. + virtual bool IsAutoSizeSupported() const; + + // This method is invoked when the contents preferred size changes. This will + // only ever fire if IsPreferredSizeSupported returns true. + virtual void OnPreferredSizeChanged(const gfx::Size& pref_size) {} + + // This method queries whether preferred size events are enabled for this + // view. By default, preferred size events are disabled, since they add a + // small amount of overhead. + virtual bool IsPreferredSizeModeEnabled() const; + + // This method queries whether drag-and-drop is enabled for this particular + // view. By default, drag-and-drop is disabled. Derived classes can override + // this behavior to enable drag-and-drop. + virtual bool IsDragAndDropEnabled() const; + + // This method is called immediately before suspended resource loads have been + // resumed on attachment to an embedder. + // + // This method can be overriden by subclasses. This gives the derived class + // an opportunity to perform setup actions before attachment. + virtual void WillAttachToEmbedder() {} + + // This method is called when the guest WebContents is about to be destroyed. + // + // This gives the derived class an opportunity to perform some cleanup prior + // to destruction. + virtual void WillDestroy() {} + + // This method is to be implemented by the derived class. This indicates + // whether zoom should propagate from the embedder to the guest content. + virtual bool ZoomPropagatesFromEmbedderToGuest() const; + + // This method is to be implemented by the derived class. Access to guest + // views are determined by the availability of the internal extension API + // used to implement the guest view. + // + // This should be the name of the API as it appears in the _api_features.json + // file. + virtual const char* GetAPINamespace() const = 0; + + // This method is to be implemented by the derived class. This method is the + // task prefix to show for a task produced by this GuestViewBase's derived + // type. + virtual int GetTaskPrefix() const = 0; + + // This method is to be implemented by the derived class. Given a set of + // initialization parameters, a concrete subclass of GuestViewBase can + // create a specialized WebContents that it returns back to GuestViewBase. + using WebContentsCreatedCallback = + base::Callback<void(content::WebContents*)>; + virtual void CreateWebContents( + const base::DictionaryValue& create_params, + const WebContentsCreatedCallback& callback) = 0; + + // This creates a WebContents and initializes |this| GuestViewBase to use the + // newly created WebContents. + void Init(const base::DictionaryValue& create_params, + const WebContentsCreatedCallback& callback); + + void InitWithWebContents(const base::DictionaryValue& create_params, + content::WebContents* guest_web_contents); + + void LoadURLWithParams( + const content::NavigationController::LoadURLParams& load_params); + + bool IsViewType(const char* const view_type) const { + return !strcmp(GetViewType(), view_type); + } + + // Used to toggle autosize mode for this GuestView, and set both the automatic + // and normal sizes. + void SetSize(const SetSizeParams& params); + + bool initialized() const { return initialized_; } + + content::WebContents* embedder_web_contents() const { + return attached() ? owner_web_contents_ : nullptr; + } + + content::WebContents* owner_web_contents() const { + return owner_web_contents_; + } + + content::GuestHost* host() const { + return guest_host_; + } + + // Returns the parameters associated with the element hosting this GuestView + // passed in from JavaScript. + base::DictionaryValue* attach_params() const { return attach_params_.get(); } + + // Returns whether this guest has an associated embedder. + bool attached() const { + return element_instance_id_ != kInstanceIDNone; + } + + // Returns the instance ID of the <*view> element. + int view_instance_id() const { return view_instance_id_; } + + // Returns the instance ID of this GuestViewBase. + int guest_instance_id() const { return guest_instance_id_; } + + // Returns the instance ID of the GuestViewBase's element. + int element_instance_id() const { return element_instance_id_; } + + bool can_owner_receive_events() const { return !!view_instance_id_; } + + // Returns the user browser context of the embedder. + content::BrowserContext* browser_context() const { return browser_context_; } + + GuestViewBase* GetOpener() const { + return opener_.get(); + } + + // Returns the URL of the owner WebContents. + const GURL& GetOwnerSiteURL() const; + + // Returns the host of the owner WebContents. For extensions, this is the + // extension ID. + std::string owner_host() const { return owner_host_; } + + // Whether the guest view is inside a plugin document. + bool is_full_page_plugin() const { return is_full_page_plugin_; } + + // Returns the routing ID of the guest proxy in the owner's renderer process. + // This value is only valid after attachment or first navigation. + int proxy_routing_id() const { return guest_proxy_routing_id_; } + + // Destroy this guest. + void Destroy(); + + // Saves the attach state of the custom element hosting this GuestView. + void SetAttachParams(const base::DictionaryValue& params); + void SetOpener(GuestViewBase* opener); + + // BrowserPluginGuestDelegate implementation. + content::WebContents* CreateNewGuestWindow( + const content::WebContents::CreateParams& create_params) final; + void DidAttach(int guest_proxy_routing_id) final; + void DidDetach() final; + content::WebContents* GetOwnerWebContents() const final; + void GuestSizeChanged(const gfx::Size& new_size) final; + void SetGuestHost(content::GuestHost* guest_host) final; + void WillAttach(content::WebContents* embedder_web_contents, + int browser_plugin_instance_id, + bool is_full_page_plugin) final; + + // ui_zoom::ZoomObserver implementation. + void OnZoomChanged( + const ui_zoom::ZoomController::ZoomChangedEventData& data) final; + + // Dispatches an event to the guest proxy. + void DispatchEventToGuestProxy(GuestViewEvent* event); + + // Dispatches an event to the view. + void DispatchEventToView(GuestViewEvent* event); + + protected: + explicit GuestViewBase(content::WebContents* owner_web_contents); + + ~GuestViewBase() override; + + // Convert sizes in pixels from logical to physical numbers of pixels. + // Note that a size can consist of a fractional number of logical pixels + // (hence |logical_pixels| is represented as a double), but will always + // consist of an integral number of physical pixels (hence the return value + // is represented as an int). + int LogicalPixelsToPhysicalPixels(double logical_pixels) const; + + // Convert sizes in pixels from physical to logical numbers of pixels. + // Note that a size can consist of a fractional number of logical pixels + // (hence the return value is represented as a double), but will always + // consist of an integral number of physical pixels (hence |physical_pixels| + // is represented as an int). + double PhysicalPixelsToLogicalPixels(int physical_pixels) const; + + // WebContentsObserver implementation. + void DidStopLoading() final; + void RenderViewReady() final; + void WebContentsDestroyed() final; + void DidNavigateMainFrame( + const content::LoadCommittedDetails& details, + const content::FrameNavigateParams& params) override; + + // WebContentsDelegate implementation. + void ActivateContents(content::WebContents* contents) final; + void DeactivateContents(content::WebContents* contents) final; + void ContentsMouseEvent(content::WebContents* source, + const gfx::Point& location, + bool motion) override; + void ContentsZoomChange(bool zoom_in) override; + void HandleKeyboardEvent( + content::WebContents* source, + const content::NativeWebKeyboardEvent& event) override; + void LoadingStateChanged(content::WebContents* source, + bool to_different_document) final; + content::ColorChooser* OpenColorChooser( + content::WebContents* web_contents, + SkColor color, + const std::vector<content::ColorSuggestion>& suggestions) override; + void RunFileChooser(content::WebContents* web_contents, + const content::FileChooserParams& params) override; + bool ShouldFocusPageAfterCrash() final; + bool PreHandleGestureEvent(content::WebContents* source, + const blink::WebGestureEvent& event) override; + void UpdatePreferredSize(content::WebContents* web_contents, + const gfx::Size& pref_size) final; + void UpdateTargetURL(content::WebContents* source, const GURL& url) override; + bool ShouldResumeRequestsForCreatedWindow() override; + + void SetGuestZoomLevelToMatchEmbedder(); + + private: + class OwnerContentsObserver; + + class OpenerLifetimeObserver; + + void SendQueuedEvents(); + + void CompleteInit(scoped_ptr<base::DictionaryValue> create_params, + const WebContentsCreatedCallback& callback, + content::WebContents* guest_web_contents); + + // Dispatches the onResize event to the embedder. + void DispatchOnResizeEvent(const gfx::Size& old_size, + const gfx::Size& new_size); + + // Returns the default size of the guestview. + gfx::Size GetDefaultSize() const; + + // Get the zoom factor for the embedder's web contents. + double GetEmbedderZoomFactor() const; + + void SetUpSizing(const base::DictionaryValue& params); + + void StartTrackingEmbedderZoomLevel(); + void StopTrackingEmbedderZoomLevel(); + + // This guest tracks the lifetime of the WebContents specified by + // |owner_web_contents_|. If |owner_web_contents_| is destroyed then this + // guest will also self-destruct. + content::WebContents* owner_web_contents_; + std::string owner_host_; + content::BrowserContext* const browser_context_; + + // |guest_instance_id_| is a profile-wide unique identifier for a guest + // WebContents. + const int guest_instance_id_; + + // |view_instance_id_| is an identifier that's unique within a particular + // embedder RenderViewHost for a particular <*view> instance. + int view_instance_id_; + + // |element_instance_id_| is an identifer that's unique to a particular + // GuestViewContainer element. + int element_instance_id_; + + // |initialized_| indicates whether GuestViewBase::Init has been called for + // this object. + bool initialized_; + + // Indicates that this guest is in the process of being destroyed. + bool is_being_destroyed_; + + // This is a queue of Events that are destined to be sent to the embedder once + // the guest is attached to a particular embedder. + std::deque<linked_ptr<GuestViewEvent> > pending_events_; + + // The opener guest view. + base::WeakPtr<GuestViewBase> opener_; + + // The parameters associated with the element hosting this GuestView that + // are passed in from JavaScript. This will typically be the view instance ID, + // and element-specific parameters. These parameters are passed along to new + // guests that are created from this guest. + scoped_ptr<base::DictionaryValue> attach_params_; + + // This observer ensures that this guest self-destructs if the embedder goes + // away. + scoped_ptr<OwnerContentsObserver> owner_contents_observer_; + + // This observer ensures that if the guest is unattached and its opener goes + // away then this guest also self-destructs. + scoped_ptr<OpenerLifetimeObserver> opener_lifetime_observer_; + + // The size of the guest content. Note: In autosize mode, the container + // element may not match the size of the guest. + gfx::Size guest_size_; + + // A pointer to the guest_host. + content::GuestHost* guest_host_; + + // Indicates whether autosize mode is enabled or not. + bool auto_size_enabled_; + + // The maximum size constraints of the container element in autosize mode. + gfx::Size max_auto_size_; + + // The minimum size constraints of the container element in autosize mode. + gfx::Size min_auto_size_; + + // The size that will be used when autosize mode is disabled. + gfx::Size normal_size_; + + // Whether the guest view is inside a plugin document. + bool is_full_page_plugin_; + + // The routing ID of the proxy to the guest in the owner's renderer process. + int guest_proxy_routing_id_; + + // This is used to ensure pending tasks will not fire after this object is + // destroyed. + base::WeakPtrFactory<GuestViewBase> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(GuestViewBase); +}; + +} // namespace guest_view + +#endif // COMPONENTS_GUEST_VIEW_BROWSER_GUEST_VIEW_BASE_H_ diff --git a/components/guest_view/browser/guest_view_event.cc b/components/guest_view/browser/guest_view_event.cc new file mode 100644 index 0000000..a88d62f --- /dev/null +++ b/components/guest_view/browser/guest_view_event.cc @@ -0,0 +1,28 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/guest_view/browser/guest_view_event.h" + +#include "components/guest_view/browser/guest_view_base.h" +#include "components/guest_view/browser/guest_view_manager.h" + +namespace guest_view { + +GuestViewEvent::GuestViewEvent(const std::string& name, + scoped_ptr<base::DictionaryValue> args) + : name_(name), + args_(args.Pass()) { +} + +GuestViewEvent::~GuestViewEvent() { +} + +void GuestViewEvent::Dispatch(GuestViewBase* guest, int instance_id) { + GuestViewManager::FromBrowserContext(guest->browser_context())-> + DispatchEvent(name_, args_.Pass(), guest, instance_id); + + delete this; +} + +} // namespace guest_view diff --git a/components/guest_view/browser/guest_view_event.h b/components/guest_view/browser/guest_view_event.h new file mode 100644 index 0000000..7f51d46 --- /dev/null +++ b/components/guest_view/browser/guest_view_event.h @@ -0,0 +1,41 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_GUEST_VIEW_BROWSER_GUEST_VIEW_EVENT_H_ +#define COMPONENTS_GUEST_VIEW_BROWSER_GUEST_VIEW_EVENT_H_ + +#include <string> + +#include "base/memory/scoped_ptr.h" +#include "base/values.h" + +namespace guest_view { + +class GuestViewBase; + +// A GuestViewEvent is a wrapper class for a GuestView event. +// GuestViewEvents may be queued until the guest is attached to a container. +// This wrapper class holds all the necessary information to fire the event +// on attachment. GuestViewEvents are owned by GuestViewBase. +class GuestViewEvent { + public: + GuestViewEvent(const std::string& name, + scoped_ptr<base::DictionaryValue> args); + ~GuestViewEvent(); + + // This method will dispatch the event to the specified |guest|'s embedder and + // use the provided |instance_id| for routing. After dispatch, this object + // will self-destruct. + void Dispatch(GuestViewBase* guest, int instance_id); + +private: + const std::string name_; + scoped_ptr<base::DictionaryValue> args_; + + DISALLOW_COPY_AND_ASSIGN(GuestViewEvent); +}; + +} // namespace guest_view + +#endif // COMPONENTS_GUEST_VIEW_BROWSER_GUEST_VIEW_EVENT_H_ diff --git a/components/guest_view/browser/guest_view_manager.cc b/components/guest_view/browser/guest_view_manager.cc new file mode 100644 index 0000000..04cc220 --- /dev/null +++ b/components/guest_view/browser/guest_view_manager.cc @@ -0,0 +1,376 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/guest_view/browser/guest_view_manager.h" + +#include "base/macros.h" +#include "base/strings/stringprintf.h" +#include "components/guest_view/browser/guest_view_base.h" +#include "components/guest_view/browser/guest_view_manager_delegate.h" +#include "components/guest_view/browser/guest_view_manager_factory.h" +#include "components/guest_view/common/guest_view_constants.h" +#include "content/public/browser/browser_context.h" +#include "content/public/browser/render_frame_host.h" +#include "content/public/browser/render_process_host.h" +#include "content/public/browser/render_view_host.h" +#include "content/public/browser/user_metrics.h" +#include "content/public/browser/web_contents_observer.h" +#include "content/public/common/child_process_host.h" +#include "content/public/common/result_codes.h" +#include "content/public/common/url_constants.h" +#include "url/gurl.h" + +using content::BrowserContext; +using content::SiteInstance; +using content::WebContents; + +namespace guest_view { + +// static +GuestViewManagerFactory* GuestViewManager::factory_ = nullptr; + +GuestViewManager::GuestViewManager( + content::BrowserContext* context, + scoped_ptr<GuestViewManagerDelegate> delegate) + : current_instance_id_(0), + last_instance_id_removed_(0), + context_(context), + delegate_(delegate.Pass()) { +} + +GuestViewManager::~GuestViewManager() {} + +// static +GuestViewManager* GuestViewManager::CreateWithDelegate( + BrowserContext* context, + scoped_ptr<GuestViewManagerDelegate> delegate) { + GuestViewManager* guest_manager = FromBrowserContext(context); + if (!guest_manager) { + if (factory_) { + guest_manager = + factory_->CreateGuestViewManager(context, delegate.Pass()); + } else { + guest_manager = new GuestViewManager(context, delegate.Pass()); + } + context->SetUserData(kGuestViewManagerKeyName, guest_manager); + } + return guest_manager; +} + +// static +GuestViewManager* GuestViewManager::FromBrowserContext( + BrowserContext* context) { + return static_cast<GuestViewManager*>(context->GetUserData( + kGuestViewManagerKeyName)); +} + +content::WebContents* GuestViewManager::GetGuestByInstanceIDSafely( + int guest_instance_id, + int embedder_render_process_id) { + if (!CanEmbedderAccessInstanceIDMaybeKill(embedder_render_process_id, + guest_instance_id)) { + return nullptr; + } + return GetGuestByInstanceID(guest_instance_id); +} + +void GuestViewManager::AttachGuest(int embedder_process_id, + int element_instance_id, + int guest_instance_id, + const base::DictionaryValue& attach_params) { + auto guest_view = GuestViewBase::From(embedder_process_id, guest_instance_id); + if (!guest_view) + return; + + ElementInstanceKey key(embedder_process_id, element_instance_id); + auto it = instance_id_map_.find(key); + // If there is an existing guest attached to the element, then destroy the + // existing guest. + if (it != instance_id_map_.end()) { + int old_guest_instance_id = it->second; + if (old_guest_instance_id == guest_instance_id) + return; + + auto old_guest_view = GuestViewBase::From(embedder_process_id, + old_guest_instance_id); + old_guest_view->Destroy(); + } + instance_id_map_[key] = guest_instance_id; + reverse_instance_id_map_[guest_instance_id] = key; + guest_view->SetAttachParams(attach_params); +} + +void GuestViewManager::DetachGuest(GuestViewBase* guest) { + if (!guest->attached()) + return; + + auto reverse_it = reverse_instance_id_map_.find(guest->guest_instance_id()); + if (reverse_it == reverse_instance_id_map_.end()) + return; + + const ElementInstanceKey& key = reverse_it->second; + + auto it = instance_id_map_.find(key); + DCHECK(it != instance_id_map_.end()); + + reverse_instance_id_map_.erase(reverse_it); + instance_id_map_.erase(it); +} + +bool GuestViewManager::IsOwnedByExtension(GuestViewBase* guest) { + return delegate_->IsOwnedByExtension(guest); +} + +int GuestViewManager::GetNextInstanceID() { + return ++current_instance_id_; +} + +void GuestViewManager::CreateGuest(const std::string& view_type, + content::WebContents* owner_web_contents, + const base::DictionaryValue& create_params, + const WebContentsCreatedCallback& callback) { + GuestViewBase* guest = CreateGuestInternal(owner_web_contents, view_type); + if (!guest) { + callback.Run(nullptr); + return; + } + guest->Init(create_params, callback); +} + +content::WebContents* GuestViewManager::CreateGuestWithWebContentsParams( + const std::string& view_type, + content::WebContents* owner_web_contents, + const content::WebContents::CreateParams& create_params) { + auto guest = CreateGuestInternal(owner_web_contents, view_type); + if (!guest) + return nullptr; + content::WebContents::CreateParams guest_create_params(create_params); + guest_create_params.guest_delegate = guest; + auto guest_web_contents = WebContents::Create(guest_create_params); + guest->InitWithWebContents(base::DictionaryValue(), guest_web_contents); + return guest_web_contents; +} + +content::WebContents* GuestViewManager::GetGuestByInstanceID( + int owner_process_id, + int element_instance_id) { + int guest_instance_id = GetGuestInstanceIDForElementID(owner_process_id, + element_instance_id); + if (guest_instance_id == kInstanceIDNone) + return nullptr; + + return GetGuestByInstanceID(guest_instance_id); +} + +int GuestViewManager::GetGuestInstanceIDForElementID(int owner_process_id, + int element_instance_id) { + auto iter = instance_id_map_.find( + ElementInstanceKey(owner_process_id, element_instance_id)); + if (iter == instance_id_map_.end()) + return kInstanceIDNone; + return iter->second; +} + +SiteInstance* GuestViewManager::GetGuestSiteInstance( + const GURL& guest_site) { + for (const auto& guest : guest_web_contents_by_instance_id_) { + if (guest.second->GetSiteInstance()->GetSiteURL() == guest_site) + return guest.second->GetSiteInstance(); + } + return nullptr; +} + +bool GuestViewManager::ForEachGuest(WebContents* owner_web_contents, + const GuestCallback& callback) { + for (const auto& guest : guest_web_contents_by_instance_id_) { + auto guest_view = GuestViewBase::FromWebContents(guest.second); + if (guest_view->owner_web_contents() != owner_web_contents) + continue; + + if (callback.Run(guest_view->web_contents())) + return true; + } + return false; +} + +WebContents* GuestViewManager::GetFullPageGuest( + WebContents* embedder_web_contents) { + WebContents* result = nullptr; + ForEachGuest(embedder_web_contents, + base::Bind(&GuestViewManager::GetFullPageGuestHelper, &result)); + return result; +} + +void GuestViewManager::AddGuest(int guest_instance_id, + WebContents* guest_web_contents) { + CHECK(!ContainsKey(guest_web_contents_by_instance_id_, guest_instance_id)); + CHECK(CanUseGuestInstanceID(guest_instance_id)); + guest_web_contents_by_instance_id_[guest_instance_id] = guest_web_contents; +} + +void GuestViewManager::RemoveGuest(int guest_instance_id) { + auto it = guest_web_contents_by_instance_id_.find(guest_instance_id); + DCHECK(it != guest_web_contents_by_instance_id_.end()); + guest_web_contents_by_instance_id_.erase(it); + + auto id_iter = reverse_instance_id_map_.find(guest_instance_id); + if (id_iter != reverse_instance_id_map_.end()) { + const ElementInstanceKey& instance_id_key = id_iter->second; + instance_id_map_.erase(instance_id_map_.find(instance_id_key)); + reverse_instance_id_map_.erase(id_iter); + } + + // All the instance IDs that lie within [0, last_instance_id_removed_] + // are invalid. + // The remaining sparse invalid IDs are kept in |removed_instance_ids_| set. + // The following code compacts the set by incrementing + // |last_instance_id_removed_|. + if (guest_instance_id == last_instance_id_removed_ + 1) { + ++last_instance_id_removed_; + // Compact. + auto iter = removed_instance_ids_.begin(); + while (iter != removed_instance_ids_.end()) { + int instance_id = *iter; + // The sparse invalid IDs must not lie within + // [0, last_instance_id_removed_] + DCHECK(instance_id > last_instance_id_removed_); + if (instance_id != last_instance_id_removed_ + 1) + break; + ++last_instance_id_removed_; + removed_instance_ids_.erase(iter++); + } + } else { + removed_instance_ids_.insert(guest_instance_id); + } +} + +GuestViewBase* GuestViewManager::CreateGuestInternal( + content::WebContents* owner_web_contents, + const std::string& view_type) { + if (guest_view_registry_.empty()) + RegisterGuestViewTypes(); + + auto it = guest_view_registry_.find(view_type); + if (it == guest_view_registry_.end()) { + NOTREACHED(); + return nullptr; + } + + return it->second.Run(owner_web_contents); +} + +void GuestViewManager::RegisterGuestViewTypes() { + delegate_->RegisterAdditionalGuestViewTypes(); +} + +bool GuestViewManager::IsGuestAvailableToContext(GuestViewBase* guest) { + return delegate_->IsGuestAvailableToContext(guest); +} + +void GuestViewManager::DispatchEvent(const std::string& event_name, + scoped_ptr<base::DictionaryValue> args, + GuestViewBase* guest, + int instance_id) { + // TODO(fsamuel): GuestViewManager should probably do something more useful + // here like log an error if the event could not be dispatched. + delegate_->DispatchEvent(event_name, args.Pass(), guest, instance_id); +} + +content::WebContents* GuestViewManager::GetGuestByInstanceID( + int guest_instance_id) { + auto it = guest_web_contents_by_instance_id_.find(guest_instance_id); + if (it == guest_web_contents_by_instance_id_.end()) + return nullptr; + return it->second; +} + +bool GuestViewManager::CanEmbedderAccessInstanceIDMaybeKill( + int embedder_render_process_id, + int guest_instance_id) { + if (!CanEmbedderAccessInstanceID(embedder_render_process_id, + guest_instance_id)) { + // The embedder process is trying to access a guest it does not own. + content::RecordAction( + base::UserMetricsAction("BadMessageTerminate_BPGM")); + content::RenderProcessHost::FromID(embedder_render_process_id) + ->Shutdown(content::RESULT_CODE_KILLED_BAD_MESSAGE, false); + return false; + } + return true; +} + +bool GuestViewManager::CanUseGuestInstanceID(int guest_instance_id) { + if (guest_instance_id <= last_instance_id_removed_) + return false; + return !ContainsKey(removed_instance_ids_, guest_instance_id); +} + +// static +bool GuestViewManager::GetFullPageGuestHelper( + content::WebContents** result, + content::WebContents* guest_web_contents) { + auto guest_view = GuestViewBase::FromWebContents(guest_web_contents); + if (guest_view && guest_view->is_full_page_plugin()) { + *result = guest_web_contents; + return true; + } + return false; +} + +bool GuestViewManager::CanEmbedderAccessInstanceID( + int embedder_render_process_id, + int guest_instance_id) { + // The embedder is trying to access a guest with a negative or zero + // instance ID. + if (guest_instance_id <= kInstanceIDNone) + return false; + + // The embedder is trying to access an instance ID that has not yet been + // allocated by GuestViewManager. This could cause instance ID + // collisions in the future, and potentially give one embedder access to a + // guest it does not own. + if (guest_instance_id > current_instance_id_) + return false; + + // We might get some late arriving messages at tear down. Let's let the + // embedder tear down in peace. + auto it = guest_web_contents_by_instance_id_.find(guest_instance_id); + if (it == guest_web_contents_by_instance_id_.end()) + return true; + + auto guest_view = GuestViewBase::FromWebContents(it->second); + if (!guest_view) + return false; + + return embedder_render_process_id == + guest_view->owner_web_contents()->GetRenderProcessHost()->GetID(); +} + +GuestViewManager::ElementInstanceKey::ElementInstanceKey() + : embedder_process_id(content::ChildProcessHost::kInvalidUniqueID), + element_instance_id(content::ChildProcessHost::kInvalidUniqueID) { +} + +GuestViewManager::ElementInstanceKey::ElementInstanceKey( + int embedder_process_id, + int element_instance_id) + : embedder_process_id(embedder_process_id), + element_instance_id(element_instance_id) { +} + +bool GuestViewManager::ElementInstanceKey::operator<( + const GuestViewManager::ElementInstanceKey& other) const { + if (embedder_process_id != other.embedder_process_id) + return embedder_process_id < other.embedder_process_id; + + return element_instance_id < other.element_instance_id; +} + +bool GuestViewManager::ElementInstanceKey::operator==( + const GuestViewManager::ElementInstanceKey& other) const { + return (embedder_process_id == other.embedder_process_id) && + (element_instance_id == other.element_instance_id); +} + +} // namespace guest_view diff --git a/components/guest_view/browser/guest_view_manager.h b/components/guest_view/browser/guest_view_manager.h new file mode 100644 index 0000000..f51d0a6 --- /dev/null +++ b/components/guest_view/browser/guest_view_manager.h @@ -0,0 +1,212 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_GUEST_VIEW_BROWSER_GUEST_VIEW_MANAGER_H_ +#define COMPONENTS_GUEST_VIEW_BROWSER_GUEST_VIEW_MANAGER_H_ + +#include <map> + +#include "base/bind.h" +#include "base/gtest_prod_util.h" +#include "base/lazy_instance.h" +#include "base/macros.h" +#include "content/public/browser/browser_plugin_guest_manager.h" +#include "content/public/browser/site_instance.h" +#include "content/public/browser/web_contents.h" + +class GURL; + +namespace content { +class BrowserContext; +class WebContents; +} // namespace content + +namespace guest_view { + +class GuestViewBase; +class GuestViewManagerDelegate; +class GuestViewManagerFactory; + +class GuestViewManager : public content::BrowserPluginGuestManager, + public base::SupportsUserData::Data { + public: + GuestViewManager(content::BrowserContext* context, + scoped_ptr<GuestViewManagerDelegate> delegate); + ~GuestViewManager() override; + + // Returns the GuestViewManager associated with |context|. If one isn't + // available, then it is created and returned. + static GuestViewManager* CreateWithDelegate( + content::BrowserContext* context, + scoped_ptr<GuestViewManagerDelegate> delegate); + + // Returns the GuestViewManager associated with |context|. If one isn't + // available, then nullptr is returned. + static GuestViewManager* FromBrowserContext(content::BrowserContext* context); + + // Overrides factory for testing. Default (NULL) value indicates regular + // (non-test) environment. + static void set_factory_for_testing(GuestViewManagerFactory* factory) { + GuestViewManager::factory_ = factory; + } + // Returns the guest WebContents associated with the given |guest_instance_id| + // if the provided |embedder_render_process_id| is allowed to access it. + // If the embedder is not allowed access, the embedder will be killed, and + // this method will return NULL. If no WebContents exists with the given + // instance ID, then NULL will also be returned. + content::WebContents* GetGuestByInstanceIDSafely( + int guest_instance_id, + int embedder_render_process_id); + + // Associates the Browser Plugin with |element_instance_id| to a + // guest that has ID of |guest_instance_id| and sets initialization + // parameters, |params| for it. + void AttachGuest(int embedder_process_id, + int element_instance_id, + int guest_instance_id, + const base::DictionaryValue& attach_params); + + // Removes the association between |element_instance_id| and a guest instance + // ID if one exists. + void DetachGuest(GuestViewBase* guest); + + // Indicates whether the |guest| is owned by an extension or Chrome App. + bool IsOwnedByExtension(GuestViewBase* guest); + + int GetNextInstanceID(); + int GetGuestInstanceIDForElementID( + int owner_process_id, + int element_instance_id); + + template <typename T> + void RegisterGuestViewType() { + auto it = guest_view_registry_.find(T::Type); + DCHECK(it == guest_view_registry_.end()); + guest_view_registry_[T::Type] = base::Bind(&T::Create); + } + + using WebContentsCreatedCallback = + base::Callback<void(content::WebContents*)>; + void CreateGuest(const std::string& view_type, + content::WebContents* owner_web_contents, + const base::DictionaryValue& create_params, + const WebContentsCreatedCallback& callback); + + content::WebContents* CreateGuestWithWebContentsParams( + const std::string& view_type, + content::WebContents* owner_web_contents, + const content::WebContents::CreateParams& create_params); + + content::SiteInstance* GetGuestSiteInstance( + const GURL& guest_site); + + // BrowserPluginGuestManager implementation. + content::WebContents* GetGuestByInstanceID( + int owner_process_id, + int element_instance_id) override; + bool ForEachGuest(content::WebContents* owner_web_contents, + const GuestCallback& callback) override; + content::WebContents* GetFullPageGuest( + content::WebContents* embedder_web_contents) override; + + protected: + friend class GuestViewBase; + friend class GuestViewEvent; + + // Can be overriden in tests. + virtual void AddGuest(int guest_instance_id, + content::WebContents* guest_web_contents); + + // Can be overriden in tests. + virtual void RemoveGuest(int guest_instance_id); + + // Creates a guest of the provided |view_type|. + GuestViewBase* CreateGuestInternal(content::WebContents* owner_web_contents, + const std::string& view_type); + + // Adds GuestView types to the GuestView registry. + void RegisterGuestViewTypes(); + + // Indicates whether the provided |guest| can be used in the context it has + // been created. + bool IsGuestAvailableToContext(GuestViewBase* guest); + + // Dispatches the event with |name| with the provided |args| to the embedder + // of the given |guest| with |instance_id| for routing. + void DispatchEvent(const std::string& event_name, + scoped_ptr<base::DictionaryValue> args, + GuestViewBase* guest, + int instance_id); + + content::WebContents* GetGuestByInstanceID(int guest_instance_id); + + bool CanEmbedderAccessInstanceIDMaybeKill( + int embedder_render_process_id, + int guest_instance_id); + + bool CanEmbedderAccessInstanceID(int embedder_render_process_id, + int guest_instance_id); + + // Returns true if |guest_instance_id| can be used to add a new guest to this + // manager. + // We disallow adding new guest with instance IDs that were previously removed + // from this manager using RemoveGuest. + bool CanUseGuestInstanceID(int guest_instance_id); + + static bool GetFullPageGuestHelper(content::WebContents** result, + content::WebContents* guest_web_contents); + + // Static factory instance (always NULL for non-test). + static GuestViewManagerFactory* factory_; + + // Contains guests' WebContents, mapping from their instance ids. + using GuestInstanceMap = std::map<int, content::WebContents*>; + GuestInstanceMap guest_web_contents_by_instance_id_; + + struct ElementInstanceKey { + int embedder_process_id; + int element_instance_id; + + ElementInstanceKey(); + ElementInstanceKey(int embedder_process_id, + int element_instance_id); + + bool operator<(const ElementInstanceKey& other) const; + bool operator==(const ElementInstanceKey& other) const; + }; + + using GuestInstanceIDMap = std::map<ElementInstanceKey, int>; + GuestInstanceIDMap instance_id_map_; + + // The reverse map of GuestInstanceIDMap. + using GuestInstanceIDReverseMap = std::map<int, ElementInstanceKey>; + GuestInstanceIDReverseMap reverse_instance_id_map_; + + using GuestCreationCallback = + base::Callback<GuestViewBase*(content::WebContents*)>; + using GuestViewCreationMap = + std::map<std::string, GuestViewManager::GuestCreationCallback>; + GuestViewCreationMap guest_view_registry_; + + int current_instance_id_; + + // Any instance ID whose number not greater than this was removed via + // RemoveGuest. + // This is used so that we don't have store all removed instance IDs in + // |removed_instance_ids_|. + int last_instance_id_removed_; + // The remaining instance IDs that are greater than + // |last_instance_id_removed_| are kept here. + std::set<int> removed_instance_ids_; + + content::BrowserContext* context_; + + scoped_ptr<GuestViewManagerDelegate> delegate_; + + DISALLOW_COPY_AND_ASSIGN(GuestViewManager); +}; + +} // namespace guest_view + +#endif // COMPONETS_GUEST_VIEW_BROWSER_GUEST_VIEW_MANAGER_H_ diff --git a/components/guest_view/browser/guest_view_manager_delegate.cc b/components/guest_view/browser/guest_view_manager_delegate.cc new file mode 100644 index 0000000..244c516 --- /dev/null +++ b/components/guest_view/browser/guest_view_manager_delegate.cc @@ -0,0 +1,23 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/guest_view/browser/guest_view_manager_delegate.h" + +namespace guest_view { + +GuestViewManagerDelegate::GuestViewManagerDelegate() { +} + +GuestViewManagerDelegate::~GuestViewManagerDelegate() { +} + +bool GuestViewManagerDelegate::IsGuestAvailableToContext(GuestViewBase* guest) { + return false; +} + +bool GuestViewManagerDelegate::IsOwnedByExtension(GuestViewBase* guest) { + return false; +} + +} // namespace guest diff --git a/components/guest_view/browser/guest_view_manager_delegate.h b/components/guest_view/browser/guest_view_manager_delegate.h new file mode 100644 index 0000000..a46c278d --- /dev/null +++ b/components/guest_view/browser/guest_view_manager_delegate.h @@ -0,0 +1,53 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_GUEST_VIEW_BROWSER_GUEST_VIEW_MANAGER_DELEGATE_H_ +#define COMPONENTS_GUEST_VIEW_BROWSER_GUEST_VIEW_MANAGER_DELEGATE_H_ + +#include <string> + +#include "base/memory/scoped_ptr.h" +#include "base/values.h" + +namespace base { +class DictionaryValue; +} // namespace base + +namespace guest_view { + +class GuestViewBase; + +// A GuestViewManagerDelegate interface allows GuestViewManager to delegate +// responsibilities to other modules in Chromium. Different builds of Chromium +// may use different GuestViewManagerDelegate implementations. For example, +// mobile builds of Chromium do not include an extensions module and so +// permission checks would be different, and IsOwnedByExtension would always +// return false. +class GuestViewManagerDelegate { + public: + GuestViewManagerDelegate(); + virtual ~GuestViewManagerDelegate(); + + // Dispatches the event with |name| with the provided |args| to the embedder + // of the given |guest| with |instance_id| for routing. + virtual void DispatchEvent(const std::string& event_name, + scoped_ptr<base::DictionaryValue> args, + GuestViewBase* guest, + int instance_id) {} + + // Indicates whether the |guest| can be used within the context of where it + // was created. + virtual bool IsGuestAvailableToContext(GuestViewBase* guest); + + // Indicates whether the |guest| is owned by an extension or Chrome App. + virtual bool IsOwnedByExtension(GuestViewBase* guest); + + // Registers additional GuestView types the delegator (GuestViewManger) can + // create. + virtual void RegisterAdditionalGuestViewTypes() {} +}; + +} // namespace guest_view + +#endif // COMPONENTS_GUEST_VIEW_BROWSER_GUEST_VIEW_MANAGER_DELEGATE_H_ diff --git a/components/guest_view/browser/guest_view_manager_factory.h b/components/guest_view/browser/guest_view_manager_factory.h new file mode 100644 index 0000000..0d127a3 --- /dev/null +++ b/components/guest_view/browser/guest_view_manager_factory.h @@ -0,0 +1,30 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_GUEST_VIEW_BROWSER_GUEST_VIEW_MANAGER_FACTORY_H_ +#define COMPONENTS_GUEST_VIEW_BROWSER_GUEST_VIEW_MANAGER_FACTORY_H_ + +namespace content { +class BrowserContext; +} + +namespace guest_view { + +class GuestViewManager; +class GuestViewManagerDelegate; + +class GuestViewManagerFactory { + public: + virtual GuestViewManager* CreateGuestViewManager( + content::BrowserContext* context, + scoped_ptr<GuestViewManagerDelegate> delegate) = 0; + + protected: + virtual ~GuestViewManagerFactory() {} +}; + +} // namespace guest_view + +#endif // COMPONENTS_GUEST_VIEW_BROWSER_GUEST_VIEW_MANAGER_FACTORY_H_ + diff --git a/components/guest_view/browser/guest_view_manager_unittest.cc b/components/guest_view/browser/guest_view_manager_unittest.cc new file mode 100644 index 0000000..1d43dbd --- /dev/null +++ b/components/guest_view/browser/guest_view_manager_unittest.cc @@ -0,0 +1,84 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/guest_view/browser/guest_view_manager.h" +#include "components/guest_view/browser/guest_view_manager_delegate.h" +#include "components/guest_view/browser/test_guest_view_manager.h" +#include "content/public/test/test_browser_context.h" +#include "content/public/test/test_renderer_host.h" +#include "content/public/test/web_contents_tester.h" +#include "testing/gtest/include/gtest/gtest.h" + +using content::WebContents; +using content::WebContentsTester; + +namespace guest_view { + +namespace { + +class GuestViewManagerTest : public content::RenderViewHostTestHarness { + public: + GuestViewManagerTest() {} + ~GuestViewManagerTest() override {} + + scoped_ptr<WebContents> CreateWebContents() { + return scoped_ptr<WebContents>( + WebContentsTester::CreateTestWebContents(&browser_context_, NULL)); + } + + private: + content::TestBrowserContext browser_context_; + + DISALLOW_COPY_AND_ASSIGN(GuestViewManagerTest); +}; + +} // namespace + +TEST_F(GuestViewManagerTest, AddRemove) { + content::TestBrowserContext browser_context; + scoped_ptr<GuestViewManagerDelegate> delegate( + new GuestViewManagerDelegate()); + scoped_ptr<TestGuestViewManager> manager( + new TestGuestViewManager(&browser_context, delegate.Pass())); + + scoped_ptr<WebContents> web_contents1(CreateWebContents()); + scoped_ptr<WebContents> web_contents2(CreateWebContents()); + scoped_ptr<WebContents> web_contents3(CreateWebContents()); + + EXPECT_EQ(0, manager->last_instance_id_removed()); + + EXPECT_TRUE(manager->CanUseGuestInstanceID(1)); + EXPECT_TRUE(manager->CanUseGuestInstanceID(2)); + EXPECT_TRUE(manager->CanUseGuestInstanceID(3)); + + manager->AddGuest(1, web_contents1.get()); + manager->AddGuest(2, web_contents2.get()); + manager->RemoveGuest(2); + + // Since we removed 2, it would be an invalid ID. + EXPECT_TRUE(manager->CanUseGuestInstanceID(1)); + EXPECT_FALSE(manager->CanUseGuestInstanceID(2)); + EXPECT_TRUE(manager->CanUseGuestInstanceID(3)); + + EXPECT_EQ(0, manager->last_instance_id_removed()); + + EXPECT_TRUE(manager->CanUseGuestInstanceID(3)); + + manager->AddGuest(3, web_contents3.get()); + manager->RemoveGuest(1); + EXPECT_FALSE(manager->CanUseGuestInstanceID(1)); + EXPECT_FALSE(manager->CanUseGuestInstanceID(2)); + + EXPECT_EQ(2, manager->last_instance_id_removed()); + manager->RemoveGuest(3); + EXPECT_EQ(3, manager->last_instance_id_removed()); + + EXPECT_FALSE(manager->CanUseGuestInstanceID(1)); + EXPECT_FALSE(manager->CanUseGuestInstanceID(2)); + EXPECT_FALSE(manager->CanUseGuestInstanceID(3)); + + EXPECT_EQ(0u, manager->GetNumRemovedInstanceIDs()); +} + +} // namespace guest_view diff --git a/components/guest_view/browser/guest_view_message_filter.cc b/components/guest_view/browser/guest_view_message_filter.cc new file mode 100644 index 0000000..d313f53 --- /dev/null +++ b/components/guest_view/browser/guest_view_message_filter.cc @@ -0,0 +1,80 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/guest_view/browser/guest_view_message_filter.h" + +#include "components/guest_view/browser/guest_view_base.h" +#include "components/guest_view/browser/guest_view_manager.h" +#include "components/guest_view/common/guest_view_messages.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/render_frame_host.h" +#include "content/public/browser/render_process_host.h" +#include "content/public/browser/render_view_host.h" +#include "ipc/ipc_message_macros.h" + +using content::BrowserContext; +using content::BrowserThread; +using content::RenderFrameHost; +using content::WebContents; + +namespace guest_view { + +GuestViewMessageFilter::GuestViewMessageFilter(int render_process_id, + BrowserContext* context) + : BrowserMessageFilter(GuestViewMsgStart), + render_process_id_(render_process_id), + browser_context_(context), + weak_ptr_factory_(this) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); +} + +GuestViewMessageFilter::~GuestViewMessageFilter() { + DCHECK_CURRENTLY_ON(BrowserThread::IO); +} + +void GuestViewMessageFilter::OverrideThreadForMessage( + const IPC::Message& message, + BrowserThread::ID* thread) { + switch (message.type()) { + case GuestViewHostMsg_AttachGuest::ID: + *thread = BrowserThread::UI; + break; + default: + break; + } +} + +void GuestViewMessageFilter::OnDestruct() const { + // Destroy the filter on the IO thread since that's where its weak pointers + // are being used. + BrowserThread::DeleteOnIOThread::Destruct(this); +} + +bool GuestViewMessageFilter::OnMessageReceived(const IPC::Message& message) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(GuestViewMessageFilter, message) + IPC_MESSAGE_HANDLER(GuestViewHostMsg_AttachGuest, OnAttachGuest) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void GuestViewMessageFilter::OnAttachGuest( + int element_instance_id, + int guest_instance_id, + const base::DictionaryValue& params) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + auto manager = GuestViewManager::FromBrowserContext(browser_context_); + // We should have a GuestViewManager at this point. If we don't then the + // embedder is misbehaving. + if (!manager) + return; + + manager->AttachGuest(render_process_id_, + element_instance_id, + guest_instance_id, + params); +} + +} // namespace guest_view diff --git a/components/guest_view/browser/guest_view_message_filter.h b/components/guest_view/browser/guest_view_message_filter.h new file mode 100644 index 0000000..7d2448f --- /dev/null +++ b/components/guest_view/browser/guest_view_message_filter.h @@ -0,0 +1,67 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_GUEST_VIEW_BROWSER_GUEST_VIEW_MESSAGE_FILTER_H_ +#define COMPONENTS_GUEST_VIEW_BROWSER_GUEST_VIEW_MESSAGE_FILTER_H_ + +#include <string> + +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "content/public/browser/browser_message_filter.h" + +namespace base { +class DictionaryValue; +} + +namespace content { +class BrowserContext; +class WebContents; +} + +namespace gfx { +class Size; +} + +namespace guest_view { + +// This class filters out incoming GuestView-specific IPC messages from the +// renderer process. It is created on the UI thread. Messages may be handled on +// the IO thread or the UI thread. +class GuestViewMessageFilter : public content::BrowserMessageFilter { + public: + GuestViewMessageFilter(int render_process_id, + content::BrowserContext* context); + + private: + friend class content::BrowserThread; + friend class base::DeleteHelper<GuestViewMessageFilter>; + + ~GuestViewMessageFilter() override; + + // content::BrowserMessageFilter implementation. + void OverrideThreadForMessage(const IPC::Message& message, + content::BrowserThread::ID* thread) override; + void OnDestruct() const override; + bool OnMessageReceived(const IPC::Message& message) override; + + // Message handlers on the UI thread. + void OnAttachGuest(int element_instance_id, + int guest_instance_id, + const base::DictionaryValue& attach_params); + + const int render_process_id_; + + // Should only be accessed on the UI thread. + content::BrowserContext* const browser_context_; + + // Weak pointers produced by this factory are bound to the IO thread. + base::WeakPtrFactory<GuestViewMessageFilter> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(GuestViewMessageFilter); +}; + +} // namespace guest_view + +#endif // COMPONENTS_GUEST_VIEW_BROWSER_GUEST_VIEW_MESSAGE_FILTER_H_ diff --git a/components/guest_view/browser/test_guest_view_manager.cc b/components/guest_view/browser/test_guest_view_manager.cc new file mode 100644 index 0000000..90a1023 --- /dev/null +++ b/components/guest_view/browser/test_guest_view_manager.cc @@ -0,0 +1,99 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/guest_view/browser/test_guest_view_manager.h" + +#include "base/memory/scoped_ptr.h" +#include "components/guest_view/browser/guest_view_manager_delegate.h" + +namespace guest_view { + +TestGuestViewManager::TestGuestViewManager( + content::BrowserContext* context, + scoped_ptr<GuestViewManagerDelegate> delegate) + : GuestViewManager(context, delegate.Pass()), + num_guests_created_(0) { +} + +TestGuestViewManager::~TestGuestViewManager() { +} + +size_t TestGuestViewManager::GetNumGuestsActive() const { + return guest_web_contents_by_instance_id_.size(); +} + +size_t TestGuestViewManager::GetNumRemovedInstanceIDs() const { + return removed_instance_ids_.size(); +} + +content::WebContents* TestGuestViewManager::GetLastGuestCreated() { + content::WebContents* web_contents = nullptr; + for (int i = current_instance_id_; i >= 0; i--) { + web_contents = GetGuestByInstanceID(i); + if (web_contents) { + break; + } + } + return web_contents; +} + +void TestGuestViewManager::WaitForAllGuestsDeleted() { + // Make sure that every guest that was created have been removed. + for (auto& watcher : guest_web_contents_watchers_) + watcher->Wait(); +} + +void TestGuestViewManager::WaitForGuestCreated() { + created_message_loop_runner_ = new content::MessageLoopRunner; + created_message_loop_runner_->Run(); +} + +content::WebContents* TestGuestViewManager::WaitForSingleGuestCreated() { + if (!GetNumGuestsActive()) { + // Guests have been created and subsequently destroyed. + if (num_guests_created() > 0) + return nullptr; + WaitForGuestCreated(); + } + + return GetLastGuestCreated(); +} + +void TestGuestViewManager::AddGuest(int guest_instance_id, + content::WebContents* guest_web_contents) { + GuestViewManager::AddGuest(guest_instance_id, guest_web_contents); + + guest_web_contents_watchers_.push_back( + linked_ptr<content::WebContentsDestroyedWatcher>( + new content::WebContentsDestroyedWatcher(guest_web_contents))); + + ++num_guests_created_; + + if (created_message_loop_runner_.get()) + created_message_loop_runner_->Quit(); +} + +void TestGuestViewManager::RemoveGuest(int guest_instance_id) { + GuestViewManager::RemoveGuest(guest_instance_id); +} + +// Test factory for creating test instances of GuestViewManager. +TestGuestViewManagerFactory::TestGuestViewManagerFactory() + : test_guest_view_manager_(NULL) { +} + +TestGuestViewManagerFactory::~TestGuestViewManagerFactory() { +} + +GuestViewManager* TestGuestViewManagerFactory::CreateGuestViewManager( + content::BrowserContext* context, + scoped_ptr<GuestViewManagerDelegate> delegate) { + if (!test_guest_view_manager_) { + test_guest_view_manager_ = + new TestGuestViewManager(context, delegate.Pass()); + } + return test_guest_view_manager_; +} + +} // namespace guest_view diff --git a/components/guest_view/browser/test_guest_view_manager.h b/components/guest_view/browser/test_guest_view_manager.h new file mode 100644 index 0000000..cbf942f --- /dev/null +++ b/components/guest_view/browser/test_guest_view_manager.h @@ -0,0 +1,82 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_GUEST_VIEW_BROWSER_TEST_GUEST_VIEW_MANAGER_H_ +#define COMPONENTS_GUEST_VIEW_BROWSER_TEST_GUEST_VIEW_MANAGER_H_ + +#include "base/memory/linked_ptr.h" +#include "components/guest_view/browser/guest_view_manager.h" +#include "components/guest_view/browser/guest_view_manager_factory.h" +#include "content/public/test/browser_test_utils.h" +#include "content/public/test/test_utils.h" + +namespace guest_view { + +class TestGuestViewManager : public GuestViewManager { + public: + TestGuestViewManager( + content::BrowserContext* context, + scoped_ptr<GuestViewManagerDelegate> delegate); + ~TestGuestViewManager() override; + + void WaitForAllGuestsDeleted(); + content::WebContents* WaitForSingleGuestCreated(); + + content::WebContents* GetLastGuestCreated(); + + // Returns the number of guests currently still alive at the time of calling + // this method. + size_t GetNumGuestsActive() const; + + // Returns the size of the set of removed instance IDs. + size_t GetNumRemovedInstanceIDs() const; + + // Returns the number of guests that have been created since the creation of + // this GuestViewManager. + int num_guests_created() const { return num_guests_created_; } + + // Returns the last guest instance ID removed from the manager. + int last_instance_id_removed() const { return last_instance_id_removed_; } + + private: + FRIEND_TEST_ALL_PREFIXES(GuestViewManagerTest, AddRemove); + + // GuestViewManager override: + void AddGuest(int guest_instance_id, + content::WebContents* guest_web_contents) override; + void RemoveGuest(int guest_instance_id) override; + + void WaitForGuestCreated(); + + using GuestViewManager::last_instance_id_removed_; + using GuestViewManager::removed_instance_ids_; + + int num_guests_created_; + + std::vector<linked_ptr<content::WebContentsDestroyedWatcher>> + guest_web_contents_watchers_; + scoped_refptr<content::MessageLoopRunner> created_message_loop_runner_; + + DISALLOW_COPY_AND_ASSIGN(TestGuestViewManager); +}; + +// Test factory for creating test instances of GuestViewManager. +class TestGuestViewManagerFactory : public GuestViewManagerFactory { + public: + TestGuestViewManagerFactory(); + ~TestGuestViewManagerFactory() override; + + GuestViewManager* CreateGuestViewManager( + content::BrowserContext* context, + scoped_ptr<GuestViewManagerDelegate> delegate) override; + + private: + TestGuestViewManager* test_guest_view_manager_; + + DISALLOW_COPY_AND_ASSIGN(TestGuestViewManagerFactory); +}; + +} // namespace guest_view + +#endif // COMPONENTS_GUEST_VIEW_BROWSER_TEST_GUEST_VIEW_MANAGER_H_ diff --git a/components/guest_view/common/DEPS b/components/guest_view/common/DEPS new file mode 100644 index 0000000..b0e64bf --- /dev/null +++ b/components/guest_view/common/DEPS @@ -0,0 +1,3 @@ +include_rules = [ + "+ipc" +] diff --git a/components/guest_view/common/OWNERS b/components/guest_view/common/OWNERS new file mode 100644 index 0000000..bba0da4 --- /dev/null +++ b/components/guest_view/common/OWNERS @@ -0,0 +1,15 @@ +fsamuel@chromium.org +lazyboy@chromium.org + +# For security review of IPC message files. +per-file *_messages*.h=set noparent +per-file *_messages*.h=dcheng@chromium.org +per-file *_messages*.h=inferno@chromium.org +per-file *_messages*.h=jln@chromium.org +per-file *_messages*.h=jschuh@chromium.org +per-file *_messages*.h=kenrb@chromium.org +per-file *_messages*.h=mkwst@chromium.org +per-file *_messages*.h=nasko@chromium.org +per-file *_messages*.h=palmer@chromium.org +per-file *_messages*.h=tsepez@chromium.org +per-file *_messages*.h=wfh@chromium.org diff --git a/components/guest_view/common/guest_view_constants.cc b/components/guest_view/common/guest_view_constants.cc new file mode 100644 index 0000000..e68c3b8 --- /dev/null +++ b/components/guest_view/common/guest_view_constants.cc @@ -0,0 +1,45 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/guest_view/common/guest_view_constants.h" + +namespace guest_view { + +// Sizing attributes/parameters. +const char kAttributeAutoSize[] = "autosize"; +const char kAttributeMaxHeight[] = "maxheight"; +const char kAttributeMaxWidth[] = "maxwidth"; +const char kAttributeMinHeight[] = "minheight"; +const char kAttributeMinWidth[] = "minwidth"; +const char kElementWidth[] = "elementWidth"; +const char kElementHeight[] = "elementHeight"; +const char kElementSizeIsLogical[] = "elementSizeIsLogical"; + +// Events. +const char kEventResize[] = "guestViewInternal.onResize"; + +// Parameters/properties on events. +const char kCode[] = "code"; +const char kContentWindowID[] = "contentWindowId"; +const char kID[] = "id"; +const char kIsTopLevel[] = "isTopLevel"; +const char kNewWidth[] = "newWidth"; +const char kNewHeight[] = "newHeight"; +const char kOldWidth[] = "oldWidth"; +const char kOldHeight[] = "oldHeight"; +const char kReason[] = "reason"; +const char kUrl[] = "url"; +const char kUserGesture[] = "userGesture"; + +// Initialization parameters. +const char kParameterApi[] = "api"; +const char kParameterInstanceId[] = "instanceId"; + +// Other. +const char kGuestViewManagerKeyName[] = "guest_view_manager"; +const int kInstanceIDNone = 0; +const int kDefaultWidth = 300; +const int kDefaultHeight = 300; + +} // namespace guestview diff --git a/components/guest_view/common/guest_view_constants.h b/components/guest_view/common/guest_view_constants.h new file mode 100644 index 0000000..ef9066e --- /dev/null +++ b/components/guest_view/common/guest_view_constants.h @@ -0,0 +1,50 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Constants used for the WebView API. + +#ifndef COMPONENTS_GUEST_VIEW_COMMON_GUEST_VIEW_CONSTANTS_H_ +#define COMPONENTS_GUEST_VIEW_COMMON_GUEST_VIEW_CONSTANTS_H_ + +namespace guest_view { + +// Sizing attributes/parameters. +extern const char kAttributeAutoSize[]; +extern const char kAttributeMaxHeight[]; +extern const char kAttributeMaxWidth[]; +extern const char kAttributeMinHeight[]; +extern const char kAttributeMinWidth[]; +extern const char kElementWidth[]; +extern const char kElementHeight[]; +extern const char kElementSizeIsLogical[]; + +// Events. +extern const char kEventResize[]; + +// Parameters/properties on events. +extern const char kCode[]; +extern const char kContentWindowID[]; +extern const char kID[]; +extern const char kIsTopLevel[]; +extern const char kNewWidth[]; +extern const char kNewHeight[]; +extern const char kOldWidth[]; +extern const char kOldHeight[]; +extern const char kReason[]; +extern const char kUrl[]; +extern const char kUserGesture[]; + +// Initialization parameters. +extern const char kParameterApi[]; +extern const char kParameterInstanceId[]; + +// Other. +extern const char kGuestViewManagerKeyName[]; +extern const int kInstanceIDNone; +extern const int kDefaultWidth; +extern const int kDefaultHeight; + +} // namespace guest_view + +#endif // COMPONENTS_GUEST_VIEW_COMMON_GUEST_VIEW_CONSTANTS_H_ diff --git a/components/guest_view/common/guest_view_message_generator.cc b/components/guest_view/common/guest_view_message_generator.cc new file mode 100644 index 0000000..6a0bca1 --- /dev/null +++ b/components/guest_view/common/guest_view_message_generator.cc @@ -0,0 +1,33 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Get basic type definitions. +#define IPC_MESSAGE_IMPL +#include "components/guest_view/common/guest_view_message_generator.h" + +// Generate constructors. +#include "ipc/struct_constructor_macros.h" +#include "components/guest_view/common/guest_view_message_generator.h" + +// Generate destructors. +#include "ipc/struct_destructor_macros.h" +#include "components/guest_view/common/guest_view_message_generator.h" + +// Generate param traits write methods. +#include "ipc/param_traits_write_macros.h" +namespace IPC { +#include "components/guest_view/common/guest_view_message_generator.h" +} // namespace IPC + +// Generate param traits read methods. +#include "ipc/param_traits_read_macros.h" +namespace IPC { +#include "components/guest_view/common/guest_view_message_generator.h" +} // namespace IPC + +// Generate param traits log methods. +#include "ipc/param_traits_log_macros.h" +namespace IPC { +#include "components/guest_view/common/guest_view_message_generator.h" +} // namespace IPC diff --git a/components/guest_view/common/guest_view_message_generator.h b/components/guest_view/common/guest_view_message_generator.h new file mode 100644 index 0000000..0e569e2 --- /dev/null +++ b/components/guest_view/common/guest_view_message_generator.h @@ -0,0 +1,7 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Multiply-included file, no traditional include guard. + +#include "components/guest_view/common/guest_view_messages.h" diff --git a/components/guest_view/common/guest_view_messages.h b/components/guest_view/common/guest_view_messages.h new file mode 100644 index 0000000..9772b6f --- /dev/null +++ b/components/guest_view/common/guest_view_messages.h @@ -0,0 +1,35 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// IPC messages for GuestViews. +// Multiply-included message file, hence no include guard. + +#include "base/values.h" +#include "ipc/ipc_message_macros.h" + +#define IPC_MESSAGE_START GuestViewMsgStart + +// Messages sent from the browser to the renderer. + +// Once a RenderView proxy has been created for the guest in the embedder render +// process, this IPC informs the embedder of the proxy's routing ID. +IPC_MESSAGE_CONTROL2(GuestViewMsg_GuestAttached, + int /* element_instance_id */, + int /* source_routing_id */) + +// This IPC tells the browser process to detach the provided +// |element_instance_id| from a GuestViewBase if it is attached to one. +// In other words, routing of input and graphics will no longer flow through +// the container associated with the provided ID. +IPC_MESSAGE_CONTROL1(GuestViewMsg_GuestDetached, + int /* element_instance_id*/) + +// Messages sent from the renderer to the browser. + +// Sent by the renderer to set initialization parameters of a Browser Plugin +// that is identified by |element_instance_id|. +IPC_MESSAGE_CONTROL3(GuestViewHostMsg_AttachGuest, + int /* element_instance_id */, + int /* guest_instance_id */, + base::DictionaryValue /* attach_params */) |