Clone of chromium aad1ce808763f59c7a3753e08f1500a104ecc6fd refs/remotes/origin/HEAD
diff --git a/mojo/services/native_viewport/BUILD.gn b/mojo/services/native_viewport/BUILD.gn
new file mode 100644
index 0000000..036e8e9
--- /dev/null
+++ b/mojo/services/native_viewport/BUILD.gn
@@ -0,0 +1,84 @@
+# Copyright 2014 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("//build/config/ui.gni")
+
+if (!is_android) {
+  shared_library("native_viewport") {
+    output_name = "mojo_native_viewport_service"
+
+    deps = [
+      ":lib",
+      "//base",
+      "//mojo/application",
+      "//mojo/public/c/system:for_shared_library",
+      "//mojo/public/cpp/bindings:bindings",
+      "//mojo/services/public/interfaces/native_viewport",
+      "//ui/gl",
+    ]
+
+    sources = [ "main.cc" ]
+  }
+}
+
+source_set("lib") {
+  deps = [
+    "//base",
+    "//cc/surfaces",
+    "//gpu/command_buffer/service",
+    "//mojo/application",
+    "//mojo/common",
+    "//mojo/environment:chromium",
+    "//mojo/services/gles2",
+    "//mojo/services/gles2:interfaces",
+    "//mojo/services/public/cpp/geometry",
+    "//mojo/services/public/cpp/input_events",
+    "//mojo/services/public/cpp/surfaces",
+    "//mojo/services/public/interfaces/geometry",
+    "//mojo/services/public/interfaces/native_viewport",
+    "//mojo/services/public/interfaces/surfaces",
+    "//ui/events",
+    "//ui/events/platform",
+    "//ui/gfx",
+    "//ui/gfx/geometry",
+    "//ui/gl",
+    "//ui/platform_window",
+  ]
+
+  sources = [
+    "gpu_impl.cc",
+    "gpu_impl.h",
+    "native_viewport_impl.cc",
+    "native_viewport_impl.h",
+    "platform_viewport.h",
+    "platform_viewport_android.cc",
+    "platform_viewport_android.h",
+    "platform_viewport_mac.mm",
+    "platform_viewport_headless.cc",
+    "platform_viewport_headless.h",
+    "platform_viewport_win.cc",
+    "viewport_surface.cc",
+    "viewport_surface.h",
+  ]
+
+  if (is_ios) {
+    sources += [ "platform_viewport_stub.cc" ]
+  }
+
+  if (is_android) {
+    deps += [ "//mojo:jni_headers" ]
+  }
+
+  if (use_x11) {
+    sources += [ "platform_viewport_x11.cc" ]
+    deps += [
+      "//ui/events/platform/x11",
+      "//ui/platform_window/x11",
+    ]
+  }
+
+  if (use_ozone) {
+    sources += [ "platform_viewport_ozone.cc" ]
+  }
+}
diff --git a/mojo/services/native_viewport/DEPS b/mojo/services/native_viewport/DEPS
new file mode 100644
index 0000000..abf7ef8
--- /dev/null
+++ b/mojo/services/native_viewport/DEPS
@@ -0,0 +1,18 @@
+include_rules = [
+  "+cc/surfaces",
+  "+gpu/command_buffer/service/mailbox_manager.h",
+  "+mojo/application",
+  "+mojo/services/public/cpp/geometry",
+  "+mojo/services/public/cpp/input_events",
+  "+mojo/services/public/cpp/surfaces",
+  "+mojo/services/public/interfaces/gpu",
+  "+mojo/services/public/interfaces/native_viewport",
+  "+mojo/services/public/interfaces/geometry",
+  "+mojo/services/public/interfaces/surfaces",
+  "+mojo/services/gles2",
+  "+ui/events",
+  "+ui/gfx",
+  "+ui/gl",
+  "+ui/ozone/public",
+  "+ui/platform_window",
+]
diff --git a/mojo/services/native_viewport/android/src/org/chromium/mojo/PlatformViewportAndroid.java b/mojo/services/native_viewport/android/src/org/chromium/mojo/PlatformViewportAndroid.java
new file mode 100644
index 0000000..c3f8075
--- /dev/null
+++ b/mojo/services/native_viewport/android/src/org/chromium/mojo/PlatformViewportAndroid.java
@@ -0,0 +1,91 @@
+// Copyright 2013 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.
+
+package org.chromium.mojo;
+
+import android.app.Activity;
+import android.content.Context;
+import android.view.MotionEvent;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+
+import org.chromium.base.CalledByNative;
+import org.chromium.base.JNINamespace;
+
+/**
+ * Exposes SurfaceView to native code.
+ */
+@JNINamespace("mojo")
+public class PlatformViewportAndroid extends SurfaceView {
+
+    private long mNativeMojoViewport;
+    private final SurfaceHolder.Callback mSurfaceCallback;
+
+    @SuppressWarnings("unused")
+    @CalledByNative
+    public static void createForActivity(Activity activity, long nativeViewport) {
+        activity.setContentView(new PlatformViewportAndroid(activity, nativeViewport));
+    }
+
+    public PlatformViewportAndroid(Context context, long nativeViewport) {
+        super(context);
+
+        mNativeMojoViewport = nativeViewport;
+        assert mNativeMojoViewport != 0;
+
+        mSurfaceCallback = new SurfaceHolder.Callback() {
+            @Override
+            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+                assert mNativeMojoViewport != 0;
+                nativeSurfaceSetSize(mNativeMojoViewport, width, height);
+            }
+
+            @Override
+            public void surfaceCreated(SurfaceHolder holder) {
+                assert mNativeMojoViewport != 0;
+                nativeSurfaceCreated(mNativeMojoViewport, holder.getSurface());
+            }
+
+            @Override
+            public void surfaceDestroyed(SurfaceHolder holder) {
+                assert mNativeMojoViewport != 0;
+                nativeSurfaceDestroyed(mNativeMojoViewport);
+            }
+        };
+        getHolder().addCallback(mSurfaceCallback);
+
+    }
+
+    // TODO(abarth): Someone needs to call destroy at some point.
+    public void destroy() {
+        getHolder().removeCallback(mSurfaceCallback);
+        nativeDestroy(mNativeMojoViewport);
+        mNativeMojoViewport = 0;
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        return nativeTouchEvent(mNativeMojoViewport,
+                                event.getPointerId(0),
+                                event.getAction(),
+                                event.getX(), event.getY(),
+                                event.getEventTime());
+    }
+
+    private static native void nativeDestroy(long nativePlatformViewportAndroid);
+    private static native void nativeSurfaceCreated(
+        long nativePlatformViewportAndroid, Surface surface);
+    private static native void nativeSurfaceDestroyed(
+        long nativePlatformViewportAndroid);
+    private static native void nativeSurfaceSetSize(
+        long nativePlatformViewportAndroid,
+        int width, int height);
+    private static native boolean nativeTouchEvent(
+        long nativePlatformViewportAndroid,
+        int pointerId,
+        int action,
+        float x, float y,
+        long timeMs);
+};
diff --git a/mojo/services/native_viewport/gpu_impl.cc b/mojo/services/native_viewport/gpu_impl.cc
new file mode 100644
index 0000000..de0b69e
--- /dev/null
+++ b/mojo/services/native_viewport/gpu_impl.cc
@@ -0,0 +1,43 @@
+// Copyright 2014 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/services/native_viewport/gpu_impl.h"
+
+#include "gpu/command_buffer/service/mailbox_manager.h"
+#include "mojo/services/gles2/command_buffer_impl.h"
+#include "mojo/services/public/cpp/geometry/geometry_type_converters.h"
+#include "ui/gl/gl_share_group.h"
+
+namespace mojo {
+
+GpuImpl::GpuImpl(
+    const scoped_refptr<gfx::GLShareGroup>& share_group,
+    const scoped_refptr<gpu::gles2::MailboxManager> mailbox_manager)
+    : share_group_(share_group), mailbox_manager_(mailbox_manager) {
+}
+
+GpuImpl::~GpuImpl() {
+}
+
+void GpuImpl::CreateOnscreenGLES2Context(
+    uint64_t native_viewport_id,
+    SizePtr size,
+    InterfaceRequest<CommandBuffer> command_buffer_request) {
+  gfx::AcceleratedWidget widget = bit_cast<gfx::AcceleratedWidget>(
+      static_cast<uintptr_t>(native_viewport_id));
+  BindToRequest(new CommandBufferImpl(widget,
+                                      size.To<gfx::Size>(),
+                                      share_group_.get(),
+                                      mailbox_manager_.get()),
+                &command_buffer_request);
+}
+
+void GpuImpl::CreateOffscreenGLES2Context(
+    InterfaceRequest<CommandBuffer> command_buffer_request) {
+  BindToRequest(
+      new CommandBufferImpl(share_group_.get(), mailbox_manager_.get()),
+      &command_buffer_request);
+}
+
+}  // namespace mojo
diff --git a/mojo/services/native_viewport/gpu_impl.h b/mojo/services/native_viewport/gpu_impl.h
new file mode 100644
index 0000000..ac0f435
--- /dev/null
+++ b/mojo/services/native_viewport/gpu_impl.h
@@ -0,0 +1,49 @@
+// Copyright 2014 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/macros.h"
+#include "base/memory/ref_counted.h"
+#include "mojo/public/cpp/bindings/interface_impl.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "mojo/services/gles2/command_buffer.mojom.h"
+#include "mojo/services/public/interfaces/geometry/geometry.mojom.h"
+#include "mojo/services/public/interfaces/gpu/gpu.mojom.h"
+
+namespace gfx {
+class GLShareGroup;
+}
+
+namespace gpu {
+namespace gles2 {
+class MailboxManager;
+}
+}
+
+namespace mojo {
+
+class GpuImpl : public InterfaceImpl<Gpu> {
+ public:
+  GpuImpl(const scoped_refptr<gfx::GLShareGroup>& share_group,
+          const scoped_refptr<gpu::gles2::MailboxManager> mailbox_manager);
+
+  virtual ~GpuImpl();
+
+  virtual void CreateOnscreenGLES2Context(
+      uint64_t native_viewport_id,
+      SizePtr size,
+      InterfaceRequest<CommandBuffer> command_buffer_request) override;
+
+  virtual void CreateOffscreenGLES2Context(
+      InterfaceRequest<CommandBuffer> command_buffer_request) override;
+
+ private:
+  // We need to share these across all NativeViewport instances so that contexts
+  // they create can share resources with each other via mailboxes.
+  scoped_refptr<gfx::GLShareGroup> share_group_;
+  scoped_refptr<gpu::gles2::MailboxManager> mailbox_manager_;
+
+  DISALLOW_COPY_AND_ASSIGN(GpuImpl);
+};
+
+}  // namespace mojo
diff --git a/mojo/services/native_viewport/main.cc b/mojo/services/native_viewport/main.cc
new file mode 100644
index 0000000..0185e67
--- /dev/null
+++ b/mojo/services/native_viewport/main.cc
@@ -0,0 +1,111 @@
+// Copyright 2014 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/macros.h"
+#include "base/message_loop/message_loop.h"
+#include "gpu/command_buffer/service/mailbox_manager.h"
+#include "mojo/application/application_runner_chromium.h"
+#include "mojo/public/c/system/main.h"
+#include "mojo/public/cpp/application/application_connection.h"
+#include "mojo/public/cpp/application/application_delegate.h"
+#include "mojo/public/cpp/application/interface_factory_impl.h"
+#include "mojo/services/native_viewport/gpu_impl.h"
+#include "mojo/services/native_viewport/native_viewport_impl.h"
+#include "ui/gl/gl_share_group.h"
+#include "ui/gl/gl_surface.h"
+
+namespace mojo {
+
+class NativeViewportAppDelegate
+    : public ApplicationDelegate,
+      public InterfaceFactory<NativeViewport>,
+      public InterfaceFactory<Gpu>,
+      public InterfaceFactory<NativeViewportConfig> {
+ public:
+  NativeViewportAppDelegate()
+      : share_group_(new gfx::GLShareGroup),
+        mailbox_manager_(new gpu::gles2::MailboxManager),
+        is_test_(false),
+        is_headless_(false),
+        is_initialized_(false) {}
+  virtual ~NativeViewportAppDelegate() {}
+
+ private:
+  class NativeViewportConfigImpl : public InterfaceImpl<NativeViewportConfig> {
+   public:
+    NativeViewportConfigImpl(NativeViewportAppDelegate* app_delegate)
+      : app_delegate_(app_delegate) {}
+
+    virtual void UseTestConfig(
+        const Callback<void()>& callback) override {
+      app_delegate_->is_test_ = true;
+      callback.Run();
+    }
+
+    virtual void UseHeadlessConfig(
+        const Callback<void()>& callback) override {
+      app_delegate_->is_headless_ = true;
+      callback.Run();
+    }
+
+   private:
+    NativeViewportAppDelegate* app_delegate_;
+  };
+
+  // ApplicationDelegate implementation.
+  virtual void Initialize(ApplicationImpl* application) override {
+    app_ = application;
+  }
+
+  virtual bool ConfigureIncomingConnection(
+      mojo::ApplicationConnection* connection) override {
+    connection->AddService<NativeViewport>(this);
+    connection->AddService<Gpu>(this);
+    connection->AddService<NativeViewportConfig>(this);
+    return true;
+  }
+
+  // InterfaceFactory<NativeViewport> implementation.
+  virtual void Create(ApplicationConnection* connection,
+                      InterfaceRequest<NativeViewport> request) override {
+#if !defined(COMPONENT_BUILD)
+    if (!is_initialized_) {
+      if (is_test_)
+        gfx::GLSurface::InitializeOneOffForTests();
+      else
+        gfx::GLSurface::InitializeOneOff();
+      is_initialized_ = true;
+    }
+#endif
+    BindToRequest(new NativeViewportImpl(app_, is_headless_), &request);
+  }
+
+  // InterfaceFactory<Gpu> implementation.
+  virtual void Create(ApplicationConnection* connection,
+                      InterfaceRequest<Gpu> request) override {
+    BindToRequest(new GpuImpl(share_group_.get(), mailbox_manager_.get()),
+                  &request);
+  }
+
+  // InterfaceFactory<NVTestConfig> implementation.
+  virtual void Create(ApplicationConnection* connection,
+                      InterfaceRequest<NativeViewportConfig> request) override {
+    BindToRequest(new NativeViewportConfigImpl(this), &request);
+  }
+
+  ApplicationImpl* app_;
+  scoped_refptr<gfx::GLShareGroup> share_group_;
+  scoped_refptr<gpu::gles2::MailboxManager> mailbox_manager_;
+  bool is_test_;
+  bool is_headless_;
+  bool is_initialized_;
+  DISALLOW_COPY_AND_ASSIGN(NativeViewportAppDelegate);
+};
+}
+
+MojoResult MojoMain(MojoHandle shell_handle) {
+  mojo::ApplicationRunnerChromium runner(new mojo::NativeViewportAppDelegate);
+  runner.set_message_loop_type(base::MessageLoop::TYPE_UI);
+  return runner.Run(shell_handle);
+}
diff --git a/mojo/services/native_viewport/native_viewport_impl.cc b/mojo/services/native_viewport/native_viewport_impl.cc
new file mode 100644
index 0000000..3006612
--- /dev/null
+++ b/mojo/services/native_viewport/native_viewport_impl.cc
@@ -0,0 +1,160 @@
+// Copyright 2014 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/services/native_viewport/native_viewport_impl.h"
+
+#include "base/auto_reset.h"
+#include "base/bind.h"
+#include "base/macros.h"
+#include "base/message_loop/message_loop.h"
+#include "base/time/time.h"
+#include "mojo/public/cpp/application/application_delegate.h"
+#include "mojo/public/cpp/application/application_impl.h"
+#include "mojo/public/cpp/application/interface_factory.h"
+#include "mojo/services/native_viewport/platform_viewport_headless.h"
+#include "mojo/services/native_viewport/viewport_surface.h"
+#include "mojo/services/public/cpp/geometry/geometry_type_converters.h"
+#include "mojo/services/public/cpp/input_events/input_events_type_converters.h"
+#include "mojo/services/public/cpp/surfaces/surfaces_type_converters.h"
+#include "ui/events/event.h"
+
+namespace mojo {
+namespace {
+
+bool IsRateLimitedEventType(ui::Event* event) {
+  return event->type() == ui::ET_MOUSE_MOVED ||
+         event->type() == ui::ET_MOUSE_DRAGGED ||
+         event->type() == ui::ET_TOUCH_MOVED;
+}
+
+}  // namespace
+
+NativeViewportImpl::NativeViewportImpl(ApplicationImpl* app, bool is_headless)
+    : is_headless_(is_headless),
+      widget_id_(0u),
+      waiting_for_event_ack_(false),
+      weak_factory_(this) {
+  app->ConnectToService("mojo:mojo_surfaces_service", &surfaces_service_);
+  // TODO(jamesr): Should be mojo_gpu_service
+  app->ConnectToService("mojo:mojo_native_viewport_service", &gpu_service_);
+}
+
+NativeViewportImpl::~NativeViewportImpl() {
+  // Destroy the NativeViewport early on as it may call us back during
+  // destruction and we want to be in a known state.
+  platform_viewport_.reset();
+}
+
+void NativeViewportImpl::Create(SizePtr size,
+                                const Callback<void(uint64_t)>& callback) {
+  create_callback_ = callback;
+  size_ = size.To<gfx::Size>();
+  if (is_headless_)
+    platform_viewport_ = PlatformViewportHeadless::Create(this);
+  else
+    platform_viewport_ = PlatformViewport::Create(this);
+  platform_viewport_->Init(gfx::Rect(size.To<gfx::Size>()));
+}
+
+void NativeViewportImpl::Show() {
+  platform_viewport_->Show();
+}
+
+void NativeViewportImpl::Hide() {
+  platform_viewport_->Hide();
+}
+
+void NativeViewportImpl::Close() {
+  DCHECK(platform_viewport_);
+  platform_viewport_->Close();
+}
+
+void NativeViewportImpl::SetSize(SizePtr size) {
+  platform_viewport_->SetBounds(gfx::Rect(size.To<gfx::Size>()));
+}
+
+void NativeViewportImpl::SubmittedFrame(SurfaceIdPtr child_surface_id) {
+  if (child_surface_id_.is_null()) {
+    // If this is the first indication that the client will use surfaces,
+    // initialize that system.
+    // TODO(jamesr): When everything is converted to surfaces initialize this
+    // eagerly.
+    viewport_surface_.reset(
+        new ViewportSurface(surfaces_service_.get(),
+                            gpu_service_.get(),
+                            size_,
+                            child_surface_id.To<cc::SurfaceId>()));
+    if (widget_id_)
+      viewport_surface_->SetWidgetId(widget_id_);
+  }
+  child_surface_id_ = child_surface_id.To<cc::SurfaceId>();
+  if (viewport_surface_)
+    viewport_surface_->SetChildId(child_surface_id_);
+}
+
+void NativeViewportImpl::OnBoundsChanged(const gfx::Rect& bounds) {
+  if (size_ == bounds.size())
+    return;
+
+  size_ = bounds.size();
+
+  // Wait for the accelerated widget before telling the client of the bounds.
+  if (create_callback_.is_null())
+    ProcessOnBoundsChanged();
+}
+
+void NativeViewportImpl::OnAcceleratedWidgetAvailable(
+    gfx::AcceleratedWidget widget) {
+  widget_id_ = static_cast<uint64_t>(bit_cast<uintptr_t>(widget));
+  // TODO(jamesr): Remove once everything is converted to surfaces.
+  create_callback_.Run(widget_id_);
+  create_callback_.reset();
+  // Immediately tell the client of the size. The size may be wrong, if so we'll
+  // get the right one in the next OnBoundsChanged() call.
+  ProcessOnBoundsChanged();
+  if (viewport_surface_)
+    viewport_surface_->SetWidgetId(widget_id_);
+}
+
+bool NativeViewportImpl::OnEvent(ui::Event* ui_event) {
+  // Must not return early before updating capture.
+  switch (ui_event->type()) {
+    case ui::ET_MOUSE_PRESSED:
+    case ui::ET_TOUCH_PRESSED:
+      platform_viewport_->SetCapture();
+      break;
+    case ui::ET_MOUSE_RELEASED:
+    case ui::ET_TOUCH_RELEASED:
+      platform_viewport_->ReleaseCapture();
+      break;
+    default:
+      break;
+  }
+
+  if (waiting_for_event_ack_ && IsRateLimitedEventType(ui_event))
+    return false;
+
+  client()->OnEvent(
+      Event::From(*ui_event),
+      base::Bind(&NativeViewportImpl::AckEvent, weak_factory_.GetWeakPtr()));
+  waiting_for_event_ack_ = true;
+  return false;
+}
+
+void NativeViewportImpl::OnDestroyed() {
+  client()->OnDestroyed();
+}
+
+void NativeViewportImpl::AckEvent() {
+  waiting_for_event_ack_ = false;
+}
+
+void NativeViewportImpl::ProcessOnBoundsChanged() {
+  client()->OnSizeChanged(Size::From(size_));
+  if (viewport_surface_)
+    viewport_surface_->SetSize(size_);
+}
+
+}  // namespace mojo
+
diff --git a/mojo/services/native_viewport/native_viewport_impl.h b/mojo/services/native_viewport/native_viewport_impl.h
new file mode 100644
index 0000000..03918cb
--- /dev/null
+++ b/mojo/services/native_viewport/native_viewport_impl.h
@@ -0,0 +1,69 @@
+// Copyright 2014 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 MOJO_SERVICES_NATIVE_VIEWPORT_IMPL_H_
+#define MOJO_SERVICES_NATIVE_VIEWPORT_IMPL_H_
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "cc/surfaces/surface_id.h"
+#include "mojo/services/native_viewport/platform_viewport.h"
+#include "mojo/services/public/interfaces/gpu/gpu.mojom.h"
+#include "mojo/services/public/interfaces/native_viewport/native_viewport.mojom.h"
+#include "mojo/services/public/interfaces/surfaces/surfaces_service.mojom.h"
+#include "ui/gfx/geometry/rect.h"
+
+namespace ui {
+class Event;
+}
+
+namespace mojo {
+class ApplicationImpl;
+class ViewportSurface;
+
+class NativeViewportImpl : public InterfaceImpl<NativeViewport>,
+                           public PlatformViewport::Delegate {
+ public:
+  NativeViewportImpl(ApplicationImpl* app, bool is_headless);
+  virtual ~NativeViewportImpl();
+
+  // InterfaceImpl<NativeViewport> implementation.
+  virtual void Create(SizePtr size,
+                      const Callback<void(uint64_t)>& callback) override;
+  virtual void Show() override;
+  virtual void Hide() override;
+  virtual void Close() override;
+  virtual void SetSize(SizePtr size) override;
+  virtual void SubmittedFrame(SurfaceIdPtr surface_id) override;
+
+  // PlatformViewport::Delegate implementation.
+  virtual void OnBoundsChanged(const gfx::Rect& bounds) override;
+  virtual void OnAcceleratedWidgetAvailable(
+      gfx::AcceleratedWidget widget) override;
+  virtual bool OnEvent(ui::Event* ui_event) override;
+  virtual void OnDestroyed() override;
+
+  void AckEvent();
+
+ private:
+  void ProcessOnBoundsChanged();
+
+  bool is_headless_;
+  scoped_ptr<PlatformViewport> platform_viewport_;
+  scoped_ptr<ViewportSurface> viewport_surface_;
+  uint64_t widget_id_;
+  gfx::Size size_;
+  GpuPtr gpu_service_;
+  SurfacesServicePtr surfaces_service_;
+  cc::SurfaceId child_surface_id_;
+  bool waiting_for_event_ack_;
+  Callback<void(uint64_t)> create_callback_;
+  base::WeakPtrFactory<NativeViewportImpl> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(NativeViewportImpl);
+};
+
+}  // namespace mojo
+
+#endif  // MOJO_SERVICES_NATIVE_VIEWPORT_IMPL_H_
diff --git a/mojo/services/native_viewport/platform_viewport.h b/mojo/services/native_viewport/platform_viewport.h
new file mode 100644
index 0000000..a3ba3dc
--- /dev/null
+++ b/mojo/services/native_viewport/platform_viewport.h
@@ -0,0 +1,53 @@
+// Copyright 2013 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 MOJO_SERVICES_NATIVE_VIEWPORT_PLATFORM_VIEWPORT_H_
+#define MOJO_SERVICES_NATIVE_VIEWPORT_PLATFORM_VIEWPORT_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/gfx/size.h"
+
+namespace gfx {
+class Rect;
+}
+
+namespace ui {
+class Event;
+}
+
+namespace mojo {
+
+// Encapsulation of platform-specific Viewport.
+class PlatformViewport {
+ public:
+  class Delegate {
+   public:
+    virtual ~Delegate() {}
+
+    virtual void OnBoundsChanged(const gfx::Rect& rect) = 0;
+    virtual void OnAcceleratedWidgetAvailable(
+        gfx::AcceleratedWidget widget) = 0;
+    virtual bool OnEvent(ui::Event* ui_event) = 0;
+    virtual void OnDestroyed() = 0;
+  };
+
+  virtual ~PlatformViewport() {}
+
+  virtual void Init(const gfx::Rect& bounds) = 0;
+  virtual void Show() = 0;
+  virtual void Hide() = 0;
+  virtual void Close() = 0;
+  virtual gfx::Size GetSize() = 0;
+  virtual void SetBounds(const gfx::Rect& bounds) = 0;
+
+  virtual void SetCapture() = 0;
+  virtual void ReleaseCapture() = 0;
+
+  static scoped_ptr<PlatformViewport> Create(Delegate* delegate);
+};
+
+}  // namespace mojo
+
+#endif  // MOJO_SERVICES_NATIVE_VIEWPORT_PLATFORM_VIEWPORT_H_
diff --git a/mojo/services/native_viewport/platform_viewport_android.cc b/mojo/services/native_viewport/platform_viewport_android.cc
new file mode 100644
index 0000000..bbe22c9
--- /dev/null
+++ b/mojo/services/native_viewport/platform_viewport_android.cc
@@ -0,0 +1,156 @@
+// Copyright 2013 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/services/native_viewport/platform_viewport_android.h"
+
+#include <android/input.h>
+#include <android/native_window_jni.h>
+
+#include "base/android/jni_android.h"
+#include "jni/PlatformViewportAndroid_jni.h"
+#include "ui/events/event.h"
+#include "ui/gfx/point.h"
+
+namespace mojo {
+
+ui::EventType MotionEventActionToEventType(jint action) {
+  switch (action) {
+    case AMOTION_EVENT_ACTION_DOWN:
+      return ui::ET_TOUCH_PRESSED;
+    case AMOTION_EVENT_ACTION_MOVE:
+      return ui::ET_TOUCH_MOVED;
+    case AMOTION_EVENT_ACTION_UP:
+      return ui::ET_TOUCH_RELEASED;
+    default:
+      NOTREACHED();
+  }
+  return ui::ET_UNKNOWN;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// PlatformViewportAndroid, public:
+
+// static
+bool PlatformViewportAndroid::Register(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+PlatformViewportAndroid::PlatformViewportAndroid(Delegate* delegate)
+    : delegate_(delegate),
+      window_(NULL),
+      id_generator_(0),
+      weak_factory_(this) {
+}
+
+PlatformViewportAndroid::~PlatformViewportAndroid() {
+  if (window_)
+    ReleaseWindow();
+}
+
+void PlatformViewportAndroid::Destroy(JNIEnv* env, jobject obj) {
+  delegate_->OnDestroyed();
+}
+
+void PlatformViewportAndroid::SurfaceCreated(JNIEnv* env,
+                                             jobject obj,
+                                             jobject jsurface) {
+  base::android::ScopedJavaLocalRef<jobject> protector(env, jsurface);
+  // Note: This ensures that any local references used by
+  // ANativeWindow_fromSurface are released immediately. This is needed as a
+  // workaround for https://code.google.com/p/android/issues/detail?id=68174
+  {
+    base::android::ScopedJavaLocalFrame scoped_local_reference_frame(env);
+    window_ = ANativeWindow_fromSurface(env, jsurface);
+  }
+  delegate_->OnAcceleratedWidgetAvailable(window_);
+}
+
+void PlatformViewportAndroid::SurfaceDestroyed(JNIEnv* env, jobject obj) {
+  DCHECK(window_);
+  ReleaseWindow();
+}
+
+void PlatformViewportAndroid::SurfaceSetSize(JNIEnv* env, jobject obj,
+                                             jint width, jint height) {
+  bounds_ = gfx::Rect(width, height);
+  delegate_->OnBoundsChanged(bounds_);
+}
+
+bool PlatformViewportAndroid::TouchEvent(JNIEnv* env, jobject obj,
+                                         jint pointer_id,
+                                         jint action,
+                                         jfloat x, jfloat y,
+                                         jlong time_ms) {
+  gfx::Point location(static_cast<int>(x), static_cast<int>(y));
+  ui::TouchEvent event(MotionEventActionToEventType(action), location,
+                       id_generator_.GetGeneratedID(pointer_id),
+                       base::TimeDelta::FromMilliseconds(time_ms));
+  // TODO(beng): handle multiple touch-points.
+  delegate_->OnEvent(&event);
+  if (action == ui::ET_TOUCH_RELEASED)
+    id_generator_.ReleaseNumber(pointer_id);
+
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// PlatformViewportAndroid, PlatformViewport implementation:
+
+void PlatformViewportAndroid::Init(const gfx::Rect& bounds) {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  Java_PlatformViewportAndroid_createForActivity(
+      env,
+      base::android::GetApplicationContext(),
+      reinterpret_cast<jlong>(this));
+}
+
+void PlatformViewportAndroid::Show() {
+  // Nothing to do. View is created visible.
+}
+
+void PlatformViewportAndroid::Hide() {
+  // Nothing to do. View is always visible.
+}
+
+void PlatformViewportAndroid::Close() {
+  // TODO(beng): close activity containing MojoView?
+
+  // TODO(beng): perform this in response to view destruction.
+  delegate_->OnDestroyed();
+}
+
+gfx::Size PlatformViewportAndroid::GetSize() {
+  return bounds_.size();
+}
+
+void PlatformViewportAndroid::SetBounds(const gfx::Rect& bounds) {
+  NOTIMPLEMENTED();
+}
+
+void PlatformViewportAndroid::SetCapture() {
+  NOTIMPLEMENTED();
+}
+
+void PlatformViewportAndroid::ReleaseCapture() {
+  NOTIMPLEMENTED();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// PlatformViewportAndroid, private:
+
+void PlatformViewportAndroid::ReleaseWindow() {
+  ANativeWindow_release(window_);
+  window_ = NULL;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// PlatformViewport, public:
+
+// static
+scoped_ptr<PlatformViewport> PlatformViewport::Create(Delegate* delegate) {
+  return scoped_ptr<PlatformViewport>(
+      new PlatformViewportAndroid(delegate)).Pass();
+}
+
+}  // namespace mojo
diff --git a/mojo/services/native_viewport/platform_viewport_android.h b/mojo/services/native_viewport/platform_viewport_android.h
new file mode 100644
index 0000000..31b0312
--- /dev/null
+++ b/mojo/services/native_viewport/platform_viewport_android.h
@@ -0,0 +1,66 @@
+// Copyright 2013 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 MOJO_SERVICES_NATIVE_VIEWPORT_PLATFORM_VIEWPORT_ANDROID_H_
+#define MOJO_SERVICES_NATIVE_VIEWPORT_PLATFORM_VIEWPORT_ANDROID_H_
+
+#include "base/android/jni_weak_ref.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "mojo/services/native_viewport/platform_viewport.h"
+#include "ui/events/event_constants.h"
+#include "ui/gfx/rect.h"
+#include "ui/gfx/sequential_id_generator.h"
+#include "ui/gfx/size.h"
+
+namespace gpu {
+class GLInProcessContext;
+}
+
+struct ANativeWindow;
+
+namespace mojo {
+
+class PlatformViewportAndroid : public PlatformViewport {
+ public:
+  static bool Register(JNIEnv* env);
+
+  explicit PlatformViewportAndroid(Delegate* delegate);
+  virtual ~PlatformViewportAndroid();
+
+  void Destroy(JNIEnv* env, jobject obj);
+  void SurfaceCreated(JNIEnv* env, jobject obj, jobject jsurface);
+  void SurfaceDestroyed(JNIEnv* env, jobject obj);
+  void SurfaceSetSize(JNIEnv* env, jobject obj, jint width, jint height);
+  bool TouchEvent(JNIEnv* env, jobject obj, jint pointer_id, jint action,
+                  jfloat x, jfloat y, jlong time_ms);
+
+ private:
+  // Overridden from PlatformViewport:
+  virtual void Init(const gfx::Rect& bounds) override;
+  virtual void Show() override;
+  virtual void Hide() override;
+  virtual void Close() override;
+  virtual gfx::Size GetSize() override;
+  virtual void SetBounds(const gfx::Rect& bounds) override;
+  virtual void SetCapture() override;
+  virtual void ReleaseCapture() override;
+
+  void ReleaseWindow();
+
+  Delegate* delegate_;
+  ANativeWindow* window_;
+  gfx::Rect bounds_;
+  ui::SequentialIDGenerator id_generator_;
+
+  base::WeakPtrFactory<PlatformViewportAndroid> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(PlatformViewportAndroid);
+};
+
+
+}  // namespace mojo
+
+#endif  // MOJO_SERVICES_NATIVE_VIEWPORT_PLATFORM_VIEWPORT_ANDROID_H_
diff --git a/mojo/services/native_viewport/platform_viewport_headless.cc b/mojo/services/native_viewport/platform_viewport_headless.cc
new file mode 100644
index 0000000..1c34711
--- /dev/null
+++ b/mojo/services/native_viewport/platform_viewport_headless.cc
@@ -0,0 +1,52 @@
+// Copyright 2013 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/services/native_viewport/platform_viewport_headless.h"
+
+namespace mojo {
+
+PlatformViewportHeadless::PlatformViewportHeadless(Delegate* delegate)
+    : delegate_(delegate) {
+}
+
+PlatformViewportHeadless::~PlatformViewportHeadless() {
+}
+
+void PlatformViewportHeadless::Init(const gfx::Rect& bounds) {
+  bounds_ = bounds;
+}
+
+void PlatformViewportHeadless::Show() {
+}
+
+void PlatformViewportHeadless::Hide() {
+}
+
+void PlatformViewportHeadless::Close() {
+  delegate_->OnDestroyed();
+}
+
+gfx::Size PlatformViewportHeadless::GetSize() {
+  return bounds_.size();
+}
+
+void PlatformViewportHeadless::SetBounds(const gfx::Rect& bounds) {
+  bounds_ = bounds;
+  delegate_->OnBoundsChanged(bounds_);
+}
+
+void PlatformViewportHeadless::SetCapture() {
+}
+
+void PlatformViewportHeadless::ReleaseCapture() {
+}
+
+// static
+scoped_ptr<PlatformViewport> PlatformViewportHeadless::Create(
+    Delegate* delegate) {
+  return scoped_ptr<PlatformViewport>(
+      new PlatformViewportHeadless(delegate)).Pass();
+}
+
+}  // namespace mojo
diff --git a/mojo/services/native_viewport/platform_viewport_headless.h b/mojo/services/native_viewport/platform_viewport_headless.h
new file mode 100644
index 0000000..9b9743f
--- /dev/null
+++ b/mojo/services/native_viewport/platform_viewport_headless.h
@@ -0,0 +1,36 @@
+// Copyright 2013 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/macros.h"
+#include "mojo/services/native_viewport/platform_viewport.h"
+#include "ui/gfx/rect.h"
+
+namespace mojo {
+
+class PlatformViewportHeadless : public PlatformViewport {
+ public:
+  virtual ~PlatformViewportHeadless();
+
+  static scoped_ptr<PlatformViewport> Create(Delegate* delegate);
+
+ private:
+  explicit PlatformViewportHeadless(Delegate* delegate);
+
+  // Overridden from PlatformViewport:
+  virtual void Init(const gfx::Rect& bounds) override;
+  virtual void Show() override;
+  virtual void Hide() override;
+  virtual void Close() override;
+  virtual gfx::Size GetSize() override;
+  virtual void SetBounds(const gfx::Rect& bounds) override;
+  virtual void SetCapture() override;
+  virtual void ReleaseCapture() override;
+
+  Delegate* delegate_;
+  gfx::Rect bounds_;
+
+  DISALLOW_COPY_AND_ASSIGN(PlatformViewportHeadless);
+};
+
+}  // namespace mojo
diff --git a/mojo/services/native_viewport/platform_viewport_mac.mm b/mojo/services/native_viewport/platform_viewport_mac.mm
new file mode 100644
index 0000000..9d11052
--- /dev/null
+++ b/mojo/services/native_viewport/platform_viewport_mac.mm
@@ -0,0 +1,84 @@
+// Copyright 2013 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/services/native_viewport/platform_viewport.h"
+
+#import <AppKit/NSApplication.h>
+#import <AppKit/NSView.h>
+#import <AppKit/NSWindow.h>
+
+#include "base/bind.h"
+#include "ui/gfx/rect.h"
+
+namespace mojo {
+
+class PlatformViewportMac : public PlatformViewport {
+ public:
+  PlatformViewportMac(Delegate* delegate)
+      : delegate_(delegate),
+        window_(nil) {
+  }
+
+  virtual ~PlatformViewportMac() {
+    [window_ orderOut:nil];
+    [window_ close];
+  }
+
+ private:
+  // Overridden from PlatformViewport:
+  virtual void Init(const gfx::Rect& bounds) OVERRIDE {
+    [NSApplication sharedApplication];
+
+    rect_ = bounds;
+    window_ = [[NSWindow alloc]
+                  initWithContentRect:NSRectFromCGRect(rect_.ToCGRect())
+                            styleMask:NSTitledWindowMask
+                              backing:NSBackingStoreBuffered
+                                defer:NO];
+    delegate_->OnAcceleratedWidgetAvailable([window_ contentView]);
+    delegate_->OnBoundsChanged(rect_);
+  }
+
+  virtual void Show() OVERRIDE {
+    [window_ orderFront:nil];
+  }
+
+  virtual void Hide() OVERRIDE {
+    [window_ orderOut:nil];
+  }
+
+  virtual void Close() OVERRIDE {
+    // TODO(beng): perform this in response to NSWindow destruction.
+    delegate_->OnDestroyed();
+  }
+
+  virtual gfx::Size GetSize() OVERRIDE {
+    return rect_.size();
+  }
+
+  virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE {
+    NOTIMPLEMENTED();
+  }
+
+  virtual void SetCapture() OVERRIDE {
+    NOTIMPLEMENTED();
+  }
+
+  virtual void ReleaseCapture() OVERRIDE {
+    NOTIMPLEMENTED();
+  }
+
+  Delegate* delegate_;
+  NSWindow* window_;
+  gfx::Rect rect_;
+
+  DISALLOW_COPY_AND_ASSIGN(PlatformViewportMac);
+};
+
+// static
+scoped_ptr<PlatformViewport> PlatformViewport::Create(Delegate* delegate) {
+  return scoped_ptr<PlatformViewport>(new PlatformViewportMac(delegate)).Pass();
+}
+
+}  // namespace mojo
diff --git a/mojo/services/native_viewport/platform_viewport_ozone.cc b/mojo/services/native_viewport/platform_viewport_ozone.cc
new file mode 100644
index 0000000..b8076fb
--- /dev/null
+++ b/mojo/services/native_viewport/platform_viewport_ozone.cc
@@ -0,0 +1,95 @@
+// Copyright 2014 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/services/native_viewport/platform_viewport.h"
+
+#include "ui/events/event.h"
+#include "ui/events/platform/platform_event_dispatcher.h"
+#include "ui/events/platform/platform_event_source.h"
+#include "ui/ozone/public/cursor_factory_ozone.h"
+#include "ui/ozone/public/ozone_platform.h"
+#include "ui/ozone/public/surface_factory_ozone.h"
+#include "ui/platform_window/platform_window.h"
+#include "ui/platform_window/platform_window_delegate.h"
+
+namespace mojo {
+
+// TODO(spang): Deduplicate with PlatformViewportX11.. but there's a hack
+// in there that prevents this.
+class PlatformViewportOzone : public PlatformViewport,
+                              public ui::PlatformWindowDelegate {
+ public:
+  explicit PlatformViewportOzone(Delegate* delegate) : delegate_(delegate) {
+    ui::OzonePlatform::InitializeForUI();
+  }
+
+  virtual ~PlatformViewportOzone() {
+    // Destroy the platform-window while |this| is still alive.
+    platform_window_.reset();
+  }
+
+ private:
+  // Overridden from PlatformViewport:
+  virtual void Init(const gfx::Rect& bounds) OVERRIDE {
+    platform_window_ =
+        ui::OzonePlatform::GetInstance()->CreatePlatformWindow(this, bounds);
+  }
+
+  virtual void Show() OVERRIDE { platform_window_->Show(); }
+
+  virtual void Hide() OVERRIDE { platform_window_->Hide(); }
+
+  virtual void Close() OVERRIDE { platform_window_->Close(); }
+
+  virtual gfx::Size GetSize() OVERRIDE {
+    return platform_window_->GetBounds().size();
+  }
+
+  virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE {
+    platform_window_->SetBounds(bounds);
+  }
+
+  virtual void SetCapture() OVERRIDE { platform_window_->SetCapture(); }
+
+  virtual void ReleaseCapture() OVERRIDE { platform_window_->ReleaseCapture(); }
+
+  // ui::PlatformWindowDelegate:
+  virtual void OnBoundsChanged(const gfx::Rect& new_bounds) OVERRIDE {
+    delegate_->OnBoundsChanged(new_bounds);
+  }
+
+  virtual void OnDamageRect(const gfx::Rect& damaged_region) OVERRIDE {}
+
+  virtual void DispatchEvent(ui::Event* event) OVERRIDE {
+    delegate_->OnEvent(event);
+  }
+
+  virtual void OnCloseRequest() OVERRIDE { platform_window_->Close(); }
+
+  virtual void OnClosed() OVERRIDE { delegate_->OnDestroyed(); }
+
+  virtual void OnWindowStateChanged(ui::PlatformWindowState state) OVERRIDE {}
+
+  virtual void OnLostCapture() OVERRIDE {}
+
+  virtual void OnAcceleratedWidgetAvailable(
+      gfx::AcceleratedWidget widget) OVERRIDE {
+    delegate_->OnAcceleratedWidgetAvailable(widget);
+  }
+
+  virtual void OnActivationChanged(bool active) OVERRIDE {}
+
+  scoped_ptr<ui::PlatformWindow> platform_window_;
+  Delegate* delegate_;
+
+  DISALLOW_COPY_AND_ASSIGN(PlatformViewportOzone);
+};
+
+// static
+scoped_ptr<PlatformViewport> PlatformViewport::Create(Delegate* delegate) {
+  return scoped_ptr<PlatformViewport>(
+      new PlatformViewportOzone(delegate)).Pass();
+}
+
+}  // namespace mojo
diff --git a/mojo/services/native_viewport/platform_viewport_stub.cc b/mojo/services/native_viewport/platform_viewport_stub.cc
new file mode 100644
index 0000000..80a7e94
--- /dev/null
+++ b/mojo/services/native_viewport/platform_viewport_stub.cc
@@ -0,0 +1,14 @@
+// Copyright 2014 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/services/native_viewport/platform_viewport_headless.h"
+
+namespace mojo {
+
+// static
+scoped_ptr<PlatformViewport> PlatformViewport::Create(Delegate* delegate) {
+  return PlatformViewportHeadless::Create(delegate);
+}
+
+}  // namespace mojo
diff --git a/mojo/services/native_viewport/platform_viewport_win.cc b/mojo/services/native_viewport/platform_viewport_win.cc
new file mode 100644
index 0000000..2227112
--- /dev/null
+++ b/mojo/services/native_viewport/platform_viewport_win.cc
@@ -0,0 +1,104 @@
+// Copyright 2013 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/services/native_viewport/platform_viewport.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "ui/gfx/rect.h"
+#include "ui/platform_window/platform_window_delegate.h"
+#include "ui/platform_window/win/win_window.h"
+
+namespace mojo {
+
+class PlatformViewportWin : public PlatformViewport,
+                            public ui::PlatformWindowDelegate {
+ public:
+  explicit PlatformViewportWin(Delegate* delegate)
+      : delegate_(delegate) {
+  }
+
+  virtual ~PlatformViewportWin() {
+    // Destroy the platform-window while |this| is still alive.
+    platform_window_.reset();
+  }
+
+ private:
+  // Overridden from PlatformViewport:
+  virtual void Init(const gfx::Rect& bounds) OVERRIDE {
+    platform_window_.reset(new ui::WinWindow(this, bounds));
+  }
+
+  virtual void Show() OVERRIDE {
+    platform_window_->Show();
+  }
+
+  virtual void Hide() OVERRIDE {
+    platform_window_->Hide();
+  }
+
+  virtual void Close() OVERRIDE {
+    platform_window_->Close();
+  }
+
+  virtual gfx::Size GetSize() OVERRIDE {
+    return platform_window_->GetBounds().size();
+  }
+
+  virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE {
+    platform_window_->SetBounds(bounds);
+  }
+
+  virtual void SetCapture() OVERRIDE {
+    platform_window_->SetCapture();
+  }
+
+  virtual void ReleaseCapture() OVERRIDE {
+    platform_window_->ReleaseCapture();
+  }
+
+  // ui::PlatformWindowDelegate:
+  virtual void OnBoundsChanged(const gfx::Rect& new_bounds) OVERRIDE {
+    delegate_->OnBoundsChanged(new_bounds);
+  }
+
+  virtual void OnDamageRect(const gfx::Rect& damaged_region) OVERRIDE {
+  }
+
+  virtual void DispatchEvent(ui::Event* event) OVERRIDE {
+    delegate_->OnEvent(event);
+  }
+
+  virtual void OnCloseRequest() OVERRIDE {
+    platform_window_->Close();
+  }
+
+  virtual void OnClosed() OVERRIDE {
+    delegate_->OnDestroyed();
+  }
+
+  virtual void OnWindowStateChanged(ui::PlatformWindowState state) OVERRIDE {
+  }
+
+  virtual void OnLostCapture() OVERRIDE {
+  }
+
+  virtual void OnAcceleratedWidgetAvailable(
+      gfx::AcceleratedWidget widget) OVERRIDE {
+    delegate_->OnAcceleratedWidgetAvailable(widget);
+  }
+
+  virtual void OnActivationChanged(bool active) OVERRIDE {}
+
+  scoped_ptr<ui::PlatformWindow> platform_window_;
+  Delegate* delegate_;
+
+  DISALLOW_COPY_AND_ASSIGN(PlatformViewportWin);
+};
+
+// static
+scoped_ptr<PlatformViewport> PlatformViewport::Create(Delegate* delegate) {
+  return scoped_ptr<PlatformViewport>(new PlatformViewportWin(delegate)).Pass();
+}
+
+}  // namespace mojo
diff --git a/mojo/services/native_viewport/platform_viewport_x11.cc b/mojo/services/native_viewport/platform_viewport_x11.cc
new file mode 100644
index 0000000..d4914c7
--- /dev/null
+++ b/mojo/services/native_viewport/platform_viewport_x11.cc
@@ -0,0 +1,150 @@
+// Copyright 2013 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/services/native_viewport/platform_viewport.h"
+
+#include "base/command_line.h"
+#include "base/message_loop/message_loop.h"
+#include "mojo/services/public/cpp/input_events/lib/mojo_extended_key_event_data.h"
+#include "ui/events/event.h"
+#include "ui/events/event_utils.h"
+#include "ui/events/platform/platform_event_dispatcher.h"
+#include "ui/events/platform/platform_event_source.h"
+#include "ui/gfx/rect.h"
+#include "ui/platform_window/platform_window.h"
+#include "ui/platform_window/platform_window_delegate.h"
+#include "ui/platform_window/x11/x11_window.h"
+
+namespace mojo {
+
+class PlatformViewportX11 : public PlatformViewport,
+                            public ui::PlatformWindowDelegate {
+ public:
+  explicit PlatformViewportX11(Delegate* delegate) : delegate_(delegate) {
+  }
+
+  virtual ~PlatformViewportX11() {
+    // Destroy the platform-window while |this| is still alive.
+    platform_window_.reset();
+  }
+
+ private:
+  // Overridden from PlatformViewport:
+  virtual void Init(const gfx::Rect& bounds) OVERRIDE {
+    CHECK(!event_source_);
+    CHECK(!platform_window_);
+
+    event_source_ = ui::PlatformEventSource::CreateDefault();
+
+    platform_window_.reset(new ui::X11Window(this));
+    platform_window_->SetBounds(bounds);
+  }
+
+  virtual void Show() OVERRIDE {
+    platform_window_->Show();
+  }
+
+  virtual void Hide() OVERRIDE {
+    platform_window_->Hide();
+  }
+
+  virtual void Close() OVERRIDE {
+    platform_window_->Close();
+  }
+
+  virtual gfx::Size GetSize() OVERRIDE {
+    return bounds_.size();
+  }
+
+  virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE {
+    platform_window_->SetBounds(bounds);
+  }
+
+  virtual void SetCapture() OVERRIDE {
+    platform_window_->SetCapture();
+  }
+
+  virtual void ReleaseCapture() OVERRIDE {
+    platform_window_->ReleaseCapture();
+  }
+
+  // ui::PlatformWindowDelegate:
+  virtual void OnBoundsChanged(const gfx::Rect& new_bounds) OVERRIDE {
+    bounds_ = new_bounds;
+    delegate_->OnBoundsChanged(new_bounds);
+  }
+
+  virtual void OnDamageRect(const gfx::Rect& damaged_region) OVERRIDE {
+  }
+
+  virtual void DispatchEvent(ui::Event* event) OVERRIDE {
+    delegate_->OnEvent(event);
+
+    // We want to emulate the WM_CHAR generation behaviour of Windows.
+    //
+    // On Linux, we've previously inserted characters by having
+    // InputMethodAuraLinux take all key down events and send a character event
+    // to the TextInputClient. This causes a mismatch in code that has to be
+    // shared between Windows and Linux, including blink code. Now that we're
+    // trying to have one way of doing things, we need to standardize on and
+    // emulate Windows character events.
+    //
+    // This is equivalent to what we're doing in the current Linux port, but
+    // done once instead of done multiple times in different places.
+    if (event->type() == ui::ET_KEY_PRESSED) {
+      ui::KeyEvent* key_press_event = static_cast<ui::KeyEvent*>(event);
+      ui::KeyEvent char_event(key_press_event->GetCharacter(),
+                              key_press_event->key_code(),
+                              key_press_event->flags());
+
+      DCHECK_EQ(key_press_event->GetCharacter(), char_event.GetCharacter());
+      DCHECK_EQ(key_press_event->key_code(), char_event.key_code());
+      DCHECK_EQ(key_press_event->flags(), char_event.flags());
+
+      char_event.SetExtendedKeyEventData(scoped_ptr<ui::ExtendedKeyEventData>(
+          new MojoExtendedKeyEventData(
+              key_press_event->GetLocatedWindowsKeyboardCode(),
+              key_press_event->GetText(),
+              key_press_event->GetUnmodifiedText())));
+      char_event.set_platform_keycode(key_press_event->platform_keycode());
+
+      delegate_->OnEvent(&char_event);
+    }
+  }
+
+  virtual void OnCloseRequest() OVERRIDE {
+    platform_window_->Close();
+  }
+
+  virtual void OnClosed() OVERRIDE {
+    delegate_->OnDestroyed();
+  }
+
+  virtual void OnWindowStateChanged(ui::PlatformWindowState state) OVERRIDE {
+  }
+
+  virtual void OnLostCapture() OVERRIDE {
+  }
+
+  virtual void OnAcceleratedWidgetAvailable(
+      gfx::AcceleratedWidget widget) OVERRIDE {
+    delegate_->OnAcceleratedWidgetAvailable(widget);
+  }
+
+  virtual void OnActivationChanged(bool active) OVERRIDE {}
+
+  scoped_ptr<ui::PlatformEventSource> event_source_;
+  scoped_ptr<ui::PlatformWindow> platform_window_;
+  Delegate* delegate_;
+  gfx::Rect bounds_;
+
+  DISALLOW_COPY_AND_ASSIGN(PlatformViewportX11);
+};
+
+// static
+scoped_ptr<PlatformViewport> PlatformViewport::Create(Delegate* delegate) {
+  return scoped_ptr<PlatformViewport>(new PlatformViewportX11(delegate)).Pass();
+}
+
+}  // namespace mojo
diff --git a/mojo/services/native_viewport/viewport_surface.cc b/mojo/services/native_viewport/viewport_surface.cc
new file mode 100644
index 0000000..8786e8c
--- /dev/null
+++ b/mojo/services/native_viewport/viewport_surface.cc
@@ -0,0 +1,111 @@
+// Copyright 2014 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/services/native_viewport/viewport_surface.h"
+
+#include "base/bind.h"
+#include "cc/surfaces/surface_id_allocator.h"
+#include "mojo/services/public/cpp/geometry/geometry_type_converters.h"
+#include "mojo/services/public/cpp/surfaces/surfaces_type_converters.h"
+#include "mojo/services/public/cpp/surfaces/surfaces_utils.h"
+#include "ui/gfx/transform.h"
+
+namespace mojo {
+
+ViewportSurface::ViewportSurface(SurfacesService* surfaces_service,
+                                 Gpu* gpu_service,
+                                 const gfx::Size& size,
+                                 cc::SurfaceId child_id)
+    : gpu_service_(gpu_service),
+      widget_id_(0u),
+      size_(size),
+      child_id_(child_id),
+      weak_factory_(this) {
+  surfaces_service->CreateSurfaceConnection(
+      base::Bind(&ViewportSurface::OnSurfaceConnectionCreated,
+                 weak_factory_.GetWeakPtr()));
+}
+
+ViewportSurface::~ViewportSurface() {
+}
+
+void ViewportSurface::SetWidgetId(uint64_t widget_id) {
+  widget_id_ = widget_id;
+  if (id_allocator_)
+    BindSurfaceToNativeViewport();
+}
+
+void ViewportSurface::SetSize(const gfx::Size& size) {
+  if (size_ == size)
+    return;
+
+  if (id_.is_null())
+    return;
+
+  surface_->DestroySurface(SurfaceId::From(id_));
+  if (widget_id_)
+    BindSurfaceToNativeViewport();
+}
+
+void ViewportSurface::SetChildId(cc::SurfaceId child_id) {
+  child_id_ = child_id;
+  SubmitFrame();
+}
+
+void ViewportSurface::OnSurfaceConnectionCreated(SurfacePtr surface,
+                                                 uint32_t id_namespace) {
+  surface_ = surface.Pass();
+  surface_.set_client(this);
+  id_allocator_.reset(new cc::SurfaceIdAllocator(id_namespace));
+  if (widget_id_ != 0u)
+    BindSurfaceToNativeViewport();
+}
+
+void ViewportSurface::BindSurfaceToNativeViewport() {
+  CommandBufferPtr cb;
+  gpu_service_->CreateOnscreenGLES2Context(
+      widget_id_, Size::From(size_), Get(&cb));
+
+  id_ = id_allocator_->GenerateId();
+  surface_->CreateGLES2BoundSurface(
+      cb.Pass(), SurfaceId::From(id_), Size::From(size_));
+
+  SubmitFrame();
+}
+
+void ViewportSurface::SubmitFrame() {
+  if (child_id_.is_null() || id_.is_null())
+    return;
+
+  SurfaceQuadStatePtr surface_quad_state = SurfaceQuadState::New();
+  surface_quad_state->surface = SurfaceId::From(child_id_);
+
+  gfx::Rect bounds(size_);
+
+  QuadPtr surface_quad = Quad::New();
+  surface_quad->material = Material::MATERIAL_SURFACE_CONTENT;
+  surface_quad->rect = Rect::From(bounds);
+  surface_quad->opaque_rect = Rect::From(bounds);
+  surface_quad->visible_rect = Rect::From(bounds);
+  surface_quad->needs_blending = true;
+  surface_quad->shared_quad_state_index = 0;
+  surface_quad->surface_quad_state = surface_quad_state.Pass();
+
+  PassPtr pass = CreateDefaultPass(1, bounds);
+
+  pass->quads.push_back(surface_quad.Pass());
+  pass->shared_quad_states.push_back(CreateDefaultSQS(size_));
+
+  FramePtr frame = Frame::New();
+  frame->passes.push_back(pass.Pass());
+  frame->resources.resize(0u);
+  surface_->SubmitFrame(SurfaceId::From(id_), frame.Pass());
+}
+
+void ViewportSurface::ReturnResources(Array<ReturnedResourcePtr> resources) {
+  // We never submit resources so we should never get any back.
+  DCHECK_EQ(0u, resources.size());
+}
+
+}  // namespace mojo
diff --git a/mojo/services/native_viewport/viewport_surface.h b/mojo/services/native_viewport/viewport_surface.h
new file mode 100644
index 0000000..2ca8105
--- /dev/null
+++ b/mojo/services/native_viewport/viewport_surface.h
@@ -0,0 +1,58 @@
+// Copyright 2014 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 MOJO_SERVICES_NATIVE_VIEWPORT_VIEWPORT_SURFACE_H_
+#define MOJO_SERVICES_NATIVE_VIEWPORT_VIEWPORT_SURFACE_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "cc/surfaces/surface_id.h"
+#include "mojo/services/public/interfaces/gpu/gpu.mojom.h"
+#include "mojo/services/public/interfaces/surfaces/surfaces.mojom.h"
+#include "mojo/services/public/interfaces/surfaces/surfaces_service.mojom.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/gfx/size.h"
+
+namespace cc {
+class SurfaceIdAllocator;
+}
+
+namespace mojo {
+
+// This manages the surface that draws to a particular NativeViewport instance.
+class ViewportSurface : public SurfaceClient {
+ public:
+  ViewportSurface(SurfacesService* surfaces_service,
+                  Gpu* gpu_service,
+                  const gfx::Size& size,
+                  cc::SurfaceId child_id);
+  virtual ~ViewportSurface();
+
+  void SetWidgetId(uint64_t widget_id);
+  void SetSize(const gfx::Size& size);
+  void SetChildId(cc::SurfaceId child_id);
+
+ private:
+  void OnSurfaceConnectionCreated(SurfacePtr surface, uint32_t id_namespace);
+  void BindSurfaceToNativeViewport();
+  void SubmitFrame();
+
+  // SurfaceClient implementation.
+  virtual void ReturnResources(Array<ReturnedResourcePtr> resources) OVERRIDE;
+
+  SurfacePtr surface_;
+  Gpu* gpu_service_;
+  uint64_t widget_id_;
+  gfx::Size size_;
+  scoped_ptr<cc::SurfaceIdAllocator> id_allocator_;
+  cc::SurfaceId id_;
+  cc::SurfaceId child_id_;
+  base::WeakPtrFactory<ViewportSurface> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(ViewportSurface);
+};
+
+}  // namespace mojo
+
+#endif  // MOJO_SERVICES_NATIVE_VIEWPORT_VIEWPORT_SURFACE_H_