cast: webview: Add an API to set insets

Insets represent a "border" like area around each side of the Webview.
By setting insets the Webview's visible area will shrink.

This will be used to represent occluded area in a Webview where the
virtual keyboard will be shown.

Bug: internal b/175873498
Test: cast_shell_browsertests and on device by calling the new API
Change-Id: Ide948ab2cd955f7f7a687de7cb91ef418dd0aa70
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2596073
Reviewed-by: Ryan Daum <rdaum@chromium.org>
Commit-Queue: Daniel Nicoara <dnicoara@chromium.org>
Cr-Commit-Position: refs/heads/master@{#840352}
diff --git a/chromecast/browser/webview/proto/webview.proto b/chromecast/browser/webview/proto/webview.proto
index 6835749..582c1c0 100644
--- a/chromecast/browser/webview/proto/webview.proto
+++ b/chromecast/browser/webview/proto/webview.proto
@@ -285,6 +285,15 @@
   int32 flags = 2;
 }
 
+// Used to represent a space within a rectangle by "shrinking" the rectangle by
+// the inset amount on all four sides.
+message SetInsetsRequest {
+  int32 top = 1;
+  int32 left = 2;
+  int32 bottom = 3;
+  int32 right = 4;
+}
+
 message WebviewRequest {
   // Unique identifier for the request. For requests that will have a response,
   // the response id will match the request id.
@@ -331,6 +340,7 @@
     AssociateCastAppWindowRequest associate = 20;
     ResizeRequest resize = 21;
     ClearCookiesRequest clear_cookies = 22;
+    SetInsetsRequest set_insets = 23;
   }
 }
 
diff --git a/chromecast/browser/webview/web_content_controller.cc b/chromecast/browser/webview/web_content_controller.cc
index 5beda14..d5043dd 100644
--- a/chromecast/browser/webview/web_content_controller.cc
+++ b/chromecast/browser/webview/web_content_controller.cc
@@ -174,6 +174,16 @@
       }
       break;
 
+    case webview::WebviewRequest::kSetInsets:
+      if (request.has_set_insets()) {
+        HandleSetInsets(gfx::Insets(
+            request.set_insets().top(), request.set_insets().left(),
+            request.set_insets().bottom(), request.set_insets().right()));
+      } else {
+        client_->OnError("set_insets() not supplied");
+      }
+      break;
+
     default:
       client_->OnError("Unknown request code");
       break;
@@ -506,6 +516,12 @@
   }
 }
 
+void WebContentController::HandleSetInsets(const gfx::Insets& insets) {
+  auto* contents = GetWebContents();
+  if (contents && contents->GetTopLevelRenderWidgetHostView())
+    contents->GetTopLevelRenderWidgetHostView()->SetInsets(insets);
+}
+
 viz::SurfaceId WebContentController::GetSurfaceId() {
   content::WebContents* web_contents = GetWebContents();
   // Web contents are destroyed before controller for cast apps.
diff --git a/chromecast/browser/webview/web_content_controller.h b/chromecast/browser/webview/web_content_controller.h
index f2fbd23..e5322c1 100644
--- a/chromecast/browser/webview/web_content_controller.h
+++ b/chromecast/browser/webview/web_content_controller.h
@@ -117,6 +117,8 @@
   void HandleClearCookies(int64_t id);
   void HandleGetTitle(int64_t id);
   void HandleResize(const gfx::Size& size);
+  void HandleSetInsets(const gfx::Insets& insets);
+
   viz::SurfaceId GetSurfaceId();
   void ChannelModified(content::RenderFrameHost* frame,
                        const std::string& channel,
diff --git a/chromecast/browser/webview/webview_browsertest.cc b/chromecast/browser/webview/webview_browsertest.cc
index 3dcaf179..c442cf0 100644
--- a/chromecast/browser/webview/webview_browsertest.cc
+++ b/chromecast/browser/webview/webview_browsertest.cc
@@ -11,6 +11,7 @@
 #include "chromecast/browser/extensions/cast_extension_system_factory.h"
 #include "chromecast/browser/webview/webview_controller.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "content/public/browser/render_widget_host_view.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_base.h"
@@ -130,4 +131,49 @@
   RunMessageLoop();
 }
 
+IN_PROC_BROWSER_TEST_F(WebviewTest, SetInsets) {
+  // Webview creation sends messages to the client (eg: accessibility ID).
+  EXPECT_CALL(client_, EnqueueSend(_)).Times(testing::AnyNumber());
+
+  WebviewController webview(context_.get(), &client_, true);
+  GURL test_url = embedded_test_server()->GetURL("foo.com", "/test");
+
+  auto check = [](const std::unique_ptr<webview::WebviewResponse>& response) {
+    return response->has_page_event() &&
+           response->page_event().current_page_state() ==
+               webview::AsyncPageEvent_State_LOADED;
+  };
+  EXPECT_CALL(client_, EnqueueSend(Truly(check)))
+      .Times(testing::AtLeast(1))
+      .WillOnce(
+          [this, &webview](std::unique_ptr<webview::WebviewResponse> response) {
+            webview::WebviewRequest request;
+            request.mutable_set_insets()->set_top(0);
+            request.mutable_set_insets()->set_left(0);
+            request.mutable_set_insets()->set_bottom(200);
+            request.mutable_set_insets()->set_right(0);
+            webview.ProcessRequest(request);
+
+            gfx::Size size_after = webview.GetWebContents()
+                                       ->GetRenderWidgetHostView()
+                                       ->GetVisibleViewportSize();
+            EXPECT_EQ(gfx::Size(800, 400), size_after);
+
+            Quit();
+          });
+
+  // Requests are executed serially. Resize first to make sure the Webview is
+  // properly sized by the time the page loads.
+  webview::WebviewRequest resize;
+  resize.mutable_resize()->set_width(800);
+  resize.mutable_resize()->set_height(600);
+  webview.ProcessRequest(resize);
+
+  webview::WebviewRequest nav;
+  nav.mutable_navigate()->set_url(test_url.spec());
+  webview.ProcessRequest(nav);
+
+  RunMessageLoop();
+}
+
 }  // namespace chromecast
diff --git a/chromecast/browser/webview/webview_controller.h b/chromecast/browser/webview/webview_controller.h
index 4d64453..489519d 100644
--- a/chromecast/browser/webview/webview_controller.h
+++ b/chromecast/browser/webview/webview_controller.h
@@ -28,6 +28,7 @@
 namespace chromecast {
 
 class WebviewNavigationThrottle;
+class WebviewTest;
 
 // This owns a WebContents and CastWebContents and processes proto commands
 // to allow the web contents to be controlled and embedded.
@@ -62,6 +63,8 @@
   void OnNavigationThrottleDestroyed(WebviewNavigationThrottle* throttle);
 
  protected:
+  FRIEND_TEST_ALL_PREFIXES(WebviewTest, SetInsets);
+
   content::WebContents* GetWebContents() override;
 
  private: