Add initial SHM-only Wayland Ozone implementation

This is just the bare minimum to get a window on the screen.

Things like cursor handling, input handling, and vsync provider will come in
subsequent commits.

BUG=578890

Review URL: https://codereview.chromium.org/1610683003

Cr-Commit-Position: refs/heads/master@{#372770}
diff --git a/build/common.gypi b/build/common.gypi
index d34e015..545eb24 100644
--- a/build/common.gypi
+++ b/build/common.gypi
@@ -1579,6 +1579,7 @@
     'ozone_platform_gbm%': 0,
     'ozone_platform_ozonex%': 0,
     'ozone_platform_headless%': 0,
+    'ozone_platform_wayland%': 0,
 
     # Experiment: http://crbug.com/426914
     'envoy%': 0,
diff --git a/media/ozone/media_ozone_platform.cc b/media/ozone/media_ozone_platform.cc
index f17d827..c1c4586 100644
--- a/media/ozone/media_ozone_platform.cc
+++ b/media/ozone/media_ozone_platform.cc
@@ -57,6 +57,10 @@
   return new MediaOzonePlatformStub;
 }
 
+MediaOzonePlatform* CreateMediaOzonePlatformWayland() {
+  return new MediaOzonePlatformStub;
+}
+
 MediaOzonePlatform::MediaOzonePlatform() {
   CHECK(!instance_) << "There should only be a single MediaOzonePlatform.";
   instance_ = this;
diff --git a/ui/ozone/BUILD.gn b/ui/ozone/BUILD.gn
index 27a25c5..9ef3103 100644
--- a/ui/ozone/BUILD.gn
+++ b/ui/ozone/BUILD.gn
@@ -43,6 +43,11 @@
   ozone_platform_deps += [ "platform/cast" ]
 }
 
+if (ozone_platform_wayland) {
+  ozone_platforms += [ "wayland" ]
+  ozone_platform_deps += [ "platform/wayland" ]
+}
+
 platform_list_cc_file = "$target_gen_dir/platform_list.cc"
 platform_list_h_file = "$target_gen_dir/platform_list.h"
 platform_list_txt_file = "$target_gen_dir/platform_list.txt"
diff --git a/ui/ozone/ozone.gni b/ui/ozone/ozone.gni
index 8b67fab..31e6dbf8 100644
--- a/ui/ozone/ozone.gni
+++ b/ui/ozone/ozone.gni
@@ -29,6 +29,7 @@
   ozone_platform_ozonex = false
   ozone_platform_headless = false
   ozone_platform_x11 = false
+  ozone_platform_wayland = false
 
   if (ozone_auto_platforms) {
     # Use headless as the default platform.
diff --git a/ui/ozone/ozone.gyp b/ui/ozone/ozone.gyp
index a878f8e..399a6b5 100644
--- a/ui/ozone/ozone.gyp
+++ b/ui/ozone/ozone.gyp
@@ -250,5 +250,10 @@
         'platform/headless/headless.gypi',
       ],
     }],
+    ['<(ozone_platform_wayland) == 1', {
+      'includes': [
+        'platform/wayland/wayland.gypi',
+      ],
+    }],
   ],
 }
