Expose the necessary Java routines to render decorations through JNI
authorPatrick Walton <pwalton@mozilla.com>
Thu, 09 Feb 2012 22:58:18 -0800
changeset 92425 79653c6e92b5866d12ef625986d06fae99ed710b
parent 92424 737218b404d98ee30d4c43ef7f308449134e20ed
child 92426 44a5593f8133497e1cc87b194413074fc10165ec
push id886
push userlsblakk@mozilla.com
push dateMon, 04 Jun 2012 19:57:52 +0000
treeherdermozilla-beta@bbd8d5efd6d1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone13.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Expose the necessary Java routines to render decorations through JNI
mobile/android/base/gfx/GeckoGLLayerClient.java
mobile/android/base/gfx/LayerRenderer.java
widget/android/AndroidJavaWrappers.cpp
widget/android/AndroidJavaWrappers.h
--- a/mobile/android/base/gfx/GeckoGLLayerClient.java
+++ b/mobile/android/base/gfx/GeckoGLLayerClient.java
@@ -39,23 +39,27 @@ package org.mozilla.gecko.gfx;
 
 import org.mozilla.gecko.GeckoAppShell;
 import org.mozilla.gecko.GeckoEvent;
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.Point;
 import android.graphics.PointF;
 import android.graphics.Rect;
+import android.graphics.RectF;
 import android.util.Log;
 import android.view.View;
 
 public class GeckoGLLayerClient extends GeckoLayerClient
                                 implements FlexibleGLSurfaceView.Listener, VirtualLayer.Listener {
     private static final String LOGTAG = "GeckoGLLayerClient";
 
+    private LayerRenderer mLayerRenderer;
+    private boolean mLayerRendererInitialized;
+
     public GeckoGLLayerClient(Context context) {
         super(context);
     }
 
     @Override
     public boolean beginDrawing(int width, int height, int tileWidth, int tileHeight,
                                 String metadata, boolean hasDirectTexture) {
         if (!super.beginDrawing(width, height, tileWidth, tileHeight, metadata,
@@ -90,17 +94,20 @@ public class GeckoGLLayerClient extends 
         sendResizeEventIfNecessary(true);
         return true;
     }
 
     @Override
     public void setLayerController(LayerController layerController) {
         super.setLayerController(layerController);
 
-        ((FlexibleGLSurfaceView)layerController.getView()).setListener(this);
+        LayerView view = layerController.getView();
+        view.setListener(this);
+
+        mLayerRenderer = new LayerRenderer(view);
     }
 
     @Override
     protected boolean shouldDrawProceed(int tileWidth, int tileHeight) {
         Log.e(LOGTAG, "### shouldDrawProceed");
         // Always draw.
         return true;
     }
@@ -206,10 +213,30 @@ public class GeckoGLLayerClient extends 
 
     public void surfaceChanged(int width, int height) {
         compositionPauseRequested();
         LayerController layerController = getLayerController();
         layerController.setViewportSize(new FloatSize(width, height));
         compositionResumeRequested();
         renderRequested();
     }
+
+    /** For Gecko to use. */
+    public LayerRenderer.Frame createFrame(float offsetX, float offsetY, float zoomFactor) {
+        // Create the shaders and textures if necessary.
+        if (!mLayerRendererInitialized) {
+            mLayerRenderer.onSurfaceCreated(null, null);
+        }
+
+        // FIXME: This geometry is surely wrong.
+        ViewportMetrics metrics = getLayerController().getViewportMetrics();
+        FloatSize pageSize = metrics.getPageSize(), screenSize = metrics.getSize();
+        RectF viewport = new RectF(offsetX, offsetY, offsetX + screenSize.width,
+                                   offsetY + screenSize.height);
+
+        // Build the contexts and create the frame.
+        Layer.RenderContext pageContext = mLayerRenderer.createContext(viewport, pageSize,
+                                                                       zoomFactor);
+        Layer.RenderContext screenContext = mLayerRenderer.createScreenContext();
+        return mLayerRenderer.createFrame(false, pageContext, screenContext);
+    }
 }
 
--- a/mobile/android/base/gfx/LayerRenderer.java
+++ b/mobile/android/base/gfx/LayerRenderer.java
@@ -250,17 +250,18 @@ public class LayerRenderer implements GL
             mExtraLayers.remove(layer);
         }
     }
 
     /**
      * Called whenever a new frame is about to be drawn.
      */
     public void onDrawFrame(GL10 gl) {
-        Frame frame = new Frame(true);
+        RenderContext pageContext = createPageContext(), screenContext = createScreenContext();
+        Frame frame = createFrame(true, pageContext, screenContext);
         synchronized (mView.getController()) {
             frame.beginDrawing();
             frame.drawBackground();
             frame.drawRootLayer();
             frame.drawForeground();
             frame.endDrawing();
         }
     }
