Merge inbound to mozilla-central. a=merge
authorBogdan Tara <btara@mozilla.com>
Fri, 16 Nov 2018 11:47:51 +0200
changeset 446723 4d6d3403eb6b015ebd2e6949d57dd518d07d024f
parent 446711 02f799e4c3da742224ee54e1389c683d83779470 (current diff)
parent 446722 a424be1d8a667c799cbe4f337626591b1087f14d (diff)
child 446733 1209d6c6f4f78f6f7b7d07a96e008985d119493a
child 446756 9ea67e7f7a0f4c37a58202346634b771ed360986
push id35047
push userbtara@mozilla.com
push dateFri, 16 Nov 2018 09:48:23 +0000
treeherdermozilla-central@4d6d3403eb6b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone65.0a1
first release with
nightly linux32
4d6d3403eb6b / 65.0a1 / 20181116100115 / files
nightly linux64
4d6d3403eb6b / 65.0a1 / 20181116100115 / files
nightly mac
4d6d3403eb6b / 65.0a1 / 20181116100115 / files
nightly win32
4d6d3403eb6b / 65.0a1 / 20181116100115 / files
nightly win64
4d6d3403eb6b / 65.0a1 / 20181116100115 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to mozilla-central. a=merge
devtools/client/framework/toolbox-process-window.js
layout/base/PresShell.cpp
--- a/devtools/client/framework/toolbox-process-window.js
+++ b/devtools/client/framework/toolbox-process-window.js
@@ -99,16 +99,17 @@ var connect = async function() {
 };
 
 // Certain options should be toggled since we can assume chrome debugging here
 function setPrefDefaults() {
   Services.prefs.setBoolPref("devtools.inspector.showUserAgentStyles", true);
   Services.prefs.setBoolPref("devtools.performance.ui.show-platform-data", true);
   Services.prefs.setBoolPref("devtools.inspector.showAllAnonymousContent", true);
   Services.prefs.setBoolPref("browser.dom.window.dump.enabled", true);
+  Services.prefs.setBoolPref("devtools.console.stdout.chrome", true);
   Services.prefs.setBoolPref("devtools.command-button-noautohide.enabled", true);
   // Bug 1225160 - Using source maps with browser debugging can lead to a crash
   Services.prefs.setBoolPref("devtools.debugger.source-maps-enabled", false);
   Services.prefs.setBoolPref("devtools.preference.new-panel-enabled", false);
   Services.prefs.setBoolPref("layout.css.emulate-moz-box-with-flex", false);
 
   Services.prefs.setBoolPref("devtools.performance.enabled", false);
 }
