Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(20)

Unified Diff: chromecast/browser/cast_web_view.cc

Issue 2626863006: [Chromecast] Add CastWebContents (Closed)
Patch Set: Long overdue rebase Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chromecast/browser/cast_web_view.cc
diff --git a/chromecast/browser/cast_web_view.cc b/chromecast/browser/cast_web_view.cc
new file mode 100644
index 0000000000000000000000000000000000000000..4b3cfd607c9f710da92721b551932e57739babcf
--- /dev/null
+++ b/chromecast/browser/cast_web_view.cc
@@ -0,0 +1,260 @@
+// Copyright 2017 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 "chromecast/browser/cast_web_view.h"
+
+#include "base/logging.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "chromecast/base/metrics/cast_metrics_helper.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
+#include "content/public/browser/render_widget_host_view.h"
+#include "content/public/common/renderer_preferences.h"
+#include "ipc/ipc_message.h"
+#include "net/base/net_errors.h"
+#include "ui/display/display.h"
+#include "ui/display/screen.h"
+#include "url/gurl.h"
+
+#if defined(OS_ANDROID)
+#include "chromecast/browser/android/cast_web_contents_activity.h"
+#endif // defined(OS_ANDROID)
+
+#if defined(USE_AURA)
+#include "ui/aura/window.h"
+#endif
+
+namespace chromecast {
+
+namespace {
+// The time (in milliseconds) we wait for after a page is closed (i.e.
+// after an app is stopped) before we delete the corresponding WebContents.
+constexpr int kWebContentsDestructionDelayInMs = 50;
+
+std::unique_ptr<content::WebContents> CreateWebContents(
+ content::BrowserContext* browser_context,
+ scoped_refptr<content::SiteInstance> site_instance) {
+ CHECK(display::Screen::GetScreen());
+ gfx::Size display_size =
+ display::Screen::GetScreen()->GetPrimaryDisplay().size();
+
+ content::WebContents::CreateParams create_params(browser_context, NULL);
+ create_params.routing_id = MSG_ROUTING_NONE;
+ create_params.initial_size = display_size;
+ create_params.site_instance = site_instance;
+ content::WebContents* web_contents =
+ content::WebContents::Create(create_params);
+
+#if defined(USE_AURA)
+ // Resize window
+ aura::Window* content_window = web_contents->GetNativeView();
+ content_window->SetBounds(
+ gfx::Rect(display_size.width(), display_size.height()));
+#endif
+
+#if defined(OS_ANDROID)
+ content::RendererPreferences* prefs = web_contents->GetMutableRendererPrefs();
+ prefs->use_video_overlay_for_embedded_encrypted_video = true;
+ web_contents->GetRenderViewHost()->SyncRendererPrefs();
+#endif
+
+ return base::WrapUnique(web_contents);
+}
+
+} // namespace
+
+CastWebView::CastWebView(Delegate* delegate,
+ content::BrowserContext* browser_context,
+ scoped_refptr<content::SiteInstance> site_instance,
+ bool transparent)
+ : delegate_(delegate),
+ browser_context_(browser_context),
+ site_instance_(std::move(site_instance)),
+ transparent_(transparent),
+ window_(shell::CastContentWindow::Create(delegate)),
+ web_contents_(CreateWebContents(browser_context_, site_instance_)),
+ weak_factory_(this) {
+ DCHECK(delegate_);
+ DCHECK(browser_context_);
+ DCHECK(window_);
+ content::WebContentsObserver::Observe(web_contents_.get());
+ web_contents_->SetDelegate(this);
+
+ if (transparent_)
+ window_->SetTransparent();
+}
+
+CastWebView::~CastWebView() {}
halliwell 2017/02/20 22:09:11 do we need WebContentsObserver::Observe(nullptr),
derekjchow1 2017/02/22 00:50:41 Looks like it's taken care of in the WebContentsOb
+
+void CastWebView::LoadUrl(GURL url) {
+ web_contents_->GetController().LoadURL(url, content::Referrer(),
+ ui::PAGE_TRANSITION_TYPED, "");
+}
+
+void CastWebView::ClosePage() {
+ content::WebContentsObserver::Observe(nullptr);
+ web_contents_->ClosePage();
+}
+
+void CastWebView::CloseContents(content::WebContents* source) {
+ DCHECK_EQ(source, web_contents_.get());
+
+ // We need to delay the deletion of web_contents_ (currently for 50ms) to
halliwell 2017/02/20 22:09:11 nit, delete 'currently for 50ms' ... just risks be
derekjchow1 2017/02/22 00:50:41 Done.
+ // give (and guarantee) the renderer enough time to finish 'onunload'
+ // handler (but we don't want to wait any longer than that to delay the
+ // starting of next app).
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, base::Bind(&CastWebView::DelayedCloseContents,
+ weak_factory_.GetWeakPtr()),
+ base::TimeDelta::FromMilliseconds(kWebContentsDestructionDelayInMs));
+}
+
+void CastWebView::DelayedCloseContents() {
+ // Delete the WebContents object here so that the gfx surface will be
+ // deleted as part of destroying RenderWidgetHostViewCast object.
+ // We want to delete the surface before we start the next app because
+ // the next app could be an external one whose Start() function would
+ // destroy the primary gfx plane.
+ web_contents_.reset();
+ delegate_->OnPageStopped(net::OK);
+}
+
+void CastWebView::Show(CastWindowManager* window_manager) {
+ DCHECK(window_manager);
+ window_->ShowWebContents(web_contents_.get(), window_manager);
+ web_contents_->Focus();
+}
+
+content::WebContents* CastWebView::OpenURLFromTab(
+ content::WebContents* source,
+ const content::OpenURLParams& params) {
+ LOG(INFO) << "Change url: " << params.url;
+ // If source is NULL which means current tab, use web_contents_ of this class.
+ if (!source)
+ source = web_contents_.get();
+ DCHECK_EQ(source, web_contents_.get());
+ // We don't want to create another web_contents. Load url only when source is
+ // specified.
+ if (source) {
halliwell 2017/02/20 22:09:11 in what scenario is source null here?
derekjchow1 2017/02/22 00:50:41 I don't think it's ever null. I don't think web_co
+ source->GetController().LoadURL(params.url, params.referrer,
+ params.transition, params.extra_headers);
+ }
+ return source;
+}
+
+void CastWebView::LoadingStateChanged(content::WebContents* source,
+ bool to_different_document) {
+ delegate_->OnLoadingStateChanged(source->IsLoading());
+}
+
+void CastWebView::ActivateContents(content::WebContents* contents) {
+ DCHECK_EQ(contents, web_contents_.get());
+ contents->GetRenderViewHost()->GetWidget()->Focus();
+}
+
+#if defined(OS_ANDROID)
+base::android::ScopedJavaLocalRef<jobject>
+CastWebView::GetContentVideoViewEmbedder() {
+ DCHECK(web_contents_);
+ auto activity = shell::CastWebContentsActivity::Get(web_contents_.get());
+ return activity->GetContentVideoViewEmbedder();
+}
+#endif // defined(OS_ANDROID)
+
+void CastWebView::RenderProcessGone(base::TerminationStatus status) {
+ LOG(INFO) << "APP_ERROR_CHILD_PROCESS_CRASHED";
+ delegate_->OnPageStopped(net::ERR_UNEXPECTED);
+}
+
+void CastWebView::RenderViewCreated(content::RenderViewHost* render_view_host) {
+ content::RenderWidgetHostView* view =
+ render_view_host->GetWidget()->GetView();
+ if (view) {
+ view->SetBackgroundColor(transparent_ ? SK_ColorTRANSPARENT
+ : SK_ColorBLACK);
+ }
+}
+
+void CastWebView::DidFinishNavigation(
+ content::NavigationHandle* navigation_handle) {
+ // If the navigation was not committed, it means either the page was a
+ // download or error 204/205, or the navigation never left the previous
+ // URL. Ignore these navigations.
+ if (!navigation_handle->HasCommitted()) {
+ LOG(WARNING) << "Navigation did not commit: url="
+ << navigation_handle->GetURL();
+ return;
+ }
+
+ net::Error error_code = navigation_handle->GetNetErrorCode();
+ if (!navigation_handle->IsErrorPage())
+ return;
+
+ // If we abort errors in an iframe, it can create a really confusing
+ // and fragile user experience. Rather than create a list of errors
+ // that are most likely to occur, we ignore all of them for now.
+ if (!navigation_handle->IsInMainFrame()) {
+ LOG(ERROR) << "Got error on sub-iframe: url=" << navigation_handle->GetURL()
+ << ", error=" << error_code
+ << ", description=" << net::ErrorToShortString(error_code);
+ return;
+ }
+
+ LOG(ERROR) << "Got error on navigation: url=" << navigation_handle->GetURL()
+ << ", error_code=" << error_code
+ << ", description= " << net::ErrorToShortString(error_code);
+ delegate_->OnPageStopped(error_code);
+}
+
+void CastWebView::DidFailLoad(content::RenderFrameHost* render_frame_host,
+ const GURL& validated_url,
+ int error_code,
+ const base::string16& error_description,
+ bool was_ignored_by_handler) {
+ // Only report an error if we are the main frame. See b/8433611.
+ if (render_frame_host->GetParent()) {
+ LOG(ERROR) << "Got error on sub-iframe: url=" << validated_url.spec()
+ << ", error=" << error_code;
+ } else if (error_code == net::ERR_ABORTED) {
+ // ERR_ABORTED means download was aborted by the app, typically this happens
+ // when flinging URL for direct playback, the initial URLRequest gets
+ // cancelled/aborted and then the same URL is requested via the buffered
+ // data source for media::Pipeline playback.
+ LOG(INFO) << "Load canceled: url=" << validated_url.spec();
+ } else {
+ LOG(ERROR) << "Got error on load: url=" << validated_url.spec()
+ << ", error_code=" << error_code;
+ delegate_->OnPageStopped(error_code);
+ }
+}
+
+void CastWebView::DidFirstVisuallyNonEmptyPaint() {
+ metrics::CastMetricsHelper::GetInstance()->LogTimeToFirstPaint();
+}
+
+void CastWebView::DidStartNavigation(
+ content::NavigationHandle* navigation_handle) {
+#if defined(USE_AURA)
+ // Resize window
+ gfx::Size display_size =
+ display::Screen::GetScreen()->GetPrimaryDisplay().size();
+ aura::Window* content_window = web_contents()->GetNativeView();
+ content_window->SetBounds(
+ gfx::Rect(display_size.width(), display_size.height()));
+#endif
+}
+
+void CastWebView::MediaStartedPlaying(const MediaPlayerInfo& media_info,
+ const MediaPlayerId& id) {
+ metrics::CastMetricsHelper::GetInstance()->LogMediaPlay();
+}
+
+void CastWebView::MediaStoppedPlaying(const MediaPlayerInfo& media_info,
+ const MediaPlayerId& id) {
+ metrics::CastMetricsHelper::GetInstance()->LogMediaPause();
+}
+
+} // namespace chromecast

Powered by Google App Engine
This is Rietveld 408576698