[go: nahoru, domu]

Adds a porting layer so aura can be made to work with mus

This introduces WindowPort and the single concrete implementation of
it WindowPortAura. WindowPort contains the set of functions needed to
get aura to work with mus. A new constructor is added to Window and
WindowTreeNhost that can be used to specify an explicit
WindowPort. This is not the common case though, the common case is to
use a constructor that does not take a WindowPort, in which case a
WindowPort is created using a callback specified at the time of
creating Env.

BUG=659155
TEST=covered by existing tests
sadrul@chromium.org

Review-Url: https://codereview.chromium.org/2446893005
Cr-Commit-Position: refs/heads/master@{#427750}
diff --git a/ui/aura/BUILD.gn b/ui/aura/BUILD.gn
index 457615b5..fd4fc49 100644
--- a/ui/aura/BUILD.gn
+++ b/ui/aura/BUILD.gn
@@ -78,6 +78,10 @@
     "window_event_dispatcher.h",
     "window_observer.cc",
     "window_observer.h",
+    "window_port.cc",
+    "window_port.h",
+    "window_port_local.cc",
+    "window_port_local.h",
     "window_targeter.cc",
     "window_targeter.h",
     "window_tracker.h",
diff --git a/ui/aura/env.cc b/ui/aura/env.cc
index 07c1138..5671451 100644
--- a/ui/aura/env.cc
+++ b/ui/aura/env.cc
@@ -6,9 +6,11 @@
 
 #include "base/command_line.h"
 #include "base/lazy_instance.h"
+#include "base/memory/ptr_util.h"
 #include "base/threading/thread_local.h"
 #include "ui/aura/env_observer.h"
 #include "ui/aura/input_state_lookup.h"
+#include "ui/aura/window_port_local.h"
 #include "ui/events/event_target_iterator.h"
 #include "ui/events/platform/platform_event_source.h"
 
@@ -43,9 +45,10 @@
 }
 
 // static
-std::unique_ptr<Env> Env::CreateInstance() {
+std::unique_ptr<Env> Env::CreateInstance(
+    const WindowPortFactory& window_port_factory) {
   DCHECK(!lazy_tls_ptr.Pointer()->Get());
-  std::unique_ptr<Env> env(new Env());
+  std::unique_ptr<Env> env(new Env(window_port_factory));
   env->Init();
   return env;
 }
@@ -63,6 +66,12 @@
   return lazy_tls_ptr.Pointer()->Get();
 }
 
+std::unique_ptr<WindowPort> Env::CreateWindowPort(Window* window) {
+  if (window_port_factory_.is_null())
+    return base::MakeUnique<WindowPortLocal>(window);
+  return window_port_factory_.Run(window);
+}
+
 void Env::AddObserver(EnvObserver* observer) {
   observers_.AddObserver(observer);
 }
@@ -79,8 +88,9 @@
 ////////////////////////////////////////////////////////////////////////////////
 // Env, private:
 
