Add support for pausing/resuming composition from Java.
authorAli Juma <ajuma@mozilla.com>
Sun, 05 Feb 2012 13:33:38 -0500
changeset 90886 d721b3df0c6bdd8e0ea83ec816b94453d13ca49b
parent 90885 d678113069ca2b8d5b9e96596576cc4526d6a049
child 90887 43016f417f0bc2a1d22c4078ecbc2eb9eb02af00
push idunknown
push userunknown
push dateunknown
milestone12.0a1
Add support for pausing/resuming composition from Java.
gfx/layers/ipc/CompositorParent.cpp
gfx/layers/ipc/CompositorParent.h
mobile/android/base/GeckoAppShell.java
mobile/android/base/gfx/FlexibleGLSurfaceView.java
mobile/android/base/gfx/GeckoGLLayerClient.java
widget/android/AndroidBridge.cpp
widget/android/AndroidBridge.h
widget/android/AndroidJNI.cpp
--- a/gfx/layers/ipc/CompositorParent.cpp
+++ b/gfx/layers/ipc/CompositorParent.cpp
@@ -47,17 +47,17 @@
 #include "AndroidBridge.h"
 #include <android/log.h>
 #endif
 
 namespace mozilla {
 namespace layers {
 
 CompositorParent::CompositorParent(nsIWidget* aWidget)
-  : mStopped(false), mWidget(aWidget)
+  : mPaused(false), mWidget(aWidget)
 {
   MOZ_COUNT_CTOR(CompositorParent);
 }
 
 CompositorParent::~CompositorParent()
 {
   MOZ_COUNT_DTOR(CompositorParent);
 }
@@ -70,30 +70,66 @@ CompositorParent::Destroy()
 
   // Ensure that the layer manager is destroyed on the compositor thread.
   mLayerManager = NULL;
 }
 
 bool
 CompositorParent::RecvStop()
 {
-  mStopped = true;
+  mPaused = true;
   Destroy();
   return true;
 }
 
 
 void
 CompositorParent::ScheduleRenderOnCompositorThread(::base::Thread &aCompositorThread)
 {
   CancelableTask *renderTask = NewRunnableMethod(this, &CompositorParent::AsyncRender);
   aCompositorThread.message_loop()->PostTask(FROM_HERE, renderTask);
 }
 
 void
+CompositorParent::PauseComposition()
+{
+  mPaused = true;
+
+#ifdef MOZ_WIDGET_ANDROID
+  // TODO: Tell GLContextEGL we're paused, so it should release surface.
+#endif
+}
+
+void
+CompositorParent::ResumeComposition()
+{
+  mPaused = false;
+
+#ifdef MOZ_WIDGET_ANDROID
+  // TODO: Tell GLContextEGL we've resumed, so it should obtain new surface.
+#endif
+}
+
+void
+CompositorParent::SchedulePauseOnCompositorThread(::base::Thread &aCompositorThread)
+{
+  CancelableTask *pauseTask = NewRunnableMethod(this,
+                                                &CompositorParent::PauseComposition);
+  aCompositorThread.message_loop()->PostTask(FROM_HERE, pauseTask);
+}
+
+void
+CompositorParent::ScheduleResumeOnCompositorThread(::base::Thread &aCompositorThread)
+{
+  CancelableTask *resumeTask = NewRunnableMethod(this,
+                                                 &CompositorParent::ResumeComposition);
+  aCompositorThread.message_loop()->PostTask(FROM_HERE, resumeTask);
+}
+
+void
 CompositorParent::ScheduleComposition()
 {
   printf_stderr("Schedule composition\n");
   CancelableTask *composeTask = NewRunnableMethod(this, &CompositorParent::Composite);
   MessageLoop::current()->PostTask(FROM_HERE, composeTask);
 
 // Test code for async scrolling.
 #ifdef OMTC_TEST_ASYNC_SCROLLING
@@ -113,17 +149,17 @@ CompositorParent::SetTransformation(floa
   mXScale = aScale;
   mYScale = aScale;
   mScrollOffset = aScrollOffset;
 }
 
 void
 CompositorParent::Composite()
 {
-  if (mStopped || !mLayerManager) {
+  if (mPaused || !mLayerManager) {
     return;
   }
 
   mLayerManager->EndEmptyTransaction();
 }
 
 // Go down shadow layer tree, setting properties to match their non-shadow
 // counterparts.
@@ -213,17 +249,17 @@ CompositorParent::TransformShadowTree(La
                        aTempScaleDiffY);
   }*/
 
 }
 
 void
 CompositorParent::AsyncRender()
 {
-  if (mStopped || !mLayerManager) {
+  if (mPaused || !mLayerManager) {
     return;
   }
 
   Layer* root = mLayerManager->GetRoot();
 
 /*
   ContainerLayer* container = root->AsContainerLayer();
   if (!container)
--- a/gfx/layers/ipc/CompositorParent.h
+++ b/gfx/layers/ipc/CompositorParent.h
@@ -87,16 +87,21 @@ public:
   void Destroy();
 
   LayerManager* GetLayerManager() { return mLayerManager; }
 
   void SetTransformation(float aScale, nsIntPoint aScrollOffset);
   void AsyncRender();
   void ScheduleRenderOnCompositorThread(::base::Thread &aCompositorThread);
 
+  void PauseComposition();
+  void ResumeComposition();
+  void SchedulePauseOnCompositorThread(::base::Thread &aCompositorThread);
+  void ScheduleResumeOnCompositorThread(::base::Thread &aCompositorThread);
+
 protected:
   virtual PLayersParent* AllocPLayers(const LayersBackend &backendType);
   virtual bool DeallocPLayers(PLayersParent* aLayers);
 
 private:
   void ScheduleComposition();
   void Composite();
 #ifdef OMTC_TEST_ASYNC_SCROLLING
@@ -118,17 +123,17 @@ private:
   /**
    * Asks Java for the viewport position and updates the world transform
    * accordingly.
    */
   void RequestViewTransform();
 #endif
 
   nsRefPtr<LayerManager> mLayerManager;
-  bool mStopped;
+  bool mPaused;
   nsIWidget* mWidget;
   float mXScale;
   float mYScale;
   nsIntPoint mScrollOffset;
 
   DISALLOW_EVIL_CONSTRUCTORS(CompositorParent);
 };
 
--- a/mobile/android/base/GeckoAppShell.java
+++ b/mobile/android/base/GeckoAppShell.java
@@ -166,16 +166,18 @@ public class GeckoAppShell
     public static native void notifyListCreated(int aListId, int aMessageId, String aReceiver, String aSender, String aBody, long aTimestamp, int aRequestId, long aProcessId);
     public static native void notifyGotNextMessage(int aMessageId, String aReceiver, String aSender, String aBody, long aTimestamp, int aRequestId, long aProcessId);
     public static native void notifyReadingMessageListFailed(int aError, int aRequestId, long aProcessId);
 
     public static native ByteBuffer allocateDirectBuffer(long size);
     public static native void freeDirectBuffer(ByteBuffer buf);
     public static native void bindWidgetTexture();
     public static native void scheduleComposite();
+    public static native void schedulePauseComposition();
+    public static native void scheduleResumeComposition();
 
     // A looper thread, accessed by GeckoAppShell.getHandler
     private static class LooperThread extends Thread {
         public SynchronousQueue<Handler> mHandlerQueue =
             new SynchronousQueue<Handler>();
         
         public void run() {
             setName("GeckoLooper Thread");
--- a/mobile/android/base/gfx/FlexibleGLSurfaceView.java
+++ b/mobile/android/base/gfx/FlexibleGLSurfaceView.java
@@ -187,16 +187,18 @@ public class FlexibleGLSurfaceView exten
         } catch (Exception e) {
             Log.e(LOGTAG, "### Exception! " + e);
             return null;
         }
     }
 
     public interface Listener {
         void renderRequested();
+        void compositionPauseRequested();
+        void compositionResumeRequested();
     }
 
     public static class FlexibleGLSurfaceViewException extends RuntimeException {
         public static final long serialVersionUID = 1L;
 
         FlexibleGLSurfaceViewException(String e) {
             super(e);
         }
--- a/mobile/android/base/gfx/GeckoGLLayerClient.java
+++ b/mobile/android/base/gfx/GeckoGLLayerClient.java
@@ -188,10 +188,20 @@ public class GeckoGLLayerClient extends 
             return new ViewTransform(scrollX, scrollY, zoomFactor);
         }
     }
 
     public void renderRequested() {
         Log.e(LOGTAG, "### Render requested, scheduling composite");
         GeckoAppShell.scheduleComposite();
     }
+
+    public void compositionPauseRequested() {
+        Log.e(LOGTAG, "### Scheduling PauseComposition");
+        GeckoAppShell.schedulePauseComposition();
+    }
+
+    public void compositionResumeRequested() {
+        Log.e(LOGTAG, "### Scheduling ResumeComposition");
+        GeckoAppShell.scheduleResumeComposition();
+    }
 }
 
