mozart: Initial commit of the view manager.

The view manager implements the ViewManager interface and maintains
the View hierarchy on behalf of applications.

Note: This version does not support input yet.

Review URL: https://codereview.chromium.org/1415493003 .
diff --git a/services/BUILD.gn b/services/BUILD.gn
index 22a7c57..9a19a15 100644
--- a/services/BUILD.gn
+++ b/services/BUILD.gn
@@ -49,6 +49,7 @@
       "//services/device_info",
       "//services/files",
       "//services/kiosk_wm",
+      "//services/ui",
       "//services/native_viewport",
       "//services/surfaces",
       "//services/url_response_disk_cache",
diff --git a/services/ui/BUILD.gn b/services/ui/BUILD.gn
new file mode 100644
index 0000000..bb93fba
--- /dev/null
+++ b/services/ui/BUILD.gn
@@ -0,0 +1,9 @@
+# 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.
+
+group("ui") {
+  deps = [
+    "//services/ui/view_manager",
+  ]
+}
diff --git a/services/ui/README.md b/services/ui/README.md
new file mode 100644
index 0000000..cccc9c3
--- /dev/null
+++ b/services/ui/README.md
@@ -0,0 +1,4 @@
+# Mozart UI System
+
+This directory contains Mozart, an implementation of a composable view
+management system named after the classical composer.
diff --git a/services/ui/view_manager/BUILD.gn b/services/ui/view_manager/BUILD.gn
new file mode 100644
index 0000000..833582b
--- /dev/null
+++ b/services/ui/view_manager/BUILD.gn
@@ -0,0 +1,45 @@
+# 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.
+
+import("//mojo/public/mojo_application.gni")
+import("//testing/test.gni")
+
+mojo_native_application("view_manager") {
+  output_name = "view_manager_service"
+
+  sources = [
+    "main.cc",
+    "surface_manager.cc",
+    "surface_manager.h",
+    "view_host_impl.cc",
+    "view_host_impl.h",
+    "view_layout_request.cc",
+    "view_layout_request.h",
+    "view_manager_app.cc",
+    "view_manager_app.h",
+    "view_manager_impl.cc",
+    "view_manager_impl.h",
+    "view_registry.cc",
+    "view_registry.h",
+    "view_state.cc",
+    "view_state.h",
+    "view_tree_host_impl.cc",
+    "view_tree_host_impl.h",
+    "view_tree_state.cc",
+    "view_tree_state.h",
+  ]
+
+  deps = [
+    "//base",
+    "//mojo/application",
+    "//mojo/common",
+    "//mojo/common:tracing_impl",
+    "//mojo/environment:chromium",
+    "//mojo/converters/geometry",
+    "//mojo/public/cpp/bindings:bindings",
+    "//mojo/services/surfaces/cpp",
+    "//mojo/services/surfaces/interfaces",
+    "//mojo/services/ui/views/interfaces",
+  ]
+}
diff --git a/services/ui/view_manager/README.md b/services/ui/view_manager/README.md
new file mode 100644
index 0000000..c9109a9
--- /dev/null
+++ b/services/ui/view_manager/README.md
@@ -0,0 +1,10 @@
+# Mozart View Manager
+
+This directory contains an implementation of the ViewManager interface.
+It provides a composable view management system for used by other
+applications.
+
+It doesn't make sense to run this application stand-alone since it
+doesn't have any UI of its own to display.  Instead, use the Mozart
+Launcher or some other application to launch and embed the UI of some
+other application using the view manager.
diff --git a/services/ui/view_manager/main.cc b/services/ui/view_manager/main.cc
new file mode 100644
index 0000000..dbfdade
--- /dev/null
+++ b/services/ui/view_manager/main.cc
@@ -0,0 +1,12 @@
+// 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 "mojo/application/application_runner_chromium.h"
+#include "mojo/public/c/system/main.h"
+#include "services/ui/view_manager/view_manager_app.h"
+
+MojoResult MojoMain(MojoHandle application_request) {
+  mojo::ApplicationRunnerChromium runner(new view_manager::ViewManagerApp);
+  return runner.Run(application_request);
+}
diff --git a/services/ui/view_manager/surface_manager.cc b/services/ui/view_manager/surface_manager.cc
new file mode 100644
index 0000000..24ec899
--- /dev/null
+++ b/services/ui/view_manager/surface_manager.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 "base/bind.h"
+#include "base/bind_helpers.h"
+#include "mojo/services/surfaces/cpp/surfaces_utils.h"
+#include "mojo/services/surfaces/interfaces/quads.mojom.h"
+#include "mojo/services/surfaces/interfaces/surfaces.mojom.h"
+#include "services/ui/view_manager/surface_manager.h"
+
+namespace view_manager {
+
+SurfaceManager::SurfaceManager(mojo::SurfacePtr surfaces)
+    : surfaces_(surfaces.Pass()), surface_namespace_(0u) {}
+
+SurfaceManager::~SurfaceManager() {}
+
+mojo::SurfaceIdPtr SurfaceManager::CreateWrappedSurface(
+    mojo::SurfaceId* inner_surface_id) {
+  return inner_surface_id->Clone();
+}
+
+void SurfaceManager::DestroySurface(mojo::SurfaceIdPtr surface_id) {
+  // surfaces_->DestroySurface(surface_id->local);
+}
+
+}  // namespace view_manager
diff --git a/services/ui/view_manager/surface_manager.h b/services/ui/view_manager/surface_manager.h
new file mode 100644
index 0000000..d5d2068
--- /dev/null
+++ b/services/ui/view_manager/surface_manager.h
@@ -0,0 +1,34 @@
+// 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 SERVICES_UI_VIEW_MANAGER_SURFACE_MANAGER_H_
+#define SERVICES_UI_VIEW_MANAGER_SURFACE_MANAGER_H_
+
+#include "base/macros.h"
+#include "mojo/services/surfaces/interfaces/surfaces.mojom.h"
+
+namespace view_manager {
+
+// Manages surfaces on behalf of the view manager.
+class SurfaceManager {
+ public:
+  explicit SurfaceManager(mojo::SurfacePtr surfaces);
+  ~SurfaceManager();
+
+  mojo::SurfaceIdPtr CreateWrappedSurface(mojo::SurfaceId* inner_surface_id);
+
+  void DestroySurface(mojo::SurfaceIdPtr surface_id);
+
+ private:
+  void OnSurfaceIdNamespaceAvailable(uint32_t id_namespace);
+
+  mojo::SurfacePtr surfaces_;
+  uint32_t surface_namespace_;
+
+  DISALLOW_COPY_AND_ASSIGN(SurfaceManager);
+};
+
+}  // namespace view_manager
+
+#endif  // SERVICES_UI_VIEW_MANAGER_SURFACE_MANAGER_H_
diff --git a/services/ui/view_manager/view_host_impl.cc b/services/ui/view_manager/view_host_impl.cc
new file mode 100644
index 0000000..fef8f0b
--- /dev/null
+++ b/services/ui/view_manager/view_host_impl.cc
@@ -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.
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "services/ui/view_manager/view_host_impl.h"
+
+namespace view_manager {
+
+ViewHostImpl::ViewHostImpl(
+    ViewRegistry* registry,
+    ViewState* state,
+    mojo::InterfaceRequest<mojo::ui::ViewHost> view_host_request)
+    : registry_(registry),
+      state_(state),
+      binding_(this, view_host_request.Pass()) {}
+
+ViewHostImpl::~ViewHostImpl() {}
+
+void ViewHostImpl::GetServiceProvider(
+    mojo::InterfaceRequest<mojo::ServiceProvider> service_provider) {
+  state_->GetServiceProvider(service_provider.Pass());
+}
+
+void ViewHostImpl::RequestLayout() {
+  registry_->RequestLayout(state_);
+}
+
+void ViewHostImpl::AddChild(uint32_t child_key,
+                            mojo::ui::ViewTokenPtr child_view_token) {
+  registry_->AddChild(state_, child_key, child_view_token.Pass());
+}
+
+void ViewHostImpl::RemoveChild(uint32_t child_key) {
+  registry_->RemoveChild(state_, child_key);
+}
+
+static void RunLayoutChildCallback(
+    const ViewHostImpl::LayoutChildCallback& callback,
+    mojo::ui::ViewLayoutInfoPtr info) {
+  callback.Run(info.Pass());
+}
+
+void ViewHostImpl::LayoutChild(
+    uint32_t child_key,
+    mojo::ui::ViewLayoutParamsPtr child_layout_params,
+    const LayoutChildCallback& callback) {
+  registry_->LayoutChild(state_, child_key, child_layout_params.Pass(),
+                         base::Bind(&RunLayoutChildCallback, callback));
+}
+
+}  // namespace view_manager
diff --git a/services/ui/view_manager/view_host_impl.h b/services/ui/view_manager/view_host_impl.h
new file mode 100644
index 0000000..274d1f1
--- /dev/null
+++ b/services/ui/view_manager/view_host_impl.h
@@ -0,0 +1,50 @@
+// 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 SERVICES_UI_VIEW_MANAGER_VIEW_HOST_IMPL_H_
+#define SERVICES_UI_VIEW_MANAGER_VIEW_HOST_IMPL_H_
+
+#include "base/macros.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/services/ui/views/interfaces/views.mojom.h"
+#include "services/ui/view_manager/view_registry.h"
+#include "services/ui/view_manager/view_state.h"
+
+namespace view_manager {
+
+// ViewHost interface implementation.
+// This object is owned by its associated ViewState.
+class ViewHostImpl : public mojo::ui::ViewHost {
+ public:
+  ViewHostImpl(ViewRegistry* registry,
+               ViewState* state,
+               mojo::InterfaceRequest<mojo::ui::ViewHost> view_host_request);
+  ~ViewHostImpl() override;
+
+  void set_view_host_connection_error_handler(const base::Closure& handler) {
+    binding_.set_connection_error_handler(handler);
+  }
+
+ private:
+  // |ViewHost|:
+  void GetServiceProvider(
+      mojo::InterfaceRequest<mojo::ServiceProvider> service_provider) override;
+  void RequestLayout() override;
+  void AddChild(uint32_t child_key,
+                mojo::ui::ViewTokenPtr child_view_token) override;
+  void RemoveChild(uint32_t child_key) override;
+  void LayoutChild(uint32_t child_key,
+                   mojo::ui::ViewLayoutParamsPtr child_layout_params,
+                   const LayoutChildCallback& callback) override;
+
+  ViewRegistry* const registry_;
+  ViewState* const state_;
+  mojo::Binding<mojo::ui::ViewHost> binding_;
+
+  DISALLOW_COPY_AND_ASSIGN(ViewHostImpl);
+};
+
+}  // namespace view_manager
+
+#endif  // SERVICES_UI_VIEW_MANAGER_VIEW_HOST_IMPL_H_
diff --git a/services/ui/view_manager/view_layout_request.cc b/services/ui/view_manager/view_layout_request.cc
new file mode 100644
index 0000000..cbec836
--- /dev/null
+++ b/services/ui/view_manager/view_layout_request.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.
+
+#include "base/logging.h"
+#include "services/ui/view_manager/view_layout_request.h"
+
+namespace view_manager {
+
+ViewLayoutRequest::ViewLayoutRequest(
+    mojo::ui::ViewLayoutParamsPtr layout_params)
+    : layout_params_(layout_params.Pass()),
+      was_dispatched_(false),
+      issued_(false) {}
+
+ViewLayoutRequest::~ViewLayoutRequest() {
+  if (!was_dispatched_)
+    DispatchLayoutInfo(nullptr);
+}
+
+void ViewLayoutRequest::AddCallback(const ViewLayoutCallback& callback) {
+  DCHECK(!was_dispatched_);
+  callbacks_.emplace_back(callback);
+}
+
+void ViewLayoutRequest::DispatchLayoutInfo(mojo::ui::ViewLayoutInfo* info) {
+  DCHECK(!was_dispatched_);
+  was_dispatched_ = true;
+  for (const auto& callback : callbacks_)
+    callback.Run(info ? info->Clone() : nullptr);
+}
+
+}  // namespace view_manager
diff --git a/services/ui/view_manager/view_layout_request.h b/services/ui/view_manager/view_layout_request.h
new file mode 100644
index 0000000..8091d2f
--- /dev/null
+++ b/services/ui/view_manager/view_layout_request.h
@@ -0,0 +1,65 @@
+// 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 SERVICES_UI_VIEW_MANAGER_VIEW_LAYOUT_REQUEST_H_
+#define SERVICES_UI_VIEW_MANAGER_VIEW_LAYOUT_REQUEST_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "mojo/services/ui/views/interfaces/layouts.mojom.h"
+
+namespace view_manager {
+
+using ViewLayoutCallback = base::Callback<void(mojo::ui::ViewLayoutInfoPtr)>;
+
+// Describes a pending layout request for a view.
+class ViewLayoutRequest {
+ public:
+  explicit ViewLayoutRequest(mojo::ui::ViewLayoutParamsPtr layout_params);
+
+  // Dispatches null layout info automatically if DispatchLayoutInfo was not
+  // called.
+  ~ViewLayoutRequest();
+
+  // Gets the layout parameters for this request.
+  // Does not confer ownership.
+  mojo::ui::ViewLayoutParams* layout_params() { return layout_params_.get(); }
+
+  // Gets the layout parameters for this request and takes ownership.
+  mojo::ui::ViewLayoutParamsPtr TakeLayoutParams() {
+    return layout_params_.Pass();
+  }
+
+  // Adds a callback to this layout request.
+  // Must be called before dispatching.
+  void AddCallback(const ViewLayoutCallback& callback);
+
+  // Returns true if the request has callbacks.
+  bool has_callbacks() { return !callbacks_.empty(); }
+
+  // Sends the layout information to each client.
+  // Must be invoked exactly once before destroying the request to prevent
+  // dangling callbacks.
+  void DispatchLayoutInfo(mojo::ui::ViewLayoutInfo* info);
+
+  // True if the request has been issued to the view.
+  // False if it is still pending in the queue.
+  bool issued() const { return issued_; }
+  void set_issued(bool value) { issued_ = value; }
+
+ private:
+  mojo::ui::ViewLayoutParamsPtr layout_params_;
+  std::vector<ViewLayoutCallback> callbacks_;
+  bool was_dispatched_;
+  bool issued_;
+
+  DISALLOW_COPY_AND_ASSIGN(ViewLayoutRequest);
+};
+
+}  // namespace view_manager
+
+#endif  // SERVICES_UI_VIEW_MANAGER_VIEW_LAYOUT_REQUEST_H_
diff --git a/services/ui/view_manager/view_manager_app.cc b/services/ui/view_manager/view_manager_app.cc
new file mode 100644
index 0000000..2190590
--- /dev/null
+++ b/services/ui/view_manager/view_manager_app.cc
@@ -0,0 +1,44 @@
+// 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 "base/trace_event/trace_event.h"
+#include "mojo/application/application_runner_chromium.h"
+#include "mojo/common/tracing_impl.h"
+#include "mojo/public/c/system/main.h"
+#include "mojo/public/cpp/application/application_connection.h"
+#include "mojo/public/cpp/application/application_impl.h"
+#include "services/ui/view_manager/view_manager_app.h"
+#include "services/ui/view_manager/view_manager_impl.h"
+
+namespace view_manager {
+
+ViewManagerApp::ViewManagerApp() : app_impl_(nullptr) {}
+
+ViewManagerApp::~ViewManagerApp() {}
+
+void ViewManagerApp::Initialize(mojo::ApplicationImpl* app_impl) {
+  app_impl_ = app_impl;
+  tracing_.Initialize(app_impl);
+
+  mojo::SurfacePtr surfaces;
+  app_impl->ConnectToService("mojo:surfaces_service", &surfaces);
+  surface_manager_.reset(new SurfaceManager(surfaces.Pass()));
+
+  registry_.reset(new ViewRegistry(surface_manager_.get()));
+}
+
+bool ViewManagerApp::ConfigureIncomingConnection(
+    mojo::ApplicationConnection* connection) {
+  connection->AddService<mojo::ui::ViewManager>(this);
+  return true;
+}
+
+void ViewManagerApp::Create(
+    mojo::ApplicationConnection* connection,
+    mojo::InterfaceRequest<mojo::ui::ViewManager> request) {
+  view_managers.AddBinding(new ViewManagerImpl(registry_.get()),
+                           request.Pass());
+}
+
+}  // namespace view_manager
diff --git a/services/ui/view_manager/view_manager_app.h b/services/ui/view_manager/view_manager_app.h
new file mode 100644
index 0000000..ca37dea
--- /dev/null
+++ b/services/ui/view_manager/view_manager_app.h
@@ -0,0 +1,50 @@
+// 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 SERVICES_UI_VIEW_MANAGER_VIEW_MANAGER_APP_H_
+#define SERVICES_UI_VIEW_MANAGER_VIEW_MANAGER_APP_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "mojo/common/strong_binding_set.h"
+#include "mojo/common/tracing_impl.h"
+#include "mojo/public/cpp/application/application_delegate.h"
+#include "mojo/services/ui/views/interfaces/view_manager.mojom.h"
+#include "services/ui/view_manager/surface_manager.h"
+#include "services/ui/view_manager/view_registry.h"
+
+namespace view_manager {
+
+// View manager application entry point.
+class ViewManagerApp : public mojo::ApplicationDelegate,
+                       public mojo::InterfaceFactory<mojo::ui::ViewManager> {
+ public:
+  ViewManagerApp();
+  ~ViewManagerApp() override;
+
+ private:
+  // |ApplicationDelegate|:
+  void Initialize(mojo::ApplicationImpl* app_impl) override;
+  bool ConfigureIncomingConnection(
+      mojo::ApplicationConnection* connection) override;
+
+  // |InterfaceFactory<ViewManager>|:
+  void Create(mojo::ApplicationConnection* connection,
+              mojo::InterfaceRequest<mojo::ui::ViewManager> request) override;
+
+  mojo::ApplicationImpl* app_impl_;
+  mojo::TracingImpl tracing_;
+
+  mojo::StrongBindingSet<mojo::ui::ViewManager> view_managers;
+  std::unique_ptr<ViewRegistry> registry_;
+  std::unique_ptr<SurfaceManager> surface_manager_;  // must come after registry
+
+  DISALLOW_COPY_AND_ASSIGN(ViewManagerApp);
+};
+
+}  // namespace view_manager
+
+#endif  // SERVICES_UI_VIEW_MANAGER_VIEW_MANAGER_APP_H_
diff --git a/services/ui/view_manager/view_manager_impl.cc b/services/ui/view_manager/view_manager_impl.cc
new file mode 100644
index 0000000..38cf975
--- /dev/null
+++ b/services/ui/view_manager/view_manager_impl.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.
+
+#include "services/ui/view_manager/view_host_impl.h"
+#include "services/ui/view_manager/view_manager_impl.h"
+#include "services/ui/view_manager/view_tree_host_impl.h"
+
+namespace view_manager {
+
+ViewManagerImpl::ViewManagerImpl(ViewRegistry* registry)
+    : registry_(registry) {}
+
+ViewManagerImpl::~ViewManagerImpl() {}
+
+void ViewManagerImpl::RegisterView(
+    mojo::ui::ViewPtr view,
+    mojo::InterfaceRequest<mojo::ui::ViewHost> view_host_request,
+    const RegisterViewCallback& callback) {
+  mojo::ui::ViewTokenPtr view_token =
+      registry_->RegisterView(view.Pass(), view_host_request.Pass());
+  callback.Run(view_token.Pass());
+}
+
+void ViewManagerImpl::RegisterViewTree(
+    mojo::ui::ViewTreePtr view_tree,
+    mojo::InterfaceRequest<mojo::ui::ViewTreeHost> view_tree_host_request,
+    const RegisterViewTreeCallback& callback) {
+  registry_->RegisterViewTree(view_tree.Pass(), view_tree_host_request.Pass());
+  callback.Run();
+}
+
+}  // namespace view_manager
diff --git a/services/ui/view_manager/view_manager_impl.h b/services/ui/view_manager/view_manager_impl.h
new file mode 100644
index 0000000..db84e4f
--- /dev/null
+++ b/services/ui/view_manager/view_manager_impl.h
@@ -0,0 +1,39 @@
+// 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 SERVICES_UI_VIEW_MANAGER_VIEW_MANAGER_IMPL_H_
+#define SERVICES_UI_VIEW_MANAGER_VIEW_MANAGER_IMPL_H_
+
+#include "base/macros.h"
+#include "mojo/common/strong_binding_set.h"
+#include "mojo/services/ui/views/interfaces/view_manager.mojom.h"
+#include "services/ui/view_manager/view_registry.h"
+
+namespace view_manager {
+
+// ViewManager interface implementation.
+class ViewManagerImpl : public mojo::ui::ViewManager {
+ public:
+  explicit ViewManagerImpl(ViewRegistry* registry);
+  ~ViewManagerImpl() override;
+
+ private:
+  // |ViewManager|:
+  void RegisterView(
+      mojo::ui::ViewPtr view,
+      mojo::InterfaceRequest<mojo::ui::ViewHost> view_host_request,
+      const RegisterViewCallback& callback) override;
+  void RegisterViewTree(
+      mojo::ui::ViewTreePtr view_tree,
+      mojo::InterfaceRequest<mojo::ui::ViewTreeHost> view_tree_host_request,
+      const RegisterViewTreeCallback& callback) override;
+
+  ViewRegistry* registry_;
+
+  DISALLOW_COPY_AND_ASSIGN(ViewManagerImpl);
+};
+
+}  // namespace view_manager
+
+#endif  // SERVICES_UI_VIEW_MANAGER_VIEW_MANAGER_IMPL_H_
diff --git a/services/ui/view_manager/view_registry.cc b/services/ui/view_manager/view_registry.cc
new file mode 100644
index 0000000..182ae3d
--- /dev/null
+++ b/services/ui/view_manager/view_registry.cc
@@ -0,0 +1,725 @@
+// 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 <algorithm>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "services/ui/view_manager/surface_manager.h"
+#include "services/ui/view_manager/view_host_impl.h"
+#include "services/ui/view_manager/view_registry.h"
+#include "services/ui/view_manager/view_tree_host_impl.h"
+
+namespace view_manager {
+
+static bool AreViewLayoutParamsValid(mojo::ui::ViewLayoutParams* params) {
+  return params && params->constraints && params->constraints->min_width >= 0 &&
+         params->constraints->max_width >= params->constraints->min_width &&
+         params->constraints->min_height >= 0 &&
+         params->constraints->max_height >= params->constraints->min_height &&
+         params->device_pixel_ratio > 0;
+}
+
+static std::ostream& operator<<(std::ostream& os, mojo::Size* size) {
+  return size
+             ? os << "{width=" << size->width << ", height=" << size->height
+                  << "}"
+             : os << "{null}";
+}
+
+static std::ostream& operator<<(std::ostream& os, mojo::SurfaceId* surface_id) {
+  return surface_id
+             ? os << "{id_namespace=" << surface_id->id_namespace
+                  << ", local=" << surface_id->local << "}"
+             : os << "{null}";
+}
+
+static std::ostream& operator<<(std::ostream& os, mojo::ui::ViewToken* token) {
+  return token ? os << "{token=" << token->value << "}" : os << "{null}";
+}
+
+static std::ostream& operator<<(std::ostream& os, ViewState* view_state) {
+  return view_state ? os << "{token=" << view_state->view_token_value() << "}"
+                    : os << "{null}";
+}
+
+static std::ostream& operator<<(std::ostream& os,
+                                mojo::ui::BoxConstraints* constraints) {
+  return constraints
+             ? os << "{min_width=" << constraints->min_width
+                  << ", max_width=" << constraints->max_width
+                  << ", min_height=" << constraints->min_height
+                  << ", max_height=" << constraints->max_height << "}"
+             : os << "{null}";
+};
+
+static std::ostream& operator<<(std::ostream& os,
+                                mojo::ui::ViewLayoutParams* params) {
+  return params
+             ? os << "{constraints=" << params->constraints.get()
+                  << ", device_pixel_ratio=" << params->device_pixel_ratio
+                  << "}"
+             : os << "{null}";
+}
+
+static std::ostream& operator<<(std::ostream& os,
+                                mojo::ui::ViewLayoutInfo* info) {
+  return info
+             ? os << "{size=" << info->size.get()
+                  << ", surface_id=" << info->surface_id.get() << "}"
+             : os << "{null}";
+}
+
+ViewRegistry::ViewRegistry(SurfaceManager* surface_manager)
+    : surface_manager_(surface_manager), next_view_token_value_(1u) {}
+
+ViewRegistry::~ViewRegistry() {}
+
+mojo::ui::ViewTokenPtr ViewRegistry::RegisterView(
+    mojo::ui::ViewPtr view,
+    mojo::InterfaceRequest<mojo::ui::ViewHost> view_host_request) {
+  DCHECK(view);
+  uint32_t view_token_value = next_view_token_value_++;
+  DCHECK(!FindView(view_token_value));
+
+  // Create the state and bind host to it.
+  ViewState* view_state = new ViewState(view.Pass(), view_token_value);
+  ViewHostImpl* view_host =
+      new ViewHostImpl(this, view_state, view_host_request.Pass());
+  view_state->set_view_host(view_host);
+  view_state->set_view_connection_error_handler(
+      base::Bind(&ViewRegistry::OnViewConnectionError, base::Unretained(this),
+                 view_state));
+  view_host->set_view_host_connection_error_handler(
+      base::Bind(&ViewRegistry::OnViewConnectionError, base::Unretained(this),
+                 view_state));
+
+  // Add to registry and return token.
+  views_by_token_.insert({view_token_value, view_state});
+  mojo::ui::ViewTokenPtr token = mojo::ui::ViewToken::New();
+  token->value = view_state->view_token_value();
+  DVLOG(1) << "RegisterView: view=" << view_state;
+  return token;
+}
+
+void ViewRegistry::OnViewConnectionError(ViewState* view_state) {
+  DCHECK(IsViewStateRegisteredDebug(view_state));
+  DVLOG(1) << "OnViewConnectionError: view=" << view_state;
+
+  UnregisterView(view_state);
+}
+
+void ViewRegistry::UnregisterView(ViewState* view_state) {
+  DCHECK(IsViewStateRegisteredDebug(view_state));
+  DVLOG(1) << "UnregisterView: view=" << view_state;
+
+  // Remove from parent or roots.
+  HijackView(view_state);
+
+  // Remove from registry.
+  views_by_token_.erase(view_state->view_token_value());
+  delete view_state;
+}
+
+void ViewRegistry::RegisterViewTree(
+    mojo::ui::ViewTreePtr view_tree,
+    mojo::InterfaceRequest<mojo::ui::ViewTreeHost> view_tree_host_request) {
+  DCHECK(view_tree);
+
+  // Create the state and bind host to it.
+  ViewTreeState* tree_state = new ViewTreeState(view_tree.Pass());
+  ViewTreeHostImpl* tree_host =
+      new ViewTreeHostImpl(this, tree_state, view_tree_host_request.Pass());
+  tree_state->set_view_tree_host(tree_host);
+  tree_state->set_view_tree_connection_error_handler(
+      base::Bind(&ViewRegistry::OnViewTreeConnectionError,
+                 base::Unretained(this), tree_state));
+  tree_host->set_view_tree_host_connection_error_handler(
+      base::Bind(&ViewRegistry::OnViewTreeConnectionError,
+                 base::Unretained(this), tree_state));
+
+  // Add to registry.
+  view_trees_.push_back(tree_state);
+  DVLOG(1) << "RegisterViewTree: tree=" << tree_state;
+}
+
+void ViewRegistry::OnViewTreeConnectionError(ViewTreeState* tree_state) {
+  DCHECK(IsViewTreeStateRegisteredDebug(tree_state));
+  DVLOG(1) << "OnViewTreeConnectionError: tree=" << tree_state;
+
+  UnregisterViewTree(tree_state);
+}
+
+void ViewRegistry::UnregisterViewTree(ViewTreeState* tree_state) {
+  DCHECK(IsViewTreeStateRegisteredDebug(tree_state));
+  DVLOG(1) << "UnregisterViewTree: tree=" << tree_state;
+
+  // Unlink the root if needed.
+  if (tree_state->root())
+    UnlinkRoot(tree_state);
+
+  // Remove from registry.
+  view_trees_.erase(std::find_if(
+      view_trees_.begin(), view_trees_.end(),
+      [tree_state](ViewTreeState* other) { return tree_state == other; }));
+  delete tree_state;
+}
+
+void ViewRegistry::RequestLayout(ViewState* view_state) {
+  DCHECK(IsViewStateRegisteredDebug(view_state));
+  DVLOG(1) << "RequestLayout: view=" << view_state;
+
+  InvalidateLayout(view_state);
+}
+
+void ViewRegistry::AddChild(ViewState* parent_state,
+                            uint32_t child_key,
+                            mojo::ui::ViewTokenPtr child_view_token) {
+  DCHECK(IsViewStateRegisteredDebug(parent_state));
+  DCHECK(child_view_token);
+  DVLOG(1) << "AddChild: parent=" << parent_state << ", child_key=" << child_key
+           << ", child=" << child_view_token.get();
+
+  // Check for duplicate children.
+  if (parent_state->children().find(child_key) !=
+      parent_state->children().end()) {
+    LOG(ERROR) << "View attempted to add a child with a duplicate key: "
+               << "parent=" << parent_state << ", child_key=" << child_key
+               << ", child=" << child_view_token.get();
+    UnregisterView(parent_state);
+    return;
+  }
+
+  // Check whether the desired child view still exists.
+  // Adding a non-existent child still succeeds but the view manager will
+  // immediately report it as being unavailable.
+  ViewState* child_state = FindView(child_view_token->value);
+  if (!child_state) {
+    LinkChildAsUnavailable(parent_state, child_key);
+    return;
+  }
+
+  // Check whether the child needs to be reparented.
+  // The old parent will receive an unavailable event.  For interface symmetry,
+  // we deliberately do this even if the old and new parents are the same.
+  HijackView(child_state);
+
+  // Link the child into its new parent.
+  LinkChild(parent_state, child_key, child_state);
+}
+
+void ViewRegistry::RemoveChild(ViewState* parent_state, uint32_t child_key) {
+  DCHECK(IsViewStateRegisteredDebug(parent_state));
+  DVLOG(1) << "RemoveChild: parent=" << parent_state
+           << ", child_key=" << child_key;
+
+  // Check whether the child key exists in the parent.
+  auto child_it = parent_state->children().find(child_key);
+  if (child_it == parent_state->children().end()) {
+    LOG(ERROR) << "View attempted to remove a child with an invalid key: "
+               << "parent=" << parent_state << ", child_key=" << child_key;
+    UnregisterView(parent_state);
+    return;
+  }
+
+  // Unlink the child from its parent.
+  UnlinkChild(parent_state, child_it);
+}
+
+void ViewRegistry::LayoutChild(
+    ViewState* parent_state,
+    uint32_t child_key,
+    mojo::ui::ViewLayoutParamsPtr child_layout_params,
+    const ViewLayoutCallback& callback) {
+  DCHECK(IsViewStateRegisteredDebug(parent_state));
+  DCHECK(child_layout_params);
+  DCHECK(child_layout_params->constraints);
+  DVLOG(1) << "LayoutChild: parent=" << parent_state
+           << ", child_key=" << child_key
+           << ", child_layout_params=" << child_layout_params.get();
+
+  // Check whether the layout parameters are well-formed.
+  if (!AreViewLayoutParamsValid(child_layout_params.get())) {
+    LOG(ERROR) << "View provided invalid child layout parameters: "
+               << "parent=" << parent_state << ", child_key=" << child_key
+               << ", child_layout_params=" << child_layout_params;
+    UnregisterView(parent_state);
+    callback.Run(nullptr);
+    return;
+  }
+
+  // Check whether the child key exists in the parent.
+  auto child_it = parent_state->children().find(child_key);
+  if (child_it == parent_state->children().end()) {
+    LOG(ERROR) << "View attempted to layout a child with an invalid key: "
+               << "parent=" << parent_state << ", child_key=" << child_key
+               << ", child_layout_params=" << child_layout_params;
+    UnregisterView(parent_state);
+    callback.Run(nullptr);
+    return;
+  }
+
+  SetLayout(child_it->second, child_layout_params.Pass(), callback);
+}
+
+void ViewRegistry::RequestLayout(ViewTreeState* tree_state) {
+  DCHECK(IsViewTreeStateRegisteredDebug(tree_state));
+  DVLOG(1) << "RequestLayout: tree=" << tree_state;
+
+  InvalidateLayoutForRoot(tree_state);
+}
+
+void ViewRegistry::SetRoot(ViewTreeState* tree_state,
+                           uint32_t root_key,
+                           mojo::ui::ViewTokenPtr root_view_token) {
+  DCHECK(IsViewTreeStateRegisteredDebug(tree_state));
+  DCHECK(root_view_token);
+  DVLOG(1) << "SetRoot: tree=" << tree_state << ", root_key=" << root_key
+           << ", root=" << root_view_token.get();
+
+  // Check whether the desired root view still exists.
+  // Using a non-existent root view still succeeds but the view manager will
+  // immediately report it as being unavailable.
+  ViewState* root_state = FindView(root_view_token->value);
+  if (root_state) {
+    HijackView(root_state);
+    LinkRoot(tree_state, root_state, root_key);
+  } else {
+    SendRootUnavailable(tree_state, root_key);
+  }
+  tree_state->set_explicit_root(true);
+}
+
+void ViewRegistry::ResetRoot(ViewTreeState* tree_state) {
+  DCHECK(IsViewTreeStateRegisteredDebug(tree_state));
+  DVLOG(1) << "ResetRoot: tree=" << tree_state;
+
+  if (tree_state->root())
+    UnlinkRoot(tree_state);
+  tree_state->set_explicit_root(false);
+}
+
+void ViewRegistry::LayoutRoot(ViewTreeState* tree_state,
+                              mojo::ui::ViewLayoutParamsPtr root_layout_params,
+                              const ViewLayoutCallback& callback) {
+  DCHECK(IsViewTreeStateRegisteredDebug(tree_state));
+  DCHECK(root_layout_params);
+  DCHECK(root_layout_params->constraints);
+  DVLOG(1) << "LayoutRoot: tree=" << tree_state
+           << ", root_layout_params=" << root_layout_params.get();
+
+  // Check whether the layout parameters are well-formed.
+  if (!AreViewLayoutParamsValid(root_layout_params.get())) {
+    LOG(ERROR) << "View tree provided invalid root layout parameters: "
+               << "tree=" << tree_state
+               << ", root_layout_params=" << root_layout_params;
+    UnregisterViewTree(tree_state);
+    callback.Run(nullptr);
+    return;
+  }
+
+  // Check whether the client called LayoutRoot without first having actually
+  // set a root.
+  if (!tree_state->explicit_root()) {
+    LOG(ERROR) << "View tree attempted to layout the rout without having "
+                  "set one first: tree="
+               << tree_state << ", root_layout_params=" << root_layout_params;
+    UnregisterViewTree(tree_state);
+    callback.Run(nullptr);
+    return;
+  }
+
+  // Check whether the root is unavailable and therefore cannot be laid out.
+  // This is not an error.
+  if (!tree_state->root()) {
+    callback.Run(nullptr);
+    return;
+  }
+
+  SetLayout(tree_state->root(), root_layout_params.Pass(), callback);
+}
+
+ViewState* ViewRegistry::FindView(uint32_t view_token) {
+  auto it = views_by_token_.find(view_token);
+  return it != views_by_token_.end() ? it->second : nullptr;
+}
+
+void ViewRegistry::LinkChild(ViewState* parent_state,
+                             uint32_t child_key,
+                             ViewState* child_state) {
+  DCHECK(IsViewStateRegisteredDebug(parent_state));
+  DCHECK(parent_state->children().find(child_key) ==
+         parent_state->children().end());
+  DCHECK(IsViewStateRegisteredDebug(child_state));
+
+  DVLOG(2) << "Added child " << child_key << " {"
+           << child_state->view_token_value() << "} to parent {"
+           << parent_state->view_token_value() << "}";
+
+  parent_state->children().insert({child_key, child_state});
+  child_state->SetParent(parent_state, child_key);
+
+  // Schedule layout of the parent on behalf of its newly added child.
+  // We don't need to schedule layout of the child until the parent provides
+  // new layout parameters.
+  InvalidateLayoutForChild(parent_state, child_key);
+}
+
+void ViewRegistry::LinkChildAsUnavailable(ViewState* parent_state,
+                                          uint32_t child_key) {
+  DCHECK(IsViewStateRegisteredDebug(parent_state));
+  DCHECK(parent_state->children().find(child_key) ==
+         parent_state->children().end());
+
+  DVLOG(2) << "Added unavailable child " << child_key << " to parent {"
+           << parent_state->view_token_value() << "}";
+
+  parent_state->children().insert({child_key, nullptr});
+  SendChildUnavailable(parent_state, child_key);
+
+  // Don't schedule layout for the parent just yet.  Wait for it to
+  // remove its child in response to the OnChildUnavailable notification.
+}
+
+void ViewRegistry::MarkChildAsUnavailable(ViewState* parent_state,
+                                          uint32_t child_key) {
+  DCHECK(IsViewStateRegisteredDebug(parent_state));
+  auto child_it = parent_state->children().find(child_key);
+  DCHECK(child_it != parent_state->children().end());
+  DCHECK(child_it->second);
+
+  DVLOG(2) << "Marked unavailable child " << child_key << " {"
+           << child_it->second->view_token_value() << "} from parent {"
+           << parent_state->view_token_value() << "}";
+
+  ResetStateWhenUnlinking(child_it->second);
+  child_it->second->ResetContainer();
+  child_it->second = nullptr;
+  SendChildUnavailable(parent_state, child_key);
+
+  // Don't schedule layout for the parent just yet.  Wait for it to
+  // remove its child in response to the OnChildUnavailable notification.
+  // We don't need to schedule layout for the child either since it will
+  // retain its old layout parameters.
+}
+
+void ViewRegistry::UnlinkChild(ViewState* parent_state,
+                               ViewState::ChildrenMap::iterator child_it) {
+  DCHECK(IsViewStateRegisteredDebug(parent_state));
+  DCHECK(child_it != parent_state->children().end());
+
+  ViewState* child_state = child_it->second;
+  if (child_state) {
+    DVLOG(2) << "Removed child " << child_state->key() << " {"
+             << child_state->view_token_value() << "} from parent {"
+             << parent_state->view_token_value() << "}";
+    ResetStateWhenUnlinking(child_it->second);
+    child_state->ResetContainer();
+  } else {
+    DVLOG(2) << "Removed unavailable child " << child_it->first
+             << "} from parent {" << parent_state->view_token_value() << "}";
+  }
+  parent_state->children().erase(child_it);
+
+  // Schedule layout for the parent now that it has lost its child.
+  // We don't need to schedule layout for the child itself since it will
+  // retain its old layout parameters.
+  InvalidateLayout(parent_state);
+}
+
+void ViewRegistry::LinkRoot(ViewTreeState* tree_state,
+                            ViewState* root_state,
+                            uint32_t root_key) {
+  DCHECK(IsViewTreeStateRegisteredDebug(tree_state));
+  DCHECK(IsViewStateRegisteredDebug(root_state));
+  DCHECK(!tree_state->root());
+  DCHECK(!root_state->parent());
+
+  DVLOG(2) << "Linked view tree root " << root_key << " {"
+           << root_state->view_token_value() << "}";
+
+  tree_state->SetRoot(root_state, root_key);
+
+  // Schedule layout of the tree on behalf of its newly added root.
+  // We don't need to schedule layout of the root until the tree provides
+  // new layout parameters.
+  InvalidateLayoutForRoot(tree_state);
+}
+
+void ViewRegistry::UnlinkRoot(ViewTreeState* tree_state) {
+  DCHECK(IsViewTreeStateRegisteredDebug(tree_state));
+  DCHECK(tree_state->root());
+
+  DVLOG(2) << "Unlinked view tree root " << tree_state->root()->key() << " {"
+           << tree_state->root()->view_token_value() << "}";
+
+  ResetStateWhenUnlinking(tree_state->root());
+  tree_state->ResetRoot();
+
+  // We don't need to schedule layout for the root since it will retain
+  // its old layout parameters.
+}
+
+void ViewRegistry::HijackView(ViewState* view_state) {
+  if (view_state->parent()) {
+    MarkChildAsUnavailable(view_state->parent(), view_state->key());
+  } else if (view_state->tree()) {
+    ViewTreeState* tree_state = view_state->tree();
+    uint32_t root_key = tree_state->root()->key();
+    UnlinkRoot(tree_state);
+    SendRootUnavailable(tree_state, root_key);
+  }
+}
+
+void ViewRegistry::InvalidateLayout(ViewState* view_state) {
+  DCHECK(IsViewStateRegisteredDebug(view_state));
+
+  // We can consider the layout request to have been satisfied if
+  // there is already a pending layout request in the queue that has not
+  // yet been issued (this is coalescing).  Otherwise we must manufacture
+  // a new one based on the current layout parameters.
+  if (view_state->layout_params() &&
+      (view_state->pending_layout_requests().empty() ||
+       view_state->pending_layout_requests().back()->issued())) {
+    EnqueueLayoutRequest(view_state, view_state->layout_params().Clone());
+    IssueNextViewLayoutRequest(view_state);
+  }
+}
+
+void ViewRegistry::InvalidateLayoutForChild(ViewState* parent_state,
+                                            uint32_t child_key) {
+  DCHECK(IsViewStateRegisteredDebug(parent_state));
+  DCHECK(parent_state->children().find(child_key) !=
+         parent_state->children().end());
+
+  parent_state->children_needing_layout().insert(child_key);
+  InvalidateLayout(parent_state);
+}
+
+void ViewRegistry::InvalidateLayoutForRoot(ViewTreeState* tree_state) {
+  DCHECK(IsViewTreeStateRegisteredDebug(tree_state));
+
+  if (!tree_state->layout_request_pending()) {
+    tree_state->set_layout_request_pending(true);
+    IssueNextViewTreeLayoutRequest(tree_state);
+  }
+}
+
+void ViewRegistry::SetLayout(ViewState* view_state,
+                             mojo::ui::ViewLayoutParamsPtr layout_params,
+                             const ViewLayoutCallback& callback) {
+  DCHECK(IsViewStateRegisteredDebug(view_state));
+  DCHECK(AreViewLayoutParamsValid(layout_params.get()));
+
+  // Check whether the currently cached layout parameters are the same
+  // and we already have a result and we have no pending layout requests.
+  if (view_state->pending_layout_requests().empty() &&
+      view_state->layout_params() && view_state->layout_info() &&
+      view_state->layout_params()->Equals(*layout_params)) {
+    DVLOG(2) << "Layout cache hit";
+    callback.Run(view_state->layout_info().Clone());
+    return;
+  }
+
+  // Check whether the layout parameters are different from the most
+  // recent pending layout request if we have one.
+  if (view_state->pending_layout_requests().empty() ||
+      !view_state->pending_layout_requests().back()->layout_params()->Equals(
+          *layout_params)) {
+    // Enqueue a new request for these parameters.
+    EnqueueLayoutRequest(view_state, layout_params.Pass());
+  }
+
+  // Enlist ourselves into the callbacks for the pending request.
+  view_state->pending_layout_requests().back()->AddCallback(callback);
+  IssueNextViewLayoutRequest(view_state);
+}
+
+void ViewRegistry::EnqueueLayoutRequest(
+    ViewState* view_state,
+    mojo::ui::ViewLayoutParamsPtr layout_params) {
+  DCHECK(IsViewStateRegisteredDebug(view_state));
+  DCHECK(AreViewLayoutParamsValid(layout_params.get()));
+
+  // Drop the previous layout request if it hasn't been issued yet.
+  // This may cause callbacks to be invoked will null information.
+  if (!view_state->pending_layout_requests().empty() &&
+      !view_state->pending_layout_requests().back()->issued())
+    view_state->pending_layout_requests().pop_back();
+
+  // Enqueue the new request.
+  view_state->pending_layout_requests().emplace_back(
+      std::unique_ptr<ViewLayoutRequest>(
+          new ViewLayoutRequest(layout_params.Pass())));
+}
+
+void ViewRegistry::IssueNextViewLayoutRequest(ViewState* view_state) {
+  DCHECK(IsViewStateRegisteredDebug(view_state));
+
+  if (!view_state->pending_layout_requests().empty() &&
+      !view_state->pending_layout_requests().front()->issued()) {
+    view_state->pending_layout_requests().front()->set_issued(true);
+    SendViewLayoutRequest(view_state);
+  }
+}
+
+void ViewRegistry::IssueNextViewTreeLayoutRequest(ViewTreeState* tree_state) {
+  DCHECK(IsViewTreeStateRegisteredDebug(tree_state));
+
+  if (tree_state->layout_request_pending() &&
+      !tree_state->layout_request_issued()) {
+    tree_state->set_layout_request_pending(false);
+    tree_state->set_layout_request_issued(true);
+    SendViewTreeLayoutRequest(tree_state);
+  }
+}
+
+void ViewRegistry::ResetStateWhenUnlinking(ViewState* view_state) {
+  // Clean up parent's recorded state for the child.
+  if (view_state->parent()) {
+    view_state->parent()->children_needing_layout().erase(view_state->key());
+  }
+
+  // Clean up child's recorded state for the parent or tree.
+  if (view_state->wrapped_surface()) {
+    surface_manager_->DestroySurface(view_state->wrapped_surface().Pass());
+  }
+}
+
+void ViewRegistry::SendChildUnavailable(ViewState* parent_state,
+                                        uint32_t child_key) {
+  DCHECK(IsViewStateRegisteredDebug(parent_state));
+
+  // TODO: Detect ANRs
+  DVLOG(1) << "SendChildUnavailable: child_key=" << child_key;
+  parent_state->view()->OnChildUnavailable(child_key,
+                                           base::Bind(&base::DoNothing));
+}
+
+void ViewRegistry::SendRootUnavailable(ViewTreeState* tree_state,
+                                       uint32_t root_key) {
+  DCHECK(IsViewTreeStateRegisteredDebug(tree_state));
+
+  // TODO: Detect ANRs
+  DVLOG(1) << "SendRootUnavailable: root_key=" << root_key;
+  tree_state->view_tree()->OnRootUnavailable(root_key,
+                                             base::Bind(&base::DoNothing));
+}
+
+void ViewRegistry::SendViewLayoutRequest(ViewState* view_state) {
+  DCHECK(IsViewStateRegisteredDebug(view_state));
+  DCHECK(!view_state->pending_layout_requests().empty());
+  DCHECK(view_state->pending_layout_requests().front()->issued());
+
+  // TODO: Detect ANRs
+  DVLOG(1) << "SendViewLayoutRequest: view.token="
+           << view_state->view_token_value();
+  view_state->view()->OnLayout(
+      view_state->pending_layout_requests().front()->layout_params()->Clone(),
+      mojo::Array<uint32_t>::From(view_state->children_needing_layout()),
+      base::Bind(&ViewRegistry::OnViewLayoutResult, base::Unretained(this),
+                 view_state->GetWeakPtr()));
+  view_state->children_needing_layout().clear();
+}
+
+void ViewRegistry::SendViewTreeLayoutRequest(ViewTreeState* tree_state) {
+  DCHECK(IsViewTreeStateRegisteredDebug(tree_state));
+  DCHECK(tree_state->layout_request_issued());
+
+  // TODO: Detect ANRs
+  DVLOG(1) << "SendViewTreeLayoutRequest";
+  tree_state->view_tree()->OnLayout(
+      base::Bind(&ViewRegistry::OnViewTreeLayoutResult, base::Unretained(this),
+                 tree_state->GetWeakPtr()));
+}
+
+static bool IsSizeInBounds(mojo::ui::BoxConstraints* constraints,
+                           mojo::Size* size) {
+  return size && size->width >= constraints->min_width &&
+         size->width <= constraints->max_width &&
+         size->height >= constraints->min_height &&
+         size->height <= constraints->max_height;
+}
+
+void ViewRegistry::OnViewLayoutResult(base::WeakPtr<ViewState> view_state_weak,
+                                      mojo::ui::ViewLayoutInfoPtr info) {
+  DCHECK(info);
+  DCHECK(info->surface_id);  // checked by mojom
+
+  ViewState* view_state = view_state_weak.get();
+  if (!view_state)
+    return;
+
+  DCHECK(!view_state->pending_layout_requests().empty());
+  DCHECK(view_state->pending_layout_requests().front()->issued());
+
+  std::unique_ptr<ViewLayoutRequest> request(
+      std::move(view_state->pending_layout_requests().front()));
+  view_state->pending_layout_requests().erase(
+      view_state->pending_layout_requests().begin());
+
+  DVLOG(1) << "OnViewLayoutResult: view=" << view_state
+           << ", params=" << request->layout_params()
+           << ", info=" << info.get();
+
+  // Validate the layout info.
+  if (!IsSizeInBounds(request->layout_params()->constraints.get(),
+                      info->size.get())) {
+    LOG(ERROR) << "View returned invalid size in its layout info: "
+               << "view=" << view_state
+               << ", params=" << request->layout_params()
+               << ", info=" << info.get();
+    UnregisterView(view_state);
+    return;
+  }
+
+  // Assume the parent or root will not see the new layout information if
+  // there are no callbacks so we need to inform it when things change.
+  const bool size_changed =
+      !view_state->layout_info() ||
+      !view_state->layout_info()->size->Equals(*info->size);
+  const bool surface_changed =
+      !view_state->layout_info() ||
+      !view_state->layout_info()->surface_id->Equals(*info->surface_id);
+  const bool recurse =
+      !request->has_callbacks() && (surface_changed || size_changed);
+
+  view_state->layout_params() = request->TakeLayoutParams().Pass();
+  view_state->layout_info() = info.Pass();
+
+  if (surface_changed) {
+    if (view_state->wrapped_surface())
+      surface_manager_->DestroySurface(view_state->wrapped_surface().Pass());
+    view_state->wrapped_surface() = surface_manager_->CreateWrappedSurface(
+        view_state->layout_info()->surface_id.get());
+  }
+
+  request->DispatchLayoutInfo(view_state->layout_info().get());
+
+  if (recurse) {
+    if (view_state->parent()) {
+      InvalidateLayoutForChild(view_state->parent(), view_state->key());
+    } else if (view_state->tree()) {
+      InvalidateLayoutForRoot(view_state->tree());
+    }
+  }
+
+  IssueNextViewLayoutRequest(view_state);
+}
+
+void ViewRegistry::OnViewTreeLayoutResult(
+    base::WeakPtr<ViewTreeState> tree_state_weak) {
+  ViewTreeState* tree_state = tree_state_weak.get();
+  if (tree_state) {
+    DCHECK(tree_state->layout_request_issued());
+
+    DVLOG(1) << "OnViewTreeLayoutResult";
+
+    tree_state->set_layout_request_issued(false);
+    IssueNextViewTreeLayoutRequest(tree_state);
+  }
+}
+
+}  // namespace view_manager
diff --git a/services/ui/view_manager/view_registry.h b/services/ui/view_manager/view_registry.h
new file mode 100644
index 0000000..52f6782
--- /dev/null
+++ b/services/ui/view_manager/view_registry.h
@@ -0,0 +1,161 @@
+// 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 SERVICES_UI_VIEW_MANAGER_VIEW_REGISTRY_H_
+#define SERVICES_UI_VIEW_MANAGER_VIEW_REGISTRY_H_
+
+#include <unordered_map>
+#include <vector>
+
+#include "base/macros.h"
+#include "mojo/services/ui/views/interfaces/view_trees.mojom.h"
+#include "mojo/services/ui/views/interfaces/views.mojom.h"
+#include "services/ui/view_manager/view_layout_request.h"
+#include "services/ui/view_manager/view_state.h"
+#include "services/ui/view_manager/view_tree_state.h"
+
+namespace view_manager {
+
+class SurfaceManager;
+
+// Maintains a registry of the state of all views.
+// All ViewState objects are owned by the registry.
+class ViewRegistry {
+ public:
+  explicit ViewRegistry(SurfaceManager* surface_manager);
+  ~ViewRegistry();
+
+  // VIEW MANAGER REQUESTS
+
+  // Registers a view and returns its ViewToken.
+  mojo::ui::ViewTokenPtr RegisterView(
+      mojo::ui::ViewPtr view,
+      mojo::InterfaceRequest<mojo::ui::ViewHost> view_host_request);
+
+  // Registers a view tree.
+  void RegisterViewTree(
+      mojo::ui::ViewTreePtr view_tree,
+      mojo::InterfaceRequest<mojo::ui::ViewTreeHost> view_tree_host_request);
+
+  // VIEW HOST REQUESTS
+
+  // Requests layout.
+  // Destroys |view_state| if an error occurs.
+  void RequestLayout(ViewState* view_state);
+
+  // Adds a child, reparenting it if necessary.
+  // Destroys |parent_state| if an error occurs.
+  void AddChild(ViewState* parent_state,
+                uint32_t child_key,
+                mojo::ui::ViewTokenPtr child_view_token);
+
+  // Removes a child.
+  // Destroys |parent_state| if an error occurs.
+  void RemoveChild(ViewState* parent_state, uint32_t child_key);
+
+  // Lays out a child and optionally provides its size.
+  // Destroys |parent_state| if an error occurs.
+  void LayoutChild(ViewState* parent_state,
+                   uint32_t child_key,
+                   mojo::ui::ViewLayoutParamsPtr child_layout_params,
+                   const ViewLayoutCallback& callback);
+
+  // VIEW TREE HOST REQUESTS
+
+  // Requests layout.
+  // Destroys |tree_state| if an error occurs.
+  void RequestLayout(ViewTreeState* tree_state);
+
+  // Sets the root of the view tree.
+  // Destroys |tree_state| if an error occurs.
+  void SetRoot(ViewTreeState* tree_state,
+               uint32_t root_key,
+               mojo::ui::ViewTokenPtr root_view_token);
+
+  // Resets the root of the view tree.
+  // Destroys |tree_state| if an error occurs.
+  void ResetRoot(ViewTreeState* tree_state);
+
+  // Lays out a view tree's root and optionally provides its size.
+  // Destroys |tree_state| if an error occurs.
+  void LayoutRoot(ViewTreeState* tree_state,
+                  mojo::ui::ViewLayoutParamsPtr root_layout_params,
+                  const ViewLayoutCallback& callback);
+
+ private:
+  // LIFETIME
+
+  void OnViewConnectionError(ViewState* view_state);
+  void UnregisterView(ViewState* view_state);
+  void OnViewTreeConnectionError(ViewTreeState* tree_state);
+  void UnregisterViewTree(ViewTreeState* tree_state);
+
+  // TREE MANIPULATION
+
+  ViewState* FindView(uint32_t view_token);
+  void LinkChild(ViewState* parent_state,
+                 uint32_t child_key,
+                 ViewState* child_state);
+  void LinkChildAsUnavailable(ViewState* parent_state, uint32_t child_key);
+  void MarkChildAsUnavailable(ViewState* parent_state, uint32_t child_key);
+  void UnlinkChild(ViewState* parent_state,
+                   ViewState::ChildrenMap::iterator child_it);
+  void LinkRoot(ViewTreeState* tree_state,
+                ViewState* root_state,
+                uint32_t root_key);
+  void UnlinkRoot(ViewTreeState* tree_state);
+  void HijackView(ViewState* view_state);
+
+  // Must be called before the view is actually unlinked from the tree.
+  // Caller is still responsible for actually unlinking the view.
+  void ResetStateWhenUnlinking(ViewState* view_state);
+
+  // LAYOUT
+
+  void InvalidateLayout(ViewState* view_state);
+  void InvalidateLayoutForChild(ViewState* parent_state, uint32_t child_key);
+  void InvalidateLayoutForRoot(ViewTreeState* tree_state);
+  void SetLayout(ViewState* view_state,
+                 mojo::ui::ViewLayoutParamsPtr layout_params,
+                 const ViewLayoutCallback& callback);
+  void EnqueueLayoutRequest(ViewState* view_state,
+                            mojo::ui::ViewLayoutParamsPtr layout_params);
+  void IssueNextViewLayoutRequest(ViewState* view_state);
+  void IssueNextViewTreeLayoutRequest(ViewTreeState* tree_state);
+
+  // SIGNALLING
+
+  void SendChildUnavailable(ViewState* parent_state, uint32_t child_key);
+  void SendRootUnavailable(ViewTreeState* tree_state, uint32_t root_key);
+  void SendViewLayoutRequest(ViewState* view_state);
+  void SendViewTreeLayoutRequest(ViewTreeState* tree_state);
+  void OnViewLayoutResult(base::WeakPtr<ViewState> view_state_weak,
+                          mojo::ui::ViewLayoutInfoPtr info);
+  void OnViewTreeLayoutResult(base::WeakPtr<ViewTreeState> tree_state_weak);
+
+#if DCHECK_IS_ON()
+  bool IsViewStateRegisteredDebug(ViewState* view_state) {
+    return view_state && FindView(view_state->view_token_value());
+  }
+
+  bool IsViewTreeStateRegisteredDebug(ViewTreeState* tree_state) {
+    return tree_state && std::any_of(view_trees_.begin(), view_trees_.end(),
+                                     [tree_state](ViewTreeState* other) {
+                                       return tree_state == other;
+                                     });
+  }
+#endif
+
+  SurfaceManager* surface_manager_;
+
+  uint32_t next_view_token_value_;
+  std::unordered_map<uint32_t, ViewState*> views_by_token_;
+  std::vector<ViewTreeState*> view_trees_;
+
+  DISALLOW_COPY_AND_ASSIGN(ViewRegistry);
+};
+
+}  // namespace view_manager
+
+#endif  // SERVICES_UI_VIEW_MANAGER_VIEW_REGISTRY_H_
diff --git a/services/ui/view_manager/view_state.cc b/services/ui/view_manager/view_state.cc
new file mode 100644
index 0000000..cfccc56
--- /dev/null
+++ b/services/ui/view_manager/view_state.cc
@@ -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.
+
+#include "base/logging.h"
+#include "services/ui/view_manager/view_state.h"
+#include "services/ui/view_manager/view_tree_state.h"
+
+namespace view_manager {
+
+ViewState::ViewState(mojo::ui::ViewPtr view, uint32_t view_token_value)
+    : view_(view.Pass()),
+      view_token_value_(view_token_value),
+      tree_(nullptr),
+      parent_(nullptr),
+      key_(0),
+      weak_factory_(this) {
+  DCHECK(view_);
+}
+
+ViewState::~ViewState() {}
+
+void ViewState::SetTree(ViewTreeState* tree, uint32_t key) {
+  DCHECK(tree);
+  DCHECK(!parent_);  // must be the root
+  if (tree_ != tree) {
+    SetTreeUnchecked(tree);
+  }
+  key_ = key;
+}
+
+void ViewState::SetTreeUnchecked(ViewTreeState* tree) {
+  tree_ = tree;
+  for (const auto& pair : children_) {
+    pair.second->SetTreeUnchecked(tree);
+  }
+}
+
+void ViewState::SetParent(ViewState* parent, uint32_t key) {
+  DCHECK(parent);
+  parent_ = parent;
+  key_ = key;
+  SetTreeUnchecked(parent->tree_);
+}
+
+void ViewState::ResetContainer() {
+  parent_ = nullptr;
+  key_ = 0;
+  SetTreeUnchecked(nullptr);
+}
+
+void ViewState::GetServiceProvider(
+    mojo::InterfaceRequest<mojo::ServiceProvider> service_provider) {}
+
+}  // namespace view_manager
diff --git a/services/ui/view_manager/view_state.h b/services/ui/view_manager/view_state.h
new file mode 100644
index 0000000..1f1d2a8
--- /dev/null
+++ b/services/ui/view_manager/view_state.h
@@ -0,0 +1,128 @@
+// 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 SERVICES_UI_VIEW_MANAGER_VIEW_STATE_H_
+#define SERVICES_UI_VIEW_MANAGER_VIEW_STATE_H_
+
+#include <memory>
+#include <set>
+#include <unordered_map>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "mojo/services/ui/views/interfaces/views.mojom.h"
+#include "services/ui/view_manager/view_layout_request.h"
+
+namespace view_manager {
+
+class ViewTreeState;
+
+// Describes the state of a particular view.
+// This object is owned by the ViewRegistry that created it.
+class ViewState {
+ public:
+  using ChildrenMap = std::unordered_map<uint32_t, ViewState*>;
+
+  ViewState(mojo::ui::ViewPtr view, uint32_t view_token_value);
+  ~ViewState();
+
+  base::WeakPtr<ViewState> GetWeakPtr() { return weak_factory_.GetWeakPtr(); }
+
+  // Gets the view interface, never null.
+  // Caller does not obtain ownership of the view.
+  mojo::ui::View* view() const { return view_.get(); }
+
+  // Gets the view token value used to refer to this view globally.
+  uint32_t view_token_value() const { return view_token_value_; }
+
+  // Sets the associated host implementation and takes ownership of it.
+  void set_view_host(mojo::ui::ViewHost* host) { view_host_.reset(host); }
+
+  // Sets the connection error handler for the view.
+  void set_view_connection_error_handler(const base::Closure& handler) {
+    view_.set_connection_error_handler(handler);
+  }
+
+  // Gets the view tree to which this view belongs, or null if none.
+  ViewTreeState* tree() const { return tree_; }
+
+  // Gets the parent view state, or null if none.
+  ViewState* parent() const { return parent_; }
+
+  // Gets the key that this child has in its container, or 0 if none.
+  uint32_t key() const { return key_; }
+
+  // Recursively sets the view tree to which this view and all of its
+  // descendents belongs.  Must not be null.  This method must only be called
+  // on root views.
+  void SetTree(ViewTreeState* tree, uint32_t key);
+
+  // Sets the parent view state pointer, the child's key in its parent,
+  // and set its view tree to that of its parent.  Must not be null.
+  void SetParent(ViewState* parent, uint32_t key);
+
+  // Resets the parent view state and tree pointers to null.
+  void ResetContainer();
+
+  // Gets the view's service provider.
+  void GetServiceProvider(
+      mojo::InterfaceRequest<mojo::ServiceProvider> service_provider);
+
+  // The map of children, indexed by child key.
+  // Child view state may be null if the child with the given key has
+  // become unavailable but not yet removed.
+  ChildrenMap& children() { return children_; }
+
+  // The set of children needing layout.
+  // This set must never contain non-existent or unavailable children.
+  std::set<uint32_t>& children_needing_layout() {
+    return children_needing_layout_;
+  }
+
+  // The list of pending layout requests.
+  std::vector<std::unique_ptr<ViewLayoutRequest>>& pending_layout_requests() {
+    return pending_layout_requests_;
+  }
+
+  // The layout parameters most recently processed by the view,
+  // or null if none.  These parameters are preserved across reparenting.
+  mojo::ui::ViewLayoutParamsPtr& layout_params() { return layout_params_; }
+
+  // The layout information most recently provided by the view in
+  // response to the value of |layout_params|, or null if none.  These
+  // results are preserved across reparenting.
+  mojo::ui::ViewLayoutInfoPtr& layout_info() { return layout_info_; }
+
+  // The id of the Surface which the view manager itself created to wrap the
+  // view's own Surface, or null if none.  The wrapped Surface is destroyed
+  // when the view is reparented so that the old parent can no longer embed
+  // the view's actual content.
+  mojo::SurfaceIdPtr& wrapped_surface() { return wrapped_surface_; }
+
+ private:
+  void SetTreeUnchecked(ViewTreeState* tree);
+
+  mojo::ui::ViewPtr view_;
+  const uint32_t view_token_value_;
+
+  std::unique_ptr<mojo::ui::ViewHost> view_host_;
+  ViewTreeState* tree_;
+  ViewState* parent_;
+  uint32_t key_;
+  ChildrenMap children_;
+  std::set<uint32_t> children_needing_layout_;
+  std::vector<std::unique_ptr<ViewLayoutRequest>> pending_layout_requests_;
+  mojo::ui::ViewLayoutParamsPtr layout_params_;
+  mojo::ui::ViewLayoutInfoPtr layout_info_;
+  mojo::SurfaceIdPtr wrapped_surface_;
+
+  base::WeakPtrFactory<ViewState> weak_factory_;  // must be last
+
+  DISALLOW_COPY_AND_ASSIGN(ViewState);
+};
+
+}  // namespace view_manager
+
+#endif  // SERVICES_UI_VIEW_MANAGER_VIEW_STATE_H_
diff --git a/services/ui/view_manager/view_tree_host_impl.cc b/services/ui/view_manager/view_tree_host_impl.cc
new file mode 100644
index 0000000..e970a69
--- /dev/null
+++ b/services/ui/view_manager/view_tree_host_impl.cc
@@ -0,0 +1,47 @@
+// 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 "base/bind.h"
+#include "base/bind_helpers.h"
+#include "services/ui/view_manager/view_tree_host_impl.h"
+
+namespace view_manager {
+
+ViewTreeHostImpl::ViewTreeHostImpl(
+    ViewRegistry* registry,
+    ViewTreeState* state,
+    mojo::InterfaceRequest<mojo::ui::ViewTreeHost> view_tree_host_request)
+    : registry_(registry),
+      state_(state),
+      binding_(this, view_tree_host_request.Pass()) {}
+
+ViewTreeHostImpl::~ViewTreeHostImpl() {}
+
+void ViewTreeHostImpl::RequestLayout() {
+  registry_->RequestLayout(state_);
+}
+
+void ViewTreeHostImpl::SetRoot(uint32_t root_key,
+                               mojo::ui::ViewTokenPtr root_view_token) {
+  registry_->SetRoot(state_, root_key, root_view_token.Pass());
+}
+
+void ViewTreeHostImpl::ResetRoot() {
+  registry_->ResetRoot(state_);
+}
+
+static void RunLayoutRootCallback(
+    const ViewTreeHostImpl::LayoutRootCallback& callback,
+    mojo::ui::ViewLayoutInfoPtr info) {
+  callback.Run(info.Pass());
+}
+
+void ViewTreeHostImpl::LayoutRoot(
+    mojo::ui::ViewLayoutParamsPtr root_layout_params,
+    const LayoutRootCallback& callback) {
+  registry_->LayoutRoot(state_, root_layout_params.Pass(),
+                        base::Bind(&RunLayoutRootCallback, callback));
+}
+
+}  // namespace view_manager
diff --git a/services/ui/view_manager/view_tree_host_impl.h b/services/ui/view_manager/view_tree_host_impl.h
new file mode 100644
index 0000000..9677d81
--- /dev/null
+++ b/services/ui/view_manager/view_tree_host_impl.h
@@ -0,0 +1,49 @@
+// 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 SERVICES_UI_VIEW_MANAGER_VIEW_TREE_HOST_IMPL_H_
+#define SERVICES_UI_VIEW_MANAGER_VIEW_TREE_HOST_IMPL_H_
+
+#include "base/macros.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/services/ui/views/interfaces/view_trees.mojom.h"
+#include "services/ui/view_manager/view_registry.h"
+#include "services/ui/view_manager/view_tree_state.h"
+
+namespace view_manager {
+
+// ViewTreeHost interface implementation.
+// This object is owned by its associated ViewTreeState.
+class ViewTreeHostImpl : public mojo::ui::ViewTreeHost {
+ public:
+  ViewTreeHostImpl(
+      ViewRegistry* registry,
+      ViewTreeState* state,
+      mojo::InterfaceRequest<mojo::ui::ViewTreeHost> view_tree_host_request);
+  ~ViewTreeHostImpl() override;
+
+  void set_view_tree_host_connection_error_handler(
+      const base::Closure& handler) {
+    binding_.set_connection_error_handler(handler);
+  }
+
+ private:
+  // |ViewTreeHost|:
+  void RequestLayout() override;
+  void SetRoot(uint32_t root_key,
+               mojo::ui::ViewTokenPtr root_view_token) override;
+  void ResetRoot() override;
+  void LayoutRoot(mojo::ui::ViewLayoutParamsPtr root_layout_params,
+                  const LayoutRootCallback& callback) override;
+
+  ViewRegistry* const registry_;
+  ViewTreeState* const state_;
+  mojo::Binding<mojo::ui::ViewTreeHost> binding_;
+
+  DISALLOW_COPY_AND_ASSIGN(ViewTreeHostImpl);
+};
+
+}  // namespace view_manager
+
+#endif  // SERVICES_UI_VIEW_MANAGER_VIEW_TREE_HOST_IMPL_H_
diff --git a/services/ui/view_manager/view_tree_state.cc b/services/ui/view_manager/view_tree_state.cc
new file mode 100644
index 0000000..e236c08
--- /dev/null
+++ b/services/ui/view_manager/view_tree_state.cc
@@ -0,0 +1,38 @@
+// 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 "base/logging.h"
+#include "services/ui/view_manager/view_tree_state.h"
+
+namespace view_manager {
+
+ViewTreeState::ViewTreeState(mojo::ui::ViewTreePtr view_tree)
+    : view_tree_(view_tree.Pass()),
+      root_(nullptr),
+      explicit_root_(false),
+      layout_request_pending_(false),
+      layout_request_issued_(false),
+      weak_factory_(this) {
+  DCHECK(view_tree_);
+}
+
+ViewTreeState::~ViewTreeState() {}
+
+void ViewTreeState::SetRoot(ViewState* root, uint32_t key) {
+  DCHECK(root);
+  if (root_ != root) {
+    ResetRoot();
+    root->SetTree(this, key);
+    root_ = root;
+  }
+}
+
+void ViewTreeState::ResetRoot() {
+  if (root_) {
+    root_->ResetContainer();
+  }
+  root_ = nullptr;
+}
+
+}  // namespace view_manager
diff --git a/services/ui/view_manager/view_tree_state.h b/services/ui/view_manager/view_tree_state.h
new file mode 100644
index 0000000..abcbad9
--- /dev/null
+++ b/services/ui/view_manager/view_tree_state.h
@@ -0,0 +1,87 @@
+// 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 SERVICES_UI_VIEW_MANAGER_VIEW_TREE_STATE_H_
+#define SERVICES_UI_VIEW_MANAGER_VIEW_TREE_STATE_H_
+
+#include <memory>
+#include <set>
+#include <unordered_map>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/services/ui/views/interfaces/view_trees.mojom.h"
+#include "services/ui/view_manager/view_state.h"
+
+namespace view_manager {
+
+// Describes the state of a particular view tree.
+// This object is owned by the ViewRegistry that created it.
+class ViewTreeState {
+ public:
+  explicit ViewTreeState(mojo::ui::ViewTreePtr view_tree);
+  ~ViewTreeState();
+
+  base::WeakPtr<ViewTreeState> GetWeakPtr() {
+    return weak_factory_.GetWeakPtr();
+  }
+
+  // Gets the view tree interface, never null.
+  // Caller does not obtain ownership of the view.
+  mojo::ui::ViewTree* view_tree() const { return view_tree_.get(); }
+
+  // Sets the associated host implementation and takes ownership of it.
+  void set_view_tree_host(mojo::ui::ViewTreeHost* host) {
+    view_tree_host_.reset(host);
+  }
+
+  // Sets the connection error handler for the view.
+  void set_view_tree_connection_error_handler(const base::Closure& handler) {
+    view_tree_.set_connection_error_handler(handler);
+  }
+
+  // Gets the root of the view tree, or null if it is unavailable.
+  ViewState* root() const { return root_; }
+
+  // Sets the root of the view tree.  Must not be null.
+  // The view specified as the new root must not have any parents.
+  void SetRoot(ViewState* root, uint32_t key);
+
+  // Resets the root view to null.
+  void ResetRoot();
+
+  // True if the client previously set but has not yet explicitly unset
+  // the root, independent of whether it is currently available.
+  bool explicit_root() const { return explicit_root_; }
+  void set_explicit_root(bool value) { explicit_root_ = value; }
+
+  // True if there is a pending layout request.
+  bool layout_request_pending() const { return layout_request_pending_; }
+  void set_layout_request_pending(bool value) {
+    layout_request_pending_ = value;
+  }
+
+  // True if a layout request has been issued.
+  bool layout_request_issued() const { return layout_request_issued_; }
+  void set_layout_request_issued(bool value) { layout_request_issued_ = value; }
+
+ private:
+  mojo::ui::ViewTreePtr view_tree_;
+
+  std::unique_ptr<mojo::ui::ViewTreeHost> view_tree_host_;
+  ViewState* root_;
+  bool explicit_root_;
+  bool layout_request_pending_;
+  bool layout_request_issued_;
+
+  base::WeakPtrFactory<ViewTreeState> weak_factory_;  // must be last
+
+  DISALLOW_COPY_AND_ASSIGN(ViewTreeState);
+};
+
+}  // namespace view_manager
+
+#endif  // SERVICES_UI_VIEW_MANAGER_VIEW_TREE_STATE_H_