-Env::Env()
-    : mouse_button_flags_(0),
+Env::Env(const WindowPortFactory& window_port_factory)
+    : window_port_factory_(window_port_factory),
+      mouse_button_flags_(0),
       is_touch_down_(false),
       input_state_lookup_(InputStateLookup::Create()),
       context_factory_(NULL) {
diff --git a/ui/aura/env.h b/ui/aura/env.h
index 01b9e0dd..d557a1f 100644
--- a/ui/aura/env.h
+++ b/ui/aura/env.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 
+#include "base/callback.h"
 #include "base/macros.h"
 #include "base/observer_list.h"
 #include "base/supports_user_data.h"
@@ -28,6 +29,7 @@
 class EnvObserver;
 class InputStateLookup;
 class Window;
+class WindowPort;
 class WindowTreeHost;
 
 // A singleton object that tracks general state within Aura.
@@ -35,10 +37,16 @@
  public:
   ~Env() override;
 
-  static std::unique_ptr<Env> CreateInstance();
+  using WindowPortFactory =
+      base::Callback<std::unique_ptr<WindowPort>(Window* window)>;
+  static std::unique_ptr<Env> CreateInstance(
+      const WindowPortFactory& window_port_factory = WindowPortFactory());
   static Env* GetInstance();
   static Env* GetInstanceDontCreate();
 
+  // Called internally to create the appropriate WindowPort implementation.
+  std::unique_ptr<WindowPort> CreateWindowPort(Window* window);
+
   void AddObserver(EnvObserver* observer);
   void RemoveObserver(EnvObserver* observer);
 
@@ -71,7 +79,7 @@
   friend class Window;
   friend class WindowTreeHost;
 
-  Env();
+  explicit Env(const WindowPortFactory& window_port_factory);
 
   void Init();
 
@@ -90,6 +98,8 @@
   std::unique_ptr<ui::EventTargetIterator> GetChildIterator() const override;
   ui::EventTargeter* GetEventTargeter() override;
 
+  WindowPortFactory window_port_factory_;
+
   base::ObserverList<EnvObserver> observers_;
 
   int mouse_button_flags_;
diff --git a/ui/aura/window.cc b/ui/aura/window.cc
index be94111..3e3858b 100644
--- a/ui/aura/window.cc
+++ b/ui/aura/window.cc
@@ -30,6 +30,8 @@
 #include "ui/aura/window_delegate.h"
 #include "ui/aura/window_event_dispatcher.h"
 #include "ui/aura/window_observer.h"
+#include "ui/aura/window_port.h"
+#include "ui/aura/window_port_local.h"
 #include "ui/aura/window_tracker.h"
 #include "ui/aura/window_tree_host.h"
 #include "ui/compositor/compositor.h"
@@ -43,56 +45,20 @@
 
 namespace aura {
 
-class ScopedCursorHider {
- public:
-  explicit ScopedCursorHider(Window* window)
-      : window_(window),
-        hid_cursor_(false) {
-    if (!window_->IsRootWindow())
-      return;
-    const bool cursor_is_in_bounds = window_->GetBoundsInScreen().Contains(
-        Env::GetInstance()->last_mouse_location());
-    client::CursorClient* cursor_client = client::GetCursorClient(window_);
-    if (cursor_is_in_bounds && cursor_client &&
-        cursor_client->IsCursorVisible()) {
-      cursor_client->HideCursor();
-      hid_cursor_ = true;
-    }
-  }
-  ~ScopedCursorHider() {
-    if (!window_->IsRootWindow())
-      return;
+Window::Window(WindowDelegate* delegate) : Window(delegate, nullptr) {}
 
-    // Update the device scale factor of the cursor client only when the last
-    // mouse location is on this root window.
-    if (hid_cursor_) {
-      client::CursorClient* cursor_client = client::GetCursorClient(window_);
-      if (cursor_client) {
-        const display::Display& display =
-            display::Screen::GetScreen()->GetDisplayNearestWindow(window_);
-        cursor_client->SetDisplay(display);
-        cursor_client->ShowCursor();
-      }
-    }
-  }
-
- private:
-  Window* window_;
-  bool hid_cursor_;
-
-  DISALLOW_COPY_AND_ASSIGN(ScopedCursorHider);
-};
-
-Window::Window(WindowDelegate* delegate)
-    : host_(NULL),
+Window::Window(WindowDelegate* delegate, std::unique_ptr<WindowPort> port)
+    : port_owner_(std::move(port)),
+      port_(port_owner_.get()),
+      host_(nullptr),
       type_(ui::wm::WINDOW_TYPE_UNKNOWN),
       owned_by_parent_(true),
       delegate_(delegate),
-      parent_(NULL),
+      parent_(nullptr),
       visible_(false),
       id_(kInitialId),
       transparent_(false),
-      user_data_(NULL),
+      user_data_(nullptr),
       ignore_events_(false),
       // Don't notify newly added observers during notification. This causes
       // problems for code that adds an observer as part of an observer
@@ -102,6 +68,9 @@
 }
 
 Window::~Window() {
+  // See comment in header as to why this is done.
+  std::unique_ptr<WindowPort> port = std::move(port_owner_);
+
   if (layer()->owner() == this)
     layer()->CompleteAllAnimations();
   layer()->SuppressPaint();
@@ -170,12 +139,18 @@
 }
 
 void Window::Init(ui::LayerType layer_type) {
+  if (!port_owner_) {
+    port_owner_ = Env::GetInstance()->CreateWindowPort(this);
+    port_ = port_owner_.get();
+  }
   SetLayer(new ui::Layer(layer_type));
+  std::unique_ptr<WindowPortInitData> init_data = port_->OnPreInit(this);
   layer()->SetVisible(false);
   layer()->set_delegate(this);
   UpdateLayerName();
   layer()->SetFillsBoundsOpaquely(!transparent_);
   Env::GetInstance()->NotifyWindowInitialized(this);
+  port_->OnPostInit(std::move(init_data));
 }
 
 void Window::SetType(ui::wm::WindowType type) {
@@ -373,6 +348,8 @@
 
   Window* old_root = child->GetRootWindow();
 
+  port_->OnWillAddChild(child);
+
   DCHECK(std::find(children_.begin(), children_.end(), child) ==
       children_.end());
   if (child->parent())
@@ -406,6 +383,7 @@
   params.phase = WindowObserver::HierarchyChangeParams::HIERARCHY_CHANGING;
   NotifyWindowHierarchyChange(params);
 
+  port_->OnWillRemoveChild(child);
   RemoveChildImpl(child, NULL);
 
   params.phase = WindowObserver::HierarchyChangeParams::HIERARCHY_CHANGED;
@@ -517,6 +495,8 @@
 }
 
 Window* Window::GetToplevelWindow() {
+  // TODO: this may need to call to the WindowPort. For mus this may need to
+  // return for any top level.
   Window* topmost_window_with_delegate = NULL;
   for (aura::Window* window = this; window != NULL; window = window->parent()) {
     if (window->delegate())
@@ -556,6 +536,8 @@
 }
 
 bool Window::CanReceiveEvents() const {
+  // TODO(sky): this may want to delegate to the WindowPort as for mus there
+  // isn't a point in descending into windows owned by the client.
   if (IsRootWindow())
     return IsVisible();
 
@@ -603,6 +585,13 @@
   layer()->SuppressPaint();
 }
 
+std::set<const void*> Window::GetAllPropertKeys() const {
+  std::set<const void*> keys;
+  for (auto& pair : prop_map_)
+    keys.insert(pair.first);
+  return keys;
+}
+
 // {Set,Get,Clear}Property are implemented in window_property.h.
 
 void Window::SetNativeWindowProperty(const char* key, void* value) {
@@ -614,9 +603,7 @@
 }
 
 void Window::OnDeviceScaleFactorChanged(float device_scale_factor) {
-  ScopedCursorHider hider(this);
-  if (delegate_)
-    delegate_->OnDeviceScaleFactorChanged(device_scale_factor);
+  port_->OnDeviceScaleFactorChanged(device_scale_factor);
 }
 
 #if !defined(NDEBUG)
@@ -668,6 +655,9 @@
                                     PropertyDeallocator deallocator,
                                     int64_t value,
                                     int64_t default_value) {
+  // This code may be called before |port_| has been created.
+  std::unique_ptr<WindowPortPropertyData> data =
+      port_ ? port_->OnWillChangeProperty(key) : nullptr;
   int64_t old = GetPropertyInternal(key, default_value);
   if (value == default_value) {
     prop_map_.erase(key);
@@ -678,6 +668,8 @@
     prop_value.deallocator = deallocator;
     prop_map_[key] = prop_value;
   }
+  if (port_)
+    port_->OnPropertyChanged(key, std::move(data));
   for (WindowObserver& observer : observers_)
     observer.OnWindowPropertyChanged(this, key, old);
   return old;
@@ -735,6 +727,7 @@
   else
     layer()->SetVisible(visible);
   visible_ = visible;
+  port_->OnVisibilityChanged(visible);
   SchedulePaint();
   if (parent_ && parent_->layout_manager_)
     parent_->layout_manager_->OnChildWindowVisibilityChanged(this, visible);
@@ -864,6 +857,7 @@
       direction == STACK_ABOVE ?
       (child_i < target_i ? target_i : target_i + 1) :
       (child_i < target_i ? target_i - 1 : target_i);
+  port_->OnWillMoveChild(child_i, dest_i);
   children_.erase(children_.begin() + child_i);
   children_.insert(children_.begin() + dest_i, child);
 
@@ -1038,6 +1032,11 @@
 
 void Window::OnLayerBoundsChanged(const gfx::Rect& old_bounds) {
   bounds_ = layer()->bounds();
+
+  // Use |bounds_| as that is the bounds before any animations, which is what
+  // mus wants.
+  port_->OnDidChangeBounds(old_bounds, bounds_);
+
   if (layout_manager_)
     layout_manager_->OnWindowResized();
   if (delegate_)
diff --git a/ui/aura/window.h b/ui/aura/window.h
index f27c2be..2592c320 100644
--- a/ui/aura/window.h
+++ b/ui/aura/window.h
@@ -9,6 +9,7 @@
 
 #include <map>
 #include <memory>
+#include <set>
 #include <string>
 #include <vector>
 
@@ -50,6 +51,7 @@
 
 class LayoutManager;
 class WindowDelegate;
+class WindowPort;
 class WindowObserver;
 class WindowTreeHost;
 
@@ -85,6 +87,7 @@
   typedef std::vector<Window*> Windows;
 
   explicit Window(WindowDelegate* delegate);
+  Window(WindowDelegate* delegate, std::unique_ptr<WindowPort> port);
   ~Window() override;
 
   // Initializes the window. This creates the window's layer.
@@ -313,6 +316,9 @@
   template<typename T>
   void ClearProperty(const WindowProperty<T>* property);
 
+  // Returns the value of all properties with a non-default value.
+  std::set<const void*> GetAllPropertKeys() const;
+
   // NativeWidget::[GS]etNativeWindowProperty use strings as keys, and this is
   // difficult to change while retaining compatibility with other platforms.
   // TODO(benrg): Find a better solution.
@@ -340,10 +346,12 @@
   void RemoveOrDestroyChildren();
 
  private:
-  friend class test::WindowTestApi;
   friend class LayoutManager;
+  friend class WindowPort;
   friend class WindowTargeter;
   friend class subtle::PropertyHelper;
+  friend class test::WindowTestApi;
+
   // Called by the public {Set,Get,Clear}Property functions.
   int64_t SetPropertyInternal(const void* key,
                               const char* name,
@@ -460,6 +468,13 @@
   // Updates the layer name based on the window's name and id.
   void UpdateLayerName();
 
+  // Window owns its corresponding WindowPort, but the ref is held as a raw
+  // pointer in |port_| so that it can still be accessed during destruction.
+  // This is important as deleting the WindowPort may result in trying to lookup
+  // the WindowPort associated with the Window.
+  std::unique_ptr<WindowPort> port_owner_;
+  WindowPort* port_;
+
   // Bounds of this window relative to the parent. This is cached as the bounds
   // of the Layer and Window are not necessarily the same. In particular bounds
   // of the Layer are relative to the first ancestor with a Layer, where as this
diff --git a/ui/aura/window_port.cc b/ui/aura/window_port.cc
new file mode 100644
index 0000000..c774fbc
--- /dev/null
+++ b/ui/aura/window_port.cc
@@ -0,0 +1,22 @@
+// Copyright 2016 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 "ui/aura/window_port.h"
+
+#include "ui/aura/window.h"
+
+namespace aura {
+
+// static
+WindowPort* WindowPort::Get(Window* window) {
+  return window ? window->port_ : nullptr;
+}
+
+// static
+base::ObserverList<WindowObserver, true>* WindowPort::GetObservers(
+    Window* window) {
+  return &(window->observers_);
+}
+
+}  // namespace aura
diff --git a/ui/aura/window_port.h b/ui/aura/window_port.h
new file mode 100644
index 0000000..6f04399d
--- /dev/null
+++ b/ui/aura/window_port.h
@@ -0,0 +1,96 @@
+// Copyright 2016 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 UI_AURA_WINDOW_PORT_H_
+#define UI_AURA_WINDOW_PORT_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+
+#include "base/observer_list.h"
+#include "base/strings/string16.h"
+#include "ui/aura/aura_export.h"
+
+namespace gfx {
+class Rect;
+}
+
+namespace aura {
+
+class Window;
+class WindowObserver;
+
+// See comments in OnWillChangeProperty() for details.
+struct AURA_EXPORT WindowPortPropertyData {
+  virtual ~WindowPortPropertyData() {}
+};
+
+// See comments in Init() for details.
+struct AURA_EXPORT WindowPortInitData {
+  virtual ~WindowPortInitData() {}
+};
+
+// WindowPort defines an interface to enable Window to be used with or without
+// mus. WindowPort is owned by Window and called at key points in Windows
+// lifetime that enable Window to be used in both environments.
+//
+// If a Window is created without an explicit WindowPort then
+// Env::CreateWindowPort() is used to create the WindowPort.
+class AURA_EXPORT WindowPort {
+ public:
+  virtual ~WindowPort() {}
+
+  // Called from Window::Init(). The return value of this is supplied to
+  // OnInitDone() and is used to allow the WindowPort to pass data between the
+  // two functions.
+  virtual std::unique_ptr<WindowPortInitData> OnPreInit(Window* window) = 0;
+
+  virtual void OnPostInit(std::unique_ptr<WindowPortInitData> data) = 0;
+
+  virtual void OnDeviceScaleFactorChanged(float device_scale_factor) = 0;
+
+  // Called when a window is being added as a child. |child| may already have
+  // a parent, but its parent is not the Window this WindowPort is associated
+  // with.
+  virtual void OnWillAddChild(Window* child) = 0;
+
+  virtual void OnWillRemoveChild(Window* child) = 0;
+
+  // Called to move the child at |current_index| to |dest_index|. |dest_index|
+  // is calculated assuming the window at |current_index| has been removed, e.g.
+  //   Window* child = children_[current_index];
+  //   children_.erase(children_.begin() + current_index);
+  //   children_.insert(children_.begin() + dest_index, child);
+  virtual void OnWillMoveChild(size_t current_index, size_t dest_index) = 0;
+
+  virtual void OnVisibilityChanged(bool visible) = 0;
+
+  virtual void OnDidChangeBounds(const gfx::Rect& old_bounds,
+                                 const gfx::Rect& new_bounds) = 0;
+
+  // Called before a property is changed. The return value from this is supplied
+  // into OnPropertyChanged() so that WindowPort may pass data between the two
+  // calls.
+  virtual std::unique_ptr<WindowPortPropertyData> OnWillChangeProperty(
+      const void* key) = 0;
+
+  // Called after a property changes, but before observers are notified. |data|
+  // is the return value from OnWillChangeProperty().
+  virtual void OnPropertyChanged(
+      const void* key,
+      std::unique_ptr<WindowPortPropertyData> data) = 0;
+
+ protected:
+  // Returns the WindowPort associated with a Window.
+  static WindowPort* Get(Window* window);
+
+  // Returns the ObserverList of a Window.
+  static base::ObserverList<WindowObserver, true>* GetObservers(Window* window);
+};
+
+}  // namespace aura
+
+#endif  // UI_AURA_WINDOW_PORT_H_
diff --git a/ui/aura/window_port_local.cc b/ui/aura/window_port_local.cc
new file mode 100644
index 0000000..f1183014
--- /dev/null
+++ b/ui/aura/window_port_local.cc
@@ -0,0 +1,96 @@
+// Copyright 2016 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 "ui/aura/window_port_local.h"
+
+#include "ui/aura/client/cursor_client.h"
+#include "ui/aura/env.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_delegate.h"
+#include "ui/display/display.h"
+#include "ui/display/screen.h"
+
+namespace aura {
+namespace {
+
+class ScopedCursorHider {
+ public:
+  explicit ScopedCursorHider(Window* window)
+      : window_(window), hid_cursor_(false) {
+    if (!window_->IsRootWindow())
+      return;
+    const bool cursor_is_in_bounds = window_->GetBoundsInScreen().Contains(
+        Env::GetInstance()->last_mouse_location());
+    client::CursorClient* cursor_client = client::GetCursorClient(window_);
+    if (cursor_is_in_bounds && cursor_client &&
+        cursor_client->IsCursorVisible()) {
+      cursor_client->HideCursor();
+      hid_cursor_ = true;
+    }
+  }
+  ~ScopedCursorHider() {
+    if (!window_->IsRootWindow())
+      return;
+
+    // Update the device scale factor of the cursor client only when the last
+    // mouse location is on this root window.
+    if (hid_cursor_) {
+      client::CursorClient* cursor_client = client::GetCursorClient(window_);
+      if (cursor_client) {
+        const display::Display& display =
+            display::Screen::GetScreen()->GetDisplayNearestWindow(window_);
+        cursor_client->SetDisplay(display);
+        cursor_client->ShowCursor();
+      }
+    }
+  }
+
+ private:
+  Window* window_;
+  bool hid_cursor_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedCursorHider);
+};
+
+}  // namespace
+
+WindowPortLocal::WindowPortLocal(Window* window) : window_(window) {}
+
+WindowPortLocal::~WindowPortLocal() {}
+
+std::unique_ptr<WindowPortInitData> WindowPortLocal::OnPreInit(Window* window) {
+  return nullptr;
+}
+
+void WindowPortLocal::OnPostInit(
+    std::unique_ptr<WindowPortInitData> init_data) {}
+
+void WindowPortLocal::OnDeviceScaleFactorChanged(float device_scale_factor) {
+  ScopedCursorHider hider(window_);
+  if (window_->delegate())
+    window_->delegate()->OnDeviceScaleFactorChanged(device_scale_factor);
+}
+
+void WindowPortLocal::OnWillAddChild(Window* child) {}
+
+void WindowPortLocal::OnWillRemoveChild(Window* child) {}
+
+void WindowPortLocal::OnWillMoveChild(size_t current_index, size_t dest_index) {
+}
+
+void WindowPortLocal::OnVisibilityChanged(bool visible) {}
+
+void WindowPortLocal::OnDidChangeBounds(const gfx::Rect& old_bounds,
+                                        const gfx::Rect& new_bounds) {}
+
+std::unique_ptr<WindowPortPropertyData> WindowPortLocal::OnWillChangeProperty(
+    const void* key) {
+  return nullptr;
+}
+
+void WindowPortLocal::OnPropertyChanged(
+    const void* key,
+    std::unique_ptr<WindowPortPropertyData> data) {}
+
+}  // namespace aura
diff --git a/ui/aura/window_port_local.h b/ui/aura/window_port_local.h
new file mode 100644
index 0000000..edf5ce00
--- /dev/null
+++ b/ui/aura/window_port_local.h
@@ -0,0 +1,44 @@
+// Copyright 2016 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 UI_AURA_WINDOW_PORT_LOCAL_H_
+#define UI_AURA_WINDOW_PORT_LOCAL_H_
+
+#include "base/macros.h"
+#include "ui/aura/window_port.h"
+
+namespace aura {
+
+class Window;
+
+// WindowPort implementation for classic aura, e.g. not mus.
+class AURA_EXPORT WindowPortLocal : public WindowPort {
+ public:
+  explicit WindowPortLocal(Window* window);
+  ~WindowPortLocal() override;
+
+  // WindowPort:
+  std::unique_ptr<WindowPortInitData> OnPreInit(Window* window) override;
+  void OnPostInit(std::unique_ptr<WindowPortInitData> init_data) override;
+  void OnDeviceScaleFactorChanged(float device_scale_factor) override;
+  void OnWillAddChild(Window* child) override;
+  void OnWillRemoveChild(Window* child) override;
+  void OnWillMoveChild(size_t current_index, size_t dest_index) override;
+  void OnVisibilityChanged(bool visible) override;
+  void OnDidChangeBounds(const gfx::Rect& old_bounds,
+                         const gfx::Rect& new_bounds) override;
+  std::unique_ptr<WindowPortPropertyData> OnWillChangeProperty(
+      const void* key) override;
+  void OnPropertyChanged(const void* key,
+                         std::unique_ptr<WindowPortPropertyData> data) override;
+
+ private:
+  Window* window_;
+
+  DISALLOW_COPY_AND_ASSIGN(WindowPortLocal);
+};
+
+}  // namespace aura
+
+#endif  // UI_AURA_WINDOW_PORT_LOCAL_H_
diff --git a/ui/aura/window_property.h b/ui/aura/window_property.h
index 1f8a6353..b3774d6 100644
--- a/ui/aura/window_property.h
+++ b/ui/aura/window_property.h
@@ -19,7 +19,7 @@
 //
 //  DECLARE_EXPORTED_WINDOW_PROPERTY_TYPE(FOO_EXPORT, MyType);
 //  namespace foo {
-//    // Use this to define an exported property that is premitive,
+//    // Use this to define an exported property that is primitive,
 //    // or a pointer you don't want automatically deleted.
 //    DEFINE_WINDOW_PROPERTY_KEY(MyType, kMyKey, MyDefault);
 //
diff --git a/ui/aura/window_tree_host.cc b/ui/aura/window_tree_host.cc
index 2da90f8..ef62625 100644
--- a/ui/aura/window_tree_host.cc
+++ b/ui/aura/window_tree_host.cc
@@ -11,6 +11,7 @@
 #include "ui/aura/env.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_event_dispatcher.h"
+#include "ui/aura/window_port.h"
 #include "ui/aura/window_targeter.h"
 #include "ui/aura/window_tree_host_observer.h"
 #include "ui/base/ime/input_method.h"
@@ -218,12 +219,13 @@
 ////////////////////////////////////////////////////////////////////////////////
 // WindowTreeHost, protected:
 
-WindowTreeHost::WindowTreeHost()
-    : window_(new Window(nullptr)),
+WindowTreeHost::WindowTreeHost() : WindowTreeHost(nullptr) {}
+
+WindowTreeHost::WindowTreeHost(std::unique_ptr<WindowPort> window_port)
+    : window_(new Window(nullptr, std::move(window_port))),
       last_cursor_(ui::kCursorNull),
       input_method_(nullptr),
-      owned_input_method_(false) {
-}
+      owned_input_method_(false) {}
 
 void WindowTreeHost::DestroyCompositor() {
   compositor_.reset();
diff --git a/ui/aura/window_tree_host.h b/ui/aura/window_tree_host.h
index f31992c..fcbcbd8 100644
--- a/ui/aura/window_tree_host.h
+++ b/ui/aura/window_tree_host.h
@@ -5,6 +5,7 @@
 #ifndef UI_AURA_WINDOW_TREE_HOST_H_
 #define UI_AURA_WINDOW_TREE_HOST_H_
 
+#include <memory>
 #include <vector>
 
 #include "base/event_types.h"
@@ -39,6 +40,7 @@
 }
 
 class WindowEventDispatcher;
+class WindowPort;
 class WindowTreeHostObserver;
 
 // WindowTreeHost bridges between a native window and the embedded RootWindow.
@@ -184,6 +186,8 @@
   friend class TestScreen;  // TODO(beng): see if we can remove/consolidate.
 
   WindowTreeHost();
+  explicit WindowTreeHost(std::unique_ptr<WindowPort> window_port);
+
   void DestroyCompositor();
   void DestroyDispatcher();
 
diff --git a/ui/aura/window_tree_host_platform.cc b/ui/aura/window_tree_host_platform.cc
index 02bb8f7..6233739a 100644
--- a/ui/aura/window_tree_host_platform.cc
+++ b/ui/aura/window_tree_host_platform.cc
@@ -9,6 +9,7 @@
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
 #include "ui/aura/window_event_dispatcher.h"
+#include "ui/aura/window_port.h"
 #include "ui/compositor/compositor.h"
 #include "ui/display/display.h"
 #include "ui/display/screen.h"
@@ -52,7 +53,12 @@
 }
 
 WindowTreeHostPlatform::WindowTreeHostPlatform()
-    : widget_(gfx::kNullAcceleratedWidget),
+    : WindowTreeHostPlatform(nullptr) {}
+
+WindowTreeHostPlatform::WindowTreeHostPlatform(
+    std::unique_ptr<WindowPort> window_port)
+    : WindowTreeHost(std::move(window_port)),
+      widget_(gfx::kNullAcceleratedWidget),
       current_cursor_(ui::kCursorNull) {
   CreateCompositor();
 }
diff --git a/ui/aura/window_tree_host_platform.h b/ui/aura/window_tree_host_platform.h
index eb25d349..0ee8824 100644
--- a/ui/aura/window_tree_host_platform.h
+++ b/ui/aura/window_tree_host_platform.h
@@ -17,6 +17,8 @@
 
 namespace aura {
 
+class WindowPort;
+
 // The unified WindowTreeHost implementation for platforms
 // that implement PlatformWindow.
 class AURA_EXPORT WindowTreeHostPlatform
@@ -42,6 +44,8 @@
 
  protected:
   WindowTreeHostPlatform();
+  explicit WindowTreeHostPlatform(std::unique_ptr<WindowPort> window_port);
+
   void SetPlatformWindow(std::unique_ptr<ui::PlatformWindow> window);
   ui::PlatformWindow* platform_window() { return window_.get(); }