--- a/widget/android/AndroidBridge.cpp
+++ b/widget/android/AndroidBridge.cpp
@@ -1865,16 +1865,32 @@ void
 AndroidBridge::ScheduleComposite()
 {
     if (mCompositorParent) {
         mCompositorParent->ScheduleRenderOnCompositorThread(*mCompositorThread);
     }
 }
 
 void
+AndroidBridge::SchedulePauseComposition()
+{
+    if (mCompositorParent) {
+        mCompositorParent->SchedulePauseOnCompositorThread(*mCompositorThread);
+    }
+}
+
+void
+AndroidBridge::ScheduleResumeComposition()
+{
+    if (mCompositorParent) {
+        mCompositorParent->ScheduleResumeOnCompositorThread(*mCompositorThread);
+    }
+}
+
+void
 AndroidBridge::SetViewTransformGetter(AndroidViewTransformGetter& aViewTransformGetter)
 {
     __android_log_print(ANDROID_LOG_ERROR, "Gecko", "### SetViewTransformGetter()");
     mViewTransformGetter = &aViewTransformGetter;
 }
 
 void
 AndroidBridge::GetViewTransform(nsIntPoint& aScrollOffset, float& aScaleX, float& aScaleY)
--- a/widget/android/AndroidBridge.h
+++ b/widget/android/AndroidBridge.h
@@ -398,16 +398,18 @@ public:
 
     void GetCurrentNetworkInformation(hal::NetworkInformation* aNetworkInfo);
     void EnableNetworkNotifications();
     void DisableNetworkNotifications();
 
     void SetCompositorParent(mozilla::layers::CompositorParent* aCompositorParent,
                              base::Thread* aCompositorThread);
     void ScheduleComposite();
