Merge inbound to m-c. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Fri, 15 Aug 2014 16:10:19 -0400
changeset 199822 95bed435b123b960da22675cb43e59e83f6a6ba9
parent 199821 668ade60cde96bae2334699dbd724af9e0557cd9 (current diff)
parent 199805 e8d9ec641ec6b0d2d0ce34e22beccc82d851b322 (diff)
child 199856 b9da9928d0610a60e7f0158b8536d44ab4b108b8
push id47750
push userryanvm@gmail.com
push dateFri, 15 Aug 2014 21:04:12 +0000
treeherdermozilla-inbound@baea646f5a80 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone34.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to m-c. a=merge
build/link.py
content/media/fmp4/eme/EMEAACDecoder.cpp
content/media/fmp4/eme/EMEAACDecoder.h
content/media/fmp4/ffmpeg/FFmpegAACDecoder.cpp
content/media/fmp4/ffmpeg/FFmpegAACDecoder.h
editor/composer/res/caret_left.svg
editor/composer/res/caret_middle.svg
editor/composer/res/caret_right.svg
editor/libeditor/base/ChangeAttributeTxn.cpp
editor/libeditor/base/ChangeAttributeTxn.h
editor/libeditor/base/ChangeCSSInlineStyleTxn.cpp
editor/libeditor/base/ChangeCSSInlineStyleTxn.h
editor/libeditor/base/CreateElementTxn.cpp
editor/libeditor/base/CreateElementTxn.h
editor/libeditor/base/DeleteNodeTxn.cpp
editor/libeditor/base/DeleteNodeTxn.h
editor/libeditor/base/DeleteRangeTxn.cpp
editor/libeditor/base/DeleteRangeTxn.h
editor/libeditor/base/DeleteTextTxn.cpp
editor/libeditor/base/DeleteTextTxn.h
editor/libeditor/base/EditActionListener.h
editor/libeditor/base/EditAggregateTxn.cpp
editor/libeditor/base/EditAggregateTxn.h
editor/libeditor/base/EditTxn.cpp
editor/libeditor/base/EditTxn.h
editor/libeditor/base/IMETextTxn.cpp
editor/libeditor/base/IMETextTxn.h
editor/libeditor/base/InsertElementTxn.cpp
editor/libeditor/base/InsertElementTxn.h
editor/libeditor/base/InsertTextTxn.cpp
editor/libeditor/base/InsertTextTxn.h
editor/libeditor/base/JoinElementTxn.cpp
editor/libeditor/base/JoinElementTxn.h
editor/libeditor/base/PlaceholderTxn.cpp
editor/libeditor/base/PlaceholderTxn.h
editor/libeditor/base/SetDocTitleTxn.cpp
editor/libeditor/base/SetDocTitleTxn.h
editor/libeditor/base/SplitElementTxn.cpp
editor/libeditor/base/SplitElementTxn.h
editor/libeditor/base/crashtests/336104.html
editor/libeditor/base/crashtests/382527-1.html
editor/libeditor/base/crashtests/402172-1.html
editor/libeditor/base/crashtests/407079-1.html
editor/libeditor/base/crashtests/407256-1.html
editor/libeditor/base/crashtests/430624-1.html
editor/libeditor/base/crashtests/459613-iframe.html
editor/libeditor/base/crashtests/459613.html
editor/libeditor/base/crashtests/475132-1.xhtml
editor/libeditor/base/crashtests/633709.xhtml
editor/libeditor/base/crashtests/636074-1.html
editor/libeditor/base/crashtests/713427-1.html
editor/libeditor/base/crashtests/713427-2.xhtml
editor/libeditor/base/crashtests/762183.html
editor/libeditor/base/crashtests/766360.html
editor/libeditor/base/crashtests/766413.html
editor/libeditor/base/crashtests/766845.xhtml
editor/libeditor/base/crashtests/768765.html
editor/libeditor/base/crashtests/771749.html
editor/libeditor/base/crashtests/772282.html
editor/libeditor/base/crashtests/776323.html
editor/libeditor/base/crashtests/crashtests.list
editor/libeditor/base/moz.build
editor/libeditor/base/nsEditProperty.h
editor/libeditor/base/nsEditPropertyAtomList.h
editor/libeditor/base/nsEditRules.h
editor/libeditor/base/nsEditor.cpp
editor/libeditor/base/nsEditor.h
editor/libeditor/base/nsEditorCommands.cpp
editor/libeditor/base/nsEditorCommands.h
editor/libeditor/base/nsEditorController.cpp
editor/libeditor/base/nsEditorController.h
editor/libeditor/base/nsEditorEventListener.cpp
editor/libeditor/base/nsEditorEventListener.h
editor/libeditor/base/nsEditorUtils.cpp
editor/libeditor/base/nsEditorUtils.h
editor/libeditor/base/nsIAbsorbingTransaction.h
editor/libeditor/base/nsSelectionState.cpp
editor/libeditor/base/nsSelectionState.h
editor/libeditor/base/nsStyleSheetTxns.cpp
editor/libeditor/base/nsStyleSheetTxns.h
editor/libeditor/base/tests/chrome.ini
editor/libeditor/base/tests/file_bug586662.html
editor/libeditor/base/tests/mochitest.ini
editor/libeditor/base/tests/moz.build
editor/libeditor/base/tests/test_bug408231.html
editor/libeditor/base/tests/test_bug46555.html
editor/libeditor/base/tests/test_bug502673.html
editor/libeditor/base/tests/test_bug514156.html
editor/libeditor/base/tests/test_bug567213.html
editor/libeditor/base/tests/test_bug586662.html
editor/libeditor/base/tests/test_bug599983.html
editor/libeditor/base/tests/test_bug599983.xul
editor/libeditor/base/tests/test_bug646194.xul
editor/libeditor/base/tests/test_bug742261.html
editor/libeditor/base/tests/test_bug773262.html
editor/libeditor/base/tests/test_bug795785.html
editor/libeditor/base/tests/test_composition_event_created_in_chrome.html
editor/libeditor/base/tests/test_dragdrop.html
editor/libeditor/base/tests/test_selection_move_commands.xul
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -652,19 +652,16 @@
 ; Services (gre) prefs
 #ifdef MOZ_SERVICES_SYNC
 @BINPATH@/defaults/pref/services-sync.js
 #endif
 
 ; [Layout Engine Resources]
 ; Style Sheets, Graphics and other Resources used by the layout engine.
 @BINPATH@/res/EditorOverride.css
-@BINPATH@/res/caret_left.svg
-@BINPATH@/res/caret_middle.svg
-@BINPATH@/res/caret_right.svg
 @BINPATH@/res/contenteditable.css
 @BINPATH@/res/designmode.css
 @BINPATH@/res/ImageDocument.css
 @BINPATH@/res/TopLevelImageDocument.css
 @BINPATH@/res/TopLevelVideoDocument.css
 @BINPATH@/res/table-add-column-after-active.gif
 @BINPATH@/res/table-add-column-after-hover.gif
 @BINPATH@/res/table-add-column-after.gif
@@ -678,16 +675,31 @@
 @BINPATH@/res/table-add-row-before-hover.gif
 @BINPATH@/res/table-add-row-before.gif
 @BINPATH@/res/table-remove-column-active.gif
 @BINPATH@/res/table-remove-column-hover.gif
 @BINPATH@/res/table-remove-column.gif
 @BINPATH@/res/table-remove-row-active.gif
 @BINPATH@/res/table-remove-row-hover.gif
 @BINPATH@/res/table-remove-row.gif
+@BINPATH@/res/text_caret.png
+@BINPATH@/res/text_caret@1.5x.png
+@BINPATH@/res/text_caret@2.25x.png
+@BINPATH@/res/text_caret@2x.png
+@BINPATH@/res/text_caret_tilt_left.png
+@BINPATH@/res/text_caret_tilt_left@1.5x.png
+@BINPATH@/res/text_caret_tilt_left@2.25x.png
+@BINPATH@/res/text_caret_tilt_left@2x.png
+@BINPATH@/res/text_caret_tilt_right.png
+@BINPATH@/res/text_caret_tilt_right@1.5x.png
+@BINPATH@/res/text_caret_tilt_right@2.25x.png
+@BINPATH@/res/text_caret_tilt_right@2x.png
+@BINPATH@/res/text_selection_handle.png
+@BINPATH@/res/text_selection_handle@1.5.png
+@BINPATH@/res/text_selection_handle@2.png
 @BINPATH@/res/grabber.gif
 #ifdef XP_MACOSX
 @BINPATH@/res/cursors/*
 #endif
 @BINPATH@/res/fonts/*
 @BINPATH@/res/dtd/*
 @BINPATH@/res/html/*
 @BINPATH@/res/langGroups.properties
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -25,17 +25,16 @@ XPCOMUtils.defineLazyModuleGetter(this, 
                                   "resource://gre/modules/GMPInstallManager.jsm");
 XPCOMUtils.defineLazyServiceGetter(this, "gDNSService",
                                    "@mozilla.org/network/dns-service;1",
                                    "nsIDNSService");
 
 const nsIWebNavigation = Ci.nsIWebNavigation;
 
 var gLastBrowserCharset = null;
-var gPrevCharset = null;
 var gProxyFavIcon = null;
 var gLastValidURLStr = "";
 var gInPrintPreviewMode = false;
 var gContextMenu = null; // nsContextMenu instance
 var gMultiProcessBrowser = false;
 
 #ifndef XP_MACOSX
 var gEditUIVisible = true;
@@ -237,17 +236,16 @@ XPCOMUtils.defineLazyGetter(this, "PageM
   return new tmp.PageMenu();
 });
 
 /**
 * We can avoid adding multiple load event listeners and save some time by adding
 * one listener that calls all real handlers.
 */
 function pageShowEventHandlers(persisted) {
-  charsetLoadListener();
   XULBrowserWindow.asyncUpdateUI();
 
   // The PluginClickToPlay events are not fired when navigating using the
   // BF cache. |persisted| is true when the page is loaded from the
   // BF cache, so this code reshows the notification if necessary.
   if (persisted)
     gPluginHandler.reshowClickToPlayNotification();
 }
@@ -2583,17 +2581,17 @@ let BrowserOnClick = {
     }
 
     let anchorTarget = event.originalTarget.parentNode;
 
     if (anchorTarget instanceof HTMLAnchorElement &&
         anchorTarget.classList.contains("newtab-link")) {
       event.preventDefault();
       let where = whereToOpenLink(event, false, false);
-      openUILinkIn(anchorTarget.href, where);
+      openLinkIn(anchorTarget.href, where, { charset: ownerDoc.characterSet });
     }
   },
 
   /**
    * The about:tabcrashed can't do window.reload() because that
    * would reload the page but not use a remote browser.
    */
   onAboutTabCrashed: function(event, ownerDoc) {
@@ -3506,19 +3504,17 @@ function updateEditUIVisibility()
  * To be called when the View menu or the app menu is opened.
  */
 function updateCharacterEncodingMenuState()
 {
   let charsetMenu = document.getElementById("charsetMenu");
   // gBrowser is null on Mac when the menubar shows in the context of
   // non-browser windows. The above elements may be null depending on
   // what parts of the menubar are present. E.g. no app menu on Mac.
-  if (gBrowser &&
-      gBrowser.docShell &&
-      gBrowser.docShell.mayEnableCharacterEncodingMenu) {
+  if (gBrowser && gBrowser.selectedBrowser.mayEnableCharacterEncodingMenu) {
     if (charsetMenu) {
       charsetMenu.removeAttribute("disabled");
     }
   } else {
     if (charsetMenu) {
       charsetMenu.setAttribute("disabled", "true");
     }
   }
@@ -5353,59 +5349,34 @@ function handleDroppedLink(event, url, n
   // Keep the event from being handled by the dragDrop listeners
   // built-in to gecko if they happen to be above us.
   event.preventDefault();
 };
 
 function BrowserSetForcedCharacterSet(aCharset)
 {
   if (aCharset) {
-    gBrowser.docShell.gatherCharsetMenuTelemetry();
-    gBrowser.docShell.charset = aCharset;
+    gBrowser.selectedBrowser.characterSet = aCharset;
     // Save the forced character-set
     if (!PrivateBrowsingUtils.isWindowPrivate(window))
       PlacesUtils.setCharsetForURI(getWebNavigation().currentURI, aCharset);
   }
   BrowserCharsetReload();
 }
 
 function BrowserCharsetReload()
 {
   BrowserReloadWithFlags(nsIWebNavigation.LOAD_FLAGS_CHARSET_CHANGE);
 }
 
-function charsetMenuGetElement(parent, charset) {
-  return parent.getElementsByAttribute("charset", charset)[0];
-}
-
 function UpdateCurrentCharset(target) {
-    // extract the charset from DOM
-    var wnd = document.commandDispatcher.focusedWindow;
-    if ((window == wnd) || (wnd == null)) wnd = window.content;
-
-    // Uncheck previous item
-    if (gPrevCharset) {
-        var pref_item = charsetMenuGetElement(target, gPrevCharset);
-        if (pref_item)
-          pref_item.setAttribute('checked', 'false');
-    }
-
-    var menuitem = charsetMenuGetElement(target, CharsetMenu.foldCharset(wnd.document.characterSet));
-    if (menuitem) {
-        menuitem.setAttribute('checked', 'true');
-    }
-}
-
-function charsetLoadListener() {
-  let currCharset = gBrowser.selectedBrowser.characterSet;
-  let charset = CharsetMenu.foldCharset(currCharset);
-
-  if (charset.length > 0 && (charset != gLastBrowserCharset)) {
-    gPrevCharset = gLastBrowserCharset;
-    gLastBrowserCharset = charset;
+  for (let menuItem of target.getElementsByTagName("menuitem")) {
+    let isSelected = menuItem.getAttribute("charset") ===
+                     CharsetMenu.foldCharset(gBrowser.selectedBrowser.characterSet);
+    menuItem.setAttribute("checked", isSelected);
   }
 }
 
 var gPageStyleMenu = {
 
   // This maps from a <browser> element (or, more specifically, a
   // browser's permanentKey) to a CPOW that gives synchronous access
   // to the list of style sheets in a content window. The use of the
--- a/browser/components/customizableui/CustomizableWidgets.jsm
+++ b/browser/components/customizableui/CustomizableWidgets.jsm
@@ -730,18 +730,17 @@ const CustomizableWidgets = [{
     id: "characterencoding-button",
     type: "view",
     viewId: "PanelUI-characterEncodingView",
     tooltiptext: "characterencoding-button.tooltiptext2",
     defaultArea: CustomizableUI.AREA_PANEL,
     maybeDisableMenu: function(aDocument) {
       let window = aDocument.defaultView;
       return !(window.gBrowser &&
-               window.gBrowser.docShell &&
-               window.gBrowser.docShell.mayEnableCharacterEncodingMenu);
+               window.gBrowser.selectedBrowser.mayEnableCharacterEncodingMenu);
     },
     populateList: function(aDocument, aContainerId, aSection) {
       let containerElem = aDocument.getElementById(aContainerId);
 
       containerElem.addEventListener("command", this.onCommand, false);
 
       let list = this.charsetInfo[aSection];
 
@@ -751,18 +750,17 @@ const CustomizableWidgets = [{
         elem.setAttribute("type", "checkbox");
         elem.section = aSection;
         elem.value = item.value;
         elem.setAttribute("class", "subviewbutton");
         containerElem.appendChild(elem);
       }
     },
     updateCurrentCharset: function(aDocument) {
-      let content = aDocument.defaultView.content;
-      let currentCharset = content && content.document && content.document.characterSet;
+      let currentCharset = aDocument.defaultView.gBrowser.selectedBrowser.characterSet;
       currentCharset = CharsetMenu.foldCharset(currentCharset);
 
       let pinnedContainer = aDocument.getElementById("PanelUI-characterEncodingView-pinned");
       let charsetContainer = aDocument.getElementById("PanelUI-characterEncodingView-charsets");
       let elements = [...(pinnedContainer.childNodes), ...(charsetContainer.childNodes)];
 
       this._updateElements(elements, currentCharset);
     },
--- a/browser/experiments/Experiments.jsm
+++ b/browser/experiments/Experiments.jsm
@@ -59,16 +59,18 @@ const PREF_FORCE_SAMPLE         = "force
 const PREF_HEALTHREPORT_ENABLED = "datareporting.healthreport.service.enabled";
 
 const PREF_BRANCH_TELEMETRY     = "toolkit.telemetry.";
 const PREF_TELEMETRY_ENABLED    = "enabled";
 
 const URI_EXTENSION_STRINGS     = "chrome://mozapps/locale/extensions/extensions.properties";
 const STRING_TYPE_NAME          = "type.%ID%.name";
 
+const CACHE_WRITE_RETRY_DELAY_SEC = 60 * 3;
+
 const TELEMETRY_LOG = {
   // log(key, [kind, experimentId, details])
   ACTIVATION_KEY: "EXPERIMENT_ACTIVATION",
   ACTIVATION: {
     // Successfully activated.
     ACTIVATED: "ACTIVATED",
     // Failed to install the add-on.
     INSTALL_FAILURE: "INSTALL_FAILURE",
@@ -326,20 +328,29 @@ Experiments.Policy.prototype = {
 
 function AlreadyShutdownError(message="already shut down") {
   Error.call(this, message);
   let error = new Error();
   this.name = "AlreadyShutdownError";
   this.message = message;
   this.stack = error.stack;
 }
-
 AlreadyShutdownError.prototype = Object.create(Error.prototype);
 AlreadyShutdownError.prototype.constructor = AlreadyShutdownError;
 
+function CacheWriteError(message="Error writing cache file") {
+  Error.call(this, message);
+  let error = new Error();
+  this.name = "CacheWriteError";
+  this.message = message;
+  this.stack = error.stack;
+}
+CacheWriteError.prototype = Object.create(Error.prototype);
+CacheWriteError.prototype.constructor = CacheWriteError;
+
 /**
  * Manages the experiments and provides an interface to control them.
  */
 
 Experiments.Experiments = function (policy=new Experiments.Policy()) {
   let log = Log.repository.getLoggerWithMessagePrefix(
       "Browser.Experiments.Experiments",
       "Experiments #" + gExperimentsCounter++ + "::");
@@ -685,16 +696,17 @@ Experiments.Experiments.prototype = {
    */
   setExperimentBranch: Task.async(function*(id, branchstr) {
     yield this._loadTask;
     let e = this._experiments.get(id);
     if (!e) {
       throw new Error("Experiment not found");
     }
     e.branch = String(branchstr);
+    this._log.trace("setExperimentBranch(" + id + ", " + e.branch + ") _dirty=" + this._dirty);
     this._dirty = true;
     Services.obs.notifyObservers(null, EXPERIMENTS_CHANGED_TOPIC, null);
     yield this._run();
   }),
   /**
    * Get the branch of the specified experiment. If the experiment is unknown,
    * throws an error.
    *
@@ -761,16 +773,18 @@ Experiments.Experiments.prototype = {
 
   _run: function() {
     this._log.trace("_run");
     this._checkForShutdown();
     if (!this._mainTask) {
       this._mainTask = Task.spawn(function*() {
         try {
           yield this._main();
+	} catch (e if e instanceof CacheWriteError) {
+	  // In this case we want to reschedule
         } catch (e) {
           this._log.error("_main caught error: " + e);
           return;
         } finally {
           this._mainTask = null;
         }
         this._log.trace("_main finished, scheduling next run");
         try {
@@ -796,17 +810,17 @@ Experiments.Experiments.prototype = {
       }
       yield this._evaluateExperiments();
       if (this._dirty) {
         yield this._saveToCache();
       }
       // If somebody called .updateManifest() or disableExperiment()
       // while we were running, go again right now.
     }
-    while (this._refresh || this._terminateReason);
+    while (this._refresh || this._terminateReason || this._dirty);
   },
 
   _loadManifest: function*() {
     this._log.trace("_loadManifest");
     let uri = Services.urlFormatter.formatURLPref(PREF_BRANCH + PREF_MANIFEST_URI);
 
     this._checkForShutdown();
 
@@ -987,17 +1001,17 @@ Experiments.Experiments.prototype = {
       let encoder = new TextEncoder();
       let data = encoder.encode(textData);
       let options = { tmpPath: path + ".tmp", compression: "lz4" };
       yield OS.File.writeAtomic(path, data, options);
     } catch (e) {
       // We failed to write the cache, it's still dirty.
       this._dirty = true;
       this._log.error("_saveToCache failed and caught error: " + e);
-      return;
+      throw new CacheWriteError();
     }
 
     this._log.debug("_saveToCache saved to " + path);
   },
 
   /*
    * Task function, load the cached experiments manifest file from disk.
    */
@@ -1302,16 +1316,20 @@ Experiments.Experiments.prototype = {
     }
 
     if (!gExperimentsEnabled || this._experiments.length == 0) {
       return;
     }
 
     let time = null;
     let now = this._policy.now().getTime();
+    if (this._dirty) {
+      // If we failed to write the cache, we should try again periodically
+      time = now + 1000 * CACHE_WRITE_RETRY_DELAY_SEC;
+    }
 
     for (let [id, experiment] of this._experiments) {
       let scheduleTime = experiment.getScheduleTime();
       if (scheduleTime > now) {
         if (time !== null) {
           time = Math.min(time, scheduleTime);
         } else {
           time = scheduleTime;
deleted file mode 100644
--- a/build/link.py
+++ /dev/null
@@ -1,53 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-from __future__ import with_statement
-import os, subprocess, sys, threading, time
-from win32 import procmem
-
-def measure_vsize_threadfunc(proc, output_file):
-    """
-    Measure the virtual memory usage of |proc| at regular intervals
-    until it exits, then print the maximum value and write it to
-    |output_file|.  Also, print something to the console every
-    half an hour to prevent the build job from getting killed when
-    linking a large PGOed binary.
-    """
-    maxvsize = 0
-    idleTime = 0
-    while proc.returncode is None:
-        maxvsize, vsize = procmem.get_vmsize(proc._handle)
-        time.sleep(0.5)
-        idleTime += 0.5
-        if idleTime > 30 * 60:
-          print "Still linking, 30 minutes passed..."
-          sys.stdout.flush()
-          idleTime = 0
-    print "TinderboxPrint: linker max vsize: %d" % maxvsize
-    with open(output_file, "w") as f:
-        f.write("%d\n" % maxvsize)
-
-def measure_link_vsize(output_file, args):
-    """
-    Execute |args|, and measure the maximum virtual memory usage of the process,
-    printing it to stdout when finished.
-    """
-    proc = subprocess.Popen(args)
-    t = threading.Thread(target=measure_vsize_threadfunc,
-                         args=(proc, output_file))
-    t.start()
-    # Wait for the linker to finish.
-    exitcode = proc.wait()
-    # ...and then wait for the background thread to finish.
-    t.join()
-    return exitcode
-
-if __name__ == "__main__":
-    if sys.platform != "win32":
-        print >>sys.stderr, "link.py is only for use on Windows!"
-        sys.exit(1)
-    if len(sys.argv) < 3:
-        print >>sys.stderr, "Usage: link.py <output filename> <commandline>"
-        sys.exit(1)
-    sys.exit(measure_link_vsize(sys.argv[1], sys.argv[2:]))
--- a/config/expandlibs_exec.py
+++ b/config/expandlibs_exec.py
@@ -306,46 +306,49 @@ class SectionFinder(object):
 def print_command(out, args):
     print >>out, "Executing: " + " ".join(args)
     for tmp in [f for f in args.tmp if os.path.isfile(f)]:
         print >>out, tmp + ":"
         with open(tmp) as file:
             print >>out, "".join(["    " + l for l in file.readlines()])
     out.flush()
 
-def main():
+def main(args, proc_callback=None):
     parser = OptionParser()
     parser.add_option("--extract", action="store_true", dest="extract",
         help="when a library has no descriptor file, extract it first, when possible")
     parser.add_option("--uselist", action="store_true", dest="uselist",
         help="use a list file for objects when executing a command")
     parser.add_option("--verbose", action="store_true", dest="verbose",
         help="display executed command and temporary files content")
     parser.add_option("--symbol-order", dest="symbol_order", metavar="FILE",
         help="use the given list of symbols to order symbols in the resulting binary when using with a linker")
 
-    (options, args) = parser.parse_args()
+    (options, args) = parser.parse_args(args)
 
     with ExpandArgsMore(args) as args:
         if options.extract:
             args.extract()
         if options.symbol_order:
             args.orderSymbols(options.symbol_order)
         if options.uselist:
             args.makelist()
 
         if options.verbose:
             print_command(sys.stderr, args)
         try:
             proc = subprocess.Popen(args, stdout = subprocess.PIPE, stderr = subprocess.STDOUT)
+            if proc_callback:
+                proc_callback(proc)
         except Exception, e:
             print >>sys.stderr, 'error: Launching', args, ':', e
             raise e
         (stdout, stderr) = proc.communicate()
         if proc.returncode and not options.verbose:
             print_command(sys.stderr, args)
         sys.stderr.write(stdout)
         sys.stderr.flush()
         if proc.returncode:
-            exit(proc.returncode)
+            return proc.returncode
+        return 0
 
 if __name__ == '__main__':
-    main()
+    exit(main(sys.argv[1:]))
new file mode 100644
--- /dev/null
+++ b/config/link.py
@@ -0,0 +1,60 @@
+# 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/.
+
+import expandlibs_exec
+import sys
+import threading
+import time
+
+from win32 import procmem
+
+def measure_vsize_threadfunc(proc, output_file):
+    """
+    Measure the virtual memory usage of |proc| at regular intervals
+    until it exits, then print the maximum value and write it to
+    |output_file|.  Also, print something to the console every
+    half an hour to prevent the build job from getting killed when
+    linking a large PGOed binary.
+    """
+    maxvsize = 0
+    idleTime = 0
+    while proc.returncode is None:
+        maxvsize, vsize = procmem.get_vmsize(proc._handle)
+        time.sleep(0.5)
+        idleTime += 0.5
+        if idleTime > 30 * 60:
+          print "Still linking, 30 minutes passed..."
+          sys.stdout.flush()
+          idleTime = 0
+    print "TinderboxPrint: linker max vsize: %d" % maxvsize
+    with open(output_file, "w") as f:
+        f.write("%d\n" % maxvsize)
+
+def measure_link_vsize(output_file, args):
+    """
+    Execute |args|, and measure the maximum virtual memory usage of the process,
+    printing it to stdout when finished.
+    """
+
+    # This needs to be a list in order for the callback to set the
+    # variable properly with python-2's scoping rules.
+    t = [None]
+    def callback(proc):
+        t[0] = threading.Thread(target=measure_vsize_threadfunc,
+                             args=(proc, output_file))
+        t[0].start()
+    exitcode = expandlibs_exec.main(args, proc_callback=callback)
+    # Wait for the background thread to finish.
+    t[0].join()
+    return exitcode
+
+if __name__ == "__main__":
+    if sys.platform != "win32":
+        print >>sys.stderr, "link.py is only for use on Windows!"
+        sys.exit(1)
+    if len(sys.argv) < 3:
+        print >>sys.stderr, "Usage: link.py <output filename> <commandline>"
+        sys.exit(1)
+    output_file = sys.argv.pop(1)
+    sys.exit(measure_link_vsize(output_file, sys.argv[1:]))
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -3968,21 +3968,25 @@ ArrayBufferBuilder::reset()
   mCapacity = mLength = 0;
 }
 
 bool
 ArrayBufferBuilder::setCapacity(uint32_t aNewCap)
 {
   MOZ_ASSERT(!mMapPtr);
 
-  uint8_t *newdata = (uint8_t *) JS_ReallocateArrayBufferContents(nullptr, aNewCap, mDataPtr, mCapacity);
+  uint8_t *newdata = (uint8_t *) realloc(mDataPtr, aNewCap);
   if (!newdata) {
     return false;
   }
 
+  if (aNewCap > mCapacity) {
+    memset(newdata + mCapacity, 0, aNewCap - mCapacity);
+  }
+
   mDataPtr = newdata;
   mCapacity = aNewCap;
   if (mLength > aNewCap) {
     mLength = aNewCap;
   }
 
   return true;
 }
--- a/content/html/content/src/moz.build
+++ b/content/html/content/src/moz.build
@@ -173,17 +173,17 @@ FINAL_LIBRARY = 'xul'
 LOCAL_INCLUDES += [
     '/content/base/src',
     '/content/html/document/src',
     '/content/media/',
     '/content/xul/content/src',
     '/dom/base',
     '/dom/canvas',
     '/dom/xbl',
-    '/editor/libeditor/base',
+    '/editor/libeditor',
     '/editor/libeditor/text',
     '/editor/txmgr',
     '/layout/forms',
     '/layout/generic',
     '/layout/style',
     '/layout/tables',
     '/layout/xul',
     '/netwerk/base/src',
--- a/content/html/document/src/ImageDocument.cpp
+++ b/content/html/document/src/ImageDocument.cpp
@@ -108,22 +108,24 @@ ImageListener::OnStartRequest(nsIRequest
                                              nsContentUtils::GetContentPolicy(),
                                              secMan);
 
   if (NS_FAILED(rv) || NS_CP_REJECTED(decision)) {
     request->Cancel(NS_ERROR_CONTENT_BLOCKED);
     return NS_OK;
   }
 
-  nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(imgDoc->mImageContent);
-  NS_ENSURE_TRUE(imageLoader, NS_ERROR_UNEXPECTED);
+  if (!imgDoc->mObservingImageLoader) {
+    nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(imgDoc->mImageContent);
+    NS_ENSURE_TRUE(imageLoader, NS_ERROR_UNEXPECTED);
 
-  imageLoader->AddObserver(imgDoc);
-  imgDoc->mObservingImageLoader = true;
-  imageLoader->LoadImageWithChannel(channel, getter_AddRefs(mNextStream));
+    imageLoader->AddObserver(imgDoc);
+    imgDoc->mObservingImageLoader = true;
+    imageLoader->LoadImageWithChannel(channel, getter_AddRefs(mNextStream));
+  }
 
   return MediaDocumentStreamListener::OnStartRequest(request, ctxt);
 }
 
 NS_IMETHODIMP
 ImageListener::OnStopRequest(nsIRequest* aRequest, nsISupports* aCtxt, nsresult aStatus)
 {
   ImageDocument* imgDoc = static_cast<ImageDocument*>(mDocument.get());
@@ -379,22 +381,24 @@ ImageDocument::ScrollImageTo(int32_t aX,
   float ratio = GetRatio();
 
   if (restoreImage) {
     RestoreImage();
     FlushPendingNotifications(Flush_Layout);
   }
 
   nsCOMPtr<nsIPresShell> shell = GetShell();
-  if (!shell)
+  if (!shell) {
     return;
+  }
 
   nsIScrollableFrame* sf = shell->GetRootScrollFrameAsScrollable();
-  if (!sf)
+  if (!sf) {
     return;
+  }
 
   nsRect portRect = sf->GetScrollPortRect();
   sf->ScrollTo(nsPoint(nsPresContext::CSSPixelsToAppUnits(aX/ratio) - portRect.width/2,
                        nsPresContext::CSSPixelsToAppUnits(aY/ratio) - portRect.height/2),
                nsIScrollableFrame::INSTANT);
 }
 
 void
--- a/content/html/document/src/MediaDocument.cpp
+++ b/content/html/document/src/MediaDocument.cpp
@@ -16,16 +16,17 @@
 #include "nsIDocShell.h"
 #include "nsCharsetSource.h" // kCharsetFrom* macro definition
 #include "nsNodeInfoManager.h"
 #include "nsContentUtils.h"
 #include "nsDocElementCreatedNotificationRunner.h"
 #include "mozilla/Services.h"
 #include "nsServiceManagerUtils.h"
 #include "nsIPrincipal.h"
+#include "nsIMultiPartChannel.h"
 
 namespace mozilla {
 namespace dom {
 
 MediaDocumentStreamListener::MediaDocumentStreamListener(MediaDocument *aDocument)
 {
   mDocument = aDocument;
 }
@@ -65,19 +66,26 @@ MediaDocumentStreamListener::OnStopReque
                                            nsISupports *ctxt,
                                            nsresult status)
 {
   nsresult rv = NS_OK;
   if (mNextStream) {
     rv = mNextStream->OnStopRequest(request, ctxt, status);
   }
 
-  // No more need for our document so clear our reference and prevent leaks
-  mDocument = nullptr;
+  // Don't release mDocument here if we're in the middle of a multipart response.
+  bool lastPart = true;
+  nsCOMPtr<nsIMultiPartChannel> mpchan(do_QueryInterface(request));
+  if (mpchan) {
+    mpchan->GetIsLastPart(&lastPart);
+  }
 
+  if (lastPart) {
+    mDocument = nullptr;
+  }
   return rv;
 }
 
 NS_IMETHODIMP
 MediaDocumentStreamListener::OnDataAvailable(nsIRequest* request,
                                              nsISupports *ctxt,
                                              nsIInputStream *inStr,
                                              uint64_t sourceOffset,
--- a/content/media/MediaDecoder.h
+++ b/content/media/MediaDecoder.h
@@ -753,16 +753,19 @@ public:
 
   // Send a new set of metadata to the state machine, to be dispatched to the
   // main thread to be presented when the |currentTime| of the media is greater
   // or equal to aPublishTime.
   void QueueMetadata(int64_t aPublishTime,
                      MediaInfo* aInfo,
                      MetadataTags* aTags);
 
+  int64_t GetSeekTime() { return mRequestedSeekTarget.mTime; }
+  void ResetSeekTime() { mRequestedSeekTarget.Reset(); }
+
   /******
    * The following methods must only be called on the main
    * thread.
    ******/
 
   // Change to a new play state. This updates the mState variable and
   // notifies any thread blocking on this object's monitor of the
   // change. Call on the main thread only.
--- a/content/media/MediaDecoderStateMachine.cpp
+++ b/content/media/MediaDecoderStateMachine.cpp
@@ -1513,27 +1513,26 @@ nsresult
 MediaDecoderStateMachine::EnqueueDecodeMetadataTask()
 {
   AssertCurrentThreadInMonitor();
 
   if (mState != DECODER_STATE_DECODING_METADATA ||
       mDispatchedDecodeMetadataTask) {
     return NS_OK;
   }
+
+  mDispatchedDecodeMetadataTask = true;
   RefPtr<nsIRunnable> task(
     NS_NewRunnableMethod(this, &MediaDecoderStateMachine::CallDecodeMetadata));
   nsresult rv = mDecodeTaskQueue->Dispatch(task);
-  if (NS_SUCCEEDED(rv)) {
-    mDispatchedDecodeMetadataTask = true;
-  } else {
+  if (NS_FAILED(rv)) {
     NS_WARNING("Dispatch ReadMetadata task failed.");
-    return rv;
+    mDispatchedDecodeMetadataTask = false;
   }
-
-  return NS_OK;
+  return rv;
 }
 
 void
 MediaDecoderStateMachine::SetReaderIdle()
 {
 #ifdef PR_LOGGING
   {
     ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
@@ -1837,17 +1836,16 @@ MediaDecoderStateMachine::DecodeError()
     NS_DispatchToMainThread(event, NS_DISPATCH_SYNC);
   }
 }
 
 void
 MediaDecoderStateMachine::CallDecodeMetadata()
 {
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
-  AutoSetOnScopeExit<bool> unsetOnExit(mDispatchedDecodeMetadataTask, false);
   if (mState != DECODER_STATE_DECODING_METADATA) {
     return;
   }
   if (NS_FAILED(DecodeMetadata())) {
     DECODER_LOG(PR_LOG_WARNING, "Decode metadata failed, shutting down decoder");
     DecodeError();
   }
 }
@@ -1869,16 +1867,17 @@ nsresult MediaDecoderStateMachine::Decod
   }
 
   if (NS_SUCCEEDED(res)) {
     if (mState == DECODER_STATE_DECODING_METADATA &&
         mReader->IsWaitingMediaResources()) {
       // change state to DECODER_STATE_WAIT_FOR_RESOURCES
       StartWaitForResources();
       // affect values only if ReadMetadata succeeds
+      mDispatchedDecodeMetadataTask = false;
       return NS_OK;
     }
   }
 
   if (NS_SUCCEEDED(res)) {
     mDecoder->SetMediaSeekable(mReader->IsMediaSeekable());
   }
 
@@ -1991,16 +1990,17 @@ MediaDecoderStateMachine::FinishDecodeMe
 
   if ((mState == DECODER_STATE_DECODING || mState == DECODER_STATE_COMPLETED) &&
       mDecoder->GetState() == MediaDecoder::PLAY_STATE_PLAYING &&
       !IsPlaying())
   {
     StartPlayback();
   }
 
+  mDispatchedDecodeMetadataTask = false;
   return NS_OK;
 }
 
 void MediaDecoderStateMachine::DecodeSeek()
 {
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   NS_ASSERTION(OnDecodeThread(), "Should be on decode thread.");
   if (mState != DECODER_STATE_SEEKING) {
@@ -2438,33 +2438,33 @@ nsresult MediaDecoderStateMachine::RunSt
 
 void
 MediaDecoderStateMachine::FlushDecoding()
 {
   NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
                "Should be on state machine or decode thread.");
   mDecoder->GetReentrantMonitor().AssertNotCurrentThreadIn();
 
-  // Put a task in the decode queue to abort any decoding operations.
-  // The reader is not supposed to put any tasks to deliver samples into
-  // the queue after we call this (unless we request another sample from it).
-  RefPtr<nsIRunnable> task;
-  task = NS_NewRunnableMethod(mReader, &MediaDecoderReader::ResetDecode);
-  mDecodeTaskQueue->Dispatch(task);
-
   {
-    // Wait for the thread decoding to abort decoding operations and run
-    // any pending callbacks. This is important, as we don't want any
-    // pending tasks posted to the task queue by the reader to deliver
-    // any samples after we've posted the reader Shutdown() task below,
-    // as the sample-delivery tasks will keep video frames alive until
-    // after we've called Reader::Shutdown(), and shutdown on B2G will
-    // fail as there are outstanding video frames alive.
+    // Put a task in the decode queue to abort any decoding operations.
+    // The reader is not supposed to put any tasks to deliver samples into
+    // the queue after this runs (unless we request another sample from it).
+    RefPtr<nsIRunnable> task;
+    task = NS_NewRunnableMethod(mReader, &MediaDecoderReader::ResetDecode);
+
+    // Wait for the ResetDecode to run and for the decoder to abort
+    // decoding operations and run any pending callbacks. This is
+    // important, as we don't want any pending tasks posted to the task
+    // queue by the reader to deliver any samples after we've posted the
+    // reader Shutdown() task below, as the sample-delivery tasks will
+    // keep video frames alive until after we've called Reader::Shutdown(),
+    // and shutdown on B2G will fail as there are outstanding video frames
+    // alive.
     ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
-    mDecodeTaskQueue->Flush();
+    mDecodeTaskQueue->FlushAndDispatch(task);
   }
 
   // We must reset playback so that all references to frames queued
   // in the state machine are dropped, else subsequent calls to Shutdown()
   // or ReleaseMediaResources() can fail on B2G.
   ResetPlayback();
 }
 
--- a/content/media/MediaTaskQueue.cpp
+++ b/content/media/MediaTaskQueue.cpp
@@ -10,31 +10,43 @@
 
 namespace mozilla {
 
 MediaTaskQueue::MediaTaskQueue(TemporaryRef<SharedThreadPool> aPool)
   : mPool(aPool)
   , mQueueMonitor("MediaTaskQueue::Queue")
   , mIsRunning(false)
   , mIsShutdown(false)
+  , mIsFlushing(false)
 {
   MOZ_COUNT_CTOR(MediaTaskQueue);
 }
 
 MediaTaskQueue::~MediaTaskQueue()
 {
   MonitorAutoLock mon(mQueueMonitor);
   MOZ_ASSERT(mIsShutdown);
   MOZ_COUNT_DTOR(MediaTaskQueue);
 }
 
 nsresult
 MediaTaskQueue::Dispatch(TemporaryRef<nsIRunnable> aRunnable)
 {
   MonitorAutoLock mon(mQueueMonitor);
+  return DispatchLocked(aRunnable, AbortIfFlushing);
+}
+
+nsresult
+MediaTaskQueue::DispatchLocked(TemporaryRef<nsIRunnable> aRunnable,
+                               DispatchMode aMode)
+{
+  mQueueMonitor.AssertCurrentThreadOwns();
+  if (mIsFlushing && aMode == AbortIfFlushing) {
+    return NS_ERROR_ABORT;
+  }
   if (mIsShutdown) {
     return NS_ERROR_FAILURE;
   }
   mTasks.push(aRunnable);
   if (mIsRunning) {
     return NS_OK;
   }
   RefPtr<nsIRunnable> runner(new Runner(this));
@@ -108,20 +120,35 @@ MediaTaskQueue::AwaitIdleLocked()
 void
 MediaTaskQueue::Shutdown()
 {
   MonitorAutoLock mon(mQueueMonitor);
   mIsShutdown = true;
   AwaitIdleLocked();
 }
 
+nsresult
+MediaTaskQueue::FlushAndDispatch(TemporaryRef<nsIRunnable> aRunnable)
+{
+  MonitorAutoLock mon(mQueueMonitor);
+  AutoSetFlushing autoFlush(this);
+  while (!mTasks.empty()) {
+    mTasks.pop();
+  }
+  nsresult rv = DispatchLocked(aRunnable, IgnoreFlushing);
+  NS_ENSURE_SUCCESS(rv, rv);
+  AwaitIdleLocked();
+  return NS_OK;
+}
+
 void
 MediaTaskQueue::Flush()
 {
   MonitorAutoLock mon(mQueueMonitor);
+  AutoSetFlushing autoFlush(this);
   while (!mTasks.empty()) {
     mTasks.pop();
   }
   AwaitIdleLocked();
 }
 
 bool
 MediaTaskQueue::IsEmpty()
--- a/content/media/MediaTaskQueue.h
+++ b/content/media/MediaTaskQueue.h
@@ -30,16 +30,18 @@ public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaTaskQueue)
 
   MediaTaskQueue(TemporaryRef<SharedThreadPool> aPool);
 
   nsresult Dispatch(TemporaryRef<nsIRunnable> aRunnable);
 
   nsresult SyncDispatch(TemporaryRef<nsIRunnable> aRunnable);
 
+  nsresult FlushAndDispatch(TemporaryRef<nsIRunnable> aRunnable);
+
   // Removes all pending tasks from the task queue, and blocks until
   // the currently running task (if any) finishes.
   void Flush();
 
   // Blocks until all tasks finish executing, then shuts down the task queue
   // and exits.
   void Shutdown();
 
@@ -54,16 +56,21 @@ public:
 
 private:
 
   // Blocks until all task finish executing. Called internally by methods
   // that need to wait until the task queue is idle.
   // mQueueMonitor must be held.
   void AwaitIdleLocked();
 
+  enum DispatchMode { AbortIfFlushing, IgnoreFlushing };
+
+  nsresult DispatchLocked(TemporaryRef<nsIRunnable> aRunnable,
+                          DispatchMode aMode);
+
   RefPtr<SharedThreadPool> mPool;
 
   // Monitor that protects the queue and mIsRunning;
   Monitor mQueueMonitor;
 
   // Queue of tasks to run.
   std::queue<RefPtr<nsIRunnable>> mTasks;
 
@@ -74,16 +81,37 @@ private:
 
   // True if we've dispatched an event to the pool to execute events from
   // the queue.
   bool mIsRunning;
 
   // True if we've started our shutdown process.
   bool mIsShutdown;
 
+  class MOZ_STACK_CLASS AutoSetFlushing
+  {
+  public:
+    AutoSetFlushing(MediaTaskQueue* aTaskQueue) : mTaskQueue(aTaskQueue)
+    {
+      mTaskQueue->mQueueMonitor.AssertCurrentThreadOwns();
+      mTaskQueue->mIsFlushing = true;
+    }
+    ~AutoSetFlushing()
+    {
+      mTaskQueue->mQueueMonitor.AssertCurrentThreadOwns();
+      mTaskQueue->mIsFlushing = false;
+    }
+
+  private:
+    MediaTaskQueue* mTaskQueue;
+  };
+
+  // True if we're flushing; we reject new tasks if we're flushing.
+  bool mIsFlushing;
+
   class Runner : public nsRunnable {
   public:
     Runner(MediaTaskQueue* aQueue)
       : mQueue(aQueue)
     {
     }
     NS_METHOD Run() MOZ_OVERRIDE;
   private:
--- a/content/media/fmp4/apple/AppleATDecoder.cpp
+++ b/content/media/fmp4/apple/AppleATDecoder.cpp
@@ -49,31 +49,32 @@ AppleATDecoder::AppleATDecoder(const mp4
 AppleATDecoder::~AppleATDecoder()
 {
   MOZ_COUNT_DTOR(AppleATDecoer);
   MOZ_ASSERT(!mConverter);
   MOZ_ASSERT(!mStream);
 }
 
 static void
-_MetadataCallback(void *aDecoder,
+_MetadataCallback(void* aDecoder,
                   AudioFileStreamID aStream,
                   AudioFileStreamPropertyID aProperty,
-                  UInt32 *aFlags)
+                  UInt32* aFlags)
 {
   LOG("AppleATDecoder metadata callback");
   AppleATDecoder* decoder = static_cast<AppleATDecoder*>(aDecoder);
   decoder->MetadataCallback(aStream, aProperty, aFlags);
 }
 
 static void
-_SampleCallback(void *aDecoder,
-                UInt32 aNumBytes, UInt32 aNumPackets,
-                const void *aData,
-                AudioStreamPacketDescription *aPackets)
+_SampleCallback(void* aDecoder,
+                UInt32 aNumBytes,
+                UInt32 aNumPackets,
+                const void* aData,
+                AudioStreamPacketDescription* aPackets)
 {
   LOG("AppleATDecoder sample callback %u bytes %u packets",
       aNumBytes, aNumPackets);
   AppleATDecoder* decoder = static_cast<AppleATDecoder*>(aDecoder);
   decoder->SampleCallback(aNumBytes, aNumPackets, aData, aPackets);
 }
 
 nsresult
@@ -165,33 +166,33 @@ AppleATDecoder::MetadataCallback(AudioFi
     SetupDecoder();
   }
 }
 
 struct PassthroughUserData {
   AppleATDecoder* mDecoder;
   UInt32 mNumPackets;
   UInt32 mDataSize;
-  const void *mData;
-  AudioStreamPacketDescription *mPacketDesc;
+  const void* mData;
+  AudioStreamPacketDescription* mPacketDesc;
   bool mDone;
 };
 
 // Error value we pass through the decoder to signal that nothing
 // has gone wrong during decoding, but more data is needed.
 const uint32_t kNeedMoreData = 'MOAR';
 
 static OSStatus
 _PassthroughInputDataCallback(AudioConverterRef aAudioConverter,
-                              UInt32 *aNumDataPackets /* in/out */,
-                              AudioBufferList *aData /* in/out */,
-                              AudioStreamPacketDescription **aPacketDesc,
-                              void *aUserData)
+                              UInt32* aNumDataPackets /* in/out */,
+                              AudioBufferList* aData /* in/out */,
+                              AudioStreamPacketDescription** aPacketDesc,
+                              void* aUserData)
 {
-  PassthroughUserData *userData = (PassthroughUserData *)aUserData;
+  PassthroughUserData* userData = (PassthroughUserData*)aUserData;
   if (userData->mDone) {
     // We make sure this callback is run _once_, with all the data we received
     // from |AudioFileStreamParseBytes|. When we return an error, the decoder
     // simply passes the return value on to the calling method,
     // |SampleCallback|; and flushes all of the audio frames it had
     // buffered. It does not change the decoder's state.
     LOG("requested too much data; returning\n");
     *aNumDataPackets = 0;
@@ -202,17 +203,17 @@ static OSStatus
 
   LOG("AudioConverter wants %u packets of audio data\n", *aNumDataPackets);
 
   *aNumDataPackets = userData->mNumPackets;
   *aPacketDesc = userData->mPacketDesc;
 
   aData->mBuffers[0].mNumberChannels = userData->mDecoder->mConfig.channel_count;
   aData->mBuffers[0].mDataByteSize = userData->mDataSize;
-  aData->mBuffers[0].mData = const_cast<void *>(userData->mData);
+  aData->mBuffers[0].mData = const_cast<void*>(userData->mData);
 
   return noErr;
 }
 
 void
 AppleATDecoder::SampleCallback(uint32_t aNumBytes,
                                uint32_t aNumPackets,
                                const void* aData,
@@ -275,19 +276,19 @@ AppleATDecoder::SampleCallback(uint32_t 
     const int channels = mOutputFormat.mChannelsPerFrame;
 
     int64_t time = FramesToUsecs(mCurrentAudioFrame, rate).value();
     int64_t duration = FramesToUsecs(numFrames, rate).value();
 
     LOG("pushed audio at time %lfs; duration %lfs\n",
         (double)time / USECS_PER_S, (double)duration / USECS_PER_S);
 
-    AudioData *audio = new AudioData(mSamplePosition,
+    AudioData* audio = new AudioData(mSamplePosition,
                                      time, duration, numFrames,
-                                     reinterpret_cast<AudioDataValue *>(decoded.forget()),
+                                     reinterpret_cast<AudioDataValue*>(decoded.forget()),
                                      channels, rate);
     mCallback->Output(audio);
     mHaveOutput = true;
 
     mCurrentAudioFrame += numFrames;
 
     if (rv == kNeedMoreData) {
       // No error; we just need more data.
@@ -297,19 +298,24 @@ AppleATDecoder::SampleCallback(uint32_t 
     }
   } while (true);
 }
 
 void
 AppleATDecoder::SetupDecoder()
 {
   AudioStreamBasicDescription inputFormat;
-  // Fill in the input format description from the stream.
-  AppleUtils::GetProperty(mStream,
-      kAudioFileStreamProperty_DataFormat, &inputFormat);
+
+  mHaveOutput = false;
+
+  nsresult rv = AppleUtils::GetRichestDecodableFormat(mStream, inputFormat);
+  if (NS_FAILED(rv)) {
+    mCallback->Error();
+    return;
+  }
 
   // Fill in the output format manually.
   PodZero(&mOutputFormat);
   mOutputFormat.mFormatID = kAudioFormatLinearPCM;
   mOutputFormat.mSampleRate = inputFormat.mSampleRate;
   mOutputFormat.mChannelsPerFrame = inputFormat.mChannelsPerFrame;
 #if defined(MOZ_SAMPLE_TYPE_FLOAT32)
   mOutputFormat.mBitsPerChannel = 32;
@@ -319,23 +325,23 @@ AppleATDecoder::SetupDecoder()
 #else
 # error Unknown audio sample type
 #endif
   // Set up the decoder so it gives us one sample per frame
   mOutputFormat.mFramesPerPacket = 1;
   mOutputFormat.mBytesPerPacket = mOutputFormat.mBytesPerFrame
         = mOutputFormat.mChannelsPerFrame * mOutputFormat.mBitsPerChannel / 8;
 
-  OSStatus rv = AudioConverterNew(&inputFormat, &mOutputFormat, &mConverter);
-  if (rv) {
+  OSStatus status =
+    AudioConverterNew(&inputFormat, &mOutputFormat, &mConverter);
+  if (status) {
     LOG("Error %d constructing AudioConverter", rv);
     mConverter = nullptr;
     mCallback->Error();
   }
-  mHaveOutput = false;
 }
 
 void
 AppleATDecoder::SubmitSample(nsAutoPtr<mp4_demuxer::MP4Sample> aSample)
 {
   mSamplePosition = aSample->byte_offset;
   OSStatus rv = AudioFileStreamParseBytes(mStream,
                                           aSample->size,
--- a/content/media/fmp4/apple/AppleUtils.cpp
+++ b/content/media/fmp4/apple/AppleUtils.cpp
@@ -1,17 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // Utility functions to help with Apple API calls.
 
-#include <AudioToolbox/AudioToolbox.h>
 #include "AppleUtils.h"
 #include "prlog.h"
+#include "nsAutoPtr.h"
 
 #ifdef PR_LOGGING
 PRLogModuleInfo* GetDemuxerLog();
 #define WARN(...) PR_LOG(GetDemuxerLog(), PR_LOG_WARNING, (__VA_ARGS__))
 #else
 #define WARN(...)
 #endif
 
@@ -21,22 +21,22 @@ PRLogModuleInfo* GetDemuxerLog();
                              ((x) >> 8) & 0xff, \
                               (x) & 0xff
 
 namespace mozilla {
 
 nsresult
 AppleUtils::GetProperty(AudioFileStreamID aAudioFileStream,
                         AudioFileStreamPropertyID aPropertyID,
-                        void *aData)
+                        void* aData)
 {
   UInt32 size;
   Boolean writeable;
   OSStatus rv = AudioFileStreamGetPropertyInfo(aAudioFileStream, aPropertyID,
-                                                             &size, &writeable);
+                                               &size, &writeable);
 
   if (rv) {
     WARN("Couldn't get property " PROPERTY_ID_FORMAT "\n",
          PROPERTY_ID_PRINT(aPropertyID));
     return NS_ERROR_FAILURE;
   }
 
   rv = AudioFileStreamGetProperty(aAudioFileStream, aPropertyID,
@@ -75,10 +75,57 @@ AppleUtils::SetCFDict(CFMutableDictionar
                       const char* key,
                       bool value)
 {
   AutoCFRelease<CFStringRef> keyRef =
     CFStringCreateWithCString(NULL, key, kCFStringEncodingUTF8);
   CFDictionarySetValue(dict, keyRef, value ? kCFBooleanTrue : kCFBooleanFalse);
 }
 
+nsresult
+AppleUtils::GetRichestDecodableFormat(AudioFileStreamID aAudioFileStream,
+                                      AudioStreamBasicDescription& aFormat)
+{
+  // Fill in the default format description from the stream.
+  nsresult rv = GetProperty(aAudioFileStream,
+                            kAudioFileStreamProperty_DataFormat, &aFormat);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  UInt32 propertySize;
+  OSStatus status = AudioFileStreamGetPropertyInfo(
+    aAudioFileStream, kAudioFileStreamProperty_FormatList, &propertySize, NULL);
+  if (NS_WARN_IF(status)) {
+    // Return the default format description.
+    return NS_OK;
+  }
+
+  MOZ_ASSERT(propertySize % sizeof(AudioFormatListItem) == 0);
+  uint32_t sizeList = propertySize / sizeof(AudioFormatListItem);
+  nsAutoArrayPtr<AudioFormatListItem> formatListPtr(
+    new AudioFormatListItem[sizeList]);
+
+  rv = GetProperty(aAudioFileStream, kAudioFileStreamProperty_FormatList,
+                   formatListPtr);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    // Return the default format description.
+    return NS_OK;
+  }
+
+  // Get the index number of the first playable format.
+  // This index number will be for the highest quality layer the platform
+  // is capable of playing.
+  UInt32 itemIndex;
+  UInt32 indexSize = sizeof(itemIndex);
+  status =
+    AudioFormatGetProperty(kAudioFormatProperty_FirstPlayableFormatFromList,
+                           propertySize, formatListPtr, &indexSize, &itemIndex);
+  if (NS_WARN_IF(status)) {
+    // Return the default format description.
+    return NS_OK;
+  }
+  aFormat = formatListPtr[itemIndex].mASBD;
+
+  return NS_OK;
+}
 
 } // namespace mozilla
--- a/content/media/fmp4/apple/AppleUtils.h
+++ b/content/media/fmp4/apple/AppleUtils.h
@@ -11,30 +11,36 @@
 #include "nsError.h"
 
 namespace mozilla {
 
 struct AppleUtils {
   // Helper to retrieve properties from AudioFileStream objects.
   static nsresult GetProperty(AudioFileStreamID aAudioFileStream,
                               AudioFileStreamPropertyID aPropertyID,
-                              void *aData);
+                              void* aData);
 
   // Helper to set a string, string pair on a CFMutableDictionaryRef.
   static void SetCFDict(CFMutableDictionaryRef dict,
                         const char* key,
                         const char* value);
   // Helper to set a string, int32_t pair on a CFMutableDictionaryRef.
   static void SetCFDict(CFMutableDictionaryRef dict,
                         const char* key,
                         int32_t value);
   // Helper to set a string, bool pair on a CFMutableDictionaryRef.
   static void SetCFDict(CFMutableDictionaryRef dict,
                         const char* key,
                         bool value);
+
+  // Helper to retrieve the best audio format available in the given
+  // audio stream.
+  // The basic format will be returned by default should an error occur.
+  static nsresult GetRichestDecodableFormat(
+    AudioFileStreamID aAudioFileStream, AudioStreamBasicDescription& aFormat);
 };
 
 // Wrapper class to call CFRelease on reference types
 // when they go out of scope.
 template <class T>
 class AutoCFRelease {
 public:
   AutoCFRelease(T aRef)
--- a/content/media/gmp/GMPVideoEncoderParent.cpp
+++ b/content/media/gmp/GMPVideoEncoderParent.cpp
@@ -7,16 +7,17 @@
 #include "prlog.h"
 #include "GMPVideoi420FrameImpl.h"
 #include "GMPVideoEncodedFrameImpl.h"
 #include "mozilla/unused.h"
 #include "GMPMessageUtils.h"
 #include "nsAutoRef.h"
 #include "GMPParent.h"
 #include "mozilla/gmp/GMPTypes.h"
+#include "nsThread.h"
 #include "nsThreadUtils.h"
 #include "runnable_utils.h"
 
 template <>
 class nsAutoRefTraits<GMPVideoi420Frame> : public nsPointerRefTraits<GMPVideoi420Frame>
 {
 public:
   static void Release(GMPVideoi420Frame* aFrame) { aFrame->Destroy(); }
@@ -67,17 +68,19 @@ GMPVideoEncoderParent::GMPVideoEncoderPa
   nsresult rv = NS_NewNamedThread("GMPEncoded", getter_AddRefs(mEncodedThread));
   if (NS_FAILED(rv)) {
     MOZ_CRASH();
   }
 }
 
 GMPVideoEncoderParent::~GMPVideoEncoderParent()
 {
-  mEncodedThread->Shutdown();
+  if (mEncodedThread) {
+    mEncodedThread->Shutdown();
+  }
 }
 
 GMPVideoHostImpl&
 GMPVideoEncoderParent::Host()
 {
   return mVideoHost;
 }
 
@@ -233,27 +236,42 @@ GMPVideoEncoderParent::Shutdown()
   mVideoHost.DoneWithAPI();
   if (mIsOpen) {
     // Don't send EncodingComplete if we died
     mIsOpen = false;
     unused << SendEncodingComplete();
   }
 }
 
+static void
+ShutdownEncodedThread(nsCOMPtr<nsIThread>& aThread)
+{
+  aThread->Shutdown();
+}
+
 // Note: Keep this sync'd up with Shutdown
 void
 GMPVideoEncoderParent::ActorDestroy(ActorDestroyReason aWhy)
 {
   LOGD(("%s::%s: %p (%d)", __CLASS__, __FUNCTION__, this, (int) aWhy));
   mIsOpen = false;
   if (mCallback) {
     // May call Close() (and Shutdown()) immediately or with a delay
     mCallback->Terminated();
     mCallback = nullptr;
   }
+  // Must be shut down before VideoEncoderDestroyed(), since this can recurse
+  // the GMPThread event loop.  See bug 1049501
+  if (mEncodedThread) {
+    // Can't get it to allow me to use WrapRunnable with a nsCOMPtr<nsIThread>()
+    NS_DispatchToMainThread(
+      WrapRunnableNM<decltype(&ShutdownEncodedThread),
+                     nsCOMPtr<nsIThread> >(&ShutdownEncodedThread, mEncodedThread));
+    mEncodedThread = nullptr;
+  }
   if (mPlugin) {
     // Ignore any return code. It is OK for this to fail without killing the process.
     mPlugin->VideoEncoderDestroyed(this);
     mPlugin = nullptr;
   }
   mVideoHost.ActorDestroyed();
 }
 
old mode 100755
new mode 100644
--- a/content/media/omx/AudioOffloadPlayer.cpp
+++ b/content/media/omx/AudioOffloadPlayer.cpp
@@ -16,16 +16,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 #include "AudioOffloadPlayer.h"
 #include "nsComponentManagerUtils.h"
 #include "nsITimer.h"
 #include "mozilla/dom/HTMLMediaElement.h"
+#include "VideoUtils.h"
 
 #include <binder/IPCThreadState.h>
 #include <stagefright/foundation/ADebug.h>
 #include <stagefright/foundation/ALooper.h>
 #include <stagefright/MediaDefs.h>
 #include <stagefright/MediaErrors.h>
 #include <stagefright/MediaSource.h>
 #include <stagefright/MetaData.h>
@@ -46,17 +47,17 @@ PRLogModuleInfo* gAudioOffloadPlayerLog;
 #else
 #define AUDIO_OFFLOAD_LOG(type, msg)
 #endif
 
 // maximum time in paused state when offloading audio decompression.
 // When elapsed, the AudioSink is destroyed to allow the audio DSP to power down.
 static const uint64_t OFFLOAD_PAUSE_MAX_MSECS = 60000ll;
 
-AudioOffloadPlayer::AudioOffloadPlayer(MediaOmxDecoder* aObserver) :
+AudioOffloadPlayer::AudioOffloadPlayer(MediaOmxCommonDecoder* aObserver) :
   mObserver(aObserver),
   mInputBuffer(nullptr),
   mSampleRate(0),
   mSeeking(false),
   mSeekDuringPause(false),
   mReachedEOS(false),
   mSeekTimeUs(0),
   mStartPosUs(0),
@@ -192,17 +193,18 @@ status_t AudioOffloadPlayer::ChangeState
           = mObserver->GetSeekTime();
       SeekTo(seekTimeUs, true);
       mObserver->ResetSeekTime();
     } break;
 
     case MediaDecoder::PLAY_STATE_PAUSED:
     case MediaDecoder::PLAY_STATE_SHUTDOWN:
       // Just pause here during play state shutdown as well to stop playing
-      // offload track immediately. Resources will be freed by MediaOmxDecoder
+      // offload track immediately. Resources will be freed by
+      // MediaOmxCommonDecoder
       Pause();
       break;
 
     case MediaDecoder::PLAY_STATE_ENDED:
       Pause(true);
       break;
 
     default:
@@ -416,24 +418,24 @@ void AudioOffloadPlayer::NotifyAudioEOS(
   nsCOMPtr<nsIRunnable> nsEvent = NS_NewRunnableMethod(mObserver,
       &MediaDecoder::PlaybackEnded);
   NS_DispatchToMainThread(nsEvent);
 }
 
 void AudioOffloadPlayer::NotifyPositionChanged()
 {
   nsCOMPtr<nsIRunnable> nsEvent = NS_NewRunnableMethod(mObserver,
-      &MediaOmxDecoder::PlaybackPositionChanged);
+      &MediaOmxCommonDecoder::PlaybackPositionChanged);
   NS_DispatchToMainThread(nsEvent);
 }
 
 void AudioOffloadPlayer::NotifyAudioTearDown()
 {
   nsCOMPtr<nsIRunnable> nsEvent = NS_NewRunnableMethod(mObserver,
-      &MediaOmxDecoder::AudioOffloadTearDown);
+      &MediaOmxCommonDecoder::AudioOffloadTearDown);
   NS_DispatchToMainThread(nsEvent);
 }
 
 // static
 size_t AudioOffloadPlayer::AudioSinkCallback(AudioSink* aAudioSink,
                                              void* aBuffer,
                                              size_t aSize,
                                              void* aCookie,
old mode 100755
new mode 100644
--- a/content/media/omx/AudioOffloadPlayer.h
+++ b/content/media/omx/AudioOffloadPlayer.h
@@ -22,41 +22,40 @@
 
 #include <stagefright/MediaBuffer.h>
 #include <stagefright/MediaSource.h>
 #include <stagefright/TimeSource.h>
 #include <utils/threads.h>
 #include <utils/RefBase.h>
 
 #include "AudioOutput.h"
-
+#include "AudioOffloadPlayerBase.h"
 #include "MediaDecoderOwner.h"
-#include "MediaOmxDecoder.h"
+#include "MediaOmxCommonDecoder.h"
 
 namespace mozilla {
 
-class MediaOmxDecoder;
-
 /**
  * AudioOffloadPlayer adds support for audio tunneling to a digital signal
  * processor (DSP) in the device chipset. With tunneling, audio decoding is
  * off-loaded to the DSP, waking the application processor less often and using
  * less battery
  *
  * This depends on offloading capability provided by Android KK AudioTrack class
  *
  * Audio playback is based on pull mechanism, whenever audio sink needs
  * data, FillBuffer() will read data from compressed audio source and provide
  * it to the sink
  *
- * Also this class passes state changes (play/pause/seek) from MediaOmxDecoder
- * to AudioSink as well as provide AudioSink status (position changed,
- * playback ended, seek complete, audio tear down) back to MediaOmxDecoder
+ * Also this class passes state changes (play/pause/seek) from
+ * MediaOmxCommonDecoder to AudioSink as well as provide AudioSink status
+ * (position changed, playback ended, seek complete, audio tear down) back to
+ * MediaOmxCommonDecoder
  *
- * It acts as a bridge between MediaOmxDecoder and AudioSink during
+ * It acts as a bridge between MediaOmxCommonDecoder and AudioSink during
  * offload playback
  */
 
 class AudioOffloadPlayer : public AudioOffloadPlayerBase
 {
   typedef android::Mutex Mutex;
   typedef android::MetaData MetaData;
   typedef android::status_t status_t;
@@ -65,17 +64,17 @@ class AudioOffloadPlayer : public AudioO
   typedef android::MediaSource MediaSource;
 
 public:
   enum {
     REACHED_EOS,
     SEEK_COMPLETE
   };
 
-  AudioOffloadPlayer(MediaOmxDecoder* aDecoder = nullptr);
+  AudioOffloadPlayer(MediaOmxCommonDecoder* aDecoder = nullptr);
 
   ~AudioOffloadPlayer();
 
   // Caller retains ownership of "aSource".
   void SetSource(const android::sp<MediaSource> &aSource);
 
   // Start the source if it's not already started and open the AudioSink to
   // create an offloaded audio track
@@ -141,32 +140,33 @@ private:
 
   // Sample rate of current audio track. Used only in main thread
   int mSampleRate;
 
   // After seeking, positions returned by offlaoded tracks (DSP) will be
   // relative to the seeked position. And seeked position may be slightly
   // different than given mSeekTimeUs, if audio source cannot find a frame at
   // that position. Store seeked position in mStartPosUs and provide
-  // mStartPosUs + GetPosition() (i.e. absolute position) to MediaOmxDecoder
+  // mStartPosUs + GetPosition() (i.e. absolute position) to
+  // MediaOmxCommonDecoder
   // Used in main thread and offload callback thread, protected by Mutex
   // mLock
   int64_t mStartPosUs;
 
   // Given seek time when there is a request to seek
   // Used in main thread and offload callback thread, protected by Mutex
   // mLock
   int64_t mSeekTimeUs;
 
   // Positions obtained from offlaoded tracks (DSP)
   // Used in main thread and offload callback thread, protected by Mutex
   // mLock
   int64_t mPositionTimeMediaUs;
 
-  // State obtained from MediaOmxDecoder. Used only in main thread
+  // State obtained from MediaOmxCommonDecoder. Used only in main thread
   MediaDecoder::PlayState mPlayState;
 
   // Protect accessing audio position related variables between main thread and
   // offload callback thread
   Mutex mLock;
 
   // Compressed audio source.
   // Used in main thread first and later in offload callback thread
@@ -175,18 +175,18 @@ private:
   // Audio sink wrapper to access offloaded audio tracks
   // Used in main thread and offload callback thread
   // Race conditions are protected in underlying Android::AudioTrack class
   android::sp<AudioSink> mAudioSink;
 
   // Buffer used to get date from audio source. Used in offload callback thread
   MediaBuffer* mInputBuffer;
 
-  // MediaOmxDecoder object used mainly to notify the audio sink status
-  MediaOmxDecoder* mObserver;
+  // MediaOmxCommonDecoder object used mainly to notify the audio sink status
+  MediaOmxCommonDecoder* mObserver;
 
   TimeStamp mLastFireUpdateTime;
 
   // Timer to trigger position changed events
   nsCOMPtr<nsITimer> mTimeUpdateTimer;
 
   // Timer to reset AudioSink when audio is paused for OFFLOAD_PAUSE_MAX_USECS.
   // It is triggered in Pause() and canceled when there is a Play() within
--- a/content/media/omx/AudioOffloadPlayerBase.h
+++ b/content/media/omx/AudioOffloadPlayerBase.h
@@ -15,23 +15,21 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 #ifndef AUDIO_OFFLOAD_PLAYER_BASE_H_
 #define AUDIO_OFFLOAD_PLAYER_BASE_H_
 
+#include "MediaDecoder.h"
 #include "MediaDecoderOwner.h"
-#include "MediaOmxDecoder.h"
 
 namespace mozilla {
 
-class MediaOmxDecoder;
-
 /**
  * AudioOffloadPlayer interface class which has funtions used by MediaOmxDecoder
  * This is to reduce the dependency of AudioOffloadPlayer in MediaOmxDecoder
  */
 class AudioOffloadPlayerBase
 {
   typedef android::status_t status_t;
   typedef android::MediaSource MediaSource;
--- a/content/media/omx/MediaCodecDecoder.cpp
+++ b/content/media/omx/MediaCodecDecoder.cpp
@@ -1,25 +1,34 @@
 /* -*- 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 "MediaCodecDecoder.h"
+
+#include <stagefright/MediaSource.h>
+
 #include "MediaCodecReader.h"
 #include "MediaDecoderStateMachine.h"
 
 namespace mozilla {
 
 MediaDecoder*
 MediaCodecDecoder::Clone()
 {
   return new MediaCodecDecoder();
 }
 
+MediaOmxCommonReader*
+MediaCodecDecoder::CreateReader()
+{
+  return new MediaCodecReader(this);
+}
+
 MediaDecoderStateMachine*
-MediaCodecDecoder::CreateStateMachine()
+MediaCodecDecoder::CreateStateMachine(MediaOmxCommonReader* aReader)
 {
-  return new MediaDecoderStateMachine(this, new MediaCodecReader(this));
+  return new MediaDecoderStateMachine(this, aReader);
 }
 
 } // namespace mozilla
--- a/content/media/omx/MediaCodecDecoder.h
+++ b/content/media/omx/MediaCodecDecoder.h
@@ -2,25 +2,27 @@
 /* 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 MEDIA_CODEC_DECODER_H
 #define MEDIA_CODEC_DECODER_H
 
-#include "MediaDecoder.h"
+#include "MediaOmxCommonDecoder.h"
 
 namespace mozilla {
 
 // MediaDecoder that uses MediaCodecReader.
-class MediaCodecDecoder : public MediaDecoder
+class MediaCodecDecoder : public MediaOmxCommonDecoder
 {
 public:
 
   virtual MediaDecoder* Clone();
 
-  virtual MediaDecoderStateMachine* CreateStateMachine();
+  virtual MediaOmxCommonReader* CreateReader();
+
+  virtual MediaDecoderStateMachine* CreateStateMachine(MediaOmxCommonReader* aReader);
 };
 
 } // namespace mozilla
 
 #endif // MEDIA_CODEC_DECODER_H
--- a/content/media/omx/MediaCodecReader.cpp
+++ b/content/media/omx/MediaCodecReader.cpp
@@ -101,17 +101,18 @@ MediaCodecReader::VideoResourceListener:
 void
 MediaCodecReader::VideoResourceListener::codecCanceled()
 {
   if (mReader != nullptr) {
     mReader->codecCanceled(mReader->mVideoTrack);
   }
 }
 
-bool MediaCodecReader::TrackInputCopier::Copy(MediaBuffer* aSourceBuffer, sp<ABuffer> aCodecBuffer)
+bool
+MediaCodecReader::TrackInputCopier::Copy(MediaBuffer* aSourceBuffer, sp<ABuffer> aCodecBuffer)
 {
   if (aSourceBuffer == nullptr ||
       aCodecBuffer == nullptr ||
       aSourceBuffer->range_length() > aCodecBuffer->capacity()) {
     return false;
   }
 
   aCodecBuffer->setRange(0, aSourceBuffer->range_length());
@@ -127,17 +128,18 @@ MediaCodecReader::Track::Track()
   , mSeekTimeUs(sInvalidTimestampUs)
   , mFlushed(false)
 {
 }
 
 // Append the value of |kKeyValidSamples| to the end of each vorbis buffer.
 // https://github.com/mozilla-b2g/platform_frameworks_av/blob/master/media/libstagefright/OMXCodec.cpp#L3128
 // https://github.com/mozilla-b2g/platform_frameworks_av/blob/master/media/libstagefright/NuMediaExtractor.cpp#L472
-bool MediaCodecReader::VorbisInputCopier::Copy(MediaBuffer* aSourceBuffer, sp<ABuffer> aCodecBuffer)
+bool
+MediaCodecReader::VorbisInputCopier::Copy(MediaBuffer* aSourceBuffer, sp<ABuffer> aCodecBuffer)
 {
   if (aSourceBuffer == nullptr ||
       aCodecBuffer == nullptr ||
       aSourceBuffer->range_length() + sizeof(int32_t) > aCodecBuffer->capacity()) {
     return false;
   }
 
   int32_t numPageSamples = 0;
@@ -171,17 +173,17 @@ MediaCodecReader::CodecBufferInfo::Codec
   , mOffset(0)
   , mSize(0)
   , mTimeUs(0)
   , mFlags(0)
 {
 }
 
 MediaCodecReader::MediaCodecReader(AbstractMediaDecoder* aDecoder)
-  : MediaDecoderReader(aDecoder)
+  : MediaOmxCommonReader(aDecoder)
   , mColorConverterBufferSize(0)
 {
   mHandler = new MessageHandler(this);
   mVideoListener = new VideoResourceListener(this);
 }
 
 MediaCodecReader::~MediaCodecReader()
 {
@@ -422,16 +424,20 @@ MediaCodecReader::ReadMetadata(MediaInfo
                                MetadataTags** aTags)
 {
   MOZ_ASSERT(mDecoder->OnDecodeThread(), "Should be on decode thread.");
 
   if (!ReallocateResources()) {
     return NS_ERROR_FAILURE;
   }
 
+#ifdef MOZ_AUDIO_OFFLOAD
+  CheckAudioOffload();
+#endif
+
   if (IsWaitingMediaResources()) {
     return NS_OK;
   }
 
   // TODO: start streaming
 
   if (!UpdateDuration()) {
     return NS_ERROR_FAILURE;
@@ -519,16 +525,22 @@ MediaCodecReader::Seek(int64_t aTime,
 
 bool
 MediaCodecReader::IsMediaSeekable()
 {
   // Check the MediaExtract flag if the source is seekable.
   return (mExtractor != nullptr) && (mExtractor->flags() & MediaExtractor::CAN_SEEK);
 }
 
+android::sp<android::MediaSource>
+MediaCodecReader::GetAudioOffloadTrack()
+{
+  return mAudioOffloadTrack.mSource;
+}
+
 bool
 MediaCodecReader::ReallocateResources()
 {
   if (CreateLooper() &&
       CreateExtractor() &&
       CreateMediaSources() &&
       CreateMediaCodecs()) {
     return true;
@@ -670,16 +682,18 @@ MediaCodecReader::CreateMediaSources()
     return false;
   }
 
   if (audioTrackIndex != invalidTrackIndex && mAudioTrack.mSource == nullptr) {
     sp<MediaSource> audioSource = mExtractor->getTrack(audioTrackIndex);
     if (audioSource != nullptr && audioSource->start() == OK) {
       mAudioTrack.mSource = audioSource;
     }
+    // Get one another track instance for audio offload playback.
+    mAudioOffloadTrack.mSource = mExtractor->getTrack(audioTrackIndex);
   }
 
   if (videoTrackIndex != invalidTrackIndex && mVideoTrack.mSource == nullptr) {
     sp<MediaSource> videoSource = mExtractor->getTrack(videoTrackIndex);
     if (videoSource != nullptr && videoSource->start() == OK) {
       mVideoTrack.mSource = videoSource;
     }
   }
@@ -689,16 +703,17 @@ MediaCodecReader::CreateMediaSources()
       (videoTrackIndex == invalidTrackIndex || mVideoTrack.mSource != nullptr);
 }
 
 void
 MediaCodecReader::DestroyMediaSources()
 {
   mAudioTrack.mSource = nullptr;
   mVideoTrack.mSource = nullptr;
+  mAudioOffloadTrack.mSource = nullptr;
 }
 
 bool
 MediaCodecReader::CreateMediaCodecs()
 {
   if (CreateMediaCodec(mLooper, mAudioTrack, false, nullptr) &&
       CreateMediaCodec(mLooper, mVideoTrack, true, mVideoListener)) {
     return true;
@@ -1222,18 +1237,16 @@ MediaCodecReader::onMessageReceived(cons
     }
 
     case kNotifyCodecCanceled:
     {
       ReleaseCriticalResources();
       break;
     }
 
-    // TODO
-
     default:
       TRESPASS();
       break;
   }
 }
 
 // Called on Binder thread.
 void
--- a/content/media/omx/MediaCodecReader.h
+++ b/content/media/omx/MediaCodecReader.h
@@ -10,31 +10,31 @@
 #include <utils/threads.h>
 
 #include <mozilla/CheckedInt.h>
 
 #include "MediaData.h"
 
 #include "I420ColorConverterHelper.h"
 #include "MediaCodecProxy.h"
-#include "MediaDecoderReader.h"
+#include "MediaOmxCommonReader.h"
 
 namespace android {
 struct ALooper;
 struct AMessage;
 
 class MOZ_EXPORT MediaExtractor;
 class MOZ_EXPORT MediaBuffer;
 struct MOZ_EXPORT MediaSource;
 struct MediaCodec;
 } // namespace android
 
 namespace mozilla {
 
-class MediaCodecReader : public MediaDecoderReader
+class MediaCodecReader : public MediaOmxCommonReader
 {
 public:
   MediaCodecReader(AbstractMediaDecoder* aDecoder);
   virtual ~MediaCodecReader();
 
   // Initializes the reader, returns NS_OK on success, or NS_ERROR_FAILURE
   // on failure.
   virtual nsresult Init(MediaDecoderReader* aCloneDonor);
@@ -80,16 +80,18 @@ public:
   // is the current playback position in microseconds.
   virtual nsresult Seek(int64_t aTime,
                         int64_t aStartTime,
                         int64_t aEndTime,
                         int64_t aCurrentTime);
 
   virtual bool IsMediaSeekable() MOZ_OVERRIDE;
 
+  virtual android::sp<android::MediaSource> GetAudioOffloadTrack();
+
 protected:
   struct TrackInputCopier
   {
     virtual bool Copy(android::MediaBuffer* aSourceBuffer, android::sp<android::ABuffer> aCodecBuffer);
   };
 
   struct Track
   {
@@ -244,19 +246,20 @@ private:
   void ClearColorConverterBuffer();
 
   android::sp<MessageHandler> mHandler;
   android::sp<VideoResourceListener> mVideoListener;
 
   android::sp<android::ALooper> mLooper;
   android::sp<android::MediaExtractor> mExtractor;
 
-  // media elements
+  // media tracks
   AudioTrack mAudioTrack;
   VideoTrack mVideoTrack;
+  AudioTrack mAudioOffloadTrack; // only Track::mSource is valid
 
   // color converter
   android::I420ColorConverterHelper mColorConverter;
   nsAutoArrayPtr<uint8_t> mColorConverterBuffer;
   size_t mColorConverterBufferSize;
 };
 
 } // namespace mozilla
old mode 100755
new mode 100644
copy from content/media/omx/MediaOmxDecoder.cpp
copy to content/media/omx/MediaOmxCommonDecoder.cpp
--- a/content/media/omx/MediaOmxDecoder.cpp
+++ b/content/media/omx/MediaOmxCommonDecoder.cpp
@@ -1,110 +1,108 @@
 /* -*- 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 "MediaOmxDecoder.h"
-#include "MediaOmxReader.h"
+#include "MediaOmxCommonDecoder.h"
+
+#include <stagefright/MediaSource.h>
+
+#include "AudioOffloadPlayerBase.h"
 #include "MediaDecoderStateMachine.h"
-#include "VideoUtils.h"
-
-#include "OmxDecoder.h"
+#include "MediaOmxCommonReader.h"
 
 #ifdef MOZ_AUDIO_OFFLOAD
 #include "AudioOffloadPlayer.h"
 #endif
 
 using namespace android;
 
 namespace mozilla {
 
 #ifdef PR_LOGGING
 extern PRLogModuleInfo* gMediaDecoderLog;
 #define DECODER_LOG(type, msg) PR_LOG(gMediaDecoderLog, type, msg)
 #else
 #define DECODER_LOG(type, msg)
 #endif
 
-MediaOmxDecoder::MediaOmxDecoder() :
-  MediaDecoder(),
-  mCanOffloadAudio(false),
-  mFallbackToStateMachine(false)
+MediaOmxCommonDecoder::MediaOmxCommonDecoder()
+  : MediaDecoder()
+  , mReader(nullptr)
+  , mCanOffloadAudio(false)
+  , mFallbackToStateMachine(false)
 {
 #ifdef PR_LOGGING
   if (!gMediaDecoderLog) {
     gMediaDecoderLog = PR_NewLogModule("MediaDecoder");
   }
 #endif
 }
 
-MediaDecoder* MediaOmxDecoder::Clone()
-{
-  return new MediaOmxDecoder();
-}
-
-MediaDecoderStateMachine* MediaOmxDecoder::CreateStateMachine()
-{
-  mReader = new MediaOmxReader(this);
-  mReader->SetAudioChannel(GetAudioChannel());
-  return new MediaDecoderStateMachine(this, mReader);
-}
-
-void MediaOmxDecoder::SetCanOffloadAudio(bool aCanOffloadAudio)
+void
+MediaOmxCommonDecoder::SetCanOffloadAudio(bool aCanOffloadAudio)
 {
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
   mCanOffloadAudio = aCanOffloadAudio;
 }
 
-void MediaOmxDecoder::MetadataLoaded(MediaInfo* aInfo,
-                                     MetadataTags* aTags)
+void
+MediaOmxCommonDecoder::MetadataLoaded(MediaInfo* aInfo,
+                                      MetadataTags* aTags)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MediaDecoder::MetadataLoaded(aInfo, aTags);
 
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
   if (!mCanOffloadAudio || mFallbackToStateMachine || mOutputStreams.Length() ||
       mInitialPlaybackRate != 1.0) {
     DECODER_LOG(PR_LOG_DEBUG, ("In %s Offload Audio check failed",
         __PRETTY_FUNCTION__));
     return;
   }
 
 #ifdef MOZ_AUDIO_OFFLOAD
   mAudioOffloadPlayer = new AudioOffloadPlayer(this);
 #endif
+  if (!mAudioOffloadPlayer) {
+    return;
+  }
+
   mAudioOffloadPlayer->SetSource(mReader->GetAudioOffloadTrack());
   status_t err = mAudioOffloadPlayer->Start(false);
   if (err == OK) {
     PauseStateMachine();
     // Call ChangeState() to run AudioOffloadPlayer since offload state enabled
     ChangeState(mPlayState);
     return;
   }
 
   mAudioOffloadPlayer = nullptr;
   DECODER_LOG(PR_LOG_DEBUG, ("In %s Unable to start offload audio %d."
       "Switching to normal mode", __PRETTY_FUNCTION__, err));
 }
 
-void MediaOmxDecoder::PauseStateMachine()
+void
+MediaOmxCommonDecoder::PauseStateMachine()
 {
   MOZ_ASSERT(NS_IsMainThread());
   GetReentrantMonitor().AssertCurrentThreadIn();
   DECODER_LOG(PR_LOG_DEBUG, ("%s", __PRETTY_FUNCTION__));
   if (!mDecoderStateMachine) {
     return;
   }
   StopProgress();
   mDecoderStateMachine->SetDormant(true);
 }
 
-void MediaOmxDecoder::ResumeStateMachine()
+void
+MediaOmxCommonDecoder::ResumeStateMachine()
 {
   MOZ_ASSERT(NS_IsMainThread());
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
   DECODER_LOG(PR_LOG_DEBUG, ("%s current time %f", __PRETTY_FUNCTION__,
       mCurrentTime));
 
   if (!mDecoderStateMachine) {
     return;
@@ -116,87 +114,93 @@ void MediaOmxDecoder::ResumeStateMachine
   SecondsToUsecs(mCurrentTime, timeUsecs);
   mRequestedSeekTarget = SeekTarget(timeUsecs, SeekTarget::Accurate);
 
   mNextState = mPlayState;
   ChangeState(PLAY_STATE_LOADING);
   mDecoderStateMachine->SetDormant(false);
 }
 
-void MediaOmxDecoder::AudioOffloadTearDown()
+void
+MediaOmxCommonDecoder::AudioOffloadTearDown()
 {
   MOZ_ASSERT(NS_IsMainThread());
   DECODER_LOG(PR_LOG_DEBUG, ("%s", __PRETTY_FUNCTION__));
 
   // mAudioOffloadPlayer can be null here if ResumeStateMachine was called
   // just before because of some other error.
   if (mAudioOffloadPlayer) {
     // Audio offload player sent tear down event. Fallback to state machine
     PlaybackPositionChanged();
     ResumeStateMachine();
   }
 }
 
-void MediaOmxDecoder::AddOutputStream(ProcessedMediaStream* aStream,
-                                      bool aFinishWhenEnded)
+void
+MediaOmxCommonDecoder::AddOutputStream(ProcessedMediaStream* aStream,
+                                       bool aFinishWhenEnded)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (mAudioOffloadPlayer) {
     // Offload player cannot handle MediaStream. Fallback
     PlaybackPositionChanged();
     ResumeStateMachine();
   }
 
   MediaDecoder::AddOutputStream(aStream, aFinishWhenEnded);
 }
 
-void MediaOmxDecoder::SetPlaybackRate(double aPlaybackRate)
+void
+MediaOmxCommonDecoder::SetPlaybackRate(double aPlaybackRate)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (mAudioOffloadPlayer &&
       ((aPlaybackRate != 0.0) || (aPlaybackRate != 1.0))) {
     // Offload player cannot handle playback rate other than 1/0. Fallback
     PlaybackPositionChanged();
     ResumeStateMachine();
   }
 
   MediaDecoder::SetPlaybackRate(aPlaybackRate);
 }
 
-void MediaOmxDecoder::ChangeState(PlayState aState)
+void
+MediaOmxCommonDecoder::ChangeState(PlayState aState)
 {
   MOZ_ASSERT(NS_IsMainThread());
   // Keep MediaDecoder state in sync with MediaElement irrespective of offload
   // playback so it will continue to work in normal mode when offloading fails
   // in between
   MediaDecoder::ChangeState(aState);
 
   if (mAudioOffloadPlayer) {
     status_t err = mAudioOffloadPlayer->ChangeState(aState);
     if (err != OK) {
       ResumeStateMachine();
     }
   }
 }
 
-void MediaOmxDecoder::ApplyStateToStateMachine(PlayState aState)
+void
+MediaOmxCommonDecoder::ApplyStateToStateMachine(PlayState aState)
 {
   MOZ_ASSERT(NS_IsMainThread());
   // During offload playback, state machine should be in dormant state.
   // ApplyStateToStateMachine() can change state machine state to
   // something else or reset the seek time. So don't call this when audio is
   // offloaded
   if (!mAudioOffloadPlayer) {
     MediaDecoder::ApplyStateToStateMachine(aState);
   }
 }
 
-void MediaOmxDecoder::PlaybackPositionChanged()
+void
+MediaOmxCommonDecoder::PlaybackPositionChanged()
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (!mAudioOffloadPlayer) {
     MediaDecoder::PlaybackPositionChanged();
     return;
   }
 
   if (!mOwner || mShuttingDown) {
@@ -208,40 +212,53 @@ void MediaOmxDecoder::PlaybackPositionCh
     ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
     mCurrentTime = mAudioOffloadPlayer->GetMediaTimeSecs();
   }
   if (mOwner && lastTime != mCurrentTime) {
     FireTimeUpdate();
   }
 }
 
-void MediaOmxDecoder::SetElementVisibility(bool aIsVisible)
+void
+MediaOmxCommonDecoder::SetElementVisibility(bool aIsVisible)
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (mAudioOffloadPlayer) {
     mAudioOffloadPlayer->SetElementVisibility(aIsVisible);
   }
 }
 
-void MediaOmxDecoder::UpdateReadyStateForData()
+void
+MediaOmxCommonDecoder::UpdateReadyStateForData()
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (!mAudioOffloadPlayer) {
     MediaDecoder::UpdateReadyStateForData();
     return;
   }
 
   if (!mOwner || mShuttingDown)
     return;
   mOwner->UpdateReadyStateForData(mAudioOffloadPlayer->GetNextFrameStatus());
 }
 
-void MediaOmxDecoder::SetVolume(double aVolume)
+void
+MediaOmxCommonDecoder::SetVolume(double aVolume)
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (!mAudioOffloadPlayer) {
     MediaDecoder::SetVolume(aVolume);
     return;
   }
   mAudioOffloadPlayer->SetVolume(aVolume);
 }
 
+MediaDecoderStateMachine*
+MediaOmxCommonDecoder::CreateStateMachine()
+{
+  mReader = CreateReader();
+  if (mReader != nullptr) {
+    mReader->SetAudioChannel(GetAudioChannel());
+  }
+  return CreateStateMachine(mReader);
+}
+
 } // namespace mozilla
old mode 100755
new mode 100644
copy from content/media/omx/MediaOmxDecoder.h
copy to content/media/omx/MediaOmxCommonDecoder.h
--- a/content/media/omx/MediaOmxDecoder.h
+++ b/content/media/omx/MediaOmxCommonDecoder.h
@@ -1,62 +1,67 @@
 /* -*- 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/. */
-#if !defined(MediaOmxDecoder_h_)
-#define MediaOmxDecoder_h_
+
+#ifndef MEDIA_OMX_COMMON_DECODER_H
+#define MEDIA_OMX_COMMON_DECODER_H
 
-#include "base/basictypes.h"
 #include "MediaDecoder.h"
-#include "MediaOmxReader.h"
-#include "AudioOffloadPlayerBase.h"
+
+namespace android {
+struct MOZ_EXPORT MediaSource;
+} // namespace android
 
 namespace mozilla {
 
-class MediaOmxDecoder : public MediaDecoder
+class AudioOffloadPlayerBase;
+class MediaOmxCommonReader;
+
+class MediaOmxCommonDecoder : public MediaDecoder
 {
-  typedef android::MediaSource MediaSource;
 public:
-  MediaOmxDecoder();
-  virtual MediaDecoder* Clone();
-  virtual MediaDecoderStateMachine* CreateStateMachine();
+  MediaOmxCommonDecoder();
 
   virtual void MetadataLoaded(MediaInfo* aInfo,
                               MetadataTags* aTags);
   virtual void ChangeState(PlayState aState);
   virtual void ApplyStateToStateMachine(PlayState aState);
   virtual void SetVolume(double aVolume);
   virtual void PlaybackPositionChanged();
   virtual void UpdateReadyStateForData();
   virtual void SetElementVisibility(bool aIsVisible);
   virtual void SetCanOffloadAudio(bool aCanOffloadAudio);
   virtual void AddOutputStream(ProcessedMediaStream* aStream,
                                bool aFinishWhenEnded);
   virtual void SetPlaybackRate(double aPlaybackRate);
 
   void AudioOffloadTearDown();
-  int64_t GetSeekTime() { return mRequestedSeekTarget.mTime; }
-  void ResetSeekTime() { mRequestedSeekTarget.Reset(); }
+
+  virtual MediaDecoderStateMachine* CreateStateMachine();
 
-private:
+  virtual MediaOmxCommonReader* CreateReader() = 0;
+  virtual MediaDecoderStateMachine* CreateStateMachine(MediaOmxCommonReader* aReader) = 0;
+
+protected:
   void PauseStateMachine();
   void ResumeStateMachine();
 
-  MediaOmxReader* mReader;
+  MediaOmxCommonReader* mReader;
 
   // Offloaded audio track
-  android::sp<MediaSource> mAudioTrack;
+  android::sp<android::MediaSource> mAudioTrack;
 
   nsAutoPtr<AudioOffloadPlayerBase> mAudioOffloadPlayer;
 
-  // Set by MediaOmxReader to denote current track can be offloaded
+  // Set by Media*Reader to denote current track can be offloaded
   bool mCanOffloadAudio;
 
   // Set when offload playback of current track fails in the middle and need to
   // fallback to state machine
   bool mFallbackToStateMachine;
 };
 
 } // namespace mozilla
 
-#endif
+#endif // MEDIA_OMX_COMMON_DECODER_H
copy from content/media/omx/MediaOmxReader.cpp
copy to content/media/omx/MediaOmxCommonReader.cpp
--- a/content/media/omx/MediaOmxReader.cpp
+++ b/content/media/omx/MediaOmxCommonReader.cpp
@@ -1,453 +1,69 @@
 /* -*- 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 "MediaOmxReader.h"
+#include "MediaOmxCommonReader.h"
 
-#include "MediaDecoderStateMachine.h"
-#include "mozilla/TimeStamp.h"
-#include "mozilla/dom/TimeRanges.h"
-#include "MediaResource.h"
-#include "VideoUtils.h"
-#include "MediaOmxDecoder.h"
+#include <stagefright/MediaSource.h>
+
 #include "AbstractMediaDecoder.h"
 #include "AudioChannelService.h"
-#include "OmxDecoder.h"
-#include "MPAPI.h"
-#include "gfx2DGlue.h"
 #include "MediaStreamSource.h"
 
 #ifdef MOZ_AUDIO_OFFLOAD
 #include <stagefright/Utils.h>
 #include <cutils/properties.h>
 #include <stagefright/MetaData.h>
 #endif
 
-#define MAX_DROPPED_FRAMES 25
-// Try not to spend more than this much time in a single call to DecodeVideoFrame.
-#define MAX_VIDEO_DECODE_SECONDS 0.1
-
-using namespace mozilla::gfx;
 using namespace android;
 
 namespace mozilla {
 
 #ifdef PR_LOGGING
 extern PRLogModuleInfo* gMediaDecoderLog;
 #define DECODER_LOG(type, msg) PR_LOG(gMediaDecoderLog, type, msg)
 #else
 #define DECODER_LOG(type, msg)
 #endif
 
-MediaOmxReader::MediaOmxReader(AbstractMediaDecoder *aDecoder)
+MediaOmxCommonReader::MediaOmxCommonReader(AbstractMediaDecoder *aDecoder)
   : MediaDecoderReader(aDecoder)
-  , mHasVideo(false)
-  , mHasAudio(false)
-  , mVideoSeekTimeUs(-1)
-  , mAudioSeekTimeUs(-1)
-  , mSkipCount(0)
 {
 #ifdef PR_LOGGING
   if (!gMediaDecoderLog) {
     gMediaDecoderLog = PR_NewLogModule("MediaDecoder");
   }
 #endif
 
   mAudioChannel = dom::AudioChannelService::GetDefaultAudioChannel();
 }
 
-MediaOmxReader::~MediaOmxReader()
-{
-}
-
-nsresult MediaOmxReader::Init(MediaDecoderReader* aCloneDonor)
-{
-  return NS_OK;
-}
-
-void MediaOmxReader::ReleaseDecoder()
-{
-  if (mOmxDecoder.get()) {
-    mOmxDecoder->ReleaseDecoder();
-  }
-  mOmxDecoder.clear();
-}
-
-void MediaOmxReader::Shutdown()
-{
-  ReleaseMediaResources();
-  nsCOMPtr<nsIRunnable> event =
-    NS_NewRunnableMethod(this, &MediaOmxReader::ReleaseDecoder);
-  NS_DispatchToMainThread(event);
-}
-
-bool MediaOmxReader::IsWaitingMediaResources()
-{
-  if (!mOmxDecoder.get()) {
-    return false;
-  }
-  return mOmxDecoder->IsWaitingMediaResources();
-}
-
-bool MediaOmxReader::IsDormantNeeded()
-{
-  if (!mOmxDecoder.get()) {
-    return false;
-  }
-  return mOmxDecoder->IsDormantNeeded();
-}
-
-void MediaOmxReader::ReleaseMediaResources()
-{
-  ResetDecode();
-  // Before freeing a video codec, all video buffers needed to be released
-  // even from graphics pipeline.
-  VideoFrameContainer* container = mDecoder->GetVideoFrameContainer();
-  if (container) {
-    container->ClearCurrentFrame();
-  }
-  if (mOmxDecoder.get()) {
-    mOmxDecoder->ReleaseMediaResources();
-  }
-}
-
-nsresult MediaOmxReader::InitOmxDecoder()
-{
-  if (!mOmxDecoder.get()) {
-    //register sniffers, if they are not registered in this process.
-    DataSource::RegisterDefaultSniffers();
-    mDecoder->GetResource()->SetReadMode(MediaCacheStream::MODE_METADATA);
-
-    sp<DataSource> dataSource = new MediaStreamSource(mDecoder->GetResource());
-    dataSource->initCheck();
-
-    mExtractor = MediaExtractor::Create(dataSource);
-    if (!mExtractor.get()) {
-      return NS_ERROR_FAILURE;
-    }
-    mOmxDecoder = new OmxDecoder(mDecoder->GetResource(), mDecoder);
-    if (!mOmxDecoder->Init(mExtractor)) {
-      return NS_ERROR_FAILURE;
-    }
-  }
-  return NS_OK;
-}
-
-nsresult MediaOmxReader::ReadMetadata(MediaInfo* aInfo,
-                                      MetadataTags** aTags)
-{
-  NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
-  EnsureActive();
-
-  *aTags = nullptr;
-
-  // Initialize the internal OMX Decoder.
-  nsresult rv = InitOmxDecoder();
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  if (!mOmxDecoder->TryLoad()) {
-    return NS_ERROR_FAILURE;
-  }
-
 #ifdef MOZ_AUDIO_OFFLOAD
-  CheckAudioOffload();
-#endif
-
-  if (IsWaitingMediaResources()) {
-    return NS_OK;
-  }
-
-  // Set the total duration (the max of the audio and video track).
-  int64_t durationUs;
-  mOmxDecoder->GetDuration(&durationUs);
-  if (durationUs) {
-    ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
-    mDecoder->SetMediaDuration(durationUs);
-  }
-
-  if (mOmxDecoder->HasVideo()) {
-    int32_t displayWidth, displayHeight, width, height;
-    mOmxDecoder->GetVideoParameters(&displayWidth, &displayHeight,
-                                    &width, &height);
-    nsIntRect pictureRect(0, 0, width, height);
-
-    // Validate the container-reported frame and pictureRect sizes. This ensures
-    // that our video frame creation code doesn't overflow.
-    nsIntSize displaySize(displayWidth, displayHeight);
-    nsIntSize frameSize(width, height);
-    if (!IsValidVideoRegion(frameSize, pictureRect, displaySize)) {
-      return NS_ERROR_FAILURE;
-    }
-
-    // Video track's frame sizes will not overflow. Activate the video track.
-    mHasVideo = mInfo.mVideo.mHasVideo = true;
-    mInfo.mVideo.mDisplay = displaySize;
-    mPicture = pictureRect;
-    mInitialFrame = frameSize;
-    VideoFrameContainer* container = mDecoder->GetVideoFrameContainer();
-    if (container) {
-      container->SetCurrentFrame(gfxIntSize(displaySize.width, displaySize.height),
-                                 nullptr,
-                                 mozilla::TimeStamp::Now());
-    }
-  }
-
-  if (mOmxDecoder->HasAudio()) {
-    int32_t numChannels, sampleRate;
-    mOmxDecoder->GetAudioParameters(&numChannels, &sampleRate);
-    mHasAudio = mInfo.mAudio.mHasAudio = true;
-    mInfo.mAudio.mChannels = numChannels;
-    mInfo.mAudio.mRate = sampleRate;
-  }
-
- *aInfo = mInfo;
-
-  return NS_OK;
-}
-
-bool
-MediaOmxReader::IsMediaSeekable()
-{
-  // Check the MediaExtract flag if the source is seekable.
-  return (mExtractor->flags() & MediaExtractor::CAN_SEEK);
-}
-
-bool MediaOmxReader::DecodeVideoFrame(bool &aKeyframeSkip,
-                                      int64_t aTimeThreshold)
-{
-  NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
-  EnsureActive();
-
-  // Record number of frames decoded and parsed. Automatically update the
-  // stats counters using the AutoNotifyDecoded stack-based class.
-  uint32_t parsed = 0, decoded = 0;
-  AbstractMediaDecoder::AutoNotifyDecoded autoNotify(mDecoder, parsed, decoded);
-
-  bool doSeek = mVideoSeekTimeUs != -1;
-  if (doSeek) {
-    aTimeThreshold = mVideoSeekTimeUs;
-  }
-
-  TimeStamp start = TimeStamp::Now();
-
-  // Read next frame. Don't let this loop run for too long.
-  while ((TimeStamp::Now() - start) < TimeDuration::FromSeconds(MAX_VIDEO_DECODE_SECONDS)) {
-    MPAPI::VideoFrame frame;
-    frame.mGraphicBuffer = nullptr;
-    frame.mShouldSkip = false;
-    if (!mOmxDecoder->ReadVideo(&frame, aTimeThreshold, aKeyframeSkip, doSeek)) {
-      return false;
-    }
-    doSeek = false;
-
-    // Ignore empty buffer which stagefright media read will sporadically return
-    if (frame.mSize == 0 && !frame.mGraphicBuffer) {
-      continue;
-    }
-
-    parsed++;
-    if (frame.mShouldSkip && mSkipCount < MAX_DROPPED_FRAMES) {
-      mSkipCount++;
-      continue;
-    }
-
-    mSkipCount = 0;
-
-    mVideoSeekTimeUs = -1;
-    aKeyframeSkip = false;
-
-    IntRect picture = ToIntRect(mPicture);
-    if (frame.Y.mWidth != mInitialFrame.width ||
-        frame.Y.mHeight != mInitialFrame.height) {
-
-      // Frame size is different from what the container reports. This is legal,
-      // and we will preserve the ratio of the crop rectangle as it
-      // was reported relative to the picture size reported by the container.
-      picture.x = (mPicture.x * frame.Y.mWidth) / mInitialFrame.width;
-      picture.y = (mPicture.y * frame.Y.mHeight) / mInitialFrame.height;
-      picture.width = (frame.Y.mWidth * mPicture.width) / mInitialFrame.width;
-      picture.height = (frame.Y.mHeight * mPicture.height) / mInitialFrame.height;
-    }
-
-    // This is the approximate byte position in the stream.
-    int64_t pos = mDecoder->GetResource()->Tell();
-
-    VideoData *v;
-    if (!frame.mGraphicBuffer) {
-
-      VideoData::YCbCrBuffer b;
-      b.mPlanes[0].mData = static_cast<uint8_t *>(frame.Y.mData);
-      b.mPlanes[0].mStride = frame.Y.mStride;
-      b.mPlanes[0].mHeight = frame.Y.mHeight;
-      b.mPlanes[0].mWidth = frame.Y.mWidth;
-      b.mPlanes[0].mOffset = frame.Y.mOffset;
-      b.mPlanes[0].mSkip = frame.Y.mSkip;
-
-      b.mPlanes[1].mData = static_cast<uint8_t *>(frame.Cb.mData);
-      b.mPlanes[1].mStride = frame.Cb.mStride;
-      b.mPlanes[1].mHeight = frame.Cb.mHeight;
-      b.mPlanes[1].mWidth = frame.Cb.mWidth;
-      b.mPlanes[1].mOffset = frame.Cb.mOffset;
-      b.mPlanes[1].mSkip = frame.Cb.mSkip;
-
-      b.mPlanes[2].mData = static_cast<uint8_t *>(frame.Cr.mData);
-      b.mPlanes[2].mStride = frame.Cr.mStride;
-      b.mPlanes[2].mHeight = frame.Cr.mHeight;
-      b.mPlanes[2].mWidth = frame.Cr.mWidth;
-      b.mPlanes[2].mOffset = frame.Cr.mOffset;
-      b.mPlanes[2].mSkip = frame.Cr.mSkip;
-
-      v = VideoData::Create(mInfo.mVideo,
-                            mDecoder->GetImageContainer(),
-                            pos,
-                            frame.mTimeUs,
-                            1, // We don't know the duration.
-                            b,
-                            frame.mKeyFrame,
-                            -1,
-                            picture);
-    } else {
-      v = VideoData::Create(mInfo.mVideo,
-                            mDecoder->GetImageContainer(),
-                            pos,
-                            frame.mTimeUs,
-                            1, // We don't know the duration.
-                            frame.mGraphicBuffer,
-                            frame.mKeyFrame,
-                            -1,
-                            picture);
-    }
-
-    if (!v) {
-      NS_WARNING("Unable to create VideoData");
-      return false;
-    }
-
-    decoded++;
-    NS_ASSERTION(decoded <= parsed, "Expect to decode fewer frames than parsed in OMX decoder...");
-
-    mVideoQueue.Push(v);
-
-    break;
-  }
-
-  return true;
-}
-
-void MediaOmxReader::NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset)
-{
-  android::OmxDecoder *omxDecoder = mOmxDecoder.get();
-
-  if (omxDecoder) {
-    omxDecoder->NotifyDataArrived(aBuffer, aLength, aOffset);
-  }
-}
-
-bool MediaOmxReader::DecodeAudioData()
-{
-  NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
-  EnsureActive();
-
-  // This is the approximate byte position in the stream.
-  int64_t pos = mDecoder->GetResource()->Tell();
-
-  // Read next frame
-  MPAPI::AudioFrame source;
-  if (!mOmxDecoder->ReadAudio(&source, mAudioSeekTimeUs)) {
-    return false;
-  }
-  mAudioSeekTimeUs = -1;
-
-  // Ignore empty buffer which stagefright media read will sporadically return
-  if (source.mSize == 0) {
-    return true;
-  }
-
-  uint32_t frames = source.mSize / (source.mAudioChannels *
-                                    sizeof(AudioDataValue));
-
-  typedef AudioCompactor::NativeCopy OmxCopy;
-  return mAudioCompactor.Push(pos,
-                              source.mTimeUs,
-                              source.mAudioSampleRate,
-                              frames,
-                              source.mAudioChannels,
-                              OmxCopy(static_cast<uint8_t *>(source.mData),
-                                      source.mSize,
-                                      source.mAudioChannels));
-}
-
-nsresult MediaOmxReader::Seek(int64_t aTarget, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime)
-{
-  NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
-  EnsureActive();
-
-  VideoFrameContainer* container = mDecoder->GetVideoFrameContainer();
-  if (container && container->GetImageContainer()) {
-    container->GetImageContainer()->ClearAllImagesExceptFront();
-  }
-
-  if (mHasAudio && mHasVideo) {
-    // The OMXDecoder seeks/demuxes audio and video streams separately. So if
-    // we seek both audio and video to aTarget, the audio stream can typically
-    // seek closer to the seek target, since typically every audio block is
-    // a sync point, whereas for video there are only keyframes once every few
-    // seconds. So if we have both audio and video, we must seek the video
-    // stream to the preceeding keyframe first, get the stream time, and then
-    // seek the audio stream to match the video stream's time. Otherwise, the
-    // audio and video streams won't be in sync after the seek.
-    mVideoSeekTimeUs = aTarget;
-    const VideoData* v = DecodeToFirstVideoData();
-    mAudioSeekTimeUs = v ? v->mTime : aTarget;
-  } else {
-    mAudioSeekTimeUs = mVideoSeekTimeUs = aTarget;
-  }
-
-  return NS_OK;
-}
-
-void MediaOmxReader::SetIdle() {
-  if (!mOmxDecoder.get()) {
-    return;
-  }
-  mOmxDecoder->Pause();
-}
-
-void MediaOmxReader::EnsureActive() {
-  if (!mOmxDecoder.get()) {
-    return;
-  }
-  DebugOnly<nsresult> result = mOmxDecoder->Play();
-  NS_ASSERTION(result == NS_OK, "OmxDecoder should be in play state to continue decoding");
-}
-
-#ifdef MOZ_AUDIO_OFFLOAD
-void MediaOmxReader::CheckAudioOffload()
+void MediaOmxCommonReader::CheckAudioOffload()
 {
   NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
 
   char offloadProp[128];
   property_get("audio.offload.disable", offloadProp, "0");
   bool offloadDisable =  atoi(offloadProp) != 0;
   if (offloadDisable) {
     return;
   }
 
-  mAudioOffloadTrack = mOmxDecoder->GetAudioOffloadTrack();
-  sp<MetaData> meta = (mAudioOffloadTrack.get()) ?
-      mAudioOffloadTrack->getFormat() : nullptr;
+  sp<MediaSource> audioOffloadTrack = GetAudioOffloadTrack();
+  sp<MetaData> meta = audioOffloadTrack.get()
+      ? audioOffloadTrack->getFormat() : nullptr;
 
   // Supporting audio offload only when there is no video, no streaming
-  bool hasNoVideo = !mOmxDecoder->HasVideo();
+  bool hasNoVideo = !HasVideo();
   bool isNotStreaming
       = mDecoder->GetResource()->IsDataCachedToEndOfResource(0);
 
   // Not much benefit in trying to offload other channel types. Most of them
   // aren't supported and also duration would be less than a minute
   bool isTypeMusic = mAudioChannel == dom::AudioChannel::Content;
 
   DECODER_LOG(PR_LOG_DEBUG, ("%s meta %p, no video %d, no streaming %d,"
copy from content/media/omx/MediaOmxReader.h
copy to content/media/omx/MediaOmxCommonReader.h
--- a/content/media/omx/MediaOmxReader.h
+++ b/content/media/omx/MediaOmxCommonReader.h
@@ -1,113 +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/. */
-#if !defined(MediaOmxReader_h_)
-#define MediaOmxReader_h_
 
-#include "MediaResource.h"
+#ifndef MEDIA_OMX_COMMON_READER_H
+#define MEDIA_OMX_COMMON_READER_H
+
 #include "MediaDecoderReader.h"
-#include "nsRect.h"
+
+#include <utils/RefBase.h>
+
 #include "mozilla/dom/AudioChannelBinding.h"
-#include <ui/GraphicBuffer.h>
-#include <stagefright/MediaSource.h>
 
 namespace android {
-class OmxDecoder;
-class MOZ_EXPORT MediaExtractor;
-}
+struct MOZ_EXPORT MediaSource;
+} // namespace android
 
 namespace mozilla {
 
-namespace dom {
-  class TimeRanges;
-}
-
 class AbstractMediaDecoder;
 
-class MediaOmxReader : public MediaDecoderReader
+class MediaOmxCommonReader : public MediaDecoderReader
 {
-  nsCString mType;
-  bool mHasVideo;
-  bool mHasAudio;
-  nsIntRect mPicture;
-  nsIntSize mInitialFrame;
-  int64_t mVideoSeekTimeUs;
-  int64_t mAudioSeekTimeUs;
-  int32_t mSkipCount;
-  dom::AudioChannel mAudioChannel;
-  android::sp<android::MediaSource> mAudioOffloadTrack;
-
-protected:
-  android::sp<android::OmxDecoder> mOmxDecoder;
-  android::sp<android::MediaExtractor> mExtractor;
-
-  // Called by ReadMetadata() during MediaDecoderStateMachine::DecodeMetadata()
-  // on decode thread. It create and initialize the OMX decoder including
-  // setting up custom extractor. The extractor provide the essential
-  // information used for creating OMX decoder such as video/audio codec.
-  virtual nsresult InitOmxDecoder();
-
-  // Called inside DecodeVideoFrame, DecodeAudioData, ReadMetadata and Seek
-  // to activate the decoder automatically.
-  virtual void EnsureActive();
-
 public:
-  MediaOmxReader(AbstractMediaDecoder* aDecoder);
-  ~MediaOmxReader();
-
-  virtual nsresult Init(MediaDecoderReader* aCloneDonor);
-
-  virtual void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset);
-
-  virtual bool DecodeAudioData();
-  virtual bool DecodeVideoFrame(bool &aKeyframeSkip,
-                                int64_t aTimeThreshold);
-
-  virtual bool HasAudio()
-  {
-    return mHasAudio;
-  }
-
-  virtual bool HasVideo()
-  {
-    return mHasVideo;
-  }
-
-  virtual bool IsWaitingMediaResources();
-
-  virtual bool IsDormantNeeded();
-  virtual void ReleaseMediaResources();
-
-  virtual nsresult ReadMetadata(MediaInfo* aInfo,
-                                MetadataTags** aTags);
-  virtual nsresult Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime);
-
-  virtual bool IsMediaSeekable() MOZ_OVERRIDE;
-
-  virtual void SetIdle() MOZ_OVERRIDE;
-
-  virtual void Shutdown() MOZ_OVERRIDE;
+  MediaOmxCommonReader(AbstractMediaDecoder* aDecoder);
 
   void SetAudioChannel(dom::AudioChannel aAudioChannel) {
     mAudioChannel = aAudioChannel;
   }
 
-  android::sp<android::MediaSource> GetAudioOffloadTrack() {
-    return mAudioOffloadTrack;
-  }
+  virtual android::sp<android::MediaSource> GetAudioOffloadTrack() = 0;
 
 #ifdef MOZ_AUDIO_OFFLOAD
   // Check whether it is possible to offload current audio track. This access
   // canOffloadStream() from libStageFright Utils.cpp, which is not there in
   // ANDROID_VERSION < 19
   void CheckAudioOffload();
 #endif
 
-  void ReleaseDecoder();
+protected:
+  dom::AudioChannel mAudioChannel;
 };
 
 } // namespace mozilla
 
-#endif
+#endif // MEDIA_OMX_COMMON_READER_H
old mode 100755
new mode 100644
--- a/content/media/omx/MediaOmxDecoder.cpp
+++ b/content/media/omx/MediaOmxDecoder.cpp
@@ -2,246 +2,32 @@
 /* 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 "MediaOmxDecoder.h"
 #include "MediaOmxReader.h"
 #include "MediaDecoderStateMachine.h"
-#include "VideoUtils.h"
-
-#include "OmxDecoder.h"
-
-#ifdef MOZ_AUDIO_OFFLOAD
-#include "AudioOffloadPlayer.h"
-#endif
 
 using namespace android;
 
 namespace mozilla {
 
-#ifdef PR_LOGGING
-extern PRLogModuleInfo* gMediaDecoderLog;
-#define DECODER_LOG(type, msg) PR_LOG(gMediaDecoderLog, type, msg)
-#else
-#define DECODER_LOG(type, msg)
-#endif
-
-MediaOmxDecoder::MediaOmxDecoder() :
-  MediaDecoder(),
-  mCanOffloadAudio(false),
-  mFallbackToStateMachine(false)
-{
-#ifdef PR_LOGGING
-  if (!gMediaDecoderLog) {
-    gMediaDecoderLog = PR_NewLogModule("MediaDecoder");
-  }
-#endif
-}
-
-MediaDecoder* MediaOmxDecoder::Clone()
+MediaDecoder*
+MediaOmxDecoder::Clone()
 {
   return new MediaOmxDecoder();
 }
 
-MediaDecoderStateMachine* MediaOmxDecoder::CreateStateMachine()
-{
-  mReader = new MediaOmxReader(this);
-  mReader->SetAudioChannel(GetAudioChannel());
-  return new MediaDecoderStateMachine(this, mReader);
-}
-
-void MediaOmxDecoder::SetCanOffloadAudio(bool aCanOffloadAudio)
-{
-  ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
-  mCanOffloadAudio = aCanOffloadAudio;
-}
-
-void MediaOmxDecoder::MetadataLoaded(MediaInfo* aInfo,
-                                     MetadataTags* aTags)
+MediaOmxCommonReader*
+MediaOmxDecoder::CreateReader()
 {
-  MOZ_ASSERT(NS_IsMainThread());
-  MediaDecoder::MetadataLoaded(aInfo, aTags);
-
-  ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
-  if (!mCanOffloadAudio || mFallbackToStateMachine || mOutputStreams.Length() ||
-      mInitialPlaybackRate != 1.0) {
-    DECODER_LOG(PR_LOG_DEBUG, ("In %s Offload Audio check failed",
-        __PRETTY_FUNCTION__));
-    return;
-  }
-
-#ifdef MOZ_AUDIO_OFFLOAD
-  mAudioOffloadPlayer = new AudioOffloadPlayer(this);
-#endif
-  mAudioOffloadPlayer->SetSource(mReader->GetAudioOffloadTrack());
-  status_t err = mAudioOffloadPlayer->Start(false);
-  if (err == OK) {
-    PauseStateMachine();
-    // Call ChangeState() to run AudioOffloadPlayer since offload state enabled
-    ChangeState(mPlayState);
-    return;
-  }
-
-  mAudioOffloadPlayer = nullptr;
-  DECODER_LOG(PR_LOG_DEBUG, ("In %s Unable to start offload audio %d."
-      "Switching to normal mode", __PRETTY_FUNCTION__, err));
-}
-
-void MediaOmxDecoder::PauseStateMachine()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  GetReentrantMonitor().AssertCurrentThreadIn();
-  DECODER_LOG(PR_LOG_DEBUG, ("%s", __PRETTY_FUNCTION__));
-  if (!mDecoderStateMachine) {
-    return;
-  }
-  StopProgress();
-  mDecoderStateMachine->SetDormant(true);
-}
-
-void MediaOmxDecoder::ResumeStateMachine()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
-  DECODER_LOG(PR_LOG_DEBUG, ("%s current time %f", __PRETTY_FUNCTION__,
-      mCurrentTime));
-
-  if (!mDecoderStateMachine) {
-    return;
-  }
-
-  mFallbackToStateMachine = true;
-  mAudioOffloadPlayer = nullptr;
-  int64_t timeUsecs = 0;
-  SecondsToUsecs(mCurrentTime, timeUsecs);
-  mRequestedSeekTarget = SeekTarget(timeUsecs, SeekTarget::Accurate);
-
-  mNextState = mPlayState;
-  ChangeState(PLAY_STATE_LOADING);
-  mDecoderStateMachine->SetDormant(false);
-}
-
-void MediaOmxDecoder::AudioOffloadTearDown()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  DECODER_LOG(PR_LOG_DEBUG, ("%s", __PRETTY_FUNCTION__));
-
-  // mAudioOffloadPlayer can be null here if ResumeStateMachine was called
-  // just before because of some other error.
-  if (mAudioOffloadPlayer) {
-    // Audio offload player sent tear down event. Fallback to state machine
-    PlaybackPositionChanged();
-    ResumeStateMachine();
-  }
+  return new MediaOmxReader(this);
 }
 
-void MediaOmxDecoder::AddOutputStream(ProcessedMediaStream* aStream,
-                                      bool aFinishWhenEnded)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  if (mAudioOffloadPlayer) {
-    // Offload player cannot handle MediaStream. Fallback
-    PlaybackPositionChanged();
-    ResumeStateMachine();
-  }
-
-  MediaDecoder::AddOutputStream(aStream, aFinishWhenEnded);
-}
-
-void MediaOmxDecoder::SetPlaybackRate(double aPlaybackRate)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  if (mAudioOffloadPlayer &&
-      ((aPlaybackRate != 0.0) || (aPlaybackRate != 1.0))) {
-    // Offload player cannot handle playback rate other than 1/0. Fallback
-    PlaybackPositionChanged();
-    ResumeStateMachine();
-  }
-
-  MediaDecoder::SetPlaybackRate(aPlaybackRate);
-}
-
-void MediaOmxDecoder::ChangeState(PlayState aState)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  // Keep MediaDecoder state in sync with MediaElement irrespective of offload
-  // playback so it will continue to work in normal mode when offloading fails
-  // in between
-  MediaDecoder::ChangeState(aState);
-
-  if (mAudioOffloadPlayer) {
-    status_t err = mAudioOffloadPlayer->ChangeState(aState);
-    if (err != OK) {
-      ResumeStateMachine();
-    }
-  }
-}
-
-void MediaOmxDecoder::ApplyStateToStateMachine(PlayState aState)
+MediaDecoderStateMachine*
+MediaOmxDecoder::CreateStateMachine(MediaOmxCommonReader* aReader)
 {
-  MOZ_ASSERT(NS_IsMainThread());
-  // During offload playback, state machine should be in dormant state.
-  // ApplyStateToStateMachine() can change state machine state to
-  // something else or reset the seek time. So don't call this when audio is
-  // offloaded
-  if (!mAudioOffloadPlayer) {
-    MediaDecoder::ApplyStateToStateMachine(aState);
-  }
-}
-
-void MediaOmxDecoder::PlaybackPositionChanged()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  if (!mAudioOffloadPlayer) {
-    MediaDecoder::PlaybackPositionChanged();
-    return;
-  }
-
-  if (!mOwner || mShuttingDown) {
-    return;
-  }
-
-  double lastTime = mCurrentTime;
-  {
-    ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
-    mCurrentTime = mAudioOffloadPlayer->GetMediaTimeSecs();
-  }
-  if (mOwner && lastTime != mCurrentTime) {
-    FireTimeUpdate();
-  }
-}
-
-void MediaOmxDecoder::SetElementVisibility(bool aIsVisible)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  if (mAudioOffloadPlayer) {
-    mAudioOffloadPlayer->SetElementVisibility(aIsVisible);
-  }
-}
-
-void MediaOmxDecoder::UpdateReadyStateForData()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  if (!mAudioOffloadPlayer) {
-    MediaDecoder::UpdateReadyStateForData();
-    return;
-  }
-
-  if (!mOwner || mShuttingDown)
-    return;
-  mOwner->UpdateReadyStateForData(mAudioOffloadPlayer->GetNextFrameStatus());
-}
-
-void MediaOmxDecoder::SetVolume(double aVolume)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  if (!mAudioOffloadPlayer) {
-    MediaDecoder::SetVolume(aVolume);
-    return;
-  }
-  mAudioOffloadPlayer->SetVolume(aVolume);
+  return new MediaDecoderStateMachine(this, aReader);
 }
 
 } // namespace mozilla
old mode 100755
new mode 100644
--- a/content/media/omx/MediaOmxDecoder.h
+++ b/content/media/omx/MediaOmxDecoder.h
@@ -1,62 +1,23 @@
 /* -*- 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/. */
 #if !defined(MediaOmxDecoder_h_)
 #define MediaOmxDecoder_h_
 
-#include "base/basictypes.h"
-#include "MediaDecoder.h"
-#include "MediaOmxReader.h"
-#include "AudioOffloadPlayerBase.h"
+#include "MediaOmxCommonDecoder.h"
 
 namespace mozilla {
 
-class MediaOmxDecoder : public MediaDecoder
+class MediaOmxDecoder : public MediaOmxCommonDecoder
 {
-  typedef android::MediaSource MediaSource;
 public:
-  MediaOmxDecoder();
   virtual MediaDecoder* Clone();
-  virtual MediaDecoderStateMachine* CreateStateMachine();
-
-  virtual void MetadataLoaded(MediaInfo* aInfo,
-                              MetadataTags* aTags);
-  virtual void ChangeState(PlayState aState);
-  virtual void ApplyStateToStateMachine(PlayState aState);
-  virtual void SetVolume(double aVolume);
-  virtual void PlaybackPositionChanged();
-  virtual void UpdateReadyStateForData();
-  virtual void SetElementVisibility(bool aIsVisible);
-  virtual void SetCanOffloadAudio(bool aCanOffloadAudio);
-  virtual void AddOutputStream(ProcessedMediaStream* aStream,
-                               bool aFinishWhenEnded);
-  virtual void SetPlaybackRate(double aPlaybackRate);
-
-  void AudioOffloadTearDown();
-  int64_t GetSeekTime() { return mRequestedSeekTarget.mTime; }
-  void ResetSeekTime() { mRequestedSeekTarget.Reset(); }
-
-private:
-  void PauseStateMachine();
-  void ResumeStateMachine();
-
-  MediaOmxReader* mReader;
-
-  // Offloaded audio track
-  android::sp<MediaSource> mAudioTrack;
-
-  nsAutoPtr<AudioOffloadPlayerBase> mAudioOffloadPlayer;
-
-  // Set by MediaOmxReader to denote current track can be offloaded
-  bool mCanOffloadAudio;
-
-  // Set when offload playback of current track fails in the middle and need to
-  // fallback to state machine
-  bool mFallbackToStateMachine;
+  virtual MediaOmxCommonReader* CreateReader();
+  virtual MediaDecoderStateMachine* CreateStateMachine(MediaOmxCommonReader* aReader);
 };
 
 } // namespace mozilla
 
 #endif
--- a/content/media/omx/MediaOmxReader.cpp
+++ b/content/media/omx/MediaOmxReader.cpp
@@ -14,22 +14,16 @@
 #include "MediaOmxDecoder.h"
 #include "AbstractMediaDecoder.h"
 #include "AudioChannelService.h"
 #include "OmxDecoder.h"
 #include "MPAPI.h"
 #include "gfx2DGlue.h"
 #include "MediaStreamSource.h"
 
-#ifdef MOZ_AUDIO_OFFLOAD
-#include <stagefright/Utils.h>
-#include <cutils/properties.h>
-#include <stagefright/MetaData.h>
-#endif
-
 #define MAX_DROPPED_FRAMES 25
 // Try not to spend more than this much time in a single call to DecodeVideoFrame.
 #define MAX_VIDEO_DECODE_SECONDS 0.1
 
 using namespace mozilla::gfx;
 using namespace android;
 
 namespace mozilla {
@@ -37,17 +31,17 @@ namespace mozilla {
 #ifdef PR_LOGGING
 extern PRLogModuleInfo* gMediaDecoderLog;
 #define DECODER_LOG(type, msg) PR_LOG(gMediaDecoderLog, type, msg)
 #else
 #define DECODER_LOG(type, msg)
 #endif
 
 MediaOmxReader::MediaOmxReader(AbstractMediaDecoder *aDecoder)
-  : MediaDecoderReader(aDecoder)
+  : MediaOmxCommonReader(aDecoder)
   , mHasVideo(false)
   , mHasAudio(false)
   , mVideoSeekTimeUs(-1)
   , mAudioSeekTimeUs(-1)
   , mSkipCount(0)
 {
 #ifdef PR_LOGGING
   if (!gMediaDecoderLog) {
@@ -420,46 +414,17 @@ void MediaOmxReader::SetIdle() {
 void MediaOmxReader::EnsureActive() {
   if (!mOmxDecoder.get()) {
     return;
   }
   DebugOnly<nsresult> result = mOmxDecoder->Play();
   NS_ASSERTION(result == NS_OK, "OmxDecoder should be in play state to continue decoding");
 }
 
-#ifdef MOZ_AUDIO_OFFLOAD
-void MediaOmxReader::CheckAudioOffload()
+android::sp<android::MediaSource> MediaOmxReader::GetAudioOffloadTrack()
 {
-  NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
-
-  char offloadProp[128];
-  property_get("audio.offload.disable", offloadProp, "0");
-  bool offloadDisable =  atoi(offloadProp) != 0;
-  if (offloadDisable) {
-    return;
+  if (!mOmxDecoder.get()) {
+    return nullptr;
   }
-
-  mAudioOffloadTrack = mOmxDecoder->GetAudioOffloadTrack();
-  sp<MetaData> meta = (mAudioOffloadTrack.get()) ?
-      mAudioOffloadTrack->getFormat() : nullptr;
-
-  // Supporting audio offload only when there is no video, no streaming
-  bool hasNoVideo = !mOmxDecoder->HasVideo();
-  bool isNotStreaming
-      = mDecoder->GetResource()->IsDataCachedToEndOfResource(0);
-
-  // Not much benefit in trying to offload other channel types. Most of them
-  // aren't supported and also duration would be less than a minute
-  bool isTypeMusic = mAudioChannel == dom::AudioChannel::Content;
-
-  DECODER_LOG(PR_LOG_DEBUG, ("%s meta %p, no video %d, no streaming %d,"
-      " channel type %d", __FUNCTION__, meta.get(), hasNoVideo,
-      isNotStreaming, mAudioChannel));
-
-  if ((meta.get()) && hasNoVideo && isNotStreaming && isTypeMusic &&
-      canOffloadStream(meta, false, false, AUDIO_STREAM_MUSIC)) {
-    DECODER_LOG(PR_LOG_DEBUG, ("Can offload this audio stream"));
-    mDecoder->SetCanOffloadAudio(true);
-  }
+  return mOmxDecoder->GetAudioOffloadTrack();
 }
-#endif
 
 } // namespace mozilla
--- a/content/media/omx/MediaOmxReader.h
+++ b/content/media/omx/MediaOmxReader.h
@@ -1,48 +1,46 @@
 /* -*- 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/. */
 #if !defined(MediaOmxReader_h_)
 #define MediaOmxReader_h_
 
+#include "MediaOmxCommonReader.h"
 #include "MediaResource.h"
 #include "MediaDecoderReader.h"
 #include "nsRect.h"
-#include "mozilla/dom/AudioChannelBinding.h"
 #include <ui/GraphicBuffer.h>
 #include <stagefright/MediaSource.h>
 
 namespace android {
 class OmxDecoder;
 class MOZ_EXPORT MediaExtractor;
 }
 
 namespace mozilla {
 
 namespace dom {
   class TimeRanges;
 }
 
 class AbstractMediaDecoder;
 
-class MediaOmxReader : public MediaDecoderReader
+class MediaOmxReader : public MediaOmxCommonReader
 {
   nsCString mType;
   bool mHasVideo;
   bool mHasAudio;
   nsIntRect mPicture;
   nsIntSize mInitialFrame;
   int64_t mVideoSeekTimeUs;
   int64_t mAudioSeekTimeUs;
   int32_t mSkipCount;
-  dom::AudioChannel mAudioChannel;
-  android::sp<android::MediaSource> mAudioOffloadTrack;
 
 protected:
   android::sp<android::OmxDecoder> mOmxDecoder;
   android::sp<android::MediaExtractor> mExtractor;
 
   // Called by ReadMetadata() during MediaDecoderStateMachine::DecodeMetadata()
   // on decode thread. It create and initialize the OMX decoder including
   // setting up custom extractor. The extractor provide the essential
@@ -85,29 +83,16 @@ public:
   virtual nsresult Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime);
 
   virtual bool IsMediaSeekable() MOZ_OVERRIDE;
 
   virtual void SetIdle() MOZ_OVERRIDE;
 
   virtual void Shutdown() MOZ_OVERRIDE;
 
-  void SetAudioChannel(dom::AudioChannel aAudioChannel) {
-    mAudioChannel = aAudioChannel;
-  }
-
-  android::sp<android::MediaSource> GetAudioOffloadTrack() {
-    return mAudioOffloadTrack;
-  }
+  void ReleaseDecoder();
 
-#ifdef MOZ_AUDIO_OFFLOAD
-  // Check whether it is possible to offload current audio track. This access
-  // canOffloadStream() from libStageFright Utils.cpp, which is not there in
-  // ANDROID_VERSION < 19
-  void CheckAudioOffload();
-#endif
-
-  void ReleaseDecoder();
+  android::sp<android::MediaSource> GetAudioOffloadTrack();
 };
 
 } // namespace mozilla
 
 #endif
--- a/content/media/omx/moz.build
+++ b/content/media/omx/moz.build
@@ -1,21 +1,25 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 EXPORTS += [
     'AudioOffloadPlayerBase.h',
+    'MediaOmxCommonDecoder.h',
+    'MediaOmxCommonReader.h',
     'MediaOmxDecoder.h',
     'MediaOmxReader.h',
 ]
 
 SOURCES += [
+    'MediaOmxCommonDecoder.cpp',
+    'MediaOmxCommonReader.cpp',
     'MediaOmxDecoder.cpp',
     'MediaOmxReader.cpp',
     'MediaStreamSource.cpp',
     'OMXCodecProxy.cpp',
     'OmxDecoder.cpp',
 ]
 
 if CONFIG['MOZ_AUDIO_OFFLOAD']:
--- a/docshell/base/nsDSURIContentListener.cpp
+++ b/docshell/base/nsDSURIContentListener.cpp
@@ -15,26 +15,28 @@
 #include "nsAutoPtr.h"
 #include "nsIHttpChannel.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsError.h"
 #include "nsCharSeparatedTokenizer.h"
 #include "nsIConsoleService.h"
 #include "nsIScriptError.h"
 #include "nsDocShellLoadTypes.h"
+#include "nsIMultiPartChannel.h"
 
 using namespace mozilla;
 
 //*****************************************************************************
 //***    nsDSURIContentListener: Object Management
 //*****************************************************************************
 
 nsDSURIContentListener::nsDSURIContentListener(nsDocShell* aDocShell)
-    : mDocShell(aDocShell), 
-      mParentContentListener(nullptr)
+    : mDocShell(aDocShell)
+    , mExistingJPEGRequest(nullptr)
+    , mParentContentListener(nullptr)
 {
 }
 
 nsDSURIContentListener::~nsDSURIContentListener()
 {
 }
 
 nsresult
@@ -113,18 +115,43 @@ nsDSURIContentListener::DoContent(const 
 
     if(loadFlags & nsIChannel::LOAD_RETARGETED_DOCUMENT_URI)
     {
         // XXX: Why does this not stop the content too?
         mDocShell->Stop(nsIWebNavigation::STOP_NETWORK);
 
         mDocShell->SetLoadType(aIsContentPreferred ? LOAD_LINK : LOAD_NORMAL);
     }
+  
+    // In case of multipart jpeg request (mjpeg) we don't really want to
+    // create new viewer since the one we already have is capable of
+    // rendering multipart jpeg correctly (see bug 625012)
+    nsCOMPtr<nsIChannel> baseChannel;
+    if (nsCOMPtr<nsIMultiPartChannel> mpchan = do_QueryInterface(request)) {
+        mpchan->GetBaseChannel(getter_AddRefs(baseChannel));
+    }
 
-    rv = mDocShell->CreateContentViewer(aContentType, request, aContentHandler);
+    bool reuseCV = baseChannel
+        && baseChannel == mExistingJPEGRequest
+        && nsDependentCString(aContentType).EqualsLiteral("image/jpeg");
+
+    if (mExistingJPEGStreamListener && reuseCV) {
+        nsRefPtr<nsIStreamListener> copy(mExistingJPEGStreamListener);
+        copy.forget(aContentHandler);
+        rv = NS_OK;
+    } else {
+        rv = mDocShell->CreateContentViewer(aContentType, request, aContentHandler);
+        if (NS_SUCCEEDED(rv) && reuseCV) {
+           mExistingJPEGStreamListener = *aContentHandler;
+        } else {
+           mExistingJPEGStreamListener = nullptr;
+        }
+        mExistingJPEGRequest = baseChannel;
+    }
+
 
     if (rv == NS_ERROR_REMOTE_XUL) {
       request->Cancel(rv);
       *aAbortProcess = true;
       return NS_OK;
     }
 
     if (NS_FAILED(rv)) { 
--- a/docshell/base/nsDSURIContentListener.h
+++ b/docshell/base/nsDSURIContentListener.h
@@ -29,16 +29,18 @@ public:
     nsresult Init();
 
 protected:
     explicit nsDSURIContentListener(nsDocShell* aDocShell);
     virtual ~nsDSURIContentListener();
 
     void DropDocShellreference() {
         mDocShell = nullptr;
+        mExistingJPEGRequest = nullptr;
+        mExistingJPEGStreamListener = nullptr;
     }
 
     // Determine if X-Frame-Options allows content to be framed
     // as a subdocument
     bool CheckFrameOptions(nsIRequest* request);
     bool CheckOneFrameOptionsPolicy(nsIHttpChannel* httpChannel,
                                     const nsAString& policy);
 
@@ -48,16 +50,19 @@ protected:
       eALLOWFROM
     };
 
     void ReportXFOViolation(nsIDocShellTreeItem* aTopDocShellItem,
                             nsIURI* aThisURI,
                             XFOHeader aHeader);
 protected:
     nsDocShell*                      mDocShell;
+    // Hack to handle multipart images without creating a new viewer
+    nsCOMPtr<nsIStreamListener>      mExistingJPEGStreamListener;
+    nsCOMPtr<nsIChannel>             mExistingJPEGRequest;
 
     // Store the parent listener in either of these depending on
     // if supports weak references or not. Proper weak refs are
     // preferred and encouraged!
     nsWeakPtr                        mWeakParentContentListener;
     nsIURIContentListener*           mParentContentListener;
 
     nsCOMPtr<nsIWebNavigationInfo>   mNavInfo;
--- a/dom/camera/GonkCameraHwMgr.cpp
+++ b/dom/camera/GonkCameraHwMgr.cpp
@@ -53,17 +53,17 @@ GonkCameraHardware::OnRateLimitPreview(b
 void
 GonkCameraHardware::OnNewFrame()
 {
   if (mClosing) {
     return;
   }
   RefPtr<TextureClient> buffer = mNativeWindow->getCurrentBuffer();
   if (!buffer) {
-    DOM_CAMERA_LOGW("received null frame");
+    DOM_CAMERA_LOGE("received null frame");
     return;
   }
   OnNewPreviewFrame(mTarget, buffer);
 }
 
 // Android data callback
 void
 GonkCameraHardware::postData(int32_t aMsgType, const sp<IMemory>& aDataPtr, camera_frame_metadata_t* metadata)
@@ -180,19 +180,23 @@ GonkCameraHardware::Init()
 
   // Disable shutter sound in android CameraService because gaia camera app will play it
   mCamera->sendCommand(CAMERA_CMD_ENABLE_SHUTTER_SOUND, 0, 0);
 
 #if defined(MOZ_WIDGET_GONK)
 
 #if ANDROID_VERSION >= 19
   mNativeWindow = new GonkNativeWindow(GonkCameraHardware::MIN_UNDEQUEUED_BUFFERS);
+  sp<GonkBufferQueue> bq = mNativeWindow->getBufferQueue();
+  bq->setSynchronousMode(false);
   mCamera->setPreviewTarget(mNativeWindow->getBufferQueue());
 #elif ANDROID_VERSION >= 17
   mNativeWindow = new GonkNativeWindow(GonkCameraHardware::MIN_UNDEQUEUED_BUFFERS);
+  sp<GonkBufferQueue> bq = mNativeWindow->getBufferQueue();
+  bq->setSynchronousMode(false);
   mCamera->setPreviewTexture(mNativeWindow->getBufferQueue());
 #else
   mNativeWindow = new GonkNativeWindow();
   mCamera->setPreviewTexture(mNativeWindow);
 #endif
   mNativeWindow->setNewFrameCallback(this);
   mCamera->setListener(this);
 
--- a/editor/composer/moz.build
+++ b/editor/composer/moz.build
@@ -22,19 +22,16 @@ UNIFIED_SOURCES += [
     'nsEditingSession.cpp',
     'nsEditorSpellCheck.cpp',
 ]
 
 FAIL_ON_WARNINGS = True
 
 FINAL_LIBRARY = 'xul'
 RESOURCE_FILES += [
-    'res/caret_left.svg',
-    'res/caret_middle.svg',
-    'res/caret_right.svg',
     'res/EditorOverride.css',
     'res/grabber.gif',
     'res/table-add-column-after-active.gif',
     'res/table-add-column-after-hover.gif',
     'res/table-add-column-after.gif',
     'res/table-add-column-before-active.gif',
     'res/table-add-column-before-hover.gif',
     'res/table-add-column-before.gif',
@@ -45,9 +42,24 @@ RESOURCE_FILES += [
     'res/table-add-row-before-hover.gif',
     'res/table-add-row-before.gif',
     'res/table-remove-column-active.gif',
     'res/table-remove-column-hover.gif',
     'res/table-remove-column.gif',
     'res/table-remove-row-active.gif',
     'res/table-remove-row-hover.gif',
     'res/table-remove-row.gif',
+    'res/text_caret.png',
+    'res/text_caret@1.5x.png',
+    'res/text_caret@2.25x.png',
+    'res/text_caret@2x.png',
+    'res/text_caret_tilt_left.png',
+    'res/text_caret_tilt_left@1.5x.png',
+    'res/text_caret_tilt_left@2.25x.png',
+    'res/text_caret_tilt_left@2x.png',
+    'res/text_caret_tilt_right.png',
+    'res/text_caret_tilt_right@1.5x.png',
+    'res/text_caret_tilt_right@2.25x.png',
+    'res/text_caret_tilt_right@2x.png',
+    'res/text_selection_handle.png',
+    'res/text_selection_handle@1.5.png',
+    'res/text_selection_handle@2.png',
 ]
deleted file mode 100644
--- a/editor/composer/res/caret_left.svg
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1"?>
-<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
-     width="29px" height="31px" viewBox="0 0 29 31" style="enable-background:new 0 0 29 31;" xml:space="preserve">
-  <!-- TODO: Enable shadow after bug 1015575 is resolved.
-  <defs>
-    <filter id="caretFilter">
-      <feOffset result="offsetOut" in="SourceAlpha" dx="1" dy="1" />
-      <feGaussianBlur result="blurOut" in="offsetOut" stdDeviation="0.5" />
-      <feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
-    </filter>
-  </defs>
-  <g fill="#2da9e3" filter="url(#caretFilter)">
-  -->
-  <g fill="#2da9e3">
-    <path d="M25.368,2.674c-0.049,0.104-0.09,0.209-0.134,0.314C25.304,2.893,25.347,2.786,25.368,2.674z"/>
-    <path d="M24.27,1.734c0.003-0.001,0.008-0.003,0.013-0.004C24.277,1.73,24.272,1.733,24.27,1.734z"/>
-    <path d="M24.583,8.574C24.25,6.7,24.478,4.755,25.234,2.989c0.044-0.105,0.085-0.21,0.134-0.314
-             c0.053-0.254-0.016-0.528-0.204-0.73c-0.232-0.249-0.581-0.322-0.882-0.215c-0.005,0.001-0.01,0.003-0.013,0.004
-             c-1.915,0.71-4.001,0.798-5.954,0.277C15.015,0.898,11.222,1.587,8.5,4.134c-3.947,3.691-4.155,9.882-0.464,13.828
-             c3.691,3.947,9.881,4.154,13.828,0.462C24.64,15.828,25.562,11.994,24.583,8.574z"/>
-  </g>
-</svg>
deleted file mode 100644
--- a/editor/composer/res/caret_middle.svg
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1"?>
-<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
-     width="29px" height="31px" style="enable-background:new 0 0 29 31;" xml:space="preserve">
-  <!-- TODO: Enable shadow after bug 1015575 is resolved.
-  <defs>
-    <filter id="caretFilter">
-      <feOffset result="offsetOut" in="SourceAlpha" dx="1" dy="1" />
-      <feGaussianBlur result="blurOut" in="offsetOut" stdDeviation="0.5" />
-      <feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
-    </filter>
-  </defs>
-  <g fill="#2da9e3" filter="url(#caretFilter)">
-  -->
-  <g fill="#2da9e3">
-    <path d="M15.174,1.374c0.042,0.106,0.091,0.208,0.138,0.312C15.288,1.57,15.239,1.466,15.174,1.374z"/>
-    <path d="M13.735,1.534c0.002-0.003,0.004-0.009,0.006-0.013C13.739,1.525,13.737,1.531,13.735,1.534z"/>
-    <path d="M18.945,5.978c-1.596-1.038-2.861-2.532-3.634-4.292c-0.047-0.104-0.096-0.206-0.138-0.312
-             c-0.15-0.212-0.396-0.349-0.674-0.349c-0.34,0-0.631,0.204-0.759,0.497c-0.002,0.004-0.004,0.009-0.006,0.013
-             c-0.789,1.883-2.149,3.467-3.864,4.538c-3.068,1.651-5.155,4.892-5.155,8.62c0,5.404,4.379,9.784,9.783,9.784
-             c5.403,0,9.783-4.38,9.783-9.784C24.283,10.891,22.113,7.598,18.945,5.978z"/>
-  </g>
-</svg>
deleted file mode 100644
--- a/editor/composer/res/caret_right.svg
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1"?>
-<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
-     width="29px" height="31px" viewBox="0 0 29 31" style="enable-background:new 0 0 29 31;" xml:space="preserve">
-  <!-- TODO: Enable shadow after bug 1015575 is resolved.
-  <defs>
-    <filter id="caretFilter">
-      <feOffset result="offsetOut" in="SourceAlpha" dx="1" dy="1" />
-      <feGaussianBlur result="blurOut" in="offsetOut" stdDeviation="0.5" />
-      <feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
-    </filter>
-  </defs>
-  <g fill="#2da9e3" filter="url(#caretFilter)">
-  -->
-  <g fill="#2da9e3">
-    <path fill="#2da9e3" d="M27.296,2.674c-0.049,0.104-0.09,0.209-0.134,0.314C27.231,2.893,27.274,2.786,27.296,2.674z"/>
-    <path fill="#2da9e3" d="M26.197,1.734C26.2,1.733,26.205,1.73,26.21,1.729C26.205,1.73,26.2,1.733,26.197,1.734z"/>
-    <path fill="#2da9e3" d="M4.299,8.574C4.632,6.7,4.404,4.755,3.647,2.989c-0.044-0.105-0.085-0.21-0.134-0.314C3.461,2.42,3.529,2.146,3.718,1.944
-                            C3.95,1.696,4.299,1.623,4.6,1.729c0.005,0.001,0.01,0.003,0.013,0.004c1.915,0.71,4.001,0.798,5.954,0.277
-                            c3.301-1.113,7.094-0.423,9.815,2.123c3.947,3.691,4.156,9.882,0.465,13.828c-3.691,3.947-9.881,4.154-13.828,0.462
-                            C4.242,15.828,3.319,11.994,4.299,8.574z"/>
-  </g>
-</svg>
--- a/editor/crashtests.list
+++ b/editor/crashtests.list
@@ -1,9 +1,9 @@
 # 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 libeditor/html/crashtests/crashtests.list
-include libeditor/base/crashtests/crashtests.list
+include libeditor/crashtests/crashtests.list
 include libeditor/text/crashtests/crashtests.list
 include composer/crashtests/crashtests.list
 include txmgr/tests/crashtests/crashtests.list
rename from editor/libeditor/base/ChangeAttributeTxn.cpp
rename to editor/libeditor/ChangeAttributeTxn.cpp
rename from editor/libeditor/base/ChangeAttributeTxn.h
rename to editor/libeditor/ChangeAttributeTxn.h
rename from editor/libeditor/base/ChangeCSSInlineStyleTxn.cpp
rename to editor/libeditor/ChangeCSSInlineStyleTxn.cpp
rename from editor/libeditor/base/ChangeCSSInlineStyleTxn.h
rename to editor/libeditor/ChangeCSSInlineStyleTxn.h
rename from editor/libeditor/base/CreateElementTxn.cpp
rename to editor/libeditor/CreateElementTxn.cpp
rename from editor/libeditor/base/CreateElementTxn.h
rename to editor/libeditor/CreateElementTxn.h
rename from editor/libeditor/base/DeleteNodeTxn.cpp
rename to editor/libeditor/DeleteNodeTxn.cpp
rename from editor/libeditor/base/DeleteNodeTxn.h
rename to editor/libeditor/DeleteNodeTxn.h
rename from editor/libeditor/base/DeleteRangeTxn.cpp
rename to editor/libeditor/DeleteRangeTxn.cpp
rename from editor/libeditor/base/DeleteRangeTxn.h
rename to editor/libeditor/DeleteRangeTxn.h
rename from editor/libeditor/base/DeleteTextTxn.cpp
rename to editor/libeditor/DeleteTextTxn.cpp
rename from editor/libeditor/base/DeleteTextTxn.h
rename to editor/libeditor/DeleteTextTxn.h
rename from editor/libeditor/base/EditActionListener.h
rename to editor/libeditor/EditActionListener.h
rename from editor/libeditor/base/EditAggregateTxn.cpp
rename to editor/libeditor/EditAggregateTxn.cpp
rename from editor/libeditor/base/EditAggregateTxn.h
rename to editor/libeditor/EditAggregateTxn.h
rename from editor/libeditor/base/EditTxn.cpp
rename to editor/libeditor/EditTxn.cpp
rename from editor/libeditor/base/EditTxn.h
rename to editor/libeditor/EditTxn.h
rename from editor/libeditor/base/IMETextTxn.cpp
rename to editor/libeditor/IMETextTxn.cpp
rename from editor/libeditor/base/IMETextTxn.h
rename to editor/libeditor/IMETextTxn.h
rename from editor/libeditor/base/InsertElementTxn.cpp
rename to editor/libeditor/InsertElementTxn.cpp
rename from editor/libeditor/base/InsertElementTxn.h
rename to editor/libeditor/InsertElementTxn.h
rename from editor/libeditor/base/InsertTextTxn.cpp
rename to editor/libeditor/InsertTextTxn.cpp
rename from editor/libeditor/base/InsertTextTxn.h
rename to editor/libeditor/InsertTextTxn.h
rename from editor/libeditor/base/JoinElementTxn.cpp
rename to editor/libeditor/JoinElementTxn.cpp
rename from editor/libeditor/base/JoinElementTxn.h
rename to editor/libeditor/JoinElementTxn.h
rename from editor/libeditor/base/PlaceholderTxn.cpp
rename to editor/libeditor/PlaceholderTxn.cpp
rename from editor/libeditor/base/PlaceholderTxn.h
rename to editor/libeditor/PlaceholderTxn.h
rename from editor/libeditor/base/SetDocTitleTxn.cpp
rename to editor/libeditor/SetDocTitleTxn.cpp
rename from editor/libeditor/base/SetDocTitleTxn.h
rename to editor/libeditor/SetDocTitleTxn.h
rename from editor/libeditor/base/SplitElementTxn.cpp
rename to editor/libeditor/SplitElementTxn.cpp
rename from editor/libeditor/base/SplitElementTxn.h
rename to editor/libeditor/SplitElementTxn.h
deleted file mode 100644
--- a/editor/libeditor/base/moz.build
+++ /dev/null
@@ -1,44 +0,0 @@
-# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-TEST_DIRS += ['tests']
-
-UNIFIED_SOURCES += [
-    'ChangeAttributeTxn.cpp',
-    'ChangeCSSInlineStyleTxn.cpp',
-    'CreateElementTxn.cpp',
-    'DeleteNodeTxn.cpp',
-    'DeleteRangeTxn.cpp',
-    'DeleteTextTxn.cpp',
-    'EditAggregateTxn.cpp',
-    'EditTxn.cpp',
-    'IMETextTxn.cpp',
-    'InsertElementTxn.cpp',
-    'InsertTextTxn.cpp',
-    'JoinElementTxn.cpp',
-    'nsEditor.cpp',
-    'nsEditorCommands.cpp',
-    'nsEditorController.cpp',
-    'nsEditorEventListener.cpp',
-    'nsEditorUtils.cpp',
-    'nsSelectionState.cpp',
-    'nsStyleSheetTxns.cpp',
-    'PlaceholderTxn.cpp',
-    'SetDocTitleTxn.cpp',
-    'SplitElementTxn.cpp',
-]
-
-FAIL_ON_WARNINGS = True
-
-LOCAL_INCLUDES += [
-    '../text',
-    '/content/base/src',
-    '/editor/txmgr',
-    '/extensions/spellcheck/src',
-    '/layout/style',
-]
-
-FINAL_LIBRARY = 'xul'
rename from editor/libeditor/base/crashtests/336104.html
rename to editor/libeditor/crashtests/336104.html
rename from editor/libeditor/base/crashtests/382527-1.html
rename to editor/libeditor/crashtests/382527-1.html
rename from editor/libeditor/base/crashtests/402172-1.html
rename to editor/libeditor/crashtests/402172-1.html
rename from editor/libeditor/base/crashtests/407079-1.html
rename to editor/libeditor/crashtests/407079-1.html
rename from editor/libeditor/base/crashtests/407256-1.html
rename to editor/libeditor/crashtests/407256-1.html
rename from editor/libeditor/base/crashtests/430624-1.html
rename to editor/libeditor/crashtests/430624-1.html
rename from editor/libeditor/base/crashtests/459613-iframe.html
rename to editor/libeditor/crashtests/459613-iframe.html
rename from editor/libeditor/base/crashtests/459613.html
rename to editor/libeditor/crashtests/459613.html
rename from editor/libeditor/base/crashtests/475132-1.xhtml
rename to editor/libeditor/crashtests/475132-1.xhtml
rename from editor/libeditor/base/crashtests/633709.xhtml
rename to editor/libeditor/crashtests/633709.xhtml
rename from editor/libeditor/base/crashtests/636074-1.html
rename to editor/libeditor/crashtests/636074-1.html
rename from editor/libeditor/base/crashtests/713427-1.html
rename to editor/libeditor/crashtests/713427-1.html
rename from editor/libeditor/base/crashtests/713427-2.xhtml
rename to editor/libeditor/crashtests/713427-2.xhtml
rename from editor/libeditor/base/crashtests/762183.html
rename to editor/libeditor/crashtests/762183.html
rename from editor/libeditor/base/crashtests/766360.html
rename to editor/libeditor/crashtests/766360.html
rename from editor/libeditor/base/crashtests/766413.html
rename to editor/libeditor/crashtests/766413.html
rename from editor/libeditor/base/crashtests/766845.xhtml
rename to editor/libeditor/crashtests/766845.xhtml
rename from editor/libeditor/base/crashtests/768765.html
rename to editor/libeditor/crashtests/768765.html
rename from editor/libeditor/base/crashtests/771749.html
rename to editor/libeditor/crashtests/771749.html
rename from editor/libeditor/base/crashtests/772282.html
rename to editor/libeditor/crashtests/772282.html
rename from editor/libeditor/base/crashtests/776323.html
rename to editor/libeditor/crashtests/776323.html
rename from editor/libeditor/base/crashtests/crashtests.list
rename to editor/libeditor/crashtests/crashtests.list
--- a/editor/libeditor/html/moz.build
+++ b/editor/libeditor/html/moz.build
@@ -24,17 +24,17 @@ UNIFIED_SOURCES += [
     'nsWSRunObject.cpp',
     'TextEditorTest.cpp',
     'TypeInState.cpp',
 ]
 
 FAIL_ON_WARNINGS = True
 
 LOCAL_INCLUDES += [
-    '../base',
+    '..',
     '../text',
     '/content/base/src',
     '/editor/txmgr',
     '/layout/generic',
     '/layout/style',
     '/layout/tables',
     '/layout/xul',
 ]
--- a/editor/libeditor/html/tests/mochitest.ini
+++ b/editor/libeditor/html/tests/mochitest.ini
@@ -96,15 +96,15 @@ skip-if = toolkit == 'android' || e10s
 [test_bug966155.html]
 skip-if = os != "win"
 [test_bug966552.html]
 skip-if = os != "win"
 [test_bug998188.html]
 [test_CF_HTML_clipboard.html]
 [test_contenteditable_focus.html]
 [test_dom_input_event_on_htmleditor.html]
-skip-if = android_version == "10" # bug 1054087
+skip-if = toolkit == 'android' # bug 1054087
 [test_keypress_untrusted_event.html]
 [test_root_element_replacement.html]
 [test_select_all_without_body.html]
 skip-if = e10s
 [test_spellcheck_pref.html]
 skip-if = toolkit == 'android'
--- a/editor/libeditor/moz.build
+++ b/editor/libeditor/moz.build
@@ -1,7 +1,46 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-DIRS += ['base', 'text', 'html']
+DIRS += ['text', 'html']
+
+TEST_DIRS += ['tests']
+
+UNIFIED_SOURCES += [
+    'ChangeAttributeTxn.cpp',
+    'ChangeCSSInlineStyleTxn.cpp',
+    'CreateElementTxn.cpp',
+    'DeleteNodeTxn.cpp',
+    'DeleteRangeTxn.cpp',
+    'DeleteTextTxn.cpp',
+    'EditAggregateTxn.cpp',
+    'EditTxn.cpp',
+    'IMETextTxn.cpp',
+    'InsertElementTxn.cpp',
+    'InsertTextTxn.cpp',
+    'JoinElementTxn.cpp',
+    'nsEditor.cpp',
+    'nsEditorCommands.cpp',
+    'nsEditorController.cpp',
+    'nsEditorEventListener.cpp',
+    'nsEditorUtils.cpp',
+    'nsSelectionState.cpp',
+    'nsStyleSheetTxns.cpp',
+    'PlaceholderTxn.cpp',
+    'SetDocTitleTxn.cpp',
+    'SplitElementTxn.cpp',
+]
+
+FAIL_ON_WARNINGS = True
+
+LOCAL_INCLUDES += [
+    '/content/base/src',
+    '/editor/txmgr',
+    '/extensions/spellcheck/src',
+    '/layout/style',
+    'text',
+]
+
+FINAL_LIBRARY = 'xul'
rename from editor/libeditor/base/nsEditProperty.h
rename to editor/libeditor/nsEditProperty.h
rename from editor/libeditor/base/nsEditPropertyAtomList.h
rename to editor/libeditor/nsEditPropertyAtomList.h
rename from editor/libeditor/base/nsEditRules.h
rename to editor/libeditor/nsEditRules.h
rename from editor/libeditor/base/nsEditor.cpp
rename to editor/libeditor/nsEditor.cpp
rename from editor/libeditor/base/nsEditor.h
rename to editor/libeditor/nsEditor.h
rename from editor/libeditor/base/nsEditorCommands.cpp
rename to editor/libeditor/nsEditorCommands.cpp
rename from editor/libeditor/base/nsEditorCommands.h
rename to editor/libeditor/nsEditorCommands.h
rename from editor/libeditor/base/nsEditorController.cpp
rename to editor/libeditor/nsEditorController.cpp
rename from editor/libeditor/base/nsEditorController.h
rename to editor/libeditor/nsEditorController.h
rename from editor/libeditor/base/nsEditorEventListener.cpp
rename to editor/libeditor/nsEditorEventListener.cpp
rename from editor/libeditor/base/nsEditorEventListener.h
rename to editor/libeditor/nsEditorEventListener.h
rename from editor/libeditor/base/nsEditorUtils.cpp
rename to editor/libeditor/nsEditorUtils.cpp
rename from editor/libeditor/base/nsEditorUtils.h
rename to editor/libeditor/nsEditorUtils.h
rename from editor/libeditor/base/nsIAbsorbingTransaction.h
rename to editor/libeditor/nsIAbsorbingTransaction.h
rename from editor/libeditor/base/nsSelectionState.cpp
rename to editor/libeditor/nsSelectionState.cpp
rename from editor/libeditor/base/nsSelectionState.h
rename to editor/libeditor/nsSelectionState.h
rename from editor/libeditor/base/nsStyleSheetTxns.cpp
rename to editor/libeditor/nsStyleSheetTxns.cpp
rename from editor/libeditor/base/nsStyleSheetTxns.h
rename to editor/libeditor/nsStyleSheetTxns.h
rename from editor/libeditor/base/tests/chrome.ini
rename to editor/libeditor/tests/chrome.ini
rename from editor/libeditor/base/tests/file_bug586662.html
rename to editor/libeditor/tests/file_bug586662.html
rename from editor/libeditor/base/tests/mochitest.ini
rename to editor/libeditor/tests/mochitest.ini
rename from editor/libeditor/base/tests/moz.build
rename to editor/libeditor/tests/moz.build
rename from editor/libeditor/base/tests/test_bug408231.html
rename to editor/libeditor/tests/test_bug408231.html
rename from editor/libeditor/base/tests/test_bug46555.html
rename to editor/libeditor/tests/test_bug46555.html
rename from editor/libeditor/base/tests/test_bug502673.html
rename to editor/libeditor/tests/test_bug502673.html
rename from editor/libeditor/base/tests/test_bug514156.html
rename to editor/libeditor/tests/test_bug514156.html
rename from editor/libeditor/base/tests/test_bug567213.html
rename to editor/libeditor/tests/test_bug567213.html
rename from editor/libeditor/base/tests/test_bug586662.html
rename to editor/libeditor/tests/test_bug586662.html
rename from editor/libeditor/base/tests/test_bug599983.html
rename to editor/libeditor/tests/test_bug599983.html
rename from editor/libeditor/base/tests/test_bug599983.xul
rename to editor/libeditor/tests/test_bug599983.xul
rename from editor/libeditor/base/tests/test_bug646194.xul
rename to editor/libeditor/tests/test_bug646194.xul
rename from editor/libeditor/base/tests/test_bug742261.html
rename to editor/libeditor/tests/test_bug742261.html
rename from editor/libeditor/base/tests/test_bug773262.html
rename to editor/libeditor/tests/test_bug773262.html
rename from editor/libeditor/base/tests/test_bug795785.html
rename to editor/libeditor/tests/test_bug795785.html
rename from editor/libeditor/base/tests/test_composition_event_created_in_chrome.html
rename to editor/libeditor/tests/test_composition_event_created_in_chrome.html
rename from editor/libeditor/base/tests/test_dragdrop.html
rename to editor/libeditor/tests/test_dragdrop.html
rename from editor/libeditor/base/tests/test_selection_move_commands.xul
rename to editor/libeditor/tests/test_selection_move_commands.xul
--- a/editor/libeditor/text/moz.build
+++ b/editor/libeditor/text/moz.build
@@ -11,17 +11,17 @@ UNIFIED_SOURCES += [
     'nsTextEditRules.cpp',
     'nsTextEditRulesBidi.cpp',
     'nsTextEditUtils.cpp',
 ]
 
 FAIL_ON_WARNINGS = True
 
 LOCAL_INCLUDES += [
-    '../base',
+    '..',
     '/content/base/src',
     '/editor/txmgr',
 ]
 
 FINAL_LIBRARY = 'xul'
 
 MOCHITEST_MANIFESTS += ['tests/mochitest.ini']
 
--- a/extensions/spellcheck/hunspell/src/moz.build
+++ b/extensions/spellcheck/hunspell/src/moz.build
@@ -30,17 +30,17 @@ if not CONFIG['MOZ_NATIVE_HUNSPELL']:
     DEFINES['HUNSPELL_STATIC'] = True
 else:
     CXXFLAGS += CONFIG['MOZ_HUNSPELL_CFLAGS']
 
 FINAL_LIBRARY = 'xul'
 
 LOCAL_INCLUDES += [
     '/content/base/src',
-    '/editor/libeditor/base',
+    '/editor/libeditor',
     '/extensions/spellcheck/src',
 ]
 
 # Suppress warnings in third-party code.
 if CONFIG['CLANG_CXX']:
     CXXFLAGS += ['-Wno-unused-private-field']
 
 include('/ipc/chromium/chromium-config.mozbuild')
--- a/extensions/spellcheck/src/moz.build
+++ b/extensions/spellcheck/src/moz.build
@@ -16,15 +16,15 @@ SOURCES += [
     'mozSpellI18NManager.cpp',
 ]
 
 FINAL_LIBRARY = 'xul'
 
 LOCAL_INCLUDES += [
     '../hunspell/src',
     '/content/base/src',
-    '/editor/libeditor/base',
+    '/editor/libeditor',
 ]
 EXPORTS.mozilla += [
      'mozSpellChecker.h',
 ]
 
 FAIL_ON_WARNINGS = True
--- a/image/src/imgRequest.cpp
+++ b/image/src/imgRequest.cpp
@@ -598,16 +598,18 @@ NS_IMETHODIMP imgRequest::OnStartRequest
   LOG_SCOPE(GetImgLog(), "imgRequest::OnStartRequest");
 
   // Figure out if we're multipart
   nsCOMPtr<nsIMultiPartChannel> mpchan(do_QueryInterface(aRequest));
   nsRefPtr<imgStatusTracker> statusTracker = GetStatusTracker();
   if (mpchan) {
     mIsMultiPartChannel = true;
     statusTracker->SetIsMultipart();
+  } else {
+    NS_ABORT_IF_FALSE(!mIsMultiPartChannel, "Something went wrong");
   }
 
   // If we're not multipart, we shouldn't have an image yet
   NS_ABORT_IF_FALSE(mIsMultiPartChannel || !mImage,
                     "Already have an image for non-multipart request");
 
   // If we're multipart and about to load another image, signal so we can
   // detect the mime type in OnDataAvailable.
--- a/js/src/builtin/embedjs.py
+++ b/js/src/builtin/embedjs.py
@@ -73,24 +73,16 @@ namespace selfhosted {
 
     uint32_t GetRawScriptsSize() {
         return %(raw_total_length)i;
     }
 } // selfhosted
 } // js
 """
 
-MSGS_TEMPLATE = """\
-#define hash #
-#define id(x) x
-#define hashify(x) id(hash)x
-#define MSG_DEF(name, id, argc, ex, msg) hashify(define) name id
-#include "%(msgs)s"
-"""
-
 def embed(cxx, preprocessorOption, msgs, sources, c_out, js_out, env):
   combinedSources = '\n'.join([msgs] + ['#include "%(s)s"' % { 's': source } for source in sources])
   args = ['-D%(k)s=%(v)s' % { 'k': k, 'v': env[k] } for k in env]
   preprocessed = preprocess(cxx, preprocessorOption, combinedSources, args)
   processed = '\n'.join([line for line in preprocessed.splitlines() if \
                          (line.strip() and not line.startswith('#'))])
 
   with open(js_out, 'w') as output:
@@ -123,16 +115,27 @@ def preprocess(cxx, preprocessorOption, 
   if (result != 0):
     sys.exit(result);
   with open(tmpOut, 'r') as output:
     processed = output.read();
   os.remove(tmpIn)
   os.remove(tmpOut)
   return processed
 
+def messages(jsmsg):
+  defines = []
+  for line in open(jsmsg):
+    match = re.match("MSG_DEF\((JSMSG_(\w+))", line)
+    if match:
+      defines.append("#define %s %i" % (match.group(1), len(defines)))
+    else:
+      # Make sure that MSG_DEF isn't preceded by whitespace
+      assert not line.strip().startswith("MSG_DEF")
+  return '\n'.join(defines)
+
 def main():
   env = {}
   def define_env(option, opt, value, parser):
     pair = value.split('=', 1)
     if len(pair) == 1:
       pair.append(1)
     env[pair[0]] = pair[1]
   p = OptionParser(usage="%prog [options] file")
@@ -147,13 +150,13 @@ def main():
                help='C array header file')
   p.add_option('-s', type='string', metavar='jsfilename', default='selfhosted.js',
                help='Combined postprocessed JS file')
   (options, sources) = p.parse_args()
   if not (options.p and sources):
     p.print_help()
     sys.exit(1)
   cxx = shlex.split(options.c)
-  msgs = preprocess(cxx, options.p, MSGS_TEMPLATE % { 'msgs': options.m })
+  msgs = messages(options.m)
   embed(cxx, options.p, msgs, sources, options.o, options.s, env)
 
 if __name__ == "__main__":
   main()
--- a/js/src/ctypes/CTypes.cpp
+++ b/js/src/ctypes/CTypes.cpp
@@ -865,17 +865,17 @@ GetABICode(JSObject* obj)
   if (JS_GetClass(obj) != &sCABIClass)
     return INVALID_ABI;
 
   jsval result = JS_GetReservedSlot(obj, SLOT_ABICODE);
   return ABICode(result.toInt32());
 }
 
 static const JSErrorFormatString ErrorFormatString[CTYPESERR_LIMIT] = {
-#define MSG_DEF(name, number, count, exception, format) \
+#define MSG_DEF(name, count, exception, format) \
   { format, count, exception } ,
 #include "ctypes/ctypes.msg"
 #undef MSG_DEF
 };
 
 static const JSErrorFormatString*
 GetErrorMessage(void* userRef, const unsigned errorNumber)
 {
--- a/js/src/ctypes/CTypes.h
+++ b/js/src/ctypes/CTypes.h
@@ -195,18 +195,18 @@ DeflateStringToUTF8Buffer(JSContext *may
 MOZ_ALWAYS_INLINE void
 ASSERT_OK(bool ok)
 {
   JS_ASSERT(ok);
 }
 
 // for JS error reporting
 enum ErrorNum {
-#define MSG_DEF(name, number, count, exception, format) \
-  name = number,
+#define MSG_DEF(name, count, exception, format) \
+  name,
 #include "ctypes/ctypes.msg"
 #undef MSG_DEF
   CTYPESERR_LIMIT
 };
 
 /**
  * ABI constants that specify the calling convention to use.
  * ctypes.default_abi corresponds to the cdecl convention, and in almost all
--- a/js/src/ctypes/ctypes.msg
+++ b/js/src/ctypes/ctypes.msg
@@ -4,11 +4,11 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /*
  * This is the jsctypes error message file.
  *
  * For syntax details, see js/src/js.msg.
  */
 
-MSG_DEF(CTYPESMSG_PLACEHOLDER_0, 0, 0, JSEXN_NONE, NULL)
-MSG_DEF(CTYPESMSG_TYPE_ERROR,    1, 2, JSEXN_TYPEERR, "expected type {0}, got {1}")
+MSG_DEF(CTYPESMSG_PLACEHOLDER_0, 0, JSEXN_NONE, NULL)
+MSG_DEF(CTYPESMSG_TYPE_ERROR,    2, JSEXN_TYPEERR, "expected type {0}, got {1}")
 
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -4,441 +4,431 @@
  * 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/. */
 
 /*
  * This is the JavaScript error message file.
  *
  * The format for each JS error message is:
  *
- * MSG_DEF(<SYMBOLIC_NAME>, <ERROR_NUMBER>, <ARGUMENT_COUNT>, <EXCEPTION_NAME>,
+ * MSG_DEF(<SYMBOLIC_NAME>, <ARGUMENT_COUNT>, <EXCEPTION_NAME>,
  *         <FORMAT_STRING>)
  *
  * where ;
  * <SYMBOLIC_NAME> is a legal C identifer that will be used in the
  * JS engine source.
  *
- * <ERROR_NUMBER> is an unique integral value identifying this error.
- *
  * <ARGUMENT_COUNT> is an integer literal specifying the total number of
  * replaceable arguments in the following format string.
  *
  * <EXCEPTION_NAME> is an exception index from the enum in jsexn.c;
  * JSEXN_NONE for none.  The given exception index will be raised by the
  * engine when the corresponding error occurs.
  *
  * <FORMAT_STRING> is a string literal, optionally containing sequences
  * {X} where X  is an integer representing the argument number that will
  * be replaced with a string value when the error is reported.
  *
  * e.g.
  *
- * MSG_DEF(JSMSG_NOT_A_SUBSPECIES, 73, JSEXN_NONE, 2,
+ * MSG_DEF(JSMSG_NOT_A_SUBSPECIES, 2, JSEXN_NONE,
  *         "{0} is not a member of the {1} family")
  *
  * can be used:
  *
  * JS_ReportErrorNumber(JSMSG_NOT_A_SUBSPECIES, "Rhino", "Monkey");
  *
  * to report:
  *
  * "Rhino is not a member of the Monkey family"
- *
- * When removing MSG_DEFs, convert them to JSMSG_UNUSED<n> placeholders:
- *
- *    MSG_DEF(JSMSG_UNUSED7,                  7, 0, JSEXN_NONE, "")
- *
- * Before adding a new MSG_DEF at the end, look for existing JSMSG_UNUSED<n>
- * free index placeholders in the middle of the list.
  */
 
-MSG_DEF(JSMSG_NOT_AN_ERROR,             0, 0, JSEXN_NONE, "<Error #0 is reserved>")
-MSG_DEF(JSMSG_NOT_DEFINED,              1, 1, JSEXN_REFERENCEERR, "{0} is not defined")
-MSG_DEF(JSMSG_INACTIVE,                 2, 0, JSEXN_INTERNALERR, "nothing active on context")
-MSG_DEF(JSMSG_MORE_ARGS_NEEDED,         3, 3, JSEXN_TYPEERR, "{0} requires more than {1} argument{2}")
-MSG_DEF(JSMSG_BAD_CHAR,                 4, 1, JSEXN_INTERNALERR, "invalid format character {0}")
-MSG_DEF(JSMSG_BAD_TYPE,                 5, 1, JSEXN_TYPEERR, "unknown type {0}")
-MSG_DEF(JSMSG_ALLOC_OVERFLOW,           6, 0, JSEXN_INTERNALERR, "allocation size overflow")
-MSG_DEF(JSMSG_MISSING_HEXDIGITS,        7, 0, JSEXN_SYNTAXERR, "missing hexadecimal digits after '0x'")
-MSG_DEF(JSMSG_INCOMPATIBLE_PROTO,       8, 3, JSEXN_TYPEERR, "{0}.prototype.{1} called on incompatible {2}")
-MSG_DEF(JSMSG_NO_CONSTRUCTOR,           9, 1, JSEXN_TYPEERR, "{0} has no constructor")
-MSG_DEF(JSMSG_CANT_ALIAS,              10, 3, JSEXN_TYPEERR, "can't alias {0} to {1} in class {2}")
-MSG_DEF(JSMSG_NOT_SCRIPTED_FUNCTION,   11, 1, JSEXN_TYPEERR, "{0} is not a scripted function")
-MSG_DEF(JSMSG_BAD_SORT_ARG,            12, 0, JSEXN_TYPEERR, "invalid Array.prototype.sort argument")
-MSG_DEF(JSMSG_BAD_ATOMIC_NUMBER,       13, 1, JSEXN_INTERNALERR, "internal error: no index for atom {0}")
-MSG_DEF(JSMSG_TOO_MANY_LITERALS,       14, 0, JSEXN_INTERNALERR, "too many literals")
-MSG_DEF(JSMSG_CANT_WATCH,              15, 1, JSEXN_TYPEERR, "can't watch non-native objects of class {0}")
-MSG_DEF(JSMSG_STACK_UNDERFLOW,         16, 2, JSEXN_INTERNALERR, "internal error compiling {0}: stack underflow at pc {1}")
-MSG_DEF(JSMSG_NEED_DIET,               17, 1, JSEXN_INTERNALERR, "{0} too large")
-MSG_DEF(JSMSG_TOO_MANY_LOCAL_ROOTS,    18, 0, JSEXN_ERR, "out of local root space")
-MSG_DEF(JSMSG_READ_ONLY,               19, 1, JSEXN_TYPEERR, "{0} is read-only")
-MSG_DEF(JSMSG_BAD_FORMAL,              20, 0, JSEXN_SYNTAXERR, "malformed formal parameter")
-MSG_DEF(JSMSG_CANT_DELETE,             21, 1, JSEXN_TYPEERR, "property {0} is non-configurable and can't be deleted")
-MSG_DEF(JSMSG_NOT_FUNCTION,            22, 1, JSEXN_TYPEERR, "{0} is not a function")
-MSG_DEF(JSMSG_NOT_CONSTRUCTOR,         23, 1, JSEXN_TYPEERR, "{0} is not a constructor")
-MSG_DEF(JSMSG_INVALID_DATE,            24, 0, JSEXN_RANGEERR, "invalid date")
-MSG_DEF(JSMSG_TOO_DEEP,                25, 1, JSEXN_INTERNALERR, "{0} nested too deeply")
-MSG_DEF(JSMSG_OVER_RECURSED,           26, 0, JSEXN_INTERNALERR, "too much recursion")
-MSG_DEF(JSMSG_IN_NOT_OBJECT,           27, 1, JSEXN_TYPEERR, "invalid 'in' operand {0}")
-MSG_DEF(JSMSG_BAD_NEW_RESULT,          28, 1, JSEXN_TYPEERR, "invalid new expression result {0}")
-MSG_DEF(JSMSG_OBJECT_ACCESS_DENIED,    29, 0, JSEXN_ERR, "Permission denied to access object")
-MSG_DEF(JSMSG_PROPERTY_ACCESS_DENIED,  30, 1, JSEXN_ERR, "Permission denied to access property '{0}'")
-MSG_DEF(JSMSG_BAD_INSTANCEOF_RHS,      31, 1, JSEXN_TYPEERR, "invalid 'instanceof' operand {0}")
-MSG_DEF(JSMSG_BAD_BYTECODE,            32, 1, JSEXN_INTERNALERR, "unimplemented JavaScript bytecode {0}")
-MSG_DEF(JSMSG_BAD_RADIX,               33, 0, JSEXN_RANGEERR, "radix must be an integer at least 2 and no greater than 36")
-MSG_DEF(JSMSG_PAREN_BEFORE_LET,        34, 0, JSEXN_SYNTAXERR, "missing ( before let head")
-MSG_DEF(JSMSG_CANT_CONVERT,            35, 1, JSEXN_ERR, "can't convert {0} to an integer")
-MSG_DEF(JSMSG_CYCLIC_VALUE,            36, 1, JSEXN_TYPEERR, "cyclic {0} value")
-MSG_DEF(JSMSG_COMPILE_EXECED_SCRIPT,   37, 0, JSEXN_TYPEERR, "can't compile over a script that is currently executing")
-MSG_DEF(JSMSG_CANT_CONVERT_TO,         38, 2, JSEXN_TYPEERR, "can't convert {0} to {1}")
-MSG_DEF(JSMSG_NO_PROPERTIES,           39, 1, JSEXN_TYPEERR, "{0} has no properties")
-MSG_DEF(JSMSG_CANT_FIND_CLASS,         40, 1, JSEXN_TYPEERR, "can't find class id {0}")
-MSG_DEF(JSMSG_DEAD_OBJECT,             41, 0, JSEXN_TYPEERR, "can't access dead object")
-MSG_DEF(JSMSG_BYTECODE_TOO_BIG,        42, 2, JSEXN_INTERNALERR, "bytecode {0} too large (limit {1})")
-MSG_DEF(JSMSG_UNKNOWN_FORMAT,          43, 1, JSEXN_INTERNALERR, "unknown bytecode format {0}")
-MSG_DEF(JSMSG_TOO_MANY_CON_ARGS,       44, 0, JSEXN_SYNTAXERR, "too many constructor arguments")
-MSG_DEF(JSMSG_TOO_MANY_FUN_ARGS,       45, 0, JSEXN_SYNTAXERR, "too many function arguments")
-MSG_DEF(JSMSG_BAD_QUANTIFIER,          46, 0, JSEXN_SYNTAXERR, "invalid quantifier")
-MSG_DEF(JSMSG_MIN_TOO_BIG,             47, 1, JSEXN_SYNTAXERR, "overlarge minimum {0}")
-MSG_DEF(JSMSG_MAX_TOO_BIG,             48, 1, JSEXN_SYNTAXERR, "overlarge maximum {0}")
-MSG_DEF(JSMSG_OUT_OF_ORDER,            49, 1, JSEXN_SYNTAXERR, "maximum {0} less than minimum")
-MSG_DEF(JSMSG_BAD_DESTRUCT_DECL,       50, 0, JSEXN_SYNTAXERR, "missing = in destructuring declaration")
-MSG_DEF(JSMSG_BAD_DESTRUCT_ASS,        51, 0, JSEXN_REFERENCEERR, "invalid destructuring assignment operator")
-MSG_DEF(JSMSG_PAREN_AFTER_LET,         52, 0, JSEXN_SYNTAXERR, "missing ) after let head")
-MSG_DEF(JSMSG_CURLY_AFTER_LET,         53, 0, JSEXN_SYNTAXERR, "missing } after let block")
-MSG_DEF(JSMSG_MISSING_PAREN,           54, 0, JSEXN_SYNTAXERR, "unterminated parenthetical")
-MSG_DEF(JSMSG_UNTERM_CLASS,            55, 0, JSEXN_SYNTAXERR, "unterminated character class")
-MSG_DEF(JSMSG_TRAILING_SLASH,          56, 0, JSEXN_SYNTAXERR, "trailing \\ in regular expression")
-MSG_DEF(JSMSG_BAD_CLASS_RANGE,         57, 0, JSEXN_SYNTAXERR, "invalid range in character class")
-MSG_DEF(JSMSG_BAD_REGEXP_FLAG,         58, 1, JSEXN_SYNTAXERR, "invalid regular expression flag {0}")
-MSG_DEF(JSMSG_NO_INPUT,                59, 5, JSEXN_SYNTAXERR, "no input for /{0}/{1}{2}{3}{4}")
-MSG_DEF(JSMSG_CANT_OPEN,               60, 2, JSEXN_ERR, "can't open {0}: {1}")
-MSG_DEF(JSMSG_TOO_MANY_FUN_APPLY_ARGS, 61, 0, JSEXN_RANGEERR, "arguments array passed to Function.prototype.apply is too large")
-MSG_DEF(JSMSG_UNMATCHED_RIGHT_PAREN,   62, 0, JSEXN_SYNTAXERR, "unmatched ) in regular expression")
-MSG_DEF(JSMSG_TOO_BIG_TO_ENCODE,       63, 0, JSEXN_INTERNALERR, "data are to big to encode")
-MSG_DEF(JSMSG_ARG_INDEX_OUT_OF_RANGE,  64, 1, JSEXN_RANGEERR, "argument {0} accesses an index that is out of range")
-MSG_DEF(JSMSG_SPREAD_TOO_LARGE,        65, 0, JSEXN_RANGEERR, "array too large due to spread operand(s)")
-MSG_DEF(JSMSG_SOURCE_TOO_LONG,         66, 0, JSEXN_RANGEERR, "source is too long")
-MSG_DEF(JSMSG_BAD_WEAKMAP_KEY,         67, 0, JSEXN_TYPEERR, "cannot use the given object as a weak map key")
-MSG_DEF(JSMSG_BAD_SCRIPT_MAGIC,        68, 0, JSEXN_INTERNALERR, "bad script XDR magic number")
-MSG_DEF(JSMSG_PAREN_BEFORE_FORMAL,     69, 0, JSEXN_SYNTAXERR, "missing ( before formal parameters")
-MSG_DEF(JSMSG_MISSING_FORMAL,          70, 0, JSEXN_SYNTAXERR, "missing formal parameter")
-MSG_DEF(JSMSG_PAREN_AFTER_FORMAL,      71, 0, JSEXN_SYNTAXERR, "missing ) after formal parameters")
-MSG_DEF(JSMSG_CURLY_BEFORE_BODY,       72, 0, JSEXN_SYNTAXERR, "missing { before function body")
-MSG_DEF(JSMSG_CURLY_AFTER_BODY,        73, 0, JSEXN_SYNTAXERR, "missing } after function body")
-MSG_DEF(JSMSG_PAREN_BEFORE_COND,       74, 0, JSEXN_SYNTAXERR, "missing ( before condition")
-MSG_DEF(JSMSG_PAREN_AFTER_COND,        75, 0, JSEXN_SYNTAXERR, "missing ) after condition")
-MSG_DEF(JSMSG_BAD_DUP_ARGS,            76, 0, JSEXN_SYNTAXERR, "duplicate argument names not allowed in this context")
-MSG_DEF(JSMSG_NAME_AFTER_DOT,          77, 0, JSEXN_SYNTAXERR, "missing name after . operator")
-MSG_DEF(JSMSG_BRACKET_IN_INDEX,        78, 0, JSEXN_SYNTAXERR, "missing ] in index expression")
-MSG_DEF(JSMSG_ACCESSOR_DEF_DENIED,     79, 1, JSEXN_ERR, "Permission denied to define accessor property '{0}'")
-MSG_DEF(JSMSG_PAREN_BEFORE_SWITCH,     80, 0, JSEXN_SYNTAXERR, "missing ( before switch expression")
-MSG_DEF(JSMSG_PAREN_AFTER_SWITCH,      81, 0, JSEXN_SYNTAXERR, "missing ) after switch expression")
-MSG_DEF(JSMSG_CURLY_BEFORE_SWITCH,     82, 0, JSEXN_SYNTAXERR, "missing { before switch body")
-MSG_DEF(JSMSG_COLON_AFTER_CASE,        83, 0, JSEXN_SYNTAXERR, "missing : after case label")
-MSG_DEF(JSMSG_WHILE_AFTER_DO,          84, 0, JSEXN_SYNTAXERR, "missing while after do-loop body")
-MSG_DEF(JSMSG_PAREN_AFTER_FOR,         85, 0, JSEXN_SYNTAXERR, "missing ( after for")
-MSG_DEF(JSMSG_SEMI_AFTER_FOR_INIT,     86, 0, JSEXN_SYNTAXERR, "missing ; after for-loop initializer")
-MSG_DEF(JSMSG_SEMI_AFTER_FOR_COND,     87, 0, JSEXN_SYNTAXERR, "missing ; after for-loop condition")
-MSG_DEF(JSMSG_PAREN_AFTER_FOR_CTRL,    88, 0, JSEXN_SYNTAXERR, "missing ) after for-loop control")
-MSG_DEF(JSMSG_CURLY_BEFORE_TRY,        89, 0, JSEXN_SYNTAXERR, "missing { before try block")
-MSG_DEF(JSMSG_CURLY_AFTER_TRY,         90, 0, JSEXN_SYNTAXERR, "missing } after try block")
-MSG_DEF(JSMSG_PAREN_BEFORE_CATCH,      91, 0, JSEXN_SYNTAXERR, "missing ( before catch")
-MSG_DEF(JSMSG_CATCH_IDENTIFIER,        92, 0, JSEXN_SYNTAXERR, "missing identifier in catch")
-MSG_DEF(JSMSG_PAREN_AFTER_CATCH,       93, 0, JSEXN_SYNTAXERR, "missing ) after catch")
-MSG_DEF(JSMSG_CURLY_BEFORE_CATCH,      94, 0, JSEXN_SYNTAXERR, "missing { before catch block")
-MSG_DEF(JSMSG_CURLY_AFTER_CATCH,       95, 0, JSEXN_SYNTAXERR, "missing } after catch block")
-MSG_DEF(JSMSG_CURLY_BEFORE_FINALLY,    96, 0, JSEXN_SYNTAXERR, "missing { before finally block")
-MSG_DEF(JSMSG_CURLY_AFTER_FINALLY,     97, 0, JSEXN_SYNTAXERR, "missing } after finally block")
-MSG_DEF(JSMSG_CATCH_OR_FINALLY,        98, 0, JSEXN_SYNTAXERR, "missing catch or finally after try")
-MSG_DEF(JSMSG_PAREN_BEFORE_WITH,       99, 0, JSEXN_SYNTAXERR, "missing ( before with-statement object")
-MSG_DEF(JSMSG_PAREN_AFTER_WITH,       100, 0, JSEXN_SYNTAXERR, "missing ) after with-statement object")
-MSG_DEF(JSMSG_CURLY_IN_COMPOUND,      101, 0, JSEXN_SYNTAXERR, "missing } in compound statement")
-MSG_DEF(JSMSG_NO_VARIABLE_NAME,       102, 0, JSEXN_SYNTAXERR, "missing variable name")
-MSG_DEF(JSMSG_COLON_IN_COND,          103, 0, JSEXN_SYNTAXERR, "missing : in conditional expression")
-MSG_DEF(JSMSG_PAREN_AFTER_ARGS,       104, 0, JSEXN_SYNTAXERR, "missing ) after argument list")
-MSG_DEF(JSMSG_BRACKET_AFTER_LIST,     105, 0, JSEXN_SYNTAXERR, "missing ] after element list")
-MSG_DEF(JSMSG_COLON_AFTER_ID,         106, 0, JSEXN_SYNTAXERR, "missing : after property id")
-MSG_DEF(JSMSG_CURLY_AFTER_LIST,       107, 0, JSEXN_SYNTAXERR, "missing } after property list")
-MSG_DEF(JSMSG_PAREN_IN_PAREN,         108, 0, JSEXN_SYNTAXERR, "missing ) in parenthetical")
-MSG_DEF(JSMSG_SEMI_BEFORE_STMNT,      109, 0, JSEXN_SYNTAXERR, "missing ; before statement")
-MSG_DEF(JSMSG_TEMPLSTR_UNTERM_EXPR,   110, 0, JSEXN_SYNTAXERR, "missing } in template string")
-MSG_DEF(JSMSG_DUPLICATE_FORMAL,       111, 1, JSEXN_SYNTAXERR, "duplicate formal argument {0}")
-MSG_DEF(JSMSG_EQUAL_AS_ASSIGN,        112, 0, JSEXN_SYNTAXERR, "test for equality (==) mistyped as assignment (=)?")
-MSG_DEF(JSMSG_OPTIMIZED_CLOSURE_LEAK, 113, 0, JSEXN_INTERNALERR, "can't access optimized closure")
-MSG_DEF(JSMSG_TOO_MANY_DEFAULTS,      114, 0, JSEXN_SYNTAXERR, "more than one switch default")
-MSG_DEF(JSMSG_TOO_MANY_CASES,         115, 0, JSEXN_INTERNALERR, "too many switch cases")
-MSG_DEF(JSMSG_BAD_SWITCH,             116, 0, JSEXN_SYNTAXERR, "invalid switch statement")
-MSG_DEF(JSMSG_BAD_FOR_LEFTSIDE,       117, 0, JSEXN_SYNTAXERR, "invalid for/in left-hand side")
-MSG_DEF(JSMSG_CATCH_AFTER_GENERAL,    118, 0, JSEXN_SYNTAXERR, "catch after unconditional catch")
-MSG_DEF(JSMSG_CATCH_WITHOUT_TRY,      119, 0, JSEXN_SYNTAXERR, "catch without try")
-MSG_DEF(JSMSG_FINALLY_WITHOUT_TRY,    120, 0, JSEXN_SYNTAXERR, "finally without try")
-MSG_DEF(JSMSG_LABEL_NOT_FOUND,        121, 0, JSEXN_SYNTAXERR, "label not found")
-MSG_DEF(JSMSG_TOUGH_BREAK,            122, 0, JSEXN_SYNTAXERR, "unlabeled break must be inside loop or switch")
-MSG_DEF(JSMSG_BAD_CONTINUE,           123, 0, JSEXN_SYNTAXERR, "continue must be inside loop")
-MSG_DEF(JSMSG_BAD_RETURN_OR_YIELD,    124, 1, JSEXN_SYNTAXERR, "{0} not in function")
-MSG_DEF(JSMSG_BAD_LABEL,              125, 0, JSEXN_SYNTAXERR, "invalid label")
-MSG_DEF(JSMSG_DUPLICATE_LABEL,        126, 0, JSEXN_SYNTAXERR, "duplicate label")
-MSG_DEF(JSMSG_VAR_HIDES_ARG,          127, 1, JSEXN_TYPEERR, "variable {0} redeclares argument")
-MSG_DEF(JSMSG_BAD_VAR_INIT,           128, 0, JSEXN_SYNTAXERR, "invalid variable initialization")
-MSG_DEF(JSMSG_BAD_LEFTSIDE_OF_ASS,    129, 0, JSEXN_REFERENCEERR, "invalid assignment left-hand side")
-MSG_DEF(JSMSG_BAD_OPERAND,            130, 1, JSEXN_SYNTAXERR, "invalid {0} operand")
-MSG_DEF(JSMSG_BAD_PROP_ID,            131, 0, JSEXN_SYNTAXERR, "invalid property id")
-MSG_DEF(JSMSG_RESERVED_ID,            132, 1, JSEXN_SYNTAXERR, "{0} is a reserved identifier")
-MSG_DEF(JSMSG_SYNTAX_ERROR,           133, 0, JSEXN_SYNTAXERR, "syntax error")
-MSG_DEF(JSMSG_MISSING_BINARY_DIGITS,  134, 0, JSEXN_SYNTAXERR, "missing binary digits after '0b'")
-MSG_DEF(JSMSG_BAD_PROTOTYPE,          135, 1, JSEXN_TYPEERR,   "'prototype' property of {0} is not an object")
-MSG_DEF(JSMSG_MISSING_EXPONENT,       136, 0, JSEXN_SYNTAXERR, "missing exponent")
-MSG_DEF(JSMSG_OUT_OF_MEMORY,          137, 0, JSEXN_ERR, "out of memory")
-MSG_DEF(JSMSG_UNTERMINATED_STRING,    138, 0, JSEXN_SYNTAXERR, "unterminated string literal")
-MSG_DEF(JSMSG_TOO_MANY_PARENS,        139, 0, JSEXN_INTERNALERR, "too many parentheses in regular expression")
-MSG_DEF(JSMSG_UNTERMINATED_COMMENT,   140, 0, JSEXN_SYNTAXERR, "unterminated comment")
-MSG_DEF(JSMSG_UNTERMINATED_REGEXP,    141, 0, JSEXN_SYNTAXERR, "unterminated regular expression literal")
-MSG_DEF(JSMSG_BAD_CLONE_FUNOBJ_SCOPE, 142, 0, JSEXN_TYPEERR, "bad cloned function scope chain")
-MSG_DEF(JSMSG_MISSING_OCTAL_DIGITS,   143, 0, JSEXN_SYNTAXERR, "missing octal digits after '0o'")
-MSG_DEF(JSMSG_ILLEGAL_CHARACTER,      144, 0, JSEXN_SYNTAXERR, "illegal character")
-MSG_DEF(JSMSG_BAD_OCTAL,              145, 1, JSEXN_SYNTAXERR, "{0} is not a legal ECMA-262 octal constant")
-MSG_DEF(JSMSG_RESULTING_STRING_TOO_LARGE, 146, 0, JSEXN_RANGEERR, "repeat count must be less than infinity and not overflow maximum string size")
-MSG_DEF(JSMSG_UNCAUGHT_EXCEPTION,     147, 1, JSEXN_INTERNALERR, "uncaught exception: {0}")
-MSG_DEF(JSMSG_INVALID_BACKREF,        148, 0, JSEXN_SYNTAXERR, "non-octal digit in an escape sequence that doesn't match a back-reference")
-MSG_DEF(JSMSG_BAD_BACKREF,            149, 0, JSEXN_SYNTAXERR, "back-reference exceeds number of capturing parentheses")
-MSG_DEF(JSMSG_PRECISION_RANGE,        150, 1, JSEXN_RANGEERR, "precision {0} out of range")
-MSG_DEF(JSMSG_BAD_GETTER_OR_SETTER,   151, 1, JSEXN_TYPEERR, "invalid {0} usage")
-MSG_DEF(JSMSG_BAD_ARRAY_LENGTH,       152, 0, JSEXN_RANGEERR, "invalid array length")
-MSG_DEF(JSMSG_CANT_DESCRIBE_PROPS,    153, 1, JSEXN_TYPEERR, "can't describe non-native properties of class {0}")
-MSG_DEF(JSMSG_BAD_APPLY_ARGS,         154, 1, JSEXN_TYPEERR, "second argument to Function.prototype.{0} must be an array")
-MSG_DEF(JSMSG_REDECLARED_VAR,         155, 2, JSEXN_TYPEERR, "redeclaration of {0} {1}")
-MSG_DEF(JSMSG_UNDECLARED_VAR,         156, 1, JSEXN_REFERENCEERR, "assignment to undeclared variable {0}")
-MSG_DEF(JSMSG_PROXY_REVOKED,          157, 0, JSEXN_TYPEERR, "illegal operation attempted on a revoked proxy")
-MSG_DEF(JSMSG_DEPRECATED_USAGE,       158, 1, JSEXN_REFERENCEERR, "deprecated {0} usage")
-MSG_DEF(JSMSG_BAD_URI,                159, 0, JSEXN_URIERR, "malformed URI sequence")
-MSG_DEF(JSMSG_GETTER_ONLY,            160, 0, JSEXN_TYPEERR, "setting a property that has only a getter")
-MSG_DEF(JSMSG_IDSTART_AFTER_NUMBER,   161, 0, JSEXN_SYNTAXERR, "identifier starts immediately after numeric literal")
-MSG_DEF(JSMSG_UNDEFINED_PROP,         162, 1, JSEXN_REFERENCEERR, "reference to undefined property {0}")
-MSG_DEF(JSMSG_USELESS_EXPR,           163, 0, JSEXN_TYPEERR, "useless expression")
-MSG_DEF(JSMSG_REDECLARED_PARAM,       164, 1, JSEXN_TYPEERR, "redeclaration of formal parameter {0}")
-MSG_DEF(JSMSG_NEWREGEXP_FLAGGED,      165, 0, JSEXN_TYPEERR, "can't supply flags when constructing one RegExp from another")
-MSG_DEF(JSMSG_RESERVED_SLOT_RANGE,    166, 0, JSEXN_RANGEERR, "reserved slot index out of range")
-MSG_DEF(JSMSG_CANT_DECODE_PRINCIPALS, 167, 0, JSEXN_INTERNALERR, "can't decode JSPrincipals")
-MSG_DEF(JSMSG_CANT_SEAL_OBJECT,       168, 1, JSEXN_ERR, "can't seal {0} objects")
-MSG_DEF(JSMSG_TOO_MANY_CATCH_VARS,    169, 0, JSEXN_SYNTAXERR, "too many catch variables")
-MSG_DEF(JSMSG_NEGATIVE_REPETITION_COUNT, 170, 0, JSEXN_RANGEERR, "repeat count must be non-negative")
-MSG_DEF(JSMSG_INVALID_FOR_OF_INIT,    171, 0, JSEXN_SYNTAXERR, "for-of loop variable declaration may not have an initializer")
-MSG_DEF(JSMSG_INVALID_MAP_ITERABLE,   172, 0, JSEXN_TYPEERR, "iterable for map should have array-like objects")
-MSG_DEF(JSMSG_NOT_A_CODEPOINT,        173, 1, JSEXN_RANGEERR, "{0} is not a valid code point")
-MSG_DEF(JSMSG_BRACKET_AFTER_ARRAY_COMPREHENSION, 174, 0, JSEXN_SYNTAXERR, "missing ] after array comprehension")
-MSG_DEF(JSMSG_NESTING_GENERATOR,      175, 0, JSEXN_TYPEERR, "already executing generator")
-MSG_DEF(JSMSG_PAREN_AFTER_FOR_OF_ITERABLE, 176, 0, JSEXN_SYNTAXERR, "missing ) after for-of iterable")
-MSG_DEF(JSMSG_INVALID_NORMALIZE_FORM, 177, 0, JSEXN_RANGEERR, "form must be one of 'NFC', 'NFD', 'NFKC', or 'NFKD'")
-MSG_DEF(JSMSG_NOTHING_TO_REPEAT,      178, 0, JSEXN_SYNTAXERR, "nothing to repeat")
-MSG_DEF(JSMSG_INVALID_GROUP,          179, 0, JSEXN_SYNTAXERR, "invalid regexp group")
-MSG_DEF(JSMSG_ESCAPE_AT_END_OF_REGEXP, 180, 0, JSEXN_SYNTAXERR, "\\ at end of pattern")
-MSG_DEF(JSMSG_NUMBERS_OUT_OF_ORDER,   181, 0, JSEXN_SYNTAXERR, "numbers out of order in {} quantifier.")
-MSG_DEF(JSMSG_BAD_GENERATOR_SEND,     182, 1, JSEXN_TYPEERR, "attempt to send {0} to newborn generator")
-MSG_DEF(JSMSG_SC_NOT_TRANSFERABLE,    183, 0, JSEXN_TYPEERR, "invalid transferable array for structured clone")
-MSG_DEF(JSMSG_SC_DUP_TRANSFERABLE,    184, 0, JSEXN_TYPEERR, "duplicate transferable for structured clone")
-MSG_DEF(JSMSG_CANT_REPORT_AS_NON_EXTENSIBLE, 185, 0, JSEXN_TYPEERR, "proxy can't report an extensible object as non-extensible")
-MSG_DEF(JSMSG_SYMBOL_TO_STRING,       186, 0, JSEXN_TYPEERR, "can't convert symbol to string")
-MSG_DEF(JSMSG_OBJECT_METADATA_CALLBACK_ALREADY_SET, 187, 0, JSEXN_ERR, "Cannot track object allocation, because other tools are already doing so")
-MSG_DEF(JSMSG_INCOMPATIBLE_METHOD,    188, 3, JSEXN_TYPEERR, "{0} {1} called on incompatible {2}")
-MSG_DEF(JSMSG_SYMBOL_TO_NUMBER,       189, 0, JSEXN_TYPEERR, "can't convert symbol to number")
-MSG_DEF(JSMSG_NOT_TRACKING_ALLOCATIONS, 190, 1, JSEXN_ERR, "Cannot call {0} without setting trackingAllocationSites to true")
-MSG_DEF(JSMSG_BAD_INDEX,              191, 0, JSEXN_RANGEERR, "invalid or out-of-range index")
-MSG_DEF(JSMSG_SELFHOSTED_TOP_LEVEL_LET,192,0, JSEXN_SYNTAXERR, "self-hosted code cannot contain top-level 'let' declarations")
-MSG_DEF(JSMSG_BAD_FOR_EACH_LOOP,      193, 0, JSEXN_SYNTAXERR, "invalid for each loop")
-MSG_DEF(JSMSG_OBJECT_WATCH_DEPRECATED,194, 0, JSEXN_NONE, "Object.prototype.watch and unwatch are very slow, non-standard, and deprecated; use a getter/setter instead")
-MSG_DEF(JSMSG_TYPE_ERR_BAD_ARGS,      195, 0, JSEXN_TYPEERR, "invalid arguments")
-MSG_DEF(JSMSG_REDECLARED_CATCH_IDENTIFIER, 196, 1, JSEXN_TYPEERR, "redeclaration of identifier '{0}' in catch")
-MSG_DEF(JSMSG_INTERNAL_INTL_ERROR,    197, 0, JSEXN_ERR, "internal error while computing Intl data")
-MSG_DEF(JSMSG_DEFAULT_LOCALE_ERROR,   198, 0, JSEXN_ERR, "internal error getting the default locale")
-MSG_DEF(JSMSG_TOO_MANY_LOCALS,        199, 0, JSEXN_SYNTAXERR, "too many local variables")
-MSG_DEF(JSMSG_ARRAY_INIT_TOO_BIG,     200, 0, JSEXN_INTERNALERR, "array initialiser too large")
-MSG_DEF(JSMSG_REGEXP_TOO_COMPLEX,     201, 0, JSEXN_INTERNALERR, "regular expression too complex")
-MSG_DEF(JSMSG_BUFFER_TOO_SMALL,       202, 0, JSEXN_INTERNALERR, "buffer too small")
-MSG_DEF(JSMSG_BAD_SURROGATE_CHAR,     203, 1, JSEXN_TYPEERR, "bad surrogate character {0}")
-MSG_DEF(JSMSG_UTF8_CHAR_TOO_LARGE,    204, 1, JSEXN_TYPEERR, "UTF-8 character {0} too large")
-MSG_DEF(JSMSG_MALFORMED_UTF8_CHAR,    205, 1, JSEXN_TYPEERR, "malformed UTF-8 character sequence at offset {0}")
-MSG_DEF(JSMSG_USER_DEFINED_ERROR,     206, 0, JSEXN_ERR, "JS_ReportError was called")
-MSG_DEF(JSMSG_WRONG_CONSTRUCTOR,      207, 1, JSEXN_TYPEERR, "wrong constructor called for {0}")
-MSG_DEF(JSMSG_BAD_GENERATOR_RETURN,   208, 1, JSEXN_TYPEERR, "generator function {0} returns a value")
-MSG_DEF(JSMSG_BAD_ANON_GENERATOR_RETURN, 209, 0, JSEXN_TYPEERR, "anonymous generator function returns a value")
-MSG_DEF(JSMSG_PROTO_SETTING_SLOW,     210, 0, JSEXN_NONE, "mutating the [[Prototype]] of an object will cause your code to run very slowly; instead create the object with the correct initial [[Prototype]] value using Object.create")
-MSG_DEF(JSMSG_IN_AFTER_FOR_NAME,      211, 0, JSEXN_SYNTAXERR, "missing 'in' or 'of' after for")
-MSG_DEF(JSMSG_BAD_TRAP_RETURN_VALUE,  212, 2, JSEXN_TYPEERR,"trap {1} for {0} returned a primitive value")
-MSG_DEF(JSMSG_OF_AFTER_FOR_NAME,      213, 0, JSEXN_SYNTAXERR, "missing 'of' after for")
-MSG_DEF(JSMSG_BAD_GENERATOR_YIELD,    214, 1, JSEXN_TYPEERR, "yield from closing generator {0}")
-MSG_DEF(JSMSG_BAD_GENERATOR_SYNTAX,   215, 1, JSEXN_SYNTAXERR, "{0} expression must be parenthesized")
-MSG_DEF(JSMSG_ARRAY_COMP_LEFTSIDE,    216, 0, JSEXN_SYNTAXERR, "invalid array comprehension left-hand side")
-MSG_DEF(JSMSG_LET_COMP_BINDING,       217, 0, JSEXN_SYNTAXERR, "'let' is not a valid name for a comprehension variable")
-MSG_DEF(JSMSG_EMPTY_ARRAY_REDUCE,     218, 0, JSEXN_TYPEERR, "reduce of empty array with no initial value")
-MSG_DEF(JSMSG_BAD_SYMBOL,             219, 1, JSEXN_TYPEERR, "{0} is not a well-known @@-symbol")
-MSG_DEF(JSMSG_BAD_DELETE_OPERAND,     220, 0, JSEXN_REFERENCEERR, "invalid delete operand")
-MSG_DEF(JSMSG_BAD_INCOP_OPERAND,      221, 0, JSEXN_REFERENCEERR, "invalid increment/decrement operand")
-MSG_DEF(JSMSG_UNEXPECTED_TYPE,        222, 2, JSEXN_TYPEERR, "{0} is {1}")
-MSG_DEF(JSMSG_LET_DECL_NOT_IN_BLOCK,  223, 0, JSEXN_SYNTAXERR, "let declaration not directly within block")
-MSG_DEF(JSMSG_CONTRARY_NONDIRECTIVE,  224, 1, JSEXN_SYNTAXERR, "'{0}' statement won't be enforced as a directive because it isn't in directive prologue position")
-MSG_DEF(JSMSG_CANT_SET_ARRAY_ATTRS,   225, 0, JSEXN_INTERNALERR, "can't set attributes on indexed array properties")
-MSG_DEF(JSMSG_EVAL_ARITY,             226, 0, JSEXN_TYPEERR, "eval accepts only one parameter")
-MSG_DEF(JSMSG_MISSING_FUN_ARG,        227, 2, JSEXN_TYPEERR, "missing argument {0} when calling function {1}")
-MSG_DEF(JSMSG_JSON_BAD_PARSE,         228, 3, JSEXN_SYNTAXERR, "JSON.parse: {0} at line {1} column {2} of the JSON data")
-MSG_DEF(JSMSG_JSON_BAD_STRINGIFY,     229, 0, JSEXN_ERR, "JSON.stringify")
-MSG_DEF(JSMSG_NOT_CALLABLE_OR_UNDEFINED, 230, 0, JSEXN_TYPEERR, "value is not a function or undefined")
-MSG_DEF(JSMSG_NOT_NONNULL_OBJECT,     231, 0, JSEXN_TYPEERR, "value is not a non-null object")
-MSG_DEF(JSMSG_DEPRECATED_OCTAL,       232, 0, JSEXN_SYNTAXERR, "octal literals and octal escape sequences are deprecated")
-MSG_DEF(JSMSG_STRICT_CODE_WITH,       233, 0, JSEXN_SYNTAXERR, "strict mode code may not contain 'with' statements")
-MSG_DEF(JSMSG_DUPLICATE_PROPERTY,     234, 1, JSEXN_SYNTAXERR, "property name {0} appears more than once in object literal")
-MSG_DEF(JSMSG_DEPRECATED_DELETE_OPERAND, 235, 0, JSEXN_SYNTAXERR, "applying the 'delete' operator to an unqualified name is deprecated")
-MSG_DEF(JSMSG_BAD_STRICT_ASSIGN,      236, 1, JSEXN_SYNTAXERR, "can't assign to {0} in strict mode")
-MSG_DEF(JSMSG_BAD_BINDING,            237, 1, JSEXN_SYNTAXERR, "redefining {0} is deprecated")
-MSG_DEF(JSMSG_INVALID_DESCRIPTOR,     238, 0, JSEXN_TYPEERR, "property descriptors must not specify a value or be writable when a getter or setter has been specified")
-MSG_DEF(JSMSG_OBJECT_NOT_EXTENSIBLE,  239, 1, JSEXN_TYPEERR, "{0} is not extensible")
-MSG_DEF(JSMSG_CANT_REDEFINE_PROP,     240, 1, JSEXN_TYPEERR, "can't redefine non-configurable property '{0}'")
-MSG_DEF(JSMSG_CANT_APPEND_TO_ARRAY,   241, 0, JSEXN_TYPEERR, "can't add elements past the end of an array if its length property is unwritable")
-MSG_DEF(JSMSG_CANT_REDEFINE_ARRAY_LENGTH,242, 0, JSEXN_TYPEERR, "can't redefine array length")
-MSG_DEF(JSMSG_CANT_DEFINE_PAST_ARRAY_LENGTH,243, 0, JSEXN_TYPEERR, "can't define array index property past the end of an array with non-writable length")
-MSG_DEF(JSMSG_TYPED_ARRAY_BAD_INDEX,  244, 0, JSEXN_ERR, "invalid or out-of-range index")
-MSG_DEF(JSMSG_TYPED_ARRAY_NEGATIVE_ARG, 245, 1, JSEXN_ERR, "argument {0} must be >= 0")
-MSG_DEF(JSMSG_TYPED_ARRAY_BAD_ARGS,   246, 0, JSEXN_ERR, "invalid arguments")
-MSG_DEF(JSMSG_CSP_BLOCKED_FUNCTION,   247, 0, JSEXN_ERR, "call to Function() blocked by CSP")
-MSG_DEF(JSMSG_BAD_GET_SET_FIELD,      248, 1, JSEXN_TYPEERR, "property descriptor's {0} field is neither undefined nor a function")
-MSG_DEF(JSMSG_BAD_PROXY_FIX,          249, 0, JSEXN_TYPEERR, "proxy was fixed while executing the handler")
-MSG_DEF(JSMSG_INVALID_EVAL_SCOPE_ARG, 250, 0, JSEXN_EVALERR, "invalid eval scope argument")
-MSG_DEF(JSMSG_ACCESSOR_WRONG_ARGS,    251, 3, JSEXN_SYNTAXERR, "{0} functions must have {1} argument{2}")
-MSG_DEF(JSMSG_THROW_TYPE_ERROR,       252, 0, JSEXN_TYPEERR, "'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them")
-MSG_DEF(JSMSG_BAD_TOISOSTRING_PROP,   253, 0, JSEXN_TYPEERR, "toISOString property is not callable")
-MSG_DEF(JSMSG_BAD_PARSE_NODE,         254, 0, JSEXN_INTERNALERR, "bad parse node")
-MSG_DEF(JSMSG_NOT_EXPECTED_TYPE,      255, 3, JSEXN_TYPEERR, "{0}: expected {1}, got {2}")
-MSG_DEF(JSMSG_CALLER_IS_STRICT,       256, 0, JSEXN_TYPEERR, "access to strict mode caller function is censored")
-MSG_DEF(JSMSG_NEED_DEBUG_MODE,        257, 0, JSEXN_ERR, "function can be called only in debug mode")
-MSG_DEF(JSMSG_STRICT_CODE_LET_EXPR_STMT, 258, 0, JSEXN_ERR, "strict mode code may not contain unparenthesized let expression statements")
-MSG_DEF(JSMSG_CANT_CHANGE_EXTENSIBILITY, 259, 0, JSEXN_TYPEERR, "can't change object's extensibility")
-MSG_DEF(JSMSG_SC_BAD_SERIALIZED_DATA, 260, 1, JSEXN_INTERNALERR, "bad serialized structured data ({0})")
-MSG_DEF(JSMSG_SC_UNSUPPORTED_TYPE,    261, 0, JSEXN_TYPEERR, "unsupported type for structured data")
-MSG_DEF(JSMSG_SC_RECURSION,           262, 0, JSEXN_INTERNALERR, "recursive object")
-MSG_DEF(JSMSG_DEBUG_CANT_DEBUG_GLOBAL, 263, 0, JSEXN_ERR, "passing non-debuggable global to addDebuggee")
-MSG_DEF(JSMSG_BAD_CLONE_VERSION,      264, 0, JSEXN_ERR, "unsupported structured clone version")
-MSG_DEF(JSMSG_CANT_CLONE_OBJECT,      265, 0, JSEXN_TYPEERR, "can't clone object")
-MSG_DEF(JSMSG_DEBUG_RESUMPTION_VALUE_DISALLOWED, 266, 0, JSEXN_TYPEERR, "resumption values are disallowed in this hook")
-MSG_DEF(JSMSG_STRICT_FUNCTION_STATEMENT, 267, 0, JSEXN_SYNTAXERR, "in strict mode code, functions may be declared only at top level or immediately within another function")
-MSG_DEF(JSMSG_INVALID_FOR_IN_INIT,    268, 0, JSEXN_SYNTAXERR, "for-in loop let declaration may not have an initializer")
-MSG_DEF(JSMSG_CLEARED_SCOPE,          269, 0, JSEXN_TYPEERR, "attempt to run compile-and-go script on a cleared scope")
-MSG_DEF(JSMSG_MALFORMED_ESCAPE,       270, 1, JSEXN_SYNTAXERR, "malformed {0} character escape sequence")
-MSG_DEF(JSMSG_BAD_GENEXP_BODY,        271, 1, JSEXN_SYNTAXERR, "illegal use of {0} in generator expression")
-MSG_DEF(JSMSG_YIELD_WITHOUT_OPERAND,  272, 0, JSEXN_SYNTAXERR, "yield without a value is deprecated, and illegal in ES6 (use 'yield undefined' instead)")
-MSG_DEF(JSMSG_UNNAMED_FUNCTION_STMT,  273, 0, JSEXN_SYNTAXERR, "function statement requires a name")
-MSG_DEF(JSMSG_CCW_REQUIRED,           274, 1, JSEXN_TYPEERR, "{0}: argument must be an object from a different compartment")
-MSG_DEF(JSMSG_DEBUG_BAD_RESUMPTION,   275, 0, JSEXN_TYPEERR, "debugger resumption value must be undefined, {throw: val}, {return: val}, or null")
-MSG_DEF(JSMSG_ASSIGN_FUNCTION_OR_NULL, 276, 1, JSEXN_TYPEERR, "value assigned to {0} must be a function or null")
-MSG_DEF(JSMSG_DEBUG_NOT_LIVE,         277, 1, JSEXN_ERR, "{0} is not live")
-MSG_DEF(JSMSG_DEBUG_OBJECT_WRONG_OWNER, 278, 0, JSEXN_TYPEERR, "Debugger.Object belongs to a different Debugger")
-MSG_DEF(JSMSG_DEBUG_OBJECT_PROTO,     279, 0, JSEXN_TYPEERR, "Debugger.Object.prototype is not a valid Debugger.Object")
-MSG_DEF(JSMSG_DEBUG_LOOP,             280, 0, JSEXN_TYPEERR, "cannot debug an object in same compartment as debugger or a compartment that is already debugging the debugger")
-MSG_DEF(JSMSG_DEBUG_NOT_IDLE,         281, 0, JSEXN_ERR, "can't start debugging: a debuggee script is on the stack")
-MSG_DEF(JSMSG_DEBUG_BAD_OFFSET,       282, 0, JSEXN_TYPEERR, "invalid script offset")
-MSG_DEF(JSMSG_DEBUG_BAD_LINE,         283, 0, JSEXN_TYPEERR, "invalid line number")
-MSG_DEF(JSMSG_DEBUG_NOT_DEBUGGING,    284, 0, JSEXN_ERR, "can't set breakpoint: script global is not a debuggee")
-MSG_DEF(JSMSG_DEBUG_COMPARTMENT_MISMATCH, 285, 2, JSEXN_TYPEERR, "{0}: descriptor .{1} property is an object in a different compartment than the target object")
-MSG_DEF(JSMSG_DEBUG_NOT_SCRIPT_FRAME, 286, 0, JSEXN_ERR, "stack frame is not running JavaScript code")
-MSG_DEF(JSMSG_CANT_WATCH_PROP,        287, 0, JSEXN_TYPEERR, "properties whose names are objects can't be watched")
-MSG_DEF(JSMSG_CSP_BLOCKED_EVAL,       288, 0, JSEXN_ERR, "call to eval() blocked by CSP")
-MSG_DEF(JSMSG_DEBUG_NO_SCOPE_OBJECT,  289, 0, JSEXN_TYPEERR, "declarative Environments don't have binding objects")
-MSG_DEF(JSMSG_EMPTY_CONSEQUENT,       290, 0, JSEXN_SYNTAXERR, "mistyped ; after conditional?")
-MSG_DEF(JSMSG_NOT_ITERABLE,           291, 1, JSEXN_TYPEERR, "{0} is not iterable")
-MSG_DEF(JSMSG_QUERY_LINE_WITHOUT_URL, 292, 0, JSEXN_TYPEERR, "findScripts query object has 'line' property, but no 'url' property")
-MSG_DEF(JSMSG_QUERY_INNERMOST_WITHOUT_LINE_URL, 293, 0, JSEXN_TYPEERR, "findScripts query object has 'innermost' property without both 'url' and 'line' properties")
-MSG_DEF(JSMSG_DEBUG_VARIABLE_NOT_FOUND, 294, 0, JSEXN_TYPEERR, "variable not found in environment")
-MSG_DEF(JSMSG_PARAMETER_AFTER_REST,   295, 0, JSEXN_SYNTAXERR, "parameter after rest parameter")
-MSG_DEF(JSMSG_NO_REST_NAME,           296, 0, JSEXN_SYNTAXERR, "no parameter name after ...")
-MSG_DEF(JSMSG_ARGUMENTS_AND_REST,     297, 0, JSEXN_SYNTAXERR, "'arguments' object may not be used in conjunction with a rest parameter")
-MSG_DEF(JSMSG_FUNCTION_ARGUMENTS_AND_REST, 298, 0, JSEXN_ERR, "the 'arguments' property of a function with a rest parameter may not be used")
-MSG_DEF(JSMSG_REST_WITH_DEFAULT,      299, 0, JSEXN_SYNTAXERR, "rest parameter may not have a default")
-MSG_DEF(JSMSG_NONDEFAULT_FORMAL_AFTER_DEFAULT, 300, 0, JSEXN_SYNTAXERR, "parameter(s) with default followed by parameter without default")
-MSG_DEF(JSMSG_YIELD_IN_DEFAULT,       301, 0, JSEXN_SYNTAXERR, "yield in default expression")
-MSG_DEF(JSMSG_INTRINSIC_NOT_DEFINED,  302, 1, JSEXN_REFERENCEERR, "no intrinsic function {0}")
-MSG_DEF(JSMSG_ALREADY_HAS_PRAGMA,     303, 2, JSEXN_NONE,      "{0} is being assigned a {1}, but already has one")
-MSG_DEF(JSMSG_PAR_ARRAY_BAD_ARG,      304, 0, JSEXN_RANGEERR, "invalid parallel method argument")
-MSG_DEF(JSMSG_REGEXP_RUNTIME_ERROR,   305, 0, JSEXN_INTERNALERR, "an error occurred while executing regular expression")
-MSG_DEF(JSMSG_DEBUG_OPTIMIZED_OUT,    306, 0, JSEXN_ERR, "variable has been optimized out")
-MSG_DEF(JSMSG_NEXT_RETURNED_PRIMITIVE,307, 0, JSEXN_TYPEERR, "iterator.next() returned a non-object value")
-MSG_DEF(JSMSG_PAR_ARRAY_SCATTER_CONFLICT, 308, 0, JSEXN_ERR, "no conflict resolution function provided")
-MSG_DEF(JSMSG_PAR_ARRAY_SCATTER_BOUNDS, 309, 0, JSEXN_ERR, "index in scatter vector out of bounds")
-MSG_DEF(JSMSG_CANT_REPORT_NC_AS_NE,   310, 0, JSEXN_TYPEERR, "proxy can't report a non-configurable own property as non-existent")
-MSG_DEF(JSMSG_CANT_REPORT_E_AS_NE,    311, 0, JSEXN_TYPEERR, "proxy can't report an existing own property as non-existent on a non-extensible object")
-MSG_DEF(JSMSG_CANT_REPORT_NEW,        312, 0, JSEXN_TYPEERR, "proxy can't report a new property on a non-extensible object")
-MSG_DEF(JSMSG_CANT_REPORT_INVALID,    313, 0, JSEXN_TYPEERR, "proxy can't report an incompatible property descriptor")
-MSG_DEF(JSMSG_CANT_REPORT_NE_AS_NC,   314, 0, JSEXN_TYPEERR, "proxy can't report a non-existent property as non-configurable")
-MSG_DEF(JSMSG_CANT_DEFINE_NEW,        315, 0, JSEXN_TYPEERR, "proxy can't define a new property on a non-extensible object")
-MSG_DEF(JSMSG_CANT_DEFINE_INVALID,    316, 0, JSEXN_TYPEERR, "proxy can't define an incompatible property descriptor")
-MSG_DEF(JSMSG_CANT_DEFINE_NE_AS_NC,   317, 0, JSEXN_TYPEERR, "proxy can't define a non-existent property as non-configurable")
-MSG_DEF(JSMSG_INVALID_TRAP_RESULT,    318, 2, JSEXN_TYPEERR, "trap {1} for {0} returned an invalid result")
-MSG_DEF(JSMSG_CANT_SKIP_NC,           319, 0, JSEXN_TYPEERR, "proxy can't skip a non-configurable property")
-MSG_DEF(JSMSG_MUST_REPORT_SAME_VALUE, 320, 0, JSEXN_TYPEERR, "proxy must report the same value for a non-writable, non-configurable property")
-MSG_DEF(JSMSG_MUST_REPORT_UNDEFINED,  321, 0, JSEXN_TYPEERR, "proxy must report undefined for a non-configurable accessor property without a getter")
-MSG_DEF(JSMSG_CANT_SET_NW_NC,         322, 0, JSEXN_TYPEERR, "proxy can't successfully set a non-writable, non-configurable property")
-MSG_DEF(JSMSG_CANT_SET_WO_SETTER,     323, 0, JSEXN_TYPEERR, "proxy can't succesfully set an accessor property without a setter")
-MSG_DEF(JSMSG_DEBUG_BAD_REFERENT,     324, 2, JSEXN_TYPEERR, "{0} does not refer to {1}")
-MSG_DEF(JSMSG_DEBUG_WRAPPER_IN_WAY,   325, 3, JSEXN_TYPEERR, "{0} is {1}{2}a global object, but a direct reference is required")
-MSG_DEF(JSMSG_UNWRAP_DENIED,          326, 0, JSEXN_ERR, "permission denied to unwrap object")
-MSG_DEF(JSMSG_INTL_OBJECT_NOT_INITED, 327, 3, JSEXN_TYPEERR, "Intl.{0}.prototype.{1} called on value that's not an object initialized as a {2}")
-MSG_DEF(JSMSG_INVALID_LOCALES_ELEMENT,328, 0, JSEXN_TYPEERR, "invalid element in locales argument")
-MSG_DEF(JSMSG_INVALID_LANGUAGE_TAG,   329, 1, JSEXN_RANGEERR, "invalid language tag: {0}")
-MSG_DEF(JSMSG_INVALID_LOCALE_MATCHER, 330, 1, JSEXN_RANGEERR, "invalid locale matcher in supportedLocalesOf(): {0}")
-MSG_DEF(JSMSG_INVALID_OPTION_VALUE,   331, 2, JSEXN_RANGEERR, "invalid value {1} for option {0}")
-MSG_DEF(JSMSG_INVALID_DIGITS_VALUE,   332, 1, JSEXN_RANGEERR, "invalid digits value: {0}")
-MSG_DEF(JSMSG_INTL_OBJECT_REINITED,   333, 0, JSEXN_TYPEERR, "can't initialize object twice as an object of an Intl constructor")
-MSG_DEF(JSMSG_INVALID_CURRENCY_CODE,  334, 1, JSEXN_RANGEERR, "invalid currency code in NumberFormat(): {0}")
-MSG_DEF(JSMSG_UNDEFINED_CURRENCY,     335, 0, JSEXN_TYPEERR, "undefined currency in NumberFormat() with currency style")
-MSG_DEF(JSMSG_INVALID_TIME_ZONE,      336, 1, JSEXN_RANGEERR, "invalid time zone in DateTimeFormat(): {0}")
-MSG_DEF(JSMSG_DATE_NOT_FINITE,        337, 0, JSEXN_RANGEERR, "date value is not finite in DateTimeFormat.format()")
-MSG_DEF(JSMSG_USE_ASM_DIRECTIVE_FAIL, 338, 0, JSEXN_SYNTAXERR, "\"use asm\" is only meaningful in the Directive Prologue of a function body")
-MSG_DEF(JSMSG_USE_ASM_TYPE_FAIL,      339, 1, JSEXN_TYPEERR, "asm.js type error: {0}")
-MSG_DEF(JSMSG_USE_ASM_LINK_FAIL,      340, 1, JSEXN_TYPEERR, "asm.js link error: {0}")
-MSG_DEF(JSMSG_USE_ASM_TYPE_OK,        341, 1, JSEXN_NONE,    "Successfully compiled asm.js code ({0})")
-MSG_DEF(JSMSG_BAD_ARROW_ARGS,         342, 0, JSEXN_SYNTAXERR, "invalid arrow-function arguments (parentheses around the arrow-function may help)")
-MSG_DEF(JSMSG_YIELD_IN_ARROW,         343, 0, JSEXN_SYNTAXERR, "arrow function may not contain yield")
-MSG_DEF(JSMSG_WRONG_VALUE,            344, 2, JSEXN_ERR, "expected {0} but found {1}")
-MSG_DEF(JSMSG_PAR_ARRAY_SCATTER_BAD_TARGET, 345, 1, JSEXN_ERR, "target for index {0} is not an integer")
-MSG_DEF(JSMSG_SELFHOSTED_UNBOUND_NAME,346, 0, JSEXN_TYPEERR, "self-hosted code may not contain unbound name lookups")
-MSG_DEF(JSMSG_DEPRECATED_PRAGMA,  347, 1, JSEXN_NONE, "Using //@ to indicate {0} pragmas is deprecated. Use //# instead")
-MSG_DEF(JSMSG_BAD_DESTRUCT_ASSIGN,    348, 1, JSEXN_SYNTAXERR, "can't assign to {0} using destructuring assignment")
-MSG_DEF(JSMSG_TYPEDOBJECT_ARRAYTYPE_BAD_ARGS, 349, 0, JSEXN_ERR, "Invalid arguments")
-MSG_DEF(JSMSG_TYPEDOBJECT_BINARYARRAY_BAD_INDEX, 350, 0, JSEXN_RANGEERR, "invalid or out-of-range index")
-MSG_DEF(JSMSG_TYPEDOBJECT_STRUCTTYPE_BAD_ARGS, 351, 0, JSEXN_RANGEERR, "invalid field descriptor")
-MSG_DEF(JSMSG_TYPEDOBJECT_NOT_BINARYSTRUCT,   352, 1, JSEXN_TYPEERR, "{0} is not a BinaryStruct")
-MSG_DEF(JSMSG_TYPEDOBJECT_SUBARRAY_INTEGER_ARG, 353, 1, JSEXN_ERR, "argument {0} must be an integer")
-MSG_DEF(JSMSG_TYPEDOBJECT_STRUCTTYPE_EMPTY_DESCRIPTOR, 354, 0, JSEXN_ERR, "field descriptor cannot be empty")
-MSG_DEF(JSMSG_TYPEDOBJECT_STRUCTTYPE_BAD_FIELD, 355, 1, JSEXN_ERR, "field {0} is not a valid BinaryData Type descriptor")
-MSG_DEF(JSMSG_GENERATOR_FINISHED,     356, 0, JSEXN_TYPEERR, "generator has already finished")
-MSG_DEF(JSMSG_TYPEDOBJECT_TOO_BIG, 357, 0, JSEXN_ERR, "Type is too large to allocate")
-MSG_DEF(JSMSG_TYPEDOBJECT_NOT_TYPE_OBJECT, 358, 0, JSEXN_ERR, "Expected a type object")
-MSG_DEF(JSMSG_TOO_MANY_CON_SPREADARGS, 359, 0, JSEXN_RANGEERR, "too many constructor arguments")
-MSG_DEF(JSMSG_TOO_MANY_FUN_SPREADARGS, 360, 0, JSEXN_RANGEERR, "too many function arguments")
-MSG_DEF(JSMSG_DEBUG_NOT_DEBUGGEE,     361, 2, JSEXN_ERR, "{0} is not a debuggee {1}")
-MSG_DEF(JSMSG_TYPEDOBJECT_NOT_TYPED_OBJECT, 362, 0, JSEXN_ERR, "Expected a typed object")
-MSG_DEF(JSMSG_TYPEDOBJECT_NO_SUCH_PROP, 363, 1, JSEXN_TYPEERR, "No such property: {0}")
-MSG_DEF(JSMSG_TYPEDOBJECT_BAD_ARGS, 364, 0, JSEXN_TYPEERR, "invalid arguments")
-MSG_DEF(JSMSG_TYPEDOBJECT_HANDLE_UNATTACHED, 365, 0, JSEXN_TYPEERR, "handle unattached")
-MSG_DEF(JSMSG_TYPEDOBJECT_HANDLE_BAD_TYPE, 366, 0, JSEXN_TYPEERR, "handle moved to destination of incorrect type")
-
-MSG_DEF(JSMSG_IMPORT_DECL_AT_TOP_LEVEL, 367, 0, JSEXN_SYNTAXERR, "import declarations may only appear at top level")
-MSG_DEF(JSMSG_NO_IMPORT_NAME,         368, 0, JSEXN_SYNTAXERR, "missing import name")
-MSG_DEF(JSMSG_AS_AFTER_RESERVED_WORD, 369, 1, JSEXN_SYNTAXERR, "missing keyword 'as' after reserved word '{0}'")
-MSG_DEF(JSMSG_NO_BINDING_NAME,	      370, 0, JSEXN_SYNTAXERR, "missing binding name")
-MSG_DEF(JSMSG_RC_AFTER_IMPORT_SPEC_LIST, 371, 0, JSEXN_SYNTAXERR, "missing '}' after module specifier list")
-MSG_DEF(JSMSG_FROM_AFTER_IMPORT_SPEC_SET, 372, 0, JSEXN_SYNTAXERR, "missing keyword 'from' after import specifier set")
-MSG_DEF(JSMSG_DECLARATION_AFTER_IMPORT, 373, 0, JSEXN_SYNTAXERR, "missing declaration after 'import' keyword")
-MSG_DEF(JSMSG_MODULE_SPEC_AFTER_FROM,   374, 0, JSEXN_SYNTAXERR, "missing module specifier after 'from' keyword")
-MSG_DEF(JSMSG_MODULES_NOT_IMPLEMENTED,  375, 0, JSEXN_SYNTAXERR, "modules are not implemented yet")
-MSG_DEF(JSMSG_EXPORT_DECL_AT_TOP_LEVEL, 376, 0, JSEXN_SYNTAXERR, "export declarations may only appear at top level")
-MSG_DEF(JSMSG_RC_AFTER_EXPORT_SPEC_LIST, 377, 0, JSEXN_SYNTAXERR, "missing '}' after export specifier list")
-MSG_DEF(JSMSG_NO_EXPORT_NAME,           378, 0, JSEXN_SYNTAXERR, "missing export name")
-MSG_DEF(JSMSG_DECLARATION_AFTER_EXPORT, 379, 0, JSEXN_SYNTAXERR, "missing declaration after 'export' keyword")
-MSG_DEF(JSMSG_INVALID_PROTOTYPE,        380, 0, JSEXN_TYPEERR, "prototype field is not an object")
-MSG_DEF(JSMSG_TYPEDOBJECT_HANDLE_TO_UNSIZED, 381, 0, JSEXN_TYPEERR, "cannot create a handle to an unsized type")
-MSG_DEF(JSMSG_SETPROTOTYPEOF_FAIL,      382, 1, JSEXN_TYPEERR, "[[SetPrototypeOf]] failed on {0}")
-MSG_DEF(JSMSG_INVALID_ARG_TYPE,         383, 3, JSEXN_TYPEERR, "Invalid type: {0} can't be a{1} {2}")
-MSG_DEF(JSMSG_TERMINATED,               384, 1, JSEXN_ERR, "Script terminated by timeout at:\n{0}")
-MSG_DEF(JSMSG_NO_SUCH_SELF_HOSTED_PROP, 385, 1, JSEXN_ERR, "No such property on self-hosted object: {0}")
-MSG_DEF(JSMSG_PROXY_EXTENSIBILITY,      386, 0, JSEXN_TYPEERR, "proxy must report same extensiblitity as target")
-MSG_DEF(JSMSG_PROXY_CONSTRUCT_OBJECT,   387, 0, JSEXN_TYPEERR, "proxy [[Construct]] must return an object")
-MSG_DEF(JSMSG_PROXY_GETOWN_OBJORUNDEF,  388, 0, JSEXN_TYPEERR, "proxy [[GetOwnProperty]] must return an object or undefined")
-MSG_DEF(JSMSG_CANT_REPORT_C_AS_NC,      389, 0, JSEXN_TYPEERR, "proxy can't report existing configurable property as non-configurable")
-MSG_DEF(JSMSG_COMP_PROP_UNTERM_EXPR,    390, 0, JSEXN_SYNTAXERR, "missing ] in computed property name")
+MSG_DEF(JSMSG_NOT_AN_ERROR,            0, JSEXN_NONE, "<Error #0 is reserved>")
+MSG_DEF(JSMSG_NOT_DEFINED,             1, JSEXN_REFERENCEERR, "{0} is not defined")
+MSG_DEF(JSMSG_INACTIVE,                0, JSEXN_INTERNALERR, "nothing active on context")
+MSG_DEF(JSMSG_MORE_ARGS_NEEDED,        3, JSEXN_TYPEERR, "{0} requires more than {1} argument{2}")
+MSG_DEF(JSMSG_BAD_CHAR,                1, JSEXN_INTERNALERR, "invalid format character {0}")
+MSG_DEF(JSMSG_BAD_TYPE,                1, JSEXN_TYPEERR, "unknown type {0}")
+MSG_DEF(JSMSG_ALLOC_OVERFLOW,          0, JSEXN_INTERNALERR, "allocation size overflow")
+MSG_DEF(JSMSG_MISSING_HEXDIGITS,       0, JSEXN_SYNTAXERR, "missing hexadecimal digits after '0x'")
+MSG_DEF(JSMSG_INCOMPATIBLE_PROTO,      3, JSEXN_TYPEERR, "{0}.prototype.{1} called on incompatible {2}")
+MSG_DEF(JSMSG_NO_CONSTRUCTOR,          1, JSEXN_TYPEERR, "{0} has no constructor")
+MSG_DEF(JSMSG_CANT_ALIAS,              3, JSEXN_TYPEERR, "can't alias {0} to {1} in class {2}")
+MSG_DEF(JSMSG_NOT_SCRIPTED_FUNCTION,   1, JSEXN_TYPEERR, "{0} is not a scripted function")
+MSG_DEF(JSMSG_BAD_SORT_ARG,            0, JSEXN_TYPEERR, "invalid Array.prototype.sort argument")
+MSG_DEF(JSMSG_BAD_ATOMIC_NUMBER,       1, JSEXN_INTERNALERR, "internal error: no index for atom {0}")
+MSG_DEF(JSMSG_TOO_MANY_LITERALS,       0, JSEXN_INTERNALERR, "too many literals")
+MSG_DEF(JSMSG_CANT_WATCH,              1, JSEXN_TYPEERR, "can't watch non-native objects of class {0}")
+MSG_DEF(JSMSG_STACK_UNDERFLOW,         2, JSEXN_INTERNALERR, "internal error compiling {0}: stack underflow at pc {1}")
+MSG_DEF(JSMSG_NEED_DIET,               1, JSEXN_INTERNALERR, "{0} too large")
+MSG_DEF(JSMSG_TOO_MANY_LOCAL_ROOTS,    0, JSEXN_ERR, "out of local root space")
+MSG_DEF(JSMSG_READ_ONLY,               1, JSEXN_TYPEERR, "{0} is read-only")
+MSG_DEF(JSMSG_BAD_FORMAL,              0, JSEXN_SYNTAXERR, "malformed formal parameter")
+MSG_DEF(JSMSG_CANT_DELETE,             1, JSEXN_TYPEERR, "property {0} is non-configurable and can't be deleted")
+MSG_DEF(JSMSG_NOT_FUNCTION,            1, JSEXN_TYPEERR, "{0} is not a function")
+MSG_DEF(JSMSG_NOT_CONSTRUCTOR,         1, JSEXN_TYPEERR, "{0} is not a constructor")
+MSG_DEF(JSMSG_INVALID_DATE,            0, JSEXN_RANGEERR, "invalid date")
+MSG_DEF(JSMSG_TOO_DEEP,                1, JSEXN_INTERNALERR, "{0} nested too deeply")
+MSG_DEF(JSMSG_OVER_RECURSED,           0, JSEXN_INTERNALERR, "too much recursion")
+MSG_DEF(JSMSG_IN_NOT_OBJECT,           1, JSEXN_TYPEERR, "invalid 'in' operand {0}")
+MSG_DEF(JSMSG_BAD_NEW_RESULT,          1, JSEXN_TYPEERR, "invalid new expression result {0}")
+MSG_DEF(JSMSG_OBJECT_ACCESS_DENIED,    0, JSEXN_ERR, "Permission denied to access object")
+MSG_DEF(JSMSG_PROPERTY_ACCESS_DENIED,  1, JSEXN_ERR, "Permission denied to access property '{0}'")
+MSG_DEF(JSMSG_BAD_INSTANCEOF_RHS,      1, JSEXN_TYPEERR, "invalid 'instanceof' operand {0}")
+MSG_DEF(JSMSG_BAD_BYTECODE,            1, JSEXN_INTERNALERR, "unimplemented JavaScript bytecode {0}")
+MSG_DEF(JSMSG_BAD_RADIX,               0, JSEXN_RANGEERR, "radix must be an integer at least 2 and no greater than 36")
+MSG_DEF(JSMSG_PAREN_BEFORE_LET,        0, JSEXN_SYNTAXERR, "missing ( before let head")
+MSG_DEF(JSMSG_CANT_CONVERT,            1, JSEXN_ERR, "can't convert {0} to an integer")
+MSG_DEF(JSMSG_CYCLIC_VALUE,            1, JSEXN_TYPEERR, "cyclic {0} value")
+MSG_DEF(JSMSG_COMPILE_EXECED_SCRIPT,   0, JSEXN_TYPEERR, "can't compile over a script that is currently executing")
+MSG_DEF(JSMSG_CANT_CONVERT_TO,         2, JSEXN_TYPEERR, "can't convert {0} to {1}")
+MSG_DEF(JSMSG_NO_PROPERTIES,           1, JSEXN_TYPEERR, "{0} has no properties")
+MSG_DEF(JSMSG_CANT_FIND_CLASS,         1, JSEXN_TYPEERR, "can't find class id {0}")
+MSG_DEF(JSMSG_DEAD_OBJECT,             0, JSEXN_TYPEERR, "can't access dead object")
+MSG_DEF(JSMSG_BYTECODE_TOO_BIG,        2, JSEXN_INTERNALERR, "bytecode {0} too large (limit {1})")
+MSG_DEF(JSMSG_UNKNOWN_FORMAT,          1, JSEXN_INTERNALERR, "unknown bytecode format {0}")
+MSG_DEF(JSMSG_TOO_MANY_CON_ARGS,       0, JSEXN_SYNTAXERR, "too many constructor arguments")
+MSG_DEF(JSMSG_TOO_MANY_FUN_ARGS,       0, JSEXN_SYNTAXERR, "too many function arguments")
+MSG_DEF(JSMSG_BAD_QUANTIFIER,          0, JSEXN_SYNTAXERR, "invalid quantifier")
+MSG_DEF(JSMSG_MIN_TOO_BIG,             1, JSEXN_SYNTAXERR, "overlarge minimum {0}")
+MSG_DEF(JSMSG_MAX_TOO_BIG,             1, JSEXN_SYNTAXERR, "overlarge maximum {0}")
+MSG_DEF(JSMSG_OUT_OF_ORDER,            1, JSEXN_SYNTAXERR, "maximum {0} less than minimum")
+MSG_DEF(JSMSG_BAD_DESTRUCT_DECL,       0, JSEXN_SYNTAXERR, "missing = in destructuring declaration")
+MSG_DEF(JSMSG_BAD_DESTRUCT_ASS,        0, JSEXN_REFERENCEERR, "invalid destructuring assignment operator")
+MSG_DEF(JSMSG_PAREN_AFTER_LET,         0, JSEXN_SYNTAXERR, "missing ) after let head")
+MSG_DEF(JSMSG_CURLY_AFTER_LET,         0, JSEXN_SYNTAXERR, "missing } after let block")
+MSG_DEF(JSMSG_MISSING_PAREN,           0, JSEXN_SYNTAXERR, "unterminated parenthetical")
+MSG_DEF(JSMSG_UNTERM_CLASS,            0, JSEXN_SYNTAXERR, "unterminated character class")
+MSG_DEF(JSMSG_TRAILING_SLASH,          0, JSEXN_SYNTAXERR, "trailing \\ in regular expression")
+MSG_DEF(JSMSG_BAD_CLASS_RANGE,         0, JSEXN_SYNTAXERR, "invalid range in character class")
+MSG_DEF(JSMSG_BAD_REGEXP_FLAG,         1, JSEXN_SYNTAXERR, "invalid regular expression flag {0}")
+MSG_DEF(JSMSG_NO_INPUT,                5, JSEXN_SYNTAXERR, "no input for /{0}/{1}{2}{3}{4}")
+MSG_DEF(JSMSG_CANT_OPEN,               2, JSEXN_ERR, "can't open {0}: {1}")
+MSG_DEF(JSMSG_TOO_MANY_FUN_APPLY_ARGS, 0, JSEXN_RANGEERR, "arguments array passed to Function.prototype.apply is too large")
+MSG_DEF(JSMSG_UNMATCHED_RIGHT_PAREN,   0, JSEXN_SYNTAXERR, "unmatched ) in regular expression")
+MSG_DEF(JSMSG_TOO_BIG_TO_ENCODE,       0, JSEXN_INTERNALERR, "data are to big to encode")
+MSG_DEF(JSMSG_ARG_INDEX_OUT_OF_RANGE,  1, JSEXN_RANGEERR, "argument {0} accesses an index that is out of range")
+MSG_DEF(JSMSG_SPREAD_TOO_LARGE,        0, JSEXN_RANGEERR, "array too large due to spread operand(s)")
+MSG_DEF(JSMSG_SOURCE_TOO_LONG,         0, JSEXN_RANGEERR, "source is too long")
+MSG_DEF(JSMSG_BAD_WEAKMAP_KEY,         0, JSEXN_TYPEERR, "cannot use the given object as a weak map key")
+MSG_DEF(JSMSG_BAD_SCRIPT_MAGIC,        0, JSEXN_INTERNALERR, "bad script XDR magic number")
+MSG_DEF(JSMSG_PAREN_BEFORE_FORMAL,     0, JSEXN_SYNTAXERR, "missing ( before formal parameters")
+MSG_DEF(JSMSG_MISSING_FORMAL,          0, JSEXN_SYNTAXERR, "missing formal parameter")
+MSG_DEF(JSMSG_PAREN_AFTER_FORMAL,      0, JSEXN_SYNTAXERR, "missing ) after formal parameters")
+MSG_DEF(JSMSG_CURLY_BEFORE_BODY,       0, JSEXN_SYNTAXERR, "missing { before function body")
+MSG_DEF(JSMSG_CURLY_AFTER_BODY,        0, JSEXN_SYNTAXERR, "missing } after function body")
+MSG_DEF(JSMSG_PAREN_BEFORE_COND,       0, JSEXN_SYNTAXERR, "missing ( before condition")
+MSG_DEF(JSMSG_PAREN_AFTER_COND,        0, JSEXN_SYNTAXERR, "missing ) after condition")
+MSG_DEF(JSMSG_BAD_DUP_ARGS,            0, JSEXN_SYNTAXERR, "duplicate argument names not allowed in this context")
+MSG_DEF(JSMSG_NAME_AFTER_DOT,          0, JSEXN_SYNTAXERR, "missing name after . operator")
+MSG_DEF(JSMSG_BRACKET_IN_INDEX,        0, JSEXN_SYNTAXERR, "missing ] in index expression")
+MSG_DEF(JSMSG_ACCESSOR_DEF_DENIED,     1, JSEXN_ERR, "Permission denied to define accessor property '{0}'")
+MSG_DEF(JSMSG_PAREN_BEFORE_SWITCH,     0, JSEXN_SYNTAXERR, "missing ( before switch expression")
+MSG_DEF(JSMSG_PAREN_AFTER_SWITCH,      0, JSEXN_SYNTAXERR, "missing ) after switch expression")
+MSG_DEF(JSMSG_CURLY_BEFORE_SWITCH,     0, JSEXN_SYNTAXERR, "missing { before switch body")
+MSG_DEF(JSMSG_COLON_AFTER_CASE,        0, JSEXN_SYNTAXERR, "missing : after case label")
+MSG_DEF(JSMSG_WHILE_AFTER_DO,          0, JSEXN_SYNTAXERR, "missing while after do-loop body")
+MSG_DEF(JSMSG_PAREN_AFTER_FOR,         0, JSEXN_SYNTAXERR, "missing ( after for")
+MSG_DEF(JSMSG_SEMI_AFTER_FOR_INIT,     0, JSEXN_SYNTAXERR, "missing ; after for-loop initializer")
+MSG_DEF(JSMSG_SEMI_AFTER_FOR_COND,     0, JSEXN_SYNTAXERR, "missing ; after for-loop condition")
+MSG_DEF(JSMSG_PAREN_AFTER_FOR_CTRL,    0, JSEXN_SYNTAXERR, "missing ) after for-loop control")
+MSG_DEF(JSMSG_CURLY_BEFORE_TRY,        0, JSEXN_SYNTAXERR, "missing { before try block")
+MSG_DEF(JSMSG_CURLY_AFTER_TRY,         0, JSEXN_SYNTAXERR, "missing } after try block")
+MSG_DEF(JSMSG_PAREN_BEFORE_CATCH,      0, JSEXN_SYNTAXERR, "missing ( before catch")
+MSG_DEF(JSMSG_CATCH_IDENTIFIER,        0, JSEXN_SYNTAXERR, "missing identifier in catch")
+MSG_DEF(JSMSG_PAREN_AFTER_CATCH,       0, JSEXN_SYNTAXERR, "missing ) after catch")
+MSG_DEF(JSMSG_CURLY_BEFORE_CATCH,      0, JSEXN_SYNTAXERR, "missing { before catch block")
+MSG_DEF(JSMSG_CURLY_AFTER_CATCH,       0, JSEXN_SYNTAXERR, "missing } after catch block")
+MSG_DEF(JSMSG_CURLY_BEFORE_FINALLY,    0, JSEXN_SYNTAXERR, "missing { before finally block")
+MSG_DEF(JSMSG_CURLY_AFTER_FINALLY,     0, JSEXN_SYNTAXERR, "missing } after finally block")
+MSG_DEF(JSMSG_CATCH_OR_FINALLY,        0, JSEXN_SYNTAXERR, "missing catch or finally after try")
+MSG_DEF(JSMSG_PAREN_BEFORE_WITH,       0, JSEXN_SYNTAXERR, "missing ( before with-statement object")
+MSG_DEF(JSMSG_PAREN_AFTER_WITH,        0, JSEXN_SYNTAXERR, "missing ) after with-statement object")
+MSG_DEF(JSMSG_CURLY_IN_COMPOUND,       0, JSEXN_SYNTAXERR, "missing } in compound statement")
+MSG_DEF(JSMSG_NO_VARIABLE_NAME,        0, JSEXN_SYNTAXERR, "missing variable name")
+MSG_DEF(JSMSG_COLON_IN_COND,           0, JSEXN_SYNTAXERR, "missing : in conditional expression")
+MSG_DEF(JSMSG_PAREN_AFTER_ARGS,        0, JSEXN_SYNTAXERR, "missing ) after argument list")
+MSG_DEF(JSMSG_BRACKET_AFTER_LIST,      0, JSEXN_SYNTAXERR, "missing ] after element list")
+MSG_DEF(JSMSG_COLON_AFTER_ID,          0, JSEXN_SYNTAXERR, "missing : after property id")
+MSG_DEF(JSMSG_CURLY_AFTER_LIST,        0, JSEXN_SYNTAXERR, "missing } after property list")
+MSG_DEF(JSMSG_PAREN_IN_PAREN,          0, JSEXN_SYNTAXERR, "missing ) in parenthetical")
+MSG_DEF(JSMSG_SEMI_BEFORE_STMNT,       0, JSEXN_SYNTAXERR, "missing ; before statement")
+MSG_DEF(JSMSG_TEMPLSTR_UNTERM_EXPR,    0, JSEXN_SYNTAXERR, "missing } in template string")
+MSG_DEF(JSMSG_DUPLICATE_FORMAL,        1, JSEXN_SYNTAXERR, "duplicate formal argument {0}")
+MSG_DEF(JSMSG_EQUAL_AS_ASSIGN,         0, JSEXN_SYNTAXERR, "test for equality (==) mistyped as assignment (=)?")
+MSG_DEF(JSMSG_OPTIMIZED_CLOSURE_LEAK,  0, JSEXN_INTERNALERR, "can't access optimized closure")
+MSG_DEF(JSMSG_TOO_MANY_DEFAULTS,       0, JSEXN_SYNTAXERR, "more than one switch default")
+MSG_DEF(JSMSG_TOO_MANY_CASES,          0, JSEXN_INTERNALERR, "too many switch cases")
+MSG_DEF(JSMSG_BAD_SWITCH,              0, JSEXN_SYNTAXERR, "invalid switch statement")
+MSG_DEF(JSMSG_BAD_FOR_LEFTSIDE,        0, JSEXN_SYNTAXERR, "invalid for/in left-hand side")
+MSG_DEF(JSMSG_CATCH_AFTER_GENERAL,     0, JSEXN_SYNTAXERR, "catch after unconditional catch")
+MSG_DEF(JSMSG_CATCH_WITHOUT_TRY,       0, JSEXN_SYNTAXERR, "catch without try")
+MSG_DEF(JSMSG_FINALLY_WITHOUT_TRY,     0, JSEXN_SYNTAXERR, "finally without try")
+MSG_DEF(JSMSG_LABEL_NOT_FOUND,         0, JSEXN_SYNTAXERR, "label not found")
+MSG_DEF(JSMSG_TOUGH_BREAK,             0, JSEXN_SYNTAXERR, "unlabeled break must be inside loop or switch")
+MSG_DEF(JSMSG_BAD_CONTINUE,            0, JSEXN_SYNTAXERR, "continue must be inside loop")
+MSG_DEF(JSMSG_BAD_RETURN_OR_YIELD,     1, JSEXN_SYNTAXERR, "{0} not in function")
+MSG_DEF(JSMSG_BAD_LABEL,               0, JSEXN_SYNTAXERR, "invalid label")
+MSG_DEF(JSMSG_DUPLICATE_LABEL,         0, JSEXN_SYNTAXERR, "duplicate label")
+MSG_DEF(JSMSG_VAR_HIDES_ARG,           1, JSEXN_TYPEERR, "variable {0} redeclares argument")
+MSG_DEF(JSMSG_BAD_VAR_INIT,            0, JSEXN_SYNTAXERR, "invalid variable initialization")
+MSG_DEF(JSMSG_BAD_LEFTSIDE_OF_ASS,     0, JSEXN_REFERENCEERR, "invalid assignment left-hand side")
+MSG_DEF(JSMSG_BAD_OPERAND,             1, JSEXN_SYNTAXERR, "invalid {0} operand")
+MSG_DEF(JSMSG_BAD_PROP_ID,             0, JSEXN_SYNTAXERR, "invalid property id")
+MSG_DEF(JSMSG_RESERVED_ID,             1, JSEXN_SYNTAXERR, "{0} is a reserved identifier")
+MSG_DEF(JSMSG_SYNTAX_ERROR,            0, JSEXN_SYNTAXERR, "syntax error")
+MSG_DEF(JSMSG_MISSING_BINARY_DIGITS,   0, JSEXN_SYNTAXERR, "missing binary digits after '0b'")
+MSG_DEF(JSMSG_BAD_PROTOTYPE,           1, JSEXN_TYPEERR,   "'prototype' property of {0} is not an object")
+MSG_DEF(JSMSG_MISSING_EXPONENT,        0, JSEXN_SYNTAXERR, "missing exponent")
+MSG_DEF(JSMSG_OUT_OF_MEMORY,           0, JSEXN_ERR, "out of memory")
+MSG_DEF(JSMSG_UNTERMINATED_STRING,     0, JSEXN_SYNTAXERR, "unterminated string literal")
+MSG_DEF(JSMSG_TOO_MANY_PARENS,         0, JSEXN_INTERNALERR, "too many parentheses in regular expression")
+MSG_DEF(JSMSG_UNTERMINATED_COMMENT,    0, JSEXN_SYNTAXERR, "unterminated comment")
+MSG_DEF(JSMSG_UNTERMINATED_REGEXP,     0, JSEXN_SYNTAXERR, "unterminated regular expression literal")
+MSG_DEF(JSMSG_BAD_CLONE_FUNOBJ_SCOPE,  0, JSEXN_TYPEERR, "bad cloned function scope chain")
+MSG_DEF(JSMSG_MISSING_OCTAL_DIGITS,    0, JSEXN_SYNTAXERR, "missing octal digits after '0o'")
+MSG_DEF(JSMSG_ILLEGAL_CHARACTER,       0, JSEXN_SYNTAXERR, "illegal character")
+MSG_DEF(JSMSG_BAD_OCTAL,               1, JSEXN_SYNTAXERR, "{0} is not a legal ECMA-262 octal constant")
+MSG_DEF(JSMSG_RESULTING_STRING_TOO_LARGE, 0, JSEXN_RANGEERR, "repeat count must be less than infinity and not overflow maximum string size")
+MSG_DEF(JSMSG_UNCAUGHT_EXCEPTION,      1, JSEXN_INTERNALERR, "uncaught exception: {0}")
+MSG_DEF(JSMSG_INVALID_BACKREF,         0, JSEXN_SYNTAXERR, "non-octal digit in an escape sequence that doesn't match a back-reference")
+MSG_DEF(JSMSG_BAD_BACKREF,             0, JSEXN_SYNTAXERR, "back-reference exceeds number of capturing parentheses")
+MSG_DEF(JSMSG_PRECISION_RANGE,         1, JSEXN_RANGEERR, "precision {0} out of range")
+MSG_DEF(JSMSG_BAD_GETTER_OR_SETTER,    1, JSEXN_TYPEERR, "invalid {0} usage")
+MSG_DEF(JSMSG_BAD_ARRAY_LENGTH,        0, JSEXN_RANGEERR, "invalid array length")
+MSG_DEF(JSMSG_CANT_DESCRIBE_PROPS,     1, JSEXN_TYPEERR, "can't describe non-native properties of class {0}")
+MSG_DEF(JSMSG_BAD_APPLY_ARGS,          1, JSEXN_TYPEERR, "second argument to Function.prototype.{0} must be an array")
+MSG_DEF(JSMSG_REDECLARED_VAR,          2, JSEXN_TYPEERR, "redeclaration of {0} {1}")
+MSG_DEF(JSMSG_UNDECLARED_VAR,          1, JSEXN_REFERENCEERR, "assignment to undeclared variable {0}")
+MSG_DEF(JSMSG_PROXY_REVOKED,           0, JSEXN_TYPEERR, "illegal operation attempted on a revoked proxy")
+MSG_DEF(JSMSG_DEPRECATED_USAGE,        1, JSEXN_REFERENCEERR, "deprecated {0} usage")
+MSG_DEF(JSMSG_BAD_URI,                 0, JSEXN_URIERR, "malformed URI sequence")
+MSG_DEF(JSMSG_GETTER_ONLY,             0, JSEXN_TYPEERR, "setting a property that has only a getter")
+MSG_DEF(JSMSG_IDSTART_AFTER_NUMBER,    0, JSEXN_SYNTAXERR, "identifier starts immediately after numeric literal")
+MSG_DEF(JSMSG_UNDEFINED_PROP,          1, JSEXN_REFERENCEERR, "reference to undefined property {0}")
+MSG_DEF(JSMSG_USELESS_EXPR,            0, JSEXN_TYPEERR, "useless expression")
+MSG_DEF(JSMSG_REDECLARED_PARAM,        1, JSEXN_TYPEERR, "redeclaration of formal parameter {0}")
+MSG_DEF(JSMSG_NEWREGEXP_FLAGGED,       0, JSEXN_TYPEERR, "can't supply flags when constructing one RegExp from another")
+MSG_DEF(JSMSG_RESERVED_SLOT_RANGE,     0, JSEXN_RANGEERR, "reserved slot index out of range")
+MSG_DEF(JSMSG_CANT_DECODE_PRINCIPALS,  0, JSEXN_INTERNALERR, "can't decode JSPrincipals")
+MSG_DEF(JSMSG_CANT_SEAL_OBJECT,        1, JSEXN_ERR, "can't seal {0} objects")
+MSG_DEF(JSMSG_TOO_MANY_CATCH_VARS,     0, JSEXN_SYNTAXERR, "too many catch variables")
+MSG_DEF(JSMSG_NEGATIVE_REPETITION_COUNT, 0, JSEXN_RANGEERR, "repeat count must be non-negative")
+MSG_DEF(JSMSG_INVALID_FOR_OF_INIT,     0, JSEXN_SYNTAXERR, "for-of loop variable declaration may not have an initializer")
+MSG_DEF(JSMSG_INVALID_MAP_ITERABLE,    0, JSEXN_TYPEERR, "iterable for map should have array-like objects")
+MSG_DEF(JSMSG_NOT_A_CODEPOINT,         1, JSEXN_RANGEERR, "{0} is not a valid code point")
+MSG_DEF(JSMSG_BRACKET_AFTER_ARRAY_COMPREHENSION, 0, JSEXN_SYNTAXERR, "missing ] after array comprehension")
+MSG_DEF(JSMSG_NESTING_GENERATOR,       0, JSEXN_TYPEERR, "already executing generator")
+MSG_DEF(JSMSG_PAREN_AFTER_FOR_OF_ITERABLE, 0, JSEXN_SYNTAXERR, "missing ) after for-of iterable")
+MSG_DEF(JSMSG_INVALID_NORMALIZE_FORM,  0, JSEXN_RANGEERR, "form must be one of 'NFC', 'NFD', 'NFKC', or 'NFKD'")
+MSG_DEF(JSMSG_NOTHING_TO_REPEAT,       0, JSEXN_SYNTAXERR, "nothing to repeat")
+MSG_DEF(JSMSG_INVALID_GROUP,           0, JSEXN_SYNTAXERR, "invalid regexp group")
+MSG_DEF(JSMSG_ESCAPE_AT_END_OF_REGEXP, 0, JSEXN_SYNTAXERR, "\\ at end of pattern")
+MSG_DEF(JSMSG_NUMBERS_OUT_OF_ORDER,    0, JSEXN_SYNTAXERR, "numbers out of order in {} quantifier.")
+MSG_DEF(JSMSG_BAD_GENERATOR_SEND,      1, JSEXN_TYPEERR, "attempt to send {0} to newborn generator")
+MSG_DEF(JSMSG_SC_NOT_TRANSFERABLE,     0, JSEXN_TYPEERR, "invalid transferable array for structured clone")
+MSG_DEF(JSMSG_SC_DUP_TRANSFERABLE,     0, JSEXN_TYPEERR, "duplicate transferable for structured clone")
+MSG_DEF(JSMSG_CANT_REPORT_AS_NON_EXTENSIBLE, 0, JSEXN_TYPEERR, "proxy can't report an extensible object as non-extensible")
+MSG_DEF(JSMSG_SYMBOL_TO_STRING,        0, JSEXN_TYPEERR, "can't convert symbol to string")
+MSG_DEF(JSMSG_OBJECT_METADATA_CALLBACK_ALREADY_SET, 0, JSEXN_ERR, "Cannot track object allocation, because other tools are already doing so")
+MSG_DEF(JSMSG_INCOMPATIBLE_METHOD,     3, JSEXN_TYPEERR, "{0} {1} called on incompatible {2}")
+MSG_DEF(JSMSG_SYMBOL_TO_NUMBER,        0, JSEXN_TYPEERR, "can't convert symbol to number")
+MSG_DEF(JSMSG_NOT_TRACKING_ALLOCATIONS, 1, JSEXN_ERR, "Cannot call {0} without setting trackingAllocationSites to true")
+MSG_DEF(JSMSG_BAD_INDEX,               0, JSEXN_RANGEERR, "invalid or out-of-range index")
+MSG_DEF(JSMSG_SELFHOSTED_TOP_LEVEL_LET,0, JSEXN_SYNTAXERR, "self-hosted code cannot contain top-level 'let' declarations")
+MSG_DEF(JSMSG_BAD_FOR_EACH_LOOP,       0, JSEXN_SYNTAXERR, "invalid for each loop")
+MSG_DEF(JSMSG_OBJECT_WATCH_DEPRECATED, 0, JSEXN_NONE, "Object.prototype.watch and unwatch are very slow, non-standard, and deprecated; use a getter/setter instead")
+MSG_DEF(JSMSG_TYPE_ERR_BAD_ARGS,       0, JSEXN_TYPEERR, "invalid arguments")
+MSG_DEF(JSMSG_REDECLARED_CATCH_IDENTIFIER, 1, JSEXN_TYPEERR, "redeclaration of identifier '{0}' in catch")
+MSG_DEF(JSMSG_INTERNAL_INTL_ERROR,     0, JSEXN_ERR, "internal error while computing Intl data")
+MSG_DEF(JSMSG_DEFAULT_LOCALE_ERROR,    0, JSEXN_ERR, "internal error getting the default locale")
+MSG_DEF(JSMSG_TOO_MANY_LOCALS,         0, JSEXN_SYNTAXERR, "too many local variables")
+MSG_DEF(JSMSG_ARRAY_INIT_TOO_BIG,      0, JSEXN_INTERNALERR, "array initialiser too large")
+MSG_DEF(JSMSG_REGEXP_TOO_COMPLEX,      0, JSEXN_INTERNALERR, "regular expression too complex")
+MSG_DEF(JSMSG_BUFFER_TOO_SMALL,        0, JSEXN_INTERNALERR, "buffer too small")
+MSG_DEF(JSMSG_BAD_SURROGATE_CHAR,      1, JSEXN_TYPEERR, "bad surrogate character {0}")
+MSG_DEF(JSMSG_UTF8_CHAR_TOO_LARGE,     1, JSEXN_TYPEERR, "UTF-8 character {0} too large")
+MSG_DEF(JSMSG_MALFORMED_UTF8_CHAR,     1, JSEXN_TYPEERR, "malformed UTF-8 character sequence at offset {0}")
+MSG_DEF(JSMSG_USER_DEFINED_ERROR,      0, JSEXN_ERR, "JS_ReportError was called")
+MSG_DEF(JSMSG_WRONG_CONSTRUCTOR,       1, JSEXN_TYPEERR, "wrong constructor called for {0}")
+MSG_DEF(JSMSG_BAD_GENERATOR_RETURN,    1, JSEXN_TYPEERR, "generator function {0} returns a value")
+MSG_DEF(JSMSG_BAD_ANON_GENERATOR_RETURN, 0, JSEXN_TYPEERR, "anonymous generator function returns a value")
+MSG_DEF(JSMSG_PROTO_SETTING_SLOW,      0, JSEXN_NONE, "mutating the [[Prototype]] of an object will cause your code to run very slowly; instead create the object with the correct initial [[Prototype]] value using Object.create")
+MSG_DEF(JSMSG_IN_AFTER_FOR_NAME,       0, JSEXN_SYNTAXERR, "missing 'in' or 'of' after for")
+MSG_DEF(JSMSG_BAD_TRAP_RETURN_VALUE,   2, JSEXN_TYPEERR,"trap {1} for {0} returned a primitive value")
+MSG_DEF(JSMSG_OF_AFTER_FOR_NAME,       0, JSEXN_SYNTAXERR, "missing 'of' after for")
+MSG_DEF(JSMSG_BAD_GENERATOR_YIELD,     1, JSEXN_TYPEERR, "yield from closing generator {0}")
+MSG_DEF(JSMSG_BAD_GENERATOR_SYNTAX,    1, JSEXN_SYNTAXERR, "{0} expression must be parenthesized")
+MSG_DEF(JSMSG_ARRAY_COMP_LEFTSIDE,     0, JSEXN_SYNTAXERR, "invalid array comprehension left-hand side")
+MSG_DEF(JSMSG_LET_COMP_BINDING,        0, JSEXN_SYNTAXERR, "'let' is not a valid name for a comprehension variable")
+MSG_DEF(JSMSG_EMPTY_ARRAY_REDUCE,      0, JSEXN_TYPEERR, "reduce of empty array with no initial value")
+MSG_DEF(JSMSG_BAD_SYMBOL,              1, JSEXN_TYPEERR, "{0} is not a well-known @@-symbol")
+MSG_DEF(JSMSG_BAD_DELETE_OPERAND,      0, JSEXN_REFERENCEERR, "invalid delete operand")
+MSG_DEF(JSMSG_BAD_INCOP_OPERAND,       0, JSEXN_REFERENCEERR, "invalid increment/decrement operand")
+MSG_DEF(JSMSG_UNEXPECTED_TYPE,         2, JSEXN_TYPEERR, "{0} is {1}")
+MSG_DEF(JSMSG_LET_DECL_NOT_IN_BLOCK,   0, JSEXN_SYNTAXERR, "let declaration not directly within block")
+MSG_DEF(JSMSG_CONTRARY_NONDIRECTIVE,   1, JSEXN_SYNTAXERR, "'{0}' statement won't be enforced as a directive because it isn't in directive prologue position")
+MSG_DEF(JSMSG_CANT_SET_ARRAY_ATTRS,    0, JSEXN_INTERNALERR, "can't set attributes on indexed array properties")
+MSG_DEF(JSMSG_EVAL_ARITY,              0, JSEXN_TYPEERR, "eval accepts only one parameter")
+MSG_DEF(JSMSG_MISSING_FUN_ARG,         2, JSEXN_TYPEERR, "missing argument {0} when calling function {1}")
+MSG_DEF(JSMSG_JSON_BAD_PARSE,          3, JSEXN_SYNTAXERR, "JSON.parse: {0} at line {1} column {2} of the JSON data")
+MSG_DEF(JSMSG_JSON_BAD_STRINGIFY,      0, JSEXN_ERR, "JSON.stringify")
+MSG_DEF(JSMSG_NOT_CALLABLE_OR_UNDEFINED, 0, JSEXN_TYPEERR, "value is not a function or undefined")
+MSG_DEF(JSMSG_NOT_NONNULL_OBJECT,      0, JSEXN_TYPEERR, "value is not a non-null object")
+MSG_DEF(JSMSG_DEPRECATED_OCTAL,        0, JSEXN_SYNTAXERR, "octal literals and octal escape sequences are deprecated")
+MSG_DEF(JSMSG_STRICT_CODE_WITH,        0, JSEXN_SYNTAXERR, "strict mode code may not contain 'with' statements")
+MSG_DEF(JSMSG_DUPLICATE_PROPERTY,      1, JSEXN_SYNTAXERR, "property name {0} appears more than once in object literal")
+MSG_DEF(JSMSG_DEPRECATED_DELETE_OPERAND, 0, JSEXN_SYNTAXERR, "applying the 'delete' operator to an unqualified name is deprecated")
+MSG_DEF(JSMSG_BAD_STRICT_ASSIGN,       1, JSEXN_SYNTAXERR, "can't assign to {0} in strict mode")
+MSG_DEF(JSMSG_BAD_BINDING,             1, JSEXN_SYNTAXERR, "redefining {0} is deprecated")
+MSG_DEF(JSMSG_INVALID_DESCRIPTOR,      0, JSEXN_TYPEERR, "property descriptors must not specify a value or be writable when a getter or setter has been specified")
+MSG_DEF(JSMSG_OBJECT_NOT_EXTENSIBLE,   1, JSEXN_TYPEERR, "{0} is not extensible")
+MSG_DEF(JSMSG_CANT_REDEFINE_PROP,      1, JSEXN_TYPEERR, "can't redefine non-configurable property '{0}'")
+MSG_DEF(JSMSG_CANT_APPEND_TO_ARRAY,    0, JSEXN_TYPEERR, "can't add elements past the end of an array if its length property is unwritable")
+MSG_DEF(JSMSG_CANT_REDEFINE_ARRAY_LENGTH, 0, JSEXN_TYPEERR, "can't redefine array length")
+MSG_DEF(JSMSG_CANT_DEFINE_PAST_ARRAY_LENGTH, 0, JSEXN_TYPEERR, "can't define array index property past the end of an array with non-writable length")
+MSG_DEF(JSMSG_TYPED_ARRAY_BAD_INDEX,   0, JSEXN_ERR, "invalid or out-of-range index")
+MSG_DEF(JSMSG_TYPED_ARRAY_NEGATIVE_ARG,1, JSEXN_ERR, "argument {0} must be >= 0")
+MSG_DEF(JSMSG_TYPED_ARRAY_BAD_ARGS,    0, JSEXN_ERR, "invalid arguments")
+MSG_DEF(JSMSG_CSP_BLOCKED_FUNCTION,    0, JSEXN_ERR, "call to Function() blocked by CSP")
+MSG_DEF(JSMSG_BAD_GET_SET_FIELD,       1, JSEXN_TYPEERR, "property descriptor's {0} field is neither undefined nor a function")
+MSG_DEF(JSMSG_BAD_PROXY_FIX,           0, JSEXN_TYPEERR, "proxy was fixed while executing the handler")
+MSG_DEF(JSMSG_INVALID_EVAL_SCOPE_ARG,  0, JSEXN_EVALERR, "invalid eval scope argument")
+MSG_DEF(JSMSG_ACCESSOR_WRONG_ARGS,     3, JSEXN_SYNTAXERR, "{0} functions must have {1} argument{2}")
+MSG_DEF(JSMSG_THROW_TYPE_ERROR,        0, JSEXN_TYPEERR, "'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them")
+MSG_DEF(JSMSG_BAD_TOISOSTRING_PROP,    0, JSEXN_TYPEERR, "toISOString property is not callable")
+MSG_DEF(JSMSG_BAD_PARSE_NODE,          0, JSEXN_INTERNALERR, "bad parse node")
+MSG_DEF(JSMSG_NOT_EXPECTED_TYPE,       3, JSEXN_TYPEERR, "{0}: expected {1}, got {2}")
+MSG_DEF(JSMSG_CALLER_IS_STRICT,        0, JSEXN_TYPEERR, "access to strict mode caller function is censored")
+MSG_DEF(JSMSG_NEED_DEBUG_MODE,         0, JSEXN_ERR, "function can be called only in debug mode")
+MSG_DEF(JSMSG_STRICT_CODE_LET_EXPR_STMT, 0, JSEXN_ERR, "strict mode code may not contain unparenthesized let expression statements")
+MSG_DEF(JSMSG_CANT_CHANGE_EXTENSIBILITY, 0, JSEXN_TYPEERR, "can't change object's extensibility")
+MSG_DEF(JSMSG_SC_BAD_SERIALIZED_DATA,  1, JSEXN_INTERNALERR, "bad serialized structured data ({0})")
+MSG_DEF(JSMSG_SC_UNSUPPORTED_TYPE,     0, JSEXN_TYPEERR, "unsupported type for structured data")
+MSG_DEF(JSMSG_SC_RECURSION,            0, JSEXN_INTERNALERR, "recursive object")
+MSG_DEF(JSMSG_DEBUG_CANT_DEBUG_GLOBAL, 0, JSEXN_ERR, "passing non-debuggable global to addDebuggee")
+MSG_DEF(JSMSG_BAD_CLONE_VERSION,       0, JSEXN_ERR, "unsupported structured clone version")
+MSG_DEF(JSMSG_CANT_CLONE_OBJECT,       0, JSEXN_TYPEERR, "can't clone object")
+MSG_DEF(JSMSG_DEBUG_RESUMPTION_VALUE_DISALLOWED, 0, JSEXN_TYPEERR, "resumption values are disallowed in this hook")
+MSG_DEF(JSMSG_STRICT_FUNCTION_STATEMENT, 0, JSEXN_SYNTAXERR, "in strict mode code, functions may be declared only at top level or immediately within another function")
+MSG_DEF(JSMSG_INVALID_FOR_IN_INIT,     0, JSEXN_SYNTAXERR, "for-in loop let declaration may not have an initializer")
+MSG_DEF(JSMSG_CLEARED_SCOPE,           0, JSEXN_TYPEERR, "attempt to run compile-and-go script on a cleared scope")
+MSG_DEF(JSMSG_MALFORMED_ESCAPE,        1, JSEXN_SYNTAXERR, "malformed {0} character escape sequence")
+MSG_DEF(JSMSG_BAD_GENEXP_BODY,         1, JSEXN_SYNTAXERR, "illegal use of {0} in generator expression")
+MSG_DEF(JSMSG_YIELD_WITHOUT_OPERAND,   0, JSEXN_SYNTAXERR, "yield without a value is deprecated, and illegal in ES6 (use 'yield undefined' instead)")
+MSG_DEF(JSMSG_UNNAMED_FUNCTION_STMT,   0, JSEXN_SYNTAXERR, "function statement requires a name")
+MSG_DEF(JSMSG_CCW_REQUIRED,            1, JSEXN_TYPEERR, "{0}: argument must be an object from a different compartment")
+MSG_DEF(JSMSG_DEBUG_BAD_RESUMPTION,    0, JSEXN_TYPEERR, "debugger resumption value must be undefined, {throw: val}, {return: val}, or null")
+MSG_DEF(JSMSG_ASSIGN_FUNCTION_OR_NULL, 1, JSEXN_TYPEERR, "value assigned to {0} must be a function or null")
+MSG_DEF(JSMSG_DEBUG_NOT_LIVE,          1, JSEXN_ERR, "{0} is not live")
+MSG_DEF(JSMSG_DEBUG_OBJECT_WRONG_OWNER,0, JSEXN_TYPEERR, "Debugger.Object belongs to a different Debugger")
+MSG_DEF(JSMSG_DEBUG_OBJECT_PROTO,      0, JSEXN_TYPEERR, "Debugger.Object.prototype is not a valid Debugger.Object")
+MSG_DEF(JSMSG_DEBUG_LOOP,              0, JSEXN_TYPEERR, "cannot debug an object in same compartment as debugger or a compartment that is already debugging the debugger")
+MSG_DEF(JSMSG_DEBUG_NOT_IDLE,          0, JSEXN_ERR, "can't start debugging: a debuggee script is on the stack")
+MSG_DEF(JSMSG_DEBUG_BAD_OFFSET,        0, JSEXN_TYPEERR, "invalid script offset")
+MSG_DEF(JSMSG_DEBUG_BAD_LINE,          0, JSEXN_TYPEERR, "invalid line number")
+MSG_DEF(JSMSG_DEBUG_NOT_DEBUGGING,     0, JSEXN_ERR, "can't set breakpoint: script global is not a debuggee")
+MSG_DEF(JSMSG_DEBUG_COMPARTMENT_MISMATCH, 2, JSEXN_TYPEERR, "{0}: descriptor .{1} property is an object in a different compartment than the target object")
+MSG_DEF(JSMSG_DEBUG_NOT_SCRIPT_FRAME,  0, JSEXN_ERR, "stack frame is not running JavaScript code")
+MSG_DEF(JSMSG_CANT_WATCH_PROP,         0, JSEXN_TYPEERR, "properties whose names are objects can't be watched")
+MSG_DEF(JSMSG_CSP_BLOCKED_EVAL,        0, JSEXN_ERR, "call to eval() blocked by CSP")
+MSG_DEF(JSMSG_DEBUG_NO_SCOPE_OBJECT,   0, JSEXN_TYPEERR, "declarative Environments don't have binding objects")
+MSG_DEF(JSMSG_EMPTY_CONSEQUENT,        0, JSEXN_SYNTAXERR, "mistyped ; after conditional?")
+MSG_DEF(JSMSG_NOT_ITERABLE,            1, JSEXN_TYPEERR, "{0} is not iterable")
+MSG_DEF(JSMSG_QUERY_LINE_WITHOUT_URL,  0, JSEXN_TYPEERR, "findScripts query object has 'line' property, but no 'url' property")
+MSG_DEF(JSMSG_QUERY_INNERMOST_WITHOUT_LINE_URL, 0, JSEXN_TYPEERR, "findScripts query object has 'innermost' property without both 'url' and 'line' properties")
+MSG_DEF(JSMSG_DEBUG_VARIABLE_NOT_FOUND,0, JSEXN_TYPEERR, "variable not found in environment")
+MSG_DEF(JSMSG_PARAMETER_AFTER_REST,    0, JSEXN_SYNTAXERR, "parameter after rest parameter")
+MSG_DEF(JSMSG_NO_REST_NAME,            0, JSEXN_SYNTAXERR, "no parameter name after ...")
+MSG_DEF(JSMSG_ARGUMENTS_AND_REST,      0, JSEXN_SYNTAXERR, "'arguments' object may not be used in conjunction with a rest parameter")
+MSG_DEF(JSMSG_FUNCTION_ARGUMENTS_AND_REST, 0, JSEXN_ERR, "the 'arguments' property of a function with a rest parameter may not be used")
+MSG_DEF(JSMSG_REST_WITH_DEFAULT,       0, JSEXN_SYNTAXERR, "rest parameter may not have a default")
+MSG_DEF(JSMSG_NONDEFAULT_FORMAL_AFTER_DEFAULT, 0, JSEXN_SYNTAXERR, "parameter(s) with default followed by parameter without default")
+MSG_DEF(JSMSG_YIELD_IN_DEFAULT,        0, JSEXN_SYNTAXERR, "yield in default expression")
+MSG_DEF(JSMSG_INTRINSIC_NOT_DEFINED,   1, JSEXN_REFERENCEERR, "no intrinsic function {0}")
+MSG_DEF(JSMSG_ALREADY_HAS_PRAGMA,      2, JSEXN_NONE,      "{0} is being assigned a {1}, but already has one")
+MSG_DEF(JSMSG_PAR_ARRAY_BAD_ARG,       0, JSEXN_RANGEERR, "invalid parallel method argument")
+MSG_DEF(JSMSG_REGEXP_RUNTIME_ERROR,    0, JSEXN_INTERNALERR, "an error occurred while executing regular expression")
+MSG_DEF(JSMSG_DEBUG_OPTIMIZED_OUT,     0, JSEXN_ERR, "variable has been optimized out")
+MSG_DEF(JSMSG_NEXT_RETURNED_PRIMITIVE, 0, JSEXN_TYPEERR, "iterator.next() returned a non-object value")
+MSG_DEF(JSMSG_PAR_ARRAY_SCATTER_CONFLICT, 0, JSEXN_ERR, "no conflict resolution function provided")
+MSG_DEF(JSMSG_PAR_ARRAY_SCATTER_BOUNDS,0, JSEXN_ERR, "index in scatter vector out of bounds")
+MSG_DEF(JSMSG_CANT_REPORT_NC_AS_NE,    0, JSEXN_TYPEERR, "proxy can't report a non-configurable own property as non-existent")
+MSG_DEF(JSMSG_CANT_REPORT_E_AS_NE,     0, JSEXN_TYPEERR, "proxy can't report an existing own property as non-existent on a non-extensible object")
+MSG_DEF(JSMSG_CANT_REPORT_NEW,         0, JSEXN_TYPEERR, "proxy can't report a new property on a non-extensible object")
+MSG_DEF(JSMSG_CANT_REPORT_INVALID,     0, JSEXN_TYPEERR, "proxy can't report an incompatible property descriptor")
+MSG_DEF(JSMSG_CANT_REPORT_NE_AS_NC,    0, JSEXN_TYPEERR, "proxy can't report a non-existent property as non-configurable")
+MSG_DEF(JSMSG_CANT_DEFINE_NEW,         0, JSEXN_TYPEERR, "proxy can't define a new property on a non-extensible object")
+MSG_DEF(JSMSG_CANT_DEFINE_INVALID,     0, JSEXN_TYPEERR, "proxy can't define an incompatible property descriptor")
+MSG_DEF(JSMSG_CANT_DEFINE_NE_AS_NC,    0, JSEXN_TYPEERR, "proxy can't define a non-existent property as non-configurable")
+MSG_DEF(JSMSG_INVALID_TRAP_RESULT,     2, JSEXN_TYPEERR, "trap {1} for {0} returned an invalid result")
+MSG_DEF(JSMSG_CANT_SKIP_NC,            0, JSEXN_TYPEERR, "proxy can't skip a non-configurable property")
+MSG_DEF(JSMSG_MUST_REPORT_SAME_VALUE,  0, JSEXN_TYPEERR, "proxy must report the same value for a non-writable, non-configurable property")
+MSG_DEF(JSMSG_MUST_REPORT_UNDEFINED,   0, JSEXN_TYPEERR, "proxy must report undefined for a non-configurable accessor property without a getter")
+MSG_DEF(JSMSG_CANT_SET_NW_NC,          0, JSEXN_TYPEERR, "proxy can't successfully set a non-writable, non-configurable property")
+MSG_DEF(JSMSG_CANT_SET_WO_SETTER,      0, JSEXN_TYPEERR, "proxy can't succesfully set an accessor property without a setter")
+MSG_DEF(JSMSG_DEBUG_BAD_REFERENT,      2, JSEXN_TYPEERR, "{0} does not refer to {1}")
+MSG_DEF(JSMSG_DEBUG_WRAPPER_IN_WAY,    3, JSEXN_TYPEERR, "{0} is {1}{2}a global object, but a direct reference is required")
+MSG_DEF(JSMSG_UNWRAP_DENIED,           0, JSEXN_ERR, "permission denied to unwrap object")
+MSG_DEF(JSMSG_INTL_OBJECT_NOT_INITED,  3, JSEXN_TYPEERR, "Intl.{0}.prototype.{1} called on value that's not an object initialized as a {2}")
+MSG_DEF(JSMSG_INVALID_LOCALES_ELEMENT, 0, JSEXN_TYPEERR, "invalid element in locales argument")
+MSG_DEF(JSMSG_INVALID_LANGUAGE_TAG,    1, JSEXN_RANGEERR, "invalid language tag: {0}")
+MSG_DEF(JSMSG_INVALID_LOCALE_MATCHER,  1, JSEXN_RANGEERR, "invalid locale matcher in supportedLocalesOf(): {0}")
+MSG_DEF(JSMSG_INVALID_OPTION_VALUE,    2, JSEXN_RANGEERR, "invalid value {1} for option {0}")
+MSG_DEF(JSMSG_INVALID_DIGITS_VALUE,    1, JSEXN_RANGEERR, "invalid digits value: {0}")
+MSG_DEF(JSMSG_INTL_OBJECT_REINITED,    0, JSEXN_TYPEERR, "can't initialize object twice as an object of an Intl constructor")
+MSG_DEF(JSMSG_INVALID_CURRENCY_CODE,   1, JSEXN_RANGEERR, "invalid currency code in NumberFormat(): {0}")
+MSG_DEF(JSMSG_UNDEFINED_CURRENCY,      0, JSEXN_TYPEERR, "undefined currency in NumberFormat() with currency style")
+MSG_DEF(JSMSG_INVALID_TIME_ZONE,       1, JSEXN_RANGEERR, "invalid time zone in DateTimeFormat(): {0}")
+MSG_DEF(JSMSG_DATE_NOT_FINITE,         0, JSEXN_RANGEERR, "date value is not finite in DateTimeFormat.format()")
+MSG_DEF(JSMSG_USE_ASM_DIRECTIVE_FAIL,  0, JSEXN_SYNTAXERR, "\"use asm\" is only meaningful in the Directive Prologue of a function body")
+MSG_DEF(JSMSG_USE_ASM_TYPE_FAIL,       1, JSEXN_TYPEERR, "asm.js type error: {0}")
+MSG_DEF(JSMSG_USE_ASM_LINK_FAIL,       1, JSEXN_TYPEERR, "asm.js link error: {0}")
+MSG_DEF(JSMSG_USE_ASM_TYPE_OK,         1, JSEXN_NONE,    "Successfully compiled asm.js code ({0})")
+MSG_DEF(JSMSG_BAD_ARROW_ARGS,          0, JSEXN_SYNTAXERR, "invalid arrow-function arguments (parentheses around the arrow-function may help)")
+MSG_DEF(JSMSG_YIELD_IN_ARROW,          0, JSEXN_SYNTAXERR, "arrow function may not contain yield")
+MSG_DEF(JSMSG_WRONG_VALUE,             2, JSEXN_ERR, "expected {0} but found {1}")
+MSG_DEF(JSMSG_PAR_ARRAY_SCATTER_BAD_TARGET, 1, JSEXN_ERR, "target for index {0} is not an integer")
+MSG_DEF(JSMSG_SELFHOSTED_UNBOUND_NAME, 0, JSEXN_TYPEERR, "self-hosted code may not contain unbound name lookups")
+MSG_DEF(JSMSG_DEPRECATED_PRAGMA,       1, JSEXN_NONE, "Using //@ to indicate {0} pragmas is deprecated. Use //# instead")
+MSG_DEF(JSMSG_BAD_DESTRUCT_ASSIGN,     1, JSEXN_SYNTAXERR, "can't assign to {0} using destructuring assignment")
+MSG_DEF(JSMSG_TYPEDOBJECT_ARRAYTYPE_BAD_ARGS, 0, JSEXN_ERR, "Invalid arguments")
+MSG_DEF(JSMSG_TYPEDOBJECT_BINARYARRAY_BAD_INDEX, 0, JSEXN_RANGEERR, "invalid or out-of-range index")
+MSG_DEF(JSMSG_TYPEDOBJECT_STRUCTTYPE_BAD_ARGS, 0, JSEXN_RANGEERR, "invalid field descriptor")
+MSG_DEF(JSMSG_TYPEDOBJECT_NOT_BINARYSTRUCT, 1, JSEXN_TYPEERR, "{0} is not a BinaryStruct")
+MSG_DEF(JSMSG_TYPEDOBJECT_SUBARRAY_INTEGER_ARG, 1, JSEXN_ERR, "argument {0} must be an integer")
+MSG_DEF(JSMSG_TYPEDOBJECT_STRUCTTYPE_EMPTY_DESCRIPTOR, 0, JSEXN_ERR, "field descriptor cannot be empty")
+MSG_DEF(JSMSG_TYPEDOBJECT_STRUCTTYPE_BAD_FIELD, 1, JSEXN_ERR, "field {0} is not a valid BinaryData Type descriptor")
+MSG_DEF(JSMSG_GENERATOR_FINISHED,      0, JSEXN_TYPEERR, "generator has already finished")
+MSG_DEF(JSMSG_TYPEDOBJECT_TOO_BIG,     0, JSEXN_ERR, "Type is too large to allocate")
+MSG_DEF(JSMSG_TYPEDOBJECT_NOT_TYPE_OBJECT, 0, JSEXN_ERR, "Expected a type object")
+MSG_DEF(JSMSG_TOO_MANY_CON_SPREADARGS, 0, JSEXN_RANGEERR, "too many constructor arguments")
+MSG_DEF(JSMSG_TOO_MANY_FUN_SPREADARGS, 0, JSEXN_RANGEERR, "too many function arguments")
+MSG_DEF(JSMSG_DEBUG_NOT_DEBUGGEE,      2, JSEXN_ERR, "{0} is not a debuggee {1}")
+MSG_DEF(JSMSG_TYPEDOBJECT_NOT_TYPED_OBJECT, 0, JSEXN_ERR, "Expected a typed object")
+MSG_DEF(JSMSG_TYPEDOBJECT_NO_SUCH_PROP,1, JSEXN_TYPEERR, "No such property: {0}")
+MSG_DEF(JSMSG_TYPEDOBJECT_BAD_ARGS,    0, JSEXN_TYPEERR, "invalid arguments")
+MSG_DEF(JSMSG_TYPEDOBJECT_HANDLE_UNATTACHED, 0, JSEXN_TYPEERR, "handle unattached")
+MSG_DEF(JSMSG_TYPEDOBJECT_HANDLE_BAD_TYPE, 0, JSEXN_TYPEERR, "handle moved to destination of incorrect type")
+MSG_DEF(JSMSG_IMPORT_DECL_AT_TOP_LEVEL, 0, JSEXN_SYNTAXERR, "import declarations may only appear at top level")
+MSG_DEF(JSMSG_NO_IMPORT_NAME,          0, JSEXN_SYNTAXERR, "missing import name")
+MSG_DEF(JSMSG_AS_AFTER_RESERVED_WORD,  1, JSEXN_SYNTAXERR, "missing keyword 'as' after reserved word '{0}'")
+MSG_DEF(JSMSG_NO_BINDING_NAME,        0, JSEXN_SYNTAXERR, "missing binding name")
+MSG_DEF(JSMSG_RC_AFTER_IMPORT_SPEC_LIST, 0, JSEXN_SYNTAXERR, "missing '}' after module specifier list")
+MSG_DEF(JSMSG_FROM_AFTER_IMPORT_SPEC_SET, 0, JSEXN_SYNTAXERR, "missing keyword 'from' after import specifier set")
+MSG_DEF(JSMSG_DECLARATION_AFTER_IMPORT,0, JSEXN_SYNTAXERR, "missing declaration after 'import' keyword")
+MSG_DEF(JSMSG_MODULE_SPEC_AFTER_FROM,  0, JSEXN_SYNTAXERR, "missing module specifier after 'from' keyword")
+MSG_DEF(JSMSG_MODULES_NOT_IMPLEMENTED, 0, JSEXN_SYNTAXERR, "modules are not implemented yet")
+MSG_DEF(JSMSG_EXPORT_DECL_AT_TOP_LEVEL,0, JSEXN_SYNTAXERR, "export declarations may only appear at top level")
+MSG_DEF(JSMSG_RC_AFTER_EXPORT_SPEC_LIST, 0, JSEXN_SYNTAXERR, "missing '}' after export specifier list")
+MSG_DEF(JSMSG_NO_EXPORT_NAME,          0, JSEXN_SYNTAXERR, "missing export name")
+MSG_DEF(JSMSG_DECLARATION_AFTER_EXPORT,0, JSEXN_SYNTAXERR, "missing declaration after 'export' keyword")
+MSG_DEF(JSMSG_INVALID_PROTOTYPE,       0, JSEXN_TYPEERR, "prototype field is not an object")
+MSG_DEF(JSMSG_TYPEDOBJECT_HANDLE_TO_UNSIZED, 0, JSEXN_TYPEERR, "cannot create a handle to an unsized type")
+MSG_DEF(JSMSG_SETPROTOTYPEOF_FAIL,     1, JSEXN_TYPEERR, "[[SetPrototypeOf]] failed on {0}")
+MSG_DEF(JSMSG_INVALID_ARG_TYPE,        3, JSEXN_TYPEERR, "Invalid type: {0} can't be a{1} {2}")
+MSG_DEF(JSMSG_TERMINATED,              1, JSEXN_ERR, "Script terminated by timeout at:\n{0}")
+MSG_DEF(JSMSG_NO_SUCH_SELF_HOSTED_PROP,1, JSEXN_ERR, "No such property on self-hosted object: {0}")
+MSG_DEF(JSMSG_PROXY_EXTENSIBILITY,     0, JSEXN_TYPEERR, "proxy must report same extensiblitity as target")
+MSG_DEF(JSMSG_PROXY_CONSTRUCT_OBJECT,  0, JSEXN_TYPEERR, "proxy [[Construct]] must return an object")
+MSG_DEF(JSMSG_PROXY_GETOWN_OBJORUNDEF, 0, JSEXN_TYPEERR, "proxy [[GetOwnProperty]] must return an object or undefined")
+MSG_DEF(JSMSG_CANT_REPORT_C_AS_NC,     0, JSEXN_TYPEERR, "proxy can't report existing configurable property as non-configurable")
+MSG_DEF(JSMSG_COMP_PROP_UNTERM_EXPR,   0, JSEXN_SYNTAXERR, "missing ] in computed property name")
\ No newline at end of file
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -515,49 +515,34 @@ JS_IsBuiltinFunctionConstructor(JSFuncti
  * initialization can take a comparatively long time (15ms or so), so we
  * really don't want to do it in JS_Init, and we really do want to do it only
  * when PRMJ_Now is eventually called.
  */
 enum InitState { Uninitialized, Running, ShutDown };
 static InitState jsInitState = Uninitialized;
 
 #ifdef DEBUG
-static void
-CheckMessageNumbering()
-{
-    // Assert that the numbers associated with the error names in js.msg are
-    // monotonically increasing.  It's not a compile-time check, but it's
-    // better than nothing.
-    int errorNumber = 0;
-# define MSG_DEF(name, number, count, exception, format)                      \
-    JS_ASSERT(name == errorNumber++);
-# include "js.msg"
-# undef MSG_DEF
-}
-
 static unsigned
 MessageParameterCount(const char *format)
 {
     unsigned numfmtspecs = 0;
     for (const char *fmt = format; *fmt != '\0'; fmt++) {
         if (*fmt == '{' && isdigit(fmt[1]))
             ++numfmtspecs;
     }
     return numfmtspecs;
 }
 
 static void
 CheckMessageParameterCounts()
 {
     // Assert that each message format has the correct number of braced
     // parameters.
-# define MSG_DEF(name, number, count, exception, format)                      \
-    JS_BEGIN_MACRO                                                            \
-        JS_ASSERT(MessageParameterCount(format) == count);                    \
-    JS_END_MACRO;
+# define MSG_DEF(name, count, exception, format)           \
+        JS_ASSERT(MessageParameterCount(format) == count);
 # include "js.msg"
 # undef MSG_DEF
 }
 #endif /* DEBUG */
 
 JS_PUBLIC_API(bool)
 JS_Init(void)
 {
@@ -565,17 +550,16 @@ JS_Init(void)
                "must call JS_Init once before any JSAPI operation except "
                "JS_SetICUMemoryFunctions");
     MOZ_ASSERT(!JSRuntime::hasLiveRuntimes(),
                "how do we have live runtimes before JS_Init?");
 
     PRMJ_NowInit();
 
 #ifdef DEBUG
-    CheckMessageNumbering();
     CheckMessageParameterCounts();
 #endif
 
     using js::TlsPerThreadData;
     if (!TlsPerThreadData.initialized() && !TlsPerThreadData.init())
         return false;
 
     if (!jit::InitializeIon())
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -3211,51 +3211,36 @@ JS_DeleteElement2(JSContext *cx, JS::Han
 /*
  * Assign 'undefined' to all of the object's non-reserved slots. Note: this is
  * done for all slots, regardless of the associated property descriptor.
  */
 JS_PUBLIC_API(void)
 JS_SetAllNonReservedSlotsToUndefined(JSContext *cx, JSObject *objArg);
 
 /*
- * Create a new array buffer with the given contents. On success, the ownership
- * is transferred to the new array buffer.
+ * Create a new array buffer with the given contents. It must be legal to pass
+ * these contents to free(). On success, the ownership is transferred to the
+ * new array buffer.
  */
 extern JS_PUBLIC_API(JSObject *)
 JS_NewArrayBufferWithContents(JSContext *cx, size_t nbytes, void *contents);
 
 /*
  * Steal the contents of the given array buffer. The array buffer has its
  * length set to 0 and its contents array cleared. The caller takes ownership
  * of the return value and must free it or transfer ownership via
  * JS_NewArrayBufferWithContents when done using it.
  */
 extern JS_PUBLIC_API(void *)
 JS_StealArrayBufferContents(JSContext *cx, JS::HandleObject obj);
 
 /*
- * Allocate memory that may be eventually passed to
- * JS_NewArrayBufferWithContents. |maybecx| is optional; if a non-nullptr cx is
- * given, it will be used for memory accounting and OOM reporting. |nbytes| is
- * the number of payload bytes required.
- */
-extern JS_PUBLIC_API(void *)
-JS_AllocateArrayBufferContents(JSContext *maybecx, uint32_t nbytes);
-
-/*
- * Reallocate memory allocated by JS_AllocateArrayBufferContents, growing or
- * shrinking it as appropriate. If oldContents is null then this behaves like
- * JS_AllocateArrayBufferContents.
- */
-extern JS_PUBLIC_API(void *)
-JS_ReallocateArrayBufferContents(JSContext *cx, uint32_t nbytes, void *oldContents, uint32_t oldNbytes);
-
-/*
- * Create a new mapped array buffer with the given memory mapped contents. On success,
- * the ownership is transferred to the new mapped array buffer.
+ * Create a new mapped array buffer with the given memory mapped contents. It
+ * must be legal to free the contents pointer by unmapping it. On success,
+ * ownership is transferred to the new mapped array buffer.
  */
 extern JS_PUBLIC_API(JSObject *)
 JS_NewMappedArrayBufferWithContents(JSContext *cx, size_t nbytes, void *contents);
 
 /*
  * Create memory mapped array buffer contents.
  * Caller must take care of closing fd after calling this function.
  */
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -955,17 +955,17 @@ js_ReportValueErrorFlags(JSContext *cx, 
 
     ok = JS_ReportErrorFlagsAndNumber(cx, flags, js_GetErrorMessage,
                                       nullptr, errorNumber, bytes, arg1, arg2);
     js_free(bytes);
     return ok;
 }
 
 const JSErrorFormatString js_ErrorFormatString[JSErr_Limit] = {
-#define MSG_DEF(name, number, count, exception, format) \
+#define MSG_DEF(name, count, exception, format) \
     { format, count, exception } ,
 #include "js.msg"
 #undef MSG_DEF
 };
 
 JS_FRIEND_API(const JSErrorFormatString *)
 js_GetErrorMessage(void *userRef, const unsigned errorNumber)
 {
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -1245,18 +1245,18 @@ js_DateGetMsecSinceEpoch(JSObject *obj);
 
 /* Implemented in jscntxt.cpp. */
 
 /*
  * Report an exception, which is currently realized as a printf-style format
  * string and its arguments.
  */
 typedef enum JSErrNum {
-#define MSG_DEF(name, number, count, exception, format) \
-    name = number,
+#define MSG_DEF(name, count, exception, format) \
+    name,
 #include "js.msg"
 #undef MSG_DEF
     JSErr_Limit
 } JSErrNum;
 
 extern JS_FRIEND_API(const JSErrorFormatString *)
 js_GetErrorMessage(void *userRef, const unsigned errorNumber);
 
--- a/js/src/jsshell.msg
+++ b/js/src/jsshell.msg
@@ -3,27 +3,27 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /*
 	Error messages for JSShell. See js.msg for format.
 */
 
-MSG_DEF(JSSMSG_NOT_AN_ERROR,             0, 0, JSEXN_NONE, "<Error #0 is reserved>")
-MSG_DEF(JSSMSG_CANT_OPEN,                1, 2, JSEXN_NONE, "can't open {0}: {1}")
-MSG_DEF(JSSMSG_TRAP_USAGE,               2, 0, JSEXN_NONE, "usage: trap [fun] [pc] expr")
-MSG_DEF(JSSMSG_LINE2PC_USAGE,            3, 0, JSEXN_NONE, "usage: line2pc [fun] line")
-MSG_DEF(JSSMSG_FILE_SCRIPTS_ONLY,        4, 0, JSEXN_NONE, "only works on JS scripts read from files")
-MSG_DEF(JSSMSG_UNEXPECTED_EOF,           5, 1, JSEXN_NONE, "unexpected EOF in {0}")
-MSG_DEF(JSSMSG_DOEXP_USAGE,              6, 0, JSEXN_NONE, "usage: doexp obj id")
-MSG_DEF(JSSMSG_SCRIPTS_ONLY,             7, 0, JSEXN_NONE, "only works on scripts")
-MSG_DEF(JSSMSG_NOT_ENOUGH_ARGS,          8, 1, JSEXN_NONE, "{0}: not enough arguments")
-MSG_DEF(JSSMSG_TOO_MANY_ARGS,            9, 1, JSEXN_NONE, "{0}: too many arguments")
-MSG_DEF(JSSMSG_ASSERT_EQ_FAILED,        10, 2, JSEXN_NONE, "Assertion failed: got {0}, expected {1}")
-MSG_DEF(JSSMSG_ASSERT_EQ_FAILED_MSG,    11, 3, JSEXN_NONE, "Assertion failed: got {0}, expected {1}: {2}")
-MSG_DEF(JSSMSG_INVALID_ARGS,            12, 1, JSEXN_NONE, "{0}: invalid arguments")
-MSG_DEF(JSSMSG_BAD_ALIGNMENT,           13, 0, JSEXN_NONE, "serialized data must be 8-byte-aligned")
-MSG_DEF(JSSMSG_BAD_ENV_VAR,             14, 1, JSEXN_NONE, "unable to read getenv({0})")
-MSG_DEF(JSSMSG_NESTED_FAIL,             15, 0, JSEXN_NONE, "error executing nested JS shell")
-MSG_DEF(JSSMSG_CACHE_EQ_SIZE_FAILED,    16, 2, JSEXN_NONE, "cache does not have the same size: got {0}, expected {1}")
-MSG_DEF(JSSMSG_CACHE_EQ_CONTENT_FAILED, 17, 0, JSEXN_NONE, "cache does not have the same content.")
-MSG_DEF(JSSMSG_CACHE_SINGLETON_FAILED,  18, 0, JSEXN_NONE, "compartment cannot save singleton anymore.")
+MSG_DEF(JSSMSG_NOT_AN_ERROR,            0, JSEXN_NONE, "<Error #0 is reserved>")
+MSG_DEF(JSSMSG_CANT_OPEN,               2, JSEXN_NONE, "can't open {0}: {1}")
+MSG_DEF(JSSMSG_TRAP_USAGE,              0, JSEXN_NONE, "usage: trap [fun] [pc] expr")
+MSG_DEF(JSSMSG_LINE2PC_USAGE,           0, JSEXN_NONE, "usage: line2pc [fun] line")
+MSG_DEF(JSSMSG_FILE_SCRIPTS_ONLY,       0, JSEXN_NONE, "only works on JS scripts read from files")
+MSG_DEF(JSSMSG_UNEXPECTED_EOF,          1, JSEXN_NONE, "unexpected EOF in {0}")
+MSG_DEF(JSSMSG_DOEXP_USAGE,             0, JSEXN_NONE, "usage: doexp obj id")
+MSG_DEF(JSSMSG_SCRIPTS_ONLY,            0, JSEXN_NONE, "only works on scripts")
+MSG_DEF(JSSMSG_NOT_ENOUGH_ARGS,         1, JSEXN_NONE, "{0}: not enough arguments")
+MSG_DEF(JSSMSG_TOO_MANY_ARGS,           1, JSEXN_NONE, "{0}: too many arguments")
+MSG_DEF(JSSMSG_ASSERT_EQ_FAILED,        2, JSEXN_NONE, "Assertion failed: got {0}, expected {1}")
+MSG_DEF(JSSMSG_ASSERT_EQ_FAILED_MSG,    3, JSEXN_NONE, "Assertion failed: got {0}, expected {1}: {2}")
+MSG_DEF(JSSMSG_INVALID_ARGS,            1, JSEXN_NONE, "{0}: invalid arguments")
+MSG_DEF(JSSMSG_BAD_ALIGNMENT,           0, JSEXN_NONE, "serialized data must be 8-byte-aligned")
+MSG_DEF(JSSMSG_BAD_ENV_VAR,             1, JSEXN_NONE, "unable to read getenv({0})")
+MSG_DEF(JSSMSG_NESTED_FAIL,             0, JSEXN_NONE, "error executing nested JS shell")
+MSG_DEF(JSSMSG_CACHE_EQ_SIZE_FAILED,    2, JSEXN_NONE, "cache does not have the same size: got {0}, expected {1}")
+MSG_DEF(JSSMSG_CACHE_EQ_CONTENT_FAILED, 0, JSEXN_NONE, "cache does not have the same content.")
+MSG_DEF(JSSMSG_CACHE_SINGLETON_FAILED,  0, JSEXN_NONE, "compartment cannot save singleton anymore.")
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -170,18 +170,18 @@ static bool compileOnly = false;
 static bool fuzzingSafe = false;
 
 #ifdef DEBUG
 static bool dumpEntrainedVariables = false;
 static bool OOM_printAllocationCount = false;
 #endif
 
 enum JSShellErrNum {
-#define MSG_DEF(name, number, count, exception, format) \
-    name = number,
+#define MSG_DEF(name, count, exception, format) \
+    name,
 #include "jsshell.msg"
 #undef MSG_DEF
     JSShellErr_Limit
 };
 
 static JSContext *
 NewContext(JSRuntime *rt);
 
@@ -1051,17 +1051,19 @@ CacheEntry_getBytecode(HandleObject cach
     *length = arrayBuffer->byteLength();
     return arrayBuffer->dataPointer();
 }
 
 static bool
 CacheEntry_setBytecode(JSContext *cx, HandleObject cache, uint8_t *buffer, uint32_t length)
 {
     JS_ASSERT(CacheEntry_isCacheEntry(cache));
-    Rooted<ArrayBufferObject*> arrayBuffer(cx, ArrayBufferObject::create(cx, length, buffer));
+    ArrayBufferObject::BufferContents contents =
+        ArrayBufferObject::BufferContents::create<ArrayBufferObject::PLAIN_BUFFER>(buffer);
+    Rooted<ArrayBufferObject*> arrayBuffer(cx, ArrayBufferObject::create(cx, length, contents));
 
     if (!arrayBuffer || !ArrayBufferObject::ensureNonInline(cx, arrayBuffer))
         return false;
 
     SetReservedSlot(cache, CacheEntry_BYTECODE, OBJECT_TO_JSVAL(arrayBuffer));
     return true;
 }
 
@@ -4897,17 +4899,17 @@ Help(JSContext *cx, unsigned argc, jsval
         }
     }
 
     args.rval().setUndefined();
     return true;
 }
 
 static const JSErrorFormatString jsShell_ErrorFormatString[JSShellErr_Limit] = {
-#define MSG_DEF(name, number, count, exception, format) \
+#define MSG_DEF(name, count, exception, format) \
     { format, count, JSEXN_ERR } ,
 #include "jsshell.msg"
 #undef MSG_DEF
 };
 
 static const JSErrorFormatString *
 my_GetErrorMessage(void *userRef, const unsigned errorNumber)
 {
@@ -5053,18 +5055,22 @@ env_enumerate(JSContext *cx, HandleObjec
 
     reflected = true;
     return true;
 }
 
 static bool
 env_resolve(JSContext *cx, HandleObject obj, HandleId id, MutableHandleObject objp)
 {
-    RootedValue idvalue(cx, IdToValue(id));
-    RootedString idstring(cx, ToString(cx, idvalue));
+    if (JSID_IS_SYMBOL(id))
+        return true;
+
+    RootedString idstring(cx, IdToString(cx, id));
+    if (!idstring)
+        return false;
     JSAutoByteString idstr;
     if (!idstr.encodeLatin1(cx, idstring))
         return false;
 
     const char *name = idstr.ptr();
     const char *value = getenv(name);
     if (value) {
         RootedString valstr(cx, JS_NewStringCopyZ(cx, value));
--- a/js/src/vm/ArrayBufferObject.cpp
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -261,42 +261,24 @@ ArrayBufferObject::class_constructor(JSC
 
     JSObject *bufobj = create(cx, uint32_t(nbytes));
     if (!bufobj)
         return false;
     args.rval().setObject(*bufobj);
     return true;
 }
 
-/*
- * Note that some callers are allowed to pass in a nullptr cx, so we allocate
- * with the cx if available and fall back to the runtime.  If oldptr is given,
- * it's expected to be a previously-allocated contents pointer that we then
- * realloc.
- */
-static void *
-AllocateArrayBufferContents(JSContext *maybecx, uint32_t nbytes, void *oldptr = nullptr, size_t oldnbytes = 0)
+static ArrayBufferObject::BufferContents
+AllocateArrayBufferContents(JSContext *cx, uint32_t nbytes)
 {
-    void *p;
+    void *p = cx->runtime()->callocCanGC(nbytes);
+    if (!p)
+        js_ReportOutOfMemory(cx);
 
-    // if oldptr is given, then we need to do a realloc
-    if (oldptr) {
-        p = maybecx ? maybecx->runtime()->reallocCanGC(oldptr, nbytes) : js_realloc(oldptr, nbytes);
-
-        // if we grew the array, we need to set the new bytes to 0
-        if (p && nbytes > oldnbytes)
-            memset(reinterpret_cast<uint8_t *>(p) + oldnbytes, 0, nbytes - oldnbytes);
-    } else {
-        p = maybecx ? maybecx->runtime()->callocCanGC(nbytes) : js_calloc(nbytes);
-    }
-
-    if (!p && maybecx)
-        js_ReportOutOfMemory(maybecx);
-
-    return p;
+    return ArrayBufferObject::BufferContents::create<ArrayBufferObject::PLAIN_BUFFER>(p);
 }
 
 ArrayBufferViewObject *
 ArrayBufferObject::viewList() const
 {
     return reinterpret_cast<ArrayBufferViewObject *>(getSlot(VIEW_LIST_SLOT).toPrivate());
 }
 
@@ -325,32 +307,33 @@ ArrayBufferObject::canNeuter(JSContext *
         if (!ArrayBufferObject::canNeuterAsmJSArrayBuffer(cx, *this))
             return false;
     }
 
     return true;
 }
 
 /* static */ void
-ArrayBufferObject::neuter(JSContext *cx, Handle<ArrayBufferObject*> buffer, void *newData)
+ArrayBufferObject::neuter(JSContext *cx, Handle<ArrayBufferObject*> buffer,
+                          BufferContents newContents)
 {
     JS_ASSERT(buffer->canNeuter(cx));
 
     // Neuter all views on the buffer, clear out the list of views and the
     // buffer's data.
 
     for (ArrayBufferViewObject *view = buffer->viewList(); view; view = view->nextView()) {
-        view->neuter(newData);
+        view->neuter(newContents.data());
 
         // Notify compiled jit code that the base pointer has moved.
         MarkObjectStateChange(cx, view);
     }
 
-    if (newData != buffer->dataPointer())
-        buffer->setNewOwnedData(cx->runtime()->defaultFreeOp(), newData);
+    if (newContents.data() != buffer->dataPointer())
+        buffer->setNewOwnedData(cx->runtime()->defaultFreeOp(), newContents);
 
     buffer->setByteLength(0);
     buffer->setViewList(nullptr);
     buffer->setIsNeutered();
 
     // If this is happening during an incremental GC, remove the buffer from
     // the list of live buffers with multiple views if necessary.
     if (buffer->inLiveList()) {
@@ -365,47 +348,47 @@ ArrayBufferObject::neuter(JSContext *cx,
             }
         }
         JS_ASSERT(found);
         buffer->setInLiveList(false);
     }
 }
 
 void
-ArrayBufferObject::setNewOwnedData(FreeOp* fop, void *newData)
+ArrayBufferObject::setNewOwnedData(FreeOp* fop, BufferContents newContents)
 {
     JS_ASSERT(!isAsmJSArrayBuffer());
     JS_ASSERT(!isSharedArrayBuffer());
 
     if (ownsData()) {
-        JS_ASSERT(newData != dataPointer());
+        JS_ASSERT(newContents.data() != dataPointer());
         releaseData(fop);
     }
 
-    setDataPointer(static_cast<uint8_t *>(newData), OwnsData);
+    setDataPointer(newContents, OwnsData);
 }
 
 void
-ArrayBufferObject::changeContents(JSContext *cx, void *newData)
+ArrayBufferObject::changeContents(JSContext *cx, BufferContents newContents)
 {
     // Change buffer contents.
     uint8_t* oldDataPointer = dataPointer();
-    setNewOwnedData(cx->runtime()->defaultFreeOp(), newData);
+    setNewOwnedData(cx->runtime()->defaultFreeOp(), newContents);
 
     // Update all views.
     ArrayBufferViewObject *viewListHead = viewList();
     for (ArrayBufferViewObject *view = viewListHead; view; view = view->nextView()) {
         // Watch out for NULL data pointers in views. This means that the view
         // is not fully initialized (in which case it'll be initialized later
         // with the correct pointer).
         uint8_t *viewDataPointer = view->dataPointer();
         if (viewDataPointer) {
-            JS_ASSERT(newData);
+            JS_ASSERT(newContents);
             ptrdiff_t offset = viewDataPointer - oldDataPointer;
-            viewDataPointer = static_cast<uint8_t *>(newData) + offset;
+            viewDataPointer = static_cast<uint8_t *>(newContents.data()) + offset;
             view->setPrivate(viewDataPointer);
         }
 
         // Notify compiled jit code that the base pointer has moved.
         MarkObjectStateChange(cx, view);
     }
 }
 
@@ -428,17 +411,17 @@ ArrayBufferObject::prepareForAsmJSNoSign
 
     buffer->setIsAsmJSArrayBuffer();
     return true;
 }
 
 void
 ArrayBufferObject::releaseAsmJSArrayNoSignals(FreeOp *fop)
 {
-    JS_ASSERT(!isAsmJSMappedArrayBuffer());
+    JS_ASSERT(!(bufferKind() & MAPPED_BUFFER));
     fop->free_(dataPointer());
 }
 
 #ifdef JS_CODEGEN_X64
 /* static */ bool
 ArrayBufferObject::prepareForAsmJS(JSContext *cx, Handle<ArrayBufferObject*> buffer,
                                    bool usesSignalHandlers)
 {
@@ -483,32 +466,29 @@ ArrayBufferObject::prepareForAsmJS(JSCon
     VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE((unsigned char*)data + validLength,
                                                    AsmJSMappedSize-validLength);
 #   endif
 # endif
 
     // Copy over the current contents of the typed array.
     memcpy(data, buffer->dataPointer(), buffer->byteLength());
 
-    // Swap the new elements into the ArrayBufferObject.
-    buffer->changeContents(cx, data);
+    // Swap the new elements into the ArrayBufferObject. Mark the
+    // ArrayBufferObject so we don't do this again.
+    BufferContents newContents = BufferContents::create<BufferKind(ASMJS_BUFFER|MAPPED_BUFFER)>(data);
+    buffer->changeContents(cx, newContents);
     JS_ASSERT(data == buffer->dataPointer());
 
-    // Mark the ArrayBufferObject so (1) we don't do this again, (2) we know not
-    // to js_free the data in the normal way.
-    buffer->setIsAsmJSArrayBuffer();
-    buffer->setIsAsmJSMappedArrayBuffer();
-
     return true;
 }
 
 void
 ArrayBufferObject::releaseAsmJSArray(FreeOp *fop)
 {
-    if (!isAsmJSMappedArrayBuffer()) {
+    if (!(bufferKind() & MAPPED_BUFFER)) {
         releaseAsmJSArrayNoSignals(fop);
         return;
     }
 
     void *data = dataPointer();
 
     JS_ASSERT(uintptr_t(data) % AsmJSPageSize == 0);
 # ifdef XP_WIN
@@ -553,20 +533,21 @@ ArrayBufferObject::canNeuterAsmJSArrayBu
             break;
     }
     if (!act)
         return true;
 
     return false;
 }
 
-void *
+ArrayBufferObject::BufferContents
 ArrayBufferObject::createMappedContents(int fd, size_t offset, size_t length)
 {
-    return AllocateMappedContent(fd, offset, length, ARRAY_BUFFER_ALIGNMENT);
+    void *data = AllocateMappedContent(fd, offset, length, ARRAY_BUFFER_ALIGNMENT);
+    return BufferContents::create<MAPPED_BUFFER>(data);
 }
 
 void
 ArrayBufferObject::releaseMappedArray()
 {
     if(!isMappedArrayBuffer() || isNeutered())
         return;
 
@@ -601,30 +582,32 @@ ArrayBufferObject::dataPointer() const
     return static_cast<uint8_t *>(getSlot(DATA_SLOT).toPrivate());
 }
 
 void
 ArrayBufferObject::releaseData(FreeOp *fop)
 {
     JS_ASSERT(ownsData());
 
-    if (isAsmJSArrayBuffer())
+    BufferKind bufkind = bufferKind();
+    if (bufkind & ASMJS_BUFFER)
         releaseAsmJSArray(fop);
-    else if (isMappedArrayBuffer())
+    else if (bufkind & MAPPED_BUFFER)
         releaseMappedArray();
     else
         fop->free_(dataPointer());
 }
 
 void
-ArrayBufferObject::setDataPointer(void *data, OwnsState ownsData)
+ArrayBufferObject::setDataPointer(BufferContents contents, OwnsState ownsData)
 {
-    MOZ_ASSERT_IF(!is<SharedArrayBufferObject>() && !isMappedArrayBuffer(), data != nullptr);
-    setSlot(DATA_SLOT, PrivateValue(data));
+    MOZ_ASSERT_IF(!is<SharedArrayBufferObject>(), contents.data());
+    setSlot(DATA_SLOT, PrivateValue(contents.data()));
     setOwnsData(ownsData);
+    setFlags((flags() & ~KIND_MASK) | contents.kind());
 }
 
 size_t
 ArrayBufferObject::byteLength() const
 {
     return size_t(getSlot(BYTE_LENGTH_SLOT).toDouble());
 }
 
@@ -642,68 +625,81 @@ ArrayBufferObject::flags() const
 
 void
 ArrayBufferObject::setFlags(uint32_t flags)
 {
     setSlot(FLAGS_SLOT, Int32Value(flags));
 }
 
 ArrayBufferObject *
-ArrayBufferObject::create(JSContext *cx, uint32_t nbytes, void *data /* = nullptr */,
-                          NewObjectKind newKind /* = GenericObject */,
-                          bool mapped /* = false */)
+ArrayBufferObject::create(JSContext *cx, uint32_t nbytes, BufferContents contents,
+                          NewObjectKind newKind /* = GenericObject */)
 {
-    JS_ASSERT_IF(mapped, data);
+    JS_ASSERT_IF(contents.kind() & MAPPED_BUFFER, contents);
 
     // If we need to allocate data, try to use a larger object size class so
     // that the array buffer's data can be allocated inline with the object.
     // The extra space will be left unused by the object's fixed slots and
     // available for the buffer's data, see NewObject().
     size_t reservedSlots = JSCLASS_RESERVED_SLOTS(&class_);
 
     size_t nslots = reservedSlots;
-    if (!data) {
+    bool allocated = false;
+    if (contents) {
+        // The ABO is taking ownership, so account the bytes against the zone.
+        size_t nAllocated = nbytes;
+        if (contents.kind() & MAPPED_BUFFER)
+            nAllocated = JS_ROUNDUP(nbytes, js::gc::SystemPageSize());
+        cx->zone()->updateMallocCounter(nAllocated);
+    } else {
         size_t usableSlots = JSObject::MAX_FIXED_SLOTS - reservedSlots;
         if (nbytes <= usableSlots * sizeof(Value)) {
             int newSlots = (nbytes - 1) / sizeof(Value) + 1;
             JS_ASSERT(int(nbytes) <= newSlots * int(sizeof(Value)));
             nslots = reservedSlots + newSlots;
+            contents = BufferContents::createUnowned(nullptr);
         } else {
-            data = AllocateArrayBufferContents(cx, nbytes);
-            if (!data)
+            contents = AllocateArrayBufferContents(cx, nbytes);
+            if (!contents)
                 return nullptr;
+            allocated = true;
         }
     }
 
     JS_ASSERT(!(class_.flags & JSCLASS_HAS_PRIVATE));
     gc::AllocKind allocKind = GetGCObjectKind(nslots);
 
     Rooted<ArrayBufferObject*> obj(cx, NewBuiltinClassInstance<ArrayBufferObject>(cx, allocKind, newKind));
-    if (!obj)
+    if (!obj) {
+        if (allocated)
+            js_free(contents.data());
         return nullptr;
+    }
 
     JS_ASSERT(obj->getClass() == &class_);
-
     JS_ASSERT(!gc::IsInsideNursery(obj));
 
-    if (data) {
-        obj->initialize(nbytes, data, OwnsData);
-        if (mapped)
-            obj->setIsMappedArrayBuffer();
-        if (mapped)
-            JS_updateMallocCounter(cx, JS_ROUNDUP(nbytes, js::gc::SystemPageSize()));
-    } else {
+    if (!contents) {
         void *data = obj->fixedData(reservedSlots);
         memset(data, 0, nbytes);
-        obj->initialize(nbytes, data, DoesntOwnData);
+        obj->initialize(nbytes, BufferContents::createUnowned(data), DoesntOwnData);
+    } else {
+        obj->initialize(nbytes, contents, OwnsData);
     }
 
     return obj;
 }
 
+ArrayBufferObject *
+ArrayBufferObject::create(JSContext *cx, uint32_t nbytes,
+                          NewObjectKind newKind /* = GenericObject */)
+{
+    return create(cx, nbytes, BufferContents::createUnowned(nullptr));
+}
+
 JSObject *
 ArrayBufferObject::createSlice(JSContext *cx, Handle<ArrayBufferObject*> arrayBuffer,
                                uint32_t begin, uint32_t end)
 {
     uint32_t bufLength = arrayBuffer->byteLength();
     if (begin > bufLength || end > bufLength || begin > end) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPE_ERR_BAD_ARGS);
         return nullptr;
@@ -751,68 +747,72 @@ ArrayBufferObject::createDataViewForThis
     CallArgs args = CallArgsFromVp(argc, vp);
     return CallNonGenericMethod<IsArrayBuffer, createDataViewForThisImpl>(cx, args);
 }
 
 /* static */ bool
 ArrayBufferObject::ensureNonInline(JSContext *cx, Handle<ArrayBufferObject*> buffer)
 {
     if (!buffer->ownsData()) {
-        void *data = AllocateArrayBufferContents(cx, buffer->byteLength());
-        if (!data)
+        MOZ_ASSERT(!buffer->isSharedArrayBuffer());
+        BufferContents contents = AllocateArrayBufferContents(cx, buffer->byteLength());
+        if (!contents)
             return false;
-        memcpy(data, buffer->dataPointer(), buffer->byteLength());
-        buffer->changeContents(cx, data);
+        memcpy(contents.data(), buffer->dataPointer(), buffer->byteLength());
+        buffer->changeContents(cx, contents);
     }
 
     return true;
 }
 
 /* static */ void *
 ArrayBufferObject::stealContents(JSContext *cx, Handle<ArrayBufferObject*> buffer)
 {
     if (!buffer->canNeuter(cx)) {
         js_ReportOverRecursed(cx);
         return nullptr;
     }
 
-    void *oldData = buffer->dataPointer();
-    void *newData = AllocateArrayBufferContents(cx, buffer->byteLength());
-    if (!newData)
+    BufferContents oldContents(buffer->dataPointer(), buffer->bufferKind());
+    BufferContents newContents = AllocateArrayBufferContents(cx, buffer->byteLength());
+    if (!newContents)
         return nullptr;
 
     if (buffer->hasStealableContents()) {
+        // Return the old contents and give the neutered buffer a pointer to
+        // freshly allocated memory that we will never write to and should
+        // never get committed.
         buffer->setOwnsData(DoesntOwnData);
-        ArrayBufferObject::neuter(cx, buffer, newData);
-        return oldData;
+        ArrayBufferObject::neuter(cx, buffer, newContents);
+        return oldContents.data();
     } else {
-        memcpy(newData, oldData, buffer->byteLength());
-        ArrayBufferObject::neuter(cx, buffer, oldData);
-        return newData;
+        // Create a new chunk of memory to return since we cannot steal the
+        // existing contents away from the buffer.
+        memcpy(newContents.data(), oldContents.data(), buffer->byteLength());
+        ArrayBufferObject::neuter(cx, buffer, oldContents);
+        return newContents.data();
     }
-
-    return oldData;
 }
 
 /* static */ void
 ArrayBufferObject::addSizeOfExcludingThis(JSObject *obj, mozilla::MallocSizeOf mallocSizeOf, JS::ObjectsExtraSizes *sizes)
 {
     ArrayBufferObject &buffer = AsArrayBuffer(obj);
 
     if (!buffer.ownsData())
         return;
 
-    if (MOZ_UNLIKELY(buffer.isAsmJSArrayBuffer())) {
+    if (MOZ_UNLIKELY(buffer.bufferKind() & ASMJS_BUFFER)) {
         // On x64, ArrayBufferObject::prepareForAsmJS switches the
         // ArrayBufferObject to use mmap'd storage.
-        if (buffer.isAsmJSMappedArrayBuffer())
+        if (buffer.bufferKind() & MAPPED_BUFFER)
             sizes->nonHeapElementsAsmJS += buffer.byteLength();
         else
             sizes->mallocHeapElementsAsmJS += mallocSizeOf(buffer.dataPointer());
-    } else if (MOZ_UNLIKELY(buffer.isMappedArrayBuffer())) {
+    } else if (MOZ_UNLIKELY(buffer.bufferKind() & MAPPED_BUFFER)) {
         sizes->nonHeapElementsMapped += buffer.byteLength();
     } else if (buffer.dataPointer()) {
         sizes->mallocHeapElementsNonAsmJS += mallocSizeOf(buffer.dataPointer());
     }
 }
 
 /* static */ void
 ArrayBufferObject::finalize(FreeOp *fop, JSObject *obj)
@@ -1094,26 +1094,26 @@ JS_NeuterArrayBuffer(JSContext *cx, Hand
 
     Rooted<ArrayBufferObject*> buffer(cx, &obj->as<ArrayBufferObject>());
 
     if (!buffer->canNeuter(cx)) {
         js_ReportOverRecursed(cx);
         return false;
     }
 
-    void *newData;
     if (changeData == ChangeData && buffer->hasStealableContents()) {
-        newData = AllocateArrayBufferContents(cx, buffer->byteLength());
-        if (!newData)
+        ArrayBufferObject::BufferContents newContents =
+            AllocateArrayBufferContents(cx, buffer->byteLength());
+        if (!newContents)
             return false;
+        ArrayBufferObject::neuter(cx, buffer, newContents);
     } else {
-        newData = buffer->dataPointer();
+        ArrayBufferObject::neuter(cx, buffer, buffer->contents());
     }
 
-    ArrayBufferObject::neuter(cx, buffer, newData);
     return true;
 }
 
 JS_FRIEND_API(bool)
 JS_IsNeuteredArrayBufferObject(JSObject *obj)
 {
     obj = CheckedUnwrap(obj);
     if (!obj)
@@ -1127,32 +1127,22 @@ JS_IsNeuteredArrayBufferObject(JSObject 
 JS_FRIEND_API(JSObject *)
 JS_NewArrayBuffer(JSContext *cx, uint32_t nbytes)
 {
     JS_ASSERT(nbytes <= INT32_MAX);
     return ArrayBufferObject::create(cx, nbytes);
 }
 
 JS_PUBLIC_API(JSObject *)
-JS_NewArrayBufferWithContents(JSContext *cx, size_t nbytes, void *contents)
+JS_NewArrayBufferWithContents(JSContext *cx, size_t nbytes, void *data)
 {
-    JS_ASSERT(contents);
-    return ArrayBufferObject::create(cx, nbytes, contents, TenuredObject, false);
-}
-
-JS_PUBLIC_API(void *)
-JS_AllocateArrayBufferContents(JSContext *maybecx, uint32_t nbytes)
-{
-    return AllocateArrayBufferContents(maybecx, nbytes);
-}
-
-JS_PUBLIC_API(void *)
-JS_ReallocateArrayBufferContents(JSContext *maybecx, uint32_t nbytes, void *oldContents, uint32_t oldNbytes)
-{
-    return AllocateArrayBufferContents(maybecx, nbytes, oldContents, oldNbytes);
+    JS_ASSERT(data);
+    ArrayBufferObject::BufferContents contents =
+        ArrayBufferObject::BufferContents::create<ArrayBufferObject::PLAIN_BUFFER>(data);
+    return ArrayBufferObject::create(cx, nbytes, contents, TenuredObject);
 }
 
 JS_FRIEND_API(bool)
 JS_IsArrayBufferObject(JSObject *obj)
 {
     obj = CheckedUnwrap(obj);
     return obj ? obj->is<ArrayBufferObject>() : false;
 }
@@ -1177,26 +1167,28 @@ JS_StealArrayBufferContents(JSContext *c
         return nullptr;
     }
 
     Rooted<ArrayBufferObject*> buffer(cx, &obj->as<ArrayBufferObject>());
     return ArrayBufferObject::stealContents(cx, buffer);
 }
 
 JS_PUBLIC_API(JSObject *)
-JS_NewMappedArrayBufferWithContents(JSContext *cx, size_t nbytes, void *contents)
+JS_NewMappedArrayBufferWithContents(JSContext *cx, size_t nbytes, void *data)
 {
-    JS_ASSERT(contents);
-    return ArrayBufferObject::create(cx, nbytes, contents, TenuredObject, true);
+    JS_ASSERT(data);
+    ArrayBufferObject::BufferContents contents =
+        ArrayBufferObject::BufferContents::create<ArrayBufferObject::MAPPED_BUFFER>(data);
+    return ArrayBufferObject::create(cx, nbytes, contents, TenuredObject);
 }
 
 JS_PUBLIC_API(void *)
 JS_CreateMappedArrayBufferContents(int fd, size_t offset, size_t length)
 {
-    return ArrayBufferObject::createMappedContents(fd, offset, length);
+    return ArrayBufferObject::createMappedContents(fd, offset, length).data();
 }
 
 JS_PUBLIC_API(void)
 JS_ReleaseMappedArrayBufferContents(void *contents, size_t length)
 {
     DeallocateMappedContent(contents, length);
 }
 
--- a/js/src/vm/ArrayBufferObject.h
+++ b/js/src/vm/ArrayBufferObject.h
@@ -57,32 +57,97 @@ class ArrayBufferObject : public JSObjec
     static const uint8_t BYTE_LENGTH_SLOT = 1;
     static const uint8_t VIEW_LIST_SLOT = 2;
     static const uint8_t FLAGS_SLOT = 3;
 
     static const uint8_t RESERVED_SLOTS = 4;
 
     static const size_t ARRAY_BUFFER_ALIGNMENT = 8;
 
+  public:
+
+    enum BufferKind {
+        PLAIN_BUFFER        =   0, // malloced or inline data
+        ASMJS_BUFFER        = 0x1,
+        SHARED_BUFFER       = 0x2,
+        MAPPED_BUFFER       = 0x4,
+        KIND_MASK           = ASMJS_BUFFER | SHARED_BUFFER | MAPPED_BUFFER
+    };
+
+  protected:
+
+    enum ArrayBufferFlags {
+        // The flags also store the BufferKind
+        BUFFER_KIND_MASK    = BufferKind::KIND_MASK,
+
+        NEUTERED_BUFFER     = 0x8,
+
+        // In the gcLiveArrayBuffers list.
+        IN_LIVE_LIST        =  0x10,
+
+        // The dataPointer() is owned by this buffer and should be released
+        // when no longer in use. Releasing the pointer may be done by either
+        // freeing or unmapping it, and how to do this is determined by the
+        // buffer's other flags.
+        OWNS_DATA           =  0x20,
+    };
+
+  public:
+
+    class BufferContents {
+        uint8_t *data_;
+        BufferKind kind_;
+
+        friend class ArrayBufferObject;
+
+        typedef void (BufferContents::* ConvertibleToBool)();
+        void nonNull() {}
+
+        BufferContents(uint8_t *data, BufferKind kind) : data_(data), kind_(kind) {
+            MOZ_ASSERT((kind_ & ~KIND_MASK) == 0);
+        }
+
+      public:
+
+        template<BufferKind Kind>
+        static BufferContents create(void *data)
+        {
+            return BufferContents(static_cast<uint8_t*>(data), Kind);
+        }
+
+        static BufferContents createUnowned(void *data)
+        {
+            return BufferContents(static_cast<uint8_t*>(data), PLAIN_BUFFER);
+        }
+
+        uint8_t *data() const { return data_; }
+        BufferKind kind() const { return kind_; }
+
+        operator ConvertibleToBool() const { return data_ ? &BufferContents::nonNull : nullptr; }
+    };
+
     static const Class class_;
 
     static const Class protoClass;
     static const JSFunctionSpec jsfuncs[];
     static const JSFunctionSpec jsstaticfuncs[];
 
     static bool byteLengthGetter(JSContext *cx, unsigned argc, Value *vp);
 
     static bool fun_slice(JSContext *cx, unsigned argc, Value *vp);
 
     static bool fun_isView(JSContext *cx, unsigned argc, Value *vp);
 
     static bool class_constructor(JSContext *cx, unsigned argc, Value *vp);
 
-    static ArrayBufferObject *create(JSContext *cx, uint32_t nbytes, void *contents = nullptr,
-                                     NewObjectKind newKind = GenericObject, bool mapped = false);
+    static ArrayBufferObject *create(JSContext *cx, uint32_t nbytes,
+                                     BufferContents contents,
+                                     NewObjectKind newKind = GenericObject);
+    static ArrayBufferObject *create(JSContext *cx, uint32_t nbytes,
+                                     NewObjectKind newKind = GenericObject);
 
     static JSObject *createSlice(JSContext *cx, Handle<ArrayBufferObject*> arrayBuffer,
                                  uint32_t begin, uint32_t end);
 
     static bool createDataViewForThisImpl(JSContext *cx, CallArgs args);
     static bool createDataViewForThis(JSContext *cx, unsigned argc, Value *vp);
 
     template<typename T>
@@ -121,118 +186,103 @@ class ArrayBufferObject : public JSObjec
         return !isNeutered();
     }
 
     static void addSizeOfExcludingThis(JSObject *obj, mozilla::MallocSizeOf mallocSizeOf,
                                        JS::ObjectsExtraSizes *sizes);
 
     void addView(ArrayBufferViewObject *view);
 
-    void setNewOwnedData(FreeOp* fop, void *newData);
-    void changeContents(JSContext *cx, void *newData);
+    void setNewOwnedData(FreeOp* fop, BufferContents newContents);
+    void changeContents(JSContext *cx, BufferContents newContents);
 
     /*
      * Ensure data is not stored inline in the object. Used when handing back a
      * GC-safe pointer.
      */
     static bool ensureNonInline(JSContext *cx, Handle<ArrayBufferObject*> buffer);
 
     bool canNeuter(JSContext *cx);
 
     /* Neuter this buffer and all its views. */
-    static void neuter(JSContext *cx, Handle<ArrayBufferObject*> buffer, void *newData);
+    static void neuter(JSContext *cx, Handle<ArrayBufferObject*> buffer, BufferContents newContents);
 
     uint8_t *dataPointer() const;
     size_t byteLength() const;
+    BufferContents contents() const {
+        return BufferContents(dataPointer(), bufferKind());
+    }
 
     void releaseData(FreeOp *fop);
 
     /*
      * Check if the arrayBuffer contains any data. This will return false for
      * ArrayBuffer.prototype and neutered ArrayBuffers.
      */
     bool hasData() const {
         return getClass() == &class_;
     }
 
+    BufferKind bufferKind() const { return BufferKind(flags() & BUFFER_KIND_MASK); }
     bool isAsmJSArrayBuffer() const { return flags() & ASMJS_BUFFER; }
-    bool isAsmJSMappedArrayBuffer() const { return flags() & ASMJS_MAPPED_BUFFER; }
     bool isSharedArrayBuffer() const { return flags() & SHARED_BUFFER; }
     bool isMappedArrayBuffer() const { return flags() & MAPPED_BUFFER; }
     bool isNeutered() const { return flags() & NEUTERED_BUFFER; }
 
     static bool prepareForAsmJS(JSContext *cx, Handle<ArrayBufferObject*> buffer,
                                 bool usesSignalHandlers);
     static bool prepareForAsmJSNoSignals(JSContext *cx, Handle<ArrayBufferObject*> buffer);
     static bool canNeuterAsmJSArrayBuffer(JSContext *cx, ArrayBufferObject &buffer);
 
     static void finalize(FreeOp *fop, JSObject *obj);
 
-    static void *createMappedContents(int fd, size_t offset, size_t length);
+    static BufferContents createMappedContents(int fd, size_t offset, size_t length);
 
     static size_t flagsOffset() {
         return getFixedSlotOffset(FLAGS_SLOT);
     }
 
     static uint32_t neuteredFlag() { return NEUTERED_BUFFER; }
 
   protected:
     enum OwnsState {
         DoesntOwnData = 0,
         OwnsData = 1,
     };
 
-    void setDataPointer(void *data, OwnsState ownsState);
+    void setDataPointer(BufferContents contents, OwnsState ownsState);
     void setByteLength(size_t length);
 
     ArrayBufferViewObject *viewList() const;
     void setViewList(ArrayBufferViewObject *viewsHead);
     void setViewListNoBarrier(ArrayBufferViewObject *viewsHead);
 
-    enum ArrayBufferFlags {
-        // In the gcLiveArrayBuffers list.
-        IN_LIVE_LIST        =  0x1,
-
-        // The dataPointer() is owned by this buffer and should be released
-        // when no longer in use. Releasing the pointer may be done by either
-        // freeing or unmapping it, and how to do this is determined by the
-        // buffer's other flags.
-        OWNS_DATA           =  0x2,
-
-        ASMJS_BUFFER        =  0x4,
-        ASMJS_MAPPED_BUFFER =  0x8,
-        SHARED_BUFFER       = 0x10,
-        MAPPED_BUFFER       = 0x20,
-        NEUTERED_BUFFER     = 0x40,
-    };
-
     uint32_t flags() const;
     void setFlags(uint32_t flags);
 
     bool inLiveList() const { return flags() & IN_LIVE_LIST; }
     void setInLiveList(bool value) {
         setFlags(value ? (flags() | IN_LIVE_LIST) : (flags() & ~IN_LIVE_LIST));
     }
 
     bool ownsData() const { return flags() & OWNS_DATA; }
     void setOwnsData(OwnsState owns) {
         setFlags(owns ? (flags() | OWNS_DATA) : (flags() & ~OWNS_DATA));
     }
 
     void setIsAsmJSArrayBuffer() { setFlags(flags() | ASMJS_BUFFER); }
-    void setIsAsmJSMappedArrayBuffer() { setFlags(flags() | ASMJS_MAPPED_BUFFER); }
     void setIsSharedArrayBuffer() { setFlags(flags() | SHARED_BUFFER); }
     void setIsMappedArrayBuffer() { setFlags(flags() | MAPPED_BUFFER); }
     void setIsNeutered() { setFlags(flags() | NEUTERED_BUFFER); }
 
-    void initialize(size_t byteLength, void *data, OwnsState ownsState) {
+    void initialize(size_t byteLength, BufferContents contents, OwnsState ownsState) {
         setByteLength(byteLength);
         setFlags(0);
         setViewListNoBarrier(nullptr);
-        setDataPointer(data, ownsState);
+        setDataPointer(contents, ownsState);
     }
 
     void releaseAsmJSArray(FreeOp *fop);
     void releaseAsmJSArrayNoSignals(FreeOp *fop);
     void releaseMappedArray();
 };
 
 /*
--- a/js/src/vm/SharedArrayObject.cpp
+++ b/js/src/vm/SharedArrayObject.cpp
@@ -207,17 +207,17 @@ JSObject *
 SharedArrayBufferObject::New(JSContext *cx, SharedArrayRawBuffer *buffer)
 {
     Rooted<SharedArrayBufferObject*> obj(cx, NewBuiltinClassInstance<SharedArrayBufferObject>(cx));
     if (!obj)
         return nullptr;
 
     JS_ASSERT(obj->getClass() == &class_);
 
-    obj->initialize(buffer->byteLength(), nullptr, DoesntOwnData);
+    obj->initialize(buffer->byteLength(), BufferContents::createUnowned(nullptr), DoesntOwnData);
 
     obj->acceptRawBuffer(buffer);
     obj->setIsSharedArrayBuffer();
 
     return obj;
 }
 
 void
--- a/js/src/vm/StructuredClone.cpp
+++ b/js/src/vm/StructuredClone.cpp
@@ -1102,22 +1102,23 @@ JSStructuredCloneWriter::transferOwnersh
 
 #if DEBUG
         SCInput::getPair(point, &tag, (uint32_t*) &ownership);
         MOZ_ASSERT(tag == SCTAG_TRANSFER_MAP_PENDING_ENTRY);
         MOZ_ASSERT(ownership == JS::SCTAG_TMO_UNFILLED);
 #endif
 
         if (obj->is<ArrayBufferObject>()) {
+            bool isMapped = obj->as<ArrayBufferObject>().isMappedArrayBuffer();
             size_t nbytes = obj->as<ArrayBufferObject>().byteLength();
             content = JS_StealArrayBufferContents(context(), obj);
             if (!content)
                 return false; // Destructor will clean up the already-transferred data
             tag = SCTAG_TRANSFER_MAP_ARRAY_BUFFER;
-            if (obj->as<ArrayBufferObject>().isMappedArrayBuffer())
+            if (isMapped)
                 ownership = JS::SCTAG_TMO_MAPPED_DATA;
             else
                 ownership = JS::SCTAG_TMO_ALLOC_DATA;
             extraData = nbytes;
         } else if (obj->is<SharedArrayBufferObject>()) {
             SharedArrayRawBuffer *rawbuf = obj->as<SharedArrayBufferObject>().rawBufferObject();
 
             // Avoids a race condition where the parent thread frees the buffer
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -4568,23 +4568,26 @@ nsCSSFrameConstructor::FindDisplayData(c
     { NS_STYLE_DISPLAY_GRID,
       FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewGridContainerFrame) },
     { NS_STYLE_DISPLAY_INLINE_GRID,
       FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewGridContainerFrame) },
     { NS_STYLE_DISPLAY_RUBY,
       FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT,
                   NS_NewRubyFrame) },
     { NS_STYLE_DISPLAY_RUBY_BASE,
-      FCDATA_DECL(FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRubyBaseContainer),
+      FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT |
+                  FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRubyBaseContainer),
                   NS_NewRubyBaseFrame) },
     { NS_STYLE_DISPLAY_RUBY_BASE_CONTAINER,
-      FCDATA_DECL(FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRuby),
+      FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT |
+                  FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRuby),
                   NS_NewRubyBaseContainerFrame) },
     { NS_STYLE_DISPLAY_RUBY_TEXT,
-      FCDATA_DECL(FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRubyTextContainer),
+      FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT |
+                  FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRubyTextContainer),
                   NS_NewRubyTextFrame) },
     { NS_STYLE_DISPLAY_RUBY_TEXT_CONTAINER,
       FCDATA_DECL(FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRuby),
                   NS_NewRubyTextContainerFrame) },
     { NS_STYLE_DISPLAY_TABLE,
       FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructTable) },
     { NS_STYLE_DISPLAY_INLINE_TABLE,
       FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructTable) },
@@ -9091,30 +9094,33 @@ nsCSSFrameConstructor::sPseudoParentData
     FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT |
                 FCDATA_USE_CHILD_ITEMS |
                 FCDATA_SKIP_FRAMESET,
                 NS_NewRubyFrame),
     &nsCSSAnonBoxes::ruby
   },
   { // Ruby Base
     FCDATA_DECL(FCDATA_USE_CHILD_ITEMS | 
+                FCDATA_IS_LINE_PARTICIPANT |
                 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRubyBaseContainer) |
                 FCDATA_SKIP_FRAMESET,
                 NS_NewRubyBaseFrame),
     &nsCSSAnonBoxes::rubyBase
   },
   { // Ruby Base Container
-    FCDATA_DECL(FCDATA_USE_CHILD_ITEMS | 
+    FCDATA_DECL(FCDATA_USE_CHILD_ITEMS |
+                FCDATA_IS_LINE_PARTICIPANT |
                 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRuby) |
                 FCDATA_SKIP_FRAMESET,
                 NS_NewRubyBaseContainerFrame),
     &nsCSSAnonBoxes::rubyBaseContainer
   },
   { // Ruby Text
     FCDATA_DECL(FCDATA_USE_CHILD_ITEMS |
+                FCDATA_IS_LINE_PARTICIPANT |
                 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRubyTextContainer) |
                 FCDATA_SKIP_FRAMESET,
                 NS_NewRubyTextFrame),
     &nsCSSAnonBoxes::rubyText
   },
   { // Ruby Text Container
     FCDATA_DECL(FCDATA_USE_CHILD_ITEMS |
                 FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRuby) |
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -6927,8 +6927,44 @@ nsLayoutUtils::IsOutlineStyleAutoEnabled
   if (!sOutlineStyleAutoPrefCached) {
     sOutlineStyleAutoPrefCached = true;
     Preferences::AddBoolVarCache(&sOutlineStyleAutoEnabled,
                                  "layout.css.outline-style-auto.enabled",
                                  false);
   }
   return sOutlineStyleAutoEnabled;
 }
+
+/* static */ void
+nsLayoutUtils::SetBSizeFromFontMetrics(const nsIFrame* aFrame,
+                                       nsHTMLReflowMetrics& aMetrics,
+                                       const nsHTMLReflowState& aReflowState,
+                                       LogicalMargin aFramePadding, 
+                                       WritingMode aLineWM,
+                                       WritingMode aFrameWM)
+{
+  nsRefPtr<nsFontMetrics> fm;
+  float inflation = nsLayoutUtils::FontSizeInflationFor(aFrame);
+  nsLayoutUtils::GetFontMetricsForFrame(aFrame, getter_AddRefs(fm), inflation);
+  aReflowState.rendContext->SetFont(fm);
+
+  if (fm) {
+    // Compute final height of the frame.
+    //
+    // Do things the standard css2 way -- though it's hard to find it
+    // in the css2 spec! It's actually found in the css1 spec section
+    // 4.4 (you will have to read between the lines to really see
+    // it).
+    //
+    // The height of our box is the sum of our font size plus the top
+    // and bottom border and padding. The height of children do not
+    // affect our height.
+    aMetrics.SetBlockStartAscent(fm->MaxAscent());
+    aMetrics.BSize(aLineWM) = fm->MaxHeight();
+  } else {
+    NS_WARNING("Cannot get font metrics - defaulting sizes to 0");
+    aMetrics.SetBlockStartAscent(aMetrics.BSize(aLineWM) = 0);
+  }
+  aMetrics.SetBlockStartAscent(aMetrics.BlockStartAscent() +
+                               aFramePadding.BStart(aFrameWM));
+  aMetrics.BSize(aLineWM) +=
+    aReflowState.ComputedLogicalBorderPadding().BStartEnd(aFrameWM);
+}
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -22,16 +22,17 @@
 #include "nsStyleCoord.h"
 #include "nsStyleConsts.h"
 #include "nsGkAtoms.h"
 #include "nsRuleNode.h"
 #include "imgIContainer.h"
 #include "mozilla/gfx/2D.h"
 #include "Units.h"
 #include "mozilla/ToString.h"
+#include "nsHTMLReflowMetrics.h"
 
 #include <limits>
 #include <algorithm>
 
 class nsIFormControlFrame;
 class nsPresContext;
 class nsIContent;
 class nsIAtom;
@@ -2264,16 +2265,23 @@ public:
    */
   static bool GetOrMaybeCreateDisplayPort(nsDisplayListBuilder& aBuilder,
                                           nsIFrame* aScrollFrame,
                                           nsRect aDisplayPortBase,
                                           nsRect* aOutDisplayport);
 
   static bool IsOutlineStyleAutoEnabled();
 
+  static void SetBSizeFromFontMetrics(const nsIFrame* aFrame,
+                                      nsHTMLReflowMetrics& aMetrics,
+                                      const nsHTMLReflowState& aReflowState,
+                                      mozilla::LogicalMargin aFramePadding, 
+                                      mozilla::WritingMode aLineWM,
+                                      mozilla::WritingMode aFrameWM);
+
 private:
   static uint32_t sFontSizeInflationEmPerLine;
   static uint32_t sFontSizeInflationMinTwips;
   static uint32_t sFontSizeInflationLineThreshold;
   static int32_t  sFontSizeInflationMappingIntercept;
   static uint32_t sFontSizeInflationMaxRatio;
   static bool sFontSizeInflationForceEnabled;
   static bool sFontSizeInflationDisabledInMasterProcess;
--- a/layout/build/moz.build
+++ b/layout/build/moz.build
@@ -60,17 +60,17 @@ LOCAL_INCLUDES += [
     '/dom/src/storage',
     '/dom/telephony',
     '/dom/xbl',
     '/dom/xslt/base',
     '/dom/xslt/xml',
     '/dom/xslt/xpath',
     '/dom/xslt/xslt',
     '/editor/composer',
-    '/editor/libeditor/base',
+    '/editor/libeditor',
     '/editor/libeditor/html',
     '/editor/libeditor/text',
     '/editor/txmgr',
     '/editor/txtsvc',
     '/extensions/cookie',
     '/js/xpconnect/loader',
     '/js/xpconnect/src',
     '/netwerk/base/src',
--- a/layout/forms/moz.build
+++ b/layout/forms/moz.build
@@ -40,17 +40,17 @@ FAIL_ON_WARNINGS = True
 
 MSVC_ENABLE_PGO = True
 
 FINAL_LIBRARY = 'xul'
 
 LOCAL_INCLUDES += [
     '../../content/base/src',
     '../../content/html/content/src',
-    '../../editor/libeditor/base',
+    '../../editor/libeditor',
     '../../editor/libeditor/text',
     '../../editor/txmgr',
     '../base',
     '../generic',
     '../xul',
 ]
 
 if CONFIG['ENABLE_INTL_API']:
--- a/layout/generic/nsInlineFrame.cpp
+++ b/layout/generic/nsInlineFrame.cpp
@@ -700,42 +700,18 @@ nsInlineFrame::ReflowFrames(nsPresContex
    */
   if ((NS_FRAME_IS_COMPLETE(aStatus) &&
        !LastInFlow()->GetNextContinuation() &&
        !FrameIsNonLastInIBSplit()) ||
       boxDecorationBreakClone) {
     aMetrics.ISize(lineWM) += framePadding.IEnd(frameWM);
   }
 
-  nsRefPtr<nsFontMetrics> fm;
-  float inflation = nsLayoutUtils::FontSizeInflationFor(this);
-  nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm), inflation);
-  aReflowState.rendContext->SetFont(fm);
-
-  if (fm) {
-    // Compute final height of the frame.
-    //
-    // Do things the standard css2 way -- though it's hard to find it
-    // in the css2 spec! It's actually found in the css1 spec section
-    // 4.4 (you will have to read between the lines to really see
-    // it).
-    //
-    // The height of our box is the sum of our font size plus the top
-    // and bottom border and padding. The height of children do not
-    // affect our height.
-    aMetrics.SetBlockStartAscent(fm->MaxAscent());
-    aMetrics.BSize(lineWM) = fm->MaxHeight();
-  } else {
-    NS_WARNING("Cannot get font metrics - defaulting sizes to 0");
-    aMetrics.SetBlockStartAscent(aMetrics.BSize(lineWM) = 0);
-  }
-  aMetrics.SetBlockStartAscent(aMetrics.BlockStartAscent() +
-                               framePadding.BStart(frameWM));
-  aMetrics.BSize(lineWM) +=
-    aReflowState.ComputedLogicalBorderPadding().BStartEnd(frameWM);
+  nsLayoutUtils::SetBSizeFromFontMetrics(this, aMetrics, aReflowState,
+                                         framePadding, lineWM, frameWM);
 
   // For now our overflow area is zero. The real value will be
   // computed in |nsLineLayout::RelativePositionFrames|.
   aMetrics.mOverflowAreas.Clear();
 
 #ifdef NOISY_FINAL_SIZE
   ListTag(stdout);
   printf(": metrics=%d,%d ascent=%d\n",
--- a/layout/generic/nsLineLayout.cpp
+++ b/layout/generic/nsLineLayout.cpp
@@ -2729,8 +2729,26 @@ nsLineLayout::RelativePositionFrames(Per
   // overflow rect...
   if (psd->mFrame) {
     PerFrameData* spanPFD = psd->mFrame;
     nsIFrame* frame = spanPFD->mFrame;
     frame->FinishAndStoreOverflow(overflowAreas, frame->GetSize());
   }
   aOverflowAreas = overflowAreas;
 }
+
+void
+nsLineLayout::AdvanceICoord(nscoord aAmount)
+{
+  mCurrentSpan->mICoord += aAmount;
+}
+
+WritingMode
+nsLineLayout::GetWritingMode()
+{
+  return mRootSpan->mWritingMode;
+}
+
+nscoord
+nsLineLayout::GetCurrentICoord()
+{
+  return mCurrentSpan->mICoord;
+}
--- a/layout/generic/nsLineLayout.h
+++ b/layout/generic/nsLineLayout.h
@@ -311,16 +311,30 @@ public:
    * the right edge for RTL blocks and from the left edge for LTR blocks.
    * In other words, the current frame's distance from the line container's
    * start content edge is:
    * <code>GetCurrentFrameInlineDistanceFromBlock() - lineContainer->GetUsedBorderAndPadding().left</code>
    * Note the use of <code>.left</code> for both LTR and RTL line containers.
    */
   nscoord GetCurrentFrameInlineDistanceFromBlock();
 
+  /**
+   * Move the inline position where the next frame will be reflowed forward by
+   * aAmount.
+   */
+  void AdvanceICoord(nscoord aAmount);
+  /**
+   * Returns the writing mode for the root span.
+   */
+  mozilla::WritingMode GetWritingMode();
+  /**
+   * Returns the inline position where the next frame will be reflowed.
+   */
+  nscoord GetCurrentICoord();
+
 protected:
   // This state is constant for a given block frame doing line layout
   nsFloatManager* mFloatManager;
   const nsStyleText* mStyleText; // for the block
   const nsHTMLReflowState* mBlockReflowState;
 
   nsIContent* mLastOptionalBreakContent;
   nsIContent* mForceBreakContent;
--- a/layout/generic/nsRubyBaseContainerFrame.cpp
+++ b/layout/generic/nsRubyBaseContainerFrame.cpp
@@ -2,18 +2,22 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code is subject to the terms of the Mozilla Public License
  * version 2.0 (the "License"). You can obtain a copy of the License at
  * http://mozilla.org/MPL/2.0/. */
 
 /* rendering object for CSS "display: ruby-base-container" */
 
 #include "nsRubyBaseContainerFrame.h"
+#include "nsLineLayout.h"
 #include "nsPresContext.h"
 #include "nsStyleContext.h"
+#include "WritingModes.h"
+
+using namespace mozilla;
 
 //----------------------------------------------------------------------
 
 // Frame class boilerplate
 // =======================
 
 NS_QUERYFRAME_HEAD(nsRubyBaseContainerFrame)
   NS_QUERYFRAME_ENTRY(nsRubyBaseContainerFrame)
@@ -42,8 +46,179 @@ nsRubyBaseContainerFrame::GetType() cons
 
 #ifdef DEBUG_FRAME_DUMP
 nsresult
 nsRubyBaseContainerFrame::GetFrameName(nsAString& aResult) const
 {
   return MakeFrameName(NS_LITERAL_STRING("RubyBaseContainer"), aResult);
 }
 #endif
+
+/* virtual */ bool 
+nsRubyBaseContainerFrame::IsFrameOfType(uint32_t aFlags) const 
+{
+  return nsContainerFrame::IsFrameOfType(aFlags & 
+         ~(nsIFrame::eLineParticipant));
+}
+
+void nsRubyBaseContainerFrame::AppendTextContainer(nsIFrame* aFrame)
+{
+  nsRubyTextContainerFrame* rtcFrame = do_QueryFrame(aFrame);
+  if (rtcFrame) {
+    mTextContainers.AppendElement(rtcFrame);
+  }
+}
+
+void nsRubyBaseContainerFrame::ClearTextContainers() {
+  mTextContainers.Clear();
+}
+
+/* virtual */ bool
+nsRubyBaseContainerFrame::CanContinueTextRun() const
+{
+  return true;
+}
+
+/* virtual */ void
+nsRubyBaseContainerFrame::Reflow(nsPresContext* aPresContext,
+                                 nsHTMLReflowMetrics& aDesiredSize,
+                                 const nsHTMLReflowState& aReflowState,
+                                 nsReflowStatus& aStatus)
+{
+  DO_GLOBAL_REFLOW_COUNT("nsRubyBaseContainerFrame");
+  DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
+
+  if (!aReflowState.mLineLayout) {
+    NS_ASSERTION(
+      aReflowState.mLineLayout,
+      "No line layout provided to RubyBaseContainerFrame reflow method.");
+    aStatus = NS_FRAME_COMPLETE;
+    return;
+  }
+
+  aStatus = NS_FRAME_COMPLETE;
+  nscoord isize = 0;
+  int baseNum = 0;
+  nscoord leftoverSpace = 0;
+  nscoord spaceApart = 0;
+  WritingMode lineWM = aReflowState.mLineLayout->GetWritingMode();
+  WritingMode frameWM = aReflowState.GetWritingMode();
+  LogicalMargin borderPadding =
+    aReflowState.ComputedLogicalBorderPadding();
+  nscoord baseStart = 0;
+
+  LogicalSize availSize(lineWM, aReflowState.AvailableWidth(),
+                        aReflowState.AvailableHeight());
+
+  // Begin the line layout for each ruby text container in advance.
+  for (uint32_t i = 0; i < mTextContainers.Length(); i++) {
+    nsRubyTextContainerFrame* rtcFrame = mTextContainers.ElementAt(i);
+    nsHTMLReflowState rtcReflowState(aPresContext,
+                                     *aReflowState.parentReflowState,
+                                     rtcFrame, availSize);
+    rtcReflowState.mLineLayout = aReflowState.mLineLayout;
+    // FIXME: Avoid using/needing the rtcReflowState argument
+    rtcFrame->BeginRTCLineLayout(aPresContext, rtcReflowState);
+  }
+
+  for (nsFrameList::Enumerator e(mFrames); !e.AtEnd(); e.Next()) {
+    nsIFrame* rbFrame = e.get();
+    if (rbFrame->GetType() != nsGkAtoms::rubyBaseFrame) {
+      NS_ASSERTION(false, "Unrecognized child type for ruby base container");
+      continue;
+    }
+
+    nsReflowStatus frameReflowStatus;
+    nsHTMLReflowMetrics metrics(aReflowState, aDesiredSize.mFlags);
+
+    // Determine if we need more spacing between bases in the inline direction
+    // depending on the inline size of the corresponding annotations
+    // FIXME: The use of GetPrefISize here and below is easier but not ideal. It
+    // would be better to use metrics from reflow.
+    nscoord prefWidth = rbFrame->GetPrefISize(aReflowState.rendContext);
+    nscoord textWidth = 0;
+
+    for (uint32_t i = 0; i < mTextContainers.Length(); i++) {
+      nsRubyTextFrame* rtFrame = do_QueryFrame(mTextContainers.ElementAt(i)->
+                          PrincipalChildList().FrameAt(baseNum));
+      if (rtFrame) {
+        int newWidth = rtFrame->GetPrefISize(aReflowState.rendContext);
+        if (newWidth > textWidth) {
+          textWidth = newWidth;
+        }
+      }
+    }
+    if (textWidth > prefWidth) {
+      spaceApart = std::max((textWidth - prefWidth) / 2, spaceApart);
+      leftoverSpace = spaceApart;
+    } else {
+      spaceApart = leftoverSpace;
+      leftoverSpace = 0;
+    }
+    if (spaceApart > 0) {
+      aReflowState.mLineLayout->AdvanceICoord(spaceApart);
+    }
+    baseStart = aReflowState.mLineLayout->GetCurrentICoord();
+
+    bool pushedFrame;
+    aReflowState.mLineLayout->ReflowFrame(rbFrame, frameReflowStatus,
+                                          &metrics, pushedFrame);
+    NS_ASSERTION(!pushedFrame, "Ruby line breaking is not yet implemented");
+
+    isize += metrics.ISize(lineWM);
+    rbFrame->SetSize(LogicalSize(lineWM, metrics.ISize(lineWM),
+                                 metrics.BSize(lineWM)));
+    FinishReflowChild(rbFrame, aPresContext, metrics, &aReflowState, 0, 0,
+                      NS_FRAME_NO_MOVE_FRAME | NS_FRAME_NO_MOVE_VIEW);
+
+    // Now reflow the ruby text boxes that correspond to this ruby base box.
+    for (uint32_t i = 0; i < mTextContainers.Length(); i++) {
+      nsRubyTextFrame* rtFrame = do_QueryFrame(mTextContainers.ElementAt(i)->
+                          PrincipalChildList().FrameAt(baseNum));
+      nsRubyTextContainerFrame* rtcFrame = mTextContainers.ElementAt(i);
+      if (rtFrame) {
+        nsHTMLReflowMetrics rtcMetrics(*aReflowState.parentReflowState,
+                                       aDesiredSize.mFlags);
+        nsHTMLReflowState rtcReflowState(aPresContext,
+                                         *aReflowState.parentReflowState,
+                                         rtcFrame, availSize);
+        rtcReflowState.mLineLayout = rtcFrame->GetLineLayout();
+        rtcFrame->ReflowRubyTextFrame(rtFrame, rbFrame, baseStart,
+                                      aPresContext, rtcMetrics,
+                                      rtcReflowState);
+      }
+    }
+    baseNum++;
+  }
+
+  // Reflow ruby annotations which do not have a corresponding ruby base box due
+  // to a ruby base shortage. According to the spec, an empty ruby base is
+  // assumed to exist for each of these annotations.
+  bool continueReflow = true;
+  while (continueReflow) {
+    continueReflow = false;
+    for (uint32_t i = 0; i < mTextContainers.Length(); i++) {
+      nsRubyTextFrame* rtFrame = do_QueryFrame(mTextContainers.ElementAt(i)->
+                          PrincipalChildList().FrameAt(baseNum));
+      nsRubyTextContainerFrame* rtcFrame = mTextContainers.ElementAt(i);
+      if (rtFrame) {
+        continueReflow = true;
+        nsHTMLReflowMetrics rtcMetrics(*aReflowState.parentReflowState,
+                                       aDesiredSize.mFlags);
+        nsHTMLReflowState rtcReflowState(aPresContext,
+                                         *aReflowState.parentReflowState,
+                                         rtcFrame, availSize);
+        rtcReflowState.mLineLayout = rtcFrame->GetLineLayout();
+        rtcFrame->ReflowRubyTextFrame(rtFrame, nullptr, baseStart,
+                                      aPresContext, rtcMetrics,
+                                      rtcReflowState);
+        // Update the inline coord to make space for subsequent ruby annotations
+        // (since there is no corresponding base inline size to use).
+        baseStart += rtcMetrics.ISize(lineWM);
+      }
+    }
+    baseNum++;
+  }
+
+  aDesiredSize.ISize(lineWM) = isize;
+  nsLayoutUtils::SetBSizeFromFontMetrics(this, aDesiredSize, aReflowState,
+                                         borderPadding, lineWM, frameWM);
+}
--- a/layout/generic/nsRubyBaseContainerFrame.h
+++ b/layout/generic/nsRubyBaseContainerFrame.h
@@ -5,16 +5,19 @@
  * http://mozilla.org/MPL/2.0/. */
 
 /* rendering object for CSS "display: ruby-base-container" */
 
 #ifndef nsRubyBaseContainerFrame_h___
 #define nsRubyBaseContainerFrame_h___
 
 #include "nsContainerFrame.h"
+#include "nsRubyTextContainerFrame.h"
+#include "nsRubyBaseFrame.h"
+#include "nsRubyTextFrame.h"
 
 /**
  * Factory function.
  * @return a newly allocated nsRubyBaseContainerFrame (infallible)
  */
 nsContainerFrame* NS_NewRubyBaseContainerFrame(nsIPresShell* aPresShell,
                                                nsStyleContext* aContext);
 
@@ -22,21 +25,37 @@ class nsRubyBaseContainerFrame MOZ_FINAL
 {
 public:
   NS_DECL_FRAMEARENA_HELPERS
   NS_DECL_QUERYFRAME_TARGET(nsRubyBaseContainerFrame)
   NS_DECL_QUERYFRAME
 
   // nsIFrame overrides
   virtual nsIAtom* GetType() const MOZ_OVERRIDE;
+  virtual bool IsFrameOfType(uint32_t aFlags) const MOZ_OVERRIDE;
+  virtual bool CanContinueTextRun() const MOZ_OVERRIDE;
+  virtual void Reflow(nsPresContext* aPresContext,
+                      nsHTMLReflowMetrics& aDesiredSize,
+                      const nsHTMLReflowState& aReflowState,
+                      nsReflowStatus& aStatus) MOZ_OVERRIDE;
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE;
 #endif
 
+  void AppendTextContainer(nsIFrame* aFrame);
+  void ClearTextContainers();
+
 protected:
   friend nsContainerFrame*
     NS_NewRubyBaseContainerFrame(nsIPresShell* aPresShell,
                                  nsStyleContext* aContext);
   nsRubyBaseContainerFrame(nsStyleContext* aContext) : nsContainerFrame(aContext) {}
+  /*
+   * The ruby text containers that belong to the ruby segment defined by
+   * this ruby base container. These text containers are located at the start
+   * of reflow for the ruby frame (parent) and cleared at the end of that
+   * reflow.
+   */
+  nsTArray<nsRubyTextContainerFrame*> mTextContainers;
 };
 
 #endif /* nsRubyBaseContainerFrame_h___ */
--- a/layout/generic/nsRubyBaseFrame.cpp
+++ b/layout/generic/nsRubyBaseFrame.cpp
@@ -2,18 +2,22 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code is subject to the terms of the Mozilla Public License
  * version 2.0 (the "License"). You can obtain a copy of the License at
  * http://mozilla.org/MPL/2.0/. */
 
 /* rendering object for CSS "display: ruby-base" */
 
 #include "nsRubyBaseFrame.h"
+#include "nsLineLayout.h"
 #include "nsPresContext.h"
 #include "nsStyleContext.h"
+#include "WritingModes.h"
+
+using namespace mozilla;
 
 //----------------------------------------------------------------------
 
 // Frame class boilerplate
 // =======================
 
 NS_QUERYFRAME_HEAD(nsRubyBaseFrame)
   NS_QUERYFRAME_ENTRY(nsRubyBaseFrame)
@@ -42,8 +46,109 @@ nsRubyBaseFrame::GetType() const
 
 #ifdef DEBUG_FRAME_DUMP
 nsresult
 nsRubyBaseFrame::GetFrameName(nsAString& aResult) const
 {
   return MakeFrameName(NS_LITERAL_STRING("RubyBase"), aResult);
 }
 #endif
+
+nscoord
+nsRubyBaseFrame::GetMinISize(nsRenderingContext *aRenderingContext)
+{
+  return nsLayoutUtils::MinISizeFromInline(this, aRenderingContext);
+}
+
+nscoord
+nsRubyBaseFrame::GetPrefISize(nsRenderingContext *aRenderingContext)
+{
+  return nsLayoutUtils::PrefISizeFromInline(this, aRenderingContext);
+}
+
+/* virtual */ void
+nsRubyBaseFrame::AddInlineMinISize(nsRenderingContext *aRenderingContext,
+                                   nsIFrame::InlineMinISizeData *aData)
+{
+  for (nsFrameList::Enumerator e(PrincipalChildList()); !e.AtEnd(); e.Next()) {
+    e.get()->AddInlineMinISize(aRenderingContext, aData);
+  }
+}
+
+/* virtual */ void
+nsRubyBaseFrame::AddInlinePrefISize(nsRenderingContext *aRenderingContext,
+                                    nsIFrame::InlinePrefISizeData *aData)
+{
+  for (nsFrameList::Enumerator e(PrincipalChildList()); !e.AtEnd(); e.Next()) {
+    e.get()->AddInlinePrefISize(aRenderingContext, aData);
+  }
+}
+
+/* virtual */ bool 
+nsRubyBaseFrame::IsFrameOfType(uint32_t aFlags) const 
+{
+  return nsContainerFrame::IsFrameOfType(aFlags & 
+         ~(nsIFrame::eLineParticipant));
+}
+
+/* virtual */ nscoord
+nsRubyBaseFrame::GetLogicalBaseline(WritingMode aWritingMode) const
+{
+  return mBaseline;
+}
+
+/* virtual */ bool
+nsRubyBaseFrame::CanContinueTextRun() const
+{
+  return true;
+}
+
+/* virtual */ void
+nsRubyBaseFrame::Reflow(nsPresContext* aPresContext,
+                        nsHTMLReflowMetrics& aDesiredSize,
+                        const nsHTMLReflowState& aReflowState,
+                        nsReflowStatus& aStatus)
+{
+  DO_GLOBAL_REFLOW_COUNT("nsRubyBaseFrame");
+  DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
+  
+  if (!aReflowState.mLineLayout) {
+    NS_ASSERTION(aReflowState.mLineLayout,
+                 "No line layout provided to RubyBaseFrame reflow method.");
+    aStatus = NS_FRAME_COMPLETE;
+    return;
+  }
+
+  WritingMode lineWM = aReflowState.mLineLayout->GetWritingMode();
+  WritingMode frameWM = aReflowState.GetWritingMode();
+  aStatus = NS_FRAME_COMPLETE;
+  LogicalSize availSize(lineWM, aReflowState.AvailableWidth(),
+                        aReflowState.AvailableHeight());
+  LogicalMargin borderPadding = aReflowState.ComputedLogicalBorderPadding();
+
+  // Begin the span for the ruby base frame
+  nscoord availableISize = aReflowState.AvailableISize();
+  NS_ASSERTION(availableISize != NS_UNCONSTRAINEDSIZE,
+               "should no longer use available widths");
+  // Subtract off inline axis border+padding from availableISize
+  availableISize -= borderPadding.IStartEnd(frameWM);
+  aReflowState.mLineLayout->BeginSpan(this, &aReflowState,
+                                      borderPadding.IStart(frameWM),
+                                      availableISize, &mBaseline);
+
+  for (nsFrameList::Enumerator e(mFrames); !e.AtEnd(); e.Next()) {
+    nsReflowStatus frameReflowStatus;
+    nsHTMLReflowMetrics metrics(aReflowState, aDesiredSize.mFlags);
+
+    bool pushedFrame;
+    aReflowState.mLineLayout->ReflowFrame(e.get(), frameReflowStatus,
+                                          &metrics, pushedFrame);
+    NS_ASSERTION(!pushedFrame,
+                 "Ruby line breaking is not yet implemented");
+
+    e.get()->SetSize(LogicalSize(lineWM, metrics.ISize(lineWM),
+                                 metrics.BSize(lineWM)));
+  }
+
+  aDesiredSize.ISize(lineWM) = aReflowState.mLineLayout->EndSpan(this);
+  nsLayoutUtils::SetBSizeFromFontMetrics(this, aDesiredSize, aReflowState,
+                                         borderPadding, lineWM, frameWM);
+}
--- a/layout/generic/nsRubyBaseFrame.h
+++ b/layout/generic/nsRubyBaseFrame.h
@@ -22,20 +22,35 @@ class nsRubyBaseFrame MOZ_FINAL : public
 {
 public:
   NS_DECL_FRAMEARENA_HELPERS
   NS_DECL_QUERYFRAME_TARGET(nsRubyBaseFrame)
   NS_DECL_QUERYFRAME
 
   // nsIFrame overrides
   virtual nsIAtom* GetType() const MOZ_OVERRIDE;
+  virtual void AddInlineMinISize(nsRenderingContext *aRenderingContext,
+                                 InlineMinISizeData *aData) MOZ_OVERRIDE;
+  virtual void AddInlinePrefISize(nsRenderingContext *aRenderingContext,
+                                  InlinePrefISizeData *aData) MOZ_OVERRIDE;
+  virtual nscoord GetMinISize(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE;
+  virtual nscoord GetPrefISize(nsRenderingContext *aRenderingContext);
+  virtual void Reflow(nsPresContext* aPresContext,
+                      nsHTMLReflowMetrics& aDesiredSize,
+                      const nsHTMLReflowState& aReflowState,
+                      nsReflowStatus& aStatus) MOZ_OVERRIDE;
+  virtual bool IsFrameOfType(uint32_t aFlags) const MOZ_OVERRIDE;
+  virtual nscoord GetLogicalBaseline(mozilla::WritingMode aWritingMode)
+    const MOZ_OVERRIDE;
+  virtual bool CanContinueTextRun() const MOZ_OVERRIDE;
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE;
 #endif
 
 protected:
   friend nsContainerFrame* NS_NewRubyBaseFrame(nsIPresShell* aPresShell,
                                                nsStyleContext* aContext);
   nsRubyBaseFrame(nsStyleContext* aContext) : nsContainerFrame(aContext) {}
+  nscoord mBaseline;
 };
 
 #endif /* nsRubyBaseFrame_h___ */
--- a/layout/generic/nsRubyFrame.cpp
+++ b/layout/generic/nsRubyFrame.cpp
@@ -1,18 +1,24 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code is subject to the terms of the Mozilla Public License
  * version 2.0 (the "License"). You can obtain a copy of the License at
  * http://mozilla.org/MPL/2.0/. */
 
 /* rendering object for CSS "display: ruby" */
 #include "nsRubyFrame.h"
+#include "nsLineLayout.h"
 #include "nsPresContext.h"
 #include "nsStyleContext.h"
+#include "WritingModes.h"
+#include "nsRubyBaseContainerFrame.h"
+#include "nsRubyTextContainerFrame.h"
+
+using namespace mozilla;
 
 //----------------------------------------------------------------------
 
 // Frame class boilerplate
 // =======================
 
 NS_QUERYFRAME_HEAD(nsRubyFrame)
   NS_QUERYFRAME_ENTRY(nsRubyFrame)
@@ -22,34 +28,263 @@ NS_IMPL_FRAMEARENA_HELPERS(nsRubyFrame)
 
 nsContainerFrame*
 NS_NewRubyFrame(nsIPresShell* aPresShell,
                 nsStyleContext* aContext)
 {
   return new (aPresShell) nsRubyFrame(aContext);
 }
 
-
 //----------------------------------------------------------------------
 
 // nsRubyFrame Method Implementations
 // ==================================
 
 nsIAtom*
 nsRubyFrame::GetType() const
 {
   return nsGkAtoms::rubyFrame;
 }
 
-bool
+/* virtual */ bool
 nsRubyFrame::IsFrameOfType(uint32_t aFlags) const
 {
   return nsContainerFrame::IsFrameOfType(aFlags &
-    ~(nsIFrame::eBidiInlineContainer | nsIFrame::eLineParticipant));
+    ~(nsIFrame::eLineParticipant));
 }
 
 #ifdef DEBUG_FRAME_DUMP
 nsresult
 nsRubyFrame::GetFrameName(nsAString& aResult) const
 {
   return MakeFrameName(NS_LITERAL_STRING("Ruby"), aResult);
 }
 #endif
+
+void
+nsRubyFrame::CalculateColSizes(nsRenderingContext* aRenderingContext,
+                               nsTArray<nscoord>& aColSizes)
+{
+  nsFrameList::Enumerator e(this->PrincipalChildList());
+  uint32_t annotationNum = 0;
+  int segmentNum = -1;
+
+  nsTArray<int> segmentBaseCounts;
+
+  for(; !e.AtEnd(); e.Next()) {
+    nsIFrame* childFrame = e.get();
+    if (childFrame->GetType() == nsGkAtoms::rubyBaseContainerFrame) {
+      segmentNum++;
+      segmentBaseCounts.AppendElement(0);
+      nsFrameList::Enumerator bases(childFrame->PrincipalChildList());
+      for(; !bases.AtEnd(); bases.Next()) {
+        aColSizes.AppendElement(bases.get()->GetPrefISize(aRenderingContext));
+        segmentBaseCounts.ElementAt(segmentNum)++;
+      }
+    } else if (childFrame->GetType() == nsGkAtoms::rubyTextContainerFrame) {
+      if (segmentNum == -1) {
+        // No rbc exists for first segment, so act as if there is one
+        segmentNum++;
+        segmentBaseCounts.AppendElement(1);
+        aColSizes.AppendElement(0);
+      }
+      nsFrameList::Enumerator annotations(childFrame->PrincipalChildList());
+      uint32_t baseCount = segmentBaseCounts.ElementAt(segmentNum);
+      for(; !annotations.AtEnd(); annotations.Next()) {
+        nsIFrame* annotationFrame = annotations.get();
+        if (annotationNum > baseCount) {
+          aColSizes.AppendElement(annotationFrame->
+            GetPrefISize(aRenderingContext));
+          baseCount++;
+          segmentBaseCounts.ElementAt(segmentNum) = baseCount;
+          annotationNum++;
+        } else if (annotationNum < baseCount - 1) {
+          //there are fewer annotations than bases, so the last annotation is
+          //associated with (spans) the remaining bases. This means these
+          //columns can't be broken up, so gather their entire ISize in one
+          //entry of aColSizes and clear the other entries.
+          int baseSum = 0;
+          for (uint32_t i = annotationNum; i < annotationNum + baseCount; i++) {
+            baseSum += aColSizes.ElementAt(i);
+            if (i > annotationNum) {
+              aColSizes.ElementAt(i) = 0;
+            }
+          }
+          aColSizes.ElementAt(annotationNum) =
+            std::max(baseSum, annotationFrame->GetPrefISize(aRenderingContext));
+          annotationNum = baseCount;
+        } else {
+          aColSizes.ElementAt(annotationNum) =
+            std::max(aColSizes.ElementAt(annotationNum),
+                     annotationFrame->GetPrefISize(aRenderingContext));
+          annotationNum++;
+        }
+      }
+    } else {
+      NS_ASSERTION(false, "Unrecognized child type for ruby frame.");
+    }
+  }
+}
+
+/* virtual */ void
+nsRubyFrame::AddInlineMinISize(nsRenderingContext *aRenderingContext,
+                               nsIFrame::InlineMinISizeData *aData)
+{
+  //FIXME: This needs to handle the cases where it's possible for a ruby base to
+  //break, as well as forced breaks.
+  nsTArray<int> colSizes;
+  CalculateColSizes(aRenderingContext, colSizes);
+
+  nscoord max = 0;
+  for (uint32_t i = 0; i < colSizes.Length(); i++) {
+    if (colSizes.ElementAt(i) > max) {
+      max = colSizes.ElementAt(i);
+    }
+  }
+
+  aData->currentLine += max;
+}
+
+/* virtual */ void
+nsRubyFrame::AddInlinePrefISize(nsRenderingContext *aRenderingContext,
+                                nsIFrame::InlinePrefISizeData *aData)
+{
+  nsTArray<int> colSizes;
+  CalculateColSizes(aRenderingContext, colSizes);
+
+  nscoord sum = 0;
+  for (uint32_t i = 0; i < colSizes.Length(); i++) {
+    sum += colSizes.ElementAt(i);
+  }
+
+  aData->currentLine += sum;
+}
+
+/* virtual */ nscoord
+nsRubyFrame::GetLogicalBaseline(WritingMode aWritingMode) const
+{
+  return mBaseline;
+}
+
+/* virtual */ bool
+nsRubyFrame::CanContinueTextRun() const
+{
+  return true;
+}
+
+/* virtual */ void
+nsRubyFrame::Reflow(nsPresContext* aPresContext,
+                    nsHTMLReflowMetrics& aDesiredSize,
+                    const nsHTMLReflowState& aReflowState,
+                    nsReflowStatus& aStatus)
+{
+  DO_GLOBAL_REFLOW_COUNT("nsRubyFrame");
+  DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
+  
+  if (!aReflowState.mLineLayout) {
+    NS_ASSERTION(aReflowState.mLineLayout,
+                 "No line layout provided to RubyFrame reflow method.");
+    aStatus = NS_FRAME_COMPLETE;
+    return;
+  }
+
+  // Begin the span for the ruby frame
+  WritingMode frameWM = aReflowState.GetWritingMode();
+  WritingMode lineWM = aReflowState.mLineLayout->GetWritingMode();
+  LogicalMargin borderPadding = aReflowState.ComputedLogicalBorderPadding();
+  nscoord availableISize = aReflowState.AvailableISize();
+  NS_ASSERTION(availableISize != NS_UNCONSTRAINEDSIZE,
+               "should no longer use available widths");
+  // Subtract off inline axis border+padding from availableISize
+  availableISize -= borderPadding.IStartEnd(frameWM);
+  aReflowState.mLineLayout->BeginSpan(this, &aReflowState,
+                                      borderPadding.IStart(frameWM),
+                                      availableISize, &mBaseline);
+
+  // FIXME: line breaking / continuations not yet implemented
+  aStatus = NS_FRAME_COMPLETE;
+  LogicalSize availSize(lineWM, aReflowState.AvailableISize(),
+                        aReflowState.AvailableBSize());
+  // The ruby base container for the current segment
+  nsRubyBaseContainerFrame* segmentRBC = nullptr;
+  nscoord annotationBSize = 0;
+  for (nsFrameList::Enumerator e(mFrames); !e.AtEnd(); e.Next()) {
+    nsIFrame* childFrame = e.get();
+    if (e.get()->GetType() == nsGkAtoms::rubyBaseContainerFrame) {
+      if (segmentRBC) {
+        annotationBSize = 0;
+      }
+
+      // Figure out what all the text containers are for this segment (necessary
+      // for reflow calculations)
+      segmentRBC = do_QueryFrame(childFrame);
+      nsFrameList::Enumerator segment(e);
+      segment.Next();
+      while (!segment.AtEnd() && (segment.get()->GetType() !=
+             nsGkAtoms::rubyBaseContainerFrame)) {
+        if (segment.get()->GetType() == nsGkAtoms::rubyTextContainerFrame) {
+          segmentRBC->AppendTextContainer(segment.get());
+        }
+        segment.Next();
+      }
+
+      nsReflowStatus frameReflowStatus;
+      nsHTMLReflowMetrics metrics(aReflowState, aDesiredSize.mFlags);
+      nsHTMLReflowState childReflowState(aPresContext, aReflowState,
+                                         childFrame, availSize);
+      childReflowState.mLineLayout = aReflowState.mLineLayout;
+      childFrame->Reflow(aPresContext, metrics, childReflowState,
+                         frameReflowStatus);
+      NS_ASSERTION(frameReflowStatus == NS_FRAME_COMPLETE,
+                 "Ruby line breaking is not yet implemented");
+      childFrame->SetSize(LogicalSize(lineWM, metrics.ISize(lineWM),
+                                      metrics.BSize(lineWM)));
+      FinishReflowChild(childFrame, aPresContext, metrics, &childReflowState, 0,
+                        0, NS_FRAME_NO_MOVE_FRAME | NS_FRAME_NO_MOVE_VIEW);
+
+    } else if (childFrame->GetType() == nsGkAtoms::rubyTextContainerFrame) {
+      nsReflowStatus frameReflowStatus;
+      nsHTMLReflowMetrics metrics(aReflowState, aDesiredSize.mFlags);
+      nsHTMLReflowState childReflowState(aPresContext, aReflowState, childFrame,
+                                         availSize);
+      childReflowState.mLineLayout = aReflowState.mLineLayout;
+      childFrame->Reflow(aPresContext, metrics, childReflowState,
+                      frameReflowStatus);
+      NS_ASSERTION(frameReflowStatus == NS_FRAME_COMPLETE,
+                 "Ruby line breaking is not yet implemented");
+      annotationBSize += metrics.BSize(lineWM);
+      childFrame->SetSize(LogicalSize(lineWM, metrics.ISize(lineWM),
+                                      metrics.BSize(lineWM)));
+      // FIXME: This is a temporary calculation for finding the block coordinate
+      // of the ruby text container. A better one replace it once it's been
+      // spec'ed.
+      nscoord baseContainerBCoord; 
+      if (segmentRBC) {
+        // Find the starting block coordinate of the ruby base container for
+        // this segment. For now, the ruby text container will be placed so that
+        // its bottom edge touches this coordinate.
+        baseContainerBCoord = segmentRBC->
+          GetLogicalPosition(this->GetParent()->GetLogicalSize().ISize(lineWM)).
+          B(lineWM);
+      } else {
+        baseContainerBCoord = 0;
+      }
+      FinishReflowChild(childFrame, aPresContext, metrics, &childReflowState, 0,
+                        baseContainerBCoord - metrics.BSize(lineWM), 0);
+    } else {
+      NS_NOTREACHED(
+        "Unrecognized child type for ruby frame will not be reflowed."); 
+    }
+  }
+
+  // Null the pointers between child frames.
+  for (nsFrameList::Enumerator children(mFrames); !children.AtEnd();
+       children.Next()) {
+    nsRubyBaseContainerFrame* rbcFrame = do_QueryFrame(children.get());
+    if (rbcFrame) {
+      rbcFrame->ClearTextContainers();
+    }
+  }
+
+  aDesiredSize.ISize(lineWM) = aReflowState.mLineLayout->EndSpan(this);
+  nsLayoutUtils::SetBSizeFromFontMetrics(this, aDesiredSize, aReflowState,
+                                         borderPadding, lineWM, frameWM);
+}
--- a/layout/generic/nsRubyFrame.h
+++ b/layout/generic/nsRubyFrame.h
@@ -23,20 +23,34 @@ class nsRubyFrame MOZ_FINAL : public nsC
 public:
   NS_DECL_FRAMEARENA_HELPERS
   NS_DECL_QUERYFRAME_TARGET(nsRubyFrame)
   NS_DECL_QUERYFRAME
 
   // nsIFrame overrides
   virtual nsIAtom* GetType() const MOZ_OVERRIDE;
   virtual bool IsFrameOfType(uint32_t aFlags) const MOZ_OVERRIDE;
+  virtual void AddInlineMinISize(nsRenderingContext *aRenderingContext,
+                                 InlineMinISizeData *aData) MOZ_OVERRIDE;
+  virtual void AddInlinePrefISize(nsRenderingContext *aRenderingContext,
+                                  InlinePrefISizeData *aData) MOZ_OVERRIDE;
+  virtual void Reflow(nsPresContext* aPresContext,
+                      nsHTMLReflowMetrics& aDesiredSize,
+                      const nsHTMLReflowState& aReflowState,
+                      nsReflowStatus& aStatus) MOZ_OVERRIDE;
+  virtual nscoord GetLogicalBaseline(mozilla::WritingMode aWritingMode)
+    const MOZ_OVERRIDE;
+  virtual bool CanContinueTextRun() const MOZ_OVERRIDE;
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE;
 #endif
 
 protected:
   friend nsContainerFrame* NS_NewRubyFrame(nsIPresShell* aPresShell,
                                            nsStyleContext* aContext);
   nsRubyFrame(nsStyleContext* aContext) : nsContainerFrame(aContext) {}
+  void CalculateColSizes(nsRenderingContext* aRenderingContext,
+                         nsTArray<nscoord>& aColSizes);
+  nscoord mBaseline;
 };
 
 #endif /* nsRubyFrame_h___ */
--- a/layout/generic/nsRubyTextContainerFrame.cpp
+++ b/layout/generic/nsRubyTextContainerFrame.cpp
@@ -4,16 +4,18 @@
  * version 2.0 (the "License"). You can obtain a copy of the License at
  * http://mozilla.org/MPL/2.0/. */
 
 /* rendering object for CSS "display: ruby-text-container" */
 
 #include "nsRubyTextContainerFrame.h"
 #include "nsPresContext.h"
 #include "nsStyleContext.h"
+#include "WritingModes.h"
+#include "mozilla/UniquePtr.h"
 
 //----------------------------------------------------------------------
 
 // Frame class boilerplate
 // =======================
 
 NS_QUERYFRAME_HEAD(nsRubyTextContainerFrame)
   NS_QUERYFRAME_ENTRY(nsRubyTextContainerFrame)
@@ -42,8 +44,136 @@ nsRubyTextContainerFrame::GetType() cons
 
 #ifdef DEBUG_FRAME_DUMP
 nsresult
 nsRubyTextContainerFrame::GetFrameName(nsAString& aResult) const
 {
   return MakeFrameName(NS_LITERAL_STRING("RubyTextContainer"), aResult);
 }
 #endif
+
+void
+nsRubyTextContainerFrame::BeginRTCLineLayout(nsPresContext* aPresContext,
+                                             const nsHTMLReflowState& aReflowState)
+{
+  // Construct block reflow state and line layout
+  nscoord consumedBSize = GetConsumedBSize();
+
+  ClearLineCursor();
+
+  mISize = 0;
+
+  nsBlockReflowState state(aReflowState, aPresContext, this, true, true,
+                           false, consumedBSize);
+
+  NS_ASSERTION(!mLines.empty(),
+    "There should be at least one line in the ruby text container");
+  line_iterator firstLine = begin_lines();
+  mLineLayout = mozilla::MakeUnique<nsLineLayout>(
+                           state.mPresContext,
+                           state.mReflowState.mFloatManager,
+                           &state.mReflowState, &firstLine);
+  mLineLayout->Init(&state, state.mMinLineHeight, state.mLineNumber);
+
+  mozilla::WritingMode lineWM = aReflowState.mLineLayout->GetWritingMode();
+  mozilla::LogicalRect lineRect(state.mContentArea);
+  nscoord iStart = lineRect.IStart(lineWM);
+  nscoord availISize = lineRect.ISize(lineWM);
+  nscoord availBSize = NS_UNCONSTRAINEDSIZE;
+
+  mLineLayout->BeginLineReflow(iStart, state.mBCoord,
+                              availISize, availBSize,
+                              false,
+                              false,
+                              lineWM, state.mContainerWidth);
+}
+
+void
+nsRubyTextContainerFrame::ReflowRubyTextFrame(
+                            nsRubyTextFrame* rtFrame,
+                            nsIFrame* rbFrame,
+                            nscoord baseStart,
+                            nsPresContext* aPresContext,
+                            nsHTMLReflowMetrics& aDesiredSize,
+                            const nsHTMLReflowState& aReflowState)
+{
+  nsReflowStatus frameReflowStatus;
+  nsHTMLReflowMetrics metrics(aReflowState, aDesiredSize.mFlags);
+  mozilla::WritingMode lineWM = mLineLayout->GetWritingMode();
+  mozilla::LogicalSize availSize(lineWM, aReflowState.AvailableWidth(),
+                   aReflowState.AvailableHeight());
+  nsHTMLReflowState childReflowState(aPresContext, aReflowState, rtFrame, availSize);
+
+  // Determine the inline coordinate for the text frame by centering over
+  // the corresponding base frame
+  int baseWidth;
+  if (rbFrame) {
+    baseWidth = rbFrame->ISize();
+
+    // If this is the last ruby annotation, it gets paired with ALL remaining
+    // ruby bases
+    if (!rtFrame->GetNextSibling()) {
+      rbFrame = rbFrame->GetNextSibling();
+      while (rbFrame) {
+        baseWidth += rbFrame->ISize();
+        rbFrame = rbFrame->GetNextSibling();
+      }
+    }
+  } else {
+    baseWidth = 0;
+  }
+  
+  int baseCenter = baseStart + baseWidth / 2;
+  // FIXME: Find a way to avoid using GetPrefISize here, potentially by moving
+  // the frame after it has reflowed.
+  nscoord ICoord = baseCenter - rtFrame->GetPrefISize(aReflowState.rendContext) / 2;
+  if (ICoord > mLineLayout->GetCurrentICoord()) {
+    mLineLayout->AdvanceICoord(ICoord - mLineLayout->GetCurrentICoord());
+  } 
+
+  bool pushedFrame;
+  mLineLayout->ReflowFrame(rtFrame, frameReflowStatus,
+                           &metrics, pushedFrame);
+
+  NS_ASSERTION(!pushedFrame, "Ruby line breaking is not yet implemented");
+
+  mISize += metrics.ISize(lineWM);
+  rtFrame->SetSize(nsSize(metrics.ISize(lineWM), metrics.BSize(lineWM)));
+  FinishReflowChild(rtFrame, aPresContext, metrics, &childReflowState, 0, 0,
+                    NS_FRAME_NO_MOVE_FRAME | NS_FRAME_NO_MOVE_VIEW);
+} 
+
+/* virtual */ void
+nsRubyTextContainerFrame::Reflow(nsPresContext* aPresContext,
+                                 nsHTMLReflowMetrics& aDesiredSize,
+                                 const nsHTMLReflowState& aReflowState,
+                                 nsReflowStatus& aStatus)
+{
+  DO_GLOBAL_REFLOW_COUNT("nsRubyTextContainerFrame");
+  DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
+
+  // All rt children have already been reflowed. All we need to do is clean up
+  // the line layout.
+
+  aStatus = NS_FRAME_COMPLETE;
+  mozilla::WritingMode lineWM = aReflowState.mLineLayout->GetWritingMode();
+  mozilla::WritingMode frameWM = aReflowState.GetWritingMode();
+  mozilla::LogicalMargin borderPadding =
+    aReflowState.ComputedLogicalBorderPadding();
+
+  aDesiredSize.ISize(lineWM) = mISize;
+  nsLayoutUtils::SetBSizeFromFontMetrics(this, aDesiredSize, aReflowState,
+                                         borderPadding, lineWM, frameWM);
+
+  nscoord bsize = aDesiredSize.BSize(lineWM);
+  if (!mLines.empty()) {
+    // Okay to use BlockStartAscent because it has just been correctly set by
+    // nsLayoutUtils::SetBSizeFromFontMetrics.
+    mLines.begin()->SetLogicalAscent(aDesiredSize.BlockStartAscent());
+    mLines.begin()->SetBounds(aReflowState.GetWritingMode(), 0, 0, mISize,
+                              bsize, mISize);
+  }
+
+  if (mLineLayout) {
+    mLineLayout->EndLineReflow();
+    mLineLayout = nullptr;
+  }
+}
--- a/layout/generic/nsRubyTextContainerFrame.h
+++ b/layout/generic/nsRubyTextContainerFrame.h
@@ -5,16 +5,19 @@
  * http://mozilla.org/MPL/2.0/. */
 
 /* rendering object for CSS "display: ruby-text-container" */
 
 #ifndef nsRubyTextContainerFrame_h___
 #define nsRubyTextContainerFrame_h___
 
 #include "nsBlockFrame.h"
+#include "nsRubyBaseFrame.h"
+#include "nsRubyTextFrame.h"
+#include "nsLineLayout.h"
 
 /**
  * Factory function.
  * @return a newly allocated nsRubyTextContainerFrame (infallible)
  */
 nsContainerFrame* NS_NewRubyTextContainerFrame(nsIPresShell* aPresShell,
                                                nsStyleContext* aContext);
 
@@ -25,21 +28,41 @@ class nsRubyTextContainerFrame MOZ_FINAL
 {
 public:
   NS_DECL_FRAMEARENA_HELPERS
   NS_DECL_QUERYFRAME_TARGET(nsRubyTextContainerFrame)
   NS_DECL_QUERYFRAME
 
   // nsIFrame overrides
   virtual nsIAtom* GetType() const MOZ_OVERRIDE;
+  virtual void Reflow(nsPresContext* aPresContext,
+                      nsHTMLReflowMetrics& aDesiredSize,
+                      const nsHTMLReflowState& aReflowState,
+                      nsReflowStatus& aStatus) MOZ_OVERRIDE;
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE;
 #endif
 
+  void ReflowRubyTextFrame(nsRubyTextFrame* rtFrame, nsIFrame* rbFrame,
+                           nscoord baseStart, nsPresContext* aPresContext,
+                           nsHTMLReflowMetrics& aDesiredSize,
+                           const nsHTMLReflowState& aReflowState);
+  void BeginRTCLineLayout(nsPresContext* aPresContext,
+                          const nsHTMLReflowState& aReflowState);
+  nsLineLayout* GetLineLayout() { return mLineLayout.get(); };
+
 protected:
   friend nsContainerFrame*
     NS_NewRubyTextContainerFrame(nsIPresShell* aPresShell,
                                  nsStyleContext* aContext);
   nsRubyTextContainerFrame(nsStyleContext* aContext) : nsBlockFrame(aContext) {}
+  // This pointer is active only during reflow of the ruby structure. It gets
+  // created when the corresponding ruby base container is reflowed, and it is
+  // destroyed when the ruby text container itself is reflowed.
+  mozilla::UniquePtr<nsLineLayout> mLineLayout;
+  // The intended dimensions of the ruby text container. These are modified
+  // whenever a ruby text box is reflowed and used when the ruby text container
+  // is reflowed.
+  nscoord mISize;
 };
 
 #endif /* nsRubyTextContainerFrame_h___ */
--- a/layout/generic/nsRubyTextFrame.cpp
+++ b/layout/generic/nsRubyTextFrame.cpp
@@ -4,16 +4,20 @@
  * version 2.0 (the "License"). You can obtain a copy of the License at
  * http://mozilla.org/MPL/2.0/. */
 
 /* rendering object for CSS "display: ruby-text" */
 
 #include "nsRubyTextFrame.h"
 #include "nsPresContext.h"
 #include "nsStyleContext.h"
+#include "WritingModes.h"
+#include "nsLineLayout.h"
+
+using namespace mozilla;
 
 //----------------------------------------------------------------------
 
 // Frame class boilerplate
 // =======================
 
 NS_QUERYFRAME_HEAD(nsRubyTextFrame)
   NS_QUERYFRAME_ENTRY(nsRubyTextFrame)
@@ -42,8 +46,103 @@ nsRubyTextFrame::GetType() const
 
 #ifdef DEBUG_FRAME_DUMP
 nsresult
 nsRubyTextFrame::GetFrameName(nsAString& aResult) const
 {
   return MakeFrameName(NS_LITERAL_STRING("RubyText"), aResult);
 }
 #endif
+
+/* virtual */ bool 
+nsRubyTextFrame::IsFrameOfType(uint32_t aFlags) const 
+{
+  return nsContainerFrame::IsFrameOfType(aFlags & 
+         ~(nsIFrame::eLineParticipant));
+}
+
+/* virtual */ nscoord
+nsRubyTextFrame::GetMinISize(nsRenderingContext *aRenderingContext)
+{
+  return nsLayoutUtils::MinISizeFromInline(this, aRenderingContext);
+}
+
+/* virtual */ nscoord
+nsRubyTextFrame::GetPrefISize(nsRenderingContext *aRenderingContext)
+{
+  return nsLayoutUtils::PrefISizeFromInline(this, aRenderingContext);
+}
+
+/* virtual */ void
+nsRubyTextFrame::AddInlineMinISize(nsRenderingContext *aRenderingContext,
+                                   nsIFrame::InlineMinISizeData *aData)
+{
+  for (nsFrameList::Enumerator e(PrincipalChildList()); !e.AtEnd(); e.Next()) {
+    e.get()->AddInlineMinISize(aRenderingContext, aData);
+  }
+}
+
+/* virtual */ void
+nsRubyTextFrame::AddInlinePrefISize(nsRenderingContext *aRenderingContext,
+                                    nsIFrame::InlinePrefISizeData *aData)
+{
+  for (nsFrameList::Enumerator e(PrincipalChildList()); !e.AtEnd(); e.Next()) {
+    e.get()->AddInlinePrefISize(aRenderingContext, aData);
+  }
+}
+
+/* virtual */ nscoord
+nsRubyTextFrame::GetLogicalBaseline(WritingMode aWritingMode) const
+{
+  return mBaseline;
+}
+
+/* virtual */ void
+nsRubyTextFrame::Reflow(nsPresContext* aPresContext,
+                        nsHTMLReflowMetrics& aDesiredSize,
+                        const nsHTMLReflowState& aReflowState,
+                        nsReflowStatus& aStatus)
+{
+  DO_GLOBAL_REFLOW_COUNT("nsRubyBaseFrame");
+  DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
+  
+  if (!aReflowState.mLineLayout) {
+    NS_ASSERTION(aReflowState.mLineLayout,
+                 "No line layout provided to RubyTextFrame reflow method.");
+    aStatus = NS_FRAME_COMPLETE;
+    return;
+  }
+
+  WritingMode lineWM = aReflowState.mLineLayout->GetWritingMode();
+  WritingMode frameWM = aReflowState.GetWritingMode();
+  LogicalMargin borderPadding = aReflowState.ComputedLogicalBorderPadding();
+  aStatus = NS_FRAME_COMPLETE;
+  LogicalSize availSize(lineWM, aReflowState.AvailableWidth(),
+                        aReflowState.AvailableHeight());
+
+  // Begin the span for the ruby text frame
+  nscoord availableISize = aReflowState.AvailableISize();
+  NS_ASSERTION(availableISize != NS_UNCONSTRAINEDSIZE,
+               "should no longer use available widths");
+  // Subtract off inline axis border+padding from availableISize
+  availableISize -= borderPadding.IStartEnd(frameWM);
+  aReflowState.mLineLayout->BeginSpan(this, &aReflowState,
+                                      borderPadding.IStart(frameWM),
+                                      availableISize, &mBaseline);
+
+  for (nsFrameList::Enumerator e(mFrames); !e.AtEnd(); e.Next()) {
+    nsReflowStatus frameReflowStatus;
+    nsHTMLReflowMetrics metrics(aReflowState, aDesiredSize.mFlags);
+
+    bool pushedFrame;
+    aReflowState.mLineLayout->ReflowFrame(e.get(), frameReflowStatus,
+                                          &metrics, pushedFrame);
+    NS_ASSERTION(!pushedFrame,
+                 "Ruby line breaking is not yet implemented");
+    e.get()->SetSize(LogicalSize(lineWM, metrics.ISize(lineWM),
+                                 metrics.BSize(lineWM)));
+  }
+
+  aDesiredSize.ISize(lineWM) = aReflowState.mLineLayout->EndSpan(this);
+  nsLayoutUtils::SetBSizeFromFontMetrics(this, aDesiredSize, aReflowState,
+                                         borderPadding, lineWM, frameWM);
+
+}
--- a/layout/generic/nsRubyTextFrame.h
+++ b/layout/generic/nsRubyTextFrame.h
@@ -22,20 +22,34 @@ class nsRubyTextFrame MOZ_FINAL : public
 {
 public:
   NS_DECL_FRAMEARENA_HELPERS
   NS_DECL_QUERYFRAME_TARGET(nsRubyTextFrame)
   NS_DECL_QUERYFRAME
 
   // nsIFrame overrides
   virtual nsIAtom* GetType() const MOZ_OVERRIDE;
+  virtual void Reflow(nsPresContext* aPresContext,
+                      nsHTMLReflowMetrics& aDesiredSize,
+                      const nsHTMLReflowState& aReflowState,
+                      nsReflowStatus& aStatus) MOZ_OVERRIDE;
+  virtual bool IsFrameOfType(uint32_t aFlags) const MOZ_OVERRIDE;
+  virtual void AddInlineMinISize(nsRenderingContext *aRenderingContext,
+                                 InlineMinISizeData *aData) MOZ_OVERRIDE;
+  virtual void AddInlinePrefISize(nsRenderingContext *aRenderingContext,
+                                  InlinePrefISizeData *aData) MOZ_OVERRIDE;
+  virtual nscoord GetMinISize(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE;
+  virtual nscoord GetPrefISize(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE;
+  virtual nscoord GetLogicalBaseline(mozilla::WritingMode aWritingMode)
+    const MOZ_OVERRIDE;
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE;
 #endif
 
 protected:
   friend nsContainerFrame* NS_NewRubyTextFrame(nsIPresShell* aPresShell,
                                                nsStyleContext* aContext);
   nsRubyTextFrame(nsStyleContext* aContext) : nsContainerFrame(aContext) {}
+  nscoord mBaseline;
 };
 
 #endif /* nsRubyTextFrame_h___ */
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -1021,17 +1021,18 @@ private:
   nsTextFrame::TextRunType      mWhichTextRun;
   uint8_t                       mNextRunContextInfo;
   uint8_t                       mCurrentRunContextInfo;
 };
 
 static nsIFrame*
 FindLineContainer(nsIFrame* aFrame)
 {
-  while (aFrame && aFrame->CanContinueTextRun()) {
+  while (aFrame && (aFrame->IsFrameOfType(nsIFrame::eLineParticipant) ||
+                    aFrame->CanContinueTextRun())) {
     aFrame = aFrame->GetParent();
   }
   return aFrame;
 }
 
 static bool
 IsLineBreakingWhiteSpace(char16_t aChar)
 {
@@ -1126,16 +1127,26 @@ CanTextCrossFrameBoundary(nsIFrame* aFra
       result.mFrameToScan = aFrame->GetFirstPrincipalChild();
       result.mOverflowFrameToScan =
         aFrame->GetFirstChild(nsIFrame::kOverflowList);
       NS_WARN_IF_FALSE(!result.mOverflowFrameToScan,
                        "Scanning overflow inline frames is something we should avoid");
       result.mScanSiblings = true;
       result.mTextRunCanCrossFrameBoundary = true;
       result.mLineBreakerCanCrossFrameBoundary = true;
+    } else if (aFrame->GetType() == nsGkAtoms::rubyTextFrame ||
+               aFrame->GetType() == nsGkAtoms::rubyTextContainerFrame) {
+      result.mFrameToScan = aFrame->GetFirstPrincipalChild();
+      result.mOverflowFrameToScan =
+        aFrame->GetFirstChild(nsIFrame::kOverflowList);
+      NS_WARN_IF_FALSE(!result.mOverflowFrameToScan,
+                       "Scanning overflow inline frames is something we should avoid");
+      result.mScanSiblings = true;
+      result.mTextRunCanCrossFrameBoundary = false;
+      result.mLineBreakerCanCrossFrameBoundary = false;
     } else {
       result.mFrameToScan = nullptr;
       result.mOverflowFrameToScan = nullptr;
       result.mTextRunCanCrossFrameBoundary = false;
       result.mLineBreakerCanCrossFrameBoundary = false;
     }
   }    
   return result;
@@ -1239,16 +1250,17 @@ BuildTextRuns(gfxContext* aContext, nsTe
     if (aForFrame->IsFloatingFirstLetterChild()) {
       lineContainerChild = aForFrame->PresContext()->PresShell()->
         GetPlaceholderFrameFor(aForFrame->GetParent());
     }
     aLineContainer = FindLineContainer(lineContainerChild);
   } else {
     NS_ASSERTION(!aForFrame ||
                  (aLineContainer == FindLineContainer(aForFrame) ||
+                  aLineContainer->GetType() == nsGkAtoms::rubyTextContainerFrame ||
                   (aLineContainer->GetType() == nsGkAtoms::letterFrame &&
                    aLineContainer->IsFloating())),
                  "Wrong line container hint");
   }
 
   if (aForFrame) {
     if (aForFrame->HasAnyStateBits(TEXT_IS_IN_TOKEN_MATHML)) {
       aLineContainer->AddStateBits(TEXT_IS_IN_TOKEN_MATHML);
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-ruby/reftest.list
@@ -0,0 +1,6 @@
+default-preferences pref(layout.css.ruby.enabled,true)
+
+fails asserts(3-7) == ruby-whitespace-1.html ruby-whitespace-1-ref.html # bug 1052924
+== ruby-whitespace-2.html ruby-whitespace-2-ref.html
+asserts(0-1) != ruby-reflow-1-opaqueruby.html ruby-reflow-1-noruby.html # bug 1052924
+asserts(0-1) == ruby-reflow-1-transparentruby.html ruby-reflow-1-noruby.html # bug 1052924
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-ruby/ruby-reflow-1-noruby.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html style="overflow:hidden;">
+<head>
+<title>CSS Test: Ruby Base Frames Reflowed</title>
+<link rel="author" title="Susanna Bowen" href="mailto:sgbowen8@gmail.com">
+<link rel="help" href="http://www.w3.org/TR/2014/WD-css-ruby-1-20140805/">
+<meta name="assert" content="Test checks that ruby bases are reflowed.">
+<meta charset="UTF-8">
+<style>
+ruby { display: ruby; }
+rb   { display: ruby-base; white-space: nowrap; }
+rp   { display: none; }
+rt   { display: ruby-text; white-space: nowrap; }
+rbc  { display: ruby-base-container; }
+rtc  { display: ruby-text-container; font-size:50%; }
+ruby, rb, rt, rbc, rtc { unicode-bidi: isolate; }
+</style>
+</head>
+<body>
+新幹線
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-ruby/ruby-reflow-1-opaqueruby.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html style="overflow:hidden;">
+<head>
+<title>CSS Test: Ruby Text Frames Visible</title>
+<link rel="author" title="Susanna Bowen" href="mailto:sgbowen8@gmail.com">
+<link rel="help" href="http://www.w3.org/TR/2014/WD-css-ruby-1-20140805/">
+<meta name="assert" content="Test checks that ruby text is rendered.">
+<meta charset="UTF-8">
+<style>
+ruby { display: ruby; }
+rb   { display: ruby-base; white-space: nowrap; }
+rp   { display: none; }
+rt   { display: ruby-text; white-space: nowrap; }
+rbc  { display: ruby-base-container; }
+rtc  { display: ruby-text-container; font-size:50%; }
+ruby, rb, rt, rbc, rtc { unicode-bidi: isolate; }
+</style>
+</head>
+<body>
+<ruby>
+  <rbc><rb>新</rb><rb>幹</rb><rb>線</rb></rbc>
+  <rtc><rt>しん</rt><rt>かん</rt><rt>せん</rt></rtc>
+</ruby>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-ruby/ruby-reflow-1-transparentruby.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html style="overflow:hidden;">
+<head>
+<title>CSS Test: Ruby Base Frames Reflowed</title>
+<link rel="author" title="Susanna Bowen" href="mailto:sgbowen8@gmail.com">
+<link rel="help" href="http://www.w3.org/TR/2014/WD-css-ruby-1-20140805/">
+<meta name="assert" content="Test checks that ruby bases are reflowed.">
+<meta charset="UTF-8">
+<style>
+ruby { display: ruby; }
+rb   { display: ruby-base; white-space: nowrap; }
+rp   { display: none; }
+rt   { display: ruby-text; white-space: nowrap; }
+rbc  { display: ruby-base-container; }
+rtc  { display: ruby-text-container; font-size:50%; color: transparent; }
+ruby, rb, rt, rbc, rtc { unicode-bidi: isolate; }
+</style>
+</head>
+<body>
+<ruby>
+  <rbc><rb>新</rb><rb>幹</rb><rb>線</rb></rbc>
+  <rtc><rt>しん</rt><rt>かん</rt><rt>せん</rt></rtc>
+</ruby>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-ruby/ruby-whitespace-1-ref.html
@@ -0,0 +1,35 @@
+<html>
+<meta charset="UTF-8">
+<head>
+<style>
+ruby { display: ruby; }
+rb   { display: ruby-base; white-space: nowrap; }
+rp   { display: none; }
+rt   { display: ruby-text; white-space: nowrap; font-size: 50%; }
+rbc  { display: ruby-base-container; }
+rtc  { display: ruby-text-container; }
+ruby, rb, rt, rbc, rtc { unicode-bidi: isolate; }
+</style>
+</head>
+<body>
+
+<!-- It's unclear what should happen to the whitespace between the </rtc> and
+     the <rbc>. A literal application of the spec suggests: it gets converted to
+     its own ruby segment, since it is "inter-segment" white space. But then
+     it's a segment containing only trailing whitespace, which gets removed.
+     This results in an empty segment with no whitespace, which doesn't seem
+     correct. //-->
+<ruby><rbc><rb><span>   </span></rb><rb><span>    </span></rb><rb
+  >Base three</rb></rbc><rtc><rt></rt><rt>Text two</rt></rtc><rtc
+  ><rt></rt></rtc><rbc><span>        </span></rbc><rbc><rb
+  >Segment two</rb></rbc><rtc><rt></rt></rtc></ruby>
+
+<ruby><rbc><rb><span>  </span></rb>Base two<rb><span>    </span></rb><rb></rb
+  ></rbc><rtc><rt><span>  </span></rt>Text two<rt><span>     </span></rt><rt
+  ></rt></rtc></ruby>
+
+<ruby><rbc><rb><span>   </span></rb><rb>Base two</rb></rbc><rtc><rt> </rt></rtc
+  ></ruby>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-ruby/ruby-whitespace-1.html
@@ -0,0 +1,28 @@
+<html>
+<meta charset="UTF-8">
+<head>
+<style>
+ruby { display: ruby; }
+rb   { display: ruby-base; white-space: nowrap; }
+rp   { display: none; }
+rt   { display: ruby-text; white-space: nowrap; font-size: 50%; }
+rbc  { display: ruby-base-container; }
+rtc  { display: ruby-text-container; }
+ruby, rb, rt, rbc, rtc { unicode-bidi: isolate; }
+</style>
+</head>
+<body>
+
+<ruby>
+  <rbc>       <rb>   </rb>    <rb>Base three</rb>   </rbc> 
+      <rtc>    <rt>   </rt>   <rt>Text two</rt>   </rtc>    <rtc><rt></rt></rtc>
+        <rbc><rb>Segment two</rb></rbc><rtc><rt></rt></rtc>
+</ruby>
+
+<rbc>   <rb>  </rb>    <rb>Base two</rb>  </rbc>   <rtc><rt>  </rt>     <rt
+  >Text two</rt></rtc>
+
+<rb></rb>   <rb>Base two</rb>   <rt> </rt>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-ruby/ruby-whitespace-2-ref.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<meta charset="UTF-8">
+<head>
+<style>
+ruby { display: ruby; }
+rb   { display: ruby-base; white-space: nowrap; }
+rp   { display: none; }
+rt   { display: ruby-text; white-space: nowrap; font-size: 50%; }
+rbc  { display: ruby-base-container; }
+rtc  { display: ruby-text-container; }
+ruby, rb, rt, rbc, rtc { unicode-bidi: isolate; }
+</style>
+</head>
+
+<body>
+
+<!-- Unclear how this should render. See http://lists.w3.org/Archives/Public/www-style/2014Jul/0620.html //-->
+abcd<ruby><rbc><rb><span> BASE</span></rb></rbc><rtc><rt>TEXT</rt></rtc></ruby>
+
+abcd<ruby><rbc><rb><span>BASE</span></rb></rbc><rtc><rt>TEXT</rt></rtc></ruby>
+
+abcd<ruby><rbc><rb><span> BASE</span></rb></rbc><rtc><rt>TEXT</rt></rtc></ruby>
+
+<ruby><rbc></rbc></ruby>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-ruby/ruby-whitespace-2.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<meta charset="UTF-8">
+<head>
+<style>
+ruby { display: ruby; }
+rb   { display: ruby-base; white-space: nowrap; }
+rp   { display: none; }
+rt   { display: ruby-text; white-space: nowrap; font-size: 50%; }
+rbc  { display: ruby-base-container; }
+rtc  { display: ruby-text-container; }
+ruby, rb, rt, rbc, rtc { unicode-bidi: isolate; }
+</style>
+</head>
+
+<body>
+
+abcd<rbc> BASE</rbc><rt>TEXT</rt>
+
+abcd<rbc> <span>BASE</span></rbc><rt>TEXT</rt>
+
+abcd<rbc><span> BASE</span></rbc><rt>TEXT</rt>
+
+<rbc> </rbc>
+
+</body>
+</html>
--- a/layout/reftests/reftest.list
+++ b/layout/reftests/reftest.list
@@ -85,16 +85,20 @@ include css-gradients/reftest.list
 include css-mediaqueries/reftest.list
 
 # css parsing
 include css-parsing/reftest.list
 
 # css placeholder
 include css-placeholder/reftest.list
 
+# css ruby
+# (Skipping on B2G because of timeouts there; see bug 1054383)
+skip-if(B2G) include css-ruby/reftest.list
+
 # css required
 include css-required/reftest.list
 
 # css optional
 include css-optional/reftest.list
 
 # css valid
 include css-valid/reftest.list
--- a/layout/style/ua.css
+++ b/layout/style/ua.css
@@ -48,26 +48,26 @@
   -moz-backface-visibility: inherit;
   clip: inherit;
 }
 
 *|*::-moz-table-row {
   display: table-row !important;
 }
 
-/* The ::-moz-table-column pseudo-element is for extra columns at the end
+/* The ::-moz-table-column pseudo-element is for extra columns at the end 
    of a table. */
 *|*::-moz-table-column {
   display: table-column !important;
 }
 
 *|*::-moz-table-column-group {
   display: table-column-group !important;
 }
-
+ 
 *|*::-moz-table-row-group {
   display: table-row-group !important;
 }
 
 *|*::-moz-table-cell {
   display: table-cell !important;
   white-space: inherit;
 }
@@ -181,17 +181,17 @@
 
 *|*::-moz-viewport-scroll {
   overflow: auto;
 %ifdef XP_WIN
   resize: both;
 %endif
 }
 
-*|*::-moz-column-content {
+*|*::-moz-column-content { 
   /* the column boxes inside a column-flowed block */
   /* make unicode-bidi inherit, otherwise it has no effect on column boxes */
   unicode-bidi: inherit;
   text-overflow: inherit;
   /* inherit the outer frame's display, otherwise we turn into an inline */
   display: inherit !important;
   /* Carry through our parent's height so that %-height children get
   their heights set */
@@ -302,37 +302,113 @@ parsererror|sourcetext {
   font-family: -moz-fixed;
   margin-top: 2em;
   margin-bottom: 1em;
   color: red;
   font-weight: bold;
   font-size: 12pt;
 }
 
-div[\_moz_anonclass="mozTouchCaret"].moz-touchcaret,
+div[\_moz_anonclass="mozTouchCaret"].moz-touchcaret {
+  background-image: url("resource://gre/res/text_selection_handle.png");
+  position: absolute;
+  width: 19px;
+  height: 24px;
+  margin-left: -10px;
+  background-position: center center;
+  z-index: 2147483647;
+}
+
 div[\_moz_anonclass="mozTouchCaret"].moz-selectioncaret-left,
 div[\_moz_anonclass="mozTouchCaret"].moz-selectioncaret-right {
-  background-image: url("resource://gre/res/caret_middle.svg");
+  background-image: url("resource://gre/res/text_caret.png");
   position: absolute;
-  width: 29px;
-  height: 31px;
-  margin-left: -15px;
+  width: 21px;
+  height: 26px;
+  margin-left: -11px;
   background-position: center center;
   background-size: 100% 100%;
   z-index: 2147483647;
 }
 
 div[\_moz_anonclass="mozTouchCaret"].moz-selectioncaret-left.tilt {
-  background-image: url("resource://gre/res/caret_left.svg");
-  margin-left: -29px;
+  background-image: url("resource://gre/res/text_caret_tilt_left.png");
+  margin-left: -22px;
+  width: 22px;
 }
 
 div[\_moz_anonclass="mozTouchCaret"].moz-selectioncaret-right.tilt {
-  background-image: url("resource://gre/res/caret_right.svg");
+  background-image: url("resource://gre/res/text_caret_tilt_right.png");
   margin-left: 0px;
+  width: 22px;
+}
+
+@media (min-resolution: 1.5dppx) {
+  div[\_moz_anonclass="mozTouchCaret"].moz-touchcaret {
+    background-image: url("resource://gre/res/text_selection_handle@1.5.png");
+    position: absolute;
+    width: 29px;
+    height: 36px;
+    margin-left: -15px;
+    background-position: center center;
+    z-index: 2147483647;
+  }
+
+  div[\_moz_anonclass="mozTouchCaret"].moz-selectioncaret-left,
+  div[\_moz_anonclass="mozTouchCaret"].moz-selectioncaret-right {
+    background-image: url("resource://gre/res/text_caret@1.5x.png");
+  }
+
+  div[\_moz_anonclass="mozTouchCaret"].moz-selectioncaret-left.tilt {
+    background-image: url("resource://gre/res/text_caret_tilt_left@1.5x.png");
+  }
+
+  div[\_moz_anonclass="mozTouchCaret"].moz-selectioncaret-right.tilt {
+    background-image: url("resource://gre/res/text_caret_tilt_right@1.5x.png");
+  }
+}
+
+@media (min-resolution: 2dppx) {
+  div[\_moz_anonclass="mozTouchCaret"].moz-touchcaret {
+    background-image: url("resource://gre/res/text_selection_handle@2.png");
+    position: absolute;
+    width: 38px;
+    height: 48px;
+    margin-left: -19px;
+    background-position: center center;
+    z-index: 2147483647;
+  }
+
+  div[\_moz_anonclass="mozTouchCaret"].moz-selectioncaret-left,
+  div[\_moz_anonclass="mozTouchCaret"].moz-selectioncaret-right {
+    background-image: url("resource://gre/res/text_caret@2x.png");
+  }
+
+  div[\_moz_anonclass="mozTouchCaret"].moz-selectioncaret-left.tilt {
+    background-image: url("resource://gre/res/text_caret_tilt_left@2x.png");
+  }
+
+  div[\_moz_anonclass="mozTouchCaret"].moz-selectioncaret-right.tilt {
+    background-image: url("resource://gre/res/text_caret_tilt_right@2x.png");
+  }
+}
+
+@media (min-resolution: 2.25dppx) {
+  div[\_moz_anonclass="mozTouchCaret"].moz-selectioncaret-left
+  div[\_moz_anonclass="mozTouchCaret"].moz-selectioncaret-right {
+    background-image: url("resource://gre/res/text_caret@2.25x.png");
+  }
+
+  div[\_moz_anonclass="mozTouchCaret"].moz-selectioncaret-left.tilt {
+    background-image: url("resource://gre/res/text_caret_tilt_left@2.25x.png");
+  }
+
+  div[\_moz_anonclass="mozTouchCaret"].moz-selectioncaret-right.tilt {
+    background-image: url("resource://gre/res/text_caret_tilt_right@2.25x.png");
+  }
 }
 
 div[\_moz_anonclass="mozTouchCaret"].moz-touchcaret.hidden,
 div[\_moz_anonclass="mozTouchCaret"].moz-selectioncaret-left.hidden,
 div[\_moz_anonclass="mozTouchCaret"].moz-selectioncaret-right.hidden {
   width: 0px;
   height: 0px;
   margin: 0px;
--- a/layout/svg/nsCSSFilterInstance.cpp
+++ b/layout/svg/nsCSSFilterInstance.cpp
@@ -34,26 +34,33 @@ nsCSSFilterInstance::BuildPrimitives(nsT
   nsresult result;
 
   switch(mFilter.GetType()) {
     case NS_STYLE_FILTER_BLUR:
       descr = CreatePrimitiveDescription(PrimitiveType::GaussianBlur, aPrimitiveDescrs);
       result = SetAttributesForBlur(descr);
       break;
     case NS_STYLE_FILTER_BRIGHTNESS:
+      return NS_ERROR_NOT_IMPLEMENTED;
     case NS_STYLE_FILTER_CONTRAST:
+      return NS_ERROR_NOT_IMPLEMENTED;
     case NS_STYLE_FILTER_DROP_SHADOW:
       descr = CreatePrimitiveDescription(PrimitiveType::DropShadow, aPrimitiveDescrs);
       result = SetAttributesForDropShadow(descr);
       break;
     case NS_STYLE_FILTER_GRAYSCALE:
+      return NS_ERROR_NOT_IMPLEMENTED;
     case NS_STYLE_FILTER_HUE_ROTATE:
+      return NS_ERROR_NOT_IMPLEMENTED;
     case NS_STYLE_FILTER_INVERT:
+      return NS_ERROR_NOT_IMPLEMENTED;
     case NS_STYLE_FILTER_OPACITY:
+      return NS_ERROR_NOT_IMPLEMENTED;
     case NS_STYLE_FILTER_SATURATE:
+      return NS_ERROR_NOT_IMPLEMENTED;
     case NS_STYLE_FILTER_SEPIA:
       return NS_ERROR_NOT_IMPLEMENTED;
     default:
       NS_NOTREACHED("not a valid CSS filter type");
       return NS_ERROR_FAILURE;
   }
 
   if (NS_FAILED(result)) {
--- a/media/webrtc/signaling/src/media-conduit/WebrtcOMXH264VideoCodec.cpp
+++ b/media/webrtc/signaling/src/media-conduit/WebrtcOMXH264VideoCodec.cpp
@@ -280,16 +280,17 @@ public:
 
     sp<Surface> surface = nullptr;
     mNativeWindow = new GonkNativeWindow();
     if (mNativeWindow.get()) {
       // listen to buffers queued by MediaCodec::RenderOutputBufferAndRelease().
       mNativeWindow->setNewFrameCallback(this);
       // XXX remove buffer changes after a better solution lands - bug 1009420
       sp<GonkBufferQueue> bq = mNativeWindow->getBufferQueue();
+      bq->setSynchronousMode(false);
       // More spare buffers to avoid OMX decoder waiting for native window
       bq->setMaxAcquiredBufferCount(WEBRTC_OMX_H264_MIN_DECODE_BUFFERS);
       surface = new Surface(bq);
     }
     status_t result = mCodec->configure(config, surface, nullptr, 0);
     if (result == OK) {
       CODEC_LOGD("OMX:%p decoder configured", this);
       result = Start();
@@ -431,17 +432,20 @@ public:
     return err;
   }
 
   // Will be called when MediaCodec::RenderOutputBufferAndRelease() returns
   // buffers back to native window for rendering.
   void OnNewFrame() MOZ_OVERRIDE
   {
     RefPtr<layers::TextureClient> buffer = mNativeWindow->getCurrentBuffer();
-    MOZ_ASSERT(buffer != nullptr);
+    if (!buffer) {
+      CODEC_LOGE("Decoder NewFrame: Get null buffer");
+      return;
+    }
 
     layers::GrallocImage::GrallocData grallocData;
     grallocData.mPicSize = buffer->GetSize();
     grallocData.mGraphicBuffer = buffer;
 
     nsAutoPtr<layers::GrallocImage> grallocImage(new layers::GrallocImage());
     grallocImage->SetData(grallocData);
 
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -2819,16 +2819,23 @@ pref("intl.tsf.force_enable", false);
 
 // Support IMEs implemented with IMM in TSF mode.
 pref("intl.tsf.support_imm", true);
 
 // Enables/Disables hack for specific TIP.
 
 // Whether creates native caret for ATOK or not.
 pref("intl.tsf.hack.atok.create_native_caret", true);
+// Whether use composition start position for the result of
+// ITfContextView::GetTextExt() if the specified range is larger than
+// composition start offset.
+// For Free ChangJie 2010
+pref("intl.tsf.hack.free_chang_jie.do_not_return_no_layout_error", true);
+// For Easy Changjei
+pref("intl.tsf.hack.easy_changjei.do_not_return_no_layout_error", true);
 #endif
 
 // See bug 448927, on topmost panel, some IMEs are not usable on Windows.
 pref("ui.panel.default_level_parent", false);
 
 pref("mousewheel.system_scroll_override_on_root_content.enabled", true);
 
 // High resolution scrolling with supported mouse drivers on Vista or later.
--- a/netwerk/base/public/nsIEncodedChannel.idl
+++ b/netwerk/base/public/nsIEncodedChannel.idl
@@ -1,16 +1,19 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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 "nsISupports.idl"
 
 interface nsIUTF8StringEnumerator;
+interface nsIStreamListener;
+interface nsISupports;
+
 /**
  * A channel interface which allows special handling of encoded content
  */
 
 [scriptable, uuid(30d7ec3a-f376-4652-9276-3092ec57abb6)]
 interface nsIEncodedChannel : nsISupports
 {
     /**
@@ -36,9 +39,17 @@ interface nsIEncodedChannel : nsISupport
      * This attribute controls whether or not content conversion should be
      * done per the Content-Encoding response header.  applyConversion can only 
      * be set before or during OnStartRequest.  Calling this during 
      * OnDataAvailable is an error. 
      *
      * TRUE by default.
      */
     attribute boolean applyConversion;
+
+    /**
+     * This function will start converters if they are available.
+     * aNewNextListener will be nullptr if no converter is available.
+     */
+    void doApplyContentConversions(in nsIStreamListener aNextListener,
+                                   out nsIStreamListener aNewNextListener,
+                                   in nsISupports aCtxt);
 };
--- a/netwerk/base/src/nsInputStreamPump.cpp
+++ b/netwerk/base/src/nsInputStreamPump.cpp
@@ -464,16 +464,26 @@ nsInputStreamPump::OnInputStreamReady(ns
         if (nextState == STATE_STOP && !NS_IsMainThread()) {
             mRetargeting = true;
         }
 
         // Unset mProcessingCallbacks here (while we have lock) so our own call to
         // EnsureWaiting isn't blocked by it.
         mProcessingCallbacks = false;
 
+        // We must break the loop when we're switching event delivery to another
+        // thread and the input stream pump is suspended, otherwise
+        // OnStateStop() might be called off the main thread. See bug 1026951
+        // comment #107 for the exact scenario.
+        if (mSuspendCount && mRetargeting) {
+            mState = nextState;
+            mWaitingForInputStreamReady = false;
+            break;
+        }
+
         // Wait asynchronously if there is still data to transfer, or we're
         // switching event delivery to another thread.
         if (!mSuspendCount && (stillTransferring || mRetargeting)) {
             mState = nextState;
             mWaitingForInputStreamReady = false;
             nsresult rv = EnsureWaiting();
             if (NS_SUCCEEDED(rv))
                 break;
--- a/netwerk/protocol/http/HttpBaseChannel.cpp
+++ b/netwerk/protocol/http/HttpBaseChannel.cpp
@@ -599,23 +599,27 @@ HttpBaseChannel::GetApplyConversion(bool
 NS_IMETHODIMP
 HttpBaseChannel::SetApplyConversion(bool value)
 {
   LOG(("HttpBaseChannel::SetApplyConversion [this=%p value=%d]\n", this, value));
   mApplyConversion = value;
   return NS_OK;
 }
 
-nsresult
-HttpBaseChannel::ApplyContentConversions()
+NS_IMETHODIMP
+HttpBaseChannel::DoApplyContentConversions(nsIStreamListener* aNextListener,
+                                           nsIStreamListener** aNewNextListener,
+                                           nsISupports *aCtxt)
 {
+  *aNewNextListener = nullptr;
+  nsCOMPtr<nsIStreamListener> nextListener = aNextListener;
   if (!mResponseHead)
     return NS_OK;
 
-  LOG(("HttpBaseChannel::ApplyContentConversions [this=%p]\n", this));
+  LOG(("HttpBaseChannel::DoApplyContentConversions [this=%p]\n", this));
 
   if (!mApplyConversion) {
     LOG(("not applying conversion per mApplyConversion\n"));
     return NS_OK;
   }
 
   nsAutoCString contentEncoding;
   char *cePtr, *val;
@@ -654,33 +658,34 @@ HttpBaseChannel::ApplyContentConversions
         continue;
       }
 
       nsCOMPtr<nsIStreamListener> converter;
       nsAutoCString from(val);
       ToLowerCase(from);
       rv = serv->AsyncConvertData(from.get(),
                                   "uncompressed",
-                                  mListener,
-                                  mListenerContext,
+                                  nextListener,
+                                  aCtxt,
                                   getter_AddRefs(converter));
       if (NS_FAILED(rv)) {
         LOG(("Unexpected failure of AsyncConvertData %s\n", val));
         return rv;
       }
 
       LOG(("converter removed '%s' content-encoding\n", val));
-      mListener = converter;
+      nextListener = converter;
     }
     else {
       if (val)
         LOG(("Unknown content encoding '%s', ignoring\n", val));
     }
   }
-
+  *aNewNextListener = nextListener;
+  NS_ADDREF(*aNewNextListener);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 HttpBaseChannel::GetContentEncodings(nsIUTF8StringEnumerator** aEncodings)
 {
   if (!mResponseHead) {
     *aEncodings = nullptr;
--- a/netwerk/protocol/http/HttpBaseChannel.h
+++ b/netwerk/protocol/http/HttpBaseChannel.h
@@ -235,17 +235,19 @@ protected:
 
   // Handle notifying listener, removing from loadgroup if request failed.
   void     DoNotifyListener();
   virtual void DoNotifyListenerCleanup() = 0;
 
   // drop reference to listener, its callbacks, and the progress sink
   void ReleaseListeners();
 
-  nsresult ApplyContentConversions();
+  NS_IMETHOD DoApplyContentConversions(nsIStreamListener *aNextListener,
+                                     nsIStreamListener **aNewNextListener,
+                                     nsISupports *aCtxt);
 
   void AddCookiesToRequest();
   virtual nsresult SetupReplacementChannel(nsIURI *,
                                            nsIChannel *,
                                            bool preserveMethod);
 
   // bundle calling OMR observers and marking flag into one function
   inline void CallOnModifyRequestObservers() {
--- a/netwerk/protocol/http/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/HttpChannelChild.cpp
@@ -331,19 +331,24 @@ HttpChannelChild::OnStartRequest(const n
     if (mLoadGroup) {
       mLoadGroup->RemoveRequest(this, nullptr, mStatus);
     }
   }
 
   if (mResponseHead)
     SetCookie(mResponseHead->PeekHeader(nsHttp::Set_Cookie));
 
-  rv = ApplyContentConversions();
-  if (NS_FAILED(rv))
+  nsCOMPtr<nsIStreamListener> listener;
+  rv = DoApplyContentConversions(mListener, getter_AddRefs(listener),
+                                 mListenerContext);
+  if (NS_FAILED(rv)) {
     Cancel(rv);
+  } else if (listener) {
+    mListener = listener;
+  }
 
   mSelfAddr = selfAddr;
   mPeerAddr = peerAddr;
 }
 
 class TransportAndDataEvent : public ChannelEvent
 {
  public:
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -863,42 +863,40 @@ nsHttpChannel::CallOnStartRequest()
           mTransactionPump->PeekStream(CallTypeSniffers, thisChannel);
         }
     }
 
     bool shouldSniff = mResponseHead && (mResponseHead->ContentType().IsEmpty() ||
         ((mResponseHead->ContentType().EqualsLiteral(APPLICATION_OCTET_STREAM) &&
         (mLoadFlags & LOAD_TREAT_APPLICATION_OCTET_STREAM_AS_UNKNOWN))));
 
+    bool unknownDecoderStarted = false;
     if (shouldSniff) {
         MOZ_ASSERT(mConnectionInfo, "Should have connection info here");
         if (!mContentTypeHint.IsEmpty())
             mResponseHead->SetContentType(mContentTypeHint);
         else if (mResponseHead->Version() == NS_HTTP_VERSION_0_9 &&
                  mConnectionInfo->Port() != mConnectionInfo->DefaultPort())
             mResponseHead->SetContentType(NS_LITERAL_CSTRING(TEXT_PLAIN));
         else {
             // Uh-oh.  We had better find out what type we are!
-
-            // XXX This does not work with content-encodings...  but
-            // neither does applying the conversion from the URILoader
-
             nsCOMPtr<nsIStreamConverterService> serv;
             rv = gHttpHandler->
                 GetStreamConverterService(getter_AddRefs(serv));
             // If we failed, we just fall through to the "normal" case
             if (NS_SUCCEEDED(rv)) {
                 nsCOMPtr<nsIStreamListener> converter;
                 rv = serv->AsyncConvertData(UNKNOWN_CONTENT_TYPE,
                                             "*/*",
                                             mListener,
                                             mListenerContext,
                                             getter_AddRefs(converter));
                 if (NS_SUCCEEDED(rv)) {
                     mListener = converter;
+                    unknownDecoderStarted = true;
                 }
             }
         }
     }
 
     if (mResponseHead && mResponseHead->ContentCharset().IsEmpty())
         mResponseHead->SetContentCharset(mContentCharsetHint);
 
@@ -919,19 +917,30 @@ nsHttpChannel::CallOnStartRequest()
     if (mListener) {
         rv = mListener->OnStartRequest(this, mListenerContext);
         if (NS_FAILED(rv))
             return rv;
     } else {
         NS_WARNING("OnStartRequest skipped because of null listener");
     }
 
-    // install stream converter if required
-    rv = ApplyContentConversions();
-    if (NS_FAILED(rv)) return rv;
+    // Install stream converter if required.
+    // If we use unknownDecoder, stream converters will be installed later (in
+    // nsUnknownDecoder) after OnStartRequest is called for the real listener.
+    if (!unknownDecoderStarted) {
+      nsCOMPtr<nsIStreamListener> listener;
+      nsISupports *ctxt = mListenerContext;
+      rv = DoApplyContentConversions(mListener, getter_AddRefs(listener), ctxt);
+      if (NS_FAILED(rv)) {
+        return rv;
+      }
+      if (listener) {
+        mListener = listener;
+      }
+    }
 
     rv = EnsureAssocReq();
     if (NS_FAILED(rv))
         return rv;
 
     // if this channel is for a download, close off access to the cache.
     if (mCacheEntry && mChannelIsForDownload) {
         mCacheEntry->AsyncDoom(nullptr);
--- a/netwerk/streamconv/converters/nsUnknownDecoder.cpp
+++ b/netwerk/streamconv/converters/nsUnknownDecoder.cpp
@@ -13,26 +13,86 @@
 
 #include "nsCRT.h"
 
 #include "nsIMIMEService.h"
 
 #include "nsIViewSourceChannel.h"
 #include "nsIHttpChannel.h"
 #include "nsIForcePendingChannel.h"
+#include "nsIEncodedChannel.h"
 #include "nsNetCID.h"
 #include "nsNetUtil.h"
 
+#include <algorithm>
 
-#define MAX_BUFFER_SIZE 512
+#define MAX_BUFFER_SIZE 512u
+
+NS_IMPL_ISUPPORTS(nsUnknownDecoder::ConvertedStreamListener,
+                  nsIStreamListener,
+                  nsIRequestObserver)
+
+nsUnknownDecoder::ConvertedStreamListener::
+                  ConvertedStreamListener(nsUnknownDecoder *aDecoder)
+{
+  mDecoder = aDecoder;
+}
+
+nsUnknownDecoder::ConvertedStreamListener::~ConvertedStreamListener()
+{
+}
+
+NS_IMETHODIMP
+nsUnknownDecoder::ConvertedStreamListener::
+                  AppendDataToString(nsIInputStream* inputStream,
+                                     void* closure,
+                                     const char* rawSegment,
+                                     uint32_t toOffset,
+                                     uint32_t count,
+                                     uint32_t* writeCount)
+{
+  nsCString* decodedData = static_cast<nsCString*>(closure);
+  decodedData->Append(rawSegment, count);
+  *writeCount = count;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsUnknownDecoder::ConvertedStreamListener::OnStartRequest(nsIRequest* request,
+                                                          nsISupports* context)
+{
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsUnknownDecoder::ConvertedStreamListener::
+                  OnDataAvailable(nsIRequest* request,
+                                  nsISupports* context,
+                                  nsIInputStream* stream,
+                                  uint64_t offset,
+                                  uint32_t count)
+{
+  uint32_t read;
+  return stream->ReadSegments(AppendDataToString, &mDecoder->mDecodedData, count,
+                              &read);
+}
+
+NS_IMETHODIMP
+nsUnknownDecoder::ConvertedStreamListener::OnStopRequest(nsIRequest* request,
+                                                         nsISupports* context,
+                                                         nsresult status)
+{
+  return NS_OK;
+}
 
 nsUnknownDecoder::nsUnknownDecoder()
   : mBuffer(nullptr)
   , mBufferLen(0)
   , mRequireHTMLsuffix(false)
+  , mDecodedData("")
 {
   nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
   if (prefs) {
     bool val;
     if (NS_SUCCEEDED(prefs->GetBoolPref("security.requireHTMLsuffix", &val)))
       mRequireHTMLsuffix = val;
   }
 }
@@ -309,22 +369,36 @@ uint32_t nsUnknownDecoder::sSnifferEntry
   sizeof(nsUnknownDecoder::sSnifferEntries) /
     sizeof(nsUnknownDecoder::nsSnifferEntry);
 
 void nsUnknownDecoder::DetermineContentType(nsIRequest* aRequest)
 {
   NS_ASSERTION(mContentType.IsEmpty(), "Content type is already known.");
   if (!mContentType.IsEmpty()) return;
 
+  const char* testData = mBuffer;
+  uint32_t testDataLen = mBufferLen;
+  // Check if data are compressed.
+  nsCOMPtr<nsIHttpChannel> channel(do_QueryInterface(aRequest));
+  if (channel) {
+    nsresult rv = ConvertEncodedData(aRequest, mBuffer, mBufferLen);
+    if (NS_SUCCEEDED(rv)) {
+      if (!mDecodedData.IsEmpty()) {
+        testData = mDecodedData.get();
+        testDataLen = std::min(mDecodedData.Length(), MAX_BUFFER_SIZE);
+      }
+    }
+  }
+
   // First, run through all the types we can detect reliably based on
   // magic numbers
   uint32_t i;
   for (i = 0; i < sSnifferEntryNum; ++i) {
-    if (mBufferLen >= sSnifferEntries[i].mByteLen &&  // enough data
-        memcmp(mBuffer, sSnifferEntries[i].mBytes, sSnifferEntries[i].mByteLen) == 0) {  // and type matches
+    if (testDataLen >= sSnifferEntries[i].mByteLen &&  // enough data
+        memcmp(testData, sSnifferEntries[i].mBytes, sSnifferEntries[i].mByteLen) == 0) {  // and type matches
       NS_ASSERTION(sSnifferEntries[i].mMimeType ||
                    sSnifferEntries[i].mContentTypeSniffer,
                    "Must have either a type string or a function to set the type");
       NS_ASSERTION(!sSnifferEntries[i].mMimeType ||
                    !sSnifferEntries[i].mContentTypeSniffer,
                    "Both a type string and a type sniffing function set;"
                    " using type string");
       if (sSnifferEntries[i].mMimeType) {
@@ -337,17 +411,17 @@ void nsUnknownDecoder::DetermineContentT
         NS_ASSERTION(!mContentType.IsEmpty(), 
                      "Content type should be known by now.");
         return;
       }        
     }
   }
 
   NS_SniffContent(NS_DATA_SNIFFER_CATEGORY, aRequest,
-                  (const uint8_t*)mBuffer, mBufferLen, mContentType);
+                  (const uint8_t*)testData, testDataLen, mContentType);
   if (!mContentType.IsEmpty()) {
     return;
   }
 
   if (SniffForHTML(aRequest)) {
     NS_ASSERTION(!mContentType.IsEmpty(), 
                  "Content type should be known by now.");
     return;
@@ -371,20 +445,28 @@ bool nsUnknownDecoder::SniffForHTML(nsIR
   /*
    * To prevent a possible attack, we will not consider this to be
    * html content if it comes from the local file system and our prefs
    * are set right
    */
   if (!AllowSniffing(aRequest)) {
     return false;
   }
-  
+
   // Now look for HTML.
-  const char* str = mBuffer;
-  const char* end = mBuffer + mBufferLen;
+  const char* str;
+  const char* end;
+  if (mDecodedData.IsEmpty()) {
+    str = mBuffer;
+    end = mBuffer + mBufferLen;
+  } else {
+    str = mDecodedData.get();
+    end = mDecodedData.get() + std::min(mDecodedData.Length(),
+                                        MAX_BUFFER_SIZE);
+  }
 
   // skip leading whitespace
   while (str != end && nsCRT::IsAsciiSpace(*str)) {
     ++str;
   }
 
   // did we find something like a start tag?
   if (str == end || *str != '<' || ++str == end) {
@@ -488,48 +570,58 @@ bool nsUnknownDecoder::SniffURI(nsIReque
 #define IS_TEXT_CHAR(ch)                                     \
   (((unsigned char)(ch)) > 31 || (9 <= (ch) && (ch) <= 13) || (ch) == 27)
 
 bool nsUnknownDecoder::LastDitchSniff(nsIRequest* aRequest)
 {
   // All we can do now is try to guess whether this is text/plain or
   // application/octet-stream
 
+  const char* testData;
+  uint32_t testDataLen;
+  if (mDecodedData.IsEmpty()) {
+    testData = mBuffer;
+    testDataLen = mBufferLen;
+  } else {
+    testData = mDecodedData.get();
+    testDataLen = std::min(mDecodedData.Length(), MAX_BUFFER_SIZE);
+  }
+
   // First, check for a BOM.  If we see one, assume this is text/plain
   // in whatever encoding.  If there is a BOM _and_ text we will
   // always have at least 4 bytes in the buffer (since the 2-byte BOMs
   // are for 2-byte encodings and the UTF-8 BOM is 3 bytes).
-  if (mBufferLen >= 4) {
-    const unsigned char* buf = (const unsigned char*)mBuffer;
+  if (testDataLen >= 4) {
+    const unsigned char* buf = (const unsigned char*)testData;
     if ((buf[0] == 0xFE && buf[1] == 0xFF) || // UTF-16, Big Endian
         (buf[0] == 0xFF && buf[1] == 0xFE) || // UTF-16 or UCS-4, Little Endian
         (buf[0] == 0xEF && buf[1] == 0xBB && buf[2] == 0xBF) || // UTF-8
         (buf[0] == 0 && buf[1] == 0 && buf[2] == 0xFE && buf[3] == 0xFF)) { // UCS-4, Big Endian
-        
+       
       mContentType = TEXT_PLAIN;
       return true;
     }
   }
-  
+
   // Now see whether the buffer has any non-text chars.  If not, then let's
   // just call it text/plain...
   //
   uint32_t i;
-  for (i = 0; i < mBufferLen && IS_TEXT_CHAR(mBuffer[i]); i++) {
+  for (i = 0; i < testDataLen && IS_TEXT_CHAR(testData[i]); i++) {
     continue;
   }
 
-  if (i == mBufferLen) {
+  if (i == testDataLen) {
     mContentType = TEXT_PLAIN;
   }
   else {
     mContentType = APPLICATION_OCTET_STREAM;
   }
 
-  return true;    
+  return true;
 }
 
 
 nsresult nsUnknownDecoder::FireListenerNotifications(nsIRequest* request,
                                                      nsISupports *aCtxt)
 {
   nsresult rv = NS_OK;
 
@@ -557,16 +649,28 @@ nsresult nsUnknownDecoder::FireListenerN
       mNextListener->OnStartRequest(request, aCtxt);
       return rv;
     }
   }
 
   // Fire the OnStartRequest(...)
   rv = mNextListener->OnStartRequest(request, aCtxt);
 
+  if (NS_SUCCEEDED(rv)) {
+    // install stream converter if required
+    nsCOMPtr<nsIEncodedChannel> encodedChannel = do_QueryInterface(request);
+    if (encodedChannel) {
+      nsCOMPtr<nsIStreamListener> listener;
+      rv = encodedChannel->DoApplyContentConversions(mNextListener, getter_AddRefs(listener), aCtxt);
+      if (NS_SUCCEEDED(rv) && listener) {
+        mNextListener = listener;
+      }
+    }
+  }
+
   if (!mBuffer) return NS_ERROR_OUT_OF_MEMORY;
 
   // If the request was canceled, then we need to treat that equivalently
   // to an error returned by OnStartRequest.
   if (NS_SUCCEEDED(rv))
     request->GetStatus(&rv);
 
   // Fire the first OnDataAvailable for the data that was read from the
@@ -595,16 +699,61 @@ nsresult nsUnknownDecoder::FireListenerN
 
   delete [] mBuffer;
   mBuffer = nullptr;
   mBufferLen = 0;
 
   return rv;
 }
 
+
+nsresult
+nsUnknownDecoder::ConvertEncodedData(nsIRequest* request,
+                                     const char* data,
+                                     uint32_t length)
+{
+  nsresult rv = NS_OK;
+
+  mDecodedData = "";
+  nsCOMPtr<nsIEncodedChannel> encodedChannel(do_QueryInterface(request));
+  if (encodedChannel) {
+
+    nsRefPtr<ConvertedStreamListener> strListener =
+      new ConvertedStreamListener(this);
+
+    nsCOMPtr<nsIStreamListener> listener;
+    rv = encodedChannel->DoApplyContentConversions(strListener,
+                                                   getter_AddRefs(listener),
+                                                   nullptr);
+
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+
+    if (listener) {
+      listener->OnStartRequest(request, nullptr);
+
+      nsCOMPtr<nsIStringInputStream> rawStream =
+        do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID);
+      if (!rawStream)
+        return NS_ERROR_FAILURE;
+
+      rv = rawStream->SetData((const char*)data, length);
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      rv = listener->OnDataAvailable(request, nullptr, rawStream, 0,
+                                     length);
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      listener->OnStopRequest(request, nullptr, NS_OK);
+    }
+  }
+  return rv;
+}
+
 void
 nsBinaryDetector::DetermineContentType(nsIRequest* aRequest)
 {
   nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aRequest);
   if (!httpChannel) {
     return;
   }
 
--- a/netwerk/streamconv/converters/nsUnknownDecoder.h
+++ b/netwerk/streamconv/converters/nsUnknownDecoder.h
@@ -42,16 +42,36 @@ public:
   nsUnknownDecoder();
 
 protected:
   virtual ~nsUnknownDecoder();
 
   virtual void DetermineContentType(nsIRequest* aRequest);
   nsresult FireListenerNotifications(nsIRequest* request, nsISupports *aCtxt);
 
+  class ConvertedStreamListener: public nsIStreamListener
+  {
+  public:
+    ConvertedStreamListener(nsUnknownDecoder *aDecoder);
+
+    NS_DECL_ISUPPORTS
+    NS_DECL_NSIREQUESTOBSERVER
+    NS_DECL_NSISTREAMLISTENER
+
+  private:
+    virtual ~ConvertedStreamListener();
+    static NS_METHOD AppendDataToString(nsIInputStream* inputStream,
+                                        void* closure,
+                                        const char* rawSegment,
+                                        uint32_t toOffset,
+                                        uint32_t count,
+                                        uint32_t* writeCount);
+    nsUnknownDecoder *mDecoder;
+  };
+
 protected:
   nsCOMPtr<nsIStreamListener> mNextListener;
 
   // Function to use to check whether sniffing some potentially
   // dangerous types (eg HTML) is ok for this request.  We can disable
   // sniffing for local files if needed using this.  Just a security
   // precation thingy... who knows when we suddenly need to flip this
   // pref?
@@ -101,16 +121,20 @@ protected:
   static uint32_t sSnifferEntryNum;
   
   char *mBuffer;
   uint32_t mBufferLen;
   bool mRequireHTMLsuffix;
 
   nsCString mContentType;
 
+protected:
+  nsresult ConvertEncodedData(nsIRequest* request, const char* data,
+                              uint32_t length);
+  nsCString mDecodedData; // If data are encoded this will be uncompress data.
 };
 
 #define NS_BINARYDETECTOR_CID                        \
 { /* a2027ec6-ba0d-4c72-805d-148233f5f33c */         \
     0xa2027ec6,                                      \
     0xba0d,                                          \
     0x4c72,                                          \
     {0x80, 0x5d, 0x14, 0x82, 0x33, 0xf5, 0xf3, 0x3c} \
--- a/netwerk/test/unit/test_reply_without_content_type.js
+++ b/netwerk/test/unit/test_reply_without_content_type.js
@@ -2,56 +2,89 @@
 // tests HTTP replies that lack content-type (where we try to sniff content-type).
 //
 
 // Note: sets Cc and Ci variables
 
 Cu.import("resource://testing-common/httpd.js");
 
 var httpserver = new HttpServer();
-var testpath = "/simple";
+var testpath = "/simple_plainText";
 var httpbody = "<html><body>omg hai</body></html>";
+var testpathGZip = "/simple_gzip";
+//this is compressed httpbody;
+var httpbodyGZip = ["0x1f", "0x8b", "0x8", "0x0", "0x0", "0x0", "0x0", "0x0",
+                  "0x0", "0x3", "0xb3", "0xc9", "0x28", "0xc9", "0xcd", "0xb1",
+                  "0xb3", "0x49", "0xca", "0x4f", "0xa9", "0xb4", "0xcb",
+                  "0xcf", "0x4d", "0x57", "0xc8", "0x48", "0xcc", "0xb4",
+                  "0xd1", "0x7", "0xf3", "0x6c", "0xf4", "0xc1", "0x52", "0x0",
+                  "0x4", "0x99", "0x79", "0x2b", "0x21", "0x0", "0x0", "0x0"];
 var buffer = "";
 
 var dbg=0
 if (dbg) { print("============== START =========="); }
 
-function run_test() {
-  setup_test();
-  do_test_pending();
-}
-
-function setup_test() {
-  if (dbg) { print("============== setup_test: in"); }
-  httpserver.registerPathHandler(testpath, serverHandler);
+add_test(function test_plainText() {
+  if (dbg) { print("============== test_plainText: in"); }
+  httpserver.registerPathHandler(testpath, serverHandler_plainText);
   httpserver.start(-1);
   var channel = setupChannel(testpath);
   // ChannelListener defined in head_channels.js
   channel.asyncOpen(new ChannelListener(checkRequest, channel), null);
-  if (dbg) { print("============== setup_test: out"); }
-}
+  do_test_pending();
+  if (dbg) { print("============== test_plainText: out"); }
+});
+
+add_test(function test_GZip() {
+  if (dbg) { print("============== test_GZip: in"); }
+  httpserver.registerPathHandler(testpathGZip, serverHandler_GZip);
+  httpserver.start(-1);
+  var channel = setupChannel(testpathGZip);
+  // ChannelListener defined in head_channels.js
+  channel.asyncOpen(new ChannelListener(checkRequest, channel,
+                                        CL_EXPECT_GZIP), null);
+  do_test_pending();
+  if (dbg) { print("============== test_GZip: out"); }
+});
+
 
 function setupChannel(path) {
   var ios = Cc["@mozilla.org/network/io-service;1"].
                        getService(Ci.nsIIOService);
   var chan = ios.newChannel("http://localhost:" +
                             httpserver.identity.primaryPort + path, "", null);
   chan.QueryInterface(Ci.nsIHttpChannel);
   chan.requestMethod = "GET";
   return chan;
 }
 
-function serverHandler(metadata, response) {
-  if (dbg) { print("============== serverHandler: in"); }
+function serverHandler_plainText(metadata, response) {
+  if (dbg) { print("============== serverHandler plainText: in"); }
 //  no content type set
 //  response.setHeader("Content-Type", "text/plain", false);
   response.bodyOutputStream.write(httpbody, httpbody.length);
-  if (dbg) { print("============== serverHandler: out"); }
+  if (dbg) { print("============== serverHandler plainText: out"); }
+}
+
+function serverHandler_GZip(metadata, response) {
+    if (dbg) { print("============== serverHandler GZip: in"); }
+    //  no content type set
+    //  response.setHeader("Content-Type", "text/plain", false);
+      response.setHeader("Content-Encoding", "gzip", false);
+      var bos = Cc["@mozilla.org/binaryoutputstream;1"]
+                  .createInstance(Ci.nsIBinaryOutputStream);
+      bos.setOutputStream(response.bodyOutputStream);
+      bos.writeByteArray(httpbodyGZip, httpbodyGZip.length);
+    if (dbg) { print("============== serverHandler GZip: out"); }
 }
 
 function checkRequest(request, data, context) {
   if (dbg) { print("============== checkRequest: in"); }
   do_check_eq(data, httpbody);
   do_check_eq(request.QueryInterface(Ci.nsIChannel).contentType,"text/html");
   httpserver.stop(do_test_finished);
+  run_next_test();
   if (dbg) { print("============== checkRequest: out"); }
 }
 
+function run_test() {
+  run_next_test();
+}
--- a/security/manager/locales/en-US/chrome/pipnss/nsserrors.properties
+++ b/security/manager/locales/en-US/chrome/pipnss/nsserrors.properties
@@ -294,8 +294,9 @@ SEC_ERROR_PKCS11_FUNCTION_FAILED=A PKCS 
 SEC_ERROR_PKCS11_DEVICE_ERROR=A PKCS #11 module returned CKR_DEVICE_ERROR, indicating that a problem has occurred with the token or slot.
 SEC_ERROR_BAD_INFO_ACCESS_METHOD=Unknown information access method in certificate extension.
 SEC_ERROR_CRL_IMPORT_FAILED=Error attempting to import a CRL.
 SEC_ERROR_EXPIRED_PASSWORD=The password expired.
 SEC_ERROR_LOCKED_PASSWORD=The password is locked.
 SEC_ERROR_UNKNOWN_PKCS11_ERROR=Unknown PKCS #11 error.
 SEC_ERROR_BAD_CRL_DP_URL=Invalid or unsupported URL in CRL distribution point name.
 SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED=The certificate was signed using a signature algorithm that is disabled because it is not secure.
+MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE=The server presented a certificate with a key size that is too small to establish a secure connection.
--- a/security/manager/ssl/src/nsUsageArrayHelper.cpp
+++ b/security/manager/ssl/src/nsUsageArrayHelper.cpp
@@ -145,16 +145,17 @@ void
 nsUsageArrayHelper::verifyFailed(uint32_t *_verified, int err)
 {
   switch (err) {
   /* For these cases, verify only failed for the particular usage */
   case SEC_ERROR_INADEQUATE_KEY_USAGE:
   case SEC_ERROR_INADEQUATE_CERT_TYPE:
   case SEC_ERROR_CA_CERT_INVALID:
   case mozilla::pkix::MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY:
+  case mozilla::pkix::MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE:
     *_verified = nsNSSCertificate::USAGE_NOT_ALLOWED; break;
   /* These are the cases that have individual error messages */
   case SEC_ERROR_REVOKED_CERTIFICATE:
     *_verified = nsNSSCertificate::CERT_REVOKED; break;
   case SEC_ERROR_EXPIRED_CERTIFICATE:
     *_verified = nsNSSCertificate::CERT_EXPIRED; break;
   case SEC_ERROR_UNTRUSTED_CERT:
     *_verified = nsNSSCertificate::CERT_NOT_TRUSTED; break;
--- a/security/manager/ssl/tests/unit/head_psm.js
+++ b/security/manager/ssl/tests/unit/head_psm.js
@@ -55,16 +55,17 @@ const SEC_ERROR_POLICY_VALIDATION_FAILED
 const SEC_ERROR_OCSP_BAD_SIGNATURE                      = SEC_ERROR_BASE + 157;
 const SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED       = SEC_ERROR_BASE + 176;
 const SEC_ERROR_APPLICATION_CALLBACK_ERROR              = SEC_ERROR_BASE + 178;
 
 const SSL_ERROR_BAD_CERT_DOMAIN                         = SSL_ERROR_BASE +  12;
 const SSL_ERROR_BAD_CERT_ALERT                          = SSL_ERROR_BASE +  17;
 
 const MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE            = MOZILLA_PKIX_ERROR_BASE +   0;
+const MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE            = MOZILLA_PKIX_ERROR_BASE +   2; // -16382
 
 // Supported Certificate Usages
 const certificateUsageSSLClient              = 0x0001;
 const certificateUsageSSLServer              = 0x0002;
 const certificateUsageSSLCA                  = 0x0008;
 const certificateUsageEmailSigner            = 0x0010;
 const certificateUsageEmailRecipient         = 0x0020;
 const