--- a/devtools/docs/getting-started/development-profiles.md
+++ b/devtools/docs/getting-started/development-profiles.md
@@ -24,16 +24,18 @@ Next time you start Firefox with `./mach
 
 ## Enable additional logging
 
 You can change the value of these preferences by going to `about:config`:
 
 | Preference name | Value | Comments |
 | --------------- | --------------- | -------- |
 | `browser.dom.window.dump.enabled` | `true` | Adds global `dump` function to log strings to `stdout` |
+| `devtools.console.stdout.chrome` | `true` | Allows console API to write to `stdout` when used by chrome content |
+| `devtools.console.stdout.content` | `true` | Allows console API to write to `stdout` when used by content |
 | `devtools.debugger.log` (*) | `true` | Dump packets sent over remote debugging protocol to `stdout`.<br /><br />The [remote protocol inspector add-on](https://github.com/firebug/rdp-inspector/wiki) might be useful too. |
 | `devtools.dump.emit` (*) | `true` | Log event notifications from the EventEmitter class<br />(found at `devtools/shared/event-emitter.js`). |
 
 Preferences marked with a (`*`) also require `browser.dom.window.dump.enabled` in order to work. You might not want to enable *all* of those all the time, as they can cause the output to be way too verbose, but they might be useful if you're working on a server actor, for example<!--TODO link to actors doc-->.
 
 Restart the browser to apply configuration changes.
 
 ## Enable remote debugging and the Browser Toolbox
--- a/devtools/server/actors/replay/debugger.js
+++ b/devtools/server/actors/replay/debugger.js
@@ -238,37 +238,44 @@ ReplayDebugger.prototype = {
     const data = this._sendRequest({ type: "findSources" });
     return data.map(source => this._addSource(source));
   },
 
   /////////////////////////////////////////////////////////
   // Object methods
   /////////////////////////////////////////////////////////
 
-  _getObject(id) {
+  // Objects which |forConsole| is set are objects that were logged in console
+  // messages, and had their properties recorded so that they can be inspected
+  // without switching to a replaying child.
+  _getObject(id, forConsole) {
     if (id && !this._objects[id]) {
       const data = this._sendRequest({ type: "getObject", id });
       switch (data.kind) {
       case "Object":
-        this._objects[id] = new ReplayDebuggerObject(this, data);
+        this._objects[id] = new ReplayDebuggerObject(this, data, forConsole);
         break;
       case "Environment":
         this._objects[id] = new ReplayDebuggerEnvironment(this, data);
         break;
       default:
         ThrowError("Unknown object kind");
       }
     }
-    return this._objects[id];
+    const rv = this._objects[id];
+    if (forConsole) {
+      rv._forConsole = true;
+    }
+    return rv;
   },
 
-  _convertValue(value) {
-    if (value && typeof value == "object") {
+  _convertValue(value, forConsole) {
+    if (isNonNullObject(value)) {
       if (value.object) {
-        return this._getObject(value.object);
+        return this._getObject(value.object, forConsole);
       } else if (value.special == "undefined") {
         return undefined;
       } else if (value.special == "NaN") {
         return NaN;
       } else if (value.special == "Infinity") {
         return Infinity;
       } else if (value.special == "-Infinity") {
         return -Infinity;
@@ -327,17 +334,18 @@ ReplayDebugger.prototype = {
   // Console Message methods
   /////////////////////////////////////////////////////////
 
   _convertConsoleMessage(message) {
     // Console API message arguments need conversion to debuggee values, but
     // other contents of the message can be left alone.
     if (message.messageType == "ConsoleAPI" && message.arguments) {
       for (let i = 0; i < message.arguments.length; i++) {
-        message.arguments[i] = this._convertValue(message.arguments[i]);
+        message.arguments[i] = this._convertValue(message.arguments[i],
+                                                  /* forConsole = */ true);
       }
     }
     return message;
   },
 
   /////////////////////////////////////////////////////////
   // Handlers
   /////////////////////////////////////////////////////////
@@ -492,17 +500,17 @@ ReplayDebuggerScriptSource.prototype = {
 // ReplayDebuggerFrame
 ///////////////////////////////////////////////////////////////////////////////
 
 function ReplayDebuggerFrame(dbg, data) {
   this._dbg = dbg;
   this._data = data;
   if (this._data.arguments) {
     this._data.arguments =
-      this._data.arguments.map(this._dbg._convertValue.bind(this._dbg));
+      this._data.arguments.map(a => this._dbg._convertValue(a));
   }
 }
 
 ReplayDebuggerFrame.prototype = {
   _invalidate() {
     this._data = null;
   },
 
@@ -601,34 +609,34 @@ ReplayDebuggerFrame.prototype = {
   get implementation() { NYI(); },
   evalWithBindings: NYI,
 };
 
 ///////////////////////////////////////////////////////////////////////////////
 // ReplayDebuggerObject
 ///////////////////////////////////////////////////////////////////////////////
 
-function ReplayDebuggerObject(dbg, data) {
+function ReplayDebuggerObject(dbg, data, forConsole) {
   this._dbg = dbg;
   this._data = data;
+  this._forConsole = forConsole;
   this._properties = null;
 }
 
 ReplayDebuggerObject.prototype = {
   _invalidate() {
     this._data = null;
     this._properties = null;
   },
 
   get callable() { return this._data.callable; },
   get isBoundFunction() { return this._data.isBoundFunction; },
   get isArrowFunction() { return this._data.isArrowFunction; },
   get isGeneratorFunction() { return this._data.isGeneratorFunction; },
   get isAsyncFunction() { return this._data.isAsyncFunction; },
-  get proto() { return this._dbg._getObject(this._data.proto); },
   get class() { return this._data.class; },
   get name() { return this._data.name; },
   get displayName() { return this._data.displayName; },
   get parameterNames() { return this._data.parameterNames; },
   get script() { return this._dbg._getScript(this._data.script); },
   get environment() { return this._dbg._getObject(this._data.environment); },
   get boundTargetFunction() { return this.isBoundFunction ? NYI() : undefined; },
   get boundThis() { return this.isBoundFunction ? NYI() : undefined; },
@@ -636,16 +644,23 @@ ReplayDebuggerObject.prototype = {
   get global() { return this._dbg._getObject(this._data.global); },
   get isProxy() { return this._data.isProxy; },
 
   isExtensible() { return this._data.isExtensible; },
   isSealed() { return this._data.isSealed; },
   isFrozen() { return this._data.isFrozen; },
   unwrap() { return this.isProxy ? NYI() : this; },
 
+  get proto() {
+    // Don't allow inspection of the prototypes of objects logged to the
+    // console. This is a hack that prevents the object inspector from crawling
+    // the object's prototype chain.
+    return this._forConsole ? null : this._dbg._getObject(this._data.proto);
+  },
+
   unsafeDereference() {
     // Direct access to the referent is not currently available.
     return null;
   },
 
   getOwnPropertyNames() {
     this._ensureProperties();
     return Object.keys(this._properties);
@@ -659,20 +674,20 @@ ReplayDebuggerObject.prototype = {
   getOwnPropertyDescriptor(name) {
     this._ensureProperties();
     const desc = this._properties[name];
     return desc ? this._convertPropertyDescriptor(desc) : null;
   },
 
   _ensureProperties() {
     if (!this._properties) {
-      const properties = this._dbg._sendRequestAllowDiverge({
-        type: "getObjectProperties",
-        id: this._data.id,
-      });
+      const id = this._data.id;
+      const properties = this._forConsole
+        ? this._dbg._sendRequest({ type: "getObjectPropertiesForConsole", id })
+        : this._dbg._sendRequestAllowDiverge({ type: "getObjectProperties", id });
       this._properties = {};
       properties.forEach(({name, desc}) => { this._properties[name] = desc; });
     }
   },
 
   _convertPropertyDescriptor(desc) {
     const rv = Object.assign({}, desc);
     if ("value" in desc) {
@@ -786,9 +801,13 @@ function ThrowError(msg)
 }
 
 function assert(v) {
   if (!v) {
     throw new Error("Assertion Failed!");
   }
 }
 
+function isNonNullObject(obj) {
+  return obj && (typeof obj == "object" || typeof obj == "function");
+}
+
 module.exports = ReplayDebugger;
--- a/devtools/server/actors/replay/replay.js
+++ b/devtools/server/actors/replay/replay.js
@@ -111,16 +111,20 @@ function scriptFrameForIndex(index) {
         break;
       }
     }
     frame = frame.older;
   }
   return frame;
 }
 
+function isNonNullObject(obj) {
+  return obj && (typeof obj == "object" || typeof obj == "function");
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // Persistent Script State
 ///////////////////////////////////////////////////////////////////////////////
 
 // Association between Debugger.Scripts and their IDs. The indices that this
 // table assigns to scripts are stable across the entire recording, even though
 // this table (like all JS state) is included in snapshots, rolled back when
 // rewinding, and so forth.  In debuggee time, this table only grows (there is
@@ -174,16 +178,36 @@ dbg.onNewScript = function(script) {
 
   hitGlobalHandler("NewScript");
 
   // Check in case any handlers we need to install are on the scripts just
   // created.
   installPendingHandlers();
 };
 
+const gConsoleObjectProperties = new Map();
+
+function shouldSaveConsoleProperty({ desc }) {
+  // When logging an object to the console, only properties captured here will
+  // be shown. We limit this to non-object data properties, as more complex
+  // properties have two problems: A) to inspect them we will need to switch to
+  // a replaying child process, which is very slow when there are many console
+  // messages, and B) trying to access objects transitively referred to by
+  // logged console objects will fail when unpaused, and depends on the current
+  // state of the process otherwise.
+  return "value" in desc && !isNonNullObject(desc.value);
+}
+
+function saveConsoleObjectProperties(obj) {
+  if (obj instanceof Debugger.Object) {
+    const properties = getObjectProperties(obj).filter(shouldSaveConsoleProperty);
+    gConsoleObjectProperties.set(obj, properties);
+  }
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // Console Message State
 ///////////////////////////////////////////////////////////////////////////////
 
 const gConsoleMessages = [];
 
 function newConsoleMessage(messageType, executionPoint, contents) {
   // Each new console message advances the progress counter, to make sure
@@ -245,16 +269,17 @@ Services.obs.addObserver({
       if (id != "wrappedJSObject" && id != "arguments") {
         contents[id] = JSON.parse(JSON.stringify(apiMessage[id]));
       }
     }
 
     // Message arguments are preserved as debuggee values.
     if (apiMessage.arguments) {
       contents.arguments = apiMessage.arguments.map(makeDebuggeeValue);
+      contents.arguments.forEach(saveConsoleObjectProperties);
     }
 
     newConsoleMessage("ConsoleAPI", null, contents);
   },
 }, "console-api-log-event");
 
 function convertConsoleMessage(contents) {
   const result = {};
@@ -460,17 +485,17 @@ function convertCompletionValue(value) {
   }
   if ("throw" in value) {
     return { throw: convertValue(value.throw) };
   }
   throw new Error("Unexpected completion value");
 }
 
 function makeDebuggeeValue(value) {
-  if (value && typeof value == "object") {
+  if (isNonNullObject(value)) {
     assert(!(value instanceof Debugger.Object));
     const global = Cu.getGlobalForObject(value);
     const dbgGlobal = dbg.makeGlobalObjectReference(global);
     return dbgGlobal.makeDebuggeeValue(value);
   }
   return value;
 }
 
@@ -512,16 +537,34 @@ function getSourceData(id) {
     sourceMapURL: source.sourceMapURL,
   };
 }
 
 function forwardToScript(name) {
   return request => gScripts.getObject(request.id)[name](request.value);
 }
 
+function getObjectProperties(object) {
+  const names = object.getOwnPropertyNames();
+
+  return names.map(name => {
+    const desc = object.getOwnPropertyDescriptor(name);
+    if ("value" in desc) {
+      desc.value = convertValue(desc.value);
+    }
+    if ("get" in desc) {
+      desc.get = getObjectId(desc.get);
+    }
+    if ("set" in desc) {
+      desc.set = getObjectId(desc.set);
+    }
+    return { name, desc };
+  });
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // Handlers
 ///////////////////////////////////////////////////////////////////////////////
 
 const gRequestHandlers = {
 
   repaint() {
     if (!RecordReplayControl.maybeDivergeFromRecording()) {
@@ -621,31 +664,26 @@ const gRequestHandlers = {
         desc: {
           value: "Recording divergence in getObjectProperties",
           enumerable: true,
         },
       }];
     }
 
     const object = gPausedObjects.getObject(request.id);
-    const names = object.getOwnPropertyNames();
+    return getObjectProperties(object);
+  },
 
-    return names.map(name => {
-      const desc = object.getOwnPropertyDescriptor(name);
-      if ("value" in desc) {
-        desc.value = convertValue(desc.value);
-      }
-      if ("get" in desc) {
-        desc.get = getObjectId(desc.get);
-      }
-      if ("set" in desc) {
-        desc.set = getObjectId(desc.set);
-      }
-      return { name, desc };
-    });
+  getObjectPropertiesForConsole(request) {
+    const object = gPausedObjects.getObject(request.id);
+    const properties = gConsoleObjectProperties.get(object);
+    if (!properties) {
+      throw new Error("Console object properties not saved");
+    }
+    return properties;
   },
 
   getEnvironmentNames(request) {
     if (!RecordReplayControl.maybeDivergeFromRecording()) {
       return [{name: "Unknown names",
                value: "Recording divergence in getEnvironmentNames" }];
     }
 
--- a/devtools/server/actors/thread.js
+++ b/devtools/server/actors/thread.js
@@ -540,20 +540,30 @@ const ThreadActor = ActorClassWithSpec(t
 
       // Note that we're popping this frame; we need to watch for
       // subsequent step events on its caller.
       this.reportedPop = true;
 
       if (steppingType == "finish") {
         const parentFrame = thread._getNextStepFrame(this);
         if (parentFrame && parentFrame.script) {
+          // We can't use the completion value in stepping hooks if we're
+          // replaying, as we can't use its contents after resuming.
+          const ncompletion = thread.dbg.replaying ? null : completion;
           const { onStep, onPop } = thread._makeSteppingHooks(
-            originalLocation, "next", false, completion
+            originalLocation, "next", false, ncompletion
           );
-          parentFrame.onStep = onStep;
+          if (thread.dbg.replaying) {
+            const offsets =
+              thread._findReplayingStepOffsets(originalLocation, parentFrame,
+                                               /* rewinding = */ false);
+            parentFrame.setReplayingOnStep(onStep, offsets);
+          } else {
+            parentFrame.onStep = onStep;
+          }
           // We need the onPop alongside the onStep because it is possible that
           // the parent frame won't have any steppable offsets, and we want to
           // make sure that we always pause in the parent _somewhere_.
           parentFrame.onPop = onPop;
           return undefined;
         }
       }
 
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -479,16 +479,25 @@ WebGLContext::CreateAndInitGL(bool force
     if (gfxPlatform::IsHeadless()) {
         FailureReason reason;
         reason.info = "Can't use WebGL in headless mode (https://bugzil.la/1375585).";
         out_failReasons->push_back(reason);
         GenerateWarning("%s", reason.info.BeginReading());
         return false;
     }
 
+    // WebGL can't be used when recording/replaying.
+    if (recordreplay::IsRecordingOrReplaying()) {
+        FailureReason reason;
+        reason.info = "Can't use WebGL when recording or replaying (https://bugzil.la/1506467).";
+        out_failReasons->push_back(reason);
+        GenerateWarning("%s", reason.info.BeginReading());
+        return false;
+    }
+
     // WebGL2 is separately blocked:
     if (IsWebGL2()) {
         const nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
         const auto feature = nsIGfxInfo::FEATURE_WEBGL2;
 
         FailureReason reason;
         if (IsFeatureInBlacklist(gfxInfo, feature, &reason.key)) {
             reason.info = "Refused to create WebGL2 context because of blacklist"
--- a/dom/console/Console.cpp
+++ b/dom/console/Console.cpp
@@ -1088,17 +1088,19 @@ Console::Console(JSContext* aCx, nsIGlob
   , mDumpToStdout(false)
   , mChromeInstance(false)
   , mMaxLogLevel(ConsoleLogLevel::All)
   , mStatus(eUnknown)
   , mCreationTimeStamp(TimeStamp::Now())
 {
   // Let's enable the dumping to stdout by default for chrome.
   if (nsContentUtils::ThreadsafeIsSystemCaller(aCx)) {
-    mDumpToStdout = DOMPrefs::DumpEnabled();
+    mDumpToStdout = StaticPrefs::devtools_console_stdout_chrome();
+  } else {
+    mDumpToStdout = StaticPrefs::devtools_console_stdout_content();
   }
 
   mozilla::HoldJSObjects(this);
 }
 
 Console::~Console()
 {
   AssertIsOnOwningThread();
new file mode 100644
--- /dev/null
+++ b/dom/media/tests/crashtests/1505957.html
@@ -0,0 +1,23 @@
+<html id='a'>
+<script>
+window.onload=function() {
+    b.src=document.getElementById('c').innerHTML;
+    b.setAttribute('src', 'data:audio/mpeg,');
+    document.documentElement.style.display='none';
+    window.top.open('');
+    var o = window.frames[0].document.body.childNodes[0];
+    document.getElementById('d').appendChild(o.parentNode.removeChild(o));
+    o = document.getElementById('a');
+    var p = o.parentNode;
+    o.setAttribute('id', 0)
+    p.removeChild(o);
+    p.appendChild(o);
+    o.setAttribute('style', 0)
+    p.removeChild(o);
+    p.appendChild(o);
+}
+</script>
+<iframe id='b'></iframe>
+<object id='c'>
+<ruby id='d'>
+</html>
--- a/dom/media/tests/crashtests/crashtests.list
+++ b/dom/media/tests/crashtests/crashtests.list
@@ -19,8 +19,9 @@ load 1281695.html
 load 1306476.html
 load 1348381.html
 load 1367930_1.html
 load 1367930_2.html
 pref(browser.link.open_newwindow,2) load 1429507_1.html # window.open() in tab doesn't work for crashtest in e10s, this opens a new window instead
 pref(browser.link.open_newwindow,2) load 1429507_2.html # window.open() in tab doesn't work for crashtest in e10s, this opens a new window instead
 load 1453030.html
 skip-if(Android) load 1490700.html # No screenshare on Android
+load 1505957.html
--- a/embedding/ios/GeckoEmbed/GeckoEmbed/browser/defaults/preferences/prefs.js
+++ b/embedding/ios/GeckoEmbed/GeckoEmbed/browser/defaults/preferences/prefs.js
@@ -1,3 +1,4 @@
 pref("toolkit.defaultChromeURI", "chrome://mybrowser/content/hello.xul");
 pref("browser.dom.window.dump.enabled", true);
+pref("devtools.console.stdout.chrome", true);
 pref("dom.max_script_run_time", 0);
--- a/gfx/layers/opengl/TextureHostOGL.cpp
+++ b/gfx/layers/opengl/TextureHostOGL.cpp
@@ -11,26 +11,31 @@
 #include "GLLibraryEGL.h"               // for GLLibraryEGL
 #include "GLUploadHelpers.h"
 #include "GLReadTexImageHelper.h"
 #include "gfx2DGlue.h"                  // for ContentForFormat, etc
 #include "mozilla/gfx/2D.h"             // for DataSourceSurface
 #include "mozilla/gfx/BaseSize.h"       // for BaseSize
 #include "mozilla/gfx/Logging.h"        // for gfxCriticalError
 #include "mozilla/layers/ISurfaceAllocator.h"
+#include "mozilla/webrender/WebRenderAPI.h"
 #include "nsRegion.h"                   // for nsIntRegion
 #include "AndroidSurfaceTexture.h"
 #include "GfxTexturesReporter.h"        // for GfxTexturesReporter
 #include "GLBlitTextureImageHelper.h"
 #include "GeckoProfiler.h"
 
 #ifdef XP_MACOSX
 #include "mozilla/layers/MacIOSurfaceTextureHostOGL.h"
 #endif
 
+#ifdef MOZ_WIDGET_ANDROID
+#include "mozilla/webrender/RenderAndroidSurfaceTextureHostOGL.h"
+#endif
+
 using namespace mozilla::gl;
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace layers {
 
 class Compositor;
 
@@ -673,16 +678,76 @@ SurfaceTextureHost::DeallocateDeviceData
   }
 
   if (mSurfTex) {
     mSurfTex->DecrementUse();
     mSurfTex = nullptr;
   }
 }
 
+void
+SurfaceTextureHost::CreateRenderTexture(const wr::ExternalImageId& aExternalImageId)
+{
+  RefPtr<wr::RenderTextureHost> texture =
+      new wr::RenderAndroidSurfaceTextureHostOGL(mSurfTex, mSize, mFormat, mContinuousUpdate);
+  wr::RenderThread::Get()->RegisterExternalImage(wr::AsUint64(aExternalImageId), texture.forget());
+}
+
+void
+SurfaceTextureHost::PushResourceUpdates(wr::TransactionBuilder& aResources,
+                                        ResourceUpdateOp aOp,
+                                        const Range<wr::ImageKey>& aImageKeys,
+                                        const wr::ExternalImageId& aExtID)
+{
+  auto method = aOp == TextureHost::ADD_IMAGE ? &wr::TransactionBuilder::AddExternalImage
+                                              : &wr::TransactionBuilder::UpdateExternalImage;
+  auto bufferType = wr::WrExternalImageBufferType::TextureRectHandle;
+
+  switch (GetFormat()) {
+    case gfx::SurfaceFormat::R8G8B8X8:
+    case gfx::SurfaceFormat::R8G8B8A8: {
+      MOZ_ASSERT(aImageKeys.length() == 1);
+
+      // XXX Add RGBA handling. Temporary hack to avoid crash
+      // With BGRA format setting, rendering works without problem.
+      auto format = GetFormat() == gfx::SurfaceFormat::R8G8B8A8 ? gfx::SurfaceFormat::B8G8R8A8
+                                                                : gfx::SurfaceFormat::B8G8R8X8;
+      wr::ImageDescriptor descriptor(GetSize(), format);
+      (aResources.*method)(aImageKeys[0], descriptor, aExtID, bufferType, 0);
+      break;
+    }
+    default: {
+      MOZ_ASSERT_UNREACHABLE("unexpected to be called");
+    }
+  }
+}
+
+void
+SurfaceTextureHost::PushDisplayItems(wr::DisplayListBuilder& aBuilder,
+                                     const wr::LayoutRect& aBounds,
+                                     const wr::LayoutRect& aClip,
+                                     wr::ImageRendering aFilter,
+                                     const Range<wr::ImageKey>& aImageKeys)
+{
+  switch (GetFormat()) {
+    case gfx::SurfaceFormat::R8G8B8X8:
+    case gfx::SurfaceFormat::R8G8B8A8:
+    case gfx::SurfaceFormat::B8G8R8A8:
+    case gfx::SurfaceFormat::B8G8R8X8: {
+
+      MOZ_ASSERT(aImageKeys.length() == 1);
+      aBuilder.PushImage(aBounds, aClip, true, aFilter, aImageKeys[0], !(mFlags & TextureFlags::NON_PREMULTIPLIED));
+      break;
+    }
+    default: {
+      MOZ_ASSERT_UNREACHABLE("unexpected to be called");
+    }
+  }
+}
+
 #endif // MOZ_WIDGET_ANDROID
 
 ////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////
 // EGLImage
 
 EGLImageTextureSource::EGLImageTextureSource(TextureSourceProvider* aProvider,
                                              EGLImage aImage,
--- a/gfx/layers/opengl/TextureHostOGL.h
+++ b/gfx/layers/opengl/TextureHostOGL.h
@@ -21,16 +21,17 @@
 #include "mozilla/gfx/Matrix.h"         // for Matrix4x4
 #include "mozilla/gfx/Point.h"          // for IntSize, IntPoint
 #include "mozilla/gfx/Types.h"          // for SurfaceFormat, etc
 #include "mozilla/layers/CompositorOGL.h"  // for CompositorOGL
 #include "mozilla/layers/CompositorTypes.h"  // for TextureFlags
 #include "mozilla/layers/LayersSurfaces.h"  // for SurfaceDescriptor
 #include "mozilla/layers/TextureHost.h"  // for TextureHost, etc
 #include "mozilla/mozalloc.h"           // for operator delete, etc
+#include "mozilla/webrender/RenderThread.h"
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsDebug.h"                    // for NS_WARNING
 #include "nsISupportsImpl.h"            // for TextureImage::Release, etc
 #include "nsRegionFwd.h"                // for nsIntRegion
 #include "OGLShaderProgram.h"           // for ShaderProgramType, etc
 
 #ifdef MOZ_WIDGET_ANDROID
 #include "GeneratedJNIWrappers.h"
@@ -469,16 +470,29 @@ public:
   }
 
   gl::GLContext* gl() const;
 
   virtual gfx::IntSize GetSize() const override { return mSize; }
 
   virtual const char* Name() override { return "SurfaceTextureHost"; }
 
+  virtual void CreateRenderTexture(const wr::ExternalImageId& aExternalImageId) override;
+
+  virtual void PushResourceUpdates(wr::TransactionBuilder& aResources,
+                                   ResourceUpdateOp aOp,
+                                   const Range<wr::ImageKey>& aImageKeys,
+                                   const wr::ExternalImageId& aExtID) override;
+
+  virtual void PushDisplayItems(wr::DisplayListBuilder& aBuilder,
+                                const wr::LayoutRect& aBounds,
+                                const wr::LayoutRect& aClip,
+                                wr::ImageRendering aFilter,
+                                const Range<wr::ImageKey>& aImageKeys) override;
+
 protected:
   bool EnsureAttached();
 
   mozilla::java::GeckoSurfaceTexture::GlobalRef mSurfTex;
   const gfx::IntSize mSize;
   const gfx::SurfaceFormat mFormat;
   bool mContinuousUpdate;
   const bool mIgnoreTransform;
new file mode 100644
--- /dev/null
+++ b/gfx/webrender_bindings/RenderAndroidSurfaceTextureHostOGL.cpp
@@ -0,0 +1,120 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "RenderAndroidSurfaceTextureHostOGL.h"
+
+#include "mozilla/gfx/Logging.h"
+
+namespace mozilla {
+namespace wr {
+
+RenderAndroidSurfaceTextureHostOGL::RenderAndroidSurfaceTextureHostOGL(
+  const java::GeckoSurfaceTexture::GlobalRef& aSurfTex,
+  gfx::IntSize aSize,
+  gfx::SurfaceFormat aFormat,
+  bool aContinuousUpdate)
+  : mSurfTex(aSurfTex)
+  , mSize(aSize)
+{
+  MOZ_COUNT_CTOR_INHERITED(RenderAndroidSurfaceTextureHostOGL, RenderTextureHostOGL);
+
+  if (mSurfTex) {
+    mSurfTex->IncrementUse();
+  }
+}
+
+RenderAndroidSurfaceTextureHostOGL::~RenderAndroidSurfaceTextureHostOGL()
+{
+  MOZ_COUNT_DTOR_INHERITED(RenderAndroidSurfaceTextureHostOGL, RenderTextureHostOGL);
+  DeleteTextureHandle();
+  if (mSurfTex) {
+    mSurfTex->DecrementUse();
+  }
+}
+
+GLuint
+RenderAndroidSurfaceTextureHostOGL::GetGLHandle(uint8_t aChannelIndex) const
+{
+  if (!mSurfTex) {
+    return 0;
+  }
+  return mSurfTex->GetTexName();
+}
+
+gfx::IntSize
+RenderAndroidSurfaceTextureHostOGL::GetSize(uint8_t aChannelIndex) const
+{
+  return mSize;
+}
+
+wr::WrExternalImage
+RenderAndroidSurfaceTextureHostOGL::Lock(uint8_t aChannelIndex,
+                                       gl::GLContext* aGL,
+                                       wr::ImageRendering aRendering)
+{
+  MOZ_ASSERT(aChannelIndex == 0);
+
+  if (mGL.get() != aGL) {
+    // release the texture handle in the previous gl context
+    DeleteTextureHandle();
+    mGL = aGL;
+    mGL->MakeCurrent();
+  }
+
+  if (!mSurfTex || !mGL || !mGL->MakeCurrent()) {
+    return InvalidToWrExternalImage();
+  }
+
+  if (!mSurfTex->IsAttachedToGLContext((int64_t)mGL.get())) {
+    GLuint texName;
+    mGL->fGenTextures(1, &texName);
+    // Cache rendering filter.
+    mCachedRendering = aRendering;
+    ActivateBindAndTexParameteri(mGL,
+                                 LOCAL_GL_TEXTURE0,
+                                 LOCAL_GL_TEXTURE_EXTERNAL_OES,
+                                 texName,
+                                 aRendering);
+
+    if (NS_FAILED(mSurfTex->AttachToGLContext((int64_t)mGL.get(), texName))) {
+      MOZ_ASSERT(0);
+      mGL->fDeleteTextures(1, &texName);
+      return InvalidToWrExternalImage();;
+    }
+  } else if(IsFilterUpdateNecessary(aRendering)) {
+    // Cache new rendering filter.
+    mCachedRendering = aRendering;
+    ActivateBindAndTexParameteri(mGL,
+                                 LOCAL_GL_TEXTURE0,
+                                 LOCAL_GL_TEXTURE_EXTERNAL_OES,
+                                 mSurfTex->GetTexName(),
+                                 aRendering);
+  }
+
+  // XXX Call UpdateTexImage() only when it is necessary.
+  // For now, alyways call UpdateTexImage().
+  //if (mContinuousUpdate) {
+    mSurfTex->UpdateTexImage();
+  //}
+
+  return NativeTextureToWrExternalImage(mSurfTex->GetTexName(), 0, 0,
+                                        mSize.width, mSize.height);
+}
+
+void
+RenderAndroidSurfaceTextureHostOGL::Unlock()
+{
+}
+
+void
+RenderAndroidSurfaceTextureHostOGL::DeleteTextureHandle()
+{
+  // XXX Do we need to call mSurfTex->DetachFromGLContext() here?
+  // But Surface texture is shared among many SurfaceTextureHosts.
+}
+
+} // namespace wr
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/webrender_bindings/RenderAndroidSurfaceTextureHostOGL.h
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef MOZILLA_GFX_RENDERANDROIDSURFACETEXTUREHOSTOGL_H
+#define MOZILLA_GFX_RENDERANDROIDSURFACETEXTUREHOSTOGL_H
+
+#include "GeneratedJNIWrappers.h"
+#include "mozilla/layers/TextureHostOGL.h"
+#include "RenderTextureHostOGL.h"
+
+namespace mozilla {
+
+namespace wr {
+
+class RenderAndroidSurfaceTextureHostOGL final : public RenderTextureHostOGL
+{
+public:
+  explicit RenderAndroidSurfaceTextureHostOGL(const java::GeckoSurfaceTexture::GlobalRef& aSurfTex,
+                                              gfx::IntSize aSize,
+                                              gfx::SurfaceFormat aFormat,
+                                              bool aContinuousUpdate);
+
+  wr::WrExternalImage Lock(uint8_t aChannelIndex,
+                           gl::GLContext* aGL,
+                           wr::ImageRendering aRendering) override;
+  void Unlock() override;
+
+  virtual gfx::IntSize GetSize(uint8_t aChannelIndex) const override;
+  virtual GLuint GetGLHandle(uint8_t aChannelIndex) const override;
+
+private:
+  virtual ~RenderAndroidSurfaceTextureHostOGL();
+  void DeleteTextureHandle();
+
+  const mozilla::java::GeckoSurfaceTexture::GlobalRef mSurfTex;
+  const gfx::IntSize mSize;
+  // XXX const bool mContinuousUpdate;
+  // XXX const bool mIgnoreTransform;
+
+  RefPtr<gl::GLContext> mGL;
+};
+
+} // namespace wr
+} // namespace mozilla
+
+#endif // MOZILLA_GFX_RENDERANDROIDSURFACETEXTUREHOSTOGL_H
--- a/gfx/webrender_bindings/moz.build
+++ b/gfx/webrender_bindings/moz.build
@@ -41,16 +41,24 @@ UNIFIED_SOURCES += [
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
     EXPORTS.mozilla.webrender += [
         'RenderMacIOSurfaceTextureHostOGL.h',
     ]
     UNIFIED_SOURCES += [
         'RenderMacIOSurfaceTextureHostOGL.cpp',
     ]
 
+if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
+    EXPORTS.mozilla.webrender += [
+        'RenderAndroidSurfaceTextureHostOGL.h',
+    ]
+    UNIFIED_SOURCES += [
+        'RenderAndroidSurfaceTextureHostOGL.cpp',
+    ]
+
 if CONFIG['MOZ_ENABLE_D3D10_LAYER']:
     DEFINES['MOZ_ENABLE_D3D10_LAYER'] = True
     EXPORTS.mozilla.webrender += [
         'RenderCompositorANGLE.h',
         'RenderD3D11TextureHostOGL.h',
     ]
     UNIFIED_SOURCES += [
         'RenderD3D11TextureHostOGL.cpp',
--- a/js/src/tests/user.js
+++ b/js/src/tests/user.js
@@ -1,10 +1,11 @@
 user_pref("app.update.disabledForTesting", true);
 user_pref("browser.dom.window.dump.enabled", true);
+user_pref("devtools.console.stdout.chrome", true);
 user_pref("browser.sessionstore.resume_from_crash", false);
 user_pref("browser.shell.checkDefaultBrowser", false);
 user_pref("browser.xul.error_pages.enabled", true);
 user_pref("security.fileuri.strict_origin_policy", false);
 user_pref("dom.allow_scripts_to_close_windows", true);
 user_pref("dom.disable_open_during_load", false);
 user_pref("dom.max_script_run_time", 0);
 user_pref("dom.max_chrome_script_run_time", 0);
--- a/js/xpconnect/src/XPCShellImpl.cpp
+++ b/js/xpconnect/src/XPCShellImpl.cpp
@@ -1286,16 +1286,17 @@ XRE_XPCShellMain(int argc, char** argv, 
         if (NS_FAILED(rv)) {
             printf("NS_InitXPCOM2 failed!\n");
             return 1;
         }
 
         // xpc::ErrorReport::LogToConsoleWithStack needs this to print errors
         // to stderr.
         Preferences::SetBool("browser.dom.window.dump.enabled", true);
+        Preferences::SetBool("devtools.console.stdout.chrome", true);
 
         AutoJSAPI jsapi;
         jsapi.Init();
         cx = jsapi.cx();
 
         // Override the default XPConnect interrupt callback. We could store the
         // old one and restore it before shutting down, but there's not really a
         // reason to bother.
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -6395,16 +6395,24 @@ PresShell::Paint(nsView*         aViewTo
     flags |= PaintFrameFlags::PAINT_COMPRESSED;
     mNextPaintCompressed = false;
   }
 
   if (frame) {
     // We can paint directly into the widget using its layer manager.
     nsLayoutUtils::PaintFrame(nullptr, frame, aDirtyRegion, bgcolor,
                               nsDisplayListBuilderMode::PAINTING, flags);
+
+    // When recording/replaying, create a checkpoint after every paint. This
+    // can cause content JS to run, so reset |nojs|.
+    if (recordreplay::IsRecordingOrReplaying()) {
+      nojs.reset();
+      recordreplay::child::CreateCheckpoint();
+    }
+
     return;
   }
 
   if (layerManager->GetBackendType() == layers::LayersBackend::LAYERS_WR) {
     nsPresContext* pc = GetPresContext();
     LayoutDeviceRect bounds =
       LayoutDeviceRect::FromAppUnits(pc->GetVisibleArea(), pc->AppUnitsPerDevPixel());
     bgcolor = NS_ComposeColors(bgcolor, mCanvasBackgroundColor);
--- a/layout/forms/nsRangeFrame.cpp
+++ b/layout/forms/nsRangeFrame.cpp
@@ -25,17 +25,19 @@
 #include "mozilla/dom/Element.h"
 #include "mozilla/ServoStyleSet.h"
 #include "nsStyleConsts.h"
 
 #ifdef ACCESSIBILITY
 #include "nsAccessibilityService.h"
 #endif
 
-#define LONG_SIDE_TO_SHORT_SIDE_RATIO 10
+// Our intrinsic size is 12em in the main-axis and 1.3em in the cross-axis.
+#define MAIN_AXIS_EM_SIZE 12
+#define CROSS_AXIS_EM_SIZE 1.3f
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::image;
 
 NS_IMPL_ISUPPORTS(nsRangeFrame::DummyTouchListener, nsIDOMEventListener)
 
 nsIFrame*
@@ -769,71 +771,44 @@ nsRangeFrame::ComputeAutoSize(gfxContext
                               WritingMode         aWM,
                               const LogicalSize&  aCBSize,
                               nscoord             aAvailableISize,
                               const LogicalSize&  aMargin,
                               const LogicalSize&  aBorder,
                               const LogicalSize&  aPadding,
                               ComputeSizeFlags    aFlags)
 {
-  nscoord oneEm = NSToCoordRound(StyleFont()->mFont.size *
-                                 nsLayoutUtils::FontSizeInflationFor(this)); // 1em
-
   bool isInlineOriented = IsInlineOriented();
+  auto em = StyleFont()->mFont.size * nsLayoutUtils::FontSizeInflationFor(this);
 
   const WritingMode wm = GetWritingMode();
   LogicalSize autoSize(wm);
-
-  // nsFrame::ComputeSize calls GetMinimumWidgetSize to prevent us from being
-  // given too small a size when we're natively themed. If we're themed, we set
-  // our "thickness" dimension to zero below and rely on that
-  // GetMinimumWidgetSize check to correct that dimension to the natural
-  // thickness of a slider in the current theme.
-
   if (isInlineOriented) {
-    autoSize.ISize(wm) = LONG_SIDE_TO_SHORT_SIDE_RATIO * oneEm;
-    autoSize.BSize(wm) = IsThemed() ? 0 : oneEm;
+    autoSize.ISize(wm) = NSToCoordRound(MAIN_AXIS_EM_SIZE * em);
+    autoSize.BSize(wm) = NSToCoordRound(CROSS_AXIS_EM_SIZE * em);
   } else {
-    autoSize.ISize(wm) = IsThemed() ? 0 : oneEm;
-    autoSize.BSize(wm) = LONG_SIDE_TO_SHORT_SIDE_RATIO * oneEm;
+    autoSize.ISize(wm) = NSToCoordRound(CROSS_AXIS_EM_SIZE * em);
+    autoSize.BSize(wm) = NSToCoordRound(MAIN_AXIS_EM_SIZE * em);
   }
 
   return autoSize.ConvertTo(aWM, wm);
 }
 
 nscoord
-nsRangeFrame::GetMinISize(gfxContext *aRenderingContext)
+nsRangeFrame::GetMinISize(gfxContext* aRenderingContext)
 {
-  // nsFrame::ComputeSize calls GetMinimumWidgetSize to prevent us from being
-  // given too small a size when we're natively themed. If we aren't native
-  // themed, we don't mind how small we're sized.
   return nscoord(0);
 }
 
 nscoord
-nsRangeFrame::GetPrefISize(gfxContext *aRenderingContext)
+nsRangeFrame::GetPrefISize(gfxContext* aRenderingContext)
 {
   bool isInline = IsInlineOriented();
-
-  if (!isInline && IsThemed()) {
-    // nsFrame::ComputeSize calls GetMinimumWidgetSize to prevent us from being
-    // given too small a size when we're natively themed. We return zero and
-    // depend on that correction to get our "natural" width when we're a
-    // vertical slider.
-    return 0;
-  }
-
-  nscoord prefISize = NSToCoordRound(StyleFont()->mFont.size *
-                                     nsLayoutUtils::FontSizeInflationFor(this)); // 1em
-
-  if (isInline) {
-    prefISize *= LONG_SIDE_TO_SHORT_SIDE_RATIO;
-  }
-
-  return prefISize;
+  auto em = StyleFont()->mFont.size * nsLayoutUtils::FontSizeInflationFor(this);
+  return NSToCoordRound(em * (isInline ? MAIN_AXIS_EM_SIZE : CROSS_AXIS_EM_SIZE));
 }
 
 bool
 nsRangeFrame::IsHorizontal() const
 {
   dom::HTMLInputElement* element =
     static_cast<dom::HTMLInputElement*>(GetContent());
   return element->AttrValueIs(kNameSpaceID_None, nsGkAtoms::orient,
@@ -871,19 +846,16 @@ nsRangeFrame::GetValue() const
 bool
 nsRangeFrame::ShouldUseNativeStyle() const
 {
   nsIFrame* trackFrame = mTrackDiv->GetPrimaryFrame();
   nsIFrame* progressFrame = mProgressDiv->GetPrimaryFrame();
   nsIFrame* thumbFrame = mThumbDiv->GetPrimaryFrame();
 
   return (StyleDisplay()->mAppearance == StyleAppearance::Range) &&
-         !PresContext()->HasAuthorSpecifiedRules(this,
-                                                 (NS_AUTHOR_SPECIFIED_BORDER |
-                                                  NS_AUTHOR_SPECIFIED_BACKGROUND)) &&
          trackFrame &&
          !PresContext()->HasAuthorSpecifiedRules(trackFrame,
                                                  STYLES_DISABLING_NATIVE_THEMING) &&
          progressFrame &&
          !PresContext()->HasAuthorSpecifiedRules(progressFrame,
                                                  STYLES_DISABLING_NATIVE_THEMING) &&
          thumbFrame &&
          !PresContext()->HasAuthorSpecifiedRules(thumbFrame,
new file mode 100644
--- /dev/null
+++ b/layout/reftests/forms/input/range/range-border-background-ref.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+<style>
+html,body {
+  color:black; background-color:white; font:16px/1 monospace; padding:0; margin:0;
+}
+input { height: 2em; }
+</style>
+<div style="float:left">
+<input type=range><br>
+<span style="display:inline-block; background-color:rgba(0,255,0,0.3);"><input type=range style="-webkit-appearance:none; margin:0; vertical-align:top; background: none"></span><br>
+</div>
+
+<div style="float:left">
+<span><input type=range style="-webkit-appearance:none; margin:0; vertical-align:top"></span><br>
+</div>
+
+<div style="float:left">
+<input type=range><br>
+<span style="display:inline-block; background-color: -moz-Field; background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAE0lEQVQYlWNg+M/gTRQeVUhfhQBHR4DpEUeLigAAAABJRU5ErkJggg==)"><input type=range style="-webkit-appearance:none; margin:0; vertical-align:top; background: none"></span><br>
+</div>
+
+<div style="float:left">
+<input type=range><br>
+<span style="display:inline-block; border:1px solid green"><input type=range style="-webkit-appearance:none; margin:0; vertical-align:top"></span><br>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/forms/input/range/range-border-background.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+<style>
+html,body {
+  color:black; background-color:white; font:16px/1 monospace; padding:0; margin:0;
+}
+input { height: 2em; }
+</style>
+<div style="float:left">
+<input type=range style="background-color:rgba(0,255,0,0.3)"><br>
+<input type=range style="-webkit-appearance:none; background-color:rgba(0,255,0,0.3); margin:0"><br>
+</div>
+
+<div style="float:left">
+<span style="background:red"><input type=range style="-webkit-appearance:none; margin:0; vertical-align:top"></span><br>
+</div>
+
+<div style="float:left">
+<input type=range style="background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAE0lEQVQYlWNg+M/gTRQeVUhfhQBHR4DpEUeLigAAAABJRU5ErkJggg==)"><br>
+<input type=range style="-webkit-appearance:none; background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAE0lEQVQYlWNg+M/gTRQeVUhfhQBHR4DpEUeLigAAAABJRU5ErkJggg==); margin:0"><br>
+</div>
+
+<div style="float:left">
+<input type=range style="border:1px solid red"><br>
+<input type=range style="-webkit-appearance:none; border:1px solid green; margin:0"><br>
+</div>
--- a/layout/reftests/forms/input/range/reftest.list
+++ b/layout/reftests/forms/input/range/reftest.list
@@ -9,23 +9,23 @@ fuzzy-if(skiaContent,0-1,0-40) == to-ran
 == from-range-to-other-type-unthemed-1.html from-range-to-other-type-unthemed-1-ref.html
 
 # for different values:
 != different-fraction-of-range-unthemed-1.html different-fraction-of-range-unthemed-1-notref.html
 == same-fraction-of-range-unthemed-1.html same-fraction-of-range-unthemed-1-ref.html
 
 # dynamic value changes:
 fuzzy-if(skiaContent,0-1,0-40) == value-prop-unthemed.html 75pct-unthemed-common-ref.html
-fuzzy-if(webrender&&gtkWidget,96-96,163-163) == value-prop.html 75pct-common-ref.html
+fuzzy-if(webrender&&gtkWidget,79-79,138-138) == value-prop.html 75pct-common-ref.html
 fuzzy-if(skiaContent,0-1,0-40) == valueAsNumber-prop-unthemed.html 75pct-unthemed-common-ref.html
-fuzzy-if(webrender&&gtkWidget,96-96,163-163) == valueAsNumber-prop.html 75pct-common-ref.html
+fuzzy-if(webrender&&gtkWidget,79-79,138-138) == valueAsNumber-prop.html 75pct-common-ref.html
 fuzzy-if(skiaContent,0-1,0-40) == stepDown-unthemed.html 75pct-unthemed-common-ref.html
-fuzzy-if(webrender&&gtkWidget,96-96,163-163) == stepDown.html 75pct-common-ref.html
+fuzzy-if(webrender&&gtkWidget,79-79,138-138) == stepDown.html 75pct-common-ref.html
 fuzzy-if(skiaContent,0-1,0-40) == stepUp-unthemed.html 75pct-unthemed-common-ref.html
-fuzzy-if(webrender&&gtkWidget,96-96,163-163) == stepUp.html 75pct-common-ref.html
+fuzzy-if(webrender&&gtkWidget,79-79,138-138) == stepUp.html 75pct-common-ref.html
 == max-prop.html 100pct-common-ref.html
 == reset-value.html reset-value-ref.html
 
 # 'direction' property:
 == direction-unthemed-1.html direction-unthemed-1-ref.html
 
 # ::-moz-range-progress pseudo-element:
 == moz-range-progress-1.html moz-range-progress-1-ref.html
@@ -42,8 +42,10 @@ fuzzy-if(webrender&&gtkWidget,96-96,163-
 == range-vlr-orient-inline.html range-orient-vertical.html
 == range-vlr-orient-horizontal.html range-orient-horizontal.html
 == range-vlr-orient-vertical.html range-orient-vertical.html
 == range-vrl.html range-orient-vertical-rtl.html
 == range-vrl-orient-block.html range-orient-horizontal-rtl.html
 == range-vrl-orient-inline.html range-orient-vertical-rtl.html
 == range-vrl-orient-horizontal.html range-orient-horizontal-rtl.html
 == range-vrl-orient-vertical.html range-orient-vertical-rtl.html
+
+skip-if(Android) == range-border-background.html range-border-background-ref.html # Android doesn't have a native theme for -webkit-appearance:range
--- a/layout/style/res/forms.css
+++ b/layout/style/res/forms.css
@@ -872,51 +872,25 @@ meter {
 :-moz-meter-sub-sub-optimum::-moz-meter-bar {
   /* red. */
   background: linear-gradient(#f77, #f77, #fcc 20%, #d44 45%, #d44 55%);
 }
 
 input[type=range] {
   -moz-appearance: range;
   display: inline-block;
-  inline-size: 12em;
-  block-size: 1.3em;
-  margin-inline-start: 0.7em;
-  margin-inline-end: 0.7em;
-  margin-block-start: 0;
-  margin-block-end: 0;
+  margin: 2px;
   /* Override some rules that apply on all input types: */
   cursor: default;
-  background: none;
-  border: none;
+  padding: unset;
+  border: unset;
   /* Prevent nsFrame::HandlePress setting mouse capture to this element. */
   -moz-user-select: none ! important;
 }
 
-input[type=range][orient=block] {
-  inline-size: 1.3em;
-  block-size: 12em;
-  margin-inline-start: 0;
-  margin-inline-end: 0;
-  margin-block-start: 0.7em;
-  margin-block-end: 0.7em;
-}
-
-input[type=range][orient=horizontal] {
-  width: 12em;
-  height: 1.3em;
-  margin: 0 0.7em;
-}
-
-input[type=range][orient=vertical] {
-  width: 1.3em;
-  height: 12em;
-  margin: 0.7em 0;
-}
-
 /**
  * Ideally we'd also require :-moz-focusring here, but that doesn't currently
  * work. Instead we only use the -moz-focus-outer border style if
  * NS_EVENT_STATE_FOCUSRING is set (the check is in
  * nsRangeFrame::BuildDisplayList).
  */
 input[type=range]::-moz-focus-outer {
   border: 1px dotted black;
@@ -928,55 +902,41 @@ input[type=range]::-moz-focus-outer {
  * logic to position it). Specifically the 'margin', 'top' and 'left'
  * properties are ignored.
  *
  * If content authors want to have a vertical range, they will also need to
  * set the width/height of this pseudo-element.
  */
 input[type=range]::-moz-range-track {
   /* Prevent styling that would change the type of frame we construct. */
-  display: inline-block !important;
+  display: block !important;
   float: none !important;
   position: static !important;
-  border: none;
-  background-color: #999;
-  inline-size: 100%;
+  writing-mode: unset !important;
+  direction: unset !important;
   block-size: 0.2em;
   /* Prevent nsFrame::HandlePress setting mouse capture to this element. */
   -moz-user-select: none ! important;
 }
 
-input[type=range][orient=block]::-moz-range-track {
-  inline-size: 0.2em;
-  block-size: 100%;
-}
-
-input[type=range][orient=horizontal]::-moz-range-track {
-  width: 100%;
-  height: 0.2em;
-}
-
-input[type=range][orient=vertical]::-moz-range-track {
-  width: 0.2em;
-  height: 100%;
-}
-
 /**
  * Layout handles positioning of this pseudo-element specially (so that content
  * authors can concentrate on styling this pseudo-element without worrying
  * about the logic to position it). Specifically the 'margin', 'top' and 'left'
  * properties are ignored. Additionally, if the range is horizontal, the width
  * property is ignored, and if the range range is vertical, the height property
  * is ignored.
  */
 input[type=range]::-moz-range-progress {
   /* Prevent styling that would change the type of frame we construct. */
-  display: inline-block !important;
+  display: block !important;
   float: none !important;
   position: static !important;
+  writing-mode: unset !important;
+  direction: unset !important;
   /* Since one of width/height will be ignored, this just sets the "other"
      dimension.
    */
   width: 0.2em;
   height: 0.2em;
   /* Prevent nsFrame::HandlePress setting mouse capture to this element. */
   -moz-user-select: none ! important;
 }
@@ -988,19 +948,21 @@ input[type=range]::-moz-range-progress {
  * properties are ignored.
  */
 input[type=range]::-moz-range-thumb {
   /* Native theming is atomic for range. Set -moz-appearance on the range
    * to get rid of it. The thumb's -moz-appearance is fixed.
    */
   -moz-appearance: range-thumb !important;
   /* Prevent styling that would change the type of frame we construct. */
-  display: inline-block !important;
+  display: block !important;
   float: none !important;
   position: static !important;
+  writing-mode: unset !important;
+  direction: unset !important;
   width: 1em;
   height: 1em;
   border: 0.1em solid #999;
   border-radius: 0.5em;
   background-color: #F0F0F0;
   /* Prevent nsFrame::HandlePress setting mouse capture to this element. */
   -moz-user-select: none ! important;
 }
--- a/layout/tools/reftest/README.txt
+++ b/layout/tools/reftest/README.txt
@@ -389,18 +389,19 @@ 4. Specification of default preferences
    overwrite them with the specified <preference> values.
 
 This test manifest format could be used by other harnesses, such as ones
 that do not depend on XUL, or even ones testing other layout engines.
 
 Running Tests
 =============
 
-(If you're not using a DEBUG build, first set browser.dom.window.dump.enabled
-to true (in about:config, in the profile you'll be using to run the tests).
+(If you're not using a DEBUG build, first set browser.dom.window.dump.enabled,
+devtools.console.stdout.chrome and devtools.console.stdout.content to true (in
+about:config, in the profile you'll be using to run the tests).
 Create the option as a new boolean if it doesn't exist already. If you skip
 this step you won't get any output in the terminal.)
 
 At some point in the future there will hopefully be a cleaner way to do
 this.  For now, go to your object directory, and run (perhaps using
 MOZ_NO_REMOTE=1 or the -profile <directory> option)
 
 ./firefox -reftest /path/to/srcdir/mozilla/layout/reftests/reftest.list > reftest.out
--- a/mobile/android/app/mobile.js
+++ b/mobile/android/app/mobile.js
@@ -618,16 +618,17 @@ pref("browser.firstrun.show.localepicker
 //
 // On Android, you also need to do the following for the output
 // to show up in logcat:
 //
 // $ adb shell stop
 // $ adb shell setprop log.redirect-stdio true
 // $ adb shell start
 pref("browser.dom.window.dump.enabled", true);
+pref("devtools.console.stdout.chrome", true);
 
 // controls if we want camera support
 pref("device.camera.enabled", true);
 pref("media.realtime_decoder.enabled", true);
 
 pref("javascript.options.showInConsole", true);
 
 pref("full-screen-api.enabled", true);
--- a/modules/libpref/init/StaticPrefList.h
+++ b/modules/libpref/init/StaticPrefList.h
@@ -1771,16 +1771,34 @@ VARCACHE_PREF(
 //---------------------------------------------------------------------------
 
 VARCACHE_PREF(
   "devtools.enabled",
    devtools_enabled,
   RelaxedAtomicBool, false
 )
 
+#ifdef MOZILLA_OFFICIAL
+# define PREF_VALUE false
+#else
+# define PREF_VALUE true
+#endif
+VARCACHE_PREF(
+  "devtools.console.stdout.chrome",
+   devtools_console_stdout_chrome,
+  RelaxedAtomicBool, PREF_VALUE
+)
+#undef PREF_VALUE
+
+VARCACHE_PREF(
+  "devtools.console.stdout.content",
+   devtools_console_stdout_content,
+  RelaxedAtomicBool, false
+)
+
 //---------------------------------------------------------------------------
 // Feature-Policy prefs
 //---------------------------------------------------------------------------
 
 #ifdef NIGHTLY_BUILD
 # define PREF_VALUE true
 #else
 # define PREF_VALUE false
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -1091,20 +1091,24 @@ pref("toolkit.asyncshutdown.crash_timeou
 pref("toolkit.asyncshutdown.log", false);
 
 // Enable JS dump() function.
 // IMPORTANT: Keep this in condition in sync with StaticPrefList.h. The value
 // of MOZILLA_OFFICIAL is different between full and artifact builds, so without
 // it being specified, dump is disabled in artifact builds (see Bug 1490412).
 #ifdef MOZILLA_OFFICIAL
 pref("browser.dom.window.dump.enabled", false, sticky);
+pref("devtools.console.stdout.chrome", false, sticky);
 #else
 pref("browser.dom.window.dump.enabled", true, sticky);
+pref("devtools.console.stdout.chrome", true, sticky);
 #endif
 
+pref("devtools.console.stdout.content", false, sticky);
+
 // Controls whether EventEmitter module throws dump message on each emit
 pref("toolkit.dump.emit", false);
 
 // Enable recording/replaying executions.
 #if defined(XP_MACOSX) && defined(NIGHTLY_BUILD)
 pref("devtools.recordreplay.enabled", true);
 pref("devtools.recordreplay.enableRewinding", true);
 #endif
--- a/services/fxaccounts/tests/mochitest/test_invalidEmailCase.html
+++ b/services/fxaccounts/tests/mochitest/test_invalidEmailCase.html
@@ -113,16 +113,17 @@ function runTest() {
     }
   );
 }
 
 SpecialPowers.pushPrefEnv({"set": [
     ["identity.fxaccounts.enabled", true],         // fx accounts
     ["identity.fxaccounts.auth.uri", TEST_SERVER], // our sjs server
     ["browser.dom.window.dump.enabled", true],
+    ["devtools.console.stdout.chrome", true],
   ]},
   function() { runTest(); }
 );
 
 </script>
 </pre>
 </body>
 </html>
--- a/testing/geckodriver/src/prefs.rs
+++ b/testing/geckodriver/src/prefs.rs
@@ -13,16 +13,17 @@ lazy_static! {
         ("app.normandy.api_url", Pref::new("")),
 
         // Disable automatically upgrading Firefox
         ("app.update.disabledForTesting", Pref::new(true)),
 
         // Enable the dump function, which sends messages to the system
         // console
         ("browser.dom.window.dump.enabled", Pref::new(true)),
+        ("devtools.console.stdout.chrome", Pref::new(true)),
 
         // Disable safebrowsing components
         ("browser.safebrowsing.blockedURIs.enabled", Pref::new(false)),
         ("browser.safebrowsing.downloads.enabled", Pref::new(false)),
         ("browser.safebrowsing.passwords.enabled", Pref::new(false)),
         ("browser.safebrowsing.malware.enabled", Pref::new(false)),
         ("browser.safebrowsing.phishing.enabled", Pref::new(false)),
 
--- a/testing/marionette/client/marionette_driver/geckoinstance.py
+++ b/testing/marionette/client/marionette_driver/geckoinstance.py
@@ -371,18 +371,19 @@ class GeckoInstance(object):
             self.prefs = None
 
         self.close(clean=clean)
         self.start()
 
 
 class FennecInstance(GeckoInstance):
     fennec_prefs = {
-        # Enable output of dump()
+        # Enable output for dump() and chrome console API
         "browser.dom.window.dump.enabled": True,
+        "devtools.console.stdout.chrome": True,
 
         # Disable Android snippets
         "browser.snippets.enabled": False,
         "browser.snippets.syncPromo.enabled": False,
         "browser.snippets.firstrunHomepage.enabled": False,
 
         # Disable safebrowsing components
         "browser.safebrowsing.blockedURIs.enabled": False,
@@ -499,18 +500,19 @@ class DesktopInstance(GeckoInstance):
         # app.update.enabled is being removed. Once Firefox 62 becomes stable,
         # the line below can be removed as well.
         "app.update.enabled": False,
 
         # Don't show the content blocking introduction panel
         # We use a larger number than the default 22 to have some buffer
         "browser.contentblocking.introCount": 99,
 
-        # Enable output of dump()
+        # Enable output for dump() and chrome console API
         "browser.dom.window.dump.enabled": True,
+        "devtools.console.stdout.chrome": True,
 
         # Indicate that the download panel has been shown once so that whichever
         # download test runs first doesn"t show the popup inconsistently
         "browser.download.panel.shown": True,
 
         # Do not show the EULA notification which can interfer with tests
         "browser.EULA.override": True,
 
--- a/testing/mozbase/mozrunner/mozrunner/application.py
+++ b/testing/mozbase/mozrunner/mozrunner/application.py
@@ -88,26 +88,41 @@ class RemoteContext(object):
         return find_executable(binary)
 
     @abstractmethod
     def stop_application(self):
         """ Run (device manager) command to stop application. """
         pass
 
 
+devices = {}
+
+
 class FennecContext(RemoteContext):
     _remote_profiles_ini = None
     _remote_test_root = None
 
     def __init__(self, app=None, adb_path=None, avd_home=None, device_serial=None):
         self._adb = adb_path
         self.avd_home = avd_home
         self.remote_process = app
         self.device_serial = device_serial
-        self.device = ADBAndroid(adb=self.adb, device=device_serial)
+        self.device = self.get_device(self.adb, device_serial)
+
+    def get_device(self, adb_path, device_serial):
+        # Create a mozdevice.ADBAndroid object for the specified device_serial
+        # and cache it for future use. If the same device_serial is subsequently
+        # requested, retrieve it from the cache to avoid costly re-initialization.
+        global devices
+        if device_serial in devices:
+            device = devices[device_serial]
+        else:
+            device = ADBAndroid(adb=adb_path, device=device_serial)
+            devices[device_serial] = device
+        return device
 
     def stop_application(self):
         self.device.stop_application(self.remote_process)
 
     @property
     def remote_test_root(self):
         if not self._remote_test_root:
             self._remote_test_root = self.device.test_root
--- a/testing/profiles/common/user.js
+++ b/testing/profiles/common/user.js
@@ -1,13 +1,14 @@
 // Common preferences file used by both unittest and perf harnesses.
 /* globals user_pref */
 user_pref("app.update.disabledForTesting", true);
 user_pref("browser.chrome.guess_favicon", false);
 user_pref("browser.dom.window.dump.enabled", true);
+user_pref("devtools.console.stdout.chrome", true);
 // Use a python-eval-able empty JSON array even though asrouter expects plain object
 user_pref("browser.newtabpage.activity-stream.asrouter.providers.snippets", "[]");
 user_pref("browser.newtabpage.activity-stream.feeds.section.topstories", false);
 user_pref("browser.newtabpage.activity-stream.feeds.snippets", false);
 user_pref("browser.newtabpage.activity-stream.tippyTop.service.endpoint", "");
 // For Activity Stream firstrun page, use an empty string to avoid fetching.
 user_pref("browser.newtabpage.activity-stream.fxaccounts.endpoint", "");
 // Tell the search service we are running in the US.  This also has the desired
--- a/testing/tps/tps/testrunner.py
+++ b/testing/tps/tps/testrunner.py
@@ -54,16 +54,17 @@ class TPSTestRunner(object):
         'MOZ_NO_REMOTE': '1',
         'XPCOM_DEBUG_BREAK': 'warn',
     }
 
     default_preferences = {
         'app.update.disabledForTesting': True,
         'security.turn_off_all_security_so_that_viruses_can_take_over_this_computer': True,
         'browser.dom.window.dump.enabled': True,
+        'devtools.console.stdout.chrome': True,
         'browser.sessionstore.resume_from_crash': False,
         'browser.shell.checkDefaultBrowser': False,
         'browser.tabs.warnOnClose': False,
         'browser.warnOnQuit': False,
         # Allow installing extensions dropped into the profile folder
         'extensions.autoDisableScopes': 10,
         'extensions.getAddons.get.url': 'http://127.0.0.1:4567/addons/api/%IDS%.json',
         # Our pretend addons server doesn't support metadata...
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-grid/alignment/grid-self-alignment-stretch-input-range-ref.html
@@ -0,0 +1,61 @@
+<!DOCTYPE HTML>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html><head>
+  <meta charset="utf-8">
+  <title>CSS Grid Reference: align/justify-self on range INPUT items</title>
+  <link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=">
+  <style>
+html,body {
+  color:black; background-color:white; font:16px/1 monospace;
+}
+
+input {
+  margin:0;
+  padding:0;
+  border:none; /* NOTE: On Windows, GetWidgetBorder returns 1px on all sides,
+                  so we need the next declaration for the width/height to match: */
+  box-sizing: border-box;
+  width:300px;
+  height:80px;
+}
+
+.grid {
+  display: inline-grid;
+  grid: 80px / 300px;
+  place-items: stretch;
+  border:1px solid;
+}
+
+.zero { grid:0/0; }
+.zero input { width:0; height:0; }
+
+.none input { -webkit-appearance:none; }
+
+    </style>
+</head>
+<body>
+
+<div class="grid"><input type=range></div>
+<br>
+<div class="grid zero"><input type=range></div>
+<br>
+<div class="grid"><input type=range style="place-self:normal"></div>
+<br>
+<div class="grid zero"><input type=range style="place-self:normal"></div>
+<br>
+
+<div class="none">
+<div class="grid"><input type=range></div>
+<br>
+<div class="grid zero"><input type=range></div>
+<br>
+<div class="grid"><input type=range style="place-self:normal"></div>
+<br>
+<div class="grid zero"><input type=range style="place-self:normal"></div>
+</div>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-grid/alignment/grid-self-alignment-stretch-input-range.html
@@ -0,0 +1,58 @@
+<!DOCTYPE HTML>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html><head>
+  <meta charset="utf-8">
+  <title>CSS Grid Test: align/justify-self on range INPUT items</title>
+  <link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=">
+  <link rel="help" href="https://drafts.csswg.org/css-align-3/#align-self-property">
+  <link rel="match" href="grid-self-alignment-stretch-input-range-ref.html">
+  <style>
+html,body {
+  color:black; background-color:white; font:16px/1 monospace;
+}
+
+input {
+  margin:0;
+  padding:0;
+  border:none;
+}
+
+.grid {
+  display: inline-grid;
+  grid: 80px / 300px;
+  place-items: stretch;
+  border:1px solid;
+}
+
+.zero { grid:0/0; }
+
+.none input { -webkit-appearance:none; }
+
+    </style>
+</head>
+<body>
+
+<div class="grid"><input type=range></div>
+<br>
+<div class="grid zero"><input type=range></div>
+<br>
+<div class="grid"><input type=range style="place-self:normal"></div>
+<br>
+<div class="grid zero"><input type=range style="place-self:normal"></div>
+<br>
+
+<div class="none">
+<div class="grid"><input type=range></div>
+<br>
+<div class="grid zero"><input type=range></div>
+<br>
+<div class="grid"><input type=range style="place-self:normal"></div>
+<br>
+<div class="grid zero"><input type=range style="place-self:normal"></div>
+</div>
+
+</body>
+</html>
--- a/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/fennec.py
+++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/fennec.py
@@ -34,18 +34,19 @@ from .firefox import (get_timeout_multip
 
 class FennecProfile(FirefoxProfile):
     # WPT-specific prefs are set in FennecBrowser.start()
     FirefoxProfile.preferences.update({
         # Make sure Shield doesn't hit the network.
         "app.normandy.api_url": "",
         # Increase the APZ content response timeout in tests to 1 minute.
         "apz.content_response_timeout": 60000,
-        # Enable output of dump()
+        # Enable output for dump() and chrome console API
         "browser.dom.window.dump.enabled": True,
+        "devtools.console.stdout.chrome": True,
         # Disable safebrowsing components
         "browser.safebrowsing.blockedURIs.enabled": False,
         "browser.safebrowsing.downloads.enabled": False,
         "browser.safebrowsing.passwords.enabled": False,
         "browser.safebrowsing.malware.enabled": False,
         "browser.safebrowsing.phishing.enabled": False,
         # Do not restore the last open set of tabs if the browser has crashed
         "browser.sessionstore.resume_from_crash": False,
--- a/toolkit/recordreplay/ipc/ChildIPC.cpp
+++ b/toolkit/recordreplay/ipc/ChildIPC.cpp
@@ -531,18 +531,16 @@ NotifyPaintStart()
     // Repaint failures are not allowed in the repaint stress mode.
     gAllowRepaintFailures =
       Preferences::GetBool("devtools.recordreplay.allowRepaintFailures") &&
       !parent::InRepaintStressMode();
   }
 
   gNumPendingPaints++;
   gNumPendingMainThreadPaints++;
-
-  CreateCheckpoint();
 }
 
 static void
 PaintFromMainThread()
 {
   MOZ_RELEASE_ASSERT(NS_IsMainThread());
 
   gNumPendingMainThreadPaints--;
--- a/toolkit/recordreplay/ipc/ParentIPC.cpp
+++ b/toolkit/recordreplay/ipc/ParentIPC.cpp
@@ -580,18 +580,17 @@ SpawnReplayingChildren()
   gFirstReplayingChild =
     new ChildProcessInfo(std::move(firstRole), Nothing());
   gSecondReplayingChild =
     new ChildProcessInfo(MakeUnique<ChildRoleStandby>(), Nothing());
   AssignMajorCheckpoint(gSecondReplayingChild, CheckpointId::First);
 }
 
 // Hit any installed breakpoints with the specified kind.
-static void HitBreakpointsWithKind(js::BreakpointPosition::Kind aKind,
-                                   bool aRecordingBoundary = false);
+static void HitBreakpointsWithKind(js::BreakpointPosition::Kind aKind);
 
 // Change the current active child, and select a new role for the old one.
 static void
 SwitchActiveChild(ChildProcessInfo* aChild, bool aRecoverPosition = true)
 {
   MOZ_RELEASE_ASSERT(aChild != gActiveChild);
   ChildProcessInfo* oldActiveChild = gActiveChild;
   aChild->WaitUntilPaused();
@@ -1053,18 +1052,17 @@ Resume(bool aForward)
   // When rewinding, make sure the active child can rewind to the previous
   // checkpoint.
   if (!aForward && !gActiveChild->HasSavedCheckpoint(gActiveChild->RewindTargetCheckpoint())) {
     size_t targetCheckpoint = gActiveChild->RewindTargetCheckpoint();
 
     // Don't rewind if we are at the beginning of the recording.
     if (targetCheckpoint == CheckpointId::Invalid) {
       SendMessageToUIProcess("HitRecordingBeginning");
-      HitBreakpointsWithKind(js::BreakpointPosition::Kind::ForcedPause,
-                             /* aRecordingBoundary = */ true);
+      HitBreakpointsWithKind(js::BreakpointPosition::Kind::ForcedPause);
       return;
     }
 
     // Find the replaying child responsible for saving the target checkpoint.
     // We should have explicitly paused before rewinding and given fill roles
     // to the replaying children.
     ChildProcessInfo* targetChild = ReplayingChildResponsibleForSavingCheckpoint(targetCheckpoint);
     MOZ_RELEASE_ASSERT(targetChild != gActiveChild);
@@ -1081,18 +1079,17 @@ Resume(bool aForward)
 
   if (aForward) {
     // Don't send a replaying process past the recording endpoint.
     if (gActiveChild->IsPausedAtRecordingEndpoint()) {
       // Look for a recording child we can transition into.
       MOZ_RELEASE_ASSERT(!gActiveChild->IsRecording());
       if (!gRecordingChild) {
         SendMessageToUIProcess("HitRecordingEndpoint");
-        HitBreakpointsWithKind(js::BreakpointPosition::Kind::ForcedPause,
-                               /* aRecordingBoundary = */ true);
+        HitBreakpointsWithKind(js::BreakpointPosition::Kind::ForcedPause);
         return;
       }
 
       // Switch to the recording child as the active child and continue execution.
       SwitchActiveChild(gRecordingChild);
     }
 
     EnsureMajorCheckpointSaved(gActiveChild, gActiveChild->LastCheckpoint() + 1);
@@ -1211,72 +1208,85 @@ RecvHitCheckpoint(const HitCheckpointMes
   } else if (!gResumeForwardOrBackward) {
     gResumeForwardOrBackward = true;
     gMainThreadMessageLoop->PostTask(NewRunnableFunction("ResumeForwardOrBackward",
                                                          ResumeForwardOrBackward));
   }
 }
 
 static void
-HitBreakpoint(uint32_t* aBreakpoints, size_t aNumBreakpoints, bool aRecordingBoundary)
+HitBreakpoint(uint32_t* aBreakpoints, size_t aNumBreakpoints,
+              js::BreakpointPosition::Kind aSharedKind)
 {
   if (!gActiveChild->IsPaused()) {
-    if (aNumBreakpoints) {
-      Print("Warning: Process resumed before breakpoints were hit.\n");
-    }
     delete[] aBreakpoints;
     return;
   }
 
-  MarkActiveChildExplicitPause();
-
-  gResumeForwardOrBackward = true;
+  switch (aSharedKind) {
+  case js::BreakpointPosition::ForcedPause:
+    MarkActiveChildExplicitPause();
+    MOZ_FALLTHROUGH;
+  case js::BreakpointPosition::PositionChange:
+    // Call all breakpoint handlers.
+    for (size_t i = 0; i < aNumBreakpoints; i++) {
+      AutoSafeJSContext cx;
+      if (!js::HitBreakpoint(cx, aBreakpoints[i])) {
+        Print("Warning: hitBreakpoint hook threw an exception.\n");
+      }
+    }
+    break;
+  default:
+    gResumeForwardOrBackward = true;
 
-  // Call breakpoint handlers until one of them explicitly resumes forward or
-  // backward travel.
-  for (size_t i = 0; i < aNumBreakpoints && gResumeForwardOrBackward; i++) {
-    AutoSafeJSContext cx;
-    if (!js::HitBreakpoint(cx, aBreakpoints[i])) {
-      Print("Warning: hitBreakpoint hook threw an exception.\n");
+    MarkActiveChildExplicitPause();
+
+    // Call breakpoint handlers until one of them explicitly resumes forward or
+    // backward travel.
+    for (size_t i = 0; i < aNumBreakpoints && gResumeForwardOrBackward; i++) {
+      AutoSafeJSContext cx;
+      if (!js::HitBreakpoint(cx, aBreakpoints[i])) {
+        Print("Warning: hitBreakpoint hook threw an exception.\n");
+      }
     }
-  }
 
-  // If the child was not explicitly resumed by any breakpoint handler, and we
-  // are not at a forced pause at the recording boundary, resume travel in
-  // whichever direction it was going previously.
-  if (gResumeForwardOrBackward && !aRecordingBoundary) {
-    ResumeForwardOrBackward();
+    // If the child was not explicitly resumed by any breakpoint handler,
+    // resume travel in whichever direction we were going previously.
+    if (gResumeForwardOrBackward) {
+      ResumeForwardOrBackward();
+    }
+    break;
   }
 
   delete[] aBreakpoints;
 }
 
 static void
 RecvHitBreakpoint(const HitBreakpointMessage& aMsg)
 {
   uint32_t* breakpoints = new uint32_t[aMsg.NumBreakpoints()];
   PodCopy(breakpoints, aMsg.Breakpoints(), aMsg.NumBreakpoints());
   gMainThreadMessageLoop->PostTask(NewRunnableFunction("HitBreakpoint", HitBreakpoint,
                                                        breakpoints, aMsg.NumBreakpoints(),
-                                                       /* aRecordingBoundary = */ false));
+                                                       js::BreakpointPosition::Invalid));
 }
 
 static void
-HitBreakpointsWithKind(js::BreakpointPosition::Kind aKind, bool aRecordingBoundary)
+HitBreakpointsWithKind(js::BreakpointPosition::Kind aKind)
 {
   Vector<uint32_t> breakpoints;
   gActiveChild->GetMatchingInstalledBreakpoints([=](js::BreakpointPosition::Kind aInstalled) {
       return aInstalled == aKind;
     }, breakpoints);
   if (!breakpoints.empty()) {
     uint32_t* newBreakpoints = new uint32_t[breakpoints.length()];
     PodCopy(newBreakpoints, breakpoints.begin(), breakpoints.length());
     gMainThreadMessageLoop->PostTask(NewRunnableFunction("HitBreakpoint", HitBreakpoint,
                                                          newBreakpoints, breakpoints.length(),
-                                                         aRecordingBoundary));
+                                                         aKind));
   }
 }
 
 static void
 RecvMiddlemanCallRequest(const MiddlemanCallRequestMessage& aMsg)
 {
   MiddlemanCallResponseMessage* response = ProcessMiddlemanCallMessage(aMsg);
   gActiveChild->SendMessage(*response);
--- a/widget/cocoa/nsNativeThemeCocoa.mm
+++ b/widget/cocoa/nsNativeThemeCocoa.mm
@@ -4385,34 +4385,16 @@ nsNativeThemeCocoa::GetMinimumWidgetSize
     }
 
     case StyleAppearance::Tab:
     {
       aResult->SizeTo(0, tabHeights[miniControlSize]);
       break;
     }
 
-    case StyleAppearance::Range:
-    {
-      // The Mac Appearance Manager API (the old API we're currently using)
-      // doesn't define constants to obtain a minimum size for sliders. We use
-      // the "thickness" of a slider that has default dimensions for both the
-      // minimum width and height to get something sane and so that paint
-      // invalidation works.
-      SInt32 size = 0;
-      if (IsRangeHorizontal(aFrame)) {
-        ::GetThemeMetric(kThemeMetricHSliderHeight, &size);
-      } else {
-        ::GetThemeMetric(kThemeMetricVSliderWidth, &size);
-      }
-      aResult->SizeTo(size, size);
-      *aIsOverridable = true;
-      break;
-    }
-
     case StyleAppearance::RangeThumb:
     {
       SInt32 width = 0;
       SInt32 height = 0;
       ::GetThemeMetric(kThemeMetricSliderMinThumbWidth, &width);
       ::GetThemeMetric(kThemeMetricSliderMinThumbHeight, &height);
       aResult->SizeTo(width, height);
       *aIsOverridable = false;
--- a/widget/gtk/nsNativeThemeGTK.cpp
+++ b/widget/gtk/nsNativeThemeGTK.cpp
@@ -1613,29 +1613,16 @@ nsNativeThemeGTK::GetMinimumWidgetSize(n
           moz_gtk_get_scalethumb_metrics(GTK_ORIENTATION_VERTICAL, &thumb_height, &thumb_length);
         }
         aResult->width = thumb_length;
         aResult->height = thumb_height;
 
         *aIsOverridable = false;
       }
       break;
-    case StyleAppearance::Range:
-      {
-        gint scale_width, scale_height;
-
-        moz_gtk_get_scale_metrics(IsRangeHorizontal(aFrame) ?
-            GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL,
-            &scale_width, &scale_height);
-        aResult->width = scale_width;
-        aResult->height = scale_height;
-
-        *aIsOverridable = true;
-      }
-      break;
     case StyleAppearance::ScalethumbHorizontal:
     case StyleAppearance::ScalethumbVertical:
       {
         gint thumb_length, thumb_height;
 
         if (aAppearance == StyleAppearance::ScalethumbVertical) {
           moz_gtk_get_scalethumb_metrics(GTK_ORIENTATION_VERTICAL, &thumb_length, &thumb_height);
           aResult->width = thumb_height;
--- a/widget/headless/HeadlessThemeGTK.cpp
+++ b/widget/headless/HeadlessThemeGTK.cpp
@@ -300,20 +300,16 @@ HeadlessThemeGTK::GetMinimumWidgetSize(n
       aResult->height = 18;
       *aIsOverridable = false;
       break;
     case StyleAppearance::ScalethumbVertical:
       aResult->width = 18;
       aResult->height = 13;
       *aIsOverridable = false;
       break;
-    case StyleAppearance::Range:
-      aResult->width = 14;
-      aResult->height = 18;
-      break;
     case StyleAppearance::Menuseparator:
       aResult->width = 0;
       aResult->height = 8;
       *aIsOverridable = false;
       break;
     default:
       break;
   }