Merge autoland to mozilla-central. a=merge FIREFOX_BETA_70_BASE
authorDorel Luca <dluca@mozilla.com>
Mon, 26 Aug 2019 12:42:03 +0300
changeset 489837 c75d6a0539eb4b2c7961f0c9782fcb364198c6b2
parent 489795 714f6061c12c657c5d9b9a5f6be7127f07be90bb (current diff)
parent 489836 fbbcc4e9d6f4408eceb646f1ba877cff009a54b9 (diff)
child 489838 0cf9eded35d8150796eda1f892666d0a778bd488
child 489911 65d4c80d42c0b07bc3364fd67d1a7efc45b5f1ec
push id36489
push userdluca@mozilla.com
push dateMon, 26 Aug 2019 09:42:55 +0000
treeherdermozilla-central@c75d6a0539eb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone70.0a1
first release with
nightly linux32
c75d6a0539eb / 70.0a1 / 20190826094255 / files
nightly linux64
c75d6a0539eb / 70.0a1 / 20190826094255 / files
nightly mac
c75d6a0539eb / 70.0a1 / 20190826094255 / files
nightly win32
c75d6a0539eb / 70.0a1 / 20190826094255 / files
nightly win64
c75d6a0539eb / 70.0a1 / 20190826094255 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge autoland to mozilla-central. a=merge
devtools/client/preferences/devtools-client.js
devtools/client/webide/preferences/moz.build
devtools/client/webide/preferences/webide.js
devtools/shared/preferences/README.md
devtools/shared/preferences/devtools-shared.js
devtools/startup/preferences/devtools-startup.js
devtools/startup/preferences/moz.build
--- a/.eslintignore
+++ b/.eslintignore
@@ -106,19 +106,16 @@ devtools/client/debugger/images/
 devtools/client/debugger/test/
 devtools/client/debugger/index.html
 
 # Ignore devtools imported repositories
 devtools/client/shared/components/reps/
 
 # Ignore devtools preferences files
 devtools/client/preferences/
-devtools/client/webide/preferences/
-devtools/shared/preferences/
-devtools/startup/preferences/devtools-startup.js
 
 # Ignore devtools generated code
 devtools/shared/css/generated/properties-db.js
 devtools/client/webconsole/test/node/fixtures/stubs/*.js
 !devtools/client/webconsole/test/node/fixtures/stubs/index.js
 
 # Ignore devtools third-party libs
 devtools/shared/jsbeautify/
--- a/.prettierignore
+++ b/.prettierignore
@@ -10,20 +10,16 @@
 # Ignore default pref files which have a .js suffix but aren't parsed normally as JavaScript.
 browser/app/profile/channel-prefs.js
 browser/app/profile/firefox.js
 browser/branding/aurora/pref/firefox-branding.js
 browser/branding/nightly/pref/firefox-branding.js
 browser/branding/official/pref/firefox-branding.js
 browser/branding/unofficial/pref/firefox-branding.js
 devtools/client/preferences/debugger.js
-devtools/client/preferences/devtools-client.js
-devtools/client/webide/preferences/webide.js
-devtools/shared/preferences/devtools-shared.js
-devtools/startup/preferences/devtools-startup.js
 extensions/pref/autoconfig/test/unit/autoconfig.js
 mobile/android/app/geckoview-prefs.js
 mobile/android/app/mobile.js
 mobile/android/installer/mobile-l10n.js
 modules/libpref/init/all.js
 modules/libpref/test/unit/data/testParser.js
 modules/libpref/test/unit/data/testPrefLocked.js
 modules/libpref/test/unit/data/testPrefSticky.js
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -548,17 +548,17 @@ dependencies = [
 
 [[package]]
 name = "constant_time_eq"
 version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "cookie"
-version = "0.11.0"
+version = "0.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "core-foundation"
 version = "0.6.3"
@@ -3570,17 +3570,17 @@ name = "wasmparser"
 version = "0.32.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "webdriver"
 version = "0.40.1"
 dependencies = [
  "base64 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "cookie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cookie 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "regex 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)",
  "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3905,17 +3905,17 @@ dependencies = [
 "checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"
 "checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878"
 "checksum clang-sys 0.28.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4227269cec09f5f83ff160be12a1e9b0262dd1aa305302d5ba296c2ebd291055"
 "checksum clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0f16b89cbb9ee36d87483dc939fe9f1e13c05898d56d7b230a0d4dff033a536"
 "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
 "checksum cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)" = "56d741ea7a69e577f6d06b36b7dff4738f680593dc27a701ffa8506b73ce28bb"
 "checksum comedy 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6d4f03fbb05a4df3523a44cda10340e6ae6bea03ee9d01240a1a2c1ef6c73e95"
 "checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e"
-"checksum cookie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1465f8134efa296b4c19db34d909637cb2bf0f7aaf21299e23e18fa29ac557cf"
+"checksum cookie 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "888604f00b3db336d2af898ec3c1d5d0ddf5e6d462220f2ededc33a87ac4bbd5"
 "checksum core-foundation 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4e2640d6d0bf22e82bed1b73c6aef8d5dd31e5abe6666c57e6d45e2649f4f887"
 "checksum core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b"
 "checksum core-graphics 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)" = "62ceafe1622ffc9a332199096841d0ff9912ec8cf8f9cde01e254a7d5217cd10"
 "checksum core-text 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f3f46450d6f2397261af420b4ccce23807add2e45fa206410a03d66fb7f050ae"
 "checksum cose 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "72fa26cb151d3ae4b70f63d67d0fed57ce04220feafafbae7f503bef7aae590d"
 "checksum cose-c 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "49726015ab0ca765144fcca61e4a7a543a16b795a777fa53f554da2fffff9a94"
 "checksum cranelift-bforest 0.38.0 (git+https://github.com/CraneStation/Cranelift?rev=72b97fcb398537c6bb3ab73c45c428652321cbb6)" = "<none>"
 "checksum cranelift-codegen 0.38.0 (git+https://github.com/CraneStation/Cranelift?rev=72b97fcb398537c6bb3ab73c45c428652321cbb6)" = "<none>"
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1944,8 +1944,437 @@ pref("privacy.socialtracking.notificatio
 // timestamp of last popup was shown.
 pref("privacy.socialtracking.notification.lastShown", "0");
 // don't show popup again within 2 days (2 * 86400 * 1000 milliseconds)
 pref("privacy.socialtracking.notification.period.min", 172800000);
 // current number of popup shown in the profile.
 pref("privacy.socialtracking.notification.counter", 0);
 // maximum number of popup shown in the profile.
 pref("privacy.socialtracking.notification.max", 2);
+
+// Disable WebIDE and ConnectPage by default (Bug 1539451)
+pref("devtools.webide.enabled", false);
+pref("devtools.connectpage.enabled", false);
+
+// Toolbox preferences
+pref("devtools.toolbox.footer.height", 250);
+pref("devtools.toolbox.sidebar.width", 500);
+pref("devtools.toolbox.host", "bottom");
+pref("devtools.toolbox.previousHost", "right");
+pref("devtools.toolbox.selectedTool", "inspector");
+pref("devtools.toolbox.sideEnabled", true);
+pref("devtools.toolbox.zoomValue", "1");
+pref("devtools.toolbox.splitconsoleEnabled", false);
+pref("devtools.toolbox.splitconsoleHeight", 100);
+pref("devtools.toolbox.tabsOrder", "");
+
+// The fission pref is enabling the "Omniscient Browser Toolbox", which will
+// make it possible to debug anything in Firefox (See Bug 1570639 for more
+// information).
+// ⚠ This is a work in progress. Expect weirdness when the pref is enabled. ⚠
+pref("devtools.browsertoolbox.fission", false);
+
+// Toolbox Button preferences
+pref("devtools.command-button-pick.enabled", true);
+pref("devtools.command-button-frames.enabled", true);
+pref("devtools.command-button-splitconsole.enabled", true);
+pref("devtools.command-button-paintflashing.enabled", false);
+pref("devtools.command-button-scratchpad.enabled", false);
+pref("devtools.command-button-responsive.enabled", true);
+pref("devtools.command-button-screenshot.enabled", false);
+pref("devtools.command-button-rulers.enabled", false);
+pref("devtools.command-button-measure.enabled", false);
+pref("devtools.command-button-noautohide.enabled", false);
+
+// Inspector preferences
+// Enable the Inspector
+pref("devtools.inspector.enabled", true);
+// What was the last active sidebar in the inspector
+pref("devtools.inspector.activeSidebar", "layoutview");
+pref("devtools.inspector.remote", false);
+
+// Enable the 3 pane mode in the inspector
+pref("devtools.inspector.three-pane-enabled", true);
+// Enable the 3 pane mode in the chrome inspector
+pref("devtools.inspector.chrome.three-pane-enabled", false);
+// Collapse pseudo-elements by default in the rule-view
+pref("devtools.inspector.show_pseudo_elements", false);
+// The default size for image preview tooltips in the rule-view/computed-view/markup-view
+pref("devtools.inspector.imagePreviewTooltipSize", 300);
+// Enable user agent style inspection in rule-view
+pref("devtools.inspector.showUserAgentStyles", false);
+// Show all native anonymous content
+pref("devtools.inspector.showAllAnonymousContent", false);
+// Show user agent shadow roots
+pref("devtools.inspector.showUserAgentShadowRoots", false);
+// Enable the new Rules View
+pref("devtools.inspector.new-rulesview.enabled", false);
+
+// Grid highlighter preferences
+pref("devtools.gridinspector.gridOutlineMaxColumns", 50);
+pref("devtools.gridinspector.gridOutlineMaxRows", 50);
+pref("devtools.gridinspector.showGridAreas", false);
+pref("devtools.gridinspector.showGridLineNumbers", false);
+pref("devtools.gridinspector.showInfiniteLines", false);
+// Max number of grid highlighters that can be displayed
+pref("devtools.gridinspector.maxHighlighters", 3);
+
+// Whether or not the box model panel is opened in the layout view
+pref("devtools.layout.boxmodel.opened", true);
+// Whether or not the flexbox panel is opened in the layout view
+pref("devtools.layout.flexbox.opened", true);
+// Whether or not the grid inspector panel is opened in the layout view
+pref("devtools.layout.grid.opened", true);
+
+// Enable hovering Box Model values and jumping to their source CSS rule in the
+// rule-view.
+#if defined(NIGHTLY_BUILD)
+  pref("devtools.layout.boxmodel.highlightProperty", true);
+#else
+  pref("devtools.layout.boxmodel.highlightProperty", false);
+#endif
+
+// By how many times eyedropper will magnify pixels
+pref("devtools.eyedropper.zoom", 6);
+
+// Enable to collapse attributes that are too long.
+pref("devtools.markup.collapseAttributes", true);
+// Length to collapse attributes
+pref("devtools.markup.collapseAttributeLength", 120);
+// Whether to auto-beautify the HTML on copy.
+pref("devtools.markup.beautifyOnCopy", false);
+// Whether or not the DOM mutation breakpoints context menu are enabled in the
+// markup view.
+pref("devtools.markup.mutationBreakpoints.enabled", false);
+
+// DevTools default color unit
+pref("devtools.defaultColorUnit", "authored");
+
+// Enable the Memory tools
+pref("devtools.memory.enabled", true);
+
+pref("devtools.memory.custom-census-displays", "{}");
+pref("devtools.memory.custom-label-displays", "{}");
+pref("devtools.memory.custom-tree-map-displays", "{}");
+
+pref("devtools.memory.max-individuals", 1000);
+pref("devtools.memory.max-retaining-paths", 10);
+
+// Enable the Performance tools
+pref("devtools.performance.enabled", true);
+
+// The default Performance UI settings
+pref("devtools.performance.memory.sample-probability", "0.05");
+// Can't go higher than this without causing internal allocation overflows while
+// serializing the allocations data over the RDP.
+pref("devtools.performance.memory.max-log-length", 125000);
+pref("devtools.performance.timeline.hidden-markers",
+  "[\"Composite\",\"CompositeForwardTransaction\"]");
+pref("devtools.performance.profiler.buffer-size", 10000000);
+pref("devtools.performance.profiler.sample-frequency-hz", 1000);
+pref("devtools.performance.ui.invert-call-tree", true);
+pref("devtools.performance.ui.invert-flame-graph", false);
+pref("devtools.performance.ui.flatten-tree-recursion", true);
+pref("devtools.performance.ui.show-platform-data", false);
+pref("devtools.performance.ui.show-idle-blocks", true);
+pref("devtools.performance.ui.enable-memory", false);
+pref("devtools.performance.ui.enable-allocations", false);
+pref("devtools.performance.ui.enable-framerate", true);
+pref("devtools.performance.ui.show-jit-optimizations", false);
+pref("devtools.performance.ui.show-triggers-for-gc-types",
+  "TOO_MUCH_MALLOC ALLOC_TRIGGER LAST_DITCH EAGER_ALLOC_TRIGGER");
+
+// Temporary pref disabling memory flame views
+// TODO remove once we have flame charts via bug 1148663
+pref("devtools.performance.ui.enable-memory-flame", false);
+
+// Enable experimental options in the UI only in Nightly
+#if defined(NIGHTLY_BUILD)
+  pref("devtools.performance.ui.experimental", true);
+#else
+  pref("devtools.performance.ui.experimental", false);
+#endif
+
+// Preferences for the new performance panel. This pref configures the base URL
+// for the profiler.firefox.com instance to use. This is useful so that a
+// developer can change it while working on profiler.firefox.com, or in tests.
+// This isn't exposed directly to the user.
+pref("devtools.performance.recording.ui-base-url", "https://profiler.firefox.com");
+
+// A JSON array of strings, where each string is a file path to an objdir on
+// the host machine. This is used in order to look up symbol information from
+// build artifacts of local builds.
+pref("devtools.performance.recording.objdirs", "[]");
+
+// The default cache UI setting
+pref("devtools.cache.disabled", false);
+
+// The default service workers UI setting
+pref("devtools.serviceWorkers.testing.enabled", false);
+
+// Enable the Network Monitor
+pref("devtools.netmonitor.enabled", true);
+
+// Enable Network Search
+pref("devtools.netmonitor.features.search", false);
+
+// Enable the Application panel
+pref("devtools.application.enabled", false);
+
+// The default Network Monitor UI settings
+pref("devtools.netmonitor.panes-network-details-width", 550);
+pref("devtools.netmonitor.panes-network-details-height", 450);
+pref("devtools.netmonitor.panes-search-width", 550);
+pref("devtools.netmonitor.panes-search-height", 450);
+pref("devtools.netmonitor.filters", "[\"all\"]");
+pref("devtools.netmonitor.visibleColumns",
+  "[\"status\",\"method\",\"domain\",\"file\",\"cause\",\"type\",\"transferred\",\"contentSize\",\"waterfall\"]"
+);
+pref("devtools.netmonitor.columnsData",
+  '[{"name":"status","minWidth":30,"width":5}, {"name":"method","minWidth":30,"width":5}, {"name":"domain","minWidth":30,"width":10}, {"name":"file","minWidth":30,"width":25}, {"name":"url","minWidth":30,"width":25}, {"name":"cause","minWidth":30,"width":10},{"name":"type","minWidth":30,"width":5},{"name":"transferred","minWidth":30,"width":10},{"name":"contentSize","minWidth":30,"width":5},{"name":"waterfall","minWidth":150,"width":25}]');
+pref("devtools.netmonitor.ws.payload-preview-height", 128);
+pref("devtools.netmonitor.ws.visibleColumns",
+  '["data", "time"]'
+);
+pref("devtools.netmonitor.ws.displayed-frames.limit", 500);
+
+pref("devtools.netmonitor.response.ui.limit", 10240);
+
+// Save request/response bodies yes/no.
+pref("devtools.netmonitor.saveRequestAndResponseBodies", true);
+
+// The default Network monitor HAR export setting
+pref("devtools.netmonitor.har.defaultLogDir", "");
+pref("devtools.netmonitor.har.defaultFileName", "%hostname_Archive [%date]");
+pref("devtools.netmonitor.har.jsonp", false);
+pref("devtools.netmonitor.har.jsonpCallback", "");
+pref("devtools.netmonitor.har.includeResponseBodies", true);
+pref("devtools.netmonitor.har.compress", false);
+pref("devtools.netmonitor.har.forceExport", false);
+pref("devtools.netmonitor.har.pageLoadedTimeout", 1500);
+pref("devtools.netmonitor.har.enableAutoExportToFile", false);
+
+// Enable WebSocket monitoring in Nightly builds.
+#if defined(NIGHTLY_BUILD)
+  pref("devtools.netmonitor.features.webSockets", true);
+#else
+  pref("devtools.netmonitor.features.webSockets", false);
+#endif
+
+// Scratchpad settings
+// - recentFileMax: The maximum number of recently-opened files
+//                  stored. Setting this preference to 0 will not
+//                  clear any recent files, but rather hide the
+//                  'Open Recent'-menu.
+// - lineNumbers: Whether to show line numbers or not.
+// - wrapText: Whether to wrap text or not.
+// - showTrailingSpace: Whether to highlight trailing space or not.
+// - editorFontSize: Editor font size configuration.
+// - enableAutocompletion: Whether to enable JavaScript autocompletion.
+pref("devtools.scratchpad.recentFilesMax", 10);
+pref("devtools.scratchpad.lineNumbers", true);
+pref("devtools.scratchpad.wrapText", false);
+pref("devtools.scratchpad.showTrailingSpace", false);
+pref("devtools.scratchpad.editorFontSize", 12);
+pref("devtools.scratchpad.enableAutocompletion", true);
+
+// Enable the Storage Inspector
+pref("devtools.storage.enabled", true);
+
+// Enable the Style Editor.
+pref("devtools.styleeditor.enabled", true);
+pref("devtools.styleeditor.autocompletion-enabled", true);
+pref("devtools.styleeditor.showMediaSidebar", true);
+pref("devtools.styleeditor.mediaSidebarWidth", 238);
+pref("devtools.styleeditor.navSidebarWidth", 245);
+pref("devtools.styleeditor.transitions", true);
+
+// Screenshot Option Settings.
+pref("devtools.screenshot.clipboard.enabled", false);
+pref("devtools.screenshot.audio.enabled", true);
+
+// Enable Scratchpad
+pref("devtools.scratchpad.enabled", false);
+
+// Make sure the DOM panel is hidden by default
+pref("devtools.dom.enabled", false);
+
+// Enable the Accessibility panel.
+pref("devtools.accessibility.enabled", true);
+
+// Web console filters
+pref("devtools.webconsole.filter.error", true);
+pref("devtools.webconsole.filter.warn", true);
+pref("devtools.webconsole.filter.info", true);
+pref("devtools.webconsole.filter.log", true);
+pref("devtools.webconsole.filter.debug", true);
+pref("devtools.webconsole.filter.css", false);
+pref("devtools.webconsole.filter.net", false);
+pref("devtools.webconsole.filter.netxhr", false);
+
+// Webconsole autocomplete preference
+pref("devtools.webconsole.input.autocomplete",true);
+
+// Browser console filters
+pref("devtools.browserconsole.filter.error", true);
+pref("devtools.browserconsole.filter.warn", true);
+pref("devtools.browserconsole.filter.info", true);
+pref("devtools.browserconsole.filter.log", true);
+pref("devtools.browserconsole.filter.debug", true);
+pref("devtools.browserconsole.filter.css", false);
+pref("devtools.browserconsole.filter.net", false);
+pref("devtools.browserconsole.filter.netxhr", false);
+
+// Max number of inputs to store in web console history.
+pref("devtools.webconsole.inputHistoryCount", 300);
+
+// Persistent logging: |true| if you want the relevant tool to keep all of the
+// logged messages after reloading the page, |false| if you want the output to
+// be cleared each time page navigation happens.
+pref("devtools.webconsole.persistlog", false);
+pref("devtools.netmonitor.persistlog", false);
+
+// Web Console timestamp: |true| if you want the logs and instructions
+// in the Web Console to display a timestamp, or |false| to not display
+// any timestamps.
+pref("devtools.webconsole.timestampMessages", false);
+
+// Enable the webconsole sidebar toggle in Nightly builds.
+#if defined(NIGHTLY_BUILD)
+  pref("devtools.webconsole.sidebarToggle", true);
+#else
+  pref("devtools.webconsole.sidebarToggle", false);
+#endif
+
+// Enable editor mode in the console in Nightly builds.
+#if defined(NIGHTLY_BUILD)
+  pref("devtools.webconsole.features.editor", true);
+#else
+  pref("devtools.webconsole.features.editor", false);
+#endif
+
+// Saved editor mode state in the console.
+pref("devtools.webconsole.input.editor", false);
+
+// Editor width for webconsole and browserconsole
+pref("devtools.webconsole.input.editorWidth", 0);
+pref("devtools.browserconsole.input.editorWidth", 0);
+
+// Disable the new performance recording panel by default
+pref("devtools.performance.new-panel-enabled", false);
+
+// Enable message grouping in the console, true by default
+pref("devtools.webconsole.groupWarningMessages", true);
+
+// Saved state of the Display content messages checkbox in the browser console.
+pref("devtools.browserconsole.contentMessages", false);
+
+// Enable client-side mapping service for source maps
+pref("devtools.source-map.client-service.enabled", true);
+
+// The number of lines that are displayed in the web console.
+pref("devtools.hud.loglimit", 10000);
+
+// The developer tools editor configuration:
+// - tabsize: how many spaces to use when a Tab character is displayed.
+// - expandtab: expand Tab characters to spaces.
+// - keymap: which keymap to use (can be 'default', 'emacs' or 'vim')
+// - autoclosebrackets: whether to permit automatic bracket/quote closing.
+// - detectindentation: whether to detect the indentation from the file
+// - enableCodeFolding: Whether to enable code folding or not.
+pref("devtools.editor.tabsize", 2);
+pref("devtools.editor.expandtab", true);
+pref("devtools.editor.keymap", "default");
+pref("devtools.editor.autoclosebrackets", true);
+pref("devtools.editor.detectindentation", true);
+pref("devtools.editor.enableCodeFolding", true);
+pref("devtools.editor.autocomplete", true);
+
+// The angle of the viewport.
+pref("devtools.responsive.viewport.angle", 0);
+// The width of the viewport.
+pref("devtools.responsive.viewport.width", 320);
+// The height of the viewport.
+pref("devtools.responsive.viewport.height", 480);
+// The pixel ratio of the viewport.
+pref("devtools.responsive.viewport.pixelRatio", 0);
+// Whether or not the viewports are left aligned.
+pref("devtools.responsive.leftAlignViewport.enabled", false);
+// Whether to reload when touch simulation is toggled
+pref("devtools.responsive.reloadConditions.touchSimulation", false);
+// Whether to reload when user agent is changed
+pref("devtools.responsive.reloadConditions.userAgent", false);
+// Whether to show the notification about reloading to apply emulation
+pref("devtools.responsive.reloadNotification.enabled", true);
+// Whether or not touch simulation is enabled.
+pref("devtools.responsive.touchSimulation.enabled", false);
+// Whether or not meta viewport is enabled, if and only if touchSimulation
+// is also enabled.
+pref("devtools.responsive.metaViewport.enabled", false);
+// The user agent of the viewport.
+pref("devtools.responsive.userAgent", "");
+
+// Whether to show the settings onboarding tooltip only in release or beta
+// builds.
+#if defined(RELEASE_OR_BETA)
+  pref("devtools.responsive.show-setting-tooltip", true);
+#else
+  pref("devtools.responsive.show-setting-tooltip", false);
+#endif
+// Show the custom user agent input in Nightly builds.
+#if defined(NIGHTLY_BUILD)
+  pref("devtools.responsive.showUserAgentInput", true);
+#else
+  pref("devtools.responsive.showUserAgentInput", false);
+#endif
+
+// Show tab debug targets for This Firefox (on by default for local builds).
+#ifdef MOZILLA_OFFICIAL
+  pref("devtools.aboutdebugging.local-tab-debugging", false);
+#else
+  pref("devtools.aboutdebugging.local-tab-debugging", true);
+#endif
+
+// Show process debug targets.
+pref("devtools.aboutdebugging.process-debugging", true);
+// Stringified array of network locations that users can connect to.
+pref("devtools.aboutdebugging.network-locations", "[]");
+// Debug target pane collapse/expand settings.
+pref("devtools.aboutdebugging.collapsibilities.installedExtension", false);
+pref("devtools.aboutdebugging.collapsibilities.otherWorker", false);
+pref("devtools.aboutdebugging.collapsibilities.serviceWorker", false);
+pref("devtools.aboutdebugging.collapsibilities.sharedWorker", false);
+pref("devtools.aboutdebugging.collapsibilities.tab", false);
+pref("devtools.aboutdebugging.collapsibilities.temporaryExtension", false);
+
+// about:debugging: only show system and hidden extensions in local builds by
+// default.
+#ifdef MOZILLA_OFFICIAL
+  pref("devtools.aboutdebugging.showHiddenAddons", false);
+#else
+  pref("devtools.aboutdebugging.showHiddenAddons", true);
+#endif
+
+// Map top-level await expressions in the console
+pref("devtools.debugger.features.map-await-expression", true);
+
+// Disable autohide for DevTools popups and tooltips.
+// This is currently not exposed by any UI to avoid making
+// about:devtools-toolbox tabs unusable by mistake.
+pref("devtools.popup.disable_autohide", false);
+
+// Load the DevTools toolbox in a frame with type=content instead of type=chrome
+// See Bug 1539979 for more details.
+// We keep the option of running devtools in a chrome frame while we fix racy
+// tests that started failing when using type=content, but this ultimately
+// should be removed.
+pref("devtools.toolbox.content-frame", true);
+
+pref("devtools.webide.templatesURL", "https://code.cdn.mozilla.net/templates/list.json");
+pref("devtools.webide.autoinstallADBExtension", true);
+pref("devtools.webide.autoConnectRuntime", true);
+pref("devtools.webide.restoreLastProject", true);
+pref("devtools.webide.enableLocalRuntime", false);
+pref("devtools.webide.lastConnectedRuntime", "");
+pref("devtools.webide.lastSelectedProject", "");
+pref("devtools.webide.zoom", "1");
+pref("devtools.webide.busyTimeout", 10000);
+
--- a/browser/components/newtab/locales-src/asrouter.ftl
+++ b/browser/components/newtab/locales-src/asrouter.ftl
@@ -87,16 +87,52 @@ cfr-protections-panel-link-text = Learn 
 ## What's New toolbar button and panel
 
 cfr-whatsnew-button =
   .label = What’s New
   .tooltiptext = What’s New
 
 cfr-whatsnew-panel-header = What’s New
 
+cfr-whatsnew-release-notes-link-text = Read the release notes
+
+cfr-whatsnew-fx70-title = { -brand-short-name } now fights harder for your privacy
+cfr-whatsnew-fx70-body =
+   The latest update enhances the Tracking Protection feature and makes it
+   easier than ever to create secure passwords for every site.
+
+cfr-whatsnew-tracking-protect-title = Protect yourself from trackers
+cfr-whatsnew-tracking-protect-body =
+   { -brand-short-name } blocks many common social and cross-site trackers that
+   follow what you do online.
+cfr-whatsnew-tracking-protect-link-text = View Your Report
+
+# This string is displayed before a large numeral that indicates the total
+# number of tracking elements blocked. Don’t add $blockedCount to your
+# localization, because it would result in the number showing twice.
+cfr-whatsnew-tracking-blocked-title =
+  { $blockedCount ->
+    [one] Tracker blocked
+   *[other] Trackers blocked
+  }
+cfr-whatsnew-tracking-blocked-subtitle =
+   Since { DATETIME($earliestDate, month: "long", year: "numeric") }
+cfr-whatsnew-tracking-blocked-link-text = View Report
+
+cfr-whatsnew-lockwise-backup-title = Back up your passwords
+cfr-whatsnew-lockwise-backup-body =
+   Now generate secure passwords you can access anywhere you sign in.
+cfr-whatsnew-lockwise-backup-link-text = Turn on backups
+
+cfr-whatsnew-lockwise-take-title = Take your passwords with you
+cfr-whatsnew-lockwise-take-body =
+   The { -lockwise-brand-short-name } mobile app lets you securely access your
+   backed up passwords from anywhere.
+cfr-whatsnew-lockwise-take-link-text = Get the app
+
 ## Bookmark Sync
 
 cfr-doorhanger-sync-bookmarks-header = Get this bookmark on your phone
 cfr-doorhanger-sync-bookmarks-body = Take your bookmarks, passwords, history and more everywhere you’re signed into { -brand-product-name }.
 cfr-doorhanger-sync-bookmarks-ok-button = Turn on { -sync-brand-short-name }
   .accesskey = T
 
 ## Login Sync
--- a/browser/components/newtab/moz.build
+++ b/browser/components/newtab/moz.build
@@ -1,16 +1,16 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
 with Files("**"):
-    BUG_COMPONENT = ("Firefox", "Activity Streams: Newtab")
+    BUG_COMPONENT = ("Firefox", "New Tab Page")
 
 BROWSER_CHROME_MANIFESTS += ['test/browser/browser.ini']
 
 SPHINX_TREES['docs'] = 'docs'
 
 XPCSHELL_TESTS_MANIFESTS += [
     'test/xpcshell/xpcshell.ini',
 ]
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -256,27 +256,24 @@
 @RESPATH@/browser/chrome/icons/default/default64.png
 @RESPATH@/browser/chrome/icons/default/default128.png
 #endif
 @RESPATH@/browser/features/*
 
 ; [Webide Files]
 @RESPATH@/browser/chrome/webide@JAREXT@
 @RESPATH@/browser/chrome/webide.manifest
-@RESPATH@/browser/@PREF_DIR@/webide.js
 
 ; [DevTools Startup Files]
 @RESPATH@/browser/chrome/devtools-startup@JAREXT@
 @RESPATH@/browser/chrome/devtools-startup.manifest
-@RESPATH@/browser/@PREF_DIR@/devtools-startup.js
 
 ; DevTools
 @RESPATH@/browser/chrome/devtools@JAREXT@
 @RESPATH@/browser/chrome/devtools.manifest
-@RESPATH@/browser/@PREF_DIR@/devtools-client.js
 @RESPATH@/browser/@PREF_DIR@/debugger.js
 
 ; shell icons
 #ifdef XP_UNIX
 #ifndef XP_MACOSX
 #ifdef MOZ_UPDATER
 ; updater icon
 @RESPATH@/icons/updater.png
--- a/browser/locales/en-US/browser/newtab/asrouter.ftl
+++ b/browser/locales/en-US/browser/newtab/asrouter.ftl
@@ -87,16 +87,52 @@ cfr-protections-panel-link-text = Learn 
 ## What's New toolbar button and panel
 
 cfr-whatsnew-button =
   .label = What’s New
   .tooltiptext = What’s New
 
 cfr-whatsnew-panel-header = What’s New
 
+cfr-whatsnew-release-notes-link-text = Read the release notes
+
+cfr-whatsnew-fx70-title = { -brand-short-name } now fights harder for your privacy
+cfr-whatsnew-fx70-body =
+   The latest update enhances the Tracking Protection feature and makes it
+   easier than ever to create secure passwords for every site.
+
+cfr-whatsnew-tracking-protect-title = Protect yourself from trackers
+cfr-whatsnew-tracking-protect-body =
+   { -brand-short-name } blocks many common social and cross-site trackers that
+   follow what you do online.
+cfr-whatsnew-tracking-protect-link-text = View Your Report
+
+# This string is displayed before a large numeral that indicates the total
+# number of tracking elements blocked. Don’t add $blockedCount to your
+# localization, because it would result in the number showing twice.
+cfr-whatsnew-tracking-blocked-title =
+  { $blockedCount ->
+    [one] Tracker blocked
+   *[other] Trackers blocked
+  }
+cfr-whatsnew-tracking-blocked-subtitle =
+   Since { DATETIME($earliestDate, month: "long", year: "numeric") }
+cfr-whatsnew-tracking-blocked-link-text = View Report
+
+cfr-whatsnew-lockwise-backup-title = Back up your passwords
+cfr-whatsnew-lockwise-backup-body =
+   Now generate secure passwords you can access anywhere you sign in.
+cfr-whatsnew-lockwise-backup-link-text = Turn on backups
+
+cfr-whatsnew-lockwise-take-title = Take your passwords with you
+cfr-whatsnew-lockwise-take-body =
+   The { -lockwise-brand-short-name } mobile app lets you securely access your
+   backed up passwords from anywhere.
+cfr-whatsnew-lockwise-take-link-text = Get the app
+
 ## Bookmark Sync
 
 cfr-doorhanger-sync-bookmarks-header = Get this bookmark on your phone
 cfr-doorhanger-sync-bookmarks-body = Take your bookmarks, passwords, history and more everywhere you’re signed into { -brand-product-name }.
 cfr-doorhanger-sync-bookmarks-ok-button = Turn on { -sync-brand-short-name }
   .accesskey = T
 
 ## Login Sync
--- a/build/moz.configure/memory.configure
+++ b/build/moz.configure/memory.configure
@@ -57,16 +57,19 @@ def phc_default(milestone, target, repla
     if not replace_malloc_default or \
        (replace_malloc.origin != 'default' and not replace_malloc):
         return False
     # Nightly only because PHC has a non-negligible performance cost.
     if not milestone.is_nightly:
         return False
     # Both Linux32 and Win32 have frequent crashes when stack tracing (for
     # unclear reasons), so PHC is enabled only on 64-bit only in both cases.
+    #
+    # XXX: PHC is implemented but not yet enabled on Mac. Bug 1576515 is about
+    #      enabling it on Mac, but it is blocked by bug 1035892.
     return (target.os == 'GNU' and target.kernel == 'Linux' and
             target.bitness == 64) or \
            (target.kernel == 'WINNT' and target.bitness == 64)
 
 
 option('--enable-phc', env='MOZ_PHC', default=phc_default,
        when='--enable-jemalloc',
        help='{Enable|Disable} PHC (Probabilistic Memory Checker). '
--- a/devtools/client/preferences/debugger.js
+++ b/devtools/client/preferences/debugger.js
@@ -1,12 +1,17 @@
 /* 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/>. */
 
+// Most devtools prefs are found in browser/app/profile/firefox.js. The
+// debugger prefs are separate so they can be easily mirrored to the debugger
+// project on GitHub, here:
+// https://github.com/firefox-devtools/debugger/blob/master/assets/panel/prefs.js
+
 // Enable the Debugger
 pref("devtools.debugger.enabled", true);
 pref("devtools.debugger.chrome-debugging-host", "localhost");
 pref("devtools.debugger.chrome-debugging-websocket", false);
 pref("devtools.debugger.remote-host", "localhost");
 pref("devtools.debugger.remote-timeout", 20000);
 pref("devtools.debugger.pause-on-exceptions", false);
 pref("devtools.debugger.ignore-caught-exceptions", true);
deleted file mode 100644
--- a/devtools/client/preferences/devtools-client.js
+++ /dev/null
@@ -1,417 +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/. */
-
-// Disable WebIDE and ConnectPage by default (Bug 1539451)
-pref("devtools.webide.enabled", false);
-pref("devtools.connectpage.enabled", false);
-
-// Toolbox preferences
-pref("devtools.toolbox.footer.height", 250);
-pref("devtools.toolbox.sidebar.width", 500);
-pref("devtools.toolbox.host", "bottom");
-pref("devtools.toolbox.previousHost", "right");
-pref("devtools.toolbox.selectedTool", "inspector");
-pref("devtools.toolbox.sideEnabled", true);
-pref("devtools.toolbox.zoomValue", "1");
-pref("devtools.toolbox.splitconsoleEnabled", false);
-pref("devtools.toolbox.splitconsoleHeight", 100);
-pref("devtools.toolbox.tabsOrder", "");
-
-// The fission pref is enabling the "Omniscient Browser Toolbox", which will make it
-// possible to debug anything in Firefox (See Bug 1570639 for more information).
-// ⚠ This is a work in progress. Expect weirdness when the pref is flipped on ⚠
-pref("devtools.browsertoolbox.fission", false);
-
-// Toolbox Button preferences
-pref("devtools.command-button-pick.enabled", true);
-pref("devtools.command-button-frames.enabled", true);
-pref("devtools.command-button-splitconsole.enabled", true);
-pref("devtools.command-button-paintflashing.enabled", false);
-pref("devtools.command-button-scratchpad.enabled", false);
-pref("devtools.command-button-responsive.enabled", true);
-pref("devtools.command-button-screenshot.enabled", false);
-pref("devtools.command-button-rulers.enabled", false);
-pref("devtools.command-button-measure.enabled", false);
-pref("devtools.command-button-noautohide.enabled", false);
-
-// Inspector preferences
-// Enable the Inspector
-pref("devtools.inspector.enabled", true);
-// What was the last active sidebar in the inspector
-pref("devtools.inspector.activeSidebar", "layoutview");
-pref("devtools.inspector.remote", false);
-
-// Enable the 3 pane mode in the inspector
-pref("devtools.inspector.three-pane-enabled", true);
-// Enable the 3 pane mode in the chrome inspector
-pref("devtools.inspector.chrome.three-pane-enabled", false);
-// Collapse pseudo-elements by default in the rule-view
-pref("devtools.inspector.show_pseudo_elements", false);
-// The default size for image preview tooltips in the rule-view/computed-view/markup-view
-pref("devtools.inspector.imagePreviewTooltipSize", 300);
-// Enable user agent style inspection in rule-view
-pref("devtools.inspector.showUserAgentStyles", false);
-// Show all native anonymous content
-pref("devtools.inspector.showAllAnonymousContent", false);
-// Show user agent shadow roots
-pref("devtools.inspector.showUserAgentShadowRoots", false);
-// Enable the new Rules View
-pref("devtools.inspector.new-rulesview.enabled", false);
-
-// Grid highlighter preferences
-pref("devtools.gridinspector.gridOutlineMaxColumns", 50);
-pref("devtools.gridinspector.gridOutlineMaxRows", 50);
-pref("devtools.gridinspector.showGridAreas", false);
-pref("devtools.gridinspector.showGridLineNumbers", false);
-pref("devtools.gridinspector.showInfiniteLines", false);
-// Max number of grid highlighters that can be displayed
-pref("devtools.gridinspector.maxHighlighters", 3);
-
-// Whether or not the box model panel is opened in the layout view
-pref("devtools.layout.boxmodel.opened", true);
-// Whether or not the flexbox panel is opened in the layout view
-pref("devtools.layout.flexbox.opened", true);
-// Whether or not the grid inspector panel is opened in the layout view
-pref("devtools.layout.grid.opened", true);
-
-// Enable hovering Box Model values and jumping to their source CSS rule in the rule-view
-#if defined(NIGHTLY_BUILD)
-pref("devtools.layout.boxmodel.highlightProperty", true);
-#else
-pref("devtools.layout.boxmodel.highlightProperty", false);
-#endif
-
-// By how many times eyedropper will magnify pixels
-pref("devtools.eyedropper.zoom", 6);
-
-// Enable to collapse attributes that are too long.
-pref("devtools.markup.collapseAttributes", true);
-// Length to collapse attributes
-pref("devtools.markup.collapseAttributeLength", 120);
-// Whether to auto-beautify the HTML on copy.
-pref("devtools.markup.beautifyOnCopy", false);
-// Whether or not the DOM mutation breakpoints context menu are enabled in the markup view
-pref("devtools.markup.mutationBreakpoints.enabled", false);
-
-// DevTools default color unit
-pref("devtools.defaultColorUnit", "authored");
-
-// Enable the Memory tools
-pref("devtools.memory.enabled", true);
-
-pref("devtools.memory.custom-census-displays", "{}");
-pref("devtools.memory.custom-label-displays", "{}");
-pref("devtools.memory.custom-tree-map-displays", "{}");
-
-pref("devtools.memory.max-individuals", 1000);
-pref("devtools.memory.max-retaining-paths", 10);
-
-// Enable the Performance tools
-pref("devtools.performance.enabled", true);
-
-// The default Performance UI settings
-pref("devtools.performance.memory.sample-probability", "0.05");
-// Can't go higher than this without causing internal allocation overflows while
-// serializing the allocations data over the RDP.
-pref("devtools.performance.memory.max-log-length", 125000);
-pref("devtools.performance.timeline.hidden-markers",
-  "[\"Composite\",\"CompositeForwardTransaction\"]");
-pref("devtools.performance.profiler.buffer-size", 10000000);
-pref("devtools.performance.profiler.sample-frequency-hz", 1000);
-pref("devtools.performance.ui.invert-call-tree", true);
-pref("devtools.performance.ui.invert-flame-graph", false);
-pref("devtools.performance.ui.flatten-tree-recursion", true);
-pref("devtools.performance.ui.show-platform-data", false);
-pref("devtools.performance.ui.show-idle-blocks", true);
-pref("devtools.performance.ui.enable-memory", false);
-pref("devtools.performance.ui.enable-allocations", false);
-pref("devtools.performance.ui.enable-framerate", true);
-pref("devtools.performance.ui.show-jit-optimizations", false);
-pref("devtools.performance.ui.show-triggers-for-gc-types",
-  "TOO_MUCH_MALLOC ALLOC_TRIGGER LAST_DITCH EAGER_ALLOC_TRIGGER");
-
-// Temporary pref disabling memory flame views
-// TODO remove once we have flame charts via bug 1148663
-pref("devtools.performance.ui.enable-memory-flame", false);
-
-// Enable experimental options in the UI only in Nightly
-#if defined(NIGHTLY_BUILD)
-pref("devtools.performance.ui.experimental", true);
-#else
-pref("devtools.performance.ui.experimental", false);
-#endif
-
-// Preferences for the new performance panel
-// This pref configures the base URL for the profiler.firefox.com instance to use. This is
-// useful so that a developer can change it while working on profiler.firefox.com, or in
-// tests.
-// This isn't exposed directly to the user.
-pref("devtools.performance.recording.ui-base-url", "https://profiler.firefox.com");
-
-// A JSON array of strings, where each string is a file path to an objdir on
-// the host machine. This is used in order to look up symbol information from
-// build artifacts of local builds.
-pref("devtools.performance.recording.objdirs", "[]");
-
-// The default cache UI setting
-pref("devtools.cache.disabled", false);
-
-// The default service workers UI setting
-pref("devtools.serviceWorkers.testing.enabled", false);
-
-// Enable the Network Monitor
-pref("devtools.netmonitor.enabled", true);
-
-// Enable Network Search
-pref("devtools.netmonitor.features.search", false);
-
-// Enable the Application panel
-pref("devtools.application.enabled", false);
-
-// The default Network Monitor UI settings
-pref("devtools.netmonitor.panes-network-details-width", 550);
-pref("devtools.netmonitor.panes-network-details-height", 450);
-pref("devtools.netmonitor.panes-search-width", 550);
-pref("devtools.netmonitor.panes-search-height", 450);
-pref("devtools.netmonitor.filters", "[\"all\"]");
-pref("devtools.netmonitor.visibleColumns",
-  "[\"status\",\"method\",\"domain\",\"file\",\"cause\",\"type\",\"transferred\",\"contentSize\",\"waterfall\"]"
-);
-pref("devtools.netmonitor.columnsData",
-  '[{"name":"status","minWidth":30,"width":5}, {"name":"method","minWidth":30,"width":5}, {"name":"domain","minWidth":30,"width":10}, {"name":"file","minWidth":30,"width":25}, {"name":"url","minWidth":30,"width":25}, {"name":"cause","minWidth":30,"width":10},{"name":"type","minWidth":30,"width":5},{"name":"transferred","minWidth":30,"width":10},{"name":"contentSize","minWidth":30,"width":5},{"name":"waterfall","minWidth":150,"width":25}]');
-pref("devtools.netmonitor.ws.payload-preview-height", 128);
-pref("devtools.netmonitor.ws.visibleColumns",
-  '["data", "time"]'
-);
-pref("devtools.netmonitor.ws.displayed-frames.limit", 500);
-
-pref("devtools.netmonitor.response.ui.limit", 10240);
-
-// Save request/response bodies yes/no.
-pref("devtools.netmonitor.saveRequestAndResponseBodies", true);
-
-// The default Network monitor HAR export setting
-pref("devtools.netmonitor.har.defaultLogDir", "");
-pref("devtools.netmonitor.har.defaultFileName", "%hostname_Archive [%date]");
-pref("devtools.netmonitor.har.jsonp", false);
-pref("devtools.netmonitor.har.jsonpCallback", "");
-pref("devtools.netmonitor.har.includeResponseBodies", true);
-pref("devtools.netmonitor.har.compress", false);
-pref("devtools.netmonitor.har.forceExport", false);
-pref("devtools.netmonitor.har.pageLoadedTimeout", 1500);
-pref("devtools.netmonitor.har.enableAutoExportToFile", false);
-
-// Enable WebSocket monitoring in Nightly builds.
-#if defined(NIGHTLY_BUILD)
-pref("devtools.netmonitor.features.webSockets", true);
-#else
-pref("devtools.netmonitor.features.webSockets", false);
-#endif
-
-// Scratchpad settings
-// - recentFileMax: The maximum number of recently-opened files
-//                  stored. Setting this preference to 0 will not
-//                  clear any recent files, but rather hide the
-//                  'Open Recent'-menu.
-// - lineNumbers: Whether to show line numbers or not.
-// - wrapText: Whether to wrap text or not.
-// - showTrailingSpace: Whether to highlight trailing space or not.
-// - editorFontSize: Editor font size configuration.
-// - enableAutocompletion: Whether to enable JavaScript autocompletion.
-pref("devtools.scratchpad.recentFilesMax", 10);
-pref("devtools.scratchpad.lineNumbers", true);
-pref("devtools.scratchpad.wrapText", false);
-pref("devtools.scratchpad.showTrailingSpace", false);
-pref("devtools.scratchpad.editorFontSize", 12);
-pref("devtools.scratchpad.enableAutocompletion", true);
-
-// Enable the Storage Inspector
-pref("devtools.storage.enabled", true);
-
-// Enable the Style Editor.
-pref("devtools.styleeditor.enabled", true);
-pref("devtools.styleeditor.autocompletion-enabled", true);
-pref("devtools.styleeditor.showMediaSidebar", true);
-pref("devtools.styleeditor.mediaSidebarWidth", 238);
-pref("devtools.styleeditor.navSidebarWidth", 245);
-pref("devtools.styleeditor.transitions", true);
-
-// Screenshot Option Settings.
-pref("devtools.screenshot.clipboard.enabled", false);
-pref("devtools.screenshot.audio.enabled", true);
-
-// Enable Scratchpad
-pref("devtools.scratchpad.enabled", false);
-
-// Make sure the DOM panel is hidden by default
-pref("devtools.dom.enabled", false);
-
-// Enable the Accessibility panel.
-pref("devtools.accessibility.enabled", true);
-
-// Web console filters
-pref("devtools.webconsole.filter.error", true);
-pref("devtools.webconsole.filter.warn", true);
-pref("devtools.webconsole.filter.info", true);
-pref("devtools.webconsole.filter.log", true);
-pref("devtools.webconsole.filter.debug", true);
-pref("devtools.webconsole.filter.css", false);
-pref("devtools.webconsole.filter.net", false);
-pref("devtools.webconsole.filter.netxhr", false);
-
-// Webconsole autocomplete preference
-pref("devtools.webconsole.input.autocomplete",true);
-
-// Browser console filters
-pref("devtools.browserconsole.filter.error", true);
-pref("devtools.browserconsole.filter.warn", true);
-pref("devtools.browserconsole.filter.info", true);
-pref("devtools.browserconsole.filter.log", true);
-pref("devtools.browserconsole.filter.debug", true);
-pref("devtools.browserconsole.filter.css", false);
-pref("devtools.browserconsole.filter.net", false);
-pref("devtools.browserconsole.filter.netxhr", false);
-
-// Max number of inputs to store in web console history.
-pref("devtools.webconsole.inputHistoryCount", 300);
-
-// Persistent logging: |true| if you want the relevant tool to keep all of the
-// logged messages after reloading the page, |false| if you want the output to
-// be cleared each time page navigation happens.
-pref("devtools.webconsole.persistlog", false);
-pref("devtools.netmonitor.persistlog", false);
-
-// Web Console timestamp: |true| if you want the logs and instructions
-// in the Web Console to display a timestamp, or |false| to not display
-// any timestamps.
-pref("devtools.webconsole.timestampMessages", false);
-
-// Enable the webconsole sidebar toggle in Nightly builds.
-#if defined(NIGHTLY_BUILD)
-pref("devtools.webconsole.sidebarToggle", true);
-#else
-pref("devtools.webconsole.sidebarToggle", false);
-#endif
-
-// Enable editor mode in the console in Nightly builds.
-#if defined(NIGHTLY_BUILD)
-pref("devtools.webconsole.features.editor", true);
-#else
-pref("devtools.webconsole.features.editor", false);
-#endif
-
-// Saved editor mode state in the console.
-pref("devtools.webconsole.input.editor", false);
-
-// Editor width for webconsole and browserconsole
-pref("devtools.webconsole.input.editorWidth", 0);
-pref("devtools.browserconsole.input.editorWidth", 0);
-
-// Disable the new performance recording panel by default
-pref("devtools.performance.new-panel-enabled", false);
-
-// Enable message grouping in the console, true by default
-pref("devtools.webconsole.groupWarningMessages", true);
-
-// Saved state of the Display content messages checkbox in the browser console.
-pref("devtools.browserconsole.contentMessages", false);
-
-// Enable client-side mapping service for source maps
-pref("devtools.source-map.client-service.enabled", true);
-
-// The number of lines that are displayed in the web console.
-pref("devtools.hud.loglimit", 10000);
-
-// The developer tools editor configuration:
-// - tabsize: how many spaces to use when a Tab character is displayed.
-// - expandtab: expand Tab characters to spaces.
-// - keymap: which keymap to use (can be 'default', 'emacs' or 'vim')
-// - autoclosebrackets: whether to permit automatic bracket/quote closing.
-// - detectindentation: whether to detect the indentation from the file
-// - enableCodeFolding: Whether to enable code folding or not.
-pref("devtools.editor.tabsize", 2);
-pref("devtools.editor.expandtab", true);
-pref("devtools.editor.keymap", "default");
-pref("devtools.editor.autoclosebrackets", true);
-pref("devtools.editor.detectindentation", true);
-pref("devtools.editor.enableCodeFolding", true);
-pref("devtools.editor.autocomplete", true);
-
-// The angle of the viewport.
-pref("devtools.responsive.viewport.angle", 0);
-// The width of the viewport.
-pref("devtools.responsive.viewport.width", 320);
-// The height of the viewport.
-pref("devtools.responsive.viewport.height", 480);
-// The pixel ratio of the viewport.
-pref("devtools.responsive.viewport.pixelRatio", 0);
-// Whether or not the viewports are left aligned.
-pref("devtools.responsive.leftAlignViewport.enabled", false);
-// Whether to reload when touch simulation is toggled
-pref("devtools.responsive.reloadConditions.touchSimulation", false);
-// Whether to reload when user agent is changed
-pref("devtools.responsive.reloadConditions.userAgent", false);
-// Whether to show the notification about reloading to apply emulation
-pref("devtools.responsive.reloadNotification.enabled", true);
-// Whether or not touch simulation is enabled.
-pref("devtools.responsive.touchSimulation.enabled", false);
-// Whether or not meta viewport is enabled, if and only if touchSimulation
-// is also enabled.
-pref("devtools.responsive.metaViewport.enabled", false);
-// The user agent of the viewport.
-pref("devtools.responsive.userAgent", "");
-
-// Whether to show the settings onboarding tooltip only in release or beta builds.
-#if defined(RELEASE_OR_BETA)
-pref("devtools.responsive.show-setting-tooltip", true);
-#else
-pref("devtools.responsive.show-setting-tooltip", false);
-#endif
-// Show the custom user agent input in Nightly builds.
-#if defined(NIGHTLY_BUILD)
-pref("devtools.responsive.showUserAgentInput", true);
-#else
-pref("devtools.responsive.showUserAgentInput", false);
-#endif
-
-// Show tab debug targets for This Firefox (on by default for local builds).
-#ifdef MOZILLA_OFFICIAL
-  pref("devtools.aboutdebugging.local-tab-debugging", false);
-#else
-  pref("devtools.aboutdebugging.local-tab-debugging", true);
-#endif
-
-// Show process debug targets.
-pref("devtools.aboutdebugging.process-debugging", true);
-// Stringified array of network locations that users can connect to.
-pref("devtools.aboutdebugging.network-locations", "[]");
-// Debug target pane collapse/expand settings.
-pref("devtools.aboutdebugging.collapsibilities.installedExtension", false);
-pref("devtools.aboutdebugging.collapsibilities.otherWorker", false);
-pref("devtools.aboutdebugging.collapsibilities.serviceWorker", false);
-pref("devtools.aboutdebugging.collapsibilities.sharedWorker", false);
-pref("devtools.aboutdebugging.collapsibilities.tab", false);
-pref("devtools.aboutdebugging.collapsibilities.temporaryExtension", false);
-
-// about:debugging: only show system and hidden extensions in local builds by default.
-#ifdef MOZILLA_OFFICIAL
-  pref("devtools.aboutdebugging.showHiddenAddons", false);
-#else
-  pref("devtools.aboutdebugging.showHiddenAddons", true);
-#endif
-
-// Map top-level await expressions in the console
-pref("devtools.debugger.features.map-await-expression", true);
-
-// Disable autohide for DevTools popups and tooltips.
-// This is currently not exposed by any UI to avoid making
-// about:devtools-toolbox tabs unusable by mistake.
-pref("devtools.popup.disable_autohide", false);
-
-// Load the DevTools toolbox in a frame with type=content instead of type=chrome
-// See Bug 1539979 for more details.
-// We keep the option of running devtools in a chrome frame while we fix racy
-// tests that started failing when using type=content, but this ultimately should
-// be removed.
-pref("devtools.toolbox.content-frame", true);
--- a/devtools/client/preferences/moz.build
+++ b/devtools/client/preferences/moz.build
@@ -1,13 +1,9 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
-JS_PREFERENCE_PP_FILES += [
-    'devtools-client.js'
-]
-
 JS_PREFERENCE_FILES += [
     'debugger.js',
 ]
--- a/devtools/client/responsive/test/browser/browser_device_width.js
+++ b/devtools/client/responsive/test/browser/browser_device_width.js
@@ -1,37 +1,53 @@
 /* Any copyright is dedicated to the Public Domain.
 http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
-const TEST_URL = "data:text/html;charset=utf-8,";
+const TEST_URL =
+  'data:text/html;charset=utf-8,<iframe id="subframe" ' +
+  'width="200" height="200"></iframe>';
 
 addRDMTask(TEST_URL, async function({ ui, manager }) {
+  await pushPref("devtools.responsive.metaViewport.enabled", true);
+
   ok(ui, "An instance of the RDM should be attached to the tab.");
-  await setViewportSize(ui, manager, 110, 500);
+  await setViewportSizeAndAwaitReflow(ui, manager, 110, 500);
 
   info("Checking initial width/height properties.");
-  await doInitialChecks(ui);
+  await doInitialChecks(ui, 110);
+
+  info("Checking initial width/height with meta viewport on");
+  await setTouchAndMetaViewportSupport(ui, true);
+  await doInitialChecks(ui, 440);
+  await setTouchAndMetaViewportSupport(ui, false);
 
   info("Changing the RDM size");
-  await setViewportSize(ui, manager, 90, 500);
+  await setViewportSizeAndAwaitReflow(ui, manager, 90, 500);
 
   info("Checking for screen props");
   await checkScreenProps(ui);
 
+  info("Checking for screen props with meta viewport on");
+  await setTouchAndMetaViewportSupport(ui, true);
+  await checkScreenProps(ui);
+  await setTouchAndMetaViewportSupport(ui, false);
+
+  info("Checking for subframe props");
+  await checkSubframeProps(ui);
+
+  info("Checking for subframe props with meta viewport on");
+  await setTouchAndMetaViewportSupport(ui, true);
+  await checkSubframeProps(ui);
+  await setTouchAndMetaViewportSupport(ui, false);
+
   info("Changing the RDM size using input keys");
   await setViewportSizeWithInputKeys(ui);
 
-  info("Setting docShell.deviceSizeIsPageSize to false");
-  await ContentTask.spawn(ui.getViewportBrowser(), {}, async function() {
-    const docShell = content.docShell;
-    docShell.deviceSizeIsPageSize = false;
-  });
-
   info("Checking for screen props once again.");
   await checkScreenProps2(ui);
 });
 
 async function setViewportSizeWithInputKeys(ui) {
   const width = 320,
     height = 500;
   let resized = waitForViewportResizeTo(ui, width, height);
@@ -66,24 +82,24 @@ async function setViewportSizeWithInputK
 
   // Resetting height value back to 500 by using `PageDown + Shift` key
   resized = waitForViewportResizeTo(ui, width, height);
   dimensions[1].focus();
   EventUtils.synthesizeKey("KEY_PageDown", { shiftKey: true });
   await resized;
 }
 
-async function doInitialChecks(ui) {
+async function doInitialChecks(ui, expectedInnerWidth) {
   const {
     innerWidth,
     matchesMedia,
     outerHeight,
     outerWidth,
   } = await grabContentInfo(ui);
-  is(innerWidth, 110, "initial width should be 110px");
+  is(innerWidth, expectedInnerWidth, "inner width should be as expected");
   is(outerWidth, 110, "device's outerWidth should be 110px");
   is(outerHeight, 500, "device's outerHeight should be 500px");
   isnot(
     window.outerHeight,
     outerHeight,
     "window.outerHeight should not be the size of the device's outerHeight"
   );
   isnot(
@@ -102,31 +118,57 @@ async function checkScreenProps(ui) {
     screen.width,
     "screen.width should not be the size of the screen."
   );
   is(screen.width, 90, "screen.width should be the page width");
   is(screen.height, 500, "screen.height should be the page height");
 }
 
 async function checkScreenProps2(ui) {
-  const { matchesMedia, screen } = await grabContentInfo(ui);
-  ok(!matchesMedia, "media query should be re-evaluated.");
-  is(
+  const { screen } = await grabContentInfo(ui);
+  isnot(
     window.screen.width,
     screen.width,
-    "screen.width should be the size of the screen."
+    "screen.width should not be the size of the screen."
   );
 }
 
+async function checkSubframeProps(ui) {
+  const { outerWidth, matchesMedia, screen } = await grabContentSubframeInfo(
+    ui
+  );
+  is(outerWidth, 90, "subframe outerWidth should be 90px");
+  ok(matchesMedia, "subframe media query should match");
+  is(screen.width, 90, "subframe screen.width should be the page width");
+  is(screen.height, 500, "subframe screen.height should be the page height");
+}
+
 function grabContentInfo(ui) {
   return ContentTask.spawn(ui.getViewportBrowser(), {}, async function() {
     return {
       screen: {
         width: content.screen.width,
         height: content.screen.height,
       },
       innerWidth: content.innerWidth,
       matchesMedia: content.matchMedia("(max-device-width:100px)").matches,
       outerHeight: content.outerHeight,
       outerWidth: content.outerWidth,
     };
   });
 }
+
+function grabContentSubframeInfo(ui) {
+  return ContentTask.spawn(ui.getViewportBrowser(), {}, async function() {
+    const subframe = content.document.getElementById("subframe");
+    const win = subframe.contentWindow;
+    return {
+      screen: {
+        width: win.screen.width,
+        height: win.screen.height,
+      },
+      innerWidth: win.innerWidth,
+      matchesMedia: win.matchMedia("(max-device-width:100px)").matches,
+      outerHeight: win.outerHeight,
+      outerWidth: win.outerWidth,
+    };
+  });
+}
--- a/devtools/client/responsive/test/browser/head.js
+++ b/devtools/client/responsive/test/browser/head.js
@@ -723,30 +723,30 @@ async function testViewportZoomWidthAndH
   if (typeof zoom !== "undefined") {
     const resolution = await spawnViewportTask(ui, {}, function() {
       return content.windowUtils.getResolution();
     });
     is(resolution, zoom, message + " should have expected zoom.");
   }
 
   if (typeof width !== "undefined" || typeof height !== "undefined") {
-    const layoutSize = await spawnViewportTask(ui, {}, function() {
+    const innerSize = await spawnViewportTask(ui, {}, function() {
       return {
-        width: content.screen.width,
-        height: content.screen.height,
+        width: content.innerWidth,
+        height: content.innerHeight,
       };
     });
     if (typeof width !== "undefined") {
       is(
-        layoutSize.width,
+        innerSize.width,
         width,
-        message + " should have expected layout width."
+        message + " should have expected inner width."
       );
     }
     if (typeof height !== "undefined") {
       is(
-        layoutSize.height,
+        innerSize.height,
         height,
-        message + " should have expected layout height."
+        message + " should have expected inner height."
       );
     }
   }
 }
--- a/devtools/client/webide/moz.build
+++ b/devtools/client/webide/moz.build
@@ -2,17 +2,16 @@
 # vim: set filetype=python:
 # 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/.
 
 DIRS += [
     'content',
     'modules',
-    'preferences',
     'themes',
 ]
 
 BROWSER_CHROME_MANIFESTS += [
     'test/browser.ini'
 ]
 MOCHITEST_CHROME_MANIFESTS += [
     'test/chrome.ini'
deleted file mode 100644
--- a/devtools/client/webide/preferences/moz.build
+++ /dev/null
@@ -1,9 +0,0 @@
-# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# 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/.
-
-JS_PREFERENCE_FILES += [
-    'webide.js',
-]
deleted file mode 100644
--- a/devtools/client/webide/preferences/webide.js
+++ /dev/null
@@ -1,13 +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/. */
-
-pref("devtools.webide.templatesURL", "https://code.cdn.mozilla.net/templates/list.json");
-pref("devtools.webide.autoinstallADBExtension", true);
-pref("devtools.webide.autoConnectRuntime", true);
-pref("devtools.webide.restoreLastProject", true);
-pref("devtools.webide.enableLocalRuntime", false);
-pref("devtools.webide.lastConnectedRuntime", "");
-pref("devtools.webide.lastSelectedProject", "");
-pref("devtools.webide.zoom", "1");
-pref("devtools.webide.busyTimeout", 10000);
--- a/devtools/docs/preferences.md
+++ b/devtools/docs/preferences.md
@@ -63,29 +63,22 @@ The main APIs you will have to know and 
 preference cannot be found and you didn't pass a default value!
 * `Services.pref.setIntPref(prefName, prefValue)` This method will throw if the provided
 value does not match the preference type!
 
 These APIs are very similar for each preference type.
 
 ## Create a new preference
 
-To create a new preference, it should be assigned a default value. Default preferences are
-defined in preferences files such as:
-- devtools/client/preferences/devtools-client.js
-- devtools/client/preferences/debugger.js
-- devtools/shared/preferences/devtools-shared.js
-- devtools/startup/preferences/devtools-startup.js
-
-Most new preferences should go in devtools/client/preferences/devtools-client.js. Debugger
-specific preferences should go in devtools/client/preferences/debugger.js. If a preference
-should be available even when the client for DevTools is not shipped (for instance on
-Fennec) the preference should go to devtools/shared/preferences/devtools-shared.js.
-Finally if a preference needs to be available very early during the Firefox startup
-sequence, it should go in devtools/startup/preferences/devtools-startup.js.
+Debugger-specific preferences should go in
+devtools/client/preferences/debugger.js. Beyond that, most new preferences
+should go in browser/app/profile/firefox.js, which is for desktop Firefox only.
+If a preference should be available even when the client for DevTools is not
+shipped (for instance on Fennec) it should go in modules/libpref/init/all.js,
+which is for preferences that go in all products.
 
 ### Projects using Launchpad
 
 At the time of writing this doc, projects using Launchpad have to duplicate the default
 definition of a preference.
 * debugger.html: update [src/utils/prefs.js](https://github.com/firefox-devtools/debugger.html/blob/master/src/utils/prefs.js)
 * netmonitor: update [index.js](http://searchfox.org/mozilla-central/source/devtools/client/netmonitor/index.js)
 * webconsole: update [local-dev/index.js](http://searchfox.org/mozilla-central/source/devtools/client/webconsole/local-dev/index.js)
deleted file mode 100644
--- a/devtools/shared/preferences/README.md
+++ /dev/null
@@ -1,4 +0,0 @@
-# How is devtools-shared loaded?
-
-This preference file is included via modules/libpref/greprefs.js which guarantees it will
-be loaded on all distributions, including xpcshell binary.
deleted file mode 100644
--- a/devtools/shared/preferences/devtools-shared.js
+++ /dev/null
@@ -1,73 +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/. */
-
-// Tells if DevTools have been explicitely enabled by the user.
-// This pref allows to disable all features related to DevTools
-// for users that never use them.
-// Until bug 1361080 lands, we always consider them enabled.
-pref("devtools.enabled", true);
-
-// Enable deprecation warnings.
-pref("devtools.errorconsole.deprecation_warnings", true);
-
-#ifdef NIGHTLY_BUILD
-// Don't show the Browser Toolbox prompt on local builds / nightly
-pref("devtools.debugger.prompt-connection", false, sticky);
-#else
-pref("devtools.debugger.prompt-connection", true, sticky);
-#endif
-
-#ifdef MOZILLA_OFFICIAL
-// Disable debugging chrome
-pref("devtools.chrome.enabled", false, sticky);
-// Disable remote debugging connections
-pref("devtools.debugger.remote-enabled", false, sticky);
-#else
-// In local builds, enable the browser toolbox by default
-pref("devtools.chrome.enabled", true, sticky);
-pref("devtools.debugger.remote-enabled", true, sticky);
-#endif
-
-// Disable remote debugging protocol logging
-pref("devtools.debugger.log", false);
-pref("devtools.debugger.log.verbose", false);
-
-pref("devtools.debugger.remote-port", 6000);
-pref("devtools.debugger.remote-websocket", false);
-// Force debugger server binding on the loopback interface
-pref("devtools.debugger.force-local", true);
-
-// Limit for intercepted request and response bodies (1 MB)
-// Possible values:
-// 0 => the response body has no limit
-// n => represents max number of bytes stored
-pref("devtools.netmonitor.responseBodyLimit", 1048576);
-pref("devtools.netmonitor.requestBodyLimit", 1048576);
-
-// Limit for WebSocket frames (100 KB)
-pref("devtools.netmonitor.ws.messageDataLimit", 100000);
-
-// DevTools default color unit
-pref("devtools.defaultColorUnit", "authored");
-
-// Used for devtools debugging
-pref("devtools.dump.emit", false);
-
-// Disable device discovery logging
-pref("devtools.discovery.log", false);
-// Whether to scan for DevTools devices via WiFi
-pref("devtools.remote.wifi.scan", true);
-// Client must complete TLS handshake within this window (ms)
-pref("devtools.remote.tls-handshake-timeout", 10000);
-
-// The extension ID for devtools-adb-extension
-pref("devtools.remote.adb.extensionID", "adb@mozilla.org");
-// The URL for for devtools-adb-extension (overridden in tests to a local path)
-pref("devtools.remote.adb.extensionURL", "https://ftp.mozilla.org/pub/mozilla.org/labs/devtools/adb-extension/#OS#/adb-extension-latest-#OS#.xpi");
-
-// URL of the remote JSON catalog used for device simulation
-pref("devtools.devices.url", "https://code.cdn.mozilla.net/devices/devices.json");
-
-// Enable Inactive CSS detection; used both by the client and the server.
-pref("devtools.inspector.inactive.css.enabled", true);
--- a/devtools/startup/moz.build
+++ b/devtools/startup/moz.build
@@ -1,20 +1,16 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
 JAR_MANIFESTS += ['jar.mn']
 
-DIRS += [
-    'preferences',
-]
-
 # Register the startup components only for 'all' builds.
 if CONFIG['MOZ_DEVTOOLS'] == 'all':
     EXTRA_JS_MODULES += [
         'AboutDebuggingRegistration.jsm',
         'AboutDevToolsToolboxRegistration.jsm',
         'DevToolsStartup.jsm',
     ]
 
deleted file mode 100644
--- a/devtools/startup/preferences/devtools-startup.js
+++ /dev/null
@@ -1,20 +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/. */
-
-// The preferences defined here should be used by the components in devtools-startup.
-// devtools-startup is always shipped and those preferences will always be available.
-
-// Enable the JSON View tool (an inspector for application/json documents).
-pref("devtools.jsonview.enabled", true);
-
-// Default theme ("dark" or "light")
-#ifdef MOZ_DEV_EDITION
-pref("devtools.theme", "dark", sticky);
-#else
-pref("devtools.theme", "light", sticky);
-#endif
-
-// Completely disable DevTools entry points, as well as all DevTools command line
-// arguments This should be merged with devtools.enabled, see Bug 1440675.
-pref("devtools.policy.disabled", false);
deleted file mode 100644
--- a/devtools/startup/preferences/moz.build
+++ /dev/null
@@ -1,9 +0,0 @@
-# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# 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/.
-
-JS_PREFERENCE_PP_FILES += [
-    'devtools-startup.js'
-]
--- a/dom/base/nsGlobalWindowOuter.cpp
+++ b/dom/base/nsGlobalWindowOuter.cpp
@@ -3569,33 +3569,23 @@ void nsGlobalWindowOuter::SetInnerHeight
 nsIntSize nsGlobalWindowOuter::GetOuterSize(CallerType aCallerType,
                                             ErrorResult& aError) {
   if (nsContentUtils::ResistFingerprinting(aCallerType)) {
     CSSIntSize size;
     aError = GetInnerSize(size);
     return nsIntSize(size.width, size.height);
   }
 
-  if (mDoc && mDoc->InRDMPane()) {
-    CSSIntSize size;
-    aError = GetInnerSize(size);
-
-    // Obtain the current zoom of the presentation shell. The zoom value will
-    // be used to scale the size of the visual viewport to the device browser's
-    // outer size values. Once RDM no longer relies on the having the page
-    // content being embedded in a <iframe mozbrowser>, we can do away with
-    // this approach and retrieve the size of the frame containing the browser
-    // content.
-    RefPtr<nsPresContext> presContext = mDocShell->GetPresContext();
-
-    if (presContext) {
-      float zoom = presContext->GetDeviceFullZoom();
-      int32_t width = std::round(size.width * zoom);
-      int32_t height = std::round(size.height * zoom);
-      return nsIntSize(width, height);
+  // Windows showing documents in RDM panes and any subframes within them
+  // return the simulated device size.
+  if (mDoc) {
+    Maybe<CSSIntSize> deviceSize = GetRDMDeviceSize(*mDoc);
+    if (deviceSize.isSome()) {
+      const CSSIntSize& size = deviceSize.value();
+      return nsIntSize(size.width, size.height);
     }
   }
 
   nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
   if (!treeOwnerAsWin) {
     aError.Throw(NS_ERROR_FAILURE);
     return nsIntSize(0, 0);
   }
@@ -3727,16 +3717,41 @@ nsRect nsGlobalWindowOuter::GetInnerScre
   nsIFrame* rootFrame = presShell->GetRootFrame();
   if (!rootFrame) {
     return nsRect();
   }
 
   return rootFrame->GetScreenRectInAppUnits();
 }
 
+Maybe<CSSIntSize> nsGlobalWindowOuter::GetRDMDeviceSize(
+    const Document& aDocument) {
+  // RDM device size should reflect the simulated device resolution, and
+  // be independent of any full zoom or resolution zoom applied to the
+  // content. To get this value, we get the unscaled browser child size.
+  MOZ_RELEASE_ASSERT(NS_IsMainThread());
+
+  Maybe<CSSIntSize> deviceSize;
+
+  // Bug 1576256: This does not work for cross-process subframes.
+  const Document* topInProcessContentDoc =
+      aDocument.GetTopLevelContentDocument();
+  if (topInProcessContentDoc && topInProcessContentDoc->InRDMPane()) {
+    nsIDocShell* docShell = topInProcessContentDoc->GetDocShell();
+    if (docShell) {
+      nsCOMPtr<nsIBrowserChild> child = docShell->GetBrowserChild();
+      if (child) {
+        BrowserChild* bc = static_cast<BrowserChild*>(child.get());
+        deviceSize = Some(bc->GetUnscaledInnerSize());
+      }
+    }
+  }
+  return deviceSize;
+}
+
 float nsGlobalWindowOuter::GetMozInnerScreenXOuter(CallerType aCallerType) {
   // When resisting fingerprinting, always return 0.
   if (nsContentUtils::ResistFingerprinting(aCallerType)) {
     return 0.0;
   }
 
   nsRect r = GetInnerScreenRect();
   return nsPresContext::AppUnitsToFloatCSSPixels(r.x);
@@ -4032,17 +4047,18 @@ Nullable<WindowProxyHolder> nsGlobalWind
   BrowsingContext* bc = GetBrowsingContext();
   return bc ? bc->GetTop(IgnoreErrors()) : nullptr;
 }
 
 already_AddRefed<BrowsingContext> nsGlobalWindowOuter::GetChildWindow(
     const nsAString& aName) {
   NS_ENSURE_TRUE(mBrowsingContext, nullptr);
 
-  return do_AddRef(mBrowsingContext->FindChildWithName(aName, *mBrowsingContext));
+  return do_AddRef(
+      mBrowsingContext->FindChildWithName(aName, *mBrowsingContext));
 }
 
 bool nsGlobalWindowOuter::DispatchCustomEvent(const nsAString& aEventName) {
   bool defaultActionEnabled = true;
   nsContentUtils::DispatchTrustedEvent(mDoc, ToSupports(this), aEventName,
                                        CanBubble::eYes, Cancelable::eYes,
                                        &defaultActionEnabled);
 
--- a/dom/base/nsGlobalWindowOuter.h
+++ b/dom/base/nsGlobalWindowOuter.h
@@ -883,16 +883,17 @@ class nsGlobalWindowOuter final : public
   // Outer windows only.
   nsresult GetInnerSize(mozilla::CSSIntSize& aSize);
   nsIntSize GetOuterSize(mozilla::dom::CallerType aCallerType,
                          mozilla::ErrorResult& aError);
   void SetOuterSize(int32_t aLengthCSSPixels, bool aIsWidth,
                     mozilla::dom::CallerType aCallerType,
                     mozilla::ErrorResult& aError);
   nsRect GetInnerScreenRect();
+  static Maybe<mozilla::CSSIntSize> GetRDMDeviceSize(const Document& aDocument);
 
   bool IsFrame();
 
   // Outer windows only.
   // If aLookForCallerOnJSStack is true, this method will look at the JS stack
   // to determine who the caller is.  If it's false, it'll use |this| as the
   // caller.
   bool WindowExists(const nsAString& aName, bool aForceNoOpener,
--- a/dom/base/nsIDocumentEncoder.idl
+++ b/dom/base/nsIDocumentEncoder.idl
@@ -274,17 +274,17 @@ interface nsIDocumentEncoder : nsISuppor
    *  character set when encoding the document.
    *
    *  Possible result codes: NS_ERROR_NO_CHARSET_CONVERTER
    */
   void setCharset(in ACString aCharset);
 
   /**
    *  Set a wrap column.  This may have no effect in some types of encoders.
-   * @param aWrapColumn Column to which to wrap.
+   * @param aWrapColumn Column to which to wrap. If 0, wrapping is disabled.
    */
   void setWrapColumn(in unsigned long aWrapColumn);
 
   /**
    *  The mime type preferred by the encoder.  This piece of api was
    *  added because the copy encoder may need to switch mime types on you
    *  if you ask it to copy html that really represents plaintext content.
    *  Call this AFTER Init() and SetSelection() have both been called.
--- a/dom/base/nsPlainTextSerializer.cpp
+++ b/dom/base/nsPlainTextSerializer.cpp
@@ -49,16 +49,18 @@ static const int32_t kIndentIncrementHea
                                               indent h(x+1) this many
                                               columns more than h(x) */
 static const int32_t kIndentSizeList = kTabSize;
 // Indention of non-first lines of ul and ol
 static const int32_t kIndentSizeDD = kTabSize;  // Indention of <dd>
 static const char16_t kNBSP = 160;
 static const char16_t kSPACE = ' ';
 
+constexpr int32_t kNoFlags = 0;
+
 static int32_t HeaderLevel(nsAtom* aTag);
 static int32_t GetUnicharWidth(char16_t ucs);
 static int32_t GetUnicharStringWidth(const char16_t* pwcs, int32_t n);
 
 // Someday may want to make this non-const:
 static const uint32_t TagStackSize = 500;
 static const uint32_t OLStackSize = 100;
 
@@ -76,18 +78,56 @@ NS_INTERFACE_MAP_END
 NS_IMPL_CYCLE_COLLECTION(nsPlainTextSerializer, mElement)
 
 nsresult NS_NewPlainTextSerializer(nsIContentSerializer** aSerializer) {
   RefPtr<nsPlainTextSerializer> it = new nsPlainTextSerializer();
   it.forget(aSerializer);
   return NS_OK;
 }
 
+// @param aFlags As defined in nsIDocumentEncoder.idl.
+static void DetermineLineBreak(const int32_t aFlags, nsAString& aLineBreak) {
+  // Set the line break character:
+  if ((aFlags & nsIDocumentEncoder::OutputCRLineBreak) &&
+      (aFlags & nsIDocumentEncoder::OutputLFLineBreak)) {
+    // Windows
+    aLineBreak.AssignLiteral(u"\r\n");
+  } else if (aFlags & nsIDocumentEncoder::OutputCRLineBreak) {
+    // Mac
+    aLineBreak.AssignLiteral(u"\r");
+  } else if (aFlags & nsIDocumentEncoder::OutputLFLineBreak) {
+    // Unix/DOM
+    aLineBreak.AssignLiteral(u"\n");
+  } else {
+    // Platform/default
+    aLineBreak.AssignLiteral(NS_ULINEBREAK);
+  }
+}
+
+nsPlainTextSerializer::CurrentLineContent::CurrentLineContent(
+    const int32_t aFlags)
+    : mFlags(aFlags) {
+  DetermineLineBreak(mFlags, mLineBreak);
+}
+
+void nsPlainTextSerializer::CurrentLineContent::MaybeReplaceNbsps() {
+  if (!(mFlags & nsIDocumentEncoder::OutputPersistNBSP)) {
+    // First, replace all nbsp characters with spaces,
+    // which the unicode encoder won't do for us.
+    mValue.ReplaceChar(kNBSP, kSPACE);
+  }
+}
+
+void nsPlainTextSerializer::CurrentLineContent::AppendLineBreak() {
+  mValue.Append(mLineBreak);
+}
+
 nsPlainTextSerializer::nsPlainTextSerializer()
-    : mFloatingLines(-1),
+    : mCurrentLineContent{kNoFlags},
+      mFloatingLines(-1),
       mLineBreakDue(false),
       kSpace(NS_LITERAL_STRING(" "))  // Init of "constant"
 {
   mOutputString = nullptr;
   mHeadLevel = 0;
   mAtFirstColumn = true;
   mIndent = 0;
   mCiteQuoteLevel = 0;
@@ -131,17 +171,17 @@ nsPlainTextSerializer::nsPlainTextSerial
 
 nsPlainTextSerializer::~nsPlainTextSerializer() {
   delete[] mTagStack;
   delete[] mOLStack;
   NS_WARNING_ASSERTION(mHeadLevel == 0, "Wrong head level!");
 }
 
 NS_IMETHODIMP
-nsPlainTextSerializer::Init(uint32_t aFlags, uint32_t aWrapColumn,
+nsPlainTextSerializer::Init(const uint32_t aFlags, uint32_t aWrapColumn,
                             const Encoding* aEncoding, bool aIsCopying,
                             bool aIsWholeDocument,
                             bool* aNeedsPreformatScanning) {
 #ifdef DEBUG
   // Check if the major control flags are set correctly.
   if (aFlags & nsIDocumentEncoder::OutputFormatFlowed) {
     NS_ASSERTION(aFlags & nsIDocumentEncoder::OutputFormatted,
                  "If you want format=flowed, you must combine it with "
@@ -159,32 +199,16 @@ nsPlainTextSerializer::Init(uint32_t aFl
   mSettings.mFlags = aFlags;
   mWrapColumn = aWrapColumn;
 
   // Only create a linebreaker if we will handle wrapping.
   if (MayWrap() && MayBreakLines()) {
     mLineBreaker = nsContentUtils::LineBreaker();
   }
 
-  // Set the line break character:
-  if ((mSettings.mFlags & nsIDocumentEncoder::OutputCRLineBreak) &&
-      (mSettings.mFlags & nsIDocumentEncoder::OutputLFLineBreak)) {
-    // Windows
-    mLineBreak.AssignLiteral("\r\n");
-  } else if (mSettings.mFlags & nsIDocumentEncoder::OutputCRLineBreak) {
-    // Mac
-    mLineBreak.Assign(char16_t('\r'));
-  } else if (mSettings.mFlags & nsIDocumentEncoder::OutputLFLineBreak) {
-    // Unix/DOM
-    mLineBreak.Assign(char16_t('\n'));
-  } else {
-    // Platform/default
-    mLineBreak.AssignLiteral(NS_LINEBREAK);
-  }
-
   mLineBreakDue = false;
   mFloatingLines = -1;
 
   mPreformattedBlockBoundary = false;
 
   if (mSettings.mFlags & nsIDocumentEncoder::OutputFormatted) {
     // Get some prefs that controls how we do formatted output
     mSettings.mStructs = Preferences::GetBool(PREF_STRUCTS, mSettings.mStructs);
@@ -198,16 +222,18 @@ nsPlainTextSerializer::Init(uint32_t aFl
   // other places which use this serializer currently.
   mSettings.mWithRubyAnnotation =
       gAlwaysIncludeRuby ||
       (mSettings.mFlags & nsIDocumentEncoder::OutputRubyAnnotation);
 
   // XXX We should let the caller decide whether to do this or not
   mSettings.mFlags &= ~nsIDocumentEncoder::OutputNoFramesContent;
 
+  mCurrentLineContent = CurrentLineContent{mSettings.mFlags};
+
   return NS_OK;
 }
 
 bool nsPlainTextSerializer::GetLastBool(const nsTArray<bool>& aStack) {
   uint32_t size = aStack.Length();
   if (size == 0) {
     return false;
   }
@@ -312,17 +338,17 @@ nsPlainTextSerializer::AppendText(nsICon
   int32_t offset = textstr.FindCharInSet("\n\r");
   while (offset != kNotFound) {
     if (offset > start) {
       // Pass in the line
       DoAddText(false, Substring(textstr, start, offset - start));
     }
 
     // Pass in a newline
-    DoAddText(true, mLineBreak);
+    DoAddText();
 
     start = offset + 1;
     offset = textstr.FindCharInSet("\n\r", start);
   }
 
   // Consume the last bit of the string if there's any left
   if (start < length) {
     if (start) {
@@ -946,16 +972,18 @@ bool nsPlainTextSerializer::MustSuppress
     // Might be nice, eventually, to output just the selected element.
     // Read more in bug 31994.
     return true;
   }
 
   return false;
 }
 
+void nsPlainTextSerializer::DoAddText() { DoAddText(true, EmptyString()); }
+
 void nsPlainTextSerializer::DoAddText(bool aIsLineBreak,
                                       const nsAString& aText) {
   // If we don't want any output, just return
   if (!DoOutput()) {
     return;
   }
 
   if (!aIsLineBreak) {
@@ -1087,33 +1115,24 @@ void nsPlainTextSerializer::EnsureVertic
  * at the start of the line.
  */
 void nsPlainTextSerializer::FlushLine() {
   if (!mCurrentLineContent.mValue.IsEmpty()) {
     if (mAtFirstColumn) {
       OutputQuotesAndIndent();  // XXX: Should we always do this? Bug?
     }
 
-    MaybeReplaceNbspsForOutput(mCurrentLineContent.mValue);
+    mCurrentLineContent.MaybeReplaceNbsps();
     Output(mCurrentLineContent.mValue);
-    mAtFirstColumn = mAtFirstColumn && mCurrentLineContent.mValue.IsEmpty();
+    mAtFirstColumn = false;
     mCurrentLineContent.mValue.Truncate();
     mCurrentLineContent.mWidth = 0;
   }
 }
 
-void nsPlainTextSerializer::MaybeReplaceNbspsForOutput(
-    nsString& aString) const {
-  if (!(mSettings.mFlags & nsIDocumentEncoder::OutputPersistNBSP)) {
-    // First, replace all nbsp characters with spaces,
-    // which the unicode encoder won't do for us.
-    aString.ReplaceChar(kNBSP, kSPACE);
-  }
-}
-
 void nsPlainTextSerializer::Output(nsString& aString) {
   mOutputString->Append(aString);
 }
 
 static bool IsSpaceStuffable(const char16_t* s) {
   if (s[0] == '>' || s[0] == ' ' || s[0] == kNBSP ||
       NS_strncmp(s, u"From ", 5) == 0)
     return true;
@@ -1356,18 +1375,18 @@ void nsPlainTextSerializer::EndLine(bool
   if (mAtFirstColumn) {
     // If we don't have anything "real" to output we have to
     // make sure the indent doesn't end in a space since that
     // would trick a format=flowed-aware receiver.
     bool stripTrailingSpaces = mCurrentLineContent.mValue.IsEmpty();
     OutputQuotesAndIndent(stripTrailingSpaces);
   }
 
-  mCurrentLineContent.mValue.Append(mLineBreak);
-  MaybeReplaceNbspsForOutput(mCurrentLineContent.mValue);
+  mCurrentLineContent.MaybeReplaceNbsps();
+  mCurrentLineContent.AppendLineBreak();
   Output(mCurrentLineContent.mValue);
   mCurrentLineContent.mValue.Truncate();
   mCurrentLineContent.mWidth = 0;
   mAtFirstColumn = true;
   mInWhitespace = true;
   mLineBreakDue = false;
   mFloatingLines = -1;
 }
@@ -1391,47 +1410,45 @@ void nsPlainTextSerializer::OutputQuotes
       /* Better don't output a space here, if the line is empty,
          in case a receiving f=f-aware UA thinks, this were a flowed line,
          which it isn't - it's just empty.
          (Flowed lines may be joined with the following one,
          so the empty line may be lost completely.) */
       quotes.Append(char16_t(' '));
     }
     stringToOutput = quotes;
-    mAtFirstColumn = false;
   }
 
   // Indent if necessary
   int32_t indentwidth = mIndent - mInIndentString.Length();
   if (indentwidth > 0 &&
       (!mCurrentLineContent.mValue.IsEmpty() || !mInIndentString.IsEmpty())
       // Don't make empty lines look flowed
   ) {
     nsAutoString spaces;
     for (int i = 0; i < indentwidth; ++i) spaces.Append(char16_t(' '));
     stringToOutput += spaces;
-    mAtFirstColumn = false;
   }
 
   if (!mInIndentString.IsEmpty()) {
     stringToOutput += mInIndentString;
-    mAtFirstColumn = false;
     mInIndentString.Truncate();
   }
 
   if (stripTrailingSpaces) {
     int32_t lineLength = stringToOutput.Length();
     while (lineLength > 0 && ' ' == stringToOutput[lineLength - 1]) {
       --lineLength;
     }
     stringToOutput.SetLength(lineLength);
   }
 
   if (!stringToOutput.IsEmpty()) {
     Output(stringToOutput);
+    mAtFirstColumn = false;
   }
 }
 
 /**
  * Write a string. This is the highlevel function to use to get text output.
  * By using AddToLine, Output, EndLine and other functions it handles quotation,
  * line wrapping, indentation, whitespace compression and other things.
  */
@@ -1554,21 +1571,22 @@ void nsPlainTextSerializer::Write(const 
       }
       mCurrentLineContent.mValue.Append(stringpart);
 
       if (outputQuotes) {
         // Note: this call messes with mAtFirstColumn
         OutputQuotesAndIndent();
       }
 
-      MaybeReplaceNbspsForOutput(mCurrentLineContent.mValue);
-      Output(mCurrentLineContent.mValue);
+      mCurrentLineContent.MaybeReplaceNbsps();
       if (outputLineBreak) {
-        Output(mLineBreak);
+        mCurrentLineContent.AppendLineBreak();
       }
+      Output(mCurrentLineContent.mValue);
+
       mAtFirstColumn = atFirstColumn;
     }
 
     // Reset mCurrentLineContent.mValue.
     mCurrentLineContent.mValue.Truncate();
 
 #ifdef DEBUG_wrapping
     printf("No wrapping: newline is %d, totLen is %d\n", newline, totLen);
--- a/dom/base/nsPlainTextSerializer.h
+++ b/dom/base/nsPlainTextSerializer.h
@@ -84,18 +84,16 @@ class nsPlainTextSerializer final : publ
 
   nsresult GetAttributeValue(nsAtom* aName, nsString& aValueRet);
   void AddToLine(const char16_t* aStringToAdd, int32_t aLength);
   void EndLine(bool softlinebreak, bool aBreakBySpace = false);
   void EnsureVerticalSpace(int32_t noOfRows);
   void FlushLine();
   void OutputQuotesAndIndent(bool stripTrailingSpaces = false);
 
-  void MaybeReplaceNbspsForOutput(nsString& aString) const;
-
   void Output(nsString& aString);
   void Write(const nsAString& aString);
 
   // @return true, iff the elements' whitespace and newline characters have to
   //         be preserved according to its style or because it's a `<pre>`
   //         element.
   bool IsElementPreformatted() const;
   bool IsInOL();
@@ -105,25 +103,28 @@ class nsPlainTextSerializer final : publ
   /**
    * Returns the local name of the element as an atom if the element is an
    * HTML element and the atom is a static atom. Otherwise, nullptr is returned.
    */
   static nsAtom* GetIdForContent(nsIContent* aContent);
   nsresult DoOpenContainer(nsAtom* aTag);
   nsresult DoCloseContainer(nsAtom* aTag);
   nsresult DoAddLeaf(nsAtom* aTag);
-  void DoAddText(bool aIsWhitespace, const nsAString& aText);
+
+  void DoAddText();
+  // @param aText Ignored if aIsLineBreak is true.
+  void DoAddText(bool aIsLineBreak, const nsAString& aText);
 
   // Inlined functions
-  inline bool MayWrap() {
+  inline bool MayWrap() const {
     return mWrapColumn &&
            ((mSettings.mFlags & nsIDocumentEncoder::OutputFormatted) ||
             (mSettings.mFlags & nsIDocumentEncoder::OutputWrap));
   }
-  inline bool MayBreakLines() {
+  inline bool MayBreakLines() const {
     return !(mSettings.mFlags & nsIDocumentEncoder::OutputDisallowLineBreaking);
   }
 
   inline bool DoOutput() const { return mHeadLevel == 0; }
 
   inline bool IsQuotedLine(const nsAString& aLine) {
     return !aLine.IsEmpty() && aLine.First() == char16_t('>');
   }
@@ -163,22 +164,36 @@ class nsPlainTextSerializer final : publ
     int32_t mFlags = 0;
 
     // Whether the output should include ruby annotations.
     bool mWithRubyAnnotation = false;
   };
 
   Settings mSettings;
 
-  struct CurrentLineContent {
-    // Excludes indentation and quotes.
+  // Excludes indentation and quotes.
+  class CurrentLineContent {
+   public:
+    // @param aFlags As defined in nsIDocumentEncoder.idl.
+    explicit CurrentLineContent(int32_t aFlags);
+
+    void MaybeReplaceNbsps();
+
+    void AppendLineBreak();
+
     nsString mValue;
 
     // The width of the line as it will appear on the screen (approx.).
     uint32_t mWidth = 0;
+
+   private:
+    // As defined in nsIDocumentEncoder.idl.
+    int32_t mFlags;
+
+    nsString mLineBreak;
   };
 
   CurrentLineContent mCurrentLineContent;
 
   // If we've just written out a cite blockquote, we need to remember it
   // so we don't duplicate spaces before a <pre wrap> (which mail uses to quote
   // old messages).
   bool mHasWrittenCiteBlockquote;
@@ -248,17 +263,16 @@ class nsPlainTextSerializer final : publ
   uint32_t mIgnoreAboveIndex;
 
   // The stack for ordered lists
   int32_t* mOLStack;
   uint32_t mOLStackIndex;
 
   uint32_t mULCount;
 
-  nsString mLineBreak;
   RefPtr<mozilla::intl::LineBreaker> mLineBreaker;
 
   // Conveniance constant. It would be nice to have it as a const static
   // variable, but that causes issues with OpenBSD and module unloading.
   const nsString kSpace;
 
   // mIgnoredChildNodeLevel is used to tell if current node is an ignorable
   // child node. The initial value of mIgnoredChildNodeLevel is 0. When
--- a/dom/base/nsScreen.cpp
+++ b/dom/base/nsScreen.cpp
@@ -81,16 +81,32 @@ nsDeviceContext* nsScreen::GetDeviceCont
 }
 
 nsresult nsScreen::GetRect(nsRect& aRect) {
   // Return window inner rect to prevent fingerprinting.
   if (ShouldResistFingerprinting()) {
     return GetWindowInnerRect(aRect);
   }
 
+  // Here we manipulate the value of aRect to represent the screen size,
+  // if in RDM.
+  nsCOMPtr<nsPIDOMWindowInner> owner = GetOwner();
+  if (owner) {
+    mozilla::dom::Document* doc = owner->GetExtantDoc();
+    if (doc) {
+      Maybe<mozilla::CSSIntSize> deviceSize =
+          nsGlobalWindowOuter::GetRDMDeviceSize(*doc);
+      if (deviceSize.isSome()) {
+        const mozilla::CSSIntSize& size = deviceSize.value();
+        aRect.SetRect(0, 0, size.width, size.height);
+        return NS_OK;
+      }
+    }
+  }
+
   nsDeviceContext* context = GetDeviceContext();
 
   if (!context) {
     return NS_ERROR_FAILURE;
   }
 
   context->GetRect(aRect);
   LayoutDevicePoint screenTopLeftDev = LayoutDevicePixel::FromAppUnits(
@@ -108,20 +124,30 @@ nsresult nsScreen::GetRect(nsRect& aRect
 }
 
 nsresult nsScreen::GetAvailRect(nsRect& aRect) {
   // Return window inner rect to prevent fingerprinting.
   if (ShouldResistFingerprinting()) {
     return GetWindowInnerRect(aRect);
   }
 
-  // Here we manipulate the value of aRect to represent the screen avail size,
+  // Here we manipulate the value of aRect to represent the screen size,
   // if in RDM.
-  if (IsInRDMPane()) {
-    return GetRDMScreenSize(aRect);
+  nsCOMPtr<nsPIDOMWindowInner> owner = GetOwner();
+  if (owner) {
+    mozilla::dom::Document* doc = owner->GetExtantDoc();
+    if (doc) {
+      Maybe<mozilla::CSSIntSize> deviceSize =
+          nsGlobalWindowOuter::GetRDMDeviceSize(*doc);
+      if (deviceSize.isSome()) {
+        const mozilla::CSSIntSize& size = deviceSize.value();
+        aRect.SetRect(0, 0, size.width, size.height);
+        return NS_OK;
+      }
+    }
   }
 
   nsDeviceContext* context = GetDeviceContext();
 
   if (!context) {
     return NS_ERROR_FAILURE;
   }
 
@@ -140,39 +166,16 @@ nsresult nsScreen::GetAvailRect(nsRect& 
             nsPresContext::AppUnitsToIntCSSPixels(aRect.y - r.y);
 
   aRect.SetHeight(nsPresContext::AppUnitsToIntCSSPixels(aRect.Height()));
   aRect.SetWidth(nsPresContext::AppUnitsToIntCSSPixels(aRect.Width()));
 
   return NS_OK;
 }
 
-nsresult nsScreen::GetRDMScreenSize(nsRect& aRect) {
-  GetWindowInnerRect(aRect);
-
-  // GetOwner(), GetDocShell(), and GetPresContext() can potentially return
-  // nullptr, so to be safe let's make sure we check these before proceeding.
-  nsCOMPtr<nsPIDOMWindowInner> owner = GetOwner();
-  if (owner) {
-    nsIDocShell* docShell = owner->GetDocShell();
-    if (docShell) {
-      RefPtr<nsPresContext> presContext = docShell->GetPresContext();
-      if (presContext) {
-        float zoom = presContext->GetDeviceFullZoom();
-        int32_t width = std::round(aRect.Width() * zoom);
-        int32_t height = std::round(aRect.Height() * zoom);
-        aRect.SetHeight(height);
-        aRect.SetWidth(width);
-        return NS_OK;
-      }
-    }
-  }
-  return NS_ERROR_FAILURE;
-}
-
 mozilla::dom::ScreenOrientation* nsScreen::Orientation() const {
   return mScreenOrientation;
 }
 
 void nsScreen::GetMozOrientation(nsString& aOrientation,
                                  CallerType aCallerType) const {
   switch (mScreenOrientation->DeviceType(aCallerType)) {
     case OrientationType::Portrait_primary:
@@ -276,26 +279,16 @@ bool nsScreen::MozLockOrientation(const 
 void nsScreen::MozUnlockOrientation() {
   if (ShouldResistFingerprinting()) {
     return;
   }
   UpdateDocShellOrientationLock(GetOwner(), hal::eScreenOrientation_None);
   mScreenOrientation->UnlockDeviceOrientation();
 }
 
-bool nsScreen::IsDeviceSizePageSize() {
-  if (nsPIDOMWindowInner* owner = GetOwner()) {
-    nsIDocShell* docShell = owner->GetDocShell();
-    if (docShell) {
-      return docShell->GetDeviceSizeIsPageSize();
-    }
-  }
-  return false;
-}
-
 /* virtual */
 JSObject* nsScreen::WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aGivenProto) {
   return Screen_Binding::Wrap(aCx, this, aGivenProto);
 }
 
 nsresult nsScreen::GetWindowInnerRect(nsRect& aRect) {
   aRect.x = 0;
@@ -312,20 +305,8 @@ nsresult nsScreen::GetWindowInnerRect(ns
 bool nsScreen::ShouldResistFingerprinting() const {
   bool resist = false;
   nsCOMPtr<nsPIDOMWindowInner> owner = GetOwner();
   if (owner) {
     resist = nsContentUtils::ShouldResistFingerprinting(owner->GetDocShell());
   }
   return resist;
 }
-
-bool nsScreen::IsInRDMPane() const {
-  bool isInRDM = false;
-  nsCOMPtr<nsPIDOMWindowInner> owner = GetOwner();
-
-  if (owner) {
-    Document* doc = owner->GetExtantDoc();
-    isInRDM = doc && doc->InRDMPane();
-  }
-
-  return isInRDM;
-}
--- a/dom/base/nsScreen.h
+++ b/dom/base/nsScreen.h
@@ -42,48 +42,22 @@ class nsScreen : public mozilla::DOMEven
   int32_t GetLeft(ErrorResult& aRv) {
     nsRect rect;
     aRv = GetRect(rect);
     return rect.x;
   }
 
   int32_t GetWidth(ErrorResult& aRv) {
     nsRect rect;
-    if (IsDeviceSizePageSize()) {
-      if (IsInRDMPane()) {
-        GetRDMScreenSize(rect);
-        return rect.Width();
-      }
-
-      if (nsCOMPtr<nsPIDOMWindowInner> owner = GetOwner()) {
-        int32_t innerWidth = 0;
-        aRv = owner->GetInnerWidth(&innerWidth);
-        return innerWidth;
-      }
-    }
-
     aRv = GetRect(rect);
     return rect.Width();
   }
 
   int32_t GetHeight(ErrorResult& aRv) {
     nsRect rect;
-    if (IsDeviceSizePageSize()) {
-      if (IsInRDMPane()) {
-        GetRDMScreenSize(rect);
-        return rect.Height();
-      }
-
-      if (nsCOMPtr<nsPIDOMWindowInner> owner = GetOwner()) {
-        int32_t innerHeight = 0;
-        aRv = owner->GetInnerHeight(&innerHeight);
-        return innerHeight;
-      }
-    }
-
     aRv = GetRect(rect);
     return rect.Height();
   }
 
   int32_t GetPixelDepth(ErrorResult& aRv);
   int32_t GetColorDepth(ErrorResult& aRv) { return GetPixelDepth(aRv); }
 
   int32_t GetAvailTop(ErrorResult& aRv) {
@@ -141,24 +115,21 @@ class nsScreen : public mozilla::DOMEven
 
   mozilla::dom::ScreenOrientation* Orientation() const;
 
  protected:
   nsDeviceContext* GetDeviceContext();
   nsresult GetRect(nsRect& aRect);
   nsresult GetAvailRect(nsRect& aRect);
   nsresult GetWindowInnerRect(nsRect& aRect);
-  nsresult GetRDMScreenSize(nsRect& aRect);
 
  private:
   explicit nsScreen(nsPIDOMWindowInner* aWindow);
   virtual ~nsScreen();
 
-  bool IsDeviceSizePageSize();
-
   bool ShouldResistFingerprinting() const;
 
-  bool IsInRDMPane() const;
+  mozilla::dom::Document* TopContentDocumentInRDMPane() const;
 
   RefPtr<mozilla::dom::ScreenOrientation> mScreenOrientation;
 };
 
 #endif /* nsScreen_h___ */
new file mode 100644
--- /dev/null
+++ b/dom/base/test/bug1576154.sjs
@@ -0,0 +1,8 @@
+function handleRequest(request, response)
+{
+  response.setStatusLine("1.1", 500, "Internal Server Error");
+  response.setHeader("Content-Type", "image/svg+xml", false);
+
+  let body = "<svg xmlns='http://www.w3.org/2000/svg' width='70' height='0'></svg>";
+  response.bodyOutputStream.write(body, body.length);
+}
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..7df25f33bdb26cc7f41138501ab399059839137d
GIT binary patch
literal 255
zc%17D@N?(olHy`uVBq!ia0vp^DIm<j1SJ1AFfjuu&H|6fVg?3oVGw3ym^DWND9B#o
z>FdgVmrY2>Os;yW$XlS$JWm(LkcwMxFBmd1FmNz0$ozjU>fm{HrGS|QSGZD6PEz%r
zro*}k!eEMoFdB8hjHM3Kz>FXTZ!kl1f-0CHassR?l5*|8wspoc9#?7J!~=9GgQu&X
J%Q~loCICH_Rq+4-
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -47,16 +47,17 @@ support-files =
   bug638112-response.txt
   bug638112.sjs
   bug696301-script-1.js
   bug696301-script-1.js^headers^
   bug696301-script-2.js
   bug704320.sjs
   bug704320_counter.sjs
   bug819051.sjs
+  bug1576154.sjs
   chrome/bug418986-1.js
   copypaste.js
   delayedServerEvents.sjs
   eventsource.resource
   eventsource.resource^headers^
   eventsource_redirect.resource
   eventsource_redirect.resource^headers^
   eventsource_redirect_to.resource
@@ -239,16 +240,17 @@ support-files =
   file2_setting_opener.html
   file3_setting_opener.html
   file4_setting_opener.html
   PASS.html
   FAIL.html
   !/dom/animation/test/testcommon.js
   !/dom/events/test/event_leak_utils.js
   ../../../browser/extensions/pdfjs/test/file_pdfjs_test.pdf
+  green.png
 
 [test_anchor_area_referrer.html]
 [test_anchor_area_referrer_changing.html]
 [test_anchor_area_referrer_invalid.html]
 [test_anchor_area_referrer_rel.html]
 [test_anonymousContent_api.html]
 [test_anonymousContent_append_after_reflow.html]
 [test_anonymousContent_canvas.html]
@@ -629,16 +631,17 @@ skip-if = toolkit == 'android'
 [test_bug1404385.html]
 [test_bug1406102.html]
 [test_bug1421568.html]
 [test_bug1453693.html]
 skip-if = os == "mac" # Different tab focus behavior on mac
 [test_bug1472427.html]
 [test_bug1499169.html]
 skip-if = toolkit == 'android' # Timeouts on android due to page closing issues with embedded pdf
+[test_bug1576154.html]
 [test_caretPositionFromPoint.html]
 [test_change_policy.html]
 [test_clearTimeoutIntervalNoArg.html]
 [test_constructor-assignment.html]
 [test_constructor.html]
 [test_content_iterator_post_order.html]
 [test_content_iterator_pre_order.html]
 [test_content_iterator_subtree.html]
new file mode 100644
--- /dev/null
+++ b/dom/base/test/test_bug1576154.html
@@ -0,0 +1,36 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1576154
+-->
+<head>
+  <title>Test for Bug 1576154</title>
+  <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+  <script src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1576154">Mozilla Bug 1576154</a>
+<p id="display"></p>
+<!-- bug1576154.sjs returns an SVG image with HTTP error code 500. -->
+<img src="bug1576154.sjs">
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 657191 **/
+SimpleTest.waitForExplicitFinish();
+
+window.onload = function() {
+  let img = document.querySelector("img");
+  img.src = "green.png";
+  img.onload = function() {
+    // As long as this doesn't crash, this test passes.
+    ok(true, "test passed");
+    SimpleTest.finish();
+  };
+}
+
+</script>
+</pre>
+</body>
+</html>
--- a/dom/ipc/BrowserChild.h
+++ b/dom/ipc/BrowserChild.h
@@ -541,16 +541,17 @@ class BrowserChild final : public nsMess
   bool IPCOpen() const { return mIPCOpen; }
 
   bool ParentIsActive() const { return mParentIsActive; }
 
   const mozilla::layers::CompositorOptions& GetCompositorOptions() const;
   bool AsyncPanZoomEnabled() const;
 
   ScreenIntSize GetInnerSize();
+  CSSIntSize GetUnscaledInnerSize() { return RoundedToInt(mUnscaledInnerSize); }
 
   Maybe<LayoutDeviceIntRect> GetVisibleRect() const;
 
   // Call RecvShow(nsIntSize(0, 0)) and block future calls to RecvShow().
   void DoFakeShow(const ShowInfo& aShowInfo);
 
   void ContentReceivedInputBlock(uint64_t aInputBlockId,
                                  bool aPreventDefault) const;
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -4066,18 +4066,19 @@ nsresult HTMLEditRules::MakeList(nsAtom&
     // Make sure we can put a list here.
     if (!HTMLEditorRef().CanContainTag(*atStartOfSelection.GetContainer(),
                                        aListType)) {
       *aCancel = true;
       return NS_OK;
     }
 
     SplitNodeResult splitAtSelectionStartResult =
-        MaybeSplitAncestorsForInsertWithTransaction(aListType,
-                                                    atStartOfSelection);
+        MOZ_KnownLive(HTMLEditorRef())
+            .MaybeSplitAncestorsForInsertWithTransaction(aListType,
+                                                         atStartOfSelection);
     if (NS_WARN_IF(splitAtSelectionStartResult.Failed())) {
       return splitAtSelectionStartResult.Rv();
     }
     RefPtr<Element> theList =
         MOZ_KnownLive(HTMLEditorRef())
             .CreateNodeWithTransaction(
                 aListType, splitAtSelectionStartResult.SplitPoint());
     if (NS_WARN_IF(!CanHandleEditAction())) {
@@ -4351,17 +4352,19 @@ nsresult HTMLEditRules::MakeList(nsAtom&
       }
       listCount = arrayOfNodes.Length();
       continue;
     }
 
     // need to make a list to put things in if we haven't already,
     if (!curList) {
       SplitNodeResult splitCurNodeResult =
-          MaybeSplitAncestorsForInsertWithTransaction(aListType, atCurNode);
+          MOZ_KnownLive(HTMLEditorRef())
+              .MaybeSplitAncestorsForInsertWithTransaction(aListType,
+                                                           atCurNode);
       if (NS_WARN_IF(splitCurNodeResult.Failed())) {
         return splitCurNodeResult.Rv();
       }
       curList = MOZ_KnownLive(HTMLEditorRef())
                     .CreateNodeWithTransaction(aListType,
                                                splitCurNodeResult.SplitPoint());
       if (NS_WARN_IF(!CanHandleEditAction())) {
         return NS_ERROR_EDITOR_DESTROYED;
@@ -4665,18 +4668,19 @@ nsresult HTMLEditRules::MakeBasicBlock(n
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
       // We don't need to act on this node any more
       arrayOfNodes.RemoveElement(brNode);
     }
     // Make sure we can put a block here.
     SplitNodeResult splitNodeResult =
-        MaybeSplitAncestorsForInsertWithTransaction(blockType,
-                                                    pointToInsertBlock);
+        MOZ_KnownLive(HTMLEditorRef())
+            .MaybeSplitAncestorsForInsertWithTransaction(blockType,
+                                                         pointToInsertBlock);
     if (NS_WARN_IF(splitNodeResult.Failed())) {
       return splitNodeResult.Rv();
     }
     RefPtr<Element> block =
         MOZ_KnownLive(HTMLEditorRef())
             .CreateNodeWithTransaction(blockType, splitNodeResult.SplitPoint());
     if (NS_WARN_IF(!CanHandleEditAction())) {
       return NS_ERROR_EDITOR_DESTROYED;
@@ -4709,28 +4713,31 @@ nsresult HTMLEditRules::MakeBasicBlock(n
       return rv;
     }
     return NS_OK;
   }
   // Okay, now go through all the nodes and make the right kind of blocks, or
   // whatever is approriate.  Woohoo!  Note: blockquote is handled a little
   // differently.
   if (&blockType == nsGkAtoms::blockquote) {
-    rv = MakeBlockquote(arrayOfNodes);
+    rv = MOZ_KnownLive(HTMLEditorRef())
+             .MoveNodesIntoNewBlockquoteElement(arrayOfNodes);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   } else if (&blockType == nsGkAtoms::normal ||
              &blockType == nsGkAtoms::_empty) {
-    rv = RemoveBlockStyle(arrayOfNodes);
+    rv = MOZ_KnownLive(HTMLEditorRef())
+             .RemoveBlockContainerElements(arrayOfNodes);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   } else {
-    rv = ApplyBlockStyle(arrayOfNodes, blockType);
+    rv = MOZ_KnownLive(HTMLEditorRef())
+             .CreateOrChangeBlockContainerElement(arrayOfNodes, blockType);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
   return NS_OK;
 }
 
 nsresult HTMLEditRules::DidMakeBasicBlock() {
@@ -4861,18 +4868,19 @@ nsresult HTMLEditRules::IndentAroundSele
 
     EditorDOMPoint atStartOfSelection(firstRange->StartRef());
     if (NS_WARN_IF(!atStartOfSelection.IsSet())) {
       return NS_ERROR_FAILURE;
     }
 
     // make sure we can put a block here
     SplitNodeResult splitNodeResult =
-        MaybeSplitAncestorsForInsertWithTransaction(*nsGkAtoms::div,
-                                                    atStartOfSelection);
+        MOZ_KnownLive(HTMLEditorRef())
+            .MaybeSplitAncestorsForInsertWithTransaction(*nsGkAtoms::div,
+                                                         atStartOfSelection);
     if (NS_WARN_IF(splitNodeResult.Failed())) {
       return splitNodeResult.Rv();
     }
     RefPtr<Element> theBlock =
         MOZ_KnownLive(HTMLEditorRef())
             .CreateNodeWithTransaction(*nsGkAtoms::div,
                                        splitNodeResult.SplitPoint());
     if (NS_WARN_IF(!CanHandleEditAction())) {
@@ -4984,18 +4992,19 @@ nsresult HTMLEditRules::IndentAroundSele
         sibling = HTMLEditorRef().GetPriorHTMLSibling(curNode);
       }
 
       if (!curList || (sibling && sibling != curList)) {
         nsAtom* containerName =
             atCurNode.GetContainer()->NodeInfo()->NameAtom();
         // Create a new nested list of correct type.
         SplitNodeResult splitNodeResult =
-            MaybeSplitAncestorsForInsertWithTransaction(
-                MOZ_KnownLive(*containerName), atCurNode);
+            MOZ_KnownLive(HTMLEditorRef())
+                .MaybeSplitAncestorsForInsertWithTransaction(
+                    MOZ_KnownLive(*containerName), atCurNode);
         if (NS_WARN_IF(splitNodeResult.Failed())) {
           return splitNodeResult.Rv();
         }
         curList = MOZ_KnownLive(HTMLEditorRef())
                       .CreateNodeWithTransaction(MOZ_KnownLive(*containerName),
                                                  splitNodeResult.SplitPoint());
         if (NS_WARN_IF(!CanHandleEditAction())) {
           return NS_ERROR_EDITOR_DESTROYED;
@@ -5037,18 +5046,19 @@ nsresult HTMLEditRules::IndentAroundSele
     if (!curQuote) {
       // First, check that our element can contain a div.
       if (!HTMLEditorRef().CanContainTag(*atCurNode.GetContainer(),
                                          *nsGkAtoms::div)) {
         return NS_OK;  // cancelled
       }
 
       SplitNodeResult splitNodeResult =
-          MaybeSplitAncestorsForInsertWithTransaction(*nsGkAtoms::div,
-                                                      atCurNode);
+          MOZ_KnownLive(HTMLEditorRef())
+              .MaybeSplitAncestorsForInsertWithTransaction(*nsGkAtoms::div,
+                                                           atCurNode);
       if (NS_WARN_IF(splitNodeResult.Failed())) {
         return splitNodeResult.Rv();
       }
       curQuote = MOZ_KnownLive(HTMLEditorRef())
                      .CreateNodeWithTransaction(*nsGkAtoms::div,
                                                 splitNodeResult.SplitPoint());
       if (NS_WARN_IF(!CanHandleEditAction())) {
         return NS_ERROR_EDITOR_DESTROYED;
@@ -5154,18 +5164,19 @@ nsresult HTMLEditRules::IndentAroundSele
 
     EditorDOMPoint atStartOfSelection(firstRange->StartRef());
     if (NS_WARN_IF(!atStartOfSelection.IsSet())) {
       return NS_ERROR_FAILURE;
     }
 
     // Make sure we can put a block here.
     SplitNodeResult splitNodeResult =
-        MaybeSplitAncestorsForInsertWithTransaction(*nsGkAtoms::blockquote,
-                                                    atStartOfSelection);
+        MOZ_KnownLive(HTMLEditorRef())
+            .MaybeSplitAncestorsForInsertWithTransaction(*nsGkAtoms::blockquote,
+                                                         atStartOfSelection);
     if (NS_WARN_IF(splitNodeResult.Failed())) {
       return splitNodeResult.Rv();
     }
     RefPtr<Element> theBlock =
         MOZ_KnownLive(HTMLEditorRef())
             .CreateNodeWithTransaction(*nsGkAtoms::blockquote,
                                        splitNodeResult.SplitPoint());
     if (NS_WARN_IF(!CanHandleEditAction())) {
@@ -5270,18 +5281,19 @@ nsresult HTMLEditRules::IndentAroundSele
         sibling = HTMLEditorRef().GetPriorHTMLSibling(curNode);
       }
 
       if (!curList || (sibling && sibling != curList)) {
         nsAtom* containerName =
             atCurNode.GetContainer()->NodeInfo()->NameAtom();
         // Create a new nested list of correct type.
         SplitNodeResult splitNodeResult =
-            MaybeSplitAncestorsForInsertWithTransaction(
-                MOZ_KnownLive(*containerName), atCurNode);
+            MOZ_KnownLive(HTMLEditorRef())
+                .MaybeSplitAncestorsForInsertWithTransaction(
+                    MOZ_KnownLive(*containerName), atCurNode);
         if (NS_WARN_IF(splitNodeResult.Failed())) {
           return splitNodeResult.Rv();
         }
         curList = MOZ_KnownLive(HTMLEditorRef())
                       .CreateNodeWithTransaction(MOZ_KnownLive(*containerName),
                                                  splitNodeResult.SplitPoint());
         if (NS_WARN_IF(!CanHandleEditAction())) {
           return NS_ERROR_EDITOR_DESTROYED;
@@ -5334,18 +5346,19 @@ nsresult HTMLEditRules::IndentAroundSele
         EditorDOMPoint atListItem(listItem);
         if (NS_WARN_IF(!listItem)) {
           return NS_ERROR_FAILURE;
         }
         nsAtom* containerName =
             atListItem.GetContainer()->NodeInfo()->NameAtom();
         // Create a new nested list of correct type.
         SplitNodeResult splitNodeResult =
-            MaybeSplitAncestorsForInsertWithTransaction(
-                MOZ_KnownLive(*containerName), atListItem);
+            MOZ_KnownLive(HTMLEditorRef())
+                .MaybeSplitAncestorsForInsertWithTransaction(
+                    MOZ_KnownLive(*containerName), atListItem);
         if (NS_WARN_IF(splitNodeResult.Failed())) {
           return splitNodeResult.Rv();
         }
         curList = MOZ_KnownLive(HTMLEditorRef())
                       .CreateNodeWithTransaction(MOZ_KnownLive(*containerName),
                                                  splitNodeResult.SplitPoint());
         if (NS_WARN_IF(!CanHandleEditAction())) {
           return NS_ERROR_EDITOR_DESTROYED;
@@ -5381,18 +5394,19 @@ nsresult HTMLEditRules::IndentAroundSele
     if (!curQuote) {
       // First, check that our element can contain a blockquote.
       if (!HTMLEditorRef().CanContainTag(*atCurNode.GetContainer(),
                                          *nsGkAtoms::blockquote)) {
         return NS_OK;  // cancelled
       }
 
       SplitNodeResult splitNodeResult =
-          MaybeSplitAncestorsForInsertWithTransaction(*nsGkAtoms::blockquote,
-                                                      atCurNode);
+          MOZ_KnownLive(HTMLEditorRef())
+              .MaybeSplitAncestorsForInsertWithTransaction(
+                  *nsGkAtoms::blockquote, atCurNode);
       if (NS_WARN_IF(splitNodeResult.Failed())) {
         return splitNodeResult.Rv();
       }
       curQuote = MOZ_KnownLive(HTMLEditorRef())
                      .CreateNodeWithTransaction(*nsGkAtoms::blockquote,
                                                 splitNodeResult.SplitPoint());
       if (NS_WARN_IF(!CanHandleEditAction())) {
         return NS_ERROR_EDITOR_DESTROYED;
@@ -5805,87 +5819,83 @@ SplitRangeOffFromNodeResult HTMLEditRule
                          curBlockQuoteIsIndentedWithCSS);
   if (NS_WARN_IF(outdentResult.Failed())) {
     return outdentResult;
   }
   return outdentResult;
 }
 
 SplitRangeOffFromNodeResult
-HTMLEditRules::SplitRangeOffFromBlockAndRemoveMiddleContainer(
+HTMLEditor::SplitRangeOffFromBlockAndRemoveMiddleContainer(
     Element& aBlockElement, nsIContent& aStartOfRange,
     nsIContent& aEndOfRange) {
-  MOZ_ASSERT(IsEditorDataAvailable());
+  MOZ_ASSERT(IsEditActionDataAvailable());
 
   SplitRangeOffFromNodeResult splitResult =
       SplitRangeOffFromBlock(aBlockElement, aStartOfRange, aEndOfRange);
   if (NS_WARN_IF(splitResult.Rv() == NS_ERROR_EDITOR_DESTROYED)) {
     return splitResult;
   }
   NS_WARNING_ASSERTION(splitResult.Succeeded(),
                        "Failed to split the range off from the block element");
-  nsresult rv = MOZ_KnownLive(HTMLEditorRef())
-                    .RemoveBlockContainerWithTransaction(aBlockElement);
-  if (NS_WARN_IF(!CanHandleEditAction())) {
+  nsresult rv = RemoveBlockContainerWithTransaction(aBlockElement);
+  if (NS_WARN_IF(Destroyed())) {
     return SplitRangeOffFromNodeResult(NS_ERROR_EDITOR_DESTROYED);
   }
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return SplitRangeOffFromNodeResult(rv);
   }
   return SplitRangeOffFromNodeResult(splitResult.GetLeftContent(), nullptr,
                                      splitResult.GetRightContent());
 }
 
-SplitRangeOffFromNodeResult HTMLEditRules::SplitRangeOffFromBlock(
+SplitRangeOffFromNodeResult HTMLEditor::SplitRangeOffFromBlock(
     Element& aBlockElement, nsIContent& aStartOfMiddleElement,
     nsIContent& aEndOfMiddleElement) {
-  MOZ_ASSERT(IsEditorDataAvailable());
+  MOZ_ASSERT(IsEditActionDataAvailable());
 
   // aStartOfMiddleElement and aEndOfMiddleElement must be exclusive
   // descendants of aBlockElement.
   MOZ_ASSERT(EditorUtils::IsDescendantOf(aStartOfMiddleElement, aBlockElement));
   MOZ_ASSERT(EditorUtils::IsDescendantOf(aEndOfMiddleElement, aBlockElement));
 
   // Split at the start.
-  SplitNodeResult splitAtStartResult =
-      MOZ_KnownLive(HTMLEditorRef())
-          .SplitNodeDeepWithTransaction(
-              aBlockElement, EditorDOMPoint(&aStartOfMiddleElement),
-              SplitAtEdges::eDoNotCreateEmptyContainer);
-  if (NS_WARN_IF(!CanHandleEditAction())) {
+  SplitNodeResult splitAtStartResult = SplitNodeDeepWithTransaction(
+      aBlockElement, EditorDOMPoint(&aStartOfMiddleElement),
+      SplitAtEdges::eDoNotCreateEmptyContainer);
+  if (NS_WARN_IF(Destroyed())) {
     return SplitRangeOffFromNodeResult(NS_ERROR_EDITOR_DESTROYED);
   }
   NS_WARNING_ASSERTION(splitAtStartResult.Succeeded(),
                        "Failed to split aBlockElement at start");
 
   // Split at after the end
   EditorDOMPoint atAfterEnd(&aEndOfMiddleElement);
   DebugOnly<bool> advanced = atAfterEnd.AdvanceOffset();
   NS_WARNING_ASSERTION(advanced, "Failed to advance offset after the end node");
-  SplitNodeResult splitAtEndResult =
-      MOZ_KnownLive(HTMLEditorRef())
-          .SplitNodeDeepWithTransaction(
-              aBlockElement, atAfterEnd,
-              SplitAtEdges::eDoNotCreateEmptyContainer);
-  if (NS_WARN_IF(!CanHandleEditAction())) {
+  SplitNodeResult splitAtEndResult = SplitNodeDeepWithTransaction(
+      aBlockElement, atAfterEnd, SplitAtEdges::eDoNotCreateEmptyContainer);
+  if (NS_WARN_IF(Destroyed())) {
     return SplitRangeOffFromNodeResult(NS_ERROR_EDITOR_DESTROYED);
   }
   NS_WARNING_ASSERTION(splitAtEndResult.Succeeded(),
                        "Failed to split aBlockElement at after end");
 
   return SplitRangeOffFromNodeResult(splitAtStartResult, splitAtEndResult);
 }
 
 SplitRangeOffFromNodeResult HTMLEditRules::OutdentPartOfBlock(
     Element& aBlockElement, nsIContent& aStartOfOutdent,
     nsIContent& aEndOfOutdent, bool aIsBlockIndentedWithCSS) {
   MOZ_ASSERT(IsEditorDataAvailable());
 
   SplitRangeOffFromNodeResult splitResult =
-      SplitRangeOffFromBlock(aBlockElement, aStartOfOutdent, aEndOfOutdent);
+      MOZ_KnownLive(HTMLEditorRef())
+          .SplitRangeOffFromBlock(aBlockElement, aStartOfOutdent,
+                                  aEndOfOutdent);
   if (NS_WARN_IF(splitResult.Rv() == NS_ERROR_EDITOR_DESTROYED)) {
     return SplitRangeOffFromNodeResult(NS_ERROR_EDITOR_DESTROYED);
   }
 
   if (NS_WARN_IF(!splitResult.GetMiddleContentAsElement())) {
     return SplitRangeOffFromNodeResult(NS_ERROR_FAILURE);
   }
 
@@ -6205,18 +6215,19 @@ nsresult HTMLEditRules::AlignContentsAtS
     }
 
     EditorDOMPoint atStartOfSelection(firstRange->StartRef());
     if (NS_WARN_IF(!atStartOfSelection.IsSet())) {
       return NS_ERROR_FAILURE;
     }
 
     SplitNodeResult splitNodeResult =
-        MaybeSplitAncestorsForInsertWithTransaction(*nsGkAtoms::div,
-                                                    atStartOfSelection);
+        MOZ_KnownLive(HTMLEditorRef())
+            .MaybeSplitAncestorsForInsertWithTransaction(*nsGkAtoms::div,
+                                                         atStartOfSelection);
     if (NS_WARN_IF(splitNodeResult.Failed())) {
       return splitNodeResult.Rv();
     }
 
     // Consume a trailing br, if any.  This is to keep an alignment from
     // creating extra lines, if possible.
     nsCOMPtr<nsIContent> brContent =
         HTMLEditorRef().GetNextEditableHTMLNodeInBlock(
@@ -6376,18 +6387,19 @@ nsresult HTMLEditRules::AlignContentsAtS
       // First, check that our element can contain a div.
       if (!HTMLEditorRef().CanContainTag(*atCurNode.GetContainer(),
                                          *nsGkAtoms::div)) {
         // Cancelled
         return NS_OK;
       }
 
       SplitNodeResult splitNodeResult =
-          MaybeSplitAncestorsForInsertWithTransaction(*nsGkAtoms::div,
-                                                      atCurNode);
+          MOZ_KnownLive(HTMLEditorRef())
+              .MaybeSplitAncestorsForInsertWithTransaction(*nsGkAtoms::div,
+                                                           atCurNode);
       if (NS_WARN_IF(splitNodeResult.Failed())) {
         return splitNodeResult.Rv();
       }
       curDiv = MOZ_KnownLive(HTMLEditorRef())
                    .CreateNodeWithTransaction(*nsGkAtoms::div,
                                               splitNodeResult.SplitPoint());
       if (NS_WARN_IF(!CanHandleEditAction())) {
         return NS_ERROR_EDITOR_DESTROYED;
@@ -8679,19 +8691,19 @@ nsresult HTMLEditRules::ReturnInListItem
     return NS_ERROR_EDITOR_DESTROYED;
   }
   if (NS_WARN_IF(error.Failed())) {
     return error.StealNSResult();
   }
   return NS_OK;
 }
 
-nsresult HTMLEditRules::MakeBlockquote(
+nsresult HTMLEditor::MoveNodesIntoNewBlockquoteElement(
     nsTArray<OwningNonNull<nsINode>>& aNodeArray) {
-  MOZ_ASSERT(IsEditorDataAvailable());
+  MOZ_ASSERT(IsTopLevelEditSubActionDataAvailable());
 
   // The idea here is to put the nodes into a minimal number of blockquotes.
   // When the user blockquotes something, they expect one blockquote.  That
   // may not be possible (for instance, if they have two table cells selected,
   // you need two blockquotes inside the cells).
   RefPtr<Element> curBlock;
   nsCOMPtr<nsINode> prevParent;
 
@@ -8704,17 +8716,17 @@ nsresult HTMLEditRules::MakeBlockquote(
     // If the node is a table element or list item, dive inside
     if (HTMLEditUtils::IsTableElementButNotTable(curNode) ||
         HTMLEditUtils::IsListItem(curNode)) {
       // Forget any previous block
       curBlock = nullptr;
       // Recursion time
       AutoTArray<OwningNonNull<nsINode>, 24> childNodes;
       HTMLEditor::GetChildNodesOf(*curNode, childNodes);
-      nsresult rv = MakeBlockquote(childNodes);
+      nsresult rv = MoveNodesIntoNewBlockquoteElement(childNodes);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
     }
 
     // If the node has different parent than previous node, further nodes in a
     // new parent
     if (prevParent) {
@@ -8730,47 +8742,47 @@ nsresult HTMLEditRules::MakeBlockquote(
     // If no curBlock, make one
     if (!curBlock) {
       SplitNodeResult splitNodeResult =
           MaybeSplitAncestorsForInsertWithTransaction(*nsGkAtoms::blockquote,
                                                       EditorDOMPoint(curNode));
       if (NS_WARN_IF(splitNodeResult.Failed())) {
         return splitNodeResult.Rv();
       }
-      curBlock = MOZ_KnownLive(HTMLEditorRef())
-                     .CreateNodeWithTransaction(*nsGkAtoms::blockquote,
-                                                splitNodeResult.SplitPoint());
-      if (NS_WARN_IF(!CanHandleEditAction())) {
+      // XXX Perhaps, we should insert the new `<blockquote>` element after
+      //     moving all nodes into it since the movement does not cause
+      //     running mutation event listeners.
+      curBlock = CreateNodeWithTransaction(*nsGkAtoms::blockquote,
+                                           splitNodeResult.SplitPoint());
+      if (NS_WARN_IF(Destroyed())) {
         return NS_ERROR_EDITOR_DESTROYED;
       }
       if (NS_WARN_IF(!curBlock)) {
         return NS_ERROR_FAILURE;
       }
       // remember our new block for postprocessing
-      HTMLEditorRef().TopLevelEditSubActionDataRef().mNewBlockElement =
-          curBlock;
+      TopLevelEditSubActionDataRef().mNewBlockElement = curBlock;
       // note: doesn't matter if we set mNewBlockElement multiple times.
     }
 
-    nsresult rv = MOZ_KnownLive(HTMLEditorRef())
-                      .MoveNodeToEndWithTransaction(
-                          MOZ_KnownLive(*curNode->AsContent()), *curBlock);
-    if (NS_WARN_IF(!CanHandleEditAction())) {
+    nsresult rv = MoveNodeToEndWithTransaction(
+        MOZ_KnownLive(*curNode->AsContent()), *curBlock);
+    if (NS_WARN_IF(Destroyed())) {
       return NS_ERROR_EDITOR_DESTROYED;
     }
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
   return NS_OK;
 }
 
-nsresult HTMLEditRules::RemoveBlockStyle(
+nsresult HTMLEditor::RemoveBlockContainerElements(
     nsTArray<OwningNonNull<nsINode>>& aNodeArray) {
-  MOZ_ASSERT(IsEditorDataAvailable());
+  MOZ_ASSERT(IsEditActionDataAvailable());
 
   // Intent of this routine is to be used for converting to/from headers,
   // paragraphs, pre, and address.  Those blocks that pretty much just contain
   // inline things...
   nsCOMPtr<Element> curBlock;
   nsCOMPtr<nsIContent> firstNode, lastNode;
   for (auto& curNode : aNodeArray) {
     // If curNode is an <address>, <p>, <hn>, or <pre>, remove it.
@@ -8780,24 +8792,23 @@ nsresult HTMLEditRules::RemoveBlockStyle
         SplitRangeOffFromNodeResult removeMiddleContainerResult =
             SplitRangeOffFromBlockAndRemoveMiddleContainer(
                 *curBlock, *firstNode, *lastNode);
         if (NS_WARN_IF(removeMiddleContainerResult.Failed())) {
           return removeMiddleContainerResult.Rv();
         }
         firstNode = lastNode = curBlock = nullptr;
       }
-      if (!HTMLEditorRef().IsEditable(curNode)) {
+      if (!IsEditable(curNode)) {
         continue;
       }
       // Remove current block
-      nsresult rv = MOZ_KnownLive(HTMLEditorRef())
-                        .RemoveBlockContainerWithTransaction(
-                            MOZ_KnownLive(*curNode->AsElement()));
-      if (NS_WARN_IF(!CanHandleEditAction())) {
+      nsresult rv = RemoveBlockContainerWithTransaction(
+          MOZ_KnownLive(*curNode->AsElement()));
+      if (NS_WARN_IF(Destroyed())) {
         return NS_ERROR_EDITOR_DESTROYED;
       }
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
       continue;
     }
 
@@ -8811,23 +8822,23 @@ nsresult HTMLEditRules::RemoveBlockStyle
         SplitRangeOffFromNodeResult removeMiddleContainerResult =
             SplitRangeOffFromBlockAndRemoveMiddleContainer(
                 *curBlock, *firstNode, *lastNode);
         if (NS_WARN_IF(removeMiddleContainerResult.Failed())) {
           return removeMiddleContainerResult.Rv();
         }
         firstNode = lastNode = curBlock = nullptr;
       }
-      if (!HTMLEditorRef().IsEditable(curNode)) {
+      if (!IsEditable(curNode)) {
         continue;
       }
       // Recursion time
       AutoTArray<OwningNonNull<nsINode>, 24> childNodes;
       HTMLEditor::GetChildNodesOf(*curNode, childNodes);
-      nsresult rv = RemoveBlockStyle(childNodes);
+      nsresult rv = RemoveBlockContainerElements(childNodes);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
       continue;
     }
 
     if (HTMLEditor::NodeIsInlineStatic(curNode)) {
       if (curBlock) {
@@ -8844,19 +8855,19 @@ nsresult HTMLEditRules::RemoveBlockStyle
             SplitRangeOffFromBlockAndRemoveMiddleContainer(
                 *curBlock, *firstNode, *lastNode);
         if (NS_WARN_IF(removeMiddleContainerResult.Failed())) {
           return removeMiddleContainerResult.Rv();
         }
         firstNode = lastNode = curBlock = nullptr;
         // Fall out and handle curNode
       }
-      curBlock = HTMLEditorRef().GetBlockNodeParent(curNode);
+      curBlock = GetBlockNodeParent(curNode);
       if (!curBlock || !HTMLEditUtils::IsFormatNode(curBlock) ||
-          !HTMLEditorRef().IsEditable(curBlock)) {
+          !IsEditable(curBlock)) {
         // Not a block kind that we care about.
         curBlock = nullptr;
       } else {
         firstNode = lastNode = curNode->AsContent();
       }
       continue;
     }
 
@@ -8881,59 +8892,56 @@ nsresult HTMLEditRules::RemoveBlockStyle
     if (NS_WARN_IF(removeMiddleContainerResult.Failed())) {
       return removeMiddleContainerResult.Rv();
     }
     firstNode = lastNode = curBlock = nullptr;
   }
   return NS_OK;
 }
 
-nsresult HTMLEditRules::ApplyBlockStyle(
+nsresult HTMLEditor::CreateOrChangeBlockContainerElement(
     nsTArray<OwningNonNull<nsINode>>& aNodeArray, nsAtom& aBlockTag) {
+  MOZ_ASSERT(IsTopLevelEditSubActionDataAvailable());
+
   // Intent of this routine is to be used for converting to/from headers,
   // paragraphs, pre, and address.  Those blocks that pretty much just contain
   // inline things...
-  MOZ_ASSERT(IsEditorDataAvailable());
-
   nsCOMPtr<Element> newBlock;
-
   nsCOMPtr<Element> curBlock;
   for (auto& curNode : aNodeArray) {
     if (NS_WARN_IF(!curNode->GetParent())) {
       // If given node has been removed from the document, let's ignore it
       // since the following code may need its parent replace it with new
       // block.
       curBlock = nullptr;
       newBlock = nullptr;
       continue;
     }
 
     EditorDOMPoint atCurNode(curNode);
 
     // Is it already the right kind of block, or an uneditable block?
     if (curNode->IsHTMLElement(&aBlockTag) ||
-        (!HTMLEditorRef().IsEditable(curNode) &&
-         HTMLEditor::NodeIsBlockStatic(curNode))) {
+        (!IsEditable(curNode) && HTMLEditor::NodeIsBlockStatic(curNode))) {
       // Forget any previous block used for previous inline nodes
       curBlock = nullptr;
       // Do nothing to this block
       continue;
     }
 
     // If curNode is a address, p, header, address, or pre, replace it with a
     // new block of correct type.
     // XXX: pre can't hold everything the others can
     if (HTMLEditUtils::IsMozDiv(curNode) ||
         HTMLEditUtils::IsFormatNode(curNode)) {
       // Forget any previous block used for previous inline nodes
       curBlock = nullptr;
-      newBlock = MOZ_KnownLive(HTMLEditorRef())
-                     .ReplaceContainerAndCloneAttributesWithTransaction(
-                         MOZ_KnownLive(*curNode->AsElement()), aBlockTag);
-      if (NS_WARN_IF(!CanHandleEditAction())) {
+      newBlock = ReplaceContainerAndCloneAttributesWithTransaction(
+          MOZ_KnownLive(*curNode->AsElement()), aBlockTag);
+      if (NS_WARN_IF(Destroyed())) {
         return NS_ERROR_EDITOR_DESTROYED;
       }
       if (NS_WARN_IF(!newBlock)) {
         return NS_ERROR_FAILURE;
       }
       // If the new block element was moved to different element or removed by
       // the web app via mutation event listener, we should stop handling this
       // action since we cannot handle each of a lot of edge cases.
@@ -8948,17 +8956,18 @@ nsresult HTMLEditRules::ApplyBlockStyle(
                                      nsGkAtoms::td, nsGkAtoms::li,
                                      nsGkAtoms::blockquote, nsGkAtoms::div)) {
       // Forget any previous block used for previous inline nodes
       curBlock = nullptr;
       // Recursion time
       AutoTArray<OwningNonNull<nsINode>, 24> childNodes;
       HTMLEditor::GetChildNodesOf(*curNode, childNodes);
       if (!childNodes.IsEmpty()) {
-        nsresult rv = ApplyBlockStyle(childNodes, aBlockTag);
+        nsresult rv =
+            CreateOrChangeBlockContainerElement(childNodes, aBlockTag);
         if (NS_WARN_IF(NS_FAILED(rv))) {
           return rv;
         }
         continue;
       }
 
       // Make sure we can put a block here
       SplitNodeResult splitNodeResult =
@@ -8970,45 +8979,42 @@ nsresult HTMLEditRules::ApplyBlockStyle(
       // mutation event listener when we need to do something more for it,
       // we should stop handling this action since we cannot handle each of
       // a lot of edge cases.
       if (NS_WARN_IF(atCurNode.HasChildMovedFromContainer())) {
         return NS_ERROR_EDITOR_UNEXPECTED_DOM_TREE;
       }
       EditorDOMPoint splitPoint = splitNodeResult.SplitPoint();
       RefPtr<Element> theBlock =
-          MOZ_KnownLive(HTMLEditorRef())
-              .CreateNodeWithTransaction(aBlockTag, splitPoint);
-      if (NS_WARN_IF(!CanHandleEditAction())) {
+          CreateNodeWithTransaction(aBlockTag, splitPoint);
+      if (NS_WARN_IF(Destroyed())) {
         return NS_ERROR_EDITOR_DESTROYED;
       }
       if (NS_WARN_IF(!theBlock)) {
         return NS_ERROR_FAILURE;
       }
       // If the new block element was moved to different element or removed by
       // the web app via mutation event listener, we should stop handling this
       // action since we cannot handle each of a lot of edge cases.
       if (NS_WARN_IF(theBlock->GetParentNode() != splitPoint.GetContainer())) {
         return NS_ERROR_EDITOR_UNEXPECTED_DOM_TREE;
       }
       // Remember our new block for postprocessing
-      HTMLEditorRef().TopLevelEditSubActionDataRef().mNewBlockElement =
-          std::move(theBlock);
+      TopLevelEditSubActionDataRef().mNewBlockElement = std::move(theBlock);
       continue;
     }
 
     if (curNode->IsHTMLElement(nsGkAtoms::br)) {
       // If the node is a break, we honor it by putting further nodes in a new
       // parent
       if (curBlock) {
         // Forget any previous block used for previous inline nodes
         curBlock = nullptr;
-        nsresult rv =
-            MOZ_KnownLive(HTMLEditorRef()).DeleteNodeWithTransaction(*curNode);
-        if (NS_WARN_IF(!CanHandleEditAction())) {
+        nsresult rv = DeleteNodeWithTransaction(*curNode);
+        if (NS_WARN_IF(Destroyed())) {
           return NS_ERROR_EDITOR_DESTROYED;
         }
         if (NS_WARN_IF(NS_FAILED(rv))) {
           return rv;
         }
         continue;
       }
 
@@ -9022,56 +9028,52 @@ nsresult HTMLEditRules::ApplyBlockStyle(
       // If current handling node has been moved from the container by a
       // mutation event listener when we need to do something more for it,
       // we should stop handling this action since we cannot handle each of
       // a lot of edge cases.
       if (NS_WARN_IF(atCurNode.HasChildMovedFromContainer())) {
         return NS_ERROR_EDITOR_UNEXPECTED_DOM_TREE;
       }
       EditorDOMPoint splitPoint = splitNodeResult.SplitPoint();
-      curBlock = MOZ_KnownLive(HTMLEditorRef())
-                     .CreateNodeWithTransaction(aBlockTag, splitPoint);
-      if (NS_WARN_IF(!CanHandleEditAction())) {
+      curBlock = CreateNodeWithTransaction(aBlockTag, splitPoint);
+      if (NS_WARN_IF(Destroyed())) {
         return NS_ERROR_EDITOR_DESTROYED;
       }
       if (NS_WARN_IF(!curBlock)) {
         return NS_ERROR_FAILURE;
       }
       // If the new block element was moved to different element or removed by
       // the web app via mutation event listener, we should stop handling this
       // action since we cannot handle each of a lot of edge cases.
       if (NS_WARN_IF(curBlock->GetParentNode() != splitPoint.GetContainer())) {
         return NS_ERROR_EDITOR_UNEXPECTED_DOM_TREE;
       }
       // Remember our new block for postprocessing
-      HTMLEditorRef().TopLevelEditSubActionDataRef().mNewBlockElement =
-          curBlock;
+      TopLevelEditSubActionDataRef().mNewBlockElement = curBlock;
       // Note: doesn't matter if we set mNewBlockElement multiple times.
-      nsresult rv = MOZ_KnownLive(HTMLEditorRef())
-                        .MoveNodeToEndWithTransaction(
-                            MOZ_KnownLive(*curNode->AsContent()), *curBlock);
-      if (NS_WARN_IF(!CanHandleEditAction())) {
+      nsresult rv = MoveNodeToEndWithTransaction(
+          MOZ_KnownLive(*curNode->AsContent()), *curBlock);
+      if (NS_WARN_IF(Destroyed())) {
         return NS_ERROR_EDITOR_DESTROYED;
       }
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
       continue;
     }
 
     if (HTMLEditor::NodeIsInlineStatic(curNode)) {
       // If curNode is inline, pull it into curBlock.  Note: it's assumed that
       // consecutive inline nodes in aNodeArray are actually members of the
       // same block parent.  This happens to be true now as a side effect of
       // how aNodeArray is contructed, but some additional logic should be
       // added here if that should change
       //
       // If curNode is a non editable, drop it if we are going to <pre>.
-      if (&aBlockTag == nsGkAtoms::pre &&
-          !HTMLEditorRef().IsEditable(curNode)) {
+      if (&aBlockTag == nsGkAtoms::pre && !IsEditable(curNode)) {
         // Do nothing to this block
         continue;
       }
 
       // If no curBlock, make one
       if (!curBlock) {
         SplitNodeResult splitNodeResult =
             MaybeSplitAncestorsForInsertWithTransaction(aBlockTag, atCurNode);
@@ -9081,19 +9083,18 @@ nsresult HTMLEditRules::ApplyBlockStyle(
         // If current handling node has been moved from the container by a
         // mutation event listener when we need to do something more for it,
         // we should stop handling this action since we cannot handle each of
         // a lot of edge cases.
         if (NS_WARN_IF(atCurNode.HasChildMovedFromContainer())) {
           return NS_ERROR_EDITOR_UNEXPECTED_DOM_TREE;
         }
         EditorDOMPoint splitPoint = splitNodeResult.SplitPoint();
-        curBlock = MOZ_KnownLive(HTMLEditorRef())
-                       .CreateNodeWithTransaction(aBlockTag, splitPoint);
-        if (NS_WARN_IF(!CanHandleEditAction())) {
+        curBlock = CreateNodeWithTransaction(aBlockTag, splitPoint);
+        if (NS_WARN_IF(Destroyed())) {
           return NS_ERROR_EDITOR_DESTROYED;
         }
         if (NS_WARN_IF(!curBlock)) {
           return NS_ERROR_FAILURE;
         }
         // If the new block element was moved to different element or removed
         // by the web app via mutation event listener, we should stop handling
         // this action since we cannot handle each of a lot of edge cases.
@@ -9101,54 +9102,52 @@ nsresult HTMLEditRules::ApplyBlockStyle(
                        splitPoint.GetContainer())) {
           return NS_ERROR_EDITOR_UNEXPECTED_DOM_TREE;
         }
 
         // Update container of curNode.
         atCurNode.Set(curNode);
 
         // Remember our new block for postprocessing
-        HTMLEditorRef().TopLevelEditSubActionDataRef().mNewBlockElement =
-            curBlock;
+        TopLevelEditSubActionDataRef().mNewBlockElement = curBlock;
         // Note: doesn't matter if we set mNewBlockElement multiple times.
       }
 
       if (NS_WARN_IF(!atCurNode.IsSet())) {
         // This is possible due to mutation events, let's not assert
         return NS_ERROR_UNEXPECTED;
       }
 
       // XXX If curNode is a br, replace it with a return if going to <pre>
 
       // This is a continuation of some inline nodes that belong together in
       // the same block item.  Use curBlock.
-      nsresult rv = MOZ_KnownLive(HTMLEditorRef())
-                        .MoveNodeToEndWithTransaction(
-                            MOZ_KnownLive(*curNode->AsContent()), *curBlock);
-      if (NS_WARN_IF(!CanHandleEditAction())) {
+      nsresult rv = MoveNodeToEndWithTransaction(
+          MOZ_KnownLive(*curNode->AsContent()), *curBlock);
+      if (NS_WARN_IF(Destroyed())) {
         return NS_ERROR_EDITOR_DESTROYED;
       }
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
     }
   }
   return NS_OK;
 }
 
-SplitNodeResult HTMLEditRules::MaybeSplitAncestorsForInsertWithTransaction(
+SplitNodeResult HTMLEditor::MaybeSplitAncestorsForInsertWithTransaction(
     nsAtom& aTag, const EditorDOMPoint& aStartOfDeepestRightNode) {
-  MOZ_ASSERT(IsEditorDataAvailable());
+  MOZ_ASSERT(IsEditActionDataAvailable());
 
   if (NS_WARN_IF(!aStartOfDeepestRightNode.IsSet())) {
     return SplitNodeResult(NS_ERROR_INVALID_ARG);
   }
   MOZ_ASSERT(aStartOfDeepestRightNode.IsSetAndValid());
 
-  RefPtr<Element> host = HTMLEditorRef().GetActiveEditingHost();
+  RefPtr<Element> host = GetActiveEditingHost();
   if (NS_WARN_IF(!host)) {
     return SplitNodeResult(NS_ERROR_FAILURE);
   }
 
   // The point must be descendant of editing host.
   if (NS_WARN_IF(aStartOfDeepestRightNode.GetContainer() != host &&
                  !EditorUtils::IsDescendantOf(
                      *aStartOfDeepestRightNode.GetContainer(), *host))) {
@@ -9160,38 +9159,35 @@ SplitNodeResult HTMLEditRules::MaybeSpli
   for (; pointToInsert.IsSet();
        pointToInsert.Set(pointToInsert.GetContainer())) {
     // We cannot split active editing host and its ancestor.  So, there is
     // no element to contain the specified element.
     if (NS_WARN_IF(pointToInsert.GetChild() == host)) {
       return SplitNodeResult(NS_ERROR_FAILURE);
     }
 
-    if (HTMLEditorRef().CanContainTag(*pointToInsert.GetContainer(), aTag)) {
+    if (CanContainTag(*pointToInsert.GetContainer(), aTag)) {
       // Found an ancestor node which can contain the element.
       break;
     }
   }
 
   MOZ_DIAGNOSTIC_ASSERT(pointToInsert.IsSet());
 
   // If the point itself can contain the tag, we don't need to split any
   // ancestor nodes.  In this case, we should return the given split point
   // as is.
   if (pointToInsert.GetContainer() == aStartOfDeepestRightNode.GetContainer()) {
     return SplitNodeResult(aStartOfDeepestRightNode);
   }
 
-  SplitNodeResult splitNodeResult =
-      MOZ_KnownLive(HTMLEditorRef())
-          .SplitNodeDeepWithTransaction(
-              MOZ_KnownLive(*pointToInsert.GetChild()),
-              aStartOfDeepestRightNode,
-              SplitAtEdges::eAllowToCreateEmptyContainer);
-  if (NS_WARN_IF(!CanHandleEditAction())) {
+  SplitNodeResult splitNodeResult = SplitNodeDeepWithTransaction(
+      MOZ_KnownLive(*pointToInsert.GetChild()), aStartOfDeepestRightNode,
+      SplitAtEdges::eAllowToCreateEmptyContainer);
+  if (NS_WARN_IF(Destroyed())) {
     return SplitNodeResult(NS_ERROR_EDITOR_DESTROYED);
   }
   NS_WARNING_ASSERTION(splitNodeResult.Succeeded(),
                        "Failed to split the node for insert the element");
   return splitNodeResult;
 }
 
 nsresult HTMLEditRules::JoinNearestEditableNodesWithTransaction(
@@ -10863,18 +10859,19 @@ nsresult HTMLEditRules::PrepareToMakeEle
 
     EditorDOMPoint atStartOfSelection(firstRange->StartRef());
     if (NS_WARN_IF(!atStartOfSelection.IsSet())) {
       return NS_ERROR_FAILURE;
     }
 
     // Make sure we can put a block here.
     SplitNodeResult splitNodeResult =
-        MaybeSplitAncestorsForInsertWithTransaction(*nsGkAtoms::div,
-                                                    atStartOfSelection);
+        MOZ_KnownLive(HTMLEditorRef())
+            .MaybeSplitAncestorsForInsertWithTransaction(*nsGkAtoms::div,
+                                                         atStartOfSelection);
     if (NS_WARN_IF(splitNodeResult.Failed())) {
       return splitNodeResult.Rv();
     }
     RefPtr<Element> positionedDiv =
         MOZ_KnownLive(HTMLEditorRef())
             .CreateNodeWithTransaction(*nsGkAtoms::div,
                                        splitNodeResult.SplitPoint());
     if (NS_WARN_IF(!CanHandleEditAction())) {
@@ -10938,18 +10935,19 @@ nsresult HTMLEditRules::PrepareToMakeEle
         sibling = HTMLEditorRef().GetPriorHTMLSibling(curNode);
       }
 
       if (!curList || (sibling && sibling != curList)) {
         nsAtom* containerName =
             atCurNode.GetContainer()->NodeInfo()->NameAtom();
         // Create a new nested list of correct type.
         SplitNodeResult splitNodeResult =
-            MaybeSplitAncestorsForInsertWithTransaction(
-                MOZ_KnownLive(*containerName), atCurNode);
+            MOZ_KnownLive(HTMLEditorRef())
+                .MaybeSplitAncestorsForInsertWithTransaction(
+                    MOZ_KnownLive(*containerName), atCurNode);
         if (NS_WARN_IF(splitNodeResult.Failed())) {
           return splitNodeResult.Rv();
         }
         if (!curPositionedDiv) {
           curPositionedDiv =
               MOZ_KnownLive(HTMLEditorRef())
                   .CreateNodeWithTransaction(*nsGkAtoms::div,
                                              splitNodeResult.SplitPoint());
@@ -11010,18 +11008,19 @@ nsresult HTMLEditRules::PrepareToMakeEle
         EditorDOMPoint atListItem(listItem);
         if (NS_WARN_IF(!atListItem.IsSet())) {
           return NS_ERROR_FAILURE;
         }
         nsAtom* containerName =
             atListItem.GetContainer()->NodeInfo()->NameAtom();
         // Create a new nested list of correct type
         SplitNodeResult splitNodeResult =
-            MaybeSplitAncestorsForInsertWithTransaction(
-                MOZ_KnownLive(*containerName), atListItem);
+            MOZ_KnownLive(HTMLEditorRef())
+                .MaybeSplitAncestorsForInsertWithTransaction(
+                    MOZ_KnownLive(*containerName), atListItem);
         if (NS_WARN_IF(splitNodeResult.Failed())) {
           return splitNodeResult.Rv();
         }
         if (!curPositionedDiv) {
           curPositionedDiv = MOZ_KnownLive(HTMLEditorRef())
                                  .CreateNodeWithTransaction(
                                      *nsGkAtoms::div,
                                      EditorDOMPoint(atListItem.GetContainer()));
@@ -11062,18 +11061,19 @@ nsresult HTMLEditRules::PrepareToMakeEle
     if (!curPositionedDiv) {
       if (curNode->IsHTMLElement(nsGkAtoms::div)) {
         curPositionedDiv = curNode->AsElement();
         *aTargetElement = curPositionedDiv;
         curList = nullptr;
         continue;
       }
       SplitNodeResult splitNodeResult =
-          MaybeSplitAncestorsForInsertWithTransaction(*nsGkAtoms::div,
-                                                      atCurNode);
+          MOZ_KnownLive(HTMLEditorRef())
+              .MaybeSplitAncestorsForInsertWithTransaction(*nsGkAtoms::div,
+                                                           atCurNode);
       if (NS_WARN_IF(splitNodeResult.Failed())) {
         return splitNodeResult.Rv();
       }
       curPositionedDiv = MOZ_KnownLive(HTMLEditorRef())
                              .CreateNodeWithTransaction(
                                  *nsGkAtoms::div, splitNodeResult.SplitPoint());
       if (NS_WARN_IF(!CanHandleEditAction())) {
         return NS_ERROR_EDITOR_DESTROYED;
--- a/editor/libeditor/HTMLEditRules.h
+++ b/editor/libeditor/HTMLEditRules.h
@@ -420,20 +420,22 @@ class HTMLEditRules : public TextEditRul
   /**
    * MakeBasicBlock() applies or clears block style around Selection.
    * This method creates AutoSelectionRestorer.  Therefore, each caller
    * need to check if the editor is still available even if this returns
    * NS_OK.
    *
    * @param aBlockType          New block tag name.
    *                            If nsGkAtoms::normal or nsGkAtoms::_empty,
-   *                            RemoveBlockStyle() will be called.
-   *                            If nsGkAtoms::blockquote, MakeBlockquote()
-   *                            will be called.
-   *                            Otherwise, ApplyBlockStyle() will be called.
+   *                            RemoveBlockContainerElements() will be called.
+   *                            If nsGkAtoms::blockquote,
+   *                            MoveNodesIntoNewBlockquoteElement() will be
+   *                            called.  Otherwise,
+   *                            CreateOrChangeBlockContainerElement() will be
+   *                            called.
    */
   MOZ_CAN_RUN_SCRIPT
   MOZ_MUST_USE nsresult MakeBasicBlock(nsAtom& aBlockType);
 
   /**
    * Called after creating a basic block, indenting, outdenting or aligning
    * contents.  This method inserts a padding <br> element for empty last line
    * if start container of Selection needs it.
@@ -630,53 +632,16 @@ class HTMLEditRules : public TextEditRul
    *                            outdented element.
    *                            The middle content is middle content of last
    *                            outdented element.
    */
   MOZ_CAN_RUN_SCRIPT
   MOZ_MUST_USE SplitRangeOffFromNodeResult OutdentAroundSelection();
 
   /**
-   * SplitRangeOffFromBlockAndRemoveMiddleContainer() splits the nodes
-   * between aStartOfRange and aEndOfRange, then, removes the middle element
-   * and moves its content to where the middle element was.
-   *
-   * @param aBlockElement           The node which will be split.
-   * @param aStartOfRange           The first node which will be unwrapped
-   *                                from aBlockElement.
-   * @param aEndOfRange             The last node which will be unwrapped from
-   *                                aBlockElement.
-   * @return                        The left content is new created left
-   *                                element of aBlockElement.
-   *                                The right content is split element,
-   *                                i.e., must be aBlockElement.
-   *                                The middle content is nullptr since
-   *                                removing it is the job of this method.
-   */
-  MOZ_CAN_RUN_SCRIPT
-  MOZ_MUST_USE SplitRangeOffFromNodeResult
-  SplitRangeOffFromBlockAndRemoveMiddleContainer(Element& aBlockElement,
-                                                 nsIContent& aStartOfRange,
-                                                 nsIContent& aEndOfRange);
-
-  /**
-   * SplitRangeOffFromBlock() splits aBlock at two points, before aStartChild
-   * and after aEndChild.  If they are very start or very end of aBlcok, this
-   * won't create empty block.
-   *
-   * @param aBlockElement           A block element which will be split.
-   * @param aStartOfMiddleElement   Start node of middle block element.
-   * @param aEndOfMiddleElement     End node of middle block element.
-   */
-  MOZ_CAN_RUN_SCRIPT
-  MOZ_MUST_USE SplitRangeOffFromNodeResult SplitRangeOffFromBlock(
-      Element& aBlockElement, nsIContent& aStartOfMiddleElement,
-      nsIContent& aEndOfMiddleElement);
-
-  /**
    * OutdentPartOfBlock() outdents the nodes between aStartOfOutdent and
    * aEndOfOutdent.  This splits the range off from aBlockElement first.
    * Then, removes the middle element if aIsBlockIndentedWithCSS is false.
    * Otherwise, decreases the margin of the middle element.
    *
    * @param aBlockElement           A block element which includes both
    *                                aStartOfOutdent and aEndOfOutdent.
    * @param aStartOfOutdent         First node which is descendant of
@@ -787,81 +752,16 @@ class HTMLEditRules : public TextEditRul
    * MakeTransitionList() detects all the transitions in the array, where a
    * transition means that adjacent nodes in the array don't have the same
    * parent.
    */
   void MakeTransitionList(nsTArray<OwningNonNull<nsINode>>& aNodeArray,
                           nsTArray<bool>& aTransitionArray);
 
   /**
-   * RemoveBlockStyle() removes all format blocks, table related element,
-   * etc in aNodeArray.
-   * If aNodeArray has a format node, it will be removed and its contents
-   * will be moved to where it was.
-   * If aNodeArray has a table related element, <li>, <blockquote> or <div>,
-   * it will removed and its contents will be moved to where it was.
-   */
-  MOZ_CAN_RUN_SCRIPT
-  nsresult RemoveBlockStyle(nsTArray<OwningNonNull<nsINode>>& aNodeArray);
-
-  /**
-   * ApplyBlockStyle() formats all nodes in aNodeArray with block elements
-   * whose name is aBlockTag.
-   * If aNodeArray has an inline element, a block element is created and the
-   * inline element and following inline elements are moved into the new block
-   * element.
-   * If aNodeArray has <br> elements, they'll be removed from the DOM tree and
-   * new block element will be created when there are some remaining inline
-   * elements.
-   * If aNodeArray has a block element, this calls itself with children of
-   * the block element.  Then, new block element will be created when there
-   * are some remaining inline elements.
-   *
-   * @param aNodeArray      Must be descendants of a node.
-   * @param aBlockTag       The element name of new block elements.
-   */
-  MOZ_CAN_RUN_SCRIPT
-  MOZ_MUST_USE nsresult ApplyBlockStyle(
-      nsTArray<OwningNonNull<nsINode>>& aNodeArray, nsAtom& aBlockTag);
-
-  /**
-   * MakeBlockquote() inserts at least one <blockquote> element and moves
-   * nodes in aNodeArray into new <blockquote> elements.  If aNodeArray
-   * includes a table related element except <table>, this calls itself
-   * recursively to insert <blockquote> into the cell.
-   *
-   * @param aNodeArray          Nodes which will be moved into created
-   *                            <blockquote> elements.
-   */
-  MOZ_CAN_RUN_SCRIPT
-  MOZ_MUST_USE nsresult
-  MakeBlockquote(nsTArray<OwningNonNull<nsINode>>& aNodeArray);
-
-  /**
-   * MaybeSplitAncestorsForInsertWithTransaction() does nothing if container of
-   * aStartOfDeepestRightNode can have an element whose tag name is aTag.
-   * Otherwise, looks for an ancestor node which is or is in active editing
-   * host and can have an element whose name is aTag.  If there is such
-   * ancestor, its descendants are split.
-   *
-   * Note that this may create empty elements while splitting ancestors.
-   *
-   * @param aTag                        The name of element to be inserted
-   *                                    after calling this method.
-   * @param aStartOfDeepestRightNode    The start point of deepest right node.
-   *                                    This point must be descendant of
-   *                                    active editing host.
-   * @return                            When succeeded, SplitPoint() returns
-   *                                    the point to insert the element.
-   */
-  MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE SplitNodeResult
-  MaybeSplitAncestorsForInsertWithTransaction(
-      nsAtom& aTag, const EditorDOMPoint& aStartOfDeepestRightNode);
-
-  /**
    * JoinNearestEditableNodesWithTransaction() joins two editable nodes which
    * are themselves or the nearest editable node of aLeftNode and aRightNode.
    * XXX This method's behavior is odd.  For example, if user types Backspace
    *     key at the second editable paragraph in this case:
    *     <div contenteditable>
    *       <p>first editable paragraph</p>
    *       <p contenteditable="false">non-editable paragraph</p>
    *       <p>second editable paragraph</p>
--- a/editor/libeditor/HTMLEditor.h
+++ b/editor/libeditor/HTMLEditor.h
@@ -40,16 +40,17 @@ class nsTableWrapperFrame;
 class nsRange;
 
 namespace mozilla {
 class AutoSelectionSetterAfterTableEdit;
 class AutoSetTemporaryAncestorLimiter;
 class EditActionResult;
 class EmptyEditableFunctor;
 class ResizerSelectionListener;
+class SplitRangeOffFromNodeResult;
 enum class EditSubAction : int32_t;
 struct PropItem;
 template <class T>
 class OwningNonNull;
 namespace dom {
 class AbstractRange;
 class Blob;
 class DocumentFragment;
@@ -1590,16 +1591,115 @@ class HTMLEditor final : public TextEdit
       }
       if (!IsEmptyInineNode(node)) {
         return false;
       }
     }
     return true;
   }
 
+  /**
+   * MaybeSplitAncestorsForInsertWithTransaction() does nothing if container of
+   * aStartOfDeepestRightNode can have an element whose tag name is aTag.
+   * Otherwise, looks for an ancestor node which is or is in active editing
+   * host and can have an element whose name is aTag.  If there is such
+   * ancestor, its descendants are split.
+   *
+   * Note that this may create empty elements while splitting ancestors.
+   *
+   * @param aTag                        The name of element to be inserted
+   *                                    after calling this method.
+   * @param aStartOfDeepestRightNode    The start point of deepest right node.
+   *                                    This point must be descendant of
+   *                                    active editing host.
+   * @return                            When succeeded, SplitPoint() returns
+   *                                    the point to insert the element.
+   */
+  MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE SplitNodeResult
+  MaybeSplitAncestorsForInsertWithTransaction(
+      nsAtom& aTag, const EditorDOMPoint& aStartOfDeepestRightNode);
+
+  /**
+   * SplitRangeOffFromBlock() splits aBlockElement at two points, before
+   * aStartOfMiddleElement and after aEndOfMiddleElement.  If they are very
+   * start or very end of aBlcok, this won't create empty block.
+   *
+   * @param aBlockElement           A block element which will be split.
+   * @param aStartOfMiddleElement   Start node of middle block element.
+   * @param aEndOfMiddleElement     End node of middle block element.
+   */
+  MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE SplitRangeOffFromNodeResult
+  SplitRangeOffFromBlock(Element& aBlockElement,
+                         nsIContent& aStartOfMiddleElement,
+                         nsIContent& aEndOfMiddleElement);
+
+  /**
+   * SplitRangeOffFromBlockAndRemoveMiddleContainer() splits the nodes
+   * between aStartOfRange and aEndOfRange, then, removes the middle element
+   * and moves its content to where the middle element was.
+   *
+   * @param aBlockElement           The node which will be split.
+   * @param aStartOfRange           The first node which will be unwrapped
+   *                                from aBlockElement.
+   * @param aEndOfRange             The last node which will be unwrapped from
+   *                                aBlockElement.
+   * @return                        The left content is new created left
+   *                                element of aBlockElement.
+   *                                The right content is split element,
+   *                                i.e., must be aBlockElement.
+   *                                The middle content is nullptr since
+   *                                removing it is the job of this method.
+   */
+  MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE SplitRangeOffFromNodeResult
+  SplitRangeOffFromBlockAndRemoveMiddleContainer(Element& aBlockElement,
+                                                 nsIContent& aStartOfRange,
+                                                 nsIContent& aEndOfRange);
+
+  /**
+   * MoveNodesIntoNewBlockquoteElement() inserts at least one <blockquote>
+   * element and moves nodes in aNodeArray into new <blockquote> elements.
+   * If aNodeArray includes a table related element except <table>, this
+   * calls itself recursively to insert <blockquote> into the cell.
+   *
+   * @param aNodeArray          Nodes which will be moved into created
+   *                            <blockquote> elements.
+   */
+  MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE nsresult MoveNodesIntoNewBlockquoteElement(
+      nsTArray<OwningNonNull<nsINode>>& aNodeArray);
+
+  /**
+   * RemoveBlockContainerElements() removes all format blocks, table related
+   * element, etc in aNodeArray from the DOM tree.
+   * If aNodeArray has a format node, it will be removed and its contents
+   * will be moved to where it was.
+   * If aNodeArray has a table related element, <li>, <blockquote> or <div>,
+   * it will be removed and its contents will be moved to where it was.
+   */
+  MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE nsresult
+  RemoveBlockContainerElements(nsTArray<OwningNonNull<nsINode>>& aNodeArray);
+
+  /**
+   * CreateOrChangeBlockContainerElement() formats all nodes in aNodeArray
+   * with block elements whose name is aBlockTag.
+   * If aNodeArray has an inline element, a block element is created and the
+   * inline element and following inline elements are moved into the new block
+   * element.
+   * If aNodeArray has <br> elements, they'll be removed from the DOM tree and
+   * new block element will be created when there are some remaining inline
+   * elements.
+   * If aNodeArray has a block element, this calls itself with children of
+   * the block element.  Then, new block element will be created when there
+   * are some remaining inline elements.
+   *
+   * @param aNodeArray      Must be descendants of a node.
+   * @param aBlockTag       The element name of new block elements.
+   */
+  MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE nsresult CreateOrChangeBlockContainerElement(
+      nsTArray<OwningNonNull<nsINode>>& aNodeArray, nsAtom& aBlockTag);
+
  protected:  // Called by helper classes.
   virtual void OnStartToHandleTopLevelEditSubAction(
       EditSubAction aEditSubAction, nsIEditor::EDirection aDirection) override;
   MOZ_CAN_RUN_SCRIPT
   virtual void OnEndHandlingTopLevelEditSubAction() override;
 
  protected:  // Shouldn't be used by friend classes
   virtual ~HTMLEditor();
--- a/gfx/layers/Compositor.cpp
+++ b/gfx/layers/Compositor.cpp
@@ -72,17 +72,16 @@ Compositor::Compositor(widget::Composito
       mDefaultClearColor(0.0, 0.0, 0.0, 0.0)
 #endif
 {
 }
 
 Compositor::~Compositor() { ReadUnlockTextures(); }
 
 void Compositor::Destroy() {
-  mWidget->DoCompositorCleanup();
   mWidget = nullptr;
 
   TextureSourceProvider::Destroy();
   mIsDestroyed = true;
 }
 
 void Compositor::EndFrame() {
   ReadUnlockTextures();
--- a/gfx/layers/Compositor.h
+++ b/gfx/layers/Compositor.h
@@ -125,16 +125,17 @@ struct Effect;
 struct EffectChain;
 class Image;
 class Layer;
 class TextureSource;
 class DataTextureSource;
 class CompositingRenderTarget;
 class CompositorBridgeParent;
 class LayerManagerComposite;
+class NativeLayer;
 class CompositorOGL;
 class CompositorD3D11;
 class BasicCompositor;
 class TextureReadLock;
 struct GPUStats;
 class AsyncReadbackBuffer;
 class RecordedFrame;
 
@@ -417,16 +418,17 @@ class Compositor : public TextureSourceP
    *
    * If aOpaque is true, then all of aInvalidRegion will be drawn to with
    * opaque content.
    */
   virtual void BeginFrame(const nsIntRegion& aInvalidRegion,
                           const gfx::IntRect* aClipRectIn,
                           const gfx::IntRect& aRenderBounds,
                           const nsIntRegion& aOpaqueRegion,
+                          NativeLayer* aNativeLayer,
                           gfx::IntRect* aClipRectOut = nullptr,
                           gfx::IntRect* aRenderBoundsOut = nullptr) = 0;
 
   /**
    * Notification that we've finished issuing draw commands for normal
    * layers (as opposed to the diagnostic overlay which comes after).
    * This is called between BeginFrame and EndFrame, and it's called before
    * GetWindowRenderTarget() is called for the purposes of screenshot capturing.
--- a/gfx/layers/basic/BasicCompositor.cpp
+++ b/gfx/layers/basic/BasicCompositor.cpp
@@ -22,16 +22,21 @@
 #include "mozilla/StaticPrefs_layers.h"
 #include "mozilla/StaticPrefs_nglayout.h"
 #include "gfxPlatform.h"
 #include "gfxUtils.h"
 #include "YCbCrUtils.h"
 #include <algorithm>
 #include "ImageContainer.h"
 
+#ifdef XP_MACOSX
+#  include "mozilla/gfx/MacIOSurface.h"
+#  include "mozilla/layers/NativeLayerCA.h"
+#endif
+
 namespace mozilla {
 using namespace mozilla::gfx;
 
 namespace layers {
 
 class DataTextureSourceBasic : public DataTextureSource,
                                public TextureSourceBasic {
  public:
@@ -879,17 +884,17 @@ bool BasicCompositor::BlitRenderTarget(C
       surface, Rect(Point(), Size(aDestSize)), Rect(Point(), Size(aSourceSize)),
       DrawSurfaceOptions(), DrawOptions(1.0f, CompositionOp::OP_SOURCE));
   return true;
 }
 
 void BasicCompositor::BeginFrame(
     const nsIntRegion& aInvalidRegion, const gfx::IntRect* aClipRectIn,
     const gfx::IntRect& aRenderBounds, const nsIntRegion& aOpaqueRegion,
-    gfx::IntRect* aClipRectOut /* = nullptr */,
+    NativeLayer* aNativeLayer, gfx::IntRect* aClipRectOut /* = nullptr */,
     gfx::IntRect* aRenderBoundsOut /* = nullptr */) {
   if (mIsPendingEndRemoteDrawing) {
     // Force to end previous remote drawing.
     TryToEndRemoteDrawing(/* aForceToEnd */ true);
     MOZ_ASSERT(!mIsPendingEndRemoteDrawing);
   }
 
   IntRect rect(IntPoint(), mWidget->GetClientSize().ToUnknownSize());
@@ -921,16 +926,41 @@ void BasicCompositor::BeginFrame(
     MOZ_RELEASE_ASSERT(!mInvalidRect.IsEmpty());
 
     // If we have a copy target, render into that DrawTarget directly without
     // any intermediate buffer. We don't need to call StartRemoteDrawingInRegion
     // because we don't need a widget-provided DrawTarget.
     mDrawTarget = mTarget;
     mDrawTargetBounds = mTargetBounds;
     bufferMode = BufferMode::BUFFER_NONE;
+  } else if (aNativeLayer) {
+#ifdef XP_MACOSX
+    if (mInvalidRect.IsEmpty()) {
+      return;
+    }
+    NativeLayerCA* nativeLayer = aNativeLayer->AsNativeLayerCA();
+    MOZ_RELEASE_ASSERT(nativeLayer, "Unexpected native layer type");
+    nativeLayer->SetSurfaceIsFlipped(false);
+    CFTypeRefPtr<IOSurfaceRef> surf = nativeLayer->NextSurface();
+    if (!surf) {
+      return;
+    }
+    nativeLayer->InvalidateRegionThroughoutSwapchain(mInvalidRegion);
+    mInvalidRegion = nativeLayer->CurrentSurfaceInvalidRegion();
+    mInvalidRect = mInvalidRegion.GetBounds();
+    MOZ_RELEASE_ASSERT(!mInvalidRect.IsEmpty());
+    mCurrentNativeLayer = aNativeLayer;
+    mCurrentIOSurface = new MacIOSurface(std::move(surf));
+    mCurrentIOSurface->Lock(false);
+    mDrawTarget = mCurrentIOSurface->GetAsDrawTargetLocked(BackendType::SKIA);
+    mDrawTargetBounds = IntRect(IntPoint(0, 0), mDrawTarget->GetSize());
+    bufferMode = BufferMode::BUFFER_NONE;
+#else
+    MOZ_CRASH("Unexpected native layer on this platform");
+#endif
   } else {
     LayoutDeviceIntRegion invalidRegion =
         LayoutDeviceIntRegion::FromUnknownRegion(mInvalidRegion);
     mDrawTarget =
         mWidget->StartRemoteDrawingInRegion(invalidRegion, &bufferMode);
     if (!mDrawTarget) {
       return;
     }
@@ -962,17 +992,17 @@ void BasicCompositor::BeginFrame(
   // Setup a render target for drawing. In cases where we need to buffer all
   // compositing (bufferMode == BufferMode::BUFFERED), this will set up the back
   // buffer. We will copy the drawing into mDrawTarget (the widget) in
   // TryToEndRemoteDrawing(), which gets called during EndFrame().
   RefPtr<CompositingRenderTarget> target =
       CreateRenderTargetForWindow(mInvalidRect, clearRegion, bufferMode);
 
   if (!target) {
-    if (!mTarget) {
+    if (!mTarget && !aNativeLayer) {
       mWidget->EndRemoteDrawingInRegion(
           mDrawTarget,
           LayoutDeviceIntRegion::FromUnknownRegion(mInvalidRegion));
     }
     return;
   }
   SetRenderTarget(target);
 
@@ -1032,17 +1062,32 @@ void BasicCompositor::EndFrame() {
   }
 
   // Pop aInvalidregion
   mRenderTarget->mDrawTarget->PopClip();
 
   // Reset the translation that was applied in CreateRenderTargetForWindow.
   mRenderTarget->mDrawTarget->SetTransform(gfx::Matrix());
 
-  TryToEndRemoteDrawing();
+  if (mCurrentNativeLayer) {
+#ifdef XP_MACOSX
+    NativeLayerCA* nativeLayer = mCurrentNativeLayer->AsNativeLayerCA();
+    MOZ_RELEASE_ASSERT(nativeLayer, "Unexpected native layer type");
+    mDrawTarget = nullptr;
+    mRenderTarget = nullptr;
+    mCurrentIOSurface->Unlock(false);
+    mCurrentIOSurface = nullptr;
+    nativeLayer->NotifySurfaceReady();
+    mCurrentNativeLayer = nullptr;
+#else
+    MOZ_CRASH("Unexpected native layer on this platform");
+#endif
+  } else {
+    TryToEndRemoteDrawing();
+  }
 }
 
 void BasicCompositor::TryToEndRemoteDrawing(bool aForceToEnd) {
   if (mIsDestroyed || !mRenderTarget) {
     return;
   }
 
   // It it is not a good timing for EndRemoteDrawing, defter to call it.
--- a/gfx/layers/basic/BasicCompositor.h
+++ b/gfx/layers/basic/BasicCompositor.h
@@ -8,16 +8,20 @@
 #define MOZILLA_GFX_BASICCOMPOSITOR_H
 
 #include "mozilla/layers/Compositor.h"
 #include "mozilla/layers/TextureHost.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/Triangle.h"
 #include "mozilla/gfx/Polygon.h"
 
+#ifdef XP_MACOSX
+class MacIOSurface;
+#endif
+
 namespace mozilla {
 namespace layers {
 
 class BasicCompositingRenderTarget : public CompositingRenderTarget {
  public:
   BasicCompositingRenderTarget(gfx::DrawTarget* aDrawTarget,
                                const gfx::IntRect& aRect)
       : CompositingRenderTarget(aRect.TopLeft()),
@@ -110,17 +114,17 @@ class BasicCompositor : public Composito
                 const gfx::Matrix4x4& aTransform,
                 const gfx::Rect& aVisibleRect) override;
 
   void ClearRect(const gfx::Rect& aRect) override;
 
   void BeginFrame(const nsIntRegion& aInvalidRegion,
                   const gfx::IntRect* aClipRectIn,
                   const gfx::IntRect& aRenderBounds,
-                  const nsIntRegion& aOpaqueRegion,
+                  const nsIntRegion& aOpaqueRegion, NativeLayer* aNativeLayer,
                   gfx::IntRect* aClipRectOut = nullptr,
                   gfx::IntRect* aRenderBoundsOut = nullptr) override;
   void NormalDrawingDone() override;
   void EndFrame() override;
 
   bool SupportsPartialTextureUpdate() override { return true; }
   bool CanUseCanvasLayerForSize(const gfx::IntSize& aSize) override {
     return true;
@@ -184,16 +188,27 @@ class BasicCompositor : public Composito
   // The final destination surface
   RefPtr<gfx::DrawTarget> mDrawTarget;
   // The bounds that mDrawTarget occupies in window space.
   gfx::IntRect mDrawTargetBounds;
 
   // The current render target for drawing
   RefPtr<BasicCompositingRenderTarget> mRenderTarget;
 
+  // The native layer that we're currently rendering to, if any.
+  // Non-null only between BeginFrame and EndFrame if BeginFrame has been called
+  // with a non-null aNativeLayer and mTarget is null.
+  RefPtr<NativeLayer> mCurrentNativeLayer;
+
+#ifdef XP_MACOSX
+  // The MacIOSurface that we're currently rendering to, if any.
+  // Non-null in the same cases as mCurrentNativeLayer.
+  RefPtr<MacIOSurface> mCurrentIOSurface;
+#endif
+
   gfx::IntRect mInvalidRect;
   gfx::IntRegion mInvalidRegion;
 
   uint32_t mMaxTextureSize;
   bool mIsPendingEndRemoteDrawing;
   bool mRecordFrames;
 
   // mDrawTarget will not be the full window on all platforms. We therefore need
--- a/gfx/layers/composite/LayerManagerComposite.cpp
+++ b/gfx/layers/composite/LayerManagerComposite.cpp
@@ -149,16 +149,21 @@ LayerManagerComposite::LayerManagerCompo
 #if defined(MOZ_WIDGET_ANDROID)
       ,
       mScreenPixelsTarget(nullptr)
 #endif  // defined(MOZ_WIDGET_ANDROID)
 {
   mTextRenderer = new TextRenderer();
   mDiagnostics = MakeUnique<Diagnostics>();
   MOZ_ASSERT(aCompositor);
+  mNativeLayerRoot = aCompositor->GetWidget()->GetNativeLayerRoot();
+  if (mNativeLayerRoot) {
+    mNativeLayerForEntireWindow = mNativeLayerRoot->CreateLayer();
+    mNativeLayerRoot->AppendLayer(mNativeLayerForEntireWindow);
+  }
 
 #ifdef USE_SKIA
   mPaintCounter = nullptr;
 #endif
 }
 
 LayerManagerComposite::~LayerManagerComposite() { Destroy(); }
 
@@ -167,16 +172,21 @@ void LayerManagerComposite::Destroy() {
     mCompositor->GetWidget()->CleanupWindowEffects();
     if (mRoot) {
       RootLayer()->Destroy();
     }
     mCompositor->CancelFrame();
     mRoot = nullptr;
     mClonedLayerTreeProperties = nullptr;
     mProfilerScreenshotGrabber.Destroy();
+    if (mNativeLayerRoot) {
+      mNativeLayerRoot->RemoveLayer(mNativeLayerForEntireWindow);
+      mNativeLayerForEntireWindow = nullptr;
+      mNativeLayerRoot = nullptr;
+    }
     mDestroyed = true;
 
 #ifdef USE_SKIA
     mPaintCounter = nullptr;
 #endif
   }
 }
 
@@ -966,26 +976,36 @@ bool LayerManagerComposite::Render(const
 #if defined(MOZ_WIDGET_ANDROID)
   LayerMetricsWrapper wrapper = GetRootContentLayer();
   if (wrapper) {
     mCompositor->SetClearColor(wrapper.Metadata().GetBackgroundColor());
   } else {
     mCompositor->SetClearColorToDefault();
   }
 #endif
+
+  if (mNativeLayerForEntireWindow) {
+    mNativeLayerForEntireWindow->SetRect(bounds);
+#ifdef XP_MACOSX
+    mNativeLayerForEntireWindow->SetOpaqueRegion(
+        mCompositor->GetWidget()->GetOpaqueWidgetRegion().ToUnknownRegion());
+#endif
+  }
+
   if (mRoot->GetClipRect()) {
     clipRect = *mRoot->GetClipRect();
     IntRect rect(clipRect.X(), clipRect.Y(), clipRect.Width(),
                  clipRect.Height());
     mCompositor->BeginFrame(aInvalidRegion, &rect, bounds, aOpaqueRegion,
-                            nullptr, &actualBounds);
+                            mNativeLayerForEntireWindow, nullptr,
+                            &actualBounds);
   } else {
     gfx::IntRect rect;
     mCompositor->BeginFrame(aInvalidRegion, nullptr, bounds, aOpaqueRegion,
-                            &rect, &actualBounds);
+                            mNativeLayerForEntireWindow, &rect, &actualBounds);
     clipRect =
         ParentLayerIntRect(rect.X(), rect.Y(), rect.Width(), rect.Height());
   }
 #if defined(MOZ_WIDGET_ANDROID)
   ScreenCoord offset = GetContentShiftForToolbar();
   ScopedCompositorRenderOffset scopedOffset(mCompositor->AsCompositorOGL(),
                                             ScreenPoint(0.0f, offset));
 #endif
@@ -997,20 +1017,16 @@ bool LayerManagerComposite::Render(const
     // Discard the current payloads. These payloads did not require a composite
     // (they caused no changes to anything visible), so we don't want to measure
     // their latency.
     mPayload.Clear();
 
     return true;
   }
 
-  // Allow widget to render a custom background.
-  mCompositor->GetWidget()->DrawWindowUnderlay(
-      &widgetContext, LayoutDeviceIntRect::FromUnknownRect(actualBounds));
-
   RefPtr<CompositingRenderTarget> previousTarget;
   if (haveLayerEffects) {
     previousTarget = PushGroupForLayerEffects();
   } else {
     mTwoPassTmpTarget = nullptr;
   }
 
   // Render our layers.
@@ -1219,18 +1235,18 @@ void LayerManagerComposite::RenderToPres
   mRoot->ComputeEffectiveTransforms(matrix);
   nsIntRegion opaque;
   PostProcessLayers(opaque);
 
   nsIntRegion invalid;
   IntRect bounds = IntRect::Truncate(0, 0, scale * pageWidth, actualHeight);
   IntRect rect, actualBounds;
   MOZ_ASSERT(mRoot->GetOpacity() == 1);
-  mCompositor->BeginFrame(invalid, nullptr, bounds, nsIntRegion(), &rect,
-                          &actualBounds);
+  mCompositor->BeginFrame(invalid, nullptr, bounds, nsIntRegion(), nullptr,
+                          &rect, &actualBounds);
 
   // The Java side of Fennec sets a scissor rect that accounts for
   // chrome such as the URL bar. Override that so that the entire frame buffer
   // is cleared.
   ScopedScissorRect scissorRect(egl, 0, 0, actualWidth, actualHeight);
   egl->fClearColor(0.0, 0.0, 0.0, 0.0);
   egl->fClear(LOCAL_GL_COLOR_BUFFER_BIT);
 
--- a/gfx/layers/composite/LayerManagerComposite.h
+++ b/gfx/layers/composite/LayerManagerComposite.h
@@ -460,16 +460,18 @@ class LayerManagerComposite final : publ
   nsIntRegion mInvalidRegion;
 
   bool mInTransaction;
   bool mIsCompositorReady;
 
   RefPtr<CompositingRenderTarget> mTwoPassTmpTarget;
   CompositorScreenshotGrabber mProfilerScreenshotGrabber;
   RefPtr<TextRenderer> mTextRenderer;
+  RefPtr<NativeLayerRoot> mNativeLayerRoot;
+  RefPtr<NativeLayer> mNativeLayerForEntireWindow;
 
 #ifdef USE_SKIA
   /**
    * Render paint and composite times above the frame.
    */
   void DrawPaintTimes(Compositor* aCompositor);
   RefPtr<PaintCounter> mPaintCounter;
 #endif
--- a/gfx/layers/d3d11/CompositorD3D11.cpp
+++ b/gfx/layers/d3d11/CompositorD3D11.cpp
@@ -1093,18 +1093,21 @@ void CompositorD3D11::DrawGeometry(const
                               0xFFFFFFFF);
   }
 }
 
 void CompositorD3D11::BeginFrame(const nsIntRegion& aInvalidRegion,
                                  const IntRect* aClipRectIn,
                                  const IntRect& aRenderBounds,
                                  const nsIntRegion& aOpaqueRegion,
+                                 NativeLayer* aNativeLayer,
                                  IntRect* aClipRectOut,
                                  IntRect* aRenderBoundsOut) {
+  MOZ_RELEASE_ASSERT(!aNativeLayer, "Unexpected native layer on this platform");
+
   // Don't composite if we are minimised. Other than for the sake of efficency,
   // this is important because resizing our buffers when mimised will fail and
   // cause a crash when we're restored.
   NS_ASSERTION(mHwnd, "Couldn't find an HWND when initialising?");
   if (mWidget->IsHidden()) {
     // We are not going to render, and not going to call EndFrame so we have to
     // read-unlock our textures to prevent them from accumulating.
     ReadUnlockTextures();
--- a/gfx/layers/d3d11/CompositorD3D11.h
+++ b/gfx/layers/d3d11/CompositorD3D11.h
@@ -91,17 +91,17 @@ class CompositorD3D11 : public Composito
 
   /**
    * Start a new frame. If aClipRectIn is null, sets *aClipRectOut to the
    * screen dimensions.
    */
   void BeginFrame(const nsIntRegion& aInvalidRegion,
                   const gfx::IntRect* aClipRectIn,
                   const gfx::IntRect& aRenderBounds,
-                  const nsIntRegion& aOpaqueRegion,
+                  const nsIntRegion& aOpaqueRegion, NativeLayer* aNativeLayer,
                   gfx::IntRect* aClipRectOut = nullptr,
                   gfx::IntRect* aRenderBoundsOut = nullptr) override;
 
   void NormalDrawingDone() override;
 
   /**
    * Flush the current frame to the screen.
    */
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -368,17 +368,16 @@ UNIFIED_SOURCES += [
     'apz/util/ScrollLinkedEffectDetector.cpp',
     'apz/util/TouchActionHelper.cpp',
     'apz/util/TouchCounter.cpp',
     'AsyncCanvasRenderer.cpp',
     'AxisPhysicsModel.cpp',
     'AxisPhysicsMSDModel.cpp',
     'basic/BasicCanvasLayer.cpp',
     'basic/BasicColorLayer.cpp',
-    'basic/BasicCompositor.cpp',
     'basic/BasicContainerLayer.cpp',
     'basic/BasicImages.cpp',
     'basic/BasicLayerManager.cpp',
     'basic/BasicLayersImpl.cpp',
     'basic/BasicPaintedLayer.cpp',
     'basic/TextureHostBasic.cpp',
     'BSPTree.cpp',
     'BufferTexture.cpp',
@@ -527,16 +526,17 @@ UNIFIED_SOURCES += [
     'wr/WebRenderLayersLogging.cpp',
     'wr/WebRenderScrollData.cpp',
     'wr/WebRenderUserData.cpp',
     # XXX here are some unified build error.
     #'wr/WebRenderTextureHost.cpp'
 ]
 
 SOURCES += [
+    'basic/BasicCompositor.cpp',
     'basic/BasicImageLayer.cpp',
     'ImageContainer.cpp',
     'PersistentBufferProvider.cpp',
     'protobuf/LayerScopePacket.pb.cc',
     'wr/WebRenderTextureHost.cpp',
 ]
 
 DEFINES['GOOGLE_PROTOBUF_NO_RTTI'] = True
--- a/gfx/layers/opengl/CompositingRenderTargetOGL.h
+++ b/gfx/layers/opengl/CompositingRenderTargetOGL.h
@@ -137,16 +137,19 @@ class CompositingRenderTargetOGL : publi
   gfx::IntSize GetSize() const override { return mInitParams.mSize; }
 
   gfx::SurfaceFormat GetFormat() const override {
     // XXX - Should it be implemented ? is the above assert true ?
     MOZ_ASSERT(false, "Not implemented");
     return gfx::SurfaceFormat::UNKNOWN;
   }
 
+  void SetClipRect(const Maybe<gfx::IntRect>& aRect) { mClipRect = aRect; }
+  const Maybe<gfx::IntRect>& GetClipRect() const { return mClipRect; }
+
 #ifdef MOZ_DUMP_PAINTING
   already_AddRefed<gfx::DataSourceSurface> Dump(
       Compositor* aCompositor) override;
 #endif
 
   const gfx::IntSize& GetInitSize() const { return mInitParams.mSize; }
 
  private:
@@ -159,16 +162,17 @@ class CompositingRenderTargetOGL : publi
   InitParams mInitParams;
   /**
    * There is temporary a cycle between the compositor and the render target,
    * each having a strong ref to the other. The compositor's reference to
    * the target is always cleared at the end of a frame.
    */
   RefPtr<CompositorOGL> mCompositor;
   RefPtr<GLContext> mGL;
+  Maybe<gfx::IntRect> mClipRect;
   GLuint mTextureHandle;
   GLuint mFBO;
 };
 
 }  // namespace layers
 }  // namespace mozilla
 
 #endif /* MOZILLA_GFX_SURFACEOGL_H */
--- a/gfx/layers/opengl/CompositorOGL.cpp
+++ b/gfx/layers/opengl/CompositorOGL.cpp
@@ -53,16 +53,21 @@
 #include "HeapCopyOfStackArray.h"
 #include "GLBlitHelper.h"
 #include "mozilla/gfx/Swizzle.h"
 
 #if MOZ_WIDGET_ANDROID
 #  include "GeneratedJNIWrappers.h"
 #endif
 
+#ifdef XP_MACOSX
+#  include "GLContextCGL.h"
+#  include "mozilla/layers/NativeLayerCA.h"
+#endif
+
 #include "GeckoProfiler.h"
 
 namespace mozilla {
 
 using namespace std;
 using namespace gfx;
 
 namespace layers {
@@ -196,16 +201,21 @@ CompositorOGL::CompositorOGL(CompositorB
       mPreviousFrameDoneSync(nullptr),
       mThisFrameDoneSync(nullptr),
       mHasBGRA(0),
       mUseExternalSurfaceSize(aUseExternalSurfaceSize),
       mFrameInProgress(false),
       mDestroyed(false),
       mViewportSize(0, 0),
       mCurrentProgram(nullptr) {
+  if (aWidget->GetNativeLayerRoot()) {
+    // We can only render into native layers, our GLContext won't have a usable
+    // default framebuffer.
+    mCanRenderToDefaultFramebuffer = false;
+  }
 #ifdef XP_DARWIN
   TextureSync::RegisterTextureSourceProvider(this);
 #endif
   MOZ_COUNT_CTOR(CompositorOGL);
 }
 
 CompositorOGL::~CompositorOGL() {
 #ifdef XP_DARWIN
@@ -743,21 +753,131 @@ void CompositorOGL::ClearRect(const gfx:
 
   ScopedGLState scopedScissorTestState(mGLContext, LOCAL_GL_SCISSOR_TEST, true);
   ScopedScissorRect autoScissorRect(mGLContext, aRect.X(), y, aRect.Width(),
                                     aRect.Height());
   mGLContext->fClearColor(0.0, 0.0, 0.0, 0.0);
   mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT);
 }
 
+#ifdef XP_MACOSX
+class SurfaceRegistryWrapperAroundCompositorOGL
+    : public layers::IOSurfaceRegistry {
+ public:
+  explicit SurfaceRegistryWrapperAroundCompositorOGL(CompositorOGL* aCompositor)
+      : mCompositor(aCompositor) {}
+  void RegisterSurface(CFTypeRefPtr<IOSurfaceRef> aSurface) override {
+    mCompositor->RegisterIOSurface((IOSurfacePtr)aSurface.get());
+  }
+  void UnregisterSurface(CFTypeRefPtr<IOSurfaceRef> aSurface) override {
+    mCompositor->UnregisterIOSurface((IOSurfacePtr)aSurface.get());
+  }
+  RefPtr<CompositorOGL> mCompositor;
+};
+
+void CompositorOGL::RegisterIOSurface(IOSurfacePtr aSurface) {
+  MOZ_RELEASE_ASSERT(mRegisteredIOSurfaceRenderTargets.find(aSurface) ==
+                         mRegisteredIOSurfaceRenderTargets.end(),
+                     "double-registering IOSurface");
+
+  IOSurfaceRef surface = (IOSurfaceRef)aSurface;
+  auto glContextCGL = GLContextCGL::Cast(mGLContext);
+  MOZ_RELEASE_ASSERT(glContextCGL, "Unexpected GLContext type");
+
+  IntSize size(IOSurfaceGetWidth(surface), IOSurfaceGetHeight(surface));
+
+  mGLContext->MakeCurrent();
+  GLuint tex = mGLContext->CreateTexture();
+  {
+    const ScopedBindTexture bindTex(mGLContext, tex,
+                                    LOCAL_GL_TEXTURE_RECTANGLE_ARB);
+    CGLTexImageIOSurface2D(glContextCGL->GetCGLContext(),
+                           LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_RGBA,
+                           size.width, size.height, LOCAL_GL_BGRA,
+                           LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV, surface, 0);
+  }
+
+  GLuint fbo = mGLContext->CreateFramebuffer();
+  {
+    const ScopedBindFramebuffer bindFB(mGLContext, fbo);
+    mGLContext->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
+                                      LOCAL_GL_COLOR_ATTACHMENT0,
+                                      LOCAL_GL_TEXTURE_RECTANGLE_ARB, tex, 0);
+  }
+
+  RefPtr<CompositingRenderTargetOGL> rt =
+      new CompositingRenderTargetOGL(this, gfx::IntPoint(), tex, fbo);
+  rt->Initialize(size, size, LOCAL_GL_TEXTURE_RECTANGLE_ARB, INIT_MODE_NONE);
+
+  mRegisteredIOSurfaceRenderTargets.insert({aSurface, rt});
+}
+
+void CompositorOGL::UnregisterIOSurface(IOSurfacePtr aSurface) {
+  size_t removeCount = mRegisteredIOSurfaceRenderTargets.erase(aSurface);
+  MOZ_RELEASE_ASSERT(removeCount == 1,
+                     "Unregistering IOSurface that's not registered");
+}
+#endif
+
+already_AddRefed<CompositingRenderTargetOGL>
+CompositorOGL::RenderTargetForNativeLayer(NativeLayer* aNativeLayer,
+                                          IntRegion& aInvalidRegion) {
+  if (aInvalidRegion.IsEmpty()) {
+    return nullptr;
+  }
+
+#ifdef XP_MACOSX
+  NativeLayerCA* nativeLayer = aNativeLayer->AsNativeLayerCA();
+  MOZ_RELEASE_ASSERT(nativeLayer, "Unexpected native layer type");
+  nativeLayer->SetSurfaceIsFlipped(true);
+  auto glContextCGL = GLContextCGL::Cast(mGLContext);
+  MOZ_RELEASE_ASSERT(glContextCGL, "Unexpected GLContext type");
+  RefPtr<layers::IOSurfaceRegistry> currentRegistry =
+      nativeLayer->GetSurfaceRegistry();
+  if (!currentRegistry) {
+    nativeLayer->SetSurfaceRegistry(
+        MakeAndAddRef<SurfaceRegistryWrapperAroundCompositorOGL>(this));
+  } else {
+    MOZ_RELEASE_ASSERT(static_cast<SurfaceRegistryWrapperAroundCompositorOGL*>(
+                           currentRegistry.get())
+                           ->mCompositor == this);
+  }
+  CFTypeRefPtr<IOSurfaceRef> surf = nativeLayer->NextSurface();
+  if (!surf) {
+    return nullptr;
+  }
+
+  IntRect layerRect = nativeLayer->GetRect();
+  IntRegion invalidRelativeToLayer =
+      aInvalidRegion.MovedBy(-layerRect.TopLeft());
+  nativeLayer->InvalidateRegionThroughoutSwapchain(invalidRelativeToLayer);
+  invalidRelativeToLayer = nativeLayer->CurrentSurfaceInvalidRegion();
+  aInvalidRegion = invalidRelativeToLayer.MovedBy(layerRect.TopLeft());
+
+  auto match = mRegisteredIOSurfaceRenderTargets.find((IOSurfacePtr)surf.get());
+  MOZ_RELEASE_ASSERT(match != mRegisteredIOSurfaceRenderTargets.end(),
+                     "IOSurface has not been registered with this Compositor");
+  RefPtr<CompositingRenderTargetOGL> rt = match->second;
+
+  // Clip the render target to the invalid rect. This conserves memory bandwidth
+  // and power.
+  IntRect invalidRect = aInvalidRegion.GetBounds();
+  rt->SetClipRect(invalidRect == layerRect ? Nothing() : Some(invalidRect));
+
+  return rt.forget();
+#else
+  MOZ_CRASH("Unexpected native layer on this platform");
+#endif
+}
+
 void CompositorOGL::BeginFrame(const nsIntRegion& aInvalidRegion,
                                const IntRect* aClipRectIn,
                                const IntRect& aRenderBounds,
                                const nsIntRegion& aOpaqueRegion,
-                               IntRect* aClipRectOut,
+                               NativeLayer* aNativeLayer, IntRect* aClipRectOut,
                                IntRect* aRenderBoundsOut) {
   AUTO_PROFILER_LABEL("CompositorOGL::BeginFrame", GRAPHICS);
 
   MOZ_ASSERT(!mFrameInProgress,
              "frame still in progress (should have called EndFrame");
 
   gfx::IntRect rect;
   if (mUseExternalSurfaceSize) {
@@ -773,19 +893,16 @@ void CompositorOGL::BeginFrame(const nsI
 
   auto width = rect.Width();
   auto height = rect.Height();
 
   // We can't draw anything to something with no area
   // so just return
   if (width == 0 || height == 0) return;
 
-  // We're about to actually draw a frame.
-  mFrameInProgress = true;
-
   // If the widget size changed, we have to force a MakeCurrent
   // to make sure that GL sees the updated widget size.
   if (mWidgetSize.width != width || mWidgetSize.height != height) {
     MakeCurrent(ForceMakeCurrent);
 
     mWidgetSize.width = width;
     mWidgetSize.height = height;
   } else {
@@ -800,19 +917,42 @@ void CompositorOGL::BeginFrame(const nsI
   mGLContext->MakeCurrent();  // DestroyUnused can change the current context!
 #endif
 
   // Default blend function implements "OVER"
   mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
                                  LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA);
   mGLContext->fEnable(LOCAL_GL_BLEND);
 
-  RefPtr<CompositingRenderTargetOGL> rt =
-      CompositingRenderTargetOGL::RenderTargetForWindow(this,
-                                                        IntSize(width, height));
+  RefPtr<CompositingRenderTarget> rt;
+  if (mTarget) {
+    if (mCanRenderToDefaultFramebuffer) {
+      rt = CompositingRenderTargetOGL::RenderTargetForWindow(this, rect.Size());
+    } else {
+      rt = CreateRenderTarget(rect, INIT_MODE_CLEAR);
+    }
+  } else if (aNativeLayer) {
+    IntRegion layerInvalid;
+    layerInvalid.And(aInvalidRegion, rect);
+    rt = RenderTargetForNativeLayer(aNativeLayer, layerInvalid);
+    mCurrentNativeLayer = aNativeLayer;
+  } else {
+    MOZ_RELEASE_ASSERT(mCanRenderToDefaultFramebuffer);
+    rt = CompositingRenderTargetOGL::RenderTargetForWindow(this, rect.Size());
+  }
+
+  if (!rt) {
+    *aRenderBoundsOut = IntRect();
+    mCurrentNativeLayer = nullptr;
+    return;
+  }
+
+  // We're about to actually draw a frame.
+  mFrameInProgress = true;
+
   SetRenderTarget(rt);
   mWindowRenderTarget = mCurrentRenderTarget;
 
   if (aClipRectOut && !aClipRectIn) {
     aClipRectOut->SetRect(0, 0, width, height);
   }
 
 #if defined(MOZ_WIDGET_ANDROID)
@@ -825,17 +965,36 @@ void CompositorOGL::BeginFrame(const nsI
   } else {
     mGLContext->fClearColor(mClearColor.r, mClearColor.g, mClearColor.b,
                             mClearColor.a);
   }
 #else
   mGLContext->fClearColor(mClearColor.r, mClearColor.g, mClearColor.b,
                           mClearColor.a);
 #endif  // defined(MOZ_WIDGET_ANDROID)
-  mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT);
+
+  if (const Maybe<IntRect>& rtClip = mCurrentRenderTarget->GetClipRect()) {
+    // We need to apply a scissor rect during the clear. And since clears with
+    // scissor rects are usually treated differently by the GPU than regular
+    // clears, let's try to clear as little as possible in order to conserve
+    // memory bandwidth.
+    IntRegion clearRegion;
+    clearRegion.Sub(*rtClip, aOpaqueRegion);
+    if (!clearRegion.IsEmpty()) {
+      IntRect clearRect = clearRegion.GetBounds();
+      ScopedGLState scopedScissorTestState(mGLContext, LOCAL_GL_SCISSOR_TEST,
+                                           true);
+      ScopedScissorRect autoScissorRect(mGLContext, clearRect.x,
+                                        FlipY(clearRect.YMost()),
+                                        clearRect.Width(), clearRect.Height());
+      mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT);
+    }
+  } else {
+    mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT);
+  }
 }
 
 void CompositorOGL::CreateFBOWithTexture(const gfx::IntRect& aRect,
                                          bool aCopyFromSource,
                                          GLuint aSourceFrameBuffer,
                                          GLuint* aFBO, GLuint* aTexture,
                                          gfx::IntSize* aAllocSize) {
   *aTexture =
@@ -1177,16 +1336,20 @@ void CompositorOGL::DrawGeometry(const G
     NS_ASSERTION(maskTransform.Is2D(),
                  "How did we end up with a 3D transform here?!");
     maskBounds = Rect(Point(), Size(maskSize));
     maskBounds = maskTransform.As2D().TransformBounds(maskBounds);
 
     clipRect = clipRect.Intersect(RoundedOut(maskBounds) - offset);
   }
 
+  if (Maybe<IntRect> rtClip = mCurrentRenderTarget->GetClipRect()) {
+    clipRect = clipRect.Intersect(*rtClip);
+  }
+
   // aClipRect is in destination coordinate space (after all
   // transforms and offsets have been applied) so if our
   // drawing is going to be shifted by mRenderOffset then we need
   // to shift the clip rect by the same amount.
   if (!mTarget && mCurrentRenderTarget->IsWindow()) {
     clipRect.MoveBy(mRenderOffset.x + mSurfaceOrigin.x,
                     mRenderOffset.y - mSurfaceOrigin.y);
   }
@@ -1734,18 +1897,44 @@ void CompositorOGL::EndFrame() {
             IntSize(size.width, size.height), SurfaceFormat::B8G8R8A8);
     if (target) {
       CopyToTarget(target, nsIntPoint(), Matrix());
       WriteSnapshotToDumpFile(this, target);
     }
   }
 #endif
 
+  if (StaticPrefs::nglayout_debug_widget_update_flashing()) {
+    float r = float(rand()) / RAND_MAX;
+    float g = float(rand()) / RAND_MAX;
+    float b = float(rand()) / RAND_MAX;
+    EffectChain effectChain;
+    effectChain.mPrimaryEffect = new EffectSolidColor(Color(r, g, b, 0.2f));
+    // If we're clipping the render target to the invalid rect, then the
+    // current render target is still clipped, so just fill the bounds.
+    IntRect rect = mCurrentRenderTarget->GetRect();
+    DrawQuad(Rect(rect), rect - rect.TopLeft(), effectChain, 1.0, Matrix4x4(),
+             Rect(rect));
+  }
+
+  mCurrentRenderTarget->SetClipRect(Nothing());
+
   mFrameInProgress = false;
 
+  if (mCurrentNativeLayer) {
+#ifdef XP_MACOSX
+    NativeLayerCA* nativeLayer = mCurrentNativeLayer->AsNativeLayerCA();
+    MOZ_RELEASE_ASSERT(nativeLayer, "Unexpected native layer type");
+    nativeLayer->NotifySurfaceReady();
+    mCurrentNativeLayer = nullptr;
+#else
+    MOZ_CRASH("Unexpected native layer on this platform");
+#endif
+  }
+
   if (mTarget) {
     CopyToTarget(mTarget, mTargetBounds.TopLeft(), Matrix());
     mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
     mWindowRenderTarget = nullptr;
     mCurrentRenderTarget = nullptr;
     Compositor::EndFrame();
     return;
   }
--- a/gfx/layers/opengl/CompositorOGL.h
+++ b/gfx/layers/opengl/CompositorOGL.h
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_COMPOSITOROGL_H
 #define MOZILLA_GFX_COMPOSITOROGL_H
 
 #include <map>
+#include <unordered_map>
 #include <unordered_set>
 
 #include "gfx2DGlue.h"
 #include "GLContextTypes.h"             // for GLContext, etc
 #include "GLDefs.h"                     // for GLuint, LOCAL_GL_TEXTURE_2D, etc
 #include "OGLShaderConfig.h"            // for ShaderConfigOGL
 #include "Units.h"                      // for ScreenPoint
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
@@ -31,16 +32,24 @@
 #include "nsCOMPtr.h"         // for already_AddRefed
 #include "nsDebug.h"          // for NS_ASSERTION, NS_WARNING
 #include "nsISupportsImpl.h"  // for MOZ_COUNT_CTOR, etc
 #include "nsTArray.h"         // for AutoTArray, nsTArray, etc
 #include "nsThreadUtils.h"    // for nsRunnable
 #include "nsXULAppAPI.h"      // for XRE_GetProcessType
 #include "nscore.h"           // for NS_IMETHOD
 
+#ifdef XP_MACOSX
+// This file uses IOSurfacePtr instead of IOSurfaceRef because IOSurfaceRef is
+// hard to forward declare, and including <IOSurface/IOSurface.h> brings in
+// MacTypes.h which defines Point and Rect which cause name lookup trouble.
+struct DummyIOSurface;
+typedef DummyIOSurface* IOSurfacePtr;
+#endif
+
 class nsIWidget;
 
 namespace mozilla {
 
 namespace layers {
 
 class CompositingRenderTarget;
 class CompositingRenderTargetOGL;
@@ -138,16 +147,23 @@ class CompositorOGL final : public Compo
     TextureFactoryIdentifier result = TextureFactoryIdentifier(
         LayersBackend::LAYERS_OPENGL, XRE_GetProcessType(), GetMaxTextureSize(),
         SupportsTextureDirectMapping(), false,
         mFBOTextureTarget == LOCAL_GL_TEXTURE_2D,
         SupportsPartialTextureUpdate());
     return result;
   }
 
+  // Returns a render target for the native layer.
+  // aInvalidRegion will be mutated to include existing invalid areas in the
+  // layer. aInvalidRegion is in window coordinates, i.e. in the same space
+  // as aNativeLayer->GetRect().
+  already_AddRefed<CompositingRenderTargetOGL> RenderTargetForNativeLayer(
+      NativeLayer* aNativeLayer, gfx::IntRegion& aInvalidRegion);
+
   already_AddRefed<CompositingRenderTarget> CreateRenderTarget(
       const gfx::IntRect& aRect, SurfaceInitMode aInit) override;
 
   already_AddRefed<CompositingRenderTarget> CreateRenderTargetFromSource(
       const gfx::IntRect& aRect, const CompositingRenderTarget* aSource,
       const gfx::IntPoint& aSourcePoint) override;
 
   void SetRenderTarget(CompositingRenderTarget* aSurface) override;
@@ -261,16 +277,21 @@ class CompositorOGL final : public Compo
     mSurfaceOrigin = aOrigin;
   }
 
   // Register TextureSource which own device data that have to be deleted before
   // destroying this CompositorOGL.
   void RegisterTextureSource(TextureSource* aTextureSource);
   void UnregisterTextureSource(TextureSource* aTextureSource);
 
+#ifdef XP_MACOSX
+  void RegisterIOSurface(IOSurfacePtr aSurface);
+  void UnregisterIOSurface(IOSurfacePtr aSurface);
+#endif
+
  private:
   template <typename Geometry>
   void DrawGeometry(const Geometry& aGeometry, const gfx::Rect& aRect,
                     const gfx::IntRect& aClipRect,
                     const EffectChain& aEffectChain, gfx::Float aOpacity,
                     const gfx::Matrix4x4& aTransform,
                     const gfx::Rect& aVisibleRect);
 
@@ -280,16 +301,17 @@ class CompositorOGL final : public Compo
 
   void InsertFrameDoneSync();
 
   /** Widget associated with this compositor */
   LayoutDeviceIntSize mWidgetSize;
   RefPtr<GLContext> mGLContext;
   UniquePtr<GLBlitTextureImageHelper> mBlitTextureImageHelper;
   gfx::Matrix4x4 mProjMatrix;
+  bool mCanRenderToDefaultFramebuffer = true;
 
 #ifdef XP_DARWIN
   nsTArray<RefPtr<BufferTextureHost>> mMaybeUnlockBeforeNextComposition;
 #endif
 
   /** The size of the surface we are rendering to */
   gfx::IntSize mSurfaceSize;
 
@@ -343,17 +365,17 @@ class CompositorOGL final : public Compo
   void ClearRect(const gfx::Rect& aRect) override;
 
   /* Start a new frame. If aClipRectIn is null and aClipRectOut is non-null,
    * sets *aClipRectOut to the screen dimensions.
    */
   void BeginFrame(const nsIntRegion& aInvalidRegion,
                   const gfx::IntRect* aClipRectIn,
                   const gfx::IntRect& aRenderBounds,
-                  const nsIntRegion& aOpaqueRegion,
+                  const nsIntRegion& aOpaqueRegion, NativeLayer* aNativeLayer,
                   gfx::IntRect* aClipRectOut = nullptr,
                   gfx::IntRect* aRenderBoundsOut = nullptr) override;
 
   ShaderConfigOGL GetShaderConfigFor(
       Effect* aEffect, TextureSourceOGL* aSourceMask = nullptr,
       gfx::CompositionOp aOp = gfx::CompositionOp::OP_OVER,
       bool aColorMatrix = false, bool aDEAAEnabled = false) const;
 
@@ -448,29 +470,46 @@ class CompositorOGL final : public Compo
    * pointing upwards, but the layers/compositor coordinate system has the
    * y-axis pointing downwards, for good reason as Web pages are typically
    * scrolled downwards. So, some flipping has to take place; FlippedY does it.
    */
   GLint FlipY(GLint y) const { return mViewportSize.height - y; }
 
   RefPtr<CompositorTexturePoolOGL> mTexturePool;
 
+  // The native layer that we're currently rendering to, if any.
+  // Non-null only between BeginFrame and EndFrame if BeginFrame has been called
+  // with a non-null aNativeLayer.
+  RefPtr<NativeLayer> mCurrentNativeLayer;
+
 #ifdef MOZ_WIDGET_GTK
   // Hold TextureSources which own device data that have to be deleted before
   // destroying this CompositorOGL.
   std::unordered_set<TextureSource*> mRegisteredTextureSources;
 #endif
 
   bool mDestroyed;
 
   /**
    * Size of the OpenGL context's primary framebuffer in pixels. Used by
    * FlipY for the y-flipping calculation and by the DEAA shader.
    */
   gfx::IntSize mViewportSize;
 
   ShaderProgramOGL* mCurrentProgram;
+
+#ifdef XP_MACOSX
+  struct IOSurfaceRefHasher {
+    std::size_t operator()(const IOSurfacePtr& aSurface) const {
+      return HashGeneric(reinterpret_cast<uintptr_t>(aSurface));
+    }
+  };
+
+  std::unordered_map<IOSurfacePtr, RefPtr<CompositingRenderTargetOGL>,
+                     IOSurfaceRefHasher>
+      mRegisteredIOSurfaceRenderTargets;
+#endif
 };
 
 }  // namespace layers
 }  // namespace mozilla
 
 #endif /* MOZILLA_GFX_COMPOSITOROGL_H */
--- a/gfx/webrender_bindings/RenderCompositor.h
+++ b/gfx/webrender_bindings/RenderCompositor.h
@@ -13,34 +13,35 @@
 
 namespace mozilla {
 
 namespace gl {
 class GLContext;
 }
 
 namespace layers {
+class NativeLayer;
 class SyncObjectHost;
-}
+}  // namespace layers
 
 namespace widget {
 class CompositorWidget;
 }
 
 namespace wr {
 
 class RenderCompositor {
  public:
   static UniquePtr<RenderCompositor> Create(
       RefPtr<widget::CompositorWidget>&& aWidget);
 
   RenderCompositor(RefPtr<widget::CompositorWidget>&& aWidget);
   virtual ~RenderCompositor();
 
-  virtual bool BeginFrame() = 0;
+  virtual bool BeginFrame(layers::NativeLayer* aNativeLayer) = 0;
   virtual void EndFrame() = 0;
   // Returns false when waiting gpu tasks is failed.
   // It might happen when rendering context is lost.
   virtual bool WaitForGPU() { return true; }
   virtual void Pause() = 0;
   virtual bool Resume() = 0;
 
   virtual gl::GLContext* gl() const { return nullptr; }
--- a/gfx/webrender_bindings/RenderCompositorANGLE.cpp
+++ b/gfx/webrender_bindings/RenderCompositorANGLE.cpp
@@ -330,17 +330,18 @@ void RenderCompositorANGLE::CreateSwapCh
     mSwapChain = swapChain1;
     mVisual->SetContent(swapChain1);
     mCompositionTarget->SetRoot(mVisual);
     mCompositionDevice = dCompDevice;
     mUseTripleBuffering = useTripleBuffering;
   }
 }
 
-bool RenderCompositorANGLE::BeginFrame() {
+bool RenderCompositorANGLE::BeginFrame(layers::NativeLayer* aNativeLayer) {
+  MOZ_RELEASE_ASSERT(!aNativeLayer, "Unexpected native layer on this platform");
   mWidget->AsWindows()->UpdateCompositorWndSizeIfNecessary();
 
   if (!ResizeBufferIfNeeded()) {
     return false;
   }
 
   if (!MakeCurrent()) {
     gfxCriticalNote << "Failed to make render context current, can't draw.";
--- a/gfx/webrender_bindings/RenderCompositorANGLE.h
+++ b/gfx/webrender_bindings/RenderCompositorANGLE.h
@@ -34,17 +34,17 @@ class RenderCompositorANGLE : public Ren
  public:
   static UniquePtr<RenderCompositor> Create(
       RefPtr<widget::CompositorWidget>&& aWidget);
 
   explicit RenderCompositorANGLE(RefPtr<widget::CompositorWidget>&& aWidget);
   virtual ~RenderCompositorANGLE();
   bool Initialize();
 
-  bool BeginFrame() override;
+  bool BeginFrame(layers::NativeLayer* aNativeLayer) override;
   void EndFrame() override;
   bool WaitForGPU() override;
   void Pause() override;
   bool Resume() override;
 
   gl::GLContext* gl() const override { return RenderThread::Get()->SharedGL(); }
 
   bool MakeCurrent() override;
--- a/gfx/webrender_bindings/RenderCompositorEGL.cpp
+++ b/gfx/webrender_bindings/RenderCompositorEGL.cpp
@@ -58,17 +58,18 @@ RenderCompositorEGL::RenderCompositorEGL
 RenderCompositorEGL::~RenderCompositorEGL() {
 #ifdef MOZ_WIDGET_ANDROID
   java::GeckoSurfaceTexture::DestroyUnused((int64_t)gl());
   java::GeckoSurfaceTexture::DetachAllFromGLContext((int64_t)gl());
 #endif
   DestroyEGLSurface();
 }
 
-bool RenderCompositorEGL::BeginFrame() {
+bool RenderCompositorEGL::BeginFrame(layers::NativeLayer* aNativeLayer) {
+  MOZ_RELEASE_ASSERT(!aNativeLayer, "Unexpected native layer on this platform");
 #ifdef MOZ_WAYLAND
   bool newSurface =
       mWidget->AsX11() && mWidget->AsX11()->WaylandRequestsUpdatingEGLSurface();
   if (newSurface) {
     // Destroy EGLSurface if it exists and create a new one. We will set the
     // swap interval after MakeCurrent() has been called.
     DestroyEGLSurface();
     mEGLSurface = CreateEGLSurface();
--- a/gfx/webrender_bindings/RenderCompositorEGL.h
+++ b/gfx/webrender_bindings/RenderCompositorEGL.h
@@ -17,17 +17,17 @@ namespace wr {
 class RenderCompositorEGL : public RenderCompositor {
  public:
   static UniquePtr<RenderCompositor> Create(
       RefPtr<widget::CompositorWidget> aWidget);
 
   explicit RenderCompositorEGL(RefPtr<widget::CompositorWidget> aWidget);
   virtual ~RenderCompositorEGL();
 
-  bool BeginFrame() override;
+  bool BeginFrame(layers::NativeLayer* aNativeLayer) override;
   void EndFrame() override;
   void Pause() override;
   bool Resume() override;
 
   gl::GLContext* gl() const override;
 
   bool MakeCurrent() override;
 
--- a/gfx/webrender_bindings/RenderCompositorOGL.cpp
+++ b/gfx/webrender_bindings/RenderCompositorOGL.cpp
@@ -6,16 +6,21 @@
 
 #include "RenderCompositorOGL.h"
 
 #include "GLContext.h"
 #include "GLContextProvider.h"
 #include "mozilla/StaticPrefs_gfx.h"
 #include "mozilla/widget/CompositorWidget.h"
 
+#ifdef XP_MACOSX
+#  include "GLContextCGL.h"
+#  include "mozilla/layers/NativeLayerCA.h"
+#endif
+
 namespace mozilla {
 namespace wr {
 
 /* static */
 UniquePtr<RenderCompositor> RenderCompositorOGL::Create(
     RefPtr<widget::CompositorWidget>&& aWidget) {
   RefPtr<gl::GLContext> gl;
   gl = gl::GLContextProvider::CreateForCompositorWidget(
@@ -50,29 +55,85 @@ RenderCompositorOGL::~RenderCompositorOG
   if (mPreviousFrameDoneSync) {
     mGL->fDeleteSync(mPreviousFrameDoneSync);
   }
   if (mThisFrameDoneSync) {
     mGL->fDeleteSync(mThisFrameDoneSync);
   }
 }
 
-bool RenderCompositorOGL::BeginFrame() {
+#ifdef XP_MACOSX
+class SurfaceRegistryWrapperAroundGLContextCGL
+    : public layers::IOSurfaceRegistry {
+ public:
+  explicit SurfaceRegistryWrapperAroundGLContextCGL(gl::GLContextCGL* aContext)
+      : mContext(aContext) {}
+  void RegisterSurface(CFTypeRefPtr<IOSurfaceRef> aSurface) override {
+    mContext->RegisterIOSurface(aSurface.get());
+  }
+  void UnregisterSurface(CFTypeRefPtr<IOSurfaceRef> aSurface) override {
+    mContext->UnregisterIOSurface(aSurface.get());
+  }
+  RefPtr<gl::GLContextCGL> mContext;
+};
+#endif
+
+bool RenderCompositorOGL::BeginFrame(layers::NativeLayer* aNativeLayer) {
   if (!mGL->MakeCurrent()) {
     gfxCriticalNote << "Failed to make render context current, can't draw.";
     return false;
   }
 
+  if (aNativeLayer) {
+#ifdef XP_MACOSX
+    layers::NativeLayerCA* nativeLayer = aNativeLayer->AsNativeLayerCA();
+    MOZ_RELEASE_ASSERT(nativeLayer, "Unexpected native layer type");
+    nativeLayer->SetSurfaceIsFlipped(true);
+    auto glContextCGL = gl::GLContextCGL::Cast(mGL);
+    MOZ_RELEASE_ASSERT(glContextCGL, "Unexpected GLContext type");
+    RefPtr<layers::IOSurfaceRegistry> currentRegistry =
+        nativeLayer->GetSurfaceRegistry();
+    if (!currentRegistry) {
+      nativeLayer->SetSurfaceRegistry(
+          MakeAndAddRef<SurfaceRegistryWrapperAroundGLContextCGL>(
+              glContextCGL));
+    } else {
+      MOZ_RELEASE_ASSERT(static_cast<SurfaceRegistryWrapperAroundGLContextCGL*>(
+                             currentRegistry.get())
+                             ->mContext == glContextCGL);
+    }
+    CFTypeRefPtr<IOSurfaceRef> surf = nativeLayer->NextSurface();
+    if (!surf) {
+      return false;
+    }
+    glContextCGL->UseRegisteredIOSurfaceForDefaultFramebuffer(surf.get());
+    mCurrentNativeLayer = aNativeLayer;
+#else
+    MOZ_CRASH("Unexpected native layer on this platform");
+#endif
+  }
+
   mGL->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mGL->GetDefaultFramebuffer());
   return true;
 }
 
 void RenderCompositorOGL::EndFrame() {
   InsertFrameDoneSync();
   mGL->SwapBuffers();
+
+  if (mCurrentNativeLayer) {
+#ifdef XP_MACOSX
+    layers::NativeLayerCA* nativeLayer = mCurrentNativeLayer->AsNativeLayerCA();
+    MOZ_RELEASE_ASSERT(nativeLayer, "Unexpected native layer type");
+    nativeLayer->NotifySurfaceReady();
+    mCurrentNativeLayer = nullptr;
+#else
+    MOZ_CRASH("Unexpected native layer on this platform");
+#endif
+  }
 }
 
 void RenderCompositorOGL::InsertFrameDoneSync() {
 #ifdef XP_MACOSX
   // Only do this on macOS.
   // On other platforms, SwapBuffers automatically applies back-pressure.
   if (StaticPrefs::gfx_core_animation_enabled_AtStartup()) {
     if (mThisFrameDoneSync) {
--- a/gfx/webrender_bindings/RenderCompositorOGL.h
+++ b/gfx/webrender_bindings/RenderCompositorOGL.h
@@ -17,33 +17,38 @@ class RenderCompositorOGL : public Rende
  public:
   static UniquePtr<RenderCompositor> Create(
       RefPtr<widget::CompositorWidget>&& aWidget);
 
   RenderCompositorOGL(RefPtr<gl::GLContext>&& aGL,
                       RefPtr<widget::CompositorWidget>&& aWidget);
   virtual ~RenderCompositorOGL();
 
-  bool BeginFrame() override;
+  bool BeginFrame(layers::NativeLayer* aNativeLayer) override;
   void EndFrame() override;
   bool WaitForGPU() override;
   void Pause() override;
   bool Resume() override;
 
   gl::GLContext* gl() const override { return mGL; }
 
   bool UseANGLE() const override { return false; }
 
   LayoutDeviceIntSize GetBufferSize() override;
 
  protected:
   void InsertFrameDoneSync();
 
   RefPtr<gl::GLContext> mGL;
 
+  // The native layer that we're currently rendering to, if any.
+  // Non-null only between BeginFrame and EndFrame if BeginFrame has been called
+  // with a non-null aNativeLayer.
+  RefPtr<layers::NativeLayer> mCurrentNativeLayer;
+
   // Used to apply back-pressure in WaitForGPU().
   GLsync mPreviousFrameDoneSync;
   GLsync mThisFrameDoneSync;
 };
 
 }  // namespace wr
 }  // namespace mozilla
 
--- a/gfx/webrender_bindings/RendererOGL.cpp
+++ b/gfx/webrender_bindings/RendererOGL.cpp
@@ -53,27 +53,37 @@ RendererOGL::RendererOGL(RefPtr<RenderTh
       mRenderer(aRenderer),
       mBridge(aBridge),
       mWindowId(aWindowId) {
   MOZ_ASSERT(mThread);
   MOZ_ASSERT(mCompositor);
   MOZ_ASSERT(mRenderer);
   MOZ_ASSERT(mBridge);
   MOZ_COUNT_CTOR(RendererOGL);
+
+  mNativeLayerRoot = mCompositor->GetWidget()->GetNativeLayerRoot();
+  if (mNativeLayerRoot) {
+    mNativeLayerForEntireWindow = mNativeLayerRoot->CreateLayer();
+    mNativeLayerRoot->AppendLayer(mNativeLayerForEntireWindow);
+  }
 }
 
 RendererOGL::~RendererOGL() {
   MOZ_COUNT_DTOR(RendererOGL);
   if (!mCompositor->MakeCurrent()) {
     gfxCriticalNote
         << "Failed to make render context current during destroying.";
     // Leak resources!
     return;
   }
-  mCompositor->GetWidget()->DoCompositorCleanup();
+  if (mNativeLayerRoot) {
+    mNativeLayerRoot->RemoveLayer(mNativeLayerForEntireWindow);
+    mNativeLayerForEntireWindow = nullptr;
+    mNativeLayerRoot = nullptr;
+  }
   wr_renderer_delete(mRenderer);
 }
 
 wr::WrExternalImageHandler RendererOGL::GetExternalImageHandler() {
   return wr::WrExternalImageHandler{
       this,
   };
 }
@@ -105,30 +115,41 @@ bool RendererOGL::UpdateAndRender(const 
 
   if (!mCompositor->GetWidget()->PreRender(&widgetContext)) {
     // XXX This could cause oom in webrender since pending_texture_updates is
     // not handled. It needs to be addressed.
     return false;
   }
   // XXX set clear color if MOZ_WIDGET_ANDROID is defined.
 
-  if (!mCompositor->BeginFrame()) {
+  auto size = mCompositor->GetBufferSize();
+
+  if (mNativeLayerForEntireWindow) {
+    gfx::IntRect bounds(gfx::IntPoint(0, 0), size.ToUnknownSize());
+    mNativeLayerForEntireWindow->SetRect(bounds);
+#ifdef XP_MACOSX
+    mNativeLayerForEntireWindow->SetOpaqueRegion(
+        mCompositor->GetWidget()->GetOpaqueWidgetRegion().ToUnknownRegion());
+#endif
+  }
+
+  if (!mCompositor->BeginFrame(mNativeLayerForEntireWindow)) {
     if (mCompositor->IsContextLost()) {
       RenderThread::Get()->HandleDeviceReset("BeginFrame", /* aNotify */ true);
     }
+    mCompositor->GetWidget()->PostRender(&widgetContext);
     return false;
   }
 
   wr_renderer_update(mRenderer);
 
-  auto size = mCompositor->GetBufferSize();
-
   if (!wr_renderer_render(mRenderer, size.width, size.height, aHadSlowFrame,
                           aOutStats)) {
     RenderThread::Get()->HandleWebRenderError(WebRenderError::RENDER);
+    mCompositor->GetWidget()->PostRender(&widgetContext);
     return false;
   }
 
   if (aReadbackBuffer.isSome()) {
     MOZ_ASSERT(aReadbackSize.isSome());
     MOZ_ASSERT(aReadbackFormat.isSome());
     wr_renderer_readback(mRenderer, aReadbackSize.ref().width,
                          aReadbackSize.ref().height, aReadbackFormat.ref(),
--- a/gfx/webrender_bindings/RendererOGL.h
+++ b/gfx/webrender_bindings/RendererOGL.h
@@ -21,16 +21,18 @@ class DrawTarget;
 }
 
 namespace gl {
 class GLContext;
 }
 
 namespace layers {
 class CompositorBridgeParent;
+class NativeLayerRoot;
+class NativeLayer;
 class SyncObjectHost;
 }  // namespace layers
 
 namespace widget {
 class CompositorWidget;
 }
 
 namespace wr {
@@ -101,16 +103,18 @@ class RendererOGL {
 
   wr::Renderer* GetRenderer() { return mRenderer; }
 
   gl::GLContext* gl() const;
 
  protected:
   RefPtr<RenderThread> mThread;
   UniquePtr<RenderCompositor> mCompositor;
+  RefPtr<layers::NativeLayerRoot> mNativeLayerRoot;
+  RefPtr<layers::NativeLayer> mNativeLayerForEntireWindow;
   wr::Renderer* mRenderer;
   layers::CompositorBridgeParent* mBridge;
   wr::WindowId mWindowId;
   TimeStamp mFrameStartTime;
 
   RendererScreenshotGrabber mScreenshotGrabber;
 };
 
--- a/image/VectorImage.cpp
+++ b/image/VectorImage.cpp
@@ -1278,17 +1278,18 @@ NS_IMETHODIMP
 VectorImage::RequestDiscard() {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (mDiscardable && mLockCount == 0) {
     SurfaceCache::RemoveImage(ImageKey(this));
     mProgressTracker->OnDiscard();
   }
 
-  if (Document* doc = mSVGDocumentWrapper->GetDocument()) {
+  if (Document* doc =
+          mSVGDocumentWrapper ? mSVGDocumentWrapper->GetDocument() : nullptr) {
     doc->ReportUseCounters();
   }
 
   return NS_OK;
 }
 
 void VectorImage::OnSurfaceDiscarded(const SurfaceKey& aSurfaceKey) {
   MOZ_ASSERT(mProgressTracker);
--- a/layout/style/nsMediaFeatures.cpp
+++ b/layout/style/nsMediaFeatures.cpp
@@ -61,31 +61,30 @@ static nsSize GetSize(const Document* aD
     //
     // FIXME(emilio, bug 1414600): Not quite!
     return pc->GetPageSize();
   }
 
   return pc->GetVisibleArea().Size();
 }
 
-static bool IsDeviceSizePageSize(const Document* aDocument) {
-  nsIDocShell* docShell = aDocument->GetDocShell();
-  if (!docShell) {
-    return false;
-  }
-  return docShell->GetDeviceSizeIsPageSize();
-}
-
 // A helper for three features below.
 static nsSize GetDeviceSize(const Document* aDocument) {
-  if (nsContentUtils::ShouldResistFingerprinting(aDocument) ||
-      IsDeviceSizePageSize(aDocument)) {
+  if (nsContentUtils::ShouldResistFingerprinting(aDocument)) {
     return GetSize(aDocument);
   }
 
+  // Media queries in documents in an RDM pane should use the simulated
+  // device size.
+  Maybe<CSSIntSize> deviceSize =
+      nsGlobalWindowOuter::GetRDMDeviceSize(*aDocument);
+  if (deviceSize.isSome()) {
+    return CSSPixel::ToAppUnits(deviceSize.value());
+  }
+
   nsPresContext* pc = aDocument->GetPresContext();
   // NOTE(emilio): We should probably figure out how to return an appropriate
   // device size here, though in a multi-screen world that makes no sense
   // really.
   if (!pc) {
     return {};
   }
 
--- a/layout/tools/layout-debug/src/nsLayoutDebugCLH.cpp
+++ b/layout/tools/layout-debug/src/nsLayoutDebugCLH.cpp
@@ -17,61 +17,161 @@
 #include "nsIURI.h"
 
 nsLayoutDebugCLH::nsLayoutDebugCLH() {}
 
 nsLayoutDebugCLH::~nsLayoutDebugCLH() {}
 
 NS_IMPL_ISUPPORTS(nsLayoutDebugCLH, ICOMMANDLINEHANDLER)
 
-NS_IMETHODIMP
-nsLayoutDebugCLH::Handle(nsICommandLine* aCmdLine) {
+static nsresult HandleFlagWithOptionalArgument(nsICommandLine* aCmdLine,
+                                               const nsAString& aName,
+                                               const nsAString& aDefaultValue,
+                                               nsAString& aValue,
+                                               bool& aFlagPresent) {
+  aValue = EmptyString();
+  aFlagPresent = false;
+
   nsresult rv;
+  int32_t idx;
 
-  int32_t idx;
-  rv = aCmdLine->FindFlag(NS_LITERAL_STRING("layoutdebug"), false, &idx);
+  rv = aCmdLine->FindFlag(aName, false, &idx);
   NS_ENSURE_SUCCESS(rv, rv);
   if (idx < 0) return NS_OK;
 
+  aFlagPresent = true;
+
   int32_t length;
   aCmdLine->GetLength(&length);
 
-  nsAutoString url;
+  bool argPresent = false;
+
   if (idx + 1 < length) {
-    rv = aCmdLine->GetArgument(idx + 1, url);
+    rv = aCmdLine->GetArgument(idx + 1, aValue);
     NS_ENSURE_SUCCESS(rv, rv);
-    if (!url.IsEmpty() && url.CharAt(0) == '-') url.Truncate();
+
+    if (!aValue.IsEmpty() && aValue.CharAt(0) == '-') {
+      aValue = EmptyString();
+    } else {
+      argPresent = true;
+    }
+  }
+
+  if (!argPresent) {
+    aValue = aDefaultValue;
+  }
+
+  return aCmdLine->RemoveArguments(idx, idx + argPresent);
+}
+
+static nsresult HandleFlagWithOptionalArgument(nsICommandLine* aCmdLine,
+                                               const nsAString& aName,
+                                               double aDefaultValue,
+                                               double& aValue,
+                                               bool& aFlagPresent) {
+  nsresult rv;
+  nsString s;
+
+  rv = HandleFlagWithOptionalArgument(aCmdLine, aName, NS_LITERAL_STRING("0"),
+                                      s, aFlagPresent);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (!aFlagPresent) {
+    aValue = 0.0;
+    return NS_OK;
   }
 
-  aCmdLine->RemoveArguments(idx, idx + !url.IsEmpty());
+  aValue = s.ToDouble(&rv);
+  return rv;
+}
+
+static nsresult AppendArg(nsIMutableArray* aArray, const nsAString& aString) {
+  nsCOMPtr<nsISupportsString> s =
+      do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID);
+  NS_ENSURE_TRUE(s, NS_ERROR_FAILURE);
+  s->SetData(aString);
+  return aArray->AppendElement(s);
+}
+
+NS_IMETHODIMP
+nsLayoutDebugCLH::Handle(nsICommandLine* aCmdLine) {
+  nsresult rv;
+  bool flagPresent;
+
+  nsString url;
+  bool autoclose = false;
+  double delay = 0.0;
+  bool captureProfile = false;
+  nsString profileFilename;
+
+  rv = HandleFlagWithOptionalArgument(
+      aCmdLine, NS_LITERAL_STRING("layoutdebug"),
+      NS_LITERAL_STRING("about:blank"), url, flagPresent);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (!flagPresent) {
+    return NS_OK;
+  }
+
+  rv = HandleFlagWithOptionalArgument(aCmdLine, NS_LITERAL_STRING("autoclose"),
+                                      0.0, delay, autoclose);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = HandleFlagWithOptionalArgument(
+      aCmdLine, NS_LITERAL_STRING("capture-profile"),
+      NS_LITERAL_STRING("profile.json"), profileFilename, captureProfile);
+  NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIMutableArray> argsArray = nsArray::Create();
 
-  if (!url.IsEmpty()) {
-    nsCOMPtr<nsIURI> uri;
-    rv = aCmdLine->ResolveURI(url, getter_AddRefs(uri));
+  nsCOMPtr<nsIURI> uri;
+  nsAutoCString resolvedSpec;
+
+  rv = aCmdLine->ResolveURI(url, getter_AddRefs(uri));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = uri->GetSpec(resolvedSpec);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = AppendArg(argsArray, NS_ConvertUTF8toUTF16(resolvedSpec));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (autoclose) {
+    nsString arg;
+    arg.AppendPrintf("autoclose=%f", delay);
+
+    rv = AppendArg(argsArray, arg);
     NS_ENSURE_SUCCESS(rv, rv);
-    nsCOMPtr<nsISupportsString> scriptableURL =
-        do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID);
-    NS_ENSURE_TRUE(scriptableURL, NS_ERROR_FAILURE);
-    nsAutoCString resolvedSpec;
-    rv = uri->GetSpec(resolvedSpec);
+  }
+
+  if (captureProfile) {
+    nsString arg;
+    arg.AppendLiteral("profile=");
+    arg.Append(profileFilename);
+
+    rv = AppendArg(argsArray, arg);
     NS_ENSURE_SUCCESS(rv, rv);
-    scriptableURL->SetData(NS_ConvertUTF8toUTF16(resolvedSpec));
-    argsArray->AppendElement(scriptableURL);
   }
 
   nsCOMPtr<nsIWindowWatcher> wwatch =
       do_GetService(NS_WINDOWWATCHER_CONTRACTID);
   NS_ENSURE_TRUE(wwatch, NS_ERROR_FAILURE);
 
   nsCOMPtr<mozIDOMWindowProxy> opened;
   wwatch->OpenWindow(nullptr, "chrome://layoutdebug/content/", "_blank",
                      "chrome,dialog=no,all", argsArray, getter_AddRefs(opened));
   aCmdLine->SetPreventDefault(true);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsLayoutDebugCLH::GetHelpInfo(nsACString& aResult) {
-  aResult.AssignLiteral("  --layoutdebug [<url>] Start with Layout Debugger\n");
+  aResult.AssignLiteral(
+      "  --layoutdebug [<url>] Start with Layout Debugger\n"
+      "  --autoclose [<seconds>] Automatically close the Layout Debugger once\n"
+      "                     the page has loaded, after delaying the specified\n"
+      "                     number of seconds (which defaults to 0).\n"
+      "  --capture-profile [<filename>] Capture a profile of the Layout\n"
+      "                     Debugger using the Gecko Profiler, and save the\n"
+      "                     profile to the specified file (which defaults to\n"
+      "                     profile.json).\n");
   return NS_OK;
 }
--- a/layout/tools/layout-debug/ui/content/layoutdebug.js
+++ b/layout/tools/layout-debug/ui/content/layoutdebug.js
@@ -1,23 +1,27 @@
 /* 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/. */
 
+var gArgs;
 var gBrowser;
 var gURLBar;
 var gDebugger;
 var gMultiProcessBrowser = window.docShell.QueryInterface(Ci.nsILoadContext)
   .useRemoteTabs;
 var gFissionBrowser = window.docShell.QueryInterface(Ci.nsILoadContext)
   .useRemoteSubframes;
+var gWritingProfile = false;
+var gWrittenProfile = false;
 
 const { E10SUtils } = ChromeUtils.import(
   "resource://gre/modules/E10SUtils.jsm"
 );
+const { OS } = ChromeUtils.import("resource://gre/modules/osfile.jsm");
 const { Preferences } = ChromeUtils.import(
   "resource://gre/modules/Preferences.jsm"
 );
 const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
 
 const HELPER_URL = "chrome://layoutdebug/content/layoutdebug-helper.js";
 
 const FEATURES = {
@@ -165,16 +169,30 @@ nsLDBBrowserContentListener.prototype = 
       this.setButtonEnabled(this.mForwardButton, gBrowser.canGoForward);
       this.setButtonEnabled(this.mBackButton, gBrowser.canGoBack);
       this.mStatusText.value = "loading...";
       this.mLoading = true;
     } else if (aStateFlags & Ci.nsIWebProgressListener.STATE_STOP) {
       this.setButtonEnabled(this.mStopButton, false);
       this.mStatusText.value = gURLBar.value + " loaded";
       this.mLoading = false;
+      if (gArgs.autoclose && gBrowser.currentURI.spec != "about:blank") {
+        // We check for about:blank just to avoid one or two STATE_STOP
+        // notifications that occur before the loadURI() call completes.
+        // This does mean that --autoclose doesn't work when the URL on
+        // the command line is about:blank (or not specified), but that's
+        // not a big deal.
+        setTimeout(function() {
+          if (gArgs.profile && Services.profiler) {
+            dumpProfile();
+          } else {
+            Services.startup.quit(Ci.nsIAppStartup.eAttemptQuit);
+          }
+        }, gArgs.delay * 1000);
+      }
     }
   },
 
   onProgressChange: function(
     aWebProgress,
     aRequest,
     aCurSelfProgress,
     aMaxSelfProgress,
@@ -208,34 +226,82 @@ nsLDBBrowserContentListener.prototype = 
   mStatusText: null,
   mForwardButton: null,
   mBackButton: null,
   mStopButton: null,
 
   mLoading: false,
 };
 
+function parseArguments() {
+  let args = {
+    url: null,
+    autoclose: false,
+    delay: 0,
+  };
+  if (window.arguments) {
+    args.url = window.arguments[0];
+    for (let i = 1; i < window.arguments.length; ++i) {
+      let arg = window.arguments[i];
+      if (/^autoclose=(.*)$/.test(arg)) {
+        args.autoclose = true;
+        args.delay = +RegExp.$1;
+      } else if (/^profile=(.*)$/.test(arg)) {
+        args.profile = true;
+        args.profileFilename = RegExp.$1;
+      } else {
+        throw `Unknown option ${arg}`;
+      }
+    }
+  }
+  return args;
+}
+
 function OnLDBLoad() {
   gBrowser = document.getElementById("browser");
   gURLBar = document.getElementById("urlbar");
 
   gDebugger = new Debugger();
 
   checkPersistentMenus();
 
   // Pretend slightly to be like a normal browser, so that SessionStore.jsm
   // doesn't get too confused.  The effect is that we'll never switch process
   // type when navigating, and for layout debugging purposes we don't bother
   // about getting that right.
   gBrowser.getTabForBrowser = function() {
     return null;
   };
 
-  if (window.arguments && window.arguments[0]) {
-    loadURI(window.arguments[0]);
+  gArgs = parseArguments();
+
+  if (gArgs.profile) {
+    if (Services.profiler) {
+      let env = Cc["@mozilla.org/process/environment;1"].getService(
+        Ci.nsIEnvironment
+      );
+      if (!env.exists("MOZ_PROFILER_SYMBOLICATE")) {
+        dump(
+          "Warning: MOZ_PROFILER_SYMBOLICATE environment variable not set; " +
+            "profile will not be symbolicated.\n"
+        );
+      }
+      Services.profiler.StartProfiler(
+        1 << 20,
+        1,
+        ["default"],
+        ["GeckoMain", "Compositor", "Renderer", "RenderBackend", "StyleThread"]
+      );
+    } else {
+      dump("Cannot profile Layout Debugger; profiler was not compiled in.\n");
+    }
+  }
+
+  if (gArgs.url) {
+    loadURI(gArgs.url);
   }
 }
 
 function checkPersistentMenu(item) {
   var menuitem = document.getElementById("menu_" + item);
   menuitem.setAttribute("checked", gDebugger[item]);
 }
 
@@ -245,16 +311,53 @@ function checkPersistentMenus() {
   checkPersistentMenu("paintDumping");
   checkPersistentMenu("invalidateDumping");
   checkPersistentMenu("eventDumping");
   checkPersistentMenu("motionEventDumping");
   checkPersistentMenu("crossingEventDumping");
   checkPersistentMenu("reflowCounts");
 }
 
+function dumpProfile() {
+  gWritingProfile = true;
+
+  let cwd = Services.dirsvc.get("CurWorkD", Ci.nsIFile).path;
+  let filename = OS.Path.join(cwd, gArgs.profileFilename);
+
+  dump(`Writing profile to ${filename}...\n`);
+
+  Services.profiler.dumpProfileToFileAsync(filename).then(function() {
+    gWritingProfile = false;
+    gWrittenProfile = true;
+    dump(`done\n`);
+    Services.startup.quit(Ci.nsIAppStartup.eAttemptQuit);
+  });
+}
+
+function OnLDBBeforeUnload(event) {
+  if (gArgs.profile && Services.profiler) {
+    if (gWrittenProfile) {
+      // We've finished writing the profile.  Allow the window to close.
+      return;
+    }
+
+    event.preventDefault();
+
+    if (gWritingProfile) {
+      // Wait for the profile to finish being written out.
+      return;
+    }
+
+    // The dumpProfileToFileAsync call can block for a while, so run it off a
+    // timeout to avoid annoying the window manager if we're doing this in
+    // response to clicking the window's close button.
+    setTimeout(dumpProfile, 0);
+  }
+}
+
 function OnLDBUnload() {
   gDebugger.detachBrowser();
 }
 
 function toggle(menuitem) {
   // trim the initial "menu_"
   var feature = menuitem.id.substring(5);
   gDebugger[feature] = menuitem.getAttribute("checked") == "true";
--- a/layout/tools/layout-debug/ui/content/layoutdebug.xul
+++ b/layout/tools/layout-debug/ui/content/layoutdebug.xul
@@ -23,16 +23,17 @@
         id="main-window"
         align="stretch"
         title="&ldb.MainWindow.title;"
         titlemodifier="&ldb.MainWindow.title;"
         contenttitlesetting="true"
         titlemenuseparator=" - "
         windowtype="mozapp:layoutdebug"
         onload="OnLDBLoad();"
+        onclose="OnLDBBeforeUnload(event);"
         onunload="OnLDBUnload();"
         width="1024" height="768"
         screenX="4" screenY="4"
         >
 
   <script src="chrome://layoutdebug/content/layoutdebug.js"/>
 
   <commandset id="tasksCommands">
--- a/memory/replace/phc/PHC.cpp
+++ b/memory/replace/phc/PHC.cpp
@@ -86,16 +86,17 @@
 #include "mozilla/Attributes.h"
 #include "mozilla/CheckedInt.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/StackWalk.h"
 #include "mozilla/ThreadLocal.h"
 #include "mozilla/XorShift128PlusRNG.h"
 
 using namespace mozilla;
+using namespace mozilla::recordreplay;
 
 //---------------------------------------------------------------------------
 // Utilities
 //---------------------------------------------------------------------------
 
 #ifdef ANDROID
 // Android doesn't have pthread_atfork defined in pthread.h.
 extern "C" MOZ_EXPORT int pthread_atfork(void (*)(void), void (*)(void),
@@ -321,26 +322,26 @@ class GAtomic {
   static int32_t DecrementDelay() { return --sAllocDelay; }
 
   static void SetAllocDelay(Delay aAllocDelay) { sAllocDelay = aAllocDelay; }
 
  private:
   // The current time. Relaxed semantics because it's primarily used for
   // determining if an allocation can be recycled yet and therefore it doesn't
   // need to be exact.
-  static Atomic<Time, Relaxed> sNow;
+  static Atomic<Time, Relaxed, Behavior::DontPreserve> sNow;
 
   // Delay until the next attempt at a page allocation. See the comment in
   // MaybePageAlloc() for an explanation of why it is a signed integer, and why
   // it uses ReleaseAcquire semantics.
-  static Atomic<Delay, ReleaseAcquire> sAllocDelay;
+  static Atomic<Delay, ReleaseAcquire, Behavior::DontPreserve> sAllocDelay;
 };
 
-Atomic<Time, Relaxed> GAtomic::sNow;
-Atomic<Delay, ReleaseAcquire> GAtomic::sAllocDelay;
+Atomic<Time, Relaxed, Behavior::DontPreserve> GAtomic::sNow;
+Atomic<Delay, ReleaseAcquire, Behavior::DontPreserve> GAtomic::sAllocDelay;
 
 // Shared, immutable global state. Initialized by replace_init() and never
 // changed after that. replace_init() runs early enough that no synchronization
 // is needed.
 class GConst {
  private:
   // The bounds of the allocated pages.
   const uintptr_t mPagesStart;
--- a/modules/libpref/greprefs.js
+++ b/modules/libpref/greprefs.js
@@ -1,2 +1,1 @@
 #include init/all.js
-#include ../../devtools/shared/preferences/devtools-shared.js
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -2081,16 +2081,19 @@ pref("network.dns.forceResolve", "");
 
 // Contols whether or not "localhost" should resolve when offline
 pref("network.dns.offline-localhost", true);
 
 // Defines how much longer resolver threads should stay idle before are shut down.
 // A negative value will keep the thread alive forever.
 pref("network.dns.resolver-thread-extra-idle-time-seconds", 60);
 
+// Whether to disable TRR when parental control is enabled.
+pref("network.dns.skipTRR-when-parental-control-enabled", true);
+
 // The maximum allowed length for a URL - 1MB default
 pref("network.standard-url.max-length", 1048576);
 
 // Whether nsIURI.host/.hostname/.spec should return a punycode string
 // If set to false we will revert to previous behaviour and return a unicode string.
 pref("network.standard-url.punycode-host", true);
 
 // Idle timeout for ftp control connections - 5 minute default
@@ -5625,8 +5628,92 @@ pref("remote.enabled", false);
 pref("remote.force-local", true);
 
 // Defines the verbosity of the internal logger.
 //
 // Available levels are, in descending order of severity, "Trace", "Debug",
 // "Config", "Info", "Warn", "Error", and "Fatal". The value is treated
 // case-sensitively.
 pref("remote.log.level", "Info");
+
+// Enable the JSON View tool (an inspector for application/json documents).
+pref("devtools.jsonview.enabled", true);
+
+// Default theme ("dark" or "light").
+#ifdef MOZ_DEV_EDITION
+  pref("devtools.theme", "dark", sticky);
+#else
+  pref("devtools.theme", "light", sticky);
+#endif
+
+// Completely disable DevTools entry points, as well as all DevTools command
+// line arguments This should be merged with devtools.enabled, see Bug 1440675.
+pref("devtools.policy.disabled", false);
+
+// Tells if DevTools have been explicitely enabled by the user. This pref
+// allows to disable all features related to DevTools for users that never use
+// them. Until bug 1361080 lands, we always consider them enabled.
+pref("devtools.enabled", true);
+
+// Enable deprecation warnings.
+pref("devtools.errorconsole.deprecation_warnings", true);
+
+#ifdef NIGHTLY_BUILD
+  // Don't show the Browser Toolbox prompt on local builds / nightly.
+  pref("devtools.debugger.prompt-connection", false, sticky);
+#else
+  pref("devtools.debugger.prompt-connection", true, sticky);
+#endif
+
+#ifdef MOZILLA_OFFICIAL
+  // Disable debugging chrome.
+  pref("devtools.chrome.enabled", false, sticky);
+  // Disable remote debugging connections.
+  pref("devtools.debugger.remote-enabled", false, sticky);
+#else
+  // In local builds, enable the browser toolbox by default.
+  pref("devtools.chrome.enabled", true, sticky);
+  pref("devtools.debugger.remote-enabled", true, sticky);
+#endif
+
+// Disable remote debugging protocol logging.
+pref("devtools.debugger.log", false);
+pref("devtools.debugger.log.verbose", false);
+
+pref("devtools.debugger.remote-port", 6000);
+pref("devtools.debugger.remote-websocket", false);
+// Force debugger server binding on the loopback interface.
+pref("devtools.debugger.force-local", true);
+
+// Limit for intercepted request and response bodies (1 MB).
+// Possible values:
+// 0 => the response body has no limit
+// n => represents max number of bytes stored
+pref("devtools.netmonitor.responseBodyLimit", 1048576);
+pref("devtools.netmonitor.requestBodyLimit", 1048576);
+
+// Limit for WebSocket frames (100 KB).
+pref("devtools.netmonitor.ws.messageDataLimit", 100000);
+
+// DevTools default color unit.
+pref("devtools.defaultColorUnit", "authored");
+
+// Used for devtools debugging.
+pref("devtools.dump.emit", false);
+
+// Disable device discovery logging.
+pref("devtools.discovery.log", false);
+// Whether to scan for DevTools devices via WiFi.
+pref("devtools.remote.wifi.scan", true);
+// Client must complete TLS handshake within this window (ms).
+pref("devtools.remote.tls-handshake-timeout", 10000);
+
+// The extension ID for devtools-adb-extension.
+pref("devtools.remote.adb.extensionID", "adb@mozilla.org");
+// The URL for for devtools-adb-extension (overridden in tests to a local
+// path).
+pref("devtools.remote.adb.extensionURL", "https://ftp.mozilla.org/pub/mozilla.org/labs/devtools/adb-extension/#OS#/adb-extension-latest-#OS#.xpi");
+
+// URL of the remote JSON catalog used for device simulation.
+pref("devtools.devices.url", "https://code.cdn.mozilla.net/devices/devices.json");
+
+// Enable Inactive CSS detection; used both by the client and the server.
+pref("devtools.inspector.inactive.css.enabled", true);
--- a/netwerk/dns/ChildDNSService.cpp
+++ b/netwerk/dns/ChildDNSService.cpp
@@ -277,16 +277,21 @@ ChildDNSService::GetDNSCacheEntries(
   // unless we start keeping per-app DNS caches).
   return NS_ERROR_NOT_AVAILABLE;
 }
 
 NS_IMETHODIMP
 ChildDNSService::ClearCache(bool aTrrToo) { return NS_ERROR_NOT_AVAILABLE; }
 
 NS_IMETHODIMP
+ChildDNSService::ReloadParentalControlEnabled() {
+  return NS_ERROR_NOT_AVAILABLE;
+}
+
+NS_IMETHODIMP
 ChildDNSService::GetMyHostName(nsACString& result) {
   // TODO: get value from parent during PNecko construction?
   return NS_ERROR_NOT_AVAILABLE;
 }
 
 void ChildDNSService::NotifyRequestDone(DNSRequestChild* aDnsRequest) {
   // We need the original flags and listener for the pending requests hash.
   uint32_t originalFlags = aDnsRequest->mFlags & ~RESOLVE_OFFLINE;
--- a/netwerk/dns/TRRService.cpp
+++ b/netwerk/dns/TRRService.cpp
@@ -1,14 +1,15 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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 "nsICaptivePortalService.h"
+#include "nsIParentalControlsService.h"
 #include "nsIObserverService.h"
 #include "nsIURIMutator.h"
 #include "nsNetUtil.h"
 #include "nsStandardURL.h"
 #include "TRR.h"
 #include "TRRService.h"
 
 #include "mozilla/Preferences.h"
@@ -45,17 +46,18 @@ TRRService::TRRService()
       mRfc1918(false),
       mCaptiveIsPassed(false),
       mUseGET(false),
       mDisableECS(true),
       mDisableAfterFails(5),
       mClearTRRBLStorage(false),
       mConfirmationState(CONFIRM_INIT),
       mRetryConfirmInterval(1000),
-      mTRRFailures(0) {
+      mTRRFailures(0),
+      mParentalControlEnabled(false) {
   MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
 }
 
 nsresult TRRService::Init() {
   MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
   if (mInitialized) {
     return NS_OK;
   }
@@ -85,24 +87,36 @@ nsresult TRRService::Init() {
     if ((captiveState == nsICaptivePortalService::UNLOCKED_PORTAL) ||
         (captiveState == nsICaptivePortalService::NOT_CAPTIVE)) {
       mCaptiveIsPassed = true;
     }
     LOG(("TRRService::Init mCaptiveState=%d mCaptiveIsPassed=%d\n",
          captiveState, (int)mCaptiveIsPassed));
   }
 
+  GetParentalControlEnabledInternal();
+
   ReadPrefs(nullptr);
 
   gTRRService = this;
 
   LOG(("Initialized TRRService\n"));
   return NS_OK;
 }
 
+void TRRService::GetParentalControlEnabledInternal() {
+  nsCOMPtr<nsIParentalControlsService> pc =
+      do_CreateInstance("@mozilla.org/parental-controls-service;1");
+  if (pc) {
+    pc->GetParentalControlsEnabled(&mParentalControlEnabled);
+    LOG(("TRRService::GetParentalControlEnabledInternal=%d\n",
+         mParentalControlEnabled));
+  }
+}
+
 bool TRRService::Enabled() {
   if (mConfirmationState == CONFIRM_INIT &&
       (!mWaitForCaptive || mCaptiveIsPassed || (mMode == MODE_TRRONLY))) {
     LOG(("TRRService::Enabled => CONFIRM_TRYING\n"));
     mConfirmationState = CONFIRM_TRYING;
   }
 
   if (mConfirmationState == CONFIRM_TRYING) {
--- a/netwerk/dns/TRRService.h
+++ b/netwerk/dns/TRRService.h
@@ -7,16 +7,17 @@
 #define TRRService_h_
 
 #include "mozilla/Atomics.h"
 #include "mozilla/DataStorage.h"
 #include "nsHostResolver.h"
 #include "nsIObserver.h"
 #include "nsWeakReference.h"
 
+class nsDNSService;
 class nsIPrefBranch;
 
 namespace mozilla {
 namespace net {
 
 class TRRService : public nsIObserver,
                    public nsITimerCallback,
                    public nsSupportsWeakReference,
@@ -54,23 +55,26 @@ class TRRService : public nsIObserver,
   bool IsTRRBlacklisted(const nsACString& aHost,
                         const nsACString& aOriginSuffix, bool aPrivateBrowsing,
                         bool aParentsToo);
   bool IsExcludedFromTRR(const nsACString& aHost);
 
   bool MaybeBootstrap(const nsACString& possible, nsACString& result);
   enum TrrOkay { OKAY_NORMAL = 0, OKAY_TIMEOUT = 1, OKAY_BAD = 2 };
   void TRRIsOkay(enum TrrOkay aReason);
+  bool ParentalControlEnabled() const { return mParentalControlEnabled; }
 
  private:
   virtual ~TRRService();
   nsresult ReadPrefs(const char* name);
   void GetPrefBranch(nsIPrefBranch** result);
   void MaybeConfirm();
   void MaybeConfirm_locked();
+  friend class ::nsDNSService;
+  void GetParentalControlEnabledInternal();
 
   bool mInitialized;
   Atomic<uint32_t, Relaxed> mMode;
   Atomic<uint32_t, Relaxed> mTRRBlacklistExpireTime;
   Atomic<uint32_t, Relaxed> mTRRTimeout;
 
   Mutex mLock;
 
@@ -110,16 +114,17 @@ class TRRService : public nsIObserver,
     CONFIRM_OK = 2,
     CONFIRM_FAILED = 3
   };
   Atomic<ConfirmationState, Relaxed> mConfirmationState;
   RefPtr<TRR> mConfirmer;
   nsCOMPtr<nsITimer> mRetryConfirmTimer;
   uint32_t mRetryConfirmInterval;  // milliseconds until retry
   Atomic<uint32_t, Relaxed> mTRRFailures;
+  bool mParentalControlEnabled;
 };
 
 extern TRRService* gTRRService;
 
 }  // namespace net
 }  // namespace mozilla
 
 #endif  // TRRService_h_
--- a/netwerk/dns/nsDNSService2.cpp
+++ b/netwerk/dns/nsDNSService2.cpp
@@ -1201,16 +1201,24 @@ nsDNSService::GetDNSCacheEntries(
 }
 
 NS_IMETHODIMP
 nsDNSService::ClearCache(bool aTrrToo) {
   mResolver->FlushCache(aTrrToo);
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsDNSService::ReloadParentalControlEnabled() {
+  if (mTrrService) {
+    mTrrService->GetParentalControlEnabledInternal();
+  }
+  return NS_OK;
+}
+
 size_t nsDNSService::SizeOfIncludingThis(
     mozilla::MallocSizeOf mallocSizeOf) const {
   // Measurement of the following members may be added later if DMD finds it
   // is worthwhile:
   // - mIDN
   // - mLock
 
   size_t n = mallocSizeOf(this);
--- a/netwerk/dns/nsHostResolver.cpp
+++ b/netwerk/dns/nsHostResolver.cpp
@@ -542,16 +542,18 @@ void TypeHostRecord::Cancel() {
 }
 
 //----------------------------------------------------------------------------
 
 static const char kPrefGetTtl[] = "network.dns.get-ttl";
 static const char kPrefNativeIsLocalhost[] = "network.dns.native-is-localhost";
 static const char kPrefThreadIdleTime[] =
     "network.dns.resolver-thread-extra-idle-time-seconds";
+static const char kPrefSkipTRRParentalControl[] =
+    "network.dns.skipTRR-when-parental-control-enabled";
 static bool sGetTtlEnabled = false;
 mozilla::Atomic<bool, mozilla::Relaxed> gNativeIsLocalhost;
 
 static void DnsPrefChanged(const char* aPref, nsHostResolver* aSelf) {
   MOZ_ASSERT(NS_IsMainThread(),
              "Should be getting pref changed notification on main thread!");
 
   MOZ_ASSERT(aSelf);
@@ -571,16 +573,17 @@ nsHostResolver::nsHostResolver(uint32_t 
                                uint32_t defaultCacheEntryLifetime,
                                uint32_t defaultGracePeriod)
     : mMaxCacheEntries(maxCacheEntries),
       mDefaultCacheLifetime(defaultCacheEntryLifetime),
       mDefaultGracePeriod(defaultGracePeriod),
       mLock("nsHostResolver.mLock"),
       mIdleTaskCV(mLock, "nsHostResolver.mIdleTaskCV"),
       mEvictionQSize(0),
+      mSkipTRRWhenParentalControlEnabled(true),
       mShutdown(true),
       mNumIdleTasks(0),
       mActiveTaskCount(0),
       mActiveAnyThreadCount(0),
       mPendingCount(0) {
   mCreationTime = PR_Now();
 
   mLongIdleTimeout = TimeDuration::FromSeconds(LongIdleTimeoutSeconds);
@@ -594,16 +597,18 @@ nsresult nsHostResolver::Init() {
   if (NS_FAILED(GetAddrInfoInit())) {
     return NS_ERROR_FAILURE;
   }
 
   LOG(("nsHostResolver::Init this=%p", this));
 
   mShutdown = false;
   mNCS = NetworkConnectivityService::GetSingleton();
+  mSkipTRRWhenParentalControlEnabled =
+      Preferences::GetBool(kPrefSkipTRRParentalControl, true);
 
   // The preferences probably haven't been loaded from the disk yet, so we
   // need to register a callback that will set up the experiment once they
   // are. We also need to explicitly set a value for the props otherwise the
   // callback won't be called.
   {
     DebugOnly<nsresult> rv = Preferences::RegisterCallbackAndCall(
         &DnsPrefChanged, kPrefGetTtl, this);
@@ -1391,23 +1396,25 @@ nsresult nsHostResolver::NameLookup(nsHo
     addrRec->mTRRUsed = false;
     addrRec->mNativeSuccess = false;
     addrRec->mTRRSuccess = 0;
     addrRec->mDidCallbacks = false;
     addrRec->mTrrAUsed = AddrHostRecord::INIT;
     addrRec->mTrrAAAAUsed = AddrHostRecord::INIT;
   }
 
-  // For domains that are excluded from TRR we fallback to NativeLookup.
-  // This happens even in MODE_TRRONLY.
-  // By default localhost and local are excluded (so we cover *.local hosts)
-  // See the network.trr.excluded-domains pref.
+  // For domains that are excluded from TRR or when parental control is enabled,
+  // we fallback to NativeLookup. This happens even in MODE_TRRONLY. By default
+  // localhost and local are excluded (so we cover *.local hosts) See the
+  // network.trr.excluded-domains pref.
   bool skipTRR = true;
   if (gTRRService) {
-    skipTRR = gTRRService->IsExcludedFromTRR(rec->host);
+    skipTRR = gTRRService->IsExcludedFromTRR(rec->host) ||
+              (mSkipTRRWhenParentalControlEnabled &&
+               gTRRService->ParentalControlEnabled());
   }
 
   if (rec->flags & RES_DISABLE_TRR) {
     if (mode == MODE_TRRONLY && !skipTRR) {
       return rv;
     }
     mode = MODE_NATIVEONLY;
   }
--- a/netwerk/dns/nsHostResolver.h
+++ b/netwerk/dns/nsHostResolver.h
@@ -546,16 +546,17 @@ class nsHostResolver : public nsISupport
   mozilla::LinkedList<RefPtr<nsHostRecord>> mHighQ;
   mozilla::LinkedList<RefPtr<nsHostRecord>> mMediumQ;
   mozilla::LinkedList<RefPtr<nsHostRecord>> mLowQ;
   mozilla::LinkedList<RefPtr<nsHostRecord>> mEvictionQ;
   uint32_t mEvictionQSize;
   PRTime mCreationTime;
   mozilla::TimeDuration mLongIdleTimeout;
   mozilla::TimeDuration mShortIdleTimeout;
+  bool mSkipTRRWhenParentalControlEnabled;
 
   RefPtr<nsIThreadPool> mResolverThreads;
   RefPtr<mozilla::net::NetworkConnectivityService> mNCS;
 
   mozilla::Atomic<bool> mShutdown;
   mozilla::Atomic<uint32_t> mNumIdleTasks;
   mozilla::Atomic<uint32_t> mActiveTaskCount;
   mozilla::Atomic<uint32_t> mActiveAnyThreadCount;
--- a/netwerk/dns/nsIDNSService.idl
+++ b/netwerk/dns/nsIDNSService.idl
@@ -219,16 +219,22 @@ interface nsIDNSService : nsISupports
      *        If true we will clear TRR cached entries too. Since these
      *        are resolved remotely it's not necessary to clear them when
      *        the network status changes, but it's sometimes useful to do so
      *        for tests or other situations.
      */
     void clearCache(in boolean aTrrToo);
 
     /**
+     * The method is used only for test purpose. We use this to recheck if
+     * parental control is enabled or not.
+     */
+    void reloadParentalControlEnabled();
+
+    /**
      * @return the hostname of the operating system.
      */
     readonly attribute AUTF8String myHostName;
 
     /*************************************************************************
      * Listed below are the various flags that may be OR'd together to form
      * the aFlags parameter passed to asyncResolve() and resolve().
      */
--- a/netwerk/test/unit/test_trr.js
+++ b/netwerk/test/unit/test_trr.js
@@ -1,18 +1,34 @@
 "use strict";
 
 const dns = Cc["@mozilla.org/network/dns-service;1"].getService(
   Ci.nsIDNSService
 );
+const { MockRegistrar } = ChromeUtils.import(
+  "resource://testing-common/MockRegistrar.jsm"
+);
 const mainThread = Services.tm.currentThread;
 
 const defaultOriginAttributes = {};
 let h2Port = null;
 
+async function SetParentalControlEnabled(aEnabled) {
+  let parentalControlsService = {
+    parentalControlsEnabled: aEnabled,
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIParentalControlsService]),
+  };
+  let cid = MockRegistrar.register(
+    "@mozilla.org/parental-controls-service;1",
+    parentalControlsService
+  );
+  dns.reloadParentalControlEnabled();
+  MockRegistrar.unregister(cid);
+}
+
 add_task(function setup() {
   dump("start!\n");
 
   let env = Cc["@mozilla.org/process/environment;1"].getService(
     Ci.nsIEnvironment
   );
   h2Port = env.get("MOZHTTP2_PORT");
   Assert.notEqual(h2Port, null);
@@ -43,16 +59,18 @@ add_task(function setup() {
   Services.prefs.setCharPref("network.trr.confirmationNS", "skip");
 
   // The moz-http2 cert is for foo.example.com and is signed by http2-ca.pem
   // so add that cert to the trust list as a signing cert.  // the foo.example.com domain name.
   let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
     Ci.nsIX509CertDB
   );
   addCertFromFile(certdb, "http2-ca.pem", "CTu,u,u");
+
+  SetParentalControlEnabled(false);
 });
 
 registerCleanupFunction(() => {
   Services.prefs.clearUserPref("network.trr.mode");
   Services.prefs.clearUserPref("network.trr.uri");
   Services.prefs.clearUserPref("network.trr.credentials");
   Services.prefs.clearUserPref("network.trr.wait-for-portal");
   Services.prefs.clearUserPref("network.trr.allow-rfc1918");
@@ -705,16 +723,24 @@ add_task(async function test24f() {
   Services.prefs.setCharPref(
     "captivedetect.canonicalURL",
     "http://test.detectportal.com/success.txt"
   );
 
   await new DNSListener("test.detectportal.com", "127.0.0.1");
 });
 
+// TRR-first check that a domain is resolved via native DNS when parental control is enabled.
+add_task(async function test24g() {
+  dns.clearCache(true);
+  await SetParentalControlEnabled(true);
+  await new DNSListener("www.example.com", "127.0.0.1");
+  await SetParentalControlEnabled(false);
+});
+
 // TRR-only that resolving localhost with TRR-only mode will use the remote
 // resolver if it's not in the excluded domains
 add_task(async function test25() {
   dns.clearCache(true);
   Services.prefs.setIntPref("network.trr.mode", 3); // TRR-only
   Services.prefs.setCharPref("network.trr.excluded-domains", "");
   Services.prefs.setCharPref(
     "network.trr.uri",
@@ -777,16 +803,25 @@ add_task(async function test25e() {
   Services.prefs.setCharPref(
     "network.trr.uri",
     `https://foo.example.com:${h2Port}/doh?responseIP=192.192.192.192`
   );
 
   await new DNSListener("test.detectportal.com", "127.0.0.1");
 });
 
+// TRR-only check that a domain is resolved via native DNS when parental control is enabled.
+add_task(async function test25f() {
+  dns.clearCache(true);
+  Services.prefs.setIntPref("network.trr.mode", 3); // TRR-only
+  await SetParentalControlEnabled(true);
+  await new DNSListener("www.example.com", "127.0.0.1");
+  await SetParentalControlEnabled(false);
+});
+
 // Check that none of the requests have set any cookies.
 add_task(async function count_cookies() {
   let cm = Cc["@mozilla.org/cookiemanager;1"].getService(Ci.nsICookieManager);
   Assert.equal(cm.countCookiesFromHost("example.com"), 0);
   Assert.equal(cm.countCookiesFromHost("foo.example.com."), 0);
 });
 
 add_task(async function test_connection_closed() {
--- a/old-configure.in
+++ b/old-configure.in
@@ -841,19 +841,16 @@ case "$target" in
     fi
 
     case "$target" in
     i*86-*)
         if test -n "$GNU_CC"; then
             CFLAGS="$CFLAGS -mstackrealign"
             CXXFLAGS="$CXXFLAGS -mstackrealign"
             LDFLAGS="$LDFLAGS -Wl,--large-address-aware"
-            if test -z "$CLANG_CC"; then
-                LDFLAGS="$LDFLAGS -Wl,--enable-stdcall-fixup"
-            fi
         else
             DSO_LDOPTS="$DSO_LDOPTS -MACHINE:X86"
             LDFLAGS="$LDFLAGS -SAFESEH"
         fi
 
         AC_DEFINE(_X86_)
         ;;
     x86_64-*)
--- a/testing/webdriver/Cargo.toml
+++ b/testing/webdriver/Cargo.toml
@@ -6,17 +6,17 @@ description = "Library implementing the 
 keywords = ["webdriver", "browser", "automation", "protocol", "w3c"]
 documentation = "https://docs.rs/webdriver"
 repository = "https://hg.mozilla.org/mozilla-central/file/tip/testing/webdriver"
 readme = "README.md"
 license = "MPL-2.0"
 
 [dependencies]
 base64 = "0.10"
-cookie = { version = "0.11", default-features = false }
+cookie = { version = "0.12", default-features = false }
 http = "0.1"
 log = "0.4"
 regex = "1.0"
 serde = "1.0"
 serde_json = "1.0"
 serde_derive = "1.0"
 time = "0.1"
 tokio = "0.1"
--- a/third_party/rust/cookie/.cargo-checksum.json
+++ b/third_party/rust/cookie/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{"Cargo.toml":"6a8f9c03d5260359e497a70910ab444f32b51551e9c0aaffabcfbbb2dd7c906d","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"9205f5b7d179b5ca140ec7322c5894540aef149a38bd55874bef9de5a48e0938","src/builder.rs":"4200963d44d1a59f1268965b77407ba977eb5a777875cb76ea927ddc829be3d8","src/delta.rs":"510fc3dbf0a70d635d0488c5a5a32a2ba8e1490ce05bee39d944ea8c02189bbc","src/draft.rs":"950b43b3f6e1c4c13b1e90220c71defe02713170807b41e5ffde9a1327688f48","src/jar.rs":"0e8a6e2f0426834101bd9608baf9f695839053523e9e9ac58aea03a73506b8fb","src/lib.rs":"963ff56045a4ee22e280ee24a42efc9b1d6a96de30d3856b39287ec2b51b00db","src/parse.rs":"549844993601f20f5de3f5d5f8bea0fce3fe4f09d72e343aff9e433948a4ec5c","src/secure/key.rs":"734f35ef4b0d6b63174befdcb970f0304ac63f0895871b7c2f267fefdd43b648","src/secure/macros.rs":"83d770e5c4eb7fbd3c3d86973b69042e9e2bb9fafb72a4456598e2ae78638d5f","src/secure/mod.rs":"5d7fecb62295827d474ed1ce6b7628fe93d4a09eb14babfde036d64e8e4a04f8","src/secure/private.rs":"bea61d91772285e0db7c234bda32d9e95ce386dba5cab640859531d72f13628c","src/secure/signed.rs":"26c46c2d561ea14d1d8d79f85342a98b4bd749df776677dde91dd9b928e91fbe"},"package":"1465f8134efa296b4c19db34d909637cb2bf0f7aaf21299e23e18fa29ac557cf"}
\ No newline at end of file
+{"files":{"Cargo.toml":"2c65ccbf56c2640abee1927d35423ade48e20588630ac31e094d434595ee80d8","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"3fcac69759e004d729a868ed5ef248c84d86fb0f3ab5c7a93abb547b91a0eb4e","src/builder.rs":"4200963d44d1a59f1268965b77407ba977eb5a777875cb76ea927ddc829be3d8","src/delta.rs":"510fc3dbf0a70d635d0488c5a5a32a2ba8e1490ce05bee39d944ea8c02189bbc","src/draft.rs":"950b43b3f6e1c4c13b1e90220c71defe02713170807b41e5ffde9a1327688f48","src/jar.rs":"8cc6531203e2a9422bfe1b2a00aeb96beb57d4676fa147a66f28f2d7c3129b57","src/lib.rs":"6a267d63ad90998f4a463c726be6a93fc33979eb8a72bfb53cae9f5b7a13fae0","src/parse.rs":"549844993601f20f5de3f5d5f8bea0fce3fe4f09d72e343aff9e433948a4ec5c","src/secure/key.rs":"734f35ef4b0d6b63174befdcb970f0304ac63f0895871b7c2f267fefdd43b648","src/secure/macros.rs":"83d770e5c4eb7fbd3c3d86973b69042e9e2bb9fafb72a4456598e2ae78638d5f","src/secure/mod.rs":"5d7fecb62295827d474ed1ce6b7628fe93d4a09eb14babfde036d64e8e4a04f8","src/secure/private.rs":"81d782cd4fa4b1415795710ad9e2e77eca3f4326e20ef96675093db9a378da32","src/secure/signed.rs":"26c46c2d561ea14d1d8d79f85342a98b4bd749df776677dde91dd9b928e91fbe"},"package":"888604f00b3db336d2af898ec3c1d5d0ddf5e6d462220f2ededc33a87ac4bbd5"}
\ No newline at end of file
--- a/third_party/rust/cookie/Cargo.toml
+++ b/third_party/rust/cookie/Cargo.toml
@@ -1,36 +1,36 @@
 # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
 #
 # When uploading crates to the registry Cargo will automatically
 # "normalize" Cargo.toml files for maximal compatibility
 # with all versions of Cargo and also rewrite `path` dependencies
-# to registry (e.g. crates.io) dependencies
+# to registry (e.g., crates.io) dependencies
 #
 # If you believe there's an error in this file please file an
 # issue against the rust-lang/cargo repository. If you're
 # editing this file be aware that the upstream Cargo.toml
 # will likely look very different (and much more reasonable)
 
 [package]
 name = "cookie"
-version = "0.11.0"
+version = "0.12.0"
 authors = ["Alex Crichton <alex@alexcrichton.com>", "Sergio Benitez <sb@sergio.bz>"]
 description = "Crate for parsing HTTP cookie headers and managing a cookie jar. Supports signed\nand private (encrypted + signed) jars.\n"
 documentation = "https://docs.rs/cookie"
 license = "MIT/Apache-2.0"
 repository = "https://github.com/alexcrichton/cookie-rs"
 [package.metadata.docs.rs]
 all-features = true
 [dependencies.base64]
-version = "0.9.0"
+version = "0.10.0"
 optional = true
 
 [dependencies.ring]
-version = "0.13.0"
+version = "0.14.0"
 optional = true
 
 [dependencies.time]
 version = "0.1"
 
 [dependencies.url]
 version = "1.0"
 optional = true
--- a/third_party/rust/cookie/README.md
+++ b/third_party/rust/cookie/README.md
@@ -1,22 +1,22 @@
 # cookie-rs
 
-[![Build Status](https://travis-ci.org/alexcrichton/cookie-rs.svg?branch=master)](https://travis-ci.org/alexcrichton/cookie-rs)
+[![Build Status](https://travis-ci.com/SergioBenitez/cookie-rs.svg?branch=master)](https://travis-ci.com/SergioBenitez/cookie-rs)
 [![Current Crates.io Version](https://img.shields.io/crates/v/cookie.svg)](https://crates.io/crates/cookie)
 
 A library for parsing HTTP cookies and managing cookie jars.
 
 # Usage
 
 Add the following to your `Cargo.toml`:
 
 ```toml
 [dependencies]
-cookie = "0.10"
+cookie = "0.12"
 ```
 
 See the [documentation](http://docs.rs/cookie) for detailed usage information.
 
 # License
 
 This project is licensed under either of
 
--- a/third_party/rust/cookie/src/jar.rs
+++ b/third_party/rust/cookie/src/jar.rs
@@ -339,17 +339,20 @@ impl CookieJar {
     ///         "second" => assert_eq!(cookie.value(), "two"),
     ///         "new" => assert_eq!(cookie.value(), "third"),
     ///         "yac" => assert_eq!(cookie.value(), "fifth"),
     ///         _ => unreachable!("there are only three cookies in the jar")
     ///     }
     /// }
     /// ```
     pub fn iter(&self) -> Iter {
-        Iter { delta_cookies: self.delta_cookies.union(&self.original_cookies) }
+        Iter {
+            delta_cookies: self.delta_cookies.iter()
+                .chain(self.original_cookies.difference(&self.delta_cookies)),
+        }
     }
 
     /// Returns a `PrivateJar` with `self` as its parent jar using the key `key`
     /// to sign/encrypt and verify/decrypt cookies added/retrieved from the
     /// child jar.
     ///
     /// Any modifications to the child jar will be reflected on the parent jar,
     /// and any retrievals from the child jar will be made from the parent jar.
@@ -434,22 +437,23 @@ pub struct Delta<'a> {
 impl<'a> Iterator for Delta<'a> {
     type Item = &'a Cookie<'static>;
 
     fn next(&mut self) -> Option<&'a Cookie<'static>> {
         self.iter.next().map(|c| &c.cookie)
     }
 }
 
-use std::collections::hash_set::Union;
+use std::collections::hash_set::Difference;
 use std::collections::hash_map::RandomState;
+use std::iter::Chain;
 
 /// Iterator over all of the cookies in a jar.
 pub struct Iter<'a> {
-    delta_cookies: Union<'a, DeltaCookie, RandomState>,
+    delta_cookies: Chain<HashSetIter<'a, DeltaCookie>, Difference<'a, DeltaCookie, RandomState>>,
 }
 
 impl<'a> Iterator for Iter<'a> {
     type Item = &'a Cookie<'static>;
 
     fn next(&mut self) -> Option<&'a Cookie<'static>> {
         for cookie in self.delta_cookies.by_ref() {
             if !cookie.removed {
--- a/third_party/rust/cookie/src/lib.rs
+++ b/third_party/rust/cookie/src/lib.rs
@@ -5,17 +5,17 @@
 //! which allows for simple management of many cookies as well as encryption and
 //! signing of cookies for session management.
 //!
 //! # Usage
 //!
 //! Add the following to the `[dependencies]` section of your `Cargo.toml`:
 //!
 //! ```ignore
-//! cookie = "0.11"
+//! cookie = "0.12"
 //! ```
 //!
 //! Then add the following line to your crate root:
 //!
 //! ```ignore
 //! extern crate cookie;
 //! ```
 //!
@@ -53,17 +53,17 @@
 //!
 //! You can enable features via the `Cargo.toml` file:
 //!
 //! ```ignore
 //! [dependencies.cookie]
 //! features = ["secure", "percent-encode"]
 //! ```
 
-#![doc(html_root_url = "https://docs.rs/cookie/0.11")]
+#![doc(html_root_url = "https://docs.rs/cookie/0.12")]
 #![deny(missing_docs)]
 
 #[cfg(feature = "percent-encode")] extern crate url;
 extern crate time;
 
 mod builder;
 mod parse;
 mod jar;
--- a/third_party/rust/cookie/src/secure/private.rs
+++ b/third_party/rust/cookie/src/secure/private.rs
@@ -1,9 +1,9 @@
-use secure::ring::aead::{seal_in_place, open_in_place, Algorithm, AES_256_GCM};
+use secure::ring::aead::{seal_in_place, open_in_place, Aad, Algorithm, Nonce, AES_256_GCM};
 use secure::ring::aead::{OpeningKey, SealingKey};
 use secure::ring::rand::{SecureRandom, SystemRandom};
 use secure::{base64, Key};
 
 use {Cookie, CookieJar};
 
 // Keep these in sync, and keep the key len synced with the `private` docs as
 // well as the `KEYS_INFO` const in secure::Key.
@@ -41,19 +41,21 @@ impl<'a> PrivateJar<'a> {
     /// verifies and decrypts the sealed value and returns it. If there's a
     /// problem, returns an `Err` with a string describing the issue.
     fn unseal(&self, name: &str, value: &str) -> Result<String, &'static str> {
         let mut data = base64::decode(value).map_err(|_| "bad base64 value")?;
         if data.len() <= NONCE_LEN {
             return Err("length of decoded data is <= NONCE_LEN");
         }
 
-        let ad = name.as_bytes();
+        let ad = Aad::from(name.as_bytes());
         let key = OpeningKey::new(ALGO, &self.key).expect("opening key");
         let (nonce, sealed) = data.split_at_mut(NONCE_LEN);
+        let nonce = Nonce::try_assume_unique_for_key(nonce)
+            .expect("invalid length of `nonce`");
         let unsealed = open_in_place(&key, nonce, ad, 0, sealed)
             .map_err(|_| "invalid key/nonce/value: bad seal")?;
 
         ::std::str::from_utf8(unsealed)
             .map(|s| s.to_string())
             .map_err(|_| "bad unsealed utf8")
     }
 
@@ -151,19 +153,21 @@ impl<'a> PrivateJar<'a> {
             let overhead = ALGO.tag_len();
             let cookie_val = cookie.value().as_bytes();
             data = vec![0; NONCE_LEN + cookie_val.len() + overhead];
 
             // Randomly generate the nonce, then copy the cookie value as input.
             let (nonce, in_out) = data.split_at_mut(NONCE_LEN);
             SystemRandom::new().fill(nonce).expect("couldn't random fill nonce");
             in_out[..cookie_val.len()].copy_from_slice(cookie_val);
+            let nonce = Nonce::try_assume_unique_for_key(nonce)
+                .expect("invalid length of `nonce`");
 
             // Use cookie's name as associated data to prevent value swapping.
-            let ad = cookie.name().as_bytes();
+            let ad = Aad::from(cookie.name().as_bytes());
 
             // Perform the actual sealing operation and get the output length.
             seal_in_place(&key, nonce, ad, in_out, overhead).expect("in-place seal")
         };
 
         // Base64 encode the nonce and encrypted value.
         let sealed_value = base64::encode(&data[..(NONCE_LEN + output_len)]);
         cookie.set_value(sealed_value);
--- a/toolkit/crashreporter/breakpad-client/mac/handler/exception_handler.cc
+++ b/toolkit/crashreporter/breakpad-client/mac/handler/exception_handler.cc
@@ -36,16 +36,20 @@
 #include <map>
 
 #include "mac/handler/exception_handler.h"
 #include "mac/handler/minidump_generator.h"
 #include "common/mac/macho_utilities.h"
 #include "common/mac/scoped_task_suspend-inl.h"
 #include "google_breakpad/common/minidump_exception_mac.h"
 
+#ifdef MOZ_PHC
+#include "replace_malloc_bridge.h"
+#endif
+
 #include "mozilla/RecordReplay.h"
 
 #ifndef __EXCEPTIONS
 // This file uses C++ try/catch (but shouldn't). Duplicate the macros from
 // <c++/4.2.1/exception_defines.h> allowing this file to work properly with
 // exceptions disabled even when other C++ libraries are used. #undef the try
 // and catch macros first in case libstdc++ is in use and has already provided
 // its own definitions.
@@ -343,46 +347,64 @@ bool ExceptionHandler::WriteMinidumpForC
 
   if (callback) {
     return callback(dump_path.c_str(), dump_id.c_str(),
                     callback_context, nullptr, result);
   }
   return result;
 }
 
+#ifdef MOZ_PHC
+static void GetPHCAddrInfo(int64_t exception_subcode,
+                           mozilla::phc::AddrInfo* addr_info) {
+  // Is this a crash involving a PHC allocation?
+  if (exception_subcode) {
+    // `exception_subcode` is only non-zero when it's a bad access, in which
+    // case it holds the address of the bad access.
+    char* addr = reinterpret_cast<char*>(exception_subcode);
+    ReplaceMalloc::IsPHCAllocation(addr, addr_info);
+  }
+}
+#endif
+
 bool ExceptionHandler::WriteMinidumpWithException(
     int exception_type,
     int exception_code,
     int exception_subcode,
     breakpad_ucontext_t* task_context,
     mach_port_t thread_name,
     bool exit_after_write,
     bool report_current_thread) {
   bool result = false;
 
 #if TARGET_OS_IPHONE
   // _exit() should never be called on iOS.
   exit_after_write = false;
 #endif
 
+    mozilla::phc::AddrInfo addr_info;
+#ifdef MOZ_PHC
+    GetPHCAddrInfo(exception_subcode, &addr_info);
+#endif
+
   if (directCallback_) {
     if (directCallback_(callback_context_,
                         exception_type,
                         exception_code,
                         exception_subcode,
                         thread_name) ) {
       if (exit_after_write)
         _exit(exception_type);
     }
 #if !TARGET_OS_IPHONE
   } else if (IsOutOfProcess()) {
     if (exception_type && exception_code) {
       // If this is a real exception, give the filter (if any) a chance to
       // decide if this should be sent.
-      if (filter_ && !filter_(callback_context_, nullptr))
+      if (filter_ && !filter_(callback_context_, &addr_info))
         return false;
       result = crash_generation_client_->RequestDumpForException(
           exception_type,
           exception_code,
           exception_subcode,
           thread_name);
       if (result && exit_after_write) {
         _exit(exception_type);
@@ -413,17 +435,17 @@ bool ExceptionHandler::WriteMinidumpWith
     }
 
     // Call user specified callback (if any)
     if (callback_) {
       // If the user callback returned true and we're handling an exception
       // (rather than just writing out the file), then we should exit without
       // forwarding the exception to the next handler.
       if (callback_(dump_path_c_, next_minidump_id_c_, callback_context_,
-                    nullptr, result)) {
+                    &addr_info, result)) {
         if (exit_after_write)
           _exit(exception_type);
       }
     }
   }
 
   return result;
 }
--- a/toolkit/crashreporter/breakpad-client/mac/handler/moz.build
+++ b/toolkit/crashreporter/breakpad-client/mac/handler/moz.build
@@ -13,8 +13,10 @@ UNIFIED_SOURCES += [
 
 FINAL_LIBRARY = 'breakpad_client'
 
 LOCAL_INCLUDES += [
     '/toolkit/crashreporter/breakpad-client',
     '/toolkit/crashreporter/google-breakpad/src',
 ]
 
+if CONFIG['MOZ_PHC']:
+    DEFINES['MOZ_PHC'] = True
--- a/toolkit/crashreporter/test/unit/test_crash_phc.js
+++ b/toolkit/crashreporter/test/unit/test_crash_phc.js
@@ -2,18 +2,19 @@ function check(extra, size) {
   Assert.equal(extra.PHCKind, "FreedPage");
 
   // This is a string holding a decimal address.
   Assert.ok(/^\d+$/.test(extra.PHCBaseAddress));
 
   Assert.equal(extra.PHCUsableSize, size);
 
   // These are strings holding comma-separated lists of decimal addresses.
-  Assert.ok(/^(\d+,)+\d+$/.test(extra.PHCAllocStack));
-  Assert.ok(/^(\d+,)+\d+$/.test(extra.PHCFreeStack));
+  // Sometimes on Mac they have a single entry.
+  Assert.ok(/^(\d+,)*\d+$/.test(extra.PHCAllocStack));
+  Assert.ok(/^(\d+,)*\d+$/.test(extra.PHCFreeStack));
 }
 
 function run_test() {
   if (!("@mozilla.org/toolkit/crash-reporter;1" in Cc)) {
     dump(
       "INFO | test_crash_phc.js | Can't test crashreporter in a non-libxul build.\n"
     );
     return;
--- a/toolkit/crashreporter/test/unit_ipc/test_content_phc.js
+++ b/toolkit/crashreporter/test/unit_ipc/test_content_phc.js
@@ -18,13 +18,14 @@ function run_test() {
 
       // This is a string holding a decimal address.
       Assert.ok(/^\d+$/.test(extra.PHCBaseAddress));
 
       // CRASH_PHC_USE_AFTER_FREE uses 32 for the size.
       Assert.equal(extra.PHCUsableSize, 32);
 
       // These are strings holding comma-separated lists of decimal addresses.
-      Assert.ok(/^(\d+,)+\d+$/.test(extra.PHCAllocStack));
-      Assert.ok(/^(\d+,)+\d+$/.test(extra.PHCFreeStack));
+      // Sometimes on Mac they have a single entry.
+      Assert.ok(/^(\d+,)*\d+$/.test(extra.PHCAllocStack));
+      Assert.ok(/^(\d+,)*\d+$/.test(extra.PHCFreeStack));
     }
   );
 }
--- a/toolkit/crashreporter/test/unit_ipc/test_content_phc2.js
+++ b/toolkit/crashreporter/test/unit_ipc/test_content_phc2.js
@@ -21,13 +21,14 @@ function run_test() {
 
       // This is a string holding a decimal address.
       Assert.ok(/^\d+$/.test(extra.PHCBaseAddress));
 
       // CRASH_PHC_DOUBLE_FREE uses 64 for the size.
       Assert.equal(extra.PHCUsableSize, 64);
 
       // These are strings holding comma-separated lists of decimal addresses.
-      Assert.ok(/^(\d+,)+\d+$/.test(extra.PHCAllocStack));
-      Assert.ok(/^(\d+,)+\d+$/.test(extra.PHCFreeStack));
+      // Sometimes on Mac they have a single entry.
+      Assert.ok(/^(\d+,)*\d+$/.test(extra.PHCAllocStack));
+      Assert.ok(/^(\d+,)*\d+$/.test(extra.PHCFreeStack));
     }
   );
 }
--- a/widget/CompositorWidget.h
+++ b/widget/CompositorWidget.h
@@ -6,16 +6,17 @@
 #define mozilla_widget_CompositorWidget_h__
 
 #include "nsISupports.h"
 #include "mozilla/RefPtr.h"
 #include "Units.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/layers/CompositorOptions.h"
 #include "mozilla/layers/LayersTypes.h"
+#include "mozilla/layers/NativeLayer.h"
 
 class nsIWidget;
 class nsBaseWidget;
 
 namespace mozilla {
 class VsyncObserver;
 namespace gl {
 class GLContext;
@@ -112,59 +113,55 @@ class CompositorWidget {
    * cancelled by a negative return value from PreRender.
    *
    * Always called from the compositing thread, which may be the main-thread if
    * OMTC is not enabled.
    */
   virtual void PostRender(WidgetRenderingContext* aContext) {}
 
   /**
-   * Called on the same thread as PreRender/PostRender during destruction.
-   * This method gives the widget a chance to do any cleanup for state that it
-   * created during PreRender / PostRender.
+   * Called before the first composite. If the result is non-null, one or more
+   * native layers will be placed on the window and used for compositing.
+   * When native layers are used, StartRemoteDrawing(InRegion) and
+   * EndRemoteDrawing(InRegion) will not be called.
    */
-  virtual void DoCompositorCleanup() {}
-
-  /**
-   * Called before the LayerManager draws the layer tree.
-   *
-   * Always called from the compositing thread.
-   */
-  virtual void DrawWindowUnderlay(WidgetRenderingContext* aContext,
-                                  LayoutDeviceIntRect aRect) {}
+  virtual RefPtr<layers::NativeLayerRoot> GetNativeLayerRoot() {
+    return nullptr;
+  }
 
   /**
    * Called after the LayerManager draws the layer tree
    *
    * Always called from the compositing thread.
    */
   virtual void DrawWindowOverlay(WidgetRenderingContext* aContext,
                                  LayoutDeviceIntRect aRect) {}
 
   /**
    * Return a DrawTarget for the window which can be composited into.
    *
+   * Only called if GetNativeLayerRoot() returns nullptr.
    * Called by BasicCompositor on the compositor thread for OMTC drawing
-   * before each composition.
+   * before each composition (unless there's a native layer root).
    *
    * The window may specify its buffer mode. If unspecified, it is assumed
    * to require double-buffering.
    */
   virtual already_AddRefed<gfx::DrawTarget> StartRemoteDrawing();
   virtual already_AddRefed<gfx::DrawTarget> StartRemoteDrawingInRegion(
       LayoutDeviceIntRegion& aInvalidRegion, layers::BufferMode* aBufferMode) {
     return StartRemoteDrawing();
   }
 
   /**
    * Ensure that what was painted into the DrawTarget returned from
    * StartRemoteDrawing reaches the screen.
    *
    * Called by BasicCompositor on the compositor thread for OMTC drawing
-   * after each composition.
+   * after each composition for which StartRemoteDrawing(InRegion) was called.
    */
   virtual void EndRemoteDrawing() {}
   virtual void EndRemoteDrawingInRegion(
       gfx::DrawTarget* aDrawTarget,
       const LayoutDeviceIntRegion& aInvalidRegion) {
     EndRemoteDrawing();
   }
 
@@ -242,16 +239,34 @@ class CompositorWidget {
   /**
    * Ensure end of composition to back buffer.
    *
    * Called by BasicCompositor on the compositor thread for OMTC drawing
    * after each composition to back buffer.
    */
   virtual already_AddRefed<gfx::SourceSurface> EndBackBufferDrawing();
 
+#ifdef XP_MACOSX
+  /**
+   * Return the opaque region of the widget. This is racy and can only be used
+   * on macOS, where the widget works around the raciness.
+   * Bug 1576491 tracks fixing this properly.
+   * The problem with this method is that it can return values "from the future"
+   * - the compositor might be working on frame N but the widget will return its
+   * opaque region from frame N + 1.
+   * It is believed that this won't lead to visible glitches on macOS due to the
+   * SuspendAsyncCATransactions call when the vibrant region changes or when the
+   * window resizes. Whenever the compositor uses an opaque region that's a
+   * frame ahead, the result it renders won't be shown on the screen; instead,
+   * the next composite will happen with the correct display list, and that's
+   * what's shown on the screen once the FlushRendering call completes.
+   */
+  virtual LayoutDeviceIntRegion GetOpaqueWidgetRegion() { return {}; }
+#endif
+
   /**
    * Observe or unobserve vsync.
    */
   virtual void ObserveVsync(VsyncObserver* aObserver) = 0;
 
   /**
    * Get the compositor options for the compositor associated with this
    * CompositorWidget.
--- a/widget/InProcessCompositorWidget.cpp
+++ b/widget/InProcessCompositorWidget.cpp
@@ -39,23 +39,19 @@ InProcessCompositorWidget::InProcessComp
 bool InProcessCompositorWidget::PreRender(WidgetRenderingContext* aContext) {
   return mWidget->PreRender(aContext);
 }
 
 void InProcessCompositorWidget::PostRender(WidgetRenderingContext* aContext) {
   mWidget->PostRender(aContext);
 }
 
-void InProcessCompositorWidget::DoCompositorCleanup() {
-  mWidget->DoCompositorCleanup();
-}
-
-void InProcessCompositorWidget::DrawWindowUnderlay(
-    WidgetRenderingContext* aContext, LayoutDeviceIntRect aRect) {
-  mWidget->DrawWindowUnderlay(aContext, aRect);
+RefPtr<layers::NativeLayerRoot>
+InProcessCompositorWidget::GetNativeLayerRoot() {
+  return mWidget->GetNativeLayerRoot();
 }
 
 void InProcessCompositorWidget::DrawWindowOverlay(
     WidgetRenderingContext* aContext, LayoutDeviceIntRect aRect) {
   mWidget->DrawWindowOverlay(aContext, aRect);
 }
 
 already_AddRefed<gfx::DrawTarget>
@@ -100,16 +96,22 @@ uint32_t InProcessCompositorWidget::GetG
 }
 
 uintptr_t InProcessCompositorWidget::GetWidgetKey() {
   return reinterpret_cast<uintptr_t>(mWidget);
 }
 
 nsIWidget* InProcessCompositorWidget::RealWidget() { return mWidget; }
 
+#ifdef XP_MACOSX
+LayoutDeviceIntRegion InProcessCompositorWidget::GetOpaqueWidgetRegion() {
+  return mWidget->GetOpaqueWidgetRegion();
+}
+#endif
+
 void InProcessCompositorWidget::ObserveVsync(VsyncObserver* aObserver) {
   if (RefPtr<CompositorVsyncDispatcher> cvd =
           mWidget->GetCompositorVsyncDispatcher()) {
     cvd->SetCompositorVsyncObserver(aObserver);
   }
 }
 
 }  // namespace widget
--- a/widget/InProcessCompositorWidget.h
+++ b/widget/InProcessCompositorWidget.h
@@ -14,34 +14,35 @@ namespace widget {
 // nsBaseWidget.
 class InProcessCompositorWidget : public CompositorWidget {
  public:
   explicit InProcessCompositorWidget(const layers::CompositorOptions& aOptions,
                                      nsBaseWidget* aWidget);
 
   virtual bool PreRender(WidgetRenderingContext* aManager) override;
   virtual void PostRender(WidgetRenderingContext* aManager) override;
-  virtual void DoCompositorCleanup() override;
-  virtual void DrawWindowUnderlay(WidgetRenderingContext* aContext,
-                                  LayoutDeviceIntRect aRect) override;
+  virtual RefPtr<layers::NativeLayerRoot> GetNativeLayerRoot() override;
   virtual void DrawWindowOverlay(WidgetRenderingContext* aContext,
                                  LayoutDeviceIntRect aRect) override;
   virtual already_AddRefed<gfx::DrawTarget> StartRemoteDrawing() override;
   virtual already_AddRefed<gfx::DrawTarget> StartRemoteDrawingInRegion(
       LayoutDeviceIntRegion& aInvalidRegion,
       layers::BufferMode* aBufferMode) override;
   virtual void EndRemoteDrawing() override;
   virtual void EndRemoteDrawingInRegion(
       gfx::DrawTarget* aDrawTarget,
       const LayoutDeviceIntRegion& aInvalidRegion) override;
   virtual void CleanupRemoteDrawing() override;
   virtual void CleanupWindowEffects() override;
   virtual bool InitCompositor(layers::Compositor* aCompositor) override;
   virtual LayoutDeviceIntSize GetClientSize() override;
   virtual uint32_t GetGLFrameBufferFormat() override;
+#ifdef XP_MACOSX
+  virtual LayoutDeviceIntRegion GetOpaqueWidgetRegion() override;
+#endif
   virtual void ObserveVsync(VsyncObserver* aObserver) override;
   virtual uintptr_t GetWidgetKey() override;
 
   // If you can override this method, inherit from CompositorWidget instead.
   nsIWidget* RealWidget() override;
 
  protected:
   nsBaseWidget* mWidget;
--- a/widget/cocoa/nsChildView.h
+++ b/widget/cocoa/nsChildView.h
@@ -392,16 +392,17 @@ class nsChildView final : public nsBaseW
   // between HiDPI and non-HiDPI screens
   void BackingScaleFactorChanged();
 
   virtual double GetDefaultScaleInternal() override;
 
   virtual int32_t RoundsWidgetCoordinatesTo() override;
 
   virtual void Invalidate(const LayoutDeviceIntRect& aRect) override;
+  void EnsureContentLayerForMainThreadPainting();
 
   virtual void* GetNativeData(uint32_t aDataType) override;
   virtual nsresult ConfigureChildren(const nsTArray<Configuration>& aConfigurations) override;
   virtual LayoutDeviceIntPoint WidgetToScreenOffset() override;
   virtual bool ShowsResizeIndicator(LayoutDeviceIntRect* aResizerRect) override { return false; }
 
   static bool ConvertStatus(nsEventStatus aStatus) {
     return aStatus == nsEventStatus_eConsumeNoDefault;
@@ -492,17 +493,17 @@ class nsChildView final : public nsBaseW
 
   virtual void AddWindowOverlayWebRenderCommands(
       mozilla::layers::WebRenderBridgeChild* aWrBridge, mozilla::wr::DisplayListBuilder& aBuilder,
       mozilla::wr::IpcResourceUpdateQueue& aResourceUpdates) override;
 
   virtual bool PreRender(mozilla::widget::WidgetRenderingContext* aContext) override;
   bool PreRenderImpl(mozilla::widget::WidgetRenderingContext* aContext);
   virtual void PostRender(mozilla::widget::WidgetRenderingContext* aContext) override;
-  virtual void DoCompositorCleanup() override;
+  virtual RefPtr<mozilla::layers::NativeLayerRoot> GetNativeLayerRoot() override;
   virtual void DrawWindowOverlay(mozilla::widget::WidgetRenderingContext* aManager,
                                  LayoutDeviceIntRect aRect) override;
 
   virtual void UpdateThemeGeometries(const nsTArray<ThemeGeometry>& aThemeGeometries) override;
 
   virtual void UpdateWindowDraggingRegion(const LayoutDeviceIntRegion& aRegion) override;
   LayoutDeviceIntRegion GetNonDraggableRegion() { return mNonDraggableRegion.Region(); }
 
@@ -562,16 +563,18 @@ class nsChildView final : public nsBaseW
                                                nsString& aCommitted) override;
 
   virtual void SetPluginFocused(bool& aFocused) override;
 
   bool IsPluginFocused() { return mPluginFocused; }
 
   virtual LayoutDeviceIntPoint GetClientOffset() override;
 
+  virtual LayoutDeviceIntRegion GetOpaqueWidgetRegion() override;
+
   void DispatchAPZWheelInputEvent(mozilla::InputData& aEvent, bool aCanTriggerSwipe);
   nsEventStatus DispatchAPZInputEvent(mozilla::InputData& aEvent);
 
   void SwipeFinished();
 
   nsresult SetPrefersReducedMotionOverrideForTest(bool aValue) override;
   nsresult ResetPrefersReducedMotionOverrideForTest() override;
 
@@ -700,26 +703,23 @@ class nsChildView final : public nsBaseW
 
   // Used in BasicCompositor OMTC mode. Presents the BasicCompositor result
   // surface to the screen using an OpenGL context.
   // Always null if StaticPrefs::gfx_core_animation_enabled_AtStartup() is true.
   mozilla::UniquePtr<GLPresenter> mGLPresenter;
 
   RefPtr<mozilla::layers::NativeLayerRootCA> mNativeLayerRoot;
 
-  // The CoreAnimation layer that contains the rendering from Gecko. This is a
-  // sublayer of mNativeLayerRoot's underlying wrapper layer.
+  // In BasicLayers mode, this is the CoreAnimation layer that contains the
+  // rendering from Gecko. It is a sublayer of mNativeLayerRoot's underlying
+  // wrapper layer.
+  // Lazily created by EnsureContentLayerForMainThreadPainting().
   // Always null if StaticPrefs::gfx_core_animation_enabled_AtStartup() is false.
   RefPtr<mozilla::layers::NativeLayerCA> mContentLayer;
 
-  // Used in BasicCompositor OMTC mode.
-  // Non-null between calls to PreRender(Impl) and PostRender,
-  // if StaticPrefs::gfx_core_animation_enabled_AtStartup() is true.
-  RefPtr<MacIOSurface> mBasicCompositorIOSurface;
-
   mozilla::UniquePtr<mozilla::VibrancyManager> mVibrancyManager;
   RefPtr<mozilla::SwipeTracker> mSwipeTracker;
   mozilla::UniquePtr<mozilla::SwipeEventQueue> mSwipeEventQueue;
 
   // Only used for drawRect-based painting in popups.
   // Always null if StaticPrefs::gfx_core_animation_enabled_AtStartup() is true.
   RefPtr<mozilla::gfx::DrawTarget> mBackingSurface;
 
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -356,17 +356,19 @@ nsChildView::~nsChildView() {
     nsChildView* childView = static_cast<nsChildView*>(kid);
     kid = kid->GetPrevSibling();
     childView->ResetParent();
   }
 
   NS_WARNING_ASSERTION(mOnDestroyCalled, "nsChildView object destroyed without calling Destroy()");
 
   if (StaticPrefs::gfx_core_animation_enabled_AtStartup()) {
-    mNativeLayerRoot->RemoveLayer(mContentLayer);  // safe if already removed
+    if (mContentLayer) {
+      mNativeLayerRoot->RemoveLayer(mContentLayer);  // safe if already removed
+    }
   }
 
   DestroyCompositor();
 
   // An nsChildView object that was in use can be destroyed without Destroy()
   // ever being called on it.  So we also need to do a quick, safe cleanup
   // here (it's too late to just call Destroy(), which can cause crashes).
   // It's particularly important to make sure widgetDestroyed is called on our
@@ -420,19 +422,16 @@ nsresult nsChildView::Create(nsIWidget* 
   // that NS_NATIVE_WIDGET is the NSView.
   CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(mParentView);
   NSRect r = nsCocoaUtils::DevPixelsToCocoaPoints(mBounds, scaleFactor);
   mView = [[ChildView alloc] initWithFrame:r geckoChild:this];
 
   if (StaticPrefs::gfx_core_animation_enabled_AtStartup()) {
     mNativeLayerRoot = NativeLayerRootCA::CreateForCALayer([mView rootCALayer]);
     mNativeLayerRoot->SetBackingScale(scaleFactor);
-    RefPtr<NativeLayer> contentLayer = mNativeLayerRoot->CreateLayer();
-    mNativeLayerRoot->AppendLayer(contentLayer);
-    mContentLayer = contentLayer->AsNativeLayerCA();
   }
 
   // If this view was created in a Gecko view hierarchy, the initial state
   // is hidden.  If the view is attached only to a native NSView but has
   // no Gecko parent (as in embedding), the initial state is visible.
   if (mParentWidget)
     [mView setHidden:YES];
   else
@@ -1294,16 +1293,17 @@ void nsChildView::Invalidate(const Layou
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
 
   if (!mView || !mVisible) return;
 
   NS_ASSERTION(GetLayerManager()->GetBackendType() != LayersBackend::LAYERS_CLIENT,
                "Shouldn't need to invalidate with accelerated OMTC layers!");
 
   if (StaticPrefs::gfx_core_animation_enabled_AtStartup()) {
+    EnsureContentLayerForMainThreadPainting();
     mContentLayer->InvalidateRegionThroughoutSwapchain(aRect.ToUnknownRect());
     [mView markLayerForDisplay];
   } else {
     [[mView pixelHostingView] setNeedsDisplayInRect:DevPixelsToCocoaPoints(aRect)];
   }
 
   NS_OBJC_END_TRY_ABORT_BLOCK;
 }
@@ -1497,17 +1497,29 @@ bool nsChildView::PaintWindowInIOSurface
   RefPtr<MacIOSurface> surf = new MacIOSurface(std::move(aSurface));
   surf->Lock(false);
   RefPtr<gfx::DrawTarget> dt = surf->GetAsDrawTargetLocked(gfx::BackendType::SKIA);
   bool result = PaintWindowInDrawTarget(dt, aInvalidRegion, dt->GetSize());
   surf->Unlock(false);
   return result;
 }
 
+void nsChildView::EnsureContentLayerForMainThreadPainting() {
+  if (!mContentLayer) {
+    // The content layer gets created on demand for BasicLayers windows. We do
+    // not create it during widget creation because, for non-BasicLayers windows,
+    // the compositing layer manager will create any layers it needs.
+    RefPtr<NativeLayer> contentLayer = mNativeLayerRoot->CreateLayer();
+    mNativeLayerRoot->AppendLayer(contentLayer);
+    mContentLayer = contentLayer->AsNativeLayerCA();
+  }
+}
+
 void nsChildView::PaintWindowInContentLayer() {
+  EnsureContentLayerForMainThreadPainting();
   mContentLayer->SetRect(GetBounds().ToUnknownRect());
   {
     auto opaqueRegion = mOpaqueRegion.Lock();
     mContentLayer->SetOpaqueRegion(opaqueRegion->ToUnknownRegion());
   }
   mContentLayer->SetSurfaceIsFlipped(false);
   CFTypeRefPtr<IOSurfaceRef> surf = mContentLayer->NextSurface();
   if (!surf) {
@@ -1523,23 +1535,23 @@ void nsChildView::HandleMainThreadCATran
   WillPaintWindow();
 
   if (GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_BASIC) {
     // We're in BasicLayers mode, i.e. main thread software compositing.
     // Composite the window into our layer's surface.
     PaintWindowInContentLayer();
   } else {
     // Trigger a synchronous OMTC composite. This will call NextSurface and
-    // NotifySurfaceReady on the compositor thread to update mContentLayer's
-    // surface, and the main thread (this thread) will wait inside PaintWindow
+    // NotifySurfaceReady on the compositor thread to update mNativeLayerRoot's
+    // contents, and the main thread (this thread) will wait inside PaintWindow
     // during that time.
     PaintWindow(LayoutDeviceIntRegion(GetBounds()));
   }
 
-  // Apply the changes from mContentLayer to its underlying CALayer. Now is a
+  // Apply the changes inside mNativeLayerRoot to the underlying CALayers. Now is a
   // good time to call this because we know we're currently inside a main thread
   // CATransaction.
   {
     auto compositingState = mCompositingState.Lock();
     mNativeLayerRoot->ApplyChanges();
     compositingState->mNativeLayerChangesPending = false;
   }
 
@@ -1585,16 +1597,21 @@ LayoutDeviceIntPoint nsChildView::Widget
   FlipCocoaScreenCoordinate(origin);
 
   // convert to device pixels
   return CocoaPointsToDevPixels(origin);
 
   NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(LayoutDeviceIntPoint(0, 0));
 }
 
+LayoutDeviceIntRegion nsChildView::GetOpaqueWidgetRegion() {
+  auto opaqueRegion = mOpaqueRegion.Lock();
+  return *opaqueRegion;
+}
+
 nsresult nsChildView::SetTitle(const nsAString& title) {
   // child views don't have titles
   return NS_OK;
 }
 
 nsresult nsChildView::GetAttention(int32_t aCycleCount) {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
 
@@ -1975,71 +1992,21 @@ bool nsChildView::PreRender(WidgetRender
 
   if (!canComposite) {
     mViewTearDownLock.Unlock();
     return false;
   }
   return true;
 }
 
-class SurfaceRegistryWrapperAroundGLContextCGL : public layers::IOSurfaceRegistry {
- public:
-  explicit SurfaceRegistryWrapperAroundGLContextCGL(gl::GLContextCGL* aContext)
-      : mContext(aContext) {}
-  void RegisterSurface(CFTypeRefPtr<IOSurfaceRef> aSurface) override {
-    mContext->RegisterIOSurface(aSurface.get());
-  }
-  void UnregisterSurface(CFTypeRefPtr<IOSurfaceRef> aSurface) override {
-    mContext->UnregisterIOSurface(aSurface.get());
-  }
-  RefPtr<gl::GLContextCGL> mContext;
-};
-
 bool nsChildView::PreRenderImpl(WidgetRenderingContext* aContext) {
   UniquePtr<GLManager> manager(GLManager::CreateGLManager(aContext->mLayerManager));
   gl::GLContext* gl = manager ? manager->gl() : aContext->mGL;
 
   if (StaticPrefs::gfx_core_animation_enabled_AtStartup()) {
-    if (gl) {
-      auto glContextCGL = GLContextCGL::Cast(gl);
-      mContentLayer->SetRect(GetBounds().ToUnknownRect());
-      {
-        auto opaqueRegion = mOpaqueRegion.Lock();
-        mContentLayer->SetOpaqueRegion(opaqueRegion->ToUnknownRegion());
-      }
-      mContentLayer->SetSurfaceIsFlipped(true);
-      RefPtr<layers::IOSurfaceRegistry> currentRegistry = mContentLayer->GetSurfaceRegistry();
-      if (!currentRegistry) {
-        mContentLayer->SetSurfaceRegistry(
-            MakeAndAddRef<SurfaceRegistryWrapperAroundGLContextCGL>(glContextCGL));
-      } else {
-        MOZ_RELEASE_ASSERT(
-            static_cast<SurfaceRegistryWrapperAroundGLContextCGL*>(currentRegistry.get())
-                ->mContext == glContextCGL);
-      }
-      CFTypeRefPtr<IOSurfaceRef> surf = mContentLayer->NextSurface();
-      if (!surf) {
-        return false;
-      }
-      glContextCGL->UseRegisteredIOSurfaceForDefaultFramebuffer(surf.get());
-      return true;
-    }
-    // We're using BasicCompositor.
-    MOZ_RELEASE_ASSERT(!mBasicCompositorIOSurface);
-    mContentLayer->SetRect(GetBounds().ToUnknownRect());
-    {
-      auto opaqueRegion = mOpaqueRegion.Lock();
-      mContentLayer->SetOpaqueRegion(opaqueRegion->ToUnknownRegion());
-    }
-    mContentLayer->SetSurfaceIsFlipped(false);
-    CFTypeRefPtr<IOSurfaceRef> surf = mContentLayer->NextSurface();
-    if (!surf) {
-      return false;
-    }
-    mBasicCompositorIOSurface = new MacIOSurface(std::move(surf));
     return true;
   }
 
   if (gl) {
     return [mView preRender:GLContextCGL::Cast(gl)->GetNSOpenGLContext()];
   }
 
   // BasicCompositor.
@@ -2051,18 +2018,16 @@ bool nsChildView::PreRenderImpl(WidgetRe
   if (!mBasicCompositorImage) {
     mBasicCompositorImage = MakeUnique<RectTextureImage>();
   }
   return true;
 }
 
 void nsChildView::PostRender(WidgetRenderingContext* aContext) {
   if (StaticPrefs::gfx_core_animation_enabled_AtStartup()) {
-    mContentLayer->NotifySurfaceReady();
-
     auto compositingState = mCompositingState.Lock();
     if (compositingState->mAsyncCATransactionsSuspended) {
       // We should not trigger a CATransactions on this thread. Instead, let the
       // main thread take care of calling ApplyChanges at an appropriate time.
       compositingState->mNativeLayerChangesPending = true;
     } else {
       // Force a CoreAnimation layer tree update from this thread.
       [CATransaction begin];
@@ -2075,21 +2040,17 @@ void nsChildView::PostRender(WidgetRende
     GLContext* gl = manager ? manager->gl() : aContext->mGL;
     NSOpenGLContext* glContext =
         gl ? GLContextCGL::Cast(gl)->GetNSOpenGLContext() : mGLPresenter->GetNSOpenGLContext();
     [mView postRender:glContext];
   }
   mViewTearDownLock.Unlock();
 }
 
-void nsChildView::DoCompositorCleanup() {
-  if (mContentLayer) {
-    mContentLayer->SetSurfaceRegistry(nullptr);
-  }
-}
+RefPtr<layers::NativeLayerRoot> nsChildView::GetNativeLayerRoot() { return mNativeLayerRoot; }
 
 void nsChildView::DrawWindowOverlay(WidgetRenderingContext* aContext, LayoutDeviceIntRect aRect) {
   mozilla::UniquePtr<GLManager> manager(GLManager::CreateGLManager(aContext->mLayerManager));
   if (manager) {
     DrawWindowOverlay(manager.get(), aRect);
   }
 }
 
@@ -2600,28 +2561,19 @@ void nsChildView::UpdateBoundsFromView()
   mBounds = CocoaPointsToDevPixels([mView frame]);
   if (mBounds.Size() != oldSize) {
     SuspendAsyncCATransactions();
   }
 }
 
 already_AddRefed<gfx::DrawTarget> nsChildView::StartRemoteDrawingInRegion(
     LayoutDeviceIntRegion& aInvalidRegion, BufferMode* aBufferMode) {
-  if (StaticPrefs::gfx_core_animation_enabled_AtStartup()) {
-    MOZ_RELEASE_ASSERT(mBasicCompositorIOSurface,
-                       "Should have been set up by nsChildView::PreRender");
-
-    mContentLayer->InvalidateRegionThroughoutSwapchain(aInvalidRegion.ToUnknownRegion());
-    aInvalidRegion =
-        LayoutDeviceIntRegion::FromUnknownRegion(mContentLayer->CurrentSurfaceInvalidRegion());
-    *aBufferMode = BufferMode::BUFFER_NONE;
-    mBasicCompositorIOSurface->Lock(false);
-    return mBasicCompositorIOSurface->GetAsDrawTargetLocked(gfx::BackendType::SKIA);
-  }
-
+  MOZ_RELEASE_ASSERT(!StaticPrefs::gfx_core_animation_enabled_AtStartup(),
+                     "Not expecting calls to StartRemoteDrawingInRegion when using CoreAnimation "
+                     "because we return something non-null from GetNativeLayerRoot()");
   MOZ_RELEASE_ASSERT(mGLPresenter);
 
   LayoutDeviceIntRegion dirtyRegion(aInvalidRegion);
   LayoutDeviceIntSize renderSize = mBounds.Size();
 
   MOZ_RELEASE_ASSERT(mBasicCompositorImage, "Should have created this in PreRender.");
   RefPtr<gfx::DrawTarget> drawTarget = mBasicCompositorImage->BeginUpdate(renderSize, dirtyRegion);
 
@@ -2633,28 +2585,22 @@ already_AddRefed<gfx::DrawTarget> nsChil
 
   aInvalidRegion = mBasicCompositorImage->GetUpdateRegion();
   *aBufferMode = BufferMode::BUFFER_NONE;
 
   return drawTarget.forget();
 }
 
 void nsChildView::EndRemoteDrawing() {
-  if (StaticPrefs::gfx_core_animation_enabled_AtStartup()) {
-    MOZ_RELEASE_ASSERT(mBasicCompositorIOSurface);
-
-    // The DrawTarget we returned from StartRemoteDrawingInRegion, which
-    // referred to pixels in mBasicCompositorIOSurface, is no longer in use.
-    // We can unlock the surface and release our reference to it.
-    mBasicCompositorIOSurface->Unlock(false);
-    mBasicCompositorIOSurface = nullptr;
-  } else {
-    mBasicCompositorImage->EndUpdate();
-    DoRemoteComposition(mBounds);
-  }
+  MOZ_RELEASE_ASSERT(!StaticPrefs::gfx_core_animation_enabled_AtStartup(),
+                     "Not expecting calls to EndRemoteDrawing when using CoreAnimation "
+                     "because we return something non-null from GetNativeLayerRoot()");
+
+  mBasicCompositorImage->EndUpdate();
+  DoRemoteComposition(mBounds);
 }
 
 void nsChildView::CleanupRemoteDrawing() {
   mBasicCompositorImage = nullptr;
   mCornerMaskImage = nullptr;
   mTitlebarImage = nullptr;
   mGLPresenter = nullptr;
 }
@@ -2691,16 +2637,35 @@ void nsChildView::DoRemoteComposition(co
 
 @implementation NonDraggableView
 - (BOOL)mouseDownCanMoveWindow {
   return NO;
 }
 - (NSView*)hitTest:(NSPoint)aPoint {
   return nil;
 }
+- (NSRect)_opaqueRectForWindowMoveWhenInTitlebar {
+  // In NSWindows that use NSFullSizeContentViewWindowMask, NSViews which
+  // overlap the titlebar do not disable window dragging in the overlapping
+  // areas even if they return NO from mouseDownCanMoveWindow. This can have
+  // unfortunate effects: For example, dragging tabs in a browser window would
+  // move the window if those tabs are in the titlebar.
+  // macOS does not seem to offer a documented way to opt-out of the forced
+  // window dragging in the titlebar.
+  // Overriding _opaqueRectForWindowMoveWhenInTitlebar is an undocumented way
+  // of opting out of this behavior. This method was added in 10.11 and is used
+  // by some NSControl subclasses to prevent window dragging in the titlebar.
+  // The function which assembles the draggable area of the window calls
+  // _opaqueRect for the content area and _opaqueRectForWindowMoveWhenInTitlebar
+  // for the titlebar area, on all visible NSViews. The default implementation
+  // of _opaqueRect returns [self visibleRect], and the default implementation
+  // of _opaqueRectForWindowMoveWhenInTitlebar returns NSZeroRect unless it's
+  // overridden.
+  return [self visibleRect];
+}
 @end
 
 void nsChildView::UpdateWindowDraggingRegion(const LayoutDeviceIntRegion& aRegion) {
   // mView returns YES from mouseDownCanMoveWindow, so we need to put NSViews
   // that return NO from mouseDownCanMoveWindow in the places that shouldn't
   // be draggable. We can't do it the other way round because returning
   // YES from mouseDownCanMoveWindow doesn't have any effect if there's a
   // superview that returns NO.
--- a/widget/cocoa/nsCocoaWindow.mm
+++ b/widget/cocoa/nsCocoaWindow.mm
@@ -1911,16 +1911,17 @@ LayoutDeviceIntSize nsCocoaWindow::Clien
   //
   // So we call frameRectForContentRect on NSWindow here, instead of mWindow, so
   // that we don't run into our override if this window is a window that draws
   // its content into the titlebar.
   //
   // This is the same thing the windows widget does, but we probably should fix
   // that, see bug 1445738.
   NSUInteger styleMask = [mWindow styleMask];
+  styleMask &= ~NSFullSizeContentViewWindowMask;
   NSRect inflatedRect = [NSWindow frameRectForContentRect:rect styleMask:styleMask];
   r = nsCocoaUtils::CocoaRectToGeckoRectDevPix(inflatedRect, backingScale);
   return r.Size();
 
   NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(LayoutDeviceIntSize(0, 0));
 }
 
 nsMenuBarX* nsCocoaWindow::GetMenuBar() { return mMenuBar; }
@@ -2622,16 +2623,17 @@ already_AddRefed<nsIWidget> nsIWidget::C
 }
 
 @end
 
 @interface NSView (FrameViewMethodSwizzling)
 - (NSPoint)FrameView__closeButtonOrigin;
 - (NSPoint)FrameView__fullScreenButtonOrigin;
 - (BOOL)FrameView__wantsFloatingTitlebar;
+- (CGFloat)FrameView__titlebarHeight;
 @end
 
 @implementation NSView (FrameViewMethodSwizzling)
 
 - (NSPoint)FrameView__closeButtonOrigin {
   NSPoint defaultPosition = [self FrameView__closeButtonOrigin];
   if ([[self window] isKindOfClass:[ToolbarWindow class]]) {
     return [(ToolbarWindow*)[self window] windowButtonsPositionWithDefaultPosition:defaultPosition];
@@ -2647,16 +2649,35 @@ already_AddRefed<nsIWidget> nsIWidget::C
   }
   return defaultPosition;
 }
 
 - (BOOL)FrameView__wantsFloatingTitlebar {
   return NO;
 }
 
+- (CGFloat)FrameView__titlebarHeight {
+  CGFloat height = [self FrameView__titlebarHeight];
+  if ([[self window] isKindOfClass:[ToolbarWindow class]]) {
+    // Make sure that the titlebar height includes our shifted buttons.
+    // The following coordinates are in window space, with the origin being at the bottom left
+    // corner of the window.
+    ToolbarWindow* win = (ToolbarWindow*)[self window];
+    CGFloat frameHeight = [self frame].size.height;
+    NSPoint pointAboveWindow = {0.0, frameHeight};
+    CGFloat windowButtonY = [win windowButtonsPositionWithDefaultPosition:pointAboveWindow].y;
+    CGFloat fullScreenButtonY =
+        [win fullScreenButtonPositionWithDefaultPosition:pointAboveWindow].y;
+    CGFloat maxDistanceFromWindowTopToButtonBottom =
+        std::max(frameHeight - windowButtonY, frameHeight - fullScreenButtonY);
+    height = std::max(height, maxDistanceFromWindowTopToButtonBottom);
+  }
+  return height;
+}
+
 @end
 
 static NSMutableSet* gSwizzledFrameViewClasses = nil;
 
 @interface NSWindow (PrivateSetNeedsDisplayInRectMethod)
 - (void)_setNeedsDisplayInRect:(NSRect)aRect;
 @end
 
@@ -2725,16 +2746,18 @@ static NSMutableSet* gSwizzledFrameViewC
   }
 
   static IMP our_closeButtonOrigin =
       class_getMethodImplementation([NSView class], @selector(FrameView__closeButtonOrigin));
   static IMP our_fullScreenButtonOrigin =
       class_getMethodImplementation([NSView class], @selector(FrameView__fullScreenButtonOrigin));
   static IMP our_wantsFloatingTitlebar =
       class_getMethodImplementation([NSView class], @selector(FrameView__wantsFloatingTitlebar));
+  static IMP our_titlebarHeight =
+      class_getMethodImplementation([NSView class], @selector(FrameView__titlebarHeight));
 
   if (![gSwizzledFrameViewClasses containsObject:frameViewClass]) {
     // Either of these methods might be implemented in both a subclass of
     // NSFrameView and one of its own subclasses.  Which means that if we
     // aren't careful we might end up swizzling the same method twice.
     // Since method swizzling involves swapping pointers, this would break
     // things.
     IMP _closeButtonOrigin =
@@ -2744,33 +2767,36 @@ static NSMutableSet* gSwizzledFrameViewC
                                 @selector(FrameView__closeButtonOrigin));
     }
     IMP _fullScreenButtonOrigin =
         class_getMethodImplementation(frameViewClass, @selector(_fullScreenButtonOrigin));
     if (_fullScreenButtonOrigin && _fullScreenButtonOrigin != our_fullScreenButtonOrigin) {
       nsToolkit::SwizzleMethods(frameViewClass, @selector(_fullScreenButtonOrigin),
                                 @selector(FrameView__fullScreenButtonOrigin));
     }
-    // Override the _wantsFloatingTitlebar method to return NO, because it works around multiple
-    // problems:
-    // When we're not using CoreAnimation, the "floating titlebar" overlaps in a glitchy way with
-    // the NSOpenGLContext when we're drawing in the titlebar. These glitches do not happen when we
-    // use CoreAnimation.
-    // An additional problem appears in builds that link against the 10.14 SDK: In windows where
-    // _wantsFloatingTitlebar returns YES, the root NSView contains an additional view that provides
-    // a window background. This confuses our setContentView override which will place the content
-    // view *below* that background view, effectively hiding the content view completely.
-    // The floating titlebar view also slightly clips the bottom of the window buttons which we
-    // forcefully move down with our override of _closeButtonOrigin.
-    // See bug 1576391 for the removal of the _wantsFloatingTitlebar override.
-    IMP _wantsFloatingTitlebar =
-        class_getMethodImplementation(frameViewClass, @selector(_wantsFloatingTitlebar));
-    if (_wantsFloatingTitlebar && _wantsFloatingTitlebar != our_wantsFloatingTitlebar) {
-      nsToolkit::SwizzleMethods(frameViewClass, @selector(_wantsFloatingTitlebar),
-                                @selector(FrameView__wantsFloatingTitlebar));
+
+    if (StaticPrefs::gfx_core_animation_enabled_AtStartup()) {
+      // Override _titlebarHeight so that the floating titlebar doesn't clip the bottom of the
+      // window buttons which we move down with our override of _closeButtonOrigin.
+      IMP _titlebarHeight =
+          class_getMethodImplementation(frameViewClass, @selector(_titlebarHeight));
+      if (_titlebarHeight && _titlebarHeight != our_titlebarHeight) {
+        nsToolkit::SwizzleMethods(frameViewClass, @selector(_titlebarHeight),
+                                  @selector(FrameView__titlebarHeight));
+      }
+    } else {
+      // If CoreAnimation is not enabled, override the _wantsFloatingTitlebar method to return NO,
+      // in order to avoid titlebar glitches when in that configuration. These glitches do not
+      // appear when CoreAnimation is enabled.
+      IMP _wantsFloatingTitlebar =
+          class_getMethodImplementation(frameViewClass, @selector(_wantsFloatingTitlebar));
+      if (_wantsFloatingTitlebar && _wantsFloatingTitlebar != our_wantsFloatingTitlebar) {
+        nsToolkit::SwizzleMethods(frameViewClass, @selector(_wantsFloatingTitlebar),
+                                  @selector(FrameView__wantsFloatingTitlebar));
+      }
     }
 
     [gSwizzledFrameViewClasses addObject:frameViewClass];
   }
 
   return frameViewClass;
 }
 
@@ -2927,24 +2953,26 @@ static const NSString* kStateWantsTitleD
   return mDrawsIntoWindowFrame;
 }
 
 - (NSRect)childViewRectForFrameRect:(NSRect)aFrameRect {
   if (mDrawsIntoWindowFrame) {
     return aFrameRect;
   }
   NSUInteger styleMask = [self styleMask];
+  styleMask &= ~NSFullSizeContentViewWindowMask;
   return [NSWindow contentRectForFrameRect:aFrameRect styleMask:styleMask];
 }
 
 - (NSRect)frameRectForChildViewRect:(NSRect)aChildViewRect {
   if (mDrawsIntoWindowFrame) {
     return aChildViewRect;
   }
   NSUInteger styleMask = [self styleMask];
+  styleMask &= ~NSFullSizeContentViewWindowMask;
   return [NSWindow frameRectForContentRect:aChildViewRect styleMask:styleMask];
 }
 
 - (void)setWantsTitleDrawn:(BOOL)aDrawTitle {
   mDrawTitle = aDrawTitle;
   if ([self respondsToSelector:@selector(setTitleVisibility:)]) {
     [self setTitleVisibility:mDrawTitle ? NSWindowTitleVisible : NSWindowTitleHidden];
   }
@@ -3038,49 +3066,16 @@ static const NSString* kStateWantsTitleD
 // Possibly move the titlebar buttons.
 - (void)reflowTitlebarElements {
   NSView* frameView = [[self contentView] superview];
   if ([frameView respondsToSelector:@selector(_tileTitlebarAndRedisplay:)]) {
     [frameView _tileTitlebarAndRedisplay:NO];
   }
 }
 
-// Override methods that translate between content rect and frame rect.
-- (NSRect)contentRectForFrameRect:(NSRect)aRect {
-  return aRect;
-}
-
-- (NSRect)contentRectForFrameRect:(NSRect)aRect styleMask:(NSUInteger)aMask {
-  return aRect;
-}
-
-- (NSRect)frameRectForContentRect:(NSRect)aRect {
-  return aRect;
-}
-
-- (NSRect)frameRectForContentRect:(NSRect)aRect styleMask:(NSUInteger)aMask {
-  return aRect;
-}
-
-- (void)setContentView:(NSView*)aView {
-  [super setContentView:aView];
-
-  // Now move the contentView to the bottommost layer so that it's guaranteed
-  // to be under the window buttons.
-  NSView* frameView = [aView superview];
-  [aView removeFromSuperview];
-  if ([frameView respondsToSelector:@selector(_addKnownSubview:positioned:relativeTo:)]) {
-    // 10.10 prints a warning when we call addSubview on the frame view, so we
-    // silence the warning by calling a private method instead.
-    [frameView _addKnownSubview:aView positioned:NSWindowBelow relativeTo:nil];
-  } else {
-    [frameView addSubview:aView positioned:NSWindowBelow relativeTo:nil];
-  }
-}
-
 - (NSArray*)titlebarControls {
   MOZ_RELEASE_ASSERT(!StaticPrefs::gfx_core_animation_enabled_AtStartup());
 
   // Return all subviews of the frameView which are not the content view.
   NSView* frameView = [[self contentView] superview];
   NSMutableArray* array = [[[frameView subviews] mutableCopy] autorelease];
   [array removeObject:[self contentView]];
   return array;
@@ -3256,16 +3251,26 @@ static const NSString* kStateWantsTitleD
                     defer:(BOOL)aFlag {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
 
   // We treat aChildViewRect as the rectangle that the window's main ChildView
   // should be sized to. Get the right frameRect for the requested child view
   // rect.
   NSRect frameRect = [NSWindow frameRectForContentRect:aChildViewRect styleMask:aStyle];
 
+  if (StaticPrefs::gfx_core_animation_enabled_AtStartup() && nsCocoaFeatures::OnYosemiteOrLater()) {
+    // Always size the content view to the full frame size of the window.
+    // We cannot use this window mask on 10.9, because it was added in 10.10.
+    // We also cannot use it when our CoreAnimation pref is disabled: This flag forces CoreAnimation
+    // on for the entire window, which causes glitches in combination with our non-CoreAnimation
+    // drawing. (Specifically, on macOS versions up until at least 10.14.0, layer-backed
+    // NSOpenGLViews have extremely glitchy resizing behavior.)
+    aStyle |= NSFullSizeContentViewWindowMask;
+  }
+
   // -[NSWindow initWithContentRect:styleMask:backing:defer:] calls
   // [self frameRectForContentRect:styleMask:] to convert the supplied content
   // rect to the window's frame rect. We've overridden that method to be a
   // pass-through function. So, in order to get the intended frameRect, we need
   // to supply frameRect itself as the "content rect".
   NSRect contentRect = frameRect;
 
   if ((self = [super initWithContentRect:contentRect
@@ -3311,16 +3316,56 @@ static const NSString* kStateWantsTitleD
     [self.contentView addSubview:mTitlebarGradientView];
   } else if (!needTitlebarView && mTitlebarGradientView) {
     [mTitlebarGradientView removeFromSuperview];
     [mTitlebarGradientView release];
     mTitlebarGradientView = nil;
   }
 }
 
+// Override methods that translate between content rect and frame rect.
+// These overrides are only needed on 10.9 or when the CoreAnimation pref is
+// is false; otherwise we use NSFullSizeContentViewMask and get this behavior
+// for free.
+- (NSRect)contentRectForFrameRect:(NSRect)aRect {
+  return aRect;
+}
+
+- (NSRect)contentRectForFrameRect:(NSRect)aRect styleMask:(NSUInteger)aMask {
+  return aRect;
+}
+
+- (NSRect)frameRectForContentRect:(NSRect)aRect {
+  return aRect;
+}
+
+- (NSRect)frameRectForContentRect:(NSRect)aRect styleMask:(NSUInteger)aMask {
+  return aRect;
+}
+
+- (void)setContentView:(NSView*)aView {
+  [super setContentView:aView];
+
+  if (!([self styleMask] & NSFullSizeContentViewWindowMask)) {
+    // Move the contentView to the bottommost layer so that it's guaranteed
+    // to be under the window buttons.
+    // When the window uses the NSFullSizeContentViewMask, this manual
+    // adjustment is not necessary.
+    NSView* frameView = [aView superview];
+    [aView removeFromSuperview];
+    if ([frameView respondsToSelector:@selector(_addKnownSubview:positioned:relativeTo:)]) {
+      // 10.10 prints a warning when we call addSubview on the frame view, so we
+      // silence the warning by calling a private method instead.
+      [frameView _addKnownSubview:aView positioned:NSWindowBelow relativeTo:nil];
+    } else {
+      [frameView addSubview:aView positioned:NSWindowBelow relativeTo:nil];
+    }
+  }
+}
+
 - (void)windowMainStateChanged {
   [self setTitlebarNeedsDisplay];
   [[self mainChildView] ensureNextCompositeIsAtomicWithMainThreadPaint];
 }
 
 - (void)setTitlebarNeedsDisplay {
   [mTitlebarGradientView setNeedsDisplay:YES];
 }
@@ -3337,16 +3382,17 @@ static const NSString* kStateWantsTitleD
 }
 
 - (CGFloat)titlebarHeight {
   // We use the original content rect here, not what we return from
   // [self contentRectForFrameRect:], because that would give us a
   // titlebarHeight of zero.
   NSRect frameRect = [self frame];
   NSUInteger styleMask = [self styleMask];
+  styleMask &= ~NSFullSizeContentViewWindowMask;
   NSRect originalContentRect = [NSWindow contentRectForFrameRect:frameRect styleMask:styleMask];
   return NSMaxY(frameRect) - NSMaxY(originalContentRect);
 }
 
 // Stores the complete height of titlebar + toolbar.
 - (void)setUnifiedToolbarHeight:(CGFloat)aHeight {
   if (aHeight == mUnifiedToolbarHeight) return;
 
--- a/widget/nsBaseWidget.h
+++ b/widget/nsBaseWidget.h
@@ -8,16 +8,17 @@
 #include "InputData.h"
 #include "mozilla/EventForwards.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/WidgetUtils.h"
 #include "mozilla/layers/APZCCallbackHelper.h"
 #include "mozilla/layers/CompositorOptions.h"
+#include "mozilla/layers/NativeLayer.h"
 #include "nsRect.h"
 #include "nsIWidget.h"
 #include "nsWidgetsCID.h"
 #include "nsIFile.h"
 #include "nsString.h"
 #include "nsCOMPtr.h"
 #include "nsIRollupListener.h"
 #include "nsIObserver.h"
@@ -443,20 +444,19 @@ class nsBaseWidget : public nsIWidget, p
  protected:
   // These are methods for CompositorWidgetWrapper, and should only be
   // accessed from that class. Derived widgets can choose which methods to
   // implement, or none if supporting out-of-process compositing.
   virtual bool PreRender(mozilla::widget::WidgetRenderingContext* aContext) {
     return true;
   }
   virtual void PostRender(mozilla::widget::WidgetRenderingContext* aContext) {}
-  virtual void DoCompositorCleanup() {}
-  virtual void DrawWindowUnderlay(
-      mozilla::widget::WidgetRenderingContext* aContext,
-      LayoutDeviceIntRect aRect) {}
+  virtual RefPtr<mozilla::layers::NativeLayerRoot> GetNativeLayerRoot() {
+    return nullptr;
+  }
   virtual void DrawWindowOverlay(
       mozilla::widget::WidgetRenderingContext* aContext,
       LayoutDeviceIntRect aRect) {}
   virtual already_AddRefed<DrawTarget> StartRemoteDrawing();
   virtual already_AddRefed<DrawTarget> StartRemoteDrawingInRegion(
       LayoutDeviceIntRegion& aInvalidRegion, BufferMode* aBufferMode) {
     return StartRemoteDrawing();
   }
@@ -467,16 +467,19 @@ class nsBaseWidget : public nsIWidget, p
   }
   virtual void CleanupRemoteDrawing() {}
   virtual void CleanupWindowEffects() {}
   virtual bool InitCompositor(mozilla::layers::Compositor* aCompositor) {
     return true;
   }
   virtual uint32_t GetGLFrameBufferFormat();
   virtual bool CompositorInitiallyPaused() { return false; }
+#ifdef XP_MACOSX
+  virtual LayoutDeviceIntRegion GetOpaqueWidgetRegion() { return {}; }
+#endif
 
  protected:
   void ResolveIconName(const nsAString& aIconName, const nsAString& aIconSuffix,
                        nsIFile** aResult);
   virtual void OnDestroy();
   void BaseCreate(nsIWidget* aParent, nsWidgetInitData* aInitData);
 
   virtual void ConfigureAPZCTreeManager();
--- a/xpcom/ds/nsCRT.h
+++ b/xpcom/ds/nsCRT.h
@@ -9,20 +9,22 @@
 #include <stdlib.h>
 #include <ctype.h>
 #include "plstr.h"
 #include "nscore.h"
 #include "nsCRTGlue.h"
 
 #if defined(XP_WIN)
 #  define NS_LINEBREAK "\015\012"
+#  define NS_ULINEBREAK u"\015\012"
 #  define NS_LINEBREAK_LEN 2
 #else
 #  ifdef XP_UNIX
 #    define NS_LINEBREAK "\012"
+#    define NS_ULINEBREAK u"\012"
 #    define NS_LINEBREAK_LEN 1
 #  endif /* XP_UNIX */
 #endif   /* XP_WIN */
 
 extern const char16_t kIsoLatin1ToUCS2[256];
 
 /// This is a wrapper class around all the C runtime functions.