Merge mozilla-central to autoland a=merge
authorCoroiu Cristina <ccoroiu@mozilla.com>
Tue, 16 Apr 2019 07:09:25 +0300
changeset 469608 c918588ff945
parent 469607 38ecdf260ccd (current diff)
parent 469606 a83cab75b00d (diff)
child 469609 2a5c7852f148
push id35876
push useropoprus@mozilla.com
push dateTue, 16 Apr 2019 09:47:48 +0000
treeherdermozilla-central@fe4a28a68cfc [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to autoland a=merge
--- 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: 2.2.129
+Current extension version is: 2.2.145
 
-Taken from upstream commit: 725a6959
+Taken from upstream commit: 8bbae798
--- a/browser/extensions/pdfjs/content/build/pdf.js
+++ b/browser/extensions/pdfjs/content/build/pdf.js
@@ -118,18 +118,18 @@ return /******/ (function(modules) { // 
 /************************************************************************/
 /******/ ([
 /* 0 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
-var pdfjsVersion = '2.2.129';
-var pdfjsBuild = '725a6959';
+var pdfjsVersion = '2.2.145';
+var pdfjsBuild = '8bbae798';
 
 var pdfjsSharedUtil = __w_pdfjs_require__(1);
 
 var pdfjsDisplayAPI = __w_pdfjs_require__(6);
 
 var pdfjsDisplayTextLayer = __w_pdfjs_require__(18);
 
 var pdfjsDisplayAnnotationLayer = __w_pdfjs_require__(19);
@@ -1298,17 +1298,17 @@ function _fetchDocument(worker, source, 
   if (pdfDataRangeTransport) {
     source.length = pdfDataRangeTransport.length;
     source.initialData = pdfDataRangeTransport.initialData;
     source.progressiveDone = pdfDataRangeTransport.progressiveDone;
   }
 
   return worker.messageHandler.sendWithPromise('GetDocRequest', {
     docId,
-    apiVersion: '2.2.129',
+    apiVersion: '2.2.145',
     source: {
       data: source.data,
       url: source.url,
       password: source.password,
       disableAutoFetch: source.disableAutoFetch,
       rangeChunkSize: source.rangeChunkSize,
       length: source.length
     },
@@ -2376,16 +2376,21 @@ class WorkerTransport {
       }, headersCapability.reject);
       return headersCapability.promise;
     }, this);
     messageHandler.on('GetRangeReader', function (data, sink) {
       (0, _util.assert)(this._networkStream);
 
       const rangeReader = this._networkStream.getRangeReader(data.begin, data.end);
 
+      if (!rangeReader) {
+        sink.close();
+        return;
+      }
+
       sink.onPull = () => {
         rangeReader.read().then(function ({
           value,
           done
         }) {
           if (done) {
             sink.close();
             return;
@@ -3078,19 +3083,19 @@ const InternalRenderTask = function Inte
       }
     }
 
   }
 
   return InternalRenderTask;
 }();
 
-const version = '2.2.129';
+const version = '2.2.145';
 exports.version = version;
-const build = '725a6959';
+const build = '8bbae798';
 exports.build = build;
 
 /***/ }),
 /* 7 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
@@ -7387,16 +7392,21 @@ var PDFDataTransportStream = function PD
           rangeReader._enqueue(buffer);
 
           return true;
         });
 
         (0, _util.assert)(found);
       }
     },
+
+    get _progressiveDataLength() {
+      return this._fullRequestReader ? this._fullRequestReader._loaded : 0;
+    },
+
     _onProgress: function PDFDataTransportStream_onDataProgress(evt) {
       if (evt.total === undefined && this._rangeReaders.length > 0) {
         var firstReader = this._rangeReaders[0];
 
         if (firstReader.onProgress) {
           firstReader.onProgress({
             loaded: evt.loaded
           });
@@ -7431,16 +7441,20 @@ var PDFDataTransportStream = function PD
     },
     getFullReader: function PDFDataTransportStream_getFullReader() {
       (0, _util.assert)(!this._fullRequestReader);
       var queuedChunks = this._queuedChunks;
       this._queuedChunks = null;
       return new PDFDataTransportStreamReader(this, queuedChunks, this._progressiveDone);
     },
     getRangeReader: function PDFDataTransportStream_getRangeReader(begin, end) {
+      if (end <= this._progressiveDataLength) {
+        return null;
+      }
+
       var reader = new PDFDataTransportStreamRangeReader(this, begin, end);
 
       this._pdfDataRangeTransport.requestDataRange(begin, end);
 
       this._rangeReaders.push(reader);
 
       return reader;
     },
@@ -7459,16 +7473,22 @@ var PDFDataTransportStream = function PD
     }
   };
 
   function PDFDataTransportStreamReader(stream, queuedChunks, progressiveDone = false) {
     this._stream = stream;
     this._done = progressiveDone || false;
     this._filename = null;
     this._queuedChunks = queuedChunks || [];
+    this._loaded = 0;
+
+    for (const chunk of this._queuedChunks) {
+      this._loaded += chunk.byteLength;
+    }
+
     this._requests = [];
     this._headersReady = Promise.resolve();
     stream._fullRequestReader = this;
     this.onProgress = null;
   }
 
   PDFDataTransportStreamReader.prototype = {
     _enqueue: function PDFDataTransportStreamReader_enqueue(chunk) {
@@ -7478,20 +7498,21 @@ var PDFDataTransportStream = function PD
 
       if (this._requests.length > 0) {
         var requestCapability = this._requests.shift();
 
         requestCapability.resolve({
           value: chunk,
           done: false
         });
-        return;
-      }
-
-      this._queuedChunks.push(chunk);
+      } else {
+        this._queuedChunks.push(chunk);
+      }
+
+      this._loaded += chunk.byteLength;
     },
 
     get headersReady() {
       return this._headersReady;
     },
 
     get filename() {
       return this._filename;
@@ -8820,28 +8841,34 @@ class AnnotationElementFactory {
             return new ChoiceWidgetAnnotationElement(parameters);
         }
 
         return new WidgetAnnotationElement(parameters);
 
       case _util.AnnotationType.POPUP:
         return new PopupAnnotationElement(parameters);
 
+      case _util.AnnotationType.FREETEXT:
+        return new FreeTextAnnotationElement(parameters);
+
       case _util.AnnotationType.LINE:
         return new LineAnnotationElement(parameters);
 
       case _util.AnnotationType.SQUARE:
         return new SquareAnnotationElement(parameters);
 
       case _util.AnnotationType.CIRCLE:
         return new CircleAnnotationElement(parameters);
 
       case _util.AnnotationType.POLYLINE:
         return new PolylineAnnotationElement(parameters);
 
+      case _util.AnnotationType.CARET:
+        return new CaretAnnotationElement(parameters);
+
       case _util.AnnotationType.INK:
         return new InkAnnotationElement(parameters);
 
       case _util.AnnotationType.POLYGON:
         return new PolygonAnnotationElement(parameters);
 
       case _util.AnnotationType.HIGHLIGHT:
         return new HighlightAnnotationElement(parameters);
@@ -9362,16 +9389,34 @@ class PopupElement {
     if (!this.hideElement.hasAttribute('hidden') && !this.pinned) {
       this.hideElement.setAttribute('hidden', true);
       this.container.style.zIndex -= 1;
     }
   }
 
 }
 
+class FreeTextAnnotationElement extends AnnotationElement {
+  constructor(parameters) {
+    const isRenderable = !!(parameters.data.hasPopup || parameters.data.title || parameters.data.contents);
+    super(parameters, isRenderable, true);
+  }
+
+  render() {
+    this.container.className = 'freeTextAnnotation';
+
+    if (!this.data.hasPopup) {
+      this._createPopup(this.container, null, this.data);
+    }
+
+    return this.container;
+  }
+
+}
+
 class LineAnnotationElement extends AnnotationElement {
   constructor(parameters) {
     let isRenderable = !!(parameters.data.hasPopup || parameters.data.title || parameters.data.contents);
     super(parameters, isRenderable, true);
   }
 
   render() {
     this.container.className = 'lineAnnotation';
@@ -9502,16 +9547,34 @@ class PolygonAnnotationElement extends P
   constructor(parameters) {
     super(parameters);
     this.containerClassName = 'polygonAnnotation';
     this.svgElementName = 'svg:polygon';
   }
 
 }
 
+class CaretAnnotationElement extends AnnotationElement {
+  constructor(parameters) {
+    const isRenderable = !!(parameters.data.hasPopup || parameters.data.title || parameters.data.contents);
+    super(parameters, isRenderable, true);
+  }
+
+  render() {
+    this.container.className = 'caretAnnotation';
+
+    if (!this.data.hasPopup) {
+      this._createPopup(this.container, null, this.data);
+    }
+
+    return this.container;
+  }
+
+}
+
 class InkAnnotationElement extends AnnotationElement {
   constructor(parameters) {
     let isRenderable = !!(parameters.data.hasPopup || parameters.data.title || parameters.data.contents);
     super(parameters, isRenderable, true);
     this.containerClassName = 'inkAnnotation';
     this.svgElementName = 'svg:polyline';
   }
 
--- a/browser/extensions/pdfjs/content/build/pdf.worker.js
+++ b/browser/extensions/pdfjs/content/build/pdf.worker.js
@@ -118,18 +118,18 @@ return /******/ (function(modules) { // 
 /************************************************************************/
 /******/ ([
 /* 0 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
-const pdfjsVersion = '2.2.129';
-const pdfjsBuild = '725a6959';
+const pdfjsVersion = '2.2.145';
+const pdfjsBuild = '8bbae798';
 
 const pdfjsCoreWorker = __w_pdfjs_require__(1);
 
 exports.WorkerMessageHandler = pdfjsCoreWorker.WorkerMessageHandler;
 
 /***/ }),
 /* 1 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
@@ -373,17 +373,17 @@ var WorkerMessageHandler = {
 
   createDocumentHandler(docParams, port) {
     var pdfManager;
     var terminated = false;
     var cancelXHRs = null;
     var WorkerTasks = [];
     const verbosity = (0, _util.getVerbosityLevel)();
     let apiVersion = docParams.apiVersion;
-    let workerVersion = '2.2.129';
+    let workerVersion = '2.2.145';
 
     if (apiVersion !== workerVersion) {
       throw new Error(`The API version "${apiVersion}" does not match ` + `the Worker version "${workerVersion}".`);
     }
 
     var docId = docParams.docId;
     var docBaseUrl = docParams.docBaseUrl;
     var workerHandlerName = docParams.docId + '_worker';
@@ -2033,16 +2033,20 @@ class ChunkedStream {
       if (!this.loadedChunks[curChunk]) {
         this.loadedChunks[curChunk] = true;
         ++this.numChunksLoaded;
       }
     }
   }
 
   ensureByte(pos) {
+    if (pos < this.progressiveDataLength) {
+      return;
+    }
+
     const chunk = Math.floor(pos / this.chunkSize);
 
     if (chunk === this.lastSuccessfulEnsureByteChunk) {
       return;
     }
 
     if (!this.loadedChunks[chunk]) {
       throw new _core_utils.MissingDataException(pos, pos + 1);
@@ -2179,17 +2183,21 @@ class ChunkedStream {
     this.pos = this.start;
   }
 
   moveStart() {
     this.start = this.pos;
   }
 
   makeSubStream(start, length, dict) {
-    this.ensureRange(start, start + length);
+    if (length) {
+      this.ensureRange(start, start + length);
+    } else {
+      this.ensureByte(start);
+    }
 
     function ChunkedStreamSubstream() {}
 
     ChunkedStreamSubstream.prototype = Object.create(this);
 
     ChunkedStreamSubstream.prototype.getMissingChunks = function () {
       const chunkSize = this.chunkSize;
       const beginChunk = Math.floor(this.start / chunkSize);
@@ -18071,31 +18079,37 @@ class AnnotationFactory {
         }
 
         (0, _util.warn)('Unimplemented widget field type "' + fieldType + '", ' + 'falling back to base field type.');
         return new WidgetAnnotation(parameters);
 
       case 'Popup':
         return new PopupAnnotation(parameters);
 
+      case 'FreeText':
+        return new FreeTextAnnotation(parameters);
+
       case 'Line':
         return new LineAnnotation(parameters);
 
       case 'Square':
         return new SquareAnnotation(parameters);
 
       case 'Circle':
         return new CircleAnnotation(parameters);
 
       case 'PolyLine':
         return new PolylineAnnotation(parameters);
 
       case 'Polygon':
         return new PolygonAnnotation(parameters);
 
+      case 'Caret':
+        return new CaretAnnotation(parameters);
+
       case 'Ink':
         return new InkAnnotation(parameters);
 
       case 'Highlight':
         return new HighlightAnnotation(parameters);
 
       case 'Underline':
         return new UnderlineAnnotation(parameters);
@@ -18300,26 +18314,16 @@ class Annotation {
 
     if (!(0, _primitives.isName)(as) || !normalAppearanceState.has(as.name)) {
       return;
     }
 
     this.appearance = normalAppearanceState.get(as.name);
   }
 
-  _preparePopup(dict) {
-    if (!dict.has('C')) {
-      this.data.color = null;
-    }
-
-    this.data.hasPopup = dict.has('Popup');
-    this.data.title = (0, _util.stringToPDFString)(dict.get('T') || '');
-    this.data.contents = (0, _util.stringToPDFString)(dict.get('Contents') || '');
-  }
-
   loadResources(keys) {
     return this.appearance.dict.getAsync('Resources').then(resources => {
       if (!resources) {
         return;
       }
 
       let objectLoader = new _obj.ObjectLoader(resources, keys, resources.xref);
       return objectLoader.load().then(function () {
@@ -18448,16 +18452,32 @@ class AnnotationBorderStyle {
       this.verticalCornerRadius = radius;
     }
   }
 
 }
 
 exports.AnnotationBorderStyle = AnnotationBorderStyle;
 
+class MarkupAnnotation extends Annotation {
+  constructor(parameters) {
+    super(parameters);
+    const dict = parameters.dict;
+
+    if (!dict.has('C')) {
+      this.data.color = null;
+    }
+
+    this.data.hasPopup = dict.has('Popup');
+    this.data.title = (0, _util.stringToPDFString)(dict.get('T') || '');
+    this.data.contents = (0, _util.stringToPDFString)(dict.get('Contents') || '');
+  }
+
+}
+
 class WidgetAnnotation extends Annotation {
   constructor(params) {
     super(params);
     let dict = params.dict;
     let data = this.data;
     data.annotationType = _util.AnnotationType.WIDGET;
     data.fieldName = this._constructFieldName(dict);
     data.fieldValue = (0, _core_utils.getInheritableProperty)({
@@ -18717,31 +18737,29 @@ class ChoiceWidgetAnnotation extends Wid
     }
 
     this.data.combo = this.hasFieldFlag(_util.AnnotationFieldFlag.COMBO);
     this.data.multiSelect = this.hasFieldFlag(_util.AnnotationFieldFlag.MULTISELECT);
   }
 
 }
 
-class TextAnnotation extends Annotation {
+class TextAnnotation extends MarkupAnnotation {
   constructor(parameters) {
     const DEFAULT_ICON_SIZE = 22;
     super(parameters);
     this.data.annotationType = _util.AnnotationType.TEXT;
 
     if (this.data.hasAppearance) {
       this.data.name = 'NoIcon';
     } else {
       this.data.rect[1] = this.data.rect[3] - DEFAULT_ICON_SIZE;
       this.data.rect[2] = this.data.rect[0] + DEFAULT_ICON_SIZE;
       this.data.name = parameters.dict.has('Name') ? parameters.dict.get('Name').name : 'Note';
     }
-
-    this._preparePopup(parameters.dict);
   }
 
 }
 
 class LinkAnnotation extends Annotation {
   constructor(params) {
     super(params);
     this.data.annotationType = _util.AnnotationType.LINK;
@@ -18786,77 +18804,85 @@ class PopupAnnotation extends Annotation
       if (this._isViewable(parentFlags)) {
         this.setFlags(parentFlags);
       }
     }
   }
 
 }
 
-class LineAnnotation extends Annotation {
+class FreeTextAnnotation extends MarkupAnnotation {
+  constructor(parameters) {
+    super(parameters);
+    this.data.annotationType = _util.AnnotationType.FREETEXT;
+  }
+
+}
+
+class LineAnnotation extends MarkupAnnotation {
   constructor(parameters) {
     super(parameters);
     this.data.annotationType = _util.AnnotationType.LINE;
     let dict = parameters.dict;
     this.data.lineCoordinates = _util.Util.normalizeRect(dict.getArray('L'));
-
-    this._preparePopup(dict);
-  }
-
-}
-
-class SquareAnnotation extends Annotation {
+  }
+
+}
+
+class SquareAnnotation extends MarkupAnnotation {
   constructor(parameters) {
     super(parameters);
     this.data.annotationType = _util.AnnotationType.SQUARE;
-
-    this._preparePopup(parameters.dict);
-  }
-
-}
-
-class CircleAnnotation extends Annotation {
+  }
+
+}
+
+class CircleAnnotation extends MarkupAnnotation {
   constructor(parameters) {
     super(parameters);
     this.data.annotationType = _util.AnnotationType.CIRCLE;
-
-    this._preparePopup(parameters.dict);
-  }
-
-}
-
-class PolylineAnnotation extends Annotation {
+  }
+
+}
+
+class PolylineAnnotation extends MarkupAnnotation {
   constructor(parameters) {
     super(parameters);
     this.data.annotationType = _util.AnnotationType.POLYLINE;
     let dict = parameters.dict;
     let rawVertices = dict.getArray('Vertices');
     this.data.vertices = [];
 
     for (let i = 0, ii = rawVertices.length; i < ii; i += 2) {
       this.data.vertices.push({
         x: rawVertices[i],
         y: rawVertices[i + 1]
       });
     }
-
-    this._preparePopup(dict);
   }
 
 }
 
 class PolygonAnnotation extends PolylineAnnotation {
   constructor(parameters) {
     super(parameters);
     this.data.annotationType = _util.AnnotationType.POLYGON;
   }
 
 }
 
-class InkAnnotation extends Annotation {
+class CaretAnnotation extends MarkupAnnotation {
+  constructor(parameters) {
+    super(parameters);
+    this.data.annotationType = _util.AnnotationType.CARET;
+  }
+
+}
+
+class InkAnnotation extends MarkupAnnotation {
   constructor(parameters) {
     super(parameters);
     this.data.annotationType = _util.AnnotationType.INK;
     let dict = parameters.dict;
     const xref = parameters.xref;
     let originalInkLists = dict.getArray('InkList');
     this.data.inkLists = [];
 
@@ -18865,80 +18891,66 @@ class InkAnnotation extends Annotation {
 
       for (let j = 0, jj = originalInkLists[i].length; j < jj; j += 2) {
         this.data.inkLists[i].push({
           x: xref.fetchIfRef(originalInkLists[i][j]),
           y: xref.fetchIfRef(originalInkLists[i][j + 1])
         });
       }
     }
-
-    this._preparePopup(dict);
-  }
-
-}
-
-class HighlightAnnotation extends Annotation {
+  }
+
+}
+
+class HighlightAnnotation extends MarkupAnnotation {
   constructor(parameters) {
     super(parameters);
     this.data.annotationType = _util.AnnotationType.HIGHLIGHT;
-
-    this._preparePopup(parameters.dict);
-  }
-
-}
-
-class UnderlineAnnotation extends Annotation {
+  }
+
+}
+
+class UnderlineAnnotation extends MarkupAnnotation {
   constructor(parameters) {
     super(parameters);
     this.data.annotationType = _util.AnnotationType.UNDERLINE;
-
-    this._preparePopup(parameters.dict);
-  }
-
-}
-
-class SquigglyAnnotation extends Annotation {
+  }
+
+}
+
+class SquigglyAnnotation extends MarkupAnnotation {
   constructor(parameters) {
     super(parameters);
     this.data.annotationType = _util.AnnotationType.SQUIGGLY;
-
-    this._preparePopup(parameters.dict);
-  }
-
-}
-
-class StrikeOutAnnotation extends Annotation {
+  }
+
+}
+
+class StrikeOutAnnotation extends MarkupAnnotation {
   constructor(parameters) {
     super(parameters);
     this.data.annotationType = _util.AnnotationType.STRIKEOUT;
-
-    this._preparePopup(parameters.dict);
-  }
-
-}
-
-class StampAnnotation extends Annotation {
+  }
+
+}
+
+class StampAnnotation extends MarkupAnnotation {
   constructor(parameters) {
     super(parameters);
     this.data.annotationType = _util.AnnotationType.STAMP;
-
-    this._preparePopup(parameters.dict);
-  }
-
-}
-
-class FileAttachmentAnnotation extends Annotation {
+  }
+
+}
+
+class FileAttachmentAnnotation extends MarkupAnnotation {
   constructor(parameters) {
     super(parameters);
     let file = new _obj.FileSpec(parameters.dict.get('FS'), parameters.xref);
     this.data.annotationType = _util.AnnotationType.FILEATTACHMENT;
     this.data.file = file.serializable;
-
-    this._preparePopup(parameters.dict);
   }
 
 }
 
 /***/ }),
 /* 27 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
--- a/browser/extensions/pdfjs/content/web/viewer.css
+++ b/browser/extensions/pdfjs/content/web/viewer.css
@@ -242,21 +242,23 @@
   margin: 0;
   padding-top: 0.2em;
 }
 
 .annotationLayer .highlightAnnotation,
 .annotationLayer .underlineAnnotation,
 .annotationLayer .squigglyAnnotation,
 .annotationLayer .strikeoutAnnotation,
+.annotationLayer .freeTextAnnotation,
 .annotationLayer .lineAnnotation svg line,
 .annotationLayer .squareAnnotation svg rect,
 .annotationLayer .circleAnnotation svg ellipse,
 .annotationLayer .polylineAnnotation svg polyline,
 .annotationLayer .polygonAnnotation svg polygon,
+.annotationLayer .caretAnnotation,
 .annotationLayer .inkAnnotation svg polyline,
 .annotationLayer .stampAnnotation,
 .annotationLayer .fileAttachmentAnnotation {
   cursor: pointer;
 }
 
 .pdfViewer .canvasWrapper {
   overflow: hidden;
--- a/browser/extensions/pdfjs/moz.yaml
+++ b/browser/extensions/pdfjs/moz.yaml
@@ -15,15 +15,15 @@ origin:
   description: Portable Document Format (PDF) viewer that is built with HTML5
 
   # Full URL for the package's homepage/etc
   # Usually different from repository url
   url: https://github.com/mozilla/pdf.js
 
   # Human-readable identifier for this version/release
   # Generally "version NNN", "tag SSS", "bookmark SSS"
-  release: version 2.2.129
+  release: version 2.2.145
 
   # The package's license, where possible using the mnemonic from
   # https://spdx.org/licenses/
   # Multiple licenses can be specified (as a YAML list)
   # A "LICENSE" file must exist containing the full license text
   license: Apache-2.0
--- a/dom/base/Document.cpp
+++ b/dom/base/Document.cpp
@@ -4430,29 +4430,21 @@ void Document::SetContainer(nsDocShell* 
 
   // IsTopLevelWindowInactive depends on the docshell, so
   // update the cached value now that it's available.
   UpdateDocumentStates(NS_DOCUMENT_STATE_WINDOW_INACTIVE);
   if (!aContainer) {
     return;
   }
 
-  // Get the Docshell
-  if (aContainer->ItemType() == nsIDocShellTreeItem::typeContent) {
-    // check if same type root
-    nsCOMPtr<nsIDocShellTreeItem> sameTypeRoot;
-    aContainer->GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot));
-    NS_ASSERTION(
-        sameTypeRoot,
-        "No document shell root tree item from document shell tree item!");
-
-    if (sameTypeRoot == aContainer) {
+  BrowsingContext* context = aContainer->GetBrowsingContext();
+  if (context && context->IsContent()) {
+    if (!context->GetParent()) {
       SetIsTopLevelContentDocument(true);
     }
-
     SetIsContentDocument(true);
   }
 
   mAncestorPrincipals = aContainer->AncestorPrincipals();
   mAncestorOuterWindowIDs = aContainer->AncestorOuterWindowIDs();
 }
 
 nsISupports* Document::GetContainer() const {
--- a/dom/indexedDB/ActorsParent.cpp
+++ b/dom/indexedDB/ActorsParent.cpp
@@ -5476,16 +5476,17 @@ class TransactionDatabaseOperationBase :
     WaitingForContinue,
     SendingResults,
     Completed
   };
 
   RefPtr<TransactionBase> mTransaction;
   const int64_t mTransactionLoggingSerialNumber;
   InternalState mInternalState;
+  bool mWaitingForContinue;
   const bool mTransactionIsAborted;
 
  public:
   void AssertIsOnConnectionThread() const
 #ifdef DEBUG
       ;
 #else
   {
@@ -5501,16 +5502,22 @@ class TransactionDatabaseOperationBase :
   void DispatchToConnectionPool();
 
   TransactionBase* Transaction() const {
     MOZ_ASSERT(mTransaction);
 
     return mTransaction;
   }
 
+  bool IsWaitingForContinue() const {
+    AssertIsOnOwningThread();
+
+    return mWaitingForContinue;
+  }
+
   void NoteContinueReceived();
 
   // May be overridden by subclasses if they need to perform work on the
   // background thread before being dispatched. Returning false will kill the
   // child actors and prevent dispatch.
   virtual bool Init(TransactionBase* aTransaction);
 
   // This callback will be called on the background thread before releasing the
@@ -21527,16 +21534,17 @@ nsresult DeleteDatabaseOp::VersionChange
 
 TransactionDatabaseOperationBase::TransactionDatabaseOperationBase(
     TransactionBase* aTransaction)
     : DatabaseOperationBase(aTransaction->GetLoggingInfo()->Id(),
                             aTransaction->GetLoggingInfo()->NextRequestSN()),
       mTransaction(aTransaction),
       mTransactionLoggingSerialNumber(aTransaction->LoggingSerialNumber()),
       mInternalState(InternalState::Initial),
+      mWaitingForContinue(false),
       mTransactionIsAborted(aTransaction->IsAborted()) {
   MOZ_ASSERT(aTransaction);
   MOZ_ASSERT(LoggingSerialNumber());
 }
 
 TransactionDatabaseOperationBase::TransactionDatabaseOperationBase(
     TransactionBase* aTransaction, uint64_t aLoggingSerialNumber)
     : DatabaseOperationBase(aTransaction->GetLoggingInfo()->Id(),
@@ -21671,16 +21679,18 @@ bool TransactionDatabaseOperationBase::H
 nsresult TransactionDatabaseOperationBase::SendPreprocessInfo() {
   return NS_OK;
 }
 
 void TransactionDatabaseOperationBase::NoteContinueReceived() {
   AssertIsOnOwningThread();
   MOZ_ASSERT(mInternalState == InternalState::WaitingForContinue);
 
+  mWaitingForContinue = false;
+
   mInternalState = InternalState::SendingResults;
 
   // This TransactionDatabaseOperationBase can only be held alive by the IPDL.
   // Run() can end up with clearing that last reference. So we need to add
   // a self reference here.
   RefPtr<TransactionDatabaseOperationBase> kungFuDeathGrip = this;
 
   Unused << this->Run();
@@ -21753,16 +21763,18 @@ void TransactionDatabaseOperationBase::S
     if (!SendFailureResult(mResultCode)) {
       // Abort the transaction.
       mTransaction->Abort(mResultCode, /* aForce */ false);
     }
   }
 
   if (aSendPreprocessInfo && NS_SUCCEEDED(mResultCode)) {
     mInternalState = InternalState::WaitingForContinue;
+
+    mWaitingForContinue = true;
   } else {
     if (mLoggingSerialNumber) {
       mTransaction->NoteFinishedRequest();
     }
 
     Cleanup();
 
     mInternalState = InternalState::Completed;
@@ -23721,16 +23733,34 @@ void NormalTransactionOp::Cleanup() {
 
   TransactionDatabaseOperationBase::Cleanup();
 }
 
 void NormalTransactionOp::ActorDestroy(ActorDestroyReason aWhy) {
   AssertIsOnOwningThread();
 
   NoteActorDestroyed();
+
+  // Assume ActorDestroy can happen at any time, so we can't probe the current
+  // state since mInternalState can be modified on any thread (only one thread
+  // at a time based on the state machine).
+  // However we can use mWaitingForContinue which is only touched on the owning
+  // thread.  If mWaitingForContinue is true, we can also modify mInternalState
+  // since we are guaranteed that there are no pending runnables which would
+  // probe mInternalState to decide what code needs to run (there shouldn't be
+  // any running runnables on other threads either).
+
+  if (IsWaitingForContinue()) {
+    NoteContinueReceived();
+  }
+
+  // We don't have to handle the case when mWaitingForContinue is not true since
+  // it means that either nothing has been initialized yet, so nothing to
+  // cleanup or there are pending runnables that will detect that the actor has
+  // been destroyed and cleanup accordingly.
 }
 
 mozilla::ipc::IPCResult NormalTransactionOp::RecvContinue(
     const PreprocessResponse& aResponse) {
   AssertIsOnOwningThread();
 
   switch (aResponse.type()) {
     case PreprocessResponse::Tnsresult:
--- a/dom/localstorage/ActorsChild.cpp
+++ b/dom/localstorage/ActorsChild.cpp
@@ -188,17 +188,17 @@ mozilla::ipc::IPCResult LSRequestChild::
 
 mozilla::ipc::IPCResult LSRequestChild::RecvReady() {
   AssertIsOnOwningThread();
 
   mFinishing = true;
 
   // We only expect this to return false if the channel has been closed, but
   // PBackground's channel never gets shutdown.
-  MOZ_ALWAYS_TRUE(SendFinish());
+  MOZ_DIAGNOSTIC_ALWAYS_TRUE(SendFinish());
 
   return IPC_OK();
 }
 
 /*******************************************************************************
  * LSSimpleRequestChild
  ******************************************************************************/
 
--- a/dom/media/webspeech/recognition/SpeechRecognition.cpp
+++ b/dom/media/webspeech/recognition/SpeechRecognition.cpp
@@ -572,16 +572,17 @@ SpeechRecognition::StopRecording() {
     // MSG, as it holds a reference to us, and we reference the world, which we
     // don't want to leak.
     mSpeechListener->mRemovedPromise->Then(
         GetCurrentThreadSerialEventTarget(), __func__,
         [blocker = std::move(mShutdownBlocker)] {
           RefPtr<nsIAsyncShutdownClient> shutdown = media::GetShutdownBarrier();
           nsresult rv = shutdown->RemoveBlocker(blocker);
           MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
+          Unused << rv;
         });
   }
   MOZ_ASSERT(!mShutdownBlocker);
 
   mStream->UnregisterTrackListener(this);
   mTrack->RemoveListener(mSpeechListener);
   mStream = nullptr;
   mSpeechListener = nullptr;
--- a/js/src/gc/FreeOp.h
+++ b/js/src/gc/FreeOp.h
@@ -24,32 +24,33 @@ namespace js {
  * convenience methods that also call destructors.
  *
  * FreeOp is passed to finalizers and other sweep-phase hooks so that we do not
  * need to pass a JSContext to those hooks.
  */
 class FreeOp : public JSFreeOp {
   Vector<void*, 0, SystemAllocPolicy> freeLaterList;
   jit::JitPoisonRangeVector jitPoisonRanges;
+  const bool isDefault;
 
  public:
   static FreeOp* get(JSFreeOp* fop) { return static_cast<FreeOp*>(fop); }
 
-  explicit FreeOp(JSRuntime* maybeRuntime);
+  explicit FreeOp(JSRuntime* maybeRuntime, bool isDefault = false);
   ~FreeOp();
 
   bool onMainThread() const { return runtime_ != nullptr; }
 
   bool maybeOnHelperThread() const {
     // Sometimes background finalization happens on the main thread so
     // runtime_ being null doesn't always mean we are off thread.
     return !runtime_;
   }
 
-  bool isDefaultFreeOp() const;
+  bool isDefaultFreeOp() const { return isDefault; }
 
   void free_(void* p) { js_free(p); }
 
   void freeLater(void* p) {
     // FreeOps other than the defaultFreeOp() are constructed on the stack,
     // and won't hold onto the pointers to free indefinitely.
     MOZ_ASSERT(!isDefaultFreeOp());
 
--- a/js/src/gc/GC.cpp
+++ b/js/src/gc/GC.cpp
@@ -3724,19 +3724,20 @@ void GCRuntime::freeFromBackgroundThread
 
     Nursery::BufferSet buffers;
     mozilla::Swap(buffers, buffersToFreeAfterMinorGC.ref());
 
     AutoUnlockHelperThreadState unlock(lock);
 
     lifoBlocks.freeAll();
 
+    FreeOp* fop = TlsContext.get()->defaultFreeOp();
     for (Nursery::BufferSet::Range r = buffers.all(); !r.empty();
          r.popFront()) {
-      rt->defaultFreeOp()->free_(r.front());
+      fop->free_(r.front());
     }
   } while (!lifoBlocksToFree.ref().isEmpty() ||
            !buffersToFreeAfterMinorGC.ref().empty());
 }
 
 void GCRuntime::waitBackgroundFreeEnd() { freeTask.join(); }
 
 /* static */
--- a/js/src/gc/Heap.h
+++ b/js/src/gc/Heap.h
@@ -2,41 +2,26 @@
  * vim: set ts=8 sts=2 et sw=2 tw=80:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef gc_Heap_h
 #define gc_Heap_h
 
-#include "mozilla/ArrayUtils.h"
 #include "mozilla/Atomics.h"
-#include "mozilla/Attributes.h"
 #include "mozilla/DebugOnly.h"
-#include "mozilla/PodOperations.h"
 
-#include <stddef.h>
-#include <stdint.h>
-
-#include "jsfriendapi.h"
-#include "jspubtd.h"
-#include "jstypes.h"
 #include "jsutil.h"
 
 #include "ds/BitArray.h"
 #include "gc/AllocKind.h"
 #include "gc/GCEnum.h"
-#include "gc/Memory.h"
-#include "js/HeapAPI.h"
-#include "js/RootingAPI.h"
-#include "js/TracingAPI.h"
 #include "js/TypeDecls.h"
 
-#include "vm/Printer.h"
-
 namespace js {
 
 class AutoLockGC;
 class AutoLockGCBgAlloc;
 class FreeOp;
 
 namespace gc {
 
--- a/js/src/jit/BaselineJIT.cpp
+++ b/js/src/jit/BaselineJIT.cpp
@@ -276,19 +276,19 @@ MethodStatus jit::CanEnterBaselineAtBran
                                            InterpreterFrame* fp) {
   if (!CheckFrame(fp)) {
     return Method_CantCompile;
   }
 
   // This check is needed in the following corner case. Consider a function h,
   //
   //   function h(x) {
-  //      h(false);
   //      if (!x)
   //        return;
+  //      h(false);
   //      for (var i = 0; i < N; i++)
   //         /* do stuff */
   //   }
   //
   // Suppose h is not yet compiled in baseline and is executing in the
   // interpreter. Let this interpreter frame be f_older. The debugger marks
   // f_older as isDebuggee. At the point of the recursive call h(false), h is
   // compiled in baseline without debug instrumentation, pushing a baseline
--- a/js/src/vm/JSContext.cpp
+++ b/js/src/vm/JSContext.cpp
@@ -1219,16 +1219,17 @@ mozilla::GenericErrorResult<JS::Error&> 
 }
 
 JSContext::JSContext(JSRuntime* runtime, const JS::ContextOptions& options)
     : runtime_(runtime),
       kind_(ContextKind::HelperThread),
       helperThread_(nullptr),
       options_(options),
       freeLists_(nullptr),
+      defaultFreeOp_(runtime, true),
       jitActivation(nullptr),
       activation_(nullptr),
       profilingActivation_(nullptr),
       nativeStackBase(GetNativeStackBase()),
       entryMonitor(nullptr),
       noExecuteDebuggerTop(nullptr),
 #ifdef DEBUG
       inUnsafeCallWithABI(false),
--- a/js/src/vm/JSContext.h
+++ b/js/src/vm/JSContext.h
@@ -7,16 +7,17 @@
 /* JS execution context. */
 
 #ifndef vm_JSContext_h
 #define vm_JSContext_h
 
 #include "mozilla/MemoryReporting.h"
 
 #include "ds/TraceableFifo.h"
+#include "gc/Memory.h"
 #include "js/CharacterEncoding.h"
 #include "js/ContextOptions.h"  // JS::ContextOptions
 #include "js/GCVector.h"
 #include "js/Promise.h"
 #include "js/Result.h"
 #include "js/Utility.h"
 #include "js/Vector.h"
 #include "threading/ProtectedData.h"
@@ -168,16 +169,18 @@ struct JSContext : public JS::RootingCon
   // This is reset each time we switch zone, then added to the variable in the
   // zone when we switch away from it.  This would be a js::ThreadData but we
   // need to take its address.
   uint32_t allocsThisZoneSinceMinorGC_;
 
   // Free lists for parallel allocation in the atoms zone on helper threads.
   js::ThreadData<js::gc::FreeLists*> atomsZoneFreeLists_;
 
+  js::ThreadData<js::FreeOp> defaultFreeOp_;
+
  public:
   // This is used by helper threads to change the runtime their context is
   // currently operating on.
   void setRuntime(JSRuntime* rt);
 
   bool isMainThreadContext() const {
     return kind_ == js::ContextKind::MainThread;
   }
@@ -263,17 +266,17 @@ struct JSContext : public JS::RootingCon
   bool permanentAtomsPopulated() { return runtime_->permanentAtomsPopulated(); }
   const js::FrozenAtomSet& permanentAtoms() {
     return *runtime_->permanentAtoms();
   }
   js::WellKnownSymbols& wellKnownSymbols() {
     return *runtime_->wellKnownSymbols;
   }
   js::PropertyName* emptyString() { return runtime_->emptyString; }
-  js::FreeOp* defaultFreeOp() { return runtime_->defaultFreeOp(); }
+  js::FreeOp* defaultFreeOp() { return &defaultFreeOp_.ref(); }
   void* stackLimitAddress(JS::StackKind kind) {
     return &nativeStackLimit[kind];
   }
   void* stackLimitAddressForJitCode(JS::StackKind kind);
   uintptr_t stackLimit(JS::StackKind kind) { return nativeStackLimit[kind]; }
   uintptr_t stackLimitForJitCode(JS::StackKind kind);
   size_t gcSystemPageSize() { return js::gc::SystemPageSize(); }
   bool jitSupportsFloatingPoint() const {
--- a/js/src/vm/Runtime.cpp
+++ b/js/src/vm/Runtime.cpp
@@ -196,20 +196,17 @@ bool JSRuntime::init(JSContext* cx, uint
 #endif
 
   if (CanUseExtraThreads() && !EnsureHelperThreadsInitialized()) {
     return false;
   }
 
   mainContext_ = cx;
 
-  defaultFreeOp_ = js_new<js::FreeOp>(this);
-  if (!defaultFreeOp_) {
-    return false;
-  }
+  defaultFreeOp_ = cx->defaultFreeOp();
 
   if (!gc.init(maxbytes, maxNurseryBytes)) {
     return false;
   }
 
   UniquePtr<Zone> atomsZone = MakeUnique<Zone>(this);
   if (!atomsZone || !atomsZone->init(true)) {
     return false;
@@ -298,18 +295,16 @@ void JSRuntime::destroyRuntime() {
   FreeScriptData(this);
 
 #if !EXPOSE_INTL_API
   FinishRuntimeNumberState(this);
 #endif
 
   gc.finish();
 
-  js_delete(defaultFreeOp_.ref());
-
   defaultLocale = nullptr;
   js_delete(jitRuntime_.ref());
 
 #ifdef DEBUG
   initialized_ = false;
 #endif
 }
 
@@ -568,34 +563,31 @@ const char* JSRuntime::getDefaultLocale(
   defaultLocale.ref() = std::move(lang);
   return defaultLocale.ref().get();
 }
 
 void JSRuntime::traceSharedIntlData(JSTracer* trc) {
   sharedIntlData.ref().trace(trc);
 }
 
-FreeOp::FreeOp(JSRuntime* maybeRuntime) : JSFreeOp(maybeRuntime) {
+FreeOp::FreeOp(JSRuntime* maybeRuntime, bool isDefault)
+    : JSFreeOp(maybeRuntime), isDefault(isDefault) {
   MOZ_ASSERT_IF(maybeRuntime, CurrentThreadCanAccessRuntime(maybeRuntime));
 }
 
 FreeOp::~FreeOp() {
   for (size_t i = 0; i < freeLaterList.length(); i++) {
     free_(freeLaterList[i]);
   }
 
   if (!jitPoisonRanges.empty()) {
     jit::ExecutableAllocator::poisonCode(runtime(), jitPoisonRanges);
   }
 }
 
-bool FreeOp::isDefaultFreeOp() const {
-  return runtime_ && runtime_->defaultFreeOp() == this;
-}
-
 GlobalObject* JSRuntime::getIncumbentGlobal(JSContext* cx) {
   MOZ_ASSERT(cx->jobQueue);
 
   JSObject* obj = cx->jobQueue->getIncumbentGlobal(cx);
   if (!obj) {
     return nullptr;
   }
 
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -639,17 +639,17 @@ struct JSRuntime : public js::MallocProv
   /* Well-known numbers. */
   const js::Value NaNValue;
   const js::Value negativeInfinityValue;
   const js::Value positiveInfinityValue;
 
   js::WriteOnceData<js::PropertyName*> emptyString;
 
  private:
-  js::WriteOnceData<js::FreeOp*> defaultFreeOp_;
+  js::MainThreadData<js::FreeOp*> defaultFreeOp_;
 
  public:
   js::FreeOp* defaultFreeOp() {
     MOZ_ASSERT(defaultFreeOp_);
     return defaultFreeOp_;
   }
 
 #if !EXPOSE_INTL_API
--- a/js/src/vm/SharedArrayObject.h
+++ b/js/src/vm/SharedArrayObject.h
@@ -8,16 +8,17 @@
 #define vm_SharedArrayObject_h
 
 #include "mozilla/Atomics.h"
 
 #include "jsapi.h"
 #include "jstypes.h"
 
 #include "gc/Barrier.h"
+#include "gc/Memory.h"
 #include "vm/ArrayBufferObject.h"
 #include "vm/JSObject.h"
 
 namespace js {
 
 class FutexWaiter;
 
 /*
--- a/layout/style/nsLayoutStylesheetCache.cpp
+++ b/layout/style/nsLayoutStylesheetCache.cpp
@@ -25,16 +25,85 @@
 #include "nsNetUtil.h"
 #include "nsPresContext.h"
 #include "nsPrintfCString.h"
 #include "nsServiceManagerUtils.h"
 #include "nsXULAppAPI.h"
 
 #include <mozilla/ServoBindings.h>
 
+// The nsLayoutStylesheetCache is responsible for sharing user agent style sheet
+// contents across processes using shared memory.  Here is a high level view of
+// how that works:
+//
+// * In the parent process, in the nsLayoutStylesheetCache constructor (which is
+//   called early on in a process' lifetime), we parse all UA style sheets into
+//   Gecko StyleSheet objects.
+//
+// * The constructor calls InitSharedSheetsInParent, which creates a shared
+//   memory segment that we know ahead of time will be big enough to store the
+//   UA sheets.
+//
+// * It then creates a Rust SharedMemoryBuilder object and passes it a pointer
+//   to the start of the shared memory.
+//
+// * For each UA sheet, we call Servo_SharedMemoryBuilder_AddStylesheet, which
+//   takes the StylesheetContents::rules (an Arc<Locked<CssRules>>), produces a
+//   deep clone of it, and writes that clone into the shared memory:
+//
+//   * The deep clone isn't a clone() call, but a call to ToShmem::to_shmem. The
+//     ToShmem trait must be implemented on every type that is reachable under
+//     the Arc<Locked<CssRules>>. The to_shmem call for each type will clone the
+//     value, but any heap allocation will be cloned and placed into the shared
+//     memory buffer, rather than heap allocated.
+//
+//   * For most types, the ToShmem implementation is simple, and we just
+//     #[derive(ToShmem)] it. For the types that need special handling due to
+//     having heap allocations (Vec<T>, Box<T>, Arc<T>, etc.) we have impls that
+//     call to_shmem on the heap allocated data, and then create a new container
+//     (e.g. using Box::from_raw) that points into the shared memory.
+//
+//   * Arc<T> and Locked<T> want to perform atomic writes on data that needs to
+//     be in the shared memory buffer (the reference count for Arc<T>, and the
+//     SharedRwLock's AtomicRefCell for Locked<T>), so we add special modes to
+//     those objects that skip the writes.  For Arc<T>, that means never
+//     dropping the object since we don't track the reference count.  That's
+//     fine, since we want to just drop the entire shared memory buffer at
+//     shutdown.  For Locked<T>, we just panic on attempting to take the lock
+//     for writing.  That's also fine, since we don't want devtools being able
+//     to modify UA sheets.
+//
+//   * For Atoms in Rust, static atoms are represented by an index into the
+//     static atom table.  Then if we need to Deref the Atom we look up the
+//     table.  We panic if any Atom we encounter in the UA style sheets is
+//     not a static atom.
+//
+// * For each UA sheet, we create a new C++ StyleSheet object using the shared
+//   memory clone of the sheet contents, and throw away the original heap
+//   allocated one.  (We could avoid creating a new C++ StyleSheet object
+//   wrapping the shared contents, and update the original StyleSheet object's
+//   contents, but it's doubtful that matters.)
+//
+// * When we initially map the shared memory in the parent process in
+//   InitSharedSheetsInParent, we choose an address which is far away from the
+//   current extent of the heap.  Although not too far, since we don't want to
+//   unnecessarily fragment the virtual address space.
+//
+// * In the child process, as early as possible (in
+//   ContentChild::InitSharedUASheets), we try to map the shared memory at that
+//   same address, then pass the shared memory buffer to
+//   nsLayoutStylesheetCache::SetSharedMemory.  Since we map at the same
+//   address, this means any internal pointers in the UA sheets back into the
+//   shared memory buffer that were written by the parent process are valid in
+//   the child process too.
+//
+// * In practice, mapping at the address we need in the child process this works
+//   nearly all the time.  If we fail to map at the address we need, the child
+//   process falls back to parsing and allocating its own copy of the UA sheets.
+
 using namespace mozilla;
 using namespace mozilla::css;
 
 NS_IMPL_ISUPPORTS(nsLayoutStylesheetCache, nsIObserver, nsIMemoryReporter)
 
 nsresult nsLayoutStylesheetCache::Observe(nsISupports* aSubject,
                                           const char* aTopic,
                                           const char16_t* aData) {
--- a/parser/html/javasrc/Tokenizer.java
+++ b/parser/html/javasrc/Tokenizer.java
@@ -2815,20 +2815,22 @@ public class Tokenizer implements Locato
                                 appendStrBuf(c);
                                 /*
                                  * Switch to the comment end dash state.
                                  */
                                 state = transition(state, Tokenizer.COMMENT_END_DASH, reconsume, pos);
                                 continue stateloop;
                             case '\r':
                                 appendStrBufCarriageReturn();
+                                state = transition(state, Tokenizer.COMMENT, reconsume, pos);
                                 break stateloop;
                             case '\n':
                                 appendStrBufLineFeed();
-                                continue;
+                                state = transition(state, Tokenizer.COMMENT, reconsume, pos);
+                                continue stateloop;
                             case '\u0000':
                                 c = '\uFFFD';
                                 // CPPONLY: MOZ_FALLTHROUGH;
                             default:
                                 /*
                                  * Anything else Append two U+002D HYPHEN-MINUS
                                  * (-) characters, a U+0021 EXCLAMATION MARK (!)
                                  * character, and the input character to the
--- a/parser/html/javasrc/TreeBuilder.java
+++ b/parser/html/javasrc/TreeBuilder.java
@@ -1723,17 +1723,17 @@ public abstract class TreeBuilder<T> imp
                         case TABLE:
                         case FONT:
                             // re-check FONT to deal with the special case
                             if (!(group == FONT && !(attributes.contains(AttributeName.COLOR)
                                     || attributes.contains(AttributeName.FACE) || attributes.contains(AttributeName.SIZE)))) {
                                 errHtmlStartTagInForeignContext(name);
                                 if (!fragment) {
                                     while (!isSpecialParentInForeign(stack[currentPtr])) {
-                                        pop();
+                                        popForeign(-1, -1);
                                     }
                                     continue starttagloop;
                                 } // else fall thru
                             }
                             // CPPONLY: MOZ_FALLTHROUGH;
                         default:
                             if ("http://www.w3.org/2000/svg" == currNs) {
                                 attributes.adjustForSvg();
@@ -5226,17 +5226,17 @@ public abstract class TreeBuilder<T> imp
         elementPopped(node.ns, node.popName, node.node);
         node.release(this);
     }
 
     private void popForeign(int origPos, int eltPos) throws SAXException {
         StackNode<T> node = stack[currentPtr];
         if (origPos != currentPtr || eltPos != currentPtr) {
             markMalformedIfScript(node.node);
-            }
+        }
         assert debugOnlyClearLastStackSlot();
         currentPtr--;
         elementPopped(node.ns, node.popName, node.node);
         node.release(this);
     }
 
     private void silentPop() throws SAXException {
         StackNode<T> node = stack[currentPtr];
--- a/parser/html/nsHtml5Tokenizer.cpp
+++ b/parser/html/nsHtml5Tokenizer.cpp
@@ -1433,21 +1433,25 @@ stateloop:
               appendStrBuf(c);
               state =
                   P::transition(mViewSource, nsHtml5Tokenizer::COMMENT_END_DASH,
                                 reconsume, pos);
               NS_HTML5_CONTINUE(stateloop);
             }
             case '\r': {
               appendStrBufCarriageReturn();
+              state = P::transition(mViewSource, nsHtml5Tokenizer::COMMENT,
+                                    reconsume, pos);
               NS_HTML5_BREAK(stateloop);
             }
             case '\n': {
               appendStrBufLineFeed();
-              continue;
+              state = P::transition(mViewSource, nsHtml5Tokenizer::COMMENT,
+                                    reconsume, pos);
+              NS_HTML5_CONTINUE(stateloop);
             }
             case '\0': {
               c = 0xfffd;
               MOZ_FALLTHROUGH;
             }
             default: {
               appendStrBuf(c);
               state = P::transition(mViewSource, nsHtml5Tokenizer::COMMENT,
--- a/parser/html/nsHtml5TreeBuilder.cpp
+++ b/parser/html/nsHtml5TreeBuilder.cpp
@@ -728,17 +728,17 @@ starttagloop:
           case FONT: {
             if (!(group == FONT &&
                   !(attributes->contains(nsHtml5AttributeName::ATTR_COLOR) ||
                     attributes->contains(nsHtml5AttributeName::ATTR_FACE) ||
                     attributes->contains(nsHtml5AttributeName::ATTR_SIZE)))) {
               errHtmlStartTagInForeignContext(name);
               if (!fragment) {
                 while (!isSpecialParentInForeign(stack[currentPtr])) {
-                  pop();
+                  popForeign(-1, -1);
                 }
                 NS_HTML5_CONTINUE(starttagloop);
               }
             }
             MOZ_FALLTHROUGH;
           }
           default: {
             if (kNameSpaceID_SVG == currNs) {
--- a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/comments01.dat
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/comments01.dat
@@ -19,16 +19,44 @@ FOO<!-- BAR --!>BAZ
 | <html>
 |   <head>
 |   <body>
 |     "FOO"
 |     <!--  BAR  -->
 |     "BAZ"
 
 #data
+FOO<!-- BAR --! >BAZ
+#errors
+(1,3): expected-doctype-but-got-chars
+#new-errors
+(1:20) eof-in-comment
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <!--  BAR --! >BAZ -->
+
+#data
+FOO<!-- BAR --!
+>BAZ
+#errors
+(1,3): expected-doctype-but-got-chars
+#new-errors
+(1:20) eof-in-comment
+#document
+| <html>
+|   <head>
+|   <body>
+|     "FOO"
+|     <!--  BAR --!
+>BAZ -->
+
+#data
 FOO<!-- BAR --   >BAZ
 #errors
 (1,3): expected-doctype-but-got-chars
 (1,15): unexpected-char-in-comment
 (1,21): eof-in-comment
 #document
 | <html>
 |   <head>
--- a/testing/web-platform/tests/html/syntax/parsing/unclosed-svg-script.html
+++ b/testing/web-platform/tests/html/syntax/parsing/unclosed-svg-script.html
@@ -2,29 +2,37 @@
 <meta charset=utf-8>
 <title></title>
 <script src=/resources/testharness.js></script>
 <script src=/resources/testharnessreport.js></script>
 <script>
     var scriptWithEndTagRan = false;
     var scriptWithoutEndTagRan = false;
     var scriptWithBogusEndTagInsideRan = false;
+    var scriptWithBreakout = false;
 </script>
 <svg>
     <script>scriptWithEndTagRan = true;</script>
 </svg>
 <svg>
     <script>scriptWithoutEndTagRan = true;
 </svg>
 <svg>
     <script>scriptWithBogusEndTagInsideRan = true;</g></script>
 </svg>
+<svg>
+    <script>scriptWithBreakout = true;<s></script>
+</svg>
+</s>
 <script>
     test(function() {
         assert_true(scriptWithEndTagRan);
     }, "SVG scripts with end tag should run");
     test(function() {
         assert_false(scriptWithoutEndTagRan);
     }, "SVG scripts without end tag should not run");
     test(function() {
         assert_true(scriptWithBogusEndTagInsideRan);
     }, "SVG scripts with bogus end tag inside should run");
+    test(function() {
+        assert_false(scriptWithBreakout);
+    }, "SVG scripts ended by HTML breakout should not run");
 </script>