Merge mozilla-central to fx-team
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Fri, 08 Nov 2013 16:02:49 +0100
changeset 168708 ff3e6bc839c63e224650c285cd72831408d5bd68
parent 168707 ff7e84f5968bad29b075f354ee74bfe695e5bf9b (current diff)
parent 168697 361a24da71128ed043c93d44cacbbae8b0234357 (diff)
child 168709 e18759fb71eacdbb1dc94f3a45ab425341584f1d
push id3224
push userlsblakk@mozilla.com
push dateTue, 04 Feb 2014 01:06:49 +0000
treeherdermozilla-beta@60c04d0987f1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone28.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to fx-team
dom/base/nsIScriptGlobalObjectOwner.h
dom/inputmethod/forms.js
dom/inputmethod/jar.mn
media/webrtc/trunk/webrtc/common_audio/signal_processing/webrtc_fft_t_1024_8.c
media/webrtc/trunk/webrtc/common_audio/signal_processing/webrtc_fft_t_rad.c
media/webrtc/trunk/webrtc/common_video/jpeg/Android.mk
media/webrtc/trunk/webrtc/common_video/jpeg/data_manager.cc
media/webrtc/trunk/webrtc/common_video/jpeg/data_manager.h
media/webrtc/trunk/webrtc/common_video/jpeg/include/jpeg.h
media/webrtc/trunk/webrtc/common_video/jpeg/jpeg.cc
media/webrtc/trunk/webrtc/common_video/jpeg/jpeg_unittest.cc
media/webrtc/trunk/webrtc/modules/audio_coding/codecs/isac/fix/source/transform.h
media/webrtc/trunk/webrtc/modules/audio_coding/codecs/isac/fix/test/ISACHist.cc
media/webrtc/trunk/webrtc/modules/audio_coding/codecs/isac/fix/test/Isac_test.cc
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/acm_common_defs.h
media/webrtc/trunk/webrtc/modules/audio_coding/main/source/audio_coding_module.cc
media/webrtc/trunk/webrtc/modules/audio_conference_mixer/test/FunctionTest/functionTest.cc
media/webrtc/trunk/webrtc/modules/audio_conference_mixer/test/FunctionTest/functionTest.h
media/webrtc/trunk/webrtc/modules/audio_device/android/org/webrtc/voiceengine/WebRTCAudioDevice.java
media/webrtc/trunk/webrtc/modules/audio_device/audio_device_opensles.cc
media/webrtc/trunk/webrtc/modules/audio_device/audio_device_opensles.h
media/webrtc/trunk/webrtc/modules/audio_device/test/android/audio_device_android_test/jni/audio_device_android_test.cc
media/webrtc/trunk/webrtc/modules/audio_device/test/android/audio_device_android_test/jni/org_webrtc_voiceengine_test_AudioDeviceAndroidTest.h
media/webrtc/trunk/webrtc/modules/audio_processing/test/unit_test.cc
media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_linux.cc
media/webrtc/trunk/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_multi_stream.cc
media/webrtc/trunk/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_multi_stream_unittest.cc
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/mock/mock_rtp_receiver_video.h
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/receiver_fec.cc
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/receiver_fec.h
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/receiver_fec_unittest.cc
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_payload_registry.h
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_receiver.cc
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_receiver.h
media/webrtc/trunk/webrtc/modules/rtp_rtcp/test/BWEStandAlone/BWEConvergenceTest.cc
media/webrtc/trunk/webrtc/modules/rtp_rtcp/test/BWEStandAlone/BWEConvergenceTest.h
media/webrtc/trunk/webrtc/modules/rtp_rtcp/test/BWEStandAlone/BWEStabilityTest.cc
media/webrtc/trunk/webrtc/modules/rtp_rtcp/test/BWEStandAlone/BWEStabilityTest.h
media/webrtc/trunk/webrtc/modules/rtp_rtcp/test/BWEStandAlone/BWETestBase.cc
media/webrtc/trunk/webrtc/modules/rtp_rtcp/test/BWEStandAlone/BWETestBase.h
media/webrtc/trunk/webrtc/modules/rtp_rtcp/test/BWEStandAlone/BWETester.cc
media/webrtc/trunk/webrtc/modules/rtp_rtcp/test/BWEStandAlone/BWETwoWayLimitFinding.cc
media/webrtc/trunk/webrtc/modules/rtp_rtcp/test/BWEStandAlone/BWETwoWayLimitFinding.h
media/webrtc/trunk/webrtc/modules/rtp_rtcp/test/testTMMBR/testTMMBR.cc
media/webrtc/trunk/webrtc/modules/utility/test/testAPI.cc
media/webrtc/trunk/webrtc/modules/video_capture/android/java/org/webrtc/videoengine/CaptureCapabilityAndroid.java
media/webrtc/trunk/webrtc/modules/video_capture/android/java/org/webrtc/videoengine/VideoCaptureAndroid.java
media/webrtc/trunk/webrtc/modules/video_capture/android/java/org/webrtc/videoengine/VideoCaptureDeviceInfoAndroid.java
media/webrtc/trunk/webrtc/modules/video_capture/mac/quicktime/video_capture_quick_time.cc
media/webrtc/trunk/webrtc/modules/video_capture/mac/quicktime/video_capture_quick_time.h
media/webrtc/trunk/webrtc/modules/video_capture/mac/quicktime/video_capture_quick_time_info.cc
media/webrtc/trunk/webrtc/modules/video_capture/mac/quicktime/video_capture_quick_time_info.h
media/webrtc/trunk/webrtc/modules/video_capture/mac/video_capture_mac.h
media/webrtc/trunk/webrtc/modules/video_coding/main/source/stream_generator.cc
media/webrtc/trunk/webrtc/modules/video_coding/main/source/stream_generator.h
media/webrtc/trunk/webrtc/modules/video_coding/main/source/video_coding_impl_unittest.cc
media/webrtc/trunk/webrtc/modules/video_coding/main/test/decode_from_storage_test.cc
media/webrtc/trunk/webrtc/modules/video_coding/main/test/jitter_estimate_test.cc
media/webrtc/trunk/webrtc/modules/video_coding/main/test/release_test.cc
media/webrtc/trunk/webrtc/modules/video_coding/main/test/release_test_pt2.cc
media/webrtc/trunk/webrtc/modules/video_processing/main/test/unit_test/unit_test.cc
media/webrtc/trunk/webrtc/modules/video_processing/main/test/unit_test/unit_test.h
media/webrtc/trunk/webrtc/modules/video_render/android/java/org/webrtc/videoengine/ViEAndroidGLES20.java
media/webrtc/trunk/webrtc/modules/video_render/android/java/org/webrtc/videoengine/ViERenderer.java
media/webrtc/trunk/webrtc/modules/video_render/android/java/org/webrtc/videoengine/ViESurfaceRenderer.java
media/webrtc/trunk/webrtc/system_wrappers/interface/map_wrapper.h
media/webrtc/trunk/webrtc/system_wrappers/source/map.cc
media/webrtc/trunk/webrtc/system_wrappers/source/map_no_stl.cc
media/webrtc/trunk/webrtc/system_wrappers/source/map_no_stl.h
media/webrtc/trunk/webrtc/system_wrappers/source/map_unittest.cc
media/webrtc/trunk/webrtc/system_wrappers/test/map/map.cc
media/webrtc/trunk/webrtc/video_engine/include/vie_file.h
media/webrtc/trunk/webrtc/video_engine/internal/video_call.cc
media/webrtc/trunk/webrtc/video_engine/internal/video_call.h
media/webrtc/trunk/webrtc/video_engine/internal/video_engine.cc
media/webrtc/trunk/webrtc/video_engine/new_include/video_engine.h
media/webrtc/trunk/webrtc/video_engine/test/android/build_demo.py
media/webrtc/trunk/webrtc/video_engine/test/android/jni/Android.mk
media/webrtc/trunk/webrtc/video_engine/test/android/jni/Application.mk
media/webrtc/trunk/webrtc/video_engine/test/auto_test/source/vie_autotest_file.cc
media/webrtc/trunk/webrtc/video_engine/test/common/frame_generator.cc
media/webrtc/trunk/webrtc/video_engine/test/common/frame_generator.h
media/webrtc/trunk/webrtc/video_engine/vie_file_impl.cc
media/webrtc/trunk/webrtc/video_engine/vie_file_impl.h
media/webrtc/trunk/webrtc/video_engine/vie_file_player.cc
media/webrtc/trunk/webrtc/video_engine/vie_file_player.h
media/webrtc/trunk/webrtc/video_engine/vie_file_recorder.cc
media/webrtc/trunk/webrtc/video_engine/vie_file_recorder.h
media/webrtc/trunk/webrtc/voice_engine/channel_manager_base.cc
media/webrtc/trunk/webrtc/voice_engine/channel_manager_base.h
--- a/accessible/src/generic/DocAccessible.cpp
+++ b/accessible/src/generic/DocAccessible.cpp
@@ -1727,17 +1727,18 @@ DocAccessible::ProcessContentInserted(Ac
         // there is no HTML body element.
       }
 
       // XXX: Invalidate parent-child relations for container accessible and its
       // children because there's no good way to find insertion point of new child
       // accessibles into accessible tree. We need to invalidate children even
       // there's no inserted accessibles in the end because accessible children
       // are created while parent recaches child accessibles.
-      aContainer->UpdateChildren();
+      aContainer->InvalidateChildren();
+      CacheChildrenInSubtree(aContainer);
     }
 
     UpdateTree(aContainer, aInsertedContent->ElementAt(idx), true);
   }
 }
 
 void
 DocAccessible::UpdateTree(Accessible* aContainer, nsIContent* aChildNode,
--- a/accessible/tests/mochitest/treeupdate/a11y.ini
+++ b/accessible/tests/mochitest/treeupdate/a11y.ini
@@ -1,12 +1,13 @@
 [DEFAULT]
 
 [test_ariadialog.html]
 [test_bug852150.xhtml]
+[test_bug895082.html]
 [test_canvas.html]
 [test_colorpicker.xul]
 [test_contextmenu.xul]
 [test_cssoverflow.html]
 [test_deck.xul]
 [test_doc.html]
 [test_gencontent.html]
 [test_hidden.html]
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/treeupdate/test_bug895082.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Replace body test</title>
+  <link rel="stylesheet" type="text/css"
+        href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+  <script type="application/javascript"
+          src="../common.js"></script>
+  <script type="application/javascript"
+          src="../role.js"></script>
+  <script type="application/javascript"
+          src="../events.js"></script>
+
+  <script type="application/javascript">
+function doTest()
+{
+  var y = document.getElementById("y");
+  var oldBody = document.body;
+  var newBody = document.createElement("body")
+  document.documentElement.insertBefore(newBody, oldBody);
+  setTimeout(function() {
+    document.documentElement.removeChild(oldBody);
+    newBody.appendChild(y);
+    ok(true, "we didn't assert");
+    SimpleTest.finish();
+  }, 0);
+}
+
+    SimpleTest.waitForExplicitFinish();
+    addA11yLoadEvent(doTest);
+  </script>
+</head>
+<body>
+
+  <a target="_blank"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=895082"
+     title="Bug 895082 - replacing body element asserts">
+    Bug 895082</a>
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+
+<div><div id="y"></div></div>
+
+</body>
+</html>
--- a/b2g/app/Makefile.in
+++ b/b2g/app/Makefile.in
@@ -108,41 +108,44 @@ APP_VERSION = $(MOZ_APP_VERSION)
 ifdef MOZ_DEBUG
 APP_NAME := $(APP_NAME)Debug
 endif
 
 AB_CD = $(MOZ_UI_LOCALE)
 
 AB := $(firstword $(subst -, ,$(AB_CD)))
 
-clean clobber::
+clean clobber repackage::
 	rm -rf $(DIST)/$(APP_NAME).app
 
 ifdef LIBXUL_SDK
 APPFILES = Resources
 else
 APPFILES = MacOS
 endif
 
 libs-preqs = \
   $(call mkdir_deps,$(DIST)/$(APP_NAME).app/Contents/MacOS) \
   $(call mkdir_deps,$(DIST)/$(APP_NAME).app/Contents/Resources/$(AB).lproj) \
   $(NULL)
 
 .PHONY: repackage
-libs:: $(libs-preqs)
+tools repackage:: $(libs-preqs)
 	rsync -a --exclude "*.in" $(srcdir)/macbuild/Contents $(DIST)/$(APP_NAME).app --exclude English.lproj
 	rsync -a --exclude "*.in" $(srcdir)/macbuild/Contents/Resources/English.lproj/ $(DIST)/$(APP_NAME).app/Contents/Resources/$(AB).lproj
 	sed -e "s/%MOZ_APP_VERSION%/$(MOZ_APP_VERSION)/" -e "s/%MOZ_APP_NAME%/$(MOZ_APP_NAME)/" -e "s/%APP_VERSION%/$(APP_VERSION)/" -e "s/%APP_NAME%/$(APP_NAME)/" -e "s/%APP_BINARY%/$(APP_BINARY)/" $(srcdir)/macbuild/Contents/Info.plist.in > $(DIST)/$(APP_NAME).app/Contents/Info.plist
 	sed -e "s/%APP_VERSION%/$(APP_VERSION)/" -e "s/%APP_NAME%/$(APP_NAME)/" $(srcdir)/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in | iconv -f UTF-8 -t UTF-16 > $(DIST)/$(APP_NAME).app/Contents/Resources/$(AB).lproj/InfoPlist.strings
-	rm -rf $(DIST)/$(APP_NAME).app/Contents/$(APPFILES)
-	ln -s $(abspath $(DIST)/bin) $(DIST)/$(APP_NAME).app/Contents/$(APPFILES)
+	rsync -a $(DIST)/bin/ $(DIST)/$(APP_NAME).app/Contents/$(APPFILES)
+	$(RM) $(DIST)/$(APP_NAME).app/Contents/$(APPFILES)/mangle $(DIST)/$(APP_NAME).app/Contents/$(APPFILES)/shlibsign
 ifdef LIBXUL_SDK
 	cp $(LIBXUL_DIST)/bin/xulrunner$(BIN_SUFFIX) $(DIST)/$(APP_NAME).app/Contents/MacOS/$(APP_BINARY)
 	rsync -a --exclude nsinstall --copy-unsafe-links $(LIBXUL_DIST)/XUL.framework $(DIST)/$(APP_NAME).app/Contents/Frameworks
+else
+	$(RM) $(DIST)/$(APP_NAME).app/Contents/MacOS/$(PROGRAM)
+	rsync -aL $(PROGRAM) $(DIST)/$(APP_NAME).app/Contents/MacOS
 endif
 	cp -RL $(srcdir)/b2g.icns $(DIST)/$(APP_NAME).app/Contents/Resources/$(MOZ_APP_NAME).icns
 	printf "APPLMOZB" > $(DIST)/$(APP_NAME).app/Contents/PkgInfo
 
 else # MOZ_WIDGET_TOOLKIT != cocoa
 
 libs::
 ifdef LIBXUL_SDK
rename from dom/inputmethod/forms.js
rename to b2g/chrome/content/forms.js
--- a/b2g/chrome/jar.mn
+++ b/b2g/chrome/jar.mn
@@ -5,16 +5,17 @@
 
 
 chrome.jar:
 % content branding %content/branding/
 % content browser %content/
 
   content/arrow.svg                     (content/arrow.svg)
 * content/dbg-browser-actors.js         (content/dbg-browser-actors.js)
+  content/forms.js                      (content/forms.js)
 * content/settings.js                   (content/settings.js)
 * content/shell.html                    (content/shell.html)
 * content/shell.js                      (content/shell.js)
 #ifndef ANDROID
   content/screen.js                     (content/screen.js)
   content/runapp.js                     (content/runapp.js)
 #endif
 * content/content.css                   (content/content.css)
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,4 +1,4 @@
 {
-    "revision": "0af41c1c297f1b784fb103e6150910f334036f20", 
+    "revision": "6ce2fe088a1113ac761dfa1f6a6a09fb7f38f787", 
     "repo_path": "/integration/gaia-central"
 }
--- a/browser/app/Makefile.in
+++ b/browser/app/Makefile.in
@@ -157,40 +157,38 @@ MAC_APP_NAME = $(MOZ_APP_DISPLAYNAME)
 ifdef MOZ_DEBUG
 MAC_APP_NAME := $(MAC_APP_NAME)Debug
 endif
 
 AB_CD = $(MOZ_UI_LOCALE)
 
 AB := $(firstword $(subst -, ,$(AB_CD)))
 
-clean clobber::
+clean clobber repackage::
 	$(RM) -r $(dist_dest)
 
 ifdef LIBXUL_SDK
 APPFILES = Resources
 else
 APPFILES = MacOS
 endif
 
 MAC_BUNDLE_VERSION = $(shell $(PYTHON) $(srcdir)/macversion.py --version=$(MOZ_APP_VERSION) --buildid=$(DEPTH)/config/buildid)
 
-libs:: $(PROGRAM)
+.PHONY: repackage
+tools repackage:: $(PROGRAM)
 	$(MKDIR) -p $(dist_dest)/Contents/MacOS
 	$(MKDIR) -p $(dist_dest)/Contents/Resources/$(AB).lproj
 	rsync -a --exclude "*.in" $(srcdir)/macbuild/Contents $(dist_dest) --exclude English.lproj
 	rsync -a --exclude "*.in" $(srcdir)/macbuild/Contents/Resources/English.lproj/ $(dist_dest)/Contents/Resources/$(AB).lproj
 	sed -e "s/%APP_VERSION%/$(MOZ_APP_VERSION)/" -e "s/%MAC_APP_NAME%/$(MAC_APP_NAME)/" -e "s/%MOZ_MACBUNDLE_ID%/$(MOZ_MACBUNDLE_ID)/" -e "s/%MAC_BUNDLE_VERSION%/$(MAC_BUNDLE_VERSION)/" $(srcdir)/macbuild/Contents/Info.plist.in > $(dist_dest)/Contents/Info.plist
 	sed -e "s/%MAC_APP_NAME%/$(MAC_APP_NAME)/" $(srcdir)/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in | iconv -f UTF-8 -t UTF-16 > $(dist_dest)/Contents/Resources/$(AB).lproj/InfoPlist.strings
-	rm -rf $(dist_dest)/Contents/$(APPFILES)
-	ln -s $(abspath $(DIST)/bin) $(dist_dest)/Contents/$(APPFILES)
-ifdef LIBXUL_SDK
+	rsync -a $(DIST)/bin/ $(dist_dest)/Contents/$(APPFILES)
 	$(RM) $(dist_dest)/Contents/MacOS/$(PROGRAM)
 	rsync -aL $(PROGRAM) $(dist_dest)/Contents/MacOS
-endif
 	cp -RL $(DIST)/branding/firefox.icns $(dist_dest)/Contents/Resources/firefox.icns
 	cp -RL $(DIST)/branding/document.icns $(dist_dest)/Contents/Resources/document.icns
 	printf APPLMOZB > $(dist_dest)/Contents/PkgInfo
 endif
 
 ifdef LIBXUL_SDK #{
 ifndef SKIP_COPY_XULRUNNER #{
 libs::
--- a/browser/metro/base/content/bindings/browser.js
+++ b/browser/metro/base/content/bindings/browser.js
@@ -4,16 +4,19 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 let Cc = Components.classes;
 let Ci = Components.interfaces;
 let Cu = Components.utils;
 
 Cu.import("resource://gre/modules/Services.jsm");
 
+XPCOMUtils.defineLazyServiceGetter(this, "gUUIDGenerator",
+                                   "@mozilla.org/uuid-generator;1", "nsIUUIDGenerator");
+
 let WebProgressListener = {
   _lastLocation: null,
   _firstPaint: false,
 
   init: function() {
     let flags = Ci.nsIWebProgress.NOTIFY_LOCATION |
                 Ci.nsIWebProgress.NOTIFY_SECURITY |
                 Ci.nsIWebProgress.NOTIFY_STATE_WINDOW |
@@ -255,17 +258,17 @@ let WebNavigation =  {
       shEntry.cacheKey = cacheKey;
     }
 
     if (aEntry.ID) {
       // get a new unique ID for this frame (since the one from the last
       // start might already be in use)
       let id = aIdMap[aEntry.ID] || 0;
       if (!id) {
-        for (id = Date.now(); id in aIdMap.used; id++);
+        id = gUUIDGenerator.generateUUID();
         aIdMap[aEntry.ID] = id;
         aIdMap.used[id] = true;
       }
       shEntry.ID = id;
     }
 
     if (aEntry.docshellID)
       shEntry.docshellID = aEntry.docshellID;
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -1368,17 +1368,17 @@ endif
 
 ifneq ($(DIST_CHROME_FILES),)
 DIST_CHROME_FILES_PATH := $(FINAL_TARGET)/chrome
 DIST_CHROME_FILES_FLAGS := $(XULAPP_DEFINES)
 PP_TARGETS += DIST_CHROME_FILES
 endif
 
 ifneq ($(XPI_PKGNAME),)
-libs realchrome::
+tools realchrome::
 ifdef STRIP_XPI
 ifndef MOZ_DEBUG
 	@echo "Stripping $(XPI_PKGNAME) package directory..."
 	@echo $(FINAL_TARGET)
 	@cd $(FINAL_TARGET) && find . ! -type d \
 			! -name "*.js" \
 			! -name "*.xpt" \
 			! -name "*.gif" \
@@ -1407,17 +1407,17 @@ endif
 	cd $(FINAL_TARGET) && $(ZIP) -qr ../$(XPI_PKGNAME).xpi *
 endif
 
 ifdef INSTALL_EXTENSION_ID
 ifndef XPI_NAME
 $(error XPI_NAME must be set for INSTALL_EXTENSION_ID)
 endif
 
-libs::
+tools::
 	$(RM) -r "$(DIST)/bin$(DIST_SUBDIR:%=/%)/extensions/$(INSTALL_EXTENSION_ID)"
 	$(NSINSTALL) -D "$(DIST)/bin$(DIST_SUBDIR:%=/%)/extensions/$(INSTALL_EXTENSION_ID)"
 	$(call copy_dir,$(FINAL_TARGET),$(DIST)/bin$(DIST_SUBDIR:%=/%)/extensions/$(INSTALL_EXTENSION_ID))
 
 endif
 
 #############################################################################
 # MDDEPDIR is the subdirectory where all the dependency files are placed.
--- a/content/canvas/src/WebGLContextExtensions.cpp
+++ b/content/canvas/src/WebGLContextExtensions.cpp
@@ -111,30 +111,32 @@ bool WebGLContext::IsExtensionSupported(
                 return false;
             }
             return gl->IsSupported(GLFeature::depth_texture) ||
                    gl->IsExtensionSupported(GLContext::ANGLE_depth_texture);
         case ANGLE_instanced_arrays:
             return WebGLExtensionInstancedArrays::IsSupported(this);
         case EXT_sRGB:
             return WebGLExtensionSRGB::IsSupported(this);
+        case WEBGL_draw_buffers:
+            return WebGLExtensionDrawBuffers::IsSupported(this);
         default:
             // For warnings-as-errors.
             break;
     }
-
+// Uncomment this switch for any new extensions
+#if 0
     if (Preferences::GetBool("webgl.enable-draft-extensions", false) || IsWebGL2()) {
         switch (ext) {
-            case WEBGL_draw_buffers:
-                return WebGLExtensionDrawBuffers::IsSupported(this);
             default:
                 // For warnings-as-errors.
                 break;
         }
     }
+#endif
 
     return false;
 }
 
 static bool
 CompareWebGLExtensionName(const nsACString& name, const char *other)
 {
     return name.Equals(other, nsCaseInsensitiveCStringComparator());
--- a/content/html/document/src/nsHTMLContentSink.cpp
+++ b/content/html/document/src/nsHTMLContentSink.cpp
@@ -55,17 +55,16 @@
 #include "nsINameSpaceManager.h"
 #include "nsIDOMHTMLMapElement.h"
 #include "nsICookieService.h"
 #include "nsTArray.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIPrincipal.h"
 #include "nsTextFragment.h"
 #include "nsIScriptGlobalObject.h"
-#include "nsIScriptGlobalObjectOwner.h"
 
 #include "nsIParserService.h"
 
 #include "nsIStyleSheetLinkingElement.h"
 #include "nsITimer.h"
 #include "nsError.h"
 #include "nsContentPolicyUtils.h"
 #include "nsIScriptContext.h"
@@ -707,20 +706,17 @@ IsScriptEnabled(nsIDocument *aDoc, nsIDo
   NS_ENSURE_TRUE(aDoc && aContainer, true);
 
   nsCOMPtr<nsIScriptGlobalObject> globalObject =
     do_QueryInterface(aDoc->GetWindow());
 
   // Getting context is tricky if the document hasn't had its
   // GlobalObject set yet
   if (!globalObject) {
-    nsCOMPtr<nsIScriptGlobalObjectOwner> owner = do_GetInterface(aContainer);
-    NS_ENSURE_TRUE(owner, true);
-
-    globalObject = owner->GetScriptGlobalObject();
+    globalObject = aContainer->GetScriptGlobalObject();
     NS_ENSURE_TRUE(globalObject, true);
   }
 
   nsIScriptContext *scriptContext = globalObject->GetContext();
   NS_ENSURE_TRUE(scriptContext, true);
   JSContext *cx = scriptContext->GetNativeContext();
   NS_ENSURE_TRUE(cx, true);
 
--- a/content/media/webrtc/MediaEngineWebRTC.cpp
+++ b/content/media/webrtc/MediaEngineWebRTC.cpp
@@ -29,16 +29,17 @@ GetUserMediaLog()
 
 #include "MediaEngineWebRTC.h"
 #include "ImageContainer.h"
 #include "nsIComponentRegistrar.h"
 #include "MediaEngineTabVideoSource.h"
 #include "nsITabSource.h"
 
 #ifdef MOZ_WIDGET_ANDROID
+#include "AndroidJNIWrapper.h"
 #include "AndroidBridge.h"
 #endif
 
 #undef LOG
 #define LOG(args) PR_LOG(GetUserMediaLog(), PR_LOG_DEBUG, args)
 
 namespace mozilla {
 #ifndef MOZ_B2G_CAMERA
@@ -245,26 +246,22 @@ MediaEngineWebRTC::EnumerateAudioDevices
   // We spawn threads to handle gUM runnables, so we must protect the member vars
   MutexAutoLock lock(mMutex);
 
 #ifdef MOZ_WIDGET_ANDROID
   jobject context = mozilla::AndroidBridge::Bridge()->GetGlobalContextRef();
 
   // get the JVM
   JavaVM *jvm = mozilla::AndroidBridge::Bridge()->GetVM();
+  JNIEnv *env = GetJNIForThread();
 
-  JNIEnv *env;
-  jvm->AttachCurrentThread(&env, nullptr);
-
-  if (webrtc::VoiceEngine::SetAndroidObjects(jvm, (void*)context) != 0) {
+  if (webrtc::VoiceEngine::SetAndroidObjects(jvm, env, (void*)context) != 0) {
     LOG(("VoiceEngine:SetAndroidObjects Failed"));
     return;
   }
-
-  env->DeleteGlobalRef(context);
 #endif
 
   if (!mVoiceEngine) {
     mVoiceEngine = webrtc::VoiceEngine::Create();
     if (!mVoiceEngine) {
       return;
     }
   }
--- a/content/media/webrtc/MediaEngineWebRTC.h
+++ b/content/media/webrtc/MediaEngineWebRTC.h
@@ -40,17 +40,16 @@
 #include "webrtc/voice_engine/include/voe_external_media.h"
 #include "webrtc/voice_engine/include/voe_audio_processing.h"
 
 // Video Engine
 #include "webrtc/video_engine/include/vie_base.h"
 #include "webrtc/video_engine/include/vie_codec.h"
 #include "webrtc/video_engine/include/vie_render.h"
 #include "webrtc/video_engine/include/vie_capture.h"
-#include "webrtc/video_engine/include/vie_file.h"
 #ifdef MOZ_B2G_CAMERA
 #include "CameraPreviewMediaStream.h"
 #include "DOMCameraManager.h"
 #include "GonkCameraControl.h"
 #include "ImageContainer.h"
 #include "nsGlobalWindow.h"
 #include "prprf.h"
 #endif
@@ -113,17 +112,24 @@ public:
   {
     mState = kReleased;
     NS_NewNamedThread("CameraThread", getter_AddRefs(mCameraThread));
     Init();
   }
 #else
   // ViEExternalRenderer.
   virtual int FrameSizeChange(unsigned int, unsigned int, unsigned int);
-  virtual int DeliverFrame(unsigned char*, int, uint32_t, int64_t);
+  virtual int DeliverFrame(unsigned char*,int, uint32_t , int64_t,
+                           void *handle);
+  /**
+   * Does DeliverFrame() support a null buffer and non-null handle
+   * (video texture)?
+   * XXX Investigate!  Especially for Android/B2G
+   */
+  virtual bool IsTextureSupported() { return false; }
 
   MediaEngineWebRTCVideoSource(webrtc::VideoEngine* aVideoEnginePtr, int aIndex)
     : mVideoEngine(aVideoEnginePtr)
     , mCaptureIndex(aIndex)
     , mFps(-1)
     , mMinFps(-1)
     , mMonitor("WebRTCCamera.Monitor")
     , mWidth(0)
--- a/content/media/webrtc/MediaEngineWebRTCVideo.cpp
+++ b/content/media/webrtc/MediaEngineWebRTCVideo.cpp
@@ -35,17 +35,18 @@ MediaEngineWebRTCVideoSource::FrameSizeC
   mHeight = h;
   LOG(("Video FrameSizeChange: %ux%u", w, h));
   return 0;
 }
 
 // ViEExternalRenderer Callback. Process every incoming frame here.
 int
 MediaEngineWebRTCVideoSource::DeliverFrame(
-   unsigned char* buffer, int size, uint32_t time_stamp, int64_t render_time)
+   unsigned char* buffer, int size, uint32_t time_stamp, int64_t render_time,
+   void *handle)
 {
   // mInSnapshotMode can only be set before the camera is turned on and
   // the renderer is started, so this amounts to a 1-shot
   if (mInSnapshotMode) {
     // Set the condition variable to false and notify Snapshot().
     MonitorAutoLock lock(mMonitor);
     mInSnapshotMode = false;
     lock.Notify();
@@ -394,136 +395,17 @@ MediaEngineWebRTCVideoSource::Stop(Sourc
 #endif
 
   return NS_OK;
 }
 
 nsresult
 MediaEngineWebRTCVideoSource::Snapshot(uint32_t aDuration, nsIDOMFile** aFile)
 {
-  /**
-   * To get a Snapshot we do the following:
-   * - Set a condition variable (mInSnapshotMode) to true
-   * - Attach the external renderer and start the camera
-   * - Wait for the condition variable to change to false
-   *
-   * Starting the camera has the effect of invoking DeliverFrame() when
-   * the first frame arrives from the camera. We only need one frame for
-   * GetCaptureDeviceSnapshot to work, so we immediately set the condition
-   * variable to false and notify this method.
-   *
-   * This causes the current thread to continue (PR_CondWaitVar will return),
-   * at which point we can grab a snapshot, convert it to a file and
-   * return from this function after cleaning up the temporary stream object
-   * and caling Stop() on the media source.
-   */
-#ifdef MOZ_B2G_CAMERA
-  ReentrantMonitorAutoEnter sync(mCallbackMonitor);
-#endif
-  *aFile = nullptr;
-  if (!mInitDone || mState != kAllocated) {
-    return NS_ERROR_FAILURE;
-  }
-#ifdef MOZ_B2G_CAMERA
-  mLastCapture = nullptr;
-
-  NS_DispatchToMainThread(WrapRunnable(this,
-                                       &MediaEngineWebRTCVideoSource::StartImpl,
-                                       mCapability));
-  mCallbackMonitor.Wait();
-  if (mState != kStarted) {
-    return NS_ERROR_FAILURE;
-  }
-
-  NS_DispatchToMainThread(WrapRunnable(this,
-                                       &MediaEngineWebRTCVideoSource::SnapshotImpl));
-  mCallbackMonitor.Wait();
-  if (mLastCapture == nullptr)
-    return NS_ERROR_FAILURE;
-
-  mState = kStopped;
-  NS_DispatchToMainThread(WrapRunnable(this,
-                                       &MediaEngineWebRTCVideoSource::StopImpl));
-
-  // The camera return nsDOMMemoryFile indeed, and the inheritance tree is:
-  // nsIDOMBlob <- nsIDOMFile <- nsDOMFileBase <- nsDOMFile <- nsDOMMemoryFile
-  *aFile = mLastCapture.get();
-  return NS_OK;
-#else
-  {
-    MonitorAutoLock lock(mMonitor);
-    mInSnapshotMode = true;
-  }
-
-  // Start the rendering (equivalent to calling Start(), but without a track).
-  int error = 0;
-  if (!mInitDone || mState != kAllocated) {
-    return NS_ERROR_FAILURE;
-  }
-  error = mViERender->AddRenderer(mCaptureIndex, webrtc::kVideoI420, (webrtc::ExternalRenderer*)this);
-  if (error == -1) {
-    return NS_ERROR_FAILURE;
-  }
-  error = mViERender->StartRender(mCaptureIndex);
-  if (error == -1) {
-    return NS_ERROR_FAILURE;
-  }
-
-  if (mViECapture->StartCapture(mCaptureIndex, mCapability) < 0) {
-    return NS_ERROR_FAILURE;
-  }
-
-  // Wait for the condition variable, will be set in DeliverFrame.
-  // We use a while loop, because even if Wait() returns, it's not
-  // guaranteed that the condition variable changed.
-  // FIX: we need need a way to cancel this and to bail if it appears to not be working
-  // Perhaps a maximum time, though some cameras can take seconds to start.  10 seconds?
-  {
-    MonitorAutoLock lock(mMonitor);
-    while (mInSnapshotMode) {
-      lock.Wait();
-    }
-  }
-
-  // If we get here, DeliverFrame received at least one frame.
-  webrtc::ViEFile* vieFile = webrtc::ViEFile::GetInterface(mVideoEngine);
-  if (!vieFile) {
-    return NS_ERROR_FAILURE;
-  }
-
-  // Create a temporary file on the main thread and put the snapshot in it.
-  // See Run() in MediaEngineWebRTCVideo.h (sets mSnapshotPath).
-  NS_DispatchToMainThread(this, NS_DISPATCH_SYNC);
-
-  if (!mSnapshotPath) {
-    return NS_ERROR_FAILURE;
-  }
-
-  NS_ConvertUTF16toUTF8 path(*mSnapshotPath);
-  if (vieFile->GetCaptureDeviceSnapshot(mCaptureIndex, path.get()) < 0) {
-    delete mSnapshotPath;
-    mSnapshotPath = nullptr;
-    return NS_ERROR_FAILURE;
-  }
-
-  // Stop the camera.
-  mViERender->StopRender(mCaptureIndex);
-  mViERender->RemoveRenderer(mCaptureIndex);
-
-  nsCOMPtr<nsIFile> file;
-  nsresult rv = NS_NewLocalFile(*mSnapshotPath, false, getter_AddRefs(file));
-
-  delete mSnapshotPath;
-  mSnapshotPath = nullptr;
-
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  NS_ADDREF(*aFile = new nsDOMFileFile(file));
-#endif
-  return NS_OK;
+  return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 /**
  * Initialization and Shutdown functions for the video source, called by the
  * constructor and destructor respectively.
  */
 
 void
--- a/content/xml/document/src/XMLDocument.cpp
+++ b/content/xml/document/src/XMLDocument.cpp
@@ -35,17 +35,16 @@
 #include "nsCExternalHandlerService.h"
 #include "nsMimeTypes.h"
 #include "nsEventListenerManager.h"
 #include "nsContentUtils.h"
 #include "nsThreadUtils.h"
 #include "nsJSUtils.h"
 #include "nsCRT.h"
 #include "nsIAuthPrompt.h"
-#include "nsIScriptGlobalObjectOwner.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsContentPolicyUtils.h"
 #include "nsIDOMUserDataHandler.h"
 #include "nsEventDispatcher.h"
 #include "nsNodeUtils.h"
 #include "nsIConsoleService.h"
 #include "nsIScriptError.h"
 #include "nsIHTMLDocument.h"
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -893,17 +893,16 @@ NS_INTERFACE_MAP_BEGIN(nsDocShell)
     NS_INTERFACE_MAP_ENTRY(nsIDocShell)
     NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeItem)
     NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeNode)
     NS_INTERFACE_MAP_ENTRY(nsIWebNavigation)
     NS_INTERFACE_MAP_ENTRY(nsIBaseWindow)
     NS_INTERFACE_MAP_ENTRY(nsIScrollable)
     NS_INTERFACE_MAP_ENTRY(nsITextScroll)
     NS_INTERFACE_MAP_ENTRY(nsIDocCharset)
-    NS_INTERFACE_MAP_ENTRY(nsIScriptGlobalObjectOwner)
     NS_INTERFACE_MAP_ENTRY(nsIRefreshURI)
     NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener)
     NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
     NS_INTERFACE_MAP_ENTRY(nsIContentViewerContainer)
     NS_INTERFACE_MAP_ENTRY(nsIWebPageDescriptor)
     NS_INTERFACE_MAP_ENTRY(nsIAuthPromptProvider)
     NS_INTERFACE_MAP_ENTRY(nsILoadContext)
     NS_INTERFACE_MAP_ENTRY(nsIWebShellServices)
@@ -3916,16 +3915,23 @@ nsDocShell::GetCurrentSHEntry(nsISHEntry
         NS_ADDREF(*aEntry = mLSHE);
     } else if (mOSHE) {
         NS_ADDREF(*aEntry = mOSHE);
         *aOSHE = true;
     }
     return NS_OK;
 }
 
+nsIScriptGlobalObject*
+nsDocShell::GetScriptGlobalObject()
+{
+    NS_ENSURE_SUCCESS(EnsureScriptEnvironment(), nullptr);
+    return mScriptGlobal;
+}
+
 NS_IMETHODIMP
 nsDocShell::SetDeviceSizeIsPageSize(bool aValue)
 {
     if (mDeviceSizeIsPageSize != aValue) {
       mDeviceSizeIsPageSize = aValue;
       nsRefPtr<nsPresContext> presContext;
       GetPresContext(getter_AddRefs(presContext));
       if (presContext) {
@@ -5840,27 +5846,16 @@ nsDocShell::ScrollByPages(int32_t numPag
     NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE);
 
     sf->ScrollBy(nsIntPoint(0, numPages), nsIScrollableFrame::PAGES,
                  nsIScrollableFrame::SMOOTH);
     return NS_OK;
 }
 
 //*****************************************************************************
-// nsDocShell::nsIScriptGlobalObjectOwner
-//*****************************************************************************   
-
-nsIScriptGlobalObject*
-nsDocShell::GetScriptGlobalObject()
-{
-    NS_ENSURE_SUCCESS(EnsureScriptEnvironment(), nullptr);
-    return mScriptGlobal;
-}
-
-//*****************************************************************************
 // nsDocShell::nsIRefreshURI
 //*****************************************************************************   
 
 NS_IMETHODIMP
 nsDocShell::RefreshURI(nsIURI * aURI, int32_t aDelay, bool aRepeat,
                        bool aMetaRefresh)
 {
     NS_ENSURE_ARG(aURI);
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -28,17 +28,16 @@
 
 // Threshold value in ms for META refresh based redirects
 #define REFRESH_REDIRECT_TIMER 15000
 
 // Interfaces Needed
 #include "nsIDocCharset.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIRefreshURI.h"
-#include "nsIScriptGlobalObjectOwner.h"
 #include "nsIWebNavigation.h"
 #include "nsIWebPageDescriptor.h"
 #include "nsIWebProgressListener.h"
 #include "nsIDocShellLoadInfo.h"
 #include "nsIAuthPromptProvider.h"
 #include "nsILoadContext.h"
 #include "nsIWebShellServices.h"
 #include "nsILinkHandler.h"
@@ -125,17 +124,16 @@ typedef enum {
 class nsDocShell : public nsDocLoader,
                    public nsIDocShell,
                    public nsIWebNavigation,
                    public nsIBaseWindow, 
                    public nsIScrollable, 
                    public nsITextScroll, 
                    public nsIDocCharset, 
                    public nsIContentViewerContainer,
-                   public nsIScriptGlobalObjectOwner,
                    public nsIRefreshURI,
                    public nsIWebProgressListener,
                    public nsIWebPageDescriptor,
                    public nsIAuthPromptProvider,
                    public nsILoadContext,
                    public nsIWebShellServices,
                    public nsILinkHandler,
                    public nsIClipboardCommands,
@@ -200,19 +198,16 @@ public:
     NS_IMETHOD OnOverLink(nsIContent* aContent,
         nsIURI* aURI,
         const PRUnichar* aTargetSpec);
     NS_IMETHOD OnLeaveLink();
 
     nsDocShellInfoLoadType ConvertLoadTypeToDocShellLoadInfo(uint32_t aLoadType);
     uint32_t ConvertDocShellLoadInfoToLoadType(nsDocShellInfoLoadType aDocShellLoadType);
 
-    // nsIScriptGlobalObjectOwner methods
-    virtual nsIScriptGlobalObject* GetScriptGlobalObject();
-
     // Don't use NS_DECL_NSILOADCONTEXT because some of nsILoadContext's methods
     // are shared with nsIDocShell (appID, etc.) and can't be declared twice.
     NS_IMETHOD GetAssociatedWindow(nsIDOMWindow**);
     NS_IMETHOD GetTopWindow(nsIDOMWindow**);
     NS_IMETHOD GetTopFrameElement(nsIDOMElement**);
     NS_IMETHOD IsAppOfType(uint32_t, bool*);
     NS_IMETHOD GetIsContent(bool*);
     NS_IMETHOD GetUsePrivateBrowsing(bool*);
--- a/docshell/base/nsIDocShell.idl
+++ b/docshell/base/nsIDocShell.idl
@@ -29,26 +29,27 @@ interface nsIDocShellLoadInfo;
 interface nsIEditor;
 interface nsIWebNavigation;
 interface nsISimpleEnumerator;
 interface nsIInputStream;
 interface nsIRequest;
 interface nsISHEntry;
 interface nsILayoutHistoryState;
 interface nsISecureBrowserUI;
+interface nsIScriptGlobalObject;
 interface nsIDOMStorage;
 interface nsIPrincipal;
 interface nsIWebBrowserPrint;
 interface nsIVariant;
 interface nsIPrivacyTransitionObserver;
 interface nsIReflowObserver;
 
 typedef unsigned long nsLoadFlags;
 
-[scriptable, builtinclass, uuid(77aca3ee-7417-4cd2-994e-9bd95ca1d98a)]
+[scriptable, builtinclass, uuid(55ca6545-7ce4-49ad-8117-8286ca9c61bb)]
 interface nsIDocShell : nsIDocShellTreeItem
 {
   /**
    * Loads a given URI.  This will give priority to loading the requested URI
    * in the object implementing	this interface.  If it can't be loaded here
    * however, the URL dispatcher will go through its normal process of content
    * loading.
    *
@@ -903,16 +904,21 @@ interface nsIDocShell : nsIDocShellTreeI
   /**
    * Invisible DocShell are dummy construct to simulate DOM windows
    * without any actual visual representation. They have to be marked
    * at construction time, to avoid any painting activity.
    */
   [noscript, notxpcom] bool IsInvisible();
   [noscript, notxpcom] void SetInvisible(in bool aIsInvisibleDochsell);
 
+/**
+ * Get the script global for the document in this docshell.
+*/
+  [noscript,notxpcom,nostdcall] nsIScriptGlobalObject GetScriptGlobalObject();
+
   /**
    * If deviceSizeIsPageSize is set to true, device-width/height media queries
    * will be calculated from the page size, not the device size.
    *
    * Used by the Responsive Design View and B2G Simulator.
    *
    * Default is False.
    * Default value can be overriden with
--- a/dom/base/moz.build
+++ b/dom/base/moz.build
@@ -29,17 +29,16 @@ EXPORTS += [
     'nsIDOMClassInfo.h',
     'nsIDOMScriptObjectFactory.h',
     'nsIGlobalObject.h',
     'nsIJSEventListener.h',
     'nsIJSNativeInitializer.h',
     'nsIScriptContext.h',
     'nsIScriptExternalNameSet.h',
     'nsIScriptGlobalObject.h',
-    'nsIScriptGlobalObjectOwner.h',
     'nsIScriptNameSpaceManager.h',
     'nsIScriptObjectPrincipal.h',
     'nsIScriptTimeoutHandler.h',
     'nsJSEnvironment.h',
     'nsJSUtils.h',
     'nsPerformance.h',
     'nsPIDOMWindow.h',
     'nsPIWindowRoot.h',
deleted file mode 100644
--- a/dom/base/nsIScriptGlobalObjectOwner.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* 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 nsIScriptGlobalObjectOwner_h__
-#define nsIScriptGlobalObjectOwner_h__
-
-#include "nsISupports.h"
-
-class nsIScriptGlobalObject;
-
-#define NS_ISCRIPTGLOBALOBJECTOWNER_IID \
-  {0xfd25ca8e, 0x6b63, 0x435f, \
-    { 0xb8, 0xc6, 0xb8, 0x07, 0x68, 0xa4, 0x0a, 0xdc }}
-
-/**
- * Implemented by any object capable of supplying a nsIScriptGlobalObject.
- * The implentor may create the script global object on demand.
- */
-
-class nsIScriptGlobalObjectOwner : public nsISupports
-{
-public:
-  NS_DECLARE_STATIC_IID_ACCESSOR(NS_ISCRIPTGLOBALOBJECTOWNER_IID)
-
-  /**
-   * Returns the script global object
-   */
-  virtual nsIScriptGlobalObject* GetScriptGlobalObject() = 0;
-};
-
-NS_DEFINE_STATIC_IID_ACCESSOR(nsIScriptGlobalObjectOwner,
-                              NS_ISCRIPTGLOBALOBJECTOWNER_IID)
-
-#endif /* nsIScriptGlobalObjectOwner_h__ */
--- a/dom/bluetooth/BluetoothA2dpManager.cpp
+++ b/dom/bluetooth/BluetoothA2dpManager.cpp
@@ -92,29 +92,28 @@ BluetoothA2dpManager::ResetAvrcp()
   mTotalMediaCount = 0;
   mPosition = 0;
   mPlayStatus = ControlPlayStatus::PLAYSTATUS_UNKNOWN;
 }
 
 static BluetoothA2dpManager::SinkState
 StatusStringToSinkState(const nsAString& aStatus)
 {
-  BluetoothA2dpManager::SinkState state;
+  BluetoothA2dpManager::SinkState state =
+    BluetoothA2dpManager::SinkState::SINK_UNKNOWN;
   if (aStatus.EqualsLiteral("disconnected")) {
     state = BluetoothA2dpManager::SinkState::SINK_DISCONNECTED;
   } else if (aStatus.EqualsLiteral("connecting")) {
     state = BluetoothA2dpManager::SinkState::SINK_CONNECTING;
   } else if (aStatus.EqualsLiteral("connected")) {
     state = BluetoothA2dpManager::SinkState::SINK_CONNECTED;
   } else if (aStatus.EqualsLiteral("playing")) {
     state = BluetoothA2dpManager::SinkState::SINK_PLAYING;
-  } else if (aStatus.EqualsLiteral("disconnecting")) {
-    state = BluetoothA2dpManager::SinkState::SINK_DISCONNECTING;
   } else {
-    MOZ_ASSERT(false, "Unknown sink state");
+    BT_WARNING("Unknown sink state");
   }
   return state;
 }
 
 //static
 BluetoothA2dpManager*
 BluetoothA2dpManager::Get()
 {
@@ -223,35 +222,31 @@ BluetoothA2dpManager::OnDisconnect(const
   NS_ENSURE_TRUE_VOID(mController);
 
   nsRefPtr<BluetoothProfileController> controller = mController.forget();
   controller->OnDisconnect(aErrorStr);
 }
 
 /* HandleSinkPropertyChanged update sink state in A2dp
  *
- * Possible values: "disconnected", "disconnecting",
- *                  "connecting", "connected",
- *                  "playing"
+ * Possible values: "disconnected", "connecting", "connected", "playing"
  *
  * 1. "disconnected" -> "connecting"
  *    Either an incoming or outgoing connection attempt ongoing
  * 2. "connecting" -> "disconnected"
  *    Connection attempt failed
  * 3. "connecting" -> "connected"
  *    Successfully connected
  * 4. "connected" -> "playing"
  *    Audio stream active
  * 5. "playing" -> "connected"
  *    Audio stream suspended
  * 6. "connected" -> "disconnected"
  *    "playing" -> "disconnected"
- *    Disconnected from the remote device
- * 7. "disconnecting" -> "disconnected"
- *    Disconnected from local
+ *    Disconnected from local or the remote device
  */
 void
 BluetoothA2dpManager::HandleSinkPropertyChanged(const BluetoothSignal& aSignal)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aSignal.value().type() == BluetoothValue::TArrayOfBluetoothNamedValue);
 
   const nsString& address = aSignal.path();
@@ -268,20 +263,22 @@ BluetoothA2dpManager::HandleSinkProperty
    * Note that only "State" is handled in this function.
    */
 
   const nsString& name = arr[0].name();
   NS_ENSURE_TRUE_VOID(name.EqualsLiteral("State"));
 
   const BluetoothValue& value = arr[0].value();
   MOZ_ASSERT(value.type() == BluetoothValue::TnsString);
+  SinkState newState = StatusStringToSinkState(value.get_nsString());
+  NS_ENSURE_TRUE_VOID((newState != SinkState::SINK_UNKNOWN) &&
+                      (newState != mSinkState));
+
   SinkState prevState = mSinkState;
-  mSinkState = StatusStringToSinkState(value.get_nsString());
-
-  NS_ENSURE_TRUE_VOID(mSinkState != prevState);
+  mSinkState = newState;
 
   switch(mSinkState) {
     case SinkState::SINK_CONNECTING:
       // case 1: Either an incoming or outgoing connection attempt ongoing
       MOZ_ASSERT(prevState == SinkState::SINK_DISCONNECTED);
       break;
     case SinkState::SINK_PLAYING:
       // case 4: Audio stream active
@@ -298,37 +295,30 @@ BluetoothA2dpManager::HandleSinkProperty
 
       mA2dpConnected = true;
       mDeviceAddress = address;
       NotifyConnectionStatusChanged();
 
       OnConnect(EmptyString());
       break;
     case SinkState::SINK_DISCONNECTED:
-      // XXX
       // case 2: Connection attempt failed
-      if (prevState == SinkState::SINK_CONNECTING) {  
+      if (prevState == SinkState::SINK_CONNECTING) {
         OnConnect(NS_LITERAL_STRING("A2dpConnectionError"));
         break;
       }
-      
+
       // case 6: Disconnected from the remote device
-      // case 7: Disconnected from local
       MOZ_ASSERT(prevState == SinkState::SINK_CONNECTED ||
-                 prevState == SinkState::SINK_PLAYING ||
-                 prevState == SinkState::SINK_DISCONNECTING);
-  
+                 prevState == SinkState::SINK_PLAYING) ;
+
       mA2dpConnected = false;
       NotifyConnectionStatusChanged();
       mDeviceAddress.Truncate();
-
-      // case 7 only
-      if (prevState == SinkState::SINK_DISCONNECTING) {
-        OnDisconnect(EmptyString());
-      }
+      OnDisconnect(EmptyString());
       break;
     default:
       break;
   }
 }
 
 void
 BluetoothA2dpManager::NotifyConnectionStatusChanged()
--- a/dom/bluetooth/BluetoothA2dpManager.h
+++ b/dom/bluetooth/BluetoothA2dpManager.h
@@ -15,21 +15,21 @@ BEGIN_BLUETOOTH_NAMESPACE
 
 class BluetoothA2dpManager : public BluetoothProfileManagerBase
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIOBSERVER
 
   enum SinkState {
-    SINK_DISCONNECTED = 1,
+    SINK_UNKNOWN,
+    SINK_DISCONNECTED,
     SINK_CONNECTING,
     SINK_CONNECTED,
     SINK_PLAYING,
-    SINK_DISCONNECTING
   };
 
   static BluetoothA2dpManager* Get();
   ~BluetoothA2dpManager();
   void ResetA2dp();
   void ResetAvrcp();
 
   // The following functions are inherited from BluetoothProfileManagerBase
--- a/dom/browser-element/BrowserElementChild.js
+++ b/dom/browser-element/BrowserElementChild.js
@@ -19,24 +19,19 @@ docShell.isActive = true;
 
 let infos = sendSyncMessage('browser-element-api:call',
                             { 'msg_name': 'hello' })[0];
 docShell.QueryInterface(Ci.nsIDocShellTreeItem).name = infos.name;
 docShell.setFullscreenAllowed(infos.fullscreenAllowed);
 
 
 if (!('BrowserElementIsPreloaded' in this)) {
-  try {
-    if (Services.prefs.getBoolPref("dom.mozInputMethod.enabled")) {
-      Services.scriptloader.loadSubScript("chrome://global/content/forms.js", global);
-    }
-  } catch (e) {
-  }
   // Those are produc-specific files that's sometimes unavailable.
   try {
+    Services.scriptloader.loadSubScript("chrome://browser/content/forms.js");
     Services.scriptloader.loadSubScript("chrome://browser/content/ErrorPage.js");
   } catch (e) {
   }
   Services.scriptloader.loadSubScript("chrome://global/content/BrowserElementPanning.js");
   Services.scriptloader.loadSubScript("chrome://global/content/BrowserElementChildPreload.js");
 }
 
 var BrowserElementIsReady = true;
--- a/dom/inputmethod/Keyboard.jsm
+++ b/dom/inputmethod/Keyboard.jsm
@@ -4,17 +4,17 @@
 
 'use strict';
 
 this.EXPORTED_SYMBOLS = ['Keyboard'];
 
 const Cu = Components.utils;
 const Cc = Components.classes;
 const Ci = Components.interfaces;
-const kFormsFrameScript = 'chrome://global/content/forms.js';
+const kFormsFrameScript = 'chrome://browser/content/forms.js';
 
 Cu.import('resource://gre/modules/Services.jsm');
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
   "@mozilla.org/parentprocessmessagemanager;1", "nsIMessageBroadcaster");
 
 this.Keyboard = {
@@ -59,41 +59,37 @@ this.Keyboard = {
 
     if (topic == 'oop-frameloader-crashed') {
       if (this.messageManager == mm) {
         // The application has been closed unexpectingly. Let's tell the
         // keyboard app that the focus has been lost.
         ppmm.broadcastAsyncMessage('Keyboard:FocusChange', { 'type': 'blur' });
       }
     } else {
-      this.initFormsFrameScript(mm);
-    }
-  },
+      mm.addMessageListener('Forms:Input', this);
+      mm.addMessageListener('Forms:SelectionChange', this);
+      mm.addMessageListener('Forms:GetText:Result:OK', this);
+      mm.addMessageListener('Forms:GetText:Result:Error', this);
+      mm.addMessageListener('Forms:SetSelectionRange:Result:OK', this);
+      mm.addMessageListener('Forms:ReplaceSurroundingText:Result:OK', this);
+      mm.addMessageListener('Forms:SendKey:Result:OK', this);
+      mm.addMessageListener('Forms:SequenceError', this);
+      mm.addMessageListener('Forms:GetContext:Result:OK', this);
+      mm.addMessageListener('Forms:SetComposition:Result:OK', this);
+      mm.addMessageListener('Forms:EndComposition:Result:OK', this);
 
-  initFormsFrameScript: function(mm) {
-    mm.addMessageListener('Forms:Input', this);
-    mm.addMessageListener('Forms:SelectionChange', this);
-    mm.addMessageListener('Forms:GetText:Result:OK', this);
-    mm.addMessageListener('Forms:GetText:Result:Error', this);
-    mm.addMessageListener('Forms:SetSelectionRange:Result:OK', this);
-    mm.addMessageListener('Forms:ReplaceSurroundingText:Result:OK', this);
-    mm.addMessageListener('Forms:SendKey:Result:OK', this);
-    mm.addMessageListener('Forms:SequenceError', this);
-    mm.addMessageListener('Forms:GetContext:Result:OK', this);
-    mm.addMessageListener('Forms:SetComposition:Result:OK', this);
-    mm.addMessageListener('Forms:EndComposition:Result:OK', this);
-
-    // When not running apps OOP, we need to load forms.js here since this
-    // won't happen from dom/ipc/preload.js
-    try {
-      if (Services.prefs.getBoolPref("dom.ipc.tabs.disabled") === true) {
-        mm.loadFrameScript(kFormsFrameScript, true);
+      // When not running apps OOP, we need to load forms.js here since this
+      // won't happen from dom/ipc/preload.js
+      try {
+         if (Services.prefs.getBoolPref("dom.ipc.tabs.disabled") === true) {
+           mm.loadFrameScript(kFormsFrameScript, true);
+        }
+      } catch (e) {
+         dump('Error loading ' + kFormsFrameScript + ' as frame script: ' + e + '\n');
       }
-    } catch (e) {
-      dump('Error loading ' + kFormsFrameScript + ' as frame script: ' + e + '\n');
     }
   },
 
   receiveMessage: function keyboardReceiveMessage(msg) {
     // If we get a 'Keyboard:XXX' message, check that the sender has the
     // input permission.
     if (msg.name.indexOf("Keyboard:") != -1) {
       if (!this.messageManager) {
deleted file mode 100644
--- a/dom/inputmethod/jar.mn
+++ /dev/null
@@ -1,6 +0,0 @@
-# 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/.
-
-toolkit.jar:
-  content/global/forms.js                      (forms.js)
--- a/dom/ipc/preload.js
+++ b/dom/ipc/preload.js
@@ -82,25 +82,19 @@ const BrowserElementIsPreloaded = true;
 
   try {
     if (Services.prefs.getBoolPref("dom.sysmsg.enabled")) {
       Cc["@mozilla.org/system-message-manager;1"].getService(Ci["nsIDOMNavigatorSystemMessages"]);
     }
   } catch(e) {
   }
 
-  try {
-    if (Services.prefs.getBoolPref("dom.mozInputMethod.enabled")) {
-      Services.scriptloader.loadSubScript("chrome://global/content/forms.js", global);
-    }
-  } catch (e) {
-  }
-
   // Those are produc-specific files that's sometimes unavailable.
   try {
+    Services.scriptloader.loadSubScript("chrome://browser/content/forms.js", global);
     Services.scriptloader.loadSubScript("chrome://browser/content/ErrorPage.js", global);
   } catch (e) {
   }
   Services.scriptloader.loadSubScript("chrome://global/content/BrowserElementPanning.js", global);
   Services.scriptloader.loadSubScript("chrome://global/content/BrowserElementChildPreload.js", global);
 
   Services.io.getProtocolHandler("app");
   Services.io.getProtocolHandler("default");
--- a/dom/plugins/ipc/interpose/plugin_child_interpose.mm
+++ b/dom/plugins/ipc/interpose/plugin_child_interpose.mm
@@ -32,17 +32,17 @@
 
 // The header file QuickdrawAPI.h is missing on OS X 10.7 and up (though the
 // QuickDraw APIs defined in it are still present) -- so we need to supply the
 // relevant parts of its contents here.  It's likely that Apple will eventually
 // remove the APIs themselves (probably in OS X 10.8), so we need to make them
 // weak imports, and test for their presence before using them.
 #if !defined(__QUICKDRAWAPI__)
 
-typedef struct Cursor;
+struct Cursor;
 extern "C" void SetCursor(const Cursor * crsr) __attribute__((weak_import));
 
 #endif /* __QUICKDRAWAPI__ */
 
 BOOL (*OnSetThemeCursorPtr) (ThemeCursor) = NULL;
 BOOL (*OnSetCursorPtr) (const Cursor*) = NULL;
 BOOL (*OnHideCursorPtr) () = NULL;
 BOOL (*OnShowCursorPtr) () = NULL;
--- a/dom/src/jsurl/nsJSProtocolHandler.cpp
+++ b/dom/src/jsurl/nsJSProtocolHandler.cpp
@@ -16,17 +16,16 @@
 #include "nsStringStream.h"
 #include "nsNetUtil.h"
 
 #include "nsIComponentManager.h"
 #include "nsIServiceManager.h"
 #include "nsIURI.h"
 #include "nsIScriptContext.h"
 #include "nsIScriptGlobalObject.h"
-#include "nsIScriptGlobalObjectOwner.h"
 #include "nsIPrincipal.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIWindowMediator.h"
 #include "nsPIDOMWindow.h"
 #include "nsIConsoleService.h"
 #include "nsXPIDLString.h"
@@ -114,32 +113,29 @@ IsISO88591(const nsString& aString)
     }
     return true;
 }
 
 static
 nsIScriptGlobalObject* GetGlobalObject(nsIChannel* aChannel)
 {
     // Get the global object owner from the channel
-    nsCOMPtr<nsIScriptGlobalObjectOwner> globalOwner;
-    NS_QueryNotificationCallbacks(aChannel, globalOwner);
-    if (!globalOwner) {
-        NS_WARNING("Unable to get an nsIScriptGlobalObjectOwner from the "
-                   "channel!");
-    }
-    if (!globalOwner) {
+    nsCOMPtr<nsIDocShell> docShell;
+    NS_QueryNotificationCallbacks(aChannel, docShell);
+    if (!docShell) {
+        NS_WARNING("Unable to get a docShell from the channel!");
         return nullptr;
     }
 
-    // So far so good: get the script context from its owner.
-    nsIScriptGlobalObject* global = globalOwner->GetScriptGlobalObject();
+    // So far so good: get the script global from its docshell
+    nsIScriptGlobalObject* global = docShell->GetScriptGlobalObject();
 
     NS_ASSERTION(global,
                  "Unable to get an nsIScriptGlobalObject from the "
-                 "ScriptGlobalObjectOwner!");
+                 "docShell!");
     return global;
 }
 
 nsresult nsJSThunk::EvaluateScript(nsIChannel *aChannel,
                                    PopupControlState aPopupState,
                                    uint32_t aExecutionPolicy,
                                    nsPIDOMWindow *aOriginalInnerWindow)
 {
--- a/dom/system/gonk/AutoMounterSetting.cpp
+++ b/dom/system/gonk/AutoMounterSetting.cpp
@@ -186,17 +186,20 @@ public:
   NS_IMETHOD Run()
   {
     MOZ_ASSERT(NS_IsMainThread());
     nsCOMPtr<nsISettingsService> settingsService =
       do_GetService("@mozilla.org/settingsService;1");
     NS_ENSURE_TRUE(settingsService, NS_ERROR_FAILURE);
     nsCOMPtr<nsISettingsServiceLock> lock;
     settingsService->CreateLock(getter_AddRefs(lock));
-    lock->Set(UMS_STATUS, INT_TO_JSVAL(mStatus), nullptr, nullptr);
+    // lock may be null if this gets called during shutdown.
+    if (lock) {
+      lock->Set(UMS_STATUS, INT_TO_JSVAL(mStatus), nullptr, nullptr);
+    }
     return NS_OK;
   }
 
 private:
   int32_t mStatus;
 };
 
 //static
--- a/gfx/2d/DrawTargetCG.cpp
+++ b/gfx/2d/DrawTargetCG.cpp
@@ -5,17 +5,17 @@
 #include "BorrowedContext.h"
 #include "DrawTargetCG.h"
 #include "SourceSurfaceCG.h"
 #include "Rect.h"
 #include "ScaledFontMac.h"
 #include "Tools.h"
 #include <vector>
 #include <algorithm>
-#include "QuartzSupport.h"
+#include "MacIOSurface.h"
 
 using namespace std;
 
 //CG_EXTERN void CGContextSetCompositeOperation (CGContextRef, PrivateCGCompositeMode);
 
 // A private API that Cairo has been using for a long time
 CG_EXTERN void CGContextSetCTM(CGContextRef, CGAffineTransform);
 
--- a/gfx/2d/DrawTargetCG.h
+++ b/gfx/2d/DrawTargetCG.h
@@ -32,16 +32,22 @@ static inline Rect
 CGRectToRect(CGRect rect)
 {
   return Rect(rect.origin.x,
               rect.origin.y,
               rect.size.width,
               rect.size.height);
 }
 
+static inline Point
+CGPointToPoint(CGPoint point)
+{
+  return Point(point.x, point.y);
+}
+
 static inline void
 SetStrokeOptions(CGContextRef cg, const StrokeOptions &aStrokeOptions)
 {
   switch (aStrokeOptions.mLineCap)
   {
     case CAP_BUTT:
       CGContextSetLineCap(cg, kCGLineCapButt);
       break;
--- a/gfx/2d/DrawTargetCairo.cpp
+++ b/gfx/2d/DrawTargetCairo.cpp
@@ -719,24 +719,29 @@ DrawTargetCairo::CopySurfaceInternal(cai
 void
 DrawTargetCairo::CopySurface(SourceSurface *aSurface,
                              const IntRect &aSource,
                              const IntPoint &aDest)
 {
   AutoPrepareForDrawing prep(this, mContext);
   AutoClearDeviceOffset clear(aSurface);
 
-  if (!aSurface || aSurface->GetType() != SURFACE_CAIRO) {
+  if (!aSurface) {
     gfxWarning() << "Unsupported surface type specified";
     return;
   }
 
-  cairo_surface_t* surf = static_cast<SourceSurfaceCairo*>(aSurface)->GetSurface();
+  cairo_surface_t* surf = GetCairoSurfaceForSourceSurface(aSurface);
+  if (!surf) {
+    gfxWarning() << "Unsupported surface type specified";
+    return;
+  }
 
   CopySurfaceInternal(surf, aSource, aDest);
+  cairo_surface_destroy(surf);
 }
 
 void
 DrawTargetCairo::CopyRect(const IntRect &aSource,
                           const IntPoint &aDest)
 {
   AutoPrepareForDrawing prep(this, mContext);
 
--- a/gfx/2d/DrawTargetD2D.cpp
+++ b/gfx/2d/DrawTargetD2D.cpp
@@ -758,36 +758,17 @@ DrawTargetD2D::CopySurface(SourceSurface
                Float(aSourceRect.width), Float(aSourceRect.height));
 
   mRT->SetTransform(D2D1::IdentityMatrix());
   mTransformDirty = true;
   mRT->PushAxisAlignedClip(D2DRect(dstRect), D2D1_ANTIALIAS_MODE_ALIASED);
   mRT->Clear(D2D1::ColorF(0, 0.0f));
   mRT->PopAxisAlignedClip();
 
-  RefPtr<ID2D1Bitmap> bitmap;
-
-  switch (aSurface->GetType()) {
-  case SURFACE_D2D1_BITMAP:
-    {
-      SourceSurfaceD2D *srcSurf = static_cast<SourceSurfaceD2D*>(aSurface);
-      bitmap = srcSurf->GetBitmap();
-    }
-    break;
-  case SURFACE_D2D1_DRAWTARGET:
-    {
-      SourceSurfaceD2DTarget *srcSurf = static_cast<SourceSurfaceD2DTarget*>(aSurface);
-      bitmap = srcSurf->GetBitmap(mRT);
-      AddDependencyOnSource(srcSurf);
-    }
-    break;
-  default:
-    return;
-  }
-
+  RefPtr<ID2D1Bitmap> bitmap = GetBitmapForSurface(aSurface, srcRect);
   if (!bitmap) {
     return;
   }
 
   mRT->DrawBitmap(bitmap, D2DRect(dstRect), 1.0f,
                   D2D1_BITMAP_INTERPOLATION_MODE_LINEAR,
                   D2DRect(srcRect));
 }
new file mode 100644
--- /dev/null
+++ b/gfx/2d/MacIOSurface.cpp
@@ -0,0 +1,419 @@
+#include "MacIOSurface.h"
+#include <QuartzCore/QuartzCore.h>
+#include <dlfcn.h>
+#include "mozilla/RefPtr.h"
+#include "mozilla/Assertions.h"
+
+using namespace mozilla;
+// IOSurface signatures
+#define IOSURFACE_FRAMEWORK_PATH \
+  "/System/Library/Frameworks/IOSurface.framework/IOSurface"
+#define OPENGL_FRAMEWORK_PATH \
+  "/System/Library/Frameworks/OpenGL.framework/OpenGL"
+#define COREGRAPHICS_FRAMEWORK_PATH \
+  "/System/Library/Frameworks/ApplicationServices.framework/Frameworks/CoreGraphics.framework/CoreGraphics"
+
+
+
+#define GET_CONST(const_name) \
+  ((CFStringRef*) dlsym(sIOSurfaceFramework, const_name))
+#define GET_IOSYM(dest,sym_name) \
+  (typeof(dest)) dlsym(sIOSurfaceFramework, sym_name)
+#define GET_CGLSYM(dest,sym_name) \
+  (typeof(dest)) dlsym(sOpenGLFramework, sym_name)
+#define GET_CGSYM(dest,sym_name) \
+  (typeof(dest)) dlsym(sCoreGraphicsFramework, sym_name)
+
+MacIOSurfaceLib::LibraryUnloader MacIOSurfaceLib::sLibraryUnloader;
+bool                          MacIOSurfaceLib::isLoaded = false;
+void*                         MacIOSurfaceLib::sIOSurfaceFramework;
+void*                         MacIOSurfaceLib::sOpenGLFramework;
+void*                         MacIOSurfaceLib::sCoreGraphicsFramework;
+IOSurfaceCreateFunc           MacIOSurfaceLib::sCreate;
+IOSurfaceGetIDFunc            MacIOSurfaceLib::sGetID;
+IOSurfaceLookupFunc           MacIOSurfaceLib::sLookup;
+IOSurfaceGetBaseAddressFunc   MacIOSurfaceLib::sGetBaseAddress;
+IOSurfaceGetWidthFunc         MacIOSurfaceLib::sWidth;
+IOSurfaceGetHeightFunc        MacIOSurfaceLib::sHeight;
+IOSurfaceGetBytesPerRowFunc   MacIOSurfaceLib::sBytesPerRow;
+IOSurfaceLockFunc             MacIOSurfaceLib::sLock;
+IOSurfaceUnlockFunc           MacIOSurfaceLib::sUnlock;
+CGLTexImageIOSurface2DFunc    MacIOSurfaceLib::sTexImage;
+IOSurfaceContextCreateFunc    MacIOSurfaceLib::sIOSurfaceContextCreate;
+IOSurfaceContextCreateImageFunc   MacIOSurfaceLib::sIOSurfaceContextCreateImage;
+IOSurfaceContextGetSurfaceFunc    MacIOSurfaceLib::sIOSurfaceContextGetSurface;
+unsigned int                  (*MacIOSurfaceLib::sCGContextGetTypePtr) (CGContextRef) = nullptr;
+
+CFStringRef                   MacIOSurfaceLib::kPropWidth;
+CFStringRef                   MacIOSurfaceLib::kPropHeight;
+CFStringRef                   MacIOSurfaceLib::kPropBytesPerElem;
+CFStringRef                   MacIOSurfaceLib::kPropBytesPerRow;
+CFStringRef                   MacIOSurfaceLib::kPropIsGlobal;
+
+bool MacIOSurfaceLib::isInit() {
+  // Guard against trying to reload the library
+  // if it is not available.
+  if (!isLoaded)
+    LoadLibrary();
+  MOZ_ASSERT(sIOSurfaceFramework);
+  return sIOSurfaceFramework;
+}
+
+IOSurfacePtr MacIOSurfaceLib::IOSurfaceCreate(CFDictionaryRef properties) {
+  return sCreate(properties);
+}
+
+IOSurfacePtr MacIOSurfaceLib::IOSurfaceLookup(IOSurfaceID aIOSurfaceID) {
+  return sLookup(aIOSurfaceID);
+}
+
+IOSurfaceID MacIOSurfaceLib::IOSurfaceGetID(IOSurfacePtr aIOSurfacePtr) {
+  return sGetID(aIOSurfacePtr);
+}
+
+void* MacIOSurfaceLib::IOSurfaceGetBaseAddress(IOSurfacePtr aIOSurfacePtr) {
+  return sGetBaseAddress(aIOSurfacePtr);
+}
+
+size_t MacIOSurfaceLib::IOSurfaceGetWidth(IOSurfacePtr aIOSurfacePtr) {
+  return sWidth(aIOSurfacePtr);
+}
+
+size_t MacIOSurfaceLib::IOSurfaceGetHeight(IOSurfacePtr aIOSurfacePtr) {
+  return sHeight(aIOSurfacePtr);
+}
+
+size_t MacIOSurfaceLib::IOSurfaceGetBytesPerRow(IOSurfacePtr aIOSurfacePtr) {
+  return sBytesPerRow(aIOSurfacePtr);
+}
+
+IOReturn MacIOSurfaceLib::IOSurfaceLock(IOSurfacePtr aIOSurfacePtr, 
+                                       uint32_t options, uint32_t *seed) {
+  return sLock(aIOSurfacePtr, options, seed);
+}
+
+IOReturn MacIOSurfaceLib::IOSurfaceUnlock(IOSurfacePtr aIOSurfacePtr, 
+                                         uint32_t options, uint32_t *seed) {
+  return sUnlock(aIOSurfacePtr, options, seed);
+}
+
+CGLError MacIOSurfaceLib::CGLTexImageIOSurface2D(CGLContextObj ctxt,
+                             GLenum target, GLenum internalFormat,
+                             GLsizei width, GLsizei height,
+                             GLenum format, GLenum type,
+                             IOSurfacePtr ioSurface, GLuint plane) {
+  return sTexImage(ctxt, target, internalFormat, width, height,
+                   format, type, ioSurface, plane);
+}
+
+CGContextRef MacIOSurfaceLib::IOSurfaceContextCreate(IOSurfacePtr aIOSurfacePtr,
+                             unsigned aWidth, unsigned aHeight,
+                             unsigned aBitsPerComponent, unsigned aBytes,
+                             CGColorSpaceRef aColorSpace, CGBitmapInfo bitmapInfo) {
+  if (!sIOSurfaceContextCreate)
+    return nullptr;
+  return sIOSurfaceContextCreate(aIOSurfacePtr, aWidth, aHeight, aBitsPerComponent, aBytes, aColorSpace, bitmapInfo);
+}
+
+CGImageRef MacIOSurfaceLib::IOSurfaceContextCreateImage(CGContextRef aContext) {
+  if (!sIOSurfaceContextCreateImage)
+    return nullptr;
+  return sIOSurfaceContextCreateImage(aContext);
+}
+
+IOSurfacePtr MacIOSurfaceLib::IOSurfaceContextGetSurface(CGContextRef aContext) {
+  if (!sIOSurfaceContextGetSurface)
+    return nullptr;
+  return sIOSurfaceContextGetSurface(aContext);
+}
+
+CFStringRef MacIOSurfaceLib::GetIOConst(const char* symbole) {
+  CFStringRef *address = (CFStringRef*)dlsym(sIOSurfaceFramework, symbole);
+  if (!address)
+    return nullptr;
+
+  return *address;
+}
+
+void MacIOSurfaceLib::LoadLibrary() {
+  if (isLoaded) {
+    return;
+  } 
+  isLoaded = true;
+  sIOSurfaceFramework = dlopen(IOSURFACE_FRAMEWORK_PATH,
+                            RTLD_LAZY | RTLD_LOCAL);
+  sOpenGLFramework = dlopen(OPENGL_FRAMEWORK_PATH,
+                            RTLD_LAZY | RTLD_LOCAL);
+
+  sCoreGraphicsFramework = dlopen(COREGRAPHICS_FRAMEWORK_PATH,
+                            RTLD_LAZY | RTLD_LOCAL);
+  if (!sIOSurfaceFramework || !sOpenGLFramework || !sCoreGraphicsFramework) {
+    if (sIOSurfaceFramework)
+      dlclose(sIOSurfaceFramework);
+    if (sOpenGLFramework)
+      dlclose(sOpenGLFramework);
+    if (sCoreGraphicsFramework)
+      dlclose(sCoreGraphicsFramework);
+    sIOSurfaceFramework = nullptr;
+    sOpenGLFramework = nullptr;
+    sCoreGraphicsFramework = nullptr;
+    return;
+  }
+
+  kPropWidth = GetIOConst("kIOSurfaceWidth");
+  kPropHeight = GetIOConst("kIOSurfaceHeight");
+  kPropBytesPerElem = GetIOConst("kIOSurfaceBytesPerElement");
+  kPropBytesPerRow = GetIOConst("kIOSurfaceBytesPerRow");
+  kPropIsGlobal = GetIOConst("kIOSurfaceIsGlobal");
+  sCreate = GET_IOSYM(sCreate, "IOSurfaceCreate");
+  sGetID  = GET_IOSYM(sGetID,  "IOSurfaceGetID");
+  sWidth = GET_IOSYM(sWidth, "IOSurfaceGetWidth");
+  sHeight = GET_IOSYM(sHeight, "IOSurfaceGetHeight");
+  sBytesPerRow = GET_IOSYM(sBytesPerRow, "IOSurfaceGetBytesPerRow");
+  sLookup = GET_IOSYM(sLookup, "IOSurfaceLookup");
+  sLock = GET_IOSYM(sLock, "IOSurfaceLock");
+  sUnlock = GET_IOSYM(sUnlock, "IOSurfaceUnlock");
+  sGetBaseAddress = GET_IOSYM(sGetBaseAddress, "IOSurfaceGetBaseAddress");
+  sTexImage = GET_CGLSYM(sTexImage, "CGLTexImageIOSurface2D");
+  sCGContextGetTypePtr = (unsigned int (*)(CGContext*))dlsym(RTLD_DEFAULT, "CGContextGetType");
+
+  // Optional symbols
+  sIOSurfaceContextCreate = GET_CGSYM(sIOSurfaceContextCreate, "CGIOSurfaceContextCreate");
+  sIOSurfaceContextCreateImage = GET_CGSYM(sIOSurfaceContextCreateImage, "CGIOSurfaceContextCreateImage");
+  sIOSurfaceContextGetSurface = GET_CGSYM(sIOSurfaceContextGetSurface, "CGIOSurfaceContextGetSurface");
+
+  if (!sCreate || !sGetID || !sLookup || !sTexImage || !sGetBaseAddress ||
+      !kPropWidth || !kPropHeight || !kPropBytesPerElem || !kPropIsGlobal ||
+      !sLock || !sUnlock || !sWidth || !sHeight || !kPropBytesPerRow ||
+      !sBytesPerRow) {
+    CloseLibrary();
+  }
+}
+
+void MacIOSurfaceLib::CloseLibrary() {
+  if (sIOSurfaceFramework) {
+    dlclose(sIOSurfaceFramework);
+  }
+  if (sOpenGLFramework) {
+    dlclose(sOpenGLFramework);
+  }
+  sIOSurfaceFramework = nullptr;
+  sOpenGLFramework = nullptr;
+}
+
+MacIOSurface::~MacIOSurface() {
+  CFRelease(mIOSurfacePtr);
+}
+
+TemporaryRef<MacIOSurface> MacIOSurface::CreateIOSurface(int aWidth, int aHeight,
+                                                         double aContentsScaleFactor,
+                                                         bool aHasAlpha) {
+  if (!MacIOSurfaceLib::isInit() || aContentsScaleFactor <= 0)
+    return nullptr;
+
+  CFMutableDictionaryRef props = ::CFDictionaryCreateMutable(
+                      kCFAllocatorDefault, 4,
+                      &kCFTypeDictionaryKeyCallBacks,
+                      &kCFTypeDictionaryValueCallBacks);
+  if (!props)
+    return nullptr;
+
+  int32_t bytesPerElem = 4;
+  size_t intScaleFactor = ceil(aContentsScaleFactor);
+  aWidth *= intScaleFactor;
+  aHeight *= intScaleFactor;
+  CFNumberRef cfWidth = ::CFNumberCreate(nullptr, kCFNumberSInt32Type, &aWidth);
+  CFNumberRef cfHeight = ::CFNumberCreate(nullptr, kCFNumberSInt32Type, &aHeight);
+  CFNumberRef cfBytesPerElem = ::CFNumberCreate(nullptr, kCFNumberSInt32Type, &bytesPerElem);
+  ::CFDictionaryAddValue(props, MacIOSurfaceLib::kPropWidth,
+                                cfWidth);
+  ::CFRelease(cfWidth);
+  ::CFDictionaryAddValue(props, MacIOSurfaceLib::kPropHeight,
+                                cfHeight);
+  ::CFRelease(cfHeight);
+  ::CFDictionaryAddValue(props, MacIOSurfaceLib::kPropBytesPerElem, 
+                                cfBytesPerElem);
+  ::CFRelease(cfBytesPerElem);
+  ::CFDictionaryAddValue(props, MacIOSurfaceLib::kPropIsGlobal, 
+                                kCFBooleanTrue);
+
+  IOSurfacePtr surfaceRef = MacIOSurfaceLib::IOSurfaceCreate(props);
+  ::CFRelease(props);
+
+  if (!surfaceRef)
+    return nullptr;
+
+  RefPtr<MacIOSurface> ioSurface = new MacIOSurface(surfaceRef, aContentsScaleFactor, aHasAlpha);
+  if (!ioSurface) {
+    ::CFRelease(surfaceRef);
+    return nullptr;
+  }
+
+  return ioSurface.forget();
+}
+
+TemporaryRef<MacIOSurface> MacIOSurface::LookupSurface(IOSurfaceID aIOSurfaceID,
+                                                       double aContentsScaleFactor,
+                                                       bool aHasAlpha) { 
+  if (!MacIOSurfaceLib::isInit() || aContentsScaleFactor <= 0)
+    return nullptr;
+
+  IOSurfacePtr surfaceRef = MacIOSurfaceLib::IOSurfaceLookup(aIOSurfaceID);
+  if (!surfaceRef)
+    return nullptr;
+
+  RefPtr<MacIOSurface> ioSurface = new MacIOSurface(surfaceRef, aContentsScaleFactor, aHasAlpha);
+  if (!ioSurface) {
+    ::CFRelease(surfaceRef);
+    return nullptr;
+  }
+  return ioSurface.forget();
+}
+
+IOSurfaceID MacIOSurface::GetIOSurfaceID() { 
+  return MacIOSurfaceLib::IOSurfaceGetID(mIOSurfacePtr);
+}
+
+void* MacIOSurface::GetBaseAddress() { 
+  return MacIOSurfaceLib::IOSurfaceGetBaseAddress(mIOSurfacePtr);
+}
+
+size_t MacIOSurface::GetWidth() {
+  size_t intScaleFactor = ceil(mContentsScaleFactor);
+  return GetDevicePixelWidth() / intScaleFactor;
+}
+
+size_t MacIOSurface::GetHeight() {
+  size_t intScaleFactor = ceil(mContentsScaleFactor);
+  return GetDevicePixelHeight() / intScaleFactor;
+}
+
+size_t MacIOSurface::GetDevicePixelWidth() {
+  return MacIOSurfaceLib::IOSurfaceGetWidth(mIOSurfacePtr);
+}
+
+size_t MacIOSurface::GetDevicePixelHeight() {
+  return MacIOSurfaceLib::IOSurfaceGetHeight(mIOSurfacePtr);
+}
+
+size_t MacIOSurface::GetBytesPerRow() { 
+  return MacIOSurfaceLib::IOSurfaceGetBytesPerRow(mIOSurfacePtr);
+}
+
+#define READ_ONLY 0x1
+void MacIOSurface::Lock() {
+  MacIOSurfaceLib::IOSurfaceLock(mIOSurfacePtr, READ_ONLY, nullptr);
+}
+
+void MacIOSurface::Unlock() {
+  MacIOSurfaceLib::IOSurfaceUnlock(mIOSurfacePtr, READ_ONLY, nullptr);
+}
+
+#include "SourceSurfaceRawData.h"
+using mozilla::gfx::SourceSurface;
+using mozilla::gfx::SourceSurfaceRawData;
+using mozilla::gfx::IntSize;
+using mozilla::gfx::SurfaceFormat;
+
+TemporaryRef<SourceSurface>
+MacIOSurface::GetAsSurface() {
+  Lock();
+  size_t bytesPerRow = GetBytesPerRow();
+  size_t ioWidth = GetDevicePixelWidth();
+  size_t ioHeight = GetDevicePixelHeight();
+
+  unsigned char* ioData = (unsigned char*)GetBaseAddress();
+  unsigned char* dataCpy = (unsigned char*)malloc(bytesPerRow*ioHeight);
+  for (size_t i = 0; i < ioHeight; i++) {
+    memcpy(dataCpy + i * bytesPerRow,
+           ioData + i * bytesPerRow, ioWidth * 4);
+  }
+
+  Unlock();
+
+  SurfaceFormat format = HasAlpha() ? mozilla::gfx::FORMAT_B8G8R8A8 :
+                                      mozilla::gfx::FORMAT_B8G8R8X8;
+
+  RefPtr<SourceSurfaceRawData> surf = new SourceSurfaceRawData();
+  surf->InitWrappingData(dataCpy, IntSize(ioWidth, ioHeight), bytesPerRow, format, true);
+
+  return surf.forget();
+}
+
+CGLError
+MacIOSurface::CGLTexImageIOSurface2D(CGLContextObj ctx)
+{
+  return MacIOSurfaceLib::CGLTexImageIOSurface2D(ctx,
+                                                GL_TEXTURE_RECTANGLE_ARB,
+                                                HasAlpha() ? GL_RGBA : GL_RGB,
+                                                GetDevicePixelWidth(),
+                                                GetDevicePixelHeight(),
+                                                GL_BGRA,
+                                                GL_UNSIGNED_INT_8_8_8_8_REV,
+                                                mIOSurfacePtr, 0);
+}
+
+static
+CGColorSpaceRef CreateSystemColorSpace() {
+  CGColorSpaceRef cspace = ::CGDisplayCopyColorSpace(::CGMainDisplayID());
+  if (!cspace) {
+    cspace = ::CGColorSpaceCreateDeviceRGB();
+  }
+  return cspace;
+}
+
+CGContextRef MacIOSurface::CreateIOSurfaceContext() {
+  CGColorSpaceRef cspace = CreateSystemColorSpace();
+  CGContextRef ref = MacIOSurfaceLib::IOSurfaceContextCreate(mIOSurfacePtr,
+                                                GetDevicePixelWidth(),
+                                                GetDevicePixelHeight(),
+                                                8, 32, cspace, 0x2002);
+  ::CGColorSpaceRelease(cspace);
+  return ref;
+}
+
+CGImageRef MacIOSurface::CreateImageFromIOSurfaceContext(CGContextRef aContext) {
+  if (!MacIOSurfaceLib::isInit())
+    return nullptr;
+
+  return MacIOSurfaceLib::IOSurfaceContextCreateImage(aContext);
+}
+
+TemporaryRef<MacIOSurface> MacIOSurface::IOSurfaceContextGetSurface(CGContextRef aContext,
+                                                                    double aContentsScaleFactor,
+                                                                    bool aHasAlpha) {
+  if (!MacIOSurfaceLib::isInit() || aContentsScaleFactor <= 0)
+    return nullptr;
+
+  IOSurfacePtr surfaceRef = MacIOSurfaceLib::IOSurfaceContextGetSurface(aContext);
+  if (!surfaceRef)
+    return nullptr;
+
+  // Retain the IOSurface because MacIOSurface will release it
+  CFRetain(surfaceRef);
+
+  RefPtr<MacIOSurface> ioSurface = new MacIOSurface(surfaceRef, aContentsScaleFactor, aHasAlpha);
+  if (!ioSurface) {
+    ::CFRelease(surfaceRef);
+    return nullptr;
+  }
+  return ioSurface.forget();
+}
+
+
+CGContextType GetContextType(CGContextRef ref)
+{
+  if (!MacIOSurfaceLib::isInit() || !MacIOSurfaceLib::sCGContextGetTypePtr)
+    return CG_CONTEXT_TYPE_UNKNOWN;
+
+  unsigned int type = MacIOSurfaceLib::sCGContextGetTypePtr(ref);
+  if (type == CG_CONTEXT_TYPE_BITMAP) {
+    return CG_CONTEXT_TYPE_BITMAP;
+  } else if (type == CG_CONTEXT_TYPE_IOSURFACE) {
+    return CG_CONTEXT_TYPE_IOSURFACE;
+  } else {
+    return CG_CONTEXT_TYPE_UNKNOWN;
+  }
+}
+
+
--- a/gfx/2d/MacIOSurface.h
+++ b/gfx/2d/MacIOSurface.h
@@ -2,29 +2,69 @@
 // vim:set ts=2 sts=2 sw=2 et cin:
 /* 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 MacIOSurface_h__
 #define MacIOSurface_h__
 #ifdef XP_MACOSX
+#include <QuartzCore/QuartzCore.h>
+#include <dlfcn.h>
+#include "mozilla/RefPtr.h"
+
+typedef CFTypeRef IOSurfacePtr;
+typedef IOSurfacePtr (*IOSurfaceCreateFunc) (CFDictionaryRef properties);
+typedef IOSurfacePtr (*IOSurfaceLookupFunc) (uint32_t io_surface_id);
+typedef IOSurfaceID (*IOSurfaceGetIDFunc) (CFTypeRef io_surface);
+typedef IOReturn (*IOSurfaceLockFunc) (CFTypeRef io_surface, 
+                                       uint32_t options, 
+                                       uint32_t *seed);
+typedef IOReturn (*IOSurfaceUnlockFunc) (CFTypeRef io_surface, 
+                                         uint32_t options, 
+                                         uint32_t *seed);
+typedef void* (*IOSurfaceGetBaseAddressFunc) (CFTypeRef io_surface);
+typedef size_t (*IOSurfaceGetWidthFunc) (IOSurfacePtr io_surface);
+typedef size_t (*IOSurfaceGetHeightFunc) (IOSurfacePtr io_surface);
+typedef size_t (*IOSurfaceGetBytesPerRowFunc) (IOSurfacePtr io_surface);
+typedef CGLError (*CGLTexImageIOSurface2DFunc) (CGLContextObj ctxt,
+                             GLenum target, GLenum internalFormat,
+                             GLsizei width, GLsizei height,
+                             GLenum format, GLenum type,
+                             IOSurfacePtr ioSurface, GLuint plane);
+typedef CGContextRef (*IOSurfaceContextCreateFunc)(CFTypeRef io_surface,
+                             unsigned width, unsigned height,
+                             unsigned bitsPerComponent, unsigned bytes,
+                             CGColorSpaceRef colorSpace, CGBitmapInfo bitmapInfo);
+typedef CGImageRef (*IOSurfaceContextCreateImageFunc)(CGContextRef ref);
+typedef IOSurfacePtr (*IOSurfaceContextGetSurfaceFunc)(CGContextRef ref);
+
+
 
 #import <OpenGL/OpenGL.h>
 #include "2D.h"
 #include "mozilla/RefPtr.h"
 
 class gfxASurface;
 struct _CGLContextObject;
 
 typedef _CGLContextObject* CGLContextObj;
 typedef struct CGContext* CGContextRef;
 typedef struct CGImage* CGImageRef;
 typedef uint32_t IOSurfaceID;
 
+enum CGContextType {
+  CG_CONTEXT_TYPE_UNKNOWN = 0,
+  // These are found by inspection, it's possible they could be changed
+  CG_CONTEXT_TYPE_BITMAP = 4,
+  CG_CONTEXT_TYPE_IOSURFACE = 8
+};
+
+CGContextType GetContextType(CGContextRef ref);
+
 class MacIOSurface : public mozilla::RefCounted<MacIOSurface> {
 public:
   typedef mozilla::gfx::SourceSurface SourceSurface;
 
   static mozilla::TemporaryRef<MacIOSurface> CreateIOSurface(int aWidth, int aHeight,
                                                              double aContentsScaleFactor = 1.0,
                                                              bool aHasAlpha = true);
   static void ReleaseIOSurface(MacIOSurface *aIOSurface);
@@ -47,27 +87,89 @@ public:
   size_t GetDevicePixelWidth();
   size_t GetDevicePixelHeight();
   size_t GetBytesPerRow();
   void Lock();
   void Unlock();
   bool HasAlpha() { return mHasAlpha; }
   // We would like to forward declare NSOpenGLContext, but it is an @interface
   // and this file is also used from c++, so we use a void *.
-  CGLError CGLTexImageIOSurface2D(void *ctxt);
+  CGLError CGLTexImageIOSurface2D(CGLContextObj ctxt);
   mozilla::TemporaryRef<SourceSurface> GetAsSurface();
   CGContextRef CreateIOSurfaceContext();
 
   // FIXME This doesn't really belong here
   static CGImageRef CreateImageFromIOSurfaceContext(CGContextRef aContext);
   static mozilla::TemporaryRef<MacIOSurface> IOSurfaceContextGetSurface(CGContextRef aContext,
                                                                         double aContentsScaleFactor = 1.0,
                                                                         bool aHasAlpha = true);
 
 private:
   friend class nsCARenderer;
   const void* mIOSurfacePtr;
   double mContentsScaleFactor;
   bool mHasAlpha;
 };
 
+class MacIOSurfaceLib: public MacIOSurface {
+public:
+  static void                        *sIOSurfaceFramework;
+  static void                        *sOpenGLFramework;
+  static void                        *sCoreGraphicsFramework;
+  static bool                         isLoaded;
+  static IOSurfaceCreateFunc          sCreate;
+  static IOSurfaceGetIDFunc           sGetID;
+  static IOSurfaceLookupFunc          sLookup;
+  static IOSurfaceGetBaseAddressFunc  sGetBaseAddress;
+  static IOSurfaceLockFunc            sLock;
+  static IOSurfaceUnlockFunc          sUnlock;
+  static IOSurfaceGetWidthFunc        sWidth;
+  static IOSurfaceGetHeightFunc       sHeight;
+  static IOSurfaceGetBytesPerRowFunc  sBytesPerRow;
+  static CGLTexImageIOSurface2DFunc   sTexImage;
+  static IOSurfaceContextCreateFunc   sIOSurfaceContextCreate;
+  static IOSurfaceContextCreateImageFunc  sIOSurfaceContextCreateImage;
+  static IOSurfaceContextGetSurfaceFunc   sIOSurfaceContextGetSurface;
+  static CFStringRef                  kPropWidth;
+  static CFStringRef                  kPropHeight;
+  static CFStringRef                  kPropBytesPerElem;
+  static CFStringRef                  kPropBytesPerRow;
+  static CFStringRef                  kPropIsGlobal;
+
+  static bool isInit();
+  static CFStringRef GetIOConst(const char* symbole);
+  static IOSurfacePtr IOSurfaceCreate(CFDictionaryRef properties);
+  static IOSurfacePtr IOSurfaceLookup(IOSurfaceID aIOSurfaceID);
+  static IOSurfaceID  IOSurfaceGetID(IOSurfacePtr aIOSurfacePtr);
+  static void        *IOSurfaceGetBaseAddress(IOSurfacePtr aIOSurfacePtr);
+  static size_t       IOSurfaceGetWidth(IOSurfacePtr aIOSurfacePtr);
+  static size_t       IOSurfaceGetHeight(IOSurfacePtr aIOSurfacePtr);
+  static size_t       IOSurfaceGetBytesPerRow(IOSurfacePtr aIOSurfacePtr);
+  static IOReturn     IOSurfaceLock(IOSurfacePtr aIOSurfacePtr, 
+                                    uint32_t options, uint32_t *seed);
+  static IOReturn     IOSurfaceUnlock(IOSurfacePtr aIOSurfacePtr, 
+                                      uint32_t options, uint32_t *seed);
+  static CGLError     CGLTexImageIOSurface2D(CGLContextObj ctxt,
+                             GLenum target, GLenum internalFormat,
+                             GLsizei width, GLsizei height,
+                             GLenum format, GLenum type,
+                             IOSurfacePtr ioSurface, GLuint plane);
+  static CGContextRef IOSurfaceContextCreate(IOSurfacePtr aIOSurfacePtr,
+                             unsigned aWidth, unsigned aHeight,
+                             unsigned aBitsPerCompoent, unsigned aBytes,
+                             CGColorSpaceRef aColorSpace, CGBitmapInfo bitmapInfo);
+  static CGImageRef   IOSurfaceContextCreateImage(CGContextRef ref);
+  static IOSurfacePtr IOSurfaceContextGetSurface(CGContextRef ref);
+  static unsigned int (*sCGContextGetTypePtr) (CGContextRef);
+  static void LoadLibrary();
+  static void CloseLibrary();
+
+  // Static deconstructor
+  static class LibraryUnloader {
+  public:
+    ~LibraryUnloader() {
+      CloseLibrary();
+    }
+  } sLibraryUnloader;
+};
+
 #endif
 #endif
--- a/gfx/2d/PathCG.cpp
+++ b/gfx/2d/PathCG.cpp
@@ -160,16 +160,64 @@ PathCG::TransformedCopyToBuilder(const M
   ta.path = CGPathCreateMutable();
   ta.transform = GfxMatrixToCGAffineTransform(aTransform);
 
   CGPathApply(mPath, &ta, TransformApplier::TranformCGPathApplierFunc);
   RefPtr<PathBuilderCG> builder = new PathBuilderCG(ta.path, aFillRule);
   return builder;
 }
 
+static void
+StreamPathToSinkApplierFunc(void *vinfo, const CGPathElement *element)
+{
+  PathSink *sink = reinterpret_cast<PathSink*>(vinfo);
+  switch (element->type) {
+    case kCGPathElementMoveToPoint:
+      {
+        CGPoint pt = element->points[0];
+        sink->MoveTo(CGPointToPoint(pt));
+        break;
+      }
+    case kCGPathElementAddLineToPoint:
+      {
+        CGPoint pt = element->points[0];
+        sink->LineTo(CGPointToPoint(pt));
+        break;
+      }
+    case kCGPathElementAddQuadCurveToPoint:
+      {
+        CGPoint cpt = element->points[0];
+        CGPoint pt  = element->points[1];
+        sink->QuadraticBezierTo(CGPointToPoint(cpt),
+                                CGPointToPoint(pt));
+        break;
+      }
+    case kCGPathElementAddCurveToPoint:
+      {
+        CGPoint cpt1 = element->points[0];
+        CGPoint cpt2 = element->points[1];
+        CGPoint pt   = element->points[2];
+        sink->BezierTo(CGPointToPoint(cpt1),
+                       CGPointToPoint(cpt2),
+                       CGPointToPoint(pt));
+        break;
+      }
+    case kCGPathElementCloseSubpath:
+      {
+        sink->Close();
+        break;
+      }
+  }
+}
+
+void
+PathCG::StreamToSink(PathSink *aSink) const
+{
+  CGPathApply(mPath, aSink, StreamPathToSinkApplierFunc);
+}
 
 bool
 PathCG::ContainsPoint(const Point &aPoint, const Matrix &aTransform) const
 {
   Matrix inverse = aTransform;
   inverse.Invert();
   Point transformedPoint = inverse*aPoint;
   // We could probably drop the input transform and just transform the point at the caller?
--- a/gfx/2d/PathCG.h
+++ b/gfx/2d/PathCG.h
@@ -80,17 +80,17 @@ public:
   virtual bool ContainsPoint(const Point &aPoint, const Matrix &aTransform) const;
   virtual bool StrokeContainsPoint(const StrokeOptions &aStrokeOptions,
                                    const Point &aPoint,
                                    const Matrix &aTransform) const;
   virtual Rect GetBounds(const Matrix &aTransform = Matrix()) const;
   virtual Rect GetStrokedBounds(const StrokeOptions &aStrokeOptions,
                                 const Matrix &aTransform = Matrix()) const;
 
-  virtual void StreamToSink(PathSink *aSink) const { MOZ_ASSERT(false); }
+  virtual void StreamToSink(PathSink *aSink) const;
 
   virtual FillRule GetFillRule() const { return mFillRule; }
 
   CGMutablePathRef GetPath() const { return mPath; }
 
 private:
   friend class DrawTargetCG;
 
--- a/gfx/2d/QuartzSupport.h
+++ b/gfx/2d/QuartzSupport.h
@@ -88,20 +88,11 @@ private:
   uint32_t                  mFBO;
   uint32_t                  mIOTexture;
   int                       mUnsupportedWidth;
   int                       mUnsupportedHeight;
   AllowOfflineRendererEnum  mAllowOfflineRenderer;
   double                    mContentsScaleFactor;
 };
 
-enum CGContextType {
-  CG_CONTEXT_TYPE_UNKNOWN = 0,
-  // These are found by inspection, it's possible they could be changed
-  CG_CONTEXT_TYPE_BITMAP = 4,
-  CG_CONTEXT_TYPE_IOSURFACE = 8
-};
-
-CGContextType GetContextType(CGContextRef ref);
-
 #endif // XP_MACOSX
 #endif // nsCoreAnimationSupport_h__
 
--- a/gfx/2d/QuartzSupport.mm
+++ b/gfx/2d/QuartzSupport.mm
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 // vim:set ts=2 sts=2 sw=2 et cin:
 /* 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 "QuartzSupport.h"
 #include "nsDebug.h"
+#include "MacIOSurface.h"
 
 #import <QuartzCore/QuartzCore.h>
 #import <AppKit/NSOpenGL.h>
 #include <dlfcn.h>
 #include "GLDefs.h"
 
 #define IOSURFACE_FRAMEWORK_PATH \
   "/System/Library/Frameworks/IOSurface.framework/IOSurface"
@@ -22,464 +23,24 @@
 @interface CALayer (ContentsScale)
 - (double)contentsScale;
 - (void)setContentsScale:(double)scale;
 @end
 
 using mozilla::RefPtr;
 using mozilla::TemporaryRef;
 
-// IOSurface signatures
-typedef CFTypeRef IOSurfacePtr;
-typedef IOSurfacePtr (*IOSurfaceCreateFunc) (CFDictionaryRef properties);
-typedef IOSurfacePtr (*IOSurfaceLookupFunc) (uint32_t io_surface_id);
-typedef IOSurfaceID (*IOSurfaceGetIDFunc) (CFTypeRef io_surface);
-typedef IOReturn (*IOSurfaceLockFunc) (CFTypeRef io_surface, 
-                                       uint32_t options, 
-                                       uint32_t *seed);
-typedef IOReturn (*IOSurfaceUnlockFunc) (CFTypeRef io_surface, 
-                                         uint32_t options, 
-                                         uint32_t *seed);
-typedef void* (*IOSurfaceGetBaseAddressFunc) (CFTypeRef io_surface);
-typedef size_t (*IOSurfaceGetWidthFunc) (IOSurfacePtr io_surface);
-typedef size_t (*IOSurfaceGetHeightFunc) (IOSurfacePtr io_surface);
-typedef size_t (*IOSurfaceGetBytesPerRowFunc) (IOSurfacePtr io_surface);
-typedef CGLError (*CGLTexImageIOSurface2DFunc) (CGLContextObj ctxt,
-                             GLenum target, GLenum internalFormat,
-                             GLsizei width, GLsizei height,
-                             GLenum format, GLenum type,
-                             IOSurfacePtr ioSurface, GLuint plane);
-typedef CGContextRef (*IOSurfaceContextCreateFunc)(CFTypeRef io_surface,
-                             unsigned width, unsigned height,
-                             unsigned bitsPerComponent, unsigned bytes,
-                             CGColorSpaceRef colorSpace, CGBitmapInfo bitmapInfo);
-typedef CGImageRef (*IOSurfaceContextCreateImageFunc)(CGContextRef ref);
-typedef IOSurfacePtr (*IOSurfaceContextGetSurfaceFunc)(CGContextRef ref);
-
-#define GET_CONST(const_name) \
-  ((CFStringRef*) dlsym(sIOSurfaceFramework, const_name))
-#define GET_IOSYM(dest,sym_name) \
-  (typeof(dest)) dlsym(sIOSurfaceFramework, sym_name)
-#define GET_CGLSYM(dest,sym_name) \
-  (typeof(dest)) dlsym(sOpenGLFramework, sym_name)
-#define GET_CGSYM(dest,sym_name) \
-  (typeof(dest)) dlsym(sCoreGraphicsFramework, sym_name)
-
-class MacIOSurfaceLib: public MacIOSurface {
-public:
-  static void                        *sIOSurfaceFramework;
-  static void                        *sOpenGLFramework;
-  static void                        *sCoreGraphicsFramework;
-  static bool                         isLoaded;
-  static IOSurfaceCreateFunc          sCreate;
-  static IOSurfaceGetIDFunc           sGetID;
-  static IOSurfaceLookupFunc          sLookup;
-  static IOSurfaceGetBaseAddressFunc  sGetBaseAddress;
-  static IOSurfaceLockFunc            sLock;
-  static IOSurfaceUnlockFunc          sUnlock;
-  static IOSurfaceGetWidthFunc        sWidth;
-  static IOSurfaceGetHeightFunc       sHeight;
-  static IOSurfaceGetBytesPerRowFunc  sBytesPerRow;
-  static CGLTexImageIOSurface2DFunc   sTexImage;
-  static IOSurfaceContextCreateFunc   sIOSurfaceContextCreate;
-  static IOSurfaceContextCreateImageFunc  sIOSurfaceContextCreateImage;
-  static IOSurfaceContextGetSurfaceFunc   sIOSurfaceContextGetSurface;
-  static CFStringRef                  kPropWidth;
-  static CFStringRef                  kPropHeight;
-  static CFStringRef                  kPropBytesPerElem;
-  static CFStringRef                  kPropBytesPerRow;
-  static CFStringRef                  kPropIsGlobal;
-
-  static bool isInit();
-  static CFStringRef GetIOConst(const char* symbole);
-  static IOSurfacePtr IOSurfaceCreate(CFDictionaryRef properties);
-  static IOSurfacePtr IOSurfaceLookup(IOSurfaceID aIOSurfaceID);
-  static IOSurfaceID  IOSurfaceGetID(IOSurfacePtr aIOSurfacePtr);
-  static void        *IOSurfaceGetBaseAddress(IOSurfacePtr aIOSurfacePtr);
-  static size_t       IOSurfaceGetWidth(IOSurfacePtr aIOSurfacePtr);
-  static size_t       IOSurfaceGetHeight(IOSurfacePtr aIOSurfacePtr);
-  static size_t       IOSurfaceGetBytesPerRow(IOSurfacePtr aIOSurfacePtr);
-  static IOReturn     IOSurfaceLock(IOSurfacePtr aIOSurfacePtr, 
-                                    uint32_t options, uint32_t *seed);
-  static IOReturn     IOSurfaceUnlock(IOSurfacePtr aIOSurfacePtr, 
-                                      uint32_t options, uint32_t *seed);
-  static CGLError     CGLTexImageIOSurface2D(CGLContextObj ctxt,
-                             GLenum target, GLenum internalFormat,
-                             GLsizei width, GLsizei height,
-                             GLenum format, GLenum type,
-                             IOSurfacePtr ioSurface, GLuint plane);
-  static CGContextRef IOSurfaceContextCreate(IOSurfacePtr aIOSurfacePtr,
-                             unsigned aWidth, unsigned aHeight,
-                             unsigned aBitsPerCompoent, unsigned aBytes,
-                             CGColorSpaceRef aColorSpace, CGBitmapInfo bitmapInfo);
-  static CGImageRef   IOSurfaceContextCreateImage(CGContextRef ref);
-  static IOSurfacePtr IOSurfaceContextGetSurface(CGContextRef ref);
-  static unsigned int (*sCGContextGetTypePtr) (CGContextRef);
-  static void LoadLibrary();
-  static void CloseLibrary();
-
-  // Static deconstructor
-  static class LibraryUnloader {
-  public:
-    ~LibraryUnloader() {
-      CloseLibrary();
-    }
-  } sLibraryUnloader;
-};
-
-MacIOSurfaceLib::LibraryUnloader MacIOSurfaceLib::sLibraryUnloader;
-bool                          MacIOSurfaceLib::isLoaded = false;
-void*                         MacIOSurfaceLib::sIOSurfaceFramework;
-void*                         MacIOSurfaceLib::sOpenGLFramework;
-void*                         MacIOSurfaceLib::sCoreGraphicsFramework;
-IOSurfaceCreateFunc           MacIOSurfaceLib::sCreate;
-IOSurfaceGetIDFunc            MacIOSurfaceLib::sGetID;
-IOSurfaceLookupFunc           MacIOSurfaceLib::sLookup;
-IOSurfaceGetBaseAddressFunc   MacIOSurfaceLib::sGetBaseAddress;
-IOSurfaceGetWidthFunc         MacIOSurfaceLib::sWidth;
-IOSurfaceGetHeightFunc        MacIOSurfaceLib::sHeight;
-IOSurfaceGetBytesPerRowFunc   MacIOSurfaceLib::sBytesPerRow;
-IOSurfaceLockFunc             MacIOSurfaceLib::sLock;
-IOSurfaceUnlockFunc           MacIOSurfaceLib::sUnlock;
-CGLTexImageIOSurface2DFunc    MacIOSurfaceLib::sTexImage;
-IOSurfaceContextCreateFunc    MacIOSurfaceLib::sIOSurfaceContextCreate;
-IOSurfaceContextCreateImageFunc   MacIOSurfaceLib::sIOSurfaceContextCreateImage;
-IOSurfaceContextGetSurfaceFunc    MacIOSurfaceLib::sIOSurfaceContextGetSurface;
-unsigned int                  (*MacIOSurfaceLib::sCGContextGetTypePtr) (CGContextRef) = nullptr;
-
-CFStringRef                   MacIOSurfaceLib::kPropWidth;
-CFStringRef                   MacIOSurfaceLib::kPropHeight;
-CFStringRef                   MacIOSurfaceLib::kPropBytesPerElem;
-CFStringRef                   MacIOSurfaceLib::kPropBytesPerRow;
-CFStringRef                   MacIOSurfaceLib::kPropIsGlobal;
-
-bool MacIOSurfaceLib::isInit() {
-  // Guard against trying to reload the library
-  // if it is not available.
-  if (!isLoaded)
-    LoadLibrary();
-  if (!sIOSurfaceFramework) {
-    NS_ERROR("MacIOSurfaceLib failed to initialize");
-  }
-  return sIOSurfaceFramework;
-}
-
-IOSurfacePtr MacIOSurfaceLib::IOSurfaceCreate(CFDictionaryRef properties) {
-  return sCreate(properties);
-}
-
-IOSurfacePtr MacIOSurfaceLib::IOSurfaceLookup(IOSurfaceID aIOSurfaceID) {
-  return sLookup(aIOSurfaceID);
-}
-
-IOSurfaceID MacIOSurfaceLib::IOSurfaceGetID(IOSurfacePtr aIOSurfacePtr) {
-  return sGetID(aIOSurfacePtr);
-}
-
-void* MacIOSurfaceLib::IOSurfaceGetBaseAddress(IOSurfacePtr aIOSurfacePtr) {
-  return sGetBaseAddress(aIOSurfacePtr);
-}
-
-size_t MacIOSurfaceLib::IOSurfaceGetWidth(IOSurfacePtr aIOSurfacePtr) {
-  return sWidth(aIOSurfacePtr);
-}
-
-size_t MacIOSurfaceLib::IOSurfaceGetHeight(IOSurfacePtr aIOSurfacePtr) {
-  return sHeight(aIOSurfacePtr);
-}
-
-size_t MacIOSurfaceLib::IOSurfaceGetBytesPerRow(IOSurfacePtr aIOSurfacePtr) {
-  return sBytesPerRow(aIOSurfacePtr);
-}
-
-IOReturn MacIOSurfaceLib::IOSurfaceLock(IOSurfacePtr aIOSurfacePtr, 
-                                       uint32_t options, uint32_t *seed) {
-  return sLock(aIOSurfacePtr, options, seed);
-}
-
-IOReturn MacIOSurfaceLib::IOSurfaceUnlock(IOSurfacePtr aIOSurfacePtr, 
-                                         uint32_t options, uint32_t *seed) {
-  return sUnlock(aIOSurfacePtr, options, seed);
-}
-
-CGLError MacIOSurfaceLib::CGLTexImageIOSurface2D(CGLContextObj ctxt,
-                             GLenum target, GLenum internalFormat,
-                             GLsizei width, GLsizei height,
-                             GLenum format, GLenum type,
-                             IOSurfacePtr ioSurface, GLuint plane) {
-  return sTexImage(ctxt, target, internalFormat, width, height,
-                   format, type, ioSurface, plane);
-}
-
-CGContextRef MacIOSurfaceLib::IOSurfaceContextCreate(IOSurfacePtr aIOSurfacePtr,
-                             unsigned aWidth, unsigned aHeight,
-                             unsigned aBitsPerComponent, unsigned aBytes,
-                             CGColorSpaceRef aColorSpace, CGBitmapInfo bitmapInfo) {
-  if (!sIOSurfaceContextCreate)
-    return nullptr;
-  return sIOSurfaceContextCreate(aIOSurfacePtr, aWidth, aHeight, aBitsPerComponent, aBytes, aColorSpace, bitmapInfo);
-}
-
-CGImageRef MacIOSurfaceLib::IOSurfaceContextCreateImage(CGContextRef aContext) {
-  if (!sIOSurfaceContextCreateImage)
-    return nullptr;
-  return sIOSurfaceContextCreateImage(aContext);
-}
-
-IOSurfacePtr MacIOSurfaceLib::IOSurfaceContextGetSurface(CGContextRef aContext) {
-  if (!sIOSurfaceContextGetSurface)
-    return nullptr;
-  return sIOSurfaceContextGetSurface(aContext);
-}
-
-CFStringRef MacIOSurfaceLib::GetIOConst(const char* symbole) {
-  CFStringRef *address = (CFStringRef*)dlsym(sIOSurfaceFramework, symbole);
-  if (!address)
-    return nullptr;
-
-  return *address;
-}
-
-void MacIOSurfaceLib::LoadLibrary() {
-  if (isLoaded) {
-    return;
-  } 
-  isLoaded = true;
-  sIOSurfaceFramework = dlopen(IOSURFACE_FRAMEWORK_PATH,
-                            RTLD_LAZY | RTLD_LOCAL);
-  sOpenGLFramework = dlopen(OPENGL_FRAMEWORK_PATH,
-                            RTLD_LAZY | RTLD_LOCAL);
-
-  sCoreGraphicsFramework = dlopen(COREGRAPHICS_FRAMEWORK_PATH,
-                            RTLD_LAZY | RTLD_LOCAL);
-  if (!sIOSurfaceFramework || !sOpenGLFramework || !sCoreGraphicsFramework) {
-    if (sIOSurfaceFramework)
-      dlclose(sIOSurfaceFramework);
-    if (sOpenGLFramework)
-      dlclose(sOpenGLFramework);
-    if (sCoreGraphicsFramework)
-      dlclose(sCoreGraphicsFramework);
-    sIOSurfaceFramework = nullptr;
-    sOpenGLFramework = nullptr;
-    sCoreGraphicsFramework = nullptr;
-    return;
-  }
-
-  kPropWidth = GetIOConst("kIOSurfaceWidth");
-  kPropHeight = GetIOConst("kIOSurfaceHeight");
-  kPropBytesPerElem = GetIOConst("kIOSurfaceBytesPerElement");
-  kPropBytesPerRow = GetIOConst("kIOSurfaceBytesPerRow");
-  kPropIsGlobal = GetIOConst("kIOSurfaceIsGlobal");
-  sCreate = GET_IOSYM(sCreate, "IOSurfaceCreate");
-  sGetID  = GET_IOSYM(sGetID,  "IOSurfaceGetID");
-  sWidth = GET_IOSYM(sWidth, "IOSurfaceGetWidth");
-  sHeight = GET_IOSYM(sHeight, "IOSurfaceGetHeight");
-  sBytesPerRow = GET_IOSYM(sBytesPerRow, "IOSurfaceGetBytesPerRow");
-  sLookup = GET_IOSYM(sLookup, "IOSurfaceLookup");
-  sLock = GET_IOSYM(sLock, "IOSurfaceLock");
-  sUnlock = GET_IOSYM(sUnlock, "IOSurfaceUnlock");
-  sGetBaseAddress = GET_IOSYM(sGetBaseAddress, "IOSurfaceGetBaseAddress");
-  sTexImage = GET_CGLSYM(sTexImage, "CGLTexImageIOSurface2D");
-  sCGContextGetTypePtr = (unsigned int (*)(CGContext*))dlsym(RTLD_DEFAULT, "CGContextGetType");
-
-  // Optional symbols
-  sIOSurfaceContextCreate = GET_CGSYM(sIOSurfaceContextCreate, "CGIOSurfaceContextCreate");
-  sIOSurfaceContextCreateImage = GET_CGSYM(sIOSurfaceContextCreateImage, "CGIOSurfaceContextCreateImage");
-  sIOSurfaceContextGetSurface = GET_CGSYM(sIOSurfaceContextGetSurface, "CGIOSurfaceContextGetSurface");
-
-  if (!sCreate || !sGetID || !sLookup || !sTexImage || !sGetBaseAddress ||
-      !kPropWidth || !kPropHeight || !kPropBytesPerElem || !kPropIsGlobal ||
-      !sLock || !sUnlock || !sWidth || !sHeight || !kPropBytesPerRow ||
-      !sBytesPerRow) {
-    CloseLibrary();
-  }
-}
-
-void MacIOSurfaceLib::CloseLibrary() {
-  if (sIOSurfaceFramework) {
-    dlclose(sIOSurfaceFramework);
-  }
-  if (sOpenGLFramework) {
-    dlclose(sOpenGLFramework);
-  }
-  sIOSurfaceFramework = nullptr;
-  sOpenGLFramework = nullptr;
-}
-
-MacIOSurface::~MacIOSurface() {
-  CFRelease(mIOSurfacePtr);
-}
-
-TemporaryRef<MacIOSurface> MacIOSurface::CreateIOSurface(int aWidth, int aHeight,
-                                                         double aContentsScaleFactor,
-                                                         bool aHasAlpha) {
-  if (!MacIOSurfaceLib::isInit() || aContentsScaleFactor <= 0)
-    return nullptr;
-
-  CFMutableDictionaryRef props = ::CFDictionaryCreateMutable(
-                      kCFAllocatorDefault, 4,
-                      &kCFTypeDictionaryKeyCallBacks,
-                      &kCFTypeDictionaryValueCallBacks);
-  if (!props)
-    return nullptr;
-
-  int32_t bytesPerElem = 4;
-  size_t intScaleFactor = ceil(aContentsScaleFactor);
-  aWidth *= intScaleFactor;
-  aHeight *= intScaleFactor;
-  CFNumberRef cfWidth = ::CFNumberCreate(nullptr, kCFNumberSInt32Type, &aWidth);
-  CFNumberRef cfHeight = ::CFNumberCreate(nullptr, kCFNumberSInt32Type, &aHeight);
-  CFNumberRef cfBytesPerElem = ::CFNumberCreate(nullptr, kCFNumberSInt32Type, &bytesPerElem);
-  ::CFDictionaryAddValue(props, MacIOSurfaceLib::kPropWidth,
-                                cfWidth);
-  ::CFRelease(cfWidth);
-  ::CFDictionaryAddValue(props, MacIOSurfaceLib::kPropHeight,
-                                cfHeight);
-  ::CFRelease(cfHeight);
-  ::CFDictionaryAddValue(props, MacIOSurfaceLib::kPropBytesPerElem, 
-                                cfBytesPerElem);
-  ::CFRelease(cfBytesPerElem);
-  ::CFDictionaryAddValue(props, MacIOSurfaceLib::kPropIsGlobal, 
-                                kCFBooleanTrue);
-
-  IOSurfacePtr surfaceRef = MacIOSurfaceLib::IOSurfaceCreate(props);
-  ::CFRelease(props);
-
-  if (!surfaceRef)
-    return nullptr;
-
-  RefPtr<MacIOSurface> ioSurface = new MacIOSurface(surfaceRef, aContentsScaleFactor, aHasAlpha);
-  if (!ioSurface) {
-    ::CFRelease(surfaceRef);
-    return nullptr;
-  }
-
-  return ioSurface.forget();
-}
-
-TemporaryRef<MacIOSurface> MacIOSurface::LookupSurface(IOSurfaceID aIOSurfaceID,
-                                                       double aContentsScaleFactor,
-                                                       bool aHasAlpha) { 
-  if (!MacIOSurfaceLib::isInit() || aContentsScaleFactor <= 0)
-    return nullptr;
-
-  IOSurfacePtr surfaceRef = MacIOSurfaceLib::IOSurfaceLookup(aIOSurfaceID);
-  if (!surfaceRef)
-    return nullptr;
-
-  RefPtr<MacIOSurface> ioSurface = new MacIOSurface(surfaceRef, aContentsScaleFactor, aHasAlpha);
-  if (!ioSurface) {
-    ::CFRelease(surfaceRef);
-    return nullptr;
-  }
-  return ioSurface.forget();
-}
-
-IOSurfaceID MacIOSurface::GetIOSurfaceID() { 
-  return MacIOSurfaceLib::IOSurfaceGetID(mIOSurfacePtr);
-}
-
-void* MacIOSurface::GetBaseAddress() { 
-  return MacIOSurfaceLib::IOSurfaceGetBaseAddress(mIOSurfacePtr);
-}
-
-size_t MacIOSurface::GetWidth() {
-  size_t intScaleFactor = ceil(mContentsScaleFactor);
-  return GetDevicePixelWidth() / intScaleFactor;
-}
-
-size_t MacIOSurface::GetHeight() {
-  size_t intScaleFactor = ceil(mContentsScaleFactor);
-  return GetDevicePixelHeight() / intScaleFactor;
-}
-
-size_t MacIOSurface::GetDevicePixelWidth() {
-  return MacIOSurfaceLib::IOSurfaceGetWidth(mIOSurfacePtr);
-}
-
-size_t MacIOSurface::GetDevicePixelHeight() {
-  return MacIOSurfaceLib::IOSurfaceGetHeight(mIOSurfacePtr);
-}
-
-size_t MacIOSurface::GetBytesPerRow() { 
-  return MacIOSurfaceLib::IOSurfaceGetBytesPerRow(mIOSurfacePtr);
-}
-
-#define READ_ONLY 0x1
-void MacIOSurface::Lock() {
-  MacIOSurfaceLib::IOSurfaceLock(mIOSurfacePtr, READ_ONLY, nullptr);
-}
-
-void MacIOSurface::Unlock() {
-  MacIOSurfaceLib::IOSurfaceUnlock(mIOSurfacePtr, READ_ONLY, nullptr);
-}
-
-#include "SourceSurfaceRawData.h"
-using mozilla::gfx::SourceSurface;
-using mozilla::gfx::SourceSurfaceRawData;
-using mozilla::gfx::IntSize;
-using mozilla::gfx::SurfaceFormat;
-
-TemporaryRef<SourceSurface>
-MacIOSurface::GetAsSurface() {
-  Lock();
-  size_t bytesPerRow = GetBytesPerRow();
-  size_t ioWidth = GetDevicePixelWidth();
-  size_t ioHeight = GetDevicePixelHeight();
-
-  unsigned char* ioData = (unsigned char*)GetBaseAddress();
-  unsigned char* dataCpy = (unsigned char*)malloc(bytesPerRow*ioHeight);
-  for (size_t i = 0; i < ioHeight; i++) {
-    memcpy(dataCpy + i * bytesPerRow,
-           ioData + i * bytesPerRow, ioWidth * 4);
-  }
-
-  Unlock();
-
-  SurfaceFormat format = HasAlpha() ? mozilla::gfx::FORMAT_B8G8R8A8 :
-                                      mozilla::gfx::FORMAT_B8G8R8X8;
-
-  RefPtr<SourceSurfaceRawData> surf = new SourceSurfaceRawData();
-  surf->InitWrappingData(dataCpy, IntSize(ioWidth, ioHeight), bytesPerRow, format, true);
-
-  return surf.forget();
-}
-
-CGLError 
-MacIOSurface::CGLTexImageIOSurface2D(void *c)
-{
-  NSOpenGLContext *ctxt = static_cast<NSOpenGLContext*>(c);
-  return MacIOSurfaceLib::CGLTexImageIOSurface2D((CGLContextObj)[ctxt CGLContextObj],
-                                                GL_TEXTURE_RECTANGLE_ARB,
-                                                HasAlpha() ? LOCAL_GL_RGBA : LOCAL_GL_RGB,
-                                                GetDevicePixelWidth(),
-                                                GetDevicePixelHeight(),
-                                                LOCAL_GL_BGRA,
-                                                LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV,
-                                                mIOSurfacePtr, 0);
-}
-
 CGColorSpaceRef CreateSystemColorSpace() {
   CGColorSpaceRef cspace = ::CGDisplayCopyColorSpace(::CGMainDisplayID());
   if (!cspace) {
     cspace = ::CGColorSpaceCreateDeviceRGB();
   }
   return cspace;
 }
 
-CGContextRef MacIOSurface::CreateIOSurfaceContext() {
-  CGColorSpaceRef cspace = CreateSystemColorSpace();
-  CGContextRef ref = MacIOSurfaceLib::IOSurfaceContextCreate(mIOSurfacePtr,
-                                                GetDevicePixelWidth(),
-                                                GetDevicePixelHeight(),
-                                                8, 32, cspace, 0x2002);
-  ::CGColorSpaceRelease(cspace);
-  return ref;
-}
-
 nsCARenderer::~nsCARenderer() {
   Destroy();
 }
 
 void cgdata_release_callback(void *aCGData, const void *data, size_t size) {
   if (aCGData) {
     free(aCGData);
   }
@@ -1062,54 +623,8 @@ void nsCARenderer::SaveToDisk(MacIOSurfa
 
   surf->Unlock();
 
   return;
 
 }
 
 #endif
-
-CGImageRef MacIOSurface::CreateImageFromIOSurfaceContext(CGContextRef aContext) {
-  if (!MacIOSurfaceLib::isInit())
-    return nullptr;
-
-  return MacIOSurfaceLib::IOSurfaceContextCreateImage(aContext);
-}
-
-TemporaryRef<MacIOSurface> MacIOSurface::IOSurfaceContextGetSurface(CGContextRef aContext,
-                                                                    double aContentsScaleFactor,
-                                                                    bool aHasAlpha) {
-  if (!MacIOSurfaceLib::isInit() || aContentsScaleFactor <= 0)
-    return nullptr;
-
-  IOSurfacePtr surfaceRef = MacIOSurfaceLib::IOSurfaceContextGetSurface(aContext);
-  if (!surfaceRef)
-    return nullptr;
-
-  // Retain the IOSurface because MacIOSurface will release it
-  CFRetain(surfaceRef);
-
-  RefPtr<MacIOSurface> ioSurface = new MacIOSurface(surfaceRef, aContentsScaleFactor, aHasAlpha);
-  if (!ioSurface) {
-    ::CFRelease(surfaceRef);
-    return nullptr;
-  }
-  return ioSurface.forget();
-}
-
-
-CGContextType GetContextType(CGContextRef ref)
-{
-  if (!MacIOSurfaceLib::isInit() || !MacIOSurfaceLib::sCGContextGetTypePtr)
-    return CG_CONTEXT_TYPE_UNKNOWN;
-
-  unsigned int type = MacIOSurfaceLib::sCGContextGetTypePtr(ref);
-  if (type == CG_CONTEXT_TYPE_BITMAP) {
-    return CG_CONTEXT_TYPE_BITMAP;
-  } else if (type == CG_CONTEXT_TYPE_IOSURFACE) {
-    return CG_CONTEXT_TYPE_IOSURFACE;
-  } else {
-    return CG_CONTEXT_TYPE_UNKNOWN;
-  }
-}
-
-
--- a/gfx/2d/SourceSurfaceCG.cpp
+++ b/gfx/2d/SourceSurfaceCG.cpp
@@ -1,17 +1,17 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * 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 "SourceSurfaceCG.h"
 #include "DrawTargetCG.h"
 
-#include "QuartzSupport.h"
+#include "MacIOSurface.h"
 #include "Tools.h"
 
 namespace mozilla {
 namespace gfx {
 
 
 SourceSurfaceCG::~SourceSurfaceCG()
 {
--- a/gfx/2d/moz.build
+++ b/gfx/2d/moz.build
@@ -97,16 +97,17 @@ SOURCES += [
     'ScaledFontBase.cpp',
     'ScaledFontCairo.cpp',
     'SourceSurfaceCairo.cpp',
     'SourceSurfaceRawData.cpp',
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
     SOURCES += [
+        'MacIOSurface.cpp',
         'QuartzSupport.mm',
     ]
 
 FAIL_ON_WARNINGS = True
 
 LIBXUL_LIBRARY = True
 
 MSVC_ENABLE_PGO = True
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -2424,16 +2424,17 @@ public:
         // MarkDestroyed will mark all these as null.
         return mSymbols.fUseProgram == nullptr;
     }
 
     enum NativeDataType {
       NativeGLContext,
       NativeImageSurface,
       NativeThebesSurface,
+      NativeCGLContext,
       NativeDataTypeMax
     };
 
     virtual void *GetNativeData(NativeDataType aType) { return nullptr; }
     GLContext *GetSharedContext() { return mSharedContext; }
 
     bool IsGlobalSharedContext() { return mIsGlobalSharedContext; }
     void SetIsGlobalSharedContext(bool aIsOne) { mIsGlobalSharedContext = aIsOne; }
--- a/gfx/gl/GLContextProviderCGL.mm
+++ b/gfx/gl/GLContextProviderCGL.mm
@@ -128,17 +128,18 @@ public:
         return true;
     }
 
     void *GetNativeData(NativeDataType aType)
     { 
         switch (aType) {
         case NativeGLContext:
             return mContext;
-
+        case NativeCGLContext:
+            return [mContext CGLContextObj];
         default:
             return nullptr;
         }
     }
 
     bool MakeCurrentImpl(bool aForce = false)
     {
         if (!aForce && [NSOpenGLContext currentContext] == mContext) {
--- a/gfx/gl/SharedSurfaceIO.cpp
+++ b/gfx/gl/SharedSurfaceIO.cpp
@@ -71,20 +71,20 @@ SharedSurface_IOSurface::SharedSurface_I
                         LOCAL_GL_LINEAR);
     mGL->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB,
                         LOCAL_GL_TEXTURE_WRAP_S,
                         LOCAL_GL_CLAMP_TO_EDGE);
     mGL->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB,
                         LOCAL_GL_TEXTURE_WRAP_T,
                         LOCAL_GL_CLAMP_TO_EDGE);
 
-    void *nativeCtx = mGL->GetNativeData(GLContext::NativeGLContext);
-    MOZ_ASSERT(nativeCtx);
+    CGLContextObj ctx = static_cast<CGLContextObj>(mGL->GetNativeData(GLContext::NativeCGLContext));
+    MOZ_ASSERT(ctx);
 
-    surface->CGLTexImageIOSurface2D(nativeCtx);
+    surface->CGLTexImageIOSurface2D(ctx);
 }
 
 SharedSurface_IOSurface::~SharedSurface_IOSurface()
 {
     if (mTexture) {
         DebugOnly<bool> success = mGL->MakeCurrent();
         MOZ_ASSERT(success);
         mGL->fDeleteTextures(1, &mTexture);
--- a/gfx/layers/opengl/CanvasLayerOGL.cpp
+++ b/gfx/layers/opengl/CanvasLayerOGL.cpp
@@ -98,19 +98,18 @@ MakeIOSurfaceTexture(void* aCGIOSurfaceC
   aGL->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, ioSurfaceTexture);
 
   aGL->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR);
   aGL->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR);
   aGL->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
   aGL->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
 
   RefPtr<MacIOSurface> ioSurface = MacIOSurface::IOSurfaceContextGetSurface((CGContextRef)aCGIOSurfaceContext);
-  void *nativeCtx = aGL->GetNativeData(GLContext::NativeGLContext);
 
-  ioSurface->CGLTexImageIOSurface2D(nativeCtx);
+  ioSurface->CGLTexImageIOSurface2D(static_cast<CGLContextObj>(aGL->GetNativeData(GLContext::NativeCGLContext)));
 
   aGL->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
 
   return ioSurfaceTexture;
 }
 #endif
 
 void
--- a/gfx/layers/opengl/TextureHostOGL.cpp
+++ b/gfx/layers/opengl/TextureHostOGL.cpp
@@ -477,18 +477,17 @@ MacIOSurfaceTextureSourceOGL::BindTextur
   if (!gl()) {
     NS_WARNING("Trying to bind a texture without a GLContext");
     return;
   }
   GLuint tex = mCompositor->GetTemporaryTexture(aTextureUnit);
 
   gl()->fActiveTexture(aTextureUnit);
   gl()->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, tex);
-  void *nativeGL = gl()->GetNativeData(gl::GLContext::NativeGLContext);
-  mSurface->CGLTexImageIOSurface2D(nativeGL);
+  mSurface->CGLTexImageIOSurface2D(static_cast<CGLContextObj>(gl()->GetNativeData(GLContext::NativeCGLContext)));
   gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
 }
 
 gl::GLContext*
 MacIOSurfaceTextureSourceOGL::gl() const
 {
   return mCompositor ? mCompositor->gl() : nullptr;
 }
new file mode 100644
--- /dev/null
+++ b/gfx/thebes/gfxGradientCache.cpp
@@ -0,0 +1,215 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 "mozilla/gfx/2D.h"
+#include "nsTArray.h"
+#include "pldhash.h"
+#include "nsExpirationTracker.h"
+#include "nsClassHashtable.h"
+#include "mozilla/Telemetry.h"
+#include "gfxGradientCache.h"
+#include <time.h>
+
+namespace mozilla {
+namespace gfx {
+
+using namespace mozilla;
+
+struct GradientCacheKey : public PLDHashEntryHdr {
+  typedef const GradientCacheKey& KeyType;
+  typedef const GradientCacheKey* KeyTypePointer;
+  enum { ALLOW_MEMMOVE = true };
+  const nsTArray<GradientStop> mStops;
+  ExtendMode mExtend;
+  BackendType mBackendType;
+
+  GradientCacheKey(const nsTArray<GradientStop>& aStops, ExtendMode aExtend, BackendType aBackendType)
+    : mStops(aStops), mExtend(aExtend), mBackendType(aBackendType)
+  { }
+
+  GradientCacheKey(const GradientCacheKey* aOther)
+    : mStops(aOther->mStops), mExtend(aOther->mExtend), mBackendType(aOther->mBackendType)
+  { }
+
+  union FloatUint32
+  {
+    float    f;
+    uint32_t u;
+  };
+
+  static PLDHashNumber
+  HashKey(const KeyTypePointer aKey)
+  {
+    PLDHashNumber hash = 0;
+    FloatUint32 convert;
+    hash = AddToHash(hash, aKey->mBackendType);
+    hash = AddToHash(hash, aKey->mExtend);
+    for (uint32_t i = 0; i < aKey->mStops.Length(); i++) {
+      hash = AddToHash(hash, aKey->mStops[i].color.ToABGR());
+      // Use the float bits as hash, except for the cases of 0.0 and -0.0 which both map to 0
+      convert.f = aKey->mStops[i].offset;
+      hash = AddToHash(hash, convert.f ? convert.u : 0);
+    }
+    return hash;
+  }
+
+  bool KeyEquals(KeyTypePointer aKey) const
+  {
+    bool sameStops = true;
+    if (aKey->mStops.Length() != mStops.Length()) {
+      sameStops = false;
+    } else {
+      for (uint32_t i = 0; i < mStops.Length(); i++) {
+        if (mStops[i].color.ToABGR() != aKey->mStops[i].color.ToABGR() ||
+            mStops[i].offset != aKey->mStops[i].offset) {
+          sameStops = false;
+          break;
+        }
+      }
+    }
+
+    return sameStops &&
+           (aKey->mBackendType == mBackendType) &&
+           (aKey->mExtend == mExtend);
+  }
+  static KeyTypePointer KeyToPointer(KeyType aKey)
+  {
+    return &aKey;
+  }
+};
+
+/**
+ * This class is what is cached. It need to be allocated in an object separated
+ * to the cache entry to be able to be tracked by the nsExpirationTracker.
+ * */
+struct GradientCacheData {
+  GradientCacheData(GradientStops* aStops, const GradientCacheKey& aKey)
+    : mStops(aStops),
+      mKey(aKey)
+  {}
+
+  GradientCacheData(const GradientCacheData& aOther)
+    : mStops(aOther.mStops),
+      mKey(aOther.mKey)
+  { }
+
+  nsExpirationState *GetExpirationState() {
+    return &mExpirationState;
+  }
+
+  nsExpirationState mExpirationState;
+  const RefPtr<GradientStops> mStops;
+  GradientCacheKey mKey;
+};
+
+/**
+ * This class implements a cache with no maximum size, that retains the
+ * gfxPatterns used to draw the gradients.
+ *
+ * The key is the nsStyleGradient that defines the gradient, and the size of the
+ * gradient.
+ *
+ * The value is the gfxPattern, and whether or not we perform an optimization
+ * based on the actual gradient property.
+ *
+ * An entry stays in the cache as long as it is used often. As long as a cache
+ * entry is in the cache, all the references it has are guaranteed to be valid:
+ * the nsStyleRect for the key, the gfxPattern for the value.
+ */
+class GradientCache MOZ_FINAL : public nsExpirationTracker<GradientCacheData,4>
+{
+  public:
+    GradientCache()
+      : nsExpirationTracker<GradientCacheData, 4>(MAX_GENERATION_MS)
+    {
+      srand(time(nullptr));
+      mTimerPeriod = rand() % MAX_GENERATION_MS + 1;
+      Telemetry::Accumulate(Telemetry::GRADIENT_RETENTION_TIME, mTimerPeriod);
+    }
+
+    virtual void NotifyExpired(GradientCacheData* aObject)
+    {
+      // This will free the gfxPattern.
+      RemoveObject(aObject);
+      mHashEntries.Remove(aObject->mKey);
+    }
+
+    GradientCacheData* Lookup(const nsTArray<GradientStop>& aStops, ExtendMode aExtend, BackendType aBackendType)
+    {
+      GradientCacheData* gradient =
+        mHashEntries.Get(GradientCacheKey(aStops, aExtend, aBackendType));
+
+      if (gradient) {
+        MarkUsed(gradient);
+      }
+
+      return gradient;
+    }
+
+    // Returns true if we successfully register the gradient in the cache, false
+    // otherwise.
+    bool RegisterEntry(GradientCacheData* aValue)
+    {
+      nsresult rv = AddObject(aValue);
+      if (NS_FAILED(rv)) {
+        // We are OOM, and we cannot track this object. We don't want stall
+        // entries in the hash table (since the expiration tracker is responsible
+        // for removing the cache entries), so we avoid putting that entry in the
+        // table, which is a good things considering we are short on memory
+        // anyway, we probably don't want to retain things.
+        return false;
+      }
+      mHashEntries.Put(aValue->mKey, aValue);
+      return true;
+    }
+
+  protected:
+    uint32_t mTimerPeriod;
+    static const uint32_t MAX_GENERATION_MS = 10000;
+    /**
+     * FIXME use nsTHashtable to avoid duplicating the GradientCacheKey.
+     * https://bugzilla.mozilla.org/show_bug.cgi?id=761393#c47
+     */
+    nsClassHashtable<GradientCacheKey, GradientCacheData> mHashEntries;
+};
+
+static GradientCache* gGradientCache = nullptr;
+
+GradientStops *
+gfxGradientCache::GetGradientStops(DrawTarget *aDT, nsTArray<GradientStop>& aStops, ExtendMode aExtend)
+{
+  if (!gGradientCache) {
+    gGradientCache = new GradientCache();
+  }
+  GradientCacheData* cached = gGradientCache->Lookup(aStops, aExtend, aDT->GetType());
+  return cached ? cached->mStops : nullptr;
+}
+
+GradientStops *
+gfxGradientCache::GetOrCreateGradientStops(DrawTarget *aDT, nsTArray<GradientStop>& aStops, ExtendMode aExtend)
+{
+  RefPtr<GradientStops> gs = GetGradientStops(aDT, aStops, aExtend);
+  if (!gs) {
+    gs = aDT->CreateGradientStops(aStops.Elements(), aStops.Length(), aExtend);
+    if (!gs) {
+      return nullptr;
+    }
+    GradientCacheData *cached = new GradientCacheData(gs, GradientCacheKey(aStops, aExtend, aDT->GetType()));
+    if (!gGradientCache->RegisterEntry(cached)) {
+      delete cached;
+    }
+  }
+  return gs;
+}
+
+void
+gfxGradientCache::Shutdown()
+{
+  delete gGradientCache;
+  gGradientCache = nullptr;
+}
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/gfx/thebes/gfxGradientCache.h
@@ -0,0 +1,32 @@
+
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 GFX_GRADIENT_CACHE_H
+#define GFX_GRADIENT_CACHE_H
+
+#include "nsTArray.h"
+#include "gfxPattern.h"
+#include "mozilla/gfx/2D.h"
+
+namespace mozilla {
+namespace gfx {
+
+class gfxGradientCache {
+public:
+  static gfx::GradientStops *GetGradientStops(gfx::DrawTarget *aDT,
+					      nsTArray<gfx::GradientStop>& aStops,
+					      gfx::ExtendMode aExtend);
+  static gfx::GradientStops *GetOrCreateGradientStops(gfx::DrawTarget *aDT,
+						      nsTArray<gfx::GradientStop>& aStops,
+						      gfx::ExtendMode aExtend);
+
+  static void Shutdown();
+};
+
+}
+}
+
+#endif
--- a/gfx/thebes/gfxPattern.cpp
+++ b/gfx/thebes/gfxPattern.cpp
@@ -3,16 +3,17 @@
  * 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 "gfxTypes.h"
 #include "gfxPattern.h"
 #include "gfxASurface.h"
 #include "gfxPlatform.h"
 #include "gfx2DGlue.h"
+#include "gfxGradientCache.h"
 
 #include "cairo.h"
 
 #include <vector>
 
 using namespace mozilla::gfx;
 
 gfxPattern::gfxPattern(cairo_pattern_t *aPattern)
@@ -98,16 +99,39 @@ gfxPattern::AddColorStop(gfxFloat offset
 
 void
 gfxPattern::SetColorStops(mozilla::RefPtr<mozilla::gfx::GradientStops> aStops)
 {
   mStops = aStops;
 }
 
 void
+gfxPattern::CacheColorStops(mozilla::gfx::DrawTarget *aDT)
+{
+  if (mPattern) {
+    mStops = nullptr;
+    nsTArray<GradientStop> stops;
+    int count = 0;
+    cairo_pattern_get_color_stop_count(mPattern, &count);
+    stops.SetLength(count);
+    for (int n = 0; n < count; ++n) {
+      double offset, r, g, b, a;
+      cairo_pattern_get_color_stop_rgba(mPattern, n, &offset, &r, &g, &b, &a);
+      stops[n].color = mozilla::gfx::Color(r, g, b, a);
+      stops[n].offset = offset;
+    }
+    mStops = gfxGradientCache::GetOrCreateGradientStops(aDT,
+                                                        stops,
+                                                        (cairo_pattern_get_extend(mPattern) == CAIRO_EXTEND_REPEAT)
+                                                        ? mozilla::gfx::EXTEND_REPEAT
+                                                        : mozilla::gfx::EXTEND_CLAMP);
+  }
+}
+
+void
 gfxPattern::SetMatrix(const gfxMatrix& matrix)
 {
   if (mPattern) {
     cairo_matrix_t mat = *reinterpret_cast<const cairo_matrix_t*>(&matrix);
     cairo_pattern_set_matrix(mPattern, &mat);
   } else {
     mTransform = ToMatrix(matrix);
     // Cairo-pattern matrices specify the conversion from DrawTarget to pattern
--- a/gfx/thebes/gfxPattern.h
+++ b/gfx/thebes/gfxPattern.h
@@ -9,16 +9,17 @@
 #include "gfxTypes.h"
 
 #include "gfxMatrix.h"
 #include "mozilla/Alignment.h"
 #include "mozilla/gfx/2D.h"
 #include "GraphicsFilter.h"
 #include "nsISupportsImpl.h"
 #include "nsAutoPtr.h"
+#include "nsTArray.h"
 
 class gfxContext;
 class gfxASurface;
 struct gfxRGBA;
 typedef struct _cairo_pattern cairo_pattern_t;
 
 
 class gfxPattern {
@@ -35,16 +36,21 @@ public:
     gfxPattern(mozilla::gfx::SourceSurface *aSurface,
                const mozilla::gfx::Matrix &aTransform); // Azure
     virtual ~gfxPattern();
 
     cairo_pattern_t *CairoPattern();
     void AddColorStop(gfxFloat offset, const gfxRGBA& c);
     void SetColorStops(mozilla::RefPtr<mozilla::gfx::GradientStops> aStops);
 
+    // This should only be called on a cairo pattern that we want to use with
+    // Azure. We will read back the color stops from cairo and try to look
+    // them up in the cache.
+    void CacheColorStops(mozilla::gfx::DrawTarget *aDT);
+
     void SetMatrix(const gfxMatrix& matrix);
     gfxMatrix GetMatrix() const;
     gfxMatrix GetInverseMatrix() const;
 
     /* Get an Azure Pattern for the current Cairo pattern. aPattern transform
      * specifies the transform that was set on the DrawTarget when the pattern
      * was set. When this is nullptr it is assumed the transform is identical
      * to the current transform.
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -43,16 +43,17 @@
 #include "nsGkAtoms.h"
 #include "gfxPlatformFontList.h"
 #include "gfxContext.h"
 #include "gfxImageSurface.h"
 #include "nsUnicodeProperties.h"
 #include "harfbuzz/hb.h"
 #include "gfxGraphiteShaper.h"
 #include "gfx2DGlue.h"
+#include "gfxGradientCache.h"
 
 #include "nsUnicodeRange.h"
 #include "nsServiceManagerUtils.h"
 #include "nsTArray.h"
 #include "nsILocaleService.h"
 #include "nsIObserverService.h"
 
 #include "nsWeakReference.h"
@@ -498,16 +499,17 @@ gfxPlatform::Init()
 
 void
 gfxPlatform::Shutdown()
 {
     // These may be called before the corresponding subsystems have actually
     // started up. That's OK, they can handle it.
     gfxFontCache::Shutdown();
     gfxFontGroup::Shutdown();
+    gfxGradientCache::Shutdown();
     gfxGraphiteShaper::Shutdown();
 #if defined(XP_MACOSX) || defined(XP_WIN) // temporary, until this is implemented on others
     gfxPlatformFontList::Shutdown();
 #endif
 
     // Free the various non-null transforms and loaded profiles
     ShutdownCMS();
 
--- a/gfx/thebes/moz.build
+++ b/gfx/thebes/moz.build
@@ -19,16 +19,17 @@ EXPORTS += [
     'gfxContext.h',
     'gfxDrawable.h',
     'gfxFailure.h',
     'gfxFont.h',
     'gfxFontConstants.h',
     'gfxFontFeatures.h',
     'gfxFontTest.h',
     'gfxFontUtils.h',
+    'gfxGradientCache.h',
     'gfxImageSurface.h',
     'gfxLineSegment.h',
     'gfxMatrix.h',
     'gfxPath.h',
     'gfxPattern.h',
     'gfxPlatform.h',
     'gfxPoint.h',
     'gfxPoint3D.h',
@@ -240,16 +241,17 @@ SOURCES += [
     'gfxCachedTempSurface.cpp',
     'gfxContext.cpp',
     'gfxDrawable.cpp',
     'gfxFont.cpp',
     'gfxFontFeatures.cpp',
     'gfxFontMissingGlyphs.cpp',
     'gfxFontTest.cpp',
     'gfxFontUtils.cpp',
+    'gfxGradientCache.cpp',
     'gfxGraphiteShaper.cpp',
     'gfxHarfBuzzShaper.cpp',
     'gfxImageSurface.cpp',
     'gfxMatrix.cpp',
     'gfxPath.cpp',
     'gfxPattern.cpp',
     'gfxPlatform.cpp',
     'gfxPlatformFontList.cpp',
--- a/js/public/Utility.h
+++ b/js/public/Utility.h
@@ -95,16 +95,18 @@ PrintBacktrace()
 
     if (!OOM_traceSymbols)
         return;
 
     for (OOM_traceIdx = 0; OOM_traceIdx < OOM_traceSize; ++OOM_traceIdx) {
         fprintf(stderr, "#%d %s\n", OOM_traceIdx, OOM_traceSymbols[OOM_traceIdx]);
     }
 
+    // This must be free(), not js_free(), because backtrace_symbols()
+    // allocates with malloc().
     free(OOM_traceSymbols);
 }
 
 #define JS_OOM_EMIT_BACKTRACE() \
     do {\
         fprintf(stderr, "Forcing artificial memory allocation function failure:\n");\
 	PrintBacktrace();\
     } while (0)
--- a/js/src/NamespaceImports.h
+++ b/js/src/NamespaceImports.h
@@ -80,16 +80,18 @@ using JS::AutoHashSetRooter;
 using JS::AutoVectorRooter;
 
 using JS::CallArgs;
 using JS::CallNonGenericMethod;
 using JS::CallReceiver;
 using JS::CompileOptions;
 using JS::IsAcceptableThis;
 using JS::NativeImpl;
+using JS::OwningCompileOptions;
+using JS::ReadOnlyCompileOptions;
 
 using JS::Rooted;
 using JS::RootedFunction;
 using JS::RootedId;
 using JS::RootedObject;
 using JS::RootedScript;
 using JS::RootedString;
 using JS::RootedValue;
--- a/js/src/TraceLogging.cpp
+++ b/js/src/TraceLogging.cpp
@@ -104,30 +104,30 @@ TraceLogging::TraceLogging(Logger id)
 {
     textMap.init();
 }
 
 TraceLogging::~TraceLogging()
 {
     if (entries) {
         flush();
-        free(entries);
+        js_free(entries);
         entries = nullptr;
     }
 
     if (out) {
         fclose(out);
         out = nullptr;
     }
 }
 
 void
 TraceLogging::grow()
 {
-    Entry* nentries = (Entry*) realloc(entries, numEntries*2*sizeof(Entry));
+    Entry* nentries = (Entry*) js_realloc(entries, numEntries*2*sizeof(Entry));
 
     // Allocating a bigger array failed.
     // Keep using the current storage, but remove all entries by flushing them.
     if (!nentries) {
         flush();
         return;
     }
 
@@ -137,17 +137,17 @@ TraceLogging::grow()
 
 void
 TraceLogging::log(Type type, const char* text /* = nullptr */, unsigned int number /* = 0 */)
 {
     uint64_t now = rdtsc() - startupTime;
 
     // Create array containing the entries if not existing.
     if (!entries) {
-        entries = (Entry*) malloc(numEntries*sizeof(Entry));
+        entries = (Entry*) js_malloc(numEntries*sizeof(Entry));
         if (!entries)
             return;
     }
 
     uint32_t textId = 0;
     char *text_ = nullptr;
 
     if (text) {
@@ -168,17 +168,17 @@ TraceLogging::log(Type type, const char*
     entries[curEntry++] = Entry(now, text_, textId, number, type);
 
     // Increase length when not enough place in the array
     if (curEntry >= numEntries)
         grow();
 }
 
 void
-TraceLogging::log(Type type, const JS::CompileOptions &options)
+TraceLogging::log(Type type, const JS::ReadOnlyCompileOptions &options)
 {
     this->log(type, options.filename, options.lineno);
 }
 
 void
 TraceLogging::log(Type type, JSScript* script)
 {
     this->log(type, script->filename(), script->lineno);
@@ -243,17 +243,17 @@ TraceLogging::flush()
         if (written < 0) {
             fprintf(stderr, "Writing tracelog to disk failed,");
             fprintf(stderr, "probably because the file would've exceeded the maximum size of 2GB");
             fclose(out);
             exit(-1);
         }
 
         if (entries[i].text() != nullptr) {
-            free(entries[i].text());
+            js_free(entries[i].text());
             entries[i].text_ = nullptr;
         }
     }
     curEntry = 0;
 }
 
 TraceLogging*
 TraceLogging::getLogger(Logger id)
--- a/js/src/TraceLogging.h
+++ b/js/src/TraceLogging.h
@@ -11,17 +11,17 @@
 #include <stdio.h>
 
 #include "jsalloc.h"
 
 #include "js/HashTable.h"
 #include "js/TypeDecls.h"
 
 namespace JS {
-class CompileOptions;
+class ReadOnlyCompileOptions;
 }
 
 namespace js {
 
 class TraceLogging
 {
   public:
     enum Type {
@@ -98,17 +98,17 @@ class TraceLogging
     static const char * const typeName[];
     static TraceLogging* loggers[];
     static uint64_t startupTime;
   public:
     TraceLogging(Logger id);
     ~TraceLogging();
 
     void log(Type type, const char* text = nullptr, unsigned int number = 0);
-    void log(Type type, const JS::CompileOptions &options);
+    void log(Type type, const JS::ReadOnlyCompileOptions &options);
     void log(Type type, JSScript* script);
     void log(const char* log);
     void flush();
 
     static TraceLogging* getLogger(Logger id);
     static TraceLogging* defaultLogger() {
         return getLogger(DEFAULT);
     }
@@ -125,17 +125,17 @@ void TraceLog(TraceLogging* logger, Trac
 
 /* Automatic logging at the start and end of function call */
 class AutoTraceLog {
     TraceLogging* logger;
     TraceLogging::Type stop;
 
   public:
     AutoTraceLog(TraceLogging* logger, TraceLogging::Type start, TraceLogging::Type stop,
-                 const JS::CompileOptions &options)
+                 const JS::ReadOnlyCompileOptions &options)
       : logger(logger),
         stop(stop)
     {
         logger->log(start, options);
     }
 
     AutoTraceLog(TraceLogging* logger, TraceLogging::Type start, TraceLogging::Type stop,
                  JSScript* script)
--- a/js/src/assembler/assembler/AssemblerBuffer.h
+++ b/js/src/assembler/assembler/AssemblerBuffer.h
@@ -65,17 +65,17 @@ namespace JSC {
             , m_size(0)
             , m_oom(false)
         {
         }
 
         ~AssemblerBuffer()
         {
             if (m_buffer != m_inlineBuffer)
-                free(m_buffer);
+                js_free(m_buffer);
         }
 
         void ensureSpace(int space)
         {
             if (m_size > m_capacity - space)
                 grow();
         }
 
@@ -217,25 +217,25 @@ namespace JSC {
             // Assembler-shared.h.
             if (newCapacity >= INT_MAX / 2) {
                 m_size = 0;
                 m_oom = true;
                 return;
             }
 
             if (m_buffer == m_inlineBuffer) {
-                newBuffer = static_cast<char*>(malloc(newCapacity));
+                newBuffer = static_cast<char*>(js_malloc(newCapacity));
                 if (!newBuffer) {
                     m_size = 0;
                     m_oom = true;
                     return;
                 }
                 memcpy(newBuffer, m_buffer, m_size);
             } else {
-                newBuffer = static_cast<char*>(realloc(m_buffer, newCapacity));
+                newBuffer = static_cast<char*>(js_realloc(m_buffer, newCapacity));
                 if (!newBuffer) {
                     m_size = 0;
                     m_oom = true;
                     return;
                 }
             }
 
             m_buffer = newBuffer;
--- a/js/src/assembler/assembler/AssemblerBufferWithConstantPool.h
+++ b/js/src/assembler/assembler/AssemblerBufferWithConstantPool.h
@@ -101,24 +101,24 @@ public:
 
     AssemblerBufferWithConstantPool()
         : AssemblerBuffer()
         , m_numConsts(0)
         , m_maxDistance(maxPoolSize)
         , m_lastConstDelta(0)
         , m_flushCount(0)
     {
-        m_pool = static_cast<uint32_t*>(malloc(maxPoolSize));
-        m_mask = static_cast<char*>(malloc(maxPoolSize / sizeof(uint32_t)));
+        m_pool = static_cast<uint32_t*>(js_malloc(maxPoolSize));
+        m_mask = static_cast<char*>(js_malloc(maxPoolSize / sizeof(uint32_t)));
     }
 
     ~AssemblerBufferWithConstantPool()
     {
-        free(m_mask);
-        free(m_pool);
+        js_free(m_mask);
+        js_free(m_pool);
     }
 
     void ensureSpace(int space)
     {
         flushIfNoSpaceFor(space);
         AssemblerBuffer::ensureSpace(space);
     }
 
--- a/js/src/builtin/Profilers.cpp
+++ b/js/src/builtin/Profilers.cpp
@@ -514,20 +514,25 @@ bool js_StartPerf()
         Vector<const char*, 0, SystemAllocPolicy> args;
         args.append(defaultArgs, ArrayLength(defaultArgs));
 
         const char *flags = getenv("MOZ_PROFILE_PERF_FLAGS");
         if (!flags) {
             flags = "--call-graph";
         }
 
-        // Split |flags| on spaces.  (Don't bother to free it -- we're going to
+        char *flags2 = (char *)js_malloc(strlen(flags) + 1);
+        if (!flags2)
+            return false;
+        strcpy(flags2, flags);
+
+        // Split |flags2| on spaces.  (Don't bother to free it -- we're going to
         // exec anyway.)
         char *toksave;
-        char *tok = strtok_r(strdup(flags), " ", &toksave);
+        char *tok = strtok_r(flags2, " ", &toksave);
         while (tok) {
             args.append(tok);
             tok = strtok_r(nullptr, " ", &toksave);
         }
 
         args.append((char*) nullptr);
 
         execvp("perf", const_cast<char**>(args.begin()));
--- a/js/src/config/rules.mk
+++ b/js/src/config/rules.mk
@@ -1368,17 +1368,17 @@ endif
 
 ifneq ($(DIST_CHROME_FILES),)
 DIST_CHROME_FILES_PATH := $(FINAL_TARGET)/chrome
 DIST_CHROME_FILES_FLAGS := $(XULAPP_DEFINES)
 PP_TARGETS += DIST_CHROME_FILES
 endif
 
 ifneq ($(XPI_PKGNAME),)
-libs realchrome::
+tools realchrome::
 ifdef STRIP_XPI
 ifndef MOZ_DEBUG
 	@echo "Stripping $(XPI_PKGNAME) package directory..."
 	@echo $(FINAL_TARGET)
 	@cd $(FINAL_TARGET) && find . ! -type d \
 			! -name "*.js" \
 			! -name "*.xpt" \
 			! -name "*.gif" \
@@ -1407,17 +1407,17 @@ endif
 	cd $(FINAL_TARGET) && $(ZIP) -qr ../$(XPI_PKGNAME).xpi *
 endif
 
 ifdef INSTALL_EXTENSION_ID
 ifndef XPI_NAME
 $(error XPI_NAME must be set for INSTALL_EXTENSION_ID)
 endif
 
-libs::
+tools::
 	$(RM) -r "$(DIST)/bin$(DIST_SUBDIR:%=/%)/extensions/$(INSTALL_EXTENSION_ID)"
 	$(NSINSTALL) -D "$(DIST)/bin$(DIST_SUBDIR:%=/%)/extensions/$(INSTALL_EXTENSION_ID)"
 	$(call copy_dir,$(FINAL_TARGET),$(DIST)/bin$(DIST_SUBDIR:%=/%)/extensions/$(INSTALL_EXTENSION_ID))
 
 endif
 
 #############################################################################
 # MDDEPDIR is the subdirectory where all the dependency files are placed.
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -2911,17 +2911,17 @@ MOZ_ARG_WITH_STRING(nspr-libs,
 AC_SUBST(NSPR_CFLAGS)
 AC_SUBST(NSPR_LIBS)
 
 if test "$_USE_SYSTEM_NSPR" || (test "$NSPR_CFLAGS" -o "$NSPR_LIBS"); then
   _HAS_NSPR=1
 fi
 
 case "$target" in
-  *linux*)
+  *linux*|*darwin*)
     if test -z "$_HAS_NSPR"; then JS_POSIX_NSPR_DEFAULT=1; fi
     ;;
 esac
 
 MOZ_ARG_ENABLE_BOOL(posix-nspr-emulation,
 [  --enable-posix-nspr-emulation
                           Enable emulation of NSPR for POSIX systems],
     JS_POSIX_NSPR=1,
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -132,42 +132,42 @@ MaybeCheckEvalFreeVariables(ExclusiveCon
             scope = scope->enclosingScope();
         }
     }
 
     return true;
 }
 
 static inline bool
-CanLazilyParse(ExclusiveContext *cx, const CompileOptions &options)
+CanLazilyParse(ExclusiveContext *cx, const ReadOnlyCompileOptions &options)
 {
     return options.canLazilyParse &&
         options.compileAndGo &&
         options.sourcePolicy == CompileOptions::SAVE_SOURCE &&
         !cx->compartment()->debugMode();
 }
 
 void
-frontend::MaybeCallSourceHandler(JSContext *cx, const CompileOptions &options,
+frontend::MaybeCallSourceHandler(JSContext *cx, const ReadOnlyCompileOptions &options,
                                  const jschar *chars, size_t length)
 {
     JSSourceHandler listener = cx->runtime()->debugHooks.sourceHandler;
     void *listenerData = cx->runtime()->debugHooks.sourceHandlerData;
 
     if (listener) {
         void *listenerTSData;
-        listener(options.filename, options.lineno, chars, length,
+        listener(options.filename(), options.lineno, chars, length,
                  &listenerTSData, listenerData);
     }
 }
 
 JSScript *
 frontend::CompileScript(ExclusiveContext *cx, LifoAlloc *alloc, HandleObject scopeChain,
                         HandleScript evalCaller,
-                        const CompileOptions &options,
+                        const ReadOnlyCompileOptions &options,
                         const jschar *chars, size_t length,
                         JSString *source_ /* = nullptr */,
                         unsigned staticLevel /* = 0 */,
                         SourceCompressionTask *extraSct /* = nullptr */)
 {
     RootedString source(cx, source_);
     SkipRoot skip(cx, &chars);
 
@@ -190,17 +190,17 @@ frontend::CompileScript(ExclusiveContext
     JS_ASSERT_IF(staticLevel != 0, evalCaller);
 
     if (!CheckLength(cx, length))
         return nullptr;
     JS_ASSERT_IF(staticLevel != 0, options.sourcePolicy != CompileOptions::LAZY_SOURCE);
     ScriptSource *ss = cx->new_<ScriptSource>(options.originPrincipals());
     if (!ss)
         return nullptr;
-    if (options.filename && !ss->setFilename(cx, options.filename))
+    if (options.filename() && !ss->setFilename(cx, options.filename()))
         return nullptr;
 
     RootedScriptSource sourceObject(cx, ScriptSourceObject::create(cx, ss));
     if (!sourceObject)
         return nullptr;
 
     SourceCompressionTask mysct(cx);
     SourceCompressionTask *sct = extraSct ? extraSct : &mysct;
@@ -374,18 +374,18 @@ frontend::CompileScript(ExclusiveContext
 
     if (!SetSourceMap(cx, parser.tokenStream, ss))
         return nullptr;
 
     /*
      * Source map URLs passed as a compile option (usually via a HTTP source map
      * header) override any source map urls passed as comment pragmas.
      */
-    if (options.sourceMapURL) {
-        if (!ss->setSourceMapURL(cx, options.sourceMapURL))
+    if (options.sourceMapURL()) {
+        if (!ss->setSourceMapURL(cx, options.sourceMapURL()))
             return nullptr;
     }
 
     /*
      * Nowadays the threaded interpreter needs a last return instruction, so we
      * do have to emit that here.
      */
     if (Emit1(cx, &bce, JSOP_RETRVAL) < 0)
@@ -467,17 +467,17 @@ frontend::CompileLazyFunction(JSContext 
         bce.lazyRunOnceLambda = true;
 
     return EmitFunctionScript(cx, &bce, pn->pn_body);
 }
 
 // Compile a JS function body, which might appear as the value of an event
 // handler attribute in an HTML <INPUT> tag, or in a Function() constructor.
 static bool
-CompileFunctionBody(JSContext *cx, MutableHandleFunction fun, CompileOptions options,
+CompileFunctionBody(JSContext *cx, MutableHandleFunction fun, const ReadOnlyCompileOptions &options,
                     const AutoNameVector &formals, const jschar *chars, size_t length,
                     GeneratorKind generatorKind)
 {
 #if JS_TRACE_LOGGING
         js::AutoTraceLog logger(js::TraceLogging::defaultLogger(),
                                 js::TraceLogging::PARSER_COMPILE_FUNCTION_START,
                                 js::TraceLogging::PARSER_COMPILE_FUNCTION_STOP,
                                 options);
@@ -489,17 +489,17 @@ CompileFunctionBody(JSContext *cx, Mutab
 
     MaybeCallSourceHandler(cx, options, chars, length);
 
     if (!CheckLength(cx, length))
         return false;
     ScriptSource *ss = cx->new_<ScriptSource>(options.originPrincipals());
     if (!ss)
         return false;
-    if (options.filename && !ss->setFilename(cx, options.filename))
+    if (options.filename() && !ss->setFilename(cx, options.filename()))
         return false;
     RootedScriptSource sourceObject(cx, ScriptSourceObject::create(cx, ss));
     if (!sourceObject)
         return false;
     SourceCompressionTask sct(cx);
     JS_ASSERT(options.sourcePolicy != CompileOptions::LAZY_SOURCE);
     if (options.sourcePolicy == CompileOptions::SAVE_SOURCE) {
         if (!ss->setSourceCopy(cx, chars, length, true, &sct))
@@ -606,21 +606,22 @@ CompileFunctionBody(JSContext *cx, Mutab
 
     if (!sct.complete())
         return false;
 
     return true;
 }
 
 bool
-frontend::CompileFunctionBody(JSContext *cx, MutableHandleFunction fun, CompileOptions options,
+frontend::CompileFunctionBody(JSContext *cx, MutableHandleFunction fun,
+                              const ReadOnlyCompileOptions &options,
                               const AutoNameVector &formals, const jschar *chars, size_t length)
 {
     return CompileFunctionBody(cx, fun, options, formals, chars, length, NotGenerator);
 }
 
 bool
 frontend::CompileStarGeneratorBody(JSContext *cx, MutableHandleFunction fun,
-                                   CompileOptions options, const AutoNameVector &formals,
+                                   const ReadOnlyCompileOptions &options, const AutoNameVector &formals,
                                    const jschar *chars, size_t length)
 {
     return CompileFunctionBody(cx, fun, options, formals, chars, length, StarGenerator);
 }
--- a/js/src/frontend/BytecodeCompiler.h
+++ b/js/src/frontend/BytecodeCompiler.h
@@ -18,36 +18,38 @@ class LazyScript;
 class LifoAlloc;
 struct SourceCompressionTask;
 
 namespace frontend {
 
 JSScript *
 CompileScript(ExclusiveContext *cx, LifoAlloc *alloc,
               HandleObject scopeChain, HandleScript evalCaller,
-              const CompileOptions &options, const jschar *chars, size_t length,
+              const ReadOnlyCompileOptions &options, const jschar *chars, size_t length,
               JSString *source_ = nullptr, unsigned staticLevel = 0,
               SourceCompressionTask *extraSct = nullptr);
 
 bool
 CompileLazyFunction(JSContext *cx, LazyScript *lazy, const jschar *chars, size_t length);
 
 bool
-CompileFunctionBody(JSContext *cx, MutableHandleFunction fun, CompileOptions options,
+CompileFunctionBody(JSContext *cx, MutableHandleFunction fun,
+                    const ReadOnlyCompileOptions &options,
                     const AutoNameVector &formals, const jschar *chars, size_t length);
 bool
-CompileStarGeneratorBody(JSContext *cx, MutableHandleFunction fun, CompileOptions options,
+CompileStarGeneratorBody(JSContext *cx, MutableHandleFunction fun,
+                         const ReadOnlyCompileOptions &options,
                          const AutoNameVector &formals, const jschar *chars, size_t length);
 
 /*
  * This should be called while still on the main thread if compilation will
  * occur on a worker thread.
  */
 void
-MaybeCallSourceHandler(JSContext *cx, const CompileOptions &options,
+MaybeCallSourceHandler(JSContext *cx, const ReadOnlyCompileOptions &options,
                        const jschar *chars, size_t length);
 
 /*
  * True if str consists of an IdentifierStart character, followed by one or
  * more IdentifierPart characters, i.e. it matches the IdentifierName production
  * in the language spec.
  *
  * This returns true even if str is a keyword like "if".
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -4805,17 +4805,17 @@ EmitFunc(ExclusiveContext *cx, BytecodeE
             SharedContext *outersc = bce->sc;
 
             if (outersc->isFunctionBox() && outersc->asFunctionBox()->mightAliasLocals())
                 funbox->setMightAliasLocals();      // inherit mightAliasLocals from parent
             JS_ASSERT_IF(outersc->strict, funbox->strict);
 
             // Inherit most things (principals, version, etc) from the parent.
             Rooted<JSScript*> parent(cx, bce->script);
-            CompileOptions options(bce->parser->options());
+            CompileOptions options(cx, bce->parser->options());
             options.setPrincipals(parent->principals())
                    .setOriginPrincipals(parent->originPrincipals())
                    .setCompileAndGo(parent->compileAndGo)
                    .setSelfHostingMode(parent->selfHosted)
                    .setNoScriptRval(false)
                    .setForEval(false)
                    .setVersion(parent->getVersion());
 
--- a/js/src/frontend/FoldConstants.cpp
+++ b/js/src/frontend/FoldConstants.cpp
@@ -244,17 +244,17 @@ MOZ_END_ENUM_CLASS(SyntacticContext)
 static SyntacticContext
 condIf(const ParseNode *pn, ParseNodeKind kind)
 {
     return pn->isKind(kind) ? SyntacticContext::Condition : SyntacticContext::Other;
 }
 
 static bool
 Fold(ExclusiveContext *cx, ParseNode **pnp,
-     FullParseHandler &handler, const CompileOptions &options,
+     FullParseHandler &handler, const ReadOnlyCompileOptions &options,
      bool inGenexpLambda, SyntacticContext sc)
 {
     ParseNode *pn = *pnp;
     ParseNode *pn1 = nullptr, *pn2 = nullptr, *pn3 = nullptr;
 
     JS_CHECK_RECURSION(cx, return false);
 
     // First, recursively fold constants on the children of this node.
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -379,17 +379,17 @@ bool
 Parser<SyntaxParseHandler>::abortIfSyntaxParser()
 {
     abortedSyntaxParse = true;
     return false;
 }
 
 template <typename ParseHandler>
 Parser<ParseHandler>::Parser(ExclusiveContext *cx, LifoAlloc *alloc,
-                             const CompileOptions &options,
+                             const ReadOnlyCompileOptions &options,
                              const jschar *chars, size_t length, bool foldConstants,
                              Parser<SyntaxParseHandler> *syntaxParser,
                              LazyScript *lazyOuterFunction)
   : AutoGCRooter(cx, PARSER),
     context(cx),
     alloc(*alloc),
     tokenStream(cx, options, chars, length, thisForCtor()),
     traceListHead(nullptr),
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -362,17 +362,17 @@ class Parser : private AutoGCRooter, pub
     bool reportHelper(ParseReportKind kind, bool strict, uint32_t offset,
                       unsigned errorNumber, va_list args);
   public:
     bool report(ParseReportKind kind, bool strict, Node pn, unsigned errorNumber, ...);
     bool reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...);
     bool reportWithOffset(ParseReportKind kind, bool strict, uint32_t offset, unsigned errorNumber,
                           ...);
 
-    Parser(ExclusiveContext *cx, LifoAlloc *alloc, const CompileOptions &options,
+    Parser(ExclusiveContext *cx, LifoAlloc *alloc, const ReadOnlyCompileOptions &options,
            const jschar *chars, size_t length, bool foldConstants,
            Parser<SyntaxParseHandler> *syntaxParser,
            LazyScript *lazyOuterFunction);
     ~Parser();
 
     // A Parser::Mark is the extension of the LifoAlloc::Mark to the entire
     // Parser's state. Note: clients must still take care that any ParseContext
     // that points into released ParseNodes is destroyed.
@@ -466,17 +466,17 @@ class Parser : private AutoGCRooter, pub
 
     // Determine whether |yield| is a valid name in the current context, or
     // whether it's prohibited due to strictness, JS version, or occurrence
     // inside a star generator.
     bool checkYieldNameValidity();
 
     virtual bool strictMode() { return pc->sc->strict; }
 
-    const CompileOptions &options() const {
+    const ReadOnlyCompileOptions &options() const {
         return tokenStream.options();
     }
 
   private:
     /*
      * JS parsers, from lowest to highest precedence.
      *
      * Each parser must be called during the dynamic scope of a ParseContext
--- a/js/src/frontend/TokenStream.cpp
+++ b/js/src/frontend/TokenStream.cpp
@@ -255,29 +255,29 @@ TokenStream::SourceCoords::lineNumAndCol
 }
 
 #ifdef _MSC_VER
 #pragma warning(push)
 #pragma warning(disable:4351)
 #endif
 
 // Initialize members that aren't initialized in |init|.
-TokenStream::TokenStream(ExclusiveContext *cx, const CompileOptions &options,
+TokenStream::TokenStream(ExclusiveContext *cx, const ReadOnlyCompileOptions &options,
                          const jschar *base, size_t length, StrictModeGetter *smg)
   : srcCoords(cx, options.lineno),
     options_(options),
     tokens(),
     cursor(),
     lookahead(),
     lineno(options.lineno),
     flags(),
     linebase(base - options.column),
     prevLinebase(nullptr),
     userbuf(cx, base - options.column, length + options.column), // See comment below
-    filename(options.filename),
+    filename(options.filename()),
     sourceURL_(nullptr),
     sourceMapURL_(nullptr),
     tokenbuf(cx),
     cx(cx),
     originPrincipals(options.originPrincipals()),
     strictModeGetter(smg),
     tokenSkip(cx, &tokens),
     linebaseSkip(cx, &linebase),
--- a/js/src/frontend/TokenStream.h
+++ b/js/src/frontend/TokenStream.h
@@ -403,17 +403,17 @@ class MOZ_STACK_CLASS TokenStream
     static const size_t ntokens = 4;                // 1 current + 2 lookahead, rounded
                                                     // to power of 2 to avoid divmod by 3
     static const unsigned maxLookahead = 2;
     static const unsigned ntokensMask = ntokens - 1;
 
   public:
     typedef Vector<jschar, 32> CharBuffer;
 
-    TokenStream(ExclusiveContext *cx, const CompileOptions &options,
+    TokenStream(ExclusiveContext *cx, const ReadOnlyCompileOptions &options,
                 const jschar *base, size_t length, StrictModeGetter *smg);
 
     ~TokenStream();
 
     // Accessors.
     const Token &currentToken() const { return tokens[cursor]; }
     bool isCurrentTokenType(TokenKind type) const {
         return currentToken().type == type;
@@ -729,17 +729,17 @@ class MOZ_STACK_CLASS TokenStream
     JSAtomState &names() const {
         return cx->names();
     }
 
     ExclusiveContext *context() const {
         return cx;
     }
 
-    const CompileOptions &options() const {
+    const ReadOnlyCompileOptions &options() const {
         return options_;
     }
 
   private:
     // This is the low-level interface to the JS source code buffer.  It just
     // gets raw chars, basically.  TokenStreams functions are layered on top
     // and do some extra stuff like converting all EOL sequences to '\n',
     // tracking the line number, and setting |flags.isEOF|.  (The "raw" in "raw
@@ -873,17 +873,17 @@ class MOZ_STACK_CLASS TokenStream
         while (--n >= 0)
             getChar();
     }
 
     void updateLineInfoForEOL();
     void updateFlagsForEOL();
 
     // Options used for parsing/tokenizing.
-    const CompileOptions &options_;
+    const ReadOnlyCompileOptions &options_;
 
     Token               tokens[ntokens];    // circular token buffer
     unsigned            cursor;             // index of last parsed token
     unsigned            lookahead;          // count of lookahead tokens
     unsigned            lineno;             // current line number
     Flags               flags;              // flags -- see above
     const jschar        *linebase;          // start of current line;  points into userbuf
     const jschar        *prevLinebase;      // start of previous line;  nullptr if on the first line
--- a/js/src/jit/AsmJS.cpp
+++ b/js/src/jit/AsmJS.cpp
@@ -1318,17 +1318,17 @@ class MOZ_STACK_CLASS ModuleCompiler
         return true;
     }
 
     bool failOffset(uint32_t offset, const char *str) {
         JS_ASSERT(!errorString_);
         JS_ASSERT(errorOffset_ == UINT32_MAX);
         JS_ASSERT(str);
         errorOffset_ = offset;
-        errorString_ = strdup(str);
+        errorString_ = js_strdup(cx_, str);
         return false;
     }
 
     bool fail(ParseNode *pn, const char *str) {
         if (pn)
             return failOffset(pn->pn_pos.begin, str);
 
         // The exact rooting static analysis does not perform dataflow analysis, so it believes
--- a/js/src/jit/AsmJSModule.cpp
+++ b/js/src/jit/AsmJSModule.cpp
@@ -726,19 +726,21 @@ GetCPUID(uint32_t *cpuId)
 #else
     return false;
 #endif
 }
 
 class MachineId
 {
     uint32_t cpuId_;
-    mozilla::Vector<char> buildId_;
+    js::Vector<char> buildId_;
 
   public:
+    MachineId(ExclusiveContext *cx) : buildId_(cx) {}
+
     bool extractCurrentState(ExclusiveContext *cx) {
         if (!cx->asmJSCacheOps().buildId)
             return false;
         if (!cx->asmJSCacheOps().buildId(&buildId_))
             return false;
         if (!GetCPUID(&cpuId_))
             return false;
         return true;
@@ -908,17 +910,17 @@ struct ScopedCacheEntryOpenedForWrite
 };
 
 void
 js::StoreAsmJSModuleInCache(AsmJSParser &parser,
                             const AsmJSModule &module,
                             const AsmJSStaticLinkData &linkData,
                             ExclusiveContext *cx)
 {
-    MachineId machineId;
+    MachineId machineId(cx);
     if (!machineId.extractCurrentState(cx))
         return;
 
     ModuleChars moduleChars;
     if (!moduleChars.initFromParsedModule(parser, module))
         return;
 
     size_t serializedSize = machineId.serializedSize() +
@@ -963,31 +965,31 @@ struct ScopedCacheEntryOpenedForRead
 bool
 js::LookupAsmJSModuleInCache(ExclusiveContext *cx,
                              AsmJSParser &parser,
                              ScopedJSDeletePtr<AsmJSModule> *moduleOut,
                              ScopedJSFreePtr<char> *compilationTimeReport)
 {
     int64_t usecBefore = PRMJ_Now();
 
-    MachineId machineId;
+    MachineId machineId(cx);
     if (!machineId.extractCurrentState(cx))
         return true;
 
     JS::OpenAsmJSCacheEntryForReadOp openEntryForRead = cx->asmJSCacheOps().openEntryForRead;
     if (!openEntryForRead)
         return true;
 
     ScopedCacheEntryOpenedForRead entry(cx);
     if (!openEntryForRead(cx->global(), &entry.serializedSize, &entry.memory, &entry.handle))
         return true;
 
     const uint8_t *cursor = entry.memory;
 
-    MachineId cachedMachineId;
+    MachineId cachedMachineId(cx);
     cursor = cachedMachineId.deserialize(cx, cursor);
     if (!cursor)
         return false;
     if (machineId != cachedMachineId)
         return true;
 
     ModuleChars moduleChars;
     cursor = moduleChars.deserialize(cx, cursor);
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -813,17 +813,17 @@ MPhi::congruentTo(MDefinition *ins) cons
     return congruentIfOperandsEqual(ins);
 }
 
 bool
 MPhi::reserveLength(size_t length)
 {
     // Initializes a new MPhi to have an Operand vector of at least the given
     // capacity. This permits use of addInput() instead of addInputSlow(), the
-    // latter of which may call realloc().
+    // latter of which may call realloc_().
     JS_ASSERT(numOperands() == 0);
 #if DEBUG
     capacity_ = length;
 #endif
     return inputs_.reserve(length);
 }
 
 static inline types::TemporaryTypeSet *
@@ -963,17 +963,17 @@ MPhi::addInputSlow(MDefinition *ins, boo
     // each of which is in the list of the producer MDefinition.
     // Because appending to a vector may reallocate the vector, it is possible
     // that this operation may cause the producers' linked lists to reference
     // invalid memory. Therefore, in the event of moving reallocation, each
     // MUse must be removed and reinserted from/into its producer's use chain.
     uint32_t index = inputs_.length();
     bool performingRealloc = !inputs_.canAppendWithoutRealloc(1);
 
-    // Remove all MUses from all use lists, in case realloc() moves.
+    // Remove all MUses from all use lists, in case realloc_() moves.
     if (performingRealloc) {
         for (uint32_t i = 0; i < index; i++) {
             MUse *use = &inputs_[i];
             use->producer()->removeUse(use);
         }
     }
 
     // Insert the new input.
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -4311,17 +4311,17 @@ class MPhi MOZ_FINAL : public MDefinitio
 
     // Initializes the operands vector to the given capacity,
     // permitting use of addInput() instead of addInputSlow().
     bool reserveLength(size_t length);
 
     // Use only if capacity has been reserved by reserveLength
     void addInput(MDefinition *ins);
 
-    // Appends a new input to the input vector. May call realloc().
+    // Appends a new input to the input vector. May call realloc_().
     // Prefer reserveLength() and addInput() instead, where possible.
     bool addInputSlow(MDefinition *ins, bool *ptypeChange = nullptr);
 
     MDefinition *foldsTo(bool useValueNumbers);
 
     bool congruentTo(MDefinition *ins) const;
 
     bool isIterator() const {
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -4262,102 +4262,180 @@ AutoFile::open(JSContext *cx, const char
             JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_CANT_OPEN,
                                  filename, "No such file or directory");
             return false;
         }
     }
     return true;
 }
 
-
-JS::CompileOptions::CompileOptions(JSContext *cx, JSVersion version)
-    : principals_(nullptr),
-      originPrincipals_(nullptr),
-      version(version != JSVERSION_UNKNOWN ? version : cx->findVersion()),
-      versionSet(false),
-      utf8(false),
-      filename(nullptr),
-      sourceMapURL(nullptr),
-      lineno(1),
-      column(0),
-      element(NullPtr()),
-      compileAndGo(cx->options().compileAndGo()),
-      forEval(false),
-      noScriptRval(cx->options().noScriptRval()),
-      selfHostingMode(false),
-      canLazilyParse(true),
-      strictOption(cx->options().strictMode()),
-      extraWarningsOption(cx->options().extraWarnings()),
-      werrorOption(cx->options().werror()),
-      asmJSOption(cx->options().asmJS()),
-      sourcePolicy(SAVE_SOURCE)
-{
+JSObject * const JS::ReadOnlyCompileOptions::nullObjectPtr = nullptr;
+
+void
+JS::ReadOnlyCompileOptions::copyPODOptions(const ReadOnlyCompileOptions &rhs)
+{
+    version = rhs.version;
+    versionSet = rhs.versionSet;
+    utf8 = rhs.utf8;
+    lineno = rhs.lineno;
+    column = rhs.column;
+    compileAndGo = rhs.compileAndGo;
+    forEval = rhs.forEval;
+    noScriptRval = rhs.noScriptRval;
+    selfHostingMode = rhs.selfHostingMode;
+    canLazilyParse = rhs.canLazilyParse;
+    strictOption = rhs.strictOption;
+    extraWarningsOption = rhs.extraWarningsOption;
+    werrorOption = rhs.werrorOption;
+    asmJSOption = rhs.asmJSOption;
+    sourcePolicy = rhs.sourcePolicy;
 }
 
 JSPrincipals *
-CompileOptions::originPrincipals() const
+JS::ReadOnlyCompileOptions::originPrincipals() const
 {
     return NormalizeOriginPrincipals(principals_, originPrincipals_);
 }
 
+JS::OwningCompileOptions::OwningCompileOptions(JSContext *cx)
+    : ReadOnlyCompileOptions(),
+      runtime(GetRuntime(cx)),
+      elementRoot(cx)
+{
+}
+
+JS::OwningCompileOptions::~OwningCompileOptions()
+{
+    if (principals_)
+        JS_DropPrincipals(runtime, principals_);
+    if (originPrincipals_)
+        JS_DropPrincipals(runtime, originPrincipals_);
+
+    // OwningCompileOptions always owns these, so these casts are okay.
+    js_free(const_cast<char *>(filename_));
+    js_free(const_cast<jschar *>(sourceMapURL_));
+}
+
+bool
+JS::OwningCompileOptions::copy(JSContext *cx, const ReadOnlyCompileOptions &rhs)
+{
+    copyPODOptions(rhs);
+
+    setPrincipals(rhs.principals());
+    setOriginPrincipals(rhs.originPrincipals());
+    setElement(rhs.element());
+
+    return (setFileAndLine(cx, rhs.filename(), rhs.lineno) &&
+            setSourceMapURL(cx, rhs.sourceMapURL()));
+}
+
+bool
+JS::OwningCompileOptions::setFileAndLine(JSContext *cx, const char *f, unsigned l)
+{
+    char *copy = nullptr;
+    if (f) {
+        copy = JS_strdup(cx, f);
+        if (!copy)
+            return false;
+    }
+
+    // OwningCompileOptions always owns filename_, so this cast is okay.
+    js_free(const_cast<char *>(filename_));
+
+    filename_ = copy;
+    lineno = l;
+    return true;
+}
+
+bool
+JS::OwningCompileOptions::setSourceMapURL(JSContext *cx, const jschar *s)
+{
+    jschar *copy = nullptr;
+    if (s) {
+        copy = js_strdup(cx, s);
+        if (!copy)
+            return false;
+    }
+
+    // OwningCompileOptions always owns sourceMapURL_, so this cast is okay.
+    js_free(const_cast<jschar *>(sourceMapURL_));
+
+    sourceMapURL_ = copy;
+    return true;
+}
+
+JS::CompileOptions::CompileOptions(JSContext *cx, JSVersion version)
+    : ReadOnlyCompileOptions(), elementRoot(cx)
+{
+    this->version = (version != JSVERSION_UNKNOWN) ? version : cx->findVersion();
+
+    compileAndGo = cx->options().compileAndGo();
+    noScriptRval = cx->options().noScriptRval();
+    strictOption = cx->options().strictMode();
+    extraWarningsOption = cx->options().extraWarnings();
+    werrorOption = cx->options().werror();
+    asmJSOption = cx->options().asmJS();
+}
+
 JSScript *
-JS::Compile(JSContext *cx, HandleObject obj, CompileOptions options,
+JS::Compile(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options,
             const jschar *chars, size_t length)
 {
     JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
     JS_ASSERT_IF(options.principals(), cx->compartment()->principals == options.principals());
     AutoLastFrameCheck lfc(cx);
 
     return frontend::CompileScript(cx, &cx->tempLifoAlloc(), obj, NullPtr(), options, chars, length);
 }
 
 JSScript *
-JS::Compile(JSContext *cx, HandleObject obj, CompileOptions options,
+JS::Compile(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options,
             const char *bytes, size_t length)
 {
     jschar *chars;
     if (options.utf8)
         chars = UTF8CharsToNewTwoByteCharsZ(cx, UTF8Chars(bytes, length), &length).get();
     else
         chars = InflateString(cx, bytes, &length);
     if (!chars)
         return nullptr;
 
     JSScript *script = Compile(cx, obj, options, chars, length);
     js_free(chars);
     return script;
 }
 
 JSScript *
-JS::Compile(JSContext *cx, HandleObject obj, CompileOptions options, FILE *fp)
+JS::Compile(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options, FILE *fp)
 {
     FileContents buffer(cx);
     if (!ReadCompleteFile(cx, fp, buffer))
         return nullptr;
 
     JSScript *script = Compile(cx, obj, options, buffer.begin(), buffer.length());
     return script;
 }
 
 JSScript *
-JS::Compile(JSContext *cx, HandleObject obj, CompileOptions options, const char *filename)
+JS::Compile(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &optionsArg, const char *filename)
 {
     AutoFile file;
     if (!file.open(cx, filename))
         return nullptr;
+    CompileOptions options(cx, optionsArg);
     options.setFileAndLine(filename, 1);
     JSScript *script = Compile(cx, obj, options, file.fp());
     return script;
 }
 
 JS_PUBLIC_API(bool)
-JS::CanCompileOffThread(JSContext *cx, const CompileOptions &options)
+JS::CanCompileOffThread(JSContext *cx, const ReadOnlyCompileOptions &options)
 {
 #ifdef JS_WORKER_THREADS
     if (!cx->runtime()->useHelperThreads() || !cx->runtime()->helperThreadCount())
         return false;
 
     if (!cx->runtime()->useHelperThreadsForParsing())
         return false;
 
@@ -4370,17 +4448,17 @@ JS::CanCompileOffThread(JSContext *cx, c
 
     return true;
 #else
     return false;
 #endif
 }
 
 JS_PUBLIC_API(bool)
-JS::CompileOffThread(JSContext *cx, Handle<JSObject*> obj, CompileOptions options,
+JS::CompileOffThread(JSContext *cx, Handle<JSObject*> obj, const ReadOnlyCompileOptions &options,
                      const jschar *chars, size_t length,
                      OffThreadCompileCallback callback, void *callbackData)
 {
 #ifdef JS_WORKER_THREADS
     JS_ASSERT(CanCompileOffThread(cx, options));
     return StartOffThreadParseScript(cx, options, chars, length, obj, callback, callbackData);
 #else
     MOZ_ASSUME_UNREACHABLE("Off thread compilation is not available.");
@@ -4498,17 +4576,17 @@ JS_BufferIsCompilableUnit(JSContext *cx,
 JS_PUBLIC_API(JSObject *)
 JS_GetGlobalFromScript(JSScript *script)
 {
     JS_ASSERT(!script->isCachedEval);
     return &script->global();
 }
 
 JS_PUBLIC_API(JSFunction *)
-JS::CompileFunction(JSContext *cx, HandleObject obj, CompileOptions options,
+JS::CompileFunction(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options,
                     const char *name, unsigned nargs, const char *const *argnames,
                     const jschar *chars, size_t length)
 {
     JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
     JS_ASSERT_IF(options.principals(), cx->compartment()->principals == options.principals());
@@ -4542,17 +4620,17 @@ JS::CompileFunction(JSContext *cx, Handl
         if (!JSObject::defineGeneric(cx, obj, id, value, nullptr, nullptr, JSPROP_ENUMERATE))
             return nullptr;
     }
 
     return fun;
 }
 
 JS_PUBLIC_API(JSFunction *)
-JS::CompileFunction(JSContext *cx, HandleObject obj, CompileOptions options,
+JS::CompileFunction(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options,
                     const char *name, unsigned nargs, const char *const *argnames,
                     const char *bytes, size_t length)
 {
     jschar *chars;
     if (options.utf8)
         chars = UTF8CharsToNewTwoByteCharsZ(cx, UTF8Chars(bytes, length), &length).get();
     else
         chars = InflateString(cx, bytes, &length);
@@ -4683,19 +4761,20 @@ JS_ExecuteScriptVersion(JSContext *cx, J
 {
     RootedObject obj(cx, objArg);
     return JS_ExecuteScript(cx, obj, script, rval);
 }
 
 static const unsigned LARGE_SCRIPT_LENGTH = 500*1024;
 
 extern JS_PUBLIC_API(bool)
-JS::Evaluate(JSContext *cx, HandleObject obj, CompileOptions options,
+JS::Evaluate(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &optionsArg,
              const jschar *chars, size_t length, jsval *rval)
 {
+    CompileOptions options(cx, optionsArg);
     JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
     JS_ASSERT_IF(options.principals(), cx->compartment()->principals == options.principals());
 
     AutoLastFrameCheck lfc(cx);
 
@@ -4724,43 +4803,44 @@ JS::Evaluate(JSContext *cx, HandleObject
         PrepareZoneForGC(cx->zone());
         GC(cx->runtime(), GC_NORMAL, gcreason::FINISH_LARGE_EVALUTE);
     }
 
     return result;
 }
 
 extern JS_PUBLIC_API(bool)
-JS::Evaluate(JSContext *cx, HandleObject obj, CompileOptions options,
+JS::Evaluate(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options,
              const char *bytes, size_t length, jsval *rval)
 {
     jschar *chars;
     if (options.utf8)
         chars = UTF8CharsToNewTwoByteCharsZ(cx, UTF8Chars(bytes, length), &length).get();
     else
         chars = InflateString(cx, bytes, &length);
     if (!chars)
         return false;
 
     bool ok = Evaluate(cx, obj, options, chars, length, rval);
     js_free(chars);
     return ok;
 }
 
 extern JS_PUBLIC_API(bool)
-JS::Evaluate(JSContext *cx, HandleObject obj, CompileOptions options,
+JS::Evaluate(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &optionsArg,
              const char *filename, jsval *rval)
 {
     FileContents buffer(cx);
     {
         AutoFile file;
         if (!file.open(cx, filename) || !file.readAll(cx, buffer))
             return false;
     }
 
+    CompileOptions options(cx, optionsArg);
     options.setFileAndLine(filename, 1);
     return Evaluate(cx, obj, options, buffer.begin(), buffer.length(), rval);
 }
 
 JS_PUBLIC_API(bool)
 JS_EvaluateUCScriptForPrincipals(JSContext *cx, JSObject *objArg,
                                  JSPrincipals *principals,
                                  const jschar *chars, unsigned length,
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -3316,83 +3316,265 @@ extern JS_PUBLIC_API(JSFunction *)
 JS_CompileUCFunction(JSContext *cx, JSObject *obj, const char *name,
                      unsigned nargs, const char *const *argnames,
                      const jschar *chars, size_t length,
                      const char *filename, unsigned lineno);
 
 namespace JS {
 
 /* Options for JavaScript compilation. */
-class JS_PUBLIC_API(CompileOptions)
+
+/*
+ * In the most common use case, a CompileOptions instance is allocated on the
+ * stack, and holds non-owning references to non-POD option values: strings;
+ * principals; objects; and so on. The code declaring the instance guarantees
+ * that such option values will outlive the CompileOptions itself: objects are
+ * otherwise rooted; principals have had their reference counts bumped; strings
+ * will not be freed until the CompileOptions goes out of scope. In this
+ * situation, CompileOptions only refers to things others own, so it can be
+ * lightweight.
+ *
+ * In some cases, however, we need to hold compilation options with a
+ * non-stack-like lifetime. For example, JS::CompileOffThread needs to save
+ * compilation options where a worker thread can find them, and then return
+ * immediately. The worker thread will come along at some later point, and use
+ * the options.
+ *
+ * The compiler itself just needs to be able to access a collection of options;
+ * it doesn't care who owns them, or what's keeping them alive. It does its own
+ * addrefs/copies/tracing/etc.
+ *
+ * So, we have a class hierarchy that reflects these three use cases:
+ *
+ * - ReadOnlyCompileOptions is the common base class. It can be used by code
+ *   that simply needs to access options set elsewhere, like the compiler.
+ *
+ * - The usual CompileOptions class must be stack-allocated, and holds
+ *   non-owning references to the filename, element, and so on. It's derived
+ *   from ReadOnlyCompileOptions, so the compiler can use it.
+ *
+ * - OwningCompileOptions roots / copies / reference counts of all its values,
+ *   and unroots / frees / releases them when it is destructed. It too is
+ *   derived from ReadOnlyCompileOptions, so the compiler accepts it.
+ */
+
+/*
+ * The common base class for the CompileOptions hierarchy.
+ *
+ * Use this in code that only needs to access compilation options created
+ * elsewhere, like the compiler. Don't instantiate this class (the constructor
+ * is protected anyway); instead, create instances only of the derived classes:
+ * CompileOptions and OwningCompileOptions.
+ */
+class JS_PUBLIC_API(ReadOnlyCompileOptions)
 {
+  protected:
     JSPrincipals *principals_;
     JSPrincipals *originPrincipals_;
+    const char *filename_;
+    const jschar *sourceMapURL_;
+
+    // This constructor leaves 'version' set to JSVERSION_UNKNOWN. The structure
+    // is unusable until that's set to something more specific; the derived
+    // classes' constructors take care of that, in ways appropriate to their
+    // purpose.
+    ReadOnlyCompileOptions()
+      : principals_(nullptr),
+        originPrincipals_(nullptr),
+        filename_(nullptr),
+        sourceMapURL_(nullptr),
+        version(JSVERSION_UNKNOWN),
+        versionSet(false),
+        utf8(false),
+        lineno(1),
+        column(0),
+        compileAndGo(false),
+        forEval(false),
+        noScriptRval(false),
+        selfHostingMode(false),
+        canLazilyParse(true),
+        strictOption(false),
+        extraWarningsOption(false),
+        werrorOption(false),
+        asmJSOption(false),
+        sourcePolicy(SAVE_SOURCE)
+    { }
+
+    // Set all POD options (those not requiring reference counts, copies,
+    // rooting, or other hand-holding) to their values in |rhs|.
+    void copyPODOptions(const ReadOnlyCompileOptions &rhs);
 
   public:
+    // Read-only accessors for non-POD options. The proper way to set these
+    // depends on the derived type.
     JSPrincipals *principals() const { return principals_; }
     JSPrincipals *originPrincipals() const;
-
+    const char *filename() const { return filename_; }
+    const jschar *sourceMapURL() const { return sourceMapURL_; }
+    virtual JSObject *element() const = 0;
+
+    // POD options.
     JSVersion version;
     bool versionSet;
     bool utf8;
-    const char *filename;
-    const jschar *sourceMapURL;
     unsigned lineno;
     unsigned column;
-    Handle<JSObject*> element;
     bool compileAndGo;
     bool forEval;
     bool noScriptRval;
     bool selfHostingMode;
     bool canLazilyParse;
     bool strictOption;
     bool extraWarningsOption;
     bool werrorOption;
     bool asmJSOption;
     enum SourcePolicy {
         NO_SOURCE,
         LAZY_SOURCE,
         SAVE_SOURCE
     } sourcePolicy;
 
+  private:
+    static JSObject * const nullObjectPtr;
+    void operator=(const ReadOnlyCompileOptions &) MOZ_DELETE;
+};
+
+/*
+ * Compilation options, with dynamic lifetime. An instance of this type
+ * makes a copy of / holds / roots all dynamically allocated resources
+ * (principals; elements; strings) that it refers to. Its destructor frees
+ * / drops / unroots them. This is heavier than CompileOptions, below, but
+ * unlike CompileOptions, it can outlive any given stack frame.
+ *
+ * Note that this *roots* any JS values it refers to - they're live
+ * unconditionally. Thus, instances of this type can't be owned, directly
+ * or indirectly, by a JavaScript object: if any value that this roots ever
+ * comes to refer to the object that owns this, then the whole cycle, and
+ * anything else it entrains, will never be freed.
+ */
+class JS_PUBLIC_API(OwningCompileOptions) : public ReadOnlyCompileOptions
+{
+    JSRuntime *runtime;
+    PersistentRootedObject elementRoot;
+
+  public:
+    // A minimal constructor, for use with OwningCompileOptions::copy. This
+    // leaves |this.version| set to JSVERSION_UNKNOWN; the instance
+    // shouldn't be used until we've set that to something real (as |copy|
+    // will).
+    explicit OwningCompileOptions(JSContext *cx);
+    ~OwningCompileOptions();
+
+    JSObject *element() const MOZ_OVERRIDE { return elementRoot; }
+
+    // Set this to a copy of |rhs|. Return false on OOM.
+    bool copy(JSContext *cx, const ReadOnlyCompileOptions &rhs);
+
+    /* These setters make copies of their string arguments, and are fallible. */
+    bool setFileAndLine(JSContext *cx, const char *f, unsigned l);
+    bool setSourceMapURL(JSContext *cx, const jschar *s);
+
+    /* These setters are infallible, and can be chained. */
+    OwningCompileOptions &setElement(JSObject *e) { elementRoot = e; return *this; }
+    OwningCompileOptions &setPrincipals(JSPrincipals *p) {
+        if (p) JS_HoldPrincipals(p);
+        if (principals_) JS_DropPrincipals(runtime, principals_);
+        principals_ = p;
+        return *this;
+    }
+    OwningCompileOptions &setOriginPrincipals(JSPrincipals *p) {
+        if (p) JS_HoldPrincipals(p);
+        if (originPrincipals_) JS_DropPrincipals(runtime, originPrincipals_);
+        originPrincipals_ = p;
+        return *this;
+    }
+    OwningCompileOptions &setVersion(JSVersion v) {
+        version = v;
+        versionSet = true;
+        return *this;
+    }
+    OwningCompileOptions &setUTF8(bool u) { utf8 = u; return *this; }
+    OwningCompileOptions &setColumn(unsigned c) { column = c; return *this; }
+    OwningCompileOptions &setCompileAndGo(bool cng) { compileAndGo = cng; return *this; }
+    OwningCompileOptions &setForEval(bool eval) { forEval = eval; return *this; }
+    OwningCompileOptions &setNoScriptRval(bool nsr) { noScriptRval = nsr; return *this; }
+    OwningCompileOptions &setSelfHostingMode(bool shm) { selfHostingMode = shm; return *this; }
+    OwningCompileOptions &setCanLazilyParse(bool clp) { canLazilyParse = clp; return *this; }
+    OwningCompileOptions &setSourcePolicy(SourcePolicy sp) { sourcePolicy = sp; return *this; }
+};
+
+/*
+ * Compilation options stored on the stack. An instance of this type
+ * simply holds references to dynamically allocated resources (element;
+ * filename; source map URL) that are owned by something else. If you
+ * create an instance of this type, it's up to you to guarantee that
+ * everything you store in it will outlive it.
+ */
+class MOZ_STACK_CLASS JS_PUBLIC_API(CompileOptions) : public ReadOnlyCompileOptions
+{
+    RootedObject elementRoot;
+
+  public:
     explicit CompileOptions(JSContext *cx, JSVersion version = JSVERSION_UNKNOWN);
-    CompileOptions &setPrincipals(JSPrincipals *p) { principals_ = p; return *this; }
-    CompileOptions &setOriginPrincipals(JSPrincipals *p) { originPrincipals_ = p; return *this; }
-    CompileOptions &setVersion(JSVersion v) { version = v; versionSet = true; return *this; }
-    CompileOptions &setUTF8(bool u) { utf8 = u; return *this; }
+    CompileOptions(js::ContextFriendFields *cx, const ReadOnlyCompileOptions &rhs)
+      : ReadOnlyCompileOptions(), elementRoot(cx)
+    {
+        copyPODOptions(rhs);
+
+        principals_ = rhs.principals();
+        originPrincipals_ = rhs.originPrincipals();
+        filename_ = rhs.filename();
+        sourceMapURL_ = rhs.sourceMapURL();
+        elementRoot = rhs.element();
+    }
+
+    JSObject *element() const MOZ_OVERRIDE { return elementRoot; }
+
     CompileOptions &setFileAndLine(const char *f, unsigned l) {
-        filename = f; lineno = l; return *this;
+        filename_ = f; lineno = l; return *this;
     }
-    CompileOptions &setSourceMapURL(const jschar *s) { sourceMapURL = s; return *this; }
+    CompileOptions &setSourceMapURL(const jschar *s) { sourceMapURL_ = s; return *this; }
+    CompileOptions &setElement(JSObject *e) { elementRoot = e; return *this; }
+
+    CompileOptions &setPrincipals(JSPrincipals *p) { principals_ = p; return *this; }
+    CompileOptions &setOriginPrincipals(JSPrincipals *p) {
+        originPrincipals_ = p;
+        return *this;
+    }
+    CompileOptions &setVersion(JSVersion v) {
+        version = v;
+        versionSet = true;
+        return *this;
+    }
+    CompileOptions &setUTF8(bool u) { utf8 = u; return *this; }
     CompileOptions &setColumn(unsigned c) { column = c; return *this; }
-    CompileOptions &setElement(Handle<JSObject*> e) { element.repoint(e); return *this; }
     CompileOptions &setCompileAndGo(bool cng) { compileAndGo = cng; return *this; }
     CompileOptions &setForEval(bool eval) { forEval = eval; return *this; }
     CompileOptions &setNoScriptRval(bool nsr) { noScriptRval = nsr; return *this; }
     CompileOptions &setSelfHostingMode(bool shm) { selfHostingMode = shm; return *this; }
     CompileOptions &setCanLazilyParse(bool clp) { canLazilyParse = clp; return *this; }
     CompileOptions &setSourcePolicy(SourcePolicy sp) { sourcePolicy = sp; return *this; }
 };
 
 extern JS_PUBLIC_API(JSScript *)
-Compile(JSContext *cx, JS::Handle<JSObject*> obj, CompileOptions options,
+Compile(JSContext *cx, JS::Handle<JSObject*> obj, const ReadOnlyCompileOptions &options,
         const char *bytes, size_t length);
 
 extern JS_PUBLIC_API(JSScript *)
-Compile(JSContext *cx, JS::Handle<JSObject*> obj, CompileOptions options,
+Compile(JSContext *cx, JS::Handle<JSObject*> obj, const ReadOnlyCompileOptions &options,
         const jschar *chars, size_t length);
 
 extern JS_PUBLIC_API(JSScript *)
-Compile(JSContext *cx, JS::Handle<JSObject*> obj, CompileOptions options, FILE *file);
+Compile(JSContext *cx, JS::Handle<JSObject*> obj, const ReadOnlyCompileOptions &options, FILE *file);
 
 extern JS_PUBLIC_API(JSScript *)
-Compile(JSContext *cx, JS::Handle<JSObject*> obj, CompileOptions options, const char *filename);
+Compile(JSContext *cx, JS::Handle<JSObject*> obj, const ReadOnlyCompileOptions &options, const char *filename);
 
 extern JS_PUBLIC_API(bool)
-CanCompileOffThread(JSContext *cx, const CompileOptions &options);
+CanCompileOffThread(JSContext *cx, const ReadOnlyCompileOptions &options);
 
 /*
  * Off thread compilation control flow.
  *
  * After successfully triggering an off thread compile of a script, the
  * callback will eventually be invoked with the specified data and a token
  * for the compilation. The callback will be invoked while off the main thread,
  * so must ensure that its operations are thread safe. Afterwards,
@@ -3401,30 +3583,30 @@ CanCompileOffThread(JSContext *cx, const
  * any error or warnings generated during the parse.
  *
  * The characters passed in to CompileOffThread must remain live until the
  * callback is invoked, and the resulting script will be rooted until the call
  * to FinishOffThreadScript.
  */
 
 extern JS_PUBLIC_API(bool)
-CompileOffThread(JSContext *cx, Handle<JSObject*> obj, CompileOptions options,
+CompileOffThread(JSContext *cx, Handle<JSObject*> obj, const ReadOnlyCompileOptions &options,
                  const jschar *chars, size_t length,
                  OffThreadCompileCallback callback, void *callbackData);
 
 extern JS_PUBLIC_API(JSScript *)
 FinishOffThreadScript(JSContext *maybecx, JSRuntime *rt, void *token);
 
 extern JS_PUBLIC_API(JSFunction *)
-CompileFunction(JSContext *cx, JS::Handle<JSObject*> obj, CompileOptions options,
+CompileFunction(JSContext *cx, JS::Handle<JSObject*> obj, const ReadOnlyCompileOptions &options,
                 const char *name, unsigned nargs, const char *const *argnames,
                 const char *bytes, size_t length);
 
 extern JS_PUBLIC_API(JSFunction *)
-CompileFunction(JSContext *cx, JS::Handle<JSObject*> obj, CompileOptions options,
+CompileFunction(JSContext *cx, JS::Handle<JSObject*> obj, const ReadOnlyCompileOptions &options,
                 const char *name, unsigned nargs, const char *const *argnames,
                 const jschar *chars, size_t length);
 
 } /* namespace JS */
 
 extern JS_PUBLIC_API(JSString *)
 JS_DecompileScript(JSContext *cx, JSScript *script, const char *name, unsigned indent);
 
@@ -3540,25 +3722,25 @@ JS_EvaluateUCScriptForPrincipalsVersionO
                                               JSPrincipals *originPrincipals,
                                               const jschar *chars, unsigned length,
                                               const char *filename, unsigned lineno,
                                               jsval *rval, JSVersion version);
 
 namespace JS {
 
 extern JS_PUBLIC_API(bool)
-Evaluate(JSContext *cx, JS::Handle<JSObject*> obj, CompileOptions options,
+Evaluate(JSContext *cx, JS::Handle<JSObject*> obj, const ReadOnlyCompileOptions &options,
          const jschar *chars, size_t length, jsval *rval);
 
 extern JS_PUBLIC_API(bool)
-Evaluate(JSContext *cx, JS::Handle<JSObject*> obj, CompileOptions options,
+Evaluate(JSContext *cx, JS::Handle<JSObject*> obj, const ReadOnlyCompileOptions &options,
          const char *bytes, size_t length, jsval *rval);
 
 extern JS_PUBLIC_API(bool)
-Evaluate(JSContext *cx, JS::Handle<JSObject*> obj, CompileOptions options,
+Evaluate(JSContext *cx, JS::Handle<JSObject*> obj, const ReadOnlyCompileOptions &options,
          const char *filename, jsval *rval);
 
 } /* namespace JS */
 
 extern JS_PUBLIC_API(bool)
 JS_CallFunction(JSContext *cx, JSObject *obj, JSFunction *fun, unsigned argc,
                 jsval *argv, jsval *rval);
 
@@ -4411,17 +4593,17 @@ typedef void
                                    intptr_t handle);
 
 // Return the buildId (represented as a sequence of characters) associated with
 // the currently-executing build. If the JS engine is embedded such that a
 // single cache entry can be observed by different compiled versions of the JS
 // engine, it is critical that the buildId shall change for each new build of
 // the JS engine.
 typedef bool
-(* BuildIdOp)(mozilla::Vector<char> *buildId);
+(* BuildIdOp)(js::Vector<char> *buildId);
 
 struct AsmJSCacheOps
 {
     OpenAsmJSCacheEntryForReadOp openEntryForRead;
     CloseAsmJSCacheEntryForReadOp closeEntryForRead;
     OpenAsmJSCacheEntryForWriteOp openEntryForWrite;
     CloseAsmJSCacheEntryForWriteOp closeEntryForWrite;
     BuildIdOp buildId;
--- a/js/src/jsprf.cpp
+++ b/js/src/jsprf.cpp
@@ -365,17 +365,17 @@ static int cvt_s(SprintfState *ss, const
 }
 
 static int
 cvt_ws(SprintfState *ss, const jschar *ws, int width, int prec, int flags)
 {
     int result;
     /*
      * Supply nullptr as the JSContext; errors are not reported,
-     * and malloc() is used to allocate the buffer buffer.
+     * and js_malloc() is used to allocate the buffer.
      */
     if (ws) {
         size_t wslen = js_strlen(ws);
         char *latin1 = js_pod_malloc<char>(wslen + 1);
         if (!latin1)
             return -1; /* JSStuffFunc error indicator. */
         for (size_t i = 0; i < wslen; ++i)
             latin1[i] = (char)ws[i];
@@ -440,17 +440,17 @@ static struct NumArgState* BuildArgArray
     }
 
     if( number == 0 ){
         return nullptr;
     }
 
 
     if( number > NAS_DEFAULT_NUM ){
-        nas = (struct NumArgState*)malloc( number * sizeof( struct NumArgState ) );
+        nas = (struct NumArgState*)js_malloc( number * sizeof( struct NumArgState ) );
         if( !nas ){
             *rv = -1;
             return nullptr;
         }
     } else {
         nas = nasArray;
     }
 
@@ -1035,17 +1035,17 @@ JS_PUBLIC_API(uint32_t) JS_vsxprintf(JSS
     ss.func = func;
     ss.arg = arg;
     ss.maxlen = 0;
     rv = dosprintf(&ss, fmt, ap);
     return (rv < 0) ? UINT32_MAX : ss.maxlen;
 }
 
 /*
-** Stuff routine that automatically grows the malloc'd output buffer
+** Stuff routine that automatically grows the js_malloc'd output buffer
 ** before it overflows.
 */
 static int GrowStuff(SprintfState *ss, const char *sp, uint32_t len)
 {
     ptrdiff_t off;
     char *newbase;
     uint32_t newlen;
 
@@ -1068,17 +1068,17 @@ static int GrowStuff(SprintfState *ss, c
         --len;
         *ss->cur++ = *sp++;
     }
     JS_ASSERT(uint32_t(ss->cur - ss->base) <= ss->maxlen);
     return 0;
 }
 
 /*
-** sprintf into a malloc'd buffer
+** sprintf into a js_malloc'd buffer
 */
 JS_PUBLIC_API(char *) JS_smprintf(const char *fmt, ...)
 {
     va_list ap;
     char *rv;
 
     va_start(ap, fmt);
     rv = JS_vsmprintf(fmt, ap);
--- a/js/src/jspubtd.h
+++ b/js/src/jspubtd.h
@@ -30,16 +30,18 @@ class AutoIdVector;
 class CallArgs;
 
 template <typename T>
 class Rooted;
 
 class JS_PUBLIC_API(AutoGCRooter);
 
 class JS_PUBLIC_API(CompileOptions);
+class JS_PUBLIC_API(ReadOnlyCompileOptions);
+class JS_PUBLIC_API(OwningCompileOptions);
 class JS_PUBLIC_API(CompartmentOptions);
 
 struct Zone;
 
 } /* namespace JS */
 
 /*
  * Run-time version enumeration.  For compile-time version checking, please use
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -1665,17 +1665,17 @@ ScriptDataSize(uint32_t nbindings, uint3
 void
 JSScript::initCompartment(ExclusiveContext *cx)
 {
     compartment_ = cx->compartment_;
 }
 
 JSScript *
 JSScript::Create(ExclusiveContext *cx, HandleObject enclosingScope, bool savedCallerFun,
-                 const CompileOptions &options, unsigned staticLevel,
+                 const ReadOnlyCompileOptions &options, unsigned staticLevel,
                  HandleScriptSource sourceObject, uint32_t bufStart, uint32_t bufEnd)
 {
     JS_ASSERT(bufStart <= bufEnd);
 
     RootedScript script(cx, js_NewGCScript(cx));
     if (!script)
         return nullptr;
 
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -634,17 +634,17 @@ class JSScript : public js::gc::Barriere
 
     //
     // End of fields.  Start methods.
     //
 
   public:
     static JSScript *Create(js::ExclusiveContext *cx,
                             js::HandleObject enclosingScope, bool savedCallerFun,
-                            const JS::CompileOptions &options, unsigned staticLevel,
+                            const JS::ReadOnlyCompileOptions &options, unsigned staticLevel,
                             js::HandleScriptSource sourceObject, uint32_t sourceStart,
                             uint32_t sourceEnd);
 
     void initCompartment(js::ExclusiveContext *cx);
 
     // Three ways ways to initialize a JSScript. Callers of partiallyInit()
     // and fullyInitTrivial() are responsible for notifying the debugger after
     // successfully creating any kind (function or other) of new JSScript.
--- a/js/src/jsworkers.cpp
+++ b/js/src/jsworkers.cpp
@@ -169,52 +169,50 @@ js::CancelOffThreadIonCompile(JSCompartm
 static const JSClass workerGlobalClass = {
     "internal-worker-global", JSCLASS_GLOBAL_FLAGS,
     JS_PropertyStub,  JS_DeletePropertyStub,
     JS_PropertyStub,  JS_StrictPropertyStub,
     JS_EnumerateStub, JS_ResolveStub,
     JS_ConvertStub,   nullptr
 };
 
-ParseTask::ParseTask(ExclusiveContext *cx, const CompileOptions &options,
+ParseTask::ParseTask(ExclusiveContext *cx, JSContext *initCx,
                      const jschar *chars, size_t length, JSObject *scopeChain,
                      JS::OffThreadCompileCallback callback, void *callbackData)
-  : cx(cx), options(options), chars(chars), length(length),
+  : cx(cx), options(initCx), chars(chars), length(length),
     alloc(JSRuntime::TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE), scopeChain(scopeChain),
     callback(callback), callbackData(callbackData), script(nullptr), errors(cx)
 {
     JSRuntime *rt = scopeChain->runtimeFromMainThread();
 
-    if (options.principals())
-        JS_HoldPrincipals(options.principals());
-    if (options.originPrincipals())
-        JS_HoldPrincipals(options.originPrincipals());
     if (!AddObjectRoot(rt, &this->scopeChain, "ParseTask::scopeChain"))
         MOZ_CRASH();
 }
 
+bool
+ParseTask::init(JSContext *cx, const ReadOnlyCompileOptions &options)
+{
+    return this->options.copy(cx, options);
+}
+
 ParseTask::~ParseTask()
 {
     JSRuntime *rt = scopeChain->runtimeFromMainThread();
 
-    if (options.principals())
-        JS_DropPrincipals(rt, options.principals());
-    if (options.originPrincipals())
-        JS_DropPrincipals(rt, options.originPrincipals());
     JS_RemoveObjectRootRT(rt, &scopeChain);
 
     // ParseTask takes over ownership of its input exclusive context.
     js_delete(cx);
 
     for (size_t i = 0; i < errors.length(); i++)
         js_delete(errors[i]);
 }
 
 bool
-js::StartOffThreadParseScript(JSContext *cx, const CompileOptions &options,
+js::StartOffThreadParseScript(JSContext *cx, const ReadOnlyCompileOptions &options,
                               const jschar *chars, size_t length, HandleObject scopeChain,
                               JS::OffThreadCompileCallback callback, void *callbackData)
 {
     // Suppress GC so that calls below do not trigger a new incremental GC
     // which could require barriers on the atoms compartment.
     gc::AutoSuppressGC suppress(cx);
 
     frontend::MaybeCallSourceHandler(cx, options, chars, length);
@@ -262,19 +260,19 @@ js::StartOffThreadParseScript(JSContext 
         cx->new_<ExclusiveContext>(cx->runtime(), (PerThreadData *) nullptr,
                                    ThreadSafeContext::Context_Exclusive));
     if (!workercx)
         return false;
 
     workercx->enterCompartment(global->compartment());
 
     ScopedJSDeletePtr<ParseTask> task(
-        cx->new_<ParseTask>(workercx.get(), options, chars, length,
+        cx->new_<ParseTask>(workercx.get(), cx, chars, length,
                             scopeChain, callback, callbackData));
-    if (!task)
+    if (!task || !task->init(cx, options))
         return false;
 
     workercx.forget();
 
     WorkerThreadState &state = *cx->runtime()->workerThreadState;
     JS_ASSERT(state.numThreads);
 
     AutoLockWorkerThreadState lock(state);
@@ -1050,17 +1048,17 @@ js::StartOffThreadIonCompile(JSContext *
 }
 
 void
 js::CancelOffThreadIonCompile(JSCompartment *compartment, JSScript *script)
 {
 }
 
 bool
-js::StartOffThreadParseScript(JSContext *cx, const CompileOptions &options,
+js::StartOffThreadParseScript(JSContext *cx, const ReadOnlyCompileOptions &options,
                               const jschar *chars, size_t length, HandleObject scopeChain,
                               JS::OffThreadCompileCallback callback, void *callbackData)
 {
     MOZ_ASSUME_UNREACHABLE("Off thread compilation not available in non-THREADSAFE builds");
 }
 
 void
 js::WaitForOffThreadParsingToFinish(JSRuntime *rt)
--- a/js/src/jsworkers.h
+++ b/js/src/jsworkers.h
@@ -240,17 +240,17 @@ StartOffThreadIonCompile(JSContext *cx, 
 void
 CancelOffThreadIonCompile(JSCompartment *compartment, JSScript *script);
 
 /*
  * Start a parse/emit cycle for a stream of source. The characters must stay
  * alive until the compilation finishes.
  */
 bool
-StartOffThreadParseScript(JSContext *cx, const CompileOptions &options,
+StartOffThreadParseScript(JSContext *cx, const ReadOnlyCompileOptions &options,
                           const jschar *chars, size_t length, HandleObject scopeChain,
                           JS::OffThreadCompileCallback callback, void *callbackData);
 
 /* Block until in progress and pending off thread parse jobs have finished. */
 void
 WaitForOffThreadParsingToFinish(JSRuntime *rt);
 
 /* Start a compression job for the specified token. */
@@ -386,17 +386,17 @@ struct AsmJSParallelTask
         this->lir = nullptr;
     }
 };
 #endif
 
 struct ParseTask
 {
     ExclusiveContext *cx;
-    CompileOptions options;
+    OwningCompileOptions options;
     const jschar *chars;
     size_t length;
     LifoAlloc alloc;
 
     // Rooted pointer to the scope in the target compartment which the
     // resulting script will be merged into. This is not safe to use off the
     // main thread.
     JSObject *scopeChain;
@@ -409,19 +409,20 @@ struct ParseTask
     // point where FinishOffThreadScript is called, which will destroy the
     // ParseTask.
     JSScript *script;
 
     // Any errors or warnings produced during compilation. These are reported
     // when finishing the script.
     Vector<frontend::CompileError *> errors;
 
-    ParseTask(ExclusiveContext *cx, const CompileOptions &options,
+    ParseTask(ExclusiveContext *cx, JSContext *initCx,
               const jschar *chars, size_t length, JSObject *scopeChain,
               JS::OffThreadCompileCallback callback, void *callbackData);
+    bool init(JSContext *cx, const ReadOnlyCompileOptions &options);
 
     ~ParseTask();
 };
 
 // Compression tasks are allocated on the stack by their triggering thread,
 // which will block on the compression completing as the task goes out of scope
 // to ensure it completes at the required time.
 struct SourceCompressionTask
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -286,17 +286,17 @@ GetLine(FILE *file, const char * prompt)
         char *t = buffer + len - 1;
         if (*t == '\n') {
             /* Line was read. We remove '\n' and exit. */
             *t = '\0';
             return buffer;
         }
         if (len + 1 == size) {
             size = size * 2;
-            char *tmp = (char *) realloc(buffer, size);
+            char *tmp = (char *) js_realloc(buffer, size);
             if (!tmp) {
                 free(buffer);
                 return nullptr;
             }
             buffer = tmp;
         }
         current = buffer + len;
     }
@@ -331,17 +331,17 @@ struct JSShellContextData {
 static JSShellContextData *
 NewContextData()
 {
     /* Prevent creation of new contexts after we have been canceled. */
     if (gTimedOut)
         return nullptr;
 
     JSShellContextData *data = (JSShellContextData *)
-                               calloc(sizeof(JSShellContextData), 1);
+                               js_calloc(sizeof(JSShellContextData), 1);
     if (!data)
         return nullptr;
     data->startTime = PRMJ_Now();
     return data;
 }
 
 static inline JSShellContextData *
 GetContextData(JSContext *cx)
@@ -453,20 +453,19 @@ RunFile(JSContext *cx, Handle<JSObject*>
 }
 
 static bool
 EvalAndPrint(JSContext *cx, Handle<JSObject*> global, const char *bytes, size_t length,
              int lineno, bool compileOnly, FILE *out)
 {
     // Eval.
     JS::CompileOptions options(cx);
-    options.utf8 = true;
-    options.compileAndGo = true;
-    options.filename = "typein";
-    options.lineno = lineno;
+    options.setUTF8(true)
+           .setCompileAndGo(true)
+           .setFileAndLine("typein", lineno);
     RootedScript script(cx);
     script = JS::Compile(cx, global, options, bytes, length);
     if (!script)
         return false;
     if (compileOnly)
         return true;
     RootedValue result(cx);
     if (!JS_ExecuteScript(cx, global, script, result.address()))
@@ -5164,22 +5163,22 @@ ShellCloseAsmJSCacheEntryForWrite(Handle
 #endif
 
     JS_ASSERT(jsCacheOpened == true);
     jsCacheOpened = false;
     close(handle);
 }
 
 static bool
-ShellBuildId(mozilla::Vector<char> *buildId)
+ShellBuildId(js::Vector<char> *buildId)
 {
     // The browser embeds the date into the buildid and the buildid is embedded
     // in the binary, so every 'make' necessarily builds a new firefox binary.
     // Fortunately, the actual firefox executable is tiny -- all the code is in
-    // libxul.so and other shared modules -- so this isn't a big deal. No so
+    // libxul.so and other shared modules -- so this isn't a big deal. Not so
     // for the statically-linked JS shell. To avoid recompmiling js.cpp and
     // re-linking 'js' on every 'make', we use a constant buildid and rely on
     // the shell user to manually clear the cache (deleting the dir passed to
     // --js-cache) between cache-breaking updates. Note: jit_tests.py does this
     // on every run).
     const char buildid[] = "JS-shell";
     return buildId->append(buildid, sizeof(buildid));
 }
--- a/js/src/vm/PosixNSPR.cpp
+++ b/js/src/vm/PosixNSPR.cpp
@@ -25,45 +25,74 @@ class nspr::Thread
     Thread(void (*start)(void *arg), void *arg, bool joinable)
       : start(start), arg(arg), joinable(joinable) {}
 
     static void *ThreadRoutine(void *arg);
 
     pthread_t &pthread() { return pthread_; }
 };
 
-static __thread nspr::Thread *gSelfThread;
+static pthread_key_t gSelfThreadIndex;
 static nspr::Thread gMainThread(nullptr, nullptr, false);
 
 void *
 nspr::Thread::ThreadRoutine(void *arg)
 {
     Thread *self = static_cast<Thread *>(arg);
-    gSelfThread = self;
+    pthread_setspecific(gSelfThreadIndex, self);
     self->start(self->arg);
     if (!self->joinable)
-	js_delete(self);
+        js_delete(self);
     return nullptr;
 }
 
+static bool gInitialized;
+
+void
+DummyDestructor(void *)
+{
+}
+
+/* Should be called from the main thread. */
+static void
+Initialize()
+{
+    gInitialized = true;
+
+    if (pthread_key_create(&gSelfThreadIndex, DummyDestructor)) {
+        MOZ_CRASH();
+        return;
+    }
+
+    pthread_setspecific(gSelfThreadIndex, &gMainThread);
+}
+
 PRThread *
 PR_CreateThread(PRThreadType type,
 		void (*start)(void *arg),
 		void *arg,
 		PRThreadPriority priority,
 		PRThreadScope scope,
 		PRThreadState state,
 		uint32_t stackSize)
 {
     JS_ASSERT(type == PR_USER_THREAD);
     JS_ASSERT(priority == PR_PRIORITY_NORMAL);
 
+    if (!gInitialized) {
+        /*
+         * We assume that the first call to PR_CreateThread happens on the main
+         * thread.
+         */
+        Initialize();
+    }
+
     pthread_attr_t attr;
     if (pthread_attr_init(&attr))
-	return nullptr;
+        return nullptr;
 
     if (stackSize && pthread_attr_setstacksize(&attr, stackSize)) {
         pthread_attr_destroy(&attr);
         return nullptr;
     }
 
     nspr::Thread *t = js_new<nspr::Thread>(start, arg,
                                            state != PR_UNJOINABLE_THREAD);
@@ -100,31 +129,30 @@ PR_JoinThread(PRThread *thread)
     js_delete(thread);
 
     return PR_SUCCESS;
 }
 
 PRThread *
 PR_GetCurrentThread()
 {
-    if (!gSelfThread) {
-        /* Must be the main thread. */
-        gSelfThread = &gMainThread;
-    }
-    return gSelfThread;
+    if (!gInitialized)
+        Initialize();
+
+    return (PRThread *)pthread_getspecific(gSelfThreadIndex);
 }
 
 PRStatus
 PR_SetCurrentThreadName(const char *name)
 {
     int result;
-#ifdef XP_UNIX
+#ifdef XP_MACOSX
+    result = pthread_setname_np(name);
+#else
     result = pthread_setname_np(pthread_self(), name);
-#else
-    result = pthread_setname_np(name);
 #endif
     if (result)
         return PR_FAILURE;
     return PR_SUCCESS;
 }
 
 static const size_t MaxTLSKeyCount = 32;
 static size_t gTLSKeyCount;
@@ -291,17 +319,17 @@ PR_TicksPerSecond()
 {
     return TicksPerSecond;
 }
 
 PRStatus
 PR_WaitCondVar(PRCondVar *cvar, uint32_t timeout)
 {
     if (timeout == PR_INTERVAL_NO_TIMEOUT) {
-	if (pthread_cond_wait(&cvar->cond(), &cvar->lock()->mutex()))
+        if (pthread_cond_wait(&cvar->cond(), &cvar->lock()->mutex()))
             return PR_FAILURE;
         return PR_SUCCESS;
     } else {
         struct timespec ts;
         struct timeval tv;
 
         gettimeofday(&tv, nullptr);
         ts.tv_sec = tv.tv_sec;
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -324,17 +324,18 @@ protected:
   class ThebesLayerData {
   public:
     ThebesLayerData() :
       mActiveScrolledRoot(nullptr), mLayer(nullptr),
       mIsSolidColorInVisibleRegion(false),
       mNeedComponentAlpha(false),
       mForceTransparentSurface(false),
       mImage(nullptr),
-      mCommonClipCount(-1) {}
+      mCommonClipCount(-1),
+      mAllDrawingAbove(false) {}
     /**
      * Record that an item has been added to the ThebesLayer, so we
      * need to update our regions.
      * @param aVisibleRect the area of the item that's visible
      * @param aDrawRect the area of the item that would be drawn if it
      * was completely visible
      * @param aOpaqueRect if non-null, the area of the item that's opaque.
      * We pass in a separate opaque rect because the opaque rect can be
@@ -352,47 +353,85 @@ protected:
 
     /**
      * If this represents only a nsDisplayImage, and the image type
      * supports being optimized to an ImageLayer (TYPE_RASTER only) returns
      * an ImageContainer for the image.
      */
     already_AddRefed<ImageContainer> CanOptimizeImageLayer(nsDisplayListBuilder* aBuilder);
 
+    void AddDrawAboveRegion(const nsIntRegion& aAbove)
+    {
+      if (!mAllDrawingAbove) {
+        mDrawAboveRegion.Or(mDrawAboveRegion, aAbove);
+        mDrawAboveRegion.SimplifyOutward(4);
+      }
+    }
+
+    void AddVisibleAboveRegion(const nsIntRegion& aAbove)
+    {
+      if (!mAllDrawingAbove) {
+        mVisibleAboveRegion.Or(mVisibleAboveRegion, aAbove);
+        mVisibleAboveRegion.SimplifyOutward(4);
+      }
+    }
+
+    void CopyAboveRegion(ThebesLayerData* aOther)
+    {
+      if (aOther->mAllDrawingAbove || mAllDrawingAbove) {
+        SetAllDrawingAbove();
+      } else {
+        mVisibleAboveRegion.Or(mVisibleAboveRegion, aOther->mVisibleAboveRegion);
+        mVisibleAboveRegion.Or(mVisibleAboveRegion, aOther->mVisibleRegion);
+        mVisibleAboveRegion.SimplifyOutward(4);
+        mDrawAboveRegion.Or(mDrawAboveRegion, aOther->mDrawAboveRegion);
+        mDrawAboveRegion.Or(mDrawAboveRegion, aOther->mDrawRegion);
+        mDrawAboveRegion.SimplifyOutward(4);
+     }
+    }
+
+    void SetAllDrawingAbove()
+    {
+      mAllDrawingAbove = true;
+      mDrawAboveRegion.SetEmpty();
+      mVisibleAboveRegion.SetEmpty();
+    }
+
+    bool IsBelow(const nsIntRect& aRect)
+    {
+      return mAllDrawingAbove || mDrawAboveRegion.Intersects(aRect);
+    }
+
+    bool IntersectsVisibleAboveRegion(const nsIntRegion& aVisibleRegion)
+    {
+      if (mAllDrawingAbove) {
+        return true;
+      }
+      nsIntRegion visibleAboveIntersection;
+      visibleAboveIntersection.And(mVisibleAboveRegion, aVisibleRegion);
+      if (visibleAboveIntersection.IsEmpty()) {
+        return false;
+      }
+      return true;
+    }
+
     /**
      * The region of visible content in the layer, relative to the
      * container layer (which is at the snapped top-left of the display
      * list reference frame).
      */
     nsIntRegion  mVisibleRegion;
     /**
-     * The region of visible content above the layer and below the
-     * next ThebesLayerData currently in the stack, if any. Note that not
-     * all ThebesLayers for the container are in the ThebesLayerData stack.
-     * Same coordinate system as mVisibleRegion.
-     * This is a conservative approximation: it contains the true region.
-     */
-    nsIntRegion  mVisibleAboveRegion;
-    /**
      * The region containing the bounds of all display items in the layer,
      * regardless of visbility.
      * Same coordinate system as mVisibleRegion.
      * This is a conservative approximation: it contains the true region.
      */
     nsIntRegion  mDrawRegion;
     /**
-     * The region containing the bounds of all display items (regardless
-     * of visibility) in the layer and below the next ThebesLayerData
-     * currently in the stack, if any.
-     * Note that not all ThebesLayers for the container are in the
-     * ThebesLayerData stack.
-     * Same coordinate system as mVisibleRegion.
-     */
-    nsIntRegion  mDrawAboveRegion;
-    /**
      * The region of visible content in the layer that is opaque.
      * Same coordinate system as mVisibleRegion.
      */
     nsIntRegion  mOpaqueRegion;
     /**
      * The "active scrolled root" for all content in the layer. Must
      * be non-null; all content in a ThebesLayer must have the same
      * active scrolled root.
@@ -444,16 +483,40 @@ protected:
     int32_t mCommonClipCount;
     /*
      * Updates mCommonClipCount by checking for rounded rect clips in common
      * between the clip on a new item (aCurrentClip) and the common clips
      * on items already in the layer (the first mCommonClipCount rounded rects
      * in mItemClip).
      */
     void UpdateCommonClipCount(const DisplayItemClip& aCurrentClip);
+
+  private:
+    /**
+     * The region of visible content above the layer and below the
+     * next ThebesLayerData currently in the stack, if any. Note that not
+     * all ThebesLayers for the container are in the ThebesLayerData stack.
+     * Same coordinate system as mVisibleRegion.
+     * This is a conservative approximation: it contains the true region.
+     */
+    nsIntRegion  mVisibleAboveRegion;
+    /**
+     * The region containing the bounds of all display items (regardless
+     * of visibility) in the layer and below the next ThebesLayerData
+     * currently in the stack, if any.
+     * Note that not all ThebesLayers for the container are in the
+     * ThebesLayerData stack.
+     * Same coordinate system as mVisibleRegion.
+     */
+    nsIntRegion  mDrawAboveRegion;
+    /**
+     * True if mDrawAboveRegion and mVisibleAboveRegion should be treated
+     * as infinite, and all display items should be considered 'above' this layer.
+     */
+    bool mAllDrawingAbove;
   };
   friend class ThebesLayerData;
 
   /**
    * Grab the next recyclable ThebesLayer, or create one if there are no
    * more recyclable ThebesLayers. Does any necessary invalidation of
    * a recycled ThebesLayer, and sets up the transform on the ThebesLayer
    * to account for scrolling.
@@ -1447,19 +1510,17 @@ SetVisibleRegionForLayer(Layer* aLayer, 
 }
 
 nscolor
 ContainerState::FindOpaqueBackgroundColorFor(int32_t aThebesLayerIndex)
 {
   ThebesLayerData* target = mThebesLayerDataStack[aThebesLayerIndex];
   for (int32_t i = aThebesLayerIndex - 1; i >= 0; --i) {
     ThebesLayerData* candidate = mThebesLayerDataStack[i];
-    nsIntRegion visibleAboveIntersection;
-    visibleAboveIntersection.And(candidate->mVisibleAboveRegion, target->mVisibleRegion);
-    if (!visibleAboveIntersection.IsEmpty()) {
+    if (candidate->IntersectsVisibleAboveRegion(target->mVisibleRegion)) {
       // Some non-Thebes content between target and candidate; this is
       // hopeless
       break;
     }
 
     nsIntRegion intersection;
     intersection.And(candidate->mVisibleRegion, target->mVisibleRegion);
     if (intersection.IsEmpty()) {
@@ -1658,26 +1719,17 @@ ContainerState::PopThebesLayerData()
   }
   layer->SetContentFlags(flags);
 
   if (lastIndex > 0) {
     // Since we're going to pop off the last ThebesLayerData, the
     // mVisibleAboveRegion of the second-to-last item will need to include
     // the regions of the last item.
     ThebesLayerData* nextData = mThebesLayerDataStack[lastIndex - 1];
-    nextData->mVisibleAboveRegion.Or(nextData->mVisibleAboveRegion,
-                                     data->mVisibleAboveRegion);
-    nextData->mVisibleAboveRegion.Or(nextData->mVisibleAboveRegion,
-                                     data->mVisibleRegion);
-    nextData->mVisibleAboveRegion.SimplifyOutward(4);
-    nextData->mDrawAboveRegion.Or(nextData->mDrawAboveRegion,
-                                     data->mDrawAboveRegion);
-    nextData->mDrawAboveRegion.Or(nextData->mDrawAboveRegion,
-                                     data->mDrawRegion);
-    nextData->mDrawAboveRegion.SimplifyOutward(4);
+    nextData->CopyAboveRegion(data);
   }
 
   mThebesLayerDataStack.RemoveElementAt(lastIndex);
 }
 
 static bool
 SuppressComponentAlpha(nsDisplayListBuilder* aBuilder,
                        nsDisplayItem* aItem,
@@ -1845,17 +1897,17 @@ ContainerState::FindThebesLayerFor(nsDis
                                    const nsIFrame* aActiveScrolledRoot,
                                    const nsPoint& aTopLeft)
 {
   int32_t i;
   int32_t lowestUsableLayerWithScrolledRoot = -1;
   int32_t topmostLayerWithScrolledRoot = -1;
   for (i = mThebesLayerDataStack.Length() - 1; i >= 0; --i) {
     ThebesLayerData* data = mThebesLayerDataStack[i];
-    if (data->mDrawAboveRegion.Intersects(aVisibleRect)) {
+    if (data->IsBelow(aVisibleRect)) {
       ++i;
       break;
     }
     if (data->mActiveScrolledRoot == aActiveScrolledRoot) {
       lowestUsableLayerWithScrolledRoot = i;
       if (topmostLayerWithScrolledRoot < 0) {
         topmostLayerWithScrolledRoot = i;
       }
@@ -2155,24 +2207,34 @@ ContainerState::ProcessDisplayItems(cons
       // It has its own layer. Update that layer's clip and visible rects.
       if (itemClip.HasClip()) {
         ownLayer->SetClipRect(&clipRect);
       } else {
         ownLayer->SetClipRect(nullptr);
       }
       ThebesLayerData* data = GetTopThebesLayerData();
       if (data) {
-        data->mVisibleAboveRegion.Or(data->mVisibleAboveRegion, itemVisibleRect);
-        data->mVisibleAboveRegion.SimplifyOutward(4);
-        // Add the entire bounds rect to the mDrawAboveRegion.
-        // The visible region may be excluding opaque content above the
-        // item, and we need to ensure that that content is not placed
-        // in a ThebesLayer below the item!
-        data->mDrawAboveRegion.Or(data->mDrawAboveRegion, itemDrawRect);
-        data->mDrawAboveRegion.SimplifyOutward(4);
+        // Prerendered transform items can be updated without layer building
+        // (async animations or an empty transaction), so we treat all other
+        // content as being above this so that the transformed layer can correctly
+        // move behind other content.
+        if (item->GetType() == nsDisplayItem::TYPE_TRANSFORM &&
+            nsDisplayTransform::ShouldPrerenderTransformedContent(mBuilder,
+                                                                  item->Frame(),
+                                                                  false)) {
+          data->SetAllDrawingAbove();
+        } else {
+          data->AddVisibleAboveRegion(itemVisibleRect);
+
+          // Add the entire bounds rect to the mDrawAboveRegion.
+          // The visible region may be excluding opaque content above the
+          // item, and we need to ensure that that content is not placed
+          // in a ThebesLayer below the item!
+          data->AddDrawAboveRegion(itemDrawRect);
+        }
       }
       itemVisibleRect.MoveBy(mParameters.mOffset);
       if (setVisibleRegion) {
         SetVisibleRegionForLayer(ownLayer, ownLayer->GetVisibleRegion(), itemVisibleRect);
       }
 
       // rounded rectangle clipping using mask layers
       // (must be done after visible rect is set on layer)
--- a/layout/base/nsCSSRendering.cpp
+++ b/layout/base/nsCSSRendering.cpp
@@ -44,20 +44,22 @@
 #include "gfxDrawable.h"
 #include "GeckoProfiler.h"
 #include "nsCSSRenderingBorders.h"
 #include "mozilla/css/ImageLoader.h"
 #include "ImageContainer.h"
 #include "mozilla/Telemetry.h"
 #include "gfxUtils.h"
 #include "gfxColor.h"
+#include "gfxGradientCache.h"
 #include <algorithm>
 
 using namespace mozilla;
 using namespace mozilla::css;
+using namespace mozilla::gfx;
 using mozilla::image::ImageOps;
 using mozilla::CSSSizeOrRatio;
 
 static int gFrameTreeLockCount = 0;
 
 // To avoid storing this data on nsInlineFrame (bloat) and to avoid
 // recalculating this for each frame in a continuation (perf), hold
 // a cache of various coordinate information that we need in order
@@ -289,174 +291,16 @@ protected:
 // and a Thebes color
 struct ColorStop {
   ColorStop(double aPosition, gfxRGBA aColor) :
     mPosition(aPosition), mColor(aColor) {}
   double mPosition; // along the gradient line; 0=start, 1=end
   gfxRGBA mColor;
 };
 
-struct GradientCacheKey : public PLDHashEntryHdr {
-  typedef const GradientCacheKey& KeyType;
-  typedef const GradientCacheKey* KeyTypePointer;
-  enum { ALLOW_MEMMOVE = true };
-  const nsTArray<gfx::GradientStop> mStops;
-  const bool mRepeating;
-  const gfx::BackendType mBackendType;
-
-  GradientCacheKey(const nsTArray<gfx::GradientStop>& aStops, const bool aRepeating, const gfx::BackendType aBackendType)
-    : mStops(aStops), mRepeating(aRepeating), mBackendType(aBackendType)
-  { }
-
-  GradientCacheKey(const GradientCacheKey* aOther)
-    : mStops(aOther->mStops), mRepeating(aOther->mRepeating), mBackendType(aOther->mBackendType)
-  { }
-
-  union FloatUint32
-  {
-    float    f;
-    uint32_t u;
-  };
-
-  static PLDHashNumber
-  HashKey(const KeyTypePointer aKey)
-  {
-    PLDHashNumber hash = 0;
-    FloatUint32 convert;
-    hash = AddToHash(hash, aKey->mBackendType);
-    hash = AddToHash(hash, aKey->mRepeating);
-    for (uint32_t i = 0; i < aKey->mStops.Length(); i++) {
-      hash = AddToHash(hash, aKey->mStops[i].color.ToABGR());
-      // Use the float bits as hash, except for the cases of 0.0 and -0.0 which both map to 0
-      convert.f = aKey->mStops[i].offset;
-      hash = AddToHash(hash, convert.f ? convert.u : 0);
-    }
-    return hash;
-  }
-
-  bool KeyEquals(KeyTypePointer aKey) const
-  {
-    bool sameStops = true;
-    if (aKey->mStops.Length() != mStops.Length()) {
-      sameStops = false;
-    } else {
-      for (uint32_t i = 0; i < mStops.Length(); i++) {
-        if (mStops[i].color.ToABGR() != aKey->mStops[i].color.ToABGR() ||
-            mStops[i].offset != aKey->mStops[i].offset) {
-          sameStops = false;
-          break;
-        }
-      }
-    }
-
-    return sameStops &&
-           (aKey->mBackendType == mBackendType) &&
-           (aKey->mRepeating == mRepeating);
-  }
-  static KeyTypePointer KeyToPointer(KeyType aKey)
-  {
-    return &aKey;
-  }
-};
-
-/**
- * This class is what is cached. It need to be allocated in an object separated
- * to the cache entry to be able to be tracked by the nsExpirationTracker.
- * */
-struct GradientCacheData {
-  GradientCacheData(mozilla::gfx::GradientStops* aStops, const GradientCacheKey& aKey)
-    : mStops(aStops),
-      mKey(aKey)
-  {}
-
-  GradientCacheData(const GradientCacheData& aOther)
-    : mStops(aOther.mStops),
-      mKey(aOther.mKey)
-  { }
-
-  nsExpirationState *GetExpirationState() {
-    return &mExpirationState;
-  }
-
-  nsExpirationState mExpirationState;
-  const mozilla::RefPtr<mozilla::gfx::GradientStops> mStops;
-  GradientCacheKey mKey;
-};
-
-/**
- * This class implements a cache with no maximum size, that retains the
- * gfxPatterns used to draw the gradients.
- *
- * The key is the nsStyleGradient that defines the gradient, and the size of the
- * gradient.
- *
- * The value is the gfxPattern, and whether or not we perform an optimization
- * based on the actual gradient property.
- *
- * An entry stays in the cache as long as it is used often. As long as a cache
- * entry is in the cache, all the references it has are guaranteed to be valid:
- * the nsStyleRect for the key, the gfxPattern for the value.
- */
-class GradientCache MOZ_FINAL : public nsExpirationTracker<GradientCacheData,4>
-{
-  public:
-    GradientCache()
-      : nsExpirationTracker<GradientCacheData, 4>(MAX_GENERATION_MS)
-    {
-      srand(time(nullptr));
-      mTimerPeriod = rand() % MAX_GENERATION_MS + 1;
-      Telemetry::Accumulate(Telemetry::GRADIENT_RETENTION_TIME, mTimerPeriod);
-    }
-
-    virtual void NotifyExpired(GradientCacheData* aObject)
-    {
-      // This will free the gfxPattern.
-      RemoveObject(aObject);
-      mHashEntries.Remove(aObject->mKey);
-    }
-
-    GradientCacheData* Lookup(const nsTArray<gfx::GradientStop>& aStops, bool aRepeating, gfx::BackendType aBackendType)
-    {
-      GradientCacheData* gradient =
-        mHashEntries.Get(GradientCacheKey(aStops, aRepeating, aBackendType));
-
-      if (gradient) {
-        MarkUsed(gradient);
-      }
-
-      return gradient;
-    }
-
-    // Returns true if we successfully register the gradient in the cache, false
-    // otherwise.
-    bool RegisterEntry(GradientCacheData* aValue)
-    {
-      nsresult rv = AddObject(aValue);
-      if (NS_FAILED(rv)) {
-        // We are OOM, and we cannot track this object. We don't want stall
-        // entries in the hash table (since the expiration tracker is responsible
-        // for removing the cache entries), so we avoid putting that entry in the
-        // table, which is a good things considering we are short on memory
-        // anyway, we probably don't want to retain things.
-        return false;
-      }
-      mHashEntries.Put(aValue->mKey, aValue);
-      return true;
-    }
-
-  protected:
-    uint32_t mTimerPeriod;
-    static const uint32_t MAX_GENERATION_MS = 10000;
-    /**
-     * FIXME use nsTHashtable to avoid duplicating the GradientCacheKey.
-     * https://bugzilla.mozilla.org/show_bug.cgi?id=761393#c47
-     */
-    nsClassHashtable<GradientCacheKey, GradientCacheData> mHashEntries;
-};
-
 /* Local functions */
 static void DrawBorderImage(nsPresContext* aPresContext,
                             nsRenderingContext& aRenderingContext,
                             nsIFrame* aForFrame,
                             const nsRect& aBorderArea,
                             const nsStyleBorder& aStyleBorder,
                             const nsRect& aDirtyRect);
 
@@ -472,35 +316,29 @@ static void DrawBorderImageComponent(nsR
                                      const nsStyleBorder& aStyleBorder,
                                      uint8_t aIndex);
 
 static nscolor MakeBevelColor(mozilla::css::Side whichSide, uint8_t style,
                               nscolor aBackgroundColor,
                               nscolor aBorderColor);
 
 static InlineBackgroundData* gInlineBGData = nullptr;
-static GradientCache* gGradientCache = nullptr;
 
 // Initialize any static variables used by nsCSSRendering.
 void nsCSSRendering::Init()
 {
   NS_ASSERTION(!gInlineBGData, "Init called twice");
   gInlineBGData = new InlineBackgroundData();
-  gGradientCache = new GradientCache();
-  nsCSSBorderRenderer::Init();
 }
 
 // Clean up any global variables used by nsCSSRendering.
 void nsCSSRendering::Shutdown()
 {
   delete gInlineBGData;
   gInlineBGData = nullptr;
-  delete gGradientCache;
-  gGradientCache = nullptr;
-  nsCSSBorderRenderer::Shutdown();
 }
 
 /**
  * Make a bevel color
  */
 static nscolor
 MakeBevelColor(mozilla::css::Side whichSide, uint8_t style,
                nscolor aBackgroundColor, nscolor aBorderColor)
@@ -2155,25 +1993,16 @@ nsCSSRendering::PaintGradient(nsPresCont
 
   gfxContext *ctx = aRenderingContext.ThebesContext();
   nscoord appUnitsPerPixel = aPresContext->AppUnitsPerDevPixel();
   gfxRect oneCellArea =
     nsLayoutUtils::RectToGfxRect(aOneCellArea, appUnitsPerPixel);
 
   bool cellContainsFill = aOneCellArea.Contains(aFillArea);
 
-  gfx::BackendType backendType = gfx::BACKEND_NONE;
-  if (ctx->IsCairo()) {
-    backendType = gfx::BACKEND_CAIRO;
-  } else {
-    gfx::DrawTarget* dt = ctx->GetDrawTarget();
-    NS_ASSERTION(dt, "If we are not using Cairo, we should have a draw target.");
-    backendType = dt->GetType();
-  }
-
   // Compute "gradient line" start and end relative to oneCellArea
   gfxPoint lineStart, lineEnd;
   double radiusX = 0, radiusY = 0; // for radial gradients only
   if (aGradient->mShape == NS_STYLE_GRADIENT_SHAPE_LINEAR) {
     ComputeLinearGradientLine(aPresContext, aGradient, oneCellArea.Size(),
                               &lineStart, &lineEnd);
   } else {
     ComputeRadialGradientLine(aPresContext, aGradient, oneCellArea.Size(),
@@ -2438,28 +2267,22 @@ nsCSSRendering::PaintGradient(nsPresCont
     // which is a lookup table used to evaluate the gradient. This surface can use
     // much memory (ram and/or GPU ram) and can be expensive to create. So we cache it.
     // The cache key correlates 1:1 with the arguments for CreateGradientStops (also the implied backend type)
     // Note that GradientStop is a simple struct with a stop value (while GradientStops has the surface).
     nsTArray<gfx::GradientStop> rawStops(stops.Length());
     rawStops.SetLength(stops.Length());
     for(uint32_t i = 0; i < stops.Length(); i++) {
       rawStops[i].color = gfx::Color(stops[i].mColor.r, stops[i].mColor.g, stops[i].mColor.b, stops[i].mColor.a);
-      rawStops[i].offset =  stopScale * (stops[i].mPosition - stopOrigin);
+      rawStops[i].offset = stopScale * (stops[i].mPosition - stopOrigin);
     }
-    GradientCacheData* cached = gGradientCache->Lookup(rawStops, isRepeat, backendType);
-    mozilla::RefPtr<mozilla::gfx::GradientStops> gs = cached ? cached->mStops : nullptr;
-    if (!gs) {
-      // CreateGradientStops is expensive (possibly lazily)
-      gs = ctx->GetDrawTarget()->CreateGradientStops(rawStops.Elements(), stops.Length(), isRepeat ? gfx::EXTEND_REPEAT : gfx::EXTEND_CLAMP);
-      cached = new GradientCacheData(gs, GradientCacheKey(rawStops, isRepeat, backendType));
-      if (!gGradientCache->RegisterEntry(cached)) {
-        delete cached;
-      }
-    }
+    mozilla::RefPtr<mozilla::gfx::GradientStops> gs =
+      gfxGradientCache::GetOrCreateGradientStops(ctx->GetDrawTarget(),
+                                                 rawStops,
+                                                 isRepeat ? gfx::EXTEND_REPEAT : gfx::EXTEND_CLAMP);
     gradientPattern->SetColorStops(gs);
   } else {
     for (uint32_t i = 0; i < stops.Length(); i++) {
       double pos = stopScale*(stops[i].mPosition - stopOrigin);
       gradientPattern->AddColorStop(pos, stops[i].mColor);
     }
     // Set repeat mode. Default cairo extend mode is PAD.
     if (isRepeat) {
--- a/layout/base/nsCSSRenderingBorders.cpp
+++ b/layout/base/nsCSSRenderingBorders.cpp
@@ -6,163 +6,26 @@
 
 #include "nsStyleConsts.h"
 #include "nsCSSColorUtils.h"
 #include "GeckoProfiler.h"
 #include "nsExpirationTracker.h"
 #include "RoundedRect.h"
 #include "nsClassHashtable.h"
 #include "nsStyleStruct.h"
-
 #include "gfxContext.h"
-
 #include "nsCSSRenderingBorders.h"
-
 #include "mozilla/gfx/2D.h"
 #include "gfx2DGlue.h"
+#include "gfxGradientCache.h"
 #include <algorithm>
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 
-struct BorderGradientCacheKey : public PLDHashEntryHdr {
-  typedef const BorderGradientCacheKey& KeyType;
-  typedef const BorderGradientCacheKey* KeyTypePointer;
-
-  enum { ALLOW_MEMMOVE = true };
-
-  const uint32_t mColor1;
-  const uint32_t mColor2;
-  const BackendType mBackendType;
-
-  BorderGradientCacheKey(const Color& aColor1, const Color& aColor2,
-                         BackendType aBackendType)
-    : mColor1(aColor1.ToABGR()), mColor2(aColor2.ToABGR())
-    , mBackendType(aBackendType)
-  { }
-
-  BorderGradientCacheKey(const BorderGradientCacheKey* aOther)
-    : mColor1(aOther->mColor1), mColor2(aOther->mColor2)
-    , mBackendType(aOther->mBackendType)
-  { }
-
-  static PLDHashNumber
-  HashKey(const KeyTypePointer aKey)
-  {
-    PLDHashNumber hash = 0;
-    hash = AddToHash(hash, aKey->mColor1);
-    hash = AddToHash(hash, aKey->mColor2);
-    hash = AddToHash(hash, aKey->mBackendType);
-    return hash;
-  }
-
-  bool KeyEquals(KeyTypePointer aKey) const
-  {
-    return (aKey->mColor1 == mColor1) &&
-           (aKey->mColor2 == mColor2) &&
-           (aKey->mBackendType == mBackendType);
-  }
-  static KeyTypePointer KeyToPointer(KeyType aKey)
-  {
-    return &aKey;
-  }
-};
-
-/**
- * This class is what is cached. It need to be allocated in an object separated
- * to the cache entry to be able to be tracked by the nsExpirationTracker.
- * */
-struct BorderGradientCacheData {
-  BorderGradientCacheData(GradientStops* aStops, const BorderGradientCacheKey& aKey)
-    : mStops(aStops), mKey(aKey)
-  {}
-
-  BorderGradientCacheData(const BorderGradientCacheData& aOther)
-    : mStops(aOther.mStops),
-      mKey(aOther.mKey)
-  { }
-
-  nsExpirationState *GetExpirationState() {
-    return &mExpirationState;
-  }
-
-  nsExpirationState mExpirationState;
-  RefPtr<GradientStops> mStops;
-  BorderGradientCacheKey mKey;
-};
-
-/**
- * This class implements a cache with no maximum size, that retains the
- * gradient stops used to draw border corners.
- *
- * The key is formed by the two gradient stops, they're always both located
- * at an offset of 0.5. So they can generously be reused. The key also includes
- * the backend type a certain gradient was created for.
- *
- * An entry stays in the cache as long as it is used often.
- *
- * This code was pretty bluntly stolen and modified from nsCSSRendering.
- */
-class BorderGradientCache MOZ_FINAL : public nsExpirationTracker<BorderGradientCacheData,4>
-{
-  public:
-    BorderGradientCache()
-      : nsExpirationTracker<BorderGradientCacheData, 4>(GENERATION_MS)
-    {
-      mTimerPeriod = GENERATION_MS;
-    }
-
-    virtual void NotifyExpired(BorderGradientCacheData* aObject)
-    {
-      // This will free the gfxPattern.
-      RemoveObject(aObject);
-      mHashEntries.Remove(aObject->mKey);
-    }
-
-    BorderGradientCacheData* Lookup(const Color& aColor1, const Color& aColor2,
-                                    BackendType aBackendType)
-    {
-      BorderGradientCacheData* gradient =
-        mHashEntries.Get(BorderGradientCacheKey(aColor1, aColor2, aBackendType));
-
-      if (gradient) {
-        MarkUsed(gradient);
-      }
-
-      return gradient;
-    }
-
-    // Returns true if we successfully register the gradient in the cache, false
-    // otherwise.
-    bool RegisterEntry(BorderGradientCacheData* aValue)
-    {
-      nsresult rv = AddObject(aValue);
-      if (NS_FAILED(rv)) {
-        // We are OOM, and we cannot track this object. We don't want stall
-        // entries in the hash table (since the expiration tracker is responsible
-        // for removing the cache entries), so we avoid putting that entry in the
-        // table, which is a good things considering we are short on memory
-        // anyway, we probably don't want to retain things.
-        return false;
-      }
-      mHashEntries.Put(aValue->mKey, aValue);
-      return true;
-    }
-
-  protected:
-    uint32_t mTimerPeriod;
-    static const uint32_t GENERATION_MS = 4000;
-    /**
-     * FIXME use nsTHashtable to avoid duplicating the BorderGradientCacheKey.
-     * This is analogous to the issue for the generic gradient cache:
-     * https://bugzilla.mozilla.org/show_bug.cgi?id=785794
-     */
-    nsClassHashtable<BorderGradientCacheKey, BorderGradientCacheData> mHashEntries;
-};
-
 /**
  * nsCSSRendering::PaintBorder
  * nsCSSRendering::PaintOutline
  *   -> DrawBorders
  *
  * DrawBorders
  *   -> Ability to use specialized approach?
  *      |- Draw using specialized function
@@ -244,18 +107,16 @@ typedef enum {
   // adjacent corners.
   CORNER_SOLID,
 
   // Paint the corner as a dot, the size of the bigger of the adjacent
   // sides.
   CORNER_DOT
 } CornerStyle;
 
-static BorderGradientCache* gBorderGradientCache = nullptr;
-
 nsCSSBorderRenderer::nsCSSBorderRenderer(int32_t aAppUnitsPerPixel,
                                          gfxContext* aDestContext,
                                          gfxRect& aOuterRect,
                                          const uint8_t* aBorderStyles,
                                          const gfxFloat* aBorderWidths,
                                          gfxCornerSizes& aBorderRadii,
                                          const nscolor* aBorderColors,
                                          nsBorderColors* const* aCompositeColors,
@@ -286,28 +147,16 @@ nsCSSBorderRenderer::nsCSSBorderRenderer
 
   ComputeBorderCornerDimensions(mOuterRect, mInnerRect, mBorderRadii, &mBorderCornerDimensions);
 
   mOneUnitBorder = CheckFourFloatsEqual(mBorderWidths, 1.0);
   mNoBorderRadius = AllCornersZeroSize(mBorderRadii);
   mAvoidStroke = false;
 }
 
-void
-nsCSSBorderRenderer::Init()
-{
-  gBorderGradientCache = new BorderGradientCache();
-}
-
-void
-nsCSSBorderRenderer::Shutdown()
-{
-  delete gBorderGradientCache;
-}
-
 /* static */ void
 nsCSSBorderRenderer::ComputeInnerRadii(const gfxCornerSizes& aRadii,
                                        const gfxFloat *aBorderSizes,
                                        gfxCornerSizes *aInnerRadiiRet)
 {
   gfxCornerSizes& iRadii = *aInnerRadiiRet;
 
   iRadii[C_TL].width = std::max(0.0, aRadii[C_TL].width - aBorderSizes[NS_SIDE_LEFT]);
@@ -1277,54 +1126,39 @@ nsCSSBorderRenderer::CreateCornerGradien
     mBorderWidths[cornerWidth[aCorner]]  * gradientCoeff[aCorner].b;
 
   aPoint1 = Point(pat1.x, pat1.y);
   aPoint2 = Point(pat2.x, pat2.y);
 
   Color firstColor = ToColor(aFirstColor);
   Color secondColor = ToColor(aSecondColor);
 
-  BorderGradientCacheData *data =
-    gBorderGradientCache->Lookup(firstColor, secondColor, aDT->GetType());
-
-  if (!data) {
+  nsTArray<gfx::GradientStop> rawStops(2);
+  rawStops.SetLength(2);
+  // This is only guaranteed to give correct (and in some cases more correct)
+  // rendering with the Direct2D Azure and Quartz Cairo backends. For other
+  // cairo backends it could create un-antialiased border corner transitions
+  // since that at least used to be pixman's behaviour for hard stops.
+  rawStops[0].color = firstColor;
+  rawStops[0].offset = 0.5;
+  rawStops[1].color = secondColor;
+  rawStops[1].offset = 0.5;
+  RefPtr<GradientStops> gs =
+    gfxGradientCache::GetGradientStops(aDT, rawStops, EXTEND_CLAMP);
+  if (!gs) {
     // Having two corners, both with reversed color stops is pretty common
     // for certain border types. Let's optimize it!
-    data = gBorderGradientCache->Lookup(secondColor, firstColor, aDT->GetType());
-
-    if (data) {
-      Point tmp = aPoint1;
-      aPoint1 = aPoint2;
-      aPoint2 = tmp;
-    }
+    rawStops[0].color = secondColor;
+    rawStops[1].color = firstColor;
+    Point tmp = aPoint1;
+    aPoint1 = aPoint2;
+    aPoint2 = tmp;
+    gs = gfxGradientCache::GetOrCreateGradientStops(aDT, rawStops, EXTEND_CLAMP);
   }
-
-  RefPtr<GradientStops> stops;
-  if (data) {
-    stops = data->mStops;
-  } else {
-    GradientStop rawStops[2];
-    // This is only guaranteed to give correct (and in some cases more correct)
-    // rendering with the Direct2D Azure and Quartz Cairo backends. For other
-    // cairo backends it could create un-antialiased border corner transitions
-    // since that at least used to be pixman's behaviour for hard stops.
-    rawStops[0].color = firstColor;
-    rawStops[0].offset = 0.5;
-    rawStops[1].color = secondColor;
-    rawStops[1].offset = 0.5;
-    stops = aDT->CreateGradientStops(rawStops, 2);
-
-    data = new BorderGradientCacheData(stops, BorderGradientCacheKey(firstColor, secondColor, aDT->GetType()));
-
-    if (!gBorderGradientCache->RegisterEntry(data)) {
-      delete data;
-    }
-  }
-
-  return stops;
+  return gs;
 }
 
 typedef struct { gfxFloat a, b; } twoFloats;
 
 void
 nsCSSBorderRenderer::DrawSingleWidthSolidBorder()
 {
   // Easy enough to deal with.
--- a/layout/base/nsCSSRenderingBorders.h
+++ b/layout/base/nsCSSRenderingBorders.h
@@ -77,19 +77,16 @@ struct nsCSSBorderRenderer {
                       const uint8_t* aBorderStyles,
                       const gfxFloat* aBorderWidths,
                       gfxCornerSizes& aBorderRadii,
                       const nscolor* aBorderColors,
                       nsBorderColors* const* aCompositeColors,
                       int aSkipSides,
                       nscolor aBackgroundColor);
 
-  static void Init();
-  static void Shutdown();
-
   gfxCornerSizes mBorderCornerDimensions;
 
   // destination context
   gfxContext* mContext;
 
   // the rectangle of the outside and the inside of the border
   gfxRect mOuterRect;
   gfxRect mInnerRect;
--- a/layout/media/webrtc/Makefile.in
+++ b/layout/media/webrtc/Makefile.in
@@ -4,33 +4,36 @@
 
 # shared libs for webrtc
 SHARED_LIBRARY_LIBS = \
   $(call EXPAND_LIBNAME_PATH,common_video,$(DEPTH)/media/webrtc/trunk/webrtc/common_video/common_video_common_video) \
   $(call EXPAND_LIBNAME_PATH,common_audio,$(DEPTH)/media/webrtc/trunk/webrtc/common_audio/common_audio_common_audio) \
   $(call EXPAND_LIBNAME_PATH,video_capture_module,$(DEPTH)/media/webrtc/trunk/webrtc/modules/modules_video_capture_module) \
   $(call EXPAND_LIBNAME_PATH,webrtc_utility,$(DEPTH)/media/webrtc/trunk/webrtc/modules/modules_webrtc_utility) \
   $(call EXPAND_LIBNAME_PATH,audio_coding_module,$(DEPTH)/media/webrtc/trunk/webrtc/modules/modules_audio_coding_module) \
+  $(call EXPAND_LIBNAME_PATH,acm2,$(DEPTH)/media/webrtc/trunk/webrtc/modules/modules_acm2) \
   $(call EXPAND_LIBNAME_PATH,CNG,$(DEPTH)/media/webrtc/trunk/webrtc/modules/modules_CNG) \
   $(call EXPAND_LIBNAME_PATH,G711,$(DEPTH)/media/webrtc/trunk/webrtc/modules/modules_G711) \
   $(call EXPAND_LIBNAME_PATH,PCM16B,$(DEPTH)/media/webrtc/trunk/webrtc/modules/modules_PCM16B) \
   $(call EXPAND_LIBNAME_PATH,NetEq,$(DEPTH)/media/webrtc/trunk/webrtc/modules/modules_NetEq) \
+  $(call EXPAND_LIBNAME_PATH,NetEq4,$(DEPTH)/media/webrtc/trunk/webrtc/modules/modules_NetEq4) \
   $(call EXPAND_LIBNAME_PATH,system_wrappers,$(DEPTH)/media/webrtc/trunk/webrtc/system_wrappers/source/system_wrappers_system_wrappers) \
   $(call EXPAND_LIBNAME_PATH,webrtc_video_coding,$(DEPTH)/media/webrtc/trunk/webrtc/modules/modules_webrtc_video_coding) \
   $(call EXPAND_LIBNAME_PATH,video_coding_utility,$(DEPTH)/media/webrtc/trunk/webrtc/modules/video_coding/utility/video_coding_utility_video_coding_utility) \
   $(call EXPAND_LIBNAME_PATH,webrtc_i420,$(DEPTH)/media/webrtc/trunk/webrtc/modules/modules_webrtc_i420) \
   $(call EXPAND_LIBNAME_PATH,webrtc_vp8,$(DEPTH)/media/webrtc/trunk/webrtc/modules/video_coding/codecs/vp8/vp8_webrtc_vp8) \
   $(call EXPAND_LIBNAME_PATH,webrtc_opus,$(DEPTH)/media/webrtc/trunk/webrtc/modules/modules_webrtc_opus) \
   $(call EXPAND_LIBNAME_PATH,video_render_module,$(DEPTH)/media/webrtc/trunk/webrtc/modules/modules_video_render_module) \
   $(call EXPAND_LIBNAME_PATH,video_engine_core,$(DEPTH)/media/webrtc/trunk/webrtc/video_engine/video_engine_video_engine_core) \
   $(call EXPAND_LIBNAME_PATH,voice_engine,$(DEPTH)/media/webrtc/trunk/webrtc/voice_engine/voice_engine_voice_engine) \
   $(call EXPAND_LIBNAME_PATH,media_file,$(DEPTH)/media/webrtc/trunk/webrtc/modules/modules_media_file) \
   $(call EXPAND_LIBNAME_PATH,rtp_rtcp,$(DEPTH)/media/webrtc/trunk/webrtc/modules/modules_rtp_rtcp) \
   $(call EXPAND_LIBNAME_PATH,bitrate_controller,$(DEPTH)/media/webrtc/trunk/webrtc/modules/modules_bitrate_controller) \
   $(call EXPAND_LIBNAME_PATH,remote_bitrate_estimator,$(DEPTH)/media/webrtc/trunk/webrtc/modules/modules_remote_bitrate_estimator) \
+  $(call EXPAND_LIBNAME_PATH,rbe_components,$(DEPTH)/media/webrtc/trunk/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_components_rbe_components) \
   $(call EXPAND_LIBNAME_PATH,paced_sender,$(DEPTH)/media/webrtc/trunk/webrtc/modules/modules_paced_sender) \
   $(call EXPAND_LIBNAME_PATH,video_processing,$(DEPTH)/media/webrtc/trunk/webrtc/modules/modules_video_processing) \
   $(call EXPAND_LIBNAME_PATH,audio_conference_mixer,$(DEPTH)/media/webrtc/trunk/webrtc/modules/modules_audio_conference_mixer) \
   $(call EXPAND_LIBNAME_PATH,audio_device,$(DEPTH)/media/webrtc/trunk/webrtc/modules/modules_audio_device) \
   $(call EXPAND_LIBNAME_PATH,audio_processing,$(DEPTH)/media/webrtc/trunk/webrtc/modules/modules_audio_processing) \
   $(call EXPAND_LIBNAME_PATH,yuv,$(DEPTH)/media/webrtc/trunk/third_party/libyuv/libyuv_libyuv) \
   $(call EXPAND_LIBNAME_PATH,nicer,$(DEPTH)/media/mtransport/third_party/nICEr/nicer_nicer) \
   $(call EXPAND_LIBNAME_PATH,nrappkit,$(DEPTH)/media/mtransport/third_party/nrappkit/nrappkit_nrappkit) \
--- a/layout/svg/nsSVGPaintServerFrame.cpp
+++ b/layout/svg/nsSVGPaintServerFrame.cpp
@@ -20,11 +20,15 @@ nsSVGPaintServerFrame::SetupPaintServer(
                                         float aOpacity)
 {
   nsRefPtr<gfxPattern> pattern =
     GetPaintServerPattern(aSource, aContext->CurrentMatrix(), aFillOrStroke,
                           aOpacity);
   if (!pattern)
     return false;
 
+  if (!aContext->IsCairo()) {
+    pattern->CacheColorStops(aContext->GetDrawTarget());
+  }
+
   aContext->SetPattern(pattern);
   return true;
 }
--- a/media/webrtc/signaling/src/media-conduit/AudioConduit.cpp
+++ b/media/webrtc/signaling/src/media-conduit/AudioConduit.cpp
@@ -148,18 +148,19 @@ MediaConduitErrorCode WebrtcAudioConduit
     MOZ_ASSERT(other->mVoiceEngine);
     mVoiceEngine = other->mVoiceEngine;
   } else {
 #ifdef MOZ_WIDGET_ANDROID
       jobject context = jsjni_GetGlobalContextRef();
 
       // get the JVM
       JavaVM *jvm = jsjni_GetVM();
+      JNIEnv* jenv = jsjni_GetJNIForThread();
 
-      if (webrtc::VoiceEngine::SetAndroidObjects(jvm, (void*)context) != 0) {
+      if (webrtc::VoiceEngine::SetAndroidObjects(jvm, jenv, (void*)context) != 0) {
         CSFLogError(logTag, "%s Unable to set Android objects", __FUNCTION__);
         return kMediaConduitSessionNotInited;
       }
 #endif
 
     //Per WebRTC APIs below function calls return NULL on failure
     if(!(mVoiceEngine = webrtc::VoiceEngine::Create()))
     {
--- a/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp
+++ b/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp
@@ -967,17 +967,18 @@ WebrtcVideoConduit::FrameSizeChange(unsi
   CSFLogError(logTag,  "%s Renderer is NULL ", __FUNCTION__);
   return -1;
 }
 
 int
 WebrtcVideoConduit::DeliverFrame(unsigned char* buffer,
                                  int buffer_size,
                                  uint32_t time_stamp,
-                                 int64_t render_time)
+                                 int64_t render_time,
+                                 void *handle)
 {
   CSFLogDebug(logTag,  "%s Buffer Size %d", __FUNCTION__, buffer_size);
 
   if(mRenderer)
   {
     mRenderer->RenderVideoFrame(buffer, buffer_size, time_stamp, render_time);
     return 0;
   }
--- a/media/webrtc/signaling/src/media-conduit/VideoConduit.h
+++ b/media/webrtc/signaling/src/media-conduit/VideoConduit.h
@@ -11,17 +11,16 @@
 
 // Video Engine Includes
 #include "webrtc/common_types.h"
 #include "webrtc/video_engine/include/vie_base.h"
 #include "webrtc/video_engine/include/vie_capture.h"
 #include "webrtc/video_engine/include/vie_codec.h"
 #include "webrtc/video_engine/include/vie_render.h"
 #include "webrtc/video_engine/include/vie_network.h"
-#include "webrtc/video_engine/include/vie_file.h"
 #include "webrtc/video_engine/include/vie_rtp_rtcp.h"
 
 /** This file hosts several structures identifying different aspects
  * of a RTP Session.
  */
 
  using  webrtc::ViEBase;
  using  webrtc::ViENetwork;
@@ -143,17 +142,25 @@ public:
 
 
   /**
    * Webrtc External Renderer Implementation APIs.
    * Raw I420 Frames are delivred to the VideoConduit by the VideoEngine
    */
   virtual int FrameSizeChange(unsigned int, unsigned int, unsigned int);
 
-  virtual int DeliverFrame(unsigned char*,int, uint32_t , int64_t);
+  virtual int DeliverFrame(unsigned char*,int, uint32_t , int64_t,
+                           void *handle);
+
+  /**
+   * Does DeliverFrame() support a null buffer and non-null handle
+   * (video texture)?
+   * XXX Investigate!  Especially for Android/B2G
+   */
+  virtual bool IsTextureSupported() { return false; }
 
   unsigned short SendingWidth() {
     return mSendingWidth;
   }
 
   unsigned short SendingHeight() {
     return mSendingHeight;
   }
--- a/media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp
+++ b/media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp
@@ -583,17 +583,17 @@ static short vcmRxAllocICE_s(TemporaryRe
 
   // Set the opaque so we can correlate events.
   stream->SetOpaque(new VcmIceOpaque(stream_id, call_handle, level));
 
   // Attach ourself to the candidate signal.
   VcmSIPCCBinding::connectCandidateSignal(stream);
 
   std::vector<std::string> candidates = stream->GetCandidates();
-  CSFLogDebug( logTag, "%s: Got %lu candidates", __FUNCTION__, candidates.size());
+  CSFLogDebug( logTag, "%s: Got %lu candidates", __FUNCTION__, (unsigned long) candidates.size());
 
   std::string default_addr;
   int default_port;
 
   nsresult res = stream->GetDefaultCandidate(1, &default_addr, &default_port);
   MOZ_ASSERT(NS_SUCCEEDED(res));
   if (!NS_SUCCEEDED(res)) {
     return VCM_ERROR;
--- a/media/webrtc/signaling/src/sipcc/core/gsm/gsm_sdp.c
+++ b/media/webrtc/signaling/src/sipcc/core/gsm/gsm_sdp.c
@@ -2668,19 +2668,17 @@ gsmsdp_update_local_sdp_media (fsmdef_dc
 
     result = sdp_insert_media_line(sdp_p, level);
     if (result != SDP_SUCCESS) {
         GSM_ERR_MSG(GSM_L_C_F_PREFIX"Inserting media line to Sdp failed",
                     dcb_p->line, dcb_p->call_id, fname);
         return;
     }
 
-    if (media->support_direction != SDP_DIRECTION_INACTIVE) {
-        gsmsdp_set_connection_address(sdp_p, media->level, dcb_p->ice_default_candidate_addr);
-    }
+    gsmsdp_set_connection_address(sdp_p, media->level, dcb_p->ice_default_candidate_addr);
 
     (void) sdp_set_media_type(sdp_p, level, media->type);
 
 
     (void) sdp_set_media_portnum(sdp_p, level, port, media->local_datachannel_port);
 
     /* Set media transport and crypto attributes if it is for SRTP */
     gsmsdp_update_local_sdp_media_transport(dcb_p, sdp_p, media, transport,
--- a/media/webrtc/signaling/test/signaling_unittests.cpp
+++ b/media/webrtc/signaling/test/signaling_unittests.cpp
@@ -2028,16 +2028,38 @@ TEST_F(SignalingTest, FullCallAudioOnly)
   a2_->CloseReceiveStreams();
   // Check that we wrote a bunch of data
   ASSERT_GE(a1_->GetPacketsSent(0), 40);
   //ASSERT_GE(a2_->GetPacketsSent(0), 40);
   //ASSERT_GE(a1_->GetPacketsReceived(0), 40);
   ASSERT_GE(a2_->GetPacketsReceived(0), 40);
 }
 
+TEST_F(SignalingTest, FullCallAnswererRejectsVideo)
+{
+  sipcc::MediaConstraints offerconstraints;
+  sipcc::MediaConstraints answerconstraints;
+  answerconstraints.setBooleanConstraint("OfferToReceiveAudio", true, false);
+  answerconstraints.setBooleanConstraint("OfferToReceiveVideo", false, false);
+  OfferAnswer(offerconstraints, answerconstraints, OFFER_AV | ANSWER_AUDIO,
+              true, SHOULD_SENDRECV_AV, SHOULD_SENDRECV_AUDIO);
+
+  // Wait for some data to get written
+  ASSERT_TRUE_WAIT(a1_->GetPacketsSent(0) >= 40 &&
+                   a2_->GetPacketsReceived(0) >= 40, kDefaultTimeout * 2);
+
+  a1_->CloseSendStreams();
+  a2_->CloseReceiveStreams();
+  // Check that we wrote a bunch of data
+  ASSERT_GE(a1_->GetPacketsSent(0), 40);
+  //ASSERT_GE(a2_->GetPacketsSent(0), 40);
+  //ASSERT_GE(a1_->GetPacketsReceived(0), 40);
+  ASSERT_GE(a2_->GetPacketsReceived(0), 40);
+}
+
 TEST_F(SignalingTest, FullCallVideoOnly)
 {
   sipcc::MediaConstraints constraints;
   OfferAnswer(constraints, constraints, OFFER_VIDEO | ANSWER_VIDEO,
               true, SHOULD_SENDRECV_VIDEO, SHOULD_SENDRECV_VIDEO);
 
   // If we could check for video packets, we would wait for some to be written
   // here. Since we can't, we don't.
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/webrtc/PRESUBMIT.py
@@ -0,0 +1,45 @@
+# Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the LICENSE file in the root of the source
+# tree. An additional intellectual property rights grant can be found
+# in the file PATENTS.  All contributing project authors may
+# be found in the AUTHORS file in the root of the source tree.
+
+def _LicenseHeader(input_api):
+  """Returns the license header regexp."""
+  # Accept any year number from 2011 to the current year
+  current_year = int(input_api.time.strftime('%Y'))
+  allowed_years = (str(s) for s in reversed(xrange(2011, current_year + 1)))
+  years_re = '(' + '|'.join(allowed_years) + ')'
+  license_header = (
+      r'.*? Copyright \(c\) %(year)s The WebRTC project authors\. '
+        r'All Rights Reserved\.\n'
+      r'.*?\n'
+      r'.*? Use of this source code is governed by a BSD-style license\n'
+      r'.*? that can be found in the LICENSE file in the root of the source\n'
+      r'.*? tree\. An additional intellectual property rights grant can be '
+        r'found\n'
+      r'.*? in the file PATENTS\.  All contributing project authors may\n'
+      r'.*? be found in the AUTHORS file in the root of the source tree\.\n'
+  ) % {
+      'year': years_re,
+  }
+  return license_header
+
+def _CommonChecks(input_api, output_api):
+  """Checks common to both upload and commit."""
+  results = []
+  results.extend(input_api.canned_checks.CheckLicense(
+      input_api, output_api, _LicenseHeader(input_api)))
+  return results
+
+def CheckChangeOnUpload(input_api, output_api):
+  results = []
+  results.extend(_CommonChecks(input_api, output_api))
+  return results
+
+def CheckChangeOnCommit(input_api, output_api):
+  results = []
+  results.extend(_CommonChecks(input_api, output_api))
+  return results
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/webrtc/build/apk_tests.gyp
@@ -0,0 +1,192 @@
+# Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the LICENSE file in the root of the source
+# tree. An additional intellectual property rights grant can be found
+# in the file PATENTS.  All contributing project authors may
+# be found in the AUTHORS file in the root of the source tree.
+
+# This file exists in two versions. A no-op version under
+# webrtc/build/apk_tests_noop.gyp and this one. This gyp file builds the apk
+# unit tests (for Android) assuming that WebRTC is built inside a Chromium
+# workspace. The no-op version is included when building WebRTC without
+# Chromium. This is a workaround for the fact that 'includes' don't expand
+# variables and that the relative location of apk_test.gypi is different for
+# WebRTC when built as part of Chromium and when it is built without Chromium.
+{
+  'includes': [
+    'common.gypi',
+  ],
+  'targets': [
+    {
+      'target_name': 'audio_decoder_unittests_apk',
+      'type': 'none',
+      'variables': {
+        'test_suite_name': 'audio_decoder_unittests',
+        'input_shlib_path': '<(SHARED_LIB_DIR)/<(SHARED_LIB_PREFIX)audio_decoder_unittests<(SHARED_LIB_SUFFIX)',
+      },
+      'dependencies': [
+        '<(webrtc_root)/modules/modules.gyp:audio_decoder_unittests',
+      ],
+      'includes': [
+        '../../../build/apk_test.gypi',
+      ],
+    },
+    {
+      'target_name': 'common_audio_unittests_apk',
+      'type': 'none',
+      'variables': {
+        'test_suite_name': 'common_audio_unittests',
+        'input_shlib_path': '<(SHARED_LIB_DIR)/<(SHARED_LIB_PREFIX)common_audio_unittests<(SHARED_LIB_SUFFIX)',
+      },
+      'dependencies': [
+        '<(webrtc_root)/common_audio/common_audio.gyp:common_audio_unittests',
+      ],
+      'includes': [
+        '../../../build/apk_test.gypi',
+      ],
+    },
+    {
+      'target_name': 'common_video_unittests_apk',
+      'type': 'none',
+      'variables': {
+        'test_suite_name': 'common_video_unittests',
+        'input_shlib_path': '<(SHARED_LIB_DIR)/<(SHARED_LIB_PREFIX)common_video_unittests<(SHARED_LIB_SUFFIX)',
+      },
+      'dependencies': [
+        '<(webrtc_root)/common_video/common_video.gyp:common_video_unittests',
+      ],
+      'includes': [
+        '../../../build/apk_test.gypi',
+      ],
+    },
+    {
+      'target_name': 'metrics_unittests_apk',
+      'type': 'none',
+      'variables': {
+        'test_suite_name': 'metrics_unittests',
+        'input_shlib_path': '<(SHARED_LIB_DIR)/<(SHARED_LIB_PREFIX)metrics_unittests<(SHARED_LIB_SUFFIX)',
+      },
+      'dependencies': [
+        '<(webrtc_root)/test/metrics.gyp:metrics_unittests',
+      ],
+      'includes': [
+        '../../../build/apk_test.gypi',
+      ],
+    },
+    {
+      'target_name': 'modules_tests_apk',
+      'type': 'none',
+      'variables': {
+        'test_suite_name': 'modules_tests',
+        'input_shlib_path': '<(SHARED_LIB_DIR)/<(SHARED_LIB_PREFIX)modules_tests<(SHARED_LIB_SUFFIX)',
+      },
+      'dependencies': [
+        '<(webrtc_root)/modules/modules.gyp:modules_tests',
+      ],
+      'includes': [
+        '../../../build/apk_test.gypi',
+      ],
+    },
+    {
+      'target_name': 'modules_unittests_apk',
+      'type': 'none',
+      'variables': {
+        'test_suite_name': 'modules_unittests',
+        'input_shlib_path': '<(SHARED_LIB_DIR)/<(SHARED_LIB_PREFIX)modules_unittests<(SHARED_LIB_SUFFIX)',
+      },
+      'dependencies': [
+        '<(webrtc_root)/modules/modules.gyp:modules_unittests',
+      ],
+      'includes': [
+        '../../../build/apk_test.gypi',
+      ],
+    },
+    {
+      'target_name': 'neteq_unittests_apk',
+      'type': 'none',
+      'variables': {
+        'test_suite_name': 'neteq_unittests',
+        'input_shlib_path': '<(SHARED_LIB_DIR)/<(SHARED_LIB_PREFIX)neteq_unittests<(SHARED_LIB_SUFFIX)',
+      },
+      'dependencies': [
+        '<(webrtc_root)/modules/modules.gyp:neteq_unittests',
+      ],
+      'includes': [
+        '../../../build/apk_test.gypi',
+      ],
+    },
+    {
+      'target_name': 'system_wrappers_unittests_apk',
+      'type': 'none',
+      'variables': {
+        'test_suite_name': 'system_wrappers_unittests',
+        'input_shlib_path': '<(SHARED_LIB_DIR)/<(SHARED_LIB_PREFIX)system_wrappers_unittests<(SHARED_LIB_SUFFIX)',
+      },
+      'dependencies': [
+        '<(webrtc_root)/system_wrappers/source/system_wrappers_tests.gyp:system_wrappers_unittests',
+      ],
+      'includes': [
+        '../../../build/apk_test.gypi',
+      ],
+    },
+    {
+      'target_name': 'test_support_unittests_apk',
+      'type': 'none',
+      'variables': {
+        'test_suite_name': 'test_support_unittests',
+        'input_shlib_path': '<(SHARED_LIB_DIR)/<(SHARED_LIB_PREFIX)test_support_unittests<(SHARED_LIB_SUFFIX)',
+      },
+      'dependencies': [
+        '<(webrtc_root)/test/test.gyp:test_support_unittests',
+      ],
+      'includes': [
+        '../../../build/apk_test.gypi',
+      ],
+    },
+    {
+      'target_name': 'tools_unittests_apk',
+      'type': 'none',
+      'variables': {
+        'test_suite_name': 'tools_unittests',
+        'input_shlib_path': '<(SHARED_LIB_DIR)/<(SHARED_LIB_PREFIX)tools_unittests<(SHARED_LIB_SUFFIX)',
+      },
+      'dependencies': [
+        '<(webrtc_root)/tools/tools.gyp:tools_unittests',
+      ],
+      'includes': [
+        '../../../build/apk_test.gypi',
+      ],
+    },
+    {
+      'target_name': 'video_engine_core_unittests_apk',
+      'type': 'none',
+      'variables': {
+        'test_suite_name': 'video_engine_core_unittests',
+        'input_shlib_path': '<(SHARED_LIB_DIR)/<(SHARED_LIB_PREFIX)video_engine_core_unittests<(SHARED_LIB_SUFFIX)',
+      },
+      'dependencies': [
+        '<(webrtc_root)/video_engine/video_engine.gyp:video_engine_core_unittests',
+      ],
+      'includes': [
+        '../../../build/apk_test.gypi',
+      ],
+    },
+    {
+      'target_name': 'voice_engine_unittests_apk',
+      'type': 'none',
+      'variables': {
+        'test_suite_name': 'voice_engine_unittests',
+        'input_shlib_path': '<(SHARED_LIB_DIR)/<(SHARED_LIB_PREFIX)voice_engine_unittests<(SHARED_LIB_SUFFIX)',
+      },
+      'dependencies': [
+        '<(webrtc_root)/voice_engine/voice_engine.gyp:voice_engine_unittests',
+      ],
+      'includes': [
+        '../../../build/apk_test.gypi',
+      ],
+    },    
+  ],
+}
+
+
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/webrtc/build/apk_tests_noop.gyp
@@ -0,0 +1,61 @@
+# Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the LICENSE file in the root of the source
+# tree. An additional intellectual property rights grant can be found
+# in the file PATENTS.  All contributing project authors may
+# be found in the AUTHORS file in the root of the source tree.
+
+# See webrtc/build/apk_tests.gyp for more information about this file.
+{
+  'targets': [
+    {
+      'target_name': 'audio_decoder_unittests_apk',
+      'type': 'none',
+    },
+    {
+      'target_name': 'common_audio_unittests_apk',
+      'type': 'none',
+    },
+    {
+      'target_name': 'common_video_unittests_apk',
+      'type': 'none',
+    },
+    {
+      'target_name': 'metrics_unittests',
+      'type': 'none',
+    },
+    {
+      'target_name': 'modules_tests_apk',
+      'type': 'none',
+    },
+    {
+      'target_name': 'modules_unittests_apk',
+      'type': 'none',
+    },
+    {
+      'target_name': 'neteq_unittests_apk',
+      'type': 'none',
+    },
+    {
+      'target_name': 'system_wrappers_unittests_apk',
+      'type': 'none',
+    },
+    {
+      'target_name': 'test_support_unittests_apk',
+      'type': 'none',
+    },
+    {
+      'target_name': 'tools_unittests_apk',
+      'type': 'none',
+    },
+    {
+      'target_name': 'video_engine_core_unittests_apk',
+      'type': 'none',
+    },
+    {
+      'target_name': 'voice_engine_unittests_apk',
+      'type': 'none',
+    },
+  ],
+}
--- a/media/webrtc/trunk/webrtc/build/common.gypi
+++ b/media/webrtc/trunk/webrtc/build/common.gypi
@@ -12,53 +12,68 @@
   # Nesting is required in order to use variables for setting other variables.
   'variables': {
     'variables': {
       'variables': {
         'variables': {
           # This will be set to zero in the supplement.gypi triggered by a
           # gclient hook in the standalone build.
           'build_with_chromium%': 1,
-          'build_with_libjingle%': 0,
         },
         'build_with_chromium%': '<(build_with_chromium)',
-        'build_with_libjingle%': '<(build_with_libjingle)',
 
         'conditions': [
-          ['build_with_chromium==1 or build_with_libjingle==1', {
+          ['build_with_chromium==1', {
+            'build_with_libjingle': 1,
             'webrtc_root%': '<(DEPTH)/third_party/webrtc',
+            'apk_tests_path%': '<(DEPTH)/third_party/webrtc/build/apk_tests.gyp',
+            'import_isolate_path%': '<(DEPTH)/third_party/webrtc/build/import_isolate_chromium.gyp',
+            'modules_java_gyp_path%': '<(DEPTH)/third_party/webrtc/modules/modules_java_chromium.gyp',
           }, {
+            'build_with_libjingle%': 0,
             'webrtc_root%': '<(DEPTH)/webrtc',
+            'apk_tests_path%': '<(DEPTH)/webrtc/build/apk_test_noop.gyp',
+            'import_isolate_path%': '<(DEPTH)/webrtc/build/import_isolate_webrtc.gyp',
+            'modules_java_gyp_path%': '<(DEPTH)/webrtc/modules/modules_java.gyp',
           }],
         ],
       },
       'build_with_chromium%': '<(build_with_chromium)',
       'build_with_libjingle%': '<(build_with_libjingle)',
       'webrtc_root%': '<(webrtc_root)',
+      'apk_tests_path%': '<(apk_tests_path)',
+      'import_isolate_path%': '<(import_isolate_path)',
+      'modules_java_gyp_path%': '<(modules_java_gyp_path)',
 
       'webrtc_vp8_dir%': '<(webrtc_root)/modules/video_coding/codecs/vp8',
+      'rbe_components_path%': '<(webrtc_root)/modules/remote_bitrate_estimator',
       'include_g711%': 1,
       'include_g722%': 1,
       'include_ilbc%': 1,
       'include_opus%': 1,
       'include_isac%': 1,
       'include_pcm16b%': 1,
     },
     'build_with_chromium%': '<(build_with_chromium)',
     'build_with_libjingle%': '<(build_with_libjingle)',
     'webrtc_root%': '<(webrtc_root)',
+    'apk_tests_path%': '<(apk_tests_path)',
+    'import_isolate_path%': '<(import_isolate_path)',
+    'modules_java_gyp_path%': '<(modules_java_gyp_path)',
     'webrtc_vp8_dir%': '<(webrtc_vp8_dir)',
 
     'include_g711%': '<(include_g711)',
     'include_g722%': '<(include_g722)',
     'include_ilbc%': '<(include_ilbc)',
     'include_opus%': '<(include_opus)',
     'include_isac%': '<(include_isac)',
     'include_pcm16b%': '<(include_pcm16b)',
 
+    'rbe_components_path%': '<(rbe_components_path)',
+
     # The Chromium common.gypi we use treats all gyp files without
     # chromium_code==1 as third party code. This disables many of the
     # preferred warning settings.
     #
     # We can set this here to have WebRTC code treated as Chromium code. Our
     # third party code will still have the reduced warning settings.
     'chromium_code': 1,
 
@@ -103,36 +118,40 @@
         'include_internal_audio_device%': 0,
 
         # Exclude internal VCM in Chromium build.
         'include_internal_video_capture%': 0,
 
         # Exclude internal video render module in Chromium build.
         'include_internal_video_render%': 0,
 
-        'include_tests%': 0,
+        # Include ndk cpu features in Chromium build.
+        'include_ndk_cpu_features%': 1,
 
-        'enable_tracing%': 0,
-	 # lazily allocate the ~4MB of trace message buffers if set
+        # lazily allocate the ~4MB of trace message buffers if set
         'enable_lazy_trace_alloc%': 0,
-
-        'enable_android_opensl%': 0,
       }, {  # Settings for the standalone (not-in-Chromium) build.
-        'include_pulse_audio%': 1,
-        'include_internal_audio_device%': 1,
-        'include_internal_video_capture%': 1,
-        'include_internal_video_render%': 1,
-        'enable_tracing%': 1,
-        'include_tests%': 1,
-
         # TODO(andrew): For now, disable the Chrome plugins, which causes a
         # flood of chromium-style warnings. Investigate enabling them:
         # http://code.google.com/p/webrtc/issues/detail?id=163
         'clang_use_chrome_plugins%': 0,
 
+        'include_pulse_audio%': 1,
+        'include_internal_audio_device%': 1,
+        'include_internal_video_capture%': 1,
+        'include_internal_video_render%': 1,
+        'include_ndk_cpu_features%': 0,
+      }],
+      ['build_with_libjingle==1', {
+        'include_tests%': 0,
+        'enable_tracing%': 0,
+        'enable_android_opensl%': 0,
+      }, {
+        'include_tests%': 1,
+        'enable_tracing%': 1,
         # Switch between Android audio device OpenSL ES implementation
         # and Java Implementation
         'enable_android_opensl%': 0,
       }],
       ['OS=="linux"', {
         'include_alsa_audio%': 1,
       }, {
         'include_alsa_audio%': 0,
@@ -143,27 +162,21 @@
         'include_pulse_audio%': 0,
       }],
       ['OS=="linux" or OS=="solaris" or os_bsd==1', {
         'include_v4l2_video_capture%': 1,
       }, {
         'include_v4l2_video_capture%': 0,
       }],
       ['OS=="ios"', {
-        'enable_video%': 0,
+        'build_libjpeg%': 0,
         'enable_protobuf%': 0,
-        'build_libjpeg%': 0,
-        'build_libyuv%': 0,
-        'build_libvpx%': 0,
         'include_tests%': 0,
       }],
-      ['build_with_libjingle==1', {
-        'include_tests%': 0,
-      }],
-      ['target_arch=="arm"', {
+      ['target_arch=="arm" or target_arch=="armv7"', {
         'prefer_fixed_point%': 1,
       }],
     ], # conditions
   },
   'target_defaults': {
     'include_dirs': [
       # TODO(andrew): Remove '..' when we've added webrtc/ to include paths.
       '..',
@@ -212,17 +225,17 @@
             ],
             'cflags_cc': [
               # This is enabled for clang; enable for gcc as well.
               '-Woverloaded-virtual',
             ],
           }],
         ],
       }],
-      ['target_arch=="arm"', {
+      ['target_arch=="arm" or target_arch=="armv7"', {
         'defines': [
           'WEBRTC_ARCH_ARM',
         ],
         'conditions': [
           ['armv7==1', {
             'defines': ['WEBRTC_ARCH_ARM_V7',
                         'WEBRTC_BUILD_NEON_LIBS'],
             'conditions': [
@@ -333,27 +346,28 @@
         # http://code.google.com/p/webrtc/issues/detail?id=261 is solved.
         'msvs_disabled_warnings': [
           4373,  # legacy warning for ignoring const / volatile in signatures.
           4389,  # Signed/unsigned mismatch.
         ],
         # Re-enable some warnings that Chromium disables.
         'msvs_disabled_warnings!': [4189,],
       }],
+      # used on GONK as well
+      ['enable_android_opensl==1 and (OS=="android" or moz_widget_toolkit_gonk==1)', {
+        'defines': [
+          'WEBRTC_ANDROID_OPENSLES',
+        ],
+      }],
       ['OS=="android"', {
         'defines': [
           'WEBRTC_LINUX',
           'WEBRTC_ANDROID',
          ],
          'conditions': [
-           ['enable_android_opensl==1', {
-             'defines': [
-               'WEBRTC_ANDROID_OPENSLES',
-             ],
-           }],
            ['clang!=1', {
              # The Android NDK doesn't provide optimized versions of these
              # functions. Ensure they are disabled for all compilers.
              'cflags': [
                '-fno-builtin-cos',
                '-fno-builtin-sin',
                '-fno-builtin-cosf',
                '-fno-builtin-sinf',
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/webrtc/build/import_isolate_chromium.gyp
@@ -0,0 +1,22 @@
+# Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the LICENSE file in the root of the source
+# tree. An additional intellectual property rights grant can be found
+# in the file PATENTS.  All contributing project authors may
+# be found in the AUTHORS file in the root of the source tree.
+
+# See webrtc/build/import_isolate_webrtc.gyp for information about this file.
+{
+  'targets': [
+    {
+      'target_name': 'import_isolate_gypi',
+      'type': 'none',
+      'includes': [
+        # Relative path to isolate.gypi when WebRTC is built from inside
+        # Chromium (i.e. the webrtc/ folder is checked out into third_party/).
+        '../../../build/apk_test.gypi',
+      ],
+    },
+  ],
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/webrtc/build/import_isolate_webrtc.gyp
@@ -0,0 +1,25 @@
+# Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the LICENSE file in the root of the source
+# tree. An additional intellectual property rights grant can be found
+# in the file PATENTS.  All contributing project authors may
+# be found in the AUTHORS file in the root of the source tree.
+
+# This file exists so we can find the isolate.gypi both when WebRTC is built
+# stand-alone and when built as a part of Chrome.
+# This is needed since GYP does not support evaluating variables in the
+# includes sections of a target, so we cannot use <(DEPTH) or <(webrtc_root).
+{
+  'targets': [
+    {
+      'target_name': 'import_isolate_gypi',
+      'type': 'none',
+      'includes': [
+        # Relative path to isolate.gypi when WebRTC built as a stand-alone
+        # project (i.e. Chromium's build/ folder is checked out into the root).
+        '../../build/isolate.gypi',
+      ],
+    },
+  ],
+}
--- a/media/webrtc/trunk/webrtc/build/ios-webrtc.sh
+++ b/media/webrtc/trunk/webrtc/build/ios-webrtc.sh
@@ -1,73 +1,25 @@
-#!/bin/bash
+#!/bin/bash -e
 
 # Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
 #
 # Use of this source code is governed by a BSD-style license
 # that can be found in the LICENSE file in the root of the source
 # tree. An additional intellectual property rights grant can be found
 # in the file PATENTS.  All contributing project authors may
 # be found in the AUTHORS file in the root of the source tree.
 
-function build_project() {
-  # make the target string
-  if [[ -z "$2" ]]; then
-    target_string=""
-  else
-    declare -a arg_target=("${!2}")
-
-  for item in ${arg_target[*]}
-    do
-      temp_string="-target $item "
-      target_string=$target_string$temp_string
-    done
-  fi
-
-  # xcodebuild
-  xcodebuild -project "$1" -sdk iphoneos \
-  -configuration ${CONFIGURATION} \
-  -CONFIGURATION_BUILD_DIR=${CONFIGURATION_BUILD_DIR} $target_string
+# Work in trunk/.
+cd "$(dirname $0)/../.."
 
-  if [ "$?" != "0" ]; then
-    echo "[Error] build $1 failed!" 1>&2
-    echo "@@@STEP_FAILURE@@@"
-    exit 1
-  fi
-}
-
-# change the working directory to trunk
-cd "$( dirname "${BASH_SOURCE[0]}" )/../.."
+export GYP_DEFINES="build_with_libjingle=1 build_with_chromium=0"
+GYP_DEFINES="$GYP_DEFINES OS=ios target_arch=armv7 key_id=\"\""
+export GYP_GENERATORS="ninja"
+export GYP_CROSSCOMPILE=1
 
-# build setting
-CONFIGURATION_BUILD_DIR=./xcodebuild
-CONFIGURATION=Debug
-GYPDEF="OS=ios target_arch=arm armv7=1 arm_neon=1 enable_video=0 include_opus=1"
-
-export GYP_DEFINES=$GYPDEF
-echo "[Running gclient runhooks...]"
 echo "@@@BUILD_STEP runhooks@@@"
-gclient runhooks
-if [ "$?" != "0" ]; then
-  echo "[Error] gclient runhooks failed!" 1>&2
-  echo "@@@STEP_FAILURE@@@"
-  exit 2
-fi
-echo "[Projects updated]\n"
+gclient runhooks || { echo "@@@STEP_FAILURE@@@"; exit 2; }
 
 echo "@@@BUILD_STEP compile@@@"
-echo "[Building XCode projects...]"
-array_target_module=(
-  "bitrate_controller" "media_file" "paced_sender" "remote_bitrate_estimator"
-  "webrtc_utility" "rtp_rtcp" "CNG" "G711" "G722" "iLBC" "iSACFix" "PCM16B"
-  "audio_coding_module" "NetEq" "audio_conference_mixer" "audio_device"
-  "audio_processing" "iSAC" "isac_neon" "audio_processing_neon" "webrtc_opus"
-)
-array_target_opus=("opus")
-
-build_project "webrtc/common_audio/common_audio.xcodeproj"
-build_project "webrtc/modules/modules.xcodeproj" array_target_module[@]
-build_project "webrtc/system_wrappers/source/system_wrappers.xcodeproj"
-build_project "webrtc/voice_engine/voice_engine.xcodeproj"
-build_project "third_party/opus/opus.xcodeproj" array_target_opus[@]
-echo "[Building XCode projects is successful]\n"
+ninja -C out/Debug || { echo "@@@STEP_FAILURE@@@"; exit 2; }
 
 exit 0
new file mode 100755
--- /dev/null
+++ b/media/webrtc/trunk/webrtc/build/vie-webrtc.sh
@@ -0,0 +1,69 @@
+#!/bin/sh
+
+# Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the LICENSE file in the root of the source
+# tree. An additional intellectual property rights grant can be found
+# in the file PATENTS.  All contributing project authors may
+# be found in the AUTHORS file in the root of the source tree.
+set -e
+
+# TODO(sjlee): remove this whole script file.
+# (https://code.google.com/p/webrtc/issues/detail?id=2028)
+function build_project() {
+  # make the target string
+  local target_string=""
+  if [[ -n "$2" ]]; then
+    target_string="-target $2"
+  fi
+
+  xcodebuild -project "$1" -sdk iphoneos -arch armv7 \
+    -configuration ${CONFIGURATION} \
+    -CONFIGURATION_BUILD_DIR=${CONFIGURATION_BUILD_DIR} $target_string
+}
+
+# change the working directory to trunk
+cd "$( dirname "$0" )/../.."
+
+# build setting
+CONFIGURATION_BUILD_DIR=./xcodebuild
+CONFIGURATION=Debug
+export GYP_DEFINES="OS=ios target_arch=arm armv7=1 arm_neon=1"
+# TODO(sjlee): remove this script.
+# (https://webrtc-codereview.appspot.com/1874005)
+
+# update gyp settings
+echo '[Updating gyp settings...]'
+gclient runhooks
+./build/gyp_chromium --depth=. \
+webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_components.gyp
+./build/gyp_chromium --depth=. \
+webrtc/modules/video_coding/utility/video_coding_utility.gyp
+./build/gyp_chromium --depth=. third_party/opus/opus.gyp
+./build/gyp_chromium --depth=. third_party/libyuv/libyuv.gyp
+./build/gyp_chromium --depth=. third_party/libjpeg/libjpeg.gyp
+
+# build the xcode projects
+echo '[Building xcode projects...]'
+
+build_project "webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_components.xcodeproj"
+build_project "webrtc/modules/video_coding/utility/video_coding_utility.xcodeproj"
+build_project "third_party/opus/opus.xcodeproj" "opus"
+build_project "third_party/libjpeg/libjpeg.xcodeproj"
+build_project "third_party/libyuv/libyuv.xcodeproj"
+
+# build the libvpx
+cd third_party/libvpx/source/libvpx
+
+./configure --target=armv7-darwin-gcc --disable-vp9 \
+  --libc=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.1.sdk
+
+make
+
+cd -
+
+cp third_party/libvpx/source/libvpx/libvpx.a \
+  ${CONFIGURATION_BUILD_DIR}/${CONFIGURATION}-iphoneos
+
+echo "[Building xcode projects is success...]\n"
--- a/media/webrtc/trunk/webrtc/common.h
+++ b/media/webrtc/trunk/webrtc/common.h
@@ -3,18 +3,18 @@
  *
  *  Use of this source code is governed by a BSD-style license
  *  that can be found in the LICENSE file in the root of the source
  *  tree. An additional intellectual property rights grant can be found
  *  in the file PATENTS.  All contributing project authors may
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#ifndef WEBRTC_COMMON_H
-#define WEBRTC_COMMON_H
+#ifndef WEBRTC_COMMON_H_
+#define WEBRTC_COMMON_H_
 
 #include <map>
 
 namespace webrtc {
 
 // Class Config is designed to ease passing a set of options across webrtc code.
 // Options are identified by typename in order to avoid incorrect casts.
 //
@@ -33,24 +33,24 @@ namespace webrtc {
 //      virtual float cost(int x) const { return x*x; }
 //    };
 //    config.Set<Algo1_CostFunction>(new SqrCost());
 //
 // Note: This class is thread-compatible (like STL containers).
 class Config {
  public:
   // Returns the option if set or a default constructed one.
-  // Callers that access options to often are encouraged to cache the result.
+  // Callers that access options too often are encouraged to cache the result.
   // Returned references are owned by this.
   //
   // Requires std::is_default_constructible<T>
   template<typename T> const T& Get() const;
 
   // Set the option, deleting any previous instance of the same.
-  // This instance gets ownership of the newly setted value.
+  // This instance gets ownership of the newly set value.
   template<typename T> void Set(T* value);
 
   Config() {}
   ~Config() {
     // Note: this method is inline so webrtc public API depends only
     // on the headers.
     for (OptionMap::iterator it = options_.begin();
          it != options_.end(); ++it) {
@@ -111,10 +111,12 @@ const T& Config::Get() const {
 }
 
 template<typename T>
 void Config::Set(T* value) {
   BaseOption*& it = options_[identifier<T>()];
   delete it;
   it = new Option<T>(value);
 }
+
 }  // namespace webrtc
-#endif  // WEBRTC_COMMON_H
+
+#endif  // WEBRTC_COMMON_H_
--- a/media/webrtc/trunk/webrtc/common_audio/audio_util_unittest.cc
+++ b/media/webrtc/trunk/webrtc/common_audio/audio_util_unittest.cc
@@ -15,16 +15,30 @@
 namespace webrtc {
 
 void ExpectArraysEq(const int16_t* ref, const int16_t* test, int length) {
   for (int i = 0; i < length; ++i) {
     EXPECT_EQ(test[i], ref[i]);
   }
 }
 
+TEST(AudioUtilTest, Clamp) {
+  EXPECT_EQ(1000.f, ClampInt16(1000.f));
+  EXPECT_EQ(32767.f, ClampInt16(32767.5f));
+  EXPECT_EQ(-32768.f, ClampInt16(-32768.5f));
+}
+
+TEST(AudioUtilTest, Round) {
+  EXPECT_EQ(0, RoundToInt16(0.f));
+  EXPECT_EQ(0, RoundToInt16(0.4f));
+  EXPECT_EQ(1, RoundToInt16(0.5f));
+  EXPECT_EQ(0, RoundToInt16(-0.4f));
+  EXPECT_EQ(-1, RoundToInt16(-0.5f));
+}
+
 TEST(AudioUtilTest, InterleavingStereo) {
   const int16_t kInterleaved[] = {2, 3, 4, 9, 8, 27, 16, 81};
   const int kSamplesPerChannel = 4;
   const int kNumChannels = 2;
   const int kLength = kSamplesPerChannel * kNumChannels;
   int16_t left[kSamplesPerChannel], right[kSamplesPerChannel];
   int16_t* deinterleaved[] = {left, right};
   Deinterleave(kInterleaved, kSamplesPerChannel, kNumChannels, deinterleaved);
--- a/media/webrtc/trunk/webrtc/common_audio/common_audio.gyp
+++ b/media/webrtc/trunk/webrtc/common_audio/common_audio.gyp
@@ -88,17 +88,17 @@
         'vad/vad_gmm.h',
         'vad/vad_sp.c',
         'vad/vad_sp.h',
       ],
       'conditions': [
         ['target_arch=="ia32" or target_arch=="x64"', {
           'dependencies': ['common_audio_sse2',],
         }],
-        ['target_arch=="arm"', {
+        ['target_arch=="arm" or target_arch=="armv7"', {
           'sources': [
             'signal_processing/complex_bit_reverse_arm.S',
             'signal_processing/spl_sqrt_floor_arm.S',
           ],
           'sources!': [
             'signal_processing/complex_bit_reverse.c',
             'signal_processing/spl_sqrt_floor.c',
           ],
@@ -111,27 +111,38 @@
               'sources!': [
                 'signal_processing/filter_ar_fast_q12.c',
               ],
             }],
           ],  # conditions
         }],
         ['target_arch=="mipsel"', {
           'sources': [
+            'signal_processing/include/spl_inl_mips.h',
             'signal_processing/complex_bit_reverse_mips.c',
             'signal_processing/complex_fft_mips.c',
+            'signal_processing/cross_correlation_mips.c',
             'signal_processing/downsample_fast_mips.c',
             'signal_processing/filter_ar_fast_q12_mips.c',
             'signal_processing/min_max_operations_mips.c',
             'signal_processing/resample_by_2_mips.c',
+            'signal_processing/spl_sqrt_floor_mips.c',
           ],
           'sources!': [
             'signal_processing/complex_bit_reverse.c',
             'signal_processing/complex_fft.c',
             'signal_processing/filter_ar_fast_q12.c',
+            'signal_processing/spl_sqrt_floor.c',
+          ],
+          'conditions': [
+            ['mips_dsp_rev>0', {
+              'sources': [
+                'signal_processing/vector_scaling_operations_mips.c',
+              ],
+            }],
           ],
         }],
       ],  # conditions
       # Ignore warning on shift operator promotion.
       'msvs_disabled_warnings': [ 4334, ],
     },
   ],  # targets
   'conditions': [
@@ -146,17 +157,17 @@
           'cflags': ['-msse2',],
           'cflags_mozilla': ['-msse2',],
           'xcode_settings': {
             'OTHER_CFLAGS': ['-msse2',],
           },
         },
       ],  # targets
     }],
-    ['target_arch=="arm" and armv7==1', {
+    ['(target_arch=="arm" and armv7==1) or target_arch=="armv7"', {
       'targets': [
         {
           'target_name': 'common_audio_neon',
           'type': 'static_library',
           'includes': ['../build/arm_neon.gypi',],
           'sources': [
             'resampler/sinc_resampler_neon.cc',
             'signal_processing/cross_correlation_neon.S',
@@ -166,17 +177,17 @@
           ],
         },
       ],  # targets
     }],
     ['include_tests==1', {
       'targets' : [
         {
           'target_name': 'common_audio_unittests',
-          'type': 'executable',
+          'type': '<(gtest_target_type)',
           'dependencies': [
             'common_audio',
             '<(webrtc_root)/test/test.gyp:test_support_main',
             '<(DEPTH)/testing/gmock.gyp:gmock',
             '<(DEPTH)/testing/gtest.gyp:gtest',
           ],
           'sources': [
             'audio_util_unittest.cc',
@@ -190,13 +201,55 @@
             'signal_processing/signal_processing_unittest.cc',
             'vad/vad_core_unittest.cc',
             'vad/vad_filterbank_unittest.cc',
             'vad/vad_gmm_unittest.cc',
             'vad/vad_sp_unittest.cc',
             'vad/vad_unittest.cc',
             'vad/vad_unittest.h',
           ],
+          'conditions': [
+            # TODO(henrike): remove build_with_chromium==1 when the bots are
+            # using Chromium's buildbots.
+            ['build_with_chromium==1 and OS=="android" and gtest_target_type=="shared_library"', {
+              'dependencies': [
+                '<(DEPTH)/testing/android/native_test.gyp:native_test_native_code',
+              ],
+            }],
+          ],
         },
       ],  # targets
+      'conditions': [
+        # TODO(henrike): remove build_with_chromium==1 when the bots are using
+        # Chromium's buildbots.
+        ['build_with_chromium==1 and OS=="android" and gtest_target_type=="shared_library"', {
+          'targets': [
+            {
+              'target_name': 'common_audio_unittests_apk_target',
+              'type': 'none',
+              'dependencies': [
+                '<(apk_tests_path):common_audio_unittests_apk',
+              ],
+            },
+          ],
+        }],
+        ['test_isolation_mode != "noop"', {
+          'targets': [
+            {
+              'target_name': 'common_audio_unittests_run',
+              'type': 'none',
+              'dependencies': [
+                '<(import_isolate_path):import_isolate_gypi',
+                'common_audio_unittests',
+              ],
+              'includes': [
+                'common_audio_unittests.isolate',
+              ],
+              'sources': [
+                'common_audio_unittests.isolate',
+              ],
+            },
+          ],
+        }],
+      ],
     }],
   ],  # conditions
 }
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/webrtc/common_audio/common_audio_unittests.isolate
@@ -0,0 +1,37 @@
+# Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the LICENSE file in the root of the source
+# tree. An additional intellectual property rights grant can be found
+# in the file PATENTS.  All contributing project authors may
+# be found in the AUTHORS file in the root of the source tree.
+{
+  'conditions': [
+    ['OS=="android"', {
+      # When doing Android builds, the WebRTC code is put in third_party/webrtc
+      # of a Chromium checkout, this is one level above the standalone build.
+      'variables': {
+        'isolate_dependency_untracked': [
+          '../../../data/',
+          '../../../resources/',
+        ],
+      },
+    }],
+    ['OS=="linux" or OS=="mac" or OS=="win"', {
+      'variables': {
+        'command': [
+          '../../testing/test_env.py',
+          '../../tools/swarm_client/googletest/run_test_cases.py',
+          '<(PRODUCT_DIR)/common_audio_unittests<(EXECUTABLE_SUFFIX)',
+        ],
+        'isolate_dependency_tracked': [
+          '../../testing/test_env.py',
+          '../../tools/swarm_client/run_isolated.py',
+          '../../tools/swarm_client/googletest/run_test_cases.py',
+          '../../tools/swarm_client/third_party/upload.py',
+          '<(PRODUCT_DIR)/common_audio_unittests<(EXECUTABLE_SUFFIX)',
+        ],
+      },
+    }],
+  ],
+}
--- a/media/webrtc/trunk/webrtc/common_audio/include/audio_util.h
+++ b/media/webrtc/trunk/webrtc/common_audio/include/audio_util.h
@@ -10,16 +10,30 @@
 
 #ifndef WEBRTC_COMMON_AUDIO_INCLUDE_AUDIO_UTIL_H_
 #define WEBRTC_COMMON_AUDIO_INCLUDE_AUDIO_UTIL_H_
 
 #include "webrtc/typedefs.h"
 
 namespace webrtc {
 
+// Clamp the floating |value| to the range representable by an int16_t.
+static inline float ClampInt16(float value) {
+  const float kMaxInt16 = 32767.f;
+  const float kMinInt16 = -32768.f;
+  return value < kMinInt16 ? kMinInt16 :
+      (value > kMaxInt16 ? kMaxInt16 : value);
+}
+
+// Return a rounded int16_t of the floating |value|. Doesn't handle overflow;
+// use ClampInt16 if necessary.
+static inline int16_t RoundToInt16(float value) {
+  return static_cast<int16_t>(value < 0.f ? value - 0.5f : value + 0.5f);
+}
+
 // Deinterleave audio from |interleaved| to the channel buffers pointed to
 // by |deinterleaved|. There must be sufficient space allocated in the
 // |deinterleaved| buffers (|num_channel| buffers with |samples_per_channel|
 // per buffer).
 void Deinterleave(const int16_t* interleaved, int samples_per_channel,
                   int num_channels, int16_t** deinterleaved);
 
 // Interleave audio from the channel buffers pointed to by |deinterleaved| to
--- a/media/webrtc/trunk/webrtc/common_audio/resampler/include/resampler.h
+++ b/media/webrtc/trunk/webrtc/common_audio/resampler/include/resampler.h
@@ -49,18 +49,17 @@ public:
     int Push(const int16_t* samples_in, int length_in,
              int16_t* samples_out, int max_len, int &out_len);
 
 private:
     bool IsFixedRate() { return !!(type_ & FIXED_RATE_RESAMPLER); }
 
     SpeexResamplerState* state_;
 
-    // State
     int in_freq_;
     int out_freq_;
     int channels_;
     ResamplerType type_;
 };
 
-} // namespace webrtc
+}  // namespace webrtc
 
 #endif // WEBRTC_RESAMPLER_RESAMPLER_H_
--- a/media/webrtc/trunk/webrtc/common_audio/resampler/push_resampler.cc
+++ b/media/webrtc/trunk/webrtc/common_audio/resampler/push_resampler.cc
@@ -5,17 +5,17 @@
  *  that can be found in the LICENSE file in the root of the source
  *  tree. An additional intellectual property rights grant can be found
  *  in the file PATENTS.  All contributing project authors may
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
 #include "webrtc/common_audio/resampler/include/push_resampler.h"
 
-#include <cstring>
+#include <string.h>
 
 #include "webrtc/common_audio/include/audio_util.h"
 #include "webrtc/common_audio/resampler/push_sinc_resampler.h"
 
 namespace webrtc {
 
 PushResampler::PushResampler()
     : sinc_resampler_(NULL),
@@ -32,25 +32,23 @@ PushResampler::PushResampler()
 PushResampler::~PushResampler() {
 }
 
 int PushResampler::InitializeIfNeeded(int src_sample_rate_hz,
                                       int dst_sample_rate_hz,
                                       int num_channels) {
   if (src_sample_rate_hz == src_sample_rate_hz_ &&
       dst_sample_rate_hz == dst_sample_rate_hz_ &&
-      num_channels == num_channels_) {
+      num_channels == num_channels_)
     // No-op if settings haven't changed.
     return 0;
-  }
 
   if (src_sample_rate_hz <= 0 || dst_sample_rate_hz <= 0 ||
-      num_channels <= 0 || num_channels > 2) {
+      num_channels <= 0 || num_channels > 2)
     return -1;
-  }
 
   src_sample_rate_hz_ = src_sample_rate_hz;
   dst_sample_rate_hz_ = dst_sample_rate_hz;
   num_channels_ = num_channels;
 
   const int src_size_10ms_mono = src_sample_rate_hz / 100;
   const int dst_size_10ms_mono = dst_sample_rate_hz / 100;
   sinc_resampler_.reset(new PushSincResampler(src_size_10ms_mono,
@@ -66,19 +64,18 @@ int PushResampler::InitializeIfNeeded(in
 
   return 0;
 }
 
 int PushResampler::Resample(const int16_t* src, int src_length,
                             int16_t* dst, int dst_capacity) {
   const int src_size_10ms = src_sample_rate_hz_ * num_channels_ / 100;
   const int dst_size_10ms = dst_sample_rate_hz_ * num_channels_ / 100;
-  if (src_length != src_size_10ms || dst_capacity < dst_size_10ms) {
+  if (src_length != src_size_10ms || dst_capacity < dst_size_10ms)
     return -1;
-  }
 
   if (src_sample_rate_hz_ == dst_sample_rate_hz_) {
     // The old resampler provides this memcpy facility in the case of matching
     // sample rates, so reproduce it here for the sinc resampler.
     memcpy(dst, src, src_length * sizeof(int16_t));
     return src_length;
   }
   if (num_channels_ == 2) {
--- a/media/webrtc/trunk/webrtc/common_audio/resampler/push_sinc_resampler.cc
+++ b/media/webrtc/trunk/webrtc/common_audio/resampler/push_sinc_resampler.cc
@@ -3,64 +3,83 @@
  *
  *  Use of this source code is governed by a BSD-style license
  *  that can be found in the LICENSE file in the root of the source
  *  tree. An additional intellectual property rights grant can be found
  *  in the file PATENTS.  All contributing project authors may
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
+#include "webrtc/common_audio/include/audio_util.h"
 #include "webrtc/common_audio/resampler/push_sinc_resampler.h"
 
-#include <cmath>
-
-#include <algorithm>
+#include <string.h>
 
 namespace webrtc {
 
-PushSincResampler::PushSincResampler(int src_block_size,
-                                     int dst_block_size)
+PushSincResampler::PushSincResampler(int source_frames,
+                                     int destination_frames)
     : resampler_(NULL),
-      float_buffer_(NULL),
+      float_buffer_(new float[destination_frames]),
       source_ptr_(NULL),
-      dst_size_(dst_block_size) {
-  resampler_.reset(new SincResampler(src_block_size * 1.0 / dst_block_size,
-                                     this, src_block_size));
-  float_buffer_.reset(new float[dst_block_size]);
+      destination_frames_(destination_frames),
+      first_pass_(true),
+      source_available_(0) {
+  resampler_.reset(new SincResampler(source_frames * 1.0 / destination_frames,
+                                     source_frames, this));
 }
 
 PushSincResampler::~PushSincResampler() {
 }
 
 int PushSincResampler::Resample(const int16_t* source,
                                 int source_length,
                                 int16_t* destination,
                                 int destination_capacity) {
-  assert(source_length == resampler_->BlockSize());
-  assert(destination_capacity >= dst_size_);
+  assert(source_length == resampler_->request_frames());
+  assert(destination_capacity >= destination_frames_);
   // Cache the source pointer. Calling Resample() will immediately trigger
   // the Run() callback whereupon we provide the cached value.
   source_ptr_ = source;
-  resampler_->Resample(float_buffer_.get(), dst_size_);
-  for (int i = 0; i < dst_size_; ++i) {
-    float clipped = std::max(std::min(float_buffer_[i], 32767.0f), -32768.0f);
-    destination[i] = static_cast<int16_t>(std::floor(clipped + 0.5));
-  }
+  source_available_ = source_length;
+
+  // On the first pass, we call Resample() twice. During the first call, we
+  // provide dummy input and discard the output. This is done to prime the
+  // SincResampler buffer with the correct delay (half the kernel size), thereby
+  // ensuring that all later Resample() calls will only result in one input
+  // request through Run().
+  //
+  // If this wasn't done, SincResampler would call Run() twice on the first
+  // pass, and we'd have to introduce an entire |source_frames| of delay, rather
+  // than the minimum half kernel.
+  //
+  // It works out that ChunkSize() is exactly the amount of output we need to
+  // request in order to prime the buffer with a single Run() request for
+  // |source_frames|.
+  if (first_pass_)
+    resampler_->Resample(resampler_->ChunkSize(), float_buffer_.get());
+
+  resampler_->Resample(destination_frames_, float_buffer_.get());
+  for (int i = 0; i < destination_frames_; ++i)
+    destination[i] = RoundToInt16(ClampInt16(float_buffer_[i]));
   source_ptr_ = NULL;
-  return dst_size_;
+  return destination_frames_;
 }
 
-void PushSincResampler::Run(float* destination, int frames) {
+void PushSincResampler::Run(int frames, float* destination) {
   assert(source_ptr_ != NULL);
-  assert(frames >= resampler_->BlockSize());
-  // We will have exactly |BlockSize| number of source samples available. If
-  // the resampler asks for more, zero pad the beginning. This will only happen
-  // on the first call while priming the buffer.
-  int i = 0;
-  for (; i < frames - resampler_->BlockSize(); ++i) {
-    destination[i] = 0;
-  }
-  for (int j = 0; i < frames; ++i, ++j) {
-    destination[i] = static_cast<float>(source_ptr_[j]);
+  // Ensure we are only asked for the available samples. This would fail if
+  // Run() was triggered more than once per Resample() call.
+  assert(source_available_ == frames);
+
+  if (first_pass_) {
+    // Provide dummy input on the first pass, the output of which will be
+    // discarded, as described in Resample().
+    memset(destination, 0, frames * sizeof(float));
+    first_pass_ = false;
+  } else {
+    for (int i = 0; i < frames; ++i)
+      destination[i] = static_cast<float>(source_ptr_[i]);
+    source_available_ -= frames;
   }
 }
 
 }  // namespace webrtc
--- a/media/webrtc/trunk/webrtc/common_audio/resampler/push_sinc_resampler.h
+++ b/media/webrtc/trunk/webrtc/common_audio/resampler/push_sinc_resampler.h
@@ -20,34 +20,42 @@ namespace webrtc {
 
 // A thin wrapper over SincResampler to provide a push-based interface as
 // required by WebRTC.
 class PushSincResampler : public SincResamplerCallback {
  public:
   // Provide the size of the source and destination blocks in samples. These
   // must correspond to the same time duration (typically 10 ms) as the sample
   // ratio is inferred from them.
-  PushSincResampler(int src_block_size, int dst_block_size);
+  PushSincResampler(int source_frames, int destination_frames);
   virtual ~PushSincResampler();
 
-  // Perform the resampling. |source_length| must always equal the
-  // |src_block_size| provided at construction. |destination_capacity| must be
-  // at least as large as |dst_block_size|. Returns the number of samples
+  // Perform the resampling. |source_frames| must always equal the
+  // |source_frames| provided at construction. |destination_capacity| must be
+  // at least as large as |destination_frames|. Returns the number of samples
   // provided in destination (for convenience, since this will always be equal
-  // to |dst_block_size|).
-  int Resample(const int16_t* source, int source_length,
+  // to |destination_frames|).
+  int Resample(const int16_t* source, int source_frames,
                int16_t* destination, int destination_capacity);
 
   // Implements SincResamplerCallback.
-  virtual void Run(float* destination, int frames);
+  virtual void Run(int frames, float* destination) OVERRIDE;
+
+  SincResampler* get_resampler_for_testing() { return resampler_.get(); }
 
  private:
   scoped_ptr<SincResampler> resampler_;
   scoped_array<float> float_buffer_;
   const int16_t* source_ptr_;
-  const int dst_size_;
+  const int destination_frames_;
+
+  // True on the first call to Resample(), to prime the SincResampler buffer.
+  bool first_pass_;
+
+  // Used to assert we are only requested for as much data as is available.
+  int source_available_;
 
   DISALLOW_COPY_AND_ASSIGN(PushSincResampler);
 };
 
 }  // namespace webrtc
 
 #endif  // WEBRTC_COMMON_AUDIO_RESAMPLER_PUSH_SINC_RESAMPLER_H_
--- a/media/webrtc/trunk/webrtc/common_audio/resampler/push_sinc_resampler_unittest.cc
+++ b/media/webrtc/trunk/webrtc/common_audio/resampler/push_sinc_resampler_unittest.cc
@@ -3,23 +3,24 @@
  *
  *  Use of this source code is governed by a BSD-style license
  *  that can be found in the LICENSE file in the root of the source
  *  tree. An additional intellectual property rights grant can be found
  *  in the file PATENTS.  All contributing project authors may
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#include <cmath>
+#include <math.h>
 
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "webrtc/common_audio/resampler/push_sinc_resampler.h"
 #include "webrtc/common_audio/resampler/sinusoidal_linear_chirp_source.h"
 #include "webrtc/system_wrappers/interface/scoped_ptr.h"
+#include "webrtc/system_wrappers/interface/tick_util.h"
 #include "webrtc/typedefs.h"
 
 namespace webrtc {
 
 typedef std::tr1::tuple<int, int, double, double> PushSincResamplerTestData;
 class PushSincResamplerTest
     : public testing::TestWithParam<PushSincResamplerTestData> {
  public:
@@ -34,16 +35,69 @@ class PushSincResamplerTest
 
  protected:
   int input_rate_;
   int output_rate_;
   double rms_error_;
   double low_freq_error_;
 };
 
+class ZeroSource : public SincResamplerCallback {
+ public:
+  void Run(int frames, float* destination) {
+    memset(destination, 0, sizeof(float) * frames);
+  }
+};
+
+// Disabled because it takes too long to run routinely. Use for performance
+// benchmarking when needed.
+TEST_P(PushSincResamplerTest, DISABLED_ResampleBenchmark) {
+  const int input_samples = input_rate_ / 100;
+  const int output_samples = output_rate_ / 100;
+  const int kResampleIterations = 200000;
+
+  // Source for data to be resampled.
+  ZeroSource resampler_source;
+
+  scoped_array<float> resampled_destination(new float[output_samples]);
+  scoped_array<float> source(new float[input_samples]);
+  scoped_array<int16_t> source_int(new int16_t[input_samples]);
+  scoped_array<int16_t> destination_int(new int16_t[output_samples]);
+
+  resampler_source.Run(input_samples, source.get());
+  for (int i = 0; i < input_samples; ++i) {
+    source_int[i] = static_cast<int16_t>(floor(32767 * source[i] + 0.5));
+  }
+
+  printf("Benchmarking %d iterations of %d Hz -> %d Hz:\n",
+         kResampleIterations, input_rate_, output_rate_);
+  const double io_ratio = input_rate_ / static_cast<double>(output_rate_);
+  SincResampler sinc_resampler(io_ratio, SincResampler::kDefaultRequestSize,
+                               &resampler_source);
+  TickTime start = TickTime::Now();
+  for (int i = 0; i < kResampleIterations; ++i) {
+    sinc_resampler.Resample(output_samples, resampled_destination.get());
+  }
+  double total_time_sinc_us = (TickTime::Now() - start).Microseconds();
+  printf("SincResampler took %.2f us per frame.\n",
+         total_time_sinc_us / kResampleIterations);
+
+  PushSincResampler resampler(input_samples, output_samples);
+  start = TickTime::Now();
+  for (int i = 0; i < kResampleIterations; ++i) {
+    EXPECT_EQ(output_samples,
+              resampler.Resample(source_int.get(), input_samples,
+                                 destination_int.get(), output_samples));
+  }
+  double total_time_us = (TickTime::Now() - start).Microseconds();
+  printf("PushSincResampler took %.2f us per frame; which is a %.1f%% overhead "
+         "on SincResampler.\n\n", total_time_us / kResampleIterations,
+         (total_time_us - total_time_sinc_us) / total_time_sinc_us * 100);
+}
+
 // Tests resampling using a given input and output sample rate.
 TEST_P(PushSincResamplerTest, Resample) {
   // Make comparisons using one second of data.
   static const double kTestDurationSecs = 1;
   // 10 ms blocks.
   const int kNumBlocks = kTestDurationSecs * 100;
   const int input_block_size = input_rate_ / 100;
   const int output_block_size = output_rate_ / 100;
@@ -62,46 +116,47 @@ TEST_P(PushSincResamplerTest, Resample) 
   // TODO(dalecurtis): If we switch to AVX/SSE optimization, we'll need to
   // allocate these on 32-byte boundaries and ensure they're sized % 32 bytes.
   scoped_array<float> resampled_destination(new float[output_samples]);
   scoped_array<float> pure_destination(new float[output_samples]);
   scoped_array<float> source(new float[input_samples]);
   scoped_array<int16_t> source_int(new int16_t[input_block_size]);
   scoped_array<int16_t> destination_int(new int16_t[output_block_size]);
 
+  // The sinc resampler has an implicit delay of approximately half the kernel
+  // size at the input sample rate. By moving to a push model, this delay
+  // becomes explicit and is managed by zero-stuffing in PushSincResampler. We
+  // deal with it in the test by delaying the "pure" source to match. It must be
+  // checked before the first call to Resample(), because ChunkSize() will
+  // change afterwards.
+  const int output_delay_samples = output_block_size -
+      resampler.get_resampler_for_testing()->ChunkSize();
+
   // Generate resampled signal.
   // With the PushSincResampler, we produce the signal block-by-10ms-block
   // rather than in a single pass, to exercise how it will be used in WebRTC.
-  resampler_source.Run(source.get(), input_samples);
+  resampler_source.Run(input_samples, source.get());
   for (int i = 0; i < kNumBlocks; ++i) {
     for (int j = 0; j < input_block_size; ++j) {
-      source_int[j] = static_cast<int16_t>(std::floor(32767 *
+      source_int[j] = static_cast<int16_t>(floor(32767 *
           source[i * input_block_size + j] + 0.5));
     }
     EXPECT_EQ(output_block_size,
               resampler.Resample(source_int.get(), input_block_size,
                                  destination_int.get(), output_block_size));
     for (int j = 0; j < output_block_size; ++j) {
       resampled_destination[i * output_block_size + j] =
           static_cast<float>(destination_int[j]) / 32767;
     }
   }
 
   // Generate pure signal.
-  // The sinc resampler has an implicit delay of half the kernel size (32) at
-  // the input sample rate. By moving to a push model, this delay becomes
-  // explicit and is managed by zero-stuffing in PushSincResampler. This delay
-  // can be a fractional sample amount, so we deal with it in the test by
-  // delaying the "pure" source to match.
-  static const int kInputKernelDelaySamples = 16;
-  double output_delay_samples = static_cast<double>(output_rate_)
-      / input_rate_ * kInputKernelDelaySamples;
   SinusoidalLinearChirpSource pure_source(
       output_rate_, output_samples, input_nyquist_freq, output_delay_samples);
-  pure_source.Run(pure_destination.get(), output_samples);
+  pure_source.Run(output_samples, pure_destination.get());
 
   // Range of the Nyquist frequency (0.5 * min(input rate, output_rate)) which
   // we refer to as low and high.
   static const double kLowFrequencyNyquistRange = 0.7;
   static const double kHighFrequencyNyquistRange = 0.9;
 
   // Calculate Root-Mean-Square-Error and maximum error for the resampling.
   double sum_of_squares = 0;
@@ -211,22 +266,22 @@ INSTANTIATE_TEST_CASE_P(
         std::tr1::make_tuple(32000, 8000, -20.36, -14.13),
         std::tr1::make_tuple(44100, 8000, -21.00, -11.39),
         std::tr1::make_tuple(48000, 8000, -20.96, -11.04),
 
         // To 16 kHz
         std::tr1::make_tuple(8000, 16000, kResamplingRMSError, -70.30),
         std::tr1::make_tuple(16000, 16000, kResamplingRMSError, -75.51),
         std::tr1::make_tuple(32000, 16000, -18.48, -28.59),
-        std::tr1::make_tuple(44100, 16000, -19.59, -19.77),
-        std::tr1::make_tuple(48000, 16000, -20.01, -18.11),
-        std::tr1::make_tuple(96000, 16000, -20.95, -10.99),
+        std::tr1::make_tuple(44100, 16000, -19.30, -19.67),
+        std::tr1::make_tuple(48000, 16000, -19.81, -18.11),
+        std::tr1::make_tuple(96000, 16000, -20.95, -10.96),
 
         // To 32 kHz
         std::tr1::make_tuple(8000, 32000, kResamplingRMSError, -70.30),
         std::tr1::make_tuple(16000, 32000, kResamplingRMSError, -75.51),
         std::tr1::make_tuple(32000, 32000, kResamplingRMSError, -75.56),
-        std::tr1::make_tuple(44100, 32000, -16.52, -51.10),
-        std::tr1::make_tuple(48000, 32000, -16.90, -44.17),
-        std::tr1::make_tuple(96000, 32000, -19.80, -18.05),
+        std::tr1::make_tuple(44100, 32000, -16.44, -51.10),
+        std::tr1::make_tuple(48000, 32000, -16.90, -44.03),
+        std::tr1::make_tuple(96000, 32000, -19.61, -18.04),
         std::tr1::make_tuple(192000, 32000, -21.02, -10.94)));
 
 }  // namespace webrtc
--- a/media/webrtc/trunk/webrtc/common_audio/resampler/resampler.cc
+++ b/media/webrtc/trunk/webrtc/common_audio/resampler/resampler.cc
@@ -127,9 +127,9 @@ int Resampler::Push(const int16_t* sampl
       len != (spx_uint32_t) length_in)
   {
     return -1;
   }
   out_len = (int) (channels_ * out);
   return 0;
 }
 
-} // namespace webrtc
+}  // namespace webrtc
--- a/media/webrtc/trunk/webrtc/common_audio/resampler/sinc_resampler.cc
+++ b/media/webrtc/trunk/webrtc/common_audio/resampler/sinc_resampler.cc
@@ -6,55 +6,98 @@
  *  tree. An additional intellectual property rights grant can be found
  *  in the file PATENTS.  All contributing project authors may
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
 // Modified from the Chromium original:
 // src/media/base/sinc_resampler.cc
 
-// Input buffer layout, dividing the total buffer into regions (r0_ - r5_):
+// Initial input buffer layout, dividing into regions r0_ to r4_ (note: r0_, r3_
+// and r4_ will move after the first load):
 //
 // |----------------|-----------------------------------------|----------------|
 //
-//                                   kBlockSize + kKernelSize / 2
+//                                        request_frames_
 //                   <--------------------------------------------------------->
-//                                              r0_
+//                                    r0_ (during first load)
 //
 //  kKernelSize / 2   kKernelSize / 2         kKernelSize / 2   kKernelSize / 2
 // <---------------> <--------------->       <---------------> <--------------->
 //        r1_               r2_                     r3_               r4_
 //
-//                                                     kBlockSize
-//                                     <--------------------------------------->
-//                                                        r5_
+//                             block_size_ == r4_ - r2_
+//                   <--------------------------------------->
+//
+//                                                  request_frames_
+//                                    <------------------ ... ----------------->
+//                                               r0_ (during second load)
+//
+// On the second request r0_ slides to the right by kKernelSize / 2 and r3_, r4_
+// and block_size_ are reinitialized via step (3) in the algorithm below.
+//
+// These new regions remain constant until a Flush() occurs.  While complicated,
+// this allows us to reduce jitter by always requesting the same amount from the
+// provided callback.
 //
 // The algorithm:
 //
-// 1) Consume input frames into r0_ (r1_ is zero-initialized).
-// 2) Position kernel centered at start of r0_ (r2_) and generate output frames
-//    until kernel is centered at start of r4_ or we've finished generating all
-//    the output frames.
-// 3) Copy r3_ to r1_ and r4_ to r2_.
-// 4) Consume input frames into r5_ (zero-pad if we run out of input).
-// 5) Goto (2) until all of input is consumed.
+// 1) Allocate input_buffer of size: request_frames_ + kKernelSize; this ensures
+//    there's enough room to read request_frames_ from the callback into region
+//    r0_ (which will move between the first and subsequent passes).
+//
+// 2) Let r1_, r2_ each represent half the kernel centered around r0_:
+//
+//        r0_ = input_buffer_ + kKernelSize / 2
+//        r1_ = input_buffer_
+//        r2_ = r0_
+//
+//    r0_ is always request_frames_ in size.  r1_, r2_ are kKernelSize / 2 in
+//    size.  r1_ must be zero initialized to avoid convolution with garbage (see
+//    step (5) for why).
+//
+// 3) Let r3_, r4_ each represent half the kernel right aligned with the end of
+//    r0_ and choose block_size_ as the distance in frames between r4_ and r2_:
+//
+//        r3_ = r0_ + request_frames_ - kKernelSize
+//        r4_ = r0_ + request_frames_ - kKernelSize / 2
+//        block_size_ = r4_ - r2_ = request_frames_ - kKernelSize / 2
+//
+// 4) Consume request_frames_ frames into r0_.
+//
+// 5) Position kernel centered at start of r2_ and generate output frames until
+//    the kernel is centered at the start of r4_ or we've finished generating
+//    all the output frames.
+//
+// 6) Wrap left over data from the r3_ to r1_ and r4_ to r2_.
+//
+// 7) If we're on the second load, in order to avoid overwriting the frames we
+//    just wrapped from r4_ we need to slide r0_ to the right by the size of
+//    r4_, which is kKernelSize / 2:
+//
+//        r0_ = r0_ + kKernelSize / 2 = input_buffer_ + kKernelSize
+//
+//    r3_, r4_, and block_size_ then need to be reinitialized, so goto (3).
+//
+// 8) Else, if we're not on the second load, goto (4).
 //
 // Note: we're glossing over how the sub-sample handling works with
 // |virtual_source_idx_|, etc.
 
 // MSVC++ requires this to be set before any other includes to get M_PI.
 #define _USE_MATH_DEFINES
 
 #include "webrtc/common_audio/resampler/sinc_resampler.h"
 #include "webrtc/system_wrappers/interface/compile_assert.h"
 #include "webrtc/system_wrappers/interface/cpu_features_wrapper.h"
 #include "webrtc/typedefs.h"
 
-#include <cmath>
-#include <cstring>
+#include <math.h>
+#include <string.h>
+
 #include <limits>
 
 namespace webrtc {
 
 static double SincScaleFactor(double io_ratio) {
   // |sinc_scale_factor| is basically the normalized cutoff frequency of the
   // low-pass filter.
   double sinc_scale_factor = io_ratio > 1.0 ? 1.0 / io_ratio : 1.0;
@@ -65,114 +108,107 @@ static double SincScaleFactor(double io_
   // some aliasing at the very high-end.
   // TODO(crogers): this value is empirical and to be more exact should vary
   // depending on kKernelSize.
   sinc_scale_factor *= 0.9;
 
   return sinc_scale_factor;
 }
 
+// If we know the minimum architecture at compile time, avoid CPU detection.
+// iOS lies about its architecture, so we also need to exclude it here.
+#if defined(WEBRTC_ARCH_X86_FAMILY) && !defined(WEBRTC_IOS)
+#if defined(__SSE__)
+#define CONVOLVE_FUNC Convolve_SSE
+void SincResampler::InitializeCPUSpecificFeatures() {}
+#else
+// X86 CPU detection required.  Function will be set by
+// InitializeCPUSpecificFeatures().
+// TODO(dalecurtis): Once Chrome moves to an SSE baseline this can be removed.
+#define CONVOLVE_FUNC convolve_proc_
+
+void SincResampler::InitializeCPUSpecificFeatures() {
+  convolve_proc_ = WebRtc_GetCPUInfo(kSSE2) ? Convolve_SSE : Convolve_C;
+}
+#endif
+#elif defined(WEBRTC_ARCH_ARM_V7)
+#if defined(WEBRTC_ARCH_ARM_NEON)
+#define CONVOLVE_FUNC Convolve_NEON
+void SincResampler::InitializeCPUSpecificFeatures() {}
+#else
+// NEON CPU detection required.  Function will be set by
+// InitializeCPUSpecificFeatures().
+#define CONVOLVE_FUNC convolve_proc_
+
+void SincResampler::InitializeCPUSpecificFeatures() {
+  convolve_proc_ = WebRtc_GetCPUFeaturesARM() & kCPUFeatureNEON ?
+      Convolve_NEON : Convolve_C;
+}
+#endif
+#else
+// Unknown architecture.
+#define CONVOLVE_FUNC Convolve_C
+void SincResampler::InitializeCPUSpecificFeatures() {}
+#endif
+
 SincResampler::SincResampler(double io_sample_rate_ratio,
-                             SincResamplerCallback* read_cb,
-                             int block_size)
+                             int request_frames,
+                             SincResamplerCallback* read_cb)
     : io_sample_rate_ratio_(io_sample_rate_ratio),
-      virtual_source_idx_(0),
-      buffer_primed_(false),
       read_cb_(read_cb),
-      block_size_(block_size),
-      buffer_size_(block_size_ + kKernelSize),
+      request_frames_(request_frames),
+      input_buffer_size_(request_frames_ + kKernelSize),
       // Create input buffers with a 16-byte alignment for SSE optimizations.
       kernel_storage_(static_cast<float*>(
           AlignedMalloc(sizeof(float) * kKernelStorageSize, 16))),
       kernel_pre_sinc_storage_(static_cast<float*>(
           AlignedMalloc(sizeof(float) * kKernelStorageSize, 16))),
       kernel_window_storage_(static_cast<float*>(
           AlignedMalloc(sizeof(float) * kKernelStorageSize, 16))),
       input_buffer_(static_cast<float*>(
-          AlignedMalloc(sizeof(float) * buffer_size_, 16))),
-#if defined(WEBRTC_ARCH_X86_FAMILY) && !defined(__SSE__)
-      convolve_proc_(WebRtc_GetCPUInfo(kSSE2) ? Convolve_SSE : Convolve_C),
-#elif defined(WEBRTC_ARCH_ARM_V7) && !defined(WEBRTC_ARCH_ARM_NEON)
-      convolve_proc_(WebRtc_GetCPUFeaturesARM() & kCPUFeatureNEON ?
-                     Convolve_NEON : Convolve_C),
+          AlignedMalloc(sizeof(float) * input_buffer_size_, 16))),
+#if defined(WEBRTC_RESAMPLER_CPU_DETECTION)
+      convolve_proc_(NULL),
 #endif
-      // Setup various region pointers in the buffer (see diagram above).
-      r0_(input_buffer_.get() + kKernelSize / 2),
       r1_(input_buffer_.get()),
-      r2_(r0_),
-      r3_(r0_ + block_size_ - kKernelSize / 2),
-      r4_(r0_ + block_size_),
-      r5_(r0_ + kKernelSize / 2) {
-  Initialize();
-  InitializeKernel();
-}
-
-SincResampler::SincResampler(double io_sample_rate_ratio,
-                             SincResamplerCallback* read_cb)
-    : io_sample_rate_ratio_(io_sample_rate_ratio),
-      virtual_source_idx_(0),
-      buffer_primed_(false),
-      read_cb_(read_cb),
-      block_size_(kDefaultBlockSize),
-      buffer_size_(kDefaultBufferSize),
-      // Create input buffers with a 16-byte alignment for SSE optimizations.
-      kernel_storage_(static_cast<float*>(
-          AlignedMalloc(sizeof(float) * kKernelStorageSize, 16))),
-      kernel_pre_sinc_storage_(static_cast<float*>(
-          AlignedMalloc(sizeof(float) * kKernelStorageSize, 16))),
-      kernel_window_storage_(static_cast<float*>(
-          AlignedMalloc(sizeof(float) * kKernelStorageSize, 16))),
-      input_buffer_(static_cast<float*>(
-          AlignedMalloc(sizeof(float) * buffer_size_, 16))),
-#if defined(WEBRTC_ARCH_X86_FAMILY) && !defined(__SSE__)
-      convolve_proc_(WebRtc_GetCPUInfo(kSSE2) ? Convolve_SSE : Convolve_C),
-#elif defined(WEBRTC_ARCH_ARM_V7) && !defined(WEBRTC_ARCH_ARM_NEON)
-      convolve_proc_(WebRtc_GetCPUFeaturesARM() & kCPUFeatureNEON ?
-                     Convolve_NEON : Convolve_C),
+      r2_(input_buffer_.get() + kKernelSize / 2) {
+#if defined(WEBRTC_RESAMPLER_CPU_DETECTION)
+  InitializeCPUSpecificFeatures();
+  assert(convolve_proc_);
 #endif
-      // Setup various region pointers in the buffer (see diagram above).
-      r0_(input_buffer_.get() + kKernelSize / 2),
-      r1_(input_buffer_.get()),
-      r2_(r0_),
-      r3_(r0_ + block_size_ - kKernelSize / 2),
-      r4_(r0_ + block_size_),
-      r5_(r0_ + kKernelSize / 2) {
-  Initialize();
-  InitializeKernel();
-}
-
-SincResampler::~SincResampler() {}
-
-void SincResampler::Initialize() {
-  // Ensure kKernelSize is a multiple of 32 for easy SSE optimizations; causes
-  // r0_ and r5_ (used for input) to always be 16-byte aligned by virtue of
-  // input_buffer_ being 16-byte aligned.
-  COMPILE_ASSERT(kKernelSize % 32 == 0);
+  assert(request_frames_ > 0);
+  Flush();
   assert(block_size_ > kKernelSize);
-  // Basic sanity checks to ensure buffer regions are laid out correctly:
-  // r0_ and r2_ should always be the same position.
-  assert(r0_ == r2_);
-  // r1_ at the beginning of the buffer.
-  assert(r1_ == input_buffer_.get());
-  // r1_ left of r2_, r2_ left of r5_ and r1_, r2_ size correct.
-  assert(r2_ - r1_ == r5_ - r2_);
-  // r3_ left of r4_, r5_ left of r0_ and r3_ size correct.
-  assert(r4_ - r3_ == r5_ - r0_);
-  // r3_, r4_ size correct and r4_ at the end of the buffer.
-  assert(r4_ + (r4_ - r3_) == r1_ + buffer_size_);
-  // r5_ size correct and at the end of the buffer.
-  assert(r5_ + block_size_ == r1_ + buffer_size_);
 
   memset(kernel_storage_.get(), 0,
          sizeof(*kernel_storage_.get()) * kKernelStorageSize);
   memset(kernel_pre_sinc_storage_.get(), 0,
          sizeof(*kernel_pre_sinc_storage_.get()) * kKernelStorageSize);
   memset(kernel_window_storage_.get(), 0,
          sizeof(*kernel_window_storage_.get()) * kKernelStorageSize);
-  memset(input_buffer_.get(), 0, sizeof(*input_buffer_.get()) * buffer_size_);
+
+  InitializeKernel();
+}
+
+SincResampler::~SincResampler() {}
+
+void SincResampler::UpdateRegions(bool second_load) {
+  // Setup various region pointers in the buffer (see diagram above).  If we're
+  // on the second load we need to slide r0_ to the right by kKernelSize / 2.
+  r0_ = input_buffer_.get() + (second_load ? kKernelSize : kKernelSize / 2);
+  r3_ = r0_ + request_frames_ - kKernelSize;
+  r4_ = r0_ + request_frames_ - kKernelSize / 2;
+  block_size_ = r4_ - r2_;
+
+  // r1_ at the beginning of the buffer.
+  assert(r1_ == input_buffer_.get());
+  // r1_ left of r2_, r4_ left of r3_ and size correct.
+  assert(r2_ - r1_ == r4_ - r3_);
+  // r2_ left of r3.
+  assert(r2_ < r3_);
 }
 
 void SincResampler::InitializeKernel() {
   // Blackman window parameters.
   static const double kAlpha = 0.16;
   static const double kA0 = 0.5 * (1.0 - kAlpha);
   static const double kA1 = 0.5;
   static const double kA2 = 0.5 * kAlpha;
@@ -229,110 +265,102 @@ void SincResampler::SetRatio(double io_s
       } else {
         kernel_storage_.get()[idx] =
             window * sin(sinc_scale_factor * pre_sinc) / pre_sinc;
       }
     }
   }
 }
 
-// If we know the minimum architecture avoid function hopping for CPU detection.
-#if defined(WEBRTC_ARCH_X86_FAMILY)
-#if defined(__SSE__)
-#define CONVOLVE_FUNC Convolve_SSE
-#else
-// X86 CPU detection required.  |convolve_proc_| will be set upon construction.
-// TODO(dalecurtis): Once Chrome moves to a SSE baseline this can be removed.
-#define CONVOLVE_FUNC convolve_proc_
-#endif
-#elif defined(WEBRTC_ARCH_ARM_V7)
-#if defined(WEBRTC_ARCH_ARM_NEON)
-#define CONVOLVE_FUNC Convolve_NEON
-#else
-// NEON CPU detection required.  |convolve_proc_| will be set upon construction.
-#define CONVOLVE_FUNC convolve_proc_
-#endif
-#else
-// Unknown architecture.
-#define CONVOLVE_FUNC Convolve_C
-#endif
-
-void SincResampler::Resample(float* destination, int frames) {
+void SincResampler::Resample(int frames, float* destination) {
   int remaining_frames = frames;
 
   // Step (1) -- Prime the input buffer at the start of the input stream.
-  if (!buffer_primed_) {
-    read_cb_->Run(r0_, block_size_ + kKernelSize / 2);
+  if (!buffer_primed_ && remaining_frames) {
+    read_cb_->Run(request_frames_, r0_);
     buffer_primed_ = true;
   }
 
-  // Step (2) -- Resample!
+  // Step (2) -- Resample!  const what we can outside of the loop for speed.  It
+  // actually has an impact on ARM performance.  See inner loop comment below.
+  const double current_io_ratio = io_sample_rate_ratio_;
+  const float* const kernel_ptr = kernel_storage_.get();
   while (remaining_frames) {
-    while (virtual_source_idx_ < block_size_) {
+    // |i| may be negative if the last Resample() call ended on an iteration
+    // that put |virtual_source_idx_| over the limit.
+    //
+    // Note: The loop construct here can severely impact performance on ARM
+    // or when built with clang.  See https://codereview.chromium.org/18566009/
+    for (int i = ceil((block_size_ - virtual_source_idx_) / current_io_ratio);
+         i > 0; --i) {
+      assert(virtual_source_idx_ < block_size_);
+
       // |virtual_source_idx_| lies in between two kernel offsets so figure out
       // what they are.
-      int source_idx = static_cast<int>(virtual_source_idx_);
-      double subsample_remainder = virtual_source_idx_ - source_idx;
+      const int source_idx = virtual_source_idx_;
+      const double subsample_remainder = virtual_source_idx_ - source_idx;
 
-      double virtual_offset_idx = subsample_remainder * kKernelOffsetCount;
-      int offset_idx = static_cast<int>(virtual_offset_idx);
+      const double virtual_offset_idx =
+          subsample_remainder * kKernelOffsetCount;
+      const int offset_idx = virtual_offset_idx;
 
       // We'll compute "convolutions" for the two kernels which straddle
       // |virtual_source_idx_|.
-      float* k1 = kernel_storage_.get() + offset_idx * kKernelSize;
-      float* k2 = k1 + kKernelSize;
+      const float* const k1 = kernel_ptr + offset_idx * kKernelSize;
+      const float* const k2 = k1 + kKernelSize;
 
       // Ensure |k1|, |k2| are 16-byte aligned for SIMD usage.  Should always be
       // true so long as kKernelSize is a multiple of 16.
-      assert((reinterpret_cast<uintptr_t>(k1) & 0x0F) == 0u);
-      assert((reinterpret_cast<uintptr_t>(k2) & 0x0F) == 0u);
+      assert(0u == (reinterpret_cast<uintptr_t>(k1) & 0x0F));
+      assert(0u == (reinterpret_cast<uintptr_t>(k2) & 0x0F));
 
       // Initialize input pointer based on quantized |virtual_source_idx_|.
-      float* input_ptr = r1_ + source_idx;
+      const float* const input_ptr = r1_ + source_idx;
 
       // Figure out how much to weight each kernel's "convolution".
-      double kernel_interpolation_factor = virtual_offset_idx - offset_idx;
+      const double kernel_interpolation_factor =
+          virtual_offset_idx - offset_idx;
       *destination++ = CONVOLVE_FUNC(
           input_ptr, k1, k2, kernel_interpolation_factor);
 
       // Advance the virtual index.
-      virtual_source_idx_ += io_sample_rate_ratio_;
+      virtual_source_idx_ += current_io_ratio;
 
       if (!--remaining_frames)
         return;
     }
 
     // Wrap back around to the start.
     virtual_source_idx_ -= block_size_;
 
-    // Step (3) Copy r3_ to r1_ and r4_ to r2_.
+    // Step (3) -- Copy r3_, r4_ to r1_, r2_.
     // This wraps the last input frames back to the start of the buffer.
-    memcpy(r1_, r3_, sizeof(*input_buffer_.get()) * (kKernelSize / 2));
-    memcpy(r2_, r4_, sizeof(*input_buffer_.get()) * (kKernelSize / 2));
+    memcpy(r1_, r3_, sizeof(*input_buffer_.get()) * kKernelSize);
 
-    // Step (4)
-    // Refresh the buffer with more input.
-    read_cb_->Run(r5_, block_size_);
+    // Step (4) -- Reinitialize regions if necessary.
+    if (r0_ == r2_)
+      UpdateRegions(true);
+
+    // Step (5) -- Refresh the buffer with more input.
+    read_cb_->Run(request_frames_, r0_);
   }
 }
 
 #undef CONVOLVE_FUNC
 
-int SincResampler::ChunkSize() {
+int SincResampler::ChunkSize() const {
   return block_size_ / io_sample_rate_ratio_;
 }
 
-int SincResampler::BlockSize() {
-  return block_size_;
-}
-
 void SincResampler::Flush() {
   virtual_source_idx_ = 0;
   buffer_primed_ = false;
-  memset(input_buffer_.get(), 0, sizeof(*input_buffer_.get()) * buffer_size_);
+  memset(input_buffer_.get(), 0,
+         sizeof(*input_buffer_.get()) * input_buffer_size_);
+  UpdateRegions(false);
 }
 
 float SincResampler::Convolve_C(const float* input_ptr, const float* k1,
                                 const float* k2,
                                 double kernel_interpolation_factor) {
   float sum1 = 0;
   float sum2 = 0;
 
--- a/media/webrtc/trunk/webrtc/common_audio/resampler/sinc_resampler.h
+++ b/media/webrtc/trunk/webrtc/common_audio/resampler/sinc_resampler.h
@@ -15,94 +15,100 @@
 #define WEBRTC_COMMON_AUDIO_RESAMPLER_SINC_RESAMPLER_H_
 
 #include "webrtc/system_wrappers/interface/aligned_malloc.h"
 #include "webrtc/system_wrappers/interface/constructor_magic.h"
 #include "webrtc/system_wrappers/interface/scoped_ptr.h"
 #include "webrtc/test/testsupport/gtest_prod_util.h"
 #include "webrtc/typedefs.h"
 
+#if (defined(WEBRTC_ARCH_X86_FAMILY) && !defined(WEBRTC_IOS) &&  \
+        !defined(__SSE__)) ||  \
+    (defined(WEBRTC_ARCH_ARM_V7) && !defined(WEBRTC_ARCH_ARM_NEON))
+// Convenience define.
+#define WEBRTC_RESAMPLER_CPU_DETECTION
+#endif
+
 namespace webrtc {
 
 // Callback class for providing more data into the resampler.  Expects |frames|
 // of data to be rendered into |destination|; zero padded if not enough frames
 // are available to satisfy the request.
 class SincResamplerCallback {
  public:
   virtual ~SincResamplerCallback() {}
-  virtual void Run(float* destination, int frames) = 0;
+  virtual void Run(int frames, float* destination) = 0;
 };
 
 // SincResampler is a high-quality single-channel sample-rate converter.
 class SincResampler {
  public:
   enum {
     // The kernel size can be adjusted for quality (higher is better) at the
     // expense of performance.  Must be a multiple of 32.
     // TODO(dalecurtis): Test performance to see if we can jack this up to 64+.
     kKernelSize = 32,
 
-    // The number of destination frames generated per processing pass.  Affects
-    // how often and for how much SincResampler calls back for input.  Must be
-    // greater than kKernelSize.
-    kDefaultBlockSize = 512,
+    // Default request size.  Affects how often and for how much SincResampler
+    // calls back for input.  Must be greater than kKernelSize.
+    kDefaultRequestSize = 512,
 
     // The kernel offset count is used for interpolation and is the number of
     // sub-sample kernel shifts.  Can be adjusted for quality (higher is better)
     // at the expense of allocating more memory.
     kKernelOffsetCount = 32,
     kKernelStorageSize = kKernelSize * (kKernelOffsetCount + 1),
-
-    // The size (in samples) of the internal buffer used by the resampler.
-    kDefaultBufferSize = kDefaultBlockSize + kKernelSize,
   };
 
   // Constructs a SincResampler with the specified |read_cb|, which is used to
-  // acquire audio data for resampling.  |io_sample_rate_ratio| is the ratio of
-  // input / output sample rates.  If desired, the number of destination frames
-  // generated per processing pass can be specified through |block_size|.
+  // acquire audio data for resampling.  |io_sample_rate_ratio| is the ratio
+  // of input / output sample rates.  |request_frames| controls the size in
+  // frames of the buffer requested by each |read_cb| call.  The value must be
+  // greater than kKernelSize.  Specify kDefaultRequestSize if there are no
+  // request size constraints.
   SincResampler(double io_sample_rate_ratio,
+                int request_frames,
                 SincResamplerCallback* read_cb);
-  SincResampler(double io_sample_rate_ratio,
-                SincResamplerCallback* read_cb,
-                int block_size);
   virtual ~SincResampler();
 
   // Resample |frames| of data from |read_cb_| into |destination|.
-  void Resample(float* destination, int frames);
+  void Resample(int frames, float* destination);
 
   // The maximum size in frames that guarantees Resample() will only make a
   // single call to |read_cb_| for more data.
-  int ChunkSize();
+  int ChunkSize() const;
 
-  // The number of source frames requested per processing pass (and equal to
-  // |block_size| if provided at construction).  The first pass will request
-  // more to prime the buffer.
-  int BlockSize();
+  int request_frames() const { return request_frames_; }
 
   // Flush all buffered data and reset internal indices.  Not thread safe, do
   // not call while Resample() is in progress.
   void Flush();
 
   // Update |io_sample_rate_ratio_|.  SetRatio() will cause a reconstruction of
   // the kernels used for resampling.  Not thread safe, do not call while
   // Resample() is in progress.
   //
-  // TODO(ajm): use this in PushSincResampler rather than reconstructing
-  // SincResampler.
+  // TODO(ajm): Use this in PushSincResampler rather than reconstructing
+  // SincResampler.  We would also need a way to update |request_frames_|.
   void SetRatio(double io_sample_rate_ratio);
 
   float* get_kernel_for_testing() { return kernel_storage_.get(); }
 
  private:
   FRIEND_TEST_ALL_PREFIXES(SincResamplerTest, Convolve);
   FRIEND_TEST_ALL_PREFIXES(SincResamplerTest, ConvolveBenchmark);
 
-  void Initialize();
   void InitializeKernel();
+  void UpdateRegions(bool second_load);
+
+  // Selects runtime specific CPU features like SSE.  Must be called before
+  // using SincResampler.
+  // TODO(ajm): Currently managed by the class internally. See the note with
+  // |convolve_proc_| below.
+  void InitializeCPUSpecificFeatures();
 
   // Compute convolution of |k1| and |k2| over |input_ptr|, resultant sums are
   // linearly interpolated using |kernel_interpolation_factor|.  On x86, the
   // underlying implementation is chosen at run time based on SSE support.  On
   // ARM, NEON support is chosen at compile time based on compilation flags.
   static float Convolve_C(const float* input_ptr, const float* k1,
                           const float* k2, double kernel_interpolation_factor);
 #if defined(WEBRTC_ARCH_X86_FAMILY)
@@ -123,47 +129,51 @@ class SincResampler {
   double virtual_source_idx_;
 
   // The buffer is primed once at the very beginning of processing.
   bool buffer_primed_;
 
   // Source of data for resampling.
   SincResamplerCallback* read_cb_;
 
-  // See kDefaultBlockSize.
+  // The size (in samples) to request from each |read_cb_| execution.
+  const int request_frames_;
+
+  // The number of source frames processed per pass.
   int block_size_;
 
-  // See kDefaultBufferSize.
-  int buffer_size_;
+  // The size (in samples) of the internal buffer used by the resampler.
+  const int input_buffer_size_;
 
   // Contains kKernelOffsetCount kernels back-to-back, each of size kKernelSize.
   // The kernel offsets are sub-sample shifts of a windowed sinc shifted from
   // 0.0 to 1.0 sample.
   scoped_ptr_malloc<float, AlignedFree> kernel_storage_;
   scoped_ptr_malloc<float, AlignedFree> kernel_pre_sinc_storage_;
   scoped_ptr_malloc<float, AlignedFree> kernel_window_storage_;
 
   // Data from the source is copied into this buffer for each processing pass.
   scoped_ptr_malloc<float, AlignedFree> input_buffer_;
 
   // Stores the runtime selection of which Convolve function to use.
-#if (defined(WEBRTC_ARCH_X86_FAMILY) && !defined(__SSE__)) ||  \
-    (defined(WEBRTC_ARCH_ARM_V7) && !defined(WEBRTC_ARCH_ARM_NEON))
+  // TODO(ajm): Move to using a global static which must only be initialized
+  // once by the user. We're not doing this initially, because we don't have
+  // e.g. a LazyInstance helper in webrtc.
+#if defined(WEBRTC_RESAMPLER_CPU_DETECTION)
   typedef float (*ConvolveProc)(const float*, const float*, const float*,
                                 double);
-  const ConvolveProc convolve_proc_;
+  ConvolveProc convolve_proc_;
 #endif
 
   // Pointers to the various regions inside |input_buffer_|.  See the diagram at
   // the top of the .cc file for more information.
-  float* const r0_;
+  float* r0_;
   float* const r1_;
   float* const r2_;
-  float* const r3_;
-  float* const r4_;
-  float* const r5_;
+  float* r3_;
+  float* r4_;
 
   DISALLOW_COPY_AND_ASSIGN(SincResampler);
 };
 
 }  // namespace webrtc
 
 #endif  // WEBRTC_COMMON_AUDIO_RESAMPLER_SINC_RESAMPLER_H_
--- a/media/webrtc/trunk/webrtc/common_audio/resampler/sinc_resampler_unittest.cc
+++ b/media/webrtc/trunk/webrtc/common_audio/resampler/sinc_resampler_unittest.cc
@@ -9,17 +9,17 @@
  */
 
 // Modified from the Chromium original:
 // src/media/base/sinc_resampler_unittest.cc
 
 // MSVC++ requires this to be set before any other includes to get M_PI.
 #define _USE_MATH_DEFINES
 
-#include <cmath>
+#include <math.h>
 
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "webrtc/common_audio/resampler/sinc_resampler.h"
 #include "webrtc/common_audio/resampler/sinusoidal_linear_chirp_source.h"
 #include "webrtc/system_wrappers/interface/cpu_features_wrapper.h"
 #include "webrtc/system_wrappers/interface/scoped_ptr.h"
 #include "webrtc/system_wrappers/interface/stringize_macros.h"
@@ -31,77 +31,93 @@ using testing::_;
 namespace webrtc {
 
 static const double kSampleRateRatio = 192000.0 / 44100.0;
 static const double kKernelInterpolationFactor = 0.5;
 
 // Helper class to ensure ChunkedResample() functions properly.
 class MockSource : public SincResamplerCallback {
  public:
-  MOCK_METHOD2(Run, void(float* destination, int frames));
+  MOCK_METHOD2(Run, void(int frames, float* destination));
 };
 
 ACTION(ClearBuffer) {
-  memset(arg0, 0, arg1 * sizeof(float));
+  memset(arg1, 0, arg0 * sizeof(float));
 }
 
 ACTION(FillBuffer) {
   // Value chosen arbitrarily such that SincResampler resamples it to something
   // easily representable on all platforms; e.g., using kSampleRateRatio this
   // becomes 1.81219.
-  memset(arg0, 64, arg1 * sizeof(float));
+  memset(arg1, 64, arg0 * sizeof(float));
 }
 
 // Test requesting multiples of ChunkSize() frames results in the proper number
 // of callbacks.
 TEST(SincResamplerTest, ChunkedResample) {
   MockSource mock_source;
 
   // Choose a high ratio of input to output samples which will result in quick
   // exhaustion of SincResampler's internal buffers.
-  SincResampler resampler(kSampleRateRatio, &mock_source);
+  SincResampler resampler(kSampleRateRatio, SincResampler::kDefaultRequestSize,
+                          &mock_source);
 
   static const int kChunks = 2;
   int max_chunk_size = resampler.ChunkSize() * kChunks;
   scoped_array<float> resampled_destination(new float[max_chunk_size]);
 
   // Verify requesting ChunkSize() frames causes a single callback.
   EXPECT_CALL(mock_source, Run(_, _))
       .Times(1).WillOnce(ClearBuffer());
-  resampler.Resample(resampled_destination.get(), resampler.ChunkSize());
+  resampler.Resample(resampler.ChunkSize(), resampled_destination.get());
 
   // Verify requesting kChunks * ChunkSize() frames causes kChunks callbacks.
   testing::Mock::VerifyAndClear(&mock_source);
   EXPECT_CALL(mock_source, Run(_, _))
       .Times(kChunks).WillRepeatedly(ClearBuffer());
-  resampler.Resample(resampled_destination.get(), max_chunk_size);
+  resampler.Resample(max_chunk_size, resampled_destination.get());
 }
 
 // Test flush resets the internal state properly.
 TEST(SincResamplerTest, Flush) {
   MockSource mock_source;
-  SincResampler resampler(kSampleRateRatio, &mock_source);
+  SincResampler resampler(kSampleRateRatio, SincResampler::kDefaultRequestSize,
+                          &mock_source);
   scoped_array<float> resampled_destination(new float[resampler.ChunkSize()]);
 
   // Fill the resampler with junk data.
   EXPECT_CALL(mock_source, Run(_, _))
       .Times(1).WillOnce(FillBuffer());
-  resampler.Resample(resampled_destination.get(), resampler.ChunkSize() / 2);
+  resampler.Resample(resampler.ChunkSize() / 2, resampled_destination.get());
   ASSERT_NE(resampled_destination[0], 0);
 
   // Flush and request more data, which should all be zeros now.
   resampler.Flush();
   testing::Mock::VerifyAndClear(&mock_source);
   EXPECT_CALL(mock_source, Run(_, _))
       .Times(1).WillOnce(ClearBuffer());
-  resampler.Resample(resampled_destination.get(), resampler.ChunkSize() / 2);
+  resampler.Resample(resampler.ChunkSize() / 2, resampled_destination.get());
   for (int i = 0; i < resampler.ChunkSize() / 2; ++i)
     ASSERT_FLOAT_EQ(resampled_destination[i], 0);
 }
 
+// Test flush resets the internal state properly.
+TEST(SincResamplerTest, DISABLED_SetRatioBench) {
+  MockSource mock_source;
+  SincResampler resampler(kSampleRateRatio, SincResampler::kDefaultRequestSize,
+                          &mock_source);
+
+  TickTime start = TickTime::Now();
+  for (int i = 1; i < 10000; ++i)
+    resampler.SetRatio(1.0 / i);
+  double total_time_c_us = (TickTime::Now() - start).Microseconds();
+  printf("SetRatio() took %.2fms.\n", total_time_c_us / 1000);
+}
+
+
 // Define platform independent function name for Convolve* tests.
 #if defined(WEBRTC_ARCH_X86_FAMILY)
 #define CONVOLVE_FUNC Convolve_SSE
 #elif defined(WEBRTC_ARCH_ARM_V7)
 #define CONVOLVE_FUNC Convolve_NEON
 #endif
 
 // Ensure various optimized Convolve() methods return the same value.  Only run
@@ -112,17 +128,18 @@ TEST(SincResamplerTest, Convolve) {
 #if defined(WEBRTC_ARCH_X86_FAMILY)
   ASSERT_TRUE(WebRtc_GetCPUInfo(kSSE2));
 #elif defined(WEBRTC_ARCH_ARM_V7)
   ASSERT_TRUE(WebRtc_GetCPUFeaturesARM() & kCPUFeatureNEON);
 #endif
 
   // Initialize a dummy resampler.
   MockSource mock_source;
-  SincResampler resampler(kSampleRateRatio, &mock_source);
+  SincResampler resampler(kSampleRateRatio, SincResampler::kDefaultRequestSize,
+                          &mock_source);
 
   // The optimized Convolve methods are slightly more precise than Convolve_C(),
   // so comparison must be done using an epsilon.
   static const double kEpsilon = 0.00000005;
 
   // Use a kernel from SincResampler as input and kernel data, this has the
   // benefit of already being properly sized and aligned for Convolve_SSE().
   double result = resampler.Convolve_C(
@@ -145,17 +162,18 @@ TEST(SincResamplerTest, Convolve) {
 #endif
 
 // Benchmark for the various Convolve() methods.  Make sure to build with
 // branding=Chrome so that DCHECKs are compiled out when benchmarking.  Original
 // benchmarks were run with --convolve-iterations=50000000.
 TEST(SincResamplerTest, ConvolveBenchmark) {
   // Initialize a dummy resampler.
   MockSource mock_source;
-  SincResampler resampler(kSampleRateRatio, &mock_source);
+  SincResampler resampler(kSampleRateRatio, SincResampler::kDefaultRequestSize,
+                          &mock_source);
 
   // Retrieve benchmark iterations from command line.
   // TODO(ajm): Reintroduce this as a command line option.
   const int kConvolveIterations = 1000000;
 
   printf("Benchmarking %d iterations:\n", kConvolveIterations);
 
   // Benchmark Convolve_C().
@@ -238,19 +256,18 @@ TEST_P(SincResamplerTest, Resample) {
   // Nyquist frequency for the input sampling rate.
   const double input_nyquist_freq = 0.5 * input_rate_;
 
   // Source for data to be resampled.
   SinusoidalLinearChirpSource resampler_source(
       input_rate_, input_samples, input_nyquist_freq, 0);
 
   const double io_ratio = input_rate_ / static_cast<double>(output_rate_);
-  SincResampler resampler(
-      io_ratio,
-      &resampler_source);
+  SincResampler resampler(io_ratio, SincResampler::kDefaultRequestSize,
+                          &resampler_source);
 
   // Force an update to the sample rate ratio to ensure dyanmic sample rate
   // changes are working correctly.
   scoped_array<float> kernel(new float[SincResampler::kKernelStorageSize]);
   memcpy(kernel.get(), resampler.get_kernel_for_testing(),
          SincResampler::kKernelStorageSize);
   resampler.SetRatio(M_PI);
   ASSERT_NE(0, memcmp(kernel.get(), resampler.get_kernel_for_testing(),
@@ -260,22 +277,22 @@ TEST_P(SincResamplerTest, Resample) {
                       SincResampler::kKernelStorageSize));
 
   // TODO(dalecurtis): If we switch to AVX/SSE optimization, we'll need to
   // allocate these on 32-byte boundaries and ensure they're sized % 32 bytes.
   scoped_array<float> resampled_destination(new float[output_samples]);
   scoped_array<float> pure_destination(new float[output_samples]);
 
   // Generate resampled signal.
-  resampler.Resample(resampled_destination.get(), output_samples);
+  resampler.Resample(output_samples, resampled_destination.get());
 
   // Generate pure signal.
   SinusoidalLinearChirpSource pure_source(
       output_rate_, output_samples, input_nyquist_freq, 0);
-  pure_source.Run(pure_destination.get(), output_samples);
+  pure_source.Run(output_samples, pure_destination.get());
 
   // Range of the Nyquist frequency (0.5 * min(input rate, output_rate)) which
   // we refer to as low and high.
   static const double kLowFrequencyNyquistRange = 0.7;
   static const double kHighFrequencyNyquistRange = 0.9;
 
   // Calculate Root-Mean-Square-Error and maximum error for the resampling.
   double sum_of_squares = 0;
--- a/media/webrtc/trunk/webrtc/common_audio/resampler/sinusoidal_linear_chirp_source.cc
+++ b/media/webrtc/trunk/webrtc/common_audio/resampler/sinusoidal_linear_chirp_source.cc
@@ -8,33 +8,33 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
 // MSVC++ requires this to be set before any other includes to get M_PI.
 #define _USE_MATH_DEFINES
 
 #include "webrtc/common_audio/resampler/sinusoidal_linear_chirp_source.h"
 
-#include <cmath>
+#include <math.h>
 
 namespace webrtc {
 
 SinusoidalLinearChirpSource::SinusoidalLinearChirpSource(int sample_rate,
   int samples, double max_frequency, double delay_samples)
     : sample_rate_(sample_rate),
       total_samples_(samples),
       max_frequency_(max_frequency),
       current_index_(0),
       delay_samples_(delay_samples) {
   // Chirp rate.
   double duration = static_cast<double>(total_samples_) / sample_rate_;
   k_ = (max_frequency_ - kMinFrequency) / duration;
 }
 
-void SinusoidalLinearChirpSource::Run(float* destination, int frames) {
+void SinusoidalLinearChirpSource::Run(int frames, float* destination) {
   for (int i = 0; i < frames; ++i, ++current_index_) {
     // Filter out frequencies higher than Nyquist.
     if (Frequency(current_index_) > 0.5 * sample_rate_) {
       destination[i] = 0;
     } else {
       // Calculate time in seconds.
       double t = (static_cast<double>(current_index_) - delay_samples_) /
           sample_rate_;
--- a/media/webrtc/trunk/webrtc/common_audio/resampler/sinusoidal_linear_chirp_source.h
+++ b/media/webrtc/trunk/webrtc/common_audio/resampler/sinusoidal_linear_chirp_source.h
@@ -26,17 +26,17 @@ class SinusoidalLinearChirpSource : publ
  public:
   // |delay_samples| can be used to insert a fractional sample delay into the
   // source.  It will produce zeros until non-negative time is reached.
   SinusoidalLinearChirpSource(int sample_rate, int samples,
                               double max_frequency, double delay_samples);
 
   virtual ~SinusoidalLinearChirpSource() {}
 
-  virtual void Run(float* destination, int frames);
+  virtual void Run(int frames, float* destination) OVERRIDE;
 
   double Frequency(int position);
 
  private:
   enum {
     kMinFrequency = 5
   };
 
--- a/media/webrtc/trunk/webrtc/common_audio/signal_processing/complex_bit_reverse_mips.c
+++ b/media/webrtc/trunk/webrtc/common_audio/signal_processing/complex_bit_reverse_mips.c
@@ -169,9 +169,8 @@ void WebRtcSpl_ComplexBitReverse(int16_t
         [ptr_j] "=&r" (ptr_j), [ti] "=&r" (ti), [tr] "=&r" (tr),
         [l] "=&r" (l), [pcoeftable_7] "+r" (pcoeftable_7),
         [tmp3] "=&r" (tmp3), [tmp4] "=&r" (tmp4)
       : [frfi] "r" (frfi)
       : "memory"
     );
   }
 }
-
--- a/media/webrtc/trunk/webrtc/common_audio/signal_processing/complex_fft.c
+++ b/media/webrtc/trunk/webrtc/common_audio/signal_processing/complex_fft.c
@@ -10,18 +10,18 @@
 
 
 /*
  * This file contains the function WebRtcSpl_ComplexFFT().
  * The description header can be found in signal_processing_library.h
  *
  */
 
+#include "webrtc/common_audio/signal_processing/complex_fft_tables.h"
 #include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
-#include "webrtc/common_audio/signal_processing/complex_fft_tables.h"
 
 #define CFFTSFT 14
 #define CFFTRND 1
 #define CFFTRND2 16384
 
 #define CIFFTSFT 14
 #define CIFFTRND 1
 
--- a/media/webrtc/trunk/webrtc/common_audio/signal_processing/complex_fft_mips.c
+++ b/media/webrtc/trunk/webrtc/common_audio/signal_processing/complex_fft_mips.c
@@ -4,18 +4,18 @@
  *  Use of this source code is governed by a BSD-style license
  *  that can be found in the LICENSE file in the root of the source
  *  tree. An additional intellectual property rights grant can be found
  *  in the file PATENTS.  All contributing project authors may
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
 
+#include "webrtc/common_audio/signal_processing/complex_fft_tables.h"
 #include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
-#include "webrtc/common_audio/signal_processing/complex_fft_tables.h"
 
 #define CFFTSFT 14
 #define CFFTRND 1
 #define CFFTRND2 16384
 
 #define CIFFTSFT 14
 #define CIFFTRND 1
 
@@ -315,9 +315,8 @@ int WebRtcSpl_ComplexIFFT(int16_t frfi[]
       [shift] "=&r" (shift), [scale] "=&r" (scale), [tempMax] "=&r" (tempMax)
     : [n] "r" (n), [frfi] "r" (frfi), [kSinTable1024] "r" (kSinTable1024)
     : "hi", "lo", "$ac1hi", "$ac1lo", "memory"
   );
 
   return scale;
 
 }
-
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/webrtc/common_audio/signal_processing/cross_correlation_mips.c
@@ -0,0 +1,104 @@
+/*
+ *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+
+void WebRtcSpl_CrossCorrelation_mips(int32_t* cross_correlation,
+                                     const int16_t* seq1,
+                                     const int16_t* seq2,
+                                     int16_t dim_seq,
+                                     int16_t dim_cross_correlation,
+                                     int16_t right_shifts,
+                                     int16_t step_seq2) {
+
+  int32_t t0 = 0, t1 = 0, t2 = 0, t3 = 0, sum = 0;
+  int16_t *pseq2 = NULL;
+  int16_t *pseq1 = NULL;
+  int16_t *pseq1_0 = (int16_t*)&seq1[0];
+  int16_t *pseq2_0 = (int16_t*)&seq2[0];
+  int k = 0;
+
+  __asm __volatile (
+    ".set        push                                           \n\t"
+    ".set        noreorder                                      \n\t"
+    "sll         %[step_seq2], %[step_seq2],   1                \n\t"
+    "andi        %[t0],        %[dim_seq],     1                \n\t"
+    "bgtz        %[t0],        3f                               \n\t"
+    " nop                                                       \n\t"
+   "1:                                                          \n\t"
+    "move        %[pseq1],     %[pseq1_0]                       \n\t"
+    "move        %[pseq2],     %[pseq2_0]                       \n\t"
+    "sra         %[k],         %[dim_seq],     1                \n\t"
+    "addiu       %[dim_cc],    %[dim_cc],      -1               \n\t"
+    "xor         %[sum],       %[sum],         %[sum]           \n\t"
+   "2:                                                          \n\t"
+    "lh          %[t0],        0(%[pseq1])                      \n\t"
+    "lh          %[t1],        0(%[pseq2])                      \n\t"
+    "lh          %[t2],        2(%[pseq1])                      \n\t"
+    "lh          %[t3],        2(%[pseq2])                      \n\t"
+    "mul         %[t0],        %[t0],          %[t1]            \n\t"
+    "addiu       %[k],         %[k],           -1               \n\t"
+    "mul         %[t2],        %[t2],          %[t3]            \n\t"
+    "addiu       %[pseq1],     %[pseq1],       4                \n\t"
+    "addiu       %[pseq2],     %[pseq2],       4                \n\t"
+    "srav        %[t0],        %[t0],          %[right_shifts]  \n\t"
+    "addu        %[sum],       %[sum],         %[t0]            \n\t"
+    "srav        %[t2],        %[t2],          %[right_shifts]  \n\t"
+    "bgtz        %[k],         2b                               \n\t"
+    " addu       %[sum],       %[sum],         %[t2]            \n\t"
+    "addu        %[pseq2_0],   %[pseq2_0],     %[step_seq2]     \n\t"
+    "sw          %[sum],       0(%[cc])                         \n\t"
+    "bgtz        %[dim_cc],    1b                               \n\t"
+    " addiu      %[cc],        %[cc],          4                \n\t"
+    "b           6f                                             \n\t"
+    " nop                                                       \n\t"
+   "3:                                                          \n\t"
+    "move        %[pseq1],     %[pseq1_0]                       \n\t"
+    "move        %[pseq2],     %[pseq2_0]                       \n\t"
+    "sra         %[k],         %[dim_seq],     1                \n\t"
+    "addiu       %[dim_cc],    %[dim_cc],      -1               \n\t"
+    "beqz        %[k],         5f                               \n\t"
+    " xor        %[sum],       %[sum],         %[sum]           \n\t"
+   "4:                                                          \n\t"
+    "lh          %[t0],        0(%[pseq1])                      \n\t"
+    "lh          %[t1],        0(%[pseq2])                      \n\t"
+    "lh          %[t2],        2(%[pseq1])                      \n\t"
+    "lh          %[t3],        2(%[pseq2])                      \n\t"
+    "mul         %[t0],        %[t0],          %[t1]            \n\t"
+    "addiu       %[k],         %[k],           -1               \n\t"
+    "mul         %[t2],        %[t2],          %[t3]            \n\t"
+    "addiu       %[pseq1],     %[pseq1],       4                \n\t"
+    "addiu       %[pseq2],     %[pseq2],       4                \n\t"
+    "srav        %[t0],        %[t0],          %[right_shifts]  \n\t"
+    "addu        %[sum],       %[sum],         %[t0]            \n\t"
+    "srav        %[t2],        %[t2],          %[right_shifts]  \n\t"
+    "bgtz        %[k],         4b                               \n\t"
+    " addu       %[sum],       %[sum],         %[t2]            \n\t"
+   "5:                                                          \n\t"
+    "lh          %[t0],        0(%[pseq1])                      \n\t"
+    "lh          %[t1],        0(%[pseq2])                      \n\t"
+    "mul         %[t0],        %[t0],          %[t1]            \n\t"
+    "srav        %[t0],        %[t0],          %[right_shifts]  \n\t"
+    "addu        %[sum],       %[sum],         %[t0]            \n\t"
+    "addu        %[pseq2_0],   %[pseq2_0],     %[step_seq2]     \n\t"
+    "sw          %[sum],       0(%[cc])                         \n\t"
+    "bgtz        %[dim_cc],    3b                               \n\t"
+    " addiu      %[cc],        %[cc],          4                \n\t"
+   "6:                                                          \n\t"
+    ".set        pop                                            \n\t"
+    : [step_seq2] "+r" (step_seq2), [t0] "=&r" (t0), [t1] "=&r" (t1),
+      [t2] "=&r" (t2), [t3] "=&r" (t3), [pseq1] "=&r" (pseq1),
+      [pseq2] "=&r" (pseq2), [pseq1_0] "+r" (pseq1_0), [pseq2_0] "+r" (pseq2_0),
+      [k] "=&r" (k), [dim_cc] "+r" (dim_cross_correlation), [sum] "=&r" (sum),
+      [cc] "+r" (cross_correlation)
+    : [dim_seq] "r" (dim_seq), [right_shifts] "r" (right_shifts)
+    : "hi", "lo", "memory"
+  );
+}
--- a/media/webrtc/trunk/webrtc/common_audio/signal_processing/downsample_fast_mips.c
+++ b/media/webrtc/trunk/webrtc/common_audio/signal_processing/downsample_fast_mips.c
@@ -162,9 +162,8 @@ int WebRtcSpl_DownsampleFast_mips(const 
       [max_16] "r" (max_16), [min_16] "r" (min_16),
 #endif  // #if !defined(MIPS_DSP_R1_LE)
       [delay] "r" (delay), [factor] "r" (factor)
     : "memory", "hi", "lo"
   );
 #endif  // #if defined(MIPS_DSP_R2_LE)
   return 0;
 }
-
--- a/media/webrtc/trunk/webrtc/common_audio/signal_processing/filter_ar_fast_q12_mips.c
+++ b/media/webrtc/trunk/webrtc/common_audio/signal_processing/filter_ar_fast_q12_mips.c
@@ -4,17 +4,17 @@
  *  Use of this source code is governed by a BSD-style license
  *  that can be found in the LICENSE file in the root of the source
  *  tree. An additional intellectual property rights grant can be found
  *  in the file PATENTS.  All contributing project authors may
  *  be found in the AUTHORS file in the root of the source tree.
  */
 #include <assert.h>
 
-#include "signal_processing_library.h"
+#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
 
 void WebRtcSpl_FilterARFastQ12(const int16_t* data_in,
                                int16_t* data_out,
                                const int16_t* __restrict coefficients,
                                int coefficients_length,
                                int data_length) {
   int r0, r1, r2, r3;
   int coef0, offset;
--- a/media/webrtc/trunk/webrtc/common_audio/signal_processing/include/real_fft.h
+++ b/media/webrtc/trunk/webrtc/common_audio/signal_processing/include/real_fft.h
@@ -8,79 +8,121 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
 #ifndef WEBRTC_COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_REAL_FFT_H_
 #define WEBRTC_COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_REAL_FFT_H_
 
 #include "webrtc/typedefs.h"
 
+// For ComplexFFT(), the maximum fft order is 10;
+// for OpenMax FFT in ARM, it is 12;
+// WebRTC APM uses orders of only 7 and 8.
+enum {kMaxFFTOrder = 10};
+
 struct RealFFT;
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+typedef struct RealFFT* (*CreateRealFFT)(int order);
+typedef void (*FreeRealFFT)(struct RealFFT* self);
 typedef int (*RealForwardFFT)(struct RealFFT* self,
-                              const int16_t* data_in,
-                              int16_t* data_out);
+                              const int16_t* real_data_in,
+                              int16_t* complex_data_out);
 typedef int (*RealInverseFFT)(struct RealFFT* self,
-                              const int16_t* data_in,
-                              int16_t* data_out);
+                              const int16_t* complex_data_in,
+                              int16_t* real_data_out);
 
+extern CreateRealFFT WebRtcSpl_CreateRealFFT;
+extern FreeRealFFT WebRtcSpl_FreeRealFFT;
 extern RealForwardFFT WebRtcSpl_RealForwardFFT;
 extern RealInverseFFT WebRtcSpl_RealInverseFFT;
 
-struct RealFFT* WebRtcSpl_CreateRealFFT(int order);
-void WebRtcSpl_FreeRealFFT(struct RealFFT* self);
+struct RealFFT* WebRtcSpl_CreateRealFFTC(int order);
+void WebRtcSpl_FreeRealFFTC(struct RealFFT* self);
+
+#if (defined WEBRTC_DETECT_ARM_NEON) || (defined WEBRTC_ARCH_ARM_NEON)
+struct RealFFT* WebRtcSpl_CreateRealFFTNeon(int order);
+void WebRtcSpl_FreeRealFFTNeon(struct RealFFT* self);
+#endif
 
-// TODO(kma): Implement FFT functions for real signals.
-
-// Compute the forward FFT for a complex signal of length 2^order.
+// Compute an FFT for a real-valued signal of length of 2^order,
+// where 1 < order <= MAX_FFT_ORDER. Transform length is determined by the
+// specification structure, which must be initialized prior to calling the FFT
+// function with WebRtcSpl_CreateRealFFT().
+// The relationship between the input and output sequences can
+// be expressed in terms of the DFT, i.e.:
+//     x[n] = (2^(-scalefactor)/N)  . SUM[k=0,...,N-1] X[k].e^(jnk.2.pi/N)
+//     n=0,1,2,...N-1
+//     N=2^order.
+// The conjugate-symmetric output sequence is represented using a CCS vector,
+// which is of length N+2, and is organized as follows:
+//     Index:      0  1  2  3  4  5   . . .   N-2       N-1       N       N+1
+//     Component:  R0 0  R1 I1 R2 I2  . . .   R[N/2-1]  I[N/2-1]  R[N/2]  0
+// where R[n] and I[n], respectively, denote the real and imaginary components
+// for FFT bin 'n'. Bins  are numbered from 0 to N/2, where N is the FFT length.
+// Bin index 0 corresponds to the DC component, and bin index N/2 corresponds to
+// the foldover frequency.
+//
 // Input Arguments:
 //   self - pointer to preallocated and initialized FFT specification structure.
-//   data_in - the input signal.
+//   real_data_in - the input signal. For an ARM Neon platform, it must be
+//                  aligned on a 32-byte boundary.
 //
 // Output Arguments:
-//   data_out - the output signal; must be different to data_in.
+//   complex_data_out - the output complex signal with (2^order + 2) 16-bit
+//                      elements. For an ARM Neon platform, it must be different
+//                      from real_data_in, and aligned on a 32-byte boundary.
 //
 // Return Value:
 //   0  - FFT calculation is successful.
-//   -1 - Error
-//
+//   -1 - Error with bad arguments (NULL pointers).
 int WebRtcSpl_RealForwardFFTC(struct RealFFT* self,
-                              const int16_t* data_in,
-                              int16_t* data_out);
+                              const int16_t* real_data_in,
+                              int16_t* complex_data_out);
 
 #if (defined WEBRTC_DETECT_ARM_NEON) || (defined WEBRTC_ARCH_ARM_NEON)
 int WebRtcSpl_RealForwardFFTNeon(struct RealFFT* self,
-                                 const int16_t* data_in,
-                                 int16_t* data_out);
+                                 const int16_t* real_data_in,
+                                 int16_t* complex_data_out);
 #endif
 
-// Compute the inverse FFT for a complex signal of length 2^order.
+// Compute the inverse FFT for a conjugate-symmetric input sequence of length of
+// 2^order, where 1 < order <= MAX_FFT_ORDER. Transform length is determined by
+// the specification structure, which must be initialized prior to calling the
+// FFT function with WebRtcSpl_CreateRealFFT().
+// For a transform of length M, the input sequence is represented using a packed
+// CCS vector of length M+2, which is explained in the comments for
+// WebRtcSpl_RealForwardFFTC above.
+//
 // Input Arguments:
 //   self - pointer to preallocated and initialized FFT specification structure.
-//   data_in - the input signal.
+//   complex_data_in - the input complex signal with (2^order + 2) 16-bit
+//                     elements. For an ARM Neon platform, it must be aligned on
+//                     a 32-byte boundary.
 //
 // Output Arguments:
-//   data_out - the output signal; must be different to data_in.
+//   real_data_out - the output real signal. For an ARM Neon platform, it must
+//                   be different to complex_data_in, and aligned on a 32-byte
+//                   boundary.
 //
 // Return Value:
-//   0 or a positive number - a value that the elements in the |data_out| should
-//                            be shifted left with in order to get correct
-//                            physical values.
-//   -1                     - Error
+//   0 or a positive number - a value that the elements in the |real_data_out|
+//                            should be shifted left with in order to get
+//                            correct physical values.
+//   -1 - Error with bad arguments (NULL pointers).
 int WebRtcSpl_RealInverseFFTC(struct RealFFT* self,
-                              const int16_t* data_in,
-                              int16_t* data_out);
+                              const int16_t* complex_data_in,
+                              int16_t* real_data_out);
 
 #if (defined WEBRTC_DETECT_ARM_NEON) || (defined WEBRTC_ARCH_ARM_NEON)
 int WebRtcSpl_RealInverseFFTNeon(struct RealFFT* self,
-                                 const int16_t* data_in,
-                                 int16_t* data_out);
+                                 const int16_t* complex_data_in,
+                                 int16_t* real_data_out);
 #endif
 
 #ifdef __cplusplus
 }
 #endif
 
 #endif  // WEBRTC_COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_REAL_FFT_H_
--- a/media/webrtc/trunk/webrtc/common_audio/signal_processing/include/signal_processing_library.h
+++ b/media/webrtc/trunk/webrtc/common_audio/signal_processing/include/signal_processing_library.h
@@ -68,30 +68,33 @@
     ((int32_t)(int16_t)(a) * (uint16_t)(b))
 #define WEBRTC_SPL_DIV(a, b) \
     ((int32_t) ((int32_t)(a) / (int32_t)(b)))
 #define WEBRTC_SPL_UDIV(a, b) \
     ((uint32_t) ((uint32_t)(a) / (uint32_t)(b)))
 
 #ifndef WEBRTC_ARCH_ARM_V7
 // For ARMv7 platforms, these are inline functions in spl_inl_armv7.h
+#ifndef MIPS32_LE
+// For MIPS platforms, these are inline functions in spl_inl_mips.h
 #define WEBRTC_SPL_MUL_16_16(a, b) \
     ((int32_t) (((int16_t)(a)) * ((int16_t)(b))))
 #define WEBRTC_SPL_MUL_16_32_RSFT16(a, b) \
     (WEBRTC_SPL_MUL_16_16(a, b >> 16) \
      + ((WEBRTC_SPL_MUL_16_16(a, (b & 0xffff) >> 1) + 0x4000) >> 15))
 #define WEBRTC_SPL_MUL_32_32_RSFT32(a32a, a32b, b32) \
     ((int32_t)(WEBRTC_SPL_MUL_16_32_RSFT16(a32a, b32) \
     + (WEBRTC_SPL_MUL_16_32_RSFT16(a32b, b32) >> 16)))
 #define WEBRTC_SPL_MUL_32_32_RSFT32BI(a32, b32) \
     ((int32_t)(WEBRTC_SPL_MUL_16_32_RSFT16(( \
     (int16_t)(a32 >> 16)), b32) + \
     (WEBRTC_SPL_MUL_16_32_RSFT16(( \
     (int16_t)((a32 & 0x0000FFFF) >> 1)), b32) >> 15)))
 #endif
+#endif
 
 #define WEBRTC_SPL_MUL_16_32_RSFT11(a, b) \
     ((WEBRTC_SPL_MUL_16_16(a, (b) >> 16) << 5) \
     + (((WEBRTC_SPL_MUL_16_U16(a, (uint16_t)(b)) >> 1) + 0x0200) >> 10))
 #define WEBRTC_SPL_MUL_16_32_RSFT14(a, b) \
     ((WEBRTC_SPL_MUL_16_16(a, (b) >> 16) << 2) \
     + (((WEBRTC_SPL_MUL_16_U16(a, (uint16_t)(b)) >> 1) + 0x1000) >> 13))
 #define WEBRTC_SPL_MUL_16_32_RSFT15(a, b) \
@@ -451,16 +454,25 @@ int WebRtcSpl_ScaleAndAddVectorsWithRoun
 int WebRtcSpl_ScaleAndAddVectorsWithRoundNeon(const int16_t* in_vector1,
                                               int16_t in_vector1_scale,
                                               const int16_t* in_vector2,
                                               int16_t in_vector2_scale,
                                               int right_shifts,
                                               int16_t* out_vector,
                                               int length);
 #endif
+#if defined(MIPS_DSP_R1_LE)
+int WebRtcSpl_ScaleAndAddVectorsWithRound_mips(const int16_t* in_vector1,
+                                               int16_t in_vector1_scale,
+                                               const int16_t* in_vector2,
+                                               int16_t in_vector2_scale,
+                                               int right_shifts,
+                                               int16_t* out_vector,
+                                               int length);
+#endif
 // End: Vector scaling operations.
 
 // iLBC specific functions. Implementations in ilbc_specific_functions.c.
 // Description at bottom of file.
 void WebRtcSpl_ReverseOrderMultArrayElements(int16_t* out_vector,
                                              const int16_t* in_vector,
                                              const int16_t* window,
                                              int16_t vector_length,
@@ -622,16 +634,25 @@ void WebRtcSpl_CrossCorrelationC(int32_t
 void WebRtcSpl_CrossCorrelationNeon(int32_t* cross_correlation,
                                     const int16_t* seq1,
                                     const int16_t* seq2,
                                     int16_t dim_seq,
                                     int16_t dim_cross_correlation,
                                     int16_t right_shifts,
                                     int16_t step_seq2);
 #endif
+#if defined(MIPS32_LE)
+void WebRtcSpl_CrossCorrelation_mips(int32_t* cross_correlation,
+                                     const int16_t* seq1,
+                                     const int16_t* seq2,
+                                     int16_t dim_seq,
+                                     int16_t dim_cross_correlation,
+                                     int16_t right_shifts,
+                                     int16_t step_seq2);
+#endif
 
 // Creates (the first half of) a Hanning window. Size must be at least 1 and
 // at most 512.
 //
 // Input:
 //      - size      : Length of the requested Hanning window (1 to 512)
 //
 // Output:
--- a/media/webrtc/trunk/webrtc/common_audio/signal_processing/include/spl_inl.h
+++ b/media/webrtc/trunk/webrtc/common_audio/signal_processing/include/spl_inl.h
@@ -14,16 +14,21 @@
 
 #ifndef WEBRTC_SPL_SPL_INL_H_
 #define WEBRTC_SPL_SPL_INL_H_
 
 #ifdef WEBRTC_ARCH_ARM_V7
 #include "webrtc/common_audio/signal_processing/include/spl_inl_armv7.h"
 #else
 
+#if defined(MIPS32_LE)
+#include "webrtc/common_audio/signal_processing/include/spl_inl_mips.h"
+#endif
+
+#if !defined(MIPS_DSP_R1_LE)
 static __inline int16_t WebRtcSpl_SatW32ToW16(int32_t value32) {
   int16_t out16 = (int16_t) value32;
 
   if (value32 > 32767)
     out16 = 32767;
   else if (value32 < -32768)
     out16 = -32768;
 
@@ -32,17 +37,19 @@ static __inline int16_t WebRtcSpl_SatW32
 
 static __inline int16_t WebRtcSpl_AddSatW16(int16_t a, int16_t b) {
   return WebRtcSpl_SatW32ToW16((int32_t) a + (int32_t) b);
 }
 
 static __inline int16_t WebRtcSpl_SubSatW16(int16_t var1, int16_t var2) {
   return WebRtcSpl_SatW32ToW16((int32_t) var1 - (int32_t) var2);
 }
+#endif  // #if !defined(MIPS_DSP_R1_LE)
 
+#if !defined(MIPS32_LE)
 static __inline int16_t WebRtcSpl_GetSizeInBits(uint32_t n) {
   int bits;
 
   if (0xFFFF0000 & n) {
     bits = 16;
   } else {
     bits = 0;
   }
@@ -116,21 +123,23 @@ static __inline int WebRtcSpl_NormW16(in
   if (!(0xC000 & (a << zeros))) zeros += 1;
 
   return zeros;
 }
 
 static __inline int32_t WebRtc_MulAccumW16(int16_t a, int16_t b, int32_t c) {
   return (a * b + c);
 }
+#endif  // #if !defined(MIPS32_LE)
 
 #endif  // WEBRTC_ARCH_ARM_V7
 
 // The following functions have no optimized versions.
 // TODO(kma): Consider saturating add/sub instructions in X86 platform.
+#if !defined(MIPS_DSP_R1_LE)
 static __inline int32_t WebRtcSpl_AddSatW32(int32_t l_var1, int32_t l_var2) {
   int32_t l_sum;
 
   // Perform long addition
   l_sum = l_var1 + l_var2;
 
   if (l_var1 < 0) {  // Check for underflow.
     if ((l_var2 < 0) && (l_sum >= 0)) {
@@ -158,10 +167,11 @@ static __inline int32_t WebRtcSpl_SubSat
   } else {  // Check for overflow.
     if ((l_var2 < 0) && (l_diff < 0)) {
       l_diff = (int32_t)0x7FFFFFFF;
     }
   }
 
   return l_diff;
 }
+#endif  // #if !defined(MIPS_DSP_R1_LE)
 
 #endif  // WEBRTC_SPL_SPL_INL_H_
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/webrtc/common_audio/signal_processing/include/spl_inl_mips.h
@@ -0,0 +1,281 @@
+/*
+ *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+
+// This header file includes the inline functions in
+// the fix point signal processing library.
+
+#ifndef WEBRTC_SPL_SPL_INL_MIPS_H_
+#define WEBRTC_SPL_SPL_INL_MIPS_H_
+
+static __inline int32_t WEBRTC_SPL_MUL_16_16(int32_t a,
+                                             int32_t b) {
+  int32_t value32 = 0;
+  int32_t a1 = 0, b1 = 0;
+
+  __asm __volatile(
+#if defined(MIPS32_R2_LE)
+    "seh    %[a1],          %[a]                \n\t"
+    "seh    %[b1],          %[b]                \n\t"
+#else
+    "sll    %[a1],          %[a],         16    \n\t"
+    "sll    %[b1],          %[b],         16    \n\t"
+    "sra    %[a1],          %[a1],        16    \n\t"
+    "sra    %[b1],          %[b1],        16    \n\t"
+#endif
+    "mul    %[value32],     %[a1],  %[b1]       \n\t"
+    : [value32] "=r" (value32), [a1] "=&r" (a1), [b1] "=&r" (b1)
+    : [a] "r" (a), [b] "r" (b)
+    : "hi", "lo"
+  );
+  return value32;
+}
+
+static __inline int32_t WEBRTC_SPL_MUL_16_32_RSFT16(int16_t a,
+                                                    int32_t b) {
+  int32_t value32 = 0, b1 = 0, b2 = 0;
+  int32_t a1 = 0;
+
+  __asm __volatile(
+#if defined(MIPS32_R2_LE)
+    "seh    %[a1],          %[a]                        \n\t"
+#else
+    "sll    %[a1],          %[a],           16          \n\t"
+    "sra    %[a1],          %[a1],          16          \n\t"
+#endif
+    "andi   %[b2],          %[b],           0xFFFF      \n\t"
+    "sra    %[b1],          %[b],           16          \n\t"
+    "sra    %[b2],          %[b2],          1           \n\t"
+    "mul    %[value32],     %[a1],          %[b1]       \n\t"
+    "mul    %[b2],          %[a1],          %[b2]       \n\t"
+    "addiu  %[b2],          %[b2],          0x4000      \n\t"
+    "sra    %[b2],          %[b2],          15          \n\t"
+    "addu   %[value32],     %[value32],     %[b2]       \n\t"
+    : [value32] "=&r" (value32), [b1] "=&r" (b1), [b2] "=&r" (b2),
+      [a1] "=&r" (a1)
+    : [a] "r" (a), [b] "r" (b)
+    : "hi", "lo"
+  );
+  return value32;
+}
+
+static __inline int32_t WEBRTC_SPL_MUL_32_32_RSFT32BI(int32_t a,
+                                                      int32_t b) {
+  int32_t tmp = 0;
+
+  if ((32767 < a) || (a < 0))
+    tmp = WEBRTC_SPL_MUL_16_32_RSFT16(((int16_t)(a >> 16)), b);
+  tmp += WEBRTC_SPL_MUL_16_32_RSFT16(((int16_t)((a & 0x0000FFFF) >> 1)),
+                                     b) >> 15;
+
+  return tmp;
+}
+
+static __inline int32_t WEBRTC_SPL_MUL_32_32_RSFT32(int16_t a,
+                                                    int16_t b,
+                                                    int32_t c) {
+  int32_t tmp1 = 0, tmp2 = 0, tmp3 = 0, tmp4 = 0;
+
+  __asm __volatile(
+    "sra                %[tmp1],   %[c],      16      \n\t"
+    "andi               %[tmp2],   %[c],      0xFFFF  \n\t"
+#if defined(MIPS32_R2_LE)
+    "seh                %[a],      %[a]               \n\t"
+    "seh                %[b],      %[b]               \n\t"
+#else
+    "sll                %[a],      %[a],      16      \n\t"
+    "sra                %[a],      %[a],      16      \n\t"
+    "sll                %[b],      %[b],      16      \n\t"
+    "sra                %[b],      %[b],      16      \n\t"
+#endif
+    "sra                %[tmp2],   %[tmp2],   1       \n\t"
+    "mul                %[tmp3],   %[a],      %[tmp2] \n\t"
+    "mul                %[tmp4],   %[b],      %[tmp2] \n\t"
+    "mul                %[tmp2],   %[a],      %[tmp1] \n\t"
+    "mul                %[tmp1],   %[b],      %[tmp1] \n\t"
+#if defined(MIPS_DSP_R1_LE)
+    "shra_r.w           %[tmp3],   %[tmp3],   15      \n\t"
+    "shra_r.w           %[tmp4],   %[tmp4],   15      \n\t"
+#else
+    "addiu              %[tmp3],   %[tmp3],   0x4000  \n\t"
+    "sra                %[tmp3],   %[tmp3],   15      \n\t"
+    "addiu              %[tmp4],   %[tmp4],   0x4000  \n\t"
+    "sra                %[tmp4],   %[tmp4],   15      \n\t"
+#endif
+    "addu               %[tmp3],   %[tmp3],   %[tmp2] \n\t"
+    "addu               %[tmp4],   %[tmp4],   %[tmp1] \n\t"
+    "sra                %[tmp4],   %[tmp4],   16      \n\t"
+    "addu               %[tmp1],   %[tmp3],   %[tmp4] \n\t"
+    : [tmp1] "=&r" (tmp1), [tmp2] "=&r" (tmp2),
+      [tmp3] "=&r" (tmp3), [tmp4] "=&r" (tmp4),
+      [a] "+r" (a), [b] "+r" (b)
+    : [c] "r" (c)
+    : "hi", "lo"
+  );
+  return tmp1;
+}
+
+#if defined(MIPS_DSP_R1_LE)
+static __inline int16_t WebRtcSpl_SatW32ToW16(int32_t value32) {
+  __asm __volatile(
+    "shll_s.w   %[value32], %[value32], 16      \n\t"
+    "sra        %[value32], %[value32], 16      \n\t"
+    : [value32] "+r" (value32)
+    :
+  );
+  int16_t out16 = (int16_t)value32;
+  return out16;
+}
+
+static __inline int16_t WebRtcSpl_AddSatW16(int16_t a, int16_t b) {
+  int32_t value32 = 0;
+
+  __asm __volatile(
+    "addq_s.ph      %[value32],     %[a],   %[b]    \n\t"
+    : [value32] "=r" (value32)
+    : [a] "r" (a), [b] "r" (b)
+  );
+  return (int16_t)value32;
+}
+
+static __inline int32_t WebRtcSpl_AddSatW32(int32_t l_var1, int32_t l_var2) {
+  int32_t l_sum;
+
+  __asm __volatile(
+    "addq_s.w   %[l_sum],       %[l_var1],      %[l_var2]    \n\t"
+    : [l_sum] "=r" (l_sum)
+    : [l_var1] "r" (l_var1), [l_var2] "r" (l_var2)
+  );
+
+  return l_sum;
+}
+
+static __inline int16_t WebRtcSpl_SubSatW16(int16_t var1, int16_t var2) {
+  int32_t value32;
+
+  __asm __volatile(
+    "subq_s.ph  %[value32], %[var1],    %[var2]     \n\t"
+    : [value32] "=r" (value32)
+    : [var1] "r" (var1), [var2] "r" (var2)
+  );
+
+  return (int16_t)value32;
+}
+
+static __inline int32_t WebRtcSpl_SubSatW32(int32_t l_var1, int32_t l_var2) {
+  int32_t l_diff;
+
+  __asm __volatile(
+    "subq_s.w   %[l_diff],      %[l_var1],      %[l_var2]    \n\t"
+    : [l_diff] "=r" (l_diff)
+    : [l_var1] "r" (l_var1), [l_var2] "r" (l_var2)
+  );
+
+  return l_diff;
+}
+#endif
+
+static __inline int16_t WebRtcSpl_GetSizeInBits(uint32_t n) {
+  int bits = 0;
+  int i32 = 32;
+
+  __asm __volatile(
+    "clz    %[bits],    %[n]                    \n\t"
+    "subu   %[bits],    %[i32],     %[bits]     \n\t"
+    : [bits] "=&r" (bits)
+    : [n] "r" (n), [i32] "r" (i32)
+  );
+
+  return bits;
+}
+
+static __inline int WebRtcSpl_NormW32(int32_t a) {
+  int zeros = 0;
+
+  __asm __volatile(
+    ".set       push                                \n\t"
+    ".set       noreorder                           \n\t"
+    "bnez       %[a],       1f                      \n\t"
+    " sra       %[zeros],   %[a],       31          \n\t"
+    "b          2f                                  \n\t"
+    " move      %[zeros],   $zero                   \n\t"
+   "1:                                              \n\t"
+    "xor        %[zeros],   %[a],       %[zeros]    \n\t"
+    "clz        %[zeros],   %[zeros]                \n\t"
+    "addiu      %[zeros],   %[zeros],   -1          \n\t"
+   "2:                                              \n\t"
+    ".set       pop                                 \n\t"
+    : [zeros]"=&r"(zeros)
+    : [a] "r" (a)
+  );
+