exo: Translate host window to root surface origin

Sub-surfaces can be positioned to the top/left of the root surface.
However, the cc::RenderSurfaceImpl for a window's layer tree expects
layers to be positioned in the window's local coordinate space, and
clips content outside the layers' bounding box. If the host window
layer has non-negative coordinates, the top/left edges of the bounding
box correspond to those of the window frame, so content at negative
coordinates is clipped.

When the root surface is not the topmost/leftmost surface in the tree,
this CL translates quads to non-negative coordinates, and translates
the host window to negative coordinates.

Bug: b:67384524
Test: No clipping for ARC clients using relative surface hierarchy.
Change-Id: I0889387370f5fdb4e3c30849a40a6ff2b5e56c02
Reviewed-on: https://chromium-review.googlesource.com/816434
Commit-Queue: Dominik Laskowski <domlaskowski@chromium.org>
Reviewed-by: David Reveman <reveman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#523019}
diff --git a/components/exo/shell_surface.cc b/components/exo/shell_surface.cc
index 52e09a7f..8d6d2887 100644
--- a/components/exo/shell_surface.cc
+++ b/components/exo/shell_surface.cc
@@ -38,6 +38,7 @@
 #include "ui/compositor/compositor.h"
 #include "ui/display/display.h"
 #include "ui/display/screen.h"
+#include "ui/gfx/geometry/vector2d_conversions.h"
 #include "ui/gfx/path.h"
 #include "ui/views/widget/widget.h"
 #include "ui/wm/core/coordinate_conversion.h"
@@ -1304,12 +1305,16 @@
 }
 
 void ShellSurface::UpdateSurfaceBounds() {
-  gfx::Rect client_view_bounds =
-      widget_->non_client_view()->frame_view()->GetBoundsForClientView();
+  gfx::Point origin = widget_->non_client_view()
+                          ->frame_view()
+                          ->GetBoundsForClientView()
+                          .origin();
 
-  host_window()->SetBounds(
-      gfx::Rect(GetSurfaceOrigin() + client_view_bounds.OffsetFromOrigin(),
-                host_window()->bounds().size()));
+  origin += GetSurfaceOrigin().OffsetFromOrigin();
+  origin -= ToFlooredVector2d(ScaleVector2d(
+      root_surface_origin().OffsetFromOrigin(), 1.f / GetScale()));
+
+  host_window()->SetBounds(gfx::Rect(origin, host_window()->bounds().size()));
 }
 
 void ShellSurface::UpdateShadow() {
diff --git a/components/exo/surface_tree_host.cc b/components/exo/surface_tree_host.cc
index 20a185aa..5a95020 100644
--- a/components/exo/surface_tree_host.cc
+++ b/components/exo/surface_tree_host.cc
@@ -287,8 +287,8 @@
   float device_scale_factor = host_window()->layer()->device_scale_factor();
   frame.metadata.device_scale_factor = device_scale_factor;
   root_surface_->AppendSurfaceHierarchyContentsToFrame(
-      gfx::Point(), device_scale_factor, layer_tree_frame_sink_holder_.get(),
-      &frame);
+      root_surface_origin_, device_scale_factor,
+      layer_tree_frame_sink_holder_.get(), &frame);
 
   if (WMHelper::GetInstance()->AreVerifiedSyncTokensNeeded()) {
     std::vector<GLbyte*> sync_tokens;
@@ -326,6 +326,10 @@
   host_window_->layer()->SetFillsBoundsOpaquely(
       bounds.size() == root_surface_->content_size() &&
       root_surface_->FillsBoundsOpaquely());
+
+  root_surface_origin_ = gfx::Point() - bounds.OffsetFromOrigin();
+  root_surface_->window()->SetBounds(gfx::Rect(
+      root_surface_origin_, root_surface_->window()->bounds().size()));
 }
 
 }  // namespace exo
diff --git a/components/exo/surface_tree_host.h b/components/exo/surface_tree_host.h
index 74e6ed11..dcc4e2f 100644
--- a/components/exo/surface_tree_host.h
+++ b/components/exo/surface_tree_host.h
@@ -81,6 +81,8 @@
   Surface* root_surface() { return root_surface_; }
   const Surface* root_surface() const { return root_surface_; }
 
+  const gfx::Point& root_surface_origin() const { return root_surface_origin_; }
+
   LayerTreeFrameSinkHolder* layer_tree_frame_sink_holder() {
     return layer_tree_frame_sink_holder_.get();
   }
@@ -106,6 +108,11 @@
   void UpdateHostWindowBounds();
 
   Surface* root_surface_ = nullptr;
+
+  // Position of root surface relative to topmost, leftmost sub-surface. The
+  // host window should be translated by the negation of this vector.
+  gfx::Point root_surface_origin_;
+
   std::unique_ptr<aura::Window> host_window_;
   std::unique_ptr<LayerTreeFrameSinkHolder> layer_tree_frame_sink_holder_;