Bug 913985: Part 2 - Add annotations to all remaining JNI entry points, marking them for generations. r=kats
☠☠ backed out by 162303fb6a9e ☠ ☠
authorChris Kitching <ckitching@mozilla.com>
Mon, 30 Sep 2013 09:07:16 +0200
changeset 149230 08844da6d9edcad252e780864f345a2f1855cd26
parent 149229 044255192754a5fad12d4b30f9683f0c393c9c7c
child 149231 b44508a5c02fec51d896e8f10d05c8e45a51f5ee
push id25380
push userryanvm@gmail.com
push dateMon, 30 Sep 2013 20:16:36 +0000
treeherdermozilla-central@1332fc1c15e1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskats
bugs913985
milestone27.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
Bug 913985: Part 2 - Add annotations to all remaining JNI entry points, marking them for generations. r=kats
mobile/android/base/GeckoEvent.java
mobile/android/base/SurfaceBits.java
mobile/android/base/gfx/DisplayPortMetrics.java
mobile/android/base/gfx/GeckoLayerClient.java
mobile/android/base/gfx/ImmutableViewportMetrics.java
mobile/android/base/gfx/LayerRenderer.java
mobile/android/base/gfx/ProgressiveUpdateData.java
mobile/android/base/gfx/ViewTransform.java
mobile/android/base/mozglue/NativeZip.java
mobile/android/base/sqlite/MatrixBlobCursor.java
mobile/android/base/sqlite/SQLiteBridgeException.java
mobile/android/base/util/Clipboard.java
--- a/mobile/android/base/GeckoEvent.java
+++ b/mobile/android/base/GeckoEvent.java
@@ -2,16 +2,18 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko;
 
 import org.mozilla.gecko.gfx.DisplayPortMetrics;
 import org.mozilla.gecko.gfx.ImmutableViewportMetrics;
+import org.mozilla.gecko.mozglue.generatorannotations.GeneratorOptions;
+import org.mozilla.gecko.mozglue.generatorannotations.WrapEntireClassForJNI;
 
 import android.content.res.Resources;
 import android.graphics.Point;
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.hardware.Sensor;
 import android.hardware.SensorEvent;
 import android.hardware.SensorManager;
@@ -78,16 +80,18 @@ public class GeckoEvent {
             this.value = value;
          }
     }
 
     /**
      * The DomKeyLocation enum encapsulates the DOM KeyboardEvent's constants.
      * @see https://developer.mozilla.org/en-US/docs/DOM/KeyboardEvent#Key_location_constants
      */
