Commit ce4e5a10 authored by Shawn Gallea's avatar Shawn Gallea Committed by Commit Bot

Add WebContentController

Split WebviewController into a generic base class that only
deals with mutating the WebContents. The split allows implementing
a Webview and CastApp controller differently while retaining common
functionality in the base class.


Bug: b/136460199
Test: Compile
Change-Id: I4267e3c6ac4e3904160e7ee34e35d2b220777cad
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1867189Reviewed-by: default avatarDaniel Nicoara <dnicoara@chromium.org>
Commit-Queue: Shawn Gallea <sagallea@google.com>
Cr-Commit-Position: refs/heads/master@{#707487}
parent 0e80dc08
...@@ -382,6 +382,8 @@ cast_source_set("browser") { ...@@ -382,6 +382,8 @@ cast_source_set("browser") {
"exo/cast_wm_helper.h", "exo/cast_wm_helper.h",
"exo/wayland_server_controller.cc", "exo/wayland_server_controller.cc",
"exo/wayland_server_controller.h", "exo/wayland_server_controller.h",
"webview/web_content_controller.cc",
"webview/web_content_controller.h",
"webview/webview_controller.cc", "webview/webview_controller.cc",
"webview/webview_controller.h", "webview/webview_controller.h",
"webview/webview_grpc_service.cc", "webview/webview_grpc_service.cc",
......
// Copyright 2019 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/webview/web_content_controller.h"
#include "base/json/json_writer.h"
#include "base/strings/utf_string_conversions.h"
#include "chromecast/base/version.h"
#include "chromecast/browser/webview/proto/webview.pb.h"
#include "chromecast/browser/webview/webview_layout_manager.h"
#include "chromecast/browser/webview/webview_navigation_throttle.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browsing_data_remover.h"
#include "content/public/browser/navigation_handle.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/browser/web_contents.h"
#include "content/public/common/web_preferences.h"
#include "ui/aura/window.h"
#include "ui/aura/window_delegate.h"
#include "ui/events/event.h"
namespace chromecast {
WebContentController::WebContentController(Client* client) : client_(client) {}
WebContentController::~WebContentController() {
if (surface_) {
surface_->RemoveSurfaceObserver(this);
surface_->SetEmbeddedSurfaceId(base::RepeatingCallback<viz::SurfaceId()>());
}
}
void WebContentController::ProcessRequest(
const webview::WebviewRequest& request) {
content::WebContents* contents = GetWebContents();
switch (request.type_case()) {
case webview::WebviewRequest::kInput:
ProcessInputEvent(request.input());
break;
case webview::WebviewRequest::kEvaluateJavascript:
if (request.has_evaluate_javascript()) {
HandleEvaluateJavascript(request.id(), request.evaluate_javascript());
} else {
client_->OnError("evaluate_javascript() not supplied");
}
break;
case webview::WebviewRequest::kAddJavascriptChannels:
if (request.has_add_javascript_channels()) {
HandleAddJavascriptChannels(request.add_javascript_channels());
} else {
client_->OnError("add_javascript_channels() not supplied");
}
break;
case webview::WebviewRequest::kRemoveJavascriptChannels:
if (request.has_remove_javascript_channels()) {
HandleRemoveJavascriptChannels(request.remove_javascript_channels());
} else {
client_->OnError("remove_javascript_channels() not supplied");
}
break;
case webview::WebviewRequest::kGetCurrentUrl:
HandleGetCurrentUrl(request.id());
break;
case webview::WebviewRequest::kCanGoBack:
HandleCanGoBack(request.id());
break;
case webview::WebviewRequest::kCanGoForward:
HandleCanGoForward(request.id());
break;
case webview::WebviewRequest::kGoBack:
contents->GetController().GoBack();
break;
case webview::WebviewRequest::kGoForward:
contents->GetController().GoForward();
break;
case webview::WebviewRequest::kReload:
// TODO(dnicoara): Are the default parameters correct?
contents->GetController().Reload(content::ReloadType::NORMAL,
/*check_for_repost=*/true);
break;
case webview::WebviewRequest::kClearCache:
HandleClearCache();
break;
case webview::WebviewRequest::kUpdateSettings:
if (request.has_update_settings()) {
HandleUpdateSettings(request.update_settings());
} else {
client_->OnError("update_settings() not supplied");
}
break;
case webview::WebviewRequest::kGetTitle:
HandleGetTitle(request.id());
break;
case webview::WebviewRequest::kSetAutoMediaPlaybackPolicy:
if (request.has_set_auto_media_playback_policy()) {
HandleSetAutoMediaPlaybackPolicy(
request.set_auto_media_playback_policy());
} else {
client_->OnError("set_auto_media_playback_policy() not supplied");
}
break;
default:
client_->OnError("Unknown request code");
break;
}
}
void WebContentController::AttachTo(aura::Window* window, int window_id) {
content::WebContents* contents = GetWebContents();
auto* contents_window = contents->GetNativeView();
window->SetLayoutManager(new WebviewLayoutManager(window, contents_window));
contents_window->set_id(window_id);
contents_window->SetBounds(gfx::Rect(window->bounds().size()));
// The aura window is hidden to avoid being shown via the usual layer method,
// instead it is shows via a SurfaceDrawQuad by exo.
contents_window->Hide();
window->AddChild(contents_window);
exo::Surface* surface = exo::Surface::AsSurface(window);
CHECK(surface) << "Attaching Webview to non-EXO surface window";
CHECK(!surface_) << "Attaching already attached WebView";
surface_ = surface;
surface_->AddSurfaceObserver(this);
// Unretained is safe because we unset this in the destructor.
surface_->SetEmbeddedSurfaceId(
base::Bind(&WebContentController::GetSurfaceId, base::Unretained(this)));
}
void WebContentController::ProcessInputEvent(const webview::InputEvent& ev) {
content::WebContents* contents = GetWebContents();
// Ensure this web contents has focus before sending it input.
if (!contents->GetNativeView()->HasFocus())
contents->GetNativeView()->Focus();
ui::EventHandler* handler =
contents->GetRenderWidgetHostView()->GetNativeView()->delegate();
ui::EventType type = static_cast<ui::EventType>(ev.event_type());
switch (type) {
case ui::ET_TOUCH_RELEASED:
case ui::ET_TOUCH_PRESSED:
case ui::ET_TOUCH_MOVED:
case ui::ET_TOUCH_CANCELLED:
if (ev.has_touch()) {
auto& touch = ev.touch();
ui::TouchEvent evt(
type, gfx::PointF(touch.x(), touch.y()),
gfx::PointF(touch.root_x(), touch.root_y()),
base::TimeTicks() +
base::TimeDelta::FromMicroseconds(ev.timestamp()),
ui::PointerDetails(
static_cast<ui::EventPointerType>(touch.pointer_type()),
static_cast<ui::PointerId>(touch.pointer_id()),
touch.radius_x(), touch.radius_y(), touch.force(),
touch.twist(), touch.tilt_x(), touch.tilt_y(),
touch.tangential_pressure()),
ev.flags());
ui::TouchEvent root_relative_event(evt);
root_relative_event.set_location_f(evt.root_location_f());
// GestureRecognizerImpl makes several APIs private so cast it to the
// interface.
ui::GestureRecognizer* recognizer = &gesture_recognizer_;
// Run touches through the gesture recognition pipeline, web content
// typically wants to process gesture events, not touch events.
if (!recognizer->ProcessTouchEventPreDispatch(
&root_relative_event, contents->GetNativeView())) {
return;
}
handler->OnTouchEvent(&evt);
// Normally this would be done when the renderer acknowledges the touch
// event and using flags from the renderer, inside
// RenderWidgetHostViewAura, but we don't have those so... fake it.
auto list =
recognizer->AckTouchEvent(evt.unique_event_id(), ui::ER_UNHANDLED,
false, contents->GetNativeView());
for (auto& e : list) {
// Forward all gestures.
handler->OnGestureEvent(e.get());
}
} else {
client_->OnError("touch() not supplied for touch event");
}
break;
case ui::ET_MOUSE_PRESSED:
case ui::ET_MOUSE_DRAGGED:
case ui::ET_MOUSE_RELEASED:
case ui::ET_MOUSE_MOVED:
case ui::ET_MOUSE_ENTERED:
case ui::ET_MOUSE_EXITED:
case ui::ET_MOUSEWHEEL:
case ui::ET_MOUSE_CAPTURE_CHANGED:
if (ev.has_mouse()) {
auto& mouse = ev.mouse();
ui::MouseEvent evt(
type, gfx::PointF(mouse.x(), mouse.y()),
gfx::PointF(mouse.root_x(), mouse.root_y()),
base::TimeTicks() +
base::TimeDelta::FromMicroseconds(ev.timestamp()),
ev.flags(), mouse.changed_button_flags());
handler->OnMouseEvent(&evt);
} else {
client_->OnError("mouse() not supplied for mouse event");
}
break;
default:
break;
}
}
void WebContentController::JavascriptCallback(int64_t id, base::Value result) {
std::string json;
base::JSONWriter::Write(result, &json);
std::unique_ptr<webview::WebviewResponse> response =
std::make_unique<webview::WebviewResponse>();
response->set_id(id);
response->mutable_evaluate_javascript()->set_json(json);
client_->EnqueueSend(std::move(response));
}
void WebContentController::HandleEvaluateJavascript(
int64_t id,
const webview::EvaluateJavascriptRequest& request) {
GetWebContents()->GetMainFrame()->ExecuteJavaScript(
base::UTF8ToUTF16(request.javascript_blob()),
base::BindOnce(&WebContentController::JavascriptCallback,
weak_ptr_factory_.GetWeakPtr(), id));
}
void WebContentController::HandleAddJavascriptChannels(
const webview::AddJavascriptChannelsRequest& request) {
// TODO(dnicoara): Handle this.
}
void WebContentController::HandleRemoveJavascriptChannels(
const webview::RemoveJavascriptChannelsRequest& request) {
// TODO(dnicoara): Handle this.
}
void WebContentController::HandleGetCurrentUrl(int64_t id) {
std::unique_ptr<webview::WebviewResponse> response =
std::make_unique<webview::WebviewResponse>();
response->set_id(id);
response->mutable_get_current_url()->set_url(
GetWebContents()->GetURL().spec());
client_->EnqueueSend(std::move(response));
}
void WebContentController::HandleCanGoBack(int64_t id) {
std::unique_ptr<webview::WebviewResponse> response =
std::make_unique<webview::WebviewResponse>();
response->set_id(id);
response->mutable_can_go_back()->set_can_go_back(
GetWebContents()->GetController().CanGoBack());
client_->EnqueueSend(std::move(response));
}
void WebContentController::HandleCanGoForward(int64_t id) {
std::unique_ptr<webview::WebviewResponse> response =
std::make_unique<webview::WebviewResponse>();
response->set_id(id);
response->mutable_can_go_forward()->set_can_go_forward(
GetWebContents()->GetController().CanGoForward());
client_->EnqueueSend(std::move(response));
}
void WebContentController::HandleClearCache() {
// TODO(dnicoara): See if there is a generic way to inform the renderer to
// clear cache.
// Android has a specific renderer message for this:
// https://cs.chromium.org/chromium/src/android_webview/common/render_view_messages.h?rcl=65107121555167a3db39de5633c3297f7e861315&l=44
// Remove disk cache.
content::BrowsingDataRemover* remover =
content::BrowserContext::GetBrowsingDataRemover(
GetWebContents()->GetBrowserContext());
remover->Remove(base::Time(), base::Time::Max(),
content::BrowsingDataRemover::DATA_TYPE_CACHE,
content::BrowsingDataRemover::ORIGIN_TYPE_UNPROTECTED_WEB |
content::BrowsingDataRemover::ORIGIN_TYPE_PROTECTED_WEB);
}
void WebContentController::HandleGetTitle(int64_t id) {
std::unique_ptr<webview::WebviewResponse> response =
std::make_unique<webview::WebviewResponse>();
response->set_id(id);
response->mutable_get_title()->set_title(
base::UTF16ToUTF8(GetWebContents()->GetTitle()));
client_->EnqueueSend(std::move(response));
}
void WebContentController::HandleUpdateSettings(
const webview::UpdateSettingsRequest& request) {
content::WebContents* contents = GetWebContents();
content::WebPreferences prefs =
contents->GetRenderViewHost()->GetWebkitPreferences();
prefs.javascript_enabled = request.javascript_enabled();
contents->GetRenderViewHost()->UpdateWebkitPreferences(prefs);
has_navigation_delegate_ = request.has_navigation_delegate();
// Given that cast_shell enables devtools unconditionally there isn't
// anything that needs to be done for |request.debugging_enabled()|. Though,
// as a note, remote debugging is always on.
if (request.has_user_agent() &&
request.user_agent().type_case() == webview::UserAgent::kValue) {
contents->SetUserAgentOverride(request.user_agent().value(), true);
}
}
void WebContentController::HandleSetAutoMediaPlaybackPolicy(
const webview::SetAutoMediaPlaybackPolicyRequest& request) {
content::WebContents* contents = GetWebContents();
content::WebPreferences prefs =
contents->GetRenderViewHost()->GetWebkitPreferences();
prefs.autoplay_policy = request.require_user_gesture()
? content::AutoplayPolicy::kUserGestureRequired
: content::AutoplayPolicy::kNoUserGestureRequired;
contents->GetRenderViewHost()->UpdateWebkitPreferences(prefs);
}
viz::SurfaceId WebContentController::GetSurfaceId() {
auto* rwhv = GetWebContents()->GetRenderWidgetHostView();
if (!rwhv)
return viz::SurfaceId();
auto frame_sink_id = rwhv->GetRenderWidgetHost()->GetFrameSinkId();
auto local_surface_id =
rwhv->GetNativeView()->GetLocalSurfaceIdAllocation().local_surface_id();
return viz::SurfaceId(frame_sink_id, local_surface_id);
}
void WebContentController::OnSurfaceDestroying(exo::Surface* surface) {
DCHECK_EQ(surface, surface_);
surface->RemoveSurfaceObserver(this);
surface_ = nullptr;
}
} // namespace chromecast
// Copyright 2019 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 CHROMECAST_BROWSER_WEBVIEW_WEB_CONTENT_CONTROLLER_H_
#define CHROMECAST_BROWSER_WEBVIEW_WEB_CONTENT_CONTROLLER_H_
#include <memory>
#include <string>
#include "chromecast/browser/webview/proto/webview.pb.h"
#include "components/exo/surface.h"
#include "components/exo/surface_observer.h"
#include "ui/events/gestures/gesture_recognizer_impl.h"
namespace aura {
class Window;
} // namespace aura
namespace content {
class WebContents;
} // namespace content
namespace chromecast {
// Processes proto commands to control WebContents
class WebContentController : public exo::SurfaceObserver {
public:
class Client {
public:
virtual ~Client() {}
virtual void EnqueueSend(
std::unique_ptr<webview::WebviewResponse> response) = 0;
virtual void OnError(const std::string& error_message) = 0;
};
WebContentController(Client* client);
~WebContentController() override;
virtual void Destroy() = 0;
virtual void ProcessRequest(const webview::WebviewRequest& request);
// Attach this web contents to an aura window as a child.
void AttachTo(aura::Window* window, int window_id);
protected:
virtual content::WebContents* GetWebContents() = 0;
Client* client_; // Not owned.
bool has_navigation_delegate_ = false;
private:
void ProcessInputEvent(const webview::InputEvent& ev);
void JavascriptCallback(int64_t id, base::Value result);
void HandleEvaluateJavascript(
int64_t id,
const webview::EvaluateJavascriptRequest& request);
void HandleAddJavascriptChannels(
const webview::AddJavascriptChannelsRequest& request);
void HandleRemoveJavascriptChannels(
const webview::RemoveJavascriptChannelsRequest& request);
void HandleGetCurrentUrl(int64_t id);
void HandleCanGoBack(int64_t id);
void HandleCanGoForward(int64_t id);
void HandleClearCache();
void HandleGetTitle(int64_t id);
void HandleUpdateSettings(const webview::UpdateSettingsRequest& request);
void HandleSetAutoMediaPlaybackPolicy(
const webview::SetAutoMediaPlaybackPolicyRequest& request);
viz::SurfaceId GetSurfaceId();
// exo::SurfaceObserver
void OnSurfaceDestroying(exo::Surface* surface) override;
ui::GestureRecognizerImpl gesture_recognizer_;
exo::Surface* surface_ = nullptr;
base::WeakPtrFactory<WebContentController> weak_ptr_factory_{this};
DISALLOW_COPY_AND_ASSIGN(WebContentController);
};
} // namespace chromecast
#endif // CHROMECAST_BROWSER_WEBVIEW_WEB_CONTENT_CONTROLLER_H_
...@@ -19,9 +19,6 @@ ...@@ -19,9 +19,6 @@
#include "content/public/browser/render_widget_host_view.h" #include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents.h"
#include "content/public/common/web_preferences.h" #include "content/public/common/web_preferences.h"
#include "ui/aura/window.h"
#include "ui/aura/window_delegate.h"
#include "ui/events/event.h"
namespace chromecast { namespace chromecast {
...@@ -46,7 +43,7 @@ class WebviewUserData : public base::SupportsUserData::Data { ...@@ -46,7 +43,7 @@ class WebviewUserData : public base::SupportsUserData::Data {
WebviewController::WebviewController(content::BrowserContext* browser_context, WebviewController::WebviewController(content::BrowserContext* browser_context,
Client* client) Client* client)
: client_(client) { : WebContentController(client) {
content::WebContents::CreateParams create_params(browser_context, nullptr); content::WebContents::CreateParams create_params(browser_context, nullptr);
contents_ = content::WebContents::Create(create_params); contents_ = content::WebContents::Create(create_params);
contents_->SetUserData(kWebviewResponseUserDataKey, contents_->SetUserData(kWebviewResponseUserDataKey,
...@@ -70,11 +67,6 @@ WebviewController::WebviewController(content::BrowserContext* browser_context, ...@@ -70,11 +67,6 @@ WebviewController::WebviewController(content::BrowserContext* browser_context,
WebviewController::~WebviewController() { WebviewController::~WebviewController() {
cast_web_contents_->RemoveObserver(this); cast_web_contents_->RemoveObserver(this);
if (surface_) {
surface_->RemoveSurfaceObserver(this);
surface_->SetEmbeddedSurfaceId(base::RepeatingCallback<viz::SurfaceId()>());
}
} }
std::unique_ptr<content::NavigationThrottle> std::unique_ptr<content::NavigationThrottle>
...@@ -93,10 +85,6 @@ WebviewController::MaybeGetNavigationThrottle( ...@@ -93,10 +85,6 @@ WebviewController::MaybeGetNavigationThrottle(
void WebviewController::ProcessRequest(const webview::WebviewRequest& request) { void WebviewController::ProcessRequest(const webview::WebviewRequest& request) {
switch (request.type_case()) { switch (request.type_case()) {
case webview::WebviewRequest::kInput:
ProcessInputEvent(request.input());
break;
case webview::WebviewRequest::kNavigate: case webview::WebviewRequest::kNavigate:
if (request.has_navigate()) { if (request.has_navigate()) {
LOG(INFO) << "Navigate webview to " << request.navigate().url(); LOG(INFO) << "Navigate webview to " << request.navigate().url();
...@@ -115,80 +103,6 @@ void WebviewController::ProcessRequest(const webview::WebviewRequest& request) { ...@@ -115,80 +103,6 @@ void WebviewController::ProcessRequest(const webview::WebviewRequest& request) {
} }
break; break;
case webview::WebviewRequest::kEvaluateJavascript:
if (request.has_evaluate_javascript()) {
HandleEvaluateJavascript(request.id(), request.evaluate_javascript());
} else {
client_->OnError("evaluate_javascript() not supplied");
}
break;
case webview::WebviewRequest::kAddJavascriptChannels:
if (request.has_add_javascript_channels()) {
HandleAddJavascriptChannels(request.add_javascript_channels());
} else {
client_->OnError("add_javascript_channels() not supplied");
}
break;
case webview::WebviewRequest::kRemoveJavascriptChannels:
if (request.has_remove_javascript_channels()) {
HandleRemoveJavascriptChannels(request.remove_javascript_channels());
} else {
client_->OnError("remove_javascript_channels() not supplied");
}
break;
case webview::WebviewRequest::kGetCurrentUrl:
HandleGetCurrentUrl(request.id());
break;
case webview::WebviewRequest::kCanGoBack:
HandleCanGoBack(request.id());
break;
case webview::WebviewRequest::kCanGoForward:
HandleCanGoForward(request.id());
break;
case webview::WebviewRequest::kGoBack:
contents_->GetController().GoBack();
break;
case webview::WebviewRequest::kGoForward:
contents_->GetController().GoForward();
break;
case webview::WebviewRequest::kReload:
// TODO(dnicoara): Are the default parameters correct?
contents_->GetController().Reload(content::ReloadType::NORMAL,
/*check_for_repost=*/true);
break;
case webview::WebviewRequest::kClearCache:
HandleClearCache();
break;
case webview::WebviewRequest::kUpdateSettings:
if (request.has_update_settings()) {
HandleUpdateSettings(request.update_settings());
} else {
client_->OnError("update_settings() not supplied");
}
break;
case webview::WebviewRequest::kGetTitle:
HandleGetTitle(request.id());
break;
case webview::WebviewRequest::kSetAutoMediaPlaybackPolicy:
if (request.has_set_auto_media_playback_policy()) {
HandleSetAutoMediaPlaybackPolicy(
request.set_auto_media_playback_policy());
} else {
client_->OnError("set_auto_media_playback_policy() not supplied");
}
break;
case webview::WebviewRequest::kNavigationDecision: case webview::WebviewRequest::kNavigationDecision:
if (current_navigation_throttle_) { if (current_navigation_throttle_) {
current_navigation_throttle_->ProcessNavigationDecision( current_navigation_throttle_->ProcessNavigationDecision(
...@@ -196,8 +110,9 @@ void WebviewController::ProcessRequest(const webview::WebviewRequest& request) { ...@@ -196,8 +110,9 @@ void WebviewController::ProcessRequest(const webview::WebviewRequest& request) {
current_navigation_throttle_ = nullptr; current_navigation_throttle_ = nullptr;
} }
break; break;
default: default:
client_->OnError("Unknown request code"); WebContentController::ProcessRequest(request);
break; break;
} }
} }
...@@ -218,239 +133,8 @@ void WebviewController::ClosePage() { ...@@ -218,239 +133,8 @@ void WebviewController::ClosePage() {
cast_web_contents_->ClosePage(); cast_web_contents_->ClosePage();
} }
viz::SurfaceId WebviewController::GetSurfaceId() { content::WebContents* WebviewController::GetWebContents() {
auto* rwhv = contents_->GetRenderWidgetHostView(); return contents_.get();
if (!rwhv)
return viz::SurfaceId();
auto frame_sink_id = rwhv->GetRenderWidgetHost()->GetFrameSinkId();
auto local_surface_id =
rwhv->GetNativeView()->GetLocalSurfaceIdAllocation().local_surface_id();
return viz::SurfaceId(frame_sink_id, local_surface_id);
}
void WebviewController::AttachTo(aura::Window* window, int window_id) {
auto* contents_window = contents_->GetNativeView();
window->SetLayoutManager(new WebviewLayoutManager(window, contents_window));
contents_window->set_id(window_id);
contents_window->SetBounds(gfx::Rect(window->bounds().size()));
// The aura window is hidden to avoid being shown via the usual layer method,
// instead it is shows via a SurfaceDrawQuad by exo.
contents_window->Hide();
window->AddChild(contents_window);
exo::Surface* surface = exo::Surface::AsSurface(window);
CHECK(surface) << "Attaching Webview to non-EXO surface window";
CHECK(!surface_) << "Attaching already attached WebView";
surface_ = surface;
surface_->AddSurfaceObserver(this);
// Unretained is safe because we unset this in the destructor.
surface_->SetEmbeddedSurfaceId(
base::Bind(&WebviewController::GetSurfaceId, base::Unretained(this)));
}
void WebviewController::OnSurfaceDestroying(exo::Surface* surface) {
DCHECK_EQ(surface, surface_);
surface->RemoveSurfaceObserver(this);
surface_ = nullptr;
}
void WebviewController::ProcessInputEvent(const webview::InputEvent& ev) {
// Ensure this web contents has focus before sending it input.
if (!contents_->GetNativeView()->HasFocus())
contents_->GetNativeView()->Focus();
ui::EventHandler* handler =
contents_->GetRenderWidgetHostView()->GetNativeView()->delegate();
ui::EventType type = static_cast<ui::EventType>(ev.event_type());
switch (type) {
case ui::ET_TOUCH_RELEASED:
case ui::ET_TOUCH_PRESSED:
case ui::ET_TOUCH_MOVED:
case ui::ET_TOUCH_CANCELLED:
if (ev.has_touch()) {
auto& touch = ev.touch();
ui::TouchEvent evt(
type, gfx::PointF(touch.x(), touch.y()),
gfx::PointF(touch.root_x(), touch.root_y()),
base::TimeTicks() +
base::TimeDelta::FromMicroseconds(ev.timestamp()),
ui::PointerDetails(
static_cast<ui::EventPointerType>(touch.pointer_type()),
static_cast<ui::PointerId>(touch.pointer_id()),
touch.radius_x(), touch.radius_y(), touch.force(),
touch.twist(), touch.tilt_x(), touch.tilt_y(),
touch.tangential_pressure()),
ev.flags());
ui::TouchEvent root_relative_event(evt);
root_relative_event.set_location_f(evt.root_location_f());
// GestureRecognizerImpl makes several APIs private so cast it to the
// interface.
ui::GestureRecognizer* recognizer = &gesture_recognizer_;
// Run touches through the gesture recognition pipeline, web content
// typically wants to process gesture events, not touch events.
if (!recognizer->ProcessTouchEventPreDispatch(
&root_relative_event, contents_->GetNativeView())) {
return;
}
handler->OnTouchEvent(&evt);
// Normally this would be done when the renderer acknowledges the touch
// event and using flags from the renderer, inside
// RenderWidgetHostViewAura, but we don't have those so... fake it.
auto list =
recognizer->AckTouchEvent(evt.unique_event_id(), ui::ER_UNHANDLED,
false, contents_->GetNativeView());
for (auto& e : list) {
// Forward all gestures.
handler->OnGestureEvent(e.get());
}
} else {
client_->OnError("touch() not supplied for touch event");
}
break;
case ui::ET_MOUSE_PRESSED:
case ui::ET_MOUSE_DRAGGED:
case ui::ET_MOUSE_RELEASED:
case ui::ET_MOUSE_MOVED:
case ui::ET_MOUSE_ENTERED:
case ui::ET_MOUSE_EXITED:
case ui::ET_MOUSEWHEEL:
case ui::ET_MOUSE_CAPTURE_CHANGED:
if (ev.has_mouse()) {
auto& mouse = ev.mouse();
ui::MouseEvent evt(
type, gfx::PointF(mouse.x(), mouse.y()),
gfx::PointF(mouse.root_x(), mouse.root_y()),
base::TimeTicks() +
base::TimeDelta::FromMicroseconds(ev.timestamp()),
ev.flags(), mouse.changed_button_flags());
handler->OnMouseEvent(&evt);
} else {
client_->OnError("mouse() not supplied for mouse event");
}
break;
default:
break;
}
}
void WebviewController::JavascriptCallback(int64_t id, base::Value result) {
std::string json;
base::JSONWriter::Write(result, &json);
std::unique_ptr<webview::WebviewResponse> response =
std::make_unique<webview::WebviewResponse>();
response->set_id(id);
response->mutable_evaluate_javascript()->set_json(json);
client_->EnqueueSend(std::move(response));
}
void WebviewController::HandleEvaluateJavascript(
int64_t id,
const webview::EvaluateJavascriptRequest& request) {
contents_->GetMainFrame()->ExecuteJavaScript(
base::UTF8ToUTF16(request.javascript_blob()),
base::BindOnce(&WebviewController::JavascriptCallback,
weak_ptr_factory_.GetWeakPtr(), id));
}
void WebviewController::HandleAddJavascriptChannels(
const webview::AddJavascriptChannelsRequest& request) {
// TODO(dnicoara): Handle this.
}
void WebviewController::HandleRemoveJavascriptChannels(
const webview::RemoveJavascriptChannelsRequest& request) {
// TODO(dnicoara): Handle this.
}
void WebviewController::HandleGetCurrentUrl(int64_t id) {
std::unique_ptr<webview::WebviewResponse> response =
std::make_unique<webview::WebviewResponse>();
response->set_id(id);
response->mutable_get_current_url()->set_url(contents_->GetURL().spec());
client_->EnqueueSend(std::move(response));
}
void WebviewController::HandleCanGoBack(int64_t id) {
std::unique_ptr<webview::WebviewResponse> response =
std::make_unique<webview::WebviewResponse>();
response->set_id(id);
response->mutable_can_go_back()->set_can_go_back(
contents_->GetController().CanGoBack());
client_->EnqueueSend(std::move(response));
}
void WebviewController::HandleCanGoForward(int64_t id) {
std::unique_ptr<webview::WebviewResponse> response =
std::make_unique<webview::WebviewResponse>();
response->set_id(id);
response->mutable_can_go_forward()->set_can_go_forward(
contents_->GetController().CanGoForward());
client_->EnqueueSend(std::move(response));
}
void WebviewController::HandleClearCache() {
// TODO(dnicoara): See if there is a generic way to inform the renderer to
// clear cache.
// Android has a specific renderer message for this:
// https://cs.chromium.org/chromium/src/android_webview/common/render_view_messages.h?rcl=65107121555167a3db39de5633c3297f7e861315&l=44
// Remove disk cache.
content::BrowsingDataRemover* remover =
content::BrowserContext::GetBrowsingDataRemover(
contents_->GetBrowserContext());
remover->Remove(base::Time(), base::Time::Max(),
content::BrowsingDataRemover::DATA_TYPE_CACHE,
content::BrowsingDataRemover::ORIGIN_TYPE_UNPROTECTED_WEB |
content::BrowsingDataRemover::ORIGIN_TYPE_PROTECTED_WEB);
}
void WebviewController::HandleGetTitle(int64_t id) {
std::unique_ptr<webview::WebviewResponse> response =
std::make_unique<webview::WebviewResponse>();
response->set_id(id);
response->mutable_get_title()->set_title(
base::UTF16ToUTF8(contents_->GetTitle()));
client_->EnqueueSend(std::move(response));
}
void WebviewController::HandleUpdateSettings(
const webview::UpdateSettingsRequest& request) {
content::WebPreferences prefs =
contents_->GetRenderViewHost()->GetWebkitPreferences();
prefs.javascript_enabled = request.javascript_enabled();
contents_->GetRenderViewHost()->UpdateWebkitPreferences(prefs);
has_navigation_delegate_ = request.has_navigation_delegate();
// Given that cast_shell enables devtools unconditionally there isn't
// anything that needs to be done for |request.debugging_enabled()|. Though,
// as a note, remote debugging is always on.
if (request.has_user_agent() &&
request.user_agent().type_case() == webview::UserAgent::kValue) {
contents_->SetUserAgentOverride(request.user_agent().value(), true);
}
}
void WebviewController::HandleSetAutoMediaPlaybackPolicy(
const webview::SetAutoMediaPlaybackPolicyRequest& request) {
content::WebPreferences prefs =
contents_->GetRenderViewHost()->GetWebkitPreferences();
prefs.autoplay_policy = request.require_user_gesture()
? content::AutoplayPolicy::kUserGestureRequired
: content::AutoplayPolicy::kNoUserGestureRequired;
contents_->GetRenderViewHost()->UpdateWebkitPreferences(prefs);
} }
webview::AsyncPageEvent_State WebviewController::current_state() { webview::AsyncPageEvent_State WebviewController::current_state() {
......
...@@ -11,15 +11,9 @@ ...@@ -11,15 +11,9 @@
#include "base/supports_user_data.h" #include "base/supports_user_data.h"
#include "chromecast/browser/cast_web_contents.h" #include "chromecast/browser/cast_web_contents.h"
#include "chromecast/browser/webview/proto/webview.pb.h" #include "chromecast/browser/webview/proto/webview.pb.h"
#include "components/exo/surface.h" #include "chromecast/browser/webview/web_content_controller.h"
#include "components/exo/surface_observer.h"
#include "ui/events/gestures/gesture_recognizer_impl.h"
#include "url/gurl.h" #include "url/gurl.h"
namespace aura {
class Window;
} // namespace aura
namespace chromecast { namespace chromecast {
class CastWebContents; class CastWebContents;
} // namespace chromecast } // namespace chromecast
...@@ -39,15 +33,8 @@ class WebviewNavigationThrottle; ...@@ -39,15 +33,8 @@ class WebviewNavigationThrottle;
// to allow the web contents to be controlled and embedded. // to allow the web contents to be controlled and embedded.
class WebviewController : public CastWebContents::Delegate, class WebviewController : public CastWebContents::Delegate,
public CastWebContents::Observer, public CastWebContents::Observer,
public exo::SurfaceObserver { public WebContentController {
public: public:
class Client {
public:
virtual ~Client() {}
virtual void EnqueueSend(
std::unique_ptr<webview::WebviewResponse> response) = 0;
virtual void OnError(const std::string& error_message) = 0;
};
WebviewController(content::BrowserContext* browser_context, Client* client); WebviewController(content::BrowserContext* browser_context, Client* client);
~WebviewController() override; ~WebviewController() override;
...@@ -59,44 +46,23 @@ class WebviewController : public CastWebContents::Delegate, ...@@ -59,44 +46,23 @@ class WebviewController : public CastWebContents::Delegate,
// Cause the controller to be destroyed after giving the webpage a chance to // Cause the controller to be destroyed after giving the webpage a chance to
// run unload events. This unsets the client so no more messages will be // run unload events. This unsets the client so no more messages will be
// sent. // sent.
void Destroy(); void Destroy() override;
void ProcessRequest(const webview::WebviewRequest& request) override;
// Close the page. This will cause a stopped response to eventually be sent. // Close the page. This will cause a stopped response to eventually be sent.
void ClosePage(); void ClosePage();
void ProcessRequest(const webview::WebviewRequest& request);
// Attach this web contents to an aura window as a child.
void AttachTo(aura::Window* window, int window_id);
void SendNavigationEvent(WebviewNavigationThrottle* throttle, void SendNavigationEvent(WebviewNavigationThrottle* throttle,
const GURL& url, const GURL& url,
bool is_in_main_frame); bool is_in_main_frame);
protected:
content::WebContents* GetWebContents() override;
private: private:
webview::AsyncPageEvent_State current_state(); webview::AsyncPageEvent_State current_state();
void ProcessInputEvent(const webview::InputEvent& ev);
void JavascriptCallback(int64_t id, base::Value result);
void HandleEvaluateJavascript(
int64_t id,
const webview::EvaluateJavascriptRequest& request);
void HandleAddJavascriptChannels(
const webview::AddJavascriptChannelsRequest& request);
void HandleRemoveJavascriptChannels(
const webview::RemoveJavascriptChannelsRequest& request);
void HandleGetCurrentUrl(int64_t id);
void HandleCanGoBack(int64_t id);
void HandleCanGoForward(int64_t id);
void HandleClearCache();
void HandleGetTitle(int64_t id);
void HandleUpdateSettings(const webview::UpdateSettingsRequest& request);
void HandleSetAutoMediaPlaybackPolicy(
const webview::SetAutoMediaPlaybackPolicyRequest& request);
viz::SurfaceId GetSurfaceId();
bool Check(bool condition, const char* error);
// CastWebContents::Delegate // CastWebContents::Delegate
void OnPageStateChanged(CastWebContents* cast_web_contents) override; void OnPageStateChanged(CastWebContents* cast_web_contents) override;
void OnPageStopped(CastWebContents* cast_web_contents, void OnPageStopped(CastWebContents* cast_web_contents,
...@@ -105,20 +71,10 @@ class WebviewController : public CastWebContents::Delegate, ...@@ -105,20 +71,10 @@ class WebviewController : public CastWebContents::Delegate,
// CastWebContents::Observer // CastWebContents::Observer
void ResourceLoadFailed(CastWebContents* cast_web_contents) override; void ResourceLoadFailed(CastWebContents* cast_web_contents) override;
// exo::SurfaceObserver
void OnSurfaceDestroying(exo::Surface* surface) override;
Client* client_; // Not owned.
std::unique_ptr<content::WebContents> contents_; std::unique_ptr<content::WebContents> contents_;
std::unique_ptr<CastWebContents> cast_web_contents_; std::unique_ptr<CastWebContents> cast_web_contents_;
bool stopped_ = false; bool stopped_ = false;
bool has_navigation_delegate_ = false;
ui::GestureRecognizerImpl gesture_recognizer_;
exo::Surface* surface_ = nullptr;
// The navigation throttle for the current navigation event, if any. // The navigation throttle for the current navigation event, if any.
// Is set only: // Is set only:
// When has_navigation_delegate is true, and // When has_navigation_delegate is true, and
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment