Merge last PGO-green changeset of mozilla-inbound to mozilla-central
authorEd Morley <bmo@edmorley.co.uk>
Tue, 31 Jan 2012 10:52:29 +0000
changeset 87037 060de47a1822f740fd317a0a18f96da47ca60b95
parent 86966 63757aa2e6291fcfde96cb96027908b66e6a7e02 (current diff)
parent 87036 2fa163bb05d764c56d243c345d003cd39567c3a2 (diff)
child 87038 1f3c7fa158aa4b7ffef8873f3f80f00f56b8accd
child 87055 1faaebaf134fbd36b01d620449714531a03322ee
push id805
push userakeybl@mozilla.com
push dateWed, 01 Feb 2012 18:17:35 +0000
treeherdermozilla-aurora@6fb3bf232436 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone12.0a1
Merge last PGO-green changeset of mozilla-inbound to mozilla-central
content/base/src/nsContentUtils.cpp
gfx/2d/DrawTargetCG.cpp
--- a/accessible/src/base/nsAccessible.cpp
+++ b/accessible/src/base/nsAccessible.cpp
@@ -588,40 +588,23 @@ nsAccessible::TranslateString(const nsAS
   aStringOut.Assign(xsValue);
 }
 
 PRUint64
 nsAccessible::VisibilityState()
 {
   PRUint64 vstates = states::INVISIBLE | states::OFFSCREEN;
 
-  // We need to check the parent chain for visibility.
-  nsAccessible* accessible = this;
-  do {
-    // We don't want background tab page content to be aggressively invisible.
-    // Otherwise this foils screen reader virtual buffer caches.
-    roles::Role role = accessible->Role();
-    if (role == roles::PROPERTYPAGE || role == roles::PANE)
-      break;
-
-    nsIFrame* frame = accessible->GetFrame();
-    if (!frame)
-      return vstates;
-
-    const nsIView* view = frame->GetView();
-    if (view && view->GetVisibility() == nsViewVisibility_kHide)
-      return vstates;
-    
-  } while (accessible = accessible->Parent());
-
   nsIFrame* frame = GetFrame();
   if (!frame)
     return vstates;
 
   const nsCOMPtr<nsIPresShell> shell(GetPresShell());
+  if (!shell)
+    return vstates;
 
   // We need to know if at least a kMinPixels around the object is visible,
   // otherwise it will be marked states::OFFSCREEN.
   const PRUint16 kMinPixels  = 12;
   const nsSize frameSize = frame->GetSize();
   const nsRectVisibility rectVisibility =
     shell->GetRectVisibility(frame, nsRect(nsPoint(0,0), frameSize),
                              nsPresContext::CSSPixelsToAppUnits(kMinPixels));
@@ -639,16 +622,20 @@ nsAccessible::VisibilityState()
       frame->GetRect().IsEmpty()) {
     nsAutoString renderedText;
     frame->GetRenderedText(&renderedText, nsnull, nsnull, 0, 1);
     if (renderedText.IsEmpty())
       return vstates;
 
   }
 
+  // XXX Do we really need to cross from content to chrome ancestor?
+  if (!frame->IsVisibleConsideringAncestors(nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY))
+    return vstates;
+
   // Assume we are visible enough.
   return vstates &= ~states::INVISIBLE;
 }
 
 PRUint64
 nsAccessible::NativeState()
 {
   PRUint64 state = 0;
--- a/b2g/confvars.sh
+++ b/b2g/confvars.sh
@@ -42,16 +42,17 @@ MOZ_APP_VERSION=11.0a1
 
 MOZ_BRANDING_DIRECTORY=b2g/branding/unofficial
 MOZ_OFFICIAL_BRANDING_DIRECTORY=b2g/branding/official
 # MOZ_APP_DISPLAYNAME is set by branding/configure.sh
 
 MOZ_SAFE_BROWSING=
 MOZ_SERVICES_SYNC=
 
+MOZ_WEBSMS_BACKEND=1
 MOZ_DISABLE_DOMCRYPTO=1
 MOZ_APP_STATIC_INI=1
 
 if test "$OS_TARGET" = "Android"; then
 MOZ_CAPTURE=1
 MOZ_RAW=1
 fi
 
--- a/build/mobile/robocop/Actions.java.in
+++ b/build/mobile/robocop/Actions.java.in
@@ -55,15 +55,21 @@ public interface Actions {
   /**
    * Listens for a gecko event to be sent from the Gecko instance.
    * The returned object can be used to test if the event has been
    * received. Note that only one event is listened for.
    * 
    * @param geckoEvent The geckoEvent JSONObject's type
    */
   EventExpecter expectGeckoEvent(String geckoEvent);
+
+  /**
+   * Listens for a paint event.
+   */
+  EventExpecter expectPaint();
+
   // Send the string kewsToSend to the application 
   void sendKeys(String keysToSend);
   //Send any of the above keys to the element
   void sendSpecialKey(SpecialKey button);
 
   void drag(int startingX, int endingX, int startingY, int endingY);
 }
--- a/build/mobile/robocop/Assert.java.in
+++ b/build/mobile/robocop/Assert.java.in
@@ -47,9 +47,12 @@ public interface Assert {
   void finalize();
   void ok(boolean condition, String name, String diag);
   void is(Object a, Object b, String name);
   void isnot(Object a, Object b, String name);
   void todo(boolean condition, String name, String diag);
   void todo_is(Object a, Object b, String name);
   void todo_isnot(Object a, Object b, String name);
   void info(String name, String message);
+
+  // robocop-specific asserts
+  void ispixel(int actual, int r, int g, int b, String name);
 }
--- a/build/mobile/robocop/Driver.java.in
+++ b/build/mobile/robocop/Driver.java.in
@@ -63,9 +63,16 @@ public interface Driver {
   int getHeight();
   int getGeckoTop();
   int getGeckoLeft();
   int getGeckoWidth();
   int getGeckoHeight();
 
   void startFrameRecording();
   int stopFrameRecording();
+
+  /**
+   * Get a copy of the painted content region.
+   * @return A 2-D array of pixels (indexed by y, then x). The pixels
+   * are in ARGB-8888 format.
+   */
+  int[][] getPaintedSurface();
 }
--- a/build/mobile/robocop/FennecNativeActions.java.in
+++ b/build/mobile/robocop/FennecNativeActions.java.in
@@ -68,44 +68,53 @@ import java.util.concurrent.SynchronousQ
 import org.json.*;
 
 import com.jayway.android.robotium.solo.Solo;
 
 public class FennecNativeActions implements Actions {
   // Map of IDs to element names.
   private Solo solo;
   private Instrumentation instr;
+  private Activity geckoApp;
 
   // Objects for reflexive access of fennec classes.
   private ClassLoader classLoader;
   private Class gel;
   private Class ge;
   private Class gas;
+  private Class drawListener;
   private Method registerGEL;
   private Method unregisterGEL;
   private Method sendGE;
-
+  private Method getLayerClient;
+  private Method setDrawListener;
 
   public FennecNativeActions(Activity activity, Solo robocop, Instrumentation instrumentation){
     this.solo = robocop;
     this.instr = instrumentation;
+    this.geckoApp = activity;
     // Set up reflexive access of java classes and methods.
     try {
       classLoader = activity.getClassLoader();
       gel = classLoader.loadClass("org.mozilla.gecko.GeckoEventListener");
       ge = classLoader.loadClass("org.mozilla.gecko.GeckoEvent");
       gas = classLoader.loadClass("org.mozilla.gecko.GeckoAppShell");
       Class [] parameters = new Class[2];
       parameters[0] = String.class;
       parameters[1] = gel;
       registerGEL = gas.getMethod("registerGeckoEventListener", parameters);
       unregisterGEL = gas.getMethod("unregisterGeckoEventListener", parameters);
       parameters = new Class[1];
       parameters[0] = ge;
       sendGE = gas.getMethod("sendEventToGecko", parameters);
+
+      getLayerClient = activity.getClass().getMethod("getSoftwareLayerClient");
+      Class gslc = classLoader.loadClass("org.mozilla.gecko.gfx.GeckoSoftwareLayerClient");
+      drawListener = classLoader.loadClass("org.mozilla.gecko.gfx.GeckoSoftwareLayerClient$DrawListener");
+      setDrawListener = gslc.getDeclaredMethod("setDrawListener", drawListener);
      } catch (ClassNotFoundException e) {
        e.printStackTrace();
      } catch (SecurityException e) {
        e.printStackTrace();
      } catch (NoSuchMethodException e) {
        e.printStackTrace();
      } catch (IllegalArgumentException e) {
        e.printStackTrace();
@@ -200,16 +209,85 @@ public class FennecNativeActions impleme
     } catch (IllegalAccessException e) {
       e.printStackTrace();
     } catch (InvocationTargetException e) {
       e.printStackTrace();
     }
     return null;
   }
 
+  class DrawListenerProxy implements InvocationHandler {
+    private final PaintExpecter mPaintExpecter;
+
+    DrawListenerProxy(PaintExpecter paintExpecter) {
+      mPaintExpecter = paintExpecter;
+    }
+
+    public Object invoke(Object proxy, Method method, Object[] args) {
+      String methodName = method.getName();
+      if ("drawFinished".equals(methodName)) {
+        Log.i("Robocop", "Received drawFinished notification");
+        mPaintExpecter.notifyOfEvent();
+      } else if ("toString".equals(methodName)) {
+        return "DrawListenerProxy";
+      } else if ("equals".equals(methodName)) {
+        return false;
+      } else if ("hashCode".equals(methodName)) {
+        return 0;
+      }
+      return null;
+    }
+  }
+
+  class PaintExpecter implements EventExpecter {
+    private Object mLayerClient;
+    private boolean mPaintDone;
+
+    PaintExpecter() throws IllegalAccessException, InvocationTargetException {
+      mLayerClient = getLayerClient.invoke(geckoApp);
+      setDrawListener.invoke(mLayerClient, Proxy.newProxyInstance(classLoader, new Class[] { drawListener }, new DrawListenerProxy(this)));
+    }
+
+    void notifyOfEvent() {
+      try {
+        setDrawListener.invoke(mLayerClient, (Object)null);
+      } catch (Exception e) {
+        e.printStackTrace();
+      }
+      synchronized (this) {
+        mPaintDone = true;
+        this.notifyAll();
+      }
+    }
+
+    public synchronized void blockForEvent() {
+      while (! mPaintDone) {
+        try {
+          this.wait();
+        } catch (InterruptedException ie) {
+          ie.printStackTrace();
+          break;
+        }
+      }
+    }
+
+    public synchronized boolean eventReceived() {
+      return mPaintDone;
+    }
+  }
+
+  public EventExpecter expectPaint() {
+    try {
+      return new PaintExpecter();
+    } catch (Exception e) {
+      e.printStackTrace();
+      return null;
+    }
+  }
+
   public void sendSpecialKey(SpecialKey button) {
     switch( button) {
       case DOWN:
         instr.sendCharacterSync(KeyEvent.KEYCODE_DPAD_DOWN);
         break;
       case UP:
         instr.sendCharacterSync(KeyEvent.KEYCODE_DPAD_UP);
         break;
--- a/build/mobile/robocop/FennecNativeAssert.java.in
+++ b/build/mobile/robocop/FennecNativeAssert.java.in
@@ -238,16 +238,33 @@ public class FennecNativeAssert implemen
     boolean pass = !a.equals(b);
     String diag = "didn't expect " + a.toString() + ", but got it";
     if(pass) {
       diag = a.toString() + " should not equal " + b.toString();
     }
     ok(pass, name, diag);
   }
 
+  public void ispixel(int actual, int r, int g, int b, String name) {
+    // When we read GL pixels the GPU has already processed them and they
+    // are usually off by a little bit. For example a CSS-color pixel of color #64FFF5
+    // was turned into #63FFF7 when it came out of glReadPixels. So in order to compare
+    // against the expected value, we use a little fuzz factor. For the alpha we just
+    // make sure it is always 0xFF.
+    int aAlpha = ((actual >> 24) & 0xFF);
+    int aR = ((actual >> 16) & 0xFF);
+    int aG = ((actual >> 8) & 0xFF);
+    int aB = (actual & 0xFF);
+    boolean pass = (aAlpha == 0xFF) /* alpha */
+                && (Math.abs(aR - r) < 8) /* red */
+                && (Math.abs(aG - g) < 8) /* green */
+                && (Math.abs(aB - b) < 8); /* blue */
+    ok(pass, name, "Color rgba(" + aR + "," + aG + "," + aB + "," + aAlpha + ")" + (pass ? " " : " not") + " close enough to expected rgb(" + r + "," + g + "," + b + ")");
+  }
+
   public void todo(boolean condition, String name, String diag) {
     testInfo test = new testInfo(condition, name, diag, true);
     _logMochitestResult(test, "TEST-UNEXPECTED-PASS", "TEST-KNOWN-FAIL");
     testList.add(test);
   }
 
   public void todo_is(Object a, Object b, String name) {
     boolean pass = a.equals(b);
--- a/build/mobile/robocop/FennecNativeDriver.java.in
+++ b/build/mobile/robocop/FennecNativeDriver.java.in
@@ -40,29 +40,31 @@
 package @ANDROID_PACKAGE_NAME@;
 
 import java.io.BufferedReader;
 import java.io.BufferedWriter;
 import java.io.File;
 import java.io.FileReader;
 import java.io.FileWriter;
 import java.io.IOException;
+import java.nio.IntBuffer;
 import java.util.ArrayList;
 import java.util.LinkedList;
 import java.util.HashMap;
 import java.util.List;
 
 import java.lang.Class;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Proxy;
 import java.lang.reflect.InvocationHandler;
 import java.lang.Long;
 
 import android.app.Activity;
+import android.opengl.GLSurfaceView;
 import android.util.Log;
 import android.view.View;
 
 import org.json.*;
 
 import com.jayway.android.robotium.solo.Solo;
 
 public class FennecNativeDriver implements Driver {
@@ -76,16 +78,17 @@ public class FennecNativeDriver implemen
   private Class gel;
   private Class ge;
   private Class gas;
   private Method registerGEL;
   private Method unregisterGEL;
   private Method sendGE;
   private Method _startFrameRecording;
   private Method _stopFrameRecording;
+  private Method _getPixels;
 
   public FennecNativeDriver(Activity activity, Solo robocop){
     this.activity = activity;
     this.solo = robocop;
 
     // Set up table of fennec_ids.
     locators = convertTextToTable(getFile("/mnt/sdcard/fennec_ids.txt"));
 
@@ -102,16 +105,19 @@ public class FennecNativeDriver implemen
       unregisterGEL = gas.getMethod("unregisterGeckoEventListener", parameters);
       parameters = new Class[1];
       parameters[0] = ge;
       sendGE = gas.getMethod("sendEventToGecko", parameters);
 
       Class gfx = classLoader.loadClass("org.mozilla.gecko.gfx.PanningPerfAPI");
       _startFrameRecording = gfx.getDeclaredMethod("startFrameTimeRecording");
       _stopFrameRecording = gfx.getDeclaredMethod("stopFrameTimeRecording");
+
+      Class layerView = classLoader.loadClass("org.mozilla.gecko.gfx.LayerView");
+      _getPixels = layerView.getDeclaredMethod("getPixels");
      } catch (ClassNotFoundException e) {
        e.printStackTrace();
      } catch (SecurityException e) {
        e.printStackTrace();
      } catch (NoSuchMethodException e) {
        e.printStackTrace();
      } catch (IllegalArgumentException e) {
        e.printStackTrace();
@@ -207,16 +213,53 @@ public class FennecNativeDriver implemen
       e.printStackTrace();
     } catch (InvocationTargetException e) {
       e.printStackTrace();
     }
 
     return 0;
   }
 
+  private GLSurfaceView getSurfaceView() {
+    for (View v : solo.getCurrentViews()) {
+      if (v instanceof GLSurfaceView) {
+        return (GLSurfaceView)v;
+      }
+    }
+    return null;
+  }
+
+  public int[][] getPaintedSurface() {
+    GLSurfaceView view = getSurfaceView();
+    if (view == null) {
+      return null;
+    }
+    IntBuffer pixelBuffer;
+    try {
+      pixelBuffer = (IntBuffer)_getPixels.invoke(view);
+    } catch (Exception e) {
+      e.printStackTrace();
+      return null;
+    }
+
+    // now we need to (1) flip the image, because GL likes to do things up-side-down,
+    // and (2) rearrange the bits from AGBR-8888 to ARGB-8888.
+    int w = view.getWidth();
+    int h = view.getHeight();
+    pixelBuffer.position(0);
+    int[][] pixels = new int[h][w];
+    for (int y = h - 1; y >= 0; y--) {
+      for (int x = 0; x < w; x++) {
+        int agbr = pixelBuffer.get();
+        pixels[y][x] = (agbr & 0xFF00FF00) | ((agbr >> 16) & 0x000000FF) | ((agbr << 16) & 0x00FF0000);
+      }
+    }
+    return pixels;
+  }
+
   class scrollHandler implements InvocationHandler {
     public scrollHandler(){};
     public Object invoke(Object proxy, Method method, Object[] args) {
       try{
         //Disect the JSON object into the appropriate variables 
         JSONObject jo = ((JSONObject)args[1]);
         scrollHeight = jo.getInt("y");
         height = jo.getInt("cheight");
--- a/build/mobile/robocop/Makefile.in
+++ b/build/mobile/robocop/Makefile.in
@@ -63,16 +63,17 @@ JAVAFILES = \
   $(NULL)
 
 _JAVA_TESTS = $(patsubst $(TESTPATH)/%.in,%,$(wildcard $(TESTPATH)/*.java.in))
 
 _TEST_FILES = \
   $(TESTPATH)/robocop_blank_01.html \
   $(TESTPATH)/robocop_blank_02.html \
   $(TESTPATH)/robocop_blank_03.html \
+  $(TESTPATH)/robocop_boxes.html \
   $(NULL)
 
 _ROBOCOP_TOOLS = \
   $(TESTPATH)/robocop.ini \
   parse_ids.py \
   $(NULL)
 
 GARBAGE += \
--- a/config/android-common.mk
+++ b/config/android-common.mk
@@ -65,11 +65,11 @@ ifndef JAVA_VERSION
 endif
 
 JAVAC_FLAGS = \
   -target $(JAVA_VERSION) \
   -source $(JAVA_VERSION) \
   -classpath $(JAVA_CLASSPATH) \
   -bootclasspath $(JAVA_BOOTCLASSPATH) \
   -encoding UTF8 \
-  -g \
+  -g:source,lines \
   -Werror \
   $(NULL)
--- a/configure.in
+++ b/configure.in
@@ -4901,22 +4901,24 @@ cairo-android)
     if test "$MOZ_BUILD_APP" = "mobile/xul"; then
         MOZ_OLD_LINKER=1
     fi
     MOZ_TOUCH=1
     ;;
 
 cairo-gonk)
     AC_DEFINE(MOZ_WIDGET_GONK)
+    AC_DEFINE(MOZ_TOUCH)
     MOZ_WIDGET_TOOLKIT=gonk
     TK_CFLAGS='$(MOZ_CAIRO_CFLAGS)'
     TK_LIBS='$(MOZ_CAIRO_LIBS)'
     MOZ_WEBGL=1
     MOZ_PDF_PRINTING=1
     MOZ_B2G_RIL=1
+    MOZ_TOUCH=1
     ;;
 
 esac
 
 AC_SUBST(MOZ_OLD_LINKER)
 AC_SUBST(MOZ_PDF_PRINTING)
 if test "$MOZ_PDF_PRINTING"; then
    PDF_SURFACE_FEATURE="#define CAIRO_HAS_PDF_SURFACE 1"
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -173,16 +173,58 @@ enum EventNameType {
   EventNameType_SVGGraphic = 0x0004, // svg graphic elements
   EventNameType_SVGSVG = 0x0008, // the svg element
   EventNameType_SMIL = 0x0016, // smil elements
 
   EventNameType_HTMLXUL = 0x0003,
   EventNameType_All = 0xFFFF
 };
 
+/**
+ * Information retrieved from the <meta name="viewport"> tag. See
+ * GetViewportInfo for more information on this functionality.
+ */
+struct ViewportInfo
+{
+    // Default zoom indicates the level at which the display is 'zoomed in'
+    // initially for the user, upon loading of the page.
+    double defaultZoom;
+
+    // The minimum zoom level permitted by the page.
+    double minZoom;
+
+    // The maximum zoom level permitted by the page.
+    double maxZoom;
+
+    // The width of the viewport, specified by the <meta name="viewport"> tag,
+    // in CSS pixels.
+    PRUint32 width;
+
+    // The height of the viewport, specified by the <meta name="viewport"> tag,
+    // in CSS pixels.
+    PRUint32 height;
+
+    // Whether or not we should automatically size the viewport to the device's
+    // width. This is true if the document has been optimized for mobile, and
+    // the width property of a specified <meta name="viewport"> tag is either
+    // not specified, or is set to the special value 'device-width'.
+    bool autoSize;
+
+    // Whether or not the user can zoom in and out on the page. Default is true.
+    bool allowZoom;
+
+    // This is a holdover from e10s fennec, and might be removed in the future.
+    // It's a hack to work around bugs that didn't allow zooming of documents
+    // from within the parent process. It is still used in native Fennec for XUL
+    // documents, but it should probably be removed.
+    // Currently, from, within GetViewportInfo(), This is only set to false
+    // if the document is a XUL document.
+    bool autoScale;
+};
+
 struct EventNameMapping
 {
   nsIAtom* mAtom;
   PRUint32 mId;
   PRInt32  mType;
   PRUint32 mStructType;
 };
 
@@ -1484,16 +1526,28 @@ public:
    *
    * The only known case where this lies is mutation events. They run, and can
    * run anything else, when this function returns false, but this is ok.
    */
   static bool IsSafeToRunScript() {
     return sScriptBlockerCount == 0;
   }
 
+  /**
+   * Retrieve information about the viewport as a data structure.
+   * This will return information in the viewport META data section
+   * of the document. This can be used in lieu of ProcessViewportInfo(),
+   * which places the viewport information in the document header instead
+   * of returning it directly.
+   *
+   * NOTE: If the site is optimized for mobile (via the doctype), this
+   * will return viewport information that specifies default information.
+   */
+  static ViewportInfo GetViewportInfo(nsIDocument* aDocument);
+
   /* Process viewport META data. This gives us information for the scale
    * and zoom of a page on mobile devices. We stick the information in
    * the document header and use it later on after rendering.
    *
    * See Bug #436083
    */
   static nsresult ProcessViewportInfo(nsIDocument *aDocument,
                                       const nsAString &viewportInfo);
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -206,26 +206,39 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_
 #include "nsIScriptElement.h"
 #include "nsIContentViewer.h"
 #include "nsIObjectLoadingContent.h"
 #include "nsCCUncollectableMarker.h"
 #include "mozilla/Base64.h"
 #include "mozilla/Preferences.h"
 
 #include "nsWrapperCacheInlines.h"
+#include "nsIDOMDocumentType.h"
+#include "nsIDOMWindowUtils.h"
 #include "nsCharSeparatedTokenizer.h"
 #include "nsUnicharUtils.h"
 
 using namespace mozilla::dom;
 using namespace mozilla::layers;
 using namespace mozilla::widget;
 using namespace mozilla;
 
 const char kLoadAsData[] = "loadAsData";
 
+/**
+ * Default values for the ViewportInfo structure.
+ */
+static const float    kViewportMinScale = 0.0;
+static const float    kViewportMaxScale = 10.0;
+static const PRUint32 kViewportMinWidth = 200;
+static const PRUint32 kViewportMaxWidth = 10000;
+static const PRUint32 kViewportMinHeight = 223;
+static const PRUint32 kViewportMaxHeight = 10000;
+static const PRInt32  kViewportDefaultScreenWidth = 980;
+
 static const char kJSStackContractID[] = "@mozilla.org/js/xpc/ContextStack;1";
 static NS_DEFINE_CID(kParserServiceCID, NS_PARSERSERVICE_CID);
 static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID);
 
 nsIDOMScriptObjectFactory *nsContentUtils::sDOMScriptObjectFactory = nsnull;
 nsIXPConnect *nsContentUtils::sXPConnect;
 nsIScriptSecurityManager *nsContentUtils::sSecurityManager;
 nsIThreadJSContextStack *nsContentUtils::sThreadJSContextStack;
@@ -4552,16 +4565,208 @@ static void ProcessViewportToken(nsIDocu
   else if (key_atom == nsGkAtoms::user_scalable)
     aDocument->SetHeaderData(nsGkAtoms::viewport_user_scalable, value);
 }
 
 #define IS_SEPARATOR(c) ((c == '=') || (c == ',') || (c == ';') || \
                          (c == '\t') || (c == '\n') || (c == '\r'))
 
 /* static */
+ViewportInfo
+nsContentUtils::GetViewportInfo(nsIDocument *aDocument)
+{
+  ViewportInfo ret;
+  ret.defaultZoom = 1.0;
+  ret.autoSize = true;
+  ret.allowZoom = true;
+  ret.autoScale = true;
+
+  // If the docType specifies that we are on a site optimized for mobile,
+  // then we want to return specially crafted defaults for the viewport info.
+  nsCOMPtr<nsIDOMDocument>
+    domDoc(do_QueryInterface(aDocument));
+
+  nsCOMPtr<nsIDOMDocumentType> docType;
+  nsresult rv = domDoc->GetDoctype(getter_AddRefs(docType));
+  if (NS_SUCCEEDED(rv) && docType) {
+    nsAutoString docId;
+    rv = docType->GetPublicId(docId);
+    if (NS_SUCCEEDED(rv)) {
+      if ((docId.Find("WAP") != -1) ||
+          (docId.Find("Mobile") != -1) ||
+          (docId.Find("WML") != -1))
+      {
+        return ret;
+      }
+    }
+  }
+
+  if (aDocument->IsXUL()) {
+    ret.autoScale = false;
+    return ret;
+  }
+
+  nsIDOMWindow* window = aDocument->GetWindow();
+  nsCOMPtr<nsIDOMWindowUtils> windowUtils(do_GetInterface(window));
+
+  if (!windowUtils) {
+    return ret;
+  }
+
+  nsAutoString handheldFriendly;
+  aDocument->GetHeaderData(nsGkAtoms::handheldFriendly, handheldFriendly);
+
+  if (handheldFriendly.EqualsLiteral("true")) {
+    return ret;
+  }
+
+  PRInt32 errorCode;
+
+  nsAutoString minScaleStr;
+  aDocument->GetHeaderData(nsGkAtoms::minimum_scale, minScaleStr);
+
+  float scaleMinFloat = minScaleStr.ToFloat(&errorCode);
+
+  if (errorCode) {
+    scaleMinFloat = kViewportMinScale;
+  }
+
+  scaleMinFloat = NS_MIN(scaleMinFloat, kViewportMaxScale);
+  scaleMinFloat = NS_MAX(scaleMinFloat, kViewportMinScale);
+
+  nsAutoString maxScaleStr;
+  aDocument->GetHeaderData(nsGkAtoms::maximum_scale, maxScaleStr);
+
+  // We define a special error code variable for the scale and max scale,
+  // because they are used later (see the width calculations).
+  PRInt32 scaleMaxErrorCode;
+  float scaleMaxFloat = maxScaleStr.ToFloat(&scaleMaxErrorCode);
+
+  if (scaleMaxErrorCode) {
+    scaleMaxFloat = kViewportMaxScale;
+  }
+
+  scaleMaxFloat = NS_MIN(scaleMaxFloat, kViewportMaxScale);
+  scaleMaxFloat = NS_MAX(scaleMaxFloat, kViewportMinScale);
+
+  nsAutoString scaleStr;
+  aDocument->GetHeaderData(nsGkAtoms::viewport_initial_scale, scaleStr);
+
+  PRInt32 scaleErrorCode;
+  float scaleFloat = scaleStr.ToFloat(&scaleErrorCode);
+  scaleFloat = NS_MIN(scaleFloat, scaleMaxFloat);
+  scaleFloat = NS_MAX(scaleFloat, scaleMinFloat);
+
+  nsAutoString widthStr, heightStr;
+
+  aDocument->GetHeaderData(nsGkAtoms::viewport_height, heightStr);
+  aDocument->GetHeaderData(nsGkAtoms::viewport_width, widthStr);
+
+  bool autoSize = false;
+
+  if (widthStr.EqualsLiteral("device-width")) {
+    autoSize = true;
+  }
+
+  if (widthStr.IsEmpty() &&
+     (heightStr.EqualsLiteral("device-height") ||
+          scaleFloat == 1.0))
+  {
+    autoSize = true;
+  }
+
+  // XXXjwir3:
+  // See bug 706918, comment 23 for more information on this particular section
+  // of the code. We're using "screen size" in place of the size of the content
+  // area, because on mobile, these are close or equal. This will work for our
+  // purposes (bug 706198), but it will need to be changed in the future to be
+  // more correct when we bring the rest of the viewport code into platform.
+  // We actually want the size of the content area, in the event that we don't
+  // have any metadata about the width and/or height. On mobile, the screen size
+  // and the size of the content area are very close, or the same value.
+  // In XUL fennec, the content area is the size of the <browser> widget, but
+  // in native fennec, the content area is the size of the Gecko LayerView
+  // object.
+
+  // TODO:
+  // Once bug 716575 has been resolved, this code should be changed so that it
+  // does the right thing on all platforms.
+  nsresult result;
+  PRInt32 screenLeft, screenTop, screenWidth, screenHeight;
+  nsCOMPtr<nsIScreenManager> screenMgr =
+    do_GetService("@mozilla.org/gfx/screenmanager;1", &result);
+
+  nsCOMPtr<nsIScreen> screen;
+  screenMgr->GetPrimaryScreen(getter_AddRefs(screen));
+  screen->GetRect(&screenLeft, &screenTop, &screenWidth, &screenHeight);
+
+  PRUint32 width = widthStr.ToInteger(&errorCode);
+  if (errorCode) {
+    if (autoSize) {
+      width = screenWidth;
+    } else {
+      width = Preferences::GetInt("browser.viewport.desktopWidth", 0);
+    }
+  }
+
+  width = NS_MIN(width, kViewportMaxWidth);
+  width = NS_MAX(width, kViewportMinWidth);
+
+  // Also recalculate the default zoom, if it wasn't specified in the metadata,
+  // and the width is specified.
+  if (scaleStr.IsEmpty() && !widthStr.IsEmpty()) {
+    scaleFloat = NS_MAX(scaleFloat, (float)(screenWidth/width));
+  }
+
+  PRUint32 height = heightStr.ToInteger(&errorCode);
+
+  if (errorCode) {
+    height = width * ((float)screenHeight / screenWidth);
+  }
+
+  // If height was provided by the user, but width wasn't, then we should
+  // calculate the width.
+  if (widthStr.IsEmpty() && !heightStr.IsEmpty()) {
+    width = (PRUint32) ((height * screenWidth) / screenHeight);
+  }
+
+  height = NS_MIN(height, kViewportMaxHeight);
+  height = NS_MAX(height, kViewportMinHeight);
+
+  // We need to perform a conversion, but only if the initial or maximum
+  // scale were set explicitly by the user.
+  if (!scaleStr.IsEmpty() && !scaleErrorCode) {
+    width = NS_MAX(width, (PRUint32)(screenWidth / scaleFloat));
+    height = NS_MAX(height, (PRUint32)(screenHeight / scaleFloat));
+  } else if (!maxScaleStr.IsEmpty() && !scaleMaxErrorCode) {
+    width = NS_MAX(width, (PRUint32)(screenWidth / scaleMaxFloat));
+    height = NS_MAX(height, (PRUint32)(screenHeight / scaleMaxFloat));
+  }
+
+  bool allowZoom = true;
+  nsAutoString userScalable;
+  aDocument->GetHeaderData(nsGkAtoms::viewport_user_scalable, userScalable);
+
+  if ((userScalable.EqualsLiteral("0")) ||
+      (userScalable.EqualsLiteral("no")) ||
+      (userScalable.EqualsLiteral("false"))) {
+    allowZoom = false;
+  }
+
+  ret.allowZoom = allowZoom;
+  ret.width = width;
+  ret.height = height;
+  ret.defaultZoom = scaleFloat;
+  ret.minZoom = scaleMinFloat;
+  ret.maxZoom = scaleMaxFloat;
+  ret.autoSize = autoSize;
+  return ret;
+}
+
+/* static */
 nsresult
 nsContentUtils::ProcessViewportInfo(nsIDocument *aDocument,
                                     const nsAString &viewportInfo) {
 
   /* We never fail. */
   nsresult rv = NS_OK;
 
   /* Iterators. */
--- a/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
+++ b/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
@@ -990,17 +990,17 @@ NS_NewCanvasRenderingContext2DAzure(nsID
 {
 #ifdef XP_WIN
   if ((gfxWindowsPlatform::GetPlatform()->GetRenderMode() !=
       gfxWindowsPlatform::RENDER_DIRECT2D ||
       !gfxWindowsPlatform::GetPlatform()->DWriteEnabled()) &&
       !Preferences::GetBool("gfx.canvas.azure.prefer-skia", false)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
-#elif !defined(XP_MACOSX) && !defined(ANDROID) && !defined(XP_LINUX)
+#elif !defined(XP_MACOSX) && !defined(ANDROID) && !defined(LINUX)
   return NS_ERROR_NOT_AVAILABLE;
 #endif
 
   nsRefPtr<nsIDOMCanvasRenderingContext2D> ctx = new nsCanvasRenderingContext2DAzure();
   if (!ctx)
     return NS_ERROR_OUT_OF_MEMORY;
 
   *aResult = ctx.forget().get();
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -278,16 +278,19 @@ static PRInt32              gRefCnt     
 static PRInt32              gOpenPopupSpamCount        = 0;
 static PopupControlState    gPopupControlState         = openAbused;
 static PRInt32              gRunningTimeoutDepth       = 0;
 static bool                 gMouseDown                 = false;
 static bool                 gDragServiceDisabled       = false;
 static FILE                *gDumpFile                  = nsnull;
 static PRUint64             gNextWindowID              = 0;
 static PRUint32             gSerialCounter             = 0;
+static PRUint32             gTimeoutsRecentlySet       = 0;
+static TimeStamp            gLastRecordedRecentTimeouts;
+#define STATISTICS_INTERVAL (30 * PR_MSEC_PER_SEC)
 
 #ifdef DEBUG_jst
 PRInt32 gTimeoutCnt                                    = 0;
 #endif
 
 #if !(defined(NS_DEBUG) || defined(MOZ_ENABLE_JS_DUMP))
 static bool                 gDOMWindowDumpEnabled      = false;
 #endif
@@ -9049,16 +9052,17 @@ nsGlobalWindow::SetTimeoutOrInterval(nsI
   }
 
   if (subsumes) {
     timeout->mPrincipal = subjectPrincipal;
   } else {
     timeout->mPrincipal = ourPrincipal;
   }
 
+  ++gTimeoutsRecentlySet;
   TimeDuration delta = TimeDuration::FromMilliseconds(realInterval);
 
   if (!IsFrozen() && !mTimeoutsSuspendDepth) {
     // If we're not currently frozen, then we set timeout->mWhen to be the
     // actual firing time of the timer (i.e., now + delta). We also actually
     // create a timer and fire it off.
 
     timeout->mWhen = TimeStamp::Now() + delta;
@@ -9223,16 +9227,26 @@ nsGlobalWindow::RunTimeout(nsTimeout *aT
 
   // Maybe the timeout that the event was fired for has been deleted
   // and there are no others timeouts with deadlines that make them
   // eligible for execution yet. Go away.
   if (!last_expired_timeout) {
     return;
   }
 
+  // Record telemetry information about timers set recently.
+  TimeDuration recordingInterval = TimeDuration::FromMilliseconds(STATISTICS_INTERVAL);
+  if (gLastRecordedRecentTimeouts.IsNull() ||
+      now - gLastRecordedRecentTimeouts > recordingInterval) {
+    PRUint32 count = gTimeoutsRecentlySet;
+    gTimeoutsRecentlySet = 0;
+    Telemetry::Accumulate(Telemetry::DOM_TIMERS_RECENTLY_SET, count);
+    gLastRecordedRecentTimeouts = now;
+  }
+
   // Insert a dummy timeout into the list of timeouts between the
   // portion of the list that we are about to process now and those
   // timeouts that will be processed in a future call to
   // win_run_timeout(). This dummy timeout serves as the head of the
   // list for any timeouts inserted as a result of running a timeout.
   dummy_timeout.mFiringDepth = firingDepth;
   dummy_timeout.mWhen = now;
   PR_INSERT_AFTER(&dummy_timeout, last_expired_timeout);
--- a/dom/wifi/nsWifiWorker.js
+++ b/dom/wifi/nsWifiWorker.js
@@ -478,25 +478,44 @@ var WifiManager = (function() {
     var handler = manager["on" + eventName];
     if (handler) {
       if (!eventObject)
         eventObject = ({});
       handler.call(eventObject);
     }
   }
 
+  function parseStatus(status) {
+    if (status === null) {
+      debug("Unable to get wpa supplicant's status");
+      return;
+    }
+
+    var lines = status.split("\n");
+    for (let i = 0; i < lines.length; ++i) {
+      let [key, value] = lines[i].split("=");
+      if (key === "wpa_state") {
+        if (value === "COMPLETED")
+          onconnected();
+      }
+    }
+  }
+
   // try to connect to the supplicant
   var connectTries = 0;
   var retryTimer = null;
   function connectCallback(ok) {
     if (ok === 0) {
-      // tell the event worker to start waiting for events
+      // Tell the event worker to start waiting for events.
       retryTimer = null;
       waitForEvent();
       notify("supplicantconnection");
+
+      // Load up the supplicant state.
+      statusCommand(parseStatus);
       return;
     }
     if (connectTries++ < 3) {
       // try again in 5 seconds
       if (!retryTimer)
         retryTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
 
       retryTimer.initWithCallback(function(timer) {
@@ -783,51 +802,27 @@ function nsWifiWorker() {
   }
   WifiManager.onsupplicantlost = function() {
     debug("Couldn't connect to supplicant");
   }
 
   var networks = Object.create(null);
   WifiManager.onscanresultsavailable = function() {
     debug("Scan results are available! Asking for them.");
-    if (networks["Mozilla Guest"])
-      return;
     WifiManager.getScanResults(function(r) {
       let lines = r.split("\n");
       // NB: Skip the header line.
-      let added = !("Mozilla Guest" in networks);
       for (let i = 1; i < lines.length; ++i) {
         // bssid / frequency / signal level / flags / ssid
         var match = /([\S]+)\s+([\S]+)\s+([\S]+)\s+(\[[\S]+\])?\s+(.*)/.exec(lines[i])
         if (match)
           networks[match[5]] = match[1];
         else
           debug("Match didn't find anything for: " + lines[i]);
       }
-
-      if (("Mozilla Guest" in networks) && added) {
-        debug("Mozilla Guest exists in networks, trying to connect!");
-        var config = Object.create(null);
-        config["ssid"] = '"Mozilla Guest"';
-        //config["bssid"] = '"' + networks["Mozilla Guest"] + '"';
-        config["key_mgmt"] = "NONE";
-        config["scan_ssid"] = 1;
-        WifiManager.addNetwork(config, function (ok) {
-          if (ok) {
-            WifiManager.enableNetwork(config.netId, false, function (ok) {
-              if (ok)
-                debug("Enabled the network!");
-              else
-                debug("Failed to enable the network :(");
-            });
-          } else {
-            debug("Failed to add the network :(");
-          }
-        });
-      }
     });
   }
 
   WifiManager.setWifiEnabled(true, function (ok) {
       if (ok === 0)
         WifiManager.start();
       else
         debug("Couldn't start Wifi");
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -227,26 +227,26 @@ public:
   }
 
   NS_IMETHOD
   CollectReports(nsIMemoryMultiReporterCallback* aCallback,
                  nsISupports* aClosure)
   {
     AssertIsOnMainThread();
 
-    JS::IterateData data(xpc::JsMallocSizeOf, xpc::GetCompartmentName,
-                         xpc::DestroyCompartmentName);
-    nsresult rv = CollectForRuntime(/* isQuick = */false, &data);
+    JS::RuntimeStats rtStats(xpc::JsMallocSizeOf, xpc::GetCompartmentName,
+                             xpc::DestroyCompartmentName);
+    nsresult rv = CollectForRuntime(/* isQuick = */false, &rtStats);
     if (NS_FAILED(rv)) {
       return rv;
     }
 
     // Always report, even if we're disabled, so that we at least get an entry
     // in about::memory.
-    ReportJSRuntimeStats(data, mPathPrefix, aCallback, aClosure);
+    ReportJSRuntimeStats(rtStats, mPathPrefix, aCallback, aClosure);
 
     return NS_OK;
   }
 
   NS_IMETHOD
   GetExplicitNonHeap(PRInt64 *aAmount)
   {
     AssertIsOnMainThread();
@@ -1519,17 +1519,17 @@ public:
 
   bool
   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
   {
     JSAutoSuspendRequest asr(aCx);
 
     *mSucceeded = mIsQuick
       ? JS::GetExplicitNonHeapForRuntime(JS_GetRuntime(aCx), static_cast<int64_t*>(mData), xpc::JsMallocSizeOf)
-      : JS::CollectCompartmentStatsForRuntime(JS_GetRuntime(aCx), static_cast<JS::IterateData*>(mData));
+      : JS::CollectRuntimeStats(JS_GetRuntime(aCx), static_cast<JS::RuntimeStats*>(mData));
 
     {
       MutexAutoLock lock(mMutex);
       mDone = true;
       mCondVar.Notify();
     }
 
     return true;
--- a/extensions/auth/nsAuthGSSAPI.cpp
+++ b/extensions/auth/nsAuthGSSAPI.cpp
@@ -160,17 +160,18 @@ gssInit()
             "gss",
             "gssapi_krb5",
             "gssapi"
         };
         
         const char *const verLibNames[] = {
             "libgssapi_krb5.so.2", /* MIT - FC, Suse10, Debian */
             "libgssapi.so.4",      /* Heimdal - Suse10, MDK */
-            "libgssapi.so.1"       /* Heimdal - Suse9, CITI - FC, MDK, Suse10*/
+            "libgssapi.so.1",      /* Heimdal - Suse9, CITI - FC, MDK, Suse10*/
+            "libgssapi.so"         /* OpenBSD */
         };
 
         for (size_t i = 0; i < ArrayLength(verLibNames) && !lib; ++i) {
             lib = PR_LoadLibrary(verLibNames[i]);
  
             /* The CITI libgssapi library calls exit() during
              * initialization if it's not correctly configured. Try to
              * ensure that we never use this library for our GSSAPI
--- a/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/upstream-hunspell.diff
+++ b/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/upstream-hunspell.diff
@@ -9138,428 +9138,430 @@ 15460a21264,21266
 > cancelled/U
 > canceller/M
 > cancelling
 15559a21366
 > capita
 15629,15630d21435
 < carburetter/SM
 < carburettor/SM
-15788d21592
+15701a21507
+> carnitas
+15788d21593
 < cashpoint/S
-15797d21600
+15797d21601
 < cassino/M
-15832a21636
+15832a21637
 > catalyses
-15940d21743
+15940d21744
 < caviare/M
-16372c22175
+16372c22176
 < chickenshit/S!
 ---
 > chickenshit/SM!
-16404c22207
+16404c22208
 < children
 ---
 > children/M
-16488d22290
+16488d22291
 < chlorophyl/M
-16629,16630c22431
+16629,16630c22432
 < cider's
 < cider/S
 ---
 > cider/MS
-17072d22872
+17072d22873
 < cocain/M
-17102,17103c22902
+17102,17103c22903
 < cocksucker's
 < cocksucker/S!
 ---
 > cocksucker/SM!
-17755c23554
+17755c23555
 < confer/S
 ---
 > confer/SB
-18151d23949
+18151d23950
 < convenor/S
-18206c24004
+18206c24005
 < cookie/M
 ---
 > cookie/SM
-18467a24266
+18467a24267
 > could've
-19246c25045
+19246c25046
 < cysteine
 ---
 > cysteine/M
-20196,20197c25995,25996
+20196,20197c25996,25997
 < dialog/SM
 < dialogue/SM
 ---
 > dialog/SMGD
 > dialogue/SMRGD
-20481a26281
+20481a26282
 > disclose/DSG
-20830c26630
+20830c26631
 < dogie/M
 ---
 > dogie/SM
-20895a26696
+20895a26697
 > donator/MS
-21820a27622
+21820a27623
 > elicitor/MS
-22071a27874
+22071a27875
 > encyclopaedia
-22556a28360
+22556a28361
 > estoppel
-22638c28442
+22638c28443
 < euthanize
 ---
 > euthanize/DSG
-22719a28524
+22719a28525
 > exabyte/MS
-22947a28753
+22947a28754
 > experimentalism
-23207,23208d29012
+23207,23208d29013
 < faecal
 < faeces/M
-23215c29019
+23215c29020
 < faggoting's
 ---
 > faggot/SMG
-23701a29506
+23701a29507
 > filesystem/MS
-24155c29960
+24155c29961
 < fluidized
 ---
 > fluidize/DSG
-24216a30022
+24216a30023
 > foci
-24736d30541
+24736d30542
 < frier/M
-24855,24856c30660,30661
+24855,24856c30661,30662
 < fucker/M!
 < fuckhead/S!
 ---
 > fucker/SM!
 > fuckhead/SM!
-24953d30757
+24953d30758
 < furore/MS
-25125c30929
+25125c30930
 < gaolbird/S
 ---
 > gaolbirds
-25180d30983
+25180d30984
 < gasolene/M
-25190a30994
+25190a30995
 > gastroenterologist/M
-25262c31066
+25262c31067
 < geezer/M
 ---
 > geezer/MS
-25327c31131
+25327c31132
 < genomic
 ---
 > genomic/S
-25462a31267
+25462a31268
 > gigabit/MS
-25464a31270,31272
+25464a31271,31273
 > gigajoule/MS
 > gigapixel/MS
 > gigawatt/MS
-25560d31367
+25560d31368
 < glamourize/DSG
-25674c31481
+25674c31482
 < glycerine's
 ---
 > glycerine/M
-25905c31712
+25905c31713
 < gram/MS
 ---
 > gram/KMS
-25909d31715
+25909d31716
 < gramme/SM
-26063c31869,31870
+26063c31870,31871
 < greybeard
 ---
 > grey/MDRTGSP
 > greybeard/SM
-26066c31873
+26066c31874
 < greyness
 ---
 > greyness/M
-26246,26247d32052
+26246,26247d32053
 < guerilla's
 < guerillas
-26432,26436d32236
+26432,26436d32237
 < haemoglobin's
 < haemophilia/M
 < haemorrhage/DSMG
 < haemorrhoid/S
 < haemorrhoids/M
-27167c32967
+27167c32968
 < hexane
 ---
 > hexane/SM
-27273a33074
+27273a33075
 > hippopotami
-27875d33675
+27875d33676
 < hyaena/SM
-28017c33817
+28017c33818
 < iPod/M
 ---
 > iPod/MS
-28105a33906
+28105a33907
 > idolator/SM
-28513c34314
+28513c34315
 < inbound
 ---
 > inbound/s
-28650a34452
+28650a34453
 > indices
-28812d34613
+28812d34614
 < inflexion/SM
-29216a35018
+29216a35019
 > intern/GDL
-29272a35075,35078
+29272a35076,35079
 > intersex
 > intersexual/MS
 > intersexualism
 > intersexuality
-29724c35530
+29724c35531
 < jewellery's
 ---
 > jewellery/M
-29870a35677
+29870a35678
 > judgement/MS
-30066c35873
+30066c35874
 < kiddie/M
 ---
 > kiddie/SM
-30262,30263c36069
+30262,30263c36070
 < kraut's
 < kraut/S!
 ---
 > kraut/MS!
-30665a36472
+30665a36473
 > lector/MS
-31031c36838
+31031c36839
 < linguini's
 ---
 > linguini/M
-31151,31152c36958
+31151,31152c36959
 < liver's
 < liver/S
 ---
 > liver/MS
-32230c38036
+32230c38037
 < meanie/M
 ---
 > meanie/MS
-32317,32318c38123
+32317,32318c38124
 < megadeath/M
 < megadeaths
 ---
 > megadeath/SM
-32320c38125
+32320c38126
 < megajoules
 ---
 > megajoule/SM
-32329c38134
+32329c38135
 < megapixel/S
 ---
 > megapixel/MS
-32708a38514
+32708a38515
 > might've
-32777d38582
+32777d38583
 < millionnaire/M
-32934a38740
+32934a38741
 > miscommunication/S
-32991a38798
+32991a38799
 > misjudgement/MS
-33784a39592
+33784a39593
 > must've
-33963c39771
+33963c39772
 < native/MS
 ---
 > native/MSY
-34169,34171c39977,39978
+34169,34171c39978,39979
 < neurone/S
 < neurophysiology
 < neuroscience
 ---
 > neurophysiology/M
 > neuroscience/MS
-34275c40082
+34275c40083
 < nightie/M
 ---
 > nightie/SM
-35104a40912
+35104a40913
 > octopi
-35219d41026
+35219d41027
 < oleomargarin/M
-35226a41034
+35226a41035
 > oligo
-35913c41721
+35913c41722
 < oversize/D
 ---
 > oversize
-36056,36059d41863
+36056,36059d41864
 < paederast/S
 < paediatrician's
 < paediatricians
 < paediatrics/M
-36291a42096
+36291a42097
 > paralyses
-36403d42207
+36403d42208
 < parrakeet/MS
-36449d42252
+36449d42253
 < partizan/SM
-37093a42897
+37093a42898
 > petabyte/MS
-37102c42906
+37102c42907
 < petitioner/M
 ---
 > petitioner/MS
-37264a43069
+37264a43070
 > phosphorylate/DSGN
-37316d43120
+37316d43121
 < phrenetic
-37796a43601
+37796a43602
 > plugin/MS
-37987c43792
+37987c43793
 < polypeptide/S
 ---
 > polypeptide/MS
-38291d44095
+38291d44096
 < practise's
-38451a44256
+38451a44257
 > prejudgement/MS
-38891a44697,44698
+38891a44698,44699
 > pronate/DSGN
 > pronator/MS
-38951c44758
+38951c44759
 < proprietorship/M
 ---
 > proprietorship/MS
-39039a44847
+39039a44848
 > provender/M
-40036a45845
+40036a45846
 > recency
-40141a45951
+40141a45952
 > recuse/DGS
-40208a46019
+40208a46020
 > refactor/SMDG
-40244d46054
+40244d46055
 < reflexion/SM
-40829c46639
+40829c46640
 < reverie/M
 ---
 > reverie/MS
-41415a47226
+41415a47227
 > sabre/MS
-41914c47725
+41914c47726
 < schnaps's
 ---
 > schnaps/M
-41949c47760
+41949c47761
 < schrod's
 ---
 > schrod/SM
-41998a42010
+41998a47811
 > scot-free
-42883,42885c48695
+42883,42885c48696
 < shit's
 < shit/S!
 < shite/S!
 ---
 > shit/MS!
-42887,42888c48697,48698
+42887,42888c48698,48699
 < shithead/S!
 < shitload/!
 ---
 > shithead/MS!
 > shitload/MS!
-42891c48701
+42891c48702
 < shitty/RT!
 ---
 > shitty/TR!
-42976a48787
+42976a48788
 > should've
-43008c48819
+43008c48820
 < showtime
 ---
 > showtime/MS
-43724,43726c49535
+43724,43726c49536
 < smoulder's
 < smouldered
 < smoulders
 ---
 > smoulder/GSMD
-44062c49871
+44062c49872
 < sonofabitch
 ---
 > sonofabitch/!
-44371a50181
+44371a50182
 > spick/S!
-44383c50193
+44383c50194
 < spik/S
 ---
 > spik/S!
-46106a51917
+46106a51918
 > syllabi
-46160c51971
+46160c51972
 < synch/GMD
 ---
 > synch/GMDS
-46167d51977
+46167d51978
 < synchs
-46203,46204c52013,52014
+46203,46204c52014,52015
 < sysadmin/S
 < sysop/S
 ---
 > sysadmin/MS
 > sysop/MS
-46752a52563
+46752a52564
 > terabit/MS
-46753a52565,52566
+46753a52566,52567
 > terahertz/M
 > terapixel/MS
-46817a52631
+46817a52632
 > testcase/MS
-46831a52646
+46831a52647
 > testsuite/MS
-46925a52741
+46925a52742
 > theremin/MS
-47755a53572
+47755a53573
 > transfect/DSMG
-47774a53592,53593
+47774a53593,53594
 > transgenderism
 > transgene/MS
-47951c53770
+47951c53771
 < triage/M
 ---
 > triage/MG
-48869a54689
+48869a54690
 > unlikeable
-49211c55031
+49211c55032
 < vagina/M
 ---
 > vagina/MS
-49368,49369c55188
+49368,49369c55189
 < velour's
 < velours's
 ---
 > velour/MS
-49478a55298
+49478a55299
 > vertices
-50148a55969
+50148a55970
 > weaponize/DSG
-50260,50261d56080
+50260,50261d56081
 < werwolf/M
 < werwolves
-50728c56547
+50728c56548
 < women
 ---
 > women/M
-50794c56613
+50794c56614
 < wop/S!
 ---
 > wop/MS!
--- a/extensions/spellcheck/locales/en-US/hunspell/en-US.dic
+++ b/extensions/spellcheck/locales/en-US/hunspell/en-US.dic
@@ -1,9 +1,9 @@
-57435
+57436
 0/nm
 0th/pt
 1/n1
 1st/p
 1th/tc
 2/nm
 2nd/p
 2th/tc
@@ -21760,16 +21760,17 @@ carjacking/M
 carload/SM
 carmine/SM
 carnage/M
 carnal/Y
 carnality/M
 carnation/IMS
 carnelian/MS
 carney/MS
+carnitas
 carnival/MS
 carnivore/SM
 carnivorous/YP
 carnivorousness/M
 carny/SM
 carob/MS
 carol/ZGMDRS
 caroler/M
--- a/gfx/2d/DrawTargetCG.cpp
+++ b/gfx/2d/DrawTargetCG.cpp
@@ -896,16 +896,24 @@ DrawTargetCG::Init(const IntSize &aSize,
                                bitinfo);
 
 
   assert(mCg);
   // CGContext's default to have the origin at the bottom left
   // so flip it to the top left
   CGContextTranslateCTM(mCg, 0, mSize.height);
   CGContextScaleCTM(mCg, 1, -1);
+  // See Bug 722164 for performance details
+  // Medium or higher quality lead to expensive interpolation
+  // for canvas we want to use low quality interpolation
+  // to have competitive performance with other canvas
+  // implementation.
+  // XXX: Create input parameter to control interpolation and
+  //      use the default for content.
+  CGContextSetInterpolationQuality(mCg, kCGInterpolationLow);
 
   //XXX: set correct format
   mFormat = FORMAT_B8G8R8A8;
 
   return true;
 }
 
 TemporaryRef<PathBuilder>
--- a/gfx/2d/DrawTargetD2D.cpp
+++ b/gfx/2d/DrawTargetD2D.cpp
@@ -1980,16 +1980,22 @@ DrawTargetD2D::CreatePartialBitmapForSur
   rect.RoundOut();
 
   Rect uploadRect(0, 0, aSurface->mSize.width, aSurface->mSize.height);
 
   // Calculate the rectangle on the source bitmap that touches our
   // surface.
   uploadRect = uploadRect.Intersect(rect);
 
+  if (uploadRect.IsEmpty()) {
+    // This bitmap does not cover anything on the screen. XXX -
+    // we need to deal with EXTEND modes here!
+    return NULL;
+  }
+
   if (uploadRect.width <= mRT->GetMaximumBitmapSize() &&
       uploadRect.height <= mRT->GetMaximumBitmapSize()) {
             
     int Bpp = BytesPerPixel(aSurface->mFormat);
     int stride = Bpp * aSurface->mSize.width;
 
     // A partial upload will suffice.
     mRT->CreateBitmap(D2D1::SizeU(uint32_t(uploadRect.width), uint32_t(uploadRect.height)),
--- a/gfx/2d/Factory.cpp
+++ b/gfx/2d/Factory.cpp
@@ -92,17 +92,17 @@ Factory::CreateDrawTarget(BackendType aB
     {
       RefPtr<DrawTargetD2D> newTarget;
       newTarget = new DrawTargetD2D();
       if (newTarget->Init(aSize, aFormat)) {
         return newTarget;
       }
       break;
     }
-#elif defined XP_MACOSX || defined ANDROID
+#elif defined XP_MACOSX || defined ANDROID || defined LINUX
 #ifdef USE_SKIA
   case BACKEND_SKIA:
     {
       RefPtr<DrawTargetSkia> newTarget;
       newTarget = new DrawTargetSkia();
       if (newTarget->Init(aSize, aFormat)) {
         return newTarget;
       }
--- a/gfx/2d/SourceSurfaceD2DTarget.cpp
+++ b/gfx/2d/SourceSurfaceD2DTarget.cpp
@@ -161,22 +161,47 @@ SourceSurfaceD2DTarget::GetBitmap(ID2D1R
 
   if (FAILED(hr)) {
     // This seems to happen for FORMAT_A8 sometimes...
     aRT->CreateBitmap(D2D1::SizeU(desc.Width, desc.Height),
                       D2D1::BitmapProperties(D2D1::PixelFormat(DXGIFormat(mFormat),
                                              AlphaMode(mFormat))),
                       byRef(mBitmap));
 
+    RefPtr<ID2D1RenderTarget> rt;
+
     if (mDrawTarget) {
-      mBitmap->CopyFromRenderTarget(NULL, mDrawTarget->mRT, NULL);
-      return mBitmap;
+      rt = mDrawTarget->mRT;
     }
-    gfxWarning() << "Failed to create shared bitmap for DrawTarget snapshot. Code: " << hr;
-    return NULL;
+
+    if (!rt) {
+      // Okay, we already separated from our drawtarget. And we're an A8
+      // surface the only way we can get to a bitmap is by creating a
+      // a rendertarget and from there copying to a bitmap! Terrible!
+      RefPtr<IDXGISurface> surface;
+
+      hr = mTexture->QueryInterface((IDXGISurface**)byRef(surface));
+
+      if (FAILED(hr)) {
+        gfxWarning() << "Failed to QI texture to surface.";
+        return NULL;
+      }
+
+      D2D1_RENDER_TARGET_PROPERTIES props =
+        D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT, D2D1::PixelFormat(DXGIFormat(mFormat), AlphaMode(mFormat)));
+      hr = DrawTargetD2D::factory()->CreateDxgiSurfaceRenderTarget(surface, props, byRef(rt));
+
+      if (FAILED(hr)) {
+        gfxWarning() << "Failed to create D2D render target for texture.";
+        return NULL;
+      }
+    }
+
+    mBitmap->CopyFromRenderTarget(NULL, rt, NULL);
+    return mBitmap;
   }
 
   return mBitmap;
 }
 
 void
 SourceSurfaceD2DTarget::MarkIndependent()
 {
--- a/gfx/cairo/README
+++ b/gfx/cairo/README
@@ -173,16 +173,18 @@ fixup-unbounded.patch: Hack to work arou
 quartz-get-image-performance: Make cairo_quartz_get_image faster in the failure case by not flushing unless we are going to succeed.
 
 lround-c99-only.patch: Only use lround in C99 programs.
 
 unicode-printing.patch: Print as unicode (bug 454532)
 
 quartz-mark-dirty.patch: Add a quartz implementation of mark_dirty_rectangle (bug 715704)
 
+expose-snapshot.patch: Make functions to add snapshots public, as well as allow creating null surfaces publically. (bug 715658)
+
 ==== pixman patches ====
 
 pixman-android-cpu-detect.patch: Add CPU detection support for Android, where we can't reliably access /proc/self/auxv.
 
 pixman-rename-and-endian.patch: include cairo-platform.h for renaming of external symbols and endian macros
 
 NOTE: we previously supported ARM assembler on MSVC, this has been removed because of the maintenance burden
 
--- a/gfx/cairo/cairo/src/cairo-analysis-surface-private.h
+++ b/gfx/cairo/cairo/src/cairo-analysis-surface-private.h
@@ -65,14 +65,11 @@ cairo_private cairo_bool_t
 cairo_private void
 _cairo_analysis_surface_get_bounding_box (cairo_surface_t *surface,
 					  cairo_box_t     *bbox);
 
 cairo_private cairo_int_status_t
 _cairo_analysis_surface_merge_status (cairo_int_status_t status_a,
 				      cairo_int_status_t status_b);
 
-cairo_private cairo_surface_t *
-_cairo_null_surface_create (cairo_content_t content);
-
 CAIRO_END_DECLS
 
 #endif /* CAIRO_ANALYSIS_SURFACE_H */
--- a/gfx/cairo/cairo/src/cairo-analysis-surface.c
+++ b/gfx/cairo/cairo/src/cairo-analysis-surface.c
@@ -902,17 +902,17 @@ static const cairo_surface_backend_t cai
     NULL, /* fill_stroke */
     NULL, /* create_solid_pattern_surface */
     NULL, /* can_repaint_solid_pattern_surface */
     NULL, /* has_show_text_glyphs */
     NULL  /* show_text_glyphs */
 };
 
 cairo_surface_t *
-_cairo_null_surface_create (cairo_content_t content)
+cairo_null_surface_create (cairo_content_t content)
 {
     cairo_surface_t *surface;
 
     surface = malloc (sizeof (cairo_surface_t));
     if (unlikely (surface == NULL)) {
 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
     }
 
--- a/gfx/cairo/cairo/src/cairo-d2d-surface.cpp
+++ b/gfx/cairo/cairo/src/cairo-d2d-surface.cpp
@@ -1951,24 +1951,24 @@ static RefPtr<ID2D1Brush>
 			rect = D2D1::RectU(1, 1, srcSurf->width + 1, srcSurf->height + 1);
 		    } else {
 			rect = D2D1::RectU(0, 0, srcSurf->width, srcSurf->height);
 		    }
 		    sourceBitmap->CopyFromMemory(&rect,
 						 srcSurf->data,
 						 srcSurf->stride);
 		    cairo_surface_t *nullSurf =
-			_cairo_null_surface_create(CAIRO_CONTENT_COLOR_ALPHA);
+			cairo_null_surface_create(CAIRO_CONTENT_COLOR_ALPHA);
 		    cachebitmap->refs++;
 		    cachebitmap->dirty = false;
 		    cairo_surface_set_user_data(nullSurf,
 						&bitmap_key_snapshot,
 						cachebitmap,
 						NULL);
-		    _cairo_surface_attach_snapshot(surfacePattern->surface,
+		    cairo_surface_attach_snapshot(surfacePattern->surface,
 						   nullSurf,
 						   _d2d_snapshot_detached);
 		}
 	    } else {
 		if (pattern->extend != CAIRO_EXTEND_NONE) {
 		    d2dsurf->rt->CreateBitmap(D2D1::SizeU(width, height),
 							  data + yoffset * stride + xoffset * Bpp,
 							  stride,
@@ -2015,22 +2015,22 @@ static RefPtr<ID2D1Brush>
 		     * and one more in the user data structure.
 		     */
 		    cachebitmap->refs = 2;
 		    cairo_surface_set_user_data(surfacePattern->surface,
 						key,
 						cachebitmap,
 						_d2d_release_bitmap);
 		    cairo_surface_t *nullSurf =
-			_cairo_null_surface_create(CAIRO_CONTENT_COLOR_ALPHA);
+			cairo_null_surface_create(CAIRO_CONTENT_COLOR_ALPHA);
 		    cairo_surface_set_user_data(nullSurf,
 						&bitmap_key_snapshot,
 						cachebitmap,
 						NULL);
-		    _cairo_surface_attach_snapshot(surfacePattern->surface,
+		    cairo_surface_attach_snapshot(surfacePattern->surface,
 						   nullSurf,
 						   _d2d_snapshot_detached);
 		    cache_usage += _d2d_compute_bitmap_mem_size(sourceBitmap);
 		}
 		if (pix_image) {
 		    pixman_image_unref(pix_image);
   		}
 	    }
--- a/gfx/cairo/cairo/src/cairo-recording-surface.c
+++ b/gfx/cairo/cairo/src/cairo-recording-surface.c
@@ -276,17 +276,17 @@ static cairo_status_t
 				     -surface->extents.y);
 
     status = _cairo_recording_surface_replay (&surface->base, image);
     if (unlikely (status)) {
 	cairo_surface_destroy (image);
 	return status;
     }
 
-    _cairo_surface_attach_snapshot (&surface->base, image, NULL);
+    cairo_surface_attach_snapshot (&surface->base, image, NULL);
 
     *image_out = (cairo_image_surface_t *) image;
     *image_extra = NULL;
     return CAIRO_STATUS_SUCCESS;
 }
 
 static void
 _cairo_recording_surface_release_source_image (void			*abstract_surface,
@@ -1046,17 +1046,17 @@ static cairo_status_t
 _recording_surface_get_ink_bbox (cairo_recording_surface_t *surface,
 				 cairo_box_t *bbox,
 				 const cairo_matrix_t *transform)
 {
     cairo_surface_t *null_surface;
     cairo_surface_t *analysis_surface;
     cairo_status_t status;
 
-    null_surface = _cairo_null_surface_create (surface->content);
+    null_surface = cairo_null_surface_create (surface->content);
     analysis_surface = _cairo_analysis_surface_create (null_surface);
     cairo_surface_destroy (null_surface);
 
     status = analysis_surface->status;
     if (unlikely (status))
 	return status;
 
     if (transform != NULL)
--- a/gfx/cairo/cairo/src/cairo-surface-private.h
+++ b/gfx/cairo/cairo/src/cairo-surface-private.h
@@ -40,18 +40,16 @@
 
 #include "cairo.h"
 
 #include "cairo-types-private.h"
 #include "cairo-list-private.h"
 #include "cairo-reference-count-private.h"
 #include "cairo-clip-private.h"
 
-typedef void (*cairo_surface_func_t) (cairo_surface_t *);
-
 struct _cairo_surface {
     const cairo_surface_backend_t *backend;
     cairo_device_t *device;
 
     /* We allow surfaces to override the backend->type by shoving something
      * else into surface->type. This is for "wrapper" surfaces that want to
      * hide their internal type from the user-level API. */
     cairo_surface_type_t type;
--- a/gfx/cairo/cairo/src/cairo-surface-snapshot.c
+++ b/gfx/cairo/cairo/src/cairo-surface-snapshot.c
@@ -209,17 +209,17 @@ cairo_surface_t *
 	    if (unlikely (status)) {
 		cairo_surface_destroy (snap);
 		return _cairo_surface_create_in_error (status);
 	    }
 
 	    snap->device_transform = surface->device_transform;
 	    snap->device_transform_inverse = surface->device_transform_inverse;
 
-	    _cairo_surface_attach_snapshot (surface, snap, NULL);
+	    cairo_surface_attach_snapshot (surface, snap, NULL);
 
 	    return snap;
 	}
     }
 
     snapshot = (cairo_surface_snapshot_t *)
 	_cairo_surface_has_snapshot (surface, &_cairo_surface_snapshot_backend);
     if (snapshot != NULL)
@@ -242,14 +242,14 @@ cairo_surface_t *
     if (unlikely (status)) {
 	cairo_surface_destroy (&snapshot->base);
 	return _cairo_surface_create_in_error (status);
     }
 
     snapshot->base.device_transform = surface->device_transform;
     snapshot->base.device_transform_inverse = surface->device_transform_inverse;
 
-    _cairo_surface_attach_snapshot (surface,
+    cairo_surface_attach_snapshot (surface,
 				    &snapshot->base,
 				    _cairo_surface_snapshot_copy_on_write);
 
     return &snapshot->base;
 }
--- a/gfx/cairo/cairo/src/cairo-surface-subsurface.c
+++ b/gfx/cairo/cairo/src/cairo-surface-subsurface.c
@@ -326,17 +326,17 @@ static cairo_status_t
 		_cairo_image_surface_create_with_content (meta->content,
 							  surface->extents.width,
 							  surface->extents.height);
 	    if (unlikely (image->base.status))
 		return image->base.status;
 
             cairo_surface_paint_to_target (&image->base, surface);
 
-	    _cairo_surface_attach_snapshot (&surface->base, &image->base, NULL);
+	    cairo_surface_attach_snapshot (&surface->base, &image->base, NULL);
 
 	    *image_out = image;
 	    *extra_out = NULL;
 	    return CAIRO_STATUS_SUCCESS;
 	}
     }
 
     extra = malloc (sizeof (struct extra));
--- a/gfx/cairo/cairo/src/cairo-surface.c
+++ b/gfx/cairo/cairo/src/cairo-surface.c
@@ -305,51 +305,51 @@ static void
     if (! _cairo_surface_has_mime_data (surface))
 	return;
 
     _cairo_user_data_array_fini (&surface->mime_data);
     _cairo_user_data_array_init (&surface->mime_data);
 }
 
 static void
-_cairo_surface_detach_snapshots (cairo_surface_t *surface)
+cairo_surface_detach_snapshots (cairo_surface_t *surface)
 {
     while (_cairo_surface_has_snapshots (surface)) {
-	_cairo_surface_detach_snapshot (cairo_list_first_entry (&surface->snapshots,
+	cairo_surface_detach_snapshot (cairo_list_first_entry (&surface->snapshots,
 								cairo_surface_t,
 								snapshot));
     }
 }
 
 void
-_cairo_surface_detach_snapshot (cairo_surface_t *snapshot)
+cairo_surface_detach_snapshot (cairo_surface_t *snapshot)
 {
     assert (snapshot->snapshot_of != NULL);
 
     snapshot->snapshot_of = NULL;
     cairo_list_del (&snapshot->snapshot);
 
     if (snapshot->snapshot_detach != NULL)
 	snapshot->snapshot_detach (snapshot);
 
     cairo_surface_destroy (snapshot);
 }
 
 void
-_cairo_surface_attach_snapshot (cairo_surface_t *surface,
+cairo_surface_attach_snapshot (cairo_surface_t *surface,
 				 cairo_surface_t *snapshot,
 				 cairo_surface_func_t detach_func)
 {
     assert (surface != snapshot);
     assert (snapshot->snapshot_of != surface);
 
     cairo_surface_reference (snapshot);
 
     if (snapshot->snapshot_of != NULL)
-	_cairo_surface_detach_snapshot (snapshot);
+	cairo_surface_detach_snapshot (snapshot);
 
     snapshot->snapshot_of = surface;
     snapshot->snapshot_detach = detach_func;
 
     cairo_list_add (&snapshot->snapshot, &surface->snapshots);
 
     assert (_cairo_surface_has_snapshot (surface, snapshot->backend) == snapshot);
 }
@@ -382,17 +382,17 @@ static cairo_bool_t
 
 static void
 _cairo_surface_begin_modification (cairo_surface_t *surface)
 {
     assert (surface->status == CAIRO_STATUS_SUCCESS);
     assert (! surface->finished);
     assert (surface->snapshot_of == NULL);
 
-    _cairo_surface_detach_snapshots (surface);
+    cairo_surface_detach_snapshots (surface);
     _cairo_surface_detach_mime_data (surface);
 }
 
 void
 _cairo_surface_init (cairo_surface_t			*surface,
 		     const cairo_surface_backend_t	*backend,
 		     cairo_device_t			*device,
 		     cairo_content_t			 content)
@@ -711,19 +711,19 @@ cairo_surface_finish (cairo_surface_t *s
 
     if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
 	return;
 
     if (surface->finished)
 	return;
 
     /* update the snapshots *before* we declare the surface as finished */
-    _cairo_surface_detach_snapshots (surface);
+    cairo_surface_detach_snapshots (surface);
     if (surface->snapshot_of != NULL)
-	_cairo_surface_detach_snapshot (surface);
+	cairo_surface_detach_snapshot (surface);
 
     cairo_surface_flush (surface);
     surface->finished = TRUE;
 
     /* call finish even if in error mode */
     if (surface->backend->finish) {
 	status = surface->backend->finish (surface);
 	if (unlikely (status))
@@ -1106,17 +1106,17 @@ cairo_surface_flush (cairo_surface_t *su
 
     if (surface->status)
 	return;
 
     if (surface->finished)
 	return;
 
     /* update the current snapshots *before* the user updates the surface */
-    _cairo_surface_detach_snapshots (surface);
+    cairo_surface_detach_snapshots (surface);
 
     if (surface->backend->flush) {
 	status = surface->backend->flush (surface);
 	if (unlikely (status))
 	    status = _cairo_surface_set_error (surface, status);
     }
 }
 slim_hidden_def (cairo_surface_flush);
@@ -1628,17 +1628,17 @@ static cairo_status_t
 	    return similar->status;
 
 	status = _cairo_recording_surface_replay (src, similar);
 	if (unlikely (status)) {
 	    cairo_surface_destroy (similar);
 	    return status;
 	}
 
-	_cairo_surface_attach_snapshot (src, similar, NULL);
+	cairo_surface_attach_snapshot (src, similar, NULL);
 
 	src_x = src_y = 0;
     }
 
     *clone_out = similar;
     *clone_offset_x = src_x;
     *clone_offset_y = src_y;
     return CAIRO_STATUS_SUCCESS;
--- a/gfx/cairo/cairo/src/cairo-vg-surface.c
+++ b/gfx/cairo/cairo/src/cairo-vg-surface.c
@@ -977,17 +977,17 @@ static cairo_status_t
     status = _cairo_cache_insert (&context->snapshot_cache,
 				  &clone->snapshot_cache_entry);
     if (unlikely (status)) {
 	clone->snapshot_cache_entry.hash = 0;
 	cairo_surface_destroy (&clone->base);
 	return status;
     }
 
-    _cairo_surface_attach_snapshot (spat->surface, &clone->base,
+    cairo_surface_attach_snapshot (spat->surface, &clone->base,
 				    _vg_surface_remove_from_cache);
 
 DONE:
     cairo_surface_destroy (&context->source->base);
     context->source = clone;
 
     vgSetParameteri (context->paint, VG_PAINT_TYPE, VG_PAINT_TYPE_PATTERN);
 
--- a/gfx/cairo/cairo/src/cairo-xcb-surface.c
+++ b/gfx/cairo/cairo/src/cairo-xcb-surface.c
@@ -560,17 +560,17 @@ static cairo_status_t
 	image = (cairo_image_surface_t *) cairo_surface_reference (&image->base);
 	goto DONE;
     }
 
     status = _get_image (surface, FALSE, &image);
     if (unlikely (status))
 	return status;
 
-    _cairo_surface_attach_snapshot (&surface->base, &image->base, NULL);
+    cairo_surface_attach_snapshot (&surface->base, &image->base, NULL);
 
 DONE:
     *image_out = image;
     *image_extra = NULL;
     return CAIRO_STATUS_SUCCESS;
 }
 
 static void
@@ -713,17 +713,17 @@ static cairo_status_t
 	status = cairo_surface_status (surface->fallback);
 
 	if (status == CAIRO_STATUS_SUCCESS) {
 	    status = _put_image (surface,
 				 (cairo_image_surface_t *) surface->fallback);
 	}
 
 	if (status == CAIRO_STATUS_SUCCESS) {
-	    _cairo_surface_attach_snapshot (&surface->base,
+	    cairo_surface_attach_snapshot (&surface->base,
 					    surface->fallback,
 					    cairo_surface_finish);
 	}
     }
 
     cairo_surface_destroy (surface->fallback);
     surface->fallback = NULL;
 
--- a/gfx/cairo/cairo/src/cairo.h
+++ b/gfx/cairo/cairo/src/cairo.h
@@ -214,16 +214,25 @@ typedef struct _cairo_pattern cairo_patt
  *
  * #cairo_destroy_func_t the type of function which is called when a
  * data element is destroyed. It is passed the pointer to the data
  * element and should free any memory and resources allocated for it.
  **/
 typedef void (*cairo_destroy_func_t) (void *data);
 
 /**
+ * cairo_surface_func_t:
+ * @surface: The surface being referred to.
+ *
+ * #cairo_surface_func_t the type of function which is used for callback
+ * when a surface needs to be apssed as a parameter.
+ */
+typedef void (*cairo_surface_func_t) (cairo_surface_t *surface);
+
+/**
  * cairo_user_data_key_t:
  * @unused: not used; ignore.
  *
  * #cairo_user_data_key_t is used for attaching user data to cairo
  * data structures.  The actual contents of the struct is never used,
  * and there is no need to initialize the object; only the unique
  * address of a #cairo_data_key_t object is used.  Typically, you
  * would just use the address of a static #cairo_data_key_t object.
@@ -2150,16 +2159,24 @@ cairo_surface_get_user_data (cairo_surfa
 			     const cairo_user_data_key_t *key);
 
 cairo_public cairo_status_t
 cairo_surface_set_user_data (cairo_surface_t		 *surface,
 			     const cairo_user_data_key_t *key,
 			     void			 *user_data,
 			     cairo_destroy_func_t	 destroy);
 
+cairo_public void
+cairo_surface_attach_snapshot (cairo_surface_t *surface,
+				cairo_surface_t *snapshot,
+				cairo_surface_func_t detach_func);
+
+cairo_public void
+cairo_surface_detach_snapshot (cairo_surface_t *snapshot);
+
 #define CAIRO_MIME_TYPE_JPEG "image/jpeg"
 #define CAIRO_MIME_TYPE_PNG "image/png"
 #define CAIRO_MIME_TYPE_JP2 "image/jp2"
 #define CAIRO_MIME_TYPE_URI "text/x-uri"
 
 cairo_public void
 cairo_surface_get_mime_data (cairo_surface_t		*surface,
                              const char			*mime_type,
@@ -2328,16 +2345,21 @@ cairo_recording_surface_create (cairo_co
 
 cairo_public void
 cairo_recording_surface_ink_extents (cairo_surface_t *surface,
                                      double *x0,
                                      double *y0,
                                      double *width,
                                      double *height);
 
+/* Null-surface functions */
+
+cairo_public cairo_surface_t *
+cairo_null_surface_create (cairo_content_t content);
+
 /* Pattern creation functions */
 
 cairo_public cairo_pattern_t *
 cairo_pattern_create_rgb (double red, double green, double blue);
 
 cairo_public cairo_pattern_t *
 cairo_pattern_create_rgba (double red, double green, double blue,
 			   double alpha);
--- a/gfx/cairo/cairo/src/cairoint.h
+++ b/gfx/cairo/cairo/src/cairoint.h
@@ -1770,27 +1770,19 @@ cairo_private cairo_status_t
 			      int               height,
 			      int              *clone_offset_x,
 			      int              *clone_offset_y,
 			      cairo_surface_t **clone_out);
 
 cairo_private cairo_surface_t *
 _cairo_surface_snapshot (cairo_surface_t *surface);
 
-cairo_private void
-_cairo_surface_attach_snapshot (cairo_surface_t *surface,
-				cairo_surface_t *snapshot,
-				cairo_surface_func_t detach_func);
-
 cairo_private cairo_surface_t *
 _cairo_surface_has_snapshot (cairo_surface_t *surface,
-			     const cairo_surface_backend_t *backend);
-
-cairo_private void
-_cairo_surface_detach_snapshot (cairo_surface_t *snapshot);
+		 	     const cairo_surface_backend_t *backend);
 
 cairo_private cairo_bool_t
 _cairo_surface_is_similar (cairo_surface_t *surface_a,
 	                   cairo_surface_t *surface_b);
 
 cairo_private cairo_bool_t
 _cairo_surface_get_extents (cairo_surface_t         *surface,
 			    cairo_rectangle_int_t   *extents);
new file mode 100644
--- /dev/null
+++ b/gfx/cairo/expose-snapshot.patch
@@ -0,0 +1,528 @@
+diff --git a/gfx/cairo/cairo/src/cairo-analysis-surface-private.h b/gfx/cairo/cairo/src/cairo-analysis-surface-private.h
+--- a/gfx/cairo/cairo/src/cairo-analysis-surface-private.h
++++ b/gfx/cairo/cairo/src/cairo-analysis-surface-private.h
+@@ -65,14 +65,11 @@ _cairo_analysis_surface_has_unsupported 
+ cairo_private void
+ _cairo_analysis_surface_get_bounding_box (cairo_surface_t *surface,
+ 					  cairo_box_t     *bbox);
+ 
+ cairo_private cairo_int_status_t
+ _cairo_analysis_surface_merge_status (cairo_int_status_t status_a,
+ 				      cairo_int_status_t status_b);
+ 
+-cairo_private cairo_surface_t *
+-_cairo_null_surface_create (cairo_content_t content);
+-
+ CAIRO_END_DECLS
+ 
+ #endif /* CAIRO_ANALYSIS_SURFACE_H */
+diff --git a/gfx/cairo/cairo/src/cairo-analysis-surface.c b/gfx/cairo/cairo/src/cairo-analysis-surface.c
+--- a/gfx/cairo/cairo/src/cairo-analysis-surface.c
++++ b/gfx/cairo/cairo/src/cairo-analysis-surface.c
+@@ -902,17 +902,17 @@ static const cairo_surface_backend_t cai
+     NULL, /* fill_stroke */
+     NULL, /* create_solid_pattern_surface */
+     NULL, /* can_repaint_solid_pattern_surface */
+     NULL, /* has_show_text_glyphs */
+     NULL  /* show_text_glyphs */
+ };
+ 
+ cairo_surface_t *
+-_cairo_null_surface_create (cairo_content_t content)
++cairo_null_surface_create (cairo_content_t content)
+ {
+     cairo_surface_t *surface;
+ 
+     surface = malloc (sizeof (cairo_surface_t));
+     if (unlikely (surface == NULL)) {
+ 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+     }
+ 
+diff --git a/gfx/cairo/cairo/src/cairo-d2d-surface.cpp b/gfx/cairo/cairo/src/cairo-d2d-surface.cpp
+--- a/gfx/cairo/cairo/src/cairo-d2d-surface.cpp
++++ b/gfx/cairo/cairo/src/cairo-d2d-surface.cpp
+@@ -1951,24 +1951,24 @@ _cairo_d2d_create_brush_for_pattern(cair
+ 			rect = D2D1::RectU(1, 1, srcSurf->width + 1, srcSurf->height + 1);
+ 		    } else {
+ 			rect = D2D1::RectU(0, 0, srcSurf->width, srcSurf->height);
+ 		    }
+ 		    sourceBitmap->CopyFromMemory(&rect,
+ 						 srcSurf->data,
+ 						 srcSurf->stride);
+ 		    cairo_surface_t *nullSurf =
+-			_cairo_null_surface_create(CAIRO_CONTENT_COLOR_ALPHA);
++			cairo_null_surface_create(CAIRO_CONTENT_COLOR_ALPHA);
+ 		    cachebitmap->refs++;
+ 		    cachebitmap->dirty = false;
+ 		    cairo_surface_set_user_data(nullSurf,
+ 						&bitmap_key_snapshot,
+ 						cachebitmap,
+ 						NULL);
+-		    _cairo_surface_attach_snapshot(surfacePattern->surface,
++		    cairo_surface_attach_snapshot(surfacePattern->surface,
+ 						   nullSurf,
+ 						   _d2d_snapshot_detached);
+ 		}
+ 	    } else {
+ 		if (pattern->extend != CAIRO_EXTEND_NONE) {
+ 		    d2dsurf->rt->CreateBitmap(D2D1::SizeU(width, height),
+ 							  data + yoffset * stride + xoffset * Bpp,
+ 							  stride,
+@@ -2015,22 +2015,22 @@ _cairo_d2d_create_brush_for_pattern(cair
+ 		     * and one more in the user data structure.
+ 		     */
+ 		    cachebitmap->refs = 2;
+ 		    cairo_surface_set_user_data(surfacePattern->surface,
+ 						key,
+ 						cachebitmap,
+ 						_d2d_release_bitmap);
+ 		    cairo_surface_t *nullSurf =
+-			_cairo_null_surface_create(CAIRO_CONTENT_COLOR_ALPHA);
++			cairo_null_surface_create(CAIRO_CONTENT_COLOR_ALPHA);
+ 		    cairo_surface_set_user_data(nullSurf,
+ 						&bitmap_key_snapshot,
+ 						cachebitmap,
+ 						NULL);
+-		    _cairo_surface_attach_snapshot(surfacePattern->surface,
++		    cairo_surface_attach_snapshot(surfacePattern->surface,
+ 						   nullSurf,
+ 						   _d2d_snapshot_detached);
+ 		    cache_usage += _d2d_compute_bitmap_mem_size(sourceBitmap);
+ 		}
+ 		if (pix_image) {
+ 		    pixman_image_unref(pix_image);
+   		}
+ 	    }
+diff --git a/gfx/cairo/cairo/src/cairo-recording-surface.c b/gfx/cairo/cairo/src/cairo-recording-surface.c
+--- a/gfx/cairo/cairo/src/cairo-recording-surface.c
++++ b/gfx/cairo/cairo/src/cairo-recording-surface.c
+@@ -276,17 +276,17 @@ _cairo_recording_surface_acquire_source_
+ 				     -surface->extents.y);
+ 
+     status = _cairo_recording_surface_replay (&surface->base, image);
+     if (unlikely (status)) {
+ 	cairo_surface_destroy (image);
+ 	return status;
+     }
+ 
+-    _cairo_surface_attach_snapshot (&surface->base, image, NULL);
++    cairo_surface_attach_snapshot (&surface->base, image, NULL);
+ 
+     *image_out = (cairo_image_surface_t *) image;
+     *image_extra = NULL;
+     return CAIRO_STATUS_SUCCESS;
+ }
+ 
+ static void
+ _cairo_recording_surface_release_source_image (void			*abstract_surface,
+@@ -1046,17 +1046,17 @@ static cairo_status_t
+ _recording_surface_get_ink_bbox (cairo_recording_surface_t *surface,
+ 				 cairo_box_t *bbox,
+ 				 const cairo_matrix_t *transform)
+ {
+     cairo_surface_t *null_surface;
+     cairo_surface_t *analysis_surface;
+     cairo_status_t status;
+ 
+-    null_surface = _cairo_null_surface_create (surface->content);
++    null_surface = cairo_null_surface_create (surface->content);
+     analysis_surface = _cairo_analysis_surface_create (null_surface);
+     cairo_surface_destroy (null_surface);
+ 
+     status = analysis_surface->status;
+     if (unlikely (status))
+ 	return status;
+ 
+     if (transform != NULL)
+diff --git a/gfx/cairo/cairo/src/cairo-surface-private.h b/gfx/cairo/cairo/src/cairo-surface-private.h
+--- a/gfx/cairo/cairo/src/cairo-surface-private.h
++++ b/gfx/cairo/cairo/src/cairo-surface-private.h
+@@ -40,18 +40,16 @@
+ 
+ #include "cairo.h"
+ 
+ #include "cairo-types-private.h"
+ #include "cairo-list-private.h"
+ #include "cairo-reference-count-private.h"
+ #include "cairo-clip-private.h"
+ 
+-typedef void (*cairo_surface_func_t) (cairo_surface_t *);
+-
+ struct _cairo_surface {
+     const cairo_surface_backend_t *backend;
+     cairo_device_t *device;
+ 
+     /* We allow surfaces to override the backend->type by shoving something
+      * else into surface->type. This is for "wrapper" surfaces that want to
+      * hide their internal type from the user-level API. */
+     cairo_surface_type_t type;
+diff --git a/gfx/cairo/cairo/src/cairo-surface-snapshot.c b/gfx/cairo/cairo/src/cairo-surface-snapshot.c
+--- a/gfx/cairo/cairo/src/cairo-surface-snapshot.c
++++ b/gfx/cairo/cairo/src/cairo-surface-snapshot.c
+@@ -209,17 +209,17 @@ _cairo_surface_snapshot (cairo_surface_t
+ 	    if (unlikely (status)) {
+ 		cairo_surface_destroy (snap);
+ 		return _cairo_surface_create_in_error (status);
+ 	    }
+ 
+ 	    snap->device_transform = surface->device_transform;
+ 	    snap->device_transform_inverse = surface->device_transform_inverse;
+ 
+-	    _cairo_surface_attach_snapshot (surface, snap, NULL);
++	    cairo_surface_attach_snapshot (surface, snap, NULL);
+ 
+ 	    return snap;
+ 	}
+     }
+ 
+     snapshot = (cairo_surface_snapshot_t *)
+ 	_cairo_surface_has_snapshot (surface, &_cairo_surface_snapshot_backend);
+     if (snapshot != NULL)
+@@ -242,14 +242,14 @@ _cairo_surface_snapshot (cairo_surface_t
+     if (unlikely (status)) {
+ 	cairo_surface_destroy (&snapshot->base);
+ 	return _cairo_surface_create_in_error (status);
+     }
+ 
+     snapshot->base.device_transform = surface->device_transform;
+     snapshot->base.device_transform_inverse = surface->device_transform_inverse;
+ 
+-    _cairo_surface_attach_snapshot (surface,
++    cairo_surface_attach_snapshot (surface,
+ 				    &snapshot->base,
+ 				    _cairo_surface_snapshot_copy_on_write);
+ 
+     return &snapshot->base;
+ }
+diff --git a/gfx/cairo/cairo/src/cairo-surface-subsurface.c b/gfx/cairo/cairo/src/cairo-surface-subsurface.c
+--- a/gfx/cairo/cairo/src/cairo-surface-subsurface.c
++++ b/gfx/cairo/cairo/src/cairo-surface-subsurface.c
+@@ -326,17 +326,17 @@ _cairo_surface_subsurface_acquire_source
+ 		_cairo_image_surface_create_with_content (meta->content,
+ 							  surface->extents.width,
+ 							  surface->extents.height);
+ 	    if (unlikely (image->base.status))
+ 		return image->base.status;
+ 
+             cairo_surface_paint_to_target (&image->base, surface);
+ 
+-	    _cairo_surface_attach_snapshot (&surface->base, &image->base, NULL);
++	    cairo_surface_attach_snapshot (&surface->base, &image->base, NULL);
+ 
+ 	    *image_out = image;
+ 	    *extra_out = NULL;
+ 	    return CAIRO_STATUS_SUCCESS;
+ 	}
+     }
+ 
+     extra = malloc (sizeof (struct extra));
+diff --git a/gfx/cairo/cairo/src/cairo-surface.c b/gfx/cairo/cairo/src/cairo-surface.c
+--- a/gfx/cairo/cairo/src/cairo-surface.c
++++ b/gfx/cairo/cairo/src/cairo-surface.c
+@@ -305,51 +305,51 @@ _cairo_surface_detach_mime_data (cairo_s
+     if (! _cairo_surface_has_mime_data (surface))
+ 	return;
+ 
+     _cairo_user_data_array_fini (&surface->mime_data);
+     _cairo_user_data_array_init (&surface->mime_data);
+ }
+ 
+ static void
+-_cairo_surface_detach_snapshots (cairo_surface_t *surface)
++cairo_surface_detach_snapshots (cairo_surface_t *surface)
+ {
+     while (_cairo_surface_has_snapshots (surface)) {
+-	_cairo_surface_detach_snapshot (cairo_list_first_entry (&surface->snapshots,
++	cairo_surface_detach_snapshot (cairo_list_first_entry (&surface->snapshots,
+ 								cairo_surface_t,
+ 								snapshot));
+     }
+ }
+ 
+ void
+-_cairo_surface_detach_snapshot (cairo_surface_t *snapshot)
++cairo_surface_detach_snapshot (cairo_surface_t *snapshot)
+ {
+     assert (snapshot->snapshot_of != NULL);
+ 
+     snapshot->snapshot_of = NULL;
+     cairo_list_del (&snapshot->snapshot);
+ 
+     if (snapshot->snapshot_detach != NULL)
+ 	snapshot->snapshot_detach (snapshot);
+ 
+     cairo_surface_destroy (snapshot);
+ }
+ 
+ void
+-_cairo_surface_attach_snapshot (cairo_surface_t *surface,
++cairo_surface_attach_snapshot (cairo_surface_t *surface,
+ 				 cairo_surface_t *snapshot,
+ 				 cairo_surface_func_t detach_func)
+ {
+     assert (surface != snapshot);
+     assert (snapshot->snapshot_of != surface);
+ 
+     cairo_surface_reference (snapshot);
+ 
+     if (snapshot->snapshot_of != NULL)
+-	_cairo_surface_detach_snapshot (snapshot);
++	cairo_surface_detach_snapshot (snapshot);
+ 
+     snapshot->snapshot_of = surface;
+     snapshot->snapshot_detach = detach_func;
+ 
+     cairo_list_add (&snapshot->snapshot, &surface->snapshots);
+ 
+     assert (_cairo_surface_has_snapshot (surface, snapshot->backend) == snapshot);
+ }
+@@ -382,17 +382,17 @@ _cairo_surface_is_writable (cairo_surfac
+ 
+ static void
+ _cairo_surface_begin_modification (cairo_surface_t *surface)
+ {
+     assert (surface->status == CAIRO_STATUS_SUCCESS);
+     assert (! surface->finished);
+     assert (surface->snapshot_of == NULL);
+ 
+-    _cairo_surface_detach_snapshots (surface);
++    cairo_surface_detach_snapshots (surface);
+     _cairo_surface_detach_mime_data (surface);
+ }
+ 
+ void
+ _cairo_surface_init (cairo_surface_t			*surface,
+ 		     const cairo_surface_backend_t	*backend,
+ 		     cairo_device_t			*device,
+ 		     cairo_content_t			 content)
+@@ -711,19 +711,19 @@ cairo_surface_finish (cairo_surface_t *s
+ 
+     if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
+ 	return;
+ 
+     if (surface->finished)
+ 	return;
+ 
+     /* update the snapshots *before* we declare the surface as finished */
+-    _cairo_surface_detach_snapshots (surface);
++    cairo_surface_detach_snapshots (surface);
+     if (surface->snapshot_of != NULL)
+-	_cairo_surface_detach_snapshot (surface);
++	cairo_surface_detach_snapshot (surface);
+ 
+     cairo_surface_flush (surface);
+     surface->finished = TRUE;
+ 
+     /* call finish even if in error mode */
+     if (surface->backend->finish) {
+ 	status = surface->backend->finish (surface);
+ 	if (unlikely (status))
+@@ -1106,17 +1106,17 @@ cairo_surface_flush (cairo_surface_t *su
+ 
+     if (surface->status)
+ 	return;
+ 
+     if (surface->finished)
+ 	return;
+ 
+     /* update the current snapshots *before* the user updates the surface */
+-    _cairo_surface_detach_snapshots (surface);
++    cairo_surface_detach_snapshots (surface);
+ 
+     if (surface->backend->flush) {
+ 	status = surface->backend->flush (surface);
+ 	if (unlikely (status))
+ 	    status = _cairo_surface_set_error (surface, status);
+     }
+ }
+ slim_hidden_def (cairo_surface_flush);
+@@ -1628,17 +1628,17 @@ _cairo_recording_surface_clone_similar (
+ 	    return similar->status;
+ 
+ 	status = _cairo_recording_surface_replay (src, similar);
+ 	if (unlikely (status)) {
+ 	    cairo_surface_destroy (similar);
+ 	    return status;
+ 	}
+ 
+-	_cairo_surface_attach_snapshot (src, similar, NULL);
++	cairo_surface_attach_snapshot (src, similar, NULL);
+ 
+ 	src_x = src_y = 0;
+     }
+ 
+     *clone_out = similar;
+     *clone_offset_x = src_x;
+     *clone_offset_y = src_y;
+     return CAIRO_STATUS_SUCCESS;
+diff --git a/gfx/cairo/cairo/src/cairo-vg-surface.c b/gfx/cairo/cairo/src/cairo-vg-surface.c
+--- a/gfx/cairo/cairo/src/cairo-vg-surface.c
++++ b/gfx/cairo/cairo/src/cairo-vg-surface.c
+@@ -977,17 +977,17 @@ _vg_setup_surface_source (cairo_vg_conte
+     status = _cairo_cache_insert (&context->snapshot_cache,
+ 				  &clone->snapshot_cache_entry);
+     if (unlikely (status)) {
+ 	clone->snapshot_cache_entry.hash = 0;
+ 	cairo_surface_destroy (&clone->base);
+ 	return status;
+     }
+ 
+-    _cairo_surface_attach_snapshot (spat->surface, &clone->base,
++    cairo_surface_attach_snapshot (spat->surface, &clone->base,
+ 				    _vg_surface_remove_from_cache);
+ 
+ DONE:
+     cairo_surface_destroy (&context->source->base);
+     context->source = clone;
+ 
+     vgSetParameteri (context->paint, VG_PAINT_TYPE, VG_PAINT_TYPE_PATTERN);
+ 
+diff --git a/gfx/cairo/cairo/src/cairo-xcb-surface.c b/gfx/cairo/cairo/src/cairo-xcb-surface.c
+--- a/gfx/cairo/cairo/src/cairo-xcb-surface.c
++++ b/gfx/cairo/cairo/src/cairo-xcb-surface.c
+@@ -560,17 +560,17 @@ _cairo_xcb_surface_acquire_source_image 
+ 	image = (cairo_image_surface_t *) cairo_surface_reference (&image->base);
+ 	goto DONE;
+     }
+ 
+     status = _get_image (surface, FALSE, &image);
+     if (unlikely (status))
+ 	return status;
+ 
+-    _cairo_surface_attach_snapshot (&surface->base, &image->base, NULL);
++    cairo_surface_attach_snapshot (&surface->base, &image->base, NULL);
+ 
+ DONE:
+     *image_out = image;
+     *image_extra = NULL;
+     return CAIRO_STATUS_SUCCESS;
+ }
+ 
+ static void
+@@ -713,17 +713,17 @@ _cairo_xcb_surface_flush (void *abstract
+ 	status = cairo_surface_status (surface->fallback);
+ 
+ 	if (status == CAIRO_STATUS_SUCCESS) {
+ 	    status = _put_image (surface,
+ 				 (cairo_image_surface_t *) surface->fallback);
+ 	}
+ 
+ 	if (status == CAIRO_STATUS_SUCCESS) {
+-	    _cairo_surface_attach_snapshot (&surface->base,
++	    cairo_surface_attach_snapshot (&surface->base,
+ 					    surface->fallback,
+ 					    cairo_surface_finish);
+ 	}
+     }
+ 
+     cairo_surface_destroy (surface->fallback);
+     surface->fallback = NULL;
+ 
+diff --git a/gfx/cairo/cairo/src/cairo.h b/gfx/cairo/cairo/src/cairo.h
+--- a/gfx/cairo/cairo/src/cairo.h
++++ b/gfx/cairo/cairo/src/cairo.h
+@@ -214,16 +214,25 @@ typedef struct _cairo_pattern cairo_patt
+  *
+  * #cairo_destroy_func_t the type of function which is called when a
+  * data element is destroyed. It is passed the pointer to the data
+  * element and should free any memory and resources allocated for it.
+  **/
+ typedef void (*cairo_destroy_func_t) (void *data);
+ 
+ /**
++ * cairo_surface_func_t:
++ * @surface: The surface being referred to.
++ *
++ * #cairo_surface_func_t the type of function which is used for callback
++ * when a surface needs to be apssed as a parameter.
++ */
++typedef void (*cairo_surface_func_t) (cairo_surface_t *surface);
++
++/**
+  * cairo_user_data_key_t:
+  * @unused: not used; ignore.
+  *
+  * #cairo_user_data_key_t is used for attaching user data to cairo
+  * data structures.  The actual contents of the struct is never used,
+  * and there is no need to initialize the object; only the unique
+  * address of a #cairo_data_key_t object is used.  Typically, you
+  * would just use the address of a static #cairo_data_key_t object.
+@@ -2150,16 +2159,24 @@ cairo_surface_get_user_data (cairo_surfa
+ 			     const cairo_user_data_key_t *key);
+ 
+ cairo_public cairo_status_t
+ cairo_surface_set_user_data (cairo_surface_t		 *surface,
+ 			     const cairo_user_data_key_t *key,
+ 			     void			 *user_data,
+ 			     cairo_destroy_func_t	 destroy);
+ 
++cairo_public void
++cairo_surface_attach_snapshot (cairo_surface_t *surface,
++				cairo_surface_t *snapshot,
++				cairo_surface_func_t detach_func);
++
++cairo_public void
++cairo_surface_detach_snapshot (cairo_surface_t *snapshot);
++
+ #define CAIRO_MIME_TYPE_JPEG "image/jpeg"
+ #define CAIRO_MIME_TYPE_PNG "image/png"
+ #define CAIRO_MIME_TYPE_JP2 "image/jp2"
+ #define CAIRO_MIME_TYPE_URI "text/x-uri"
+ 
+ cairo_public void
+ cairo_surface_get_mime_data (cairo_surface_t		*surface,
+                              const char			*mime_type,
+@@ -2328,16 +2345,21 @@ cairo_recording_surface_create (cairo_co
+ 
+ cairo_public void
+ cairo_recording_surface_ink_extents (cairo_surface_t *surface,
+                                      double *x0,
+                                      double *y0,
+                                      double *width,
+                                      double *height);
+ 
++/* Null-surface functions */
++
++cairo_public cairo_surface_t *
++cairo_null_surface_create (cairo_content_t content);
++
+ /* Pattern creation functions */
+ 
+ cairo_public cairo_pattern_t *
+ cairo_pattern_create_rgb (double red, double green, double blue);
+ 
+ cairo_public cairo_pattern_t *
+ cairo_pattern_create_rgba (double red, double green, double blue,
+ 			   double alpha);
+diff --git a/gfx/cairo/cairo/src/cairoint.h b/gfx/cairo/cairo/src/cairoint.h
+--- a/gfx/cairo/cairo/src/cairoint.h
++++ b/gfx/cairo/cairo/src/cairoint.h
+@@ -1770,27 +1770,19 @@ _cairo_surface_clone_similar (cairo_surf
+ 			      int               height,
+ 			      int              *clone_offset_x,
+ 			      int              *clone_offset_y,
+ 			      cairo_surface_t **clone_out);
+ 
+ cairo_private cairo_surface_t *
+ _cairo_surface_snapshot (cairo_surface_t *surface);
+ 
+-cairo_private void
+-_cairo_surface_attach_snapshot (cairo_surface_t *surface,
+-				cairo_surface_t *snapshot,
+-				cairo_surface_func_t detach_func);
+-
+ cairo_private cairo_surface_t *
+ _cairo_surface_has_snapshot (cairo_surface_t *surface,
+-			     const cairo_surface_backend_t *backend);
+-
+-cairo_private void
+-_cairo_surface_detach_snapshot (cairo_surface_t *snapshot);
++		 	     const cairo_surface_backend_t *backend);
+ 
+ cairo_private cairo_bool_t
+ _cairo_surface_is_similar (cairo_surface_t *surface_a,
+ 	                   cairo_surface_t *surface_b);
+ 
+ cairo_private cairo_bool_t
+ _cairo_surface_get_extents (cairo_surface_t         *surface,
+ 			    cairo_rectangle_int_t   *extents);
--- a/gfx/skia/Makefile.in
+++ b/gfx/skia/Makefile.in
@@ -304,30 +304,32 @@ EXPORTS_skia += \
 CPPSRCS += \
 	SkFontHost_mac_coretext.cpp \
 	SkTime_Unix.cpp \
 	$(NULL)
 endif
 
 ifeq (android,$(MOZ_WIDGET_TOOLKIT))
 CPPSRCS += \
-	SkFontHost_none.cpp \
+	SkFontHost_FreeType.cpp \
+	SkFontHost_android.cpp \
+	SkFontHost_gamma.cpp \
 	SkMMapStream.cpp \
 	SkTime_Unix.cpp \
 	$(NULL)
 
 DEFINES += -DSK_BUILD_FOR_ANDROID_NDK
 OS_CXXFLAGS += $(CAIRO_FT_CFLAGS)
 endif
 
 ifeq (gtk2,$(MOZ_WIDGET_TOOLKIT))
 CPPSRCS += \
 	SkFontHost_FreeType.cpp \
+	SkFontHost_gamma_none.cpp \
 	SkFontHost_linux.cpp \
-	SkFontHost_gamma.cpp \
 	SkTime_Unix.cpp \
 	SkMMapStream.cpp \
 	SkOSFile.cpp \
 	$(NULL)
 
 OS_CXXFLAGS += $(MOZ_PANGO_CFLAGS)
 endif
 
new file mode 100644
--- /dev/null
+++ b/gfx/skia/old-android-fonthost.patch
@@ -0,0 +1,530 @@
+# HG changeset patch
+# Parent 9ee29e4aace683ddf6cf8ddb2893cd34fcfc772c
+# User James Willcox <jwillcox@mozilla.com>
+diff --git a/gfx/skia/Makefile.in b/gfx/skia/Makefile.in
+--- a/gfx/skia/Makefile.in
++++ b/gfx/skia/Makefile.in
+@@ -305,21 +305,20 @@ CPPSRCS += \
+ 	SkFontHost_mac_coretext.cpp \
+ 	SkTime_Unix.cpp \
+ 	$(NULL)
+ endif
+ 
+ ifeq (android,$(MOZ_WIDGET_TOOLKIT))
+ CPPSRCS += \
+ 	SkFontHost_FreeType.cpp \
+ 	SkFontHost_android.cpp \
+ 	SkFontHost_gamma.cpp \
+-	FontHostConfiguration_android.cpp \
+ 	SkMMapStream.cpp \
+ 	SkTime_Unix.cpp \
+ 	$(NULL)
+ 
+ DEFINES += -DSK_BUILD_FOR_ANDROID_NDK
+ OS_CXXFLAGS += $(CAIRO_FT_CFLAGS)
+ endif
+ 
+ ifeq (gtk2,$(MOZ_WIDGET_TOOLKIT))
+ CPPSRCS += \
+diff --git a/gfx/skia/src/ports/SkFontHost_android.cpp b/gfx/skia/src/ports/SkFontHost_android.cpp
+--- a/gfx/skia/src/ports/SkFontHost_android.cpp
++++ b/gfx/skia/src/ports/SkFontHost_android.cpp
+@@ -1,38 +1,31 @@
++
+ /*
+-**
+-** Copyright 2006, The Android Open Source Project
+-**
+-** Licensed under the Apache License, Version 2.0 (the "License");
+-** you may not use this file except in compliance with the License.
+-** You may obtain a copy of the License at
+-**
+-**     http://www.apache.org/licenses/LICENSE-2.0
+-**
+-** Unless required by applicable law or agreed to in writing, software
+-** 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.
+-*/
++ * Copyright 2006 The Android Open Source Project
++ *
++ * Use of this source code is governed by a BSD-style license that can be
++ * found in the LICENSE file.
++ */
++
+ 
+ #include "SkFontHost.h"
+ #include "SkDescriptor.h"
+ #include "SkMMapStream.h"
+ #include "SkPaint.h"
+ #include "SkString.h"
+ #include "SkStream.h"
+ #include "SkThread.h"
+ #include "SkTSearch.h"
+-#include "FontHostConfiguration_android.h"
+ #include <stdio.h>
+ 
++#define FONT_CACHE_MEMORY_BUDGET    (768 * 1024)
++
+ #ifndef SK_FONT_FILE_PREFIX
+     #define SK_FONT_FILE_PREFIX          "/fonts/"
+ #endif
+ 
+ SkTypeface::Style find_name_and_attributes(SkStream* stream, SkString* name,
+                                            bool* isFixedWidth);
+ 
+ static void GetFullPathForSysFonts(SkString* full, const char name[]) {
+     full->set(getenv("ANDROID_ROOT"));
+     full->append(SK_FONT_FILE_PREFIX);
+@@ -99,21 +92,21 @@ static SkTypeface* find_best_face(const 
+     if (faces[SkTypeface::kNormal] != NULL) {
+         return faces[SkTypeface::kNormal];
+     }
+     // look for anything
+     for (int i = 0; i < 4; i++) {
+         if (faces[i] != NULL) {
+             return faces[i];
+         }
+     }
+     // should never get here, since the faces list should not be empty
+-    SkDEBUGFAIL("faces list is empty");
++    SkASSERT(!"faces list is empty");
+     return NULL;
+ }
+ 
+ static FamilyRec* find_family(const SkTypeface* member) {
+     FamilyRec* curr = gFamilyHead;
+     while (curr != NULL) {
+         for (int i = 0; i < 4; i++) {
+             if (curr->fFaces[i] == member) {
+                 return curr;
+             }
+@@ -138,31 +131,27 @@ static SkTypeface* find_from_uniqueID(ui
+         curr = curr->fNext;
+     }
+     return NULL;
+ }
+ 
+ /*  Remove reference to this face from its family. If the resulting family
+     is empty (has no faces), return that family, otherwise return NULL
+ */
+ static FamilyRec* remove_from_family(const SkTypeface* face) {
+     FamilyRec* family = find_family(face);
+-    if (family) {
+-        SkASSERT(family->fFaces[face->style()] == face);
+-        family->fFaces[face->style()] = NULL;
++    SkASSERT(family->fFaces[face->style()] == face);
++    family->fFaces[face->style()] = NULL;
+ 
+-        for (int i = 0; i < 4; i++) {
+-            if (family->fFaces[i] != NULL) {    // family is non-empty
+-                return NULL;
+-            }
++    for (int i = 0; i < 4; i++) {
++        if (family->fFaces[i] != NULL) {    // family is non-empty
++            return NULL;
+         }
+-    } else {
+-//        SkDebugf("remove_from_family(%p) face not found", face);
+     }
+     return family;  // return the empty family
+ }
+ 
+ // maybe we should make FamilyRec be doubly-linked
+ static void detach_and_delete_family(FamilyRec* family) {
+     FamilyRec* curr = gFamilyHead;
+     FamilyRec* prev = NULL;
+ 
+     while (curr != NULL) {
+@@ -172,21 +161,21 @@ static void detach_and_delete_family(Fam
+                 gFamilyHead = next;
+             } else {
+                 prev->fNext = next;
+             }
+             SkDELETE(family);
+             return;
+         }
+         prev = curr;
+         curr = next;
+     }
+-    SkDEBUGFAIL("Yikes, couldn't find family in our list to remove/delete");
++    SkASSERT(!"Yikes, couldn't find family in our list to remove/delete");
+ }
+ 
+ static SkTypeface* find_typeface(const char name[], SkTypeface::Style style) {
+     NameFamilyPair* list = gNameList.begin();
+     int             count = gNameList.count();
+ 
+     int index = SkStrLCSearch(&list[0].fName, count, name, sizeof(list[0]));
+ 
+     if (index >= 0) {
+         return find_best_face(list[index].fFamily, style);
+@@ -387,111 +376,90 @@ static bool get_name_and_style(const cha
+     }
+     return false;
+ }
+ 
+ // used to record our notion of the pre-existing fonts
+ struct FontInitRec {
+     const char*         fFileName;
+     const char* const*  fNames;     // null-terminated list
+ };
+ 
++static const char* gSansNames[] = {
++    "sans-serif", "arial", "helvetica", "tahoma", "verdana", NULL
++};
++
++static const char* gSerifNames[] = {
++    "serif", "times", "times new roman", "palatino", "georgia", "baskerville",
++    "goudy", "fantasy", "cursive", "ITC Stone Serif", NULL
++};
++
++static const char* gMonoNames[] = {
++    "monospace", "courier", "courier new", "monaco", NULL
++};
++
+ // deliberately empty, but we use the address to identify fallback fonts
+ static const char* gFBNames[] = { NULL };
+ 
++/*  Fonts must be grouped by family, with the first font in a family having the
++    list of names (even if that list is empty), and the following members having
++    null for the list. The names list must be NULL-terminated
++*/
++static const FontInitRec gSystemFonts[] = {
++    { "DroidSans.ttf",              gSansNames  },
++    { "DroidSans-Bold.ttf",         NULL        },
++    { "DroidSerif-Regular.ttf",     gSerifNames },
++    { "DroidSerif-Bold.ttf",        NULL        },
++    { "DroidSerif-Italic.ttf",      NULL        },
++    { "DroidSerif-BoldItalic.ttf",  NULL        },
++    { "DroidSansMono.ttf",          gMonoNames  },
++    /*  These are optional, and can be ignored if not found in the file system.
++        These are appended to gFallbackFonts[] as they are seen, so we list
++        them in the order we want them to be accessed by NextLogicalFont().
++     */
++    { "DroidSansArabic.ttf",        gFBNames    },
++    { "DroidSansHebrew.ttf",        gFBNames    },
++    { "DroidSansThai.ttf",          gFBNames    },
++    { "MTLmr3m.ttf",                gFBNames    }, // Motoya Japanese Font
++    { "MTLc3m.ttf",                 gFBNames    }, // Motoya Japanese Font
++    { "DroidSansJapanese.ttf",      gFBNames    },
++    { "DroidSansFallback.ttf",      gFBNames    }
++};
+ 
+-/*  Fonts are grouped by family, with the first font in a family having the
+-    list of names (even if that list is empty), and the following members having
+-    null for the list. The names list must be NULL-terminated.
+-*/
+-static FontInitRec *gSystemFonts;
+-static size_t gNumSystemFonts = 0;
+-
+-#define SYSTEM_FONTS_FILE "/system/etc/system_fonts.cfg"
++#define DEFAULT_NAMES   gSansNames
+ 
+ // these globals are assigned (once) by load_system_fonts()
+ static FamilyRec* gDefaultFamily;
+ static SkTypeface* gDefaultNormal;
+-static char** gDefaultNames = NULL;
+-static uint32_t *gFallbackFonts;
+ 
+-/*  Load info from a configuration file that populates the system/fallback font structures
+-*/
+-static void load_font_info() {
+-//    load_font_info_xml("/system/etc/system_fonts.xml");
+-    SkTDArray<FontFamily*> fontFamilies;
+-    getFontFamilies(fontFamilies);
+-
+-    SkTDArray<FontInitRec> fontInfo;
+-    bool firstInFamily = false;
+-    for (int i = 0; i < fontFamilies.count(); ++i) {
+-        FontFamily *family = fontFamilies[i];
+-        firstInFamily = true;
+-        for (int j = 0; j < family->fFileNames.count(); ++j) {
+-            FontInitRec fontInfoRecord;
+-            fontInfoRecord.fFileName = family->fFileNames[j];
+-            if (j == 0) {
+-                if (family->fNames.count() == 0) {
+-                    // Fallback font
+-                    fontInfoRecord.fNames = (char **)gFBNames;
+-                } else {
+-                    SkTDArray<const char*> names = family->fNames;
+-                    const char **nameList = (const char**)
+-                            malloc((names.count() + 1) * sizeof(char*));
+-                    if (nameList == NULL) {
+-                        // shouldn't get here
+-                        break;
+-                    }
+-                    if (gDefaultNames == NULL) {
+-                        gDefaultNames = (char**) nameList;
+-                    }
+-                    for (int i = 0; i < names.count(); ++i) {
+-                        nameList[i] = names[i];
+-                    }
+-                    nameList[names.count()] = NULL;
+-                    fontInfoRecord.fNames = nameList;
+-                }
+-            } else {
+-                fontInfoRecord.fNames = NULL;
+-            }
+-            *fontInfo.append() = fontInfoRecord;
+-        }
+-    }
+-    gNumSystemFonts = fontInfo.count();
+-    gSystemFonts = (FontInitRec*) malloc(gNumSystemFonts * sizeof(FontInitRec));
+-    gFallbackFonts = (uint32_t*) malloc((gNumSystemFonts + 1) * sizeof(uint32_t));
+-    if (gSystemFonts == NULL) {
+-        // shouldn't get here
+-        gNumSystemFonts = 0;
+-    }
+-    for (size_t i = 0; i < gNumSystemFonts; ++i) {
+-        gSystemFonts[i].fFileName = fontInfo[i].fFileName;
+-        gSystemFonts[i].fNames = fontInfo[i].fNames;
+-    }
+-    fontFamilies.deleteAll();
+-}
++/*  This is sized conservatively, assuming that it will never be a size issue.
++    It will be initialized in load_system_fonts(), and will be filled with the
++    fontIDs that can be used for fallback consideration, in sorted order (sorted
++    meaning element[0] should be used first, then element[1], etc. When we hit
++    a fontID==0 in the array, the list is done, hence our allocation size is
++    +1 the total number of possible system fonts. Also see NextLogicalFont().
++ */
++static uint32_t gFallbackFonts[SK_ARRAY_COUNT(gSystemFonts)+1];
+ 
+ /*  Called once (ensured by the sentinel check at the beginning of our body).
+     Initializes all the globals, and register the system fonts.
+  */
+ static void load_system_fonts() {
+     // check if we've already be called
+     if (NULL != gDefaultNormal) {
+         return;
+     }
+ 
+-    load_font_info();
+-
+     const FontInitRec* rec = gSystemFonts;
+     SkTypeface* firstInFamily = NULL;
+     int fallbackCount = 0;
+ 
+-    for (size_t i = 0; i < gNumSystemFonts; i++) {
++    for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) {
+         // if we're the first in a new family, clear firstInFamily
+         if (rec[i].fNames != NULL) {
+             firstInFamily = NULL;
+         }
+ 
+         bool isFixedWidth;
+         SkString name;
+         SkTypeface::Style style;
+ 
+         // we expect all the fonts, except the "fallback" fonts
+@@ -515,120 +483,75 @@ static void load_system_fonts() {
+             //    SkDebugf("---- adding %s as fallback[%d] fontID %d\n",
+             //             rec[i].fFileName, fallbackCount, tf->uniqueID());
+                 gFallbackFonts[fallbackCount++] = tf->uniqueID();
+             }
+ 
+             firstInFamily = tf;
+             FamilyRec* family = find_family(tf);
+             const char* const* names = rec[i].fNames;
+ 
+             // record the default family if this is it
+-            if (names == gDefaultNames) {
++            if (names == DEFAULT_NAMES) {
+                 gDefaultFamily = family;
+             }
+             // add the names to map to this family
+             while (*names) {
+                 add_name(*names, family);
+                 names += 1;
+             }
+         }
+     }
+ 
+     // do this after all fonts are loaded. This is our default font, and it
+     // acts as a sentinel so we only execute load_system_fonts() once
+     gDefaultNormal = find_best_face(gDefaultFamily, SkTypeface::kNormal);
+     // now terminate our fallback list with the sentinel value
+     gFallbackFonts[fallbackCount] = 0;
+ }
+ 
+ ///////////////////////////////////////////////////////////////////////////////
+ 
+ void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) {
+-    // lookup and record if the font is custom (i.e. not a system font)
+-    bool isCustomFont = !((FamilyTypeface*)face)->isSysFont();
+-    stream->writeBool(isCustomFont);
++    const char* name = ((FamilyTypeface*)face)->getUniqueString();
+ 
+-    if (isCustomFont) {
+-        SkStream* fontStream = ((FamilyTypeface*)face)->openStream();
++    stream->write8((uint8_t)face->style());
+ 
+-        // store the length of the custom font
+-        uint32_t len = fontStream->getLength();
+-        stream->write32(len);
+-
+-        // store the entire font in the serialized stream
+-        void* fontData = malloc(len);
+-
+-        fontStream->read(fontData, len);
+-        stream->write(fontData, len);
+-
+-        fontStream->unref();
+-        free(fontData);
+-//      SkDebugf("--- fonthost custom serialize %d %d\n", face->style(), len);
+-
++    if (NULL == name || 0 == *name) {
++        stream->writePackedUInt(0);
++//        SkDebugf("--- fonthost serialize null\n");
+     } else {
+-        const char* name = ((FamilyTypeface*)face)->getUniqueString();
+-
+-        stream->write8((uint8_t)face->style());
+-
+-        if (NULL == name || 0 == *name) {
+-            stream->writePackedUInt(0);
+-//          SkDebugf("--- fonthost serialize null\n");
+-        } else {
+-            uint32_t len = strlen(name);
+-            stream->writePackedUInt(len);
+-            stream->write(name, len);
+-//          SkDebugf("--- fonthost serialize <%s> %d\n", name, face->style());
+-        }
++        uint32_t len = strlen(name);
++        stream->writePackedUInt(len);
++        stream->write(name, len);
++//      SkDebugf("--- fonthost serialize <%s> %d\n", name, face->style());
+     }
+ }
+ 
+ SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
+     load_system_fonts();
+ 
+-    // check if the font is a custom or system font
+-    bool isCustomFont = stream->readBool();
++    int style = stream->readU8();
+ 
+-    if (isCustomFont) {
++    int len = stream->readPackedUInt();
++    if (len > 0) {
++        SkString str;
++        str.resize(len);
++        stream->read(str.writable_str(), len);
+ 
+-        // read the length of the custom font from the stream
+-        uint32_t len = stream->readU32();
+-
+-        // generate a new stream to store the custom typeface
+-        SkMemoryStream* fontStream = new SkMemoryStream(len);
+-        stream->read((void*)fontStream->getMemoryBase(), len);
+-
+-        SkTypeface* face = CreateTypefaceFromStream(fontStream);
+-
+-        fontStream->unref();
+-
+-//      SkDebugf("--- fonthost custom deserialize %d %d\n", face->style(), len);
+-        return face;
+-
+-    } else {
+-        int style = stream->readU8();
+-
+-        int len = stream->readPackedUInt();
+-        if (len > 0) {
+-            SkString str;
+-            str.resize(len);
+-            stream->read(str.writable_str(), len);
+-
+-            const FontInitRec* rec = gSystemFonts;
+-            for (size_t i = 0; i < gNumSystemFonts; i++) {
+-                if (strcmp(rec[i].fFileName, str.c_str()) == 0) {
+-                    // backup until we hit the fNames
+-                    for (int j = i; j >= 0; --j) {
+-                        if (rec[j].fNames != NULL) {
+-                            return SkFontHost::CreateTypeface(NULL,
+-                                        rec[j].fNames[0], NULL, 0,
+-                                        (SkTypeface::Style)style);
+-                        }
++        const FontInitRec* rec = gSystemFonts;
++        for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) {
++            if (strcmp(rec[i].fFileName, str.c_str()) == 0) {
++                // backup until we hit the fNames
++                for (int j = i; j >= 0; --j) {
++                    if (rec[j].fNames != NULL) {
++                        return SkFontHost::CreateTypeface(NULL,
++                                    rec[j].fNames[0], NULL, 0, (SkTypeface::Style)style);
+                     }
+                 }
+             }
+         }
+     }
+     return NULL;
+ }
+ 
+ ///////////////////////////////////////////////////////////////////////////////
+ 
+@@ -697,49 +620,32 @@ size_t SkFontHost::GetFileName(SkFontID 
+         }
+         return size;
+     } else {
+         return 0;
+     }
+ }
+ 
+ SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) {
+     load_system_fonts();
+ 
+-    const SkTypeface* origTypeface = find_from_uniqueID(origFontID);
+-    const SkTypeface* currTypeface = find_from_uniqueID(currFontID);
+-
+-    SkASSERT(origTypeface != 0);
+-    SkASSERT(currTypeface != 0);
+-
+-    // Our fallback list always stores the id of the plain in each fallback
+-    // family, so we transform currFontID to its plain equivalent.
+-    currFontID = find_typeface(currTypeface, SkTypeface::kNormal)->uniqueID();
+-
+     /*  First see if fontID is already one of our fallbacks. If so, return
+         its successor. If fontID is not in our list, then return the first one
+         in our list. Note: list is zero-terminated, and returning zero means
+         we have no more fonts to use for fallbacks.
+      */
+     const uint32_t* list = gFallbackFonts;
+     for (int i = 0; list[i] != 0; i++) {
+         if (list[i] == currFontID) {
+-            if (list[i+1] == 0)
+-                return 0;
+-            const SkTypeface* nextTypeface = find_from_uniqueID(list[i+1]);
+-            return find_typeface(nextTypeface, origTypeface->style())->uniqueID();
++            return list[i+1];
+         }
+     }
+-
+-    // If we get here, currFontID was not a fallback, so we start at the
+-    // beginning of our list.
+-    const SkTypeface* firstTypeface = find_from_uniqueID(list[0]);
+-    return find_typeface(firstTypeface, origTypeface->style())->uniqueID();
++    return list[0];
+ }
+ 
+ ///////////////////////////////////////////////////////////////////////////////
+ 
+ SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) {
+     if (NULL == stream || stream->getLength() <= 0) {
+         return NULL;
+     }
+ 
+     bool isFixedWidth;
+@@ -754,10 +660,11 @@ SkTypeface* SkFontHost::CreateTypefaceFr
+ }
+ 
+ SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
+     SkStream* stream = SkNEW_ARGS(SkMMAPStream, (path));
+     SkTypeface* face = SkFontHost::CreateTypefaceFromStream(stream);
+     // since we created the stream, we let go of our ref() here
+     stream->unref();
+     return face;
+ }
+ 
++///////////////////////////////////////////////////////////////////////////////
--- a/gfx/skia/src/ports/FontHostConfiguration_android.cpp
+++ b/gfx/skia/src/ports/FontHostConfiguration_android.cpp
@@ -11,16 +11,17 @@
 ** Unless required by applicable law or agreed to in writing, software
 ** 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.
 */
 
 #include "FontHostConfiguration_android.h"
+#include <expat_config.h>
 #include <expat.h>
 #include "SkTDArray.h"
 
 #define SYSTEM_FONTS_FILE "/system/etc/system_fonts.xml"
 #define FALLBACK_FONTS_FILE "/system/etc/fallback_fonts.xml"
 #define VENDOR_FONTS_FILE "/vendor/etc/fallback_fonts.xml"
 
 
--- a/gfx/skia/src/ports/SkFontHost_android.cpp
+++ b/gfx/skia/src/ports/SkFontHost_android.cpp
@@ -1,36 +1,29 @@
+
 /*
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** 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.
-*/
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
 
 #include "SkFontHost.h"
 #include "SkDescriptor.h"
 #include "SkMMapStream.h"
 #include "SkPaint.h"
 #include "SkString.h"
 #include "SkStream.h"
 #include "SkThread.h"
 #include "SkTSearch.h"
-#include "FontHostConfiguration_android.h"
 #include <stdio.h>
 
+#define FONT_CACHE_MEMORY_BUDGET    (768 * 1024)
+
 #ifndef SK_FONT_FILE_PREFIX
     #define SK_FONT_FILE_PREFIX          "/fonts/"
 #endif
 
 SkTypeface::Style find_name_and_attributes(SkStream* stream, SkString* name,
                                            bool* isFixedWidth);
 
 static void GetFullPathForSysFonts(SkString* full, const char name[]) {
@@ -101,17 +94,17 @@ static SkTypeface* find_best_face(const 
     }
     // look for anything
     for (int i = 0; i < 4; i++) {
         if (faces[i] != NULL) {
             return faces[i];
         }
     }
     // should never get here, since the faces list should not be empty
-    SkDEBUGFAIL("faces list is empty");
+    SkASSERT(!"faces list is empty");
     return NULL;
 }
 
 static FamilyRec* find_family(const SkTypeface* member) {
     FamilyRec* curr = gFamilyHead;
     while (curr != NULL) {
         for (int i = 0; i < 4; i++) {
             if (curr->fFaces[i] == member) {
@@ -140,27 +133,23 @@ static SkTypeface* find_from_uniqueID(ui
     return NULL;
 }
 
 /*  Remove reference to this face from its family. If the resulting family
     is empty (has no faces), return that family, otherwise return NULL
 */
 static FamilyRec* remove_from_family(const SkTypeface* face) {
     FamilyRec* family = find_family(face);
-    if (family) {
-        SkASSERT(family->fFaces[face->style()] == face);
-        family->fFaces[face->style()] = NULL;
+    SkASSERT(family->fFaces[face->style()] == face);
+    family->fFaces[face->style()] = NULL;
 
-        for (int i = 0; i < 4; i++) {
-            if (family->fFaces[i] != NULL) {    // family is non-empty
-                return NULL;
-            }
+    for (int i = 0; i < 4; i++) {
+        if (family->fFaces[i] != NULL) {    // family is non-empty
+            return NULL;
         }
-    } else {
-//        SkDebugf("remove_from_family(%p) face not found", face);
     }
     return family;  // return the empty family
 }
 
 // maybe we should make FamilyRec be doubly-linked
 static void detach_and_delete_family(FamilyRec* family) {
     FamilyRec* curr = gFamilyHead;
     FamilyRec* prev = NULL;
@@ -174,17 +163,17 @@ static void detach_and_delete_family(Fam
                 prev->fNext = next;
             }
             SkDELETE(family);
             return;
         }
         prev = curr;
         curr = next;
     }
-    SkDEBUGFAIL("Yikes, couldn't find family in our list to remove/delete");
+    SkASSERT(!"Yikes, couldn't find family in our list to remove/delete");
 }
 
 static SkTypeface* find_typeface(const char name[], SkTypeface::Style style) {
     NameFamilyPair* list = gNameList.begin();
     int             count = gNameList.count();
 
     int index = SkStrLCSearch(&list[0].fName, count, name, sizeof(list[0]));
 
@@ -389,107 +378,86 @@ static bool get_name_and_style(const cha
 }
 
 // used to record our notion of the pre-existing fonts
 struct FontInitRec {
     const char*         fFileName;
     const char* const*  fNames;     // null-terminated list
 };
 
+static const char* gSansNames[] = {
+    "sans-serif", "arial", "helvetica", "tahoma", "verdana", NULL
+};
+
+static const char* gSerifNames[] = {
+    "serif", "times", "times new roman", "palatino", "georgia", "baskerville",
+    "goudy", "fantasy", "cursive", "ITC Stone Serif", NULL
+};
+
+static const char* gMonoNames[] = {
+    "monospace", "courier", "courier new", "monaco", NULL
+};
+
 // deliberately empty, but we use the address to identify fallback fonts
 static const char* gFBNames[] = { NULL };
 
-
-/*  Fonts are grouped by family, with the first font in a family having the
+/*  Fonts must be grouped by family, with the first font in a family having the
     list of names (even if that list is empty), and the following members having
-    null for the list. The names list must be NULL-terminated.
+    null for the list. The names list must be NULL-terminated
 */
-static FontInitRec *gSystemFonts;
-static size_t gNumSystemFonts = 0;
+static const FontInitRec gSystemFonts[] = {
+    { "DroidSans.ttf",              gSansNames  },
+    { "DroidSans-Bold.ttf",         NULL        },
+    { "DroidSerif-Regular.ttf",     gSerifNames },
+    { "DroidSerif-Bold.ttf",        NULL        },
+    { "DroidSerif-Italic.ttf",      NULL        },
+    { "DroidSerif-BoldItalic.ttf",  NULL        },
+    { "DroidSansMono.ttf",          gMonoNames  },
+    /*  These are optional, and can be ignored if not found in the file system.
+        These are appended to gFallbackFonts[] as they are seen, so we list
+        them in the order we want them to be accessed by NextLogicalFont().
+     */
+    { "DroidSansArabic.ttf",        gFBNames    },
+    { "DroidSansHebrew.ttf",        gFBNames    },
+    { "DroidSansThai.ttf",          gFBNames    },
+    { "MTLmr3m.ttf",                gFBNames    }, // Motoya Japanese Font
+    { "MTLc3m.ttf",                 gFBNames    }, // Motoya Japanese Font
+    { "DroidSansJapanese.ttf",      gFBNames    },
+    { "DroidSansFallback.ttf",      gFBNames    }
+};
 
-#define SYSTEM_FONTS_FILE "/system/etc/system_fonts.cfg"
+#define DEFAULT_NAMES   gSansNames
 
 // these globals are assigned (once) by load_system_fonts()
 static FamilyRec* gDefaultFamily;
 static SkTypeface* gDefaultNormal;
-static char** gDefaultNames = NULL;
-static uint32_t *gFallbackFonts;
 
-/*  Load info from a configuration file that populates the system/fallback font structures
-*/
-static void load_font_info() {
-//    load_font_info_xml("/system/etc/system_fonts.xml");
-    SkTDArray<FontFamily*> fontFamilies;
-    getFontFamilies(fontFamilies);
-
-    SkTDArray<FontInitRec> fontInfo;
-    bool firstInFamily = false;
-    for (int i = 0; i < fontFamilies.count(); ++i) {
-        FontFamily *family = fontFamilies[i];
-        firstInFamily = true;
-        for (int j = 0; j < family->fFileNames.count(); ++j) {
-            FontInitRec fontInfoRecord;
-            fontInfoRecord.fFileName = family->fFileNames[j];
-            if (j == 0) {
-                if (family->fNames.count() == 0) {
-                    // Fallback font
-                    fontInfoRecord.fNames = (char **)gFBNames;
-                } else {
-                    SkTDArray<const char*> names = family->fNames;
-                    const char **nameList = (const char**)
-                            malloc((names.count() + 1) * sizeof(char*));
-                    if (nameList == NULL) {
-                        // shouldn't get here
-                        break;
-                    }
-                    if (gDefaultNames == NULL) {
-                        gDefaultNames = (char**) nameList;
-                    }
-                    for (int i = 0; i < names.count(); ++i) {
-                        nameList[i] = names[i];
-                    }
-                    nameList[names.count()] = NULL;
-                    fontInfoRecord.fNames = nameList;
-                }
-            } else {
-                fontInfoRecord.fNames = NULL;
-            }
-            *fontInfo.append() = fontInfoRecord;
-        }
-    }
-    gNumSystemFonts = fontInfo.count();
-    gSystemFonts = (FontInitRec*) malloc(gNumSystemFonts * sizeof(FontInitRec));
-    gFallbackFonts = (uint32_t*) malloc((gNumSystemFonts + 1) * sizeof(uint32_t));
-    if (gSystemFonts == NULL) {
-        // shouldn't get here
-        gNumSystemFonts = 0;
-    }
-    for (size_t i = 0; i < gNumSystemFonts; ++i) {
-        gSystemFonts[i].fFileName = fontInfo[i].fFileName;
-        gSystemFonts[i].fNames = fontInfo[i].fNames;
-    }
-    fontFamilies.deleteAll();
-}
+/*  This is sized conservatively, assuming that it will never be a size issue.
+    It will be initialized in load_system_fonts(), and will be filled with the
+    fontIDs that can be used for fallback consideration, in sorted order (sorted
+    meaning element[0] should be used first, then element[1], etc. When we hit
+    a fontID==0 in the array, the list is done, hence our allocation size is
+    +1 the total number of possible system fonts. Also see NextLogicalFont().
+ */
+static uint32_t gFallbackFonts[SK_ARRAY_COUNT(gSystemFonts)+1];
 
 /*  Called once (ensured by the sentinel check at the beginning of our body).
     Initializes all the globals, and register the system fonts.
  */
 static void load_system_fonts() {
     // check if we've already be called
     if (NULL != gDefaultNormal) {
         return;
     }
 
-    load_font_info();
-
     const FontInitRec* rec = gSystemFonts;
     SkTypeface* firstInFamily = NULL;
     int fallbackCount = 0;
 
-    for (size_t i = 0; i < gNumSystemFonts; i++) {
+    for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) {
         // if we're the first in a new family, clear firstInFamily
         if (rec[i].fNames != NULL) {
             firstInFamily = NULL;
         }
 
         bool isFixedWidth;
         SkString name;
         SkTypeface::Style style;
@@ -517,17 +485,17 @@ static void load_system_fonts() {
                 gFallbackFonts[fallbackCount++] = tf->uniqueID();
             }
 
             firstInFamily = tf;
             FamilyRec* family = find_family(tf);
             const char* const* names = rec[i].fNames;
 
             // record the default family if this is it
-            if (names == gDefaultNames) {
+            if (names == DEFAULT_NAMES) {
                 gDefaultFamily = family;
             }
             // add the names to map to this family
             while (*names) {
                 add_name(*names, family);
                 names += 1;
             }
         }
@@ -538,95 +506,50 @@ static void load_system_fonts() {
     gDefaultNormal = find_best_face(gDefaultFamily, SkTypeface::kNormal);
     // now terminate our fallback list with the sentinel value
     gFallbackFonts[fallbackCount] = 0;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 
 void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) {
-    // lookup and record if the font is custom (i.e. not a system font)
-    bool isCustomFont = !((FamilyTypeface*)face)->isSysFont();
-    stream->writeBool(isCustomFont);
-
-    if (isCustomFont) {
-        SkStream* fontStream = ((FamilyTypeface*)face)->openStream();
+    const char* name = ((FamilyTypeface*)face)->getUniqueString();
 
-        // store the length of the custom font
-        uint32_t len = fontStream->getLength();
-        stream->write32(len);
-
-        // store the entire font in the serialized stream
-        void* fontData = malloc(len);
-
-        fontStream->read(fontData, len);
-        stream->write(fontData, len);
+    stream->write8((uint8_t)face->style());
 
-        fontStream->unref();
-        free(fontData);
-//      SkDebugf("--- fonthost custom serialize %d %d\n", face->style(), len);
-
+    if (NULL == name || 0 == *name) {
+        stream->writePackedUInt(0);
+//        SkDebugf("--- fonthost serialize null\n");
     } else {
-        const char* name = ((FamilyTypeface*)face)->getUniqueString();
-
-        stream->write8((uint8_t)face->style());
-
-        if (NULL == name || 0 == *name) {
-            stream->writePackedUInt(0);
-//          SkDebugf("--- fonthost serialize null\n");
-        } else {
-            uint32_t len = strlen(name);
-            stream->writePackedUInt(len);
-            stream->write(name, len);
-//          SkDebugf("--- fonthost serialize <%s> %d\n", name, face->style());
-        }
+        uint32_t len = strlen(name);
+        stream->writePackedUInt(len);
+        stream->write(name, len);
+//      SkDebugf("--- fonthost serialize <%s> %d\n", name, face->style());
     }
 }
 
 SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
     load_system_fonts();
 
-    // check if the font is a custom or system font
-    bool isCustomFont = stream->readBool();
-
-    if (isCustomFont) {
-
-        // read the length of the custom font from the stream
-        uint32_t len = stream->readU32();
+    int style = stream->readU8();
 
-        // generate a new stream to store the custom typeface
-        SkMemoryStream* fontStream = new SkMemoryStream(len);
-        stream->read((void*)fontStream->getMemoryBase(), len);
-
-        SkTypeface* face = CreateTypefaceFromStream(fontStream);
-
-        fontStream->unref();
-
-//      SkDebugf("--- fonthost custom deserialize %d %d\n", face->style(), len);
-        return face;
+    int len = stream->readPackedUInt();
+    if (len > 0) {
+        SkString str;
+        str.resize(len);
+        stream->read(str.writable_str(), len);
 
-    } else {
-        int style = stream->readU8();
-
-        int len = stream->readPackedUInt();
-        if (len > 0) {
-            SkString str;
-            str.resize(len);
-            stream->read(str.writable_str(), len);
-
-            const FontInitRec* rec = gSystemFonts;
-            for (size_t i = 0; i < gNumSystemFonts; i++) {
-                if (strcmp(rec[i].fFileName, str.c_str()) == 0) {
-                    // backup until we hit the fNames
-                    for (int j = i; j >= 0; --j) {
-                        if (rec[j].fNames != NULL) {
-                            return SkFontHost::CreateTypeface(NULL,
-                                        rec[j].fNames[0], NULL, 0,
-                                        (SkTypeface::Style)style);
-                        }
+        const FontInitRec* rec = gSystemFonts;
+        for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) {
+            if (strcmp(rec[i].fFileName, str.c_str()) == 0) {
+                // backup until we hit the fNames
+                for (int j = i; j >= 0; --j) {
+                    if (rec[j].fNames != NULL) {
+                        return SkFontHost::CreateTypeface(NULL,
+                                    rec[j].fNames[0], NULL, 0, (SkTypeface::Style)style);
                     }
                 }
             }
         }
     }
     return NULL;
 }
 
@@ -699,45 +622,28 @@ size_t SkFontHost::GetFileName(SkFontID 
     } else {
         return 0;
     }
 }
 
 SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) {
     load_system_fonts();
 
-    const SkTypeface* origTypeface = find_from_uniqueID(origFontID);
-    const SkTypeface* currTypeface = find_from_uniqueID(currFontID);
-
-    SkASSERT(origTypeface != 0);
-    SkASSERT(currTypeface != 0);
-
-    // Our fallback list always stores the id of the plain in each fallback
-    // family, so we transform currFontID to its plain equivalent.
-    currFontID = find_typeface(currTypeface, SkTypeface::kNormal)->uniqueID();
-
     /*  First see if fontID is already one of our fallbacks. If so, return
         its successor. If fontID is not in our list, then return the first one
         in our list. Note: list is zero-terminated, and returning zero means
         we have no more fonts to use for fallbacks.
      */
     const uint32_t* list = gFallbackFonts;
     for (int i = 0; list[i] != 0; i++) {
         if (list[i] == currFontID) {
-            if (list[i+1] == 0)
-                return 0;
-            const SkTypeface* nextTypeface = find_from_uniqueID(list[i+1]);
-            return find_typeface(nextTypeface, origTypeface->style())->uniqueID();
+            return list[i+1];
         }
     }
-
-    // If we get here, currFontID was not a fallback, so we start at the
-    // beginning of our list.
-    const SkTypeface* firstTypeface = find_from_uniqueID(list[0]);
-    return find_typeface(firstTypeface, origTypeface->style())->uniqueID();
+    return list[0];
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 
 SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) {
     if (NULL == stream || stream->getLength() <= 0) {
         return NULL;
     }
@@ -756,8 +662,9 @@ SkTypeface* SkFontHost::CreateTypefaceFr
 SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
     SkStream* stream = SkNEW_ARGS(SkMMAPStream, (path));
     SkTypeface* face = SkFontHost::CreateTypefaceFromStream(stream);
     // since we created the stream, we let go of our ref() here
     stream->unref();
     return face;
 }
 
+///////////////////////////////////////////////////////////////////////////////
--- a/gfx/skia/src/ports/SkFontHost_none.cpp
+++ b/gfx/skia/src/ports/SkFontHost_none.cpp
@@ -25,18 +25,17 @@ SkTypeface* SkFontHost::CreateTypefaceFr
 SkTypeface* SkFontHost::CreateTypefaceFromFile(char const*) {
     SkDEBUGFAIL("SkFontHost::CreateTypefaceFromFile unimplemented");
     return NULL;
 }
 
 // static
 SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics(
         uint32_t fontID,
-        SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo,
-        const uint32_t*, uint32_t) {
+        SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo) {
     SkDEBUGFAIL("SkFontHost::GetAdvancedTypefaceMetrics unimplemented");
     return NULL;
 }
 
 void SkFontHost::FilterRec(SkScalerContext::Rec* rec) {
 }
 
 ///////////////////////////////////////////////////////////////////////////////
--- a/gfx/skia/update.sh
+++ b/gfx/skia/update.sh
@@ -105,8 +105,10 @@ patch -p3 < radial-gradients.patch
 # Fix restrict keyword problem for VS2005
 patch -p3 < skia_restrict_problem.patch
 # Changes to SkUserConfig.h - no bug
 patch -p3 < user-config.patch
 # Bug 715718 - Unitialized variable 'margin' in compute_bounds : SkDraw.cpp
 patch -p3 < uninitialized-margin.patch
 # Bug 722011 - Fix comma at end of enum list
 patch -p3 < fix-comma-end-enum-list.patch
+# Bug 719872 - Fix crash on Android by reverting to older FontHost impl
+patch -p3 < old-android-fonthost.patch
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -431,16 +431,24 @@ gfxPlatform::CreateDrawTargetForSurface(
 
 cairo_user_data_key_t kSourceSurface;
 
 void SourceBufferDestroy(void *srcBuffer)
 {
   static_cast<SourceSurface*>(srcBuffer)->Release();
 }
 
+void SourceSnapshotDetached(cairo_surface_t *nullSurf)
+{
+  gfxImageSurface* origSurf =
+    static_cast<gfxImageSurface*>(cairo_surface_get_user_data(nullSurf, &kSourceSurface));
+
+  origSurf->SetData(&kSourceSurface, NULL, NULL);
+}
+
 RefPtr<SourceSurface>
 gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget, gfxASurface *aSurface)
 {
   void *userData = aSurface->GetData(&kSourceSurface);
 
   if (userData) {
     return static_cast<SourceSurface*>(userData);
   }
@@ -498,16 +506,25 @@ gfxPlatform::GetSourceSurfaceForSurface(
       default:
         NS_RUNTIMEABORT("Invalid surface format!");
     }
 
     srcBuffer = aTarget->CreateSourceSurfaceFromData(imgSurface->Data(),
                                                      IntSize(imgSurface->GetSize().width, imgSurface->GetSize().height),
                                                      imgSurface->Stride(),
                                                      format);
+
+    cairo_surface_t *nullSurf =
+	cairo_null_surface_create(CAIRO_CONTENT_COLOR_ALPHA);
+    cairo_surface_set_user_data(nullSurf,
+				&kSourceSurface,
+				imgSurface,
+				NULL);
+    cairo_surface_attach_snapshot(imgSurface->CairoSurface(), nullSurf, SourceSnapshotDetached);
+    cairo_surface_destroy(nullSurf);
   }
 
   srcBuffer->AddRef();
   aSurface->SetData(&kSourceSurface, srcBuffer, SourceBufferDestroy);
 
   return srcBuffer;
 }
 
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -337,16 +337,22 @@ gfxWindowsPlatform::VerifyD2DDevice(bool
 
         // Try to use a DXGI 1.1 adapter in order to share resources
         // across processes.
         nsRefPtr<IDXGIAdapter1> adapter1;
         if (createDXGIFactory1) {
             nsRefPtr<IDXGIFactory1> factory1;
             HRESULT hr = createDXGIFactory1(__uuidof(IDXGIFactory1),
                                             getter_AddRefs(factory1));
+
+            if (FAILED(hr) || !factory1) {
+              // This seems to happen with some people running the iZ3D driver.
+              // They won't get acceleration.
+              return;
+            }
     
             nsRefPtr<IDXGIAdapter1> adapter1; 
             hr = factory1->EnumAdapters1(0, getter_AddRefs(adapter1));
 
             if (SUCCEEDED(hr) && adapter1) {
                 hr = adapter1->CheckInterfaceSupport(__uuidof(ID3D10Device1),
                                                      nsnull);
                 if (FAILED(hr)) {
--- a/ipc/glue/SyncChannel.cpp
+++ b/ipc/glue/SyncChannel.cpp
@@ -56,18 +56,18 @@ namespace ipc {
 
 const int32 SyncChannel::kNoTimeout = PR_INT32_MIN;
 
 SyncChannel::SyncChannel(SyncListener* aListener)
   : AsyncChannel(aListener)
   , mPendingReply(0)
   , mProcessingSyncMessage(false)
   , mNextSeqno(0)
+  , mInTimeoutSecondHalf(false)
   , mTimeoutMs(kNoTimeout)
-  , mInTimeoutSecondHalf(false)
 #ifdef OS_WIN
   , mTopFrame(NULL)
 #endif
 {
     MOZ_COUNT_CTOR(SyncChannel);
 #ifdef OS_WIN
     mEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
     NS_ASSERTION(mEvent, "CreateEvent failed! Nothing is going to work!");
--- a/ipc/testshell/XPCShellEnvironment.cpp
+++ b/ipc/testshell/XPCShellEnvironment.cpp
@@ -1056,16 +1056,17 @@ XPCShellEnvironment::~XPCShellEnvironmen
         mCxStack = nsnull;
 
         if (mJSPrincipals) {
             JSPRINCIPALS_DROP(mCx, mJSPrincipals);
         }
 
         JSRuntime* rt = gOldContextCallback ? JS_GetRuntime(mCx) : NULL;
 
+        JS_EndRequest(mCx);
         JS_DestroyContext(mCx);
 
         if (gOldContextCallback) {
             NS_ASSERTION(rt, "Should never be null!");
             JS_SetContextCallback(rt, gOldContextCallback);
             gOldContextCallback = NULL;
         }
     }
--- a/js/public/MemoryMetrics.h
+++ b/js/public/MemoryMetrics.h
@@ -48,22 +48,22 @@
 #include "jspubtd.h"
 
 #include "js/Utility.h"
 #include "js/Vector.h"
 
 namespace JS {
 
 /* Data for tracking analysis/inference memory usage. */
-struct TypeInferenceMemoryStats
+struct TypeInferenceSizes
 {
-    int64_t scripts;
-    int64_t objects;
-    int64_t tables;
-    int64_t temporary;
+    size_t scripts;
+    size_t objects;
+    size_t tables;
+    size_t temporary;
 };
 
 typedef void* (* GetNameCallback)(JSContext *cx, JSCompartment *c);
 typedef void (* DestroyNameCallback)(void *string);
 
 struct CompartmentStats
 {
     CompartmentStats()
@@ -81,50 +81,50 @@ struct CompartmentStats
     {
         destroyNameCb(name);
     }
 
     // Pointer to an nsCString, which we can't use here.
     void *name;
     DestroyNameCallback destroyNameCb;
 
-    int64_t gcHeapArenaHeaders;
-    int64_t gcHeapArenaPadding;
-    int64_t gcHeapArenaUnused;
+    size_t gcHeapArenaHeaders;
+    size_t gcHeapArenaPadding;
+    size_t gcHeapArenaUnused;
 
-    int64_t gcHeapObjectsNonFunction;
-    int64_t gcHeapObjectsFunction;
-    int64_t gcHeapStrings;
-    int64_t gcHeapShapesTree;
-    int64_t gcHeapShapesDict;
-    int64_t gcHeapShapesBase;
-    int64_t gcHeapScripts;
-    int64_t gcHeapTypeObjects;
-    int64_t gcHeapXML;
+    size_t gcHeapObjectsNonFunction;
+    size_t gcHeapObjectsFunction;
+    size_t gcHeapStrings;
+    size_t gcHeapShapesTree;
+    size_t gcHeapShapesDict;
+    size_t gcHeapShapesBase;
+    size_t gcHeapScripts;
+    size_t gcHeapTypeObjects;
+    size_t gcHeapXML;
 
-    int64_t objectSlots;
-    int64_t objectElements;
-    int64_t stringChars;
-    int64_t shapesExtraTreeTables;
-    int64_t shapesExtraDictTables;
-    int64_t shapesExtraTreeShapeKids;
-    int64_t shapesCompartmentTables;
-    int64_t scriptData;
+    size_t objectSlots;
+    size_t objectElements;
+    size_t stringChars;
+    size_t shapesExtraTreeTables;
+    size_t shapesExtraDictTables;
+    size_t shapesExtraTreeShapeKids;
+    size_t shapesCompartmentTables;
+    size_t scriptData;
 
 #ifdef JS_METHODJIT
-    int64_t mjitCode;
-    int64_t mjitData;
+    size_t mjitCode;
+    size_t mjitData;
 #endif
-    TypeInferenceMemoryStats typeInferenceMemory;
+    TypeInferenceSizes typeInferenceSizes;
 };
 
-struct IterateData
+struct RuntimeStats
 {
-    IterateData(JSMallocSizeOfFun mallocSizeOf, GetNameCallback getNameCb,
-                DestroyNameCallback destroyNameCb)
+    RuntimeStats(JSMallocSizeOfFun mallocSizeOf, GetNameCallback getNameCb,
+                 DestroyNameCallback destroyNameCb)
       : runtimeObject(0)
       , runtimeAtomsTable(0)
       , runtimeContexts(0)
       , runtimeNormal(0)
       , runtimeTemporary(0)
       , runtimeRegexpCode(0)
       , runtimeStackCommitted(0)
       , gcHeapChunkTotal(0)
@@ -146,73 +146,60 @@ struct IterateData
       , totalAnalysisTemp(0)
       , compartmentStatsVector()
       , currCompartmentStats(NULL)
       , mallocSizeOf(mallocSizeOf)
       , getNameCb(getNameCb)
       , destroyNameCb(destroyNameCb)
     {}
 
-    int64_t runtimeObject;
-    int64_t runtimeAtomsTable;
-    int64_t runtimeContexts;
-    int64_t runtimeNormal;
-    int64_t runtimeTemporary;
-    int64_t runtimeRegexpCode;
-    int64_t runtimeStackCommitted;
-    int64_t gcHeapChunkTotal;
-    int64_t gcHeapChunkCleanUnused;
-    int64_t gcHeapChunkDirtyUnused;
-    int64_t gcHeapChunkCleanDecommitted;
-    int64_t gcHeapChunkDirtyDecommitted;
-    int64_t gcHeapArenaUnused;
-    int64_t gcHeapChunkAdmin;
-    int64_t gcHeapUnusedPercentage;
-    int64_t totalObjects;
-    int64_t totalShapes;
-    int64_t totalScripts;
-    int64_t totalStrings;
+    size_t runtimeObject;
+    size_t runtimeAtomsTable;
+    size_t runtimeContexts;
+    size_t runtimeNormal;
+    size_t runtimeTemporary;
+    size_t runtimeRegexpCode;
+    size_t runtimeStackCommitted;
+    size_t gcHeapChunkTotal;
+    size_t gcHeapChunkCleanUnused;
+    size_t gcHeapChunkDirtyUnused;
+    size_t gcHeapChunkCleanDecommitted;
+    size_t gcHeapChunkDirtyDecommitted;
+    size_t gcHeapArenaUnused;
+    size_t gcHeapChunkAdmin;
+    size_t gcHeapUnusedPercentage;
+    size_t totalObjects;
+    size_t totalShapes;
+    size_t totalScripts;
+    size_t totalStrings;
 #ifdef JS_METHODJIT
-    int64_t totalMjit;
+    size_t totalMjit;
 #endif
-    int64_t totalTypeInference;
-    int64_t totalAnalysisTemp;
+    size_t totalTypeInference;
+    size_t totalAnalysisTemp;
 
     js::Vector<CompartmentStats, 0, js::SystemAllocPolicy> compartmentStatsVector;
     CompartmentStats *currCompartmentStats;
 
     JSMallocSizeOfFun mallocSizeOf;
     GetNameCallback getNameCb;
     DestroyNameCallback destroyNameCb;
 };
 
 #ifdef JS_THREADSAFE
 
 extern JS_PUBLIC_API(bool)
-CollectCompartmentStatsForRuntime(JSRuntime *rt, IterateData *data);
+CollectRuntimeStats(JSRuntime *rt, RuntimeStats *rtStats);
 
 extern JS_PUBLIC_API(bool)
 GetExplicitNonHeapForRuntime(JSRuntime *rt, int64_t *amount,
                              JSMallocSizeOfFun mallocSizeOf);
 
 #endif /* JS_THREADSAFE */
 
-extern void
-SizeOfCompartmentTypeInferenceData(JSContext *cx, JSCompartment *compartment,
-                                   TypeInferenceMemoryStats *stats,
-                                   JSMallocSizeOfFun mallocSizeOf);
-
-extern void
-SizeOfTypeObjectExcludingThis(/*TypeObject*/ void *object,
-                              TypeInferenceMemoryStats *stats,
-                              JSMallocSizeOfFun mallocSizeOf);
-
-extern size_t
-SizeOfCompartmentShapeTable(JSCompartment *c, JSMallocSizeOfFun mallocSizeOf);
-
 extern JS_PUBLIC_API(size_t)
 SystemCompartmentCount(const JSRuntime *rt);
 
 extern JS_PUBLIC_API(size_t)
 UserCompartmentCount(const JSRuntime *rt);
 
 } // namespace JS
 
--- a/js/src/MemoryMetrics.cpp
+++ b/js/src/MemoryMetrics.cpp
@@ -50,276 +50,262 @@
 
 #ifdef JS_THREADSAFE
 
 namespace JS {
 
 using namespace js;
 
 static void
-CompartmentMemoryCallback(JSContext *cx, void *vdata, JSCompartment *compartment)
+CompartmentStatsCallback(JSContext *cx, void *vdata, JSCompartment *compartment)
 {
     // Append a new CompartmentStats to the vector.
-    IterateData *data = static_cast<IterateData *>(vdata);
+    RuntimeStats *rtStats = static_cast<RuntimeStats *>(vdata);
 
-    // CollectCompartmentStatsForRuntime reserves enough space.
-    MOZ_ALWAYS_TRUE(data->compartmentStatsVector.growBy(1));
-    CompartmentStats &curr = data->compartmentStatsVector.back();
-    curr.init(data->getNameCb(cx, compartment), data->destroyNameCb);
-    data->currCompartmentStats = &curr;
+    // CollectRuntimeStats reserves enough space.
+    MOZ_ALWAYS_TRUE(rtStats->compartmentStatsVector.growBy(1));
+    CompartmentStats &cStats = rtStats->compartmentStatsVector.back();
+    cStats.init(rtStats->getNameCb(cx, compartment), rtStats->destroyNameCb);
+    rtStats->currCompartmentStats = &cStats;
 
     // Get the compartment-level numbers.
 #ifdef JS_METHODJIT
-    curr.mjitCode = compartment->sizeOfMjitCode();
+    cStats.mjitCode = compartment->sizeOfMjitCode();
 #endif
-    SizeOfCompartmentTypeInferenceData(cx, compartment,
-                                       &curr.typeInferenceMemory,
-                                       data->mallocSizeOf);
-    curr.shapesCompartmentTables =
-        SizeOfCompartmentShapeTable(compartment, data->mallocSizeOf);
+    compartment->sizeOfTypeInferenceData(cx, &cStats.typeInferenceSizes, rtStats->mallocSizeOf);
+    cStats.shapesCompartmentTables = compartment->sizeOfShapeTable(rtStats->mallocSizeOf);
 }
 
 static void
 ExplicitNonHeapCompartmentCallback(JSContext *cx, void *data, JSCompartment *compartment)
 {
 #ifdef JS_METHODJIT
     size_t *n = static_cast<size_t *>(data);
     *n += compartment->sizeOfMjitCode();
 #endif
 }
 
 static void
 ChunkCallback(JSContext *cx, void *vdata, gc::Chunk *chunk)
 {
     // Nb: This function is only called for dirty chunks, which is why we
     // increment gcHeapChunkDirtyDecommitted.
-    IterateData *data = static_cast<IterateData *>(vdata);
+    RuntimeStats *rtStats = static_cast<RuntimeStats *>(vdata);
     for (size_t i = 0; i < gc::ArenasPerChunk; i++)
         if (chunk->decommittedArenas.get(i))
-            data->gcHeapChunkDirtyDecommitted += gc::ArenaSize;
+            rtStats->gcHeapChunkDirtyDecommitted += gc::ArenaSize;
 }
 
 static void
 ArenaCallback(JSContext *cx, void *vdata, gc::Arena *arena,
               JSGCTraceKind traceKind, size_t thingSize)
 {
-    IterateData *data = static_cast<IterateData *>(vdata);
+    RuntimeStats *rtStats = static_cast<RuntimeStats *>(vdata);
 
-    data->currCompartmentStats->gcHeapArenaHeaders +=
-        sizeof(gc::ArenaHeader);
+    rtStats->currCompartmentStats->gcHeapArenaHeaders += sizeof(gc::ArenaHeader);
     size_t allocationSpace = arena->thingsSpan(thingSize);
-    data->currCompartmentStats->gcHeapArenaPadding +=
+    rtStats->currCompartmentStats->gcHeapArenaPadding +=
         gc::ArenaSize - allocationSpace - sizeof(gc::ArenaHeader);
     // We don't call the callback on unused things.  So we compute the
     // unused space like this:  arenaUnused = maxArenaUnused - arenaUsed.
     // We do this by setting arenaUnused to maxArenaUnused here, and then
     // subtracting thingSize for every used cell, in CellCallback().
-    data->currCompartmentStats->gcHeapArenaUnused += allocationSpace;
+    rtStats->currCompartmentStats->gcHeapArenaUnused += allocationSpace;
 }
 
 static void
 CellCallback(JSContext *cx, void *vdata, void *thing, JSGCTraceKind traceKind,
              size_t thingSize)
 {
-    IterateData *data = static_cast<IterateData *>(vdata);
-    CompartmentStats *curr = data->currCompartmentStats;
+    RuntimeStats *rtStats = static_cast<RuntimeStats *>(vdata);
+    CompartmentStats *cStats = rtStats->currCompartmentStats;
     switch (traceKind) {
     case JSTRACE_OBJECT:
     {
         JSObject *obj = static_cast<JSObject *>(thing);
         if (obj->isFunction()) {
-            curr->gcHeapObjectsFunction += thingSize;
+            cStats->gcHeapObjectsFunction += thingSize;
         } else {
-            curr->gcHeapObjectsNonFunction += thingSize;
+            cStats->gcHeapObjectsNonFunction += thingSize;
         }
         size_t slotsSize, elementsSize;
-        obj->sizeOfExcludingThis(data->mallocSizeOf, &slotsSize, &elementsSize);
-        curr->objectSlots += slotsSize;
-        curr->objectElements += elementsSize;
+        obj->sizeOfExcludingThis(rtStats->mallocSizeOf, &slotsSize, &elementsSize);
+        cStats->objectSlots += slotsSize;
+        cStats->objectElements += elementsSize;
         break;
     }
     case JSTRACE_STRING:
     {
         JSString *str = static_cast<JSString *>(thing);
-        curr->gcHeapStrings += thingSize;
-        curr->stringChars += str->sizeOfExcludingThis(data->mallocSizeOf);
+        cStats->gcHeapStrings += thingSize;
+        cStats->stringChars += str->sizeOfExcludingThis(rtStats->mallocSizeOf);
         break;
     }
     case JSTRACE_SHAPE:
     {
         Shape *shape = static_cast<Shape*>(thing);
         size_t propTableSize, kidsSize;
-        shape->sizeOfExcludingThis(data->mallocSizeOf, &propTableSize, &kidsSize);
+        shape->sizeOfExcludingThis(rtStats->mallocSizeOf, &propTableSize, &kidsSize);
         if (shape->inDictionary()) {
-            curr->gcHeapShapesDict += thingSize;
-            curr->shapesExtraDictTables += propTableSize;
+            cStats->gcHeapShapesDict += thingSize;
+            cStats->shapesExtraDictTables += propTableSize;
             JS_ASSERT(kidsSize == 0);
         } else {
-            curr->gcHeapShapesTree += thingSize;
-            curr->shapesExtraTreeTables += propTableSize;
-            curr->shapesExtraTreeShapeKids += kidsSize;
+            cStats->gcHeapShapesTree += thingSize;
+            cStats->shapesExtraTreeTables += propTableSize;
+            cStats->shapesExtraTreeShapeKids += kidsSize;
         }
         break;
     }
     case JSTRACE_BASE_SHAPE:
     {
-        curr->gcHeapShapesBase += thingSize;
+        cStats->gcHeapShapesBase += thingSize;
         break;
     }
     case JSTRACE_SCRIPT:
     {
         JSScript *script = static_cast<JSScript *>(thing);
-        curr->gcHeapScripts += thingSize;
-        curr->scriptData += script->sizeOfData(data->mallocSizeOf);
+        cStats->gcHeapScripts += thingSize;
+        cStats->scriptData += script->sizeOfData(rtStats->mallocSizeOf);
 #ifdef JS_METHODJIT
-        curr->mjitData += script->sizeOfJitScripts(data->mallocSizeOf);
+        cStats->mjitData += script->sizeOfJitScripts(rtStats->mallocSizeOf);
 #endif
         break;
     }
     case JSTRACE_TYPE_OBJECT:
     {
         types::TypeObject *obj = static_cast<types::TypeObject *>(thing);
-        curr->gcHeapTypeObjects += thingSize;
-        SizeOfTypeObjectExcludingThis(obj, &curr->typeInferenceMemory,
-                                      data->mallocSizeOf);
+        cStats->gcHeapTypeObjects += thingSize;
+        obj->sizeOfExcludingThis(&cStats->typeInferenceSizes, rtStats->mallocSizeOf);
         break;
     }
     case JSTRACE_XML:
     {
-        curr->gcHeapXML += thingSize;
+        cStats->gcHeapXML += thingSize;
         break;
     }
     }
     // Yes, this is a subtraction:  see ArenaCallback() for details.
-    curr->gcHeapArenaUnused -= thingSize;
+    cStats->gcHeapArenaUnused -= thingSize;
 }
 
 JS_PUBLIC_API(bool)
-CollectCompartmentStatsForRuntime(JSRuntime *rt, IterateData *data)
+CollectRuntimeStats(JSRuntime *rt, RuntimeStats *rtStats)
 {
     JSContext *cx = JS_NewContext(rt, 0);
     if (!cx)
         return false;
 
     {
         JSAutoRequest ar(cx);
 
-        if (!data->compartmentStatsVector.reserve(rt->compartments.length()))
+        if (!rtStats->compartmentStatsVector.reserve(rt->compartments.length()))
             return false;
 
-        data->gcHeapChunkCleanDecommitted =
-            rt->gcChunkPool.countCleanDecommittedArenas(rt) *
-            gc::ArenaSize;
-        data->gcHeapChunkCleanUnused =
-            int64_t(JS_GetGCParameter(rt, JSGC_UNUSED_CHUNKS)) *
-            gc::ChunkSize -
-            data->gcHeapChunkCleanDecommitted;
-        data->gcHeapChunkTotal =
-            int64_t(JS_GetGCParameter(rt, JSGC_TOTAL_CHUNKS)) *
-            gc::ChunkSize;
+        rtStats->gcHeapChunkCleanDecommitted =
+            rt->gcChunkPool.countCleanDecommittedArenas(rt) * gc::ArenaSize;
+        rtStats->gcHeapChunkCleanUnused =
+            size_t(JS_GetGCParameter(rt, JSGC_UNUSED_CHUNKS)) * gc::ChunkSize -
+            rtStats->gcHeapChunkCleanDecommitted;
+        rtStats->gcHeapChunkTotal =
+            size_t(JS_GetGCParameter(rt, JSGC_TOTAL_CHUNKS)) * gc::ChunkSize;
 
-        IterateCompartmentsArenasCells(cx, data, CompartmentMemoryCallback,
+        IterateCompartmentsArenasCells(cx, rtStats, CompartmentStatsCallback,
                                        ArenaCallback, CellCallback);
-        IterateChunks(cx, data, ChunkCallback);
+        IterateChunks(cx, rtStats, ChunkCallback);
 
-        data->runtimeObject = data->mallocSizeOf(rt);
+        rtStats->runtimeObject = rtStats->mallocSizeOf(rt);
 
-        size_t normal, temporary, regexpCode, stackCommitted;
-        rt->sizeOfExcludingThis(data->mallocSizeOf,
-                                &normal,
-                                &temporary,
-                                &regexpCode,
-                                &stackCommitted);
-
-        data->runtimeNormal = normal;
-        data->runtimeTemporary = temporary;
-        data->runtimeRegexpCode = regexpCode;
-        data->runtimeStackCommitted = stackCommitted;
+        rt->sizeOfExcludingThis(rtStats->mallocSizeOf,
+                                &rtStats->runtimeNormal,
+                                &rtStats->runtimeTemporary,
+                                &rtStats->runtimeRegexpCode,
+                                &rtStats->runtimeStackCommitted);
 
         // Nb: we use sizeOfExcludingThis() because atomState.atoms is within
         // JSRuntime, and so counted when JSRuntime is counted.
-        data->runtimeAtomsTable =
-            rt->atomState.atoms.sizeOfExcludingThis(data->mallocSizeOf);
+        rtStats->runtimeAtomsTable =
+            rt->atomState.atoms.sizeOfExcludingThis(rtStats->mallocSizeOf);
 
         JSContext *acx, *iter = NULL;
         while ((acx = JS_ContextIteratorUnlocked(rt, &iter)) != NULL)
-            data->runtimeContexts += acx->sizeOfIncludingThis(data->mallocSizeOf);
+            rtStats->runtimeContexts += acx->sizeOfIncludingThis(rtStats->mallocSizeOf);
     }
 
     JS_DestroyContextNoGC(cx);
 
     // This is initialized to all bytes stored in used chunks, and then we
     // subtract used space from it each time around the loop.
-    data->gcHeapChunkDirtyUnused = data->gcHeapChunkTotal -
-                                   data->gcHeapChunkCleanUnused -
-                                   data->gcHeapChunkCleanDecommitted -
-                                   data->gcHeapChunkDirtyDecommitted;
+    rtStats->gcHeapChunkDirtyUnused = rtStats->gcHeapChunkTotal -
+                                      rtStats->gcHeapChunkCleanUnused -
+                                      rtStats->gcHeapChunkCleanDecommitted -
+                                      rtStats->gcHeapChunkDirtyDecommitted;
 
     for (size_t index = 0;
-         index < data->compartmentStatsVector.length();
+         index < rtStats->compartmentStatsVector.length();
          index++) {
-        CompartmentStats &stats = data->compartmentStatsVector[index];
+        CompartmentStats &cStats = rtStats->compartmentStatsVector[index];
 
-        int64_t used = stats.gcHeapArenaHeaders +
-                       stats.gcHeapArenaPadding +
-                       stats.gcHeapArenaUnused +
-                       stats.gcHeapObjectsNonFunction +
-                       stats.gcHeapObjectsFunction +
-                       stats.gcHeapStrings +
-                       stats.gcHeapShapesTree +
-                       stats.gcHeapShapesDict +
-                       stats.gcHeapShapesBase +
-                       stats.gcHeapScripts +
-                       stats.gcHeapTypeObjects +
-                       stats.gcHeapXML;
+        size_t used = cStats.gcHeapArenaHeaders +
+                      cStats.gcHeapArenaPadding +
+                      cStats.gcHeapArenaUnused +
+                      cStats.gcHeapObjectsNonFunction +
+                      cStats.gcHeapObjectsFunction +
+                      cStats.gcHeapStrings +
+                      cStats.gcHeapShapesTree +
+                      cStats.gcHeapShapesDict +
+                      cStats.gcHeapShapesBase +
+                      cStats.gcHeapScripts +
+                      cStats.gcHeapTypeObjects +
+                      cStats.gcHeapXML;
 
-        data->gcHeapChunkDirtyUnused -= used;
-        data->gcHeapArenaUnused += stats.gcHeapArenaUnused;
-        data->totalObjects += stats.gcHeapObjectsNonFunction +
-                              stats.gcHeapObjectsFunction +
-                              stats.objectSlots +
-                              stats.objectElements;
-        data->totalShapes  += stats.gcHeapShapesTree +
-                              stats.gcHeapShapesDict +
-                              stats.gcHeapShapesBase +
-                              stats.shapesExtraTreeTables +
-                              stats.shapesExtraDictTables +
-                              stats.shapesCompartmentTables;
-        data->totalScripts += stats.gcHeapScripts +
-                              stats.scriptData;
-        data->totalStrings += stats.gcHeapStrings +
-                              stats.stringChars;
+        rtStats->gcHeapChunkDirtyUnused -= used;
+        rtStats->gcHeapArenaUnused += cStats.gcHeapArenaUnused;
+        rtStats->totalObjects += cStats.gcHeapObjectsNonFunction +
+                                 cStats.gcHeapObjectsFunction +
+                                 cStats.objectSlots +
+                                 cStats.objectElements;
+        rtStats->totalShapes  += cStats.gcHeapShapesTree +
+                                 cStats.gcHeapShapesDict +
+                                 cStats.gcHeapShapesBase +
+                                 cStats.shapesExtraTreeTables +
+                                 cStats.shapesExtraDictTables +
+                                 cStats.shapesCompartmentTables;
+        rtStats->totalScripts += cStats.gcHeapScripts +
+                                 cStats.scriptData;
+        rtStats->totalStrings += cStats.gcHeapStrings +
+                                 cStats.stringChars;
 #ifdef JS_METHODJIT
-        data->totalMjit    += stats.mjitCode +
-                              stats.mjitData;
+        rtStats->totalMjit    += cStats.mjitCode +
+                                 cStats.mjitData;
 #endif
-        data->totalTypeInference += stats.gcHeapTypeObjects +
-                                    stats.typeInferenceMemory.objects +
-                                    stats.typeInferenceMemory.scripts +
-                                    stats.typeInferenceMemory.tables;
-        data->totalAnalysisTemp  += stats.typeInferenceMemory.temporary;
+        rtStats->totalTypeInference += cStats.gcHeapTypeObjects +
+                                       cStats.typeInferenceSizes.objects +
+                                       cStats.typeInferenceSizes.scripts +
+                                       cStats.typeInferenceSizes.tables;
+        rtStats->totalAnalysisTemp  += cStats.typeInferenceSizes.temporary;
     }
 
-    size_t numDirtyChunks = (data->gcHeapChunkTotal -
-                             data->gcHeapChunkCleanUnused) /
+    size_t numDirtyChunks = (rtStats->gcHeapChunkTotal -
+                             rtStats->gcHeapChunkCleanUnused) /
                             gc::ChunkSize;
-    int64_t perChunkAdmin =
+    size_t perChunkAdmin =
         sizeof(gc::Chunk) - (sizeof(gc::Arena) * gc::ArenasPerChunk);
-    data->gcHeapChunkAdmin = numDirtyChunks * perChunkAdmin;
-    data->gcHeapChunkDirtyUnused -= data->gcHeapChunkAdmin;
+    rtStats->gcHeapChunkAdmin = numDirtyChunks * perChunkAdmin;
+    rtStats->gcHeapChunkDirtyUnused -= rtStats->gcHeapChunkAdmin;
 
     // Why 10000x?  100x because it's a percentage, and another 100x
     // because nsIMemoryReporter requires that for percentage amounts so
     // they can be fractional.
-    data->gcHeapUnusedPercentage = (data->gcHeapChunkCleanUnused +
-                                    data->gcHeapChunkDirtyUnused +
-                                    data->gcHeapChunkCleanDecommitted +
-                                    data->gcHeapChunkDirtyDecommitted +
-                                    data->gcHeapArenaUnused) * 10000 /
-                                   data->gcHeapChunkTotal;
+    rtStats->gcHeapUnusedPercentage = (rtStats->gcHeapChunkCleanUnused +
+                                       rtStats->gcHeapChunkDirtyUnused +
+                                       rtStats->gcHeapChunkCleanDecommitted +
+                                       rtStats->gcHeapChunkDirtyDecommitted +
+                                       rtStats->gcHeapArenaUnused) * 10000 /
+                                       rtStats->gcHeapChunkTotal;
 
     return true;
 }
 
 JS_PUBLIC_API(bool)
 GetExplicitNonHeapForRuntime(JSRuntime *rt, int64_t *amount,
                              JSMallocSizeOfFun mallocSizeOf)
 {
--- a/js/src/assembler/assembler/MacroAssemblerARM.cpp
+++ b/js/src/assembler/assembler/MacroAssemblerARM.cpp
@@ -65,16 +65,32 @@ static bool isVFPPresent()
                 close(fd);
                 return aux.a_un.a_val & HWCAP_VFP;
             }
         }
         close(fd);
     }
 #endif
 
+#if defined(__GNUC__) && defined(__VFP_FP__)
+    return true;
+#endif
+
+#ifdef WTF_OS_ANDROID
+    FILE *fp = fopen("/proc/cpuinfo", "r");
+    if (!fp)
+        return false;
+
+    char buf[1024];
+    fread(buf, sizeof(char), sizeof(buf), fp);
+    fclose(fp);
+    if (strstr(buf, "vfp"))
+        return true;
+#endif
+
     return false;
 }
 
 const bool MacroAssemblerARM::s_isVFPPresent = isVFPPresent();
 
 #if WTF_CPU_ARMV5_OR_LOWER
 /* On ARMv5 and below, natural alignment is required. */
 void MacroAssemblerARM::load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest)
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -429,28 +429,57 @@ struct TreeContext {                /* t
         flags |= TCF_FUN_MUTATES_PARAMETER;
     }
 
     bool mutatesParameter() const {
         JS_ASSERT(inFunction());
         return flags & TCF_FUN_MUTATES_PARAMETER;
     }
 
-    void noteArgumentsUse(ParseNode *pn) {
+    /*
+     * Accessing the implicit |arguments| local binding in a function must
+     * trigger appropriate code generation such that the access works.
+     */
+    void noteArgumentsNameUse(ParseNode *node) {
         JS_ASSERT(inFunction());
-        countArgumentsUse(pn);
+        JS_ASSERT(node->isKind(PNK_NAME));
+        JS_ASSERT(node->pn_atom == parser->context->runtime->atomState.argumentsAtom);
+        countArgumentsUse(node);
         flags |= TCF_FUN_USES_ARGUMENTS;
         if (funbox)
             funbox->node->pn_dflags |= PND_FUNARG;
     }
 
-    void countArgumentsUse(ParseNode *pn) {
-        JS_ASSERT(pn->pn_atom == parser->context->runtime->atomState.argumentsAtom);
+    /*
+     * Non-dynamic accesses to a property named "arguments" inside a function
+     * have to deoptimize the function in case those accesses are to the
+     * function's arguments.  (However, this is unnecessary in strict mode
+     * functions because of the f.arguments poison-pill.  O frabjous day!)
+     */
+    void noteArgumentsPropertyAccess(ParseNode *node) {
+        JS_ASSERT(inFunction());
+        JS_ASSERT(&node->asPropertyAccess().name() ==
+                  parser->context->runtime->atomState.argumentsAtom);
+        if (!inStrictMode()) {
+            flags |= TCF_FUN_USES_ARGUMENTS;
+            if (funbox)
+                funbox->node->pn_dflags |= PND_FUNARG;
+        }
+    }
+
+    /*
+     * Uses of |arguments| must be noted so that such uses can be forbidden if
+     * they occur inside generator expressions (which desugar to functions and
+     * yields, in which |arguments| would have an entirely different meaning).
+     */
+    void countArgumentsUse(ParseNode *node) {
+        JS_ASSERT(node->isKind(PNK_NAME));
+        JS_ASSERT(node->pn_atom == parser->context->runtime->atomState.argumentsAtom);
         argumentsCount++;
-        argumentsNode = pn;
+        argumentsNode = node;
     }
 
     bool needsEagerArguments() const {
         return inStrictMode() && ((usesArguments() && mutatesParameter()) || callsEval());
     }
 
     void noteHasExtensibleScope() {
         flags |= TCF_FUN_EXTENSIBLE_SCOPE;
--- a/js/src/frontend/ParseNode.h
+++ b/js/src/frontend/ParseNode.h
@@ -479,16 +479,17 @@ enum ParseNodeArity {
 
 struct Definition;
 
 class LoopControlStatement;
 class BreakStatement;
 class ContinueStatement;
 class XMLProcessingInstruction;
 class ConditionalExpression;
+class PropertyAccess;
 
 struct ParseNode {
   private:
     uint32_t            pn_type   : 16, /* PNK_* type */
                         pn_op     : 8,  /* see JSOp enum and jsopcode.tbl */
                         pn_arity  : 5,  /* see ParseNodeArity enum */
                         pn_parens : 1,  /* this expr was enclosed in parens */
                         pn_used   : 1,  /* name node is on a use-chain */
@@ -922,16 +923,17 @@ struct ParseNode {
 
     /* Casting operations. */
     inline BreakStatement &asBreakStatement();
     inline ContinueStatement &asContinueStatement();
 #if JS_HAS_XML_SUPPORT
     inline XMLProcessingInstruction &asXMLProcessingInstruction();
 #endif
     inline ConditionalExpression &asConditionalExpression();
+    inline PropertyAccess &asPropertyAccess();
 };
 
 struct NullaryNode : public ParseNode {
     static inline NullaryNode *create(ParseNodeKind kind, TreeContext *tc) {
         return (NullaryNode *)ParseNode::create(kind, PN_NULLARY, tc);
     }
 };
 
@@ -1225,16 +1227,24 @@ class PropertyAccess : public ParseNode 
         return *pn_u.name.expr;
     }
 
     PropertyName &name() const {
         return *pn_u.name.atom->asPropertyName();
     }
 };
 
+inline PropertyAccess &
+ParseNode::asPropertyAccess()
+{
+    JS_ASSERT(isKind(PNK_DOT));
+    JS_ASSERT(pn_arity == PN_NAME);
+    return *static_cast<PropertyAccess *>(this);
+}
+
 class PropertyByValue : public ParseNode {
   public:
     PropertyByValue(ParseNode *lhs, ParseNode *propExpr,
                     const TokenPtr &begin, const TokenPtr &end)
       : ParseNode(PNK_LB, JSOP_GETELEM, PN_BINARY, TokenPos::make(begin, end))
     {
         pn_u.binary.left = lhs;
         pn_u.binary.right = propExpr;
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -4388,17 +4388,17 @@ Parser::variables(ParseNodeKind kind, St
                        : JSOP_SETNAME);
 
             NoteLValue(context, pn2, tc, data.fresh ? PND_INITIALIZED : PND_ASSIGNED);
 
             /* The declarator's position must include the initializer. */
             pn2->pn_pos.end = init->pn_pos.end;
 
             if (tc->inFunction() && name == context->runtime->atomState.argumentsAtom) {
-                tc->noteArgumentsUse(pn2);
+                tc->noteArgumentsNameUse(pn2);
                 if (!blockObj)
                     tc->flags |= TCF_FUN_HEAVYWEIGHT;
             }
         }
     } while (tokenStream.matchToken(TOK_COMMA));
 
     pn->pn_pos.end = pn->last()->pn_pos.end;
     return pn;
@@ -5741,21 +5741,31 @@ Parser::memberExpr(JSBool allowCallSynta
                     nextMember = new_<XMLDoubleColonProperty>(lhs, propertyId,
                                                               lhs->pn_pos.begin,
                                                               tokenStream.currentToken().pos.end);
                     if (!nextMember)
                         return NULL;
                 } else
 #endif
                 {
-                    nextMember = new_<PropertyAccess>(lhs, tokenStream.currentToken().name(),
+                    PropertyName *field = tokenStream.currentToken().name();
+                    nextMember = new_<PropertyAccess>(lhs, field,
                                                       lhs->pn_pos.begin,
                                                       tokenStream.currentToken().pos.end);
                     if (!nextMember)
                         return NULL;
+
+                    /*
+                     * A property access of the form |<expr>.arguments| might
+                     * access this function's arguments, so we need to flag a
+                     * potential arguments use to ensure an arguments object
+                     * will be created.  See bug 721322.
+                     */
+                    if (tc->inFunction() && field == context->runtime->atomState.argumentsAtom)
+                        tc->noteArgumentsPropertyAccess(nextMember);
                 }
             }
 #if JS_HAS_XML_SUPPORT
             else if (!tc->inStrictMode()) {
                 TokenPtr begin = lhs->pn_pos.begin;
                 if (tt == TOK_LP) {
                     /* Filters are effectively 'with', so deoptimize names. */
                     tc->flags |= TCF_FUN_HEAVYWEIGHT;
@@ -6609,48 +6619,47 @@ Parser::propertyQualifiedIdentifier()
         return NULL;
 
     tokenStream.consumeKnownToken(TOK_DBLCOLON);
     return qualifiedSuffix(node);
 }
 #endif
 
 ParseNode *
-Parser::identifierName(bool afterDot)
+Parser::identifierName(bool afterDoubleDot)
 {
     JS_ASSERT(tokenStream.isCurrentTokenType(TOK_NAME));
 
     PropertyName *name = tokenStream.currentToken().name();
     ParseNode *node = NameNode::create(PNK_NAME, name, tc);
     if (!node)
         return NULL;
     JS_ASSERT(tokenStream.currentToken().t_op == JSOP_NAME);
     node->setOp(JSOP_NAME);
 
     if ((tc->flags & (TCF_IN_FUNCTION | TCF_FUN_PARAM_ARGUMENTS)) == TCF_IN_FUNCTION &&
-        name == context->runtime->atomState.argumentsAtom) {
-        /*
-         * Flag arguments usage so we can avoid unsafe optimizations such
-         * as formal parameter assignment analysis (because of the hated
-         * feature whereby arguments alias formals). We do this even for
-         * a reference of the form foo.arguments, which ancient code may
-         * still use instead of arguments (more hate).
-         */
-        tc->noteArgumentsUse(node);
-
+        name == context->runtime->atomState.argumentsAtom)
+    {
         /*
          * Bind early to JSOP_ARGUMENTS to relieve later code from having
          * to do this work (new rule for the emitter to count on).
          */
-        if (!afterDot && !(tc->flags & TCF_DECL_DESTRUCTURING)
-            && !tc->inStatement(STMT_WITH)) {
-            node->setOp(JSOP_ARGUMENTS);
-            node->pn_dflags |= PND_BOUND;
+        if (!afterDoubleDot) {
+            /*
+             * Note use of |arguments| to ensure we can properly create the
+             * |arguments| object for this function.
+             */
+            tc->noteArgumentsNameUse(node);
+
+            if (!(tc->flags & TCF_DECL_DESTRUCTURING) && !tc->inStatement(STMT_WITH)) {
+                node->setOp(JSOP_ARGUMENTS);
+                node->pn_dflags |= PND_BOUND;
+            }
         }
-    } else if ((!afterDot
+    } else if ((!afterDoubleDot
 #if JS_HAS_XML_SUPPORT
                 || (!tc->inStrictMode() && tokenStream.peekToken() == TOK_DBLCOLON)
 #endif
                ) && !(tc->flags & TCF_DECL_DESTRUCTURING))
     {
         /* In case this is a generator expression outside of any function. */
         if (!tc->inFunction() && name == context->runtime->atomState.argumentsAtom)
             tc->countArgumentsUse(node);
@@ -6703,17 +6712,17 @@ Parser::identifierName(bool afterDot)
 
         node->pn_dflags |= (dn->pn_dflags & PND_FUNARG);
         if (stmt && stmt->type == STMT_WITH)
             node->pn_dflags |= PND_DEOPTIMIZED;
     }
 
 #if JS_HAS_XML_SUPPORT
     if (!tc->inStrictMode() && tokenStream.matchToken(TOK_DBLCOLON)) {
-        if (afterDot) {
+        if (afterDoubleDot) {
             if (!checkForFunctionNode(name, node))
                 return NULL;
         }
         node = qualifiedSuffix(node);
         if (!node)
             return NULL;
     }
 #endif
@@ -6730,17 +6739,17 @@ Parser::starOrAtPropertyIdentifier(Token
         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_SYNTAX_ERROR);
         return NULL;
     }
     return (tt == TOK_AT) ? attributeIdentifier() : qualifiedIdentifier();
 }
 #endif
 
 ParseNode *
-Parser::primaryExpr(TokenKind tt, JSBool afterDot)
+Parser::primaryExpr(TokenKind tt, bool afterDoubleDot)
 {
     JS_ASSERT(tokenStream.isCurrentTokenType(tt));
 
     ParseNode *pn, *pn2, *pn3;
     JSOp op;
 
     JS_CHECK_RECURSION(context, return NULL);
 
@@ -7163,17 +7172,17 @@ Parser::primaryExpr(TokenKind tt, JSBool
         pn = new_<XMLProcessingInstruction>(tok.xmlPITarget(), tok.xmlPIData(), tok.pos);
         if (!pn)
             return NULL;
         break;
       }
 #endif
 
       case TOK_NAME:
-        pn = identifierName(afterDot);
+        pn = identifierName(afterDoubleDot);
         break;
 
       case TOK_REGEXP:
       {
         pn = NullaryNode::create(PNK_REGEXP, tc);
         if (!pn)
             return NULL;
 
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -229,17 +229,17 @@ struct Parser : private AutoGCRooter
     ParseNode *shiftExpr1i();
     ParseNode *shiftExpr1n();
     ParseNode *addExpr1i();
     ParseNode *addExpr1n();
     ParseNode *mulExpr1i();
     ParseNode *mulExpr1n();
     ParseNode *unaryExpr();
     ParseNode *memberExpr(JSBool allowCallSyntax);
-    ParseNode *primaryExpr(TokenKind tt, JSBool afterDot);
+    ParseNode *primaryExpr(TokenKind tt, bool afterDoubleDot);
     ParseNode *parenExpr(JSBool *genexp = NULL);
 
     /*
      * Additional JS parsers.
      */
     enum FunctionType { Getter, Setter, Normal };
     bool functionArguments(TreeContext &funtc, FunctionBox *funbox, ParseNode **list);
 
@@ -254,17 +254,17 @@ struct Parser : private AutoGCRooter
     JSBool argumentList(ParseNode *listNode);
     ParseNode *bracketedExpr();
     ParseNode *letBlock(LetContext letContext);
     ParseNode *returnOrYield(bool useAssignExpr);
     ParseNode *destructuringExpr(BindData *data, TokenKind tt);
 
     bool checkForFunctionNode(PropertyName *name, ParseNode *node);
 
-    ParseNode *identifierName(bool afterDot);
+    ParseNode *identifierName(bool afterDoubleDot);
 
 #if JS_HAS_XML_SUPPORT
     ParseNode *endBracketedExpr();
 
     ParseNode *propertySelector();
     ParseNode *qualifiedSuffix(ParseNode *pn);
     ParseNode *qualifiedIdentifier();
     ParseNode *attributeIdentifier();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/arguments/e4x-descendants-with-arguments.js
@@ -0,0 +1,6 @@
+function f()
+{
+  var x = <><arguments/><arguments/></>;
+  x..arguments;
+}
+f();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug714616.js
@@ -0,0 +1,8 @@
+array1 = new Array();
+size   = 10;
+for (i = 0; i < size; (array1.length)++)
+{
+  array1.push(array1.shift());
+  ++i
+}
+
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/pic/getelem-large-index.js
@@ -0,0 +1,13 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ */
+function testProperty(i)
+{
+  actual = obj[String(i)];
+}
+
+var obj = {};
+var index = [null, 1073741824, 1073741825];
+for (var j in index)
+  testProperty(index[j]);
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -760,17 +760,16 @@ JSRuntime::JSRuntime()
     positiveInfinityValue(UndefinedValue()),
     emptyString(NULL),
     debugMode(false),
     profilingScripts(false),
     hadOutOfMemory(false),
     data(NULL),
 #ifdef JS_THREADSAFE
     gcLock(NULL),
-    requestCount(0),
     gcHelperThread(thisFromCtor()),
 #endif
     debuggerMutations(0),
     securityCallbacks(NULL),
     structuredCloneCallbacks(NULL),
     telemetryCallback(NULL),
     propertyRemovals(0),
     thousandsSeparator(0),
@@ -1008,20 +1007,19 @@ StartRequest(JSContext *cx)
     JS_ASSERT(rt->onOwnerThread());
 
     if (rt->requestDepth) {
         rt->requestDepth++;
     } else {
         AutoLockGC lock(rt);
 
         /* Indicate that a request is running. */
-        rt->requestCount++;
         rt->requestDepth = 1;
 
-        if (rt->requestCount == 1 && rt->activityCallback)
+        if (rt->activityCallback)
             rt->activityCallback(rt->activityCallbackArg, true);
     }
 }
 
 static void
 StopRequest(JSContext *cx)
 {
     JSRuntime *rt = cx->runtime;
@@ -1032,23 +1030,18 @@ StopRequest(JSContext *cx)
     } else {
         rt->conservativeGC.updateForRequestEnd(rt->suspendCount);
 
         /* Lock before clearing to interlock with ClaimScope, in jslock.c. */
         AutoLockGC lock(rt);
 
         rt->requestDepth = 0;
 
-        /* Give the GC a chance to run if this was the last request running. */
-        JS_ASSERT(rt->requestCount > 0);
-        rt->requestCount--;
-        if (rt->requestCount == 0) {
-            if (rt->activityCallback)
-                rt->activityCallback(rt->activityCallbackArg, false);
-        }
+        if (rt->activityCallback)
+            rt->activityCallback(rt->activityCallbackArg, false);
     }
 }
 #endif /* JS_THREADSAFE */
 
 JS_PUBLIC_API(void)
 JS_BeginRequest(JSContext *cx)
 {
 #ifdef JS_THREADSAFE
@@ -2211,17 +2204,17 @@ JS_PUBLIC_API(void)
 JS_free(JSContext *cx, void *p)
 {
     return cx->free_(p);
 }
 
 JS_PUBLIC_API(void)
 JS_updateMallocCounter(JSContext *cx, size_t nbytes)
 {
-    return cx->runtime->updateMallocCounter(nbytes);
+    return cx->runtime->updateMallocCounter(cx, nbytes);
 }
 
 JS_PUBLIC_API(char *)
 JS_strdup(JSContext *cx, const char *s)
 {
     AssertNoGC(cx);
     size_t n = strlen(s) + 1;
     void *p = cx->malloc_(n);
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -2501,17 +2501,17 @@ mjit::stubs::ArrayShift(VMFrame &f)
     JS_ASSERT(obj->isDenseArray());
 
     /*
      * At this point the length and initialized length have already been
      * decremented and the result fetched, so just shift the array elements
      * themselves.
      */
     uint32_t initlen = obj->getDenseArrayInitializedLength();
-    obj->moveDenseArrayElements(0, 1, initlen);
+    obj->moveDenseArrayElementsUnbarriered(0, 1, initlen);
 }
 #endif /* JS_METHODJIT */
 
 JSBool
 js::array_shift(JSContext *cx, uintN argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     JSObject *obj = ToObject(cx, &args.thisv());
@@ -2528,17 +2528,17 @@ js::array_shift(JSContext *cx, uintN arg
         length--;
 
         if (obj->isDenseArray() && !js_PrototypeHasIndexedProperties(cx, obj) &&
             length < obj->getDenseArrayCapacity() &&
             0 < obj->getDenseArrayInitializedLength()) {
             args.rval() = obj->getDenseArrayElement(0);
             if (args.rval().isMagic(JS_ARRAY_HOLE))
                 args.rval().setUndefined();
-            obj->moveDenseArrayElements(0, 1, length);
+            obj->moveDenseArrayElements(0, 1, obj->getDenseArrayInitializedLength() - 1);
             obj->setDenseArrayInitializedLength(obj->getDenseArrayInitializedLength() - 1);
             obj->setArrayLength(cx, length);
             if (!js_SuppressDeletedProperty(cx, obj, INT_TO_JSID(length)))
                 return JS_FALSE;
             return JS_TRUE;
         }
 
         JSBool hole;
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -240,62 +240,42 @@ void
 js_DestroyContext(JSContext *cx, JSDestroyContextMode mode)
 {
     JSRuntime *rt = cx->runtime;
     JS_AbortIfWrongThread(rt);
 
     JS_ASSERT(!cx->enumerators);
 
 #ifdef JS_THREADSAFE
-    /*
-     * For API compatibility we support destroying contexts with non-zero
-     * cx->outstandingRequests but we assume that all JS_BeginRequest calls
-     * on this cx contributes to cx->thread->data.requestDepth and there is no
-     * JS_SuspendRequest calls that set aside the counter.
-     */
-    JS_ASSERT(cx->outstandingRequests <= cx->runtime->requestDepth);
+    JS_ASSERT(cx->outstandingRequests == 0);
 #endif
 
     if (mode != JSDCM_NEW_FAILED) {
         if (JSContextCallback cxCallback = rt->cxCallback) {
             /*
              * JSCONTEXT_DESTROY callback is not allowed to fail and must
              * return true.
              */
             DebugOnly<JSBool> callbackStatus = cxCallback(cx, JSCONTEXT_DESTROY);
             JS_ASSERT(callbackStatus);
         }
     }
 
     JS_LOCK_GC(rt);
     JS_REMOVE_LINK(&cx->link);
     bool last = !rt->hasContexts();
-    if (last || mode == JSDCM_FORCE_GC || mode == JSDCM_MAYBE_GC
-#ifdef JS_THREADSAFE
-        || cx->outstandingRequests != 0
-#endif
-        ) {
+    if (last || mode == JSDCM_FORCE_GC || mode == JSDCM_MAYBE_GC) {
         JS_ASSERT(!rt->gcRunning);
 
 #ifdef JS_THREADSAFE
         rt->gcHelperThread.waitBackgroundSweepEnd();
 #endif
         JS_UNLOCK_GC(rt);
 
         if (last) {
-#ifdef JS_THREADSAFE
-            /*
-             * If this thread is not in a request already, begin one now so
-             * that we wait for any racing GC started on a not-last context to
-             * finish, before we plow ahead and unpin atoms.
-             */
-            if (cx->runtime->requestDepth == 0)
-                JS_BeginRequest(cx);
-#endif
-
             /*
              * Dump remaining type inference results first. This printing
              * depends on atoms still existing.
              */
             {
                 AutoLockGC lock(rt);
                 for (CompartmentsIter c(rt); !c.done(); c.next())
                     c->types.print(cx, false);
@@ -303,37 +283,25 @@ js_DestroyContext(JSContext *cx, JSDestr
 
             /* Unpin all common atoms before final GC. */
             js_FinishCommonAtoms(cx);
 
             /* Clear debugging state to remove GC roots. */
             for (CompartmentsIter c(rt); !c.done(); c.next())
                 c->clearTraps(cx);
             JS_ClearAllWatchPoints(cx);
-        }
 
-#ifdef JS_THREADSAFE
-        /* Destroying a context implicitly calls JS_EndRequest(). */
-        while (cx->outstandingRequests != 0)
-            JS_EndRequest(cx);
-#endif
-
-        if (last) {
             js_GC(cx, NULL, GC_NORMAL, gcreason::LAST_CONTEXT);
 
-            /* Take the runtime down, now that it has no contexts or atoms. */
-            JS_LOCK_GC(rt);
-        } else {
-            if (mode == JSDCM_FORCE_GC)
-                js_GC(cx, NULL, GC_NORMAL, gcreason::DESTROY_CONTEXT);
-            else if (mode == JSDCM_MAYBE_GC)
-                JS_MaybeGC(cx);
-
-            JS_LOCK_GC(rt);
+        } else if (mode == JSDCM_FORCE_GC) {
+            js_GC(cx, NULL, GC_NORMAL, gcreason::DESTROY_CONTEXT);
+        } else if (mode == JSDCM_MAYBE_GC) {
+            JS_MaybeGC(cx);
         }
+        JS_LOCK_GC(rt);
     }
 #ifdef JS_THREADSAFE
     rt->gcHelperThread.waitBackgroundSweepEnd();
 #endif
     JS_UNLOCK_GC(rt);
     Foreground::delete_(cx);
 }
 
@@ -347,31 +315,16 @@ js_ContextIterator(JSRuntime *rt, JSBool
         lockIf.construct(rt);
     cx = JSContext::fromLinkField(cx ? cx->link.next : rt->contextList.next);
     if (&cx->link == &rt->contextList)
         cx = NULL;
     *iterp = cx;
     return cx;
 }
 
-JS_FRIEND_API(JSContext *)
-js_NextActiveContext(JSRuntime *rt, JSContext *cx)
-{
-    JSContext *iter = cx;
-#ifdef JS_THREADSAFE
-    while ((cx = js_ContextIterator(rt, JS_FALSE, &iter)) != NULL) {
-        if (cx->outstandingRequests && cx->runtime->requestDepth)
-            break;
-    }
-    return cx;
-#else
-    return js_ContextIterator(rt, JS_FALSE, &iter);
-#endif
-}
-
 namespace js {
 
 bool
 AutoResolving::alreadyStartedSlow() const
 {
     JS_ASSERT(link);
     AutoResolving *cursor = link;
     do {
@@ -1165,16 +1118,29 @@ JSContext::generatorFor(StackFrame *fp) 
 }
 
 bool
 JSContext::runningWithTrustedPrincipals() const
 {
     return !compartment || compartment->principals == runtime->trustedPrincipals();
 }
 
+void
+JSRuntime::updateMallocCounter(JSContext *cx, size_t nbytes)
+{
+    /* We tolerate any thread races when updating gcMallocBytes. */
+    ptrdiff_t oldCount = gcMallocBytes;
+    ptrdiff_t newCount = oldCount - ptrdiff_t(nbytes);
+    gcMallocBytes = newCount;
+    if (JS_UNLIKELY(newCount <= 0 && oldCount > 0))
+        onTooMuchMalloc();
+    else if (cx && cx->compartment)
+        cx->compartment->updateMallocCounter(nbytes);
+}
+
 JS_FRIEND_API(void)
 JSRuntime::onTooMuchMalloc()
 {
     TriggerGC(this, gcreason::TOO_MUCH_MALLOC);
 }
 
 JS_FRIEND_API(void *)
 JSRuntime::onOutOfMemory(void *p, size_t nbytes, JSContext *cx)
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -448,17 +448,16 @@ struct JSRuntime
     JSCList             debuggerList;
 
     /* Client opaque pointers */
     void                *data;
 
 #ifdef JS_THREADSAFE
     /* These combine to interlock the GC and new requests. */
     PRLock              *gcLock;
-    uint32_t            requestCount;
 
     js::GCHelperThread  gcHelperThread;
 #endif /* JS_THREADSAFE */
 
     uint32_t            debuggerMutations;
 
     /*
      * Security callbacks set on the runtime are used by each context unless
@@ -554,45 +553,45 @@ struct JSRuntime
     void setGCLastBytes(size_t lastBytes, JSGCInvocationKind gckind);
     void reduceGCTriggerBytes(size_t amount);
 
     /*
      * Call the system malloc while checking for GC memory pressure and
      * reporting OOM error when cx is not null. We will not GC from here.
      */
     void* malloc_(size_t bytes, JSContext *cx = NULL) {
-        updateMallocCounter(bytes);
+        updateMallocCounter(cx, bytes);
         void *p = ::js_malloc(bytes);
         return JS_LIKELY(!!p) ? p : onOutOfMemory(NULL, bytes, cx);
     }
 
     /*
      * Call the system calloc while checking for GC memory pressure and
      * reporting OOM error when cx is not null. We will not GC from here.
      */
     void* calloc_(size_t bytes, JSContext *cx = NULL) {
-        updateMallocCounter(bytes);
+        updateMallocCounter(cx, bytes);
         void *p = ::js_calloc(bytes);
         return JS_LIKELY(!!p) ? p : onOutOfMemory(reinterpret_cast<void *>(1), bytes, cx);
     }
 
     void* realloc_(void* p, size_t oldBytes, size_t newBytes, JSContext *cx = NULL) {
         JS_ASSERT(oldBytes < newBytes);
-        updateMallocCounter(newBytes - oldBytes);
+        updateMallocCounter(cx, newBytes - oldBytes);
         void *p2 = ::js_realloc(p, newBytes);
         return JS_LIKELY(!!p2) ? p2 : onOutOfMemory(p, newBytes, cx);
     }
 
     void* realloc_(void* p, size_t bytes, JSContext *cx = NULL) {
         /*
          * For compatibility we do not account for realloc that increases
          * previously allocated memory.
          */
         if (!p)
-            updateMallocCounter(bytes);
+            updateMallocCounter(cx, bytes);
         void *p2 = ::js_realloc(p, bytes);
         return JS_LIKELY(!!p2) ? p2 : onOutOfMemory(p, bytes, cx);
     }
 
     inline void free_(void* p) {
         /* FIXME: Making this free in the background is buggy. Can it work? */
         js::Foreground::free_(p);
     }
@@ -616,23 +615,17 @@ struct JSRuntime
     /*
      * Call this after allocating memory held by GC things, to update memory
      * pressure counters or report the OOM error if necessary. If oomError and
      * cx is not null the function also reports OOM error.
      *
      * The function must be called outside the GC lock and in case of OOM error
      * the caller must ensure that no deadlock possible during OOM reporting.
      */
-    void updateMallocCounter(size_t nbytes) {
-        /* We tolerate any thread races when updating gcMallocBytes. */
-        ptrdiff_t newCount = gcMallocBytes - ptrdiff_t(nbytes);
-        gcMallocBytes = newCount;
-        if (JS_UNLIKELY(newCount <= 0))
-            onTooMuchMalloc();
-    }
+    void updateMallocCounter(JSContext *cx, size_t nbytes);
 
     /*
      * The function must be called outside the GC lock.
      */
     JS_FRIEND_API(void) onTooMuchMalloc();
 
     /*
      * This should be called after system malloc/realloc returns NULL to try
@@ -1359,24 +1352,16 @@ js_DestroyContext(JSContext *cx, JSDestr
 
 /*
  * If unlocked, acquire and release rt->gcLock around *iterp update; otherwise
  * the caller must be holding rt->gcLock.
  */
 extern JSContext *
 js_ContextIterator(JSRuntime *rt, JSBool unlocked, JSContext **iterp);
 
-/*
- * Iterate through contexts with active requests. The caller must be holding
- * rt->gcLock in case of a thread-safe build, or otherwise guarantee that the
- * context list is not alternated asynchroniously.
- */
-extern JS_FRIEND_API(JSContext *)
-js_NextActiveContext(JSRuntime *, JSContext *);
-
 #ifdef va_start
 extern JSBool
 js_ReportErrorVA(JSContext *cx, uintN flags, const char *format, va_list ap);
 
 extern JSBool
 js_ReportErrorNumberVA(JSContext *cx, uintN flags, JSErrorCallback callback,
                        void *userRef, const uintN errorNumber,
                        JSBool charArgs, va_list ap);
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -87,16 +87,17 @@ JSCompartment::JSCompartment(JSRuntime *
 #endif
     propertyTree(thisForCtor()),
     emptyTypeObject(NULL),
     debugModeBits(rt->debugMode ? DebugFromC : 0),
     mathCache(NULL),
     watchpointMap(NULL)
 {
     PodArrayZero(evalCache);
+    setGCMaxMallocBytes(rt->gcMaxMallocBytes * 0.9);
 }
 
 JSCompartment::~JSCompartment()
 {
 #ifdef JS_METHODJIT
     Foreground::delete_(jaegerCompartment_);
 #endif
 
@@ -564,16 +565,40 @@ JSCompartment::purge(JSContext *cx)
             listHeadp = &script->evalHashLink();
         }
     }
 
     nativeIterCache.purge();
     toSourceCache.destroyIfConstructed();
 }
 
+void
+JSCompartment::resetGCMallocBytes()
+{
+    gcMallocBytes = ptrdiff_t(gcMaxMallocBytes);
+}
+
+void
+JSCompartment::setGCMaxMallocBytes(size_t value)
+{
+    /*
+     * For compatibility treat any value that exceeds PTRDIFF_T_MAX to
+     * mean that value.
+     */
+    gcMaxMallocBytes = (ptrdiff_t(value) >= 0) ? value : size_t(-1) >> 1;
+    resetGCMallocBytes();
+}
+
+void
+JSCompartment::onTooMuchMalloc()
+{
+    TriggerCompartmentGC(this, gcreason::TOO_MUCH_MALLOC);
+}
+
+
 MathCache *
 JSCompartment::allocMathCache(JSContext *cx)
 {
     JS_ASSERT(!mathCache);
     mathCache = cx->new_<MathCache>();
     if (!mathCache)
         js_ReportOutOfMemory(cx);
     return mathCache;
@@ -740,15 +765,15 @@ JSCompartment::sweepBreakpoints(JSContex
 GCMarker *
 JSCompartment::createBarrierTracer()
 {
     JS_ASSERT(!gcIncrementalTracer);
     return NULL;
 }
 
 size_t
-JS::SizeOfCompartmentShapeTable(JSCompartment *c, JSMallocSizeOfFun mallocSizeOf)
+JSCompartment::sizeOfShapeTable(JSMallocSizeOfFun mallocSizeOf)
 {
-    return c->baseShapes.sizeOfExcludingThis(mallocSizeOf)
-         + c->initialShapes.sizeOfExcludingThis(mallocSizeOf)
-         + c->newTypeObjects.sizeOfExcludingThis(mallocSizeOf)
-         + c->lazyTypeObjects.sizeOfExcludingThis(mallocSizeOf);
+    return baseShapes.sizeOfExcludingThis(mallocSizeOf)
+         + initialShapes.sizeOfExcludingThis(mallocSizeOf)
+         + newTypeObjects.sizeOfExcludingThis(mallocSizeOf)
+         + lazyTypeObjects.sizeOfExcludingThis(mallocSizeOf);
 }
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -159,16 +159,20 @@ struct ScriptFilenameHasher
 };
 
 typedef HashSet<ScriptFilenameEntry *,
                 ScriptFilenameHasher,
                 SystemAllocPolicy> ScriptFilenameTable;
 
 } /* namespace js */
 
+namespace JS {
+struct TypeInferenceSizes;
+}
+
 struct JSCompartment
 {
     JSRuntime                    *rt;
     JSPrincipals                 *principals;
 
     js::gc::ArenaLists           arenas;
 
     bool                         needsBarrier_;
@@ -183,16 +187,17 @@ struct JSCompartment
         if (gcIncrementalTracer)
             return gcIncrementalTracer;
         return createBarrierTracer();
     }
 
     size_t                       gcBytes;
     size_t                       gcTriggerBytes;
     size_t                       gcLastBytes;
+    size_t                       gcMaxMallocBytes;
 
     bool                         hold;
     bool                         isSystemCompartment;
 
     /*
      * Pool for analysis and intermediate type information in this compartment.
      * Cleared on every GC, unless the GC happens during analysis (indicated
      * by activeAnalysis, which is implied by activeInference).
@@ -234,16 +239,20 @@ struct JSCompartment
         return jaegerCompartment_;
     }
 
     bool ensureJaegerCompartmentExists(JSContext *cx);
 
     size_t sizeOfMjitCode() const;
 #endif
 
+    size_t sizeOfShapeTable(JSMallocSizeOfFun mallocSizeOf);
+    void sizeOfTypeInferenceData(JSContext *cx, JS::TypeInferenceSizes *stats,
+                                 JSMallocSizeOfFun mallocSizeOf);
+
     /*
      * Shared scope property tree, and arena-pool for allocating its nodes.
      */
     js::PropertyTree             propertyTree;
 
 #ifdef DEBUG
     /* Property metering. */
     jsrefcount                   livePropTreeNodes;
@@ -274,16 +283,22 @@ struct JSCompartment
 
     /* Cache to speed up object creation. */
     js::NewObjectCache           newObjectCache;
 
   private:
     enum { DebugFromC = 1, DebugFromJS = 2 };
 
     uintN                        debugModeBits;  // see debugMode() below
+    
+    /*
+     * Malloc counter to measure memory pressure for GC scheduling. It runs
+     * from gcMaxMallocBytes down to zero.
+     */
+    volatile ptrdiff_t           gcMallocBytes;
 
   public:
     js::NativeIterCache          nativeIterCache;
 
     typedef js::Maybe<js::ToSourceCache> LazyToSourceCache;
     LazyToSourceCache            toSourceCache;
 
     js::ScriptFilenameTable      scriptFilenameTable;
@@ -307,16 +322,28 @@ struct JSCompartment
     bool wrap(JSContext *cx, js::AutoIdVector &props);
 
     void markTypes(JSTracer *trc);
     void sweep(JSContext *cx, bool releaseTypes);
     void purge(JSContext *cx);
 
     void setGCLastBytes(size_t lastBytes, JSGCInvocationKind gckind);
     void reduceGCTriggerBytes(size_t amount);
+    
+    void resetGCMallocBytes();
+    void setGCMaxMallocBytes(size_t value);
+    void updateMallocCounter(size_t nbytes) {
+        ptrdiff_t oldCount = gcMallocBytes;
+        ptrdiff_t newCount = oldCount - ptrdiff_t(nbytes);
+        gcMallocBytes = newCount;
+        if (JS_UNLIKELY(newCount <= 0 && oldCount > 0))
+            onTooMuchMalloc();
+    }
+    
+    void onTooMuchMalloc();
 
     js::DtoaCache dtoaCache;
 
   private:
     js::MathCache                *mathCache;
 
     js::MathCache *allocMathCache(JSContext *cx);
 
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -2845,16 +2845,26 @@ static void
 MarkAndSweep(JSContext *cx, JSGCInvocationKind gckind)
 {
     JSRuntime *rt = cx->runtime;
     rt->gcNumber++;
 
     /* Clear gcIsNeeded now, when we are about to start a normal GC cycle. */
     rt->gcIsNeeded = false;
     rt->gcTriggerCompartment = NULL;
+    
+    /* Clear gcMallocBytes for all compartments */
+    JSCompartment **read = rt->compartments.begin();
+    JSCompartment **end = rt->compartments.end();
+    JS_ASSERT(rt->compartments.length() >= 1);
+    
+    while (read < end) {
+        JSCompartment *compartment = *read++;
+        compartment->resetGCMallocBytes();
+    }
 
     /* Reset weak map list. */
     WeakMapBase::resetWeakMapList(rt);
 
     /* Reset malloc counter. */
     rt->resetGCMallocBytes();
 
     AutoUnlockGC unlock(rt);
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -6253,151 +6253,147 @@ TypeScript::destroy()
 
     if (nesting)
         Foreground::delete_(nesting);
 
     Foreground::free_(this);
 }
 
 inline size_t
-TypeSet::dynamicSize()
+TypeSet::computedSizeOfExcludingThis()
 {
     /*
      * This memory is allocated within the temp pool (but accounted for
      * elsewhere) so we can't use a JSMallocSizeOfFun to measure it.  We must
-     * do it analytically.
+     * compute its size analytically.
      */
     uint32_t count = baseObjectCount();
     if (count >= 2)
         return HashSetCapacity(count) * sizeof(TypeObject *);
     return 0;
 }
 
 inline size_t
-TypeObject::dynamicSize()
+TypeObject::computedSizeOfExcludingThis()
 {
     /*
      * This memory is allocated within the temp pool (but accounted for
      * elsewhere) so we can't use a JSMallocSizeOfFun to measure it.  We must
-     * do it analytically.
+     * compute its size analytically.
      */
     size_t bytes = 0;
 
     uint32_t count = basePropertyCount();
     if (count >= 2)
         bytes += HashSetCapacity(count) * sizeof(TypeObject *);
 
     count = getPropertyCount();
     for (unsigned i = 0; i < count; i++) {
         Property *prop = getProperty(i);
         if (prop)
-            bytes += sizeof(Property) + prop->types.dynamicSize();
+            bytes += sizeof(Property) + prop->types.computedSizeOfExcludingThis();
     }
 
     return bytes;
 }
 
 static void
-GetScriptMemoryStats(JSScript *script, TypeInferenceMemoryStats *stats, JSMallocSizeOfFun mallocSizeOf)
+SizeOfScriptTypeInferenceData(JSScript *script, TypeInferenceSizes *sizes,
+                              JSMallocSizeOfFun mallocSizeOf)
 {
     TypeScript *typeScript = script->types;
     if (!typeScript)
         return;
 
     /* If TI is disabled, a single TypeScript is still present. */
     if (!script->compartment()->types.inferenceEnabled) {
-        stats->scripts += mallocSizeOf(typeScript);
+        sizes->scripts += mallocSizeOf(typeScript);
         return;
     }
 
-    stats->scripts += mallocSizeOf(typeScript->nesting);
+    sizes->scripts += mallocSizeOf(typeScript->nesting);
 
     unsigned count = TypeScript::NumTypeSets(script);
-    stats->scripts += mallocSizeOf(typeScript);
+    sizes->scripts += mallocSizeOf(typeScript);
 
     TypeResult *result = typeScript->dynamicList;
     while (result) {
-        stats->scripts += mallocSizeOf(result);
+        sizes->scripts += mallocSizeOf(result);
         result = result->next;
     }
 
     /*
      * This counts memory that is in the temp pool but gets attributed
      * elsewhere.  See JS::SizeOfCompartmentTypeInferenceData for more details.
      */
     TypeSet *typeArray = typeScript->typeArray();
     for (unsigned i = 0; i < count; i++) {
-        size_t bytes = typeArray[i].dynamicSize();
-        stats->scripts += bytes;
-        stats->temporary -= bytes;
+        size_t bytes = typeArray[i].computedSizeOfExcludingThis();
+        sizes->scripts += bytes;
+        sizes->temporary -= bytes;
     }
 }
 
 void
-JS::SizeOfCompartmentTypeInferenceData(JSContext *cx, JSCompartment *compartment,
-                                       TypeInferenceMemoryStats *stats,
+JSCompartment::sizeOfTypeInferenceData(JSContext *cx, TypeInferenceSizes *sizes,
                                        JSMallocSizeOfFun mallocSizeOf)
 {
     /*
      * Note: not all data in the pool is temporary, and some will survive GCs
      * by being copied to the replacement pool. This memory will be counted
      * elsewhere and deducted from the amount of temporary data.
      */
-    stats->temporary += compartment->typeLifoAlloc.sizeOfExcludingThis(mallocSizeOf);
+    sizes->temporary += typeLifoAlloc.sizeOfExcludingThis(mallocSizeOf);
 
     /* Pending arrays are cleared on GC along with the analysis pool. */
-    stats->temporary +=
-        mallocSizeOf(compartment->types.pendingArray);
+    sizes->temporary += mallocSizeOf(types.pendingArray);
 
     /* TypeCompartment::pendingRecompiles is non-NULL only while inference code is running. */
-    JS_ASSERT(!compartment->types.pendingRecompiles);
-
-    for (gc::CellIter i(cx, compartment, gc::FINALIZE_SCRIPT); !i.done(); i.next())
-        GetScriptMemoryStats(i.get<JSScript>(), stats, mallocSizeOf);
-
-    if (compartment->types.allocationSiteTable)
-        stats->tables += compartment->types.allocationSiteTable->sizeOfIncludingThis(mallocSizeOf);
-
-    if (compartment->types.arrayTypeTable)
-        stats->tables += compartment->types.arrayTypeTable->sizeOfIncludingThis(mallocSizeOf);
-
-    if (compartment->types.objectTypeTable) {
-        stats->tables += compartment->types.objectTypeTable->sizeOfIncludingThis(mallocSizeOf);
-
-        for (ObjectTypeTable::Enum e(*compartment->types.objectTypeTable);
+    JS_ASSERT(!types.pendingRecompiles);
+
+    for (gc::CellIter i(cx, this, gc::FINALIZE_SCRIPT); !i.done(); i.next())
+        SizeOfScriptTypeInferenceData(i.get<JSScript>(), sizes, mallocSizeOf);
+
+    if (types.allocationSiteTable)
+        sizes->tables += types.allocationSiteTable->sizeOfIncludingThis(mallocSizeOf);
+
+    if (types.arrayTypeTable)
+        sizes->tables += types.arrayTypeTable->sizeOfIncludingThis(mallocSizeOf);
+
+    if (types.objectTypeTable) {
+        sizes->tables += types.objectTypeTable->sizeOfIncludingThis(mallocSizeOf);
+
+        for (ObjectTypeTable::Enum e(*types.objectTypeTable);
              !e.empty();
              e.popFront())
         {
             const ObjectTableKey &key = e.front().key;
             const ObjectTableEntry &value = e.front().value;
 
             /* key.ids and values.types have the same length. */
-            stats->tables += mallocSizeOf(key.ids) + mallocSizeOf(value.types);
+            sizes->tables += mallocSizeOf(key.ids) + mallocSizeOf(value.types);
         }
     }
 }
 
 void
-JS::SizeOfTypeObjectExcludingThis(void *object_, TypeInferenceMemoryStats *stats, JSMallocSizeOfFun mallocSizeOf)
-{
-    TypeObject *object = (TypeObject *) object_;
-
-    if (object->singleton) {
+TypeObject::sizeOfExcludingThis(TypeInferenceSizes *sizes, JSMallocSizeOfFun mallocSizeOf)
+{
+    if (singleton) {
         /*
          * Properties and associated type sets for singletons are cleared on
          * every GC. The type object is normally destroyed too, but we don't
          * charge this to 'temporary' as this is not for GC heap values.
          */
-        JS_ASSERT(!object->newScript);
+        JS_ASSERT(!newScript);
         return;
     }
 
-    if (object->newScript)
-        stats->objects += mallocSizeOf(object->newScript);
+    sizes->objects += mallocSizeOf(newScript);
 
     /*
      * This counts memory that is in the temp pool but gets attributed
-     * elsewhere.  See JS_GetTypeInferenceMemoryStats for more details.
+     * elsewhere.  See JSCompartment::sizeOfTypeInferenceData for more details.
      */
-    size_t bytes = object->dynamicSize();
-    stats->objects += bytes;
-    stats->temporary -= bytes;
-}
+    size_t bytes = computedSizeOfExcludingThis();
+    sizes->objects += bytes;
+    sizes->temporary -= bytes;
+}
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -46,16 +46,20 @@
 #include "jscell.h"
 #include "jsfriendapi.h"
 #include "jsprvtd.h"
 
 #include "ds/LifoAlloc.h"
 #include "gc/Barrier.h"
 #include "js/HashTable.h"
 
+namespace JS {
+struct TypeInferenceSizes;
+}
+
 namespace js {
 namespace types {
 
 /* Type set entry for either a JSObject with singleton type or a non-singleton TypeObject. */
 struct TypeObjectKey {
     static intptr_t keyBits(TypeObjectKey *obj) { return (intptr_t) obj; }
     static TypeObjectKey *getKey(TypeObjectKey *obj) { return obj; }
 };
@@ -361,17 +365,17 @@ class TypeSet
 
     TypeSet()
         : flags(0), objectSet(NULL), constraintList(NULL)
     {}
 
     void print(JSContext *cx);
 
     inline void sweep(JSContext *cx, JSCompartment *compartment);
-    inline size_t dynamicSize();
+    inline size_t computedSizeOfExcludingThis();
 
     /* Whether this set contains a specific type. */
     inline bool hasType(Type type);
 
     TypeFlags baseFlags() const { return flags & TYPE_FLAG_BASE_MASK; }
     bool unknown() const { return !!(flags & TYPE_FLAG_UNKNOWN); }
     bool unknownObject() const { return !!(flags & (TYPE_FLAG_UNKNOWN | TYPE_FLAG_ANYOBJECT)); }
 
@@ -860,17 +864,19 @@ struct TypeObject : gc::Cell
     void clearNewScript(JSContext *cx);
     void getFromPrototypes(JSContext *cx, jsid id, TypeSet *types, bool force = false);
 
     void print(JSContext *cx);
 
     inline void clearProperties();
     inline void sweep(JSContext *cx);
 
-    inline size_t dynamicSize();
+    inline size_t computedSizeOfExcludingThis();
+
+    void sizeOfExcludingThis(TypeInferenceSizes *sizes, JSMallocSizeOfFun mallocSizeOf);
 
     /*
      * Type objects don't have explicit finalizers. Memory owned by a type
      * object pending deletion is released when weak references are sweeped
      * from all the compartment's type objects.
      */
     void finalize(JSContext *cx, bool background) {}
 
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -1061,16 +1061,17 @@ struct JSObject : js::gc::Cell
     inline const js::Value &getDenseArrayElement(uintN idx);
     inline void setDenseArrayElement(uintN idx, const js::Value &val);
     inline void initDenseArrayElement(uintN idx, const js::Value &val);
     inline void setDenseArrayElementWithType(JSContext *cx, uintN idx, const js::Value &val);
     inline void initDenseArrayElementWithType(JSContext *cx, uintN idx, const js::Value &val);
     inline void copyDenseArrayElements(uintN dstStart, const js::Value *src, uintN count);
     inline void initDenseArrayElements(uintN dstStart, const js::Value *src, uintN count);
     inline void moveDenseArrayElements(uintN dstStart, uintN srcStart, uintN count);
+    inline void moveDenseArrayElementsUnbarriered(uintN dstStart, uintN srcStart, uintN count);
     inline bool denseArrayHasInlineSlots() const;
 
     /* Packed information for this array. */
     inline void markDenseArrayNotPacked(JSContext *cx);
 
     /*
      * ensureDenseArrayElements ensures that the dense array can hold at least
      * index + extra elements. It returns ED_OK on success, ED_FAILED on
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -602,17 +602,17 @@ JSObject::initDenseArrayElements(uintN d
     for (unsigned i = 0; i < count; ++i)
         elements[dstStart + i].init(comp, src[i]);
 }
 
 inline void
 JSObject::moveDenseArrayElements(uintN dstStart, uintN srcStart, uintN count)
 {
     JS_ASSERT(dstStart + count <= getDenseArrayCapacity());
-    JS_ASSERT(srcStart + count <= getDenseArrayCapacity());
+    JS_ASSERT(srcStart + count <= getDenseArrayInitializedLength());
 
     /*
      * Use a custom write barrier here since it's performance sensitive. We
      * only want to barrier the elements that are being overwritten.
      */
     uintN markStart, markEnd;
     if (dstStart > srcStart) {
         markStart = js::Max(srcStart + count, dstStart);
@@ -621,16 +621,23 @@ JSObject::moveDenseArrayElements(uintN d
         markStart = dstStart;
         markEnd = js::Min(dstStart + count, srcStart);
     }
     prepareElementRangeForOverwrite(markStart, markEnd);
 
     memmove(elements + dstStart, elements + srcStart, count * sizeof(js::Value));
 }
 
+inline void
+JSObject::moveDenseArrayElementsUnbarriered(uintN dstStart, uintN srcStart, uintN count)
+{
+    JS_ASSERT(!compartment()->needsBarrier());
+    memmove(elements + dstStart, elements + srcStart, count * sizeof(js::Value));
+}
+
 inline bool
 JSObject::denseArrayHasInlineSlots() const
 {
     JS_ASSERT(isDenseArray());
     return elements == fixedElements();
 }
 
 namespace js {
--- a/js/src/methodjit/PolyIC.cpp
+++ b/js/src/methodjit/PolyIC.cpp
@@ -2602,17 +2602,18 @@ LookupStatus
 GetElementIC::update(VMFrame &f, JSObject *obj, const Value &v, jsid id, Value *vp)
 {
     /*
      * Only treat this as a GETPROP for non-numeric string identifiers. The
      * GETPROP IC assumes the id has already gone through filtering for string
      * indexes in the emitter, i.e. js_GetProtoIfDenseArray is only valid to
      * use when looking up non-integer identifiers.
      */
-    if (v.isString() && js_CheckForStringIndex(id) == id)
+    uint32_t dummy;
+    if (v.isString() && JSID_IS_ATOM(id) && !JSID_TO_ATOM(id)->isIndex(&dummy))
         return attachGetProp(f, obj, v, JSID_TO_ATOM(id)->asPropertyName(), vp);
 
     if (obj->isArguments())
         return attachArguments(f, obj, v, id, vp);
 
 #if defined JS_METHODJIT_TYPED_ARRAY
     /*
      * Typed array ICs can make stub calls, and need to know which registers
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -3883,25 +3883,16 @@ MJitChunkLimit(JSContext *cx, uintN argc
 #ifdef JS_METHODJIT
     mjit::SetChunkLimit((uint32_t) t);
 #endif
 
     vp->setUndefined();
     return true;
 }
 
-JSBool
-StringStats(JSContext *cx, uintN argc, jsval *vp)
-{
-    // XXX: should report something meaningful;  bug 625305 will probably fix
-    // this.
-    JS_SET_RVAL(cx, vp, INT_TO_JSVAL(0));
-    return true;
-}
-
 enum CompartmentKind { SAME_COMPARTMENT, NEW_COMPARTMENT };
 
 static JSObject *
 NewGlobalObject(JSContext *cx, CompartmentKind compartment);
 
 JSBool
 NewGlobal(JSContext *cx, uintN argc, jsval *vp)
 {
@@ -4057,17 +4048,16 @@ static JSFunctionSpec shell_functions[] 
     JS_FN("parent",         Parent,         1,0),
     JS_FN("wrap",           Wrap,           1,0),
     JS_FN("serialize",      Serialize,      1,0),
     JS_FN("deserialize",    Deserialize,    1,0),
 #ifdef JS_METHODJIT
     JS_FN("mjitcodestats",  MJitCodeStats,  0,0),
 #endif
     JS_FN("mjitChunkLimit", MJitChunkLimit, 1,0),
-    JS_FN("stringstats",    StringStats,    0,0),
     JS_FN("newGlobal",      NewGlobal,      1,0),
     JS_FN("parseLegacyJSON",ParseLegacyJSON,1,0),
     JS_FN("enableStackWalkingAssertion",EnableStackWalkingAssertion,1,0),
     JS_FN("getMaxArgs",     GetMaxArgs,     0,0),
     JS_FN("terminate",      Terminate,      0,0),
     JS_FS_END
 };
 
@@ -4206,17 +4196,16 @@ static const char *const shell_help_mess
 "parent(obj)              Returns the parent of obj.",
 "wrap(obj)                Wrap an object into a noop wrapper.",
 "serialize(sd)            Serialize sd using JS_WriteStructuredClone. Returns a TypedArray.",
 "deserialize(a)           Deserialize data generated by serialize.",
 #ifdef JS_METHODJIT
 "mjitcodestats()          Return stats on mjit code memory usage.",
 #endif
 "mjitChunkLimit(N)        Specify limit on compiled chunk size during mjit compilation.",
-"stringstats()            Return stats on string memory usage.",
 "newGlobal(kind)          Return a new global object, in the current\n"
 "                         compartment if kind === 'same-compartment' or in a\n"
 "                         new compartment if kind === 'new-compartment'",
 "parseLegacyJSON(str)     Parse str as legacy JSON, returning the result if the\n"
 "                         parse succeeded and throwing a SyntaxError if not.",
 "enableStackWalkingAssertion(enabled)\n"
 "  Enables or disables a particularly expensive assertion in stack-walking\n"
 "  code.  If your test isn't ridiculously thorough, such that performing this\n"
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_5/extensions/arguments-property-access-in-function.js
@@ -0,0 +1,58 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ * Contributor:
+ *   Jeff Walden <jwalden+code@mit.edu>
+ */
+
+//-----------------------------------------------------------------------------
+var BUGNUMBER = 721322;
+var summary =
+  'f.arguments must trigger an arguments object in non-strict mode functions';
+
+print(BUGNUMBER + ": " + summary);
+
+/**************
+ * BEGIN TEST *
+ **************/
+
+var obj =
+  {
+    test: function()
+    {
+      var args = obj.test.arguments;
+      assertEq(args !== null, true);
+      assertEq(args[0], 5);
+      assertEq(args[1], undefined);
+      assertEq(args.length, 2);
+    }
+  };
+obj.test(5, undefined);
+
+var sobj =
+  {
+    test: function()
+    {
+     "use strict";
+
+      try
+      {
+        var args = sobj.test.arguments;
+        throw new Error("access to arguments property of strict mode " +
+                        "function didn't throw");
+      }
+      catch (e)
+      {
+        assertEq(e instanceof TypeError, true,
+                 "should have thrown TypeError, instead got: " + e);
+      }
+    }
+  };
+sobj.test(5, undefined);
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+  reportCompare(true, true);
+
+print("Tests complete");
--- a/js/src/tests/ecma_5/extensions/jstests.list
+++ b/js/src/tests/ecma_5/extensions/jstests.list
@@ -1,9 +1,10 @@
 url-prefix ../../jsreftest.html?test=ecma_5/extensions/
+script arguments-property-access-in-function.js
 script 8.12.5-01.js
 script 15.4.4.11.js
 script 15.9.4.2.js
 script Boolean-toSource.js
 script Number-toSource.js
 script Object-keys-and-object-ids.js
 script String-toSource.js
 script bug352085.js
new file mode 100644
--- /dev/null
+++ b/js/src/tests/js1_8/genexps/arguments-property-access-in-generator.js
@@ -0,0 +1,27 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ * Contributor:
+ *   Jeff Walden <jwalden+code@mit.edu>
+ */
+
+//-----------------------------------------------------------------------------
+var BUGNUMBER = 721322;
+var summary = 'Allow f.arguments in generator expressions';
+
+print(BUGNUMBER + ": " + summary);
+
+/**************
+ * BEGIN TEST *
+ **************/
+
+eval("(function() { return (f.arguments for (x in [1])); })()");
+eval("(function() { var f = { arguments: 12 }; return [f.arguments for (x in [1])]; })()");
+
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+  reportCompare(true, true);
+
+print("Tests complete");
--- a/js/src/tests/js1_8/genexps/jstests.list
+++ b/js/src/tests/js1_8/genexps/jstests.list
@@ -1,9 +1,10 @@
 url-prefix ../../jsreftest.html?test=js1_8/genexps/
+script arguments-property-access-in-generator.js
 script regress-347739.js
 script regress-349012-01.js
 script regress-349326.js
 script regress-349331.js
 script regress-380237-01.js
 script regress-380237-02.js
 script regress-380237-03.js
 skip script regress-380237-04.js # obsolete test, need to remove minor failures to reenable.
--- a/js/src/vm/String-inl.h
+++ b/js/src/vm/String-inl.h
@@ -244,17 +244,17 @@ JSExternalString::new_(JSContext *cx, co
     JS_ASSERT(chars[length] == 0);
 
     if (!validateLength(cx, length))
         return NULL;
     JSExternalString *str = js_NewGCExternalString(cx);
     if (!str)
         return NULL;
     str->init(chars, length, type, closure);
-    cx->runtime->updateMallocCounter((length + 1) * sizeof(jschar));
+    cx->runtime->updateMallocCounter(cx, (length + 1) * sizeof(jschar));
     return str;
 }
 
 inline bool
 js::StaticStrings::fitsInSmallChar(jschar c)
 {
     return c < SMALL_CHAR_LIMIT && toSmallChar[c] != INVALID_SMALL_CHAR;
 }
--- a/js/xpconnect/shell/xpcshell.cpp
+++ b/js/xpconnect/shell/xpcshell.cpp
@@ -2007,16 +2007,17 @@ main(int argc, char **argv, char **envp)
             JS_ClearScope(cx, glob);
             JS_GC(cx);
             JSContext *oldcx;
             cxstack->Pop(&oldcx);
             NS_ASSERTION(oldcx == cx, "JS thread context push/pop mismatch");
             cxstack = nsnull;
             JS_GC(cx);
         } //this scopes the JSAutoCrossCompartmentCall
+        JS_EndRequest(cx);
         JS_DestroyContext(cx);
     } // this scopes the nsCOMPtrs
 
     if (!XRE_ShutdownTestShell())
         NS_ERROR("problem shutting down testshell");
 
 #ifdef MOZ_CRASHREPORTER
     // Get the crashreporter service while XPCOM is still active.
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -1345,21 +1345,21 @@ ReportMemoryPercentage(const nsACString 
 {
     ReportMemory(path, kind, nsIMemoryReporter::UNITS_PERCENTAGE, amount, desc,
                  callback, closure);
 }
 
 template <int N>
 inline const nsCString
 MakeMemoryReporterPath(const nsACString &pathPrefix,
-                       const JS::CompartmentStats &compartmentStats,
+                       const JS::CompartmentStats &cStats,
                        const char (&reporterName)[N])
 {
   return pathPrefix + NS_LITERAL_CSTRING("compartment(") +
-         *static_cast<nsCString*>(compartmentStats.name) +
+         *static_cast<nsCString*>(cStats.name) +
          NS_LITERAL_CSTRING(")/") + nsDependentCString(reporterName);
 }
 
 } // anonymous namespace
 
 // We have per-compartment GC heap totals, so we can't put the total GC heap
 // size in the explicit allocations tree.  But it's a useful figure, so put it
 // in the "others" list.
@@ -1416,318 +1416,314 @@ NS_MEMORY_REPORTER_IMPLEMENT(XPConnectJS
                              "and 'js-compartments-system' might not match the number of "
                              "compartments listed under 'js' if a garbage collection occurs at an "
                              "inopportune time, but such cases should be rare.")
 
 namespace mozilla {
 namespace xpconnect {
 namespace memory {
 
-#define SLOP_BYTES_STRING \
-    " The measurement includes slop bytes caused by the heap allocator rounding up request sizes."
-
 static PRInt64
-ReportCompartmentStats(const JS::CompartmentStats &stats,
+ReportCompartmentStats(const JS::CompartmentStats &cStats,
                        const nsACString &pathPrefix,
                        nsIMemoryMultiReporterCallback *callback,
                        nsISupports *closure)
 {
     PRInt64 gcTotal = 0;
 
-    ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats,
+    ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
                                               "gc-heap/arena/headers"),
-                       &gcTotal, stats.gcHeapArenaHeaders,
+                       &gcTotal, cStats.gcHeapArenaHeaders,
                        "Memory on the compartment's garbage-collected JavaScript heap, within "
                        "arenas, that is used to hold internal book-keeping information.",
                        callback, closure);
 
-    ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats,
+    ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
                                               "gc-heap/arena/padding"),
-                       &gcTotal, stats.gcHeapArenaPadding,
+                       &gcTotal, cStats.gcHeapArenaPadding,
                        "Memory on the compartment's garbage-collected JavaScript heap, within "
                        "arenas, that is unused and present only so that other data is aligned. "
                        "This constitutes internal fragmentation.",
                        callback, closure);
 
-    ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats,
+    ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
                                               "gc-heap/arena/unused"),
-                       &gcTotal, stats.gcHeapArenaUnused,
+                       &gcTotal, cStats.gcHeapArenaUnused,
                        "Memory on the compartment's garbage-collected JavaScript heap, within "
                        "arenas, that could be holding useful data but currently isn't.",
                        callback, closure);
 
-    ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats,
+    ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
                                               "gc-heap/objects/non-function"),
-                       &gcTotal, stats.gcHeapObjectsNonFunction,
+                       &gcTotal, cStats.gcHeapObjectsNonFunction,
                        "Memory on the compartment's garbage-collected JavaScript heap that holds "
                        "non-function objects.",
                        callback, closure);
 
-    ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats,
+    ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
                                               "gc-heap/objects/function"),
-                       &gcTotal, stats.gcHeapObjectsFunction,
+                       &gcTotal, cStats.gcHeapObjectsFunction,
                        "Memory on the compartment's garbage-collected JavaScript heap that holds "
                        "function objects.",
                        callback, closure);
 
-    ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats,
+    ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
                                               "gc-heap/strings"),
-                       &gcTotal, stats.gcHeapStrings,
+                       &gcTotal, cStats.gcHeapStrings,
                        "Memory on the compartment's garbage-collected JavaScript heap that holds "
                        "string headers.  String headers contain various pieces of information "
                        "about a string, but do not contain (except in the case of very short "
                        "strings) the string characters;  characters in longer strings are counted "
                        "under 'gc-heap/string-chars' instead.",
                        callback, closure);
 
-    ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats,
+    ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
                                               "gc-heap/scripts"),
-                       &gcTotal, stats.gcHeapScripts,
+                       &gcTotal, cStats.gcHeapScripts,
                        "Memory on the compartment's garbage-collected JavaScript heap that holds "
                        "JSScript instances. A JSScript is created for each user-defined function "
                        "in a script. One is also created for the top-level code in a script.",
                        callback, closure);
 
-    ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats,
+    ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
                                               "gc-heap/shapes/tree"),
-                       &gcTotal, stats.gcHeapShapesTree,
+                       &gcTotal, cStats.gcHeapShapesTree,
                        "Memory on the compartment's garbage-collected JavaScript heap that holds "
                        "shapes that are in a property tree.",
                        callback, closure);
 
-    ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats,
+    ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
                                               "gc-heap/shapes/dict"),
-                       &gcTotal, stats.gcHeapShapesDict,
+                       &gcTotal, cStats.gcHeapShapesDict,
                        "Memory on the compartment's garbage-collected JavaScript heap that holds "
                        "shapes that are in dictionary mode.",
                        callback, closure);
 
-    ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats,
+    ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
                                               "gc-heap/shapes/base"),
-                       &gcTotal, stats.gcHeapShapesBase,
+                       &gcTotal, cStats.gcHeapShapesBase,
                        "Memory on the compartment's garbage-collected JavaScript heap that collates "
                        "data common to many shapes.",
                        callback, closure);
 
-    ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats,
+    ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
                                               "gc-heap/type-objects"),
-                       &gcTotal, stats.gcHeapTypeObjects,
+                       &gcTotal, cStats.gcHeapTypeObjects,
                        "Memory on the compartment's garbage-collected JavaScript heap that holds "
                        "type inference information.",
                        callback, closure);
 
-    ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats,
+    ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
                                               "gc-heap/xml"),
-                       &gcTotal, stats.gcHeapXML,
+                       &gcTotal, cStats.gcHeapXML,
                        "Memory on the compartment's garbage-collected JavaScript heap that holds "
                        "E4X XML objects.",
                        callback, closure);
 
-    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats,
+    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
                                               "object-slots"),
-                       nsIMemoryReporter::KIND_HEAP, stats.objectSlots,
+                       nsIMemoryReporter::KIND_HEAP, cStats.objectSlots,
                        "Memory allocated for the compartment's non-fixed object slot arrays, "
                        "which are used to represent object properties.  Some objects also "
                        "contain a fixed number of slots which are stored on the compartment's "
                        "JavaScript heap; those slots are not counted here, but in "
-                       "'gc-heap/objects' instead." SLOP_BYTES_STRING,
+                       "'gc-heap/objects' instead.",
                        callback, closure);
 
-    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats,
+    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
                                               "object-elements"),
-                       nsIMemoryReporter::KIND_HEAP, stats.objectElements,
+                       nsIMemoryReporter::KIND_HEAP, cStats.objectElements,
                        "Memory allocated for the compartment's object element arrays, "
-                       "which are used to represent indexed object properties." SLOP_BYTES_STRING,
+                       "which are used to represent indexed object properties.",
                        callback, closure);
 
-    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats,
+    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
                                               "string-chars"),
-                       nsIMemoryReporter::KIND_HEAP, stats.stringChars,
+                       nsIMemoryReporter::KIND_HEAP, cStats.stringChars,
                        "Memory allocated to hold the compartment's string characters.  Sometimes "
                        "more memory is allocated than necessary, to simplify string "
                        "concatenation.  Each string also includes a header which is stored on the "
                        "compartment's JavaScript heap;  that header is not counted here, but in "
                        "'gc-heap/strings' instead.",
                        callback, closure);
 
-    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats,
+    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
                                               "shapes-extra/tree-tables"),
-                       nsIMemoryReporter::KIND_HEAP, stats.shapesExtraTreeTables,
+                       nsIMemoryReporter::KIND_HEAP, cStats.shapesExtraTreeTables,
                        "Memory allocated for the compartment's property tables that belong to "
-                       "shapes that are in a property tree." SLOP_BYTES_STRING,
+                       "shapes that are in a property tree.",
                        callback, closure);
 
-    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats,
+    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
                                               "shapes-extra/dict-tables"),
-                       nsIMemoryReporter::KIND_HEAP, stats.shapesExtraDictTables,
+                       nsIMemoryReporter::KIND_HEAP, cStats.shapesExtraDictTables,
                        "Memory allocated for the compartment's property tables that belong to "
-                       "shapes that are in dictionary mode." SLOP_BYTES_STRING,
+                       "shapes that are in dictionary mode.",
                        callback, closure);
 
-    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats,
+    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
                                               "shapes-extra/tree-shape-kids"),
-                       nsIMemoryReporter::KIND_HEAP, stats.shapesExtraTreeShapeKids,
+                       nsIMemoryReporter::KIND_HEAP, cStats.shapesExtraTreeShapeKids,
                        "Memory allocated for the compartment's kid hashes that belong to shapes "
                        "that are in a property tree.",
                        callback, closure);
 
-    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats,
+    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
                                               "shapes-extra/compartment-tables"),
-                       nsIMemoryReporter::KIND_HEAP, stats.shapesCompartmentTables,
+                       nsIMemoryReporter::KIND_HEAP, cStats.shapesCompartmentTables,
                        "Memory used by compartment wide tables storing shape information "
                        "for use during object construction.",
                        callback, closure);
 
-    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats,
+    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
                                               "script-data"),
-                       nsIMemoryReporter::KIND_HEAP, stats.scriptData,
+                       nsIMemoryReporter::KIND_HEAP, cStats.scriptData,
                        "Memory allocated for JSScript bytecode and various variable-length "
-                       "tables." SLOP_BYTES_STRING,
+                       "tables.",
                        callback, closure);
 
 #ifdef JS_METHODJIT
-    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats,
+    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
                                               "mjit-code"),
-                       nsIMemoryReporter::KIND_NONHEAP, stats.mjitCode,
+                       nsIMemoryReporter::KIND_NONHEAP, cStats.mjitCode,
                        "Memory used by the method JIT to hold the compartment's generated code.",
                        callback, closure);
 
-    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats,
+    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
                                               "mjit-data"),
-                       nsIMemoryReporter::KIND_HEAP, stats.mjitData,
+                       nsIMemoryReporter::KIND_HEAP, cStats.mjitData,
                        "Memory used by the method JIT for the compartment's compilation data: "
-                       "JITScripts, native maps, and inline cache structs." SLOP_BYTES_STRING,
+                       "JITScripts, native maps, and inline cache structs.",
                        callback, closure);
 #endif
 
-    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats,
+    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
                                               "type-inference/script-main"),
                        nsIMemoryReporter::KIND_HEAP,
-                       stats.typeInferenceMemory.scripts,
+                       cStats.typeInferenceSizes.scripts,
                        "Memory used during type inference to store type sets of variables "
                        "and dynamically observed types.",
                        callback, closure);
 
-    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats,
+    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
                                               "type-inference/object-main"),
                        nsIMemoryReporter::KIND_HEAP,
-                       stats.typeInferenceMemory.objects,
+                       cStats.typeInferenceSizes.objects,
                        "Memory used during type inference to store types and possible "
                        "property types of JS objects.",
                        callback, closure);
 
-    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats,
+    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
                                               "type-inference/tables"),
                        nsIMemoryReporter::KIND_HEAP,
-                       stats.typeInferenceMemory.tables,
+                       cStats.typeInferenceSizes.tables,
                        "Memory used during type inference for compartment-wide tables.",
                        callback, closure);
 
-    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats,
+    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
                                               "analysis-temporary"),
                        nsIMemoryReporter::KIND_HEAP,
-                       stats.typeInferenceMemory.temporary,
+                       cStats.typeInferenceSizes.temporary,
                        "Memory used during type inference and compilation to hold transient "
                        "analysis information.  Cleared on GC.",
                        callback, closure);
 
     return gcTotal;
 }
 
 void
-ReportJSRuntimeStats(const JS::IterateData &data, const nsACString &pathPrefix,
+ReportJSRuntimeStats(const JS::RuntimeStats &rtStats, const nsACString &pathPrefix,
                      nsIMemoryMultiReporterCallback *callback,
                      nsISupports *closure)
 {
     PRInt64 gcTotal = 0;
     for (size_t index = 0;
-         index < data.compartmentStatsVector.length();
+         index < rtStats.compartmentStatsVector.length();
          index++) {
-        gcTotal += ReportCompartmentStats(data.compartmentStatsVector[index], pathPrefix,
+        gcTotal += ReportCompartmentStats(rtStats.compartmentStatsVector[index], pathPrefix,
                                     callback, closure);
     }
 
     ReportMemoryBytes(pathPrefix + NS_LITERAL_CSTRING("runtime/runtime-object"),
-                      nsIMemoryReporter::KIND_HEAP, data.runtimeObject,
-                      "Memory used by the JSRuntime object." SLOP_BYTES_STRING,
+                      nsIMemoryReporter::KIND_HEAP, rtStats.runtimeObject,
+                      "Memory used by the JSRuntime object.",
                       callback, closure);
 
     ReportMemoryBytes(pathPrefix + NS_LITERAL_CSTRING("runtime/atoms-table"),
-                      nsIMemoryReporter::KIND_HEAP, data.runtimeAtomsTable,
-                      "Memory used by the atoms table." SLOP_BYTES_STRING,
+                      nsIMemoryReporter::KIND_HEAP, rtStats.runtimeAtomsTable,
+                      "Memory used by the atoms table.",
                       callback, closure);
 
     ReportMemoryBytes(pathPrefix + NS_LITERAL_CSTRING("runtime/contexts"),
-                      nsIMemoryReporter::KIND_HEAP, data.runtimeContexts,
+                      nsIMemoryReporter::KIND_HEAP, rtStats.runtimeContexts,
                       "Memory used by JSContext objects and certain structures "
-                      "hanging off them."  SLOP_BYTES_STRING,
+                      "hanging off them." ,
                       callback, closure);
 
     ReportMemoryBytes(pathPrefix + NS_LITERAL_CSTRING("runtime/normal"),
-                      nsIMemoryReporter::KIND_HEAP, data.runtimeNormal,
+                      nsIMemoryReporter::KIND_HEAP, rtStats.runtimeNormal,
                       "Memory used by a JSRuntime, "
                       "excluding memory that is reported by "
-                      "other reporters under 'explicit/js/runtime/'." SLOP_BYTES_STRING,
+                      "other reporters under 'explicit/js/runtime/'.",
                       callback, closure);
 
     ReportMemoryBytes(pathPrefix + NS_LITERAL_CSTRING("runtime/temporary"),
-                      nsIMemoryReporter::KIND_HEAP, data.runtimeTemporary,
+                      nsIMemoryReporter::KIND_HEAP, rtStats.runtimeTemporary,
                       "Memory held transiently in JSRuntime and used during "
-                      "compilation.  It mostly holds parse nodes."
-                      SLOP_BYTES_STRING,
+                      "compilation.  It mostly holds parse nodes.",
                       callback, closure);
 
     ReportMemoryBytes0(pathPrefix + NS_LITERAL_CSTRING("runtime/regexp-code"),
-                       nsIMemoryReporter::KIND_NONHEAP, data.runtimeRegexpCode,
+                       nsIMemoryReporter::KIND_NONHEAP, rtStats.runtimeRegexpCode,
                        "Memory used by the regexp JIT to hold generated code.",
                        callback, closure);
 
     ReportMemoryBytes(pathPrefix + NS_LITERAL_CSTRING("runtime/stack-committed"),
-                      nsIMemoryReporter::KIND_NONHEAP, data.runtimeStackCommitted,
+                      nsIMemoryReporter::KIND_NONHEAP, rtStats.runtimeStackCommitted,
                       "Memory used for the JS call stack.  This is the committed portion "
                       "of the stack; the uncommitted portion is not measured because it "
                       "hardly costs anything.",
                       callback, closure);
 
     ReportGCHeapBytes(pathPrefix +
                       NS_LITERAL_CSTRING("gc-heap-chunk-dirty-unused"),
-                      &gcTotal, data.gcHeapChunkDirtyUnused,
+                      &gcTotal, rtStats.gcHeapChunkDirtyUnused,
                       "Memory on the garbage-collected JavaScript heap, within chunks with at "
                       "least one allocated GC thing, that could be holding useful data but "
                       "currently isn't.  Memory here is mutually exclusive with memory reported"
                       "under 'explicit/js/gc-heap-decommitted'.",
                       callback, closure);
 
     ReportGCHeapBytes(pathPrefix +
                       NS_LITERAL_CSTRING("gc-heap-chunk-clean-unused"),
-                      &gcTotal, data.gcHeapChunkCleanUnused,
+                      &gcTotal, rtStats.gcHeapChunkCleanUnused,
                       "Memory on the garbage-collected JavaScript heap taken by completely empty "
                       "chunks, that soon will be released unless claimed for new allocations.  "
                       "Memory here is mutually exclusive with memory reported under "
                       "'explicit/js/gc-heap-decommitted'.",
                       callback, closure);
 
     ReportGCHeapBytes(pathPrefix +
                       NS_LITERAL_CSTRING("gc-heap-decommitted"),
                       &gcTotal,
-                      data.gcHeapChunkCleanDecommitted + data.gcHeapChunkDirtyDecommitted,
+                      rtStats.gcHeapChunkCleanDecommitted + rtStats.gcHeapChunkDirtyDecommitted,
                       "Memory in the address space of the garbage-collected JavaScript heap that "
                       "is currently returned to the OS.",
                       callback, closure);
 
     ReportGCHeapBytes(pathPrefix +
                       NS_LITERAL_CSTRING("gc-heap-chunk-admin"),
-                      &gcTotal, data.gcHeapChunkAdmin,
+                      &gcTotal, rtStats.gcHeapChunkAdmin,
                       "Memory on the garbage-collected JavaScript heap, within chunks, that is "
                       "used to hold internal book-keeping information.",
                       callback, closure);
 
     // gcTotal is the sum of everything we've reported for the GC heap.  It
-    // should equal data.gcHeapChunkTotal.
-    JS_ASSERT(gcTotal == data.gcHeapChunkTotal);
+    // should equal rtStats.gcHeapChunkTotal.
+    JS_ASSERT(gcTotal == rtStats.gcHeapChunkTotal);
 }
 
 } // namespace memory
 } // namespace xpconnect
 } // namespace mozilla
 
 class XPConnectJSCompartmentsMultiReporter : public nsIMemoryMultiReporter
 {
@@ -1739,119 +1735,119 @@ public:
     {
         XPCJSRuntime *xpcrt = nsXPConnect::GetRuntimeInstance();
 
         // In the first step we get all the stats and stash them in a local
         // data structure.  In the second step we pass all the stashed stats to
         // the callback.  Separating these steps is important because the
         // callback may be a JS function, and executing JS while getting these
         // stats seems like a bad idea.
-        JS::IterateData data(xpc::JsMallocSizeOf, xpc::GetCompartmentName,
-                             xpc::DestroyCompartmentName);
-        if (!JS::CollectCompartmentStatsForRuntime(xpcrt->GetJSRuntime(), &data))
+        JS::RuntimeStats rtStats(xpc::JsMallocSizeOf, xpc::GetCompartmentName,
+                                 xpc::DestroyCompartmentName);
+        if (!JS::CollectRuntimeStats(xpcrt->GetJSRuntime(), &rtStats))
             return NS_ERROR_FAILURE;
 
-        uint64_t xpconnect;
+        size_t xpconnect;
         {
             xpconnect =
                 xpcrt->SizeOfIncludingThis(xpc::JsMallocSizeOf) +
                 XPCWrappedNativeScope::SizeOfAllScopesIncludingThis(xpc::JsMallocSizeOf);
         }
 
         NS_NAMED_LITERAL_CSTRING(pathPrefix, "explicit/js/");
 
         // This is the second step (see above).
-        ReportJSRuntimeStats(data, pathPrefix, callback, closure);
+        ReportJSRuntimeStats(rtStats, pathPrefix, callback, closure);
 
         ReportMemoryBytes(pathPrefix + NS_LITERAL_CSTRING("xpconnect"),
                           nsIMemoryReporter::KIND_HEAP, xpconnect,
-                          "Memory used by XPConnect." SLOP_BYTES_STRING,
+                          "Memory used by XPConnect.",
                           callback, closure);
 
         ReportMemoryBytes(NS_LITERAL_CSTRING("js-gc-heap-chunk-dirty-unused"),
                           nsIMemoryReporter::KIND_OTHER,
-                          data.gcHeapChunkDirtyUnused,
+                          rtStats.gcHeapChunkDirtyUnused,
                           "The same as 'explicit/js/gc-heap-chunk-dirty-unused'.  Shown here for "
                           "easy comparison with other 'js-gc' reporters.",
                           callback, closure);
 
         ReportMemoryBytes(NS_LITERAL_CSTRING("js-gc-heap-chunk-clean-unused"),
                           nsIMemoryReporter::KIND_OTHER,
-                          data.gcHeapChunkCleanUnused,
+                          rtStats.gcHeapChunkCleanUnused,
                           "The same as 'explicit/js/gc-heap-chunk-clean-unused'.  Shown here for "
                           "easy comparison with other 'js-gc' reporters.",
                           callback, closure);
 
         ReportMemoryBytes(NS_LITERAL_CSTRING("js-gc-heap-decommitted"),
                           nsIMemoryReporter::KIND_OTHER,
-                          data.gcHeapChunkCleanDecommitted + data.gcHeapChunkDirtyDecommitted,
+                          rtStats.gcHeapChunkCleanDecommitted + rtStats.gcHeapChunkDirtyDecommitted,
                           "The same as 'explicit/js/gc-heap-decommitted'.  Shown here for "
                           "easy comparison with other 'js-gc' reporters.",
                           callback, closure);
 
         ReportMemoryBytes(NS_LITERAL_CSTRING("js-gc-heap-arena-unused"),
                           nsIMemoryReporter::KIND_OTHER,
-                          data.gcHeapArenaUnused,
+                          rtStats.gcHeapArenaUnused,
                           "Memory on the garbage-collected JavaScript heap, within arenas, that "
                           "could be holding useful data but currently isn't.  This is the sum of "
                           "all compartments' 'gc-heap/arena-unused' numbers.",
                           callback, closure);
 
         ReportMemoryPercentage(NS_LITERAL_CSTRING("js-gc-heap-unused-fraction"),
                                nsIMemoryReporter::KIND_OTHER,
-                               data.gcHeapUnusedPercentage,
+                               rtStats.gcHeapUnusedPercentage,
                                "Fraction of the garbage-collected JavaScript heap that is unused. "
                                "Computed as ('js-gc-heap-chunk-clean-unused' + "
                                "'js-gc-heap-chunk-dirty-unused' + 'js-gc-heap-decommitted' + "
                                "'js-gc-heap-arena-unused') / 'js-gc-heap'.",
                                callback, closure);
 
         ReportMemoryBytes(NS_LITERAL_CSTRING("js-total-objects"),
-                          nsIMemoryReporter::KIND_OTHER, data.totalObjects,
+                          nsIMemoryReporter::KIND_OTHER, rtStats.totalObjects,
                           "Memory used for all object-related data.  This is the sum of all "
                           "compartments' 'gc-heap/objects-non-function', "
                           "'gc-heap/objects-function' and 'object-slots' numbers.",
                           callback, closure);
 
         ReportMemoryBytes(NS_LITERAL_CSTRING("js-total-shapes"),
-                          nsIMemoryReporter::KIND_OTHER, data.totalShapes,
+                          nsIMemoryReporter::KIND_OTHER, rtStats.totalShapes,
                           "Memory used for all shape-related data.  This is the sum of all "
                           "compartments' 'gc-heap/shapes/tree', 'gc-heap/shapes/dict', "
                           "'gc-heap/shapes/base', "
                           "'shapes-extra/tree-tables', 'shapes-extra/dict-tables', "
                           "'shapes-extra/tree-shape-kids' and 'shapes-extra/empty-shape-arrays'.",
                           callback, closure);
 
         ReportMemoryBytes(NS_LITERAL_CSTRING("js-total-scripts"),
-                          nsIMemoryReporter::KIND_OTHER, data.totalScripts,
+                          nsIMemoryReporter::KIND_OTHER, rtStats.totalScripts,
                           "Memory used for all script-related data.  This is the sum of all "
                           "compartments' 'gc-heap/scripts' and 'script-data' numbers.",
                           callback, closure);
 
         ReportMemoryBytes(NS_LITERAL_CSTRING("js-total-strings"),
-                          nsIMemoryReporter::KIND_OTHER, data.totalStrings,
+                          nsIMemoryReporter::KIND_OTHER, rtStats.totalStrings,
                           "Memory used for all string-related data.  This is the sum of all "
                           "compartments' 'gc-heap/strings' and 'string-chars' numbers.",
                           callback, closure);
 #ifdef JS_METHODJIT
         ReportMemoryBytes(NS_LITERAL_CSTRING("js-total-mjit"),
-                          nsIMemoryReporter::KIND_OTHER, data.totalMjit,
+                          nsIMemoryReporter::KIND_OTHER, rtStats.totalMjit,
                           "Memory used by the method JIT.  This is the sum of all compartments' "
                           "'mjit-code', and 'mjit-data' numbers.",
                           callback, closure);
 #endif
         ReportMemoryBytes(NS_LITERAL_CSTRING("js-total-type-inference"),
-                          nsIMemoryReporter::KIND_OTHER, data.totalTypeInference,
+                          nsIMemoryReporter::KIND_OTHER, rtStats.totalTypeInference,
                           "Non-transient memory used by type inference.  This is the sum of all "
                           "compartments' 'gc-heap/type-objects', 'type-inference/script-main', "
                           "'type-inference/object-main' and 'type-inference/tables' numbers.",
                           callback, closure);
 
         ReportMemoryBytes(NS_LITERAL_CSTRING("js-total-analysis-temporary"),
-                          nsIMemoryReporter::KIND_OTHER, data.totalAnalysisTemp,
+                          nsIMemoryReporter::KIND_OTHER, rtStats.totalAnalysisTemp,
                           "Memory used transiently during type inference and compilation. "
                           "This is the sum of all compartments' 'analysis-temporary' numbers.",
                           callback, closure);
 
         return NS_OK;
     }
 
     NS_IMETHOD
--- a/js/xpconnect/src/xpcpublic.h
+++ b/js/xpconnect/src/xpcpublic.h
@@ -225,17 +225,17 @@ size_t JsMallocSizeOf(const void *ptr);
 
 class nsIMemoryMultiReporterCallback;
 
 namespace mozilla {
 namespace xpconnect {
 namespace memory {
 
 void
-ReportJSRuntimeStats(const JS::IterateData &data, const nsACString &pathPrefix,
+ReportJSRuntimeStats(const JS::RuntimeStats &rtStats, const nsACString &pathPrefix,
                      nsIMemoryMultiReporterCallback *callback,
                      nsISupports *closure);
 
 } // namespace memory
 } // namespace xpconnect
 
 namespace dom {
 namespace binding {
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -4799,12 +4799,23 @@ nsLayoutUtils::FontSizeInflationFor(cons
   return FontSizeInflationInner(aFrame,
                                 InflationMinFontSizeFor(aFrame,
                                                         aWidthDetermination));
 }
 
 /* static */ bool
 nsLayoutUtils::FontSizeInflationEnabled(nsPresContext *aPresContext)
 {
-  return (sFontSizeInflationEmPerLine != 0 ||
-          sFontSizeInflationMinTwips != 0) &&
-         !aPresContext->IsChrome();
+  if ((sFontSizeInflationEmPerLine == 0 &&
+       sFontSizeInflationMinTwips == 0) ||
+       aPresContext->IsChrome()) {
+    return false;
+  }
+
+  ViewportInfo vInf =
+    nsContentUtils::GetViewportInfo(aPresContext->PresShell()->GetDocument());
+
+  if (vInf.defaultZoom >= 1.0 || vInf.autoSize) {
+    return false;
+  }
+
+  return true;
 }
new file mode 100644
--- /dev/null
+++ b/layout/base/tests/font-inflation/disable-fontinfl-on-mobile-2.html
@@ -0,0 +1,20 @@
+<!--
+Without the patch for bug 706198, this website should not show up as inflated. That means
+that with a 450px container, the minimum font size with 15em per line should be 30px.
+So, we map 0px-45px into 30px-45px, and thus 12px gets mapped to 34px.
+
+With the patch, the text should be uninflated, which means that 12px should still be
+12px.
+-->
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta content='True' name='HandheldFriendly' />
+    <style>
+      p { font-size: 12px; line-height: 1.0;}
+    </style>
+    <body>
+      <p>Some uninflated text.</p>
+    </body>
+  </head>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/base/tests/font-inflation/disable-fontinfl-on-mobile-3.html
@@ -0,0 +1,20 @@
+<!--
+Without the patch for bug 706198, this website should not show up as inflated. That means
+that with a 450px container, the minimum font size with 15em per line should be 30px.
+So, we map 0px-45px into 30px-45px, and thus 12px gets mapped to 34px.
+
+With the patch, the text should be uninflated, which means that 12px should still be
+12px.
+-->
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0' name='viewport' />
+    <style>
+      p { font-size: 12px; line-height: 1.0;}
+    </style>
+    <body>
+      <p>Some uninflated text.</p>
+    </body>
+  </head>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/base/tests/font-inflation/disable-fontinfl-on-mobile-4.html
@@ -0,0 +1,20 @@
+<!--
+Without the patch for bug 706198, this website should not show up as inflated. That means
+that with a 450px container, the minimum font size with 15em per line should be 30px.
+So, we map 0px-45px into 30px-45px, and thus 12px gets mapped to 34px.
+
+With the patch, the text should be uninflated, which means that 12px should still be
+12px.
+-->
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta name="viewport" content="width=320"/>
+    <style>
+      p { font-size: 12px; line-height: 1.0;}
+    </style>
+    <body>
+      <p>Some uninflated text.</p>
+    </body>
+  </head>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/base/tests/font-inflation/disable-fontinfl-on-mobile-ref.html
@@ -0,0 +1,19 @@
+<!--
+Without the patch for bug 706198, this website should not show up as inflated. That means
+that with a 450px container, the minimum font size with 15em per line should be 30px.
+So, we map 0px-45px into 30px-45px, and thus 12px gets mapped to 34px.
+
+With the patch, the text should be uninflated, which means that 12px should still be
+12px.
+-->
+<!DOCTYPE html>
+<html>
+  <head>
+    <style>
+      p { font-size: 12px; line-height: 1.0;}
+    </style>
+    <body>
+      <p>Some uninflated text.</p>
+    </body>
+  </head>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/base/tests/font-inflation/disable-fontinfl-on-mobile.html
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.0//EN" "http://www.wapforum.org/DTD/xhtml-mobile10.dtd">
+
+<!--
+Without the patch for bug 706198, this website should not show up as inflated. That means
+that with a 450px container, the minimum font size with 15em per line should be 30px.
+So, we map 0px-45px into 30px-45px, and thus 12px gets mapped to 34px.
+
+With the patch, the text should be uninflated, which means that 12px should still be
+12px.
+-->
+<html>
+  <head>
+    <style>
+      p { font-size: 12px; line-height: 1.0;}
+    </style>
+    <body>
+      <p>Some uninflated text.</p>
+    </body>
+  </head>
+</html>
--- a/layout/base/tests/test_font_inflation_reftests.html
+++ b/layout/base/tests/test_font_inflation_reftests.html
@@ -56,16 +56,20 @@ var gTests = [
   "== select-combobox-1.html select-combobox-1-ref.html",
   "!= select-combobox-1.html select-combobox-1.html",
   "== select-listbox-2.html select-listbox-2-ref.html",
   "!= select-listbox-2.html select-listbox-2.html",
   "== select-combobox-2.html select-combobox-2-ref.html",
   "!= select-combobox-2.html select-combobox-2.html",
   "!= input-checkbox.html input-checkbox.html",
   "!= input-radio.html input-radio.html",
+  "== disable-fontinfl-on-mobile.html disable-fontinfl-on-mobile-ref.html",
+  "== disable-fontinfl-on-mobile-2.html disable-fontinfl-on-mobile-ref.html",
+  "== disable-fontinfl-on-mobile-3.html disable-fontinfl-on-mobile-ref.html",
+  "== disable-fontinfl-on-mobile-4.html disable-fontinfl-on-mobile-ref.html",
 ];
 
 // Maintain a reference count of how many things we're waiting for until
 // we can say the tests are done.
 var gDelayCount = 0;
 function AddFinishDependency()
   { ++gDelayCount; }
 function RemoveFinishDependency()
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -1007,17 +1007,17 @@ nsBlockFrame::Reflow(nsPresContext*     
     AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
   }
 
   nsresult rv = NS_OK;
 
   // ALWAYS drain overflow. We never want to leave the previnflow's
   // overflow lines hanging around; block reflow depends on the
   // overflow line lists being cleared out between reflow passes.
-  DrainOverflowLines(state);
+  DrainOverflowLines();
 
   // Handle paginated overflow (see nsContainerFrame.h)
   nsOverflowAreas ocBounds;
   nsReflowStatus ocStatus = NS_FRAME_COMPLETE;
   if (GetPrevInFlow()) {
     ReflowOverflowContainerChildren(aPresContext, *reflowState, ocBounds, 0,
                                     ocStatus);
   }
@@ -4434,17 +4434,17 @@ nsBlockFrame::PushLines(nsBlockReflowSta
 #endif
 }
 
 // The overflowLines property is stored as a pointer to a line list,
 // which must be deleted.  However, the following functions all maintain
 // the invariant that the property is never set if the list is empty.
 
 bool
-nsBlockFrame::DrainOverflowLines(nsBlockReflowState& aState)
+nsBlockFrame::DrainOverflowLines()
 {
 #ifdef DEBUG
   VerifyOverflowSituation();
 #endif
   nsLineList* overflowLines = nsnull;
   nsLineList* ourOverflowLines = nsnull;
 
   // First grab the prev-in-flows overflow lines
--- a/layout/generic/nsBlockFrame.h
+++ b/layout/generic/nsBlockFrame.h
@@ -447,17 +447,17 @@ public:
                                nsFloatManager& aFloatManager);
 
 protected:
 
   /** grab overflow lines from this block's prevInFlow, and make them
     * part of this block's mLines list.
     * @return true if any lines were drained.
     */
-  bool DrainOverflowLines(nsBlockReflowState& aState);
+  bool DrainOverflowLines();
 
   /** grab pushed floats from this block's prevInFlow, and splice
     * them into this block's mFloats list.
     */
   void DrainPushedFloats(nsBlockReflowState& aState);
 
   /** Load all our floats into the float manager (without reflowing them).
    *  Assumes float manager is in our own coordinate system.
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1634,19 +1634,19 @@ fails-if(Android) == 625409-1.html 62540
 == 630835-1.html about:blank
 == 631352-1.html 631352-1-ref.html
 fails-if(Android) == 632423-1.html 632423-1-ref.html
 skip-if(Android) == 632781-verybig.html 632781-ref.html
 == 632781-normalsize.html 632781-ref.html
 == 633344-1.html 633344-1-ref.html
 fails-if(Android) == 634232-1.html 634232-1-ref.html
 fails-if(Android) == 635302-1.html 635302-1-ref.html
-== 635373-1.html 635373-1-ref.html
-== 635373-2.html 635373-2-ref.html
-== 635373-3.html 635373-3-ref.html
+random-if(d2d) == 635373-1.html 635373-1-ref.html
+random-if(d2d) == 635373-2.html 635373-2-ref.html
+random-if(d2d) == 635373-3.html 635373-3-ref.html
 HTTP(..) == 635639-1.html 635639-1-ref.html
 HTTP(..) == 635639-2.html 635639-2-ref.html
 random == 637597-1.html 637597-1-ref.html # bug 637597 was never really fixed!
 == 637852-1.html 637852-1-ref.html
 == 637852-2.html 637852-2-ref.html
 == 637852-3.html 637852-3-ref.html
 == 641770-1.html 641770-1-ref.html
 == 641856-1.html 641856-1-ref.html
--- a/mobile/android/app/mobile.js
+++ b/mobile/android/app/mobile.js
@@ -213,26 +213,28 @@ pref("extensions.update.enabled", false)
 pref("extensions.update.interval", 86400);
 pref("extensions.dss.enabled", false);
 pref("extensions.dss.switchPending", false);
 pref("extensions.ignoreMTimeChanges", false);
 pref("extensions.logging.enabled", false);
 pref("extensions.hideInstallButton", true);
 pref("extensions.showMismatchUI", false);
 pref("extensions.hideUpdateButton", false);
+pref("extensions.strictCompatibility", false);
+pref("extensions.minCompatibleAppVersion", "11.0");
 
-pref("extensions.update.url", "https://versioncheck.addons.mozilla.org/update/VersionCheck.php?reqVersion=%REQ_VERSION%&id=%ITEM_ID%&version=%ITEM_VERSION%&maxAppVersion=%ITEM_MAXAPPVERSION%&status=%ITEM_STATUS%&appID=%APP_ID%&appVersion=%APP_VERSION%&appOS=%APP_OS%&appABI=%APP_ABI%&locale=%APP_LOCALE%&currentAppVersion=%CURRENT_APP_VERSION%&updateType=%UPDATE_TYPE%");
+pref("extensions.update.url", "https://versioncheck.addons.mozilla.org/update/VersionCheck.php?reqVersion=%REQ_VERSION%&id=%ITEM_ID%&version=%ITEM_VERSION%&maxAppVersion=%ITEM_MAXAPPVERSION%&status=%ITEM_STATUS%&appID=%APP_ID%&appVersion=%APP_VERSION%&appOS=%APP_OS%&appABI=%APP_ABI%&locale=%APP_LOCALE%&currentAppVersion=%CURRENT_APP_VERSION%&updateType=%UPDATE_TYPE%&compatMode=%COMPATIBILITY_MODE%");
 
 /* preferences for the Get Add-ons pane */
 pref("extensions.getAddons.cache.enabled", true);
 pref("extensions.getAddons.maxResults", 15);
 pref("extensions.getAddons.recommended.browseURL", "https://addons.mozilla.org/%LOCALE%/mobile/recommended/");
 pref("extensions.getAddons.recommended.url", "https://services.addons.mozilla.org/%LOCALE%/mobile/api/%API_VERSION%/list/featured/all/%MAX_RESULTS%/%OS%/%VERSION%");
 pref("extensions.getAddons.search.browseURL", "https://addons.mozilla.org/%LOCALE%/mobile/search?q=%TERMS%");
-pref("extensions.getAddons.search.url", "https://services.addons.mozilla.org/%LOCALE%/mobile/api/%API_VERSION%/search/%TERMS%/all/%MAX_RESULTS%/%OS%/%VERSION%");
+pref("extensions.getAddons.search.url", "https://services.addons.mozilla.org/%LOCALE%/mobile/api/%API_VERSION%/search/%TERMS%/all/%MAX_RESULTS%/%OS%/%VERSION%/%COMPATIBILITY_MODE%");
 pref("extensions.getAddons.browseAddons", "https://addons.mozilla.org/%LOCALE%/mobile/");
 pref("extensions.getAddons.get.url", "https://services.addons.mozilla.org/%LOCALE%/mobile/api/%API_VERSION%/search/guid:%IDS%?src=mobile&appOS=%OS%&appVersion=%VERSION%&tMain=%TIME_MAIN%&tFirstPaint=%TIME_FIRST_PAINT%&tSessionRestored=%TIME_SESSION_RESTORED%");
 
 /* preference for the locale picker */
 pref("extensions.getLocales.get.url", "");
 pref("extensions.compatability.locales.buildid", "0");
 
 /* blocklist preferences */
--- a/mobile/android/base/BrowserToolbar.java
+++ b/mobile/android/base/BrowserToolbar.java
@@ -312,9 +312,21 @@ public class BrowserToolbar extends Line
     public void setSecurityMode(String mode) {
         if (mode.equals("identified"))
             mSiteSecurity.setImageLevel(1);
         else if (mode.equals("verified"))
             mSiteSecurity.setImageLevel(2);
         else
             mSiteSecurity.setImageLevel(0);
     }
+
+    public void refresh() {
+        Tab tab = Tabs.getInstance().getSelectedTab();
+        if (tab != null) {
+            setTitle(tab.getDisplayTitle());
+            setFavicon(tab.getFavicon());
+            setSecurityMode(tab.getSecurityMode());
+            setProgressVisibility(tab.isLoading());
+            setShadowVisibility(!(tab.getURL().startsWith("about:")));
+            updateTabs(Tabs.getInstance().getCount());
+        }
+    }
 }
--- a/mobile/android/base/GeckoApp.java
+++ b/mobile/android/base/GeckoApp.java
@@ -578,36 +578,36 @@ abstract public class GeckoApp
                 if (getLayerController().getLayerClient() != mSoftwareLayerClient)
                     return;
 
                 ViewportMetrics viewportMetrics = mSoftwareLayerClient.getGeckoViewportMetrics();
                 if (viewportMetrics != null)
                     mLastViewport = viewportMetrics.toJSON();
 
                 mLastTitle = lastHistoryEntry.mTitle;
-                getAndProcessThumbnailForTab(tab);
+                getAndProcessThumbnailForTab(tab, true);
             }
         }
     }
 
-    void getAndProcessThumbnailForTab(final Tab tab) {
+    void getAndProcessThumbnailForTab(final Tab tab, boolean forceBigSceenshot) {
         boolean isSelectedTab = Tabs.getInstance().isSelectedTab(tab);
         final Bitmap bitmap = isSelectedTab ?
             mSoftwareLayerClient.getBitmap() : null;
         
         if (bitmap != null) {
             ByteArrayOutputStream bos = new ByteArrayOutputStream();
             bitmap.compress(Bitmap.CompressFormat.PNG, 0, bos);
             processThumbnail(tab, bitmap, bos.toByteArray());
         } else {
             mLastScreen = null;
-            int sw = isSelectedTab ? mSoftwareLayerClient.getWidth() : tab.getMinScreenshotWidth();
-            int sh = isSelectedTab ? mSoftwareLayerClient.getHeight(): tab.getMinScreenshotHeight();
-            int dw = isSelectedTab ? sw : tab.getThumbnailWidth();
-            int dh = isSelectedTab ? sh : tab.getThumbnailHeight();
+            int sw = forceBigSceenshot ? mSoftwareLayerClient.getWidth() : tab.getMinScreenshotWidth();
+            int sh = forceBigSceenshot ? mSoftwareLayerClient.getHeight(): tab.getMinScreenshotHeight();
+            int dw = forceBigSceenshot ? sw : tab.getThumbnailWidth();
+            int dh = forceBigSceenshot ? sh : tab.getThumbnailHeight();
             try {
                 JSONObject message = new JSONObject();
                 message.put("tabID", tab.getId());
 
                 JSONObject source = new JSONObject();
                 source.put("width", sw);
                 source.put("height", sh);
                 message.put("source", source);
@@ -1066,16 +1066,27 @@ abstract public class GeckoApp
                     mMainHandler.post(new Runnable() {
                         public void run() {
                             sMenu.findItem(R.id.char_encoding).setVisible(visible);
                         }
                     });
                 }
             } else if (event.equals("Update:Restart")) {
                 doRestart("org.mozilla.gecko.restart_update");
+            } else if (event.equals("Tab:HasTouchListener")) {
+                int tabId = message.getInt("tabID");
+                Tab tab = Tabs.getInstance().getTab(tabId);
+                tab.setHasTouchListeners(true);
+                if (Tabs.getInstance().isSelectedTab(tab)) {
+                    mMainHandler.post(new Runnable() {
+                        public void run() {
+                            mLayerController.setWaitForTouchListeners(true);
+                        }
+                    });
+                }
             }
         } catch (Exception e) {
             Log.e(LOGTAG, "Exception handling message \"" + event + "\":", e);
         }
     }
 
     public void showAboutHome() {
         Runnable r = new AboutHomeRunnable(true);
@@ -1441,16 +1452,30 @@ abstract public class GeckoApp
                 // Hide/show the system notification bar
                 getWindow().setFlags(fullscreen ?
                                      WindowManager.LayoutParams.FLAG_FULLSCREEN : 0,
                                      WindowManager.LayoutParams.FLAG_FULLSCREEN);
             }
         });
     }
 
+    // The ActionBar needs to be refreshed on rotation as different orientation uses different resources
+    public void refreshActionBar() {
+        if (Build.VERSION.SDK_INT >= 11) {
+            mBrowserToolbar = (BrowserToolbar) getLayoutInflater().inflate(R.layout.browser_toolbar, null);
+            mBrowserToolbar.refresh();
+            GeckoActionBar.setBackgroundDrawable(this, getResources().getDrawable(R.drawable.gecko_actionbar_bg));
+            GeckoActionBar.setDisplayOptions(this, ActionBar.DISPLAY_SHOW_CUSTOM, ActionBar.DISPLAY_SHOW_CUSTOM |
+                                                                                  ActionBar.DISPLAY_SHOW_HOME |
+                                                                                  ActionBar.DISPLAY_SHOW_TITLE |
+                                                                                  ActionBar.DISPLAY_USE_LOGO);
+            GeckoActionBar.setCustomView(this, mBrowserToolbar);
+        }
+    }
+
     /** Called when the activity is first created. */
     @Override
     public void onCreate(Bundle savedInstanceState)
     {
         mAppContext = this;
 
         // StrictMode is set by defaults resource flag |enableStrictMode|.
         if (getResources().getBoolean(R.bool.enableStrictMode)) {
@@ -1526,24 +1551,17 @@ abstract public class GeckoApp
 
         super.onCreate(savedInstanceState);
 
         setContentView(R.layout.gecko_app);
 
         mOrientation = getResources().getConfiguration().orientation;
 
         if (Build.VERSION.SDK_INT >= 11) {
-            mBrowserToolbar = (BrowserToolbar) getLayoutInflater().inflate(R.layout.browser_toolbar, null);
-
-            GeckoActionBar.setBackgroundDrawable(this, getResources().getDrawable(R.drawable.gecko_actionbar_bg));
-            GeckoActionBar.setDisplayOptions(this, ActionBar.DISPLAY_SHOW_CUSTOM, ActionBar.DISPLAY_SHOW_CUSTOM |
-                                                                                  ActionBar.DISPLAY_SHOW_HOME |
-                                                                                  ActionBar.DISPLAY_SHOW_TITLE |
-                                                                                  ActionBar.DISPLAY_USE_LOGO);
-            GeckoActionBar.setCustomView(this, mBrowserToolbar);
+            refreshActionBar();
         } else {
             mBrowserToolbar = (BrowserToolbar) findViewById(R.id.browser_toolbar);
         }
 
         mBrowserToolbar.setTitle(mLastTitle);
 
         mFavicons = new Favicons(this);
 
@@ -1634,16 +1652,17 @@ abstract public class GeckoApp
         GeckoAppShell.registerGeckoEventListener("ToggleChrome:Hide", GeckoApp.mAppContext);
         GeckoAppShell.registerGeckoEventListener("ToggleChrome:Show", GeckoApp.mAppContext);
         GeckoAppShell.registerGeckoEventListener("FormAssist:AutoComplete", GeckoApp.mAppContext);
         GeckoAppShell.registerGeckoEventListener("Permissions:Data", GeckoApp.mAppContext);
         GeckoAppShell.registerGeckoEventListener("Downloads:Done", GeckoApp.mAppContext);
         GeckoAppShell.registerGeckoEventListener("CharEncoding:Data", GeckoApp.mAppContext);
         GeckoAppShell.registerGeckoEventListener("CharEncoding:State", GeckoApp.mAppContext);
         GeckoAppShell.registerGeckoEventListener("Update:Restart", GeckoApp.mAppContext);
+        GeckoAppShell.registerGeckoEventListener("Tab:HasTouchListener", GeckoApp.mAppContext);
 
         mConnectivityFilter = new IntentFilter();
         mConnectivityFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
         mConnectivityReceiver = new GeckoConnectivityReceiver();
 
         IntentFilter batteryFilter = new IntentFilter();
         batteryFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
         mBatteryReceiver = new GeckoBatteryManager();
@@ -1894,16 +1913,23 @@ abstract public class GeckoApp
     {
         Log.i(LOGTAG, "resume");
         if (checkLaunchState(LaunchState.GeckoRunning))
             GeckoAppShell.onResume();
         // After an onPause, the activity is back in the foreground.
         // Undo whatever we did in onPause.
         super.onResume();
 
+        int newOrientation = getResources().getConfiguration().orientation;
+
+        if (mOrientation != newOrientation) {
+            mOrientation = newOrientation;
+            refreshActionBar();
+        }
+
         // Just in case. Normally we start in onNewIntent
         if (checkLaunchState(LaunchState.Launching))
             onNewIntent(getIntent());
 
         registerReceiver(mConnectivityReceiver, mConnectivityFilter);
         GeckoNetworkManager.getInstance().start();
 
         if (mOwnActivityDepth > 0)
@@ -1973,16 +1999,17 @@ abstract public class GeckoApp
         GeckoAppShell.unregisterGeckoEventListener("Toast:Show", GeckoApp.mAppContext);
         GeckoAppShell.unregisterGeckoEventListener("ToggleChrome:Hide", GeckoApp.mAppContext);
         GeckoAppShell.unregisterGeckoEventListener("ToggleChrome:Show", GeckoApp.mAppContext);
         GeckoAppShell.unregisterGeckoEventListener("FormAssist:AutoComplete", GeckoApp.mAppContext);
         GeckoAppShell.unregisterGeckoEventListener("Permissions:Data", GeckoApp.mAppContext);
         GeckoAppShell.unregisterGeckoEventListener("Downloads:Done", GeckoApp.mAppContext);
         GeckoAppShell.unregisterGeckoEventListener("CharEncoding:Data", GeckoApp.mAppContext);
         GeckoAppShell.unregisterGeckoEventListener("CharEncoding:State", GeckoApp.mAppContext);
+        GeckoAppShell.unregisterGeckoEventListener("Tab:HasTouchListener", GeckoApp.mAppContext);
 
         mFavicons.close();
 
         if (SmsManager.getInstance() != null) {
             SmsManager.getInstance().stop();
             if (isFinishing())
                 SmsManager.getInstance().shutdown();
         }
@@ -2007,33 +2034,17 @@ abstract public class GeckoApp
     {
         Log.i(LOGTAG, "configuration changed");
 
         super.onConfigurationChanged(newConfig);
 
         if (mOrientation != newConfig.orientation) {
             mOrientation = newConfig.orientation;
             mAutoCompletePopup.hide();
-
-            if (Build.VERSION.SDK_INT >= 11) {
-                mBrowserToolbar = (BrowserToolbar) getLayoutInflater().inflate(R.layout.browser_toolbar, null);
-
-                Tab tab = Tabs.getInstance().getSelectedTab();
-                if (tab != null) {
-                    mBrowserToolbar.setTitle(tab.getDisplayTitle());
-                    mBrowserToolbar.setFavicon(tab.getFavicon());
-                    mBrowserToolbar.setSecurityMode(tab.getSecurityMode());
-                    mBrowserToolbar.setProgressVisibility(tab.isLoading());
-                    mBrowserToolbar.setShadowVisibility(!(tab.getURL().startsWith("about:")));
-                    mBrowserToolbar.updateTabs(Tabs.getInstance().getCount());
-                }
-
-                GeckoActionBar.setBackgroundDrawable(this, getResources().getDrawable(R.drawable.gecko_actionbar_bg));
-                GeckoActionBar.setCustomView(mAppContext, mBrowserToolbar);
-            }
+            refreshActionBar();
         }
     }
 
     @Override
     public void onLowMemory()
     {
         Log.e(LOGTAG, "low memory");
         if (checkLaunchState(LaunchState.GeckoRunning))
--- a/mobile/android/base/GeckoAppShell.java
+++ b/mobile/android/base/GeckoAppShell.java
@@ -1142,38 +1142,44 @@ public class GeckoAppShell
         ConnectivityManager cm = (ConnectivityManager)
             GeckoApp.mAppContext.getSystemService(Context.CONNECTIVITY_SERVICE);
         if (cm.getActiveNetworkInfo() == null)
             return false;
         return true;
     }
 
     public static void setSelectedLocale(String localeCode) {
-        /* We're not using this, not need to save it (see bug 635342)
-          SharedPreferences settings =
+        /* Bug 713464: This method is still called from Gecko side.
+           Earlier we had an option to run Firefox in a language other than system's language.
+           However, this is not supported as of now.
+           Gecko resets the locale to en-US by calling this function with an empty string.
+           This affects GeckoPreferences activity in multi-locale builds.
+
+        //We're not using this, not need to save it (see bug 635342)
+        SharedPreferences settings =
             GeckoApp.mAppContext.getPreferences(Activity.MODE_PRIVATE);
         settings.edit().putString(GeckoApp.mAppContext.getPackageName() + ".locale",
                                   localeCode).commit();
-        */
         Locale locale;
         int index;
         if ((index = localeCode.indexOf('-')) != -1 ||
             (index = localeCode.indexOf('_')) != -1) {
             String langCode = localeCode.substring(0, index);
             String countryCode = localeCode.substring(index + 1);
             locale = new Locale(langCode, countryCode);
         } else {
             locale = new Locale(localeCode);
         }
         Locale.setDefault(locale);
 
         Resources res = GeckoApp.mAppContext.getBaseContext().getResources();
         Configuration config = res.getConfiguration();
         config.locale = locale;
         res.updateConfiguration(config, res.getDisplayMetrics());
+        */
     }
 
     public static int[] getSystemColors() {
         // attrsAppearance[] must correspond to AndroidSystemColors structure in android/AndroidBridge.h
         final int[] attrsAppearance = {
             android.R.attr.textColor,
             android.R.attr.textColorPrimary,
             android.R.attr.textColorPrimaryInverse,
--- a/mobile/android/base/Tabs.java
+++ b/mobile/android/base/Tabs.java
@@ -288,14 +288,14 @@ public class Tabs implements GeckoEventL
     }
 
     public void refreshThumbnails() {
         Iterator<Tab> iterator = tabs.values().iterator();
         while (iterator.hasNext()) {
             final Tab tab = iterator.next();
             GeckoAppShell.getHandler().post(new Runnable() {
                 public void run() {
-                    GeckoApp.mAppContext.getAndProcessThumbnailForTab(tab);
+                    GeckoApp.mAppContext.getAndProcessThumbnailForTab(tab, false);
                 }
             });
         }
     }
 }
--- a/mobile/android/base/gfx/GeckoSoftwareLayerClient.java
+++ b/mobile/android/base/gfx/GeckoSoftwareLayerClient.java
@@ -107,16 +107,19 @@ public class GeckoSoftwareLayerClient ex
 
     // mUpdateViewportOnEndDraw is used to indicate that we received a
     // viewport update notification while drawing. therefore, when the
     // draw finishes, we need to update the entire viewport rather than
     // just the page size. this boolean should always be accessed from
     // inside a transaction, so no synchronization is needed.
     private boolean mUpdateViewportOnEndDraw;
 
+    /* Used by robocop for testing purposes */
+    private DrawListener mDrawListener;
+
     private static Pattern sColorPattern;
 
     public GeckoSoftwareLayerClient(Context context) {
         mContext = context;
 
         mScreenSize = new IntSize(0, 0);
         mBufferSize = new IntSize(0, 0);
         mFormat = CairoImage.FORMAT_RGB16_565;
@@ -320,16 +323,21 @@ public class GeckoSoftwareLayerClient ex
                     ((MultiTileLayer)mTileLayer).invalidate(rect);
                     ((MultiTileLayer)mTileLayer).setRenderOffset(mRenderOffset);
                 }
             } finally {
                 endTransaction(mTileLayer);
             }
         }
         Log.i(LOGTAG, "zerdatime " + SystemClock.uptimeMillis() + " - endDrawing");
+
+        /* Used by robocop for testing purposes */
+        if (mDrawListener != null) {
+            mDrawListener.drawFinished(x, y, width, height);
+        }
     }
 
     public ViewportMetrics getGeckoViewportMetrics() {
         // Return a copy, as we modify this inside the Gecko thread
         if (mGeckoViewport != null)
             return new ViewportMetrics(mGeckoViewport);
         return null;
     }
@@ -531,10 +539,20 @@ public class GeckoSoftwareLayerClient ex
             return Color.WHITE;
         }
 
         int r = Integer.parseInt(matcher.group(1));
         int g = Integer.parseInt(matcher.group(2));
         int b = Integer.parseInt(matcher.group(3));
         return Color.rgb(r, g, b);
     }
+
+    /** Used by robocop for testing purposes. Not for production use! This is called via reflection by robocop. */
+    public void setDrawListener(DrawListener listener) {
+        mDrawListener = listener;
+    }
+
+    /** Used by robocop for testing purposes. Not for production use! This is used via reflection by robocop. */
+    public interface DrawListener {
+        public void drawFinished(int x, int y, int width, int height);
+    }
 }
 
--- a/mobile/android/base/gfx/LayerController.java
+++ b/mobile/android/base/gfx/LayerController.java
@@ -239,17 +239,23 @@ public class LayerController {
         if (mViewportMetrics.getPageSize().fuzzyEquals(size))
             return;
 
         mViewportMetrics.setPageSize(size);
         Log.d(LOGTAG, "setPageSize: " + mViewportMetrics);
 
         // Page size is owned by the LayerClient, so no need to notify it of
         // this change.
-        mView.requestRender();
+
+        mView.post(new Runnable() {
+            public void run() {
+                mPanZoomController.pageSizeUpdated();
+                mView.requestRender();
+            }
+        });
     }
 
     /**
      * Sets the entire viewport metrics at once. This function does not notify the layer client or
      * the pan/zoom controller, so you will need to call notifyLayerClientOfGeometryChange() or
      * notifyPanZoomControllerOfGeometryChange() after calling this. You must hold the monitor
      * while calling this.
      */
--- a/mobile/android/base/gfx/LayerRenderer.java
+++ b/mobile/android/base/gfx/LayerRenderer.java
@@ -56,17 +56,17 @@ import android.graphics.Rect;
 import android.graphics.RectF;
 import android.opengl.GLSurfaceView;
 import android.os.SystemClock;
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.view.WindowManager;
 import javax.microedition.khronos.egl.EGLConfig;
 import javax.microedition.khronos.opengles.GL10;
-import java.nio.ByteBuffer;
+import java.nio.IntBuffer;
 
 /**
  * The layer renderer implements the rendering logic for a layer view.
  */
 public class LayerRenderer implements GLSurfaceView.Renderer {
     private static final String LOGTAG = "GeckoLayerRenderer";
 
     /*
@@ -90,16 +90,19 @@ public class LayerRenderer implements GL
     private RenderContext mLastPageContext;
     private int mMaxTextureSize;
 
     // Dropped frames display
     private int[] mFrameTimings;
     private int mCurrentFrame, mFrameTimingsSum, mDroppedFrames;
     private boolean mShowFrameRate;
 
+    /* Used by robocop for testing purposes */
+    private IntBuffer mPixelBuffer;
+
     public LayerRenderer(LayerView view) {
         mView = view;
 
         LayerController controller = view.getController();
 
         CairoImage backgroundImage = new BufferedCairoImage(controller.getBackgroundPattern());
         mBackgroundLayer = new SingleTileLayer(true, backgroundImage);
         mBackgroundLayer.beginTransaction(null);
@@ -241,16 +244,41 @@ public class LayerRenderer implements GL
             }
         }
 
         // If a layer update requires further work, schedule another redraw
         if (!updated)
             mView.requestRender();
 
         PanningPerfAPI.recordFrameTime();
+
+        /* Used by robocop for testing purposes */
+        IntBuffer pixelBuffer = mPixelBuffer;
+        if (updated && pixelBuffer != null) {
+            synchronized (pixelBuffer) {
+                pixelBuffer.position(0);
+                gl.glReadPixels(0, 0, (int)screenContext.viewport.width(), (int)screenContext.viewport.height(), GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, pixelBuffer);
+                pixelBuffer.notify();
+            }
+        }
+    }
+
+    /** Used by robocop for testing purposes. Not for production use! */
+    IntBuffer getPixels() {
+        IntBuffer pixelBuffer = IntBuffer.allocate(mView.getWidth() * mView.getHeight());
+        synchronized (pixelBuffer) {
+            mPixelBuffer = pixelBuffer;
+            mView.requestRender();
+            try {
+                pixelBuffer.wait();
+            } catch (InterruptedException ie) {
+            }
+            mPixelBuffer = null;
+        }
+        return pixelBuffer;
     }
 
     private 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);
--- a/mobile/android/base/gfx/LayerView.java
+++ b/mobile/android/base/gfx/LayerView.java
@@ -47,16 +47,17 @@ import org.mozilla.gecko.ui.SimpleScaleG
 import android.content.Context;
 import android.opengl.GLSurfaceView;
 import android.view.GestureDetector;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnection;
 import android.util.Log;
+import java.nio.IntBuffer;
 import java.util.LinkedList;
 
 import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
 
 /**
  * A view rendered by the layer compositor.
@@ -232,10 +233,15 @@ public class LayerView extends GLSurface
             mRenderTimeReset = false;
             return System.nanoTime() - mRenderTime;
         }
     }
 
     public int getMaxTextureSize() {
         return mRenderer.getMaxTextureSize();
     }
+
+    /** Used by robocop for testing purposes. Not for production use! This is called via reflection by robocop. */
+    public IntBuffer getPixels() {
+        return mRenderer.getPixels();
+    }
 }
 
--- a/mobile/android/base/resources/drawable/address_bar_bg.xml
+++ b/mobile/android/base/resources/drawable/address_bar_bg.xml
@@ -1,11 +1,11 @@
 <?xml version="1.0" encoding="utf-8"?>
 <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
 
     <item android:right="34dp">
         <bitmap xmlns:android="http://schemas.android.com/apk/res/android"
             android:src="@drawable/address_bar_texture"
-            android:tileMode="mirror"
+            android:tileMode="repeat"
             android:dither="false"/>
      </item>
 
 </layer-list>
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/tests/robocop_boxes.html
@@ -0,0 +1,17 @@
+<html style="margin: 0; padding: 0">
+<title>Browser Box test</title>
+<body style="margin: 0; padding: 0">
+<script type="text/javascript">
+for (var y = 0; y < 2000; y += 100) {
+    document.write("<div style='width: 2000px; height: 100px; margin: 0; padding: 0; border: none'>\n");
+    for (var x = 0; x < 2000; x += 100) {
+        var r = (y + x) % 255;
+        var g = 255 - (y / 10);
+        var b = 255 - (x / 10);
+        document.write("<div style='float: left; width: 100px; height: 100px; margin: 0; padding: 0; border: none; background-color: rgb(" + r + "," + g + "," + b + ")'> </div>\n");
+    }
+    document.write("</div>\n");
+}
+</script>
+</body>
+</html>
--- a/mobile/android/base/tests/testLoad.java.in
+++ b/mobile/android/base/tests/testLoad.java.in
@@ -1,13 +1,23 @@
 #filter substitution
 package @ANDROID_PACKAGE_NAME@.tests;
 
 import @ANDROID_PACKAGE_NAME@.*;
 
 public class testLoad extends BaseTest {
-    private static final String URL = "http://mochi.test:8888/tests/robocop/robocop_blank_03.html";
+    private static final String URL = "http://mochi.test:8888/tests/robocop/robocop_boxes.html";
 
     public void testLoad() {
         loadUrl(URL);
+
+        mActions.expectPaint().blockForEvent();
+        getInstrumentation().waitForIdleSync();
+
+        int[][] painted = mDriver.getPaintedSurface();
+        mAsserter.ispixel(painted[0][0], 0, 255, 255, "Pixel at 0, 0");
+        mAsserter.ispixel(painted[0][100], 100, 255, 245, "Pixel at 100, 0");
+        mAsserter.ispixel(painted[100][0], 100, 245, 255, "Pixel at 0, 100");
+        mAsserter.ispixel(painted[100][100], 200, 245, 245, "Pixel at 100, 100");
+
         verifyUrl(URL);
     }
 }
--- a/mobile/android/base/ui/Axis.java
+++ b/mobile/android/base/ui/Axis.java
@@ -180,17 +180,22 @@ abstract class Axis {
     }
 
     /*
      * Returns the resistance, as a multiplier, that should be taken into account when
      * tracking or pinching.
      */
     float getEdgeResistance() {
         float excess = getExcess();
-        return (excess > 0.0f) ? SNAP_LIMIT - excess / getViewportLength() : 1.0f;
+        if (excess > 0.0f) {
+            // excess can be greater than viewport length, but the resistance
+            // must never drop below 0.0
+            return Math.max(0.0f, SNAP_LIMIT - excess / getViewportLength());
+        }
+        return 1.0f;
     }
 
     /* Returns the velocity. If the axis is locked, returns 0. */
     float getRealVelocity() {
         return (mLocked || !scrollable()) ? 0.0f : mVelocity;
     }
 
     void startPan() {
--- a/mobile/android/base/ui/PanZoomController.java
+++ b/mobile/android/base/ui/PanZoomController.java
@@ -229,16 +229,29 @@ public class PanZoomController
             // Don't do animations here; they're distracting and can cause flashes on page
             // transitions.
             mController.setViewportMetrics(getValidViewportMetrics());
             mController.notifyLayerClientOfGeometryChange();
             break;
         }
     }
 
+    /** This must be called on the UI thread. */
+    public void pageSizeUpdated() {
+        if (mState == PanZoomState.NOTHING) {
+            ViewportMetrics validated = getValidViewportMetrics();
+            if (! mController.getViewportMetrics().fuzzyEquals(validated)) {
+                // page size changed such that we are now in overscroll. snap to the
+                // the nearest valid viewport
+                mController.setViewportMetrics(validated);
+                mController.notifyLayerClientOfGeometryChange();
+            }
+        }
+    }
+
     /*
      * Panning/scrolling
      */
 
     private boolean onTouchStart(MotionEvent event) {
         Log.d(LOGTAG, "onTouchStart in state " + mState);
         // user is taking control of movement, so stop
         // any auto-movement we have going
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -304,26 +304,26 @@ var BrowserApp = {
       }
 
       // Be ready to handle any restore failures by making sure we have a valid tab opened
       let restoreCleanup = {
         observe: function(aSubject, aTopic, aData) {
           Services.obs.removeObserver(restoreCleanup, "sessionstore-windows-restored");
           if (aData == "fail") {
             let params = { selected: restoreToFront };
-            BrowserApp.addTab("about:home");
+            BrowserApp.addTab("about:home", { showProgress: false });
           }
         }
       };
       Services.obs.addObserver(restoreCleanup, "sessionstore-windows-restored", false);
 
       // Start the restore
       ss.restoreLastSession(restoreToFront, forceRestore);
     } else {
-      this.addTab(url);
+      this.addTab(url, { showProgress: url != "about:home" });
 
       // show telemetry door hanger if we aren't restoring a session
       this._showTelemetryPrompt();
     }
 
     // notify java that gecko has loaded
     sendMessageToJava({
       gecko: {
@@ -464,21 +464,22 @@ var BrowserApp = {
         };
         sendMessageToJava(message);
         dump("Handled load error: " + e)
       }
     }
   },
 
   addTab: function addTab(aURI, aParams) {
-    aParams = aParams || { selected: true, flags: Ci.nsIWebNavigation.LOAD_FLAGS_NONE };
+    aParams = aParams || {};
+
     let newTab = new Tab(aURI, aParams);
     this._tabs.push(newTab);
-    if ("selected" in aParams && aParams.selected)
-      newTab.active = true;
+
+    newTab.active = "selected" in aParams ? aParams.selected : true;
 
     let evt = document.createEvent("UIEvents");
     evt.initUIEvent("TabOpen", true, false, window, null);
     newTab.browser.dispatchEvent(evt);
 
     return newTab;
   },
 
@@ -765,17 +766,17 @@ var BrowserApp = {
     else {
       let pref = Cc["@mozilla.org/pref-localizedstring;1"].createInstance(Ci.nsIPrefLocalizedString);
       pref.data = json.value;
       Services.prefs.setComplexValue(json.name, Ci.nsISupportsString, pref);
     }
   },
 
   getSearchEngines: function() {
-    let engineData = Services.search.getEngines({});
+    let engineData = Services.search.getVisibleEngines({});
     let searchEngines = engineData.map(function (engine) {
       return {
         name: engine.name,
         iconURI: engine.iconURI.spec
       };
     });
 
     sendMessageToJava({
@@ -1406,17 +1407,17 @@ function Tab(aURL, aParams) {
   this._pluginOverlayShowing = false;
 }
 
 Tab.prototype = {
   create: function(aURL, aParams) {
     if (this.browser)
       return;
 
-    aParams = aParams || { selected: true };
+    aParams = aParams || {};
 
     this.vbox = document.createElement("vbox");
     this.vbox.align = "start";
     BrowserApp.deck.appendChild(this.vbox);
 
     this.browser = document.createElement("browser");
     this.browser.setAttribute("type", "content");
     this.setBrowserSize(980, 480);
--- a/mobile/android/themes/core/touchcontrols.css
+++ b/mobile/android/themes/core/touchcontrols.css
@@ -43,16 +43,21 @@
 .muteButton {
   background: url("chrome://browser/skin/images/mute-hdpi.png") no-repeat center;
 }
 
 .muteButton[muted="true"] {
   background: url("chrome://browser/skin/images/unmute-hdpi.png") no-repeat center;
 }
 
+/* This button is hidden until bug 704229 is fixed. */
+.fullscreenButton {
+  display: none;
+}
+
 /* bars */
 .scrubberStack {
   width: 100%;
   min-height: 32px;
   max-height: 32px;
   padding: 0px 8px;
   margin: 0px;
 }
--- a/mobile/xul/app/mobile.js
+++ b/mobile/xul/app/mobile.js
@@ -207,26 +207,28 @@ pref("extensions.update.enabled", false)
 pref("extensions.update.interval", 86400);
 pref("extensions.dss.enabled", false);
 pref("extensions.dss.switchPending", false);
 pref("extensions.ignoreMTimeChanges", false);
 pref("extensions.logging.enabled", false);
 pref("extensions.hideInstallButton", true);
 pref("extensions.showMismatchUI", false);
 pref("extensions.hideUpdateButton", false);
+pref("extensions.strictCompatibility", false);
+pref("extensions.minCompatibleAppVersion", "4.0");
 
-pref("extensions.update.url", "https://versioncheck.addons.mozilla.org/update/VersionCheck.php?reqVersion=%REQ_VERSION%&id=%ITEM_ID%&version=%ITEM_VERSION%&maxAppVersion=%ITEM_MAXAPPVERSION%&status=%ITEM_STATUS%&appID=%APP_ID%&appVersion=%APP_VERSION%&appOS=%APP_OS%&appABI=%APP_ABI%&locale=%APP_LOCALE%&currentAppVersion=%CURRENT_APP_VERSION%&updateType=%UPDATE_TYPE%");
+pref("extensions.update.url", "https://versioncheck.addons.mozilla.org/update/VersionCheck.php?reqVersion=%REQ_VERSION%&id=%ITEM_ID%&version=%ITEM_VERSION%&maxAppVersion=%ITEM_MAXAPPVERSION%&status=%ITEM_STATUS%&appID=%APP_ID%&appVersion=%APP_VERSION%&appOS=%APP_OS%&appABI=%APP_ABI%&locale=%APP_LOCALE%&currentAppVersion=%CURRENT_APP_VERSION%&updateType=%UPDATE_TYPE%&compatMode=%COMPATIBILITY_MODE%");
 
 /* preferences for the Get Add-ons pane */
 pref("extensions.getAddons.cache.enabled", true);
 pref("extensions.getAddons.maxResults", 15);
 pref("extensions.getAddons.recommended.browseURL", "https://addons.mozilla.org/%LOCALE%/mobile/recommended/");
 pref("extensions.getAddons.recommended.url", "https://services.addons.mozilla.org/%LOCALE%/mobile/api/%API_VERSION%/list/featured/all/%MAX_RESULTS%/%OS%/%VERSION%");
 pref("extensions.getAddons.search.browseURL", "https://addons.mozilla.org/%LOCALE%/mobile/search?q=%TERMS%");
-pref("extensions.getAddons.search.url", "https://services.addons.mozilla.org/%LOCALE%/mobile/api/%API_VERSION%/search/%TERMS%/all/%MAX_RESULTS%/%OS%/%VERSION%");
+pref("extensions.getAddons.search.url", "https://services.addons.mozilla.org/%LOCALE%/mobile/api/%API_VERSION%/search/%TERMS%/all/%MAX_RESULTS%/%OS%/%VERSION%/%COMPATIBILITY_MODE%");
 pref("extensions.getAddons.browseAddons", "https://addons.mozilla.org/%LOCALE%/mobile/");
 pref("extensions.getAddons.get.url", "https://services.addons.mozilla.org/%LOCALE%/mobile/api/%API_VERSION%/search/guid:%IDS%?src=mobile&appOS=%OS%&appVersion=%VERSION%&tMain=%TIME_MAIN%&tFirstPaint=%TIME_FIRST_PAINT%&tSessionRestored=%TIME_SESSION_RESTORED%");
 
 /* preference for the locale picker */
 pref("extensions.getLocales.get.url", "");
 pref("extensions.compatability.locales.buildid", "0");
 
 /* blocklist preferences */
--- a/testing/mochitest/runtestsremote.py
+++ b/testing/mochitest/runtestsremote.py
@@ -112,16 +112,21 @@ class RemoteOptions(MochitestOptions):
                     help = "name of the .ini file containing the list of tests to run")
         defaults["robocop"] = ""
 
         self.add_option("--robocop-path", action = "store",
                     type = "string", dest = "robocopPath",
                     help = "Path to the folder where robocop.apk is located at.  Primarily used for ADB test running")
         defaults["robocopPath"] = ""
 
+        self.add_option("--robocop-ids", action = "store",
+                    type = "string", dest = "robocopIds",
+                    help = "name of the file containing the view ID map (fennec_ids.txt)")
+        defaults["robocopIds"] = ""
+
         defaults["remoteTestRoot"] = None
         defaults["logFile"] = "mochitest.log"
         defaults["autorun"] = True
         defaults["closeWhenDone"] = True
         defaults["testPath"] = ""
         defaults["app"] = None
 
         self.set_defaults(**defaults)
@@ -183,16 +188,22 @@ class RemoteOptions(MochitestOptions):
             options.robocop = os.path.abspath(options.robocop)
 
         if options.robocopPath != "":
             if not os.path.exists(os.path.join(options.robocopPath, 'robocop.apk')):
                 print "ERROR: Unable to find robocop.apk in path '%s'" % options.robocopPath
                 return None
             options.robocopPath = os.path.abspath(options.robocopPath)
 
+        if options.robocopIds != "":
+            if not os.path.exists(options.robocopIds):
+                print "ERROR: Unable to find specified IDs file '%s'" % options.robocopIds
+                return None
+            options.robocopIds = os.path.abspath(options.robocopIds)
+
         return options
 
     def verifyOptions(self, options, mochitest):
         # since we are reusing verifyOptions, it will exit if App is not found
         temp = options.app
         options.app = sys.argv[0]
         tempPort = options.httpPort
         tempSSL = options.sslPort
@@ -387,18 +398,18 @@ def main():
         fHandle.close()
         deviceRoot = dm.getDeviceRoot()
       
         # Note, we are pushing to /sdcard since we have this location hard coded in robocop
         dm.removeFile("/sdcard/fennec_ids.txt")
         dm.removeFile("/sdcard/robotium.config")
         dm.pushFile("robotium.config", "/sdcard/robotium.config")
         fennec_ids = os.path.abspath("fennec_ids.txt")
-        if not os.path.exists(fennec_ids) and options.robocopPath:
-            fennec_ids = os.path.abspath(os.path.join(options.robocopPath, "fennec_ids.txt"))
+        if not os.path.exists(fennec_ids) and options.robocopIds:
+            fennec_ids = options.robocopIds
         dm.pushFile(fennec_ids, "/sdcard/fennec_ids.txt")
         options.extraPrefs.append('robocop.logfile="%s/robocop.log"' % deviceRoot)
 
         if (options.dm_trans == 'adb' and options.robocopPath):
           dm.checkCmd(["install", "-r", os.path.join(options.robocopPath, "robocop.apk")])
 
         appname = options.app
         retVal = None
--- a/testing/mochitest/tests/browser/Makefile.in
+++ b/testing/mochitest/tests/browser/Makefile.in
@@ -49,22 +49,22 @@ include $(topsrcdir)/config/rules.mk
 	                  browser_head.js \
 	                  browser_pass.js \
 	                  browser_async.js \
 	                  browser_privileges.js \
 	                  browser_popupNode.js \
 	                  browser_popupNode_check.js \
 			  browser_sanityException.js \
 			  browser_sanityException2.js \
+			  $(NULL)
 # Disabled, these are only good for testing the harness' failure reporting
 #	                  browser_zz_fail_openwindow.js \
 #	                  browser_fail.js \
 #	                  browser_fail_async_throw.js \
 #	                  browser_fail_fp.js \
 #	                  browser_fail_pf.js \
 #	                  browser_fail_throw.js \
 #	                  browser_fail_timeout.js \
 # Disabled because it would take too long, useful to check functionality though.
 #	                  browser_requestLongerTimeout.js \
-	                  $(NULL)
 
 libs:: $(_BROWSER_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
--- a/testing/testsuite-targets.mk
+++ b/testing/testsuite-targets.mk
@@ -71,17 +71,18 @@ RUN_MOCHITEST_REMOTE = \
 	rm -f ./$@.log && \
 	$(PYTHON) _tests/testing/mochitest/runtestsremote.py --autorun --close-when-done \
 	  --console-level=INFO --log-file=./$@.log --file-level=INFO $(DM_FLAGS) --dm_trans=$(DM_TRANS) \
 	  --app=$(TEST_PACKAGE_NAME) --deviceIP=${TEST_DEVICE} --xre-path=${MOZ_HOST_BIN} \
 	  $(SYMBOLS_PATH) $(TEST_PATH_ARG) $(EXTRA_TEST_ARGS)
 
 RUN_MOCHITEST_ROBOTIUM = \
   rm -f ./$@.log && \
-  $(PYTHON) _tests/testing/mochitest/runtestsremote.py --robocop-path=$(DEPTH)/build/mobile/robocop \
+  $(PYTHON) _tests/testing/mochitest/runtestsremote.py --robocop-path=$(DEPTH)/dist \
+    --robocop-ids=$(DEPTH)/build/mobile/robocop/fennec_ids.txt \
     --console-level=INFO --log-file=./$@.log --file-level=INFO $(DM_FLAGS) --dm_trans=adb \
     --app=$(TEST_PACKAGE_NAME) --deviceIP=${TEST_DEVICE} --xre-path=${MOZ_HOST_BIN} \
     --robocop=$(DEPTH)/build/mobile/robocop/robocop.ini $(SYMBOLS_PATH) $(TEST_PATH_ARG) $(EXTRA_TEST_ARGS)
 
 ifndef NO_FAIL_ON_TEST_ERRORS
 define CHECK_TEST_ERROR
   @errors=`grep "TEST-UNEXPECTED-" $@.log` ;\
   if test "$$errors" ; then \
--- a/toolkit/components/telemetry/Telemetry.cpp
+++ b/toolkit/components/telemetry/Telemetry.cpp
@@ -1123,16 +1123,22 @@ Accumulate(ID aHistogram, PRUint32 aSamp
 
 void
 AccumulateTimeDelta(ID aHistogram, TimeStamp start, TimeStamp end)
 {
   Accumulate(aHistogram,
              static_cast<PRUint32>((end - start).ToMilliseconds()));
 }
 
+bool
+CanRecord()
+{
+  return TelemetryImpl::CanRecord();
+}
+
 base::Histogram*
 GetHistogramById(ID id)
 {
   Histogram *h = NULL;
   GetHistogramByEnumId(id, &h);
   return h;
 }
 
--- a/toolkit/components/telemetry/Telemetry.h
+++ b/toolkit/components/telemetry/Telemetry.h
@@ -128,16 +128,23 @@ public:
   }
 
 private:
   PRUint32 counter;
   MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
 /**
+ * Indicates whether Telemetry recording is turned on.  This is intended
+ * to guard calls to Accumulate when the statistic being recorded is
+ * expensive to compute.
+ */
+bool CanRecord();
+
+/**
  * Records slow SQL statements for Telemetry reporting.
  * For privacy reasons, only prepared statements are reported.
  *
  * @param statement - offending SQL statement to record
  * @param dbName - DB filename; reporting is only done for whitelisted DBs
  * @param delay - execution time in milliseconds
  */
 void RecordSlowSQLStatement(const nsACString &statement,
--- a/toolkit/components/telemetry/TelemetryHistograms.h
+++ b/toolkit/components/telemetry/TelemetryHistograms.h
@@ -319,16 +319,17 @@ HISTOGRAM(XUL_REFLOW_MS, 1, 3000, 10, EX
 HISTOGRAM(HTML_REFLOW_MS, 1, 3000, 10, EXPONENTIAL, "HTML reflows (ms)")
 HISTOGRAM(XUL_INITIAL_FRAME_CONSTRUCTION, 1, 3000, 10, EXPONENTIAL, "initial xul frame construction")
 HISTOGRAM_BOOLEAN(XMLHTTPREQUEST_ASYNC_OR_SYNC, "Type of XMLHttpRequest, async or sync")
 
 /**
  * DOM telemetry.
  */
 HISTOGRAM(DOM_TIMERS_FIRED_PER_NATIVE_TIMEOUT, 1, 3000, 10, EXPONENTIAL, "DOM: Timer handlers called per native timer expiration")
+HISTOGRAM(DOM_TIMERS_RECENTLY_SET, 1, 3000, 10, EXPONENTIAL, "DOM: setTimeout/setInterval calls recently (last 30s or more)")
 
 /**
  * DOM Storage telemetry.
  */
 #define DOMSTORAGE_HISTOGRAM(PREFIX, TYPE, TYPESTRING, DESCRIPTION) \
   HISTOGRAM(PREFIX ## DOMSTORAGE_ ## TYPE ## _SIZE_BYTES, \
             1024, 32768, 10, EXPONENTIAL, "DOM storage: size of " TYPESTRING "s stored in " DESCRIPTION "Storage")
 #define DOMSTORAGE_KEY_VAL_SIZE(PREFIX, DESCRIPTION) \
--- a/widget/android/AndroidGraphicBuffer.cpp
+++ b/widget/android/AndroidGraphicBuffer.cpp
@@ -450,19 +450,29 @@ AndroidGraphicBuffer::Bind()
     return false;
   }
 
   clearGLError();
   sGLFunctions.fImageTargetTexture2DOES(GL_TEXTURE_2D, mEGLImage);
   return ensureNoGLError("glEGLImageTargetTexture2DOES");
 }
 
-static const char* sAllowedBoards[] = {
-  "venus2", // Motorola Droid Pro
-  "tuna", // Galaxy Nexus
+static const char* const sAllowedBoards[] = {
+  "venus2",     // Motorola Droid Pro
+  "tuna",       // Galaxy Nexus
+  "omap4sdp",   // Amazon Kindle Fire
+  "droid2",     // Motorola Droid 2
+  "targa",      // Motorola Droid Bionic
+  "spyder",     // Motorola Razr
+  "shadow",     // Motorola Droid X
+  "SGH-I897",   // Samsung Galaxy S
+  "GT-I9100",   // Samsung Galaxy SII
+  "sgh-i997",   // Samsung Infuse 4G
+  "herring",    // Samsung Nexus S
+  "sgh-t839",   // Samsung Sidekick 4G
   NULL
 };
 
 bool
 AndroidGraphicBuffer::IsBlacklisted()
 {
   nsAutoString board;
   if (!AndroidBridge::Bridge()->GetStaticStringField("android/os/Build", "BOARD", board))
@@ -475,16 +485,17 @@ AndroidGraphicBuffer::IsBlacklisted()
     return false;
   }
 
   if (Preferences::GetBool("direct-texture.force.disabled", false)) {
     LOG("disallowing board '%s' due to prefs override", boardUtf8);
     return true;
   }
 
+  // FIXME: (Bug 722605) use something better than a linear search
   for (int i = 0; sAllowedBoards[i]; i++) {
     if (board.Find(sAllowedBoards[i]) >= 0) {
       LOG("allowing board '%s' based on '%s'\n", boardUtf8, sAllowedBoards[i]);
       return false;
     }
   }
 
   LOG("disallowing board: %s\n", boardUtf8);
--- a/widget/android/Makefile.in
+++ b/widget/android/Makefile.in
@@ -50,16 +50,20 @@ IS_COMPONENT    = 1
 MODULE_NAME     = nsWidgetAndroidModule
 GRE_MODULE      = 1
 LIBXUL_LIBRARY  = 1
 
 ifdef MOZ_JAVA_COMPOSITOR
 DEFINES += -DMOZ_JAVA_COMPOSITOR
 endif
 
+ifdef MOZ_ONLY_TOUCH_EVENTS
+DEFINES += -DMOZ_ONLY_TOUCH_EVENTS
+endif
+
 CPPSRCS	= \
 	GfxInfo.cpp \
 	nsWidgetFactory.cpp \
 	nsAppShell.cpp \
 	AndroidJavaWrappers.cpp \
 	AndroidBridge.cpp \
 	AndroidDirectTexture.cpp \
 	AndroidGraphicBuffer.cpp \
--- a/widget/gonk/Makefile.in
+++ b/widget/gonk/Makefile.in
@@ -66,12 +66,13 @@ SHARED_LIBRARY_LIBS = ../xpwidgets/libxp
 include $(topsrcdir)/config/rules.mk
 
 DEFINES += -D_IMPL_NS_WIDGET
 
 LOCAL_INCLUDES += \
 	-I$(topsrcdir)/widget/xpwidgets \
 	-I$(topsrcdir)/widget/shared \
 	-I$(topsrcdir)/dom/system/android \
+	-I$(topsrcdir)/content/events/src \
 	-I$(srcdir) \
 	$(NULL)
 
 include $(topsrcdir)/ipc/chromium/chromium-config.mk
--- a/widget/gonk/nsAppShell.cpp
+++ b/widget/gonk/nsAppShell.cpp
@@ -50,16 +50,17 @@
 #include <sys/types.h>
 #include <unistd.h>
 
 #include "nscore.h"
 #include "mozilla/FileUtils.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/Services.h"
 #include "nsAppShell.h"
+#include "nsDOMTouchEvent.h"
 #include "nsGkAtoms.h"
 #include "nsGUIEvent.h"
 #include "nsIObserverService.h"
 #include "nsWindow.h"
 
 #include "android/log.h"
 #include "ui/EventHub.h"
 #include "ui/InputReader.h"
@@ -102,16 +103,42 @@ pipeHandler(int fd, FdHandler *data)
 {
     ssize_t len;
     do {
         char tmp[32];
         len = read(fd, tmp, sizeof(tmp));
     } while (len > 0);
 }
 
+struct Touch {
+    int32_t id;
+    PointerCoords coords;
+};
+
+struct UserInputData {
+    uint64_t timeMs;
+    enum {
+        MOTION_DATA,
+        KEY_DATA
+    } type;
+    int32_t action;
+    int32_t flags;
+    int32_t metaState;
+    union {
+        struct {
+            int32_t keyCode;
+            int32_t scanCode;
+        } key;
+        struct {
+            int32_t touchCount;
+            Touch touches[MAX_POINTERS];
+        } motion;
+    };
+};
+
 static void
 sendMouseEvent(PRUint32 msg, uint64_t timeMs, int x, int y)
 {
     nsMouseEvent event(true, msg, NULL,
                        nsMouseEvent::eReal, nsMouseEvent::eNormal);
 
     event.refPoint.x = x;
     event.refPoint.y = y;
@@ -122,16 +149,72 @@ sendMouseEvent(PRUint32 msg, uint64_t ti
     event.isAlt = false;
     event.button = nsMouseEvent::eLeftButton;
     if (msg != NS_MOUSE_MOVE)
         event.clickCount = 1;
 
     nsWindow::DispatchInputEvent(event);
 }
 
+static void
+addDOMTouch(UserInputData& data, nsTouchEvent& event, int i)
+{
+    const Touch& touch = data.motion.touches[i];
+    event.touches.AppendElement(
+        new nsDOMTouch(touch.id,
+                       nsIntPoint(touch.coords.x, touch.coords.y),
+                       nsIntPoint(touch.coords.size, touch.coords.size),
+                       0,
+                       touch.coords.pressure));
+}
+
+static nsEventStatus
+sendTouchEvent(UserInputData& data)
+{
+    PRUint32 msg;
+    int32_t action = data.action & AMOTION_EVENT_ACTION_MASK;
+    switch (action) {
+    case AMOTION_EVENT_ACTION_DOWN:
+    case AMOTION_EVENT_ACTION_POINTER_DOWN:
+        msg = NS_TOUCH_START;
+        break;
+    case AMOTION_EVENT_ACTION_MOVE:
+        msg = NS_TOUCH_MOVE;
+        break;
+    case AMOTION_EVENT_ACTION_UP:
+    case AMOTION_EVENT_ACTION_POINTER_UP:
+        msg = NS_TOUCH_END;
+        break;
+    case AMOTION_EVENT_ACTION_OUTSIDE:
+    case AMOTION_EVENT_ACTION_CANCEL:
+        msg = NS_TOUCH_CANCEL;
+        break;
+    }
+
+    nsTouchEvent event(true, msg, NULL);
+
+    event.time = data.timeMs;
+    event.isShift = false;
+    event.isControl = false;
+    event.isMeta = false;
+    event.isAlt = false;
+
+    int32_t i;
+    if (msg == NS_TOUCH_END) {
+        i = data.action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK;
+        i >>= AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
+        addDOMTouch(data, event, i);
+    } else {
+        for (i = 0; i < data.motion.touchCount; ++i)
+            addDOMTouch(data, event, i);
+    }
+
+    return nsWindow::DispatchInputEvent(event);
+}
+
 static nsEventStatus
 sendKeyEventWithMsg(PRUint32 keyCode,
                     PRUint32 msg,
                     uint64_t timeMs,
                     PRUint32 flags)
 {
     nsKeyEvent event(true, msg, NULL);
     event.keyCode = keyCode;
@@ -190,36 +273,16 @@ maybeSendKeyEvent(int keyCode, bool pres
             sendSpecialKeyEvent(nsGkAtoms::VolumeDown, timeMs);
         break;
     default:
         VERBOSE_LOG("Got unknown key event code. type 0x%04x code 0x%04x value %d",
                     keyCode, pressed);
     }
 }
 
-struct UserInputData {
-    uint64_t timeMs;
-    enum {
-        MOTION_DATA,
-        KEY_DATA
-    } type;
-    int32_t action;
-    int32_t flags;
-    int32_t metaState;
-    union {
-        struct {
-            int32_t keyCode;
-            int32_t scanCode;
-        } key;
-        struct {
-            PointerCoords coords;
-        } motion;
-    };
-};
-
 class GeckoInputReaderPolicy : public InputReaderPolicyInterface {
 public:
     GeckoInputReaderPolicy() {}
 
     virtual bool getDisplayInfo(int32_t displayId,
             int32_t* width, int32_t* height, int32_t* orientation);
     virtual bool filterTouchEvents();
     virtual bool filterJumpyTouchEvents();
@@ -407,41 +470,48 @@ GeckoInputDispatcher::dump(String8& dump
 void
 GeckoInputDispatcher::dispatchOnce()
 {
     UserInputData data;
     {
         MutexAutoLock lock(mQueueLock);
         if (mEventQueue.empty())
             return;
-
         data = mEventQueue.front();
         mEventQueue.pop();
         if (!mEventQueue.empty())
             gAppShell->NotifyNativeEvent();
     }
 
     switch (data.type) {
     case UserInputData::MOTION_DATA: {
+        nsEventStatus status = sendTouchEvent(data);
+        if (status == nsEventStatus_eConsumeNoDefault)
+            break;
+
         PRUint32 msg;
-        switch (data.action) {
+        switch (data.action & AMOTION_EVENT_ACTION_MASK) {
         case AMOTION_EVENT_ACTION_DOWN:
             msg = NS_MOUSE_BUTTON_DOWN;
             break;
+        case AMOTION_EVENT_ACTION_POINTER_DOWN:
+        case AMOTION_EVENT_ACTION_POINTER_UP:
         case AMOTION_EVENT_ACTION_MOVE:
             msg = NS_MOUSE_MOVE;
             break;
+        case AMOTION_EVENT_ACTION_OUTSIDE:
+        case AMOTION_EVENT_ACTION_CANCEL:
         case AMOTION_EVENT_ACTION_UP:
             msg = NS_MOUSE_BUTTON_UP;
             break;
         }
         sendMouseEvent(msg,
                        data.timeMs,
-                       data.motion.coords.x,
-                       data.motion.coords.y);
+                       data.motion.touches[0].coords.x,
+                       data.motion.touches[0].coords.y);
         break;
     }
     case UserInputData::KEY_DATA:
         maybeSendKeyEvent(data.key.scanCode,
                           data.action == AKEY_EVENT_ACTION_DOWN,
                           data.timeMs);
         break;
     }
@@ -503,17 +573,23 @@ GeckoInputDispatcher::notifyMotion(nsecs
                                    nsecs_t downTime)
 {
     UserInputData data;
     data.timeMs = nanosecsToMillisecs(eventTime);
     data.type = UserInputData::MOTION_DATA;
     data.action = action;
     data.flags = flags;
     data.metaState = metaState;
-    data.motion.coords = *pointerCoords;
+    MOZ_ASSERT(pointerCount <= MAX_POINTERS);
+    data.motion.touchCount = pointerCount;
+    for (int32_t i = 0; i < pointerCount; ++i) {
+        Touch& touch = data.motion.touches[i];
+        touch.id = pointerIds[i];
+        memcpy(&touch.coords, &pointerCoords[i], sizeof(*pointerCoords));
+    }
     {
         MutexAutoLock lock(mQueueLock);
         mEventQueue.push(data);
     }
     gAppShell->NotifyNativeEvent();
 }
 
 void
--- a/xpcom/typelib/xpt/src/Makefile.in
+++ b/xpcom/typelib/xpt/src/Makefile.in
@@ -42,47 +42,35 @@ VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE		= xpcom
 LIBRARY_NAME	= xpt
 LIB_IS_C_ONLY	= 1
 DIST_INSTALL	= 1
 
-ifdef CROSS_COMPILE
-HOST_LIBRARY_NAME	= hostxpt
-endif
-
 CSRCS		= xpt_arena.c xpt_struct.c xpt_xdr.c
-HOST_CSRCS	= $(CSRCS)
 
 # we don't want the shared lib, but we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
 USE_STATIC_LIBS = 1
 
 
 # Don't use profile-guided optimization
 NO_PROFILE_GUIDED_OPTIMIZE = 1
 
 include $(topsrcdir)/config/rules.mk
 
 DEFINES		+= -DEXPORT_XPT_API
-HOST_CFLAGS	+= -DEXPORT_XPT_API
 
 # Build libxpt early so that it'll be available to xpidl, which also
 # must be built early.
 export::
 	@$(MAKE) libs
 
-ifdef CROSS_COMPILE
-ifdef HOST_NSPR_MDCPUCFG
-HOST_CFLAGS     += -DMDCPUCFG=$(HOST_NSPR_MDCPUCFG)
-endif
-endif
-
 # XXX, bug 417045, make -jN combines badly with -save-temps in   
 # CFLAGS/CXXFLAGS (for stabs symbols with XCode3)
 ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
 .NOTPARALLEL:
 endif
 
 ifdef _MSC_VER
 OS_COMPILE_CFLAGS += -Zl