merge mozilla-inbound to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Mon, 04 Jan 2016 11:55:29 +0100
changeset 318640 0771c5eab32f0cee4f7d12bc382298a81e0eabb2
parent 318632 eb6fac84655a2763721f2946659eb2a021845645 (current diff)
parent 318639 0b48021c20c3a5eeda052e7a91bacedc8d3a0d26 (diff)
child 318641 0af68bf705c794cd653fe96ccba4a01572042ca8
child 318642 3ed47dc439f4ff0130c142bb50ff1a4df353e847
child 318644 e31a99e1f8677a11926462aebfbdfbce16afe2f8
child 318655 0666526a249c106274a4c764e325cd9810e9a2e7
child 318716 7b47adc35322566d062e51c2609e4c098e72acf2
child 318740 7d8f2bcf5d12175c695c3f7d63532de6be47cb9a
child 318758 614f913342a41eed3f0d7da9794068b977e3390b
child 318761 daae75a76dabe97eb8384e2a38ce509d567af90c
child 318763 c95cded902c1c7fec1e7b28aabca375d524ac904
child 318764 f7e1f7696e6cdfc30e2eab82aedbf5f5cb74e27a
child 318765 3b695349c19b1f38c17693149968a95735d835db
child 318794 27cf717179ed8e313460f5b619f88b74517a8121
child 318801 954e1349c073a7e32111d2a691fbb97d8ae9432a
child 318804 30e9e119053f331295c3a1ce225649ef6597a4c9
child 318819 af937b0f2c32c63ddc806a6ee420dbfc8a8c335c
child 318822 63bf685d21825675a783ec8b5befc285fdbdc1f2
child 318859 f3b7baa83f5559e7bd519f98490e3243ad55fb77
child 318860 84a97e0e50f526b7c19e53fa23cb90f0f048178c
child 318861 a79be8684a51a529a6b163c9bac378a199ab6961
child 318878 20360de81e53172b93f95b82cad6a5151ba6ea99
child 319012 24087d640aefb0f818b565e382b17613cfeb6edb
child 319105 95b646fff56658688140001cd23f2df35fd7726a
child 319106 8d15f1a842d69b92f88f067595e274ce6de625cd
child 319107 bc379edd13f2db87e9df70f239b1f4e454676dc4
child 319168 5a2435870474bfad5e9a3e37bbab7ebda8bc8a2d
child 319290 52a0e293f43e90054a459d3e89c978e5452417fa
child 319775 f6d4fdab9562c98c88d05b6db26ec9456aa2f16c
child 320046 6efffc77ef2b108617214c5ead35f8c4e90fcd3f
child 322157 cbfc8785ffe23d3cd0311e006c93123a5a1b03d0
push id8899
push userj.parkouss@gmail.com
push dateMon, 04 Jan 2016 15:30:52 +0000
reviewersmerge
milestone46.0a1
merge mozilla-inbound to mozilla-central a=merge
--- a/configure.in
+++ b/configure.in
@@ -1439,89 +1439,68 @@ if test "$GNU_CC"; then
                     DSO_LDOPTS="$DSO_LDOPTS -Wl,--warn-unresolved-symbols"
                 fi
                 ;;
             esac
         fi
     fi
 
     # Turn on gcc/clang warnings:
-    # https://gcc.gnu.org/onlinedocs/gcc-4.4.0/gcc/Warning-Options.html
-    #
-    # -Wall - turn on a lot of warnings
-    # -Wchar-subscripts - catches array index using signed char
-    # -Wcomment - catches nested comments
+    # https://gcc.gnu.org/onlinedocs/gcc-4.7.2/gcc/Warning-Options.html
+
+    # -Wall - lots of useful warnings
     # -Wempty-body - catches bugs, e.g. "if (c); foo();", few false positives
-    # -Wendif-labels - catches `#else FOO` and `#endif FOO` not in comment
-    # -Wenum-compare - catches comparison of different enum types
     # -Wignored-qualifiers - catches returns types with qualifiers like const
-    # -Wint-to-pointer-cast - catches cast to pointer from integer of different size
-    # -Wmultichar - catches multicharacter integer constants like 'THIS'
-    # -Wnon-literal-null-conversion - catches expressions used as a null pointer constant
-    # -Wnonnull - catches NULL used with functions arguments marked as non-null
     # -Wpointer-arith - catches pointer arithmetic using NULL or sizeof(void)
-    # -Wpointer-sign - catches mixing pointers to signed and unsigned types
-    # -Wpointer-to-int-cast - catches casts from pointer to different sized int
-    # -Wreturn-type - catches missing returns, zero false positives
-    # -Wsequence-point - catches undefined order behavior like `a = a++`
-    # -Wsign-compare - catches comparison of signed and unsigned types
-    # -Wtrigraphs - catches unlikely use of trigraphs
     # -Wtype-limits - catches overflow bugs, few false positives
-    # -Wunknown-pragmas - catches unexpected #pragma directives
-    #
     _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wall"
     _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wempty-body"
-    _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wpointer-to-int-cast"
-    _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wsign-compare"
+    _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wignored-qualifiers"
+    _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wpointer-arith"
     _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wtype-limits"
 
-    # Treat some warnings as errors if --enable-warnings-as-errors:
+    # -Wnon-literal-null-conversion - catches expressions used as a null pointer constant
+    # -Wsometimes-initialized - catches some uninitialized values
+    #
+    # XXX: at the time of writing, the version of clang used on the OS X test
+    # machines has a bug that causes it to reject some valid files if both
+    # -Wnon-literal-null-conversion and -Wsometimes-uninitialized are
+    # specified. We work around this by instead using
+    # -Werror=non-literal-null-conversion, but we only do that when
+    # --enable-warnings-as-errors is specified so that no unexpected fatal
+    # warnings are produced.
     if test "$MOZ_ENABLE_WARNINGS_AS_ERRORS"; then
-        _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=char-subscripts"
-        _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=comment"
-        _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=endif-labels"
-        _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=enum-compare"
-        _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=ignored-qualifiers"
-        _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=int-to-pointer-cast"
-        _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=multichar"
-        _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=nonnull"
-        _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=pointer-arith"
-        _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=pointer-sign"
-        _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=return-type"
-        _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=sequence-point"
-        _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=trigraphs"
-        _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=uninitialized"
-        _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=unknown-pragmas"
-
-        MOZ_C_SUPPORTS_WARNING(-Werror=, non-literal-null-conversion, ac_c_has_werror_non_literal_null_conversion)
-        MOZ_C_SUPPORTS_WARNING(-Werror=, sometimes-uninitialized, ac_c_has_sometimes_uninitialized)
-    fi
-
-    # Turn off the following warnings that -Wall turns on:
-    # -Wno-unused - lots of violations in third-party code
-    # -Wno-unused-local-typedef - catches unused typedefs, which are commonly used in assertion macros
-    #
-    _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wno-unused"
-
-    MOZ_CXX_SUPPORTS_WARNING(-Wno-, unused-local-typedef, ac_cxx_has_wno_unused_local_typedef)
-
+        MOZ_C_SUPPORTS_WARNING(-Werror=, non-literal-null-conversion, ac_c_has_non_literal_null_conversion)
+    fi
+    MOZ_C_SUPPORTS_WARNING(-W, sometimes-uninitialized, ac_c_has_sometimes_uninitialized)
+
+    # -Wcast-align - catches problems with cast alignment
     if test -z "$INTEL_CC" -a -z "$CLANG_CC"; then
        # Don't use -Wcast-align with ICC or clang
        case "$CPU_ARCH" in
            # And don't use it on hppa, ia64, sparc, arm, since it's noisy there
            hppa | ia64 | sparc | arm)
            ;;
            *)
         _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wcast-align"
            ;;
        esac
     fi
 
+    # Turn off some non-useful warnings that -Wall turns on.
+
+    # -Wno-unused - lots of violations in third-party code
+    _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wno-unused"
+
+    # -Wno-unused-local-typedef - catches unused typedefs, which are commonly used in assertion macros
+    MOZ_C_SUPPORTS_WARNING(-Wno-, unused-local-typedef, ac_c_has_wno_unused_local_typedef)
+
     _DEFINES_CFLAGS='-include $(topobjdir)/mozilla-config.h -DMOZILLA_CLIENT'
     _USE_CPP_INCLUDE_FLAG=1
+
     ASFLAGS="$ASFLAGS $_DEFINES_CFLAGS"
 
 elif test "$SOLARIS_SUNPRO_CC"; then
     DSO_CFLAGS=''
     if test "$CPU_ARCH" = "sparc"; then
         # for Sun Studio on Solaris/SPARC
         DSO_PIC_CFLAGS='-xcode=pic32'
     else
@@ -1543,101 +1522,83 @@ else
     _DEFINES_CFLAGS='$(ACDEFINES) -D_MOZILLA_CONFIG_H_ -DMOZILLA_CLIENT'
 fi
 
 if test "$GNU_CXX"; then
     # FIXME: Let us build with strict aliasing. bug 414641.
     CXXFLAGS="$CXXFLAGS -fno-exceptions -fno-strict-aliasing"
 
     # Turn on gcc/clang warnings:
-    # https://gcc.gnu.org/onlinedocs/gcc-4.4.0/gcc/Warning-Options.html
-    #
-    # -Wall - turn on a lot of warnings
+    # https://gcc.gnu.org/onlinedocs/gcc-4.7.2/gcc/Warning-Options.html
+
+    # -Wall - lots of useful warnings
     # -Wempty-body - catches bugs, e.g. "if (c); foo();", few false positives
-    # -Wendif-labels - catches `#else FOO` and `#endif FOO` not in comment
-    # -Wint-to-pointer-cast - catches cast to pointer from integer of different size
-    # -Wmissing-braces - catches aggregate initializers missing nested braces
-    # -Wnon-literal-null-conversion - catches expressions used as a null pointer constant
     # -Woverloaded-virtual - function declaration hides virtual function from base class
-    # -Wparentheses - catches `if (a=b)` and operator precedence bugs
     # -Wpointer-arith - catches pointer arithmetic using NULL or sizeof(void)
-    # -Wrange-loop-analysis - catches copies during range-based for loops.
-    # -Wreturn-type - catches missing returns, zero false positives
-    # -Wsequence-point - catches undefined order behavior like `a = a++`
-    # -Wsign-compare - catches comparison of signed and unsigned types
-    # -Wswitch - catches switches without all enum cases or default case
-    # -Wtrigraphs - catches unlikely use of trigraphs
     # -Wtype-limits - catches overflow bugs, few false positives
-    # -Wunused-label - catches unused goto labels
-    # -Wwrite-strings - catches non-const char* pointers to string literals
-    #
     _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wall"
     _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wempty-body"
     _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Woverloaded-virtual"
-    _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wsign-compare"
-    _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wwrite-strings"
-
-    # Treat some warnings as errors if --enable-warnings-as-errors:
+    _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wpointer-arith"
+    _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wtype-limits"
+
+    # -Wnon-literal-null-conversion - catches expressions used as a null pointer constant
+    # -Wrange-loop-analysis - catches copies during range-based for loops.
+    # -Wsometimes-initialized - catches some uninitialized values
+    #
+    # XXX: at the time of writing, the version of clang used on the OS X test
+    # machines has a bug that causes it to reject some valid files if both
+    # -Wnon-literal-null-conversion and -Wsometimes-uninitialized are
+    # specified. We work around this by instead using
+    # -Werror=non-literal-null-conversion, but we only do that when
+    # --enable-warnings-as-errors is specified so that no unexpected fatal
+    # warnings are produced.
     if test "$MOZ_ENABLE_WARNINGS_AS_ERRORS"; then
-        _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=endif-labels"
-        _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=int-to-pointer-cast"
-        _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=missing-braces"
-        _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=parentheses"
-        _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=pointer-arith"
-        _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=return-type"
-        _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=sequence-point"
-        _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=switch"
-        _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=trigraphs"
-        _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=type-limits"
-        _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=uninitialized"
-        _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=unused-label"
-
-        MOZ_CXX_SUPPORTS_WARNING(-Werror=, non-literal-null-conversion, ac_cxx_has_werror_non_literal_null_conversion)
-        MOZ_CXX_SUPPORTS_WARNING(-Werror=, range-loop-analysis, ac_cxx_has_range_loop_analysis)
-        MOZ_CXX_SUPPORTS_WARNING(-Werror=, sometimes-uninitialized, ac_cxx_has_sometimes_uninitialized)
-    fi
-
-    # Turn off the following warnings that -Wall turns on:
-    # -Wno-invalid-offsetof - we use offsetof on non-POD types frequently
-    # -Wno-inline-new-delete - we inline 'new' and 'delete' in mozalloc
-    # -Wno-unused-local-typedef - catches unused typedefs, which are commonly used in assertion macros
-    #   for performance reasons, and because GCC and clang accept it (though
-    #   clang warns about it).
-    #
-    _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wno-invalid-offsetof"
-
-    MOZ_CXX_SUPPORTS_WARNING(-Wno-, inline-new-delete, ac_cxx_has_wno_inline_new_delete)
-    MOZ_CXX_SUPPORTS_WARNING(-Wno-, unused-local-typedef, ac_cxx_has_wno_unused_local_typedef)
-
+        MOZ_CXX_SUPPORTS_WARNING(-Werror=, non-literal-null-conversion, ac_cxx_has_non_literal_null_conversion)
+    fi
+    MOZ_CXX_SUPPORTS_WARNING(-W, range-loop-analysis, ac_cxx_has_range_loop_analysis)
+    MOZ_CXX_SUPPORTS_WARNING(-W, sometimes-uninitialized, ac_cxx_has_sometimes_uninitialized)
+
+    # -Wcast-align - catches problems with cast alignment
     if test -z "$INTEL_CXX" -a -z "$CLANG_CXX"; then
        # Don't use -Wcast-align with ICC or clang
        case "$CPU_ARCH" in
            # And don't use it on hppa, ia64, sparc, arm, since it's noisy there
            hppa | ia64 | sparc | arm)
            ;;
            *)
         _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wcast-align"
            ;;
        esac
     fi
 
-    _DEFINES_CXXFLAGS='-DMOZILLA_CLIENT -include $(topobjdir)/mozilla-config.h'
-    _USE_CPP_INCLUDE_FLAG=1
+    # Turn off some non-useful warnings that -Wall turns on.
+
+    # -Wno-invalid-offsetof - we use offsetof on non-POD types frequently
+    _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wno-invalid-offsetof"
+
+    # -Wno-inline-new-delete - we inline 'new' and 'delete' in mozalloc
+    # -Wno-unused-local-typedef - catches unused typedefs, which are commonly used in assertion macros
+    MOZ_CXX_SUPPORTS_WARNING(-Wno-, inline-new-delete, ac_cxx_has_wno_inline_new_delete)
+    MOZ_CXX_SUPPORTS_WARNING(-Wno-, unused-local-typedef, ac_cxx_has_wno_unused_local_typedef)
 
     # Recent clang and gcc support C++11 deleted functions without warnings if
     # compiling with -std=c++0x or -std=gnu++0x (or c++11 or gnu++11 in very new
     # versions).  We can't use -std=c++0x yet, so gcc's support must remain
     # unused.  But clang's warning can be disabled, so when compiling with clang
     # we use it to opt out of the warning, enabling (macro-encapsulated) use of
     # deleted function syntax.
     if test "$CLANG_CXX"; then
         _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wno-c++0x-extensions"
         MOZ_CXX_SUPPORTS_WARNING(-Wno-, extended-offsetof, ac_cxx_has_wno_extended_offsetof)
     fi
 
+    _DEFINES_CXXFLAGS='-DMOZILLA_CLIENT -include $(topobjdir)/mozilla-config.h'
+    _USE_CPP_INCLUDE_FLAG=1
+
 else
     _DEFINES_CXXFLAGS='-DMOZILLA_CLIENT -D_MOZILLA_CONFIG_H_ $(ACDEFINES)'
 fi
 
 dnl ========================================================
 dnl Checking for 64-bit OS
 dnl ========================================================
 if test "$COMPILE_ENVIRONMENT"; then
@@ -3001,17 +2962,17 @@ then
     MOZ_CHECK_HEADERS(pthread.h)
 fi
 
 
 dnl Checks for library functions.
 dnl ========================================================
 AC_PROG_GCC_TRADITIONAL
 AC_FUNC_MEMCMP
