Teach PPAPI proxy to share image memory on Mac OS X

Instead of just using base::SharedMemory, we use SysV shared memory on Linux so
that we can share memory with X.  Normally we abstract this detail away with
TransportDIB, but the TransportDIB lives in chrome/app, which is outside the
dependency cone of ppapi/proxy.

This patch creates a new abstraction at this layer of the dependency graph
called ImageData::ImageHandle that represents shared memory for the purpose of
image data.  This patch also fills in the implementation of this abstraction on
Mac OS X.  Consequently, out-of-process PPAPI plugins on Mac can now draw to
the screen.

Review URL: http://codereview.chromium.org/5658003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@68569 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/ppapi/proxy/image_data.cc b/ppapi/proxy/image_data.cc
new file mode 100644
index 0000000..c01896df
--- /dev/null
+++ b/ppapi/proxy/image_data.cc
@@ -0,0 +1,91 @@
+// Copyright (c) 2010 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 "ppapi/proxy/image_data.h"
+
+#if defined(OS_LINUX)
+#include <sys/shm.h>
+#endif
+
+#if defined(OS_MACOSX)
+#include <sys/stat.h>
+#include <sys/mman.h>
+#endif
+
+namespace pp {
+namespace proxy {
+
+ImageData::ImageData(const PP_ImageDataDesc& desc, ImageHandle handle)
+    : desc_(desc),
+      handle_(handle),
+      mapped_data_(NULL) {
+}
+
+ImageData::~ImageData() {
+  Unmap();
+}
+
+void* ImageData::Map() {
+#if defined(OS_WIN)
+  NOTIMPLEMENTED();
+  return NULL;
+#elif defined(OS_MACOSX)
+  struct stat st;
+  if (fstat(handle_.fd, &st) != 0)
+    return NULL;
+  void* memory = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE,
+                      MAP_SHARED, handle_.fd, 0);
+  if (memory == MAP_FAILED)
+    return NULL;
+  mapped_data_ = memory;
+  return mapped_data_;
+#else
+  return NULL;
+  int shmkey = handle_;
+  void* address = shmat(shmkey, NULL, 0);
+  // Mark for deletion in case we crash so the kernel will clean it up.
+  shmctl(shmkey, IPC_RMID, 0);
+  if (address == (void*)-1)
+    return NULL;
+  mapped_data_ = address;
+  return address;
+#endif
+}
+
+void ImageData::Unmap() {
+#if defined(OS_WIN)
+  NOTIMPLEMENTED();
+#elif defined(OS_MACOSX)
+  if (mapped_data_) {
+    struct stat st;
+    if (fstat(handle_.fd, &st) == 0)
+      munmap(mapped_data_, st.st_size);
+  }
+#else
+  if (mapped_data_)
+    shmdt(mapped_data_);
+#endif
+  mapped_data_ = NULL;
+}
+
+#if defined(OS_WIN)
+const ImageHandle ImageData::NullHandle = NULL;
+#elif defined(OS_MACOSX)
+const ImageHandle ImageData::NullHandle = ImageHandle();
+#else
+const ImageHandle ImageData::NullHandle = 0;
+#endif
+
+ImageHandle ImageData::HandleFromInt(int32_t i) {
+#if defined(OS_WIN)
+    return reinterpret_cast<ImageHandle>(i);
+#elif defined(OS_MACOSX)
+    return ImageHandle(i, false);
+#else
+    return static_cast<ImageHandle>(i);
+#endif
+}
+
+}  // namespace proxy
+}  // namespace pp
diff --git a/ppapi/proxy/image_data.h b/ppapi/proxy/image_data.h
new file mode 100644
index 0000000..fb4a839
--- /dev/null
+++ b/ppapi/proxy/image_data.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2010 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 PPAPI_PROXY_IMAGE_DATA_H_
+#define PPAPI_PROXY_IMAGE_DATA_H_
+
+#include "base/shared_memory.h"
+#include "ppapi/c/ppb_image_data.h"
+#include "ppapi/proxy/plugin_resource.h"
+#include "ppapi/proxy/serialized_structs.h"
+
+namespace pp {
+namespace proxy {
+
+class ImageData : public PluginResource {
+ public:
+  ImageData(const PP_ImageDataDesc& desc, ImageHandle handle);
+  virtual ~ImageData();
+
+  // Resource overrides.
+  virtual ImageData* AsImageData() { return this; }
+
+  void* Map();
+  void Unmap();
+
+  const PP_ImageDataDesc& desc() const { return desc_; }
+
+  static const ImageHandle NullHandle;
+  static ImageHandle HandleFromInt(int32_t i);
+
+ private:
+  PP_ImageDataDesc desc_;
+  ImageHandle handle_;
+
+  void* mapped_data_;
+
+  DISALLOW_COPY_AND_ASSIGN(ImageData);
+};
+
+}  // namespace proxy
+}  // namespace pp
+
+#endif  // PPAPI_PROXY_IMAGE_DATA_H_
diff --git a/ppapi/proxy/ppapi_messages_internal.h b/ppapi/proxy/ppapi_messages_internal.h
index 5259725..5e9ad61 100644
--- a/ppapi/proxy/ppapi_messages_internal.h
+++ b/ppapi/proxy/ppapi_messages_internal.h
@@ -359,7 +359,7 @@
                              PP_Bool /* init_to_zero */,
                              PP_Resource /* result_resource */,
                              std::string /* image_data_desc */,