+    @GeneratorOptions(generatedClassName = "JavaDomKeyLocation")
+    @WrapEntireClassForJNI
     public enum DomKeyLocation {
         DOM_KEY_LOCATION_STANDARD(0),
         DOM_KEY_LOCATION_LEFT(1),
         DOM_KEY_LOCATION_RIGHT(2),
         DOM_KEY_LOCATION_NUMPAD(3),
         DOM_KEY_LOCATION_MOBILE(4),
         DOM_KEY_LOCATION_JOYSTICK(5);
 
--- a/mobile/android/base/SurfaceBits.java
+++ b/mobile/android/base/SurfaceBits.java
@@ -1,14 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko;
 
+import org.mozilla.gecko.mozglue.generatorannotations.WrapEntireClassForJNI;
+
 import java.nio.ByteBuffer;
 
+@WrapEntireClassForJNI
 public class SurfaceBits {
     public int width;
     public int height;
     public int format;
     public ByteBuffer buffer;
 }
--- a/mobile/android/base/gfx/DisplayPortMetrics.java
+++ b/mobile/android/base/gfx/DisplayPortMetrics.java
@@ -1,35 +1,39 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.gfx;
 
+import org.mozilla.gecko.mozglue.generatorannotations.WrapElementForJNI;
 import org.mozilla.gecko.util.FloatUtils;
 
 import android.graphics.RectF;
 
 /*
  * This class keeps track of the area we request Gecko to paint, as well
  * as the resolution of the paint. The area may be different from the visible
  * area of the page, and the resolution may be different from the resolution
  * used in the compositor to render the page. This is so that we can ask Gecko
  * to paint a much larger area without using extra memory, and then render some
  * subsection of that with compositor scaling.
  */
 public final class DisplayPortMetrics {
+    @WrapElementForJNI
     public final float resolution;
+    @WrapElementForJNI
     private final RectF mPosition;
 
     public DisplayPortMetrics() {
         this(0, 0, 0, 0, 1);
     }
 
+    @WrapElementForJNI
     public DisplayPortMetrics(float left, float top, float right, float bottom, float resolution) {
         this.resolution = resolution;
         mPosition = new RectF(left, top, right, bottom);
     }
 
     public float getLeft() {
         return mPosition.left;
     }
--- a/mobile/android/base/gfx/GeckoLayerClient.java
+++ b/mobile/android/base/gfx/GeckoLayerClient.java
@@ -6,16 +6,17 @@
 package org.mozilla.gecko.gfx;
 
 import org.mozilla.gecko.BrowserApp;
 import org.mozilla.gecko.GeckoAppShell;
 import org.mozilla.gecko.GeckoEvent;
 import org.mozilla.gecko.Tab;
 import org.mozilla.gecko.Tabs;
 import org.mozilla.gecko.ZoomConstraints;
+import org.mozilla.gecko.mozglue.generatorannotations.WrapElementForJNI;
 import org.mozilla.gecko.util.EventDispatcher;
 import org.mozilla.gecko.util.FloatUtils;
 import org.mozilla.gecko.util.ThreadUtils;
 
 import android.content.Context;
 import android.graphics.PointF;
 import android.graphics.RectF;
 import android.os.SystemClock;
@@ -408,48 +409,49 @@ public class GeckoLayerClient implements
             });
 
             setViewportMetrics(newMetrics, type == ViewportMessageType.UPDATE);
             mDisplayPort = DisplayPortCalculator.calculate(getViewportMetrics(), null);
         }
         return mDisplayPort;
     }
 
-    /* This is invoked by JNI on the gecko thread */
+    @WrapElementForJNI
     DisplayPortMetrics getDisplayPort(boolean pageSizeUpdate, boolean isBrowserContentDisplayed, int tabId, ImmutableViewportMetrics metrics) {
         Tabs tabs = Tabs.getInstance();
         if (tabs.isSelectedTab(tabs.getTab(tabId)) && isBrowserContentDisplayed) {
             // for foreground tabs, send the viewport update unless the document
             // displayed is different from the content document. In that case, just
             // calculate the display port.
             return handleViewportMessage(metrics, pageSizeUpdate ? ViewportMessageType.PAGE_SIZE : ViewportMessageType.UPDATE);
         } else {
             // for background tabs, request a new display port calculation, so that
             // when we do switch to that tab, we have the correct display port and
             // don't need to draw twice (once to allow the first-paint viewport to
             // get to java, and again once java figures out the display port).
             return DisplayPortCalculator.calculate(metrics, null);
         }
     }
 
-    /* This is invoked by JNI on the gecko thread */
+    @WrapElementForJNI
     void contentDocumentChanged() {
         mContentDocumentIsDisplayed = false;
     }
 
-    /* This is invoked by JNI on the gecko thread */
+    @WrapElementForJNI
     boolean isContentDocumentDisplayed() {
         return mContentDocumentIsDisplayed;
     }
 
     // This is called on the Gecko thread to determine if we're still interested
     // in the update of this display-port to continue. We can return true here
     // to abort the current update and continue with any subsequent ones. This
     // is useful for slow-to-render pages when the display-port starts lagging
     // behind enough that continuing to draw it is wasted effort.
