Merge inbound to m-c a=merge
authorWes Kocher <wkocher@mozilla.com>
Wed, 13 May 2015 11:12:07 -0700
changeset 243665 324c3423deafbf1db194df3d6a2accbad2b67c42
parent 243603 33d19a206cad6996d060dedfc176dbb835595d05 (current diff)
parent 243664 1c91f5d39dea877e84bf75f38d7772c8893c1933 (diff)
child 243709 6b9fcd51adc138e2fdcb87e951effae8a0e7d022
push id28744
push userkwierso@gmail.com
push dateWed, 13 May 2015 18:12:16 +0000
treeherdermozilla-central@324c3423deaf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone41.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to m-c a=merge
browser/modules/test/xpcshell/test_DirectoryLinksProvider.js
xpcom/base/nsIDebug.idl
--- a/accessible/base/TextAttrs.cpp
+++ b/accessible/base/TextAttrs.cpp
@@ -13,16 +13,20 @@
 #include "gfxFont.h"
 #include "nsFontMetrics.h"
 #include "nsLayoutUtils.h"
 #include "nsContainerFrame.h"
 #include "HyperTextAccessible.h"
 #include "mozilla/AppUnits.h"
 #include "mozilla/gfx/2D.h"
 
+#if defined(MOZ_WIDGET_GTK)
+#include "gfxPlatformGtk.h" // xxx - for UseFcFontList
+#endif
+
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // TextAttrsMgr
 ////////////////////////////////////////////////////////////////////////////////
 
 void
@@ -623,31 +627,40 @@ TextAttrsMgr::FontWeightTextAttr::
   // When there doesn't exist a bold font in the family and so the rendering of
   // a non-bold font face is changed so that the user sees what looks like a
   // bold font, i.e. synthetic bolding is used. IsSyntheticBold method is only
   // needed on Mac, but it is "safe" to use on all platforms.  (For non-Mac
   // platforms it always return false.)
   if (font->IsSyntheticBold())
     return 700;
 
-#if defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_QT)
-  // On Linux, font->GetStyle()->weight will give the absolute weight requested
-  // of the font face. The Linux code uses the gfxFontEntry constructor which
-  // doesn't initialize the weight field.
-  return font->GetStyle()->weight;
-#else
-  // On Windows, font->GetStyle()->weight will give the same weight as
-  // fontEntry->Weight(), the weight of the first font in the font group, which
-  // may not be the weight of the font face used to render the characters.
-  // On Mac, font->GetStyle()->weight will just give the same number as
-  // getComputedStyle(). fontEntry->Weight() will give the weight of the font
-  // face used.
-  gfxFontEntry *fontEntry = font->GetFontEntry();
-  return fontEntry->Weight();
+  bool useFontEntryWeight = true;
+
+  // Under Linux, when gfxPangoFontGroup code is used,
+  // font->GetStyle()->weight will give the absolute weight requested of the
+  // font face. The gfxPangoFontGroup code uses the gfxFontEntry constructor
+  // which doesn't initialize the weight field.
+#if defined(MOZ_WIDGET_QT)
+  useFontEntryWeight = false;
+#elif defined(MOZ_WIDGET_GTK)
+  useFontEntryWeight = gfxPlatformGtk::UseFcFontList();
 #endif
+
+  if (useFontEntryWeight) {
+    // On Windows, font->GetStyle()->weight will give the same weight as
+    // fontEntry->Weight(), the weight of the first font in the font group,
+    // which may not be the weight of the font face used to render the
+    // characters. On Mac, font->GetStyle()->weight will just give the same
+    // number as getComputedStyle(). fontEntry->Weight() will give the weight
+    // of the font face used.
+    gfxFontEntry *fontEntry = font->GetFontEntry();
+    return fontEntry->Weight();
+  } else {
+    return font->GetStyle()->weight;
+  }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // AutoGeneratedTextAttr
 ////////////////////////////////////////////////////////////////////////////////
 TextAttrsMgr::AutoGeneratedTextAttr::
   AutoGeneratedTextAttr(HyperTextAccessible* aHyperTextAcc,
                         Accessible* aAccessible) :
--- a/accessible/windows/msaa/nsWinUtils.cpp
+++ b/accessible/windows/msaa/nsWinUtils.cpp
@@ -144,17 +144,20 @@ WindowProc(HWND hWnd, UINT msg, WPARAM w
 {
   // Note, this window's message handling should not invoke any call that
   // may result in a cross-process ipc call. Doing so may violate RPC
   // message semantics.
 
   switch (msg) {
     case WM_GETOBJECT:
     {
-      if (lParam == OBJID_CLIENT) {
+      // Do explicit casting to make it working on 64bit systems (see bug 649236
+      // for details).
+      int32_t objId = static_cast<DWORD>(lParam);
+      if (objId == OBJID_CLIENT) {
         DocAccessible* document =
           nsWinUtils::sHWNDCache->GetWeak(static_cast<void*>(hWnd));
         if (document) {
           IAccessible* msaaAccessible = nullptr;
           document->GetNativeInterface((void**)&msaaAccessible); // does an addref
           if (msaaAccessible) {
             LRESULT result = ::LresultFromObject(IID_IAccessible, wParam,
                                                  msaaAccessible); // does an addref
--- a/b2g/components/AboutServiceWorkers.jsm
+++ b/b2g/components/AboutServiceWorkers.jsm
@@ -1,15 +1,15 @@
 /* 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/. */
 
 "use strict"
 
-this.EXPORTED_SYMBOLS = [];
+this.EXPORTED_SYMBOLS = ["AboutServiceWorkers"];
 
 const { interfaces: Ci, utils: Cu } = Components;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "SystemAppProxy",
                                   "resource://gre/modules/SystemAppProxy.jsm");
@@ -42,126 +42,129 @@ function serializeServiceWorkerInfo(aSer
       return;
     }
     result[property] = aServiceWorkerInfo[property];
   });
 
   return result;
 }
 
-function sendResult(aId, aResult) {
-  SystemAppProxy._sendCustomEvent("mozAboutServiceWorkersChromeEvent", {
-    id: aId,
-    result: aResult
-  });
-}
-
-function sendError(aId, aError) {
-  SystemAppProxy._sendCustomEvent("mozAboutServiceWorkersChromeEvent", {
-    id: aId,
-    error: aError
-  });
-}
 
 this.AboutServiceWorkers = {
   get enabled() {
     if (this._enabled) {
       return this._enabled;
     }
     this._enabled = false;
     try {
       this._enabled = Services.prefs.getBoolPref("dom.serviceWorkers.enabled");
     } catch(e) {}
     return this._enabled;
   },
 
   init: function() {
     SystemAppProxy.addEventListener("mozAboutServiceWorkersContentEvent",
-                                   AboutServiceWorkers);
+                                    AboutServiceWorkers);
+  },
+
+  sendResult: function(aId, aResult) {
+    SystemAppProxy._sendCustomEvent("mozAboutServiceWorkersChromeEvent", {
+      id: aId,
+      result: aResult
+    });
+  },
+
+  sendError: function(aId, aError) {
+    SystemAppProxy._sendCustomEvent("mozAboutServiceWorkersChromeEvent", {
+      id: aId,
+      error: aError
+    });
   },
 
   handleEvent: function(aEvent) {
     let message = aEvent.detail;
 
     debug("Got content event " + JSON.stringify(message));
 
     if (!message.id || !message.name) {
       dump("Invalid event " + JSON.stringify(message) + "\n");
       return;
     }
 
+    let self = AboutServiceWorkers;
+
     switch(message.name) {
       case "init":
-        if (!this.enabled) {
-          sendResult({
+        if (!self.enabled) {
+          self.sendResult(message.id, {
             enabled: false,
             registrations: []
           });
           return;
         };
 
         let data = gServiceWorkerManager.getAllRegistrations();
         if (!data) {
-          sendError(message.id, "NoServiceWorkersRegistrations");
+          self.sendError(message.id, "NoServiceWorkersRegistrations");
           return;
         }
 
         let registrations = [];
 
         for (let i = 0; i < data.length; i++) {
           let info = data.queryElementAt(i, Ci.nsIServiceWorkerInfo);
           if (!info) {
             dump("AboutServiceWorkers: Invalid nsIServiceWorkerInfo " +
                  "interface.\n");
             continue;
           }
           registrations.push(serializeServiceWorkerInfo(info));
         }
 
-        sendResult(message.id, {
-          enabled: this.enabled,
+        self.sendResult(message.id, {
+          enabled: self.enabled,
           registrations: registrations
         });
         break;
 
       case "update":
         if (!message.scope) {
-          sendError(message.id, "MissingScope");
+          self.sendError(message.id, "MissingScope");
           return;
         }
-        gServiceWorkerManager.update(message.scope);
-        sendResult(message.id, true);
+        gServiceWorkerManager.softUpdate(message.scope);
+        self.sendResult(message.id, true);
         break;
 
       case "unregister":
         if (!message.principal ||
             !message.principal.origin ||
             !message.principal.appId) {
-          sendError("MissingPrincipal");
+          self.sendError("MissingPrincipal");
           return;
         }
 
         let principal = Services.scriptSecurityManager.getAppCodebasePrincipal(
           Services.io.newURI(message.principal.origin, null, null),
           message.principal.appId,
           message.principal.isInBrowser
         );
 
         if (!message.scope) {
-          sendError("MissingScope");
+          self.sendError("MissingScope");
           return;
         }
 
         let serviceWorkerUnregisterCallback = {
           unregisterSucceeded: function() {
-            sendResult(message.id, true);
+            self.sendResult(message.id, true);
           },
 
           unregisterFailed: function() {
-            sendError(message.id, "UnregisterError");
+            self.sendError(message.id, "UnregisterError");
           },
 
           QueryInterface: XPCOMUtils.generateQI([
             Ci.nsIServiceWorkerUnregisterCallback
           ])
         };
         gServiceWorkerManager.unregister(principal,
                                          serviceWorkerUnregisterCallback,
new file mode 100644
--- /dev/null
+++ b/b2g/components/test/unit/test_aboutserviceworkers.js
@@ -0,0 +1,139 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const {utils: Cu} = Components;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "AboutServiceWorkers",
+  "resource://gre/modules/AboutServiceWorkers.jsm");
+
+XPCOMUtils.defineLazyServiceGetter(this, "gServiceWorkerManager",
+                                   "@mozilla.org/serviceworkers/manager;1",
+                                   "nsIServiceWorkerManager");
+
+const CHROME_MSG = "mozAboutServiceWorkersChromeEvent";
+
+const ORIGINAL_SENDRESULT = AboutServiceWorkers.sendResult;
+const ORIGINAL_SENDERROR = AboutServiceWorkers.sendError;
+
+do_get_profile();
+
+let mockSendResult = (aId, aResult) => {
+  let msg = {
+    id: aId,
+    result: aResult
+  };
+  Services.obs.notifyObservers({wrappedJSObject: msg}, CHROME_MSG, null);
+};
+
+let mockSendError = (aId, aError) => {
+  let msg = {
+    id: aId,
+    result: aError
+  };
+  Services.obs.notifyObservers({wrappedJSObject: msg}, CHROME_MSG, null);
+};
+
+function attachMocks() {
+  AboutServiceWorkers.sendResult = mockSendResult;
+  AboutServiceWorkers.sendError = mockSendError;
+}
+
+function restoreMocks() {
+  AboutServiceWorkers.sendResult = ORIGINAL_SENDRESULT;
+  AboutServiceWorkers.sendError = ORIGINAL_SENDERROR;
+}
+
+do_register_cleanup(restoreMocks);
+
+function run_test() {
+  run_next_test();
+}
+
+/**
+ * "init" tests
+ */
+[
+// Pref disabled, no registrations
+{
+  prefEnabled: false,
+  expectedMessage: {
+    id: Date.now(),
+    result: {
+      enabled: false,
+      registrations: []
+    }
+  }
+},
+// Pref enabled, no registrations
+{
+  prefEnabled: true,
+  expectedMessage: {
+    id: Date.now(),
+    result: {
+      enabled: true,
+      registrations: []
+    }
+  }
+}].forEach(test => {
+  add_test(function() {
+    Services.prefs.setBoolPref("dom.serviceWorkers.enabled", test.prefEnabled);
+
+    let id = test.expectedMessage.id;
+
+    function onMessage(subject, topic, data) {
+      let message = subject.wrappedJSObject;
+      let expected = test.expectedMessage;
+
+      do_check_true(message.id, "Message should have id");
+      do_check_eq(message.id, test.expectedMessage.id,
+                  "Id should be the expected one");
+      do_check_eq(message.result.enabled, expected.result.enabled,
+                  "Pref should be disabled");
+      do_check_true(message.result.registrations, "Registrations should exist");
+      do_check_eq(message.result.registrations.length,
+                  expected.result.registrations.length,
+                  "Registrations length should be the expected one");
+
+      Services.obs.removeObserver(onMessage, CHROME_MSG);
+
+      run_next_test();
+    }
+
+    Services.obs.addObserver(onMessage, CHROME_MSG, false);
+
+    attachMocks();
+
+    AboutServiceWorkers.handleEvent({ detail: {
+      id: id,
+      name: "init"
+    }});
+  });
+});
+
+/**
+ * ServiceWorkerManager tests.
+ */
+
+// We cannot register a sw via ServiceWorkerManager cause chrome
+// registrations are not allowed.
+// All we can do for now is to test the interface of the swm.
+add_test(function test_swm() {
+  do_check_true(gServiceWorkerManager, "SWM exists");
+  do_check_true(gServiceWorkerManager.getAllRegistrations,
+                "SWM.getAllRegistrations exists");
+  do_check_true(typeof gServiceWorkerManager.getAllRegistrations == "function",
+                "SWM.getAllRegistrations is a function");
+  do_check_true(gServiceWorkerManager.softUpdate, "SWM.softUpdate exists");
+  do_check_true(typeof gServiceWorkerManager.softUpdate == "function",
+                "SWM.softUpdate is a function");
+  do_check_true(gServiceWorkerManager.unregister, "SWM.unregister exists");
+  do_check_true(typeof gServiceWorkerManager.unregister == "function",
+                "SWM.unregister exists");
+
+  run_next_test();
+});
--- a/b2g/components/test/unit/xpcshell.ini
+++ b/b2g/components/test/unit/xpcshell.ini
@@ -23,8 +23,10 @@ skip-if = toolkit != "gonk"
 
 [test_logparser.js]
 
 [test_logshake.js]
 
 [test_logshake_gonk.js]
 # only run on b2g builds due to requiring b2g-specific log files to exist
 skip-if = (toolkit != "gonk")
+
+[test_aboutserviceworkers.js]
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -3094,21 +3094,22 @@
               if (!needSpinner && this.spinnerTab) {
                 this.spinnerHidden();
                 this.tabbrowser.removeAttribute("pendingpaint");
                 this.spinnerTab.linkedBrowser.removeAttribute("pendingpaint");
                 this.spinnerTab = null;
               } else if (needSpinner && this.spinnerTab !== showTab) {
                 if (this.spinnerTab) {
                   this.spinnerTab.linkedBrowser.removeAttribute("pendingpaint");
+                } else {
+                  this.spinnerDisplayed();
                 }
                 this.spinnerTab = showTab;
                 this.tabbrowser.setAttribute("pendingpaint", "true");
                 this.spinnerTab.linkedBrowser.setAttribute("pendingpaint", "true");
-                this.spinnerDisplayed();
               }
 
               // Switch to the tab we've decided to make visible.
               if (this.visibleTab !== showTab) {
                 this.visibleTab = showTab;
 
                 this.maybeVisibleTabs.add(showTab);
 
@@ -3166,16 +3167,17 @@
                   this.tabState.delete(tab);
                 }
               }
 
               if (this.lastVisibleTab && !this.lastVisibleTab.linkedBrowser) {
                 this.lastVisibleTab = null;
               }
               if (this.spinnerTab && !this.spinnerTab.linkedBrowser) {
+                this.spinnerHidden();
                 this.spinnerTab = null;
               }
               if (this.loadingTab && !this.loadingTab.linkedBrowser) {
                 this.loadingTab = null;
                 clearTimeout(this.loadTimer);
                 this.loadTimer = null;
               }
             },
@@ -3349,47 +3351,46 @@
             },
 
             /*
              * Telemetry and Profiler related helpers for recording tab switch
              * timing.
              */
 
             startTabSwitch: function () {
+              TelemetryStopwatch.cancel("FX_TAB_SWITCH_TOTAL_E10S_MS", window);
               TelemetryStopwatch.start("FX_TAB_SWITCH_TOTAL_E10S_MS", window);
               this.addMarker("AsyncTabSwitch:Start");
             },
 
             finishTabSwitch: function () {
               if (this.requestedTab && this.getTabState(this.requestedTab) == this.STATE_LOADED) {
                 let time = TelemetryStopwatch.timeElapsed("FX_TAB_SWITCH_TOTAL_E10S_MS", window);
                 if (time != -1) {
                   TelemetryStopwatch.finish("FX_TAB_SWITCH_TOTAL_E10S_MS", window);
                   this.log("DEBUG: tab switch time = " + time);
                   this.addMarker("AsyncTabSwitch:Finish");
                 }
               }
             },
 
             spinnerDisplayed: function () {
-              if (this.spinnerTab) {
-                TelemetryStopwatch.start("FX_TAB_SWITCH_SPINNER_VISIBLE_MS", window);
-                this.addMarker("AsyncTabSwitch:SpinnerShown");
-              }
+              this.assert(!this.spinnerTab);
+              TelemetryStopwatch.start("FX_TAB_SWITCH_SPINNER_VISIBLE_MS", window);
+              this.addMarker("AsyncTabSwitch:SpinnerShown");
             },
 
             spinnerHidden: function () {
-              if (this.spinnerTab) {
-                this.log("DEBUG: spinner time = " +
-                         TelemetryStopwatch.timeElapsed("FX_TAB_SWITCH_SPINNER_VISIBLE_MS", window));
-                TelemetryStopwatch.finish("FX_TAB_SWITCH_SPINNER_VISIBLE_MS", window);
-                this.addMarker("AsyncTabSwitch:SpinnerHidden");
-                // we do not get a onPaint after displaying the spinner
-                this.finishTabSwitch();
-              }
+              this.assert(this.spinnerTab);
+              this.log("DEBUG: spinner time = " +
+                       TelemetryStopwatch.timeElapsed("FX_TAB_SWITCH_SPINNER_VISIBLE_MS", window));
+              TelemetryStopwatch.finish("FX_TAB_SWITCH_SPINNER_VISIBLE_MS", window);
+              this.addMarker("AsyncTabSwitch:SpinnerHidden");
+              // we do not get a onPaint after displaying the spinner
+              this.finishTabSwitch();
             },
 
             addMarker: function(marker) {
               if (Services.profiler) {
                 Services.profiler.AddMarker(marker);
               }
             },
 
--- a/browser/components/customizableui/test/browser_1003588_no_specials_in_panel.js
+++ b/browser/components/customizableui/test/browser_1003588_no_specials_in_panel.js
@@ -1,13 +1,28 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
+function simulateItemDragAndEnd(aToDrag, aTarget) {
+  var ds = Components.classes["@mozilla.org/widget/dragservice;1"].
+           getService(Components.interfaces.nsIDragService);
+
+  ds.startDragSession();
+  try {
+    var [result, dataTransfer] = ChromeUtils.synthesizeDragOver(aToDrag.parentNode, aTarget);
+    ChromeUtils.synthesizeDropAfterDragOver(result, dataTransfer, aTarget);
+    // Send dragend to move dragging item back to initial place.
+    EventUtils.sendDragEvent({ type: "dragend", dataTransfer: dataTransfer },
+                             aToDrag.parentNode);
+  } finally {
+    ds.endDragSession(true);
+  }
+}
 
 add_task(function* checkNoAddingToPanel() {
   let area = CustomizableUI.AREA_PANEL;
   let previousPlacements = getAreaWidgetIds(area);
   CustomizableUI.addWidgetToArea("separator", area);
   CustomizableUI.addWidgetToArea("spring", area);
   CustomizableUI.addWidgetToArea("spacer", area);
   assertAreaPlacements(area, previousPlacements);
@@ -61,17 +76,17 @@ add_task(function* checkDragging() {
     if (CustomizableUI.isSpecialWidget(id)) {
       elementsToMove.push(id);
     }
   }
   is(elementsToMove.length, 3, "Should have 3 elements to try and drag.");
 
   yield startCustomizing();
   for (let id of elementsToMove) {
-    simulateItemDrag(document.getElementById(id), PanelUI.contents);
+    simulateItemDragAndEnd(document.getElementById(id), PanelUI.contents);
   }
 
   assertAreaPlacements(startArea, placementsWithSpecials);
   assertAreaPlacements(targetArea, startingTargetPlacements);
 
   for (let id of elementsToMove) {
     simulateItemDrag(document.getElementById(id), gCustomizeMode.visiblePalette);
   }
--- a/browser/components/customizableui/test/browser_962069_drag_to_overflow_chevron.js
+++ b/browser/components/customizableui/test/browser_962069_drag_to_overflow_chevron.js
@@ -21,18 +21,30 @@ add_task(function*() {
   let panelShownPromise = promisePanelElementShown(window, widgetOverflowPanel);
   let identityBox = document.getElementById("identity-box");
   let overflowChevron = document.getElementById("nav-bar-overflow-button");
 
   // Listen for hiding immediately so we don't miss the event because of the
   // async-ness of the 'shown' yield...
   let panelHiddenPromise = promisePanelElementHidden(window, widgetOverflowPanel);
 
-  ChromeUtils.synthesizeDrop(identityBox, overflowChevron, [], null);
-  yield panelShownPromise;
+  var ds = Components.classes["@mozilla.org/widget/dragservice;1"].
+           getService(Components.interfaces.nsIDragService);
+
+  ds.startDragSession();
+  try {
+    var [result, dataTransfer] = ChromeUtils.synthesizeDragOver(identityBox, overflowChevron);
+
+    // Wait for showing panel before ending drag session.
+    yield panelShownPromise;
+
+    ChromeUtils.synthesizeDropAfterDragOver(result, dataTransfer, overflowChevron);
+  } finally {
+    ds.endDragSession(true);
+  }
 
   info("Overflow panel is shown.");
 
   widgetOverflowPanel.hidePopup();
   yield panelHiddenPromise;
 });
 
 add_task(function*() {
--- a/browser/components/customizableui/test/browser_978084_dragEnd_after_move.js
+++ b/browser/components/customizableui/test/browser_978084_dragEnd_after_move.js
@@ -16,29 +16,31 @@ add_task(function() {
   draggedItem.setAttribute("label", "Test");
   draggedItem.setAttribute("removable", "true");
   let navbar = document.getElementById("nav-bar");
   navbar.customizationTarget.appendChild(draggedItem);
   yield startCustomizing();
   simulateItemDrag(draggedItem, gCustomizeMode.visiblePalette);
   is(document.documentElement.hasAttribute("customizing-movingItem"), false,
      "Make sure customizing-movingItem is removed after dragging to the palette");
+  yield endCustomizing();
 });
 
 // Drop on a customization target itself
 add_task(function() {
   draggedItem = document.createElement("toolbarbutton");
   draggedItem.id = "test-dragEnd-after-move2";
   draggedItem.setAttribute("label", "Test");
   draggedItem.setAttribute("removable", "true");
   let dest = createToolbarWithPlacements("test-dragEnd");
   let navbar = document.getElementById("nav-bar");
   navbar.customizationTarget.appendChild(draggedItem);
   yield startCustomizing();
   simulateItemDrag(draggedItem, dest.customizationTarget);
   is(document.documentElement.hasAttribute("customizing-movingItem"), false,
      "Make sure customizing-movingItem is removed");
+  yield endCustomizing();
 });
 
 add_task(function asyncCleanup() {
   yield endCustomizing();
   yield resetCustomization();
 });
--- a/browser/components/customizableui/test/browser_995164_registerArea_during_customize_mode.js
+++ b/browser/components/customizableui/test/browser_995164_registerArea_during_customize_mode.js
@@ -13,16 +13,17 @@ add_task(function*() {
   let syncButton = document.getElementById("sync-button");
   ok(syncButton, "Sync button should exist.");
   is(syncButton.parentNode.localName, "toolbarpaletteitem", "Sync button's parent node should be a wrapper.");
 
   simulateItemDrag(syncButton, gNavToolbox.palette);
   ok(!CustomizableUI.getPlacementOfWidget("sync-button"), "Button moved to the palette");
   ok(gNavToolbox.palette.querySelector("#sync-button"), "Sync button really is in palette.");
 
+  syncButton.scrollIntoView();
   simulateItemDrag(syncButton, toolbar);
   ok(CustomizableUI.getPlacementOfWidget("sync-button"), "Button moved out of palette");
   is(CustomizableUI.getPlacementOfWidget("sync-button").area, TOOLBARID, "Button's back on toolbar");
   ok(toolbar.querySelector("#sync-button"), "Sync button really is on toolbar.");
 
   yield endCustomizing();
   isnot(syncButton.parentNode.localName, "toolbarpaletteitem", "Sync button's parent node should not be a wrapper outside customize mode.");
   yield startCustomizing();
@@ -44,16 +45,17 @@ add_task(function*() {
   ok(CustomizableUI.inDefaultState, "Now that the toolbar is no longer registered, should be in default state.");
   ok(!gCustomizeMode.areas.has(toolbar), "Toolbar shouldn't be known to customize mode.");
 
   CustomizableUI.registerArea(TOOLBARID, {legacy: true, defaultPlacements: []});
   CustomizableUI.registerToolbarNode(toolbar, []);
   ok(!CustomizableUI.inDefaultState, "Now that the toolbar is registered again, should no longer be in default state.");
   ok(gCustomizeMode.areas.has(toolbar), "Toolbar should be known to customize mode again.");
 
+  syncButton.scrollIntoView();
   simulateItemDrag(syncButton, toolbar);
   ok(CustomizableUI.getPlacementOfWidget("sync-button"), "Button moved out of palette");
   is(CustomizableUI.getPlacementOfWidget("sync-button").area, TOOLBARID, "Button's back on toolbar");
   ok(toolbar.querySelector("#sync-button"), "Sync button really is on toolbar.");
 
   let otherWin = yield openAndLoadWindow({}, true);
   let otherTB = otherWin.document.createElementNS(kNSXUL, "toolbar");
   otherTB.id = TOOLBARID;
@@ -73,16 +75,17 @@ add_task(function*() {
 
   ok(otherTB.querySelector("#sync-button"), "Sync button is on other toolbar, too.");
 
   simulateItemDrag(syncButton, gNavToolbox.palette);
   ok(!CustomizableUI.getPlacementOfWidget("sync-button"), "Button moved to the palette");
   ok(gNavToolbox.palette.querySelector("#sync-button"), "Sync button really is in palette.");
   ok(!otherTB.querySelector("#sync-button"), "Sync button is in palette in other window, too.");
 
+  syncButton.scrollIntoView();
   simulateItemDrag(syncButton, toolbar);
   ok(CustomizableUI.getPlacementOfWidget("sync-button"), "Button moved out of palette");
   is(CustomizableUI.getPlacementOfWidget("sync-button").area, TOOLBARID, "Button's back on toolbar");
   ok(toolbar.querySelector("#sync-button"), "Sync button really is on toolbar.");
   ok(otherTB.querySelector("#sync-button"), "Sync button is on other toolbar, too.");
 
   let wasInformedCorrectlyOfAreaDisappearing = false;
   //XXXgijs So we could be using promiseWindowClosed here. However, after
--- a/browser/components/customizableui/test/head.js
+++ b/browser/components/customizableui/test/head.js
@@ -168,22 +168,18 @@ function todoAssertAreaPlacements(areaId
   todo(isPassing, "The area placements for " + areaId +
                   " should equal the expected placements.");
 }
 
 function getAreaWidgetIds(areaId) {
   return CustomizableUI.getWidgetIdsInArea(areaId);
 }
 
-function simulateItemDrag(toDrag, target) {
-  let docId = toDrag.ownerDocument.documentElement.id;
-  let dragData = [[{type: 'text/toolbarwrapper-id/' + docId,
-                    data: toDrag.id}]];
-  synthesizeDragStart(toDrag.parentNode, dragData);
-  synthesizeDrop(target, target, dragData);
+function simulateItemDrag(aToDrag, aTarget) {
+  synthesizeDrop(aToDrag.parentNode, aTarget);
 }
 
 function endCustomizing(aWindow=window) {
   if (aWindow.document.documentElement.getAttribute("customizing") != "true") {
     return true;
   }
   Services.prefs.setBoolPref("browser.uiCustomization.disableAnimation", true);
   let deferredEndCustomizing = Promise.defer();
--- a/browser/docs/DirectoryLinksProvider.rst
+++ b/browser/docs/DirectoryLinksProvider.rst
@@ -18,17 +18,17 @@ 3 kinds of links:
 To power the above features, DirectoryLinksProvider module downloads, at most
 once per 24 hours, the directory source links as JSON with enough data for
 Firefox to determine what should be shown or not. This module also handles
 reporting back data about the tiles via asynchronous pings that don't return
 data from the server.
 
 For the directory source and ping endpoints, the default preference values point
 to Mozilla key-pinned servers with encryption. No cookies are set by the servers
-but not enforced by Firefox.
+and Firefox enforces this by making anonymous requests.
 
 - default directory source endpoint:
   https://tiles.services.mozilla.com/v3/links/fetch/%LOCALE%/%CHANNEL%
 - default directory ping endpoint: https://tiles.services.mozilla.com/v3/links/
 
 
 Preferences
 ===========
--- a/browser/modules/DirectoryLinksProvider.jsm
+++ b/browser/modules/DirectoryLinksProvider.jsm
@@ -4,18 +4,18 @@
 
 "use strict";
 
 this.EXPORTED_SYMBOLS = ["DirectoryLinksProvider"];
 
 const Ci = Components.interfaces;
 const Cc = Components.classes;
 const Cu = Components.utils;
-const XMLHttpRequest =
-  Components.Constructor("@mozilla.org/xmlextras/xmlhttprequest;1", "nsIXMLHttpRequest");
+
+Cu.importGlobalProperties(["XMLHttpRequest"]);
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
 Cu.import("resource://gre/modules/Timer.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
   "resource://gre/modules/NetUtil.jsm");
@@ -264,17 +264,17 @@ let DirectoryLinksProvider = {
   },
 
   _fetchAndCacheLinks: function DirectoryLinksProvider_fetchAndCacheLinks(uri) {
     // Replace with the same display locale used for selecting links data
     uri = uri.replace("%LOCALE%", this.locale);
     uri = uri.replace("%CHANNEL%", UpdateChannel.get());
 
     let deferred = Promise.defer();
-    let xmlHttp = new XMLHttpRequest();
+    let xmlHttp = this._newXHR();
 
     let self = this;
     xmlHttp.onload = function(aResponse) {
       let json = this.responseText;
       if (this.status && this.status != 200) {
         json = "{}";
       }
       OS.File.writeAtomic(self._directoryFilePath, json, {tmpPath: self._directoryFilePath + ".tmp"})
@@ -342,16 +342,23 @@ let DirectoryLinksProvider = {
     // fail if last download occured less then 24 hours ago
     if ((Date.now() - this._lastDownloadMS) > this._downloadIntervalMS) {
       return true;
     }
     return false;
   },
 
   /**
+   * Create a new XMLHttpRequest that is anonymous, i.e., doesn't send cookies
+   */
+  _newXHR() {
+    return new XMLHttpRequest({mozAnon: true});
+  },
+
+  /**
    * Reads directory links file and parses its content
    * @return a promise resolved to an object with keys 'directory' and 'suggested',
    *         each containing a valid list of links,
    *         or {'directory': [], 'suggested': []} if read or parse fails.
    */
   _readDirectoryLinksFile: function DirectoryLinksProvider_readDirectoryLinksFile() {
     let emptyOutput = {directory: [], suggested: [], enhanced: []};
     return OS.File.read(this._directoryFilePath).then(binaryData => {
@@ -532,17 +539,17 @@ let DirectoryLinksProvider = {
     };
 
     // Provide a direct index to the tile triggering the action
     if (actionIndex !== undefined) {
       data[action] = actionIndex;
     }
 
     // Package the data to be sent with the ping
-    let ping = new XMLHttpRequest();
+    let ping = this._newXHR();
     ping.open("POST", pingEndPoint + (action == "view" ? "view" : "click"));
     ping.send(JSON.stringify(data));
 
     return Task.spawn(function* () {
       // since we updated views/clicks we need write _frequencyCaps to disk
       yield this._writeFrequencyCapFile();
       // Use this as an opportunity to potentially fetch new links
       yield this._fetchAndCacheLinksIfNecessary();
--- a/browser/modules/test/xpcshell/test_DirectoryLinksProvider.js
+++ b/browser/modules/test/xpcshell/test_DirectoryLinksProvider.js
@@ -1669,8 +1669,12 @@ add_task(function test_DirectoryLinksPro
 
   // verify that disk written data is kosher
   data = yield readJsonFile(DirectoryLinksProvider._frequencyCapFilePath);
   do_check_false(data[landingUrl].hasOwnProperty("clicked"));
   do_check_false(data["http://bar.com"].hasOwnProperty("clicked"));
 
   yield promiseCleanDirectoryLinksProvider();
 });
+
+add_task(function test_DirectoryLinksProvider_anonymous() {
+  do_check_true(DirectoryLinksProvider._newXHR().mozAnon);
+});
--- a/config/system-headers
+++ b/config/system-headers
@@ -233,37 +233,32 @@ Bitmap.h
 bitset
 blapi.h
 bsd/libc.h
 bsd/syscall.h
 bstring.h
 builtin.h
 Button.h
 byteswap.h
-#if MOZ_TREE_CAIRO!=1
-#define WRAP_CAIRO_HEADERS
-#endif
-#ifdef WRAP_CAIRO_HEADERS
 pixman.h
 cairo.h
 cairo-atsui.h
 cairo-beos.h
 cairo-ft.h
 cairo-glitz.h
 cairo-pdf.h
 cairo-ps.h
 cairo-tee.h
 cairo-quartz.h
 cairo-win32.h
 cairo-xlib.h
 cairo-xlib-xrender.h
 cairo-directfb.h
 cairo-qpainter.h
 cairo-qt.h
-#endif
 dfiff.h
 exception
 ffi.h
 fusion/reactor.h
 fusion/property.h
 fusion/conf.h
 fusion/build.h
 fusion/hash.h
--- a/configure.in
+++ b/configure.in
@@ -544,16 +544,19 @@ case "$target" in
             MSVC_APPCRT_DLL=appcrt140.dll
             MSVC_DESKTOPCRT_DLL=desktopcrt140.dll
 
             # -Wv:18 disables all warnings introduced after VS2013
             # See http://blogs.msdn.com/b/vcblog/archive/2014/11/12/improvements-to-warnings-in-the-c-compiler.aspx
             CFLAGS="$CFLAGS -Wv:18"
             CXXFLAGS="$CXXFLAGS -Wv:18"
 
+            # -Zc:sizedDealloc- disables C++14 global sized deallocation (see bug 1160146)
+            CXXFLAGS="$CXXFLAGS -Zc:sizedDealloc-"
+
             # https://connect.microsoft.com/VisualStudio/feedback/details/888527/warnings-on-dbghelp-h
             # for dbghelp.h, imagehlp.h, and shobj.h
             # C4091: 'typedef ': ignored on left of '' when no variable is declared
             CFLAGS="$CFLAGS -wd4091"
             CXXFLAGS="$CXXFLAGS -wd4091"
         else
             AC_MSG_ERROR([This version (${_CC_MAJOR_VERSION}.${_CC_MINOR_VERSION}.${_CC_BUILD_VERSION}) of the MSVC compiler is unsupported.
 You must install Visual C++ 2013 Update 3 or newer in order to build.
@@ -8049,23 +8052,17 @@ if test "$USE_FC_FREETYPE"; then
         fi
     ])
 fi
 
 dnl ========================================================
 dnl Check for pixman and cairo
 dnl ========================================================
 
-if test "$MOZ_WIDGET_TOOLKIT" = "gtk3" ; then
-  # cairo-gtk3 can be build with system-cairo only
-  MOZ_TREE_CAIRO=
-else
-  MOZ_TREE_CAIRO=1
-fi
-
+MOZ_TREE_CAIRO=1
 MOZ_ARG_ENABLE_BOOL(system-cairo,
 [  --enable-system-cairo   Use system cairo (located with pkgconfig)],
 MOZ_TREE_CAIRO=,
 MOZ_TREE_CAIRO=1 )
 
 MOZ_TREE_PIXMAN=1
 MOZ_ARG_ENABLE_BOOL(system-pixman,
 [ --enable-system-pixman Use system pixman (located with pkgconfig)],
@@ -8147,19 +8144,16 @@ if test "$MOZ_TREE_CAIRO"; then
 
         MOZ_CHECK_HEADER(d3d9.h, MOZ_ENABLE_D3D9_LAYER=1)
 
         dnl D3D10 Layers depend on D2D Surfaces.
         if test -n "$WIN32_D2D_SURFACE_FEATURE"; then
           MOZ_CHECK_HEADER(d3d10.h, MOZ_ENABLE_D3D10_LAYER=1)
         fi
         ;;
-      gtk3)
-        AC_MSG_ERROR([cairo-gtk3 toolkit is incompatible with in-tree cairo. Please add --enable-system-cairo to your build config.])
-        ;;
     esac
     if test "$USE_FC_FREETYPE"; then
         FC_FONT_FEATURE="#define CAIRO_HAS_FC_FONT 1"
     fi
     AC_SUBST(MOZ_ENABLE_CAIRO_FT)
     AC_SUBST(MOZ_ENABLE_DWRITE_FONT)
     AC_SUBST(MOZ_ENABLE_D2D_SURFACE)
     AC_SUBST(MOZ_ENABLE_D3D9_LAYER)
--- a/dom/animation/Animation.cpp
+++ b/dom/animation/Animation.cpp
@@ -571,20 +571,28 @@ Animation::DoPlay(LimitBehavior aLimitBe
   // If the hold time is null then we're either already playing normally (and
   // we can ignore this call) or we aborted a pending pause operation (in which
   // case, for consistency, we need to go through the motions of doing an
   // asynchronous start even though we already have a resolved start time).
   if (mHoldTime.IsNull() && !abortedPause) {
     return;
   }
 
-  // Clear the start time until we resolve a new one (unless we are aborting
-  // a pending pause operation, in which case we keep the old start time so
-  // that the animation continues moving uninterrupted by the aborted pause).
-  if (!abortedPause) {
+  // Clear the start time until we resolve a new one. We do this except
+  // for the case where we are aborting a pause and don't have a hold time.
+  //
+  // If we're aborting a pause and *do* have a hold time (e.g. because
+  // the animation is finished or we just applied the auto-rewind behavior
+  // above) we should respect it by clearing the start time. If we *don't*
+  // have a hold time we should keep the current start time so that the
+  // the animation continues moving uninterrupted by the aborted pause.
+  //
+  // (If we're not aborting a pause, mHoldTime must be resolved by now
+  //  or else we would have returned above.)
+  if (!mHoldTime.IsNull()) {
     mStartTime.SetNull();
   }
 
   if (!reuseReadyPromise) {
     // Clear ready promise. We'll create a new one lazily.
     mReady = nullptr;
   }
 
--- a/dom/animation/test/css-animations/file_animation-currenttime.html
+++ b/dom/animation/test/css-animations/file_animation-currenttime.html
@@ -537,12 +537,35 @@ test(function(t) {
   div.style.animation = 'anim 100s';
 
   var animation = div.getAnimations()[0];
   animation.cancel();
   assert_equals(animation.currentTime, null,
                 'The currentTime of a cancelled animation should be null');
 }, 'Animation.currentTime after cancelling');
 
+async_test(function(t) {
+  var div = addDiv(t, {'class': 'animated-div'});
+  div.style.animation = 'anim 100s';
+
+  var animation = div.getAnimations()[0];
+  animation.ready.then(t.step_func(function() {
+    animation.finish();
+
+    // Initiate a pause then abort it
+    animation.pause();
+    animation.play();
+
+    // Wait to return to running state
+    return animation.ready;
+  })).then(t.step_func(function() {
+    assert_true(animation.currentTime < 100 * 1000,
+                'After aborting a pause when finished, the currentTime should'
+                + ' jump back towards the start of the animation');
+    t.done();
+  }));
+}, 'After aborting a pause when finished, the call to play() should rewind'
+   + ' the current time');
+
 done();
     </script>
   </body>
 </html>
--- a/dom/base/nsContentList.cpp
+++ b/dom/base/nsContentList.cpp
@@ -148,17 +148,17 @@ NS_IMPL_RELEASE_INHERITED(nsSimpleConten
 
 JSObject*
 nsSimpleContentList::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto)
 {
   return NodeListBinding::Wrap(cx, this, aGivenProto);
 }
 
 // Hashtable for storing nsContentLists
-static PLDHashTable gContentListHashTable;
+static PLDHashTable* gContentListHashTable;
 
 #define RECENTLY_USED_CONTENT_LIST_CACHE_SIZE 31
 static nsContentList*
   sRecentlyUsedContentLists[RECENTLY_USED_CONTENT_LIST_CACHE_SIZE] = {};
 
 static MOZ_ALWAYS_INLINE uint32_t
 RecentlyUsedCacheIndex(const nsContentListKey& aKey)
 {
@@ -210,29 +210,27 @@ NS_GetContentList(nsINode* aRootNode,
   {
     ContentListHashtableHashKey,
     ContentListHashtableMatchEntry,
     PL_DHashMoveEntryStub,
     PL_DHashClearEntryStub
   };
 
   // Initialize the hashtable if needed.
-  if (!gContentListHashTable.IsInitialized()) {
-    PL_DHashTableInit(&gContentListHashTable, &hash_table_ops,
-                      sizeof(ContentListHashEntry));
+  if (!gContentListHashTable) {
+    gContentListHashTable =
+      new PLDHashTable(&hash_table_ops, sizeof(ContentListHashEntry));
   }
 
   ContentListHashEntry *entry = nullptr;
   // First we look in our hashtable.  Then we create a content list if needed
-  if (gContentListHashTable.IsInitialized()) {
-    entry = static_cast<ContentListHashEntry *>
-      (PL_DHashTableAdd(&gContentListHashTable, &hashKey, fallible));
-    if (entry)
-      list = entry->mContentList;
-  }
+  entry = static_cast<ContentListHashEntry *>
+    (PL_DHashTableAdd(gContentListHashTable, &hashKey, fallible));
+  if (entry)
+    list = entry->mContentList;
 
   if (!list) {
     // We need to create a ContentList and add it to our new entry, if
     // we have an entry
     nsCOMPtr<nsIAtom> xmlAtom = do_GetAtom(aTagname);
     nsCOMPtr<nsIAtom> htmlAtom;
     if (aMatchNameSpaceId == kNameSpaceID_Unknown) {
       nsAutoString lowercaseName;
@@ -267,17 +265,17 @@ nsCacheableFuncStringNodeList::WrapObjec
 
 JSObject*
 nsCacheableFuncStringHTMLCollection::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto)
 {
   return HTMLCollectionBinding::Wrap(cx, this, aGivenProto);
 }
 
 // Hashtable for storing nsCacheableFuncStringContentList
-static PLDHashTable gFuncStringContentListHashTable;
+static PLDHashTable* gFuncStringContentListHashTable;
 
 struct FuncStringContentListHashEntry : public PLDHashEntryHdr
 {
   nsCacheableFuncStringContentList* mContentList;
 };
 
 static PLDHashNumber
 FuncStringContentListHashtableHashKey(PLDHashTable *table, const void *key)
@@ -316,28 +314,28 @@ GetFuncStringContentList(nsINode* aRootN
   {
     FuncStringContentListHashtableHashKey,
     FuncStringContentListHashtableMatchEntry,
     PL_DHashMoveEntryStub,
     PL_DHashClearEntryStub
   };
 
   // Initialize the hashtable if needed.
-  if (!gFuncStringContentListHashTable.IsInitialized()) {
-    PL_DHashTableInit(&gFuncStringContentListHashTable, &hash_table_ops,
-                      sizeof(FuncStringContentListHashEntry));
+  if (!gFuncStringContentListHashTable) {
+    gFuncStringContentListHashTable =
+      new PLDHashTable(&hash_table_ops, sizeof(FuncStringContentListHashEntry));
   }
 
   FuncStringContentListHashEntry *entry = nullptr;
   // First we look in our hashtable.  Then we create a content list if needed
-  if (gFuncStringContentListHashTable.IsInitialized()) {
+  if (gFuncStringContentListHashTable) {
     nsFuncStringCacheKey hashKey(aRootNode, aFunc, aString);
 
     entry = static_cast<FuncStringContentListHashEntry *>
-      (PL_DHashTableAdd(&gFuncStringContentListHashTable, &hashKey, fallible));
+      (PL_DHashTableAdd(gFuncStringContentListHashTable, &hashKey, fallible));
     if (entry) {
       list = entry->mContentList;
 #ifdef DEBUG
       MOZ_ASSERT_IF(list, list->mType == ListType::sType);
 #endif
     }
   }
 
@@ -965,23 +963,24 @@ nsContentList::RemoveFromHashtable()
   
   nsDependentAtomString str(mXMLMatchAtom);
   nsContentListKey key(mRootNode, mMatchNameSpaceId, str);
   uint32_t recentlyUsedCacheIndex = RecentlyUsedCacheIndex(key);
   if (sRecentlyUsedContentLists[recentlyUsedCacheIndex] == this) {
     sRecentlyUsedContentLists[recentlyUsedCacheIndex] = nullptr;
   }
 
-  if (!gContentListHashTable.IsInitialized())
+  if (!gContentListHashTable)
     return;
 
-  PL_DHashTableRemove(&gContentListHashTable, &key);
+  PL_DHashTableRemove(gContentListHashTable, &key);
 
-  if (gContentListHashTable.EntryCount() == 0) {
-    PL_DHashTableFinish(&gContentListHashTable);
+  if (gContentListHashTable->EntryCount() == 0) {
+    delete gContentListHashTable;
+    gContentListHashTable = nullptr;
   }
 }
 
 void
 nsContentList::BringSelfUpToDate(bool aDoFlush)
 {
   if (mRootNode && aDoFlush && mFlushesNeeded) {
     // XXX sXBL/XBL2 issue
@@ -1003,25 +1002,26 @@ nsContentList::BringSelfUpToDate(bool aD
 nsCacheableFuncStringContentList::~nsCacheableFuncStringContentList()
 {
   RemoveFromFuncStringHashtable();
 }
 
 void
 nsCacheableFuncStringContentList::RemoveFromFuncStringHashtable()
 {
-  if (!gFuncStringContentListHashTable.IsInitialized()) {
+  if (!gFuncStringContentListHashTable) {
     return;
   }
 
   nsFuncStringCacheKey key(mRootNode, mFunc, mString);
-  PL_DHashTableRemove(&gFuncStringContentListHashTable, &key);
+  PL_DHashTableRemove(gFuncStringContentListHashTable, &key);
 
-  if (gFuncStringContentListHashTable.EntryCount() == 0) {
-    PL_DHashTableFinish(&gFuncStringContentListHashTable);
+  if (gFuncStringContentListHashTable->EntryCount() == 0) {
+    delete gFuncStringContentListHashTable;
+    gFuncStringContentListHashTable = nullptr;
   }
 }
 
 #ifdef DEBUG_CONTENT_LIST
 void
 nsContentList::AssertInSync()
 {
   if (mState == LIST_DIRTY) {
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -332,35 +332,35 @@ static const nsAttrValue::EnumTable kAut
   { 0 }
 };
 
 namespace {
 
 static NS_DEFINE_CID(kParserServiceCID, NS_PARSERSERVICE_CID);
 static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID);
 
-static PLDHashTable sEventListenerManagersHash;
+static PLDHashTable* sEventListenerManagersHash;
 
 class DOMEventListenerManagersHashReporter final : public nsIMemoryReporter
 {
   MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf)
 
   ~DOMEventListenerManagersHashReporter() {}
 
 public:
   NS_DECL_ISUPPORTS
 
   NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
                             nsISupports* aData, bool aAnonymize) override
   {
     // We don't measure the |EventListenerManager| objects pointed to by the
     // entries because those references are non-owning.
-    int64_t amount = sEventListenerManagersHash.IsInitialized()
+    int64_t amount = sEventListenerManagersHash
                    ? PL_DHashTableSizeOfExcludingThis(
-                       &sEventListenerManagersHash, nullptr, MallocSizeOf)
+                       sEventListenerManagersHash, nullptr, MallocSizeOf)
                    : 0;
 
     return MOZ_COLLECT_REPORT(
       "explicit/dom/event-listener-managers-hash", KIND_HEAP, UNITS_BYTES,
       amount,
       "Memory used by the event listener manager's hash table.");
   }
 };
@@ -483,28 +483,28 @@ nsContentUtils::Init()
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = CallGetService(NS_WBRK_CONTRACTID, &sWordBreaker);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!InitializeEventTable())
     return NS_ERROR_FAILURE;
 
-  if (!sEventListenerManagersHash.IsInitialized()) {
+  if (!sEventListenerManagersHash) {
     static const PLDHashTableOps hash_table_ops =
     {
       PL_DHashVoidPtrKeyStub,
       PL_DHashMatchEntryStub,
       PL_DHashMoveEntryStub,
       EventListenerManagerHashClearEntry,
       EventListenerManagerHashInitEntry
     };
 
-    PL_DHashTableInit(&sEventListenerManagersHash, &hash_table_ops,
-                      sizeof(EventListenerManagerMapEntry));
+    sEventListenerManagersHash =
+      new PLDHashTable(&hash_table_ops, sizeof(EventListenerManagerMapEntry));
 
     RegisterStrongMemoryReporter(new DOMEventListenerManagersHashReporter());
   }
 
   sBlockedScriptRunners = new nsTArray< nsCOMPtr<nsIRunnable> >;
 
   Preferences::AddBoolVarCache(&sAllowXULXBL_for_file,
                                "dom.allow_XUL_XBL_for_file");
@@ -1805,31 +1805,32 @@ nsContentUtils::Shutdown()
 
   delete sAtomEventTable;
   sAtomEventTable = nullptr;
   delete sStringEventTable;
   sStringEventTable = nullptr;
   delete sUserDefinedEvents;
   sUserDefinedEvents = nullptr;
 
-  if (sEventListenerManagersHash.IsInitialized()) {
-    NS_ASSERTION(sEventListenerManagersHash.EntryCount() == 0,
+  if (sEventListenerManagersHash) {
+    NS_ASSERTION(sEventListenerManagersHash->EntryCount() == 0,
                  "Event listener manager hash not empty at shutdown!");
 
     // See comment above.
 
     // However, we have to handle this table differently.  If it still
     // has entries, we want to leak it too, so that we can keep it alive
     // in case any elements are destroyed.  Because if they are, we need
     // their event listener managers to be destroyed too, or otherwise
     // it could leave dangling references in DOMClassInfo's preserved
     // wrapper table.
 
-    if (sEventListenerManagersHash.EntryCount() == 0) {
-      PL_DHashTableFinish(&sEventListenerManagersHash);
+    if (sEventListenerManagersHash->EntryCount() == 0) {
+      delete sEventListenerManagersHash;
+      sEventListenerManagersHash = nullptr;
     }
   }
 
   NS_ASSERTION(!sBlockedScriptRunners ||
                sBlockedScriptRunners->Length() == 0,
                "How'd this happen?");
   delete sBlockedScriptRunners;
   sBlockedScriptRunners = nullptr;
@@ -3984,54 +3985,54 @@ ListenerEnumerator(PLDHashTable* aTable,
     }
   }
   return PL_DHASH_NEXT;
 }
 
 void
 nsContentUtils::UnmarkGrayJSListenersInCCGenerationDocuments(uint32_t aGeneration)
 {
-  if (sEventListenerManagersHash.IsInitialized()) {
-    PL_DHashTableEnumerate(&sEventListenerManagersHash, ListenerEnumerator,
+  if (sEventListenerManagersHash) {
+    PL_DHashTableEnumerate(sEventListenerManagersHash, ListenerEnumerator,
                            &aGeneration);
   }
 }
 
 /* static */
 void
 nsContentUtils::TraverseListenerManager(nsINode *aNode,
                                         nsCycleCollectionTraversalCallback &cb)
 {
-  if (!sEventListenerManagersHash.IsInitialized()) {
+  if (!sEventListenerManagersHash) {
     // We're already shut down, just return.
     return;
   }
 
   EventListenerManagerMapEntry *entry =
     static_cast<EventListenerManagerMapEntry *>
-               (PL_DHashTableSearch(&sEventListenerManagersHash, aNode));
+               (PL_DHashTableSearch(sEventListenerManagersHash, aNode));
   if (entry) {
     CycleCollectionNoteChild(cb, entry->mListenerManager.get(),
                              "[via hash] mListenerManager");
   }
 }
 
 EventListenerManager*
 nsContentUtils::GetListenerManagerForNode(nsINode *aNode)
 {
-  if (!sEventListenerManagersHash.IsInitialized()) {
+  if (!sEventListenerManagersHash) {
     // We're already shut down, don't bother creating an event listener
     // manager.
 
     return nullptr;
   }
 
   EventListenerManagerMapEntry *entry =
     static_cast<EventListenerManagerMapEntry *>
-      (PL_DHashTableAdd(&sEventListenerManagersHash, aNode, fallible));
+      (PL_DHashTableAdd(sEventListenerManagersHash, aNode, fallible));
 
   if (!entry) {
     return nullptr;
   }
 
   if (!entry->mListenerManager) {
     entry->mListenerManager = new EventListenerManager(aNode);
 
@@ -4043,47 +4044,47 @@ nsContentUtils::GetListenerManagerForNod
 
 EventListenerManager*
 nsContentUtils::GetExistingListenerManagerForNode(const nsINode *aNode)
 {
   if (!aNode->HasFlag(NODE_HAS_LISTENERMANAGER)) {
     return nullptr;
   }
 
-  if (!sEventListenerManagersHash.IsInitialized()) {
+  if (!sEventListenerManagersHash) {
     // We're already shut down, don't bother creating an event listener
     // manager.
 
     return nullptr;
   }
 
   EventListenerManagerMapEntry *entry =
     static_cast<EventListenerManagerMapEntry *>
-               (PL_DHashTableSearch(&sEventListenerManagersHash, aNode));
+               (PL_DHashTableSearch(sEventListenerManagersHash, aNode));
   if (entry) {
     return entry->mListenerManager;
   }
 
   return nullptr;
 }
 
 /* static */
 void
 nsContentUtils::RemoveListenerManager(nsINode *aNode)
 {
-  if (sEventListenerManagersHash.IsInitialized()) {
+  if (sEventListenerManagersHash) {
     EventListenerManagerMapEntry *entry =
       static_cast<EventListenerManagerMapEntry *>
-                 (PL_DHashTableSearch(&sEventListenerManagersHash, aNode));
+                 (PL_DHashTableSearch(sEventListenerManagersHash, aNode));
     if (entry) {
       nsRefPtr<EventListenerManager> listenerManager;
       listenerManager.swap(entry->mListenerManager);
       // Remove the entry and *then* do operations that could cause further
       // modification of sEventListenerManagersHash.  See bug 334177.
-      PL_DHashTableRawRemove(&sEventListenerManagersHash, entry);
+      PL_DHashTableRawRemove(sEventListenerManagersHash, entry);
       if (listenerManager) {
         listenerManager->Disconnect();
       }
     }
   }
 }
 
 /* static */
@@ -7758,9 +7759,9 @@ nsContentUtils::FirePageShowEvent(nsIDoc
     }
   }
 
   nsCOMPtr<nsIDocument> doc = aItem->GetDocument();
   NS_ASSERTION(doc, "What happened here?");
   if (doc->IsShowing() == aFireIfShowing) {
     doc->OnPageShow(true, aChromeEventHandler);
   }
-}
\ No newline at end of file
+}
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -403,25 +403,34 @@ public:
     GetOrCreateListenerManager() override;
 
   using mozilla::dom::EventTarget::RemoveEventListener;
   virtual void AddEventListener(const nsAString& aType,
                                 mozilla::dom::EventListener* aListener,
                                 bool aUseCapture,
                                 const mozilla::dom::Nullable<bool>& aWantsUntrusted,
                                 mozilla::ErrorResult& aRv) override;
-  virtual nsIDOMWindow* GetOwnerGlobal() override
+  virtual nsIDOMWindow* GetOwnerGlobalForBindings() override
   {
     if (IsOuterWindow()) {
       return this;
     }
 
     return GetOuterFromCurrentInner(this);
   }
 
+  virtual nsIGlobalObject* GetOwnerGlobal() const override
+  {
+    if (IsOuterWindow()) {
+      return GetCurrentInnerWindowInternal();
+    }
+
+    return const_cast<nsGlobalWindow*>(this);
+  }
+
   // nsPIDOMWindow
   virtual nsPIDOMWindow* GetPrivateRoot() override;
 
   // Outer windows only.
   virtual void ActivateOrDeactivate(bool aActivate) override;
   virtual void SetActive(bool aActive) override;
   virtual void SetIsBackground(bool aIsBackground) override;
   virtual void SetChromeEventHandler(mozilla::dom::EventTarget* aChromeEventHandler) override;
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -2867,17 +2867,17 @@ protected:
   // Array of nodes that have been blocked to prevent user tracking.
   // They most likely have had their nsIChannel canceled by the URL
   // classifier. (Safebrowsing)
   //
   // Weak nsINode pointers are used to allow nodes to disappear.
   nsTArray<nsWeakPtr> mBlockedTrackingNodes;
 
   // Weak reference to mScriptGlobalObject QI:d to nsPIDOMWindow,
-  // updated on every set of mSecriptGlobalObject.
+  // updated on every set of mScriptGlobalObject.
   nsPIDOMWindow *mWindow;
 
   nsCOMPtr<nsIDocumentEncoder> mCachedEncoder;
 
   struct FrameRequest;
 
   nsTArray<FrameRequest> mFrameRequestCallbacks;
 
--- a/dom/base/nsINode.cpp
+++ b/dom/base/nsINode.cpp
@@ -1291,23 +1291,30 @@ nsINode::GetExistingListenerManager() co
 
 nsIScriptContext*
 nsINode::GetContextForEventHandlers(nsresult* aRv)
 {
   return nsContentUtils::GetContextForEventHandlers(this, aRv);
 }
 
 nsIDOMWindow*
-nsINode::GetOwnerGlobal()
+nsINode::GetOwnerGlobalForBindings()
 {
   bool dummy;
   return nsPIDOMWindow::GetOuterFromCurrentInner(
     static_cast<nsGlobalWindow*>(OwnerDoc()->GetScriptHandlingObject(dummy)));
 }
 
+nsIGlobalObject*
+nsINode::GetOwnerGlobal() const
+{
+  bool dummy;
+  return OwnerDoc()->GetScriptHandlingObject(dummy);
+}
+
 bool
 nsINode::UnoptimizableCCNode() const
 {
   const uintptr_t problematicFlags = (NODE_IS_ANONYMOUS_ROOT |
                                       NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE |
                                       NODE_IS_NATIVE_ANONYMOUS_ROOT |
                                       NODE_MAY_BE_IN_BINDING_MNGR |
                                       NODE_IS_IN_SHADOW_TREE);
--- a/dom/base/nsINode.h
+++ b/dom/base/nsINode.h
@@ -983,17 +983,18 @@ public:
   using mozilla::dom::EventTarget::RemoveEventListener;
   using nsIDOMEventTarget::AddEventListener;
   virtual void AddEventListener(const nsAString& aType,
                                 mozilla::dom::EventListener* aListener,
                                 bool aUseCapture,
                                 const mozilla::dom::Nullable<bool>& aWantsUntrusted,
                                 mozilla::ErrorResult& aRv) override;
   using nsIDOMEventTarget::AddSystemEventListener;
-  virtual nsIDOMWindow* GetOwnerGlobal() override;
+  virtual nsIDOMWindow* GetOwnerGlobalForBindings() override;
+  virtual nsIGlobalObject* GetOwnerGlobal() const override;
 
   /**
    * Adds a mutation observer to be notified when this node, or any of its
    * descendants, are modified. The node will hold a weak reference to the
    * observer, which means that it is the responsibility of the observer to
    * remove itself in case it dies before the node.  If an observer is added
    * while observers are being notified, it may also be notified.  In general,
    * adding observers while inside a notification is not a good idea.  An
--- a/dom/base/nsPIWindowRoot.h
+++ b/dom/base/nsPIWindowRoot.h
@@ -33,14 +33,13 @@ public:
                                            nsIController** aResult) = 0;
   virtual nsresult GetControllers(nsIControllers** aResult) = 0;
 
   virtual void GetEnabledDisabledCommands(nsTArray<nsCString>& aEnabledCommands,
                                           nsTArray<nsCString>& aDisabledCommands) = 0;
 
   virtual void SetParentTarget(mozilla::dom::EventTarget* aTarget) = 0;
   virtual mozilla::dom::EventTarget* GetParentTarget() = 0;
-  virtual nsIDOMWindow* GetOwnerGlobal() override = 0;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsPIWindowRoot, NS_IWINDOWROOT_IID)
 
 #endif // nsPIWindowRoot_h__
--- a/dom/base/nsPropertyTable.cpp
+++ b/dom/base/nsPropertyTable.cpp
@@ -282,31 +282,28 @@ nsPropertyTable::GetPropertyListFor(nsIA
 
 //----------------------------------------------------------------------
 
 nsPropertyTable::PropertyList::PropertyList(nsIAtom            *aName,
                                             NSPropertyDtorFunc  aDtorFunc,
                                             void               *aDtorData,
                                             bool                aTransfer)
   : mName(aName),
+    mObjectValueMap(PL_DHashGetStubOps(), sizeof(PropertyListMapEntry)),
     mDtorFunc(aDtorFunc),
     mDtorData(aDtorData),
     mTransfer(aTransfer),
     mNext(nullptr)
 {
-  PL_DHashTableInit(&mObjectValueMap, PL_DHashGetStubOps(),
-                    sizeof(PropertyListMapEntry));
 }
 
 nsPropertyTable::PropertyList::~PropertyList()
 {
-  PL_DHashTableFinish(&mObjectValueMap);
 }
 
-
 static PLDHashOperator
 DestroyPropertyEnumerator(PLDHashTable *table, PLDHashEntryHdr *hdr,
                           uint32_t number, void *arg)
 {
   nsPropertyTable::PropertyList *propList =
       static_cast<nsPropertyTable::PropertyList*>(arg);
   PropertyListMapEntry* entry = static_cast<PropertyListMapEntry*>(hdr);
 
--- a/dom/base/nsWindowRoot.cpp
+++ b/dom/base/nsWindowRoot.cpp
@@ -183,21 +183,30 @@ nsWindowRoot::PreHandleEvent(EventChainP
 
 nsresult
 nsWindowRoot::PostHandleEvent(EventChainPostVisitor& aVisitor)
 {
   return NS_OK;
 }
 
 nsIDOMWindow*
-nsWindowRoot::GetOwnerGlobal()
+nsWindowRoot::GetOwnerGlobalForBindings()
 {
   return GetWindow();
 }
 
+nsIGlobalObject*
+nsWindowRoot::GetOwnerGlobal() const
+{
+  nsCOMPtr<nsIGlobalObject> global =
+    do_QueryInterface(mWindow->GetCurrentInnerWindow());
+  // We're still holding a ref to it, so returning the raw pointer is ok...
+  return global;
+}
+
 nsPIDOMWindow*
 nsWindowRoot::GetWindow()
 {
   return mWindow;
 }
 
 nsresult
 nsWindowRoot::GetControllers(nsIControllers** aResult)
--- a/dom/base/nsWindowRoot.h
+++ b/dom/base/nsWindowRoot.h
@@ -54,17 +54,18 @@ public:
   virtual nsIDOMNode* GetPopupNode() override;
   virtual void SetPopupNode(nsIDOMNode* aNode) override;
 
   virtual void SetParentTarget(mozilla::dom::EventTarget* aTarget) override
   {
     mParent = aTarget;
   }
   virtual mozilla::dom::EventTarget* GetParentTarget() override { return mParent; }
-  virtual nsIDOMWindow* GetOwnerGlobal() override;
+  virtual nsIDOMWindow* GetOwnerGlobalForBindings() override;
+  virtual nsIGlobalObject* GetOwnerGlobal() const override;
 
   nsIGlobalObject* GetParentObject();
 
   virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsWindowRoot,
                                                          nsIDOMEventTarget)
 
--- a/dom/base/nsXMLHttpRequest.cpp
+++ b/dom/base/nsXMLHttpRequest.cpp
@@ -386,39 +386,43 @@ nsXMLHttpRequest::Init(nsIPrincipal* aPr
 void
 nsXMLHttpRequest::InitParameters(bool aAnon, bool aSystem)
 {
   if (!aAnon && !aSystem) {
     return;
   }
 
   // Check for permissions.
-  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(GetOwner());
-  if (!window || !window->GetDocShell()) {
-    return;
-  }
-
   // Chrome is always allowed access, so do the permission check only
   // for non-chrome pages.
   if (!IsSystemXHR() && aSystem) {
-    nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
-    if (!doc) {
+    nsIGlobalObject* global = GetOwnerGlobal();
+    if (NS_WARN_IF(!global)) {
+      SetParameters(aAnon, false);
       return;
     }
 
-    nsCOMPtr<nsIPrincipal> principal = doc->NodePrincipal();
+    nsIPrincipal* principal = global->PrincipalOrNull();
+    if (NS_WARN_IF(!principal)) {
+      SetParameters(aAnon, false);
+      return;
+    }
+
     nsCOMPtr<nsIPermissionManager> permMgr =
       services::GetPermissionManager();
-    if (!permMgr)
+    if (NS_WARN_IF(!permMgr)) {
+      SetParameters(aAnon, false);
       return;
+    }
 
     uint32_t permission;
     nsresult rv =
       permMgr->TestPermissionFromPrincipal(principal, "systemXHR", &permission);
     if (NS_FAILED(rv) || permission != nsIPermissionManager::ALLOW_ACTION) {
+      SetParameters(aAnon, false);
       return;
     }
   }
 
   SetParameters(aAnon, aSystem);
 }
 
 void
--- a/dom/base/test/test_bug927196.html
+++ b/dom/base/test/test_bug927196.html
@@ -16,41 +16,41 @@ https://bugzilla.mozilla.org/show_bug.cg
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 /** Test for Bug 927196 **/
 
 function startTest() {
   req = new XMLHttpRequest({mozSystem: true});
-  is(req.mozAnon, true, "XMLHttpRequest should be mozAnon");
+  is(req.mozAnon, true, "XMLHttpRequest should be mozAnon (3)");
 
   req = new XMLHttpRequest({mozAnon: true});
-  is(req.mozAnon, true, "XMLHttpRequest should be mozAnon");
-  is(req.mozSystem, false, "XMLHttpRequest should not be mozSystem");
+  is(req.mozAnon, true, "XMLHttpRequest should be mozAnon (4)");
+  is(req.mozSystem, false, "XMLHttpRequest should not be mozSystem (4)");
 
   req = new XMLHttpRequest({mozAnon: true, mozSystem: true});
-  is(req.mozAnon, true, "XMLHttpRequest should be mozAnon");
-  is(req.mozSystem, true, "XMLHttpRequest should be mozSystem");
+  is(req.mozAnon, true, "XMLHttpRequest should be mozAnon (5)");
+  is(req.mozSystem, true, "XMLHttpRequest should be mozSystem (5)");
 
   req = new XMLHttpRequest({mozAnon: false, mozSystem: true});
-  is(req.mozAnon, true, "XMLHttpRequest should be mozAnon");
+  is(req.mozAnon, true, "XMLHttpRequest should be mozAnon (6)");
 
   SimpleTest.finish();
 }
 
 SimpleTest.waitForExplicitFinish();
 
 var req = new XMLHttpRequest({mozAnon: true});
 is(req.mozAnon, true, "XMLHttpRequest should be mozAnon");
 is(req.mozSystem, false, "XMLHttpRequest should not be mozSystem");
 
 req = new XMLHttpRequest({mozAnon: true, mozSystem: true});
-is(req.mozAnon, false, "XMLHttpRequest should be mozAnon");
-is(req.mozSystem, false, "XMLHttpRequest should not be mozSystem");
+is(req.mozAnon, true, "XMLHttpRequest should be mozAnon (2)");
+is(req.mozSystem, false, "XMLHttpRequest should not be mozSystem (2)");
 
 addLoadEvent(function() {
    SpecialPowers.pushPermissions([{'type': 'systemXHR', 'allow': true, 'context': document}], startTest);
 });
 </script>
 </pre>
 </body>
 </html>
--- a/dom/events/DOMEventTargetHelper.h
+++ b/dom/events/DOMEventTargetHelper.h
@@ -116,17 +116,17 @@ public:
   nsresult SetEventHandler(nsIAtom* aType,
                            JSContext* aCx,
                            const JS::Value& aValue);
   using dom::EventTarget::SetEventHandler;
   void GetEventHandler(nsIAtom* aType,
                        JSContext* aCx,
                        JS::Value* aValue);
   using dom::EventTarget::GetEventHandler;
-  virtual nsIDOMWindow* GetOwnerGlobal() override
+  virtual nsIDOMWindow* GetOwnerGlobalForBindings() override
   {
     return nsPIDOMWindow::GetOuterFromCurrentInner(GetOwner());
   }
 
   nsresult CheckInnerWindowCorrectness()
   {
     NS_ENSURE_STATE(!mHasOrHasHadOwnerWindow || mOwnerWindow);
     if (mOwnerWindow && !mOwnerWindow->IsCurrentInnerWindow()) {
@@ -135,17 +135,22 @@ public:
     return NS_OK;
   }
 
   nsPIDOMWindow* GetOwner() const { return mOwnerWindow; }
   void BindToOwner(nsIGlobalObject* aOwner);
   void BindToOwner(nsPIDOMWindow* aOwner);
   void BindToOwner(DOMEventTargetHelper* aOther);
   virtual void DisconnectFromOwner();                   
-  nsIGlobalObject* GetParentObject() const {
+  nsIGlobalObject* GetParentObject() const
+  {
+    return GetOwnerGlobal();
+  }
+  virtual nsIGlobalObject* GetOwnerGlobal() const override
+  {
     nsCOMPtr<nsIGlobalObject> parentObject = do_QueryReferent(mParentObject);
     return parentObject;
   }
   bool HasOrHasHadOwner() { return mHasOrHasHadOwnerWindow; }
 
   virtual void EventListenerAdded(nsIAtom* aType) override;
   virtual void EventListenerRemoved(nsIAtom* aType) override;
   virtual void EventListenerWasAdded(const nsAString& aType,
--- a/dom/events/EventTarget.h
+++ b/dom/events/EventTarget.h
@@ -7,33 +7,34 @@
 #ifndef mozilla_dom_EventTarget_h_
 #define mozilla_dom_EventTarget_h_
 
 #include "nsIDOMEventTarget.h"
 #include "nsWrapperCache.h"
 #include "nsIAtom.h"
 
 class nsIDOMWindow;
+class nsIGlobalObject;
 
 namespace mozilla {
 
 class ErrorResult;
 class EventListenerManager;
 
 namespace dom {
 
 class Event;
 class EventListener;
 class EventHandlerNonNull;
 template <class T> struct Nullable;
 
 // IID for the dom::EventTarget interface
 #define NS_EVENTTARGET_IID \
-{ 0xce3817d0, 0x177b, 0x402f, \
- { 0xae, 0x75, 0xf8, 0x4e, 0xbe, 0x5a, 0x07, 0xc3 } }
+{ 0x605158a9, 0xe229, 0x45b1, \
+ { 0xbc, 0x12, 0x02, 0x9f, 0xa3, 0xa9, 0x3f, 0xcb } }
 
 class EventTarget : public nsIDOMEventTarget,
                     public nsWrapperCache
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_EVENTTARGET_IID)
 
   // WebIDL API
@@ -64,17 +65,22 @@ public:
 
   // Note, for an event 'foo' aType will be 'onfoo'.
   virtual void EventListenerAdded(nsIAtom* aType) {}
   virtual void EventListenerRemoved(nsIAtom* aType) {}
 
   // Returns an outer window that corresponds to the inner window this event
   // target is associated with.  Will return null if the inner window is not the
   // current inner or if there is no window around at all.
-  virtual nsIDOMWindow* GetOwnerGlobal() = 0;
+  virtual nsIDOMWindow* GetOwnerGlobalForBindings() = 0;
+
+  // The global object this event target is associated with, if any.
+  // This may be an inner window or some other global object.  This
+  // will never be an outer window.
+  virtual nsIGlobalObject* GetOwnerGlobal() const = 0;
 
   /**
    * Get the event listener manager, creating it if it does not already exist.
    */
   virtual EventListenerManager* GetOrCreateListenerManager() = 0;
 
   /**
    * Get the event listener manager, returning null if it does not already
--- a/dom/events/Touch.cpp
+++ b/dom/events/Touch.cpp
@@ -131,27 +131,22 @@ Touch::Equals(Touch* aTouch)
 }
 
 JSObject*
 Touch::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return TouchBinding::Wrap(aCx, this, aGivenProto);
 }
 
-// Parent ourselves to the window of the target. This achieves the desirable
+// Parent ourselves to the global of the target. This achieves the desirable
 // effects of parenting to the target, but avoids making the touch inaccessible
 // when the target happens to be NAC and therefore reflected into the XBL scope.
-EventTarget*
+nsIGlobalObject*
 Touch::GetParentObject()
 {
   if (!mTarget) {
     return nullptr;
   }
-  nsCOMPtr<nsPIDOMWindow> outer = do_QueryInterface(mTarget->GetOwnerGlobal());
-  if (!outer) {
-    return nullptr;
-  }
-  MOZ_ASSERT(outer->IsOuterWindow());
-  return static_cast<nsGlobalWindow*>(outer->GetCurrentInnerWindow());
+  return mTarget->GetOwnerGlobal();
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/events/Touch.h
+++ b/dom/events/Touch.h
@@ -52,17 +52,17 @@ public:
   void InitializePoints(nsPresContext* aPresContext, WidgetEvent* aEvent);
 
   void SetTarget(EventTarget* aTarget);
 
   bool Equals(Touch* aTouch);
 
   virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
-  EventTarget* GetParentObject();
+  nsIGlobalObject* GetParentObject();
 
   // WebIDL
   int32_t Identifier() const { return mIdentifier; }
   EventTarget* GetTarget() const;
   int32_t ScreenX() const { return mScreenPoint.x; }
   int32_t ScreenY() const { return mScreenPoint.y; }
   int32_t ClientX() const { return mClientPoint.x; }
   int32_t ClientY() const { return mClientPoint.y; }
--- a/dom/imptests/html/html/dom/elements/global-attributes/reftest.list
+++ b/dom/imptests/html/html/dom/elements/global-attributes/reftest.list
@@ -41,16 +41,16 @@
 == dir_auto-N-EN-R.html dir_auto-N-EN-R-ref.html
 == dir_auto-N-L.html dir_auto-N-L-ref.html
 == dir_auto-N-R.html dir_auto-N-R-ref.html
 == dir_auto-pre-mixed.html dir_auto-pre-mixed-ref.html
 == dir_auto-pre-N-between-Rs.html dir_auto-pre-N-between-Rs-ref.html
 == dir_auto-pre-N-EN.html dir_auto-pre-N-EN-ref.html
 == dir_auto-R.html dir_auto-R-ref.html
 == dir_auto-textarea-mixed.html dir_auto-textarea-mixed-ref.html
-fails-if(B2G) == dir_auto-textarea-N-between-Rs.html dir_auto-textarea-N-between-Rs-ref.html # B2G scrollbar on opposite side
+fails-if(B2G||Mulet) == dir_auto-textarea-N-between-Rs.html dir_auto-textarea-N-between-Rs-ref.html # B2G scrollbar on opposite side
 == dir_auto-textarea-N-EN.html dir_auto-textarea-N-EN-ref.html
 == dir_auto-textarea-script-mixed.html dir_auto-textarea-script-mixed-ref.html
-fails-if(B2G) == dir_auto-textarea-script-N-between-Rs.html dir_auto-textarea-script-N-between-Rs-ref.html # B2G scrollbar on reference only
+fails-if(B2G||Mulet) == dir_auto-textarea-script-N-between-Rs.html dir_auto-textarea-script-N-between-Rs-ref.html # B2G scrollbar on reference only
 == dir_auto-textarea-script-N-EN.html dir_auto-textarea-script-N-EN-ref.html
 == lang-xyzzy.html lang-xyzzy-ref.html
 == lang-xmllang-01.html lang-xmllang-01-ref.html
 == style-01.html style-01-ref.html
--- a/dom/indexedDB/IndexedDatabaseManager.cpp
+++ b/dom/indexedDB/IndexedDatabaseManager.cpp
@@ -423,17 +423,18 @@ IndexedDatabaseManager::CommonPostHandle
 
   init.mMessage = errorName;
   init.mCancelable = true;
   init.mBubbles = true;
 
   nsEventStatus status = nsEventStatus_eIgnore;
 
   if (NS_IsMainThread()) {
-    if (nsIDOMWindow* window = eventTarget->GetOwnerGlobal()) {
+    nsCOMPtr<nsIDOMWindow> window = do_QueryInterface(eventTarget->GetOwnerGlobal());
+    if (window) {
       nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(window);
       MOZ_ASSERT(sgo);
 
       if (NS_WARN_IF(NS_FAILED(sgo->HandleScriptError(init, &status)))) {
         status = nsEventStatus_eIgnore;
       }
     } else {
       // We don't fire error events at any global for non-window JS on the main
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -2543,17 +2543,17 @@ ContentParent::RecvReadPrefsArray(Infall
     Preferences::GetPreferences(aPrefs);
     return true;
 }
 
 bool
 ContentParent::RecvReadFontList(InfallibleTArray<FontListEntry>* retValue)
 {
 #ifdef ANDROID
-    gfxAndroidPlatform::GetPlatform()->GetFontList(retValue);
+    gfxAndroidPlatform::GetPlatform()->GetSystemFontList(retValue);
 #endif
     return true;
 }
 
 bool
 ContentParent::RecvReadPermissions(InfallibleTArray<IPC::Permission>* aPermissions)
 {
 #ifdef MOZ_PERMISSIONS
new file mode 100644
--- /dev/null
+++ b/dom/media/test/crashtests/1122218.html
@@ -0,0 +1,24 @@
+<html>
+<head>
+<script>
+function boom() {
+  var r0=new AudioContext();
+
+  var cm=r0.createChannelMerger(20);
+
+  var o1=r0.createOscillator();
+  var o2=r0.createOscillator();
+
+  var pw=r0.createPeriodicWave(new Float32Array(4),new Float32Array(4));
+  o2.setPeriodicWave(pw);
+
+  o1.connect(cm);
+  cm.connect(o2.frequency);
+
+  o1.start();
+  o2.start(0.476);
+}
+</script>
+</head>
+<body onload="boom();"></body>
+</html>
--- a/dom/media/test/crashtests/crashtests.list
+++ b/dom/media/test/crashtests/crashtests.list
@@ -72,12 +72,13 @@ skip-if(Android||B2G) test-pref(media.na
 load buffer-source-ended-1.html
 HTTP load media-element-source-seek-1.html
 load offline-buffer-source-ended-1.html
 load oscillator-ended-1.html
 load oscillator-ended-2.html
 load 1080986.html
 load 1158427.html
 load 1157994.html
+load 1122218.html
 include ../../mediasource/test/crashtests/crashtests.list
 
 # This needs to run at the end to avoid leaking busted state into other tests.
 skip-if(B2G||winWidget||OSX==1006||OSX==1010&&isDebugBuild) load 691096-1.html
--- a/dom/media/webaudio/OscillatorNode.cpp
+++ b/dom/media/webaudio/OscillatorNode.cpp
@@ -298,17 +298,17 @@ public:
     }
 
     if (ticks >= mStop) {
       // We've finished playing.
       ComputeSilence(aOutput);
       *aFinished = true;
       return;
     }
-    if (ticks + WEBAUDIO_BLOCK_SIZE < mStart) {
+    if (ticks + WEBAUDIO_BLOCK_SIZE <= mStart) {
       // We're not playing yet.
       ComputeSilence(aOutput);
       return;
     }
 
     AllocateAudioBlock(1, aOutput);
     float* output = static_cast<float*>(
         const_cast<void*>(aOutput->mChannelData[0]));
--- a/dom/media/webspeech/synth/SpeechSynthesisUtterance.cpp
+++ b/dom/media/webspeech/synth/SpeechSynthesisUtterance.cpp
@@ -143,16 +143,22 @@ SpeechSynthesisUtterance::Pitch() const
 
 void
 SpeechSynthesisUtterance::SetPitch(float aPitch)
 {
   mPitch = aPitch;
 }
 
 void
+SpeechSynthesisUtterance::GetChosenVoiceURI(nsString& aResult) const
+{
+  aResult = mChosenVoiceURI;
+}
+
+void
 SpeechSynthesisUtterance::DispatchSpeechSynthesisEvent(const nsAString& aEventType,
                                                        uint32_t aCharIndex,
                                                        float aElapsedTime,
                                                        const nsAString& aName)
 {
   SpeechSynthesisEventInit init;
   init.mBubbles = false;
   init.mCancelable = false;
--- a/dom/media/webspeech/synth/SpeechSynthesisUtterance.h
+++ b/dom/media/webspeech/synth/SpeechSynthesisUtterance.h
@@ -66,16 +66,18 @@ public:
   float Rate() const;
 
   void SetRate(float aRate);
 
   float Pitch() const;
 
   void SetPitch(float aPitch);
 
+  void GetChosenVoiceURI(nsString& aResult) const;
+
   enum {
     STATE_NONE,
     STATE_PENDING,
     STATE_SPEAKING,
     STATE_ENDED
   };
 
   uint32_t GetState() { return mState; }
@@ -102,16 +104,18 @@ private:
   nsString mLang;
 
   float mVolume;
 
   float mRate;
 
   float mPitch;
 
+  nsString mChosenVoiceURI;
+
   uint32_t mState;
 
   bool mPaused;
 
   nsRefPtr<SpeechSynthesisVoice> mVoice;
 };
 
 } // namespace dom
--- a/dom/media/webspeech/synth/ipc/PSpeechSynthesisRequest.ipdl
+++ b/dom/media/webspeech/synth/ipc/PSpeechSynthesisRequest.ipdl
@@ -20,17 +20,17 @@ async protocol PSpeechSynthesisRequest
   Resume();
 
   Cancel();
 
  child:
 
   __delete__(bool aIsError, float aElapsedTime, uint32_t aCharIndex);
 
-  OnStart();
+  OnStart(nsString aUri);
 
   OnPause(float aElapsedTime, uint32_t aCharIndex);
 
   OnResume(float aElapsedTime, uint32_t aCharIndex);
 
   OnBoundary(nsString aName, float aElapsedTime, uint32_t aCharIndex);
 
   OnMark(nsString aName, float aElapsedTime, uint32_t aCharIndex);
--- a/dom/media/webspeech/synth/ipc/SpeechSynthesisChild.cpp
+++ b/dom/media/webspeech/synth/ipc/SpeechSynthesisChild.cpp
@@ -68,19 +68,19 @@ SpeechSynthesisRequestChild::SpeechSynth
 }
 
 SpeechSynthesisRequestChild::~SpeechSynthesisRequestChild()
 {
   MOZ_COUNT_DTOR(SpeechSynthesisRequestChild);
 }
 
 bool
-SpeechSynthesisRequestChild::RecvOnStart()
+SpeechSynthesisRequestChild::RecvOnStart(const nsString& aUri)
 {
-  mTask->DispatchStartImpl();
+  mTask->DispatchStartImpl(aUri);
   return true;
 }
 
 bool
 SpeechSynthesisRequestChild::Recv__delete__(const bool& aIsError,
                                             const float& aElapsedTime,
                                             const uint32_t& aCharIndex)
 {
--- a/dom/media/webspeech/synth/ipc/SpeechSynthesisChild.h
+++ b/dom/media/webspeech/synth/ipc/SpeechSynthesisChild.h
@@ -43,17 +43,17 @@ protected:
 
 class SpeechSynthesisRequestChild : public PSpeechSynthesisRequestChild
 {
 public:
   explicit SpeechSynthesisRequestChild(SpeechTaskChild* aTask);
   virtual ~SpeechSynthesisRequestChild();
 
 protected:
-  virtual bool RecvOnStart() override;
+  virtual bool RecvOnStart(const nsString& aUri) override;
 
   virtual bool Recv__delete__(const bool& aIsError,
                               const float& aElapsedTime,
                               const uint32_t& aCharIndex) override;
 
   virtual bool RecvOnPause(const float& aElapsedTime, const uint32_t& aCharIndex) override;
 
   virtual bool RecvOnResume(const float& aElapsedTime, const uint32_t& aCharIndex) override;
--- a/dom/media/webspeech/synth/ipc/SpeechSynthesisParent.cpp
+++ b/dom/media/webspeech/synth/ipc/SpeechSynthesisParent.cpp
@@ -115,20 +115,20 @@ SpeechSynthesisRequestParent::RecvCancel
   MOZ_ASSERT(mTask);
   mTask->Cancel();
   return true;
 }
 
 // SpeechTaskParent
 
 nsresult
-SpeechTaskParent::DispatchStartImpl()
+SpeechTaskParent::DispatchStartImpl(const nsAString& aUri)
 {
   MOZ_ASSERT(mActor);
-  NS_ENSURE_TRUE(mActor->SendOnStart(), NS_ERROR_FAILURE);
+  NS_ENSURE_TRUE(mActor->SendOnStart(nsString(aUri)), NS_ERROR_FAILURE);
 
   return NS_OK;
 }
 
 nsresult
 SpeechTaskParent::DispatchEndImpl(float aElapsedTime, uint32_t aCharIndex)
 {
   MOZ_ASSERT(mActor);
--- a/dom/media/webspeech/synth/ipc/SpeechSynthesisParent.h
+++ b/dom/media/webspeech/synth/ipc/SpeechSynthesisParent.h
@@ -70,17 +70,17 @@ protected:
 
 class SpeechTaskParent : public nsSpeechTask
 {
   friend class SpeechSynthesisRequestParent;
 public:
   SpeechTaskParent(float aVolume, const nsAString& aUtterance)
     : nsSpeechTask(aVolume, aUtterance) {}
 
-  virtual nsresult DispatchStartImpl();
+  virtual nsresult DispatchStartImpl(const nsAString& aUri);
 
   virtual nsresult DispatchEndImpl(float aElapsedTime, uint32_t aCharIndex);
 
   virtual nsresult DispatchPauseImpl(float aElapsedTime, uint32_t aCharIndex);
 
   virtual nsresult DispatchResumeImpl(float aElapsedTime, uint32_t aCharIndex);
 
   virtual nsresult DispatchErrorImpl(float aElapsedTime, uint32_t aCharIndex);
--- a/dom/media/webspeech/synth/nsSpeechTask.cpp
+++ b/dom/media/webspeech/synth/nsSpeechTask.cpp
@@ -135,16 +135,22 @@ nsSpeechTask::~nsSpeechTask()
 
 void
 nsSpeechTask::BindStream(ProcessedMediaStream* aStream)
 {
   mStream = MediaStreamGraph::GetInstance()->CreateSourceStream(nullptr);
   mPort = aStream->AllocateInputPort(mStream, 0);
 }
 
+void
+nsSpeechTask::SetChosenVoiceURI(const nsAString& aUri)
+{
+  mChosenVoiceURI = aUri;
+}
+
 NS_IMETHODIMP
 nsSpeechTask::Setup(nsISpeechTaskCallback* aCallback,
                     uint32_t aChannels, uint32_t aRate, uint8_t argc)
 {
   MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
 
   LOG(PR_LOG_DEBUG, ("nsSpeechTask::Setup"));
 
@@ -277,23 +283,30 @@ nsSpeechTask::DispatchStart()
   }
 
   return DispatchStartImpl();
 }
 
 nsresult
 nsSpeechTask::DispatchStartImpl()
 {
+  return DispatchStartImpl(mChosenVoiceURI);
+}
+
+nsresult
+nsSpeechTask::DispatchStartImpl(const nsAString& aUri)
+{
   LOG(PR_LOG_DEBUG, ("nsSpeechTask::DispatchStart"));
 
   MOZ_ASSERT(mUtterance);
   NS_ENSURE_TRUE(mUtterance->mState == SpeechSynthesisUtterance::STATE_PENDING,
                  NS_ERROR_NOT_AVAILABLE);
 
   mUtterance->mState = SpeechSynthesisUtterance::STATE_SPEAKING;
+  mUtterance->mChosenVoiceURI = aUri;
   mUtterance->DispatchSpeechSynthesisEvent(NS_LITERAL_STRING("start"), 0, 0,
                                            NS_LITERAL_STRING(""));
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsSpeechTask::DispatchEnd(float aElapsedTime, uint32_t aCharIndex)
--- a/dom/media/webspeech/synth/nsSpeechTask.h
+++ b/dom/media/webspeech/synth/nsSpeechTask.h
@@ -42,20 +42,24 @@ public:
   uint32_t GetCurrentCharOffset();
 
   void SetSpeechSynthesis(SpeechSynthesis* aSpeechSynthesis);
 
   void SetIndirectAudio(bool aIndirectAudio) { mIndirectAudio = aIndirectAudio; }
 
   void BindStream(ProcessedMediaStream* aStream);
 
+  void SetChosenVoiceURI(const nsAString& aUri);
+
 protected:
   virtual ~nsSpeechTask();
 
-  virtual nsresult DispatchStartImpl();
+  nsresult DispatchStartImpl();
+
+  virtual nsresult DispatchStartImpl(const nsAString& aUri);
 
   virtual nsresult DispatchEndImpl(float aElapsedTime, uint32_t aCharIndex);
 
   virtual nsresult DispatchPauseImpl(float aElapsedTime, uint32_t aCharIndex);
 
   virtual nsresult DispatchResumeImpl(float aElapsedTime, uint32_t aCharIndex);
 
   virtual nsresult DispatchErrorImpl(float aElapsedTime, uint32_t aCharIndex);
@@ -84,14 +88,16 @@ private:
 
   nsCOMPtr<nsISpeechTaskCallback> mCallback;
 
   uint32_t mChannels;
 
   nsRefPtr<SpeechSynthesis> mSpeechSynthesis;
 
   bool mIndirectAudio;
+
+  nsString mChosenVoiceURI;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif
--- a/dom/media/webspeech/synth/nsSynthVoiceRegistry.cpp
+++ b/dom/media/webspeech/synth/nsSynthVoiceRegistry.cpp
@@ -562,16 +562,18 @@ nsSynthVoiceRegistry::Speak(const nsAStr
   VoiceData* voice = FindBestMatch(aUri, aLang);
 
   if (!voice) {
     NS_WARNING("No voices found.");
     aTask->DispatchError(0, 0);
     return;
   }
 
+  aTask->SetChosenVoiceURI(voice->mUri);
+
   LOG(PR_LOG_DEBUG, ("nsSynthVoiceRegistry::Speak - Using voice URI: %s",
                      NS_ConvertUTF16toUTF8(voice->mUri).get()));
 
   SpeechServiceType serviceType;
 
   DebugOnly<nsresult> rv = voice->mService->GetServiceType(&serviceType);
   NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to get speech service type");
 
--- a/dom/media/webspeech/synth/pico/nsPicoService.cpp
+++ b/dom/media/webspeech/synth/pico/nsPicoService.cpp
@@ -12,17 +12,17 @@
 #include "nsISimpleEnumerator.h"
 
 #include "mozilla/dom/nsSynthVoiceRegistry.h"
 #include "mozilla/dom/nsSpeechTask.h"
 
 #include "nsIFile.h"
 #include "nsThreadUtils.h"
 #include "prenv.h"
-
+#include "mozilla/Preferences.h"
 #include "mozilla/DebugOnly.h"
 #include <dlfcn.h>
 
 // Pico API constants
 
 // Size of memory allocated for pico engine and voice resources.
 // We only have one voice and its resources loaded at once, so this
 // should always be enough.
@@ -448,16 +448,21 @@ nsPicoService::~nsPicoService()
 
 NS_IMETHODIMP
 nsPicoService::Observe(nsISupports* aSubject, const char* aTopic,
                        const char16_t* aData)
 {
   MOZ_ASSERT(NS_IsMainThread());
   NS_ENSURE_TRUE(!strcmp(aTopic, "profile-after-change"), NS_ERROR_UNEXPECTED);
 
+  if (!Preferences::GetBool("media.webspeech.synth.enabled") ||
+      Preferences::GetBool("media.webspeech.synth.test")) {
+    return NS_OK;
+  }
+
   DebugOnly<nsresult> rv = NS_NewNamedThread("Pico Worker", getter_AddRefs(mThread));
   MOZ_ASSERT(NS_SUCCEEDED(rv));
   return mThread->Dispatch(
     NS_NewRunnableMethod(this, &nsPicoService::Init), NS_DISPATCH_NORMAL);
 }
 // nsISpeechService
 
 NS_IMETHODIMP
--- a/dom/plugins/base/nsJSNPRuntime.cpp
+++ b/dom/plugins/base/nsJSNPRuntime.cpp
@@ -78,17 +78,17 @@ typedef js::HashMap<nsJSObjWrapperKey,
                     js::SystemAllocPolicy> JSObjWrapperTable;
 static JSObjWrapperTable sJSObjWrappers;
 
 // Whether it's safe to iterate sJSObjWrappers.  Set to true when sJSObjWrappers
 // has been initialized and is not currently being enumerated.
 static bool sJSObjWrappersAccessible = false;
 
 // Hash of NPObject wrappers that wrap NPObjects as JSObjects.
-static PLDHashTable sNPObjWrappers;
+static PLDHashTable* sNPObjWrappers;
 
 // Global wrapper count. This includes JSObject wrappers *and*
 // NPObject wrappers. When this count goes to zero, there are no more
 // wrappers and we can kill off hash tables etc.
 static int32_t sWrapperCount;
 
 // The runtime service used to register/unregister GC callbacks.
 nsCOMPtr<nsIJSRuntimeService> sCallbackRuntime;
@@ -396,33 +396,34 @@ DestroyJSObjWrapperTable()
   // hash to prevent leaking it.
   sJSObjWrappers.finish();
   sJSObjWrappersAccessible = false;
 }
 
 static bool
 CreateNPObjWrapperTable()
 {
-  MOZ_ASSERT(!sNPObjWrappers.IsInitialized());
+  MOZ_ASSERT(!sNPObjWrappers);
 
   if (!RegisterGCCallbacks()) {
     return false;
   }
 
-  PL_DHashTableInit(&sNPObjWrappers, PL_DHashGetStubOps(),
-                    sizeof(NPObjWrapperHashEntry));
+  sNPObjWrappers =
+    new PLDHashTable(PL_DHashGetStubOps(), sizeof(NPObjWrapperHashEntry));
   return true;
 }
 
 static void
 DestroyNPObjWrapperTable()
 {
-  MOZ_ASSERT(sNPObjWrappers.EntryCount() == 0);
-
-  PL_DHashTableFinish(&sNPObjWrappers);
+  MOZ_ASSERT(sNPObjWrappers->EntryCount() == 0);
+
+  delete sNPObjWrappers;
+  sNPObjWrappers = nullptr;
 }
 
 static void
 OnWrapperCreated()
 {
   ++sWrapperCount;
 }
 
@@ -431,17 +432,17 @@ OnWrapperDestroyed()
 {
   NS_ASSERTION(sWrapperCount, "Whaaa, unbalanced created/destroyed calls!");
 
   if (--sWrapperCount == 0) {
     if (sJSObjWrappersAccessible) {
       DestroyJSObjWrapperTable();
     }
 
-    if (sNPObjWrappers.IsInitialized()) {
+    if (sNPObjWrappers) {
       // No more wrappers, and our hash was initialized. Finish the
       // hash to prevent leaking it.
       DestroyNPObjWrapperTable();
     }
 
     UnregisterGCCallbacks();
   }
 }
@@ -1756,46 +1757,46 @@ NPObjWrapper_Convert(JSContext *cx, JS::
   return false;
 }
 
 static void
 NPObjWrapper_Finalize(js::FreeOp *fop, JSObject *obj)
 {
   NPObject *npobj = (NPObject *)::JS_GetPrivate(obj);
   if (npobj) {
-    if (sNPObjWrappers.IsInitialized()) {
-      PL_DHashTableRemove(&sNPObjWrappers, npobj);
+    if (sNPObjWrappers) {
+      PL_DHashTableRemove(sNPObjWrappers, npobj);
     }
   }
 
   if (!sDelayedReleases)
     sDelayedReleases = new nsTArray<NPObject*>;
   sDelayedReleases->AppendElement(npobj);
 }
 
 static void
 NPObjWrapper_ObjectMoved(JSObject *obj, const JSObject *old)
 {
   // The wrapper JSObject has been moved, so we need to update the entry in the
   // sNPObjWrappers hash table, if present.
 
-  if (!sNPObjWrappers.IsInitialized()) {
+  if (!sNPObjWrappers) {
     return;
   }
 
   NPObject *npobj = (NPObject *)::JS_GetPrivate(obj);
   if (!npobj) {
     return;
   }
 
   // Calling PL_DHashTableSearch() will not result in GC.
   JS::AutoSuppressGCAnalysis nogc;
 
   NPObjWrapperHashEntry *entry = static_cast<NPObjWrapperHashEntry *>
-    (PL_DHashTableSearch(&sNPObjWrappers, npobj));
+    (PL_DHashTableSearch(sNPObjWrappers, npobj));
   MOZ_ASSERT(entry && entry->mJSObj);
   MOZ_ASSERT(entry->mJSObj == old);
   entry->mJSObj = obj;
 }
 
 static bool
 NPObjWrapper_Call(JSContext *cx, unsigned argc, JS::Value *vp)
 {
@@ -1831,33 +1832,33 @@ nsNPObjWrapper::OnDestroy(NPObject *npob
   }
 
   if (npobj->_class == &nsJSObjWrapper::sJSObjWrapperNPClass) {
     // npobj is one of our own, no private data to clean up here.
 
     return;
   }
 
-  if (!sNPObjWrappers.IsInitialized()) {
+  if (!sNPObjWrappers) {
     // No hash yet (or any more), no used wrappers available.
 
     return;
   }
 
   NPObjWrapperHashEntry *entry = static_cast<NPObjWrapperHashEntry *>
-    (PL_DHashTableSearch(&sNPObjWrappers, npobj));
+    (PL_DHashTableSearch(sNPObjWrappers, npobj));
 
   if (entry && entry->mJSObj) {
     // Found a live NPObject wrapper, null out its JSObjects' private
     // data.
 
     ::JS_SetPrivate(entry->mJSObj, nullptr);
 
     // Remove the npobj from the hash now that it went away.
-    PL_DHashTableRawRemove(&sNPObjWrappers, entry);
+    PL_DHashTableRawRemove(sNPObjWrappers, entry);
 
     // The finalize hook will call OnWrapperDestroyed().
   }
 }
 
 // Look up or create a JSObject that wraps the NPObject npobj.
 
 // static
@@ -1881,25 +1882,25 @@ nsNPObjWrapper::GetNewOrUsed(NPP npp, JS
   }
 
   if (!npp) {
     NS_ERROR("No npp passed to nsNPObjWrapper::GetNewOrUsed()!");
 
     return nullptr;
   }
 
-  if (!sNPObjWrappers.IsInitialized()) {
+  if (!sNPObjWrappers) {
     // No hash yet (or any more), initialize it.
     if (!CreateNPObjWrapperTable()) {
       return nullptr;
     }
   }
 
   NPObjWrapperHashEntry *entry = static_cast<NPObjWrapperHashEntry *>
-    (PL_DHashTableAdd(&sNPObjWrappers, npobj, fallible));
+    (PL_DHashTableAdd(sNPObjWrappers, npobj, fallible));
 
   if (!entry) {
     // Out of memory
     JS_ReportOutOfMemory(cx);
 
     return nullptr;
   }
 
@@ -1911,34 +1912,34 @@ nsNPObjWrapper::GetNewOrUsed(NPP npp, JS
       return nullptr;
     }
     return obj;
   }
 
   entry->mNPObj = npobj;
   entry->mNpp = npp;
 
-  uint32_t generation = sNPObjWrappers.Generation();
+  uint32_t generation = sNPObjWrappers->Generation();
 
   // No existing JSObject, create one.
 
   JS::Rooted<JSObject*> obj(cx, ::JS_NewObject(cx, js::Jsvalify(&sNPObjectJSWrapperClass)));
 
-  if (generation != sNPObjWrappers.Generation()) {
+  if (generation != sNPObjWrappers->Generation()) {
       // Reload entry if the JS_NewObject call caused a GC and reallocated
       // the table (see bug 445229). This is guaranteed to succeed.
 
-      NS_ASSERTION(PL_DHashTableSearch(&sNPObjWrappers, npobj),
+      NS_ASSERTION(PL_DHashTableSearch(sNPObjWrappers, npobj),
                    "Hashtable didn't find what we just added?");
   }
 
   if (!obj) {
     // OOM? Remove the stale entry from the hash.
 
-    PL_DHashTableRawRemove(&sNPObjWrappers, entry);
+    PL_DHashTableRawRemove(sNPObjWrappers, entry);
 
     return nullptr;
   }
 
   OnWrapperCreated();
 
   entry->mJSObj = obj;
 
@@ -2034,19 +2035,19 @@ nsJSNPRuntime::OnPluginDestroy(NPP npp)
     }
 
     sJSObjWrappersAccessible = true;
   }
 
   // Use the safe JSContext here as we're not always able to find the
   // JSContext associated with the NPP any more.
   AutoSafeJSContext cx;
-  if (sNPObjWrappers.IsInitialized()) {
+  if (sNPObjWrappers) {
     NppAndCx nppcx = { npp, cx };
-    PL_DHashTableEnumerate(&sNPObjWrappers,
+    PL_DHashTableEnumerate(sNPObjWrappers,
                            NPObjWrapperPluginDestroyedCallback, &nppcx);
   }
 }
 
 // static
 void
 nsJSNPRuntime::OnPluginDestroyPending(NPP npp)
 {
@@ -2069,17 +2070,17 @@ static NPP
 LookupNPP(NPObject *npobj)
 {
   if (npobj->_class == &nsJSObjWrapper::sJSObjWrapperNPClass) {
     nsJSObjWrapper* o = static_cast<nsJSObjWrapper*>(npobj);
     return o->mNpp;
   }
 
   NPObjWrapperHashEntry *entry = static_cast<NPObjWrapperHashEntry *>
-    (PL_DHashTableAdd(&sNPObjWrappers, npobj, fallible));
+    (PL_DHashTableAdd(sNPObjWrappers, npobj, fallible));
 
   if (!entry) {
     return nullptr;
   }
 
   NS_ASSERTION(entry->mNpp, "Live NPObject entry w/o an NPP!");
 
   return entry->mNpp;
new file mode 100644
--- /dev/null
+++ b/dom/tests/unit/test_xhr_init.js
@@ -0,0 +1,16 @@
+function run_test()
+{
+    Components.utils.importGlobalProperties(["XMLHttpRequest"]);
+
+    var x = new XMLHttpRequest({mozAnon: true, mozSystem: false});
+    do_check_true(x.mozAnon);
+    do_check_true(x.mozSystem); // Because we're system principal
+
+    x = new XMLHttpRequest({mozAnon: true});
+    do_check_true(x.mozAnon);
+    do_check_true(x.mozSystem);
+
+    x = new XMLHttpRequest();
+    do_check_false(x.mozAnon);
+    do_check_true(x.mozSystem);
+}
--- a/dom/tests/unit/xpcshell.ini
+++ b/dom/tests/unit/xpcshell.ini
@@ -18,8 +18,9 @@ skip-if = os == "mac" || os == "android"
 skip-if = os == "android"
 [test_geolocation_reset_accuracy_wrap.js]
 skip-if = os == "mac" || os == "android"
 [test_geolocation_position_unavailable.js]
 skip-if = os == "android"
 [test_geolocation_position_unavailable_wrap.js]
 skip-if = os == "mac" || os == "android"
 [test_PromiseDebugging.js]
+[test_xhr_init.js]
--- a/dom/webidl/EventTarget.webidl
+++ b/dom/webidl/EventTarget.webidl
@@ -38,11 +38,11 @@ partial interface EventTarget {
   [ChromeOnly]
   EventHandler getEventHandler(DOMString type);
 };
 
 // Mozilla extension to make firing events on event targets from
 // chrome easier.  This returns the window which can be used to create
 // events to fire at this EventTarget, or null if there isn't one.
 partial interface EventTarget {
-  [ChromeOnly, Exposed=Window]
+  [ChromeOnly, Exposed=Window, BinaryName="ownerGlobalForBindings"]
   readonly attribute WindowProxy? ownerGlobal;
 };
--- a/dom/webidl/FontFaceSet.webidl
+++ b/dom/webidl/FontFaceSet.webidl
@@ -31,17 +31,17 @@ enum FontFaceSetLoadStatus { "loading", 
 // [Constructor(sequence<FontFace> initialFaces)]
 [Pref="layout.css.font-loading-api.enabled"]
 interface FontFaceSet : EventTarget {
 
   // Emulate setlike behavior until we can use that directly.
   readonly attribute unsigned long size;
   [Throws] void add(FontFace font);
   boolean has(FontFace font);
-  [Throws] boolean delete(FontFace font);
+  boolean delete(FontFace font);
   void clear();
   [NewObject] FontFaceSetIterator entries();
   // Iterator keys();
   [NewObject, Alias=keys, Alias="@@iterator"] FontFaceSetIterator values();
   [Throws] void forEach(FontFaceSetForEachCallback cb, optional any thisArg);
 
   // -- events for when loading state changes
   attribute EventHandler onloading;
--- a/dom/webidl/SpeechSynthesisUtterance.webidl
+++ b/dom/webidl/SpeechSynthesisUtterance.webidl
@@ -23,9 +23,12 @@ interface SpeechSynthesisUtterance : Eve
 
   attribute EventHandler onstart;
   attribute EventHandler onend;
   attribute EventHandler onerror;
   attribute EventHandler onpause;
   attribute EventHandler onresume;
   attribute EventHandler onmark;
   attribute EventHandler onboundary;
+
+  [ChromeOnly]
+  readonly attribute DOMString chosenVoiceURI;
 };
--- a/editor/libeditor/nsHTMLDataTransfer.cpp
+++ b/editor/libeditor/nsHTMLDataTransfer.cpp
@@ -1088,17 +1088,17 @@ nsresult nsHTMLEditor::InsertObject(cons
     AppendUTF8toUTF16(data64, stuffToPaste);
     stuffToPaste.AppendLiteral("\" alt=\"\" >");
     nsAutoEditBatch beginBatching(this);
     rv = DoInsertHTMLWithContext(stuffToPaste, EmptyString(), EmptyString(), 
                                  NS_LITERAL_STRING(kFileMime),
                                  aSourceDoc,
                                  aDestinationNode, aDestOffset,
                                  aDoDeleteSelection,
-                                 aIsSafe);
+                                 aIsSafe, false);
   }
 
   return NS_OK;
 }
 
 nsresult
 nsHTMLEditor::InsertFromTransferable(nsITransferable *transferable,
                                      nsIDOMDocument *aSourceDoc,
--- a/editor/libeditor/tests/chrome.ini
+++ b/editor/libeditor/tests/chrome.ini
@@ -20,16 +20,17 @@ skip-if = buildapp == 'mulet'
 [test_bug646194.xul]
 [test_bug780908.xul]
 [test_bug830600.html]
 [test_bug1053048.html]
 [test_bug1100966.html]
 [test_bug1102906.html]
 [test_bug1101392.html]
 [test_bug1140105.html]
+[test_bug1140617.xul]
 [test_bug1154791.html]
 [test_composition_event_created_in_chrome.html]
 [test_contenteditable_text_input_handling.html]
 [test_dragdrop.html]
 skip-if = buildapp == 'mulet'
 [test_htmleditor_keyevent_handling.html]
 [test_selection_move_commands.xul]
 [test_texteditor_keyevent_handling.html]
new file mode 100644
--- /dev/null
+++ b/editor/libeditor/tests/test_bug1140617.xul
@@ -0,0 +1,70 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin"
+                 type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+                 type="text/css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1140617
+-->
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        title="Mozilla Bug 1140617" onload="runTest();">
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+
+  <body xmlns="http://www.w3.org/1999/xhtml">
+  <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1140617"
+     target="_blank">Mozilla Bug 1140617</a>
+  <p/>
+  <iframe id="i1" width="200" height="100" src="about:blank" /><br />
+  <img id="i" src="green.png" />
+  <p/>
+  <pre id="test">
+  </pre>
+  </body>
+  <script class="testbody" type="application/javascript">
+  <![CDATA[
+
+function runTest() {
+  function pasteIntoAndCheck() {
+    var e = document.getElementById('i1');
+    var doc = e.contentDocument;
+    doc.designMode = "on";
+    doc.defaultView.focus();
+    var selection = doc.defaultView.getSelection();
+    selection.removeAllRanges();
+    selection.selectAllChildren(doc.body);
+    selection.collapseToEnd();
+
+    doc.execCommand("fontname", false, "Arial");
+    doc.execCommand("bold", false, null);
+    doc.execCommand("insertText", false, "12345");
+    doc.execCommand("paste", false, null);
+    doc.execCommand("insertText", false, "a");
+
+    is(doc.queryCommandValue("fontname"), "Arial", "Arial expected");
+    is(doc.queryCommandState("bold"), true, "Bold expected");
+  }
+
+  function copyToClipBoard() {
+    var tmpNode = document.popupNode;
+    document.popupNode = document.getElementById("i");
+
+    const kCmd = "cmd_copyImageContents";
+    var controller = top.document.commandDispatcher
+                     .getControllerForCommand(kCmd);
+    ok((controller && controller.isCommandEnabled(kCmd)), "have copy command");
+    controller.doCommand(kCmd);
+
+    document.popupNode = tmpNode;
+  }
+
+  copyToClipBoard();
+  pasteIntoAndCheck();
+
+  SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+]]>
+</script>
+</window>
--- a/embedding/browser/build/nsWebBrowserModule.cpp
+++ b/embedding/browser/build/nsWebBrowserModule.cpp
@@ -1,11 +1,11 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/ModuleUtils.h"
 #include "nsIServiceManager.h"
 #include "nsXPIDLString.h"
 
 #include "nsEmbedCID.h"
--- a/embedding/browser/nsCTooltipTextProvider.h
+++ b/embedding/browser/nsCTooltipTextProvider.h
@@ -1,9 +1,10 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* -*- 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 NSCTOOLTIPTEXTPROVIDER_H
 #define NSCTOOLTIPTEXTPROVIDER_H
 
 #include "nsITooltipTextProvider.h"
--- a/embedding/browser/nsCommandHandler.cpp
+++ b/embedding/browser/nsCommandHandler.cpp
@@ -1,11 +1,11 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsCommandHandler.h"
 #include "nsWebBrowser.h"
 #include "nsDocShellTreeOwner.h"
 
 #include "nsMemory.h"
--- a/embedding/browser/nsCommandHandler.h
+++ b/embedding/browser/nsCommandHandler.h
@@ -1,11 +1,11 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- 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 NSCOMMANDHANDLER_H
 #define NSCOMMANDHANDLER_H
 
 #include "nsISupports.h"
 #include "nsICommandHandler.h"
--- a/embedding/browser/nsContextMenuInfo.cpp
+++ b/embedding/browser/nsContextMenuInfo.cpp
@@ -1,9 +1,10 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsContextMenuInfo.h"
 
 #include "nsIImageLoadingContent.h"
 #include "imgLoader.h"
--- a/embedding/browser/nsContextMenuInfo.h
+++ b/embedding/browser/nsContextMenuInfo.h
@@ -1,11 +1,11 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- 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 nsContextMenuInfo_h__
 #define nsContextMenuInfo_h__
 
 #include "nsCOMPtr.h"
 #include "nsIContextMenuListener2.h"
--- a/embedding/browser/nsDocShellTreeOwner.cpp
+++ b/embedding/browser/nsDocShellTreeOwner.cpp
@@ -1,9 +1,10 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* -*- 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/. */
 
 // Local Includes
 #include "nsDocShellTreeOwner.h"
 #include "nsWebBrowser.h"
 
--- a/embedding/browser/nsDocShellTreeOwner.h
+++ b/embedding/browser/nsDocShellTreeOwner.h
@@ -1,11 +1,11 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- 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 nsDocShellTreeOwner_h__
 #define nsDocShellTreeOwner_h__
 
 // Helper Classes
 #include "nsAutoPtr.h"
--- a/embedding/browser/nsEmbedStream.cpp
+++ b/embedding/browser/nsEmbedStream.cpp
@@ -1,9 +1,10 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsIAsyncInputStream.h"
 #include "nsIAsyncOutputStream.h"
 #include "nsIDocShell.h"
 #include "nsIInterfaceRequestorUtils.h"
--- a/embedding/browser/nsEmbedStream.h
+++ b/embedding/browser/nsEmbedStream.h
@@ -1,9 +1,10 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* -*- 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 nsEmbedStream_h__
 #define nsEmbedStream_h__
 
 #include "nsCOMPtr.h"
--- a/embedding/browser/nsWebBrowserContentPolicy.cpp
+++ b/embedding/browser/nsWebBrowserContentPolicy.cpp
@@ -1,12 +1,11 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: ft=cpp tw=78 sw=4 et ts=8
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsWebBrowserContentPolicy.h"
 #include "nsIDocShell.h"
 #include "nsCOMPtr.h"
 #include "nsContentPolicyUtils.h"
 #include "nsIContentViewer.h"
--- a/embedding/browser/nsWebBrowserContentPolicy.h
+++ b/embedding/browser/nsWebBrowserContentPolicy.h
@@ -1,11 +1,11 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsIContentPolicy.h"
 
 /* f66bc334-1dd1-11b2-bab2-90e04fe15c19 */
 #define NS_WEBBROWSERCONTENTPOLICY_CID \
   { 0xf66bc334, 0x1dd1, 0x11b2, { 0xba, 0xb2, 0x90, 0xe0, 0x4f, 0xe1, 0x5c, 0x19 } }
--- a/embedding/components/commandhandler/nsBaseCommandController.cpp
+++ b/embedding/components/commandhandler/nsBaseCommandController.cpp
@@ -1,9 +1,10 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsString.h"
 #include "nsIComponentManager.h"
 #include "nsBaseCommandController.h"
 
--- a/embedding/components/commandhandler/nsBaseCommandController.h
+++ b/embedding/components/commandhandler/nsBaseCommandController.h
@@ -1,9 +1,10 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* -*- 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 nsBaseCommandController_h__
 #define nsBaseCommandController_h__
 
 #define NS_BASECOMMANDCONTROLLER_CID \
--- a/embedding/components/commandhandler/nsCommandGroup.cpp
+++ b/embedding/components/commandhandler/nsCommandGroup.cpp
@@ -1,9 +1,10 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsString.h"
 #include "nsReadableUtils.h"
 #include "nsTArray.h"
 #include "nsISimpleEnumerator.h"
--- a/embedding/components/commandhandler/nsCommandGroup.h
+++ b/embedding/components/commandhandler/nsCommandGroup.h
@@ -1,9 +1,10 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* -*- 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 nsCommandGroup_h__
 #define nsCommandGroup_h__
 
 #include "nsIController.h"
--- a/embedding/components/commandhandler/nsCommandManager.cpp
+++ b/embedding/components/commandhandler/nsCommandManager.cpp
@@ -1,9 +1,10 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsString.h"
 
 #include "nsIController.h"
 #include "nsIControllers.h"
--- a/embedding/components/commandhandler/nsCommandManager.h
+++ b/embedding/components/commandhandler/nsCommandManager.h
@@ -1,9 +1,10 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* -*- 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 nsCommandManager_h__
 #define nsCommandManager_h__
 
 #include "nsString.h"
--- a/embedding/components/commandhandler/nsControllerCommandTable.cpp
+++ b/embedding/components/commandhandler/nsControllerCommandTable.cpp
@@ -1,9 +1,10 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsString.h"
 #include "nsIControllerCommand.h"
 #include "nsControllerCommandTable.h"
 
--- a/embedding/components/commandhandler/nsControllerCommandTable.h
+++ b/embedding/components/commandhandler/nsControllerCommandTable.h
@@ -1,9 +1,10 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* -*- 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 nsControllerCommandTable_h_
 #define nsControllerCommandTable_h_
 
 #include "nsIControllerCommandTable.h"
--- a/embedding/components/find/nsFind.cpp
+++ b/embedding/components/find/nsFind.cpp
@@ -1,9 +1,10 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* -*- 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/. */
 
 //#define DEBUG_FIND 1
 
 #include "nsFind.h"
 #include "nsContentCID.h"
--- a/embedding/components/find/nsFind.h
+++ b/embedding/components/find/nsFind.h
@@ -1,9 +1,10 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* -*- 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 nsFind_h__
 #define nsFind_h__
 
 #include "nsIFind.h"
--- a/embedding/components/find/nsWebBrowserFind.cpp
+++ b/embedding/components/find/nsWebBrowserFind.cpp
@@ -1,11 +1,11 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsWebBrowserFind.h"
 
 // Only need this for NS_FIND_CONTRACTID,
 // else we could use nsIDOMRange.h and nsIFind.h.
 #include "nsFind.h"
--- a/embedding/components/find/nsWebBrowserFind.h
+++ b/embedding/components/find/nsWebBrowserFind.h
@@ -1,11 +1,11 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- 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 nsWebBrowserFindImpl_h__
 #define nsWebBrowserFindImpl_h__
 
 #include "nsIWebBrowserFind.h"
 
--- a/embedding/components/windowwatcher/nsAutoWindowStateHelper.cpp
+++ b/embedding/components/windowwatcher/nsAutoWindowStateHelper.cpp
@@ -1,9 +1,10 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsAutoWindowStateHelper.h"
 
 #include "mozilla/dom/Event.h"
 #include "nsIDocument.h"
--- a/embedding/components/windowwatcher/nsAutoWindowStateHelper.h
+++ b/embedding/components/windowwatcher/nsAutoWindowStateHelper.h
@@ -1,9 +1,10 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* -*- 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 __nsAutoWindowStateHelper_h
 #define __nsAutoWindowStateHelper_h
 
 #include "nsCOMPtr.h"
--- a/embedding/components/windowwatcher/nsDialogParamBlock.cpp
+++ b/embedding/components/windowwatcher/nsDialogParamBlock.cpp
@@ -1,9 +1,10 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsDialogParamBlock.h"
 #include "nsString.h"
 #include "nsReadableUtils.h"
 
--- a/embedding/components/windowwatcher/nsDialogParamBlock.h
+++ b/embedding/components/windowwatcher/nsDialogParamBlock.h
@@ -1,9 +1,10 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* -*- 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 __nsDialogParamBlock_h
 #define __nsDialogParamBlock_h
 
 #include "nsIDialogParamBlock.h"
--- a/embedding/components/windowwatcher/nsPromptUtils.h
+++ b/embedding/components/windowwatcher/nsPromptUtils.h
@@ -1,8 +1,10 @@
+/* -*- 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 NSPROMPTUTILS_H_
 #define NSPROMPTUTILS_H_
 
 #include "nsIHttpChannel.h"
--- a/embedding/components/windowwatcher/nsWindowWatcher.cpp
+++ b/embedding/components/windowwatcher/nsWindowWatcher.cpp
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=2 sw=2 et tw=78: */
+/* -*- 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/. */
 
 //#define USEWEAKREFS // (haven't quite figured that out yet)
 
 #include "nsWindowWatcher.h"
 #include "nsAutoWindowStateHelper.h"
--- a/embedding/components/windowwatcher/nsWindowWatcher.h
+++ b/embedding/components/windowwatcher/nsWindowWatcher.h
@@ -1,9 +1,10 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* -*- 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 __nsWindowWatcher_h__
 #define __nsWindowWatcher_h__
 
 // {a21bfa01-f349-4394-a84c-8de5cf0737d0}
--- a/gfx/2d/BorrowedContext.h
+++ b/gfx/2d/BorrowedContext.h
@@ -3,16 +3,21 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef _MOZILLA_GFX_BORROWED_CONTEXT_H
 #define _MOZILLA_GFX_BORROWED_CONTEXT_H
 
 #include "2D.h"
 
+#ifdef MOZ_X11
+#include <X11/extensions/Xrender.h>
+#include <X11/Xlib.h>
+#endif
+
 struct _cairo;
 typedef struct _cairo cairo_t;
 
 namespace mozilla {
 
 namespace gfx {
 
 /* This is a helper class that let's you borrow a cairo_t from a
@@ -64,16 +69,79 @@ public:
 
   cairo_t *mCairo;
 private:
   static cairo_t* BorrowCairoContextFromDrawTarget(DrawTarget *aDT);
   static void ReturnCairoContextToDrawTarget(DrawTarget *aDT, cairo_t *aCairo);
   DrawTarget *mDT;
 };
 
+#ifdef MOZ_X11
+/* This is a helper class that let's you borrow an Xlib drawable from
+ * a DrawTarget. This is used for drawing themed widgets.
+ *
+ * Callers should check the Xlib drawable after constructing the object
+ * to see if it succeeded. The DrawTarget should not be used while
+ * the drawable is borrowed. */
+class BorrowedXlibDrawable
+{
+public:
+  BorrowedXlibDrawable()
+    : mDT(nullptr),
+      mDisplay(nullptr),
+      mDrawable(None),
+      mScreen(nullptr),
+      mVisual(nullptr),
+      mXRenderFormat(nullptr)
+  {}
+
+  explicit BorrowedXlibDrawable(DrawTarget *aDT)
+    : mDT(nullptr),
+      mDisplay(nullptr),
+      mDrawable(None),
+      mScreen(nullptr),
+      mVisual(nullptr),
+      mXRenderFormat(nullptr)
+  {
+    Init(aDT);
+  }
+
+  // We can optionally Init after construction in
+  // case we don't know what the DT will be at construction
+  // time.
+  bool Init(DrawTarget *aDT);
+
+  // The caller needs to call Finish if drawable is non-zero when
+  // they are done with the context. This is currently explicit
+  // instead of happening implicitly in the destructor to make
+  // what's happening in the caller more clear. It also
+  // let's you resume using the DrawTarget in the same scope.
+  void Finish();
+
+  ~BorrowedXlibDrawable() {
+    MOZ_ASSERT(!mDrawable);
+  }
+
+  Display *GetDisplay() const { return mDisplay; }
+  Drawable GetDrawable() const { return mDrawable; }
+  Screen *GetScreen() const { return mScreen; }
+  Visual *GetVisual() const { return mVisual; }
+
+  XRenderPictFormat* GetXRenderFormat() const { return mXRenderFormat; }
+
+private:
+  DrawTarget *mDT;
+  Display *mDisplay;
+  Drawable mDrawable;
+  Screen *mScreen;
+  Visual *mVisual;
+  XRenderPictFormat *mXRenderFormat;
+};
+#endif
+
 #ifdef XP_MACOSX
 /* This is a helper class that let's you borrow a CGContextRef from a
  * DrawTargetCG. This is used for drawing themed widgets.
  *
  * Callers should check the cg member after constructing the object
  * to see if it succeeded. The DrawTarget should not be used while
  * the context is borrowed. */
 class BorrowedCGContext
--- a/gfx/2d/DrawTargetCairo.cpp
+++ b/gfx/2d/DrawTargetCairo.cpp
@@ -1709,10 +1709,55 @@ BorrowedCairoContext::ReturnCairoContext
     return;
   }
   DrawTargetCairo* cairoDT = static_cast<DrawTargetCairo*>(aDT);
 
   cairo_restore(aCairo);
   cairoDT->mContext = aCairo;
 }
 
+#ifdef MOZ_X11
+bool
+BorrowedXlibDrawable::Init(DrawTarget* aDT)
+{
+  MOZ_ASSERT(aDT, "Caller should check for nullptr");
+  MOZ_ASSERT(!mDT, "Can't initialize twice!");
+  mDT = aDT;
+  mDrawable = None;
+
+#ifdef CAIRO_HAS_XLIB_SURFACE
+  if (aDT->GetBackendType() != BackendType::CAIRO ||
+      aDT->IsDualDrawTarget() ||
+      aDT->IsTiledDrawTarget()) {
+    return false;
+  }
+
+  DrawTargetCairo* cairoDT = static_cast<DrawTargetCairo*>(aDT);
+  cairo_surface_t* surf = cairoDT->mSurface;
+  if (cairo_surface_get_type(surf) != CAIRO_SURFACE_TYPE_XLIB) {
+    return false;
+  }
+
+  cairoDT->WillChange();
+
+  mDisplay = cairo_xlib_surface_get_display(surf);
+  mDrawable = cairo_xlib_surface_get_drawable(surf);
+  mScreen = cairo_xlib_surface_get_screen(surf);
+  mVisual = cairo_xlib_surface_get_visual(surf);
+  mXRenderFormat = cairo_xlib_surface_get_xrender_format(surf);
+
+  return true;
+#else
+  return false;
+#endif
+}
+
+void
+BorrowedXlibDrawable::Finish()
+{
+  if (mDrawable) {
+    mDrawable = None;
+  }
+}
+#endif
+
 }
 }
--- a/gfx/2d/DrawTargetCairo.h
+++ b/gfx/2d/DrawTargetCairo.h
@@ -49,16 +49,17 @@ class GradientStopsCairo : public Gradie
     ExtendMode mExtendMode;
 };
 
 class DrawTargetCairo final : public DrawTarget
 {
 public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawTargetCairo, override)
   friend class BorrowedCairoContext;
+  friend class BorrowedXlibDrawable;
 
   DrawTargetCairo();
   virtual ~DrawTargetCairo();
 
   virtual DrawTargetType GetType() const override;
   virtual BackendType GetBackendType() const override { return BackendType::CAIRO; }
   virtual TemporaryRef<SourceSurface> Snapshot() override;
   virtual IntSize GetSize() override;
--- a/gfx/2d/DrawTargetSkia.cpp
+++ b/gfx/2d/DrawTargetSkia.cpp
@@ -143,16 +143,45 @@ DrawTargetSkia::Snapshot()
     mSnapshot = snapshot;
     if (!snapshot->InitFromCanvas(mCanvas.get(), mFormat, this))
       return nullptr;
   }
 
   return snapshot.forget();
 }
 
+bool
+DrawTargetSkia::LockBits(uint8_t** aData, IntSize* aSize,
+                          int32_t* aStride, SurfaceFormat* aFormat)
+{
+  const SkBitmap &bitmap = mCanvas->getDevice()->accessBitmap(false);
+  if (!bitmap.lockPixelsAreWritable()) {
+    return false;
+  }
+
+  MarkChanged();
+
+  bitmap.lockPixels();
+  *aData = reinterpret_cast<uint8_t*>(bitmap.getPixels());
+  *aSize = IntSize(bitmap.width(), bitmap.height());
+  *aStride = int32_t(bitmap.rowBytes());
+  *aFormat = SkiaColorTypeToGfxFormat(bitmap.colorType());
+  return true;
+}
+
+void
+DrawTargetSkia::ReleaseBits(uint8_t* aData)
+{
+  const SkBitmap &bitmap = mCanvas->getDevice()->accessBitmap(false);
+  MOZ_ASSERT(bitmap.lockPixelsAreWritable());
+
+  bitmap.unlockPixels();
+  bitmap.notifyPixelsChanged();
+}
+
 static void
 SetPaintPattern(SkPaint& aPaint, const Pattern& aPattern, TempBitmap& aTmpBitmap,
                 Float aAlpha = 1.0)
 {
   switch (aPattern.GetType()) {
     case PatternType::COLOR: {
       Color color = static_cast<const ColorPattern&>(aPattern).mColor;
       aPaint.setColor(ColorToSkColor(color, aAlpha));
@@ -683,20 +712,20 @@ DrawTargetSkia::CreateSourceSurfaceFromN
     if (aSurface.mSize.width <= 0 ||
         aSurface.mSize.height <= 0) {
       gfxWarning() << "Can't create a SourceSurface without a valid size";
       return nullptr;
     }
     cairo_surface_t* surf = static_cast<cairo_surface_t*>(aSurface.mSurface);
     return new SourceSurfaceCairo(surf, aSurface.mSize, aSurface.mFormat);
 #if USE_SKIA_GPU
-  } else if (aSurface.mType == NativeSurfaceType::OPENGL_TEXTURE) {
+  } else if (aSurface.mType == NativeSurfaceType::OPENGL_TEXTURE && UsingSkiaGPU()) {
     RefPtr<SourceSurfaceSkia> newSurf = new SourceSurfaceSkia();
     unsigned int texture = (unsigned int)((uintptr_t)aSurface.mSurface);
-    if (UsingSkiaGPU() && newSurf->InitFromTexture((DrawTargetSkia*)this, texture, aSurface.mSize, aSurface.mFormat)) {
+    if (newSurf->InitFromTexture((DrawTargetSkia*)this, texture, aSurface.mSize, aSurface.mFormat)) {
       return newSurf;
     }
     return nullptr;
 #endif
   }
 
   return nullptr;
 }
--- a/gfx/2d/DrawTargetSkia.h
+++ b/gfx/2d/DrawTargetSkia.h
@@ -31,16 +31,19 @@ public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawTargetSkia, override)
   DrawTargetSkia();
   virtual ~DrawTargetSkia();
 
   virtual DrawTargetType GetType() const override;
   virtual BackendType GetBackendType() const override { return BackendType::SKIA; }
   virtual TemporaryRef<SourceSurface> Snapshot() override;
   virtual IntSize GetSize() override { return mSize; }
+  virtual bool LockBits(uint8_t** aData, IntSize* aSize,
+                        int32_t* aStride, SurfaceFormat* aFormat) override;
+  virtual void ReleaseBits(uint8_t* aData) override;
   virtual void Flush() override;
   virtual void DrawSurface(SourceSurface *aSurface,
                            const Rect &aDest,
                            const Rect &aSource,
                            const DrawSurfaceOptions &aSurfOptions = DrawSurfaceOptions(),
                            const DrawOptions &aOptions = DrawOptions()) override;
   virtual void DrawFilter(FilterNode *aNode,
                           const Rect &aSourceRect,
--- a/gfx/2d/moz.build
+++ b/gfx/2d/moz.build
@@ -74,16 +74,17 @@ if CONFIG['MOZ_ENABLE_SKIA']:
         'DrawTargetSkia.cpp',
         'PathSkia.cpp',
         'SourceSurfaceSkia.cpp',
     ]
     SOURCES += [
         'image_operations.cpp', # Uses _USE_MATH_DEFINES
     ]
     EXPORTS.mozilla.gfx += [
+        'HelpersCairo.h',
         'HelpersSkia.h',
     ]
 
 # Are we targeting x86 or x64?  If so, build SSE2 files.
 if CONFIG['INTEL_ARCHITECTURE']:
     SOURCES += [
         'BlurSSE2.cpp',
         'FilterProcessingSSE2.cpp',
--- a/gfx/cairo/cairo/src/cairo-rename.h
+++ b/gfx/cairo/cairo/src/cairo-rename.h
@@ -9,21 +9,54 @@
 #define cairo_clip_preserve _moz_cairo_clip_preserve
 #define cairo_close_path _moz_cairo_close_path
 #define cairo_copy_clip_rectangle_list _moz_cairo_copy_clip_rectangle_list
 #define cairo_copy_page _moz_cairo_copy_page
 #define cairo_copy_path _moz_cairo_copy_path
 #define cairo_copy_path_flat _moz_cairo_copy_path_flat
 #define cairo_create _moz_cairo_create
 #define cairo_curve_to _moz_cairo_curve_to
+#define cairo_d2d_create_device _moz_cairo_d2d_create_device
+#define cairo_d2d_create_device_from_d3d10device _moz_cairo_d2d_create_device_from_d3d10device
+#define cairo_d2d_device_get_device _moz_cairo_d2d_device_get_device
+#define cairo_d2d_get_dc _moz_cairo_d2d_get_dc
+#define cairo_d2d_get_image_surface_cache_usage _moz_cairo_d2d_get_image_surface_cache_usage
+#define cairo_d2d_get_surface_vram_usage _moz_cairo_d2d_get_surface_vram_usage
+#define cairo_d2d_present_backbuffer _moz_cairo_d2d_present_backbuffer
+#define cairo_d2d_release_dc _moz_cairo_d2d_release_dc
+#define cairo_d2d_scroll _moz_cairo_d2d_scroll
+#define cairo_d2d_surface_create _moz_cairo_d2d_surface_create
+#define cairo_d2d_surface_create_for_handle _moz_cairo_d2d_surface_create_for_handle
+#define cairo_d2d_surface_create_for_hwnd _moz_cairo_d2d_surface_create_for_hwnd
+#define cairo_d2d_surface_create_for_texture _moz_cairo_d2d_surface_create_for_texture
+#define cairo_d2d_surface_get_height _moz_cairo_d2d_surface_get_height
+#define cairo_d2d_surface_get_texture _moz_cairo_d2d_surface_get_texture
+#define cairo_d2d_surface_get_width _moz_cairo_d2d_surface_get_width
 #define cairo_debug_reset_static_data _moz_cairo_debug_reset_static_data
 #define cairo_destroy _moz_cairo_destroy
+#define cairo_device_acquire _moz_cairo_device_acquire
+#define cairo_device_destroy _moz_cairo_device_destroy
+#define cairo_device_finish _moz_cairo_device_finish
+#define cairo_device_flush _moz_cairo_device_flush
+#define cairo_device_get_reference_count _moz_cairo_device_get_reference_count
+#define cairo_device_get_type _moz_cairo_device_get_type
+#define cairo_device_get_user_data _moz_cairo_device_get_user_data
+#define cairo_device_release _moz_cairo_device_release
+#define cairo_device_set_user_data _moz_cairo_device_set_user_data
+#define cairo_device_status _moz_cairo_device_status
+#define cairo_device_reference _moz_cairo_device_reference
 #define cairo_device_to_user _moz_cairo_device_to_user
 #define cairo_device_to_user_distance _moz_cairo_device_to_user_distance
 #define cairo_directfb_surface_create _moz_cairo_directfb_surface_create
+#define cairo_dwrite_font_face_create_for_dwrite_fontface _moz_cairo_dwrite_font_face_create_for_dwrite_fontface
+#define cairo_dwrite_get_cleartype_rendering_mode _moz_cairo_dwrite_get_cleartype_rendering_mode
+#define cairo_dwrite_scaled_font_allow_manual_show_glyphs _moz_cairo_dwrite_scaled_font_allow_manual_show_glyphs
+#define cairo_dwrite_scaled_font_get_force_GDI_classic _moz_cairo_dwrite_scaled_font_get_force_GDI_classic
+#define cairo_dwrite_scaled_font_set_force_GDI_classic _moz_cairo_dwrite_scaled_font_set_force_GDI_classic
+#define cairo_dwrite_set_cleartype_params _moz_cairo_dwrite_set_cleartype_params
 #define cairo_fill _moz_cairo_fill
 #define cairo_fill_extents _moz_cairo_fill_extents
 #define cairo_fill_preserve _moz_cairo_fill_preserve
 #define cairo_font_extents _moz_cairo_font_extents
 #define cairo_font_face_destroy _moz_cairo_font_face_destroy
 #define cairo_font_face_get_reference_count _moz_cairo_font_face_get_reference_count
 #define cairo_font_face_get_type _moz_cairo_font_face_get_type
 #define cairo_font_face_get_user_data _moz_cairo_font_face_get_user_data
@@ -107,16 +140,17 @@
 #define cairo_matrix_rotate _moz_cairo_matrix_rotate
 #define cairo_matrix_scale _moz_cairo_matrix_scale
 #define cairo_matrix_transform_distance _moz_cairo_matrix_transform_distance
 #define cairo_matrix_transform_point _moz_cairo_matrix_transform_point
 #define cairo_matrix_translate _moz_cairo_matrix_translate
 #define cairo_move_to _moz_cairo_move_to
 #define cairo_new_path _moz_cairo_new_path
 #define cairo_new_sub_path _moz_cairo_new_sub_path
+#define cairo_null_surface_create _moz_cairo_null_surface_create
 #define cairo_os2_fini _moz_cairo_os2_fini
 #define cairo_os2_init _moz_cairo_os2_init
 #define cairo_os2_surface_create _moz_cairo_os2_surface_create
 #define cairo_os2_surface_create_for_window _moz_cairo_os2_surface_create_for_window
 #define cairo_os2_surface_get_hps _moz_cairo_os2_surface_get_hps
 #define cairo_os2_surface_get_manual_window_refresh _moz_cairo_os2_surface_get_manual_window_refresh
 #define cairo_os2_surface_refresh_window _moz_cairo_os2_surface_refresh_window
 #define cairo_os2_surface_set_hps _moz_cairo_os2_surface_set_hps
@@ -210,19 +244,22 @@
 #define cairo_region_num_rectangles _moz_cairo_region_num_rectangles
 #define cairo_region_reference _moz_cairo_region_reference
 #define cairo_region_status _moz_cairo_region_status
 #define cairo_region_subtract _moz_cairo_region_subtract
 #define cairo_region_subtract_rectangle _moz_cairo_region_subtract_rectangle
 #define cairo_region_translate _moz_cairo_region_translate
 #define cairo_region_union _moz_cairo_region_union
 #define cairo_region_union_rectangle _moz_cairo_region_union_rectangle
+#define cairo_region_xor _moz_cairo_region_xor
+#define cairo_region_xor_rectangle _moz_cairo_region_xor_rectangle
 #define cairo_rel_curve_to _moz_cairo_rel_curve_to
 #define cairo_rel_line_to _moz_cairo_rel_line_to
 #define cairo_rel_move_to _moz_cairo_rel_move_to
+#define cairo_release_device _moz_cairo_release_device
 #define cairo_reset_clip _moz_cairo_reset_clip
 #define cairo_restore _moz_cairo_restore
 #define cairo_rotate _moz_cairo_rotate
 #define cairo_save _moz_cairo_save
 #define cairo_scale _moz_cairo_scale
 #define cairo_scaled_font_create _moz_cairo_scaled_font_create
 #define cairo_scaled_font_destroy _moz_cairo_scaled_font_destroy
 #define cairo_scaled_font_extents _moz_cairo_scaled_font_extents
@@ -266,22 +303,26 @@
 #define cairo_show_text _moz_cairo_show_text
 #define cairo_show_text_glyphs _moz_cairo_show_text_glyphs
 #define cairo_status _moz_cairo_status
 #define cairo_status_to_string _moz_cairo_status_to_string
 #define cairo_stroke _moz_cairo_stroke
 #define cairo_stroke_extents _moz_cairo_stroke_extents
 #define cairo_stroke_preserve _moz_cairo_stroke_preserve
 #define cairo_stroke_to_path _moz_cairo_stroke_to_path
+#define cairo_surface_attach_snapshot _moz_cairo_surface_attach_snapshot
 #define cairo_surface_copy_page _moz_cairo_surface_copy_page
+#define cairo_surface_create_for_rectangle _moz_cairo_surface_create_for_rectangle
 #define cairo_surface_create_similar _moz_cairo_surface_create_similar
+#define cairo_surface_detach_snapshot _moz_cairo_surface_detach_snapshot
 #define cairo_surface_destroy _moz_cairo_surface_destroy
 #define cairo_surface_finish _moz_cairo_surface_finish
 #define cairo_surface_flush _moz_cairo_surface_flush
 #define cairo_surface_get_content _moz_cairo_surface_get_content
+#define cairo_surface_get_device _moz_cairo_surface_get_device
 #define cairo_surface_get_device_offset _moz_cairo_surface_get_device_offset
 #define cairo_surface_get_fallback_resolution _moz_cairo_surface_get_fallback_resolution
 #define cairo_surface_get_font_options _moz_cairo_surface_get_font_options
 #define cairo_surface_get_mime_data _moz_cairo_surface_get_mime_data
 #define cairo_surface_get_reference_count _moz_cairo_surface_get_reference_count
 #define cairo_surface_get_subpixel_antialiasing _moz_cairo_surface_get_subpixel_antialiasing
 #define cairo_surface_get_type _moz_cairo_surface_get_type
 #define cairo_surface_get_user_data _moz_cairo_surface_get_user_data
@@ -325,31 +366,37 @@
 #define cairo_user_font_face_set_init_func _moz_cairo_user_font_face_set_init_func
 #define cairo_user_font_face_set_render_glyph_func _moz_cairo_user_font_face_set_render_glyph_func
 #define cairo_user_font_face_set_text_to_glyphs_func _moz_cairo_user_font_face_set_text_to_glyphs_func
 #define cairo_user_font_face_set_unicode_to_glyph_func _moz_cairo_user_font_face_set_unicode_to_glyph_func
 #define cairo_user_to_device _moz_cairo_user_to_device
 #define cairo_user_to_device_distance _moz_cairo_user_to_device_distance
 #define cairo_version _moz_cairo_version
 #define cairo_version_string _moz_cairo_version_string
+#define cairo_win32_get_dc_with_clip _moz_cairo_win32_get_dc_with_clip
+#define cairo_win32_get_system_text_quality _moz_cairo_win32_get_system_text_quality
 #define cairo_win32_font_face_create_for_hfont _moz_cairo_win32_font_face_create_for_hfont
 #define cairo_win32_font_face_create_for_logfontw _moz_cairo_win32_font_face_create_for_logfontw
 #define cairo_win32_font_face_create_for_logfontw_hfont _moz_cairo_win32_font_face_create_for_logfontw_hfont
 #define cairo_win32_printing_surface_create _moz_cairo_win32_printing_surface_create
 #define cairo_win32_scaled_font_done_font _moz_cairo_win32_scaled_font_done_font
 #define cairo_win32_scaled_font_get_device_to_logical _moz_cairo_win32_scaled_font_get_device_to_logical
 #define cairo_win32_scaled_font_get_logical_to_device _moz_cairo_win32_scaled_font_get_logical_to_device
 #define cairo_win32_scaled_font_get_metrics_factor _moz_cairo_win32_scaled_font_get_metrics_factor
 #define cairo_win32_scaled_font_select_font _moz_cairo_win32_scaled_font_select_font
 #define cairo_win32_surface_create _moz_cairo_win32_surface_create
+#define cairo_win32_surface_create_with_alpha _moz_cairo_win32_surface_create_with_alpha
 #define cairo_win32_surface_create_with_d3dsurface9 _moz_cairo_win32_surface_create_with_d3dsurface9
 #define cairo_win32_surface_create_with_ddb _moz_cairo_win32_surface_create_with_ddb
 #define cairo_win32_surface_create_with_dib _moz_cairo_win32_surface_create_with_dib
 #define cairo_win32_surface_get_dc _moz_cairo_win32_surface_get_dc
+#define cairo_win32_surface_get_height _moz_cairo_win32_surface_get_height
 #define cairo_win32_surface_get_image _moz_cairo_win32_surface_get_image
+#define cairo_win32_surface_get_width _moz_cairo_win32_surface_get_width
+#define cairo_win32_surface_set_can_convert_to_dib _moz_cairo_win32_surface_set_can_convert_to_dib
 #define cairo_xcb_surface_create _moz_cairo_xcb_surface_create
 #define cairo_xcb_surface_create_for_bitmap _moz_cairo_xcb_surface_create_for_bitmap
 #define cairo_xcb_surface_create_with_xrender_format _moz_cairo_xcb_surface_create_with_xrender_format
 #define cairo_xcb_surface_set_size _moz_cairo_xcb_surface_set_size
 #define cairo_xlib_surface_create _moz_cairo_xlib_surface_create
 #define cairo_xlib_surface_create_for_bitmap _moz_cairo_xlib_surface_create_for_bitmap
 #define cairo_xlib_surface_create_with_xrender_format _moz_cairo_xlib_surface_create_with_xrender_format
 #define cairo_xlib_surface_get_depth _moz_cairo_xlib_surface_get_depth
@@ -357,9 +404,8 @@
 #define cairo_xlib_surface_get_drawable _moz_cairo_xlib_surface_get_drawable
 #define cairo_xlib_surface_get_height _moz_cairo_xlib_surface_get_height
 #define cairo_xlib_surface_get_screen _moz_cairo_xlib_surface_get_screen
 #define cairo_xlib_surface_get_visual _moz_cairo_xlib_surface_get_visual
 #define cairo_xlib_surface_get_width _moz_cairo_xlib_surface_get_width
 #define cairo_xlib_surface_get_xrender_format _moz_cairo_xlib_surface_get_xrender_format
 #define cairo_xlib_surface_set_drawable _moz_cairo_xlib_surface_set_drawable
 #define cairo_xlib_surface_set_size _moz_cairo_xlib_surface_set_size
-#include "pixman-rename.h"
--- a/gfx/cairo/cairo/src/pixman-rename.h
+++ b/gfx/cairo/cairo/src/pixman-rename.h
@@ -1,9 +1,20 @@
 #ifdef MOZ_TREE_PIXMAN
+#define pixman_composite_glyphs _moz_pixman_composite_glyphs
+#define pixman_composite_glyphs_no_mask _moz_pixman_composite_glyphs_no_mask
+#define pixman_glyph_cache_create _moz_pixman_glyph_cache_create
+#define pixman_glyph_cache_destroy _moz_pixman_glyph_cache_destroy
+#define pixman_glyph_cache_freeze _moz_pixman_glyph_cache_freeze
+#define pixman_glyph_cache_insert _moz_pixman_glyph_cache_insert
+#define pixman_glyph_cache_lookup _moz_pixman_glyph_cache_lookup
+#define pixman_glyph_cache_remove _moz_pixman_glyph_cache_remove
+#define pixman_glyph_cache_thaw _moz_pixman_glyph_cache_thaw
+#define pixman_glyph_get_extents _moz_pixman_glyph_get_extents
+#define pixman_glyph_get_mask_format _moz_pixman_glyph_get_mask_format
 #define pixman_region_set_static_pointers _moz_pixman_region_set_static_pointers
 #define pixman_region_init _moz_pixman_region_init
 #define pixman_region_init_rect _moz_pixman_region_init_rect
 #define pixman_region_init_rects _moz_pixman_region_init_rects
 #define pixman_region_init_with_extents _moz_pixman_region_init_with_extents
 #define pixman_region_fini _moz_pixman_region_fini
 #define pixman_region_translate _moz_pixman_region_translate
 #define pixman_region_copy _moz_pixman_region_copy
@@ -16,16 +27,18 @@
 #define pixman_region_contains_rectangle _moz_pixman_region_contains_rectangle
 #define pixman_region_not_empty _moz_pixman_region_not_empty
 #define pixman_region_extents _moz_pixman_region_extents
 #define pixman_region_n_rects _moz_pixman_region_n_rects
 #define pixman_region_rectangles _moz_pixman_region_rectangles
 #define pixman_region_equal _moz_pixman_region_equal
 #define pixman_region_selfcheck _moz_pixman_region_selfcheck
 #define pixman_region_reset _moz_pixman_region_reset
+#define pixman_region_clear _moz_pixman_region_clear
+#define pixman_region_print _moz_pixman_region_print
 #define pixman_region32_init _moz_pixman_region32_init
 #define pixman_region32_init_rect _moz_pixman_region32_init_rect
 #define pixman_region32_init_rects _moz_pixman_region32_init_rects
 #define pixman_region32_init_with_extents _moz_pixman_region32_init_with_extents
 #define pixman_region32_init_from_image _moz_pixman_region32_init_from_image
 #define pixman_region32_fini _moz_pixman_region32_fini
 #define pixman_region32_translate _moz_pixman_region32_translate
 #define pixman_region32_copy _moz_pixman_region32_copy
@@ -40,16 +53,17 @@
 #define pixman_region32_not_empty _moz_pixman_region32_not_empty
 #define pixman_region32_extents _moz_pixman_region32_extents
 #define pixman_region32_n_rects _moz_pixman_region32_n_rects
 #define pixman_region32_rectangles _moz_pixman_region32_rectangles
 #define pixman_region32_equal _moz_pixman_region32_equal
 #define pixman_region32_selfcheck _moz_pixman_region32_selfcheck
 #define pixman_region32_reset _moz_pixman_region32_reset
 #define pixman_region32_clear _moz_pixman_region32_clear
+#define pixman_region32_print _moz_pixman_region32_print
 #define pixman_blt _moz_pixman_blt
 #define pixman_fill _moz_pixman_fill
 #define pixman_transform_point_3d _moz_pixman_transform_point_3d
 #define pixman_version _moz_pixman_version
 #define pixman_version_string _moz_pixman_version_string
 #define pixman_format_supported_destination _moz_pixman_format_supported_destination
 #define pixman_format_supported_source _moz_pixman_format_supported_source
 #define pixman_image_create_solid_fill _moz_pixman_image_create_solid_fill
@@ -81,16 +95,19 @@
 #define pixman_sample_ceil_y _moz_pixman_sample_ceil_y
 #define pixman_sample_floor_y _moz_pixman_sample_floor_y
 #define pixman_edge_step _moz_pixman_edge_step
 #define pixman_edge_init _moz_pixman_edge_init
 #define pixman_line_fixed_edge_init _moz_pixman_line_fixed_edge_init
 #define pixman_rasterize_edges _moz_pixman_rasterize_edges
 #define pixman_add_traps _moz_pixman_add_traps
 #define pixman_add_trapezoids _moz_pixman_add_trapezoids
+#define pixman_add_triangles _moz_pixman_add_triangles
+#define pixman_composite_trapezoids _moz_pixman_composite_trapezoids
+#define pixman_composite_triangles _moz_pixman_composite_triangles
 #define pixman_rasterize_trapezoid _moz_pixman_rasterize_trapezoid
 #define pixman_disable_out_of_bounds_workaround _moz_pixman_disable_out_of_bounds_workaround
 #define pixman_f_transform_bounds _moz_pixman_f_transform_bounds
 #define pixman_f_transform_from_pixman_transform _moz_pixman_f_transform_from_pixman_transform
 #define pixman_f_transform_init_identity _moz_pixman_f_transform_init_identity
 #define pixman_f_transform_init_rotate _moz_pixman_f_transform_init_rotate
 #define pixman_f_transform_init_scale _moz_pixman_f_transform_init_scale
 #define pixman_f_transform_init_translate _moz_pixman_f_transform_init_translate
--- a/gfx/layers/basic/BasicCompositor.cpp
+++ b/gfx/layers/basic/BasicCompositor.cpp
@@ -512,17 +512,17 @@ BasicCompositor::BeginFrame(const nsIntR
     return;
   }
 
   // Setup an intermediate render target to buffer all compositing. We will
   // copy this into mDrawTarget (the widget), and/or mTarget in EndFrame()
   RefPtr<CompositingRenderTarget> target = CreateRenderTarget(mInvalidRect, INIT_MODE_CLEAR);
   if (!target) {
     if (!mTarget) {
-      mWidget->EndRemoteDrawing();
+      mWidget->EndRemoteDrawingInRegion(mDrawTarget, mInvalidRegion);
     }
     return;
   }
   SetRenderTarget(target);
 
   // We only allocate a surface sized to the invalidated region, so we need to
   // translate future coordinates.
   mRenderTarget->mDrawTarget->SetTransform(Matrix::Translation(-invalidRect.x,
@@ -574,17 +574,17 @@ BasicCompositor::EndFrame()
   // pixels.
   nsIntRegionRectIterator iter(mInvalidRegion);
   for (const IntRect *r = iter.Next(); r; r = iter.Next()) {
     dest->CopySurface(source,
                       IntRect(r->x - mInvalidRect.x, r->y - mInvalidRect.y, r->width, r->height),
                       IntPoint(r->x - offset.x, r->y - offset.y));
   }
   if (!mTarget) {
-    mWidget->EndRemoteDrawing();
+    mWidget->EndRemoteDrawingInRegion(mDrawTarget, mInvalidRegion);
   }
 
   mDrawTarget = nullptr;
   mRenderTarget = nullptr;
 }
 
 }
 }
--- a/gfx/src/nsRegion.h
+++ b/gfx/src/nsRegion.h
@@ -710,16 +710,22 @@ public:
   }
 
   Derived& ScaleRoundOut (float aXScale, float aYScale)
   {
     mImpl.ScaleRoundOut(aXScale, aYScale);
     return This();
   }
 
+  Derived& ScaleInverseRoundOut (float aXScale, float aYScale)
+  {
+    mImpl.ScaleInverseRoundOut(aXScale, aYScale);
+    return This();
+  }
+
   Derived& Transform (const gfx3DMatrix &aTransform)
   {
     mImpl.Transform(aTransform);
     return This();
   }
 
   /**
    * Make sure the region has at most aMaxRects by adding area to it
--- a/gfx/tests/crashtests/crashtests.list
+++ b/gfx/tests/crashtests/crashtests.list
@@ -97,17 +97,17 @@ load 633322-1.html
 load 665218.html
 load 686190-1.html
 load 693143-1.html
 load 768079-1.html
 load 783041-1.html
 load 783041-2.html
 load 783041-3.html
 load 783041-4.html
-asserts-if(gtk2Widget,1) load 798853.html # bug 868792
+load 798853.html # bug 868792
 asserts-if(winWidget,0-1) skip-if(B2G) load 815489.html
 load 836225-1.html
 load 839745-1.html
 load 856784-1.html
 load 893572-1.html
 load 893572-2.html
 load 893572-3.html
 load 893572-4.html
--- a/gfx/thebes/gfxAndroidPlatform.cpp
+++ b/gfx/thebes/gfxAndroidPlatform.cpp
@@ -242,19 +242,19 @@ gfxAndroidPlatform::GetFontList(nsIAtom 
 {
     gfxPlatformFontList::PlatformFontList()->GetFontList(aLangGroup,
                                                          aGenericFamily,
                                                          aListOfFonts);
     return NS_OK;
 }
 
 void
-gfxAndroidPlatform::GetFontList(InfallibleTArray<FontListEntry>* retValue)
+gfxAndroidPlatform::GetSystemFontList(InfallibleTArray<FontListEntry>* retValue)
 {
-    gfxFT2FontList::PlatformFontList()->GetFontList(retValue);
+    gfxFT2FontList::PlatformFontList()->GetSystemFontList(retValue);
 }
 
 nsresult
 gfxAndroidPlatform::UpdateFontList()
 {
     gfxPlatformFontList::PlatformFontList()->UpdateFontList();
     return NS_OK;
 }
--- a/gfx/thebes/gfxAndroidPlatform.h
+++ b/gfx/thebes/gfxAndroidPlatform.h
@@ -35,17 +35,17 @@ public:
                            gfxContentType contentType);
     
     virtual gfxImageFormat GetOffscreenFormat() { return mOffscreenFormat; }
     
     mozilla::TemporaryRef<mozilla::gfx::ScaledFont>
       GetScaledFontForFont(mozilla::gfx::DrawTarget* aTarget, gfxFont *aFont);
 
     // to support IPC font list (sharing between chrome and content)
-    void GetFontList(InfallibleTArray<FontListEntry>* retValue);
+    void GetSystemFontList(InfallibleTArray<FontListEntry>* retValue);
 
     // platform implementations of font functions
     virtual bool IsFontFormatSupported(nsIURI *aFontURI, uint32_t aFormatFlags);
     virtual gfxPlatformFontList* CreatePlatformFontList();
     virtual gfxFontEntry* LookupLocalFont(const nsAString& aFontName,
                                           uint16_t aWeight,
                                           int16_t aStretch,
                                           bool aItalic);
--- a/gfx/thebes/gfxContext.cpp
+++ b/gfx/thebes/gfxContext.cpp
@@ -614,16 +614,33 @@ gfxContext::GetClipExtents()
   Matrix mat = mTransform;
   mat.Invert();
   rect = mat.TransformBounds(rect);
 
   return ThebesRect(rect);
 }
 
 bool
+gfxContext::HasComplexClip() const
+{
+  for (int i = mStateStack.Length() - 1; i >= 0; i--) {
+    for (unsigned int c = 0; c < mStateStack[i].pushedClips.Length(); c++) {
+      const AzureState::PushedClip &clip = mStateStack[i].pushedClips[c];
+      if (clip.path || !clip.transform.IsRectilinear()) {
+        return true;
+      }
+    }
+    if (mStateStack[i].clipWasReset) {
+      break;
+    }
+  }
+  return false;
+}
+
+bool
 gfxContext::ClipContainsRect(const gfxRect& aRect)
 {
   unsigned int lastReset = 0;
   for (int i = mStateStack.Length() - 2; i > 0; i--) {
     if (mStateStack[i].clipWasReset) {
       lastReset = i;
       break;
     }
--- a/gfx/thebes/gfxContext.h
+++ b/gfx/thebes/gfxContext.h
@@ -441,16 +441,21 @@ public:
 
     /**
      * This will return the current bounds of the clip region in user
      * space.
      */
     gfxRect GetClipExtents();
 
     /**
+     * Whether the current clip is not a simple rectangle.
+     */
+    bool HasComplexClip() const;
+
+    /**
      * Returns true if the given rectangle is fully contained in the current clip. 
      * This is conservative; it may return false even when the given rectangle is 
      * fully contained by the current clip.
      */
     bool ClipContainsRect(const gfxRect& aRect);
 
     /**
      * Groups
--- a/gfx/thebes/gfxDWriteFontList.cpp
+++ b/gfx/thebes/gfxDWriteFontList.cpp
@@ -1299,17 +1299,19 @@ gfxDWriteFontList::GetStandardFamilyName
         family->LocalizedName(aFamilyName);
         return true;
     }
 
     return false;
 }
 
 gfxFontFamily*
-gfxDWriteFontList::FindFamily(const nsAString& aFamily, bool aUseSystemFonts)
+gfxDWriteFontList::FindFamily(const nsAString& aFamily,
+                              nsIAtom* aLanguage,
+                              bool aUseSystemFonts)
 {
     if (!mInitialized) {
         mInitialized = true;
         DelayedInitFontList();
     }
 
     nsAutoString keyName(aFamily);
     BuildKeyNameFromFontName(keyName);
--- a/gfx/thebes/gfxDWriteFontList.h
+++ b/gfx/thebes/gfxDWriteFontList.h
@@ -360,16 +360,17 @@ public:
     
     bool GetStandardFamilyName(const nsAString& aFontName,
                                  nsAString& aFamilyName);
 
     IDWriteGdiInterop *GetGDIInterop() { return mGDIInterop; }
     bool UseGDIFontTableAccess() { return mGDIFontTableAccess; }
 
     virtual gfxFontFamily* FindFamily(const nsAString& aFamily,
+                                      nsIAtom* aLanguage = nullptr,
                                       bool aUseSystemFonts = false);
 
     virtual void GetFontFamilyList(nsTArray<nsRefPtr<gfxFontFamily> >& aFamilyArray);
 
     gfxFloat GetForceGDIClassicMaxFontSize() { return mForceGDIClassicMaxFontSize; }
 
     virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
                                         FontListSizes* aSizes) const;
--- a/gfx/thebes/gfxFT2FontList.cpp
+++ b/gfx/thebes/gfxFT2FontList.cpp
@@ -612,49 +612,35 @@ FT2FontFamily::AddFacesToFontList(Infall
  * find their attributes), leading to significantly quicker startup.
  */
 
 #define CACHE_KEY "font.cached-list"
 
 class FontNameCache {
 public:
     FontNameCache()
-        : mWriteNeeded(false)
+        : mMap(&sMapOps, sizeof(FNCMapEntry), 0)
+        , mWriteNeeded(false)
     {
-        mOps = (PLDHashTableOps) {
-            StringHash,
-            HashMatchEntry,
-            MoveEntry,
-            PL_DHashClearEntryStub,
-            nullptr
-        };
-
-        PL_DHashTableInit(&mMap, &mOps, sizeof(FNCMapEntry), 0);
-
         MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default,
                    "StartupCacheFontNameCache should only be used in chrome "
                    "process");
         mCache = mozilla::scache::StartupCache::GetSingleton();
 
         Init();
     }
 
     ~FontNameCache()
     {
-        if (!mMap.IsInitialized()) {
-            return;
-        }
         if (!mWriteNeeded || !mCache) {
-            PL_DHashTableFinish(&mMap);
             return;
         }
 
         nsAutoCString buf;
         PL_DHashTableEnumerate(&mMap, WriteOutMap, &buf);
-        PL_DHashTableFinish(&mMap);
         mCache->PutBuffer(CACHE_KEY, buf.get(), buf.Length() + 1);
     }
 
     void Init()
     {
         if (!mMap.IsInitialized() || !mCache) {
             return;
         }
@@ -746,17 +732,17 @@ public:
         mWriteNeeded = true;
     }
 
 private:
     mozilla::scache::StartupCache* mCache;
     PLDHashTable mMap;
     bool mWriteNeeded;
 
-    PLDHashTableOps mOps;
+    static const PLDHashTableOps sMapOps;
 
     static PLDHashOperator WriteOutMap(PLDHashTable *aTable,
                                        PLDHashEntryHdr *aHdr,
                                        uint32_t aNumber, void *aData)
     {
         FNCMapEntry* entry = static_cast<FNCMapEntry*>(aHdr);
         if (!entry->mFileExists) {
             // skip writing entries for files that are no longer present
@@ -805,16 +791,25 @@ private:
         to->mFilename.Assign(from->mFilename);
         to->mTimestamp = from->mTimestamp;
         to->mFilesize = from->mFilesize;
         to->mFaces.Assign(from->mFaces);
         to->mFileExists = from->mFileExists;
     }
 };
 
+/* static */ const PLDHashTableOps FontNameCache::sMapOps =
+{
+    FontNameCache::StringHash,
+    FontNameCache::HashMatchEntry,
+    FontNameCache::MoveEntry,
+    PL_DHashClearEntryStub,
+    nullptr
+};
+
 /***************************************************************
  *
  * gfxFT2FontList
  *
  */
 
 // For Mobile, we use gfxFT2Fonts, and we build the font list by directly
 // scanning the system's Fonts directory for OpenType and TrueType files.
@@ -1352,17 +1347,17 @@ AddHiddenFamilyToFontList(nsStringHashKe
 
     FT2FontFamily *family = static_cast<FT2FontFamily*>(aFamily.get());
     family->AddFacesToFontList(fontlist, FT2FontFamily::kHidden);
 
     return PL_DHASH_NEXT;
 }
 
 void
-gfxFT2FontList::GetFontList(InfallibleTArray<FontListEntry>* retValue)
+gfxFT2FontList::GetSystemFontList(InfallibleTArray<FontListEntry>* retValue)
 {
     mFontFamilies.Enumerate(AddFamilyToFontList, retValue);
     mHiddenFontFamilies.Enumerate(AddHiddenFamilyToFontList, retValue);
 }
 
 static void
 LoadSkipSpaceLookupCheck(nsTHashtable<nsStringHashKey>& aSkipSpaceLookupCheck)
 {
--- a/gfx/thebes/gfxFT2FontList.h
+++ b/gfx/thebes/gfxFT2FontList.h
@@ -129,17 +129,17 @@ public:
 
     virtual gfxFontEntry* MakePlatformFont(const nsAString& aFontName,
                                            uint16_t aWeight,
                                            int16_t aStretch,
                                            bool aItalic,
                                            const uint8_t* aFontData,
                                            uint32_t aLength);
 
-    void GetFontList(InfallibleTArray<FontListEntry>* retValue);
+    void GetSystemFontList(InfallibleTArray<FontListEntry>* retValue);
 
     static gfxFT2FontList* PlatformFontList() {
         return static_cast<gfxFT2FontList*>(gfxPlatformFontList::PlatformFontList());
     }
 
     virtual void GetFontFamilyList(nsTArray<nsRefPtr<gfxFontFamily> >& aFamilyArray);
 
 protected:
new file mode 100644
--- /dev/null
+++ b/gfx/thebes/gfxFcPlatformFontList.cpp
@@ -0,0 +1,1506 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "prlog.h"
+
+#include "gfxFcPlatformFontList.h"
+#include "gfxFont.h"
+#include "gfxFontConstants.h"
+#include "gfxFontFamilyList.h"
+#include "gfxFT2Utils.h"
+#include "gfxPlatform.h"
+#include "mozilla/ArrayUtils.h"
+#include "mozilla/TimeStamp.h"
+#include "nsGkAtoms.h"
+#include "nsILanguageAtomService.h"
+#include "nsUnicodeProperties.h"
+#include "nsUnicodeRange.h"
+#include "nsDirectoryServiceUtils.h"
+#include "nsDirectoryServiceDefs.h"
+#include "nsAppDirectoryServiceDefs.h"
+
+#include <fontconfig/fcfreetype.h>
+
+#ifdef MOZ_WIDGET_GTK
+#include <gdk/gdk.h>
+#endif
+
+using namespace mozilla;
+using namespace mozilla::unicode;
+
+#ifndef FC_POSTSCRIPT_NAME
+#define FC_POSTSCRIPT_NAME  "postscriptname"      /* String */
+#endif
+
+#define PRINTING_FC_PROPERTY "gfx.printing"
+
+#ifdef PR_LOGGING
+
+#define LOG_FONTLIST(args) PR_LOG(gfxPlatform::GetLog(eGfxLog_fontlist), \
+                               PR_LOG_DEBUG, args)
+#define LOG_FONTLIST_ENABLED() PR_LOG_TEST( \
+                                   gfxPlatform::GetLog(eGfxLog_fontlist), \
+                                   PR_LOG_DEBUG)
+#define LOG_CMAPDATA_ENABLED() PR_LOG_TEST( \
+                                   gfxPlatform::GetLog(eGfxLog_cmapdata), \
+                                   PR_LOG_DEBUG)
+
+#endif
+
+static const FcChar8*
+ToFcChar8Ptr(const char* aStr)
+{
+    return reinterpret_cast<const FcChar8*>(aStr);
+}
+
+static const char*
+ToCharPtr(const FcChar8 *aStr)
+{
+    return reinterpret_cast<const char*>(aStr);
+}
+
+FT_Library gfxFcPlatformFontList::sCairoFTLibrary = nullptr;
+static cairo_user_data_key_t sFcFontlistUserFontDataKey;
+
+// canonical name ==> first en name or first name if no en name
+// This is the required logic for fullname lookups as per CSS3 Fonts spec.
+static uint32_t
+FindCanonicalNameIndex(FcPattern* aFont, const char* aLangField)
+{
+    uint32_t n = 0, en = 0;
+    FcChar8* lang;
+    while (FcPatternGetString(aFont, aLangField, n, &lang) == FcResultMatch) {
+        // look for 'en' or variants, en-US, en-JP etc.
+        uint32_t len = strlen(ToCharPtr(lang));
+        bool enPrefix = (strncmp(ToCharPtr(lang), "en", 2) == 0);
+        if (enPrefix && (len == 2 || (len > 2 && aLangField[2] == '-'))) {
+            en = n;
+            break;
+        }
+        n++;
+    }
+    return en;
+}
+
+static void
+GetFaceNames(FcPattern* aFont, const nsAString& aFamilyName,
+             nsAString& aPostscriptName, nsAString& aFullname)
+{
+    // get the Postscript name
+    FcChar8* psname;
+    if (FcPatternGetString(aFont, FC_POSTSCRIPT_NAME, 0, &psname) == FcResultMatch) {
+        AppendUTF8toUTF16(ToCharPtr(psname), aPostscriptName);
+    }
+
+    // get the canonical fullname (i.e. en name or first name)
+    uint32_t en = FindCanonicalNameIndex(aFont, FC_FULLNAMELANG);
+    FcChar8* fullname;
+    if (FcPatternGetString(aFont, FC_FULLNAME, en, &fullname) == FcResultMatch) {
+        AppendUTF8toUTF16(ToCharPtr(fullname), aFullname);
+    }
+
+    // if have fullname, done
+    if (!aFullname.IsEmpty()) {
+        return;
+    }
+
+    // otherwise, set the fullname to family + style name [en] and use that
+    aFullname.Append(aFamilyName);
+
+    // figure out the en style name
+    en = FindCanonicalNameIndex(aFont, FC_STYLELANG);
+    nsAutoString style;
+    FcChar8* stylename = nullptr;
+    FcPatternGetString(aFont, FC_STYLE, en, &stylename);
+    if (stylename) {
+        AppendUTF8toUTF16(ToCharPtr(stylename), style);
+    }
+
+    if (!style.IsEmpty() && !style.EqualsLiteral("Regular")) {
+        aFullname.Append(' ');
+        aFullname.Append(style);
+    }
+}
+
+static uint16_t
+MapFcWeight(int aFcWeight)
+{
+    if (aFcWeight <= (FC_WEIGHT_THIN + FC_WEIGHT_EXTRALIGHT) / 2) {
+        return 100;
+    } else if (aFcWeight <= (FC_WEIGHT_EXTRALIGHT + FC_WEIGHT_LIGHT) / 2) {
+        return 200;
+    } else if (aFcWeight <= (FC_WEIGHT_LIGHT + FC_WEIGHT_BOOK) / 2) {
+        return 300;
+    } else if (aFcWeight <= (FC_WEIGHT_REGULAR + FC_WEIGHT_MEDIUM) / 2) {
+        // This includes FC_WEIGHT_BOOK
+        return 400;
+    } else if (aFcWeight <= (FC_WEIGHT_MEDIUM + FC_WEIGHT_DEMIBOLD) / 2) {
+        return 500;
+    } else if (aFcWeight <= (FC_WEIGHT_DEMIBOLD + FC_WEIGHT_BOLD) / 2) {
+        return 600;
+    } else if (aFcWeight <= (FC_WEIGHT_BOLD + FC_WEIGHT_EXTRABOLD) / 2) {
+        return 700;
+    } else if (aFcWeight <= (FC_WEIGHT_EXTRABOLD + FC_WEIGHT_BLACK) / 2) {
+        return 800;
+    } else if (aFcWeight <= FC_WEIGHT_BLACK) {
+        return 900;
+    }
+
+    // including FC_WEIGHT_EXTRABLACK
+    return 901;
+}
+
+static int16_t
+MapFcWidth(int aFcWidth)
+{
+    if (aFcWidth <= (FC_WIDTH_ULTRACONDENSED + FC_WIDTH_EXTRACONDENSED) / 2) {
+        return NS_FONT_STRETCH_ULTRA_CONDENSED;
+    }
+    if (aFcWidth <= (FC_WIDTH_EXTRACONDENSED + FC_WIDTH_CONDENSED) / 2) {
+        return NS_FONT_STRETCH_EXTRA_CONDENSED;
+    }
+    if (aFcWidth <= (FC_WIDTH_CONDENSED + FC_WIDTH_SEMICONDENSED) / 2) {
+        return NS_FONT_STRETCH_CONDENSED;
+    }
+    if (aFcWidth <= (FC_WIDTH_SEMICONDENSED + FC_WIDTH_NORMAL) / 2) {
+        return NS_FONT_STRETCH_SEMI_CONDENSED;
+    }
+    if (aFcWidth <= (FC_WIDTH_NORMAL + FC_WIDTH_SEMIEXPANDED) / 2) {
+        return NS_FONT_STRETCH_NORMAL;
+    }
+    if (aFcWidth <= (FC_WIDTH_SEMIEXPANDED + FC_WIDTH_EXPANDED) / 2) {
+        return NS_FONT_STRETCH_SEMI_EXPANDED;
+    }
+    if (aFcWidth <= (FC_WIDTH_EXPANDED + FC_WIDTH_EXTRAEXPANDED) / 2) {
+        return NS_FONT_STRETCH_EXPANDED;
+    }
+    if (aFcWidth <= (FC_WIDTH_EXTRAEXPANDED + FC_WIDTH_ULTRAEXPANDED) / 2) {
+        return NS_FONT_STRETCH_EXTRA_EXPANDED;
+    }
+    return NS_FONT_STRETCH_ULTRA_EXPANDED;
+}
+
+// mapping of moz lang groups ==> default lang
+struct MozLangGroupData {
+    nsIAtom* const& mozLangGroup;
+    const char *defaultLang;
+};
+
+const MozLangGroupData MozLangGroups[] = {
+    { nsGkAtoms::x_western,      "en" },
+    { nsGkAtoms::x_cyrillic,     "ru" },
+    { nsGkAtoms::x_devanagari,   "hi" },
+    { nsGkAtoms::x_tamil,        "ta" },
+    { nsGkAtoms::x_armn,         "hy" },
+    { nsGkAtoms::x_beng,         "bn" },
+    { nsGkAtoms::x_cans,         "iu" },
+    { nsGkAtoms::x_ethi,         "am" },
+    { nsGkAtoms::x_geor,         "ka" },
+    { nsGkAtoms::x_gujr,         "gu" },
+    { nsGkAtoms::x_guru,         "pa" },
+    { nsGkAtoms::x_khmr,         "km" },
+    { nsGkAtoms::x_knda,         "kn" },
+    { nsGkAtoms::x_mlym,         "ml" },
+    { nsGkAtoms::x_orya,         "or" },
+    { nsGkAtoms::x_sinh,         "si" },
+    { nsGkAtoms::x_tamil,        "ta" },
+    { nsGkAtoms::x_telu,         "te" },
+    { nsGkAtoms::x_tibt,         "bo" },
+    { nsGkAtoms::Unicode,        0    }
+};
+
+static void
+GetSampleLangForGroup(nsIAtom* aLanguage, nsACString& aLangStr)
+{
+    aLangStr.Truncate();
+    if (aLanguage) {
+        // set up lang string
+        const MozLangGroupData *mozLangGroup = nullptr;
+
+        // -- look it up in the list of moz lang groups
+        for (unsigned int i = 0; i < ArrayLength(MozLangGroups); ++i) {
+            if (aLanguage == MozLangGroups[i].mozLangGroup) {
+                mozLangGroup = &MozLangGroups[i];
+                break;
+            }
+        }
+
+        // xxx - Is this sufficient? The code in
+        // gfxFontconfigUtils::GetSampleLangForGroup has logic for sniffing the
+        // LANGUAGE environment to try and map langGroup ==> closest user language
+        // but I'm guessing that's not really all that useful. For now, just use
+        // the default lang mapping.
+
+        // -- get the BCP47 string representation of the lang group
+        if (mozLangGroup) {
+            if (mozLangGroup->defaultLang) {
+                aLangStr.Assign(mozLangGroup->defaultLang);
+            }
+        } else {
+            // Not a special mozilla language group.
+            // Use aLangGroup as a language code.
+            aLanguage->ToUTF8String(aLangStr);
+        }
+    }
+}
+
+gfxFontconfigFontEntry::gfxFontconfigFontEntry(const nsAString& aFaceName,
+                                               FcPattern* aFontPattern)
+        : gfxFontEntry(aFaceName), mFontPattern(aFontPattern),
+          mFTFace(nullptr), mFTFaceInitialized(false),
+          mAspect(0.0), mFontData(nullptr)
+{
+    // italic
+    int slant;
+    if (FcPatternGetInteger(aFontPattern, FC_SLANT, 0, &slant) != FcResultMatch) {
+        slant = FC_SLANT_ROMAN;
+    }
+    if (slant > 0) {
+        mItalic = true;
+    }
+
+    // weight
+    int weight;
+    if (FcPatternGetInteger(aFontPattern, FC_WEIGHT, 0, &weight) != FcResultMatch) {
+        weight = FC_WEIGHT_REGULAR;
+    }
+    mWeight = MapFcWeight(weight);
+
+    // width
+    int width;
+    if (FcPatternGetInteger(aFontPattern, FC_WIDTH, 0, &width) != FcResultMatch) {
+        width = FC_WIDTH_NORMAL;
+    }
+    mStretch = MapFcWidth(width);
+}
+
+gfxFontconfigFontEntry::gfxFontconfigFontEntry(const nsAString& aFaceName,
+                                               uint16_t aWeight,
+                                               int16_t aStretch,
+                                               bool aItalic,
+                                               const uint8_t *aData,
+                                               FT_Face aFace)
+    : gfxFontEntry(aFaceName), mFontPattern(FcPatternCreate()),
+      mFTFace(aFace), mFTFaceInitialized(true),
+      mAspect(0.0), mFontData(aData)
+{
+    mWeight = aWeight;
+    mItalic = aItalic;
+    mStretch = aStretch;
+    mIsDataUserFont = true;
+
+    // Make a new pattern and store the face in it so that cairo uses
+    // that when creating a cairo font face.
+    FcPatternAddFTFace(mFontPattern, FC_FT_FACE, mFTFace);
+
+    mUserFontData = new FTUserFontData(mFTFace, mFontData);
+}
+
+gfxFontconfigFontEntry::gfxFontconfigFontEntry(const nsAString& aFaceName,
+                                               FcPattern* aFontPattern,
+                                               uint16_t aWeight,
+                                               int16_t aStretch,
+                                               bool aItalic)
+        : gfxFontEntry(aFaceName), mFontPattern(aFontPattern),
+          mFTFace(nullptr), mFTFaceInitialized(false),
+          mAspect(0.0), mFontData(nullptr)
+{
+    mWeight = aWeight;
+    mItalic = aItalic;
+    mStretch = aStretch;
+    mIsLocalUserFont = true;
+}
+
+gfxFontconfigFontEntry::~gfxFontconfigFontEntry()
+{
+}
+
+bool
+gfxFontconfigFontEntry::SupportsLangGroup(nsIAtom *aLangGroup) const
+{
+    if (!aLangGroup || aLangGroup == nsGkAtoms::Unicode) {
+        return true;
+    }
+
+    nsAutoCString fcLang;
+    GetSampleLangForGroup(aLangGroup, fcLang);
+    if (fcLang.IsEmpty()) {
+        return true;
+    }
+
+    // is lang included in the underlying pattern?
+    FcLangSet *langset;
+    if (FcPatternGetLangSet(mFontPattern, FC_LANG, 0, &langset) != FcResultMatch) {
+        return false;
+    }
+
+    if (FcLangSetHasLang(langset, (FcChar8 *)fcLang.get()) != FcLangDifferentLang) {
+        return true;
+    }
+
+    return false;
+}
+
+nsresult
+gfxFontconfigFontEntry::ReadCMAP(FontInfoData *aFontInfoData)
+{
+    // attempt this once, if errors occur leave a blank cmap
+    if (mCharacterMap) {
+        return NS_OK;
+    }
+
+    nsRefPtr<gfxCharacterMap> charmap;
+    nsresult rv;
+    bool symbolFont;
+
+    if (aFontInfoData && (charmap = GetCMAPFromFontInfo(aFontInfoData,
+                                                        mUVSOffset,
+                                                        symbolFont))) {
+        rv = NS_OK;
+    } else {
+        uint32_t kCMAP = TRUETYPE_TAG('c','m','a','p');
+        charmap = new gfxCharacterMap();
+        AutoTable cmapTable(this, kCMAP);
+
+        if (cmapTable) {
+            bool unicodeFont = false, symbolFont = false; // currently ignored
+            uint32_t cmapLen;
+            const uint8_t* cmapData =
+                reinterpret_cast<const uint8_t*>(hb_blob_get_data(cmapTable,
+                                                                  &cmapLen));
+            rv = gfxFontUtils::ReadCMAP(cmapData, cmapLen,
+                                        *charmap, mUVSOffset,
+                                        unicodeFont, symbolFont);
+        } else {
+            rv = NS_ERROR_NOT_AVAILABLE;
+        }
+    }
+
+    mHasCmapTable = NS_SUCCEEDED(rv);
+    if (mHasCmapTable) {
+        gfxPlatformFontList *pfl = gfxPlatformFontList::PlatformFontList();
+        mCharacterMap = pfl->FindCharMap(charmap);
+    } else {
+        // if error occurred, initialize to null cmap
+        mCharacterMap = new gfxCharacterMap();
+    }
+
+#ifdef PR_LOGGING
+    LOG_FONTLIST(("(fontlist-cmap) name: %s, size: %d hash: %8.8x%s\n",
+                  NS_ConvertUTF16toUTF8(mName).get(),
+                  charmap->SizeOfIncludingThis(moz_malloc_size_of),
+                  charmap->mHash, mCharacterMap == charmap ? " new" : ""));
+    if (LOG_CMAPDATA_ENABLED()) {
+        char prefix[256];
+        sprintf(prefix, "(cmapdata) name: %.220s",
+                NS_ConvertUTF16toUTF8(mName).get());
+        charmap->Dump(prefix, eGfxLog_cmapdata);
+    }
+#endif
+
+    return rv;
+}
+
+static bool
+HasChar(FcPattern *aFont, FcChar32 aCh)
+{
+    FcCharSet *charset = nullptr;
+    FcPatternGetCharSet(aFont, FC_CHARSET, 0, &charset);
+    return charset && FcCharSetHasChar(charset, aCh);
+}
+
+bool
+gfxFontconfigFontEntry::TestCharacterMap(uint32_t aCh)
+{
+    // for system fonts, use the charmap in the pattern
+    if (!mIsDataUserFont) {
+        return HasChar(mFontPattern, aCh);
+    }
+    return gfxFontEntry::TestCharacterMap(aCh);
+}
+
+hb_blob_t*
+gfxFontconfigFontEntry::GetFontTable(uint32_t aTableTag)
+{
+    // for data fonts, read directly from the font data
+    if (mFontData) {
+        return GetTableFromFontData(mFontData, aTableTag);
+    }
+
+    return gfxFontEntry::GetFontTable(aTableTag);
+}
+
+void
+gfxFontconfigFontEntry::MaybeReleaseFTFace()
+{
+    // don't release if either HB or Gr face still exists
+    if (mHBFace || mGrFace) {
+        return;
+    }
+    // only close out FT_Face for system fonts, not for data fonts
+    if (!mIsDataUserFont) {
+        if (mFTFace) {
+            FT_Done_Face(mFTFace);
+            mFTFace = nullptr;
+        }
+        mFTFaceInitialized = false;
+    }
+}
+
+void
+gfxFontconfigFontEntry::ForgetHBFace()
+{
+    gfxFontEntry::ForgetHBFace();
+    MaybeReleaseFTFace();
+}
+
+void
+gfxFontconfigFontEntry::ReleaseGrFace(gr_face* aFace)
+{
+    gfxFontEntry::ReleaseGrFace(aFace);
+    MaybeReleaseFTFace();
+}
+
+double
+gfxFontconfigFontEntry::GetAspect()
+{
+    if (mAspect == 0.0) {
+        // default to aspect = 0.5
+        mAspect = 0.5;
+
+        // create a font to calculate x-height / em-height
+        gfxFontStyle s;
+        s.size = 100.0; // pick large size to avoid possible hinting artifacts
+        nsRefPtr<gfxFont> font = FindOrMakeFont(&s, false);
+        if (font) {
+            const gfxFont::Metrics& metrics =
+                font->GetMetrics(gfxFont::eHorizontal);
+
+            // The factor of 0.1 ensures that xHeight is sane so fonts don't
+            // become huge.  Strictly ">" ensures that xHeight and emHeight are
+            // not both zero.
+            if (metrics.xHeight > 0.1 * metrics.emHeight) {
+                mAspect = metrics.xHeight / metrics.emHeight;
+            }
+        }
+    }
+    return mAspect;
+}
+
+static void
+PrepareFontOptions(FcPattern* aPattern,
+                   cairo_font_options_t* aFontOptions)
+{
+    NS_ASSERTION(aFontOptions, "null font options passed to PrepareFontOptions");
+
+    // xxx - taken from the gfxPangoFonts code, needs to be reviewed
+
+    FcBool printing;
+    if (FcPatternGetBool(aPattern, PRINTING_FC_PROPERTY, 0, &printing) !=
+            FcResultMatch) {
+        printing = FcFalse;
+    }
+
+    // Font options are set explicitly here to improve cairo's caching
+    // behavior and to record the relevant parts of the pattern for
+    // SetupCairoFont (so that the pattern can be released).
+    //
+    // Most font_options have already been set as defaults on the FcPattern
+    // with cairo_ft_font_options_substitute(), then user and system
+    // fontconfig configurations were applied.  The resulting font_options
+    // have been recorded on the face during
+    // cairo_ft_font_face_create_for_pattern().
+    //
+    // None of the settings here cause this scaled_font to behave any
+    // differently from how it would behave if it were created from the same
+    // face with default font_options.
+    //
+    // We set options explicitly so that the same scaled_font will be found in
+    // the cairo_scaled_font_map when cairo loads glyphs from a context with
+    // the same font_face, font_matrix, ctm, and surface font_options.
+    //
+    // Unfortunately, _cairo_scaled_font_keys_equal doesn't know about the
+    // font_options on the cairo_ft_font_face, and doesn't consider default
+    // option values to not match any explicit values.
+    //
+    // Even after cairo_set_scaled_font is used to set font_options for the
+    // cairo context, when cairo looks for a scaled_font for the context, it
+    // will look for a font with some option values from the target surface if
+    // any values are left default on the context font_options.  If this
+    // scaled_font is created with default font_options, cairo will not find
+    // it.
+    //
+    // The one option not recorded in the pattern is hint_metrics, which will
+    // affect glyph metrics.  The default behaves as CAIRO_HINT_METRICS_ON.
+    // We should be considering the font_options of the surface on which this
+    // font will be used, but currently we don't have different gfxFonts for
+    // different surface font_options, so we'll create a font suitable for the
+    // Screen. Image and xlib surfaces default to CAIRO_HINT_METRICS_ON.
+    if (printing) {
+        cairo_font_options_set_hint_metrics(aFontOptions, CAIRO_HINT_METRICS_OFF);
+    } else {
+        cairo_font_options_set_hint_metrics(aFontOptions, CAIRO_HINT_METRICS_ON);
+    }
+
+    // The remaining options have been recorded on the pattern and the face.
+    // _cairo_ft_options_merge has some logic to decide which options from the
+    // scaled_font or from the cairo_ft_font_face take priority in the way the
+    // font behaves.
+    //
+    // In the majority of cases, _cairo_ft_options_merge uses the options from
+    // the cairo_ft_font_face, so sometimes it is not so important which
+    // values are set here so long as they are not defaults, but we'll set
+    // them to the exact values that we expect from the font, to be consistent
+    // and to protect against changes in cairo.
+    //
+    // In some cases, _cairo_ft_options_merge uses some options from the
+    // scaled_font's font_options rather than options on the
+    // cairo_ft_font_face (from fontconfig).
+    // https://bugs.freedesktop.org/show_bug.cgi?id=11838
+    //
+    // Surface font options were set on the pattern in
+    // cairo_ft_font_options_substitute.  If fontconfig has changed the
+    // hint_style then that is what the user (or distribution) wants, so we
+    // use the setting from the FcPattern.
+    //
+    // Fallback values here mirror treatment of defaults in cairo-ft-font.c.
+    FcBool hinting = FcFalse;
+    if (FcPatternGetBool(aPattern, FC_HINTING, 0, &hinting) != FcResultMatch) {
+        hinting = FcTrue;
+    }
+
+    cairo_hint_style_t hint_style;
+    if (printing || !hinting) {
+        hint_style = CAIRO_HINT_STYLE_NONE;
+    } else {
+        int fc_hintstyle;
+        if (FcPatternGetInteger(aPattern, FC_HINT_STYLE,
+                                0, &fc_hintstyle) != FcResultMatch) {
+            fc_hintstyle = FC_HINT_FULL;
+        }
+        switch (fc_hintstyle) {
+            case FC_HINT_NONE:
+                hint_style = CAIRO_HINT_STYLE_NONE;
+                break;
+            case FC_HINT_SLIGHT:
+                hint_style = CAIRO_HINT_STYLE_SLIGHT;
+                break;
+            case FC_HINT_MEDIUM:
+            default: // This fallback mirrors _get_pattern_ft_options in cairo.
+                hint_style = CAIRO_HINT_STYLE_MEDIUM;
+                break;
+            case FC_HINT_FULL:
+                hint_style = CAIRO_HINT_STYLE_FULL;
+                break;
+        }
+    }
+    cairo_font_options_set_hint_style(aFontOptions, hint_style);
+
+    int rgba;
+    if (FcPatternGetInteger(aPattern,
+                            FC_RGBA, 0, &rgba) != FcResultMatch) {
+        rgba = FC_RGBA_UNKNOWN;
+    }
+    cairo_subpixel_order_t subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT;
+    switch (rgba) {
+        case FC_RGBA_UNKNOWN:
+        case FC_RGBA_NONE:
+        default:
+            // There is no CAIRO_SUBPIXEL_ORDER_NONE.  Subpixel antialiasing
+            // is disabled through cairo_antialias_t.
+            rgba = FC_RGBA_NONE;
+            // subpixel_order won't be used by the font as we won't use
+            // CAIRO_ANTIALIAS_SUBPIXEL, but don't leave it at default for
+            // caching reasons described above.  Fall through:
+        case FC_RGBA_RGB:
+            subpixel_order = CAIRO_SUBPIXEL_ORDER_RGB;
+            break;
+        case FC_RGBA_BGR:
+            subpixel_order = CAIRO_SUBPIXEL_ORDER_BGR;
+            break;
+        case FC_RGBA_VRGB:
+            subpixel_order = CAIRO_SUBPIXEL_ORDER_VRGB;
+            break;
+        case FC_RGBA_VBGR:
+            subpixel_order = CAIRO_SUBPIXEL_ORDER_VBGR;
+            break;
+    }
+    cairo_font_options_set_subpixel_order(aFontOptions, subpixel_order);
+
+    FcBool fc_antialias;
+    if (FcPatternGetBool(aPattern,
+                         FC_ANTIALIAS, 0, &fc_antialias) != FcResultMatch) {
+        fc_antialias = FcTrue;
+    }
+    cairo_antialias_t antialias;
+    if (!fc_antialias) {
+        antialias = CAIRO_ANTIALIAS_NONE;
+    } else if (rgba == FC_RGBA_NONE) {
+        antialias = CAIRO_ANTIALIAS_GRAY;
+    } else {
+        antialias = CAIRO_ANTIALIAS_SUBPIXEL;
+    }
+    cairo_font_options_set_antialias(aFontOptions, antialias);
+}
+
+cairo_scaled_font_t*
+gfxFontconfigFontEntry::CreateScaledFont(FcPattern* aRenderPattern,
+                                         const gfxFontStyle *aStyle,
+                                         bool aNeedsBold)
+{
+    if (aNeedsBold) {
+        FcPatternAddBool(aRenderPattern, FC_EMBOLDEN, FcTrue);
+    }
+
+    // synthetic oblique by skewing via the font matrix
+    bool needsOblique = !IsItalic() &&
+            (aStyle->style & (NS_FONT_STYLE_ITALIC | NS_FONT_STYLE_OBLIQUE)) &&
+            aStyle->allowSyntheticStyle;
+
+    if (needsOblique) {
+        // disable embedded bitmaps (mimics behavior in 90-synthetic.conf)
+        FcPatternDel(aRenderPattern, FC_EMBEDDED_BITMAP);
+        FcPatternAddBool(aRenderPattern, FC_EMBEDDED_BITMAP, FcFalse);
+    }
+
+    cairo_font_face_t *face =
+        cairo_ft_font_face_create_for_pattern(aRenderPattern);
+
+    if (mFontData) {
+        // for data fonts, add the face/data pointer to the cairo font face
+        // so that it gets deleted whenever cairo decides
+        NS_ASSERTION(mFTFace, "FT_Face is null when setting user data");
+        NS_ASSERTION(mUserFontData, "user font data is null when setting user data");
+        cairo_font_face_set_user_data(face,
+                                      &sFcFontlistUserFontDataKey,
+                                      new FTUserFontDataRef(mUserFontData),
+                                      FTUserFontDataRef::Destroy);
+    }
+
+    cairo_scaled_font_t *scaledFont = nullptr;
+
+    cairo_matrix_t sizeMatrix;
+    cairo_matrix_t identityMatrix;
+
+    double adjustedSize = aStyle->size;
+    if (aStyle->sizeAdjust >= 0.0) {
+        adjustedSize = aStyle->GetAdjustedSize(GetAspect());
+    }
+    cairo_matrix_init_scale(&sizeMatrix, adjustedSize, adjustedSize);
+    cairo_matrix_init_identity(&identityMatrix);
+
+    if (needsOblique) {
+        const double kSkewFactor = OBLIQUE_SKEW_FACTOR;
+
+        cairo_matrix_t style;
+        cairo_matrix_init(&style,
+                          1,                //xx
+                          0,                //yx
+                          -1 * kSkewFactor,  //xy
+                          1,                //yy
+                          0,                //x0
+                          0);               //y0
+        cairo_matrix_multiply(&sizeMatrix, &sizeMatrix, &style);
+    }
+
+    cairo_font_options_t *fontOptions = cairo_font_options_create();
+    PrepareFontOptions(aRenderPattern, fontOptions);
+
+    scaledFont = cairo_scaled_font_create(face, &sizeMatrix,
+                                          &identityMatrix, fontOptions);
+    cairo_font_options_destroy(fontOptions);
+
+    NS_ASSERTION(cairo_scaled_font_status(scaledFont) == CAIRO_STATUS_SUCCESS,
+                 "Failed to make scaled font");
+
+    cairo_font_face_destroy(face);
+
+    return scaledFont;
+}
+
+#ifdef MOZ_WIDGET_GTK
+// defintion included below
+static void ApplyGdkScreenFontOptions(FcPattern *aPattern);
+#endif
+
+static void
+PreparePattern(FcPattern* aPattern, bool aIsPrinterFont)
+{
+    // This gets cairo_font_options_t for the Screen.  We should have
+    // different font options for printing (no hinting) but we are not told
+    // what we are measuring for.
+    //
+    // If cairo adds support for lcd_filter, gdk will not provide the default
+    // setting for that option.  We could get the default setting by creating
+    // an xlib surface once, recording its font_options, and then merging the
+    // gdk options.
+    //
+    // Using an xlib surface would also be an option to get Screen font
+    // options for non-GTK X11 toolkits, but less efficient than using GDK to
+    // pick up dynamic changes.
+    if(aIsPrinterFont) {
+       cairo_font_options_t *options = cairo_font_options_create();
+       cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_NONE);
+       cairo_font_options_set_antialias (options, CAIRO_ANTIALIAS_GRAY);
+       cairo_ft_font_options_substitute(options, aPattern);
+       cairo_font_options_destroy(options);
+       FcPatternAddBool(aPattern, PRINTING_FC_PROPERTY, FcTrue);
+    } else {
+#ifdef MOZ_WIDGET_GTK
+       ApplyGdkScreenFontOptions(aPattern);
+#endif
+    }
+
+    FcDefaultSubstitute(aPattern);
+}
+
+gfxFont*
+gfxFontconfigFontEntry::CreateFontInstance(const gfxFontStyle *aFontStyle,
+                                           bool aNeedsBold)
+{
+    nsAutoRef<FcPattern> pattern(FcPatternCreate());
+    FcPatternAddDouble(pattern, FC_PIXEL_SIZE, aFontStyle->size);
+
+    PreparePattern(pattern, aFontStyle->printerFont);
+    nsAutoRef<FcPattern> renderPattern
+        (FcFontRenderPrepare(nullptr, pattern, mFontPattern));
+
+    cairo_scaled_font_t* scaledFont =
+        CreateScaledFont(renderPattern, aFontStyle, aNeedsBold);
+    gfxFont* newFont =
+        new gfxFontconfigFont(scaledFont, this, aFontStyle, aNeedsBold);
+    cairo_scaled_font_destroy(scaledFont);
+
+    return newFont;
+}
+
+nsresult
+gfxFontconfigFontEntry::CopyFontTable(uint32_t aTableTag,
+                                      FallibleTArray<uint8_t>& aBuffer)
+{
+    NS_ASSERTION(!mIsDataUserFont,
+                 "data fonts should be reading tables directly from memory");
+
+    if (!mFTFaceInitialized) {
+        mFTFaceInitialized = true;
+        FcChar8 *filename;
+        if (FcPatternGetString(mFontPattern, FC_FILE, 0, &filename) != FcResultMatch) {
+            return NS_ERROR_FAILURE;
+        }
+        int index;
+        if (FcPatternGetInteger(mFontPattern, FC_INDEX, 0, &index) != FcResultMatch) {
+            index = 0; // default to 0 if not found in pattern
+        }
+        if (FT_New_Face(gfxFcPlatformFontList::GetFTLibrary(),
+                        (const char*)filename, index, &mFTFace) != 0) {
+            return NS_ERROR_FAILURE;
+        }
+    }
+
+    if (!mFTFace) {
+        return NS_ERROR_NOT_AVAILABLE;
+    }
+
+    FT_ULong length = 0;
+    if (FT_Load_Sfnt_Table(mFTFace, aTableTag, 0, nullptr, &length) != 0) {
+        return NS_ERROR_NOT_AVAILABLE;
+    }
+    if (!aBuffer.SetLength(length)) {
+        return NS_ERROR_OUT_OF_MEMORY;
+    }
+    if (FT_Load_Sfnt_Table(mFTFace, aTableTag, 0, aBuffer.Elements(), &length) != 0) {
+        aBuffer.Clear();
+        return NS_ERROR_FAILURE;
+    }
+
+    return NS_OK;
+}
+
+void
+gfxFontconfigFontFamily::FindStyleVariations(FontInfoData *aFontInfoData)
+{
+    if (mHasStyles) {
+        return;
+    }
+
+    // add font entries for each of the faces
+    gfxPlatformFontList *fp = gfxPlatformFontList::PlatformFontList();
+    uint32_t numFonts = mFontPatterns.Length();
+    NS_ASSERTION(numFonts, "font family containing no faces!!");
+    for (uint32_t i = 0; i < numFonts; i++) {
+        FcPattern* face = mFontPatterns[i];
+
+        // figure out the psname/fullname and choose which to use as the facename
+        nsAutoString psname, fullname;
+        GetFaceNames(face, mName, psname, fullname);
+        const nsAutoString& faceName = !psname.IsEmpty() ? psname : fullname;
+
+        gfxFontconfigFontEntry *fontEntry =
+            new gfxFontconfigFontEntry(faceName, face);
+        AddFontEntry(fontEntry);
+
+        // add entry to local name lists
+        if (!psname.IsEmpty()) {
+            fp->AddPostscriptName(fontEntry, psname);
+        }
+        NS_ASSERTION(!fullname.IsEmpty(), "empty font fullname");
+        if (!fullname.IsEmpty()) {
+            fp->AddFullname(fontEntry, fullname);
+        }
+
+#ifdef PR_LOGGING
+        if (LOG_FONTLIST_ENABLED()) {
+            LOG_FONTLIST(("(fontlist) added (%s) to family (%s)"
+                 " with style: %s weight: %d stretch: %d"
+                 " psname: %s fullname: %s",
+                 NS_ConvertUTF16toUTF8(fontEntry->Name()).get(),
+                 NS_ConvertUTF16toUTF8(Name()).get(),
+                 fontEntry->IsItalic() ? "italic" : "normal",
+                 fontEntry->Weight(), fontEntry->Stretch(),
+                 NS_ConvertUTF16toUTF8(psname).get(),
+                 NS_ConvertUTF16toUTF8(fullname).get()));
+        }
+#endif
+    }
+    mFaceNamesInitialized = true;
+    mFontPatterns.Clear();
+    SetHasStyles(true);
+}
+
+void
+gfxFontconfigFontFamily::AddFontPattern(FcPattern* aFontPattern)
+{
+    NS_ASSERTION(!mHasStyles,
+                 "font patterns must not be added to already enumerated families");
+
+    nsCountedRef<FcPattern> pattern(aFontPattern);
+    mFontPatterns.AppendElement(pattern);
+}
+
+gfxFontconfigFont::gfxFontconfigFont(cairo_scaled_font_t *aScaledFont,
+                                     gfxFontEntry *aFontEntry,
+                                     const gfxFontStyle *aFontStyle,
+                                     bool aNeedsBold) :
+    gfxFT2FontBase(aScaledFont, aFontEntry, aFontStyle)
+{
+}
+
+gfxFontconfigFont::~gfxFontconfigFont()
+{
+}
+
+#ifdef USE_SKIA
+mozilla::TemporaryRef<mozilla::gfx::GlyphRenderingOptions>
+gfxFontconfigFont::GetGlyphRenderingOptions(const TextRunDrawParams* aRunParams)
+{
+  cairo_scaled_font_t *scaled_font = CairoScaledFont();
+  cairo_font_options_t *options = cairo_font_options_create();
+  cairo_scaled_font_get_font_options(scaled_font, options);
+  cairo_hint_style_t hint_style = cairo_font_options_get_hint_style(options);
+  cairo_font_options_destroy(options);
+
+  mozilla::gfx::FontHinting hinting;
+
+  switch (hint_style) {
+    case CAIRO_HINT_STYLE_NONE:
+      hinting = mozilla::gfx::FontHinting::NONE;
+      break;
+    case CAIRO_HINT_STYLE_SLIGHT:
+      hinting = mozilla::gfx::FontHinting::LIGHT;
+      break;
+    case CAIRO_HINT_STYLE_FULL:
+      hinting = mozilla::gfx::FontHinting::FULL;
+      break;
+    default:
+      hinting = mozilla::gfx::FontHinting::NORMAL;
+      break;
+  }
+
+  // We don't want to force the use of the autohinter over the font's built in hints
+  return mozilla::gfx::Factory::CreateCairoGlyphRenderingOptions(hinting, false);
+}
+#endif
+
+gfxFcPlatformFontList::gfxFcPlatformFontList()
+    : mLocalNames(64), mGenericMappings(32), mLastConfig(nullptr)
+{
+    // if the rescan interval is set, start the timer
+    int rescanInterval = FcConfigGetRescanInterval(nullptr);
+    if (rescanInterval) {
+        mLastConfig = FcConfigGetCurrent();
+        mCheckFontUpdatesTimer = do_CreateInstance("@mozilla.org/timer;1");
+        if (mCheckFontUpdatesTimer) {
+            mCheckFontUpdatesTimer->
+                InitWithFuncCallback(CheckFontUpdates, this,
+                                     (rescanInterval + 1) * 1000,
+                                     nsITimer::TYPE_REPEATING_SLACK);
+        } else {
+            NS_WARNING("Failure to create font updates timer");
+        }
+    }
+
+#ifdef MOZ_BUNDLED_FONTS
+    mBundledFontsInitialized = false;
+#endif
+}
+
+gfxFcPlatformFontList::~gfxFcPlatformFontList()
+{
+    if (mCheckFontUpdatesTimer) {
+        mCheckFontUpdatesTimer->Cancel();
+        mCheckFontUpdatesTimer = nullptr;
+    }
+}
+
+void
+gfxFcPlatformFontList::AddFontSetFamilies(FcFontSet* aFontSet)
+{
+    // This iterates over the fonts in a font set and adds in gfxFontFamily
+    // objects for each family. The patterns for individual fonts are not
+    // copied here. When a family is actually used, the fonts in the family
+    // are enumerated and the patterns copied. Note that we're explicitly
+    // excluding non-scalable fonts such as X11 bitmap fonts, which
+    // Chrome Skia/Webkit code does also.
+
+    FcChar8* lastFamilyName = (FcChar8*)"";
+    gfxFontFamily* fontFamily = nullptr;
+    nsAutoString familyName;
+    for (int f = 0; f < aFontSet->nfont; f++) {
+        FcPattern* font = aFontSet->fonts[f];
+
+        // not scalable? skip...
+        FcBool scalable;
+        if (FcPatternGetBool(font, FC_SCALABLE, 0, &scalable) != FcResultMatch ||
+            !scalable) {
+            continue;
+        }
+
+        // get canonical name
+        uint32_t cIndex = FindCanonicalNameIndex(font, FC_FAMILYLANG);
+        FcChar8* canonical = nullptr;
+        FcPatternGetString(font, FC_FAMILY, cIndex, &canonical);
+        if (!canonical) {
+            continue;
+        }
+
+        // same as the last one? no need to add a new family, skip
+        if (FcStrCmp(canonical, lastFamilyName) != 0) {
+            lastFamilyName = canonical;
+
+            // add new family if one doesn't already exist
+            familyName.Truncate();
+            AppendUTF8toUTF16(ToCharPtr(canonical), familyName);
+            nsAutoString keyName(familyName);
+            ToLowerCase(keyName);
+
+            fontFamily = mFontFamilies.GetWeak(keyName);
+            if (!fontFamily) {
+                fontFamily = new gfxFontconfigFontFamily(familyName);
+                mFontFamilies.Put(keyName, fontFamily);
+            }
+
+            // Add pointers to other localized family names. Most fonts
+            // only have a single name, so the first call to GetString
+            // will usually not match
+            FcChar8* otherName;
+            int n = (cIndex == 0 ? 1 : 0);
+            while (FcPatternGetString(font, FC_FAMILY, n, &otherName) == FcResultMatch) {
+                NS_ConvertUTF8toUTF16 otherFamilyName(ToCharPtr(otherName));
+                AddOtherFamilyName(fontFamily, otherFamilyName);
+                n++;
+                if (n == int(cIndex)) {
+                    n++; // skip over canonical name
+                }
+            }
+        }
+
+        NS_ASSERTION(fontFamily, "font must belong to a font family");
+        gfxFontconfigFontFamily* fcFamily =
+            static_cast<gfxFontconfigFontFamily*>(fontFamily);
+        fcFamily->AddFontPattern(font);
+
+        // map the psname, fullname ==> font family for local font lookups
+        nsAutoString psname, fullname;
+        GetFaceNames(font, familyName, psname, fullname);
+        if (!psname.IsEmpty()) {
+            ToLowerCase(psname);
+            mLocalNames.Put(psname, fontFamily);
+        }
+        if (!fullname.IsEmpty()) {
+            ToLowerCase(fullname);
+            mLocalNames.Put(fullname, fontFamily);
+        }
+    }
+}
+
+nsresult
+gfxFcPlatformFontList::InitFontList()
+{
+    mLastConfig = FcConfigGetCurrent();
+
+    // reset font lists
+    gfxPlatformFontList::InitFontList();
+
+    mLocalNames.Clear();
+    mGenericMappings.Clear();
+
+    // iterate over available fonts
+    FcFontSet* systemFonts = FcConfigGetFonts(nullptr, FcSetSystem);
+    AddFontSetFamilies(systemFonts);
+
+#ifdef MOZ_BUNDLED_FONTS
+    ActivateBundledFonts();
+    FcFontSet* appFonts = FcConfigGetFonts(nullptr, FcSetApplication);
+    AddFontSetFamilies(appFonts);
+#endif
+
+    mOtherFamilyNamesInitialized = true;
+    return NS_OK;
+}
+
+// For displaying the fontlist in UI, use explicit call to FcFontList. Using
+// FcFontList results in the list containing the localized names as dictated
+// by system defaults.
+static void
+GetSystemFontList(nsTArray<nsString>& aListOfFonts, nsIAtom *aLangGroup)
+{
+    aListOfFonts.Clear();
+
+    nsAutoRef<FcPattern> pat(FcPatternCreate());
+    if (!pat) {
+        return;
+    }
+
+    nsAutoRef<FcObjectSet> os(FcObjectSetBuild(FC_FAMILY, nullptr));
+    if (!os) {
+        return;
+    }
+
+    // add the lang to the pattern
+    nsAutoCString fcLang;
+    GetSampleLangForGroup(aLangGroup, fcLang);
+    if (!fcLang.IsEmpty()) {
+        FcPatternAddString(pat, FC_LANG, ToFcChar8Ptr(fcLang.get()));
+    }
+
+    // ignore size-specific fonts
+    FcPatternAddBool(pat, FC_SCALABLE, FcTrue);
+
+    nsAutoRef<FcFontSet> fs(FcFontList(nullptr, pat, os));
+    if (!fs) {
+        return;
+    }
+
+    for (int i = 0; i < fs->nfont; i++) {
+        char *family;
+
+        if (FcPatternGetString(fs->fonts[i], FC_FAMILY, 0,
+                               (FcChar8 **) &family) != FcResultMatch)
+        {
+            continue;
+        }
+
+        // Remove duplicates...
+        nsAutoString strFamily;
+        AppendUTF8toUTF16(family, strFamily);
+        if (aListOfFonts.Contains(strFamily)) {
+            continue;
+        }
+
+        aListOfFonts.AppendElement(strFamily);
+    }
+
+    aListOfFonts.Sort();
+}
+
+void
+gfxFcPlatformFontList::GetFontList(nsIAtom *aLangGroup,
+                                   const nsACString& aGenericFamily,
+                                   nsTArray<nsString>& aListOfFonts)
+{
+    // Get the list of font family names using fontconfig
+    GetSystemFontList(aListOfFonts, aLangGroup);
+
+    // Under Linux, the generics "serif", "sans-serif" and "monospace"
+    // are included in the pref fontlist. These map to whatever fontconfig
+    // decides they should be for a given language, rather than one of the
+    // fonts listed in the prefs font lists (e.g. font.name.*, font.name-list.*)
+    bool serif = false, sansSerif = false, monospace = false;
+    if (aGenericFamily.IsEmpty())
+        serif = sansSerif = monospace = true;
+    else if (aGenericFamily.LowerCaseEqualsLiteral("serif"))
+        serif = true;
+    else if (aGenericFamily.LowerCaseEqualsLiteral("sans-serif"))
+        sansSerif = true;
+    else if (aGenericFamily.LowerCaseEqualsLiteral("monospace"))
+        monospace = true;
+    else if (aGenericFamily.LowerCaseEqualsLiteral("cursive") ||
+             aGenericFamily.LowerCaseEqualsLiteral("fantasy"))
+        serif = sansSerif = true;
+    else
+        NS_NOTREACHED("unexpected CSS generic font family");
+
+    // The first in the list becomes the default in
+    // gFontsDialog.readFontSelection() if the preference-selected font is not
+    // available, so put system configured defaults first.
+    if (monospace)
+        aListOfFonts.InsertElementAt(0, NS_LITERAL_STRING("monospace"));
+    if (sansSerif)
+        aListOfFonts.InsertElementAt(0, NS_LITERAL_STRING("sans-serif"));
+    if (serif)
+        aListOfFonts.InsertElementAt(0, NS_LITERAL_STRING("serif"));
+}
+
+gfxFontFamily*
+gfxFcPlatformFontList::GetDefaultFont(const gfxFontStyle* aStyle)
+{
+    return FindGenericFamily(NS_LITERAL_STRING("serif"), nsGkAtoms::x_western);
+}
+
+gfxFontEntry*
+gfxFcPlatformFontList::LookupLocalFont(const nsAString& aFontName,
+                                       uint16_t aWeight,
+                                       int16_t aStretch,
+                                       bool aItalic)
+{
+    gfxFontEntry* lookup;
+
+    // first, lookup in face name lists
+    lookup = FindFaceName(aFontName);
+    if (!lookup) {
+        // if not found, check in global facename ==> family list
+        nsAutoString keyName(aFontName);
+        ToLowerCase(keyName);
+        gfxFontFamily* fontFamily = mLocalNames.GetWeak(keyName);
+
+        // name is not in the global list, done
+        if (!fontFamily) {
+            return nullptr;
+        }
+
+        // name is in global list but family needs enumeration
+        fontFamily->FindStyleVariations();
+
+        // facename ==> font entry should now be in the list
+        lookup = FindFaceName(aFontName);
+        NS_ASSERTION(lookup, "facename to family mapping failure");
+        if (!lookup) {
+            return nullptr;
+        }
+    }
+
+    gfxFontconfigFontEntry* fcFontEntry =
+        static_cast<gfxFontconfigFontEntry*>(lookup);
+
+    return new gfxFontconfigFontEntry(fcFontEntry->Name(),
+                                      fcFontEntry->GetPattern(),
+                                      aWeight, aStretch, aItalic);
+}
+
+gfxFontEntry*
+gfxFcPlatformFontList::MakePlatformFont(const nsAString& aFontName,
+                                        uint16_t aWeight,
+                                        int16_t aStretch,
+                                        bool aItalic,
+                                        const uint8_t* aFontData,
+                                        uint32_t aLength)
+{
+    FT_Face face;
+    FT_Error error =
+        FT_New_Memory_Face(gfxFcPlatformFontList::GetFTLibrary(),
+                           aFontData, aLength, 0, &face);
+    if (error != FT_Err_Ok) {
+        NS_Free((void*)aFontData);
+        return nullptr;
+    }
+    if (FT_Err_Ok != FT_Select_Charmap(face, FT_ENCODING_UNICODE)) {
+        FT_Done_Face(face);
+        NS_Free((void*)aFontData);
+        return nullptr;
+    }
+
+    return new gfxFontconfigFontEntry(aFontName, aWeight, aStretch, aItalic,
+                                      aFontData, face);
+}
+
+gfxFontFamily*
+gfxFcPlatformFontList::FindFamily(const nsAString& aFamily,
+                                  nsIAtom* aLanguage,
+                                  bool aUseSystemFonts)
+{
+    nsAutoString familyName(aFamily);
+    ToLowerCase(familyName);
+
+    // deprecated generic names are explicitly converted to standard generics
+    bool isDeprecatedGeneric = false;
+    if (familyName.EqualsLiteral("sans") ||
+        familyName.EqualsLiteral("sans serif")) {
+        familyName.AssignLiteral("sans-serif");
+        isDeprecatedGeneric = true;
+    } else if (familyName.EqualsLiteral("mono")) {
+        familyName.AssignLiteral("monospace");
+        isDeprecatedGeneric = true;
+    }
+
+    // fontconfig generics? use fontconfig to determine the family for lang
+    if (isDeprecatedGeneric ||
+        mozilla::FontFamilyName::Convert(familyName).IsGeneric()) {
+        return FindGenericFamily(familyName, aLanguage);
+    }
+
+    // fontconfig allows conditional substitutions in such a way that it's
+    // difficult to distinguish an explicit substitution from other suggested
+    // choices. To sniff out explicit substitutions, compare the substitutions
+    // for "font, -moz-sentinel" to "-moz-sentinel" to sniff out the
+    // substitutions
+    //
+    // Example:
+    //
+    //   serif ==> DejaVu Serif, ...
+    //   Helvetica, serif ==> Helvetica, TeX Gyre Heros, Nimbus Sans L, DejaVu Serif
+    //
+    // In this case fontconfig is including Tex Gyre Heros and
+    // Nimbus Sans L as alternatives for Helvetica.
+
+    // substitutions for serif pattern
+    const FcChar8* kSentinelName = ToFcChar8Ptr("-moz-sentinel");
+    nsAutoRef<FcPattern> sentinelSubst(FcPatternCreate());
+    FcPatternAddString(sentinelSubst, FC_FAMILY, kSentinelName);
+    FcConfigSubstitute(nullptr, sentinelSubst, FcMatchPattern);
+    FcChar8* sentinelFirstFamily = nullptr;
+    FcPatternGetString(sentinelSubst, FC_FAMILY, 0, &sentinelFirstFamily);
+
+    // substitutions for font, -moz-sentinel pattern
+    nsAutoRef<FcPattern> fontWithSentinel(FcPatternCreate());
+    NS_ConvertUTF16toUTF8 familyToFind(familyName);
+    FcPatternAddString(fontWithSentinel, FC_FAMILY, ToFcChar8Ptr(familyToFind.get()));
+    FcPatternAddString(fontWithSentinel, FC_FAMILY, kSentinelName);
+    FcConfigSubstitute(nullptr, fontWithSentinel, FcMatchPattern);
+
+    // iterate through substitutions until hitting the first serif font
+    FcChar8* substName = nullptr;
+    for (int i = 0;
+         FcPatternGetString(fontWithSentinel, FC_FAMILY,
+                            i, &substName) == FcResultMatch;
+         i++)
+    {
+        NS_ConvertUTF8toUTF16 subst(ToCharPtr(substName));
+        if (sentinelFirstFamily && FcStrCmp(substName, sentinelFirstFamily) == 0) {
+            break;
+        }
+        gfxFontFamily* foundFamily = gfxPlatformFontList::FindFamily(subst);
+        if (foundFamily) {
+            return foundFamily;
+        }
+    }
+
+    return nullptr;
+}
+
+bool
+gfxFcPlatformFontList::GetStandardFamilyName(const nsAString& aFontName,
+                                             nsAString& aFamilyName)
+{
+    // The fontconfig list of fonts includes generic family names in the
+    // font list. For these, just use the generic name.
+    if (aFontName.EqualsLiteral("serif") ||
+        aFontName.EqualsLiteral("sans-serif") ||
+        aFontName.EqualsLiteral("monospace")) {
+        aFamilyName.Assign(aFontName);
+        return true;
+    }
+
+    gfxFontFamily *family = FindFamily(aFontName);
+    if (family) {
+        family->LocalizedName(aFamilyName);
+        return true;
+    }
+
+    return false;
+}
+
+/* static */ FT_Library
+gfxFcPlatformFontList::GetFTLibrary()
+{
+    if (!sCairoFTLibrary) {
+        // Use cairo's FT_Library so that cairo takes care of shutdown of the
+        // FT_Library after it has destroyed its font_faces, and FT_Done_Face
+        // has been called on each FT_Face, at least until this bug is fixed:
+        // https://bugs.freedesktop.org/show_bug.cgi?id=18857
+        //
+        // Cairo keeps it's own FT_Library object for creating FT_Face
+        // instances, so use that. There's no simple API for accessing this
+        // so use the hacky method below of making a font and extracting
+        // the library pointer from that.
+
+        bool needsBold;
+        gfxFontStyle style;
+        gfxPlatformFontList* pfl = gfxPlatformFontList::PlatformFontList();
+        gfxFontFamily* family = pfl->GetDefaultFont(&style);
+        NS_ASSERTION(family, "couldn't find a default font family");
+        gfxFontEntry* fe = family->FindFontForStyle(style, needsBold);
+        if (!fe) {
+            return nullptr;
+        }
+        nsRefPtr<gfxFont> font = fe->FindOrMakeFont(&style, false);
+        if (!font) {
+            return nullptr;
+        }
+
+        gfxFT2FontBase* ft2Font = reinterpret_cast<gfxFT2FontBase*>(font.get());
+        gfxFT2LockedFace face(ft2Font);
+        if (!face.get()) {
+            return nullptr;
+        }
+
+        sCairoFTLibrary = face.get()->glyph->library;
+    }
+
+    return sCairoFTLibrary;
+}
+
+gfxFontFamily*
+gfxFcPlatformFontList::FindGenericFamily(const nsAString& aGeneric,
+                                         nsIAtom* aLanguage)
+{
+    // set up name
+    NS_ConvertUTF16toUTF8 generic(aGeneric);
+
+    nsAutoCString fcLang;
+    GetSampleLangForGroup(aLanguage, fcLang);
+
+    nsAutoCString genericLang(generic);
+    genericLang.Append(fcLang);
+
+    // try to get the family from the cache
+    gfxFontFamily *genericFamily = mGenericMappings.GetWeak(genericLang);
+    if (genericFamily) {
+        return genericFamily;
+    }
+
+    // if not found, ask fontconfig to pick the appropriate font
+    nsAutoRef<FcPattern> genericPattern(FcPatternCreate());
+    FcPatternAddString(genericPattern, FC_FAMILY,
+                       ToFcChar8Ptr(generic.get()));
+
+    // -- add the lang to the pattern
+    if (!fcLang.IsEmpty()) {
+        FcPatternAddString(genericPattern, FC_LANG,
+                           ToFcChar8Ptr(fcLang.get()));
+    }
+
+    // -- perform substitutions
+    FcConfigSubstitute(nullptr, genericPattern, FcMatchPattern);
+    FcDefaultSubstitute(genericPattern);
+
+    // -- sort to get the closest matches
+    FcResult result;
+    nsAutoRef<FcFontSet> faces(FcFontSort(nullptr, genericPattern, FcFalse,
+                                          nullptr, &result));
+
+    // -- pick the first font for which a font family exists
+    for (int i = 0; i < faces->nfont; i++) {
+        FcPattern* font = faces->fonts[i];
+        FcChar8* mappedGeneric = nullptr;
+
+        // not scalable? skip...
+        FcBool scalable;
+        if (FcPatternGetBool(font, FC_SCALABLE, 0, &scalable) != FcResultMatch ||
+            !scalable) {
+            continue;
+        }
+
+        FcPatternGetString(font, FC_FAMILY, 0, &mappedGeneric);
+        if (mappedGeneric) {
+            NS_ConvertUTF8toUTF16 mappedGenericName(ToCharPtr(mappedGeneric));
+            genericFamily = gfxPlatformFontList::FindFamily(mappedGenericName);
+            if (genericFamily) {
+                //printf("generic %s ==> %s\n", genericLang.get(), (const char*)mappedGeneric);
+                mGenericMappings.Put(genericLang, genericFamily);
+                break;
+            }
+        }
+    }
+
+    return genericFamily;
+}
+
+/* static */ void
+gfxFcPlatformFontList::CheckFontUpdates(nsITimer *aTimer, void *aThis)
+{
+    // check for font updates
+    FcInitBringUptoDate();
+
+    // update fontlist if current config changed
+    gfxFcPlatformFontList *pfl = static_cast<gfxFcPlatformFontList*>(aThis);
+    FcConfig* current = FcConfigGetCurrent();
+    if (current != pfl->GetLastConfig()) {
+        pfl->UpdateFontList();
+        pfl->ForceGlobalReflow();
+    }
+}
+
+#ifdef MOZ_BUNDLED_FONTS
+void
+gfxFcPlatformFontList::ActivateBundledFonts()
+{
+    if (!mBundledFontsInitialized) {
+        mBundledFontsInitialized = true;
+        nsCOMPtr<nsIFile> localDir;
+        nsresult rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(localDir));
+        if (NS_FAILED(rv)) {
+            return;
+        }
+        if (NS_FAILED(localDir->Append(NS_LITERAL_STRING("fonts")))) {
+            return;
+        }
+        bool isDir;
+        if (NS_FAILED(localDir->IsDirectory(&isDir)) || !isDir) {
+            return;
+        }
+        if (NS_FAILED(localDir->GetNativePath(mBundledFontsPath))) {
+            return;
+        }
+    }
+    if (!mBundledFontsPath.IsEmpty()) {
+        FcConfigAppFontAddDir(nullptr, ToFcChar8Ptr(mBundledFontsPath.get()));
+    }
+}
+#endif
+
+#ifdef MOZ_WIDGET_GTK
+/***************************************************************************
+ *
+ * This function must be last in the file because it uses the system cairo
+ * library.  Above this point the cairo library used is the tree cairo if
+ * MOZ_TREE_CAIRO.
+ */
+
+#if MOZ_TREE_CAIRO
+// Tree cairo symbols have different names.  Disable their activation through
+// preprocessor macros.
+#undef cairo_ft_font_options_substitute
+
+// The system cairo functions are not declared because the include paths cause
+// the gdk headers to pick up the tree cairo.h.
+extern "C" {
+NS_VISIBILITY_DEFAULT void
+cairo_ft_font_options_substitute (const cairo_font_options_t *options,
+                                  FcPattern                  *pattern);
+}
+#endif
+
+static void
+ApplyGdkScreenFontOptions(FcPattern *aPattern)
+{
+    const cairo_font_options_t *options =
+        gdk_screen_get_font_options(gdk_screen_get_default());
+
+    cairo_ft_font_options_substitute(options, aPattern);
+}
+
+#endif // MOZ_WIDGET_GTK2
+
+
new file mode 100644
--- /dev/null
+++ b/gfx/thebes/gfxFcPlatformFontList.h
@@ -0,0 +1,263 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef GFXFCPLATFORMFONTLIST_H_
+#define GFXFCPLATFORMFONTLIST_H_
+
+#include "gfxFont.h"
+#include "gfxFontEntry.h"
+#include "gfxFT2FontBase.h"
+#include "gfxPlatformFontList.h"
+#include "mozilla/mozalloc.h"
+
+#include <fontconfig/fontconfig.h>
+#include "ft2build.h"
+#include FT_FREETYPE_H
+#include FT_TRUETYPE_TABLES_H
+#include <cairo.h>
+#include <cairo-ft.h>
+
+#include "gfxFontconfigUtils.h" // xxx - only for nsAutoRefTraits<FcPattern>, etc.
+
+template <>
+class nsAutoRefTraits<FcObjectSet> : public nsPointerRefTraits<FcObjectSet>
+{
+public:
+    static void Release(FcObjectSet *ptr) { FcObjectSetDestroy(ptr); }
+};
+
+template <>
+class nsAutoRefTraits<FcConfig> : public nsPointerRefTraits<FcConfig>
+{
+public:
+    static void Release(FcConfig *ptr) { FcConfigDestroy(ptr); }
+    static void AddRef(FcConfig *ptr) { FcConfigReference(ptr); }
+};
+
+// Helper classes used for clearning out user font data when cairo font
+// face is destroyed. Since multiple faces may use the same data, be
+// careful to assure that the data is only cleared out when all uses
+// expire. The font entry object contains a refptr to FTUserFontData and
+// each cairo font created from that font entry contains a
+// FTUserFontDataRef with a refptr to that same FTUserFontData object.
+
+class FTUserFontData {
+public:
+    NS_INLINE_DECL_REFCOUNTING(FTUserFontData)
+
+    explicit FTUserFontData(FT_Face aFace, const uint8_t* aData)
+        : mFace(aFace), mFontData(aData)
+    {
+    }
+
+    const uint8_t *FontData() const { return mFontData; }
+
+private:
+    ~FTUserFontData()
+    {
+        FT_Done_Face(mFace);
+        if (mFontData) {
+            NS_Free((void*)mFontData);
+        }
+    }
+
+    FT_Face        mFace;
+    const uint8_t *mFontData;
+};
+
+class FTUserFontDataRef {
+public:
+    explicit FTUserFontDataRef(FTUserFontData *aUserFontData)
+        : mUserFontData(aUserFontData)
+    {
+    }
+
+    static void Destroy(void* aData) {
+        FTUserFontDataRef* aUserFontDataRef =
+            static_cast<FTUserFontDataRef*>(aData);
+        delete aUserFontDataRef;
+    }
+
+private:
+    nsRefPtr<FTUserFontData> mUserFontData;
+};
+
+// The names for the font entry and font classes should really
+// the common 'Fc' abbreviation but the gfxPangoFontGroup code already
+// defines versions of these, so use the verbose name for now.
+
+class gfxFontconfigFontEntry : public gfxFontEntry {
+public:
+    // used for system fonts with explicit patterns
+    explicit gfxFontconfigFontEntry(const nsAString& aFaceName,
+                                    FcPattern* aFontPattern);
+
+    // used for data fonts where the fontentry takes ownership
+    // of the font data and the FT_Face
+    explicit gfxFontconfigFontEntry(const nsAString& aFaceName,
+                                    uint16_t aWeight,
+                                    int16_t aStretch,
+                                    bool aItalic,
+                                    const uint8_t *aData,
+                                    FT_Face aFace);
+
+    // used for @font-face local system fonts with explicit patterns
+    explicit gfxFontconfigFontEntry(const nsAString& aFaceName,
+                                    FcPattern* aFontPattern,
+                                    uint16_t aWeight,
+                                    int16_t aStretch,
+                                    bool aItalic);
+
+    FcPattern* GetPattern() { return mFontPattern; }
+
+    bool SupportsLangGroup(nsIAtom *aLangGroup) const override;
+
+    nsresult ReadCMAP(FontInfoData *aFontInfoData = nullptr) override;
+    bool TestCharacterMap(uint32_t aCh) override;
+
+    hb_blob_t* GetFontTable(uint32_t aTableTag) override;
+
+    void ForgetHBFace() override;
+    void ReleaseGrFace(gr_face* aFace) override;
+
+protected:
+    virtual ~gfxFontconfigFontEntry();
+
+    gfxFont *CreateFontInstance(const gfxFontStyle *aFontStyle,
+                                bool aNeedsBold) override;
+
+    // helper method for creating cairo font from pattern
+    cairo_scaled_font_t*
+    CreateScaledFont(FcPattern* aRenderPattern,
+                     const gfxFontStyle *aStyle,
+                     bool aNeedsBold);
+
+    // override to pull data from FTFace
+    virtual nsresult
+    CopyFontTable(uint32_t aTableTag,
+                  FallibleTArray<uint8_t>& aBuffer) override;
+
+    // if HB or GR faces are gone, close down the FT_Face
+    void MaybeReleaseFTFace();
+
+    double GetAspect();
+
+    // pattern for a single face of a family
+    nsCountedRef<FcPattern> mFontPattern;
+
+    // user font data, when needed
+    nsRefPtr<FTUserFontData> mUserFontData;
+
+    // FTFace - initialized when needed
+    FT_Face   mFTFace;
+    bool      mFTFaceInitialized;
+    double    mAspect;
+
+    // data font
+    const uint8_t* mFontData;
+};
+
+class gfxFontconfigFontFamily : public gfxFontFamily {
+public:
+    explicit gfxFontconfigFontFamily(const nsAString& aName) :
+        gfxFontFamily(aName) { }
+
+    void FindStyleVariations(FontInfoData *aFontInfoData = nullptr) override;
+
+    // Families are constructed initially with just references to patterns.
+    // When necessary, these are enumerated within FindStyleVariations.
+    void AddFontPattern(FcPattern* aFontPattern);
+
+protected:
+    virtual ~gfxFontconfigFontFamily() { }
+
+    nsTArray<nsCountedRef<FcPattern> > mFontPatterns;
+};
+
+class gfxFontconfigFont : public gfxFT2FontBase {
+public:
+    gfxFontconfigFont(cairo_scaled_font_t *aScaledFont,
+                      gfxFontEntry *aFontEntry,
+                      const gfxFontStyle *aFontStyle,
+                      bool aNeedsBold);
+
+#ifdef USE_SKIA
+    virtual mozilla::TemporaryRef<mozilla::gfx::GlyphRenderingOptions>
+    GetGlyphRenderingOptions(const TextRunDrawParams* aRunParams = nullptr) override;
+#endif
+
+protected:
+    virtual ~gfxFontconfigFont();
+};
+
+class gfxFcPlatformFontList : public gfxPlatformFontList {
+public:
+    gfxFcPlatformFontList();
+
+    // initialize font lists
+    nsresult InitFontList() override;
+
+    void GetFontList(nsIAtom *aLangGroup,
+                     const nsACString& aGenericFamily,
+                     nsTArray<nsString>& aListOfFonts) override;
+
+
+    gfxFontFamily*
+    GetDefaultFont(const gfxFontStyle* aStyle) override;
+
+    gfxFontEntry*
+    LookupLocalFont(const nsAString& aFontName, uint16_t aWeight,
+                    int16_t aStretch, bool aItalic) override;
+
+    gfxFontEntry*
+    MakePlatformFont(const nsAString& aFontName, uint16_t aWeight,
+                     int16_t aStretch, bool aItalic,
+                     const uint8_t* aFontData,
+                     uint32_t aLength) override;
+
+    gfxFontFamily* FindFamily(const nsAString& aFamily,
+                              nsIAtom* aLanguage = nullptr,
+                              bool aUseSystemFonts = false) override;
+
+    bool GetStandardFamilyName(const nsAString& aFontName,
+                               nsAString& aFamilyName) override;
+
+    FcConfig* GetLastConfig() const { return mLastConfig; }
+
+    static FT_Library GetFTLibrary();
+
+protected:
+    virtual ~gfxFcPlatformFontList();
+
+    // add all the font families found in a font set
+    void AddFontSetFamilies(FcFontSet* aFontSet);
+
+    // figure out which family fontconfig maps a generic to
+    // (aGeneric assumed already lowercase)
+    gfxFontFamily* FindGenericFamily(const nsAString& aGeneric,
+                                     nsIAtom* aLanguage);
+
+    static void CheckFontUpdates(nsITimer *aTimer, void *aThis);
+
+#ifdef MOZ_BUNDLED_FONTS
+    void ActivateBundledFonts();
+    nsCString mBundledFontsPath;
+    bool mBundledFontsInitialized;
+#endif
+
+    // to avoid enumerating all fonts, maintain a mapping of local font
+    // names to family
+    nsRefPtrHashtable<nsStringHashKey, gfxFontFamily> mLocalNames;
+
+    // caching generic/lang ==> font family
+    nsRefPtrHashtable<nsCStringHashKey, gfxFontFamily> mGenericMappings;
+
+    nsCOMPtr<nsITimer> mCheckFontUpdatesTimer;
+    nsCountedRef<FcConfig> mLastConfig;
+
+    static FT_Library sCairoFTLibrary;
+};
+
+#endif /* GFXPLATFORMFONTLIST_H_ */
--- a/gfx/thebes/gfxFont.h
+++ b/gfx/thebes/gfxFont.h
@@ -49,16 +49,18 @@ class gfxTextContextPaint;
 #define NO_FONT_LANGUAGE_OVERRIDE      0
 
 #define SMALL_CAPS_SCALE_FACTOR        0.8
 
 // The skew factor used for synthetic-italic [oblique] fonts;
 // we use a platform-dependent value to harmonize with the platform's own APIs.
 #ifdef XP_WIN
 #define OBLIQUE_SKEW_FACTOR  0.3
+#elif defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_QT)
+#define OBLIQUE_SKEW_FACTOR  0.2
 #else
 #define OBLIQUE_SKEW_FACTOR  0.25
 #endif
 
 struct gfxTextRunDrawCallbacks;
 
 namespace mozilla {
 namespace gfx {
--- a/gfx/thebes/gfxFontTest.h
+++ b/gfx/thebes/gfxFontTest.h
@@ -4,17 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_FONT_TEST_H
 #define GFX_FONT_TEST_H
 
 #include "nsString.h"
 #include "nsTArray.h"
 
-#include "cairo/cairo.h"
+#include "cairo.h"
 
 struct gfxFontTestItem {
     gfxFontTestItem(const nsCString& fontName,
                     cairo_glyph_t *cglyphs, int nglyphs)
         : platformFont(fontName)
     {
         glyphs = new cairo_glyph_t[nglyphs];
         memcpy (glyphs, cglyphs, sizeof(cairo_glyph_t) * nglyphs);
--- a/gfx/thebes/gfxGDIFontList.cpp
+++ b/gfx/thebes/gfxGDIFontList.cpp
@@ -825,17 +825,19 @@ gfxGDIFontList::MakePlatformFont(const n
     if (isCFF && !IsWin7OrLater()) {
         fe->mForceGDI = true;
     }
 
     return fe;
 }
 
 gfxFontFamily*
-gfxGDIFontList::FindFamily(const nsAString& aFamily, bool aUseSystemFonts)
+gfxGDIFontList::FindFamily(const nsAString& aFamily,
+                           nsIAtom* aLanguage,
+                           bool aUseSystemFonts)
 {
     nsAutoString keyName(aFamily);
     BuildKeyNameFromFontName(keyName);
 
     gfxFontFamily *ff = mFontSubstitutes.GetWeak(keyName);
     if (ff) {
         return ff;
     }
--- a/gfx/thebes/gfxGDIFontList.h
+++ b/gfx/thebes/gfxGDIFontList.h
@@ -305,16 +305,17 @@ public:
     }
 
     // initialize font lists
     virtual nsresult InitFontList();
 
     virtual gfxFontFamily* GetDefaultFont(const gfxFontStyle* aStyle);
 
     virtual gfxFontFamily* FindFamily(const nsAString& aFamily,
+                                      nsIAtom* aLanguage = nullptr,
                                       bool aUseSystemFonts = false);
 
     virtual gfxFontEntry* LookupLocalFont(const nsAString& aFontName,
                                           uint16_t aWeight,
                                           int16_t aStretch,
                                           bool aItalic);
 
     virtual gfxFontEntry* MakePlatformFont(const nsAString& aFontName,
--- a/gfx/thebes/gfxPangoFonts.cpp
+++ b/gfx/thebes/gfxPangoFonts.cpp
@@ -1257,16 +1257,17 @@ gfxPangoFontGroup::gfxPangoFontGroup(con
     // This language is passed to the font for shaping.
     // Shaping doesn't know about lang groups so make it a real language.
     if (mPangoLanguage) {
         mStyle.language = do_GetAtom(pango_language_to_string(mPangoLanguage));
     }
 
     // dummy entry, will be replaced when actually needed
     mFonts.AppendElement(FamilyFace());
+    mSkipUpdateUserFonts = true;
 }
 
 gfxPangoFontGroup::~gfxPangoFontGroup()
 {
 }
 
 gfxFontGroup *
 gfxPangoFontGroup::Copy(const gfxFontStyle *aStyle)
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -71,16 +71,20 @@
 #include "imgITools.h"
 
 #include "plstr.h"
 #include "nsCRT.h"
 #include "GLContext.h"
 #include "GLContextProvider.h"
 #include "mozilla/gfx/Logging.h"
 
+#if defined(MOZ_WIDGET_GTK)
+#include "gfxPlatformGtk.h" // xxx - for UseFcFontList
+#endif
+
 #ifdef MOZ_WIDGET_ANDROID
 #include "TexturePoolOGL.h"
 #endif
 
 #ifdef MOZ_WIDGET_GONK
 #include "mozilla/layers/GrallocTextureHost.h"
 #endif
 
@@ -377,16 +381,49 @@ static const char *gPrefLangNames[] = {
     "x-orya",
     "x-telu",
     "x-knda",
     "x-sinh",
     "x-tibt",
     "x-unicode",
 };
 
+// this needs to match the list of pref font.default.xx entries listed in all.js!
+// the order *must* match the order in eFontPrefLang
+static nsIAtom* gPrefLangToLangGroups[] = {
+    nsGkAtoms::x_western,
+    nsGkAtoms::Japanese,
+    nsGkAtoms::Taiwanese,
+    nsGkAtoms::Chinese,
+    nsGkAtoms::HongKongChinese,
+    nsGkAtoms::ko,
+    nsGkAtoms::x_cyrillic,
+    nsGkAtoms::el,
+    nsGkAtoms::th,
+    nsGkAtoms::he,
+    nsGkAtoms::ar,
+    nsGkAtoms::x_devanagari,
+    nsGkAtoms::x_tamil,
+    nsGkAtoms::x_armn,
+    nsGkAtoms::x_beng,
+    nsGkAtoms::x_cans,
+    nsGkAtoms::x_ethi,
+    nsGkAtoms::x_geor,
+    nsGkAtoms::x_gujr,
+    nsGkAtoms::x_guru,
+    nsGkAtoms::x_khmr,
+    nsGkAtoms::x_mlym,
+    nsGkAtoms::x_orya,
+    nsGkAtoms::x_telu,
+    nsGkAtoms::x_knda,
+    nsGkAtoms::x_sinh,
+    nsGkAtoms::x_tibt,
+    nsGkAtoms::Unicode
+};
+
 gfxPlatform::gfxPlatform()
   : mTileWidth(-1)
   , mTileHeight(-1)
   , mAzureCanvasBackendCollector(this, &gfxPlatform::GetAzureBackendInfo)
   , mApzSupportCollector(this, &gfxPlatform::GetApzSupportInfo)
 {
     mAllowDownloadableFonts = UNINITIALIZED_VALUE;
     mFallbackUsesCmaps = UNINITIALIZED_VALUE;
@@ -498,22 +535,29 @@ gfxPlatform::Init()
     mozilla::gl::GLContext::StaticInit();
 #endif
 
     InitLayersAccelerationPrefs();
     InitLayersIPC();
 
     nsresult rv;
 
-#if defined(XP_MACOSX) || defined(XP_WIN) || defined(ANDROID) // temporary, until this is implemented on others
-    rv = gfxPlatformFontList::Init();
-    if (NS_FAILED(rv)) {
-        NS_RUNTIMEABORT("Could not initialize gfxPlatformFontList");
+    bool usePlatformFontList = true;
+#if defined(MOZ_WIDGET_GTK)
+    usePlatformFontList = gfxPlatformGtk::UseFcFontList();
+#elif defined(MOZ_WIDGET_QT)
+    usePlatformFontList = false;
+#endif
+
+    if (usePlatformFontList) {
+        rv = gfxPlatformFontList::Init();
+        if (NS_FAILED(rv)) {
+            NS_RUNTIMEABORT("Could not initialize gfxPlatformFontList");
+        }
     }
-#endif
 
     gPlatform->mScreenReferenceSurface =
         gPlatform->CreateOffscreenSurface(IntSize(1, 1),
                                           gfxContentType::COLOR_ALPHA);
     if (!gPlatform->mScreenReferenceSurface) {
         NS_RUNTIMEABORT("Could not initialize mScreenReferenceSurface");
     }
 
@@ -1469,16 +1513,29 @@ gfxPlatform::GetFontPrefLangFor(nsIAtom 
 {
     if (!aLang)
         return eFontPrefLang_Others;
     nsAutoCString lang;
     aLang->ToUTF8String(lang);
     return GetFontPrefLangFor(lang.get());
 }
 
+nsIAtom*
+gfxPlatform::GetLangGroupForPrefLang(eFontPrefLang aLang)
+{
+    // the special CJK set pref lang should be resolved into separate
+    // calls to individual CJK pref langs before getting here
+    NS_ASSERTION(aLang != eFontPrefLang_CJKSet, "unresolved CJK set pref lang");
+
+    if (uint32_t(aLang) < ArrayLength(gPrefLangToLangGroups)) {
+        return gPrefLangToLangGroups[uint32_t(aLang)];
+    }
+    return nsGkAtoms::Unicode;
+}
+
 const char*
 gfxPlatform::GetPrefLangName(eFontPrefLang aLang)
 {
     if (uint32_t(aLang) < ArrayLength(gPrefLangNames)) {
         return gPrefLangNames[uint32_t(aLang)];
     }
     return nullptr;
 }
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -465,16 +465,19 @@ public:
                                   void *aClosure);
 
     // convert a lang group to enum constant (i.e. "zh-TW" ==> eFontPrefLang_ChineseTW)
     static eFontPrefLang GetFontPrefLangFor(const char* aLang);
 
     // convert a lang group atom to enum constant
     static eFontPrefLang GetFontPrefLangFor(nsIAtom *aLang);
 
+    // convert an enum constant to a lang group atom
+    static nsIAtom* GetLangGroupForPrefLang(eFontPrefLang aLang);
+
     // convert a enum constant to lang group string (i.e. eFontPrefLang_ChineseTW ==> "zh-TW")
     static const char* GetPrefLangName(eFontPrefLang aLang);
    
     // map a Unicode range (based on char code) to a font language for Preferences
     static eFontPrefLang GetFontPrefLangFor(uint8_t aUnicodeRange);
 
     // returns true if a pref lang is CJK
     static bool IsLangCJK(eFontPrefLang aLang);
--- a/gfx/thebes/gfxPlatformFontList.cpp
+++ b/gfx/thebes/gfxPlatformFontList.cpp
@@ -645,18 +645,17 @@ gfxPlatformFontList::CommonFontFallback(
                                                        aRunScript,
                                                        defaultFallbacks);
     numFallbacks = defaultFallbacks.Length();
     for (i = 0; i < numFallbacks; i++) {
         nsAutoString familyName;
         const char *fallbackFamily = defaultFallbacks[i];
 
         familyName.AppendASCII(fallbackFamily);
-        gfxFontFamily *fallback =
-                gfxPlatformFontList::PlatformFontList()->FindFamily(familyName);
+        gfxFontFamily *fallback = FindFamilyByCanonicalName(familyName);
         if (!fallback)
             continue;
 
         gfxFontEntry *fontEntry;
         bool needsBold;  // ignored in the system fallback case
 
         // use first font in list that supports a given character
         fontEntry = fallback->FindFontForStyle(*aMatchStyle, needsBold);
@@ -721,17 +720,19 @@ gfxPlatformFontList::CheckFamily(gfxFont
         mFontFamilies.Remove(key);
         return nullptr;
     }
 
     return aFamily;
 }
 
 gfxFontFamily* 
-gfxPlatformFontList::FindFamily(const nsAString& aFamily, bool aUseSystemFonts)
+gfxPlatformFontList::FindFamily(const nsAString& aFamily,
+                                nsIAtom* aLanguage,
+                                bool aUseSystemFonts)
 {
     nsAutoString key;
     gfxFontFamily *familyEntry;
     GenerateFontListKey(aFamily, key);
 
     NS_ASSERTION(mFontFamilies.Count() != 0, "system font list was not initialized correctly");
 
     // lookup in canonical (i.e. English) family name list
--- a/gfx/thebes/gfxPlatformFontList.h
+++ b/gfx/thebes/gfxPlatformFontList.h
@@ -105,32 +105,33 @@ public:
         sPlatformFontList = nullptr;
     }
 
     virtual ~gfxPlatformFontList();
 
     // initialize font lists
     virtual nsresult InitFontList();
 
-    void GetFontList (nsIAtom *aLangGroup,
-                      const nsACString& aGenericFamily,
-                      nsTArray<nsString>& aListOfFonts);
+    virtual void GetFontList(nsIAtom *aLangGroup,
+                             const nsACString& aGenericFamily,
+                             nsTArray<nsString>& aListOfFonts);
 
     void UpdateFontList();
 
     void ClearPrefFonts() { mPrefFonts.Clear(); }
 
     virtual void GetFontFamilyList(nsTArray<nsRefPtr<gfxFontFamily> >& aFamilyArray);
 
     gfxFontEntry*
     SystemFindFontForChar(uint32_t aCh, uint32_t aNextCh,
                           int32_t aRunScript,
                           const gfxFontStyle* aStyle);
 
     virtual gfxFontFamily* FindFamily(const nsAString& aFamily,
+                                      nsIAtom* aLanguage = nullptr,
                                       bool aUseSystemFonts = false);
 
     gfxFontEntry* FindFontForFamily(const nsAString& aFamily, const gfxFontStyle* aStyle, bool& aNeedsBold);
 
     bool GetPrefFontFamilyEntries(eFontPrefLang aLangGroup, nsTArray<nsRefPtr<gfxFontFamily> > *array);
     void SetPrefFontFamilyEntries(eFontPrefLang aLangGroup, nsTArray<nsRefPtr<gfxFontFamily> >& array);
 
     // name lookup table methods
@@ -205,16 +206,28 @@ protected:
     explicit gfxPlatformFontList(bool aNeedFullnamePostscriptNames = true);
 
     static gfxPlatformFontList *sPlatformFontList;
 
     static PLDHashOperator FindFontForCharProc(nsStringHashKey::KeyType aKey,
                                                nsRefPtr<gfxFontFamily>& aFamilyEntry,
                                                void* userArg);
 
+    // Lookup family name in global family list without substitutions or
+    // localized family name lookup. Used for common font fallback families.
+    gfxFontFamily* FindFamilyByCanonicalName(const nsAString& aFamily) {
+        nsAutoString key;
+        gfxFontFamily *familyEntry;
+        GenerateFontListKey(aFamily, key);
+        if ((familyEntry = mFontFamilies.GetWeak(key))) {
+            return CheckFamily(familyEntry);
+        }
+        return nullptr;
+    }
+
     // returns default font for a given character, null otherwise
     gfxFontEntry* CommonFontFallback(uint32_t aCh, uint32_t aNextCh,
                                      int32_t aRunScript,
                                      const gfxFontStyle* aMatchStyle,
                                      gfxFontFamily** aMatchedFamily);
 
     // search fonts system-wide for a given character, null otherwise
     virtual gfxFontEntry* GlobalFontFallback(const uint32_t aCh,
--- a/gfx/thebes/gfxPlatformGtk.cpp
+++ b/gfx/thebes/gfxPlatformGtk.cpp
@@ -7,16 +7,17 @@
 #define PANGO_ENABLE_ENGINE
 
 #include "gfxPlatformGtk.h"
 #include "prenv.h"
 
 #include "nsUnicharUtils.h"
 #include "nsUnicodeProperties.h"
 #include "gfx2DGlue.h"
+#include "gfxFcPlatformFontList.h"
 #include "gfxFontconfigUtils.h"
 #include "gfxPangoFonts.h"
 #include "gfxContext.h"
 #include "gfxUserFontSet.h"
 #include "gfxUtils.h"
 #include "gfxFT2FontBase.h"
 
 #include "mozilla/gfx/2D.h"
@@ -54,37 +55,43 @@ gfxFontconfigUtils *gfxPlatformGtk::sFon
 #if (MOZ_WIDGET_GTK == 2)
 static cairo_user_data_key_t cairo_gdk_drawable_key;
 #endif
 
 #ifdef MOZ_X11
     bool gfxPlatformGtk::sUseXRender = true;
 #endif
 
+bool gfxPlatformGtk::sUseFcFontList = false;
+
 gfxPlatformGtk::gfxPlatformGtk()
 {
-    if (!sFontconfigUtils)
+    sUseFcFontList = mozilla::Preferences::GetBool("gfx.font_rendering.fontconfig.fontlist.enabled");
+    if (!sUseFcFontList && !sFontconfigUtils) {
         sFontconfigUtils = gfxFontconfigUtils::GetFontconfigUtils();
+    }
+
 #ifdef MOZ_X11
     sUseXRender = (GDK_IS_X11_DISPLAY(gdk_display_get_default())) ? 
                     mozilla::Preferences::GetBool("gfx.xrender.enabled") : false;
 #endif
 
     uint32_t canvasMask = BackendTypeBit(BackendType::CAIRO) | BackendTypeBit(BackendType::SKIA);
     uint32_t contentMask = BackendTypeBit(BackendType::CAIRO) | BackendTypeBit(BackendType::SKIA);
     InitBackendPrefs(canvasMask, BackendType::CAIRO,
                      contentMask, BackendType::CAIRO);
 }
 
 gfxPlatformGtk::~gfxPlatformGtk()
 {
-    gfxFontconfigUtils::Shutdown();
-    sFontconfigUtils = nullptr;
-
-    gfxPangoFontGroup::Shutdown();
+    if (!sUseFcFontList) {
+        gfxFontconfigUtils::Shutdown();
+        sFontconfigUtils = nullptr;
+        gfxPangoFontGroup::Shutdown();
+    }
 }
 
 void
 gfxPlatformGtk::FlushContentDrawing()
 {
     if (UseXRender()) {
         XFlush(DefaultXDisplay());
     }
@@ -144,58 +151,138 @@ gfxPlatformGtk::CreateOffscreenSurface(c
     return newSurface.forget();
 }
 
 nsresult
 gfxPlatformGtk::GetFontList(nsIAtom *aLangGroup,
                             const nsACString& aGenericFamily,
                             nsTArray<nsString>& aListOfFonts)
 {
-    return sFontconfigUtils->GetFontList(aLangGroup, aGenericFamily,
+    if (sUseFcFontList) {
+        gfxPlatformFontList::PlatformFontList()->GetFontList(aLangGroup,
+                                                             aGenericFamily,
+                                                             aListOfFonts);
+        return NS_OK;
+    }
+
+    return sFontconfigUtils->GetFontList(aLangGroup,
+                                         aGenericFamily,
                                          aListOfFonts);
 }
 
 nsresult
 gfxPlatformGtk::UpdateFontList()
 {
+    if (sUseFcFontList) {
+        gfxPlatformFontList::PlatformFontList()->UpdateFontList();
+        return NS_OK;
+    }
+
     return sFontconfigUtils->UpdateFontList();
 }
 
+// xxx - this is ubuntu centric, need to go through other distros and flesh
+// out a more general list
+static const char kFontDejaVuSans[] = "DejaVu Sans";
+static const char kFontDejaVuSerif[] = "DejaVu Serif";
+static const char kFontFreeSans[] = "FreeSans";
+static const char kFontFreeSerif[] = "FreeSerif";
+static const char kFontTakaoPGothic[] = "TakaoPGothic";
+static const char kFontDroidSansFallback[] = "Droid Sans Fallback";
+static const char kFontWenQuanYiMicroHei[] = "WenQuanYi Micro Hei";
+static const char kFontNanumGothic[] = "NanumGothic";
+
+void
+gfxPlatformGtk::GetCommonFallbackFonts(uint32_t aCh, uint32_t aNextCh,
+                                       int32_t aRunScript,
+                                       nsTArray<const char*>& aFontList)
+{
+    aFontList.AppendElement(kFontDejaVuSerif);
+    aFontList.AppendElement(kFontFreeSerif);
+    aFontList.AppendElement(kFontDejaVuSans);
+    aFontList.AppendElement(kFontFreeSans);
+
+    // add fonts for CJK ranges
+    // xxx - this isn't really correct, should use the same CJK font ordering
+    // as the pref font code
+    if (aCh >= 0x3000 &&
+        ((aCh < 0xe000) ||
+         (aCh >= 0xf900 && aCh < 0xfff0) ||
+         ((aCh >> 16) == 2))) {
+        aFontList.AppendElement(kFontTakaoPGothic);
+        aFontList.AppendElement(kFontDroidSansFallback);
+        aFontList.AppendElement(kFontWenQuanYiMicroHei);
+        aFontList.AppendElement(kFontNanumGothic);
+    }
+}
+
+gfxPlatformFontList*
+gfxPlatformGtk::CreatePlatformFontList()
+{
+    gfxPlatformFontList* list = new gfxFcPlatformFontList();
+    if (NS_SUCCEEDED(list->InitFontList())) {
+        return list;
+    }
+    gfxPlatformFontList::Shutdown();
+    return nullptr;
+}
+
 nsresult
 gfxPlatformGtk::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
 {
+    if (sUseFcFontList) {
+        gfxPlatformFontList::PlatformFontList()->
+            GetStandardFamilyName(aFontName, aFamilyName);
+        return NS_OK;
+    }
+
     return sFontconfigUtils->GetStandardFamilyName(aFontName, aFamilyName);
 }
 
 gfxFontGroup *
 gfxPlatformGtk::CreateFontGroup(const FontFamilyList& aFontFamilyList,
                                 const gfxFontStyle *aStyle,
                                 gfxUserFontSet *aUserFontSet)
 {
+    if (sUseFcFontList) {
+        return new gfxFontGroup(aFontFamilyList, aStyle, aUserFontSet);
+    }
+
     return new gfxPangoFontGroup(aFontFamilyList, aStyle, aUserFontSet);
 }
 
 gfxFontEntry*
 gfxPlatformGtk::LookupLocalFont(const nsAString& aFontName,
                                 uint16_t aWeight,
                                 int16_t aStretch,
                                 bool aItalic)
 {
+    if (sUseFcFontList) {
+        gfxPlatformFontList* pfl = gfxPlatformFontList::PlatformFontList();
+        return pfl->LookupLocalFont(aFontName, aWeight, aStretch, aItalic);
+    }
+
     return gfxPangoFontGroup::NewFontEntry(aFontName, aWeight,
                                            aStretch, aItalic);
 }
 
 gfxFontEntry* 
 gfxPlatformGtk::MakePlatformFont(const nsAString& aFontName,
                                  uint16_t aWeight,
                                  int16_t aStretch,
                                  bool aItalic,
                                  const uint8_t* aFontData,
                                  uint32_t aLength)
 {
+    if (sUseFcFontList) {
+        gfxPlatformFontList* pfl = gfxPlatformFontList::PlatformFontList();
+        return pfl->MakePlatformFont(aFontName, aWeight, aStretch, aItalic,
+                                     aFontData, aLength);
+    }
+
     // passing ownership of the font data to the new font entry
     return gfxPangoFontGroup::NewFontEntry(aFontName, aWeight,
                                            aStretch, aItalic,
                                            aFontData, aLength);
 }
 
 bool
 gfxPlatformGtk::IsFontFormatSupported(nsIURI *aFontURI, uint32_t aFormatFlags)
--- a/gfx/thebes/gfxPlatformGtk.h
+++ b/gfx/thebes/gfxPlatformGtk.h
@@ -36,16 +36,23 @@ public:
       GetScaledFontForFont(mozilla::gfx::DrawTarget* aTarget, gfxFont *aFont) override;
 
     virtual nsresult GetFontList(nsIAtom *aLangGroup,
                                  const nsACString& aGenericFamily,
                                  nsTArray<nsString>& aListOfFonts) override;
 
     virtual nsresult UpdateFontList() override;
 
+    virtual void
+    GetCommonFallbackFonts(uint32_t aCh, uint32_t aNextCh,
+                           int32_t aRunScript,
+                           nsTArray<const char*>& aFontList) override;
+
+    virtual gfxPlatformFontList* CreatePlatformFontList() override;
+
     virtual nsresult GetStandardFamilyName(const nsAString& aFontName,
                                            nsAString& aFamilyName) override;
 
     virtual gfxFontGroup* CreateFontGroup(const mozilla::FontFamilyList& aFontFamilyList,
                                           const gfxFontStyle *aStyle,
                                           gfxUserFontSet *aUserFontSet) override;
 
     /**
@@ -96,16 +103,18 @@ public:
             return false;
 
         return sUseXRender;
 #else
         return false;
 #endif
     }
 
+    static bool UseFcFontList() { return sUseFcFontList; }
+
     bool UseImageOffscreenSurfaces() {
         // We want to turn on image offscreen surfaces ONLY for GTK3 builds
         // since GTK2 theme rendering still requires xlib surfaces per se.
 #if (MOZ_WIDGET_GTK == 3)
         return gfxPrefs::UseImageOffscreenSurfaces();
 #else
         return false;
 #endif
@@ -124,11 +133,15 @@ protected:
 
 private:
     virtual void GetPlatformCMSOutputProfile(void *&mem,
                                              size_t &size) override;
 
 #ifdef MOZ_X11
     static bool sUseXRender;
 #endif
+
+    // xxx - this will be removed once the new fontconfig platform font list
+    // replaces gfxPangoFontGroup
+    static bool sUseFcFontList;
 };
 
 #endif /* GFX_PLATFORM_GTK_H */
--- a/gfx/thebes/gfxTextRun.cpp
+++ b/gfx/thebes/gfxTextRun.cpp
@@ -18,16 +18,20 @@
 #include "gfxFontMissingGlyphs.h"
 #include "gfxScriptItemizer.h"
 #include "nsUnicodeProperties.h"
 #include "nsUnicodeRange.h"
 #include "nsStyleConsts.h"
 #include "mozilla/Likely.h"
 #include "gfx2DGlue.h"
 
+#if defined(MOZ_WIDGET_GTK)
+#include "gfxPlatformGtk.h" // xxx - for UseFcFontList
+#endif
+
 #include "cairo.h"
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 using namespace mozilla::unicode;
 using mozilla::services::GetObserverService;
 
 static const char16_t kEllipsisChar[] = { 0x2026, 0x0 };
@@ -1531,16 +1535,17 @@ gfxFontGroup::gfxFontGroup(const FontFam
     : mFamilyList(aFontFamilyList)
     , mStyle(*aStyle)
     , mUnderlineOffset(UNDERLINE_OFFSET_NOT_SET)
     , mHyphenWidth(-1)
     , mUserFontSet(aUserFontSet)
     , mTextPerf(nullptr)
     , mPageLang(gfxPlatform::GetFontPrefLangFor(aStyle->language))
     , mSkipDrawing(false)
+    , mSkipUpdateUserFonts(false)
 {
     // We don't use SetUserFontSet() here, as we want to unconditionally call
     // BuildFontList() rather than only do UpdateUserFonts() if it changed.
     mCurrGeneration = GetGeneration();
     BuildFontList();
 }
 
 gfxFontGroup::~gfxFontGroup()
@@ -1677,20 +1682,27 @@ void gfxFontGroup::EnumerateFontList(nsI
                          aLanguage,
                          aClosure);
     }
 }
 
 void
 gfxFontGroup::BuildFontList()
 {
-// gfxPangoFontGroup behaves differently, so this method is a no-op on that platform
-#if defined(XP_MACOSX) || defined(XP_WIN) || defined(ANDROID)
-    EnumerateFontList(mStyle.language);
+    bool enumerateFonts = true;
+
+#if defined(MOZ_WIDGET_GTK)
+    // xxx - eliminate this once gfxPangoFontGroup is no longer needed
+    enumerateFonts = gfxPlatformGtk::UseFcFontList();
+#elif defined(MOZ_WIDGET_QT)
+    enumerateFonts = false;
 #endif
+    if (enumerateFonts) {
+        EnumerateFontList(mStyle.language);
+    }
 }
 
 void
 gfxFontGroup::FindPlatformFont(const nsAString& aName,
                                bool aUseFontSet,
                                void *aClosure)
 {
     bool needsBold;
@@ -1719,17 +1731,17 @@ gfxFontGroup::FindPlatformFont(const nsA
                 }
             }
         }
     }
 
     // Not known in the user font set ==> check system fonts
     if (!family) {
         gfxPlatformFontList *fontList = gfxPlatformFontList::PlatformFontList();
-        family = fontList->FindFamily(aName, mStyle.systemFont);
+        family = fontList->FindFamily(aName, mStyle.language, mStyle.systemFont);
         if (family) {
             fe = family->FindFontForStyle(mStyle, needsBold);
         }
     }
 
     // add to the font group, unless it's already there
     if (fe && !HasFont(fe)) {
         mFonts.AppendElement(FamilyFace(family, fe, needsBold));
@@ -2340,23 +2352,21 @@ gfxFontGroup::InitScriptRun(gfxContext *
                             uint32_t aLength, // length of the script run
                             int32_t aRunScript,
                             gfxMissingFontRecorder *aMFR)
 {
     NS_ASSERTION(aLength > 0, "don't call InitScriptRun for a 0-length run");
     NS_ASSERTION(aTextRun->GetShapingState() != gfxTextRun::eShapingState_Aborted,
                  "don't call InitScriptRun with aborted shaping state");
 
-#if defined(XP_MACOSX) || defined(XP_WIN) || defined(ANDROID)
-    // non-linux platforms build the fontlist lazily and include userfonts
-    // so need to confirm the load state of userfonts in the list
-    if (mUserFontSet && mCurrGeneration != mUserFontSet->GetGeneration()) {
+    // confirm the load state of userfonts in the list
+    if (!mSkipUpdateUserFonts && mUserFontSet &&
+        mCurrGeneration != mUserFontSet->GetGeneration()) {
         UpdateUserFonts();
     }
-#endif
 
     gfxFont *mainFont = GetFirstValidFont();
 
     uint32_t runStart = 0;
     nsAutoTArray<gfxTextRange,3> fontRanges;
     ComputeRanges(fontRanges, aString, aLength, aRunScript,
                   aTextRun->GetFlags() & gfxTextRunFactory::TEXT_ORIENT_MASK);
     uint32_t numRanges = fontRanges.Length();
@@ -2602,20 +2612,16 @@ gfxFontGroup::GetEllipsisTextRun(int32_t
 }
 
 already_AddRefed<gfxFont>
 gfxFontGroup::FindNonItalicFaceForChar(gfxFontFamily* aFamily, uint32_t aCh)
 {
     NS_ASSERTION(mStyle.style != NS_FONT_STYLE_NORMAL,
                  "should only be called in the italic/oblique case");
 
-    if (!aFamily->TestCharacterMap(aCh)) {
-        return nullptr;
-    }
-
     gfxFontStyle regularStyle = mStyle;
     regularStyle.style = NS_FONT_STYLE_NORMAL;
     bool needsBold;
     gfxFontEntry *fe = aFamily->FindFontForStyle(regularStyle, needsBold);
     NS_ASSERTION(!fe->mIsUserFontContainer,
                  "should only be searching platform fonts");
     if (!fe->HasCharacter(aCh)) {
         return nullptr;
@@ -2792,19 +2798,21 @@ gfxFontGroup::FindFontForChar(uint32_t a
             if (font) {
                 *aMatchType = gfxTextRange::kFontGroup;
                 return font.forget();
             }
         }
 
         // If italic, test the regular face to see if it supports the character.
         // Only do this for platform fonts, not userfonts.
+        fe = ff.FontEntry();
         if (mStyle.style != NS_FONT_STYLE_NORMAL &&
-            !ff.FontEntry()->IsUserFont()) {
-            font = FindNonItalicFaceForChar(mFonts[i].Family(), aCh);
+            !fe->mIsUserFontContainer &&
+            !fe->IsUserFont()) {
+            font = FindNonItalicFaceForChar(ff.Family(), aCh);
             if (font) {
                 *aMatchType = gfxTextRange::kFontGroup;
                 return font.forget();
             }
         }
     }
 
     if (fontListLength == 0) {
@@ -3077,17 +3085,20 @@ struct PrefFontCallbackData {
     {}
 
     nsTArray<nsRefPtr<gfxFontFamily> >& mPrefFamilies;
 
     static bool AddFontFamilyEntry(eFontPrefLang aLang, const nsAString& aName, void *aClosure)
     {
         PrefFontCallbackData *prefFontData = static_cast<PrefFontCallbackData*>(aClosure);
 
-        gfxFontFamily *family = gfxPlatformFontList::PlatformFontList()->FindFamily(aName);
+        // map pref lang to langGroup for language-sensitive lookups
+        nsIAtom* lang = gfxPlatform::GetLangGroupForPrefLang(aLang);
+        gfxFontFamily *family =
+            gfxPlatformFontList::PlatformFontList()->FindFamily(aName, lang);
         if (family) {
             prefFontData->mPrefFamilies.AppendElement(family);
         }
         return true;
     }
 };
 
 already_AddRefed<gfxFont>
--- a/gfx/thebes/gfxTextRun.h
+++ b/gfx/thebes/gfxTextRun.h
@@ -1051,16 +1051,19 @@ protected:
     eFontPrefLang           mLastPrefLang;       // lang group for last pref font
     eFontPrefLang           mPageLang;
     bool                    mLastPrefFirstFont;  // is this the first font in the list of pref fonts for this lang group?
 
     bool                    mSkipDrawing; // hide text while waiting for a font
                                           // download to complete (or fallback
                                           // timer to fire)
 
+    // xxx - gfxPangoFontGroup skips UpdateUserFonts
+    bool                    mSkipUpdateUserFonts;
+
     /**
      * Textrun creation short-cuts for special cases where we don't need to
      * call a font shaper to generate glyphs.
      */
     gfxTextRun *MakeEmptyTextRun(const Parameters *aParams, uint32_t aFlags);
     gfxTextRun *MakeSpaceTextRun(const Parameters *aParams, uint32_t aFlags);
     gfxTextRun *MakeBlankTextRun(uint32_t aLength,
                                  const Parameters *aParams, uint32_t aFlags);
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -1885,18 +1885,18 @@ gfxWindowsPlatform::InitD3D11Devices()
   bool useWARP = false;
 
   nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
   if (gfxInfo) {
     int32_t status;
     if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS, &status))) {
       if (status != nsIGfxInfo::FEATURE_STATUS_OK) {
 
-        // It seems like nvdxgiwrapper makes a mess of WARP. See bug 1154703 for more.
-        if (gfxPrefs::LayersD3D11DisableWARP() || GetModuleHandleA("nvdxgiwrapper.dll")) {
+        // It seems like nvdxgiwrap makes a mess of WARP. See bug 1154703 for more.
+        if (gfxPrefs::LayersD3D11DisableWARP() || GetModuleHandleA("nvdxgiwrap.dll")) {
           return;
         }
 
         useWARP = true;
       }
     }
   }
 
--- a/gfx/thebes/moz.build
+++ b/gfx/thebes/moz.build
@@ -106,16 +106,17 @@ elif CONFIG['MOZ_WIDGET_GTK']:
         'gfxGdkNativeRenderer.h',
         'gfxPangoFonts.h',
         'gfxPDFSurface.h',
         'gfxPlatformGtk.h',
         'gfxPSSurface.h',
     ]
 
     SOURCES += [
+        'gfxFcPlatformFontList.cpp',
         'gfxFontconfigUtils.cpp',
         'gfxFT2FontBase.cpp',
         'gfxFT2Utils.cpp',
         'gfxGdkNativeRenderer.cpp',
         'gfxPangoFonts.cpp',
         'gfxPDFSurface.cpp',
         'gfxPlatformGtk.cpp',
         'gfxPSSurface.cpp',
--- a/image/imgIContainer.idl
+++ b/image/imgIContainer.idl
@@ -111,17 +111,17 @@ native nsIntSizeByVal(nsIntSize);
 
 /**
  * imgIContainer is the interface that represents an image. It allows
  * access to frames as Thebes surfaces. It also allows drawing of images
  * onto Thebes contexts.
  *
  * Internally, imgIContainer also manages animation of images.
  */
-[scriptable, builtinclass, uuid(e3261ae7-4749-4cf6-bf06-59946233366f)]
+[scriptable, builtinclass, uuid(f5e1230a-3733-477f-b49b-fee8717a786b)]
 interface imgIContainer : nsISupports
 {
   /**
    * The width of the container rectangle.  In the case of any error,
    * zero is returned, and an exception will be thrown.
    */
   readonly attribute int32_t width;
 
@@ -265,18 +265,27 @@ interface imgIContainer : nsISupports
                                                      in uint32_t aFlags);
 
   /**
    * Whether this image is opaque (i.e., needs a background painted behind it).
    */
   [notxpcom] boolean isOpaque();
 
   /**
+   * @return true if getImageContainer() is expected to return a valid
+   *         ImageContainer when passed the given @Manager and @Flags
+   *         parameters.
+   */
+  [noscript, notxpcom] boolean isImageContainerAvailable(in LayerManager aManager,
+                                                         in uint32_t aFlags);
+  /**
    * Attempts to create an ImageContainer (and Image) containing the current
-   * frame. Only valid for RASTER type images.
+   * frame.
+   *
+   * Avoid calling this unless you're actually going to layerize this image.
    *
    * @param aManager The LayerManager which will be used to create the
    *                 ImageContainer.
    * @param aFlags Decoding / drawing flags (in other words, FLAG_* flags).
    *               Currently only FLAG_SYNC_DECODE and FLAG_SYNC_DECODE_IF_FAST
    *               are supported.
    * @return An ImageContainer for the current frame, or nullptr if one could
    *         not be created.
--- a/image/src/ClippedImage.cpp
+++ b/image/src/ClippedImage.cpp
@@ -263,30 +263,39 @@ ClippedImage::GetFrameInternal(const nsI
                                                    aSVGContext, frameToDraw,
                                                    aFlags);
   }
 
   MOZ_ASSERT(mCachedSurface, "Should have a cached surface now");
   return mCachedSurface->Surface();
 }
 
+NS_IMETHODIMP_(bool)
+ClippedImage::IsImageContainerAvailable(LayerManager* aManager, uint32_t aFlags)
+{
+  if (!ShouldClip()) {
+    return InnerImage()->IsImageContainerAvailable(aManager, aFlags);
+  }
+  return false;
+}
+
 NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
 ClippedImage::GetImageContainer(LayerManager* aManager, uint32_t aFlags)
 {
   // XXX(seth): We currently don't have a way of clipping the result of
   // GetImageContainer. We work around this by always returning null, but if it
   // ever turns out that ClippedImage is widely used on codepaths that can
   // actually benefit from GetImageContainer, it would be a good idea to fix
   // that method for performance reasons.
 
   if (!ShouldClip()) {
     return InnerImage()->GetImageContainer(aManager, aFlags);
   }
 
-  return (nullptr);
+  return nullptr;
 }
 
 static bool
 MustCreateSurface(gfxContext* aContext,
                   const nsIntSize& aSize,
                   const ImageRegion& aRegion,
                   const uint32_t aFlags)
 {
--- a/image/src/ClippedImage.h
+++ b/image/src/ClippedImage.h
@@ -32,16 +32,18 @@ public:
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_IMETHOD GetWidth(int32_t* aWidth) override;
   NS_IMETHOD GetHeight(int32_t* aHeight) override;
   NS_IMETHOD GetIntrinsicSize(nsSize* aSize) override;
   NS_IMETHOD GetIntrinsicRatio(nsSize* aRatio) override;
   NS_IMETHOD_(TemporaryRef<SourceSurface>)
     GetFrame(uint32_t aWhichFrame, uint32_t aFlags) override;
+  NS_IMETHOD_(bool) IsImageContainerAvailable(layers::LayerManager* aManager,
+                                              uint32_t aFlags) override;
   NS_IMETHOD_(already_AddRefed<layers::ImageContainer>)
     GetImageContainer(layers::LayerManager* aManager,
                       uint32_t aFlags) override;
   NS_IMETHOD_(DrawResult) Draw(gfxContext* aContext,
                                const nsIntSize& aSize,
                                const ImageRegion& aRegion,
                                uint32_t aWhichFrame,
                                GraphicsFilter aFilter,
--- a/image/src/DynamicImage.cpp
+++ b/image/src/DynamicImage.cpp
@@ -189,16 +189,22 @@ DynamicImage::GetFrame(uint32_t aWhichFr
 NS_IMETHODIMP_(bool)
 DynamicImage::IsOpaque()
 {
   // XXX(seth): For performance reasons it'd be better to return true here, but
   // I'm not sure how we can guarantee it for an arbitrary gfxDrawable.
   return false;
 }
 
+NS_IMETHODIMP_(bool)
+DynamicImage::IsImageContainerAvailable(LayerManager* aManager, uint32_t aFlags)
+{
+  return false;
+}
+
 NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
 DynamicImage::GetImageContainer(LayerManager* aManager, uint32_t aFlags)
 {
   return nullptr;
 }
 
 NS_IMETHODIMP_(DrawResult)
 DynamicImage::Draw(gfxContext* aContext,
--- a/image/src/FrozenImage.cpp
+++ b/image/src/FrozenImage.cpp
@@ -39,16 +39,22 @@ FrozenImage::GetAnimated(bool* aAnimated
 
 NS_IMETHODIMP_(TemporaryRef<SourceSurface>)
 FrozenImage::GetFrame(uint32_t aWhichFrame,
                       uint32_t aFlags)
 {
   return InnerImage()->GetFrame(FRAME_FIRST, aFlags);
 }
 
+NS_IMETHODIMP_(bool)
+FrozenImage::IsImageContainerAvailable(LayerManager* aManager, uint32_t aFlags)
+{
+  return false;
+}
+
 NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
 FrozenImage::GetImageContainer(layers::LayerManager* aManager, uint32_t aFlags)
 {
   // XXX(seth): GetImageContainer does not currently support anything but the
   // current frame. We work around this by always returning null, but if it ever
   // turns out that FrozenImage is widely used on codepaths that can actually
   // benefit from GetImageContainer, it would be a good idea to fix that method
   // for performance reasons.
--- a/image/src/FrozenImage.h
+++ b/image/src/FrozenImage.h
@@ -32,16 +32,18 @@ public:
   NS_DECL_ISUPPORTS_INHERITED
 
   virtual void IncrementAnimationConsumers() override;
   virtual void DecrementAnimationConsumers() override;
 
   NS_IMETHOD GetAnimated(bool* aAnimated) override;
   NS_IMETHOD_(TemporaryRef<SourceSurface>)
     GetFrame(uint32_t aWhichFrame, uint32_t aFlags) override;
+  NS_IMETHOD_(bool) IsImageContainerAvailable(layers::LayerManager* aManager,
+                                              uint32_t aFlags) override;
   NS_IMETHOD_(already_AddRefed<layers::ImageContainer>)
     GetImageContainer(layers::LayerManager* aManager,
                       uint32_t aFlags) override;
   NS_IMETHOD_(DrawResult) Draw(gfxContext* aContext,
                                const nsIntSize& aSize,
                                const ImageRegion& aRegion,
                                uint32_t aWhichFrame,
                                GraphicsFilter aFilter,
--- a/image/src/ImageWrapper.cpp
+++ b/image/src/ImageWrapper.cpp
@@ -175,16 +175,22 @@ ImageWrapper::GetFrame(uint32_t aWhichFr
 }
 
 NS_IMETHODIMP_(bool)
 ImageWrapper::IsOpaque()
 {
   return mInnerImage->IsOpaque();
 }
 
+NS_IMETHODIMP_(bool)
+ImageWrapper::IsImageContainerAvailable(LayerManager* aManager, uint32_t aFlags)
+{
+  return mInnerImage->IsImageContainerAvailable(aManager, aFlags);
+}
+
 NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
 ImageWrapper::GetImageContainer(LayerManager* aManager, uint32_t aFlags)
 {
   return mInnerImage->GetImageContainer(aManager, aFlags);
 }
 
 NS_IMETHODIMP_(DrawResult)
 ImageWrapper::Draw(gfxContext* aContext,
--- a/image/src/OrientedImage.cpp
+++ b/image/src/OrientedImage.cpp
@@ -117,16 +117,25 @@ OrientedImage::GetFrame(uint32_t aWhichF
   ctx->Multiply(OrientationMatrix(size));
   gfxUtils::DrawPixelSnapped(ctx, drawable, size,
                              ImageRegion::Create(size),
                              surfaceFormat, GraphicsFilter::FILTER_FAST);
 
   return target->Snapshot();
 }
 
+NS_IMETHODIMP_(bool)
+OrientedImage::IsImageContainerAvailable(LayerManager* aManager, uint32_t aFlags)
+{
+  if (mOrientation.IsIdentity()) {
+    return InnerImage()->IsImageContainerAvailable(aManager, aFlags);
+  }
+  return false;
+}
+
 NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
 OrientedImage::GetImageContainer(LayerManager* aManager, uint32_t aFlags)
 {
   // XXX(seth): We currently don't have a way of orienting the result of
   // GetImageContainer. We work around this by always returning null, but if it
   // ever turns out that OrientedImage is widely used on codepaths that can
   // actually benefit from GetImageContainer, it would be a good idea to fix
   // that method for performance reasons.
--- a/image/src/OrientedImage.h
+++ b/image/src/OrientedImage.h
@@ -29,16 +29,18 @@ public:
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_IMETHOD GetWidth(int32_t* aWidth) override;
   NS_IMETHOD GetHeight(int32_t* aHeight) override;
   NS_IMETHOD GetIntrinsicSize(nsSize* aSize) override;
   NS_IMETHOD GetIntrinsicRatio(nsSize* aRatio) override;
   NS_IMETHOD_(TemporaryRef<SourceSurface>)
     GetFrame(uint32_t aWhichFrame, uint32_t aFlags) override;
+  NS_IMETHOD_(bool) IsImageContainerAvailable(layers::LayerManager* aManager,
+                                              uint32_t aFlags) override;
   NS_IMETHOD_(already_AddRefed<layers::ImageContainer>)
     GetImageContainer(layers::LayerManager* aManager,
                       uint32_t aFlags) override;
   NS_IMETHOD_(DrawResult) Draw(gfxContext* aContext,
                                const nsIntSize& aSize,
                                const ImageRegion& aRegion,
                                uint32_t aWhichFrame,
                                GraphicsFilter aFilter,
--- a/image/src/RasterImage.cpp
+++ b/image/src/RasterImage.cpp
@@ -800,16 +800,28 @@ RasterImage::GetCurrentImage(ImageContai
     aContainer->CreateImage(ImageFormat::CAIRO_SURFACE);
   MOZ_ASSERT(image);
 
   static_cast<CairoImage*>(image.get())->SetData(cairoData);
 
   return MakePair(result.first(), Move(image));
 }
 
+NS_IMETHODIMP_(bool)
+RasterImage::IsImageContainerAvailable(LayerManager* aManager, uint32_t aFlags)
+{
+  int32_t maxTextureSize = aManager->GetMaxTextureSize();
+  if (!mHasSize ||
+      mSize.width > maxTextureSize ||
+      mSize.height > maxTextureSize) {
+    return false;
+  }
+
+  return true;
+}
 
 NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
 RasterImage::GetImageContainer(LayerManager* aManager, uint32_t aFlags)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aManager);
   MOZ_ASSERT((aFlags & ~(FLAG_SYNC_DECODE |
                          FLAG_SYNC_DECODE_IF_FAST |
--- a/image/src/VectorImage.cpp
+++ b/image/src/VectorImage.cpp
@@ -707,16 +707,22 @@ VectorImage::GetFrame(uint32_t aWhichFra
   auto result = Draw(context, imageIntSize,
                      ImageRegion::Create(imageIntSize),
                      aWhichFrame, GraphicsFilter::FILTER_NEAREST,
                      Nothing(), aFlags);
 
   return result == DrawResult::SUCCESS ? dt->Snapshot() : nullptr;
 }
 
+NS_IMETHODIMP_(bool)
+VectorImage::IsImageContainerAvailable(LayerManager* aManager, uint32_t aFlags)
+{
+  return false;
+}
+
 //******************************************************************************
 /* [noscript] ImageContainer getImageContainer(); */
 NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
 VectorImage::GetImageContainer(LayerManager* aManager, uint32_t aFlags)
 {
   return nullptr;
 }
 
--- a/js/ipc/WrapperAnswer.cpp
+++ b/js/ipc/WrapperAnswer.cpp
@@ -215,69 +215,64 @@ WrapperAnswer::RecvDelete(const ObjectId
 
     ObjectOpResult success;
     if (!JS_DeletePropertyById(cx, obj, id, success))
         return fail(jsapi, rs);
     return ok(rs, success);
 }
 
 bool
-WrapperAnswer::RecvHas(const ObjectId& objId, const JSIDVariant& idVar, ReturnStatus* rs, bool* bp)
+WrapperAnswer::RecvHas(const ObjectId& objId, const JSIDVariant& idVar, ReturnStatus* rs,
+                       bool* foundp)
 {
     AutoJSAPI jsapi;
     if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
         return false;
     jsapi.TakeOwnershipOfErrorReporting();
     JSContext* cx = jsapi.cx();
-    *bp = false;
+    *foundp = false;
 
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj)
         return fail(jsapi, rs);
 
     LOG("%s.has(%s)", ReceiverObj(objId), Identifier(idVar));
 
     RootedId id(cx);
     if (!fromJSIDVariant(cx, idVar, &id))
         return fail(jsapi, rs);
 
-    bool found;
-    if (!JS_HasPropertyById(cx, obj, id, &found))
+    if (!JS_HasPropertyById(cx, obj, id, foundp))
         return fail(jsapi, rs);
-    *bp = !!found;
-
     return ok(rs);
 }
 
 bool
 WrapperAnswer::RecvHasOwn(const ObjectId& objId, const JSIDVariant& idVar, ReturnStatus* rs,
-                          bool* bp)
+                          bool* foundp)
 {
     AutoJSAPI jsapi;
     if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
         return false;
     jsapi.TakeOwnershipOfErrorReporting();
     JSContext* cx = jsapi.cx();
-    *bp = false;
+    *foundp = false;
 
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj)
         return fail(jsapi, rs);
 
     LOG("%s.hasOwn(%s)", ReceiverObj(objId), Identifier(idVar));
 
     RootedId id(cx);
     if (!fromJSIDVariant(cx, idVar, &id))
         return fail(jsapi, rs);
 
-    Rooted<JSPropertyDescriptor> desc(cx);
-    if (!JS_GetPropertyDescriptorById(cx, obj, id, &desc))
+    if (!JS_HasOwnPropertyById(cx, obj, id, foundp))
         return fail(jsapi, rs);
-    *bp = (desc.object() == obj);
-
     return ok(rs);
 }
 
 bool
 WrapperAnswer::RecvGet(const ObjectId& objId, const ObjectVariant& receiverVar,
                        const JSIDVariant& idVar, ReturnStatus* rs, JSVariant* result)
 {
     // We may run scripted getters.
--- a/js/ipc/WrapperAnswer.h
+++ b/js/ipc/WrapperAnswer.h
@@ -31,19 +31,19 @@ class WrapperAnswer : public virtual Jav
                                       const JSIDVariant& id,
                                       ReturnStatus* rs,
                                       PPropertyDescriptor* out);
     bool RecvDefineProperty(const ObjectId& objId, const JSIDVariant& id,
                             const PPropertyDescriptor& flags, ReturnStatus* rs);
     bool RecvDelete(const ObjectId& objId, const JSIDVariant& id, ReturnStatus* rs);
 
     bool RecvHas(const ObjectId& objId, const JSIDVariant& id,
-                 ReturnStatus* rs, bool* bp);
+                 ReturnStatus* rs, bool* foundp);
     bool RecvHasOwn(const ObjectId& objId, const JSIDVariant& id,
-                    ReturnStatus* rs, bool* bp);
+                    ReturnStatus* rs, bool* foundp);
     bool RecvGet(const ObjectId& objId, const ObjectVariant& receiverVar,
                  const JSIDVariant& id,
                  ReturnStatus* rs, JSVariant* result);
     bool RecvSet(const ObjectId& objId, const JSIDVariant& id, const JSVariant& value,
                  const JSVariant& receiverVar, ReturnStatus* rs);
 
     bool RecvIsExtensible(const ObjectId& objId, ReturnStatus* rs,
                           bool* result);
--- a/js/src/builtin/AtomicsObject.cpp
+++ b/js/src/builtin/AtomicsObject.cpp
@@ -1027,17 +1027,23 @@ js::FutexRuntime::destroyInstance()
 {
     if (cond_)
         PR_DestroyCondVar(cond_);
 }
 
 bool
 js::FutexRuntime::isWaiting()
 {
-    return state_ == Waiting || state_ == WaitingInterrupted;
+    // When a worker is awoken for an interrupt it goes into state
+    // WaitingNotifiedForInterrupt for a short time before it actually
+    // wakes up and goes into WaitingInterrupted.  In those states the
+    // worker is still waiting, and if an explicit wake arrives the
+    // worker transitions to Woken.  See further comments in
+    // FutexRuntime::wait().
+    return state_ == Waiting || state_ == WaitingInterrupted || state_ == WaitingNotifiedForInterrupt;
 }
 
 bool
 js::FutexRuntime::wait(JSContext* cx, double timeout_ms, AtomicsObject::FutexWaitResult* result)
 {
     MOZ_ASSERT(&cx->runtime()->fx == this);
     MOZ_ASSERT(lockHolder_ == PR_GetCurrentThread());
     MOZ_ASSERT(state_ == Idle || state_ == WaitingInterrupted);
@@ -1097,27 +1103,27 @@ js::FutexRuntime::wait(JSContext* cx, do
                 }
             }
             break;
 
           case FutexRuntime::Woken:
             *result = AtomicsObject::FutexOK;
             goto finished;
 
-          case FutexRuntime::WokenForJSInterrupt:
+          case FutexRuntime::WaitingNotifiedForInterrupt:
             // The interrupt handler may reenter the engine.  In that case
             // there are two complications:
             //
             // - The waiting thread is not actually waiting on the
             //   condition variable so we have to record that it
             //   should be woken when the interrupt handler returns.
             //   To that end, we flag the thread as interrupted around
             //   the interrupt and check state_ when the interrupt
             //   handler returns.  A futexWake() call that reaches the
-            //   runtime during the interrupt sets state_ to woken.
+            //   runtime during the interrupt sets state_ to Woken.
             //
             // - It is in principle possible for futexWait() to be
             //   reentered on the same thread/runtime and waiting on the
             //   same location and to yet again be interrupted and enter
             //   the interrupt handler.  In this case, it is important
             //   that when another agent wakes waiters, all waiters using
             //   the same runtime on the same location are woken in LIFO
             //   order; FIFO may be the required order, but FIFO would
@@ -1155,26 +1161,28 @@ finished:
 }
 
 void
 js::FutexRuntime::wake(WakeReason reason)
 {
     MOZ_ASSERT(lockHolder_ == PR_GetCurrentThread());
     MOZ_ASSERT(isWaiting());
 
-    if (state_ == WaitingInterrupted && reason == WakeExplicit) {
+    if ((state_ == WaitingInterrupted || state_ == WaitingNotifiedForInterrupt) && reason == WakeExplicit) {
         state_ = Woken;
         return;
     }
     switch (reason) {
       case WakeExplicit:
         state_ = Woken;
         break;
       case WakeForJSInterrupt:
-        state_ = WokenForJSInterrupt;
+        if (state_ == WaitingNotifiedForInterrupt)
+            return;
+        state_ = WaitingNotifiedForInterrupt;
         break;
       default:
         MOZ_CRASH();
     }
     PR_NotifyCondVar(cond_);
 }
 
 const JSFunctionSpec AtomicsMethods[] = {
--- a/js/src/builtin/AtomicsObject.h
+++ b/js/src/builtin/AtomicsObject.h
@@ -92,29 +92,32 @@ public:
     // If the thread is not waiting then this method does nothing.
     //
     // If the thread is waiting in a call to futexWait() and the
     // reason is WakeExplicit then the futexWait() call will return
     // with Woken.
     //
     // If the thread is waiting in a call to futexWait() and the
     // reason is WakeForJSInterrupt then the futexWait() will return
-    // with WokenForJSInterrupt; in the latter case the caller of
-    // futexWait() must handle the interrupt.
+    // with WaitingNotifiedForInterrupt; in the latter case the caller
+    // of futexWait() must handle the interrupt.
     void wake(WakeReason reason);
 
     bool isWaiting();
 
   private:
     enum FutexState {
-        Idle,                   // We are not waiting or woken
-        Waiting,                // We are waiting, nothing has happened yet
-        WaitingInterrupted,     // We are waiting, but have been interrupted
-        Woken,                  // Woken by a script call to futexWake
-        WokenForJSInterrupt     // Woken by an interrupt handler
+        Idle,                        // We are not waiting or woken
+        Waiting,                     // We are waiting, nothing has happened yet
+        WaitingNotifiedForInterrupt, // We are waiting, but have been interrupted,
+                                     //   and have not yet started running the
+                                     //   interrupt handler
+        WaitingInterrupted,          // We are waiting, but have been interrupted
+                                     //   and are running the interrupt handler
+        Woken                        // Woken by a script call to futexWake
     };
 
     // Condition variable that this runtime will wait on.
     PRCondVar* cond_;
 
     // Current futex state for this runtime.  When not in a wait this
     // is Idle; when in a wait it is Waiting or the reason the futex
     // is about to wake up.
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -418,17 +418,17 @@ IsLazyFunction(JSContext* cx, unsigned a
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     if (args.length() != 1) {
         JS_ReportError(cx, "The function takes exactly one argument.");
         return false;
     }
     if (!args[0].isObject() || !args[0].toObject().is<JSFunction>()) {
         JS_ReportError(cx, "The first argument should be a function.");
-        return true;
+        return false;
     }
     args.rval().setBoolean(args[0].toObject().as<JSFunction>().isInterpretedLazy());
     return true;
 }
 
 static bool
 IsRelazifiableFunction(JSContext* cx, unsigned argc, Value* vp)
 {
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -379,16 +379,19 @@ case "$target" in
             MSVC_CXX_RUNTIME_DLL=msvcp140.dll
             MSVC_APPCRT_DLL=appcrt140.dll
             MSVC_DESKTOPCRT_DLL=desktopcrt140.dll
 
             # -Wv:18 disables all warnings introduced after VS2013
             # See http://blogs.msdn.com/b/vcblog/archive/2014/11/12/improvements-to-warnings-in-the-c-compiler.aspx
             CFLAGS="$CFLAGS -Wv:18"
             CXXFLAGS="$CXXFLAGS -Wv:18"
+
+            # -Zc:sizedDealloc- disables C++14 global sized deallocation (see bug 1160146)
+            CXXFLAGS="$CXXFLAGS -Zc:sizedDealloc-"
         else
             AC_MSG_ERROR([This version ($CC_VERSION) of the MSVC compiler is unsupported. See https://developer.mozilla.org/en/Windows_Build_Prerequisites.])
         fi
         AC_SUBST(MSVC_C_RUNTIME_DLL)
         AC_SUBST(MSVC_CXX_RUNTIME_DLL)
         AC_SUBST(MSVC_APPCRT_DLL)
         AC_SUBST(MSVC_DESKTOPCRT_DLL)
 
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/bug1160182.js
@@ -0,0 +1,11 @@
+var g = newGlobal();
+g.eval("(" + function() {
+    var o = {get x() {}};
+    this.method = Object.getOwnPropertyDescriptor(o, "x").get;
+    assertEq(isLazyFunction(method), true);
+} + ")()");
+var dbg = new Debugger();
+var gw = dbg.addDebuggee(g);
+var scripts = dbg.findScripts();
+var methodv = gw.makeDebuggeeValue(g.method);
+assertEq(scripts.indexOf(methodv.script) != -1, true);
--- a/js/src/jit/arm/Simulator-arm.cpp
+++ b/js/src/jit/arm/Simulator-arm.cpp
@@ -952,18 +952,19 @@ GetCachePageLocked(Simulator::ICacheMap&
 {
     MOZ_ASSERT(Simulator::ICacheCheckingEnabled);
 
     Simulator::ICacheMap::AddPtr p = i_cache.lookupForAdd(page);
     if (p)
         return p->value();
 
     CachePage* new_page = js_new<CachePage>();
-    if (!i_cache.add(p, page, new_page))
-        return nullptr;
+    if (!new_page || !i_cache.add(p, page, new_page))
+        CrashAtUnhandlableOOM("Simulator CachePage");
+
     return new_page;
 }
 
 // Flush from start up to and not including start + size.
 static void
 FlushOnePageLocked(Simulator::ICacheMap& i_cache, intptr_t start, int size)
 {
     MOZ_ASSERT(size <= CachePage::kPageSize);
@@ -1181,21 +1182,18 @@ class Redirection
         for (; current != nullptr; current = current->next_) {
             if (current->nativeFunction_ == nativeFunction) {
                 MOZ_ASSERT(current->type() == type);
                 return current;
             }
         }
 
         Redirection* redir = (Redirection*)js_malloc(sizeof(Redirection));
-        if (!redir) {
-            MOZ_ReportAssertionFailure("[unhandlable oom] Simulator redirection",
-                                       __FILE__, __LINE__);
-            MOZ_CRASH();
-        }
+        if (!redir)
+            CrashAtUnhandlableOOM("Simulator redirection");
         new(redir) Redirection(nativeFunction, type, sim);
         return redir;
     }
 
     static Redirection* FromSwiInstruction(SimInstruction* swiInstruction) {
         uint8_t* addrOfSwi = reinterpret_cast<uint8_t*>(swiInstruction);
         uint8_t* addrOfRedirection = addrOfSwi - offsetof(Redirection, swiInstruction_);
         return reinterpret_cast<Redirection*>(addrOfRedirection);
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -2813,16 +2813,36 @@ JS_GetOwnUCPropertyDescriptor(JSContext*
     JSAtom* atom = AtomizeChars(cx, name, js_strlen(name));
     if (!atom)
         return false;
     RootedId id(cx, AtomToId(atom));
     return JS_GetOwnPropertyDescriptorById(cx, obj, id, desc);
 }
 
 JS_PUBLIC_API(bool)
+JS_HasOwnPropertyById(JSContext* cx, HandleObject obj, HandleId id, bool* foundp)
+{
+    AssertHeapIsIdle(cx);
+    CHECK_REQUEST(cx);
+    assertSameCompartment(cx, obj, id);
+
+    return HasOwnProperty(cx, obj, id, foundp);
+}
+
+JS_PUBLIC_API(bool)
+JS_HasOwnProperty(JSContext* cx, HandleObject obj, const char* name, bool* foundp)
+{
+    JSAtom* atom = Atomize(cx, name, strlen(name));
+    if (!atom)
+        return false;
+    RootedId id(cx, AtomToId(atom));
+    return JS_HasOwnPropertyById(cx, obj, id, foundp);
+}
+
+JS_PUBLIC_API(bool)
 JS_GetPropertyDescriptorById(JSContext* cx, HandleObject obj, HandleId id,
                              MutableHandle<JSPropertyDescriptor> desc)
 {
     return GetPropertyDescriptor(cx, obj, id, desc);
 }
 
 JS_PUBLIC_API(bool)
 JS_GetPropertyDescriptor(JSContext* cx, HandleObject obj, const char* name,
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -2888,16 +2888,22 @@ JS_GetOwnPropertyDescriptorById(JSContex
 extern JS_PUBLIC_API(bool)
 JS_GetOwnPropertyDescriptor(JSContext* cx, JS::HandleObject obj, const char* name,
                             JS::MutableHandle<JSPropertyDescriptor> desc);
 
 extern JS_PUBLIC_API(bool)
 JS_GetOwnUCPropertyDescriptor(JSContext* cx, JS::HandleObject obj, const char16_t* name,
                               JS::MutableHandle<JSPropertyDescriptor> desc);
 
+extern JS_PUBLIC_API(bool)
+JS_HasOwnPropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* foundp);
+
+extern JS_PUBLIC_API(bool)
+JS_HasOwnProperty(JSContext* cx, JS::HandleObject obj, const char* name, bool* foundp);
+
 /*
  * Like JS_GetOwnPropertyDescriptorById but will return a property on
  * an object on the prototype chain (returned in desc->obj). If desc->obj is null,
  * then this property was not found on the prototype chain.
  */
 extern JS_PUBLIC_API(bool)
 JS_GetPropertyDescriptorById(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
                              JS::MutableHandle<JSPropertyDescriptor> desc);
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -744,35 +744,29 @@ AddInnerLazyFunctionsFromScript(JSScript
             if (!lazyFunctions.append(obj))
                 return false;
         }
     }
     return true;
 }
 
 static bool
-CreateLazyScriptsForCompartment(JSContext* cx)
+AddLazyFunctionsForCompartment(JSContext* cx, AutoObjectVector& lazyFunctions, AllocKind kind)
 {
-    AutoObjectVector lazyFunctions(cx);
-
     // Find all live root lazy functions in the compartment: those which have a
     // source object, indicating that they have a parent, and which do not have
     // an uncompiled enclosing script. The last condition is so that we don't
     // compile lazy scripts whose enclosing scripts failed to compile,
     // indicating that the lazy script did not escape the script.
     //
     // Some LazyScripts have a non-null |JSScript* script| pointer. We still
     // want to delazify in that case: this pointer is weak so the JSScript
     // could be destroyed at the next GC.
-    //
-    // Note that while we ideally iterate over LazyScripts, LazyScripts do not
-    // currently stand in 1-1 relation with JSScripts; JSFunctions with the
-    // same LazyScript may create different JSScripts due to relazification of
-    // clones. See bug 1105306.
-    for (gc::ZoneCellIter i(cx->zone(), AllocKind::FUNCTION); !i.done(); i.next()) {
+
+    for (gc::ZoneCellIter i(cx->zone(), kind); !i.done(); i.next()) {
         JSFunction* fun = &i.get<JSObject>()->as<JSFunction>();
 
         // Sweeping is incremental; take care to not delazify functions that
         // are about to be finalized. GC things referenced by objects that are
         // about to be finalized (e.g., in slots) may already be freed.
         if (gc::IsAboutToBeFinalizedUnbarriered(&fun) ||
             fun->compartment() != cx->compartment())
         {
@@ -783,16 +777,32 @@ CreateLazyScriptsForCompartment(JSContex
             LazyScript* lazy = fun->lazyScriptOrNull();
             if (lazy && lazy->sourceObject() && !lazy->hasUncompiledEnclosingScript()) {
                 if (!lazyFunctions.append(fun))
                     return false;
             }
         }
     }
 
+    return true;
+}
+
+static bool
+CreateLazyScriptsForCompartment(JSContext* cx)
+{
+    AutoObjectVector lazyFunctions(cx);
+
+    if (!AddLazyFunctionsForCompartment(cx, lazyFunctions, AllocKind::FUNCTION))
+        return false;
+
+    // Methods, for instance {get method() {}}, are extended functions that can
+    // be relazified, so we need to handle those as well.
+    if (!AddLazyFunctionsForCompartment(cx, lazyFunctions, AllocKind::FUNCTION_EXTENDED))
+        return false;
+
     // Create scripts for each lazy function, updating the list of functions to
     // process with any newly exposed inner functions in created scripts.
     // A function cannot be delazified until its outer script exists.
     for (size_t i = 0; i < lazyFunctions.length(); i++) {
         JSFunction* fun = &lazyFunctions[i]->as<JSFunction>();
 
         // lazyFunctions may have been populated with multiple functions for
         // a lazy script.
--- a/layout/base/AccessibleCaretLogger.cpp
+++ b/layout/base/AccessibleCaretLogger.cpp
@@ -3,25 +3,21 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "AccessibleCaretLogger.h"
 
 namespace mozilla {
 
-#ifdef PR_LOGGING
-
 PRLogModuleInfo*
 GetAccessibleCaretLog()
 {
   static PRLogModuleInfo* log = nullptr;
 
   if (!log) {
     log = PR_NewLogModule("AccessibleCaret");
   }
 
   return log;
 }
 
-#endif // PR_LOGGING
-
 } // namespace mozilla
--- a/layout/base/AccessibleCaretLogger.h
+++ b/layout/base/AccessibleCaretLogger.h
@@ -5,36 +5,23 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef AccessibleCaretLog_h
 #define AccessibleCaretLog_h
 
 #include "prlog.h"
 
 namespace mozilla {
-#ifdef PR_LOGGING
 
 PRLogModuleInfo* GetAccessibleCaretLog();
 
 #ifndef AC_LOG_BASE
 #define AC_LOG_BASE(...) PR_LOG(GetAccessibleCaretLog(), PR_LOG_DEBUG, (__VA_ARGS__));
 #endif
 
 #ifndef AC_LOGV_BASE
 #define AC_LOGV_BASE(...)                                                      \
   PR_LOG(GetAccessibleCaretLog(), PR_LOG_DEBUG + 1, (__VA_ARGS__));
 #endif
 
-#else
-
-#ifndef AC_LOGV_BASE
-#define AC_LOGV_BASE(...)
-#endif
-
-#ifndef AC_LOGV_BASE
-#define AC_LOGV_BASE(...)
-#endif
-
-#endif // PR_LOGGING
-
 } // namespace mozilla
 
 #endif // AccessibleCaretLog_h
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -345,21 +345,27 @@ public:
     mMaybeHitRegion.Or(mMaybeHitRegion, aEventRegions->MaybeHitRegion());
     mDispatchToContentHitRegion.Or(mDispatchToContentHitRegion, aEventRegions->DispatchToContentHitRegion());
     mNoActionRegion.Or(mNoActionRegion, aEventRegions->NoActionRegion());
     mHorizontalPanRegion.Or(mHorizontalPanRegion, aEventRegions->HorizontalPanRegion());
     mVerticalPanRegion.Or(mVerticalPanRegion, aEventRegions->VerticalPanRegion());
   }
 
   /**
-   * If this represents only a nsDisplayImage, and the image type
-   * supports being optimized to an ImageLayer (TYPE_RASTER only) returns
-   * an ImageContainer for the image.
+   * If this represents only a nsDisplayImage, and the image type supports being
+   * optimized to an ImageLayer, returns true.
    */
-  already_AddRefed<ImageContainer> CanOptimizeImageLayer(nsDisplayListBuilder* aBuilder);
+  bool CanOptimizeToImageLayer(nsDisplayListBuilder* aBuilder);
+
+  /**
+   * If this represents only a nsDisplayImage, and the image type supports being
+   * optimized to an ImageLayer, returns an ImageContainer for the underlying
+   * image if one is available.
+   */
+  already_AddRefed<ImageContainer> GetContainerForImageLayer(nsDisplayListBuilder* aBuilder);
 
   bool VisibleAboveRegionIntersects(const nsIntRect& aRect) const
   { return mVisibleAboveRegion.Intersects(aRect); }
   bool VisibleAboveRegionIntersects(const nsIntRegion& aRegion) const
   { return !mVisibleAboveRegion.Intersect(aRegion).IsEmpty(); }
 
   bool VisibleRegionIntersects(const nsIntRect& aRect) const
   { return mVisibleRegion.Intersects(aRect); }
@@ -1046,16 +1052,29 @@ protected:
    * invalidate the layer for layer pixel alignment changes if necessary.
    */
   void PreparePaintedLayerForUse(PaintedLayer* aLayer,
                                  PaintedDisplayItemLayerUserData* aData,
                                  const nsIFrame* aAnimatedGeometryRoot,
                                  const nsIFrame* aReferenceFrame,
                                  const nsPoint& aTopLeft,
                                  bool aDidResetScrollPositionForLayerPixelAlignment);
+
+  /**
+   * Attempt to prepare an ImageLayer based upon the provided PaintedLayerData.
+   * Returns nullptr on failure.
+   */
+  already_AddRefed<Layer> PrepareImageLayer(PaintedLayerData* aData);
+
+  /**
+   * Attempt to prepare a ColorLayer based upon the provided PaintedLayerData.
+   * Returns nullptr on failure.
+   */
+  already_AddRefed<Layer> PrepareColorLayer(PaintedLayerData* aData);
+
   /**
    * Grab the next recyclable ColorLayer, or create one if there are no
    * more recyclable ColorLayers.
    */
   already_AddRefed<ColorLayer> CreateOrRecycleColorLayer(PaintedLayer* aPainted);
   /**
    * Grab the next recyclable ImageLayer, or create one if there are no
    * more recyclable ImageLayers.
@@ -2347,18 +2366,28 @@ PaintedLayerData::UpdateCommonClipCount(
   if (mCommonClipCount >= 0) {
     mCommonClipCount = mItemClip.GetCommonRoundedRectCount(aCurrentClip, mCommonClipCount);
   } else {
     // first item in the layer
     mCommonClipCount = aCurrentClip.GetRoundedRectCount();
   }
 }
 
+bool
+PaintedLayerData::CanOptimizeToImageLayer(nsDisplayListBuilder* aBuilder)
+{
+  if (!mImage) {
+    return nullptr;
+  }
+
+  return mImage->CanOptimizeToImageLayer(mLayer->Manager(), aBuilder);
+}
+
 already_AddRefed<ImageContainer>
-PaintedLayerData::CanOptimizeImageLayer(nsDisplayListBuilder* aBuilder)
+PaintedLayerData::GetContainerForImageLayer(nsDisplayListBuilder* aBuilder)
 {
   if (!mImage) {
     return nullptr;
   }
 
   return mImage->GetContainer(mLayer->Manager(), aBuilder);
 }
 
@@ -2781,16 +2810,68 @@ static int32_t FindIndexOfLayerIn(nsTArr
     if (aArray[i].mLayer == aLayer) {
       return i;
     }
   }
   return -1;
 }
 #endif
 
+already_AddRefed<Layer>
+ContainerState::PrepareImageLayer(PaintedLayerData* aData)
+{
+  nsRefPtr<ImageContainer> imageContainer =
+    aData->GetContainerForImageLayer(mBuilder);
+  if (!imageContainer) {
+    return nullptr;
+  }
+
+  nsRefPtr<ImageLayer> imageLayer = CreateOrRecycleImageLayer(aData->mLayer);
+  imageLayer->SetContainer(imageContainer);
+  aData->mImage->ConfigureLayer(imageLayer, mParameters);
+  imageLayer->SetPostScale(mParameters.mXScale,
+                           mParameters.mYScale);
+
+  if (aData->mItemClip.HasClip()) {
+    ParentLayerIntRect clip =
+      ViewAs<ParentLayerPixel>(ScaleToNearestPixels(aData->mItemClip.GetClipRect()));
+    clip.MoveBy(ViewAs<ParentLayerPixel>(mParameters.mOffset));
+    imageLayer->SetClipRect(Some(clip));
+  } else {
+    imageLayer->SetClipRect(Nothing());
+  }
+
+  mLayerBuilder->StoreOptimizedLayerForFrame(aData->mImage, imageLayer);
+  FLB_LOG_PAINTED_LAYER_DECISION(aData,
+                                 "  Selected image layer=%p\n", imageLayer.get());
+
+  return imageLayer.forget();
+}
+
+already_AddRefed<Layer>
+ContainerState::PrepareColorLayer(PaintedLayerData* aData)
+{
+  nsRefPtr<ColorLayer> colorLayer = CreateOrRecycleColorLayer(aData->mLayer);
+  colorLayer->SetColor(aData->mSolidColor);
+
+  // Copy transform
+  colorLayer->SetBaseTransform(aData->mLayer->GetBaseTransform());
+  colorLayer->SetPostScale(aData->mLayer->GetPostXScale(),
+                           aData->mLayer->GetPostYScale());
+
+  nsIntRect visibleRect = aData->mVisibleRegion.GetBounds();
+  visibleRect.MoveBy(-GetTranslationForPaintedLayer(aData->mLayer));
+  colorLayer->SetBounds(visibleRect);
+  colorLayer->SetClipRect(Nothing());
+
+  FLB_LOG_PAINTED_LAYER_DECISION(aData,
+                                 "  Selected color layer=%p\n", colorLayer.get());
+
+  return colorLayer.forget();
+}
 
 template<typename FindOpaqueBackgroundColorCallbackType>
 void ContainerState::FinishPaintedLayerData(PaintedLayerData& aData, FindOpaqueBackgroundColorCallbackType aFindOpaqueBackgroundColor)
 {
   PaintedLayerData* data = &aData;
 
   if (!data->mLayer) {
     // No layer was recycled, so we create a new one.
@@ -2809,82 +2890,56 @@ void ContainerState::FinishPaintedLayerD
     mLayerBuilder->AddPaintedDisplayItem(data, item.mItem, item.mClip,
                                          *this, item.mLayerState,
                                          data->mAnimatedGeometryRootOffset);
   }
 
   NewLayerEntry* newLayerEntry = &mNewChildLayers[data->mNewChildLayersIndex];
 
   nsRefPtr<Layer> layer;
-  nsRefPtr<ImageContainer> imageContainer = data->CanOptimizeImageLayer(mBuilder);
+  bool canOptimizeToImageLayer = data->CanOptimizeToImageLayer(mBuilder);
 
   FLB_LOG_PAINTED_LAYER_DECISION(data, "Selecting layer for pld=%p\n", data);
-  FLB_LOG_PAINTED_LAYER_DECISION(data, "  Solid=%i, hasImage=%i, canOptimizeAwayPaintedLayer=%i\n",
-          data->mIsSolidColorInVisibleRegion, !!imageContainer,
+  FLB_LOG_PAINTED_LAYER_DECISION(data, "  Solid=%i, hasImage=%c, canOptimizeAwayPaintedLayer=%i\n",
+          data->mIsSolidColorInVisibleRegion, canOptimizeToImageLayer ? 'y' : 'n',
           CanOptimizeAwayPaintedLayer(data, mLayerBuilder));
 
-  if ((data->mIsSolidColorInVisibleRegion || imageContainer) &&
+  if ((data->mIsSolidColorInVisibleRegion || canOptimizeToImageLayer) &&
       CanOptimizeAwayPaintedLayer(data, mLayerBuilder)) {
-    NS_ASSERTION(!(data->mIsSolidColorInVisibleRegion && imageContainer),
+    NS_ASSERTION(!(data->mIsSolidColorInVisibleRegion && canOptimizeToImageLayer),
                  "Can't be a solid color as well as an image!");
-    if (imageContainer) {
-      nsRefPtr<ImageLayer> imageLayer = CreateOrRecycleImageLayer(data->mLayer);
-      imageLayer->SetContainer(imageContainer);
-      data->mImage->ConfigureLayer(imageLayer, mParameters);
-      imageLayer->SetPostScale(mParameters.mXScale,
-                               mParameters.mYScale);
-      if (data->mItemClip.HasClip()) {
-        ParentLayerIntRect clip = ViewAs<ParentLayerPixel>(ScaleToNearestPixels(data->mItemClip.GetClipRect()));
-        clip.MoveBy(ViewAs<ParentLayerPixel>(mParameters.mOffset));
-        imageLayer->SetClipRect(Some(clip));
-      } else {
-        imageLayer->SetClipRect(Nothing());
-      }
-      layer = imageLayer;
-      mLayerBuilder->StoreOptimizedLayerForFrame(data->mImage,
-                                                 imageLayer);
-      FLB_LOG_PAINTED_LAYER_DECISION(data, "  Selected image layer=%p\n", layer.get());
-    } else {
-      nsRefPtr<ColorLayer> colorLayer = CreateOrRecycleColorLayer(data->mLayer);
-      colorLayer->SetColor(data->mSolidColor);
-
-      // Copy transform
-      colorLayer->SetBaseTransform(data->mLayer->GetBaseTransform());
-      colorLayer->SetPostScale(data->mLayer->GetPostXScale(), data->mLayer->GetPostYScale());
-
-      nsIntRect visibleRect = data->mVisibleRegion.GetBounds();
-      visibleRect.MoveBy(-GetTranslationForPaintedLayer(data->mLayer));
-      colorLayer->SetBounds(visibleRect);
-      colorLayer->SetClipRect(Nothing());
-
-      layer = colorLayer;
-      FLB_LOG_PAINTED_LAYER_DECISION(data, "  Selected color layer=%p\n", layer.get());
+
+    layer = canOptimizeToImageLayer ? PrepareImageLayer(data)
+                                    : PrepareColorLayer(data);
+
+    if (layer) {
+      NS_ASSERTION(FindIndexOfLayerIn(mNewChildLayers, layer) < 0,
+                   "Layer already in list???");
+      NS_ASSERTION(newLayerEntry->mLayer == data->mLayer,
+                   "Painted layer at wrong index");
+      // Store optimized layer in reserved slot
+      newLayerEntry = &mNewChildLayers[data->mNewChildLayersIndex + 1];
+      NS_ASSERTION(!newLayerEntry->mLayer, "Slot already occupied?");
+      newLayerEntry->mLayer = layer;
+      newLayerEntry->mAnimatedGeometryRoot = data->mAnimatedGeometryRoot;
+      newLayerEntry->mFixedPosFrameForLayerData = data->mFixedPosFrameForLayerData;
+
+      // Hide the PaintedLayer. We leave it in the layer tree so that we
+      // can find and recycle it later.
+      ParentLayerIntRect emptyRect;
+      data->mLayer->SetClipRect(Some(emptyRect));
+      data->mLayer->SetVisibleRegion(nsIntRegion());
+      data->mLayer->InvalidateRegion(data->mLayer->GetValidRegion().GetBounds());
+      data->mLayer->SetEventRegions(EventRegions());
     }
-
-    NS_ASSERTION(FindIndexOfLayerIn(mNewChildLayers, layer) < 0,
-                 "Layer already in list???");
-    NS_ASSERTION(newLayerEntry->mLayer == data->mLayer,
-                 "Painted layer at wrong index");
-    // Store optimized layer in reserved slot
-    newLayerEntry = &mNewChildLayers[data->mNewChildLayersIndex + 1];
-    NS_ASSERTION(!newLayerEntry->mLayer, "Slot already occupied?");
-    newLayerEntry->mLayer = layer;
-    newLayerEntry->mAnimatedGeometryRoot = data->mAnimatedGeometryRoot;
-    newLayerEntry->mFixedPosFrameForLayerData = data->mFixedPosFrameForLayerData;
-
-    // Hide the PaintedLayer. We leave it in the layer tree so that we
-    // can find and recycle it later.
-    ParentLayerIntRect emptyRect;
-    data->mLayer->SetClipRect(Some(emptyRect));
-    data->mLayer->SetVisibleRegion(nsIntRegion());
-    data->mLayer->InvalidateRegion(data->mLayer->GetValidRegion().GetBounds());
-    data->mLayer->SetEventRegions(EventRegions());
-  } else {
+  }
+  
+  if (!layer) {
+    // We couldn't optimize to an image layer or a color layer above.
     layer = data->mLayer;
-    imageContainer = nullptr;
     layer->SetClipRect(Nothing());
     FLB_LOG_PAINTED_LAYER_DECISION(data, "  Selected painted layer=%p\n", layer.get());
   }
 
   if (mLayerBuilder->IsBuildingRetainedLayers()) {
     newLayerEntry->mVisibleRegion = data->mVisibleRegion;
     newLayerEntry->mOpaqueRegion = data->mOpaqueRegion;
     newLayerEntry->mHideAllLayersBelow = data->mHideAllLayersBelow;
--- a/layout/base/nsBidi.cpp
+++ b/layout/base/nsBidi.cpp
@@ -664,17 +664,17 @@ void nsBidi::ResolveExplicitLevels(nsBid
 
     /* (X1) level is set for all codes, embeddingLevel keeps track of the push/pop operations */
     /* both variables may carry the NSBIDI_LEVEL_OVERRIDE flag to indicate the override status */
     nsBidiLevel embeddingLevel = level, newLevel;
     nsBidiLevel previousLevel = level;     /* previous level for regular (not CC) characters */
 
     uint16_t stack[NSBIDI_MAX_EXPLICIT_LEVEL + 2];   /* we never push anything >=NSBIDI_MAX_EXPLICIT_LEVEL
                                                         but we need one more entry as base */
-    uint32_t stackLast = 0;
+    int32_t stackLast = 0;
     int32_t overflowIsolateCount = 0;
     int32_t overflowEmbeddingCount = 0;
     int32_t validIsolateCount = 0;
 
     stack[0] = level;
 
     /* recalculate the flags */
     flags=0;
@@ -768,18 +768,24 @@ void nsBidi::ResolveExplicitLevels(nsBid
             dirProps[i] |= IGNORE_CC;
             overflowIsolateCount--;
           } else if (validIsolateCount) {
             overflowEmbeddingCount = 0;
             while (stack[stackLast] < ISOLATE) {
               /* pop embedding entries        */
               /* until the last isolate entry */
               stackLast--;
+
+              // Since validIsolateCount is true, there must be an isolate entry
+              // on the stack, so the stack is guaranteed to not be empty.
+              // Still, to eliminate a warning from coverity, we use an assertion.
+              MOZ_ASSERT(stackLast > 0);
             }
             stackLast--;  /* pop also the last isolate entry */
+            MOZ_ASSERT(stackLast >= 0);  // For coverity
             validIsolateCount--;
           } else {
             dirProps[i] |= IGNORE_CC;
           }
           embeddingLevel = stack[stackLast] & ~ISOLATE;
           previousLevel = level = embeddingLevel;
           flags |= DIRPROP_FLAG(O_N) | DIRPROP_FLAG(BN) | DIRPROP_FLAG_LR(embeddingLevel);
           break;
--- a/layout/base/nsCSSRendering.cpp
+++ b/layout/base/nsCSSRendering.cpp
@@ -5188,24 +5188,40 @@ nsImageRenderer::IsAnimatedImage()
     return false;
   bool animated = false;
   if (NS_SUCCEEDED(mImageContainer->GetAnimated(&animated)) && animated)
     return true;
 
   return false;
 }
 
-already_AddRefed<mozilla::layers::ImageContainer>
-nsImageRenderer::GetContainer(LayerManager* aManager)
+bool
+nsImageRenderer::IsContainerAvailable(LayerManager* aManager,
+                                      nsDisplayListBuilder* aBuilder)
+{
+  if (mType != eStyleImageType_Image || !mImageContainer) {
+    return false;
+  }
+
+  uint32_t flags = aBuilder->ShouldSyncDecodeImages()
+                 ? imgIContainer::FLAG_SYNC_DECODE
+                 : imgIContainer::FLAG_NONE;
+
+  return mImageContainer->IsImageContainerAvailable(aManager, flags);
+}
+
+already_AddRefed<imgIContainer>
+nsImageRenderer::GetImage()
 {
   if (mType != eStyleImageType_Image || !mImageContainer) {
     return nullptr;
   }
 
-  return mImageContainer->GetImageContainer(aManager, imgIContainer::FLAG_NONE);
+  nsCOMPtr<imgIContainer> image = mImageContainer;
+  return image.forget();
 }
 
 #define MAX_BLUR_RADIUS 300
 #define MAX_SPREAD_RADIUS 50
 
 static inline gfxPoint ComputeBlurStdDev(nscoord aBlurRadius,
                                          int32_t aAppUnitsPerDevPixel,
                                          gfxFloat aScaleX,
--- a/layout/base/nsCSSRendering.h
+++ b/layout/base/nsCSSRendering.h
@@ -232,17 +232,29 @@ public:
                            const mozilla::CSSIntRect& aSrc,
                            uint8_t              aHFill,
                            uint8_t              aVFill,
                            const nsSize&        aUnitSize,
                            uint8_t              aIndex);
 
   bool IsRasterImage();
   bool IsAnimatedImage();
-  already_AddRefed<ImageContainer> GetContainer(LayerManager* aManager);
+
+  /**
+   * @return true if this nsImageRenderer wraps an image which has an
+   * ImageContainer available.
+   *
+   * If IsContainerAvailable() returns true, GetImage() will return a non-null
+   * imgIContainer which callers can use to retrieve the ImageContainer.
+   */
+  bool IsContainerAvailable(LayerManager* aManager,
+                            nsDisplayListBuilder* aBuilder);
+
+  /// Retrieves the image associated with this nsImageRenderer, if there is one.
+  already_AddRefed<imgIContainer> GetImage();
 
   bool IsReady() { return mIsReady; }
 
 private:
   /**
    * Draws the image to the target rendering context.
    * aSrc is a rect on the source image which will be mapped to aDest; it's
    * currently only used for gradients.
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -2291,21 +2291,22 @@ nsDisplayBackgroundImage::ShouldFixToVie
 
   // Put background-attachment:fixed background images in their own
   // compositing layer, unless we have APZ enabled
   return mBackgroundStyle->mLayers[mLayer].mAttachment == NS_STYLE_BG_ATTACHMENT_FIXED &&
          !mBackgroundStyle->mLayers[mLayer].mImage.IsEmpty();
 }
 
 bool
-nsDisplayBackgroundImage::TryOptimizeToImageLayer(LayerManager* aManager,
+nsDisplayBackgroundImage::CanOptimizeToImageLayer(LayerManager* aManager,
                                                   nsDisplayListBuilder* aBuilder)
 {
-  if (!mBackgroundStyle)
+  if (!mBackgroundStyle) {
     return false;
+  }
 
   nsPresContext* presContext = mFrame->PresContext();
   uint32_t flags = aBuilder->GetBackgroundPaintFlags();
   nsRect borderArea = nsRect(ToReferenceFrame(), mFrame->GetSize());
   const nsStyleBackground::Layer &layer = mBackgroundStyle->mLayers[mLayer];
 
   if (layer.mClip != NS_STYLE_BG_CLIP_BORDER) {
     return false;
@@ -2315,51 +2316,65 @@ nsDisplayBackgroundImage::TryOptimizeToI
     return false;
   }
 
   nsBackgroundLayerState state =
     nsCSSRendering::PrepareBackgroundLayer(presContext, mFrame, flags,
                                            borderArea, borderArea, layer);
   nsImageRenderer* imageRenderer = &state.mImageRenderer;
   // We only care about images here, not gradients.
-  if (!imageRenderer->IsRasterImage())
+  if (!imageRenderer->IsRasterImage()) {
     return false;
-
-  nsRefPtr<ImageContainer> imageContainer = imageRenderer->GetContainer(aManager);
-  // Image is not ready to be made into a layer yet
-  if (!imageContainer)
+  }
+
+  if (!imageRenderer->IsContainerAvailable(aManager, aBuilder)) {
+    // The image is not ready to be made into a layer yet.
     return false;
+  }
 
   // We currently can't handle tiled or partial backgrounds.
   if (!state.mDestArea.IsEqualEdges(state.mFillArea)) {
     return false;
   }
 
   // XXX Ignoring state.mAnchor. ImageLayer drawing snaps mDestArea edges to
   // layer pixel boundaries. This should be OK for now.
 
   int32_t appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
   mDestRect =
     LayoutDeviceRect::FromAppUnits(state.mDestArea, appUnitsPerDevPixel);
-  mImageContainer = imageContainer;
 
   // Ok, we can turn this into a layer if needed.
+  mImage = imageRenderer->GetImage();
+  MOZ_ASSERT(mImage);
+
   return true;
 }
 
 already_AddRefed<ImageContainer>
 nsDisplayBackgroundImage::GetContainer(LayerManager* aManager,
                                        nsDisplayListBuilder *aBuilder)
 {
-  if (!TryOptimizeToImageLayer(aManager, aBuilder)) {
+  if (!mImage) {
+    MOZ_ASSERT_UNREACHABLE("Must call CanOptimizeToImage() and get true "
+                           "before calling GetContainer()");
     return nullptr;
   }
 
+  if (!mImageContainer) {
+    // We don't have an ImageContainer yet; get it from mImage.
+
+    uint32_t flags = aBuilder->ShouldSyncDecodeImages()
+                   ? imgIContainer::FLAG_SYNC_DECODE
+                   : imgIContainer::FLAG_NONE;
+
+    mImageContainer = mImage->GetImageContainer(aManager, flags);
+  }
+
   nsRefPtr<ImageContainer> container = mImageContainer;
-
   return container.forget();
 }
 
 LayerState
 nsDisplayBackgroundImage::GetLayerState(nsDisplayListBuilder* aBuilder,
                                         LayerManager* aManager,
                                         const ContainerLayerParameters& aParameters)
 {
@@ -2381,29 +2396,34 @@ nsDisplayBackgroundImage::GetLayerState(
   if (!animated ||
       !nsLayoutUtils::AnimatedImageLayersEnabled()) {
     if (!aManager->IsCompositingCheap() ||
         !nsLayoutUtils::GPUImageScalingEnabled()) {
       return LAYER_NONE;
     }
   }
 
-  if (!TryOptimizeToImageLayer(aManager, aBuilder)) {
+  if (!CanOptimizeToImageLayer(aManager, aBuilder)) {
     return LAYER_NONE;
   }
 
+  MOZ_ASSERT(mImage);
+
   if (!animated) {
-    mozilla::gfx::IntSize imageSize = mImageContainer->GetCurrentSize();
-    NS_ASSERTION(imageSize.width != 0 && imageSize.height != 0, "Invalid image size!");
+    int32_t imageWidth;
+    int32_t imageHeight;
+    mImage->GetWidth(&imageWidth);
+    mImage->GetHeight(&imageHeight);
+    NS_ASSERTION(imageWidth != 0 && imageHeight != 0, "Invalid image size!");
 
     const LayerRect destLayerRect = mDestRect * aParameters.Scale();
 
     // Calculate the scaling factor for the frame.
-    const gfxSize scale = gfxSize(destLayerRect.width / imageSize.width,
-                                  destLayerRect.height / imageSize.height);
+    const gfxSize scale = gfxSize(destLayerRect.width / imageWidth,
+                                  destLayerRect.height / imageHeight);
 
     // If we are not scaling at all, no point in separating this into a layer.
     if (scale.width == 1.0f && scale.height == 1.0f) {
       return LAYER_NONE;
     }
 
     // If the target size is pretty small, no point in using a layer.
     if (destLayerRect.width * destLayerRect.height < 64 * 64) {
@@ -2421,45 +2441,51 @@ nsDisplayBackgroundImage::BuildLayer(nsD
 {
   nsRefPtr<ImageLayer> layer = static_cast<ImageLayer*>
     (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, this));
   if (!layer) {
     layer = aManager->CreateImageLayer();
     if (!layer)
       return nullptr;
   }
-  layer->SetContainer(mImageContainer);
+  nsRefPtr<ImageContainer> imageContainer = GetContainer(aManager, aBuilder);
+  layer->SetContainer(imageContainer);
   ConfigureLayer(layer, aParameters);
   return layer.forget();
 }
 
 void
 nsDisplayBackgroundImage::ConfigureLayer(ImageLayer* aLayer,
                                          const ContainerLayerParameters& aParameters)
 {
   aLayer->SetFilter(nsLayoutUtils::GetGraphicsFilterForFrame(mFrame));
 
-  mozilla::gfx::IntSize imageSize = mImageContainer->GetCurrentSize();
-  NS_ASSERTION(imageSize.width != 0 && imageSize.height != 0, "Invalid image size!");
-  if (imageSize.width > 0 && imageSize.height > 0) {
+  MOZ_ASSERT(mImage);
+  int32_t imageWidth;
+  int32_t imageHeight;
+  mImage->GetWidth(&imageWidth);
+  mImage->GetHeight(&imageHeight);
+  NS_ASSERTION(imageWidth != 0 && imageHeight != 0, "Invalid image size!");
+
+  if (imageWidth > 0 && imageHeight > 0) {
     // We're actually using the ImageContainer. Let our frame know that it
     // should consider itself to have painted successfully.
     nsDisplayBackgroundGeometry::UpdateDrawResult(this, DrawResult::SUCCESS);
   }
 
   // XXX(seth): Right now we ignore aParameters.Scale() and
   // aParameters.Offset(), because FrameLayerBuilder already applies
   // aParameters.Scale() via the layer's post-transform, and
   // aParameters.Offset() is always zero.
   MOZ_ASSERT(aParameters.Offset() == LayerIntPoint(0,0));
 
   const LayoutDevicePoint p = mDestRect.TopLeft();
   Matrix transform = Matrix::Translation(p.x, p.y);
-  transform.PreScale(mDestRect.width / imageSize.width,
-                     mDestRect.height / imageSize.height);
+  transform.PreScale(mDestRect.width / imageWidth,
+                     mDestRect.height / imageHeight);
   aLayer->SetBaseTransform(gfx::Matrix4x4::From2D(transform));
 }
 
 void
 nsDisplayBackgroundImage::HitTest(nsDisplayListBuilder* aBuilder,
                                   const nsRect& aRect,
                                   HitTestState* aState,
                                   nsTArray<nsIFrame*> *aOutFrames)
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -1983,16 +1983,24 @@ public:
   typedef mozilla::LayoutDeviceRect LayoutDeviceRect;
   typedef mozilla::layers::ImageContainer ImageContainer;
   typedef mozilla::layers::ImageLayer ImageLayer;
 
   nsDisplayImageContainer(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
     : nsDisplayItem(aBuilder, aFrame)
   {}
 
+  /**
+   * @return true if this display item can be optimized into an image layer.
+   * It is an error to call GetContainer() unless you've called
+   * CanOptimizeToImageLayer() first and it returned true.
+   */
+  virtual bool CanOptimizeToImageLayer(LayerManager* aManager,
+                                       nsDisplayListBuilder* aBuilder) = 0;
+
   virtual already_AddRefed<ImageContainer> GetContainer(LayerManager* aManager,
                                                         nsDisplayListBuilder* aBuilder) = 0;
   virtual void ConfigureLayer(ImageLayer* aLayer,
                               const ContainerLayerParameters& aParameters) = 0;
 
   virtual bool SupportsOptimizingToImage() override { return true; }
 };
 
@@ -2331,16 +2339,18 @@ public:
   {
     return new nsDisplayBackgroundGeometry(this, aBuilder);
   }
 
   virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
                                          const nsDisplayItemGeometry* aGeometry,
                                          nsRegion* aInvalidRegion) override;
   
+  virtual bool CanOptimizeToImageLayer(LayerManager* aManager,
+                                       nsDisplayListBuilder* aBuilder) override;
   virtual already_AddRefed<ImageContainer> GetContainer(LayerManager* aManager,
                                                         nsDisplayListBuilder *aBuilder) override;
   virtual void ConfigureLayer(ImageLayer* aLayer,
                               const ContainerLayerParameters& aParameters) override;
 
   static nsRegion GetInsideClipRegion(nsDisplayItem* aItem, nsPresContext* aPresContext, uint8_t aClip,
                                       const nsRect& aRect, bool* aSnap);
 
@@ -2357,17 +2367,17 @@ protected:
   nsRect GetBoundsInternal(nsDisplayListBuilder* aBuilder);
 
   void PaintInternal(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx,
                      const nsRect& aBounds, nsRect* aClipRect);
 
   // Cache the result of nsCSSRendering::FindBackground. Always null if
   // mIsThemed is true or if FindBackground returned false.
   const nsStyleBackground* mBackgroundStyle;
-  /* If this background can be a simple image layer, we store the format here. */
+  nsCOMPtr<imgIContainer> mImage;
   nsRefPtr<ImageContainer> mImageContainer;
   LayoutDeviceRect mDestRect;
   /* Bounds of this display item */
   nsRect mBounds;
   uint32_t mLayer;
 };
 
 
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -63,16 +63,21 @@
 #include "nsFrameLoader.h"
 #include "mozilla/dom/FontFaceSet.h"
 #include "nsContentUtils.h"
 #include "nsPIWindowRoot.h"
 #include "mozilla/Preferences.h"
 #include "gfxTextRun.h"
 #include "nsFontFaceUtils.h"
 
+#if defined(MOZ_WIDGET_GTK)
+#include "gfxPlatformGtk.h" // xxx - for UseFcFontList
+#endif
+
+
 // Needed for Start/Stop of Image Animation
 #include "imgIContainer.h"
 #include "nsIImageLoadingContent.h"
 
 #include "nsCSSParser.h"
 #include "nsBidiUtils.h"
 #include "nsServiceManagerUtils.h"
 
@@ -2165,18 +2170,20 @@ nsPresContext::RebuildUserFontSet()
 
 void
 nsPresContext::UserFontSetUpdated(gfxUserFontEntry* aUpdatedFont)
 {
   if (!mShell)
     return;
 
   bool usePlatformFontList = true;
-#if defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_QT)
-  usePlatformFontList = false;
+#if defined(MOZ_WIDGET_GTK)
+    usePlatformFontList = gfxPlatformGtk::UseFcFontList();
+#elif defined(MOZ_WIDGET_QT)
+    usePlatformFontList = false;
 #endif
 
   // xxx - until the Linux platform font list is always used, use full
   // restyle to force updates with gfxPangoFontGroup usage
   // Note: this method is called without a font when rules in the userfont set
   // are updated, which may occur during reflow as a result of the lazy
   // initialization of the userfont set. It would be better to avoid a full
   // restyle but until this method is only called outside of reflow, schedule a
--- a/layout/base/tests/chrome/printpreview_helper.xul
+++ b/layout/base/tests/chrome/printpreview_helper.xul
@@ -121,31 +121,31 @@ function startTest1() {
   // after print preview, but not during it.
   window.frames[0].wrappedJSObject.counter = counter;
   window.frames[0].counterTimeout = "document.body.firstChild.nextSibling.innerHTML = ++counter + ' timers';" +
                                     "window.setTimeout(counterTimeout, 0);";
   window.frames[0].setTimeout(window.frames[0].counterTimeout, 0);
   window.frames[0].document.body.firstChild.innerHTML = "Print preview";
 
   printpreview();
-  ctx1.drawWindow(window.frames[1], 0, 0, 300, 300, "rgb(256,256,256)");
+  ctx1.drawWindow(window.frames[1], 0, 0, 400, 400, "rgb(256,256,256)");
   window.frames[0].document.body.firstChild.innerHTML = "Galley presentation";
 
   // Add some elements.
   addHTMLContent(window.frames[0].document.body.lastChild);
   // Delete them.
   window.frames[0].document.body.lastChild.innerHTML = "";
   // And readd.
   addHTMLContent(window.frames[0].document.body.lastChild);
 
   setTimeout(finalizeTest1, 1000);
 }
 
 function finalizeTest1() {
-  ctx2.drawWindow(window.frames[1], 0, 0, 300, 300, "rgb(256,256,256)");
+  ctx2.drawWindow(window.frames[1], 0, 0, 400, 400, "rgb(256,256,256)");
   exitprintpreview();
   ok(compareCanvases(), "Canvas should be the same!");
   counter = window.frames[0].counter;
   // This timeout is needed so that we can check that timers do run after
   // print preview.
   setTimeout(runTest2, 1000);
 }
 
@@ -205,23 +205,23 @@ function runTest3() {
   setTimeout(runTest4, 0)
 }
 
 function compareFormElementPrint(el1, el2, equals) {
   window.frames[0].document.body.innerHTML = el1;
   window.frames[0].document.body.firstChild.value =
     window.frames[0].document.body.firstChild.getAttribute('value');
   printpreview();
-  ctx1.drawWindow(window.frames[1], 0, 0, 300, 300, "rgb(256,256,256)");
+  ctx1.drawWindow(window.frames[1], 0, 0, 400, 400, "rgb(256,256,256)");
   exitprintpreview();
   window.frames[0].document.body.innerHTML = el2;
   window.frames[0].document.body.firstChild.value =
     window.frames[0].document.body.firstChild.getAttribute('value');
   printpreview();
-  ctx2.drawWindow(window.frames[1], 0, 0, 300, 300, "rgb(256,256,256)");
+  ctx2.drawWindow(window.frames[1], 0, 0, 400, 400, "rgb(256,256,256)");
   exitprintpreview();
   is(compareCanvases(), equals,
      "Comparing print preview didn't succeed [" + el1 + " : " + el2 + "]");
   setTimeout(runTest3, 100);
 }
 
 // This is a crash test for bug 539060.
 function runTest4() {
@@ -263,12 +263,12 @@ function runTest6end() {
 
   finish();
 }
 
 ]]></script>
 <table style="border: 1px solid black;" xmlns="http://www.w3.org/1999/xhtml">
 <tr><th>Print preview canvas 1</th><th>Print preview canvas 2</th></tr>
 <tr>
-<td><canvas height="300" width="300"></canvas></td>
-<td><canvas height="300" width="300"></canvas></td>
+<td><canvas height="400" width="400"></canvas></td>
+<td><canvas height="400" width="400"></canvas></td>
 </tr></table>
 </window>
--- a/layout/base/tests/marionette/test_selectioncarets.py
+++ b/layout/base/tests/marionette/test_selectioncarets.py
@@ -43,25 +43,27 @@ class CommonCaretsTestCase(object):
 
         For example:
         >>> set_pref('layout.accessiblecaret.enabled', True)
 
         '''
         pref_name = repr(pref_name)
         if isinstance(value, bool):
             value = 'true' if value else 'false'
+            func = 'setBoolPref'
         elif isinstance(value, int):
             value = str(value)
+            func = 'setIntPref'
         else:
             value = repr(value)
+            func = 'setCharPref'
 
-        script = '''SpecialPowers.pushPrefEnv({"set": [[%s, %s]]}, marionetteScriptFinished);''' % (
-            pref_name, value)
-
-        self.marionette.execute_async_script(script)
+        with self.marionette.using_context('chrome'):
+            script = 'Services.prefs.%s(%s, %s)' % (func, pref_name, value)
+            self.marionette.execute_script(script)
 
     def open_test_html(self, enabled=True):
         '''Open html for testing and locate elements, and enable/disable touch
         caret.'''
         self.set_pref(self.carets_tested_pref, enabled)
         self.set_pref(self.carets_disabled_pref, False)
 
         test_html = self.marionette.absolute_url('test_selectioncarets.html')
--- a/layout/base/tests/marionette/test_selectioncarets2.py
+++ b/layout/base/tests/marionette/test_selectioncarets2.py
@@ -43,25 +43,27 @@ class CommonCaretsTestCase2(object):
 
         For example:
         >>> set_pref('layout.accessiblecaret.enabled', True)
 
         '''
         pref_name = repr(pref_name)
         if isinstance(value, bool):
             value = 'true' if value else 'false'
+            func = 'setBoolPref'
         elif isinstance(value, int):
             value = str(value)
+            func = 'setIntPref'
         else:
             value = repr(value)
+            func = 'setCharPref'
 
-        script = '''SpecialPowers.pushPrefEnv({"set": [[%s, %s]]}, marionetteScriptFinished);''' % (
-            pref_name, value)
-
-        self.marionette.execute_async_script(script)
+        with self.marionette.using_context('chrome'):
+            script = 'Services.prefs.%s(%s, %s)' % (func, pref_name, value)
+            self.marionette.execute_script(script)
 
     def open_test_html(self, enabled=True):
         'Open html for testing and enable selectioncaret and non-editable support'
         self.set_pref(self.carets_tested_pref, enabled)
         self.set_pref(self.carets_disabled_pref, False)
 
         test_html = self.marionette.absolute_url('test_selectioncarets_multiplerange.html')
         self.marionette.navigate(test_html)
--- a/layout/base/tests/marionette/test_touchcaret.py
+++ b/layout/base/tests/marionette/test_touchcaret.py
@@ -37,30 +37,33 @@ class CommonCaretTestCase(object):
 
         For example:
         >>> set_pref('layout.accessiblecaret.enabled', True)
 
         '''
         pref_name = repr(pref_name)
         if isinstance(value, bool):
             value = 'true' if value else 'false'
+            func = 'setBoolPref'
         elif isinstance(value, int):
             value = str(value)
+            func = 'setIntPref'
         else:
             value = repr(value)
+            func = 'setCharPref'
 
-        script = '''SpecialPowers.pushPrefEnv({"set": [[%s, %s]]}, marionetteScriptFinished);''' % (
-            pref_name, value)
-
-        self.marionette.execute_async_script(script)
+        with self.marionette.using_context('chrome'):
+            script = 'Services.prefs.%s(%s, %s)' % (func, pref_name, value)
+            self.marionette.execute_script(script)
 
     def timeout_ms(self):
         'Return touch caret expiration time in milliseconds.'
-        return self.marionette.execute_script(
-            'return SpecialPowers.getIntPref("%s");' % self.caret_timeout_ms_pref)
+        with self.marionette.using_context('chrome'):
+            return self.marionette.execute_script(
+                'return Services.prefs.getIntPref("%s");' % self.caret_timeout_ms_pref)
 
     def open_test_html(self, enabled=True, timeout_ms=0):
         '''Open html for testing and locate elements, enable/disable touch caret, and
         set touch caret expiration time in milliseconds).
 
         '''
         self.set_pref(self.caret_tested_pref, enabled)
         self.set_pref(self.caret_disabled_pref, False)
@@ -183,21 +186,25 @@ class CommonCaretTestCase(object):
 
         # Send an arbitrary scroll-down-10px wheel event to the center of the
         # input box to hide touch caret. Then pretend to move it to the top-left
         # corner of the input box.
         src_x, src_y = sel.touch_caret_location()
         dest_x, dest_y = 0, 0
         el_center_x, el_center_y = el.rect['x'], el.rect['y']
         self.marionette.execute_script(
-            '''var utils = SpecialPowers.getDOMWindowUtils(window);
+            '''
+            var utils = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+                              .getInterface(Components.interfaces.nsIDOMWindowUtils);
             utils.sendWheelEvent(arguments[0], arguments[1],
                                  0, 10, 0, WheelEvent.DOM_DELTA_PIXEL,
-                                 0, 0, 0, 0);''',
-            script_args=[el_center_x, el_center_y]
+                                 0, 0, 0, 0);
+            ''',
+            script_args=[el_center_x, el_center_y],
+            sandbox='system'
         )
         self.actions.flick(el, src_x, src_y, dest_x, dest_y).perform()
 
         el.send_keys(content_to_add)
         assertFunc(non_target_content, sel.content)
 
     ########################################################################
     # <input> test cases with touch caret enabled
--- a/layout/generic/nsFlexContainerFrame.cpp
+++ b/layout/generic/nsFlexContainerFrame.cpp
@@ -146,16 +146,20 @@ PhysicalCoordFromFlexRelativeCoord(nscoo
 // evaluate), these macros will ensure that only the expression for the correct
 // axis gets evaluated.
 #define GET_MAIN_COMPONENT(axisTracker_, width_, height_)  \
   (axisTracker_).IsMainAxisHorizontal() ? (width_) : (height_)
 
 #define GET_CROSS_COMPONENT(axisTracker_, width_, height_)  \
   (axisTracker_).IsCrossAxisHorizontal() ? (width_) : (height_)
 
+// Logical versions of helper-macros above:
+#define GET_MAIN_COMPONENT_LOGICAL(axisTracker_, isize_, bsize_)  \
+  (axisTracker_).IsRowOriented() ? (isize_) : (bsize_)
+
 // Encapsulates our flex container's main & cross axes.
 class MOZ_STACK_CLASS nsFlexContainerFrame::FlexboxAxisTracker {
 public:
   FlexboxAxisTracker(const nsStylePosition* aStylePosition,
                      const WritingMode& aWM);
 
   // Accessors:
   // XXXdholbert [BEGIN DEPRECATED]
@@ -180,16 +184,17 @@ public:
   }
   // Returns true if our cross axis is in the reverse direction of our
   // writing mode's corresponding axis. (From 'flex-wrap: *-reverse')
   bool IsCrossAxisReversed() const {
     return mIsCrossAxisReversed;
   }
 
   bool IsRowOriented() const { return mIsRowOriented; }
+  bool IsColumnOriented() const { return !mIsRowOriented; }
 
   nscoord GetMainComponent(const nsSize& aSize) const {
     return GET_MAIN_COMPONENT(*this, aSize.width, aSize.height);
   }
   int32_t GetMainComponent(const LayoutDeviceIntSize& aIntSize) const {
     return GET_MAIN_COMPONENT(*this, aIntSize.width, aIntSize.height);
   }
 
@@ -3065,17 +3070,17 @@ AddNewFlexLineToList(LinkedList<FlexLine
   return newLine;
 }
 
 void
 nsFlexContainerFrame::GenerateFlexLines(
   nsPresContext* aPresContext,
   const nsHTMLReflowState& aReflowState,
   nscoord aContentBoxMainSize,
-  nscoord aAvailableHeightForContent,
+  nscoord aAvailableBSizeForContent,
   const nsTArray<StrutInfo>& aStruts,
   const FlexboxAxisTracker& aAxisTracker,
   LinkedList<FlexLine>& aLines)
 {
   MOZ_ASSERT(aLines.isEmpty(), "Expecting outparam to start out empty");
 
   const bool isSingleLine =
     NS_STYLE_FLEX_WRAP_NOWRAP == aReflowState.mStylePosition->mFlexWrap;
@@ -3096,32 +3101,33 @@ nsFlexContainerFrame::GenerateFlexLines(
   if (isSingleLine) {
     // Not wrapping. Set threshold to sentinel value that tells us not to wrap.
     wrapThreshold = NS_UNCONSTRAINEDSIZE;
   } else {
     // Wrapping! Set wrap threshold to flex container's content-box main-size.
     wrapThreshold = aContentBoxMainSize;
 
     // If the flex container doesn't have a definite content-box main-size
-    // (e.g. if we're 'height:auto'), make sure we at least wrap when we hit
-    // its max main-size.
+    // (e.g. if main axis is vertical & 'height' is 'auto'), make sure we at
+    // least wrap when we hit its max main-size.
     if (wrapThreshold == NS_UNCONSTRAINEDSIZE) {
       const nscoord flexContainerMaxMainSize =
-        GET_MAIN_COMPONENT(aAxisTracker,
-                           aReflowState.ComputedMaxWidth(),
-                           aReflowState.ComputedMaxHeight());
+        GET_MAIN_COMPONENT_LOGICAL(aAxisTracker,
+                                   aReflowState.ComputedMaxISize(),
+                                   aReflowState.ComputedMaxBSize());
 
       wrapThreshold = flexContainerMaxMainSize;
     }
 
-    // Also: if we're vertical and paginating, we may need to wrap sooner
-    // (before we run off the end of the page)
-    if (!aAxisTracker.IsMainAxisHorizontal() &&
-        aAvailableHeightForContent != NS_UNCONSTRAINEDSIZE) {
-      wrapThreshold = std::min(wrapThreshold, aAvailableHeightForContent);
+    // Also: if we're column-oriented and paginating in the block dimension,
+    // we may need to wrap to a new flex line sooner (before we grow past the
+    // available BSize, potentially running off the end of the page).
+    if (aAxisTracker.IsColumnOriented() &&
+        aAvailableBSizeForContent != NS_UNCONSTRAINEDSIZE) {
+      wrapThreshold = std::min(wrapThreshold, aAvailableBSizeForContent);
     }
   }
 
   // Tracks the index of the next strut, in aStruts (and when this hits
   // aStruts.Length(), that means there are no more struts):
   uint32_t nextStrutIdx = 0;
 
   // Overall index of the current flex item in the flex container. (This gets
@@ -3207,33 +3213,33 @@ GetLargestLineMainSize(const FlexLine* a
 }
 
 // Returns the content-box main-size of our flex container, based on the
 // available height (if appropriate) and the main-sizes of the flex items.
 static nscoord
 ClampFlexContainerMainSize(const nsHTMLReflowState& aReflowState,
                            const FlexboxAxisTracker& aAxisTracker,
                            nscoord aUnclampedMainSize,
-                           nscoord aAvailableHeightForContent,
+                           nscoord aAvailableBSizeForContent,
                            const FlexLine* aFirstLine,
                            nsReflowStatus& aStatus)
 {
   MOZ_ASSERT(aFirstLine, "null first line pointer");
 
   if (aAxisTracker.IsMainAxisHorizontal()) {
     // Horizontal case is easy -- our main size should already be resolved
     // before we get a call to Reflow. We don't have to worry about doing
     // page-breaking or shrinkwrapping in the horizontal axis.
     return aUnclampedMainSize;
   }
 
   if (aUnclampedMainSize != NS_INTRINSICSIZE) {
     // Vertical case, with fixed height:
-    if (aAvailableHeightForContent == NS_UNCONSTRAINEDSIZE ||
-        aUnclampedMainSize < aAvailableHeightForContent) {
+    if (aAvailableBSizeForContent == NS_UNCONSTRAINEDSIZE ||
+        aUnclampedMainSize < aAvailableBSizeForContent) {
       // Not in a fragmenting context, OR no need to fragment because we have
       // more available height than we need. Either way, just use our fixed
       // height.  (Note that the reflow state has already done the appropriate
       // min/max-height clamping.)
       return aUnclampedMainSize;
     }
 
     // Fragmenting *and* our fixed height is too tall for available height:
@@ -3241,79 +3247,79 @@ ClampFlexContainerMainSize(const nsHTMLR
     // available height (or the amount of height required by our children, if
     // that's larger; but of course not more than our own computed height).
     // XXXdholbert For now, we don't support pushing children to our next
     // continuation or splitting children, so "amount of height required by
     // our children" is just the main-size (height) of our longest flex line.
     NS_FRAME_SET_INCOMPLETE(aStatus);
     nscoord largestLineOuterSize = GetLargestLineMainSize(aFirstLine);
 
-    if (largestLineOuterSize <= aAvailableHeightForContent) {
-      return aAvailableHeightForContent;
+    if (largestLineOuterSize <= aAvailableBSizeForContent) {
+      return aAvailableBSizeForContent;
     }
     return std::min(aUnclampedMainSize, largestLineOuterSize);
   }
 
   // Vertical case, with auto-height:
   // Resolve auto-height to the largest FlexLine-length, clamped to our
   // computed min/max main-size properties (min-height & max-height).
-  // XXXdholbert Handle constrained-aAvailableHeightForContent case here.
+  // XXXdholbert Handle constrained-aAvailableBSizeForContent case here.
   nscoord largestLineOuterSize = GetLargestLineMainSize(aFirstLine);
   return NS_CSS_MINMAX(largestLineOuterSize,
                        aReflowState.ComputedMinHeight(),
                        aReflowState.ComputedMaxHeight());
 }
 
 nscoord
 nsFlexContainerFrame::ComputeCrossSize(const nsHTMLReflowState& aReflowState,
                                        const FlexboxAxisTracker& aAxisTracker,
                                        nscoord aSumLineCrossSizes,
-                                       nscoord aAvailableHeightForContent,
+                                       nscoord aAvailableBSizeForContent,
                                        bool* aIsDefinite,
                                        nsReflowStatus& aStatus)
 {
   MOZ_ASSERT(aIsDefinite, "outparam pointer must be non-null");
 
   if (aAxisTracker.IsCrossAxisHorizontal()) {
     // Cross axis is horizontal: our cross size is our computed width
     // (which is already resolved).
     *aIsDefinite = true;
     return aReflowState.ComputedISize();
   }
 
   nscoord effectiveComputedBSize = GetEffectiveComputedBSize(aReflowState);
   if (effectiveComputedBSize != NS_INTRINSICSIZE) {
     // Cross-axis is vertical, and we have a fixed height:
     *aIsDefinite = true;
-    if (aAvailableHeightForContent == NS_UNCONSTRAINEDSIZE ||
-        effectiveComputedBSize < aAvailableHeightForContent) {
+    if (aAvailableBSizeForContent == NS_UNCONSTRAINEDSIZE ||
+        effectiveComputedBSize < aAvailableBSizeForContent) {
       // Not in a fragmenting context, OR no need to fragment because we have
       // more available height than we need. Either way, just use our fixed
       // height.  (Note that the reflow state has already done the appropriate
       // min/max-height clamping.)
       return effectiveComputedBSize;
     }
 
     // Fragmenting *and* our fixed height is too tall for available height:
     // Mark incomplete so we get a next-in-flow, and take up all of the
     // available height (or the amount of height required by our children, if
     // that's larger; but of course not more than our own computed height).
     // XXXdholbert For now, we don't support pushing children to our next
     // continuation or splitting children, so "amount of height required by
     // our children" is just our line-height.
     NS_FRAME_SET_INCOMPLETE(aStatus);
-    if (aSumLineCrossSizes <= aAvailableHeightForContent) {
-      return aAvailableHeightForContent;
+    if (aSumLineCrossSizes <= aAvailableBSizeForContent) {
+      return aAvailableBSizeForContent;
     }
     return std::min(effectiveComputedBSize, aSumLineCrossSizes);
   }
 
   // Cross axis is vertical and we have auto-height: shrink-wrap our line(s),
   // subject to our min-size / max-size constraints in that (vertical) axis.
-  // XXXdholbert Handle constrained-aAvailableHeightForContent case here.
+  // XXXdholbert Handle constrained-aAvailableBSizeForContent case here.
   *aIsDefinite = false;
   return NS_CSS_MINMAX(aSumLineCrossSizes,
                        aReflowState.ComputedMinHeight(),
                        aReflowState.ComputedMaxHeight());
 }
 
 void
 FlexLine::PositionItemsInMainAxis(uint8_t aJustifyContent,
@@ -3528,40 +3534,42 @@ nsFlexContainerFrame::Reflow(nsPresConte
     }
   } else {
     SortChildrenIfNeeded<IsOrderLEQWithDOMFallback>();
   }
 
   const FlexboxAxisTracker axisTracker(aReflowState.mStylePosition,
                                        aReflowState.GetWritingMode());
 
-  // If we're being fragmented into a constrained height, subtract off
-  // borderpadding-top from it, to get the available height for our
-  // content box. (Don't subtract if we're skipping top border/padding,
-  // though.)
-  nscoord availableHeightForContent = aReflowState.AvailableHeight();
-  if (availableHeightForContent != NS_UNCONSTRAINEDSIZE &&
-      !GetSkipSides().Top()) {
-    availableHeightForContent -= aReflowState.ComputedPhysicalBorderPadding().top;
-    // (Don't let that push availableHeightForContent below zero, though):
-    availableHeightForContent = std::max(availableHeightForContent, 0);
+  // If we're being fragmented into a constrained BSize, then subtract off
+  // borderpadding BStart from that constrained BSize, to get the available
+  // BSize for our content box. (No need to subtract the borderpadding BStart
+  // if we're already skipping it via GetLogicalSkipSides, though.)
+  nscoord availableBSizeForContent = aReflowState.AvailableBSize();
+  if (availableBSizeForContent != NS_UNCONSTRAINEDSIZE &&
+      !(GetLogicalSkipSides(&aReflowState).BStart())) {
+    WritingMode wm = aReflowState.GetWritingMode();
+    availableBSizeForContent -=
+      aReflowState.ComputedLogicalBorderPadding().BStart(wm);
+    // (Don't let that push availableBSizeForContent below zero, though):
+    availableBSizeForContent = std::max(availableBSizeForContent, 0);
   }
 
   nscoord contentBoxMainSize = GetMainSizeFromReflowState(aReflowState,
                                                           axisTracker);
 
   nsAutoTArray<StrutInfo, 1> struts;
   DoFlexLayout(aPresContext, aDesiredSize, aReflowState, aStatus,
-               contentBoxMainSize, availableHeightForContent,
+               contentBoxMainSize, availableBSizeForContent,
                struts, axisTracker);
 
   if (!struts.IsEmpty()) {
     // We're restarting flex layout, with new knowledge of collapsed items.
     DoFlexLayout(aPresContext, aDesiredSize, aReflowState, aStatus,
-                 contentBoxMainSize, availableHeightForContent,
+                 contentBoxMainSize, availableBSizeForContent,
                  struts, axisTracker);
   }
 }
 
 // RAII class to clean up a list of FlexLines.
 // Specifically, this removes each line from the list, deletes all the
 // FlexItems in its list, and deletes the FlexLine.
 class MOZ_STACK_CLASS AutoFlexLineListClearer
@@ -3590,33 +3598,33 @@ private:
 };
 
 void
 nsFlexContainerFrame::DoFlexLayout(nsPresContext*           aPresContext,
                                    nsHTMLReflowMetrics&     aDesiredSize,
                                    const nsHTMLReflowState& aReflowState,
                                    nsReflowStatus&          aStatus,
                                    nscoord aContentBoxMainSize,
-                                   nscoord aAvailableHeightForContent,
+                                   nscoord aAvailableBSizeForContent,
                                    nsTArray<StrutInfo>& aStruts,
                                    const FlexboxAxisTracker& aAxisTracker)
 {
   aStatus = NS_FRAME_COMPLETE;
 
   LinkedList<FlexLine> lines;
   AutoFlexLineListClearer cleanupLines(lines);
 
   GenerateFlexLines(aPresContext, aReflowState,
                     aContentBoxMainSize,
-                    aAvailableHeightForContent,
+                    aAvailableBSizeForContent,
                     aStruts, aAxisTracker, lines);
 
   aContentBoxMainSize =
     ClampFlexContainerMainSize(aReflowState, aAxisTracker,
-                               aContentBoxMainSize, aAvailableHeightForContent,
+                               aContentBoxMainSize, aAvailableBSizeForContent,
                                lines.getFirst(), aStatus);
 
   for (FlexLine* line = lines.getFirst(); line; line = line->getNext()) {
     line->ResolveFlexibleLengths(aContentBoxMainSize);
   }
 
   // Cross Size Determination - Flexbox spec section 9.4
   // ===================================================
@@ -3666,17 +3674,17 @@ nsFlexContainerFrame::DoFlexLayout(nsPre
     // Now that we've finished with this line's items, size the line itself:
     line->ComputeCrossSizeAndBaseline(aAxisTracker);
     sumLineCrossSizes += line->GetLineCrossSize();
   }
 
   bool isCrossSizeDefinite;
   const nscoord contentBoxCrossSize =
     ComputeCrossSize(aReflowState, aAxisTracker, sumLineCrossSizes,
-                     aAvailableHeightForContent, &isCrossSizeDefinite, aStatus);
+                     aAvailableBSizeForContent, &isCrossSizeDefinite, aStatus);
 
   // Set up state for cross-axis alignment, at a high level (outside the
   // scope of a particular flex line)
   CrossAxisPositionTracker
     crossAxisPosnTracker(lines.getFirst(),
                          aReflowState.mStylePosition->mAlignContent,
                          contentBoxCrossSize, isCrossSizeDefinite,
                          aAxisTracker);
--- a/layout/generic/nsFlexContainerFrame.h
+++ b/layout/generic/nsFlexContainerFrame.h
@@ -81,17 +81,17 @@ protected:
    * to, if we find any visibility:collapse children, and Reflow() does
    * everything before that point.)
    */
   void DoFlexLayout(nsPresContext*           aPresContext,
                     nsHTMLReflowMetrics&     aDesiredSize,
                     const nsHTMLReflowState& aReflowState,
                     nsReflowStatus&          aStatus,
                     nscoord aContentBoxMainSize,
-                    nscoord aAvailableHeightForContent,
+                    nscoord aAvailableBSizeForContent,
                     nsTArray<StrutInfo>& aStruts,
                     const FlexboxAxisTracker& aAxisTracker);
 
   /**
    * Checks whether our child-frame list "mFrames" is sorted, using the given
    * IsLessThanOrEqual function, and sorts it if it's not already sorted.
    *
    * XXXdholbert Once we support pagination, we need to make this function
@@ -146,28 +146,28 @@ protected:
 
   // Creates FlexItems for all of our child frames, arranged in a list of
   // FlexLines.  These are returned by reference in |aLines|. Our actual
   // return value has to be |nsresult|, in case we have to reflow a child
   // to establish its flex base size and that reflow fails.
   void GenerateFlexLines(nsPresContext* aPresContext,
                          const nsHTMLReflowState& aReflowState,
                          nscoord aContentBoxMainSize,
-                         nscoord aAvailableHeightForContent,
+                         nscoord aAvailableBSizeForContent,
                          const nsTArray<StrutInfo>& aStruts,
                          const FlexboxAxisTracker& aAxisTracker,
                          mozilla::LinkedList<FlexLine>& aLines);
 
   nscoord GetMainSizeFromReflowState(const nsHTMLReflowState& aReflowState,
                                      const FlexboxAxisTracker& aAxisTracker);
 
   nscoord ComputeCrossSize(const nsHTMLReflowState& aReflowState,
                            const FlexboxAxisTracker& aAxisTracker,
                            nscoord aSumLineCrossSizes,
-                           nscoord aAvailableHeightForContent,
+                           nscoord aAvailableBSizeForContent,
                            bool* aIsDefinite,
                            nsReflowStatus& aStatus);
 
   void SizeItemInCrossAxis(nsPresContext* aPresContext,
                            const FlexboxAxisTracker& aAxisTracker,
                            nsHTMLReflowState& aChildReflowState,
                            FlexItem& aItem);
 
--- a/layout/generic/nsImageFrame.cpp
+++ b/layout/generic/nsImageFrame.cpp
@@ -1410,16 +1410,27 @@ nsDisplayImage::ComputeInvalidationRegio
       geometry->ShouldInvalidateToSyncDecodeImages()) {
     bool snap;
     aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
   }
 
   nsDisplayImageContainer::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion);
 }
 
+bool
+nsDisplayImage::CanOptimizeToImageLayer(LayerManager* aManager,
+                                        nsDisplayListBuilder* aBuilder)
+{
+  uint32_t flags = aBuilder->ShouldSyncDecodeImages()
+                 ? imgIContainer::FLAG_SYNC_DECODE
+                 : imgIContainer::FLAG_NONE;
+
+  return mImage->IsImageContainerAvailable(aManager, flags);
+}
+
 already_AddRefed<ImageContainer>
 nsDisplayImage::GetContainer(LayerManager* aManager,
                              nsDisplayListBuilder* aBuilder)
 {
   uint32_t flags = aBuilder->ShouldSyncDecodeImages()
                  ? imgIContainer::FLAG_SYNC_DECODE
                  : imgIContainer::FLAG_NONE;
 
@@ -1498,19 +1509,17 @@ nsDisplayImage::GetLayerState(nsDisplayL
       return LAYER_NONE;
     }
   }
 
   uint32_t flags = aBuilder->ShouldSyncDecodeImages()
                  ? imgIContainer::FLAG_SYNC_DECODE
                  : imgIContainer::FLAG_NONE;
 
-  nsRefPtr<ImageContainer> container =
-    mImage->GetImageContainer(aManager, flags);
-  if (!container) {
+  if (!mImage->IsImageContainerAvailable(aManager, flags)) {
     return LAYER_NONE;
   }
 
   return LAYER_ACTIVE;
 }
 
 
 /* virtual */ nsRegion
--- a/layout/generic/nsImageFrame.h
+++ b/layout/generic/nsImageFrame.h
@@ -389,16 +389,19 @@ public:
 
   virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) override;
   virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
                                          const nsDisplayItemGeometry* aGeometry,
                                          nsRegion* aInvalidRegion) override;
   virtual void Paint(nsDisplayListBuilder* aBuilder,
                      nsRenderingContext* aCtx) override;
 
+  virtual bool CanOptimizeToImageLayer(LayerManager* aManager,
+                                       nsDisplayListBuilder* aBuilder) override;
+
   /**
    * Returns an ImageContainer for this image if the image type
    * supports it (TYPE_RASTER only).
    */
   virtual already_AddRefed<ImageContainer> GetContainer(LayerManager* aManager,
                                                         nsDisplayListBuilder* aBuilder) override;
 
   /**
--- a/layout/media/symbols.def.in
+++ b/layout/media/symbols.def.in
@@ -312,20 +312,42 @@ MOZ_XML_StopParser
 _moz_cairo_clip_extents
 _moz_cairo_clip_preserve
 _moz_cairo_close_path
 _moz_cairo_copy_clip_rectangle_list
 _moz_cairo_copy_path
 _moz_cairo_copy_path_flat
 _moz_cairo_create
 _moz_cairo_curve_to
+_moz_cairo_d2d_create_device
+_moz_cairo_d2d_create_device_from_d3d10device
+_moz_cairo_d2d_device_get_device
+_moz_cairo_d2d_get_dc
+_moz_cairo_d2d_get_image_surface_cache_usage
+_moz_cairo_d2d_get_surface_vram_usage
+_moz_cairo_d2d_present_backbuffer
+_moz_cairo_d2d_release_dc
+_moz_cairo_d2d_scroll
+_moz_cairo_d2d_surface_create
+_moz_cairo_d2d_surface_create_for_handle
+_moz_cairo_d2d_surface_create_for_hwnd
+_moz_cairo_d2d_surface_create_for_texture
+_moz_cairo_d2d_surface_get_height
+_moz_cairo_d2d_surface_get_texture
+_moz_cairo_d2d_surface_get_width
 _moz_cairo_debug_reset_static_data
 _moz_cairo_destroy
 _moz_cairo_device_to_user
 _moz_cairo_device_to_user_distance
+_moz_cairo_dwrite_font_face_create_for_dwrite_fontface
+_moz_cairo_dwrite_get_cleartype_rendering_mode
+_moz_cairo_dwrite_scaled_font_allow_manual_show_glyphs
+_moz_cairo_dwrite_scaled_font_get_force_GDI_classic
+_moz_cairo_dwrite_scaled_font_set_force_GDI_classic
+_moz_cairo_dwrite_set_cleartype_params
 _moz_cairo_fill
 _moz_cairo_fill_extents
 _moz_cairo_fill_preserve
 _moz_cairo_font_face_destroy
 _moz_cairo_font_options_create
 _moz_cairo_font_options_destroy
 _moz_cairo_font_options_get_hint_metrics
 _moz_cairo_font_options_set_antialias
@@ -370,16 +392,17 @@ MOZ_XML_StopParser
 _moz_cairo_matrix_rotate
 _moz_cairo_matrix_scale
 _moz_cairo_matrix_transform_distance
 _moz_cairo_matrix_transform_point
 _moz_cairo_matrix_translate
 _moz_cairo_move_to
 _moz_cairo_new_path
 _moz_cairo_new_sub_path
+_moz_cairo_null_surface_create
 _moz_cairo_paint
 _moz_cairo_paint_with_alpha
 _moz_cairo_path_destroy
 _moz_cairo_path_extents
 _moz_cairo_pattern_add_color_stop_rgba
 _moz_cairo_pattern_create_for_surface
 _moz_cairo_pattern_create_linear
 _moz_cairo_pattern_create_radial
@@ -403,16 +426,17 @@ MOZ_XML_StopParser
 _moz_cairo_pdf_surface_create_for_stream
 _moz_cairo_pop_group
 _moz_cairo_pop_group_to_source
 _moz_cairo_push_group
 _moz_cairo_push_group_with_content
 _moz_cairo_rectangle
 _moz_cairo_rectangle_list_destroy
 _moz_cairo_reference
+_moz_cairo_release_device
 _moz_cairo_reset_clip
 _moz_cairo_restore
 _moz_cairo_rotate
 _moz_cairo_save
 _moz_cairo_scale
 _moz_cairo_scaled_font_create
 _moz_cairo_scaled_font_destroy
 _moz_cairo_scaled_font_get_font_matrix
@@ -436,16 +460,17 @@ MOZ_XML_StopParser
 _moz_cairo_set_source_rgba
 _moz_cairo_set_source_surface
 _moz_cairo_show_glyphs
 _moz_cairo_status
 _moz_cairo_status_to_string
 _moz_cairo_stroke
 _moz_cairo_stroke_extents
 _moz_cairo_stroke_preserve
+_moz_cairo_surface_attach_snapshot
 _moz_cairo_surface_create_similar
 _moz_cairo_surface_destroy
 _moz_cairo_surface_finish
 _moz_cairo_surface_flush
 _moz_cairo_surface_get_content
 _moz_cairo_surface_get_device_offset
 _moz_cairo_surface_get_reference_count
 _moz_cairo_surface_get_subpixel_antialiasing
@@ -463,26 +488,32 @@ MOZ_XML_StopParser
 _moz_cairo_tee_surface_add
 _moz_cairo_tee_surface_create
 _moz_cairo_tee_surface_index
 _moz_cairo_transform
 _moz_cairo_translate
 _moz_cairo_user_to_device
 _moz_cairo_user_to_device_distance
 _moz_cairo_win32_font_face_create_for_logfontw_hfont
+_moz_cairo_win32_get_dc_with_clip
+_moz_cairo_win32_get_system_text_quality
 #ifdef NS_PRINTING
 _moz_cairo_win32_printing_surface_create
 #endif
 _moz_cairo_win32_scaled_font_select_font
 _moz_cairo_win32_surface_create
+_moz_cairo_win32_surface_create_with_alpha
 _moz_cairo_win32_surface_create_with_d3dsurface9
 _moz_cairo_win32_surface_create_with_ddb
 _moz_cairo_win32_surface_create_with_dib
 _moz_cairo_win32_surface_get_dc
+_moz_cairo_win32_surface_get_height
 _moz_cairo_win32_surface_get_image
+_moz_cairo_win32_surface_get_width
+_moz_cairo_win32_surface_set_can_convert_to_dib
 #ifdef MOZ_TREE_PIXMAN
 _moz_pixman_image_composite32
 _moz_pixman_image_create_bits
 _moz_pixman_image_set_transform
 _moz_pixman_image_unref
 _moz_pixman_transform_from_pixman_f_transform
 _moz_pixman_transform_invert
 _moz_pixman_region32_reset
@@ -505,47 +536,16 @@ MOZ_XML_StopParser
 _moz_pixman_region32_extents
 _moz_pixman_region32_n_rects
 _moz_pixman_region32_rectangles
 _moz_pixman_region32_equal
 _moz_pixman_region32_selfcheck
 _moz_pixman_region32_reset
 _moz_pixman_region32_clear
 #endif
-cairo_d2d_create_device
-cairo_d2d_create_device_from_d3d10device
-cairo_d2d_device_get_device
-cairo_d2d_get_dc
-cairo_d2d_get_image_surface_cache_usage
-cairo_d2d_get_surface_vram_usage
-cairo_d2d_present_backbuffer
-cairo_d2d_release_dc
-cairo_d2d_scroll
-cairo_d2d_surface_create
-cairo_d2d_surface_create_for_handle
-cairo_d2d_surface_create_for_hwnd
-cairo_d2d_surface_create_for_texture
-cairo_d2d_surface_get_height
-cairo_d2d_surface_get_texture
-cairo_d2d_surface_get_width
-cairo_dwrite_font_face_create_for_dwrite_fontface
-cairo_dwrite_get_cleartype_rendering_mode
-cairo_dwrite_scaled_font_allow_manual_show_glyphs
-cairo_dwrite_scaled_font_get_force_GDI_classic
-cairo_dwrite_scaled_font_set_force_GDI_classic
-cairo_dwrite_set_cleartype_params
-cairo_null_surface_create
-cairo_release_device
-cairo_surface_attach_snapshot
-cairo_win32_get_dc_with_clip
-cairo_win32_get_system_text_quality
-cairo_win32_surface_create_with_alpha
-cairo_win32_surface_get_height
-cairo_win32_surface_get_width
-cairo_win32_surface_set_can_convert_to_dib
 #endif
 hb_blob_create
 hb_blob_destroy
 hb_blob_get_data
 hb_blob_get_empty
 hb_blob_get_length
 hb_blob_reference
 hb_buffer_add_utf16
--- a/layout/reftests/font-face/reftest.list
+++ b/layout/reftests/font-face/reftest.list
@@ -38,37 +38,38 @@ skip-if(B2G||Mulet) HTTP(..) == src-list
 == src-list-data-4.html src-list-data-ref.html
 
 # load with data url vs. font data load
 skip-if(B2G||Mulet) HTTP(..) == src-list-actual-font-ref.html src-list-data-1.html # bug 773482 # Initial mulet triage: parity with B2G/B2G Desktop
 
 # localized full fontnames should *not* match, only English ones (need locale-invariant key)
 skip HTTP(..) == src-list-local-localized.html src-list-local-localized-ref.html # 486787, 486497
 
-# Postscript name lookup only supported on MacOS/Windows currently
-skip-if(B2G||Mulet) fails-if(Android) random-if(gtk2Widget) == src-list-local-ps.html src-list-local-full-ref.html # bug 773482 # Initial mulet triage: parity with B2G/B2G Desktop
+# postscript name lookup
+# fontconfig only supports postscript name lookup from 2.10.92, Android/B2G not supported
+skip-if(B2G||Mulet) fails-if(Android) random-if(gtk2Widget) == src-list-local-ps.html src-list-local-full-ref.html # bug 773482
 # Mac-specific test of 100 weight faces
 random-if(!cocoaWidget) == helveticaneue-ultra.html helveticaneue-ultra-ref.html
 
 HTTP(..) == order-1.html order-1-ref.html
-pref(layout.css.unicode-range.enabled,true) random-if(gtk2Widget) HTTP(..) == order-2.html order-2-ref.html # bug 1056479
-pref(layout.css.unicode-range.enabled,true) random-if(gtk2Widget) HTTP(..) == order-3.html order-3-ref.html # bug 1056479
+pref(layout.css.unicode-range.enabled,true) HTTP(..) == order-2.html order-2-ref.html
+pref(layout.css.unicode-range.enabled,true) HTTP(..) == order-3.html order-3-ref.html
 HTTP(..) == multiple-in-family-1.html multiple-in-family-1-ref.html
 HTTP(..) == multiple-in-family-1b.html multiple-in-family-1-ref.html
 HTTP(..) != multiple-in-family-1.html multiple-in-family-1-notref.html
 HTTP(..) == prop-order-over-rule-order-1a.html prop-order-over-rule-order-2a.html
 HTTP(..) == prop-order-over-rule-order-1b.html prop-order-over-rule-order-2b.html
 HTTP(..) != prop-order-over-rule-order-1a.html prop-order-over-rule-order-1b.html
 skip-if(B2G||Mulet) HTTP(..) == cross-iframe-1.html cross-iframe-1-ref.html # bug 773482 # Initial mulet triage: parity with B2G/B2G Desktop
 
-# unicode-range (Linux implementation - bug 1056479)
-pref(layout.css.unicode-range.enabled,true) random-if(gtk2Widget) HTTP(..) == unicoderange-1.html unicoderange-1-ref.html
-pref(layout.css.unicode-range.enabled,true) random-if(gtk2Widget) HTTP(..) == unicoderange-2.html unicoderange-2-ref.html
-pref(layout.css.unicode-range.enabled,true) random-if(gtk2Widget) HTTP(..) == unicoderange-3.html unicoderange-3-ref.html
-pref(layout.css.unicode-range.enabled,true) random-if(gtk2Widget) HTTP(..) == unicoderange-4.html unicoderange-4-ref.html
+# unicode-range
+pref(layout.css.unicode-range.enabled,true) HTTP(..) == unicoderange-1.html unicoderange-1-ref.html
+pref(layout.css.unicode-range.enabled,true) HTTP(..) == unicoderange-2.html unicoderange-2-ref.html
+pref(layout.css.unicode-range.enabled,true) HTTP(..) == unicoderange-3.html unicoderange-3-ref.html
+pref(layout.css.unicode-range.enabled,true) HTTP(..) == unicoderange-4.html unicoderange-4-ref.html
 
 # Dynamic changes
 # we need to skip these because of the bug that's causing order-2.html to fail
 HTTP(..) == enable-sheet-1.html enable-sheet-1-ref.html
 skip HTTP(..) == enable-sheet-2.html multiple-in-family-1-ref.html
 skip HTTP(..) == enable-sheet-3.html multiple-in-family-1-ref.html
 HTTP(..) == enable-sheet-4.html enable-sheet-4-ref.html
 HTTP(..) == enable-sheet-5.html enable-sheet-4-ref.html
--- a/layout/reftests/font-face/src-list-local-full-quotes.html
+++ b/layout/reftests/font-face/src-list-local-full-quotes.html
@@ -10,28 +10,28 @@ body {
   margin: 50px;
   font-size: 24pt;
 }
 
 /* use full names */
 
 @font-face {
   font-family: test-regular;
-  src: local("Helvetica Neue"), local("Bitstream Vera Sans"), local("Bitstream Vera Sans Roman"), local("Free Sans"), local("SwissA"), local("DejaVu Sans"), local("Arial");
+  src: local("Helvetica Neue"), local("Bitstream Vera Sans"), local("Bitstream Vera Sans Roman"), local("FreeSans"), local("Free Sans"), local("SwissA"), local("DejaVu Sans"), local("Arial");
 }
 
 /* use Helvetica on the Mac, since Futura has no bold face on 10.4, 10.5 */
 @font-face {
   font-family: test-bold;
-  src: local("Helvetica Neue Bold"), local("Bitstream Vera Sans Bold"), local("Free Sans Bold"), local("SwissA Bold"), local("DejaVu Sans Bold"), local("Arial Bold");
+  src: local("Helvetica Neue Bold"), local("Bitstream Vera Sans Bold"), local("FreeSans Bold"), local("Free Sans Bold"), local("SwissA Bold"), local("DejaVu Sans Bold"), local("Arial Bold");
 }
 
 @font-face {
   font-family: test-italic;
-  src: local("Helvetica Neue Italic"), local("Bitstream Vera Sans Oblique"), local("Free Sans Oblique"), local("SwissA Italic"), local("DejaVu Sans Oblique"), local("Arial Italic");
+  src: local("Helvetica Neue Italic"), local("Bitstream Vera Sans Oblique"), local("FreeSans Oblique"), local("Free Sans Oblique"), local("SwissA Italic"), local("DejaVu Sans Oblique"), local("Arial Italic");
 }
 
 .regular { font-family: test-regular, serif; }
 .bold { font-family: test-bold, serif; }
 .italic { font-family: test-italic, serif; }
 
 </style>
 
--- a/layout/reftests/font-face/src-list-local-full.html
+++ b/layout/reftests/font-face/src-list-local-full.html
@@ -10,28 +10,28 @@ body {
   margin: 50px;
   font-size: 24pt;
 }
 
 /* use full names */
 
 @font-face {
   font-family: test-regular;
-  src: local(Helvetica Neue), local(Bitstream Vera Sans), local(Bitstream Vera Sans Roman), local(Free Sans), local(SwissA), local(DejaVu Sans), local(Arial);
+  src: local(Helvetica Neue), local(Bitstream Vera Sans), local(Bitstream Vera Sans Roman), local(FreeSans), local(Free Sans), local(SwissA), local(DejaVu Sans), local(Arial);
 }
 
 /* use Helvetica on the Mac, since Futura has no bold face on 10.4, 10.5 */
 @font-face {
   font-family: test-bold;
-  src: local(Helvetica Neue Bold), local(Bitstream Vera Sans Bold), local(Free Sans Bold), local(SwissA Bold), local(DejaVu Sans Bold), local(Arial Bold);
+  src: local(Helvetica Neue Bold), local(Bitstream Vera Sans Bold), local(FreeSans Bold), local(Free Sans Bold), local(SwissA Bold), local(DejaVu Sans Bold), local(Arial Bold);
 }
 
 @font-face {
   font-family: test-italic;
-  src: local(Helvetica Neue Italic), local(Bitstream Vera Sans Oblique), local(Free Sans Oblique), local(SwissA Italic), local(DejaVu Sans Oblique), local(Arial Italic);
+  src: local(Helvetica Neue Italic), local(Bitstream Vera Sans Oblique), local(FreeSans Oblique), local(Free Sans Oblique), local(SwissA Italic), local(DejaVu Sans Oblique), local(Arial Italic);
 }
 
 .regular { font-family: test-regular, serif; }
 .bold { font-family: test-bold, serif; }
 .italic { font-family: test-italic, serif; }
 
 </style>
 
--- a/layout/reftests/mathml/reftest.list
+++ b/layout/reftests/mathml/reftest.list
@@ -277,17 +277,17 @@ fuzzy-if(d2d,7,1) == menclose-6-updiagon
 == menclose-6-verticalstrike.html menclose-6-ref.html
 == menclose-6-phasorangle.html menclose-6-ref.html
 == mmultiscript-align.html mmultiscript-align-ref.html
 fails-if(winWidget&&!/^Windows\x20NT\x205\.1/.test(http.oscpu)) == subscript-italic-correction.html subscript-italic-correction-ref.html # Windows versions with Cambria Math, bug 961482
 fails-if(B2G||Android||/^Windows\x20NT\x205\.1/.test(http.oscpu)||OSX==1006) == mathvariant-1a.html mathvariant-1a-ref.html # Bug 1010679
 fails-if(B2G||Android||/^Windows\x20NT\x205\.1/.test(http.oscpu)||OSX==1006) == mathvariant-1b.html mathvariant-1b-ref.html # Bug 1010679
 fails-if(B2G||Android||/^Windows\x20NT\x205\.1/.test(http.oscpu)||OSX==1006) == mathvariant-1c.html mathvariant-1c-ref.html # Bug 1010679
 == mathvariant-1d.html mathvariant-1d-ref.html
-fails-if(B2G||Android||/^Windows\x20NT\x205\.1/.test(http.oscpu)||OSX) == mathvariant-2.html mathvariant-2-ref.html # Bugs 1010678, 1010679
+fails-if(B2G||Mulet||Android||/^Windows\x20NT\x205\.1/.test(http.oscpu)||OSX) == mathvariant-2.html mathvariant-2-ref.html # Bugs 1010678, 1010679
 == mathvariant-3.html mathvariant-3-ref.html
 == mathvariant-4.html mathvariant-4-ref.html
 == mathvariant-5.html mathvariant-5-ref.html
 == dtls-1.html dtls-1-ref.html
 == dtls-2.html dtls-2-ref.html
 == dtls-3.html dtls-3-ref.html
 == ssty-1.html ssty-1-ref.html
 == ssty-2.html ssty-2-ref.html
--- a/layout/style/FontFaceSet.cpp
+++ b/layout/style/FontFaceSet.cpp
@@ -131,25 +131,32 @@ JSObject*
 FontFaceSet::WrapObject(JSContext* aContext, JS::Handle<JSObject*> aGivenProto)
 {
   return FontFaceSetBinding::Wrap(aContext, this, aGivenProto);
 }
 
 void
 FontFaceSet::Disconnect()
 {
+  RemoveDOMContentLoadedListener();
+
+  if (mDocument && mDocument->CSSLoader()) {
+    // We're null checking CSSLoader() since FontFaceSet::Disconnect() might be
+    // being called during unlink, at which time the loader amy already have
+    // been unlinked from the document.
+    mDocument->CSSLoader()->RemoveObserver(this);
+  }
+}
+
+void
+FontFaceSet::RemoveDOMContentLoadedListener()
+{
   if (mDocument) {
     mDocument->RemoveSystemEventListener(NS_LITERAL_STRING("DOMContentLoaded"),
                                          this, false);
-    // We're null checking CSSLoader() since FontFaceSet::Disconnect() might be
-    // being called during unlink, at which time the loader amy already have
-    // been unlinked from the document.
-    if (mDocument->CSSLoader()) {
-      mDocument->CSSLoader()->RemoveObserver(this);
-    }
   }
 }
 
 already_AddRefed<Promise>
 FontFaceSet::Load(const nsAString& aFont,
                   const nsAString& aText,
                   ErrorResult& aRv)
 {
@@ -270,17 +277,17 @@ FontFaceSet::Clear()
   mNonRuleFaces.Clear();
   mNonRuleFacesDirty = true;
   mPresContext->RebuildUserFontSet();
   mHasLoadingFontFacesIsDirty = true;
   CheckLoadingFinished();
 }
 
 bool
-FontFaceSet::Delete(FontFace& aFontFace, ErrorResult& aRv)
+FontFaceSet::Delete(FontFace& aFontFace)
 {
   mPresContext->FlushUserFontSet();
 
   if (aFontFace.HasRule()) {
     return false;
   }
 
   bool removed = false;
@@ -1552,17 +1559,17 @@ FontFaceSet::HandleEvent(nsIDOMEvent* aE
 {
   nsString type;
   aEvent->GetType(type);
 
   if (!type.EqualsLiteral("DOMContentLoaded")) {
     return NS_ERROR_FAILURE;
   }
 
-  Disconnect();
+  RemoveDOMContentLoadedListener();
   CheckLoadingFinished();
 
   return NS_OK;
 }
 
 /* static */ bool
 FontFaceSet::PrefEnabled()
 {
--- a/layout/style/FontFaceSet.h
+++ b/layout/style/FontFaceSet.h
@@ -170,17 +170,17 @@ public:
   bool Check(const nsAString& aFont,
              const nsAString& aText,
              mozilla::ErrorResult& aRv);
   mozilla::dom::Promise* GetReady(mozilla::ErrorResult& aRv);
   mozilla::dom::FontFaceSetLoadStatus Status();
 
   FontFaceSet* Add(FontFace& aFontFace, mozilla::ErrorResult& aRv);
   void Clear();
-  bool Delete(FontFace& aFontFace, mozilla::ErrorResult& aRv);
+  bool Delete(FontFace& aFontFace);
   bool Has(FontFace& aFontFace);
   uint32_t Size();
   mozilla::dom::FontFaceSetIterator* Entries();
   mozilla::dom::FontFaceSetIterator* Values();
   void ForEach(JSContext* aCx, FontFaceSetForEachCallback& aCallback,
                JS::Handle<JS::Value> aThisArg,
                mozilla::ErrorResult& aRv);
 
@@ -192,16 +192,18 @@ private:
    */
   bool HasAvailableFontFace(FontFace* aFontFace);
 
   /**
    * Removes any listeners and observers.
    */
   void Disconnect();
 
+  void RemoveDOMContentLoadedListener();
+
   /**
    * Returns whether there might be any pending font loads, which should cause
    * the mReady Promise not to be resolved yet.
    */
   bool MightHavePendingFontLoads();
 
   /**
    * Checks to see whether it is time to replace mReady and dispatch a
new file mode 100644
--- /dev/null
+++ b/layout/style/crashtests/1161320-1.html
@@ -0,0 +1,25 @@
+<!doctype html>
+<html class="reftest-wait">
+<head>
+<meta charset=utf-8>
+<style>
+@keyframes a { }
+body {
+  animation-name: a;
+}
+</style>
+
+<script>
+function boom()
+{
+  var body = document.body;
+  body.style.animationPlayState = 'paused';
+  window.getComputedStyle(body).animationPlayState;
+  body.style.animationPlayState = 'running';
+  document.documentElement.removeAttribute("class");
+}
+</script>
+</head>
+
+<body onload="setTimeout(boom, 100);"></body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/style/crashtests/1161320-2.html
@@ -0,0 +1,25 @@
+<!doctype html>
+<html class="reftest-wait">
+<head>
+<meta charset=utf-8>
+<style>
+@keyframes a { }
+body {
+  animation: a 100s;
+}
+</style>
+
+<script>
+function boom()
+{
+  var anim = document.body.getAnimations()[0];
+  anim.finish();
+  anim.pause();
+  anim.play();
+  document.documentElement.removeAttribute("class");
+}
+</script>
+</head>
+
+<body onload="setTimeout(boom, 100);"></body>
+</html>
--- a/layout/style/crashtests/crashtests.list
+++ b/layout/style/crashtests/crashtests.list
@@ -108,12 +108,14 @@ load 989965-1.html
 load 992333-1.html
 pref(dom.webcomponents.enabled,true) load 1017798-1.html
 load 1028514-1.html
 load 1066089-1.html
 load 1074651-1.html
 pref(dom.webcomponents.enabled,true) load 1089463-1.html
 pref(layout.css.expensive-style-struct-assertions.enabled,true) load 1136010-1.html
 load 1153693-1.html
+load 1161320-1.html
+pref(dom.animations-api.core.enabled,true) load 1161320-2.html
 load 1161366-1.html
 load 1163446-1.html
 load large_border_image_width.html
 load border-image-visited-link.html
--- a/layout/style/nsCSSRuleProcessor.cpp
+++ b/layout/style/nsCSSRuleProcessor.cpp
@@ -484,16 +484,24 @@ protected:
   uint32_t    mElementTagCalls;
   uint32_t    mElementClassCalls;
   uint32_t    mElementIdCalls;
 #endif // RULE_HASH_STATS
 };
 
 RuleHash::RuleHash(bool aQuirksMode)
   : mRuleCount(0),
+    mIdTable(aQuirksMode ? &RuleHash_IdTable_CIOps.ops
+                         : &RuleHash_IdTable_CSOps.ops,
+             sizeof(RuleHashTableEntry)),
+    mClassTable(aQuirksMode ? &RuleHash_ClassTable_CIOps.ops
+                            : &RuleHash_ClassTable_CSOps.ops,
+                sizeof(RuleHashTableEntry)),
+    mTagTable(&RuleHash_TagTable_Ops, sizeof(RuleHashTagTableEntry)),
+    mNameSpaceTable(&RuleHash_NameSpaceTable_Ops, sizeof(RuleHashTableEntry)),
     mUniversalRules(0),
     mEnumList(nullptr), mEnumListSize(0),
     mQuirksMode(aQuirksMode)
 #ifdef RULE_HASH_STATS
     ,
     mUniversalSelectors(0),
     mNameSpaceSelectors(0),
     mTagSelectors(0),
@@ -503,30 +511,16 @@ RuleHash::RuleHash(bool aQuirksMode)
     mElementUniversalCalls(0),
     mElementNameSpaceCalls(0),
     mElementTagCalls(0),
     mElementClassCalls(0),
     mElementIdCalls(0)
 #endif
 {
   MOZ_COUNT_CTOR(RuleHash);
-
-  PL_DHashTableInit(&mIdTable, aQuirksMode ? &RuleHash_IdTable_CIOps.ops
-                                           : &RuleHash_IdTable_CSOps.ops,
-                    sizeof(RuleHashTableEntry));
-
-  PL_DHashTableInit(&mClassTable, aQuirksMode ? &RuleHash_ClassTable_CIOps.ops
-                                              : &RuleHash_ClassTable_CSOps.ops,
-                    sizeof(RuleHashTableEntry));
-
-  PL_DHashTableInit(&mTagTable, &RuleHash_TagTable_Ops,
-                    sizeof(RuleHashTagTableEntry));
-
-  PL_DHashTableInit(&mNameSpaceTable, &RuleHash_NameSpaceTable_Ops,
-                    sizeof(RuleHashTableEntry));
 }
 
 RuleHash::~RuleHash()
 {
   MOZ_COUNT_DTOR(RuleHash);
 #ifdef RULE_HASH_STATS
   printf(
 "RuleHash(%p):\n"
@@ -558,21 +552,16 @@ RuleHash::~RuleHash()
 #endif // PRINT_UNIVERSAL_RULES
 #endif // RULE_HASH_STATS
   // Rule Values are arena allocated no need to delete them. Their destructor
   // isn't doing any cleanup. So we dont even bother to enumerate through
   // the hash tables and call their destructors.
   if (nullptr != mEnumList) {
     delete [] mEnumList;
   }
-  // delete arena for strings and small objects
-  PL_DHashTableFinish(&mIdTable);
-  PL_DHashTableFinish(&mClassTable);
-  PL_DHashTableFinish(&mTagTable);
-  PL_DHashTableFinish(&mNameSpaceTable);
 }
 
 void RuleHash::AppendRuleToTable(PLDHashTable* aTable, const void* aKey,
                                  const RuleSelectorPair& aRuleInfo)
 {
   // Get a new or existing entry.
   RuleHashTableEntry *entry = static_cast<RuleHashTableEntry*>
     (PL_DHashTableAdd(aTable, aKey, fallible));
@@ -861,52 +850,41 @@ static const RuleHashTableOps AtomSelect
 
 //--------------------------------
 
 struct RuleCascadeData {
   RuleCascadeData(nsIAtom *aMedium, bool aQuirksMode)
     : mRuleHash(aQuirksMode),
       mStateSelectors(),
       mSelectorDocumentStates(0),
+      mClassSelectors(aQuirksMode ? &AtomSelector_CIOps.ops
+                                  : &AtomSelector_CSOps,
+                      sizeof(AtomSelectorEntry)),
+      mIdSelectors(aQuirksMode ? &AtomSelector_CIOps.ops
+                               : &AtomSelector_CSOps,
+                   sizeof(AtomSelectorEntry)),
+      // mAttributeSelectors is matching on the attribute _name_, not the
+      // value, and we case-fold names at parse-time, so this is a
+      // case-sensitive match.
+      mAttributeSelectors(&AtomSelector_CSOps, sizeof(AtomSelectorEntry)),
+      mAnonBoxRules(&RuleHash_TagTable_Ops, sizeof(RuleHashTagTableEntry)),
+#ifdef MOZ_XUL
+      mXULTreeRules(&RuleHash_TagTable_Ops, sizeof(RuleHashTagTableEntry)),
+#endif
       mKeyframesRuleTable(),
       mCounterStyleRuleTable(),
       mCacheKey(aMedium),
       mNext(nullptr),
       mQuirksMode(aQuirksMode)
   {
-    // mAttributeSelectors is matching on the attribute _name_, not the value,
-    // and we case-fold names at parse-time, so this is a case-sensitive match.
-    PL_DHashTableInit(&mAttributeSelectors, &AtomSelector_CSOps,
-                      sizeof(AtomSelectorEntry));
-    PL_DHashTableInit(&mAnonBoxRules, &RuleHash_TagTable_Ops,
-                      sizeof(RuleHashTagTableEntry));
-    PL_DHashTableInit(&mIdSelectors,
-                      aQuirksMode ? &AtomSelector_CIOps.ops :
-                                    &AtomSelector_CSOps,
-                      sizeof(AtomSelectorEntry));
-    PL_DHashTableInit(&mClassSelectors,
-                      aQuirksMode ? &AtomSelector_CIOps.ops :
-                                    &AtomSelector_CSOps,
-                      sizeof(AtomSelectorEntry));
     memset(mPseudoElementRuleHashes, 0, sizeof(mPseudoElementRuleHashes));
-#ifdef MOZ_XUL
-    PL_DHashTableInit(&mXULTreeRules, &RuleHash_TagTable_Ops,
-                      sizeof(RuleHashTagTableEntry));
-#endif
   }
 
   ~RuleCascadeData()
   {
-    PL_DHashTableFinish(&mAttributeSelectors);
-    PL_DHashTableFinish(&mAnonBoxRules);
-    PL_DHashTableFinish(&mIdSelectors);
-    PL_DHashTableFinish(&mClassSelectors);
-#ifdef MOZ_XUL
-    PL_DHashTableFinish(&mXULTreeRules);
-#endif
     for (uint32_t i = 0; i < ArrayLength(mPseudoElementRuleHashes); ++i) {
       delete mPseudoElementRuleHashes[i];
     }
   }
 
   size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
 
   RuleHash                 mRuleHash;
@@ -3315,30 +3293,26 @@ struct CascadeEnumData {
                   uint8_t aSheetType)
     : mPresContext(aPresContext),
       mFontFaceRules(aFontFaceRules),
       mKeyframesRules(aKeyframesRules),
       mFontFeatureValuesRules(aFontFeatureValuesRules),
       mPageRules(aPageRules),
       mCounterStyleRules(aCounterStyleRules),
       mCacheKey(aKey),
+      mRulesByWeight(&gRulesByWeightOps, sizeof(RuleByWeightEntry), 32),
       mSheetType(aSheetType)
   {
-    PL_DHashTableInit(&mRulesByWeight, &gRulesByWeightOps,
-                      sizeof(RuleByWeightEntry), 32);
-
     // Initialize our arena
     PL_INIT_ARENA_POOL(&mArena, "CascadeEnumDataArena",
                        NS_CASCADEENUMDATA_ARENA_BLOCK_SIZE);
   }
 
   ~CascadeEnumData()
   {
-    if (mRulesByWeight.IsInitialized())
-      PL_DHashTableFinish(&mRulesByWeight);
     PL_FinishArenaPool(&mArena);
   }
 
   nsPresContext* mPresContext;
   nsTArray<nsFontFaceRuleContainer>& mFontFaceRules;
   nsTArray<nsCSSKeyframesRule*>& mKeyframesRules;
   nsTArray<nsCSSFontFeatureValuesRule*>& mFontFeatureValuesRules;
   nsTArray<nsCSSPageRule*>& mPageRules;
--- a/layout/xul/nsImageBoxFrame.cpp
+++ b/layout/xul/nsImageBoxFrame.cpp
@@ -432,41 +432,77 @@ nsDisplayXULImage::ConfigureLayer(ImageL
 
   const LayoutDevicePoint p = destRect.TopLeft();
   Matrix transform = Matrix::Translation(p.x, p.y);
   transform.PreScale(destRect.Width() / imageWidth,
                      destRect.Height() / imageHeight);
   aLayer->SetBaseTransform(gfx::Matrix4x4::From2D(transform));
 }
 
+bool
+nsDisplayXULImage::CanOptimizeToImageLayer(LayerManager* aManager,
+                                           nsDisplayListBuilder* aBuilder)
+{
+  uint32_t flags = aBuilder->ShouldSyncDecodeImages()
+                 ? imgIContainer::FLAG_SYNC_DECODE
+                 : imgIContainer::FLAG_NONE;
+
+  return static_cast<nsImageBoxFrame*>(mFrame)
+    ->IsImageContainerAvailable(aManager, flags);
+}
+
+bool
+nsImageBoxFrame::IsImageContainerAvailable(LayerManager* aManager,
+                                           uint32_t aFlags)
+{
+  bool hasSubRect = !mUseSrcAttr && (mSubRect.width > 0 || mSubRect.height > 0);
+  if (hasSubRect || !mImageRequest) {
+    return false;
+  }
+
+  nsCOMPtr<imgIContainer> imgCon;
+  mImageRequest->GetImage(getter_AddRefs(imgCon));
+  if (!imgCon) {
+    return false;
+  }
+  
+  return imgCon->IsImageContainerAvailable(aManager, aFlags);
+}
+
 already_AddRefed<ImageContainer>
 nsDisplayXULImage::GetContainer(LayerManager* aManager,
                                 nsDisplayListBuilder* aBuilder)
 {
   uint32_t flags = aBuilder->ShouldSyncDecodeImages()
                  ? imgIContainer::FLAG_SYNC_DECODE
                  : imgIContainer::FLAG_NONE;
 
   return static_cast<nsImageBoxFrame*>(mFrame)->GetContainer(aManager, flags);
 }
 
 already_AddRefed<ImageContainer>
 nsImageBoxFrame::GetContainer(LayerManager* aManager, uint32_t aFlags)
 {
-  bool hasSubRect = !mUseSrcAttr && (mSubRect.width > 0 || mSubRect.height > 0);
-  if (hasSubRect || !mImageRequest) {
+  MOZ_ASSERT(IsImageContainerAvailable(aManager, aFlags),
+             "Should call IsImageContainerAvailable and get true before "
+             "calling GetContainer");
+  if (!mImageRequest) {
+    MOZ_ASSERT_UNREACHABLE("mImageRequest should be available if "
+                           "IsImageContainerAvailable returned true");
     return nullptr;
   }
 
   nsCOMPtr<imgIContainer> imgCon;
   mImageRequest->GetImage(getter_AddRefs(imgCon));
   if (!imgCon) {
+    MOZ_ASSERT_UNREACHABLE("An imgIContainer should be available if "
+                           "IsImageContainerAvailable returned true");
     return nullptr;
   }
-  
+
   return imgCon->GetImageContainer(aManager, aFlags);
 }
 
 
 //
 // DidSetStyleContext
 //
 // When the style context changes, make sure that all of our image is up to date.
--- a/layout/xul/nsImageBoxFrame.h
+++ b/layout/xul/nsImageBoxFrame.h
@@ -91,16 +91,17 @@ public:
                                 const nsDisplayListSet& aLists) override;
 
   virtual ~nsImageBoxFrame();
 
   DrawResult PaintImage(nsRenderingContext& aRenderingContext,
                         const nsRect& aDirtyRect,
                         nsPoint aPt, uint32_t aFlags);
 
+  bool IsImageContainerAvailable(LayerManager* aManager, uint32_t aFlags);
   already_AddRefed<ImageContainer> GetContainer(LayerManager* aManager,
                                                 uint32_t aFlags);
 
 protected:
   explicit nsImageBoxFrame(nsStyleContext* aContext);
 
   virtual void GetImageSize();
 
@@ -137,16 +138,18 @@ public:
     MOZ_COUNT_CTOR(nsDisplayXULImage);
   }
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayXULImage() {
     MOZ_COUNT_DTOR(nsDisplayXULImage);
   }
 #endif
 
+  virtual bool CanOptimizeToImageLayer(LayerManager* aManager,
+                                       nsDisplayListBuilder* aBuilder) override;
   virtual already_AddRefed<ImageContainer> GetContainer(LayerManager* aManager,
                                                         nsDisplayListBuilder* aBuilder) override;
   virtual void ConfigureLayer(ImageLayer* aLayer,
                               const ContainerLayerParameters& aParameters) override;
   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) override
   {
     *aSnap = true;
     return nsRect(ToReferenceFrame(), Frame()->GetSize());
--- a/media/webrtc/signaling/test/common.build
+++ b/media/webrtc/signaling/test/common.build
@@ -118,16 +118,17 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gtk2
     OS_LIBS += CONFIG['XLIBS']
     OS_LIBS += CONFIG['MOZ_GTK2_LIBS']
     OS_LIBS += [
         'gmodule-2.0',
         'gthread-2.0',
     ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gtk3':
+    OS_LIBS += CONFIG['XLIBS']
     OS_LIBS += CONFIG['MOZ_GTK3_LIBS']
     USE_LIBS += [
         'freetype',
     ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'qt':
     OS_LIBS += CONFIG['XLIBS']
     OS_LIBS += CONFIG['TK_LIBS']
--- a/mobile/android/base/gfx/GeckoLayerClient.java
+++ b/mobile/android/base/gfx/GeckoLayerClient.java
@@ -10,16 +10,17 @@ import org.mozilla.gecko.GeckoEvent;
 import org.mozilla.gecko.gfx.LayerView.DrawListener;
 import org.mozilla.gecko.Tab;
 import org.mozilla.gecko.Tabs;
 import org.mozilla.gecko.ZoomConstraints;
 import org.mozilla.gecko.mozglue.RobocopTarget;
 import org.mozilla.gecko.mozglue.generatorannotations.WrapElementForJNI;
 import org.mozilla.gecko.EventDispatcher;
 import org.mozilla.gecko.util.FloatUtils;
+import org.mozilla.gecko.AppConstants;
 
 import android.content.Context;
 import android.graphics.PointF;
 import android.graphics.RectF;
 import android.os.SystemClock;
 import android.util.DisplayMetrics;
 import android.util.Log;
 
@@ -341,16 +342,21 @@ class GeckoLayerClient implements LayerV
                                            fixedMargins.bottom + overscroll.top);
         } else if (overscroll.bottom > 0) {
             fixedMargins.top = Math.min(maxMarginHeight - fixedMargins.bottom,
                                         fixedMargins.top + overscroll.bottom);
         }
     }
 
     private void adjustViewport(DisplayPortMetrics displayPort) {
+        // TODO: APZ For fennec might need margins information to deal with
+        // the dynamic toolbar.
+        if (AppConstants.MOZ_ANDROID_APZ)
+            return;
+
         ImmutableViewportMetrics metrics = getViewportMetrics();
         ImmutableViewportMetrics clampedMetrics = metrics.clamp();
 
         RectF margins = new RectF();
         getFixedMargins(metrics, margins);
         clampedMetrics = clampedMetrics.setMargins(
             margins.left, margins.top, margins.right, margins.bottom);
 
--- a/modules/libpref/Preferences.cpp
+++ b/modules/libpref/Preferences.cpp
@@ -230,20 +230,20 @@ SizeOfObserverEntryExcludingThis(ValueOb
 // Although this is a member of Preferences, it measures sPreferences and
 // several other global structures.
 /* static */ int64_t
 Preferences::SizeOfIncludingThisAndOtherStuff(mozilla::MallocSizeOf aMallocSizeOf)
 {
   NS_ENSURE_TRUE(InitStaticMembers(), 0);
 
   size_t n = aMallocSizeOf(sPreferences);
-  if (gHashTable.IsInitialized()) {
+  if (gHashTable) {
     // pref keys are allocated in a private arena, which we count elsewhere.
     // pref stringvals are allocated out of the same private arena.
-    n += PL_DHashTableSizeOfExcludingThis(&gHashTable, nullptr, aMallocSizeOf);
+    n += PL_DHashTableSizeOfExcludingThis(gHashTable, nullptr, aMallocSizeOf);
   }
   if (gCacheData) {
     n += gCacheData->SizeOfIncludingThis(aMallocSizeOf);
     for (uint32_t i = 0, count = gCacheData->Length(); i < count; ++i) {
       n += aMallocSizeOf((*gCacheData)[i]);
     }
   }
   if (gObserverTable) {
@@ -733,18 +733,18 @@ Preferences::GetPreference(PrefSetting* 
     return;
 
   pref_GetPrefFromEntry(entry, aPref);
 }
 
 void
 Preferences::GetPreferences(InfallibleTArray<PrefSetting>* aPrefs)
 {
-  aPrefs->SetCapacity(gHashTable.Capacity());
-  PL_DHashTableEnumerate(&gHashTable, pref_GetPrefs, aPrefs);
+  aPrefs->SetCapacity(gHashTable->Capacity());
+  PL_DHashTableEnumerate(gHashTable, pref_GetPrefs, aPrefs);
 }
 
 NS_IMETHODIMP
 Preferences::GetBranch(const char *aPrefRoot, nsIPrefBranch **_retval)
 {
   nsresult rv;
 
   if ((nullptr != aPrefRoot) && (*aPrefRoot != '\0')) {
@@ -939,47 +939,48 @@ Preferences::WritePrefFile(nsIFile* aFil
     NS_LINEBREAK
     NS_LINEBREAK;
 
   nsCOMPtr<nsIOutputStream> outStreamSink;
   nsCOMPtr<nsIOutputStream> outStream;
   uint32_t                  writeAmount;
   nsresult                  rv;
 
-  if (!gHashTable.IsInitialized())
+  if (!gHashTable)
     return NS_ERROR_NOT_INITIALIZED;
 
   // execute a "safe" save by saving through a tempfile
   rv = NS_NewSafeLocalFileOutputStream(getter_AddRefs(outStreamSink),
                                        aFile,
                                        -1,
                                        0600);
   if (NS_FAILED(rv)) 
       return rv;
   rv = NS_NewBufferedOutputStream(getter_AddRefs(outStream), outStreamSink, 4096);
   if (NS_FAILED(rv)) 
       return rv;  
 
-  nsAutoArrayPtr<char*> valueArray(new char*[gHashTable.EntryCount()]);
-  memset(valueArray, 0, gHashTable.EntryCount() * sizeof(char*));
+  nsAutoArrayPtr<char*> valueArray(new char*[gHashTable->EntryCount()]);
+  memset(valueArray, 0, gHashTable->EntryCount() * sizeof(char*));
   pref_saveArgs saveArgs;
   saveArgs.prefArray = valueArray;
   saveArgs.saveTypes = SAVE_ALL;
-  
+
   // get the lines that we're supposed to be writing to the file
-  PL_DHashTableEnumerate(&gHashTable, pref_savePref, &saveArgs);
-    
+  PL_DHashTableEnumerate(gHashTable, pref_savePref, &saveArgs);
+
   /* Sort the preferences to make a readable file on disk */
-  NS_QuickSort(valueArray, gHashTable.EntryCount(), sizeof(char *), pref_CompareStrings, nullptr);
-  
+  NS_QuickSort(valueArray, gHashTable->EntryCount(), sizeof(char *),
+               pref_CompareStrings, nullptr);
+
   // write out the file header
   outStream->Write(outHeader, sizeof(outHeader) - 1, &writeAmount);
 
   char** walker = valueArray;
-  for (uint32_t valueIdx = 0; valueIdx < gHashTable.EntryCount(); valueIdx++, walker++) {
+  for (uint32_t valueIdx = 0; valueIdx < gHashTable->EntryCount(); valueIdx++, walker++) {
     if (*walker) {
       outStream->Write(*walker, strlen(*walker), &writeAmount);
       outStream->Write(NS_LINEBREAK, NS_LINEBREAK_LEN, &writeAmount);
       free(*walker);
     }
   }
 
   // tell the safe output stream to overwrite the real prefs file
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -3603,16 +3603,28 @@ pref("ui.panel.default_level_parent", tr
 pref("mousewheel.system_scroll_override_on_root_content.enabled", false);
 
 #if MOZ_WIDGET_GTK == 2
 pref("intl.ime.use_simple_context_on_password_field", true);
 #else
 pref("intl.ime.use_simple_context_on_password_field", false);
 #endif
 
+# enable new platform fontlist for linux on GTK platforms
+# temporary pref to allow flipping back to the existing
+# gfxPangoFontGroup/gfxFontconfigUtils code for handling system fonts
+
+#ifdef MOZ_WIDGET_GTK
+#ifdef RELEASE_BUILD
+pref("gfx.font_rendering.fontconfig.fontlist.enabled", false);
+#else
+pref("gfx.font_rendering.fontconfig.fontlist.enabled", true);
+#endif
+#endif
+
 # XP_UNIX
 #endif
 #endif
 #endif
 
 #if defined(ANDROID) || defined(MOZ_B2G)
 
 pref("font.size.fixed.ar", 12);
--- a/modules/libpref/nsPrefBranch.cpp
+++ b/modules/libpref/nsPrefBranch.cpp
@@ -550,25 +550,25 @@ NS_IMETHODIMP nsPrefBranch::GetChildList
 
   NS_ENSURE_ARG(aStartingAt);
   NS_ENSURE_ARG_POINTER(aCount);
   NS_ENSURE_ARG_POINTER(aChildArray);
 
   *aChildArray = nullptr;
   *aCount = 0;
 
-  if (!gHashTable.IsInitialized())
+  if (!gHashTable->IsInitialized())
     return NS_ERROR_NOT_INITIALIZED;
 
   // this will contain a list of all the pref name strings
   // allocate on the stack for speed
-  
+
   ed.parent = getPrefName(aStartingAt);
   ed.pref_list = &prefArray;
-  PL_DHashTableEnumerate(&gHashTable, pref_enumChild, &ed);
+  PL_DHashTableEnumerate(gHashTable, pref_enumChild, &ed);
 
   // now that we've built up the list, run the callback on
   // all the matching elements
   numPrefs = prefArray.Length();
 
   if (numPrefs) {
     outArray = (char **)moz_xmalloc(numPrefs * sizeof(char *));
     if (!outArray)
--- a/modules/libpref/prefapi.cpp
+++ b/modules/libpref/prefapi.cpp
@@ -63,17 +63,17 @@ matchPrefEntry(PLDHashTable*, const PLDH
     if (prefEntry->key == key) return true;
 
     if (!prefEntry->key || !key) return false;
 
     const char *otherKey = reinterpret_cast<const char*>(key);
     return (strcmp(prefEntry->key, otherKey) == 0);
 }
 
-PLDHashTable        gHashTable;
+PLDHashTable*       gHashTable;
 static PLArenaPool  gPrefNameArena;
 bool                gDirty = false;
 
 static struct CallbackNode* gCallbacks = nullptr;
 static bool         gIsAnyPrefLocked = false;
 // These are only used during the call to pref_DoCallback
 static bool         gCallbacksInProgress = false;
 static bool         gShouldCleanupDeadNodes = false;
@@ -144,19 +144,20 @@ enum {
     kPrefStickyDefault = 4,
 };
 static nsresult pref_HashPref(const char *key, PrefValue value, PrefType type, uint32_t flags);
 
 #define PREF_HASHTABLE_INITIAL_LENGTH   1024
 
 nsresult PREF_Init()
 {
-    if (!gHashTable.IsInitialized()) {
-        PL_DHashTableInit(&gHashTable, &pref_HashTableOps,
-                          sizeof(PrefHashEntry), PREF_HASHTABLE_INITIAL_LENGTH);
+    if (!gHashTable) {
+        gHashTable = new PLDHashTable(&pref_HashTableOps,
+                                      sizeof(PrefHashEntry),
+                                      PREF_HASHTABLE_INITIAL_LENGTH);
 
         PL_INIT_ARENA_POOL(&gPrefNameArena, "PrefNameArena",
                            PREFNAME_ARENA_SIZE);
     }
     return NS_OK;
 }
 
 /* Frees the callback list. */
@@ -177,18 +178,19 @@ void PREF_Cleanup()
     gCallbacks = nullptr;
 
     PREF_CleanupPrefs();
 }
 
 /* Frees up all the objects except the callback list. */
 void PREF_CleanupPrefs()
 {
-    if (gHashTable.IsInitialized()) {
-        PL_DHashTableFinish(&gHashTable);
+    if (gHashTable) {
+        delete gHashTable;
+        gHashTable = nullptr;
         PL_FinishArenaPool(&gPrefNameArena);
     }
 }
 
 // note that this appends to aResult, and does not assign!
 static void str_escape(const char * original, nsAFlatCString& aResult)
 {
     /* JavaScript does not allow quotes, slashes, or line terminators inside
@@ -461,31 +463,31 @@ pref_CompareStrings(const void *v1, cons
     else if (!s2)
         return 1;
     else
         return strcmp(s1, s2);
 }
 
 bool PREF_HasUserPref(const char *pref_name)
 {
-    if (!gHashTable.IsInitialized())
+    if (!gHashTable)
         return false;
 
     PrefHashEntry *pref = pref_HashTableLookup(pref_name);
     if (!pref) return false;
 
     /* convert PREF_HAS_USER_VALUE to bool */
     return (PREF_HAS_USER_VALUE(pref) != 0);
 
 }
 
 nsresult
 PREF_CopyCharPref(const char *pref_name, char ** return_buffer, bool get_default)
 {
-    if (!gHashTable.IsInitialized())
+    if (!gHashTable)
         return NS_ERROR_NOT_INITIALIZED;
 
     nsresult rv = NS_ERROR_UNEXPECTED;
     char* stringVal;
     PrefHashEntry* pref = pref_HashTableLookup(pref_name);
 
     if (pref && (pref->flags & PREF_STRING))
     {
@@ -499,17 +501,17 @@ PREF_CopyCharPref(const char *pref_name,
             rv = NS_OK;
         }
     }
     return rv;
 }
 
 nsresult PREF_GetIntPref(const char *pref_name,int32_t * return_int, bool get_default)
 {
-    if (!gHashTable.IsInitialized())
+    if (!gHashTable)
         return NS_ERROR_NOT_INITIALIZED;
 
     nsresult rv = NS_ERROR_UNEXPECTED;
     PrefHashEntry* pref = pref_HashTableLookup(pref_name);
     if (pref && (pref->flags & PREF_INT))
     {
         if (get_default || PREF_IS_LOCKED(pref) || !PREF_HAS_USER_VALUE(pref))
         {
@@ -523,17 +525,17 @@ nsresult PREF_GetIntPref(const char *pre
             *return_int = pref->userPref.intVal;
         rv = NS_OK;
     }
     return rv;
 }
 
 nsresult PREF_GetBoolPref(const char *pref_name, bool * return_value, bool get_default)
 {
-    if (!gHashTable.IsInitialized())
+    if (!gHashTable)
         return NS_ERROR_NOT_INITIALIZED;
 
     nsresult rv = NS_ERROR_UNEXPECTED;
     PrefHashEntry* pref = pref_HashTableLookup(pref_name);
     //NS_ASSERTION(pref, pref_name);
     if (pref && (pref->flags & PREF_BOOL))
     {
         if (get_default || PREF_IS_LOCKED(pref) || !PREF_HAS_USER_VALUE(pref))
@@ -574,49 +576,49 @@ nsresult
 PREF_DeleteBranch(const char *branch_name)
 {
 #ifndef MOZ_B2G
     MOZ_ASSERT(NS_IsMainThread());
 #endif
 
     int len = (int)strlen(branch_name);
 
-    if (!gHashTable.IsInitialized())
+    if (!gHashTable)
         return NS_ERROR_NOT_INITIALIZED;
 
     /* The following check insures that if the branch name already has a "."
      * at the end, we don't end up with a "..". This fixes an incompatibility
      * between nsIPref, which needs the period added, and nsIPrefBranch which
      * does not. When nsIPref goes away this function should be fixed to
      * never add the period at all.
      */
     nsAutoCString branch_dot(branch_name);
     if ((len > 1) && branch_name[len - 1] != '.')
         branch_dot += '.';
 
-    PL_DHashTableEnumerate(&gHashTable, pref_DeleteItem,
+    PL_DHashTableEnumerate(gHashTable, pref_DeleteItem,
                            (void*) branch_dot.get());
     gDirty = true;
     return NS_OK;
 }
 
 
 nsresult
 PREF_ClearUserPref(const char *pref_name)
 {
-    if (!gHashTable.IsInitialized())
+    if (!gHashTable)
         return NS_ERROR_NOT_INITIALIZED;
 
     PrefHashEntry* pref = pref_HashTableLookup(pref_name);
     if (pref && PREF_HAS_USER_VALUE(pref))
     {
         pref->flags &= ~PREF_USERSET;
 
         if (!(pref->flags & PREF_HAS_DEFAULT)) {
-            PL_DHashTableRemove(&gHashTable, pref_name);
+            PL_DHashTableRemove(gHashTable, pref_name);
         }
 
         pref_DoCallback(pref_name);
         gDirty = true;
     }
     return NS_OK;
 }
 
@@ -642,33 +644,33 @@ pref_ClearUserPref(PLDHashTable *table, 
 
 nsresult
 PREF_ClearAllUserPrefs()
 {
 #ifndef MOZ_B2G
     MOZ_ASSERT(NS_IsMainThread());
 #endif
 
-    if (!gHashTable.IsInitialized())
+    if (!gHashTable)
         return NS_ERROR_NOT_INITIALIZED;
 
     std::vector<std::string> prefStrings;
-    PL_DHashTableEnumerate(&gHashTable, pref_ClearUserPref, static_cast<void*>(&prefStrings));
+    PL_DHashTableEnumerate(gHashTable, pref_ClearUserPref, static_cast<void*>(&prefStrings));
 
     for (std::string& prefString : prefStrings) {
         pref_DoCallback(prefString.c_str());
     }
 
     gDirty = true;
     return NS_OK;
 }
 
 nsresult PREF_LockPref(const char *key, bool lockit)
 {
-    if (!gHashTable.IsInitialized())
+    if (!gHashTable)
         return NS_ERROR_NOT_INITIALIZED;
 
     PrefHashEntry* pref = pref_HashTableLookup(key);
     if (!pref)
         return NS_ERROR_UNEXPECTED;
 
     if (lockit) {
         if (!PREF_IS_LOCKED(pref))
@@ -729,30 +731,30 @@ static void pref_SetValue(PrefValue* exi
 }
 
 PrefHashEntry* pref_HashTableLookup(const void *key)
 {
 #ifndef MOZ_B2G
     MOZ_ASSERT(NS_IsMainThread());
 #endif
 
-    return static_cast<PrefHashEntry*>(PL_DHashTableSearch(&gHashTable, key));
+    return static_cast<PrefHashEntry*>(PL_DHashTableSearch(gHashTable, key));
 }
 
 nsresult pref_HashPref(const char *key, PrefValue value, PrefType type, uint32_t flags)
 {
 #ifndef MOZ_B2G
     MOZ_ASSERT(NS_IsMainThread());
 #endif
 
-    if (!gHashTable.IsInitialized())
+    if (!gHashTable)
         return NS_ERROR_OUT_OF_MEMORY;
 
     PrefHashEntry* pref = static_cast<PrefHashEntry*>
-        (PL_DHashTableAdd(&gHashTable, key, fallible));
+        (PL_DHashTableAdd(gHashTable, key, fallible));
 
     if (!pref)
         return NS_ERROR_OUT_OF_MEMORY;
 
     // new entry, better initialize
     if (!pref->key) {
 
         // initialize the pref entry
@@ -834,18 +836,17 @@ pref_SizeOfPrivateData(MallocSizeOf aMal
         n += aMallocSizeOf(node->domain);
     }
     return n;
 }
 
 PrefType
 PREF_GetPrefType(const char *pref_name)
 {
-    if (gHashTable.IsInitialized())
-    {
+    if (gHashTable) {
         PrefHashEntry* pref = pref_HashTableLookup(pref_name);
         if (pref)
         {
             if (pref->flags & PREF_STRING)
                 return PREF_STRING;
             else if (pref->flags & PREF_INT)
                 return PREF_INT;
             else if (pref->flags & PREF_BOOL)
@@ -856,17 +857,17 @@ PREF_GetPrefType(const char *pref_name)
 }
 
 /* -- */
 
 bool
 PREF_PrefIsLocked(const char *pref_name)
 {
     bool result = false;
-    if (gIsAnyPrefLocked && gHashTable.IsInitialized()) {
+    if (gIsAnyPrefLocked && gHashTable) {
         PrefHashEntry* pref = pref_HashTableLookup(pref_name);
         if (pref && PREF_IS_LOCKED(pref))
             result = true;
     }
 
     return result;
 }
 
--- a/modules/libpref/prefapi_private_data.h
+++ b/modules/libpref/prefapi_private_data.h
@@ -5,18 +5,18 @@
 
 /* Data shared between prefapi.c and nsPref.cpp */
 
 #ifndef prefapi_private_data_h
 #define prefapi_private_data_h
 
 #include "mozilla/MemoryReporting.h"
 
-extern PLDHashTable			gHashTable;
-extern bool                 gDirty;
+extern PLDHashTable* gHashTable;
+extern bool gDirty;
 
 namespace mozilla {
 namespace dom {
 class PrefSetting;
 }
 }
 
 enum pref_SaveTypes { SAVE_NONSHARED, SAVE_SHARED, SAVE_ALL, SAVE_ALL_AND_DEFAULTS };
--- a/netwerk/protocol/ftp/nsFtpConnectionThread.cpp
+++ b/netwerk/protocol/ftp/nsFtpConnectionThread.cpp
@@ -1598,24 +1598,16 @@ nsFtpState::R_opts() {
     // Ignore error code because "OPTS UTF8 ON" is for compatibility of
     // FTP server using IETF draft
     return FTP_S_PWD;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsIRequest methods:
 
-static inline
-uint32_t GetFtpTime()
-{
-    return uint32_t(PR_Now() / PR_USEC_PER_SEC);
-}
-
-uint32_t nsFtpState::mSessionStartTime = GetFtpTime();
-
 nsresult
 nsFtpState::Init(nsFtpChannel *channel)
 {
     // parameter validation
     NS_ASSERTION(channel, "FTP: needs a channel");
 
     mChannel = channel; // a straight ref ptr to the channel
 
--- a/netwerk/protocol/ftp/nsFtpConnectionThread.h
+++ b/netwerk/protocol/ftp/nsFtpConnectionThread.h
@@ -1,15 +1,15 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef __nsFtpState__h_
-#define __nsFtpState__h_
+#ifndef __nsFtpConnectionThread__h_
+#define __nsFtpConnectionThread__h_
 
 #include "nsBaseContentStream.h"
 
 #include "nsString.h"
 #include "nsCOMPtr.h"
 #include "nsIAsyncInputStream.h"
 #include "nsAutoPtr.h"
 #include "nsITransport.h"
@@ -198,18 +198,16 @@ private:
         // ****** other vars
     nsCOMPtr<nsITransport>        mDataTransport;
     nsCOMPtr<nsIAsyncInputStream> mDataStream;
     nsCOMPtr<nsIRequest>    mUploadRequest;
     bool                    mAddressChecked;
     bool                    mServerIsIPv6;
     bool                    mUseUTF8;
 
-    static uint32_t         mSessionStartTime;