merge mozilla-inbound to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Fri, 23 Jun 2017 11:28:19 +0200
changeset 414467 1466b62da7b2512669c6bc1a3a826fd4171e41a5
parent 414406 3b468193c933806339fa4a8dee73d03a09e635ab (current diff)
parent 414466 1fd20434759f528282da8fe419b99b9eba40b170 (diff)
child 414468 671f398507525103abbaf6eaf50a0d036e5030d6
child 414492 40b82164d801182752a63107978d3df6d63a441a
child 414704 ab1d1b0135febb8a13915ac7a78c1173e0c71c77
push id7566
push usermtabara@mozilla.com
push dateWed, 02 Aug 2017 08:25:16 +0000
treeherdermozilla-beta@86913f512c3c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone56.0a1
first release with
nightly linux32
1466b62da7b2 / 56.0a1 / 20170623100152 / files
nightly linux64
1466b62da7b2 / 56.0a1 / 20170623100152 / files
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
merge mozilla-inbound to mozilla-central a=merge
dom/base/nsNodeUtils.cpp
dom/canvas/WebGLShaderValidator.cpp
dom/ipc/ContentChild.cpp
dom/workers/RuntimeService.cpp
dom/xbl/nsXBLBinding.cpp
gfx/2d/convolver.cpp
gfx/2d/convolver.h
gfx/2d/convolverLS3.cpp
gfx/2d/convolverLS3.h
gfx/2d/convolverSSE2.cpp
gfx/2d/convolverSSE2.h
gfx/2d/image_operations.cpp
gfx/2d/image_operations.h
gfx/thebes/gfxPlatform.cpp
modules/libpref/init/all.js
uriloader/exthandler/nsExternalHelperAppService.cpp
--- a/accessible/atk/AccessibleWrap.cpp
+++ b/accessible/atk/AccessibleWrap.cpp
@@ -749,27 +749,18 @@ ConvertToAtkAttributeSet(nsIPersistentPr
     //libspi will free it
     return objAttributeSet;
 }
 
 AtkAttributeSet*
 GetAttributeSet(Accessible* aAccessible)
 {
   nsCOMPtr<nsIPersistentProperties> attributes = aAccessible->Attributes();
-  if (attributes) {
-    // There is no ATK state for haspopup, must use object attribute to expose
-    // the same info.
-    if (aAccessible->State() & states::HASPOPUP) {
-      nsAutoString unused;
-      attributes->SetStringProperty(NS_LITERAL_CSTRING("haspopup"),
-                                    NS_LITERAL_STRING("true"), unused);
-    }
-
+  if (attributes)
     return ConvertToAtkAttributeSet(attributes);
-  }
 
   return nullptr;
 }
 
 AtkAttributeSet *
 getAttributesCB(AtkObject *aAtkObj)
 {
   AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj);
--- a/accessible/base/DocManager.cpp
+++ b/accessible/base/DocManager.cpp
@@ -87,20 +87,20 @@ DocManager::FindAccessibleInCache(nsINod
 
 void
 DocManager::RemoveFromXPCDocumentCache(DocAccessible* aDocument)
 {
   xpcAccessibleDocument* xpcDoc = mXPCDocumentCache.GetWeak(aDocument);
   if (xpcDoc) {
     xpcDoc->Shutdown();
     mXPCDocumentCache.Remove(aDocument);
-  }
 
-  if (!HasXPCDocuments()) {
-    MaybeShutdownAccService(nsAccessibilityService::eXPCOM);
+    if (!HasXPCDocuments()) {
+      MaybeShutdownAccService(nsAccessibilityService::eXPCOM);
+    }
   }
 }
 
 void
 DocManager::NotifyOfDocumentShutdown(DocAccessible* aDocument,
                                      nsIDocument* aDOMDocument)
 {
   // We need to remove listeners in both cases, when document is being shutdown
--- a/accessible/base/Logging.cpp
+++ b/accessible/base/Logging.cpp
@@ -1021,17 +1021,17 @@ logging::IsEnabled(const nsAString& aMod
     if (aModuleStr.EqualsASCII(sModuleMap[idx].mStr))
       return sModules & sModuleMap[idx].mModule;
   }
 
   return false;
 }
 
 void
-logging::Enable(const nsAFlatCString& aModules)
+logging::Enable(const nsCString& aModules)
 {
   EnableLogging(aModules.get());
 }
 
 
 void
 logging::CheckEnv()
 {
--- a/accessible/base/Logging.h
+++ b/accessible/base/Logging.h
@@ -204,17 +204,17 @@ void DOMEvent(const char* aDescr, nsINod
 /**
  * Log the call stack, two spaces offset is used.
  */
 void Stack();
 
 /**
  * Enable logging of the specified modules, all other modules aren't logged.
  */
-void Enable(const nsAFlatCString& aModules);
+void Enable(const nsCString& aModules);
 
 /**
  * Enable logging of modules specified by A11YLOG environment variable,
  * all other modules aren't logged.
  */
 void CheckEnv();
 
 } // namespace logging
--- a/accessible/base/nsCoreUtils.cpp
+++ b/accessible/base/nsCoreUtils.cpp
@@ -628,19 +628,19 @@ nsCoreUtils::ScrollTo(nsIPresShell* aPre
 {
   nsIPresShell::ScrollAxis vertical, horizontal;
   ConvertScrollTypeToPercents(aScrollType, &vertical, &horizontal);
   aPresShell->ScrollContentIntoView(aContent, vertical, horizontal,
                                     nsIPresShell::SCROLL_OVERFLOW_HIDDEN);
 }
 
 bool
-nsCoreUtils::IsWhitespaceString(const nsSubstring& aString)
+nsCoreUtils::IsWhitespaceString(const nsAString& aString)
 {
-  nsSubstring::const_char_iterator iterBegin, iterEnd;
+  nsAString::const_char_iterator iterBegin, iterEnd;
 
   aString.BeginReading(iterBegin);
   aString.EndReading(iterEnd);
 
   while (iterBegin != iterEnd && IsWhitespace(*iterBegin))
     ++iterBegin;
 
   return iterBegin == iterEnd;
--- a/accessible/base/nsCoreUtils.h
+++ b/accessible/base/nsCoreUtils.h
@@ -294,17 +294,17 @@ public:
       aContent->HasAttr(kNameSpaceID_None, nsGkAtoms::scope);
   }
 
   /**
    * Returns true if the given string is empty or contains whitespace symbols
    * only. In contrast to nsWhitespaceTokenizer class it takes into account
    * non-breaking space (0xa0).
    */
-  static bool IsWhitespaceString(const nsSubstring& aString);
+  static bool IsWhitespaceString(const nsAString& aString);
 
   /**
    * Returns true if the given character is whitespace symbol.
    */
   static bool IsWhitespace(char16_t aChar)
   {
     return aChar == ' ' || aChar == '\n' ||
       aChar == '\r' || aChar == '\t' || aChar == 0xa0;
--- a/accessible/generic/Accessible.cpp
+++ b/accessible/generic/Accessible.cpp
@@ -940,16 +940,20 @@ Accessible::Attributes()
   while(attribIter.Next(name, value))
     attributes->SetStringProperty(NS_ConvertUTF16toUTF8(name), value, unused);
 
   if (IsARIAHidden()) {
     nsAccUtils::SetAccAttr(attributes, nsGkAtoms::hidden,
                            NS_LITERAL_STRING("true"));
   }
 
+  // XXX: In ARIA 1.1, the value of aria-haspopup became a token (bug 1355449).
+  if (aria::UniversalStatesFor(mContent->AsElement()) & states::HASPOPUP)
+    nsAccUtils::SetAccAttr(attributes, nsGkAtoms::haspopup, NS_LITERAL_STRING("true"));
+
   // If there is no aria-live attribute then expose default value of 'live'
   // object attribute used for ARIA role of this accessible.
   const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
   if (roleMapEntry) {
     if (roleMapEntry->Is(nsGkAtoms::searchbox)) {
       nsAccUtils::SetAccAttr(attributes, nsGkAtoms::textInputType,
                              NS_LITERAL_STRING("search"));
     }
--- a/accessible/tests/mochitest/attributes/test_obj.html
+++ b/accessible/tests/mochitest/attributes/test_obj.html
@@ -33,17 +33,19 @@ https://bugzilla.mozilla.org/show_bug.cg
       testAbsentAttrs("checkedMenuitem", {"checkable" : "true"}, true);
       testAttrs("checkedMenuitemCheckbox", {"checkable" : "true"}, true);
       testAttrs("checkedMenuitemRadio", {"checkable" : "true"}, true);
       testAttrs("checkedOption", {"checkable" : "true"}, true);
       testAttrs("checkedRadio", {"checkable" : "true"}, true);
       testAttrs("checkedTreeitem", {"checkable" : "true"}, true);
       testAttrs("dropeffect", {"dropeffect" : "copy"}, true);
       testAttrs("grabbed", {"grabbed" : "true"}, true);
-      testAbsentAttrs("haspopup", { "haspopup": "false" });
+      testAttrs("haspopupTrue", { "haspopup": "true" }, true);
+      testAbsentAttrs("haspopupFalse", { "haspopup": "false" });
+      testAbsentAttrs("haspopupEmpty", { "haspopup": "" });
       testAttrs("hidden", {"hidden" : "true"}, true);
       testAbsentAttrs("hidden_false", { "hidden": "false" });
       testAbsentAttrs("modal", {"modal" : "true"});
       testAttrs("sortAscending", {"sort" : "ascending"}, true);
       testAttrs("sortDescending", {"sort" : "descending"}, true);
       testAttrs("sortNone", {"sort" : "none"}, true);
       testAttrs("sortOther", {"sort" : "other"}, true);
       testAttrs("roledescr", {"roledescription" : "spreadshit"}, true);
@@ -209,17 +211,19 @@ https://bugzilla.mozilla.org/show_bug.cg
   <div id="checkedMenuitem" role="menuitem" aria-checked="true"></div>
   <div id="checkedMenuitemCheckbox" role="menuitemcheckbox" aria-checked="true"></div>
   <div id="checkedMenuitemRadio" role="menuitemradio" aria-checked="true"></div>
   <div id="checkedOption" role="option" aria-checked="true"></div>
   <div id="checkedRadio" role="radio" aria-checked="true"></div>
   <div id="checkedTreeitem" role="treeitem" aria-checked="true"></div>
   <div id="dropeffect" aria-dropeffect="copy"></div>
   <div id="grabbed" aria-grabbed="true"></div>
-  <div id="haspopup" aria-haspopup="true"></div>
+  <div id="haspopupTrue" aria-haspopup="true"></div>
+  <div id="haspopupFalse" aria-haspopup="false"></div>
+  <div id="haspopupEmpty" aria-haspopup=""></div>
   <div id="hidden" aria-hidden="true"></div>
   <div id="hidden_false" aria-hidden="false"></div>
   <div id="modal" aria-modal="true"></div>
   <div id="sortAscending" role="columnheader" aria-sort="ascending"></div>
   <div id="sortDescending" role="columnheader" aria-sort="descending"></div>
   <div id="sortNone" role="columnheader" aria-sort="none"></div>
   <div id="sortOther" role="columnheader" aria-sort="other"></div>
   <div id="roledescr" aria-roledescription="spreadshit"></div>
--- a/accessible/windows/msaa/LazyInstantiator.cpp
+++ b/accessible/windows/msaa/LazyInstantiator.cpp
@@ -87,20 +87,27 @@ LazyInstantiator::GetRootAccessible(HWND
     // HWND, so create a new one and return it as a surrogate for the root
     // accessible.
     result = new LazyInstantiator(aHwnd);
     return result.forget();
   }
 
   // a11y is running, so we just resolve the real root accessible.
   a11y::Accessible* rootAcc = widget::WinUtils::GetRootAccessibleForHWND(aHwnd);
-  if (!rootAcc || !rootAcc->IsRoot()) {
+  if (!rootAcc) {
     return nullptr;
   }
 
+  if (!rootAcc->IsRoot()) {
+    // rootAcc might represent a popup as opposed to a true root accessible.
+    // In that case we just use the regular Accessible::GetNativeInterface.
+    rootAcc->GetNativeInterface(getter_AddRefs(result));
+    return result.forget();
+  }
+
   // Subtle: rootAcc might still be wrapped by a LazyInstantiator, but we
   // don't need LazyInstantiator's capabilities anymore (since a11y is already
   // running). We can bypass LazyInstantiator by retrieving the internal
   // unknown (which is not wrapped by the LazyInstantiator) and then querying
   // that for IID_IAccessible.
   a11y::RootAccessibleWrap* rootWrap =
     static_cast<a11y::RootAccessibleWrap*>(rootAcc);
   RefPtr<IUnknown> punk(rootWrap->GetInternalUnknown());
--- a/browser/extensions/pdfjs/README.mozilla
+++ b/browser/extensions/pdfjs/README.mozilla
@@ -1,5 +1,5 @@
 This is the PDF.js project output, https://github.com/mozilla/pdf.js
 
-Current extension version is: 1.8.467
+Current extension version is: 1.8.480
 
-Taken from upstream commit: 679ffc84
+Taken from upstream commit: 2f2e539b
--- a/browser/extensions/pdfjs/content/build/pdf.js
+++ b/browser/extensions/pdfjs/content/build/pdf.js
@@ -3651,18 +3651,18 @@ var _UnsupportedManager = function Unsup
       for (var i = 0, ii = listeners.length; i < ii; i++) {
         listeners[i](featureId);
       }
     }
   };
 }();
 var version, build;
 {
-  exports.version = version = '1.8.467';
-  exports.build = build = '679ffc84';
+  exports.version = version = '1.8.480';
+  exports.build = build = '2f2e539b';
 }
 exports.getDocument = getDocument;
 exports.LoopbackPort = LoopbackPort;
 exports.PDFDataRangeTransport = PDFDataRangeTransport;
 exports.PDFWorker = PDFWorker;
 exports.PDFDocumentProxy = PDFDocumentProxy;
 exports.PDFPageProxy = PDFPageProxy;
 exports._UnsupportedManager = _UnsupportedManager;
@@ -4654,18 +4654,18 @@ var _text_layer = __w_pdfjs_require__(5)
 var _svg = __w_pdfjs_require__(4);
 
 var isWorker = typeof window === 'undefined';
 if (!_util.globalScope.PDFJS) {
   _util.globalScope.PDFJS = {};
 }
 var PDFJS = _util.globalScope.PDFJS;
 {
-  PDFJS.version = '1.8.467';
-  PDFJS.build = '679ffc84';
+  PDFJS.version = '1.8.480';
+  PDFJS.build = '2f2e539b';
 }
 PDFJS.pdfBug = false;
 if (PDFJS.verbosity !== undefined) {
   (0, _util.setVerbosityLevel)(PDFJS.verbosity);
 }
 delete PDFJS.verbosity;
 Object.defineProperty(PDFJS, 'verbosity', {
   get() {
@@ -10002,18 +10002,18 @@ exports.TilingPattern = TilingPattern;
 
 /***/ }),
 /* 14 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
-var pdfjsVersion = '1.8.467';
-var pdfjsBuild = '679ffc84';
+var pdfjsVersion = '1.8.480';
+var pdfjsBuild = '2f2e539b';
 var pdfjsSharedUtil = __w_pdfjs_require__(0);
 var pdfjsDisplayGlobal = __w_pdfjs_require__(8);
 var pdfjsDisplayAPI = __w_pdfjs_require__(3);
 var pdfjsDisplayTextLayer = __w_pdfjs_require__(5);
 var pdfjsDisplayAnnotationLayer = __w_pdfjs_require__(2);
 var pdfjsDisplayDOMUtils = __w_pdfjs_require__(1);
 var pdfjsDisplaySVG = __w_pdfjs_require__(4);
 exports.PDFJS = pdfjsDisplayGlobal.PDFJS;
--- a/browser/extensions/pdfjs/content/build/pdf.worker.js
+++ b/browser/extensions/pdfjs/content/build/pdf.worker.js
@@ -39771,18 +39771,18 @@ exports.Type1Parser = Type1Parser;
 
 /***/ }),
 /* 36 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
-var pdfjsVersion = '1.8.467';
-var pdfjsBuild = '679ffc84';
+var pdfjsVersion = '1.8.480';
+var pdfjsBuild = '2f2e539b';
 var pdfjsCoreWorker = __w_pdfjs_require__(17);
 ;
 exports.WorkerMessageHandler = pdfjsCoreWorker.WorkerMessageHandler;
 
 /***/ }),
 /* 37 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
--- a/browser/extensions/pdfjs/content/web/viewer.css
+++ b/browser/extensions/pdfjs/content/web/viewer.css
@@ -237,16 +237,20 @@
   border: none;
 }
 
 .pdfViewer .page canvas {
   margin: 0;
   display: block;
 }
 
+.pdfViewer .page canvas[hidden] {
+  display: none;
+}
+
 .pdfViewer .page .loadingIcon {
   position: absolute;
   display: block;
   left: 0;
   top: 0;
   right: 0;
   bottom: 0;
   background: url('images/loading-icon.gif') center no-repeat;
--- a/browser/extensions/pdfjs/content/web/viewer.js
+++ b/browser/extensions/pdfjs/content/web/viewer.js
@@ -869,17 +869,16 @@ var PDFViewerApplication = {
   store: null,
   downloadManager: null,
   overlayManager: null,
   preferences: null,
   toolbar: null,
   secondaryToolbar: null,
   eventBus: null,
   l10n: null,
-  pageRotation: 0,
   isInitialViewSet: false,
   downloadComplete: false,
   viewerPrefs: {
     sidebarViewOnLoad: _pdf_sidebar.SidebarView.NONE,
     pdfBugEnabled: false,
     showPreviousViewOnLoad: true,
     defaultZoomValue: '',
     disablePageLabels: false,
@@ -1095,16 +1094,19 @@ var PDFViewerApplication = {
       newScale = Math.floor(newScale * 10) / 10;
       newScale = Math.max(_ui_utils.MIN_SCALE, newScale);
     } while (--ticks > 0 && newScale > _ui_utils.MIN_SCALE);
     this.pdfViewer.currentScaleValue = newScale;
   },
   get pagesCount() {
     return this.pdfDocument ? this.pdfDocument.numPages : 0;
   },
+  get pageRotation() {
+    return this.pdfViewer.pagesRotation;
+  },
   set page(val) {
     this.pdfViewer.currentPageNumber = val;
   },
   get page() {
     return this.pdfViewer.currentPageNumber;
   },
   get printing() {
     return !!this.printService;
@@ -1201,17 +1203,16 @@ var PDFViewerApplication = {
     if (this.pdfDocument) {
       this.pdfDocument = null;
       this.pdfThumbnailViewer.setDocument(null);
       this.pdfViewer.setDocument(null);
       this.pdfLinkService.setDocument(null, null);
       this.pdfDocumentProperties.setDocument(null, null);
     }
     this.store = null;
-    this.pageRotation = 0;
     this.isInitialViewSet = false;
     this.downloadComplete = false;
     this.pdfSidebar.reset();
     this.pdfOutlineViewer.reset();
     this.pdfAttachmentViewer.reset();
     this.findController.reset();
     this.findBar.reset();
     this.toolbar.reset();
@@ -1618,22 +1619,23 @@ var PDFViewerApplication = {
       this.printService = null;
     }
     this.forceRendering();
   },
   rotatePages(delta) {
     if (!this.pdfDocument) {
       return;
     }
-    let pageNumber = this.page;
-    this.pageRotation = (this.pageRotation + 360 + delta) % 360;
-    this.pdfViewer.pagesRotation = this.pageRotation;
-    this.pdfThumbnailViewer.pagesRotation = this.pageRotation;
+    let { pdfViewer, pdfThumbnailViewer } = this;
+    let pageNumber = pdfViewer.currentPageNumber;
+    let newRotation = (pdfViewer.pagesRotation + 360 + delta) % 360;
+    pdfViewer.pagesRotation = newRotation;
+    pdfThumbnailViewer.pagesRotation = newRotation;
     this.forceRendering();
-    this.pdfViewer.currentPageNumber = pageNumber;
+    pdfViewer.currentPageNumber = pageNumber;
   },
   requestPresentationMode: function pdfViewRequestPresentationMode() {
     if (!this.pdfPresentationMode) {
       return;
     }
     this.pdfPresentationMode.request();
   },
   bindEvents() {
@@ -5019,17 +5021,17 @@ class PDFPageView {
         this.cssTransform(this.canvas, true);
         this.eventBus.dispatch('pagerendered', {
           source: this,
           pageNumber: this.id,
           cssTransform: true
         });
         return;
       }
-      if (!this.zoomLayer) {
+      if (!this.zoomLayer && !this.canvas.hasAttribute('hidden')) {
         this.zoomLayer = this.canvas.parentNode;
         this.zoomLayer.style.position = 'absolute';
       }
     }
     if (this.zoomLayer) {
       this.cssTransform(this.zoomLayer.firstChild);
     }
     this.reset(true, true);
@@ -7643,194 +7645,191 @@ exports.DefaultTextLayerFactory = Defaul
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 exports.Toolbar = undefined;
 
 var _ui_utils = __webpack_require__(0);
 
-var PAGE_NUMBER_LOADING_INDICATOR = 'visiblePageIsLoading';
-var SCALE_SELECT_CONTAINER_PADDING = 8;
-var SCALE_SELECT_PADDING = 22;
-var Toolbar = function ToolbarClosure() {
-  function Toolbar(options, mainContainer, eventBus, l10n = _ui_utils.NullL10n) {
+const PAGE_NUMBER_LOADING_INDICATOR = 'visiblePageIsLoading';
+const SCALE_SELECT_CONTAINER_PADDING = 8;
+const SCALE_SELECT_PADDING = 22;
+class Toolbar {
+  constructor(options, mainContainer, eventBus, l10n = _ui_utils.NullL10n) {
     this.toolbar = options.container;
     this.mainContainer = mainContainer;
     this.eventBus = eventBus;
     this.l10n = l10n;
     this.items = options;
     this._wasLocalized = false;
     this.reset();
     this._bindListeners();
   }
-  Toolbar.prototype = {
-    setPageNumber(pageNumber, pageLabel) {
-      this.pageNumber = pageNumber;
-      this.pageLabel = pageLabel;
-      this._updateUIState(false);
-    },
-    setPagesCount(pagesCount, hasPageLabels) {
-      this.pagesCount = pagesCount;
-      this.hasPageLabels = hasPageLabels;
-      this._updateUIState(true);
-    },
-    setPageScale(pageScaleValue, pageScale) {
-      this.pageScaleValue = pageScaleValue;
-      this.pageScale = pageScale;
-      this._updateUIState(false);
-    },
-    reset() {
-      this.pageNumber = 0;
-      this.pageLabel = null;
-      this.hasPageLabels = false;
-      this.pagesCount = 0;
-      this.pageScaleValue = _ui_utils.DEFAULT_SCALE_VALUE;
-      this.pageScale = _ui_utils.DEFAULT_SCALE;
-      this._updateUIState(true);
-    },
-    _bindListeners: function Toolbar_bindClickListeners() {
-      var eventBus = this.eventBus;
-      var self = this;
-      var items = this.items;
-      items.previous.addEventListener('click', function () {
-        eventBus.dispatch('previouspage');
+  setPageNumber(pageNumber, pageLabel) {
+    this.pageNumber = pageNumber;
+    this.pageLabel = pageLabel;
+    this._updateUIState(false);
+  }
+  setPagesCount(pagesCount, hasPageLabels) {
+    this.pagesCount = pagesCount;
+    this.hasPageLabels = hasPageLabels;
+    this._updateUIState(true);
+  }
+  setPageScale(pageScaleValue, pageScale) {
+    this.pageScaleValue = pageScaleValue;
+    this.pageScale = pageScale;
+    this._updateUIState(false);
+  }
+  reset() {
+    this.pageNumber = 0;
+    this.pageLabel = null;
+    this.hasPageLabels = false;
+    this.pagesCount = 0;
+    this.pageScaleValue = _ui_utils.DEFAULT_SCALE_VALUE;
+    this.pageScale = _ui_utils.DEFAULT_SCALE;
+    this._updateUIState(true);
+  }
+  _bindListeners() {
+    let eventBus = this.eventBus;
+    let self = this;
+    let items = this.items;
+    items.previous.addEventListener('click', function () {
+      eventBus.dispatch('previouspage');
+    });
+    items.next.addEventListener('click', function () {
+      eventBus.dispatch('nextpage');
+    });
+    items.zoomIn.addEventListener('click', function () {
+      eventBus.dispatch('zoomin');
+    });
+    items.zoomOut.addEventListener('click', function () {
+      eventBus.dispatch('zoomout');
+    });
+    items.pageNumber.addEventListener('click', function () {
+      this.select();
+    });
+    items.pageNumber.addEventListener('change', function () {
+      eventBus.dispatch('pagenumberchanged', {
+        source: self,
+        value: this.value
       });
-      items.next.addEventListener('click', function () {
-        eventBus.dispatch('nextpage');
-      });
-      items.zoomIn.addEventListener('click', function () {
-        eventBus.dispatch('zoomin');
-      });
-      items.zoomOut.addEventListener('click', function () {
-        eventBus.dispatch('zoomout');
-      });
-      items.pageNumber.addEventListener('click', function () {
-        this.select();
-      });
-      items.pageNumber.addEventListener('change', function () {
-        eventBus.dispatch('pagenumberchanged', {
-          source: self,
-          value: this.value
-        });
-      });
-      items.scaleSelect.addEventListener('change', function () {
-        if (this.value === 'custom') {
-          return;
-        }
-        eventBus.dispatch('scalechanged', {
-          source: self,
-          value: this.value
-        });
-      });
-      items.presentationModeButton.addEventListener('click', function (e) {
-        eventBus.dispatch('presentationmode');
+    });
+    items.scaleSelect.addEventListener('change', function () {
+      if (this.value === 'custom') {
+        return;
+      }
+      eventBus.dispatch('scalechanged', {
+        source: self,
+        value: this.value
       });
-      items.openFile.addEventListener('click', function (e) {
-        eventBus.dispatch('openfile');
-      });
-      items.print.addEventListener('click', function (e) {
-        eventBus.dispatch('print');
-      });
-      items.download.addEventListener('click', function (e) {
-        eventBus.dispatch('download');
-      });
-      items.scaleSelect.oncontextmenu = _ui_utils.noContextMenuHandler;
-      eventBus.on('localized', evt => {
-        this._localized();
+    });
+    items.presentationModeButton.addEventListener('click', function () {
+      eventBus.dispatch('presentationmode');
+    });
+    items.openFile.addEventListener('click', function () {
+      eventBus.dispatch('openfile');
+    });
+    items.print.addEventListener('click', function () {
+      eventBus.dispatch('print');
+    });
+    items.download.addEventListener('click', function () {
+      eventBus.dispatch('download');
+    });
+    items.scaleSelect.oncontextmenu = _ui_utils.noContextMenuHandler;
+    eventBus.on('localized', () => {
+      this._localized();
+    });
+  }
+  _localized() {
+    this._wasLocalized = true;
+    this._adjustScaleWidth();
+    this._updateUIState(true);
+  }
+  _updateUIState(resetNumPages = false) {
+    if (!this._wasLocalized) {
+      return;
+    }
+    let selectScaleOption = (value, scale) => {
+      let customScale = Math.round(scale * 10000) / 100;
+      this.l10n.get('page_scale_percent', { scale: customScale }, '{{scale}}%').then(msg => {
+        let options = items.scaleSelect.options;
+        let predefinedValueFound = false;
+        for (let i = 0, ii = options.length; i < ii; i++) {
+          let option = options[i];
+          if (option.value !== value) {
+            option.selected = false;
+            continue;
+          }
+          option.selected = true;
+          predefinedValueFound = true;
+        }
+        if (!predefinedValueFound) {
+          items.customScaleOption.textContent = msg;
+          items.customScaleOption.selected = true;
+        }
       });
-    },
-    _localized: function Toolbar_localized() {
-      this._wasLocalized = true;
-      this._adjustScaleWidth();
-      this._updateUIState(true);
-    },
-    _updateUIState: function Toolbar_updateUIState(resetNumPages) {
-      if (!this._wasLocalized) {
-        return;
-      }
-      let selectScaleOption = (value, scale) => {
-        let customScale = Math.round(scale * 10000) / 100;
-        this.l10n.get('page_scale_percent', { scale: customScale }, '{{scale}}%').then(msg => {
-          let options = items.scaleSelect.options;
-          let predefinedValueFound = false;
-          for (let i = 0, ii = options.length; i < ii; i++) {
-            let option = options[i];
-            if (option.value !== value) {
-              option.selected = false;
-              continue;
-            }
-            option.selected = true;
-            predefinedValueFound = true;
-          }
-          if (!predefinedValueFound) {
-            items.customScaleOption.textContent = msg;
-            items.customScaleOption.selected = true;
-          }
-        });
-      };
-      var pageNumber = this.pageNumber;
-      var scaleValue = (this.pageScaleValue || this.pageScale).toString();
-      var scale = this.pageScale;
-      var items = this.items;
-      var pagesCount = this.pagesCount;
-      if (resetNumPages) {
-        if (this.hasPageLabels) {
-          items.pageNumber.type = 'text';
-        } else {
-          items.pageNumber.type = 'number';
-          this.l10n.get('of_pages', { pagesCount }, 'of {{pagesCount}}').then(msg => {
-            items.numPages.textContent = msg;
-          });
-        }
-        items.pageNumber.max = pagesCount;
-      }
+    };
+    let pageNumber = this.pageNumber;
+    let scaleValue = (this.pageScaleValue || this.pageScale).toString();
+    let scale = this.pageScale;
+    let items = this.items;
+    let pagesCount = this.pagesCount;
+    if (resetNumPages) {
       if (this.hasPageLabels) {
-        items.pageNumber.value = this.pageLabel;
-        this.l10n.get('page_of_pages', {
-          pageNumber,
-          pagesCount
-        }, '({{pageNumber}} of {{pagesCount}})').then(msg => {
+        items.pageNumber.type = 'text';
+      } else {
+        items.pageNumber.type = 'number';
+        this.l10n.get('of_pages', { pagesCount }, 'of {{pagesCount}}').then(msg => {
           items.numPages.textContent = msg;
         });
-      } else {
-        items.pageNumber.value = pageNumber;
-      }
-      items.previous.disabled = pageNumber <= 1;
-      items.next.disabled = pageNumber >= pagesCount;
-      items.zoomOut.disabled = scale <= _ui_utils.MIN_SCALE;
-      items.zoomIn.disabled = scale >= _ui_utils.MAX_SCALE;
-      selectScaleOption(scaleValue, scale);
-    },
-    updateLoadingIndicatorState: function Toolbar_updateLoadingIndicatorState(loading) {
-      var pageNumberInput = this.items.pageNumber;
-      if (loading) {
-        pageNumberInput.classList.add(PAGE_NUMBER_LOADING_INDICATOR);
-      } else {
-        pageNumberInput.classList.remove(PAGE_NUMBER_LOADING_INDICATOR);
-      }
-    },
-    _adjustScaleWidth: function Toolbar_adjustScaleWidth() {
-      var container = this.items.scaleSelectContainer;
-      var select = this.items.scaleSelect;
-      _ui_utils.animationStarted.then(function () {
-        if (container.clientWidth === 0) {
-          container.setAttribute('style', 'display: inherit;');
-        }
-        if (container.clientWidth > 0) {
-          select.setAttribute('style', 'min-width: inherit;');
-          var width = select.clientWidth + SCALE_SELECT_CONTAINER_PADDING;
-          select.setAttribute('style', 'min-width: ' + (width + SCALE_SELECT_PADDING) + 'px;');
-          container.setAttribute('style', 'min-width: ' + width + 'px; ' + 'max-width: ' + width + 'px;');
-        }
+      }
+      items.pageNumber.max = pagesCount;
+    }
+    if (this.hasPageLabels) {
+      items.pageNumber.value = this.pageLabel;
+      this.l10n.get('page_of_pages', {
+        pageNumber,
+        pagesCount
+      }, '({{pageNumber}} of {{pagesCount}})').then(msg => {
+        items.numPages.textContent = msg;
       });
-    }
-  };
-  return Toolbar;
-}();
+    } else {
+      items.pageNumber.value = pageNumber;
+    }
+    items.previous.disabled = pageNumber <= 1;
+    items.next.disabled = pageNumber >= pagesCount;
+    items.zoomOut.disabled = scale <= _ui_utils.MIN_SCALE;
+    items.zoomIn.disabled = scale >= _ui_utils.MAX_SCALE;
+    selectScaleOption(scaleValue, scale);
+  }
+  updateLoadingIndicatorState(loading = false) {
+    let pageNumberInput = this.items.pageNumber;
+    if (loading) {
+      pageNumberInput.classList.add(PAGE_NUMBER_LOADING_INDICATOR);
+    } else {
+      pageNumberInput.classList.remove(PAGE_NUMBER_LOADING_INDICATOR);
+    }
+  }
+  _adjustScaleWidth() {
+    let container = this.items.scaleSelectContainer;
+    let select = this.items.scaleSelect;
+    _ui_utils.animationStarted.then(function () {
+      if (container.clientWidth === 0) {
+        container.setAttribute('style', 'display: inherit;');
+      }
+      if (container.clientWidth > 0) {
+        select.setAttribute('style', 'min-width: inherit;');
+        let width = select.clientWidth + SCALE_SELECT_CONTAINER_PADDING;
+        select.setAttribute('style', 'min-width: ' + (width + SCALE_SELECT_PADDING) + 'px;');
+        container.setAttribute('style', 'min-width: ' + width + 'px; ' + 'max-width: ' + width + 'px;');
+      }
+    });
+  }
+}
 exports.Toolbar = Toolbar;
 
 /***/ }),
 /* 30 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
--- a/caps/tests/mochitest/chrome.ini
+++ b/caps/tests/mochitest/chrome.ini
@@ -1,9 +1,11 @@
 [DEFAULT]
 skip-if = os == 'android'
 support-files =
+  file_data.txt
   file_disableScript.html
+  !/caps/tests/mochitest/file_data.txt
   !/caps/tests/mochitest/file_disableScript.html
 
 [test_bug995943.xul]
 [test_addonMayLoad.html]
 [test_disableScript.xul]
--- a/devtools/client/debugger/new/debugger.css
+++ b/devtools/client/debugger/new/debugger.css
@@ -351,23 +351,21 @@ body {
 ::-webkit-scrollbar-thumb {
   border-radius: 8px;
   background: rgba(113, 113, 113, 0.5);
 }
 
 :root.theme-dark .CodeMirror-scrollbar-filler {
   background: transparent;
 }
-:root.theme-light,
-:root .theme-light {
+:root.theme-light, :root .theme-light {
   --search-overlays-semitransparent: rgba(221, 225, 228, 0.66);
 }
 
-:root.theme-dark,
-:root .theme-dark {
+:root.theme-dark, :root .theme-dark {
   --search-overlays-semitransparent: rgba(42, 46, 56, 0.66);
 }
 .debugger {
   display: flex;
   flex: 1;
   height: 100%;
 }
 
@@ -458,18 +456,17 @@ menuseparator {
   height: 100%;
   z-index: 999;
 }
 /* vim:set ts=2 sw=2 sts=2 et: */
 /* 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/. */
 
-.theme-dark,
-.theme-light {
+.theme-dark, .theme-light {
   --number-color: var(--theme-highlight-green);
   --string-color: var(--theme-highlight-orange);
   --null-color: var(--theme-comment);
   --object-color: var(--theme-body-color);
   --caption-color: var(--theme-highlight-blue);
   --location-color: var(--theme-content-color1);
   --source-link-color: var(--theme-highlight-blue);
   --node-color: var(--theme-highlight-bluegrey);
@@ -501,50 +498,42 @@ menuseparator {
 }
 
 .objectBox-object {
   font-weight: bold;
   color: var(--object-color);
   white-space: pre-wrap;
 }
 
-.objectBox-string,
-.objectBox-text,
-.objectLink-textNode,
-.objectBox-table {
+.objectBox-string, .objectBox-text, .objectLink-textNode, .objectBox-table {
   white-space: pre-wrap;
 }
 
 .objectBox-number,
 .objectLink-styleRule,
 .objectLink-element,
 .objectLink-textNode,
 .objectBox-array > .length {
   color: var(--number-color);
 }
 
 .objectBox-string {
   color: var(--string-color);
 }
 
-.objectLink-function,
-.objectBox-stackTrace,
-.objectLink-profile {
+.objectLink-function, .objectBox-stackTrace, .objectLink-profile {
   color: var(--object-color);
 }
 
 .objectLink-Location {
   font-style: italic;
   color: var(--location-color);
 }
 
-.objectBox-null,
-.objectBox-undefined,
-.objectBox-hint,
-.logRowHint {
+.objectBox-null, .objectBox-undefined, .objectBox-hint, .logRowHint {
   font-style: italic;
   color: var(--null-color);
 }
 
 .objectLink-sourceLink {
   position: absolute;
   right: 4px;
   top: 2px;
@@ -578,31 +567,26 @@ menuseparator {
 }
 
 .objectLink-object .nodeName {
   font-weight: normal;
 }
 
 /******************************************************************************/
 
-.objectLeftBrace,
-.objectRightBrace,
-.arrayLeftBracket,
-.arrayRightBracket {
+.objectLeftBrace, .objectRightBrace, .arrayLeftBracket, .arrayRightBracket {
   cursor: pointer;
   font-weight: bold;
 }
 
-.objectLeftBrace,
-.arrayLeftBracket {
+.objectLeftBrace, .arrayLeftBracket {
   margin-right: 4px;
 }
 
-.objectRightBrace,
-.arrayRightBracket {
+.objectRightBrace, .arrayRightBracket {
   margin-left: 4px;
 }
 
 /******************************************************************************/
 /* Cycle reference*/
 
 .objectLink-Reference {
   font-weight: bold;
@@ -611,37 +595,35 @@ menuseparator {
 
 .objectBox-array > .objectTitle {
   font-weight: bold;
   color: var(--object-color);
 }
 
 .caption {
   font-weight: bold;
-  color:  var(--caption-color);
+  color: var(--caption-color);
 }
 
 /******************************************************************************/
 /* Themes */
 
 .theme-dark .objectBox-null,
 .theme-dark .objectBox-undefined,
 .theme-light .objectBox-null,
 .theme-light .objectBox-undefined {
   font-style: normal;
 }
 
-.theme-dark .objectBox-object,
-.theme-light .objectBox-object {
+.theme-dark .objectBox-object, .theme-light .objectBox-object {
   font-weight: normal;
   white-space: pre-wrap;
 }
 
-.theme-dark .caption,
-.theme-light .caption {
+.theme-dark .caption, .theme-light .caption {
   font-weight: normal;
 }
 /* vim:set ts=2 sw=2 sts=2 et: */
 /* 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/. */
 
 .split-box {
@@ -722,17 +704,16 @@ menuseparator {
  * Make sure splitter panels are not processing any mouse
  * events. This is good for performance during splitter
  * bar dragging.
  */
 .split-box.dragging > .controlled,
 .split-box.dragging > .uncontrolled {
   pointer-events: none;
 }
-
 .search-container {
   position: absolute;
   top: 30px;
   left: 0;
   width: calc(100% - 1px);
   height: calc(100% - 31px);
   display: flex;
   z-index: 200;
@@ -742,59 +723,39 @@ menuseparator {
 .searchinput-container {
   display: flex;
   border-bottom: 1px solid var(--theme-splitter-color);
 }
 
 .theme-dark .result-list li .subtitle {
   color: var(--theme-comment-alt);
 }
-
-.arrow,
-.folder,
-.domain,
-.file,
-.worker,
-.refresh,
-.add-button {
+.arrow, .folder, .domain, .file, .worker, .refresh, .add-button {
   fill: var(--theme-splitter-color);
 }
 
-.worker,
-.folder {
+.worker, .folder {
   position: relative;
   top: 2px;
 }
 
-.domain,
-.file,
-.worker,
-.refresh,
-.add-button {
+.domain, .file, .worker, .refresh, .add-button {
   position: relative;
   top: 1px;
 }
 
-.domain svg,
-.folder svg,
-.worker svg,
-.refresh svg,
-.add-button svg {
+.domain svg, .folder svg, .worker svg, .refresh svg, .add-button svg {
   width: 15px;
 }
 
 .file svg {
   width: 13px;
 }
 
-.file svg,
-.domain svg,
-.folder svg,
-.refresh svg,
-.worker svg {
+.file svg, .domain svg, .folder svg, .refresh svg, .worker svg {
   margin-inline-end: 5px;
 }
 
 .arrow svg {
   fill: var(--theme-splitter-color);
   margin-top: 3px;
   transition: transform 0.25s ease;
   width: 10px;
@@ -813,17 +774,16 @@ html[dir="rtl"] .arrow svg {
 /* TODO (Amit): html is just for specificity. keep it like this? */
 html .arrow.expanded svg {
   transform: rotate(0deg);
 }
 
 .arrow.hidden {
   visibility: hidden;
 }
-
 .autocomplete {
   flex: 1;
   width: 100%;
 }
 
 .autocomplete .no-result-msg {
   display: flex;
   align-items: center;
@@ -889,17 +849,16 @@ html .arrow.expanded svg {
 .close-btn.big .close {
   width: 16px;
   height: 16px;
 }
 
 .close-btn.big .close svg {
   width: 9px;
 }
-
 .search-field {
   width: calc(100% - 1px);
   height: 27px;
   background-color: var(--theme-toolbar-background);
   border-bottom: 1px solid var(--theme-splitter-color);
   padding-right: 10px;
   display: flex;
   flex-shrink: 0;
@@ -931,30 +890,27 @@ html .arrow.expanded svg {
   width: calc(100% - 38px);
   flex: 1;
 }
 
 .theme-dark .search-field input {
   color: var(--theme-body-color-inactive);
 }
 
-.search-field i.magnifying-glass,
-.search-field i.sad-face {
+.search-field i.magnifying-glass, .search-field i.sad-face {
   padding: 6px;
   width: 24px;
 }
 
-.search-field.big i.magnifying-glass,
-.search-field.big i.sad-face {
+.search-field.big i.magnifying-glass, .search-field.big i.sad-face {
   padding: 14px;
   width: 40px;
 }
 
-.search-field .magnifying-glass path,
-.search-field .magnifying-glass ellipse {
+.search-field .magnifying-glass path, .search-field .magnifying-glass ellipse {
   stroke: var(--theme-splitter-color);
 }
 
 .search-field input::placeholder {
   color: var(--theme-body-color-inactive);
 }
 
 .search-field input:focus {
@@ -1127,16 +1083,20 @@ html[dir="rtl"] .tree .node > div {
 
 .tree .node.focused svg {
   fill: white;
 }
 
 .tree-node button {
   position: fixed;
 }
+.project-text-search {
+  flex-grow: 1;
+}
+
 .project-text-search .result {
   display: flex;
   margin-left: 20px;
 }
 
 .project-text-search .file-result {
   font-weight: bold;
   margin-top: 20px;
@@ -1147,16 +1107,22 @@ html[dir="rtl"] .tree .node > div {
   font-family: monospace;
   display: "flex";
   grow: 1;
 }
 
 .project-text-search .result .line-number {
   padding-right: 5px;
 }
+
+.project-text-search .search-field {
+  display: flex;
+  align-self: stretch;
+  flex-grow: 1;
+}
 .sources-panel {
   flex: 1;
   display: flex;
   flex-direction: column;
   overflow: hidden;
   position: relative;
 }
 
@@ -1262,29 +1228,35 @@ html[dir="rtl"] .tree .node > div {
 
 .source-footer .tab.active {
   color: var(--theme-body-color);
   background-color: var(--theme-body-background);
   border-color: var(--theme-splitter-color);
   border-top-color: transparent;
 }
 
-.source-footer .tab.active path,
-.source-footer .tab:hover path {
+.source-footer .tab.active path, .source-footer .tab:hover path {
   fill: var(--theme-body-color);
 }
 .outline-list {
-  list-style-type: "-";
+  list-style-type: none;
+  padding-left: 0px;
+  width: 100%;
 }
 
 .outline-list__element {
   color: blue;
-  padding-left: 0.5rem;
-}
-
+  padding-left: 1rem;
+  padding-right: 0.5rem;
+  cursor: pointer;
+}
+
+.outline-list__element:hover {
+  background: var(--theme-toolbar-background-hover);
+}
 .function-signature {
   line-height: 20px;
   align-self: center;
 }
 
 .function-signature .function-name {
   color: var(--theme-highlight-blue);
 }
@@ -1329,37 +1301,33 @@ html[dir="rtl"] .tree .node > div {
   font-size: 14px;
   color: var(--theme-conditional-breakpoint-color);
   line-height: 30px;
 }
 
 .conditional-breakpoint-panel input:focus {
   outline-width: 0;
 }
-.toggle-button-start,
-.toggle-button-end {
+.toggle-button-start, .toggle-button-end {
   transform: translate(0, 2px);
   transition: transform 0.25s ease-in-out;
   cursor: pointer;
   padding: 5px 2px;
 }
 
-.toggle-button-start.vertical,
-.toggle-button-end.vertical {
+.toggle-button-start.vertical, .toggle-button-end.vertical {
   padding: 4px 2px;
 }
 
-.toggle-button-start svg,
-.toggle-button-end svg {
+.toggle-button-start svg, .toggle-button-end svg {
   width: 16px;
   fill: var(--theme-comment);
 }
 
-.theme-dark .toggle-button-start svg,
-.theme-dark .toggle-button-end svg {
+.theme-dark .toggle-button-start svg, .theme-dark .toggle-button-end svg {
   fill: var(--theme-comment-alt);
 }
 
 .toggle-button-end {
   margin-inline-end: 5px;
   margin-inline-start: auto;
 }
 
@@ -1371,18 +1339,17 @@ html:not([dir="rtl"]) .toggle-button-end
 html[dir="rtl"] .toggle-button-start svg {
   transform: rotate(180deg);
 }
 
 html .toggle-button-end.vertical svg {
   transform: rotate(-90deg);
 }
 
-.toggle-button-start.collapsed,
-.toggle-button-end.collapsed {
+.toggle-button-start.collapsed, .toggle-button-end.collapsed {
   transform: rotate(180deg);
 }
 .source-footer {
   background: var(--theme-toolbar-background);
   border-top: 1px solid var(--theme-splitter-color);
   position: absolute;
   display: flex;
   bottom: 0;
@@ -1585,18 +1552,17 @@ html .toggle-button-end.vertical svg {
 }
 .object-value .unavailable {
   color: var(--theme-comment);
 }
 .bracket-arrow {
   position: absolute;
 }
 
-.bracket-arrow::before,
-.bracket-arrow::after {
+.bracket-arrow::before, .bracket-arrow::after {
   content: '';
   height: 0;
   width: 0;
   position: absolute;
   border: 7px solid transparent;
 }
 
 .bracket-arrow.up::before {
@@ -1744,17 +1710,16 @@ html .toggle-button-end.vertical svg {
   color: var(--theme-comment);
   cursor: pointer;
 }
 .editor-wrapper {
   --debug-line-background: rgba(226, 236, 247, 0.5);
   --debug-line-border: rgb(145, 188, 219);
   --editor-searchbar-height: 27px;
   --editor-second-searchbar-height: 27px;
-
 }
 
 .theme-dark .editor-wrapper {
   --debug-line-background: rgb(73, 82, 103);
   --debug-line-border: rgb(119, 134, 162);
 }
 
 .editor-wrapper .CodeMirror-linewidget {
@@ -1764,19 +1729,22 @@ html .toggle-button-end.vertical svg {
 .theme-dark {
   --theme-conditional-breakpoint-color: #9fa4a9;
 }
 
 .theme-light {
   --theme-conditional-breakpoint-color: #ccd1d5;
 }
 
-.out-of-scope .CodeMirror-line,
-.out-of-scope .CodeMirror-linenumber {
-  opacity: 0.8;
+.paused .in-scope .CodeMirror-line, .paused .in-scope .CodeMirror-linenumber {
+  opacity: 1;
+}
+
+.paused .CodeMirror-line, .paused .CodeMirror-linenumber {
+  opacity: 0.7;
 }
 
 /**
  * There's a known codemirror flex issue with chrome that this addresses.
  * BUG https://github.com/devtools-html/debugger.html/issues/63
  */
 .editor-wrapper {
   position: absolute;
@@ -1919,27 +1887,35 @@ html[dir="rtl"] .editor-mount {
   display: none;
 }
 
 .highlight-line .CodeMirror-line {
   animation: fade-highlight-out 1.5s normal forwards;
 }
 
 @keyframes fade-highlight-out {
-  0% { background-color: var(--theme-highlight-gray); }
-  100% { background-color: transparent; }
+  0% {
+    background-color: var(--theme-highlight-gray);
+  }
+  100% {
+    background-color: transparent;
+  }
 }
 
 .theme-dark .highlight-line .CodeMirror-line {
   animation: fade-highlight-out-dark 1.5s normal forwards;
 }
 
 @keyframes fade-highlight-out-dark {
-  0% { background-color: var(--theme-content-color3); }
-  100% { background-color: transparent; }
+  0% {
+    background-color: var(--theme-content-color3);
+  }
+  100% {
+    background-color: transparent;
+  }
 }
 
 .welcomebox {
   width: calc(100% - 1px);
 
   /* Offsetting it by 30px for the sources-header area */
   height: calc(100% - 30px);
   position: absolute;
@@ -2072,18 +2048,17 @@ html .breakpoints-list .breakpoint.pause
   padding-bottom: 4px;
 }
 
 .breakpoints-list .pause-indicator {
   flex: 0 1 content;
   order: 3;
 }
 
-:root.theme-light .breakpoint-snippet,
-:root.theme-firebug .breakpoint-snippet {
+:root.theme-light .breakpoint-snippet, :root.theme-firebug .breakpoint-snippet {
   color: var(--theme-comment);
 }
 
 :root.theme-dark .breakpoint-snippet {
   color: var(--theme-body-color);
   opacity: 0.6;
 }
 
@@ -2186,18 +2161,17 @@ html .breakpoints-list .breakpoint.pause
   overflow-x: scroll;
   color: var(--theme-content-color2);
   max-width: 50% !important;
 }
 
 .expression-error {
   color: var(--theme-highlight-red);
 }
-.frames ul .frames-group .group,
-.frames ul .frames-group .group .location {
+.frames ul .frames-group .group, .frames ul .frames-group .group .location {
   font-weight: 500;
 }
 
 .frames ul .frames-group.expanded .group,
 .frames ul .frames-group.expanded .group .location {
   color: var(--theme-highlight-blue);
 }
 
@@ -2208,17 +2182,16 @@ html .breakpoints-list .breakpoint.pause
 .frames ul .frames-group .frames-list li {
   padding-left: 30px;
 }
 
 .frames ul .frames-group .frames-list {
   border-top: 1px solid var(--theme-splitter-color);
   border-bottom: 1px solid var(--theme-splitter-color);
 }
-
 .why-paused {
   background-color: var(--theme-body-background);
   color: var(--theme-body-color);
   padding: 10px 10px 10px 20px;
   white-space: normal;
   opacity: 0.6;
   font-size: 12px;
   flex: 0 1 auto;
@@ -2274,40 +2247,37 @@ html .breakpoints-list .breakpoint.pause
   font-weight: lighter;
   display: flex;
   justify-content: space-between;
   flex-direction: row;
   align-items: center;
   margin: 0;
 }
 
-:root.theme-light .frames .location,
-:root.theme-firebug .frames .location {
+:root.theme-light .frames .location, :root.theme-firebug .frames .location {
   color: var(--theme-comment);
 }
 
 :root.theme-dark .frames .location {
   color: var(--theme-body-color);
   opacity: 0.6;
 }
 
 .frames .title {
   text-overflow: ellipsis;
   overflow: hidden;
   margin-right: 1em;
 }
 
-.frames ul li:hover,
-.frames ul li:focus {
+.frames ul li:hover, .frames ul li:focus {
   background-color: var(--theme-toolbar-background-alt);
   outline: none;
 }
 
-.theme-dark .frames ul li:hover,
-.theme-dark .frames ul li:focus {
+.theme-dark .frames ul li:hover, .theme-dark .frames ul li:focus {
   background-color: var(--theme-tab-toolbar-background);
 }
 
 .frames ul li.selected {
   background-color: var(--theme-selection-background);
   color: white;
 }
 
@@ -2419,18 +2389,17 @@ html .breakpoints-list .breakpoint.pause
 .accordion ._header {
   display: flex;
 }
 
 .accordion ._header:hover {
   background-color: var(--theme-toolbar-background-hover);
 }
 
-.accordion ._header button svg,
-.accordion ._header:hover button svg {
+.accordion ._header button svg, .accordion ._header:hover button svg {
   fill: currentColor;
   height: 16px;
 }
 
 .accordion ._content {
   border-bottom: 1px solid var(--theme-splitter-color);
   font-size: 12px;
 }
@@ -2484,17 +2453,16 @@ html[dir="rtl"] .command-bar {
   -webkit-appearance: none;
   -moz-appearance: none;
   appearance: none;
   background: transparent;
   border: none;
   cursor: pointer;
   display: inline-block;
   text-align: center;
-  transition: all 0.25s ease;
   padding: 8px 5px;
   position: relative;
   fill: currentColor;
 }
 
 .command-bar > button:hover {
   background: var(--theme-toolbar-background-hover);
 }
@@ -2502,18 +2470,22 @@ html[dir="rtl"] .command-bar {
 :root.theme-dark .command-bar > button {
   color: var(--theme-body-color);
 }
 
 .command-bar > button {
   margin-inline-end: 0.7em;
 }
 
+.command-bar > button:focus {
+  outline: none;
+}
+
 html .command-bar > button:disabled {
-  opacity: 0.3;
+  opacity: 0.8;
   cursor: default;
 }
 
 .command-bar > button > i {
   height: 100%;
   width: 100%;
   display: block;
 }
@@ -2533,17 +2505,16 @@ html .command-bar > button:disabled {
 
 .command-bar button.pause-exceptions.uncaught {
   color: var(--theme-highlight-purple);
 }
 
 .command-bar button.pause-exceptions.all {
   color: var(--theme-highlight-blue);
 }
-
 .object-node.default-property {
   opacity: 0.6;
 }
 
 .object-label {
   color: var(--theme-highlight-blue);
 }
 
@@ -2684,36 +2655,34 @@ html .welcomebox .toggle-button-end.coll
 
 .source-tab.active {
   color: var(--theme-body-color);
   background-color: var(--theme-body-background);
   border-color: var(--theme-splitter-color);
   border-bottom-color: transparent;
 }
 
-.source-tab.active path,
-.source-tab:hover path {
+.source-tab.active path, .source-tab:hover path {
   fill: var(--theme-body-color);
 }
 
 .source-tab .prettyPrint {
   line-height: 0;
 }
 
 .source-tab .prettyPrint svg {
   height: 12px;
   width: 12px;
 }
 
 .source-tab .prettyPrint path {
   fill: var(--theme-textbox-box-shadow);
 }
 
-.source-tab .blackBox,
-.source-tab .prettyPrint {
+.source-tab .blackBox, .source-tab .prettyPrint {
   line-height: 0;
   align-self: center;
 }
 
 .source-tab .blackBox svg {
   height: 12px;
   width: 12px;
 }
--- a/devtools/client/debugger/new/debugger.js
+++ b/devtools/client/debugger/new/debugger.js
@@ -13393,34 +13393,34 @@ return /******/ (function(modules) { // 
 /* 226 */
 /***/ function(module, exports, __webpack_require__) {
 
 	// @flow
 
 	const { isDevelopment } = __webpack_require__(828);
 	const { Services, PrefsHelper } = __webpack_require__(830);
 
-	const prefsSchemaVersion = "1.0.0";
+	const prefsSchemaVersion = "1.0.1";
 
 	const pref = Services.pref;
 
 	if (isDevelopment()) {
 	  pref("devtools.debugger.client-source-maps-enabled", true);
 	  pref("devtools.debugger.pause-on-exceptions", false);
 	  pref("devtools.debugger.ignore-caught-exceptions", false);
 	  pref("devtools.debugger.call-stack-visible", false);
 	  pref("devtools.debugger.scopes-visible", false);
 	  pref("devtools.debugger.start-panel-collapsed", false);
 	  pref("devtools.debugger.end-panel-collapsed", false);
 	  pref("devtools.debugger.tabs", "[]");
 	  pref("devtools.debugger.ui.framework-grouping-on", true);
 	  pref("devtools.debugger.pending-selected-location", "{}");
-	  pref("devtools.debugger.pending-breakpoints", "[]");
+	  pref("devtools.debugger.pending-breakpoints", "{}");
 	  pref("devtools.debugger.expressions", "[]");
-	  pref("devtools.debugger.file-search-case-sensitive", true);
+	  pref("devtools.debugger.file-search-case-sensitive", false);
 	  pref("devtools.debugger.file-search-whole-word", false);
 	  pref("devtools.debugger.file-search-regex-match", false);
 	  pref("devtools.debugger.prefs-schema-version", "1.0.0");
 	}
 
 	const prefs = new PrefsHelper("devtools", {
 	  clientSourceMapsEnabled: ["Bool", "debugger.client-source-maps-enabled"],
 	  pauseOnExceptions: ["Bool", "debugger.pause-on-exceptions"],
@@ -13437,17 +13437,17 @@ return /******/ (function(modules) { // 
 	  fileSearchCaseSensitive: ["Bool", "debugger.file-search-case-sensitive"],
 	  fileSearchWholeWord: ["Bool", "debugger.file-search-whole-word"],
 	  fileSearchRegexMatch: ["Bool", "debugger.file-search-regex-match"],
 	  debuggerPrefsSchemaVersion: ["Char", "debugger.prefs-schema-version"]
 	});
 
 	if (prefs.debuggerPrefsSchemaVersion !== prefsSchemaVersion) {
 	  // clear pending Breakpoints
-	  prefs.pendingBreakpoints = [];
+	  prefs.pendingBreakpoints = {};
 	  prefs.debuggerPrefsSchemaVersion = prefsSchemaVersion;
 	}
 
 	module.exports = { prefs };
 
 
 /***/ },
 /* 227 */
@@ -13731,17 +13731,16 @@ return /******/ (function(modules) { // 
 	  value: true
 	});
 	exports.getSelectedSourceText = exports.getSelectedSource = exports.getSelectedLocation = exports.getSourcesForTabs = exports.getSourceTabs = exports.getSources = exports.State = undefined;
 	exports.removeSourceFromTabList = removeSourceFromTabList;
 	exports.removeSourcesFromTabList = removeSourcesFromTabList;
 	exports.getNewSelectedSourceId = getNewSelectedSourceId;
 	exports.getSource = getSource;
 	exports.getSourceByURL = getSourceByURL;
-	exports.getSourceText = getSourceText;
 	exports.getPendingSelectedLocation = getPendingSelectedLocation;
 	exports.getPrettySource = getPrettySource;
 	exports.getSourceInSources = getSourceInSources;
 
 	var _immutable = __webpack_require__(146);
 
 	var I = _interopRequireWildcard(_immutable);
 
@@ -13882,20 +13881,18 @@ return /******/ (function(modules) { // 
 	  };
 	}
 
 	// TODO: Action is coerced to `any` unfortunately because how we type
 	// asynchronous actions is wrong. The `value` may be null for the
 	// "start" and "error" states but we don't type it like that. We need
 	// to rethink how we type async actions.
 	function setSourceTextProps(state, action) {
-	  var source = action.source;
 	  var text = getTextPropsFromAction(action);
-	  var updatedState = state.setIn(["sourcesText", source.id], I.Map(text));
-	  return updateSource(updatedState, text);
+	  return updateSource(state, text);
 	}
 
 	function updateSource(state, source) {
 	  if (!source.id) {
 	    return state;
 	  }
 
 	  return state.mergeIn(["sources", source.id], source);
@@ -14005,22 +14002,16 @@ return /******/ (function(modules) { // 
 	function getSource(state, id) {
 	  return getSourceInSources(getSources(state), id);
 	}
 
 	function getSourceByURL(state, url) {
 	  return getSourceByUrlInSources(state.sources.sources, url);
 	}
 
-	function getSourceText(state, id) {
-	  if (id) {
-	    return state.sources.sourcesText.get(id);
-	  }
-	}
-
 	function getPendingSelectedLocation(state) {
 	  return state.sources.pendingSelectedLocation;
 	}
 
 	function getPrettySource(state, id) {
 	  var source = getSource(state, id);
 	  if (!source) {
 	    return;
@@ -14189,40 +14180,45 @@ return /******/ (function(modules) { // 
 	 *
 	 * Returns Code Mirror mode for source content type
 	 * @param contentType
 	 * @return String
 	 * @memberof utils/source
 	 * @static
 	 */
 
-	function getMode(sourceText) {
-	  var contentType = sourceText.contentType,
-	      text = sourceText.text;
+	function getMode(source) {
+	  if (!source.text) {
+	    return { name: "text" };
+	  }
+
+	  if (!source.contentType) {
+	    // Use HTML mode for files in which the first non whitespace
+	    // character is `<` regardless of extension.
+	    var name = source.text.match(/^\s*</) ? "htmlmixed" : "text";
+	    return { name };
+	  }
+
+	  var contentType = source.contentType,
+	      text = source.text;
 
 	  // //  or /*  */
 
 	  if (text.match(/^\s*(\/\/ @flow|\/\* @flow \*\/)/)) {
 	    return contentTypeModeMap["text/typescript"];
 	  }
 
 	  if (/script|elm|jsx|clojure|wasm/.test(contentType)) {
 	    if (contentType in contentTypeModeMap) {
 	      return contentTypeModeMap[contentType];
 	    }
 
 	    return contentTypeModeMap["text/javascript"];
 	  }
 
-	  // Use HTML mode for files in which the first non whitespace
-	  // character is `<` regardless of extension.
-	  if (text.match(/^\s*</)) {
-	    return { name: "htmlmixed" };
-	  }
-
 	  return { name: "text" };
 	}
 
 	exports.isJavaScript = isJavaScript;
 	exports.isPretty = isPretty;
 	exports.getPrettySourceURL = getPrettySourceURL;
 	exports.getRawSourceURL = getRawSourceURL;
 	exports.getFilename = getFilename;
@@ -15444,17 +15440,16 @@ return /******/ (function(modules) { // 
 	module.exports = {
 	  getSource: sources.getSource,
 	  getNewSelectedSourceId: sources.getNewSelectedSourceId,
 	  removeSourceFromTabList: sources.removeSourceFromTabList,
 	  removeSourcesFromTabList: sources.removeSourcesFromTabList,
 	  getSourceByURL: sources.getSourceByURL,
 	  getSourceInSources: sources.getSourceInSources,
 	  getSources: sources.getSources,
-	  getSourceText: sources.getSourceText,
 	  getSourceTabs: sources.getSourceTabs,
 	  getSourcesForTabs: sources.getSourcesForTabs,
 	  getSelectedSource: sources.getSelectedSource,
 	  getSelectedSourceText: sources.getSelectedSourceText,
 	  getSelectedLocation: sources.getSelectedLocation,
 	  getPendingSelectedLocation: sources.getPendingSelectedLocation,
 	  getPrettySource: sources.getPrettySource,
 
@@ -17240,39 +17235,34 @@ return /******/ (function(modules) { // 
 	function togglePrettyPrint(sourceId) {
 	  return (_ref16) => {
 	    var dispatch = _ref16.dispatch,
 	        getState = _ref16.getState,
 	        client = _ref16.client,
 	        sourceMaps = _ref16.sourceMaps;
 
 	    var source = (0, _selectors.getSource)(getState(), sourceId).toJS();
-	    var sourceText = (0, _selectors.getSourceText)(getState(), sourceId);
-	    if (sourceText) {
-	      sourceText = sourceText.toJS();
-	    }
-
-	    if (sourceText && sourceText.loading) {
+
+	    if (source && source.loading) {
 	      return {};
 	    }
 
 	    (0, _assert2.default)(sourceMaps.isGeneratedId(sourceId), "Pretty-printing only allowed on generated sources");
 
 	    var url = (0, _source.getPrettySourceURL)(source.url);
 	    var id = sourceMaps.generatedToOriginalId(source.id, url);
 	    var originalSource = { url, id, isPrettyPrinted: false };
 	    dispatch({ type: "ADD_SOURCE", source: originalSource });
 
 	    return dispatch({
 	      type: "TOGGLE_PRETTY_PRINT",
 	      source: originalSource,
 	      [_promise.PROMISE]: _asyncToGenerator(function* () {
 	        var _ref18 = yield (0, _prettyPrint.prettyPrint)({
 	          source,
-	          sourceText,
 	          url
 	        }),
 	            code = _ref18.code,
 	            mappings = _ref18.mappings;
 
 	        yield sourceMaps.applySourceMap(source.id, url, code, mappings);
 
 	        var frames = (0, _selectors.getFrames)(getState());
@@ -17320,20 +17310,18 @@ return /******/ (function(modules) { // 
 	  return (() => {
 	    var _ref21 = _asyncToGenerator(function* (_ref22) {
 	      var dispatch = _ref22.dispatch,
 	          getState = _ref22.getState,
 	          client = _ref22.client,
 	          sourceMaps = _ref22.sourceMaps;
 
 	      // Fetch the source text only once.
-	      var textInfo = (0, _selectors.getSourceText)(getState(), source.id);
-	      if (textInfo) {
-	        // It's already loaded or is loading
-	        return Promise.resolve(textInfo);
+	      if (source.text) {
+	        return Promise.resolve(source);
 	      }
 
 	      yield dispatch({
 	        type: "LOAD_SOURCE_TEXT",
 	        source: source,
 	        [_promise.PROMISE]: _asyncToGenerator(function* () {
 	          if (sourceMaps.isOriginalId(source.id)) {
 	            return yield sourceMaps.getOriginalSourceText(source);
@@ -17347,17 +17335,17 @@ return /******/ (function(modules) { // 
 	            contentType: response.contentType || "text/javascript"
 	          };
 
 	          return sourceText;
 	        })()
 	      });
 
 	      // get the symbols for the source as well
-	      return dispatch((0, _ast.setSymbols)(source));
+	      return dispatch((0, _ast.setSymbols)(source.id));
 	    });
 
 	    return function (_x15) {
 	      return _ref21.apply(this, arguments);
 	    };
 	  })();
 	}
 
@@ -17388,19 +17376,19 @@ return /******/ (function(modules) { // 
 	    // Can't use promise.all, because if one fetch operation is rejected, then
 	    // everything is considered rejected, thus no other subsequent source will
 	    // be getting fetched. We don't want that. Something like Q's allSettled
 	    // would work like a charm here.
 	    // Try to fetch as many sources as possible.
 
 	    var _loop = function (actor) {
 	      var source = (0, _selectors.getSource)(getState(), actor);
-	      dispatch(loadSourceText(source)).then((_ref33) => {
-	        var text = _ref33.text,
-	            contentType = _ref33.contentType;
+	      dispatch(loadSourceText(source)).then((_ref31) => {
+	        var text = _ref31.text,
+	            contentType = _ref31.contentType;
 
 	        onFetch([source, text, contentType]);
 	      }, err => {
 	        onError(source, err);
 	      });
 	    };
 
 	    for (var actor of actors) {
@@ -17427,38 +17415,34 @@ return /******/ (function(modules) { // 
 	        return;
 	      }
 	      pending.delete(aSource.actor);
 	      fetched.push([aSource.actor, aText, aContentType]);
 	      maybeFinish();
 	    }
 
 	    /* Called if fetching a source failed because of an error. */
-	    function onError(_ref27) {
-	      var _ref28 = _slicedToArray(_ref27, 2),
-	          aSource = _ref28[0],
-	          aError = _ref28[1];
-
-	      pending.delete(aSource.actor);
+	    function onError(source, error) {
+	      pending.delete(source.actor);
 	      maybeFinish();
 	    }
 
 	    /* Called every time something interesting
 	     *  happens while fetching sources.
 	     */
 	    function maybeFinish() {
 	      if (pending.size == 0) {
 	        // Sort the fetched sources alphabetically by their url.
 	        if (deferred) {
-	          deferred.resolve(fetched.sort((_ref29, _ref30) => {
-	            var _ref32 = _slicedToArray(_ref29, 1),
-	                aFirst = _ref32[0];
-
-	            var _ref31 = _slicedToArray(_ref30, 1),
-	                aSecond = _ref31[0];
+	          deferred.resolve(fetched.sort((_ref27, _ref28) => {
+	            var _ref30 = _slicedToArray(_ref27, 1),
+	                aFirst = _ref30[0];
+
+	            var _ref29 = _slicedToArray(_ref28, 1),
+	                aSecond = _ref29[0];
 
 	            return aFirst > aSecond ? -1 : 1;
 	          }));
 	        }
 	      }
 	    }
 
 	    return deferred.promise;
@@ -17647,24 +17631,23 @@ return /******/ (function(modules) { // 
 	      // Override code mirror keymap to avoid conflicts with split console.
 	      Esc: false,
 	      "Cmd-F": false,
 	      "Cmd-G": false
 	    }
 	  });
 	}
 
-	function updateDocument(editor, selectedSource, sourceText) {
-	  if (selectedSource) {
-	    var sourceId = selectedSource.get("id");
-	    var doc = getDocument(sourceId) || editor.createDocument();
-	    editor.replaceDocument(doc);
-	  } else if (sourceText) {
-	    this.setText(sourceText.get("text"));
-	  }
+	function updateDocument(editor, selectedSource) {
+	  if (!selectedSource) {
+	    return;
+	  }
+	  var sourceId = selectedSource.get("id");
+	  var doc = getDocument(sourceId) || editor.createDocument();
+	  editor.replaceDocument(doc);
 	}
 
 	module.exports = Object.assign({}, expressionUtils, sourceDocumentUtils, sourceSearchUtils, _devtoolsSourceEditor.SourceEditorUtils, {
 	  createEditor,
 	  shouldShowPrettyPrint,
 	  shouldShowFooter,
 	  breakpointAtLocation,
 	  traverseResults,
@@ -19985,16 +19968,17 @@ return /******/ (function(modules) { // 
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
 	Object.defineProperty(exports, "__esModule", {
 	  value: true
 	});
 	exports.willNavigate = willNavigate;
+	exports.navigate = navigate;
 	exports.navigated = navigated;
 
 	var _editor = __webpack_require__(257);
 
 	var _sources = __webpack_require__(232);
 
 	var _utils = __webpack_require__(234);
 
@@ -20017,28 +20001,32 @@ return /******/ (function(modules) { // 
 	      var dispatch = _ref2.dispatch,
 	          getState = _ref2.getState,
 	          client = _ref2.client,
 	          sourceMaps = _ref2.sourceMaps;
 
 	      yield sourceMaps.clearSourceMaps();
 	      (0, _editor.clearDocuments)();
 
-	      dispatch({
-	        type: "NAVIGATE",
-	        url: event.url
-	      });
+	      dispatch(navigate(event.url));
 	    });
 
 	    return function (_x) {
 	      return _ref.apply(this, arguments);
 	    };
 	  })();
 	}
 
+	function navigate(url) {
+	  return {
+	    type: "NAVIGATE",
+	    url
+	  };
+	}
+
 	/**
 	 * @memberof actions/navigation
 	 * @static
 	 */
 	function navigated() {
 	  return (() => {
 	    var _ref3 = _asyncToGenerator(function* (_ref4) {
 	      var dispatch = _ref4.dispatch,
@@ -22045,16 +22033,17 @@ return /******/ (function(modules) { // 
 	  close: __webpack_require__(352),
 	  domain: __webpack_require__(353),
 	  file: __webpack_require__(354),
 	  folder: __webpack_require__(355),
 	  globe: __webpack_require__(356),
 	  jquery: __webpack_require__(999),
 	  underscore: __webpack_require__(1117),
 	  lodash: __webpack_require__(1118),
+	  ember: __webpack_require__(1119),
 	  "magnifying-glass": __webpack_require__(357),
 	  "arrow-up": __webpack_require__(919),
 	  "arrow-down": __webpack_require__(920),
 	  pause: __webpack_require__(358),
 	  "pause-exceptions": __webpack_require__(359),
 	  plus: __webpack_require__(360),
 	  prettyPrint: __webpack_require__(361),
 	  react: __webpack_require__(1000),
@@ -22932,16 +22921,21 @@ return /******/ (function(modules) { // 
 	  }
 
 	  shouldComponentUpdate() {
 	    this.queueUpdate();
 	    return false;
 	  }
 
 	  componentWillReceiveProps(nextProps) {
+	    if (this.props.debuggeeUrl != nextProps.debuggeeUrl) {
+	      // Recreate tree because the sort order changed
+	      this.setState((0, _sourcesTree.createTree)(this.props.sources, nextProps.debuggeeUrl));
+	      return;
+	    }
 	    var selectedSource = this.props.selectedSource;
 
 	    if (nextProps.shownSource && nextProps.shownSource != this.props.shownSource) {
 	      var _listItems = (0, _sourcesTree.getDirectories)(nextProps.shownSource, this.state.sourceTree);
 
 	      if (_listItems && _listItems[0]) {
 	        this.selectItem(_listItems[0]);
 	      }
@@ -22955,20 +22949,23 @@ return /******/ (function(modules) { // 
 	      return this.setState({ highlightItems: _highlightItems });
 	    }
 
 	    if (nextProps.sources === this.props.sources) {
 	      return;
 	    }
 
 	    if (nextProps.sources.size === 0) {
+	      // remove all sources
 	      this.setState((0, _sourcesTree.createTree)(nextProps.sources, this.props.debuggeeUrl));
 	      return;
 	    }
 
+	    // TODO: do not run this every time a source is clicked,
+	    // only when a new source is added
 	    var next = (0, _immutable.Set)(nextProps.sources.valueSeq());
 	    var prev = (0, _immutable.Set)(this.props.sources.valueSeq());
 	    var newSet = next.subtract(prev);
 
 	    var uncollapsedTree = this.state.uncollapsedTree;
 	    for (var source of newSet) {
 	      (0, _sourcesTree.addToTree)(uncollapsedTree, source, this.props.debuggeeUrl);
 	    }
@@ -23336,54 +23333,59 @@ return /******/ (function(modules) { // 
 
 	  var parts = url.path.split("/").filter(p => p !== "");
 	  var isDir = isDirectory(url);
 	  parts.unshift(url.group);
 
 	  var path = "";
 	  var subtree = tree;
 
-	  for (var i = 0; i < parts.length; i++) {
+	  var _loop = function (i) {
 	    var part = parts[i];
 	    var isLastPart = i === parts.length - 1;
 
 	    // Currently we assume that we are descending into a node with
 	    // children. This will fail if a path has a directory named the
 	    // same as another file, like `foo/bar.js/file.js`.
 	    //
 	    // TODO: Be smarter about this, which we'll probably do when we
 	    // are smarter about folders and collapsing empty ones.
 	    (0, _DevToolsUtils2.default)(nodeHasChildren(subtree), `${subtree.name} should have children`);
 	    var children = subtree.contents;
 
 	    var index = determineFileSortOrder(children, part, isLastPart, i === 0 ? debuggeeUrl : "");
 
-	    if (index >= 0 && children[index].name === part) {
+	    var child = children.find(c => c.name === part);
+	    if (child) {
 	      // A node with the same name already exists, simply traverse
 	      // into it.
-	      subtree = children[index];
+	      subtree = child;
 	    } else {
 	      // No node with this name exists, so insert a new one in the
 	      // place that is alphabetically sorted.
 	      var node = createNode(part, `${path}/${part}`, []);
 	      var where = index === -1 ? children.length : index;
 	      children.splice(where, 0, node);
 	      subtree = children[where];
 	    }
 
 	    // Keep track of the children so we can tag each node with them.
 	    path = `${path}/${part}`;
+	  };
+
+	  for (var i = 0; i < parts.length; i++) {
+	    _loop(i);
 	  }
 
 	  // Overwrite the contents of the final node to store the source
 	  // there.
-	  if (isDir) {
+	  if (!isDir) {
+	    subtree.contents = source;
+	  } else if (!subtree.contents.find(c => c.name === "(index)")) {
 	    subtree.contents.unshift(createNode("(index)", source.get("url"), source));
-	  } else {
-	    subtree.contents = source;
 	  }
 	}
 
 	/**
 	 * @memberof utils/sources-tree
 	 * @static
 	 */
 	function isExactUrlMatch(pathPart, debuggeeUrl) {
@@ -23486,18 +23488,18 @@ return /******/ (function(modules) { // 
 	    focusedItem: null
 	  };
 	}
 
 	function findSource(sourceTree, sourceUrl) {
 	  var returnTarget = null;
 	  function _traverse(subtree) {
 	    if (nodeHasChildren(subtree)) {
-	      for (var child of subtree.contents) {
-	        _traverse(child);
+	      for (var _child of subtree.contents) {
+	        _traverse(_child);
 	      }
 	    } else if (!returnTarget && subtree.path.replace(/http(s)?:\//, "") == sourceUrl) {
 	      returnTarget = subtree;
 	      return;
 	    }
 	  }
 
 	  sourceTree.contents.forEach(_traverse);
@@ -24718,26 +24720,22 @@ return /******/ (function(modules) { // 
 	var _EditorMenu = __webpack_require__(656);
 
 	var _EditorMenu2 = _interopRequireDefault(_EditorMenu);
 
 	var _ConditionalPanel = __webpack_require__(711);
 
 	var _devtoolsLaunchpad = __webpack_require__(131);
 
-	var _range = __webpack_require__(1026);
-
-	var _range2 = _interopRequireDefault(_range);
-
-	var _flatMap = __webpack_require__(1067);
-
-	var _flatMap2 = _interopRequireDefault(_flatMap);
-
 	var _selectors = __webpack_require__(242);
 
+	var _linesInScope = __webpack_require__(1124);
+
+	var _linesInScope2 = _interopRequireDefault(_linesInScope);
+
 	var _breakpoint = __webpack_require__(1057);
 
 	var _actions = __webpack_require__(244);
 
 	var _actions2 = _interopRequireDefault(_actions);
 
 	var _Footer2 = __webpack_require__(427);
 
@@ -24848,18 +24846,20 @@ return /******/ (function(modules) { // 
 	    } else if (selectedSource.get("loading")) {
 	      this.showMessage(L10N.getStr("loadingText"));
 	    } else if (selectedSource.get("error")) {
 	      this.showMessage(selectedSource.get("error"));
 	    } else if (this.props.selectedSource !== selectedSource) {
 	      this.showSourceText(selectedSource, selectedLocation);
 	    }
 
-	    if (this.props.outOfScopeLocations !== nextProps.outOfScopeLocations) {
-	      (0, _editor.clearLineClass)(this.editor.codeMirror, "out-of-scope");
+	    if (this.props.linesInScope !== nextProps.linesInScope) {
+	      this.editor.codeMirror.operation(() => {
+	        (0, _editor.clearLineClass)(this.editor.codeMirror, "in-scope");
+	      });
 	    }
 
 	    this.setDebugLine(nextProps.selectedFrame, selectedLocation);
 	    (0, _editor.resizeBreakpointGutter)(this.editor.codeMirror);
 	  }
 
 	  setupEditor() {
 	    var editor = (0, _editor.createEditor)();
@@ -24911,32 +24911,30 @@ return /******/ (function(modules) { // 
 
 	    return editor;
 	  }
 
 	  componentDidMount() {
 	    this.cbPanel = null;
 	    this.editor = this.setupEditor();
 
-	    var _props = this.props,
-	        selectedSource = _props.selectedSource,
-	        sourceText = _props.sourceText;
+	    var selectedSource = this.props.selectedSource;
 	    var shortcuts = this.context.shortcuts;
 
 
 	    var searchAgainKey = L10N.getStr("sourceSearch.search.again.key2");
 	    var searchAgainPrevKey = L10N.getStr("sourceSearch.search.againPrev.key2");
 
 	    shortcuts.on("CmdOrCtrl+B", this.onToggleBreakpoint);
 	    shortcuts.on("CmdOrCtrl+Shift+B", this.onToggleBreakpoint);
 	    shortcuts.on("Esc", this.onEscape);
 	    shortcuts.on(searchAgainPrevKey, this.onSearchAgain);
 	    shortcuts.on(searchAgainKey, this.onSearchAgain);
 
-	    (0, _editor.updateDocument)(this.editor, selectedSource, sourceText);
+	    (0, _editor.updateDocument)(this.editor, selectedSource);
 	  }
 
 	  componentWillUnmount() {
 	    this.editor.destroy();
 	    this.editor = null;
 
 	    var searchAgainKey = L10N.getStr("sourceSearch.search.again.key2");
 	    var searchAgainPrevKey = L10N.getStr("sourceSearch.search.againPrev.key2");
@@ -24946,19 +24944,19 @@ return /******/ (function(modules) { // 
 	    shortcuts.off(searchAgainPrevKey);
 	    shortcuts.off(searchAgainKey);
 	  }
 
 	  componentDidUpdate(prevProps) {
 	    // This is in `componentDidUpdate` so helper functions can expect
 	    // `this.props` to be the current props. This lifecycle method is
 	    // responsible for updating the editor annotations.
-	    var _props2 = this.props,
-	        selectedLocation = _props2.selectedLocation,
-	        selectedSource = _props2.selectedSource;
+	    var _props = this.props,
+	        selectedLocation = _props.selectedLocation,
+	        selectedSource = _props.selectedSource;
 
 	    // If the location is different and a new line is requested,
 	    // update the pending jump line. Note that if jumping to a line in
 	    // a source where the text hasn't been loaded yet, we will set the
 	    // line here but not jump until rendering the actual source.
 
 	    if (prevProps.selectedLocation !== selectedLocation) {
 	      if (selectedLocation && selectedLocation.line != undefined) {
@@ -25028,21 +25026,31 @@ return /******/ (function(modules) { // 
 	  }
 
 	  onScroll() {
 	    this.clearPreviewSelection();
 	  }
 
 	  onMouseOver(e) {
 	    var target = e.target;
-
-	    if (!this.inSelectedFrameSource() || !target.parentElement.closest(".CodeMirror-line") || target.parentElement.closest(".out-of-scope")) {
-	      return;
-	    }
-	    this.previewSelectedToken(e);
+	    var linesInScope = this.props.linesInScope;
+
+
+	    if (!this.inSelectedFrameSource() || !target.parentElement.closest(".CodeMirror-line")) {
+	      return;
+	    }
+	    var location = (0, _editor.getTokenLocation)(this.editor.codeMirror, target);
+	    var line = location.line;
+
+
+	    if (!linesInScope.includes(line)) {
+	      return;
+	    }
+
+	    this.previewSelectedToken(target, location);
 	  }
 
 	  onTokenClick(e) {
 	    var target = e.target;
 
 	    if (!(0, _devtoolsConfig.isEnabled)("columnBreakpoints") || !e.altKey || !target.parentElement.closest(".CodeMirror-line")) {
 	      return;
 	    }
@@ -25050,64 +25058,61 @@ return /******/ (function(modules) { // 
 	    var _getTokenLocation = (0, _editor.getTokenLocation)(this.editor.codeMirror, target),
 	        line = _getTokenLocation.line,
 	        column = _getTokenLocation.column;
 
 	    this.toggleBreakpoint(line - 1, column - 1);
 	  }
 
 	  onSearchAgain(_, e) {
-	    var _props3 = this.props,
-	        query = _props3.query,
-	        searchModifiers = _props3.searchModifiers;
+	    var _props2 = this.props,
+	        query = _props2.query,
+	        searchModifiers = _props2.searchModifiers;
 	    var codeMirror = this.editor.editor.codeMirror;
 
 	    var ctx = { ed: this.editor, cm: codeMirror };
 
 	    var direction = e.shiftKey ? "prev" : "next";
 	    (0, _editor.traverseResults)(e, ctx, query, direction, searchModifiers.toJS());
 	  }
 
 	  clearPreviewSelection() {
 	    this.props.clearSelection();
 	    return this.setState({ selectedToken: null });
 	  }
 
-	  previewSelectedToken(e) {
+	  previewSelectedToken(token, location) {
 	    var _this = this;
 
 	    return _asyncToGenerator(function* () {
-	      var _props4 = _this.props,
-	          selectedFrame = _props4.selectedFrame,
-	          selectedSource = _props4.selectedSource,
-	          sourceText = _props4.sourceText,
-	          setSelection = _props4.setSelection,
-	          selection = _props4.selection;
-
-	      var token = e.target;
+	      var _props3 = _this.props,
+	          selectedFrame = _props3.selectedFrame,
+	          selectedSource = _props3.selectedSource,
+	          setSelection = _props3.setSelection,
+	          selection = _props3.selection;
+
 	      var tokenText = token.innerText.trim();
 
-	      if (selection && selection.updating || !selectedFrame || !sourceText || !selectedSource || tokenText === "" || tokenText.match(/\s/) || selectedFrame.location.sourceId !== selectedSource.get("id")) {
+	      if (selection && selection.updating || !selectedFrame || !selectedSource || tokenText === "" || tokenText.match(/\s/) || selectedFrame.location.sourceId !== selectedSource.get("id")) {
 	        return;
 	      }
 
-	      var location = (0, _editor.getTokenLocation)(_this.editor.codeMirror, token);
 	      setSelection(tokenText, location);
 	      _this.setState({ selectedToken: token });
 	    })();
 	  }
 
 	  openMenu(event, codeMirror) {
-	    var _props5 = this.props,
-	        selectedSource = _props5.selectedSource,
-	        selectedLocation = _props5.selectedLocation,
-	        showSource = _props5.showSource,
-	        jumpToMappedLocation = _props5.jumpToMappedLocation,
-	        addExpression = _props5.addExpression,
-	        toggleBlackBox = _props5.toggleBlackBox;
+	    var _props4 = this.props,
+	        selectedSource = _props4.selectedSource,
+	        selectedLocation = _props4.selectedLocation,
+	        showSource = _props4.showSource,
+	        jumpToMappedLocation = _props4.jumpToMappedLocation,
+	        addExpression = _props4.addExpression,
+	        toggleBlackBox = _props4.toggleBlackBox;
 
 
 	    return (0, _EditorMenu2.default)({
 	      codeMirror,
 	      event,
 	      selectedLocation,
 	      selectedSource,
 	      showSource,
@@ -25118,22 +25123,22 @@ return /******/ (function(modules) { // 
 	    });
 	  }
 
 	  onGutterClick(cm, line, gutter, ev) {
 	    var selectedSource = this.props.selectedSource;
 
 	    // ignore right clicks in the gutter
 
-	    if (ev.which === 3 || selectedSource && selectedSource.get("isBlackBoxed")) {
+	    if (ev.ctrlKey && ev.button === 0 || ev.which === 3 || selectedSource && selectedSource.get("isBlackBoxed")) {
 	      return;
 	    }
 
 	    if (this.isCbPanelOpen()) {
-	      return this.closeConditionalPanel(line);
+	      return this.closeConditionalPanel();
 	    }
 
 	    if (gutter !== "CodeMirror-foldgutter") {
 	      this.toggleBreakpoint(line);
 	    }
 	  }
 
 	  onGutterContextMenu(event) {
@@ -25159,20 +25164,20 @@ return /******/ (function(modules) { // 
 	    });
 	  }
 
 	  toggleConditionalPanel(line) {
 	    if (this.isCbPanelOpen()) {
 	      return this.closeConditionalPanel();
 	    }
 
-	    var _props6 = this.props,
-	        selectedLocation = _props6.selectedLocation,
-	        setBreakpointCondition = _props6.setBreakpointCondition,
-	        breakpoints = _props6.breakpoints;
+	    var _props5 = this.props,
+	        selectedLocation = _props5.selectedLocation,
+	        setBreakpointCondition = _props5.setBreakpointCondition,
+	        breakpoints = _props5.breakpoints;
 
 	    var sourceId = selectedLocation ? selectedLocation.sourceId : "";
 
 	    var bp = (0, _editor.breakpointAtLocation)(breakpoints, { line });
 	    var location = { sourceId, line: line + 1 };
 	    var condition = bp ? bp.condition : "";
 
 	    var setBreakpoint = value => setBreakpointCondition(location, {
@@ -25199,22 +25204,22 @@ return /******/ (function(modules) { // 
 	  }
 
 	  isCbPanelOpen() {
 	    return !!this.cbPanel;
 	  }
 
 	  toggleBreakpoint(line) {
 	    var column = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined;
-	    var _props7 = this.props,
-	        selectedSource = _props7.selectedSource,
-	        selectedLocation = _props7.selectedLocation,
-	        breakpoints = _props7.breakpoints,
-	        addBreakpoint = _props7.addBreakpoint,
-	        removeBreakpoint = _props7.removeBreakpoint;
+	    var _props6 = this.props,
+	        selectedSource = _props6.selectedSource,
+	        selectedLocation = _props6.selectedLocation,
+	        breakpoints = _props6.breakpoints,
+	        addBreakpoint = _props6.addBreakpoint,
+	        removeBreakpoint = _props6.removeBreakpoint;
 
 	    var bp = (0, _editor.breakpointAtLocation)(breakpoints, { line, column });
 
 	    if (bp && bp.loading || !selectedLocation || !selectedSource) {
 	      return;
 	    }
 
 	    var sourceId = selectedLocation.sourceId;
@@ -25329,33 +25334,33 @@ return /******/ (function(modules) { // 
 	    this.editor.setMode({ name: "text" });
 	  }
 
 	  /**
 	   * Handle getting the source document or creating a new
 	   * document with the correct mode and text.
 	   *
 	   */
-	  showSourceText(sourceText, selectedLocation) {
+	  showSourceText(source, selectedLocation) {
 	    if (!selectedLocation) {
 	      return;
 	    }
 
 	    var doc = (0, _editor.getDocument)(selectedLocation.sourceId);
 	    if (doc) {
 	      this.editor.replaceDocument(doc);
 	      return doc;
 	    }
 
 	    doc = this.editor.createDocument();
 	    (0, _editor.setDocument)(selectedLocation.sourceId, doc);
 	    this.editor.replaceDocument(doc);
 
-	    this.setText(sourceText.get("text"));
-	    this.editor.setMode((0, _source.getMode)(sourceText.toJS()));
+	    this.setText(source.get("text"));
+	    this.editor.setMode((0, _source.getMode)(source.toJS()));
 	  }
 
 	  renderHighlightLines() {
 	    var highlightedLineRange = this.props.highlightedLineRange;
 
 
 	    if (!highlightedLineRange) {
 	      return;
@@ -25363,24 +25368,22 @@ return /******/ (function(modules) { // 
 
 	    return HighlightLines({
 	      editor: this.editor,
 	      highlightedLineRange
 	    });
 	  }
 
 	  renderBreakpoints() {
-	    var _props8 = this.props,
-	        breakpoints = _props8.breakpoints,
-	        sourceText = _props8.sourceText,
-	        selectedSource = _props8.selectedSource;
-
-	    var isLoading = sourceText && sourceText.get("loading");
-
-	    if (isLoading || !breakpoints || selectedSource && selectedSource.get("isBlackBoxed")) {
+	    var _props7 = this.props,
+	        breakpoints = _props7.breakpoints,
+	        selectedSource = _props7.selectedSource;
+
+
+	    if (!selectedSource || selectedSource.get("loading") || !breakpoints || selectedSource && selectedSource.get("isBlackBoxed")) {
 	      return;
 	    }
 
 	    var breakpointMarkers = breakpoints.valueSeq().filter(b => (0, _devtoolsConfig.isEnabled)("columnBreakpoints") ? !b.location.column : true).map(bp => Breakpoint({
 	      key: (0, _breakpoint.makeLocationId)(bp.location),
 	      breakpoint: bp,
 	      editor: this.editor && this.editor.codeMirror
 	    }));
@@ -25390,38 +25393,37 @@ return /******/ (function(modules) { // 
 	      breakpoint: bp,
 	      editor: this.editor && this.editor.codeMirror
 	    }));
 
 	    return breakpointMarkers.concat(columnBreakpointBookmarks);
 	  }
 
 	  renderHitCounts() {
-	    var _props9 = this.props,
-	        hitCount = _props9.hitCount,
-	        sourceText = _props9.sourceText;
-
-	    var isLoading = sourceText && sourceText.get("loading");
-
-	    if (isLoading || !hitCount || !this.editor) {
+	    var _props8 = this.props,
+	        hitCount = _props8.hitCount,
+	        selectedSource = _props8.selectedSource;
+
+
+	    if (!selectedSource || selectedSource.get("loading") || !hitCount || !this.editor) {
 	      return;
 	    }
 
 	    return hitCount.filter(marker => marker.get("count") > 0).map(marker => HitMarker({
 	      key: marker.get("line"),
 	      hitData: marker.toJS(),
 	      editor: this.editor.codeMirror
 	    }));
 	  }
 
 	  getInlineEditorStyles() {
-	    var _props10 = this.props,
-	        selectedSource = _props10.selectedSource,
-	        horizontal = _props10.horizontal,
-	        searchOn = _props10.searchOn;
+	    var _props9 = this.props,
+	        selectedSource = _props9.selectedSource,
+	        horizontal = _props9.horizontal,
+	        searchOn = _props9.searchOn;
 
 
 	    var subtractions = [];
 
 	    if ((0, _editor.shouldShowFooter)(selectedSource, horizontal)) {
 	      subtractions.push(cssVars.footerHeight);
 	    }
 
@@ -25432,22 +25434,22 @@ return /******/ (function(modules) { // 
 
 	    return {
 	      height: subtractions.length === 0 ? "100%" : `calc(100% - ${subtractions.join(" - ")})`
 	    };
 	  }
 
 	  renderPreview() {
 	    var selectedToken = this.state.selectedToken;
-	    var _props11 = this.props,
-	        sourceText = _props11.sourceText,
-	        selection = _props11.selection;
-
-
-	    if (!this.editor || !sourceText) {
+	    var _props10 = this.props,
+	        selectedSource = _props10.selectedSource,
+	        selection = _props10.selection;
+
+
+	    if (!this.editor || !selectedSource) {
 	      return null;
 	    }
 
 	    if (!selection || !selectedToken) {
 	      return;
 	    }
 
 	    var result = selection.result,
@@ -25461,75 +25463,77 @@ return /******/ (function(modules) { // 
 	    return Preview({
 	      value,
 	      expression: expression,
 	      popoverTarget: selectedToken,
 	      onClose: () => this.clearPreviewSelection()
 	    });
 	  }
 
+	  renderInScopeLines() {
+	    var linesInScope = this.props.linesInScope;
+
+	    if (!(0, _devtoolsConfig.isEnabled)("highlightScopeLines") || !linesInScope || !this.inSelectedFrameSource()) {
+	      return;
+	    }
+
+	    this.editor.codeMirror.operation(() => {
+	      linesInScope.forEach(line => {
+	        this.editor.codeMirror.addLineClass(line - 1, "line", "in-scope");
+	      });
+	    });
+	  }
+
 	  inSelectedFrameSource() {
-	    var _props12 = this.props,
-	        selectedLocation = _props12.selectedLocation,
-	        selectedFrame = _props12.selectedFrame;
+	    var _props11 = this.props,
+	        selectedLocation = _props11.selectedLocation,
+	        selectedFrame = _props11.selectedFrame;
 
 	    return selectedFrame && selectedLocation && selectedFrame.location.sourceId == selectedLocation.sourceId;
 	  }
 
-	  renderOutOfScopedLocations() {
-	    var outOfScopeLocations = this.props.outOfScopeLocations;
-
-
-	    if (!this.inSelectedFrameSource() || !outOfScopeLocations || !this.editor) {
-	      return;
-	    }
-
-	    (0, _flatMap2.default)(outOfScopeLocations, location => (0, _range2.default)(location.start.line, location.end.line)).forEach(line => {
-	      this.editor.codeMirror.addLineClass(line - 1, "line", "out-of-scope");
-	    });
-	  }
-
 	  render() {
-	    var _props13 = this.props,
-	        sourceText = _props13.sourceText,
-	        selectSource = _props13.selectSource,
-	        selectedSource = _props13.selectedSource,
-	        highlightLineRange = _props13.highlightLineRange,
-	        clearHighlightLineRange = _props13.clearHighlightLineRange,
-	        coverageOn = _props13.coverageOn,
-	        horizontal = _props13.horizontal;
+	    var _props12 = this.props,
+	        selectSource = _props12.selectSource,
+	        selectedSource = _props12.selectedSource,
+	        highlightLineRange = _props12.highlightLineRange,
+	        clearHighlightLineRange = _props12.clearHighlightLineRange,
+	        coverageOn = _props12.coverageOn,
+	        pauseData = _props12.pauseData,
+	        horizontal = _props12.horizontal;
 
 
 	    return _react.DOM.div({
-	      className: (0, _classnames2.default)("editor-wrapper", { "coverage-on": coverageOn })
+	      className: (0, _classnames2.default)("editor-wrapper", {
+	        "coverage-on": coverageOn,
+	        paused: !!pauseData && (0, _devtoolsConfig.isEnabled)("highlightScopeLines")
+	      })
 	    }, SearchBar({
 	      editor: this.editor,
 	      selectSource,
 	      selectedSource,
 	      highlightLineRange,
-	      clearHighlightLineRange,
-	      sourceText
+	      clearHighlightLineRange
 	    }), _react.DOM.div({
 	      className: "editor-mount devtools-monospace",
 	      style: this.getInlineEditorStyles()
-	    }), this.renderOutOfScopedLocations(), this.renderHighlightLines(), this.renderBreakpoints(), this.renderHitCounts(), Footer({ editor: this.editor, horizontal }), this.renderPreview());
+	    }), this.renderHighlightLines(), this.renderBreakpoints(), this.renderInScopeLines(), this.renderHitCounts(), Footer({ editor: this.editor, horizontal }), this.renderPreview());
 	  }
 	}
 
 	Editor.displayName = "Editor";
 
 	Editor.propTypes = {
 	  breakpoints: _reactImmutableProptypes2.default.map.isRequired,
 	  hitCount: _react.PropTypes.object,
 	  selectedLocation: _react.PropTypes.object,
 	  selectedSource: _reactImmutableProptypes2.default.map,
 	  highlightLineRange: _react.PropTypes.func,
 	  clearHighlightLineRange: _react.PropTypes.func,
 	  highlightedLineRange: _react.PropTypes.object,
-	  sourceText: _reactImmutableProptypes2.default.map,
 	  searchOn: _react.PropTypes.bool,
 	  addBreakpoint: _react.PropTypes.func.isRequired,
 	  disableBreakpoint: _react.PropTypes.func.isRequired,
 	  enableBreakpoint: _react.PropTypes.func.isRequired,
 	  removeBreakpoint: _react.PropTypes.func.isRequired,
 	  setBreakpointCondition: _react.PropTypes.func.isRequired,
 	  selectSource: _react.PropTypes.func,
 	  jumpToMappedLocation: _react.PropTypes.func,
@@ -25546,17 +25550,17 @@ return /******/ (function(modules) { // 
 	    caseSensitive: _react.PropTypes.bool.isRequired,
 	    regexMatch: _react.PropTypes.bool.isRequired,
 	    wholeWord: _react.PropTypes.bool.isRequired
 	  }).isRequired,
 	  selection: _react.PropTypes.object,
 	  startPanelSize: _react.PropTypes.number,
 	  endPanelSize: _react.PropTypes.number,
 	  clearSelection: _react.PropTypes.func.isRequired,
-	  outOfScopeLocations: _react.PropTypes.array
+	  linesInScope: _react.PropTypes.array
 	};
 
 	Editor.contextTypes = {
 	  shortcuts: _react.PropTypes.object
 	};
 
 	var expressionsSel = state => state.expressions.expressions;
 	var getExpressionSel = (0, _reselect.createSelector)(expressionsSel, expressions => input => expressions.find(exp => exp.input == input));
@@ -25566,27 +25570,26 @@ return /******/ (function(modules) { // 
 	  var sourceId = selectedLocation && selectedLocation.sourceId;
 	  var selectedSource = (0, _selectors.getSelectedSource)(state);
 
 	  return {
 	    selectedLocation,
 	    selectedSource,
 	    highlightedLineRange: (0, _selectors.getHighlightedLineRange)(state),
 	    searchOn: (0, _selectors.getFileSearchState)(state),
-	    sourceText: (0, _selectors.getSourceText)(state, sourceId),
 	    loadedObjects: (0, _selectors.getLoadedObjects)(state),
 	    breakpoints: (0, _selectors.getBreakpointsForSource)(state, sourceId || ""),
 	    hitCount: (0, _selectors.getHitCountForSource)(state, sourceId),
 	    selectedFrame: (0, _selectors.getSelectedFrame)(state),
 	    getExpression: getExpressionSel(state),
 	    pauseData: (0, _selectors.getPause)(state),
 	    coverageOn: (0, _selectors.getCoverageEnabled)(state),
 	    query: (0, _selectors.getFileSearchQueryState)(state),
 	    searchModifiers: (0, _selectors.getFileSearchModifierState)(state),
-	    outOfScopeLocations: (0, _selectors.getOutOfScopeLocations)(state),
+	    linesInScope: (0, _linesInScope2.default)(state),
 	    selection: (0, _selectors.getSelection)(state)
 	  };
 	}, dispatch => (0, _redux.bindActionCreators)(_actions2.default, dispatch))(Editor);
 
 /***/ },
 /* 427 */
 /***/ function(module, exports, __webpack_require__) {
 
@@ -25937,16 +25940,17 @@ return /******/ (function(modules) { // 
 	    };
 
 	    var self = this;
 	    self.onEscape = this.onEscape.bind(this);
 	    self.clearSearch = this.clearSearch.bind(this);
 	    self.closeSearch = this.closeSearch.bind(this);
 	    self.toggleSearch = this.toggleSearch.bind(this);
 	    self.toggleSymbolSearch = this.toggleSymbolSearch.bind(this);
+	    self.toggleTextSearch = this.toggleTextSearch.bind(this);
 	    self.setSearchValue = this.setSearchValue.bind(this);
 	    self.selectSearchInput = this.selectSearchInput.bind(this);
 	    self.searchInput = this.searchInput.bind(this);
 	    self.updateSymbolSearchResults = this.updateSymbolSearchResults.bind(this);
 	    self.doSearch = this.doSearch.bind(this);
 	    self.searchContents = this.searchContents.bind(this);
 	    self.traverseSymbolResults = this.traverseSymbolResults.bind(this);
 	    self.traverseCodeResults = this.traverseCodeResults.bind(this);
@@ -26055,147 +26059,165 @@ return /******/ (function(modules) { // 
 	      var ctx = { ed, cm: ed.codeMirror };
 	      (0, _editor.removeOverlay)(ctx, query, modifiers.toJS());
 	    }
 	  }
 
 	  closeSearch(e) {
 	    var _props3 = this.props,
 	        editor = _props3.editor,
-	        setFileSearchQuery = _props3.setFileSearchQuery;
-
-
-	    if (this.props.searchOn && editor) {
+	        setFileSearchQuery = _props3.setFileSearchQuery,
+	        searchOn = _props3.searchOn,
+	        symbolSearchOn = _props3.symbolSearchOn;
+
+
+	    if (editor && (searchOn || symbolSearchOn)) {
 	      setFileSearchQuery("");
 	      this.clearSearch();
 	      this.props.toggleFileSearch(false);
 	      this.props.toggleSymbolSearch(false);
 	      this.props.setSelectedSymbolType("functions");
 	      this.props.clearHighlightLineRange();
 	      e.stopPropagation();
 	      e.preventDefault();
 	    }
 	  }
 
 	  toggleSearch(e) {
 	    e.stopPropagation();
 	    e.preventDefault();
-	    var editor = this.props.editor;
+	    var _props4 = this.props,
+	        editor = _props4.editor,
+	        symbolSearchOn = _props4.symbolSearchOn;
 
 
 	    if (!this.props.searchOn) {
 	      this.props.toggleFileSearch();
 	    }
 
-	    if (this.props.symbolSearchOn) {
+	    if (symbolSearchOn) {
 	      this.clearSearch();
 	      this.props.toggleSymbolSearch(false);
 	      this.props.setSelectedSymbolType("functions");
 	    }
 
 	    if (this.props.searchOn && editor) {
 	      var selection = editor.codeMirror.getSelection();
 	      this.setSearchValue(selection);
 	      if (selection !== "") {
 	        this.doSearch(selection);
 	      }
 	      this.selectSearchInput();
 	    }
 	  }
 
+	  ignoreEvent(e) {
+	    if (e) {
+	      e.preventDefault();
+	      e.stopPropagation();
+	    }
+	  }
+
 	  toggleSymbolSearch(e) {
 	    var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
 	        toggle = _ref.toggle,
 	        searchType = _ref.searchType;
 
 	    var selectedSource = this.props.selectedSource;
 
-
-	    if (e) {
-	      e.preventDefault();
-	      e.stopPropagation();
-	    }
+	    if (!selectedSource) {
+	      return;
+	    }
+	    this.ignoreEvent(e);
+
+	    if (this.props.symbolSearchOn) {
+	      if (toggle) {
+	        this.props.toggleSymbolSearch(false);
+	      } else {
+	        this.props.setSelectedSymbolType(searchType);
+	      }
+	      return;
+	    }
+
+	    this.clearSearch();
+	    this.props.toggleSymbolSearch(true);
+	    this.props.setSelectedSymbolType(searchType);
+	  }
+
+	  toggleTextSearch(e) {
+	    var selectedSource = this.props.selectedSource;
+
+	    this.ignoreEvent(e);
 
 	    if (!selectedSource) {
 	      return;
 	    }
 
 	    if (!this.props.searchOn) {
 	      this.props.toggleFileSearch();
 	    }
 
-	    if (this.props.symbolSearchOn) {
-	      if (toggle) {
-	        this.props.toggleSymbolSearch(false);
-	      } else {
-	        this.props.setSelectedSymbolType(searchType);
-	      }
-	      return;
-	    }
-
-	    if (this.props.selectedSource) {
-	      this.clearSearch();
-	      this.props.toggleSymbolSearch(true);
-	      this.props.setSelectedSymbolType(searchType);
-	    }
+	    this.clearSearch();
+	    this.props.toggleSymbolSearch(false);
 	  }
 
 	  setSearchValue(value) {
 	    var searchInput = this.searchInput();
 	    if (value == "" || !searchInput) {
 	      return;
 	    }
 
 	    searchInput.value = value;
 	  }
 
 	  selectSearchInput() {
 	    var searchInput = this.searchInput();
 	    if (searchInput) {
 	      searchInput.setSelectionRange(0, searchInput.value.length);
+	      searchInput.focus();
 	    }
 	  }
 
 	  searchInput() {
 	    var node = (0, _reactDom.findDOMNode)(this);
 	    if (node instanceof HTMLElement) {
 	      var input = node.querySelector("input");
 	      if (input instanceof HTMLInputElement) {
 	        return input;
 	      }
 	    }
 	    return null;
 	  }
 
 	  updateSymbolSearchResults(query) {
-	    var _props4 = this.props,
-	        selectedSource = _props4.selectedSource,
-	        updateSearchResults = _props4.updateSearchResults,
-	        updateSymbolSearchResults = _props4.updateSymbolSearchResults,
-	        selectedSymbolType = _props4.selectedSymbolType,
-	        symbols = _props4.symbols;
+	    var _props5 = this.props,
+	        selectedSource = _props5.selectedSource,
+	        updateSearchResults = _props5.updateSearchResults,
+	        updateSymbolSearchResults = _props5.updateSymbolSearchResults,
+	        selectedSymbolType = _props5.selectedSymbolType,
+	        symbols = _props5.symbols;
 
 
 	    if (query == "" || !selectedSource) {
 	      return;
 	    }
 
 	    var symbolSearchResults = (0, _fuzzaldrinPlus.filter)(symbols[selectedSymbolType], query, {
 	      key: "value"
 	    });
 
 	    updateSearchResults({ count: symbolSearchResults.length });
 	    updateSymbolSearchResults(symbolSearchResults);
 	  }
 
 	  doSearch(query) {
-	    var _props5 = this.props,
-	        selectedSource = _props5.selectedSource,
-	        setFileSearchQuery = _props5.setFileSearchQuery,
-	        ed = _props5.editor;
+	    var _props6 = this.props,
+	        selectedSource = _props6.selectedSource,
+	        setFileSearchQuery = _props6.setFileSearchQuery,
+	        ed = _props6.editor;
 
 	    if (!selectedSource || !selectedSource.get("text")) {
 	      return;
 	    }
 
 	    setFileSearchQuery(query);
 
 	    if (this.props.symbolSearchOn) {
@@ -26204,21 +26226,21 @@ return /******/ (function(modules) { // 
 	      this.searchContents(query);
 	    }
 	  }
 
 	  searchContents(query) {
 	    var _this = this;
 
 	    return _asyncToGenerator(function* () {
-	      var _props6 = _this.props,
-	          selectedSource = _props6.selectedSource,
-	          modifiers = _props6.modifiers,
-	          ed = _props6.editor,
-	          index = _props6.searchResults.index;
+	      var _props7 = _this.props,
+	          selectedSource = _props7.selectedSource,
+	          modifiers = _props7.modifiers,
+	          ed = _props7.editor,
+	          index = _props7.searchResults.index;
 
 
 	      if (!ed || !selectedSource || !selectedSource.get("text") || !modifiers) {
 	        return;
 	      }
 
 	      var ctx = { ed, cm: ed.codeMirror };
 
@@ -26265,23 +26287,23 @@ return /******/ (function(modules) { // 
 	    var ed = this.props.editor;
 
 	    if (!ed) {
 	      return;
 	    }
 
 	    var ctx = { ed, cm: ed.codeMirror };
 
-	    var _props7 = this.props,
-	        query = _props7.query,
-	        modifiers = _props7.modifiers,
-	        updateSearchResults = _props7.updateSearchResults,
-	        _props7$searchResults = _props7.searchResults,
-	        count = _props7$searchResults.count,
-	        index = _props7$searchResults.index;
+	    var _props8 = this.props,
+	        query = _props8.query,
+	        modifiers = _props8.modifiers,
+	        updateSearchResults = _props8.updateSearchResults,
+	        _props8$searchResults = _props8.searchResults,
+	        count = _props8$searchResults.count,
+	        index = _props8$searchResults.index;
 
 
 	    if (query === "") {
 	      this.props.toggleFileSearch(true);
 	    }
 
 	    if (index == -1 && modifiers) {
 	      (0, _editor.clearIndex)(ctx, query, modifiers.toJS());
@@ -26308,36 +26330,36 @@ return /******/ (function(modules) { // 
 	      return this.traverseSymbolResults(rev);
 	    }
 
 	    this.traverseCodeResults(rev);
 	  }
 
 	  // Handlers
 	  selectResultItem(e, item) {
-	    var _props8 = this.props,
-	        selectSource = _props8.selectSource,
-	        selectedSource = _props8.selectedSource;
+	    var _props9 = this.props,
+	        selectSource = _props9.selectSource,
+	        selectedSource = _props9.selectedSource;
 
 
 	    if (selectedSource) {
 	      selectSource(selectedSource.get("id"), {
 	        line: item.location.start.line
 	      });
 
 	      this.closeSearch(e);
 	    }
 	  }
 
 	  onSelectResultItem(item) {
-	    var _props9 = this.props,
-	        selectSource = _props9.selectSource,
-	        selectedSource = _props9.selectedSource,
-	        selectedSymbolType = _props9.selectedSymbolType,
-	        highlightLineRange = _props9.highlightLineRange;
+	    var _props10 = this.props,
+	        selectSource = _props10.selectSource,
+	        selectedSource = _props10.selectedSource,
+	        selectedSymbolType = _props10.selectedSymbolType,
+	        highlightLineRange = _props10.highlightLineRange;
 
 
 	    if (selectedSource && selectedSymbolType !== "functions") {
 	      selectSource(selectedSource.get("id"), {
 	        line: item.location.start.line
 	      });
 	    }
 
@@ -26359,19 +26381,19 @@ return /******/ (function(modules) { // 
 	      return;
 	    }
 
 	    this.traverseResults(e, e.shiftKey);
 	    e.preventDefault();
 	  }
 
 	  onKeyDown(e) {
-	    var _props10 = this.props,
-	        symbolSearchOn = _props10.symbolSearchOn,
-	        symbolSearchResults = _props10.symbolSearchResults;
+	    var _props11 = this.props,
+	        symbolSearchOn = _props11.symbolSearchOn,
+	        symbolSearchResults = _props11.symbolSearchResults;
 
 	    if (!symbolSearchOn || this.props.query == "") {
 	      return;
 	    }
 
 	    var searchResults = symbolSearchResults;
 
 	    if (e.key === "ArrowUp") {
@@ -26389,33 +26411,33 @@ return /******/ (function(modules) { // 
 	    } else if (e.key === "Tab") {
 	      this.closeSearch(e);
 	      e.preventDefault();
 	    }
 	  }
 
 	  // Renderers
 	  buildSummaryMsg() {
-	    var _props11 = this.props,
-	        symbolSearchOn = _props11.symbolSearchOn,
-	        symbolSearchResults = _props11.symbolSearchResults;
+	    var _props12 = this.props,
+	        symbolSearchOn = _props12.symbolSearchOn,
+	        symbolSearchResults = _props12.symbolSearchResults;
 
 	    if (symbolSearchOn) {
 	      if (symbolSearchResults.length > 1) {
 	        return L10N.getFormatStr("editor.searchResults", this.state.selectedResultIndex + 1, symbolSearchResults.length);
 	      } else if (symbolSearchResults.length === 1) {
 	        return L10N.getFormatStr("editor.singleResult");
 	      }
 	    }
 
-	    var _props12 = this.props,
-	        _props12$searchResult = _props12.searchResults,
-	        count = _props12$searchResult.count,
-	        index = _props12$searchResult.index,
-	        query = _props12.query;
+	    var _props13 = this.props,
+	        _props13$searchResult = _props13.searchResults,
+	        count = _props13$searchResult.count,
+	        index = _props13$searchResult.index,
+	        query = _props13.query;
 
 
 	    if (query.trim() == "") {
 	      return "";
 	    }
 
 	    if (count == 0) {
 	      return L10N.getStr("editor.noResults");
@@ -26424,33 +26446,33 @@ return /******/ (function(modules) { // 
 	    if (index == -1) {
 	      return L10N.getFormatStr("sourceSearch.resultsSummary1", count);
 	    }
 
 	    return L10N.getFormatStr("editor.searchResults", index + 1, count);
 	  }
 
 	  buildPlaceHolder() {
-	    var _props13 = this.props,
-	        symbolSearchOn = _props13.symbolSearchOn,
-	        selectedSymbolType = _props13.selectedSymbolType;
+	    var _props14 = this.props,
+	        symbolSearchOn = _props14.symbolSearchOn,
+	        selectedSymbolType = _props14.selectedSymbolType;
 
 	    if (symbolSearchOn) {
 	      // prettier-ignore
 	      return L10N.getFormatStr(`symbolSearch.search.${selectedSymbolType}Placeholder`);
 	    }
 
 	    return L10N.getStr("sourceSearch.search.placeholder");
 	  }
 
 	  renderSearchModifiers() {
-	    var _props14 = this.props,
-	        modifiers = _props14.modifiers,
-	        toggleFileSearchModifier = _props14.toggleFileSearchModifier,
-	        symbolSearchOn = _props14.symbolSearchOn;
+	    var _props15 = this.props,
+	        modifiers = _props15.modifiers,
+	        toggleFileSearchModifier = _props15.toggleFileSearchModifier,
+	        symbolSearchOn = _props15.symbolSearchOn;
 
 
 	    if (symbolSearchOn) {
 	      return null;
 	    }
 
 	    function searchModBtn(modVal, className, svgName, tooltip) {
 	      return _react.DOM.button({
@@ -26461,71 +26483,93 @@ return /******/ (function(modules) { // 
 	        title: tooltip
 	      }, (0, _Svg2.default)(svgName));
 	    }
 
 	    return _react.DOM.div({ className: "search-modifiers" }, searchModBtn("regexMatch", "regex-match-btn", "regex-match", L10N.getStr("symbolSearch.searchModifier.regex")), searchModBtn("caseSensitive", "case-sensitive-btn", "case-match", L10N.getStr("symbolSearch.searchModifier.caseSensitive")), searchModBtn("wholeWord", "whole-word-btn", "whole-word-match", L10N.getStr("symbolSearch.searchModifier.wholeWord")));
 	  }
 
 	  renderSearchTypeToggle() {
-	    var toggleSymbolSearch = this.toggleSymbolSearch;
-	    var _props15 = this.props,
-	        symbolSearchOn = _props15.symbolSearchOn,
-	        selectedSymbolType = _props15.selectedSymbolType;
-
-
-	    function searchTypeBtn(searchType) {
+	    var toggleSymbolSearch = this.toggleSymbolSearch,
+	        toggleTextSearch = this.toggleTextSearch;
+	    var _props16 = this.props,
+	        symbolSearchOn = _props16.symbolSearchOn,
+	        selectedSymbolType = _props16.selectedSymbolType;
+
+
+	    function isButtonActive(searchType) {
+	      switch (searchType) {
+	        case "functions":
+	        case "variables":
+	          return symbolSearchOn && selectedSymbolType == searchType;
+	        // text search
+	        default:
+	          return !symbolSearchOn;
+	      }
+	    }
+
+	    function searchTextBtn() {
+	      var searchType = "text";
+	      var active = isButtonActive(searchType);
+
 	      return _react.DOM.button({
 	        className: (0, _classnames2.default)("search-type-btn", {
-	          active: symbolSearchOn && selectedSymbolType == searchType
+	          active
 	        }),
-	        onClick: e => {
-	          if (selectedSymbolType == searchType) {
-	            toggleSymbolSearch(e, { toggle: true, searchType });
-	            return;
-	          }
-	          toggleSymbolSearch(e, { toggle: false, searchType });
-	        }
+	        onClick: e => toggleTextSearch(e)
 	      }, searchType);
 	    }
 
-	    return _react.DOM.section({ className: "search-type-toggles" }, _react.DOM.h1({ className: "search-toggle-title" }, L10N.getStr("editor.searchTypeToggleTitle")), searchTypeBtn("functions"), searchTypeBtn("variables"));
+	    function searchTypeBtn(searchType) {
+	      var active = isButtonActive(searchType);
+	      var toggle = selectedSymbolType == searchType;
+
+	      return _react.DOM.button({
+	        className: (0, _classnames2.default)("search-type-btn", {
+	          active
+	        }),
+	        onClick: e => toggleSymbolSearch(e, { toggle, searchType })
+	      }, searchType);
+	    }
+
+	    return _react.DOM.section({ className: "search-type-toggles" }, _react.DOM.h1({ className: "search-toggle-title" }, L10N.getStr("editor.searchTypeToggleTitle")), searchTextBtn(), searchTypeBtn("functions"), searchTypeBtn("variables"));
 	  }
 
 	  renderBottomBar() {
 	    return _react.DOM.div({ className: "search-bottom-bar" }, this.renderSearchTypeToggle(), this.renderSearchModifiers());
 	  }
 
 	  renderResults() {
 	    var selectedResultIndex = this.state.selectedResultIndex;
-	    var _props16 = this.props,
-	        query = _props16.query,
-	        symbolSearchResults = _props16.symbolSearchResults,
-	        symbolSearchOn = _props16.symbolSearchOn;
+	    var _props17 = this.props,
+	        query = _props17.query,
+	        symbolSearchResults = _props17.symbolSearchResults,
+	        symbolSearchOn = _props17.symbolSearchOn;
 
 	    if (query == "" || !symbolSearchOn || !symbolSearchResults.length) {
 	      return;
 	    }
 
 	    return ResultList({
 	      items: symbolSearchResults,
 	      selected: selectedResultIndex,
 	      selectItem: this.selectResultItem,
 	      ref: "resultList"
 	    });
 	  }
 
 	  render() {
-	    var _props17 = this.props,
-	        count = _props17.searchResults.count,
-	        query = _props17.query,
-	        searchOn = _props17.searchOn;
-
-
-	    if (!searchOn) {
+	    var _props18 = this.props,
+	        count = _props18.searchResults.count,
+	        query = _props18.query,
+	        searchOn = _props18.searchOn,
+	        symbolSearchOn = _props18.symbolSearchOn;
+
+
+	    if (!searchOn && !symbolSearchOn) {
 	      return _react.DOM.div();
 	    }
 
 	    return _react.DOM.div({ className: "search-bar" }, SearchInput({
 	      query,
 	      count,
 	      placeholder: this.buildPlaceHolder(),
 	      summaryMsg: this.buildSummaryMsg(),
@@ -26696,25 +26740,297 @@ return /******/ (function(modules) { // 
 /* 553 */,
 /* 554 */,
 /* 555 */,
 /* 556 */,
 /* 557 */,
 /* 558 */,
 /* 559 */,
 /* 560 */,
-/* 561 */,
-/* 562 */,
-/* 563 */,
-/* 564 */,
-/* 565 */,
-/* 566 */,
-/* 567 */,
-/* 568 */,
-/* 569 */,
+/* 561 */
+/***/ function(module, exports, __webpack_require__) {
+
+	var baseUniq = __webpack_require__(562);
+
+	/**
+	 * Creates a duplicate-free version of an array, using
+	 * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
+	 * for equality comparisons, in which only the first occurrence of each element
+	 * is kept. The order of result values is determined by the order they occur
+	 * in the array.
+	 *
+	 * @static
+	 * @memberOf _
+	 * @since 0.1.0
+	 * @category Array
+	 * @param {Array} array The array to inspect.
+	 * @returns {Array} Returns the new duplicate free array.
+	 * @example
+	 *
+	 * _.uniq([2, 1, 2]);
+	 * // => [2, 1]
+	 */
+	function uniq(array) {
+	  return (array && array.length) ? baseUniq(array) : [];
+	}
+
+	module.exports = uniq;
+
+
+/***/ },
+/* 562 */
+/***/ function(module, exports, __webpack_require__) {
+
+	var SetCache = __webpack_require__(276),
+	    arrayIncludes = __webpack_require__(563),
+	    arrayIncludesWith = __webpack_require__(567),
+	    cacheHas = __webpack_require__(280),
+	    createSet = __webpack_require__(568),
+	    setToArray = __webpack_require__(283);
+
+	/** Used as the size to enable large array optimizations. */
+	var LARGE_ARRAY_SIZE = 200;
+
+	/**
+	 * The base implementation of `_.uniqBy` without support for iteratee shorthands.
+	 *
+	 * @private
+	 * @param {Array} array The array to inspect.
+	 * @param {Function} [iteratee] The iteratee invoked per element.
+	 * @param {Function} [comparator] The comparator invoked per element.
+	 * @returns {Array} Returns the new duplicate free array.
+	 */
+	function baseUniq(array, iteratee, comparator) {
+	  var index = -1,
+	      includes = arrayIncludes,
+	      length = array.length,
+	      isCommon = true,
+	      result = [],
+	      seen = result;
+
+	  if (comparator) {
+	    isCommon = false;
+	    includes = arrayIncludesWith;
+	  }
+	  else if (length >= LARGE_ARRAY_SIZE) {
+	    var set = iteratee ? null : createSet(array);
+	    if (set) {
+	      return setToArray(set);
+	    }
+	    isCommon = false;
+	    includes = cacheHas;
+	    seen = new SetCache;
+	  }
+	  else {
+	    seen = iteratee ? [] : result;
+	  }
+	  outer:
+	  while (++index < length) {
+	    var value = array[index],
+	        computed = iteratee ? iteratee(value) : value;
+
+	    value = (comparator || value !== 0) ? value : 0;
+	    if (isCommon && computed === computed) {
+	      var seenIndex = seen.length;
+	      while (seenIndex--) {
+	        if (seen[seenIndex] === computed) {
+	          continue outer;
+	        }
+	      }
+	      if (iteratee) {
+	        seen.push(computed);
+	      }
+	      result.push(value);
+	    }
+	    else if (!includes(seen, computed, comparator)) {
+	      if (seen !== result) {
+	        seen.push(computed);
+	      }
+	      result.push(value);
+	    }
+	  }
+	  return result;
+	}
+
+	module.exports = baseUniq;
+
+
+/***/ },
+/* 563 */
+/***/ function(module, exports, __webpack_require__) {
+
+	var baseIndexOf = __webpack_require__(564);
+
+	/**
+	 * A specialized version of `_.includes` for arrays without support for
+	 * specifying an index to search from.
+	 *
+	 * @private
+	 * @param {Array} [array] The array to inspect.
+	 * @param {*} target The value to search for.
+	 * @returns {boolean} Returns `true` if `target` is found, else `false`.
+	 */
+	function arrayIncludes(array, value) {
+	  var length = array == null ? 0 : array.length;
+	  return !!length && baseIndexOf(array, value, 0) > -1;
+	}
+
+	module.exports = arrayIncludes;
+
+
+/***/ },
+/* 564 */
+/***/ function(module, exports, __webpack_require__) {
+
+	var baseFindIndex = __webpack_require__(263),
+	    baseIsNaN = __webpack_require__(565),
+	    strictIndexOf = __webpack_require__(566);
+
+	/**
+	 * The base implementation of `_.indexOf` without `fromIndex` bounds checks.
+	 *
+	 * @private
+	 * @param {Array} array The array to inspect.
+	 * @param {*} value The value to search for.
+	 * @param {number} fromIndex The index to search from.
+	 * @returns {number} Returns the index of the matched value, else `-1`.
+	 */
+	function baseIndexOf(array, value, fromIndex) {
+	  return value === value
+	    ? strictIndexOf(array, value, fromIndex)
+	    : baseFindIndex(array, baseIsNaN, fromIndex);
+	}
+
+	module.exports = baseIndexOf;
+
+
+/***/ },
+/* 565 */
+/***/ function(module, exports) {
+
+	/**
+	 * The base implementation of `_.isNaN` without support for number objects.
+	 *
+	 * @private
+	 * @param {*} value The value to check.
+	 * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.
+	 */
+	function baseIsNaN(value) {
+	  return value !== value;
+	}
+
+	module.exports = baseIsNaN;
+
+
+/***/ },
+/* 566 */
+/***/ function(module, exports) {
+
+	/**
+	 * A specialized version of `_.indexOf` which performs strict equality
+	 * comparisons of values, i.e. `===`.
+	 *
+	 * @private
+	 * @param {Array} array The array to inspect.
+	 * @param {*} value The value to search for.
+	 * @param {number} fromIndex The index to search from.
+	 * @returns {number} Returns the index of the matched value, else `-1`.
+	 */
+	function strictIndexOf(array, value, fromIndex) {
+	  var index = fromIndex - 1,
+	      length = array.length;
+
+	  while (++index < length) {
+	    if (array[index] === value) {
+	      return index;
+	    }
+	  }
+	  return -1;
+	}
+
+	module.exports = strictIndexOf;
+
+
+/***/ },
+/* 567 */
+/***/ function(module, exports) {
+
+	/**
+	 * This function is like `arrayIncludes` except that it accepts a comparator.
+	 *
+	 * @private
+	 * @param {Array} [array] The array to inspect.
+	 * @param {*} target The value to search for.
+	 * @param {Function} comparator The comparator invoked per element.
+	 * @returns {boolean} Returns `true` if `target` is found, else `false`.
+	 */
+	function arrayIncludesWith(array, value, comparator) {
+	  var index = -1,
+	      length = array == null ? 0 : array.length;
+
+	  while (++index < length) {
+	    if (comparator(value, array[index])) {
+	      return true;
+	    }
+	  }
+	  return false;
+	}
+
+	module.exports = arrayIncludesWith;
+
+
+/***/ },
+/* 568 */
+/***/ function(module, exports, __webpack_require__) {
+
+	var Set = __webpack_require__(201),
+	    noop = __webpack_require__(569),
+	    setToArray = __webpack_require__(283);
+
+	/** Used as references for various `Number` constants. */
+	var INFINITY = 1 / 0;
+
+	/**
+	 * Creates a set object of `values`.
+	 *
+	 * @private
+	 * @param {Array} values The values to add to the set.
+	 * @returns {Object} Returns the new set.
+	 */
+	var createSet = !(Set && (1 / setToArray(new Set([,-0]))[1]) == INFINITY) ? noop : function(values) {
+	  return new Set(values);
+	};
+
+	module.exports = createSet;
+
+
+/***/ },
+/* 569 */
+/***/ function(module, exports) {
+
+	/**
+	 * This method returns `undefined`.
+	 *
+	 * @static
+	 * @memberOf _
+	 * @since 2.3.0
+	 * @category Util
+	 * @example
+	 *
+	 * _.times(2, _.noop);
+	 * // => [undefined, undefined]
+	 */
+	function noop() {
+	  // No operation performed.
+	}
+
+	module.exports = noop;
+
+
+/***/ },
 /* 570 */,
 /* 571 */,
 /* 572 */,
 /* 573 */,
 /* 574 */,
 /* 575 */,
 /* 576 */,
 /* 577 */,
@@ -27424,17 +27740,17 @@ return /******/ (function(modules) { // 
 	      contents: { value }
 	    };
 
 	    if (value.class === "Function") {
 	      return this.renderFunctionPreview(value, root);
 	    }
 
 	    if (value.type === "object") {
-	      return _react.DOM.div({}, this.renderObjectPreview(expression, root), this.renderAddToExpressionBar(expression, value));
+	      return _react.DOM.div({}, this.renderObjectPreview(expression, root), this.renderAddToExpressionBar(expression));
 	    }
 
 	    return this.renderSimplePreview(value);
 	  }
 
 	  getPreviewType(value) {
 	    if (typeof value == "boolean" || value.class === "Function") {
 	      return "tooltip";
@@ -30193,18 +30509,16 @@ return /******/ (function(modules) { // 
 	"use strict";
 
 	Object.defineProperty(exports, "__esModule", {
 	  value: true
 	});
 
 	var _react = __webpack_require__(2);
 
-	var _reactDom = __webpack_require__(31);
-
 	var _reactRedux = __webpack_require__(151);
 
 	var _redux = __webpack_require__(3);
 
 	var _selectors = __webpack_require__(242);
 
 	var _Svg = __webpack_require__(344);
 
@@ -30267,31 +30581,16 @@ return /******/ (function(modules) { // 
 	  if (isMacOS) {
 	    var winKey = getKeyForOS("WINNT", `${action}Display`) || getKeyForOS("WINNT", action);
 	    // display both Windows type and Mac specific keys
 	    return (0, _text.formatKeyShortcut)([key, winKey].join(" "));
 	  }
 	  return (0, _text.formatKeyShortcut)(key);
 	}
 
-	function handlePressAnimation(button) {
-	  if (!button) {
-	    return;
-	  }
-
-	  button.style.opacity = "0";
-	  button.style.transform = "scale(1.3)";
-	  setTimeout(() => {
-	    if (button) {
-	      button.style.opacity = "1";
-	      button.style.transform = "none";
-	    }
-	  }, 200);
-	}
-
 	function debugBtn(onClick, type, className, tooltip) {
 	  var disabled = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
 
 	  className = `${type} ${className}`;
 	  return _react.DOM.button({
 	    onClick,
 	    className,
 	    key: type,
@@ -30323,20 +30622,16 @@ return /******/ (function(modules) { // 
 	    }
 	  }
 
 	  handleEvent(e, action) {
 	    e.preventDefault();
 	    e.stopPropagation();
 
 	    this.props[action]();
-	    var node = (0, _reactDom.findDOMNode)(this);
-	    if (node instanceof HTMLElement) {
-	      handlePressAnimation(node.querySelector(`.${action}`));
-	    }
 	  }
 
 	  renderStepButtons() {
 	    var isPaused = this.props.pause;
 	    var className = isPaused ? "active" : "disabled";
 	    var isDisabled = !this.props.pause;
 
 	    return [debugBtn(this.props.stepOver, "stepOver", className, L10N.getFormatStr("stepOverTooltip", formatKey("stepOver")), isDisabled), debugBtn(this.props.stepIn, "stepIn", className, L10N.getFormatStr("stepInTooltip", formatKey("stepIn")), isDisabled), debugBtn(this.props.stepOut, "stepOut", className, L10N.getFormatStr("stepOutTooltip", formatKey("stepOut")), isDisabled)];
@@ -31968,17 +32263,17 @@ return /******/ (function(modules) { // 
 	      url: tab.url,
 	      id: tab.actor,
 	      tab,
 	      clientType: "firefox"
 	    };
 	  });
 	}
 
-	function initPage() {}
+	function initPage(options) {}
 
 	module.exports = {
 	  connectClient,
 	  connectTab,
 	  initPage,
 	  getTabs
 	};
 
@@ -32173,16 +32468,17 @@ return /******/ (function(modules) { // 
 	    yield loadFromPrefs(actions);
 
 	    window.getGlobalsForTesting = function () {
 	      return {
 	        store,
 	        actions,
 	        selectors,
 	        client: client.clientCommands,
+	        prefs: _prefs.prefs,
 	        connection
 	      };
 	    };
 
 	    if (!(0, _devtoolsConfig.isFirefoxPanel)()) {
 	      console.group("Developement Notes");
 	      var baseUrl = "https://devtools-html.github.io/debugger.html";
 	      var localDevelopmentUrl = `${baseUrl}/docs/local-development.html`;
@@ -32272,16 +32568,17 @@ return /******/ (function(modules) { // 
 
 	    // In Firefox, we need to initially request all of the sources. This
 	    // usually fires off individual `newSource` notifications as the
 	    // debugger finds them, but there may be existing sources already in
 	    // the debugger (if it's paused already, or if loading the page from
 	    // bfcache) so explicity fire `newSource` events for all returned
 	    // sources.
 	    var sources = yield _commands.clientCommands.fetchSources();
+	    actions.navigate(tabTarget._form.url);
 	    yield actions.newSources(sources);
 
 	    // If the threadClient is already paused, make sure to show a
 	    // paused state.
 	    var pausedPacket = threadClient.getLastPausePacket();
 	    if (pausedPacket) {
 	      _events.clientEvents.paused("paused", pausedPacket);
 	    }
@@ -33474,28 +33771,27 @@ return /******/ (function(modules) { // 
 	Object.defineProperty(exports, "__esModule", {
 	  value: true
 	});
 	exports.prettyPrint = exports.stopPrettyPrintWorker = exports.startPrettyPrintWorker = undefined;
 
 	var prettyPrint = exports.prettyPrint = (() => {
 	  var _ref = _asyncToGenerator(function* (_ref2) {
 	    var source = _ref2.source,
-	        sourceText = _ref2.sourceText,
 	        url = _ref2.url;
 
-	    var contentType = sourceText ? sourceText.contentType : "";
+	    var contentType = source.contentType;
 	    var indent = 2;
 
 	    (0, _assert2.default)((0, _source.isJavaScript)(source.url, contentType), "Can't prettify non-javascript files.");
 
 	    return yield _prettyPrint({
 	      url,
 	      indent,
-	      source: sourceText ? sourceText.text : undefined
+	      source: source.text
 	    });
 	  });
 
 	  return function prettyPrint(_x) {
 	    return _ref.apply(this, arguments);
 	  };
 	})();
 
@@ -47388,17 +47684,17 @@ return /******/ (function(modules) { // 
 	var _Frame = __webpack_require__(1013);
 
 	var _Frame2 = _interopRequireDefault(_Frame);
 
 	var _Group2 = __webpack_require__(1015);
 
 	var _Group3 = _interopRequireDefault(_Group2);
 
-	var _WhyPaused = __webpack_require__(1119);
+	var _WhyPaused = __webpack_require__(1120);
 
 	var _WhyPaused2 = _interopRequireDefault(_WhyPaused);
 
 	var _actions = __webpack_require__(244);
 
 	var _actions2 = _interopRequireDefault(_actions);
 
 	var _frame = __webpack_require__(1014);
@@ -47765,16 +48061,20 @@ return /******/ (function(modules) { // 
 	function isUnderscore(frame) {
 	  return getFrameUrl(frame).match(/underscore/i);
 	}
 
 	function isLodash(frame) {
 	  return getFrameUrl(frame).match(/lodash/i);
 	}
 
+	function isEmber(frame) {
+	  return getFrameUrl(frame).match(/ember/i);
+	}
+
 	function getLibraryFromUrl(frame) {
 	  // @TODO each of these fns calls getFrameUrl, just call it once
 	  // (assuming there's not more complex logic to identify a lib)
 
 	  if (isBackbone(frame)) {
 	    return "Backbone";
 	  }
 
@@ -47808,29 +48108,34 @@ return /******/ (function(modules) { // 
 
 	  if (isUnderscore(frame)) {
 	    return "Underscore";
 	  }
 
 	  if (isLodash(frame)) {
 	    return "Lodash";
 	  }
+
+	  if (isEmber(frame)) {
+	    return "Ember";
+	  }
 	}
 
 	var displayNameMap = {
 	  Backbone: {
 	    "extend/child": "Create Class",
 	    ".create": "Create Model"
 	  },
 	  jQuery: {
 	    "jQuery.event.dispatch": "Dispatch Event"
 	  },
 	  React: {
 	    // eslint-disable-next-line max-len
-	    "ReactCompositeComponent._renderValidatedComponentWithoutOwnerOrContext/renderedElement<": "Render"
+	    "ReactCompositeComponent._renderValidatedComponentWithoutOwnerOrContext/renderedElement<": "Render",
+	    _renderValidatedComponentWithoutOwnerOrContext: "Render"
 	  },
 	  Webpack: {
 	    // eslint-disable-next-line camelcase
 	    __webpack_require__: "Bootstrap"
 	  }
 	};
 
 	function mapDisplayNames(frame, library) {
@@ -66172,28 +66477,33 @@ return /******/ (function(modules) { // 
 	          return state.set("selection", { updating: true });
 	        }
 
 	        if (!action.value) {
 	          return state.set("selection", null);
 	        }
 
 	        var _action$value = action.value,
-	            expression = _action$value.expression,
-	            location = _action$value.location,
-	            result = _action$value.result;
+	            _expression = _action$value.expression,
+	            _location = _action$value.location,
+	            _result = _action$value.result;
 
 	        return state.set("selection", {
 	          updating: false,
-	          expression,
-	          location,
-	          result
+	          expression: _expression,
+	          location: _location,
+	          result: _result
 	        });
 	      }
 
+	    case "RESUMED":
+	      {
+	        return state.set("outOfScopeLocations", null);
+	      }
+
 	    default:
 	      {
 	        return state;
 	      }
 	  }
 	}
 
 	// NOTE: we'd like to have the app state fully typed
@@ -66247,32 +66557,33 @@ return /******/ (function(modules) { // 
 	var _parser = __webpack_require__(827);
 
 	var parser = _interopRequireWildcard(_parser);
 
 	function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
 
 	function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
 
-	function setSymbols(source) {
+	function setSymbols(sourceId) {
 	  return (() => {
 	    var _ref = _asyncToGenerator(function* (_ref2) {
 	      var dispatch = _ref2.dispatch,
 	          getState = _ref2.getState;
 
-	      if ((0, _selectors.hasSymbols)(getState(), source)) {
+	      var sourceRecord = (0, _selectors.getSource)(getState(), sourceId);
+	      if (!sourceRecord) {
 	        return;
 	      }
 
-	      var sourceText = (0, _selectors.getSourceText)(getState(), source.id);
-	      if (!sourceText) {
+	      var source = sourceRecord.toJS();
+	      if (!source.text || (0, _selectors.hasSymbols)(getState(), source)) {
 	        return;
 	      }
 
-	      var symbols = yield parser.getSymbols(sourceText.toJS());
+	      var symbols = yield parser.getSymbols(source);
 
 	      dispatch({
 	        type: "SET_SYMBOLS",
 	        source,
 	        symbols
 	      });
 	    });
 
@@ -66284,26 +66595,30 @@ return /******/ (function(modules) { // 
 
 	function setOutOfScopeLocations() {
 	  return (() => {
 	    var _ref3 = _asyncToGenerator(function* (_ref4) {
 	      var dispatch = _ref4.dispatch,
 	          getState = _ref4.getState;
 
 	      var location = (0, _selectors.getSelectedLocation)(getState());
-	      var sourceText = (0, _selectors.getSourceText)(getState(), location.sourceId);
-
-	      if (!location.line || !sourceText) {
+	      if (!location) {
+	        return;
+	      }
+
+	      var source = (0, _selectors.getSource)(getState(), location.sourceId);
+
+	      if (!location.line || !source) {
 	        return dispatch({
 	          type: "OUT_OF_SCOPE_LOCATIONS",
 	          locations: null
 	        });
 	      }
 
-	      var locations = yield parser.getOutOfScopeLocations(sourceText.toJS(), location);
+	      var locations = yield parser.getOutOfScopeLocations(source.toJS(), location);
 
 	      return dispatch({
 	        type: "OUT_OF_SCOPE_LOCATIONS",
 	        locations
 	      });
 	    });
 
 	    return function (_x2) {
@@ -66336,36 +66651,36 @@ return /******/ (function(modules) { // 
 	          getState = _ref7.getState,
 	          client = _ref7.client;
 
 	      var currentSelection = (0, _selectors.getSelection)(getState());
 	      if (currentSelection && currentSelection.updating) {
 	        return;
 	      }
 
-	      var sourceText = (0, _selectors.getSelectedSourceText)(getState());
-	      var selectedFrame = (0, _selectors.getSelectedFrame)(getState());
-
 	      yield dispatch({
 	        type: "SET_SELECTION",
 	        [_promise.PROMISE]: _asyncToGenerator(function* () {
-	          var closestExpression = yield parser.getClosestExpression(sourceText.toJS(), token, position);
+	          var source = (0, _selectors.getSelectedSource)(getState());
+	          var closestExpression = yield parser.getClosestExpression(source.toJS(), token, position);
 
 	          if (!closestExpression) {
 	            return;
 	          }
 
 	          var expression = closestExpression.expression,
 	              location = closestExpression.location;
 
 
 	          if (!expression) {
 	            return;
 	          }
 
+	          var selectedFrame = (0, _selectors.getSelectedFrame)(getState());
+
 	          var _ref9 = yield client.evaluate(expression, {
 	            frameId: selectedFrame.id
 	          }),
 	              result = _ref9.result;
 
 	          return {
 	            expression,
 	            result,
@@ -66473,36 +66788,36 @@ return /******/ (function(modules) { // 
 
 	  constructor(props) {
 	    super(props);
 
 	    this.state = {
 	      inputValue: ""
 	    };
 
-	    this.toggle = this.toggle.bind(this);
+	    this.toggleProjectSearch = this.toggleProjectSearch.bind(this);
 	    this.onEscape = this.onEscape.bind(this);
 	    this.close = this.close.bind(this);
 	  }
 
 	  componentWillUnmount() {
 	    var shortcuts = this.context.shortcuts;
 	    var searchKeys = [L10N.getStr("sources.search.key2"), L10N.getStr("sources.search.key2")];
-	    searchKeys.forEach(key => shortcuts.off(key, this.toggle));
+	    searchKeys.forEach(key => shortcuts.off(key, this.toggleProjectSearch));
 	    shortcuts.off("Escape", this.onEscape);
 	  }
 
 	  componentDidMount() {
 	    var shortcuts = this.context.shortcuts;
 	    var searchKeys = [L10N.getStr("sources.search.key2"), L10N.getStr("sources.search.alt.key")];
-	    searchKeys.forEach(key => shortcuts.on(key, this.toggle));
+	    searchKeys.forEach(key => shortcuts.on(key, this.toggleProjectSearch));
 	    shortcuts.on("Escape", this.onEscape);
 	  }
 
-	  toggle(key, e) {
+	  toggleProjectSearch(key, e) {
 	    e.preventDefault();
 	    this.props.toggleProjectSearch();
 	  }
 
 	  onEscape(shortcut, e) {
 	    if (this.props.searchOn) {
 	      e.preventDefault();
 	      this.close();
@@ -66578,18 +66893,16 @@ return /******/ (function(modules) { // 
 	exports.searchSource = searchSource;
 
 	function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
 
 	function searchSource(source, queryText) {
 	  var _ref;
 
 	  var text = source.text,
-	      id = source.id,
-	      url = source.url,
 	      loading = source.loading;
 
 	  if (loading || !text || queryText == "") {
 	    return [];
 	  }
 
 	  var lines = text.split("\n");
 	  var result = undefined;
@@ -66598,19 +66911,18 @@ return /******/ (function(modules) { // 
 	  var matches = lines.map((_text, line) => {
 	    var indices = [];
 
 	    while (result = query.exec(_text)) {
 	      indices.push({
 	        line: line + 1,
 	        column: result.index,
 	        match: result[0],
-	        text: result.input,
-	        id,
-	        url
+	        value: _text,
+	        text: result.input
 	      });
 	    }
 	    return indices;
 	  }).filter(_matches => _matches.length > 0);
 
 	  matches = (_ref = []).concat.apply(_ref, _toConsumableArray(matches));
 	  return matches;
 	}
@@ -66641,64 +66953,131 @@ return /******/ (function(modules) { // 
 	var _Svg = __webpack_require__(344);
 
 	var _Svg2 = _interopRequireDefault(_Svg);
 
 	var _ManagedTree2 = __webpack_require__(419);
 
 	var _ManagedTree3 = _interopRequireDefault(_ManagedTree2);
 
+	var _SearchInput2 = __webpack_require__(377);
+
+	var _SearchInput3 = _interopRequireDefault(_SearchInput2);
+
+	var _projectSearch = __webpack_require__(1061);
+
 	__webpack_require__(1065);
 
 	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
+	function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
+
 	var ManagedTree = (0, _react.createFactory)(_ManagedTree3.default);
 
+	var SearchInput = (0, _react.createFactory)(_SearchInput3.default);
+
+	function search(query, sources) {
+	  var validSources = sources.valueSeq().filter(s => s.has("text")).toJS();
+	  return validSources.map(source => ({
+	    source,
+	    filepath: source.url,
+	    matches: (0, _projectSearch.searchSource)(source, query)
+	  }));
+	}
+
 	class TextSearch extends _react.Component {
 	  constructor(props) {
 	    super(props);
+	    this.state = {
+	      results: [],
+	      inputValue: props.inputValue || "",
+	      selectedIndex: 0,
+	      focused: false
+	    };
+	  }
+
+	  inputOnChange(e) {
+	    var _this = this;
+
+	    return _asyncToGenerator(function* () {
+	      var sources = _this.props.sources;
+
+	      var inputValue = e.target.value;
+	      var results = yield search(inputValue, sources);
+
+	      _this.setState({
+	        results,
+	        inputValue,
+	        selectedIndex: 0
+	      });
+	    })();
 	  }
 
 	  renderFile(file, expanded) {
 	    return _react.DOM.div({
-	      className: "file-result"
+	      className: "file-result",
+	      key: file.filepath
 	    }, (0, _Svg2.default)("arrow", {
 	      className: (0, _classnames2.default)({
 	        expanded
 	      })
 	    }), file.filepath);
 	  }
 
-	  renderLine(match) {
-	    return _react.DOM.div({ className: "result" }, _react.DOM.span({
+	  renderMatch(match) {
+	    return _react.DOM.div({ className: "result", key: `${match.line}/${match.column}` }, _react.DOM.span({
 	      className: "line-number"
 	    }, match.line), _react.DOM.span({ className: "line-match" }, match.value));
 	  }
 
 	  renderResults() {
-	    var results = this.props.results;
+	    var results = this.state.results;
 
 	    return ManagedTree({
 	      getRoots: () => results,
 	      getChildren: file => {
 	        return file.matches || [];
 	      },
 	      itemHeight: 20,
 	      autoExpand: 1,
 	      autoExpandDepth: 1,
 	      getParent: item => null,
 	      getKey: item => item.filepath || `${item.value}/${item.line}`,
-	      renderItem: (item, depth, focused, _, expanded) => item.filepath ? this.renderFile(item, expanded) : this.renderLine(item)
+	      renderItem: (item, depth, focused, _, expanded) => item.filepath ? this.renderFile(item, expanded) : this.renderMatch(item)
+	    });
+	  }
+
+	  resultCount() {
+	    var results = this.state.results;
+
+	    return results.reduce((count, file) => count + (file.matches ? file.matches.length : 0), 0);
+	  }
+
+	  renderInput() {
+	    var resultCount = this.resultCount();
+	    var summaryMsg = L10N.getFormatStr("sourceSearch.resultsSummary1", resultCount);
+
+	    return SearchInput({
+	      query: this.state.inputValue,
+	      count: resultCount,
+	      placeholder: "Search Project",
+	      size: "big",
+	      summaryMsg,
+	      onChange: e => this.inputOnChange(e),
+	      onFocus: () => this.setState({ focused: true }),
+	      onBlur: () => this.setState({ focused: false }),
+	      onKeyDown: this.onKeyDown,
+	      handleClose: this.props.close
 	    });
 	  }
 
 	  render() {
 	    return _react.DOM.div({
 	      className: "project-text-search"
-	    }, this.renderResults());
+	    }, this.renderInput(), this.renderResults());
 	  }
 	}
 
 	exports.default = TextSearch;
 	TextSearch.displayName = "TextSearch";
 
 /***/ },
 /* 1065 */
@@ -67047,16 +67426,22 @@ return /******/ (function(modules) { // 
 /***/ },
 /* 1118 */
 /***/ function(module, exports) {
 
 	module.exports = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 2500 2500\"><path d=\"M70 188.5h220v1460h870v180H70v-1640zm1776 396c-225-3-450 140-520 357-100 250-54 564 142 755 190 158 476 170 690 58 147-78 240-233 260-396 26-170 13-356-70-510-98-164-290-270-480-263l-22-3zm20 174c165 0 313 126 340 288 50 183 20 407-130 536-140 114-365 98-480-43-140-150-140-380-68-560 50-130 183-223 323-220h18z\" fill=\"#000000\"></path><path d=\"M70 2061.5h2360v250H70v-250z\" fill=\"#3492ff\"></path></svg>"
 
 /***/ },
 /* 1119 */
+/***/ function(module, exports) {
+
+	module.exports = "<svg viewBox=\"0 0 94 37\" xmlns=\"http://www.w3.org/2000/svg\"><g fill=\"none\" fill-rule=\"evenodd\"><path d=\"M65.21 27.865s-.43-1.546 1.17-4.52c1.6-2.974 2.85-1.348 2.85-1.348s1.364 1.507-.196 3.767-3.823 2.1-3.823 2.1zm-12.288 2.14c-1.833 4.877-6.28 2.895-6.28 2.895s-.507-1.744.936-6.62c1.443-4.878 4.837-2.975 4.837-2.975s2.34 1.824.507 6.7zM49.607 9.588s2.77-7.334 3.432-3.766c.663 3.57-5.813 14.195-5.813 14.195.078-2.38 2.38-10.428 2.38-10.428zM10.01 27.865c.118-4.718 3.16-6.78 4.214-5.75 1.054 1.032.664 3.252-1.326 4.64-1.99 1.387-2.887 1.11-2.887 1.11zm83.912-.783c-.156-1.586-1.56-.996-1.56-.996S90.1 27.868 88.11 27.67c-1.99-.2-1.366-4.72-1.366-4.72s.43-4.143-.74-4.49c-1.17-.348-2.615 1.08-2.615 1.08s-1.795 2.02-2.653 4.598l-.234.08s.273-4.52-.04-5.55c-.234-.517-2.38-.477-2.73.435-.35.912-2.068 7.255-2.185 9.912 0 0-3.355 2.894-6.28 3.37-2.926.475-3.628-1.388-3.628-1.388s7.958-2.26 7.685-8.722c-.273-6.463-6.417-4.074-7.113-3.542-.673.513-4.264 2.715-5.31 8.81-.037.21-.1 1.115-.1 1.115s-3.08 2.1-4.798 2.656c0 0 4.798-8.207-1.053-11.934-2.652-1.625-4.758 1.784-4.758 1.784s7.92-8.96 6.163-16.533c-.836-3.605-2.61-3.992-4.238-3.41-2.47.993-3.408 2.46-3.408 2.46s-3.2 4.718-3.94 11.736c-.742 7.017-1.834 15.502-1.834 15.502s-1.522 1.506-2.926 1.586c-1.404.08-.78-4.243-.78-4.243s1.092-6.58 1.014-7.69c-.078-1.11-.156-1.705-1.443-2.102-1.287-.396-2.69 1.27-2.69 1.27s-3.707 5.708-4.02 6.58l-.194.357-.195-.237s2.615-7.77.118-7.89c-2.497-.12-4.135 2.775-4.135 2.775s-2.848 4.837-2.965 5.392l-.195-.238s1.17-5.63.936-7.017c-.235-1.388-1.522-1.11-1.522-1.11s-1.638-.2-2.068.872c-.43 1.07-1.99 8.167-2.184 10.427 0 0-4.096 2.973-6.788 3.012-2.692.04-2.42-1.735-2.42-1.735s9.87-3.434 7.18-10.214c-1.21-1.744-2.614-2.292-4.604-2.252-1.99.04-4.46 1.273-6.058 4.92-.763 1.742-1.042 3.392-1.198 4.642 0 0-1.728.358-2.664-.435-.936-.793-1.418 0-1.418 0S.11 29.67 1.71 30.304c1.598.634 4.095.93 4.095.93h-.002c.23 1.11.897 2.996 2.844 4.5 2.926 2.26 8.543-.208 8.543-.208l2.3-1.313s.08 2.146 1.756 2.46c1.678.313 2.38-.005 5.306-7.22 1.716-3.688 1.833-3.49 1.833-3.49l.195-.04s-1.326 7.057-.82 8.96c.508 1.903 2.732 1.704 2.732 1.704s1.21.238 2.184-3.25C33.65 29.846 35.524 26 35.524 26h.234s-.82 7.217.43 9.517c1.247 2.3 4.485.773 4.485.773s2.263-1.16 2.614-1.517c0 0 2.686 2.323 6.473 1.902 8.468-1.693 11.48-3.98 11.48-3.98s1.454 3.745 5.96 4.092c5.15.396 7.958-2.895 7.958-2.895s-.04 2.14 1.756 2.894c1.794.753 3.003-3.48 3.003-3.48l3.004-8.415h.274s.156 5.473 3.12 6.345c2.966.872 6.828-2.042 6.828-2.042s.936-.525.78-2.11z\" fill=\"#E34C32\"></path></g></svg>"
+
+/***/ },
+/* 1120 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
 	Object.defineProperty(exports, "__esModule", {
 	  value: true
 	});
 	exports.default = renderWhyPaused;
@@ -67068,17 +67453,17 @@ return /******/ (function(modules) { // 
 	var _isString2 = _interopRequireDefault(_isString);
 
 	var _get = __webpack_require__(67);
 
 	var _get2 = _interopRequireDefault(_get);
 
 	var _pause = __webpack_require__(255);
 
-	__webpack_require__(1120);
+	__webpack_require__(1121);
 
 	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
 	function renderExceptionSummary(exception) {
 	  if ((0, _isString2.default)(exception)) {
 	    return exception;
 	  }
 
@@ -67115,17 +67500,190 @@ return /******/ (function(modules) { // 
 	  if (!reason) {
 	    return null;
 	  }
 
 	  return _react.DOM.div({ className: "pane why-paused" }, _react.DOM.div(null, L10N.getStr(reason)), renderMessage(pause));
 	}
 
 /***/ },
-/* 1120 */
+/* 1121 */
 /***/ function(module, exports) {
 
 	// removed by extract-text-webpack-plugin
 
+/***/ },
+/* 1122 */,
+/* 1123 */,
+/* 1124 */
+/***/ function(module, exports, __webpack_require__) {
+
+	"use strict";
+
+	Object.defineProperty(exports, "__esModule", {
+	  value: true
+	});
+	exports.default = getInScopeLines;
+
+	var _selectors = __webpack_require__(242);
+
+	var _range = __webpack_require__(1026);
+
+	var _range2 = _interopRequireDefault(_range);
+
+	var _flatMap = __webpack_require__(1067);
+
+	var _flatMap2 = _interopRequireDefault(_flatMap);
+
+	var _uniq = __webpack_require__(561);
+
+	var _uniq2 = _interopRequireDefault(_uniq);
+
+	var _without = __webpack_require__(1125);
+
+	var _without2 = _interopRequireDefault(_without);
+
+	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+	function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
+
+	function getOutOfScopeLines(outOfScopeLocations) {
+	  if (!outOfScopeLocations) {
+	    return null;
+	  }
+
+	  return (0, _uniq2.default)((0, _flatMap2.default)(outOfScopeLocations, location => (0, _range2.default)(location.start.line, location.end.line)));
+	}
+
+	function getInScopeLines(state) {
+	  var source = (0, _selectors.getSelectedSource)(state);
+	  var outOfScopeLocations = (0, _selectors.getOutOfScopeLocations)(state);
+
+	  if (!source || !source.get("text")) {
+	    return;
+	  }
+
+	  var linesOutOfScope = getOutOfScopeLines(outOfScopeLocations, source.toJS());
+
+	  var sourceNumLines = source.get("text").split("\n").length;
+	  var sourceLines = (0, _range2.default)(1, sourceNumLines + 1);
+
+	  if (!linesOutOfScope) {
+	    return sourceLines;
+	  }
+
+	  return _without2.default.apply(undefined, [sourceLines].concat(_toConsumableArray(linesOutOfScope)));
+	}
+
+/***/ },
+/* 1125 */
+/***/ function(module, exports, __webpack_require__) {
+
+	var baseDifference = __webpack_require__(1126),
+	    baseRest = __webpack_require__(411),
+	    isArrayLikeObject = __webpack_require__(404);
+
+	/**
+	 * Creates an array excluding all given values using
+	 * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
+	 * for equality comparisons.
+	 *
+	 * **Note:** Unlike `_.pull`, this method returns a new array.
+	 *
+	 * @static
+	 * @memberOf _
+	 * @since 0.1.0
+	 * @category Array
+	 * @param {Array} array The array to inspect.
+	 * @param {...*} [values] The values to exclude.
+	 * @returns {Array} Returns the new array of filtered values.
+	 * @see _.difference, _.xor
+	 * @example
+	 *
+	 * _.without([2, 1, 2, 3], 1, 2);
+	 * // => [3]
+	 */
+	var without = baseRest(function(array, values) {
+	  return isArrayLikeObject(array)
+	    ? baseDifference(array, values)
+	    : [];
+	});
+
+	module.exports = without;
+
+
+/***/ },
+/* 1126 */
+/***/ function(module, exports, __webpack_require__) {
+
+	var SetCache = __webpack_require__(276),
+	    arrayIncludes = __webpack_require__(563),
+	    arrayIncludesWith = __webpack_require__(567),
+	    arrayMap = __webpack_require__(110),
+	    baseUnary = __webpack_require__(215),
+	    cacheHas = __webpack_require__(280);
+
+	/** Used as the size to enable large array optimizations. */
+	var LARGE_ARRAY_SIZE = 200;
+
+	/**
+	 * The base implementation of methods like `_.difference` without support
+	 * for excluding multiple arrays or iteratee shorthands.
+	 *
+	 * @private
+	 * @param {Array} array The array to inspect.
+	 * @param {Array} values The values to exclude.
+	 * @param {Function} [iteratee] The iteratee invoked per element.
+	 * @param {Function} [comparator] The comparator invoked per element.
+	 * @returns {Array} Returns the new array of filtered values.
+	 */
+	function baseDifference(array, values, iteratee, comparator) {
+	  var index = -1,
+	      includes = arrayIncludes,
+	      isCommon = true,
+	      length = array.length,
+	      result = [],
+	      valuesLength = values.length;
+
+	  if (!length) {
+	    return result;
+	  }
+	  if (iteratee) {
+	    values = arrayMap(values, baseUnary(iteratee));
+	  }
+	  if (comparator) {
+	    includes = arrayIncludesWith;
+	    isCommon = false;
+	  }
+	  else if (values.length >= LARGE_ARRAY_SIZE) {
+	    includes = cacheHas;
+	    isCommon = false;
+	    values = new SetCache(values);
+	  }
+	  outer:
+	  while (++index < length) {
+	    var value = array[index],
+	        computed = iteratee == null ? value : iteratee(value);
+
+	    value = (comparator || value !== 0) ? value : 0;
+	    if (isCommon && computed === computed) {
+	      var valuesIndex = valuesLength;
+	      while (valuesIndex--) {
+	        if (values[valuesIndex] === computed) {
+	          continue outer;
+	        }
+	      }
+	      result.push(value);
+	    }
+	    else if (!includes(values, computed, comparator)) {
+	      result.push(value);
+	    }
+	  }
+	  return result;
+	}
+
+	module.exports = baseDifference;
+
+
 /***/ }
 /******/ ])
 });
 ;
\ No newline at end of file
--- a/devtools/client/debugger/new/search-worker.js
+++ b/devtools/client/debugger/new/search-worker.js
@@ -50,17 +50,17 @@ return /******/ (function(modules) { // 
 /******/ 	return __webpack_require__(0);
 /******/ })
 /************************************************************************/
 /******/ ({
 
 /***/ 0:
 /***/ function(module, exports, __webpack_require__) {
 
-	module.exports = __webpack_require__(1122);
+	module.exports = __webpack_require__(1123);
 
 
 /***/ },
 
 /***/ 6:
 /***/ function(module, exports, __webpack_require__) {
 
 	var Symbol = __webpack_require__(7),
@@ -670,17 +670,17 @@ return /******/ (function(modules) { // 
 	    return new RegExp(query, flags);
 	  }
 
 	  return new RegExp(query);
 	}
 
 /***/ },
 
-/***/ 1122:
+/***/ 1123:
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
 	Object.defineProperty(exports, "__esModule", {
 	  value: true
 	});
 	exports.countMatches = countMatches;
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-chrome-create.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-chrome-create.js
@@ -2,69 +2,84 @@
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /**
  * Tests that a chrome debugger can be created in a new process.
  */
 
-const { BrowserToolboxProcess } = Cu.import("resource://devtools/client/framework/ToolboxProcess.jsm", {});
+const { BrowserToolboxProcess } = Cu.import(
+  "resource://devtools/client/framework/ToolboxProcess.jsm",
+  {}
+);
 let gProcess = undefined;
 
 function initChromeDebugger() {
   info("Initializing a chrome debugger process.");
   return new Promise(resolve => {
     BrowserToolboxProcess.init(onClose, (event, _process) => {
       info("Browser toolbox process started successfully.");
       resolve(_process);
     });
   });
 }
 
 function onClose() {
-  is(gProcess._dbgProcess.exitCode, (Services.appinfo.OS == "WINNT" ? -9 : -15),
-    "The remote debugger process didn't die cleanly.");
+  is(
+    gProcess._dbgProcess.exitCode,
+    Services.appinfo.OS == "WINNT" ? -9 : -15,
+    "The remote debugger process didn't die cleanly."
+  );
 
   info("process exit value: " + gProcess._dbgProcess.exitCode);
 
   info("profile path: " + gProcess._dbgProfilePath);
 
   finish();
 }
 
 registerCleanupFunction(function() {
   Services.prefs.clearUserPref("devtools.debugger.remote-enabled");
   gProcess = null;
 });
 
-add_task(function* () {
+add_task(function*() {
   // Windows XP and 8.1 test slaves are terribly slow at this test.
   requestLongerTimeout(5);
   Services.prefs.setBoolPref("devtools.debugger.remote-enabled", true);
 
   gProcess = yield initChromeDebugger();
 
-  ok(gProcess._dbgProcess,
-    "The remote debugger process wasn't created properly!");
-  ok(gProcess._dbgProcess.exitCode == null,
-    "The remote debugger process isn't running!");
-  is(typeof gProcess._dbgProcess.pid, "number",
-    "The remote debugger process doesn't have a pid (?!)");
+  ok(
+    gProcess._dbgProcess,
+    "The remote debugger process wasn't created properly!"
+  );
+  ok(
+    gProcess._dbgProcess.exitCode == null,
+    "The remote debugger process isn't running!"
+  );
+  is(
+    typeof gProcess._dbgProcess.pid,
+    "number",
+    "The remote debugger process doesn't have a pid (?!)"
+  );
 
   info("process location: " + gProcess._dbgProcess.location);
   info("process pid: " + gProcess._dbgProcess.pid);
   info("process name: " + gProcess._dbgProcess.processName);
   info("process sig: " + gProcess._dbgProcess.processSignature);
 
-  ok(gProcess._dbgProfilePath,
-    "The remote debugger profile wasn't created properly!");
+  ok(
+    gProcess._dbgProfilePath,
+    "The remote debugger profile wasn't created properly!"
+  );
 
   is(
     gProcess._dbgProfilePath,
     OS.Path.join(OS.Constants.Path.profileDir, "chrome_debugger_profile"),
-     "The remote debugger profile isn't where we expect it!"
-   );
+    "The remote debugger profile isn't where we expect it!"
+  );
 
   info("profile path: " + gProcess._dbgProfilePath);
 
   yield gProcess.close();
 });
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-editor-highlight.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-editor-highlight.js
@@ -1,18 +1,18 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that the editor will always highight the right line, no
 // matter if the source text doesn't exist yet or even if the source
 // doesn't exist.
 
-add_task(function* () {
+add_task(function*() {
   const dbg = yield initDebugger("doc-scripts.html");
-  const { selectors: { getSourceText }, getState } = dbg;
+  const { selectors: { getSource }, getState } = dbg;
   const sourceUrl = EXAMPLE_URL + "long.js";
 
   // The source itself doesn't even exist yet, and using
   // `selectSourceURL` will set a pending request to load this source
   // and highlight a specific line.
   dbg.actions.selectSourceURL(sourceUrl, { line: 66 });
 
   // Wait for the source text to load and make sure we're in the right
@@ -26,23 +26,26 @@ add_task(function* () {
   yield selectSource(dbg, "long.js", 16);
   assertHighlightLocation(dbg, "long.js", 16);
 
   // Make sure only one line is ever highlighted and the flash
   // animation is cancelled on old lines.
   yield selectSource(dbg, "long.js", 17);
   yield selectSource(dbg, "long.js", 18);
   assertHighlightLocation(dbg, "long.js", 18);
-  is(findAllElements(dbg, "highlightLine").length, 1,
-     "Only 1 line is highlighted");
+  is(
+    findAllElements(dbg, "highlightLine").length,
+    1,
+    "Only 1 line is highlighted"
+  );
 
   // Test jumping to a line in a source that exists but hasn't been
   // loaded yet.
   selectSource(dbg, "simple1.js", 6);
 
   // Make sure the source is in the loading state, wait for it to be
   // fully loaded, and check the highlighted line.
   const simple1 = findSource(dbg, "simple1.js");
-  ok(getSourceText(getState(), simple1.id).get("loading"));
+  ok(getSource(getState(), simple1.id).get("loading"));
   yield waitForDispatch(dbg, "LOAD_SOURCE_TEXT");
-  ok(getSourceText(getState(), simple1.id).get("text"));
+  ok(getSource(getState(), simple1.id).get("text"));
   assertHighlightLocation(dbg, "simple1.js", 6);
 });
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-sources.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-sources.js
@@ -53,18 +53,37 @@ add_task(function*() {
   yield waitForSourceCount(dbg, 9);
   is(
     findElement(dbg, "sourceNode", 7).textContent,
     "math.min.js",
     "The dynamic script exists"
   );
 
   // Make sure named eval sources appear in the list.
+});
+
+add_task(function*() {
+  const dbg = yield initDebugger("doc-sources.html");
+  const { selectors: { getSelectedSource }, getState } = dbg;
+
+  yield waitForSources(dbg, "simple1", "simple2", "nested-source", "long.js");
+
   ContentTask.spawn(gBrowser.selectedBrowser, null, function() {
     content.eval("window.evaledFunc = function() {} //# sourceURL=evaled.js");
   });
-  yield waitForSourceCount(dbg, 11);
+  yield waitForSourceCount(dbg, 3);
   is(
-    findElement(dbg, "sourceNode", 2).textContent,
+    findElement(dbg, "sourceNode", 3).textContent,
+    "(no domain)",
+    "the folder exists"
+  );
+
+  // work around: the folder is rendered at the bottom, so we close the
+  // root folder and open the (no domain) folder
+  clickElement(dbg, "sourceArrow", 3);
+  yield waitForSourceCount(dbg, 4);
+
+  is(
+    findElement(dbg, "sourceNode", 4).textContent,
     "evaled.js",
-    "The eval script exists"
+    "the eval script exists"
   );
 });
--- a/devtools/client/debugger/new/test/mochitest/head.js
+++ b/devtools/client/debugger/new/test/mochitest/head.js
@@ -278,18 +278,18 @@ function waitForPaused(dbg) {
       const pause = dbg.selectors.getPause(state);
       // Make sure we have the paused state.
       if (!pause) {
         return false;
       }
       // Make sure the source text is completely loaded for the
       // source we are paused in.
       const sourceId = pause && pause.frame && pause.frame.location.sourceId;
-      const sourceText = dbg.selectors.getSourceText(dbg.getState(), sourceId);
-      return sourceText && !sourceText.get("loading");
+      const source = dbg.selectors.getSource(dbg.getState(), sourceId);
+      return source && source.has("loading") && !source.get("loading");
     });
   });
 }
 
 function createDebuggerContext(toolbox) {
   const panel = toolbox.getPanel("jsdebugger");
   const win = panel.panelWin;
   const { store, client, selectors, actions } = panel.getVarsForTests();
@@ -376,17 +376,17 @@ function findSource(dbg, url) {
  * @param {String} url
  * @param {Number} line
  * @return {Promise}
  * @static
  */
 function selectSource(dbg, url, line) {
   info("Selecting source: " + url);
   const source = findSource(dbg, url);
-  const hasText = !!dbg.selectors.getSourceText(dbg.getState(), source.id);
+  const hasText = !!source.text && !source.loading;
   dbg.actions.selectSource(source.id, { line });
 
   if (!hasText) {
     return waitForDispatch(dbg, "LOAD_SOURCE_TEXT");
   }
 }
 
 /**
--- a/devtools/client/preferences/debugger.js
+++ b/devtools/client/preferences/debugger.js
@@ -33,13 +33,13 @@ pref("devtools.debugger.ui.variables-onl
 pref("devtools.debugger.ui.variables-searchbox-visible", false);
 pref("devtools.debugger.ui.framework-grouping-on", true);
 pref("devtools.debugger.call-stack-visible", false);
 pref("devtools.debugger.scopes-visible", false);
 pref("devtools.debugger.start-panel-collapsed", false);
 pref("devtools.debugger.end-panel-collapsed", false);
 pref("devtools.debugger.tabs", "[]");
 pref("devtools.debugger.pending-selected-location", "{}");
-pref("devtools.debugger.pending-breakpoints", "[]");
+pref("devtools.debugger.pending-breakpoints", "{}");
 pref("devtools.debugger.expressions", "[]");
-pref("devtools.debugger.file-search-case-sensitive", true);
+pref("devtools.debugger.file-search-case-sensitive", false);
 pref("devtools.debugger.file-search-whole-word", false );
 pref("devtools.debugger.file-search-regex-match", false);
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -11422,17 +11422,17 @@ nsDocShell::AddHeadersToChannel(nsIInput
 
   static const char kWhitespace[] = "\b\t\r\n ";
   while (true) {
     crlf = headersString.Find("\r\n");
     if (crlf == kNotFound) {
       return NS_OK;
     }
 
-    const nsCSubstring& oneHeader = StringHead(headersString, crlf);
+    const nsACString& oneHeader = StringHead(headersString, crlf);
 
     colon = oneHeader.FindChar(':');
     if (colon == kNotFound) {
       return NS_ERROR_UNEXPECTED;
     }
 
     headerName = StringHead(oneHeader, colon);
     headerValue = Substring(oneHeader, colon + 1);
--- a/dom/base/DOMImplementation.cpp
+++ b/dom/base/DOMImplementation.cpp
@@ -93,17 +93,17 @@ DOMImplementation::CreateDocument(const 
                                   nsIDocument** aDocument,
                                   nsIDOMDocument** aDOMDocument)
 {
   *aDocument = nullptr;
   *aDOMDocument = nullptr;
 
   nsresult rv;
   if (!aQualifiedName.IsEmpty()) {
-    const nsAFlatString& qName = PromiseFlatString(aQualifiedName);
+    const nsString& qName = PromiseFlatString(aQualifiedName);
     const char16_t *colon;
     rv = nsContentUtils::CheckQName(qName, true, &colon);
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (colon &&
         (DOMStringIsNull(aNamespaceURI) ||
          (Substring(qName.get(), colon).EqualsLiteral("xml") &&
           !aNamespaceURI.EqualsLiteral("http://www.w3.org/XML/1998/namespace")))) {
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -396,17 +396,17 @@ Navigator::GetAcceptLanguages(nsTArray<n
     // Use uppercase for country part, e.g. "en-US", not "en-us", see BCP47
     // only uppercase 2-letter country codes, not "zh-Hant", "de-DE-x-goethe".
     // NOTE: we should probably rely on the pref being set correctly.
     if (lang.Length() > 2) {
       nsCharSeparatedTokenizer localeTokenizer(lang, '-');
       int32_t pos = 0;
       bool first = true;
       while (localeTokenizer.hasMoreTokens()) {
-        const nsSubstring& code = localeTokenizer.nextToken();
+        const nsAString& code = localeTokenizer.nextToken();
 
         if (code.Length() == 2 && !first) {
           nsAutoString upper(code);
           ToUpperCase(upper);
           lang.Replace(pos, code.Length(), upper);
         }
 
         pos += code.Length() + 1; // 1 is the separator
--- a/dom/base/SelectionChangeListener.cpp
+++ b/dom/base/SelectionChangeListener.cpp
@@ -104,16 +104,23 @@ SelectionChangeListener::NotifySelection
   }
 
   // The ranges have actually changed, update the mOldRanges array
   mOldRanges.ClearAndRetainStorage();
   for (size_t i = 0; i < sel->RangeCount(); i++) {
     mOldRanges.AppendElement(RawRangeData(sel->GetRangeAt(i)));
   }
 
+  if (doc) {
+    nsPIDOMWindowInner* inner = doc->GetInnerWindow();
+    if (inner && !inner->HasSelectionChangeEventListeners()) {
+      return NS_OK;
+    }
+  }
+
   // If we are hiding changes, then don't do anything else. We do this after we
   // update mOldRanges so that changes after the changes stop being hidden don't
   // incorrectly trigger a change, even though they didn't change anything
   if (sel->IsBlockingSelectionChangeEvents()) {
     return NS_OK;
   }
 
   // The spec currently doesn't say that we should dispatch this event on text
new file mode 100644
--- /dev/null
+++ b/dom/base/TimeoutBudgetManager.cpp
@@ -0,0 +1,95 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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 "TimeoutBudgetManager.h"
+
+#include "mozilla/dom/Timeout.h"
+
+namespace mozilla {
+namespace dom {
+
+// Time between sampling timeout execution time.
+const uint32_t kTelemetryPeriodMS = 1000;
+
+/* static */ TimeoutBudgetManager&
+TimeoutBudgetManager::Get()
+{
+  static TimeoutBudgetManager gTimeoutBudgetManager;
+  return gTimeoutBudgetManager;
+}
+
+void
+TimeoutBudgetManager::StartRecording(const TimeStamp& aNow)
+{
+  mStart = aNow;
+}
+
+void
+TimeoutBudgetManager::StopRecording()
+{
+  mStart = TimeStamp();
+}
+
+void
+TimeoutBudgetManager::RecordExecution(const TimeStamp& aNow,
+                                      const Timeout* aTimeout,
+                                      bool aIsBackground)
+{
+  if (!mStart) {
+    // If we've started a sync operation mStart might be null, in
+    // which case we should not record this piece of execution.
+    return;
+  }
+
+  TimeDuration duration = aNow - mStart;
+
+  if (aIsBackground) {
+    if (aTimeout->mIsTracking) {
+      mTelemetryData.mBackgroundTracking += duration;
+    } else {
+      mTelemetryData.mBackgroundNonTracking += duration;
+    }
+  } else {
+    if (aTimeout->mIsTracking) {
+      mTelemetryData.mForegroundTracking += duration;
+    } else {
+      mTelemetryData.mForegroundNonTracking += duration;
+    }
+  }
+}
+
+void
+TimeoutBudgetManager::Accumulate(Telemetry::HistogramID aId,
+                                 const TimeDuration& aSample)
+{
+  uint32_t sample = std::round(aSample.ToMilliseconds());
+  if (sample) {
+    Telemetry::Accumulate(aId, sample);
+  }
+}
+
+void
+TimeoutBudgetManager::MaybeCollectTelemetry(const TimeStamp& aNow)
+{
+  if ((aNow - mLastCollection).ToMilliseconds() < kTelemetryPeriodMS) {
+    return;
+  }
+
+  Accumulate(Telemetry::TIMEOUT_EXECUTION_FG_TRACKING_MS,
+             mTelemetryData.mForegroundTracking);
+  Accumulate(Telemetry::TIMEOUT_EXECUTION_FG_MS,
+             mTelemetryData.mForegroundNonTracking);
+  Accumulate(Telemetry::TIMEOUT_EXECUTION_BG_TRACKING_MS,
+             mTelemetryData.mBackgroundTracking);
+  Accumulate(Telemetry::TIMEOUT_EXECUTION_BG_MS,
+             mTelemetryData.mBackgroundNonTracking);
+
+  mTelemetryData = TelemetryData();
+  mLastCollection = aNow;
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/base/TimeoutBudgetManager.h
@@ -0,0 +1,48 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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_dom_timeoutbudgetmanager_h
+#define mozilla_dom_timeoutbudgetmanager_h
+
+#include "mozilla/Telemetry.h"
+#include "mozilla/TimeStamp.h"
+
+namespace mozilla {
+namespace dom {
+
+class Timeout;
+
+class TimeoutBudgetManager
+{
+public:
+  static TimeoutBudgetManager& Get();
+  void StartRecording(const TimeStamp& aNow);
+  void StopRecording();
+  void RecordExecution(const TimeStamp& aNow,
+                       const Timeout* aTimeout,
+                       bool aIsBackground);
+  void MaybeCollectTelemetry(const TimeStamp& aNow);
+private:
+  TimeoutBudgetManager() : mLastCollection(TimeStamp::Now()) {}
+  struct TelemetryData
+  {
+    TimeDuration mForegroundTracking;
+    TimeDuration mForegroundNonTracking;
+    TimeDuration mBackgroundTracking;
+    TimeDuration mBackgroundNonTracking;
+  };
+
+  void Accumulate(Telemetry::HistogramID aId, const TimeDuration& aSample);
+
+  TelemetryData mTelemetryData;
+  TimeStamp mStart;
+  TimeStamp mLastCollection;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_timeoutbudgetmanager_h
--- a/dom/base/TimeoutHandler.cpp
+++ b/dom/base/TimeoutHandler.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "TimeoutHandler.h"
+#include "nsJSUtils.h"
 
 namespace mozilla {
 namespace dom {
 
 TimeoutHandler::TimeoutHandler(JSContext* aCx)
   : TimeoutHandler()
 {
   nsJSUtils::GetCallingLocation(aCx, mFileName, &mLineNo, &mColumn);
--- a/dom/base/TimeoutHandler.h
+++ b/dom/base/TimeoutHandler.h
@@ -5,16 +5,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_timeout_handler_h
 #define mozilla_dom_timeout_handler_h
 
 #include "nsCOMPtr.h"
 #include "nsISupports.h"
 #include "nsITimeoutHandler.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsString.h"
 
 namespace mozilla {
 namespace dom {
 
 /**
  * Utility class for implementing nsITimeoutHandlers, designed to be subclassed.
  */
 class TimeoutHandler : public nsITimeoutHandler
--- a/dom/base/TimeoutManager.cpp
+++ b/dom/base/TimeoutManager.cpp
@@ -9,128 +9,23 @@
 #include "mozilla/Logging.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/ThrottledEventQueue.h"
 #include "mozilla/TimeStamp.h"
 #include "nsITimeoutHandler.h"
 #include "mozilla/dom/TabGroup.h"
 #include "OrderedTimeoutIterator.h"
 #include "TimeoutExecutor.h"
+#include "TimeoutBudgetManager.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 static LazyLogModule gLog("Timeout");
 
-// Time between sampling timeout execution time.
-const uint32_t kTelemetryPeriodMS = 1000;
-
-class TimeoutTelemetry
-{
-public:
-  static TimeoutTelemetry& Get();
-  TimeoutTelemetry() : mLastCollection(TimeStamp::Now()) {}
-
-  void StartRecording(TimeStamp aNow);
-  void StopRecording();
-  void RecordExecution(TimeStamp aNow, Timeout* aTimeout, bool aIsBackground);
-  void MaybeCollectTelemetry(TimeStamp aNow);
-private:
-  struct TelemetryData
-  {
-    TimeDuration mForegroundTracking;
-    TimeDuration mForegroundNonTracking;
-    TimeDuration mBackgroundTracking;
-    TimeDuration mBackgroundNonTracking;
-  };
-
-  void Accumulate(Telemetry::HistogramID aId, TimeDuration aSample);
-
-  TelemetryData mTelemetryData;
-  TimeStamp mStart;
-  TimeStamp mLastCollection;
-};
-
-static TimeoutTelemetry gTimeoutTelemetry;
-
-/* static */ TimeoutTelemetry&
-TimeoutTelemetry::Get()
-{
-  return gTimeoutTelemetry;
-}
-
-void
-TimeoutTelemetry::StartRecording(TimeStamp aNow)
-{
-  mStart = aNow;
-}
-
-void
-TimeoutTelemetry::StopRecording()
-{
-  mStart = TimeStamp();
-}
-
-void
-TimeoutTelemetry::RecordExecution(TimeStamp aNow,
-                                  Timeout* aTimeout,
-                                  bool aIsBackground)
-{
-  if (!mStart) {
-    // If we've started a sync operation mStart might be null, in
-    // which case we should not record this piece of execution.
-    return;
-  }
-
-  TimeDuration duration = aNow - mStart;
-
-  if (aIsBackground) {
-    if (aTimeout->mIsTracking) {
-      mTelemetryData.mBackgroundTracking += duration;
-    } else {
-      mTelemetryData.mBackgroundNonTracking += duration;
-    }
-  } else {
-    if (aTimeout->mIsTracking) {
-      mTelemetryData.mForegroundTracking += duration;
-    } else {
-      mTelemetryData.mForegroundNonTracking += duration;
-    }
-  }
-}
-
-void
-TimeoutTelemetry::Accumulate(Telemetry::HistogramID aId, TimeDuration aSample)
-{
-  uint32_t sample = std::round(aSample.ToMilliseconds());
-  if (sample) {
-    Telemetry::Accumulate(aId, sample);
-  }
-}
-
-void
-TimeoutTelemetry::MaybeCollectTelemetry(TimeStamp aNow)
-{
-  if ((aNow - mLastCollection).ToMilliseconds() < kTelemetryPeriodMS) {
-    return;
-  }
-
-  Accumulate(Telemetry::TIMEOUT_EXECUTION_FG_TRACKING_MS,
-             mTelemetryData.mForegroundTracking);
-  Accumulate(Telemetry::TIMEOUT_EXECUTION_FG_MS,
-             mTelemetryData.mForegroundNonTracking);
-  Accumulate(Telemetry::TIMEOUT_EXECUTION_BG_TRACKING_MS,
-             mTelemetryData.mBackgroundTracking);
-  Accumulate(Telemetry::TIMEOUT_EXECUTION_BG_MS,
-             mTelemetryData.mBackgroundNonTracking);
-
-  mTelemetryData = TelemetryData();
-  mLastCollection = aNow;
-}
-
 static int32_t              gRunningTimeoutDepth       = 0;
 
 // The default shortest interval/timeout we permit
 #define DEFAULT_MIN_CLAMP_TIMEOUT_VALUE 4 // 4ms
 #define DEFAULT_MIN_BACKGROUND_TIMEOUT_VALUE 1000 // 1000ms
 #define DEFAULT_MIN_TRACKING_TIMEOUT_VALUE 4 // 4ms
 #define DEFAULT_MIN_TRACKING_BACKGROUND_TIMEOUT_VALUE 1000 // 1000ms
 static int32_t gMinClampTimeoutValue = 0;
@@ -246,16 +141,44 @@ TimeoutManager::CalculateDelay(Timeout* 
   if (aTimeout->mIsTracking && mThrottleTrackingTimeouts) {
     result = TimeDuration::Max(
       result, TimeDuration::FromMilliseconds(gMinTrackingTimeoutValue));
   }
 
   return result;
 }
 
+void
+TimeoutManager::RecordExecution(Timeout* aRunningTimeout,
+                                Timeout* aTimeout)
+{
+  if (mWindow.IsChromeWindow()) {
+    return;
+  }
+
+  TimeoutBudgetManager& budgetManager = TimeoutBudgetManager::Get();
+  TimeStamp now = TimeStamp::Now();
+
+  if (aRunningTimeout) {
+    // If we're running a timeout callback, record any execution until
+    // now.
+    budgetManager.RecordExecution(
+      now, aRunningTimeout, mWindow.IsBackgroundInternal());
+    budgetManager.MaybeCollectTelemetry(now);
+  }
+
+  if (aTimeout) {
+    // If we're starting a new timeout callback, start recording.
+    budgetManager.StartRecording(now);
+  } else {
+    // Else stop by clearing the start timestamp.
+    budgetManager.StopRecording();
+  }
+}
+
 #define TRACKING_SEPARATE_TIMEOUT_BUCKETING_STRATEGY 0 // Consider all timeouts coming from tracking scripts as tracking
 // These strategies are useful for testing.
 #define ALL_NORMAL_TIMEOUT_BUCKETING_STRATEGY        1 // Consider all timeouts as normal
 #define ALTERNATE_TIMEOUT_BUCKETING_STRATEGY         2 // Put every other timeout in the list of tracking timeouts
 #define RANDOM_TIMEOUT_BUCKETING_STRATEGY            3 // Put timeouts into either the normal or tracking timeouts list randomly
 static int32_t gTimeoutBucketingStrategy = 0;
 
 #define DEFAULT_TRACKING_TIMEOUT_THROTTLING_DELAY  -1  // Only positive integers cause us to introduce a delay for tracking
@@ -899,51 +822,28 @@ TimeoutManager::Timeouts::Insert(Timeout
   aTimeout->mFiringId = InvalidFiringId;
 }
 
 Timeout*
 TimeoutManager::BeginRunningTimeout(Timeout* aTimeout)
 {
   Timeout* currentTimeout = mRunningTimeout;
   mRunningTimeout = aTimeout;
-
   ++gRunningTimeoutDepth;
 
-  if (!mWindow.IsChromeWindow()) {
-    TimeStamp now = TimeStamp::Now();
-    if (currentTimeout) {
-      // If we're already running a timeout and start running another
-      // one, record the fragment duration already collected.
-      TimeoutTelemetry::Get().RecordExecution(
-        now, currentTimeout, IsBackground());
-    }
-
-    TimeoutTelemetry::Get().MaybeCollectTelemetry(now);
-    TimeoutTelemetry::Get().StartRecording(now);
-  }
-
+  RecordExecution(currentTimeout, aTimeout);
   return currentTimeout;
 }
 
 void
 TimeoutManager::EndRunningTimeout(Timeout* aTimeout)
 {
   --gRunningTimeoutDepth;
 
-  if (!mWindow.IsChromeWindow()) {
-    TimeStamp now = TimeStamp::Now();
-    TimeoutTelemetry::Get().RecordExecution(now, mRunningTimeout, IsBackground());
-
-    if (aTimeout) {
-      // If we were running a nested timeout, restart the measurement
-      // from here.
-      TimeoutTelemetry::Get().StartRecording(now);
-    }
-  }
-
+  RecordExecution(mRunningTimeout, aTimeout);
   mRunningTimeout = aTimeout;
 }
 
 void
 TimeoutManager::UnmarkGrayTimers()
 {
   ForEachUnorderedTimeout([](Timeout* aTimeout) {
     if (aTimeout->mScriptHandler) {
@@ -1141,31 +1041,23 @@ void
 TimeoutManager::BeginSyncOperation()
 {
   // If we're beginning a sync operation, the currently running
   // timeout will be put on hold. To not get into an inconsistent
   // state, where the currently running timeout appears to take time
   // equivalent to the period of us spinning up a new event loop,
   // record what we have and stop recording until we reach
   // EndSyncOperation.
-  if (!mWindow.IsChromeWindow()) {
-    if (mRunningTimeout) {
-      TimeoutTelemetry::Get().RecordExecution(
-        TimeStamp::Now(), mRunningTimeout, IsBackground());
-    }
-    TimeoutTelemetry::Get().StopRecording();
-  }
+  RecordExecution(mRunningTimeout, nullptr);
 }
 
 void
 TimeoutManager::EndSyncOperation()
 {
   // If we're running a timeout, restart the measurement from here.
-  if (!mWindow.IsChromeWindow() && mRunningTimeout) {
-    TimeoutTelemetry::Get().StartRecording(TimeStamp::Now());
-  }
+  RecordExecution(nullptr, mRunningTimeout);
 }
 
 nsIEventTarget*
 TimeoutManager::EventTarget()
 {
   return mWindow.EventTargetFor(TaskCategory::Timer);
 }
--- a/dom/base/TimeoutManager.h
+++ b/dom/base/TimeoutManager.h
@@ -129,16 +129,19 @@ private:
   IsValidFiringId(uint32_t aFiringId) const;
 
   bool
   IsInvalidFiringId(uint32_t aFiringId) const;
 
   TimeDuration
   MinSchedulingDelay() const;
 
+  void RecordExecution(mozilla::dom::Timeout* aRunningTimeout,
+                       mozilla::dom::Timeout* aTimeout);
+
 private:
   struct Timeouts {
     explicit Timeouts(const TimeoutManager& aManager)
       : mManager(aManager)
     {
     }
 
     // Insert aTimeout into the list, before all timeouts that would
--- a/dom/base/moz.build
+++ b/dom/base/moz.build
@@ -348,16 +348,17 @@ UNIFIED_SOURCES += [
     'StructuredCloneHolder.cpp',
     'StyleSheetList.cpp',
     'SubtleCrypto.cpp',
     'TabGroup.cpp',
     'Text.cpp',
     'TextInputProcessor.cpp',
     'ThirdPartyUtil.cpp',
     'Timeout.cpp',
+    'TimeoutBudgetManager.cpp',
     'TimeoutExecutor.cpp',
     'TimeoutHandler.cpp',
     'TimeoutManager.cpp',
     'TreeWalker.cpp',
     'WebKitCSSMatrix.cpp',
     'WebSocket.cpp',
     'WindowNamedPropertiesHandler.cpp',
     'WindowOrientationObserver.cpp',
--- a/dom/base/nsContentPolicy.cpp
+++ b/dom/base/nsContentPolicy.cpp
@@ -23,16 +23,17 @@
 #include "nsIContent.h"
 #include "nsIImageLoadingContent.h"
 #include "nsILoadContext.h"
 #include "nsCOMArray.h"
 #include "nsContentUtils.h"
 #include "mozilla/dom/nsMixedContentBlocker.h"
 #include "nsIContentSecurityPolicy.h"
 #include "mozilla/dom/TabGroup.h"
+#include "mozilla/TaskCategory.h"
 
 using mozilla::LogLevel;
 
 NS_IMPL_ISUPPORTS(nsContentPolicy, nsIContentPolicy)
 
 static mozilla::LazyLogModule gConPolLog("nsContentPolicy");
 
 nsresult
@@ -134,17 +135,17 @@ nsContentPolicy::CheckPolicy(CPMethod   
     } else {
         window = do_QueryInterface(requestingContext);
     }
 
     if (requestPrincipal) {
         nsCOMPtr<nsIContentSecurityPolicy> csp;
         requestPrincipal->GetCsp(getter_AddRefs(csp));
         if (csp && window) {
-            csp->EnsureEventTarget(window->EventTargetFor(TaskCategory::Other));
+            csp->EnsureEventTarget(window->EventTargetFor(mozilla::TaskCategory::Other));
         }
     }
 
     int32_t count = entries.Count();
     for (int32_t i = 0; i < count; i++) {
         /* check the appropriate policy */
         // Send internal content policy type to CSP and mixed content blocker
         nsContentPolicyType type = externalType;
--- a/dom/base/nsContentSink.cpp
+++ b/dom/base/nsContentSink.cpp
@@ -351,17 +351,17 @@ nsContentSink::DoProcessLinkHeader()
   mDocument->GetHeaderData(nsGkAtoms::link, value);
   ProcessLinkHeader(value);
 }
 
 // check whether the Link header field applies to the context resource
 // see <http://tools.ietf.org/html/rfc5988#section-5.2>
 
 bool
-nsContentSink::LinkContextIsOurDocument(const nsSubstring& aAnchor)
+nsContentSink::LinkContextIsOurDocument(const nsAString& aAnchor)
 {
   if (aAnchor.IsEmpty()) {
     // anchor parameter not present or empty -> same document reference
     return true;
   }
 
   nsIURI* docUri = mDocument->GetDocumentURI();
 
@@ -675,20 +675,20 @@ nsContentSink::ProcessLinkHeader(const n
                      type, media, crossOrigin);
   }
 
   return rv;
 }
 
 
 nsresult
-nsContentSink::ProcessLink(const nsSubstring& aAnchor, const nsSubstring& aHref,
-                           const nsSubstring& aRel, const nsSubstring& aTitle,
-                           const nsSubstring& aType, const nsSubstring& aMedia,
-                           const nsSubstring& aCrossOrigin)
+nsContentSink::ProcessLink(const nsAString& aAnchor, const nsAString& aHref,
+                           const nsAString& aRel, const nsAString& aTitle,
+                           const nsAString& aType, const nsAString& aMedia,
+                           const nsAString& aCrossOrigin)
 {
   uint32_t linkTypes =
     nsStyleLinkElement::ParseLinkTypes(aRel);
 
   // The link relation may apply to a different resource, specified
   // in the anchor parameter. For the link relations supported so far,
   // we simply abort if the link applies to a resource different to the
   // one we've loaded
@@ -729,21 +729,21 @@ nsContentSink::ProcessLink(const nsSubst
 
   bool isAlternate = linkTypes & nsStyleLinkElement::eALTERNATE;
   return ProcessStyleLink(nullptr, aHref, isAlternate, aTitle, aType,
                           aMedia);
 }
 
 nsresult
 nsContentSink::ProcessStyleLink(nsIContent* aElement,
-                                const nsSubstring& aHref,
+                                const nsAString& aHref,
                                 bool aAlternate,
-                                const nsSubstring& aTitle,
-                                const nsSubstring& aType,
-                                const nsSubstring& aMedia)
+                                const nsAString& aTitle,
+                                const nsAString& aType,
+                                const nsAString& aMedia)
 {
   if (aAlternate && aTitle.IsEmpty()) {
     // alternates must have title return without error, for now
     return NS_OK;
   }
 
   nsAutoString  mimeType;
   nsAutoString  params;
--- a/dom/base/nsContentSink.h
+++ b/dom/base/nsContentSink.h
@@ -108,17 +108,17 @@ class nsContentSink : public nsICSSLoade
 
   // nsIDocumentObserver
   NS_DECL_NSIDOCUMENTOBSERVER_BEGINUPDATE
   NS_DECL_NSIDOCUMENTOBSERVER_ENDUPDATE
 
   virtual void UpdateChildCounts() = 0;
 
   bool IsTimeToNotify();
-  bool LinkContextIsOurDocument(const nsSubstring& aAnchor);
+  bool LinkContextIsOurDocument(const nsAString& aAnchor);
   bool Decode5987Format(nsAString& aEncoded);
 
   static void InitializeStatics();
 
 protected:
   nsContentSink();
   virtual ~nsContentSink();
 
@@ -146,27 +146,27 @@ protected:
 
   nsresult Init(nsIDocument* aDoc, nsIURI* aURI,
                 nsISupports* aContainer, nsIChannel* aChannel);
 
   nsresult ProcessHTTPHeaders(nsIChannel* aChannel);
   nsresult ProcessHeaderData(nsIAtom* aHeader, const nsAString& aValue,
                              nsIContent* aContent = nullptr);
   nsresult ProcessLinkHeader(const nsAString& aLinkData);
-  nsresult ProcessLink(const nsSubstring& aAnchor,
-                       const nsSubstring& aHref, const nsSubstring& aRel,
-                       const nsSubstring& aTitle, const nsSubstring& aType,
-                       const nsSubstring& aMedia, const nsSubstring& aCrossOrigin);
+  nsresult ProcessLink(const nsAString& aAnchor,
+                       const nsAString& aHref, const nsAString& aRel,
+                       const nsAString& aTitle, const nsAString& aType,
+                       const nsAString& aMedia, const nsAString& aCrossOrigin);
 
   virtual nsresult ProcessStyleLink(nsIContent* aElement,
-                                    const nsSubstring& aHref,
+                                    const nsAString& aHref,
                                     bool aAlternate,
-                                    const nsSubstring& aTitle,
-                                    const nsSubstring& aType,
-                                    const nsSubstring& aMedia);
+                                    const nsAString& aTitle,
+                                    const nsAString& aType,
+                                    const nsAString& aMedia);
 
   void PrefetchHref(const nsAString &aHref, nsINode *aSource,
                     bool aExplicit);
 
   // For PrefetchDNS() aHref can either be the usual
   // URI format or of the form "//www.hostname.com" without a scheme.
   void PrefetchDNS(const nsAString &aHref);
 
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -3258,17 +3258,17 @@ nsContentUtils::CheckQName(const nsAStri
   }
 
   return NS_ERROR_DOM_INVALID_CHARACTER_ERR;
 }
 
 //static
 nsresult
 nsContentUtils::SplitQName(const nsIContent* aNamespaceResolver,
-                           const nsAFlatString& aQName,
+                           const nsString& aQName,
                            int32_t *aNamespace, nsIAtom **aLocalName)
 {
   const char16_t* colon;
   nsresult rv = nsContentUtils::CheckQName(aQName, true, &colon);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (colon) {
     const char16_t* end;
@@ -3297,17 +3297,17 @@ nsContentUtils::SplitQName(const nsICont
 // static
 nsresult
 nsContentUtils::GetNodeInfoFromQName(const nsAString& aNamespaceURI,
                                      const nsAString& aQualifiedName,
                                      nsNodeInfoManager* aNodeInfoManager,
                                      uint16_t aNodeType,
                                      mozilla::dom::NodeInfo** aNodeInfo)
 {
-  const nsAFlatString& qName = PromiseFlatString(aQualifiedName);
+  const nsString& qName = PromiseFlatString(aQualifiedName);
   const char16_t* colon;
   nsresult rv = nsContentUtils::CheckQName(qName, true, &colon);
   NS_ENSURE_SUCCESS(rv, rv);
 
   int32_t nsID;
   sNameSpaceManager->RegisterNameSpace(aNamespaceURI, nsID);
   if (colon) {
     const char16_t* end;
@@ -3950,17 +3950,17 @@ nsContentUtils::LogSimpleConsoleError(co
 nsContentUtils::ReportToConsole(uint32_t aErrorFlags,
                                 const nsACString& aCategory,
                                 const nsIDocument* aDocument,
                                 PropertiesFile aFile,
                                 const char *aMessageName,
                                 const char16_t **aParams,
                                 uint32_t aParamsLength,
                                 nsIURI* aURI,
-                                const nsAFlatString& aSourceLine,
+                                const nsString& aSourceLine,
                                 uint32_t aLineNumber,
                                 uint32_t aColumnNumber)
 {
   NS_ASSERTION((aParams && aParamsLength) || (!aParams && !aParamsLength),
                "Supply either both parameters and their number or no"
                "parameters and 0.");
 
   nsresult rv;
@@ -3981,17 +3981,17 @@ nsContentUtils::ReportToConsole(uint32_t
 
 
 /* static */ nsresult
 nsContentUtils::ReportToConsoleNonLocalized(const nsAString& aErrorText,
                                             uint32_t aErrorFlags,
                                             const nsACString& aCategory,
                                             const nsIDocument* aDocument,
                                             nsIURI* aURI,
-                                            const nsAFlatString& aSourceLine,
+                                            const nsString& aSourceLine,
                                             uint32_t aLineNumber,
                                             uint32_t aColumnNumber,
                                             MissingErrorLocationMode aLocationMode)
 {
   uint64_t innerWindowID = 0;
   if (aDocument) {
     if (!aURI) {
       aURI = aDocument->GetDocumentURI();
@@ -4005,17 +4005,17 @@ nsContentUtils::ReportToConsoleNonLocali
 }
 
 /* static */ nsresult
 nsContentUtils::ReportToConsoleByWindowID(const nsAString& aErrorText,
                                           uint32_t aErrorFlags,
                                           const nsACString& aCategory,
                                           uint64_t aInnerWindowID,
                                           nsIURI* aURI,
-                                          const nsAFlatString& aSourceLine,
+                                          const nsString& aSourceLine,
                                           uint32_t aLineNumber,
                                           uint32_t aColumnNumber,
                                           MissingErrorLocationMode aLocationMode)
 {
   nsresult rv;
   if (!sConsoleService) { // only need to bother null-checking here
     rv = CallGetService(NS_CONSOLESERVICE_CONTRACTID, &sConsoleService);
     NS_ENSURE_SUCCESS(rv, rv);
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -158,18 +158,18 @@ class LayerManager;
 } // namespace mozilla
 
 class nsIBidiKeyboard;
 
 extern const char kLoadAsData[];
 
 // Stolen from nsReadableUtils, but that's OK, since we can declare the same
 // name multiple times.
-const nsAFlatString& EmptyString();
-const nsAFlatCString& EmptyCString();
+const nsString& EmptyString();
+const nsCString& EmptyCString();
 
 enum EventNameType {
   EventNameType_None = 0x0000,
   EventNameType_HTML = 0x0001,
   EventNameType_XUL = 0x0002,
   EventNameType_SVGGraphic = 0x0004, // svg graphic elements
   EventNameType_SVGSVG = 0x0008, // the svg element
   EventNameType_SMIL = 0x0010, // smil elements
@@ -625,17 +625,17 @@ public:
    */
   static bool IsCustomElementName(nsIAtom* aName);
 
   static nsresult CheckQName(const nsAString& aQualifiedName,
                              bool aNamespaceAware = true,
                              const char16_t** aColon = nullptr);
 
   static nsresult SplitQName(const nsIContent* aNamespaceResolver,
-                             const nsAFlatString& aQName,
+                             const nsString& aQName,
                              int32_t *aNamespace, nsIAtom **aLocalName);
 
   static nsresult GetNodeInfoFromQName(const nsAString& aNamespaceURI,
                                        const nsAString& aQualifiedName,
                                        nsNodeInfoManager* aNodeInfoManager,
                                        uint16_t aNodeType,
                                        mozilla::dom::NodeInfo** aNodeInfo);
 
@@ -917,17 +917,17 @@ public:
     // Get location information from the currently executing script.
     eUSE_CALLING_LOCATION
   };
   static nsresult ReportToConsoleNonLocalized(const nsAString& aErrorText,
                                               uint32_t aErrorFlags,
                                               const nsACString& aCategory,
                                               const nsIDocument* aDocument,
                                               nsIURI* aURI = nullptr,
-                                              const nsAFlatString& aSourceLine
+                                              const nsString& aSourceLine
                                                 = EmptyString(),
                                               uint32_t aLineNumber = 0,
                                               uint32_t aColumnNumber = 0,
                                               MissingErrorLocationMode aLocationMode
                                                 = eUSE_CALLING_LOCATION);
 
   /**
    * Report a non-localized error message to the error console base on the
@@ -948,17 +948,17 @@ public:
    *   @param [aLocationMode] (Optional) Specifies the behavior if
               error location information is omitted.
    */
   static nsresult ReportToConsoleByWindowID(const nsAString& aErrorText,
                                             uint32_t aErrorFlags,
                                             const nsACString& aCategory,
                                             uint64_t aInnerWindowID,
                                             nsIURI* aURI = nullptr,
-                                            const nsAFlatString& aSourceLine
+                                            const nsString& aSourceLine
                                               = EmptyString(),
                                             uint32_t aLineNumber = 0,
                                             uint32_t aColumnNumber = 0,
                                             MissingErrorLocationMode aLocationMode
                                               = eUSE_CALLING_LOCATION);
 
   /**
    * Report a localized error message to the error console.
@@ -999,17 +999,17 @@ public:
   static nsresult ReportToConsole(uint32_t aErrorFlags,
                                   const nsACString& aCategory,
                                   const nsIDocument* aDocument,
                                   PropertiesFile aFile,
                                   const char *aMessageName,
                                   const char16_t **aParams = nullptr,
                                   uint32_t aParamsLength = 0,
                                   nsIURI* aURI = nullptr,
-                                  const nsAFlatString& aSourceLine
+                                  const nsString& aSourceLine
                                     = EmptyString(),
                                   uint32_t aLineNumber = 0,
                                   uint32_t aColumnNumber = 0);
 
   static void LogMessageToConsole(const char* aMsg);
 
   /**
    * Get the localized string named |aKey| in properties file |aFile|.
--- a/dom/base/nsDOMNavigationTiming.cpp
+++ b/dom/base/nsDOMNavigationTiming.cpp
@@ -75,17 +75,17 @@ DOMTimeMilliSec nsDOMNavigationTiming::D
 }
 
 void
 nsDOMNavigationTiming::NotifyNavigationStart(DocShellState aDocShellState)
 {
   mNavigationStartHighRes = (double)PR_Now() / PR_USEC_PER_MSEC;
   mNavigationStartTimeStamp = TimeStamp::Now();
   mDocShellHasBeenActiveSinceNavigationStart = (aDocShellState == DocShellState::eActive);
-  PROFILER_MARKER("Navigation::Start");
+  profiler_add_marker("Navigation::Start");
 }
 
 void
 nsDOMNavigationTiming::NotifyFetchStart(nsIURI* aURI, Type aNavigationType)
 {
   mNavigationType = aNavigationType;
   // At the unload event time we don't really know the loading uri.
   // Need it for later check for unload timing access.
@@ -164,51 +164,51 @@ nsDOMNavigationTiming::SetDOMLoadingTime
 void
 nsDOMNavigationTiming::NotifyDOMLoading(nsIURI* aURI)
 {
   if (!mDOMLoadingSet) {
     mLoadedURI = aURI;
     mDOMLoading = DurationFromStart();
     mDOMLoadingSet = true;
 
-    PROFILER_MARKER("Navigation::DOMLoading");
+    profiler_add_marker("Navigation::DOMLoading");
 
     if (IsTopLevelContentDocument()) {
       Telemetry::AccumulateTimeDelta(Telemetry::TIME_TO_DOM_LOADING_MS,
                                      mNavigationStartTimeStamp);
     }
   }
 }
 
 void
 nsDOMNavigationTiming::NotifyDOMInteractive(nsIURI* aURI)
 {
   if (!mDOMInteractiveSet) {
     mLoadedURI = aURI;
     mDOMInteractive = DurationFromStart();
     mDOMInteractiveSet = true;
 
-    PROFILER_MARKER("Navigation::DOMInteractive");
+    profiler_add_marker("Navigation::DOMInteractive");
 
     if (IsTopLevelContentDocument()) {
       Telemetry::AccumulateTimeDelta(Telemetry::TIME_TO_DOM_INTERACTIVE_MS,
                                      mNavigationStartTimeStamp);
     }
   }
 }
 
 void
 nsDOMNavigationTiming::NotifyDOMComplete(nsIURI* aURI)
 {
   if (!mDOMCompleteSet) {
     mLoadedURI = aURI;
     mDOMComplete = DurationFromStart();
     mDOMCompleteSet = true;
 
-    PROFILER_MARKER("Navigation::DOMComplete");
+    profiler_add_marker("Navigation::DOMComplete");
 
     if (IsTopLevelContentDocument()) {
       Telemetry::AccumulateTimeDelta(Telemetry::TIME_TO_DOM_COMPLETE_MS,
                                      mNavigationStartTimeStamp);
     }
   }
 }
 
@@ -262,17 +262,17 @@ nsDOMNavigationTiming::NotifyNonBlankPai
   if (profiler_is_active()) {
     nsAutoCString spec;
     if (mLoadedURI) {
       mLoadedURI->GetSpec(spec);
     }
     nsPrintfCString marker("Non-blank paint after %dms for URL %s, %s",
                            int(elapsed.ToMilliseconds()), spec.get(),
                            mDocShellHasBeenActiveSinceNavigationStart ? "foreground tab" : "this tab was inactive some of the time between navigation start and first non-blank paint");
-    PROFILER_MARKER(marker.get());
+    profiler_add_marker(marker.get());
   }
 
   if (mDocShellHasBeenActiveSinceNavigationStart) {
     Telemetry::AccumulateTimeDelta(Telemetry::TIME_TO_NON_BLANK_PAINT_MS,
                                    mNavigationStartTimeStamp,
                                    mNonBlankPaintTimeStamp);
   }
 }
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -2326,16 +2326,36 @@ nsDOMWindowUtils::GetLayerManagerRemote(
   if (!mgr)
     return NS_ERROR_FAILURE;
 
   *retval = !!mgr->AsKnowsCompositor();
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsDOMWindowUtils::GetUsingAdvancedLayers(bool* retval)
+{
+  nsCOMPtr<nsIWidget> widget = GetWidget();
+  if (!widget) {
+    return NS_ERROR_FAILURE;
+  }
+
+  LayerManager *mgr = widget->GetLayerManager();
+  if (!mgr) {
+    return NS_ERROR_FAILURE;
+  }
+
+  *retval = false;
+  if (KnowsCompositor* fwd = mgr->AsKnowsCompositor()) {
+    *retval = fwd->GetTextureFactoryIdentifier().mUsingAdvancedLayers;
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsDOMWindowUtils::GetSupportsHardwareH264Decoding(JS::MutableHandle<JS::Value> aPromise)
 {
   nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
   NS_ENSURE_STATE(window);
   nsCOMPtr<nsIGlobalObject> parentObject =
     do_QueryInterface(window->GetCurrentInnerWindow());
   NS_ENSURE_STATE(parentObject);
 #ifdef MOZ_FMP4
@@ -3389,17 +3409,17 @@ PrepareForFullscreenChange(nsIPresShell*
       viewManager->SetWindowDimensions(aSize.width, aSize.height);
     }
   }
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::HandleFullscreenRequests(bool* aRetVal)
 {
-  PROFILER_MARKER("Enter fullscreen");
+  profiler_add_marker("Enter fullscreen");
   nsCOMPtr<nsIDocument> doc = GetDocument();
   NS_ENSURE_STATE(doc);
 
   // Notify the pres shell that we are starting fullscreen change, and
   // set the window dimensions in advance. Since the resize message
   // comes after the fullscreen change call, doing so could avoid an
   // extra resize reflow after this point.
   nsRect screenRect;
@@ -3412,17 +3432,17 @@ nsDOMWindowUtils::HandleFullscreenReques
 
   *aRetVal = nsIDocument::HandlePendingFullscreenRequests(doc);
   return NS_OK;
 }
 
 nsresult
 nsDOMWindowUtils::ExitFullscreen()
 {
-  PROFILER_MARKER("Exit fullscreen");
+  profiler_add_marker("Exit fullscreen");
   nsCOMPtr<nsIDocument> doc = GetDocument();
   NS_ENSURE_STATE(doc);
 
   // Although we would not use the old size if we have already exited
   // fullscreen, we still want to cleanup in case we haven't.
   nsSize oldSize = OldWindowSize::GetAndRemove(mWindow);
   if (!doc->GetFullscreenElement()) {
     return NS_OK;
--- a/dom/base/nsFrameLoader.cpp
+++ b/dom/base/nsFrameLoader.cpp
@@ -95,16 +95,18 @@
 #include "mozilla/dom/CustomEvent.h"
 
 #include "mozilla/dom/ipc/StructuredCloneData.h"
 #include "mozilla/WebBrowserPersistLocalDocument.h"
 #include "mozilla/dom/GroupedHistoryEvent.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/PromiseNativeHandler.h"
 
+#include "mozilla/dom/HTMLBodyElement.h"
+
 #include "ContentPrincipal.h"
 
 #ifdef XP_WIN
 #include "mozilla/plugins/PPluginWidgetParent.h"
 #include "../plugins/ipc/PluginWidgetParent.h"
 #endif
 
 #ifdef MOZ_XUL
@@ -265,17 +267,17 @@ nsFrameLoader::LoadFrame()
   }
 
   if (doc->IsLoadedAsInteractiveData()) {
     // XBL bindings doc shouldn't load sub-documents.
     return NS_OK;
   }
 
   nsCOMPtr<nsIURI> base_uri = mOwnerContent->GetBaseURI();
-  const nsAFlatCString &doc_charset = doc->GetDocumentCharacterSet();
+  const nsCString& doc_charset = doc->GetDocumentCharacterSet();
   const char *charset = doc_charset.IsEmpty() ? nullptr : doc_charset.get();
 
   nsCOMPtr<nsIURI> uri;
   nsresult rv = NS_NewURI(getter_AddRefs(uri), src, charset, base_uri);
 
   // If the URI was malformed, try to recover by loading about:blank.
   if (rv == NS_ERROR_MALFORMED_URI) {
     rv = NS_NewURI(getter_AddRefs(uri), NS_LITERAL_STRING("about:blank"),
--- a/dom/base/nsFrameMessageManager.cpp
+++ b/dom/base/nsFrameMessageManager.cpp
@@ -1516,22 +1516,23 @@ nsMessageManagerScriptExecutor::Shutdown
     sScriptCacheCleaner = nullptr;
   }
 }
 
 void
 nsMessageManagerScriptExecutor::LoadScriptInternal(const nsAString& aURL,
                                                    bool aRunInGlobalScope)
 {
-#ifdef MOZ_GECKO_PROFILER
-  NS_LossyConvertUTF16toASCII urlCStr(aURL);
-  PROFILER_LABEL_DYNAMIC("nsMessageManagerScriptExecutor", "LoadScriptInternal",
-                          js::ProfileEntry::Category::OTHER,
-                          urlCStr.get());
-#endif
+  if (profiler_is_active()) {
+    NS_LossyConvertUTF16toASCII urlCStr(aURL);
+    PROFILER_LABEL_DYNAMIC("nsMessageManagerScriptExecutor",
+                           "LoadScriptInternal",
+                           js::ProfileEntry::Category::OTHER,
+                           urlCStr.get());
+  }
 
   if (!mGlobal || !sCachedScripts) {
     return;
   }
 
   JS::RootingContext* rcx = RootingCx();
   JS::Rooted<JSScript*> script(rcx);
 
--- a/dom/base/nsGkAtomList.h
+++ b/dom/base/nsGkAtomList.h
@@ -509,16 +509,17 @@ GK_ATOM(h3, "h3")
 GK_ATOM(h4, "h4")
 GK_ATOM(h5, "h5")
 GK_ATOM(h6, "h6")
 GK_ATOM(handheld, "handheld")
 GK_ATOM(handheldFriendly, "HandheldFriendly")
 GK_ATOM(handler, "handler")
 GK_ATOM(handlers, "handlers")
 GK_ATOM(HARD, "HARD")
+GK_ATOM(haspopup, "haspopup")
 GK_ATOM(hasSameNode, "has-same-node")
 GK_ATOM(hbox, "hbox")
 GK_ATOM(head, "head")
 GK_ATOM(header, "header")
 GK_ATOM(headers, "headers")
 GK_ATOM(height, "height")
 GK_ATOM(hgroup, "hgroup")
 GK_ATOM(hidden, "hidden")
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -993,16 +993,17 @@ NextWindowID();
 } // namespace mozilla
 
 template<class T>
 nsPIDOMWindow<T>::nsPIDOMWindow(nsPIDOMWindowOuter *aOuterWindow)
 : mFrameElement(nullptr), mDocShell(nullptr), mModalStateDepth(0),
   mMutationBits(0), mIsDocumentLoaded(false),
   mIsHandlingResizeEvent(false), mIsInnerWindow(aOuterWindow != nullptr),
   mMayHavePaintEventListener(false), mMayHaveTouchEventListener(false),
+  mMayHaveSelectionChangeEventListener(false),
   mMayHaveMouseEnterLeaveEventListener(false),
   mMayHavePointerEnterLeaveEventListener(false),
   mInnerObjectsFreed(false),
   mIsModalContentWindow(false),
   mIsActive(false), mIsBackground(false),
   mMediaSuspend(Preferences::GetBool("media.block-autoplay-until-in-foreground", true) ?
     nsISuspendedTypes::SUSPENDED_BLOCK : nsISuspendedTypes::NONE_SUSPENDED),
   mAudioMuted(false), mAudioVolume(1.0), mAudioCaptured(false),
@@ -6966,22 +6967,22 @@ FullscreenTransitionTask::Run()
   mStage = Stage(mStage + 1);
   if (MOZ_UNLIKELY(mWidget->Destroyed())) {
     // If the widget has been destroyed before we get here, don't try to
     // do anything more. Just let it go and release ourselves.
     NS_WARNING("The widget to fullscreen has been destroyed");
     return NS_OK;
   }
   if (stage == eBeforeToggle) {
-    PROFILER_MARKER("Fullscreen transition start");
+    profiler_add_marker("Fullscreen transition start");
     mWidget->PerformFullscreenTransition(nsIWidget::eBeforeFullscreenToggle,
                                          mDuration.mFadeIn, mTransitionData,
                                          this);
   } else if (stage == eToggleFullscreen) {
-    PROFILER_MARKER("Fullscreen toggle start");
+    profiler_add_marker("Fullscreen toggle start");
     mFullscreenChangeStartTime = TimeStamp::Now();
     if (MOZ_UNLIKELY(mWindow->mFullScreen != mFullscreen)) {
       // This could happen in theory if several fullscreen requests in
       // different direction happen continuously in a short time. We
       // need to ensure the fullscreen state matches our target here,
       // otherwise the widget would change the window state as if we
       // toggle for Fullscreen Mode instead of Fullscreen API.
       NS_WARNING("The fullscreen state of the window does not match");
@@ -7015,17 +7016,17 @@ FullscreenTransitionTask::Run()
     mTimer->Init(observer, timeout, nsITimer::TYPE_ONE_SHOT);
   } else if (stage == eAfterToggle) {
     Telemetry::AccumulateTimeDelta(Telemetry::FULLSCREEN_TRANSITION_BLACK_MS,
                                    mFullscreenChangeStartTime);
     mWidget->PerformFullscreenTransition(nsIWidget::eAfterFullscreenToggle,
                                          mDuration.mFadeOut, mTransitionData,
                                          this);
   } else if (stage == eEnd) {
-    PROFILER_MARKER("Fullscreen transition end");
+    profiler_add_marker("Fullscreen transition end");
   }
   return NS_OK;
 }
 
 NS_IMPL_ISUPPORTS(FullscreenTransitionTask::Observer, nsIObserver)
 
 NS_IMETHODIMP
 FullscreenTransitionTask::Observer::Observe(nsISupports* aSubject,
@@ -7036,28 +7037,28 @@ FullscreenTransitionTask::Observer::Obse
   if (strcmp(aTopic, FullscreenTransitionTask::kPaintedTopic) == 0) {
     nsCOMPtr<nsPIDOMWindowInner> win(do_QueryInterface(aSubject));
     nsCOMPtr<nsIWidget> widget = win ?
       nsGlobalWindow::Cast(win)->GetMainWidget() : nullptr;
     if (widget == mTask->mWidget) {
       // The paint notification arrives first. Cancel the timer.
       mTask->mTimer->Cancel();
       shouldContinue = true;
-      PROFILER_MARKER("Fullscreen toggle end");
+      profiler_add_marker("Fullscreen toggle end");
     }
   } else {
 #ifdef DEBUG
     MOZ_ASSERT(strcmp(aTopic, NS_TIMER_CALLBACK_TOPIC) == 0,
                "Should only get fullscreen-painted or timer-callback");
     nsCOMPtr<nsITimer> timer(do_QueryInterface(aSubject));
     MOZ_ASSERT(timer && timer == mTask->mTimer,
                "Should only trigger this with the timer the task created");
 #endif
     shouldContinue = true;
-    PROFILER_MARKER("Fullscreen toggle timeout");
+    profiler_add_marker("Fullscreen toggle timeout");
   }
   if (shouldContinue) {
     nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
     obs->RemoveObserver(this, kPaintedTopic);
     mTask->mTimer = nullptr;
     mTask->Run();
   }
   return NS_OK;
--- a/dom/base/nsImageLoadingContent.cpp
+++ b/dom/base/nsImageLoadingContent.cpp
@@ -1123,17 +1123,17 @@ nsImageLoadingContent::StringToURI(const
   NS_PRECONDITION(aDocument, "Must have a document");
   NS_PRECONDITION(aURI, "Null out param");
 
   // (1) Get the base URI
   nsIContent* thisContent = AsContent();
   nsCOMPtr<nsIURI> baseURL = thisContent->GetBaseURI();
 
   // (2) Get the charset
-  const nsAFlatCString &charset = aDocument->GetDocumentCharacterSet();
+  const nsCString& charset = aDocument->GetDocumentCharacterSet();
 
   // (3) Construct the silly thing
   return NS_NewURI(aURI,
                    aSpec,
                    charset.IsEmpty() ? nullptr : charset.get(),
                    baseURL,
                    nsContentUtils::GetIOService());
 }
--- a/dom/base/nsJSUtils.cpp
+++ b/dom/base/nsJSUtils.cpp
@@ -130,20 +130,18 @@ EvaluationExceptionToNSResult(JSContext*
     return NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW;
   }
   return NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW_UNCATCHABLE;
 }
 
 nsJSUtils::ExecutionContext::ExecutionContext(JSContext* aCx,
                                               JS::Handle<JSObject*> aGlobal)
   :
-#ifdef MOZ_GECKO_PROFILER
     mAutoProfilerLabel("nsJSUtils::ExecutionContext", /* dynamicStr */ nullptr,
                        __LINE__, js::ProfileEntry::Category::JS),
-#endif
     mCx(aCx)
   , mCompartment(aCx, aGlobal)
   , mRetValue(aCx)
   , mScopeChain(aCx)
   , mRv(NS_OK)
   , mSkip(false)
   , mCoerceToString(false)
   , mEncodeBytecode(false)
--- a/dom/base/nsJSUtils.h
+++ b/dom/base/nsJSUtils.h
@@ -63,20 +63,18 @@ public:
                                   uint32_t aArgCount,
                                   const char** aArgArray,
                                   const nsAString& aBody,
                                   JSObject** aFunctionObject);
 
 
   // ExecutionContext is used to switch compartment.
   class MOZ_STACK_CLASS ExecutionContext {
-#ifdef MOZ_GECKO_PROFILER
     // Register stack annotations for the Gecko profiler.
     mozilla::AutoProfilerLabel mAutoProfilerLabel;
-#endif
 
     JSContext* mCx;
 
     // Handles switching to our global's compartment.
     JSAutoCompartment mCompartment;
 
     // Set to a valid handle if a return value is expected.
     JS::Rooted<JS::Value> mRetValue;
--- a/dom/base/nsNodeUtils.cpp
+++ b/dom/base/nsNodeUtils.cpp
@@ -538,16 +538,19 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNod
             window->SetHasTouchEventListeners();
           }
           if (elm->MayHaveMouseEnterLeaveEventListener()) {
             window->SetHasMouseEnterLeaveEventListeners();
           }
           if (elm->MayHavePointerEnterLeaveEventListener()) {
             window->SetHasPointerEnterLeaveEventListeners();
           }
+          if (elm->MayHaveSelectionChangeEventListener()) {
+            window->SetHasSelectionChangeEventListeners();
+          }
         }
       }
     }
 
     if (wasRegistered && oldDoc != newDoc) {
       nsCOMPtr<nsIDOMHTMLMediaElement> domMediaElem(do_QueryInterface(aNode));
       if (domMediaElem) {
         HTMLMediaElement* mediaElem = static_cast<HTMLMediaElement*>(aNode);
--- a/dom/base/nsPIDOMWindow.h
+++ b/dom/base/nsPIDOMWindow.h
@@ -361,16 +361,34 @@ public:
   {
     if (!mMayHaveTouchEventListener) {
       mMayHaveTouchEventListener = true;
       MaybeUpdateTouchState();
     }
   }
 
   /**
+   * Call this to indicate that some node (this window, its document,
+   * or content in that document) has a selectionchange event listener.
+   */
+  void SetHasSelectionChangeEventListeners()
+  {
+    mMayHaveSelectionChangeEventListener = true;
+  }
+
+  /**
+   * Call this to check whether some node (this window, its document,
+   * or content in that document) has a selectionchange event listener.
+   */
+  bool HasSelectionChangeEventListeners()
+  {
+    return mMayHaveSelectionChangeEventListener;
+  }
+
+  /**
    * Moves the top-level window into fullscreen mode if aIsFullScreen is true,
    * otherwise exits fullscreen.
    *
    * Outer windows only.
    */
   virtual nsresult SetFullscreenInternal(
     FullscreenReason aReason, bool aIsFullscreen) = 0;
 
@@ -662,16 +680,17 @@ protected:
   // These variables are only used on inner windows.
   uint32_t               mMutationBits;
 
   bool                   mIsDocumentLoaded;
   bool                   mIsHandlingResizeEvent;
   bool                   mIsInnerWindow;
   bool                   mMayHavePaintEventListener;
   bool                   mMayHaveTouchEventListener;
+  bool                   mMayHaveSelectionChangeEventListener;
   bool                   mMayHaveMouseEnterLeaveEventListener;
   bool                   mMayHavePointerEnterLeaveEventListener;
 
   // Used to detect whether we have called FreeInnerObjects() (e.g. to ensure
   // that a call to ResumeTimeouts() after FreeInnerObjects() does nothing).
   // This member is only used by inner windows.
   bool                   mInnerObjectsFreed;
 
--- a/dom/base/nsRange.cpp
+++ b/dom/base/nsRange.cpp
@@ -249,17 +249,16 @@ nsRange::nsRange(nsINode* aNode)
   : mRoot(nullptr)
   , mStartOffset(0)
   , mEndOffset(0)
   , mIsPositioned(false)
   , mMaySpanAnonymousSubtrees(false)
   , mIsGenerated(false)
   , mStartOffsetWasIncremented(false)
   , mEndOffsetWasIncremented(false)
-  , mEnableGravitationOnElementRemoval(true)
   , mCalledByJS(false)
 #ifdef DEBUG
   , mAssertNextInsertOrAppendIndex(-1)
   , mAssertNextInsertOrAppendNode(nullptr)
 #endif
 {
   MOZ_ASSERT(aNode, "range isn't in a document!");
   mOwner = aNode->OwnerDoc();
@@ -699,21 +698,16 @@ nsRange::ContentRemoved(nsIDocument* aDo
       --mEndOffset;
     }
   } else if (didCheckStartParentDescendant && mStartParent == mEndParent) {
     gravitateEnd = gravitateStart;
   } else {
     gravitateEnd = nsContentUtils::ContentIsDescendantOf(mEndParent, aChild);
   }
 
-  if (!mEnableGravitationOnElementRemoval) {
-    // Do not gravitate.
-    return;
-  }
-
   if (gravitateStart || gravitateEnd) {
     DoSetRange(gravitateStart ? container : mStartParent.get(),
                gravitateStart ? aIndexInContainer : mStartOffset,
                gravitateEnd ? container : mEndParent.get(),
                gravitateEnd ? aIndexInContainer : mEndOffset,
                mRoot);
   }
   if (container->IsSelectionDescendant() &&
--- a/dom/base/nsRange.h
+++ b/dom/base/nsRange.h
@@ -60,30 +60,16 @@ public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsRange, nsIDOMRange)
 
   nsrefcnt GetRefCount() const
   {
     return mRefCnt;
   }
 
-  /**
-   * The DOM Range spec requires that when a node is removed from its parent,
-   * and the node's subtree contains the start or end point of a range, that
-   * start or end point is moved up to where the node was removed from its
-   * parent.
-   * For some internal uses of Ranges it's useful to disable that behavior,
-   * so that a range of children within a single parent is preserved even if
-   * that parent is removed from the document tree.
-   */
-  void SetEnableGravitationOnElementRemoval(bool aEnable)
-  {
-    mEnableGravitationOnElementRemoval = aEnable;
-  }
-
   // nsIDOMRange interface
   NS_DECL_NSIDOMRANGE
 
   nsINode* GetRoot() const
   {
     return mRoot;
   }
 
@@ -444,17 +430,16 @@ protected:
   int32_t mStartOffset;
   int32_t mEndOffset;
 
   bool mIsPositioned : 1;
   bool mMaySpanAnonymousSubtrees : 1;
   bool mIsGenerated : 1;
   bool mStartOffsetWasIncremented : 1;
   bool mEndOffsetWasIncremented : 1;
-  bool mEnableGravitationOnElementRemoval : 1;
   bool mCalledByJS : 1;
 #ifdef DEBUG
   int32_t  mAssertNextInsertOrAppendIndex;
   nsINode* mAssertNextInsertOrAppendNode;
 #endif
 };
 
 inline nsISupports*
--- a/dom/base/nsXMLContentSerializer.cpp
+++ b/dom/base/nsXMLContentSerializer.cpp
@@ -1432,19 +1432,19 @@ nsXMLContentSerializer::AppendToStringCo
     }
   }
 
   return true;
 }
 
 bool
 nsXMLContentSerializer::AppendFormatedWrapped_WhitespaceSequence(
-                        nsASingleFragmentString::const_char_iterator &aPos,
-                        const nsASingleFragmentString::const_char_iterator aEnd,
-                        const nsASingleFragmentString::const_char_iterator aSequenceStart,
+                        nsAString::const_char_iterator &aPos,
+                        const nsAString::const_char_iterator aEnd,
+                        const nsAString::const_char_iterator aSequenceStart,
                         bool &aMayIgnoreStartOfLineWhitespaceSequence,
                         nsAString &aOutputStr)
 {
   // Handle the complete sequence of whitespace.
   // Continue to iterate until we find the first non-whitespace char.
   // Updates "aPos" to point to the first unhandled char.
   // Also updates the aMayIgnoreStartOfLineWhitespaceSequence flag,
   // as well as the other "global" state flags.
@@ -1510,19 +1510,19 @@ nsXMLContentSerializer::AppendFormatedWr
     }
   }
 
   return true;
 }
 
 bool
 nsXMLContentSerializer::AppendWrapped_NonWhitespaceSequence(
-                        nsASingleFragmentString::const_char_iterator &aPos,
-                        const nsASingleFragmentString::const_char_iterator aEnd,
-                        const nsASingleFragmentString::const_char_iterator aSequenceStart,
+                        nsAString::const_char_iterator &aPos,
+                        const nsAString::const_char_iterator aEnd,
+                        const nsAString::const_char_iterator aSequenceStart,
                         bool &aMayIgnoreStartOfLineWhitespaceSequence,
                         bool &aSequenceStartAfterAWhiteSpace,
                         nsAString& aOutputStr)
 {
   mMayIgnoreLineBreakSequence = false;
   aMayIgnoreStartOfLineWhitespaceSequence = false;
 
   // Handle the complete sequence of non-whitespace in this block
@@ -1675,24 +1675,24 @@ nsXMLContentSerializer::AppendWrapped_No
       aSequenceStartAfterAWhiteSpace = false;
     }
   } while (onceAgainBecauseWeAddedBreakInFront);
 
   return true;
 }
 
 bool
-nsXMLContentSerializer::AppendToStringFormatedWrapped(const nsASingleFragmentString& aStr,
+nsXMLContentSerializer::AppendToStringFormatedWrapped(const nsAString& aStr,
                                                       nsAString& aOutputStr)
 {
   if (mBodyOnly && !mInBody) {
     return true;
   }
 
-  nsASingleFragmentString::const_char_iterator pos, end, sequenceStart;
+  nsAString::const_char_iterator pos, end, sequenceStart;
 
   aStr.BeginReading(pos);
   aStr.EndReading(end);
 
   bool sequenceStartAfterAWhitespace = false;
   if (pos < end) {
     nsAString::const_char_iterator end2;
     aOutputStr.EndReading(end2);
@@ -1724,29 +1724,29 @@ nsXMLContentSerializer::AppendToStringFo
     }
   }
 
   return true;
 }
 
 bool
 nsXMLContentSerializer::AppendWrapped_WhitespaceSequence(
-                        nsASingleFragmentString::const_char_iterator &aPos,
-                        const nsASingleFragmentString::const_char_iterator aEnd,
-                        const nsASingleFragmentString::const_char_iterator aSequenceStart,
+                        nsAString::const_char_iterator &aPos,
+                        const nsAString::const_char_iterator aEnd,
+                        const nsAString::const_char_iterator aSequenceStart,
                         nsAString &aOutputStr)
 {
   // Handle the complete sequence of whitespace.
   // Continue to iterate until we find the first non-whitespace char.
   // Updates "aPos" to point to the first unhandled char.
   mAddSpace = false;
   mIsIndentationAddedOnCurrentLine = false;
 
   bool leaveLoop = false;
-  nsASingleFragmentString::const_char_iterator lastPos = aPos;
+  nsAString::const_char_iterator lastPos = aPos;
 
   do {
     switch (*aPos) {
       case ' ':
       case '\t':
         // if there are too many spaces on a line, we wrap
         if (mColPos >= mMaxColumn) {
           if (lastPos != aPos) {
@@ -1778,24 +1778,24 @@ nsXMLContentSerializer::AppendWrapped_Wh
   if (lastPos != aPos) {
     NS_ENSURE_TRUE(aOutputStr.Append(lastPos, aPos - lastPos, mozilla::fallible), false);
   }
 
   return true;
 }
 
 bool
-nsXMLContentSerializer::AppendToStringWrapped(const nsASingleFragmentString& aStr,
+nsXMLContentSerializer::AppendToStringWrapped(const nsAString& aStr,
                                               nsAString& aOutputStr)
 {
   if (mBodyOnly && !mInBody) {
     return true;
   }
 
-  nsASingleFragmentString::const_char_iterator pos, end, sequenceStart;
+  nsAString::const_char_iterator pos, end, sequenceStart;
 
   aStr.BeginReading(pos);
   aStr.EndReading(end);
 
   // not used in this case, but needed by AppendWrapped_NonWhitespaceSequence
   bool mayIgnoreStartOfLineWhitespaceSequence = false;
   mMayIgnoreLineBreakSequence = false;
 
--- a/dom/base/nsXMLContentSerializer.h
+++ b/dom/base/nsXMLContentSerializer.h
@@ -108,50 +108,50 @@ class nsXMLContentSerializer : public ns
   bool AppendToStringConvertLF(const nsAString& aStr,
                                nsAString& aOutputStr);
 
   /**
    * Appends a string by wrapping it when necessary.
    * It updates the column position.
    */
   MOZ_MUST_USE
-  bool AppendToStringWrapped(const nsASingleFragmentString& aStr,
+  bool AppendToStringWrapped(const nsAString& aStr,
                              nsAString& aOutputStr);
 
   /**
    * Appends a string by formating and wrapping it when necessary
    * It updates the column position.
    */
   MOZ_MUST_USE
-  bool AppendToStringFormatedWrapped(const nsASingleFragmentString& aStr,
+  bool AppendToStringFormatedWrapped(const nsAString& aStr,
                                      nsAString& aOutputStr);
 
   // used by AppendToStringWrapped
   MOZ_MUST_USE
   bool AppendWrapped_WhitespaceSequence(
-          nsASingleFragmentString::const_char_iterator &aPos,
-          const nsASingleFragmentString::const_char_iterator aEnd,
-          const nsASingleFragmentString::const_char_iterator aSequenceStart,
+          nsAString::const_char_iterator &aPos,
+          const nsAString::const_char_iterator aEnd,
+          const nsAString::const_char_iterator aSequenceStart,
           nsAString &aOutputStr);
 
   // used by AppendToStringFormatedWrapped
   MOZ_MUST_USE
   bool AppendFormatedWrapped_WhitespaceSequence(
-          nsASingleFragmentString::const_char_iterator &aPos,
-          const nsASingleFragmentString::const_char_iterator aEnd,
-          const nsASingleFragmentString::const_char_iterator aSequenceStart,
+          nsAString::const_char_iterator &aPos,
+          const nsAString::const_char_iterator aEnd,
+          const nsAString::const_char_iterator aSequenceStart,
           bool &aMayIgnoreStartOfLineWhitespaceSequence,
           nsAString &aOutputStr);
 
   // used by AppendToStringWrapped and AppendToStringFormatedWrapped
   MOZ_MUST_USE
   bool AppendWrapped_NonWhitespaceSequence(
-          nsASingleFragmentString::const_char_iterator &aPos,
-          const nsASingleFragmentString::const_char_iterator aEnd,
-          const nsASingleFragmentString::const_char_iterator aSequenceStart,
+          nsAString::const_char_iterator &aPos,
+          const nsAString::const_char_iterator aEnd,
+          const nsAString::const_char_iterator aSequenceStart,
           bool &aMayIgnoreStartOfLineWhitespaceSequence,
           bool &aSequenceStartAfterAWhiteSpace,
           nsAString &aOutputStr);
 
   /**
    * add mLineBreak to the string
    * It updates the column position and other flags.
    */
--- a/dom/cache/TypeUtils.cpp
+++ b/dom/cache/TypeUtils.cpp
@@ -368,17 +368,17 @@ TypeUtils::ToInternalHeaders(const nsTAr
 // provide a URL without the query.  We're not using nsIURL or URL to do this because
 // they require going to the main thread.
 // static
 void
 TypeUtils::ProcessURL(nsACString& aUrl, bool* aSchemeValidOut,
                       nsACString* aUrlWithoutQueryOut,nsACString* aUrlQueryOut,
                       ErrorResult& aRv)
 {
-  const nsAFlatCString& flatURL = PromiseFlatCString(aUrl);
+  const nsCString& flatURL = PromiseFlatCString(aUrl);
   const char* url = flatURL.get();
 
   // off the main thread URL parsing using nsStdURLParser.
   nsCOMPtr<nsIURLParser> urlParser = new nsStdURLParser();
 
   uint32_t pathPos;
   int32_t pathLen;
   uint32_t schemePos;
--- a/dom/canvas/WebGLShaderValidator.cpp
+++ b/dom/canvas/WebGLShaderValidator.cpp
@@ -39,32 +39,37 @@ ChooseValidatorCompileOptions(const ShBu
 
 #ifndef XP_MACOSX
     // We want to do this everywhere, but to do this on Mac, we need
     // to do it only on Mac OSX > 10.6 as this causes the shader
     // compiler in 10.6 to crash
     options |= SH_CLAMP_INDIRECT_ARRAY_BOUNDS;
 #endif
 
+    if (gl->WorkAroundDriverBugs()) {
 #ifdef XP_MACOSX
-    if (gl->WorkAroundDriverBugs()) {
         // Work around https://bugs.webkit.org/show_bug.cgi?id=124684,
         // https://chromium.googlesource.com/angle/angle/+/5e70cf9d0b1bb
         options |= SH_UNFOLD_SHORT_CIRCUIT;
 
         // Work around that Mac drivers handle struct scopes incorrectly.
         options |= SH_REGENERATE_STRUCT_NAMES;
         options |= SH_INIT_OUTPUT_VARIABLES;
 
         // Work around that Intel drivers on Mac OSX handle for-loop incorrectly.
         if (gl->Vendor() == gl::GLVendor::Intel) {
             options |= SH_ADD_AND_TRUE_TO_LOOP_CONDITION;
+#endif
+
+        if (!gl->IsANGLE() && gl->Vendor() == gl::GLVendor::Intel) {
+            // Failures on at least Windows+Intel+OGL on:
+            // conformance/glsl/constructors/glsl-construct-mat2.html
+            options |= SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS;
         }
     }
-#endif
 
     if (gfxPrefs::WebGLAllANGLEOptions()) {
         options = -1;
 
         options ^= SH_INTERMEDIATE_TREE;
         options ^= SH_LINE_DIRECTIVES;
         options ^= SH_SOURCE_PATH;
 
--- a/dom/events/ContentEventHandler.cpp
+++ b/dom/events/ContentEventHandler.cpp
@@ -419,17 +419,17 @@ static bool IsContentBR(nsIContent* aCon
                                 eIgnoreCase);
 }
 
 static bool IsMozBR(nsIContent* aContent)
 {
   return aContent->IsHTMLElement(nsGkAtoms::br) && !IsContentBR(aContent);
 }
 
-static void ConvertToNativeNewlines(nsAFlatString& aString)
+static void ConvertToNativeNewlines(nsString& aString)
 {
 #if defined(XP_WIN)
   aString.ReplaceSubstring(NS_LITERAL_STRING("\n"), NS_LITERAL_STRING("\r\n"));
 #endif
 }
 
 static void AppendString(nsAString& aString, nsIContent* aContent)
 {
@@ -659,33 +659,33 @@ ContentEventHandler::ShouldBreakLineBefo
   // If the element is unknown element, we shouldn't insert line breaks before
   // it since unknown elements should be ignored.
   RefPtr<HTMLUnknownElement> unknownHTMLElement = do_QueryObject(aContent);
   return !unknownHTMLElement;
 }
 
 nsresult
 ContentEventHandler::GenerateFlatTextContent(nsIContent* aContent,
-                                             nsAFlatString& aString,
+                                             nsString& aString,
                                              LineBreakType aLineBreakType)
 {
   MOZ_ASSERT(aString.IsEmpty());
 
   RefPtr<nsRange> range = new nsRange(mRootContent);
   ErrorResult rv;
   range->SelectNodeContents(*aContent, rv);
   if (NS_WARN_IF(rv.Failed())) {
     return rv.StealNSResult();
   }
   return GenerateFlatTextContent(range, aString, aLineBreakType);
 }
 
 nsresult
 ContentEventHandler::GenerateFlatTextContent(nsRange* aRange,
-                                             nsAFlatString& aString,
+                                             nsString& aString,
                                              LineBreakType aLineBreakType)
 {
   MOZ_ASSERT(aString.IsEmpty());
 
   if (aRange->Collapsed()) {
     return NS_OK;
   }
 
--- a/dom/events/ContentEventHandler.h
+++ b/dom/events/ContentEventHandler.h
@@ -241,21 +241,21 @@ protected:
                                        uint32_t aXPEndOffset,
                                        LineBreakType aLineBreakType);
   // Get the contents in aContent (meaning all children of aContent) as plain
   // text.  E.g., specifying mRootContent gets whole text in it.
   // Note that the result is not same as .textContent.  The result is
   // optimized for native IMEs.  For example, <br> element and some block
   // elements causes "\n" (or "\r\n"), see also ShouldBreakLineBefore().
   nsresult GenerateFlatTextContent(nsIContent* aContent,
-                                   nsAFlatString& aString,
+                                   nsString& aString,
                                    LineBreakType aLineBreakType);
   // Get the contents of aRange as plain text.
   nsresult GenerateFlatTextContent(nsRange* aRange,
-                                   nsAFlatString& aString,
+                                   nsString& aString,
                                    LineBreakType aLineBreakType);
   // Get offset of start of aRange.  Note that the result includes the length
   // of line breaker caused by the start of aContent because aRange never
   // includes the line breaker caused by its start node.
   nsresult GetStartOffset(nsRange* aRange,
                           uint32_t* aOffset,
                           LineBreakType aLineBreakType);
   // Check if we should insert a line break before aContent.
--- a/dom/events/Event.cpp
+++ b/dom/events/Event.cpp
@@ -661,22 +661,22 @@ PopupAllowedForEvent(const char *eventNa
 
     if (!sPopupAllowedEvents) {
       return false;
     }
   }
 
   nsDependentCString events(sPopupAllowedEvents);
 
-  nsAFlatCString::const_iterator start, end;
-  nsAFlatCString::const_iterator startiter(events.BeginReading(start));
+  nsCString::const_iterator start, end;
+  nsCString::const_iterator startiter(events.BeginReading(start));
   events.EndReading(end);
 
   while (startiter != end) {
-    nsAFlatCString::const_iterator enditer(end);
+    nsCString::const_iterator enditer(end);
 
     if (!FindInReadable(nsDependentCString(eventName), startiter, enditer))
       return false;
 
     // the match is surrounded by spaces, or at a string boundary
     if ((startiter == start || *--startiter == ' ') &&
         (enditer == end || *enditer == ' ')) {
       return true;
--- a/dom/events/EventListenerManager.cpp
+++ b/dom/events/EventListenerManager.cpp
@@ -125,16 +125,17 @@ EventListenerManagerBase::EventListenerM
   , mMayHaveMutationListeners(false)
   , mMayHaveCapturingListeners(false)
   , mMayHaveSystemGroupListeners(false)
   , mMayHaveTouchEventListener(false)
   , mMayHaveMouseEnterLeaveEventListener(false)
   , mMayHavePointerEnterLeaveEventListener(false)
   , mMayHaveKeyEventListener(false)
   , mMayHaveInputOrCompositionEventListener(false)
+  , mMayHaveSelectionChangeEventListener(false)
   , mClearingListeners(false)
   , mIsMainThreadELM(NS_IsMainThread())
 {
   static_assert(sizeof(EventListenerManagerBase) == sizeof(uint32_t),
                 "Keep the size of EventListenerManagerBase size compact!");
 }
 
 EventListenerManager::EventListenerManager(EventTarget* aTarget)
@@ -412,16 +413,21 @@ EventListenerManager::AddEventListenerIn
     }
   } else if (aTypeAtom == nsGkAtoms::oncompositionend ||
              aTypeAtom == nsGkAtoms::oncompositionstart ||
              aTypeAtom == nsGkAtoms::oncompositionupdate ||
              aTypeAtom == nsGkAtoms::oninput) {
     if (!aFlags.mInSystemGroup) {
       mMayHaveInputOrCompositionEventListener = true;
     }
+  } else if (aEventMessage == eSelectionChange) {
+    mMayHaveSelectionChangeEventListener = true;
+     if (nsPIDOMWindowInner* window = GetInnerWindowForTarget()) {
+      window->SetHasSelectionChangeEventListeners();
+    }
   }
 
   if (IsApzAwareListener(listener)) {
     ProcessApzAwareEventListenerAdd();
   }
 
   if (mTarget) {
     if (aTypeAtom) {
@@ -1294,22 +1300,20 @@ EventListenerManager::HandleEventInterna
                                      typeCStr.get());
               TimeStamp startTime = TimeStamp::Now();
 
               rv = HandleEventSubType(listener, *aDOMEvent, aCurrentTarget);
 
               TimeStamp endTime = TimeStamp::Now();
               uint16_t phase;
               (*aDOMEvent)->GetEventPhase(&phase);
-              PROFILER_MARKER_PAYLOAD(
+              profiler_add_marker(
                 "DOMEvent",
                 MakeUnique<DOMEventMarkerPayload>(typeStr, phase,
                                                   startTime, endTime));
-#else
-              MOZ_CRASH("Gecko Profiler is N/A but profiler_is_active() returned true");
 #endif
             } else {
               rv = HandleEventSubType(listener, *aDOMEvent, aCurrentTarget);
             }
 
             if (NS_FAILED(rv)) {
               aEvent->mFlags.mExceptionWasRaised = true;
             }
--- a/dom/events/EventListenerManager.h
+++ b/dom/events/EventListenerManager.h
@@ -160,19 +160,20 @@ protected:
   uint16_t mMayHaveMutationListeners : 1;
   uint16_t mMayHaveCapturingListeners : 1;
   uint16_t mMayHaveSystemGroupListeners : 1;
   uint16_t mMayHaveTouchEventListener : 1;
   uint16_t mMayHaveMouseEnterLeaveEventListener : 1;
   uint16_t mMayHavePointerEnterLeaveEventListener : 1;
   uint16_t mMayHaveKeyEventListener : 1;
   uint16_t mMayHaveInputOrCompositionEventListener : 1;
+  uint16_t mMayHaveSelectionChangeEventListener : 1;
   uint16_t mClearingListeners : 1;
   uint16_t mIsMainThreadELM : 1;
-  // uint16_t mUnused : 5;
+  // uint16_t mUnused : 4;
 };
 
 /*
  * Event listener manager
  */
 
 class EventListenerManager final : public EventListenerManagerBase
 {
@@ -436,16 +437,17 @@ public:
   /**
    * Returns true if there may be a touch event listener registered,
    * false if there definitely isn't.
    */
   bool MayHaveTouchEventListener() { return mMayHaveTouchEventListener; }
 
   bool MayHaveMouseEnterLeaveEventListener() { return mMayHaveMouseEnterLeaveEventListener; }
   bool MayHavePointerEnterLeaveEventListener() { return mMayHavePointerEnterLeaveEventListener; }
+  bool MayHaveSelectionChangeEventListener() { return mMayHaveSelectionChangeEventListener; }
 
   /**
    * Returns true if there may be a key event listener (keydown, keypress,
    * or keyup) registered, or false if there definitely isn't.
    */
   bool MayHaveKeyEventListener() { return mMayHaveKeyEventListener; }
 
   /**
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -1398,17 +1398,16 @@ NS_IMPL_RELEASE_INHERITED(HTMLMediaEleme
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLMediaElement)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLMediaElement, nsGenericHTMLElement)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaSource)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSrcMediaSource)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSrcStream)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSrcAttrStream)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSourcePointer)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLoadBlockedDoc)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSourceLoadCandidate)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAudioChannelWrapper)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mErrorSink->mError)
   for (uint32_t i = 0; i < tmp->mOutputStreams.Length(); ++i) {
     NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOutputStreams[i].mStream);
   }
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPlayed);
@@ -1417,25 +1416,25 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVideoTrackList)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaKeys)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSelectedVideoStreamTrack)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPendingPlayPromises)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSeekDOMPromise)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLMediaElement, nsGenericHTMLElement)
+  tmp->RemoveMutationObserver(tmp);
   if (tmp->mSrcStream) {
     // Need to EndMediaStreamPlayback to clear mSrcStream and make sure everything
     // gets unhooked correctly.
     tmp->EndSrcMediaStreamPlayback();
   }
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mSrcAttrStream)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mMediaSource)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mSrcMediaSource)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mSourcePointer)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mLoadBlockedDoc)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mSourceLoadCandidate)
   if (tmp->mAudioChannelWrapper) {
     tmp->mAudioChannelWrapper->Shutdown();
   }
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mAudioChannelWrapper)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mErrorSink->mError)
   for (uint32_t i = 0; i < tmp->mOutputStreams.Length(); ++i) {
@@ -1458,16 +1457,45 @@ NS_INTERFACE_MAP_END_INHERITING(nsGeneri
 // nsIDOMHTMLMediaElement
 NS_IMPL_URI_ATTR(HTMLMediaElement, Src, src)
 NS_IMPL_BOOL_ATTR(HTMLMediaElement, Controls, controls)
 NS_IMPL_BOOL_ATTR(HTMLMediaElement, Autoplay, autoplay)
 NS_IMPL_BOOL_ATTR(HTMLMediaElement, Loop, loop)
 NS_IMPL_BOOL_ATTR(HTMLMediaElement, DefaultMuted, muted)
 NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(HTMLMediaElement, Preload, preload, nullptr)
 
+void
+HTMLMediaElement::ContentInserted(nsIDocument* aDocument,
+                                  nsIContent*  aContainer,
+                                  nsIContent*  aChild,
+                                  int32_t      aIndexInContainer)
+{
+  if (aContainer != this ||
+      aIndexInContainer >= int32_t(mSourcePointer) ||
+      aIndexInContainer < 0) {
+    return;
+  }
+  ++mSourcePointer;
+}
+
+void
+HTMLMediaElement::ContentRemoved(nsIDocument* aDocument,
+                                 nsIContent*  aContainer,
+                                 nsIContent*  aChild,
+                                 int32_t      aIndexInContainer,
+                                 nsIContent*  aPreviousSibling)
+{
+  if (aContainer != this ||
+      aIndexInContainer >= int32_t(mSourcePointer) ||
+      aIndexInContainer < 0) {
+    return;
+  }
+  --mSourcePointer;
+}
+
 NS_IMETHODIMP_(bool)
 HTMLMediaElement::IsVideo()
 {
   return false;
 }
 
 already_AddRefed<MediaSource>
 HTMLMediaElement::GetMozMediaSourceObject() const
@@ -1736,17 +1764,17 @@ void HTMLMediaElement::AbortExistingLoad
   mAllowSuspendAfterFirstFrame = true;
   mHaveQueuedSelectResource = false;
   mSuspendedForPreloadNone = false;
   mDownloadSuspendedByCache = false;
   mMediaInfo = MediaInfo();
   mIsEncrypted = false;
   mPendingEncryptedInitData.Reset();
   mWaitingForKey = NOT_WAITING_FOR_KEY;
-  mSourcePointer = nullptr;
+  mSourcePointer = 0;
 
   mTags = nullptr;
 
   if (mNetworkState != nsIDOMHTMLMediaElement::NETWORK_EMPTY) {
     NS_ASSERTION(!mDecoder && !mSrcStream, "How did someone setup a new stream/decoder already?");
     // ChangeNetworkState() will call UpdateAudioChannelPlayingState()
     // indirectly which depends on mPaused. So we need to update mPaused first.
     if (!mPaused) {
@@ -2239,20 +2267,17 @@ HTMLMediaElement::NotifyOutputTrackStopp
 
 void HTMLMediaElement::LoadFromSourceChildren()
 {
   NS_ASSERTION(mDelayingLoadEvent,
                "Should delay load event (if in document) during load");
   NS_ASSERTION(mIsLoadingFromSourceChildren,
                "Must remember we're loading from source children");
 
-  nsIDocument* parentDoc = OwnerDoc()->GetParentDocument();
-  if (parentDoc) {
-    parentDoc->FlushPendingNotifications(FlushType::Layout);
-  }
+  AddMutationObserverUnlessExists(this);
 
   while (true) {
     nsIContent* child = GetNextSource();
     if (!child) {
       // Exhausted candidates, wait for more candidates to be appended to
       // the media element.
       mLoadWaitStatus = WAITING_FOR_SOURCE;
       ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_NO_SOURCE);
@@ -3703,16 +3728,17 @@ NS_IMPL_ISUPPORTS(HTMLMediaElement::Shut
 HTMLMediaElement::HTMLMediaElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
   : nsGenericHTMLElement(aNodeInfo),
     mAbstractMainThread(OwnerDoc()->AbstractMainThreadFor(TaskCategory::Other)),
     mWatchManager(this, mAbstractMainThread),
     mSrcStreamTracksAvailable(false),
     mSrcStreamPausedCurrentTime(-1),
     mShutdownObserver(new ShutdownObserver),
     mCurrentLoadID(0),
+    mSourcePointer(0),
     mNetworkState(nsIDOMHTMLMediaElement::NETWORK_EMPTY),
     mReadyState(nsIDOMHTMLMediaElement::HAVE_NOTHING, "HTMLMediaElement::mReadyState"),
     mLoadWaitStatus(NOT_WAITING),
     mVolume(1.0),
     mPreloadAction(PRELOAD_UNDEFINED),
     mLastCurrentTime(0.0),
     mFragmentStart(-1.0),
     mFragmentEnd(-1.0),
@@ -6351,56 +6377,26 @@ void HTMLMediaElement::NotifyAddedSource
     // multiple <source> are attached in an event loop.
     mLoadWaitStatus = NOT_WAITING;
     QueueLoadFromSourceTask();
   }
 }
 
 nsIContent* HTMLMediaElement::GetNextSource()
 {
-  nsCOMPtr<nsIDOMNode> thisDomNode = do_QueryObject(this);
-
   mSourceLoadCandidate = nullptr;
 
-  nsresult rv = NS_OK;
-  if (!mSourcePointer) {
-    // First time this has been run, create a selection to cover children.
-    mSourcePointer = new nsRange(this);
-    // If this media element is removed from the DOM, don't gravitate the
-    // range up to its ancestor, leave it attached to the media element.
-    mSourcePointer->SetEnableGravitationOnElementRemoval(false);
-
-    rv = mSourcePointer->SelectNodeContents(thisDomNode);
-    if (NS_FAILED(rv)) return nullptr;
-
-    rv = mSourcePointer->Collapse(true);
-    if (NS_FAILED(rv)) return nullptr;
-  }
-
   while (true) {
-#ifdef DEBUG
-    nsCOMPtr<nsIDOMNode> startContainer;
-    rv = mSourcePointer->GetStartContainer(getter_AddRefs(startContainer));
-    if (NS_FAILED(rv)) return nullptr;
-    NS_ASSERTION(startContainer == thisDomNode,
-                "Should only iterate over direct children");
-#endif
-
-    int32_t startOffset = 0;
-    rv = mSourcePointer->GetStartOffset(&startOffset);
-    NS_ENSURE_SUCCESS(rv, nullptr);
-
-    if (uint32_t(startOffset) == GetChildCount())
+    if (mSourcePointer >= GetChildCount())
       return nullptr; // No more children.
 
-    // Advance the range to the next child.
-    rv = mSourcePointer->SetStart(thisDomNode, startOffset + 1);
-    NS_ENSURE_SUCCESS(rv, nullptr);
-
-    nsIContent* child = GetChildAt(startOffset);
+    nsIContent* child = GetChildAt(mSourcePointer);
+
+    // Advance to the next child.
+    ++mSourcePointer;
 
     // If child is a <source> element, it is the next candidate.
     if (child && child->IsHTMLElement(nsGkAtoms::source)) {
       mSourceLoadCandidate = child;
       return child;
     }
   }
   NS_NOTREACHED("Execution should not reach here!");
--- a/dom/html/HTMLMediaElement.h
+++ b/dom/html/HTMLMediaElement.h
@@ -18,16 +18,17 @@
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/TextTrackManager.h"
 #include "mozilla/WeakPtr.h"
 #include "MediaDecoder.h"
 #include "mozilla/dom/MediaKeys.h"
 #include "mozilla/StateWatching.h"
 #include "nsGkAtoms.h"
 #include "PrincipalChangeObserver.h"
+#include "nsStubMutationObserver.h"
 
 // X.h on Linux #defines CurrentTime as 0L, so we have to #undef it here.
 #ifdef CurrentTime
 #undef CurrentTime
 #endif
 
 #include "mozilla/dom/HTMLMediaElementBinding.h"
 
@@ -79,28 +80,31 @@ class Promise;
 class TextTrackList;
 class AudioTrackList;
 class VideoTrackList;
 
 class HTMLMediaElement : public nsGenericHTMLElement,
                          public nsIDOMHTMLMediaElement,
                          public MediaDecoderOwner,
                          public PrincipalChangeObserver<DOMMediaStream>,
-                         public SupportsWeakPtr<HTMLMediaElement>
+                         public SupportsWeakPtr<HTMLMediaElement>,
+                         public nsStubMutationObserver
 {
 public:
   typedef mozilla::TimeStamp TimeStamp;
   typedef mozilla::layers::ImageContainer ImageContainer;
   typedef mozilla::VideoFrameContainer VideoFrameContainer;
   typedef mozilla::MediaStream MediaStream;
   typedef mozilla::MediaResource MediaResource;
   typedef mozilla::MediaDecoderOwner MediaDecoderOwner;
   typedef mozilla::MetadataTags MetadataTags;
 
   MOZ_DECLARE_WEAKREFERENCE_TYPENAME(HTMLMediaElement)
+  NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
+  NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
 
   CORSMode GetCORSMode() {
     return mCORSMode;
   }
 
   explicit HTMLMediaElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
 
   void ReportCanPlayTelemetry();
@@ -1373,18 +1377,20 @@ protected:
   RefPtr<ChannelLoader> mChannelLoader;
 
   // The current media load ID. This is incremented every time we start a
   // new load. Async events note the ID when they're first sent, and only fire
   // if the ID is unchanged when they come to fire.
   uint32_t mCurrentLoadID;
 
   // Points to the child source elements, used to iterate through the children
-  // when selecting a resource to load.
-  RefPtr<nsRange> mSourcePointer;
+  // when selecting a resource to load.  This is the index of the child element
+  // that is the current 'candidate' in:
+  // https://html.spec.whatwg.org/multipage/media.html#concept-media-load-algorithm
+  uint32_t mSourcePointer;
 
   // Points to the document whose load we're blocking. This is the document
   // we're bound to when loading starts.
   nsCOMPtr<nsIDocument> mLoadBlockedDoc;
 
   // Contains names of events that have been raised while in the bfcache.
   // These events get re-dispatched when the bfcache is exited.
   nsTArray<nsString> mPendingEvents;
--- a/dom/indexedDB/ProfilerHelpers.h
+++ b/dom/indexedDB/ProfilerHelpers.h
@@ -300,17 +300,17 @@ LoggingHelper(bool aUseProfiler, const c
       message.AppendPrintf(aFmt, args);
 
       va_end(args);
     }
 
     MOZ_LOG(logModule, logLevel, ("%s", message.get()));
 
     if (aUseProfiler) {
-      PROFILER_MARKER(message.get());
+      profiler_add_marker(message.get());
     }
   }
 }
 
 } // namespace indexedDB
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl
@@ -1412,16 +1412,21 @@ interface nsIDOMWindowUtils : nsISupport
   /**
    * True if the layer manager for the widget associated with this window is
    * forwarding layers to a remote compositor, false otherwise. Throws an
    * error if there is no widget associated with this window.
    */
   readonly attribute boolean layerManagerRemote;
 
   /**
+   * True if advanced layers is enabled on this window, false otherwise.
+   */
+  readonly attribute boolean usingAdvancedLayers;
+
+  /**
    * Returns a Promise that will be resolved with a string once the capabilities
    * of the h264 decoder have been determined.
    * Success does not mean that all h264 video decoding will be done
    * in hardware.
    */
   readonly attribute jsval supportsHardwareH264Decoding;
 
   /**
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -1514,17 +1514,17 @@ ContentChild::RecvSetProcessSandbox(cons
       // didn't intend it.
       MOZ_RELEASE_ASSERT(brokerFd >= 0);
     }
     // Allow user overrides of seccomp-bpf syscall filtering
     std::vector<int> syscallWhitelist;
     nsAdoptingCString extraSyscalls =
       Preferences::GetCString("security.sandbox.content.syscall_whitelist");
     if (extraSyscalls) {
-      for (const nsCSubstring& callNrString : extraSyscalls.Split(',')) {
+      for (const nsACString& callNrString : extraSyscalls.Split(',')) {
         nsresult rv;
         int callNr = PromiseFlatCString(callNrString).ToInteger(&rv);
         if (NS_SUCCEEDED(rv)) {
           syscallWhitelist.push_back(callNr);
         }
       }
     }
     sandboxEnabled = SetContentProcessSandbox(brokerFd, syscallWhitelist);
--- a/dom/jsurl/nsJSProtocolHandler.cpp
+++ b/dom/jsurl/nsJSProtocolHandler.cpp
@@ -1137,17 +1137,17 @@ nsJSProtocolHandler::Create(nsISupports 
     if (NS_SUCCEEDED(rv)) {
         rv = ph->QueryInterface(aIID, aResult);
     }
     NS_RELEASE(ph);
     return rv;
 }
 
 nsresult 
-nsJSProtocolHandler::EnsureUTF8Spec(const nsAFlatCString &aSpec, const char *aCharset, 
+nsJSProtocolHandler::EnsureUTF8Spec(const nsCString& aSpec, const char *aCharset, 
                                     nsACString &aUTF8Spec)
 {
   aUTF8Spec.Truncate();
 
   nsresult rv;
   
   if (!mTextToSubURI) {
     mTextToSubURI = do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv);
--- a/dom/jsurl/nsJSProtocolHandler.h
+++ b/dom/jsurl/nsJSProtocolHandler.h
@@ -49,17 +49,17 @@ public:
     static nsresult
     Create(nsISupports *aOuter, REFNSIID aIID, void **aResult);
 
     nsresult Init();
 
 protected:
     virtual ~nsJSProtocolHandler();
 
-    nsresult EnsureUTF8Spec(const nsAFlatCString &aSpec, const char *aCharset, 
+    nsresult EnsureUTF8Spec(const nsCString& aSpec, const char *aCharset, 
                             nsACString &aUTF8Spec);
 
     nsCOMPtr<nsITextToSubURI>  mTextToSubURI;
 };
 
 
 class nsJSURI : public mozilla::net::nsSimpleURI
 {
--- a/dom/media/VideoUtils.cpp
+++ b/dom/media/VideoUtils.cpp
@@ -412,17 +412,17 @@ LogToBrowserConsole(const nsAString& aMs
 
 bool
 ParseCodecsString(const nsAString& aCodecs, nsTArray<nsString>& aOutCodecs)
 {
   aOutCodecs.Clear();
   bool expectMoreTokens = false;
   nsCharSeparatedTokenizer tokenizer(aCodecs, ',');
   while (tokenizer.hasMoreTokens()) {
-    const nsSubstring& token = tokenizer.nextToken();
+    const nsAString& token = tokenizer.nextToken();
     expectMoreTokens = tokenizer.separatorAfterCurrentToken();
     aOutCodecs.AppendElement(token);
   }
   if (expectMoreTokens) {
     // Last codec name was empty
     return false;
   }
   return true;
--- a/dom/performance/Performance.cpp
+++ b/dom/performance/Performance.cpp
@@ -294,17 +294,17 @@ Performance::Mark(const nsAString& aName
   }
 
   RefPtr<PerformanceMark> performanceMark =
     new PerformanceMark(GetAsISupports(), aName, Now());
   InsertUserEntry(performanceMark);
 
 #ifdef MOZ_GECKO_PROFILER
   if (profiler_is_active()) {
-    PROFILER_MARKER_PAYLOAD(
+    profiler_add_marker(
       "UserTiming",
       MakeUnique<UserTimingMarkerPayload>(aName, TimeStamp::Now()));
   }
 #endif
 }
 
 void
 Performance::ClearMarks(const Optional<nsAString>& aName)
@@ -392,17 +392,17 @@ Performance::Measure(const nsAString& aN
   InsertUserEntry(performanceMeasure);
 
 #ifdef MOZ_GECKO_PROFILER
   if (profiler_is_active()) {
     TimeStamp startTimeStamp = CreationTimeStamp() +
                                TimeDuration::FromMilliseconds(startTime);
     TimeStamp endTimeStamp = CreationTimeStamp() +
                              TimeDuration::FromMilliseconds(endTime);
-    PROFILER_MARKER_PAYLOAD(
+    profiler_add_marker(
       "UserTiming",
       MakeUnique<UserTimingMarkerPayload>(aName, startTimeStamp, endTimeStamp));
   }
 #endif
 }
 
 void
 Performance::ClearMeasures(const Optional<nsAString>& aName)
--- a/dom/plugins/base/nsPluginTags.cpp
+++ b/dom/plugins/base/nsPluginTags.cpp
@@ -38,17 +38,17 @@ static const char kPrefDefaultEnabledSta
 static const char kPrefDefaultEnabledStateXpi[] = "plugin.defaultXpi.state";
 
 // check comma delimited extensions
 static bool ExtensionInList(const nsCString& aExtensionList,
                             const nsACString& aExtension)
 {
   nsCCharSeparatedTokenizer extensions(aExtensionList, ',');
   while (extensions.hasMoreTokens()) {
-    const nsCSubstring& extension = extensions.nextToken();
+    const nsACString& extension = extensions.nextToken();
     if (extension.Equals(aExtension, nsCaseInsensitiveCStringComparator())) {
       return true;
     }
   }
   return false;
 }
 
 // Search for an extension in an extensions array, and return its
@@ -439,17 +439,17 @@ nsPluginTag::InitSandboxLevel()
     mSandboxLevel = 2;
   }
 #endif
 #endif
 }
 
 #if !defined(XP_WIN) && !defined(XP_MACOSX)
 static void
-ConvertToUTF8(nsAFlatCString& aString)
+ConvertToUTF8(nsCString& aString)
 {
   Unused << UTF_8_ENCODING->DecodeWithoutBOMHandling(aString, aString);
 }
 #endif
 
 nsresult nsPluginTag::EnsureMembersAreUTF8()
 {
 #if defined(XP_WIN) || defined(XP_MACOSX)
--- a/dom/security/FramingChecker.cpp
+++ b/dom/security/FramingChecker.cpp
@@ -234,17 +234,17 @@ FramingChecker::CheckFrameOptions(nsICha
   if (xfoHeaderValue.IsEmpty()) {
     return true;
   }
 
   // iterate through all the header values (usually there's only one, but can
   // be many.  If any want to deny the load, deny the load.
   nsCharSeparatedTokenizer tokenizer(xfoHeaderValue, ',');
   while (tokenizer.hasMoreTokens()) {
-    const nsSubstring& tok = tokenizer.nextToken();
+    const nsAString& tok = tokenizer.nextToken();
     if (!CheckOneFrameOptionsPolicy(httpChannel, tok, aDocShell)) {
       // cancel the load and display about:blank
       httpChannel->Cancel(NS_BINDING_ABORTED);
       if (aDocShell) {
         nsCOMPtr<nsIWebNavigation> webNav(do_QueryObject(aDocShell));
         if (webNav) {
           nsCOMPtr<nsILoadInfo> loadInfo = httpChannel->GetLoadInfo();
           nsCOMPtr<nsIPrincipal> triggeringPrincipal = loadInfo
--- a/dom/security/nsCSPUtils.cpp
+++ b/dom/security/nsCSPUtils.cpp
@@ -423,17 +423,17 @@ CSP_AppendCSPFromHeader(nsIContentSecuri
   NS_ENSURE_ARG(aCsp);
 
   // Need to tokenize the header value since multiple headers could be
   // concatenated into one comma-separated list of policies.
   // See RFC2616 section 4.2 (last paragraph)
   nsresult rv = NS_OK;
   nsCharSeparatedTokenizer tokenizer(aHeaderValue, ',');
   while (tokenizer.hasMoreTokens()) {
-    const nsSubstring& policy = tokenizer.nextToken();
+    const nsAString& policy = tokenizer.nextToken();
     rv = aCsp->AppendPolicy(policy, aReportOnly, false);
     NS_ENSURE_SUCCESS(rv, rv);
     {
       CSPUTILSLOG(("CSP refined with policy: \"%s\"",
                    NS_ConvertUTF16toUTF8(policy).get()));
     }
   }
   return NS_OK;
--- a/dom/security/nsContentSecurityManager.cpp
+++ b/dom/security/nsContentSecurityManager.cpp
@@ -721,17 +721,17 @@ nsContentSecurityManager::IsOriginPotent
   // check to see if it has been whitelisted by the user.  We only apply this
   // whitelist for network resources, i.e., those with scheme "http" or "ws".
   // The pref should contain a comma-separated list of hostnames.
   if (scheme.EqualsLiteral("http") || scheme.EqualsLiteral("ws")) {
     nsAdoptingCString whitelist = Preferences::GetCString("dom.securecontext.whitelist");
     if (whitelist) {
       nsCCharSeparatedTokenizer tokenizer(whitelist, ',');
       while (tokenizer.hasMoreTokens()) {
-        const nsCSubstring& allowedHost = tokenizer.nextToken();
+        const nsACString& allowedHost = tokenizer.nextToken();
         if (host.Equals(allowedHost)) {
           *aIsTrustWorthy = true;
           return NS_OK;
         }
       }
     }
   }
 
--- a/dom/security/test/gtest/TestCSPParser.cpp
+++ b/dom/security/test/gtest/TestCSPParser.cpp
@@ -12,18 +12,18 @@
 #ifndef MOZILLA_INTERNAL_API
 // some of the includes make use of internal string types
 #define nsAString_h___
 #define nsString_h___
 #define nsStringFwd_h___
 #define nsReadableUtils_h___
 class nsACString;
 class nsAString;
-class nsAFlatString;
-class nsAFlatCString;
+class nsString;
+class nsCString;
 class nsAdoptingString;
 class nsAdoptingCString;
 class nsXPIDLString;
 template<class T> class nsReadingIterator;
 #endif
 
 #include "nsIContentSecurityPolicy.h"
 #include "nsNetUtil.h"
--- a/dom/storage/LocalStorage.cpp
+++ b/dom/storage/LocalStorage.cpp
@@ -170,19 +170,19 @@ LocalStorage::Clear(nsIPrincipal& aSubje
   }
 
   if (!aRv.ErrorCodeIs(NS_SUCCESS_DOM_NO_OPERATION)) {
     BroadcastChangeNotification(NullString(), NullString(), NullString());
   }
 }
 
 void
-LocalStorage::BroadcastChangeNotification(const nsSubstring& aKey,
-                                          const nsSubstring& aOldValue,
-                                          const nsSubstring& aNewValue)
+LocalStorage::BroadcastChangeNotification(const nsAString& aKey,
+                                          const nsAString& aOldValue,
+                                          const nsAString& aNewValue)
 {
   if (!XRE_IsParentProcess() && Principal()) {
     // If we are in a child process, we want to send a message to the parent in
     // order to broadcast the StorageEvent correctly to any child process.
     dom::ContentChild* cc = dom::ContentChild::GetSingleton();
     Unused << NS_WARN_IF(!cc->SendBroadcastLocalStorageChange(
       mDocumentURI, nsString(aKey), nsString(aOldValue), nsString(aNewValue),
       IPC::Principal(Principal()), mIsPrivate));
--- a/dom/storage/LocalStorage.h
+++ b/dom/storage/LocalStorage.h
@@ -110,17 +110,17 @@ private:
 
   // Principal this Storage (i.e. localStorage or sessionStorage) has
   // been created for
   nsCOMPtr<nsIPrincipal> mPrincipal;
 
   // Whether this storage is running in private-browsing window.
   bool mIsPrivate : 1;
 
-  void BroadcastChangeNotification(const nsSubstring& aKey,
-                                   const nsSubstring& aOldValue,
-                                   const nsSubstring& aNewValue);
+  void BroadcastChangeNotification(const nsAString& aKey,
+                                   const nsAString& aOldValue,
+                                   const nsAString& aNewValue);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_LocalStorage_h
--- a/dom/storage/StorageUtils.cpp
+++ b/dom/storage/StorageUtils.cpp
@@ -79,17 +79,17 @@ PrincipalsEqual(nsIPrincipal* aObjectPri
   if (!aObjectPrincipal) {
     return false;
   }
 
   return aSubjectPrincipal->Equals(aObjectPrincipal);
 }
 
 void
-ReverseString(const nsCSubstring& aSource, nsCSubstring& aResult)
+ReverseString(const nsACString& aSource, nsACString& aResult)
 {
   nsACString::const_iterator sourceBegin, sourceEnd;
   aSource.BeginReading(sourceBegin);
   aSource.EndReading(sourceEnd);
 
   aResult.SetLength(aSource.Length());
   nsACString::iterator destEnd;
   aResult.EndWriting(destEnd);
--- a/dom/storage/StorageUtils.h
+++ b/dom/storage/StorageUtils.h
@@ -17,17 +17,17 @@ nsresult
 GenerateOriginKey(nsIPrincipal* aPrincipal, nsACString& aOriginAttrSuffix,
                   nsACString& aOriginKey);
 
 bool
 PrincipalsEqual(nsIPrincipal* aObjectPrincipal,
                 nsIPrincipal* aSubjectPrincipal);
 
 void
-ReverseString(const nsCSubstring& aSource, nsCSubstring& aResult);
+ReverseString(const nsACString& aSource, nsACString& aResult);
 
 nsresult
 CreateReversedDomain(const nsACString& aAsciiDomain,
                      nsACString& aKey);
 
 } // StorageUtils namespace
 } // dom namespace
 } // mozilla namespace
--- a/dom/svg/SVGTests.cpp
+++ b/dom/svg/SVGTests.cpp
@@ -67,31 +67,31 @@ SVGTests::IsConditionalProcessingAttribu
     if (aAttribute == *sStringListNames[i]) {
       return true;
     }
   }
   return false;
 }
 
 int32_t
-SVGTests::GetBestLanguagePreferenceRank(const nsSubstring& aAcceptLangs) const
+SVGTests::GetBestLanguagePreferenceRank(const nsAString& aAcceptLangs) const
 {
   const nsDefaultStringComparator defaultComparator;
 
   if (!mStringListAttributes[LANGUAGE].IsExplicitlySet()) {
     return -2;
   }
 
   int32_t lowestRank = -1;
 
   for (uint32_t i = 0; i < mStringListAttributes[LANGUAGE].Length(); i++) {
     nsCharSeparatedTokenizer languageTokenizer(aAcceptLangs, ',');
     int32_t index = 0;
     while (languageTokenizer.hasMoreTokens()) {
-      const nsSubstring &languageToken = languageTokenizer.nextToken();
+      const nsAString& languageToken = languageTokenizer.nextToken();
       bool exactMatch = (languageToken == mStringListAttributes[LANGUAGE][i]);
       bool prefixOnlyMatch =
         !exactMatch &&
         nsStyleUtil::DashMatchCompare(mStringListAttributes[LANGUAGE][i],
                                       languageTokenizer.nextToken(),
                                       defaultComparator);
       if (index == 0 && exactMatch) {
         // best possible match
--- a/dom/svg/SVGTests.h
+++ b/dom/svg/SVGTests.h
@@ -41,17 +41,17 @@ public:
    * We have a match if a language name in the users language preferences
    * exactly equals one of the language names or exactly equals a prefix of
    * one of the language names in the systemLanguage attribute.
    * @returns 2 * the lowest index in the aAcceptLangs that matches + 1
    * if only the prefix matches, -2 if there's no systemLanguage attribute,
    * or -1 if no indices match.
    * XXX This algorithm is O(M*N).
    */
-  int32_t GetBestLanguagePreferenceRank(const nsSubstring& aAcceptLangs) const;
+  int32_t GetBestLanguagePreferenceRank(const nsAString& aAcceptLangs) const;
 
   /**
    * Special value to pass to PassesConditionalProcessingTests to ignore systemLanguage
    * attributes
    */
   static const nsString * const kIgnoreSystemLanguage;
 
   /**
--- a/dom/svg/nsSVGElement.cpp
+++ b/dom/svg/nsSVGElement.cpp
@@ -2489,17 +2489,17 @@ nsSVGElement::StringListAttributesInfo::
   // caller notifies
 }
 
 nsresult
 nsSVGElement::ReportAttributeParseFailure(nsIDocument* aDocument,
                                           nsIAtom* aAttribute,
                                           const nsAString& aValue)
 {
-  const nsAFlatString& attributeValue = PromiseFlatString(aValue);
+  const nsString& attributeValue = PromiseFlatString(aValue);
   const char16_t *strings[] = { aAttribute->GetUTF16String(),
                                  attributeValue.get() };
   return SVGContentUtils::ReportToConsole(aDocument,
                                           "AttributeParseWarning",
                                           strings, ArrayLength(strings));
 }
 
 void
--- a/dom/webauthn/U2FSoftTokenManager.cpp
+++ b/dom/webauthn/U2FSoftTokenManager.cpp
@@ -628,33 +628,46 @@ U2FSoftTokenManager::IsRegistered(const 
 // 1      0x05
 // 65     public key
 // 1      key handle length
 // *      key handle
 // ASN.1  attestation certificate
 // *      attestation signature
 //
 nsresult
-U2FSoftTokenManager::Register(const nsTArray<uint8_t>& aApplication,
+U2FSoftTokenManager::Register(const nsTArray<WebAuthnScopedCredentialDescriptor>& aDescriptors,
+                              const nsTArray<uint8_t>& aApplication,
                               const nsTArray<uint8_t>& aChallenge,
                               /* out */ nsTArray<uint8_t>& aRegistration,
                               /* out */ nsTArray<uint8_t>& aSignature)
 {
   nsNSSShutDownPreventionLock locker;
   if (NS_WARN_IF(isAlreadyShutDown())) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   if (!mInitialized) {
     nsresult rv = Init();
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
 
+  // Optional exclusion list.
+  for (auto desc: aDescriptors) {
+    bool isRegistered = false;
+    nsresult rv = IsRegistered(desc.id(), aApplication, isRegistered);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    if (isRegistered) {
+      return NS_ERROR_DOM_NOT_ALLOWED_ERR;
+    }
+  }
+
   // We should already have a wrapping key
   MOZ_ASSERT(mWrappingKey);
 
   UniquePK11SlotInfo slot(PK11_GetInternalSlot());
   MOZ_ASSERT(slot.get());
 
   // Construct a one-time-use Attestation Certificate
   UniqueSECKEYPrivateKey attestPrivKey;
@@ -740,34 +753,41 @@ U2FSoftTokenManager::Register(const nsTA
 //
 // The format of the signature data is as follows:
 //
 //  1     User presence
 //  4     Counter
 //  *     Signature
 //
 nsresult
-U2FSoftTokenManager::Sign(const nsTArray<uint8_t>& aApplication,
+U2FSoftTokenManager::Sign(const nsTArray<WebAuthnScopedCredentialDescriptor>& aDescriptors,
+                          const nsTArray<uint8_t>& aApplication,
                           const nsTArray<uint8_t>& aChallenge,
-                          const nsTArray<uint8_t>& aKeyHandle,
+                          nsTArray<uint8_t>& aKeyHandle,
                           nsTArray<uint8_t>& aSignature)
 {
   nsNSSShutDownPreventionLock locker;
   if (NS_WARN_IF(isAlreadyShutDown())) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
-  MOZ_ASSERT(mInitialized);
-  if (NS_WARN_IF(!mInitialized)) {
-    nsresult rv = Init();
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
+  for (auto desc: aDescriptors) {
+    bool isRegistered = false;
+    nsresult rv = IsRegistered(desc.id(), aApplication, isRegistered);
+    if (NS_SUCCEEDED(rv) && isRegistered) {
+      aKeyHandle.Assign(desc.id());
+      break;
     }
   }
 
+  // Fail if we didn't recognize a key id.
+  if (aKeyHandle.IsEmpty()) {
+    return NS_ERROR_DOM_NOT_ALLOWED_ERR;
+  }
+
   MOZ_ASSERT(mWrappingKey);
 
   UniquePK11SlotInfo slot(PK11_GetInternalSlot());
   MOZ_ASSERT(slot.get());
 
   if (NS_WARN_IF((aChallenge.Length() != kParamLen) || (aApplication.Length() != kParamLen))) {
     MOZ_LOG(gNSSTokenLog, LogLevel::Warning,
             ("Parameter lengths are wrong! challenge=%d app=%d expected=%d",
--- a/dom/webauthn/U2FSoftTokenManager.h
+++ b/dom/webauthn/U2FSoftTokenManager.h
@@ -19,37 +19,42 @@
 namespace mozilla {
 namespace dom {
 
 class U2FSoftTokenManager final : public U2FTokenTransport,
                                   public nsNSSShutDownObject
 {
 public:
   explicit U2FSoftTokenManager(uint32_t aCounter);
-  virtual nsresult Register(const nsTArray<uint8_t>& aApplication,
+
+  virtual nsresult Register(const nsTArray<WebAuthnScopedCredentialDescriptor>& aDescriptors,
+                            const nsTArray<uint8_t>& aApplication,
                             const nsTArray<uint8_t>& aChallenge,
                             /* out */ nsTArray<uint8_t>& aRegistration,
                             /* out */ nsTArray<uint8_t>& aSignature) override;
-  virtual nsresult Sign(const nsTArray<uint8_t>& aApplication,
+
+  virtual nsresult Sign(const nsTArray<WebAuthnScopedCredentialDescriptor>& aDescriptors,
+                        const nsTArray<uint8_t>& aApplication,
                         const nsTArray<uint8_t>& aChallenge,
-                        const nsTArray<uint8_t>& aKeyHandle,
+                        /* out */ nsTArray<uint8_t>& aKeyHandle,
                         /* out */ nsTArray<uint8_t>& aSignature) override;
-  nsresult IsRegistered(const nsTArray<uint8_t>& aKeyHandle,
-                        const nsTArray<uint8_t>& aAppParam,
-                        bool& aResult);
 
   // For nsNSSShutDownObject
   virtual void virtualDestroyNSSReference() override;
   void destructorSafeDestroyNSSReference();
 
 private:
   ~U2FSoftTokenManager();
   nsresult Init();
   bool IsCompatibleVersion(const nsAString& aVersion);
 
+  nsresult IsRegistered(const nsTArray<uint8_t>& aKeyHandle,
+                        const nsTArray<uint8_t>& aAppParam,
+                        bool& aResult);
+
   bool mInitialized;
   mozilla::UniquePK11SymKey mWrappingKey;
 
   static const nsCString mSecretNickname;
   static const nsString mVersion;
 
   nsresult GetOrCreateWrappingKey(const mozilla::UniquePK11SlotInfo& aSlot,
                                   const nsNSSShutDownPreventionLock&);
--- a/dom/webauthn/U2FTokenManager.cpp
+++ b/dom/webauthn/U2FTokenManager.cpp
@@ -149,17 +149,17 @@ U2FTokenManager::MaybeClearTransaction(W
 {
   // Only clear if we've been requested to do so by our current transaction
   // parent.
   if (mTransactionParent != aParent) {
     return;
   }
   mTransactionParent = nullptr;
   // Drop managers at the end of all transactions
-  mSoftTokenManager = nullptr;
+  mTokenManagerImpl = nullptr;
 }
 
 void
 U2FTokenManager::Cancel(const nsresult& aError)
 {
   if (mTransactionParent) {
     Unused << mTransactionParent->SendCancel(aError);
   }
@@ -174,106 +174,89 @@ U2FTokenManager::Register(WebAuthnTransa
   MOZ_ASSERT(U2FPrefManager::Get());
   mTransactionParent = aTransactionParent;
 
   // Since we only have soft token available at the moment, use that if the pref
   // is on.
   //
   // TODO Check all transports and use WebAuthnRequest to aggregate
   // replies
-  if (U2FPrefManager::Get()->GetSoftTokenEnabled()) {
-    if (!mSoftTokenManager) {
-      mSoftTokenManager = new U2FSoftTokenManager(U2FPrefManager::Get()->GetSoftTokenCounter());
-    }
-
-    // Check if all the supplied parameters are syntactically well-formed and
-    // of the correct length. If not, return an error code equivalent to
-    // UnknownError and terminate the operation.
-
-    if ((aTransactionInfo.RpIdHash().Length() != SHA256_LENGTH) ||
-        (aTransactionInfo.ClientDataHash().Length() != SHA256_LENGTH)) {
-      Cancel(NS_ERROR_DOM_UNKNOWN_ERR);
-      return;
-    }
-
-    nsresult rv;
-
-    for (auto desc: aTransactionInfo.Descriptors()) {
-      bool isRegistered = false;
-      rv = mSoftTokenManager->IsRegistered(desc.id(), aTransactionInfo.RpIdHash(), isRegistered);
-      if (NS_FAILED(rv)) {
-        Cancel(rv);
-        return;
-      }
-      if (isRegistered) {
-        Cancel(NS_ERROR_DOM_NOT_ALLOWED_ERR);
-        return;
-      }
-    }
-
-    nsTArray<uint8_t> reg;
-    nsTArray<uint8_t> sig;
-    rv = mSoftTokenManager->Register(aTransactionInfo.RpIdHash(),
-                                     aTransactionInfo.ClientDataHash(),
-                                     reg,
-                                     sig);
-    if (NS_FAILED(rv)) {
-      Cancel(rv);
-      return;
-    }
-    Unused << mTransactionParent->SendConfirmRegister(reg,
-                                                      sig);
-    MaybeClearTransaction(mTransactionParent);
+  if (!U2FPrefManager::Get()->GetSoftTokenEnabled()) {
+    Cancel(NS_ERROR_DOM_NOT_ALLOWED_ERR);
     return;
   }
-  Cancel(NS_ERROR_DOM_NOT_ALLOWED_ERR);
+
+  if (!mTokenManagerImpl) {
+    mTokenManagerImpl = new U2FSoftTokenManager(U2FPrefManager::Get()->GetSoftTokenCounter());
+  }
+
+  // Check if all the supplied parameters are syntactically well-formed and
+  // of the correct length. If not, return an error code equivalent to
+  // UnknownError and terminate the operation.
+
+  if ((aTransactionInfo.RpIdHash().Length() != SHA256_LENGTH) ||
+      (aTransactionInfo.ClientDataHash().Length() != SHA256_LENGTH)) {
+    Cancel(NS_ERROR_DOM_UNKNOWN_ERR);
+    return;
+  }
+
+  nsTArray<uint8_t> reg;
+  nsTArray<uint8_t> sig;
+  nsresult rv = mTokenManagerImpl->Register(aTransactionInfo.Descriptors(),
+                                            aTransactionInfo.RpIdHash(),
+                                            aTransactionInfo.ClientDataHash(),
+                                            reg,
+                                            sig);
+  if (NS_FAILED(rv)) {
+    Cancel(rv);
+    return;
+  }
+
+  Unused << mTransactionParent->SendConfirmRegister(reg, sig);
+  MaybeClearTransaction(mTransactionParent);
 }
 
 void
 U2FTokenManager::Sign(WebAuthnTransactionParent* aTransactionParent,
                       const WebAuthnTransactionInfo& aTransactionInfo)
 {
   MOZ_LOG(gU2FTokenManagerLog, LogLevel::Debug, ("U2FAuthSign"));
   MOZ_ASSERT(U2FPrefManager::Get());
   mTransactionParent = aTransactionParent;
 
   // Since we only have soft token available at the moment, use that if the pref
   // is on.
   //
   // TODO Check all transports and use WebAuthnRequest to aggregate
   // replies
-  if (U2FPrefManager::Get()->GetSoftTokenEnabled()) {
-    if (!mSoftTokenManager) {
-      mSoftTokenManager = new U2FSoftTokenManager(U2FPrefManager::Get()->GetSoftTokenCounter());
-    }
+  if (!U2FPrefManager::Get()->GetSoftTokenEnabled()) {
+    Cancel(NS_ERROR_DOM_NOT_ALLOWED_ERR);
+    return;
+  }
 
-    if ((aTransactionInfo.RpIdHash().Length() != SHA256_LENGTH) ||
-        (aTransactionInfo.ClientDataHash().Length() != SHA256_LENGTH)) {
-      Cancel(NS_ERROR_DOM_UNKNOWN_ERR);
-      return;
-    }
+  if (!mTokenManagerImpl) {
+    mTokenManagerImpl = new U2FSoftTokenManager(U2FPrefManager::Get()->GetSoftTokenCounter());
+  }
+
+  if ((aTransactionInfo.RpIdHash().Length() != SHA256_LENGTH) ||
+      (aTransactionInfo.ClientDataHash().Length() != SHA256_LENGTH)) {
+    Cancel(NS_ERROR_DOM_UNKNOWN_ERR);
+    return;
+  }
 
-    for (auto desc: aTransactionInfo.Descriptors()) {
-      bool reg;
-      nsresult rv = mSoftTokenManager->IsRegistered(desc.id(), aTransactionInfo.RpIdHash(), reg);
-      if (!reg) {
-        continue;
-      }
-      nsTArray<uint8_t> sig;
-      rv = mSoftTokenManager->Sign(aTransactionInfo.RpIdHash(),
-                                   aTransactionInfo.ClientDataHash(),
-                                   desc.id(),
-                                   sig);
-      if (NS_FAILED(rv)) {
-        Cancel(rv);
-        return;
-      }
-      Unused << mTransactionParent->SendConfirmSign(desc.id(), sig);
-      MaybeClearTransaction(mTransactionParent);
-      return;
-    }
+  nsTArray<uint8_t> id;
+  nsTArray<uint8_t> sig;
+  nsresult rv = mTokenManagerImpl->Sign(aTransactionInfo.Descriptors(),
+                                        aTransactionInfo.RpIdHash(),
+                                        aTransactionInfo.ClientDataHash(),
+                                        id,
+                                        sig);
+  if (NS_FAILED(rv)) {
+    Cancel(rv);
+    return;
   }
-  // If we come out of the loop, we aren't registered
-  Cancel(NS_ERROR_DOM_NOT_ALLOWED_ERR);
+
+  Unused << mTransactionParent->SendConfirmSign(id, sig);
+  MaybeClearTransaction(mTransactionParent);
 }
 
 }
 }
--- a/dom/webauthn/U2FTokenManager.h
+++ b/dom/webauthn/U2FTokenManager.h
@@ -29,17 +29,16 @@ class WebAuthnTransactionParent;
 
 class U2FTokenManager final
 {
   struct U2FPrefs
   {
     bool softTokenEnabled;
     uint32_t softTokenCounter;
   };
-  typedef MozPromise<bool, nsresult, false> PrefPromise;
 public:
   enum TransactionType
   {
     RegisterTransaction = 0,
     SignTransaction,
     NumTransactionTypes
   };
   NS_INLINE_DECL_REFCOUNTING(U2FTokenManager)
@@ -53,15 +52,15 @@ public:
 private:
   U2FTokenManager();
   ~U2FTokenManager();
   void Cancel(const nsresult& aError);
   // Using a raw pointer here, as the lifetime of the IPC object is managed by
   // the PBackground protocol code. This means we cannot be left holding an
   // invalid IPC protocol object after the transaction is finished.
   WebAuthnTransactionParent* mTransactionParent;
-  RefPtr<U2FSoftTokenManager> mSoftTokenManager;
+  RefPtr<U2FTokenTransport> mTokenManagerImpl;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_U2FTokenManager_h
--- a/dom/webauthn/U2FTokenTransport.h
+++ b/dom/webauthn/U2FTokenTransport.h
@@ -2,38 +2,45 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* 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_dom_U2FTokenTransport_h
 #define mozilla_dom_U2FTokenTransport_h
 
+#include "mozilla/dom/PWebAuthnTransaction.h"
+
 /*
  * Abstract class representing a transport manager for U2F Keys (software,
  * bluetooth, usb, etc.). Hides the implementation details for specific key
  * transport types.
  */
 
 namespace mozilla {
 namespace dom {
 
 class U2FTokenTransport
 {
 public:
   NS_INLINE_DECL_REFCOUNTING(U2FTokenTransport);
   U2FTokenTransport() {}
-  virtual nsresult Register(const nsTArray<uint8_t>& aApplication,
+
+  virtual nsresult Register(const nsTArray<WebAuthnScopedCredentialDescriptor>& aDescriptors,
+                            const nsTArray<uint8_t>& aApplication,
                             const nsTArray<uint8_t>& aChallenge,
                             /* out */ nsTArray<uint8_t>& aRegistration,
                             /* out */ nsTArray<uint8_t>& aSignature) = 0;
-  virtual nsresult Sign(const nsTArray<uint8_t>& aApplication,
+
+  virtual nsresult Sign(const nsTArray<WebAuthnScopedCredentialDescriptor>& aDescriptors,
+                        const nsTArray<uint8_t>& aApplication,
                         const nsTArray<uint8_t>& aChallenge,
-                        const nsTArray<uint8_t>& aKeyHandle,
+                        /* out */ nsTArray<uint8_t>& aKeyHandle,
                         /* out */ nsTArray<uint8_t>& aSignature) = 0;
+
 protected:
   virtual ~U2FTokenTransport() = default;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_U2FTokenTransport_h
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -2901,35 +2901,31 @@ WorkerThreadPrimaryRunnable::Run()
 
     if (!InitJSContextForWorker(mWorkerPrivate, cx)) {
       // XXX need to fire an error at parent.
       NS_ERROR("Failed to create context!");
       return NS_ERROR_FAILURE;
     }
 
     {
-#ifdef MOZ_GECKO_PROFILER
       profiler_set_js_context(cx);
-#endif
 
       {
         JSAutoRequest ar(cx);
 
         mWorkerPrivate->DoRunLoop(cx);
         // The AutoJSAPI in DoRunLoop should have reported any exceptions left
         // on cx.  Note that we still need the JSAutoRequest above because
         // AutoJSAPI on workers does NOT enter a request!
         MOZ_ASSERT(!JS_IsExceptionPending(cx));
       }
 
       BackgroundChild::CloseForCurrentThread();
 
-#ifdef MOZ_GECKO_PROFILER
       profiler_clear_js_context();
-#endif
     }
 
     // There may still be runnables on the debugger event queue that hold a
     // strong reference to the debugger global scope. These runnables are not
     // visible to the cycle collector, so we need to make sure to clear the
     // debugger event queue before we try to destroy the context. If we don't,
     // the garbage collector will crash.
     mWorkerPrivate->ClearDebuggerEventQueue();
--- a/dom/xbl/nsXBLBinding.cpp
+++ b/dom/xbl/nsXBLBinding.cpp
@@ -983,17 +983,17 @@ GetProtoBindingFromClassObject(JSObject*
   return static_cast<nsXBLPrototypeBinding*>(::JS_GetReservedSlot(obj, 0).toPrivate());
 }
 
 
 // static
 nsresult
 nsXBLBinding::DoInitJSClass(JSContext *cx,
                             JS::Handle<JSObject*> obj,
-                            const nsAFlatString& aClassName,
+                            const nsString& aClassName,
                             nsXBLPrototypeBinding* aProtoBinding,
                             JS::MutableHandle<JSObject*> aClassObject,
                             bool* aNew)
 {
   MOZ_ASSERT(obj);
 
   // Note that, now that NAC reflectors are created in the XBL scope, the
   // reflector is not necessarily same-compartment with the document. So we'll
--- a/dom/xbl/nsXBLBinding.h
+++ b/dom/xbl/nsXBLBinding.h
@@ -128,17 +128,17 @@ public:
 
   void ChangeDocument(nsIDocument* aOldDocument, nsIDocument* aNewDocument);
 
   void WalkRules(nsIStyleRuleProcessor::EnumFunc aFunc, void* aData);
 
   const mozilla::ServoStyleSet* GetServoStyleSet() const;
 
   static nsresult DoInitJSClass(JSContext *cx, JS::Handle<JSObject*> obj,
-                                const nsAFlatString& aClassName,
+                                const nsString& aClassName,
                                 nsXBLPrototypeBinding* aProtoBinding,
                                 JS::MutableHandle<JSObject*> aClassObject,
                                 bool* aNew);
 
   bool AllowScripts();
 
   mozilla::dom::XBLChildrenElement* FindInsertionPointFor(nsIContent* aChild);
 
--- a/dom/xbl/nsXBLContentSink.cpp
+++ b/dom/xbl/nsXBLContentSink.cpp
@@ -84,17 +84,17 @@ nsXBLContentSink::MaybeStartLayout(bool 
 {
   return;
 }
 
 nsresult
 nsXBLContentSink::FlushText(bool aReleaseTextNode)
 {
   if (mTextLength != 0) {
-    const nsASingleFragmentString& text = Substring(mText, mText+mTextLength);
+    const nsAString& text = Substring(mText, mText+mTextLength);
     if (mState == eXBL_InHandlers) {
       NS_ASSERTION(mBinding, "Must have binding here");
       // Get the text and add it to the event handler.
       if (mSecondaryState == eXBL_InHandler)
         mHandler->AppendHandlerText(text);
       mTextLength = 0;
       return NS_OK;
     }
--- a/dom/xml/nsXMLContentSink.cpp
+++ b/dom/xml/nsXMLContentSink.cpp
@@ -655,21 +655,21 @@ nsXMLContentSink::LoadXSLStyleSheet(nsIU
   // XML document whether we're able to load the XSLT stylesheet or
   // not.
 
   return NS_OK;
 }
 
 nsresult
 nsXMLContentSink::ProcessStyleLink(nsIContent* aElement,
-                                   const nsSubstring& aHref,
+                                   const nsAString& aHref,
                                    bool aAlternate,
-                                   const nsSubstring& aTitle,
-                                   const nsSubstring& aType,
-                                   const nsSubstring& aMedia)
+                                   const nsAString& aTitle,
+                                   const nsAString& aType,
+                                   const nsAString& aMedia)
 {
   nsresult rv = NS_OK;
   mPrettyPrintXML = false;
 
   nsAutoCString cmd;
   if (mParser)
     GetParser()->GetCommand(cmd);
   if (cmd.EqualsASCII(kLoadAsData))
--- a/dom/xml/nsXMLContentSink.h
+++ b/dom/xml/nsXMLContentSink.h
@@ -141,21 +141,21 @@ protected:
   {
     if (IsTimeToNotify()) {
       FlushTags();	
     }
   }
   
   // nsContentSink override
   virtual nsresult ProcessStyleLink(nsIContent* aElement,
-                                    const nsSubstring& aHref,
+                                    const nsAString& aHref,
                                     bool aAlternate,
-                                    const nsSubstring& aTitle,
-                                    const nsSubstring& aType,
-                                    const nsSubstring& aMedia) override;
+                                    const nsAString& aTitle,
+                                    const nsAString& aType,
+                                    const nsAString& aMedia) override;
 
   nsresult LoadXSLStyleSheet(nsIURI* aUrl);
 
   bool CanStillPrettyPrint();
 
   nsresult MaybePrettyPrint();
   
   bool IsMonolithicContainer(mozilla::dom::NodeInfo* aNodeInfo);
--- a/dom/xml/nsXMLFragmentContentSink.cpp
+++ b/dom/xml/nsXMLFragmentContentSink.cpp
@@ -87,21 +87,21 @@ protected:
                                  nsIContent** aResult, bool* aAppendContent,
                                  mozilla::dom::FromParser aFromParser) override;
   virtual nsresult CloseElement(nsIContent* aContent) override;
 
   virtual void MaybeStartLayout(bool aIgnorePendingSheets) override;
 
   // nsContentSink overrides
   virtual nsresult ProcessStyleLink(nsIContent* aElement,
-                                    const nsSubstring& aHref,
+                                    const nsAString& aHref,
                                     bool aAlternate,
-                                    const nsSubstring& aTitle,
-                                    const nsSubstring& aType,
-                                    const nsSubstring& aMedia) override;
+                                    const nsAString& aTitle,
+                                    const nsAString& aType,
+                                    const nsAString& aMedia) override;
   nsresult LoadXSLStyleSheet(nsIURI* aUrl);
   void StartLayout();
 
   nsCOMPtr<nsIDocument> mTargetDocument;
   // the fragment
   nsCOMPtr<nsIContent>  mRoot;
   bool                  mParseError;
 };
@@ -323,21 +323,21 @@ nsXMLFragmentContentSink::ReportError(co
   // destructor, so don't mess with it.
   mTextLength = 0;
 
   return NS_OK; 
 }
 
 nsresult
 nsXMLFragmentContentSink::ProcessStyleLink(nsIContent* aElement,
-                                           const nsSubstring& aHref,
+                                           const nsAString& aHref,
                                            bool aAlternate,
-                                           const nsSubstring& aTitle,
-                                           const nsSubstring& aType,
-                                           const nsSubstring& aMedia)
+                                           const nsAString& aTitle,
+                                           const nsAString& aType,
+                                           const nsAString& aMedia)
 {
   // don't process until moved to document
   return NS_OK;
 }
 
 nsresult
 nsXMLFragmentContentSink::LoadXSLStyleSheet(nsIURI* aUrl)
 {
--- a/dom/xslt/base/txExpandedName.cpp
+++ b/dom/xslt/base/txExpandedName.cpp
@@ -9,17 +9,17 @@
 #include "txStringUtils.h"
 #include "txNamespaceMap.h"
 #include "txXMLUtils.h"
 
 nsresult
 txExpandedName::init(const nsAString& aQName, txNamespaceMap* aResolver,
                      bool aUseDefault)
 {
-    const nsAFlatString& qName = PromiseFlatString(aQName);
+    const nsString& qName = PromiseFlatString(aQName);
     const char16_t* colon;
     bool valid = XMLUtils::isValidQName(qName, &colon);
     if (!valid) {
         return NS_ERROR_FAILURE;
     }
 
     if (colon) {
         nsCOMPtr<nsIAtom> prefix = NS_Atomize(Substring(qName.get(), colon));
--- a/dom/xslt/base/txStringUtils.h
+++ b/dom/xslt/base/txStringUtils.h
@@ -12,17 +12,17 @@
 #include "nsContentUtils.h" // For ASCIIToLower().
 
 typedef nsCaseInsensitiveStringComparator txCaseInsensitiveStringComparator;
 
 /**
  * Check equality between a string and an atom containing ASCII.
  */
 inline bool
-TX_StringEqualsAtom(const nsASingleFragmentString& aString, nsIAtom* aAtom)
+TX_StringEqualsAtom(const nsAString& aString, nsIAtom* aAtom)
 {
   return aAtom->Equals(aString);
 }
 
 inline already_AddRefed<nsIAtom>
 TX_ToLowerCaseAtom(nsIAtom* aAtom)
 {
   nsAutoString str;
--- a/dom/xslt/xml/txXMLUtils.cpp
+++ b/dom/xslt/xml/txXMLUtils.cpp
@@ -79,17 +79,17 @@ XMLUtils::splitExpatName(const char16_t 
 
     return *aLocalName ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
 }
 
 nsresult
 XMLUtils::splitQName(const nsAString& aName, nsIAtom** aPrefix,
                      nsIAtom** aLocalName)
 {
-    const nsAFlatString& qName = PromiseFlatString(aName);
+    const nsString& qName = PromiseFlatString(aName);
     const char16_t* colon;
     bool valid = XMLUtils::isValidQName(qName, &colon);
     if (!valid) {
         return NS_ERROR_FAILURE;
     }
 
     if (colon) {
         const char16_t *end;
@@ -104,19 +104,19 @@ XMLUtils::splitQName(const nsAString& aN
     }
 
     return NS_OK;
 }
 
 /**
  * Returns true if the given string has only whitespace characters
  */
-bool XMLUtils::isWhitespace(const nsAFlatString& aText)
+bool XMLUtils::isWhitespace(const nsString& aText)
 {
-    nsAFlatString::const_char_iterator start, end;
+    nsString::const_char_iterator start, end;
     aText.BeginReading(start);
     aText.EndReading(end);
     for ( ; start != end; ++start) {
         if (!isWhitespace(*start)) {
             return false;
         }
     }
     return true;
@@ -150,18 +150,17 @@ void XMLUtils::normalizePIValue(nsAStrin
         }
         piValue.Append(ch);
         prevCh = ch;
         ++conversionLoop;
     }
 }
 
 //static
-bool XMLUtils::isValidQName(const nsAFlatString& aQName,
-                            const char16_t** aColon)
+bool XMLUtils::isValidQName(const nsString& aQName, const char16_t** aColon)
 {
   return NS_SUCCEEDED(nsContentUtils::CheckQName(aQName, true, aColon));
 }
 
 //static
 bool XMLUtils::getXMLSpacePreserve(const txXPathNode& aNode)
 {
     nsAutoString value;
--- a/dom/xslt/xml/txXMLUtils.h
+++ b/dom/xslt/xml/txXMLUtils.h
@@ -38,28 +38,27 @@ public:
         return (aChar <= ' ' &&
                 (aChar == ' ' || aChar == '\r' ||
                  aChar == '\n'|| aChar == '\t'));
     }
 
     /**
      * Returns true if the given string has only whitespace characters
      */
-    static bool isWhitespace(const nsAFlatString& aText);
+    static bool isWhitespace(const nsString& aText);
 
     /**
      * Normalizes the value of a XML processingInstruction
     **/
     static void normalizePIValue(nsAString& attValue);
 
     /**
      * Returns true if the given string is a valid XML QName
      */
-    static bool isValidQName(const nsAFlatString& aQName,
-                             const char16_t** aColon);
+    static bool isValidQName(const nsString& aQName, const char16_t** aColon);
 
     /**
      * Returns true if the given character represents an Alpha letter
      */
     static bool isLetter(char16_t aChar)
     {
         return !!MOZ_XMLIsLetter(reinterpret_cast<const char*>(&aChar));
     }   
--- a/dom/xslt/xpath/txCoreFunctionCall.cpp
+++ b/dom/xslt/xpath/txCoreFunctionCall.cpp
@@ -425,17 +425,17 @@ txCoreFunctionCall::evaluate(txIEvalCont
 
             int32_t idx = arg1.Find(arg2);
             if (idx == kNotFound) {
                 aContext->recycler()->getEmptyStringResult(aResult);
                 
                 return NS_OK;
             }
 
-            const nsSubstring& result = Substring(arg1, idx + arg2.Length());
+            const nsAString& result = Substring(arg1, idx + arg2.Length());
             return aContext->recycler()->getStringResult(result, aResult);
         }
         case SUBSTRING_BEFORE:
         {
             nsAutoString arg2;
             rv = mParams[1]->evaluateToString(aContext, arg2);
             NS_ENSURE_SUCCESS(rv, rv);
 
--- a/dom/xslt/xpath/txExprLexer.cpp
+++ b/dom/xslt/xpath/txExprLexer.cpp
@@ -87,17 +87,17 @@ txExprLexer::nextIsOperatorToken(Token* 
     aToken->mType > Token::UNION_OP;
 
 }
 
 /**
  * Parses the given string into a sequence of Tokens
  */
 nsresult
-txExprLexer::parse(const nsASingleFragmentString& aPattern)
+txExprLexer::parse(const nsAString& aPattern)
 {
   iterator start, end;
   start = aPattern.BeginReading(mPosition);
   aPattern.EndReading(end);
 
   //-- initialize previous token, this will automatically get
   //-- deleted when it goes out of scope
   Token nullToken(nullptr, nullptr, Token::NULL_TOKEN);
--- a/dom/xslt/xpath/txExprLexer.h
+++ b/dom/xslt/xpath/txExprLexer.h
@@ -83,17 +83,17 @@ public:
         //-- Special endtoken
         END // 36
     };
 
 
     /**
      * Constructors
      */
-    typedef nsASingleFragmentString::const_char_iterator iterator;
+    typedef nsAString::const_char_iterator iterator;
 
     Token(iterator aStart, iterator aEnd, Type aType)
         : mStart(aStart),
           mEnd(aEnd),
           mType(aType),
           mNext(nullptr)
     {
     }
@@ -131,19 +131,19 @@ public:
 
     /**
      * Parse the given string.
      * returns an error result if lexing failed.
      * The given string must outlive the use of the lexer, as the
      * generated Tokens point to Substrings of it.
      * mPosition points to the offending location in case of an error.
      */
-    nsresult parse(const nsASingleFragmentString& aPattern);
+    nsresult parse(const nsAString& aPattern);
 
-    typedef nsASingleFragmentString::const_char_iterator iterator;
+    typedef nsAString::const_char_iterator iterator;
     iterator mPosition;
 
     /**
      * Functions for iterating over the TokenList
      */
 
     Token* nextToken();
     Token* peek()
--- a/dom/xslt/xpath/txExprParser.cpp
+++ b/dom/xslt/xpath/txExprParser.cpp
@@ -23,28 +23,28 @@
 
 using mozilla::Move;
 
 /**
  * Creates an Attribute Value Template using the given value
  * This should move to XSLProcessor class
  */
 nsresult
-txExprParser::createAVT(const nsSubstring& aAttrValue,
+txExprParser::createAVT(const nsAString& aAttrValue,
                         txIParseContext* aContext,
                         Expr** aResult)
 {
     *aResult = nullptr;
     nsresult rv = NS_OK;
     nsAutoPtr<Expr> expr;
     FunctionCall* concat = nullptr;
 
     nsAutoString literalString;
     bool inExpr = false;
-    nsSubstring::const_char_iterator iter, start, end, avtStart;
+    nsAString::const_char_iterator iter, start, end, avtStart;
     aAttrValue.BeginReading(iter);
     aAttrValue.EndReading(end);
     avtStart = iter;
 
     while (iter != end) {
         // Every iteration through this loop parses either a literal section
         // or an expression
         start = iter;
@@ -141,37 +141,37 @@ txExprParser::createAVT(const nsSubstrin
     }
 
     *aResult = expr.forget();
 
     return NS_OK;
 }
 
 nsresult
-txExprParser::createExprInternal(const nsSubstring& aExpression,
+txExprParser::createExprInternal(const nsAString& aExpression,
                                  uint32_t aSubStringPos,
                                  txIParseContext* aContext, Expr** aExpr)
 {
     NS_ENSURE_ARG_POINTER(aExpr);
     *aExpr = nullptr;
     txExprLexer lexer;
     nsresult rv = lexer.parse(aExpression);
     if (NS_FAILED(rv)) {
-        nsASingleFragmentString::const_char_iterator start;
+        nsAString::const_char_iterator start;
         aExpression.BeginReading(start);
         aContext->SetErrorOffset(lexer.mPosition - start + aSubStringPos);
         return rv;
     }
     nsAutoPtr<Expr> expr;
     rv = createExpr(lexer, aContext, getter_Transfers(expr));
     if (NS_SUCCEEDED(rv) && lexer.peek()->mType != Token::END) {
         rv = NS_ERROR_XPATH_BINARY_EXPECTED;
     }
     if (NS_FAILED(rv)) {
-        nsASingleFragmentString::const_char_iterator start;
+        nsAString::const_char_iterator start;
         aExpression.BeginReading(start);
         aContext->SetErrorOffset(lexer.peek()->mStart - start + aSubStringPos);
 
         return rv;
     }
 
     txXPathOptimizer optimizer;
     Expr* newExpr = nullptr;
--- a/dom/xslt/xpath/txExprParser.h
+++ b/dom/xslt/xpath/txExprParser.h
@@ -25,32 +25,32 @@ class PredicateList;
 class Token;
 class txIParseContext;
 class txNodeTest;
 
 class txExprParser
 {
 public:
 
-    static nsresult createExpr(const nsSubstring& aExpression,
+    static nsresult createExpr(const nsAString& aExpression,
                                txIParseContext* aContext, Expr** aExpr)
     {
         return createExprInternal(aExpression, 0, aContext, aExpr);
     }
 
     /**
      * Creates an Attribute Value Template using the given value
      */
-    static nsresult createAVT(const nsSubstring& aAttrValue,
+    static nsresult createAVT(const nsAString& aAttrValue,
                               txIParseContext* aContext,
                               Expr** aResult);
 
 
 protected:
-    static nsresult createExprInternal(const nsSubstring& aExpression,
+    static nsresult createExprInternal(const nsAString& aExpression,
                                        uint32_t aSubStringPos,
                                        txIParseContext* aContext,
                                        Expr** aExpr);
     /**
      * Using nsAutoPtr& to optimize passing the ownership to the
      * created binary expression objects.
      */
     static nsresult createBinaryExpr(nsAutoPtr<Expr>& left,
--- a/dom/xslt/xslt/txBufferingHandler.cpp
+++ b/dom/xslt/xslt/txBufferingHandler.cpp
@@ -105,17 +105,17 @@ public:
     nsCOMPtr<nsIAtom> mLowercaseLocalName;
     int32_t mNsID;
 };
 
 class txStartElementTransaction : public txOutputTransaction
 {
 public:
     txStartElementTransaction(nsIAtom* aPrefix,
-                              const nsSubstring& aLocalName, int32_t aNsID)
+                              const nsAString& aLocalName, int32_t aNsID)
         : txOutputTransaction(eStartElementTransaction),
           mPrefix(aPrefix),
           mLocalName(aLocalName),
           mNsID(aNsID)
     {
         MOZ_COUNT_CTOR_INHERITED(txStartElementTransaction, txOutputTransaction);
     }
     virtual ~txStartElementTransaction()
@@ -126,17 +126,17 @@ public:
     nsString mLocalName;
     int32_t mNsID;
 };
 
 class txAttributeTransaction : public txOutputTransaction
 {
 public:
     txAttributeTransaction(nsIAtom* aPrefix,
-                           const nsSubstring& aLocalName, int32_t aNsID,
+                           const nsAString& aLocalName, int32_t aNsID,
                            const nsString& aValue)
         : txOutputTransaction(eAttributeTransaction),
           mPrefix(aPrefix),
           mLocalName(aLocalName),
           mNsID(aNsID),
           mValue(aValue)
     {
         MOZ_COUNT_CTOR_INHERITED(txAttributeTransaction, txOutputTransaction);
@@ -203,33 +203,33 @@ txBufferingHandler::attribute(nsIAtom* a
     txOutputTransaction* transaction =
         new txAttributeAtomTransaction(aPrefix, aLocalName,
                                        aLowercaseLocalName, aNsID,
                                        aValue);
     return mBuffer->addTransaction(transaction);
 }
 
 nsresult
-txBufferingHandler::attribute(nsIAtom* aPrefix, const nsSubstring& aLocalName,
+txBufferingHandler::attribute(nsIAtom* aPrefix, const nsAString& aLocalName,
                               const int32_t aNsID, const nsString& aValue)
 {
     NS_ENSURE_TRUE(mBuffer, NS_ERROR_OUT_OF_MEMORY);
 
     if (!mCanAddAttribute) {
         // XXX ErrorReport: Can't add attributes without element
         return NS_OK;
     }
 
     txOutputTransaction* transaction =
         new txAttributeTransaction(aPrefix, aLocalName, aNsID, aValue);
     return mBuffer->addTransaction(transaction);
 }
 
 nsresult
-txBufferingHandler::characters(const nsSubstring& aData, bool aDOE)
+txBufferingHandler::characters(const nsAString& aData, bool aDOE)
 {
     NS_ENSURE_TRUE(mBuffer, NS_ERROR_OUT_OF_MEMORY);
 
     mCanAddAttribute = false;
 
     txOutputTransaction::txTransactionType type =
          aDOE ? txOutputTransaction::eCharacterNoOETransaction
               : txOutputTransaction::eCharacterTransaction;
@@ -315,17 +315,17 @@ txBufferingHandler::startElement(nsIAtom
     txOutputTransaction* transaction =
         new txStartElementAtomTransaction(aPrefix, aLocalName,
                                           aLowercaseLocalName, aNsID);
     return mBuffer->addTransaction(transaction);
 }
 
 nsresult
 txBufferingHandler::startElement(nsIAtom* aPrefix,
-                                 const nsSubstring& aLocalName,
+                                 const nsAString& aLocalName,
                                  const int32_t aNsID)
 {
     NS_ENSURE_TRUE(mBuffer, NS_ERROR_OUT_OF_MEMORY);
 
     mCanAddAttribute = true;
 
     txOutputTransaction* transaction =
         new txStartElementTransaction(aPrefix, aLocalName, aNsID);
@@ -352,17 +352,17 @@ txResultBuffer::addTransaction(txOutputT
         return NS_ERROR_OUT_OF_MEMORY;
     }
     return NS_OK;
 }
 
 static nsresult
 flushTransaction(txOutputTransaction* aTransaction,
                  txAXMLEventHandler* aHandler,
-                 nsAFlatString::const_char_iterator& aIter)
+                 nsString::const_char_iterator& aIter)
 {
     switch (aTransaction->mType) {
         case txOutputTransaction::eAttributeAtomTransaction:
         {
             txAttributeAtomTransaction* transaction =
                 static_cast<txAttributeAtomTransaction*>(aTransaction);
             return aHandler->attribute(transaction->mPrefix,
                                        transaction->mLocalName,
@@ -379,18 +379,18 @@ flushTransaction(txOutputTransaction* aT
                                        attrTransaction->mNsID,
                                        attrTransaction->mValue);
         }
         case txOutputTransaction::eCharacterTransaction:
         case txOutputTransaction::eCharacterNoOETransaction:
         {
             txCharacterTransaction* charTransaction =
                 static_cast<txCharacterTransaction*>(aTransaction);
-            nsAFlatString::const_char_iterator start = aIter;
-            nsAFlatString::const_char_iterator end =
+            nsString::const_char_iterator start = aIter;
+            nsString::const_char_iterator end =
                 start + charTransaction->mLength;
             aIter = end;
             return aHandler->characters(Substring(start, end),
                                         aTransaction->mType ==
                                         txOutputTransaction::eCharacterNoOETransaction);
         }
         case txOutputTransaction::eCommentTransaction:
         {
@@ -437,17 +437,17 @@ flushTransaction(txOutputTransaction* aT
     }
 
     return NS_ERROR_UNEXPECTED;
 }
 
 nsresult
 txResultBuffer::flushToHandler(txAXMLEventHandler* aHandler)
 {
-    nsAFlatString::const_char_iterator iter;
+    nsString::const_char_iterator iter;
     mStringValue.BeginReading(iter);
 
     for (uint32_t i = 0, len = mTransactions.Length(); i < len; ++i) {
         nsresult rv = flushTransaction(mTransactions[i], aHandler, iter);
         NS_ENSURE_SUCCESS(rv, rv);
     }
 
     return NS_OK;
--- a/dom/xslt/xslt/txEXSLTFunctions.cpp
+++ b/dom/xslt/xslt/txEXSLTFunctions.cpp
@@ -112,17 +112,17 @@ createDocFragment(txIEvalContext *aConte
     nsIDocument *doc = txXPathNativeNode::getDocument(document);
     RefPtr<DocumentFragment> fragment =
       new DocumentFragment(doc->NodeInfoManager());
 
     return fragment.forget();
 }
 
 static nsresult
-createAndAddToResult(nsIAtom* aName, const nsSubstring& aValue,
+createAndAddToResult(nsIAtom* aName, const nsAString& aValue,
                      txNodeSet* aResultSet, nsIContent* aResultHolder)
 {
     NS_ASSERTION(aResultHolder->IsNodeOfType(nsINode::eDOCUMENT_FRAGMENT) &&
                  aResultHolder->OwnerDoc(),
                  "invalid result-holder");
 
     nsIDocument* doc = aResultHolder->OwnerDoc();
     nsCOMPtr<Element> elem = doc->CreateElem(nsDependentAtomString(aName),
--- a/dom/xslt/xslt/txInstructions.cpp
+++ b/dom/xslt/xslt/txInstructions.cpp
@@ -322,17 +322,17 @@ txCopy::execute(txExecutionState& aEs)
 {
     nsresult rv = NS_OK;
     const txXPathNode& node = aEs.getEvalContext()->getContextNode();
 
     switch (txXPathNodeUtils::getNodeType(node)) {
         case txXPathNodeType::DOCUMENT_NODE:
         case txXPathNodeType::DOCUMENT_FRAGMENT_NODE:
         {
-            const nsAFlatString& empty = EmptyString();
+            const nsString& empty = EmptyString();
 
             // "close" current element to ensure that no attributes are added
             rv = aEs.mResultHandler->characters(empty, false);
             NS_ENSURE_SUCCESS(rv, rv);
 
             rv = aEs.pushBool(false);
             NS_ENSURE_SUCCESS(rv, rv);
 
--- a/dom/xslt/xslt/txMozillaTextOutput.cpp
+++ b/dom/xslt/xslt/txMozillaTextOutput.cpp
@@ -44,25 +44,25 @@ nsresult
 txMozillaTextOutput::attribute(nsIAtom* aPrefix, nsIAtom* aLocalName,
                                nsIAtom* aLowercaseLocalName,
                                int32_t aNsID, const nsString& aValue)
 {
     return NS_OK;
 }
 
 nsresult
-txMozillaTextOutput::attribute(nsIAtom* aPrefix, const nsSubstring& aName,
+txMozillaTextOutput::attribute(nsIAtom* aPrefix, const nsAString& aName,
                                const int32_t aNsID,
                                const nsString& aValue)
 {
     return NS_OK;
 }
 
 nsresult
-txMozillaTextOutput::characters(const nsSubstring& aData, bool aDOE)
+txMozillaTextOutput::characters(const nsAString& aData, bool aDOE)
 {
     mText.Append(aData);
 
     return NS_OK;
 }
 
 nsresult
 txMozillaTextOutput::comment(const nsString& aData)
@@ -232,17 +232,17 @@ txMozillaTextOutput::createResultDocumen
 nsresult
 txMozillaTextOutput::startElement(nsIAtom* aPrefix, nsIAtom* aLocalName,
                                   nsIAtom* aLowercaseLocalName, int32_t aNsID)
 {
     return NS_OK;
 }
 
 nsresult
-txMozillaTextOutput::startElement(nsIAtom* aPrefix, const nsSubstring& aName,
+txMozillaTextOutput::startElement(nsIAtom* aPrefix, const nsAString& aName,
                                   const int32_t aNsID)
 {
     return NS_OK;
 }
 
 void txMozillaTextOutput::getOutputDocument(nsIDOMDocument** aDocument)
 {
     CallQueryInterface(mDocument, aDocument);
--- a/dom/xslt/xslt/txMozillaXMLOutput.cpp
+++ b/dom/xslt/xslt/txMozillaXMLOutput.cpp
@@ -118,17 +118,17 @@ txMozillaXMLOutput::attribute(nsIAtom* a
         }
     }
 
     return attributeInternal(aPrefix, aLocalName, aNsID, aValue);
 }
 
 nsresult
 txMozillaXMLOutput::attribute(nsIAtom* aPrefix,
-                              const nsSubstring& aLocalName,
+                              const nsAString& aLocalName,
                               const int32_t aNsID,
                               const nsString& aValue)
 {
     nsCOMPtr<nsIAtom> lname;
 
     if (mOpenedElementIsHTML && aNsID == kNameSpaceID_None) {
         nsAutoString lnameStr;
         nsContentUtils::ASCIIToLower(aLocalName, lnameStr);
@@ -166,17 +166,17 @@ txMozillaXMLOutput::attributeInternal(ns
 
     NS_ASSERTION(!mBadChildLevel, "mBadChildLevel set when element is opened");
 
     return mOpenedElement->SetAttr(aNsID, aLocalName, aPrefix, aValue,
                                    false);
 }
 
 nsresult
-txMozillaXMLOutput::characters(const nsSubstring& aData, bool aDOE)
+txMozillaXMLOutput::characters(const nsAString& aData, bool aDOE)
 {
     nsresult rv = closePrevious(false);
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (!mBadChildLevel) {
         mText.Append(aData);
     }
 
@@ -449,17 +449,17 @@ txMozillaXMLOutput::startElement(nsIAtom
                                     kNameSpaceID_XHTML);
     }
 
     return startElementInternal(aPrefix, aLocalName, aNsID);
 }
 
 nsresult
 txMozillaXMLOutput::startElement(nsIAtom* aPrefix,
-                                 const nsSubstring& aLocalName,
+                                 const nsAString& aLocalName,
                                  const int32_t aNsID)
 {
     int32_t nsId = aNsID;
     nsCOMPtr<nsIAtom> lname;
 
     if (mOutputFormat.mMethod == eHTMLOutput && aNsID == kNameSpaceID_None) {
         nsId = kNameSpaceID_XHTML;
 
@@ -772,17 +772,17 @@ void txMozillaXMLOutput::processHTTPEqui
 {
     // For now we only handle "refresh". There's a longer list in
     // HTMLContentSink::ProcessHeaderData
     if (aHeader == nsGkAtoms::refresh)
         LossyCopyUTF16toASCII(aValue, mRefreshString);
 }
 
 nsresult
-txMozillaXMLOutput::createResultDocument(const nsSubstring& aName, int32_t aNsID,
+txMozillaXMLOutput::createResultDocument(const nsAString& aName, int32_t aNsID,
                                          nsIDOMDocument* aSourceDocument,
                                          bool aLoadedAsData)
 {
     nsresult rv;
 
     // Create the document
     if (mOutputFormat.mMethod == eHTMLOutput) {
         rv = NS_NewHTMLDocument(getter_AddRefs(mDocument),
--- a/dom/xslt/xslt/txMozillaXMLOutput.h
+++ b/dom/xslt/xslt/txMozillaXMLOutput.h
@@ -67,17 +67,17 @@ public:
                        bool aNoFixup);
     ~txMozillaXMLOutput();
 
     TX_DECL_TXAXMLEVENTHANDLER
     TX_DECL_TXAOUTPUTXMLEVENTHANDLER
 
     nsresult closePrevious(bool aFlushText);
 
-    nsresult createResultDocument(const nsSubstring& aName, int32_t aNsID,
+    nsresult createResultDocument(const nsAString& aName, int32_t aNsID,
                                   nsIDOMDocument* aSourceDocument,
                                   bool aLoadedAsData);
 
 private:
     nsresult createTxWrapper();
     nsresult startHTMLElement(nsIContent* aElement, bool aXHTML);
     nsresult endHTMLElement(nsIContent* aElement);
     void processHTTPEquiv(nsIAtom* aHeader, const nsString& aValue);
--- a/dom/xslt/xslt/txMozillaXSLTProcessor.cpp
+++ b/dom/xslt/xslt/txMozillaXSLTProcessor.cpp
@@ -127,17 +127,17 @@ txToDocHandlerFactory::createHandlerWith
 
     MOZ_CRASH("Unknown output method");
 
     return NS_ERROR_FAILURE;
 }
 
 nsresult
 txToDocHandlerFactory::createHandlerWith(txOutputFormat* aFormat,
-                                         const nsSubstring& aName,
+                                         const nsAString& aName,
                                          int32_t aNsID,
                                          txAXMLEventHandler** aHandler)
 {
     *aHandler = nullptr;
     switch (aFormat->mMethod) {
         case eMethodNotSet:
         {
             NS_ERROR("How can method not be known when root element is?");
@@ -219,17 +219,17 @@ txToFragmentHandlerFactory::createHandle
         }
     }
     NS_ENSURE_TRUE(*aHandler, NS_ERROR_OUT_OF_MEMORY);
     return NS_OK;
 }
 
 nsresult
 txToFragmentHandlerFactory::createHandlerWith(txOutputFormat* aFormat,
-                                              const nsSubstring& aName,
+                                              const nsAString& aName,
                                               int32_t aNsID,
                                               txAXMLEventHandler** aHandler)
 {
     *aHandler = nullptr;
     NS_ASSERTION(aFormat->mMethod != eMethodNotSet,
                  "How can method not be known when root element is?");
     NS_ENSURE_TRUE(aFormat->mMethod != eMethodNotSet, NS_ERROR_UNEXPECTED);
     return createHandlerWith(aFormat, aHandler);
--- a/dom/xslt/xslt/txPatternParser.cpp
+++ b/dom/xslt/xslt/txPatternParser.cpp
@@ -8,17 +8,17 @@
 #include "nsGkAtoms.h"
 #include "nsError.h"
 #include "txStringUtils.h"
 #include "txXSLTPatterns.h"
 #include "txStylesheetCompiler.h"
 #include "txPatternOptimizer.h"
 
 
-nsresult txPatternParser::createPattern(const nsAFlatString& aPattern,
+nsresult txPatternParser::createPattern(const nsString& aPattern,
                                         txIParseContext* aContext,
                                         txPattern** aResult)
 {
     txExprLexer lexer;
     nsresult rv = lexer.parse(aPattern);
     if (NS_FAILED(rv)) {
         // XXX error report parsing error
         return rv;
--- a/dom/xslt/xslt/txPatternParser.h
+++ b/dom/xslt/xslt/txPatternParser.h
@@ -9,17 +9,17 @@
 #include "txXSLTPatterns.h"
 #include "txExprParser.h"
 
 class txStylesheetCompilerState;
 
 class txPatternParser : public txExprParser
 {
 public:
-    static nsresult createPattern(const nsAFlatString& aPattern,
+    static nsresult createPattern(const nsString& aPattern,
                                   txIParseContext* aContext,
                                   txPattern** aResult);
 protected:
     static nsresult createUnionPattern(txExprLexer& aLexer,
                                        txIParseContext* aContext,
                                        txPattern*& aPattern);
     static nsresult createLocPathPattern(txExprLexer& aLexer,
                                          txIParseContext* aContext,
--- a/dom/xslt/xslt/txStylesheetCompileHandlers.cpp
+++ b/dom/xslt/xslt/txStylesheetCompileHandlers.cpp
@@ -1007,17 +1007,17 @@ txFnStartStripSpace(int32_t aNamespaceID
                                nsGkAtoms::elements, true, &attr);
     NS_ENSURE_SUCCESS(rv, rv);
 
     bool strip = aLocalName == nsGkAtoms::stripSpace;
 
     nsAutoPtr<txStripSpaceItem> stripItem(new txStripSpaceItem);
     nsWhitespaceTokenizer tokenizer(attr->mValue);
     while (tokenizer.hasMoreTokens()) {
-        const nsASingleFragmentString& name = tokenizer.nextToken();
+        const nsAString& name = tokenizer.nextToken();
         int32_t ns = kNameSpaceID_None;
         nsCOMPtr<nsIAtom> prefix, localName;
         rv = XMLUtils::splitQName(name, getter_AddRefs(prefix),
                                   getter_AddRefs(localName));
         if (NS_FAILED(rv)) {
             // check for "*" or "prefix:*"
             uint32_t length = name.Length();
             const char16_t* c;
--- a/dom/xslt/xslt/txTextHandler.cpp
+++ b/dom/xslt/xslt/txTextHandler.cpp
@@ -15,25 +15,25 @@ nsresult
 txTextHandler::attribute(nsIAtom* aPrefix, nsIAtom* aLocalName,
                          nsIAtom* aLowercaseLocalName, int32_t aNsID,
                          const nsString& aValue)
 {
     return NS_OK;
 }
 
 nsresult
-txTextHandler::attribute(nsIAtom* aPrefix, const nsSubstring& aLocalName,
+txTextHandler::attribute(nsIAtom* aPrefix, const nsAString& aLocalName,
                          const int32_t aNsID,
                          const nsString& aValue)
 {
     return NS_OK;
 }
 
 nsresult
-txTextHandler::characters(const nsSubstring& aData, bool aDOE)
+txTextHandler::characters(const nsAString& aData, bool aDOE)
 {
     if (mLevel == 0)
         mValue.Append(aData);
 
     return NS_OK;
 }
 
 nsresult
@@ -75,16 +75,16 @@ txTextHandler::startElement(nsIAtom* aPr
 {
     if (mOnlyText)
         ++mLevel;
 
     return NS_OK;
 }
 
 nsresult
-txTextHandler::startElement(nsIAtom* aPrefix, const nsSubstring& aLocalName,
+txTextHandler::startElement(nsIAtom* aPrefix, const nsAString& aLocalName,
                             const int32_t aNsID)
 {
     if (mOnlyText)
         ++mLevel;
 
     return NS_OK;
 }
--- a/dom/xslt/xslt/txUnknownHandler.cpp
+++ b/dom/xslt/xslt/txUnknownHandler.cpp
@@ -33,26 +33,26 @@ txUnknownHandler::attribute(nsIAtom* aPr
     return mFlushed ?
            mEs->mResultHandler->attribute(aPrefix, aLocalName,
                                           aLowercaseLocalName, aNsID, aValue) :
            txBufferingHandler::attribute(aPrefix, aLocalName,
                                          aLowercaseLocalName, aNsID, aValue);
 }
 
 nsresult
-txUnknownHandler::attribute(nsIAtom* aPrefix, const nsSubstring& aLocalName,
+txUnknownHandler::attribute(nsIAtom* aPrefix, const nsAString& aLocalName,
                             const int32_t aNsID, const nsString& aValue)
 {
     return mFlushed ?
            mEs->mResultHandler->attribute(aPrefix, aLocalName, aNsID, aValue) :
            txBufferingHandler::attribute(aPrefix, aLocalName, aNsID, aValue);
 }
 
 nsresult
-txUnknownHandler::characters(const nsSubstring& aData, bool aDOE)
+txUnknownHandler::characters(const nsAString& aData, bool aDOE)
 {
     return mFlushed ?
            mEs->mResultHandler->characters(aData, aDOE) :
            txBufferingHandler::characters(aData, aDOE);
 }
 
 nsresult
 txUnknownHandler::comment(const nsString& aData)
@@ -142,17 +142,17 @@ txUnknownHandler::startElement(nsIAtom* 
         NS_ENSURE_SUCCESS(rv, rv);
     }
 
     return mEs->mResultHandler->startElement(aPrefix, aLocalName,
                                              aLowercaseLocalName, aNsID);
 }
 
 nsresult
-txUnknownHandler::startElement(nsIAtom* aPrefix, const nsSubstring& aLocalName,
+txUnknownHandler::startElement(nsIAtom* aPrefix, const nsAString& aLocalName,
                                const int32_t aNsID)
 {
     if (!mFlushed) {
         // Make sure that mEs->mResultHandler == this is true, otherwise we'll
         // leak mEs->mResultHandler in createHandlerAndFlush.
         NS_ASSERTION(mEs->mResultHandler == this,
                      "We're leaking mEs->mResultHandler.");
 
@@ -162,17 +162,17 @@ txUnknownHandler::startElement(nsIAtom* 
         nsresult rv = createHandlerAndFlush(htmlRoot, aLocalName, aNsID);
         NS_ENSURE_SUCCESS(rv, rv);
     }
 
     return mEs->mResultHandler->startElement(aPrefix, aLocalName, aNsID);
 }
 
 nsresult txUnknownHandler::createHandlerAndFlush(bool aHTMLRoot,
-                                                 const nsSubstring& aName,
+                                                 const nsAString& aName,
                                                  const int32_t aNsID)
 {
     NS_ENSURE_TRUE(mBuffer, NS_ERROR_NOT_INITIALIZED);
 
     txOutputFormat format;
     format.merge(*(mEs->mStylesheet->getOutputFormat()));
     if (format.mMethod == eMethodNotSet) {
         format.mMethod = aHTMLRoot ? eHTMLOutput : eXMLOutput;
--- a/dom/xslt/xslt/txUnknownHandler.h
+++ b/dom/xslt/xslt/txUnknownHandler.h
@@ -16,17 +16,17 @@ class txUnknownHandler : public txBuffer
 public:
     explicit txUnknownHandler(txExecutionState* aEs);
     virtual ~txUnknownHandler();
 
     TX_DECL_TXAXMLEVENTHANDLER
 
 private:
     nsresult createHandlerAndFlush(bool aHTMLRoot,
-                                   const nsSubstring& aName,
+                                   const nsAString& aName,
                                    const int32_t aNsID);
 
     /*
      * XXX we shouldn't hold to the txExecutionState, as we're supposed
      * to live without it. But as a standalone handler, we don't.
      * The right fix may need a txOutputFormat here.
      */
     txExecutionState* mEs;
--- a/dom/xslt/xslt/txXMLEventHandler.h
+++ b/dom/xslt/xslt/txXMLEventHandler.h
@@ -42,27 +42,27 @@ public:
      * Signals to receive the start of an attribute.
      *
      * @param aPrefix the prefix of the attribute
      * @param aLocalName the localname of the attribute
      * @param aNsID the namespace ID of the attribute
      * @param aValue the value of the attribute
      */
     virtual nsresult attribute(nsIAtom* aPrefix,
-                               const nsSubstring& aLocalName,
+                               const nsAString& aLocalName,
                                const int32_t aNsID,
                                const nsString& aValue) = 0;
 
     /**
      * Signals to receive characters.
      *
      * @param aData the characters to receive
      * @param aDOE disable output escaping for these characters
      */
-    virtual nsresult characters(const nsSubstring& aData, bool aDOE) = 0;
+    virtual nsresult characters(const nsAString& aData, bool aDOE) = 0;
 
     /**
      * Signals to receive data that should be treated as a comment.
      *
      * @param data the comment data to receive
      */
     virtual nsresult comment(const nsString& aData) = 0;
 
@@ -108,41 +108,41 @@ public:
      * Signals to receive the start of an element. Can throw
      * NS_ERROR_XSLT_BAD_NODE_NAME if the name is invalid
      *
      * @param aPrefix the prefix of the element
      * @param aLocalName the localname of the element
      * @param aNsID the namespace ID of the element
      */
     virtual nsresult startElement(nsIAtom* aPrefix,
-                                  const nsSubstring& aLocalName,
+                                  const nsAString& aLocalName,
                                   const int32_t aNsID) = 0;
 };
 
 #define TX_DECL_TXAXMLEVENTHANDLER                                           \
     virtual nsresult attribute(nsIAtom* aPrefix, nsIAtom* aLocalName,        \
                                nsIAtom* aLowercaseLocalName, int32_t aNsID,  \
                                const nsString& aValue);                      \
     virtual nsresult attribute(nsIAtom* aPrefix,                             \
-                               const nsSubstring& aLocalName,                \
+                               const nsAString& aLocalName,                  \
                                const int32_t aNsID,                          \
                                const nsString& aValue);                      \
-    virtual nsresult characters(const nsSubstring& aData, bool aDOE);      \
+    virtual nsresult characters(const nsAString& aData, bool aDOE);          \
     virtual nsresult comment(const nsString& aData);                         \
     virtual nsresult endDocument(nsresult aResult = NS_OK);                  \
     virtual nsresult endElement();                                           \
     virtual nsresult processingInstruction(const nsString& aTarget,          \
                                            const nsString& aData);           \
     virtual nsresult startDocument();                                        \
     virtual nsresult startElement(nsIAtom* aPrefix,                          \
                                   nsIAtom* aLocalName,                       \
                                   nsIAtom* aLowercaseLocalName,              \
                                   int32_t aNsID);                            \
     virtual nsresult startElement(nsIAtom* aPrefix,                          \
-                                  const nsSubstring& aName,                  \
+                                  const nsAString& aName,                    \
                                   const int32_t aNsID);
 
 
 class txAOutputXMLEventHandler : public txAXMLEventHandler
 {
 public:
     /**
      * Gets the Mozilla output document
@@ -177,22 +177,22 @@ public:
      * name and namespace for the root element.
      * @param aFromat  format to get handler for
      * @param aName    name of the root element
      * @param aNsID    namespace-id of the root element
      * @param aHandler outparam. The created handler
      */
     virtual nsresult
     createHandlerWith(txOutputFormat* aFormat,
-                      const nsSubstring& aName,
+                      const nsAString& aName,
                       int32_t aNsID,
                       txAXMLEventHandler** aHandler) = 0;
 };
 
 #define TX_DECL_TXAOUTPUTHANDLERFACTORY                        \
     nsresult createHandlerWith(txOutputFormat* aFormat,        \
                                txAXMLEventHandler** aHandler); \
     nsresult createHandlerWith(txOutputFormat* aFormat,        \
-                               const nsSubstring& aName,       \
+                               const nsAString& aName,         \
                                int32_t aNsID,                  \
                                txAXMLEventHandler** aHandler);
 
 #endif
--- a/dom/xslt/xslt/txXPathResultComparator.cpp
+++ b/dom/xslt/xslt/txXPathResultComparator.cpp
@@ -12,29 +12,29 @@
 #include "nsIServiceManager.h"
 #include "prmem.h"
 
 #define kAscending (1<<0)
 #define kUpperFirst (1<<1)
 
 txResultStringComparator::txResultStringComparator(bool aAscending,
                                                    bool aUpperFirst,
-                                                   const nsAFlatString& aLanguage)
+                                                   const nsString& aLanguage)
 {
     mSorting = 0;
     if (aAscending)
         mSorting |= kAscending;
     if (aUpperFirst)
         mSorting |= kUpperFirst;
     nsresult rv = init(aLanguage);
     if (NS_FAILED(rv))
         NS_ERROR("Failed to initialize txResultStringComparator");
 }
 
-nsresult txResultStringComparator::init(const nsAFlatString& aLanguage)
+nsresult txResultStringComparator::init(const nsString& aLanguage)
 {
     nsresult rv;
 
     nsCOMPtr<nsICollationFactory> colFactory =
                     do_CreateInstance(NS_COLLATIONFACTORY_CONTRACTID, &rv);
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (aLanguage.IsEmpty()) {
--- a/dom/xslt/xslt/txXPathResultComparator.h
+++ b/dom/xslt/xslt/txXPathResultComparator.h
@@ -40,24 +40,24 @@ public:
 
 /*
  * Compare results as stings (data-type="text")
  */
 class txResultStringComparator : public txXPathResultComparator
 {
 public:
     txResultStringComparator(bool aAscending, bool aUpperFirst,
-                             const nsAFlatString& aLanguage);
+                             const nsString& aLanguage);
 
     int compareValues(txObject* aVal1, txObject* aVal2) override;
     nsresult createSortableValue(Expr *aExpr, txIEvalContext *aContext,
                                  txObject *&aResult) override;
 private:
     nsCOMPtr<nsICollation> mCollation;
-    nsresult init(const nsAFlatString& aLanguage);
+    nsresult init(const nsString& aLanguage);
     nsresult createRawSortKey(const int32_t aStrength,
                               const nsString& aString,
                               uint8_t** aKey,
                               uint32_t* aLength);
     int mSorting;
 
     class StringValue : public txObject
     {
--- a/dom/xslt/xslt/txXSLTNumber.h
+++ b/dom/xslt/xslt/txXSLTNumber.h
@@ -59,16 +59,16 @@ private:
 class txFormattedCounter {
 public:
     virtual ~txFormattedCounter()
     {
     }
     
     virtual void appendNumber(int32_t aNumber, nsAString& aDest) = 0;
 
-    static nsresult getCounterFor(const nsAFlatString& aToken, int aGroupSize,
+    static nsresult getCounterFor(const nsString& aToken, int aGroupSize,
                                   const nsAString& aGroupSeparator,
                                   txFormattedCounter*& aCounter);
     
     nsString mSeparator;
 };
 
 #endif //TRANSFRMX_TXXSLTNUMBER_H
--- a/dom/xslt/xslt/txXSLTNumberCounters.cpp
+++ b/dom/xslt/xslt/txXSLTNumberCounters.cpp
@@ -45,17 +45,17 @@ public:
     void appendNumber(int32_t aNumber, nsAString& aDest);
 
 private:
     int32_t mTableOffset;
 };
 
 
 nsresult
-txFormattedCounter::getCounterFor(const nsAFlatString& aToken,
+txFormattedCounter::getCounterFor(const nsString& aToken,
                                   int32_t aGroupSize,
                                   const nsAString& aGroupSeparator,
                                   txFormattedCounter*& aCounter)
 {
     int32_t length = aToken.Length();
     NS_ASSERTION(length, "getting counter for empty token");
     aCounter = 0;
     
--- a/dom/xslt/xslt/txXSLTPatterns.cpp
+++ b/dom/xslt/xslt/txXSLTPatterns.cpp
@@ -295,17 +295,17 @@ txRootPattern::toString(nsAString& aDest
 /*
  * txIdPattern
  *
  * txIdPattern matches if the given node has a ID attribute with one
  * of the space delimited values.
  * This looks like the id() function, but may only have LITERALs as
  * argument.
  */
-txIdPattern::txIdPattern(const nsSubstring& aString)
+txIdPattern::txIdPattern(const nsAString& aString)
 {
     nsWhitespaceTokenizer tokenizer(aString);
     while (tokenizer.hasMoreTokens()) {
         // this can fail, XXX move to a Init(aString) method
         nsCOMPtr<nsIAtom> atom = NS_Atomize(tokenizer.nextToken());
         mIds.AppendObject(atom);
     }
 }
--- a/dom/xslt/xslt/txXSLTPatterns.h
+++ b/dom/xslt/xslt/txXSLTPatterns.h
@@ -183,17 +183,17 @@ private:
     // Don't serialize txRootPattern if it's used in a txLocPathPattern
     bool mSerialize;
 #endif
 };
 
 class txIdPattern : public txPattern
 {
 public:
-    explicit txIdPattern(const nsSubstring& aString);
+    explicit txIdPattern(const nsAString& aString);
 
     TX_DECL_PATTERN;
 
 private:
     nsCOMArray<nsIAtom> mIds;
 };
 
 class txKeyPattern : public txPattern
--- a/editor/composer/nsComposerCommands.cpp
+++ b/editor/composer/nsComposerCommands.cpp
@@ -20,17 +20,17 @@
 #include "nsID.h"
 #include "nsIDOMElement.h"              // for nsIDOMElement
 #include "nsIEditor.h"                  // for nsIEditor
 #include "nsIHTMLAbsPosEditor.h"        // for nsIHTMLAbsPosEditor
 #include "nsIHTMLEditor.h"              // for nsIHTMLEditor, etc
 #include "nsLiteralString.h"            // for NS_LITERAL_STRING
 #include "nsReadableUtils.h"            // for EmptyString
 #include "nsString.h"                   // for nsAutoString, nsString, etc
-#include "nsStringFwd.h"                // for nsAFlatString
+#include "nsStringFwd.h"                // for nsString
 
 class nsISupports;
 
 //prototype
 nsresult GetListState(nsIHTMLEditor* aEditor, bool* aMixed,
                       nsAString& aLocalName);
 nsresult RemoveOneProperty(nsIHTMLEditor* aEditor, const nsAString& aProp);
 nsresult RemoveTextProperty(nsIHTMLEditor* aEditor, const nsAString& aProp);
--- a/editor/composer/nsEditingSession.cpp
+++ b/editor/composer/nsEditingSession.cpp
@@ -43,17 +43,17 @@
 #include "nsIWeakReference.h"           // for nsISupportsWeakReference, etc
 #include "nsIWebNavigation.h"           // for nsIWebNavigation
 #include "nsIWebProgress.h"             // for nsIWebProgress, etc
 #include "nsLiteralString.h"            // for NS_LITERAL_STRING
 #include "nsPICommandUpdater.h"         // for nsPICommandUpdater
 #include "nsPIDOMWindow.h"              // for nsPIDOMWindow
 #include "nsPresContext.h"              // for nsPresContext
 #include "nsReadableUtils.h"            // for AppendUTF16toUTF8
-#include "nsStringFwd.h"                // for nsAFlatString
+#include "nsStringFwd.h"                // for nsString
 #include "mozilla/dom/Selection.h"      // for AutoHideSelectionChanges
 #include "nsFrameSelection.h"           // for nsFrameSelection
 
 class nsISupports;
 class nsIURI;
 
 /*---------------------------------------------------------------------------
 
--- a/editor/libeditor/EditorBase.cpp
+++ b/editor/libeditor/EditorBase.cpp
@@ -90,17 +90,17 @@
 #include "nsITransactionManager.h"
 #include "nsIWeakReference.h"           // for nsISupportsWeakReference
 #include "nsIWidget.h"                  // for nsIWidget, IMEState, etc.
 #include "nsPIDOMWindow.h"              // for nsPIDOMWindow
 #include "nsPresContext.h"              // for nsPresContext
 #include "nsRange.h"                    // for nsRange
 #include "nsReadableUtils.h"            // for EmptyString, ToNewCString
 #include "nsString.h"                   // for nsAutoString, nsString, etc.
-#include "nsStringFwd.h"                // for nsAFlatString
+#include "nsStringFwd.h"                // for nsString
 #include "nsStyleConsts.h"              // for NS_STYLE_DIRECTION_RTL, etc.
 #include "nsStyleContext.h"             // for nsStyleContext
 #include "nsStyleStruct.h"              // for nsStyleDisplay, nsStyleText, etc.
 #include "nsStyleStructFwd.h"           // for nsIFrame::StyleUIReset, etc.
 #include "nsTextNode.h"                 // for nsTextNode
 #include "nsThreadUtils.h"              // for nsRunnable
 #include "nsTransactionManager.h"       // for nsTransactionManager
 #include "prtime.h"                     // for PR_Now
--- a/editor/libeditor/HTMLEditorDataTransfer.cpp
+++ b/editor/libeditor/HTMLEditorDataTransfer.cpp
@@ -155,17 +155,17 @@ HTMLEditor::LoadHTML(const nsAString& aI
   }
 
   return rules->DidDoAction(selection, &ruleInfo, rv);
 }
 
 NS_IMETHODIMP
 HTMLEditor::InsertHTML(const nsAString& aInString)
 {
-  const nsAFlatString& empty = EmptyString();
+  const nsString& empty = EmptyString();
 
   return InsertHTMLWithContext(aInString, empty, empty, empty,
                                nullptr,  nullptr, 0, true);
 }
 
 nsresult
 HTMLEditor::InsertHTMLWithContext(const nsAString& aInputString,
                                   const nsAString& aContextStr,
@@ -946,18 +946,18 @@ HTMLEditor::ParseCFHTML(nsCString& aCfht
 
   // remove the StartFragment/EndFragment comments from the fragment, if present
   RemoveFragComments(fragmentUTF8);
 
   // remove the StartFragment/EndFragment comments from the context, if present
   RemoveFragComments(contextUTF8);
 
   // convert both strings to usc2
-  const nsAFlatString& fragUcs2Str = NS_ConvertUTF8toUTF16(fragmentUTF8);
-  const nsAFlatString& cntxtUcs2Str = NS_ConvertUTF8toUTF16(contextUTF8);
+  const nsString& fragUcs2Str = NS_ConvertUTF8toUTF16(fragmentUTF8);
+  const nsString& cntxtUcs2Str = NS_ConvertUTF8toUTF16(contextUTF8);
 
   // translate platform linebreaks for fragment
   int32_t oldLengthInChars = fragUcs2Str.Length() + 1;  // +1 to include null terminator
   int32_t newLengthInChars = 0;
   *aStuffToPaste = nsLinebreakConverter::ConvertUnicharLineBreaks(fragUcs2Str.get(),
                                                            nsLinebreakConverter::eLinebreakAny,
                                                            nsLinebreakConverter::eLinebreakContent,
                                                            oldLengthInChars, &newLengthInChars);
@@ -1506,17 +1506,17 @@ HTMLEditor::PasteNoFormatting(int32_t aS
   // Get the nsITransferable interface for getting the data from the clipboard.
   // use TextEditor::PrepareTransferable() to force unicode plaintext data.
   nsCOMPtr<nsITransferable> trans;
   rv = TextEditor::PrepareTransferable(getter_AddRefs(trans));
   if (NS_SUCCEEDED(rv) && trans) {
     // Get the Data from the clipboard
     if (NS_SUCCEEDED(clipboard->GetData(trans, aSelectionType)) &&
         IsModifiable()) {
-      const nsAFlatString& empty = EmptyString();
+      const nsString& empty = EmptyString();
       rv = InsertFromTransferable(trans, nullptr, empty, empty, false, nullptr, 0,
                                   true);
     }
   }
 
   return rv;
 }
 
--- a/editor/libeditor/TextEditorTest.cpp
+++ b/editor/libeditor/TextEditorTest.cpp
@@ -164,17 +164,17 @@ nsresult TextEditorTest::TestTextPropert
 
   nsCOMPtr<nsIHTMLEditor> htmlEditor (do_QueryInterface(mTextEditor));
   NS_ENSURE_TRUE(htmlEditor, NS_ERROR_FAILURE);
 
   bool any = false;
   bool all = false;
   bool first=false;
 
-  const nsAFlatString& empty = EmptyString();
+  const nsString& empty = EmptyString();
 
   rv = htmlEditor->GetInlineProperty(nsGkAtoms::b, empty, empty, &first,
                                      &any, &all);
   TEST_RESULT(rv);
   NS_ASSERTION(false==first, "first should be false");
   NS_ASSERTION(false==any, "any should be false");
   NS_ASSERTION(false==all, "all should be false");
   rv = htmlEditor->SetInlineProperty(nsGkAtoms::b, empty, empty);
--- a/extensions/cookie/nsPermissionManager.cpp
+++ b/extensions/cookie/nsPermissionManager.cpp
@@ -319,34 +319,34 @@ public:
     return permManager->RemovePermissionsWithAttributes(nsDependentString(aData));
   }
 };
 
 NS_IMPL_ISUPPORTS(ClearOriginDataObserver, nsIObserver)
 
 class MOZ_STACK_CLASS UpgradeHostToOriginHelper {
 public:
-  virtual nsresult Insert(const nsACString& aOrigin, const nsAFlatCString& aType,
+  virtual nsresult Insert(const nsACString& aOrigin, const nsCString& aType,
                           uint32_t aPermission, uint32_t aExpireType, int64_t aExpireTime,
                           int64_t aModificationTime) = 0;
 };
 
 class MOZ_STACK_CLASS UpgradeHostToOriginDBMigration final : public UpgradeHostToOriginHelper {
 public:
   UpgradeHostToOriginDBMigration(mozIStorageConnection* aDBConn, int64_t* aID) : mDBConn(aDBConn)
                                                                                , mID(aID)
   {
     mDBConn->CreateStatement(NS_LITERAL_CSTRING(
       "INSERT INTO moz_hosts_new "
       "(id, origin, type, permission, expireType, expireTime, modificationTime) "
       "VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)"), getter_AddRefs(mStmt));
   }
 
   nsresult
-  Insert(const nsACString& aOrigin, const nsAFlatCString& aType,
+  Insert(const nsACString& aOrigin, const nsCString& aType,
          uint32_t aPermission, uint32_t aExpireType, int64_t aExpireTime,
          int64_t aModificationTime) final
   {
     nsresult rv = mStmt->BindInt64ByIndex(0, *mID);
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = mStmt->BindUTF8StringByIndex(1, aOrigin);
     NS_ENSURE_SUCCESS(rv, rv);
@@ -386,17 +386,17 @@ public:
   UpgradeHostToOriginHostfileImport(nsPermissionManager* aPm,
                                     nsPermissionManager::DBOperationType aOperation,
                                     int64_t aID) : mPm(aPm)
                                                  , mOperation(aOperation)
                                                  , mID(aID)
   {}
 
   nsresult
-  Insert(const nsACString& aOrigin, const nsAFlatCString& aType,
+  Insert(const nsACString& aOrigin, const nsCString& aType,
          uint32_t aPermission, uint32_t aExpireType, int64_t aExpireTime,
          int64_t aModificationTime) final
   {
     nsCOMPtr<nsIPrincipal> principal;
     nsresult rv = GetPrincipalFromOrigin(aOrigin, getter_AddRefs(principal));
     NS_ENSURE_SUCCESS(rv, rv);
 
     return mPm->AddInternal(principal, aType, aPermission, mID,
@@ -421,17 +421,17 @@ public:
       "VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)"), getter_AddRefs(mStmt));
 
     mDBConn->CreateStatement(NS_LITERAL_CSTRING(
       "SELECT id FROM moz_perms WHERE origin = ?1 AND type = ?2"),
       getter_AddRefs(mLookupStmt));
   }
 
   nsresult
-  Insert(const nsACString& aOrigin, const nsAFlatCString& aType,
+  Insert(const nsACString& aOrigin, const nsCString& aType,
          uint32_t aPermission, uint32_t aExpireType, int64_t aExpireTime,
          int64_t aModificationTime) final
   {
     // Every time the migration code wants to insert an origin into
     // the database we need to check to see if someone has already
     // created a permissions entry for that permission. If they have,
     // we don't want to insert a duplicate row.
     //
@@ -493,17 +493,17 @@ private:
   nsCOMPtr<mozIStorageStatement> mStmt;
   nsCOMPtr<mozIStorageStatement> mLookupStmt;
   nsCOMPtr<mozIStorageConnection> mDBConn;
   int64_t* mID;
 };
 
 
 nsresult
-UpgradeHostToOriginAndInsert(const nsACString& aHost, const nsAFlatCString& aType,
+UpgradeHostToOriginAndInsert(const nsACString& aHost, const nsCString& aType,
                              uint32_t aPermission, uint32_t aExpireType, int64_t aExpireTime,
                              int64_t aModificationTime, uint32_t aAppId, bool aIsInIsolatedMozBrowserElement,
                              UpgradeHostToOriginHelper* aHelper)
 {
   if (aHost.EqualsLiteral("<file>")) {
     // We no longer support the magic host <file>
     NS_WARNING("The magic host <file> is no longer supported. "
                "It is being removed from the permissions database.");
@@ -1675,17 +1675,17 @@ nsPermissionManager::AddFromPrincipal(ns
   int64_t modificationTime = 0;
 
   return AddInternal(aPrincipal, nsDependentCString(aType), aPermission, 0,
                      aExpireType, aExpireTime, modificationTime, eNotify, eWriteToDB);
 }
 
 nsresult
 nsPermissionManager::AddInternal(nsIPrincipal* aPrincipal,
-                                 const nsAFlatCString &aType,
+                                 const nsCString& aType,
                                  uint32_t              aPermission,
                                  int64_t               aID,
                                  uint32_t              aExpireType,
                                  int64_t               aExpireTime,
                                  int64_t               aModificationTime,
                                  NotifyOperationType   aNotifyOperation,
                                  DBOperationType       aDBOperation,
                                  const bool            aIgnoreSessionPermissions)
@@ -3120,43 +3120,36 @@ nsPermissionManager::GetPermissionsWithK
   aPerms.Clear();
   if (NS_WARN_IF(XRE_IsContentProcess())) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   for (auto iter = mPermissionTable.Iter(); !iter.Done(); iter.Next()) {
     PermissionHashKey* entry = iter.Get();
 
-    // XXX: Is it worthwhile to have a shortcut Origin->Key implementation? as
-    // we could implement this without creating a codebase principal.
-
-    // Fetch the principal for the given origin.
-    nsCOMPtr<nsIPrincipal> principal;
-    nsresult rv = GetPrincipalFromOrigin(entry->GetKey()->mOrigin,
-                                         getter_AddRefs(principal));
-    if (NS_WARN_IF(NS_FAILED(rv))) {
+    nsAutoCString permissionKey;
+    GetKeyForOrigin(entry->GetKey()->mOrigin, permissionKey);
+
+    // If the keys don't match, and we aren't getting the default "" key, then
+    // we can exit early. We have to keep looking if we're getting the default
+    // key, as we may see a preload permission which should be transmitted.
+    if (aPermissionKey != permissionKey && !aPermissionKey.IsEmpty()) {
       continue;
     }
 
     for (const auto& permEntry : entry->GetPermissions()) {
       // Given how "default" permissions work and the possibility of them being
       // overridden with UNKNOWN_ACTION, we might see this value here - but we
       // do not want to send it to the content process.
       if (permEntry.mPermission == nsIPermissionManager::UNKNOWN_ACTION) {
         continue;
       }
 
-      // XXX: This performs extra work, such as in many cases re-computing the
-      // Origin (which we just computed the nsIPrincipal from). We may want to
-      // implement a custom version of this logic which avoids that extra work.
-      // See bug 1354700.
-      nsAutoCString permissionKey;
-      GetKeyForPermission(principal, mTypeArray[permEntry.mType].get(), permissionKey);
-
-      if (permissionKey == aPermissionKey) {
+      bool isPreload = IsPreloadPermission(mTypeArray[permEntry.mType].get());
+      if ((isPreload && aPermissionKey.IsEmpty()) || (!isPreload && aPermissionKey == permissionKey)) {
         aPerms.AppendElement(IPC::Permission(entry->GetKey()->mOrigin,
                                              mTypeArray.ElementAt(permEntry.mType),
                                              permEntry.mPermission,
                                              permEntry.mExpireType,
                                              permEntry.mExpireTime));
       }
     }
   }
@@ -3209,53 +3202,73 @@ nsPermissionManager::SetPermissionsWithK
     AddInternal(principal, perm.type, perm.capability, 0, perm.expireType,
                 perm.expireTime, modificationTime, eNotify, eNoDBOperation,
                 true /* ignoreSessionPermissions */);
   }
   return NS_OK;
 }
 
 /* static */ void
-nsPermissionManager::GetKeyForPrincipal(nsIPrincipal* aPrincipal, nsACString& aKey)
+nsPermissionManager::GetKeyForOrigin(const nsACString& aOrigin, nsACString& aKey)
 {
-  MOZ_ASSERT(aPrincipal);
   aKey.Truncate();
 
-  nsCOMPtr<nsIURI> uri;
-  nsresult rv = aPrincipal->GetURI(getter_AddRefs(uri));
-  if (NS_WARN_IF(NS_FAILED(rv) || !uri)) {
-    // NOTE: We don't propagate the error here, instead we produce the default
-    // "" permission key. This means that we can assign every principal a key,
-    // even if the GetURI operation on that principal is not meaningful.
+  // We only key origins for http, https, and ftp URIs. All origins begin with
+  // the URL which they apply to, which means that they should begin with their
+  // scheme in the case where they are one of these interesting URIs. We don't
+  // want to actually parse the URL here however, because this can be called on
+  // hot paths.
+  if (!StringBeginsWith(aOrigin, NS_LITERAL_CSTRING("http:")) &&
+      !StringBeginsWith(aOrigin, NS_LITERAL_CSTRING("https:")) &&
+      !StringBeginsWith(aOrigin, NS_LITERAL_CSTRING("ftp:"))) {
+    return;
+  }
+
+  // We need to look at the originAttributes if they are present, to make sure
+  // to remove any which we don't want. We put the rest of the origin, not
+  // including the attributes, into the key.
+  OriginAttributes attrs;
+  if (!attrs.PopulateFromOrigin(aOrigin, aKey)) {
     aKey.Truncate();
     return;
   }
-
-  nsAutoCString scheme;
-  rv = uri->GetScheme(scheme);
+  attrs.StripAttributes(OriginAttributes::STRIP_USER_CONTEXT_ID |
+                        OriginAttributes::STRIP_FIRST_PARTY_DOMAIN);
+
+#ifdef DEBUG
+  // Parse the origin string into a principal, and extract some useful
+  // information from it for assertions.
+  nsCOMPtr<nsIPrincipal> dbgPrincipal;
+  MOZ_ALWAYS_SUCCEEDS(GetPrincipalFromOrigin(aOrigin, getter_AddRefs(dbgPrincipal)));
+  nsCOMPtr<nsIURI> dbgUri;
+  MOZ_ALWAYS_SUCCEEDS(dbgPrincipal->GetURI(getter_AddRefs(dbgUri)));
+  nsAutoCString dbgScheme;
+  MOZ_ALWAYS_SUCCEEDS(dbgUri->GetScheme(dbgScheme));
+  MOZ_ASSERT(dbgScheme.EqualsLiteral("http") ||
+             dbgScheme.EqualsLiteral("https") ||
+             dbgScheme.EqualsLiteral("ftp"));
+  MOZ_ASSERT(dbgPrincipal->OriginAttributesRef() == attrs);
+#endif
+
+  // Append the stripped suffix to the output origin key.
+  nsAutoCString suffix;
+  attrs.CreateSuffix(suffix);
+  aKey.Append(suffix);
+}
+
+/* static */ void
+nsPermissionManager::GetKeyForPrincipal(nsIPrincipal* aPrincipal, nsACString& aKey)
+{
+  nsAutoCString origin;
+  nsresult rv = aPrincipal->GetOrigin(origin);
   if (NS_WARN_IF(NS_FAILED(rv))) {
-    // NOTE: Produce the default "" key as a fallback.
     aKey.Truncate();
     return;
   }
-
-  // URIs which have schemes other than http, https and ftp share the ""
-  // permission key.
-  if (scheme.EqualsLiteral("http") ||
-      scheme.EqualsLiteral("https") ||
-      scheme.EqualsLiteral("ftp")) {
-    rv = GetOriginFromPrincipal(aPrincipal, aKey);
-    if (NS_SUCCEEDED(rv)) {
-      return;
-    }
-  }
-
-  // NOTE: Produce the default "" key as a fallback.
-  aKey.Truncate();
-  return;
+  GetKeyForOrigin(origin, aKey);
 }
 
 /* static */ void
 nsPermissionManager::GetKeyForPermission(nsIPrincipal* aPrincipal, const char* aType, nsACString& aKey)
 {
   // Preload permissions have the "" key.
   if (IsPreloadPermission(aType)) {
     aKey.Truncate();
--- a/extensions/cookie/nsPermissionManager.h
+++ b/extensions/cookie/nsPermissionManager.h
@@ -189,17 +189,17 @@ public:
   };
 
   // A special value for a permission ID that indicates the ID was loaded as
   // a default value.  These will never be written to the database, but may
   // be overridden with an explicit permission (including UNKNOWN_ACTION)
   static const int64_t cIDPermissionIsDefault = -1;
 
   nsresult AddInternal(nsIPrincipal* aPrincipal,
-                       const nsAFlatCString &aType,
+                       const nsCString& aType,
                        uint32_t aPermission,
                        int64_t aID,
                        uint32_t aExpireType,
                        int64_t  aExpireTime,
                        int64_t aModificationTime,
                        NotifyOperationType aNotifyOperation,
                        DBOperationType aDBOperation,
                        const bool aIgnoreSessionPermissions = false);
@@ -228,16 +228,32 @@ public:
    * @param aPermissionKey  A string which will be filled with the permission key.
    */
   static void GetKeyForPrincipal(nsIPrincipal* aPrincipal, nsACString& aPermissionKey);
 
   /**
    * See `nsIPermissionManager::GetPermissionsWithKey` for more info on
    * permission keys.
    *
+   * Get the permission key corresponding to the given Origin. This method is
+   * like GetKeyForPrincipal, except that it avoids creating a nsIPrincipal
+   * object when you already have access to an origin string.
+   *
+   * If this method is passed a nonsensical origin string it may produce a
+   * nonsensical permission key result.
+   *
+   * @param aOrigin  The origin which the key is to be extracted from.
+   * @param aPermissionKey  A string which will be filled with the permission key.
+   */
+  static void GetKeyForOrigin(const nsACString& aOrigin, nsACString& aPermissionKey);
+
+  /**
+   * See `nsIPermissionManager::GetPermissionsWithKey` for more info on
+   * permission keys.
+   *
    * Get the permission key corresponding to the given Principal and type. This
    * method is intentionally infallible, as we want to provide an permission key
    * to every principal. Principals which don't have meaningful URIs with
    * http://, https://, or ftp:// schemes are given the default "" Permission
    * Key.
    *
    * This method is different from GetKeyForPrincipal in that it also takes
    * permissions which must be sent down before loading a document into account.
--- a/extensions/permissions/nsContentBlocker.cpp
+++ b/extensions/permissions/nsContentBlocker.cpp
@@ -341,31 +341,31 @@ nsContentBlocker::TestPermission(nsIURI 
     // If there are no two dots found, ++dot will turn to zero,
     // that will return the entire string.
     int32_t dot = currentHost.RFindChar('.');
     dot = currentHost.RFindChar('.', dot-1);
     ++dot;
 
     // Get the domain, ie the last part of the host (www.domain.com -> domain.com)
     // This will break on co.uk
-    const nsCSubstring &tail =
+    const nsACString& tail =
       Substring(currentHost, dot, currentHost.Length() - dot);
 
     nsAutoCString firstHost;
     rv = aFirstURI->GetAsciiHost(firstHost);
     NS_ENSURE_SUCCESS(rv, rv);
 
     // If the tail is longer then the whole firstHost, it will never match
     if (firstHost.Length() < tail.Length()) {
       *aPermission = false;
       return NS_OK;
     }
     
     // Get the last part of the firstUri with the same length as |tail|
-    const nsCSubstring &firstTail = 
+    const nsACString& firstTail =
       Substring(firstHost, firstHost.Length() - tail.Length(), tail.Length());
 
     // Check that both tails are the same, and that just before the tail in
     // |firstUri| there is a dot. That means both url are in the same domain
     if ((firstHost.Length() > tail.Length() && 
          firstHost.CharAt(firstHost.Length() - tail.Length() - 1) != '.') || 
         !tail.Equals(firstTail)) {
       *aPermission = false;
--- a/extensions/spellcheck/src/mozInlineSpellWordUtil.cpp
+++ b/extensions/spellcheck/src/mozInlineSpellWordUtil.cpp
@@ -264,17 +264,17 @@ mozInlineSpellWordUtil::GetRangeForWord(
   int32_t wordIndex = FindRealWordContaining(offset, HINT_BEGIN, false);
   if (wordIndex < 0)
     return MakeRange(pt, pt, aRange);
   return MakeRangeForWord(mRealWords[wordIndex], aRange);
 }
 
 // This is to fix characters that the spellchecker may not like
 static void
-NormalizeWord(const nsSubstring& aInput, int32_t aPos, int32_t aLen, nsAString& aOutput)
+NormalizeWord(const nsAString& aInput, int32_t aPos, int32_t aLen, nsAString& aOutput)
 {
   aOutput.Truncate();
   for (int32_t i = 0; i < aLen; i++) {
     char16_t ch = aInput.CharAt(i + aPos);
 
     // remove ignorable characters from the word
     if (IsIgnorableCharacter(ch))
       continue;
@@ -731,17 +731,17 @@ CheckLeavingBreakElement(nsINode* aNode,
   CheckLeavingBreakElementClosure* cl =
     static_cast<CheckLeavingBreakElementClosure*>(aClosure);
   if (!cl->mLeftBreakElement && IsBreakElement(aNode)) {
     cl->mLeftBreakElement = true;
   }
 }
 
 void
-mozInlineSpellWordUtil::NormalizeWord(nsSubstring& aWord)
+mozInlineSpellWordUtil::NormalizeWord(nsAString& aWord)
 {
   nsAutoString result;
   ::NormalizeWord(aWord, 0, aWord.Length(), result);
   aWord = result;
 }
 
 void
 mozInlineSpellWordUtil::BuildSoftText()
--- a/extensions/spellcheck/src/mozInlineSpellWordUtil.h
+++ b/extensions/spellcheck/src/mozInlineSpellWordUtil.h
@@ -85,17 +85,17 @@ public:
   // An empty word and a nullptr range are returned when we are done checking.
   // aSkipChecking will be set if the word is "special" and shouldn't be
   // checked (e.g., an email address).
   nsresult GetNextWord(nsAString& aText, nsRange** aRange,
                        bool* aSkipChecking);
 
   // Call to normalize some punctuation. This function takes an autostring
   // so we can access characters directly.
-  static void NormalizeWord(nsSubstring& aWord);
+  static void NormalizeWord(nsAString& aWord);
 
   nsIDOMDocument* GetDOMDocument() const { return mDOMDocument; }
   nsIDocument* GetDocument() const { return mDocument; }
   nsINode* GetRootNode() { return mRootNode; }
   
 private:
 
   // cached stuff for the editor, set by Init
new file mode 100644
--- /dev/null
+++ b/gfx/2d/ConvolutionFilter.cpp
@@ -0,0 +1,175 @@
+/* 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 "2D.h"
+#include "ConvolutionFilter.h"
+#include "skia/src/core/SkBitmapFilter.h"
+#include "skia/src/core/SkConvolver.h"
+#include "skia/src/core/SkOpts.h"
+#include <algorithm>
+#include <cmath>
+#include "mozilla/Vector.h"
+
+namespace mozilla {
+namespace gfx {
+
+ConvolutionFilter::ConvolutionFilter()
+  : mFilter(MakeUnique<SkConvolutionFilter1D>())
+{
+}
+
+ConvolutionFilter::~ConvolutionFilter()
+{
+}
+
+int32_t
+ConvolutionFilter::MaxFilter() const
+{
+  return mFilter->maxFilter();
+}
+
+int32_t
+ConvolutionFilter::NumValues() const
+{
+  return mFilter->numValues();
+}
+
+bool
+ConvolutionFilter::GetFilterOffsetAndLength(int32_t aRowIndex, int32_t* aResultOffset, int32_t* aResultLength)
+{
+  if (aRowIndex >= mFilter->numValues()) {
+    return false;
+  }
+  mFilter->FilterForValue(aRowIndex, aResultOffset, aResultLength);
+  return true;
+}
+
+void
+ConvolutionFilter::ConvolveHorizontally(const uint8_t* aSrc, uint8_t* aDst, bool aHasAlpha)
+{
+  SkOpts::convolve_horizontally(aSrc, *mFilter, aDst, aHasAlpha);
+}
+
+void
+ConvolutionFilter::ConvolveVertically(uint8_t* const* aSrc, uint8_t* aDst, int32_t aRowIndex, int32_t aRowSize, bool aHasAlpha)
+{
+  MOZ_ASSERT(aRowIndex < mFilter->numValues());
+
+  int32_t filterOffset;
+  int32_t filterLength;
+  auto filterValues = mFilter->FilterForValue(aRowIndex, &filterOffset, &filterLength);
+  SkOpts::convolve_vertically(filterValues, filterLength, aSrc, aRowSize, aDst, aHasAlpha);
+}
+
+/* ConvolutionFilter::ComputeResizeFactor is derived from Skia's SkBitmapScaler/SkResizeFilter::computeFactors.
+ * It is governed by Skia's BSD-style license (see gfx/skia/LICENSE) and the following copyright:
+ * Copyright (c) 2015 Google Inc.
+ */
+bool
+ConvolutionFilter::ComputeResizeFilter(ResizeMethod aResizeMethod, int32_t aSrcSize, int32_t aDstSize)
+{
+  typedef SkConvolutionFilter1D::ConvolutionFixed Fixed;
+
+  UniquePtr<SkBitmapFilter> bitmapFilter;
+  switch (aResizeMethod) {
+  case ResizeMethod::BOX:
+    bitmapFilter = MakeUnique<SkBoxFilter>();
+    break;
+  case ResizeMethod::TRIANGLE:
+    bitmapFilter = MakeUnique<SkTriangleFilter>();
+    break;
+  case ResizeMethod::LANCZOS3:
+    bitmapFilter = MakeUnique<SkLanczosFilter>();
+    break;
+  case ResizeMethod::HAMMING:
+    bitmapFilter = MakeUnique<SkHammingFilter>();
+    break;
+  case ResizeMethod::MITCHELL:
+    bitmapFilter = MakeUnique<SkMitchellFilter>();
+    break;
+  default:
+    return false;
+  }
+
+  // When we're doing a magnification, the scale will be larger than one. This
+  // means the destination pixels are much smaller than the source pixels, and
+  // that the range covered by the filter won't necessarily cover any source
+  // pixel boundaries. Therefore, we use these clamped values (max of 1) for
+  // some computations.
+  float scale = float(aDstSize) / float(aSrcSize);
+  float clampedScale = std::min(1.0f, scale);
+  // This is how many source pixels from the center we need to count
+  // to support the filtering function.
+  float srcSupport = bitmapFilter->width() / clampedScale;
+  float invScale = 1.0f / scale;
+
+  Vector<float, 64> filterValues;
+  Vector<Fixed, 64> fixedFilterValues;
+
+  // Loop over all pixels in the output range. We will generate one set of
+  // filter values for each one. Those values will tell us how to blend the
+  // source pixels to compute the destination pixel.
+
+  // This is the pixel in the source directly under the pixel in the dest.
+  // Note that we base computations on the "center" of the pixels. To see
+  // why, observe that the destination pixel at coordinates (0, 0) in a 5.0x
+  // downscale should "cover" the pixels around the pixel with *its center*
+  // at coordinates (2.5, 2.5) in the source, not those around (0, 0).
+  // Hence we need to scale coordinates (0.5, 0.5), not (0, 0).
+  float srcPixel = 0.5f * invScale;
+  mFilter->reserveAdditional(aDstSize, int32_t(ceil(aDstSize * srcSupport * 2)));
+  for (int32_t destI = 0; destI < aDstSize; destI++) {
+    // Compute the (inclusive) range of source pixels the filter covers.
+    float srcBegin = std::max(0.0f, floorf(srcPixel - srcSupport));
+    float srcEnd = std::min(aSrcSize - 1.0f, ceilf(srcPixel + srcSupport));
+
+    // Compute the unnormalized filter value at each location of the source
+    // it covers.
+
+    // Sum of the filter values for normalizing.
+    // Distance from the center of the filter, this is the filter coordinate
+    // in source space. We also need to consider the center of the pixel
+    // when comparing distance against 'srcPixel'. In the 5x downscale
+    // example used above the distance from the center of the filter to
+    // the pixel with coordinates (2, 2) should be 0, because its center
+    // is at (2.5, 2.5).
+    float destFilterDist = (srcBegin + 0.5f - srcPixel) * clampedScale;
+    int32_t filterCount = int32_t(srcEnd - srcBegin) + 1;
+    if (filterCount <= 0 ||
+        !filterValues.resize(filterCount) ||
+        !fixedFilterValues.resize(filterCount)) {
+      return false;
+    }
+    float filterSum = bitmapFilter->evaluate_n(destFilterDist, clampedScale, filterCount,
+                                               filterValues.begin());
+
+    // The filter must be normalized so that we don't affect the brightness of
+    // the image. Convert to normalized fixed point.
+    Fixed fixedSum = 0;
+    float invFilterSum = 1.0f / filterSum;
+    for (int32_t fixedI = 0; fixedI < filterCount; fixedI++) {
+      Fixed curFixed = SkConvolutionFilter1D::FloatToFixed(filterValues[fixedI] * invFilterSum);
+      fixedSum += curFixed;
+      fixedFilterValues[fixedI] = curFixed;
+    }
+
+    // The conversion to fixed point will leave some rounding errors, which
+    // we add back in to avoid affecting the brightness of the image. We
+    // arbitrarily add this to the center of the filter array (this won't always
+    // be the center of the filter function since it could get clipped on the
+    // edges, but it doesn't matter enough to worry about that case).
+    Fixed leftovers = SkConvolutionFilter1D::FloatToFixed(1) - fixedSum;
+    fixedFilterValues[filterCount / 2] += leftovers;
+
+    mFilter->AddFilter(int32_t(srcBegin), fixedFilterValues.begin(), filterCount);
+
+    srcPixel += invScale;
+  }
+
+  return mFilter->maxFilter() > 0 && mFilter->numValues() == aDstSize;
+}
+
+} // namespace gfx
+} // namespace mozilla
+
new file mode 100644
--- /dev/null
+++ b/gfx/2d/ConvolutionFilter.h
@@ -0,0 +1,48 @@
+/* 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_CONVOLUTION_FILTER_H_
+#define MOZILLA_GFX_CONVOLUTION_FILTER_H_
+
+#include "mozilla/UniquePtr.h"
+
+class SkConvolutionFilter1D;
+
+namespace mozilla {
+namespace gfx {
+
+class ConvolutionFilter
+{
+public:
+  ConvolutionFilter();
+  ~ConvolutionFilter();
+
+  int32_t MaxFilter() const;
+  int32_t NumValues() const;
+
+  bool GetFilterOffsetAndLength(int32_t aRowIndex, int32_t* aResultOffset, int32_t* aResultLength);
+
+  void ConvolveHorizontally(const uint8_t* aSrc, uint8_t* aDst, bool aHasAlpha);
+  void ConvolveVertically(uint8_t* const* aSrc, uint8_t* aDst, int32_t aRowIndex, int32_t aRowSize, bool aHasAlpha);
+
+  enum class ResizeMethod
+  {
+    BOX,
+    TRIANGLE,
+    LANCZOS3,
+    HAMMING,
+    MITCHELL
+  };
+
+  bool ComputeResizeFilter(ResizeMethod aResizeMethod, int32_t aSrcSize, int32_t aDstSize);
+
+private:
+  UniquePtr<SkConvolutionFilter1D> mFilter;
+};
+
+} // namespace gfx
+} // namespace mozilla
+
+#endif /* MOZILLA_GFX_CONVOLUTION_FILTER_H_ */
+
--- a/gfx/2d/DrawEventRecorder.cpp
+++ b/gfx/2d/DrawEventRecorder.cpp
@@ -7,111 +7,105 @@
 #include "PathRecording.h"
 #include "RecordingTypes.h"
 
 namespace mozilla {
 namespace gfx {
 
 using namespace std;
 
-DrawEventRecorderPrivate::DrawEventRecorderPrivate(std::ostream *aStream)
-  : mOutputStream(aStream)
+DrawEventRecorderPrivate::DrawEventRecorderPrivate()
 {
 }
 
+template<class S>
+void
+DrawEventRecorderPrivate::WriteHeader(S &aStream)
+{
+  WriteElement(aStream, kMagicInt);
+  WriteElement(aStream, kMajorRevision);
+  WriteElement(aStream, kMinorRevision);
+}
+
 void
-DrawEventRecorderPrivate::WriteHeader()
+DrawEventRecorderFile::RecordEvent(const RecordedEvent &aEvent)
 {
-  WriteElement(*mOutputStream, kMagicInt);
-  WriteElement(*mOutputStream, kMajorRevision);
-  WriteElement(*mOutputStream, kMinorRevision);
-}
+  WriteElement(mOutputStream, aEvent.mType);
 
-void
-DrawEventRecorderPrivate::RecordEvent(const RecordedEvent &aEvent)
-{
-  WriteElement(*mOutputStream, aEvent.mType);
-
-  aEvent.RecordToStream(*mOutputStream);
+  aEvent.RecordToStream(mOutputStream);
 
   Flush();
 }
 
-DrawEventRecorderFile::DrawEventRecorderFile(const char *aFilename)
-  : DrawEventRecorderPrivate(nullptr)
-  , mOutputFile(aFilename, ofstream::binary)
+void
+DrawEventRecorderMemory::RecordEvent(const RecordedEvent &aEvent)
 {
-  mOutputStream = &mOutputFile;
+  WriteElement(mOutputStream, aEvent.mType);
+
+  aEvent.RecordToStream(mOutputStream);
+}
 
-  WriteHeader();
+DrawEventRecorderFile::DrawEventRecorderFile(const char *aFilename)
+  : mOutputStream(aFilename, ofstream::binary)
+{
+  WriteHeader(mOutputStream);
 }
 
 DrawEventRecorderFile::~DrawEventRecorderFile()
 {
-  mOutputFile.close();
+  mOutputStream.close();
 }
 
 void
 DrawEventRecorderFile::Flush()
 {
-  mOutputFile.flush();
+  mOutputStream.flush();
 }
 
 bool
 DrawEventRecorderFile::IsOpen()
 {
-  return mOutputFile.is_open();
+  return mOutputStream.is_open();
 }
 
 void
 DrawEventRecorderFile::OpenNew(const char *aFilename)
 {
-  MOZ_ASSERT(!mOutputFile.is_open());
+  MOZ_ASSERT(!mOutputStream.is_open());
 
-  mOutputFile.open(aFilename, ofstream::binary);
-  WriteHeader();
+  mOutputStream.open(aFilename, ofstream::binary);
+  WriteHeader(mOutputStream);
 }
 
 void
 DrawEventRecorderFile::Close()
 {
-  MOZ_ASSERT(mOutputFile.is_open());
+  MOZ_ASSERT(mOutputStream.is_open());
 
-  mOutputFile.close();
+  mOutputStream.close();
 }
 
 DrawEventRecorderMemory::DrawEventRecorderMemory()
-  : DrawEventRecorderPrivate(nullptr)
 {
-  mOutputStream = &mMemoryStream;
-
-  WriteHeader();
+  WriteHeader(mOutputStream);
 }
 
 void
 DrawEventRecorderMemory::Flush()
 {
-   mOutputStream->flush();
 }
 
 size_t
 DrawEventRecorderMemory::RecordingSize()
 {
-  return mMemoryStream.tellp();
-}
-
-bool
-DrawEventRecorderMemory::CopyRecording(char* aBuffer, size_t aBufferLen)
-{
-  return !!mMemoryStream.read(aBuffer, aBufferLen);
+  return mOutputStream.mLength;
 }
 
 void
 DrawEventRecorderMemory::WipeRecording()
 {
-  mMemoryStream.str(std::string());
-  mMemoryStream.clear();
+  mOutputStream = MemStream();
 
-  WriteHeader();
+  WriteHeader(mOutputStream);
 }
 
 } // namespace gfx
 } // namespace mozilla
--- a/gfx/2d/DrawEventRecorder.h
+++ b/gfx/2d/DrawEventRecorder.h
@@ -21,35 +21,36 @@ namespace mozilla {
 namespace gfx {
 
 class PathRecording;
 
 class DrawEventRecorderPrivate : public DrawEventRecorder
 {
 public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawEventRecorderPrivate)
-  explicit DrawEventRecorderPrivate(std::ostream *aStream);
+  DrawEventRecorderPrivate();
   virtual ~DrawEventRecorderPrivate() { }
   virtual void Finish() {
     // The iteration is a bit awkward here because our iterator will
     // be invalidated by the removal
     for (auto font = mStoredFonts.begin(); font != mStoredFonts.end(); ) {
       auto oldFont = font++;
       (*oldFont)->RemoveUserData(reinterpret_cast<UserDataKey*>(this));
     }
     for (auto surface = mStoredSurfaces.begin(); surface != mStoredSurfaces.end(); ) {
       auto oldSurface = surface++;
       (*oldSurface)->RemoveUserData(reinterpret_cast<UserDataKey*>(this));
     }
 
   }
 
-  void WriteHeader();
+  template<class S>
+  void WriteHeader(S &aStream);
 
-  void RecordEvent(const RecordedEvent &aEvent);
+  virtual void RecordEvent(const RecordedEvent &aEvent) = 0;
   void WritePath(const PathRecording *aPath);
 
   void AddStoredObject(const ReferencePtr aObject) {
     mStoredObjects.insert(aObject);
   }
 
   void RemoveStoredObject(const ReferencePtr aObject) {
     mStoredObjects.erase(aObject);
@@ -79,18 +80,16 @@ public:
     mStoredFontData.insert(aFontDataKey);
   }
 
   bool HasStoredFontData(const uint64_t aFontDataKey) {
     return mStoredFontData.find(aFontDataKey) != mStoredFontData.end();
   }
 
 protected:
-  std::ostream *mOutputStream;
-
   virtual void Flush() = 0;
 
 #if defined(_MSC_VER)
   typedef std::unordered_set<const void*> ObjectSet;
   typedef std::unordered_set<uint64_t> Uint64Set;
   typedef std::unordered_set<ScaledFont*> FontSet;
   typedef std::unordered_set<SourceSurface*> SurfaceSet;
 #else
@@ -104,20 +103,22 @@ protected:
   Uint64Set mStoredFontData;
   FontSet mStoredFonts;
   SurfaceSet mStoredSurfaces;
 };
 
 class DrawEventRecorderFile : public DrawEventRecorderPrivate
 {
 public:
-  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawEventRecorderFile)
+  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawEventRecorderFile, override)
   explicit DrawEventRecorderFile(const char *aFilename);
   ~DrawEventRecorderFile();
 
+  void RecordEvent(const RecordedEvent &aEvent) override;
+
   /**
    * Returns whether a recording file is currently open.
    */
   bool IsOpen();
 
   /**
    * Opens new file with the provided name. The recorder does NOT forget which
    * objects it has recorded. This can be used with Close, so that a recording
@@ -128,66 +129,50 @@ public:
   /**
    * Closes the file so that it can be processed. The recorder does NOT forget
    * which objects it has recorded. This can be used with OpenNew, so that a
    * recording can be processed in chunks. The file must be open.
    */
   void Close();
 
 private:
-  virtual void Flush();
+  void Flush() override;
 
-  std::ofstream mOutputFile;
+  std::ofstream mOutputStream;
 };
 
 // WARNING: This should not be used in its existing state because
 // it is likely to OOM because of large continguous allocations.
 class DrawEventRecorderMemory final : public DrawEventRecorderPrivate
 {
 public:
-  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawEventRecorderMemory)
+  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawEventRecorderMemory, override)
 
   /**
    * Constructs a DrawEventRecorder that stores the recording in memory.
    */
   DrawEventRecorderMemory();
 
+  void RecordEvent(const RecordedEvent &aEvent) override;
+
   /**
    * @return the current size of the recording (in chars).
    */
   size_t RecordingSize();
 
   /**
-   * Copies at most aBufferLen chars of the recording into aBuffer.
-   *
-   * @param aBuffer buffer to receive the recording chars
-   * @param aBufferLen length of aBuffer
-   * @return true if copied successfully
-   */
-  bool CopyRecording(char* aBuffer, size_t aBufferLen);
-
-  /**
    * Wipes the internal recording buffer, but the recorder does NOT forget which
    * objects it has recorded. This can be used so that a recording can be copied
    * and processed in chunks, releasing memory as it goes.
    */
   void WipeRecording();
 
-  /**
-   * Gets a readable reference of the underlying stream, reset to the beginning.
-   */
-  std::istream& GetInputStream() {
-    mMemoryStream.seekg(0);
-    return mMemoryStream;
-  }
-
+  MemStream mOutputStream;
 private:
   ~DrawEventRecorderMemory() {};
 
-  void Flush() final;
-
-  std::stringstream mMemoryStream;
+  void Flush() override;
 };
 
 } // namespace gfx
 } // namespace mozilla
 
 #endif /* MOZILLA_GFX_DRAWEVENTRECORDER_H_ */
--- a/gfx/2d/DrawTargetDual.cpp
+++ b/gfx/2d/DrawTargetDual.cpp
@@ -203,21 +203,15 @@ DrawTargetDual::PushLayer(bool aOpaque, 
   DualSurface mask(aMask);
   mA->PushLayer(aOpaque, aOpacity, mask.mA, aMaskTransform, aBounds, aCopyBackground);
   mB->PushLayer(aOpaque, aOpacity, mask.mB, aMaskTransform, aBounds, aCopyBackground);
 }
 
 already_AddRefed<DrawTarget>
 DrawTargetDual::CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const
 {
-  RefPtr<DrawTarget> dtA = mA->CreateSimilarDrawTarget(aSize, aFormat);
-  RefPtr<DrawTarget> dtB = mB->CreateSimilarDrawTarget(aSize, aFormat);
-
-  if (!dtA || !dtB) {
-    gfxWarning() << "Failure to allocate a similar DrawTargetDual. Size: " << aSize;
-    return nullptr;
-  }
-
-  return MakeAndAddRef<DrawTargetDual>(dtA, dtB);
+  /* Now that we have PushLayer there a very few cases where a user of DrawTargetDual
+   * wants to have a DualTarget when creating a similar one. */
+  return mA->CreateSimilarDrawTarget(aSize, aFormat);
 }
 
 } // namespace gfx
 } // namespace mozilla
--- a/gfx/2d/DrawTargetRecording.cpp
+++ b/gfx/2d/DrawTargetRecording.cpp
@@ -8,16 +8,17 @@
 #include "PathRecording.h"
 #include <stdio.h>
 
 #include "Logging.h"
 #include "Tools.h"
 #include "Filters.h"
 #include "mozilla/UniquePtr.h"
 #include "RecordingTypes.h"
+#include "RecordedEventImpl.h"
 
 namespace mozilla {
 namespace gfx {
 
 struct RecordingSourceSurfaceUserData
 {
   void *refPtr;
   RefPtr<DrawEventRecorderPrivate> recorder;
--- a/gfx/2d/DrawTargetWrapAndRecord.cpp
+++ b/gfx/2d/DrawTargetWrapAndRecord.cpp
@@ -8,16 +8,17 @@
 #include "PathRecording.h"
 #include <stdio.h>
 
 #include "Logging.h"
 #include "Tools.h"
 #include "Filters.h"
 #include "mozilla/UniquePtr.h"
 #include "RecordingTypes.h"
+#include "RecordedEventImpl.h"
 
 namespace mozilla {
 namespace gfx {
 
 struct WrapAndRecordSourceSurfaceUserData
 {
   void *refPtr;
   RefPtr<DrawEventRecorderPrivate> recorder;
--- a/gfx/2d/PathRecording.cpp
+++ b/gfx/2d/PathRecording.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; tab-width: 20; 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 "PathRecording.h"
 #include "DrawEventRecorder.h"
+#include "RecordedEventImpl.h"
 
 namespace mozilla {
 namespace gfx {
 
 using namespace std;
 
 void
 PathBuilderRecording::MoveTo(const Point &aPoint)
--- a/gfx/2d/RecordedEvent.cpp
+++ b/gfx/2d/RecordedEvent.cpp
@@ -1,50 +1,28 @@
 /* -*- Mode: C++; tab-width: 20; 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 "RecordedEvent.h"
+#include "RecordedEventImpl.h"
 
 #include "PathRecording.h"
 #include "RecordingTypes.h"
 #include "Tools.h"
 #include "Filters.h"
 #include "Logging.h"
 #include "ScaledFontBase.h"
 #include "SFNTData.h"
 
 namespace mozilla {
 namespace gfx {
 
 using namespace std;
 
-static std::string NameFromBackend(BackendType aType)
-{
-  switch (aType) {
-  case BackendType::NONE:
-    return "None";
-  case BackendType::DIRECT2D:
-    return "Direct2D";
-  default:
-    return "Unknown";
-  }
-}
-
-already_AddRefed<DrawTarget>
-Translator::CreateDrawTarget(ReferencePtr aRefPtr, const IntSize &aSize,
-                             SurfaceFormat aFormat)
-{
-  RefPtr<DrawTarget> newDT =
-    GetReferenceDrawTarget()->CreateSimilarDrawTarget(aSize, aFormat);
-  AddDrawTarget(aRefPtr, newDT);
-  return newDT.forget();
-}
-
 #define LOAD_EVENT_TYPE(_typeenum, _class) \
   case _typeenum: return new _class(aStream)
 
 RecordedEvent *
 RecordedEvent::LoadEventFromStream(std::istream &aStream, EventType aType)
 {
   switch (aType) {
     LOAD_EVENT_TYPE(DRAWTARGETCREATION, RecordedDrawTargetCreation);
@@ -173,1815 +151,20 @@ RecordedEvent::GetEventName(EventType aT
     return "UnscaledFontCreation";
   case UNSCALEDFONTDESTRUCTION:
     return "UnscaledFontDestruction";
   default:
     return "Unknown";
   }
 }
 
-void
-RecordedEvent::RecordPatternData(std::ostream &aStream, const PatternStorage &aPattern) const
-{
-  WriteElement(aStream, aPattern.mType);
-
-  switch (aPattern.mType) {
-  case PatternType::COLOR:
-    {
-      WriteElement(aStream, *reinterpret_cast<const ColorPatternStorage*>(&aPattern.mStorage));
-      return;
-    }
-  case PatternType::LINEAR_GRADIENT:
-    {
-      WriteElement(aStream, *reinterpret_cast<const LinearGradientPatternStorage*>(&aPattern.mStorage));
-      return;
-    }
-  case PatternType::RADIAL_GRADIENT:
-    {
-      WriteElement(aStream, *reinterpret_cast<const RadialGradientPatternStorage*>(&aPattern.mStorage));
-      return;
-    }
-  case PatternType::SURFACE:
-    {
-      WriteElement(aStream, *reinterpret_cast<const SurfacePatternStorage*>(&aPattern.mStorage));
-      return;
-    }
-  default:
-    return;
-  }
-}
-
-void
-RecordedEvent::ReadPatternData(std::istream &aStream, PatternStorage &aPattern) const
-{
-  ReadElement(aStream, aPattern.mType);
-
-  switch (aPattern.mType) {
-  case PatternType::COLOR:
-    {
-      ReadElement(aStream, *reinterpret_cast<ColorPatternStorage*>(&aPattern.mStorage));
-      return;
-    }
-  case PatternType::LINEAR_GRADIENT:
-    {
-      ReadElement(aStream, *reinterpret_cast<LinearGradientPatternStorage*>(&aPattern.mStorage));
-      return;
-    }
-  case PatternType::RADIAL_GRADIENT:
-    {
-      ReadElement(aStream, *reinterpret_cast<RadialGradientPatternStorage*>(&aPattern.mStorage));
-      return;
-    }
-  case PatternType::SURFACE:
-    {
-      ReadElement(aStream, *reinterpret_cast<SurfacePatternStorage*>(&aPattern.mStorage));
-      return;
-    }
-  default:
-    return;
-  }
-}
-
-void
-RecordedEvent::StorePattern(PatternStorage &aDestination, const Pattern &aSource) const
-{
-  aDestination.mType = aSource.GetType();
-  
-  switch (aSource.GetType()) {
-  case PatternType::COLOR:
-    {
-      reinterpret_cast<ColorPatternStorage*>(&aDestination.mStorage)->mColor =
-        static_cast<const ColorPattern*>(&aSource)->mColor;
-      return;
-    }
-  case PatternType::LINEAR_GRADIENT:
-    {
-      LinearGradientPatternStorage *store =
-        reinterpret_cast<LinearGradientPatternStorage*>(&aDestination.mStorage);
-      const LinearGradientPattern *pat =
-        static_cast<const LinearGradientPattern*>(&aSource);
-      store->mBegin = pat->mBegin;
-      store->mEnd = pat->mEnd;
-      store->mMatrix = pat->mMatrix;
-      store->mStops = pat->mStops.get();
-      return;
-    }
-  case PatternType::RADIAL_GRADIENT:
-    {
-      RadialGradientPatternStorage *store =
-        reinterpret_cast<RadialGradientPatternStorage*>(&aDestination.mStorage);
-      const RadialGradientPattern *pat =
-        static_cast<const RadialGradientPattern*>(&aSource);
-      store->mCenter1 = pat->mCenter1;
-      store->mCenter2 = pat->mCenter2;
-      store->mRadius1 = pat->mRadius1;
-      store->mRadius2 = pat->mRadius2;
-      store->mMatrix = pat->mMatrix;
-      store->mStops = pat->mStops.get();
-      return;
-    }
-  case PatternType::SURFACE:
-    {
-      SurfacePatternStorage *store =
-        reinterpret_cast<SurfacePatternStorage*>(&aDestination.mStorage);
-      const SurfacePattern *pat =
-        static_cast<const SurfacePattern*>(&aSource);
-      store->mExtend = pat->mExtendMode;
-      store->mSamplingFilter = pat->mSamplingFilter;
-      store->mMatrix = pat->mMatrix;
-      store->mSurface = pat->mSurface;
-      store->mSamplingRect = pat->mSamplingRect;
-      return;
-    }
-  }
-}
-
-void
-RecordedEvent::RecordStrokeOptions(std::ostream &aStream, const StrokeOptions &aStrokeOptions) const
-{
-  JoinStyle joinStyle = aStrokeOptions.mLineJoin;
-  CapStyle capStyle = aStrokeOptions.mLineCap;
-
-  WriteElement(aStream, uint64_t(aStrokeOptions.mDashLength));
-  WriteElement(aStream, aStrokeOptions.mDashOffset);
-  WriteElement(aStream, aStrokeOptions.mLineWidth);
-  WriteElement(aStream, aStrokeOptions.mMiterLimit);
-  WriteElement(aStream, joinStyle);
-  WriteElement(aStream, capStyle);
-
-  if (!aStrokeOptions.mDashPattern) {
-    return;
-  }
-
-  aStream.write((char*)aStrokeOptions.mDashPattern, sizeof(Float) * aStrokeOptions.mDashLength);
-}
-
-void
-RecordedEvent::ReadStrokeOptions(std::istream &aStream, StrokeOptions &aStrokeOptions)
-{
-  uint64_t dashLength;
-  JoinStyle joinStyle;
-  CapStyle capStyle;
-
-  ReadElement(aStream, dashLength);
-  ReadElement(aStream, aStrokeOptions.mDashOffset);
-  ReadElement(aStream, aStrokeOptions.mLineWidth);
-  ReadElement(aStream, aStrokeOptions.mMiterLimit);
-  ReadElement(aStream, joinStyle);
-  ReadElement(aStream, capStyle);
-  // On 32 bit we truncate the value of dashLength.
-  // See also bug 811850 for history.
-  aStrokeOptions.mDashLength = size_t(dashLength);
-  aStrokeOptions.mLineJoin = joinStyle;
-  aStrokeOptions.mLineCap = capStyle;
-
-  if (!aStrokeOptions.mDashLength) {
-    return;
-  }
-
-  mDashPatternStorage.resize(aStrokeOptions.mDashLength);
-  aStrokeOptions.mDashPattern = &mDashPatternStorage.front();
-  aStream.read((char*)aStrokeOptions.mDashPattern, sizeof(Float) * aStrokeOptions.mDashLength);
-}
-
-void
-RecordedEvent::OutputSimplePatternInfo(const PatternStorage &aStorage, std::stringstream &aOutput) const
-{
-  switch (aStorage.mType) {
-  case PatternType::COLOR:
-    {
-      const Color color = reinterpret_cast<const ColorPatternStorage*>(&aStorage.mStorage)->mColor;
-      aOutput << "Color: (" << color.r << ", " << color.g << ", " << color.b << ", " << color.a << ")";
-      return;
-    }
-  case PatternType::LINEAR_GRADIENT:
-    {
-      const LinearGradientPatternStorage *store =
-        reinterpret_cast<const LinearGradientPatternStorage*>(&aStorage.mStorage);
-
-      aOutput << "LinearGradient (" << store->mBegin.x << ", " << store->mBegin.y <<
-        ") - (" << store->mEnd.x << ", " << store->mEnd.y << ") Stops: " << store->mStops;
-      return;
-    }
-  case PatternType::RADIAL_GRADIENT:
-    {
-      const RadialGradientPatternStorage *store =
-        reinterpret_cast<const RadialGradientPatternStorage*>(&aStorage.mStorage);
-      aOutput << "RadialGradient (Center 1: (" << store->mCenter1.x << ", " <<
-        store->mCenter2.y << ") Radius 2: " << store->mRadius2;
-      return;
-    }
-  case PatternType::SURFACE:
-    {
-      const SurfacePatternStorage *store =
-        reinterpret_cast<const SurfacePatternStorage*>(&aStorage.mStorage);
-      aOutput << "Surface (0x" << store->mSurface << ")";
-      return;
-    }
-  }
-}
-
-RecordedDrawingEvent::RecordedDrawingEvent(EventType aType, std::istream &aStream)
-  : RecordedEvent(aType)
-{
-  ReadElement(aStream, mDT);
-}
-
-void
-RecordedDrawingEvent::RecordToStream(ostream &aStream) const
-{
-  WriteElement(aStream, mDT);
-}
-
-ReferencePtr
-RecordedDrawingEvent::GetObjectRef() const
-{
-  return mDT;
-}
-
-bool
-RecordedDrawTargetCreation::PlayEvent(Translator *aTranslator) const
-{
-  RefPtr<DrawTarget> newDT =
-    aTranslator->CreateDrawTarget(mRefPtr, mSize, mFormat);
-
-  // If we couldn't create a DrawTarget this will probably cause us to crash
-  // with nullptr later in the playback, so return false to abort.
-  if (!newDT) {
-    return false;
-  }
-
-  if (mHasExistingData) {
-    Rect dataRect(0, 0, mExistingData->GetSize().width, mExistingData->GetSize().height);
-    newDT->DrawSurface(mExistingData, dataRect, dataRect);
-  }
-
-  return true;
-}
-
-void
-RecordedDrawTargetCreation::RecordToStream(ostream &aStream) const
-{
-  WriteElement(aStream, mRefPtr);
-  WriteElement(aStream, mBackendType);
-  WriteElement(aStream, mSize);
-  WriteElement(aStream, mFormat);
-  WriteElement(aStream, mHasExistingData);
-
-  if (mHasExistingData) {
-    MOZ_ASSERT(mExistingData);
-    MOZ_ASSERT(mExistingData->GetSize() == mSize);
-    RefPtr<DataSourceSurface> dataSurf = mExistingData->GetDataSurface();
-    for (int y = 0; y < mSize.height; y++) {
-      aStream.write((const char*)dataSurf->GetData() + y * dataSurf->Stride(),
-                    BytesPerPixel(mFormat) * mSize.width);
-    }
-  }
-}
-
-RecordedDrawTargetCreation::RecordedDrawTargetCreation(istream &aStream)
-  : RecordedEvent(DRAWTARGETCREATION)
-  , mExistingData(nullptr)
-{
-  ReadElement(aStream, mRefPtr);
-  ReadElement(aStream, mBackendType);
-  ReadElement(aStream, mSize);
-  ReadElement(aStream, mFormat);
-  ReadElement(aStream, mHasExistingData);
-
-  if (mHasExistingData) {
-    RefPtr<DataSourceSurface> dataSurf = Factory::CreateDataSourceSurface(mSize, mFormat);
-    if (!dataSurf) {
-      gfxWarning() << "RecordedDrawTargetCreation had to reset mHasExistingData";
-      mHasExistingData = false;
-      return;
-    }
-
-    for (int y = 0; y < mSize.height; y++) {
-      aStream.read((char*)dataSurf->GetData() + y * dataSurf->Stride(),
-                    BytesPerPixel(mFormat) * mSize.width);
-    }
-    mExistingData = dataSurf;
-  }
-}
-
-void
-RecordedDrawTargetCreation::OutputSimpleEventInfo(stringstream &aStringStream) const
-{