@@ -281,35 +282,38 @@ public class LayerRenderer implements GL
                 pixelBuffer.wait();
             } catch (InterruptedException ie) {
             }
             mPixelBuffer = null;
         }
         return pixelBuffer;
     }
 
-    private RenderContext createScreenContext() {
+    public RenderContext createScreenContext() {
         LayerController layerController = mView.getController();
         IntSize viewportSize = new IntSize(layerController.getViewportSize());
         RectF viewport = new RectF(0.0f, 0.0f, viewportSize.width, viewportSize.height);
         FloatSize pageSize = new FloatSize(layerController.getPageSize());
-        return new RenderContext(viewport, pageSize, 1.0f, mPositionHandle, mTextureHandle,
-                                 mCoordBuffer);
+        return createContext(viewport, pageSize, 1.0f);
     }
 
     private RenderContext createPageContext() {
         LayerController layerController = mView.getController();
 
         Rect viewport = new Rect();
         layerController.getViewport().round(viewport);
 
         FloatSize pageSize = new FloatSize(layerController.getPageSize());
         float zoomFactor = layerController.getZoomFactor();
-        return new RenderContext(new RectF(viewport), pageSize, zoomFactor, mPositionHandle,
-                                 mTextureHandle, mCoordBuffer);
+        return createContext(new RectF(viewport), pageSize, zoomFactor);
+    }
+
+    public RenderContext createContext(RectF viewport, FloatSize pageSize, float zoomFactor) {
+        return new RenderContext(viewport, pageSize, zoomFactor, mPositionHandle, mTextureHandle,
+                                 mCoordBuffer);
     }
 
     private Rect getPageRect() {
         LayerController controller = mView.getController();
 
         Point origin = PointUtils.round(controller.getOrigin());
         IntSize pageSize = new IntSize(controller.getPageSize());
 
@@ -418,16 +422,21 @@ public class LayerRenderer implements GL
      */
     private int loadShader(int type, String shaderCode) {
         int shader = GLES20.glCreateShader(type);
         GLES20.glShaderSource(shader, shaderCode);
         GLES20.glCompileShader(shader);
         return shader;
     }
 
+    public Frame createFrame(boolean scissor, RenderContext pageContext,
+                             RenderContext screenContext) {
+        return new Frame(scissor, pageContext, screenContext);
+    }
+
     class FadeRunnable implements Runnable {
         private boolean mStarted;
         private long mRunAt;
 
         void scheduleStartFade(long delay) {
             mRunAt = SystemClock.elapsedRealtime() + delay;
             if (!mStarted) {
                 mView.postDelayed(this, delay);
@@ -464,33 +473,32 @@ public class LayerRenderer implements GL
         private final boolean mScissor;
         // The timestamp recording the start of this frame.
         private long mFrameStartTime;
         // A rendering context for page-positioned layers, and one for screen-positioned layers.
         private RenderContext mPageContext, mScreenContext;
         // Whether a layer was updated.
         private boolean mUpdated;
 
-        public Frame(boolean scissor) {
+        public Frame(boolean scissor, RenderContext pageContext, RenderContext screenContext) {
             mScissor = scissor;
+            mPageContext = pageContext;
+            mScreenContext = screenContext;
         }
 
         public void beginDrawing() {
             mFrameStartTime = SystemClock.uptimeMillis();
 
             TextureReaper.get().reap();
             TextureGenerator.get().fill();
 
-            LayerController controller = mView.getController();
-            mScreenContext = createScreenContext();
-
             mUpdated = true;
 
+            LayerController controller = mView.getController();
             Layer rootLayer = controller.getRoot();
-            mPageContext = createPageContext();
 
             if (!mPageContext.fuzzyEquals(mLastPageContext)) {
                 // the viewport or page changed, so show the scrollbars again
                 // as per UX decision
                 mVertScrollLayer.unfade();
                 mHorizScrollLayer.unfade();
                 mFadeRunnable.scheduleStartFade(ScrollbarLayer.FADE_DELAY);
             } else if (mFadeRunnable.timeToFade()) {
@@ -553,17 +561,17 @@ public class LayerRenderer implements GL
                                  scissorRect.width(), scissorRect.height());
             }
 
             /* Draw the checkerboard. */
             mCheckerboardLayer.draw(mScreenContext);
         }
 
         // Draws the layer the client added to us.
-        public void drawRootLayer() {
+        void drawRootLayer() {
             Layer rootLayer = mView.getController().getRoot();
             if (rootLayer != null)
                 rootLayer.draw(mPageContext);
         }
 
         public void drawForeground() {
             Rect pageRect = getPageRect();
             LayerController controller = mView.getController();
--- a/widget/android/AndroidJavaWrappers.cpp
+++ b/widget/android/AndroidJavaWrappers.cpp
@@ -115,16 +115,23 @@ jmethodID AndroidGeckoLayerClient::jEndD
 
 jclass AndroidGeckoSoftwareLayerClient::jGeckoSoftwareLayerClientClass = 0;
 jmethodID AndroidGeckoSoftwareLayerClient::jLockBufferMethod = 0;
 jmethodID AndroidGeckoSoftwareLayerClient::jUnlockBufferMethod = 0;
 jmethodID AndroidGeckoSoftwareLayerClient::jGetRenderOffsetMethod = 0;
 
 jclass AndroidGeckoGLLayerClient::jGeckoGLLayerClientClass = 0;
 jmethodID AndroidGeckoGLLayerClient::jGetViewTransformMethod = 0;
+jmethodID AndroidGeckoGLLayerClient::jCreateFrameMethod = 0;
+
+jclass AndroidLayerRendererFrame::jLayerRendererFrameClass = 0;
+jmethodID AndroidLayerRendererFrame::jBeginDrawingMethod = 0;
+jmethodID AndroidLayerRendererFrame::jDrawBackgroundMethod = 0;
+jmethodID AndroidLayerRendererFrame::jDrawForegroundMethod = 0;
+jmethodID AndroidLayerRendererFrame::jEndDrawingMethod = 0;
 
 jclass AndroidViewTransform::jViewTransformClass = 0;
 jfieldID AndroidViewTransform::jXField = 0;
 jfieldID AndroidViewTransform::jYField = 0;
 jfieldID AndroidViewTransform::jScaleField = 0;
 
 jmethodID AndroidGeckoSoftwareLayerClient::jBeginDrawingMethod = 0;
 jmethodID AndroidGeckoSoftwareLayerClient::jEndDrawingMethod = 0;
@@ -157,16 +164,17 @@ mozilla::InitAndroidJavaWrappers(JNIEnv 
     AndroidGeckoEvent::InitGeckoEventClass(jEnv);
     AndroidPoint::InitPointClass(jEnv);
     AndroidLocation::InitLocationClass(jEnv);
     AndroidAddress::InitAddressClass(jEnv);
     AndroidRect::InitRectClass(jEnv);
     AndroidGeckoLayerClient::InitGeckoLayerClientClass(jEnv);
     AndroidGeckoSoftwareLayerClient::InitGeckoSoftwareLayerClientClass(jEnv);
     AndroidGeckoGLLayerClient::InitGeckoGLLayerClientClass(jEnv);
+    AndroidLayerRendererFrame::InitLayerRendererFrameClass(jEnv);
     AndroidViewTransform::InitViewTransformClass(jEnv);
     AndroidGeckoSurfaceView::InitGeckoSurfaceViewClass(jEnv);
 }
 
 void
 AndroidGeckoEvent::InitGeckoEventClass(JNIEnv *jEnv)
 {
     initInit();
@@ -372,16 +380,33 @@ AndroidGeckoGLLayerClient::InitGeckoGLLa
 {
 #ifdef MOZ_JAVA_COMPOSITOR
     initInit();
 
     jGeckoGLLayerClientClass = getClassGlobalRef("org/mozilla/gecko/gfx/GeckoGLLayerClient");
 
     jGetViewTransformMethod = getMethod("getViewTransform",
                                         "()Lorg/mozilla/gecko/gfx/ViewTransform;");
+    jCreateFrameMethod = getMethod("createFrame",
+                                   "(FFF)Lorg/mozilla/gecko/gfx/LayerRenderer$Frame;");
+#endif
+}
+
+void
+AndroidLayerRendererFrame::InitLayerRendererFrameClass(JNIEnv *jEnv)
+{
+#ifdef MOZ_JAVA_COMPOSITOR
+    initInit();
+
+    jLayerRendererFrameClass = getClassGlobalRef("org/mozilla/gecko/gfx/LayerRenderer$Frame");
+
+    jBeginDrawingMethod = getMethod("beginDrawing", "()V");
+    jDrawBackgroundMethod = getMethod("drawBackground", "()V");
+    jDrawForegroundMethod = getMethod("drawForeground", "()V");
+    jEndDrawingMethod = getMethod("endDrawing", "()V");
 #endif
 }
 
 void
 AndroidViewTransform::InitViewTransformClass(JNIEnv *jEnv)
 {
 #ifdef MOZ_JAVA_COMPOSITOR
     initInit();
@@ -662,16 +687,23 @@ AndroidGeckoGLLayerClient::Init(jobject 
     NS_ASSERTION(wrapped_obj == nsnull, "Init called on non-null wrapped_obj!");
     wrapped_obj = jobj;
 
     // Register the view transform getter.
     AndroidBridge::Bridge()->SetViewTransformGetter(mViewTransformGetter);
 }
 
 void
+AndroidLayerRendererFrame::Init(jobject jobj)
+{
+    NS_ASSERTION(wrapped_obj == nsnull, "Init called on non-null wrapped_obj!");
+    wrapped_obj = jobj;
+}
+
+void
 AndroidViewTransform::Init(jobject jobj)
 {
     NS_ABORT_IF_FALSE(wrapped_obj == nsnull, "Init called on non-null wrapped_obj!");
     wrapped_obj = jobj;
 }
 
 void
 AndroidGeckoSurfaceView::Init(jobject jobj)
@@ -875,16 +907,80 @@ AndroidGeckoGLLayerClient::GetViewTransf
         return;
     }
 
     jobject viewTransformJObj = env->CallObjectMethod(wrapped_obj, jGetViewTransformMethod);
     NS_ABORT_IF_FALSE(viewTransformJObj, "No view transform object!");
     aViewTransform.Init(viewTransformJObj);
 }
 
+void
+AndroidGeckoGLLayerClient::CreateFrame(AndroidLayerRendererFrame& aFrame,
+                                       float aXOffset, float aYOffset, float aZoomFactor)
+{
+    JNIEnv *env = GetJNIForThread();
+    NS_ABORT_IF_FALSE(env, "No JNI environment at CreateFrame()!");
+    if (!env) {
+        return;
+    }
+
+    jobject frameJObj = env->CallObjectMethod(wrapped_obj, jCreateFrameMethod, aXOffset, aYOffset,
+                                              aZoomFactor);
+    NS_ABORT_IF_FALSE(frameJObj, "No frame object!");
+    aFrame.Init(frameJObj);
+}
+
+void
+AndroidLayerRendererFrame::BeginDrawing()
+{
+    JNIEnv *env = GetJNIForThread();
+    NS_ABORT_IF_FALSE(env, "No JNI environment at BeginDrawing()!");
+    if (!env) {
+        return;
+    }
+
+    env->CallVoidMethod(wrapped_obj, jBeginDrawingMethod);
+}
+
+void
+AndroidLayerRendererFrame::DrawBackground()
+{
+    JNIEnv *env = GetJNIForThread();
+    NS_ABORT_IF_FALSE(env, "No JNI environment at DrawBackground()!");
+    if (!env) {
+        return;
+    }
+
+    env->CallVoidMethod(wrapped_obj, jDrawBackgroundMethod);
+}
+
+void
+AndroidLayerRendererFrame::DrawForeground()
+{
+    JNIEnv *env = GetJNIForThread();
+    NS_ABORT_IF_FALSE(env, "No JNI environment at DrawForeground()!");
+    if (!env) {
+        return;
+    }
+
+    env->CallVoidMethod(wrapped_obj, jDrawForegroundMethod);
+}
+
+void
+AndroidLayerRendererFrame::EndDrawing()
+{
+    JNIEnv *env = GetJNIForThread();
+    NS_ABORT_IF_FALSE(env, "No JNI environment at EndDrawing()!");
+    if (!env) {
+        return;
+    }
+
+    env->CallVoidMethod(wrapped_obj, jEndDrawingMethod);
+}
+
 float
 AndroidViewTransform::GetX()
 {
     JNIEnv *env = GetJNIForThread();
     if (!env)
         return 0.0f;
     return env->GetFloatField(wrapped_obj, jXField);
 }
--- a/widget/android/AndroidJavaWrappers.h
+++ b/widget/android/AndroidJavaWrappers.h
@@ -232,33 +232,55 @@ public:
 
 private:
     static jclass jViewTransformClass;
     static jfieldID jXField;
     static jfieldID jYField;
     static jfieldID jScaleField;
 };
 
+class AndroidLayerRendererFrame : public WrappedJavaObject {
+public:
+    static void InitLayerRendererFrameClass(JNIEnv *jEnv);
+
+    void Init(jobject jobj);
+
+    void BeginDrawing();
+    void DrawBackground();
+    void DrawForeground();
+    void EndDrawing();
+
+private:
+    static jclass jLayerRendererFrameClass;
+    static jmethodID jBeginDrawingMethod;
+    static jmethodID jDrawBackgroundMethod;
+    static jmethodID jDrawForegroundMethod;
+    static jmethodID jEndDrawingMethod;
+};
+
 class AndroidGeckoGLLayerClient : public AndroidGeckoLayerClient {
 public:
     static void InitGeckoGLLayerClientClass(JNIEnv *jEnv);
 
     void Init(jobject jobj);
 
     AndroidGeckoGLLayerClient()
     : mViewTransformGetter(*this) {}
 
     AndroidGeckoGLLayerClient(jobject jobj)
     : mViewTransformGetter(*this) { Init(jobj); }
 
     void GetViewTransform(AndroidViewTransform& aViewTransform);
+    void CreateFrame(AndroidLayerRendererFrame& aFrame, float aXOffset, float aYOffset,
+                     float aZoomFactor);
 
 private:
     static jclass jGeckoGLLayerClientClass;
     static jmethodID jGetViewTransformMethod;
+    static jmethodID jCreateFrameMethod;
 
     AndroidGeckoGLLayerClientViewTransformGetter mViewTransformGetter;
 };
 
 class AndroidGeckoSurfaceView : public WrappedJavaObject
 {
 public:
     static void InitGeckoSurfaceViewClass(JNIEnv *jEnv);