+    @WrapElementForJNI(allowMultithread = true)
     public ProgressiveUpdateData progressiveUpdateCallback(boolean aHasPendingNewThebesContent,
                                                            float x, float y, float width, float height,
                                                            float resolution, boolean lowPrecision) {
         // Reset the checkerboard risk flag when switching to low precision
         // rendering.
         if (lowPrecision && !mLastProgressiveUpdateWasLowPrecision) {
             // Skip low precision rendering until we're at risk of checkerboarding.
             if (!mProgressiveUpdateWasInDanger) {
@@ -547,23 +549,23 @@ public class GeckoLayerClient implements
 
     void setIsRTL(boolean aIsRTL) {
         synchronized (getLock()) {
             ImmutableViewportMetrics newMetrics = getViewportMetrics().setIsRTL(aIsRTL);
             setViewportMetrics(newMetrics, false);
         }
     }
 
-    /** This function is invoked by Gecko via JNI; be careful when modifying signature.
-      * The compositor invokes this function just before compositing a frame where the document
+    /** The compositor invokes this function just before compositing a frame where the document
       * is different from the document composited on the last frame. In these cases, the viewport
       * information we have in Java is no longer valid and needs to be replaced with the new
       * viewport information provided. setPageRect will never be invoked on the same frame that
       * this function is invoked on; and this function will always be called prior to syncViewportInfo.
       */
+    @WrapElementForJNI(allowMultithread = true)
     public void setFirstPaintViewport(float offsetX, float offsetY, float zoom,
             float cssPageLeft, float cssPageTop, float cssPageRight, float cssPageBottom) {
         synchronized (getLock()) {
             ImmutableViewportMetrics currentMetrics = getViewportMetrics();
 
             Tab tab = Tabs.getInstance().getSelectedTab();
 
             RectF cssPageRect = new RectF(cssPageLeft, cssPageTop, cssPageRight, cssPageBottom);
@@ -606,43 +608,43 @@ public class GeckoLayerClient implements
             }
         }
         DisplayPortCalculator.resetPageState();
         mDrawTimingQueue.reset();
 
         mContentDocumentIsDisplayed = true;
     }
 
-    /** This function is invoked by Gecko via JNI; be careful when modifying signature.
-      * The compositor invokes this function whenever it determines that the page rect
+    /** The compositor invokes this function whenever it determines that the page rect
       * has changed (based on the information it gets from layout). If setFirstPaintViewport
       * is invoked on a frame, then this function will not be. For any given frame, this
       * function will be invoked before syncViewportInfo.
       */
+    @WrapElementForJNI(allowMultithread = true)
     public void setPageRect(float cssPageLeft, float cssPageTop, float cssPageRight, float cssPageBottom) {
         synchronized (getLock()) {
             RectF cssPageRect = new RectF(cssPageLeft, cssPageTop, cssPageRight, cssPageBottom);
             float ourZoom = getViewportMetrics().zoomFactor;
             setPageRect(RectUtils.scale(cssPageRect, ourZoom), cssPageRect);
             // Here the page size of the document has changed, but the document being displayed
             // is still the same. Therefore, we don't need to send anything to browser.js; any
             // changes we need to make to the display port will get sent the next time we call
             // adjustViewport().
         }
     }
 
-    /** This function is invoked by Gecko via JNI; be careful when modifying signature.
-      * The compositor invokes this function on every frame to figure out what part of the
+    /** The compositor invokes this function on every frame to figure out what part of the
       * page to display, and to inform Java of the current display port. Since it is called
       * on every frame, it needs to be ultra-fast.
       * It avoids taking any locks or allocating any objects. We keep around a
       * mCurrentViewTransform so we don't need to allocate a new ViewTransform
       * everytime we're called. NOTE: we might be able to return a ImmutableViewportMetrics
       * which would avoid the copy into mCurrentViewTransform.
       */
+    @WrapElementForJNI(allowMultithread = true)
     public ViewTransform syncViewportInfo(int x, int y, int width, int height, float resolution, boolean layersUpdated) {
         // getViewportMetrics is thread safe so we don't need to synchronize.
         // We save the viewport metrics here, so we later use it later in
         // createFrame (which will be called by nsWindow::DrawWindowUnderlay on
         // the native side, by the compositor). The viewport
         // metrics can change between here and there, as it's accessed outside
         // of the compositor thread.
         mFrameMetrics = getViewportMetrics();
@@ -686,48 +688,48 @@ public class GeckoLayerClient implements
         if (layersUpdated && mDrawListener != null) {
             /* Used by robocop for testing purposes */
             mDrawListener.drawFinished();
         }
 
         return mCurrentViewTransform;
     }
 
-    /* Invoked by JNI from the compositor thread */
+    @WrapElementForJNI(allowMultithread = true)
     public ViewTransform syncFrameMetrics(float offsetX, float offsetY, float zoom,
                 float cssPageLeft, float cssPageTop, float cssPageRight, float cssPageBottom,
                 boolean layersUpdated, int x, int y, int width, int height, float resolution,
                 boolean isFirstPaint)
     {
         if (isFirstPaint) {
             setFirstPaintViewport(offsetX, offsetY, zoom,
                                   cssPageLeft, cssPageTop, cssPageRight, cssPageBottom);
         }
 
         return syncViewportInfo(x, y, width, height, resolution, layersUpdated);
     }
 
-    /** This function is invoked by Gecko via JNI; be careful when modifying signature. */
+    @WrapElementForJNI(allowMultithread = true)
     public LayerRenderer.Frame createFrame() {
         // Create the shaders and textures if necessary.
         if (!mLayerRendererInitialized) {
             mLayerRenderer.checkMonitoringEnabled();
             mLayerRenderer.createDefaultProgram();
             mLayerRendererInitialized = true;
         }
 
         return mLayerRenderer.createFrame(mFrameMetrics);
     }
 
-    /** This function is invoked by Gecko via JNI; be careful when modifying signature. */
+    @WrapElementForJNI(allowMultithread = true)
     public void activateProgram() {
         mLayerRenderer.activateDefaultProgram();
     }
 
-    /** This function is invoked by Gecko via JNI; be careful when modifying signature. */
+    @WrapElementForJNI(allowMultithread = true)
     public void deactivateProgram() {
         mLayerRenderer.deactivateDefaultProgram();
     }
 
     private void geometryChanged(DisplayPortMetrics displayPort) {
         /* Let Gecko know if the screensize has changed */
         sendResizeEventIfNecessary(false);
         if (getRedrawHint()) {
--- a/mobile/android/base/gfx/ImmutableViewportMetrics.java
+++ b/mobile/android/base/gfx/ImmutableViewportMetrics.java
@@ -1,15 +1,16 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.gfx;
 
+import org.mozilla.gecko.mozglue.generatorannotations.WrapElementForJNI;
 import org.mozilla.gecko.util.FloatUtils;
 
 import android.graphics.PointF;
 import android.graphics.RectF;
 import android.util.DisplayMetrics;
 
 /**
  * ImmutableViewportMetrics are used to store the viewport metrics
@@ -47,17 +48,18 @@ public class ImmutableViewportMetrics {
         marginLeft = marginTop = marginRight = marginBottom = 0;
         zoomFactor = 1.0f;
         isRTL = false;
     }
 
     /** This constructor is used by native code in AndroidJavaWrappers.cpp, be
      * careful when modifying the signature.
      */
-    private ImmutableViewportMetrics(float aPageRectLeft, float aPageRectTop,
+    @WrapElementForJNI(allowMultithread = true)
+    public ImmutableViewportMetrics(float aPageRectLeft, float aPageRectTop,
         float aPageRectRight, float aPageRectBottom, float aCssPageRectLeft,
         float aCssPageRectTop, float aCssPageRectRight, float aCssPageRectBottom,
         float aViewportRectLeft, float aViewportRectTop, float aViewportRectRight,
         float aViewportRectBottom, float aZoomFactor)
     {
         this(aPageRectLeft, aPageRectTop,
              aPageRectRight, aPageRectBottom, aCssPageRectLeft,
              aCssPageRectTop, aCssPageRectRight, aCssPageRectBottom,
--- a/mobile/android/base/gfx/LayerRenderer.java
+++ b/mobile/android/base/gfx/LayerRenderer.java
@@ -7,24 +7,25 @@ package org.mozilla.gecko.gfx;
 
 import org.mozilla.gecko.GeckoAppShell;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.Tab;
 import org.mozilla.gecko.Tabs;
 import org.mozilla.gecko.gfx.Layer.RenderContext;
 import org.mozilla.gecko.gfx.RenderTask;
 import org.mozilla.gecko.mozglue.DirectBufferAllocator;
+import org.mozilla.gecko.mozglue.generatorannotations.GeneratorOptions;
+import org.mozilla.gecko.mozglue.generatorannotations.WrapElementForJNI;
 
 import android.content.Context;
 import android.content.SharedPreferences;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Matrix;
-import android.graphics.Point;
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.opengl.GLES20;
 import android.os.SystemClock;
 import android.util.Log;
 
 import java.nio.ByteBuffer;
@@ -432,16 +433,17 @@ public class LayerRenderer implements Ta
             } else {
                 // reached the run-at time, execute
                 mStarted = false;
                 mView.requestRender();
             }
         }
     }
 
+    @GeneratorOptions(generatedClassName = "LayerRendererFrame")
     public class Frame {
         // The timestamp recording the start of this frame.
         private long mFrameStartTime;
         // A fixed snapshot of the viewport metrics that this frame is using to render content.
         private ImmutableViewportMetrics mFrameMetrics;
         // A rendering context for page-positioned layers, and one for screen-positioned layers.
         private RenderContext mPageContext, mScreenContext;
         // Whether a layer was updated.
@@ -485,16 +487,17 @@ public class LayerRenderer implements Ta
             Rect scissorRect = new Rect(left, screenSize.height - bottom, right,
                                         (screenSize.height - bottom) + (bottom - top));
             scissorRect.offset(Math.round(-mRenderOffset.x), Math.round(-mRenderOffset.y));
 
             return scissorRect;
         }
 
         /** This function is invoked via JNI; be careful when modifying signature. */
+        @WrapElementForJNI(allowMultithread = true)
         public void beginDrawing() {
             mFrameStartTime = System.nanoTime();
 
             TextureReaper.get().reap();
             TextureGenerator.get().fill();
 
             mUpdated = true;
 
@@ -574,16 +577,17 @@ public class LayerRenderer implements Ta
                                 0.0f);
             // The bits set here need to match up with those used
             // in gfx/layers/opengl/LayerManagerOGL.cpp.
             GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT |
                            GLES20.GL_DEPTH_BUFFER_BIT);
         }
 
         /** This function is invoked via JNI; be careful when modifying signature. */
+        @WrapElementForJNI(allowMultithread = true)
         public void drawBackground() {
             GLES20.glDisable(GLES20.GL_SCISSOR_TEST);
 
             // Draw the overscroll background area as a solid color
             clear(mOverscrollColor);
 
             // Update background color.
             mBackgroundColor = mView.getBackgroundColor();
@@ -606,16 +610,17 @@ public class LayerRenderer implements Ta
             if (rootLayer == null) {
                 return;
             }
 
             rootLayer.draw(mPageContext);
         }
 
         /** This function is invoked via JNI; be careful when modifying signature. */
+        @WrapElementForJNI(allowMultithread = true)
         public void drawForeground() {
             /* Draw any extra layers that were added (likely plugins) */
             if (mExtraLayers.size() > 0) {
                 for (Layer layer : mExtraLayers) {
                     layer.draw(mPageContext);
                 }
             }
 
@@ -656,16 +661,17 @@ public class LayerRenderer implements Ta
 
                 GLES20.glEnable(GLES20.GL_BLEND);
                 GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
                 mFrameRateLayer.draw(mScreenContext);
             }
         }
 
         /** This function is invoked via JNI; be careful when modifying signature. */
+        @WrapElementForJNI(allowMultithread = true)
         public void endDrawing() {
             // If a layer update requires further work, schedule another redraw
             if (!mUpdated)
                 mView.requestRender();
 
             PanningPerfAPI.recordFrameTime();
 
             /* Used by robocop for testing purposes */
--- a/mobile/android/base/gfx/ProgressiveUpdateData.java
+++ b/mobile/android/base/gfx/ProgressiveUpdateData.java
@@ -1,21 +1,24 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.gfx;
 
+import org.mozilla.gecko.mozglue.generatorannotations.WrapEntireClassForJNI;
+
 /**
  * This is the data structure that's returned by the progressive tile update
  * callback function. It encompasses the current viewport and a boolean value
  * representing whether the front-end is interested in the current progressive
  * update continuing.
  */
+@WrapEntireClassForJNI
 public class ProgressiveUpdateData {
     public float x;
     public float y;
     public float width;
     public float height;
     public float scale;
     public boolean abort;
 
--- a/mobile/android/base/gfx/ViewTransform.java
+++ b/mobile/android/base/gfx/ViewTransform.java
@@ -1,15 +1,18 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.gfx;
 
+import org.mozilla.gecko.mozglue.generatorannotations.WrapEntireClassForJNI;
+
+@WrapEntireClassForJNI
 public class ViewTransform {
     public float x;
     public float y;
     public float scale;
     public float fixedLayerMarginLeft;
     public float fixedLayerMarginTop;
     public float fixedLayerMarginRight;
     public float fixedLayerMarginBottom;
--- a/mobile/android/base/mozglue/NativeZip.java
+++ b/mobile/android/base/mozglue/NativeZip.java
@@ -1,15 +1,17 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.mozglue;
 
+import org.mozilla.gecko.mozglue.generatorannotations.WrapElementForJNI;
+
 import java.io.InputStream;
 import java.nio.ByteBuffer;
 import java.util.zip.Inflater;
 import java.util.zip.InflaterInputStream;
 
 public class NativeZip implements NativeReference {
     private static final int DEFLATE = 8;
     private static final int STORE = 0;
@@ -63,16 +65,17 @@ public class NativeZip implements Native
         return _getInputStream(mObj, path);
     }
 
     private static native long getZip(String path);
     private static native long getZipFromByteBuffer(ByteBuffer buffer);
     private static native void _release(long obj);
     private native InputStream _getInputStream(long obj, String path);
 
+    @WrapElementForJNI
     private InputStream createInputStream(ByteBuffer buffer, int compression) {
         if (compression != STORE && compression != DEFLATE) {
             throw new IllegalArgumentException("Unexpected compression: " + compression);
         }
 
         InputStream input = new ByteBufferInputStream(buffer, this);
         if (compression == DEFLATE) {
             Inflater inflater = new Inflater(true);
--- a/mobile/android/base/sqlite/MatrixBlobCursor.java
+++ b/mobile/android/base/sqlite/MatrixBlobCursor.java
@@ -12,16 +12,18 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 package org.mozilla.gecko.sqlite;
 
+import org.mozilla.gecko.mozglue.generatorannotations.WrapElementForJNI;
+
 import android.database.AbstractCursor;
 import android.database.CursorIndexOutOfBoundsException;
 
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
 
 /*
  * Android's AbstractCursor throws on getBlob()
@@ -45,16 +47,17 @@ public class MatrixBlobCursor extends Ab
 
     /**
      * Constructs a new cursor with the given initial capacity.
      *
      * @param columnNames names of the columns, the ordering of which
      *  determines column ordering elsewhere in this cursor
      * @param initialCapacity in rows
      */
+    @WrapElementForJNI
     public MatrixBlobCursor(String[] columnNames, int initialCapacity) {
         this.columnNames = columnNames;
         this.columnCount = columnNames.length;
 
         if (initialCapacity < 1) {
             initialCapacity = 1;
         }
 
@@ -62,16 +65,17 @@ public class MatrixBlobCursor extends Ab
     }
 
     /**
      * Constructs a new cursor.
      *
      * @param columnNames names of the columns, the ordering of which
      *  determines column ordering elsewhere in this cursor
      */
+    @WrapElementForJNI
     public MatrixBlobCursor(String[] columnNames) {
         this(columnNames, 16);
     }
 
     /**
      * Gets value at the given column for the current row.
      */
     protected Object get(int column) {
@@ -107,16 +111,17 @@ public class MatrixBlobCursor extends Ab
      * Adds a new row to the end with the given column values. Not safe
      * for concurrent use.
      *
      * @throws IllegalArgumentException if {@code columnValues.length !=
      *  columnNames.length}
      * @param columnValues in the same order as the the column names specified
      *  at cursor construction time
      */
+    @WrapElementForJNI
     public void addRow(Object[] columnValues) {
         if (columnValues.length != columnCount) {
             throw new IllegalArgumentException("columnNames.length = "
                     + columnCount + ", columnValues.length = "
                     + columnValues.length);
         }
 
         int start = rowCount++ * columnCount;
@@ -128,16 +133,17 @@ public class MatrixBlobCursor extends Ab
      * Adds a new row to the end with the given column values. Not safe
      * for concurrent use.
      *
      * @throws IllegalArgumentException if {@code columnValues.size() !=
      *  columnNames.length}
      * @param columnValues in the same order as the the column names specified
      *  at cursor construction time
      */
+    @WrapElementForJNI
     public void addRow(Iterable<?> columnValues) {
         int start = rowCount * columnCount;
         int end = start + columnCount;
         ensureCapacity(end);
 
         if (columnValues instanceof ArrayList<?>) {
             addRow((ArrayList<?>) columnValues, start);
             return;
@@ -160,16 +166,17 @@ public class MatrixBlobCursor extends Ab
                     "columnValues.size() < columnNames.length");
         }
 
         // Increase row count here in case we encounter an exception.
         rowCount++;
     }
 
     /** Optimization for {@link ArrayList}. */
+    @WrapElementForJNI
     private void addRow(ArrayList<?> columnValues, int start) {
         int size = columnValues.size();
         if (size != columnCount) {
             throw new IllegalArgumentException("columnNames.length = "
                     + columnCount + ", columnValues.size() = " + size);
         }
 
         rowCount++;
--- a/mobile/android/base/sqlite/SQLiteBridgeException.java
+++ b/mobile/android/base/sqlite/SQLiteBridgeException.java
@@ -1,15 +1,18 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.sqlite;
 
+import org.mozilla.gecko.mozglue.generatorannotations.WrapEntireClassForJNI;
+
+@WrapEntireClassForJNI
 public class SQLiteBridgeException extends RuntimeException {
     static final long serialVersionUID = 1L;
 
     public SQLiteBridgeException() {}
     public SQLiteBridgeException(String msg) {
         super(msg);
     }
 }
--- a/mobile/android/base/util/Clipboard.java
+++ b/mobile/android/base/util/Clipboard.java
@@ -74,16 +74,35 @@ public final class Clipboard {
                 } else {
                     android.text.ClipboardManager cm = getClipboardManager(mContext);
                     cm.setText(text);
                 }
             }
         });
     }
 
+    /**
+     * Returns true if the clipboard is nonempty, false otherwise.
+     *
+     * @return true if the clipboard is nonempty, false otherwise.
+     */
+    @WrapElementForJNI
+    public static boolean hasText() {
+        String text = getText();
+        return text != null;
+    }
+
+    /**
+     * Deletes all text from the clipboard.
+     */
+    @WrapElementForJNI
+    public static void clearText() {
+        setText(null);
+    }
+
     private static android.content.ClipboardManager getClipboardManager11(Context context) {
         // In API Level 11 and above, CLIPBOARD_SERVICE returns android.content.ClipboardManager,
         // which is a subclass of android.text.ClipboardManager.
         return (android.content.ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
     }
 
     private static android.text.ClipboardManager getClipboardManager(Context context) {
         return (android.text.ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);