Merge mozilla-central to mozilla-inbound. CLOSED TREE
authorCsoregi Natalia <ncsoregi@mozilla.com>
Thu, 06 Dec 2018 17:43:26 +0200
changeset 508763 ab21d327592d969e876ee1c864e3da34f32b20a8
parent 508762 5f5d1c50a34213414f3f6a1f05b575e4f2176daf (current diff)
parent 508745 c6d5f17c0c813ce6b7d7cf959aa5377bbe249652 (diff)
child 508764 65e99e6399b925b8ce7ce17b687096b94bf9f2e1
push id1905
push userffxbld-merge
push dateMon, 21 Jan 2019 12:33:13 +0000
treeherdermozilla-release@c2fca1944d8c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone65.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to mozilla-inbound. CLOSED TREE
browser/components/places/tests/browser/browser_library_warnOnOpen.js
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -743,17 +743,17 @@ var BookmarksEventHandler = {
       closeMenus(aEvent.target);
     }
 
     if (target._placesNode && PlacesUtils.nodeIsContainer(target._placesNode)) {
       // Don't open the root folder in tabs when the empty area on the toolbar
       // is middle-clicked or when a non-bookmark item (except for Open in Tabs)
       // in a bookmarks menupopup is middle-clicked.
       if (target.localName == "menu" || target.localName == "toolbarbutton")
-        PlacesUIUtils.openMultipleLinksInTabs(target._placesNode, aEvent, aView);
+        PlacesUIUtils.openContainerNodeInTabs(target._placesNode, aEvent, aView);
     } else if (aEvent.button == 1) {
       // left-clicks with modifier are already served by onCommand
       this.onCommand(aEvent);
     }
   },
 
   /**
    * Handler for command event for an item in the bookmarks toolbar.
--- a/browser/components/places/PlacesUIUtils.jsm
+++ b/browser/components/places/PlacesUIUtils.jsm
@@ -621,46 +621,36 @@ var PlacesUIUtils = {
     // loadTabs with aReplace set to false.
     browserWindow.gBrowser.loadTabs(urls, {
       inBackground: loadInBackground,
       replace: false,
       triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
     });
   },
 
-  /**
-   * Loads a selected node's or nodes' URLs in tabs,
-   * warning the user when lots of URLs are being opened
-   *
-   * @param {object|array} nodeOrNodes
-   *          Contains the node or nodes that we're opening in tabs
-   * @param {event} event
-   *          The DOM mouse/key event with modifier keys set that track the
-   *          user's preferred destination window or tab.
-   * @param {object} view
-   *          The current view that contains the node or nodes selected for
-   *          opening
-   */
-  openMultipleLinksInTabs(nodeOrNodes, event, view) {
-    let window = view.ownerWindow;
+  openContainerNodeInTabs:
+  function PUIU_openContainerInTabs(aNode, aEvent, aView) {
+    let window = aView.ownerWindow;
+
+    let urlsToOpen = PlacesUtils.getURLsForContainerNode(aNode);
+    if (OpenInTabsUtils.confirmOpenInTabs(urlsToOpen.length, window)) {
+      this._openTabset(urlsToOpen, aEvent, window);
+    }
+  },
+
+  openURINodesInTabs: function PUIU_openURINodesInTabs(aNodes, aEvent, aView) {
+    let window = aView.ownerWindow;
+
     let urlsToOpen = [];
-
-    if (PlacesUtils.nodeIsContainer(nodeOrNodes)) {
-      urlsToOpen = PlacesUtils.getURLsForContainerNode(nodeOrNodes);
-    } else {
-      for (var i = 0; i < nodeOrNodes.length; i++) {
-        // Skip over separators and folders.
-        if (PlacesUtils.nodeIsURI(nodeOrNodes[i])) {
-          urlsToOpen.push({uri: nodeOrNodes[i].uri, isBookmark: PlacesUtils.nodeIsBookmark(nodeOrNodes[i])});
-        }
-      }
+    for (var i = 0; i < aNodes.length; i++) {
+      // Skip over separators and folders.
+      if (PlacesUtils.nodeIsURI(aNodes[i]))
+        urlsToOpen.push({uri: aNodes[i].uri, isBookmark: PlacesUtils.nodeIsBookmark(aNodes[i])});
     }
-    if (OpenInTabsUtils.confirmOpenInTabs(urlsToOpen.length, window)) {
-      this._openTabset(urlsToOpen, event, window);
-    }
+    this._openTabset(urlsToOpen, aEvent, window);
   },
 
   /**
    * Loads the node's URL in the appropriate tab or window given the
    * user's preference specified by modifier keys tracked by a
    * DOM mouse/key event.
    * @param   aNode
    *          An uri result node.
@@ -961,17 +951,17 @@ var PlacesUIUtils = {
                      (event.button == 1 || (event.button == 0 && modifKey)) &&
                      PlacesUtils.hasChildURIs(tree.view.nodeForTreeIndex(cell.row));
 
     if (event.button == 0 && isContainer && !openInTabs) {
       tbo.view.toggleOpenState(cell.row);
     } else if (!mouseInGutter && openInTabs &&
                event.originalTarget.localName == "treechildren") {
       tbo.view.selection.select(cell.row);
-      this.openMultipleLinksInTabs(tree.selectedNode, event, tree);
+      this.openContainerNodeInTabs(tree.selectedNode, event, tree);
     } else if (!mouseInGutter && !isContainer &&
                event.originalTarget.localName == "treechildren") {
       // Clear all other selection since we're loading a link now. We must
       // do this *before* attempting to load the link since openURL uses
       // selection as an indication of which link to load.
       tbo.view.selection.select(cell.row);
       this.openNodeWithEvent(tree.selectedNode, event);
     }
--- a/browser/components/places/content/controller.js
+++ b/browser/components/places/content/controller.js
@@ -641,17 +641,20 @@ PlacesController.prototype = {
    */
   openSelectionInTabs: function PC_openLinksInTabs(aEvent) {
     var node = this._view.selectedNode;
     var nodes = this._view.selectedNodes;
     // In the case of no selection, open the root node:
     if (!node && !nodes.length) {
       node = this._view.result.root;
     }
-    PlacesUIUtils.openMultipleLinksInTabs(node ? node : nodes, aEvent, this._view);
+    if (node && PlacesUtils.nodeIsContainer(node))
+      PlacesUIUtils.openContainerNodeInTabs(node, aEvent, this._view);
+    else
+      PlacesUIUtils.openURINodesInTabs(nodes, aEvent, this._view);
   },
 
   /**
    * Shows the Add Bookmark UI for the current insertion point.
    *
    * @param aType
    *        the type of the new item (bookmark/folder)
    */
--- a/browser/components/places/content/places.js
+++ b/browser/components/places/content/places.js
@@ -348,17 +348,17 @@ var PlacesOrganizer = {
 
     let node = this._places.selectedNode;
     if (node) {
       let middleClick = aEvent.button == 1 && aEvent.detail == 1;
       if (middleClick && PlacesUtils.nodeIsContainer(node)) {
         // The command execution function will take care of seeing if the
         // selection is a folder or a different container type, and will
         // load its contents in tabs.
-        PlacesUIUtils.openMultipleLinksInTabs(node, aEvent, this._places);
+        PlacesUIUtils.openContainerNodeInTabs(node, aEvent, this._places);
       }
     }
   },
 
   /**
    * Handle focus changes on the places list and the current content view.
    */
   updateDetailsPane: function PO_updateDetailsPane() {
@@ -1290,17 +1290,17 @@ var ContentTree = {
       let middleClick = aEvent.button == 1 && aEvent.detail == 1;
       if (PlacesUtils.nodeIsURI(node) && (doubleClick || middleClick)) {
         // Open associated uri in the browser.
         this.openSelectedNode(aEvent);
       } else if (middleClick && PlacesUtils.nodeIsContainer(node)) {
         // The command execution function will take care of seeing if the
         // selection is a folder or a different container type, and will
         // load its contents in tabs.
-        PlacesUIUtils.openMultipleLinksInTabs(node, aEvent, this.view);
+        PlacesUIUtils.openContainerNodeInTabs(node, aEvent, this.view);
       }
     }
   },
 
   onKeyPress: function CT_onKeyPress(aEvent) {
     if (aEvent.keyCode == KeyEvent.DOM_VK_RETURN)
       this.openSelectedNode(aEvent);
   },
--- a/browser/components/places/tests/browser/browser.ini
+++ b/browser/components/places/tests/browser/browser.ini
@@ -68,17 +68,16 @@ skip-if = (verify && debug && (os == 'ma
 [browser_library_middleclick.js]
 [browser_library_new_bookmark.js]
 [browser_library_open_leak.js]
 [browser_library_openFlatContainer.js]
 [browser_library_open_bookmark.js]
 [browser_library_panel_leak.js]
 [browser_library_search.js]
 [browser_library_views_liveupdate.js]
-[browser_library_warnOnOpen.js]
 [browser_markPageAsFollowedLink.js]
 [browser_panelview_bookmarks_delete.js]
 [browser_paste_bookmarks.js]
 subsuite = clipboard
 [browser_paste_into_tags.js]
 [browser_paste_resets_cut_highlights.js]
 subsuite = clipboard
 [browser_remove_bookmarks.js]
deleted file mode 100644
--- a/browser/components/places/tests/browser/browser_library_warnOnOpen.js
+++ /dev/null
@@ -1,140 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/*
- * Bug 1435562 - Test that browser.tabs.warnOnOpen is respected when
- * opening multiple items from the Library. */
-
-"use strict";
-
-var gLibrary = null;
-
-add_task(async function setup() {
-  // Temporarily disable history, so we won't record pages navigation.
-  await SpecialPowers.pushPrefEnv({set: [
-    ["places.history.enabled", false],
-  ]});
-
-  // Open Library window.
-  gLibrary = await promiseLibrary();
-
-  registerCleanupFunction(async () => {
-    // We must close "Other Bookmarks" ready for other tests.
-    gLibrary.PlacesOrganizer.selectLeftPaneBuiltIn("UnfiledBookmarks");
-    gLibrary.PlacesOrganizer._places.selectedNode.containerOpen = false;
-
-    await PlacesUtils.bookmarks.eraseEverything();
-
-    // Close Library window.
-    await promiseLibraryClosed(gLibrary);
-  });
-});
-
-add_task(async function test_warnOnOpenFolder() {
-  // Generate a list of links larger than browser.tabs.maxOpenBeforeWarn
-  const MAX_LINKS = 16;
-  let children = [];
-  for (let i = 0; i < MAX_LINKS; i++) {
-    children.push({
-      title: `Folder Target ${i}`,
-      url: `http://example${i}.com`,
-    });
-  }
-
-  // Create a new folder containing our links.
-  await PlacesUtils.bookmarks.insertTree({
-    guid: PlacesUtils.bookmarks.unfiledGuid,
-    children: [{
-      title: "bigFolder",
-      type: PlacesUtils.bookmarks.TYPE_FOLDER,
-      children,
-    }],
-  });
-  info("Pushed test folder into the bookmarks tree");
-
-  // Select unsorted bookmarks root in the left pane.
-  gLibrary.PlacesOrganizer.selectLeftPaneBuiltIn("UnfiledBookmarks");
-  info("Got selection in the Library left pane");
-
-  // Get our bookmark in the right pane.
-  gLibrary.ContentTree.view.view.nodeForTreeIndex(0);
-  info("Got bigFolder in the right pane");
-
-  gLibrary.PlacesOrganizer._places.selectedNode.containerOpen = true;
-
-  // Middle-click on folder (opens all links in folder) and then cancel opening in the dialog
-  let promiseLoaded = BrowserTestUtils.promiseAlertDialog("cancel");
-  let bookmarkedNode = gLibrary.PlacesOrganizer._places.selectedNode.getChild(0);
-  mouseEventOnCell(gLibrary.PlacesOrganizer._places,
-    gLibrary.PlacesOrganizer._places.view.treeIndexForNode(bookmarkedNode),
-    0,
-    { button: 1 });
-
-  await promiseLoaded;
-
-  Assert.ok(true, "Expected dialog was shown when attempting to open folder with lots of links");
-
-  await PlacesUtils.bookmarks.eraseEverything();
-});
-
-add_task(async function test_warnOnOpenLinks() {
-  // Generate a list of links larger than browser.tabs.maxOpenBeforeWarn
-  const MAX_LINKS = 16;
-  let children = [];
-  for (let i = 0; i < MAX_LINKS; i++) {
-    children.push({
-      title: `Highlighted Target ${i}`,
-      url: `http://example${i}.com`,
-    });
-  }
-
-  // Insert the links into the tree
-  await PlacesUtils.bookmarks.insertTree({
-    guid: PlacesUtils.bookmarks.toolbarGuid,
-    children,
-  });
-  info("Pushed test folder into the bookmarks tree");
-
-  gLibrary.PlacesOrganizer.selectLeftPaneBuiltIn("BookmarksToolbar");
-  info("Got selection in the Library left pane");
-
-  // Select all the links
-  gLibrary.ContentTree.view.selectAll();
-
-  let placesContext = gLibrary.document.getElementById("placesContext");
-  let promiseContextMenu = BrowserTestUtils.waitForEvent(placesContext, "popupshown");
-
-  // Open up the context menu and select "Open All In Tabs" (the first item in the list)
-  synthesizeClickOnSelectedTreeCell(gLibrary.ContentTree.view, {
-    button: 2,
-    type: "contextmenu",
-  });
-
-  await promiseContextMenu;
-  info("Context menu opened as expected");
-
-  let openTabs = gLibrary.document.getElementById("placesContext_openLinks:tabs");
-  let promiseLoaded = BrowserTestUtils.promiseAlertDialog("cancel");
-
-  EventUtils.synthesizeMouseAtCenter(openTabs, {}, gLibrary);
-
-  await promiseLoaded;
-
-  Assert.ok(true, "Expected dialog was shown when attempting to open lots of selected links");
-
-  await PlacesUtils.bookmarks.eraseEverything();
-});
-
-function mouseEventOnCell(aTree, aRowIndex, aColumnIndex, aEventDetails) {
-  var selection = aTree.view.selection;
-  selection.select(aRowIndex);
-  aTree.treeBoxObject.ensureRowIsVisible(aRowIndex);
-  var column = aTree.columns[aColumnIndex];
-
-  // get cell coordinates
-  var rect = aTree.treeBoxObject.getCoordsForCellItem(aRowIndex, column, "text");
-
-  EventUtils.synthesizeMouse(aTree.body, rect.x, rect.y,
-    aEventDetails, gLibrary);
-}
--- a/browser/components/places/tests/browser/head.js
+++ b/browser/components/places/tests/browser/head.js
@@ -62,17 +62,17 @@ function promiseLibraryClosed(organizer)
 function promiseClipboard(aPopulateClipboardFn, aFlavor) {
   return new Promise((resolve, reject) => {
     waitForClipboard(data => !!data, aPopulateClipboardFn, resolve, reject, aFlavor);
   });
 }
 
 function synthesizeClickOnSelectedTreeCell(aTree, aOptions) {
   let tbo = aTree.treeBoxObject;
-  if (tbo.view.selection.count < 1)
+  if (tbo.view.selection.count != 1)
      throw new Error("The test node should be successfully selected");
   // Get selection rowID.
   let min = {}, max = {};
   tbo.view.selection.getRangeAt(0, min, max);
   let rowID = min.value;
   tbo.ensureRowIsVisible(rowID);
   // Calculate the click coordinates.
   var rect = tbo.getCoordsForCellItem(rowID, aTree.columns[0], "text");
--- a/devtools/client/framework/components/ToolboxTab.js
+++ b/devtools/client/framework/components/ToolboxTab.js
@@ -21,23 +21,24 @@ class ToolboxTab extends Component {
     };
   }
 
   constructor(props) {
     super(props);
     this.renderIcon = this.renderIcon.bind(this);
   }
 
-  renderIcon(definition, isHighlighted) {
+  renderIcon(definition) {
     const {icon} = definition;
     if (!icon) {
       return [];
     }
     return [
       img({
+        alt: "",
         src: icon,
       }),
     ];
   }
 
   render() {
     const {panelDefinition, currentToolId, highlightedTools, selectTool,
            focusedButton, focusButton} = this.props;
@@ -69,17 +70,17 @@ class ToolboxTab extends Component {
           }
         },
       },
       span(
         {
           className: "devtools-tab-line",
         }
       ),
-      ...this.renderIcon(panelDefinition, isHighlighted),
+      ...this.renderIcon(panelDefinition),
       iconOnly ?
         null :
         span(
           {
             className: "devtools-tab-label",
           },
           label,
           badge && !isHighlighted ?
--- a/devtools/client/inspector/rules/test/browser_rules_cycle-color.js
+++ b/devtools/client/inspector/rules/test/browser_rules_cycle-color.js
@@ -10,111 +10,147 @@ const TEST_URI = `
   <style type="text/css">
     body {
       color: #f00;
     }
     span {
       color: blue;
       border-color: #ff000080;
     }
+    div {
+      color: green;
+    }
   </style>
-  <body><span>Test</span> cycling color types in the rule view!</body>
+  <body>
+    <span>Test</span>
+    <div>cycling color types in the rule view!</div>
+  </body>
 `;
 
 add_task(async function() {
   await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
-  const {inspector, view} = await openRuleView();
-  const container = getRuleViewProperty(view, "body", "color").valueSpan;
-  await checkColorCycling(container, view);
+  const { inspector, view } = await openRuleView();
+
+  await checkColorCycling(view);
   await checkAlphaColorCycling(inspector, view);
   await checkColorCyclingPersist(inspector, view);
+  await checkColorCyclingWithDifferentDefaultType(inspector, view);
 });
 
-async function checkColorCycling(container, view) {
-  const valueNode = container.querySelector(".ruleview-color");
-  const win = view.styleWindow;
+async function checkColorCycling(view) {
+  const { valueSpan } = getRuleViewProperty(view, "body", "color");
 
-  // Hex
-  is(valueNode.textContent, "#f00", "Color displayed as a hex value.");
+  checkColorValue(valueSpan, "#f00", "Color displayed as a hex value, its authored type");
 
-  const tests = [{
+  await runSwatchShiftClickTests(view, valueSpan, [{
     value: "hsl(0, 100%, 50%)",
-    comment: "Color displayed as an HSL value.",
+    comment: "Color displayed as an HSL value",
   }, {
     value: "rgb(255, 0, 0)",
-    comment: "Color displayed as an RGB value.",
+    comment: "Color displayed as an RGB value",
   }, {
     value: "red",
-    comment: "Color displayed as a color name.",
+    comment: "Color displayed as a color name",
   }, {
     value: "#f00",
-    comment: "Color displayed as an authored value.",
+    comment: "Color displayed as an authored value",
   }, {
     value: "hsl(0, 100%, 50%)",
-    comment: "Color displayed as an HSL value again.",
-  }];
-
-  for (const test of tests) {
-    await checkSwatchShiftClick(container, win, test.value, test.comment);
-  }
+    comment: "Color displayed as an HSL value again",
+  }]);
 }
 
 async function checkAlphaColorCycling(inspector, view) {
   await selectNode("span", inspector);
-  const container = getRuleViewProperty(view, "span", "border-color").valueSpan;
-  const valueNode = container.querySelector(".ruleview-color");
-  const win = view.styleWindow;
+  const { valueSpan } = getRuleViewProperty(view, "span", "border-color");
 
-  is(valueNode.textContent, "#ff000080",
-    "Color displayed as an alpha hex value.");
+  checkColorValue(valueSpan, "#ff000080",
+    "Color displayed as an alpha hex value, its authored type");
 
-  const tests = [{
+  await runSwatchShiftClickTests(view, valueSpan, [{
     value: "hsla(0, 100%, 50%, 0.5)",
-    comment: "Color displayed as an HSLa value.",
+    comment: "Color displayed as an HSLa value",
   }, {
     value: "rgba(255, 0, 0, 0.5)",
-    comment: "Color displayed as an RGBa value.",
+    comment: "Color displayed as an RGBa value",
   }, {
     value: "#ff000080",
-    comment: "Color displayed as an alpha hex value again.",
-  }];
-
-  for (const test of tests) {
-    await checkSwatchShiftClick(container, win, test.value, test.comment);
-  }
+    comment: "Color displayed as an alpha hex value again",
+  }]);
 }
 
 async function checkColorCyclingPersist(inspector, view) {
   await selectNode("span", inspector);
-  let container = getRuleViewProperty(view, "span", "color").valueSpan;
-  let valueNode = container.querySelector(".ruleview-color");
-  const win = view.styleWindow;
+  let { valueSpan } = getRuleViewProperty(view, "span", "color");
 
-  is(valueNode.textContent, "blue", "Color displayed as a color name.");
+  checkColorValue(valueSpan, "blue", "Color displayed as color name, its authored type");
 
-  await checkSwatchShiftClick(container, win, "#00f",
-    "Color displayed as a hex value.");
+  await checkSwatchShiftClick(view, valueSpan, "#00f", "Color displayed as a hex value");
 
-  // Select the body and reselect the span to see
-  // if the new color unit persisted
+  info("Select the body and reselect the span to see if the new color unit persisted");
   await selectNode("body", inspector);
   await selectNode("span", inspector);
 
-  // We have to query for the container and the swatch because
-  // they've been re-generated
-  container = getRuleViewProperty(view, "span", "color").valueSpan;
-  valueNode = container.querySelector(".ruleview-color");
-  is(valueNode.textContent, "#00f",
-    "Color  is still displayed as a hex value.");
+  // We have to query for the value span and the swatch again because they've been
+  // re-generated.
+  ({ valueSpan } = getRuleViewProperty(view, "span", "color"));
+  checkColorValue(valueSpan, "#00f", "Color is still displayed as a hex value");
 }
 
-async function checkSwatchShiftClick(container, win, expectedValue, comment) {
-  const swatch = container.querySelector(".ruleview-colorswatch");
-  const valueNode = container.querySelector(".ruleview-color");
+async function checkColorCyclingWithDifferentDefaultType(inspector, view) {
+  info("Change the default color type pref to hex");
+  await pushPref("devtools.defaultColorUnit", "hex");
+
+  info("Select a new node that would normally have a color with a different type");
+  await selectNode("div", inspector);
+  const { valueSpan } = getRuleViewProperty(view, "div", "color");
+
+  checkColorValue(valueSpan, "#008000",
+    "Color displayed as a hex value, which is the type just selected");
 
-  const onUnitChange = swatch.once("unit-change");
-  EventUtils.synthesizeMouseAtCenter(swatch, {
+  info("Cycle through color types again");
+  await runSwatchShiftClickTests(view, valueSpan, [{
+    value: "hsl(120, 100%, 25.1%)",
+    comment: "Color displayed as an HSL value",
+  }, {
+    value: "rgb(0, 128, 0)",
+    comment: "Color displayed as an RGB value",
+  }, {
+    value: "green",
+    comment: "Color displayed as a color name",
+  }, {
+    value: "#008000",
+    comment: "Color displayed as an authored value",
+  }, {
+    value: "hsl(120, 100%, 25.1%)",
+    comment: "Color displayed as an HSL value again",
+  }]);
+}
+
+async function runSwatchShiftClickTests(view, valueSpan, tests) {
+  for (const { value, comment } of tests) {
+    await checkSwatchShiftClick(view, valueSpan, value, comment);
+  }
+}
+
+async function checkSwatchShiftClick(view, valueSpan, expectedValue, comment) {
+  const swatchNode = valueSpan.querySelector(".ruleview-colorswatch");
+  const colorNode = valueSpan.querySelector(".ruleview-color");
+
+  info("Shift-click the color swatch and wait for the color type and ruleview to update");
+  const onRuleViewChanged = view.once("ruleview-changed");
+  const onUnitChange = swatchNode.once("unit-change");
+
+  EventUtils.synthesizeMouseAtCenter(swatchNode, {
     type: "mousedown",
     shiftKey: true,
-  }, win);
+  }, view.styleWindow);
+
   await onUnitChange;
-  is(valueNode.textContent, expectedValue, comment);
+  await onRuleViewChanged;
+
+  is(colorNode.textContent, expectedValue, comment);
 }
+
+function checkColorValue(valueSpan, expectedColorValue, comment) {
+  const colorNode = valueSpan.querySelector(".ruleview-color");
+  is(colorNode.textContent, expectedColorValue, comment);
+}
--- a/devtools/client/inspector/rules/views/text-property-editor.js
+++ b/devtools/client/inspector/rules/views/text-property-editor.js
@@ -391,16 +391,18 @@ TextPropertyEditor.prototype = {
       colorClass: "ruleview-color",
       colorSwatchClass: SHARED_SWATCH_CLASS + " " + COLOR_SWATCH_CLASS,
       filterClass: "ruleview-filter",
       filterSwatchClass: SHARED_SWATCH_CLASS + " " + FILTER_SWATCH_CLASS,
       flexClass: "ruleview-flex",
       gridClass: "ruleview-grid",
       shapeClass: "ruleview-shape",
       shapeSwatchClass: SHARED_SWATCH_CLASS + " " + SHAPE_SWATCH_CLASS,
+      // Only ask the parser to convert colors to the default color type specified by the
+      // user if the property hasn't been changed yet.
       defaultColorType: !propDirty,
       urlClass: "theme-link",
       fontFamilyClass: FONT_FAMILY_CLASS,
       baseURI: this.sheetHref,
       unmatchedVariableClass: "ruleview-unmatched-variable",
       matchedVariableClass: "ruleview-variable",
       isVariableInUse: varName => this.rule.elementStyle.getVariable(varName),
     };
--- a/devtools/client/inspector/shared/test/browser_styleinspector_output-parser.js
+++ b/devtools/client/inspector/shared/test/browser_styleinspector_output-parser.js
@@ -310,17 +310,16 @@ add_task(async function() {
     const data = TEST_DATA[i];
     info("Output-parser test data " + i + ". {" + data.name + " : " +
       data.value + ";}");
     data.test(parser.parseCssProperty(data.name, data.value, {
       colorClass: COLOR_CLASS,
       urlClass: URL_CLASS,
       bezierClass: CUBIC_BEZIER_CLASS,
       angleClass: ANGLE_CLASS,
-      defaultColorType: false,
     }));
   }
 });
 
 function countAll(fragment) {
   return fragment.querySelectorAll("*").length;
 }
 function countColors(fragment) {
--- a/devtools/client/shared/output-parser.js
+++ b/devtools/client/shared/output-parser.js
@@ -1221,20 +1221,25 @@ OutputParser.prototype = {
           style: "background-color:" + color,
         });
         this.colorSwatches.set(swatch, colorObj);
         swatch.addEventListener("mousedown", this._onColorSwatchMouseDown);
         EventEmitter.decorate(swatch);
         container.appendChild(swatch);
       }
 
-      if (options.defaultColorType) {
-        color = colorObj.toString();
-        container.dataset.colorĀ = color;
+      if (!options.defaultColorType) {
+        // If we're not being asked to convert the color to the default color type
+        // specified by the user, then force the CssColor instance to be set to the type
+        // of the current color.
+        // Not having a type means that the default color type will be automatically used.
+        colorObj.colorUnit = colorUtils.classifyColor(color);
       }
+      color = colorObj.toString();
+      container.dataset.colorĀ = color;
 
       const value = this._createNode("span", {
         class: options.colorClass,
       }, color);
 
       container.appendChild(value);
       this.parsed.push(container);
     } else {
--- a/devtools/server/tests/unit/test_blackboxing-05.js
+++ b/devtools/server/tests/unit/test_blackboxing-05.js
@@ -36,17 +36,17 @@ const BLACK_BOXED_URL = "http://example.
 const SOURCE_URL = "http://example.com/source.js";
 
 function test_black_box() {
   gClient.addOneTimeListener("paused", test_black_box_exception);
 
   /* eslint-disable no-multi-spaces, no-unreachable, no-undef */
   Cu.evalInSandbox(
     "" + function doStuff(k) {                                   // line 1
-      throw new Error("wu tang clan ain't nuthin' ta fuck wit"); // line 2
+      throw new Error("error msg");                              // line 2
       k(100);                                                    // line 3
     },                                                           // line 4
     gDebuggee,
     "1.8",
     BLACK_BOXED_URL,
     1
   );
 
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -3574,16 +3574,19 @@ void nsIDocument::SetHeaderData(nsAtom* 
     if (!aData.IsEmpty() && !found) {
       // didn't find, append
       *lastPtr = new nsDocHeaderData(aHeaderField, aData);
     }
   }
 
   if (aHeaderField == nsGkAtoms::headerContentLanguage) {
     CopyUTF16toUTF8(aData, mContentLanguage);
+    if (auto* presContext = GetPresContext()) {
+      presContext->ContentLanguageChanged();
+    }
   }
 
   if (aHeaderField == nsGkAtoms::headerDefaultStyle) {
     SetPreferredStyleSheetSet(aData);
   }
 
   if (aHeaderField == nsGkAtoms::refresh) {
     // We get into this code before we have a script global yet, so get to
--- a/dom/xslt/tests/XSLTMark/XSLTMark.xul
+++ b/dom/xslt/tests/XSLTMark/XSLTMark.xul
@@ -12,17 +12,17 @@
         orient="vertical">
 <script type="application/x-javascript" src="XSLTMark-static.js" />
 <script type="application/x-javascript" src="XSLTMark-test.js" />
 <script type="application/x-javascript" src="XSLTMark-view.js" />
 
 <hbox>
   <groupbox orient="horizontal">
     <caption label="test description file" />
-    <label value=""/><!-- needed, otherwise groupbox fucks up :-( -->
+    <label value=""/><!-- needed, otherwise groupbox is broken :-( -->
     <textbox id="config" persist="value" readonly="true"/>
     <button label="browse..." oncommand="view.browseForConfig();" />
   </groupbox>
   <groupbox orient="horizontal">
     <caption label="test control" />
     <button label="run..."
             oncommand="setTimeout('view.runBenchmark();', 0);" />
     <button label="stop" oncommand="view.onStop();" />
--- a/gfx/webrender_bindings/revision.txt
+++ b/gfx/webrender_bindings/revision.txt
@@ -1,1 +1,1 @@
-7c4162c581978d1a72ed2271a94382290855e227
+8a6a53883bc6fe9522730e09b916f4023ee10d51
--- a/gfx/wr/webrender/src/render_backend.rs
+++ b/gfx/wr/webrender/src/render_backend.rs
@@ -1105,20 +1105,20 @@ impl RenderBackend {
         if !blobs_to_rasterize.is_empty() {
             let (blob_rasterizer, blob_requests) = self.resource_cache
                 .create_blob_scene_builder_requests(&blobs_to_rasterize);
 
             txn.blob_requests = blob_requests;
             txn.blob_rasterizer = blob_rasterizer;
         }
 
-        if !transaction_msg.use_scene_builder_thread && txn.can_skip_scene_builder() {
-            if let Some(rasterizer) = txn.blob_rasterizer.take() {
-                self.resource_cache.set_blob_rasterizer(rasterizer);
-            }
+        if !transaction_msg.use_scene_builder_thread &&
+            txn.can_skip_scene_builder() &&
+            txn.blob_rasterizer.is_none() {
+
             self.update_document(
                 txn.document_id,
                 replace(&mut txn.resource_updates, Vec::new()),
                 None,
                 replace(&mut txn.frame_ops, Vec::new()),
                 replace(&mut txn.notifications, Vec::new()),
                 txn.render_frame,
                 txn.invalidate_rendered_frame,
--- a/gfx/wr/webrender/src/resource_cache.rs
+++ b/gfx/wr/webrender/src/resource_cache.rs
@@ -1077,17 +1077,17 @@ impl ResourceCache {
             }
         }
     }
 
     pub fn create_blob_scene_builder_requests(
         &mut self,
         keys: &[BlobImageKey]
     ) -> (Option<Box<AsyncBlobImageRasterizer>>, Vec<BlobImageParams>) {
-        if self.blob_image_handler.is_none() {
+        if self.blob_image_handler.is_none() || keys.is_empty() {
             return (None, Vec::new());
         }
 
         let mut blob_request_params = Vec::new();
         for key in keys {
             let template = self.blob_image_templates.get_mut(key).unwrap();
 
             if let Some(tile_size) = template.tiling {
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -1715,16 +1715,21 @@ void nsPresContext::CacheAllLangs() {
     GetDefaultFont(kPresContext_DefaultVariableFont_ID, nsGkAtoms::Unicode);
     for (auto iter = mLanguagesUsed.Iter(); !iter.Done(); iter.Next()) {
       GetDefaultFont(kPresContext_DefaultVariableFont_ID, iter.Get()->GetKey());
     }
   }
   mFontGroupCacheDirty = false;
 }
 
+void nsPresContext::ContentLanguageChanged() {
+  mFontGroupCacheDirty = true;
+  PostRebuildAllStyleDataEvent(nsChangeHint(0), eRestyle_ForceDescendants);
+}
+
 void nsPresContext::RebuildAllStyleData(nsChangeHint aExtraHint,
                                         nsRestyleHint aRestyleHint) {
   if (!mShell) {
     // We must have been torn down. Nothing to do here.
     return;
   }
 
   // FIXME(emilio): Why is it safe to reset mUsesRootEMUnits / mUsesEXChUnits
--- a/layout/base/nsPresContext.h
+++ b/layout/base/nsPresContext.h
@@ -268,16 +268,18 @@ class nsPresContext : public nsISupports
   void RebuildAllStyleData(nsChangeHint aExtraHint, nsRestyleHint aRestyleHint);
   /**
    * Just like RebuildAllStyleData, except (1) asynchronous and (2) it
    * doesn't rebuild the user font set.
    */
   void PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint,
                                     nsRestyleHint aRestyleHint);
 
+  void ContentLanguageChanged();
+
   /**
    * Handle changes in the values of media features (used in media
    * queries).
    *
    * There are three sensible values to use for aRestyleHint:
    *  * nsRestyleHint(0) to rebuild style data, with rerunning of
    *    selector matching, only if media features have changed
    *  * eRestyle_ForceDescendants to force rebuilding of style data (but
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/1511570-ref.html
@@ -0,0 +1,3 @@
+<!doctype html>
+<meta http-equiv="Content-Language" content="zh-CN">
+<p style="font-family: sans-serif">Some test in the default font for zh-CN.
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/1511570.html
@@ -0,0 +1,2 @@
+<!doctype html>
+<p lang="zh-CN" style="font-family: sans-serif">Some test in the default font for zh-CN.
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -2089,8 +2089,9 @@ fuzzy(0-1,0-625) == 1466638-1.html 14666
 == bug1472465-1.html bug1472465-1-ref.html
 == 1475971-1.html 1475971-1-ref.html
 == 1483649-1.xul 1483649-1-ref.xul
 test-pref(layout.css.contain.enabled,true) == 1483946.html 1483946-ref.html
 test-pref(layout.css.visited_links_enabled,false) == 1488155.html 1488155-ref.html
 == 1492660-1.html 1492660-1-ref.html
 pref(layout.css.supports-selector.enabled,true) == 1499386.html 1499386-ref.html
 pref(layout.css.supports-selector.enabled,false) != 1499386.html 1499386-ref.html
+== 1511570.html 1511570-ref.html
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
@@ -139,17 +139,17 @@ static const char* pciLogTag = "PeerConn
 static mozilla::LazyLogModule logModuleInfo("signaling");
 
 // Getting exceptions back down from PCObserver is generally not harmful.
 namespace {
 // This is a terrible hack.  The problem is that SuppressException is not
 // inline, and we link this file without libxul in some cases (e.g. for our test
 // setup).  So we can't use ErrorResult or IgnoredErrorResult because those call
 // SuppressException...  And we can't use FastErrorResult because we can't
-// include BindingUtils.h, because our linking is completely fucked up.  Use
+// include BindingUtils.h, because our linking is completely broken. Use
 // BaseErrorResult directly.  Please do not let me see _anyone_ doing this
 // without really careful review from someone who knows what they are doing.
 class JSErrorResult : public binding_danger::TErrorResult<
                           binding_danger::JustAssertCleanupPolicy> {
  public:
   ~JSErrorResult() { SuppressException(); }
 } JS_HAZ_ROOTED;
 
--- a/python/mozbuild/mozbuild/mach_commands.py
+++ b/python/mozbuild/mozbuild/mach_commands.py
@@ -2826,54 +2826,76 @@ class StaticAnalysis(MachCommandBase):
         process = subprocess.Popen(args, stdin=subprocess.PIPE)
         with open(paths[0], 'r') as fin:
             process.stdin.write(fin.read())
             process.stdin.close()
             process.wait();
             return 0
 
     def _run_clang_format_path(self, clang_format, show, paths):
+        import shutil
+
         # Run clang-format on files or directories directly
         from subprocess import check_output, CalledProcessError
 
         args = [clang_format, "-i"]
 
+        if show:
+            # We just want to show the diff, we create the directory to copy it
+            tmpdir = os.path.join(self.topobjdir, 'tmp')
+            if not os.path.exists(tmpdir):
+                os.makedirs(tmpdir)
+
         path_list = self._generate_path_list(paths)
 
         if path_list == []:
             return
 
         print("Processing %d file(s)..." % len(path_list))
 
         batchsize = 200
+        if show:
+            batchsize = 1
 
         for i in range(0, len(path_list), batchsize):
             l = path_list[i: (i + batchsize)]
+            if show:
+                # Copy the files into a temp directory
+                # and run clang-format on the temp directory
+                # and show the diff
+                original_path = l[0]
+                local_path = original_path.replace(self.topsrcdir, ".")
+                target_file = os.path.join(tmpdir, local_path)
+                faketmpdir = os.path.dirname(target_file)
+                if not os.path.isdir(faketmpdir):
+                    os.makedirs(faketmpdir)
+                shutil.copy(l[0], faketmpdir)
+                l[0] = target_file
+
             # Run clang-format on the list
             try:
                 check_output(args + l)
             except CalledProcessError as e:
                 # Something wrong happend
                 print("clang-format: An error occured while running clang-format.")
                 return e.returncode
 
+            if show:
+                # show the diff
+                diff_command = ["diff", "-u", original_path, target_file]
+                try:
+                    output = check_output(diff_command)
+                except CalledProcessError as e:
+                    # diff -u returns 0 when no change
+                    # here, we expect changes. if we are here, this means that
+                    # there is a diff to show
+                    if e.output:
+                        print(e.output)
         if show:
-            # show the diff
-            if self.repository.name == 'hg':
-                diff_command = ["hg", "diff"] + paths
-            else:
-                assert self.repository.name == 'git'
-                diff_command = ["git", "diff"] + paths
-            try:
-                output = check_output(diff_command)
-                print(output)
-            except CalledProcessError as e:
-                # Something wrong happend
-                print("clang-format: Unable to run the diff command.")
-                return e.returncode
+            shutil.rmtree(tmpdir)
         return 0
 
 @CommandProvider
 class Vendor(MachCommandBase):
     """Vendor third-party dependencies into the source repository."""
 
     @Command('vendor', category='misc',
              description='Vendor third-party dependencies into the source repository.')
--- a/widget/gtk/mozcontainer.cpp
+++ b/widget/gtk/mozcontainer.cpp
@@ -142,66 +142,72 @@ void moz_container_init(MozContainer *co
   gtk_widget_set_can_focus(GTK_WIDGET(container), TRUE);
   gtk_container_set_resize_mode(GTK_CONTAINER(container), GTK_RESIZE_IMMEDIATE);
   gtk_widget_set_redraw_on_allocate(GTK_WIDGET(container), FALSE);
 
 #if defined(MOZ_WAYLAND)
   container->surface = nullptr;
   container->subsurface = nullptr;
   container->eglwindow = nullptr;
+  container->frame_callback_handler = nullptr;
   container->ready_to_draw = false;
   container->surface_needs_clear = true;
 #endif
 }
 
 #if defined(MOZ_WAYLAND)
-static void moz_on_frame_clock_after_paint(GdkFrameClock *clock,
-                                           MozContainer *container) {
+static wl_surface *moz_container_get_gtk_container_surface(
+    MozContainer *container) {
+  static auto sGdkWaylandWindowGetWlSurface = (wl_surface * (*)(GdkWindow *))
+      dlsym(RTLD_DEFAULT, "gdk_wayland_window_get_wl_surface");
+
+  GdkWindow *window = gtk_widget_get_window(GTK_WIDGET(container));
+  return sGdkWaylandWindowGetWlSurface(window);
+}
+
+static void frame_callback_handler(void *data, struct wl_callback *callback,
+                                   uint32_t time) {
+  MozContainer *container = MOZ_CONTAINER(data);
+  g_clear_pointer(&container->frame_callback_handler, wl_callback_destroy);
   container->ready_to_draw = true;
-  g_signal_handler_disconnect(clock,
-                              container->frame_clock_after_paint_handler);
-  container->frame_clock_after_paint_handler = 0;
 }
 
+static const struct wl_callback_listener frame_listener = {
+    frame_callback_handler};
+
 static void moz_container_map_wayland(MozContainer *container) {
-  MOZ_ASSERT(!container->ready_to_draw, "MozContainer is already mapped.");
-  MOZ_ASSERT(!container->frame_clock_after_paint_handler,
-             "Repeated gdk_window_get_frame_clock() request?");
-
-  GdkDisplay *display = gtk_widget_get_display(GTK_WIDGET(container));
-  if (GDK_IS_X11_DISPLAY(display)) return;
-
   container->surface_needs_clear = true;
+  container->ready_to_draw = false;
 
-  static auto sGdkWindowGetFrameClock = (GdkFrameClock * (*)(GdkWindow *))
-      dlsym(RTLD_DEFAULT, "gdk_window_get_frame_clock");
-
-  GdkWindow *window = gtk_widget_get_window(GTK_WIDGET(container));
-  GdkFrameClock *clock = sGdkWindowGetFrameClock(window);
-  container->frame_clock_after_paint_handler = g_signal_connect_after(
-      clock, "after-paint", G_CALLBACK(moz_on_frame_clock_after_paint),
-      container);
+  static wl_surface *gtk_container_surface =
+      moz_container_get_gtk_container_surface(container);
+  container->frame_callback_handler = wl_surface_frame(gtk_container_surface);
+  wl_callback_add_listener(container->frame_callback_handler, &frame_listener,
+                           container);
 }
 
 static void moz_container_unmap_wayland(MozContainer *container) {
   g_clear_pointer(&container->eglwindow, wl_egl_window_destroy);
   g_clear_pointer(&container->subsurface, wl_subsurface_destroy);
   g_clear_pointer(&container->surface, wl_surface_destroy);
+  g_clear_pointer(&container->frame_callback_handler, wl_callback_destroy);
 
-  if (container->frame_clock_after_paint_handler) {
-    static auto sGdkWindowGetFrameClock = (GdkFrameClock * (*)(GdkWindow *))
-        dlsym(RTLD_DEFAULT, "gdk_window_get_frame_clock");
-    GdkWindow *window = gtk_widget_get_window(GTK_WIDGET(container));
-    GdkFrameClock *clock = sGdkWindowGetFrameClock(window);
+  container->ready_to_draw = false;
+}
+
+static gint moz_container_get_scale(MozContainer *container) {
+    static auto sGdkWindowGetScaleFactorPtr = (gint(*)(GdkWindow *))dlsym(
+        RTLD_DEFAULT, "gdk_window_get_scale_factor");
 
-    g_signal_handler_disconnect(clock,
-                                container->frame_clock_after_paint_handler);
-    container->frame_clock_after_paint_handler = 0;
-  }
-  container->ready_to_draw = false;
+    if (sGdkWindowGetScaleFactorPtr) {
+      GdkWindow *window = gtk_widget_get_window(GTK_WIDGET(container));
+      return (*sGdkWindowGetScaleFactorPtr)(window);
+    }
+
+    return 1;
 }
 #endif
 
 void moz_container_map(GtkWidget *widget) {
   MozContainer *container;
   GList *tmp_list;
   GtkWidget *tmp_child;
 
@@ -218,30 +224,34 @@ void moz_container_map(GtkWidget *widget
       if (!gtk_widget_get_mapped(tmp_child)) gtk_widget_map(tmp_child);
     }
     tmp_list = tmp_list->next;
   }
 
   if (gtk_widget_get_has_window(widget)) {
     gdk_window_show(gtk_widget_get_window(widget));
 #if defined(MOZ_WAYLAND)
-    moz_container_map_wayland(MOZ_CONTAINER(widget));
+    if (!GDK_IS_X11_DISPLAY(gdk_display_get_default())) {
+      moz_container_map_wayland(MOZ_CONTAINER(widget));
+    }
 #endif
   }
 }
 
 void moz_container_unmap(GtkWidget *widget) {
   g_return_if_fail(IS_MOZ_CONTAINER(widget));
 
   gtk_widget_set_mapped(widget, FALSE);
 
   if (gtk_widget_get_has_window(widget)) {
     gdk_window_hide(gtk_widget_get_window(widget));
 #if defined(MOZ_WAYLAND)
-    moz_container_unmap_wayland(MOZ_CONTAINER(widget));
+    if (!GDK_IS_X11_DISPLAY(gdk_display_get_default())) {
+      moz_container_unmap_wayland(MOZ_CONTAINER(widget));
+    }
 #endif
   }
 }
 
 void moz_container_realize(GtkWidget *widget) {
   GdkWindow *parent = gtk_widget_get_parent_window(widget);
   GdkWindow *window;
 
@@ -319,18 +329,20 @@ void moz_container_size_allocate(GtkWidg
   // when offset changes (GdkWindow is maximized for instance).
   // see gtk-clutter-embed.c for reference.
   if (container->subsurface) {
     gint x, y;
     gdk_window_get_position(gtk_widget_get_window(widget), &x, &y);
     wl_subsurface_set_position(container->subsurface, x, y);
   }
   if (container->eglwindow) {
-    wl_egl_window_resize(container->eglwindow, allocation->width,
-                         allocation->height, 0, 0);
+    gint scale = moz_container_get_scale(container);
+    wl_egl_window_resize(container->eglwindow,
+                         allocation->width * scale,
+                         allocation->height * scale, 0, 0);
   }
 #endif
 }
 
 void moz_container_remove(GtkContainer *container, GtkWidget *child_widget) {
   MozContainerChild *child;
   MozContainer *moz_container;
   GdkWindow *parent_window;
@@ -424,76 +436,67 @@ MozContainerChild *moz_container_get_chi
 }
 
 static void moz_container_add(GtkContainer *container, GtkWidget *widget) {
   moz_container_put(MOZ_CONTAINER(container), widget, 0, 0);
 }
 
 #ifdef MOZ_WAYLAND
 struct wl_surface *moz_container_get_wl_surface(MozContainer *container) {
-  // We're not mapped yet.
-  if (!container->ready_to_draw) return nullptr;
+  if (!container->surface) {
+    if (!container->ready_to_draw) {
+      return nullptr;
+    }
+    GdkDisplay *display = gtk_widget_get_display(GTK_WIDGET(container));
 
-  if (!container->surface) {
     // Available as of GTK 3.8+
     static auto sGdkWaylandDisplayGetWlCompositor =
         (wl_compositor * (*)(GdkDisplay *))
             dlsym(RTLD_DEFAULT, "gdk_wayland_display_get_wl_compositor");
-    static auto sGdkWaylandWindowGetWlSurface = (wl_surface * (*)(GdkWindow *))
-        dlsym(RTLD_DEFAULT, "gdk_wayland_window_get_wl_surface");
-    static auto sGdkWindowGetScaleFactorPtr = (gint(*)(GdkWindow *))dlsym(
-        RTLD_DEFAULT, "gdk_window_get_scale_factor");
-
-    GdkWindow *window = gtk_widget_get_window(GTK_WIDGET(container));
-    GdkDisplay *display = gtk_widget_get_display(GTK_WIDGET(container));
-
     struct wl_compositor *compositor =
         sGdkWaylandDisplayGetWlCompositor(display);
     container->surface = wl_compositor_create_surface(compositor);
 
-    wl_surface *parent_surface = sGdkWaylandWindowGetWlSurface(window);
-
     nsWaylandDisplay *waylandDisplay = WaylandDisplayGet(display);
-    wl_subcompositor *subcompositor = waylandDisplay->GetSubcompositor();
     container->subsurface = wl_subcompositor_get_subsurface(
-        subcompositor, container->surface, parent_surface);
+        waylandDisplay->GetSubcompositor(), container->surface,
+        moz_container_get_gtk_container_surface(container));
     WaylandDisplayRelease(waylandDisplay);
 
+    GdkWindow *window = gtk_widget_get_window(GTK_WIDGET(container));
     gint x, y;
     gdk_window_get_position(window, &x, &y);
     wl_subsurface_set_position(container->subsurface, x, y);
     wl_subsurface_set_desync(container->subsurface);
 
     // Route input to parent wl_surface owned by Gtk+ so we get input
     // events from Gtk+.
     wl_region *region = wl_compositor_create_region(compositor);
     wl_surface_set_input_region(container->surface, region);
     wl_region_destroy(region);
 
-    container->surface_needs_clear = true;
-
-    if (sGdkWindowGetScaleFactorPtr) {
-      gint scaleFactor = (*sGdkWindowGetScaleFactorPtr)(window);
-      wl_surface_set_buffer_scale(container->surface, scaleFactor);
-    }
+    wl_surface_set_buffer_scale(container->surface,
+                                moz_container_get_scale(container));
   }
 
   return container->surface;
 }
 
 struct wl_egl_window *moz_container_get_wl_egl_window(MozContainer *container) {
   if (!container->eglwindow) {
     wl_surface *surface = moz_container_get_wl_surface(container);
     if (!surface) {
       return nullptr;
     }
 
     GdkWindow *window = gtk_widget_get_window(GTK_WIDGET(container));
+    gint scale = moz_container_get_scale(container);
     container->eglwindow = wl_egl_window_create(
-        surface, gdk_window_get_width(window), gdk_window_get_height(window));
+        surface, gdk_window_get_width(window) * scale,
+                 gdk_window_get_height(window) * scale);
   }
   return container->eglwindow;
 }
 
 gboolean moz_container_has_wl_egl_window(MozContainer *container) {
   return container->eglwindow ? true : false;
 }
 
--- a/widget/gtk/mozcontainer.h
+++ b/widget/gtk/mozcontainer.h
@@ -70,31 +70,32 @@ struct wl_subsurface;
 struct _MozContainer {
   GtkContainer container;
   GList *children;
 
 #ifdef MOZ_WAYLAND
   struct wl_surface *surface;
   struct wl_subsurface *subsurface;
   struct wl_egl_window *eglwindow;
+  struct wl_callback *frame_callback_handler;
   gboolean surface_needs_clear;
   gboolean ready_to_draw;
-  gulong frame_clock_after_paint_handler;
 #endif
 };
 
 struct _MozContainerClass {
   GtkContainerClass parent_class;
 };
 
 GType moz_container_get_type(void);
 GtkWidget *moz_container_new(void);
 void moz_container_put(MozContainer *container, GtkWidget *child_widget, gint x,
                        gint y);
 
 #ifdef MOZ_WAYLAND
 struct wl_surface *moz_container_get_wl_surface(MozContainer *container);
 struct wl_egl_window *moz_container_get_wl_egl_window(MozContainer *container);
+
 gboolean moz_container_has_wl_egl_window(MozContainer *container);
 gboolean moz_container_surface_needs_clear(MozContainer *container);
 #endif
 
 #endif /* __MOZ_CONTAINER_H__ */
--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -1865,23 +1865,16 @@ gboolean nsWindow::OnExposeEvent(cairo_t
 
   if (mIsDestroyed) {
     return FALSE;
   }
 
   // Windows that are not visible will be painted after they become visible.
   if (!mGdkWindow || mIsFullyObscured || !mHasMappedToplevel) return FALSE;
 
-#ifdef MOZ_WAYLAND
-  // Window does not have visible MozContainer/wl_surface yet.
-  if (!mIsX11Display && (!mContainer || !mContainer->ready_to_draw)) {
-    return FALSE;
-  }
-#endif
-
   nsIWidgetListener *listener = GetListener();
   if (!listener) return FALSE;
 
   LayoutDeviceIntRegion exposeRegion;
   if (!ExtractExposeRegion(exposeRegion, cr)) {
     return FALSE;
   }
 
@@ -3626,20 +3619,16 @@ nsresult nsWindow::Create(nsIWidget *aPa
         SetCursor(eCursor_standard);
 
         if (aInitData->mNoAutoHide) {
           gint wmd = ConvertBorderStyles(mBorderStyle);
           if (wmd != -1)
             gdk_window_set_decorations(mGdkWindow, (GdkWMDecoration)wmd);
         }
 
-        if (!mIsX11Display) {
-          gtk_widget_set_app_paintable(mShell, TRUE);
-        }
-
         // If the popup ignores mouse events, set an empty input shape.
         if (aInitData->mMouseTransparent) {
           cairo_rectangle_int_t rect = {0, 0, 0, 0};
           cairo_region_t *region = cairo_region_create_rectangle(&rect);
 
           gdk_window_input_shape_combine_region(mGdkWindow, region, 0, 0);
           cairo_region_destroy(region);
         }