-                             int32_t /* result_shm_handle */)
+                             pp::proxy::ImageHandle /* result */)
 
   // PPB_Instance.
   IPC_SYNC_MESSAGE_ROUTED1_1(PpapiHostMsg_PPBInstance_GetWindowObject,
diff --git a/ppapi/proxy/ppb_image_data_proxy.cc b/ppapi/proxy/ppb_image_data_proxy.cc
index a3ffe715..4fa4205 100644
--- a/ppapi/proxy/ppb_image_data_proxy.cc
+++ b/ppapi/proxy/ppb_image_data_proxy.cc
@@ -13,79 +13,14 @@
 #include "ppapi/c/pp_completion_callback.h"
 #include "ppapi/c/pp_errors.h"
 #include "ppapi/c/pp_resource.h"
-#include "ppapi/c/ppb_image_data.h"
 #include "ppapi/c/trusted/ppb_image_data_trusted.h"
+#include "ppapi/proxy/image_data.h"
 #include "ppapi/proxy/plugin_dispatcher.h"
-#include "ppapi/proxy/plugin_resource.h"
 #include "ppapi/proxy/ppapi_messages.h"
 
-#if defined(OS_LINUX)
-#include <sys/shm.h>
-#endif
-
 namespace pp {
 namespace proxy {
 
-class ImageData : public PluginResource {
- public:
-  ImageData(const PP_ImageDataDesc& desc, int memory_handle);
-  virtual ~ImageData();
-
-  // Resource overrides.
-  virtual ImageData* AsImageData() { return this; }
-
-  void* Map();
-  void Unmap();
-
-  const PP_ImageDataDesc& desc() const { return desc_; }
-
- private:
-  PP_ImageDataDesc desc_;
-  int memory_handle_;
-
-  void* mapped_data_;
-
-  DISALLOW_COPY_AND_ASSIGN(ImageData);
-};
-
-ImageData::ImageData(const PP_ImageDataDesc& desc,
-                     int memory_handle)
-    : desc_(desc),
-      memory_handle_(memory_handle),
-      mapped_data_(NULL) {
-}
-
-ImageData::~ImageData() {
-  Unmap();
-}
-
-void* ImageData::Map() {
-#if defined(OS_LINUX)
-  // On linux, the memory handle is a SysV shared memory segment.
-  int shmkey = memory_handle_;
-  void* address = shmat(shmkey, NULL, 0);
-  // Mark for deletion in case we crash so the kernel will clean it up.
-  shmctl(shmkey, IPC_RMID, 0);
-  if (address == (void*)-1)
-    return NULL;
-  mapped_data_ = address;
-  return address;
-#else
-  NOTIMPLEMENTED();
-  return NULL;
-#endif
-}
-
-void ImageData::Unmap() {
-#if defined(OS_LINUX)
-  if (mapped_data_)
-    shmdt(mapped_data_);
-#else
-  NOTIMPLEMENTED();
-#endif
-  mapped_data_ = NULL;
-}
-
 namespace {
 
 PP_ImageDataFormat GetNativeImageDataFormat() {
@@ -111,11 +46,11 @@
                    PP_Bool init_to_zero) {
   PP_Resource result = 0;
   std::string image_data_desc;
-  int shm_handle = -1;
+  ImageHandle image_handle = ImageData::NullHandle;
   PluginDispatcher::Get()->Send(
       new PpapiHostMsg_PPBImageData_Create(
           INTERFACE_ID_PPB_IMAGE_DATA, module_id, format, *size, init_to_zero,
-          &result, &image_data_desc, &shm_handle));
+          &result, &image_data_desc, &image_handle));
 
   if (result && image_data_desc.size() == sizeof(PP_ImageDataDesc)) {
     // We serialize the PP_ImageDataDesc just by copying to a string.
@@ -123,7 +58,7 @@
     memcpy(&desc, image_data_desc.data(), sizeof(PP_ImageDataDesc));
 
     linked_ptr<ImageData> object(
-        new ImageData(desc, shm_handle));
+        new ImageData(desc, image_handle));
     PluginDispatcher::Get()->plugin_resource_tracker()->AddResource(
         result, object);
   }
@@ -211,10 +146,10 @@
                                       PP_Bool init_to_zero,
                                       PP_Resource* result,
                                       std::string* image_data_desc,
-                                      int* result_shm_handle) {
+                                      ImageHandle* result_image_handle) {
   *result = ppb_image_data_target()->Create(
       module, static_cast<PP_ImageDataFormat>(format), &size, init_to_zero);
-  *result_shm_handle = 0;
+  *result_image_handle = ImageData::NullHandle;
   if (*result) {
     // The ImageDesc is just serialized as a string.
     PP_ImageDataDesc desc;
@@ -231,7 +166,7 @@
     if (trusted) {
       int32_t handle;
       if (trusted->GetSharedMemory(*result, &handle, &byte_count) == PP_OK)
-        *result_shm_handle = static_cast<int>(handle);
+          *result_image_handle = ImageData::HandleFromInt(handle);
     }
   }
 }
diff --git a/ppapi/proxy/ppb_image_data_proxy.h b/ppapi/proxy/ppb_image_data_proxy.h
index a61a3a7..5ff617ca 100644
--- a/ppapi/proxy/ppb_image_data_proxy.h
+++ b/ppapi/proxy/ppb_image_data_proxy.h
@@ -12,6 +12,8 @@
 #include "ppapi/c/pp_size.h"
 #include "ppapi/c/pp_var.h"
 #include "ppapi/proxy/interface_proxy.h"
+#include "ppapi/proxy/image_data.h"
+
 
 struct PPB_ImageData;
 
@@ -42,7 +44,7 @@
                    PP_Bool init_to_zero,
                    PP_Resource* result,
                    std::string* image_data_desc,
-                   int* result_shm_handle);
+                   ImageHandle* result_image_handle);
 };
 
 }  // namespace proxy
diff --git a/ppapi/proxy/serialized_structs.h b/ppapi/proxy/serialized_structs.h
index d90926b..2c78dd4 100644
--- a/ppapi/proxy/serialized_structs.h
+++ b/ppapi/proxy/serialized_structs.h
@@ -8,6 +8,8 @@
 #include <string>
 #include <vector>
 
+#include "base/shared_memory.h"
+#include "build/build_config.h"
 #include "ppapi/c/pp_bool.h"
 #include "ppapi/c/pp_point.h"
 #include "ppapi/c/pp_rect.h"
@@ -96,9 +98,16 @@
   std::vector<PP_Point> glyph_advances;
 };
 
+#if defined(OS_WIN)
+typedef HANDLE ImageHandle;
+#elif defined(OS_MACOSX)
+typedef base::SharedMemoryHandle ImageHandle;
+#else
+// On X Windows this is a SysV shared memory key.
+typedef int ImageHandle;
+#endif
+
 }  // namespace proxy
 }  // namespace pp
 
-
-
 #endif  // PPAPI_PROXY_SERIALIZED_STRUCTS_H_