Index: content/common/android/surface_callback.cc |
diff --git a/content/common/android/surface_callback.cc b/content/common/android/surface_callback.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..de83bbd44b0da2799b28faa03878f50a91ad6cf5 |
--- /dev/null |
+++ b/content/common/android/surface_callback.cc |
@@ -0,0 +1,159 @@ |
+// Copyright (c) 2012 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 "content/common/android/surface_callback.h" |
+ |
+#include <android/native_window_jni.h> |
+ |
+#include "base/android/jni_android.h" |
+#include "base/bind.h" |
+#include "base/lazy_instance.h" |
+#include "base/logging.h" |
+#include "base/message_loop.h" |
+#include "base/message_loop_proxy.h" |
+#include "base/synchronization/lock.h" |
+#include "base/synchronization/waitable_event.h" |
+#include "ui/gl/android_native_window.h" |
+#include "jni/surface_callback_jni.h" |
+ |
+using base::android::AttachCurrentThread; |
+using base::android::CheckException; |
+using base::android::GetMethodID; |
+using base::WaitableEvent; |
+using content::SurfaceTexturePeer; |
+ |
+namespace { |
+ |
+struct GlobalState { |
+ base::Lock registration_lock; |
+ // We hold a reference to a message loop proxy which handles message loop |
+ // destruction gracefully, which is important since we post tasks from an |
+ // arbitrary binder thread while the main thread might be shutting down. |
+ // Also, in single-process mode we have two ChildThread objects for render |
+ // and gpu thread, so we need to store the msg loops separately. |
+ scoped_refptr<base::MessageLoopProxy> native_window_loop; |
+ scoped_refptr<base::MessageLoopProxy> video_surface_loop; |
+ content::NativeWindowCallback native_window_callback; |
+ content::VideoSurfaceCallback video_surface_callback; |
+}; |
+ |
+base::LazyInstance<GlobalState>::Leaky g_state = LAZY_INSTANCE_INITIALIZER; |
+ |
+void RunNativeWindowCallback(int32 routing_id, |
+ int32 renderer_id, |
+ ANativeWindow* native_window, |
+ WaitableEvent* completion) { |
+ g_state.Pointer()->native_window_callback.Run( |
+ routing_id, renderer_id, native_window, completion); |
+} |
+ |
+void RunVideoSurfaceCallback(int32 routing_id, |
+ int32 renderer_id, |
+ jobject surface) { |
+ g_state.Pointer()->video_surface_callback.Run( |
+ routing_id, renderer_id, surface); |
+} |
+ |
+} // namespace <anonymous> |
+ |
+static void SetSurface(JNIEnv* env, jclass clazz, |
+ jint type, |
+ jobject surface, |
+ jint primaryID, |
+ jint secondaryID) { |
+ SetSurfaceAsync(env, surface, |
+ static_cast<SurfaceTexturePeer::SurfaceTextureTarget>(type), |
+ primaryID, secondaryID, NULL); |
+} |
+ |
+ |
+namespace content { |
+ |
+void ReleaseSurface(jobject surface) { |
+ if (surface == NULL) |
+ return; |
+ |
+ JNIEnv* env = AttachCurrentThread(); |
+ CHECK(env); |
+ |
+ jclass cls = env->FindClass("android/view/Surface"); |
+ DCHECK(cls); |
+ |
+ jmethodID method = env->GetMethodID(cls, "release", "()V"); |
+ DCHECK(method); |
+ |
+ env->CallVoidMethod(surface, method); |
+ DCHECK(env); |
+ |
+ env->DeleteLocalRef(cls); |
+} |
+ |
+void SetSurfaceAsync(JNIEnv* env, |
+ jobject jsurface, |
+ SurfaceTexturePeer::SurfaceTextureTarget type, |
+ int primary_id, |
+ int secondary_id, |
+ WaitableEvent* completion) { |
+ base::AutoLock lock(g_state.Pointer()->registration_lock); |
+ |
+ ANativeWindow* native_window = NULL; |
+ |
+ if (jsurface && |
+ type != SurfaceTexturePeer::SET_VIDEO_SURFACE_TEXTURE) { |
+ native_window = ANativeWindow_fromSurface(env, jsurface); |
+ ReleaseSurface(jsurface); |
+ } |
+ GlobalState* const global_state = g_state.Pointer(); |
+ |
+ switch (type) { |
+ case SurfaceTexturePeer::SET_GPU_SURFACE_TEXTURE: { |
+ // This should only be sent as a reaction to the renderer |
+ // activating compositing. If the GPU process crashes, we expect this |
+ // to be resent after the new thread is initialized. |
+ DCHECK(global_state->native_window_loop); |
+ global_state->native_window_loop->PostTask( |
+ FROM_HERE, |
+ base::Bind(&RunNativeWindowCallback, |
+ primary_id, |
+ static_cast<uint32_t>(secondary_id), |
+ native_window, |
+ completion)); |
+ // ANativeWindow_release will be called in SetNativeWindow() |
+ break; |
+ } |
+ case SurfaceTexturePeer::SET_VIDEO_SURFACE_TEXTURE: { |
+ jobject surface = env->NewGlobalRef(jsurface); |
+ DCHECK(global_state->video_surface_loop); |
+ global_state->video_surface_loop->PostTask( |
+ FROM_HERE, |
+ base::Bind(&RunVideoSurfaceCallback, |
+ primary_id, |
+ secondary_id, |
+ surface)); |
+ break; |
+ } |
+ } |
+} |
+ |
+void RegisterVideoSurfaceCallback(base::MessageLoopProxy* loop, |
+ VideoSurfaceCallback& callback) { |
+ GlobalState* const global_state = g_state.Pointer(); |
+ base::AutoLock lock(global_state->registration_lock); |
+ global_state->video_surface_loop = loop; |
+ global_state->video_surface_callback = callback; |
+} |
+ |
+void RegisterNativeWindowCallback(base::MessageLoopProxy* loop, |
+ NativeWindowCallback& callback) { |
+ GlobalState* const global_state = g_state.Pointer(); |
+ base::AutoLock lock(global_state->registration_lock); |
+ global_state->native_window_loop = loop; |
+ global_state->native_window_callback = callback; |
+} |
+ |
+bool RegisterSurfaceCallback(JNIEnv* env) { |
+ return RegisterNativesImpl(env); |
+} |
+ |
+} // namespace content |