Merge inbound to mozilla-central. a=merge
authorshindli <shindli@mozilla.com>
Thu, 27 Sep 2018 00:52:12 +0300
changeset 494096 7ac88abc3c57
parent 494064 f8b2114ab512 (current diff)
parent 494095 2a668be15af5 (diff)
child 494107 23f8684d0873
child 494133 63e13f558b46
push id9984
push userffxbld-merge
push dateMon, 15 Oct 2018 21:07:35 +0000
treeherdermozilla-beta@183d27ea8570 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone64.0a1
first release with
nightly linux32
7ac88abc3c57 / 64.0a1 / 20180926220146 / files
nightly linux64
7ac88abc3c57 / 64.0a1 / 20180926220146 / files
nightly mac
7ac88abc3c57 / 64.0a1 / 20180926220146 / files
nightly win32
7ac88abc3c57 / 64.0a1 / 20180926220146 / files
nightly win64
7ac88abc3c57 / 64.0a1 / 20180926220146 / 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/netmonitor/src/assets/styles/NetworkDetailsPanel.css
gfx/webrender_bindings/WebRenderAPI.cpp
gfx/webrender_bindings/WebRenderAPI.h
gfx/webrender_bindings/src/bindings.rs
gfx/webrender_bindings/webrender_ffi_generated.h
layout/forms/nsIComboboxControlFrame.h
layout/forms/nsIListControlFrame.h
--- a/accessible/html/HTMLSelectAccessible.cpp
+++ b/accessible/html/HTMLSelectAccessible.cpp
@@ -12,19 +12,19 @@
 #include "nsEventShell.h"
 #include "nsTextEquivUtils.h"
 #include "Role.h"
 #include "States.h"
 
 #include "nsCOMPtr.h"
 #include "mozilla/dom/HTMLOptionElement.h"
 #include "mozilla/dom/HTMLSelectElement.h"
-#include "nsIComboboxControlFrame.h"
+#include "nsComboboxControlFrame.h"
 #include "nsContainerFrame.h"
-#include "nsIListControlFrame.h"
+#include "nsListControlFrame.h"
 
 using namespace mozilla::a11y;
 using namespace mozilla::dom;
 
 ////////////////////////////////////////////////////////////////////////////////
 // HTMLSelectListAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
