diff --git a/embedding/android/GeckoEvent.java b/embedding/android/GeckoEvent.java
index 821af2fb5ad93ecea427fcf8cf6279e8f82c068c..ba3b3d6dee10c25f154a62eb1cc76dc14ca2ec95 100644
--- a/embedding/android/GeckoEvent.java
+++ b/embedding/android/GeckoEvent.java
@@ -15,7 +15,6 @@ import android.hardware.*;
 import android.location.*;
 import android.util.FloatMath;
 import android.util.DisplayMetrics;
-import java.nio.ByteBuffer;
 
 import android.util.Log;
 
@@ -101,8 +100,6 @@ public class GeckoEvent {
 
     public int mNativeWindow;
 
-    public ByteBuffer mBuffer;
-
     public GeckoEvent() {
         mType = NATIVE_POKE;
     }
diff --git a/ipc/chromium/src/base/message_loop.cc b/ipc/chromium/src/base/message_loop.cc
index c19f9137ee6355565d533516cc1bec98726f0280..38edbd594a36c55d7ed21e8ea910847671349ef7 100644
--- a/ipc/chromium/src/base/message_loop.cc
+++ b/ipc/chromium/src/base/message_loop.cc
@@ -256,14 +256,6 @@ void MessageLoop::PostNonNestableDelayedTask(
   PostTask_Helper(from_here, task, delay_ms, false);
 }
 
-void MessageLoop::PostIdleTask(
-    const tracked_objects::Location& from_here, Task* task) {
-  DCHECK(current() == this);
-  task->SetBirthPlace(from_here);
-  PendingTask pending_task(task, false);
-  deferred_non_nestable_work_queue_.push(pending_task);
-}
-
 // Possibly called on a background thread!
 void MessageLoop::PostTask_Helper(
     const tracked_objects::Location& from_here, Task* task, int delay_ms,
diff --git a/ipc/chromium/src/base/message_loop.h b/ipc/chromium/src/base/message_loop.h
index e3de53f7bd2dcd8aeca38a3af482fc121720f847..dd4a814984a19c4f65efc89ae3e9c13c4d7e7c20 100644
--- a/ipc/chromium/src/base/message_loop.h
+++ b/ipc/chromium/src/base/message_loop.h
@@ -121,10 +121,6 @@ public:
   void PostNonNestableDelayedTask(
       const tracked_objects::Location& from_here, Task* task, int delay_ms);
 
-  // PostIdleTask is not thread safe and should be called on this thread
-  void PostIdleTask(
-      const tracked_objects::Location& from_here, Task* task);
-
   // A variant on PostTask that deletes the given object.  This is useful
   // if the object needs to live until the next run of the MessageLoop (for
   // example, deleting a RenderProcessHost from within an IPC callback is not
diff --git a/mobile/android/base/GeckoApp.java b/mobile/android/base/GeckoApp.java
index 68186d0de20474a08f9ba7615fbfecbe9e99fbe1..2757c7b75fc70f2ba9750aee737434825f4f1845 100644
--- a/mobile/android/base/GeckoApp.java
+++ b/mobile/android/base/GeckoApp.java
@@ -697,7 +697,7 @@ abstract public class GeckoApp
 
             int dw = tab.getThumbnailWidth();
             int dh = tab.getThumbnailHeight();
-            GeckoAppShell.sendEventToGecko(GeckoEvent.createScreenshotEvent(tab.getId(), 0, 0, 0, 0, 0, 0, dw, dh, dw, dh, GeckoAppShell.SCREENSHOT_THUMBNAIL, tab.getThumbnailBuffer()));
+            GeckoAppShell.sendEventToGecko(GeckoEvent.createScreenshotEvent(tab.getId(), 0, 0, 0, 0, 0, 0, dw, dh, GeckoAppShell.SCREENSHOT_THUMBNAIL));
         }
     }
     
diff --git a/mobile/android/base/GeckoAppShell.java b/mobile/android/base/GeckoAppShell.java
index 7ca3614ff822494c6765bdd3541758836b11bfc2..2a9a0d1ebdb4d292a1283f163b50835123a4af14 100644
--- a/mobile/android/base/GeckoAppShell.java
+++ b/mobile/android/base/GeckoAppShell.java
@@ -15,7 +15,6 @@ import org.mozilla.gecko.gfx.ScreenshotLayer;
 import org.mozilla.gecko.FloatUtils;
 import org.mozilla.gecko.gfx.ImmutableViewportMetrics;
 import org.mozilla.gecko.gfx.ViewportMetrics;
-import org.mozilla.gecko.gfx.RectUtils;
 
 import java.io.*;
 import java.lang.reflect.*;
@@ -84,7 +83,8 @@ public class GeckoAppShell
     public static final String SHORTCUT_TYPE_BOOKMARK = "bookmark";
 
     static public final int SCREENSHOT_THUMBNAIL = 0;
-    static public final int SCREENSHOT_CHECKERBOARD = 1;
+    static public final int SCREENSHOT_WHOLE_PAGE = 1;
+    static public final int SCREENSHOT_UPDATE = 2;
 
     static public final int RESTORE_NONE = 0;
     static public final int RESTORE_OOM = 1;
@@ -98,6 +98,11 @@ public class GeckoAppShell
     private static Boolean sNSSLibsLoaded = false;
     private static Boolean sLibsSetup = false;
     private static File sGREDir = null;
