diff --git a/accessible/src/base/AccTypes.h b/accessible/src/base/AccTypes.h
index 4d18bbe46df0281f7fe92accf1e0159c483673fa..a5ee2be7a2747ec18869d2974c9903ed24a89d88 100644
--- a/accessible/src/base/AccTypes.h
+++ b/accessible/src/base/AccTypes.h
@@ -55,6 +55,7 @@ enum AccType {
   eProgressType,
   eRootType,
   eXULLabelType,
+  eXULListItemType,
   eXULTabpanelsType,
   eXULTreeType,
 
diff --git a/accessible/src/base/EventQueue.cpp b/accessible/src/base/EventQueue.cpp
index b0a485f5937e3424380beb6d08586faae4ae1b65..6338785e49c9bdf2c88b9f2003e8b42f276ee824 100644
--- a/accessible/src/base/EventQueue.cpp
+++ b/accessible/src/base/EventQueue.cpp
@@ -9,6 +9,7 @@
 #include "nsEventShell.h"
 #include "DocAccessible.h"
 #include "nsAccessibilityService.h"
+#include "nsTextEquivUtils.h"
 #ifdef A11Y_LOG
 #include "Logging.h"
 #endif
@@ -37,6 +38,38 @@ EventQueue::PushEvent(AccEvent* aEvent)
   // Filter events.
   CoalesceEvents();
 
+  // Fire name change event on parent given that this event hasn't been
+  // coalesced, the parent's name was calculated from its subtree, and the
+  // subtree was changed.
+  Accessible* target = aEvent->mAccessible;
+  if (aEvent->mEventRule != AccEvent::eDoNotEmit &&
+      target->HasNameDependentParent() &&
+      (aEvent->mEventType == nsIAccessibleEvent::EVENT_NAME_CHANGE ||
+       aEvent->mEventType == nsIAccessibleEvent::EVENT_TEXT_REMOVED ||
+       aEvent->mEventType == nsIAccessibleEvent::EVENT_TEXT_INSERTED ||
+       aEvent->mEventType == nsIAccessibleEvent::EVENT_SHOW ||
+       aEvent->mEventType == nsIAccessibleEvent::EVENT_HIDE)) {
+    // Only continue traversing up the tree if it's possible that the parent
+    // accessible's name can depend on this accessible's name.
+    Accessible* parent = target->Parent();
+    while (parent &&
+           nsTextEquivUtils::HasNameRule(parent, eNameFromSubtreeIfReqRule)) {
+      // Test possible name dependent parent.
+      if (nsTextEquivUtils::HasNameRule(parent, eNameFromSubtreeRule)) {
+        nsAutoString name;
+        ENameValueFlag nameFlag = parent->Name(name);
+        // If name is obtained from subtree, fire name change event.
+        if (nameFlag == eNameFromSubtree) {
+          nsRefPtr<AccEvent> nameChangeEvent =
+            new AccEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, parent);
+          PushEvent(nameChangeEvent);
+        }
+        break;
+      }
+      parent = parent->Parent();
+    }
+  }
+
   // Associate text change with hide event if it wasn't stolen from hiding
   // siblings during coalescence.
   AccMutationEvent* showOrHideEvent = downcast_accEvent(aEvent);
diff --git a/accessible/src/base/nsTextEquivUtils.cpp b/accessible/src/base/nsTextEquivUtils.cpp
index e6651e96c0198960fc08f75dae78ff35ee3727be..bab1eee56942c1dbfe6c2a986df6cb60a6129109 100644
--- a/accessible/src/base/nsTextEquivUtils.cpp
+++ b/accessible/src/base/nsTextEquivUtils.cpp
@@ -344,7 +344,7 @@ nsTextEquivUtils::AppendString(nsAString *aString,
   return true;
 }
 
-uint32_t 
+uint32_t
 nsTextEquivUtils::GetRoleRule(role aRole)
 {
 #define ROLE(geckoRole, stringRole, atkRole, \
@@ -360,4 +360,3 @@ nsTextEquivUtils::GetRoleRule(role aRole)
 
 #undef ROLE
 }
-
diff --git a/accessible/src/base/nsTextEquivUtils.h b/accessible/src/base/nsTextEquivUtils.h
index 77ed2d39043a6c3cba286d4b9b6d99b912ea135e..3c35d0c072114d2e43d5089c773ef9161403ecc2 100644
--- a/accessible/src/base/nsTextEquivUtils.h
+++ b/accessible/src/base/nsTextEquivUtils.h
@@ -43,6 +43,18 @@ class nsTextEquivUtils
 public:
   typedef mozilla::a11y::Accessible Accessible;
 
+  /**
+   * Determines if the accessible has a given name rule.
+   *
+   * @param aAccessible [in] the given accessible
+   * @param aRule       [in] a given name rule
+   * @return true if the accessible has the rule
+   */
+  static inline bool HasNameRule(Accessible* aAccessible, ETextEquivRule aRule)
+  {
+    return (GetRoleRule(aAccessible->Role()) & aRule) == aRule;
+  }
+
   /**
    * Calculates the name from accessible subtree if allowed.
    *
diff --git a/accessible/src/generic/Accessible.cpp b/accessible/src/generic/Accessible.cpp
index 1e5d44fcb84b1bc2f682f6599765bc410fb2c4c2..24bf9814f84fc0e6db1905d9935de889527ce24e 100644
--- a/accessible/src/generic/Accessible.cpp
+++ b/accessible/src/generic/Accessible.cpp
@@ -111,8 +111,8 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_DESTROY(Accessible, LastRelease())
 Accessible::Accessible(nsIContent* aContent, DocAccessible* aDoc) :
   mContent(aContent), mDoc(aDoc),
   mParent(nullptr), mIndexInParent(-1), mChildrenFlags(eChildrenUninitialized),
-  mStateFlags(0), mType(0), mGenericTypes(0), mIndexOfEmbeddedChild(-1),
-  mRoleMapEntry(nullptr)
+  mStateFlags(0), mContextFlags(0), mType(0), mGenericTypes(0),
+  mIndexOfEmbeddedChild(-1), mRoleMapEntry(nullptr)
 {
 #ifdef NS_DEBUG_X
    {
@@ -2533,6 +2533,12 @@ Accessible::BindToParent(Accessible* aParent, uint32_t aIndexInParent)
   mIndexInParent = aIndexInParent;
 
   mParent->InvalidateChildrenGroupInfo();
+
+  // Note: this is currently only used for richlistitems and their children.
+  if (mParent->HasNameDependentParent() || mParent->IsXULListItem())
+    mContextFlags |= eHasNameDependentParent;
+  else
+    mContextFlags &= ~eHasNameDependentParent;
 }
 
 // Accessible protected
@@ -2544,6 +2550,7 @@ Accessible::UnbindFromParent()
   mIndexInParent = -1;
   mIndexOfEmbeddedChild = -1;
   mGroupInfo = nullptr;
+  mContextFlags &= ~eHasNameDependentParent;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -3241,6 +3248,8 @@ Accessible::StaticAsserts() const
                 "Accessible::mStateFlags was oversized by eLastStateFlag!");
   static_assert(eLastAccType <= (1 << kTypeBits) - 1,
                 "Accessible::mType was oversized by eLastAccType!");
+  static_assert(eLastContextFlag <= (1 << kContextFlagsBits) - 1,
+                "Accessible::mContextFlags was oversized by eLastContextFlag!");
   static_assert(eLastAccGenericType <= (1 << kGenericTypesBits) - 1,
                 "Accessible::mGenericType was oversized by eLastAccGenericType!");
 }
diff --git a/accessible/src/generic/Accessible.h b/accessible/src/generic/Accessible.h
index caba51d52010b87f3b9a544f3bedb088bb69749c..70ab16b899289afe8d5f89446854f4b9687ab959 100644
--- a/accessible/src/generic/Accessible.h
+++ b/accessible/src/generic/Accessible.h
@@ -579,6 +579,8 @@ public:
   bool IsXULLabel() const { return mType == eXULLabelType; }
   XULLabelAccessible* AsXULLabel();
 
+  bool IsXULListItem() const { return mType == eXULListItemType; }
+
   bool IsXULTabpanels() const { return mType == eXULTabpanelsType; }
 
   bool IsXULTree() const { return mType == eXULTreeType; }
@@ -790,6 +792,13 @@ public:
   bool NeedsDOMUIEvent() const
     { return !(mStateFlags & eIgnoreDOMUIEvent); }
 
+  /**
+   * Return true if this accessible has a parent whose name depends on this
+   * accessible.
+   */
+  bool HasNameDependentParent() const
+    { return mContextFlags & eHasNameDependentParent; }
+
 protected:
 
   /**
@@ -867,6 +876,15 @@ protected:
     eLastStateFlag = eGroupInfoDirty
   };
 
+  /**
+   * Flags used for contextual information about the accessible.
+   */
+  enum ContextFlags {
+    eHasNameDependentParent = 1 << 0, // Parent's name depends on this accessible.
+
+    eLastContextFlag = eHasNameDependentParent
+  };
+
 protected:
 
   //////////////////////////////////////////////////////////////////////////////
@@ -970,14 +988,16 @@ protected:
 
   static const uint8_t kChildrenFlagsBits = 2;
   static const uint8_t kStateFlagsBits = 6;
+  static const uint8_t kContextFlagsBits = 1;
   static const uint8_t kTypeBits = 6;
   static const uint8_t kGenericTypesBits = 12;
 
   /**
-   * Keep in sync with ChildrenFlags, StateFlags and AccTypes.
+   * Keep in sync with ChildrenFlags, StateFlags, ContextFlags, and AccTypes.
    */
   uint32_t mChildrenFlags : kChildrenFlagsBits;
   uint32_t mStateFlags : kStateFlagsBits;
+  uint32_t mContextFlags : kContextFlagsBits;
   uint32_t mType : kTypeBits;
   uint32_t mGenericTypes : kGenericTypesBits;
 
diff --git a/accessible/src/xul/XULListboxAccessible.cpp b/accessible/src/xul/XULListboxAccessible.cpp
index d008e5fc711e92d4a9cabad6a0ceea6c75b85d6f..b6757fd62cd36093848655e270a77a60185568e7 100644
--- a/accessible/src/xul/XULListboxAccessible.cpp
+++ b/accessible/src/xul/XULListboxAccessible.cpp
@@ -582,6 +582,7 @@ XULListitemAccessible::
                                       nsGkAtoms::type,
                                       nsGkAtoms::checkbox,
                                       eCaseMatters);
+  mType = eXULListItemType;
 }
 
 NS_IMPL_ISUPPORTS_INHERITED0(XULListitemAccessible, Accessible)
diff --git a/accessible/tests/mochitest/events/a11y.ini b/accessible/tests/mochitest/events/a11y.ini
index fb35ef23ba5f3b71882bfe84be52c62873e79b09..20daae2fb41e45c0ccdd8be394579b103819f24c 100644
--- a/accessible/tests/mochitest/events/a11y.ini
+++ b/accessible/tests/mochitest/events/a11y.ini
@@ -41,6 +41,7 @@ skip-if = os == 'win' || os == 'linux'
 [test_menu.xul]
 [test_mutation.html]
 [test_mutation.xhtml]
+[test_name.xul]
 [test_scroll.xul]
 [test_selection.html]
 [test_selection.xul]
diff --git a/accessible/tests/mochitest/events/test_name.xul b/accessible/tests/mochitest/events/test_name.xul
new file mode 100644
index 0000000000000000000000000000000000000000..9d688585c7659d021af81098b5ca4d7f6abcf69a
--- /dev/null
+++ b/accessible/tests/mochitest/events/test_name.xul
@@ -0,0 +1,92 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+                 type="text/css"?>
+
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
+  <script type="application/javascript"
+          src="chrome://mochikit/content/chrome-harness.js"/>
+
+  <script type="application/javascript"
+          src="../common.js" />
+  <script type="application/javascript"
+          src="../events.js" />
+
+  <script type="application/javascript">
+  <![CDATA[
+
+    /**
+     * Check name changed a11y event.
+     */
+    function nameChangeChecker(aMsg, aID)
+    {
+      this.type = EVENT_NAME_CHANGE;
+
+      function targetGetter()
+      {
+        return getAccessible(aID);
+      }
+      Object.defineProperty(this, "target", { get: targetGetter });
+
+      this.getID = function getID()
+      {
+        return aMsg + " name changed";
+      }
+    }
+
+    function changeRichListItemChild()
+    {
+      this.invoke = function changeRichListItemChild_invoke()
+      {
+        getNode('childcontent').setAttribute('value', 'Changed.');
+      }
+
+      this.eventSeq =
+      [
+        new nameChangeChecker("changeRichListItemChild: ", "listitem")
+      ];
+
+      this.getID = function changeRichListItemChild_getID()
+      {
+        return "changeRichListItemChild";
+      }
+    }
+
+    function doTest()
+    {
+      var queue = new eventQueue();
+      queue.push(new changeRichListItemChild());
+      queue.invoke();
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addA11yLoadEvent(doTest);
+  ]]>
+  </script>
+
+  <vbox flex="1" style="overflow: auto;">
+    <body xmlns="http://www.w3.org/1999/xhtml">
+      <a target="_blank"
+        href="https://bugzilla.mozilla.org/show_bug.cgi?id=986054"
+        title="Propagate name change events">
+       Mozilla Bug 986054
+      </a>
+
+      <p id="display"></p>
+      <div id="content" style="display: none">
+      </div>
+      <pre id="test">
+      </pre>
+    </body>
+
+    <richlistbox>
+      <richlistitem id="listitem">
+        <description id="childcontent" value="This will be changed."/>
+      </richlistitem>
+    </richlistbox>
+  </vbox>
+</window>
diff --git a/configure.in b/configure.in
index 32ca632210eae2b16cfa46ed71df85e264865ef2..8f9d85cd6537a9266e595b56bfda5cbdb6f684d6 100644
--- a/configure.in
+++ b/configure.in
@@ -5840,6 +5840,10 @@ if test "$OS_TARGET" = "WINNT" -a -z "$CROSS_COMPILE"; then
   fi
 fi
 
+# On mingw, check if headers are provided by toolchain.
+if test "$OS_TARGET" = "WINNT" -a -n "$GNU_CC"; then
+  MOZ_CHECK_HEADER(d3d10.h, MOZ_HAS_WINSDK_WITH_D3D=1)
+fi
 
 dnl ========================================================
 dnl D3D compiler DLL
@@ -5914,7 +5918,7 @@ if test -n "$MOZ_ANGLE_RENDERER"; then
     fi
   fi
 
-  if test -z "$MOZ_D3DCOMPILER_DLL_PATH" -a -z "$MOZ_D3DCOMPILER_CAB"; then
+  if test -z "$MOZ_D3DCOMPILER_DLL_PATH" -a -z "$MOZ_D3DCOMPILER_CAB" -a -z "$CROSS_COMPILE"; then
     AC_MSG_ERROR([Couldn't find an acceptable D3D compiler DLL. Either install Windows SDK 8.0+ and reconfigure with --enable-winsdk-directx, install DirectX SDK (June 2010 version or newer), or reconfigure with --disable-webgl.])
   fi
 fi
diff --git a/content/canvas/src/DocumentRendererChild.cpp b/content/canvas/src/DocumentRendererChild.cpp
index 3187a179e9a191c1fb18206dc14c7b968c3f39f4..d81d00d052d1ec0e8481bcf267c9894897783ab1 100644
--- a/content/canvas/src/DocumentRendererChild.cpp
+++ b/content/canvas/src/DocumentRendererChild.cpp
@@ -7,8 +7,9 @@
 #include "base/basictypes.h"
 
 #include "gfx2DGlue.h"
-#include "gfxImageSurface.h"
 #include "gfxPattern.h"
+#include "mozilla/gfx/2D.h"
+#include "mozilla/RefPtr.h"
 #include "nsPIDOMWindow.h"
 #include "nsIDOMWindow.h"
 #include "nsIDocShell.h"
@@ -26,6 +27,7 @@
 #include "mozilla/gfx/Matrix.h"
 
 using namespace mozilla;
+using namespace mozilla::gfx;
 using namespace mozilla::ipc;
 
 DocumentRendererChild::DocumentRendererChild()
@@ -72,12 +74,13 @@ DocumentRendererChild::RenderDocument(nsIDOMWindow *window,
     // Draw directly into the output array.
     data.SetLength(renderSize.width * renderSize.height * 4);
 
-    nsRefPtr<gfxImageSurface> surf =
-        new gfxImageSurface(reinterpret_cast<uint8_t*>(data.BeginWriting()),
-                            gfxIntSize(renderSize.width, renderSize.height),
-                            4 * renderSize.width,
-                            gfxImageFormat::ARGB32);
-    nsRefPtr<gfxContext> ctx = new gfxContext(surf);
+    RefPtr<DrawTarget> dt =
+        Factory::CreateDrawTargetForData(BackendType::CAIRO,
+                                         reinterpret_cast<uint8_t*>(data.BeginWriting()),
+                                         IntSize(renderSize.width, renderSize.height),
+                                         4 * renderSize.width,
+                                         SurfaceFormat::B8G8R8A8);
+    nsRefPtr<gfxContext> ctx = new gfxContext(dt);
     ctx->SetMatrix(mozilla::gfx::ThebesMatrix(transform));
 
     nsCOMPtr<nsIPresShell> shell = presContext->PresShell();
diff --git a/content/canvas/src/WebGLContext.h b/content/canvas/src/WebGLContext.h
index 81e2ac6921d6b4f3701fc41d78342f1dd42cde6c..b6177a428e9d118015ad553b32ca541ea4a5b941 100644
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -816,7 +816,6 @@ protected:
     WebGLVertexAttrib0Status WhatDoesVertexAttrib0Need();
     bool DoFakeVertexAttrib0(GLuint vertexCount);
     void UndoFakeVertexAttrib0();
-    void InvalidateFakeVertexAttrib0();
 
     static CheckedUint32 GetImageSize(GLsizei height,
                                       GLsizei width,
diff --git a/content/canvas/src/WebGLContextAsyncQueries.cpp b/content/canvas/src/WebGLContextAsyncQueries.cpp
index e87b5c0f5d80e5499939beef6a54d73cf2ecd981..7c767d640fad8db835a985fe67166bbb82e5de76 100644
--- a/content/canvas/src/WebGLContextAsyncQueries.cpp
+++ b/content/canvas/src/WebGLContextAsyncQueries.cpp
@@ -60,7 +60,7 @@ WebGLContext::CreateQuery()
     if (IsContextLost())
         return nullptr;
 
-    if (mActiveOcclusionQuery && !gl->IsGLES2()) {
+    if (mActiveOcclusionQuery && !gl->IsGLES()) {
         /* http://www.opengl.org/registry/specs/ARB/occlusion_query.txt
          * Calling either GenQueriesARB or DeleteQueriesARB while any query of
          * any target is active causes an INVALID_OPERATION error to be
@@ -95,7 +95,7 @@ WebGLContext::DeleteQuery(WebGLQuery *query)
         EndQuery(query->mType);
     }
 
-    if (mActiveOcclusionQuery && !gl->IsGLES2()) {
+    if (mActiveOcclusionQuery && !gl->IsGLES()) {
         /* http://www.opengl.org/registry/specs/ARB/occlusion_query.txt
          * Calling either GenQueriesARB or DeleteQueriesARB while any query of
          * any target is active causes an INVALID_OPERATION error to be
diff --git a/content/canvas/src/WebGLContextDraw.cpp b/content/canvas/src/WebGLContextDraw.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a9611575ae326cab6325a143f8894a3615b7b835
--- /dev/null
+++ b/content/canvas/src/WebGLContextDraw.cpp
@@ -0,0 +1,726 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "WebGLContext.h"
+
+#include "GLContext.h"
+#include "mozilla/CheckedInt.h"
+#include "WebGLBuffer.h"
+#include "WebGLFramebuffer.h"
+#include "WebGLProgram.h"
+#include "WebGLRenderbuffer.h"
+#include "WebGLShader.h"
+#include "WebGLTexture.h"
+#include "WebGLUniformInfo.h"
+#include "WebGLVertexArray.h"
+#include "WebGLVertexAttribData.h"
+
+using namespace mozilla;
+using namespace mozilla::dom;
+using namespace mozilla::gl;
+
+// For a Tegra workaround.
+static const int MAX_DRAW_CALLS_SINCE_FLUSH = 100;
+
+bool
+WebGLContext::DrawInstanced_check(const char* info)
+{
+    // This restriction was removed in GLES3, so WebGL2 shouldn't have it.
+    if (!IsWebGL2() &&
+        IsExtensionEnabled(ANGLE_instanced_arrays) &&
+        !mBufferFetchingHasPerVertex)
+    {
+        /* http://www.khronos.org/registry/gles/extensions/ANGLE/ANGLE_instanced_arrays.txt
+         *  If all of the enabled vertex attribute arrays that are bound to active
+         *  generic attributes in the program have a non-zero divisor, the draw
+         *  call should return INVALID_OPERATION.
+         *
+         * NB: This also appears to apply to NV_instanced_arrays, though the
+         * INVALID_OPERATION emission is not explicitly stated.
+         * ARB_instanced_arrays does not have this restriction.
+         */
+        ErrorInvalidOperation("%s: at least one vertex attribute divisor should be 0", info);
+        return false;
+    }
+
+    return true;
+}
+
+bool WebGLContext::DrawArrays_check(GLint first, GLsizei count, GLsizei primcount, const char* info)
+{
+    if (first < 0 || count < 0) {
+        ErrorInvalidValue("%s: negative first or count", info);
+        return false;
+    }
+
+    if (primcount < 0) {
+        ErrorInvalidValue("%s: negative primcount", info);
+        return false;
+    }
+
+    if (!ValidateStencilParamsForDrawCall()) {
+        return false;
+    }
+
+    // If count is 0, there's nothing to do.
+    if (count == 0 || primcount == 0) {
+        return false;
+    }
+
+    // If there is no current program, this is silently ignored.
+    // Any checks below this depend on a program being available.
+    if (!mCurrentProgram) {
+        return false;
+    }
+
+    if (!ValidateBufferFetching(info)) {
+        return false;
+    }
+
+    CheckedInt<GLsizei> checked_firstPlusCount = CheckedInt<GLsizei>(first) + count;
+
+    if (!checked_firstPlusCount.isValid()) {
+        ErrorInvalidOperation("%s: overflow in first+count", info);
+        return false;
+    }
+
+    if (uint32_t(checked_firstPlusCount.value()) > mMaxFetchedVertices) {
+        ErrorInvalidOperation("%s: bound vertex attribute buffers do not have sufficient size for given first and count", info);
+        return false;
+    }
+
+    if (uint32_t(primcount) > mMaxFetchedInstances) {
+        ErrorInvalidOperation("%s: bound instance attribute buffers do not have sufficient size for given primcount", info);
+        return false;
+    }
+
+    MakeContextCurrent();
+
+    if (mBoundFramebuffer) {
+        if (!mBoundFramebuffer->CheckAndInitializeAttachments()) {
+            ErrorInvalidFramebufferOperation("%s: incomplete framebuffer", info);
+            return false;
+        }
+    }
+
+    if (!DoFakeVertexAttrib0(checked_firstPlusCount.value())) {
+        return false;
+    }
+    BindFakeBlackTextures();
+
+    return true;
+}
+
+void
+WebGLContext::DrawArrays(GLenum mode, GLint first, GLsizei count)
+{
+    if (IsContextLost())
+        return;
+
+    if (!ValidateDrawModeEnum(mode, "drawArrays: mode"))
+        return;
+
+    if (!DrawArrays_check(first, count, 1, "drawArrays"))
+        return;
+
+    SetupContextLossTimer();
+    gl->fDrawArrays(mode, first, count);
+
+    Draw_cleanup();
+}
+
+void
+WebGLContext::DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei primcount)
+{
+    if (IsContextLost())
+        return;
+
+    if (!ValidateDrawModeEnum(mode, "drawArraysInstanced: mode"))
+        return;
+
+    if (!DrawArrays_check(first, count, primcount, "drawArraysInstanced"))
+        return;
+
+    if (!DrawInstanced_check("drawArraysInstanced"))
+        return;
+
+    SetupContextLossTimer();
+    gl->fDrawArraysInstanced(mode, first, count, primcount);
+
+    Draw_cleanup();
+}
+
+bool
+WebGLContext::DrawElements_check(GLsizei count, GLenum type,
+                                 WebGLintptr byteOffset, GLsizei primcount,
+                                 const char* info, GLuint* out_upperBound)
+{
+    if (count < 0 || byteOffset < 0) {
+        ErrorInvalidValue("%s: negative count or offset", info);
+        return false;
+    }
+
+    if (primcount < 0) {
+        ErrorInvalidValue("%s: negative primcount", info);
+        return false;
+    }
+
+    if (!ValidateStencilParamsForDrawCall()) {
+        return false;
+    }
+
+    // If count is 0, there's nothing to do.
+    if (count == 0 || primcount == 0) {
+        return false;
+    }
+
+    CheckedUint32 checked_byteCount;
+
+    GLsizei first = 0;
+
+    if (type == LOCAL_GL_UNSIGNED_SHORT) {
+        checked_byteCount = 2 * CheckedUint32(count);
+        if (byteOffset % 2 != 0) {
+            ErrorInvalidOperation("%s: invalid byteOffset for UNSIGNED_SHORT (must be a multiple of 2)", info);
+            return false;
+        }
+        first = byteOffset / 2;
+    }
+    else if (type == LOCAL_GL_UNSIGNED_BYTE) {
+        checked_byteCount = count;
+        first = byteOffset;
+    }
+    else if (type == LOCAL_GL_UNSIGNED_INT && IsExtensionEnabled(OES_element_index_uint)) {
+        checked_byteCount = 4 * CheckedUint32(count);
+        if (byteOffset % 4 != 0) {
+            ErrorInvalidOperation("%s: invalid byteOffset for UNSIGNED_INT (must be a multiple of 4)", info);
+            return false;
+        }
+        first = byteOffset / 4;
+    }
+    else {
+        ErrorInvalidEnum("%s: type must be UNSIGNED_SHORT or UNSIGNED_BYTE", info);
+        return false;
+    }
+
+    if (!checked_byteCount.isValid()) {
+        ErrorInvalidValue("%s: overflow in byteCount", info);
+        return false;
+    }
+
+    // If there is no current program, this is silently ignored.
+    // Any checks below this depend on a program being available.
+    if (!mCurrentProgram) {
+        return false;
+    }
+
+    if (!mBoundVertexArray->mBoundElementArrayBuffer) {
+        ErrorInvalidOperation("%s: must have element array buffer binding", info);
+        return false;
+    }
+
+    WebGLBuffer& elemArrayBuffer = *mBoundVertexArray->mBoundElementArrayBuffer;
+
+    if (!elemArrayBuffer.ByteLength()) {
+        ErrorInvalidOperation("%s: bound element array buffer doesn't have any data", info);
+        return false;
+    }
+
+    CheckedInt<GLsizei> checked_neededByteCount = checked_byteCount.toChecked<GLsizei>() + byteOffset;
+
+    if (!checked_neededByteCount.isValid()) {
+        ErrorInvalidOperation("%s: overflow in byteOffset+byteCount", info);
+        return false;
+    }
+
+    if (uint32_t(checked_neededByteCount.value()) > elemArrayBuffer.ByteLength()) {
+        ErrorInvalidOperation("%s: bound element array buffer is too small for given count and offset", info);
+        return false;
+    }
+
+    if (!ValidateBufferFetching(info))
+        return false;
+
+    if (!mMaxFetchedVertices ||
+        !elemArrayBuffer.Validate(type, mMaxFetchedVertices - 1, first, count, out_upperBound))
+    {
+        ErrorInvalidOperation(
+                              "%s: bound vertex attribute buffers do not have sufficient "
+                              "size for given indices from the bound element array", info);
+        return false;
+    }
+
+    if (uint32_t(primcount) > mMaxFetchedInstances) {
+        ErrorInvalidOperation("%s: bound instance attribute buffers do not have sufficient size for given primcount", info);
+        return false;
+    }
+
+    MakeContextCurrent();
+
+    if (mBoundFramebuffer) {
+        if (!mBoundFramebuffer->CheckAndInitializeAttachments()) {
+            ErrorInvalidFramebufferOperation("%s: incomplete framebuffer", info);
+            return false;
+        }
+    }
+
+    if (!DoFakeVertexAttrib0(mMaxFetchedVertices)) {
+        return false;
+    }
+    BindFakeBlackTextures();
+
+    return true;
+}
+
+void
+WebGLContext::DrawElements(GLenum mode, GLsizei count, GLenum type,
+                           WebGLintptr byteOffset)
+{
+    if (IsContextLost())
+        return;
+
+    if (!ValidateDrawModeEnum(mode, "drawElements: mode"))
+        return;
+
+    GLuint upperBound = UINT_MAX;
+    if (!DrawElements_check(count, type, byteOffset, 1, "drawElements",
+                            &upperBound))
+    {
+        return;
+    }
+
+    SetupContextLossTimer();
+
+    if (gl->IsSupported(gl::GLFeature::draw_range_elements)) {
+        gl->fDrawRangeElements(mode, 0, upperBound,
+                               count, type, reinterpret_cast<GLvoid*>(byteOffset));
+    } else {
+        gl->fDrawElements(mode, count, type, reinterpret_cast<GLvoid*>(byteOffset));
+    }
+
+    Draw_cleanup();
+}
+
+void
+WebGLContext::DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type,
+                                    WebGLintptr byteOffset, GLsizei primcount)
+{
+    if (IsContextLost())
+        return;
+
+    if (!ValidateDrawModeEnum(mode, "drawElementsInstanced: mode"))
+        return;
+
+    if (!DrawElements_check(count, type, byteOffset, primcount, "drawElementsInstanced"))
+        return;
+
+    if (!DrawInstanced_check("drawElementsInstanced"))
+        return;
+
+    SetupContextLossTimer();
+    gl->fDrawElementsInstanced(mode, count, type, reinterpret_cast<GLvoid*>(byteOffset), primcount);
+
+    Draw_cleanup();
+}
+
+void WebGLContext::Draw_cleanup()
+{
+    UndoFakeVertexAttrib0();
+    UnbindFakeBlackTextures();
+
+    if (!mBoundFramebuffer) {
+        Invalidate();
+        mShouldPresent = true;
+        mIsScreenCleared = false;
+    }
+
+    if (gl->WorkAroundDriverBugs()) {
+        if (gl->Renderer() == gl::GLRenderer::Tegra) {
+            mDrawCallsSinceLastFlush++;
+
+            if (mDrawCallsSinceLastFlush >= MAX_DRAW_CALLS_SINCE_FLUSH) {
+                gl->fFlush();
+                mDrawCallsSinceLastFlush = 0;
+            }
+        }
+    }
+
+    // Let's check the viewport
+    const WebGLRectangleObject* rect = CurValidFBRectObject();
+    if (rect) {
+        if (mViewportWidth > rect->Width() ||
+            mViewportHeight > rect->Height())
+        {
+            if (!mAlreadyWarnedAboutViewportLargerThanDest) {
+                GenerateWarning("Drawing to a destination rect smaller than the viewport rect. "
+                                "(This warning will only be given once)");
+                mAlreadyWarnedAboutViewportLargerThanDest = true;
+            }
+        }
+    }
+}
+
+/*
+ * Verify that state is consistent for drawing, and compute max number of elements (maxAllowedCount)
+ * that will be legal to be read from bound VBOs.
+ */
+
+bool
+WebGLContext::ValidateBufferFetching(const char *info)
+{
+#ifdef DEBUG
+    GLint currentProgram = 0;
+    MakeContextCurrent();
+    gl->fGetIntegerv(LOCAL_GL_CURRENT_PROGRAM, &currentProgram);
+    MOZ_ASSERT(GLuint(currentProgram) == mCurrentProgram->GLName(),
+               "WebGL: current program doesn't agree with GL state");
+#endif
+
+    if (mBufferFetchingIsVerified) {
+        return true;
+    }
+
+    bool hasPerVertex = false;
+    uint32_t maxVertices = UINT32_MAX;
+    uint32_t maxInstances = UINT32_MAX;
+    uint32_t attribs = mBoundVertexArray->mAttribs.Length();
+
+    for (uint32_t i = 0; i < attribs; ++i) {
+        const WebGLVertexAttribData& vd = mBoundVertexArray->mAttribs[i];
+
+        // If the attrib array isn't enabled, there's nothing to check;
+        // it's a static value.
+        if (!vd.enabled)
+            continue;
+
+        if (vd.buf == nullptr) {
+            ErrorInvalidOperation("%s: no VBO bound to enabled vertex attrib index %d!", info, i);
+            return false;
+        }
+
+        // If the attrib is not in use, then we don't have to validate
+        // it, just need to make sure that the binding is non-null.
+        if (!mCurrentProgram->IsAttribInUse(i))
+            continue;
+
+        // the base offset
+        CheckedUint32 checked_byteLength = CheckedUint32(vd.buf->ByteLength()) - vd.byteOffset;
+        CheckedUint32 checked_sizeOfLastElement = CheckedUint32(vd.componentSize()) * vd.size;
+
+        if (!checked_byteLength.isValid() ||
+            !checked_sizeOfLastElement.isValid())
+        {
+            ErrorInvalidOperation("%s: integer overflow occured while checking vertex attrib %d", info, i);
+            return false;
+        }
+
+        if (checked_byteLength.value() < checked_sizeOfLastElement.value()) {
+            maxVertices = 0;
+            maxInstances = 0;
+            break;
+        }
+
+        CheckedUint32 checked_maxAllowedCount = ((checked_byteLength - checked_sizeOfLastElement) / vd.actualStride()) + 1;
+
+        if (!checked_maxAllowedCount.isValid()) {
+            ErrorInvalidOperation("%s: integer overflow occured while checking vertex attrib %d", info, i);
+            return false;
+        }
+
+        if (vd.divisor == 0) {
+            maxVertices = std::min(maxVertices, checked_maxAllowedCount.value());
+            hasPerVertex = true;
+        } else {
+            maxInstances = std::min(maxInstances, checked_maxAllowedCount.value() / vd.divisor);
+        }
+    }
+
+    mBufferFetchingIsVerified = true;
+    mBufferFetchingHasPerVertex = hasPerVertex;
+    mMaxFetchedVertices = maxVertices;
+    mMaxFetchedInstances = maxInstances;
+
+    return true;
+}
+
+WebGLVertexAttrib0Status
+WebGLContext::WhatDoesVertexAttrib0Need()
+{
+    MOZ_ASSERT(mCurrentProgram);
+
+    // work around Mac OSX crash, see bug 631420
+#ifdef XP_MACOSX
+    if (gl->WorkAroundDriverBugs() &&
+        mBoundVertexArray->IsAttribArrayEnabled(0) &&
+        !mCurrentProgram->IsAttribInUse(0))
+    {
+        return WebGLVertexAttrib0Status::EmulatedUninitializedArray;
+    }
+#endif
+
+    if (MOZ_LIKELY(gl->IsGLES() ||
+                   mBoundVertexArray->IsAttribArrayEnabled(0)))
+    {
+        return WebGLVertexAttrib0Status::Default;
+    }
+
+    return mCurrentProgram->IsAttribInUse(0)
+           ? WebGLVertexAttrib0Status::EmulatedInitializedArray
+           : WebGLVertexAttrib0Status::EmulatedUninitializedArray;
+}
+
+bool
+WebGLContext::DoFakeVertexAttrib0(GLuint vertexCount)
+{
+    WebGLVertexAttrib0Status whatDoesAttrib0Need = WhatDoesVertexAttrib0Need();
+
+    if (MOZ_LIKELY(whatDoesAttrib0Need == WebGLVertexAttrib0Status::Default))
+        return true;
+
+    if (!mAlreadyWarnedAboutFakeVertexAttrib0) {
+        GenerateWarning("Drawing without vertex attrib 0 array enabled forces the browser "
+                        "to do expensive emulation work when running on desktop OpenGL "
+                        "platforms, for example on Mac. It is preferable to always draw "
+                        "with vertex attrib 0 array enabled, by using bindAttribLocation "
+                        "to bind some always-used attribute to location 0.");
+        mAlreadyWarnedAboutFakeVertexAttrib0 = true;
+    }
+
+    CheckedUint32 checked_dataSize = CheckedUint32(vertexCount) * 4 * sizeof(GLfloat);
+
+    if (!checked_dataSize.isValid()) {
+        ErrorOutOfMemory("Integer overflow trying to construct a fake vertex attrib 0 array for a draw-operation "
+                         "with %d vertices. Try reducing the number of vertices.", vertexCount);
+        return false;
+    }
+
+    GLuint dataSize = checked_dataSize.value();
+
+    if (!mFakeVertexAttrib0BufferObject) {
+        gl->fGenBuffers(1, &mFakeVertexAttrib0BufferObject);
+    }
+
+    // if the VBO status is already exactly what we need, or if the only difference is that it's initialized and
+    // we don't need it to be, then consider it OK
+    bool vertexAttrib0BufferStatusOK =
+        mFakeVertexAttrib0BufferStatus == whatDoesAttrib0Need ||
+        (mFakeVertexAttrib0BufferStatus == WebGLVertexAttrib0Status::EmulatedInitializedArray &&
+         whatDoesAttrib0Need == WebGLVertexAttrib0Status::EmulatedUninitializedArray);
+
+    if (!vertexAttrib0BufferStatusOK ||
+        mFakeVertexAttrib0BufferObjectSize < dataSize ||
+        mFakeVertexAttrib0BufferObjectVector[0] != mVertexAttrib0Vector[0] ||
+        mFakeVertexAttrib0BufferObjectVector[1] != mVertexAttrib0Vector[1] ||
+        mFakeVertexAttrib0BufferObjectVector[2] != mVertexAttrib0Vector[2] ||
+        mFakeVertexAttrib0BufferObjectVector[3] != mVertexAttrib0Vector[3])
+    {
+        mFakeVertexAttrib0BufferStatus = whatDoesAttrib0Need;
+        mFakeVertexAttrib0BufferObjectSize = dataSize;
+        mFakeVertexAttrib0BufferObjectVector[0] = mVertexAttrib0Vector[0];
+        mFakeVertexAttrib0BufferObjectVector[1] = mVertexAttrib0Vector[1];
+        mFakeVertexAttrib0BufferObjectVector[2] = mVertexAttrib0Vector[2];
+        mFakeVertexAttrib0BufferObjectVector[3] = mVertexAttrib0Vector[3];
+
+        gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mFakeVertexAttrib0BufferObject);
+
+        GetAndFlushUnderlyingGLErrors();
+
+        if (mFakeVertexAttrib0BufferStatus == WebGLVertexAttrib0Status::EmulatedInitializedArray) {
+            nsAutoArrayPtr<GLfloat> array(new GLfloat[4 * vertexCount]);
+            for(size_t i = 0; i < vertexCount; ++i) {
+                array[4 * i + 0] = mVertexAttrib0Vector[0];
+                array[4 * i + 1] = mVertexAttrib0Vector[1];
+                array[4 * i + 2] = mVertexAttrib0Vector[2];
+                array[4 * i + 3] = mVertexAttrib0Vector[3];
+            }
+            gl->fBufferData(LOCAL_GL_ARRAY_BUFFER, dataSize, array, LOCAL_GL_DYNAMIC_DRAW);
+        } else {
+            gl->fBufferData(LOCAL_GL_ARRAY_BUFFER, dataSize, nullptr, LOCAL_GL_DYNAMIC_DRAW);
+        }
+        GLenum error = GetAndFlushUnderlyingGLErrors();
+
+        gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mBoundArrayBuffer ? mBoundArrayBuffer->GLName() : 0);
+
+        // note that we do this error checking and early return AFTER having restored the buffer binding above
+        if (error) {
+            ErrorOutOfMemory("Ran out of memory trying to construct a fake vertex attrib 0 array for a draw-operation "
+                             "with %d vertices. Try reducing the number of vertices.", vertexCount);
+            return false;
+        }
+    }
+
+    gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mFakeVertexAttrib0BufferObject);
+    gl->fVertexAttribPointer(0, 4, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, 0);
+
+    return true;
+}
+
+void
+WebGLContext::UndoFakeVertexAttrib0()
+{
+    WebGLVertexAttrib0Status whatDoesAttrib0Need = WhatDoesVertexAttrib0Need();
+
+    if (MOZ_LIKELY(whatDoesAttrib0Need == WebGLVertexAttrib0Status::Default))
+        return;
+
+    if (mBoundVertexArray->HasAttrib(0) && mBoundVertexArray->mAttribs[0].buf) {
+        const WebGLVertexAttribData& attrib0 = mBoundVertexArray->mAttribs[0];
+        gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, attrib0.buf->GLName());
+        gl->fVertexAttribPointer(0,
+                                 attrib0.size,
+                                 attrib0.type,
+                                 attrib0.normalized,
+                                 attrib0.stride,
+                                 reinterpret_cast<const GLvoid *>(attrib0.byteOffset));
+    } else {
+        gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
+    }
+
+    gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mBoundArrayBuffer ? mBoundArrayBuffer->GLName() : 0);
+}
+
+WebGLContextFakeBlackStatus
+WebGLContext::ResolvedFakeBlackStatus()
+{
+    // handle this case first, it's the generic case
+    if (MOZ_LIKELY(mFakeBlackStatus == WebGLContextFakeBlackStatus::NotNeeded))
+        return mFakeBlackStatus;
+
+    if (mFakeBlackStatus == WebGLContextFakeBlackStatus::Needed)
+        return mFakeBlackStatus;
+
+    for (int32_t i = 0; i < mGLMaxTextureUnits; ++i) {
+        if ((mBound2DTextures[i] && mBound2DTextures[i]->ResolvedFakeBlackStatus() != WebGLTextureFakeBlackStatus::NotNeeded) ||
+            (mBoundCubeMapTextures[i] && mBoundCubeMapTextures[i]->ResolvedFakeBlackStatus() != WebGLTextureFakeBlackStatus::NotNeeded))
+        {
+            mFakeBlackStatus = WebGLContextFakeBlackStatus::Needed;
+            return mFakeBlackStatus;
+        }
+    }
+
+    // we have exhausted all cases where we do need fakeblack, so if the status is still unknown,
+    // that means that we do NOT need it.
+    mFakeBlackStatus = WebGLContextFakeBlackStatus::NotNeeded;
+    return mFakeBlackStatus;
+}
+
+void
+WebGLContext::BindFakeBlackTexturesHelper(
+    GLenum target,
+    const nsTArray<WebGLRefPtr<WebGLTexture> > & boundTexturesArray,
+    ScopedDeletePtr<FakeBlackTexture> & opaqueTextureScopedPtr,
+    ScopedDeletePtr<FakeBlackTexture> & transparentTextureScopedPtr)
+{
+    for (int32_t i = 0; i < mGLMaxTextureUnits; ++i) {
+        if (!boundTexturesArray[i]) {
+            continue;
+        }
+
+        WebGLTextureFakeBlackStatus s = boundTexturesArray[i]->ResolvedFakeBlackStatus();
+        MOZ_ASSERT(s != WebGLTextureFakeBlackStatus::Unknown);
+
+        if (MOZ_LIKELY(s == WebGLTextureFakeBlackStatus::NotNeeded)) {
+            continue;
+        }
+
+        bool alpha = s == WebGLTextureFakeBlackStatus::UninitializedImageData &&
+                     FormatHasAlpha(boundTexturesArray[i]->ImageInfoBase().InternalFormat());
+        ScopedDeletePtr<FakeBlackTexture>&
+            blackTexturePtr = alpha
+                              ? transparentTextureScopedPtr
+                              : opaqueTextureScopedPtr;
+
+        if (!blackTexturePtr) {
+            GLenum format = alpha ? LOCAL_GL_RGBA : LOCAL_GL_RGB;
+            blackTexturePtr
+                = new FakeBlackTexture(gl, target, format);
+        }
+
+        gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
+        gl->fBindTexture(target,
+                         blackTexturePtr->GLName());
+    }
+}
+
+void
+WebGLContext::BindFakeBlackTextures()
+{
+    // this is the generic case: try to return early
+    if (MOZ_LIKELY(ResolvedFakeBlackStatus() == WebGLContextFakeBlackStatus::NotNeeded))
+        return;
+
+    BindFakeBlackTexturesHelper(LOCAL_GL_TEXTURE_2D,
+                                mBound2DTextures,
+                                mBlackOpaqueTexture2D,
+                                mBlackTransparentTexture2D);
+    BindFakeBlackTexturesHelper(LOCAL_GL_TEXTURE_CUBE_MAP,
+                                mBoundCubeMapTextures,
+                                mBlackOpaqueTextureCubeMap,
+                                mBlackTransparentTextureCubeMap);
+}
+
+void
+WebGLContext::UnbindFakeBlackTextures()
+{
+    // this is the generic case: try to return early
+    if (MOZ_LIKELY(ResolvedFakeBlackStatus() == WebGLContextFakeBlackStatus::NotNeeded))
+        return;
+
+    for (int32_t i = 0; i < mGLMaxTextureUnits; ++i) {
+        if (mBound2DTextures[i] && mBound2DTextures[i]->ResolvedFakeBlackStatus() != WebGLTextureFakeBlackStatus::NotNeeded) {
+            gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
+            gl->fBindTexture(LOCAL_GL_TEXTURE_2D, mBound2DTextures[i]->GLName());
+        }
+        if (mBoundCubeMapTextures[i] && mBoundCubeMapTextures[i]->ResolvedFakeBlackStatus() != WebGLTextureFakeBlackStatus::NotNeeded) {
+            gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
+            gl->fBindTexture(LOCAL_GL_TEXTURE_CUBE_MAP, mBoundCubeMapTextures[i]->GLName());
+        }
+    }
+
+    gl->fActiveTexture(LOCAL_GL_TEXTURE0 + mActiveTexture);
+}
+
+WebGLContext::FakeBlackTexture::FakeBlackTexture(GLContext *gl, GLenum target, GLenum format)
+    : mGL(gl)
+    , mGLName(0)
+{
+  MOZ_ASSERT(target == LOCAL_GL_TEXTURE_2D || target == LOCAL_GL_TEXTURE_CUBE_MAP);
+  MOZ_ASSERT(format == LOCAL_GL_RGB || format == LOCAL_GL_RGBA);
+
+  mGL->MakeCurrent();
+  GLuint formerBinding = 0;
+  gl->GetUIntegerv(target == LOCAL_GL_TEXTURE_2D
+                   ? LOCAL_GL_TEXTURE_BINDING_2D
+                   : LOCAL_GL_TEXTURE_BINDING_CUBE_MAP,
+                   &formerBinding);
+  gl->fGenTextures(1, &mGLName);
+  gl->fBindTexture(target, mGLName);
+
+  // we allocate our zeros on the heap, and we overallocate (16 bytes instead of 4)
+  // to minimize the risk of running into a driver bug in texImage2D, as it is
+  // a bit unusual maybe to create 1x1 textures, and the stack may not have the alignment
+  // that texImage2D expects.
+  void* zeros = calloc(1, 16);
+  if (target == LOCAL_GL_TEXTURE_2D) {
+      gl->fTexImage2D(target, 0, format, 1, 1,
+                      0, format, LOCAL_GL_UNSIGNED_BYTE, zeros);
+  } else {
+      for (GLuint i = 0; i < 6; ++i) {
+          gl->fTexImage2D(LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, format, 1, 1,
+                          0, format, LOCAL_GL_UNSIGNED_BYTE, zeros);
+      }
+  }
+  free(zeros);
+
+  gl->fBindTexture(target, formerBinding);
+}
+
+WebGLContext::FakeBlackTexture::~FakeBlackTexture()
+{
+  if (mGL) {
+      mGL->MakeCurrent();
+      mGL->fDeleteTextures(1, &mGLName);
+  }
+}
diff --git a/content/canvas/src/WebGLContextGL.cpp b/content/canvas/src/WebGLContextGL.cpp
index 2c3a47f8eb4ba09550e4cbe867e69d89ad60f31c..6ed3790fdd4dbf0bfde03cceb33434ca1d0385bb 100644
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -72,49 +72,6 @@ WebGLContext::CurValidFBRectObject() const
     return rect;
 }
 
-WebGLContext::FakeBlackTexture::FakeBlackTexture(GLContext *gl, GLenum target, GLenum format)
-    : mGL(gl)
-    , mGLName(0)
-{
-  MOZ_ASSERT(target == LOCAL_GL_TEXTURE_2D || target == LOCAL_GL_TEXTURE_CUBE_MAP);
-  MOZ_ASSERT(format == LOCAL_GL_RGB || format == LOCAL_GL_RGBA);
-
-  mGL->MakeCurrent();
-  GLuint formerBinding = 0;
-  gl->GetUIntegerv(target == LOCAL_GL_TEXTURE_2D
-                   ? LOCAL_GL_TEXTURE_BINDING_2D
-                   : LOCAL_GL_TEXTURE_BINDING_CUBE_MAP,
-                   &formerBinding);
-  gl->fGenTextures(1, &mGLName);
-  gl->fBindTexture(target, mGLName);
-
-  // we allocate our zeros on the heap, and we overallocate (16 bytes instead of 4)
-  // to minimize the risk of running into a driver bug in texImage2D, as it is
-  // a bit unusual maybe to create 1x1 textures, and the stack may not have the alignment
-  // that texImage2D expects.
-  void* zeros = calloc(1, 16);
-  if (target == LOCAL_GL_TEXTURE_2D) {
-      gl->fTexImage2D(target, 0, format, 1, 1,
-                      0, format, LOCAL_GL_UNSIGNED_BYTE, zeros);
-  } else {
-      for (GLuint i = 0; i < 6; ++i) {
-          gl->fTexImage2D(LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, format, 1, 1,
-                          0, format, LOCAL_GL_UNSIGNED_BYTE, zeros);
-      }
-  }
-  free(zeros);
-
-  gl->fBindTexture(target, formerBinding);
-}
-
-WebGLContext::FakeBlackTexture::~FakeBlackTexture()
-{
-  if (mGL) {
-      mGL->MakeCurrent();
-      mGL->fDeleteTextures(1, &mGLName);
-  }
-}
-
 //
 //  WebGL API
 //
@@ -834,237 +791,6 @@ WebGLContext::DepthRange(GLfloat zNear, GLfloat zFar)
     gl->fDepthRange(zNear, zFar);
 }
 
-WebGLVertexAttrib0Status
-WebGLContext::WhatDoesVertexAttrib0Need()
-{
-  // here we may assume that mCurrentProgram != null
-
-    // work around Mac OSX crash, see bug 631420
-#ifdef XP_MACOSX
-    if (gl->WorkAroundDriverBugs() &&
-        mBoundVertexArray->IsAttribArrayEnabled(0) &&
-        !mCurrentProgram->IsAttribInUse(0))
-    {
-        return WebGLVertexAttrib0Status::EmulatedUninitializedArray;
-    }
-#endif
-
-    return (gl->IsGLES2() || mBoundVertexArray->IsAttribArrayEnabled(0)) ? WebGLVertexAttrib0Status::Default
-         : mCurrentProgram->IsAttribInUse(0) ? WebGLVertexAttrib0Status::EmulatedInitializedArray
-                                             : WebGLVertexAttrib0Status::EmulatedUninitializedArray;
-}
-
-bool
-WebGLContext::DoFakeVertexAttrib0(GLuint vertexCount)
-{
-    WebGLVertexAttrib0Status whatDoesAttrib0Need = WhatDoesVertexAttrib0Need();
-
-    if (whatDoesAttrib0Need == WebGLVertexAttrib0Status::Default)
-        return true;
-
-    if (!mAlreadyWarnedAboutFakeVertexAttrib0) {
-        GenerateWarning("Drawing without vertex attrib 0 array enabled forces the browser "
-                        "to do expensive emulation work when running on desktop OpenGL "
-                        "platforms, for example on Mac. It is preferable to always draw "
-                        "with vertex attrib 0 array enabled, by using bindAttribLocation "
-                        "to bind some always-used attribute to location 0.");
-        mAlreadyWarnedAboutFakeVertexAttrib0 = true;
-    }
-
-    CheckedUint32 checked_dataSize = CheckedUint32(vertexCount) * 4 * sizeof(GLfloat);
-
-    if (!checked_dataSize.isValid()) {
-        ErrorOutOfMemory("Integer overflow trying to construct a fake vertex attrib 0 array for a draw-operation "
-                         "with %d vertices. Try reducing the number of vertices.", vertexCount);
-        return false;
-    }
-
-    GLuint dataSize = checked_dataSize.value();
-
-    if (!mFakeVertexAttrib0BufferObject) {
-        gl->fGenBuffers(1, &mFakeVertexAttrib0BufferObject);
-    }
-
-    // if the VBO status is already exactly what we need, or if the only difference is that it's initialized and
-    // we don't need it to be, then consider it OK
-    bool vertexAttrib0BufferStatusOK =
-        mFakeVertexAttrib0BufferStatus == whatDoesAttrib0Need ||
-        (mFakeVertexAttrib0BufferStatus == WebGLVertexAttrib0Status::EmulatedInitializedArray &&
-         whatDoesAttrib0Need == WebGLVertexAttrib0Status::EmulatedUninitializedArray);
-
-    if (!vertexAttrib0BufferStatusOK ||
-        mFakeVertexAttrib0BufferObjectSize < dataSize ||
-        mFakeVertexAttrib0BufferObjectVector[0] != mVertexAttrib0Vector[0] ||
-        mFakeVertexAttrib0BufferObjectVector[1] != mVertexAttrib0Vector[1] ||
-        mFakeVertexAttrib0BufferObjectVector[2] != mVertexAttrib0Vector[2] ||
-        mFakeVertexAttrib0BufferObjectVector[3] != mVertexAttrib0Vector[3])
-    {
-        mFakeVertexAttrib0BufferStatus = whatDoesAttrib0Need;
-        mFakeVertexAttrib0BufferObjectSize = dataSize;
-        mFakeVertexAttrib0BufferObjectVector[0] = mVertexAttrib0Vector[0];
-        mFakeVertexAttrib0BufferObjectVector[1] = mVertexAttrib0Vector[1];
-        mFakeVertexAttrib0BufferObjectVector[2] = mVertexAttrib0Vector[2];
-        mFakeVertexAttrib0BufferObjectVector[3] = mVertexAttrib0Vector[3];
-
-        gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mFakeVertexAttrib0BufferObject);
-
-        GetAndFlushUnderlyingGLErrors();
-
-        if (mFakeVertexAttrib0BufferStatus == WebGLVertexAttrib0Status::EmulatedInitializedArray) {
-            nsAutoArrayPtr<GLfloat> array(new GLfloat[4 * vertexCount]);
-            for(size_t i = 0; i < vertexCount; ++i) {
-                array[4 * i + 0] = mVertexAttrib0Vector[0];
-                array[4 * i + 1] = mVertexAttrib0Vector[1];
-                array[4 * i + 2] = mVertexAttrib0Vector[2];
-                array[4 * i + 3] = mVertexAttrib0Vector[3];
-            }
-            gl->fBufferData(LOCAL_GL_ARRAY_BUFFER, dataSize, array, LOCAL_GL_DYNAMIC_DRAW);
-        } else {
-            gl->fBufferData(LOCAL_GL_ARRAY_BUFFER, dataSize, nullptr, LOCAL_GL_DYNAMIC_DRAW);
-        }
-        GLenum error = GetAndFlushUnderlyingGLErrors();
-
-        gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mBoundArrayBuffer ? mBoundArrayBuffer->GLName() : 0);
-
-        // note that we do this error checking and early return AFTER having restored the buffer binding above
-        if (error) {
-            ErrorOutOfMemory("Ran out of memory trying to construct a fake vertex attrib 0 array for a draw-operation "
-                             "with %d vertices. Try reducing the number of vertices.", vertexCount);
-            return false;
-        }
-    }
-
-    gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mFakeVertexAttrib0BufferObject);
-    gl->fVertexAttribPointer(0, 4, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, 0);
-
-    return true;
-}
-
-void
-WebGLContext::UndoFakeVertexAttrib0()
-{
-    WebGLVertexAttrib0Status whatDoesAttrib0Need = WhatDoesVertexAttrib0Need();
-
-    if (whatDoesAttrib0Need == WebGLVertexAttrib0Status::Default)
-        return;
-
-    if (mBoundVertexArray->HasAttrib(0) && mBoundVertexArray->mAttribs[0].buf) {
-        const WebGLVertexAttribData& attrib0 = mBoundVertexArray->mAttribs[0];
-        gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, attrib0.buf->GLName());
-        gl->fVertexAttribPointer(0,
-                                 attrib0.size,
-                                 attrib0.type,
-                                 attrib0.normalized,
-                                 attrib0.stride,
-                                 reinterpret_cast<const GLvoid *>(attrib0.byteOffset));
-    } else {
-        gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
-    }
-
-    gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mBoundArrayBuffer ? mBoundArrayBuffer->GLName() : 0);
-}
-
-WebGLContextFakeBlackStatus
-WebGLContext::ResolvedFakeBlackStatus()
-{
-    // handle this case first, it's the generic case
-    if (MOZ_LIKELY(mFakeBlackStatus == WebGLContextFakeBlackStatus::NotNeeded))
-        return mFakeBlackStatus;
-
-    if (mFakeBlackStatus == WebGLContextFakeBlackStatus::Needed)
-        return mFakeBlackStatus;
-
-    for (int32_t i = 0; i < mGLMaxTextureUnits; ++i) {
-        if ((mBound2DTextures[i] && mBound2DTextures[i]->ResolvedFakeBlackStatus() != WebGLTextureFakeBlackStatus::NotNeeded) ||
-            (mBoundCubeMapTextures[i] && mBoundCubeMapTextures[i]->ResolvedFakeBlackStatus() != WebGLTextureFakeBlackStatus::NotNeeded))
-        {
-            mFakeBlackStatus = WebGLContextFakeBlackStatus::Needed;
-            return mFakeBlackStatus;
-        }
-    }
-
-    // we have exhausted all cases where we do need fakeblack, so if the status is still unknown,
-    // that means that we do NOT need it.
-    mFakeBlackStatus = WebGLContextFakeBlackStatus::NotNeeded;
-    return mFakeBlackStatus;
-}
-
-void
-WebGLContext::BindFakeBlackTexturesHelper(
-    GLenum target,
-    const nsTArray<WebGLRefPtr<WebGLTexture> > & boundTexturesArray,
-    ScopedDeletePtr<FakeBlackTexture> & opaqueTextureScopedPtr,
-    ScopedDeletePtr<FakeBlackTexture> & transparentTextureScopedPtr)
-{
-    for (int32_t i = 0; i < mGLMaxTextureUnits; ++i) {
-        if (!boundTexturesArray[i]) {
-            continue;
-        }
-
-        WebGLTextureFakeBlackStatus s = boundTexturesArray[i]->ResolvedFakeBlackStatus();
-        MOZ_ASSERT(s != WebGLTextureFakeBlackStatus::Unknown);
-
-        if (MOZ_LIKELY(s == WebGLTextureFakeBlackStatus::NotNeeded)) {
-            continue;
-        }
-
-        bool alpha = s == WebGLTextureFakeBlackStatus::UninitializedImageData &&
-                     FormatHasAlpha(boundTexturesArray[i]->ImageInfoBase().InternalFormat());
-        ScopedDeletePtr<FakeBlackTexture>&
-            blackTexturePtr = alpha
-                              ? transparentTextureScopedPtr
-                              : opaqueTextureScopedPtr;
-
-        if (!blackTexturePtr) {
-            GLenum format = alpha ? LOCAL_GL_RGBA : LOCAL_GL_RGB;
-            blackTexturePtr
-                = new FakeBlackTexture(gl, target, format);
-        }
-
-        gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
-        gl->fBindTexture(target,
-                         blackTexturePtr->GLName());
-    }
-}
-
-void
-WebGLContext::BindFakeBlackTextures()
-{
-    // this is the generic case: try to return early
-    if (MOZ_LIKELY(ResolvedFakeBlackStatus() == WebGLContextFakeBlackStatus::NotNeeded))
-        return;
-
-    BindFakeBlackTexturesHelper(LOCAL_GL_TEXTURE_2D,
-                                mBound2DTextures,
-                                mBlackOpaqueTexture2D,
-                                mBlackTransparentTexture2D);
-    BindFakeBlackTexturesHelper(LOCAL_GL_TEXTURE_CUBE_MAP,
-                                mBoundCubeMapTextures,
-                                mBlackOpaqueTextureCubeMap,
-                                mBlackTransparentTextureCubeMap);
-}
-
-void
-WebGLContext::UnbindFakeBlackTextures()
-{
-    // this is the generic case: try to return early
-    if (MOZ_LIKELY(ResolvedFakeBlackStatus() == WebGLContextFakeBlackStatus::NotNeeded))
-        return;
-
-    for (int32_t i = 0; i < mGLMaxTextureUnits; ++i) {
-        if (mBound2DTextures[i] && mBound2DTextures[i]->ResolvedFakeBlackStatus() != WebGLTextureFakeBlackStatus::NotNeeded) {
-            gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
-            gl->fBindTexture(LOCAL_GL_TEXTURE_2D, mBound2DTextures[i]->GLName());
-        }
-        if (mBoundCubeMapTextures[i] && mBoundCubeMapTextures[i]->ResolvedFakeBlackStatus() != WebGLTextureFakeBlackStatus::NotNeeded) {
-            gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
-            gl->fBindTexture(LOCAL_GL_TEXTURE_CUBE_MAP, mBoundCubeMapTextures[i]->GLName());
-        }
-    }
-
-    gl->fActiveTexture(LOCAL_GL_TEXTURE0 + mActiveTexture);
-}
-
 void
 WebGLContext::FramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum rbtarget, WebGLRenderbuffer *wrb)
 {
@@ -2622,14 +2348,14 @@ WebGLContext::RenderbufferStorage(GLenum target, GLenum internalformat, GLsizei
     case LOCAL_GL_RGBA4:
     case LOCAL_GL_RGB5_A1:
         // 16-bit RGBA formats are not supported on desktop GL
-        if (!gl->IsGLES2()) internalformatForGL = LOCAL_GL_RGBA8;
+        if (!gl->IsGLES()) internalformatForGL = LOCAL_GL_RGBA8;
         break;
     case LOCAL_GL_RGB565:
         // the RGB565 format is not supported on desktop GL
-        if (!gl->IsGLES2()) internalformatForGL = LOCAL_GL_RGB8;
+        if (!gl->IsGLES()) internalformatForGL = LOCAL_GL_RGB8;
         break;
     case LOCAL_GL_DEPTH_COMPONENT16:
-        if (!gl->IsGLES2() || gl->IsExtensionSupported(gl::GLContext::OES_depth24))
+        if (!gl->IsGLES() || gl->IsExtensionSupported(gl::GLContext::OES_depth24))
             internalformatForGL = LOCAL_GL_DEPTH_COMPONENT24;
         else if (gl->IsExtensionSupported(gl::GLContext::OES_packed_depth_stencil))
             internalformatForGL = LOCAL_GL_DEPTH24_STENCIL8;
@@ -3230,7 +2956,7 @@ WebGLContext::CompileShader(WebGLShader *shader)
 
     MakeContextCurrent();
 
-    ShShaderOutput targetShaderSourceLanguage = gl->IsGLES2() ? SH_ESSL_OUTPUT : SH_GLSL_OUTPUT;
+    ShShaderOutput targetShaderSourceLanguage = gl->IsGLES() ? SH_ESSL_OUTPUT : SH_GLSL_OUTPUT;
     bool useShaderSourceTranslation = true;
 
     if (shader->NeedsTranslation() && mShaderValidation) {
@@ -3800,7 +3526,7 @@ GLenum WebGLContext::CheckedTexImage2D(GLenum target,
 
     // convert type for half float if not on GLES2
     GLenum realType = type;
-    if (realType == LOCAL_GL_HALF_FLOAT_OES && !gl->IsGLES2()) {
+    if (realType == LOCAL_GL_HALF_FLOAT_OES && !gl->IsGLES()) {
         realType = LOCAL_GL_HALF_FLOAT;
     }
 
@@ -3882,7 +3608,7 @@ WebGLContext::TexImage2D_base(GLenum target, GLint level, GLenum internalformat,
 
     // Handle ES2 and GL differences in floating point internal formats.  Note that
     // format == internalformat, as checked above and as required by ES.
-    internalformat = InternalFormatForFormatAndType(format, type, gl->IsGLES2());
+    internalformat = InternalFormatForFormatAndType(format, type, gl->IsGLES());
 
     // Handle ES2 and GL differences when supporting sRGB internal formats. GL ES
     // requires that format == internalformat, but GL will fail in this case.
@@ -3890,7 +3616,7 @@ WebGLContext::TexImage2D_base(GLenum target, GLint level, GLenum internalformat,
     //      format  ->  internalformat
     //      GL_RGB      GL_SRGB_EXT
     //      GL_RGBA     GL_SRGB_ALPHA_EXT
-    if (!gl->IsGLES2()) {
+    if (!gl->IsGLES()) {
         switch (internalformat) {
             case LOCAL_GL_SRGB_EXT:
                 format = LOCAL_GL_RGB;
diff --git a/content/canvas/src/WebGLContextValidate.cpp b/content/canvas/src/WebGLContextValidate.cpp
index b1c24df0dc8d8a51fa5de35c8b57d5cb4d970e8b..4f35dd13c23e56aba478011c5e8d276181e2928a 100644
--- a/content/canvas/src/WebGLContextValidate.cpp
+++ b/content/canvas/src/WebGLContextValidate.cpp
@@ -1631,7 +1631,7 @@ WebGLContext::InitAndValidateGL()
     MakeContextCurrent();
 
     // on desktop OpenGL, we always keep vertex attrib 0 array enabled
-    if (!gl->IsGLES2()) {
+    if (!gl->IsGLES()) {
         gl->fEnableVertexAttribArray(0);
     }
 
@@ -1729,7 +1729,7 @@ WebGLContext::InitAndValidateGL()
     // Always 1 for GLES2
     mMaxFramebufferColorAttachments = 1;
 
-    if (!gl->IsGLES2()) {
+    if (!gl->IsGLES()) {
         // gl_PointSize is always available in ES2 GLSL, but has to be
         // specifically enabled on desktop GLSL.
         gl->fEnable(LOCAL_GL_VERTEX_PROGRAM_POINT_SIZE);
diff --git a/content/canvas/src/WebGLContextVertices.cpp b/content/canvas/src/WebGLContextVertices.cpp
index e7786c0966f4dab81704f038c1cb37f52be4dfdc..c6afab4a64f143e6e943f07ac47c2568d3942e76 100644
--- a/content/canvas/src/WebGLContextVertices.cpp
+++ b/content/canvas/src/WebGLContextVertices.cpp
@@ -20,9 +20,6 @@
 using namespace mozilla;
 using namespace dom;
 
-// For a Tegra workaround.
-static const int MAX_DRAW_CALLS_SINCE_FLUSH = 100;
-
 void
 WebGLContext::VertexAttrib1f(GLuint index, GLfloat x0)
 {
@@ -38,7 +35,7 @@ WebGLContext::VertexAttrib1f(GLuint index, GLfloat x0)
         mVertexAttrib0Vector[1] = 0;
         mVertexAttrib0Vector[2] = 0;
         mVertexAttrib0Vector[3] = 1;
-        if (gl->IsGLES2())
+        if (gl->IsGLES())
             gl->fVertexAttrib1f(index, x0);
     }
 }
@@ -58,7 +55,7 @@ WebGLContext::VertexAttrib2f(GLuint index, GLfloat x0, GLfloat x1)
         mVertexAttrib0Vector[1] = x1;
         mVertexAttrib0Vector[2] = 0;
         mVertexAttrib0Vector[3] = 1;
-        if (gl->IsGLES2())
+        if (gl->IsGLES())
             gl->fVertexAttrib2f(index, x0, x1);
     }
 }
@@ -78,7 +75,7 @@ WebGLContext::VertexAttrib3f(GLuint index, GLfloat x0, GLfloat x1, GLfloat x2)
         mVertexAttrib0Vector[1] = x1;
         mVertexAttrib0Vector[2] = x2;
         mVertexAttrib0Vector[3] = 1;
-        if (gl->IsGLES2())
+        if (gl->IsGLES())
             gl->fVertexAttrib3f(index, x0, x1, x2);
     }
 }
@@ -99,7 +96,7 @@ WebGLContext::VertexAttrib4f(GLuint index, GLfloat x0, GLfloat x1,
         mVertexAttrib0Vector[1] = x1;
         mVertexAttrib0Vector[2] = x2;
         mVertexAttrib0Vector[3] = x3;
-        if (gl->IsGLES2())
+        if (gl->IsGLES())
             gl->fVertexAttrib4f(index, x0, x1, x2, x3);
     }
 }
@@ -120,7 +117,7 @@ WebGLContext::VertexAttrib1fv_base(GLuint idx, uint32_t arrayLength,
         mVertexAttrib0Vector[1] = GLfloat(0);
         mVertexAttrib0Vector[2] = GLfloat(0);
         mVertexAttrib0Vector[3] = GLfloat(1);
-        if (gl->IsGLES2())
+        if (gl->IsGLES())
             gl->fVertexAttrib1fv(idx, ptr);
     }
 }
@@ -140,7 +137,7 @@ WebGLContext::VertexAttrib2fv_base(GLuint idx, uint32_t arrayLength,
         mVertexAttrib0Vector[1] = ptr[1];
         mVertexAttrib0Vector[2] = GLfloat(0);
         mVertexAttrib0Vector[3] = GLfloat(1);
-        if (gl->IsGLES2())
+        if (gl->IsGLES())
             gl->fVertexAttrib2fv(idx, ptr);
     }
 }
@@ -160,7 +157,7 @@ WebGLContext::VertexAttrib3fv_base(GLuint idx, uint32_t arrayLength,
         mVertexAttrib0Vector[1] = ptr[1];
         mVertexAttrib0Vector[2] = ptr[2];
         mVertexAttrib0Vector[3] = GLfloat(1);
-        if (gl->IsGLES2())
+        if (gl->IsGLES())
             gl->fVertexAttrib3fv(idx, ptr);
     }
 }
@@ -180,7 +177,7 @@ WebGLContext::VertexAttrib4fv_base(GLuint idx, uint32_t arrayLength,
         mVertexAttrib0Vector[1] = ptr[1];
         mVertexAttrib0Vector[2] = ptr[2];
         mVertexAttrib0Vector[3] = ptr[3];
-        if (gl->IsGLES2())
+        if (gl->IsGLES())
             gl->fVertexAttrib4fv(idx, ptr);
     }
 }
@@ -214,7 +211,7 @@ WebGLContext::DisableVertexAttribArray(GLuint index)
     MakeContextCurrent();
     InvalidateBufferFetching();
 
-    if (index || gl->IsGLES2())
+    if (index || gl->IsGLES())
         gl->fDisableVertexAttribArray(index);
 
     MOZ_ASSERT(mBoundVertexArray->HasAttrib(index)); // should have been validated earlier
@@ -426,425 +423,3 @@ WebGLContext::VertexAttribDivisor(GLuint index, GLuint divisor)
 
     gl->fVertexAttribDivisor(index, divisor);
 }
-
-bool
-WebGLContext::DrawInstanced_check(const char* info)
-{
-    // This restriction was removed in GLES3, so WebGL2 shouldn't have it.
-    if (!IsWebGL2() &&
-        IsExtensionEnabled(ANGLE_instanced_arrays) &&
-        !mBufferFetchingHasPerVertex)
-    {
-        /* http://www.khronos.org/registry/gles/extensions/ANGLE/ANGLE_instanced_arrays.txt
-         *  If all of the enabled vertex attribute arrays that are bound to active
-         *  generic attributes in the program have a non-zero divisor, the draw
-         *  call should return INVALID_OPERATION.
-         *
-         * NB: This also appears to apply to NV_instanced_arrays, though the
-         * INVALID_OPERATION emission is not explicitly stated.
-         * ARB_instanced_arrays does not have this restriction.
-         */
-        ErrorInvalidOperation("%s: at least one vertex attribute divisor should be 0", info);
-        return false;
-    }
-
-    return true;
-}
-
-bool WebGLContext::DrawArrays_check(GLint first, GLsizei count, GLsizei primcount, const char* info)
-{
-    if (first < 0 || count < 0) {
-        ErrorInvalidValue("%s: negative first or count", info);
-        return false;
-    }
-
-    if (primcount < 0) {
-        ErrorInvalidValue("%s: negative primcount", info);
-        return false;
-    }
-
-    if (!ValidateStencilParamsForDrawCall()) {
-        return false;
-    }
-
-    // If count is 0, there's nothing to do.
-    if (count == 0 || primcount == 0) {
-        return false;
-    }
-
-    // If there is no current program, this is silently ignored.
-    // Any checks below this depend on a program being available.
-    if (!mCurrentProgram) {
-        return false;
-    }
-
-    if (!ValidateBufferFetching(info)) {
-        return false;
-    }
-
-    CheckedInt<GLsizei> checked_firstPlusCount = CheckedInt<GLsizei>(first) + count;
-
-    if (!checked_firstPlusCount.isValid()) {
-        ErrorInvalidOperation("%s: overflow in first+count", info);
-        return false;
-    }
-
-    if (uint32_t(checked_firstPlusCount.value()) > mMaxFetchedVertices) {
-        ErrorInvalidOperation("%s: bound vertex attribute buffers do not have sufficient size for given first and count", info);
-        return false;
-    }
-
-    if (uint32_t(primcount) > mMaxFetchedInstances) {
-        ErrorInvalidOperation("%s: bound instance attribute buffers do not have sufficient size for given primcount", info);
-        return false;
-    }
-
-    MakeContextCurrent();
-
-    if (mBoundFramebuffer) {
-        if (!mBoundFramebuffer->CheckAndInitializeAttachments()) {
-            ErrorInvalidFramebufferOperation("%s: incomplete framebuffer", info);
-            return false;
-        }
-    }
-
-    if (!DoFakeVertexAttrib0(checked_firstPlusCount.value())) {
-        return false;
-    }
-    BindFakeBlackTextures();
-
-    return true;
-}
-
-void
-WebGLContext::DrawArrays(GLenum mode, GLint first, GLsizei count)
-{
-    if (IsContextLost())
-        return;
-
-    if (!ValidateDrawModeEnum(mode, "drawArrays: mode"))
-        return;
-
-    if (!DrawArrays_check(first, count, 1, "drawArrays"))
-        return;
-
-    SetupContextLossTimer();
-    gl->fDrawArrays(mode, first, count);
-
-    Draw_cleanup();
-}
-
-void
-WebGLContext::DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei primcount)
-{
-    if (IsContextLost())
-        return;
-
-    if (!ValidateDrawModeEnum(mode, "drawArraysInstanced: mode"))
-        return;
-
-    if (!DrawArrays_check(first, count, primcount, "drawArraysInstanced"))
-        return;
-
-    if (!DrawInstanced_check("drawArraysInstanced"))
-        return;
-
-    SetupContextLossTimer();
-    gl->fDrawArraysInstanced(mode, first, count, primcount);
-
-    Draw_cleanup();
-}
-
-bool
-WebGLContext::DrawElements_check(GLsizei count, GLenum type,
-                                 WebGLintptr byteOffset, GLsizei primcount,
-                                 const char* info, GLuint* out_upperBound)
-{
-    if (count < 0 || byteOffset < 0) {
-        ErrorInvalidValue("%s: negative count or offset", info);
-        return false;
-    }
-
-    if (primcount < 0) {
-        ErrorInvalidValue("%s: negative primcount", info);
-        return false;
-    }
-
-    if (!ValidateStencilParamsForDrawCall()) {
-        return false;
-    }
-
-    // If count is 0, there's nothing to do.
-    if (count == 0 || primcount == 0) {
-        return false;
-    }
-
-    CheckedUint32 checked_byteCount;
-
-    GLsizei first = 0;
-
-    if (type == LOCAL_GL_UNSIGNED_SHORT) {
-        checked_byteCount = 2 * CheckedUint32(count);
-        if (byteOffset % 2 != 0) {
-            ErrorInvalidOperation("%s: invalid byteOffset for UNSIGNED_SHORT (must be a multiple of 2)", info);
-            return false;
-        }
-        first = byteOffset / 2;
-    }
-    else if (type == LOCAL_GL_UNSIGNED_BYTE) {
-        checked_byteCount = count;
-        first = byteOffset;
-    }
-    else if (type == LOCAL_GL_UNSIGNED_INT && IsExtensionEnabled(OES_element_index_uint)) {
-        checked_byteCount = 4 * CheckedUint32(count);
-        if (byteOffset % 4 != 0) {
-            ErrorInvalidOperation("%s: invalid byteOffset for UNSIGNED_INT (must be a multiple of 4)", info);
-            return false;
-        }
-        first = byteOffset / 4;
-    }
-    else {
-        ErrorInvalidEnum("%s: type must be UNSIGNED_SHORT or UNSIGNED_BYTE", info);
-        return false;
-    }
-
-    if (!checked_byteCount.isValid()) {
-        ErrorInvalidValue("%s: overflow in byteCount", info);
-        return false;
-    }
-
-    // If there is no current program, this is silently ignored.
-    // Any checks below this depend on a program being available.
-    if (!mCurrentProgram) {
-        return false;
-    }
-
-    if (!mBoundVertexArray->mBoundElementArrayBuffer) {
-        ErrorInvalidOperation("%s: must have element array buffer binding", info);
-        return false;
-    }
-
-    WebGLBuffer& elemArrayBuffer = *mBoundVertexArray->mBoundElementArrayBuffer;
-
-    if (!elemArrayBuffer.ByteLength()) {
-        ErrorInvalidOperation("%s: bound element array buffer doesn't have any data", info);
-        return false;
-    }
-
-    CheckedInt<GLsizei> checked_neededByteCount = checked_byteCount.toChecked<GLsizei>() + byteOffset;
-
-    if (!checked_neededByteCount.isValid()) {
-        ErrorInvalidOperation("%s: overflow in byteOffset+byteCount", info);
-        return false;
-    }
-
-    if (uint32_t(checked_neededByteCount.value()) > elemArrayBuffer.ByteLength()) {
-        ErrorInvalidOperation("%s: bound element array buffer is too small for given count and offset", info);
-        return false;
-    }
-
-    if (!ValidateBufferFetching(info))
-        return false;
-
-    if (!mMaxFetchedVertices ||
-        !elemArrayBuffer.Validate(type, mMaxFetchedVertices - 1, first, count, out_upperBound))
-    {
-        ErrorInvalidOperation(
-                              "%s: bound vertex attribute buffers do not have sufficient "
-                              "size for given indices from the bound element array", info);
-        return false;
-    }
-
-    if (uint32_t(primcount) > mMaxFetchedInstances) {
-        ErrorInvalidOperation("%s: bound instance attribute buffers do not have sufficient size for given primcount", info);
-        return false;
-    }
-
-    MakeContextCurrent();
-
-    if (mBoundFramebuffer) {
-        if (!mBoundFramebuffer->CheckAndInitializeAttachments()) {
-            ErrorInvalidFramebufferOperation("%s: incomplete framebuffer", info);
-            return false;
-        }
-    }
-
-    if (!DoFakeVertexAttrib0(mMaxFetchedVertices)) {
-        return false;
-    }
-    BindFakeBlackTextures();
-
-    return true;
-}
-
-void
-WebGLContext::DrawElements(GLenum mode, GLsizei count, GLenum type,
-                           WebGLintptr byteOffset)
-{
-    if (IsContextLost())
-        return;
-
-    if (!ValidateDrawModeEnum(mode, "drawElements: mode"))
-        return;
-
-    GLuint upperBound = UINT_MAX;
-    if (!DrawElements_check(count, type, byteOffset, 1, "drawElements",
-                            &upperBound))
-    {
-        return;
-    }
-
-    SetupContextLossTimer();
-
-    if (gl->IsSupported(gl::GLFeature::draw_range_elements)) {
-        gl->fDrawRangeElements(mode, 0, upperBound,
-                               count, type, reinterpret_cast<GLvoid*>(byteOffset));
-    } else {
-        gl->fDrawElements(mode, count, type, reinterpret_cast<GLvoid*>(byteOffset));
-    }
-
-    Draw_cleanup();
-}
-
-void
-WebGLContext::DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type,
-                                    WebGLintptr byteOffset, GLsizei primcount)
-{
-    if (IsContextLost())
-        return;
-
-    if (!ValidateDrawModeEnum(mode, "drawElementsInstanced: mode"))
-        return;
-
-    if (!DrawElements_check(count, type, byteOffset, primcount, "drawElementsInstanced"))
-        return;
-
-    if (!DrawInstanced_check("drawElementsInstanced"))
-        return;
-
-    SetupContextLossTimer();
-    gl->fDrawElementsInstanced(mode, count, type, reinterpret_cast<GLvoid*>(byteOffset), primcount);
-
-    Draw_cleanup();
-}
-
-void WebGLContext::Draw_cleanup()
-{
-    UndoFakeVertexAttrib0();
-    UnbindFakeBlackTextures();
-
-    if (!mBoundFramebuffer) {
-        Invalidate();
-        mShouldPresent = true;
-        mIsScreenCleared = false;
-    }
-
-    if (gl->WorkAroundDriverBugs()) {
-        if (gl->Renderer() == gl::GLRenderer::Tegra) {
-            mDrawCallsSinceLastFlush++;
-
-            if (mDrawCallsSinceLastFlush >= MAX_DRAW_CALLS_SINCE_FLUSH) {
-                gl->fFlush();
-                mDrawCallsSinceLastFlush = 0;
-            }
-        }
-    }
-
-    // Let's check the viewport
-    const WebGLRectangleObject* rect = CurValidFBRectObject();
-    if (rect) {
-        if (mViewportWidth > rect->Width() ||
-            mViewportHeight > rect->Height())
-        {
-            if (!mAlreadyWarnedAboutViewportLargerThanDest) {
-                GenerateWarning("Drawing to a destination rect smaller than the viewport rect. "
-                                "(This warning will only be given once)");
-                mAlreadyWarnedAboutViewportLargerThanDest = true;
-            }
-        }
-    }
-}
-
-/*
- * Verify that state is consistent for drawing, and compute max number of elements (maxAllowedCount)
- * that will be legal to be read from bound VBOs.
- */
-
-bool
-WebGLContext::ValidateBufferFetching(const char *info)
-{
-#ifdef DEBUG
-    GLint currentProgram = 0;
-    MakeContextCurrent();
-    gl->fGetIntegerv(LOCAL_GL_CURRENT_PROGRAM, &currentProgram);
-    MOZ_ASSERT(GLuint(currentProgram) == mCurrentProgram->GLName(),
-               "WebGL: current program doesn't agree with GL state");
-#endif
-
-    if (mBufferFetchingIsVerified) {
-        return true;
-    }
-
-    bool hasPerVertex = false;
-    uint32_t maxVertices = UINT32_MAX;
-    uint32_t maxInstances = UINT32_MAX;
-    uint32_t attribs = mBoundVertexArray->mAttribs.Length();
-
-    for (uint32_t i = 0; i < attribs; ++i) {
-        const WebGLVertexAttribData& vd = mBoundVertexArray->mAttribs[i];
-
-        // If the attrib array isn't enabled, there's nothing to check;
-        // it's a static value.
-        if (!vd.enabled)
-            continue;
-
-        if (vd.buf == nullptr) {
-            ErrorInvalidOperation("%s: no VBO bound to enabled vertex attrib index %d!", info, i);
-            return false;
-        }
-
-        // If the attrib is not in use, then we don't have to validate
-        // it, just need to make sure that the binding is non-null.
-        if (!mCurrentProgram->IsAttribInUse(i))
-            continue;
-
-        // the base offset
-        CheckedUint32 checked_byteLength = CheckedUint32(vd.buf->ByteLength()) - vd.byteOffset;
-        CheckedUint32 checked_sizeOfLastElement = CheckedUint32(vd.componentSize()) * vd.size;
-
-        if (!checked_byteLength.isValid() ||
-            !checked_sizeOfLastElement.isValid())
-        {
-            ErrorInvalidOperation("%s: integer overflow occured while checking vertex attrib %d", info, i);
-            return false;
-        }
-
-        if (checked_byteLength.value() < checked_sizeOfLastElement.value()) {
-            maxVertices = 0;
-            maxInstances = 0;
-            break;
-        }
-
-        CheckedUint32 checked_maxAllowedCount = ((checked_byteLength - checked_sizeOfLastElement) / vd.actualStride()) + 1;
-
-        if (!checked_maxAllowedCount.isValid()) {
-            ErrorInvalidOperation("%s: integer overflow occured while checking vertex attrib %d", info, i);
-            return false;
-        }
-
-        if (vd.divisor == 0) {
-            maxVertices = std::min(maxVertices, checked_maxAllowedCount.value());
-            hasPerVertex = true;
-        } else {
-            maxInstances = std::min(maxInstances, checked_maxAllowedCount.value() / vd.divisor);
-        }
-    }
-
-    mBufferFetchingIsVerified = true;
-    mBufferFetchingHasPerVertex = hasPerVertex;
-    mMaxFetchedVertices = maxVertices;
-    mMaxFetchedInstances = maxInstances;
-
-    return true;
-}
-
diff --git a/content/canvas/src/WebGLFramebuffer.cpp b/content/canvas/src/WebGLFramebuffer.cpp
index a9e55f238e6dbb63973a874a0355d0020cdd22d1..401f10f07bb21364ca2a13517b282d44e6f28efa 100644
--- a/content/canvas/src/WebGLFramebuffer.cpp
+++ b/content/canvas/src/WebGLFramebuffer.cpp
@@ -890,7 +890,7 @@ FinalizeDrawAndReadBuffers(GLContext* aGL, bool aColorBufferDefined)
     //
     // Note that this test is not performed if OpenGL 4.2 or ARB_ES2_compatibility is
     // available.
-    if (aGL->IsGLES2() ||
+    if (aGL->IsGLES() ||
         aGL->IsSupported(GLFeature::ES2_compatibility) ||
         aGL->IsAtLeast(ContextProfile::OpenGL, 420))
     {
diff --git a/content/canvas/src/WebGLRenderbuffer.cpp b/content/canvas/src/WebGLRenderbuffer.cpp
index 793ba63ad9956e97bad1ad99e390ec26d4bba4bf..5910f08e0fdeb0d77eb16b9f9e3cd675a248c538 100644
--- a/content/canvas/src/WebGLRenderbuffer.cpp
+++ b/content/canvas/src/WebGLRenderbuffer.cpp
@@ -16,7 +16,7 @@ using namespace mozilla::gl;
 static GLenum
 DepthStencilDepthFormat(GLContext* gl) {
     // We might not be able to get 24-bit, so let's pretend!
-    if (gl->IsGLES2() && !gl->IsExtensionSupported(gl::GLContext::OES_depth24))
+    if (gl->IsGLES() && !gl->IsExtensionSupported(gl::GLContext::OES_depth24))
         return LOCAL_GL_DEPTH_COMPONENT16;
 
     return LOCAL_GL_DEPTH_COMPONENT24;
diff --git a/content/canvas/src/WebGLTexture.cpp b/content/canvas/src/WebGLTexture.cpp
index 1974fc48352a71de8bc225d47b9e9e1aadf792f4..c4c68baff308a8e7de72b903d34135fca2f2c03a 100644
--- a/content/canvas/src/WebGLTexture.cpp
+++ b/content/canvas/src/WebGLTexture.cpp
@@ -125,7 +125,7 @@ WebGLTexture::Bind(GLenum aTarget) {
         // thanks to the WebKit people for finding this out: GL_TEXTURE_WRAP_R is not
         // present in GLES 2, but is present in GL and it seems as if for cube maps
         // we need to set it to GL_CLAMP_TO_EDGE to get the expected GLES behavior.
-        if (mTarget == LOCAL_GL_TEXTURE_CUBE_MAP && !mContext->gl->IsGLES2())
+        if (mTarget == LOCAL_GL_TEXTURE_CUBE_MAP && !mContext->gl->IsGLES())
             mContext->gl->fTexParameteri(mTarget, LOCAL_GL_TEXTURE_WRAP_R, LOCAL_GL_CLAMP_TO_EDGE);
     }
 
diff --git a/content/canvas/src/moz.build b/content/canvas/src/moz.build
index d103574501b42ad3dbff9d6c564269b9c8bcfd88..8479d6f69f6205997fa4f29af857e2c9cb092940 100644
--- a/content/canvas/src/moz.build
+++ b/content/canvas/src/moz.build
@@ -32,6 +32,7 @@ if CONFIG['MOZ_WEBGL']:
         'WebGLContext.cpp',
         'WebGLContextAsyncQueries.cpp',
         'WebGLContextBuffers.cpp',
+        'WebGLContextDraw.cpp',
         'WebGLContextExtensions.cpp',
         'WebGLContextFramebufferOperations.cpp',
         'WebGLContextGL.cpp',
diff --git a/dom/bindings/BindingUtils.h b/dom/bindings/BindingUtils.h
index a948b7e3840817b018a2bf1d85fc23235b09148d..29a8a43e3a15ce6ee2893ef684c791debb5150f1 100644
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -669,6 +669,22 @@ CouldBeDOMBinding(nsWrapperCache* aCache)
   return aCache->IsDOMBinding();
 }
 
+inline bool
+TryToOuterize(JSContext* cx, JS::MutableHandle<JS::Value> rval)
+{
+  if (js::IsInnerObject(&rval.toObject())) {
+    JS::Rooted<JSObject*> obj(cx, &rval.toObject());
+    obj = JS_ObjectToOuterObject(cx, obj);
+    if (!obj) {
+      return false;
+    }
+
+    rval.set(JS::ObjectValue(*obj));
+  }
+
+  return true;
+}
+
 // Make sure to wrap the given string value into the right compartment, as
 // needed.
 MOZ_ALWAYS_INLINE
@@ -697,10 +713,10 @@ MaybeWrapObjectValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
     return JS_WrapValue(cx, rval);
   }
 
-  // We're same-compartment. If we're a WebIDL object, we're done.
+  // We're same-compartment, but even then we might need to wrap
+  // objects specially.  Check for that.
   if (IsDOMObject(obj)) {
-    rval.set(JS::ObjectValue(*obj));
-    return true;
+    return TryToOuterize(cx, rval);
   }
 
   // It's not a WebIDL object.  But it might be an XPConnect one, in which case
@@ -821,14 +837,17 @@ WrapNewBindingObject(JSContext* cx, JS::Handle<JSObject*> scope, T* value,
   MOZ_ASSERT(js::IsObjectInContextCompartment(scope, cx));
 #endif
 
+  rval.set(JS::ObjectValue(*obj));
+
   bool sameCompartment =
     js::GetObjectCompartment(obj) == js::GetContextCompartment(cx);
   if (sameCompartment && couldBeDOMBinding) {
-    rval.set(JS::ObjectValue(*obj));
-    return true;
+    // We only need to outerize Window objects, so anything inheriting from
+    // nsGlobalWindow (which inherits from EventTarget itself).
+    return IsBaseOf<nsGlobalWindow, T>::value || IsSame<EventTarget, T>::value ?
+           TryToOuterize(cx, rval) : true;
   }
 
-  rval.set(JS::ObjectValue(*obj));
   return JS_WrapValue(cx, rval);
 }
 
diff --git a/dom/contacts/tests/test_migration_chrome.js b/dom/contacts/tests/test_migration_chrome.js
index 118f266e95ba3589642100d1f94aa1318b55e8e1..90b0d922ec1414d1cbb544b4daf3e7783258ceb8 100644
--- a/dom/contacts/tests/test_migration_chrome.js
+++ b/dom/contacts/tests/test_migration_chrome.js
@@ -14,18 +14,19 @@ Cu.import("resource://gre/modules/ContactService.jsm", imports);
 Cu.import("resource://gre/modules/Promise.jsm", imports);
 Cu.importGlobalProperties(["indexedDB"]);
 
-// |const| will not work because
-// it will make the Promise object immutable before assigning.
-// Using |let| and Object.freeze() instead.
-let {
+const {
   STORE_NAME,
   SAVED_GETALL_STORE_NAME,
   REVISION_STORE,
   DB_NAME,
   ContactService,
-  Promise
 } = imports;
-Object.freeze(imports);
+// |const| will not work because
+// it will make the Promise object immutable before assigning.
+// Using Object.defineProperty() instead.
+Object.defineProperty(this, "Promise", {
+  value: imports.Promise, writable: false, configurable: false
+});
 
 let DEBUG = false;
 function debug(str) {
diff --git a/dom/plugins/base/nsPluginTags.cpp b/dom/plugins/base/nsPluginTags.cpp
index e8c39857b54fbf3bd2d14689e582e2bee8744715..71e549c19686388be16a864d13df3de549721a1b 100644
--- a/dom/plugins/base/nsPluginTags.cpp
+++ b/dom/plugins/base/nsPluginTags.cpp
@@ -419,7 +419,7 @@ nsPluginTag::GetMimeTypes(uint32_t* aCount, char16_t*** aResults)
   *aCount = count;
 
   for (uint32_t i = 0; i < count; i++) {
-    (*aResults)[i] = ToNewUnicode(mMimeTypes[i]);
+    (*aResults)[i] = ToNewUnicode(NS_ConvertUTF8toUTF16(mMimeTypes[i]));
   }
 
   return NS_OK;
@@ -436,7 +436,7 @@ nsPluginTag::GetMimeDescriptions(uint32_t* aCount, char16_t*** aResults)
   *aCount = count;
 
   for (uint32_t i = 0; i < count; i++) {
-    (*aResults)[i] = ToNewUnicode(mMimeDescriptions[i]);
+    (*aResults)[i] = ToNewUnicode(NS_ConvertUTF8toUTF16(mMimeDescriptions[i]));
   }
 
   return NS_OK;
@@ -453,7 +453,7 @@ nsPluginTag::GetExtensions(uint32_t* aCount, char16_t*** aResults)
   *aCount = count;
 
   for (uint32_t i = 0; i < count; i++) {
-    (*aResults)[i] = ToNewUnicode(mExtensions[i]);
+    (*aResults)[i] = ToNewUnicode(NS_ConvertUTF8toUTF16(mExtensions[i]));
   }
 
   return NS_OK;
diff --git a/dom/plugins/test/mochitest/mochitest.ini b/dom/plugins/test/mochitest/mochitest.ini
index c620694236f662f52da6d8ec02ec30584b8cf2d3..a96f663cf20ab029d8584182d46ac9b28bc39b74 100644
--- a/dom/plugins/test/mochitest/mochitest.ini
+++ b/dom/plugins/test/mochitest/mochitest.ini
@@ -39,6 +39,7 @@ support-files =
 [test_bug863792.html]
 [test_bug967694.html]
 [test_bug985859.html]
+[test_bug986930.html]
 [test_cocoa_focus.html]
 skip-if = toolkit != "cocoa"
 support-files = cocoa_focus.html
diff --git a/dom/plugins/test/mochitest/test_bug986930.html b/dom/plugins/test/mochitest/test_bug986930.html
new file mode 100644
index 0000000000000000000000000000000000000000..620f93913fc50a6cfb57549dbc41cb0d6b777e06
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_bug986930.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="UTF-8"/>
+  <title>Test for Bug 986930</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="application/javascript" src="utils.js"></script>
+</head>
+<body>
+  <script class="testbody" type="application/javascript">
+    var testPlugin = getTestPlugin("Test Plug-in");
+
+    var mimeDescriptions = testPlugin.getMimeDescriptions({});
+
+    is(mimeDescriptions[0], "Test \u2122 mimetype",
+       "Plugin should handle non-ascii mime description");
+  </script>
+</body>
+</html>
diff --git a/dom/plugins/test/testplugin/Info.plist b/dom/plugins/test/testplugin/Info.plist
index e592c2c2d1edcc7570da693231c9caa12485445f..dc6aa5cec3942711923f26122d6a099c63e51471 100644
--- a/dom/plugins/test/testplugin/Info.plist
+++ b/dom/plugins/test/testplugin/Info.plist
@@ -31,7 +31,7 @@
 				<string>tst</string>
 			</array>
 			<key>WebPluginTypeDescription</key>
-			<string>Test mimetype</string>
+			<string>Test â„¢ mimetype</string>
 		</dict>
 	</dict>
 </dict>
diff --git a/dom/plugins/test/testplugin/nptest.rc b/dom/plugins/test/testplugin/nptest.rc
index a7676f83eb3d181dd942e8e758306f8173cc6021..948fb846ef5268315a18f25258a0605d458a1c5b 100644
--- a/dom/plugins/test/testplugin/nptest.rc
+++ b/dom/plugins/test/testplugin/nptest.rc
@@ -26,7 +26,7 @@ BEGIN
             VALUE "CompanyName", "mozilla.org"
             VALUE "FileDescription", L"Plug-in for testing purposes.\x2122 (\x0939\x093f\x0928\x094d\x0926\x0940 \x4e2d\x6587 \x0627\x0644\x0639\x0631\x0628\x064a\x0629)"
             VALUE "FileExtents", "tst"
-            VALUE "FileOpenName", "Test mimetype"
+            VALUE "FileOpenName", L"Test \x2122 mimetype"
             VALUE "FileVersion", "1.0"
             VALUE "InternalName", "nptest"
             VALUE "MIMEType", "application/x-test"
diff --git a/dom/plugins/test/testplugin/nptest_name.cpp b/dom/plugins/test/testplugin/nptest_name.cpp
index 3b152c703ffd07e8fb857dc63e2d207f2aadaa95..f9b57dfa8f22330944e77da5f29438fbb73295ae 100644
--- a/dom/plugins/test/testplugin/nptest_name.cpp
+++ b/dom/plugins/test/testplugin/nptest_name.cpp
@@ -3,4 +3,4 @@ const char *sPluginDescription = "Plug-in for testing purposes.\xE2\x84\xA2 "  \
   "(\xe0\xa4\xb9\xe0\xa4\xbf\xe0\xa4\xa8\xe0\xa5\x8d\xe0\xa4\xa6\xe0\xa5\x80 " \
   "\xe4\xb8\xad\xe6\x96\x87 "                                                  \
   "\xd8\xa7\xd9\x84\xd8\xb9\xd8\xb1\xd8\xa8\xd9\x8a\xd8\xa9)";
-const char *sMimeDescription = "application/x-test:tst:Test mimetype";
+const char *sMimeDescription = "application/x-test:tst:Test \xE2\x84\xA2 mimetype";
diff --git a/dom/webidl/Window.webidl b/dom/webidl/Window.webidl
index a93225c44c4103ddce8ba9b8f62c60ae785afbb5..ca486a5e02ddd596a7ab2dd5076cd7760916d523 100644
--- a/dom/webidl/Window.webidl
+++ b/dom/webidl/Window.webidl
@@ -304,6 +304,9 @@ partial interface Window {
    */
   [Throws] readonly attribute unsigned long long mozPaintCount;
 
+  [Pure]
+           attribute EventHandler onwheel;
+
            attribute EventHandler ondevicemotion;
            attribute EventHandler ondeviceorientation;
            attribute EventHandler ondeviceproximity;
diff --git a/gfx/2d/2D.h b/gfx/2d/2D.h
index 7d4c6e0d7970821508b4b704936a21dcda46143e..8b96cbb3ff3ce8f53ddff2230b31697589e28c8f 100644
--- a/gfx/2d/2D.h
+++ b/gfx/2d/2D.h
@@ -336,6 +336,16 @@ public:
    * DataSourceSurface's data can be accessed directly.
    */
   virtual TemporaryRef<DataSourceSurface> GetDataSurface() = 0;
+
+  void AddUserData(UserDataKey *key, void *userData, void (*destroy)(void*)) {
+    mUserData.Add(key, userData, destroy);
+  }
+  void *GetUserData(UserDataKey *key) {
+    return mUserData.Get(key);
+  }
+
+protected:
+  UserData mUserData;
 };
 
 class DataSourceSurface : public SourceSurface
diff --git a/gfx/angle/Makefile.in b/gfx/angle/Makefile.in
index 847f96bffafe57c69604c933db60359a7203f5a0..7ef26dc555e116ba9f7ede55ce26fa1ca1093e85 100644
--- a/gfx/angle/Makefile.in
+++ b/gfx/angle/Makefile.in
@@ -5,7 +5,7 @@
 ifdef MOZ_ANGLE_RENDERER
 
 libs::
-ifdef MOZ_HAS_WINSDK_WITH_D3D
+ifdef MOZ_D3DCOMPILER_DLL_PATH
 	cp -fp "$(MOZ_D3DCOMPILER_DLL_PATH)" "$(DIST)/bin"
 else
 ifdef MOZ_D3DCOMPILER_CAB
diff --git a/gfx/angle/src/libGLESv2/Makefile.in b/gfx/angle/src/libGLESv2/Makefile.in
index 6dc82efa58c26b262a94e4e073065310cb86514f..27a47d5cca740c677fb81b153073c5bcacd2a72d 100644
--- a/gfx/angle/src/libGLESv2/Makefile.in
+++ b/gfx/angle/src/libGLESv2/Makefile.in
@@ -5,6 +5,8 @@
 ifndef GNU_CC
 # Enable unwind semantics for exception handlers in response to warning C4530.
 OS_CPPFLAGS += -EHsc
+else
+OS_CXXFLAGS := $(filter-out -fno-exceptions,$(OS_CXXFLAGS)) -fexceptions
 endif
 
 # End build_angle.gypi transcription.
@@ -15,19 +17,9 @@ ifndef MOZ_HAS_WINSDK_WITH_D3D
 CXXFLAGS += -I'$(MOZ_DIRECTX_SDK_PATH)/include'
 endif
 
-ifdef GNU_CC
-
-OS_CXXFLAGS := $(filter-out -fno-exceptions,$(OS_CXXFLAGS)) -fexceptions
-OS_LIBS += -ld3d9 -ldxguid
-
-else
-
 ifdef MOZ_HAS_WINSDK_WITH_D3D
-EXTRA_DSO_LDOPTS = d3d9.lib dxguid.lib delayimp.lib
+EXTRA_DSO_LDOPTS = $(call EXPAND_LIBNAME,d3d9 dxguid)
 else
-EXTRA_DSO_LDOPTS = '$(MOZ_DIRECTX_SDK_PATH)/lib/$(MOZ_DIRECTX_SDK_CPU_SUFFIX)/d3d9.lib' \
-                   '$(MOZ_DIRECTX_SDK_PATH)/lib/$(MOZ_DIRECTX_SDK_CPU_SUFFIX)/dxguid.lib' \
-                   delayimp.lib
-endif
-
+EXTRA_DSO_LDOPTS = $(call EXPAND_LIBNAME_PATH,d3d9 dxguid,$(MOZ_DIRECTX_SDK_PATH)/lib/$(MOZ_DIRECTX_SDK_CPU_SUFFIX))
 endif
+EXTRA_DSO_LDOPTS += $(call EXPAND_LIBNAME,delayimp)
diff --git a/gfx/gl/DecomposeIntoNoRepeatTriangles.h b/gfx/gl/DecomposeIntoNoRepeatTriangles.h
index 5730d249b1b22c65e8e947c7e925e1a7f30c3c5d..d65e9737bc0638b708c1ec78d02c850149186e79 100644
--- a/gfx/gl/DecomposeIntoNoRepeatTriangles.h
+++ b/gfx/gl/DecomposeIntoNoRepeatTriangles.h
@@ -47,10 +47,6 @@ public:
     InfallibleTArray<coord>& texCoords() {
         return mTexCoords;
     }
-
-    unsigned int elements() {
-        return mVertexCoords.Length();
-    }
 private:
     // Reserve inline storage for one quad (2 triangles, 3 coords).
     nsAutoTArray<coord, 6> mVertexCoords;
diff --git a/gfx/gl/GLBlitTextureImageHelper.cpp b/gfx/gl/GLBlitTextureImageHelper.cpp
index a647ef1f408d4e743652cefb3fca66cf3f861832..340a4b1b0aae6dc46098a511ce9f1b41468e0d3d 100644
--- a/gfx/gl/GLBlitTextureImageHelper.cpp
+++ b/gfx/gl/GLBlitTextureImageHelper.cpp
@@ -12,6 +12,7 @@
 #include "nsRect.h"
 #include "gfx2DGlue.h"
 #include "gfxUtils.h"
+#include "GLDrawRectHelper.h"
 
 namespace mozilla {
 namespace gl {
@@ -147,25 +148,10 @@ GLBlitTextureImageHelper::BlitTextureImage(TextureImage *aSrc, const nsIntRect&
             ScopedBindTextureUnit autoTexUnit(mGL, LOCAL_GL_TEXTURE0);
             ScopedBindTexture autoTex(mGL, aSrc->GetTextureID());
 
-            mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
-
-            mGL->fVertexAttribPointer(0, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, rects.vertCoords().Elements());
-            mGL->fVertexAttribPointer(1, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, rects.texCoords().Elements());
-
-            mGL->fEnableVertexAttribArray(0);
-            mGL->fEnableVertexAttribArray(1);
-
-            mGL->fDrawArrays(LOCAL_GL_TRIANGLES, 0, rects.elements());
-
-            mGL->fDisableVertexAttribArray(0);
-            mGL->fDisableVertexAttribArray(1);
-
+            mGL->DrawRectHelper()->DrawRects(0, 1, rects);
         } while (aSrc->NextTile());
     } while (aDst->NextTile());
 
-    mGL->fVertexAttribPointer(0, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, nullptr);
-    mGL->fVertexAttribPointer(1, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, nullptr);
-
     // unbind the previous texture from the framebuffer
     SetBlitFramebufferForDestTexture(0);
 
diff --git a/gfx/gl/GLContext.cpp b/gfx/gl/GLContext.cpp
index 47b6aa7595f8325271a8ba850495da593da542ff..415d6258e2f92f617a3f58a29611801f1ee15453 100644
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -13,6 +13,7 @@
 #include "GLBlitHelper.h"
 #include "GLBlitTextureImageHelper.h"
 #include "GLReadTexImageHelper.h"
+#include "GLDrawRectHelper.h"
 
 #include "gfxCrashReporterUtils.h"
 #include "gfxUtils.h"
@@ -483,7 +484,7 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
 
     // Load OpenGL ES 2.0 symbols, or desktop if we aren't using ES 2.
     if (mInitialized) {
-        if (IsGLES2()) {
+        if (IsGLES()) {
             SymLoadStruct symbols_ES2[] = {
                 { (PRFuncPtr*) &mSymbols.fGetShaderPrecisionFormat, { "GetShaderPrecisionFormat", nullptr } },
                 { (PRFuncPtr*) &mSymbols.fClearDepthf, { "ClearDepthf", nullptr } },
@@ -1337,7 +1338,7 @@ GLContext::ChooseGLFormats(const SurfaceCaps& caps) const
     // If we're on ES2 hardware and we have an explicit request for 16 bits of color or less
     // OR we don't support full 8-bit color, return a 4444 or 565 format.
     bool bpp16 = caps.bpp16;
-    if (IsGLES2()) {
+    if (IsGLES()) {
         if (!IsExtensionSupported(OES_rgb8_rgba8))
             bpp16 = true;
     } else {
@@ -1347,7 +1348,7 @@ GLContext::ChooseGLFormats(const SurfaceCaps& caps) const
     }
 
     if (bpp16) {
-        MOZ_ASSERT(IsGLES2());
+        MOZ_ASSERT(IsGLES());
         if (caps.alpha) {
             formats.color_texInternalFormat = LOCAL_GL_RGBA;
             formats.color_texFormat = LOCAL_GL_RGBA;
@@ -1363,11 +1364,11 @@ GLContext::ChooseGLFormats(const SurfaceCaps& caps) const
         formats.color_texType = LOCAL_GL_UNSIGNED_BYTE;
 
         if (caps.alpha) {
-            formats.color_texInternalFormat = IsGLES2() ? LOCAL_GL_RGBA : LOCAL_GL_RGBA8;
+            formats.color_texInternalFormat = IsGLES() ? LOCAL_GL_RGBA : LOCAL_GL_RGBA8;
             formats.color_texFormat = LOCAL_GL_RGBA;
             formats.color_rbFormat  = LOCAL_GL_RGBA8;
         } else {
-            formats.color_texInternalFormat = IsGLES2() ? LOCAL_GL_RGB : LOCAL_GL_RGB8;
+            formats.color_texInternalFormat = IsGLES() ? LOCAL_GL_RGB : LOCAL_GL_RGB8;
             formats.color_texFormat = LOCAL_GL_RGB;
             formats.color_rbFormat  = LOCAL_GL_RGB8;
         }
@@ -1386,12 +1387,12 @@ GLContext::ChooseGLFormats(const SurfaceCaps& caps) const
 
     // Be clear that these are 0 if unavailable.
     formats.depthStencil = 0;
-    if (!IsGLES2() || IsExtensionSupported(OES_packed_depth_stencil)) {
+    if (!IsGLES() || IsExtensionSupported(OES_packed_depth_stencil)) {
         formats.depthStencil = LOCAL_GL_DEPTH24_STENCIL8;
     }
 
     formats.depth = 0;
-    if (IsGLES2()) {
+    if (IsGLES()) {
         if (IsExtensionSupported(OES_depth24)) {
             formats.depth = LOCAL_GL_DEPTH_COMPONENT24;
         } else {
@@ -1685,6 +1686,7 @@ GLContext::MarkDestroyed()
         mBlitHelper = nullptr;
         mBlitTextureImageHelper = nullptr;
         mReadTexImageHelper = nullptr;
+        mDrawRectHelper = nullptr;
 
         mTexGarbageBin->GLContextTeardown();
     } else {
@@ -2010,6 +2012,16 @@ GLContext::ReadTexImageHelper()
     return mReadTexImageHelper;
 }
 
+GLDrawRectHelper*
+GLContext::DrawRectHelper()
+{
+    if (!mDrawRectHelper) {
+        mDrawRectHelper = new GLDrawRectHelper(this);
+    }
+
+    return mDrawRectHelper;
+}
+
 bool
 DoesStringMatch(const char* aString, const char *aWantedString)
 {
diff --git a/gfx/gl/GLContext.h b/gfx/gl/GLContext.h
index 32a291b8d33162286e5b424decc091cec6c9fe96..7b9e001cb930500e1a39aef9eee33c71821c9408 100644
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -71,6 +71,7 @@ namespace mozilla {
         class GLBlitTextureImageHelper;
         class GLReadTexImageHelper;
         class SharedSurface_GL;
+        class GLDrawRectHelper;
     }
 
     namespace layers {
@@ -287,16 +288,6 @@ public:
 
     virtual bool IsCurrent() = 0;
 
-    /**
-     * If this context is the GLES2 API, returns TRUE.
-     * This means that various GLES2 restrictions might be in effect (modulo
-     * extensions).
-     */
-    inline bool IsGLES2() const {
-        return IsAtLeast(ContextProfile::OpenGLES, 200);
-    }
-
-
 protected:
 
     bool mInitialized;
@@ -1779,7 +1770,7 @@ public:
 
 private:
     void raw_fGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) {
-        MOZ_ASSERT(IsGLES2());
+        MOZ_ASSERT(IsGLES());
 
         BEFORE_GL_CALL;
         ASSERT_SYMBOL_PRESENT(fGetShaderPrecisionFormat);
@@ -1789,7 +1780,7 @@ private:
 
 public:
     void fGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) {
-        if (IsGLES2()) {
+        if (IsGLES()) {
             raw_fGetShaderPrecisionFormat(shadertype, precisiontype, range, precision);
         } else {
             // Fall back to automatic values because almost all desktop hardware supports the OpenGL standard precisions.
@@ -1877,7 +1868,7 @@ public:
 
 private:
     void raw_fDepthRange(GLclampf a, GLclampf b) {
-        MOZ_ASSERT(!IsGLES2());
+        MOZ_ASSERT(!IsGLES());
 
         BEFORE_GL_CALL;
         ASSERT_SYMBOL_PRESENT(fDepthRange);
@@ -1886,7 +1877,7 @@ private:
     }
 
     void raw_fDepthRangef(GLclampf a, GLclampf b) {
-        MOZ_ASSERT(IsGLES2());
+        MOZ_ASSERT(IsGLES());
 
         BEFORE_GL_CALL;
         ASSERT_SYMBOL_PRESENT(fDepthRangef);
@@ -1895,7 +1886,7 @@ private:
     }
 
     void raw_fClearDepth(GLclampf v) {
-        MOZ_ASSERT(!IsGLES2());
+        MOZ_ASSERT(!IsGLES());
 
         BEFORE_GL_CALL;
         ASSERT_SYMBOL_PRESENT(fClearDepth);
@@ -1904,7 +1895,7 @@ private:
     }
 
     void raw_fClearDepthf(GLclampf v) {
-        MOZ_ASSERT(IsGLES2());
+        MOZ_ASSERT(IsGLES());
 
         BEFORE_GL_CALL;
         ASSERT_SYMBOL_PRESENT(fClearDepthf);
@@ -1914,7 +1905,7 @@ private:
 
 public:
     void fDepthRange(GLclampf a, GLclampf b) {
-        if (IsGLES2()) {
+        if (IsGLES()) {
             raw_fDepthRangef(a, b);
         } else {
             raw_fDepthRange(a, b);
@@ -1922,7 +1913,7 @@ public:
     }
 
     void fClearDepth(GLclampf v) {
-        if (IsGLES2()) {
+        if (IsGLES()) {
             raw_fClearDepthf(v);
         } else {
             raw_fClearDepth(v);
@@ -2735,11 +2726,13 @@ protected:
     ScopedDeletePtr<GLBlitHelper> mBlitHelper;
     ScopedDeletePtr<GLBlitTextureImageHelper> mBlitTextureImageHelper;
     ScopedDeletePtr<GLReadTexImageHelper> mReadTexImageHelper;
+    ScopedDeletePtr<GLDrawRectHelper> mDrawRectHelper;
 
 public:
     GLBlitHelper* BlitHelper();
     GLBlitTextureImageHelper* BlitTextureImageHelper();
     GLReadTexImageHelper* ReadTexImageHelper();
+    GLDrawRectHelper* DrawRectHelper();
 
     // Assumes shares are created by all sharing with the same global context.
     bool SharesWith(const GLContext* other) const {
diff --git a/gfx/gl/GLDrawRectHelper.cpp b/gfx/gl/GLDrawRectHelper.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d77eb981cb90b1ee4d02d04fdeb25554a23fff77
--- /dev/null
+++ b/gfx/gl/GLDrawRectHelper.cpp
@@ -0,0 +1,122 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set ts=8 sts=4 et sw=4 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "GLDrawRectHelper.h"
+#include "GLContext.h"
+#include "DecomposeIntoNoRepeatTriangles.h"
+
+namespace mozilla {
+namespace gl {
+
+static GLfloat quad[] = {
+    /* First quad vertices */
+    0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
+    /* Then quad texcoords */
+    0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
+};
+
+#define BUFFER_OFFSET(i) ((char *)nullptr + (i))
+
+GLDrawRectHelper::GLDrawRectHelper(GLContext *aGL)
+    : mGL(aGL)
+{
+    mGL->fGenBuffers(1, &mQuadVBO);
+    mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO);
+
+    mGL->fBufferData(LOCAL_GL_ARRAY_BUFFER, sizeof(quad), quad, LOCAL_GL_STATIC_DRAW);
+    mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
+}
+
+GLDrawRectHelper::~GLDrawRectHelper()
+{
+    mGL->fDeleteBuffers(1, &mQuadVBO);
+}
+
+void
+GLDrawRectHelper::DrawRect(GLuint aVertAttribIndex,
+                           GLuint aTexCoordAttribIndex)
+{
+    mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO);
+
+    mGL->fVertexAttribPointer(aVertAttribIndex,
+                              2, LOCAL_GL_FLOAT,
+                              LOCAL_GL_FALSE,
+                              0, BUFFER_OFFSET(0));
+    mGL->fEnableVertexAttribArray(aVertAttribIndex);
+
+    if (aTexCoordAttribIndex != GLuint(-1)) {
+        mGL->fVertexAttribPointer(aTexCoordAttribIndex,
+                                  2, LOCAL_GL_FLOAT,
+                                  LOCAL_GL_FALSE,
+                                  0, BUFFER_OFFSET(sizeof(quad)/2));
+        mGL->fEnableVertexAttribArray(aTexCoordAttribIndex);
+    }
+
+    mGL->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
+
+    if (aTexCoordAttribIndex != GLuint(-1)) {
+        mGL->fDisableVertexAttribArray(aTexCoordAttribIndex);
+    }
+    mGL->fDisableVertexAttribArray(aVertAttribIndex);
+
+    mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
+}
+
+void
+GLDrawRectHelper::DrawRects(GLuint aVertAttribIndex,
+                            GLuint aTexCoordAttribIndex,
+                            RectTriangles& aRects)
+{
+    GLsizei bytes = aRects.vertCoords().Length() * 2 * sizeof(GLfloat);
+    GLsizei total = bytes;
+    if (aTexCoordAttribIndex != GLuint(-1)) {
+        total *= 2;
+    }
+
+    GLuint vbo;
+    mGL->fGenBuffers(1, &vbo);
+    mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, vbo);
+    mGL->fBufferData(LOCAL_GL_ARRAY_BUFFER,
+                     total,
+                     nullptr,
+                     LOCAL_GL_STREAM_DRAW);
+
+    mGL->fBufferSubData(LOCAL_GL_ARRAY_BUFFER,
+                        0,
+                        bytes,
+                        aRects.vertCoords().Elements());
+    mGL->fVertexAttribPointer(aVertAttribIndex,
+                              2, LOCAL_GL_FLOAT,
+                              LOCAL_GL_FALSE,
+                              0, BUFFER_OFFSET(0));
+    mGL->fEnableVertexAttribArray(aVertAttribIndex);
+
+    if (aTexCoordAttribIndex != GLuint(-1)) {
+        mGL->fBufferSubData(LOCAL_GL_ARRAY_BUFFER,
+                            bytes,
+                            bytes,
+                            aRects.texCoords().Elements());
+        mGL->fVertexAttribPointer(aTexCoordAttribIndex,
+                                  2, LOCAL_GL_FLOAT,
+                                  LOCAL_GL_FALSE,
+                                  0, BUFFER_OFFSET(bytes));
+        mGL->fEnableVertexAttribArray(aTexCoordAttribIndex);
+    }
+
+    mGL->fDrawArrays(LOCAL_GL_TRIANGLES, 0, aRects.vertCoords().Length());
+
+    if (aTexCoordAttribIndex != GLuint(-1)) {
+        mGL->fDisableVertexAttribArray(aTexCoordAttribIndex);
+    }
+    mGL->fDisableVertexAttribArray(aVertAttribIndex);
+
+    mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
+
+    mGL->fDeleteBuffers(1, &vbo);
+}
+
+}
+}
diff --git a/gfx/gl/GLDrawRectHelper.h b/gfx/gl/GLDrawRectHelper.h
new file mode 100644
index 0000000000000000000000000000000000000000..7694a7f7e4617b8c5cbc99557f7df9185fa0f8be
--- /dev/null
+++ b/gfx/gl/GLDrawRectHelper.h
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set ts=8 sts=4 et sw=4 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef GLDRAWRECTHELPER_H_
+#define GLDRAWRECTHELPER_H_
+
+#include "GLContextTypes.h"
+#include "GLConsts.h"
+
+namespace mozilla {
+namespace gl {
+
+class GLContext;
+class RectTriangles;
+
+/** Helper to draw rectangles to the frame buffer. */
+class GLDrawRectHelper MOZ_FINAL
+{
+public:
+    GLDrawRectHelper(GLContext* aGL);
+    ~GLDrawRectHelper();
+
+    void DrawRect(GLuint aVertAttribIndex,
+                  GLuint aTexCoordAttribIndex);
+    void DrawRects(GLuint aVertAttribIndex,
+                   GLuint aTexCoordAttribIndex,
+                   RectTriangles& aRects);
+
+private:
+    // The GLContext is the sole owner of the GLDrawHelper.
+    GLContext* mGL;
+    GLuint mQuadVBO;
+};
+
+}
+}
+
+#endif // GLDRAWRECTHELPER_H_
diff --git a/gfx/gl/GLReadTexImageHelper.cpp b/gfx/gl/GLReadTexImageHelper.cpp
index 778a441411e307d14790871eeb2d3dbbf47a54df..85b3c045a6adf2b73bff7300ffab3ebfc1af7216 100644
--- a/gfx/gl/GLReadTexImageHelper.cpp
+++ b/gfx/gl/GLReadTexImageHelper.cpp
@@ -168,7 +168,7 @@ GetActualReadFormats(GLContext* gl,
     }
 
     bool fallback = true;
-    if (gl->IsGLES2()) {
+    if (gl->IsGLES()) {
         GLenum auxFormat = 0;
         GLenum auxType = 0;
 
@@ -209,6 +209,10 @@ GetActualReadFormats(GLContext* gl,
 static void SwapRAndBComponents(DataSourceSurface* surf)
 {
   uint8_t *row = surf->GetData();
+  if (!row) {
+      MOZ_ASSERT(false, "SwapRAndBComponents: Failed to get data from DataSourceSurface.");
+      return;
+  }
 
   size_t rowBytes = surf->GetSize().width*4;
   size_t rowHole = surf->Stride() - rowBytes;
@@ -764,7 +768,7 @@ GLReadTexImageHelper::ReadTexImage(GLuint aTextureId,
         mGL->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, rb);
 
         GLenum rbInternalFormat =
-            mGL->IsGLES2()
+            mGL->IsGLES()
                 ? (mGL->IsExtensionSupported(GLContext::OES_rgb8_rgba8) ? LOCAL_GL_RGBA8 : LOCAL_GL_RGBA4)
                 : LOCAL_GL_RGBA;
         mGL->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, rbInternalFormat, aSize.width, aSize.height);
diff --git a/gfx/gl/GLUploadHelpers.cpp b/gfx/gl/GLUploadHelpers.cpp
index 3b3498885c67cfde19adab4b642eb3cd23de7d87..fc36719b9f250992a839e3e377a4291a49013ab1 100644
--- a/gfx/gl/GLUploadHelpers.cpp
+++ b/gfx/gl/GLUploadHelpers.cpp
@@ -225,7 +225,7 @@ TexSubImage2DHelper(GLContext *gl,
                     GLint pixelsize, GLenum format,
                     GLenum type, const GLvoid* pixels)
 {
-    if (gl->IsGLES2()) {
+    if (gl->IsGLES()) {
         if (stride == width * pixelsize) {
             gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT,
                              std::min(GetAddressAlignment((ptrdiff_t)pixels),
@@ -278,7 +278,7 @@ TexImage2DHelper(GLContext *gl,
                  GLint pixelsize, GLint border, GLenum format,
                  GLenum type, const GLvoid *pixels)
 {
-    if (gl->IsGLES2()) {
+    if (gl->IsGLES()) {
 
         NS_ASSERTION(format == (GLenum)internalformat,
                     "format and internalformat not the same for glTexImage2D on GLES2");
diff --git a/gfx/gl/SkiaGLGlue.cpp b/gfx/gl/SkiaGLGlue.cpp
index c1ad6f700598a470777abd5f5236cfa090e8c732..83b346c34a79435e20a721c101952fd32665a440 100755
--- a/gfx/gl/SkiaGLGlue.cpp
+++ b/gfx/gl/SkiaGLGlue.cpp
@@ -322,7 +322,7 @@ const GLubyte* glGetString_mozilla(GrGLenum name)
     // on the GL implementation and change them to match what GLContext actually exposes.
 
     if (name == LOCAL_GL_VERSION) {
-        if (sGLContext.get()->IsGLES2()) {
+        if (sGLContext.get()->IsGLES()) {
             return reinterpret_cast<const GLubyte*>("OpenGL ES 2.0");
         } else {
             return reinterpret_cast<const GLubyte*>("2.0");
@@ -336,7 +336,7 @@ const GLubyte* glGetString_mozilla(GrGLenum name)
         if (!extensionsStringBuilt) {
             extensionsString[0] = '\0';
 
-            if (sGLContext.get()->IsGLES2()) {
+            if (sGLContext.get()->IsGLES()) {
                 // OES is only applicable to GLES2
                 if (sGLContext.get()->IsExtensionSupported(GLContext::OES_packed_depth_stencil)) {
                     strcat(extensionsString, "GL_OES_packed_depth_stencil ");
@@ -384,7 +384,7 @@ const GLubyte* glGetString_mozilla(GrGLenum name)
         return reinterpret_cast<const GLubyte*>(extensionsString);
 
     } else if (name == LOCAL_GL_SHADING_LANGUAGE_VERSION) {
-        if (sGLContext.get()->IsGLES2()) {
+        if (sGLContext.get()->IsGLES()) {
             return reinterpret_cast<const GLubyte*>("OpenGL ES GLSL ES 1.0");
         } else {
             return reinterpret_cast<const GLubyte*>("1.10");
@@ -770,7 +770,7 @@ static GrGLInterface* CreateGrGLInterfaceFromGLContext(GLContext* context)
     context->MakeCurrent();
 
     // We support both desktop GL and GLES2
-    if (context->IsGLES2()) {
+    if (context->IsGLES()) {
         i->fStandard = kGLES_GrGLStandard;
     } else {
         i->fStandard = kGL_GrGLStandard;
diff --git a/gfx/gl/moz.build b/gfx/gl/moz.build
index 04762ecb542784e33160d42c6b671e1d4fb79204..a375eec02f4b06b3c42d00239637512249a220b6 100644
--- a/gfx/gl/moz.build
+++ b/gfx/gl/moz.build
@@ -38,6 +38,7 @@ EXPORTS += [
     'GLContextSymbols.h',
     'GLContextTypes.h',
     'GLDefs.h',
+    'GLDrawRectHelper.h',
     'GLLibraryEGL.h',
     'GLLibraryLoader.h',
     'GLReadTexImageHelper.h',
@@ -123,6 +124,7 @@ UNIFIED_SOURCES += [
     'GLContextFeatures.cpp',
     'GLContextTypes.cpp',
     'GLDebugUtils.cpp',
+    'GLDrawRectHelper.cpp',
     'GLLibraryEGL.cpp',
     'GLLibraryLoader.cpp',
     'GLReadTexImageHelper.cpp',
diff --git a/gfx/layers/client/CanvasClient.cpp b/gfx/layers/client/CanvasClient.cpp
index dddc829dd4c044a46971fecf7e8fdabed1742638..746efb860f2d55a23d8b3a5261c40268096ad9e7 100644
--- a/gfx/layers/client/CanvasClient.cpp
+++ b/gfx/layers/client/CanvasClient.cpp
@@ -41,10 +41,6 @@ CanvasClient::CreateCanvasClient(CanvasClientType aType,
     aFlags |= TEXTURE_DEALLOCATE_CLIENT;
     return new CanvasClientSurfaceStream(aForwarder, aFlags);
   }
-  if (gfxPlatform::GetPlatform()->UseDeprecatedTextures()) {
-    aFlags |= TEXTURE_DEALLOCATE_CLIENT;
-    return new DeprecatedCanvasClient2D(aForwarder, aFlags);
-  }
   return new CanvasClient2D(aForwarder, aFlags);
 }
 
@@ -65,21 +61,12 @@ CanvasClient2D::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
                                                 : gfxContentType::COLOR_ALPHA;
     gfxImageFormat format
       = gfxPlatform::GetPlatform()->OptimalFormatForContent(contentType);
-    mBuffer = CreateTextureClientForDrawing(gfx::ImageFormatToSurfaceFormat(format),
-                                            TEXTURE_FLAGS_DEFAULT,
-                                            gfxPlatform::GetPlatform()->GetPreferredCanvasBackend(),
-                                            aSize);
-    bool allocSuccess = false;
-    if (mBuffer->AsTextureClientSurface()) {
-      allocSuccess = mBuffer->AsTextureClientSurface()->AllocateForSurface(aSize);
-    } else {
-      MOZ_ASSERT(mBuffer->AsTextureClientDrawTarget());
-      allocSuccess = mBuffer->AsTextureClientDrawTarget()->AllocateForSurface(aSize);
-    }
-    if (!allocSuccess) {
-      mBuffer = nullptr;
-      return;
-    }
+    mBuffer = CreateBufferTextureClient(gfx::ImageFormatToSurfaceFormat(format),
+                                        TEXTURE_FLAGS_DEFAULT,
+                                        gfxPlatform::GetPlatform()->GetPreferredCanvasBackend());
+    MOZ_ASSERT(mBuffer->AsTextureClientSurface());
+    mBuffer->AsTextureClientSurface()->AllocateForSurface(aSize);
+
     bufferCreated = true;
   }
 
@@ -90,18 +77,8 @@ CanvasClient2D::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
   bool updated = false;
   {
     // Restrict drawTarget to a scope so that terminates before Unlock.
-    nsRefPtr<gfxASurface> surface;
-    if (mBuffer->AsTextureClientSurface()) {
-      surface = mBuffer->AsTextureClientSurface()->GetAsSurface();
-    } else {
-      RefPtr<gfx::DrawTarget> dt
-        = mBuffer->AsTextureClientDrawTarget()->GetAsDrawTarget();
-      if (dt) {
-        surface = gfxPlatform::GetPlatform()->CreateThebesSurfaceAliasForDrawTarget_hack(dt);
-      }
-      // the DrawTarget will be kept alive until mBuffer->Unlock() so it's
-      // OK to let go of dt before we destroy surface.
-    }
+    nsRefPtr<gfxASurface> surface =
+      mBuffer->AsTextureClientSurface()->GetAsSurface();
     if (surface) {
       aLayer->DeprecatedUpdateSurface(surface);
       updated = true;
@@ -199,133 +176,5 @@ CanvasClientSurfaceStream::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
   aLayer->Painted();
 }
 
-void
-DeprecatedCanvasClient2D::Updated()
-{
-  mForwarder->UpdateTexture(this, 1, mDeprecatedTextureClient->LockSurfaceDescriptor());
-}
-
-
-DeprecatedCanvasClient2D::DeprecatedCanvasClient2D(CompositableForwarder* aFwd,
-                                                   TextureFlags aFlags)
-: CanvasClient(aFwd, aFlags)
-{
-  mTextureInfo.mCompositableType = BUFFER_IMAGE_SINGLE;
-}
-
-void
-DeprecatedCanvasClient2D::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
-{
-  bool isOpaque = (aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE);
-  gfxContentType contentType = isOpaque
-                                              ? gfxContentType::COLOR
-                                              : gfxContentType::COLOR_ALPHA;
-
-  if (!mDeprecatedTextureClient) {
-    mDeprecatedTextureClient = CreateDeprecatedTextureClient(TEXTURE_CONTENT, contentType);
-    if (!mDeprecatedTextureClient) {
-      mDeprecatedTextureClient = CreateDeprecatedTextureClient(TEXTURE_FALLBACK, contentType);
-      if (!mDeprecatedTextureClient) {
-        NS_WARNING("Could not create texture client");
-        return;
-      }
-    }
-  }
-
-  if (!mDeprecatedTextureClient->EnsureAllocated(aSize, contentType)) {
-    // We might already be on the fallback texture client if we couldn't create a
-    // better one above. In which case this call to create is wasted. But I don't
-    // think this will happen often enough to be worth complicating the code with
-    // further checks.
-    mDeprecatedTextureClient = CreateDeprecatedTextureClient(TEXTURE_FALLBACK, contentType);
-    MOZ_ASSERT(mDeprecatedTextureClient, "Failed to create texture client");
-    if (!mDeprecatedTextureClient->EnsureAllocated(aSize, contentType)) {
-      NS_WARNING("Could not allocate texture client");
-      return;
-    }
-  }
-
-  gfxASurface* surface = mDeprecatedTextureClient->LockSurface();
-  aLayer->DeprecatedUpdateSurface(surface);
-  mDeprecatedTextureClient->Unlock();
-}
-
-void
-DeprecatedCanvasClientSurfaceStream::Updated()
-{
-  mForwarder->UpdateTextureNoSwap(this, 1, mDeprecatedTextureClient->LockSurfaceDescriptor());
-}
-
-
-DeprecatedCanvasClientSurfaceStream::DeprecatedCanvasClientSurfaceStream(CompositableForwarder* aFwd,
-                                                                         TextureFlags aFlags)
-: CanvasClient(aFwd, aFlags)
-{
-  mTextureInfo.mCompositableType = BUFFER_IMAGE_SINGLE;
-}
-
-void
-DeprecatedCanvasClientSurfaceStream::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
-{
-  if (!mDeprecatedTextureClient) {
-    mDeprecatedTextureClient = CreateDeprecatedTextureClient(TEXTURE_STREAM_GL,
-                                                             aLayer->GetSurfaceMode() == SurfaceMode::SURFACE_OPAQUE
-                                                               ? gfxContentType::COLOR
-                                                               : gfxContentType::COLOR_ALPHA);
-    MOZ_ASSERT(mDeprecatedTextureClient, "Failed to create texture client");
-  }
-
-  NS_ASSERTION(aLayer->mGLContext, "CanvasClientSurfaceStream should only be used with GL canvases");
-
-  // the content type won't be used
-  mDeprecatedTextureClient->EnsureAllocated(aSize, gfxContentType::COLOR);
-
-  GLScreenBuffer* screen = aLayer->mGLContext->Screen();
-  SurfaceStream* stream = nullptr;
-
-  if (aLayer->mStream) {
-    stream = aLayer->mStream;
-    stream->CopySurfaceToProducer(aLayer->mTextureSurface, aLayer->mFactory);
-    stream->SwapProducer(aLayer->mFactory, gfx::IntSize(aSize.width, aSize.height));
-  } else {
-    stream = screen->Stream();
-  }
-
-  bool isCrossProcess = !(XRE_GetProcessType() == GeckoProcessType_Default);
-  if (isCrossProcess) {
-    // swap staging -> consumer so we can send it to the compositor
-    SharedSurface* surf = stream->SwapConsumer();
-    if (!surf) {
-      printf_stderr("surf is null post-SwapConsumer!\n");
-      return;
-    }
-
-#ifdef MOZ_WIDGET_GONK
-    if (surf->Type() != SharedSurfaceType::Gralloc) {
-      printf_stderr("Unexpected non-Gralloc SharedSurface in IPC path!");
-      return;
-    }
-
-    SharedSurface_Gralloc* grallocSurf = SharedSurface_Gralloc::Cast(surf);
-    //XXX todo
-    //mDeprecatedTextureClient->SetDescriptor(grallocSurf->GetDescriptor());
-#else
-    printf_stderr("isCrossProcess, but not MOZ_WIDGET_GONK! Someone needs to write some code!");
-    MOZ_ASSERT(false);
-#endif
-  } else {
-    SurfaceStreamHandle handle = stream->GetShareHandle();
-    mDeprecatedTextureClient->SetDescriptor(SurfaceStreamDescriptor(handle, false));
-
-    // Bug 894405
-    //
-    // Ref this so the SurfaceStream doesn't disappear unexpectedly. The
-    // Compositor will need to unref it when finished.
-    aLayer->mGLContext->AddRef();
-  }
-
-  aLayer->Painted();
-}
-
 }
 }
diff --git a/gfx/layers/client/CanvasClient.h b/gfx/layers/client/CanvasClient.h
index de6c983e9613cafaa33588e60f52a882037c2c3c..e4b2daf36646d9d204efaa06abbe7447b56f12cb 100644
--- a/gfx/layers/client/CanvasClient.h
+++ b/gfx/layers/client/CanvasClient.h
@@ -132,56 +132,6 @@ private:
   RefPtr<TextureClient> mBuffer;
 };
 
-class DeprecatedCanvasClient2D : public CanvasClient
-{
-public:
-  DeprecatedCanvasClient2D(CompositableForwarder* aLayerForwarder,
-                           TextureFlags aFlags);
-
-  TextureInfo GetTextureInfo() const MOZ_OVERRIDE
-  {
-    return mTextureInfo;
-  }
-
-  virtual void Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer);
-  virtual void Updated() MOZ_OVERRIDE;
-
-  virtual void SetDescriptorFromReply(TextureIdentifier aTextureId,
-                                      const SurfaceDescriptor& aDescriptor) MOZ_OVERRIDE
-  {
-    mDeprecatedTextureClient->SetDescriptorFromReply(aDescriptor);
-  }
-
-private:
-  RefPtr<DeprecatedTextureClient> mDeprecatedTextureClient;
-};
-
-// Used for GL canvases where we don't need to do any readback, i.e., with a
-// GL backend.
-class DeprecatedCanvasClientSurfaceStream : public CanvasClient
-{
-public:
-  DeprecatedCanvasClientSurfaceStream(CompositableForwarder* aFwd,
-                                      TextureFlags aFlags);
-
-  TextureInfo GetTextureInfo() const MOZ_OVERRIDE
-  {
-    return mTextureInfo;
-  }
-
-  virtual void Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer);
-  virtual void Updated() MOZ_OVERRIDE;
-
-  virtual void SetDescriptorFromReply(TextureIdentifier aTextureId,
-                                      const SurfaceDescriptor& aDescriptor) MOZ_OVERRIDE
-  {
-    mDeprecatedTextureClient->SetDescriptorFromReply(aDescriptor);
-  }
-
-private:
-  RefPtr<DeprecatedTextureClient> mDeprecatedTextureClient;
-};
-
 }
 }
 
diff --git a/gfx/layers/client/ClientTiledThebesLayer.cpp b/gfx/layers/client/ClientTiledThebesLayer.cpp
index d46dc0be1432ad332aba90336edc9d63e5e0ad76..2c0fddadfc106c3b664b0929e5212ea255abc4bd 100644
--- a/gfx/layers/client/ClientTiledThebesLayer.cpp
+++ b/gfx/layers/client/ClientTiledThebesLayer.cpp
@@ -216,13 +216,17 @@ ClientTiledThebesLayer::RenderLayer()
     ToClientLayer(GetMaskLayer())->RenderLayer();
   }
 
+  bool isFixed = GetIsFixedPosition() || GetParent()->GetIsFixedPosition();
+
   // Fast path for no progressive updates, no low-precision updates and no
-  // critical display-port set, or no display-port set.
+  // critical display-port set, or no display-port set, or this is a fixed
+  // position layer/contained in a fixed position layer
   const FrameMetrics& parentMetrics = GetParent()->GetFrameMetrics();
   if ((!gfxPrefs::UseProgressiveTilePainting() &&
        !gfxPrefs::UseLowPrecisionBuffer() &&
        parentMetrics.mCriticalDisplayPort.IsEmpty()) ||
-       parentMetrics.mDisplayPort.IsEmpty()) {
+       parentMetrics.mDisplayPort.IsEmpty() ||
+       isFixed) {
     mValidRegion = mVisibleRegion;
 
     NS_ASSERTION(!ClientManager()->IsRepeatTransaction(), "Didn't paint our mask layer");
diff --git a/gfx/layers/client/ContentClient.cpp b/gfx/layers/client/ContentClient.cpp
index 369a6970fe2010c93f9a45372ec8bda747693d7f..0e97c6329822376ec8346c629b94970793fda346 100644
--- a/gfx/layers/client/ContentClient.cpp
+++ b/gfx/layers/client/ContentClient.cpp
@@ -38,6 +38,22 @@ using namespace gfx;
 
 namespace layers {
 
+static TextureFlags TextureFlagsForRotatedContentBufferFlags(uint32_t aBufferFlags)
+{
+  TextureFlags result = 0;
+
+  if (aBufferFlags & RotatedContentBuffer::BUFFER_COMPONENT_ALPHA) {
+    result |= TEXTURE_COMPONENT_ALPHA;
+  }
+
+  if (aBufferFlags & RotatedContentBuffer::ALLOW_REPEAT) {
+    result |= TEXTURE_ALLOW_REPEAT;
+  }
+
+  return result;
+}
+
+
 /* static */ TemporaryRef<ContentClient>
 ContentClient::CreateContentClient(CompositableForwarder* aForwarder)
 {
@@ -51,7 +67,12 @@ ContentClient::CreateContentClient(CompositableForwarder* aForwarder)
 
   bool useDoubleBuffering = false;
   bool useDeprecatedTextures = true;
+  // XXX We need support for gralloc with non-deprecated textures content before
+  // we can use them with FirefoxOS (bug 946720). We need the same locking for
+  // Windows.
+#if !defined(XP_WIN)
   useDeprecatedTextures = gfxPlatform::GetPlatform()->UseDeprecatedTextures();
+#endif
 
 #ifdef XP_WIN
   if (backend == LayersBackend::LAYERS_D3D11) {
@@ -210,7 +231,7 @@ ContentClientRemoteBuffer::BuildTextureClients(SurfaceFormat aFormat,
 
   mSurfaceFormat = aFormat;
   mSize = gfx::IntSize(aRect.width, aRect.height);
-  mTextureInfo.mTextureFlags = aFlags & ~TEXTURE_DEALLOCATE_CLIENT;
+  mTextureInfo.mTextureFlags = TextureFlagsForRotatedContentBufferFlags(aFlags);
 
   if (!CreateAndAllocateTextureClient(mTextureClient, TEXTURE_ON_BLACK) ||
       !AddTextureClient(mTextureClient)) {
@@ -396,19 +417,18 @@ DeprecatedContentClientRemoteBuffer::BuildDeprecatedTextureClients(ContentType a
 
   mContentType = aType;
   mSize = gfx::IntSize(aRect.width, aRect.height);
-  mTextureInfo.mTextureFlags = aFlags & ~TEXTURE_DEALLOCATE_CLIENT;
+  mTextureInfo.mTextureFlags = TextureFlagsForRotatedContentBufferFlags(aFlags);
 
   if (!CreateAndAllocateDeprecatedTextureClient(mDeprecatedTextureClient)) {
     return;
   }
-  
+
   if (aFlags & BUFFER_COMPONENT_ALPHA) {
     if (!CreateAndAllocateDeprecatedTextureClient(mDeprecatedTextureClientOnWhite)) {
       mDeprecatedTextureClient->SetFlags(0);
       mDeprecatedTextureClient = nullptr;
       return;
     }
-    mTextureInfo.mTextureFlags |= TEXTURE_COMPONENT_ALPHA;
   }
 
   CreateFrontBufferAndNotify(aRect);
diff --git a/gfx/layers/client/TextureClient.cpp b/gfx/layers/client/TextureClient.cpp
index 91a94ca4ab6ff145416946f3383cd82bd4f624df..1035ce1590e3d2aa2513408e34b2e0e11ad551b6 100644
--- a/gfx/layers/client/TextureClient.cpp
+++ b/gfx/layers/client/TextureClient.cpp
@@ -282,10 +282,6 @@ TextureClient::CreateTextureClientForDrawing(ISurfaceAllocator* aAllocator,
     aMoz2DBackend = gfxPlatform::GetPlatform()->GetContentBackend();
   }
 
-#if defined(XP_WIN) || defined(MOZ_WIDGET_GONK)
-  int32_t maxTextureSize = aAllocator->GetMaxTextureSize();
-#endif
-
   RefPtr<TextureClient> result;
 
 #ifdef XP_WIN
@@ -294,10 +290,9 @@ TextureClient::CreateTextureClientForDrawing(ISurfaceAllocator* aAllocator,
       (aMoz2DBackend == gfx::BackendType::DIRECT2D ||
         aMoz2DBackend == gfx::BackendType::DIRECT2D1_1) &&
       gfxWindowsPlatform::GetPlatform()->GetD2DDevice() &&
+
       !(aTextureFlags & TEXTURE_ALLOC_FALLBACK)) {
-    if (aSizeHint.width <= maxTextureSize && aSizeHint.height <= maxTextureSize) {
-      result = new TextureClientD3D11(aFormat, aTextureFlags);
-    }
+    result = new TextureClientD3D11(aFormat, aTextureFlags);
   }
   if (parentBackend == LayersBackend::LAYERS_D3D9 &&
       aMoz2DBackend == gfx::BackendType::CAIRO &&
@@ -342,6 +337,7 @@ TextureClient::CreateTextureClientForDrawing(ISurfaceAllocator* aAllocator,
   if (!DisableGralloc(aFormat, aSizeHint)) {
     // Don't allow Gralloc texture clients to exceed the maximum texture size.
     // BufferTextureClients have code to handle tiling the surface client-side.
+    int32_t maxTextureSize = aAllocator->GetMaxTextureSize();
     if (aSizeHint.width <= maxTextureSize && aSizeHint.height <= maxTextureSize) {
       result = new GrallocTextureClientOGL(aAllocator, aFormat, aMoz2DBackend,
                                            aTextureFlags);
diff --git a/gfx/layers/composite/ThebesLayerComposite.cpp b/gfx/layers/composite/ThebesLayerComposite.cpp
index 7db09829d9efe05c1a3edb2f59ba9c5629e8f39b..40b6102a9e0511546363779e1dee9360f24cfeb0 100644
--- a/gfx/layers/composite/ThebesLayerComposite.cpp
+++ b/gfx/layers/composite/ThebesLayerComposite.cpp
@@ -132,6 +132,7 @@ ThebesLayerComposite::RenderLayer(const nsIntRect& aClipRect)
 
   EffectChain effectChain(this);
   LayerManagerComposite::AutoAddMaskEffect autoMaskEffect(mMaskLayer, effectChain);
+
   nsIntRegion visibleRegion = GetEffectiveVisibleRegion();
 
   TiledLayerProperties tiledLayerProps;
diff --git a/gfx/layers/d3d11/TextureD3D11.cpp b/gfx/layers/d3d11/TextureD3D11.cpp
index b5b01d1c7df47defa8ae41d13e8cacb87c68f90b..801cee6827863cac1637b6816294bd81e3f9f736 100644
--- a/gfx/layers/d3d11/TextureD3D11.cpp
+++ b/gfx/layers/d3d11/TextureD3D11.cpp
@@ -171,10 +171,6 @@ bool
 TextureClientD3D11::Lock(OpenMode aMode)
 {
   MOZ_ASSERT(!mIsLocked, "The Texture is already locked!");
-  if (!mTexture) {
-    return false;
-  }
-
   LockD3DTexture(mTexture.get());
   mIsLocked = true;
 
@@ -215,10 +211,6 @@ TextureClientD3D11::GetAsDrawTarget()
     return mDrawTarget;
   }
 
-  if (!mTexture) {
-    return nullptr;
-  }
-
   mDrawTarget = Factory::CreateDrawTargetForD3D10Texture(mTexture, mFormat);
   return mDrawTarget;
 }
@@ -229,7 +221,7 @@ TextureClientD3D11::AllocateForSurface(gfx::IntSize aSize, TextureAllocationFlag
   mSize = aSize;
   ID3D10Device* device = gfxWindowsPlatform::GetPlatform()->GetD3D10Device();
 
-  CD3D10_TEXTURE2D_DESC newDesc(DXGI_FORMAT_B8G8R8A8_UNORM,
+  CD3D10_TEXTURE2D_DESC newDesc(SurfaceFormatToDXGIFormat(mFormat),
                                 aSize.width, aSize.height, 1, 1,
                                 D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE);
 
@@ -337,10 +329,10 @@ DataTextureSourceD3D11::Update(DataSourceSurface* aSurface,
                                nsIntRegion* aDestRegion,
                                IntPoint* aSrcOffset)
 {
-  // Right now we only support full surface update. If aDestRegion is provided,
-  // It will be ignered. Incremental update with a source offset is only used
-  // on Mac so it is not clear that we ever will need to support it for D3D.
-  MOZ_ASSERT(!aSrcOffset);
+  // Right now we only support null aDestRegion and aSrcOffset (which means)
+  // full surface update. Incremental update is only used on Mac so it is
+  // not clear that we ever will need to support it for D3D.
+  MOZ_ASSERT(!aDestRegion && !aSrcOffset);
   MOZ_ASSERT(aSurface);
 
   if (!mCompositor || !mCompositor->GetDevice()) {
diff --git a/gfx/layers/d3d9/TextureD3D9.cpp b/gfx/layers/d3d9/TextureD3D9.cpp
index 61d44133645b30e00d35727039faac1ca09655e7..e8016e75b32f431f3bbfab7b5be78f85acdea6f0 100644
--- a/gfx/layers/d3d9/TextureD3D9.cpp
+++ b/gfx/layers/d3d9/TextureD3D9.cpp
@@ -1061,10 +1061,10 @@ DataTextureSourceD3D9::Update(gfx::DataSourceSurface* aSurface,
                               nsIntRegion* aDestRegion,
                               gfx::IntPoint* aSrcOffset)
 {
-  // Right now we only support full surface update. If aDestRegion is provided,
-  // It will be ignered. Incremental update with a source offset is only used
-  // on Mac so it is not clear that we ever will need to support it for D3D.
-  MOZ_ASSERT(!aSrcOffset);
+  // Right now we only support null aDestRegion and aSrcOffset (which means
+  // full surface update). Incremental update is only used on Mac so it is
+  // not clear that we ever will need to support it for D3D.
+  MOZ_ASSERT(!aDestRegion && !aSrcOffset);
 
   if (!mCompositor || !mCompositor->device()) {
     NS_WARNING("No D3D device to update the texture.");
diff --git a/gfx/layers/ipc/AsyncPanZoomController.cpp b/gfx/layers/ipc/AsyncPanZoomController.cpp
index 26eeab9b20cf448e6a89464f0560851d1e3b51de..4f1364307cc92886ca724089afc104c3c8d6f836 100644
--- a/gfx/layers/ipc/AsyncPanZoomController.cpp
+++ b/gfx/layers/ipc/AsyncPanZoomController.cpp
@@ -20,7 +20,7 @@
 #include "base/message_loop.h"          // for MessageLoop
 #include "base/task.h"                  // for NewRunnableMethod, etc
 #include "base/tracked.h"               // for FROM_HERE
-#include "gfxPrefs.h"                   // for gfxPrefs::UseProgressiveTilePainting
+#include "gfxPrefs.h"                   // for gfxPrefs
 #include "gfxTypes.h"                   // for gfxFloat
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
 #include "mozilla/BasicEvents.h"        // for Modifiers, MODIFIER_*
@@ -133,18 +133,100 @@ namespace layers {
 
 typedef mozilla::layers::AllowedTouchBehavior AllowedTouchBehavior;
 
-/**
- * Specifies whether touch-action property is in force.
- */
-static bool gTouchActionPropertyEnabled = false;
-
-/**
+/*
+ * The following prefs are used to control the behaviour of the APZC.
+ * The default values are provided in gfxPrefs.h.
+ *
+ * "apz.allow-checkerboarding"
+ * Pref that allows or disallows checkerboarding
+ *
+ * "apz.asyncscroll.throttle"
+ * The time period in ms that throttles mozbrowserasyncscroll event.
+ *
+ * "apz.asyncscroll.timeout"
+ * The timeout in ms for mAsyncScrollTimeoutTask delay task.
+ *
+ * "apz.axis_lock_mode"
+ * The preferred axis locking style. See AxisLockMode for possible values.
+ *
+ * "apz.content_response_timeout"
+ * Amount of time before we timeout response from content. For example, if
+ * content is being unruly/slow and we don't get a response back within this
+ * time, we will just pretend that content did not preventDefault any touch
+ * events we dispatched to it.
+ *
+ * "apz.cross_slide_enabled"
+ * Pref that enables integration with the Metro "cross-slide" gesture.
+ *
+ * "apz.enlarge_displayport_when_clipped"
+ * Pref that enables enlarging of the displayport along one axis when the
+ * generated displayport's size is beyond that of the scrollable rect on the
+ * opposite axis.
+ *
+ * "apz.fling_friction"
+ * Amount of friction applied during flings.
+ *
+ * "apz.fling_repaint_interval"
+ * Maximum amount of time flinging before sending a viewport change. This will
+ * asynchronously repaint the page.
+ *
+ * "apz.fling_stopped_threshold"
+ * When flinging, if the velocity goes below this number, we just stop the
+ * animation completely. This is to prevent asymptotically approaching 0
+ * velocity and rerendering unnecessarily.
+ *
+ * "apz.max_velocity_inches_per_ms"
+ * Maximum velocity in inches per millisecond.  Velocity will be capped at this
+ * value if a faster fling occurs.  Negative values indicate unlimited velocity.
+ *
+ * "apz.max_velocity_queue_size"
+ * Maximum size of velocity queue. The queue contains last N velocity records.
+ * On touch end we calculate the average velocity in order to compensate
+ * touch/mouse drivers misbehaviour.
+ *
+ * "apz.min_skate_speed"
+ * Minimum amount of speed along an axis before we switch to "skate" multipliers
+ * rather than using the "stationary" multipliers.
+ *
+ * "apz.num_paint_duration_samples"
+ * Number of samples to store of how long it took to paint after the previous
+ * requests.
+ *
+ * "apz.pan_repaint_interval"
+ * Maximum amount of time while panning before sending a viewport change. This
+ * will asynchronously repaint the page. It is also forced when panning stops.
+ *
+ * "apz.touch_start_tolerance"
  * Constant describing the tolerance in distance we use, multiplied by the
  * device DPI, before we start panning the screen. This is to prevent us from
  * accidentally processing taps as touch moves, and from very short/accidental
  * touches moving the screen.
+ *
+ * "apz.use_paint_duration"
+ * Whether or not to use the estimated paint duration as a factor when projecting
+ * the displayport in the direction of scrolling. If this value is set to false,
+ * a constant 50ms paint time is used; the projection can be scaled as desired
+ * using the apz.velocity_bias pref below.
+ *
+ * "apz.velocity_bias"
+ * How much to adjust the displayport in the direction of scrolling. This value
+ * is multiplied by the velocity and added to the displayport offset.
+ *
+ * "apz.x_skate_size_multiplier", "apz.y_skate_size_multiplier"
+ * The multiplier we apply to the displayport size if it is skating (current
+ * velocity is above apz.min_skate_speed). We prefer to increase the size of the
+ * Y axis because it is more natural in the case that a user is reading a page
+ * that scrolls up/down. Note that one, both or neither of these may be used
+ * at any instant.
+ * In general we want apz.[xy]_skate_size_multiplier to be smaller than the corresponding
+ * stationary size multiplier because when panning fast we would like to paint
+ * less and get faster, more predictable paint times. When panning slowly we
+ * can afford to paint more even though it's slower.
+ *
+ * "apz.x_stationary_size_multiplier", "apz.y_stationary_size_multiplier"
+ * The multiplier we apply to the displayport size if it is not skating (see
+ * documentation for the skate size multipliers above).
  */
-static float gTouchStartTolerance = 1.0f/4.5f;
 
 /**
  * Default touch behavior (is used when not touch behavior is set).
@@ -177,43 +259,6 @@ static const double AXIS_BREAKOUT_ANGLE = M_PI / 8.0; // 22.5 degrees
  */
 static const double ALLOWED_DIRECT_PAN_ANGLE = M_PI / 3.0; // 60 degrees
 
-/**
- * The preferred axis locking style. See AxisLockMode for possible values.
- */
-static int32_t gAxisLockMode = 0;
-
-/**
- * Maximum amount of time while panning before sending a viewport change. This
- * will asynchronously repaint the page. It is also forced when panning stops.
- */
-static int32_t gPanRepaintInterval = 250;
-
-/**
- * Maximum amount of time flinging before sending a viewport change. This will
- * asynchronously repaint the page.
- */
-static int32_t gFlingRepaintInterval = 75;
-
-/**
- * Minimum amount of speed along an axis before we switch to "skate" multipliers
- * rather than using the "stationary" multipliers.
- */
-static float gMinSkateSpeed = 1.0f;
-
-/**
- * Whether or not to use the estimated paint duration as a factor when projecting
- * the displayport in the direction of scrolling. If this value is set to false,
- * a constant 50ms paint time is used; the projection can be scaled as desired
- * using the gVelocityBias pref below.
- */
-static bool gUsePaintDuration = true;
-
-/**
- * How much to adjust the displayport in the direction of scrolling. This value
- * is multiplied by the velocity and added to the displayport offset.
- */
-static float gVelocityBias = 1.0f;
-
 /**
  * Duration of a zoom to animation.
  */
@@ -234,71 +279,6 @@ static const CSSToScreenScale MAX_ZOOM(8.0f);
  */
 static const CSSToScreenScale MIN_ZOOM(0.125f);
 
-/**
- * Amount of time before we timeout response from content. For example, if
- * content is being unruly/slow and we don't get a response back within this
- * time, we will just pretend that content did not preventDefault any touch
- * events we dispatched to it.
- */
-static int gContentResponseTimeout = 300;
-
-/**
- * Number of samples to store of how long it took to paint after the previous
- * requests.
- */
-static int gNumPaintDurationSamples = 3;
-
-/**
- * The multiplier we apply to the displayport size if it is skating (current
- * velocity is above gMinSkateSpeed). We prefer to increase the size of the
- * Y axis because it is more natural in the case that a user is reading a page
- * that scrolls up/down. Note that one, both or neither of these may be used
- * at any instant.
- * In general we want g[XY]SkateSizeMultiplier to be smaller than the corresponding
- * stationary size multiplier because when panning fast we would like to paint
- * less and get faster, more predictable paint times. When panning slowly we
- * can afford to paint more even though it's slower.
- */
-static float gXSkateSizeMultiplier = 1.5f;
-static float gYSkateSizeMultiplier = 2.5f;
-
-/**
- * The multiplier we apply to the displayport size if it is not skating (see
- * documentation for gXSkateSizeMultiplier).
- */
-static float gXStationarySizeMultiplier = 3.0f;
-static float gYStationarySizeMultiplier = 3.5f;
-
-/**
- * The time period in ms that throttles mozbrowserasyncscroll event.
- * Default is 100ms if there is no "apz.asyncscroll.throttle" in preference.
- */
-
-static int gAsyncScrollThrottleTime = 100;
-
-/**
- * The timeout in ms for mAsyncScrollTimeoutTask delay task.
- * Default is 300ms if there is no "apz.asyncscroll.timeout" in preference.
- */
-static int gAsyncScrollTimeout = 300;
-
-/**
- * Pref that enables integration with the Metro "cross-slide" gesture.
- */
-static bool gCrossSlideEnabled = false;
-
-/** 
- * Pref that allows or disallows checkerboarding
- */
-static bool gAllowCheckerboarding = true;
-
-/**
- * Pref that enables enlarging of the displayport along one axis when the
- * generated displayport's size is beyond that of the scrollable rect on the
- * opposite axis.
- */
-static bool gEnlargeDisplayPortWhenClipped = false;
-
 /**
  * Is aAngle within the given threshold of the horizontal axis?
  * @param aAngle an angle in radians in the range [0, pi]
@@ -350,7 +330,7 @@ GetFrameTime() {
 class FlingAnimation: public AsyncPanZoomAnimation {
 public:
   FlingAnimation(AsyncPanZoomController& aApzc)
-    : AsyncPanZoomAnimation(TimeDuration::FromMilliseconds(gFlingRepaintInterval))
+    : AsyncPanZoomAnimation(TimeDuration::FromMilliseconds(gfxPrefs::APZFlingRepaintInterval()))
     , mApzc(aApzc)
   {}
   /**
@@ -411,27 +391,6 @@ AsyncPanZoomController::InitializeGlobalState()
     return;
   sInitialized = true;
 
-  Preferences::AddBoolVarCache(&gTouchActionPropertyEnabled, "layout.css.touch_action.enabled", gTouchActionPropertyEnabled);
-  Preferences::AddIntVarCache(&gPanRepaintInterval, "apz.pan_repaint_interval", gPanRepaintInterval);
-  Preferences::AddIntVarCache(&gFlingRepaintInterval, "apz.fling_repaint_interval", gFlingRepaintInterval);
-  Preferences::AddFloatVarCache(&gMinSkateSpeed, "apz.min_skate_speed", gMinSkateSpeed);
-  Preferences::AddBoolVarCache(&gUsePaintDuration, "apz.use_paint_duration", gUsePaintDuration);
-  Preferences::AddFloatVarCache(&gVelocityBias, "apz.velocity_bias", gVelocityBias);
-  Preferences::AddIntVarCache(&gContentResponseTimeout, "apz.content_response_timeout", gContentResponseTimeout);
-  Preferences::AddIntVarCache(&gNumPaintDurationSamples, "apz.num_paint_duration_samples", gNumPaintDurationSamples);
-  Preferences::AddFloatVarCache(&gTouchStartTolerance, "apz.touch_start_tolerance", gTouchStartTolerance);
-  Preferences::AddFloatVarCache(&gXSkateSizeMultiplier, "apz.x_skate_size_multiplier", gXSkateSizeMultiplier);
-  Preferences::AddFloatVarCache(&gYSkateSizeMultiplier, "apz.y_skate_size_multiplier", gYSkateSizeMultiplier);
-  Preferences::AddFloatVarCache(&gXStationarySizeMultiplier, "apz.x_stationary_size_multiplier", gXStationarySizeMultiplier);
-  Preferences::AddFloatVarCache(&gYStationarySizeMultiplier, "apz.y_stationary_size_multiplier", gYStationarySizeMultiplier);
-  Preferences::AddIntVarCache(&gAsyncScrollThrottleTime, "apz.asyncscroll.throttle", gAsyncScrollThrottleTime);
-  Preferences::AddIntVarCache(&gAsyncScrollTimeout, "apz.asyncscroll.timeout", gAsyncScrollTimeout);
-  Preferences::AddBoolVarCache(&gCrossSlideEnabled, "apz.cross_slide.enabled", gCrossSlideEnabled);
-  Preferences::AddIntVarCache(&gAxisLockMode, "apz.axis_lock_mode", gAxisLockMode);
-  Preferences::AddBoolVarCache(&gAllowCheckerboarding, "apz.allow-checkerboarding", gAllowCheckerboarding);
-  Preferences::AddBoolVarCache(&gEnlargeDisplayPortWhenClipped, "apz.enlarge_displayport_when_clipped",
-    gEnlargeDisplayPortWhenClipped);
-
   gComputedTimingFunction = new ComputedTimingFunction();
   gComputedTimingFunction->Init(
     nsTimingFunction(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE));
@@ -448,7 +407,7 @@ AsyncPanZoomController::AsyncPanZoomController(uint64_t aLayersId,
      mGeckoContentController(aGeckoContentController),
      mRefPtrMonitor("RefPtrMonitor"),
      mMonitor("AsyncPanZoomController"),
-     mTouchActionPropertyEnabled(gTouchActionPropertyEnabled),
+     mTouchActionPropertyEnabled(gfxPrefs::TouchActionEnabled()),
      mContentResponseTimeoutTask(nullptr),
      mX(MOZ_THIS_IN_INITIALIZER_LIST()),
      mY(MOZ_THIS_IN_INITIALIZER_LIST()),
@@ -529,12 +488,12 @@ AsyncPanZoomController::IsDestroyed()
 /* static */float
 AsyncPanZoomController::GetTouchStartTolerance()
 {
-  return (gTouchStartTolerance * APZCTreeManager::GetDPI());
+  return (gfxPrefs::APZTouchStartTolerance() * APZCTreeManager::GetDPI());
 }
 
 /* static */AsyncPanZoomController::AxisLockMode AsyncPanZoomController::GetAxisLockMode()
 {
-  return static_cast<AxisLockMode>(gAxisLockMode);
+  return static_cast<AxisLockMode>(gfxPrefs::APZAxisLockMode());
 }
 
 nsEventStatus AsyncPanZoomController::ReceiveInputEvent(const InputData& aEvent) {
@@ -1088,7 +1047,7 @@ void AsyncPanZoomController::HandlePanningWithTouchAction(double aAngle, TouchBe
 }
 
 void AsyncPanZoomController::HandlePanning(double aAngle) {
-  if (!gCrossSlideEnabled && (!mX.Scrollable() || !mY.Scrollable())) {
+  if (!gfxPrefs::APZCrossSlideEnabled() && (!mX.Scrollable() || !mY.Scrollable())) {
     SetState(PANNING);
   } else if (IsCloseToHorizontal(aAngle, AXIS_LOCK_ANGLE)) {
     mY.SetAxisLocked(true);
@@ -1187,7 +1146,7 @@ void AsyncPanZoomController::AttemptScroll(const ScreenPoint& aStartPoint,
       ScheduleComposite();
 
       TimeDuration timePaintDelta = mPaintThrottler.TimeSinceLastRequest(GetFrameTime());
-      if (timePaintDelta.ToMilliseconds() > gPanRepaintInterval) {
+      if (timePaintDelta.ToMilliseconds() > gfxPrefs::APZPanRepaintInterval()) {
         RequestContentRepaint();
       }
       UpdateSharedCompositorFrameMetrics();
@@ -1386,12 +1345,12 @@ static CSSSize
 CalculateDisplayPortSize(const CSSSize& aCompositionSize,
                          const CSSPoint& aVelocity)
 {
-  float xMultiplier = fabsf(aVelocity.x) < gMinSkateSpeed
-                        ? gXStationarySizeMultiplier
-                        : gXSkateSizeMultiplier;
-  float yMultiplier = fabsf(aVelocity.y) < gMinSkateSpeed
-                        ? gYStationarySizeMultiplier
-                        : gYSkateSizeMultiplier;
+  float xMultiplier = fabsf(aVelocity.x) < gfxPrefs::APZMinSkateSpeed()
+                        ? gfxPrefs::APZXStationarySizeMultiplier()
+                        : gfxPrefs::APZXSkateSizeMultiplier();
+  float yMultiplier = fabsf(aVelocity.y) < gfxPrefs::APZMinSkateSpeed()
+                        ? gfxPrefs::APZYStationarySizeMultiplier()
+                        : gfxPrefs::APZYSkateSizeMultiplier();
   return CSSSize(aCompositionSize.width * xMultiplier,
                  aCompositionSize.height * yMultiplier);
 }
@@ -1439,15 +1398,15 @@ const LayerMargin AsyncPanZoomController::CalculatePendingDisplayPort(
   // Calculate the displayport size based on how fast we're moving along each axis.
   CSSSize displayPortSize = CalculateDisplayPortSize(compositionSize, velocity);
 
-  if (gEnlargeDisplayPortWhenClipped) {
+  if (gfxPrefs::APZEnlargeDisplayPortWhenClipped()) {
     RedistributeDisplayPortExcess(displayPortSize, scrollableRect);
   }
 
   // Offset the displayport, depending on how fast we're moving and the
   // estimated time it takes to paint, to try to minimise checkerboarding.
   float estimatedPaintDurationMillis = (float)(aEstimatedPaintDuration * 1000.0);
-  float paintFactor = (gUsePaintDuration ? estimatedPaintDurationMillis : 50.0f);
-  CSSRect displayPort = CSSRect(scrollOffset + (velocity * paintFactor * gVelocityBias),
+  float paintFactor = (gfxPrefs::APZUsePaintDuration() ? estimatedPaintDurationMillis : 50.0f);
+  CSSRect displayPort = CSSRect(scrollOffset + (velocity * paintFactor * gfxPrefs::APZVelocityBias()),
                                 displayPortSize);
 
   // Re-center the displayport based on its expansion over the composition size.
@@ -1646,7 +1605,7 @@ bool AsyncPanZoomController::SampleContentTransformForFrame(const TimeStamp& aSa
   // with the last event.
   // Otherwise, start a timer to fire the event sAsyncScrollTimeout ms from now.
   TimeDuration delta = aSampleTime - mLastAsyncScrollTime;
-  if (delta.ToMilliseconds() > gAsyncScrollThrottleTime &&
+  if (delta.ToMilliseconds() > gfxPrefs::APZAsyncScrollThrottleTime() &&
       mCurrentAsyncScrollOffset != mLastAsyncScrollOffset) {
     ReentrantMonitorAutoEnter lock(mMonitor);
     mLastAsyncScrollTime = aSampleTime;
@@ -1658,7 +1617,7 @@ bool AsyncPanZoomController::SampleContentTransformForFrame(const TimeStamp& aSa
       NewRunnableMethod(this, &AsyncPanZoomController::FireAsyncScrollOnTimeout);
     MessageLoop::current()->PostDelayedTask(FROM_HERE,
                                             mAsyncScrollTimeoutTask,
-                                            gAsyncScrollTimeout);
+                                            gfxPrefs::APZAsyncScrollTimeout());
   }
 
   return requestAnimationFrame;
@@ -1677,7 +1636,7 @@ ViewTransform AsyncPanZoomController::GetCurrentAsyncTransform() {
 
   // If checkerboarding has been disallowed, clamp the scroll position to stay
   // within rendered content.
-  if (!gAllowCheckerboarding &&
+  if (!gfxPrefs::APZAllowCheckerboarding() &&
       !mLastContentPaintMetrics.mDisplayPort.IsEmpty()) {
     CSSSize compositedSize = mLastContentPaintMetrics.CalculateCompositedSizeInCssPixels();
     CSSPoint maxScrollOffset = lastPaintScrollOffset +
@@ -1756,7 +1715,7 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetri
     // Initialize our internal state to something sane when the content
     // that was just painted is something we knew nothing about previously
     mPaintThrottler.ClearHistory();
-    mPaintThrottler.SetMaxDurations(gNumPaintDurationSamples);
+    mPaintThrottler.SetMaxDurations(gfxPrefs::APZNumPaintDurationSamples());
 
     mX.CancelTouch();
     mY.CancelTouch();
@@ -2045,7 +2004,7 @@ void AsyncPanZoomController::SetContentResponseTimer() {
     mContentResponseTimeoutTask =
       NewRunnableMethod(this, &AsyncPanZoomController::TimeoutContentResponse);
 
-    PostDelayedTask(mContentResponseTimeoutTask, gContentResponseTimeout);
+    PostDelayedTask(mContentResponseTimeoutTask, gfxPrefs::APZContentResponseTimeout());
   }
 }
 
diff --git a/gfx/layers/ipc/Axis.cpp b/gfx/layers/ipc/Axis.cpp
index 875566877e6352cc2eda77dfa216c940c18ce0b5..00e22093c2857bf4846ea88bc22777a71b3327b7 100644
--- a/gfx/layers/ipc/Axis.cpp
+++ b/gfx/layers/ipc/Axis.cpp
@@ -22,58 +22,6 @@
 namespace mozilla {
 namespace layers {
 
-/**
- * These are the preferences that control the behavior of APZ
- */
-
-/**
- * "apz.max_event_acceleration"
- *
- * Maximum acceleration that can happen between two frames. Velocity is
- * throttled if it's above this. This may happen if a time delta is very low,
- * or we get a touch point very far away from the previous position for some
- * reason.
- *
- * The default value is 999.0f, set in gfxPrefs.h
- */
-
-/**
- * "apz.fling_friction"
- *
- * Amount of friction applied during flings.
- *
- * The default value is 0.002f, set in gfxPrefs.h
- */
-
-/**
- * "apz.fling_stopped_threshold"
- *
- * When flinging, if the velocity goes below this number, we just stop the
- * animation completely. This is to prevent asymptotically approaching 0
- * velocity and rerendering unnecessarily.
- *
- * The default value is 0.01f, set in gfxPrefs.h.
- */
-
-/**
- * "apz.max_velocity_queue_size"
- *
- * Maximum size of velocity queue. The queue contains last N velocity records.
- * On touch end we calculate the average velocity in order to compensate
- * touch/mouse drivers misbehaviour.
- *
- * The default value is 5, set in gfxPrefs.h
- */
-
-/**
- * "apz.max_velocity_inches_per_ms"
- *
- * Maximum velocity in inches per millisecond.  Velocity will be capped at this
- * value if a faster fling occurs.  Negative values indicate unlimited velocity.
- *
- * The default value is -1.0f, set in gfxPrefs.h
- */
-
 Axis::Axis(AsyncPanZoomController* aAsyncPanZoomController)
   : mPos(0),
     mVelocity(0.0f),
diff --git a/gfx/layers/ipc/ShadowLayers.cpp b/gfx/layers/ipc/ShadowLayers.cpp
index 6d29d20ca6e60cbaa0551c091997e8477b0aa9b6..cc7600a985ef25f1f6870f530094854d1bf61d4d 100644
--- a/gfx/layers/ipc/ShadowLayers.cpp
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -449,10 +449,6 @@ void
 ShadowLayerForwarder::RemoveTextureFromCompositable(CompositableClient* aCompositable,
                                                     TextureClient* aTexture)
 {
-  MOZ_ASSERT(aCompositable);
-  MOZ_ASSERT(aCompositable->GetIPDLActor());
-  MOZ_ASSERT(aTexture);
-  MOZ_ASSERT(aTexture->GetIPDLActor());
   mTxn->AddEdit(OpRemoveTexture(nullptr, aCompositable->GetIPDLActor(),
                                 nullptr, aTexture->GetIPDLActor()));
   if (aTexture->GetFlags() & TEXTURE_DEALLOCATE_CLIENT) {
diff --git a/gfx/layers/opengl/CompositorOGL.cpp b/gfx/layers/opengl/CompositorOGL.cpp
index b9302496435d7b5ca0c975f6223adfa8fbd789b8..b843cf241556ec9476463907a01e5e6341410160 100644
--- a/gfx/layers/opengl/CompositorOGL.cpp
+++ b/gfx/layers/opengl/CompositorOGL.cpp
@@ -98,7 +98,7 @@ DrawQuads(GLContext *aGLContext,
     aProg->AttribLocation(ShaderProgramOGL::TexCoordAttrib);
   bool texCoords = (texCoordAttribIndex != GLuint(-1));
 
-  GLsizei bytes = aRects.elements() * 2 * sizeof(GLfloat);
+  GLsizei bytes = aRects.vertCoords().Length() * 2 * sizeof(GLfloat);
 
   GLsizei total = bytes;
   if (texCoords) {
@@ -136,7 +136,7 @@ DrawQuads(GLContext *aGLContext,
     aGLContext->fDisableVertexAttribArray(texCoordAttribIndex);
   }
 
-  aGLContext->fDrawArrays(aMode, 0, aRects.elements());
+  aGLContext->fDrawArrays(aMode, 0, aRects.vertCoords().Length());
 
   aGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
 }
@@ -282,7 +282,7 @@ CompositorOGL::Initialize()
       LOCAL_GL_NONE
     };
 
-    if (!mGLContext->IsGLES2()) {
+    if (!mGLContext->IsGLES()) {
       // No TEXTURE_RECTANGLE_ARB available on ES2
       textureTargets[1] = LOCAL_GL_TEXTURE_RECTANGLE_ARB;
     }
@@ -372,8 +372,6 @@ CompositorOGL::Initialize()
     0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
     /* Then quad texcoords */
     0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
-    /* Then flipped quad texcoords */
-    0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
   };
   mGLContext->fBufferData(LOCAL_GL_ARRAY_BUFFER, sizeof(vertices), vertices, LOCAL_GL_STATIC_DRAW);
   mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
@@ -479,7 +477,7 @@ CompositorOGL::BindAndDrawQuadWithTextureRect(ShaderProgramOGL *aProg,
     Matrix4x4 transform;
     ToMatrix4x4(aTextureTransform * textureTransform, transform);
     aProg->SetTextureTransform(transform);
-    BindAndDrawQuad(aProg, false);
+    BindAndDrawQuad(aProg);
   } else {
     Matrix4x4 transform;
     ToMatrix4x4(aTextureTransform, transform);
@@ -736,7 +734,7 @@ CompositorOGL::CreateFBOWithTexture(const IntRect& aRect, bool aCopyFromSource,
       GetFrameBufferInternalFormat(gl(), aSourceFrameBuffer, mWidget);
 
     bool isFormatCompatibleWithRGBA
-        = gl()->IsGLES2() ? (format == LOCAL_GL_RGBA)
+        = gl()->IsGLES() ? (format == LOCAL_GL_RGBA)
                           : true;
 
     if (isFormatCompatibleWithRGBA) {
@@ -988,7 +986,7 @@ CompositorOGL::DrawQuadInternal(const Rect& aRect,
         BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE0, maskQuadTransform);
       }
 
-      BindAndDrawQuad(program, false, aDrawMode);
+      BindAndDrawQuad(program, aDrawMode);
     }
     break;
 
@@ -1072,7 +1070,12 @@ CompositorOGL::DrawQuadInternal(const Rect& aRect,
 
       surface->BindTexture(LOCAL_GL_TEXTURE0, mFBOTextureTarget);
 
-      program->SetTextureTransform(Matrix4x4());
+      // Drawing is always flipped, but when copying between surfaces we want to avoid
+      // this, so apply a flip here to cancel the other one out.
+      Matrix transform;
+      transform.Translate(0.0, 1.0);
+      transform.Scale(1.0f, -1.0f);
+      program->SetTextureTransform(Matrix4x4::From2D(transform));
       program->SetTextureUnit(0);
 
       if (maskType != MaskNone) {
@@ -1089,7 +1092,7 @@ CompositorOGL::DrawQuadInternal(const Rect& aRect,
       // Drawing is always flipped, but when copying between surfaces we want to avoid
       // this. Pass true for the flip parameter to introduce a second flip
       // that cancels the other one out.
-      BindAndDrawQuad(program, true);
+      BindAndDrawQuad(program);
     }
     break;
   case EFFECT_COMPONENT_ALPHA: {
@@ -1190,19 +1193,19 @@ CompositorOGL::EndFrame()
   // Unbind all textures
   mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
   mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, 0);
-  if (!mGLContext->IsGLES2()) {
+  if (!mGLContext->IsGLES()) {
     mGLContext->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
   }
 
   mGLContext->fActiveTexture(LOCAL_GL_TEXTURE1);
   mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, 0);
-  if (!mGLContext->IsGLES2()) {
+  if (!mGLContext->IsGLES()) {
     mGLContext->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
   }
 
   mGLContext->fActiveTexture(LOCAL_GL_TEXTURE2);
   mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, 0);
-  if (!mGLContext->IsGLES2()) {
+  if (!mGLContext->IsGLES()) {
     mGLContext->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
   }
 }
@@ -1317,7 +1320,7 @@ CompositorOGL::CopyToTarget(DrawTarget *aTarget, const gfx::Matrix& aTransform)
 
   mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
 
-  if (!mGLContext->IsGLES2()) {
+  if (!mGLContext->IsGLES()) {
     // GLES2 promises that binding to any custom FBO will attach
     // to GL_COLOR_ATTACHMENT0 attachment point.
     mGLContext->fReadBuffer(LOCAL_GL_BACK);
@@ -1429,28 +1432,16 @@ CompositorOGL::QuadVBOTexCoordsAttrib(GLuint aAttribIndex) {
                                     (GLvoid*) QuadVBOTexCoordOffset());
 }
 
-void
-CompositorOGL::QuadVBOFlippedTexCoordsAttrib(GLuint aAttribIndex) {
-  mGLContext->fVertexAttribPointer(aAttribIndex, 2,
-                                    LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0,
-                                    (GLvoid*) QuadVBOFlippedTexCoordOffset());
-}
-
 void
 CompositorOGL::BindAndDrawQuad(GLuint aVertAttribIndex,
                                GLuint aTexCoordAttribIndex,
-                               bool aFlipped,
                                GLuint aDrawMode)
 {
   BindQuadVBO();
   QuadVBOVerticesAttrib(aVertAttribIndex);
 
   if (aTexCoordAttribIndex != GLuint(-1)) {
-    if (aFlipped)
-      QuadVBOFlippedTexCoordsAttrib(aTexCoordAttribIndex);
-    else
-      QuadVBOTexCoordsAttrib(aTexCoordAttribIndex);
-
+    QuadVBOTexCoordsAttrib(aTexCoordAttribIndex);
     mGLContext->fEnableVertexAttribArray(aTexCoordAttribIndex);
   }
 
@@ -1464,13 +1455,12 @@ CompositorOGL::BindAndDrawQuad(GLuint aVertAttribIndex,
 
 void
 CompositorOGL::BindAndDrawQuad(ShaderProgramOGL *aProg,
-                               bool aFlipped,
                                GLuint aDrawMode)
 {
   NS_ASSERTION(aProg->HasInitialized(), "Shader program not correctly initialized");
   BindAndDrawQuad(aProg->AttribLocation(ShaderProgramOGL::VertexCoordAttrib),
                   aProg->AttribLocation(ShaderProgramOGL::TexCoordAttrib),
-                  aFlipped, aDrawMode);
+                  aDrawMode);
 }
 
 GLuint
diff --git a/gfx/layers/opengl/CompositorOGL.h b/gfx/layers/opengl/CompositorOGL.h
index 2b166a08f17ae011fb75a0f924a6550a5f218e29..33d036cccb00c82a18fad602a0d732dc8fc13840 100644
--- a/gfx/layers/opengl/CompositorOGL.h
+++ b/gfx/layers/opengl/CompositorOGL.h
@@ -311,9 +311,10 @@ private:
   CompositingRenderTargetOGL* mWindowRenderTarget;
 #endif
 
-  /** VBO that has some basics in it for a textured quad,
-   *  including vertex coords and texcoords for both
-   *  flipped and unflipped textures */
+  /**
+   * VBO that has some basics in it for a textured quad, including vertex
+   * coords and texcoords.
+   */
   GLuint mQuadVBO;
 
   /**
@@ -366,18 +367,14 @@ private:
 
   GLintptr QuadVBOVertexOffset() { return 0; }
   GLintptr QuadVBOTexCoordOffset() { return sizeof(float)*4*2; }
-  GLintptr QuadVBOFlippedTexCoordOffset() { return sizeof(float)*8*2; }
 
   void BindQuadVBO();
   void QuadVBOVerticesAttrib(GLuint aAttribIndex);
   void QuadVBOTexCoordsAttrib(GLuint aAttribIndex);
-  void QuadVBOFlippedTexCoordsAttrib(GLuint aAttribIndex);
   void BindAndDrawQuad(GLuint aVertAttribIndex,
                        GLuint aTexCoordAttribIndex,
-                       bool aFlipped = false,
                        GLuint aDrawMode = LOCAL_GL_TRIANGLE_STRIP);
   void BindAndDrawQuad(ShaderProgramOGL *aProg,
-                       bool aFlipped = false,
                        GLuint aDrawMode = LOCAL_GL_TRIANGLE_STRIP);
   void BindAndDrawQuadWithTextureRect(ShaderProgramOGL *aProg,
                                       const gfx3DMatrix& aTextureTransform,
diff --git a/gfx/src/nsFontMetrics.cpp b/gfx/src/nsFontMetrics.cpp
index 5df9de84f776aceea7bf763c1fca4bbc49842a84..a54ae57123af3ca5ab012fc1e2bcea63468a5061 100644
--- a/gfx/src/nsFontMetrics.cpp
+++ b/gfx/src/nsFontMetrics.cpp
@@ -74,6 +74,14 @@ public:
         NS_ERROR("This shouldn't be called because we never enable hyphens");
         return 0;
     }
+    virtual already_AddRefed<gfxContext> GetContext() {
+        NS_ERROR("This shouldn't be called because we never enable hyphens");
+        return nullptr;
+    }
+    virtual uint32_t GetAppUnitsPerDevUnit() {
+        NS_ERROR("This shouldn't be called because we never enable hyphens");
+        return 60;
+    }
     virtual void GetSpacing(uint32_t aStart, uint32_t aLength,
                             Spacing* aSpacing) {
         NS_ERROR("This shouldn't be called because we never enable spacing");
diff --git a/gfx/tests/gtest/TestAsyncPanZoomController.cpp b/gfx/tests/gtest/TestAsyncPanZoomController.cpp
index 933df231e4f770a284f22aa8672186fe76efb98b..357f84d730a71b914714df98e21b607281f5f96e 100644
--- a/gfx/tests/gtest/TestAsyncPanZoomController.cpp
+++ b/gfx/tests/gtest/TestAsyncPanZoomController.cpp
@@ -335,14 +335,14 @@ ApzcTap(AsyncPanZoomController* apzc, int aX, int aY, int& aTime, int aTapLength
   return ApzcUp(apzc, aX, aY, aTime);
 }
 
-TEST(AsyncPanZoomController, Constructor) {
+TEST_F(AsyncPanZoomControllerTester, Constructor) {
   // RefCounted class can't live in the stack
   nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
   nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc);
   apzc->SetFrameMetrics(TestFrameMetrics());
 }
 
-TEST(AsyncPanZoomController, Pinch) {
+TEST_F(AsyncPanZoomControllerTester, Pinch) {
   nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
   nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc);
 
@@ -385,7 +385,7 @@ TEST(AsyncPanZoomController, Pinch) {
   apzc->Destroy();
 }
 
-TEST(AsyncPanZoomController, PinchWithTouchActionNone) {
+TEST_F(AsyncPanZoomControllerTester, PinchWithTouchActionNone) {
   nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
   nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc);
 
@@ -419,7 +419,7 @@ TEST(AsyncPanZoomController, PinchWithTouchActionNone) {
   EXPECT_EQ(fm.GetScrollOffset().y, 300);
 }
 
-TEST(AsyncPanZoomController, Overzoom) {
+TEST_F(AsyncPanZoomControllerTester, Overzoom) {
   nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
   nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc);
 
@@ -446,7 +446,7 @@ TEST(AsyncPanZoomController, Overzoom) {
   EXPECT_LT(abs(fm.GetScrollOffset().y), 1e-5);
 }
 
-TEST(AsyncPanZoomController, SimpleTransform) {
+TEST_F(AsyncPanZoomControllerTester, SimpleTransform) {
   TimeStamp testStartTime = TimeStamp::Now();
   // RefCounted class can't live in the stack
   nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
@@ -462,7 +462,7 @@ TEST(AsyncPanZoomController, SimpleTransform) {
 }
 
 
-TEST(AsyncPanZoomController, ComplexTransform) {
+TEST_F(AsyncPanZoomControllerTester, ComplexTransform) {
   TimeStamp testStartTime = TimeStamp::Now();
   AsyncPanZoomController::SetFrameTime(testStartTime);
 
@@ -962,7 +962,7 @@ GetTargetAPZC(APZCTreeManager* manager, const ScreenPoint& aPoint,
 }
 
 // A simple hit testing test that doesn't involve any transforms on layers.
-TEST(APZCTreeManager, HitTesting1) {
+TEST_F(APZCTreeManagerTester, HitTesting1) {
   nsTArray<nsRefPtr<Layer> > layers;
   nsRefPtr<LayerManager> lm;
   nsRefPtr<Layer> root = CreateTestLayerTree1(lm, layers);
diff --git a/gfx/thebes/CJKCompatSVS.cpp b/gfx/thebes/CJKCompatSVS.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e68d98e92d1dbb48338e324cb2c1b322fbba031e
--- /dev/null
+++ b/gfx/thebes/CJKCompatSVS.cpp
@@ -0,0 +1,1039 @@
+// Generated by gencjkcisvs.py. Do not edit.
+
+#include <stdint.h>
+
+#define U16(v) (((v) >> 8) & 0xFF), ((v) & 0xFF)
+#define U24(v) (((v) >> 16) & 0xFF), (((v) >> 8) & 0xFF), ((v) & 0xFF)
+#define U32(v) (((v) >> 24) & 0xFF), (((v) >> 16) & 0xFF), (((v) >> 8) & 0xFF), ((v) & 0xFF)
+#define GLYPH(v) U16(v >= 0x2F800 ? (v) - (0x2F800 - 0xFB00) : (v))
+
+// Fallback mappings for CJK Compatibility Ideographs Standardized Variants
+// taken from StandardizedVariants-6.3.0.txt.
+// Using OpenType format 14 cmap subtable structure to reuse the lookup code
+// for fonts. The glyphID field is used to store the corresponding codepoints
+// CJK Compatibility Ideographs. To fit codepoints into the 16-bit glyphID
+// field, CJK Compatibility Ideographs Supplement (U+2F800..U+2FA1F) will be
+// mapped to 0xFB00..0xFD1F.
+extern const uint8_t sCJKCompatSVSTable[] = {
+  U16(14), // format
+  U32(5065), // length
+  U32(3), // numVarSelectorRecords
+    U24(0xFE00), U32(0), U32(43), // varSelectorRecord[0]
+    U24(0xFE01), U32(0), U32(4557), // varSelectorRecord[1]
+    U24(0xFE02), U32(0), U32(5001), // varSelectorRecord[2]
+  // 0xFE00
+  U32(902), // numUVSMappings
+    U24(0x349E), GLYPH(0x2F80C),
+    U24(0x34B9), GLYPH(0x2F813),
+    U24(0x34BB), GLYPH(0x2F9CA),
+    U24(0x34DF), GLYPH(0x2F81F),
+    U24(0x3515), GLYPH(0x2F824),
+    U24(0x36EE), GLYPH(0x2F867),
+    U24(0x36FC), GLYPH(0x2F868),
+    U24(0x3781), GLYPH(0x2F876),
+    U24(0x382F), GLYPH(0x2F883),
+    U24(0x3862), GLYPH(0x2F888),
+    U24(0x387C), GLYPH(0x2F88A),
+    U24(0x38C7), GLYPH(0x2F896),
+    U24(0x38E3), GLYPH(0x2F89B),
+    U24(0x391C), GLYPH(0x2F8A2),
+    U24(0x393A), GLYPH(0x2F8A1),
+    U24(0x3A2E), GLYPH(0x2F8C2),
+    U24(0x3A6C), GLYPH(0x2F8C7),
+    U24(0x3AE4), GLYPH(0x2F8D1),
+    U24(0x3B08), GLYPH(0x2F8D0),
+    U24(0x3B19), GLYPH(0x2F8CE),
+    U24(0x3B49), GLYPH(0x2F8DE),
+    U24(0x3B9D), GLYPH(0xFAD2),
+    U24(0x3C18), GLYPH(0x2F8EE),
+    U24(0x3C4E), GLYPH(0x2F8F2),
+    U24(0x3D33), GLYPH(0x2F90A),
+    U24(0x3D96), GLYPH(0x2F916),
+    U24(0x3EAC), GLYPH(0x2F92A),
+    U24(0x3EB8), GLYPH(0x2F92C),
+    U24(0x3F1B), GLYPH(0x2F933),
+    U24(0x3FFC), GLYPH(0x2F93E),
+    U24(0x4008), GLYPH(0x2F93F),
+    U24(0x4018), GLYPH(0xFAD3),
+    U24(0x4039), GLYPH(0xFAD4),
+    U24(0x4046), GLYPH(0x2F94B),
+    U24(0x4096), GLYPH(0x2F94C),
+    U24(0x40E3), GLYPH(0x2F951),
+    U24(0x412F), GLYPH(0x2F958),
+    U24(0x4202), GLYPH(0x2F960),
+    U24(0x4227), GLYPH(0x2F964),
+    U24(0x42A0), GLYPH(0x2F967),
+    U24(0x4301), GLYPH(0x2F96D),
+    U24(0x4334), GLYPH(0x2F971),
+    U24(0x4359), GLYPH(0x2F974),
+    U24(0x43D5), GLYPH(0x2F981),
+    U24(0x43D9), GLYPH(0x2F8D7),
+    U24(0x440B), GLYPH(0x2F984),
+    U24(0x446B), GLYPH(0x2F98E),
+    U24(0x452B), GLYPH(0x2F9A7),
+    U24(0x455D), GLYPH(0x2F9AE),
+    U24(0x4561), GLYPH(0x2F9AF),
+    U24(0x456B), GLYPH(0x2F9B2),
+    U24(0x45D7), GLYPH(0x2F9BF),
+    U24(0x45F9), GLYPH(0x2F9C2),
+    U24(0x4635), GLYPH(0x2F9C8),
+    U24(0x46BE), GLYPH(0x2F9CD),
+    U24(0x46C7), GLYPH(0x2F9CE),
+    U24(0x4995), GLYPH(0x2F9EF),
+    U24(0x49E6), GLYPH(0x2F9F2),
+    U24(0x4A6E), GLYPH(0x2F9F8),
+    U24(0x4A76), GLYPH(0x2F9F9),
+    U24(0x4AB2), GLYPH(0x2F9FC),
+    U24(0x4B33), GLYPH(0x2FA03),
+    U24(0x4BCE), GLYPH(0x2FA08),
+    U24(0x4CCE), GLYPH(0x2FA0D),
+    U24(0x4CED), GLYPH(0x2FA0E),
+    U24(0x4CF8), GLYPH(0x2FA11),
+    U24(0x4D56), GLYPH(0x2FA16),
+    U24(0x4E0D), GLYPH(0xF967),
+    U24(0x4E26), GLYPH(0xFA70),
+    U24(0x4E32), GLYPH(0xF905),
+    U24(0x4E38), GLYPH(0x2F801),
+    U24(0x4E39), GLYPH(0xF95E),
+    U24(0x4E3D), GLYPH(0x2F800),
+    U24(0x4E41), GLYPH(0x2F802),
+    U24(0x4E82), GLYPH(0xF91B),
+    U24(0x4E86), GLYPH(0xF9BA),
+    U24(0x4EAE), GLYPH(0xF977),
+    U24(0x4EC0), GLYPH(0xF9FD),
+    U24(0x4ECC), GLYPH(0x2F819),
+    U24(0x4EE4), GLYPH(0xF9A8),
+    U24(0x4F60), GLYPH(0x2F804),
+    U24(0x4F80), GLYPH(0xFA73),
+    U24(0x4F86), GLYPH(0xF92D),
+    U24(0x4F8B), GLYPH(0xF9B5),
+    U24(0x4FAE), GLYPH(0xFA30),
+    U24(0x4FBB), GLYPH(0x2F806),
+    U24(0x4FBF), GLYPH(0xF965),
+    U24(0x5002), GLYPH(0x2F807),
+    U24(0x502B), GLYPH(0xF9D4),
+    U24(0x507A), GLYPH(0x2F808),
+    U24(0x5099), GLYPH(0x2F809),
+    U24(0x50CF), GLYPH(0x2F80B),
+    U24(0x50DA), GLYPH(0xF9BB),
+    U24(0x50E7), GLYPH(0xFA31),
+    U24(0x5140), GLYPH(0xFA0C),
+    U24(0x5145), GLYPH(0xFA74),
+    U24(0x514D), GLYPH(0xFA32),
+    U24(0x5154), GLYPH(0x2F80F),
+    U24(0x5164), GLYPH(0x2F810),
+    U24(0x5167), GLYPH(0x2F814),
+    U24(0x5168), GLYPH(0xFA72),
+    U24(0x5169), GLYPH(0xF978),
+    U24(0x516D), GLYPH(0xF9D1),
+    U24(0x5177), GLYPH(0x2F811),
+    U24(0x5180), GLYPH(0xFA75),
+    U24(0x518D), GLYPH(0x2F815),
+    U24(0x5192), GLYPH(0x2F8D2),
+    U24(0x5195), GLYPH(0x2F8D3),
+    U24(0x5197), GLYPH(0x2F817),
+    U24(0x51A4), GLYPH(0x2F818),
+    U24(0x51AC), GLYPH(0x2F81A),
+    U24(0x51B5), GLYPH(0xFA71),
+    U24(0x51B7), GLYPH(0xF92E),
+    U24(0x51C9), GLYPH(0xF979),
+    U24(0x51CC), GLYPH(0xF955),
+    U24(0x51DC), GLYPH(0xF954),
+    U24(0x51DE), GLYPH(0xFA15),
+    U24(0x51F5), GLYPH(0x2F81D),
+    U24(0x5203), GLYPH(0x2F81E),
+    U24(0x5207), GLYPH(0xFA00),
+    U24(0x5217), GLYPH(0xF99C),
+    U24(0x5229), GLYPH(0xF9DD),
+    U24(0x523A), GLYPH(0xF9FF),
+    U24(0x523B), GLYPH(0x2F820),
+    U24(0x5246), GLYPH(0x2F821),
+    U24(0x5272), GLYPH(0x2F822),
+    U24(0x5277), GLYPH(0x2F823),
+    U24(0x5289), GLYPH(0xF9C7),
+    U24(0x529B), GLYPH(0xF98A),
+    U24(0x52A3), GLYPH(0xF99D),
+    U24(0x52B3), GLYPH(0x2F992),
+    U24(0x52C7), GLYPH(0xFA76),
+    U24(0x52C9), GLYPH(0xFA33),
+    U24(0x52D2), GLYPH(0xF952),
+    U24(0x52DE), GLYPH(0xF92F),
+    U24(0x52E4), GLYPH(0xFA34),
+    U24(0x52F5), GLYPH(0xF97F),
+    U24(0x52FA), GLYPH(0xFA77),
+    U24(0x5305), GLYPH(0x2F829),
+    U24(0x5306), GLYPH(0x2F82A),
+    U24(0x5317), GLYPH(0xF963),
+    U24(0x533F), GLYPH(0xF9EB),
+    U24(0x5349), GLYPH(0x2F82C),
+    U24(0x5351), GLYPH(0xFA35),
+    U24(0x535A), GLYPH(0x2F82E),
+    U24(0x5373), GLYPH(0x2F82F),
+    U24(0x5375), GLYPH(0xF91C),
+    U24(0x537D), GLYPH(0x2F830),
+    U24(0x537F), GLYPH(0x2F831),
+    U24(0x53C3), GLYPH(0xF96B),
+    U24(0x53CA), GLYPH(0x2F836),
+    U24(0x53DF), GLYPH(0x2F837),
+    U24(0x53E5), GLYPH(0xF906),
+    U24(0x53EB), GLYPH(0x2F839),
+    U24(0x53F1), GLYPH(0x2F83A),
+    U24(0x5406), GLYPH(0x2F83B),
+    U24(0x540F), GLYPH(0xF9DE),
+    U24(0x541D), GLYPH(0xF9ED),
+    U24(0x5438), GLYPH(0x2F83D),
+    U24(0x5442), GLYPH(0xF980),
+    U24(0x5448), GLYPH(0x2F83E),
+    U24(0x5468), GLYPH(0x2F83F),
+    U24(0x549E), GLYPH(0x2F83C),
+    U24(0x54A2), GLYPH(0x2F840),
+    U24(0x54BD), GLYPH(0xF99E),
+    U24(0x54F6), GLYPH(0x2F841),
+    U24(0x5510), GLYPH(0x2F842),
+    U24(0x5553), GLYPH(0x2F843),
+    U24(0x5555), GLYPH(0xFA79),
+    U24(0x5563), GLYPH(0x2F844),
+    U24(0x5584), GLYPH(0x2F845),
+    U24(0x5587), GLYPH(0xF90B),
+    U24(0x5599), GLYPH(0xFA7A),
+    U24(0x559D), GLYPH(0xFA36),
+    U24(0x55AB), GLYPH(0x2F848),
+    U24(0x55B3), GLYPH(0x2F849),
+    U24(0x55C0), GLYPH(0xFA0D),
+    U24(0x55C2), GLYPH(0x2F84A),
+    U24(0x55E2), GLYPH(0xFA7B),
+    U24(0x5606), GLYPH(0xFA37),
+    U24(0x5651), GLYPH(0x2F84E),
+    U24(0x5668), GLYPH(0xFA38),
+    U24(0x5674), GLYPH(0x2F84F),
+    U24(0x56F9), GLYPH(0xF9A9),
+    U24(0x5716), GLYPH(0x2F84B),
+    U24(0x5717), GLYPH(0x2F84D),
+    U24(0x578B), GLYPH(0x2F855),
+    U24(0x57CE), GLYPH(0x2F852),
+    U24(0x57F4), GLYPH(0x2F853),
+    U24(0x580D), GLYPH(0x2F854),
+    U24(0x5831), GLYPH(0x2F857),
+    U24(0x5832), GLYPH(0x2F856),
+    U24(0x5840), GLYPH(0xFA39),
+    U24(0x585A), GLYPH(0xFA10),
+    U24(0x585E), GLYPH(0xF96C),
+    U24(0x58A8), GLYPH(0xFA3A),
+    U24(0x58AC), GLYPH(0x2F858),
+    U24(0x58B3), GLYPH(0xFA7D),
+    U24(0x58D8), GLYPH(0xF94A),
+    U24(0x58DF), GLYPH(0xF942),
+    U24(0x58EE), GLYPH(0x2F851),
+    U24(0x58F2), GLYPH(0x2F85A),
+    U24(0x58F7), GLYPH(0x2F85B),
+    U24(0x5906), GLYPH(0x2F85C),
+    U24(0x591A), GLYPH(0x2F85D),
+    U24(0x5922), GLYPH(0x2F85E),
+    U24(0x5944), GLYPH(0xFA7E),
+    U24(0x5948), GLYPH(0xF90C),
+    U24(0x5951), GLYPH(0xF909),
+    U24(0x5954), GLYPH(0xFA7F),
+    U24(0x5962), GLYPH(0x2F85F),
+    U24(0x5973), GLYPH(0xF981),
+    U24(0x59D8), GLYPH(0x2F865),
+    U24(0x59EC), GLYPH(0x2F862),
+    U24(0x5A1B), GLYPH(0x2F863),
+    U24(0x5A27), GLYPH(0x2F864),
+    U24(0x5A62), GLYPH(0xFA80),
+    U24(0x5A66), GLYPH(0x2F866),
+    U24(0x5AB5), GLYPH(0x2F986),
+    U24(0x5B08), GLYPH(0x2F869),
+    U24(0x5B28), GLYPH(0xFA81),
+    U24(0x5B3E), GLYPH(0x2F86A),
+    U24(0x5B85), GLYPH(0xFA04),
+    U24(0x5BC3), GLYPH(0x2F86D),
+    U24(0x5BD8), GLYPH(0x2F86E),
+    U24(0x5BE7), GLYPH(0xF95F),
+    U24(0x5BEE), GLYPH(0xF9BC),
+    U24(0x5BF3), GLYPH(0x2F870),
+    U24(0x5BFF), GLYPH(0x2F872),
+    U24(0x5C06), GLYPH(0x2F873),
+    U24(0x5C22), GLYPH(0x2F875),
+    U24(0x5C3F), GLYPH(0xF9BD),
+    U24(0x5C60), GLYPH(0x2F877),
+    U24(0x5C62), GLYPH(0xF94B),
+    U24(0x5C64), GLYPH(0xFA3B),
+    U24(0x5C65), GLYPH(0xF9DF),
+    U24(0x5C6E), GLYPH(0xFA3C),
+    U24(0x5C8D), GLYPH(0x2F87A),
+    U24(0x5CC0), GLYPH(0x2F879),
+    U24(0x5D19), GLYPH(0xF9D5),
+    U24(0x5D43), GLYPH(0x2F87C),
+    U24(0x5D50), GLYPH(0xF921),
+    U24(0x5D6B), GLYPH(0x2F87F),
+    U24(0x5D6E), GLYPH(0x2F87E),
+    U24(0x5D7C), GLYPH(0x2F880),
+    U24(0x5DB2), GLYPH(0x2F9F4),
+    U24(0x5DBA), GLYPH(0xF9AB),
+    U24(0x5DE1), GLYPH(0x2F881),
+    U24(0x5DE2), GLYPH(0x2F882),
+    U24(0x5DFD), GLYPH(0x2F884),
+    U24(0x5E28), GLYPH(0x2F885),
+    U24(0x5E3D), GLYPH(0x2F886),
+    U24(0x5E69), GLYPH(0x2F887),
+    U24(0x5E74), GLYPH(0xF98E),
+    U24(0x5EA6), GLYPH(0xFA01),
+    U24(0x5EB0), GLYPH(0x2F88B),
+    U24(0x5EB3), GLYPH(0x2F88C),
+    U24(0x5EB6), GLYPH(0x2F88D),
+    U24(0x5EC9), GLYPH(0xF9A2),
+    U24(0x5ECA), GLYPH(0xF928),
+    U24(0x5ED2), GLYPH(0xFA82),
+    U24(0x5ED3), GLYPH(0xFA0B),
+    U24(0x5ED9), GLYPH(0xFA83),
+    U24(0x5EEC), GLYPH(0xF982),
+    U24(0x5EFE), GLYPH(0x2F890),
+    U24(0x5F04), GLYPH(0xF943),
+    U24(0x5F22), GLYPH(0x2F894),
+    U24(0x5F53), GLYPH(0x2F874),
+    U24(0x5F62), GLYPH(0x2F899),
+    U24(0x5F69), GLYPH(0xFA84),
+    U24(0x5F6B), GLYPH(0x2F89A),
+    U24(0x5F8B), GLYPH(0xF9D8),
+    U24(0x5F9A), GLYPH(0x2F89C),
+    U24(0x5FA9), GLYPH(0xF966),
+    U24(0x5FAD), GLYPH(0xFA85),
+    U24(0x5FCD), GLYPH(0x2F89D),
+    U24(0x5FD7), GLYPH(0x2F89E),
+    U24(0x5FF5), GLYPH(0xF9A3),
+    U24(0x5FF9), GLYPH(0x2F89F),
+    U24(0x6012), GLYPH(0xF960),
+    U24(0x601C), GLYPH(0xF9AC),
+    U24(0x6075), GLYPH(0xFA6B),
+    U24(0x6081), GLYPH(0x2F8A0),
+    U24(0x6094), GLYPH(0xFA3D),
+    U24(0x60C7), GLYPH(0x2F8A5),
+    U24(0x60D8), GLYPH(0xFA86),
+    U24(0x60E1), GLYPH(0xF9B9),
+    U24(0x6108), GLYPH(0xFA88),
+    U24(0x6144), GLYPH(0xF9D9),
+    U24(0x6148), GLYPH(0x2F8A6),
+    U24(0x614C), GLYPH(0x2F8A7),
+    U24(0x614E), GLYPH(0xFA87),
+    U24(0x6160), GLYPH(0xFA8A),
+    U24(0x6168), GLYPH(0xFA3E),
+    U24(0x617A), GLYPH(0x2F8AA),
+    U24(0x618E), GLYPH(0xFA3F),
+    U24(0x6190), GLYPH(0xF98F),
+    U24(0x61A4), GLYPH(0x2F8AD),
+    U24(0x61AF), GLYPH(0x2F8AE),
+    U24(0x61B2), GLYPH(0x2F8AC),
+    U24(0x61DE), GLYPH(0x2F8AF),
+    U24(0x61F2), GLYPH(0xFA40),
+    U24(0x61F6), GLYPH(0xF90D),
+    U24(0x6200), GLYPH(0xF990),
+    U24(0x6210), GLYPH(0x2F8B2),
+    U24(0x621B), GLYPH(0x2F8B3),
+    U24(0x622E), GLYPH(0xF9D2),
+    U24(0x6234), GLYPH(0xFA8C),
+    U24(0x625D), GLYPH(0x2F8B4),
+    U24(0x62B1), GLYPH(0x2F8B5),
+    U24(0x62C9), GLYPH(0xF925),
+    U24(0x62CF), GLYPH(0xF95B),
+    U24(0x62D3), GLYPH(0xFA02),
+    U24(0x62D4), GLYPH(0x2F8B6),
+    U24(0x62FC), GLYPH(0x2F8BA),
+    U24(0x62FE), GLYPH(0xF973),
+    U24(0x633D), GLYPH(0x2F8B9),
+    U24(0x6350), GLYPH(0x2F8B7),
+    U24(0x6368), GLYPH(0x2F8BB),
+    U24(0x637B), GLYPH(0xF9A4),
+    U24(0x6383), GLYPH(0x2F8BC),
+    U24(0x63A0), GLYPH(0xF975),
+    U24(0x63A9), GLYPH(0x2F8C1),
+    U24(0x63C4), GLYPH(0xFA8D),
+    U24(0x63C5), GLYPH(0x2F8C0),
+    U24(0x63E4), GLYPH(0x2F8BD),
+    U24(0x641C), GLYPH(0xFA8E),
+    U24(0x6422), GLYPH(0x2F8BF),
+    U24(0x6452), GLYPH(0xFA8F),
+    U24(0x6469), GLYPH(0x2F8C3),
+    U24(0x6477), GLYPH(0x2F8C6),
+    U24(0x647E), GLYPH(0x2F8C4),
+    U24(0x649A), GLYPH(0xF991),
+    U24(0x649D), GLYPH(0x2F8C5),
+    U24(0x64C4), GLYPH(0xF930),
+    U24(0x654F), GLYPH(0xFA41),
+    U24(0x6556), GLYPH(0xFA90),
+    U24(0x656C), GLYPH(0x2F8C9),
+    U24(0x6578), GLYPH(0xF969),
+    U24(0x6599), GLYPH(0xF9BE),
+    U24(0x65C5), GLYPH(0xF983),
+    U24(0x65E2), GLYPH(0xFA42),
+    U24(0x65E3), GLYPH(0x2F8CB),
+    U24(0x6613), GLYPH(0xF9E0),
+    U24(0x6649), GLYPH(0x2F8CD),
+    U24(0x6674), GLYPH(0xFA12),
+    U24(0x6688), GLYPH(0xF9C5),
+    U24(0x6691), GLYPH(0xFA43),
+    U24(0x669C), GLYPH(0x2F8D5),
+    U24(0x66B4), GLYPH(0xFA06),
+    U24(0x66C6), GLYPH(0xF98B),
+    U24(0x66F4), GLYPH(0xF901),
+    U24(0x66F8), GLYPH(0x2F8CC),
+    U24(0x6700), GLYPH(0x2F8D4),
+    U24(0x6717), GLYPH(0xF929),
+    U24(0x671B), GLYPH(0xFA93),
+    U24(0x6721), GLYPH(0x2F8DA),
+    U24(0x674E), GLYPH(0xF9E1),
+    U24(0x6753), GLYPH(0x2F8DC),
+    U24(0x6756), GLYPH(0xFA94),
+    U24(0x675E), GLYPH(0x2F8DB),
+    U24(0x677B), GLYPH(0xF9C8),
+    U24(0x6785), GLYPH(0x2F8E0),
+    U24(0x6797), GLYPH(0xF9F4),
+    U24(0x67F3), GLYPH(0xF9C9),
+    U24(0x67FA), GLYPH(0x2F8DF),
+    U24(0x6817), GLYPH(0xF9DA),
+    U24(0x681F), GLYPH(0x2F8E5),
+    U24(0x6852), GLYPH(0x2F8E1),
+    U24(0x6881), GLYPH(0xF97A),
+    U24(0x6885), GLYPH(0xFA44),
+    U24(0x688E), GLYPH(0x2F8E4),
+    U24(0x68A8), GLYPH(0xF9E2),
+    U24(0x6914), GLYPH(0x2F8E6),
+    U24(0x6942), GLYPH(0x2F8E8),
+    U24(0x69A3), GLYPH(0x2F8E9),
+    U24(0x69EA), GLYPH(0x2F8EA),
+    U24(0x6A02), GLYPH(0xF914),
+    U24(0x6A13), GLYPH(0xF94C),
+    U24(0x6AA8), GLYPH(0x2F8EB),
+    U24(0x6AD3), GLYPH(0xF931),
+    U24(0x6ADB), GLYPH(0x2F8ED),
+    U24(0x6B04), GLYPH(0xF91D),
+    U24(0x6B21), GLYPH(0x2F8EF),
+    U24(0x6B54), GLYPH(0x2F8F1),
+    U24(0x6B72), GLYPH(0x2F8F3),
+    U24(0x6B77), GLYPH(0xF98C),
+    U24(0x6B79), GLYPH(0xFA95),
+    U24(0x6B9F), GLYPH(0x2F8F4),
+    U24(0x6BAE), GLYPH(0xF9A5),
+    U24(0x6BBA), GLYPH(0xF970),
+    U24(0x6BBB), GLYPH(0x2F8F6),
+    U24(0x6C4E), GLYPH(0x2F8FA),
+    U24(0x6C67), GLYPH(0x2F8FE),
+    U24(0x6C88), GLYPH(0xF972),
+    U24(0x6CBF), GLYPH(0x2F8FC),
+    U24(0x6CCC), GLYPH(0xF968),
+    U24(0x6CCD), GLYPH(0x2F8FD),
+    U24(0x6CE5), GLYPH(0xF9E3),
+    U24(0x6D16), GLYPH(0x2F8FF),
+    U24(0x6D1B), GLYPH(0xF915),
+    U24(0x6D1E), GLYPH(0xFA05),
+    U24(0x6D34), GLYPH(0x2F907),
+    U24(0x6D3E), GLYPH(0x2F900),
+    U24(0x6D41), GLYPH(0xF9CA),
+    U24(0x6D69), GLYPH(0x2F903),
+    U24(0x6D6A), GLYPH(0xF92A),
+    U24(0x6D77), GLYPH(0xFA45),
+    U24(0x6D78), GLYPH(0x2F904),
+    U24(0x6D85), GLYPH(0x2F905),
+    U24(0x6DCB), GLYPH(0xF9F5),
+    U24(0x6DDA), GLYPH(0xF94D),
+    U24(0x6DEA), GLYPH(0xF9D6),
+    U24(0x6DF9), GLYPH(0x2F90E),
+    U24(0x6E1A), GLYPH(0xFA46),
+    U24(0x6E2F), GLYPH(0x2F908),
+    U24(0x6E6E), GLYPH(0x2F909),
+    U24(0x6E9C), GLYPH(0xF9CB),
+    U24(0x6EBA), GLYPH(0xF9EC),
+    U24(0x6EC7), GLYPH(0x2F90C),
+    U24(0x6ECB), GLYPH(0xFA99),
+    U24(0x6ED1), GLYPH(0xF904),
+    U24(0x6EDB), GLYPH(0xFA98),
+    U24(0x6F0F), GLYPH(0xF94E),
+    U24(0x6F22), GLYPH(0xFA47),
+    U24(0x6F23), GLYPH(0xF992),
+    U24(0x6F6E), GLYPH(0x2F90F),
+    U24(0x6FC6), GLYPH(0x2F912),
+    U24(0x6FEB), GLYPH(0xF922),
+    U24(0x6FFE), GLYPH(0xF984),
+    U24(0x701B), GLYPH(0x2F915),
+    U24(0x701E), GLYPH(0xFA9B),
+    U24(0x7039), GLYPH(0x2F913),
+    U24(0x704A), GLYPH(0x2F917),
+    U24(0x7070), GLYPH(0x2F835),
+    U24(0x7077), GLYPH(0x2F919),
+    U24(0x707D), GLYPH(0x2F918),
+    U24(0x7099), GLYPH(0xF9FB),
+    U24(0x70AD), GLYPH(0x2F91A),
+    U24(0x70C8), GLYPH(0xF99F),
+    U24(0x70D9), GLYPH(0xF916),
+    U24(0x7145), GLYPH(0x2F91C),
+    U24(0x7149), GLYPH(0xF993),
+    U24(0x716E), GLYPH(0xFA48),
+    U24(0x719C), GLYPH(0x2F91E),
+    U24(0x71CE), GLYPH(0xF9C0),
+    U24(0x71D0), GLYPH(0xF9EE),
+    U24(0x7210), GLYPH(0xF932),
+    U24(0x721B), GLYPH(0xF91E),
+    U24(0x7228), GLYPH(0x2F920),
+    U24(0x722B), GLYPH(0xFA49),
+    U24(0x7235), GLYPH(0xFA9E),
+    U24(0x7250), GLYPH(0x2F922),
+    U24(0x7262), GLYPH(0xF946),
+    U24(0x7280), GLYPH(0x2F924),
+    U24(0x7295), GLYPH(0x2F925),
+    U24(0x72AF), GLYPH(0xFA9F),
+    U24(0x72C0), GLYPH(0xF9FA),
+    U24(0x72FC), GLYPH(0xF92B),
+    U24(0x732A), GLYPH(0xFA16),
+    U24(0x7375), GLYPH(0xF9A7),
+    U24(0x737A), GLYPH(0x2F928),
+    U24(0x7387), GLYPH(0xF961),
+    U24(0x738B), GLYPH(0x2F929),
+    U24(0x73A5), GLYPH(0x2F92B),
+    U24(0x73B2), GLYPH(0xF9AD),
+    U24(0x73DE), GLYPH(0xF917),
+    U24(0x7406), GLYPH(0xF9E4),
+    U24(0x7409), GLYPH(0xF9CC),
+    U24(0x7422), GLYPH(0xFA4A),
+    U24(0x7447), GLYPH(0x2F92E),
+    U24(0x745C), GLYPH(0x2F92F),
+    U24(0x7469), GLYPH(0xF9AE),
+    U24(0x7471), GLYPH(0xFAA1),
+    U24(0x7485), GLYPH(0x2F931),
+    U24(0x7489), GLYPH(0xF994),
+    U24(0x7498), GLYPH(0xF9EF),
+    U24(0x74CA), GLYPH(0x2F932),
+    U24(0x7506), GLYPH(0xFAA2),
+    U24(0x7524), GLYPH(0x2F934),
+    U24(0x753B), GLYPH(0xFAA3),
+    U24(0x753E), GLYPH(0x2F936),
+    U24(0x7559), GLYPH(0xF9CD),
+    U24(0x7565), GLYPH(0xF976),
+    U24(0x7570), GLYPH(0xF962),
+    U24(0x75E2), GLYPH(0xF9E5),
+    U24(0x7610), GLYPH(0x2F93A),
+    U24(0x761D), GLYPH(0xFAA4),
+    U24(0x761F), GLYPH(0xFAA5),
+    U24(0x7642), GLYPH(0xF9C1),
+    U24(0x7669), GLYPH(0xF90E),
+    U24(0x76CA), GLYPH(0xFA17),
+    U24(0x76DB), GLYPH(0xFAA7),
+    U24(0x76E7), GLYPH(0xF933),
+    U24(0x76F4), GLYPH(0xFAA8),
+    U24(0x7701), GLYPH(0xF96D),
+    U24(0x771E), GLYPH(0x2F945),
+    U24(0x771F), GLYPH(0x2F946),
+    U24(0x7740), GLYPH(0xFAAA),
+    U24(0x774A), GLYPH(0xFAA9),
+    U24(0x778B), GLYPH(0x2F94A),
+    U24(0x77A7), GLYPH(0xFA9D),
+    U24(0x784E), GLYPH(0x2F94E),
+    U24(0x786B), GLYPH(0xF9CE),
+    U24(0x788C), GLYPH(0xF93B),
+    U24(0x7891), GLYPH(0xFA4B),
+    U24(0x78CA), GLYPH(0xF947),
+    U24(0x78CC), GLYPH(0xFAAB),
+    U24(0x78FB), GLYPH(0xF964),
+    U24(0x792A), GLYPH(0xF985),
+    U24(0x793C), GLYPH(0xFA18),
+    U24(0x793E), GLYPH(0xFA4C),
+    U24(0x7948), GLYPH(0xFA4E),
+    U24(0x7949), GLYPH(0xFA4D),
+    U24(0x7950), GLYPH(0xFA4F),
+    U24(0x7956), GLYPH(0xFA50),
+    U24(0x795D), GLYPH(0xFA51),
+    U24(0x795E), GLYPH(0xFA19),
+    U24(0x7965), GLYPH(0xFA1A),
+    U24(0x797F), GLYPH(0xF93C),
+    U24(0x798D), GLYPH(0xFA52),
+    U24(0x798E), GLYPH(0xFA53),
+    U24(0x798F), GLYPH(0xFA1B),
+    U24(0x79AE), GLYPH(0xF9B6),
+    U24(0x79CA), GLYPH(0xF995),
+    U24(0x79EB), GLYPH(0x2F957),
+    U24(0x7A1C), GLYPH(0xF956),
+    U24(0x7A40), GLYPH(0xFA54),
+    U24(0x7A4A), GLYPH(0x2F95A),
+    U24(0x7A4F), GLYPH(0x2F95B),
+    U24(0x7A81), GLYPH(0xFA55),
+    U24(0x7AB1), GLYPH(0xFAAC),
+    U24(0x7ACB), GLYPH(0xF9F7),
+    U24(0x7AEE), GLYPH(0x2F95F),
+    U24(0x7B20), GLYPH(0xF9F8),
+    U24(0x7BC0), GLYPH(0xFA56),
+    U24(0x7BC6), GLYPH(0x2F962),
+    U24(0x7BC9), GLYPH(0x2F963),
+    U24(0x7C3E), GLYPH(0xF9A6),
+    U24(0x7C60), GLYPH(0xF944),
+    U24(0x7C7B), GLYPH(0xFAAE),
+    U24(0x7C92), GLYPH(0xF9F9),
+    U24(0x7CBE), GLYPH(0xFA1D),
+    U24(0x7CD2), GLYPH(0x2F966),
+    U24(0x7CD6), GLYPH(0xFA03),
+    U24(0x7CE3), GLYPH(0x2F969),
+    U24(0x7CE7), GLYPH(0xF97B),
+    U24(0x7CE8), GLYPH(0x2F968),
+    U24(0x7D00), GLYPH(0x2F96A),
+    U24(0x7D10), GLYPH(0xF9CF),
+    U24(0x7D22), GLYPH(0xF96A),
+    U24(0x7D2F), GLYPH(0xF94F),
+    U24(0x7D5B), GLYPH(0xFAAF),
+    U24(0x7D63), GLYPH(0x2F96C),
+    U24(0x7DA0), GLYPH(0xF93D),
+    U24(0x7DBE), GLYPH(0xF957),
+    U24(0x7DC7), GLYPH(0x2F96E),
+    U24(0x7DF4), GLYPH(0xF996),
+    U24(0x7E02), GLYPH(0x2F96F),
+    U24(0x7E09), GLYPH(0xFA58),
+    U24(0x7E37), GLYPH(0xF950),
+    U24(0x7E41), GLYPH(0xFA59),
+    U24(0x7E45), GLYPH(0x2F970),
+    U24(0x7F3E), GLYPH(0xFAB1),
+    U24(0x7F72), GLYPH(0xFA5A),
+    U24(0x7F79), GLYPH(0xF9E6),
+    U24(0x7F7A), GLYPH(0x2F976),
+    U24(0x7F85), GLYPH(0xF90F),
+    U24(0x7F95), GLYPH(0x2F978),
+    U24(0x7F9A), GLYPH(0xF9AF),
+    U24(0x7FBD), GLYPH(0xFA1E),
+    U24(0x7FFA), GLYPH(0x2F979),
+    U24(0x8001), GLYPH(0xF934),
+    U24(0x8005), GLYPH(0xFA5B),
+    U24(0x8046), GLYPH(0xF9B0),
+    U24(0x8060), GLYPH(0x2F97D),
+    U24(0x806F), GLYPH(0xF997),
+    U24(0x8070), GLYPH(0x2F97F),
+    U24(0x807E), GLYPH(0xF945),
+    U24(0x808B), GLYPH(0xF953),
+    U24(0x80AD), GLYPH(0x2F8D6),
+    U24(0x80B2), GLYPH(0x2F982),
+    U24(0x8103), GLYPH(0x2F983),
+    U24(0x813E), GLYPH(0x2F985),
+    U24(0x81D8), GLYPH(0xF926),
+    U24(0x81E8), GLYPH(0xF9F6),
+    U24(0x81ED), GLYPH(0xFA5C),
+    U24(0x8201), GLYPH(0x2F893),
+    U24(0x8204), GLYPH(0x2F98C),
+    U24(0x8218), GLYPH(0xFA6D),
+    U24(0x826F), GLYPH(0xF97C),
+    U24(0x8279), GLYPH(0xFA5D),
+    U24(0x828B), GLYPH(0x2F990),
+    U24(0x8291), GLYPH(0x2F98F),
+    U24(0x829D), GLYPH(0x2F991),
+    U24(0x82B1), GLYPH(0x2F993),
+    U24(0x82B3), GLYPH(0x2F994),
+    U24(0x82BD), GLYPH(0x2F995),
+    U24(0x82E5), GLYPH(0xF974),
+    U24(0x82E6), GLYPH(0x2F996),
+    U24(0x831D), GLYPH(0x2F999),
+    U24(0x8323), GLYPH(0x2F99C),
+    U24(0x8336), GLYPH(0xF9FE),
+    U24(0x8352), GLYPH(0xFAB3),
+    U24(0x8353), GLYPH(0x2F9A0),
+    U24(0x8363), GLYPH(0x2F99A),
+    U24(0x83AD), GLYPH(0x2F99B),
+    U24(0x83BD), GLYPH(0x2F99D),
+    U24(0x83C9), GLYPH(0xF93E),
+    U24(0x83CA), GLYPH(0x2F9A1),
+    U24(0x83CC), GLYPH(0x2F9A2),
+    U24(0x83DC), GLYPH(0x2F9A3),
+    U24(0x83E7), GLYPH(0x2F99E),
+    U24(0x83EF), GLYPH(0xFAB4),
+    U24(0x83F1), GLYPH(0xF958),
+    U24(0x843D), GLYPH(0xF918),
+    U24(0x8449), GLYPH(0xF96E),
+    U24(0x8457), GLYPH(0xFA5F),
+    U24(0x84EE), GLYPH(0xF999),
+    U24(0x84F1), GLYPH(0x2F9A8),
+    U24(0x84F3), GLYPH(0x2F9A9),
+    U24(0x84FC), GLYPH(0xF9C2),
+    U24(0x8516), GLYPH(0x2F9AA),
+    U24(0x8564), GLYPH(0x2F9AC),
+    U24(0x85CD), GLYPH(0xF923),
+    U24(0x85FA), GLYPH(0xF9F0),
+    U24(0x8606), GLYPH(0xF935),
+    U24(0x8612), GLYPH(0xFA20),
+    U24(0x862D), GLYPH(0xF91F),
+    U24(0x863F), GLYPH(0xF910),
+    U24(0x8650), GLYPH(0x2F9B3),
+    U24(0x865C), GLYPH(0xF936),
+    U24(0x8667), GLYPH(0x2F9B5),
+    U24(0x8669), GLYPH(0x2F9B6),
+    U24(0x8688), GLYPH(0x2F9B8),
+    U24(0x86A9), GLYPH(0x2F9B7),
+    U24(0x86E2), GLYPH(0x2F9BA),
+    U24(0x870E), GLYPH(0x2F9B9),
+    U24(0x8728), GLYPH(0x2F9BC),
+    U24(0x876B), GLYPH(0x2F9BD),
+    U24(0x8779), GLYPH(0xFAB5),
+    U24(0x8786), GLYPH(0x2F9BE),
+    U24(0x87BA), GLYPH(0xF911),
+    U24(0x87E1), GLYPH(0x2F9C0),
+    U24(0x8801), GLYPH(0x2F9C1),
+    U24(0x881F), GLYPH(0xF927),
+    U24(0x884C), GLYPH(0xFA08),
+    U24(0x8860), GLYPH(0x2F9C3),
+    U24(0x8863), GLYPH(0x2F9C4),
+    U24(0x88C2), GLYPH(0xF9A0),
+    U24(0x88CF), GLYPH(0xF9E7),
+    U24(0x88D7), GLYPH(0x2F9C6),
+    U24(0x88DE), GLYPH(0x2F9C7),
+    U24(0x88E1), GLYPH(0xF9E8),
+    U24(0x88F8), GLYPH(0xF912),
+    U24(0x88FA), GLYPH(0x2F9C9),
+    U24(0x8910), GLYPH(0xFA60),
+    U24(0x8941), GLYPH(0xFAB6),
+    U24(0x8964), GLYPH(0xF924),
+    U24(0x8986), GLYPH(0xFAB7),
+    U24(0x898B), GLYPH(0xFA0A),
+    U24(0x8996), GLYPH(0xFA61),
+    U24(0x8AA0), GLYPH(0x2F9CF),
+    U24(0x8AAA), GLYPH(0xF96F),
+    U24(0x8ABF), GLYPH(0xFAB9),
+    U24(0x8ACB), GLYPH(0xFABB),
+    U24(0x8AD2), GLYPH(0xF97D),
+    U24(0x8AD6), GLYPH(0xF941),
+    U24(0x8AED), GLYPH(0xFABE),
+    U24(0x8AF8), GLYPH(0xFA22),
+    U24(0x8AFE), GLYPH(0xF95D),
+    U24(0x8B01), GLYPH(0xFA62),
+    U24(0x8B39), GLYPH(0xFA63),
+    U24(0x8B58), GLYPH(0xF9FC),
+    U24(0x8B80), GLYPH(0xF95A),
+    U24(0x8B8A), GLYPH(0xFAC0),
+    U24(0x8C48), GLYPH(0xF900),
+    U24(0x8C55), GLYPH(0x2F9D2),
+    U24(0x8CAB), GLYPH(0x2F9D4),
+    U24(0x8CC1), GLYPH(0x2F9D5),
+    U24(0x8CC2), GLYPH(0xF948),
+    U24(0x8CC8), GLYPH(0xF903),
+    U24(0x8CD3), GLYPH(0xFA64),
+    U24(0x8D08), GLYPH(0xFA65),
+    U24(0x8D1B), GLYPH(0x2F9D6),
+    U24(0x8D77), GLYPH(0x2F9D7),
+    U24(0x8DBC), GLYPH(0x2F9DB),
+    U24(0x8DCB), GLYPH(0x2F9DA),
+    U24(0x8DEF), GLYPH(0xF937),
+    U24(0x8DF0), GLYPH(0x2F9DC),
+    U24(0x8ECA), GLYPH(0xF902),
+    U24(0x8ED4), GLYPH(0x2F9DE),
+    U24(0x8F26), GLYPH(0xF998),
+    U24(0x8F2A), GLYPH(0xF9D7),
+    U24(0x8F38), GLYPH(0xFAC2),
+    U24(0x8F3B), GLYPH(0xFA07),
+    U24(0x8F62), GLYPH(0xF98D),
+    U24(0x8F9E), GLYPH(0x2F98D),
+    U24(0x8FB0), GLYPH(0xF971),
+    U24(0x8FB6), GLYPH(0xFA66),
+    U24(0x9023), GLYPH(0xF99A),
+    U24(0x9038), GLYPH(0xFA25),
+    U24(0x9072), GLYPH(0xFAC3),
+    U24(0x907C), GLYPH(0xF9C3),
+    U24(0x908F), GLYPH(0xF913),
+    U24(0x9094), GLYPH(0x2F9E2),
+    U24(0x90CE), GLYPH(0xF92C),
+    U24(0x90DE), GLYPH(0xFA2E),
+    U24(0x90F1), GLYPH(0x2F9E3),
+    U24(0x90FD), GLYPH(0xFA26),
+    U24(0x9111), GLYPH(0x2F9E4),
+    U24(0x911B), GLYPH(0x2F9E6),
+    U24(0x916A), GLYPH(0xF919),
+    U24(0x9199), GLYPH(0xFAC4),
+    U24(0x91B4), GLYPH(0xF9B7),
+    U24(0x91CC), GLYPH(0xF9E9),
+    U24(0x91CF), GLYPH(0xF97E),
+    U24(0x91D1), GLYPH(0xF90A),
+    U24(0x9234), GLYPH(0xF9B1),
+    U24(0x9238), GLYPH(0x2F9E7),
+    U24(0x9276), GLYPH(0xFAC5),
+    U24(0x927C), GLYPH(0x2F9EA),
+    U24(0x92D7), GLYPH(0x2F9E8),
+    U24(0x92D8), GLYPH(0x2F9E9),
+    U24(0x9304), GLYPH(0xF93F),
+    U24(0x934A), GLYPH(0xF99B),
+    U24(0x93F9), GLYPH(0x2F9EB),
+    U24(0x9415), GLYPH(0x2F9EC),
+    U24(0x958B), GLYPH(0x2F9EE),
+    U24(0x95AD), GLYPH(0xF986),
+    U24(0x95B7), GLYPH(0x2F9F0),
+    U24(0x962E), GLYPH(0xF9C6),
+    U24(0x964B), GLYPH(0xF951),
+    U24(0x964D), GLYPH(0xFA09),
+    U24(0x9675), GLYPH(0xF959),
+    U24(0x9678), GLYPH(0xF9D3),
+    U24(0x967C), GLYPH(0xFAC6),
+    U24(0x9686), GLYPH(0xF9DC),
+    U24(0x96A3), GLYPH(0xF9F1),
+    U24(0x96B7), GLYPH(0xFA2F),
+    U24(0x96B8), GLYPH(0xF9B8),
+    U24(0x96C3), GLYPH(0x2F9F3),
+    U24(0x96E2), GLYPH(0xF9EA),
+    U24(0x96E3), GLYPH(0xFA68),
+    U24(0x96F6), GLYPH(0xF9B2),
+    U24(0x96F7), GLYPH(0xF949),
+    U24(0x9723), GLYPH(0x2F9F5),
+    U24(0x9732), GLYPH(0xF938),
+    U24(0x9748), GLYPH(0xF9B3),
+    U24(0x9756), GLYPH(0xFA1C),
+    U24(0x97DB), GLYPH(0xFAC9),
+    U24(0x97E0), GLYPH(0x2F9FA),
+    U24(0x97FF), GLYPH(0xFA69),
+    U24(0x980B), GLYPH(0xFACB),
+    U24(0x9818), GLYPH(0xF9B4),
+    U24(0x9829), GLYPH(0x2FA00),
+    U24(0x983B), GLYPH(0xFA6A),
+    U24(0x985E), GLYPH(0xF9D0),
+    U24(0x98E2), GLYPH(0x2FA02),
+    U24(0x98EF), GLYPH(0xFA2A),
+    U24(0x98FC), GLYPH(0xFA2B),
+    U24(0x9928), GLYPH(0xFA2C),
+    U24(0x9929), GLYPH(0x2FA04),
+    U24(0x99A7), GLYPH(0x2FA05),
+    U24(0x99C2), GLYPH(0x2FA06),
+    U24(0x99F1), GLYPH(0xF91A),
+    U24(0x99FE), GLYPH(0x2FA07),
+    U24(0x9A6A), GLYPH(0xF987),
+    U24(0x9B12), GLYPH(0xFACD),
+    U24(0x9B6F), GLYPH(0xF939),
+    U24(0x9C40), GLYPH(0x2FA0B),
+    U24(0x9C57), GLYPH(0xF9F2),
+    U24(0x9CFD), GLYPH(0x2FA0C),
+    U24(0x9D67), GLYPH(0x2FA0F),
+    U24(0x9DB4), GLYPH(0xFA2D),
+    U24(0x9DFA), GLYPH(0xF93A),
+    U24(0x9E1E), GLYPH(0xF920),
+    U24(0x9E7F), GLYPH(0xF940),
+    U24(0x9E97), GLYPH(0xF988),
+    U24(0x9E9F), GLYPH(0xF9F3),
+    U24(0x9EBB), GLYPH(0x2FA15),
+    U24(0x9ECE), GLYPH(0xF989),
+    U24(0x9EF9), GLYPH(0x2FA17),
+    U24(0x9EFE), GLYPH(0x2FA18),
+    U24(0x9F05), GLYPH(0x2FA19),
+    U24(0x9F0F), GLYPH(0x2FA1A),
+    U24(0x9F16), GLYPH(0x2FA1B),
+    U24(0x9F3B), GLYPH(0x2FA1C),
+    U24(0x9F43), GLYPH(0xFAD8),
+    U24(0x9F8D), GLYPH(0xF9C4),
+    U24(0x9F8E), GLYPH(0xFAD9),
+    U24(0x9F9C), GLYPH(0xF907),
+    U24(0x20122), GLYPH(0x2F803),
+    U24(0x2051C), GLYPH(0x2F812),
+    U24(0x20525), GLYPH(0x2F91B),
+    U24(0x2054B), GLYPH(0x2F816),
+    U24(0x2063A), GLYPH(0x2F80D),
+    U24(0x20804), GLYPH(0x2F9D9),
+    U24(0x208DE), GLYPH(0x2F9DD),
+    U24(0x20A2C), GLYPH(0x2F834),
+    U24(0x20B63), GLYPH(0x2F838),
+    U24(0x214E4), GLYPH(0x2F859),
+    U24(0x216A8), GLYPH(0x2F860),
+    U24(0x216EA), GLYPH(0x2F861),
+    U24(0x219C8), GLYPH(0x2F86C),
+    U24(0x21B18), GLYPH(0x2F871),
+    U24(0x21D0B), GLYPH(0x2F8F8),
+    U24(0x21DE4), GLYPH(0x2F87B),
+    U24(0x21DE6), GLYPH(0x2F87D),
+    U24(0x22183), GLYPH(0x2F889),
+    U24(0x2219F), GLYPH(0x2F939),
+    U24(0x22331), GLYPH(0x2F891),
+    U24(0x226D4), GLYPH(0x2F8A4),
+    U24(0x22844), GLYPH(0xFAD0),
+    U24(0x2284A), GLYPH(0xFACF),
+    U24(0x22B0C), GLYPH(0x2F8B8),
+    U24(0x22BF1), GLYPH(0x2F8BE),
+    U24(0x2300A), GLYPH(0x2F8CA),
+    U24(0x232B8), GLYPH(0x2F897),
+    U24(0x2335F), GLYPH(0x2F980),
+    U24(0x23393), GLYPH(0x2F989),
+    U24(0x2339C), GLYPH(0x2F98A),
+    U24(0x233C3), GLYPH(0x2F8DD),
+    U24(0x233D5), GLYPH(0xFAD1),
+    U24(0x2346D), GLYPH(0x2F8E3),
+    U24(0x236A3), GLYPH(0x2F8EC),
+    U24(0x238A7), GLYPH(0x2F8F0),
+    U24(0x23A8D), GLYPH(0x2F8F7),
+    U24(0x23AFA), GLYPH(0x2F8F9),
+    U24(0x23CBC), GLYPH(0x2F8FB),
+    U24(0x23D1E), GLYPH(0x2F906),
+    U24(0x23ED1), GLYPH(0x2F90D),
+    U24(0x23F5E), GLYPH(0x2F910),
+    U24(0x23F8E), GLYPH(0x2F911),
+    U24(0x24263), GLYPH(0x2F91D),
+    U24(0x242EE), GLYPH(0xFA6C),
+    U24(0x243AB), GLYPH(0x2F91F),
+    U24(0x24608), GLYPH(0x2F923),
+    U24(0x24735), GLYPH(0x2F926),
+    U24(0x24814), GLYPH(0x2F927),
+    U24(0x24C36), GLYPH(0x2F935),
+    U24(0x24C92), GLYPH(0x2F937),
+    U24(0x24FA1), GLYPH(0x2F93B),
+    U24(0x24FB8), GLYPH(0x2F93C),
+    U24(0x25044), GLYPH(0x2F93D),
+    U24(0x250F2), GLYPH(0x2F942),
+    U24(0x250F3), GLYPH(0x2F941),
+    U24(0x25119), GLYPH(0x2F943),
+    U24(0x25133), GLYPH(0x2F944),
+    U24(0x25249), GLYPH(0xFAD5),
+    U24(0x2541D), GLYPH(0x2F94D),
+    U24(0x25626), GLYPH(0x2F952),
+    U24(0x2569A), GLYPH(0x2F954),
+    U24(0x256C5), GLYPH(0x2F955),
+    U24(0x2597C), GLYPH(0x2F95C),
+    U24(0x25AA7), GLYPH(0x2F95D),
+    U24(0x25BAB), GLYPH(0x2F961),
+    U24(0x25C80), GLYPH(0x2F965),
+    U24(0x25CD0), GLYPH(0xFAD6),
+    U24(0x25F86), GLYPH(0x2F96B),
+    U24(0x261DA), GLYPH(0x2F898),
+    U24(0x26228), GLYPH(0x2F972),
+    U24(0x26247), GLYPH(0x2F973),
+    U24(0x262D9), GLYPH(0x2F975),
+    U24(0x2633E), GLYPH(0x2F977),
+    U24(0x264DA), GLYPH(0x2F97B),
+    U24(0x26523), GLYPH(0x2F97C),
+    U24(0x265A8), GLYPH(0x2F97E),
+    U24(0x267A7), GLYPH(0x2F987),
+    U24(0x267B5), GLYPH(0x2F988),
+    U24(0x26B3C), GLYPH(0x2F997),
+    U24(0x26C36), GLYPH(0x2F9A4),
+    U24(0x26CD5), GLYPH(0x2F9A6),
+    U24(0x26D6B), GLYPH(0x2F9A5),
+    U24(0x26F2C), GLYPH(0x2F9AD),
+    U24(0x26FB1), GLYPH(0x2F9B0),
+    U24(0x270D2), GLYPH(0x2F9B1),
+    U24(0x273CA), GLYPH(0x2F9AB),
+    U24(0x27667), GLYPH(0x2F9C5),
+    U24(0x278AE), GLYPH(0x2F9CB),
+    U24(0x27966), GLYPH(0x2F9CC),
+    U24(0x27CA8), GLYPH(0x2F9D3),
+    U24(0x27ED3), GLYPH(0xFAD7),
+    U24(0x27F2F), GLYPH(0x2F9D8),
+    U24(0x285D2), GLYPH(0x2F9E0),
+    U24(0x285ED), GLYPH(0x2F9E1),
+    U24(0x2872E), GLYPH(0x2F9E5),
+    U24(0x28BFA), GLYPH(0x2F9ED),
+    U24(0x28D77), GLYPH(0x2F9F1),
+    U24(0x29145), GLYPH(0x2F9F6),
+    U24(0x291DF), GLYPH(0x2F81C),
+    U24(0x2921A), GLYPH(0x2F9F7),
+    U24(0x2940A), GLYPH(0x2F9FB),
+    U24(0x29496), GLYPH(0x2F9FD),
+    U24(0x295B6), GLYPH(0x2FA01),
+    U24(0x29B30), GLYPH(0x2FA09),
+    U24(0x2A0CE), GLYPH(0x2FA10),
+    U24(0x2A105), GLYPH(0x2FA12),
+    U24(0x2A20E), GLYPH(0x2FA13),
+    U24(0x2A291), GLYPH(0x2FA14),
+    U24(0x2A392), GLYPH(0x2F88F),
+    U24(0x2A600), GLYPH(0x2FA1D),
+  // 0xFE01
+  U32(88), // numUVSMappings
+    U24(0x3B9D), GLYPH(0x2F8E7),
+    U24(0x3EB8), GLYPH(0x2F92D),
+    U24(0x4039), GLYPH(0x2F949),
+    U24(0x4FAE), GLYPH(0x2F805),
+    U24(0x50E7), GLYPH(0x2F80A),
+    U24(0x514D), GLYPH(0x2F80E),
+    U24(0x51B5), GLYPH(0x2F81B),
+    U24(0x5207), GLYPH(0x2F850),
+    U24(0x52C7), GLYPH(0x2F825),
+    U24(0x52C9), GLYPH(0x2F826),
+    U24(0x52E4), GLYPH(0x2F827),
+    U24(0x52FA), GLYPH(0x2F828),
+    U24(0x5317), GLYPH(0x2F82B),
+    U24(0x5351), GLYPH(0x2F82D),
+    U24(0x537F), GLYPH(0x2F832),
+    U24(0x5584), GLYPH(0x2F846),
+    U24(0x5599), GLYPH(0x2F847),
+    U24(0x559D), GLYPH(0xFA78),
+    U24(0x5606), GLYPH(0x2F84C),
+    U24(0x585A), GLYPH(0xFA7C),
+    U24(0x5B3E), GLYPH(0x2F86B),
+    U24(0x5BE7), GLYPH(0xF9AA),
+    U24(0x5C6E), GLYPH(0x2F878),
+    U24(0x5ECA), GLYPH(0x2F88E),
+    U24(0x5F22), GLYPH(0x2F895),
+    U24(0x6094), GLYPH(0x2F8A3),
+    U24(0x614C), GLYPH(0x2F8A9),
+    U24(0x614E), GLYPH(0x2F8A8),
+    U24(0x618E), GLYPH(0xFA89),
+    U24(0x61F2), GLYPH(0xFA8B),
+    U24(0x61F6), GLYPH(0x2F8B1),
+    U24(0x654F), GLYPH(0x2F8C8),
+    U24(0x6674), GLYPH(0xFA91),
+    U24(0x6691), GLYPH(0x2F8CF),
+    U24(0x6717), GLYPH(0xFA92),
+    U24(0x671B), GLYPH(0x2F8D9),
+    U24(0x6885), GLYPH(0x2F8E2),
+    U24(0x6A02), GLYPH(0xF95C),
+    U24(0x6BBA), GLYPH(0xFA96),
+    U24(0x6D41), GLYPH(0xFA97),
+    U24(0x6D77), GLYPH(0x2F901),
+    U24(0x6ECB), GLYPH(0x2F90B),
+    U24(0x6F22), GLYPH(0xFA9A),
+    U24(0x701E), GLYPH(0x2F914),
+    U24(0x716E), GLYPH(0xFA9C),
+    U24(0x7235), GLYPH(0x2F921),
+    U24(0x732A), GLYPH(0xFAA0),
+    U24(0x7387), GLYPH(0xF9DB),
+    U24(0x7471), GLYPH(0x2F930),
+    U24(0x7570), GLYPH(0x2F938),
+    U24(0x76CA), GLYPH(0xFAA6),
+    U24(0x76F4), GLYPH(0x2F940),
+    U24(0x771F), GLYPH(0x2F947),
+    U24(0x774A), GLYPH(0x2F948),
+    U24(0x788C), GLYPH(0x2F94F),
+    U24(0x78CC), GLYPH(0x2F950),
+    U24(0x7956), GLYPH(0x2F953),
+    U24(0x798F), GLYPH(0x2F956),
+    U24(0x7A40), GLYPH(0x2F959),
+    U24(0x7BC0), GLYPH(0xFAAD),
+    U24(0x7DF4), GLYPH(0xFA57),
+    U24(0x8005), GLYPH(0xFAB2),
+    U24(0x8201), GLYPH(0x2F98B),
+    U24(0x8279), GLYPH(0xFA5E),
+    U24(0x82E5), GLYPH(0x2F998),
+    U24(0x8457), GLYPH(0x2F99F),
+    U24(0x865C), GLYPH(0x2F9B4),
+    U24(0x8779), GLYPH(0x2F9BB),
+    U24(0x8996), GLYPH(0xFAB8),
+    U24(0x8AAA), GLYPH(0xF9A1),
+    U24(0x8AED), GLYPH(0x2F9D0),
+    U24(0x8AF8), GLYPH(0xFABA),
+    U24(0x8AFE), GLYPH(0xFABD),
+    U24(0x8B01), GLYPH(0xFABC),
+    U24(0x8B39), GLYPH(0xFABF),
+    U24(0x8B8A), GLYPH(0x2F9D1),
+    U24(0x8D08), GLYPH(0xFAC1),
+    U24(0x8F38), GLYPH(0x2F9DF),
+    U24(0x9038), GLYPH(0xFA67),
+    U24(0x96E3), GLYPH(0xFAC7),
+    U24(0x9756), GLYPH(0xFAC8),
+    U24(0x97FF), GLYPH(0xFACA),
+    U24(0x980B), GLYPH(0x2F9FE),
+    U24(0x983B), GLYPH(0xFACC),
+    U24(0x9B12), GLYPH(0x2FA0A),
+    U24(0x9F9C), GLYPH(0xF908),
+    U24(0x22331), GLYPH(0x2F892),
+    U24(0x25AA7), GLYPH(0x2F95E),
+  // 0xFE02
+  U32(12), // numUVSMappings
+    U24(0x537F), GLYPH(0x2F833),
+    U24(0x5BE7), GLYPH(0x2F86F),
+    U24(0x618E), GLYPH(0x2F8AB),
+    U24(0x61F2), GLYPH(0x2F8B0),
+    U24(0x6717), GLYPH(0x2F8D8),
+    U24(0x6A02), GLYPH(0xF9BF),
+    U24(0x6BBA), GLYPH(0x2F8F5),
+    U24(0x6D41), GLYPH(0x2F902),
+    U24(0x7DF4), GLYPH(0xFAB0),
+    U24(0x8005), GLYPH(0x2F97A),
+    U24(0x980B), GLYPH(0x2F9FF),
+    U24(0x9F9C), GLYPH(0xFACE),
+};
+
+#undef U16
+#undef U24
+#undef U32
+#undef GLYPH
+
+static_assert(sizeof sCJKCompatSVSTable == 5065, "Table generator has a bug.");
diff --git a/gfx/thebes/gencjkcisvs.py b/gfx/thebes/gencjkcisvs.py
new file mode 100644
index 0000000000000000000000000000000000000000..401ebaa97a058e939de5774bd8c734a94d36b3f1
--- /dev/null
+++ b/gfx/thebes/gencjkcisvs.py
@@ -0,0 +1,77 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this file,
+# You can obtain one at http://mozilla.org/MPL/2.0/.
+
+import os.path
+import re
+import sys
+
+f = open(sys.argv[1] if len(sys.argv) > 1 else 'StandardizedVariants.txt')
+
+line = f.readline()
+m = re.compile('^# (StandardizedVariants(-\d+(\.\d+)*)?\.txt)').search(line)
+fileversion = m.group(1)
+vsdict = {}
+r = re.compile('^([0-9A-F]{4,6}) (FE0[0-9A-F]); CJK COMPATIBILITY IDEOGRAPH-([0-9A-F]{4,6});')
+while True:
+    line = f.readline()
+    if not line:
+        break
+    if not 'CJK COMPATIBILITY IDEOGRAPH-' in line:
+        continue
+
+    m = r.search(line)
+    unified = int(m.group(1), 16)
+    vs = int(m.group(2), 16)
+    compat = int(m.group(3), 16)
+
+    if not vs in vsdict:
+        vsdict[vs] = {}
+    vsdict[vs][unified] = compat
+
+f.close
+
+offsets = []
+length = 10 + 11 * len(vsdict)
+for (k, mappings) in sorted(vsdict.items()):
+    offsets.append(length)
+    length += 4 + 5 * len(mappings)
+
+f = open(sys.argv[2] if len(sys.argv) > 2 else 'CJKCompatSVS.cpp', 'wb')
+f.write("""// Generated by %s. Do not edit.
+
+#include <stdint.h>
+
+#define U16(v) (((v) >> 8) & 0xFF), ((v) & 0xFF)
+#define U24(v) (((v) >> 16) & 0xFF), (((v) >> 8) & 0xFF), ((v) & 0xFF)
+#define U32(v) (((v) >> 24) & 0xFF), (((v) >> 16) & 0xFF), (((v) >> 8) & 0xFF), ((v) & 0xFF)
+#define GLYPH(v) U16(v >= 0x2F800 ? (v) - (0x2F800 - 0xFB00) : (v))
+
+// Fallback mappings for CJK Compatibility Ideographs Standardized Variants
+// taken from %s.
+// Using OpenType format 14 cmap subtable structure to reuse the lookup code
+// for fonts. The glyphID field is used to store the corresponding codepoints
+// CJK Compatibility Ideographs. To fit codepoints into the 16-bit glyphID
+// field, CJK Compatibility Ideographs Supplement (U+2F800..U+2FA1F) will be
+// mapped to 0xFB00..0xFD1F.
+extern const uint8_t sCJKCompatSVSTable[] = {
+""" % (os.path.basename(sys.argv[0]), fileversion))
+f.write('  U16(14), // format\n')
+f.write('  U32(%d), // length\n' % length)
+f.write('  U32(%d), // numVarSelectorRecords\n' % len(vsdict))
+for i, k in enumerate(sorted(vsdict.keys())):
+    f.write('    U24(0x%04X), U32(0), U32(%d), // varSelectorRecord[%d]\n' % (k, offsets[i], i))
+for (k, mappings) in sorted(vsdict.items()):
+    f.write('  // 0x%04X\n' % k)
+    f.write('  U32(%d), // numUVSMappings\n' % len(mappings))
+    for (unified, compat) in sorted(mappings.items()):
+        f.write('    U24(0x%04X), GLYPH(0x%04X),\n' % (unified, compat))
+f.write("""};
+
+#undef U16
+#undef U24
+#undef U32
+#undef GLYPH
+
+static_assert(sizeof sCJKCompatSVSTable == %d, "Table generator has a bug.");
+""" % length)
diff --git a/gfx/thebes/gfxFT2FontBase.cpp b/gfx/thebes/gfxFT2FontBase.cpp
index a77b9ad9342dea6e78b44bed304d8f7f6ce639f0..0693b9aff38bcd0bf419c741e8d073bb147a6f83 100644
--- a/gfx/thebes/gfxFT2FontBase.cpp
+++ b/gfx/thebes/gfxFT2FontBase.cpp
@@ -8,6 +8,7 @@
 #include "harfbuzz/hb.h"
 #include "mozilla/Likely.h"
 #include "gfxFontConstants.h"
+#include "gfxFontUtils.h"
 
 using namespace mozilla::gfx;
 
@@ -155,6 +156,10 @@ gfxFT2FontBase::GetGlyph(uint32_t unicode, uint32_t variation_selector)
             gfxFT2LockedFace(this).GetUVSGlyph(unicode, variation_selector);
         if (id)
             return id;
+        id = gfxFontUtils::GetUVSFallback(unicode, variation_selector);
+        if (id) {
+            unicode = id;
+        }
     }
 
     return GetGlyph(unicode);
diff --git a/gfx/thebes/gfxFont.cpp b/gfx/thebes/gfxFont.cpp
index 1028459c5d7a0a72be9ccf30996085bd2c0933f9..033f1ea7f42ebed63c84d0155be59c55a9e38813 100644
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -4878,13 +4878,17 @@ gfxFontGroup::MakeHyphenTextRun(gfxContext *aCtx, uint32_t aAppUnitsPerDevUnit)
 }
 
 gfxFloat
-gfxFontGroup::GetHyphenWidth(gfxContext *aCtx, uint32_t aAppUnitsPerDevUnit)
+gfxFontGroup::GetHyphenWidth(gfxTextRun::PropertyProvider *aProvider)
 {
     if (mHyphenWidth < 0) {
-        nsAutoPtr<gfxTextRun> hyphRun(MakeHyphenTextRun(aCtx,
-                                                        aAppUnitsPerDevUnit));
-        mHyphenWidth = hyphRun.get() ?
-            hyphRun->GetAdvanceWidth(0, hyphRun->GetLength(), nullptr) : 0;
+        nsRefPtr<gfxContext> ctx(aProvider->GetContext());
+        if (ctx) {
+            nsAutoPtr<gfxTextRun>
+                hyphRun(MakeHyphenTextRun(ctx,
+                                          aProvider->GetAppUnitsPerDevUnit()));
+            mHyphenWidth = hyphRun.get() ?
+                hyphRun->GetAdvanceWidth(0, hyphRun->GetLength(), nullptr) : 0;
+        }
     }
     return mHyphenWidth;
 }
diff --git a/gfx/thebes/gfxFont.h b/gfx/thebes/gfxFont.h
index 5ae3a0faa562d89fc3f3ac3174d5b292ff8cc8b3..9c8a697ac30171f4536acad7e0b9576eb260bc67 100644
--- a/gfx/thebes/gfxFont.h
+++ b/gfx/thebes/gfxFont.h
@@ -2834,6 +2834,14 @@ public:
          */
         virtual void GetSpacing(uint32_t aStart, uint32_t aLength,
                                 Spacing *aSpacing) = 0;
+
+        // Returns a gfxContext that can be used to measure the hyphen glyph.
+        // Only called if the hyphen width is requested.
+        virtual already_AddRefed<gfxContext> GetContext() = 0;
+
+        // Return the appUnitsPerDevUnit value to be used when measuring.
+        // Only called if the hyphen width is requested.
+        virtual uint32_t GetAppUnitsPerDevUnit() = 0;
     };
 
     class ClusterIterator {
@@ -3433,7 +3441,7 @@ public:
      * needed to initialize the cached hyphen width; otherwise they are
      * ignored.
      */
-    gfxFloat GetHyphenWidth(gfxContext *aCtx, uint32_t aAppUnitsPerDevUnit);
+    gfxFloat GetHyphenWidth(gfxTextRun::PropertyProvider* aProvider);
 
     /**
      * Make a text run representing a single hyphen character.
diff --git a/gfx/thebes/gfxFontUtils.cpp b/gfx/thebes/gfxFontUtils.cpp
index f9bfbb0ee5c9371d02a15ce5411101aeec598d07..d45753c13189832b2cc0b81841823b7ca316cc95 100644
--- a/gfx/thebes/gfxFontUtils.cpp
+++ b/gfx/thebes/gfxFontUtils.cpp
@@ -692,9 +692,27 @@ gfxFontUtils::MapCharToGlyph(const uint8_t *aCmapBuf, uint32_t aBufLength,
         uint32_t varGID =
             gfxFontUtils::MapUVSToGlyphFormat14(aCmapBuf + uvsOffset,
                                                 aUnicode, aVarSelector);
+        if (!varGID) {
+            aUnicode = gfxFontUtils::GetUVSFallback(aUnicode, aVarSelector);
+            if (aUnicode) {
+                switch (format) {
+                case 4:
+                    if (aUnicode < UNICODE_BMP_LIMIT) {
+                        varGID = MapCharToGlyphFormat4(aCmapBuf + offset,
+                                                       char16_t(aUnicode));
+                    }
+                    break;
+                case 12:
+                    varGID = MapCharToGlyphFormat12(aCmapBuf + offset,
+                                                    aUnicode);
+                    break;
+                }
+            }
+        }
         if (varGID) {
             gid = varGID;
         }
+
         // else the variation sequence was not supported, use default mapping
         // of the character code alone
     }
diff --git a/gfx/thebes/gfxFontUtils.h b/gfx/thebes/gfxFontUtils.h
index 88c3d850c302ecf4bab4db3fdb75aa4b30bfe14b..7e3f24cf0885df7a43f3d9c0a23f70cd27d989ad 100644
--- a/gfx/thebes/gfxFontUtils.h
+++ b/gfx/thebes/gfxFontUtils.h
@@ -639,6 +639,8 @@ enum gfxUserFontType {
     GFX_USERFONT_WOFF = 3
 };
 
+extern const uint8_t sCJKCompatSVSTable[];
+
 class gfxFontUtils {
 
 public:
@@ -784,6 +786,15 @@ public:
     static uint16_t
     MapUVSToGlyphFormat14(const uint8_t *aBuf, uint32_t aCh, uint32_t aVS);
 
+    // sCJKCompatSVSTable is a 'cmap' format 14 subtable that maps
+    // <char + var-selector> pairs to the corresponding Unicode
+    // compatibility ideograph codepoints.
+    static MOZ_ALWAYS_INLINE uint32_t
+    GetUVSFallback(uint32_t aCh, uint32_t aVS) {
+        aCh = MapUVSToGlyphFormat14(sCJKCompatSVSTable, aCh, aVS);
+        return aCh >= 0xFB00 ? aCh + (0x2F800 - 0xFB00) : aCh;
+    }
+
     static uint32_t
     MapCharToGlyph(const uint8_t *aCmapBuf, uint32_t aBufLength,
                    uint32_t aUnicode, uint32_t aVarSelector = 0);
diff --git a/gfx/thebes/gfxHarfBuzzShaper.cpp b/gfx/thebes/gfxHarfBuzzShaper.cpp
index 24ea0ee8ff25f6e6a6821bafa8b64bbd126865b6..5c4b803490d9cbdda87b1333e0cf9bfe863a2b91 100644
--- a/gfx/thebes/gfxHarfBuzzShaper.cpp
+++ b/gfx/thebes/gfxHarfBuzzShaper.cpp
@@ -95,6 +95,24 @@ gfxHarfBuzzShaper::GetGlyph(hb_codepoint_t unicode,
                                                         unicode,
                                                         variation_selector);
             }
+            if (!gid) {
+                uint32_t compat =
+                    gfxFontUtils::GetUVSFallback(unicode, variation_selector);
+                if (compat) {
+                    switch (mCmapFormat) {
+                    case 4:
+                        if (compat < UNICODE_BMP_LIMIT) {
+                            gid = gfxFontUtils::MapCharToGlyphFormat4(data + mSubtableOffset,
+                                                                      compat);
+                        }
+                        break;
+                    case 12:
+                        gid = gfxFontUtils::MapCharToGlyphFormat12(data + mSubtableOffset,
+                                                                   compat);
+                        break;
+                    }
+                }
+            }
             // If the variation sequence was not supported, return zero here;
             // harfbuzz will call us again for the base character alone
             return gid;
diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp
index 5e602b2c2094e2bd7f2779b79b1cae4370e1efb3..3fb2e01595b5746d5fe7b6fd6db1e8b3b38869bf 100644
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -273,7 +273,7 @@ gfxPlatform::gfxPlatform()
 #ifdef XP_WIN
     // XXX - When 957560 is fixed, the pref can go away entirely
     mLayersUseDeprecated =
-        Preferences::GetBool("layers.use-deprecated-textures", false)
+        Preferences::GetBool("layers.use-deprecated-textures", true)
         && !gfxPrefs::LayersPreferOpenGL();
 #else
     mLayersUseDeprecated = false;
@@ -632,6 +632,18 @@ void SourceBufferDestroy(void *srcSurfUD)
   delete static_cast<SourceSurfaceUserData*>(srcSurfUD);
 }
 
+UserDataKey kThebesSurface;
+
+struct DependentSourceSurfaceUserData
+{
+  nsRefPtr<gfxASurface> mSurface;
+};
+
+void SourceSurfaceDestroyed(void *aData)
+{
+  delete static_cast<DependentSourceSurfaceUserData*>(aData);
+}
+
 #if MOZ_TREE_CAIRO
 void SourceSnapshotDetached(cairo_surface_t *nullSurf)
 {
@@ -654,6 +666,34 @@ gfxPlatform::ClearSourceSurfaceForSurface(gfxASurface *aSurface)
   aSurface->SetData(&kSourceSurface, nullptr, nullptr);
 }
 
+static TemporaryRef<DataSourceSurface>
+CopySurface(gfxASurface* aSurface)
+{
+  const nsIntSize size = aSurface->GetSize();
+  gfxImageFormat format = gfxPlatform::GetPlatform()->OptimalFormatForContent(aSurface->GetContentType());
+  RefPtr<DataSourceSurface> data =
+    Factory::CreateDataSourceSurface(ToIntSize(size),
+                                     ImageFormatToSurfaceFormat(format));
+  if (!data) {
+    return nullptr;
+  }
+
+  DataSourceSurface::MappedSurface map;
+  DebugOnly<bool> result = data->Map(DataSourceSurface::WRITE, &map);
+  MOZ_ASSERT(result, "Should always succeed mapping raw data surfaces!");
+
+  nsRefPtr<gfxImageSurface> image = new gfxImageSurface(map.mData, size, map.mStride, format);
+  nsRefPtr<gfxContext> ctx = new gfxContext(image);
+
+  ctx->SetSource(aSurface);
+  ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
+  ctx->Paint();
+
+  data->Unmap();
+
+  return data;
+}
+
 RefPtr<SourceSurface>
 gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget, gfxASurface *aSurface)
 {
@@ -722,18 +762,24 @@ gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget, gfxASurface *aSurfa
     }
   }
 
+  bool dependsOnData = false;
   if (!srcBuffer) {
     nsRefPtr<gfxImageSurface> imgSurface = aSurface->GetAsImageSurface();
 
-    bool isWin32ImageSurf = imgSurface &&
-                            aSurface->GetType() == gfxSurfaceType::Win32;
-
+    RefPtr<DataSourceSurface> copy;
     if (!imgSurface) {
-      imgSurface = new gfxImageSurface(aSurface->GetSize(), OptimalFormatForContent(aSurface->GetContentType()));
-      nsRefPtr<gfxContext> ctx = new gfxContext(imgSurface);
-      ctx->SetSource(aSurface);
-      ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
-      ctx->Paint();
+      copy = CopySurface(aSurface);
+
+      if (!copy) {
+        return nullptr;
+      }
+
+      DataSourceSurface::MappedSurface map;
+      DebugOnly<bool> result = copy->Map(DataSourceSurface::WRITE, &map);
+      MOZ_ASSERT(result, "Should always succeed mapping raw data surfaces!");
+
+      imgSurface = new gfxImageSurface(map.mData, aSurface->GetSize(), map.mStride,
+                                       SurfaceFormatToImageFormat(copy->GetFormat()));
     }
 
     gfxImageFormat cairoFormat = imgSurface->Format();
@@ -760,38 +806,56 @@ gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget, gfxASurface *aSurfa
                                                      imgSurface->Stride(),
                                                      format);
 
+    if (copy) {
+      copy->Unmap();
+    }
+
     if (!srcBuffer) {
-      // We need to check if our gfxASurface will keep the underlying data
-      // alive. This is true if gfxASurface actually -is- an ImageSurface or
-      // if it is a gfxWindowsSurface which supports GetAsImageSurface.
-      if (imgSurface != aSurface && !isWin32ImageSurf) {
-        return nullptr;
+      // If we had to make a copy, then just return that. Otherwise aSurface
+      // must have supported GetAsImageSurface, so we can just wrap that data.
+      if (copy) {
+        srcBuffer = copy;
+      } else {
+        srcBuffer = Factory::CreateWrappingDataSourceSurface(imgSurface->Data(),
+                                                             imgSurface->Stride(),
+                                                             size, format);
+        dependsOnData = true;
       }
+    }
 
-      srcBuffer = Factory::CreateWrappingDataSourceSurface(imgSurface->Data(),
-                                                           imgSurface->Stride(),
-                                                           size, format);
-
+    if (!srcBuffer) {
+      return nullptr;
     }
 
+    if (!dependsOnData) {
 #if MOZ_TREE_CAIRO
-    cairo_surface_t *nullSurf =
-	cairo_null_surface_create(CAIRO_CONTENT_COLOR_ALPHA);
-    cairo_surface_set_user_data(nullSurf,
-                                &kSourceSurface,
-                                imgSurface,
-                                nullptr);
-    cairo_surface_attach_snapshot(imgSurface->CairoSurface(), nullSurf, SourceSnapshotDetached);
-    cairo_surface_destroy(nullSurf);
+      cairo_surface_t *nullSurf =
+      cairo_null_surface_create(CAIRO_CONTENT_COLOR_ALPHA);
+      cairo_surface_set_user_data(nullSurf,
+                                  &kSourceSurface,
+                                  imgSurface,
+                                  nullptr);
+      cairo_surface_attach_snapshot(imgSurface->CairoSurface(), nullSurf, SourceSnapshotDetached);
+      cairo_surface_destroy(nullSurf);
 #else
-    cairo_surface_set_mime_data(imgSurface->CairoSurface(), "mozilla/magic", (const unsigned char*) "data", 4, SourceSnapshotDetached, imgSurface.get());
+      cairo_surface_set_mime_data(imgSurface->CairoSurface(), "mozilla/magic", (const unsigned char*) "data", 4, SourceSnapshotDetached, imgSurface.get());
 #endif
+    }
   }
 
-  SourceSurfaceUserData *srcSurfUD = new SourceSurfaceUserData;
-  srcSurfUD->mBackendType = aTarget->GetType();
-  srcSurfUD->mSrcSurface = srcBuffer;
-  aSurface->SetData(&kSourceSurface, srcSurfUD, SourceBufferDestroy);
+  if (dependsOnData) {
+    // If we wrapped the underlying data of aSurface, then we need to add user data
+    // to make sure aSurface stays alive until we are done with the data.
+    DependentSourceSurfaceUserData *srcSurfUD = new DependentSourceSurfaceUserData;
+    srcSurfUD->mSurface = aSurface;
+    srcBuffer->AddUserData(&kThebesSurface, srcSurfUD, SourceSurfaceDestroyed);
+  } else {
+    // Otherwise add user data to aSurface so we can cache lookups in the future.
+    SourceSurfaceUserData *srcSurfUD = new SourceSurfaceUserData;
+    srcSurfUD->mBackendType = aTarget->GetType();
+    srcSurfUD->mSrcSurface = srcBuffer;
+    aSurface->SetData(&kSourceSurface, srcSurfUD, SourceBufferDestroy);
+  }
 
   return srcBuffer;
 }
diff --git a/gfx/thebes/gfxPrefs.h b/gfx/thebes/gfxPrefs.h
index 0a429f90829280716155ac373c3b1de4db1163dc..9989428879f08ba989212f85a41fb01f0a78d5dc 100644
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -103,11 +103,29 @@ private:
   // We will keep these in an alphabetical order to make it easier to see if
   // a method accessing a pref already exists. Just add yours in the list.
 
+  // The apz prefs are explained in AsyncPanZoomController.cpp
+  DECL_GFX_PREF(Live, "apz.allow-checkerboarding",             APZAllowCheckerboarding, bool, true);
+  DECL_GFX_PREF(Live, "apz.asyncscroll.throttle",              APZAsyncScrollThrottleTime, int32_t, 100);
+  DECL_GFX_PREF(Live, "apz.asyncscroll.timeout",               APZAsyncScrollTimeout, int32_t, 300);
+  DECL_GFX_PREF(Live, "apz.axis_lock_mode",                    APZAxisLockMode, int32_t, 0);
+  DECL_GFX_PREF(Live, "apz.content_response_timeout",          APZContentResponseTimeout, int32_t, 300);
+  DECL_GFX_PREF(Live, "apz.cross_slide.enabled",               APZCrossSlideEnabled, bool, false);
+  DECL_GFX_PREF(Live, "apz.enlarge_displayport_when_clipped",  APZEnlargeDisplayPortWhenClipped, bool, false);
   DECL_GFX_PREF(Once, "apz.fling_friction",                    APZFlingFriction, float, 0.002f);
+  DECL_GFX_PREF(Live, "apz.fling_repaint_interval",            APZFlingRepaintInterval, int32_t, 75);
   DECL_GFX_PREF(Once, "apz.fling_stopped_threshold",           APZFlingStoppedThreshold, float, 0.01f);
-  DECL_GFX_PREF(Once, "apz.max_event_acceleration",            APZMaxEventAcceleration, float, 999.0f);
   DECL_GFX_PREF(Once, "apz.max_velocity_inches_per_ms",        APZMaxVelocity, float, -1.0f);
   DECL_GFX_PREF(Once, "apz.max_velocity_queue_size",           APZMaxVelocityQueueSize, uint32_t, 5);
+  DECL_GFX_PREF(Live, "apz.min_skate_speed",                   APZMinSkateSpeed, float, 1.0f);
+  DECL_GFX_PREF(Live, "apz.num_paint_duration_samples",        APZNumPaintDurationSamples, int32_t, 3);
+  DECL_GFX_PREF(Live, "apz.pan_repaint_interval",              APZPanRepaintInterval, int32_t, 250);
+  DECL_GFX_PREF(Live, "apz.touch_start_tolerance",             APZTouchStartTolerance, float, 1.0f/4.5f);
+  DECL_GFX_PREF(Live, "apz.use_paint_duration",                APZUsePaintDuration, bool, true);
+  DECL_GFX_PREF(Live, "apz.velocity_bias",                     APZVelocityBias, float, 1.0f);
+  DECL_GFX_PREF(Live, "apz.x_skate_size_multiplier",           APZXSkateSizeMultiplier, float, 1.5f);
+  DECL_GFX_PREF(Live, "apz.x_stationary_size_multiplier",      APZXStationarySizeMultiplier, float, 3.0f);
+  DECL_GFX_PREF(Live, "apz.y_skate_size_multiplier",           APZYSkateSizeMultiplier, float, 2.5f);
+  DECL_GFX_PREF(Live, "apz.y_stationary_size_multiplier",      APZYStationarySizeMultiplier, float, 3.5f);
 
   DECL_GFX_PREF(Once, "gfx.android.rgb16.force",               AndroidRGB16Force, bool, false);
 #if defined(ANDROID)
@@ -175,6 +193,7 @@ private:
   DECL_GFX_PREF(Once, "layers.progressive-paint",              UseProgressiveTilePainting, bool, false);
   DECL_GFX_PREF(Once, "layers.scroll-graph",                   LayersScrollGraph, bool, false);
 
+  DECL_GFX_PREF(Once, "layout.css.touch_action.enabled",       TouchActionEnabled, bool, false);
   DECL_GFX_PREF(Once, "layout.frame_rate",                     LayoutFrameRate, int32_t, -1);
 
   DECL_GFX_PREF(Live, "nglayout.debug.widget_update_flashing", WidgetUpdateFlashing, bool, false);
diff --git a/gfx/thebes/moz.build b/gfx/thebes/moz.build
index 9493632c45a316ffc91602e20a890aeb1a8acbb6..221e158c7717b1fba08e6179d093a8a420c9883b 100644
--- a/gfx/thebes/moz.build
+++ b/gfx/thebes/moz.build
@@ -226,6 +226,7 @@ SOURCES += [
 ]
 
 UNIFIED_SOURCES += [
+    'CJKCompatSVS.cpp',
     'gfx3DMatrix.cpp',
     'gfxAlphaRecovery.cpp',
     'gfxBaseSharedMemorySurface.cpp',
diff --git a/js/src/jit-test/tests/gc/bug-986864.js b/js/src/jit-test/tests/gc/bug-986864.js
new file mode 100644
index 0000000000000000000000000000000000000000..abb8de6b2b5a8f563b761b77043649f9ad36cd04
--- /dev/null
+++ b/js/src/jit-test/tests/gc/bug-986864.js
@@ -0,0 +1,8 @@
+// |jit-test| slow
+function x() {}
+for (var j = 0; j < 9999; ++j) {
+    (function() {
+        x += x.watch("endsWith", ArrayBuffer);
+        return 0 >> Function(x)
+    })()
+}
diff --git a/js/src/jit/Bailouts.cpp b/js/src/jit/Bailouts.cpp
index 487a7aa033ee486b902f95f0793450206ae12c13..f8ee8402bf098c23879caf32cdd693388b1b4c95 100644
--- a/js/src/jit/Bailouts.cpp
+++ b/js/src/jit/Bailouts.cpp
@@ -41,7 +41,9 @@ SnapshotIterator::SnapshotIterator(const IonBailoutIterator &iter)
               iter.snapshotOffset(),
               iter.ionScript()->snapshotsRVATableSize(),
               iter.ionScript()->snapshotsListSize()),
-    recover_(snapshot_),
+    recover_(snapshot_,
+             iter.ionScript()->recovers(),
+             iter.ionScript()->recoversSize()),
     fp_(iter.jsFrame()),
     machine_(iter.machineState()),
     ionScript_(iter.ionScript())
diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp
index ab80e0f682bdc973af57b525d6745c4e330c002c..ee8848d5c646eedb59f67185f4d51260748678a8 100644
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -6110,6 +6110,7 @@ CodeGenerator::generateAsmJS()
     // every step in CodeGenerator::link must be a nop, as asserted here:
     JS_ASSERT(snapshots_.listSize() == 0);
     JS_ASSERT(snapshots_.RVATableSize() == 0);
+    JS_ASSERT(recovers_.size() == 0);
     JS_ASSERT(bailouts_.empty());
     JS_ASSERT(graph.numConstants() == 0);
     JS_ASSERT(safepointIndices_.empty());
@@ -6233,7 +6234,7 @@ CodeGenerator::link(JSContext *cx, types::CompilerConstraintList *constraints)
       IonScript::New(cx, recompileInfo,
                      graph.totalSlotCount(), scriptFrameSize,
                      snapshots_.listSize(), snapshots_.RVATableSize(),
-                     bailouts_.length(), graph.numConstants(),
+                     recovers_.size(), bailouts_.length(), graph.numConstants(),
                      safepointIndices_.length(), osiIndices_.length(),
                      cacheList_.length(), runtimeData_.length(),
                      safepoints_.size(), callTargets.length(),
@@ -6343,6 +6344,9 @@ CodeGenerator::link(JSContext *cx, types::CompilerConstraintList *constraints)
         ionScript->copyOsiIndices(&osiIndices_[0], masm);
     if (snapshots_.listSize())
         ionScript->copySnapshots(&snapshots_);
+    MOZ_ASSERT_IF(snapshots_.listSize(), recovers_.size());
+    if (recovers_.size())
+        ionScript->copyRecovers(&recovers_);
     if (graph.numConstants())
         ionScript->copyConstants(graph.constantPool());
     if (callTargets.length() > 0)
diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp
index 7adc1721d61c6d3d6ceee72c8b64b6e7e19735d2..108dc1657ead83d87f5c38f5669cc701c876bbf5 100644
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -820,9 +820,11 @@ IonScript *
 IonScript::New(JSContext *cx, types::RecompileInfo recompileInfo,
                uint32_t frameSlots, uint32_t frameSize,
                size_t snapshotsListSize, size_t snapshotsRVATableSize,
-               size_t bailoutEntries, size_t constants, size_t safepointIndices,
-               size_t osiIndices, size_t cacheEntries, size_t runtimeSize,
-               size_t safepointsSize, size_t callTargetEntries, size_t backedgeEntries,
+               size_t recoversSize, size_t bailoutEntries,
+               size_t constants, size_t safepointIndices,
+               size_t osiIndices, size_t cacheEntries,
+               size_t runtimeSize,  size_t safepointsSize,
+               size_t callTargetEntries, size_t backedgeEntries,
                OptimizationLevel optimizationLevel)
 {
     static const int DataAlignment = sizeof(void *);
@@ -838,6 +840,7 @@ IonScript::New(JSContext *cx, types::RecompileInfo recompileInfo,
     // *somewhere* and if their total overflowed there would be no memory left
     // at all.
     size_t paddedSnapshotsSize = AlignBytes(snapshotsListSize + snapshotsRVATableSize, DataAlignment);
+    size_t paddedRecoversSize = AlignBytes(recoversSize, DataAlignment);
     size_t paddedBailoutSize = AlignBytes(bailoutEntries * sizeof(uint32_t), DataAlignment);
     size_t paddedConstantsSize = AlignBytes(constants * sizeof(Value), DataAlignment);
     size_t paddedSafepointIndicesSize = AlignBytes(safepointIndices * sizeof(SafepointIndex), DataAlignment);
@@ -848,6 +851,7 @@ IonScript::New(JSContext *cx, types::RecompileInfo recompileInfo,
     size_t paddedCallTargetSize = AlignBytes(callTargetEntries * sizeof(JSScript *), DataAlignment);
     size_t paddedBackedgeSize = AlignBytes(backedgeEntries * sizeof(PatchableBackedge), DataAlignment);
     size_t bytes = paddedSnapshotsSize +
+                   paddedRecoversSize +
                    paddedBailoutSize +
                    paddedConstantsSize +
                    paddedSafepointIndicesSize+
@@ -895,6 +899,10 @@ IonScript::New(JSContext *cx, types::RecompileInfo recompileInfo,
     script->snapshotsRVATableSize_ = snapshotsRVATableSize;
     offsetCursor += paddedSnapshotsSize;
 
+    script->recovers_ = offsetCursor;
+    script->recoversSize_ = recoversSize;
+    offsetCursor += paddedRecoversSize;
+
     script->constantTable_ = offsetCursor;
     script->constantEntries_ = constants;
     offsetCursor += paddedConstantsSize;
@@ -961,6 +969,13 @@ IonScript::copySnapshots(const SnapshotWriter *writer)
            writer->RVATableBuffer(), snapshotsRVATableSize_);
 }
 
+void
+IonScript::copyRecovers(const RecoverWriter *writer)
+{
+    MOZ_ASSERT(writer->size() == recoversSize_);
+    memcpy((uint8_t *)this + recovers_, writer->buffer(), recoversSize_);
+}
+
 void
 IonScript::copySafepoints(const SafepointWriter *writer)
 {
diff --git a/js/src/jit/IonCode.h b/js/src/jit/IonCode.h
index bbac4c43ed4eb07d38f8fe2335b0c011c6bbef16..bdf1e691b640b9b382d0f2c9fb33b11ec9eb57d4 100644
--- a/js/src/jit/IonCode.h
+++ b/js/src/jit/IonCode.h
@@ -143,6 +143,7 @@ class JitCode : public gc::BarrieredCell<JitCode>
 };
 
 class SnapshotWriter;
+class RecoverWriter;
 class SafepointWriter;
 class SafepointIndex;
 class OsiIndex;
@@ -250,6 +251,10 @@ struct IonScript
     uint32_t snapshotsListSize_;
     uint32_t snapshotsRVATableSize_;
 
+    // List of instructions needed to recover stack frames.
+    uint32_t recovers_;
+    uint32_t recoversSize_;
+
     // Constant table for constants stored in snapshots.
     uint32_t constantTable_;
     uint32_t constantEntries_;
@@ -351,9 +356,10 @@ struct IonScript
     static IonScript *New(JSContext *cx, types::RecompileInfo recompileInfo,
                           uint32_t frameLocals, uint32_t frameSize,
                           size_t snapshotsListSize, size_t snapshotsRVATableSize,
-                          size_t bailoutEntries, size_t constants,
-                          size_t safepointIndexEntries, size_t osiIndexEntries,
-                          size_t cacheEntries, size_t runtimeSize, size_t safepointsSize,
+                          size_t recoversSize, size_t bailoutEntries,
+                          size_t constants, size_t safepointIndexEntries,
+                          size_t osiIndexEntries, size_t cacheEntries,
+                          size_t runtimeSize, size_t safepointsSize,
                           size_t callTargetEntries, size_t backedgeEntries,
                           OptimizationLevel optimizationLevel);
     static void Trace(JSTracer *trc, IonScript *script);
@@ -472,6 +478,12 @@ struct IonScript
     size_t snapshotsRVATableSize() const {
         return snapshotsRVATableSize_;
     }
+    const uint8_t *recovers() const {
+        return reinterpret_cast<const uint8_t *>(this) + recovers_;
+    }
+    size_t recoversSize() const {
+        return recoversSize_;
+    }
     const uint8_t *safepoints() const {
         return reinterpret_cast<const uint8_t *>(this) + safepointsStart_;
     }
@@ -532,6 +544,7 @@ struct IonScript
     void destroyCaches();
     void unlinkFromRuntime(FreeOp *fop);
     void copySnapshots(const SnapshotWriter *writer);
+    void copyRecovers(const RecoverWriter *writer);
     void copyBailoutTable(const SnapshotOffset *table);
     void copyConstants(const Value *vp);
     void copySafepointIndices(const SafepointIndex *firstSafepointIndex, MacroAssembler &masm);
diff --git a/js/src/jit/IonFrameIterator.h b/js/src/jit/IonFrameIterator.h
index 9de60268d44f0c365b51fd593a687e2265b810a5..a924755296f40698dc0da41a930d99419f76069f 100644
--- a/js/src/jit/IonFrameIterator.h
+++ b/js/src/jit/IonFrameIterator.h
@@ -309,7 +309,7 @@ class SnapshotIterator
         // the call.
         if (moreFrames())
             return false;
-        return snapshot_.resumeAfter();
+        return recover_.resumeAfter();
     }
     inline BailoutKind bailoutKind() const {
         return snapshot_.bailoutKind();
diff --git a/js/src/jit/IonFrames.cpp b/js/src/jit/IonFrames.cpp
index b64ce84897c71784b9fb6f480973d4c11084e19d..d7d1ff70469bfd7c9554743a468f70d5c3f871e6 100644
--- a/js/src/jit/IonFrames.cpp
+++ b/js/src/jit/IonFrames.cpp
@@ -1295,7 +1295,9 @@ SnapshotIterator::SnapshotIterator(IonScript *ionScript, SnapshotOffset snapshot
               snapshotOffset,
               ionScript->snapshotsRVATableSize(),
               ionScript->snapshotsListSize()),
-    recover_(snapshot_),
+    recover_(snapshot_,
+             ionScript->recovers(),
+             ionScript->recoversSize()),
     fp_(fp),
     machine_(machine),
     ionScript_(ionScript)
@@ -1308,7 +1310,9 @@ SnapshotIterator::SnapshotIterator(const IonFrameIterator &iter)
               iter.osiIndex()->snapshotOffset(),
               iter.ionScript()->snapshotsRVATableSize(),
               iter.ionScript()->snapshotsListSize()),
-    recover_(snapshot_),
+    recover_(snapshot_,
+             iter.ionScript()->recovers(),
+             iter.ionScript()->recoversSize()),
     fp_(iter.jsFrame()),
     machine_(iter.machineState()),
     ionScript_(iter.ionScript())
@@ -1317,7 +1321,7 @@ SnapshotIterator::SnapshotIterator(const IonFrameIterator &iter)
 
 SnapshotIterator::SnapshotIterator()
   : snapshot_(nullptr, 0, 0, 0),
-    recover_(snapshot_),
+    recover_(snapshot_, nullptr, 0),
     fp_(nullptr),
     ionScript_(nullptr)
 {
diff --git a/js/src/jit/IonTypes.h b/js/src/jit/IonTypes.h
index 8b7e87ae1be3e793bdd4552229b8b8a98aea79ae..f5c8fd4daab8e7f67aba31e353c2cdb0f2e99e1f 100644
--- a/js/src/jit/IonTypes.h
+++ b/js/src/jit/IonTypes.h
@@ -14,6 +14,7 @@
 namespace js {
 namespace jit {
 
+typedef uint32_t RecoverOffset;
 typedef uint32_t SnapshotOffset;
 typedef uint32_t BailoutId;
 
@@ -25,6 +26,7 @@ static const uint32_t MAX_BUFFER_SIZE = (1 << 30) - 1;
 // Maximum number of scripted arg slots.
 static const uint32_t SNAPSHOT_MAX_NARGS = 127;
 
+static const SnapshotOffset INVALID_RECOVER_OFFSET = uint32_t(-1);
 static const SnapshotOffset INVALID_SNAPSHOT_OFFSET = uint32_t(-1);
 
 // Different kinds of bailouts. When extending this enum, make sure to check
diff --git a/js/src/jit/LIR.cpp b/js/src/jit/LIR.cpp
index f25e7d5a2a99ccdc744a2ce359695aceb9431cdb..3116a86faf934c5aad6fdd7fc70c75358fd2e0de 100644
--- a/js/src/jit/LIR.cpp
+++ b/js/src/jit/LIR.cpp
@@ -119,10 +119,28 @@ TotalOperandCount(MResumePoint *mir)
     return accum;
 }
 
-LSnapshot::LSnapshot(MResumePoint *mir, BailoutKind kind)
-  : numSlots_(TotalOperandCount(mir) * BOX_PIECES),
+LRecoverInfo::LRecoverInfo(MResumePoint *mir)
+  : mir_(mir),
+    recoverOffset_(INVALID_RECOVER_OFFSET)
+{ }
+
+LRecoverInfo *
+LRecoverInfo::New(MIRGenerator *gen, MResumePoint *mir)
+{
+    LRecoverInfo *recover = new(gen->alloc()) LRecoverInfo(mir);
+    if (!recover)
+        return nullptr;
+
+    IonSpew(IonSpew_Snapshots, "Generating LIR recover %p from MIR (%p)",
+            (void *)recover, (void *)mir);
+
+    return recover;
+}
+
+LSnapshot::LSnapshot(LRecoverInfo *recover, BailoutKind kind)
+  : numSlots_(TotalOperandCount(recover->mir()) * BOX_PIECES),
     slots_(nullptr),
-    mir_(mir),
+    recoverInfo_(recover),
     snapshotOffset_(INVALID_SNAPSHOT_OFFSET),
     bailoutId_(INVALID_BAILOUT_ID),
     bailoutKind_(kind)
@@ -136,14 +154,14 @@ LSnapshot::init(MIRGenerator *gen)
 }
 
 LSnapshot *
-LSnapshot::New(MIRGenerator *gen, MResumePoint *mir, BailoutKind kind)
+LSnapshot::New(MIRGenerator *gen, LRecoverInfo *recover, BailoutKind kind)
 {
-    LSnapshot *snapshot = new(gen->alloc()) LSnapshot(mir, kind);
-    if (!snapshot->init(gen))
+    LSnapshot *snapshot = new(gen->alloc()) LSnapshot(recover, kind);
+    if (!snapshot || !snapshot->init(gen))
         return nullptr;
 
-    IonSpew(IonSpew_Snapshots, "Generating LIR snapshot %p from MIR (%p)",
-            (void *)snapshot, (void *)mir);
+    IonSpew(IonSpew_Snapshots, "Generating LIR snapshot %p from recover (%p)",
+            (void *)snapshot, (void *)recover);
 
     return snapshot;
 }
diff --git a/js/src/jit/LIR.h b/js/src/jit/LIR.h
index 211e4fbefc5f46314f6f76f66cc783006ae1e075..20652f80d2dac449583601fec22521d601ef237c 100644
--- a/js/src/jit/LIR.h
+++ b/js/src/jit/LIR.h
@@ -876,6 +876,30 @@ class LCallInstructionHelper : public LInstructionHelper<Defs, Operands, Temps>
     }
 };
 
+class LRecoverInfo : public TempObject
+{
+    MResumePoint *mir_;
+
+    // Cached offset where this resume point is encoded.
+    RecoverOffset recoverOffset_;
+
+    LRecoverInfo(MResumePoint *mir);
+
+  public:
+    static LRecoverInfo *New(MIRGenerator *gen, MResumePoint *mir);
+
+    MResumePoint *mir() const {
+        return mir_;
+    }
+    RecoverOffset recoverOffset() const {
+        return recoverOffset_;
+    }
+    void setRecoverOffset(RecoverOffset offset) {
+        JS_ASSERT(recoverOffset_ == INVALID_RECOVER_OFFSET);
+        recoverOffset_ = offset;
+    }
+};
+
 // An LSnapshot is the reflection of an MResumePoint in LIR. Unlike MResumePoints,
 // they cannot be shared, as they are filled in by the register allocator in
 // order to capture the precise low-level stack state in between an
@@ -886,16 +910,16 @@ class LSnapshot : public TempObject
   private:
     uint32_t numSlots_;
     LAllocation *slots_;
-    MResumePoint *mir_;
+    LRecoverInfo *recoverInfo_;
     SnapshotOffset snapshotOffset_;
     BailoutId bailoutId_;
     BailoutKind bailoutKind_;
 
-    LSnapshot(MResumePoint *mir, BailoutKind kind);
+    LSnapshot(LRecoverInfo *recover, BailoutKind kind);
     bool init(MIRGenerator *gen);
 
   public:
-    static LSnapshot *New(MIRGenerator *gen, MResumePoint *snapshot, BailoutKind kind);
+    static LSnapshot *New(MIRGenerator *gen, LRecoverInfo *recover, BailoutKind kind);
 
     size_t numEntries() const {
         return numSlots_;
@@ -923,8 +947,11 @@ class LSnapshot : public TempObject
         JS_ASSERT(i < numSlots_);
         slots_[i] = alloc;
     }
+    LRecoverInfo *recoverInfo() const {
+        return recoverInfo_;
+    }
     MResumePoint *mir() const {
-        return mir_;
+        return recoverInfo()->mir();
     }
     SnapshotOffset snapshotOffset() const {
         return snapshotOffset_;
diff --git a/js/src/jit/Snapshots.cpp b/js/src/jit/Snapshots.cpp
index ac58faa9368188cc8a80308716f748a00b22e766..63ca5fb7d491c548b01c64e5aac35db5746f7305 100644
--- a/js/src/jit/Snapshots.cpp
+++ b/js/src/jit/Snapshots.cpp
@@ -465,19 +465,25 @@ SnapshotReader::SnapshotReader(const uint8_t *snapshots, uint32_t offset,
 }
 
 #define COMPUTE_SHIFT_AFTER_(name) (name ## _BITS + name ##_SHIFT)
-#define COMPUTE_MASK_(name) (((1 << name ## _BITS) - 1) << name ##_SHIFT)
+#define COMPUTE_MASK_(name) ((uint32_t(1 << name ## _BITS) - 1) << name ##_SHIFT)
 
+// Details of snapshot header packing.
 static const uint32_t SNAPSHOT_BAILOUTKIND_SHIFT = 0;
 static const uint32_t SNAPSHOT_BAILOUTKIND_BITS = 3;
 static const uint32_t SNAPSHOT_BAILOUTKIND_MASK = COMPUTE_MASK_(SNAPSHOT_BAILOUTKIND);
 
-static const uint32_t SNAPSHOT_RESUMEAFTER_SHIFT = COMPUTE_SHIFT_AFTER_(SNAPSHOT_BAILOUTKIND);
-static const uint32_t SNAPSHOT_RESUMEAFTER_BITS = 1;
-static const uint32_t SNAPSHOT_RESUMEAFTER_MASK = COMPUTE_MASK_(SNAPSHOT_RESUMEAFTER);
+static const uint32_t SNAPSHOT_ROFFSET_SHIFT = COMPUTE_SHIFT_AFTER_(SNAPSHOT_BAILOUTKIND);
+static const uint32_t SNAPSHOT_ROFFSET_BITS = 32 - SNAPSHOT_ROFFSET_SHIFT;
+static const uint32_t SNAPSHOT_ROFFSET_MASK = COMPUTE_MASK_(SNAPSHOT_ROFFSET);
 
-static const uint32_t SNAPSHOT_FRAMECOUNT_SHIFT = COMPUTE_SHIFT_AFTER_(SNAPSHOT_RESUMEAFTER);
-static const uint32_t SNAPSHOT_FRAMECOUNT_BITS = 32 - 4;
-static const uint32_t SNAPSHOT_FRAMECOUNT_MASK = COMPUTE_MASK_(SNAPSHOT_FRAMECOUNT);
+// Details of recover header packing.
+static const uint32_t RECOVER_RESUMEAFTER_SHIFT = 0;
+static const uint32_t RECOVER_RESUMEAFTER_BITS = 1;
+static const uint32_t RECOVER_RESUMEAFTER_MASK = COMPUTE_MASK_(RECOVER_RESUMEAFTER);
+
+static const uint32_t RECOVER_FRAMECOUNT_SHIFT = COMPUTE_SHIFT_AFTER_(RECOVER_RESUMEAFTER);
+static const uint32_t RECOVER_FRAMECOUNT_BITS = 32 - RECOVER_FRAMECOUNT_SHIFT;
+static const uint32_t RECOVER_FRAMECOUNT_MASK = COMPUTE_MASK_(RECOVER_FRAMECOUNT);
 
 #undef COMPUTE_MASK_
 #undef COMPUTE_SHIFT_AFTER_
@@ -486,24 +492,29 @@ void
 SnapshotReader::readSnapshotHeader()
 {
     uint32_t bits = reader_.readUnsigned();
-    frameCount_ = bits >> SNAPSHOT_FRAMECOUNT_SHIFT;
-    JS_ASSERT(frameCount_ > 0);
+
     bailoutKind_ = BailoutKind((bits & SNAPSHOT_BAILOUTKIND_MASK) >> SNAPSHOT_BAILOUTKIND_SHIFT);
-    resumeAfter_ = !!(bits & (1 << SNAPSHOT_RESUMEAFTER_SHIFT));
+    recoverOffset_ = (bits & SNAPSHOT_ROFFSET_MASK) >> SNAPSHOT_ROFFSET_SHIFT;
+
+    IonSpew(IonSpew_Snapshots, "Read snapshot header with bailout kind %u",
+            bailoutKind_);
 
 #ifdef TRACK_SNAPSHOTS
+    readTrackSnapshot();
+#endif
+}
+
+#ifdef TRACK_SNAPSHOTS
+void
+SnapshotReader::readTrackSnapshot()
+{
     pcOpcode_  = reader_.readUnsigned();
     mirOpcode_ = reader_.readUnsigned();
     mirId_     = reader_.readUnsigned();
     lirOpcode_ = reader_.readUnsigned();
     lirId_     = reader_.readUnsigned();
-#endif
-
-    IonSpew(IonSpew_Snapshots, "Read snapshot header with frameCount %u, bailout kind %u (ra: %d)",
-            frameCount_, bailoutKind_, resumeAfter_);
 }
 
-#ifdef TRACK_SNAPSHOTS
 void
 SnapshotReader::spewBailingFrom() const
 {
@@ -539,25 +550,40 @@ SnapshotWriter::init()
     return allocMap_.init(32);
 }
 
-RecoverReader::RecoverReader(SnapshotReader &snapshot)
-  : frameCount_(0),
+RecoverReader::RecoverReader(SnapshotReader &snapshot, const uint8_t *recovers, uint32_t size)
+  : reader_(nullptr, nullptr),
+    frameCount_(0),
     framesRead_(0),
     allocCount_(0)
 {
-    if (!snapshot.reader_.more())
+    if (!recovers)
         return;
-    frameCount_ = snapshot.frameCount_;
+    reader_ = CompactBufferReader(recovers + snapshot.recoverOffset(), recovers + size);
+    readRecoverHeader();
     readFrame(snapshot);
 }
 
+void
+RecoverReader::readRecoverHeader()
+{
+    uint32_t bits = reader_.readUnsigned();
+
+    frameCount_ = (bits & RECOVER_FRAMECOUNT_MASK) >> RECOVER_FRAMECOUNT_SHIFT;
+    resumeAfter_ = (bits & RECOVER_RESUMEAFTER_MASK) >> RECOVER_RESUMEAFTER_SHIFT;
+    JS_ASSERT(frameCount_);
+
+    IonSpew(IonSpew_Snapshots, "Read recover header with frameCount %u (ra: %d)",
+            frameCount_, resumeAfter_);
+}
+
 void
 RecoverReader::readFrame(SnapshotReader &snapshot)
 {
     JS_ASSERT(moreFrames());
     JS_ASSERT(snapshot.allocRead_ == allocCount_);
 
-    pcOffset_ = snapshot.reader_.readUnsigned();
-    allocCount_ = snapshot.reader_.readUnsigned();
+    pcOffset_ = reader_.readUnsigned();
+    allocCount_ = reader_.readUnsigned();
     IonSpew(IonSpew_Snapshots, "Read pc offset %u, nslots %u", pcOffset_, allocCount_);
 
     framesRead_++;
@@ -565,20 +591,19 @@ RecoverReader::readFrame(SnapshotReader &snapshot)
 }
 
 SnapshotOffset
-SnapshotWriter::startSnapshot(uint32_t frameCount, BailoutKind kind, bool resumeAfter)
+SnapshotWriter::startSnapshot(RecoverOffset recoverOffset, BailoutKind kind)
 {
     lastStart_ = writer_.length();
+    allocWritten_ = 0;
 
-    IonSpew(IonSpew_Snapshots, "starting snapshot with frameCount %u, bailout kind %u",
-            frameCount, kind);
-    JS_ASSERT(frameCount > 0);
-    JS_ASSERT(frameCount < (1 << SNAPSHOT_FRAMECOUNT_BITS));
-    JS_ASSERT(uint32_t(kind) < (1 << SNAPSHOT_BAILOUTKIND_BITS));
+    IonSpew(IonSpew_Snapshots, "starting snapshot with recover offset %u, bailout kind %u",
+            recoverOffset, kind);
 
-    uint32_t bits = (uint32_t(kind) << SNAPSHOT_BAILOUTKIND_SHIFT) |
-                    (frameCount << SNAPSHOT_FRAMECOUNT_SHIFT);
-    if (resumeAfter)
-        bits |= (1 << SNAPSHOT_RESUMEAFTER_SHIFT);
+    JS_ASSERT(uint32_t(kind) < (1 << SNAPSHOT_BAILOUTKIND_BITS));
+    JS_ASSERT(recoverOffset < (1 << SNAPSHOT_ROFFSET_BITS));
+    uint32_t bits =
+        (uint32_t(kind) << SNAPSHOT_BAILOUTKIND_SHIFT) |
+        (recoverOffset << SNAPSHOT_ROFFSET_SHIFT);
 
     writer_.writeUnsigned(bits);
     return lastStart_;
@@ -637,22 +662,29 @@ SnapshotWriter::endSnapshot()
             uint32_t(writer_.length() - lastStart_), lastStart_);
 }
 
-RecoverWriter::RecoverWriter(SnapshotWriter &snapshot)
-  : snapshot_(snapshot)
-{
-}
-
-SnapshotOffset
-RecoverWriter::startRecover(uint32_t frameCount, BailoutKind kind, bool resumeAfter)
+RecoverOffset
+RecoverWriter::startRecover(uint32_t frameCount, bool resumeAfter)
 {
     MOZ_ASSERT(frameCount);
     nframes_ = frameCount;
     framesWritten_ = 0;
-    return snapshot_.startSnapshot(frameCount, kind, resumeAfter);
+
+    IonSpew(IonSpew_Snapshots, "starting recover with frameCount %u",
+            frameCount);
+
+    MOZ_ASSERT(!(uint32_t(resumeAfter) &~ RECOVER_RESUMEAFTER_MASK));
+    MOZ_ASSERT(frameCount < uint32_t(1 << RECOVER_FRAMECOUNT_BITS));
+    uint32_t bits =
+        (uint32_t(resumeAfter) << RECOVER_RESUMEAFTER_SHIFT) |
+        (frameCount << RECOVER_FRAMECOUNT_SHIFT);
+
+    RecoverOffset recoverOffset = writer_.length();
+    writer_.writeUnsigned(bits);
+    return recoverOffset;
 }
 
 void
-RecoverWriter::startFrame(JSFunction *fun, JSScript *script,
+RecoverWriter::writeFrame(JSFunction *fun, JSScript *script,
                           jsbytecode *pc, uint32_t exprStack)
 {
     // Test if we honor the maximum of arguments at all times.
@@ -662,30 +694,20 @@ RecoverWriter::startFrame(JSFunction *fun, JSScript *script,
 
     uint32_t implicit = StartArgSlot(script);
     uint32_t formalArgs = CountArgSlots(script, fun);
-
-    nallocs_ = formalArgs + script->nfixed() + exprStack;
-    snapshot_.allocWritten_ = 0;
+    uint32_t nallocs = formalArgs + script->nfixed() + exprStack;
 
     IonSpew(IonSpew_Snapshots, "Starting frame; implicit %u, formals %u, fixed %u, exprs %u",
             implicit, formalArgs - implicit, script->nfixed(), exprStack);
 
     uint32_t pcoff = script->pcToOffset(pc);
-    IonSpew(IonSpew_Snapshots, "Writing pc offset %u, nslots %u", pcoff, nallocs_);
-    snapshot_.writer_.writeUnsigned(pcoff);
-    snapshot_.writer_.writeUnsigned(nallocs_);
-}
-
-void
-RecoverWriter::endFrame()
-{
-    MOZ_ASSERT(snapshot_.allocWritten_ == nallocs_);
-    nallocs_ = snapshot_.allocWritten_ = 0;
+    IonSpew(IonSpew_Snapshots, "Writing pc offset %u, nslots %u", pcoff, nallocs);
+    writer_.writeUnsigned(pcoff);
+    writer_.writeUnsigned(nallocs);
     framesWritten_++;
 }
 
 void
 RecoverWriter::endRecover()
 {
-    snapshot_.endSnapshot();
     JS_ASSERT(nframes_ == framesWritten_);
 }
diff --git a/js/src/jit/Snapshots.h b/js/src/jit/Snapshots.h
index c4d652f27ec5892a023e1e0876d1fed7fd41f6e7..39d46209f72f3e958aeb6e509437ed198cb385d9 100644
--- a/js/src/jit/Snapshots.h
+++ b/js/src/jit/Snapshots.h
@@ -327,17 +327,21 @@ class SnapshotWriter
   public:
     bool init();
 
-    SnapshotOffset startSnapshot(uint32_t frameCount, BailoutKind kind, bool resumeAfter);
+    SnapshotOffset startSnapshot(RecoverOffset recoverOffset, BailoutKind kind);
 #ifdef TRACK_SNAPSHOTS
     void trackSnapshot(uint32_t pcOpcode, uint32_t mirOpcode, uint32_t mirId,
                        uint32_t lirOpcode, uint32_t lirId);
 #endif
     bool add(const RValueAllocation &slot);
 
+    uint32_t allocWritten() const {
+        return allocWritten_;
+    }
     void endSnapshot();
 
     bool oom() const {
-        return writer_.oom() || writer_.length() >= MAX_BUFFER_SIZE;
+        return writer_.oom() || writer_.length() >= MAX_BUFFER_SIZE ||
+            allocWriter_.oom() || allocWriter_.length() >= MAX_BUFFER_SIZE;
     }
 
     size_t listSize() const {
@@ -357,22 +361,28 @@ class SnapshotWriter
 
 class RecoverWriter
 {
-    SnapshotWriter &snapshot_;
-
-    uint32_t nallocs_;
+    CompactBufferWriter writer_;
 
     uint32_t nframes_;
     uint32_t framesWritten_;
 
   public:
-    RecoverWriter(SnapshotWriter &snapshot);
-
-    SnapshotOffset startRecover(uint32_t frameCount, BailoutKind kind, bool resumeAfter);
+    SnapshotOffset startRecover(uint32_t frameCount, bool resumeAfter);
 
-    void startFrame(JSFunction *fun, JSScript *script, jsbytecode *pc, uint32_t exprStack);
-    void endFrame();
+    void writeFrame(JSFunction *fun, JSScript *script, jsbytecode *pc, uint32_t exprStack);
 
     void endRecover();
+
+    size_t size() const {
+        return writer_.length();
+    }
+    const uint8_t *buffer() const {
+        return writer_.buffer();
+    }
+
+    bool oom() const {
+        return writer_.oom() || writer_.length() >= MAX_BUFFER_SIZE;
+    }
 };
 
 class RecoverReader;
@@ -389,10 +399,9 @@ class SnapshotReader
     CompactBufferReader allocReader_;
     const uint8_t* allocTable_;
 
-    uint32_t frameCount_;
     BailoutKind bailoutKind_;
     uint32_t allocRead_;          // Number of slots that have been read.
-    bool resumeAfter_;
+    RecoverOffset recoverOffset_; // Offset of the recover instructions.
 
 #ifdef TRACK_SNAPSHOTS
   private:
@@ -403,6 +412,7 @@ class SnapshotReader
     uint32_t lirId_;
 
   public:
+    void readTrackSnapshot();
     void spewBailingFrom() const;
 #endif
 
@@ -419,23 +429,27 @@ class SnapshotReader
     BailoutKind bailoutKind() const {
         return bailoutKind_;
     }
-    bool resumeAfter() const {
-        return resumeAfter_;
+    RecoverOffset recoverOffset() const {
+        return recoverOffset_;
     }
 };
 
 class RecoverReader
 {
+    CompactBufferReader reader_;
+
     uint32_t frameCount_;
     uint32_t framesRead_;         // Number of frame headers that have been read.
     uint32_t pcOffset_;           // Offset from script->code.
     uint32_t allocCount_;         // Number of slots.
+    bool resumeAfter_;
 
   private:
+    void readRecoverHeader();
     void readFrame(SnapshotReader &snapshot);
 
   public:
-    RecoverReader(SnapshotReader &snapshot);
+    RecoverReader(SnapshotReader &snapshot, const uint8_t *recovers, uint32_t size);
 
     bool moreFrames() const {
         return framesRead_ < frameCount_;
@@ -450,6 +464,9 @@ class RecoverReader
     uint32_t pcOffset() const {
         return pcOffset_;
     }
+    bool resumeAfter() const {
+        return resumeAfter_;
+    }
 
     uint32_t allocations() const {
         return allocCount_;
diff --git a/js/src/jit/shared/CodeGenerator-shared.cpp b/js/src/jit/shared/CodeGenerator-shared.cpp
index c84dd1ab32bab281ffea115091734b6a4334e145..94cb728554df448142ffaa2bb79e94b5399baffb 100644
--- a/js/src/jit/shared/CodeGenerator-shared.cpp
+++ b/js/src/jit/shared/CodeGenerator-shared.cpp
@@ -42,7 +42,7 @@ CodeGeneratorShared::CodeGeneratorShared(MIRGenerator *gen, LIRGraph *graph, Mac
     graph(*graph),
     current(nullptr),
     snapshots_(),
-    recovers_(snapshots_),
+    recovers_(),
     deoptTable_(nullptr),
 #ifdef DEBUG
     pushedArgs_(0),
@@ -235,48 +235,25 @@ CodeGeneratorShared::encodeAllocations(LSnapshot *snapshot, MResumePoint *resume
 }
 
 bool
-CodeGeneratorShared::encode(LSnapshot *snapshot)
+CodeGeneratorShared::encode(LRecoverInfo *recover)
 {
-    if (snapshot->snapshotOffset() != INVALID_SNAPSHOT_OFFSET)
+    if (recover->recoverOffset() != INVALID_RECOVER_OFFSET)
         return true;
 
-    uint32_t frameCount = snapshot->mir()->frameCount();
-
-    IonSpew(IonSpew_Snapshots, "Encoding LSnapshot %p (frameCount %u)",
-            (void *)snapshot, frameCount);
+    uint32_t frameCount = recover->mir()->frameCount();
+    IonSpew(IonSpew_Snapshots, "Encoding LRecoverInfo %p (frameCount %u)",
+            (void *)recover, frameCount);
 
-    MResumePoint::Mode mode = snapshot->mir()->mode();
+    MResumePoint::Mode mode = recover->mir()->mode();
     JS_ASSERT(mode != MResumePoint::Outer);
     bool resumeAfter = (mode == MResumePoint::ResumeAfter);
 
-    SnapshotOffset offset = recovers_.startRecover(frameCount, snapshot->bailoutKind(),
-                                                   resumeAfter);
-
-#ifdef TRACK_SNAPSHOTS
-    uint32_t pcOpcode = 0;
-    uint32_t lirOpcode = 0;
-    uint32_t lirId = 0;
-    uint32_t mirOpcode = 0;
-    uint32_t mirId = 0;
-
-    if (LInstruction *ins = instruction()) {
-        lirOpcode = ins->op();
-        lirId = ins->id();
-        if (ins->mirRaw()) {
-            mirOpcode = ins->mirRaw()->op();
-            mirId = ins->mirRaw()->id();
-            if (ins->mirRaw()->trackedPc())
-                pcOpcode = *ins->mirRaw()->trackedPc();
-        }
-    }
-    snapshots_.trackSnapshot(pcOpcode, mirOpcode, mirId, lirOpcode, lirId);
-#endif
+    RecoverOffset offset = recovers_.startRecover(frameCount, resumeAfter);
 
-    FlattenedMResumePointIter mirOperandIter(snapshot->mir());
+    FlattenedMResumePointIter mirOperandIter(recover->mir());
     if (!mirOperandIter.init())
         return false;
 
-    uint32_t startIndex = 0;
     for (MResumePoint **it = mirOperandIter.begin(), **end = mirOperandIter.end();
          it != end;
          ++it)
@@ -287,20 +264,24 @@ CodeGeneratorShared::encode(LSnapshot *snapshot)
         JSScript *script = block->info().script();
         jsbytecode *pc = mir->pc();
         uint32_t exprStack = mir->stackDepth() - block->info().ninvoke();
-        recovers_.startFrame(fun, script, pc, exprStack);
+        recovers_.writeFrame(fun, script, pc, exprStack);
 
+#ifdef DEBUG
         // Ensure that all snapshot which are encoded can safely be used for
         // bailouts.
-        DebugOnly<jsbytecode *> bailPC = pc;
-        if (mir->mode() == MResumePoint::ResumeAfter)
-          bailPC = GetNextPc(pc);
-
-#ifdef DEBUG
         if (GetIonContext()->cx) {
             uint32_t stackDepth;
             bool reachablePC;
-            if (!ReconstructStackDepth(GetIonContext()->cx, script, bailPC, &stackDepth, &reachablePC))
+            jsbytecode *bailPC = pc;
+
+            if (mir->mode() == MResumePoint::ResumeAfter)
+                bailPC = GetNextPc(pc);
+
+            if (!ReconstructStackDepth(GetIonContext()->cx, script,
+                                       bailPC, &stackDepth, &reachablePC))
+            {
                 return false;
+            }
 
             if (reachablePC) {
                 if (JSOp(*bailPC) == JSOP_FUNCALL) {
@@ -326,15 +307,67 @@ CodeGeneratorShared::encode(LSnapshot *snapshot)
             }
         }
 #endif
+    }
+
+    recovers_.endRecover();
+    recover->setRecoverOffset(offset);
+    return !recovers_.oom();
+}
+
+bool
+CodeGeneratorShared::encode(LSnapshot *snapshot)
+{
+    if (snapshot->snapshotOffset() != INVALID_SNAPSHOT_OFFSET)
+        return true;
+
+    if (!encode(snapshot->recoverInfo()))
+        return false;
+
+    RecoverOffset recoverOffset = snapshot->recoverInfo()->recoverOffset();
+    MOZ_ASSERT(recoverOffset != INVALID_RECOVER_OFFSET);
+
+    IonSpew(IonSpew_Snapshots, "Encoding LSnapshot %p (LRecoverInfo %p)",
+            (void *)snapshot, (void*) snapshot->recoverInfo());
+
+    SnapshotOffset offset = snapshots_.startSnapshot(recoverOffset, snapshot->bailoutKind());
+
+#ifdef TRACK_SNAPSHOTS
+    uint32_t pcOpcode = 0;
+    uint32_t lirOpcode = 0;
+    uint32_t lirId = 0;
+    uint32_t mirOpcode = 0;
+    uint32_t mirId = 0;
+
+    if (LInstruction *ins = instruction()) {
+        lirOpcode = ins->op();
+        lirId = ins->id();
+        if (ins->mirRaw()) {
+            mirOpcode = ins->mirRaw()->op();
+            mirId = ins->mirRaw()->id();
+            if (ins->mirRaw()->trackedPc())
+                pcOpcode = *ins->mirRaw()->trackedPc();
+        }
+    }
+    snapshots_.trackSnapshot(pcOpcode, mirOpcode, mirId, lirOpcode, lirId);
+#endif
 
+    FlattenedMResumePointIter mirOperandIter(snapshot->recoverInfo()->mir());
+    if (!mirOperandIter.init())
+        return false;
+
+    uint32_t startIndex = 0;
+    for (MResumePoint **it = mirOperandIter.begin(), **end = mirOperandIter.end();
+         it != end;
+         ++it)
+    {
+        MResumePoint *mir = *it;
         if (!encodeAllocations(snapshot, mir, &startIndex))
             return false;
-        recovers_.endFrame();
     }
 
-    recovers_.endRecover();
+    MOZ_ASSERT(snapshots_.allocWritten() == snapshot->numSlots());
+    snapshots_.endSnapshot();
     snapshot->setSnapshotOffset(offset);
-
     return !snapshots_.oom();
 }
 
diff --git a/js/src/jit/shared/CodeGenerator-shared.h b/js/src/jit/shared/CodeGenerator-shared.h
index ea3807d9967e12ff6024d5ea087d761d08c8fce5..8c621a37aa99ad1f32a72147c9233b1a88ce1610 100644
--- a/js/src/jit/shared/CodeGenerator-shared.h
+++ b/js/src/jit/shared/CodeGenerator-shared.h
@@ -258,6 +258,7 @@ class CodeGeneratorShared : public LInstructionVisitor
   protected:
     // Encodes an LSnapshot into the compressed snapshot buffer, returning
     // false on failure.
+    bool encode(LRecoverInfo *recover);
     bool encode(LSnapshot *snapshot);
     bool encodeAllocations(LSnapshot *snapshot, MResumePoint *resumePoint, uint32_t *startIndex);
 
diff --git a/js/src/jit/shared/Lowering-shared.cpp b/js/src/jit/shared/Lowering-shared.cpp
index 62b376b3a79e24bfaeb413d9704b681ce0cccfa5..f23ecd9361095320789cdf2b43d8c35c231c98f9 100644
--- a/js/src/jit/shared/Lowering-shared.cpp
+++ b/js/src/jit/shared/Lowering-shared.cpp
@@ -56,11 +56,26 @@ LIRGeneratorShared::lowerTypedPhiInput(MPhi *phi, uint32_t inputPosition, LBlock
     lir->setOperand(inputPosition, LUse(operand->virtualRegister(), LUse::ANY));
 }
 
+LRecoverInfo *
+LIRGeneratorShared::getRecoverInfo(MResumePoint *rp)
+{
+    if (cachedRecoverInfo_ && cachedRecoverInfo_->mir() == rp)
+        return cachedRecoverInfo_;
+
+    LRecoverInfo *recoverInfo = LRecoverInfo::New(gen, rp);
+    cachedRecoverInfo_ = recoverInfo;
+    return recoverInfo;
+}
+
 #ifdef JS_NUNBOX32
 LSnapshot *
 LIRGeneratorShared::buildSnapshot(LInstruction *ins, MResumePoint *rp, BailoutKind kind)
 {
-    LSnapshot *snapshot = LSnapshot::New(gen, rp, kind);
+    LRecoverInfo *recover = getRecoverInfo(rp);
+    if (!recover)
+        return nullptr;
+
+    LSnapshot *snapshot = LSnapshot::New(gen, recover, kind);
     if (!snapshot)
         return nullptr;
 
@@ -114,7 +129,11 @@ LIRGeneratorShared::buildSnapshot(LInstruction *ins, MResumePoint *rp, BailoutKi
 LSnapshot *
 LIRGeneratorShared::buildSnapshot(LInstruction *ins, MResumePoint *rp, BailoutKind kind)
 {
-    LSnapshot *snapshot = LSnapshot::New(gen, rp, kind);
+    LRecoverInfo *recover = getRecoverInfo(rp);
+    if (!recover)
+        return nullptr;
+
+    LSnapshot *snapshot = LSnapshot::New(gen, recover, kind);
     if (!snapshot)
         return nullptr;
 
diff --git a/js/src/jit/shared/Lowering-shared.h b/js/src/jit/shared/Lowering-shared.h
index d26982909f64675b51aba29c2136c7aeccf4c4f6..26bd474c375fd089598d8875ea063a12ec59f450 100644
--- a/js/src/jit/shared/Lowering-shared.h
+++ b/js/src/jit/shared/Lowering-shared.h
@@ -31,6 +31,7 @@ class LIRGeneratorShared : public MInstructionVisitorWithDefaults
     LIRGraph &lirGraph_;
     LBlock *current;
     MResumePoint *lastResumePoint_;
+    LRecoverInfo *cachedRecoverInfo_;
     LOsiPoint *osiPoint_;
 
   public:
@@ -39,6 +40,7 @@ class LIRGeneratorShared : public MInstructionVisitorWithDefaults
         graph(graph),
         lirGraph_(lirGraph),
         lastResumePoint_(nullptr),
+        cachedRecoverInfo_(nullptr),
         osiPoint_(nullptr)
     { }
 
@@ -160,6 +162,7 @@ class LIRGeneratorShared : public MInstructionVisitorWithDefaults
         return tmp;
     }
 
+    LRecoverInfo *getRecoverInfo(MResumePoint *rp);
     LSnapshot *buildSnapshot(LInstruction *ins, MResumePoint *rp, BailoutKind kind);
     bool assignPostSnapshot(MInstruction *mir, LInstruction *ins);
 
diff --git a/js/src/js.msg b/js/src/js.msg
index 146b1136d68266ce7f8c384c4b8de4f3ed71f872..235aed7e4019792938757659d418438c212e9b1a 100644
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -436,3 +436,4 @@ MSG_DEF(JSMSG_TYPEDOBJECT_HANDLE_TO_UNSIZED, 381, 0, JSEXN_TYPEERR, "cannot crea
 MSG_DEF(JSMSG_SETPROTOTYPEOF_FAIL,      382, 1, JSEXN_TYPEERR, "[[SetPrototypeOf]] failed on {0}")
 MSG_DEF(JSMSG_INVALID_ARG_TYPE,         383, 3, JSEXN_TYPEERR, "Invalid type: {0} can't be a{1} {2}")
 MSG_DEF(JSMSG_TERMINATED,               384, 1, JSEXN_ERR, "Script terminated by timeout at:\n{0}")
+MSG_DEF(JSMSG_NO_SUCH_SELF_HOSTED_PROP, 385, 1, JSEXN_ERR, "No such property on self-hosted object: {0}")
diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp
index c6df08f8083e32d3075ad5d47e6e596183cf6694..38d9ca2eda4772fbef4b1f2f4bd298f3c2ad80b8 100644
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -1147,8 +1147,8 @@ JSFunction::createScriptForLazilyInterpretedFunction(JSContext *cx, HandleFuncti
         JS_ASSERT(lazy->source()->hasSourceData());
 
         // Parse and compile the script from source.
-        SourceDataCache::AutoSuppressPurge asp(cx);
-        const jschar *chars = lazy->source()->chars(cx, asp);
+        SourceDataCache::AutoHoldEntry holder;
+        const jschar *chars = lazy->source()->chars(cx, holder);
         if (!chars)
             return false;
 
diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp
index a7afc7e2a9629d839be0b6e75e90ed5abf5c7d6d..7eac22b62a6b8297f970298fafe649fd5e7c2e07 100644
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -1392,33 +1392,77 @@ JSScript::sourceData(JSContext *cx)
     return scriptSource()->substring(cx, sourceStart(), sourceEnd());
 }
 
-SourceDataCache::AutoSuppressPurge::AutoSuppressPurge(JSContext *cx)
- : cache_(cx->runtime()->sourceDataCache)
+SourceDataCache::AutoHoldEntry::AutoHoldEntry()
+  : cache_(nullptr), source_(nullptr), charsToFree_(nullptr)
 {
-    oldValue_ = cache_.numSuppressPurges_++;
 }
 
-SourceDataCache::AutoSuppressPurge::~AutoSuppressPurge()
+void
+SourceDataCache::AutoHoldEntry::holdEntry(SourceDataCache *cache, ScriptSource *source)
+{
+    // Initialise the holder for a specific cache and script source. This will
+    // hold on to the cached source chars in the event that the cache is purged.
+    JS_ASSERT(!cache_ && !source_ && !charsToFree_);
+    cache_ = cache;
+    source_ = source;
+}
+
+void
+SourceDataCache::AutoHoldEntry::deferDelete(const jschar *chars)
+{
+    // Take ownership of source chars now the cache is being purged. Remove our
+    // reference to the ScriptSource which might soon be destroyed.
+    JS_ASSERT(cache_ && source_ && !charsToFree_);
+    cache_ = nullptr;
+    source_ = nullptr;
+    charsToFree_ = chars;
+}
+
+SourceDataCache::AutoHoldEntry::~AutoHoldEntry()
+{
+    // The holder is going out of scope. If it has taken ownership of cached
+    // chars then delete them, otherwise unregister ourself with the cache.
+    if (charsToFree_) {
+        JS_ASSERT(!cache_ && !source_);
+        js_free(const_cast<jschar *>(charsToFree_));
+    } else if (cache_) {
+        JS_ASSERT(source_);
+        cache_->releaseEntry(*this);
+    }
+}
+
+void
+SourceDataCache::holdEntry(AutoHoldEntry &holder, ScriptSource *ss)
 {
-    cache_.numSuppressPurges_--;
-    JS_ASSERT(cache_.numSuppressPurges_ == oldValue_);
+    JS_ASSERT(!holder_);
+    holder.holdEntry(this, ss);
+    holder_ = &holder;
+}
+
+void
+SourceDataCache::releaseEntry(AutoHoldEntry &holder)
+{
+    JS_ASSERT(holder_ == &holder);
+    holder_ = nullptr;
 }
 
 const jschar *
-SourceDataCache::lookup(ScriptSource *ss, const AutoSuppressPurge &asp)
+SourceDataCache::lookup(ScriptSource *ss, AutoHoldEntry &holder)
 {
-    JS_ASSERT(this == &asp.cache());
+    JS_ASSERT(!holder_);
     if (!map_)
         return nullptr;
-    if (Map::Ptr p = map_->lookup(ss))
+    if (Map::Ptr p = map_->lookup(ss)) {
+        holdEntry(holder, ss);
         return p->value();
+    }
     return nullptr;
 }
 
 bool
-SourceDataCache::put(ScriptSource *ss, const jschar *str, const AutoSuppressPurge &asp)
+SourceDataCache::put(ScriptSource *ss, const jschar *str, AutoHoldEntry &holder)
 {
-    JS_ASSERT(this == &asp.cache());
+    JS_ASSERT(!holder_);
 
     if (!map_) {
         map_ = js_new<Map>();
@@ -1432,17 +1476,28 @@ SourceDataCache::put(ScriptSource *ss, const jschar *str, const AutoSuppressPurg
         }
     }
 
-    return map_->put(ss, str);
+    if (!map_->put(ss, str))
+        return false;
+
+    holdEntry(holder, ss);
+    return true;
 }
 
 void
 SourceDataCache::purge()
 {
-    if (!map_ || numSuppressPurges_ > 0)
+    if (!map_)
         return;
 
-    for (Map::Range r = map_->all(); !r.empty(); r.popFront())
-        js_delete(const_cast<jschar*>(r.front().value()));
+    for (Map::Range r = map_->all(); !r.empty(); r.popFront()) {
+        const jschar *chars = r.front().value();
+        if (holder_ && r.front().key() == holder_->source()) {
+            holder_->deferDelete(chars);
+            holder_ = nullptr;
+        } else {
+            js_free(const_cast<jschar*>(chars));
+        }
+    }
 
     js_delete(map_);
     map_ = nullptr;
@@ -1463,7 +1518,7 @@ SourceDataCache::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf)
 }
 
 const jschar *
-ScriptSource::chars(JSContext *cx, const SourceDataCache::AutoSuppressPurge &asp)
+ScriptSource::chars(JSContext *cx, SourceDataCache::AutoHoldEntry &holder)
 {
     if (const jschar *chars = getOffThreadCompressionChars(cx))
         return chars;
@@ -1471,9 +1526,9 @@ ScriptSource::chars(JSContext *cx, const SourceDataCache::AutoSuppressPurge &asp
 
 #ifdef USE_ZLIB
     if (compressed()) {
-        if (const jschar *decompressed = cx->runtime()->sourceDataCache.lookup(this, asp))
+        if (const jschar *decompressed = cx->runtime()->sourceDataCache.lookup(this, holder))
             return decompressed;
-      
+
         const size_t nbytes = sizeof(jschar) * (length_ + 1);
         jschar *decompressed = static_cast<jschar *>(js_malloc(nbytes));
         if (!decompressed)
@@ -1488,7 +1543,7 @@ ScriptSource::chars(JSContext *cx, const SourceDataCache::AutoSuppressPurge &asp
 
         decompressed[length_] = 0;
 
-        if (!cx->runtime()->sourceDataCache.put(this, decompressed, asp)) {
+        if (!cx->runtime()->sourceDataCache.put(this, decompressed, holder)) {
             JS_ReportOutOfMemory(cx);
             js_free(decompressed);
             return nullptr;
@@ -1504,8 +1559,8 @@ JSFlatString *
 ScriptSource::substring(JSContext *cx, uint32_t start, uint32_t stop)
 {
     JS_ASSERT(start <= stop);
-    SourceDataCache::AutoSuppressPurge asp(cx);
-    const jschar *chars = this->chars(cx, asp);
+    SourceDataCache::AutoHoldEntry holder;
+    const jschar *chars = this->chars(cx, holder);
     if (!chars)
         return nullptr;
     return js_NewStringCopyN<CanGC>(cx, chars + start, stop - start);
@@ -3784,13 +3839,13 @@ LazyScriptHashPolicy::match(JSScript *script, const Lookup &lookup)
         return false;
     }
 
-    SourceDataCache::AutoSuppressPurge asp(cx);
+    SourceDataCache::AutoHoldEntry holder;
 
-    const jschar *scriptChars = script->scriptSource()->chars(cx, asp);
+    const jschar *scriptChars = script->scriptSource()->chars(cx, holder);
     if (!scriptChars)
         return false;
 
-    const jschar *lazyChars = lazy->source()->chars(cx, asp);
+    const jschar *lazyChars = lazy->source()->chars(cx, holder);
     if (!lazyChars)
         return false;
 
diff --git a/js/src/jsscript.h b/js/src/jsscript.h
index f80bad30a6421969e62eb385b6614e3e400b6e98..3ca098cf6e844929115973e9e6ab0b3a8f9d55b8 100644
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -349,28 +349,41 @@ class SourceDataCache
                     const jschar *,
                     DefaultHasher<ScriptSource *>,
                     SystemAllocPolicy> Map;
-    Map *map_;
-    size_t numSuppressPurges_;
 
   public:
-    SourceDataCache() : map_(nullptr), numSuppressPurges_(0) {}
-
-    class AutoSuppressPurge
+    // Hold an entry in the source data cache and prevent it from being purged on GC.
+    class AutoHoldEntry
     {
-        SourceDataCache &cache_;
-        mozilla::DebugOnly<size_t> oldValue_;
+        SourceDataCache *cache_;
+        ScriptSource *source_;
+        const jschar *charsToFree_;
       public:
-        explicit AutoSuppressPurge(JSContext *cx);
-        ~AutoSuppressPurge();
-        SourceDataCache &cache() const { return cache_; }
+        explicit AutoHoldEntry();
+        ~AutoHoldEntry();
+      private:
+        void holdEntry(SourceDataCache *cache, ScriptSource *source);
+        void deferDelete(const jschar *chars);
+        ScriptSource *source() const { return source_; }
+        friend class SourceDataCache;
     };
 
-    const jschar *lookup(ScriptSource *ss, const AutoSuppressPurge &asp);
-    bool put(ScriptSource *ss, const jschar *chars, const AutoSuppressPurge &asp);
+  private:
+    Map *map_;
+    AutoHoldEntry *holder_;
+
+  public:
+    SourceDataCache() : map_(nullptr), holder_(nullptr) {}
+
+    const jschar *lookup(ScriptSource *ss, AutoHoldEntry &asp);
+    bool put(ScriptSource *ss, const jschar *chars, AutoHoldEntry &asp);
 
     void purge();
 
     size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf);
+
+  private:
+    void holdEntry(AutoHoldEntry &holder, ScriptSource *ss);
+    void releaseEntry(AutoHoldEntry &holder);
 };
 
 class ScriptSource
@@ -484,7 +497,7 @@ class ScriptSource
         JS_ASSERT(hasSourceData());
         return argumentsNotIncluded_;
     }
-    const jschar *chars(JSContext *cx, const SourceDataCache::AutoSuppressPurge &asp);
+    const jschar *chars(JSContext *cx, SourceDataCache::AutoHoldEntry &asp);
     JSFlatString *substring(JSContext *cx, uint32_t start, uint32_t stop);
     void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
                                 JS::ScriptSourceInfo *info) const;
diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp
index a8d0d4c7b541934d23a68c9a5c45156a99cae44c..41332fa668a46cf69824ecb0860eae78c8678da0 100644
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -1000,15 +1000,17 @@ GetUnclonedValue(JSContext *cx, JSObject *selfHostedObject, jsid id, Value *vp)
     if (JSID_IS_STRING(id) && !JSID_TO_STRING(id)->isPermanentAtom()) {
         JS_ASSERT(selfHostedObject->is<GlobalObject>());
         gc::AutoSuppressGC suppress(cx);
-        JS_ReportError(cx, "No such property on self hosted object");
-        return false;
+        RootedValue value(cx, IdToValue(id));
+        return js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_NO_SUCH_SELF_HOSTED_PROP,
+                                        JSDVG_IGNORE_STACK, value, NullPtr(), nullptr, nullptr);
     }
 
     Shape *shape = selfHostedObject->nativeLookupPure(id);
     if (!shape) {
         gc::AutoSuppressGC suppress(cx);
-        JS_ReportError(cx, "No such property on self hosted object");
-        return false;
+        RootedValue value(cx, IdToValue(id));
+        return js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_NO_SUCH_SELF_HOSTED_PROP,
+                                        JSDVG_IGNORE_STACK, value, NullPtr(), nullptr, nullptr);
     }
 
     JS_ASSERT(shape->hasSlot() && shape->hasDefaultGetter());
diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp
index 30320ffb6eb12677d71012c63d250f3dbe425f81..30d375cd9d78b4ea2749e2f4e31cdf29235dd36c 100644
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -1801,6 +1801,34 @@ nsLayoutUtils::ChangeMatrixBasis(const gfxPoint3D &aOrigin,
   return result; 
 }
 
+static void ConstrainToCoordValues(float& aStart, float& aSize)
+{
+  MOZ_ASSERT(aSize > 0);
+
+  // Here we try to make sure that the resulting nsRect will continue to cover
+  // as much of the area that was covered by the original gfx Rect as possible.
+
+  // We clamp the bounds of the rect to {nscoord_MIN,nscoord_MAX} since
+  // nsRect::X/Y() and nsRect::XMost/YMost() can't return values outwith this
+  // range:
+  float end = aStart + aSize;
+  aStart = clamped(aStart, float(nscoord_MIN), float(nscoord_MAX));
+  end = clamped(end, float(nscoord_MIN), float(nscoord_MAX));
+
+  aSize = end - aStart;
+
+  // We must also clamp aSize to {0,nscoord_MAX} since nsRect::Width/Height()
+  // can't return a value greater than nscoord_MAX. If aSize is greater than
+  // nscoord_MAX then we reduce it to nscoord_MAX while keeping the rect
+  // centered:
+  if (aSize > nscoord_MAX) {
+    float excess = aSize - nscoord_MAX;
+    excess /= 2;
+    aStart += excess;
+    aSize = nscoord_MAX;
+  }
+}
+
 /**
  * Given a gfxFloat, constrains its value to be between nscoord_MIN and nscoord_MAX.
  *
@@ -1840,6 +1868,22 @@ static void ConstrainToCoordValues(gfxFloat& aStart, gfxFloat& aSize)
   }
 }
 
+nsRect
+nsLayoutUtils::RoundGfxRectToAppRect(const Rect &aRect, float aFactor)
+{
+  /* Get a new Rect whose units are app units by scaling by the specified factor. */
+  Rect scaledRect = aRect;
+  scaledRect.ScaleRoundOut(aFactor);
+
+  /* We now need to constrain our results to the max and min values for coords. */
+  ConstrainToCoordValues(scaledRect.x, scaledRect.width);
+  ConstrainToCoordValues(scaledRect.y, scaledRect.height);
+
+  /* Now typecast everything back.  This is guaranteed to be safe. */
+  return nsRect(nscoord(scaledRect.X()), nscoord(scaledRect.Y()),
+                nscoord(scaledRect.Width()), nscoord(scaledRect.Height()));
+}
+
 nsRect
 nsLayoutUtils::RoundGfxRectToAppRect(const gfxRect &aRect, float aFactor)
 {
diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h
index 843aafdf706ef98bb2dd2a019e7d9c6dc1bcf25d..e16dbd12f398d1d345bea46a6b1e99d9c9f7f8ea 100644
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -117,6 +117,7 @@ class nsLayoutUtils
   typedef mozilla::ContainerLayerParameters ContainerLayerParameters;
   typedef mozilla::gfx::SourceSurface SourceSurface;
   typedef mozilla::gfx::DrawTarget DrawTarget;
+  typedef mozilla::gfx::Rect Rect;
 
 public:
   typedef mozilla::layers::FrameMetrics FrameMetrics;
@@ -790,6 +791,16 @@ public:
   static nsPoint MatrixTransformPoint(const nsPoint &aPoint,
                                       const gfx3DMatrix &aMatrix, float aFactor);
 
+  /**
+   * Given a graphics rectangle in graphics space, return a rectangle in
+   * app space that contains the graphics rectangle, rounding out as necessary.
+   *
+   * @param aRect The graphics rect to round outward.
+   * @param aFactor The number of app units per graphics unit.
+   * @return The smallest rectangle in app space that contains aRect.
+   */
+  static nsRect RoundGfxRectToAppRect(const Rect &aRect, float aFactor);
+
   /**
    * Given a graphics rectangle in graphics space, return a rectangle in
    * app space that contains the graphics rectangle, rounding out as necessary.
diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp
index e1cd9c15ba662ed1cf8b35f7744fb623ea855daf..f5ecd43769a5843e220c0c23902d46b2b07f2ac1 100644
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -4927,24 +4927,14 @@ PresShell::PaintRangePaintInfo(nsTArray<nsAutoPtr<RangePaintInfo> >* aItems,
   aScreenRect->width = pixelArea.width;
   aScreenRect->height = pixelArea.height;
 
-  nsRefPtr<gfxImageSurface> surface =
-    new gfxImageSurface(gfxIntSize(pixelArea.width, pixelArea.height),
-                        gfxImageFormat::ARGB32);
-  if (surface->CairoStatus()) {
+  RefPtr<DrawTarget> dt =
+   gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
+                                 IntSize(pixelArea.width, pixelArea.height),
+                                 SurfaceFormat::B8G8R8A8);
+  if (!dt) {
     return nullptr;
   }
 
-  // clear the image
-  gfxContext context(surface);
-  context.SetOperator(gfxContext::OPERATOR_CLEAR);
-  context.Rectangle(gfxRect(0, 0, pixelArea.width, pixelArea.height));
-  context.Fill();
-
-
-  RefPtr<DrawTarget> dt =
-    gfxPlatform::GetPlatform()->
-      CreateDrawTargetForSurface(surface, gfx::IntSize(pixelArea.width, pixelArea.height));
-
   nsRefPtr<gfxContext> ctx = new gfxContext(dt);
   nsRefPtr<nsRenderingContext> rc = new nsRenderingContext();
   rc->Init(deviceContext, ctx);
diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp
index 8cb725d5edd889e623bba5cd340365d3ff59f700..db056162c54de197e7c18784cdc3d469ae031485 100644
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -2839,6 +2839,14 @@ public:
     return mTextStyle->mHyphens;
   }
 
+  virtual already_AddRefed<gfxContext> GetContext() {
+    return GetReferenceRenderingContext(GetFrame(), nullptr);
+  }
+
+  virtual uint32_t GetAppUnitsPerDevUnit() {
+    return mTextRun->GetAppUnitsPerDevUnit();
+  }
+
   void GetSpacingInternal(uint32_t aStart, uint32_t aLength, Spacing* aSpacing,
                           bool aIgnoreTabs);
 
@@ -3194,16 +3202,9 @@ gfxFloat
 PropertyProvider::GetHyphenWidth()
 {
   if (mHyphenWidth < 0) {
-    mHyphenWidth = mLetterSpacing;
-    nsRefPtr<gfxContext> context(GetReferenceRenderingContext(GetFrame(),
-                                                              nullptr));
-    if (context) {
-      mHyphenWidth +=
-        GetFontGroup()->GetHyphenWidth(context,
-                                       mTextRun->GetAppUnitsPerDevUnit());
-    }
+    mHyphenWidth = GetFontGroup()->GetHyphenWidth(this);
   }
-  return mHyphenWidth;
+  return mHyphenWidth + mLetterSpacing;
 }
 
 void
diff --git a/layout/generic/test/test_bug470212.html b/layout/generic/test/test_bug470212.html
index 3ac6f3a3aab665bc13a07383b81d4efc0a69d8ae..42c600348117ed6eb80e550355574804344395a1 100644
--- a/layout/generic/test/test_bug470212.html
+++ b/layout/generic/test/test_bug470212.html
@@ -20,12 +20,12 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=470212
 function doShiftDrag(){
   setTimeout(function() {
     var wu = SpecialPowers.DOMWindowUtils;
-    wu.sendMouseEvent('mousedown',  0, 50, 0, 1, 4);
-    wu.sendMouseEvent('mousemove',  70, 70, 0, 0, 4);
-    wu.sendMouseEvent('mousemove',  80, 500, 0, 0, 4);
+    wu.sendMouseEvent('mousedown',  0, 0, 0, 1, 4);
+    wu.sendMouseEvent('mousemove',  60, 10, 0, 0, 4);
+    wu.sendMouseEvent('mousemove',  70, 250, 0, 0, 4);
 
     is(window.getSelection().rangeCount, 0, "rangeCount should be 0");
-    wu.sendMouseEvent('mouseup',  80, 500, 0, 0, 4);
+    wu.sendMouseEvent('mouseup',  70, 250, 0, 0, 4);
 
     SimpleTest.finish();
   }, 0);
diff --git a/layout/reftests/font-face/cjkcisvs-1-ref.html b/layout/reftests/font-face/cjkcisvs-1-ref.html
new file mode 100644
index 0000000000000000000000000000000000000000..49c384b153f77ea20524b59656799fcc206fcf8b
--- /dev/null
+++ b/layout/reftests/font-face/cjkcisvs-1-ref.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html><meta charset=utf-8>
+<title>Duplicate encoded quartet</title>
+<style>
+@font-face { font-family: DupEncQuartet; src: url('../fonts/gw1270797.ttf') format("truetype"); }
+th { width: 72pt }
+td { font-size: 72pt; font-family: DupEncQuartet, sans-serif; text-align: center }
+</style>
+<body>
+<table border>
+<caption>Duplicate encoded quartet</caption>
+<tr>
+<th>CJK Compatibility Ideographs</td>
+<th>Adobe-Japan1 IVS</td>
+<th>Hanyo-Denshi IVS</td>
+<th>CJK Compatibility Ideographs Standardized Variant</td>
+</tr>
+<tr>
+<td>&#xE000;</td>
+<td>&#xE000;</td>
+<td>&#xE000;</td>
+<td>&#xE000;</td>
+</tr>
diff --git a/layout/reftests/font-face/cjkcisvs-1.html b/layout/reftests/font-face/cjkcisvs-1.html
new file mode 100644
index 0000000000000000000000000000000000000000..e0d63e4917c4f380a589062a7e3bc4949a8e9e71
--- /dev/null
+++ b/layout/reftests/font-face/cjkcisvs-1.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html><meta charset=utf-8>
+<title>Duplicate encoded quartet</title>
+<style>
+@font-face { font-family: DupEncQuartet; src: url('../fonts/gw1270797.ttf') format("truetype"); }
+th { width: 72pt }
+td { font-size: 72pt; font-family: DupEncQuartet, sans-serif; text-align: center }
+</style>
+<body>
+<table border>
+<caption>Duplicate encoded quartet</caption>
+<tr>
+<th>CJK Compatibility Ideographs</td>
+<th>Adobe-Japan1 IVS</td>
+<th>Hanyo-Denshi IVS</td>
+<th>CJK Compatibility Ideographs Standardized Variant</td>
+</tr>
+<tr>
+<td>&#xFA19;</td>
+<td>&#x795E;&#xE0100;</td>
+<td>&#x795E;&#xE0103;</td>
+<td>&#x795E;&#xFE00;</td>
+</tr>
diff --git a/layout/reftests/font-face/reftest.list b/layout/reftests/font-face/reftest.list
index afd0a23a106c749e30aaa1f255cabd4b0024a016..46e47592f205495ba8bd70c9d3c9ffa32debe115 100644
--- a/layout/reftests/font-face/reftest.list
+++ b/layout/reftests/font-face/reftest.list
@@ -142,6 +142,7 @@ HTTP(..) == font-familiy-whitespace-1.html font-familiy-whitespace-1-ref.html
 HTTP(..) != font-familiy-whitespace-1.html font-familiy-whitespace-1-notref.html
 
 skip-if(B2G) HTTP(..) == ivs-1.html ivs-1-ref.html # bug 773482
+skip-if(B2G) HTTP(..) == cjkcisvs-1.html cjkcisvs-1-ref.html
 
 skip-if(B2G) HTTP(..) == missing-names.html missing-names-ref.html # bug 773482
 
diff --git a/layout/reftests/fonts/gw432047-license.txt b/layout/reftests/fonts/glyphwiki-license.txt
similarity index 97%
rename from layout/reftests/fonts/gw432047-license.txt
rename to layout/reftests/fonts/glyphwiki-license.txt
index b47419fbc5b8b0a7ee3fc642966e9cb6caf3ff35..927c138d6a7187da1f55d472dcc9123463a4f59d 100644
--- a/layout/reftests/fonts/gw432047-license.txt
+++ b/layout/reftests/fonts/glyphwiki-license.txt
@@ -1,3 +1,5 @@
+gw432047.ttf, gw1270797.ttf
+
 <http://en.glyphwiki.org/wiki/GlyphWiki:License>
 '''This document is a direct translation of the October 8th, 2008 revision of the Japanese original at ([[GlyphWiki:データ・記事のライセンス]]). This translation is provided as a service, and should not be taken to be a definitive statement. Please be aware that in case the Japanese original and the English version differ, the Japanese original takes precedence.'''
 
diff --git a/layout/reftests/fonts/gw1270797.ttf b/layout/reftests/fonts/gw1270797.ttf
new file mode 100644
index 0000000000000000000000000000000000000000..b3041fd9aea6396e58cf7ee2576a9c1513983d88
Binary files /dev/null and b/layout/reftests/fonts/gw1270797.ttf differ
diff --git a/layout/svg/nsSVGImageFrame.cpp b/layout/svg/nsSVGImageFrame.cpp
index bf0fa875891f4f3fafc0821bb71bf05e29654d2e..617e50fc45d9bef72bd419938b7256498cefcdd6 100644
--- a/layout/svg/nsSVGImageFrame.cpp
+++ b/layout/svg/nsSVGImageFrame.cpp
@@ -6,6 +6,7 @@
 // Keep in (case-insensitive) order:
 #include "gfxContext.h"
 #include "gfxPlatform.h"
+#include "mozilla/gfx/2D.h"
 #include "imgIContainer.h"
 #include "nsIImageLoadingContent.h"
 #include "nsLayoutUtils.h"
@@ -23,6 +24,7 @@
 
 using namespace mozilla;
 using namespace mozilla::dom;
+using namespace mozilla::gfx;
 
 class nsSVGImageFrame;
 
@@ -469,32 +471,11 @@ nsSVGImageFrame::ReflowSVG()
     return;
   }
 
-  gfxContext tmpCtx(gfxPlatform::GetPlatform()->ScreenReferenceSurface());
-
-  // We'd like to just pass the identity matrix to GeneratePath, but if
-  // this frame's user space size is _very_ large/small then the extents we
-  // obtain below might have overflowed or otherwise be broken. This would
-  // cause us to end up with a broken mRect and visual overflow rect and break
-  // painting of this frame. This is particularly noticeable if the transforms
-  // between us and our nsSVGOuterSVGFrame scale this frame to a reasonable
-  // size. To avoid this we sadly have to do extra work to account for the
-  // transforms between us and our nsSVGOuterSVGFrame, even though the
-  // overwhelming number of SVGs will never have this problem.
-  // XXX Will Azure eventually save us from having to do this?
-  gfxSize scaleFactors = GetCanvasTM(FOR_OUTERSVG_TM).ScaleFactors(true);
-  bool applyScaling = fabs(scaleFactors.width) >= 1e-6 &&
-                      fabs(scaleFactors.height) >= 1e-6;
-  Matrix scaling;
-  if (applyScaling) {
-    scaling.Scale(scaleFactors.width, scaleFactors.height);
-  }
-  tmpCtx.Save();
-  GeneratePath(&tmpCtx, scaling);
-  tmpCtx.Restore();
-  gfxRect extent = tmpCtx.GetUserPathExtent();
-  if (applyScaling) {
-    extent.Scale(1 / scaleFactors.width, 1 / scaleFactors.height);
-  }
+  float x, y, width, height;
+  SVGImageElement *element = static_cast<SVGImageElement*>(mContent);
+  element->GetAnimatedLengthValues(&x, &y, &width, &height, nullptr);
+
+  Rect extent(x, y, width, height);
 
   if (!extent.IsEmpty()) {
     mRect = nsLayoutUtils::RoundGfxRectToAppRect(extent, 
diff --git a/modules/libpref/src/init/all.js b/modules/libpref/src/init/all.js
index 20c7e280928fda216abd77b2225779a7f1d7b871..b37ad139d747c9e039ec022f2293fb274ad2326a 100644
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -4002,12 +4002,13 @@ pref("layers.offmainthreadcomposition.enabled", false);
 // -1 -> default (match layout.frame_rate or 60 FPS)
 // 0  -> full-tilt mode: Recomposite even if not transaction occured.
 pref("layers.offmainthreadcomposition.frame-rate", -1);
-
-#ifdef XP_WIN
+// Whether to use the deprecated texture architecture rather than the new one.
+#ifndef XP_WIN
 // Asynchonous video compositing using the ImageBridge IPDL protocol.
 // requires off-main-thread compositing.
 // Never works on Windows, so no point pref'ing it on.
-pref("layers.async-video.enabled", false);
+pref("layers.async-video.enabled",false);
+pref("layers.use-deprecated-textures", true);
 #endif
 
 #ifdef MOZ_X11
diff --git a/rdf/base/src/nsCompositeDataSource.cpp b/rdf/base/src/nsCompositeDataSource.cpp
index 50ee18f2b619fb66cfe0c305987aa9251d9413c6..76ad9f51001c08432cd96b692fa537ee8806ad03 100644
--- a/rdf/base/src/nsCompositeDataSource.cpp
+++ b/rdf/base/src/nsCompositeDataSource.cpp
@@ -42,7 +42,7 @@
 
 #include "nsEnumeratorUtils.h"
 
-#ifdef DEBUG
+#ifdef PR_LOGGING
 #include "prlog.h"
 #include "prprf.h"
 #include <stdio.h>
diff --git a/security/manager/ssl/tests/unit/test_ev_certs.js b/security/manager/ssl/tests/unit/test_ev_certs.js
index 682a3b675db309a8d0eaa91bc038d4f477d70f98..19fc0253b6603b729a92b351c7a88093b70be9c4 100644
--- a/security/manager/ssl/tests/unit/test_ev_certs.js
+++ b/security/manager/ssl/tests/unit/test_ev_certs.js
@@ -21,6 +21,8 @@ let certList = [
   // Test for successful EV validation
   'int-ev-valid',
   'ev-valid',
+  'ev-valid-anypolicy-int',
+  'int-ev-valid-anypolicy-int',
   'no-ocsp-url-cert', // a cert signed by the EV auth that has no OCSP url
                       // but that contains a valid CRLDP.
 
@@ -136,6 +138,17 @@ function add_tests_in_mode(useMozillaPKIX)
     ocspResponder.stop(run_next_test);
   });
 
+
+  add_test(function () {
+    clearOCSPCache();
+
+    let ocspResponder = start_ocsp_responder(
+                          isDebugBuild ? ["int-ev-valid-anypolicy-int", "ev-valid-anypolicy-int"]
+                                       : ["ev-valid-anypolicy-int"]);
+    check_ee_for_ev("ev-valid-anypolicy-int", isDebugBuild);
+    ocspResponder.stop(run_next_test);
+  });
+
   add_test(function() {
     clearOCSPCache();
     let ocspResponder = start_ocsp_responder(["non-ev-root"]);
@@ -205,6 +218,7 @@ function add_tests_in_mode(useMozillaPKIX)
                                      : SEC_ERROR_EXTENSION_NOT_FOUND));
   });
 
+
   // Test the EV continues to work with flags after successful EV verification
   add_test(function () {
     clearOCSPCache();
@@ -231,6 +245,7 @@ function add_tests_in_mode(useMozillaPKIX)
       failingOcspResponder.stop(run_next_test);
     });
   });
+
 }
 
 // bug 950240: add FLAG_MUST_BE_EV to CertVerifier::VerifyCert
@@ -258,3 +273,4 @@ function check_no_ocsp_requests(cert_name, expected_error) {
   do_check_eq(identityInfo.isExtendedValidation, false);
   ocspResponder.stop(run_next_test);
 }
+
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/cert8.db b/security/manager/ssl/tests/unit/test_ev_certs/cert8.db
index 226f654774ea5d474a98f53a0f9e0bdefaa2339e..79ee652ead3a79cbc5f95c612bd890fcb92620ff 100644
Binary files a/security/manager/ssl/tests/unit/test_ev_certs/cert8.db and b/security/manager/ssl/tests/unit/test_ev_certs/cert8.db differ
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/ev-valid-anypolicy-int.der b/security/manager/ssl/tests/unit/test_ev_certs/ev-valid-anypolicy-int.der
new file mode 100644
index 0000000000000000000000000000000000000000..629415c57588253011125db925e9a78bdb7bc12c
Binary files /dev/null and b/security/manager/ssl/tests/unit/test_ev_certs/ev-valid-anypolicy-int.der differ
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/ev-valid.der b/security/manager/ssl/tests/unit/test_ev_certs/ev-valid.der
index a046525fc039a8e7cdac3445b6a9b42513d3e699..2cfaa2758baf6c900f36e18d480cbdd758bb5bf5 100644
Binary files a/security/manager/ssl/tests/unit/test_ev_certs/ev-valid.der and b/security/manager/ssl/tests/unit/test_ev_certs/ev-valid.der differ
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/generate.py b/security/manager/ssl/tests/unit/test_ev_certs/generate.py
index f09b854c7ae882aea824da190c0908bc83677d1b..a790f6709c4ab3c61d34c19529f4ba17dbb4e633 100755
--- a/security/manager/ssl/tests/unit/test_ev_certs/generate.py
+++ b/security/manager/ssl/tests/unit/test_ev_certs/generate.py
@@ -40,6 +40,13 @@ mozilla_testing_ev_policy = ("certificatePolicies = @v3_ca_ev_cp\n\n" +
                                "1.3.6.1.4.1.13769.666.666.666.1.500.9.1\n\n" +
                              "CPS.1 = \"http://mytestdomain.local/cps\"")
 
+anypolicy_policy = ("certificatePolicies = @v3_ca_ev_cp\n\n" +
+                    "[ v3_ca_ev_cp ]\n" +
+                    "policyIdentifier = " +
+                    "2.5.29.32.0\n\n" +
+                    "CPS.1 = \"http://mytestdomain.local/cps\"")
+
+
 def import_untrusted_cert(certfile, nickname):
     os.system("certutil -A -d . -n " + nickname + " -i " + certfile +
               " -t ',,'")
@@ -108,6 +115,30 @@ def generate_certs():
                                       int_key, int_cert);
     import_untrusted_cert(no_ocsp_cert, 'no-ocsp-url-cert');
 
+    # add an ev cert whose intermediate has a anypolicy oid
+    prefix = "ev-valid-anypolicy-int"
+    ee_ext_text = (EE_basic_constraints + EE_full_ku + Server_eku +
+                   authority_key_ident + aia_prefix + prefix + aia_suffix +
+                   endentity_crl + mozilla_testing_ev_policy)
+    int_ext_text = (CA_basic_constraints + EE_full_ku + CA_eku +
+                    authority_key_ident + subject_key_ident +
+                    aia_prefix + "int-" + prefix + aia_suffix +
+                    intermediate_crl + anypolicy_policy)
+
+    [int_key, int_cert, ee_key, ee_cert] = CertUtils.generate_int_and_ee(db,
+                                             srcdir,
+                                             ca_key,
+                                             ca_cert,
+                                             prefix,
+                                             int_ext_text,
+                                             ee_ext_text,
+                                             key_type)
+    pk12file = CertUtils.generate_pkcs12(db, srcdir, int_cert, int_key,
+                                         "int-" + prefix)
+    import_cert_and_pkcs12(int_cert, pk12file, "int-" + prefix, ",,")
+    import_untrusted_cert(ee_cert, prefix)
+
+
     [bad_ca_key, bad_ca_cert] = CertUtils.generate_cert_generic( db,
                                       srcdir,
                                       1,
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/int-ev-valid-anypolicy-int.der b/security/manager/ssl/tests/unit/test_ev_certs/int-ev-valid-anypolicy-int.der
new file mode 100644
index 0000000000000000000000000000000000000000..0839693dd55e497cd9d87a76da518dd7a74da934
Binary files /dev/null and b/security/manager/ssl/tests/unit/test_ev_certs/int-ev-valid-anypolicy-int.der differ
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/int-ev-valid.der b/security/manager/ssl/tests/unit/test_ev_certs/int-ev-valid.der
index c7c60fa406cdb5ecf223494e3b8b746320a723ff..60eddd88f5b64026c26029f835b56571b3f7aea8 100644
Binary files a/security/manager/ssl/tests/unit/test_ev_certs/int-ev-valid.der and b/security/manager/ssl/tests/unit/test_ev_certs/int-ev-valid.der differ
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/int-ev-valid.p12 b/security/manager/ssl/tests/unit/test_ev_certs/int-ev-valid.p12
index e0d5e73f8f140c32abb9e8e7b5604af6831d93e6..9a50320d4c08382248f37e15f2ddb18b5cbe1692 100644
Binary files a/security/manager/ssl/tests/unit/test_ev_certs/int-ev-valid.p12 and b/security/manager/ssl/tests/unit/test_ev_certs/int-ev-valid.p12 differ
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/int-non-ev-root.der b/security/manager/ssl/tests/unit/test_ev_certs/int-non-ev-root.der
index ad245b2e045348bbe2ca6a67db245116f30468ed..cc848f221e169cb3d22c7ad9b089419bafa6c27d 100644
Binary files a/security/manager/ssl/tests/unit/test_ev_certs/int-non-ev-root.der and b/security/manager/ssl/tests/unit/test_ev_certs/int-non-ev-root.der differ
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/int-non-ev-root.p12 b/security/manager/ssl/tests/unit/test_ev_certs/int-non-ev-root.p12
index 7377f689a24b4f2036629e96b59c03639370a49a..4170d2bdebcf38363c14641dd7bdb17457d14b22 100644
Binary files a/security/manager/ssl/tests/unit/test_ev_certs/int-non-ev-root.p12 and b/security/manager/ssl/tests/unit/test_ev_certs/int-non-ev-root.p12 differ
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/key3.db b/security/manager/ssl/tests/unit/test_ev_certs/key3.db
index 974fc126ac56159cf9489521f1bad44cc3884a14..faafb6bec8d2d7726db65f7154d418e194a2eb99 100644
Binary files a/security/manager/ssl/tests/unit/test_ev_certs/key3.db and b/security/manager/ssl/tests/unit/test_ev_certs/key3.db differ
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/no-ocsp-url-cert.der b/security/manager/ssl/tests/unit/test_ev_certs/no-ocsp-url-cert.der
index eb6b1ccb84ccc60ed2555cc9a179f685b9179478..b0e5832fba34ab62a9cc2574f69710ab194d63f7 100644
Binary files a/security/manager/ssl/tests/unit/test_ev_certs/no-ocsp-url-cert.der and b/security/manager/ssl/tests/unit/test_ev_certs/no-ocsp-url-cert.der differ
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/non-ev-root.der b/security/manager/ssl/tests/unit/test_ev_certs/non-ev-root.der
index 6907db91afdde1093315cfb77f0bd7a17092c2df..144171257c96107f474ef611a6d925d3ebf4a94f 100644
Binary files a/security/manager/ssl/tests/unit/test_ev_certs/non-ev-root.der and b/security/manager/ssl/tests/unit/test_ev_certs/non-ev-root.der differ
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/non-evroot-ca.der b/security/manager/ssl/tests/unit/test_ev_certs/non-evroot-ca.der
index 32257c7f656f14683ee1a887ccd76587cf8cec25..6fa04d6b0177c9f7bf97ea8da93460d21e3d0658 100644
Binary files a/security/manager/ssl/tests/unit/test_ev_certs/non-evroot-ca.der and b/security/manager/ssl/tests/unit/test_ev_certs/non-evroot-ca.der differ
diff --git a/security/manager/ssl/tests/unit/test_ev_certs/non-evroot-ca.p12 b/security/manager/ssl/tests/unit/test_ev_certs/non-evroot-ca.p12
index 09920a30db25e82a7306833d511c06e8000a4170..c706797c5cc16d96ab5a2ce7852089ecbe1b5b29 100644
Binary files a/security/manager/ssl/tests/unit/test_ev_certs/non-evroot-ca.p12 and b/security/manager/ssl/tests/unit/test_ev_certs/non-evroot-ca.p12 differ
diff --git a/security/pkix/include/pkix/pkix.h b/security/pkix/include/pkix/pkix.h
index 7d23ccefb0cc7b44189ada514e0827296b288498..dc59c0cff245e83c9fc63c8c023edab097333027 100644
--- a/security/pkix/include/pkix/pkix.h
+++ b/security/pkix/include/pkix/pkix.h
@@ -34,11 +34,13 @@ namespace mozilla { namespace pkix {
 //
 //    * user-initial-policy-set = { requiredPolicy }.
 //    * initial-explicit-policy = true
-//    * initial-any-policy-inhibit = true
+//    * initial-any-policy-inhibit = false
 //
+// We allow intermediate cerificates to use this extension but since
+// we do not process the inhibit anyPolicy extesion we will fail if this
+// extension is present. TODO(bug 989051)
 // Because we force explicit policy and because we prohibit policy mapping, we
-// do not bother processing the policy mapping, policy constraint, or inhibit
-// anyPolicy extensions.
+// do not bother processing the policy mapping, or policy constraint.
 //
 // ----------------------------------------------------------------------------
 // ERROR RANKING
diff --git a/security/pkix/lib/pkixbuild.cpp b/security/pkix/lib/pkixbuild.cpp
index 3aa0ca4ba00f12b40d40f9c21cc240c94b3db289..119e595ef662c8ab04aa959c25663f6732726cb8 100644
--- a/security/pkix/lib/pkixbuild.cpp
+++ b/security/pkix/lib/pkixbuild.cpp
@@ -68,6 +68,7 @@ BackCert::Init()
         case 32: out = &encodedCertificatePolicies; break;
         case 35: out = &dummyEncodedAuthorityKeyIdentifier; break; // bug 965136
         case 37: out = &encodedExtendedKeyUsage; break;
+        case 54: out = &encodedInhibitAnyPolicy; break; // Bug 989051
       }
     } else if (ext->id.len == 9 &&
                ext->id.data[0] == 0x2b && ext->id.data[1] == 0x06 &&
diff --git a/security/pkix/lib/pkixcheck.cpp b/security/pkix/lib/pkixcheck.cpp
index ca4f3deb542d667a5d85f01d014df5fa567dc0c4..b10330005268151f8a798e8ad38ca74f7e52d782 100644
--- a/security/pkix/lib/pkixcheck.cpp
+++ b/security/pkix/lib/pkixcheck.cpp
@@ -118,6 +118,14 @@ CheckCertificatePolicies(BackCert& cert, EndEntityOrCA endEntityOrCA,
     return FatalError;
   }
 
+  // Bug 989051. Until we handle inhibitAnyPolicy we will fail close when
+  // inhibitAnyPolicy extension is present and we need to evaluate certificate
+  // policies.
+  if (cert.encodedInhibitAnyPolicy) {
+    PR_SetError(SEC_ERROR_POLICY_VALIDATION_FAILED, 0);
+    return RecoverableError;
+  }
+
   // The root CA certificate may omit the policies that it has been
   // trusted for, so we cannot require the policies to be present in those
   // certificates. Instead, the determination of which roots are trusted for
@@ -143,6 +151,11 @@ CheckCertificatePolicies(BackCert& cert, EndEntityOrCA endEntityOrCA,
     if ((*policyInfos)->oid == requiredPolicy) {
       return Success;
     }
+    // Intermediate certs are allowed to have the anyPolicy OID
+    if (endEntityOrCA == MustBeCA &&
+        (*policyInfos)->oid == SEC_OID_X509_ANY_POLICY) {
+      return Success;
+    }
   }
 
   PR_SetError(SEC_ERROR_POLICY_VALIDATION_FAILED, 0);
diff --git a/security/pkix/lib/pkixutil.h b/security/pkix/lib/pkixutil.h
index a9b7edfd4d23ab1a35abb4b34ab062afaff7aad9..d261ba4efa549e1d1a0ef162902004e38057b8fc 100644
--- a/security/pkix/lib/pkixutil.h
+++ b/security/pkix/lib/pkixutil.h
@@ -94,6 +94,7 @@ public:
     , encodedExtendedKeyUsage(nullptr)
     , encodedKeyUsage(nullptr)
     , encodedNameConstraints(nullptr)
+    , encodedInhibitAnyPolicy(nullptr)
     , childCert(childCert)
     , nssCert(nssCert)
     , constrainedNames(nullptr)
@@ -108,6 +109,7 @@ public:
   const SECItem* encodedExtendedKeyUsage;
   const SECItem* encodedKeyUsage;
   const SECItem* encodedNameConstraints;
+  const SECItem* encodedInhibitAnyPolicy;
 
   BackCert* const childCert;
 
diff --git a/testing/mach_commands.py b/testing/mach_commands.py
index 48144e278c43f355aa9e773f5626d37c28a55f72..2f3f04644a0ade988fae740858696c5923a0b369 100644
--- a/testing/mach_commands.py
+++ b/testing/mach_commands.py
@@ -62,6 +62,11 @@ TEST_SUITES = {
         'mach_command': 'jetpack-test',
         'kwargs': {},
     },
+    'jittest': {
+        'aliases': ('Jit', 'jit'),
+        'mach_command': 'jittest',
+        'kwargs': {'test_file': None},
+    },
     'mochitest-a11y': {
         'mach_command': 'mochitest-a11y',
         'kwargs': {'test_file': None},
@@ -204,3 +209,24 @@ class MachCommands(MachCommandBase):
             result = False
 
         return 0 if result else 1
+
+@CommandProvider
+class JittestCommand(MachCommandBase):
+    @Command('jittest', category='testing', description='Run jit-test tests.')
+    @CommandArgument('--valgrind', action='store_true', help='Run jit-test suite with valgrind flag')
+
+    def run_jittest(self, **params):
+        import subprocess
+        import sys
+
+        if sys.platform.startswith('win'):
+            js = os.path.join(self.bindir, 'js.exe')
+        else:
+            js = os.path.join(self.bindir, 'js')
+        cmd = [os.path.join(self.topsrcdir, 'js', 'src', 'jit-test', 'jit_test.py'),
+              js, '--no-slow', '--no-progress', '--tinderbox', '--tbpl']
+
+        if params['valgrind']:
+            cmd.append('--valgrind')
+
+        return subprocess.call(cmd)
diff --git a/testing/mozbase/mozrunner/mozrunner/remote.py b/testing/mozbase/mozrunner/mozrunner/remote.py
index cf7bc9fa6f71bcf2427ecbdb0e65ab43de470b0f..bc17b523156f4a34a4224cca37a8731299db9182 100644
--- a/testing/mozbase/mozrunner/mozrunner/remote.py
+++ b/testing/mozbase/mozrunner/mozrunner/remote.py
@@ -45,7 +45,8 @@ class RemoteRunner(Runner):
         self.remote_test_root = remote_test_root or self.dm.getDeviceRoot()
         self.remote_profile = posixpath.join(self.remote_test_root, 'profile')
         self.restore = restore
-        self.backup_files = set([])
+        self.added_files = set()
+        self.backup_files = set()
 
     def backup_file(self, remote_path):
         if not self.restore:
@@ -54,7 +55,8 @@ class RemoteRunner(Runner):
         if self.dm.fileExists(remote_path):
             self.dm.shellCheckOutput(['dd', 'if=%s' % remote_path, 'of=%s.orig' % remote_path])
             self.backup_files.add(remote_path)
-
+        else:
+            self.added_files.add(remote_path)
 
     def check_for_crashes(self, last_test=None):
         last_test = last_test or self.last_test
@@ -80,7 +82,10 @@ class RemoteRunner(Runner):
         Runner.cleanup(self)
 
         self.dm.remount()
-        # Restore the original profiles.ini
+        # Restore the original profile
+        for added_file in self.added_files:
+            self.dm.removeFile(added_file)
+
         for backup_file in self.backup_files:
             if self.dm.fileExists('%s.orig' % backup_file):
                 self.dm.shellCheckOutput(['dd', 'if=%s.orig' % backup_file, 'of=%s' % backup_file])
@@ -100,8 +105,9 @@ class RemoteRunner(Runner):
 
 class B2GRunner(RemoteRunner):
 
-    def __init__(self, profile, devicemanager, marionette, context_chrome=True,
-                 test_script=None, test_script_args=None, **kwargs):
+    def __init__(self, profile, devicemanager, marionette=None, context_chrome=True,
+                 test_script=None, test_script_args=None,
+                 marionette_port=None, emulator=None, **kwargs):
 
         RemoteRunner.__init__(self, profile, devicemanager, **kwargs)
         self.log = mozlog.getLogger('B2GRunner')
@@ -120,7 +126,22 @@ class B2GRunner(RemoteRunner):
                      'NO_EM_RESTART': '1', }
         self.env.update(tmp_env)
         self.last_test = "automation"
+
         self.marionette = marionette
+        if self.marionette is not None:
+            if marionette_port is None:
+                marionette_port = self.marionette.port
+            elif self.marionette.port != marionette_port:
+                raise ValueError("Got a marionette object and a port but they don't match")
+
+            if emulator is None:
+                emulator = marionette.emulator
+            elif marionette.emulator != emulator:
+                raise ValueError("Got a marionette object and an emulator argument but they don't match")
+
+        self.marionette_port = marionette_port
+        self.emulator = emulator
+
         self.context_chrome = context_chrome
         self.test_script = test_script
         self.test_script_args = test_script_args
@@ -144,8 +165,8 @@ class B2GRunner(RemoteRunner):
         self.outputTimeout = outputTimeout
         self._setup_remote_profile()
         # reboot device so it starts up with the proper profile
-        if not self.marionette.emulator:
-            self._reboot_device()
+        if not self.emulator:
+            self.dm.reboot(wait=True)
             #wait for wlan to come up
             if not self._wait_for_net():
                 raise Exception("network did not come up, please configure the network" +
@@ -161,11 +182,19 @@ class B2GRunner(RemoteRunner):
 
         # Set up port forwarding again for Marionette, since any that
         # existed previously got wiped out by the reboot.
-        if not self.marionette.emulator:
+        if self.emulator is None:
             subprocess.Popen([self.dm._adbPath,
                               'forward',
-                              'tcp:%s' % self.marionette.port,
-                              'tcp:%s' % self.marionette.port]).communicate()
+                              'tcp:%s' % self.marionette_port,
+                              'tcp:2828']).communicate()
+
+        if self.marionette is not None:
+            self.start_marionette()
+
+        if self.test_script is not None:
+            self.start_tests()
+
+    def start_marionette(self):
         self.marionette.wait_for_port()
 
         # start a marionette session
@@ -189,18 +218,15 @@ class B2GRunner(RemoteRunner):
         else:
             self.marionette.set_context(self.marionette.CONTEXT_CONTENT)
 
-        # run the script that starts the tests
 
-        if self.test_script:
-            if os.path.isfile(self.test_script):
-                script = open(self.test_script, 'r')
-                self.marionette.execute_script(script.read(), script_args=self.test_script_args)
-                script.close()
-            elif isinstance(self.test_script, basestring):
-                self.marionette.execute_script(self.test_script, script_args=self.test_script_args)
-        else:
-            # assumes the tests are started on startup automatically
-            pass
+    def start_tests(self):
+        # run the script that starts the tests
+        if os.path.isfile(self.test_script):
+            script = open(self.test_script, 'r')
+            self.marionette.execute_script(script.read(), script_args=self.test_script_args)
+            script.close()
+        elif isinstance(self.test_script, basestring):
+            self.marionette.execute_script(self.test_script, script_args=self.test_script_args)
 
     def on_output(self, line):
         match = re.findall(r"TEST-START \| ([^\s]*)", line)
@@ -221,29 +247,6 @@ class B2GRunner(RemoteRunner):
         self.log.testFail(msg % (self.last_test, timeout))
         self.check_for_crashes()
 
-    def _reboot_device(self):
-        serial, status = self._get_device_status()
-
-        buf = StringIO()
-        self.dm.shell('/system/bin/reboot', buf)
-        buf.close()
-
-        # The reboot command can return while adb still thinks the device is
-        # connected, so wait a little bit for it to disconnect from adb.
-        time.sleep(10)
-
-        # wait for device to come back to previous status
-        self.log.info('waiting for device to come back online after reboot')
-        start = time.time()
-        rserial, rstatus = self._get_device_status(serial)
-        while rstatus != 'device':
-            if time.time() - start > 120:
-                # device hasn't come back online in 2 minutes, something's wrong
-                raise Exception("Device %s (status: %s) not back online after reboot" % (serial, rstatus))
-            time.sleep(5)
-            rserial, rstatus = self._get_device_status(serial)
-        self.log.info('device: %s, status: %s' % (serial, rstatus))
-
     def _get_device_status(self, serial=None):
         # If we know the device serial number, we look for that,
         # otherwise we use the (presumably only) device shown in 'adb devices'.
diff --git a/testing/mozbase/mozrunner/setup.py b/testing/mozbase/mozrunner/setup.py
index 355cfe65bbf09d3ec58bda5aec343fd938626797..d724c39c06273e6b0bfd65e3107cd2fd3151b659 100644
--- a/testing/mozbase/mozrunner/setup.py
+++ b/testing/mozbase/mozrunner/setup.py
@@ -6,7 +6,7 @@ import sys
 from setuptools import setup
 
 PACKAGE_NAME = 'mozrunner'
-PACKAGE_VERSION = '5.35'
+PACKAGE_VERSION = '5.36'
 
 desc = """Reliable start/stop/configuration of Mozilla Applications (Firefox, Thunderbird, etc.)"""
 
diff --git a/testing/specialpowers/content/specialpowers.js b/testing/specialpowers/content/specialpowers.js
index 34f0ab9dc6a48873b03b9c8369f7cd6c89e7f14e..31ff09303ae5d32d3050c3e7a8bb2a5920f7ff8b 100644
--- a/testing/specialpowers/content/specialpowers.js
+++ b/testing/specialpowers/content/specialpowers.js
@@ -104,17 +104,7 @@ function attachSpecialPowersToWindow(aWindow) {
     if ((aWindow !== null) &&
         (aWindow !== undefined) &&
         (aWindow.wrappedJSObject) &&
-        (aWindow.parent !== null) &&
-        (aWindow.parent !== undefined) &&
-        (aWindow.parent.wrappedJSObject.SpecialPowers) &&
-        !(aWindow.wrappedJSObject.SpecialPowers) &&
-        aWindow.location.hostname == aWindow.parent.location.hostname) {
-      aWindow.wrappedJSObject.SpecialPowers = aWindow.parent.wrappedJSObject.SpecialPowers;
-    }
-    else if ((aWindow !== null) &&
-             (aWindow !== undefined) &&
-             (aWindow.wrappedJSObject) &&
-             !(aWindow.wrappedJSObject.SpecialPowers)) {
+        !(aWindow.wrappedJSObject.SpecialPowers)) {
       aWindow.wrappedJSObject.SpecialPowers = new SpecialPowers(aWindow);
     }
   } catch(ex) {
diff --git a/testing/tps/tps/cli.py b/testing/tps/tps/cli.py
index 54dd934f3de4f700d4ef10c060c9c04b63141eb0..862caa11f1590508baeff8b06f8e72d8a6dada54 100644
--- a/testing/tps/tps/cli.py
+++ b/testing/tps/tps/cli.py
@@ -14,29 +14,6 @@ from tps import TPSTestRunner
 
 def main():
     parser = optparse.OptionParser()
-    parser.add_option('--mobile',
-                      action='store_true',
-                      dest='mobile',
-                      default=False,
-                      help='run with mobile settings')
-    parser.add_option('--testfile',
-                      action='store',
-                      type='string',
-                      dest='testfile',
-                      default='../../services/sync/tests/tps/all_tests.json',
-                      help='path to the test file to run [default: %default]')
-    parser.add_option('--logfile',
-                      action='store',
-                      type='string',
-                      dest='logfile',
-                      default='tps.log',
-                      help='path to the log file [default: %default]')
-    parser.add_option('--resultfile',
-                      action='store',
-                      type='string',
-                      dest='resultfile',
-                      default='tps_result.json',
-                      help='path to the result file [default: %default]')
     parser.add_option('--binary',
                       action='store',
                       type='string',
@@ -51,6 +28,28 @@ def main():
                       dest='configfile',
                       default=None,
                       help='path to the config file to use default: %default]')
+    parser.add_option('--debug',
+                      action='store_true',
+                      dest='debug',
+                      default=False,
+                      help='run in debug mode')
+    parser.add_option('--ignore-unused-engines',
+                       default=False,
+                       action='store_true',
+                       dest='ignore_unused_engines',
+                       help='If defined, do not load unused engines in individual tests.'
+                            ' Has no effect for pulse monitor.')
+    parser.add_option('--logfile',
+                      action='store',
+                      type='string',
+                      dest='logfile',
+                      default='tps.log',
+                      help='path to the log file [default: %default]')
+    parser.add_option('--mobile',
+                      action='store_true',
+                      dest='mobile',
+                      default=False,
+                      help='run with mobile settings')
     parser.add_option('--pulsefile',
                       action='store',
                       type='string',
@@ -58,12 +57,18 @@ def main():
                       default=None,
                       help='path to file containing a pulse message in '
                            'json format that you want to inject into the monitor')
-    parser.add_option('--ignore-unused-engines',
-                       default=False,
-                       action='store_true',
-                       dest='ignore_unused_engines',
-                       help='If defined, do not load unused engines in individual tests.'
-                            ' Has no effect for pulse monitor.')
+    parser.add_option('--resultfile',
+                      action='store',
+                      type='string',
+                      dest='resultfile',
+                      default='tps_result.json',
+                      help='path to the result file [default: %default]')
+    parser.add_option('--testfile',
+                      action='store',
+                      type='string',
+                      dest='testfile',
+                      default='../../services/sync/tests/tps/all_tests.json',
+                      help='path to the test file to run [default: %default]')
     (options, args) = parser.parse_args()
 
     configfile = options.configfile
@@ -97,14 +102,16 @@ def main():
                 extensionDir = extensionDir.replace('/', '\\')
 
     TPS = TPSTestRunner(extensionDir,
-                        testfile=options.testfile,
-                        logfile=options.logfile,
                         binary=options.binary,
                         config=config,
-                        rlock=rlock,
+                        debug=options.debug,
+                        ignore_unused_engines=options.ignore_unused_engines,
+                        logfile=options.logfile,
                         mobile=options.mobile,
                         resultfile=options.resultfile,
-                        ignore_unused_engines=options.ignore_unused_engines)
+                        rlock=rlock,
+                        testfile=options.testfile,
+                      )
     TPS.run_tests()
 
 if __name__ == '__main__':
diff --git a/testing/tps/tps/testrunner.py b/testing/tps/tps/testrunner.py
index 4d86e34c155e2d4d9d6c7f13cd0e1fda4a5d3310..1e5255cbc13f0fa04a7c014bae08f69b8f8a28a1 100644
--- a/testing/tps/tps/testrunner.py
+++ b/testing/tps/tps/testrunner.py
@@ -46,35 +46,58 @@ class TempFile(object):
 
 class TPSTestRunner(object):
 
-    default_env = { 'MOZ_CRASHREPORTER_DISABLE': '1',
-                    'GNOME_DISABLE_CRASH_DIALOG': '1',
-                    'XRE_NO_WINDOWS_CRASH_DIALOG': '1',
-                    'MOZ_NO_REMOTE': '1',
-                    'XPCOM_DEBUG_BREAK': 'warn',
-                  }
-    default_preferences = { 'app.update.enabled' : False,
-                            'browser.dom.window.dump.enabled': True,
-                            'browser.sessionstore.resume_from_crash': False,
-                            'browser.shell.checkDefaultBrowser' : False,
-                            'browser.tabs.warnOnClose' : False,
-                            'browser.warnOnQuit': False,
-                            # Allow installing extensions dropped into the profile folder
-                            'extensions.autoDisableScopes': 10,
-                            'extensions.getAddons.get.url': 'http://127.0.0.1:4567/addons/api/%IDS%.xml',
-                            'extensions.update.enabled'    : False,
-                            # Don't open a dialog to show available add-on updates
-                            'extensions.update.notifyUser' : False,
-                            'services.sync.addons.ignoreRepositoryChecking': True,
-                            'services.sync.firstSync': 'notReady',
-                            'services.sync.lastversion': '1.0',
-                            'services.sync.log.rootLogger': 'Trace',
-                            'services.sync.log.logger.engine.addons': 'Trace',
-                            'services.sync.log.logger.service.main': 'Trace',
-                            'services.sync.log.logger.engine.bookmarks': 'Trace',
-                            'services.sync.log.appender.console': 'Trace',
-                            'services.sync.log.appender.debugLog.enabled': True,
-                            'toolkit.startup.max_resumed_crashes': -1,
-                          }
+    default_env = {
+        'MOZ_CRASHREPORTER_DISABLE': '1',
+        'GNOME_DISABLE_CRASH_DIALOG': '1',
+        'XRE_NO_WINDOWS_CRASH_DIALOG': '1',
+        'MOZ_NO_REMOTE': '1',
+        'XPCOM_DEBUG_BREAK': 'warn',
+    }
+
+    default_preferences = {
+        'app.update.enabled': False,
+        'browser.dom.window.dump.enabled': True,
+        'browser.sessionstore.resume_from_crash': False,
+        'browser.shell.checkDefaultBrowser': False,
+        'browser.tabs.warnOnClose': False,
+        'browser.warnOnQuit': False,
+        # Allow installing extensions dropped into the profile folder
+        'extensions.autoDisableScopes': 10,
+        'extensions.getAddons.get.url': 'http://127.0.0.1:4567/addons/api/%IDS%.xml',
+        'extensions.update.enabled': False,
+        # Don't open a dialog to show available add-on updates
+        'extensions.update.notifyUser': False,
+        'services.sync.addons.ignoreRepositoryChecking': True,
+        'services.sync.firstSync': 'notReady',
+        'services.sync.lastversion': '1.0',
+        'toolkit.startup.max_resumed_crashes': -1,
+    }
+
+    debug_preferences = {
+        'services.sync.log.appender.console': 'Trace',
+        'services.sync.log.appender.dump': 'Trace',
+        'services.sync.log.appender.file.level': 'Trace',
+        'services.sync.log.appender.file.logOnSuccess': True,
+        'services.sync.log.rootLogger': 'Trace',
+        'services.sync.log.logger.addonutils': 'Trace',
+        'services.sync.log.logger.declined': 'Trace',
+        'services.sync.log.logger.service.main': 'Trace',
+        'services.sync.log.logger.status': 'Trace',
+        'services.sync.log.logger.authenticator': 'Trace',
+        'services.sync.log.logger.network.resources': 'Trace',
+        'services.sync.log.logger.service.jpakeclient': 'Trace',
+        'services.sync.log.logger.engine.bookmarks': 'Trace',
+        'services.sync.log.logger.engine.clients': 'Trace',
+        'services.sync.log.logger.engine.forms': 'Trace',
+        'services.sync.log.logger.engine.history': 'Trace',
+        'services.sync.log.logger.engine.passwords': 'Trace',
+        'services.sync.log.logger.engine.prefs': 'Trace',
+        'services.sync.log.logger.engine.tabs': 'Trace',
+        'services.sync.log.logger.engine.addons': 'Trace',
+        'services.sync.log.logger.engine.apps': 'Trace',
+        'services.sync.log.logger.identity': 'Trace',
+        'services.sync.log.logger.userapi': 'Trace',
+    }
 
     syncVerRe = re.compile(
         r'Sync version: (?P<syncversion>.*)\n')
@@ -84,32 +107,39 @@ class TPSTestRunner(object):
         r'Firefox builddate: (?P<ffdate>.*)\n')
 
     def __init__(self, extensionDir,
-                 testfile='sync.test',
-                 binary=None, config=None, rlock=None, mobile=False,
-                 logfile='tps.log', resultfile='tps_result.json',
-                 ignore_unused_engines=False):
+                 binary=None,
+                 config=None,
+                 debug=False,
+                 ignore_unused_engines=False,
+                 logfile='tps.log',
+                 mobile=False,
+                 rlock=None,
+                 resultfile='tps_result.json',
+                 testfile=None):
+        self.binary = binary
+        self.config = config if config else {}
+        self.debug = debug
         self.extensions = []
-        self.testfile = testfile
+        self.ignore_unused_engines = ignore_unused_engines
         self.logfile = os.path.abspath(logfile)
+        self.mobile = mobile
+        self.rlock = rlock
         self.resultfile = resultfile
-        self.binary = binary
-        self.ignore_unused_engines = ignore_unused_engines
-        self.config = config if config else {}
-        self.repo = None
-        self.changeset = None
+        self.testfile = testfile
+
+        self.addonversion = None
         self.branch = None
+        self.changeset = None
+        self.errorlogs = {}
+        self.extensionDir = extensionDir
+        self.firefoxRunner = None
+        self.nightly = False
         self.numfailed = 0
         self.numpassed = 0
-        self.nightly = False
-        self.rlock = rlock
-        self.mobile = mobile
-        self.tpsxpi = None
-        self.firefoxRunner = None
-        self.extensionDir = extensionDir
-        self.productversion = None
-        self.addonversion = None
         self.postdata = {}
-        self.errorlogs = {}
+        self.productversion = None
+        self.repo = None
+        self.tpsxpi = None
 
     @property
     def mobile(self):
@@ -301,15 +331,9 @@ class TPSTestRunner(object):
 
         return resultdata
 
-    def run_tests(self):
-        # delete the logfile if it already exists
-        if os.access(self.logfile, os.F_OK):
-            os.remove(self.logfile)
-
-        # Make a copy of the default env variables and preferences, and update
-        # them for mobile settings if needed.
-        self.env = self.default_env.copy()
+    def update_preferences(self):
         self.preferences = self.default_preferences.copy()
+
         if self.mobile:
             self.preferences.update({'services.sync.client.type' : 'mobile'})
 
@@ -319,6 +343,19 @@ class TPSTestRunner(object):
         auth_type = self.config.get('auth_type', 'fx_account')
         self.preferences.update({'services.sync.username': dummy[auth_type]})
 
+        if self.debug:
+            self.preferences.update(self.debug_preferences)
+
+    def run_tests(self):
+        # delete the logfile if it already exists
+        if os.access(self.logfile, os.F_OK):
+            os.remove(self.logfile)
+
+        # Make a copy of the default env variables and preferences, and update
+        # them for custom settings
+        self.env = self.default_env.copy()
+        self.update_preferences()
+
         # Acquire a lock to make sure no other threads are running tests
         # at the same time.
         if self.rlock:
diff --git a/toolkit/components/osfile/NativeOSFileInternals.cpp b/toolkit/components/osfile/NativeOSFileInternals.cpp
index 71b4caab95847a7937d6a6c561d4f29f98f6002f..ae6ba8106fab084946e587b79601d6e33be48478 100644
--- a/toolkit/components/osfile/NativeOSFileInternals.cpp
+++ b/toolkit/components/osfile/NativeOSFileInternals.cpp
@@ -46,7 +46,7 @@
 #endif // defined (XP_UNIX)
 
 #if defined(XP_WIN)
-#include <Windows.h>
+#include <windows.h>
 #endif // defined (XP_WIN)
 
 namespace mozilla {
diff --git a/toolkit/devtools/tests/unit/test_async-utils.js b/toolkit/devtools/tests/unit/test_async-utils.js
index ddd2a6426993cb61369d6be15f7af650ad647038..a4a91c831ba63af5753fec6794c02d156acd0ebc 100644
--- a/toolkit/devtools/tests/unit/test_async-utils.js
+++ b/toolkit/devtools/tests/unit/test_async-utils.js
@@ -7,9 +7,11 @@
 const {Task} = Cu.import("resource://gre/modules/Task.jsm", {});
 // |const| will not work because
 // it will make the Promise object immutable before assigning.
-// Using |let| and Object.freeze() instead.
-let {Promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
-Object.freeze(Promise);
+// Using Object.defineProperty() instead.
+Object.defineProperty(this, "Promise", {
+  value: Cu.import("resource://gre/modules/Promise.jsm", {}).Promise,
+  writable: false, configurable: false
+});
 const {require} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools;
 const {async, asyncOnce, promiseInvoke, promiseCall} = require("devtools/async-utils");
 
diff --git a/toolkit/library/Makefile.in b/toolkit/library/Makefile.in
index 2f513b2f632f65e57df92a966714ddc4f8d7b731..86d48d69be099f7ec44629c76be23216c10a7ebb 100644
--- a/toolkit/library/Makefile.in
+++ b/toolkit/library/Makefile.in
@@ -233,18 +233,10 @@ ifdef MOZ_METRO
 OS_LIBS += $(call EXPAND_LIBNAME,uiautomationcore runtimeobject)
 endif
 ifdef MOZ_GAMEPAD
-ifndef GNU_CC
 ifdef MOZ_HAS_WINSDK_WITH_D3D
-OS_LIBS += dxguid.lib dinput8.lib
-else
-DXSDK := $(subst \,/,$(MOZ_DIRECTX_SDK_PATH))/Lib/$(MOZ_DIRECTX_SDK_CPU_SUFFIX)
-OS_LIBS += \
-  '$(DXSDK)/dxguid.lib' \
-  '$(DXSDK)/dinput8.lib' \
-  $(NULL)
-endif
-else
 OS_LIBS += $(call EXPAND_LIBNAME,dxguid dinput8)
+else
+OS_LIBS += $(call EXPAND_LIBNAME_PATH,dxguid dinput8, $(subst \,/,$(MOZ_DIRECTX_SDK_PATH))/Lib/$(MOZ_DIRECTX_SDK_CPU_SUFFIX))
 endif
 endif
 endif # WINNT
diff --git a/tools/profiler/platform.h b/tools/profiler/platform.h
index 9a68f1e4c573fbec39d98072572061ca8b678426..5fb03960dc22f39ff184d1069e715bbb6c2771ea 100644
--- a/tools/profiler/platform.h
+++ b/tools/profiler/platform.h
@@ -40,6 +40,7 @@
 #endif
 
 #include <stdint.h>
+#include <math.h>
 #include "mozilla/unused.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/Mutex.h"