+    void SchedulePauseComposition();
+    void ScheduleResumeComposition();
     void SetViewTransformGetter(AndroidViewTransformGetter& aViewTransformGetter);
     void GetViewTransform(nsIntPoint& aScrollOffset, float& aScaleX, float& aScaleY);
 
 protected:
     static AndroidBridge *sBridge;
 
     // the global JavaVM
     JavaVM *mJavaVM;
--- a/widget/android/AndroidJNI.cpp
+++ b/widget/android/AndroidJNI.cpp
@@ -102,16 +102,18 @@ extern "C" {
     NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_notifyNoMessageInList(JNIEnv* jenv, jclass, jint, jlong);
     NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_notifyListCreated(JNIEnv* jenv, jclass, jint, jint, jstring, jstring, jstring, jlong, jint, jlong);
     NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_notifyGotNextMessage(JNIEnv* jenv, jclass, jint, jstring, jstring, jstring, jlong, jint, jlong);
     NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_notifyReadingMessageListFailed(JNIEnv* jenv, jclass, jint, jint, jlong);
 
 #ifdef MOZ_JAVA_COMPOSITOR
     NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_bindWidgetTexture(JNIEnv* jenv, jclass);
     NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_scheduleComposite(JNIEnv* jenv, jclass);
+    NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_schedulePauseComposition(JNIEnv* jenv, jclass);
+    NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_scheduleResumeComposition(JNIEnv* jenv, jclass);
 #endif
 
 }
 
 
 /*
  * Incoming JNI methods
  */
@@ -856,9 +858,23 @@ Java_org_mozilla_gecko_GeckoAppShell_bin
 
 NS_EXPORT void JNICALL
 Java_org_mozilla_gecko_GeckoAppShell_scheduleComposite(JNIEnv*, jclass)
 {
     __android_log_print(ANDROID_LOG_ERROR, "Gecko", "### scheduleComposite()");
     AndroidBridge::Bridge()->ScheduleComposite();
 }
 
+NS_EXPORT void JNICALL
+Java_org_mozilla_gecko_GeckoAppShell_schedulePauseComposition(JNIEnv*, jclass)
+{
+    __android_log_print(ANDROID_LOG_ERROR, "Gecko", "### schedulePauseComposition()");
+    AndroidBridge::Bridge()->SchedulePauseComposition();
+}
+
+NS_EXPORT void JNICALL
+Java_org_mozilla_gecko_GeckoAppShell_scheduleResumeComposition(JNIEnv*, jclass)
+{
+    __android_log_print(ANDROID_LOG_ERROR, "Gecko", "### scheduleResumeComposition()");
+    AndroidBridge::Bridge()->ScheduleResumeComposition();
+}
+
 #endif