+    private static RectF sCheckerboardPageRect;
+    private static float sLastCheckerboardWidthRatio, sLastCheckerboardHeightRatio;
+    private static RepaintRunnable sRepaintRunnable = new RepaintRunnable();
+    static private int sMaxTextureSize = 0;
+
     private static Map<String, CopyOnWriteArrayList<GeckoEventListener>> mEventListeners
             = new HashMap<String, CopyOnWriteArrayList<GeckoEventListener>>();
 
@@ -123,6 +128,8 @@ public class GeckoAppShell
 
     private static Handler sGeckoHandler;
 
+    private static boolean sDisableScreenshot = false;
+
     /* The Android-side API: API methods that Android calls */
 
     // Initialization methods
@@ -528,7 +535,42 @@ public class GeckoAppShell
     // Called by AndroidBridge using JNI
     public static void notifyScreenShot(final ByteBuffer data, final int tabId, final int x, final int y,
                                         final int width, final int height, final int token) {
-        ScreenshotHandler.notifyScreenShot(data, tabId, x, y, width, height, token);
+        getHandler().post(new Runnable() {
+            public void run() {
+                try {
+                    final Tab tab = Tabs.getInstance().getTab(tabId);
+                    if (tab == null)
+                        return;
+
+                    if (!Tabs.getInstance().isSelectedTab(tab) && SCREENSHOT_THUMBNAIL != token)
+                        return;
+
+                    Bitmap b = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
+                    b.copyPixelsFromBuffer(data);
+                    switch (token) {
+                    case SCREENSHOT_WHOLE_PAGE:
+                        GeckoApp.mAppContext.getLayerController()
+                            .getView().getRenderer()
+                            .setCheckerboardBitmap(b, sCheckerboardPageRect);
+                        break;
+                    case SCREENSHOT_UPDATE:
+                        GeckoApp.mAppContext.getLayerController().getView().getRenderer().
+                            updateCheckerboardBitmap(
+                                b, sLastCheckerboardWidthRatio * x,
+                                sLastCheckerboardHeightRatio * y,
+                                sLastCheckerboardWidthRatio * width,
+                                sLastCheckerboardHeightRatio * height,
+                                sCheckerboardPageRect);
+                        break;
+                    case SCREENSHOT_THUMBNAIL:
+                        GeckoApp.mAppContext.processThumbnail(tab, b, null);
+                        break;
+                    }
+                } finally {
+                    freeDirectBuffer(data);
+                }
+            }
+        });
     }
 
     private static CountDownLatch sGeckoPendingAcks = null;
@@ -2094,26 +2136,6 @@ public class GeckoAppShell
         if (!GeckoApp.mAppContext.showFilePicker(aMimeType, new AsyncResultHandler(id)))
             GeckoAppShell.notifyFilePickerResult("", id);
     }
-    public static void screenshotWholePage(Tab tab) {
-        ScreenshotHandler.screenshotWholePage(tab);
-    }
-
-    // Called by AndroidBridge using JNI
-    public static void notifyPaintedRect(float top, float left, float bottom, float right) {
-        ScreenshotHandler.notifyPaintedRect(top, left, bottom, right);
-    }
-}
-
-class ScreenshotHandler {
-    private static Queue<PendingScreenshot> sPendingScreenshots = new LinkedList<PendingScreenshot>();
-    private static RectF sCheckerboardPageRect;
-    private static float sLastCheckerboardWidthRatio, sLastCheckerboardHeightRatio;
-    private static RepaintRunnable sRepaintRunnable = new RepaintRunnable();
-    private static int sMaxTextureSize = 0;
-    private static final String LOGTAG = "GeckoScreenshot";
-    private static boolean sDisableScreenshot = false;
-    private static ByteBuffer sWholePageScreenshotBuffer;
-    private static int sCheckerboardBufferWidth, sCheckerboardBufferHeight;
 
     static class RepaintRunnable implements Runnable {
         private boolean mIsRepaintRunnablePosted = false;
@@ -2136,40 +2158,25 @@ class ScreenshotHandler {
                 mIsRepaintRunnablePosted = false;
             }
 
-
             Tab tab = Tabs.getInstance().getSelectedTab();
-            ImmutableViewportMetrics viewport = GeckoApp.mAppContext.getLayerController().getViewportMetrics();
-            
-            if (RectUtils.fuzzyEquals(sCheckerboardPageRect, viewport.getCssPageRect())) {
-                float width = right - left;
-                float height = bottom - top;
-                scheduleCheckerboardScreenshotEvent(tab.getId(), 
-                                                    (int)left, (int)top, (int)width, (int)height, 
-                                                    (int)(sLastCheckerboardWidthRatio * left), 
-                                                    (int)(sLastCheckerboardHeightRatio * top),
-                                                    (int)(sLastCheckerboardWidthRatio * width),
-                                                    (int)(sLastCheckerboardHeightRatio * height),
-                                                    sCheckerboardBufferWidth, sCheckerboardBufferHeight);
-            } else {
-                GeckoAppShell.screenshotWholePage(tab);
-            }
+            GeckoAppShell.screenshotWholePage(tab);
         }
 
         void addRectToRepaint(float top, float left, float bottom, float right) {
             synchronized(this) {
-                ImmutableViewportMetrics viewport = GeckoApp.mAppContext.getLayerController().getViewportMetrics();
-                mDirtyTop = Math.max(sCheckerboardPageRect.top, Math.min(top, mDirtyTop));
-                mDirtyLeft = Math.max(sCheckerboardPageRect.left, Math.min(left, mDirtyLeft));
-                mDirtyBottom = Math.min(sCheckerboardPageRect.bottom, Math.max(bottom, mDirtyBottom));
-                mDirtyRight = Math.min(sCheckerboardPageRect.right, Math.max(right, mDirtyRight));
+                mDirtyTop = Math.min(top, mDirtyTop);
+                mDirtyLeft = Math.min(left, mDirtyLeft);
+                mDirtyBottom = Math.max(bottom, mDirtyBottom);
+                mDirtyRight = Math.max(right, mDirtyRight);
                 if (!mIsRepaintRunnablePosted) {
-                    GeckoAppShell.getHandler().postDelayed(this, 5000);
+                    getHandler().postDelayed(this, 5000);
                     mIsRepaintRunnablePosted = true;
                 }
             }
         }
     }
 