-AC_CHECK_FUNCS(stat64 lstat64 truncate64 statvfs64 statvfs statfs64 statfs getpagesize gmtime_r localtime_r arc4random arc4random_buf)
+AC_CHECK_FUNCS(stat64 lstat64 truncate64 statvfs64 statvfs statfs64 statfs getpagesize gmtime_r localtime_r arc4random arc4random_buf mallinfo)
 
 dnl check for clock_gettime(), the CLOCK_MONOTONIC clock
 AC_CACHE_CHECK(for clock_gettime(CLOCK_MONOTONIC),
                ac_cv_clock_monotonic,
                [for libs in "" -lrt; do
                     _SAVE_LIBS="$LIBS"
                     LIBS="$LIBS $libs"
                     AC_TRY_LINK([#include <time.h>],
new file mode 100644
--- /dev/null
+++ b/dom/canvas/crashtests/1233613.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<iframe style="display:none" srcdoc="
+
+<html>
+<head>
+<script type='text/javascript'>
+function boom() {
+    var gl = canvas.getContext('experimental-webgl');
+    video.srcObject = canvas.captureStream(0);
+}
+</script>
+</head>
+<body onload='boom();'>
+    <video id='video' width='256' height='256'></video>
+    <canvas id='canvas' width='256' height='256'></canvas>
+</body>
+</html>
+
+"></iframe>
--- a/dom/canvas/crashtests/crashtests.list
+++ b/dom/canvas/crashtests/crashtests.list
@@ -21,9 +21,10 @@ load 916128-1.html
 load 934939-1.html
 load 1099143-1.html
 load 1161277-1.html
 load 1183363.html
 load 1190705.html
 load 1223740-1.html
 load 1225381-1.html
 load 1229932-1.html
+load 1233613.html
 load texImage2D.html
--- a/dom/html/HTMLCanvasElement.cpp
+++ b/dom/html/HTMLCanvasElement.cpp
@@ -678,17 +678,23 @@ HTMLCanvasElement::CaptureStream(const O
   TrackID videoTrackId = 1;
   nsresult rv = stream->Init(aFrameRate, videoTrackId);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return nullptr;
   }
 
   stream->CreateOwnDOMTrack(videoTrackId, MediaSegment::VIDEO);
-  RegisterFrameCaptureListener(stream->FrameCaptureListener());
+
+  rv = RegisterFrameCaptureListener(stream->FrameCaptureListener());
+  if (NS_FAILED(rv)) {
+    aRv.Throw(rv);
+    return nullptr;
+  }
+
   return stream.forget();
 }
 
 nsresult
 HTMLCanvasElement::ExtractData(nsAString& aType,
                                const nsAString& aOptions,
                                nsIInputStream** aStream)
 {
@@ -1123,48 +1129,62 @@ HTMLCanvasElement::MarkContextCleanForFr
 }
 
 bool
 HTMLCanvasElement::IsContextCleanForFrameCapture()
 {
   return mCurrentContext && mCurrentContext->IsContextCleanForFrameCapture();
 }
 
-void
+nsresult
 HTMLCanvasElement::RegisterFrameCaptureListener(FrameCaptureListener* aListener)
 {
   WeakPtr<FrameCaptureListener> listener = aListener;
 
   if (mRequestedFrameListeners.Contains(listener)) {
-    return;
+    return NS_OK;
   }
 
-  mRequestedFrameListeners.AppendElement(listener);
-
   if (!mRequestedFrameRefreshObserver) {
     nsIDocument* doc = OwnerDoc();
-    MOZ_RELEASE_ASSERT(doc);
+    if (!doc) {
+      return NS_ERROR_FAILURE;
+    }
+
+    while (doc->GetParentDocument()) {
+      doc = doc->GetParentDocument();
+    }
 
     nsIPresShell* shell = doc->GetShell();
-    MOZ_RELEASE_ASSERT(shell);
+    if (!shell) {
+      return NS_ERROR_FAILURE;
+    }
 
     nsPresContext* context = shell->GetPresContext();
-    MOZ_RELEASE_ASSERT(context);
+    if (!context) {
+      return NS_ERROR_FAILURE;
+    }
 
     context = context->GetRootPresContext();
-    MOZ_RELEASE_ASSERT(context);
+    if (!context) {
+      return NS_ERROR_FAILURE;
+    }
 
     nsRefreshDriver* driver = context->RefreshDriver();
-    MOZ_RELEASE_ASSERT(driver);
+    if (!driver) {
+      return NS_ERROR_FAILURE;
+    }
 
     mRequestedFrameRefreshObserver =
       new RequestedFrameRefreshObserver(this, driver);
   }
 
+  mRequestedFrameListeners.AppendElement(listener);
   mRequestedFrameRefreshObserver->Register();
+  return NS_OK;
 }
 
 bool
 HTMLCanvasElement::IsFrameCaptureRequested() const
 {
   for (WeakPtr<FrameCaptureListener> listener : mRequestedFrameListeners) {
     if (!listener) {
       continue;
--- a/dom/html/HTMLCanvasElement.h
+++ b/dom/html/HTMLCanvasElement.h
@@ -261,17 +261,17 @@ public:
   /*
    * Register a FrameCaptureListener with this canvas.
    * The canvas hooks into the RefreshDriver while there are
    * FrameCaptureListeners registered.
    * The registered FrameCaptureListeners are stored as WeakPtrs, thus it's the
    * caller's responsibility to keep them alive. Once a registered
    * FrameCaptureListener is destroyed it will be automatically deregistered.
    */
-  void RegisterFrameCaptureListener(FrameCaptureListener* aListener);
+  nsresult RegisterFrameCaptureListener(FrameCaptureListener* aListener);
 
   /*
    * Returns true when there is at least one registered FrameCaptureListener
    * that has requested a frame capture.
    */
   bool IsFrameCaptureRequested() const;
 
   /*
--- a/dom/media/test/manifest.js
+++ b/dom/media/test/manifest.js
@@ -1555,9 +1555,13 @@ function setMediaTestsPrefs(callback, ex
   SpecialPowers.pushPrefEnv({"set": prefs}, callback);
 }
 
 // B2G emulator and Android 2.3 are condidered slow platforms
 function isSlowPlatform() {
   return SpecialPowers.Services.appinfo.name == "B2G" || getAndroidVersion() == 10;
 }
 
-SimpleTest.requestFlakyTimeout("untriaged");
+// Could be undefined in a page opened by the parent test page
+// like file_access_controls.html.
+if ("SimpleTest" in window) {
+  SimpleTest.requestFlakyTimeout("untriaged");
+}
--- a/gfx/layers/client/ClientLayerManager.cpp
+++ b/gfx/layers/client/ClientLayerManager.cpp
@@ -185,17 +185,16 @@ ClientLayerManager::BeginTransactionWith
   MOZ_LAYERS_LOG(("[----- BeginTransaction"));
   Log();
 #endif
 
   NS_ASSERTION(!InTransaction(), "Nested transactions not allowed");
   mPhase = PHASE_CONSTRUCTION;
 
   MOZ_ASSERT(mKeepAlive.IsEmpty(), "uncommitted txn?");
-  RefPtr<gfxContext> targetContext = aTarget;
 
   // If the last transaction was incomplete (a failed DoEmptyTransaction),
   // don't signal a new transaction to ShadowLayerForwarder. Carry on adding
   // to the previous transaction.
   dom::ScreenOrientationInternal orientation;
   if (dom::TabChild* window = mWidget->GetOwningTabChild()) {
     orientation = window->GetOrientation();
   } else {
--- a/gfx/layers/client/TiledContentClient.cpp
+++ b/gfx/layers/client/TiledContentClient.cpp
@@ -51,17 +51,17 @@ static void DrawDebugOverlay(mozilla::gf
   c.Stroke();
 
   // Build tile description
   std::stringstream ss;
   ss << x << ", " << y;
 
   // Draw text using cairo toy text API
   // XXX: this drawing will silently fail if |dt| doesn't have a Cairo backend
-  cairo_t* cr = gfxContext::RefCairo(dt);
+  cairo_t* cr = gfxFont::RefCairo(dt);
   cairo_set_font_size(cr, 25);
   cairo_text_extents_t extents;
   cairo_text_extents(cr, ss.str().c_str(), &extents);
 
   int textWidth = extents.width + 6;
 
   c.NewPath();
   c.SetDeviceColor(Color(0.f, 0.f, 0.f));
@@ -1323,18 +1323,16 @@ ClientMultiTiledLayerBuffer::ValidateTil
   MOZ_ASSERT(!backBufferOnWhite, "Component alpha only supported with TiledDrawTarget");
 
   // We must not keep a reference to the DrawTarget after it has been unlocked,
   // make sure these are null'd before unlocking as destruction of the context
   // may cause the target to be flushed.
   RefPtr<DrawTarget> drawTarget = backBuffer->BorrowDrawTarget();
   drawTarget->SetTransform(Matrix());
 
-  RefPtr<gfxContext> ctxt = new gfxContext(drawTarget);
-
   // XXX Perhaps we should just copy the bounding rectangle here?
   RefPtr<gfx::SourceSurface> source = mSinglePaintDrawTarget->Snapshot();
   nsIntRegionRectIterator it(aDirtyRegion);
   for (const IntRect* dirtyRect = it.Next(); dirtyRect != nullptr; dirtyRect = it.Next()) {
 #ifdef GFX_TILEDLAYER_PREF_WARNINGS
     printf_stderr(" break into subdirtyRect %i, %i, %i, %i\n",
                   dirtyRect->x, dirtyRect->y, dirtyRect->width, dirtyRect->height);
 #endif
@@ -1358,17 +1356,16 @@ ClientMultiTiledLayerBuffer::ValidateTil
   // The new buffer is now validated, remove the dirty region from it.
   aTile.mInvalidBack.SubOut(offsetScaledDirtyRegion);
 
 #ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
   DrawDebugOverlay(drawTarget, aTileOrigin.x * mResolution,
                    aTileOrigin.y * GetPresShellResolution(), GetTileLength(), GetTileLength());
 #endif
 
-  ctxt = nullptr;
   drawTarget = nullptr;
 
   nsIntRegion tileRegion =
     IntRect(aTileOrigin.x, aTileOrigin.y,
               GetScaledTileSize().width, GetScaledTileSize().height);
   // Intersect this area with the portion that's invalid.
   tileRegion.SubOut(GetValidRegion());
   tileRegion.SubOut(aDirtyRegion); // Has now been validated
--- a/gfx/thebes/gfxContext.cpp
+++ b/gfx/thebes/gfxContext.cpp
@@ -124,50 +124,16 @@ gfxContext::CurrentSurface(gfxFloat *dx,
 
   if (dx && dy) {
     *dx = *dy = 0;
   }
   // An Azure context doesn't have a surface backing it.
   return nullptr;
 }
 
-static void
-DestroyRefCairo(void* aData)
-{
-  cairo_t* refCairo = static_cast<cairo_t*>(aData);
-  MOZ_ASSERT(refCairo);
-  cairo_destroy(refCairo);
-}
-
-/* static */ cairo_t *
-gfxContext::RefCairo(DrawTarget* aDT)
-{
-  // DrawTargets that don't use a Cairo backend can be given a 1x1 "reference"
-  // |cairo_t*|, stored in the DrawTarget's user data, for doing font-related
-  // operations.
-  static UserDataKey sRefCairo;
-
-  cairo_t* refCairo = nullptr;
-  if (aDT->GetBackendType() == BackendType::CAIRO) {
-    refCairo = static_cast<cairo_t*>
-      (aDT->GetNativeSurface(NativeSurfaceType::CAIRO_CONTEXT));
-    if (refCairo) {
-      return refCairo;
-    }
-  }
-
-  refCairo = static_cast<cairo_t*>(aDT->GetUserData(&sRefCairo));
-  if (!refCairo) {
-    refCairo = cairo_create(gfxPlatform::GetPlatform()->ScreenReferenceSurface()->CairoSurface());
-    aDT->AddUserData(&sRefCairo, refCairo, DestroyRefCairo);
-  }
-
-  return refCairo;
-}
-
 void
 gfxContext::Save()
 {
   CurrentState().transform = mTransform;
   mStateStack.AppendElement(AzureState(CurrentState()));
   CurrentState().pushedClips.Clear();
 }
 
@@ -1291,91 +1257,8 @@ gfxContext::PushNewDT(gfxContentType con
   Save();
 
   CurrentState().drawTarget = newDT;
   CurrentState().deviceOffset = clipBounds.TopLeft();
 
   mDT = newDT;
 }
 
-/**
- * Work out whether cairo will snap inter-glyph spacing to pixels.
- *
- * Layout does not align text to pixel boundaries, so, with font drawing
- * backends that snap glyph positions to pixels, it is important that
- * inter-glyph spacing within words is always an integer number of pixels.
- * This ensures that the drawing backend snaps all of the word's glyphs in the
- * same direction and so inter-glyph spacing remains the same.
- */
-void
-gfxContext::GetRoundOffsetsToPixels(bool *aRoundX, bool *aRoundY)
-{
-    *aRoundX = false;
-    // Could do something fancy here for ScaleFactors of
-    // AxisAlignedTransforms, but we leave things simple.
-    // Not much point rounding if a matrix will mess things up anyway.
-    // Also return false for non-cairo contexts.
-    if (CurrentMatrix().HasNonTranslation()) {
-        *aRoundY = false;
-        return;
-    }
-
-    // All raster backends snap glyphs to pixels vertically.
-    // Print backends set CAIRO_HINT_METRICS_OFF.
-    *aRoundY = true;
-
-    cairo_t *cr = gfxContext::RefCairo(GetDrawTarget());
-    cairo_scaled_font_t *scaled_font = cairo_get_scaled_font(cr);
-
-    // bug 1198921 - this sometimes fails under Windows for whatver reason
-    NS_ASSERTION(scaled_font, "null cairo scaled font should never be returned "
-                 "by cairo_get_scaled_font");
-    if (!scaled_font) {
-        *aRoundX = true; // default to the same as the fallback path below
-        return;
-    }
-
-    // Sometimes hint metrics gets set for us, most notably for printing.
-    cairo_font_options_t *font_options = cairo_font_options_create();
-    cairo_scaled_font_get_font_options(scaled_font, font_options);
-    cairo_hint_metrics_t hint_metrics =
-        cairo_font_options_get_hint_metrics(font_options);
-    cairo_font_options_destroy(font_options);
-
-    switch (hint_metrics) {
-    case CAIRO_HINT_METRICS_OFF:
-        *aRoundY = false;
-        return;
-    case CAIRO_HINT_METRICS_DEFAULT:
-        // Here we mimic what cairo surface/font backends do.  Printing
-        // surfaces have already been handled by hint_metrics.  The
-        // fallback show_glyphs implementation composites pixel-aligned
-        // glyph surfaces, so we just pick surface/font combinations that
-        // override this.
-        switch (cairo_scaled_font_get_type(scaled_font)) {
-#if CAIRO_HAS_DWRITE_FONT // dwrite backend is not in std cairo releases yet
-        case CAIRO_FONT_TYPE_DWRITE:
-            // show_glyphs is implemented on the font and so is used for
-            // all surface types; however, it may pixel-snap depending on
-            // the dwrite rendering mode
-            if (!cairo_dwrite_scaled_font_get_force_GDI_classic(scaled_font) &&
-                gfxWindowsPlatform::GetPlatform()->DWriteMeasuringMode() ==
-                    DWRITE_MEASURING_MODE_NATURAL) {
-                return;
-            }
-            MOZ_FALLTHROUGH;
-#endif
-        case CAIRO_FONT_TYPE_QUARTZ:
-            // Quartz surfaces implement show_glyphs for Quartz fonts
-            if (cairo_surface_get_type(cairo_get_target(cr)) ==
-                CAIRO_SURFACE_TYPE_QUARTZ) {
-                return;
-            }
-            break;
-        default:
-            break;
-        }
-        break;
-    case CAIRO_HINT_METRICS_ON:
-        break;
-    }
-    *aRoundX = true;
-}
--- a/gfx/thebes/gfxContext.h
+++ b/gfx/thebes/gfxContext.h
@@ -80,22 +80,16 @@ public:
      * active, returns the surface the gfxContext was created with,
      * and 0,0 in dx,dy.
      */
     already_AddRefed<gfxASurface> CurrentSurface(gfxFloat *dx, gfxFloat *dy);
     already_AddRefed<gfxASurface> CurrentSurface() {
         return CurrentSurface(nullptr, nullptr);
     }
 
-    /**
-     * Return the reference cairo_t object from aDT.
-     * XXX this should be moved into gfxFont at some point.
-     */
-    static cairo_t* RefCairo(mozilla::gfx::DrawTarget* aDT);
-
     mozilla::gfx::DrawTarget *GetDrawTarget() { return mDT; }
 
     /**
      ** State
      **/
     // XXX document exactly what bits are saved
     void Save();
     void Restore();
@@ -440,19 +434,16 @@ public:
     void PushGroupAndCopyBackground(gfxContentType content = gfxContentType::COLOR,
                                     mozilla::gfx::Float aOpacity = 1.0f,
                                     mozilla::gfx::SourceSurface* aMask = nullptr,
                                     const mozilla::gfx::Matrix& aMaskTransform = mozilla::gfx::Matrix());
     void PopGroupAndBlend();
 
     mozilla::gfx::Point GetDeviceOffset() const;
 
-    // Work out whether cairo will snap inter-glyph spacing to pixels.
-    void GetRoundOffsetsToPixels(bool *aRoundX, bool *aRoundY);
-
 #ifdef MOZ_DUMP_PAINTING
     /**
      * Debug functions to encode the current surface as a PNG and export it.
      */
 
     /**
      * Writes a binary PNG file.
      */
--- a/gfx/thebes/gfxDWriteFonts.cpp
+++ b/gfx/thebes/gfxDWriteFonts.cpp
@@ -449,26 +449,25 @@ gfxDWriteFont::HasBitmapStrikeForSize(ui
 
 uint32_t
 gfxDWriteFont::GetSpaceGlyph()
 {
     return mSpaceGlyph;
 }
 
 bool
-gfxDWriteFont::SetupCairoFont(gfxContext *aContext)
+gfxDWriteFont::SetupCairoFont(DrawTarget* aDrawTarget)
 {
     cairo_scaled_font_t *scaledFont = GetCairoScaledFont();
     if (cairo_scaled_font_status(scaledFont) != CAIRO_STATUS_SUCCESS) {
         // Don't cairo_set_scaled_font as that would propagate the error to
         // the cairo_t, precluding any further drawing.
         return false;
     }
-    cairo_set_scaled_font(gfxContext::RefCairo(aContext->GetDrawTarget()),
-                          scaledFont);
+    cairo_set_scaled_font(gfxFont::RefCairo(aDrawTarget), scaledFont);
     return true;
 }
 
 bool
 gfxDWriteFont::IsValid() const
 {
     return mFontFace != nullptr;
 }
--- a/gfx/thebes/gfxDWriteFonts.h
+++ b/gfx/thebes/gfxDWriteFonts.h
@@ -28,17 +28,17 @@ public:
                   AntialiasOption = kAntialiasDefault);
     ~gfxDWriteFont();
 
     virtual gfxFont*
     CopyWithAntialiasOption(AntialiasOption anAAOption) override;
 
     virtual uint32_t GetSpaceGlyph() override;
 
-    virtual bool SetupCairoFont(gfxContext *aContext) override;
+    virtual bool SetupCairoFont(DrawTarget* aDrawTarget) override;
 
     virtual bool AllowSubpixelAA() override
     { return mAllowManualShowGlyphs; }
 
     bool IsValid() const;
 
     virtual gfxFloat GetAdjustedSize() const override {
         return mAdjustedSize;
--- a/gfx/thebes/gfxFT2FontBase.cpp
+++ b/gfx/thebes/gfxFT2FontBase.cpp
@@ -171,17 +171,17 @@ gfxFT2FontBase::GetGlyphWidth(DrawTarget
 {
     cairo_text_extents_t extents;
     GetGlyphExtents(aGID, &extents);
     // convert to 16.16 fixed point
     return NS_lround(0x10000 * extents.x_advance);
 }
 
 bool
-gfxFT2FontBase::SetupCairoFont(gfxContext *aContext)
+gfxFT2FontBase::SetupCairoFont(DrawTarget* aDrawTarget)
 {
     // The scaled font ctm is not relevant right here because
     // cairo_set_scaled_font does not record the scaled font itself, but
     // merely the font_face, font_matrix, font_options.  The scaled_font used
     // for the target can be different from the scaled_font passed to
     // cairo_set_scaled_font.  (Unfortunately we have measured only for an
     // identity ctm.)
     cairo_scaled_font_t *cairoFont = CairoScaledFont();
@@ -205,12 +205,11 @@ gfxFT2FontBase::SetupCairoFont(gfxContex
     // scaled_font that was used to measure.  As the same font_face is being
     // used, its font_options will often override some values anyway (unless
     // perhaps we remove those from the FcPattern at face creation).
     //
     // I can't see any significant difference in printing, irrespective of
     // what is set here.  It's too late to change things here as measuring has
     // already taken place.  We should really be measuring with a different
     // font for pdf and ps surfaces (bug 403513).
-    cairo_set_scaled_font(gfxContext::RefCairo(aContext->GetDrawTarget()),
-                          cairoFont);
+    cairo_set_scaled_font(gfxFont::RefCairo(aDrawTarget), cairoFont);
     return true;
 }
--- a/gfx/thebes/gfxFT2FontBase.h
+++ b/gfx/thebes/gfxFT2FontBase.h
@@ -25,17 +25,17 @@ public:
     virtual bool ProvidesGetGlyph() const override { return true; }
     virtual uint32_t GetGlyph(uint32_t unicode,
                               uint32_t variation_selector) override;
     virtual bool ProvidesGlyphWidths() const override { return true; }
     virtual int32_t GetGlyphWidth(DrawTarget& aDrawTarget,
                                   uint16_t aGID) override;
 
     cairo_scaled_font_t *CairoScaledFont() { return mScaledFont; };
-    virtual bool SetupCairoFont(gfxContext *aContext) override;
+    virtual bool SetupCairoFont(DrawTarget* aDrawTarget) override;
 
     virtual FontType GetType() const override { return FONT_TYPE_FT2; }
 
 protected:
     virtual const Metrics& GetHorizontalMetrics() override;
 
     uint32_t mSpaceGlyph;
     bool mHasMetrics;
--- a/gfx/thebes/gfxFT2Fonts.cpp
+++ b/gfx/thebes/gfxFT2Fonts.cpp
@@ -50,18 +50,18 @@ gfxFT2Font::ShapeText(gfxContext     *aC
                       int32_t         aScript,
                       bool            aVertical,
                       gfxShapedText  *aShapedText)
 {
     if (!gfxFont::ShapeText(aContext, aText, aOffset, aLength, aScript,
                             aVertical, aShapedText)) {
         // harfbuzz must have failed(?!), just render raw glyphs
         AddRange(aText, aOffset, aLength, aShapedText);
-        PostShapingFixup(aContext, aText, aOffset, aLength, aVertical,
-                         aShapedText);
+        PostShapingFixup(aContext->GetDrawTarget(), aText, aOffset, aLength,
+                         aVertical, aShapedText);
     }
 
     return true;
 }
 
 void
 gfxFT2Font::AddRange(const char16_t *aText, uint32_t aOffset,
                      uint32_t aLength, gfxShapedText *aShapedText)
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -544,16 +544,100 @@ gfxFontShaper::MergeFontFeatures(
 
     if (mergedFeatures.Count() != 0) {
         for (auto iter = mergedFeatures.Iter(); !iter.Done(); iter.Next()) {
             aHandleFeature(iter.Key(), iter.Data(), aHandleFeatureData);
         }
     }
 }
 
+// Work out whether cairo will snap inter-glyph spacing to pixels.
+//
+// Layout does not align text to pixel boundaries, so, with font drawing
+// backends that snap glyph positions to pixels, it is important that
+// inter-glyph spacing within words is always an integer number of pixels.
+// This ensures that the drawing backend snaps all of the word's glyphs in the
+// same direction and so inter-glyph spacing remains the same.
+//
+/* static */ void
+gfxFontShaper::GetRoundOffsetsToPixels(DrawTarget* aDrawTarget,
+                                       bool* aRoundX, bool* aRoundY)
+{
+    *aRoundX = false;
+    // Could do something fancy here for ScaleFactors of
+    // AxisAlignedTransforms, but we leave things simple.
+    // Not much point rounding if a matrix will mess things up anyway.
+    // Also return false for non-cairo contexts.
+    if (aDrawTarget->GetTransform().HasNonTranslation()) {
+        *aRoundY = false;
+        return;
+    }
+
+    // All raster backends snap glyphs to pixels vertically.
+    // Print backends set CAIRO_HINT_METRICS_OFF.
+    *aRoundY = true;
+
+    cairo_t* cr = gfxFont::RefCairo(aDrawTarget);
+    cairo_scaled_font_t *scaled_font = cairo_get_scaled_font(cr);
+
+    // bug 1198921 - this sometimes fails under Windows for whatver reason
+    NS_ASSERTION(scaled_font, "null cairo scaled font should never be returned "
+                 "by cairo_get_scaled_font");
+    if (!scaled_font) {
+        *aRoundX = true; // default to the same as the fallback path below
+        return;
+    }
+
+    // Sometimes hint metrics gets set for us, most notably for printing.
+    cairo_font_options_t *font_options = cairo_font_options_create();
+    cairo_scaled_font_get_font_options(scaled_font, font_options);
+    cairo_hint_metrics_t hint_metrics =
+        cairo_font_options_get_hint_metrics(font_options);
+    cairo_font_options_destroy(font_options);
+
+    switch (hint_metrics) {
+    case CAIRO_HINT_METRICS_OFF:
+        *aRoundY = false;
+        return;
+    case CAIRO_HINT_METRICS_DEFAULT:
+        // Here we mimic what cairo surface/font backends do.  Printing
+        // surfaces have already been handled by hint_metrics.  The
+        // fallback show_glyphs implementation composites pixel-aligned
+        // glyph surfaces, so we just pick surface/font combinations that
+        // override this.
+        switch (cairo_scaled_font_get_type(scaled_font)) {
+#if CAIRO_HAS_DWRITE_FONT // dwrite backend is not in std cairo releases yet
+        case CAIRO_FONT_TYPE_DWRITE:
+            // show_glyphs is implemented on the font and so is used for
+            // all surface types; however, it may pixel-snap depending on
+            // the dwrite rendering mode
+            if (!cairo_dwrite_scaled_font_get_force_GDI_classic(scaled_font) &&
+                gfxWindowsPlatform::GetPlatform()->DWriteMeasuringMode() ==
+                    DWRITE_MEASURING_MODE_NATURAL) {
+                return;
+            }
+            MOZ_FALLTHROUGH;
+#endif
+        case CAIRO_FONT_TYPE_QUARTZ:
+            // Quartz surfaces implement show_glyphs for Quartz fonts
+            if (cairo_surface_get_type(cairo_get_target(cr)) ==
+                CAIRO_SURFACE_TYPE_QUARTZ) {
+                return;
+            }
+            break;
+        default:
+            break;
+        }
+        break;
+    case CAIRO_HINT_METRICS_ON:
+        break;
+    }
+    *aRoundX = true;
+}
+
 void
 gfxShapedText::SetupClusterBoundaries(uint32_t        aOffset,
                                       const char16_t *aString,
                                       uint32_t        aLength)
 {
     CompressedGlyph *glyphs = GetCharacterGlyphs() + aOffset;
 
     gfxTextRun::CompressedGlyph extendCluster;
@@ -776,17 +860,17 @@ gfxFont::~gfxFont()
             it.Get()->GetKey()->ForgetFont();
         }
     }
 }
 
 gfxFloat
 gfxFont::GetGlyphHAdvance(gfxContext *aCtx, uint16_t aGID)
 {
-    if (!SetupCairoFont(aCtx)) {
+    if (!SetupCairoFont(aCtx->GetDrawTarget())) {
         return 0;
     }
     if (ProvidesGlyphWidths()) {
         return GetGlyphWidth(*aCtx->GetDrawTarget(), aGID) / 65536.0;
     }
     if (mFUnitsConvFactor < 0.0f) {
         GetMetrics(eHorizontal);
     }
@@ -1637,20 +1721,20 @@ private:
 
 // Bug 674909. When synthetic bolding text by drawing twice, need to
 // render using a pixel offset in device pixels, otherwise text
 // doesn't appear bolded, it appears as if a bad text shadow exists
 // when a non-identity transform exists.  Use an offset factor so that
 // the second draw occurs at a constant offset in device pixels.
 
 double
-gfxFont::CalcXScale(gfxContext *aContext)
+gfxFont::CalcXScale(DrawTarget* aDrawTarget)
 {
     // determine magnitude of a 1px x offset in device space
-    Size t = aContext->UserToDevice(Size(1.0, 0.0));
+    Size t = aDrawTarget->GetTransform() * Size(1.0, 0.0);
     if (t.width == 1.0 && t.height == 0.0) {
         // short-circuit the most common case to avoid sqrt() and division
         return 1.0;
     }
 
     double m = sqrt(t.width * t.width + t.height * t.height);
 
     NS_ASSERTION(m != 0.0, "degenerate transform while synthetic bolding");
@@ -1711,18 +1795,19 @@ gfxFont::DrawOneGlyph(uint32_t aGlyphID,
         if (RenderSVGGlyph(runParams.context, devPt, mode,
                            aGlyphID, fontParams.contextPaint,
                            runParams.callbacks, *aEmittedGlyphs)) {
             return;
         }
     }
 
     if (fontParams.haveColorGlyphs &&
-        RenderColorGlyph(runParams.context, fontParams.scaledFont,
-                         fontParams.renderingOptions, fontParams.drawOptions,
+        RenderColorGlyph(runParams.dt,
+                         fontParams.scaledFont, fontParams.renderingOptions,
+                         fontParams.drawOptions,
                          fontParams.matInv * gfx::Point(devPt.x, devPt.y),
                          aGlyphID)) {
         return;
     }
 
     aBuffer.OutputGlyph(aGlyphID, devPt);
 
     // Synthetic bolding (if required) by multi-striking.
@@ -1964,17 +2049,17 @@ gfxFont::Draw(gfxTextRun *aTextRun, uint
             new SimpleTextContextPaint(fillPattern, nullptr,
                                        aRunParams.context->CurrentMatrix());
         fontParams.contextPaint = contextPaint;
     }
 
     // Synthetic-bold strikes are each offset one device pixel in run direction.
     // (these values are only needed if IsSyntheticBold() is true)
     if (IsSyntheticBold()) {
-        double xscale = CalcXScale(aRunParams.context);
+        double xscale = CalcXScale(aRunParams.context->GetDrawTarget());
         fontParams.synBoldOnePixelOffset = aRunParams.direction * xscale;
         if (xscale != 0.0) {
             // use as many strikes as needed for the the increased advance
             fontParams.extraStrikes =
                 std::max(1, NS_lroundf(GetSyntheticBoldOffset() / xscale));
         }
     } else {
         fontParams.synBoldOnePixelOffset = 0;
@@ -2093,44 +2178,43 @@ gfxFont::RenderSVGGlyph(gfxContext *aCon
     if (aCallbacks && aEmittedGlyphs) {
         aCallbacks->NotifyGlyphPathEmitted();
         aEmittedGlyphs = false;
     }
     return RenderSVGGlyph(aContext, aPoint, aDrawMode, aGlyphId, aContextPaint);
 }
 
 bool
-gfxFont::RenderColorGlyph(gfxContext* aContext,
+gfxFont::RenderColorGlyph(DrawTarget* aDrawTarget,
                           mozilla::gfx::ScaledFont* scaledFont,
                           GlyphRenderingOptions* aRenderingOptions,
                           mozilla::gfx::DrawOptions aDrawOptions,
                           const mozilla::gfx::Point& aPoint,
                           uint32_t aGlyphId) const
 {
     nsAutoTArray<uint16_t, 8> layerGlyphs;
     nsAutoTArray<mozilla::gfx::Color, 8> layerColors;
 
     if (!GetFontEntry()->GetColorLayersInfo(aGlyphId, layerGlyphs, layerColors)) {
         return false;
     }
 
-    RefPtr<DrawTarget> dt = aContext->GetDrawTarget();
     for (uint32_t layerIndex = 0; layerIndex < layerGlyphs.Length();
          layerIndex++) {
         Glyph glyph;
         glyph.mIndex = layerGlyphs[layerIndex];
         glyph.mPosition = aPoint;
 
         mozilla::gfx::GlyphBuffer buffer;
         buffer.mGlyphs = &glyph;
         buffer.mNumGlyphs = 1;
 
-        dt->FillGlyphs(scaledFont, buffer,
-                       ColorPattern(layerColors[layerIndex]),
-                       aDrawOptions, aRenderingOptions);
+        aDrawTarget->FillGlyphs(scaledFont, buffer,
+                                ColorPattern(layerColors[layerIndex]),
+                                aDrawOptions, aRenderingOptions);
     }
     return true;
 }
 
 static void
 UnionRange(gfxFloat aX, gfxFloat* aDestMin, gfxFloat* aDestMax)
 {
     *aDestMin = std::min(*aDestMin, aX);
@@ -2572,36 +2656,36 @@ gfxFont::ShapeText(gfxContext      *aCon
             mHarfBuzzShaper = new gfxHarfBuzzShaper(this);
         }
         ok = mHarfBuzzShaper->ShapeText(aContext, aText, aOffset, aLength,
                                         aScript, aVertical, aShapedText);
     }
 
     NS_WARN_IF_FALSE(ok, "shaper failed, expect scrambled or missing text");
 
-    PostShapingFixup(aContext, aText, aOffset, aLength, aVertical,
-                     aShapedText);
+    PostShapingFixup(aContext->GetDrawTarget(), aText, aOffset, aLength,
+                     aVertical, aShapedText);
 
     return ok;
 }
 
 void
-gfxFont::PostShapingFixup(gfxContext      *aContext,
-                          const char16_t *aText,
-                          uint32_t         aOffset,
-                          uint32_t         aLength,
-                          bool             aVertical,
-                          gfxShapedText   *aShapedText)
+gfxFont::PostShapingFixup(DrawTarget*     aDrawTarget,
+                          const char16_t* aText,
+                          uint32_t        aOffset,
+                          uint32_t        aLength,
+                          bool            aVertical,
+                          gfxShapedText*  aShapedText)
 {
     if (IsSyntheticBold()) {
         const Metrics& metrics =
             GetMetrics(aVertical ? eVertical : eHorizontal);
         if (metrics.maxAdvance > metrics.aveCharWidth) {
             float synBoldOffset =
-                    GetSyntheticBoldOffset() * CalcXScale(aContext);
+                    GetSyntheticBoldOffset() * CalcXScale(aDrawTarget);
             aShapedText->AdjustAdvancesForSyntheticBold(synBoldOffset,
                                                         aOffset, aLength);
         }
     }
 }
 
 #define MAX_SHAPING_LENGTH  32760 // slightly less than 32K, trying to avoid
                                   // over-stressing platform shapers
@@ -3167,16 +3251,50 @@ gfxFont::GetSubSuperscriptFont(int32_t a
 {
     gfxFontStyle style(*GetStyle());
     style.AdjustForSubSuperscript(aAppUnitsPerDevPixel);
     gfxFontEntry* fe = GetFontEntry();
     bool needsBold = style.weight >= 600 && !fe->IsBold();
     return fe->FindOrMakeFont(&style, needsBold, mUnicodeRangeMap);
 }
 
+static void
+DestroyRefCairo(void* aData)
+{
+  cairo_t* refCairo = static_cast<cairo_t*>(aData);
+  MOZ_ASSERT(refCairo);
+  cairo_destroy(refCairo);
+}
+
+/* static */ cairo_t *
+gfxFont::RefCairo(DrawTarget* aDT)
+{
+  // DrawTargets that don't use a Cairo backend can be given a 1x1 "reference"
+  // |cairo_t*|, stored in the DrawTarget's user data, for doing font-related
+  // operations.
+  static UserDataKey sRefCairo;
+
+  cairo_t* refCairo = nullptr;
+  if (aDT->GetBackendType() == BackendType::CAIRO) {
+    refCairo = static_cast<cairo_t*>
+      (aDT->GetNativeSurface(NativeSurfaceType::CAIRO_CONTEXT));
+    if (refCairo) {
+      return refCairo;
+    }
+  }
+
+  refCairo = static_cast<cairo_t*>(aDT->GetUserData(&sRefCairo));
+  if (!refCairo) {
+    refCairo = cairo_create(gfxPlatform::GetPlatform()->ScreenReferenceSurface()->CairoSurface());
+    aDT->AddUserData(&sRefCairo, refCairo, DestroyRefCairo);
+  }
+
+  return refCairo;
+}
+
 gfxGlyphExtents *
 gfxFont::GetOrCreateGlyphExtents(int32_t aAppUnitsPerDevUnit) {
     uint32_t i, count = mGlyphExtentsArray.Length();
     for (i = 0; i < count; ++i) {
         if (mGlyphExtentsArray[i]->GetAppUnitsPerDevUnit() == aAppUnitsPerDevUnit)
             return mGlyphExtentsArray[i];
     }
     gfxGlyphExtents *glyphExtents = new gfxGlyphExtents(aAppUnitsPerDevUnit);
@@ -3185,42 +3303,37 @@ gfxFont::GetOrCreateGlyphExtents(int32_t
         // Initialize the extents of a space glyph, assuming that spaces don't
         // render anything!
         glyphExtents->SetContainedGlyphWidthAppUnits(GetSpaceGlyph(), 0);
     }
     return glyphExtents;
 }
 
 void
-gfxFont::SetupGlyphExtents(gfxContext *aContext,
-                           uint32_t aGlyphID, bool aNeedTight,
-                           gfxGlyphExtents *aExtents)
+gfxFont::SetupGlyphExtents(DrawTarget* aDrawTarget, uint32_t aGlyphID,
+                           bool aNeedTight, gfxGlyphExtents *aExtents)
 {
-    gfxContextMatrixAutoSaveRestore matrixRestore(aContext);
-    aContext->SetMatrix(gfxMatrix());
-
     gfxRect svgBounds;
     if (mFontEntry->TryGetSVGData(this) && mFontEntry->HasSVGGlyph(aGlyphID) &&
-        mFontEntry->GetSVGGlyphExtents(aContext, aGlyphID, &svgBounds)) {
+        mFontEntry->GetSVGGlyphExtents(aDrawTarget, aGlyphID, &svgBounds)) {
         gfxFloat d2a = aExtents->GetAppUnitsPerDevUnit();
         aExtents->SetTightGlyphExtents(aGlyphID,
                                        gfxRect(svgBounds.x * d2a,
                                                svgBounds.y * d2a,
                                                svgBounds.width * d2a,
                                                svgBounds.height * d2a));
         return;
     }
 
     cairo_glyph_t glyph;
     glyph.index = aGlyphID;
     glyph.x = 0;
     glyph.y = 0;
     cairo_text_extents_t extents;
-    cairo_glyph_extents(gfxContext::RefCairo(aContext->GetDrawTarget()),
-                        &glyph, 1, &extents);
+    cairo_glyph_extents(gfxFont::RefCairo(aDrawTarget), &glyph, 1, &extents);
 
     const Metrics& fontMetrics = GetMetrics(eHorizontal);
     int32_t appUnitsPerDevUnit = aExtents->GetAppUnitsPerDevUnit();
     if (!aNeedTight && extents.x_bearing >= 0 &&
         extents.y_bearing >= -fontMetrics.maxAscent &&
         extents.height + extents.y_bearing <= fontMetrics.maxDescent) {
         uint32_t appUnitsWidth =
             uint32_t(ceil((extents.x_bearing + extents.width)*appUnitsPerDevUnit));
--- a/gfx/thebes/gfxFont.h
+++ b/gfx/thebes/gfxFont.h
@@ -24,16 +24,17 @@
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/Attributes.h"
 #include <algorithm>
 #include "DrawMode.h"
 #include "nsDataHashtable.h"
 #include "harfbuzz/hb.h"
 #include "mozilla/gfx/2D.h"
 
+typedef struct _cairo cairo_t;
 typedef struct _cairo_scaled_font cairo_scaled_font_t;
 //typedef struct gr_face            gr_face;
 
 #ifdef DEBUG
 #include <stdio.h>
 #endif
 
 class gfxContext;
@@ -607,16 +608,18 @@ protected:
  * Platform-specific implementations designed to interface to platform
  * shaping APIs such as Uniscribe or CoreText may rely on features of a
  * specific font subclass to access native font references
  * (such as CTFont, HFONT, DWriteFont, etc).
  */
 
 class gfxFontShaper {
 public:
+    typedef mozilla::gfx::DrawTarget DrawTarget;
+
     explicit gfxFontShaper(gfxFont *aFont)
         : mFont(aFont)
     {
         NS_ASSERTION(aFont, "shaper requires a valid font!");
     }
 
     virtual ~gfxFontShaper() { }
 
@@ -639,16 +642,20 @@ public:
                       bool aDisableLigatures,
                       const nsAString& aFamilyName,
                       bool aAddSmallCaps,
                       void (*aHandleFeature)(const uint32_t&,
                                              uint32_t&, void*),
                       void* aHandleFeatureData);
 
 protected:
+    // Work out whether cairo will snap inter-glyph spacing to pixels.
+    static void GetRoundOffsetsToPixels(DrawTarget* aDrawTarget,
+                                        bool* aRoundX, bool* aRoundY);
+
     // the font this shaper is working with. The font owns a nsAutoPtr reference
     // to this object, and will destroy it before it dies. Thus, mFont will always
     // be valid.
     gfxFont* MOZ_NON_OWNING_REF mFont;
 };
 
 
 /*
@@ -1650,22 +1657,22 @@ public:
     // Expiration tracking
     nsExpirationState *GetExpirationState() { return &mExpirationState; }
 
     // Get the glyphID of a space
     virtual uint32_t GetSpaceGlyph() = 0;
 
     gfxGlyphExtents *GetOrCreateGlyphExtents(int32_t aAppUnitsPerDevUnit);
 
-    // You need to call SetupCairoFont on the aCR just before calling this
-    virtual void SetupGlyphExtents(gfxContext *aContext, uint32_t aGlyphID,
+    // You need to call SetupCairoFont on aDrawTarget just before calling this.
+    virtual void SetupGlyphExtents(DrawTarget* aDrawTarget, uint32_t aGlyphID,
                                    bool aNeedTight, gfxGlyphExtents *aExtents);
 
     // This is called by the default Draw() implementation above.
-    virtual bool SetupCairoFont(gfxContext *aContext) = 0;
+    virtual bool SetupCairoFont(DrawTarget* aDrawTarget) = 0;
 
     virtual bool AllowSubpixelAA() { return true; }
 
     bool IsSyntheticBold() { return mApplySyntheticBold; }
 
     // Amount by which synthetic bold "fattens" the glyphs:
     // For size S up to a threshold size T, we use (0.25 + 3S / 4T),
     // so that the result ranges from 0.25 to 1.0; thereafter,
@@ -1837,16 +1844,21 @@ public:
     {
         return mFontEntry->GetMathConstant(aConstant);
     }
 
     // return a cloned font resized and offset to simulate sub/superscript glyphs
     virtual already_AddRefed<gfxFont>
     GetSubSuperscriptFont(int32_t aAppUnitsPerDevPixel);
 
+    /**
+     * Return the reference cairo_t object from aDT.
+     */
+    static cairo_t* RefCairo(mozilla::gfx::DrawTarget* aDT);
+
 protected:
     virtual const Metrics& GetHorizontalMetrics() = 0;
 
     const Metrics* CreateVerticalMetrics();
 
     // Output a single glyph at *aPt, which is updated by the glyph's advance.
     // Normal glyphs are simply accumulated in aBuffer until it is full and
     // gets flushed, but SVG or color-font glyphs will instead be rendered
@@ -1921,22 +1933,22 @@ protected:
                            uint32_t         aLength,
                            int32_t          aScript,
                            bool             aVertical,
                            gfxShapedText   *aShapedText);
 
     // Helper to adjust for synthetic bold and set character-type flags
     // in the shaped text; implementations of ShapeText should call this
     // after glyph shaping has been completed.
-    void PostShapingFixup(gfxContext      *aContext,
-                          const char16_t *aText,
-                          uint32_t         aOffset, // position within aShapedText
-                          uint32_t         aLength,
-                          bool             aVertical,
-                          gfxShapedText   *aShapedText);
+    void PostShapingFixup(DrawTarget*     aContext,
+                          const char16_t* aText,
+                          uint32_t        aOffset, // position within aShapedText
+                          uint32_t        aLength,
+                          bool            aVertical,
+                          gfxShapedText*  aShapedText);
 
     // Shape text directly into a range within a textrun, without using the
     // font's word cache. Intended for use when the font has layout features
     // that involve space, and therefore require shaping complete runs rather
     // than isolated words, or for long strings that are inefficient to cache.
     // This will split the text on "invalid" characters (tab/newline) that are
     // not handled via normal shaping, but does not otherwise divide up the
     // text.
@@ -2120,31 +2132,31 @@ protected:
 
     bool RenderSVGGlyph(gfxContext *aContext, gfxPoint aPoint, DrawMode aDrawMode,
                         uint32_t aGlyphId, gfxTextContextPaint *aContextPaint) const;
     bool RenderSVGGlyph(gfxContext *aContext, gfxPoint aPoint, DrawMode aDrawMode,
                         uint32_t aGlyphId, gfxTextContextPaint *aContextPaint,
                         gfxTextRunDrawCallbacks *aCallbacks,
                         bool& aEmittedGlyphs) const;
 
-    bool RenderColorGlyph(gfxContext* aContext,
+    bool RenderColorGlyph(DrawTarget* aDrawTarget,
                           mozilla::gfx::ScaledFont* scaledFont,
                           mozilla::gfx::GlyphRenderingOptions* renderingOptions,
                           mozilla::gfx::DrawOptions drawOptions,
                           const mozilla::gfx::Point& aPoint,
                           uint32_t aGlyphId) const;
 
     // Bug 674909. When synthetic bolding text by drawing twice, need to
     // render using a pixel offset in device pixels, otherwise text
     // doesn't appear bolded, it appears as if a bad text shadow exists
     // when a non-identity transform exists.  Use an offset factor so that
     // the second draw occurs at a constant offset in device pixels.
     // This helper calculates the scale factor we need to apply to the
     // synthetic-bold offset.
-    static double CalcXScale(gfxContext *aContext);
+    static double CalcXScale(DrawTarget* aDrawTarget);
 };
 
 // proportion of ascent used for x-height, if unable to read value from font
 #define DEFAULT_XHEIGHT_FACTOR 0.56f
 
 // Parameters passed to gfxFont methods for drawing glyphs from a textrun.
 // The TextRunDrawParams are set up once per textrun; the FontDrawParams
 // are dependent on the specific font, so they are set per GlyphRun.
--- a/gfx/thebes/gfxFontEntry.cpp
+++ b/gfx/thebes/gfxFontEntry.cpp
@@ -328,27 +328,26 @@ gfxFontEntry::UnitsPerEm()
 bool
 gfxFontEntry::HasSVGGlyph(uint32_t aGlyphId)
 {
     NS_ASSERTION(mSVGInitialized, "SVG data has not yet been loaded. TryGetSVGData() first.");
     return mSVGGlyphs->HasSVGGlyph(aGlyphId);
 }
 
 bool
-gfxFontEntry::GetSVGGlyphExtents(gfxContext *aContext, uint32_t aGlyphId,
+gfxFontEntry::GetSVGGlyphExtents(DrawTarget* aDrawTarget, uint32_t aGlyphId,
                                  gfxRect *aResult)
 {
     MOZ_ASSERT(mSVGInitialized,
                "SVG data has not yet been loaded. TryGetSVGData() first.");
     MOZ_ASSERT(mUnitsPerEm >= kMinUPEM && mUnitsPerEm <= kMaxUPEM,
                "font has invalid unitsPerEm");
 
     cairo_matrix_t fontMatrix;
-    cairo_get_font_matrix(gfxContext::RefCairo(aContext->GetDrawTarget()),
-                          &fontMatrix);
+    cairo_get_font_matrix(gfxFont::RefCairo(aDrawTarget), &fontMatrix);
 
     gfxMatrix svgToAppSpace(fontMatrix.xx, fontMatrix.yx,
                             fontMatrix.xy, fontMatrix.yy,
                             fontMatrix.x0, fontMatrix.y0);
     svgToAppSpace.Scale(1.0f / mUnitsPerEm, 1.0f / mUnitsPerEm);
 
     return mSVGGlyphs->GetGlyphExtents(aGlyphId, svgToAppSpace, aResult);
 }
--- a/gfx/thebes/gfxFontEntry.h
+++ b/gfx/thebes/gfxFontEntry.h
@@ -92,16 +92,18 @@ protected:
 
 private:
     gfxCharacterMap(const gfxCharacterMap&);
     gfxCharacterMap& operator=(const gfxCharacterMap&);
 };
 
 class gfxFontEntry {
 public:
+    typedef mozilla::gfx::DrawTarget DrawTarget;
+
     NS_INLINE_DECL_REFCOUNTING(gfxFontEntry)
 
     explicit gfxFontEntry(const nsAString& aName, bool aIsStandardFace = false);
 
     // unique name for the face, *not* the family; not necessarily the
     // "real" or user-friendly name, may be an internal identifier
     const nsString& Name() const { return mName; }
 
@@ -175,17 +177,17 @@ public:
     // be considered to support no characters.
     // ReadCMAP() must *always* set the mCharacterMap pointer to a valid
     // gfxCharacterMap, even if empty, as other code assumes this pointer
     // can be safely dereferenced.
     virtual nsresult ReadCMAP(FontInfoData *aFontInfoData = nullptr);
 
     bool TryGetSVGData(gfxFont* aFont);
     bool HasSVGGlyph(uint32_t aGlyphId);
-    bool GetSVGGlyphExtents(gfxContext *aContext, uint32_t aGlyphId,
+    bool GetSVGGlyphExtents(DrawTarget* aDrawTarget, uint32_t aGlyphId,
                             gfxRect *aResult);
     bool RenderSVGGlyph(gfxContext *aContext, uint32_t aGlyphId, int aDrawMode,
                         gfxTextContextPaint *aContextPaint);
     // Call this when glyph geometry or rendering has changed
     // (e.g. animated SVG glyphs)
     void NotifyGlyphsChanged();
 
     enum MathConstant {
--- a/gfx/thebes/gfxGDIFont.cpp
+++ b/gfx/thebes/gfxGDIFont.cpp
@@ -93,17 +93,17 @@ gfxGDIFont::ShapeText(gfxContext     *aC
         NS_WARNING("invalid font! expect incorrect text rendering");
         return false;
     }
 
     // Ensure the cairo font is set up, so there's no risk it'll fall back to
     // creating a "toy" font internally (see bug 544617).
     // We must check that this succeeded, otherwise we risk cairo creating the
     // wrong kind of font internally as a fallback (bug 744480).
-    if (!SetupCairoFont(aContext)) {
+    if (!SetupCairoFont(aContext->GetDrawTarget())) {
         return false;
     }
 
     return gfxFont::ShapeText(aContext, aText, aOffset, aLength, aScript,
                               aVertical, aShapedText);
 }
 
 const gfxFont::Metrics&
@@ -120,29 +120,28 @@ gfxGDIFont::GetSpaceGlyph()
 {
     if (!mMetrics) {
         Initialize();
     }
     return mSpaceGlyph;
 }
 
 bool
-gfxGDIFont::SetupCairoFont(gfxContext *aContext)
+gfxGDIFont::SetupCairoFont(DrawTarget* aDrawTarget)
 {
     if (!mMetrics) {
         Initialize();
     }
     if (!mScaledFont ||
         cairo_scaled_font_status(mScaledFont) != CAIRO_STATUS_SUCCESS) {
         // Don't cairo_set_scaled_font as that would propagate the error to
         // the cairo_t, precluding any further drawing.
         return false;
     }
-    cairo_set_scaled_font(gfxContext::RefCairo(aContext->GetDrawTarget()),
-                          mScaledFont);
+    cairo_set_scaled_font(gfxFont::RefCairo(aDrawTarget), mScaledFont);
     return true;
 }
 
 gfxFont::RunMetrics
 gfxGDIFont::Measure(gfxTextRun *aTextRun,
                     uint32_t aStart, uint32_t aEnd,
                     BoundingBoxType aBoundingBoxType,
                     gfxContext *aRefContext,
--- a/gfx/thebes/gfxGDIFont.h
+++ b/gfx/thebes/gfxGDIFont.h
@@ -37,17 +37,17 @@ public:
     }
 
     cairo_font_face_t   *CairoFontFace() { return mFontFace; }
     cairo_scaled_font_t *CairoScaledFont() { return mScaledFont; }
 
     /* overrides for the pure virtual methods in gfxFont */
     virtual uint32_t GetSpaceGlyph() override;
 
-    virtual bool SetupCairoFont(gfxContext *aContext) override;
+    virtual bool SetupCairoFont(DrawTarget* aDrawTarget) override;
 
     /* override Measure to add padding for antialiasing */
     virtual RunMetrics Measure(gfxTextRun *aTextRun,
                                uint32_t aStart, uint32_t aEnd,
                                BoundingBoxType aBoundingBoxType,
                                gfxContext *aContextForTightBoundingBox,
                                Spacing *aSpacing,
                                uint16_t aOrientation) override;
--- a/gfx/thebes/gfxGlyphExtents.cpp
+++ b/gfx/thebes/gfxGlyphExtents.cpp
@@ -40,21 +40,21 @@ gfxGlyphExtents::GetTightGlyphExtentsApp
 {
     HashEntry *entry = mTightGlyphExtents.GetEntry(aGlyphID);
     if (!entry) {
         if (!aContext) {
             NS_WARNING("Could not get glyph extents (no aContext)");
             return false;
         }
 
-        if (aFont->SetupCairoFont(aContext)) {
+        if (aFont->SetupCairoFont(aContext->GetDrawTarget())) {
 #ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
             ++gGlyphExtentsSetupLazyTight;
 #endif
-            aFont->SetupGlyphExtents(aContext, aGlyphID, true, this);
+            aFont->SetupGlyphExtents(aContext->GetDrawTarget(), aGlyphID, true, this);
             entry = mTightGlyphExtents.GetEntry(aGlyphID);
         }
         if (!entry) {
             NS_WARNING("Could not get glyph extents");
             return false;
         }
     }
 
--- a/gfx/thebes/gfxGraphiteShaper.cpp
+++ b/gfx/thebes/gfxGraphiteShaper.cpp
@@ -86,17 +86,17 @@ gfxGraphiteShaper::ShapeText(gfxContext 
                              const char16_t *aText,
                              uint32_t         aOffset,
                              uint32_t         aLength,
                              int32_t          aScript,
                              bool             aVertical,
                              gfxShapedText   *aShapedText)
 {
     // some font back-ends require this in order to get proper hinted metrics
-    if (!mFont->SetupCairoFont(aContext)) {
+    if (!mFont->SetupCairoFont(aContext->GetDrawTarget())) {
         return false;
     }
 
     mCallbackData.mDrawTarget = aContext->GetDrawTarget();
 
     const gfxFontStyle *style = mFont->GetStyle();
 
     if (!mGrFont) {
@@ -263,19 +263,18 @@ gfxGraphiteShaper::SetGlyphsFromSegment(
         ++clusters[cIndex].nGlyphs;
 
         // extend cluster if necessary to reach the glyph's "after" index
         if (clusters[cIndex].baseChar + clusters[cIndex].nChars < after + 1) {
             clusters[cIndex].nChars = after + 1 - clusters[cIndex].baseChar;
         }
     }
 
-    bool roundX;
-    bool roundY;
-    aContext->GetRoundOffsetsToPixels(&roundX, &roundY);
+    bool roundX, roundY;
+    GetRoundOffsetsToPixels(aContext->GetDrawTarget(), &roundX, &roundY);
 
     gfxShapedText::CompressedGlyph *charGlyphs =
         aShapedText->GetCharacterGlyphs() + aOffset;
 
     // now put glyphs into the textrun, one cluster at a time
     for (uint32_t i = 0; i <= cIndex; ++i) {
         const Cluster& c = clusters[i];
 
--- a/gfx/thebes/gfxHarfBuzzShaper.cpp
+++ b/gfx/thebes/gfxHarfBuzzShaper.cpp
@@ -1466,17 +1466,17 @@ gfxHarfBuzzShaper::ShapeText(gfxContext 
                              const char16_t *aText,
                              uint32_t         aOffset,
                              uint32_t         aLength,
                              int32_t          aScript,
                              bool             aVertical,
                              gfxShapedText   *aShapedText)
 {
     // some font back-ends require this in order to get proper hinted metrics
-    if (!mFont->SetupCairoFont(aContext)) {
+    if (!mFont->SetupCairoFont(aContext->GetDrawTarget())) {
         return false;
     }
 
     mCallbackData.mDrawTarget = aContext->GetDrawTarget();
     mUseVerticalPresentationForms = false;
 
     if (!Initialize()) {
         return false;
@@ -1612,22 +1612,22 @@ gfxHarfBuzzShaper::SetGlyphsFromRun(gfxC
         if (loc < wordLength) {
             charToGlyph[loc] = i;
         }
     }
 
     int32_t glyphStart = 0; // looking for a clump that starts at this glyph
     int32_t charStart = 0; // and this char index within the range of the run
 
-    bool roundI;
-    bool roundB;
+    bool roundI, roundB;
+    DrawTarget* drawTarget = aContext->GetDrawTarget();
     if (aVertical) {
-        aContext->GetRoundOffsetsToPixels(&roundB, &roundI);
+        GetRoundOffsetsToPixels(drawTarget, &roundB, &roundI);
     } else {
-        aContext->GetRoundOffsetsToPixels(&roundI, &roundB);
+        GetRoundOffsetsToPixels(drawTarget, &roundI, &roundB);
     }
 
     int32_t appUnitsPerDevUnit = aShapedText->GetAppUnitsPerDevUnit();
     gfxShapedText::CompressedGlyph *charGlyphs =
         aShapedText->GetCharacterGlyphs() + aOffset;
 
     // factor to convert 16.16 fixed-point pixels to app units
     // (only used if not rounding)
--- a/gfx/thebes/gfxMacFont.cpp
+++ b/gfx/thebes/gfxMacFont.cpp
@@ -137,36 +137,35 @@ gfxMacFont::ShapeText(gfxContext     *aC
     // so we ignore RequiresAATLayout if vertical is requested.
     if (static_cast<MacOSFontEntry*>(GetFontEntry())->RequiresAATLayout() &&
         !aVertical) {
         if (!mCoreTextShaper) {
             mCoreTextShaper = new gfxCoreTextShaper(this);
         }
         if (mCoreTextShaper->ShapeText(aContext, aText, aOffset, aLength,
                                        aScript, aVertical, aShapedText)) {
-            PostShapingFixup(aContext, aText, aOffset, aLength, aVertical,
-                             aShapedText);
+            PostShapingFixup(aContext->GetDrawTarget(), aText, aOffset,
+                             aLength, aVertical, aShapedText);
             return true;
         }
     }
 
     return gfxFont::ShapeText(aContext, aText, aOffset, aLength, aScript,
                               aVertical, aShapedText);
 }
 
 bool
-gfxMacFont::SetupCairoFont(gfxContext *aContext)
+gfxMacFont::SetupCairoFont(DrawTarget* aDrawTarget)
 {
     if (cairo_scaled_font_status(mScaledFont) != CAIRO_STATUS_SUCCESS) {
         // Don't cairo_set_scaled_font as that would propagate the error to
         // the cairo_t, precluding any further drawing.
         return false;
     }
-    cairo_set_scaled_font(gfxContext::RefCairo(aContext->GetDrawTarget()),
-                          mScaledFont);
+    cairo_set_scaled_font(gfxFont::RefCairo(aDrawTarget), mScaledFont);
     return true;
 }
 
 gfxFont::RunMetrics
 gfxMacFont::Measure(gfxTextRun *aTextRun,
                     uint32_t aStart, uint32_t aEnd,
                     BoundingBoxType aBoundingBoxType,
                     gfxContext *aRefContext,
--- a/gfx/thebes/gfxMacFont.h
+++ b/gfx/thebes/gfxMacFont.h
@@ -23,17 +23,17 @@ public:
 
     CGFontRef GetCGFontRef() const { return mCGFont; }
 
     /* overrides for the pure virtual methods in gfxFont */
     virtual uint32_t GetSpaceGlyph() override {
         return mSpaceGlyph;
     }
 
-    virtual bool SetupCairoFont(gfxContext *aContext) override;
+    virtual bool SetupCairoFont(DrawTarget* aDrawTarget) override;
 
     /* override Measure to add padding for antialiasing */
     virtual RunMetrics Measure(gfxTextRun *aTextRun,
                                uint32_t aStart, uint32_t aEnd,
                                BoundingBoxType aBoundingBoxType,
                                gfxContext *aContextForTightBoundingBox,
                                Spacing *aSpacing,
                                uint16_t aOrientation) override;
--- a/gfx/thebes/gfxTextRun.cpp
+++ b/gfx/thebes/gfxTextRun.cpp
@@ -206,18 +206,17 @@ gfxTextRun::ReleaseFontGroup()
 {
     NS_ASSERTION(!mReleasedFontGroup, "doubly released!");
     NS_RELEASE(mFontGroup);
     mReleasedFontGroup = true;
 }
 
 bool
 gfxTextRun::SetPotentialLineBreaks(uint32_t aStart, uint32_t aLength,
-                                   uint8_t *aBreakBefore,
-                                   gfxContext *aRefContext)
+                                   uint8_t *aBreakBefore)
 {
     NS_ASSERTION(aStart + aLength <= GetLength(), "Overflow");
 
     uint32_t changed = 0;
     uint32_t i;
     CompressedGlyph *charGlyphs = mCharacterGlyphs + aStart;
     for (i = 0; i < aLength; ++i) {
         uint8_t canBreak = aBreakBefore[i];
@@ -1406,52 +1405,52 @@ gfxTextRun::FetchGlyphExtents(gfxContext
             const gfxTextRun::CompressedGlyph *glyphData = &charGlyphs[j];
             if (glyphData->IsSimpleGlyph()) {
                 // If we're in speed mode, don't set up glyph extents here; we'll
                 // just return "optimistic" glyph bounds later
                 if (needsGlyphExtents) {
                     uint32_t glyphIndex = glyphData->GetSimpleGlyph();
                     if (!extents->IsGlyphKnown(glyphIndex)) {
                         if (!fontIsSetup) {
-                            if (!font->SetupCairoFont(aRefContext)) {
+                            if (!font->SetupCairoFont(aRefContext->GetDrawTarget())) {
                                 NS_WARNING("failed to set up font for glyph extents");
                                 break;
                             }
                             fontIsSetup = true;
                         }
 #ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
                         ++gGlyphExtentsSetupEagerSimple;
 #endif
-                        font->SetupGlyphExtents(aRefContext,
+                        font->SetupGlyphExtents(aRefContext->GetDrawTarget(),
                                                 glyphIndex, false, extents);
                     }
                 }
             } else if (!glyphData->IsMissing()) {
                 uint32_t glyphCount = glyphData->GetGlyphCount();
                 if (glyphCount == 0) {
                     continue;
                 }
                 const gfxTextRun::DetailedGlyph *details = GetDetailedGlyphs(j);
                 if (!details) {
                     continue;
                 }
                 for (uint32_t k = 0; k < glyphCount; ++k, ++details) {
                     uint32_t glyphIndex = details->mGlyphID;
                     if (!extents->IsGlyphKnownWithTightExtents(glyphIndex)) {
                         if (!fontIsSetup) {
-                            if (!font->SetupCairoFont(aRefContext)) {
+                            if (!font->SetupCairoFont(aRefContext->GetDrawTarget())) {
                                 NS_WARNING("failed to set up font for glyph extents");
                                 break;
                             }
                             fontIsSetup = true;
                         }
 #ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
                         ++gGlyphExtentsSetupEagerTight;
 #endif
-                        font->SetupGlyphExtents(aRefContext,
+                        font->SetupGlyphExtents(aRefContext->GetDrawTarget(),
                                                 glyphIndex, true, extents);
                     }
                 }
             }
         }
     }
 }
 
--- a/gfx/thebes/gfxTextRun.h
+++ b/gfx/thebes/gfxTextRun.h
@@ -148,18 +148,17 @@ public:
      * This can change glyphs and/or geometry! Some textruns' shapes
      * depend on potential line breaks (e.g., title-case-converting textruns).
      * This function is virtual so that those textruns can reshape themselves.
      * 
      * @return true if this changed the linebreaks, false if the new line
      * breaks are the same as the old
      */
     virtual bool SetPotentialLineBreaks(uint32_t aStart, uint32_t aLength,
-                                          uint8_t *aBreakBefore,
-                                          gfxContext *aRefContext);
+                                        uint8_t *aBreakBefore);
 
     /**
      * Layout provides PropertyProvider objects. These allow detection of
      * potential line break points and computation of spacing. We pass the data
      * this way to allow lazy data acquisition; for example BreakAndMeasureText
      * will want to only ask for properties of text it's actually looking at.
      * 
      * NOTE that requested spacing may not actually be applied, if the textrun
--- a/js/src/builtin/Array.js
+++ b/js/src/builtin/Array.js
@@ -727,16 +727,17 @@ function ArrayIteratorNext() {
 
 function ArrayValuesAt(n) {
     return CreateArrayIteratorAt(this, ITEM_KIND_VALUE, n);
 }
 
 function ArrayValues() {
     return CreateArrayIterator(this, ITEM_KIND_VALUE);
 }
+_SetCanonicalName(ArrayValues, "values");
 
 function ArrayEntries() {
     return CreateArrayIterator(this, ITEM_KIND_KEY_AND_VALUE);
 }
 
 function ArrayKeys() {
     return CreateArrayIterator(this, ITEM_KIND_KEY);
 }
--- a/js/src/builtin/Generator.js
+++ b/js/src/builtin/Generator.js
@@ -83,16 +83,17 @@ function LegacyGeneratorNext(val) {
     try {
         return resumeGenerator(this, val, 'next');
     } catch(e) {
         if (!LegacyGeneratorObjectIsClosed(this))
             GeneratorSetClosed(this);
         throw e;
     }
 }
+_SetCanonicalName(LegacyGeneratorNext, "next");
 
 function LegacyGeneratorThrow(val) {
     if (!IsObject(this) || !IsLegacyGeneratorObject(this))
         return callFunction(CallLegacyGeneratorMethodIfWrapped, this, val, "LegacyGeneratorThrow");
 
     if (LegacyGeneratorObjectIsClosed(this))
         throw val;
 
--- a/js/src/builtin/Intl.js
+++ b/js/src/builtin/Intl.js
@@ -95,18 +95,18 @@ function removeUnicodeExtensions(locale)
 
     // Otherwise, split on "-x-" marking the start of any privateuse component.
     // Replace Unicode locale extension sequences in the left half, and return
     // the concatenation.
     var pos = callFunction(std_String_indexOf, locale, "-x-");
     if (pos < 0)
         pos = locale.length;
 
-    var left = callFunction(std_String_substring, locale, 0, pos);
-    var right = callFunction(std_String_substring, locale, pos);
+    var left = callFunction(String_substring, locale, 0, pos);
+    var right = callFunction(String_substring, locale, pos);
 
     var extensions;
     var unicodeLocaleExtensionSequenceRE = getUnicodeLocaleExtensionSequenceRE();
     while ((extensions = regexp_exec_no_statics(unicodeLocaleExtensionSequenceRE, left)) !== null) {
         left = callFunction(std_String_replace, left, extensions[0], "");
         unicodeLocaleExtensionSequenceRE.lastIndex = 0;
     }
 
@@ -327,17 +327,17 @@ function IsStructurallyValidLanguageTag(
 
     // Before checking for duplicate variant or singleton subtags with
     // regular expressions, we have to get private use subtag sequences
     // out of the picture.
     if (callFunction(std_String_startsWith, locale, "x-"))
         return true;
     var pos = callFunction(std_String_indexOf, locale, "-x-");
     if (pos !== -1)
-        locale = callFunction(std_String_substring, locale, 0, pos);
+        locale = callFunction(String_substring, locale, 0, pos);
 
     // Check for duplicate variant or singleton subtags.
     var duplicateVariantRE = getDuplicateVariantRE();
     var duplicateSingletonRE = getDuplicateSingletonRE();
     return !regexp_test_no_statics(duplicateVariantRE, locale) &&
            !regexp_test_no_statics(duplicateSingletonRE, locale);
 }
 
@@ -396,17 +396,17 @@ function CanonicalizeLanguageTag(locale)
         // In the example, we break at "u".
         if (subtag.length === 1 && (i > 0 || subtag === "x"))
             break;
 
         if (subtag.length === 4) {
             // 4-character subtags are script codes; their first character
             // needs to be capitalized. "hans" -> "Hans"
             subtag = callFunction(std_String_toUpperCase, subtag[0]) +
-                     callFunction(std_String_substring, subtag, 1);
+                     callFunction(String_substring, subtag, 1);
         } else if (i !== 0 && subtag.length === 2) {
             // 2-character subtags that are not in initial position are region
             // codes; they need to be upper case. "bu" -> "BU"
             subtag = callFunction(std_String_toUpperCase, subtag);
         }
         if (callFunction(std_Object_hasOwnProperty, langSubtagMappings, subtag)) {
             // Replace deprecated subtags with their preferred values.
             // "BU" -> "MM"
@@ -673,17 +673,17 @@ function CanonicalizeLocaleList(locales)
         if (kPresent) {
             var kValue = O[k];
             if (!(typeof kValue === "string" || IsObject(kValue)))
                 ThrowTypeError(JSMSG_INVALID_LOCALES_ELEMENT);
             var tag = ToString(kValue);
             if (!IsStructurallyValidLanguageTag(tag))
                 ThrowRangeError(JSMSG_INVALID_LANGUAGE_TAG, tag);
             tag = CanonicalizeLanguageTag(tag);
-            if (callFunction(std_Array_indexOf, seen, tag) === -1)
+            if (callFunction(ArrayIndexOf, seen, tag) === -1)
                 callFunction(std_Array_push, seen, tag);
         }
         k++;
     }
     return seen;
 }
 
 
@@ -721,17 +721,17 @@ function BestAvailableLocaleHelper(avail
 
         var pos = callFunction(std_String_lastIndexOf, candidate, "-");
         if (pos === -1)
             return undefined;
 
         if (pos >= 2 && candidate[pos - 2] === "-")
             pos -= 2;
 
-        candidate = callFunction(std_String_substring, candidate, 0, pos);
+        candidate = callFunction(String_substring, candidate, 0, pos);
     }
 }
 
 
 /**
  * Compares a BCP 47 language tag against the locales in availableLocales
  * and returns the best available match. Uses the fallback
  * mechanism of RFC 4647, section 3.4.
@@ -874,77 +874,77 @@ function ResolveLocale(availableLocales,
 
         // Step 11.f is implemented by Utilities.js.
 
         var valuePos;
 
         // Step 11.g.
         if (extensionSubtags !== undefined) {
             // Step 11.g.i.
-            var keyPos = callFunction(std_Array_indexOf, extensionSubtags, key);
+            var keyPos = callFunction(ArrayIndexOf, extensionSubtags, key);
 
             // Step 11.g.ii.
             if (keyPos !== -1) {
                 // Step 11.g.ii.1.
                 if (keyPos + 1 < extensionSubtagsLength &&
                     extensionSubtags[keyPos + 1].length > 2)
                 {
                     // Step 11.g.ii.1.a.
                     var requestedValue = extensionSubtags[keyPos + 1];
 
                     // Step 11.g.ii.1.b.
-                    valuePos = callFunction(std_Array_indexOf, keyLocaleData, requestedValue);
+                    valuePos = callFunction(ArrayIndexOf, keyLocaleData, requestedValue);
 
                     // Step 11.g.ii.1.c.
                     if (valuePos !== -1) {
                         value = requestedValue;
                         supportedExtensionAddition = "-" + key + "-" + value;
                     }
                 } else {
                     // Step 11.g.ii.2.
 
                     // According to the LDML spec, if there's no type value,
                     // and true is an allowed value, it's used.
 
                     // Step 11.g.ii.2.a.
-                    valuePos = callFunction(std_Array_indexOf, keyLocaleData, "true");
+                    valuePos = callFunction(ArrayIndexOf, keyLocaleData, "true");
 
                     // Step 11.g.ii.2.b.
                     if (valuePos !== -1)
                         value = "true";
                 }
             }
         }
 
         // Options override all.
 
         // Step 11.h.i.
         var optionsValue = options[key];
 
         // Step 11.h, 11.h.ii.
         if (optionsValue !== undefined &&
-            callFunction(std_Array_indexOf, keyLocaleData, optionsValue) !== -1)
+            callFunction(ArrayIndexOf, keyLocaleData, optionsValue) !== -1)
         {
             // Step 11.h.ii.1.
             if (optionsValue !== value) {
                 value = optionsValue;
                 supportedExtensionAddition = "";
             }
         }
 
         // Steps 11.i-k.
         result[key] = value;
         supportedExtension += supportedExtensionAddition;
         i++;
     }
 
     // Step 12.
     if (supportedExtension.length > 2) {
-        var preExtension = callFunction(std_String_substring, foundLocale, 0, extensionIndex);
-        var postExtension = callFunction(std_String_substring, foundLocale, extensionIndex);
+        var preExtension = callFunction(String_substring, foundLocale, 0, extensionIndex);
+        var postExtension = callFunction(String_substring, foundLocale, extensionIndex);
         foundLocale = preExtension + supportedExtension + postExtension;
     }
 
     // Steps 13-14.
     result.locale = foundLocale;
     return result;
 }
 
@@ -1055,17 +1055,17 @@ function GetOption(options, property, ty
         if (type === "boolean")
             value = ToBoolean(value);
         else if (type === "string")
             value = ToString(value);
         else
             assert(false, "GetOption");
 
         // Step 2.d.
-        if (values !== undefined && callFunction(std_Array_indexOf, values, value) === -1)
+        if (values !== undefined && callFunction(ArrayIndexOf, values, value) === -1)
             ThrowRangeError(JSMSG_INVALID_OPTION_VALUE, property, value);
 
         // Step 2.e.
         return value;
     }
 
     // Step 3.
     return fallback;
@@ -2607,18 +2607,18 @@ function BasicFormatMatcher(options, for
             if (optionsProp === undefined && formatProp !== undefined) {
                 // Step 11.c.iv.
                 score -= additionPenalty;
             } else if (optionsProp !== undefined && formatProp === undefined) {
                 // Step 11.c.v.
                 score -= removalPenalty;
             } else {
                 // Step 11.c.vi.
-                var optionsPropIndex = callFunction(std_Array_indexOf, values, optionsProp);
-                var formatPropIndex = callFunction(std_Array_indexOf, values, formatProp);
+                var optionsPropIndex = callFunction(ArrayIndexOf, values, optionsProp);
+                var formatPropIndex = callFunction(ArrayIndexOf, values, formatProp);
                 var delta = std_Math_max(std_Math_min(formatPropIndex - optionsPropIndex, 2), -2);
                 if (delta === 2)
                     score -= longMorePenalty;
                 else if (delta === 1)
                     score -= shortMorePenalty;
                 else if (delta === -1)
                     score -= shortLessPenalty;
                 else if (delta === -2)
--- a/js/src/builtin/Map.js
+++ b/js/src/builtin/Map.js
@@ -20,17 +20,17 @@ function MapForEach(callbackfn, thisArg 
 
     /* Step 5. */
     if (!IsCallable(callbackfn))
         ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn));
 
     /* Step 6-8. */
     var entries = callFunction(std_Map_iterator, M);
     while (true) {
-        var result = callFunction(std_Map_iterator_next, entries);
+        var result = callFunction(MapIteratorNext, entries);
         if (result.done)
             break;
         var entry = result.value;
         callContentFunction(callbackfn, thisArg, entry[1], entry[0], M);
     }
 }
 
 var iteratorTemp = { mapIterationResultPair : null };
@@ -83,8 +83,9 @@ function MapIteratorNext() {
     return retVal;
 }
 
 // ES6 final draft 23.1.2.2.
 function MapSpecies() {
     // Step 1.
     return this;
 }
+_SetCanonicalName(MapSpecies, "get [Symbol.species]");
--- a/js/src/builtin/RegExp.js
+++ b/js/src/builtin/RegExp.js
@@ -30,16 +30,17 @@ function RegExpFlagsGetter() {
 
     // Steps 16-18.
     if (R.sticky)
         result += "y";
 
     // Step 19.
     return result;
 }
+_SetCanonicalName(RegExpFlagsGetter, "get flags");
 
 // ES6 draft rc1 21.2.5.14.
 function RegExpToString()
 {
     // Steps 1-2.
     var R = this;
     if (!IsObject(R))
         ThrowTypeError(JSMSG_NOT_NONNULL_OBJECT, R === null ? "null" : typeof R);
@@ -48,8 +49,9 @@ function RegExpToString()
     var pattern = R.source;
 
     // Steps 5-6.
     var flags = R.flags;
 
     // Step 7.
     return '/' + pattern + '/' + flags;
 }
+_SetCanonicalName(RegExpToString, "toString");
--- a/js/src/builtin/SelfHostingDefines.h
+++ b/js/src/builtin/SelfHostingDefines.h
@@ -29,16 +29,21 @@
 #define ATTR_NONENUMERABLE      0x08
 #define ATTR_NONCONFIGURABLE    0x10
 #define ATTR_NONWRITABLE        0x20
 
 // The extended slot in which the self-hosted name for self-hosted builtins is
 // stored.
 #define LAZY_FUNCTION_NAME_SLOT 0
 
+// The extended slot which contains a boolean value that indicates whether
+// that the canonical name of the self-hosted builtins is set in self-hosted
+// global. This slot is used only in debug build.
+#define HAS_SELFHOSTED_CANONICAL_NAME_SLOT 0
+
 // Stores the private WeakMap slot used for WeakSets
 #define WEAKSET_MAP_SLOT 0
 
 #define ITERATOR_SLOT_TARGET 0
 // Used for collection iterators.
 #define ITERATOR_SLOT_RANGE 1
 // Used for list, i.e. Array and String, iterators.
 #define ITERATOR_SLOT_NEXT_INDEX 1
--- a/js/src/builtin/Set.js
+++ b/js/src/builtin/Set.js
@@ -33,8 +33,9 @@ function SetForEach(callbackfn, thisArg 
     }
 }
 
 // ES6 final draft 23.2.2.2.
 function SetSpecies() {
     // Step 1.
     return this;
 }
+_SetCanonicalName(SetSpecies, "get [Symbol.species]");
--- a/js/src/builtin/String.js
+++ b/js/src/builtin/String.js
@@ -223,17 +223,17 @@ function StringIteratorNext() {
     if (first >= 0xD800 && first <= 0xDBFF && index + 1 < size) {
         var second = callFunction(std_String_charCodeAt, S, index + 1);
         if (second >= 0xDC00 && second <= 0xDFFF) {
             charCount = 2;
         }
     }
 
     UnsafeSetReservedSlot(this, ITERATOR_SLOT_NEXT_INDEX, index + charCount);
-    result.value = callFunction(std_String_substring, S, index, index + charCount);
+    result.value = callFunction(String_substring, S, index, index + charCount);
 
     return result;
 }
 
 /**
  * Compare this String against that String, using the locale and collation
  * options provided.
  *
@@ -428,24 +428,24 @@ function String_sup() {
 
 function EscapeAttributeValue(v) {
     var inputStr = ToString(v);
     var inputLen = inputStr.length;
     var outputStr = "";
     var chunkStart = 0;
     for (var i = 0; i < inputLen; i++) {
         if (inputStr[i] === '"') {
-            outputStr += callFunction(std_String_substring, inputStr, chunkStart, i) + '&quot;';
+            outputStr += callFunction(String_substring, inputStr, chunkStart, i) + '&quot;';
             chunkStart = i + 1;
         }
     }
     if (chunkStart === 0)
         return inputStr;
     if (chunkStart < inputLen)
-        outputStr += callFunction(std_String_substring, inputStr, chunkStart);
+        outputStr += callFunction(String_substring, inputStr, chunkStart);
     return outputStr;
 }
 
 // ES6 draft 2014-04-27 B.2.3.2
 function String_anchor(name) {
     RequireObjectCoercible(this);
     var S = ToString(this);
     return '<a name="' + EscapeAttributeValue(name) + '">' + S + "</a>";
--- a/js/src/builtin/TypedArray.js
+++ b/js/src/builtin/TypedArray.js
@@ -959,16 +959,17 @@ function TypedArrayValues() {
         return callFunction(CallTypedArrayMethodIfWrapped, O, "TypedArrayValues");
     }
 
     // Step 4-6. Bug 1101256: detachment checks
 
     // Step 7.
     return CreateArrayIterator(O, ITEM_KIND_VALUE);
 }
+_SetCanonicalName(TypedArrayValues, "values");
 
 // Proposed for ES7:
 // https://github.com/tc39/Array.prototype.includes/blob/7c023c19a0/spec.md
 function TypedArrayIncludes(searchElement, fromIndex = 0) {
     // This function is not generic.
     if (!IsObject(this) || !IsTypedArray(this)) {
         return callFunction(CallTypedArrayMethodIfWrapped, this, searchElement,
                             fromIndex, "TypedArrayIncludes");
--- a/js/src/builtin/Utilities.js
+++ b/js/src/builtin/Utilities.js
@@ -31,25 +31,23 @@
 #else
 #define assert(b, info) // Elided assertion.
 #endif
 
 // All C++-implemented standard builtins library functions used in self-hosted
 // code are installed via the std_functions JSFunctionSpec[] in
 // SelfHosting.cpp.
 //
-// The few items below here are either self-hosted or installing them under a
-// std_Foo name would require ugly contortions, so they just get aliased here.
-var std_Array_indexOf = ArrayIndexOf;
-var std_String_substring = String_substring;
+// Do not create an alias to a self-hosted builtin, otherwise it will be cloned
+// twice.
+//
 // WeakMap is a bare constructor without properties or methods.
 var std_WeakMap = WeakMap;
 // StopIteration is a bare constructor without properties or methods.
 var std_StopIteration = StopIteration;
-var std_Map_iterator_next = MapIteratorNext;
 
 
 /********** List specification type **********/
 
 /* Spec: ECMAScript Language Specification, 5.1 edition, 8.8 */
 function List() {
     this.length = 0;
 }
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -1182,101 +1182,65 @@ if test "$GNU_CC"; then
     _SAVE_LDFLAGS=$LDFLAGS
     LDFLAGS="$LDFLAGS -Wl,--build-id"
     AC_TRY_LINK(,,AC_MSG_RESULT([yes])
                   [NSPR_LDFLAGS="$NSPR_LDFLAGS -Wl,--build-id"],
                   AC_MSG_RESULT([no])
                   LDFLAGS=$_SAVE_LDFLAGS)
 
     # Turn on gcc/clang warnings:
-    # https://gcc.gnu.org/onlinedocs/gcc-4.4.0/gcc/Warning-Options.html
-    #
-    # -Wall - turn on a lot of warnings
-    # -Waddress - catches suspicious uses of memory addresses
-    # -Wchar-subscripts - catches array index using signed char
-    # -Wcomment - catches nested comments
+    # https://gcc.gnu.org/onlinedocs/gcc-4.7.2/gcc/Warning-Options.html
+
+    # -Wall - lots of useful warnings
     # -Wempty-body - catches bugs, e.g. "if (c); foo();", few false positives
-    # -Wendif-labels - catches `#else FOO` and `#endif FOO` not in comment
-    # -Wenum-compare - catches comparison of different enum types
     # -Wignored-qualifiers - catches returns types with qualifiers like const
-    # -Wimplicit-function-declaration - catches missing C function prototypes
-    # -Wint-to-pointer-cast - catches cast to pointer from integer of different size
-    # -Wmissing-braces - catches aggregate initializers missing nested braces
-    # -Wmultichar - catches multicharacter integer constants like 'THIS'
+    # -Wpointer-arith - catches pointer arithmetic using NULL or sizeof(void)
+    # -Wtype-limits - catches overflow bugs, few false positives
+    _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wall"
+    _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wempty-body"
+    _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wignored-qualifiers"
+    _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wpointer-arith"
+    _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wtype-limits"
+
     # -Wnon-literal-null-conversion - catches expressions used as a null pointer constant
-    # -Wnonnull - catches NULL used with functions arguments marked as non-null
-    # -Wparentheses - catches `if (a=b)` and operator precedence bugs
-    # -Wpointer-arith - catches pointer arithmetic using NULL or sizeof(void)
-    # -Wpointer-sign - catches mixing pointers to signed and unsigned types
-    # -Wpointer-to-int-cast - catches casts from pointer to different sized int
-    # -Wreturn-type - catches missing returns, zero false positives
-    # -Wsequence-point - catches undefined order behavior like `a = a++`
-    # -Wsign-compare - catches comparison of signed and unsigned types
-    # -Wswitch - catches switches without all enum cases or default case
-    # -Wtrigraphs - catches unlikely use of trigraphs
-    # -Wtype-limits - catches overflow bugs, few false positives
-    # -Wunknown-pragmas - catches unexpected #pragma directives
-    # -Wwrite-strings - catches non-const char* pointers to string literals
+    # -Wsometimes-initialized - catches some uninitialized values
     #
-    _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wall"
-    _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wsign-compare"
-    _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wtype-limits"
-
-    # Treat some warnings as errors if --enable-warnings-as-errors:
+    # XXX: at the time of writing, the version of clang used on the OS X test
+    # machines has a bug that causes it to reject some valid files if both
+    # -Wnon-literal-null-conversion and -Wsometimes-uninitialized are
+    # specified. We work around this by instead using
+    # -Werror=non-literal-null-conversion, but we only do that when
+    # --enable-warnings-as-errors is specified so that no unexpected fatal
+    # warnings are produced.
     if test "$MOZ_ENABLE_WARNINGS_AS_ERRORS"; then
-        _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=address"
-        _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=char-subscripts"
-        _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=comment"
-        _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=empty-body"
-        _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=endif-labels"
-        _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=enum-compare"
-        _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=ignored-qualifiers"
-        _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=implicit-function-declaration"
-        _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=int-to-pointer-cast"
-        _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=missing-braces"
-        _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=multichar"
-        _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=nonnull"
-        _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=parentheses"
-        _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=pointer-arith"
-        _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=pointer-sign"
-        _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=pointer-to-int-cast"
-        _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=return-type"
-        _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=sequence-point"
-        _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=switch"
-        _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=trigraphs"
-        _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=uninitialized"
-        _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=unknown-pragmas"
-        _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=write-strings"
-
-        MOZ_C_SUPPORTS_WARNING(-Werror=, non-literal-null-conversion, ac_c_has_werror_non_literal_null_conversion)
-        MOZ_C_SUPPORTS_WARNING(-Werror=, sometimes-uninitialized, ac_c_has_sometimes_uninitialized)
+        MOZ_C_SUPPORTS_WARNING(-Werror=, non-literal-null-conversion, ac_c_has_non_literal_null_conversion)
     fi
-
-    # Turn off the following warnings that -Wall turns on:
-    # -Wno-unused - lots of violations in third-party code
-    # -Wno-inline-new-delete - we inline 'new' and 'delete' in mozalloc
-    # -Wno-unused-local-typedef - catches unused typedefs, which are commonly used in assertion macros
-    #
-    _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wno-unused"
-
-    MOZ_CXX_SUPPORTS_WARNING(-Wno-, inline-new-delete, ac_cxx_has_wno_inline_new_delete)
-    MOZ_CXX_SUPPORTS_WARNING(-Wno-, unused-local-typedef, ac_cxx_has_wno_unused_local_typedef)
-
+    MOZ_C_SUPPORTS_WARNING(-W, sometimes-uninitialized, ac_c_has_sometimes_uninitialized)
+
+    # -Wcast-align - catches problems with cast alignment
     if test -z "$INTEL_CC" -a -z "$CLANG_CC"; then
        # Don't use -Wcast-align with ICC or clang
        case "$CPU_ARCH" in
            # And don't use it on hppa, ia64, sparc, arm, since it's noisy there
            hppa | ia64 | sparc | arm)
            ;;
            *)
         _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wcast-align"
            ;;
        esac
     fi
 
+    # Turn off some non-useful warnings that -Wall turns on.
+
+    # -Wno-unused - lots of violations in third-party code
+    _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wno-unused"
+
+    # -Wno-unused-local-typedef - catches unused typedefs, which are commonly used in assertion macros
+    MOZ_C_SUPPORTS_WARNING(-Wno-, unused-local-typedef, ac_c_has_wno_unused_local_typedef)
+
     _DEFINES_CFLAGS='-include $(topobjdir)/js/src/js-confdefs.h -DMOZILLA_CLIENT'
     _USE_CPP_INCLUDE_FLAG=1
 
 elif test "$SOLARIS_SUNPRO_CC"; then
     DSO_CFLAGS=''
     if test "$CPU_ARCH" = "sparc"; then
         # for Sun Studio on Solaris/SPARC
         DSO_PIC_CFLAGS='-xcode=pic32'
@@ -1296,113 +1260,86 @@ else
 
     DSO_CFLAGS=''
     DSO_PIC_CFLAGS='-KPIC'
     _DEFINES_CFLAGS='$(ACDEFINES) -D_JS_CONFDEFS_H_ -DMOZILLA_CLIENT'
 fi
 
 if test "$GNU_CXX"; then
     # Turn on gcc/clang warnings:
-    # https://gcc.gnu.org/onlinedocs/gcc-4.4.0/gcc/Warning-Options.html
-    #
-    # -Wall - turn on a lot of warnings
-    # -Wchar-subscripts - catches array index using signed char
-    # -Wcomment - catches nested comments
-    # -Wconversion-null - catches conversions between NULL and non-pointer types
+    # https://gcc.gnu.org/onlinedocs/gcc-4.7.2/gcc/Warning-Options.html
+
+    # -Wall - lots of useful warnings
     # -Wempty-body - catches bugs, e.g. "if (c); foo();", few false positives
-    # -Wendif-labels - catches `#else FOO` and `#endif FOO` not in comment
-    # -Wignored-qualifiers - catches returns types with qualifiers like const
-    # -Wint-to-pointer-cast - catches cast to pointer from integer of different size
-    # -Wmissing-braces - catches aggregate initializers missing nested braces
+    # -Woverloaded-virtual - function declaration hides virtual function from base class
+    # -Wpointer-arith - catches pointer arithmetic using NULL or sizeof(void)
+    # -Wtype-limits - catches overflow bugs, few false positives
+    _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wall"
+    _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wempty-body"
+    _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Woverloaded-virtual"
+    _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wpointer-arith"
+    _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wtype-limits"
+
+    # -Wclass-varargs - ???
     # -Wnon-literal-null-conversion - catches expressions used as a null pointer constant
-    # -Woverloaded-virtual - function declaration hides virtual function from base class
-    # -Wparentheses - catches `if (a=b)` and operator precedence bugs
-    # -Wpointer-arith - catches pointer arithmetic using NULL or sizeof(void)
-    # -Wpointer-to-int-cast - catches casts from pointer to different sized int
     # -Wrange-loop-analysis - catches copies during range-based for loops.
-    # -Wreorder - catches ctor initializer list not matching class definition order
-    # -Wreturn-type - catches missing returns, zero false positives
-    # -Wsequence-point - catches undefined order behavior like `a = a++`
-    # -Wsign-compare - catches comparison of signed and unsigned types
-    # -Wswitch - catches switches without all enum cases or default case
-    # -Wtrigraphs - catches unlikely use of trigraphs
-    # -Wtype-limits - catches overflow bugs, few false positives
-    # -Wunknown-pragmas - catches unexpected #pragma directives
-    # -Wunused-label - catches unused goto labels
-    # -Wunused-value - catches unused expression results
-    # -Wwrite-strings - catches non-const char* pointers to string literals
+    # -Wsometimes-initialized - catches some uninitialized values
     #
-    _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wall"
-    _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wsign-compare"
-    _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wtype-limits"
-
+    # XXX: at the time of writing, the version of clang used on the OS X test
+    # machines has a bug that causes it to reject some valid files if both
+    # -Wnon-literal-null-conversion and -Wsometimes-uninitialized are
+    # specified. We work around this by instead using
+    # -Werror=non-literal-null-conversion, but we only do that when
+    # --enable-warnings-as-errors is specified so that no unexpected fatal
+    # warnings are produced.
     MOZ_CXX_SUPPORTS_WARNING(-W, class-varargs, ac_cxx_has_wclass_varargs)
 
-    # Treat some warnings as errors if --enable-warnings-as-errors:
     if test "$MOZ_ENABLE_WARNINGS_AS_ERRORS"; then
-        _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=char-subscripts"
-        _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=comment"
-        _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=endif-labels"
-        _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=ignored-qualifiers"
-        _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=int-to-pointer-cast"
-        _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=missing-braces"
-        _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=overloaded-virtual"
-        _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=parentheses"
-        _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=pointer-arith"
-        _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=reorder"
-        _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=return-type"
-        _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=sequence-point"
-        _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=switch"
-        _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=trigraphs"
-        _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=uninitialized"
-        _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=unknown-pragmas"
-        _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=unused-label"
-        _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=unused-value"
-        _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=write-strings"
-
-        MOZ_CXX_SUPPORTS_WARNING(-Werror=, conversion-null, ac_cxx_has_werror_conversion_null)
-        MOZ_CXX_SUPPORTS_WARNING(-Werror=, non-literal-null-conversion, ac_cxx_has_werror_non_literal_null_conversion)
-        MOZ_CXX_SUPPORTS_WARNING(-Werror=, range-loop-analysis, ac_cxx_has_range_loop_analysis)
-        MOZ_CXX_SUPPORTS_WARNING(-Werror=, sometimes-uninitialized, ac_cxx_has_sometimes_uninitialized)
+        MOZ_CXX_SUPPORTS_WARNING(-Werror=, non-literal-null-conversion, ac_cxx_has_non_literal_null_conversion)
     fi
-
-    # Turn off the following warnings that -Wall turns on:
-    # -Wno-invalid-offsetof - we use offsetof on non-POD types frequently
-    # -Wno-unused-local-typedef - catches unused typedefs, which are commonly used in assertion macros
-    #
-    _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wno-invalid-offsetof"
-
-    MOZ_CXX_SUPPORTS_WARNING(-Wno-, unused-local-typedef, ac_cxx_has_wno_unused_local_typedef)
-
+    MOZ_CXX_SUPPORTS_WARNING(-W, range-loop-analysis, ac_cxx_has_range_loop_analysis)
+    MOZ_CXX_SUPPORTS_WARNING(-W, sometimes-uninitialized, ac_cxx_has_sometimes_uninitialized)
+
+    # -Wcast-align - catches problems with cast alignment
     if test -z "$INTEL_CXX" -a -z "$CLANG_CXX"; then
        # Don't use -Wcast-align with ICC or clang
        case "$CPU_ARCH" in
            # And don't use it on hppa, ia64, sparc, arm, since it's noisy there
            hppa | ia64 | sparc | arm)
            ;;
            *)
         _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wcast-align"
            ;;
        esac
     fi
 
-    _DEFINES_CXXFLAGS='-DMOZILLA_CLIENT -include $(topobjdir)/js/src/js-confdefs.h'
-    _USE_CPP_INCLUDE_FLAG=1
+    # Turn off some non-useful warnings that -Wall turns on.
+
+    # -Wno-invalid-offsetof - we use offsetof on non-POD types frequently
+    _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wno-invalid-offsetof"
+
+    # -Wno-inline-new-delete - we inline 'new' and 'delete' in mozalloc
+    # -Wno-unused-local-typedef - catches unused typedefs, which are commonly used in assertion macros
+    MOZ_CXX_SUPPORTS_WARNING(-Wno-, inline-new-delete, ac_cxx_has_wno_inline_new_delete)
+    MOZ_CXX_SUPPORTS_WARNING(-Wno-, unused-local-typedef, ac_cxx_has_wno_unused_local_typedef)
 
     # Recent clang and gcc support C++11 deleted functions without warnings if
     # compiling with -std=c++0x or -std=gnu++0x (or c++11 or gnu++11 in very new
     # versions).  We can't use -std=c++0x yet, so gcc's support must remain
     # unused.  But clang's warning can be disabled, so when compiling with clang
     # we use it to opt out of the warning, enabling (macro-encapsulated) use of
     # deleted function syntax.
     if test "$CLANG_CXX"; then
         _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wno-c++0x-extensions"
         MOZ_CXX_SUPPORTS_WARNING(-Wno-, extended-offsetof, ac_cxx_has_wno_extended_offsetof)
     fi
 
+    _DEFINES_CXXFLAGS='-DMOZILLA_CLIENT -include $(topobjdir)/js/src/js-confdefs.h'
+    _USE_CPP_INCLUDE_FLAG=1
+
 else
     _DEFINES_CXXFLAGS='-DMOZILLA_CLIENT -D_JS_CONFDEFS_H_ $(ACDEFINES)'
 fi
 
 dnl ========================================================
 dnl Checking for 64-bit OS
 dnl ========================================================
 if test "$COMPILE_ENVIRONMENT"; then
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -25,16 +25,17 @@
 #include "jsfun.h"
 #include "jsobj.h"
 #include "jsopcode.h"
 #include "jsscript.h"
 #include "jstypes.h"
 
 #include "asmjs/AsmJS.h"
 #include "builtin/ModuleObject.h"
+#include "builtin/SelfHostingDefines.h"
 #include "frontend/BytecodeCompiler.h"
 #include "frontend/FoldConstants.h"
 #include "frontend/ParseMaps.h"
 #include "frontend/TokenStream.h"
 #include "vm/Shape.h"
 
 #include "jsatominlines.h"
 #include "jsscriptinlines.h"
@@ -1588,16 +1589,19 @@ Parser<ParseHandler>::newFunction(Handle
                                   GeneratorKind generatorKind, HandleObject proto)
 {
     MOZ_ASSERT_IF(kind == Statement, atom != nullptr);
 
     RootedFunction fun(context);
 
     gc::AllocKind allocKind = gc::AllocKind::FUNCTION;
     JSFunction::Flags flags;
+#ifdef DEBUG
+    bool isGlobalSelfHostedBuiltin = false;
+#endif
     switch (kind) {
       case Expression:
         flags = (generatorKind == NotGenerator
                  ? JSFunction::INTERPRETED_LAMBDA
                  : JSFunction::INTERPRETED_LAMBDA_GENERATOR);
         break;
       case Arrow:
         flags = JSFunction::INTERPRETED_LAMBDA_ARROW;
@@ -1621,27 +1625,39 @@ Parser<ParseHandler>::newFunction(Handle
         allocKind = gc::AllocKind::FUNCTION_EXTENDED;
         break;
       case Setter:
       case SetterNoExpressionClosure:
         flags = JSFunction::INTERPRETED_SETTER;
         allocKind = gc::AllocKind::FUNCTION_EXTENDED;
         break;
       default:
+        MOZ_ASSERT(kind == Statement);
+#ifdef DEBUG
+        if (options().selfHostingMode && !pc->sc->isFunctionBox()) {
+            isGlobalSelfHostedBuiltin = true;
+            allocKind = gc::AllocKind::FUNCTION_EXTENDED;
+        }
+#endif
         flags = (generatorKind == NotGenerator
                  ? JSFunction::INTERPRETED_NORMAL
                  : JSFunction::INTERPRETED_GENERATOR);
     }
 
     fun = NewFunctionWithProto(context, nullptr, 0, flags, nullptr, atom, proto,
                                allocKind, TenuredObject);
     if (!fun)
         return nullptr;
-    if (options().selfHostingMode)
+    if (options().selfHostingMode) {
         fun->setIsSelfHostedBuiltin();
+#ifdef DEBUG
+        if (isGlobalSelfHostedBuiltin)
+            fun->setExtendedSlot(HAS_SELFHOSTED_CANONICAL_NAME_SLOT, BooleanValue(false));
+#endif
+    }
     return fun;
 }
 
 /*
  * WARNING: Do not call this function directly.
  * Call either MatchOrInsertSemicolonAfterExpression or
  * MatchOrInsertSemicolonAfterNonExpression instead, depending on context.
  */
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -653,26 +653,47 @@ GlobalObject::getIntrinsicsHolder(JSCont
     return intrinsicsHolder;
 }
 
 /* static */ bool
 GlobalObject::getSelfHostedFunction(JSContext* cx, Handle<GlobalObject*> global,
                                     HandlePropertyName selfHostedName, HandleAtom name,
                                     unsigned nargs, MutableHandleValue funVal)
 {
-    if (GlobalObject::maybeGetIntrinsicValue(cx, global, selfHostedName, funVal))
-        return true;
+    if (GlobalObject::maybeGetIntrinsicValue(cx, global, selfHostedName, funVal)) {
+        RootedFunction fun(cx, &funVal.toObject().as<JSFunction>());
+        if (fun->atom() == name)
+            return true;
 
-    JSFunction* fun =
-        NewScriptedFunction(cx, nargs, JSFunction::INTERPRETED_LAZY,
-                            name, gc::AllocKind::FUNCTION_EXTENDED, SingletonObject);
-    if (!fun)
+        if (fun->atom() == selfHostedName) {
+            // This function was initially cloned because it was called by
+            // other self-hosted code, so the clone kept its self-hosted name,
+            // instead of getting the name it's intended to have in content
+            // compartments. This can happen when a lazy builtin is initialized
+            // after self-hosted code for another builtin used the same
+            // function. In that case, we need to change the function's name,
+            // which is ok because it can't have been exposed to content
+            // before.
+            fun->initAtom(name);
+            return true;
+        }
+
+
+        // The function might be installed multiple times on the same or
+        // different builtins, under different property names, so its name
+        // might be neither "selfHostedName" nor "name". In that case, its
+        // canonical name must've been set using the `_SetCanonicalName`
+        // intrinsic.
+        cx->runtime()->assertSelfHostedFunctionHasCanonicalName(cx, selfHostedName);
+        return true;
+    }
+
+    RootedFunction fun(cx);
+    if (!cx->runtime()->createLazySelfHostedFunctionClone(cx, selfHostedName, name, nargs, &fun))
         return false;
-    fun->setIsSelfHostedBuiltin();
-    fun->setExtendedSlot(LAZY_FUNCTION_NAME_SLOT, StringValue(selfHostedName));
     funVal.setObject(*fun);
 
     return GlobalObject::addIntrinsicValue(cx, global, selfHostedName, funVal);
 }
 
 /* static */ bool
 GlobalObject::addIntrinsicValue(JSContext* cx, Handle<GlobalObject*> global,
                                 HandlePropertyName name, HandleValue value)
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -947,16 +947,20 @@ struct JSRuntime : public JS::shadow::Ru
      * Self-hosting state cloned on demand into other compartments. Shared with the parent
      * runtime if there is one.
      */
     js::NativeObject* selfHostingGlobal_;
 
     static js::GlobalObject*
     createSelfHostingGlobal(JSContext* cx);
 
+    bool getUnclonedSelfHostedValue(JSContext* cx, js::HandlePropertyName name,
+                                    js::MutableHandleValue vp);
+    JSFunction* getUnclonedSelfHostedFunction(JSContext* cx, js::HandlePropertyName name);
+
     /* Space for interpreter frames. */
     js::InterpreterStack interpreterStack_;
 
     js::jit::JitRuntime* createJitRuntime(JSContext* cx);
 
   public:
     js::jit::JitRuntime* getJitRuntime(JSContext* cx) {
         return jitRuntime_ ? jitRuntime_ : createJitRuntime(cx);
@@ -978,20 +982,24 @@ struct JSRuntime : public JS::shadow::Ru
     bool initSelfHosting(JSContext* cx);
     void finishSelfHosting();
     void markSelfHostingGlobal(JSTracer* trc);
     bool isSelfHostingGlobal(JSObject* global) {
         return global == selfHostingGlobal_;
     }
     bool isSelfHostingCompartment(JSCompartment* comp) const;
     bool isSelfHostingZone(const JS::Zone* zone) const;
+    bool createLazySelfHostedFunctionClone(JSContext* cx, js::HandlePropertyName selfHostedName,
+                                           js::HandleAtom name, unsigned nargs,
+                                           js::MutableHandleFunction fun);
     bool cloneSelfHostedFunctionScript(JSContext* cx, js::Handle<js::PropertyName*> name,
                                        js::Handle<JSFunction*> targetFun);
     bool cloneSelfHostedValue(JSContext* cx, js::Handle<js::PropertyName*> name,
                               js::MutableHandleValue vp);
+    void assertSelfHostedFunctionHasCanonicalName(JSContext* cx, js::HandlePropertyName name);
 
     //-------------------------------------------------------------------------
     // Locale information
     //-------------------------------------------------------------------------
 
     /*
      * Set the default locale for the ECMAScript Internationalization API
      * (Intl.Collator, Intl.NumberFormat, Intl.DateTimeFormat).
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -10,16 +10,17 @@
 #include "mozilla/Casting.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Maybe.h"
 
 #include "jscntxt.h"
 #include "jscompartment.h"
 #include "jsdate.h"
 #include "jsfriendapi.h"
+#include "jsfun.h"
 #include "jshashutil.h"
 #include "jsweakmap.h"
 #include "jswrapper.h"
 #include "selfhosted.out.h"
 
 #include "builtin/Intl.h"
 #include "builtin/MapObject.h"
 #include "builtin/ModuleObject.h"
@@ -534,16 +535,36 @@ intrinsic_ActiveFunction(JSContext* cx, 
 
     ScriptFrameIter iter(cx);
     MOZ_ASSERT(iter.isFunctionFrame());
     args.rval().setObject(*iter.callee(cx));
     return true;
 }
 
 static bool
+intrinsic_SetCanonicalName(JSContext* cx, unsigned argc, Value* vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    MOZ_ASSERT(args.length() == 2);
+
+    RootedFunction fun(cx, &args[0].toObject().as<JSFunction>());
+    MOZ_ASSERT(fun->isSelfHostedBuiltin());
+    RootedAtom atom(cx, AtomizeString(cx, args[1].toString()));
+    if (!atom)
+        return false;
+
+    fun->initAtom(atom);
+#ifdef DEBUG
+    fun->setExtendedSlot(HAS_SELFHOSTED_CANONICAL_NAME_SLOT, BooleanValue(true));
+#endif
+    args.rval().setUndefined();
+    return true;
+}
+
+static bool
 intrinsic_StarGeneratorObjectIsClosed(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     MOZ_ASSERT(args.length() == 1);
     MOZ_ASSERT(args[0].isObject());
 
     StarGeneratorObject* genObj = &args[0].toObject().as<StarGeneratorObject>();
     args.rval().setBoolean(genObj->isClosed());
@@ -1514,16 +1535,18 @@ static const JSFunctionSpec intrinsic_fu
     JS_FN("CallArrayIteratorMethodIfWrapped",
           CallNonGenericSelfhostedMethod<Is<ArrayIteratorObject>>,      2,0),
 
     JS_FN("NewListIterator",         intrinsic_NewListIterator,         0,0),
     JS_FN("CallListIteratorMethodIfWrapped",
           CallNonGenericSelfhostedMethod<Is<ListIteratorObject>>,       2,0),
     JS_FN("ActiveFunction",          intrinsic_ActiveFunction,          0,0),
 
+    JS_FN("_SetCanonicalName",       intrinsic_SetCanonicalName,        2,0),
+
     JS_INLINABLE_FN("IsArrayIterator",
                     intrinsic_IsInstanceOfBuiltin<ArrayIteratorObject>, 1,0,
                     IntrinsicIsArrayIterator),
     JS_INLINABLE_FN("IsMapIterator",
                     intrinsic_IsInstanceOfBuiltin<MapIteratorObject>,   1,0,
                     IntrinsicIsMapIterator),
     JS_INLINABLE_FN("IsStringIterator",
                     intrinsic_IsInstanceOfBuiltin<StringIteratorObject>, 1,0,
@@ -1980,18 +2003,20 @@ CloneObject(JSContext* cx, HandleNativeO
                                  : selfHostedFunction->getAllocKind();
         MOZ_ASSERT(!CanReuseScriptForClone(cx->compartment(), selfHostedFunction, cx->global()));
         Rooted<ClonedBlockObject*> globalLexical(cx, &cx->global()->lexicalScope());
         RootedObject staticGlobalLexical(cx, &globalLexical->staticBlock());
         clone = CloneFunctionAndScript(cx, selfHostedFunction, globalLexical,
                                        staticGlobalLexical, kind);
         // To be able to re-lazify the cloned function, its name in the
         // self-hosting compartment has to be stored on the clone.
-        if (clone && hasName)
-            clone->as<JSFunction>().setExtendedSlot(0, StringValue(selfHostedFunction->atom()));
+        if (clone && hasName) {
+            clone->as<JSFunction>().setExtendedSlot(LAZY_FUNCTION_NAME_SLOT,
+                                                    StringValue(selfHostedFunction->atom()));
+        }
     } else if (selfHostedObject->is<RegExpObject>()) {
         RegExpObject& reobj = selfHostedObject->as<RegExpObject>();
         RootedAtom source(cx, reobj.getSource());
         MOZ_ASSERT(source->isPermanentAtom());
         clone = RegExpObject::createNoStatics(cx, source, reobj.getFlags(), nullptr, cx->tempLifoAlloc());
     } else if (selfHostedObject->is<DateObject>()) {
         clone = JS::NewDateObject(cx, selfHostedObject->as<DateObject>().clippedTime());
     } else if (selfHostedObject->is<BooleanObject>()) {
@@ -2049,25 +2074,46 @@ CloneValue(JSContext* cx, HandleValue se
         vp.set(selfHostedValue);
     } else {
         MOZ_CRASH("Self-hosting CloneValue can't clone given value.");
     }
     return true;
 }
 
 bool
+JSRuntime::createLazySelfHostedFunctionClone(JSContext* cx, HandlePropertyName selfHostedName,
+                                             HandleAtom name, unsigned nargs,
+                                             MutableHandleFunction fun)
+{
+    RootedAtom funName(cx, name);
+    JSFunction* selfHostedFun = getUnclonedSelfHostedFunction(cx, selfHostedName);
+    if (!selfHostedFun)
+        return false;
+
+    if (selfHostedFun->atom() != selfHostedName) {
+        MOZ_ASSERT(selfHostedFun->getExtendedSlot(HAS_SELFHOSTED_CANONICAL_NAME_SLOT).toBoolean());
+        funName = selfHostedFun->atom();
+    }
+
+    fun.set(NewScriptedFunction(cx, nargs, JSFunction::INTERPRETED_LAZY,
+                                funName, gc::AllocKind::FUNCTION_EXTENDED, SingletonObject));
+    if (!fun)
+        return false;
+    fun->setIsSelfHostedBuiltin();
+    fun->setExtendedSlot(LAZY_FUNCTION_NAME_SLOT, StringValue(selfHostedName));
+    return true;
+}
+
+bool
 JSRuntime::cloneSelfHostedFunctionScript(JSContext* cx, HandlePropertyName name,
                                          HandleFunction targetFun)
 {
-    RootedId id(cx, NameToId(name));
-    RootedValue funVal(cx);
-    if (!GetUnclonedValue(cx, HandleNativeObject::fromMarkedLocation(&selfHostingGlobal_), id, &funVal))
+    RootedFunction sourceFun(cx, getUnclonedSelfHostedFunction(cx, name));
+    if (!sourceFun)
         return false;
-
-    RootedFunction sourceFun(cx, &funVal.toObject().as<JSFunction>());
     // JSFunction::generatorKind can't handle lazy self-hosted functions, so we make sure there
     // aren't any.
     MOZ_ASSERT(!sourceFun->isGenerator());
     MOZ_ASSERT(sourceFun->nargs() == targetFun->nargs());
     MOZ_ASSERT(targetFun->isExtended());
     MOZ_ASSERT(targetFun->isInterpretedLazy());
     MOZ_ASSERT(targetFun->isSelfHostedBuiltin());
 
@@ -2087,36 +2133,63 @@ JSRuntime::cloneSelfHostedFunctionScript
     MOZ_ASSERT(!targetFun->isInterpretedLazy());
 
     // The target function might have been relazified after its flags changed.
     targetFun->setFlags(targetFun->flags() | sourceFun->flags());
     return true;
 }
 
 bool
-JSRuntime::cloneSelfHostedValue(JSContext* cx, HandlePropertyName name, MutableHandleValue vp)
+JSRuntime::getUnclonedSelfHostedValue(JSContext* cx, HandlePropertyName name,
+                                      MutableHandleValue vp)
 {
     RootedId id(cx, NameToId(name));
+    return GetUnclonedValue(cx, HandleNativeObject::fromMarkedLocation(&selfHostingGlobal_), id, vp);
+}
+
+JSFunction*
+JSRuntime::getUnclonedSelfHostedFunction(JSContext* cx, HandlePropertyName name)
+{
     RootedValue selfHostedValue(cx);
-    if (!GetUnclonedValue(cx, HandleNativeObject::fromMarkedLocation(&selfHostingGlobal_), id, &selfHostedValue))
+    if (!getUnclonedSelfHostedValue(cx, name, &selfHostedValue))
+        return nullptr;
+
+    return &selfHostedValue.toObject().as<JSFunction>();
+}
+
+bool
+JSRuntime::cloneSelfHostedValue(JSContext* cx, HandlePropertyName name, MutableHandleValue vp)
+{
+    RootedValue selfHostedValue(cx);
+    if (!getUnclonedSelfHostedValue(cx, name, &selfHostedValue))
         return false;
 
     /*
      * We don't clone if we're operating in the self-hosting global, as that
      * means we're currently executing the self-hosting script while
      * initializing the runtime (see JSRuntime::initSelfHosting).
      */
     if (cx->global() == selfHostingGlobal_) {
         vp.set(selfHostedValue);
         return true;
     }
 
     return CloneValue(cx, selfHostedValue, vp);
 }
 
+void
+JSRuntime::assertSelfHostedFunctionHasCanonicalName(JSContext* cx, HandlePropertyName name)
+{
+#ifdef DEBUG
+    JSFunction* selfHostedFun = getUnclonedSelfHostedFunction(cx, name);
+    MOZ_ASSERT(selfHostedFun);
+    MOZ_ASSERT(selfHostedFun->getExtendedSlot(HAS_SELFHOSTED_CANONICAL_NAME_SLOT).toBoolean());
+#endif
+}
+
 JSFunction*
 js::SelfHostedFunction(JSContext* cx, HandlePropertyName propName)
 {
     RootedValue func(cx);
     if (!GlobalObject::getIntrinsicValue(cx, cx->global(), propName, &func))
         return nullptr;
 
     MOZ_ASSERT(func.isObject());
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -5731,25 +5731,25 @@ FrameLayerBuilder::PaintItems(nsTArray<C
   }
 }
 
 /**
  * Returns true if it is preferred to draw the list of display
  * items separately for each rect in the visible region rather
  * than clipping to a complex region.
  */
-static bool ShouldDrawRectsSeparately(gfxContext* aContext, DrawRegionClip aClip)
+static bool
+ShouldDrawRectsSeparately(DrawTarget* aDrawTarget, DrawRegionClip aClip)
 {
   if (!gfxPrefs::LayoutPaintRectsSeparately() ||
       aClip == DrawRegionClip::NONE) {
     return false;
   }
 
-  DrawTarget *dt = aContext->GetDrawTarget();
-  return !dt->SupportsRegionClipping();
+  return !aDrawTarget->SupportsRegionClipping();
 }
 
 static void DrawForcedBackgroundColor(DrawTarget& aDrawTarget,
                                       Layer* aLayer, nscolor
                                       aBackgroundColor)
 {
   if (NS_GET_A(aBackgroundColor) > 0) {
     LayerIntRect r = aLayer->GetVisibleRegion().GetBounds();
@@ -5816,17 +5816,18 @@ FrameLayerBuilder::DrawPaintedLayer(Pain
   }
 
 
   PaintedDisplayItemLayerUserData* userData =
     static_cast<PaintedDisplayItemLayerUserData*>
       (aLayer->GetUserData(&gPaintedDisplayItemLayerUserData));
   NS_ASSERTION(userData, "where did our user data go?");
 
-  bool shouldDrawRectsSeparately = ShouldDrawRectsSeparately(aContext, aClip);
+  bool shouldDrawRectsSeparately =
+    ShouldDrawRectsSeparately(&aDrawTarget, aClip);
 
   if (!shouldDrawRectsSeparately) {
     if (aClip == DrawRegionClip::DRAW) {
       gfxUtils::ClipToRegion(aContext, aRegionToDraw);
     }
 
     DrawForcedBackgroundColor(aDrawTarget, aLayer,
                               userData->mForcedBackgroundColor);
--- a/layout/base/nsCSSRendering.cpp
+++ b/layout/base/nsCSSRendering.cpp
@@ -924,20 +924,19 @@ nsCSSRendering::PaintOutline(nsPresConte
 
   // convert the border widths
   Float outlineWidths[4] = { Float(width / twipsPerPixel),
                              Float(width / twipsPerPixel),
                              Float(width / twipsPerPixel),
                              Float(width / twipsPerPixel) };
 
   // start drawing
-  gfxContext *ctx = aRenderingContext.ThebesContext();
 
   nsCSSBorderRenderer br(aPresContext->Type(),
-                         ctx->GetDrawTarget(),
+                         aRenderingContext.GetDrawTarget(),
                          oRect,
                          outlineStyles,
                          outlineWidths,
                          outlineRadii,
                          outlineColors,
                          nullptr,
                          bgColor);
   br.DrawBorders();
--- a/layout/generic/MathMLTextRunFactory.cpp
+++ b/layout/generic/MathMLTextRunFactory.cpp
@@ -773,17 +773,17 @@ MathMLTextRunFactory::RebuildTextRun(nsT
   }
   if (!child)
     return;
   // Copy potential linebreaks into child so they're preserved
   // (and also child will be shaped appropriately)
   NS_ASSERTION(convertedString.Length() == canBreakBeforeArray.Length(),
                "Dropped characters or break-before values somewhere!");
   child->SetPotentialLineBreaks(0, canBreakBeforeArray.Length(),
-      canBreakBeforeArray.Elements(), aRefContext);
+                                canBreakBeforeArray.Elements());
   if (transformedChild) {
     transformedChild->FinishSettingProperties(aRefContext, aMFR);
   }
 
   if (mergeNeeded) {
     // Now merge multiple characters into one multi-glyph character as required
     NS_ASSERTION(charsToMergeArray.Length() == child->GetLength(),
                  "source length mismatch");
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -970,31 +970,31 @@ public:
     BreakSink(gfxTextRun* aTextRun, gfxContext* aContext,
               uint32_t aOffsetIntoTextRun) :
                 mTextRun(aTextRun), mContext(aContext),
                 mOffsetIntoTextRun(aOffsetIntoTextRun) {}
 
     virtual void SetBreaks(uint32_t aOffset, uint32_t aLength,
                            uint8_t* aBreakBefore) override {
       if (mTextRun->SetPotentialLineBreaks(aOffset + mOffsetIntoTextRun, aLength,
-                                           aBreakBefore, mContext)) {
+                                           aBreakBefore)) {
         // Be conservative and assume that some breaks have been set
         mTextRun->ClearFlagBits(nsTextFrameUtils::TEXT_NO_BREAKS);
       }
     }
     
     virtual void SetCapitalization(uint32_t aOffset, uint32_t aLength,
                                    bool* aCapitalize) override {
       MOZ_ASSERT(mTextRun->GetFlags() & nsTextFrameUtils::TEXT_IS_TRANSFORMED,
                  "Text run should be transformed!");
       if (mTextRun->GetFlags() & nsTextFrameUtils::TEXT_IS_TRANSFORMED) {
         nsTransformedTextRun* transformedTextRun =
           static_cast<nsTransformedTextRun*>(mTextRun);
         transformedTextRun->SetCapitalization(aOffset + mOffsetIntoTextRun, aLength,
-                                              aCapitalize, mContext);
+                                              aCapitalize);
       }
     }
 
     void Finish(gfxMissingFontRecorder* aMFR) {
       MOZ_ASSERT(!(mTextRun->GetFlags() &
                    (gfxTextRunFactory::TEXT_UNUSED_FLAGS |
                     nsTextFrameUtils::TEXT_UNUSED_FLAG)),
                    "Flag set that should never be set! (memory safety error?)");
--- a/layout/generic/nsTextRunTransformations.cpp
+++ b/layout/generic/nsTextRunTransformations.cpp
@@ -52,35 +52,33 @@ nsTransformedTextRun::Create(const gfxTe
   return new (storage) nsTransformedTextRun(aParams, aFactory, aFontGroup,
                                             aString, aLength,
                                             aFlags, Move(aStyles),
                                             aOwnsFactory);
 }
 
 void
 nsTransformedTextRun::SetCapitalization(uint32_t aStart, uint32_t aLength,
-                                        bool* aCapitalization,
-                                        gfxContext* aRefContext)
+                                        bool* aCapitalization)
 {
   if (mCapitalize.IsEmpty()) {
     if (!mCapitalize.AppendElements(GetLength()))
       return;
     memset(mCapitalize.Elements(), 0, GetLength()*sizeof(bool));
   }
   memcpy(mCapitalize.Elements() + aStart, aCapitalization, aLength*sizeof(bool));
   mNeedsRebuild = true;
 }
 
 bool
 nsTransformedTextRun::SetPotentialLineBreaks(uint32_t aStart, uint32_t aLength,
-                                             uint8_t* aBreakBefore,
-                                             gfxContext* aRefContext)
+                                             uint8_t* aBreakBefore)
 {
-  bool changed = gfxTextRun::SetPotentialLineBreaks(aStart, aLength,
-      aBreakBefore, aRefContext);
+  bool changed =
+    gfxTextRun::SetPotentialLineBreaks(aStart, aLength, aBreakBefore);
   if (changed) {
     mNeedsRebuild = true;
   }
   return changed;
 }
 
 size_t
 nsTransformedTextRun::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf)
@@ -643,17 +641,17 @@ nsCaseTransformTextRunFactory::RebuildTe
   }
   if (!child)
     return;
   // Copy potential linebreaks into child so they're preserved
   // (and also child will be shaped appropriately)
   NS_ASSERTION(convertedString.Length() == canBreakBeforeArray.Length(),
                "Dropped characters or break-before values somewhere!");
   child->SetPotentialLineBreaks(0, canBreakBeforeArray.Length(),
-      canBreakBeforeArray.Elements(), aRefContext);
+                                canBreakBeforeArray.Elements());
   if (transformedChild) {
     transformedChild->FinishSettingProperties(aRefContext, aMFR);
   }
 
   if (mergeNeeded) {
     // Now merge multiple characters into one multi-glyph character as required
     // and deal with skipping deleted accent chars
     NS_ASSERTION(charsToMergeArray.Length() == child->GetLength(),
--- a/layout/generic/nsTextRunTransformations.h
+++ b/layout/generic/nsTextRunTransformations.h
@@ -124,21 +124,19 @@ public:
 
   ~nsTransformedTextRun() {
     if (mOwnsFactory) {
       delete mFactory;
     }
   }
   
   void SetCapitalization(uint32_t aStart, uint32_t aLength,
-                         bool* aCapitalization,
-                         gfxContext* aRefContext);
+                         bool* aCapitalization);
   virtual bool SetPotentialLineBreaks(uint32_t aStart, uint32_t aLength,
-                                        uint8_t* aBreakBefore,
-                                        gfxContext* aRefContext);
+                                      uint8_t* aBreakBefore);
   /**
    * Called after SetCapitalization and SetPotentialLineBreaks
    * are done and before we request any data from the textrun. Also always
    * called after a Create.
    */
   void FinishSettingProperties(gfxContext* aRefContext,
                                gfxMissingFontRecorder* aMFR)
   {
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/1234758-1-ref.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<style>
+button { -moz-appearance: none; }
+button::-moz-focus-inner { border-width: 2px; }
+</style>
+<body>
+<button>hello</button>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/1234758-1.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<style>
+button { -moz-appearance: none; }
+</style>
+<body onload="document.querySelector('button').focus()">
+<button>hello</button>
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1939,8 +1939,9 @@ fuzzy(1,74) fuzzy-if(gtkWidget,6,79) == 
 == 1209603-1.html 1209603-1-ref.html
 == 1209994-1.html 1209994-1-ref.html
 == 1209994-2.html 1209994-2-ref.html
 == 1209994-3.html 1209994-3-ref.html
 == 1209994-4.html 1209994-4-ref.html
 == 1222226-1.html 1222226-1-ref.html
 pref(layout.css.overflow-clip-box.enabled,true) == 1226278.html 1226278-ref.html
 == 1230466.html about:blank
+# pref(browser.display.focus_ring_width,2) == 1234758-1.html 1234758-1-ref.html # disabled until a followup fix in bug 1234758
--- a/layout/style/noframes.css
+++ b/layout/style/noframes.css
@@ -1,16 +1,13 @@
 /* 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/. */
 
 /* This sheet is added to the style set for documents with frames disabled */
 
-/* Until bug 1194856 is fixed, if you update this file you should also update
-   the data: URL in nsLayoutStylesheetCache::NoFramesSheet(). */
-
 noframes {
   display: block;
 }
 
 frame, frameset, iframe {
   display: none !important;
 }
--- a/layout/style/noscript.css
+++ b/layout/style/noscript.css
@@ -1,12 +1,9 @@
 /* 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/. */
 
 /* This sheet is added to the style set for documents with script disabled */
 
-/* Until bug 1194856 is fixed, if you update this file you should also update
-   the data: URL in nsLayoutStylesheetCache::NoScriptSheet(). */
-
 noscript {
   display: none !important;
 }
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -14656,18 +14656,17 @@ CSSParserImpl::ParseTextEmphasis()
   nsCSSValue values[numProps];
 
   int32_t found = ParseChoice(values, kTextEmphasisIDs, numProps);
   if (found < 1) {
     return false;
   }
 
   if (!(found & 1)) { // Provide default text-emphasis-style
-    values[0].SetIntValue(NS_STYLE_TEXT_EMPHASIS_STYLE_NONE,
-                          eCSSUnit_Enumerated);
+    values[0].SetNoneValue();
   }
   if (!(found & 2)) { // Provide default text-emphasis-color
     values[1].SetIntValue(NS_COLOR_CURRENTCOLOR, eCSSUnit_EnumColor);
   }
 
   for (int32_t index = 0; index < numProps; index++) {
     AppendValue(kTextEmphasisIDs[index], values[index]);
   }
--- a/layout/style/nsLayoutStylesheetCache.cpp
+++ b/layout/style/nsLayoutStylesheetCache.cpp
@@ -188,43 +188,30 @@ nsLayoutStylesheetCache::CounterStylesSh
 }
 
 CSSStyleSheet*
 nsLayoutStylesheetCache::NoScriptSheet()
 {
   EnsureGlobal();
 
   if (!gStyleCache->mNoScriptSheet) {
-    // If you update the data: URL, also update noscript.css  (See bug 1194856.)
-    LoadSheetURL(
-#ifdef RELEASE_BUILD
-                 "data:text/css,noscript { display%3A none !important%3B }",
-#else
-                 "resource://gre-resources/noscript.css",
-#endif
+    LoadSheetURL("resource://gre-resources/noscript.css",
                  gStyleCache->mNoScriptSheet, eAgentSheetFeatures);
   }
 
   return gStyleCache->mNoScriptSheet;
 }
 
 CSSStyleSheet*
 nsLayoutStylesheetCache::NoFramesSheet()
 {
   EnsureGlobal();
 
   if (!gStyleCache->mNoFramesSheet) {
-    // If you update the data: URL, also update noframes.css  (See bug 1194856.)
-    LoadSheetURL(
-#ifdef RELEASE_BUILD
-                 "data:text/css,noframes { display%3A block%3B } "
-                 "frame%2C frameset%2C iframe { display%3A none !important%3B }",
-#else
-                 "resource://gre-resources/noframes.css",
-#endif
+    LoadSheetURL("resource://gre-resources/noframes.css",
                  gStyleCache->mNoFramesSheet, eAgentSheetFeatures);
   }
 
   return gStyleCache->mNoFramesSheet;
 }
 
 /* static */ CSSStyleSheet*
 nsLayoutStylesheetCache::ChromePreferenceSheet(nsPresContext* aPresContext)
@@ -812,129 +799,116 @@ nsLayoutStylesheetCache::InvalidatePrefe
   if (!gStyleCache) {
     return;
   }
 
   gStyleCache->mContentPreferenceSheet = nullptr;
   gStyleCache->mChromePreferenceSheet = nullptr;
 }
 
-/* static */ void
-nsLayoutStylesheetCache::AppendPreferenceRule(CSSStyleSheet* aSheet,
-                                              const nsAString& aString)
-{
-  uint32_t result;
-  aSheet->InsertRuleInternal(aString, aSheet->StyleRuleCount(), &result);
-}
-
-/* static */ void
-nsLayoutStylesheetCache::AppendPreferenceColorRule(CSSStyleSheet* aSheet,
-                                                   const char* aString,
-                                                   nscolor aColor)
-{
-  nsAutoString rule;
-  rule.AppendPrintf(
-      aString, NS_GET_R(aColor), NS_GET_G(aColor), NS_GET_B(aColor));
-  AppendPreferenceRule(aSheet, rule);
-}
-
 void
 nsLayoutStylesheetCache::BuildPreferenceSheet(RefPtr<CSSStyleSheet>& aSheet,
                                               nsPresContext* aPresContext)
 {
   aSheet = new CSSStyleSheet(CORS_NONE, mozilla::net::RP_Default);
 
   nsCOMPtr<nsIURI> uri;
   NS_NewURI(getter_AddRefs(uri), "about:PreferenceStyleSheet", nullptr);
   MOZ_ASSERT(uri, "URI creation shouldn't fail");
 
   aSheet->SetURIs(uri, uri, uri);
   aSheet->SetComplete();
 
-  AppendPreferenceRule(aSheet,
-      NS_LITERAL_STRING("@namespace url(http://www.w3.org/1999/xhtml);"));
-  AppendPreferenceRule(aSheet,
-      NS_LITERAL_STRING("@namespace svg url(http://www.w3.org/2000/svg);"));
+  static const uint32_t kPreallocSize = 1024;
+
+  nsString sheetText;
+  sheetText.SetCapacity(kPreallocSize);
+
+#define NS_GET_R_G_B(color_) \
+  NS_GET_R(color_), NS_GET_G(color_), NS_GET_B(color_)
+
+  sheetText.AppendLiteral(
+      "@namespace url(http://www.w3.org/1999/xhtml);\n"
+      "@namespace svg url(http://www.w3.org/2000/svg);\n");
 
   // Rules for link styling.
+  nscolor linkColor = aPresContext->DefaultLinkColor();
+  nscolor activeColor = aPresContext->DefaultActiveLinkColor();
+  nscolor visitedColor = aPresContext->DefaultVisitedLinkColor();
 
-  AppendPreferenceColorRule(aSheet,
-      "*|*:link { color: #%02x%02x%02x; }",
-      aPresContext->DefaultLinkColor());
-  AppendPreferenceColorRule(aSheet,
-      "*|*:-moz-any-link:active { color: #%02x%02x%02x; }",
-      aPresContext->DefaultActiveLinkColor());
-  AppendPreferenceColorRule(aSheet,
-      "*|*:visited { color: #%02x%02x%02x; }",
-      aPresContext->DefaultVisitedLinkColor());
+  sheetText.AppendPrintf(
+      "*|*:link { color: #%02x%02x%02x; }\n"
+      "*|*:-moz-any-link:active { color: #%02x%02x%02x; }\n"
+      "*|*:visited { color: #%02x%02x%02x; }\n",
+      NS_GET_R_G_B(linkColor),
+      NS_GET_R_G_B(activeColor),
+      NS_GET_R_G_B(visitedColor));
 
-  AppendPreferenceRule(aSheet,
-      aPresContext->GetCachedBoolPref(kPresContext_UnderlineLinks) ?
-        NS_LITERAL_STRING(
-            "*|*:-moz-any-link:not(svg|a) { text-decoration: underline; }") :
-        NS_LITERAL_STRING(
-            "*|*:-moz-any-link{ text-decoration: none; }"));
+  bool underlineLinks =
+    aPresContext->GetCachedBoolPref(kPresContext_UnderlineLinks);
+  sheetText.AppendPrintf(
+      "*|*:-moz-any-link%s { text-decoration: %s; }\n",
+      underlineLinks ? ":not(svg|a)" : "",
+      underlineLinks ? "underline" : "none");
 
   // Rules for focus styling.
 
   bool focusRingOnAnything = aPresContext->GetFocusRingOnAnything();
   uint8_t focusRingWidth = aPresContext->FocusRingWidth();
   uint8_t focusRingStyle = aPresContext->GetFocusRingStyle();
 
   if ((focusRingWidth != 1 && focusRingWidth <= 4) || focusRingOnAnything) {
     if (focusRingWidth != 1) {
       // If the focus ring width is different from the default, fix buttons
       // with rings.
-      nsString rule;
-      rule.AppendPrintf(
+      sheetText.AppendPrintf(
           "button::-moz-focus-inner, input[type=\"reset\"]::-moz-focus-inner, "
           "input[type=\"button\"]::-moz-focus-inner, "
           "input[type=\"submit\"]::-moz-focus-inner { "
           "padding: 1px 2px 1px 2px; "
-          "border: %d %s transparent !important; }",
+          "border: %dpx %s transparent !important; }\n",
           focusRingWidth,
-          focusRingWidth == 0 ? (const char*) "solid" : (const char*) "dotted");
-      AppendPreferenceRule(aSheet, rule);
+          focusRingStyle == 0 ? "solid" : "dotted");
 
-      // NS_LITERAL_STRING doesn't work with concatenated string literals, hence
-      // the newline escaping.
-      AppendPreferenceRule(aSheet, NS_LITERAL_STRING("\
-button:focus::-moz-focus-inner, \
-input[type=\"reset\"]:focus::-moz-focus-inner, \
-input[type=\"button\"]:focus::-moz-focus-inner, \
-input[type=\"submit\"]:focus::-moz-focus-inner { \
-border-color: ButtonText !important; }"));
+      sheetText.AppendLiteral(
+          "button:focus::-moz-focus-inner, "
+          "input[type=\"reset\"]:focus::-moz-focus-inner, "
+          "input[type=\"button\"]:focus::-moz-focus-inner, "
+          "input[type=\"submit\"]:focus::-moz-focus-inner { "
+          "border-color: ButtonText !important; }\n");
     }
 
-    nsString rule;
-    if (focusRingOnAnything) {
-      rule.AppendLiteral(":focus");
-    } else {
-      rule.AppendLiteral("*|*:link:focus, *|*:visited:focus");
-    }
-    rule.AppendPrintf(" { outline: %dpx ", focusRingWidth);
-    if (focusRingStyle == 0) { // solid
-      rule.AppendLiteral("solid -moz-mac-focusring !important; "
-                         "-moz-outline-radius: 3px; outline-offset: 1px; }");
-    } else {
-      rule.AppendLiteral("dotted WindowText !important; }");
-    }
-    AppendPreferenceRule(aSheet, rule);
+    sheetText.AppendPrintf(
+        "%s { outline: %dpx %s !important; %s}\n",
+        focusRingOnAnything ?
+          ":focus" :
+          "*|*:link:focus, *|*:visited:focus",
+        focusRingWidth,
+        focusRingStyle == 0 ? // solid
+          "solid -moz-mac-focusring" : "dotted WindowText",
+        focusRingStyle == 0 ? // solid
+          "-moz-outline-radius: 3px; outline-offset: 1px; " : "");
   }
 
   if (aPresContext->GetUseFocusColors()) {
-    nsString rule;
     nscolor focusText = aPresContext->FocusTextColor();
     nscolor focusBG = aPresContext->FocusBackgroundColor();
-    rule.AppendPrintf(
+    sheetText.AppendPrintf(
         "*:focus, *:focus > font { color: #%02x%02x%02x !important; "
-        "background-color: #%02x%02x%02x !important; }",
-        NS_GET_R(focusText), NS_GET_G(focusText), NS_GET_B(focusText),
-        NS_GET_R(focusBG), NS_GET_G(focusBG), NS_GET_B(focusBG));
-    AppendPreferenceRule(aSheet, rule);
+        "background-color: #%02x%02x%02x !important; }\n",
+        NS_GET_R_G_B(focusText),
+        NS_GET_R_G_B(focusBG));
   }
+
+  NS_ASSERTION(sheetText.Length() <= kPreallocSize,
+               "kPreallocSize should be big enough to build preference style "
+               "sheet without reallocation");
+
+  aSheet->ReparseSheet(sheetText);
+
+#undef NS_GET_R_G_B
 }
 
 mozilla::StaticRefPtr<nsLayoutStylesheetCache>
 nsLayoutStylesheetCache::gStyleCache;
 
 mozilla::css::Loader*
 nsLayoutStylesheetCache::gCSSLoader = nullptr;
--- a/layout/style/nsLayoutStylesheetCache.h
+++ b/layout/style/nsLayoutStylesheetCache.h
@@ -72,20 +72,16 @@ private:
                             RefPtr<mozilla::CSSStyleSheet>& aSheet,
                             mozilla::css::SheetParsingMode aParsingMode);
   static void LoadSheet(nsIURI* aURI, RefPtr<mozilla::CSSStyleSheet>& aSheet,
                         mozilla::css::SheetParsingMode aParsingMode);
   static void InvalidateSheet(RefPtr<mozilla::CSSStyleSheet>& aSheet);
   static void DependentPrefChanged(const char* aPref, void* aData);
   void BuildPreferenceSheet(RefPtr<mozilla::CSSStyleSheet>& aSheet,
                             nsPresContext* aPresContext);
-  static void AppendPreferenceRule(mozilla::CSSStyleSheet* aSheet,
-                                   const nsAString& aRule);
-  static void AppendPreferenceColorRule(mozilla::CSSStyleSheet* aSheet,
-                                        const char* aString, nscolor aColor);
 
   static mozilla::StaticRefPtr<nsLayoutStylesheetCache> gStyleCache;
   static mozilla::css::Loader* gCSSLoader;
   RefPtr<mozilla::CSSStyleSheet> mChromePreferenceSheet;
   RefPtr<mozilla::CSSStyleSheet> mContentEditableSheet;
   RefPtr<mozilla::CSSStyleSheet> mContentPreferenceSheet;
   RefPtr<mozilla::CSSStyleSheet> mCounterStylesSheet;
   RefPtr<mozilla::CSSStyleSheet> mDesignModeSheet;
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -1741,17 +1741,18 @@ struct nsStyleText {
     this->~nsStyleText();
     aContext->PresShell()->
       FreeByObjectID(mozilla::eArenaObjectID_nsStyleText, this);
   }
 
   nsChangeHint CalcDifference(const nsStyleText& aOther) const;
   static nsChangeHint MaxDifference() {
     return NS_STYLE_HINT_FRAMECHANGE |
-           nsChangeHint_UpdateSubtreeOverflow;
+           nsChangeHint_UpdateSubtreeOverflow |
+           nsChangeHint_NeutralChange;
   }
   static nsChangeHint DifferenceAlwaysHandledForDescendants() {
     // CalcDifference never returns the reflow hints that are sometimes
     // handled for descendants as hints not handled for descendants.
     return nsChangeHint_NeedReflow |
            nsChangeHint_ReflowChangesSizeOrPosition |
            nsChangeHint_ClearAncestorIntrinsics;
   }
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -7050,27 +7050,28 @@ if (IsCSSPropertyPrefEnabled("layout.css
   gCSSProperties["clear"].invalid_values.push("inline-end");
 }
 
 if (IsCSSPropertyPrefEnabled("layout.css.text-emphasis.enabled")) {
   gCSSProperties["text-emphasis"] = {
     domProp: "textEmphasis",
     inherited: true,
     type: CSS_TYPE_TRUE_SHORTHAND,
+    prerequisites: { "color": "black" },
     subproperties: [ "text-emphasis-style", "text-emphasis-color" ],
-    initial_values: [ "none currentColor", "currentColor none", "none", "currentColor" ],
-    other_values: [ "filled dot black", "#f00 circle open", "sesame filled rgba(0,0,255,0.5)", "red", "none black", "green none", "currentColor filled", "currentColor open" ],
+    initial_values: [ "none currentColor", "currentColor none", "none", "currentColor", "none black" ],
+    other_values: [ "filled dot black", "#f00 circle open", "sesame filled rgba(0,0,255,0.5)", "red", "green none", "currentColor filled", "currentColor open" ],
     invalid_values: [ "filled black dot", "filled filled red", "open open circle #000", "circle dot #f00", "rubbish" ]
   };
   gCSSProperties["text-emphasis-color"] = {
     domProp: "textEmphasisColor",
     inherited: true,
     type: CSS_TYPE_LONGHAND,
     prerequisites: { "color": "black" },
-    initial_values: [ "currentColor", "-moz-use-text-color" ],
+    initial_values: [ "currentColor", "black", "rgb(0,0,0)" ],
     other_values: [ "red", "rgba(255,255,255,0.5)", "transparent" ],
     invalid_values: [ "#0", "#00", "#0000", "#00000", "#0000000", "#00000000", "#000000000", "000000", "ff00ff", "rgb(255,xxx,255)" ]
   };
   gCSSProperties["text-emphasis-position"] = {
     domProp: "textEmphasisPosition",
     inherited: true,
     type: CSS_TYPE_LONGHAND,
     initial_values: [ "over right", "right over" ],
--- a/layout/style/test/test_transitions_per_property.html
+++ b/layout/style/test/test_transitions_per_property.html
@@ -230,16 +230,18 @@ var supported_properties = {
     // NOTE: when calc() is supported on 'stroke-width', we should add
     // test_length_percent_calc_transition.
     "stroke-width": [ test_length_transition_svg, test_percent_transition,
                       test_length_clamped_svg, test_percent_clamped ],
     "text-decoration": [ test_color_shorthand_transition,
                          test_border_color_shorthand_transition ],
     "text-decoration-color": [ test_color_transition,
                                test_border_color_transition ],
+    "text-emphasis-color": [ test_color_transition,
+                             test_border_color_transition ],
     "text-indent": [ test_length_transition, test_percent_transition,
                      test_length_percent_calc_transition,
                      test_length_unclamped, test_percent_unclamped ],
     "text-shadow": [ test_shadow_transition ],
     "top": [ test_length_transition, test_percent_transition,
              test_length_percent_calc_transition,
              test_length_unclamped, test_percent_unclamped ],
     "transform": [ test_transform_transition ],
--- a/layout/xul/nsTextBoxFrame.cpp
+++ b/layout/xul/nsTextBoxFrame.cpp
@@ -471,17 +471,16 @@ nsTextBoxFrame::DrawText(nsRenderingCont
             (wm.IsVerticalRL() ? aTextRect.width - ascent : ascent));
       baselinePt.y = aTextRect.y;
     } else {
       baselinePt.x = aTextRect.x;
       baselinePt.y =
         presContext->RoundAppUnitsToNearestDevPixels(aTextRect.y + ascent);
     }
 
-    RefPtr<gfxContext> ctx = aRenderingContext.ThebesContext();
     Point pt(presContext->AppUnitsToGfxUnits(aTextRect.x),
              presContext->AppUnitsToGfxUnits(aTextRect.y));
     Float width = presContext->AppUnitsToGfxUnits(aTextRect.width);
     gfxFloat ascentPixel = presContext->AppUnitsToGfxUnits(ascent);
     Float xInFrame = Float(PresContext()->AppUnitsToGfxUnits(mTextDrawRect.x));
     gfxRect dirtyRect(presContext->AppUnitsToGfxUnits(aDirtyRect));
 
     // XXX todo: vertical-mode support for decorations not tested yet,
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -2408,17 +2408,17 @@ pref("layout.css.font-loading-api.enable
 // Should stray control characters be rendered visibly?
 #ifdef RELEASE_BUILD
 pref("layout.css.control-characters.visible", false);
 #else
 pref("layout.css.control-characters.visible", true);
 #endif
 
 // Is support for text-emphasis enabled?
-pref("layout.css.text-emphasis.enabled", false);
+pref("layout.css.text-emphasis.enabled", true);
 
 // pref for which side vertical scrollbars should be on
 // 0 = end-side in UI direction
 // 1 = end-side in document/content direction
 // 2 = right
 // 3 = left
 pref("layout.scrollbar.side", 0);
 
--- a/xpcom/base/nsMemoryReporterManager.cpp
+++ b/xpcom/base/nsMemoryReporterManager.cpp
@@ -148,16 +148,17 @@ ResidentFastDistinguishedAmount(int64_t*
 
 #define HAVE_RESIDENT_UNIQUE_REPORTER 1
 static nsresult
 ResidentUniqueDistinguishedAmount(int64_t* aN)
 {
   return GetProcSelfSmapsPrivate(aN);
 }
 
+#ifdef HAVE_MALLINFO
 #define HAVE_SYSTEM_HEAP_REPORTER 1
 nsresult
 SystemHeapSize(int64_t* aSizeOut)
 {
     struct mallinfo info = mallinfo();
 
     // The documentation in the glibc man page makes it sound like |uordblks|
     // would suffice, but that only gets the small allocations that are put in
@@ -167,16 +168,17 @@ SystemHeapSize(int64_t* aSizeOut)
     // The fields in |struct mallinfo| are all |int|, <sigh>, so it is
     // unreliable if memory usage gets high. However, the system heap size on
     // Linux should usually be zero (so long as jemalloc is enabled) so that
     // shouldn't be a problem. Nonetheless, cast the |int|s to |size_t| before
     // adding them to provide a small amount of extra overflow protection.
     *aSizeOut = size_t(info.hblkhd) + size_t(info.uordblks);
     return NS_OK;
 }
+#endif
 
 #elif defined(__DragonFly__) || defined(__FreeBSD__) \
     || defined(__NetBSD__) || defined(__OpenBSD__) \
     || defined(__FreeBSD_kernel__)
 
 #include <sys/param.h>
 #include <sys/sysctl.h>
 #if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)