diff --git a/ui/ozone/platform/wayland/BUILD.gn b/ui/ozone/platform/wayland/BUILD.gn
new file mode 100644
index 0000000..98c74a4
--- /dev/null
+++ b/ui/ozone/platform/wayland/BUILD.gn
@@ -0,0 +1,27 @@
+# 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.
+
+source_set("wayland") {
+  sources = [
+    "client_native_pixmap_factory_wayland.cc",
+    "client_native_pixmap_factory_wayland.h",
+    "ozone_platform_wayland.cc",
+    "ozone_platform_wayland.h",
+    "wayland_display.cc",
+    "wayland_display.h",
+    "wayland_object.h",
+    "wayland_surface_factory.cc",
+    "wayland_surface_factory.h",
+    "wayland_window.cc",
+    "wayland_window.h",
+  ]
+
+  deps = [
+    "//base",
+    "//skia",
+    "//third_party/wayland:wayland_client",
+    "//third_party/wayland-protocols:xdg_shell_protocol",
+    "//ui/ozone:ozone_base",
+  ]
+}
diff --git a/ui/ozone/platform/wayland/client_native_pixmap_factory_wayland.cc b/ui/ozone/platform/wayland/client_native_pixmap_factory_wayland.cc
new file mode 100644
index 0000000..eeea61b
--- /dev/null
+++ b/ui/ozone/platform/wayland/client_native_pixmap_factory_wayland.cc
@@ -0,0 +1,15 @@
+// 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/ozone/platform/wayland/client_native_pixmap_factory_wayland.h"
+
+#include "ui/ozone/common/stub_client_native_pixmap_factory.h"
+
+namespace ui {
+
+ClientNativePixmapFactory* CreateClientNativePixmapFactoryWayland() {
+  return CreateStubClientNativePixmapFactory();
+}
+
+}  // namespace ui
diff --git a/ui/ozone/platform/wayland/client_native_pixmap_factory_wayland.h b/ui/ozone/platform/wayland/client_native_pixmap_factory_wayland.h
new file mode 100644
index 0000000..4e0121a
--- /dev/null
+++ b/ui/ozone/platform/wayland/client_native_pixmap_factory_wayland.h
@@ -0,0 +1,17 @@
+// 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_OZONE_PLATFORM_WAYLAND_CLIENT_NATIVE_PIXMAP_FACTORY_WAYLAND_H_
+#define UI_OZONE_PLATFORM_WAYLAND_CLIENT_NATIVE_PIXMAP_FACTORY_WAYLAND_H_
+
+namespace ui {
+
+class ClientNativePixmapFactory;
+
+// Constructor hook for use in constructor_list.cc
+ClientNativePixmapFactory* CreateClientNativePixmapFactoryWayland();
+
+}  // namespace ui
+
+#endif  // UI_OZONE_PLATFORM_WAYLAND_CLIENT_NATIVE_PIXMAP_FACTORY_WAYLAND_H_
diff --git a/ui/ozone/platform/wayland/ozone_platform_wayland.cc b/ui/ozone/platform/wayland/ozone_platform_wayland.cc
new file mode 100644
index 0000000..9aa77f9
--- /dev/null
+++ b/ui/ozone/platform/wayland/ozone_platform_wayland.cc
@@ -0,0 +1,114 @@
+// 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/ozone/platform/wayland/ozone_platform_wayland.h"
+
+#include "ui/ozone/common/native_display_delegate_ozone.h"
+#include "ui/ozone/common/stub_overlay_manager.h"
+#include "ui/ozone/platform/wayland/wayland_display.h"
+#include "ui/ozone/platform/wayland/wayland_surface_factory.h"
+#include "ui/ozone/platform/wayland/wayland_window.h"
+#include "ui/ozone/public/cursor_factory_ozone.h"
+#include "ui/ozone/public/gpu_platform_support.h"
+#include "ui/ozone/public/gpu_platform_support_host.h"
+#include "ui/ozone/public/input_controller.h"
+#include "ui/ozone/public/ozone_platform.h"  // nogncheck
+#include "ui/ozone/public/system_input_injector.h"
+
+namespace ui {
+
+namespace {
+
+class OzonePlatformWayland : public OzonePlatform {
+ public:
+  OzonePlatformWayland() {}
+  ~OzonePlatformWayland() override {}
+
+  // OzonePlatform
+  SurfaceFactoryOzone* GetSurfaceFactoryOzone() override {
+    return surface_factory_.get();
+  }
+
+  OverlayManagerOzone* GetOverlayManager() override {
+    return overlay_manager_.get();
+  }
+
+  CursorFactoryOzone* GetCursorFactoryOzone() override {
+    return cursor_factory_.get();
+  }
+
+  InputController* GetInputController() override {
+    return input_controller_.get();
+  }
+
+  GpuPlatformSupport* GetGpuPlatformSupport() override {
+    return gpu_platform_support_.get();
+  }
+
+  GpuPlatformSupportHost* GetGpuPlatformSupportHost() override {
+    return gpu_platform_support_host_.get();
+  }
+
+  scoped_ptr<SystemInputInjector> CreateSystemInputInjector() override {
+    return nullptr;
+  }
+
+  scoped_ptr<PlatformWindow> CreatePlatformWindow(
+      PlatformWindowDelegate* delegate,
+      const gfx::Rect& bounds) override {
+    auto window =
+        make_scoped_ptr(new WaylandWindow(delegate, display_.get(), bounds));
+    if (!window->Initialize())
+      return nullptr;
+    return std::move(window);
+  }
+
+  scoped_ptr<NativeDisplayDelegate> CreateNativeDisplayDelegate() override {
+    return make_scoped_ptr(new NativeDisplayDelegateOzone);
+  }
+
+  base::ScopedFD OpenClientNativePixmapDevice() const override {
+    NOTIMPLEMENTED();
+    return base::ScopedFD();
+  }
+
+  void InitializeUI() override {
+    display_.reset(new WaylandDisplay);
+    if (!display_->Initialize())
+      LOG(FATAL) << "Failed to initialize Wayland platform";
+
+    cursor_factory_.reset(new CursorFactoryOzone);
+    overlay_manager_.reset(new StubOverlayManager);
+    input_controller_ = CreateStubInputController();
+    surface_factory_.reset(new WaylandSurfaceFactory(display_.get()));
+    gpu_platform_support_host_.reset(CreateStubGpuPlatformSupportHost());
+  }
+
+  void InitializeGPU() override {
+    // Don't reinitialize the surface factory in case InitializeUI was called
+    // previously in the same process.
+    if (!surface_factory_)
+      surface_factory_.reset(new WaylandSurfaceFactory(nullptr));
+    gpu_platform_support_.reset(CreateStubGpuPlatformSupport());
+  }
+
+ private:
+  scoped_ptr<WaylandDisplay> display_;
+  scoped_ptr<WaylandSurfaceFactory> surface_factory_;
+  scoped_ptr<CursorFactoryOzone> cursor_factory_;
+  scoped_ptr<StubOverlayManager> overlay_manager_;
+  scoped_ptr<InputController> input_controller_;
+  scoped_ptr<GpuPlatformSupportHost> gpu_platform_support_host_;
+  scoped_ptr<GpuPlatformSupport> gpu_platform_support_;
+
+  DISALLOW_COPY_AND_ASSIGN(OzonePlatformWayland);
+};
+
+}  // namespace
+
+OzonePlatform* CreateOzonePlatformWayland() {
+  return new OzonePlatformWayland;
+}
+
+}  // namespace ui
diff --git a/ui/ozone/platform/wayland/ozone_platform_wayland.h b/ui/ozone/platform/wayland/ozone_platform_wayland.h
new file mode 100644
index 0000000..2eb802c
--- /dev/null
+++ b/ui/ozone/platform/wayland/ozone_platform_wayland.h
@@ -0,0 +1,17 @@
+// 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_OZONE_PLATFORM_DRM_OZONE_PLATFORM_WAYLAND_H_
+#define UI_OZONE_PLATFORM_DRM_OZONE_PLATFORM_WAYLAND_H_
+
+namespace ui {
+
+class OzonePlatform;
+
+// Constructor hook for use in ozone_platform_list.cc
+OzonePlatform* CreateOzonePlatformWayland();
+
+}  // namespace ui
+
+#endif  // UI_OZONE_PLATFORM_DRM_OZONE_PLATFORM_WAYLAND_H_
diff --git a/ui/ozone/platform/wayland/wayland.gypi b/ui/ozone/platform/wayland/wayland.gypi
new file mode 100644
index 0000000..cd4bb85
--- /dev/null
+++ b/ui/ozone/platform/wayland/wayland.gypi
@@ -0,0 +1,43 @@
+# 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.
+
+{
+  'variables': {
+    'internal_ozone_platform_deps': [
+      'ozone_platform_wayland',
+    ],
+    'internal_ozone_platforms': [
+      'wayland'
+    ],
+  },
+  'targets': [
+    {
+      'target_name': 'ozone_platform_wayland',
+      'type': 'static_library',
+      'defines': [
+        'OZONE_IMPLEMENTATION',
+      ],
+      'dependencies': [
+        '../../base/base.gyp:base',
+        '../../skia/skia.gyp:skia',
+        '../../third_party/wayland-protocols/wayland-protocols.gyp:xdg_shell_protocol',
+        '../../third_party/wayland/wayland.gyp:wayland_client',
+        '../events/platform/events_platform.gyp:events_platform',
+      ],
+      'sources': [
+        "client_native_pixmap_factory_wayland.cc",
+        "client_native_pixmap_factory_wayland.h",
+        "ozone_platform_wayland.cc",
+        "ozone_platform_wayland.h",
+        "wayland_display.cc",
+        "wayland_display.h",
+        "wayland_object.h",
+        "wayland_surface_factory.cc",
+        "wayland_surface_factory.h",
+        "wayland_window.cc",
+        "wayland_window.h",
+      ],
+    },
+  ],
+}
diff --git a/ui/ozone/platform/wayland/wayland_display.cc b/ui/ozone/platform/wayland/wayland_display.cc
new file mode 100644
index 0000000..488754a
--- /dev/null
+++ b/ui/ozone/platform/wayland/wayland_display.cc
@@ -0,0 +1,137 @@
+// 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/ozone/platform/wayland/wayland_display.h"
+
+#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+#include "ui/ozone/platform/wayland/wayland_object.h"
+#include "ui/ozone/platform/wayland/wayland_window.h"
+
+static_assert(XDG_SHELL_VERSION_CURRENT == 5, "Unsupported xdg-shell version");
+
+namespace ui {
+
+WaylandDisplay::WaylandDisplay() {}
+
+WaylandDisplay::~WaylandDisplay() {}
+
+bool WaylandDisplay::Initialize() {
+  static const wl_registry_listener registry_listener = {
+      &WaylandDisplay::Global, &WaylandDisplay::GlobalRemove,
+  };
+
+  display_.reset(wl_display_connect(nullptr));
+  if (!display_) {
+    LOG(ERROR) << "Failed to connect to Wayland display";
+    return false;
+  }
+
+  registry_.reset(wl_display_get_registry(display_.get()));
+  if (!registry_) {
+    LOG(ERROR) << "Failed to get Wayland registry";
+    return false;
+  }
+
+  wl_registry_add_listener(registry_.get(), &registry_listener, this);
+  wl_display_roundtrip(display_.get());
+
+  if (!compositor_) {
+    LOG(ERROR) << "No wl_compositor object";
+    return false;
+  }
+  if (!shm_) {
+    LOG(ERROR) << "No wl_shm object";
+    return false;
+  }
+  if (!shell_) {
+    LOG(ERROR) << "No xdg_shell object";
+    return false;
+  }
+
+  return true;
+}
+
+void WaylandDisplay::Flush() {
+  DCHECK(display_);
+  wl_display_flush(display_.get());
+}
+
+WaylandWindow* WaylandDisplay::GetWindow(gfx::AcceleratedWidget widget) {
+  auto it = window_map_.find(widget);
+  return it == window_map_.end() ? nullptr : it->second;
+}
+
+void WaylandDisplay::AddWindow(WaylandWindow* window) {
+  window_map_[window->GetWidget()] = window;
+}
+
+void WaylandDisplay::RemoveWindow(WaylandWindow* window) {
+  window_map_.erase(window->GetWidget());
+}
+
+void WaylandDisplay::OnDispatcherListChanged() {
+  if (watching_)
+    return;
+
+  DCHECK(display_);
+  DCHECK(base::MessageLoopForUI::IsCurrent());
+  base::MessageLoopForUI::current()->WatchFileDescriptor(
+      wl_display_get_fd(display_.get()), true,
+      base::MessagePumpLibevent::WATCH_READ, &controller_, this);
+  watching_ = true;
+}
+
+void WaylandDisplay::OnFileCanReadWithoutBlocking(int fd) {
+  wl_display_dispatch(display_.get());
+  for (const auto& window : window_map_)
+    window.second->ApplyPendingBounds();
+}
+
+void WaylandDisplay::OnFileCanWriteWithoutBlocking(int fd) {}
+
+// static
+void WaylandDisplay::Global(void* data,
+                            wl_registry* registry,
+                            uint32_t name,
+                            const char* interface,
+                            uint32_t version) {
+  static const xdg_shell_listener shell_listener = {
+      &WaylandDisplay::Ping,
+  };
+
+  WaylandDisplay* display = static_cast<WaylandDisplay*>(data);
+  if (!display->compositor_ && strcmp(interface, "wl_compositor") == 0) {
+    display->compositor_ = wl::Bind<wl_compositor>(registry, name, version);
+    if (!display->compositor_)
+      LOG(ERROR) << "Failed to bind to wl_compositor global";
+  } else if (!display->shm_ && strcmp(interface, "wl_shm") == 0) {
+    display->shm_ = wl::Bind<wl_shm>(registry, name, version);
+    if (!display->shm_)
+      LOG(ERROR) << "Failed to bind to wl_shm global";
+  } else if (!display->shell_ && strcmp(interface, "xdg_shell") == 0) {
+    display->shell_ = wl::Bind<xdg_shell>(registry, name, version);
+    if (!display->shell_) {
+      LOG(ERROR) << "Failed to  bind to xdg_shell global";
+      return;
+    }
+    xdg_shell_add_listener(display->shell_.get(), &shell_listener, display);
+    xdg_shell_use_unstable_version(display->shell_.get(),
+                                   XDG_SHELL_VERSION_CURRENT);
+  }
+}
+
+// static
+void WaylandDisplay::GlobalRemove(void* data,
+                                  wl_registry* registry,
+                                  uint32_t name) {
+  NOTIMPLEMENTED();
+}
+
+// static
+void WaylandDisplay::Ping(void* data, xdg_shell* shell, uint32_t serial) {
+  xdg_shell_pong(shell, serial);
+}
+
+}  // namespace ui
diff --git a/ui/ozone/platform/wayland/wayland_display.h b/ui/ozone/platform/wayland/wayland_display.h
new file mode 100644
index 0000000..99b1366
--- /dev/null
+++ b/ui/ozone/platform/wayland/wayland_display.h
@@ -0,0 +1,73 @@
+// 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_OZONE_PLATFORM_WAYLAND_WAYLAND_DISPLAY_H_
+#define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_DISPLAY_H_
+
+#include <map>
+
+#include "base/message_loop/message_pump_libevent.h"
+#include "ui/events/platform/platform_event_source.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/ozone/platform/wayland/wayland_object.h"
+
+namespace ui {
+
+class WaylandWindow;
+
+class WaylandDisplay : public PlatformEventSource,
+                       public base::MessagePumpLibevent::Watcher {
+ public:
+  WaylandDisplay();
+  ~WaylandDisplay() override;
+
+  bool Initialize();
+
+  // Flushes the Wayland connection.
+  void Flush();
+
+  wl_compositor* compositor() { return compositor_.get(); }
+  wl_shm* shm() { return shm_.get(); }
+  xdg_shell* shell() { return shell_.get(); }
+
+  WaylandWindow* GetWindow(gfx::AcceleratedWidget widget);
+  void AddWindow(WaylandWindow* window);
+  void RemoveWindow(WaylandWindow* window);
+
+ private:
+  // PlatformEventSource
+  void OnDispatcherListChanged() override;
+
+  // base::MessagePumpLibevent::Watcher
+  void OnFileCanReadWithoutBlocking(int fd) override;
+  void OnFileCanWriteWithoutBlocking(int fd) override;
+
+  // wl_registry_listener
+  static void Global(void* data,
+                     wl_registry* registry,
+                     uint32_t name,
+                     const char* interface,
+                     uint32_t version);
+  static void GlobalRemove(void* data, wl_registry* registry, uint32_t name);
+
+  // xdg_shell_listener
+  static void Ping(void* data, xdg_shell* shell, uint32_t serial);
+
+  std::map<gfx::AcceleratedWidget, WaylandWindow*> window_map_;
+
+  wl::Object<wl_display> display_;
+  wl::Object<wl_registry> registry_;
+  wl::Object<wl_compositor> compositor_;
+  wl::Object<wl_shm> shm_;
+  wl::Object<xdg_shell> shell_;
+
+  bool watching_ = false;
+  base::MessagePumpLibevent::FileDescriptorWatcher controller_;
+
+  DISALLOW_COPY_AND_ASSIGN(WaylandDisplay);
+};
+
+}  // namespace ui
+
+#endif  // UI_OZONE_PLATFORM_WAYLAND_WAYLAND_DISPLAY_H_
diff --git a/ui/ozone/platform/wayland/wayland_object.h b/ui/ozone/platform/wayland/wayland_object.h
new file mode 100644
index 0000000..99196539
--- /dev/null
+++ b/ui/ozone/platform/wayland/wayland_object.h
@@ -0,0 +1,99 @@
+// 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_OZONE_PLATFORM_WAYLAND_WAYLAND_OBJECT_H_
+#define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_OBJECT_H_
+
+#include <wayland-client.h>
+#include <xdg-shell-unstable-v5-client-protocol.h>
+
+#include "base/memory/scoped_ptr.h"
+
+namespace wl {
+
+template <typename T>
+struct ObjectTraits;
+
+template <>
+struct ObjectTraits<wl_buffer> {
+  static constexpr const wl_interface* interface = &wl_buffer_interface;
+  static constexpr void (*deleter)(wl_buffer*) = &wl_buffer_destroy;
+};
+
+template <>
+struct ObjectTraits<wl_compositor> {
+  static constexpr const wl_interface* interface = &wl_compositor_interface;
+  static constexpr void (*deleter)(wl_compositor*) = &wl_compositor_destroy;
+};
+
+template <>
+struct ObjectTraits<wl_display> {
+  static constexpr const wl_interface* interface = &wl_display_interface;
+  static constexpr void (*deleter)(wl_display*) = &wl_display_disconnect;
+};
+
+template <>
+struct ObjectTraits<wl_registry> {
+  static constexpr const wl_interface* interface = &wl_registry_interface;
+  static constexpr void (*deleter)(wl_registry*) = &wl_registry_destroy;
+};
+
+template <>
+struct ObjectTraits<wl_shm> {
+  static constexpr const wl_interface* interface = &wl_shm_interface;
+  static constexpr void (*deleter)(wl_shm*) = &wl_shm_destroy;
+};
+
+template <>
+struct ObjectTraits<wl_shm_pool> {
+  static constexpr const wl_interface* interface = &wl_shm_pool_interface;
+  static constexpr void (*deleter)(wl_shm_pool*) = &wl_shm_pool_destroy;
+};
+
+template <>
+struct ObjectTraits<wl_surface> {
+  static constexpr const wl_interface* interface = &wl_surface_interface;
+  static constexpr void (*deleter)(wl_surface*) = &wl_surface_destroy;
+};
+
+template <>
+struct ObjectTraits<xdg_shell> {
+  static constexpr const wl_interface* interface = &xdg_shell_interface;
+  static constexpr void (*deleter)(xdg_shell*) = &xdg_shell_destroy;
+};
+
+template <>
+struct ObjectTraits<xdg_surface> {
+  static constexpr const wl_interface* interface = &xdg_surface_interface;
+  static constexpr void (*deleter)(xdg_surface*) = &xdg_surface_destroy;
+};
+
+struct Deleter {
+  template <typename T>
+  void operator()(T* obj) {
+    ObjectTraits<T>::deleter(obj);
+  }
+};
+
+template <typename T>
+class Object : public scoped_ptr<T, Deleter> {
+ public:
+  Object() {}
+  explicit Object(T* obj) : scoped_ptr<T, Deleter>(obj) {}
+
+  uint32_t id() {
+    return wl_proxy_get_id(
+        reinterpret_cast<wl_proxy*>(scoped_ptr<T, Deleter>::get()));
+  }
+};
+
+template <typename T>
+wl::Object<T> Bind(wl_registry* registry, uint32_t name, uint32_t version) {
+  return wl::Object<T>(static_cast<T*>(
+      wl_registry_bind(registry, name, ObjectTraits<T>::interface, version)));
+}
+
+}  // namespace wl
+
+#endif  // UI_OZONE_PLATFORM_WAYLAND_WAYLAND_OBJECT_H_
diff --git a/ui/ozone/platform/wayland/wayland_surface_factory.cc b/ui/ozone/platform/wayland/wayland_surface_factory.cc
new file mode 100644
index 0000000..faeba1d
--- /dev/null
+++ b/ui/ozone/platform/wayland/wayland_surface_factory.cc
@@ -0,0 +1,173 @@
+// 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/ozone/platform/wayland/wayland_surface_factory.h"
+
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#include "base/memory/shared_memory.h"
+#include "third_party/skia/include/core/SkSurface.h"
+#include "ui/gfx/vsync_provider.h"
+#include "ui/ozone/platform/wayland/wayland_display.h"
+#include "ui/ozone/platform/wayland/wayland_object.h"
+#include "ui/ozone/platform/wayland/wayland_window.h"
+#include "ui/ozone/public/surface_ozone_canvas.h"
+#include "ui/ozone/public/surface_ozone_egl.h"
+
+namespace ui {
+
+static void DeleteSharedMemory(void* pixels, void* context) {
+  delete static_cast<base::SharedMemory*>(context);
+}
+
+class WaylandCanvasSurface : public SurfaceOzoneCanvas {
+ public:
+  WaylandCanvasSurface(WaylandDisplay* display, WaylandWindow* window_);
+  ~WaylandCanvasSurface() override;
+
+  // SurfaceOzoneCanvas
+  skia::RefPtr<SkSurface> GetSurface() override;
+  void ResizeCanvas(const gfx::Size& viewport_size) override;
+  void PresentCanvas(const gfx::Rect& damage) override;
+  scoped_ptr<gfx::VSyncProvider> CreateVSyncProvider() override;
+
+ private:
+  WaylandDisplay* display_;
+  WaylandWindow* window_;
+
+  gfx::Size size_;
+  skia::RefPtr<SkSurface> sk_surface_;
+  wl::Object<wl_shm_pool> pool_;
+  wl::Object<wl_buffer> buffer_;
+
+  DISALLOW_COPY_AND_ASSIGN(WaylandCanvasSurface);
+};
+
+WaylandCanvasSurface::WaylandCanvasSurface(WaylandDisplay* display,
+                                           WaylandWindow* window)
+    : display_(display), window_(window) {}
+
+WaylandCanvasSurface::~WaylandCanvasSurface() {}
+
+skia::RefPtr<SkSurface> WaylandCanvasSurface::GetSurface() {
+  if (sk_surface_)
+    return sk_surface_;
+
+  size_t length = size_.width() * size_.height() * 4;
+  auto shared_memory = make_scoped_ptr(new base::SharedMemory);
+  if (!shared_memory->CreateAndMapAnonymous(length))
+    return nullptr;
+
+  wl::Object<wl_shm_pool> pool(
+      wl_shm_create_pool(display_->shm(), shared_memory->handle().fd, length));
+  if (!pool)
+    return nullptr;
+  wl::Object<wl_buffer> buffer(
+      wl_shm_pool_create_buffer(pool.get(), 0, size_.width(), size_.height(),
+                                size_.width() * 4, WL_SHM_FORMAT_ARGB8888));
+  if (!buffer)
+    return nullptr;
+
+  sk_surface_ = skia::AdoptRef(SkSurface::NewRasterDirectReleaseProc(
+      SkImageInfo::MakeN32Premul(size_.width(), size_.height()),
+      shared_memory->memory(), size_.width() * 4, &DeleteSharedMemory,
+      shared_memory.get(), nullptr));
+  if (!sk_surface_)
+    return nullptr;
+  pool_ = std::move(pool);
+  buffer_ = std::move(buffer);
+  (void)shared_memory.release();
+  return sk_surface_;
+}
+
+void WaylandCanvasSurface::ResizeCanvas(const gfx::Size& viewport_size) {
+  if (size_ == viewport_size)
+    return;
+  // TODO(forney): We could implement more efficient resizes by allocating
+  // buffers rounded up to larger sizes, and then reusing them if the new size
+  // still fits (but still reallocate if the new size is much smaller than the
+  // old size).
+  if (sk_surface_) {
+    sk_surface_.clear();
+    buffer_.reset();
+    pool_.reset();
+  }
+  size_ = viewport_size;
+}
+
+void WaylandCanvasSurface::PresentCanvas(const gfx::Rect& damage) {
+  // TODO(forney): This is just a naive implementation that allows chromium to
+  // draw to the buffer at any time, even if it is being used by the Wayland
+  // compositor. Instead, we should track buffer releases and frame callbacks
+  // from Wayland to ensure perfect frames (while minimizing copies).
+  wl_surface* surface = window_->GetSurface();
+  wl_surface_damage(surface, damage.x(), damage.y(), damage.width(),
+                    damage.height());
+  wl_surface_attach(surface, buffer_.get(), 0, 0);
+  wl_surface_commit(surface);
+  display_->Flush();
+}
+
+scoped_ptr<gfx::VSyncProvider> WaylandCanvasSurface::CreateVSyncProvider() {
+  // TODO(forney): This can be implemented with information from frame
+  // callbacks, and possibly output refresh rate.
+  NOTIMPLEMENTED();
+  return nullptr;
+}
+
+WaylandSurfaceFactory::WaylandSurfaceFactory(WaylandDisplay* display)
+    : display_(display) {}
+
+WaylandSurfaceFactory::~WaylandSurfaceFactory() {}
+
+intptr_t WaylandSurfaceFactory::GetNativeDisplay() {
+  NOTIMPLEMENTED();
+  return 0;
+}
+
+const int32_t* WaylandSurfaceFactory::GetEGLSurfaceProperties(
+    const int32_t* desired_list) {
+  NOTIMPLEMENTED();
+  return nullptr;
+}
+
+bool WaylandSurfaceFactory::LoadEGLGLES2Bindings(
+    AddGLLibraryCallback add_gl_library,
+    SetGLGetProcAddressProcCallback set_gl_get_proc_address) {
+  // This Ozone implementation does not support multi-process rendering so
+  // disable EGL unconditionally for now.
+  return false;
+}
+
+scoped_ptr<SurfaceOzoneCanvas> WaylandSurfaceFactory::CreateCanvasForWidget(
+    gfx::AcceleratedWidget widget) {
+  DCHECK(display_);
+  WaylandWindow* window = display_->GetWindow(widget);
+  DCHECK(window);
+  return make_scoped_ptr(new WaylandCanvasSurface(display_, window));
+}
+
+scoped_ptr<SurfaceOzoneEGL> WaylandSurfaceFactory::CreateEGLSurfaceForWidget(
+    gfx::AcceleratedWidget widget) {
+  NOTREACHED();
+  return nullptr;
+}
+
+scoped_refptr<NativePixmap> WaylandSurfaceFactory::CreateNativePixmap(
+    gfx::AcceleratedWidget widget,
+    gfx::Size size,
+    gfx::BufferFormat format,
+    gfx::BufferUsage usage) {
+  NOTIMPLEMENTED();
+  return nullptr;
+}
+
+scoped_refptr<NativePixmap> WaylandSurfaceFactory::CreateNativePixmapFromHandle(
+    const gfx::NativePixmapHandle& handle) {
+  NOTIMPLEMENTED();
+  return nullptr;
+}
+
+}  // namespace ui
diff --git a/ui/ozone/platform/wayland/wayland_surface_factory.h b/ui/ozone/platform/wayland/wayland_surface_factory.h
new file mode 100644
index 0000000..0d27a42
--- /dev/null
+++ b/ui/ozone/platform/wayland/wayland_surface_factory.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_OZONE_PLATFORM_WAYLAND_WAYLAND_SURFACE_FACTORY_H_
+#define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_SURFACE_FACTORY_H_
+
+#include "ui/ozone/public/surface_factory_ozone.h"
+
+namespace ui {
+
+class WaylandDisplay;
+
+class WaylandSurfaceFactory : public SurfaceFactoryOzone {
+ public:
+  WaylandSurfaceFactory(WaylandDisplay* display);
+  ~WaylandSurfaceFactory() override;
+
+  intptr_t GetNativeDisplay() override;
+  const int32_t* GetEGLSurfaceProperties(const int32_t* desired_list) override;
+  bool LoadEGLGLES2Bindings(
+      AddGLLibraryCallback add_gl_library,
+      SetGLGetProcAddressProcCallback set_gl_get_proc_address) override;
+  scoped_ptr<SurfaceOzoneCanvas> CreateCanvasForWidget(
+      gfx::AcceleratedWidget widget) override;
+  scoped_ptr<SurfaceOzoneEGL> CreateEGLSurfaceForWidget(
+      gfx::AcceleratedWidget w) override;
+  scoped_refptr<NativePixmap> CreateNativePixmap(
+      gfx::AcceleratedWidget widget,
+      gfx::Size size,
+      gfx::BufferFormat format,
+      gfx::BufferUsage usage) override;
+  scoped_refptr<NativePixmap> CreateNativePixmapFromHandle(
+      const gfx::NativePixmapHandle& handle) override;
+
+ private:
+  WaylandDisplay* display_;
+
+  DISALLOW_COPY_AND_ASSIGN(WaylandSurfaceFactory);
+};
+
+}  // namespace ui
+
+#endif  // UI_OZONE_PLATFORM_WAYLAND_WAYLAND_SURFACE_FACTORY_H_
diff --git a/ui/ozone/platform/wayland/wayland_window.cc b/ui/ozone/platform/wayland/wayland_window.cc
new file mode 100644
index 0000000..b0c02d7
--- /dev/null
+++ b/ui/ozone/platform/wayland/wayland_window.cc
@@ -0,0 +1,159 @@
+// 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/ozone/platform/wayland/wayland_window.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "ui/ozone/platform/wayland/wayland_display.h"
+#include "ui/platform_window/platform_window_delegate.h"
+
+namespace ui {
+
+WaylandWindow::WaylandWindow(PlatformWindowDelegate* delegate,
+                             WaylandDisplay* display,
+                             const gfx::Rect& bounds)
+    : delegate_(delegate), display_(display), bounds_(bounds) {}
+
+WaylandWindow::~WaylandWindow() {
+  if (xdg_surface_) {
+    display_->RemoveWindow(this);
+  }
+}
+
+bool WaylandWindow::Initialize() {
+  static const xdg_surface_listener xdg_surface_listener = {
+      &WaylandWindow::Configure, &WaylandWindow::Close,
+  };
+
+  surface_.reset(wl_compositor_create_surface(display_->compositor()));
+  if (!surface_) {
+    LOG(ERROR) << "Failed to create wl_surface";
+    return false;
+  }
+  wl_surface_set_user_data(surface_.get(), this);
+  xdg_surface_.reset(
+      xdg_shell_get_xdg_surface(display_->shell(), surface_.get()));
+  if (!xdg_surface_) {
+    LOG(ERROR) << "Failed to create xdg_surface";
+    return false;
+  }
+  xdg_surface_add_listener(xdg_surface_.get(), &xdg_surface_listener, this);
+
+  display_->AddWindow(this);
+  delegate_->OnAcceleratedWidgetAvailable(surface_.id(), 1.f);
+
+  return true;
+}
+
+wl_surface* WaylandWindow::GetSurface() {
+  DCHECK(surface_);
+  return surface_.get();
+}
+
+gfx::AcceleratedWidget WaylandWindow::GetWidget() {
+  DCHECK(surface_);
+  return surface_.id();
+}
+
+void WaylandWindow::ApplyPendingBounds() {
+  if (pending_bounds_.IsEmpty())
+    return;
+
+  SetBounds(pending_bounds_);
+  DCHECK(xdg_surface_);
+  xdg_surface_ack_configure(xdg_surface_.get(), pending_configure_serial_);
+  pending_bounds_ = gfx::Rect();
+}
+
+void WaylandWindow::Show() {}
+
+void WaylandWindow::Hide() {
+  NOTIMPLEMENTED();
+}
+
+void WaylandWindow::Close() {
+  NOTIMPLEMENTED();
+}
+
+void WaylandWindow::SetBounds(const gfx::Rect& bounds) {
+  if (bounds == bounds_)
+    return;
+  bounds_ = bounds;
+  delegate_->OnBoundsChanged(bounds);
+}
+
+gfx::Rect WaylandWindow::GetBounds() {
+  return bounds_;
+}
+
+void WaylandWindow::SetTitle(const base::string16& title) {
+  DCHECK(xdg_surface_);
+  xdg_surface_set_title(xdg_surface_.get(), UTF16ToUTF8(title).c_str());
+}
+
+void WaylandWindow::SetCapture() {
+  NOTIMPLEMENTED();
+}
+
+void WaylandWindow::ReleaseCapture() {
+  NOTIMPLEMENTED();
+}
+
+void WaylandWindow::ToggleFullscreen() {
+  NOTIMPLEMENTED();
+}
+
+void WaylandWindow::Maximize() {
+  DCHECK(xdg_surface_);
+  xdg_surface_set_maximized(xdg_surface_.get());
+}
+
+void WaylandWindow::Minimize() {
+  DCHECK(xdg_surface_);
+  xdg_surface_set_minimized(xdg_surface_.get());
+}
+
+void WaylandWindow::Restore() {
+  DCHECK(xdg_surface_);
+  xdg_surface_unset_maximized(xdg_surface_.get());
+}
+
+void WaylandWindow::SetCursor(PlatformCursor cursor) {
+  NOTIMPLEMENTED();
+}
+
+void WaylandWindow::MoveCursorTo(const gfx::Point& location) {
+  NOTIMPLEMENTED();
+}
+
+void WaylandWindow::ConfineCursorToBounds(const gfx::Rect& bounds) {
+  NOTIMPLEMENTED();
+}
+
+PlatformImeController* WaylandWindow::GetPlatformImeController() {
+  NOTIMPLEMENTED();
+  return nullptr;
+}
+
+void WaylandWindow::Configure(void* data,
+                              xdg_surface* obj,
+                              int32_t width,
+                              int32_t height,
+                              wl_array* states,
+                              uint32_t serial) {
+  WaylandWindow* window = static_cast<WaylandWindow*>(data);
+
+  // Rather than call SetBounds here for every configure event, just save the
+  // most recent bounds, and have WaylandDisplay call ApplyPendingBounds when it
+  // has finished processing events. We may get many configure events in a row
+  // during an interactive resize, and only the last one matters.
+  window->pending_bounds_ = gfx::Rect(0, 0, width, height);
+  window->pending_configure_serial_ = serial;
+}
+
+void WaylandWindow::Close(void* data, xdg_surface* obj) {
+  NOTIMPLEMENTED();
+}
+
+}  // namespace ui
diff --git a/ui/ozone/platform/wayland/wayland_window.h b/ui/ozone/platform/wayland/wayland_window.h
new file mode 100644
index 0000000..8b8d5a2
--- /dev/null
+++ b/ui/ozone/platform/wayland/wayland_window.h
@@ -0,0 +1,76 @@
+// 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_OZONE_PLATFORM_WAYLAND_WAYLAND_WINDOW_H_
+#define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_WINDOW_H_
+
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/ozone/platform/wayland/wayland_object.h"
+#include "ui/platform_window/platform_window.h"
+
+namespace ui {
+
+class WaylandDisplay;
+
+class WaylandWindow : public PlatformWindow {
+ public:
+  WaylandWindow(PlatformWindowDelegate* delegate,
+                WaylandDisplay* display,
+                const gfx::Rect& bounds);
+  ~WaylandWindow() override;
+
+  bool Initialize();
+
+  wl_surface* GetSurface();
+  gfx::AcceleratedWidget GetWidget();
+
+  // Apply the bounds specified in the most recent configure event. This should
+  // be called after processing all pending events in the wayland connection.
+  void ApplyPendingBounds();
+
+  // PlatformWindow
+  void Show() override;
+  void Hide() override;
+  void Close() override;
+  void SetBounds(const gfx::Rect& bounds) override;
+  gfx::Rect GetBounds() override;
+  void SetTitle(const base::string16& title) override;
+  void SetCapture() override;
+  void ReleaseCapture() override;
+  void ToggleFullscreen() override;
+  void Maximize() override;
+  void Minimize() override;
+  void Restore() override;
+  void SetCursor(PlatformCursor cursor) override;
+  void MoveCursorTo(const gfx::Point& location) override;
+  void ConfineCursorToBounds(const gfx::Rect& bounds) override;
+  PlatformImeController* GetPlatformImeController() override;
+
+  // xdg_surface_listener
+  static void Configure(void* data,
+                        xdg_surface* obj,
+                        int32_t width,
+                        int32_t height,
+                        wl_array* states,
+                        uint32_t serial);
+  static void Close(void* data, xdg_surface* obj);
+
+ private:
+  PlatformWindowDelegate* delegate_;
+  WaylandDisplay* display_;
+
+  wl::Object<wl_surface> surface_;
+  wl::Object<xdg_surface> xdg_surface_;
+
+  gfx::Rect bounds_;
+  gfx::Rect pending_bounds_;
+  uint32_t pending_configure_serial_;
+
+  DISALLOW_COPY_AND_ASSIGN(WaylandWindow);
+};
+
+}  // namespace ui
+
+#endif  // UI_OZONE_PLATFORM_WAYLAND_WAYLAND_WINDOW_H_