+    // Called by AndroidBridge using JNI
     public static void notifyPaintedRect(float top, float left, float bottom, float right) {
         sRepaintRunnable.addRectToRepaint(top, left, bottom, right);
     }
@@ -2196,9 +2203,7 @@ class ScreenshotHandler {
             sMaxTextureSize = maxTextureSize[0];
             if (sMaxTextureSize == 0)
                 return;
-            sWholePageScreenshotBuffer = GeckoAppShell.allocateDirectBuffer(ScreenshotLayer.getMaxNumPixels() * 2 /* 16 bpp */);
         }
-
         ImmutableViewportMetrics viewport = GeckoApp.mAppContext.getLayerController().getViewportMetrics();
         Log.i(LOGTAG, "Taking whole-screen screenshot, viewport: " + viewport);
         // source width and height to screenshot
@@ -2206,8 +2211,6 @@ class ScreenshotHandler {
         float sy = viewport.cssPageRectTop;
         float sw = viewport.cssPageRectRight - viewport.cssPageRectLeft;
         float sh = viewport.cssPageRectBottom - viewport.cssPageRectTop;
-        if (sw == 0 || sh == 0)
-            return;
         int maxPixels = Math.min(ScreenshotLayer.getMaxNumPixels(), sMaxTextureSize * sMaxTextureSize);
         // 2Mb of 16bit image data
         // may be bumped by up to 4x for power of 2 alignment
@@ -2221,98 +2224,14 @@ class ScreenshotHandler {
         int dy = 0;
         int dw = clamp(minTextureSize, idealDstWidth, sMaxTextureSize);
         int dh = maxPixels / dw;
-        sCheckerboardBufferWidth = dw;
-        sCheckerboardBufferHeight = dh;
 
         sLastCheckerboardWidthRatio = dw / sw;
         sLastCheckerboardHeightRatio = dh / sh;
         sCheckerboardPageRect = viewport.getCssPageRect();
-        scheduleCheckerboardScreenshotEvent(tab.getId(), (int)sx, (int)sy, (int)sw, (int)sh, dx, dy, dw, dh, dw, dh);
-    }
-
-    static void scheduleCheckerboardScreenshotEvent(int tabId, int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh, int bw, int bh) {
-        float totalSize = sw * sh;
-        int numSlices = (int) Math.ceil(totalSize / 100000);
-        if (numSlices == 0)
-            return;
-        int srcSliceSize = (int) Math.ceil(sh / numSlices);
-        int dstSliceSize = (int) Math.ceil(dh / numSlices);
-        for (int i = 0; i < numSlices; i++) {
-            GeckoEvent event =
-                GeckoEvent.createScreenshotEvent(tabId, 
-                                                 sx, sy + srcSliceSize * i,  sw, srcSliceSize, 
-                                                 dx, dy + dstSliceSize * i,  dw, dstSliceSize, bw, bh,
-                                                 GeckoAppShell.SCREENSHOT_CHECKERBOARD,
-                                                 sWholePageScreenshotBuffer);
-            synchronized(sPendingScreenshots) {
-                sPendingScreenshots.add(new PendingScreenshot(tabId, event));
-                if (sPendingScreenshots.size() == 1)
-                    sendNextEventToGecko();
-            }
-        }
-    }
-
-    static void sendNextEventToGecko() {
-        synchronized(sPendingScreenshots) {
-            if (sPendingScreenshots.isEmpty())
-                return;
-            GeckoAppShell.sendEventToGecko(sPendingScreenshots.element().getEvent());
-        }
-    }
-    
-    static class PendingScreenshot {
-        private final GeckoEvent mEvent;
-        private final int mTabId;
-
-        PendingScreenshot(int tabId, GeckoEvent event) {
-            mTabId = tabId;
-            mEvent = event;
-        }
-
-        GeckoEvent getEvent() {
-            return mEvent;
-        }
-
-    }
 
-    public static void notifyScreenShot(final ByteBuffer data, final int tabId, final int x, final int y,
-                                        final int width, final int height, final int token) {
-
-        GeckoAppShell.getHandler().post(new Runnable() {
-            public void run() {
-                final Tab tab = Tabs.getInstance().getTab(tabId);
-                if (tab == null) {
-                    if (token == GeckoAppShell.SCREENSHOT_CHECKERBOARD) {
-                        synchronized(sPendingScreenshots) {
-                            sPendingScreenshots.remove();
-                            sendNextEventToGecko();
-                        }
-                    }
-                    return;
-                }
-                switch (token) {
-                    case GeckoAppShell.SCREENSHOT_CHECKERBOARD:
-                    {
-                        GeckoApp.mAppContext.getLayerController()
-                            .getView().getRenderer()
-                            .setCheckerboardBitmap(data, width, height, sCheckerboardPageRect);
-                        synchronized(sPendingScreenshots) {
-                            sPendingScreenshots.remove();
-                            sendNextEventToGecko();
-                        }
-                        break;
-                    }
-                    case GeckoAppShell.SCREENSHOT_THUMBNAIL:
-                    {
-                        if (Tabs.getInstance().isSelectedTab(tab)) {
-                            Bitmap b = tab.getThumbnailBitmap();
-                            b.copyPixelsFromBuffer(data);
-                            GeckoApp.mAppContext.processThumbnail(tab, b, null);
-                        }
-                        break;
-                    }
-                }
-            }
-        });
+        GeckoAppShell.sendEventToGecko(GeckoEvent.createScreenshotEvent(tab.getId(),
+                (int)FloatMath.ceil(sx), (int)FloatMath.ceil(sy),
+                (int)FloatMath.floor(sw), (int)FloatMath.floor(sh),
+                dx, dy, dw, dh, GeckoAppShell.SCREENSHOT_WHOLE_PAGE));
     }
 }