@@ -90,17 +90,17 @@ bool
 HTMLSelectListAccessible::AreItemsOperable() const
 {
   return true;
 }
 
 Accessible*
 HTMLSelectListAccessible::CurrentItem() const
 {
-  nsIListControlFrame* listControlFrame = do_QueryFrame(GetFrame());
+  nsListControlFrame* listControlFrame = do_QueryFrame(GetFrame());
   if (listControlFrame) {
     nsCOMPtr<nsIContent> activeOptionNode = listControlFrame->GetCurrentOption();
     if (activeOptionNode) {
       DocAccessible* document = Document();
       if (document)
         return document->GetAccessible(activeOptionNode);
     }
   }
@@ -348,17 +348,17 @@ HTMLSelectOptGroupAccessible::DoAction(u
 HTMLComboboxAccessible::
   HTMLComboboxAccessible(nsIContent* aContent, DocAccessible* aDoc) :
   AccessibleWrap(aContent, aDoc)
 {
   mType = eHTMLComboboxType;
   mGenericTypes |= eCombobox;
   mStateFlags |= eNoKidsFromDOM;
 
-  nsIComboboxControlFrame* comboFrame = do_QueryFrame(GetFrame());
+  nsComboboxControlFrame* comboFrame = do_QueryFrame(GetFrame());
   if (comboFrame) {
     nsIFrame* listFrame = comboFrame->GetDropDown();
     if (listFrame) {
       mListAccessible = new HTMLComboboxListAccessible(mParent, mContent, mDoc);
       Document()->BindToDocument(mListAccessible, nullptr);
       AppendChild(mListAccessible);
     }
   }
@@ -399,17 +399,17 @@ HTMLComboboxAccessible::Shutdown()
 uint64_t
 HTMLComboboxAccessible::NativeState() const
 {
   // As a HTMLComboboxAccessible we can have the following states:
   // FOCUSED, FOCUSABLE, HASPOPUP, EXPANDED, COLLAPSED
   // Get focus status from base class
   uint64_t state = Accessible::NativeState();
 
-  nsIComboboxControlFrame* comboFrame = do_QueryFrame(GetFrame());
+  nsComboboxControlFrame* comboFrame = do_QueryFrame(GetFrame());
   if (comboFrame && comboFrame->IsDroppedDown())
     state |= states::EXPANDED;
   else
     state |= states::COLLAPSED;
 
   state |= states::HASPOPUP;
   return state;
 }
@@ -456,17 +456,17 @@ HTMLComboboxAccessible::DoAction(uint8_t
 }
 
 void
 HTMLComboboxAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName)
 {
   if (aIndex != HTMLComboboxAccessible::eAction_Click)
     return;
 
-  nsIComboboxControlFrame* comboFrame = do_QueryFrame(GetFrame());
+  nsComboboxControlFrame* comboFrame = do_QueryFrame(GetFrame());
   if (!comboFrame)
     return;
 
   if (comboFrame->IsDroppedDown())
     aName.AssignLiteral("close");
   else
     aName.AssignLiteral("open");
 }
@@ -490,17 +490,17 @@ bool
 HTMLComboboxAccessible::IsActiveWidget() const
 {
   return FocusMgr()->HasDOMFocus(mContent);
 }
 
 bool
 HTMLComboboxAccessible::AreItemsOperable() const
 {
-  nsIComboboxControlFrame* comboboxFrame = do_QueryFrame(GetFrame());
+  nsComboboxControlFrame* comboboxFrame = do_QueryFrame(GetFrame());
   return comboboxFrame && comboboxFrame->IsDroppedDown();
 }
 
 Accessible*
 HTMLComboboxAccessible::CurrentItem() const
 {
   return AreItemsOperable() ? mListAccessible->CurrentItem() : nullptr;
 }
@@ -548,17 +548,17 @@ HTMLComboboxListAccessible::
 
 ////////////////////////////////////////////////////////////////////////////////
 // HTMLComboboxAccessible: Accessible
 
 nsIFrame*
 HTMLComboboxListAccessible::GetFrame() const
 {
   nsIFrame* frame = HTMLSelectListAccessible::GetFrame();
-  nsIComboboxControlFrame* comboBox = do_QueryFrame(frame);
+  nsComboboxControlFrame* comboBox = do_QueryFrame(frame);
   if (comboBox) {
     return comboBox->GetDropDown();
   }
 
   return nullptr;
 }
 
 role
@@ -570,17 +570,17 @@ HTMLComboboxListAccessible::NativeRole()
 uint64_t
 HTMLComboboxListAccessible::NativeState() const
 {
   // As a HTMLComboboxListAccessible we can have the following states:
   // FOCUSED, FOCUSABLE, FLOATING, INVISIBLE
   // Get focus status from base class
   uint64_t state = Accessible::NativeState();
 
-  nsIComboboxControlFrame* comboFrame = do_QueryFrame(mParent->GetFrame());
+  nsComboboxControlFrame* comboFrame = do_QueryFrame(mParent->GetFrame());
   if (comboFrame && comboFrame->IsDroppedDown())
     state |= states::FLOATING;
   else
     state |= states::INVISIBLE;
 
   return state;
 }
 
--- a/accessible/html/moz.build
+++ b/accessible/html/moz.build
@@ -14,16 +14,17 @@ UNIFIED_SOURCES += [
     'HTMLSelectAccessible.cpp',
     'HTMLTableAccessible.cpp',
 ]
 
 LOCAL_INCLUDES += [
     '/accessible/base',
     '/accessible/generic',
     '/accessible/xpcom',
+    '/layout/forms',
     '/layout/generic',
     '/layout/tables',
     '/layout/xul',
 ]
 
 if 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']:
     LOCAL_INCLUDES += [
         '/accessible/atk',
--- a/accessible/ipc/win/ProxyAccessible.cpp
+++ b/accessible/ipc/win/ProxyAccessible.cpp
@@ -492,17 +492,17 @@ GetIA2TextBoundary(AccessibleTextBoundar
   switch (aGeckoBoundaryType) {
     case nsIAccessibleText::BOUNDARY_CHAR:
       return IA2_TEXT_BOUNDARY_CHAR;
     case nsIAccessibleText::BOUNDARY_WORD_START:
       return IA2_TEXT_BOUNDARY_WORD;
     case nsIAccessibleText::BOUNDARY_LINE_START:
       return IA2_TEXT_BOUNDARY_LINE;
     default:
-      MOZ_RELEASE_ASSERT(false);
+      MOZ_CRASH();
   }
 }
 
 bool
 ProxyAccessible::TextSubstring(int32_t aStartOffset, int32_t aEndOffset,
                                nsString& aText) const
 {
   RefPtr<IAccessibleText> acc = QueryInterface<IAccessibleText>(this);
@@ -682,17 +682,17 @@ ProxyAccessible::ScrollSubstringToPoint(
   }
 
   IA2CoordinateType coordType;
   if (aCoordinateType == nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE) {
     coordType = IA2_COORDTYPE_SCREEN_RELATIVE;
   } else if (aCoordinateType == nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE) {
     coordType = IA2_COORDTYPE_PARENT_RELATIVE;
   } else {
-    MOZ_RELEASE_ASSERT(false, "unsupported coord type");
+    MOZ_CRASH("unsupported coord type");
   }
 
   acc->scrollSubstringToPoint(static_cast<long>(aStartOffset),
                               static_cast<long>(aEndOffset),
                               coordType,
                               static_cast<long>(aX),
                               static_cast<long>(aY));
 }
--- a/accessible/ipc/win/moz.build
+++ b/accessible/ipc/win/moz.build
@@ -47,14 +47,24 @@ if CONFIG['ACCESSIBILITY']:
     LOCAL_INCLUDES += [
         '/accessible/base',
         '/accessible/generic',
         '/accessible/windows/ia2',
         '/accessible/windows/msaa',
         '/accessible/xpcom',
     ]
 
+    # Suppress warnings from the MIDL generated code.
+    if CONFIG['CC_TYPE'] == 'clang-cl':
+        CFLAGS += [
+            '-Wno-extern-initializer',
+            '-Wno-incompatible-pointer-types',
+            '-Wno-missing-braces',
+            '-Wno-unused-const-variable',
+        ]
+
+        CXXFLAGS += [
+            '-Wno-missing-braces',
+        ]
+
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
-
-if CONFIG['CC_TYPE'] == 'clang-cl':
-    AllowCompilerWarnings()  # workaround for bug 1090497
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -63,16 +63,17 @@ XPCOMUtils.defineLazyModuleGetters(this,
   SiteDataManager: "resource:///modules/SiteDataManager.jsm",
   SitePermissions: "resource:///modules/SitePermissions.jsm",
   TabCrashHandler: "resource:///modules/ContentCrashHandlers.jsm",
   TelemetryStopwatch: "resource://gre/modules/TelemetryStopwatch.jsm",
   Translation: "resource:///modules/translation/Translation.jsm",
   UITour: "resource:///modules/UITour.jsm",
   UpdateUtils: "resource://gre/modules/UpdateUtils.jsm",
   UrlbarInput: "resource:///modules/UrlbarInput.jsm",
+  UrlbarPrefs: "resource:///modules/UrlbarPrefs.jsm",
   Utils: "resource://gre/modules/sessionstore/Utils.jsm",
   Weave: "resource://services-sync/main.js",
   WebNavigationFrames: "resource://gre/modules/WebNavigationFrames.jsm",
   fxAccounts: "resource://gre/modules/FxAccounts.jsm",
   webrtcUI: "resource:///modules/webrtcUI.jsm",
   ZoomUI: "resource:///modules/ZoomUI.jsm",
 });
 
@@ -4649,18 +4650,19 @@ var XULBrowserWindow = {
     if (url) {
       url = Services.textToSubURI.unEscapeURIForUI("UTF-8", url);
 
       // Encode bidirectional formatting characters.
       // (RFC 3987 sections 3.2 and 4.1 paragraph 6)
       url = url.replace(/[\u200e\u200f\u202a\u202b\u202c\u202d\u202e]/g,
                         encodeURIComponent);
 
-      if (gURLBar._mayTrimURLs /* corresponds to browser.urlbar.trimURLs */)
+      if (UrlbarPrefs.get("trimURLs")) {
         url = trimURL(url);
+      }
     }
 
     this.overLink = url;
     LinkTargetDisplay.update();
   },
 
   showTooltip(x, y, tooltip, direction, browser) {
     if (Cc["@mozilla.org/widget/dragservice;1"].getService(Ci.nsIDragService).
--- a/browser/components/extensions/parent/ext-sessions.js
+++ b/browser/components/extensions/parent/ext-sessions.js
@@ -177,36 +177,36 @@ this.sessions = class extends ExtensionA
 
           SessionStore.deleteCustomTabValue(tab, encodedKey);
         },
 
         setWindowValue(windowId, key, value) {
           let {win, encodedKey} =
             getWindowParams(extension.id, key, windowId, context);
 
-          SessionStore.setWindowValue(win, encodedKey, JSON.stringify(value));
+          SessionStore.setCustomWindowValue(win, encodedKey, JSON.stringify(value));
         },
 
         async getWindowValue(windowId, key) {
           let {win, encodedKey} =
             getWindowParams(extension.id, key, windowId, context);
 
-          let value = SessionStore.getWindowValue(win, encodedKey);
+          let value = SessionStore.getCustomWindowValue(win, encodedKey);
           if (value) {
             return JSON.parse(value);
           }
 
           return undefined;
         },
 
         removeWindowValue(windowId, key) {
           let {win, encodedKey} =
             getWindowParams(extension.id, key, windowId, context);
 
-          SessionStore.deleteWindowValue(win, encodedKey);
+          SessionStore.deleteCustomWindowValue(win, encodedKey);
         },
 
         onChanged: new EventManager({
           context,
           name: "sessions.onChanged",
           register: fire => {
             let observer = () => {
               fire.async();
--- a/browser/components/sessionstore/SessionStore.jsm
+++ b/browser/components/sessionstore/SessionStore.jsm
@@ -295,26 +295,26 @@ var SessionStore = {
   undoCloseWindow: function ss_undoCloseWindow(aIndex) {
     return SessionStoreInternal.undoCloseWindow(aIndex);
   },
 
   forgetClosedWindow: function ss_forgetClosedWindow(aIndex) {
     return SessionStoreInternal.forgetClosedWindow(aIndex);
   },
 
-  getWindowValue: function ss_getWindowValue(aWindow, aKey) {
-    return SessionStoreInternal.getWindowValue(aWindow, aKey);
-  },
-
-  setWindowValue: function ss_setWindowValue(aWindow, aKey, aStringValue) {
-    SessionStoreInternal.setWindowValue(aWindow, aKey, aStringValue);
-  },
-
-  deleteWindowValue: function ss_deleteWindowValue(aWindow, aKey) {
-    SessionStoreInternal.deleteWindowValue(aWindow, aKey);
+  getCustomWindowValue(aWindow, aKey) {
+    return SessionStoreInternal.getCustomWindowValue(aWindow, aKey);
+  },
+
+  setCustomWindowValue(aWindow, aKey, aStringValue) {
+    SessionStoreInternal.setCustomWindowValue(aWindow, aKey, aStringValue);
+  },
+
+  deleteCustomWindowValue(aWindow, aKey) {
+    SessionStoreInternal.deleteCustomWindowValue(aWindow, aKey);
   },
 
   getCustomTabValue(aTab, aKey) {
     return SessionStoreInternal.getCustomTabValue(aTab, aKey);
   },
 
   setCustomTabValue(aTab, aKey, aStringValue) {
     SessionStoreInternal.setCustomTabValue(aTab, aKey, aStringValue);
@@ -323,26 +323,26 @@ var SessionStore = {
   deleteCustomTabValue(aTab, aKey) {
     SessionStoreInternal.deleteCustomTabValue(aTab, aKey);
   },
 
   getLazyTabValue(aTab, aKey) {
     return SessionStoreInternal.getLazyTabValue(aTab, aKey);
   },
 
-  getGlobalValue: function ss_getGlobalValue(aKey) {
-    return SessionStoreInternal.getGlobalValue(aKey);
-  },
-
-  setGlobalValue: function ss_setGlobalValue(aKey, aStringValue) {
-    SessionStoreInternal.setGlobalValue(aKey, aStringValue);
-  },
-
-  deleteGlobalValue: function ss_deleteGlobalValue(aKey) {
-    SessionStoreInternal.deleteGlobalValue(aKey);
+  getCustomGlobalValue(aKey) {
+    return SessionStoreInternal.getCustomGlobalValue(aKey);
+  },
+
+  setCustomGlobalValue(aKey, aStringValue) {
+    SessionStoreInternal.setCustomGlobalValue(aKey, aStringValue);
+  },
+
+  deleteCustomGlobalValue(aKey) {
+    SessionStoreInternal.deleteCustomGlobalValue(aKey);
   },
 
   persistTabAttribute: function ss_persistTabAttribute(aName) {
     SessionStoreInternal.persistTabAttribute(aName);
   },
 
   restoreLastSession: function ss_restoreLastSession() {
     SessionStoreInternal.restoreLastSession();
@@ -2602,46 +2602,46 @@ var SessionStoreInternal = {
     let winData = this._closedWindows[aIndex];
     this._removeClosedWindow(aIndex);
     this._saveableClosedWindowData.delete(winData);
 
     // Notify of changes to closed objects.
     this._notifyOfClosedObjectsChange();
   },
 
-  getWindowValue: function ssi_getWindowValue(aWindow, aKey) {
+  getCustomWindowValue(aWindow, aKey) {
     if ("__SSi" in aWindow) {
       let data = this._windows[aWindow.__SSi].extData || {};
       return data[aKey] || "";
     }
 
     if (DyingWindowCache.has(aWindow)) {
       let data = DyingWindowCache.get(aWindow).extData || {};
       return data[aKey] || "";
     }
 
     throw Components.Exception("Window is not tracked", Cr.NS_ERROR_INVALID_ARG);
   },
 
-  setWindowValue: function ssi_setWindowValue(aWindow, aKey, aStringValue) {
+  setCustomWindowValue(aWindow, aKey, aStringValue) {
     if (typeof aStringValue != "string") {
-      throw new TypeError("setWindowValue only accepts string values");
+      throw new TypeError("setCustomWindowValue only accepts string values");
     }
 
     if (!("__SSi" in aWindow)) {
       throw Components.Exception("Window is not tracked", Cr.NS_ERROR_INVALID_ARG);
     }
     if (!this._windows[aWindow.__SSi].extData) {
       this._windows[aWindow.__SSi].extData = {};
     }
     this._windows[aWindow.__SSi].extData[aKey] = aStringValue;
     this.saveStateDelayed(aWindow);
   },
 
-  deleteWindowValue: function ssi_deleteWindowValue(aWindow, aKey) {
+  deleteCustomWindowValue(aWindow, aKey) {
     if (aWindow.__SSi && this._windows[aWindow.__SSi].extData &&
         this._windows[aWindow.__SSi].extData[aKey])
       delete this._windows[aWindow.__SSi].extData[aKey];
     this.saveStateDelayed(aWindow);
   },
 
   getCustomTabValue(aTab, aKey) {
     return (TAB_CUSTOM_VALUES.get(aTab) || {})[aKey] || "";
@@ -2678,30 +2678,30 @@ var SessionStoreInternal = {
    *        The tabbrowser-tab the data is for.
    * @param aKey (string)
    *        The key which maps to the desired data.
    */
   getLazyTabValue(aTab, aKey) {
     return (TAB_LAZY_STATES.get(aTab) || {})[aKey];
   },
 
-  getGlobalValue: function ssi_getGlobalValue(aKey) {
+  getCustomGlobalValue(aKey) {
     return this._globalState.get(aKey);
   },
 
-  setGlobalValue: function ssi_setGlobalValue(aKey, aStringValue) {
+  setCustomGlobalValue(aKey, aStringValue) {
     if (typeof aStringValue != "string") {
-      throw new TypeError("setGlobalValue only accepts string values");
+      throw new TypeError("setCustomGlobalValue only accepts string values");
     }
 
     this._globalState.set(aKey, aStringValue);
     this.saveStateDelayed();
   },
 
-  deleteGlobalValue: function ssi_deleteGlobalValue(aKey) {
+  deleteCustomGlobalValue(aKey) {
     this._globalState.delete(aKey);
     this.saveStateDelayed();
   },
 
   persistTabAttribute: function ssi_persistTabAttribute(aName) {
     if (TabAttributes.persist(aName)) {
       this.saveStateDelayed();
     }
--- a/browser/components/sessionstore/test/browser_345898.js
+++ b/browser/components/sessionstore/test/browser_345898.js
@@ -31,15 +31,15 @@ function test() {
     /NS_ERROR_ILLEGAL_VALUE/,
     "Invalid window for getClosedTabData throws");
   Assert.throws(() => ss.undoCloseTab({}, 0),
     /NS_ERROR_ILLEGAL_VALUE/,
     "Invalid window for undoCloseTab throws");
   Assert.throws(() => ss.undoCloseTab(window, -1),
     /NS_ERROR_ILLEGAL_VALUE/,
     "Invalid index for undoCloseTab throws");
-  Assert.throws(() => ss.getWindowValue({}, ""),
+  Assert.throws(() => ss.getCustomWindowValue({}, ""),
     /NS_ERROR_ILLEGAL_VALUE/,
-    "Invalid window for getWindowValue throws");
-  Assert.throws(() => ss.setWindowValue({}, "", ""),
+    "Invalid window for getCustomWindowValue throws");
+  Assert.throws(() => ss.setCustomWindowValue({}, "", ""),
     /NS_ERROR_ILLEGAL_VALUE/,
-    "Invalid window for setWindowValue throws");
+    "Invalid window for setCustomWindowValue throws");
 }
--- a/browser/components/sessionstore/test/browser_350525.js
+++ b/browser/components/sessionstore/test/browser_350525.js
@@ -12,35 +12,35 @@ add_task(async function() {
   function test(aLambda) {
     try {
       return aLambda() || true;
     } catch (ex) { }
     return false;
   }
 
   /**
-   * setWindowValue, et al.
+   * setCustomWindowValue, et al.
    */
   let key = "Unique name: " + Date.now();
   let value = "Unique value: " + Math.random();
 
   // test adding
-  ok(test(() => ss.setWindowValue(window, key, value)), "set a window value");
+  ok(test(() => ss.setCustomWindowValue(window, key, value)), "set a window value");
 
   // test retrieving
-  is(ss.getWindowValue(window, key), value, "stored window value matches original");
+  is(ss.getCustomWindowValue(window, key), value, "stored window value matches original");
 
   // test deleting
-  ok(test(() => ss.deleteWindowValue(window, key)), "delete the window value");
+  ok(test(() => ss.deleteCustomWindowValue(window, key)), "delete the window value");
 
   // value should not exist post-delete
-  is(ss.getWindowValue(window, key), "", "window value was deleted");
+  is(ss.getCustomWindowValue(window, key), "", "window value was deleted");
 
   // test deleting a non-existent value
-  ok(test(() => ss.deleteWindowValue(window, key)), "delete non-existent window value");
+  ok(test(() => ss.deleteCustomWindowValue(window, key)), "delete non-existent window value");
 
   /**
    * setCustomTabValue, et al.
    */
   key = "Unique name: " + Math.random();
   value = "Unique value: " + Date.now();
   let tab = BrowserTestUtils.addTab(gBrowser);
   tab.linkedBrowser.stop();
--- a/browser/components/sessionstore/test/browser_394759_basic.js
+++ b/browser/components/sessionstore/test/browser_394759_basic.js
@@ -23,17 +23,17 @@ function test() {
 
   // Clear the list of closed windows.
   forgetClosedWindows();
 
   provideWindow(function onTestURLLoaded(newWin) {
     BrowserTestUtils.addTab(newWin.gBrowser).linkedBrowser.stop();
 
     // Mark the window with some unique data to be restored later on.
-    ss.setWindowValue(newWin, uniqueKey, uniqueValue);
+    ss.setCustomWindowValue(newWin, uniqueKey, uniqueValue);
     let [txt] = newWin.content.document.querySelectorAll("#txt");
     txt.value = uniqueText;
 
     let browser = newWin.gBrowser.selectedBrowser;
     setInputChecked(browser, {id: "chk", checked: true}).then(() => {
       BrowserTestUtils.closeWindow(newWin).then(() => {
         is(ss.getClosedWindowCount(), 1,
            "The closed window was added to Recently Closed Windows");
@@ -72,17 +72,17 @@ function test() {
              "The window correctly restored 2 tabs");
           is(newWin2.gBrowser.currentURI.spec, TEST_URL,
              "The window correctly restored the URL");
 
           let chk;
           [txt, chk] = newWin2.content.document.querySelectorAll("#txt, #chk");
           ok(txt.value == uniqueText && chk.checked,
              "The window correctly restored the form");
-          is(ss.getWindowValue(newWin2, uniqueKey), uniqueValue,
+          is(ss.getCustomWindowValue(newWin2, uniqueKey), uniqueValue,
              "The window correctly restored the data associated with it");
 
           // Clean up.
           BrowserTestUtils.closeWindow(newWin2).then(finish);
         }, true);
       });
     });
   }, TEST_URL);
--- a/browser/components/sessionstore/test/browser_394759_perwindowpb.js
+++ b/browser/components/sessionstore/test/browser_394759_perwindowpb.js
@@ -14,17 +14,17 @@ const TESTS = [
 ];
 
 function promiseTestOpenCloseWindow(aIsPrivate, aTest) {
   return (async function() {
     let win = await BrowserTestUtils.openNewBrowserWindow({ "private": aIsPrivate });
     BrowserTestUtils.loadURI(win.gBrowser.selectedBrowser, aTest.url);
     await promiseBrowserLoaded(win.gBrowser.selectedBrowser, true, aTest.url);
     // Mark the window with some unique data to be restored later on.
-    ss.setWindowValue(win, aTest.key, aTest.value);
+    ss.setCustomWindowValue(win, aTest.key, aTest.value);
     await TabStateFlusher.flushWindow(win);
     // Close.
     await BrowserTestUtils.closeWindow(win);
   })();
 }
 
 function promiseTestOnWindow(aIsPrivate, aValue) {
   return (async function() {
--- a/browser/components/sessionstore/test/browser_465223.js
+++ b/browser/components/sessionstore/test/browser_465223.js
@@ -8,34 +8,34 @@ add_task(async function test_clearWindow
   let uniqueKey1 = "bug 465223.1";
   let uniqueKey2 = "bug 465223.2";
   let uniqueValue1 = "unik" + Date.now();
   let uniqueValue2 = "pi != " + Math.random();
 
   // open a window and set a value on it
   let newWin = openDialog(location, "_blank", "chrome,all,dialog=no");
   await promiseWindowLoaded(newWin);
-  ss.setWindowValue(newWin, uniqueKey1, uniqueValue1);
+  ss.setCustomWindowValue(newWin, uniqueKey1, uniqueValue1);
 
   let newState = { windows: [{ tabs: [{ entries: [] }], extData: {} }] };
   newState.windows[0].extData[uniqueKey2] = uniqueValue2;
   await setWindowState(newWin, newState);
 
   is(newWin.gBrowser.tabs.length, 2,
     "original tab wasn't overwritten");
-  is(ss.getWindowValue(newWin, uniqueKey1), uniqueValue1,
+  is(ss.getCustomWindowValue(newWin, uniqueKey1), uniqueValue1,
     "window value wasn't overwritten when the tabs weren't");
-  is(ss.getWindowValue(newWin, uniqueKey2), uniqueValue2,
+  is(ss.getCustomWindowValue(newWin, uniqueKey2), uniqueValue2,
     "new window value was correctly added");
 
   newState.windows[0].extData[uniqueKey2] = uniqueValue1;
   await setWindowState(newWin, newState, true);
 
   is(newWin.gBrowser.tabs.length, 1,
     "original tabs were overwritten");
-  is(ss.getWindowValue(newWin, uniqueKey1), "",
+  is(ss.getCustomWindowValue(newWin, uniqueKey1), "",
     "window value was cleared");
-  is(ss.getWindowValue(newWin, uniqueKey2), uniqueValue1,
+  is(ss.getCustomWindowValue(newWin, uniqueKey2), uniqueValue1,
     "window value was correctly overwritten");
 
   // clean up
   await BrowserTestUtils.closeWindow(newWin);
 });
--- a/browser/components/sessionstore/test/browser_477657.js
+++ b/browser/components/sessionstore/test/browser_477657.js
@@ -13,25 +13,25 @@ add_task(async function test_sizemodeDef
       title: "About:",
     }],
     sizemode: "maximized",
   }] };
 
   let uniqueKey = "bug 477657";
   let uniqueValue = "unik" + Date.now();
 
-  ss.setWindowValue(newWin, uniqueKey, uniqueValue);
-  is(ss.getWindowValue(newWin, uniqueKey), uniqueValue,
+  ss.setCustomWindowValue(newWin, uniqueKey, uniqueValue);
+  is(ss.getCustomWindowValue(newWin, uniqueKey), uniqueValue,
      "window value was set before the window was overwritten");
 
   await setWindowState(newWin, newState, true);
   // use newWin.setTimeout(..., 0) to mirror sss_restoreWindowFeatures
   await new Promise(resolve => newWin.setTimeout(resolve, 0));
 
-  is(ss.getWindowValue(newWin, uniqueKey), "",
+  is(ss.getCustomWindowValue(newWin, uniqueKey), "",
     "window value was implicitly cleared");
 
   is(newWin.windowState, newWin.STATE_MAXIMIZED,
     "the window was maximized");
 
   is(JSON.parse(ss.getClosedTabData(newWin)).length, 1,
     "the closed tab was added before the window was overwritten");
   delete newState.windows[0]._closedTabs;
--- a/browser/components/sessionstore/test/browser_524745.js
+++ b/browser/components/sessionstore/test/browser_524745.js
@@ -8,17 +8,17 @@ function test() {
   let uniqKey = "bug524745";
   let uniqVal = Date.now().toString();
 
   waitForExplicitFinish();
 
   whenNewWindowLoaded({ private: false }, function(window_B) {
     waitForFocus(function() {
       // Add identifying information to window_B
-      ss.setWindowValue(window_B, uniqKey, uniqVal);
+      ss.setCustomWindowValue(window_B, uniqKey, uniqVal);
       let state = JSON.parse(ss.getBrowserState());
       let selectedWindow = state.windows[state.selectedWindow - 1];
       is(selectedWindow.extData && selectedWindow.extData[uniqKey], uniqVal,
          "selectedWindow is window_B");
 
       // Now minimize window_B. The selected window shouldn't have the secret data
       window_B.minimize();
       waitForFocus(function() {
--- a/browser/components/sessionstore/test/browser_dying_cache.js
+++ b/browser/components/sessionstore/test/browser_dying_cache.js
@@ -19,46 +19,46 @@ add_task(async function test() {
   let tab = BrowserTestUtils.addTab(win.gBrowser, "about:mozilla");
   await promiseBrowserLoaded(tab.linkedBrowser);
   await TabStateFlusher.flush(tab.linkedBrowser);
   await promiseRemoveTabAndSessionState(win.gBrowser.tabs[0]);
 
   // Make sure our window is still tracked by sessionstore
   // and the window state is as expected.
   ok("__SSi" in win, "window is being tracked by sessionstore");
-  ss.setWindowValue(win, "foo", "bar");
+  ss.setCustomWindowValue(win, "foo", "bar");
   checkWindowState(win);
 
   // Close our window.
   await BrowserTestUtils.closeWindow(win);
 
   // SessionStore should no longer track our window
   // but it should still report the same state.
   ok(!("__SSi" in win), "sessionstore does no longer track our window");
   checkWindowState(win);
 
   // Make sure we're not allowed to modify state data.
   Assert.throws(() => ss.setWindowState(win, {}),
     /Window is not tracked/,
     "we're not allowed to modify state data anymore");
-  Assert.throws(() => ss.setWindowValue(win, "foo", "baz"),
+  Assert.throws(() => ss.setCustomWindowValue(win, "foo", "baz"),
     /Window is not tracked/,
     "we're not allowed to modify state data anymore");
 });
 
 function checkWindowState(window) {
   let {windows: [{tabs}]} = JSON.parse(ss.getWindowState(window));
   is(tabs.length, 1, "the window has a single tab");
   is(tabs[0].entries[0].url, "about:mozilla", "the tab is about:mozilla");
 
   is(ss.getClosedTabCount(window), 1, "the window has one closed tab");
   let [{state: {entries: [{url}]}}] = JSON.parse(ss.getClosedTabData(window));
   is(url, "about:robots", "the closed tab is about:robots");
 
-  is(ss.getWindowValue(window, "foo"), "bar", "correct extData value");
+  is(ss.getCustomWindowValue(window, "foo"), "bar", "correct extData value");
 }
 
 function shouldThrow(f) {
   try {
     f();
   } catch (e) {
     return true;
   }
--- a/browser/components/sessionstore/test/browser_global_store.js
+++ b/browser/components/sessionstore/test/browser_global_store.js
@@ -18,28 +18,28 @@ add_task(async function() {
           { entries: [{ url: "about:blank", triggeringPrincipal_base64 }] },
         ],
       },
     ],
     global,
   };
 
   function testRestoredState() {
-    is(ss.getGlobalValue(key1), value1, "restored state has global value");
+    is(ss.getCustomGlobalValue(key1), value1, "restored state has global value");
   }
 
   function testGlobalStore() {
-    is(ss.getGlobalValue(key2), "", "global value initially not set");
+    is(ss.getCustomGlobalValue(key2), "", "global value initially not set");
 
-    ss.setGlobalValue(key2, value1);
-    is(ss.getGlobalValue(key2), value1, "retreived value matches stored");
+    ss.setCustomGlobalValue(key2, value1);
+    is(ss.getCustomGlobalValue(key2), value1, "retreived value matches stored");
 
-    ss.setGlobalValue(key2, value2);
-    is(ss.getGlobalValue(key2), value2, "previously stored value was overwritten");
+    ss.setCustomGlobalValue(key2, value2);
+    is(ss.getCustomGlobalValue(key2), value2, "previously stored value was overwritten");
 
-    ss.deleteGlobalValue(key2);
-    is(ss.getGlobalValue(key2), "", "global value was deleted");
+    ss.deleteCustomGlobalValue(key2);
+    is(ss.getCustomGlobalValue(key2), "", "global value was deleted");
   }
 
   await promiseBrowserState(testState);
   testRestoredState();
   testGlobalStore();
 });
--- a/browser/components/urlbar/UrlbarInput.jsm
+++ b/browser/components/urlbar/UrlbarInput.jsm
@@ -6,17 +6,19 @@
 
 var EXPORTED_SYMBOLS = ["UrlbarInput"];
 
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetters(this, {
   PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
   QueryContext: "resource:///modules/UrlbarController.jsm",
+  Services: "resource://gre/modules/Services.jsm",
   UrlbarController: "resource:///modules/UrlbarController.jsm",
+  UrlbarPrefs: "resource:///modules/UrlbarPrefs.jsm",
   UrlbarView: "resource:///modules/UrlbarView.jsm",
 });
 
 /**
  * Represents the urlbar <textbox>.
  * Also forwards important textbox properties and methods.
  */
 class UrlbarInput {
@@ -53,64 +55,125 @@ class UrlbarInput {
         this.textbox[method](...args);
       };
     }
 
     for (let property of READ_ONLY_PROPERTIES) {
       Object.defineProperty(this, property, {
         enumerable: true,
         get() {
+          let getter = "_get_" + property;
+          if (getter in this) {
+            return this[getter]();
+          }
           return this.textbox[property];
         },
       });
     }
 
     for (let property of READ_WRITE_PROPERTIES) {
       Object.defineProperty(this, property, {
         enumerable: true,
         get() {
+          let getter = "_get_" + property;
+          if (getter in this) {
+            return this[getter]();
+          }
           return this.textbox[property];
         },
         set(val) {
+          let setter = "_set_" + property;
+          if (setter in this) {
+            return this[setter](val);
+          }
           return this.textbox[property] = val;
         },
       });
     }
 
     this.addEventListener("input", this);
+    this.inputField.addEventListener("select", this);
     this.inputField.addEventListener("overflow", this);
     this.inputField.addEventListener("underflow", this);
     this.inputField.addEventListener("scrollend", this);
+
+    this.inputField.controllers.insertControllerAt(0, new CopyCutController(this));
+  }
+
+  /* Shortens the given value, usually by removing http:// and trailing slashes,
+   * such that calling nsIURIFixup::createFixupURI with the result will produce
+   * the same URI.
+   *
+   * @param {string} val
+   *   The string to be trimmed if it appears to be URI
+   */
+  trimValue(val) {
+    return UrlbarPrefs.get("trimURLs") ? this.window.trimURL(val) : val;
   }
 
   formatValue() {
   }
 
   closePopup() {
     this.view.close();
   }
 
   openResults() {
     this.view.open();
   }
 
   /**
+   * Converts an internal URI (e.g. a wyciwyg URI) into one which we can
+   * expose to the user.
+   *
+   * @param {nsIURI} uri
+   *   The URI to be converted
+   * @returns {nsIURI}
+   *   The converted, exposable URI
+   */
+  makeURIReadable(uri) {
+    // Avoid copying 'about:reader?url=', and always provide the original URI:
+    // Reader mode ensures we call createExposableURI itself.
+    let readerStrippedURI = this.window.ReaderMode.getOriginalUrlObjectForDisplay(uri.displaySpec);
+    if (readerStrippedURI) {
+      return readerStrippedURI;
+    }
+
+    try {
+      return Services.uriFixup.createExposableURI(uri);
+    } catch (ex) {}
+
+    return uri;
+  }
+
+  /**
    * Passes DOM events for the textbox to the _on<event type> methods.
    * @param {Event} event
    *   DOM event from the <textbox>.
    */
   handleEvent(event) {
     let methodName = "_on" + event.type;
     if (methodName in this) {
       this[methodName](event);
     } else {
       throw "Unrecognized urlbar event: " + event.type;
     }
   }
 
+  // Getters and Setters below.
+
+  _set_value(val) {
+    val = this.trimValue(val);
+
+    this.valueIsTyped = false;
+    this.inputField.value = val;
+
+    return val;
+  }
+
   // Private methods below.
 
   _updateTextOverflow() {
     if (!this._inOverflow) {
       this.removeAttribute("textoverflow");
       return;
     }
 
@@ -120,28 +183,158 @@ class UrlbarInput {
       if (input && this._inOverflow) {
         let side = input.scrollLeft &&
                    input.scrollLeft == input.scrollLeftMax ? "start" : "end";
         this.setAttribute("textoverflow", side);
       }
     });
   }
 
+  _getSelectedValueForClipboard() {
+    // Grab the actual input field's value, not our value, which could
+    // include "moz-action:".
+    let inputVal = this.inputField.value;
+    let selection = this.editor.selection;
+    const flags = Ci.nsIDocumentEncoder.OutputPreformatted |
+                  Ci.nsIDocumentEncoder.OutputRaw;
+    let selectedVal = selection.toStringWithFormat("text/plain", flags, 0);
+
+    // Handle multiple-range selection as a string for simplicity.
+    if (selection.rangeCount > 1) {
+      return selectedVal;
+    }
+
+    // If the selection doesn't start at the beginning or doesn't span the
+    // full domain or the URL bar is modified or there is no text at all,
+    // nothing else to do here.
+    if (this.selectionStart > 0 || this.valueIsTyped || selectedVal == "") {
+      return selectedVal;
+    }
+
+    // The selection doesn't span the full domain if it doesn't contain a slash and is
+    // followed by some character other than a slash.
+    if (!selectedVal.includes("/")) {
+      let remainder = inputVal.replace(selectedVal, "");
+      if (remainder != "" && remainder[0] != "/") {
+        return selectedVal;
+      }
+    }
+
+    // If the value was filled by a search suggestion, just return it.
+    let action = this._parseActionUrl(this.value);
+    if (action && action.type == "searchengine") {
+      return selectedVal;
+    }
+
+    let uri;
+    if (this.getAttribute("pageproxystate") == "valid") {
+      uri = this.window.gBrowser.currentURI;
+    } else {
+      // We're dealing with an autocompleted value, create a new URI from that.
+      try {
+        uri = Services.uriFixup.createFixupURI(inputVal, Services.uriFixup.FIXUP_FLAG_NONE);
+      } catch (e) {}
+      if (!uri) {
+        return selectedVal;
+      }
+    }
+
+    uri = this.makeURIReadable(uri);
+
+    // If the entire URL is selected, just use the actual loaded URI,
+    // unless we want a decoded URI, or it's a data: or javascript: URI,
+    // since those are hard to read when encoded.
+    if (inputVal == selectedVal &&
+        !uri.schemeIs("javascript") && !uri.schemeIs("data") &&
+        !Services.prefs.getBoolPref("browser.urlbar.decodeURLsOnCopy")) {
+      return uri.displaySpec;
+    }
+
+    // Just the beginning of the URL is selected, or we want a decoded
+    // url. First check for a trimmed value.
+    let spec = uri.displaySpec;
+    let trimmedSpec = this.trimValue(spec);
+    if (spec != trimmedSpec) {
+      // Prepend the portion that trimValue removed from the beginning.
+      // This assumes trimValue will only truncate the URL at
+      // the beginning or end (or both).
+      let trimmedSegments = spec.split(trimmedSpec);
+      selectedVal = trimmedSegments[0] + selectedVal;
+    }
+
+    return selectedVal;
+  }
+
+  /**
+   * @param {string} url
+   * @returns {object}
+   *   The action object
+   */
+  _parseActionUrl(url) {
+    const MOZ_ACTION_REGEX = /^moz-action:([^,]+),(.*)$/;
+    if (!MOZ_ACTION_REGEX.test(url)) {
+      return null;
+    }
+
+    // URL is in the format moz-action:ACTION,PARAMS
+    // Where PARAMS is a JSON encoded object.
+    let [, type, params] = url.match(MOZ_ACTION_REGEX);
+
+    let action = {
+      type,
+    };
+
+    action.params = JSON.parse(params);
+    for (let key in action.params) {
+      action.params[key] = decodeURIComponent(action.params[key]);
+    }
+
+    if ("url" in action.params) {
+      try {
+        let uri = Services.io.newURI(action.params.url);
+        action.params.displayUrl = this.window.losslessDecodeURI(uri);
+      } catch (e) {
+        action.params.displayUrl = action.params.url;
+      }
+    }
+
+    return action;
+  }
+
   // Event handlers below.
 
   _oninput(event) {
+    this.valueIsTyped = true;
+
     // XXX Fill in lastKey & maxResults, and add anything else we need.
     this.controller.handleQuery(new QueryContext({
       searchString: event.target.value,
       lastKey: "",
       maxResults: 12,
       isPrivate: this.isPrivate,
     }));
   }
 
+  _onselect(event) {
+    if (!Services.clipboard.supportsSelectionClipboard()) {
+      return;
+    }
+
+    if (!this.window.windowUtils.isHandlingUserInput) {
+      return;
+    }
+
+    let val = this._getSelectedValueForClipboard();
+    if (!val) {
+      return;
+    }
+
+    Services.clipboard.copyStringToClipboard(val, Services.clipboard.kSelectionClipboard);
+  }
+
   _onoverflow(event) {
     const targetIsPlaceholder =
       !event.originalTarget.classList.contains("anonymous-div");
     // We only care about the non-placeholder text.
     // This shouldn't be needed, see bug 1487036.
     if (targetIsPlaceholder) {
       return;
     }
@@ -160,8 +353,79 @@ class UrlbarInput {
     this._inOverflow = false;
     this._updateTextOverflow();
   }
 
   _onscrollend(event) {
     this._updateTextOverflow();
   }
 }
+
+/**
+ * Handles copy and cut commands for the urlbar.
+ */
+class CopyCutController {
+  /**
+   * @param {UrlbarInput} urlbar
+   *   The UrlbarInput instance to use this controller for.
+   */
+  constructor(urlbar) {
+    this.urlbar = urlbar;
+  }
+
+  /**
+   * @param {string} command
+   *   The name of the command to handle.
+   */
+  doCommand(command) {
+    let urlbar = this.urlbar;
+    let val = urlbar._getSelectedValueForClipboard();
+    if (!val) {
+      return;
+    }
+
+    if (command == "cmd_cut" && this.isCommandEnabled(command)) {
+      let start = urlbar.selectionStart;
+      let end = urlbar.selectionEnd;
+      urlbar.inputField.value = urlbar.inputField.value.substring(0, start) +
+                                urlbar.inputField.value.substring(end);
+      urlbar.selectionStart = urlbar.selectionEnd = start;
+
+      let event = urlbar.window.document.createEvent("UIEvents");
+      event.initUIEvent("input", true, false, this.window, 0);
+      urlbar.dispatchEvent(event);
+
+      urlbar.window.SetPageProxyState("invalid");
+    }
+
+    Cc["@mozilla.org/widget/clipboardhelper;1"]
+      .getService(Ci.nsIClipboardHelper)
+      .copyString(val);
+  }
+
+  /**
+   * @param {string} command
+   * @returns {boolean}
+   *   Whether the command is handled by this controller.
+   */
+  supportsCommand(command) {
+    switch (command) {
+      case "cmd_copy":
+      case "cmd_cut":
+        return true;
+    }
+    return false;
+  }
+
+  /**
+   * @param {string} command
+   * @returns {boolean}
+   *   Whether the command should be enabled.
+   */
+  isCommandEnabled(command) {
+    return this.supportsCommand(command) &&
+           (command != "cmd_cut" || !this.urlbar.readOnly) &&
+           this.urlbar.selectionStart < this.urlbar.selectionEnd;
+  }
+
+  onEvent() {}
+}
+
--- a/browser/components/urlbar/UrlbarPrefs.jsm
+++ b/browser/components/urlbar/UrlbarPrefs.jsm
@@ -90,16 +90,19 @@ const PREF_URLBAR_DEFAULTS = new Map([
   ["suggest.history.onlyTyped", false],
 
   // Results will include switch-to-tab results when this is true.
   ["suggest.openpage", true],
 
   // Results will include search suggestions when this is true.
   ["suggest.searches", false],
 
+  // Remove redundant portions from URLs.
+  ["trimURLs", true],
+
   // Results will include a built-in set of popular domains when this is true.
   ["usepreloadedtopurls.enabled", true],
 
   // After this many days from the profile creation date, the built-in set of
   // popular domains will no longer be included in the results.
   ["usepreloadedtopurls.expire_days", 14],
 
   // When true, URLs in the user's history that look like search result pages
@@ -163,17 +166,17 @@ class Preferences {
     this._updateLinkedPrefs();
   }
 
   /**
    * Returns the value for the preference with the given name.
    *
    * @param {string} pref
    *        The name of the preference to get.
-   * @returns {value} The preference value.
+   * @returns {*} The preference value.
    */
   get(pref) {
     if (!this._map.has(pref))
       this._map.set(pref, this._getPrefValue(pref));
     return this._map.get(pref);
   }
 
   /**
@@ -201,17 +204,17 @@ class Preferences {
     }
   }
 
   /**
    * Returns the raw value of the given preference straight from Services.prefs.
    *
    * @param {string} pref
    *        The name of the preference to get.
-   * @returns {value} The raw preference value.
+   * @returns {*} The raw preference value.
    */
   _readPref(pref) {
     let prefs = Services.prefs.getBranch(PREF_URLBAR_BRANCH);
     let def = PREF_URLBAR_DEFAULTS.get(pref);
     if (def === undefined) {
       prefs = Services.prefs;
       def = PREF_OTHER_DEFAULTS.get(pref);
     }
@@ -235,17 +238,17 @@ class Preferences {
    * different value that is easier to work with than the actual value stored in
    * the preferences branch.  Not all preferences require validation or fixup.
    *
    * The values returned from this method are the values that are made public by
    * this module.
    *
    * @param {string} pref
    *        The name of the preference to get.
-   * @returns {value} The validated and/or fixed-up preference value.
+   * @returns {*} The validated and/or fixed-up preference value.
    */
    _getPrefValue(pref) {
     switch (pref) {
       case "matchBuckets": {
         // Convert from pref char format to an array and add the default
         // buckets.
         let val = this._readPref(pref);
         try {
--- a/browser/components/urlbar/tests/unit/test_UrlbarInput_unit.js
+++ b/browser/components/urlbar/tests/unit/test_UrlbarInput_unit.js
@@ -73,16 +73,17 @@ add_task(function setup() {
 
   fakeController = new UrlbarController();
 
   sandbox.stub(fakeController, "handleQuery");
   sandbox.stub(PrivateBrowsingUtils, "isWindowPrivate").returns(false);
 
   let textbox = createFakeElement();
   textbox.inputField = createFakeElement();
+  textbox.inputField.controllers = { insertControllerAt() {} };
   inputOptions = {
     textbox,
     panel: {
       ownerDocument: {},
       querySelector() {
         return createFakeElement();
       },
     },
--- a/devtools/client/netmonitor/src/assets/styles/NetworkDetailsPanel.css
+++ b/devtools/client/netmonitor/src/assets/styles/NetworkDetailsPanel.css
@@ -239,16 +239,17 @@
 }
 
 .headers-summary .textbox-input {
   margin-inline-end: 2px;
 }
 
 .network-monitor .headers-summary .status-text {
     width: auto!important;
+    margin-left: 4px;
 }
 
 /* Response tabpanel */
 
 .network-monitor .response-error-header {
   margin: 0;
   padding: 3px 8px;
   background-color: var(--theme-highlight-red);
--- a/devtools/client/netmonitor/src/components/HeadersPanel.js
+++ b/devtools/client/netmonitor/src/components/HeadersPanel.js
@@ -207,26 +207,34 @@ class HeadersPanel extends Component {
     const summaryAddress = remoteAddress ?
       this.renderSummary(SUMMARY_ADDRESS,
         getFormattedIPAndPort(remoteAddress, remotePort)) : null;
 
     let summaryStatus;
 
     if (status) {
       const statusCodeDocURL = getHTTPStatusCodeURL(status.toString());
+      const inputWidth = statusText.length + 1;
       const toggleRawHeadersClassList = ["devtools-button", "raw-headers-button"];
       if (this.state.rawHeadersOpened) {
         toggleRawHeadersClassList.push("checked");
       }
       summaryStatus = (
         div({ className: "tabpanel-summary-container headers-summary" },
           div({
             className: "tabpanel-summary-label headers-summary-label",
           }, SUMMARY_STATUS),
           StatusCode({ item }),
+          input({
+            className: "tabpanel-summary-value textbox-input devtools-monospace"
+              + " status-text",
+            readOnly: true,
+            value: `${statusText}`,
+            size: `${inputWidth}`,
+          }),
           statusCodeDocURL ? MDNLink({
             url: statusCodeDocURL,
           }) : span({
             className: "headers-summary learn-more-link",
           }),
           button({
             className: "devtools-button edit-and-resend-button",
             onClick: cloneSelectedRequest,
--- a/devtools/client/netmonitor/src/components/ParamsPanel.js
+++ b/devtools/client/netmonitor/src/components/ParamsPanel.js
@@ -68,32 +68,35 @@ class ParamsPanel extends Component {
   }
 
   /**
    * Mapping array to dict for TreeView usage.
    * Since TreeView only support Object(dict) format.
    * This function also deal with duplicate key case
    * (for multiple selection and query params with same keys)
    *
+   * This function is not sorting result properties since it can
+   * results in unexpected order of params. See bug 1469533
+   *
    * @param {Object[]} arr - key-value pair array like query or form params
    * @returns {Object} Rep compatible object
    */
   getProperties(arr) {
-    return sortObjectKeys(arr.reduce((map, obj) => {
+    return arr.reduce((map, obj) => {
       const value = map[obj.name];
       if (value) {
         if (typeof value !== "object") {
           map[obj.name] = [value];
         }
         map[obj.name].push(obj.value);
       } else {
         map[obj.name] = obj.value;
       }
       return map;
-    }, {}));
+    }, {});
   }
 
   render() {
     const {
       openLink,
       request
     } = this.props;
     const {
--- a/devtools/client/netmonitor/test/browser_net_post-data-01.js
+++ b/devtools/client/netmonitor/test/browser_net_post-data-01.js
@@ -112,30 +112,30 @@ add_task(async function() {
       L10N.getStr(type == "urlencoded" ? "paramsFormData" : "paramsPostPayload"),
       "The post section doesn't have the correct title.");
 
     const labels = tabpanel
       .querySelectorAll("tr:not(.tree-section) .treeLabelCell .treeLabel");
     const values = tabpanel
       .querySelectorAll("tr:not(.tree-section) .treeValueCell .objectBox");
 
-    is(labels[0].textContent, "baz", "The first query param name was incorrect.");
-    is(values[0].textContent, "42", "The first query param value was incorrect.");
-    is(labels[1].textContent, "foo", "The second query param name was incorrect.");
-    is(values[1].textContent, "bar", "The second query param value was incorrect.");
+    is(labels[0].textContent, "foo", "The first query param name was incorrect.");
+    is(values[0].textContent, "bar", "The first query param value was incorrect.");
+    is(labels[1].textContent, "baz", "The second query param name was incorrect.");
+    is(values[1].textContent, "42", "The second query param value was incorrect.");
     is(labels[2].textContent, "type", "The third query param name was incorrect.");
     is(values[2].textContent, type, "The third query param value was incorrect.");
 
     if (type == "urlencoded") {
       checkVisibility("params");
       is(labels.length, 5, "There should be 5 param values displayed in this tabpanel.");
-      is(labels[3].textContent, "baz", "The first post param name was incorrect.");
-      is(values[3].textContent, "123", "The first post param value was incorrect.");
-      is(labels[4].textContent, "foo", "The second post param name was incorrect.");
-      is(values[4].textContent, "bar", "The second post param value was incorrect.");
+      is(labels[3].textContent, "foo", "The first post param name was incorrect.");
+      is(values[3].textContent, "bar", "The first post param value was incorrect.");
+      is(labels[4].textContent, "baz", "The second post param name was incorrect.");
+      is(values[4].textContent, "123", "The second post param value was incorrect.");
     } else {
       checkVisibility("params editor");
 
       is(labels.length, 3, "There should be 3 param values displayed in this tabpanel.");
 
       // Collect code lines and combine into one text for checking
       let text = "";
       const lines = [...document.querySelectorAll(".CodeMirror-line")];
--- a/devtools/client/netmonitor/test/browser_net_post-data-02.js
+++ b/devtools/client/netmonitor/test/browser_net_post-data-02.js
@@ -46,15 +46,15 @@ add_task(async function() {
     L10N.getStr("paramsFormData"),
     "The post section doesn't have the correct title.");
 
   const labels = tabpanel
     .querySelectorAll("tr:not(.tree-section) .treeLabelCell .treeLabel");
   const values = tabpanel
     .querySelectorAll("tr:not(.tree-section) .treeValueCell .objectBox");
 
-  is(labels[0].textContent, "baz", "The first query param name was incorrect.");
-  is(values[0].textContent, "123", "The first query param value was incorrect.");
-  is(labels[1].textContent, "foo", "The second query param name was incorrect.");
-  is(values[1].textContent, "bar", "The second query param value was incorrect.");
+  is(labels[0].textContent, "foo", "The first query param name was incorrect.");
+  is(values[0].textContent, "bar", "The first query param value was incorrect.");
+  is(labels[1].textContent, "baz", "The second query param name was incorrect.");
+  is(values[1].textContent, "123", "The second query param value was incorrect.");
 
   return teardown(monitor);
 });
--- a/devtools/client/netmonitor/test/browser_net_post-data-03.js
+++ b/devtools/client/netmonitor/test/browser_net_post-data-03.js
@@ -69,15 +69,15 @@ add_task(async function() {
     L10N.getStr("paramsFormData"),
     "The form data section doesn't have the correct title.");
 
   labels = tabpanel
     .querySelectorAll("tr:not(.tree-section) .treeLabelCell .treeLabel");
   values = tabpanel
     .querySelectorAll("tr:not(.tree-section) .treeValueCell .objectBox");
 
-  is(labels[0].textContent, "baz", "The first payload param name was incorrect.");
-  is(values[0].textContent, "123", "The first payload param value was incorrect.");
-  is(labels[1].textContent, "foo", "The second payload param name was incorrect.");
-  is(values[1].textContent, "bar", "The second payload param value was incorrect.");
+  is(labels[0].textContent, "foo", "The first payload param name was incorrect.");
+  is(values[0].textContent, "bar", "The first payload param value was incorrect.");
+  is(labels[1].textContent, "baz", "The second payload param name was incorrect.");
+  is(values[1].textContent, "123", "The second payload param value was incorrect.");
 
   return teardown(monitor);
 });
--- a/devtools/client/netmonitor/test/browser_net_status-codes.js
+++ b/devtools/client/netmonitor/test/browser_net_status-codes.js
@@ -171,26 +171,28 @@ add_task(async function() {
 
     await waitUntil(() => document.querySelector(
       "#headers-panel .tabpanel-summary-value.textbox-input"));
 
     const panel = document.querySelector("#headers-panel");
     const summaryValues = panel.querySelectorAll(".tabpanel-summary-value.textbox-input");
     const { method, correctUri, details: { status, statusText } } = data;
     const statusCode = panel.querySelector(".status-code");
+    const statusTextInput = panel.querySelector(".status-text");
     EventUtils.sendMouseEvent({ type: "mouseover" }, statusCode);
     await waitUntil(() => statusCode.title);
 
     is(summaryValues[0].value, correctUri,
       "The url summary value is incorrect.");
     is(summaryValues[1].value, method, "The method summary value is incorrect.");
     is(statusCode.dataset.code, status,
       "The status summary code is incorrect.");
     is(statusCode.getAttribute("title"), status + " " + statusText,
       "The status summary value is incorrect.");
+    is(statusTextInput.value, statusText, "The status text value is incorrect.");
   }
 
   /**
    * A function that tests "Params" panel contains correct information.
    */
   function testParams(data, index) {
     EventUtils.sendMouseEvent({ type: "mousedown" },
       document.querySelectorAll(".request-list-item")[index]);
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -39,17 +39,17 @@
 #include "nsIContentInlines.h"
 #include "nsIDocument.h"
 #include "nsIFrame.h"
 #include "nsIWidget.h"
 #include "nsPresContext.h"
 #include "nsIPresShell.h"
 #include "nsGkAtoms.h"
 #include "nsIFormControl.h"
-#include "nsIComboboxControlFrame.h"
+#include "nsComboboxControlFrame.h"
 #include "nsIScrollableFrame.h"
 #include "nsIDOMXULControlElement.h"
 #include "nsNameSpaceManager.h"
 #include "nsIBaseWindow.h"
 #include "nsFrameSelection.h"
 #include "nsPIDOMWindow.h"
 #include "nsPIWindowRoot.h"
 #include "nsIWebNavigation.h"
@@ -2679,17 +2679,17 @@ EventStateManager::ComputeScrollTargetAn
         canScroll = true;
       }
     } else if (WheelHandlingUtils::CanScrollOn(scrollableFrame,
                                                aDirectionX, aDirectionY)) {
       canScroll = true;
     }
 
     // Comboboxes need special care.
-    nsIComboboxControlFrame* comboBox = do_QueryFrame(scrollFrame);
+    nsComboboxControlFrame* comboBox = do_QueryFrame(scrollFrame);
     if (comboBox) {
       if (comboBox->IsDroppedDown()) {
         // Don't propagate to parent when drop down menu is active.
         return canScroll ? frameToScroll : nullptr;
       }
       // Always propagate when not dropped down (even if focused).
       continue;
     }
--- a/dom/events/moz.build
+++ b/dom/events/moz.build
@@ -154,15 +154,16 @@ LOCAL_INCLUDES += [
     '/docshell/base',
     '/dom/base',
     '/dom/html',
     '/dom/storage',
     '/dom/svg',
     '/dom/xml',
     '/dom/xul',
     '/js/xpconnect/wrappers',
+    '/layout/forms',
     '/layout/generic',
     '/layout/xul',
     '/layout/xul/tree/',
 ]
 
 if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
     CXXFLAGS += ['-Wno-error=shadow']
--- a/dom/html/HTMLOptionsCollection.cpp
+++ b/dom/html/HTMLOptionsCollection.cpp
@@ -13,22 +13,20 @@
 #include "mozilla/MappedDeclarations.h"
 #include "mozilla/dom/HTMLFormSubmission.h"
 #include "mozilla/dom/HTMLOptionElement.h"
 #include "mozilla/dom/HTMLOptionsCollectionBinding.h"
 #include "mozilla/dom/HTMLSelectElement.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsError.h"
 #include "nsGkAtoms.h"
-#include "nsIComboboxControlFrame.h"
 #include "nsIDocument.h"
 #include "nsIFormControlFrame.h"
 #include "nsIForm.h"
 #include "nsIFormProcessor.h"
-#include "nsIListControlFrame.h"
 #include "nsLayoutUtils.h"
 #include "nsMappedAttributes.h"
 #include "nsServiceManagerUtils.h"
 #include "nsStyleConsts.h"
 #include "jsfriendapi.h"
 
 namespace mozilla {
 namespace dom {
--- a/dom/html/HTMLSelectElement.cpp
+++ b/dom/html/HTMLSelectElement.cpp
@@ -17,23 +17,23 @@
 #include "mozilla/dom/HTMLOptionElement.h"
 #include "mozilla/dom/HTMLSelectElementBinding.h"
 #include "mozilla/dom/UnionTypes.h"
 #include "mozilla/MappedDeclarations.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsContentList.h"
 #include "nsError.h"
 #include "nsGkAtoms.h"
-#include "nsIComboboxControlFrame.h"
+#include "nsComboboxControlFrame.h"
 #include "nsIDocument.h"
 #include "nsIFormControlFrame.h"
 #include "nsIForm.h"
 #include "nsIFormProcessor.h"
 #include "nsIFrame.h"
-#include "nsIListControlFrame.h"
+#include "nsListControlFrame.h"
 #include "nsISelectControlFrame.h"
 #include "nsLayoutUtils.h"
 #include "nsMappedAttributes.h"
 #include "mozilla/PresState.h"
 #include "nsServiceManagerUtils.h"
 #include "nsStyleConsts.h"
 #include "nsTextNode.h"
 
@@ -1595,22 +1595,22 @@ HTMLSelectElement::SubmitNamesValues(HTM
 void
 HTMLSelectElement::DispatchContentReset()
 {
   nsIFormControlFrame* formControlFrame = GetFormControlFrame(false);
   if (formControlFrame) {
     // Only dispatch content reset notification if this is a list control
     // frame or combo box control frame.
     if (IsCombobox()) {
-      nsIComboboxControlFrame* comboFrame = do_QueryFrame(formControlFrame);
+      nsComboboxControlFrame* comboFrame = do_QueryFrame(formControlFrame);
       if (comboFrame) {
         comboFrame->OnContentReset();
       }
     } else {
-      nsIListControlFrame* listFrame = do_QueryFrame(formControlFrame);
+      nsListControlFrame* listFrame = do_QueryFrame(formControlFrame);
       if (listFrame) {
         listFrame->OnContentReset();
       }
     }
   }
 }
 
 static void
@@ -1774,41 +1774,41 @@ HTMLSelectElement::UpdateSelectedOptions
     mSelectedOptions->SetDirty();
   }
 }
 
 bool
 HTMLSelectElement::OpenInParentProcess()
 {
   nsIFormControlFrame* formControlFrame = GetFormControlFrame(false);
-  nsIComboboxControlFrame* comboFrame = do_QueryFrame(formControlFrame);
+  nsComboboxControlFrame* comboFrame = do_QueryFrame(formControlFrame);
   if (comboFrame) {
     return comboFrame->IsOpenInParentProcess();
   }
 
   return false;
 }
 
 void
 HTMLSelectElement::SetOpenInParentProcess(bool aVal)
 {
   nsIFormControlFrame* formControlFrame = GetFormControlFrame(false);
-  nsIComboboxControlFrame* comboFrame = do_QueryFrame(formControlFrame);
+  nsComboboxControlFrame* comboFrame = do_QueryFrame(formControlFrame);
   if (comboFrame) {
     comboFrame->SetOpenInParentProcess(aVal);
   }
 }
 
 void
 HTMLSelectElement::SetPreviewValue(const nsAString& aValue)
 {
   mPreviewValue = aValue;
   nsContentUtils::RemoveNewlines(mPreviewValue);
   nsIFormControlFrame* formControlFrame = GetFormControlFrame(false);
-  nsIComboboxControlFrame* comboFrame = do_QueryFrame(formControlFrame);
+  nsComboboxControlFrame* comboFrame = do_QueryFrame(formControlFrame);
   if (comboFrame) {
     comboFrame->RedisplaySelectedText();
   }
 }
 
 JSObject*
 HTMLSelectElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
--- a/dom/svg/nsSVGFilters.cpp
+++ b/dom/svg/nsSVGFilters.cpp
@@ -332,18 +332,20 @@ SVGComponentTransferFunctionElement::Com
       aAttributes.mValues[aChannel].SetLength(3);
       aAttributes.mValues[aChannel][kComponentTransferAmplitudeIndex] = amplitude;
       aAttributes.mValues[aChannel][kComponentTransferExponentIndex] = exponent;
       aAttributes.mValues[aChannel][kComponentTransferOffsetIndex] = offset;
       break;
     }
     case SVG_FECOMPONENTTRANSFER_TYPE_DISCRETE:
     case SVG_FECOMPONENTTRANSFER_TYPE_TABLE: {
-      aAttributes.mValues[aChannel].AppendElements(&tableValues[0],
-                                                                      tableValues.Length());
+      if (!tableValues.IsEmpty()) {
+        aAttributes.mValues[aChannel].AppendElements(&tableValues[0],
+                                                     tableValues.Length());
+      }
       break;
     }
   }
 }
 
 //----------------------------------------------------------------------
 // nsSVGElement methods
 
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -659,30 +659,43 @@ struct WebRenderMemoryReporterHelper {
   WebRenderMemoryReporterHelper(nsIHandleReportCallback* aCallback, nsISupports* aData)
     : mCallback(aCallback), mData(aData)
   {}
   nsCOMPtr<nsIHandleReportCallback> mCallback;
   nsCOMPtr<nsISupports> mData;
 
   void Report(size_t aBytes, const char* aName) const
   {
+    nsPrintfCString path("explicit/gfx/webrender/%s", aName);
+    nsCString desc(NS_LITERAL_CSTRING("CPU heap memory used by WebRender"));
+    ReportInternal(aBytes, path, desc, nsIMemoryReporter::KIND_HEAP);
+  }
+
+  void ReportTexture(size_t aBytes, const char* aName) const
+  {
+    nsPrintfCString path("gfx/webrender/textures/%s", aName);
+    nsCString desc(NS_LITERAL_CSTRING("GPU texture memory used by WebRender"));
+    ReportInternal(aBytes, path, desc, nsIMemoryReporter::KIND_OTHER);
+  }
+
+  void ReportInternal(size_t aBytes, nsACString& aPath, nsACString& aDesc, int32_t aKind) const
+  {
     // Generally, memory reporters pass the empty string as the process name to
     // indicate "current process". However, if we're using a GPU process, the
     // measurements will actually take place in that process, and it's easier to
     // just note that here rather than trying to invoke the memory reporter in
     // the GPU process.
     nsAutoCString processName;
     if (gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
       GPUParent::GetGPUProcessName(processName);
     }
 
-    nsPrintfCString path("explicit/gfx/webrender/%s", aName);
-    mCallback->Callback(processName, path,
-                        nsIMemoryReporter::KIND_HEAP, nsIMemoryReporter::UNITS_BYTES,
-                        aBytes, EmptyCString(), mData);
+    mCallback->Callback(processName, aPath,
+                        aKind, nsIMemoryReporter::UNITS_BYTES,
+                        aBytes, aDesc, mData);
   }
 };
 
 static void
 FinishAsyncMemoryReport()
 {
   nsCOMPtr<nsIMemoryReporterManager> imgr =
     do_GetService("@mozilla.org/memory-reporter-manager;1");
@@ -703,25 +716,33 @@ WebRenderMemoryReporter::CollectReports(
   if (!manager) {
     FinishAsyncMemoryReport();
     return NS_OK;
   }
 
   WebRenderMemoryReporterHelper helper(aHandleReport, aData);
   manager->SendReportMemory(
     [=](wr::MemoryReport aReport) {
+      // CPU Memory.
       helper.Report(aReport.primitive_stores, "primitive-stores");
       helper.Report(aReport.clip_stores, "clip-stores");
       helper.Report(aReport.gpu_cache_metadata, "gpu-cache/metadata");
       helper.Report(aReport.gpu_cache_cpu_mirror, "gpu-cache/cpu-mirror");
       helper.Report(aReport.render_tasks, "render-tasks");
       helper.Report(aReport.hit_testers, "hit-testers");
-      helper.Report(aReport.fonts, "resource-cache/font");
+      helper.Report(aReport.fonts, "resource-cache/fonts");
       helper.Report(aReport.images, "resource-cache/images");
       helper.Report(aReport.rasterized_blobs, "resource-cache/rasterized-blobs");
+
+      // GPU Memory.
+      helper.ReportTexture(aReport.gpu_cache_textures, "gpu-cache");
+      helper.ReportTexture(aReport.vertex_data_textures, "vertex-data");
+      helper.ReportTexture(aReport.render_target_textures, "render-targets");
+      helper.ReportTexture(aReport.texture_cache_textures, "texture-cache");
+
       FinishAsyncMemoryReport();
     },
     [](mozilla::ipc::ResponseRejectReason aReason) {
       FinishAsyncMemoryReport();
     }
   );
 
   return NS_OK;
--- a/gfx/webrender/src/border.rs
+++ b/gfx/webrender/src/border.rs
@@ -209,21 +209,19 @@ impl BorderSideHelpers for BorderSide {
             _ => return self.color,
         };
 
         // The modulate colors below are not part of the specification. They are
         // derived from the Gecko source code and experimentation, and used to
         // modulate the colors in order to generate colors for the inset/outset
         // and groove/ridge border styles.
         //
-        // NOTE(emilio): Gecko at least takes the background color into
-        // account, should we do the same? Looks a bit annoying for this.
-        //
         // NOTE(emilio): If you change this algorithm, do the same change on
-        // get_colors_for_side in cs_border_segment.glsl.
+        // get_colors_for_side in cs_border_segment.glsl, and
+        // NS_GetSpecial3DColors in Gecko.
         if self.color.r != 0.0 || self.color.g != 0.0 || self.color.b != 0.0 {
             let scale = if lighter { 1.0 } else { 2.0 / 3.0 };
             return self.color.scale_rgb(scale)
         }
 
         let black = if lighter { 0.7 } else { 0.3 };
         ColorF::new(black, black, black, self.color.a)
     }
--- a/gfx/webrender_bindings/WebRenderAPI.cpp
+++ b/gfx/webrender_bindings/WebRenderAPI.cpp
@@ -1189,24 +1189,26 @@ DisplayListBuilder::PushIFrame(const wr:
 }
 
 void
 DisplayListBuilder::PushBorder(const wr::LayoutRect& aBounds,
                                const wr::LayoutRect& aClip,
                                bool aIsBackfaceVisible,
                                const wr::LayoutSideOffsets& aWidths,
                                const Range<const wr::BorderSide>& aSides,
-                               const wr::BorderRadius& aRadius)
+                               const wr::BorderRadius& aRadius,
+                               wr::AntialiasBorder aAntialias)
 {
   MOZ_ASSERT(aSides.length() == 4);
   if (aSides.length() != 4) {
     return;
   }
   wr_dp_push_border(mWrState, aBounds, MergeClipLeaf(aClip), aIsBackfaceVisible,
-                    aWidths, aSides[0], aSides[1], aSides[2], aSides[3], aRadius);
+                    aAntialias, aWidths, aSides[0], aSides[1], aSides[2],
+                    aSides[3], aRadius);
 }
 
 void
 DisplayListBuilder::PushBorderImage(const wr::LayoutRect& aBounds,
                                     const wr::LayoutRect& aClip,
                                     bool aIsBackfaceVisible,
                                     const wr::LayoutSideOffsets& aWidths,
                                     wr::ImageKey aImage,
--- a/gfx/webrender_bindings/WebRenderAPI.h
+++ b/gfx/webrender_bindings/WebRenderAPI.h
@@ -436,17 +436,18 @@ public:
 
   // XXX WrBorderSides are passed with Range.
   // It is just to bypass compiler bug. See Bug 1357734.
   void PushBorder(const wr::LayoutRect& aBounds,
                   const wr::LayoutRect& aClip,
                   bool aIsBackfaceVisible,
                   const wr::LayoutSideOffsets& aWidths,
                   const Range<const wr::BorderSide>& aSides,
-                  const wr::BorderRadius& aRadius);
+                  const wr::BorderRadius& aRadius,
+                  wr::AntialiasBorder = wr::AntialiasBorder::Yes);
 
   void PushBorderImage(const wr::LayoutRect& aBounds,
                        const wr::LayoutRect& aClip,
                        bool aIsBackfaceVisible,
                        const wr::LayoutSideOffsets& aWidths,
                        wr::ImageKey aImage,
                        const uint32_t aWidth,
                        const uint32_t aHeight,
--- a/gfx/webrender_bindings/src/bindings.rs
+++ b/gfx/webrender_bindings/src/bindings.rs
@@ -24,16 +24,24 @@ use nsstring::nsAString;
 #[cfg(target_os = "windows")]
 use dwrote::{FontDescriptor, FontWeight, FontStretch, FontStyle};
 
 #[cfg(target_os = "macos")]
 use core_foundation::string::CFString;
 #[cfg(target_os = "macos")]
 use core_graphics::font::CGFont;
 
+/// Whether a border should be antialiased.
+#[repr(C)]
+#[derive(Eq, PartialEq, Copy, Clone)]
+pub enum AntialiasBorder {
+    No = 0,
+    Yes,
+}
+
 #[repr(C)]
 pub enum WrExternalImageBufferType {
     TextureHandle = 0,
     TextureRectHandle = 1,
     TextureArrayHandle = 2,
     TextureExternalHandle = 3,
     ExternalBuffer = 4,
 }
@@ -2186,32 +2194,34 @@ pub extern "C" fn wr_dp_push_line(state:
 
 }
 
 #[no_mangle]
 pub extern "C" fn wr_dp_push_border(state: &mut WrState,
                                     rect: LayoutRect,
                                     clip: LayoutRect,
                                     is_backface_visible: bool,
+                                    do_aa: AntialiasBorder,
                                     widths: LayoutSideOffsets,
                                     top: BorderSide,
                                     right: BorderSide,
                                     bottom: BorderSide,
                                     left: BorderSide,
                                     radius: BorderRadius) {
     debug_assert!(unsafe { is_in_main_thread() });
 
     let border_details = BorderDetails::Normal(NormalBorder {
-                                                   left: left.into(),
-                                                   right: right.into(),
-                                                   top: top.into(),
-                                                   bottom: bottom.into(),
-                                                   radius: radius.into(),
-                                                   do_aa: true,
-                                               });
+        left: left.into(),
+        right: right.into(),
+        top: top.into(),
+        bottom: bottom.into(),
+        radius: radius.into(),
+        do_aa: do_aa == AntialiasBorder::Yes,
+    });
+
     let mut prim_info = LayoutPrimitiveInfo::with_clip_rect(rect, clip.into());
     prim_info.is_backface_visible = is_backface_visible;
     prim_info.tag = state.current_tag;
     state.frame_builder
          .dl_builder
          .push_border(&prim_info,
                       widths,
                       border_details);
--- a/gfx/webrender_bindings/webrender_ffi_generated.h
+++ b/gfx/webrender_bindings/webrender_ffi_generated.h
@@ -16,16 +16,24 @@
 
 namespace mozilla {
 namespace wr {
 
 static const uint32_t MAX_CACHED_PROGRAM_COUNT = 15;
 
 static const uint64_t MAX_LOAD_TIME_MS = 400;
 
+// Whether a border should be antialiased.
+enum class AntialiasBorder {
+  No = 0,
+  Yes,
+
+  Sentinel /* this must be last for serialization purposes. */
+};
+
 enum class BorderStyle : uint32_t {
   None = 0,
   Solid = 1,
   Double = 2,
   Dotted = 3,
   Dashed = 4,
   Hidden = 5,
   Groove = 6,
@@ -1294,16 +1302,17 @@ void wr_dp_pop_stacking_context(WrState 
                                 bool aIsReferenceFrame)
 WR_FUNC;
 
 WR_INLINE
 void wr_dp_push_border(WrState *aState,
                        LayoutRect aRect,
                        LayoutRect aClip,
                        bool aIsBackfaceVisible,
+                       AntialiasBorder aDoAa,
                        LayoutSideOffsets aWidths,
                        BorderSide aTop,
                        BorderSide aRight,
                        BorderSide aBottom,
                        BorderSide aLeft,
                        BorderRadius aRadius)
 WR_FUNC;
 
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -12950,53 +12950,16 @@ IonBuilder::jsop_setarg(uint32_t arg)
 
         MSetFrameArgument* store = MSetFrameArgument::New(alloc(), arg, val);
         modifiesFrameArguments_ = true;
         current->add(store);
         current->setArg(arg);
         return Ok();
     }
 
-    // If this assignment is at the start of the function and is coercing
-    // the original value for the argument which was passed in, loosen
-    // the type information for that original argument if it is currently
-    // empty due to originally executing in the interpreter.
-    if (graph().numBlocks() == 1 &&
-        (val->isBitOr() || val->isBitAnd() || val->isMul() /* for JSOP_POS */))
-     {
-         for (size_t i = 0; i < val->numOperands(); i++) {
-            MDefinition* op = val->getOperand(i);
-            if (op->isParameter() &&
-                op->toParameter()->index() == (int32_t)arg &&
-                op->resultTypeSet() &&
-                op->resultTypeSet()->empty())
-            {
-                bool otherUses = false;
-                for (MUseDefIterator iter(op); iter; iter++) {
-                    MDefinition* def = iter.def();
-                    if (def == val) {
-                        continue;
-                    }
-                    otherUses = true;
-                }
-                if (!otherUses) {
-                    MOZ_ASSERT(op->resultTypeSet() == &argTypes[arg]);
-                    argTypes[arg].addType(TypeSet::UnknownType(), alloc_->lifoAlloc());
-                    if (val->isMul()) {
-                        val->setResultType(MIRType::Double);
-                        val->toMul()->setSpecialization(MIRType::Double);
-                    } else {
-                        MOZ_ASSERT(val->type() == MIRType::Int32);
-                    }
-                    val->setResultTypeSet(nullptr);
-                }
-            }
-        }
-    }
-
     current->setArg(arg);
     return Ok();
 }
 
 AbortReasonOr<Ok>
 IonBuilder::jsop_defvar(uint32_t index)
 {
     MOZ_ASSERT(JSOp(*pc) == JSOP_DEFVAR);
--- a/js/src/vm/TraceLogging.cpp
+++ b/js/src/vm/TraceLogging.cpp
@@ -74,17 +74,17 @@ rdtsc(void)
     uint64_t ret = tv.tv_sec;
     ret *= 1000000;
     ret += tv.tv_usec;
     return ret;
 }
 
 #else
 
-static __inline__ uint64_t
+uint64_t inline
 rdtsc(void)
 {
     return 0;
 }
 
 #endif // defined(MOZ_HAVE_RDTSC)
 
 static bool
--- a/layout/base/nsCSSColorUtils.cpp
+++ b/layout/base/nsCSSColorUtils.cpp
@@ -14,96 +14,37 @@
 // from the xfe which was written originally by Eric Bina. So there.
 
 #define RED_LUMINOSITY        299
 #define GREEN_LUMINOSITY      587
 #define BLUE_LUMINOSITY       114
 #define INTENSITY_FACTOR      25
 #define LUMINOSITY_FACTOR     75
 
-#define MAX_COLOR             255
-#define COLOR_DARK_THRESHOLD  51
-#define COLOR_LIGHT_THRESHOLD 204
-
-#define COLOR_LITE_BS_FACTOR 45
-#define COLOR_LITE_TS_FACTOR 70
-
-#define COLOR_DARK_BS_FACTOR 30
-#define COLOR_DARK_TS_FACTOR 50
-
-#define LIGHT_GRAY NS_RGB(192, 192, 192)
-#define DARK_GRAY  NS_RGB(96, 96, 96)
-
-#define MAX_BRIGHTNESS  254
-#define MAX_DARKNESS     0
-
-void NS_GetSpecial3DColors(nscolor aResult[2],
-                           nscolor aBackgroundColor,
-                           nscolor aBorderColor)
+void NS_GetSpecial3DColors(nscolor aResult[2], nscolor aBorderColor)
 {
-
-  uint8_t f0, f1;
-  uint8_t r, g, b;
-
-  uint8_t rb = NS_GET_R(aBorderColor);
-  uint8_t gb = NS_GET_G(aBorderColor);
-  uint8_t bb = NS_GET_B(aBorderColor);
-
-  uint8_t a = NS_GET_A(aBorderColor);
+  const float kDarkerScale = 2.0 / 3.0;
 
-  // This needs to be optimized.
-  // Calculating background brightness again and again is
-  // a waste of time!!!. Just calculate it only once.
-  // .....somehow!!!
-
-  uint8_t red = NS_GET_R(aBackgroundColor);
-  uint8_t green = NS_GET_G(aBackgroundColor);
-  uint8_t blue = NS_GET_B(aBackgroundColor);
-
-  uint8_t elementBrightness = NS_GetBrightness(rb,gb,bb);
-  uint8_t backgroundBrightness = NS_GetBrightness(red, green, blue);
-
-
-  if (backgroundBrightness < COLOR_DARK_THRESHOLD) {
-    f0 = COLOR_DARK_BS_FACTOR;
-    f1 = COLOR_DARK_TS_FACTOR;
-	if(elementBrightness == MAX_DARKNESS)
-	{
-       rb = NS_GET_R(DARK_GRAY);
-       gb = NS_GET_G(DARK_GRAY);
-       bb = NS_GET_B(DARK_GRAY);
-	}
-  }else if (backgroundBrightness > COLOR_LIGHT_THRESHOLD) {
-    f0 = COLOR_LITE_BS_FACTOR;
-    f1 = COLOR_LITE_TS_FACTOR;
-	if(elementBrightness == MAX_BRIGHTNESS)
-	{
-       rb = NS_GET_R(LIGHT_GRAY);
-       gb = NS_GET_G(LIGHT_GRAY);
-       bb = NS_GET_B(LIGHT_GRAY);
-	}
-  }else {
-    f0 = COLOR_DARK_BS_FACTOR +
-      (backgroundBrightness *
-       (COLOR_LITE_BS_FACTOR - COLOR_DARK_BS_FACTOR) / MAX_COLOR);
-    f1 = COLOR_DARK_TS_FACTOR +
-      (backgroundBrightness *
-       (COLOR_LITE_TS_FACTOR - COLOR_DARK_TS_FACTOR) / MAX_COLOR);
+  uint8_t r = NS_GET_R(aBorderColor);
+  uint8_t g = NS_GET_G(aBorderColor);
+  uint8_t b = NS_GET_B(aBorderColor);
+  uint8_t a = NS_GET_A(aBorderColor);
+  if (r == 0 && g == 0 && b == 0) {
+    // 0.3 * black
+    aResult[0] = NS_RGBA(76, 76, 76, a);
+    // 0.7 * black
+    aResult[1] = NS_RGBA(178, 178, 178, a);
+    return;
   }
 
-
-  r = rb - (f0 * rb / 100);
-  g = gb - (f0 * gb / 100);
-  b = bb - (f0 * bb / 100);
-  aResult[0] = NS_RGBA(r, g, b, a);
-
-  r = rb + (f1 * (MAX_COLOR - rb) / 100);
-  g = gb + (f1 * (MAX_COLOR - gb) / 100);
-  b = bb + (f1 * (MAX_COLOR - bb) / 100);
-  aResult[1] = NS_RGBA(r, g, b, a);
+  aResult[0] = NS_RGBA(uint8_t(r * kDarkerScale),
+                       uint8_t(g * kDarkerScale),
+                       uint8_t(b * kDarkerScale),
+                       a);
+  aResult[1] = aBorderColor;
 }
 
 int NS_GetBrightness(uint8_t aRed, uint8_t aGreen, uint8_t aBlue)
 {
 
   uint8_t intensity = (aRed + aGreen + aBlue) / 3;
 
   uint8_t luminosity = NS_GetLuminosity(NS_RGB(aRed, aGreen, aBlue)) / 1000;
@@ -237,24 +178,8 @@ void NS_HSV2RGB(nscolor &aColor, uint16_
   aColor = NS_RGBA(r, g, b, aAlpha);
 }
 
 #undef RED_LUMINOSITY
 #undef GREEN_LUMINOSITY
 #undef BLUE_LUMINOSITY
 #undef INTENSITY_FACTOR
 #undef LUMINOSITY_FACTOR
-
-#undef MAX_COLOR
-#undef COLOR_DARK_THRESHOLD
-#undef COLOR_LIGHT_THRESHOLD
-
-#undef COLOR_LITE_BS_FACTOR
-#undef COLOR_LITE_TS_FACTOR
-
-#undef COLOR_DARK_BS_FACTOR
-#undef COLOR_DARK_TS_FACTOR
-
-#undef LIGHT_GRAY
-#undef DARK_GRAY
-
-#undef MAX_BRIGHTNESS
-#undef MAX_DARKNESS
--- a/layout/base/nsCSSColorUtils.h
+++ b/layout/base/nsCSSColorUtils.h
@@ -14,20 +14,18 @@
 // "Sufficient contrast" is determined by
 // "Techniques For Accessibility Evalution And Repair Tools".
 // See http://www.w3.org/TR/AERT#color-contrast
 #define NS_SUFFICIENT_LUMINOSITY_DIFFERENCE 125000
 #define NS_LUMINOSITY_DIFFERENCE(a, b) \
           int32_t(mozilla::Abs( \
             NS_GetLuminosity(a | 0xff000000) - NS_GetLuminosity(b | 0xff000000)))
 
-// To determine colors based on the background brightness and border color
-void NS_GetSpecial3DColors(nscolor aResult[2],
-                           nscolor aBackgroundColor,
-                           nscolor aBorderColor);
+// To determine 3D colors for groove / ridge borders based on the border color
+void NS_GetSpecial3DColors(nscolor aResult[2], nscolor aBorderColor);
 
 // Determins brightness for a specific color
 int NS_GetBrightness(uint8_t aRed, uint8_t aGreen, uint8_t aBlue);
 
 // Get Luminosity of a specific color. That is same as Y of YIQ color space.
 // The range of return value is 0 to 255000.
 int32_t NS_GetLuminosity(nscolor aColor);
 
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -45,19 +45,18 @@
 #include "nsViewManager.h"
 #include "nsStyleConsts.h"
 #ifdef MOZ_XUL
 #include "nsXULElement.h"
 #include "mozilla/dom/BoxObject.h"
 #endif // MOZ_XUL
 #include "nsContainerFrame.h"
 #include "nsNameSpaceManager.h"
-#include "nsIComboboxControlFrame.h"
 #include "nsComboboxControlFrame.h"
-#include "nsIListControlFrame.h"
+#include "nsListControlFrame.h"
 #include "nsPlaceholderFrame.h"
 #include "nsTableRowGroupFrame.h"
 #include "nsIFormControl.h"
 #include "nsCSSAnonBoxes.h"
 #include "nsTextFragment.h"
 #include "nsIAnonymousContentCreator.h"
 #include "nsBindingManager.h"
 #include "nsXBLBinding.h"
@@ -3048,17 +3047,17 @@ nsCSSFrameConstructor::ConstructSelectFr
     listStyle = mPresShell->StyleSet()->
       ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::dropDownList(),
                                          computedStyle);
 
     // Create a listbox
     nsContainerFrame* listFrame = NS_NewListControlFrame(mPresShell, listStyle);
 
     // Notify the listbox that it is being used as a dropdown list.
-    nsIListControlFrame * listControlFrame = do_QueryFrame(listFrame);
+    nsListControlFrame * listControlFrame = do_QueryFrame(listFrame);
     if (listControlFrame) {
       listControlFrame->SetComboboxFrame(comboboxFrame);
     }
     // Notify combobox that it should use the listbox as it's popup
     comboboxFrame->SetDropDown(listFrame);
 
     if (!nsLayoutUtils::IsContentSelectEnabled()) {
       // TODO(kuoe0) Remove this assertion when content-select is shipped.
--- a/layout/forms/moz.build
+++ b/layout/forms/moz.build
@@ -6,19 +6,17 @@
 
 with Files('**'):
     BUG_COMPONENT = ('Core', 'Layout: Form Controls')
 
 MOCHITEST_MANIFESTS += ['test/mochitest.ini']
 MOCHITEST_CHROME_MANIFESTS += ['test/chrome.ini']
 
 EXPORTS += [
-    'nsIComboboxControlFrame.h',
     'nsIFormControlFrame.h',
-    'nsIListControlFrame.h',
     'nsISelectControlFrame.h',
     'nsITextControlFrame.h',
 ]
 
 UNIFIED_SOURCES += [
     'nsButtonFrameRenderer.cpp',
     'nsCheckboxRadioFrame.cpp',
     'nsColorControlFrame.cpp',
--- a/layout/forms/nsComboboxControlFrame.cpp
+++ b/layout/forms/nsComboboxControlFrame.cpp
@@ -13,31 +13,30 @@
 #include "nsCOMPtr.h"
 #include "nsFocusManager.h"
 #include "nsCheckboxRadioFrame.h"
 #include "nsGkAtoms.h"
 #include "nsCSSAnonBoxes.h"
 #include "nsHTMLParts.h"
 #include "nsIFormControl.h"
 #include "nsNameSpaceManager.h"
-#include "nsIListControlFrame.h"
+#include "nsListControlFrame.h"
 #include "nsPIDOMWindow.h"
 #include "nsIPresShell.h"
 #include "mozilla/PresState.h"
 #include "nsView.h"
 #include "nsViewManager.h"
 #include "nsIContentInlines.h"
 #include "nsIDOMEventListener.h"
 #include "nsISelectControlFrame.h"
 #include "nsContentUtils.h"
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/HTMLSelectElement.h"
 #include "nsIDocument.h"
 #include "nsIScrollableFrame.h"
-#include "nsListControlFrame.h"
 #include "mozilla/ServoStyleSet.h"
 #include "nsNodeInfoManager.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsLayoutUtils.h"
 #include "nsDisplayList.h"
 #include "nsITheme.h"
 #include "nsStyleConsts.h"
 #include "mozilla/Likely.h"
@@ -247,17 +246,16 @@ nsComboboxControlFrame::~nsComboboxContr
 {
   REFLOW_COUNTER_DUMP("nsCCF");
 }
 
 //--------------------------------------------------------------
 
 NS_QUERYFRAME_HEAD(nsComboboxControlFrame)
   NS_QUERYFRAME_ENTRY(nsComboboxControlFrame)
-  NS_QUERYFRAME_ENTRY(nsIComboboxControlFrame)
   NS_QUERYFRAME_ENTRY(nsIFormControlFrame)
   NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator)
   NS_QUERYFRAME_ENTRY(nsISelectControlFrame)
   NS_QUERYFRAME_ENTRY(nsIStatefulFrame)
 NS_QUERYFRAME_TAIL_INHERITING(nsBlockFrame)
 
 #ifdef ACCESSIBILITY
 a11y::AccType
@@ -931,19 +929,16 @@ nsComboboxControlFrame::Reflow(nsPresCon
 nsresult
 nsComboboxControlFrame::GetFrameName(nsAString& aResult) const
 {
   return MakeFrameName(NS_LITERAL_STRING("ComboboxControl"), aResult);
 }
 #endif
 
 
-//----------------------------------------------------------------------
-// nsIComboboxControlFrame
-//----------------------------------------------------------------------
 void
 nsComboboxControlFrame::ShowDropDown(bool aDoDropDown)
 {
   if (!nsLayoutUtils::IsContentSelectEnabled()) {
     // TODO(kuoe0) remove this assertion after content-select is enabled
     MOZ_ASSERT(!XRE_IsContentProcess());
   }
   mDelayedShowDropDown = false;
@@ -986,17 +981,17 @@ nsIFrame*
 nsComboboxControlFrame::GetDropDown()
 {
   return mDropdownFrame;
 }
 
 ///////////////////////////////////////////////////////////////
 
 
-NS_IMETHODIMP
+nsresult
 nsComboboxControlFrame::RedisplaySelectedText()
 {
   nsAutoScriptBlocker scriptBlocker;
   mDisplayedIndex = mListControlFrame->GetSelectedIndex();
   return RedisplayText();
 }
 
 
--- a/layout/forms/nsComboboxControlFrame.h
+++ b/layout/forms/nsComboboxControlFrame.h
@@ -20,38 +20,36 @@
 #endif
 
 //Mark used to indicate when onchange has been fired for current combobox item
 #define NS_SKIP_NOTIFY_INDEX -2
 
 #include "mozilla/Attributes.h"
 #include "nsBlockFrame.h"
 #include "nsIFormControlFrame.h"
-#include "nsIComboboxControlFrame.h"
 #include "nsIAnonymousContentCreator.h"
 #include "nsISelectControlFrame.h"
 #include "nsIRollupListener.h"
 #include "nsIStatefulFrame.h"
 #include "nsThreadUtils.h"
 
-class nsIListControlFrame;
+class nsListControlFrame;
 class nsComboboxDisplayFrame;
 class nsIDOMEventListener;
 class nsIScrollableFrame;
 class nsTextNode;
 
 namespace mozilla {
 namespace gfx {
 class DrawTarget;
 } // namespace gfx
 } // namespace mozilla
 
 class nsComboboxControlFrame final : public nsBlockFrame,
                                      public nsIFormControlFrame,
-                                     public nsIComboboxControlFrame,
                                      public nsIAnonymousContentCreator,
                                      public nsISelectControlFrame,
                                      public nsIRollupListener,
                                      public nsIStatefulFrame
 {
   typedef mozilla::gfx::DrawTarget DrawTarget;
 
 public:
@@ -127,58 +125,59 @@ public:
    * If it lost focus, the dropdown menu will be rolled up if needed,
    * and FireOnChange() will be called.
    * @param aOn true if got focus, false if lost focus.
    * @param aRepaint if true then force repaint (NOTE: we always force repaint currently)
    * @note This method might destroy |this|.
    */
   virtual void SetFocus(bool aOn, bool aRepaint) override;
 
-  //nsIComboboxControlFrame
-  virtual bool IsDroppedDown() override { return mDroppedDown; }
+  bool IsDroppedDown() { return mDroppedDown; }
   /**
    * @note This method might destroy |this|.
    */
-  virtual void ShowDropDown(bool aDoDropDown) override;
-  virtual nsIFrame* GetDropDown() override;
-  virtual void SetDropDown(nsIFrame* aDropDownFrame) override;
+  void ShowDropDown(bool aDoDropDown);
+  nsIFrame* GetDropDown();
+  void SetDropDown(nsIFrame* aDropDownFrame);
   /**
    * @note This method might destroy |this|.
    */
-  virtual void RollupFromList() override;
+  void RollupFromList();
 
   /**
    * Return the available space before and after this frame for
    * placing the drop-down list, and the current 2D translation.
    * Note that either or both can be less than or equal to zero,
    * if both are then the drop-down should be closed.
    */
   void GetAvailableDropdownSpace(mozilla::WritingMode aWM,
                                  nscoord* aBefore,
                                  nscoord* aAfter,
                                  mozilla::LogicalPoint* aTranslation);
-  virtual int32_t GetIndexOfDisplayArea() override;
+  int32_t GetIndexOfDisplayArea();
   /**
    * @note This method might destroy |this|.
    */
-  NS_IMETHOD RedisplaySelectedText() override;
-  virtual int32_t UpdateRecentIndex(int32_t aIndex) override;
-  virtual void OnContentReset() override;
+  nsresult RedisplaySelectedText();
+  int32_t UpdateRecentIndex(int32_t aIndex);
+  void OnContentReset();
 
 
-  bool IsOpenInParentProcess() override
+  bool IsOpenInParentProcess()
   {
     return mIsOpenInParentProcess;
   }
 
-  void SetOpenInParentProcess(bool aVal) override
+  void SetOpenInParentProcess(bool aVal)
   {
     mIsOpenInParentProcess = aVal;
   }
 
+  bool IsDroppedDownOrHasParentPopup() { return IsDroppedDown() || IsOpenInParentProcess(); }
+
   // nsISelectControlFrame
   NS_IMETHOD AddOption(int32_t index) override;
   NS_IMETHOD RemoveOption(int32_t index) override;
   NS_IMETHOD DoneAddingChildren(bool aIsDone) override;
   NS_IMETHOD OnOptionSelected(int32_t aIndex, bool aSelected) override;
   NS_IMETHOD OnSetSelectedIndex(int32_t aOldIndex, int32_t aNewIndex) override;
 
   //nsIRollupListener
@@ -286,17 +285,17 @@ private:
 
 protected:
   nsFrameList              mPopupFrames;             // additional named child list
   RefPtr<nsTextNode>       mDisplayContent;          // Anonymous content used to display the current selection
   RefPtr<Element>     mButtonContent;                // Anonymous content for the button
   nsContainerFrame*        mDisplayFrame;            // frame to display selection
   nsIFrame*                mButtonFrame;             // button frame
   nsIFrame*                mDropdownFrame;           // dropdown list frame
-  nsIListControlFrame *    mListControlFrame;        // ListControl Interface for the dropdown frame
+  nsListControlFrame*      mListControlFrame;        // ListControl for the dropdown frame
 
   // The inline size of our display area.  Used by that frame's reflow
   // to size to the full inline size except the drop-marker.
   nscoord mDisplayISize;
 
   nsRevocableEventPtr<RedisplayTextEvent> mRedisplayTextEvent;
 
   int32_t               mRecentSelectedIndex;
deleted file mode 100644
--- a/layout/forms/nsIComboboxControlFrame.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/* -*- 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 nsIComboboxControlFrame_h___
-#define nsIComboboxControlFrame_h___
-
-#include "nsQueryFrame.h"
-
-/**
-  * nsIComboboxControlFrame is the interface for comboboxes.
-  */
-class nsIComboboxControlFrame : public nsQueryFrame
-{
-public:
-  NS_DECL_QUERYFRAME_TARGET(nsIComboboxControlFrame)
-
-  /**
-   * Indicates whether the list is dropped down
-   */
-  virtual bool IsDroppedDown() = 0;
-
-  virtual bool IsOpenInParentProcess() = 0;
-  virtual void SetOpenInParentProcess(bool aVal) = 0;
-
-  bool IsDroppedDownOrHasParentPopup() { return IsDroppedDown() || IsOpenInParentProcess(); }
-
-  /**
-   * Shows or hides the drop down
-   */
-  virtual void ShowDropDown(bool aDoDropDown) = 0;
-
-  /**
-   * Gets the Drop Down List
-   */
-  virtual nsIFrame* GetDropDown() = 0;
-
-  /**
-   * Sets the Drop Down List
-   */
-  virtual void SetDropDown(nsIFrame* aDropDownFrame) = 0;
-
-  /**
-   * Tells the combobox to roll up
-   */
-  virtual void RollupFromList() = 0;
-
-  /**
-   * Redisplay the selected text (will do nothing if text has not changed).
-   * This method might destroy this frame or any others that happen to be
-   * around.  It might even run script.
-   */
-  NS_IMETHOD RedisplaySelectedText() = 0;
-
-  /**
-   * Method for the listbox to set and get the recent index
-   */
-  virtual int32_t UpdateRecentIndex(int32_t aIndex) = 0;
-
-  /**
-   * Notification that the content has been reset
-   */
-  virtual void OnContentReset() = 0;
-
-  /**
-   * This returns the index of the item that is currently being displayed
-   * in the display area. It may differ from what the currently Selected index
-   * is in in the dropdown.
-   *
-   * Detailed explanation:
-   * When the dropdown is dropped down via a mouse click and the user moves the mouse
-   * up and down without clicking, the currently selected item is being tracking inside
-   * the dropdown, but the combobox is not being updated. When the user selects items
-   * with the arrow keys, the combobox is being updated. So when the user clicks outside
-   * the dropdown and it needs to roll up it has to decide whether to keep the current
-   * selection or not. This method is used to get the current index in the combobox to
-   * compare it to the current index in the dropdown to see if the combox has been updated
-   * and that way it knows whether to "cancel" the current selection residing in the
-   * dropdown. Or whether to leave the selection alone.
-   */
-  virtual int32_t GetIndexOfDisplayArea() = 0;
-};
-
-#endif
-
deleted file mode 100644
--- a/layout/forms/nsIListControlFrame.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/* -*- 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 nsIListControlFrame_h___
-#define nsIListControlFrame_h___
-
-#include "nsQueryFrame.h"
-#include "nsStringFwd.h"
-
-namespace mozilla {
-namespace dom {
-class HTMLOptionElement;
-} // namespace dom
-} // namespace mozilla
-
-/**
-  * nsIListControlFrame is the interface for frame-based listboxes.
-  */
-class nsIListControlFrame : public nsQueryFrame
-{
-public:
-  NS_DECL_QUERYFRAME_TARGET(nsIListControlFrame)
-
-  /**
-   * Sets the ComboBoxFrame
-   *
-   */
-  virtual void SetComboboxFrame(nsIFrame* aComboboxFrame) = 0;
-
-  /**
-   * Get the display string for an item
-   */
-  virtual void GetOptionText(uint32_t aIndex, nsAString& aStr) = 0;
-
-  /**
-   * Get the Selected Item's index
-   *
-   */
-  virtual int32_t GetSelectedIndex() = 0;
-
-  /**
-   * Return current option. The current option is the option displaying
-   * the focus ring when the listbox is focused.
-   */
-  virtual mozilla::dom::HTMLOptionElement* GetCurrentOption() = 0;
-
-  /**
-   * Initiates mouse capture for the listbox
-   *
-   */
-  virtual void CaptureMouseEvents(bool aGrabMouseEvents) = 0;
-
-  /**
-   * Returns the block size of a single row in the list.  This is the
-   * maximum of the block sizes of all the options/optgroups.
-   */
-  virtual nscoord GetBSizeOfARow() = 0;
-
-  /**
-   * Returns the number of options in the listbox
-   */
-
-  virtual uint32_t GetNumberOfOptions() = 0;
-
-  /**
-   * Called by combobox when it's about to drop down
-   */
-  virtual void AboutToDropDown() = 0;
-
-  /**
-   * Called by combobox when it's about to roll up
-   */
-  virtual void AboutToRollup() = 0;
-
-  /**
-   * Fire on input and on change (used by combobox)
-   */
-  virtual void FireOnInputAndOnChange() = 0;
-
-  /**
-   * Tell the selected list to roll up and ensure that the proper index is
-   * selected, possibly firing onChange if the index has changed
-   *
-   * @param aIndex the index to actually select
-   */
-  virtual void ComboboxFinish(int32_t aIndex) = 0;
-
-  /**
-   * Notification that the content has been reset
-   */
-  virtual void OnContentReset() = 0;
-};
-
-#endif
-
--- a/layout/forms/nsListControlFrame.cpp
+++ b/layout/forms/nsListControlFrame.cpp
@@ -262,18 +262,18 @@ nsListControlFrame::InvalidateFocus()
   nsIFrame* containerFrame = GetOptionsContainer();
   if (containerFrame) {
     containerFrame->InvalidateFrame();
   }
 }
 
 NS_QUERYFRAME_HEAD(nsListControlFrame)
   NS_QUERYFRAME_ENTRY(nsIFormControlFrame)
-  NS_QUERYFRAME_ENTRY(nsIListControlFrame)
   NS_QUERYFRAME_ENTRY(nsISelectControlFrame)
+  NS_QUERYFRAME_ENTRY(nsListControlFrame)
 NS_QUERYFRAME_TAIL_INHERITING(nsHTMLScrollFrame)
 
 #ifdef ACCESSIBILITY
 a11y::AccType
 nsListControlFrame::AccessibleType()
 {
   return a11y::eHTMLSelectListType;
 }
--- a/layout/forms/nsListControlFrame.h
+++ b/layout/forms/nsListControlFrame.h
@@ -15,26 +15,25 @@
 //#define DO_REFLOW_COUNTER
 //#define DO_UNCONSTRAINED_CHECK
 //#define DO_PIXELS
 #endif
 
 #include "mozilla/Attributes.h"
 #include "nsGfxScrollFrame.h"
 #include "nsIFormControlFrame.h"
-#include "nsIListControlFrame.h"
 #include "nsISelectControlFrame.h"
 #include "nsSelectsAreaFrame.h"
 
 // X.h defines KeyPress
 #ifdef KeyPress
 #undef KeyPress
 #endif
 
-class nsIComboboxControlFrame;
+class nsComboboxControlFrame;
 class nsPresContext;
 class nsListEventListener;
 
 namespace mozilla {
 namespace dom {
 class Event;
 class HTMLOptionElement;
 class HTMLOptionsCollection;
@@ -42,17 +41,16 @@ class HTMLOptionsCollection;
 } // namespace mozilla
 
 /**
  * Frame-based listbox.
  */
 
 class nsListControlFrame final : public nsHTMLScrollFrame,
                                  public nsIFormControlFrame,
-                                 public nsIListControlFrame,
                                  public nsISelectControlFrame
 {
 public:
   typedef mozilla::dom::HTMLOptionElement HTMLOptionElement;
 
   friend nsContainerFrame* NS_NewListControlFrame(nsIPresShell* aPresShell,
                                                   ComputedStyle* aStyle);
 
@@ -105,50 +103,49 @@ public:
   virtual mozilla::ScrollStyles GetScrollStyles() const override;
   virtual bool ShouldPropagateComputedBSizeToScrolledContent() const override;
 
     // for accessibility purposes
 #ifdef ACCESSIBILITY
   virtual mozilla::a11y::AccType AccessibleType() override;
 #endif
 
-    // nsIListControlFrame
-  virtual void SetComboboxFrame(nsIFrame* aComboboxFrame) override;
-  virtual int32_t GetSelectedIndex() override;
-  virtual HTMLOptionElement* GetCurrentOption() override;
+  void SetComboboxFrame(nsIFrame* aComboboxFrame);
+  int32_t GetSelectedIndex();
+  HTMLOptionElement* GetCurrentOption();
 
   /**
    * Gets the text of the currently selected item.
    * If the there are zero items then an empty string is returned
    * If there is nothing selected, then the 0th item's text is returned.
    */
-  virtual void GetOptionText(uint32_t aIndex, nsAString& aStr) override;
+  void GetOptionText(uint32_t aIndex, nsAString& aStr);
 
-  virtual void CaptureMouseEvents(bool aGrabMouseEvents) override;
-  virtual nscoord GetBSizeOfARow() override;
-  virtual uint32_t GetNumberOfOptions() override;
-  virtual void AboutToDropDown() override;
+  void CaptureMouseEvents(bool aGrabMouseEvents);
+  nscoord GetBSizeOfARow();
+  uint32_t GetNumberOfOptions();
+  void AboutToDropDown();
 
   /**
    * @note This method might destroy the frame, pres shell and other objects.
    */
-  virtual void AboutToRollup() override;
+  void AboutToRollup();
 
   /**
    * Dispatch a DOM oninput and onchange event synchroniously.
    * @note This method might destroy the frame, pres shell and other objects.
    */
-  virtual void FireOnInputAndOnChange() override;
+  void FireOnInputAndOnChange();
 
   /**
    * Makes aIndex the selected option of a combobox list.
    * @note This method might destroy the frame, pres shell and other objects.
    */
-  virtual void ComboboxFinish(int32_t aIndex) override;
-  virtual void OnContentReset() override;
+  void ComboboxFinish(int32_t aIndex);
+  void OnContentReset();
 
   // nsISelectControlFrame
   NS_IMETHOD AddOption(int32_t index) override;
   NS_IMETHOD RemoveOption(int32_t index) override;
   NS_IMETHOD DoneAddingChildren(bool aIsDone) override;
 
   /**
    * Gets the content (an option) by index and then set it as
@@ -390,17 +387,17 @@ protected:
 
   nsView* GetViewInternal() const override { return mView; }
   void SetViewInternal(nsView* aView) override { mView = aView; }
 
   // Data Members
   int32_t      mStartSelectionIndex;
   int32_t      mEndSelectionIndex;
 
-  nsIComboboxControlFrame* mComboboxFrame;
+  nsComboboxControlFrame* mComboboxFrame;
 
   // The view is only created (& non-null) if IsInDropDownMode() is true.
   nsView* mView;
 
   uint32_t mNumDisplayRows;
   bool mChangesSinceDragStart:1;
   bool mButtonDown:1;
 
--- a/layout/painting/nsCSSRendering.cpp
+++ b/layout/painting/nsCSSRendering.cpp
@@ -428,23 +428,16 @@ protected:
       }
       MOZ_ASSERT_UNREACHABLE("None of the frames is a descendant of this rtc?");
     }
     MOZ_ASSERT_UNREACHABLE("Do we have any other type of line container?");
     return false;
   }
 };
 
-/* Local functions */
-static nscolor
-MakeBevelColor(mozilla::Side whichSide,
-               uint8_t style,
-               nscolor aBackgroundColor,
-               nscolor aBorderColor);
-
 static InlineBackgroundData* gInlineBGData = nullptr;
 
 // Initialize any static variables used by nsCSSRendering.
 void
 nsCSSRendering::Init()
 {
   NS_ASSERTION(!gInlineBGData, "Init called twice");
   gInlineBGData = new InlineBackgroundData();
@@ -459,26 +452,25 @@ nsCSSRendering::Shutdown()
 }
 
 /**
  * Make a bevel color
  */
 static nscolor
 MakeBevelColor(mozilla::Side whichSide,
                uint8_t style,
-               nscolor aBackgroundColor,
                nscolor aBorderColor)
 {
 
   nscolor colors[2];
   nscolor theColor;
 
   // Given a background color and a border color
   // calculate the color used for the shading
-  NS_GetSpecial3DColors(colors, aBackgroundColor, aBorderColor);
+  NS_GetSpecial3DColors(colors, aBorderColor);
 
   if ((style == NS_STYLE_BORDER_STYLE_OUTSET) ||
       (style == NS_STYLE_BORDER_STYLE_RIDGE)) {
     // Flip colors for these two border styles
     switch (whichSide) {
       case eSideBottom:
         whichSide = eSideTop;
         break;
@@ -850,25 +842,16 @@ ConstructBorderRenderer(nsPresContext* a
                         const nsRect& aDirtyRect,
                         const nsRect& aBorderArea,
                         const nsStyleBorder& aStyleBorder,
                         Sides aSkipSides,
                         bool* aNeedsClip)
 {
   nsMargin border = aStyleBorder.GetComputedBorder();
 
-  // In NavQuirks mode we want to use the parent's context as a starting point
-  // for determining the background color.
-  bool quirks = aPresContext->CompatibilityMode() == eCompatibility_NavQuirks;
-  nsIFrame* bgFrame =
-    nsCSSRendering::FindNonTransparentBackgroundFrame(aForFrame, quirks);
-  ComputedStyle* bgContext = bgFrame->Style();
-  nscolor bgColor =
-    bgContext->GetVisitedDependentColor(&nsStyleBackground::mBackgroundColor);
-
   // Compute the outermost boundary of the area that might be painted.
   // Same coordinate space as aBorderArea & aBGClipRect.
   nsRect joinedBorderArea = nsCSSRendering::BoxDecorationRectForBorder(
     aForFrame, aBorderArea, aSkipSides, &aStyleBorder);
   RectCornerRadii bgRadii;
   ::GetRadii(aForFrame, aStyleBorder, aBorderArea, joinedBorderArea, &bgRadii);
 
   PrintAsFormatString(" joinedBorderArea: %d %d %d %d\n",
@@ -938,17 +921,16 @@ ConstructBorderRenderer(nsPresContext* a
     document,
     aDrawTarget,
     dirtyRect,
     joinedBorderAreaPx,
     borderStyles,
     borderWidths,
     bgRadii,
     borderColors,
-    bgColor,
     !aForFrame->BackfaceIsHidden(),
     *aNeedsClip ? Some(NSRectToRect(aBorderArea, oneDevPixel)) : Nothing());
 }
 
 ImgDrawResult
 nsCSSRendering::PaintBorderWithStyleBorder(nsPresContext* aPresContext,
                                            gfxContext& aRenderingContext,
                                            nsIFrame* aForFrame,
@@ -1121,22 +1103,16 @@ nsCSSRendering::CreateBorderRendererForO
   // Get our ComputedStyle's color struct.
   const nsStyleOutline* ourOutline = aComputedStyle->StyleOutline();
 
   if (!ourOutline->ShouldPaintOutline()) {
     // Empty outline
     return Nothing();
   }
 
-  nsIFrame* bgFrame =
-    nsCSSRendering::FindNonTransparentBackgroundFrame(aForFrame, false);
-  ComputedStyle* bgContext = bgFrame->Style();
-  nscolor bgColor =
-    bgContext->GetVisitedDependentColor(&nsStyleBackground::mBackgroundColor);
-
   nsRect innerRect;
   if (
 #ifdef MOZ_XUL
     aComputedStyle->GetPseudoType() == CSSPseudoElementType::XULTree
 #else
     false
 #endif
   ) {
@@ -1230,17 +1206,16 @@ nsCSSRendering::CreateBorderRendererForO
                          document,
                          dt,
                          dirtyRect,
                          oRect,
                          outlineStyles,
                          outlineWidths,
                          outlineRadii,
                          outlineColors,
-                         bgColor,
                          !aForFrame->BackfaceIsHidden(),
                          Nothing());
 
   return Some(br);
 }
 
 void
 nsCSSRendering::PaintOutline(nsPresContext* aPresContext,
@@ -1307,17 +1282,16 @@ nsCSSRendering::PaintFocus(nsPresContext
                          nullptr,
                          aDrawTarget,
                          focusRect,
                          focusRect,
                          focusStyles,
                          focusWidths,
                          focusRadii,
                          focusColors,
-                         NS_RGB(255, 0, 0),
                          true,
                          Nothing());
   br.DrawBorders();
 
   PrintAsStringNewline();
 }
 
 // Thebes Border Rendering Code End
@@ -3782,28 +3756,26 @@ GetDashInfo(nscoord aBorderLength,
     }
   }
 }
 
 void
 nsCSSRendering::DrawTableBorderSegment(DrawTarget& aDrawTarget,
                                        uint8_t aBorderStyle,
                                        nscolor aBorderColor,
-                                       nscolor aBGColor,
                                        const nsRect& aBorder,
                                        int32_t aAppUnitsPerDevPixel,
                                        mozilla::Side aStartBevelSide,
                                        nscoord aStartBevelOffset,
                                        mozilla::Side aEndBevelSide,
                                        nscoord aEndBevelOffset)
 {
   bool horizontal =
     ((eSideTop == aStartBevelSide) || (eSideBottom == aStartBevelSide));
   nscoord oneDevPixel = NSIntPixelsToAppUnits(1, aAppUnitsPerDevPixel);
-  uint8_t ridgeGroove = NS_STYLE_BORDER_STYLE_RIDGE;
 
   if ((oneDevPixel >= aBorder.width) || (oneDevPixel >= aBorder.height) ||
       (NS_STYLE_BORDER_STYLE_DASHED == aBorderStyle) ||
       (NS_STYLE_BORDER_STYLE_DOTTED == aBorderStyle)) {
     // no beveling for 1 pixel border, dash or dot
     aStartBevelOffset = 0;
     aEndBevelOffset = 0;
   }
@@ -3875,259 +3847,273 @@ nsCSSRendering::DrawTableBorderSegment(D
                           aAppUnitsPerDevPixel,
                           horizontal);
 
         rect.y += rect.height;
         rect.height = endDashLength;
         DrawSolidBorderSegment(
           aDrawTarget, rect, aBorderColor, aAppUnitsPerDevPixel);
       }
-    } break;
-    case NS_STYLE_BORDER_STYLE_GROOVE:
-      ridgeGroove = NS_STYLE_BORDER_STYLE_GROOVE; // and fall through to ridge
-      MOZ_FALLTHROUGH;
-    case NS_STYLE_BORDER_STYLE_RIDGE:
-      if ((horizontal && (oneDevPixel >= aBorder.height)) ||
-          (!horizontal && (oneDevPixel >= aBorder.width))) {
-        // a one pixel border
-        DrawSolidBorderSegment(aDrawTarget,
-                               aBorder,
-                               aBorderColor,
-                               aAppUnitsPerDevPixel,
-                               aStartBevelSide,
-                               aStartBevelOffset,
-                               aEndBevelSide,
-                               aEndBevelOffset);
-      } else {
-        nscoord startBevel =
-          (aStartBevelOffset > 0)
-            ? RoundFloatToPixel(
-                0.5f * (float)aStartBevelOffset, aAppUnitsPerDevPixel, true)
-            : 0;
-        nscoord endBevel = (aEndBevelOffset > 0)
-                             ? RoundFloatToPixel(0.5f * (float)aEndBevelOffset,
-                                                 aAppUnitsPerDevPixel,
-                                                 true)
-                             : 0;
-        mozilla::Side ridgeGrooveSide = (horizontal) ? eSideTop : eSideLeft;
-        // FIXME: In theory, this should use the visited-dependent
-        // background color, but I don't care.
-        nscolor bevelColor =
-          MakeBevelColor(ridgeGrooveSide, ridgeGroove, aBGColor, aBorderColor);
-        nsRect rect(aBorder);
-        nscoord half;
-        if (horizontal) { // top, bottom
-          half = RoundFloatToPixel(0.5f * (float)aBorder.height,
-                                   aAppUnitsPerDevPixel);
-          rect.height = half;
-          if (eSideTop == aStartBevelSide) {
-            rect.x += startBevel;
-            rect.width -= startBevel;
-          }
-          if (eSideTop == aEndBevelSide) {
-            rect.width -= endBevel;
-          }
-          DrawSolidBorderSegment(aDrawTarget,
-                                 rect,
-                                 bevelColor,
-                                 aAppUnitsPerDevPixel,
-                                 aStartBevelSide,
-                                 startBevel,
-                                 aEndBevelSide,
-                                 endBevel);
-        } else { // left, right
-          half = RoundFloatToPixel(0.5f * (float)aBorder.width,
-                                   aAppUnitsPerDevPixel);
-          rect.width = half;
-          if (eSideLeft == aStartBevelSide) {
-            rect.y += startBevel;
-            rect.height -= startBevel;
-          }
-          if (eSideLeft == aEndBevelSide) {
-            rect.height -= endBevel;
-          }
-          DrawSolidBorderSegment(aDrawTarget,
-                                 rect,
-                                 bevelColor,
-                                 aAppUnitsPerDevPixel,
-                                 aStartBevelSide,
-                                 startBevel,
-                                 aEndBevelSide,
-                                 endBevel);
+    }
+    break;
+  default:
+    AutoTArray<SolidBeveledBorderSegment, 3> segments;
+    GetTableBorderSolidSegments(segments,
+                                aBorderStyle,
+                                aBorderColor,
+                                aBorder,
+                                aAppUnitsPerDevPixel,
+                                aStartBevelSide,
+                                aStartBevelOffset,
+                                aEndBevelSide,
+                                aEndBevelOffset);
+    for (const auto& segment : segments) {
+      DrawSolidBorderSegment(aDrawTarget,
+                             segment.mRect,
+                             segment.mColor,
+                             aAppUnitsPerDevPixel,
+                             segment.mStartBevel.mSide,
+                             segment.mStartBevel.mOffset,
+                             segment.mEndBevel.mSide,
+                             segment.mEndBevel.mOffset);
+    }
+    break;
+  }
+}
+
+void
+nsCSSRendering::GetTableBorderSolidSegments(
+    nsTArray<SolidBeveledBorderSegment>& aSegments,
+    uint8_t       aBorderStyle,
+    nscolor       aBorderColor,
+    const nsRect& aBorder,
+    int32_t       aAppUnitsPerDevPixel,
+    mozilla::Side aStartBevelSide,
+    nscoord       aStartBevelOffset,
+    mozilla::Side aEndBevelSide,
+    nscoord       aEndBevelOffset)
+{
+  const bool horizontal = eSideTop == aStartBevelSide || eSideBottom == aStartBevelSide;
+  const nscoord oneDevPixel = NSIntPixelsToAppUnits(1, aAppUnitsPerDevPixel);
+
+  switch (aBorderStyle) {
+  case NS_STYLE_BORDER_STYLE_NONE:
+  case NS_STYLE_BORDER_STYLE_HIDDEN:
+    return;
+  case NS_STYLE_BORDER_STYLE_DOTTED:
+  case NS_STYLE_BORDER_STYLE_DASHED:
+    MOZ_ASSERT_UNREACHABLE("Caller should have checked");
+    return;
+  case NS_STYLE_BORDER_STYLE_GROOVE:
+  case NS_STYLE_BORDER_STYLE_RIDGE:
+    if ((horizontal && (oneDevPixel >= aBorder.height)) ||
+        (!horizontal && (oneDevPixel >= aBorder.width))) {
+      aSegments.AppendElement(SolidBeveledBorderSegment {
+        aBorder,
+        aBorderColor,
+        { aStartBevelSide, aStartBevelOffset },
+        { aEndBevelSide, aEndBevelOffset }
+      });
+    } else {
+      nscoord startBevel = (aStartBevelOffset > 0)
+                            ? RoundFloatToPixel(0.5f * (float)aStartBevelOffset,
+                                                aAppUnitsPerDevPixel, true) : 0;
+      nscoord endBevel =   (aEndBevelOffset > 0)
+                            ? RoundFloatToPixel(0.5f * (float)aEndBevelOffset,
+                                                aAppUnitsPerDevPixel, true) : 0;
+      mozilla::Side ridgeGrooveSide = (horizontal) ? eSideTop : eSideLeft;
+      // FIXME: In theory, this should use the visited-dependent
+      // background color, but I don't care.
+      nscolor bevelColor = MakeBevelColor(ridgeGrooveSide, aBorderStyle,
+                                          aBorderColor);
+      nsRect rect(aBorder);
+      nscoord half;
+      if (horizontal) { // top, bottom
+        half = RoundFloatToPixel(0.5f * (float)aBorder.height,
+                                 aAppUnitsPerDevPixel);
+        rect.height = half;
+        if (eSideTop == aStartBevelSide) {
+          rect.x += startBevel;
+          rect.width -= startBevel;
         }
-
-        rect = aBorder;
-        ridgeGrooveSide =
-          (eSideTop == ridgeGrooveSide) ? eSideBottom : eSideRight;
-        // FIXME: In theory, this should use the visited-dependent
-        // background color, but I don't care.
-        bevelColor =
-          MakeBevelColor(ridgeGrooveSide, ridgeGroove, aBGColor, aBorderColor);
-        if (horizontal) {
-          rect.y = rect.y + half;
-          rect.height = aBorder.height - half;
-          if (eSideBottom == aStartBevelSide) {
-            rect.x += startBevel;
-            rect.width -= startBevel;
-          }
-          if (eSideBottom == aEndBevelSide) {
-            rect.width -= endBevel;
-          }
-          DrawSolidBorderSegment(aDrawTarget,
-                                 rect,
-                                 bevelColor,
-                                 aAppUnitsPerDevPixel,
-                                 aStartBevelSide,
-                                 startBevel,
-                                 aEndBevelSide,
-                                 endBevel);
-        } else {
-          rect.x = rect.x + half;
-          rect.width = aBorder.width - half;
-          if (eSideRight == aStartBevelSide) {
-            rect.y += aStartBevelOffset - startBevel;
-            rect.height -= startBevel;
-          }
-          if (eSideRight == aEndBevelSide) {
-            rect.height -= endBevel;
-          }
-          DrawSolidBorderSegment(aDrawTarget,
-                                 rect,
-                                 bevelColor,
-                                 aAppUnitsPerDevPixel,
-                                 aStartBevelSide,
-                                 startBevel,
-                                 aEndBevelSide,
-                                 endBevel);
+        if (eSideTop == aEndBevelSide) {
+          rect.width -= endBevel;
         }
+        aSegments.AppendElement(SolidBeveledBorderSegment {
+          rect,
+          bevelColor,
+          { aStartBevelSide, startBevel },
+          { aEndBevelSide, endBevel }
+        });
+      } else { // left, right
+        half = RoundFloatToPixel(0.5f * (float)aBorder.width,
+                                 aAppUnitsPerDevPixel);
+        rect.width = half;
+        if (eSideLeft == aStartBevelSide) {
+          rect.y += startBevel;
+          rect.height -= startBevel;
+        }
+        if (eSideLeft == aEndBevelSide) {
+          rect.height -= endBevel;
+        }
+        aSegments.AppendElement(SolidBeveledBorderSegment {
+          rect,
+          bevelColor,
+          { aStartBevelSide, startBevel },
+          { aEndBevelSide, endBevel }
+        });
       }
-      break;
-    case NS_STYLE_BORDER_STYLE_DOUBLE:
-      // We can only do "double" borders if the thickness of the border
-      // is more than 2px.  Otherwise, we fall through to painting a
-      // solid border.
-      if ((aBorder.width > 2 * oneDevPixel || horizontal) &&
-          (aBorder.height > 2 * oneDevPixel || !horizontal)) {
-        nscoord startBevel =
-          (aStartBevelOffset > 0)
-            ? RoundFloatToPixel(0.333333f * (float)aStartBevelOffset,
-                                aAppUnitsPerDevPixel)
-            : 0;
-        nscoord endBevel =
-          (aEndBevelOffset > 0)
-            ? RoundFloatToPixel(0.333333f * (float)aEndBevelOffset,
-                                aAppUnitsPerDevPixel)
-            : 0;
-        if (horizontal) { // top, bottom
-          nscoord thirdHeight = RoundFloatToPixel(
-            0.333333f * (float)aBorder.height, aAppUnitsPerDevPixel);
-
-          // draw the top line or rect
-          nsRect topRect(aBorder.x, aBorder.y, aBorder.width, thirdHeight);
-          if (eSideTop == aStartBevelSide) {
-            topRect.x += aStartBevelOffset - startBevel;
-            topRect.width -= aStartBevelOffset - startBevel;
-          }
-          if (eSideTop == aEndBevelSide) {
-            topRect.width -= aEndBevelOffset - endBevel;
-          }
-          DrawSolidBorderSegment(aDrawTarget,
-                                 topRect,
-                                 aBorderColor,
-                                 aAppUnitsPerDevPixel,
-                                 aStartBevelSide,
-                                 startBevel,
-                                 aEndBevelSide,
-                                 endBevel);
-
-          // draw the botom line or rect
-          nscoord heightOffset = aBorder.height - thirdHeight;
-          nsRect bottomRect(aBorder.x,
-                            aBorder.y + heightOffset,
-                            aBorder.width,
-                            aBorder.height - heightOffset);
-          if (eSideBottom == aStartBevelSide) {
-            bottomRect.x += aStartBevelOffset - startBevel;
-            bottomRect.width -= aStartBevelOffset - startBevel;
-          }
-          if (eSideBottom == aEndBevelSide) {
-            bottomRect.width -= aEndBevelOffset - endBevel;
-          }
-          DrawSolidBorderSegment(aDrawTarget,
-                                 bottomRect,
-                                 aBorderColor,
-                                 aAppUnitsPerDevPixel,
-                                 aStartBevelSide,
-                                 startBevel,
-                                 aEndBevelSide,
-                                 endBevel);
-        } else { // left, right
-          nscoord thirdWidth = RoundFloatToPixel(
-            0.333333f * (float)aBorder.width, aAppUnitsPerDevPixel);
-
-          nsRect leftRect(aBorder.x, aBorder.y, thirdWidth, aBorder.height);
-          if (eSideLeft == aStartBevelSide) {
-            leftRect.y += aStartBevelOffset - startBevel;
-            leftRect.height -= aStartBevelOffset - startBevel;
-          }
-          if (eSideLeft == aEndBevelSide) {
-            leftRect.height -= aEndBevelOffset - endBevel;
-          }
-          DrawSolidBorderSegment(aDrawTarget,
-                                 leftRect,
-                                 aBorderColor,
-                                 aAppUnitsPerDevPixel,
-                                 aStartBevelSide,
-                                 startBevel,
-                                 aEndBevelSide,
-                                 endBevel);
-
-          nscoord widthOffset = aBorder.width - thirdWidth;
-          nsRect rightRect(aBorder.x + widthOffset,
-                           aBorder.y,
-                           aBorder.width - widthOffset,
-                           aBorder.height);
-          if (eSideRight == aStartBevelSide) {
-            rightRect.y += aStartBevelOffset - startBevel;
-            rightRect.height -= aStartBevelOffset - startBevel;
-          }
-          if (eSideRight == aEndBevelSide) {
-            rightRect.height -= aEndBevelOffset - endBevel;
-          }
-          DrawSolidBorderSegment(aDrawTarget,
-                                 rightRect,
-                                 aBorderColor,
-                                 aAppUnitsPerDevPixel,
-                                 aStartBevelSide,
-                                 startBevel,
-                                 aEndBevelSide,
-                                 endBevel);
+
+      rect = aBorder;
+      ridgeGrooveSide = (eSideTop == ridgeGrooveSide) ? eSideBottom : eSideRight;
+      // FIXME: In theory, this should use the visited-dependent
+      // background color, but I don't care.
+      bevelColor = MakeBevelColor(ridgeGrooveSide, aBorderStyle,
+                                  aBorderColor);
+      if (horizontal) {
+        rect.y = rect.y + half;
+        rect.height = aBorder.height - half;
+        if (eSideBottom == aStartBevelSide) {
+          rect.x += startBevel;
+          rect.width -= startBevel;
+        }
+        if (eSideBottom == aEndBevelSide) {
+          rect.width -= endBevel;
+        }
+        aSegments.AppendElement(SolidBeveledBorderSegment {
+          rect,
+          bevelColor,
+          { aStartBevelSide, startBevel },
+          { aEndBevelSide, endBevel }
+        });
+      } else {
+        rect.x = rect.x + half;
+        rect.width = aBorder.width - half;
+        if (eSideRight == aStartBevelSide) {
+          rect.y += aStartBevelOffset - startBevel;
+          rect.height -= startBevel;
+        }
+        if (eSideRight == aEndBevelSide) {
+          rect.height -= endBevel;
+        }
+        aSegments.AppendElement(SolidBeveledBorderSegment {
+          rect,
+          bevelColor,
+          { aStartBevelSide, startBevel },
+          { aEndBevelSide, endBevel }
+        });
+      }
+    }
+    break;
+  case NS_STYLE_BORDER_STYLE_DOUBLE:
+    // We can only do "double" borders if the thickness of the border
+    // is more than 2px.  Otherwise, we fall through to painting a
+    // solid border.
+    if ((aBorder.width > 2 * oneDevPixel || horizontal) &&
+        (aBorder.height > 2 * oneDevPixel || !horizontal)) {
+      nscoord startBevel = (aStartBevelOffset > 0)
+                            ? RoundFloatToPixel(0.333333f *
+                                                (float)aStartBevelOffset,
+                                                 aAppUnitsPerDevPixel) : 0;
+      nscoord endBevel =   (aEndBevelOffset > 0)
+                            ? RoundFloatToPixel(0.333333f *
+                                                (float)aEndBevelOffset,
+                                                aAppUnitsPerDevPixel) : 0;
+      if (horizontal) { // top, bottom
+        nscoord thirdHeight = RoundFloatToPixel(0.333333f *
+                                                (float)aBorder.height,
+                                                aAppUnitsPerDevPixel);
+
+        // draw the top line or rect
+        nsRect topRect(aBorder.x, aBorder.y, aBorder.width, thirdHeight);
+        if (eSideTop == aStartBevelSide) {
+          topRect.x += aStartBevelOffset - startBevel;
+          topRect.width -= aStartBevelOffset - startBevel;
+        }
+        if (eSideTop == aEndBevelSide) {
+          topRect.width -= aEndBevelOffset - endBevel;
         }
-        break;
+
+        aSegments.AppendElement(SolidBeveledBorderSegment {
+          topRect,
+          aBorderColor,
+          { aStartBevelSide, startBevel },
+          { aEndBevelSide, endBevel }
+        });
+
+        // draw the botom line or rect
+        nscoord heightOffset = aBorder.height - thirdHeight;
+        nsRect bottomRect(aBorder.x, aBorder.y + heightOffset, aBorder.width, aBorder.height - heightOffset);
+        if (eSideBottom == aStartBevelSide) {
+          bottomRect.x += aStartBevelOffset - startBevel;
+          bottomRect.width -= aStartBevelOffset - startBevel;
+        }
+        if (eSideBottom == aEndBevelSide) {
+          bottomRect.width -= aEndBevelOffset - endBevel;
+        }
+        aSegments.AppendElement(SolidBeveledBorderSegment {
+          bottomRect,
+          aBorderColor,
+          { aStartBevelSide, startBevel },
+          { aEndBevelSide, endBevel }
+        });
+      } else { // left, right
+        nscoord thirdWidth = RoundFloatToPixel(0.333333f * (float)aBorder.width,
+                                               aAppUnitsPerDevPixel);
+
+        nsRect leftRect(aBorder.x, aBorder.y, thirdWidth, aBorder.height);
+        if (eSideLeft == aStartBevelSide) {
+          leftRect.y += aStartBevelOffset - startBevel;
+          leftRect.height -= aStartBevelOffset - startBevel;
+        }
+        if (eSideLeft == aEndBevelSide) {
+          leftRect.height -= aEndBevelOffset - endBevel;
+        }
+
+        aSegments.AppendElement(SolidBeveledBorderSegment {
+          leftRect,
+          aBorderColor,
+          { aStartBevelSide, startBevel },
+          { aEndBevelSide, endBevel }
+        });
+
+        nscoord widthOffset = aBorder.width - thirdWidth;
+        nsRect rightRect(aBorder.x + widthOffset, aBorder.y, aBorder.width - widthOffset, aBorder.height);
+        if (eSideRight == aStartBevelSide) {
+          rightRect.y += aStartBevelOffset - startBevel;
+          rightRect.height -= aStartBevelOffset - startBevel;
+        }
+        if (eSideRight == aEndBevelSide) {
+          rightRect.height -= aEndBevelOffset - endBevel;
+        }
+        aSegments.AppendElement(SolidBeveledBorderSegment {
+          rightRect,
+          aBorderColor,
+          { aStartBevelSide, startBevel },
+          { aEndBevelSide, endBevel }
+        });
       }
-      // else fall through to solid
-      MOZ_FALLTHROUGH;
-    case NS_STYLE_BORDER_STYLE_SOLID:
-      DrawSolidBorderSegment(aDrawTarget,
-                             aBorder,
-                             aBorderColor,
-                             aAppUnitsPerDevPixel,
-                             aStartBevelSide,
-                             aStartBevelOffset,
-                             aEndBevelSide,
-                             aEndBevelOffset);
-      break;
-    case NS_STYLE_BORDER_STYLE_OUTSET:
-    case NS_STYLE_BORDER_STYLE_INSET:
-      NS_ASSERTION(false,
-                   "inset, outset should have been converted to groove, ridge");
-      break;
-    case NS_STYLE_BORDER_STYLE_AUTO:
-      NS_ASSERTION(false, "Unexpected 'auto' table border");
-      break;
+    }
+    // else fall through to solid
+    MOZ_FALLTHROUGH;
+  case NS_STYLE_BORDER_STYLE_SOLID:
+    aSegments.AppendElement(SolidBeveledBorderSegment {
+      aBorder,
+      aBorderColor,
+      { aStartBevelSide, aStartBevelOffset },
+      { aEndBevelSide, aEndBevelOffset }
+    });
+    break;
+  case NS_STYLE_BORDER_STYLE_OUTSET:
+  case NS_STYLE_BORDER_STYLE_INSET:
+    MOZ_ASSERT_UNREACHABLE("inset, outset should have been converted to groove, ridge");
+    break;
+  case NS_STYLE_BORDER_STYLE_AUTO:
+    MOZ_ASSERT_UNREACHABLE("Unexpected 'auto' table border");
+    break;
   }
 }
 
 // End table border-collapsing section
 
 Rect
 nsCSSRendering::ExpandPaintingRectForDecorationLine(nsIFrame* aFrame,
                                                     const uint8_t aStyle,
--- a/layout/painting/nsCSSRendering.h
+++ b/layout/painting/nsCSSRendering.h
@@ -586,29 +586,57 @@ struct nsCSSRendering
   static void BeginFrameTreesLocked();
   /**
    * Called when we've finished using a display list. When all
    * BeginFrameTreeLocked calls have been balanced by an EndFrameTreeLocked,
    * the frame tree may start changing again.
    */
   static void EndFrameTreesLocked();
 
-  // Draw a border segment in the table collapsing border model without
-  // beveling corners
+  // Draw a border segment in the table collapsing border model with beveling
+  // corners.
   static void DrawTableBorderSegment(
     DrawTarget& aDrawTarget,
     uint8_t aBorderStyle,
     nscolor aBorderColor,
-    nscolor aBGColor,
     const nsRect& aBorderRect,
     int32_t aAppUnitsPerDevPixel,
-    mozilla::Side aStartBevelSide = mozilla::eSideTop,
-    nscoord aStartBevelOffset = 0,
-    mozilla::Side aEndBevelSide = mozilla::eSideTop,
-    nscoord aEndBevelOffset = 0);
+    mozilla::Side aStartBevelSide,
+    nscoord aStartBevelOffset,
+    mozilla::Side aEndBevelSide,
+    nscoord aEndBevelOffset);
+
+  // A single border bevel.
+  struct Bevel
+  {
+    mozilla::Side mSide;
+    nscoord mOffset;
+  };
+
+  // A single solid beveled border segment.
+  struct SolidBeveledBorderSegment
+  {
+    nsRect mRect;
+    nscolor mColor;
+    Bevel mStartBevel;
+    Bevel mEndBevel;
+  };
+
+  // Collect the table border segments with beveling. Can't be called with
+  // dashed / dotted borders, since we don't support beveling those.
+  static void GetTableBorderSolidSegments(
+      nsTArray<SolidBeveledBorderSegment>& aSegments,
+      uint8_t aBorderStyle,
+      nscolor aBorderColor,
+      const nsRect& aBorderRect,
+      int32_t aAppUnitsPerDevPixel,
+      mozilla::Side aStartBevelSide,
+      nscoord aStartBevelOffset,
+      mozilla::Side aEndBevelSide,
+      nscoord aEndBevelOffset);
 
   // NOTE: pt, dirtyRect, lineSize, ascent, offset in the following
   //       structs are non-rounded device pixels, not app units.
   struct DecorationRectParams
   {
     // The width [length] and the height [thickness] of the decoration
     // line. This is a "logical" size in textRun orientation, so that
     // for a vertical textrun, width will actually be a physical height;
--- a/layout/painting/nsCSSRenderingBorders.cpp
+++ b/layout/painting/nsCSSRenderingBorders.cpp
@@ -78,28 +78,26 @@ ComputeBorderCornerDimensions(const Floa
 // given a corner index, get the previous and next corner index
 #define NEXT_CORNER(_s) Corner(((_s) + 1) & 3)
 #define PREV_CORNER(_s) Corner(((_s) + 3) & 3)
 
 // from the given base color and the background color, turn
 // color into a color for the given border pattern style
 static Color
 MakeBorderColor(nscolor aColor,
-                nscolor aBackgroundColor,
                 BorderColorStyle aBorderColorStyle);
 
 // Given a line index (an index starting from the outside of the
 // border going inwards) and an array of line styles, calculate the
 // color that that stripe of the border should be rendered in.
 static Color
 ComputeColorForLine(uint32_t aLineIndex,
                     const BorderColorStyle* aBorderColorStyle,
                     uint32_t aBorderColorStyleCount,
-                    nscolor aBorderColor,
-                    nscolor aBackgroundColor);
+                    nscolor aBorderColor);
 
 // little helper function to check if the array of 4 floats given are
 // equal to the given value
 static bool
 CheckFourFloatsEqual(const Float* vals, Float k)
 {
   return (vals[0] == k && vals[1] == k && vals[2] == k && vals[3] == k);
 }
@@ -175,26 +173,24 @@ nsCSSBorderRenderer::nsCSSBorderRenderer
                                          const nsIDocument* aDocument,
                                          DrawTarget* aDrawTarget,
                                          const Rect& aDirtyRect,
                                          Rect& aOuterRect,
                                          const uint8_t* aBorderStyles,
                                          const Float* aBorderWidths,
                                          RectCornerRadii& aBorderRadii,
                                          const nscolor* aBorderColors,
-                                         nscolor aBackgroundColor,
                                          bool aBackfaceIsVisible,
                                          const Maybe<Rect>& aClipRect)
   : mPresContext(aPresContext)
   , mDocument(aDocument)
   , mDrawTarget(aDrawTarget)
   , mDirtyRect(aDirtyRect)
   , mOuterRect(aOuterRect)
   , mBorderRadii(aBorderRadii)
-  , mBackgroundColor(aBackgroundColor)
   , mBackfaceIsVisible(aBackfaceIsVisible)
   , mLocalClip(aClipRect)
 {
   PodCopy(mBorderStyles, aBorderStyles, 4);
   PodCopy(mBorderWidths, aBorderWidths, 4);
   PodCopy(mBorderColors, aBorderColors, 4);
   mInnerRect = mOuterRect;
   mInnerRect.Deflate(Margin(
@@ -1248,51 +1244,47 @@ nsCSSBorderRenderer::FillSolidBorder(con
     if (aSides & (1 << i)) {
       MaybeSnapToDevicePixels(r[i], *mDrawTarget, true);
       mDrawTarget->FillRect(r[i], aColor);
     }
   }
 }
 
 Color
-MakeBorderColor(nscolor aColor,
-                nscolor aBackgroundColor,
-                BorderColorStyle aBorderColorStyle)
+MakeBorderColor(nscolor aColor, BorderColorStyle aBorderColorStyle)
 {
   nscolor colors[2];
   int k = 0;
 
   switch (aBorderColorStyle) {
     case BorderColorStyleNone:
       return Color(0.f, 0.f, 0.f, 0.f); // transparent black
 
     case BorderColorStyleLight:
       k = 1;
       MOZ_FALLTHROUGH;
     case BorderColorStyleDark:
-      NS_GetSpecial3DColors(colors, aBackgroundColor, aColor);
+      NS_GetSpecial3DColors(colors, aColor);
       return Color::FromABGR(colors[k]);
 
     case BorderColorStyleSolid:
     default:
       return Color::FromABGR(aColor);
   }
 }
 
 Color
 ComputeColorForLine(uint32_t aLineIndex,
                     const BorderColorStyle* aBorderColorStyle,
                     uint32_t aBorderColorStyleCount,
-                    nscolor aBorderColor,
-                    nscolor aBackgroundColor)
+                    nscolor aBorderColor)
 {
   NS_ASSERTION(aLineIndex < aBorderColorStyleCount, "Invalid lineIndex given");
 
-  return MakeBorderColor(
-    aBorderColor, aBackgroundColor, aBorderColorStyle[aLineIndex]);
+  return MakeBorderColor(aBorderColor, aBorderColorStyle[aLineIndex]);
 }
 
 void
 nsCSSBorderRenderer::DrawBorderSides(int aSides)
 {
   if (aSides == 0 || (aSides & ~eSideBitsAll) != 0) {
     NS_WARNING("DrawBorderSides: invalid sides!");
     return;
@@ -1563,18 +1555,17 @@ nsCSSBorderRenderer::DrawBorderSides(int
                           noMarginRight ? 0 : borderWidths[i][1],
                           noMarginBottom ? 0 : borderWidths[i][2],
                           noMarginLeft ? 0 : borderWidths[i][3]));
 
     if (borderColorStyle[i] != BorderColorStyleNone) {
       Color c = ComputeColorForLine(i,
                                     borderColorStyle,
                                     borderColorStyleCount,
-                                    borderRenderColor,
-                                    mBackgroundColor);
+                                    borderRenderColor);
       ColorPattern color(ToDeviceColor(c));
 
       FillSolidBorder(soRect, siRect, radii, borderWidths[i], aSides, color);
     }
 
     ComputeInnerRadii(radii, borderWidths[i], &radii);
 
     // And now soRect is the same as siRect, for the next line in.
@@ -3407,17 +3398,16 @@ nsCSSBorderRenderer::DrawBorders()
 
       // If we don't have anything complex going on in this corner,
       // then we can just fill the corner with a solid color, and avoid
       // the potentially expensive clip.
       if (simpleCornerStyle && IsZeroSize(mBorderRadii[corner]) &&
           IsSolidCornerStyle(mBorderStyles[sides[0]], corner)) {
         Color color = MakeBorderColor(
           mBorderColors[sides[0]],
-          mBackgroundColor,
           BorderColorStyleForSolidCorner(mBorderStyles[sides[0]], corner));
         mDrawTarget->FillRect(GetCornerRect(corner),
                               ColorPattern(ToDeviceColor(color)));
         continue;
       }
 
       // clip to the corner
       mDrawTarget->PushClipRect(GetCornerRect(corner));
--- a/layout/painting/nsCSSRenderingBorders.h
+++ b/layout/painting/nsCSSRenderingBorders.h
@@ -91,17 +91,16 @@ public:
                       const nsIDocument* aDocument,
                       DrawTarget* aDrawTarget,
                       const Rect& aDirtyRect,
                       Rect& aOuterRect,
                       const uint8_t* aBorderStyles,
                       const Float* aBorderWidths,
                       RectCornerRadii& aBorderRadii,
                       const nscolor* aBorderColors,
-                      nscolor aBackgroundColor,
                       bool aBackfaceIsVisible,
                       const mozilla::Maybe<Rect>& aClipRect);
 
   // draw the entire border
   void DrawBorders();
 
   void CreateWebRenderCommands(
     nsDisplayItem* aItem,
@@ -142,19 +141,16 @@ private:
   // the style and size of the border
   uint8_t mBorderStyles[4];
   Float mBorderWidths[4];
   RectCornerRadii mBorderRadii;
 
   // the colors for 'border-top-color' et. al.
   nscolor mBorderColors[4];
 
-  // the background color
-  nscolor mBackgroundColor;
-
   // calculated values
   bool mAllBordersSameStyle;
   bool mAllBordersSameWidth;
   bool mOneUnitBorder;
   bool mNoBorderRadius;
   bool mAvoidStroke;
   bool mBackfaceIsVisible;
   mozilla::Maybe<Rect> mLocalClip;
--- a/layout/reftests/bugs/448193-ref.html
+++ b/layout/reftests/bugs/448193-ref.html
@@ -7,12 +7,12 @@ div {
   height: 50px;
   margin: 10px;
   border-width: 1px;
   border-style: solid;
   -moz-border-radius: 20px;
 }
 </style>
 <body>
-<div style="border-color: #b30000 #ff7f7f #ff7f7f #b30000"></div>
-<div style="border-color: #ff7f7f #b30000 #b30000 #ff7f7f"></div>
+<div style="border-color: #aa0000 #ff0000 #ff0000 #aa0000"></div>
+<div style="border-color: #ff0000 #aa0000 #aa0000 #ff0000"></div>
 </body>
 </html>
--- a/layout/reftests/bugs/461512-1-ref.html
+++ b/layout/reftests/bugs/461512-1-ref.html
@@ -35,20 +35,20 @@
       p.groove > span, p.ridge > span {
         border: 5px solid;
         margin: 0;
         padding: 0;
         display: block;
         height: 10px;
       }
       p.inset, p.groove, p.ridge > span {
-        border-color: rgb(182, 171, 160) rgb(246, 240, 234) rgb(246, 240, 234) rgb(182, 171, 160);
+        border-color: rgb(194, 180, 167) rgb(227, 207, 187) rgb(227, 207, 187) rgb(194, 180, 167);
       }
       p.outset, p.ridge, p.groove > span {
-        border-color: rgb(246, 240, 234) rgb(182, 171, 160) rgb(182, 171, 160) rgb(246, 240, 234);
+        border-color: rgb(227, 207, 187) rgb(194, 180, 167) rgb(194, 180, 167) rgb(227, 207, 187);
       }
     </style>
   </head>
   <body>
     <p style="border-style: solid;">&nbsp;</p>
     <!-- <p style="border-style: dashed;">&nbsp;</p> -->
     <!-- <p style="border-style: dotted;">&nbsp;</p> -->
     <p style="border-style: double;">&nbsp;</p>
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1168,17 +1168,17 @@ fails-if(usesRepeatResampling) fails-if(
 fails-if(Android) fails-if(usesRepeatResampling) fails-if(webrender) == 446100-1b.html about:blank
 fails-if(Android) fails-if(usesRepeatResampling) fails-if(webrender) == 446100-1c.html about:blank
 fails-if(usesRepeatResampling) fails-if(webrender) == 446100-1d.html about:blank
 fails-if(usesRepeatResampling) fails-if(webrender) == 446100-1e.html about:blank
 == 446100-1f.html about:blank
 fails-if(usesRepeatResampling) fails-if(Android) fails-if(webrender) == 446100-1g.html about:blank
 == 446100-1h.html about:blank
 == 447749-1.html 447749-1-ref.html
-fuzzy(0-127,0-2) fails-if(webrender) == 448193.html 448193-ref.html # bug 1382896 for webrender
+fuzzy(0-127,0-2) == 448193.html 448193-ref.html
 # There isn't a way to load UA Widget in reftest yet.
 test-pref(dom.ua_widget.enabled,false) != 449149-1a.html about:blank
 test-pref(dom.ua_widget.enabled,false) != 449149-1b.html about:blank
 # Retry the above with XBL scopes
 test-pref(dom.ua_widget.enabled,false) test-pref(dom.use_xbl_scopes_for_remote_xul,true) != 449149-1a.html about:blank
 test-pref(dom.ua_widget.enabled,false) test-pref(dom.use_xbl_scopes_for_remote_xul,true) != 449149-1b.html about:blank
 == 449149-2.html 449149-2-ref.html
 == 449171-1.html 449171-ref.html
@@ -1223,17 +1223,17 @@ fuzzy-if(skiaContent,0-1,0-45) fuzzy-if(
 == 458487-4b.html 458487-4-ref.html
 == 458487-4c.html 458487-4-ref.html
 == 458487-5a.html 458487-5-ref.html
 == 458487-5b.html 458487-5-ref.html
 fuzzy-if(skiaContent,0-1,0-5) == 459443-1.html 459443-1-ref.html
 == 459613-1.html 459613-1-ref.html
 == 460012-1.html 460012-1-ref.html
 == 461266-1.html 461266-1-ref.html
-fuzzy-if(skiaContent,0-1,0-12000) fails-if(webrender) == 461512-1.html 461512-1-ref.html # bug 1382896 for webrender
+fuzzy-if(skiaContent||webrender,0-1,0-31200) == 461512-1.html 461512-1-ref.html
 == 462844-1.html 462844-ref.html
 == 462844-2.html 462844-ref.html
 == 462844-3.html 462844-ref.html
 == 462844-4.html 462844-ref.html
 == 463204-1.html 463204-1-ref.html
 fuzzy-if(webrender,16-16,3425-3483) == 463217-1.xul 463217-1-ref.xul
 == 463952-1.html 463952-1-ref.html
 == 464811-1.html 464811-1-ref.html
--- a/layout/reftests/invalidation/reftest.list
+++ b/layout/reftests/invalidation/reftest.list
@@ -39,18 +39,18 @@ pref(layout.animated-image-layers.enable
 == filter-userspace-offset.svg?offsetContainer=foreignObject&mask=boundingBox filter-userspace-offset.svg
 == filter-userspace-offset.svg?offsetContainer=rect&mask=userSpace-at100 filter-userspace-offset.svg
 == filter-userspace-offset.svg?offsetContainer=use&mask=userSpace-atZero filter-userspace-offset.svg
 == filter-userspace-offset.svg?offsetContainer=innerSVG&mask=userSpace-atZero filter-userspace-offset.svg
 == filter-userspace-offset.svg?offsetContainer=foreignObject&mask=userSpace-at100 filter-userspace-offset.svg
 == filter-userspace-offset.svg?offsetContainer=rect&filter=matrix-fillPaint-boundingBox filter-userspace-offset.svg
 == filter-userspace-offset.svg?offsetContainer=rect&filter=matrix-fillPaint-userSpace-at100 filter-userspace-offset.svg
 
-fails-if(webrender) != scroll-inactive-layers.html about:blank
-fails-if(webrender) != scroll-inactive-layers-2.html about:blank
+fails-if(webrender) fails-if(!Android) != scroll-inactive-layers.html about:blank   # bug 1494110 for the fails-if(!Android) (Android is a false pass, no doubt)
+fails-if(webrender) fails-if(!Android) != scroll-inactive-layers-2.html about:blank # bug 1494110 for the fails-if(!Android) (Android is a false pass, no doubt)
 != inactive-layertree-visible-region-1.html about:blank
 != inactive-layertree-visible-region-2.html about:blank
 != transform-floating-point-invalidation.html about:blank
 != transform-floating-point-invalidation.html?reverse about:blank
 != nudge-to-integer-invalidation.html about:blank
 != nudge-to-integer-invalidation.html?reverse about:blank
 != clipped-animated-transform-1.html about:blank
 != paintedlayer-recycling-1.html about:blank
--- a/layout/reftests/table-bordercollapse/bordercol.css
+++ b/layout/reftests/table-bordercollapse/bordercol.css
@@ -1,24 +1,22 @@
-	
-table {
-	margin-bottom: 0.5in;
-	}
-caption {
-	font-weight: bold;
-	font-style: italic;
-	}
-td {background-color:LightCyan }
-
-table.topLight {border-top: 1px solid #AFAFAF}
-table.bottom {border-bottom: 1px solid black}
-table.bottomDark {border-bottom: 1px solid #444444}
-table.leftLight {border-left: 1px solid #AFAFAF}
-table.right {border-right: 1px solid  black}
-table.rightDark {border-right: 1px solid #444444}
-table.top {border-top: 1px solid  black}
-table.left {border-left: 1px solid  black}
-table.bc {border-collapse:collapse}
-tbody.border{border-top: 1px solid  black; border-bottom: 1px solid black; }
-tr.border{border-top: 1px solid black; border-bottom: 1px solid  black; }
-td.border{border-left:1px solid black;}
-div.maskPixel{position:absolute; background-color:Black; width:1px; height:1px; }
-
+table {
+  margin-bottom: 0.5in;
+}
+caption {
+  font-weight: bold;
+  font-style: italic;
+}
+td {background-color:LightCyan}
+table.topLight {border-top: 1px solid #b2b2b2}
+table.bottom {border-bottom: 1px solid black}
+table.bottomDark {border-bottom: 1px solid #4c4c4c}
+table.leftLight {border-left: 1px solid #b2b2b2}
+table.right {border-right: 1px solid  black}
+table.rightDark {border-right: 1px solid #4c4c4c}
+table.top {border-top: 1px solid  black}
+table.left {border-left: 1px solid  black}
+table.bc {border-collapse:collapse}
+tbody.border{border-top: 1px solid  black; border-bottom: 1px solid black; }
+tr.border{border-top: 1px solid black; border-bottom: 1px solid  black; }
+td.border{border-left:1px solid black;}
+div.maskPixel{position:absolute; background-color:Black; width:1px; height:1px; }
+
--- a/layout/reftests/table-bordercollapse/reftest.list
+++ b/layout/reftests/table-bordercollapse/reftest.list
@@ -29,58 +29,58 @@ random-if(/^Windows\x20NT\x206\.1/.test(
 == bc_dyn_table1.html bc_dyn_table1_ref.html
 == bc_dyn_table2.html bc_dyn_table2_ref.html
 == bc_dyn_table3.html bc_dyn_table3_ref.html
 == bc_borderoffset1.html bc_borderoffset1_ref.html
 == bc_borderoffset2.html bc_borderoffset2_ref.html
 == frame_above_rules_all.html frame_above_rules_all_ref.html
 == frame_above_rules_cols.html frame_above_rules_cols_ref.html
 == frame_above_rules_groups.html frame_above_rules_groups_ref.html
-fails-if(webrender) == frame_above_rules_none.html frame_above_rules_none_ref.html # bug 1382896 for webrender
+== frame_above_rules_none.html frame_above_rules_none_ref.html
 == frame_above_rules_rows.html frame_above_rules_rows_ref.html
 == frame_below_rules_all.html frame_below_rules_all_ref.html
 == frame_below_rules_cols.html frame_below_rules_cols_ref.html
 == frame_below_rules_groups.html frame_below_rules_groups_ref.html
-fails-if(webrender) == frame_below_rules_none.html frame_below_rules_none_ref.html # bug 1382896 for webrender
+== frame_below_rules_none.html frame_below_rules_none_ref.html
 == frame_below_rules_rows.html frame_below_rules_rows_ref.html
 == frame_border_rules_all.html frame_border_rules_all_ref.html
 == frame_border_rules_cols.html frame_border_rules_cols_ref.html
 == frame_border_rules_groups.html frame_border_rules_groups_ref.html
-fails-if(webrender) == frame_border_rules_none.html frame_border_rules_none_ref.html # bug 1382896 for webrender
+== frame_border_rules_none.html frame_border_rules_none_ref.html
 == frame_border_rules_rows.html frame_border_rules_rows_ref.html
 == frame_box_rules_all.html frame_box_rules_all_ref.html
 == frame_box_rules_cols.html frame_box_rules_cols_ref.html
 == frame_box_rules_groups.html frame_box_rules_groups_ref.html
-fails-if(webrender) == frame_box_rules_none.html frame_box_rules_none_ref.html # bug 1382896 for webrender
+== frame_box_rules_none.html frame_box_rules_none_ref.html
 == frame_box_rules_none-collapse.html frame_box_rules_none-collapse-ref.html
 == frame_box_rules_rows.html frame_box_rules_rows_ref.html
 == frame_hsides_rules_all.html frame_hsides_rules_all_ref.html
 == frame_hsides_rules_cols.html frame_hsides_rules_cols_ref.html
 == frame_hsides_rules_groups.html frame_hsides_rules_groups_ref.html
-fails-if(webrender) == frame_hsides_rules_none.html frame_hsides_rules_none_ref.html # bug 1382896 for webrender
+== frame_hsides_rules_none.html frame_hsides_rules_none_ref.html
 == frame_hsides_rules_rows.html frame_hsides_rules_rows_ref.html
 == frame_lhs_rules_all.html frame_lhs_rules_all_ref.html
 == frame_lhs_rules_cols.html frame_lhs_rules_cols_ref.html
 == frame_lhs_rules_groups.html frame_lhs_rules_groups_ref.html
-fails-if(webrender) == frame_lhs_rules_none.html frame_lhs_rules_none_ref.html # bug 1382896 for webrender
+== frame_lhs_rules_none.html frame_lhs_rules_none_ref.html
 == frame_lhs_rules_rows.html frame_lhs_rules_rows_ref.html
 == frame_rhs_rules_all.html frame_rhs_rules_all_ref.html
 == frame_rhs_rules_cols.html frame_rhs_rules_cols_ref.html
 == frame_rhs_rules_groups.html frame_rhs_rules_groups_ref.html
-fails-if(webrender) == frame_rhs_rules_none.html  frame_rhs_rules_none_ref.html # bug 1382896 for webrender
+== frame_rhs_rules_none.html  frame_rhs_rules_none_ref.html
 == frame_rhs_rules_rows.html frame_rhs_rules_rows_ref.html
 == frame_void_rules_all.html frame_void_rules_all_ref.html
 == frame_void_rules_cols.html frame_void_rules_cols_ref.html
 == frame_void_rules_groups.html frame_void_rules_groups_ref.html
 == frame_void_rules_none.html frame_void_rules_none_ref.html
 == frame_void_rules_rows.html frame_void_rules_rows_ref.html
 == frame_vsides_rules_all.html frame_vsides_rules_all_ref.html
 == frame_vsides_rules_cols.html frame_vsides_rules_cols_ref.html
 == frame_vsides_rules_groups.html frame_vsides_rules_groups_ref.html
-fails-if(webrender) == frame_vsides_rules_none.html frame_vsides_rules_none_ref.html # bug 1382896 for webrender
+== frame_vsides_rules_none.html frame_vsides_rules_none_ref.html
 == frame_vsides_rules_rows.html frame_vsides_rules_rows_ref.html
 == borderhandling-1.html borderhandling-ref.html
 == borderhandling-2.html borderhandling-ref.html
 == borderhandling-3.html borderhandling-ref.html
 == borderhandling-4.html borderhandling-ref.html
 == borderhandling-5.xhtml borderhandling-strict-ref.html
 == borderhandling-6.xhtml borderhandling-strict-ref.html
 == borderhandling-7.xhtml borderhandling-strict-ref.html
@@ -102,19 +102,19 @@ fails-if(webrender) == frame_vsides_rule
 == borderhandling-rules-border-all-strict.html borderhandling-rules-border-all-strict-ref.html
 == bordercolor-1.html bordercolor-ref.html
 != bordercolor-2.html bordercolor-ref.html
 == bordercolor-3.html bordercolor-3-ref.html
 == bordercolor-4.html bordercolor-4-ref.html
 == empty-toprow.html empty-toprow-ref.html
 == double_borders.html double_borders_ref.html
 == border-collapse-rtl.html border-collapse-rtl-ref.html
-# Fuzzy because for some reason the corner beveling is antialiased differently.
+# Fuzzy because border-collapsed borders are not antialiased, since each segment is painted separately.
 # So get 40 pixels of fuzz, 20 at each beveled corner (because the border width
 # is 20px).
 fuzzy(0-255,0-40) == border-style-outset-becomes-groove.html border-style-outset-becomes-groove-ref.html
-# Fuzzy because for some reason the corner beveling is antialiased differently.
+# Fuzzy because border-collapsed borders are not antialiased, since each segment is painted separately.
 # So get 40 pixels of fuzz, 20 at each beveled corner (because the border width
 # is 20px).
 fuzzy(0-255,0-40) == border-style-inset-becomes-ridge.html border-style-inset-becomes-ridge-ref.html
 fuzzy(0-2,0-11000) == 1324524.html 1324524-ref.html
 == 1384602-1a.html 1384602-1-ref.html
 == 1384602-1b.html 1384602-1-ref.html
--- a/layout/reftests/writing-mode/tables/reftest.list
+++ b/layout/reftests/writing-mode/tables/reftest.list
@@ -4,17 +4,17 @@
 fuzzy-if(skiaContent,0-3,0-750) == vertical-table-2b.html vertical-table-2-ref.html
 == vertical-table-rowspan-1.html vertical-table-rowspan-1-ref.html
 == vertical-table-rowspan-2.html vertical-table-rowspan-2-ref.html
 == vertical-table-colspan-1.html vertical-table-colspan-1-ref.html
 == vertical-table-colspan-2.html vertical-table-colspan-2-ref.html
 == vertical-table-specified-width-1.html vertical-table-specified-width-1-ref.html
 asserts(1) == vertical-table-specified-width-2.html vertical-table-specified-width-2-ref.html # bug 1179741
 fuzzy-if(cocoaWidget,0-141,0-24) == vertical-border-collapse-1.html vertical-border-collapse-1-ref.html
-fuzzy-if(cocoaWidget,0-141,0-24) fails-if(webrender) == vertical-border-collapse-2.html vertical-border-collapse-2-ref.html # bug 1393907 for webrender
+fuzzy-if(cocoaWidget,0-141,0-24) == vertical-border-collapse-2.html vertical-border-collapse-2-ref.html
 
 == fixed-table-layout-002-vlr.html fixed-table-layout-002-ref.html
 == fixed-table-layout-003-vlr.html fixed-table-layout-002-ref.html
 == fixed-table-layout-004-vlr.html fixed-table-layout-004-ref.html
 == fixed-table-layout-005-vlr.html fixed-table-layout-005-ref.html
 == fixed-table-layout-006-vlr.html fixed-table-layout-006-ref.html
 == fixed-table-layout-007-vlr.html fixed-table-layout-007-ref.html
 == fixed-table-layout-009-vlr.html fixed-table-layout-009-ref.html
--- a/layout/svg/SVGObserverUtils.cpp
+++ b/layout/svg/SVGObserverUtils.cpp
@@ -362,27 +362,16 @@ SVGFilterObserverList::ReferencesValidRe
   for (uint32_t i = 0; i < mObservers.Length(); i++) {
     if (!mObservers[i]->ReferencesValidResource()) {
       return false;
     }
   }
   return true;
 }
 
-bool
-SVGFilterObserverList::IsInObserverLists() const
-{
-  for (uint32_t i = 0; i < mObservers.Length(); i++) {
-    if (!mObservers[i]->IsInObserverList()) {
-      return false;
-    }
-  }
-  return true;
-}
-
 void
 SVGFilterObserverListForCSSProp::OnRenderingChange()
 {
   nsIFrame* frame = mFrameReference.Get();
   if (!frame)
     return;
 
   // Repaint asynchronously in case the filter frame is being torn down
--- a/layout/svg/SVGObserverUtils.h
+++ b/layout/svg/SVGObserverUtils.h
@@ -114,18 +114,16 @@ public:
    */
   void OnNonDOMMutationRenderingChange();
 
   // When a SVGRenderingObserver list gets forcibly cleared, it uses this
   // callback to notify every observer that's cleared from it, so they can
   // react.
   void NotifyEvictedFromRenderingObserverList();
 
-  bool IsInObserverList() const { return mInObserverList; }
-
   nsIFrame* GetReferencedFrame();
   /**
    * @param aOK this is only for the convenience of callers. We set *aOK to false
    * if the frame is the wrong type
    */
   nsIFrame* GetReferencedFrame(mozilla::LayoutFrameType aFrameType, bool* aOK);
 
   Element* GetReferencedElement();
@@ -361,17 +359,16 @@ NS_DEFINE_STATIC_IID_ACCESSOR(SVGFilterO
 class SVGFilterObserverList : public nsISupports
 {
 public:
   SVGFilterObserverList(const nsTArray<nsStyleFilter>& aFilters,
                         nsIContent* aFilteredElement,
                         nsIFrame* aFiltedFrame = nullptr);
 
   bool ReferencesValidResources();
-  bool IsInObserverLists() const;
   void Invalidate() { OnRenderingChange(); }
 
   // nsISupports
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS(SVGFilterObserverList)
 
 protected:
   virtual ~SVGFilterObserverList();
--- a/layout/svg/nsSVGIntegrationUtils.cpp
+++ b/layout/svg/nsSVGIntegrationUtils.cpp
@@ -320,27 +320,28 @@ nsSVGIntegrationUtils::AdjustInvalidArea
   }
 
   // Don't bother calling GetEffectProperties; the filter property should
   // already have been set up during reflow/ComputeFrameEffectsRect
   nsIFrame* firstFrame =
     nsLayoutUtils::FirstContinuationOrIBSplitSibling(aFrame);
   SVGFilterObserverListForCSSProp* observers =
     SVGObserverUtils::GetFilterObserverList(firstFrame);
-  if (!observers || !observers->IsInObserverLists()) {
-    return aInvalidRegion;
-  }
 
   int32_t appUnitsPerDevPixel = aFrame->PresContext()->AppUnitsPerDevPixel();
 
   if (!observers || !observers->ReferencesValidResources()) {
     // The frame is either not there or not currently available,
     // perhaps because we're in the middle of tearing stuff down.
     // Be conservative, return our visual overflow rect relative
     // to the reference frame.
+    // XXX we may get here purely due to an SVG mask, in which case there is
+    // no need to do this it causes over-invalidation. See:
+    // https://bugzilla.mozilla.org/show_bug.cgi?id=1494110
+    // Do we still even need this for filters? If so, why?
     nsRect overflow = aFrame->GetVisualOverflowRect() + aToReferenceFrame;
     return overflow.ToOutsidePixels(appUnitsPerDevPixel);
   }
 
   // Convert aInvalidRegion into bounding box frame space in app units:
   nsPoint toBoundingBox =
     aFrame->GetOffsetTo(firstFrame) + GetOffsetToBoundingBox(firstFrame);
   // The initial rect was relative to the reference frame, so we need to
--- a/layout/tables/nsTableFrame.cpp
+++ b/layout/tables/nsTableFrame.cpp
@@ -1238,36 +1238,35 @@ nsDisplayTableItem::ComputeInvalidationR
   }
 
   nsDisplayItem::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion);
 }
 
 // A display item that draws all collapsed borders for a table.
 // At some point, we may want to find a nicer partitioning for dividing
 // border-collapse segments into their own display items.
-class nsDisplayTableBorderCollapse : public nsDisplayTableItem {
+class nsDisplayTableBorderCollapse final : public nsDisplayTableItem {
 public:
   nsDisplayTableBorderCollapse(nsDisplayListBuilder* aBuilder,
                                nsTableFrame* aFrame)
     : nsDisplayTableItem(aBuilder, aFrame) {
     MOZ_COUNT_CTOR(nsDisplayTableBorderCollapse);
     }
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayTableBorderCollapse() {
     MOZ_COUNT_DTOR(nsDisplayTableBorderCollapse);
   }
 #endif
 
-  virtual void Paint(nsDisplayListBuilder* aBuilder,
-                     gfxContext* aCtx) override;
-  virtual bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
-                                       wr::IpcResourceUpdateQueue& aResources,
-                                       const StackingContextHelper& aSc,
-                                       mozilla::layers::WebRenderLayerManager* aManager,
-                                       nsDisplayListBuilder* aDisplayListBuilder) override;
+  void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
+  bool CreateWebRenderCommands(wr::DisplayListBuilder& aBuilder,
+                               wr::IpcResourceUpdateQueue& aResources,
+                               const StackingContextHelper& aSc,
+                               layers::WebRenderLayerManager* aManager,
+                               nsDisplayListBuilder* aDisplayListBuilder) override;
   NS_DISPLAY_DECL_NAME("TableBorderCollapse", TYPE_TABLE_BORDER_COLLAPSE)
 };
 
 void
 nsDisplayTableBorderCollapse::Paint(nsDisplayListBuilder* aBuilder,
                                     gfxContext* aCtx)
 {
   nsPoint pt = ToReferenceFrame();
@@ -1281,26 +1280,27 @@ nsDisplayTableBorderCollapse::Paint(nsDi
   AutoRestoreTransform autoRestoreTransform(drawTarget);
   drawTarget->SetTransform(
       drawTarget->GetTransform().PreTranslate(ToPoint(devPixelOffset)));
 
   static_cast<nsTableFrame*>(mFrame)->PaintBCBorders(*drawTarget, GetPaintRect() - pt);
 }
 
 bool
-nsDisplayTableBorderCollapse::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
+nsDisplayTableBorderCollapse::CreateWebRenderCommands(wr::DisplayListBuilder& aBuilder,
                                                       wr::IpcResourceUpdateQueue& aResources,
                                                       const StackingContextHelper& aSc,
                                                       mozilla::layers::WebRenderLayerManager* aManager,
                                                       nsDisplayListBuilder* aDisplayListBuilder)
 {
-  static_cast<nsTableFrame *>(mFrame)->CreateWebRenderCommandsForBCBorders(aBuilder,
-                                                                          aSc,
-                                                                          GetPaintRect(),
-                                                                          ToReferenceFrame());
+  static_cast<nsTableFrame*>(mFrame)->
+    CreateWebRenderCommandsForBCBorders(aBuilder,
+                                        aSc,
+                                        GetPaintRect(),
+                                        ToReferenceFrame());
   return true;
 }
 
 /* static */ void
 nsTableFrame::GenericTraversal(nsDisplayListBuilder* aBuilder, nsFrame* aFrame,
                                const nsDisplayListSet& aLists)
 {
   // This is similar to what nsContainerFrame::BuildDisplayListForNonBlockChildren
@@ -6492,24 +6492,37 @@ nsTableFrame::CalcBCBorders()
 }
 
 class BCPaintBorderIterator;
 
 struct BCBorderParameters
 {
   uint8_t mBorderStyle;
   nscolor mBorderColor;
-  nscolor mBGColor;
   nsRect mBorderRect;
   int32_t mAppUnitsPerDevPixel;
   mozilla::Side mStartBevelSide;
   nscoord mStartBevelOffset;
   mozilla::Side mEndBevelSide;
   nscoord mEndBevelOffset;
   bool mBackfaceIsVisible;
+
+  bool NeedToBevel() const
+  {
+    if (!mStartBevelOffset && !mEndBevelOffset) {
+      return false;
+    }
+
+    if (mBorderStyle == NS_STYLE_BORDER_STYLE_DASHED ||
+        mBorderStyle == NS_STYLE_BORDER_STYLE_DOTTED) {
+      return false;
+    }
+
+    return true;
+  }
 };
 
 struct BCBlockDirSeg
 {
   BCBlockDirSeg();
 
   void Start(BCPaintBorderIterator& aIter,
              BCBorderOwner          aBorderOwner,
@@ -6524,18 +6537,17 @@ struct BCBlockDirSeg
                                                   BCPixelSize aInlineSegBSize);
   void Paint(BCPaintBorderIterator& aIter,
              DrawTarget&            aDrawTarget,
              BCPixelSize            aInlineSegBSize);
   void CreateWebRenderCommands(BCPaintBorderIterator& aIter,
                                BCPixelSize aInlineSegBSize,
                                wr::DisplayListBuilder& aBuilder,
                                const layers::StackingContextHelper& aSc,
-                               const nsPoint& aPt,
-                               Maybe<BCBorderParameters>* aBevelBorders);
+                               const nsPoint& aPt);
   void AdvanceOffsetB();
   void IncludeCurrentBorder(BCPaintBorderIterator& aIter);
 
 
   union {
     nsTableColFrame*  mCol;
     int32_t           mColWidth;
   };
@@ -6579,18 +6591,17 @@ struct BCInlineDirSeg
                      BCPixelSize            aIStartSegISize);
   void AdvanceOffsetI();
   void IncludeCurrentBorder(BCPaintBorderIterator& aIter);
   Maybe<BCBorderParameters> BuildBorderParameters(BCPaintBorderIterator& aIter);
   void Paint(BCPaintBorderIterator& aIter, DrawTarget& aDrawTarget);
   void CreateWebRenderCommands(BCPaintBorderIterator& aIter,
                                wr::DisplayListBuilder& aBuilder,
                                const layers::StackingContextHelper& aSc,
-                               const nsPoint& aPt,
-                               Maybe<BCBorderParameters>* aBevelBorders);
+                               const nsPoint& aPt);
 
   nscoord            mOffsetI;       // i-offset with respect to the table edge
   nscoord            mOffsetB;       // b-offset with respect to the table edge
   nscoord            mLength;        // inline-dir length including corners
   BCPixelSize        mWidth;         // border thickness in pixels
   nscoord            mIStartBevelOffset; // how much to bevel at the iStart
   LogicalSide        mIStartBevelSide;   // direction to bevel at the iStart
   bool               mIsIEndBevel;       // should we bevel at the iEnd end
@@ -6627,34 +6638,32 @@ struct BCCreateWebRenderCommandsData
     , mSc(aSc)
     , mOffsetToReferenceFrame(aOffsetToReferenceFrame)
   {
   }
 
   wr::DisplayListBuilder& mBuilder;
   const layers::StackingContextHelper& mSc;
   const nsPoint& mOffsetToReferenceFrame;
-  Maybe<BCBorderParameters> mBevelBorders[4];
 };
 
 struct BCPaintBorderAction
 {
   explicit BCPaintBorderAction(DrawTarget& aDrawTarget)
     : mMode(Mode::PAINT)
     , mPaintData(aDrawTarget)
   {
   }
 
   BCPaintBorderAction(wr::DisplayListBuilder& aBuilder,
                       const layers::StackingContextHelper& aSc,
                       const nsPoint& aOffsetToReferenceFrame)
     : mMode(Mode::CREATE_WEBRENDER_COMMANDS)
     , mCreateWebRenderCommandsData(aBuilder, aSc, aOffsetToReferenceFrame)
   {
-    mMode = Mode::CREATE_WEBRENDER_COMMANDS;
   }
 
   ~BCPaintBorderAction()
   {
     // mCreateWebRenderCommandsData is in a union which means the destructor
     // wouldn't be called when BCPaintBorderAction get destroyed. So call the
     // destructor here explicitly.
     if (mMode == Mode::CREATE_WEBRENDER_COMMANDS) {
@@ -6702,17 +6711,16 @@ public:
   void StoreColumnWidth(int32_t aIndex);
   bool BlockDirSegmentOwnsCorner();
 
   nsTableFrame*         mTable;
   nsTableFrame*         mTableFirstInFlow;
   nsTableCellMap*       mTableCellMap;
   nsCellMap*            mCellMap;
   WritingMode           mTableWM;
-  nscolor               mTableBgColor;
   nsTableFrame::RowGroupArray mRowGroups;
 
   nsTableRowGroupFrame* mPrevRg;
   nsTableRowGroupFrame* mRg;
   bool                  mIsRepeatedHeader;
   bool                  mIsRepeatedFooter;
   nsTableRowGroupFrame* mStartRg; // first row group in the damagearea
   int32_t               mRgIndex; // current row group index in the
@@ -6842,20 +6850,16 @@ BCPaintBorderIterator::BCPaintBorderIter
     mTable->GetPrevInFlow() ? 0 : childAreaOffset.BStart(mTableWM);
   mNumTableRows  = mTable->GetRowCount();
   mNumTableCols  = mTable->GetColCount();
 
   // Get the ordered row groups
   mTable->OrderRowGroups(mRowGroups);
   // initialize to a non existing index
   mRepeatedHeaderRowIndex = -99;
-
-  nsIFrame* bgFrame =
-    nsCSSRendering::FindNonTransparentBackgroundFrame(aTable);
-  mTableBgColor = bgFrame->StyleBackground()->BackgroundColor(bgFrame);
 }
 
 bool
 BCPaintBorderIterator::SetDamageArea(const nsRect& aDirtyRect)
 {
   nsSize containerSize = mTable->GetSize();
   LogicalRect dirtyRect(mTableWM, aDirtyRect, containerSize);
   uint32_t startRowIndex, endRowIndex, startColIndex, endColIndex;
@@ -7369,17 +7373,16 @@ BCBlockDirSeg::BuildBorderParameters(BCP
   LogicalSide side =
     aIter.IsDamageAreaIEndMost() ? eLogicalSideIEnd : eLogicalSideIStart;
   int32_t relColIndex = aIter.GetRelativeColIndex();
   nsTableColFrame* col           = mCol; if (!col) ABORT1(Nothing());
   nsTableCellFrame* cell         = mFirstCell; // ???
   nsIFrame* owner = nullptr;
   result.mBorderStyle = NS_STYLE_BORDER_STYLE_SOLID;
   result.mBorderColor = 0xFFFFFFFF;
-  result.mBGColor = aIter.mTableBgColor;
   result.mBackfaceIsVisible = true;
 
   // All the tables frames have the same presContext, so we just use any one
   // that exists here:
   nsPresContext* presContext = aIter.mTable->PresContext();
   result.mAppUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
 
   switch (mOwner) {
@@ -7488,88 +7491,224 @@ BCBlockDirSeg::Paint(BCPaintBorderIterat
                      BCPixelSize            aInlineSegBSize)
 {
   Maybe<BCBorderParameters> param = BuildBorderParameters(aIter, aInlineSegBSize);
   if (param.isNothing()) {
     return;
   }
 
   nsCSSRendering::DrawTableBorderSegment(aDrawTarget, param->mBorderStyle, param->mBorderColor,
-                                         param->mBGColor, param->mBorderRect,
+                                         param->mBorderRect,
                                          param->mAppUnitsPerDevPixel,
                                          param->mStartBevelSide, param->mStartBevelOffset,
                                          param->mEndBevelSide, param->mEndBevelOffset);
 }
 
+// Pushes a border bevel triangle and substracts the relevant rectangle from
+// aRect, which, after all the bevels, will end up being a solid segment rect.
+static void
+AdjustAndPushBevel(wr::DisplayListBuilder& aBuilder,
+                   wr::LayoutRect& aRect,
+                   nscolor aColor,
+                   const nsCSSRendering::Bevel& aBevel,
+                   int32_t aAppUnitsPerDevPixel,
+                   bool aBackfaceIsVisible,
+                   bool aIsStart)
+{
+  if (!aBevel.mOffset) {
+    return;
+  }
+
+  const auto kTransparent = wr::ToColorF(gfx::Color(0., 0., 0., 0.));
+  const bool horizontal =
+    aBevel.mSide == eSideTop || aBevel.mSide == eSideBottom;
+
+  // Crappy CSS triangle as known by every web developer ever :)
+  Float offset = NSAppUnitsToFloatPixels(aBevel.mOffset, aAppUnitsPerDevPixel);
+  wr::LayoutRect bevelRect = aRect;
+  wr::BorderSide bevelBorder[4];
+  NS_FOR_CSS_SIDES(i) {
+    bevelBorder[i] = wr::ToBorderSide(ToDeviceColor(aColor), NS_STYLE_BORDER_STYLE_SOLID);
+  }
+
+  // We're creating a half-transparent triangle using the border primitive.
+  //
+  // Classic web-dev trick, with a gotcha: we use a single corner to avoid
+  // seams and rounding errors.
+  //
+  // Classic web-dev trick :P
+  auto borderWidths = wr::ToBorderWidths(0, 0, 0, 0);
+  bevelBorder[aBevel.mSide].color = kTransparent;
+  if (aIsStart) {
+    if (horizontal) {
+      bevelBorder[eSideLeft].color = kTransparent;
+      borderWidths.left = offset;
+    } else {
+      bevelBorder[eSideTop].color = kTransparent;
+      borderWidths.top = offset;
+    }
+  } else {
+    if (horizontal) {
+      bevelBorder[eSideRight].color = kTransparent;
+      borderWidths.right = offset;
+    } else {
+      bevelBorder[eSideBottom].color = kTransparent;
+      borderWidths.bottom = offset;
+    }
+  }
+
+  if (horizontal) {
+    if (aIsStart) {
+      aRect.origin.x += offset;
+    } else {
+      bevelRect.origin.x += aRect.size.width - offset;
+    }
+    aRect.size.width -= offset;
+    bevelRect.size.height = aRect.size.height;
+    bevelRect.size.width = offset;
+    if (aBevel.mSide == eSideTop) {
+      borderWidths.bottom = aRect.size.height;
+    } else {
+      borderWidths.top = aRect.size.height;
+    }
+  } else {
+    if (aIsStart) {
+      aRect.origin.y += offset;
+    } else {
+      bevelRect.origin.y += aRect.size.height - offset;
+    }
+    aRect.size.height -= offset;
+    bevelRect.size.width = aRect.size.width;
+    bevelRect.size.height = offset;
+    if (aBevel.mSide == eSideLeft) {
+      borderWidths.right = aRect.size.width;
+    } else {
+      borderWidths.left = aRect.size.width;
+    }
+  }
+
+  Range<const wr::BorderSide> wrsides(bevelBorder, 4);
+  // It's important to _not_ anti-alias the bevel, because otherwise we wouldn't
+  // be able bevel to sides of the same color without bleeding in the middle.
+  aBuilder.PushBorder(bevelRect,
+                      bevelRect,
+                      aBackfaceIsVisible,
+                      borderWidths,
+                      wrsides,
+                      wr::EmptyBorderRadius(),
+                      wr::AntialiasBorder::No);
+}
+
+static void
+CreateWRCommandsForBeveledBorder(const BCBorderParameters& aBorderParams,
+                                 wr::DisplayListBuilder& aBuilder,
+                                 const layers::StackingContextHelper& aSc,
+                                 const nsPoint& aOffset)
+{
+  MOZ_ASSERT(aBorderParams.NeedToBevel());
+
+  AutoTArray<nsCSSRendering::SolidBeveledBorderSegment, 3> segments;
+  nsCSSRendering::GetTableBorderSolidSegments(segments,
+                                              aBorderParams.mBorderStyle,
+                                              aBorderParams.mBorderColor,
+                                              aBorderParams.mBorderRect,
+                                              aBorderParams.mAppUnitsPerDevPixel,
+                                              aBorderParams.mStartBevelSide,
+                                              aBorderParams.mStartBevelOffset,
+                                              aBorderParams.mEndBevelSide,
+                                              aBorderParams.mEndBevelOffset);
+
+  for (const auto& segment : segments) {
+    auto rect = LayoutDeviceRect::FromUnknownRect(
+      NSRectToRect(segment.mRect + aOffset, aBorderParams.mAppUnitsPerDevPixel));
+    auto roundedRect = wr::ToRoundedLayoutRect(rect);
+    auto color = wr::ToColorF(ToDeviceColor(segment.mColor));
+
+    // Adjust for the start bevel if needed.
+    AdjustAndPushBevel(aBuilder,
+                       roundedRect,
+                       segment.mColor,
+                       segment.mStartBevel,
+                       aBorderParams.mAppUnitsPerDevPixel,
+                       aBorderParams.mBackfaceIsVisible,
+                       true);
+
+    AdjustAndPushBevel(aBuilder,
+                       roundedRect,
+                       segment.mColor,
+                       segment.mEndBevel,
+                       aBorderParams.mAppUnitsPerDevPixel,
+                       aBorderParams.mBackfaceIsVisible,
+                       false);
+
+    aBuilder.PushRect(roundedRect, roundedRect, aBorderParams.mBackfaceIsVisible, color);
+  }
+}
+
+static void
+CreateWRCommandsForBorderSegment(const BCBorderParameters& aBorderParams,
+                                 wr::DisplayListBuilder& aBuilder,
+                                 const layers::StackingContextHelper& aSc,
+                                 const nsPoint& aOffset)
+{
+  if (aBorderParams.NeedToBevel()) {
+    CreateWRCommandsForBeveledBorder(aBorderParams, aBuilder, aSc, aOffset);
+    return;
+  }
+
+  auto borderRect = LayoutDeviceRect::FromUnknownRect(
+      NSRectToRect(aBorderParams.mBorderRect + aOffset,
+                   aBorderParams.mAppUnitsPerDevPixel));
+
+  wr::LayoutRect roundedRect = wr::ToRoundedLayoutRect(borderRect);
+  wr::BorderSide wrSide[4];
+  NS_FOR_CSS_SIDES(i) {
+    wrSide[i] = wr::ToBorderSide(ToDeviceColor(aBorderParams.mBorderColor), NS_STYLE_BORDER_STYLE_NONE);
+  }
+  const bool horizontal = aBorderParams.mStartBevelSide == eSideTop ||
+                          aBorderParams.mStartBevelSide == eSideBottom;
+  auto borderWidth = horizontal ? roundedRect.size.height : roundedRect.size.width;
+
+  // All border style is set to none except left side. So setting the widths of
+  // each side to width of rect is fine.
+  auto borderWidths =
+    wr::ToBorderWidths(0, 0, 0, 0);
+
+  wrSide[horizontal ? eSideTop : eSideLeft] =
+    wr::ToBorderSide(ToDeviceColor(aBorderParams.mBorderColor),
+                     aBorderParams.mBorderStyle);
+
+  if (horizontal) {
+    borderWidths.top = borderWidth;
+  } else {
+    borderWidths.left = borderWidth;
+  }
+
+  Range<const wr::BorderSide> wrsides(wrSide, 4);
+  aBuilder.PushBorder(roundedRect,
+                      roundedRect,
+                      aBorderParams.mBackfaceIsVisible,
+                      borderWidths,
+                      wrsides,
+                      wr::EmptyBorderRadius());
+}
+
 void
 BCBlockDirSeg::CreateWebRenderCommands(BCPaintBorderIterator& aIter,
                                        BCPixelSize aInlineSegBSize,
                                        wr::DisplayListBuilder& aBuilder,
                                        const layers::StackingContextHelper& aSc,
-                                       const nsPoint& aOffset,
-                                       Maybe<BCBorderParameters>* aBevelBorders)
+                                       const nsPoint& aOffset)
 {
   Maybe<BCBorderParameters> param = BuildBorderParameters(aIter, aInlineSegBSize);
   if (param.isNothing()) {
     return;
   }
 
-  if (param->mStartBevelOffset != 0 || param->mEndBevelOffset != 0) {
-    // If both bevel offsets are non zero, the parameters of two bevels should
-    // be the same. So we choose start bevel side here.
-    mozilla::Side bevelSide = param->mStartBevelOffset != 0 ? param->mStartBevelSide : param->mEndBevelSide;
-
-    // The left border is going to be beveled on its right edge because that's
-    // the edge that intersects other borders (in this case the top and bottom borders).
-    // Correspondingly, if the bevel side is "right" that means we are operating on
-    // the left border, and so store the parameters for that entry in aBevelBorders.
-    // Same goes for the other directions.
-    switch (bevelSide) {
-      case eSideTop:
-        aBevelBorders[eSideBottom] = param;
-        break;
-      case eSideBottom:
-        aBevelBorders[eSideTop] = param;
-        break;
-      case eSideLeft:
-        aBevelBorders[eSideRight] = param;
-        break;
-      case eSideRight:
-        aBevelBorders[eSideLeft] = param;
-        break;
-    }
-
-    return;
-  }
-
-  LayoutDeviceRect borderRect = LayoutDeviceRect::FromUnknownRect(NSRectToRect(param->mBorderRect + aOffset,
-                                                                               param->mAppUnitsPerDevPixel));
-
-  wr::LayoutRect roundedRect = wr::ToRoundedLayoutRect(borderRect);
-  wr::BorderSide wrSide[4];
-  NS_FOR_CSS_SIDES(i) {
-    wrSide[i] = wr::ToBorderSide(ToDeviceColor(param->mBorderColor), NS_STYLE_BORDER_STYLE_NONE);
-  }
-  wrSide[eSideLeft] = wr::ToBorderSide(ToDeviceColor(param->mBorderColor), param->mBorderStyle);
-
-  wr::BorderRadius borderRadii = wr::EmptyBorderRadius();
-
-  // All border style is set to none except left side. So setting the widths of
-  // each side to width of rect is fine.
-  wr::LayoutSideOffsets borderWidths = wr::ToBorderWidths(roundedRect.size.width,
-                                                     roundedRect.size.width,
-                                                     roundedRect.size.width,
-                                                     roundedRect.size.width);
-  Range<const wr::BorderSide> wrsides(wrSide, 4);
-  aBuilder.PushBorder(roundedRect,
-                      roundedRect,
-                      param->mBackfaceIsVisible,
-                      borderWidths,
-                      wrsides,
-                      borderRadii);
+  CreateWRCommandsForBorderSegment(*param, aBuilder, aSc, aOffset);
 }
 
 /**
  * Advance the start point of a segment
  */
 void
 BCBlockDirSeg::AdvanceOffsetB()
 {
@@ -7683,17 +7822,16 @@ BCInlineDirSeg::BuildBorderParameters(BC
 
   // All the tables frames have the same presContext, so we just use any one
   // that exists here:
   nsPresContext* presContext = aIter.mTable->PresContext();
   result.mAppUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
 
   result.mBorderStyle = NS_STYLE_BORDER_STYLE_SOLID;
   result.mBorderColor = 0xFFFFFFFF;
-  result.mBGColor = aIter.mTableBgColor;
 
   switch (mOwner) {
     case eTableOwner:
       owner = aIter.mTable;
       break;
     case eAjaColGroupOwner:
       NS_ERROR("neighboring colgroups can never own an inline-dir border");
       MOZ_FALLTHROUGH;
@@ -7783,80 +7921,34 @@ void
 BCInlineDirSeg::Paint(BCPaintBorderIterator& aIter, DrawTarget& aDrawTarget)
 {
   Maybe<BCBorderParameters> param = BuildBorderParameters(aIter);
   if (param.isNothing()) {
     return;
   }
 
   nsCSSRendering::DrawTableBorderSegment(aDrawTarget, param->mBorderStyle, param->mBorderColor,
-                                         param->mBGColor, param->mBorderRect,
+                                         param->mBorderRect,
                                          param->mAppUnitsPerDevPixel,
                                          param->mStartBevelSide, param->mStartBevelOffset,
                                          param->mEndBevelSide, param->mEndBevelOffset);
 }
 
 void
 BCInlineDirSeg::CreateWebRenderCommands(BCPaintBorderIterator& aIter,
                                         wr::DisplayListBuilder& aBuilder,
                                         const layers::StackingContextHelper& aSc,
-                                        const nsPoint& aPt,
-                                        Maybe<BCBorderParameters>* aBevelBorders)
+                                        const nsPoint& aPt)
 {
   Maybe<BCBorderParameters> param = BuildBorderParameters(aIter);
   if (param.isNothing()) {
     return;
   }
 
-  if (param->mStartBevelOffset != 0 || param->mEndBevelOffset != 0) {
-    mozilla::Side bevelSide = param->mStartBevelOffset != 0 ? param->mStartBevelSide : param->mEndBevelSide;
-
-    // See detailed comment on equivalent code in BCBlockDirSeg::CreateWebRenderCommands.
-    switch (bevelSide) {
-      case eSideTop:
-        aBevelBorders[eSideBottom] = param;
-        break;
-      case eSideBottom:
-        aBevelBorders[eSideTop] = param;
-        break;
-      case eSideLeft:
-        aBevelBorders[eSideRight] = param;
-        break;
-      case eSideRight:
-        aBevelBorders[eSideLeft] = param;
-        break;
-    }
-
-    return;
-  }
-
-  LayoutDeviceRect borderRect = LayoutDeviceRect::FromUnknownRect(NSRectToRect(param->mBorderRect + aPt,
-                                                                               param->mAppUnitsPerDevPixel));
-  wr::LayoutRect roundedRect = wr::ToRoundedLayoutRect(borderRect);
-  wr::BorderSide wrSide[4];
-  NS_FOR_CSS_SIDES(i) {
-    wrSide[i] = wr::ToBorderSide(ToDeviceColor(param->mBorderColor), NS_STYLE_BORDER_STYLE_NONE);
-  }
-  wrSide[eSideTop] = wr::ToBorderSide(ToDeviceColor(param->mBorderColor), param->mBorderStyle);
-
-  wr::BorderRadius borderRadii = wr::EmptyBorderRadius();
-
-  // All border style is set to none except top side. So setting the widths of
-  // each side to height of rect is fine.
-  wr::LayoutSideOffsets borderWidths = wr::ToBorderWidths(roundedRect.size.height,
-                                                     roundedRect.size.height,
-                                                     roundedRect.size.height,
-                                                     roundedRect.size.height);
-  Range<const wr::BorderSide> wrsides(wrSide, 4);
-  aBuilder.PushBorder(roundedRect,
-                      roundedRect,
-                      param->mBackfaceIsVisible,
-                      borderWidths,
-                      wrsides,
-                      borderRadii);
+  CreateWRCommandsForBorderSegment(*param, aBuilder, aSc, aPt);
 }
 
 /**
  * Advance the start point of a segment
  */
 void
 BCInlineDirSeg::AdvanceOffsetI()
 {
@@ -7943,18 +8035,17 @@ BCPaintBorderIterator::AccumulateOrDoAct
       if (mInlineSeg.mWidth > 0) {
         if (aAction.mMode == BCPaintBorderAction::Mode::PAINT) {
           mInlineSeg.Paint(*this, aAction.mPaintData.mDrawTarget);
         } else {
           MOZ_ASSERT(aAction.mMode == BCPaintBorderAction::Mode::CREATE_WEBRENDER_COMMANDS);
           mInlineSeg.CreateWebRenderCommands(*this,
                                              aAction.mCreateWebRenderCommandsData.mBuilder,
                                              aAction.mCreateWebRenderCommandsData.mSc,
-                                             aAction.mCreateWebRenderCommandsData.mOffsetToReferenceFrame,
-                                             aAction.mCreateWebRenderCommandsData.mBevelBorders);
+                                             aAction.mCreateWebRenderCommandsData.mOffsetToReferenceFrame);
         }
       }
       mInlineSeg.AdvanceOffsetI();
     }
     mInlineSeg.Start(*this, borderOwner, iStartSegISize, bStartSegBSize);
   }
   mInlineSeg.IncludeCurrentBorder(*this);
   mBlockDirInfo[relColIndex].mWidth = iStartSegISize;
@@ -7996,18 +8087,17 @@ BCPaintBorderIterator::AccumulateOrDoAct
         if (aAction.mMode == BCPaintBorderAction::Mode::PAINT) {
           blockDirSeg.Paint(*this, aAction.mPaintData.mDrawTarget, inlineSegBSize);
         } else {
           MOZ_ASSERT(aAction.mMode == BCPaintBorderAction::Mode::CREATE_WEBRENDER_COMMANDS);
           blockDirSeg.CreateWebRenderCommands(*this,
                                               inlineSegBSize,
                                               aAction.mCreateWebRenderCommandsData.mBuilder,
                                               aAction.mCreateWebRenderCommandsData.mSc,
-                                              aAction.mCreateWebRenderCommandsData.mOffsetToReferenceFrame,
-                                              aAction.mCreateWebRenderCommandsData.mBevelBorders);
+                                              aAction.mCreateWebRenderCommandsData.mOffsetToReferenceFrame);
         }
       }
       blockDirSeg.AdvanceOffsetB();
     }
     blockDirSeg.Start(*this, borderOwner, blockSegISize, inlineSegBSize);
   }
   blockDirSeg.IncludeCurrentBorder(*this);
   mPrevInlineSegBSize = inlineSegBSize;
@@ -8078,64 +8168,16 @@ nsTableFrame::CreateWebRenderCommandsFor
                                                   const mozilla::layers::StackingContextHelper& aSc,
                                                   const nsRect& aVisibleRect,
                                                   const nsPoint& aOffsetToReferenceFrame)
 {
   BCPaintBorderAction action(aBuilder, aSc, aOffsetToReferenceFrame);
   // We always draw whole table border for webrender. Passing the visible rect
   // dirty rect.
   IterateBCBorders(action, aVisibleRect - aOffsetToReferenceFrame);
-
-  LayoutDeviceRect allBorderRect;
-  wr::BorderSide wrSide[4];
-  wr::LayoutSideOffsets wrWidths;
-  wr::BorderRadius borderRadii = wr::EmptyBorderRadius();
-  bool backfaceIsVisible = false;
-  NS_FOR_CSS_SIDES(side) {
-    auto param = action.mCreateWebRenderCommandsData.mBevelBorders[side];
-    LayoutDeviceRect borderRect;
-    nscolor borderColor = NS_RGBA(0, 0, 0, 255);
-    uint8_t borderStyle = NS_STYLE_BORDER_STYLE_NONE;
-    if (param.isSome()) {
-      borderRect = LayoutDeviceRect::FromUnknownRect(NSRectToRect(param->mBorderRect + aOffsetToReferenceFrame,
-                                                                  param->mAppUnitsPerDevPixel));
-      borderColor = param->mBorderColor;
-      borderStyle = param->mBorderStyle;
-      backfaceIsVisible |= param->mBackfaceIsVisible;
-    }
-
-    wr::LayoutRect roundedRect = wr::ToRoundedLayoutRect(borderRect);
-    allBorderRect = allBorderRect.Union(borderRect);
-    wrSide[side] = wr::ToBorderSide(ToDeviceColor(borderColor), borderStyle);
-    switch (side) {
-      case eSideTop:
-        wrWidths.top = roundedRect.size.height;
-        break;
-      case eSideBottom:
-        wrWidths.bottom = roundedRect.size.height;
-        break;
-      case eSideLeft:
-        wrWidths.left = roundedRect.size.width;
-        break;
-      case eSideRight:
-        wrWidths.right = roundedRect.size.width;
-        break;
-    }
-  }
-
-  if (!allBorderRect.IsEmpty()) {
-    Range<const wr::BorderSide> wrsides(wrSide, 4);
-    wr::LayoutRect allRoundedRect = wr::ToRoundedLayoutRect(allBorderRect);
-    aBuilder.PushBorder(allRoundedRect,
-                        allRoundedRect,
-                        backfaceIsVisible,
-                        wrWidths,
-                        wrsides,
-                        borderRadii);
-  }
 }
 
 bool
 nsTableFrame::RowHasSpanningCells(int32_t aRowIndex, int32_t aNumEffCols)
 {
   bool result = false;
   nsTableCellMap* cellMap = GetCellMap();
   MOZ_ASSERT (cellMap, "bad call, cellMap not yet allocated.");
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java
@@ -46,17 +46,17 @@ import android.support.annotation.NonNul
 import android.support.annotation.StringDef;
 import android.util.Base64;
 import android.util.Log;
 import android.view.Surface;
 import android.view.inputmethod.CursorAnchorInfo;
 import android.view.inputmethod.ExtractedText;
 import android.view.inputmethod.ExtractedTextRequest;
 
-public final class GeckoSession extends LayerSession
+public class GeckoSession extends LayerSession
         implements Parcelable {
     private static final String LOGTAG = "GeckoSession";
     private static final boolean DEBUG = false;
 
     // Type of changes given to onWindowChanged.
     // Window has been cleared due to the session being closed.
     private static final int WINDOW_CLOSE = 0;
     // Window has been set due to the session being opened.
--- a/testing/geckodriver/doc/Bugs.md
+++ b/testing/geckodriver/doc/Bugs.md
@@ -37,9 +37,10 @@ in the latest Firefox Nightly before you
 Once we are satisfied the issue raised is of sufficiently actionable
 character, we will continue with triaging it and file a bug where it
 is appropriate.  Bugs specific to geckodriver will be filed in the
 [`Testing :: geckodriver`] component in Bugzilla.
 
 [mailing list]: ./#communication
 [trace-level log]: TraceLogs.html
 [GitHub issue tracker]: https://github.com/mozilla/geckodriver/issues
+[ISSUE_TEMPLATE.md]: https://raw.githubusercontent.com/mozilla/geckodriver/master/ISSUE_TEMPLATE.md
 [`Testing :: geckodriver`]: https://bugzilla.mozilla.org/buglist.cgi?component=geckodriver
--- a/testing/mochitest/browser-test.js
+++ b/testing/mochitest/browser-test.js
@@ -14,26 +14,17 @@ ChromeUtils.import("resource://gre/modul
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 
 ChromeUtils.defineModuleGetter(this, "ContentSearch",
   "resource:///modules/ContentSearch.jsm");
 
 const SIMPLETEST_OVERRIDES =
   ["ok", "is", "isnot", "todo", "todo_is", "todo_isnot", "info", "expectAssertions", "requestCompleteLog"];
 
-// non-android is bootstrapped by marionette
-if (Services.appinfo.OS == "Android") {
-  window.addEventListener("load", function() {
-    window.addEventListener("MozAfterPaint", function() {
-      setTimeout(testInit, 0);
-    }, {once: true});
-  }, {once: true});
-} else {
-  setTimeout(testInit, 0);
-}
+setTimeout(testInit, 0);
 
 var TabDestroyObserver = {
   outstanding: new Set(),
   promiseResolver: null,
 
   init() {
     Services.obs.addObserver(this, "message-manager-close");
     Services.obs.addObserver(this, "message-manager-disconnect");
--- a/testing/mochitest/redirect.html
+++ b/testing/mochitest/redirect.html
@@ -16,25 +16,19 @@
       document.dispatchEvent(event);
     }
 
     function redirectToHarness() {
       redirect("chrome://mochikit/content/harness.xul");
     }
 
     function onLoad() {
-      // Wait for MozAfterPaint, since the listener in browser-test.js is not
-      // added until then.
-      window.addEventListener("MozAfterPaint", function() {
-        setTimeout(redirectToHarness, 0);
-
-        // In case the listener is not ready, re-try periodically
-        setInterval(redirectToHarness, 5000);
-      }, {once: true});
-
+      setTimeout(redirectToHarness, 0);
+      // In case the listener is not ready, re-try periodically
+      setInterval(redirectToHarness, 5000);
     }
   </script>
 </head>
 
 <body onload="onLoad();">
 redirecting...
 </body>
 </html>
--- a/testing/mozharness/mozharness/mozilla/testing/codecoverage.py
+++ b/testing/mozharness/mozharness/mozilla/testing/codecoverage.py
@@ -55,21 +55,30 @@ code_coverage_config_options = [
 
 
 class CodeCoverageMixin(SingleTestMixin):
     """
     Mixin for setting GCOV_PREFIX during test execution, packaging up
     the resulting .gcda files and uploading them to blobber.
     """
     gcov_dir = None
+    grcov_dir = None
+    grcov_bin = None
     jsvm_dir = None
     prefix = None
     per_test_reports = {}
 
     def __init__(self, **kwargs):
+        if mozinfo.os == 'linux' or mozinfo.os == 'mac':
+            self.grcov_bin = 'grcov'
+        elif mozinfo.os == 'win':
+            self.grcov_bin = 'grcov.exe'
+        else:
+            raise Exception('Unexpected OS: {}'.format(mozinfo.os))
+
         super(CodeCoverageMixin, self).__init__(**kwargs)
 
     @property
     def code_coverage_enabled(self):
         try:
             return bool(self.config.get('code_coverage'))
         except (AttributeError, KeyError, TypeError):
             return False
@@ -144,17 +153,17 @@ class CodeCoverageMixin(SingleTestMixin)
         self.java_coverage_output_dir = tempfile.mkdtemp()
 
     @PostScriptAction('download-and-extract')
     def setup_coverage_tools(self, action, success=None):
         if not self.code_coverage_enabled and not self.java_code_coverage_enabled:
             return
 
         self.grcov_dir = os.environ['MOZ_FETCHES_DIR']
-        if not os.path.isfile(os.path.join(self.grcov_dir, 'grcov')):
+        if not os.path.isfile(os.path.join(self.grcov_dir, self.grcov_bin)):
             self.fetch_content()
 
         if self.code_coverage_enabled:
             self._setup_cpp_js_coverage_tools()
 
         if self.java_code_coverage_enabled:
             self._setup_java_coverage_tools()
 
@@ -285,17 +294,17 @@ class CodeCoverageMixin(SingleTestMixin)
 
         from lcov_rewriter import LcovFileRewriter
         jsvm_files = [os.path.join(jsvm_dir, e) for e in os.listdir(jsvm_dir)]
         rewriter = LcovFileRewriter(os.path.join(self.grcov_dir, 'chrome-map.json'))
         rewriter.rewrite_files(jsvm_files, jsvm_output_file, '')
 
         # Run grcov on the zipped .gcno and .gcda files.
         grcov_command = [
-            os.path.join(self.grcov_dir, 'grcov'),
+            os.path.join(self.grcov_dir, self.grcov_bin),
             '-t', output_format,
             '-p', self.prefix,
             '--ignore-dir', 'gcc*',
             '--ignore-dir', 'vs2017_*',
             os.path.join(self.grcov_dir, 'target.code-coverage-gcno.zip'), gcov_dir
         ]
 
         if 'coveralls' in output_format:
@@ -517,17 +526,17 @@ class CodeCoverageMixin(SingleTestMixin)
         jacoco_command = ['java', '-jar', self.jacoco_jar, 'report'] + \
             report_files + \
             ['--classfiles', self.classfiles_dir,
              '--name', 'geckoview-junit',
              '--xml', os.path.join(xml_path, 'geckoview-junit.xml')]
         self.run_command(jacoco_command, halt_on_failure=True)
 
         grcov_command = [
-            os.path.join(self.grcov_dir, 'grcov'),
+            os.path.join(self.grcov_dir, self.grcov_bin),
             '-t', 'lcov',
             xml_path,
         ]
         tmp_output_file, _ = self.get_output_from_command(
             grcov_command,
             silent=True,
             save_tmpfiles=True,
             return_type='files',
--- a/toolkit/themes/osx/global/toolbarbutton.css
+++ b/toolkit/themes/osx/global/toolbarbutton.css
@@ -14,20 +14,17 @@ toolbarbutton {
 
 .toolbarbutton-text {
   margin: 0;
   padding: 0;
   text-align: center;
   vertical-align: middle;
 }
 
-toolbarbutton[disabled="true"],
-toolbarbutton[disabled="true"]:hover,
-toolbarbutton[disabled="true"]:hover:active,
-toolbarbutton[disabled="true"][open="true"] {
+toolbarbutton[disabled="true"] {
   color: -moz-mac-disabledtoolbartext;
 }
 
 /* ::::: toolbarbutton menu ::::: */
 
 .toolbarbutton-menu-dropmarker {
   -moz-appearance: none;
   list-style-image: url("chrome://global/skin/arrow/arrow-dn.png");
--- a/widget/windows/moz.build
+++ b/widget/windows/moz.build
@@ -141,16 +141,17 @@ if CONFIG['MOZ_ENABLE_SKIA_PDF']:
   LOCAL_INCLUDES += [
     '/gfx/skia/skia/include/config',
     '/gfx/skia/skia/include/core',
     '/modules/pdfium/pdfium/public',
   ]
   TEST_DIRS += ['gtest']
 
 LOCAL_INCLUDES += [
+    '/layout/forms',
     '/layout/generic',
     '/layout/xul',
     '/toolkit/xre',
     '/widget',
     '/widget/headless',
     '/xpcom/base',
 ]
 
--- a/widget/windows/nsNativeThemeWin.cpp
+++ b/widget/windows/nsNativeThemeWin.cpp
@@ -24,17 +24,17 @@
 #include "nsIFrame.h"
 #include "nsLayoutUtils.h"
 #include "nsNameSpaceManager.h"
 #include "nsLookAndFeel.h"
 #include "nsMenuFrame.h"
 #include "nsGkAtoms.h"
 #include <malloc.h>
 #include "nsWindow.h"
-#include "nsIComboboxControlFrame.h"
+#include "nsComboboxControlFrame.h"
 #include "prinrval.h"
 #include "WinUtils.h"
 
 #include "gfxPlatform.h"
 #include "gfxContext.h"
 #include "gfxWindowsPlatform.h"
 #include "gfxWindowsSurface.h"
 #include "gfxWindowsNativeDrawing.h"
@@ -1326,17 +1326,17 @@ nsNativeThemeWin::GetThemePartAndState(n
         aPart = CBP_DROPMARKER;
 
       if (IsDisabled(aFrame, eventState)) {
         aState = TS_DISABLED;
         return NS_OK;
       }
 
       if (isHTML) {
-        nsIComboboxControlFrame* ccf = do_QueryFrame(aFrame);
+        nsComboboxControlFrame* ccf = do_QueryFrame(aFrame);
         isOpen = (ccf && ccf->IsDroppedDownOrHasParentPopup());
       }
       else
         isOpen = IsOpenButton(aFrame);
 
       if (isHTML) {
         if (isOpen) {
           /* Hover is propagated, but we need to know whether we're hovering
@@ -3384,17 +3384,17 @@ nsresult nsNativeThemeWin::ClassicGetThe
       EventStates eventState = GetContentState(aFrame, aWidgetType);
 
       if (IsDisabled(aFrame, eventState)) {
         aState |= DFCS_INACTIVE;
         return NS_OK;
       }
 
       if (isHTML) {
-        nsIComboboxControlFrame* ccf = do_QueryFrame(aFrame);
+        nsComboboxControlFrame* ccf = do_QueryFrame(aFrame);
         isOpen = (ccf && ccf->IsDroppedDownOrHasParentPopup());
       }
       else
         isOpen = IsOpenButton(aFrame);
 
       // XXX Button should look active until the mouse is released, but
       //     without making it look active when the popup is clicked.
       if (isOpen && (isHTML || isMenulist))