Bug 1166309 - Fix startup crashes in standalone GeckoView. r=snorp, r=mfinkle, r=rnewman, a=sledru
authorJim Chen <nchen@mozilla.com>
Thu, 11 Jun 2015 13:04:00 -0400
changeset 275064 1ec10fb571da53b1a62206f2570b3311bec6a8ef
parent 275063 c65ac58ea75e4fda27cc8ce5151565c727c93afb
child 275065 7333a8d7b494c79743a88056a03810f150a0fce8
push id863
push userraliiev@mozilla.com
push dateMon, 03 Aug 2015 13:22:43 +0000
treeherdermozilla-release@f6321b14228d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssnorp, mfinkle, rnewman, sledru
bugs1166309
milestone40.0a2
Bug 1166309 - Fix startup crashes in standalone GeckoView. r=snorp, r=mfinkle, r=rnewman, a=sledru
mobile/android/base/GeckoView.java
mobile/android/base/gfx/BufferedImage.java
mobile/android/base/gfx/LayerRenderer.java
--- a/mobile/android/base/GeckoView.java
+++ b/mobile/android/base/GeckoView.java
@@ -114,16 +114,24 @@ public class GeckoView extends LayerView
         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.GeckoView);
         String url = a.getString(R.styleable.GeckoView_url);
         boolean doInit = a.getBoolean(R.styleable.GeckoView_doinit, true);
         a.recycle();
         init(context, url, doInit);
     }
 
     private void init(Context context, String url, boolean doInit) {
+
+        // Set the GeckoInterface if the context is an activity and the GeckoInterface
+        // has not already been set
+        if (context instanceof Activity && getGeckoInterface() == null) {
+            setGeckoInterface(new BaseGeckoInterface(context));
+            GeckoAppShell.setContextGetter(this);
+        }
+
         // Perform common initialization for Fennec/GeckoView.
         GeckoAppShell.setLayerView(this);
 
         initializeView(EventDispatcher.getInstance());
         GeckoAppShell.sendEventToGecko(GeckoEvent.createObjectEvent(
                 GeckoEvent.ACTION_OBJECT_LAYER_CLIENT, getLayerClientObject()));
 
         // TODO: Fennec currently takes care of its own initialization, so this
@@ -136,22 +144,16 @@ public class GeckoView extends LayerView
         // If running outside of a GeckoActivity (eg, from a library project),
         // load the native code and disable content providers
         boolean isGeckoActivity = false;
         try {
             isGeckoActivity = context instanceof GeckoActivity;
         } catch (NoClassDefFoundError ex) {}
 
         if (!isGeckoActivity) {
-            // Set the GeckoInterface if the context is an activity and the GeckoInterface
-            // has not already been set
-            if (context instanceof Activity && getGeckoInterface() == null) {
-                setGeckoInterface(new BaseGeckoInterface(context));
-            }
-
             Clipboard.init(context);
             HardwareUtils.init(context);
 
             // If you want to use GeckoNetworkManager, start it.
 
             GeckoLoader.loadMozGlue(context);
 
             final GeckoProfile profile = GeckoProfile.get(context);
@@ -159,17 +161,16 @@ public class GeckoView extends LayerView
 
         if (url != null) {
             GeckoThread.ensureInit(null, Intent.ACTION_VIEW, url);
             GeckoAppShell.sendEventToGecko(GeckoEvent.createURILoadEvent(url));
         } else {
             GeckoThread.ensureInit(null, null, null);
         }
 
-        GeckoAppShell.setContextGetter(this);
         if (context instanceof Activity) {
             Tabs tabs = Tabs.getInstance();
             tabs.attachToContext(context);
         }
 
         EventDispatcher.getInstance().registerGeckoThreadListener(mGeckoEventListener,
             "Gecko:Ready",
             "Accessibility:Event",
--- a/mobile/android/base/gfx/BufferedImage.java
+++ b/mobile/android/base/gfx/BufferedImage.java
@@ -10,49 +10,58 @@ import org.mozilla.gecko.mozglue.DirectB
 import android.graphics.Bitmap;
 import android.util.Log;
 
 import java.nio.ByteBuffer;
 
 /** A buffered image that simply saves a buffer of pixel data. */
 public class BufferedImage {
     private ByteBuffer mBuffer;
+    private Bitmap mBitmap;
     private IntSize mSize;
     private int mFormat;
 
     private static final String LOGTAG = "GeckoBufferedImage";
 
     /** Creates an empty buffered image */
     public BufferedImage() {
         mSize = new IntSize(0, 0);
     }
 
     /** Creates a buffered image from an Android bitmap. */
     public BufferedImage(Bitmap bitmap) {
         mFormat = bitmapConfigToFormat(bitmap.getConfig());
         mSize = new IntSize(bitmap.getWidth(), bitmap.getHeight());
-
-        int bpp = bitsPerPixelForFormat(mFormat);
-        mBuffer = DirectBufferAllocator.allocate(mSize.getArea() * bpp);
-        bitmap.copyPixelsToBuffer(mBuffer.asIntBuffer());
+        mBitmap = bitmap;
     }
 
     private synchronized void freeBuffer() {
-        mBuffer = DirectBufferAllocator.free(mBuffer);
+        if (mBuffer != null) {
+            mBuffer = DirectBufferAllocator.free(mBuffer);
+        }
     }
 
     public void destroy() {
         try {
             freeBuffer();
         } catch (Exception ex) {
             Log.e(LOGTAG, "error clearing buffer: ", ex);
         }
     }
 
-    public ByteBuffer getBuffer() { return mBuffer; }
+    public ByteBuffer getBuffer() {
+        if (mBuffer == null) {
+            int bpp = bitsPerPixelForFormat(mFormat);
+            mBuffer = DirectBufferAllocator.allocate(mSize.getArea() * bpp);
+            mBitmap.copyPixelsToBuffer(mBuffer.asIntBuffer());
+            mBitmap = null;
+        }
+        return mBuffer;
+    }
+
     public IntSize getSize() { return mSize; }
     public int getFormat() { return mFormat; }
 
     public static final int FORMAT_INVALID = -1;
     public static final int FORMAT_ARGB32 = 0;
     public static final int FORMAT_RGB24 = 1;
     public static final int FORMAT_A8 = 2;
     public static final int FORMAT_A1 = 3;
--- a/mobile/android/base/gfx/LayerRenderer.java
+++ b/mobile/android/base/gfx/LayerRenderer.java
@@ -156,22 +156,16 @@ public class LayerRenderer implements Ta
 
         mVertScrollLayer = new ScrollbarLayer(this, scrollbarImage, size, true);
         mHorizScrollLayer = new ScrollbarLayer(this, diagonalFlip(scrollbarImage), new IntSize(size.height, size.width), false);
         mFadeRunnable = new FadeRunnable();
 
         mFrameTimings = new int[60];
         mCurrentFrame = mFrameTimingsSum = mDroppedFrames = 0;
 
-        // Initialize the FloatBuffer that will be used to store all vertices and texture
-        // coordinates in draw() commands.
-        mCoordByteBuffer = DirectBufferAllocator.allocate(COORD_BUFFER_SIZE * 4);
-        mCoordByteBuffer.order(ByteOrder.nativeOrder());
-        mCoordBuffer = mCoordByteBuffer.asFloatBuffer();
-
         Tabs.registerOnTabsChangedListener(this);
         mZoomedViewListeners = new ArrayList<LayerView.ZoomedViewListener>();
     }
 
     private Bitmap expandCanvasToPowerOfTwo(Bitmap image, IntSize size) {
         IntSize potSize = size.nextPowerOfTwo();
         if (size.equals(potSize)) {
             return image;
@@ -185,19 +179,21 @@ public class LayerRenderer implements Ta
     private Bitmap diagonalFlip(Bitmap image) {
         Matrix rotation = new Matrix();
         rotation.setValues(new float[] { 0, 1, 0, 1, 0, 0, 0, 0, 1 }); // transform (x,y) into (y,x)
         Bitmap rotated = Bitmap.createBitmap(image, 0, 0, image.getWidth(), image.getHeight(), rotation, true);
         return rotated;
     }
 
     public void destroy() {
-        DirectBufferAllocator.free(mCoordByteBuffer);
-        mCoordByteBuffer = null;
-        mCoordBuffer = null;
+        if (mCoordByteBuffer != null) {
+            DirectBufferAllocator.free(mCoordByteBuffer);
+            mCoordByteBuffer = null;
+            mCoordBuffer = null;
+        }
         mHorizScrollLayer.destroy();
         mVertScrollLayer.destroy();
         Tabs.unregisterOnTabsChangedListener(this);
         mZoomedViewListeners.clear();
     }
 
     void onSurfaceCreated(EGLConfig config) {
         checkMonitoringEnabled();
@@ -343,20 +339,27 @@ public class LayerRenderer implements Ta
         RectF pageRect = metrics.getPageRect();
         float zoomFactor = metrics.zoomFactor;
 
         return createContext(new RectF(RectUtils.round(viewport)), pageRect, zoomFactor, offset);
     }
 
     private RenderContext createContext(RectF viewport, RectF pageRect, float zoomFactor, PointF offset) {
         if (mCoordBuffer == null) {
-            throw new IllegalStateException();
+            // Initialize the FloatBuffer that will be used to store all vertices and texture
+            // coordinates in draw() commands.
+            mCoordByteBuffer = DirectBufferAllocator.allocate(COORD_BUFFER_SIZE * 4);
+            mCoordByteBuffer.order(ByteOrder.nativeOrder());
+            mCoordBuffer = mCoordByteBuffer.asFloatBuffer();
+            if (mCoordBuffer == null) {
+                throw new IllegalStateException();
+            }
         }
-        return new RenderContext(viewport, pageRect, zoomFactor, offset, mPositionHandle, mTextureHandle,
-                                 mCoordBuffer);
+        return new RenderContext(viewport, pageRect, zoomFactor, offset,
+                                 mPositionHandle, mTextureHandle, mCoordBuffer);
     }
 
     private void updateDroppedFrames(long frameStartTime) {
         int frameElapsedTime = (int)((System.nanoTime() - frameStartTime) / NANOS_PER_MS);
 
         /* Update the running statistics. */
         mFrameTimingsSum -= mFrameTimings[mCurrentFrame];
         mFrameTimingsSum += frameElapsedTime;