diff --git a/mobile/android/base/GeckoEvent.java b/mobile/android/base/GeckoEvent.java
index 1b01bd7fcd01b6371a5f0c660823edb784c0ac60..f9682507715c049a23df0e68cb90492b82c192e0 100644
--- a/mobile/android/base/GeckoEvent.java
+++ b/mobile/android/base/GeckoEvent.java
@@ -23,7 +23,6 @@ import android.text.format.Time;
 import android.os.SystemClock;
 import java.lang.Math;
 import java.lang.System;
-import java.nio.ByteBuffer;
 
 import android.util.Log;
 
@@ -117,8 +116,6 @@ public class GeckoEvent {
 
     public short mScreenOrientation;
 
-    public ByteBuffer mBuffer;
-
     private GeckoEvent(int evType) {
         mType = evType;
     }
@@ -459,17 +456,15 @@ public class GeckoEvent {
         return event;
     }
 
-    public static GeckoEvent createScreenshotEvent(int tabId, int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh, int bw, int bh, int token, ByteBuffer buffer) {
+    public static GeckoEvent createScreenshotEvent(int tabId, int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh, int token) {
         GeckoEvent event = new GeckoEvent(SCREENSHOT);
-        event.mPoints = new Point[5];
+        event.mPoints = new Point[4];
         event.mPoints[0] = new Point(sx, sy);
         event.mPoints[1] = new Point(sw, sh);
         event.mPoints[2] = new Point(dx, dy);
         event.mPoints[3] = new Point(dw, dh);
-        event.mPoints[4] = new Point(bw, bh);
         event.mMetaState = tabId;
         event.mFlags = token;
-        event.mBuffer = buffer;
         return event;
     }
 
diff --git a/mobile/android/base/Tab.java b/mobile/android/base/Tab.java
index 6b8d4491000a04881811183f9f3401065e89206c..e7737c4ef7650936e12dbbddb6912cd42fd32e14 100644
--- a/mobile/android/base/Tab.java
+++ b/mobile/android/base/Tab.java
@@ -21,7 +21,6 @@ import org.json.JSONObject;
 import org.mozilla.gecko.db.BrowserDB;
 import org.mozilla.gecko.gfx.Layer;
 
-import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
@@ -66,8 +65,6 @@ public final class Tab {
     private ContentObserver mContentObserver;
     private int mCheckerboardColor = Color.WHITE;
     private int mState;
-    private ByteBuffer mThumbnailBuffer;
-    private Bitmap mThumbnailBitmap;
 
     public static final int STATE_DELAYED = 0;
     public static final int STATE_LOADING = 1;
@@ -143,31 +140,6 @@ public final class Tab {
         return mThumbnail;
     }
 
-    synchronized public ByteBuffer getThumbnailBuffer() {
-        int capacity = getThumbnailWidth() * getThumbnailHeight() * 2 /* 16 bpp */;
-        if (mThumbnailBuffer != null && mThumbnailBuffer.capacity() == capacity)
-            return mThumbnailBuffer;
-        if (mThumbnailBuffer != null)
-            GeckoAppShell.freeDirectBuffer(mThumbnailBuffer); // not calling freeBuffer() because it would deadlock
-        return mThumbnailBuffer = GeckoAppShell.allocateDirectBuffer(capacity);
-    }
-
-    public Bitmap getThumbnailBitmap() {
-        if (mThumbnailBitmap != null)
-            return mThumbnailBitmap;
-        return mThumbnailBitmap = Bitmap.createBitmap(getThumbnailWidth(), getThumbnailHeight(), Bitmap.Config.RGB_565);
-    }
-
-    public void finalize() {
-        freeBuffer();
-    }
-
-    synchronized void freeBuffer() {
-        if (mThumbnailBuffer != null)
-            GeckoAppShell.freeDirectBuffer(mThumbnailBuffer);
-        mThumbnailBuffer = null;
-    }
-
     float getDensity() {
         if (sDensity == 0.0f) {
             sDensity = GeckoApp.mAppContext.getDisplayMetrics().density;
@@ -189,10 +161,13 @@ public final class Tab {
             public void run() {
                 if (b != null) {
                     try {
+                        Bitmap bitmap = Bitmap.createScaledBitmap(b, getThumbnailWidth(), getThumbnailHeight(), false);
+
                         if (mState == Tab.STATE_SUCCESS)
-                            saveThumbnailToDB(new BitmapDrawable(b));
+                            saveThumbnailToDB(new BitmapDrawable(bitmap));
 
-                        mThumbnail = new BitmapDrawable(b);
+                        mThumbnail = new BitmapDrawable(bitmap);
+                        b.recycle();
                     } catch (OutOfMemoryError oom) {
                         Log.e(LOGTAG, "Unable to create/scale bitmap", oom);
                         mThumbnail = null;
diff --git a/mobile/android/base/Tabs.java b/mobile/android/base/Tabs.java
index e8123d513320bf35756d65f87dc582ed729b22b4..c688a76d7be979143bf910c94e6d9c1b8c13cdbb 100644
--- a/mobile/android/base/Tabs.java
+++ b/mobile/android/base/Tabs.java
@@ -76,10 +76,8 @@ public class Tabs implements GeckoEventListener {
 
     public void removeTab(int id) {
         if (tabs.containsKey(id)) {
-            Tab tab = getTab(id);
-            order.remove(tab);
+            order.remove(getTab(id));
             tabs.remove(id);
-            tab.freeBuffer();
             Log.i(LOGTAG, "Removed a tab with id: " + id);
         }
     }
diff --git a/mobile/android/base/gfx/IntSize.java b/mobile/android/base/gfx/IntSize.java
index dfc594885330d8efeb51ed4b57e426f8f117cb61..8560ca23e915103584b94afd9e7f977d5d135e2f 100644
--- a/mobile/android/base/gfx/IntSize.java
+++ b/mobile/android/base/gfx/IntSize.java
@@ -71,11 +71,5 @@ public class IntSize {
     public IntSize nextPowerOfTwo() {
         return new IntSize(nextPowerOfTwo(width), nextPowerOfTwo(height));
     }
-
-    public static boolean isPowerOfTwo(int value) {
-        if (value == 0)
-            return false;
-        return (value & (value - 1)) == 0;
-    }
 }
 
diff --git a/mobile/android/base/gfx/LayerRenderer.java b/mobile/android/base/gfx/LayerRenderer.java
index e896c283aa47c828914358a86c23f1d0d1612975..be5bbc38899a38b3cfc315cde626e1335d8866c7 100644
--- a/mobile/android/base/gfx/LayerRenderer.java
+++ b/mobile/android/base/gfx/LayerRenderer.java
@@ -134,8 +134,8 @@ public class LayerRenderer {
         "    gl_FragColor = texture2D(sTexture, vTexCoord);\n" +
         "}\n";
 
-    public void setCheckerboardBitmap(ByteBuffer data, int width, int height, RectF pageRect) {
-        mCheckerboardLayer.setBitmap(data, width, height);
+    public void setCheckerboardBitmap(Bitmap bitmap, RectF pageRect) {
+        mCheckerboardLayer.setBitmap(bitmap);
         mCheckerboardLayer.beginTransaction();
         try {
             mCheckerboardLayer.setPosition(RectUtils.round(pageRect));
diff --git a/mobile/android/base/gfx/ScreenshotLayer.java b/mobile/android/base/gfx/ScreenshotLayer.java
index 1a3ed9fc7b6837994bd39dadc5c74a8ec49f2465..355cea785607c43cb330caead2fb9e3549011c01 100644
--- a/mobile/android/base/gfx/ScreenshotLayer.java
+++ b/mobile/android/base/gfx/ScreenshotLayer.java
@@ -35,7 +35,6 @@ public class ScreenshotLayer extends SingleTileLayer {
     private IntSize mImageSize;
     // Whether we have an up-to-date image to draw
     private boolean mHasImage;
-    private static String LOGTAG = "GeckoScreenshot";
 
     public static int getMaxNumPixels() {
         return SCREENSHOT_SIZE_LIMIT;
@@ -45,19 +44,6 @@ public class ScreenshotLayer extends SingleTileLayer {
         mHasImage = false;
     }
 
-    void setBitmap(ByteBuffer data, int width, int height) {
-        mImageSize = new IntSize(width, height);
-        if (IntSize.isPowerOfTwo(width) && IntSize.isPowerOfTwo(height)) {
-            mBufferSize = mImageSize;
-            mHasImage = true;
-            mImage.setBitmap(data, width, height, CairoImage.FORMAT_RGB16_565);
-        } else {
-            Bitmap b = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
-            b.copyPixelsFromBuffer(data);
-            setBitmap(b);
-        }
-    }
-    
     void setBitmap(Bitmap bitmap) {
         mImageSize = new IntSize(bitmap.getWidth(), bitmap.getHeight());
         int width = IntSize.nextPowerOfTwo(bitmap.getWidth());
@@ -130,17 +116,7 @@ public class ScreenshotLayer extends SingleTileLayer {
             }
         }
 
-        void copyBuffer(ByteBuffer src, ByteBuffer dst, int size) {
-            dst.asIntBuffer().put(src.asIntBuffer());
-        }
-
-        synchronized void setBitmap(ByteBuffer data, int width, int height, int format) {
-            mSize = new IntSize(width, height);
-            mFormat = format;
-            copyBuffer(data, mBuffer, width * height * 2);
-        }
-
-        synchronized void setBitmap(Bitmap bitmap, int width, int height, int format) {
+        void setBitmap(Bitmap bitmap, int width, int height, int format) {
             Bitmap tmp;
             mSize = new IntSize(width, height);
             mFormat = format;
@@ -162,10 +138,10 @@ public class ScreenshotLayer extends SingleTileLayer {
         }
 
         @Override
-        synchronized public ByteBuffer getBuffer() { return mBuffer; }
+        public ByteBuffer getBuffer() { return mBuffer; }
         @Override
-        synchronized public IntSize getSize() { return mSize; }
+        public IntSize getSize() { return mSize; }
         @Override
-        synchronized public int getFormat() { return mFormat; }
+        public int getFormat() { return mFormat; }
     }
 }
diff --git a/widget/android/AndroidBridge.cpp b/widget/android/AndroidBridge.cpp
index d13a14d5da8850f6844635db29d599236c2543ab..c735c313e1b19872b336b9021662477fe58accc1 100644
--- a/widget/android/AndroidBridge.cpp
+++ b/widget/android/AndroidBridge.cpp
@@ -2350,13 +2350,9 @@ jobject JNICALL
 Java_org_mozilla_gecko_GeckoAppShell_allocateDirectBuffer(JNIEnv *env, jclass, jlong size);
 
 
-nsresult AndroidBridge::TakeScreenshot(nsIDOMWindow *window, PRInt32 srcX, PRInt32 srcY, PRInt32 srcW, PRInt32 srcH, PRInt32 dstX, PRInt32 dstY, PRInt32 dstW, PRInt32 dstH, PRInt32 bufW, PRInt32 bufH, PRInt32 tabId, PRInt32 token, jobject buffer)
+nsresult AndroidBridge::TakeScreenshot(nsIDOMWindow *window, PRInt32 srcX, PRInt32 srcY, PRInt32 srcW, PRInt32 srcH, PRInt32 dstW, PRInt32 dstH, PRInt32 tabId, float scale, PRInt32 token)
 {
     nsresult rv;
-    float scale = 1.0;
- 
-    if (!buffer)
-        return NS_OK;
 
     // take a screenshot, as wide as possible, proportional to the destination size
     if (!srcW && !srcH) {
@@ -2417,17 +2413,21 @@ nsresult AndroidBridge::TakeScreenshot(nsIDOMWindow *window, PRInt32 srcX, PRInt
              nsPresContext::CSSPixelsToAppUnits(srcW / scale),
              nsPresContext::CSSPixelsToAppUnits(srcH / scale));
 
-    PRUint32 stride = bufW * 2 /* 16 bpp */;
+    PRUint32 stride = dstW * 2;
+    PRUint32 bufferSize = dstH * stride;
+
+    jobject buffer = Java_org_mozilla_gecko_GeckoAppShell_allocateDirectBuffer(env, NULL, bufferSize);
+    if (!buffer)
+        return NS_OK;
 
     void* data = env->GetDirectBufferAddress(buffer);
-    nsRefPtr<gfxImageSurface> surf = new gfxImageSurface(static_cast<unsigned char*>(data), nsIntSize(bufW, bufH), stride, gfxASurface::ImageFormatRGB16_565);
+    memset(data, 0, bufferSize);
+    nsRefPtr<gfxImageSurface> surf = new gfxImageSurface(static_cast<unsigned char*>(data), nsIntSize(dstW, dstH), stride, gfxASurface::ImageFormatRGB16_565);
     nsRefPtr<gfxContext> context = new gfxContext(surf);
-    gfxPoint pt(dstX, dstY);
-    context->Translate(pt);
     context->Scale(scale * dstW / srcW, scale * dstH / srcH);
     rv = presShell->RenderDocument(r, renderDocFlags, bgColor, context);
     NS_ENSURE_SUCCESS(rv, rv);
-    env->CallStaticVoidMethod(AndroidBridge::Bridge()->mGeckoAppShellClass, AndroidBridge::Bridge()->jNotifyScreenShot, buffer, tabId, srcX * dstW / srcW , srcY * dstH / srcH, bufW, bufH, token);
+    env->CallStaticVoidMethod(AndroidBridge::Bridge()->mGeckoAppShellClass, AndroidBridge::Bridge()->jNotifyScreenShot, buffer, tabId, srcX * dstW / srcW , srcY * dstH / srcH, dstW, dstH, token);
     return NS_OK;
 }
 
diff --git a/widget/android/AndroidBridge.h b/widget/android/AndroidBridge.h
index 6917cb7300a0928423d75245ffd1dc4f4638c2c1..5f3f383bfb0274157a7bbc745bebafb098997c81 100644
--- a/widget/android/AndroidBridge.h
+++ b/widget/android/AndroidBridge.h
@@ -155,7 +155,7 @@ public:
         SCREENSHOT_UPDATE = 2
     };
 
-    nsresult TakeScreenshot(nsIDOMWindow *window, PRInt32 srcX, PRInt32 srcY, PRInt32 srcW, PRInt32 srcH, PRInt32 dstY, PRInt32 dstX, PRInt32 dstW, PRInt32 dstH, PRInt32 bufW, PRInt32 bufH, PRInt32 tabId, PRInt32 token, jobject buffer);
+    nsresult TakeScreenshot(nsIDOMWindow *window, PRInt32 srcX, PRInt32 srcY, PRInt32 srcW, PRInt32 srcH, PRInt32 dstW, PRInt32 dstH, PRInt32 tabId, float scale, PRInt32 token);
 
     static void NotifyPaintedRect(float top, float left, float bottom, float right);
 
diff --git a/widget/android/AndroidJavaWrappers.cpp b/widget/android/AndroidJavaWrappers.cpp
index 698de5f41272b304c3a221a5446ef81435e55471..9233526762010930fce8c828c88253b9b6f7a85b 100644
--- a/widget/android/AndroidJavaWrappers.cpp
+++ b/widget/android/AndroidJavaWrappers.cpp
@@ -42,7 +42,6 @@ jfieldID AndroidGeckoEvent::jLocationField = 0;
 jfieldID AndroidGeckoEvent::jBandwidthField = 0;
 jfieldID AndroidGeckoEvent::jCanBeMeteredField = 0;
 jfieldID AndroidGeckoEvent::jScreenOrientationField = 0;
-jfieldID AndroidGeckoEvent::jByteBufferField = 0;
 
 jclass AndroidPoint::jPointClass = 0;
 jfieldID AndroidPoint::jXField = 0;
@@ -104,12 +103,6 @@ jmethodID AndroidGeckoSurfaceView::jGetHolderMethod = 0;
 #define getMethod(fname, ftype) \
     ((jmethodID) jEnv->GetMethodID(jClass, fname, ftype))
 
-RefCountedJavaObject::~RefCountedJavaObject() {
-    if (mObject)
-        GetJNIForThread()->DeleteGlobalRef(mObject);
-    mObject = NULL;
-}
-
 void
 mozilla::InitAndroidJavaWrappers(JNIEnv *jEnv)
 {
@@ -161,7 +154,6 @@ AndroidGeckoEvent::InitGeckoEventClass(JNIEnv *jEnv)
     jBandwidthField = getField("mBandwidth", "D");
     jCanBeMeteredField = getField("mCanBeMetered", "Z");
     jScreenOrientationField = getField("mScreenOrientation", "S");
-    jByteBufferField = getField("mBuffer", "Ljava/nio/ByteBuffer;");
 }
 
 void
@@ -506,8 +498,7 @@ AndroidGeckoEvent::Init(JNIEnv *jenv, jobject jobj)
         case SCREENSHOT: {
             mMetaState = jenv->GetIntField(jobj, jMetaStateField);
             mFlags = jenv->GetIntField(jobj, jFlagsField);
-            ReadPointArray(mPoints, jenv, jPoints, 5);
-            mByteBuffer = new RefCountedJavaObject(jenv, jenv->GetObjectField(jobj, jByteBufferField));
+            ReadPointArray(mPoints, jenv, jPoints, 4);
             break;
         }
 
diff --git a/widget/android/AndroidJavaWrappers.h b/widget/android/AndroidJavaWrappers.h
index 9efa1049e315dd87e711192de31aea7e2fb8bb20..a152adad420f50d3373d25b8e6325cb0cf672fea 100644
--- a/widget/android/AndroidJavaWrappers.h
+++ b/widget/android/AndroidJavaWrappers.h
@@ -41,27 +41,6 @@ void InitAndroidJavaWrappers(JNIEnv *jEnv);
  * handle it.
  */
 
-class RefCountedJavaObject {
-public:
-    RefCountedJavaObject(JNIEnv* env, jobject obj) : mObject(env->NewGlobalRef(obj)) {}
-
-    ~RefCountedJavaObject();
-
-    PRInt32 AddRef() { return ++mRefCnt; }
-
-    PRInt32 Release() {
-        PRInt32 refcnt = --mRefCnt;
-        if (refcnt == 0)
-            delete this;
-        return refcnt;
-    }
-
-    jobject GetObject() { return mObject; }
-private:
-    PRInt32 mRefCnt;
-    jobject mObject;
-};
-
 class WrappedJavaObject {
 public:
     WrappedJavaObject() :
@@ -597,7 +576,6 @@ public:
     double Bandwidth() { return mBandwidth; }
     bool CanBeMetered() { return mCanBeMetered; }
     short ScreenOrientation() { return mScreenOrientation; }
-    RefCountedJavaObject* ByteBuffer() { return mByteBuffer; }
 
 protected:
     int mAction;
@@ -622,7 +600,6 @@ protected:
     double mBandwidth;
     bool mCanBeMetered;
     short mScreenOrientation;
-    nsRefPtr<RefCountedJavaObject> mByteBuffer;
 
     void ReadIntArray(nsTArray<int> &aVals,
                       JNIEnv *jenv,
@@ -676,7 +653,6 @@ protected:
     static jfieldID jCanBeMeteredField;
 
     static jfieldID jScreenOrientationField;
-    static jfieldID jByteBufferField;
 
 public:
     enum {
diff --git a/widget/android/nsAppShell.cpp b/widget/android/nsAppShell.cpp
index ef7a5f5cff4e482769da3c406ab693b8894dc0e1..8c9f82210108f4f15b6c0c6a15af17bbd0f51980 100644
--- a/widget/android/nsAppShell.cpp
+++ b/widget/android/nsAppShell.cpp
@@ -6,8 +6,6 @@
 // Make sure the order of included headers
 #include "base/basictypes.h"
 #include "nspr/prtypes.h"
-#include "base/message_loop.h"
-#include "base/task.h"
 
 #include "mozilla/Hal.h"
 #include "nsAppShell.h"
@@ -65,34 +63,6 @@ nsAppShell *nsAppShell::gAppShell = nsnull;
 
 NS_IMPL_ISUPPORTS_INHERITED1(nsAppShell, nsBaseAppShell, nsIObserver)
 
-class ScreenshotRunnable : public nsRunnable {
-public:
-    ScreenshotRunnable(nsIAndroidBrowserApp* aBrowserApp, int aTabId, nsTArray<nsIntPoint>& aPoints, int aToken, RefCountedJavaObject* aBuffer):
-        mBrowserApp(aBrowserApp), mTabId(aTabId), mPoints(aPoints), mToken(aToken), mBuffer(aBuffer) {}
-
-    virtual nsresult Run() {
-        nsCOMPtr<nsIDOMWindow> domWindow;
-        nsCOMPtr<nsIBrowserTab> tab;
-        mBrowserApp->GetBrowserTab(mTabId, getter_AddRefs(tab));
-        if (!tab)
-            return NS_OK;
-
-        tab->GetWindow(getter_AddRefs(domWindow));
-        if (!domWindow)
-            return NS_OK;
-
-        NS_ASSERTION(mPoints.Length() == 5, "Screenshot event does not have enough coordinates");
-
-        AndroidBridge::Bridge()->TakeScreenshot(domWindow, mPoints[0].x, mPoints[0].y, mPoints[1].x, mPoints[1].y, mPoints[2].x, mPoints[2].y, mPoints[3].x, mPoints[3].y, mPoints[4].x, mPoints[4].y, mTabId, mToken, mBuffer->GetObject());
-        return NS_OK;
-    }
-private:
-    nsCOMPtr<nsIAndroidBrowserApp> mBrowserApp;
-    nsTArray<nsIntPoint> mPoints;
-    int mTabId, mToken;
-    nsRefPtr<RefCountedJavaObject> mBuffer;
-};
-
 class AfterPaintListener : public nsIDOMEventListener {
   public:
     NS_DECL_ISUPPORTS
@@ -119,15 +89,23 @@ class AfterPaintListener : public nsIDOMEventListener {
         if (!paintEvent)
             return NS_OK;
 
-        nsCOMPtr<nsIDOMClientRect> rect;
-        paintEvent->GetBoundingClientRect(getter_AddRefs(rect));
-        float top, left, bottom, right;
-        rect->GetTop(&top);
-        rect->GetLeft(&left);
-        rect->GetRight(&right);
-        rect->GetBottom(&bottom);
-        __android_log_print(ANDROID_LOG_INFO, "GeckoScreenshot", "rect: %f, %f, %f, %f", top, left, right, bottom);
-        AndroidBridge::NotifyPaintedRect(top, left, bottom, right);
+        nsCOMPtr<nsIDOMClientRectList> rects;
+        paintEvent->GetClientRects(getter_AddRefs(rects));
+        if (!rects)
+            return NS_OK;
+        PRUint32 length;
+        rects->GetLength(&length);
+        for (PRUint32 i = 0; i < length; ++i) {
+            float top, left, bottom, right;
+            nsCOMPtr<nsIDOMClientRect> rect = rects->GetItemAt(i);
+            if (!rect)
+                continue;
+            rect->GetTop(&top);
+            rect->GetLeft(&left);
+            rect->GetRight(&right);
+            rect->GetBottom(&bottom);
+            AndroidBridge::NotifyPaintedRect(top, left, bottom, right);
+        }
         return NS_OK;
     }
 
@@ -447,13 +425,21 @@ nsAppShell::ProcessNextNativeEvent(bool mayWait)
             break;
 
         PRInt32 token = curEvent->Flags();
-        PRInt32 tabId = curEvent->MetaState();
+
+        nsCOMPtr<nsIDOMWindow> domWindow;
+        nsCOMPtr<nsIBrowserTab> tab;
+        mBrowserApp->GetBrowserTab(curEvent->MetaState(), getter_AddRefs(tab));
+        if (!tab)
+            break;
+
+        tab->GetWindow(getter_AddRefs(domWindow));
+        if (!domWindow)
+            break;
+
+        float scale = 1.0;
         nsTArray<nsIntPoint> points = curEvent->Points();
-        RefCountedJavaObject* buffer = curEvent->ByteBuffer();
-        nsCOMPtr<ScreenshotRunnable> sr = 
-            new ScreenshotRunnable(mBrowserApp, tabId, points, token, buffer);
-        MessageLoop::current()->PostIdleTask(
-            FROM_HERE, NewRunnableMethod(sr.get(), &ScreenshotRunnable::Run));
+        NS_ASSERTION(points.Length() == 4, "Screenshot event does not have enough coordinates");
+        bridge->TakeScreenshot(domWindow, points[0].x, points[0].y, points[1].x, points[1].y, points[3].x, points[3].y, curEvent->MetaState(), scale, curEvent->Flags());
         break;
     }