Merge mc->Maple
authorBenoit Girard <b56girard@gmail.com>
Fri, 09 Mar 2012 11:13:30 -0500
changeset 92622 c6dcca94622e4b66c69ef48a03c256b5fde85295
parent 92621 217568c1b04763eee6cf086d30a8a3a2c9b15cc6 (current diff)
parent 91495 ead9016b4102e8bcadc7f02cb47f54e9a890e2c2 (diff)
child 92623 469024778d7fcb77feb4050ae090e60c92d1c019
push id886
push userlsblakk@mozilla.com
push dateMon, 04 Jun 2012 19:57:52 +0000
treeherdermozilla-beta@bbd8d5efd6d1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone13.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 mc->Maple
browser/devtools/styleinspector/CssRuleView.jsm
browser/devtools/styleinspector/test/Makefile.in
browser/themes/gnomestripe/fullscreen-video.css
browser/themes/gnomestripe/jar.mn
browser/themes/gnomestripe/section_collapsed-rtl.png
browser/themes/gnomestripe/section_collapsed.png
browser/themes/gnomestripe/section_expanded.png
browser/themes/pinstripe/fullscreen-video.css
browser/themes/pinstripe/jar.mn
browser/themes/pinstripe/section_collapsed-rtl.png
browser/themes/pinstripe/section_collapsed.png
browser/themes/pinstripe/section_expanded.png
browser/themes/winstripe/fullscreen-video.css
browser/themes/winstripe/jar.mn
browser/themes/winstripe/section_collapsed-rtl.png
browser/themes/winstripe/section_collapsed.png
browser/themes/winstripe/section_expanded.png
build/unix/check_debug_ranges.py
configure.in
content/base/public/nsContentUtils.h
content/base/public/nsIHTMLToTextSink.h
content/base/src/nsContentUtils.cpp
content/base/src/nsGenericElement.cpp
content/html/content/src/nsFormSubmission.cpp
dom/base/nsGlobalWindow.cpp
gfx/gl/GLContextProviderEGL.cpp
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jscntxt.h
js/src/jscompartment.cpp
js/src/jscompartment.h
js/src/jsfriendapi.cpp
js/src/jsfriendapi.h
js/src/jsgc.cpp
js/src/jsstr.cpp
js/src/shell/js.cpp
js/xpconnect/src/XPCJSRuntime.cpp
js/xpconnect/src/xpcprivate.h
layout/build/nsLayoutModule.cpp
mobile/android/app/mobile.js
mobile/android/base/AboutHomeContent.java
mobile/android/base/AndroidManifest.xml.in
mobile/android/base/GeckoApp.java
mobile/android/base/GeckoAppShell.java
mobile/android/base/GeckoInputConnection.java
mobile/android/base/Makefile.in
mobile/android/base/gfx/ImmutableViewportMetrics.java
mobile/android/base/gfx/ViewportMetrics.java
mobile/android/base/ui/PanZoomController.java
mobile/android/chrome/content/aboutAddons.js
mobile/android/chrome/content/browser.js
modules/libpref/src/init/all.js
mozglue/android/APKOpen.cpp
testing/talos/talos.json
toolkit/components/telemetry/TelemetryPing.js
widget/android/AndroidBridge.cpp
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -13,16 +13,17 @@ builtin(include, build/autoconf/altoptio
 builtin(include, build/autoconf/mozprog.m4)dnl
 builtin(include, build/autoconf/mozheader.m4)dnl
 builtin(include, build/autoconf/mozcommonheader.m4)dnl
 builtin(include, build/autoconf/acwinpaths.m4)dnl
 builtin(include, build/autoconf/lto.m4)dnl
 builtin(include, build/autoconf/gcc-pr49911.m4)dnl
 builtin(include, build/autoconf/frameptr.m4)dnl
 builtin(include, build/autoconf/compiler-opts.m4)dnl
+builtin(include, build/autoconf/expandlibs.m4)dnl
 
 MOZ_PROG_CHECKMSYS()
 
 # Read the user's .mozconfig script.  We can't do this in
 # configure.in: autoconf puts the argument parsing code above anything
 # expanded from configure.in, and we need to get the configure options
 # from .mozconfig in place before that argument parsing code.
 MOZ_READ_MOZCONFIG(.)
--- a/browser/base/content/nsContextMenu.js
+++ b/browser/base/content/nsContextMenu.js
@@ -845,17 +845,17 @@ nsContextMenu.prototype = {
   saveVideoFrameAsImage: function () {
     urlSecurityCheck(this.mediaURL, this.browser.contentPrincipal,
                      Ci.nsIScriptSecurityManager.DISALLOW_SCRIPT);
     let name = "";
     try {
       let uri = makeURI(this.mediaURL);
       let url = uri.QueryInterface(Ci.nsIURL);
       if (url.fileBaseName)
-        name = url.fileBaseName + ".jpg";
+        name = decodeURI(url.fileBaseName) + ".jpg";
     } catch (e) { }
     if (!name)
       name = "snapshot.jpg";
     var video = this.target;
     var canvas = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
     canvas.width = video.videoWidth;
     canvas.height = video.videoHeight;
     var ctxDraw = canvas.getContext("2d");
--- a/browser/base/content/test/newtab/Makefile.in
+++ b/browser/base/content/test/newtab/Makefile.in
@@ -15,15 +15,16 @@ include $(topsrcdir)/config/rules.mk
 	browser_newtab_block.js \
 	browser_newtab_disable.js \
 	browser_newtab_drag_drop.js \
 	browser_newtab_drop_preview.js \
 	browser_newtab_private_browsing.js \
 	browser_newtab_reset.js \
 	browser_newtab_tabsync.js \
 	browser_newtab_unpin.js \
+	browser_newtab_bug722273.js \
 	browser_newtab_bug723102.js \
 	browser_newtab_bug723121.js \
 	head.js \
 	$(NULL)
 
 libs::	$(_BROWSER_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/newtab/browser_newtab_bug722273.js
@@ -0,0 +1,62 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const NOW = Date.now() * 1000;
+const URL = "http://fake-site.com/";
+
+let tmp = {};
+Cu.import("resource:///modules/NewTabUtils.jsm", tmp);
+Cc["@mozilla.org/moz/jssubscript-loader;1"]
+  .getService(Ci.mozIJSSubScriptLoader)
+  .loadSubScript("chrome://browser/content/sanitize.js", tmp);
+
+let {NewTabUtils, Sanitizer} = tmp;
+
+let bhist = Cc["@mozilla.org/browser/global-history;2"]
+  .getService(Ci.nsIBrowserHistory);
+
+function runTests() {
+  clearHistory();
+  fillHistory();
+  yield addNewTabPageTab();
+
+  is(cells[0].site.url, URL, "first site is our fake site");
+
+  let page = {
+    update: function () {
+      executeSoon(TestRunner.next);
+    },
+
+    observe: function () {}
+  };
+
+  NewTabUtils.allPages.register(page);
+  yield clearHistory();
+
+  NewTabUtils.allPages.unregister(page);
+  ok(!cells[0].site, "the fake site is gone");
+}
+
+function fillHistory() {
+  let uri = makeURI(URL);
+  for (let i = 59; i > 0; i--)
+    bhist.addPageWithDetails(uri, "fake site", NOW - i * 60 * 1000000);
+}
+
+function clearHistory() {
+  let s = new Sanitizer();
+  s.prefDomain = "privacy.cpd.";
+
+  let prefs = gPrefService.getBranch(s.prefDomain);
+  prefs.setBoolPref("history", true);
+  prefs.setBoolPref("downloads", false);
+  prefs.setBoolPref("cache", false);
+  prefs.setBoolPref("cookies", false);
+  prefs.setBoolPref("formdata", false);
+  prefs.setBoolPref("offlineApps", false);
+  prefs.setBoolPref("passwords", false);
+  prefs.setBoolPref("sessions", false);
+  prefs.setBoolPref("siteSettings", false);
+
+  s.sanitize();
+}
--- a/browser/base/content/test/newtab/head.js
+++ b/browser/base/content/test/newtab/head.js
@@ -124,20 +124,21 @@ function addNewTabPageTab() {
 
   // Wait for the new tab page to be loaded.
   browser.addEventListener("load", function onLoad() {
     browser.removeEventListener("load", onLoad, true);
 
     cw = browser.contentWindow;
 
     if (NewTabUtils.allPages.enabled) {
-      cells = cw.gGrid.cells;
-
       // Continue when the link cache has been populated.
-      NewTabUtils.links.populateCache(TestRunner.next);
+      NewTabUtils.links.populateCache(function () {
+        cells = cw.gGrid.cells;
+        executeSoon(TestRunner.next);
+      });
     } else {
       TestRunner.next();
     }
 
   }, true);
 }
 
 /**
@@ -241,16 +242,18 @@ function unpinCell(aCell) {
 
 /**
  * Simulates a drop and drop operation.
  * @param aDropTarget the cell that is the drop target
  * @param aDragSource the cell that contains the dragged site (optional)
  */
 function simulateDrop(aDropTarget, aDragSource) {
   let event = {
+    clientX: 0,
+    clientY: 0,
     dataTransfer: {
       mozUserCancelled: false,
       setData: function () null,
       setDragImage: function () null,
       getData: function () "about:blank#99\nblank"
     }
   };
 
--- a/browser/components/certerror/content/aboutCertError.css
+++ b/browser/components/certerror/content/aboutCertError.css
@@ -42,25 +42,11 @@
 /* Logical CSS rules belong here, but presentation & theming rules
    should live in the CSS of the appropriate theme */
 
 #technicalContentText {
   overflow: auto;
   white-space: pre-wrap;
 }
 
-#technicalContent > h2, #expertContent > h2 {
-  cursor: pointer;
-  -moz-padding-start: 20px;
-  position: relative;
-  left: -20px;
-}
-
-body[dir="rtl"] #technicalContent > h2,
-body[dir="rtl"] #expertContent > h2 {
-  left: auto;
-  right: -20px;
-}
-
-div[collapsed] > p,
-div[collapsed] > div {
+.expander[collapsed] + * {
   display: none;
 }
--- a/browser/components/certerror/content/aboutCertError.xhtml
+++ b/browser/components/certerror/content/aboutCertError.xhtml
@@ -255,28 +255,28 @@
           <div id="whatShouldIDoContentText">
             <p>&certerror.whatShouldIDo.content;</p>
             <button id='getMeOutOfHereButton'>&certerror.getMeOutOfHere.label;</button>
           </div>
         </div>
         
         <!-- The following sections can be unhidden by default by setting the
              "browser.xul.error_pages.expert_bad_cert" pref to true -->
-        <div id="technicalContent" collapsed="true">
-          <h2 onclick="toggle('technicalContent');" id="technicalContentHeading">&certerror.technical.heading;</h2>
-          <p id="technicalContentText"/>
-        </div>
+        <h2 id="technicalContent" class="expander" collapsed="true">
+          <button onclick="toggle('technicalContent');">&certerror.technical.heading;</button>
+        </h2>
+        <p id="technicalContentText"/>
         
-        <div id="expertContent" collapsed="true">
-          <h2 onclick="toggle('expertContent');" id="expertContentHeading">&certerror.expert.heading;</h2>
-          <div>
-            <p>&certerror.expert.content;</p>
-            <p>&certerror.expert.contentPara2;</p>
-            <button id='exceptionDialogButton'>&certerror.addException.label;</button>
-          </div>
+        <h2 id="expertContent" class="expander" collapsed="true">
+          <button onclick="toggle('expertContent');">&certerror.expert.heading;</button>
+        </h2>
+        <div>
+          <p>&certerror.expert.content;</p>
+          <p>&certerror.expert.contentPara2;</p>
+          <button id='exceptionDialogButton'>&certerror.addException.label;</button>
         </div>
       </div>
     </div>
 
     <!--
     - Note: It is important to run the script this way, instead of using
     - an onload handler. This is because error pages are loaded as
     - LOAD_BACKGROUND, which means that onload handlers will not be executed.
--- a/browser/components/dirprovider/DirectoryProvider.cpp
+++ b/browser/components/dirprovider/DirectoryProvider.cpp
@@ -51,16 +51,17 @@
 #include "nsCategoryManagerUtils.h"
 #include "nsComponentManagerUtils.h"
 #include "nsCOMArray.h"
 #include "nsDirectoryServiceUtils.h"
 #include "mozilla/ModuleUtils.h"
 #include "nsServiceManagerUtils.h"
 #include "nsStringAPI.h"
 #include "nsXULAppAPI.h"
+#include "nsIPrefLocalizedString.h"
 
 namespace mozilla {
 namespace browser {
 
 NS_IMPL_ISUPPORTS2(DirectoryProvider,
                    nsIDirectoryServiceProvider,
                    nsIDirectoryServiceProvider2)
 
@@ -195,17 +196,28 @@ AppendDistroSearchDirs(nsIProperties* aD
     nsCOMPtr<nsIFile> localePlugins;
     rv = searchPlugins->Clone(getter_AddRefs(localePlugins));
     if (NS_FAILED(rv))
       return;
 
     localePlugins->AppendNative(NS_LITERAL_CSTRING("locale"));
 
     nsCString locale;
-    rv = prefs->GetCharPref("general.useragent.locale", getter_Copies(locale));
+    nsCOMPtr<nsIPrefLocalizedString> prefString;
+    rv = prefs->GetComplexValue("general.useragent.locale",
+                                NS_GET_IID(nsIPrefLocalizedString),
+                                getter_AddRefs(prefString));
+    if (NS_SUCCEEDED(rv)) {
+      nsAutoString wLocale;
+      prefString->GetData(getter_Copies(wLocale));
+      CopyUTF16toUTF8(wLocale, locale);
+    } else {
+      rv = prefs->GetCharPref("general.useragent.locale", getter_Copies(locale));
+    }
+
     if (NS_SUCCEEDED(rv)) {
 
       nsCOMPtr<nsIFile> curLocalePlugins;
       rv = localePlugins->Clone(getter_AddRefs(curLocalePlugins));
       if (NS_SUCCEEDED(rv)) {
 
         curLocalePlugins->AppendNative(locale);
         rv = curLocalePlugins->Exists(&exists);
--- a/browser/components/places/content/browserPlacesViews.js
+++ b/browser/components/places/content/browserPlacesViews.js
@@ -652,17 +652,19 @@ PlacesViewBase.prototype = {
         PlacesUtils.livemarks.getLivemark({ id: aPlacesNode.itemId },
           (function (aStatus, aLivemark) {
             if (Components.isSuccessCode(aStatus)) {
               let shouldInvalidate = !aPlacesNode._feedURI;
               aPlacesNode._feedURI = aLivemark.feedURI;
               aPlacesNode._siteURI = aLivemark.siteURI;
               if (aNewState == Ci.nsINavHistoryContainerResultNode.STATE_OPENED) {
                 aLivemark.registerForUpdates(aPlacesNode, this);
+                // Prioritize the current livemark.
                 aLivemark.reload();
+                PlacesUtils.livemarks.reloadLivemarks();
                 if (shouldInvalidate)
                   this.invalidateContainer(aPlacesNode);
               }
               else {
                 aLivemark.unregisterForUpdates(aPlacesNode);
               }
             }
           }).bind(this)
@@ -895,21 +897,16 @@ function PlacesToolbar(aPlace) {
   Services.telemetry.getHistogramById("FX_BOOKMARKS_TOOLBAR_INIT_MS")
                     .add(Date.now() - startTime);
 }
 
 PlacesToolbar.prototype = {
   __proto__: PlacesViewBase.prototype,
 
   _cbEvents: ["dragstart", "dragover", "dragexit", "dragend", "drop",
-#ifdef XP_UNIX
-#ifndef XP_MACOSX
-              "mousedown", "mouseup",
-#endif
-#endif
               "mousemove", "mouseover", "mouseout"],
 
   QueryInterface: function PT_QueryInterface(aIID) {
     if (aIID.equals(Ci.nsIDOMEventListener) ||
         aIID.equals(Ci.nsITimerCallback))
       return this;
 
     return PlacesViewBase.prototype.QueryInterface.apply(this, arguments);
@@ -1096,26 +1093,16 @@ PlacesToolbar.prototype = {
         this._onMouseOver(aEvent);
         break;
       case "mousemove":
         this._onMouseMove(aEvent);
         break;
       case "mouseout":
         this._onMouseOut(aEvent);
         break;
-#ifdef XP_UNIX
-#ifndef XP_MACOSX
-      case "mouseup":
-        this._onMouseUp(aEvent);
-        break;
-      case "mousedown":
-        this._onMouseDown(aEvent);
-        break;
-#endif
-#endif
       case "popupshowing":
         this._onPopupShowing(aEvent);
         break;
       case "popuphidden":
         this._onPopupHidden(aEvent);
         break;
       default:
         throw "Trying to handle unexpected event.";
@@ -1533,24 +1520,16 @@ PlacesToolbar.prototype = {
     let draggedElt = aEvent.target;
     if (draggedElt.parentNode != this._rootElt || !draggedElt._placesNode)
       return;
 
     if (draggedElt.localName == "toolbarbutton" &&
         draggedElt.getAttribute("type") == "menu") {
       // If the drag gesture on a container is toward down we open instead
       // of dragging.
-#ifdef XP_UNIX
-#ifndef XP_MACOSX
-      if (this._mouseDownTimer) {
-        this._mouseDownTimer.cancel();
-        this._mouseDownTimer = null;
-      }
-#endif
-#endif
       let translateY = this._cachedMouseMoveEvent.clientY - aEvent.clientY;
       let translateX = this._cachedMouseMoveEvent.clientX - aEvent.clientX;
       if ((translateY) >= Math.abs(translateX/2)) {
         // Don't start the drag.
         aEvent.preventDefault();
         // Open the menu.
         draggedElt.open = true;
         return;
@@ -1713,57 +1692,16 @@ PlacesToolbar.prototype = {
       // Clear the dragover attribute if present, if we are dragging into a
       // folder in the hierachy of current opened popup we don't clear
       // this attribute on clearOverFolder.  See Notify for closeTimer.
       if (parent.hasAttribute("dragover"))
         parent.removeAttribute("dragover");
     }
   },
 
-#ifdef XP_UNIX
-#ifndef XP_MACOSX
-  _onMouseDown: function PT__onMouseDown(aEvent) {
-    let target = aEvent.target;
-    if (aEvent.button == 0 &&
-        target.localName == "toolbarbutton" &&
-        target.getAttribute("type") == "menu") {
-      this._allowPopupShowing = false;
-      // On Linux we can open the popup only after a delay.
-      // Indeed as soon as the menupopup opens we are unable to start a
-      // drag aEvent.  See bug 500081 for details.
-      this._mouseDownTimer = Cc["@mozilla.org/timer;1"].
-                             createInstance(Ci.nsITimer);
-      let callback = {
-        _self: this,
-        _target: target,
-        notify: function(timer) {
-          this._target.open = true;
-          this._mouseDownTimer = null;
-        }
-      };
-
-      this._mouseDownTimer.initWithCallback(callback, 300,
-                                            Ci.nsITimer.TYPE_ONE_SHOT);
-    }
-  },
-
-  _onMouseUp: function PT__onMouseUp(aEvent) {
-    if (aEvent.button != 0)
-      return;
-
-    if (this._mouseDownTimer) {
-      // On a click (down/up), we should open the menu popup.
-      this._mouseDownTimer.cancel();
-      this._mouseDownTimer = null;
-      aEvent.target.open = true;
-    }
-  },
-#endif
-#endif
-
   _onMouseMove: function PT__onMouseMove(aEvent) {
     // Used in dragStart to prevent dragging folders when dragging down.
     this._cachedMouseMoveEvent = aEvent;
 
     if (this._openedMenuButton == null ||
         PlacesControllerDragHelper.getSession())
       return;
 
--- a/browser/components/places/content/editBookmarkOverlay.xul
+++ b/browser/components/places/content/editBookmarkOverlay.xul
@@ -85,29 +85,27 @@
         <row align="center" id="editBMPanel_feedLocationRow">
           <label value="&editBookmarkOverlay.feedLocation.label;"
                  class="editBMPanel_rowLabel"
                  accesskey="&editBookmarkOverlay.feedLocation.accesskey;"
                  control="editBMPanel_feedLocationField"
                  observes="paneElementsBroadcaster"/>
           <textbox id="editBMPanel_feedLocationField"
                    class="uri-element"
-                   onblur="gEditItemOverlay.onFeedLocationFieldBlur();"
                    observes="paneElementsBroadcaster"/>
         </row>
 
         <row align="center" id="editBMPanel_siteLocationRow">
           <label value="&editBookmarkOverlay.siteLocation.label;"
                  class="editBMPanel_rowLabel"
                  accesskey="&editBookmarkOverlay.siteLocation.accesskey;"
                  control="editBMPanel_siteLocationField"
                  observes="paneElementsBroadcaster"/>
           <textbox id="editBMPanel_siteLocationField"
                    class="uri-element"
-                   onblur="gEditItemOverlay.onSiteLocationFieldBlur();"
                    observes="paneElementsBroadcaster"/>
         </row>
 
         <row align="center" id="editBMPanel_folderRow">
           <label value="&editBookmarkOverlay.folder.label;"
                  class="editBMPanel_rowLabel"
                  control="editBMPanel_folderMenuList"
                  observes="paneElementsBroadcaster"/>
--- a/browser/components/places/content/treeView.js
+++ b/browser/components/places/content/treeView.js
@@ -891,17 +891,19 @@ PlacesTreeView.prototype = {
 
       PlacesUtils.livemarks.getLivemark({ id: aNode.itemId },
         (function (aStatus, aLivemark) {
           if (Components.isSuccessCode(aStatus)) {
             let shouldInvalidate = !aNode._feedURI;
             aNode._feedURI = aLivemark.feedURI;
             if (aNewState == Components.interfaces.nsINavHistoryContainerResultNode.STATE_OPENED) {
               aLivemark.registerForUpdates(aNode, this);
+              // Prioritize the current livemark.
               aLivemark.reload();
+              PlacesUtils.livemarks.reloadLivemarks();
               if (shouldInvalidate)
                 this.invalidateContainer(aNode);
             }
             else {
               aLivemark.unregisterForUpdates(aNode);
             }
           }
         }).bind(this)
--- a/browser/devtools/styleinspector/CssRuleView.jsm
+++ b/browser/devtools/styleinspector/CssRuleView.jsm
@@ -727,18 +727,36 @@ CssRuleView.prototype = {
     }
 
     this._elementStyle = new ElementStyle(aElement, this.store);
     this._elementStyle.onChanged = function() {
       this._changed();
     }.bind(this);
 
     this._createEditors();
+
+    // When creating a new property, we fake the normal property
+    // editor behavior (focusing a property's value after entering its
+    // name) by responding to the name's blur event, creating the
+    // value editor, and grabbing focus to the value editor.  But if
+    // focus has already moved to another document, we won't be able
+    // to move focus to the new editor.
+    // Create a focusable item at the end of the editors to catch these
+    // cases.
+    this._focusBackstop = createChild(this.element, "div", {
+      tabindex: 0,
+    });
+    this._backstopHandler = function() {
+      // If this item is actually focused long enough to get the focus
+      // event, allow focus to move on out of this document.
+      moveFocus(this.doc.defaultView, FOCUS_FORWARD);
+    }.bind(this);
+    this._focusBackstop.addEventListener("focus", this._backstopHandler, false);
   },
-  
+
   /**
    * Update the rules for the currently highlighted element.
    */
   nodeChanged: function CssRuleView_nodeChanged()
   {
     this._clearRules();
     this._elementStyle.populate();
     this._createEditors();
@@ -757,16 +775,22 @@ CssRuleView.prototype = {
   /**
    * Clear the rule view.
    */
   clear: function CssRuleView_clear()
   {
     this._clearRules();
     this._viewedElement = null;
     this._elementStyle = null;
+
+    if (this._focusBackstop) {
+      this._focusBackstop.removeEventListener("focus", this._backstopHandler, false);
+      this._backstopHandler = null;
+      this._focusBackstop = null;
+    }
   },
 
   /**
    * Called when the user has made changes to the ElementStyle.
    * Emits an event that clients can listen to.
    */
   _changed: function CssRuleView_changed()
   {
@@ -840,17 +864,16 @@ RuleEditor.prototype = {
 
     let selectors = createChild(header, "span", {
       class: "ruleview-selector",
       textContent: this.rule.selectorText
     });
 
     this.openBrace = createChild(header, "span", {
       class: "ruleview-ruleopen",
-      tabindex: "0",
       textContent: " {"
     });
 
     this.openBrace.addEventListener("click", function() {
       this.newProperty();
     }.bind(this), true);
 
     this.propertyList = createChild(code, "ul", {
--- a/browser/devtools/styleinspector/test/Makefile.in
+++ b/browser/devtools/styleinspector/test/Makefile.in
@@ -55,16 +55,17 @@ include $(topsrcdir)/config/rules.mk
   browser_bug_692400_element_style.js \
   browser_csslogic_inherited.js \
   browser_ruleview_editor.js \
   browser_ruleview_editor_changedvalues.js \
   browser_ruleview_inherit.js \
   browser_ruleview_manipulation.js \
   browser_ruleview_override.js \
   browser_ruleview_ui.js \
+  browser_ruleview_focus.js \
   browser_bug705707_is_content_stylesheet.js \
   browser_bug722196_property_view_media_queries.js \
   browser_bug722196_rule_view_media_queries.js \
   browser_bug_592743_specificity.js \
   head.js \
   $(NULL)
 
 _BROWSER_TEST_PAGES = \
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleinspector/test/browser_ruleview_focus.js
@@ -0,0 +1,106 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that focus doesn't leave the style editor when adding a property
+// (bug 719916)
+
+let doc;
+let stylePanel;
+
+function waitForRuleView(aCallback)
+{
+  if (InspectorUI.ruleView) {
+    aCallback();
+    return;
+  }
+
+  let ruleViewFrame = InspectorUI.getToolIframe(InspectorUI.ruleViewObject);
+  ruleViewFrame.addEventListener("load", function(evt) {
+    ruleViewFrame.removeEventListener(evt.type, arguments.callee, true);
+    executeSoon(function() {
+      aCallback();
+    });
+  }, true);
+}
+
+function waitForEditorFocus(aParent, aCallback)
+{
+  aParent.addEventListener("focus", function onFocus(evt) {
+    if (evt.target.inplaceEditor) {
+      aParent.removeEventListener("focus", onFocus, true);
+      let editor = evt.target.inplaceEditor;
+      executeSoon(function() {
+        aCallback(editor);
+      });
+    }
+  }, true);
+}
+
+function openRuleView()
+{
+  Services.obs.addObserver(function onOpened() {
+    Services.obs.removeObserver(onOpened,
+    InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
+
+    // Highlight a node.
+    let node = content.document.getElementsByTagName("h1")[0];
+    InspectorUI.inspectNode(node);
+    InspectorUI.stopInspecting();
+
+    // Open the rule view sidebar.
+    waitForRuleView(testFocus);
+
+    InspectorUI.showSidebar();
+    InspectorUI.ruleButton.click();
+
+    testFocus();
+  }, InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
+  InspectorUI.openInspectorUI();
+}
+
+function testFocus()
+{
+  let ruleViewFrame = InspectorUI.getToolIframe(InspectorUI.ruleViewObject);
+  let brace = ruleViewFrame.contentDocument.querySelectorAll(".ruleview-ruleclose")[0];
+  waitForEditorFocus(brace.parentNode, function onNewElement(aEditor) {
+    aEditor.input.value = "color";
+    waitForEditorFocus(brace.parentNode, function onEditingValue(aEditor) {
+      // If we actually get this focus we're ok.
+      ok(true, "We got focus.");
+      aEditor.input.value = "green";
+
+      // If we've retained focus, pressing return will start a new editor.
+      // If not, we'll wait here until we time out.
+      waitForEditorFocus(brace.parentNode, function onNewEditor(aEditor) {
+        aEditor.input.blur();
+        finishTest();
+      });
+      EventUtils.sendKey("return");
+    });
+    EventUtils.sendKey("return");
+  });
+
+  brace.focus();
+}
+
+function finishUp()
+{
+  doc = stylePanel = null;
+  gBrowser.removeCurrentTab();
+  finish();
+}
+
+function test()
+{
+  waitForExplicitFinish();
+  gBrowser.selectedTab = gBrowser.addTab();
+  gBrowser.selectedBrowser.addEventListener("load", function(evt) {
+    gBrowser.selectedBrowser.removeEventListener(evt.type, arguments.callee, true);
+    doc = content.document;
+    doc.title = "Rule View Test";
+    waitForFocus(openRuleView, content);
+  }, true);
+
+  content.location = "data:text/html,<h1>Some header text</h1>";
+}
--- a/browser/modules/NewTabUtils.jsm
+++ b/browser/modules/NewTabUtils.jsm
@@ -116,18 +116,16 @@ let Storage = {
       // Reset to normal DOM storage.
       this.currentStorage = this.domStorage;
 
       // When switching back from private browsing we need to reset the
       // grid and re-read its values from the underlying storage. We don't
       // want any data from private browsing to show up.
       PinnedLinks.resetCache();
       BlockedLinks.resetCache();
-
-      Pages.update();
     }
   },
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
                                          Ci.nsISupportsWeakReference])
 };
 
 /**
@@ -183,37 +181,27 @@ PrivateBrowsingStorage.prototype = {
  */
 let AllPages = {
   /**
    * The array containing all active pages.
    */
   _pages: [],
 
   /**
-   * Tells whether we already added a preference observer.
-   */
-  _observing: false,
-
-  /**
    * Cached value that tells whether the New Tab Page feature is enabled.
    */
   _enabled: null,
 
   /**
    * Adds a page to the internal list of pages.
    * @param aPage The page to register.
    */
   register: function AllPages_register(aPage) {
     this._pages.push(aPage);
-
-    // Add the preference observer if we haven't already.
-    if (!this._observing) {
-      this._observing = true;
-      Services.prefs.addObserver(PREF_NEWTAB_ENABLED, this, true);
-    }
+    this._addObserver();
   },
 
   /**
    * Removes a page from the internal list of pages.
    * @param aPage The page to unregister.
    */
   unregister: function AllPages_unregister(aPage) {
     let index = this._pages.indexOf(aPage);
@@ -234,16 +222,24 @@ let AllPages = {
    * Enables or disables the 'New Tab Page' feature.
    */
   set enabled(aEnabled) {
     if (this.enabled != aEnabled)
       Services.prefs.setBoolPref(PREF_NEWTAB_ENABLED, !!aEnabled);
   },
 
   /**
+   * Returns the number of registered New Tab Pages (i.e. the number of open
+   * about:newtab instances).
+   */
+  get length() {
+    return this._pages.length;
+  },
+
+  /**
    * Updates all currently active pages but the given one.
    * @param aExceptPage The page to exclude from updating.
    */
   update: function AllPages_update(aExceptPage) {
     this._pages.forEach(function (aPage) {
       if (aExceptPage != aPage)
         aPage.update();
     });
@@ -259,16 +255,25 @@ let AllPages = {
 
     let args = Array.slice(arguments);
 
     this._pages.forEach(function (aPage) {
       aPage.observe.apply(aPage, args);
     }, this);
   },
 
+  /**
+   * Adds a preference observer and turns itself into a no-op after the first
+   * invokation.
+   */
+  _addObserver: function AllPages_addObserver() {
+    Services.prefs.addObserver(PREF_NEWTAB_ENABLED, this, true);
+    this._addObserver = function () {};
+  },
+
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
                                          Ci.nsISupportsWeakReference])
 };
 
 /**
  * Singleton that keeps track of all pinned links and their positions in the
  * grid.
  */
@@ -507,16 +512,18 @@ let Links = {
 
     if (this._links && !aForce) {
       executeCallbacks();
     } else {
       this._provider.getLinks(function (aLinks) {
         this._links = aLinks;
         executeCallbacks();
       }.bind(this));
+
+      this._addObserver();
     }
   },
 
   /**
    * Gets the current set of links contained in the grid.
    * @return The links in the grid.
    */
   getLinks: function Links_getLinks() {
@@ -539,17 +546,42 @@ let Links = {
     return pinnedLinks;
   },
 
   /**
    * Resets the links cache.
    */
   resetCache: function Links_resetCache() {
     this._links = [];
-  }
+  },
+
+  /**
+   * Implements the nsIObserver interface to get notified about browser history
+   * sanitization.
+   */
+  observe: function Links_observe(aSubject, aTopic, aData) {
+    // Make sure to update open about:newtab instances. If there are no opened
+    // pages we can just wait for the next new tab to populate the cache again.
+    if (AllPages.length && AllPages.enabled)
+      this.populateCache(function () { AllPages.update() }, true);
+    else
+      this._links = null;
+  },
+
+  /**
+   * Adds a sanitization observer and turns itself into a no-op after the first
+   * invokation.
+   */
+  _addObserver: function Links_addObserver() {
+    Services.obs.addObserver(this, "browser:purge-session-history", true);
+    this._addObserver = function () {};
+  },
+
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
+                                         Ci.nsISupportsWeakReference])
 };
 
 /**
  * Singleton that provides the public API of this JSM.
  */
 let NewTabUtils = {
   /**
    * Resets the NewTabUtils module, its links and its storage.
--- a/browser/themes/gnomestripe/aboutCertError.css
+++ b/browser/themes/gnomestripe/aboutCertError.css
@@ -81,26 +81,29 @@ body[dir="rtl"] #errorPageContainer {
 #errorTitle {
   -moz-margin-start: 80px;
 }
 
 #errorLongContent {
   -moz-margin-start: 80px;
 }
 
-#technicalContent > h2, #expertContent > h2 {
-  background : url("chrome://browser/skin/section_expanded.png") left 0 no-repeat;
-}
-
-body[dir="rtl"] #technicalContent > h2,
-body[dir="rtl"] #expertContent > h2 {
-  background-position: right 0;
+.expander > button {
+  -moz-padding-start: 20px;
+  -moz-margin-start: -20px;
+  background: url("chrome://browser/skin/aboutCertError_sectionExpanded.png") left center no-repeat;
+  border: none;
+  font: inherit;
+  color: inherit;
+  cursor: pointer;
 }
 
-#technicalContent[collapsed] > h2,
-#expertContent[collapsed] > h2{
-  background-image: url("chrome://browser/skin/section_collapsed.png");
+body[dir="rtl"] .expander > button {
+  background-position: right center;
 }
 
-body[dir="rtl"] #technicalContent[collapsed] > h2,
-body[dir="rtl"] #expertContent[collapsed] > h2 {
-  background-image: url("chrome://browser/skin/section_collapsed-rtl.png");
+.expander[collapsed] > button {
+  background-image: url("chrome://browser/skin/aboutCertError_sectionCollapsed.png");
 }
+
+body[dir="rtl"] .expander[collapsed] > button {
+  background-image: url("chrome://browser/skin/aboutCertError_sectionCollapsed-rtl.png");
+}
rename from browser/themes/gnomestripe/section_collapsed-rtl.png
rename to browser/themes/gnomestripe/aboutCertError_sectionCollapsed-rtl.png
rename from browser/themes/gnomestripe/section_collapsed.png
rename to browser/themes/gnomestripe/aboutCertError_sectionCollapsed.png
rename from browser/themes/gnomestripe/section_expanded.png
rename to browser/themes/gnomestripe/aboutCertError_sectionExpanded.png
deleted file mode 100644
--- a/browser/themes/gnomestripe/fullscreen-video.css
+++ /dev/null
@@ -1,8 +0,0 @@
-#close {
-  position: absolute;
-  top: 0;
-  right: 0;
-  width: 32px;
-  height: 32px;
-  background: url(KUI-close.png) center center no-repeat;
-}
--- a/browser/themes/gnomestripe/jar.mn
+++ b/browser/themes/gnomestripe/jar.mn
@@ -1,40 +1,39 @@
 browser.jar:
 % skin browser classic/1.0 %skin/classic/browser/
 % override chrome://global/skin/icons/warning-16.png moz-icon://stock/gtk-dialog-warning?size=menu
   skin/classic/browser/sanitizeDialog.css             (sanitizeDialog.css)
 * skin/classic/browser/aboutPrivateBrowsing.css             (aboutPrivateBrowsing.css)
 * skin/classic/browser/aboutSessionRestore.css        (aboutSessionRestore.css)
   skin/classic/browser/aboutSessionRestore-window-icon.png
-  skin/classic/browser/aboutCertError.css             (aboutCertError.css)
+  skin/classic/browser/aboutCertError.css
+  skin/classic/browser/aboutCertError_sectionCollapsed.png
+  skin/classic/browser/aboutCertError_sectionCollapsed-rtl.png
+  skin/classic/browser/aboutCertError_sectionExpanded.png
 #ifdef MOZ_SERVICES_SYNC
   skin/classic/browser/aboutSyncTabs.css
 #endif
   skin/classic/browser/actionicon-tab.png
 * skin/classic/browser/browser.css                    (browser.css)
 * skin/classic/browser/engineManager.css              (engineManager.css)
-  skin/classic/browser/fullscreen-video.css
   skin/classic/browser/Geolocation-16.png
   skin/classic/browser/Geolocation-64.png
   skin/classic/browser/Go-arrow.png
   skin/classic/browser/identity.png
   skin/classic/browser/Info.png
   skin/classic/browser/KUI-close.png
   skin/classic/browser/monitor.png
   skin/classic/browser/monitor_16-10.png
 * skin/classic/browser/pageInfo.css
   skin/classic/browser/pageInfo.png
   skin/classic/browser/page-livemarks.png
   skin/classic/browser/Privacy-16.png
   skin/classic/browser/Privacy-48.png
   skin/classic/browser/searchbar.css                  (searchbar.css)
-  skin/classic/browser/section_collapsed.png
-  skin/classic/browser/section_collapsed-rtl.png
-  skin/classic/browser/section_expanded.png
   skin/classic/browser/Secure.png
   skin/classic/browser/Security-broken.png
   skin/classic/browser/setDesktopBackground.css
   skin/classic/browser/Toolbar.png
   skin/classic/browser/Toolbar-small.png
   skin/classic/browser/urlbar-arrow.png
   skin/classic/browser/feeds/feedIcon.png             (feeds/feedIcon.png)
   skin/classic/browser/feeds/feedIcon16.png           (feeds/feedIcon16.png)
--- a/browser/themes/pinstripe/aboutCertError.css
+++ b/browser/themes/pinstripe/aboutCertError.css
@@ -81,26 +81,29 @@ body[dir="rtl"] #errorPageContainer {
 #errorTitle {
   -moz-margin-start: 80px;
 }
 
 #errorLongContent {
   -moz-margin-start: 80px;
 }
 
-#technicalContent > h2, #expertContent > h2 {
-  background : url("chrome://browser/skin/section_expanded.png") left 0 no-repeat;
-}
-
-body[dir="rtl"] #technicalContent > h2,
-body[dir="rtl"] #expertContent > h2 {
-  background-position: right 0;
+.expander > button {
+  -moz-padding-start: 20px;
+  -moz-margin-start: -20px;
+  background: url("chrome://browser/skin/aboutCertError_sectionExpanded.png") left center no-repeat;
+  border: none;
+  font: inherit;
+  color: inherit;
+  cursor: pointer;
 }
 
-#technicalContent[collapsed] > h2,
-#expertContent[collapsed] > h2{
-  background-image: url("chrome://browser/skin/section_collapsed.png");
+body[dir="rtl"] .expander > button {
+  background-position: right center;
 }
 
-body[dir="rtl"] #technicalContent[collapsed] > h2,
-body[dir="rtl"] #expertContent[collapsed] > h2 {
-  background-image: url("chrome://browser/skin/section_collapsed-rtl.png");
+.expander[collapsed] > button {
+  background-image: url("chrome://browser/skin/aboutCertError_sectionCollapsed.png");
 }
+
+body[dir="rtl"] .expander[collapsed] > button {
+  background-image: url("chrome://browser/skin/aboutCertError_sectionCollapsed-rtl.png");
+}
rename from browser/themes/pinstripe/section_collapsed-rtl.png
rename to browser/themes/pinstripe/aboutCertError_sectionCollapsed-rtl.png
rename from browser/themes/pinstripe/section_collapsed.png
rename to browser/themes/pinstripe/aboutCertError_sectionCollapsed.png
rename from browser/themes/pinstripe/section_expanded.png
rename to browser/themes/pinstripe/aboutCertError_sectionExpanded.png
deleted file mode 100644
--- a/browser/themes/pinstripe/fullscreen-video.css
+++ /dev/null
@@ -1,8 +0,0 @@
-#close {
-  position: absolute;
-  top: 0;
-  left: 0;
-  width: 32px;
-  height: 32px;
-  background: url(KUI-close.png) center center no-repeat;
-}
--- a/browser/themes/pinstripe/jar.mn
+++ b/browser/themes/pinstripe/jar.mn
@@ -1,22 +1,24 @@
 browser.jar:
 % skin browser classic/1.0 %skin/classic/browser/
   skin/classic/browser/sanitizeDialog.css                   (sanitizeDialog.css)
 * skin/classic/browser/aboutPrivateBrowsing.css             (aboutPrivateBrowsing.css)
 * skin/classic/browser/aboutSessionRestore.css              (aboutSessionRestore.css)
   skin/classic/browser/aboutSessionRestore-window-icon.png
-  skin/classic/browser/aboutCertError.css                   (aboutCertError.css)
+  skin/classic/browser/aboutCertError.css
+  skin/classic/browser/aboutCertError_sectionCollapsed.png
+  skin/classic/browser/aboutCertError_sectionCollapsed-rtl.png
+  skin/classic/browser/aboutCertError_sectionExpanded.png
 #ifdef MOZ_SERVICES_SYNC
   skin/classic/browser/aboutSyncTabs.css
 #endif
   skin/classic/browser/actionicon-tab.png
 * skin/classic/browser/browser.css                          (browser.css)
 * skin/classic/browser/engineManager.css                    (engineManager.css)
-  skin/classic/browser/fullscreen-video.css
   skin/classic/browser/Geolocation-16.png
   skin/classic/browser/Geolocation-64.png
   skin/classic/browser/home.png
   skin/classic/browser/hud-style-check-box-checked.png
   skin/classic/browser/hud-style-check-box-empty.png
   skin/classic/browser/hud-style-dropmarker-double-arrows.png
   skin/classic/browser/hud-style-expander-closed.png
   skin/classic/browser/hud-style-expander-open.png
@@ -31,19 +33,16 @@ browser.jar:
   skin/classic/browser/page-livemarks.png
   skin/classic/browser/pageInfo.css
   skin/classic/browser/Privacy-16.png
   skin/classic/browser/Privacy-48.png
   skin/classic/browser/reload-stop-go.png
   skin/classic/browser/searchbar-dropmarker.png
   skin/classic/browser/searchbar.css
   skin/classic/browser/Search.png
-  skin/classic/browser/section_collapsed.png
-  skin/classic/browser/section_collapsed-rtl.png
-  skin/classic/browser/section_expanded.png
   skin/classic/browser/Secure-Glyph-White.png
   skin/classic/browser/keyhole-circle.png
   skin/classic/browser/Toolbar.png
   skin/classic/browser/toolbarbutton-dropmarker.png
   skin/classic/browser/urlbar-history-dropmarker.png
   skin/classic/browser/urlbar-arrow.png
   skin/classic/browser/urlbar-popup-blocked.png
   skin/classic/browser/feeds/subscribe.css                  (feeds/subscribe.css)
--- a/browser/themes/winstripe/aboutCertError.css
+++ b/browser/themes/winstripe/aboutCertError.css
@@ -81,26 +81,29 @@ body[dir="rtl"] #errorPageContainer {
 #errorTitle {
   -moz-margin-start: 80px;
 }
 
 #errorLongContent {
   -moz-margin-start: 80px;
 }
 
-#technicalContent > h2, #expertContent > h2 {
-  background : url("chrome://browser/skin/section_expanded.png") left center no-repeat;
+.expander > button {
+  -moz-padding-start: 20px;
+  -moz-margin-start: -20px;
+  background: url("chrome://browser/skin/aboutCertError_sectionExpanded.png") left center no-repeat;
+  border: none;
+  font: inherit;
+  color: inherit;
+  cursor: pointer;
 }
 
-body[dir="rtl"] #technicalContent > h2,
-body[dir="rtl"] #expertContent > h2 {
+body[dir="rtl"] .expander > button {
   background-position: right center;
 }
 
-#technicalContent[collapsed] > h2,
-#expertContent[collapsed] > h2{
-  background-image: url("chrome://browser/skin/section_collapsed.png");
+.expander[collapsed] > button {
+  background-image: url("chrome://browser/skin/aboutCertError_sectionCollapsed.png");
 }
 
-body[dir="rtl"] #technicalContent[collapsed] > h2,
-body[dir="rtl"] #expertContent[collapsed] > h2 {
-  background-image: url("chrome://browser/skin/section_collapsed-rtl.png");
+body[dir="rtl"] .expander[collapsed] > button {
+  background-image: url("chrome://browser/skin/aboutCertError_sectionCollapsed-rtl.png");
 }
rename from browser/themes/winstripe/section_collapsed-rtl.png
rename to browser/themes/winstripe/aboutCertError_sectionCollapsed-rtl.png
rename from browser/themes/winstripe/section_collapsed.png
rename to browser/themes/winstripe/aboutCertError_sectionCollapsed.png
rename from browser/themes/winstripe/section_expanded.png
rename to browser/themes/winstripe/aboutCertError_sectionExpanded.png
deleted file mode 100644
--- a/browser/themes/winstripe/fullscreen-video.css
+++ /dev/null
@@ -1,8 +0,0 @@
-#close {
-  position: absolute;
-  top: 0;
-  right: 0;
-  width: 32px;
-  height: 32px;
-  background: url(KUI-close.png) center center no-repeat;
-}
--- a/browser/themes/winstripe/jar.mn
+++ b/browser/themes/winstripe/jar.mn
@@ -2,26 +2,28 @@ browser.jar:
 % skin browser classic/1.0 %skin/classic/browser/ os=WINNT osversion<6
 % skin browser classic/1.0 %skin/classic/browser/ os!=WINNT
 # NOTE: If you add a new file here, you'll need to add it to the aero
 # section at the bottom of this file
         skin/classic/browser/sanitizeDialog.css                      (sanitizeDialog.css)
 *       skin/classic/browser/aboutPrivateBrowsing.css                (aboutPrivateBrowsing.css)
 *       skin/classic/browser/aboutSessionRestore.css                 (aboutSessionRestore.css)
         skin/classic/browser/aboutSessionRestore-window-icon.png     (preferences/application.png)
-        skin/classic/browser/aboutCertError.css                      (aboutCertError.css)
+        skin/classic/browser/aboutCertError.css
+        skin/classic/browser/aboutCertError_sectionCollapsed.png
+        skin/classic/browser/aboutCertError_sectionCollapsed-rtl.png
+        skin/classic/browser/aboutCertError_sectionExpanded.png
 #ifdef MOZ_SERVICES_SYNC
         skin/classic/browser/aboutSyncTabs.css
 #endif
         skin/classic/browser/actionicon-tab.png
         skin/classic/browser/appmenu-icons.png
         skin/classic/browser/appmenu-dropmarker.png
 *       skin/classic/browser/browser.css                             (browser.css)
 *       skin/classic/browser/engineManager.css                       (engineManager.css)
-        skin/classic/browser/fullscreen-video.css
         skin/classic/browser/Geolocation-16.png
         skin/classic/browser/Geolocation-64.png
         skin/classic/browser/Info.png                                (Info.png)
         skin/classic/browser/identity.png                            (identity.png)
         skin/classic/browser/keyhole-forward-mask.svg
         skin/classic/browser/KUI-background.png
         skin/classic/browser/KUI-close.png
         skin/classic/browser/pageInfo.css
@@ -33,19 +35,16 @@ browser.jar:
         skin/classic/browser/reload-stop-go.png
         skin/classic/browser/Secure24.png                            (Secure24.png)
         skin/classic/browser/Toolbar.png                             (Toolbar.png)
         skin/classic/browser/Toolbar-inverted.png
         skin/classic/browser/toolbarbutton-dropdown-arrow.png
         skin/classic/browser/toolbarbutton-dropdown-arrow-inverted.png
 *       skin/classic/browser/searchbar.css                           (searchbar.css)
         skin/classic/browser/searchbar-dropdown-arrow.png
-        skin/classic/browser/section_collapsed.png
-        skin/classic/browser/section_collapsed-rtl.png
-        skin/classic/browser/section_expanded.png
         skin/classic/browser/setDesktopBackground.css
         skin/classic/browser/menu-back.png                           (menu-back.png)
         skin/classic/browser/menu-forward.png                        (menu-forward.png)
         skin/classic/browser/monitor.png
         skin/classic/browser/monitor_16-10.png
         skin/classic/browser/urlbar-arrow.png
         skin/classic/browser/urlbar-popup-blocked.png
         skin/classic/browser/urlbar-history-dropmarker.png
@@ -172,26 +171,28 @@ browser.jar:
 
 #ifdef XP_WIN
 browser.jar:
 % skin browser classic/1.0 %skin/classic/aero/browser/ os=WINNT osversion>=6
         skin/classic/aero/browser/sanitizeDialog.css                       (sanitizeDialog.css)
 *       skin/classic/aero/browser/aboutPrivateBrowsing.css           (aboutPrivateBrowsing.css)
 *       skin/classic/aero/browser/aboutSessionRestore.css            (aboutSessionRestore.css)
         skin/classic/aero/browser/aboutSessionRestore-window-icon.png (aboutSessionRestore-window-icon-aero.png)
-        skin/classic/aero/browser/aboutCertError.css                 (aboutCertError.css)
+        skin/classic/aero/browser/aboutCertError.css
+        skin/classic/aero/browser/aboutCertError_sectionCollapsed.png
+        skin/classic/aero/browser/aboutCertError_sectionCollapsed-rtl.png
+        skin/classic/aero/browser/aboutCertError_sectionExpanded.png
 #ifdef MOZ_SERVICES_SYNC
         skin/classic/aero/browser/aboutSyncTabs.css
 #endif
         skin/classic/aero/browser/actionicon-tab.png                 (actionicon-tab.png)
         skin/classic/aero/browser/appmenu-dropmarker.png
         skin/classic/aero/browser/appmenu-icons.png
 *       skin/classic/aero/browser/browser.css                        (browser-aero.css)
 *       skin/classic/aero/browser/engineManager.css                  (engineManager.css)
-        skin/classic/aero/browser/fullscreen-video.css
         skin/classic/aero/browser/Geolocation-16.png
         skin/classic/aero/browser/Geolocation-64.png
         skin/classic/aero/browser/Info.png                           (Info-aero.png)
         skin/classic/aero/browser/identity.png                       (identity-aero.png)
         skin/classic/aero/browser/keyhole-forward-mask.svg
         skin/classic/aero/browser/KUI-background.png
         skin/classic/aero/browser/KUI-close.png
         skin/classic/aero/browser/pageInfo.css
@@ -203,19 +204,16 @@ browser.jar:
         skin/classic/aero/browser/reload-stop-go.png
         skin/classic/aero/browser/Secure24.png                       (Secure24-aero.png)
         skin/classic/aero/browser/Toolbar.png
         skin/classic/aero/browser/Toolbar-inverted.png
         skin/classic/aero/browser/toolbarbutton-dropdown-arrow.png
         skin/classic/aero/browser/toolbarbutton-dropdown-arrow-inverted.png
 *       skin/classic/aero/browser/searchbar.css                      (searchbar.css)
         skin/classic/aero/browser/searchbar-dropdown-arrow.png       (searchbar-dropdown-arrow-aero.png)
-        skin/classic/aero/browser/section_collapsed.png
-        skin/classic/aero/browser/section_collapsed-rtl.png
-        skin/classic/aero/browser/section_expanded.png
         skin/classic/aero/browser/setDesktopBackground.css
         skin/classic/aero/browser/menu-back.png                      (menu-back-aero.png)
         skin/classic/aero/browser/menu-forward.png                   (menu-forward-aero.png)
         skin/classic/aero/browser/monitor.png
         skin/classic/aero/browser/monitor_16-10.png
         skin/classic/aero/browser/urlbar-arrow.png
         skin/classic/aero/browser/urlbar-popup-blocked.png
         skin/classic/aero/browser/urlbar-history-dropmarker.png
rename from build/unix/check_debug_ranges.py
rename to build/autoconf/check_debug_ranges.py
--- a/build/autoconf/compiler-opts.m4
+++ b/build/autoconf/compiler-opts.m4
@@ -4,10 +4,81 @@ AC_DEFUN([MOZ_COMPILER_OPTS],
 [
 if test "$CLANG_CXX"; then
     ## We disable return-type-c-linkage because jsval is defined as a C++ type but is
     ## returned by C functions. This is possible because we use knowledge about the ABI
     ## to typedef it to a C type with the same layout when the headers are included
     ## from C.
     _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wno-unknown-warning-option -Wno-return-type-c-linkage"
 fi
+
+if test "$GNU_CC"; then
+    CFLAGS="$CFLAGS -ffunction-sections -fdata-sections"
+    CXXFLAGS="$CXXFLAGS -ffunction-sections -fdata-sections"
+fi
+
+dnl ========================================================
+dnl = Identical Code Folding
+dnl ========================================================
+
+MOZ_ARG_DISABLE_BOOL(icf,
+[  --disable-icf          Disable Identical Code Folding],
+    MOZ_DISABLE_ICF=1,
+    MOZ_DISABLE_ICF= )
+
+if test "$GNU_CC" -a "$GCC_USE_GNU_LD" -a -z "$MOZ_DISABLE_ICF"; then
+    AC_CACHE_CHECK([whether the linker supports Identical Code Folding],
+        LD_SUPPORTS_ICF,
+        [echo 'int foo() {return 42;}' \
+              'int bar() {return 42;}' \
+              'int main() {return foo() - bar();}' > conftest.${ac_ext}
+        # If the linker supports ICF, foo and bar symbols will have
+        # the same address
+        if AC_TRY_COMMAND([${CC-cc} -o conftest${ac_exeext} $LDFLAGS -Wl,--icf=safe -ffunction-sections conftest.${ac_ext} $LIBS 1>&2]) &&
+           test -s conftest${ac_exeext} &&
+           objdump -t conftest${ac_exeext} | awk changequote(<<, >>)'{a[<<$>>6] = <<$>>1} END {if (a["foo"] && (a["foo"] != a["bar"])) { exit 1 }}'changequote([, ]); then
+            LD_SUPPORTS_ICF=yes
+        else
+            LD_SUPPORTS_ICF=no
+        fi
+        rm -rf conftest*])
+    if test "$LD_SUPPORTS_ICF" = yes; then
+        _SAVE_LDFLAGS="$LDFLAGS -Wl,--icf=safe"
+        LDFLAGS="$LDFLAGS -Wl,--icf=safe -Wl,--print-icf-sections"
+        AC_TRY_LINK([], [],
+                    [LD_PRINT_ICF_SECTIONS=-Wl,--print-icf-sections],
+                    [LD_PRINT_ICF_SECTIONS=])
+        AC_SUBST([LD_PRINT_ICF_SECTIONS])
+        LDFLAGS="$_SAVE_LDFLAGS"
+    fi
+fi
+
+dnl ========================================================
+dnl = Automatically remove dead symbols
+dnl ========================================================
+
+if test "$GNU_CC" -a "$GCC_USE_GNU_LD" -a -n "$MOZ_DEBUG_FLAGS"; then
+   dnl See bug 670659
+   AC_CACHE_CHECK([whether removing dead symbols breaks debugging],
+       GC_SECTIONS_BREAKS_DEBUG_RANGES,
+       [echo 'int foo() {return 42;}' \
+             'int bar() {return 1;}' \
+             'int main() {return foo();}' > conftest.${ac_ext}
+        if AC_TRY_COMMAND([${CC-cc} -o conftest.${ac_objext} $CFLAGS $MOZ_DEBUG_FLAGS -c conftest.${ac_ext} 1>&2]) &&
+           AC_TRY_COMMAND([${CC-cc} -o conftest${ac_exeext} $LDFLAGS $MOZ_DEBUG_FLAGS -Wl,--gc-sections conftest.${ac_objext} $LIBS 1>&2]) &&
+           test -s conftest${ac_exeext} -a -s conftest.${ac_objext}; then
+            if test "`$PYTHON "$_topsrcdir"/build/autoconf/check_debug_ranges.py conftest.${ac_objext} conftest.${ac_ext}`" = \
+                    "`$PYTHON "$_topsrcdir"/build/autoconf/check_debug_ranges.py conftest${ac_exeext} conftest.${ac_ext}`"; then
+                GC_SECTIONS_BREAKS_DEBUG_RANGES=no
+            else
+                GC_SECTIONS_BREAKS_DEBUG_RANGES=yes
+            fi
+        else
+             dnl We really don't expect to get here, but just in case
+             GC_SECTIONS_BREAKS_DEBUG_RANGES="no, but it's broken in some other way"
+        fi
+        rm -rf conftest*])
+    if test "$GC_SECTIONS_BREAKS_DEBUG_RANGES" = no; then
+        DSO_LDOPTS="$DSO_LDOPTS -Wl,--gc-sections"
+    fi
+fi
+
 ])
-
new file mode 100644
--- /dev/null
+++ b/build/autoconf/expandlibs.m4
@@ -0,0 +1,56 @@
+AC_DEFUN([MOZ_EXPAND_LIBS],
+[
+dnl ========================================================
+dnl =
+dnl = Check what kind of list files are supported by the
+dnl = linker
+dnl =
+dnl ========================================================
+
+AC_CACHE_CHECK(what kind of list files are supported by the linker,
+    EXPAND_LIBS_LIST_STYLE,
+    [echo "int main() {return 0;}" > conftest.${ac_ext}
+     if AC_TRY_COMMAND(${CC-cc} -o conftest.${OBJ_SUFFIX} -c $CFLAGS $CPPFLAGS conftest.${ac_ext} 1>&5) && test -s conftest.${OBJ_SUFFIX}; then
+         echo "INPUT(conftest.${OBJ_SUFFIX})" > conftest.list
+         if AC_TRY_COMMAND(${CC-cc} -o conftest${ac_exeext} $LDFLAGS conftest.list $LIBS 1>&5) && test -s conftest${ac_exeext}; then
+             EXPAND_LIBS_LIST_STYLE=linkerscript
+         else
+             echo "conftest.${OBJ_SUFFIX}" > conftest.list
+             if AC_TRY_COMMAND(${CC-cc} -o conftest${ac_exeext} $LDFLAGS @conftest.list $LIBS 1>&5) && test -s conftest${ac_exeext}; then
+                 EXPAND_LIBS_LIST_STYLE=list
+             else
+                 EXPAND_LIBS_LIST_STYLE=none
+             fi
+         fi
+     else
+         dnl We really don't expect to get here, but just in case
+         AC_ERROR([couldn't compile a simple C file])
+     fi
+     rm -rf conftest*])
+
+LIBS_DESC_SUFFIX=desc
+AC_SUBST(LIBS_DESC_SUFFIX)
+AC_SUBST(EXPAND_LIBS_LIST_STYLE)
+
+if test "$GCC_USE_GNU_LD"; then
+    AC_CACHE_CHECK(what kind of ordering can be done with the linker,
+        EXPAND_LIBS_ORDER_STYLE,
+        [> conftest.order
+         _SAVE_LDFLAGS="$LDFLAGS"
+         LDFLAGS="${LDFLAGS} -Wl,--section-ordering-file,conftest.order"
+         AC_TRY_LINK([], [],
+             EXPAND_LIBS_ORDER_STYLE=section-ordering-file,
+             EXPAND_LIBS_ORDER_STYLE=)
+         LDFLAGS="$_SAVE_LDFLAGS"
+         if test -z "$EXPAND_LIBS_ORDER_STYLE"; then
+             if AC_TRY_COMMAND(${CC-cc} ${DSO_LDOPTS} ${LDFLAGS} -o ${DLL_PREFIX}conftest${DLL_SUFFIX} -Wl,--verbose 2> /dev/null | sed -n '/^===/,/^===/p' | grep '\.text'); then
+                 EXPAND_LIBS_ORDER_STYLE=linkerscript
+             else
+                 EXPAND_LIBS_ORDER_STYLE=none
+             fi
+             rm -f ${DLL_PREFIX}conftest${DLL_SUFFIX}
+         fi])
+fi
+AC_SUBST(EXPAND_LIBS_ORDER_STYLE)
+
+])
--- a/build/automationutils.py
+++ b/build/automationutils.py
@@ -454,17 +454,17 @@ def wrapCommand(cmd):
   return cmd
 
 class ShutdownLeakLogger(object):
   """
   Parses the mochitest run log when running a debug build, assigns all leaked
   DOM windows (that are still around after test suite shutdown, despite running
   the GC) to the tests that created them and prints leak statistics.
   """
-  MAX_LEAK_COUNT = 123
+  MAX_LEAK_COUNT = 120
 
   def __init__(self, logger):
     self.logger = logger
     self.tests = []
     self.leakedWindows = {}
     self.leakedDocShells = set()
     self.currentTest = None
     self.seenShutdown = False
--- a/config/config.mk
+++ b/config/config.mk
@@ -784,18 +784,22 @@ OPTIMIZE_JARS_CMD = $(PYTHON) $(call cor
 CREATE_PRECOMPLETE_CMD = $(PYTHON) $(call core_abspath,$(topsrcdir)/config/createprecomplete.py)
 
 EXPAND_LIBS = $(PYTHON) -I$(DEPTH)/config $(topsrcdir)/config/expandlibs.py
 EXPAND_LIBS_EXEC = $(PYTHON) $(topsrcdir)/config/pythonpath.py -I$(DEPTH)/config $(topsrcdir)/config/expandlibs_exec.py
 EXPAND_LIBS_GEN = $(PYTHON) $(topsrcdir)/config/pythonpath.py -I$(DEPTH)/config $(topsrcdir)/config/expandlibs_gen.py
 EXPAND_AR = $(EXPAND_LIBS_EXEC) --extract -- $(AR)
 EXPAND_CC = $(EXPAND_LIBS_EXEC) --uselist -- $(CC)
 EXPAND_CCC = $(EXPAND_LIBS_EXEC) --uselist -- $(CCC)
-EXPAND_LD = $(EXPAND_LIBS_EXEC) --uselist $(if $(REORDER),--reorder $(REORDER))-- $(LD)
-EXPAND_MKSHLIB = $(EXPAND_LIBS_EXEC) --uselist $(if $(REORDER),--reorder $(REORDER))-- $(MKSHLIB)
+EXPAND_LD = $(EXPAND_LIBS_EXEC) --uselist -- $(LD)
+EXPAND_MKSHLIB_ARGS = --uselist
+ifdef SYMBOL_ORDER
+EXPAND_MKSHLIB_ARGS += --symbol-order $(SYMBOL_ORDER)
+endif
+EXPAND_MKSHLIB = $(EXPAND_LIBS_EXEC) $(EXPAND_MKSHLIB_ARGS) -- $(MKSHLIB)
 
 ifdef STDCXX_COMPAT
 ifneq ($(OS_ARCH),Darwin)
 CHECK_STDCXX = objdump -p $(1) | grep -e 'GLIBCXX_3\.4\.\(9\|[1-9][0-9]\)' > /dev/null && echo "TEST-UNEXPECTED-FAIL | | We don't want these libstdc++ symbols to be used:" && objdump -T $(1) | grep -e 'GLIBCXX_3\.4\.\(9\|[1-9][0-9]\)' && exit 1 || exit 0
 endif
 endif
 
 # autoconf.mk sets OBJ_SUFFIX to an error to avoid use before including
--- a/config/expandlibs_config.py.in
+++ b/config/expandlibs_config.py.in
@@ -49,8 +49,10 @@ AR_EXTRACT = "@AR_EXTRACT@".replace('$(A
 DLL_PREFIX = "@DLL_PREFIX@"
 LIB_PREFIX = "@LIB_PREFIX@"
 OBJ_SUFFIX = normalize_suffix("@OBJ_SUFFIX@")
 LIB_SUFFIX = normalize_suffix("@LIB_SUFFIX@")
 DLL_SUFFIX = normalize_suffix("@DLL_SUFFIX@")
 IMPORT_LIB_SUFFIX = normalize_suffix("@IMPORT_LIB_SUFFIX@")
 LIBS_DESC_SUFFIX = normalize_suffix("@LIBS_DESC_SUFFIX@")
 EXPAND_LIBS_LIST_STYLE = "@EXPAND_LIBS_LIST_STYLE@"
+EXPAND_LIBS_ORDER_STYLE = "@EXPAND_LIBS_ORDER_STYLE@"
+LD_PRINT_ICF_SECTIONS = "@LD_PRINT_ICF_SECTIONS@"
--- a/config/expandlibs_exec.py
+++ b/config/expandlibs_exec.py
@@ -44,29 +44,41 @@ from static libraries (or use those list
 
 With the --uselist argument (useful for e.g. $(CC)), it replaces all object
 files with a list file. This can be used to avoid limitations in the length
 of a command line. The kind of list file format used depends on the
 EXPAND_LIBS_LIST_STYLE variable: 'list' for MSVC style lists (@file.list)
 or 'linkerscript' for GNU ld linker scripts.
 See https://bugzilla.mozilla.org/show_bug.cgi?id=584474#c59 for more details.
 
-With the --reorder argument, followed by a file name, it will reorder the
-object files from the command line according to the order given in the file.
-Implies --extract.
+With the --symbol-order argument, followed by a file name, it will add the
+relevant linker options to change the order in which the linker puts the
+symbols appear in the resulting binary. Only works for ELF targets.
 '''
 from __future__ import with_statement
 import sys
 import os
 from expandlibs import ExpandArgs, relativize, isObject
 import expandlibs_config as conf
 from optparse import OptionParser
 import subprocess
 import tempfile
 import shutil
+import subprocess
+import re
+
+# The are the insert points for a GNU ld linker script, assuming a more
+# or less "standard" default linker script. This is not a dict because
+# order is important.
+SECTION_INSERT_BEFORE = [
+  ('.text', '.fini'),
+  ('.rodata', '.rodata1'),
+  ('.data.rel.ro', '.dynamic'),
+  ('.data', '.data1'),
+]
 
 class ExpandArgsMore(ExpandArgs):
     ''' Meant to be used as 'with ExpandArgsMore(args) as ...: '''
     def __enter__(self):
         self.tmp = []
         return self
         
     def __exit__(self, type, value, tb):
@@ -114,61 +126,203 @@ class ExpandArgsMore(ExpandArgs):
         fd, tmp = tempfile.mkstemp(suffix=".list",dir=os.curdir)
         if conf.EXPAND_LIBS_LIST_STYLE == "linkerscript":
             content = ["INPUT(%s)\n" % obj for obj in objs]
             ref = tmp
         elif conf.EXPAND_LIBS_LIST_STYLE == "list":
             content = ["%s\n" % obj for obj in objs]
             ref = "@" + tmp
         else:
+            os.close(fd)
             os.remove(tmp)
             return
         self.tmp.append(tmp)
         f = os.fdopen(fd, "w")
         f.writelines(content)
         f.close()
         idx = self.index(objs[0])
         newlist = self[0:idx] + [ref] + [item for item in self[idx:] if item not in objs]
         self[0:] = newlist
 
-    def reorder(self, order_list):
-        '''Given a list of file names without OBJ_SUFFIX, rearrange self
-        so that the object file names it contains are ordered according to
-        that list.
-        '''
-        objs = [o for o in self if isObject(o)]
-        if not objs: return
-        idx = self.index(objs[0])
-        # Keep everything before the first object, then the ordered objects,
-        # then any other objects, then any non-objects after the first object
-        objnames = dict([(os.path.splitext(os.path.basename(o))[0], o) for o in objs])
-        self[0:] = self[0:idx] + [objnames[o] for o in order_list if o in objnames] + \
-                   [o for o in objs if os.path.splitext(os.path.basename(o))[0] not in order_list] + \
-                   [x for x in self[idx:] if not isObject(x)]
+    def _getFoldedSections(self):
+        '''Returns a dict about folded sections.
+        When section A and B are folded into section C, the dict contains:
+        { 'A': 'C',
+          'B': 'C',
+          'C': ['A', 'B'] }'''
+        if not conf.LD_PRINT_ICF_SECTIONS:
+            return {}
+
+        proc = subprocess.Popen(self + [conf.LD_PRINT_ICF_SECTIONS], stdout = subprocess.PIPE, stderr = subprocess.PIPE)
+        (stdout, stderr) = proc.communicate()
+        result = {}
+        # gold's --print-icf-sections output looks like the following:
+        # ld: ICF folding section '.section' in file 'file.o'into '.section' in file 'file.o'
+        # In terms of words, chances are this will change in the future,
+        # especially considering "into" is misplaced. Splitting on quotes
+        # seems safer.
+        for l in stderr.split('\n'):
+            quoted = l.split("'")
+            if len(quoted) > 5 and quoted[1] != quoted[5]:
+                result[quoted[1]] = quoted[5]
+                if quoted[5] in result:
+                    result[quoted[5]].append(quoted[1])
+                else:
+                    result[quoted[5]] = [quoted[1]]
+        return result
+
+    def _getOrderedSections(self, ordered_symbols):
+        '''Given an ordered list of symbols, returns the corresponding list
+        of sections following the order.'''
+        if not conf.EXPAND_LIBS_ORDER_STYLE in ['linkerscript', 'section-ordering-file']:
+            raise Exception('EXPAND_LIBS_ORDER_STYLE "%s" is not supported' % conf.EXPAND_LIBS_ORDER_STYLE)
+        finder = SectionFinder([arg for arg in self if isObject(arg) or os.path.splitext(arg)[1] == conf.LIB_SUFFIX])
+        folded = self._getFoldedSections()
+        sections = set()
+        ordered_sections = []
+        for symbol in ordered_symbols:
+            symbol_sections = finder.getSections(symbol)
+            all_symbol_sections = []
+            for section in symbol_sections:
+                if section in folded:
+                    if isinstance(folded[section], str):
+                        section = folded[section]
+                    all_symbol_sections.append(section)
+                    all_symbol_sections.extend(folded[section])
+                else:
+                    all_symbol_sections.append(section)
+            for section in all_symbol_sections:
+                if not section in sections:
+                    ordered_sections.append(section)
+                    sections.add(section)
+        return ordered_sections
+
+    def orderSymbols(self, order):
+        '''Given a file containing a list of symbols, adds the appropriate
+        argument to make the linker put the symbols in that order.'''
+        with open(order) as file:
+            sections = self._getOrderedSections([l.strip() for l in file.readlines() if l.strip()])
+        split_sections = {}
+        linked_sections = [s[0] for s in SECTION_INSERT_BEFORE]
+        for s in sections:
+            for linked_section in linked_sections:
+                if s.startswith(linked_section):
+                    if linked_section in split_sections:
+                        split_sections[linked_section].append(s)
+                    else:
+                        split_sections[linked_section] = [s]
+                    break
+        content = []
+        # Order is important
+        linked_sections = [s for s in linked_sections if s in split_sections]
 
+        if conf.EXPAND_LIBS_ORDER_STYLE == 'section-ordering-file':
+            option = '-Wl,--section-ordering-file,%s'
+            content = sections
+            for linked_section in linked_sections:
+                content.extend(split_sections[linked_section])
+                content.append('%s.*' % linked_section)
+                content.append(linked_section)
+
+        elif conf.EXPAND_LIBS_ORDER_STYLE == 'linkerscript':
+            option = '-Wl,-T,%s'
+            section_insert_before = dict(SECTION_INSERT_BEFORE)
+            for linked_section in linked_sections:
+                content.append('SECTIONS {')
+                content.append('  %s : {' % linked_section)
+                content.extend('    *(%s)' % s for s in split_sections[linked_section])
+                content.append('  }')
+                content.append('}')
+                content.append('INSERT BEFORE %s' % section_insert_before[linked_section])
+        else:
+            raise Exception('EXPAND_LIBS_ORDER_STYLE "%s" is not supported' % conf.EXPAND_LIBS_ORDER_STYLE)
+
+        fd, tmp = tempfile.mkstemp(dir=os.curdir)
+        f = os.fdopen(fd, "w")
+        f.write('\n'.join(content)+'\n')
+        f.close()
+        self.tmp.append(tmp)
+        self.append(option % tmp)
+
+class SectionFinder(object):
+    '''Instances of this class allow to map symbol names to sections in
+    object files.'''
+
+    def __init__(self, objs):
+        '''Creates an instance, given a list of object files.'''
+        if not conf.EXPAND_LIBS_ORDER_STYLE in ['linkerscript', 'section-ordering-file']:
+            raise Exception('EXPAND_LIBS_ORDER_STYLE "%s" is not supported' % conf.EXPAND_LIBS_ORDER_STYLE)
+        self.mapping = {}
+        for obj in objs:
+            if not isObject(obj) and os.path.splitext(obj)[1] != conf.LIB_SUFFIX:
+                raise Exception('%s is not an object nor a static library' % obj)
+            for symbol, section in SectionFinder._getSymbols(obj):
+                sym = SectionFinder._normalize(symbol)
+                if sym in self.mapping:
+                    if not section in self.mapping[sym]:
+                        self.mapping[sym].append(section)
+                else:
+                    self.mapping[sym] = [section]
+
+    def getSections(self, symbol):
+        '''Given a symbol, returns a list of sections containing it or the
+        corresponding thunks. When the given symbol is a thunk, returns the
+        list of sections containing its corresponding normal symbol and the
+        other thunks for that symbol.'''
+        sym = SectionFinder._normalize(symbol)
+        if sym in self.mapping:
+            return self.mapping[sym]
+        return []
+
+    @staticmethod
+    def _normalize(symbol):
+        '''For normal symbols, return the given symbol. For thunks, return
+        the corresponding normal symbol.'''
+        if re.match('^_ZThn[0-9]+_', symbol):
+            return re.sub('^_ZThn[0-9]+_', '_Z', symbol)
+        return symbol
+
+    @staticmethod
+    def _getSymbols(obj):
+        '''Returns a list of (symbol, section) contained in the given object
+        file.'''
+        proc = subprocess.Popen(['objdump', '-t', obj], stdout = subprocess.PIPE, stderr = subprocess.PIPE)
+        (stdout, stderr) = proc.communicate()
+        syms = []
+        for line in stdout.splitlines():
+            # Each line has the following format:
+            # <addr> [lgu!][w ][C ][W ][Ii ][dD ][FfO ] <section>\t<length> <symbol>
+            tmp = line.split(' ',1)
+            # This gives us ["<addr>", "[lgu!][w ][C ][W ][Ii ][dD ][FfO ] <section>\t<length> <symbol>"]
+            # We only need to consider cases where "<section>\t<length> <symbol>" is present,
+            # and where the [FfO] flag is either F (function) or O (object).
+            if len(tmp) > 1 and len(tmp[1]) > 6 and tmp[1][6] in ['O', 'F']:
+                tmp = tmp[1][8:].split()
+                # That gives us ["<section>","<length>", "<symbol>"]
+                syms.append((tmp[-1], tmp[0]))
+        return syms
 
 def main():
     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("--reorder", dest="reorder",
-        help="reorder the objects according to the given list", metavar="FILE")
+    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()
 
     with ExpandArgsMore(args) as args:
-        if options.extract or options.reorder:
+        if options.extract:
             args.extract()
-        if options.reorder:
-            with open(options.reorder) as file:
-                args.reorder([l.strip() for l in file.readlines()])
+        if options.symbol_order:
+            args.orderSymbols(options.symbol_order)
         if options.uselist:
             args.makelist()
 
         if options.verbose:
             print >>sys.stderr, "Executing: " + " ".join(args)
             for tmp in [f for f in args.tmp if os.path.isfile(f)]:
                 print >>sys.stderr, tmp + ":"
                 with open(tmp) as file:
--- a/config/tests/unit-expandlibs.py
+++ b/config/tests/unit-expandlibs.py
@@ -33,17 +33,17 @@ config_unix = {
     'LIBS_DESC_SUFFIX': '.desc',
     'EXPAND_LIBS_LIST_STYLE': 'linkerscript',
 }
 
 config = sys.modules['expandlibs_config'] = imp.new_module('expandlibs_config')
 
 from expandlibs import LibDescriptor, ExpandArgs, relativize
 from expandlibs_gen import generate
-from expandlibs_exec import ExpandArgsMore
+from expandlibs_exec import ExpandArgsMore, SectionFinder
 
 def Lib(name):
     return config.LIB_PREFIX + name + config.LIB_SUFFIX
 
 def Obj(name):
     return name + config.OBJ_SUFFIX
 
 def Dll(name):
@@ -262,33 +262,106 @@ class TestExpandArgsMore(TestExpandInit)
 
             tmp = args.tmp
         # Check that all temporary files are properly removed
         self.assertEqual(True, all([not os.path.exists(f) for f in tmp]))
 
         # Restore subprocess.call
         subprocess.call = subprocess_call
 
-    def test_reorder(self):
-        '''Test object reordering'''
-        # We don't care about AR_EXTRACT testing, which is done in test_extract
-        config.AR_EXTRACT = ''
+class FakeProcess(object):
+    def __init__(self, out, err = ''):
+        self.out = out
+        self.err = err
+
+    def communicate(self):
+        return (self.out, self.err)
 
-        # ExpandArgsMore does the same as ExpandArgs
-        with ExpandArgsMore(['foo', '-bar'] + self.arg_files + [self.tmpfile('liby', Lib('y'))]) as args:
-            self.assertRelEqual(args, ['foo', '-bar'] + self.files + self.liby_files + self.libx_files) 
+OBJDUMPS = {
+'foo.o': '''
+00000000 g     F .text\t00000001 foo
+00000000 g     F .text._Z6foobarv\t00000001 _Z6foobarv
+00000000 g     F .text.hello\t00000001 hello
+00000000 g     F .text._ZThn4_6foobarv\t00000001 _ZThn4_6foobarv
+''',
+'bar.o': '''
+00000000 g     F .text.hi\t00000001 hi
+00000000 g     F .text.hot._Z6barbazv\t00000001 .hidden _Z6barbazv
+''',
+}
+
+PRINT_ICF = '''
+ld: ICF folding section '.text.hello' in file 'foo.o'into '.text.hi' in file 'bar.o'
+ld: ICF folding section '.foo' in file 'foo.o'into '.foo' in file 'bar.o'
+'''
+
+class SubprocessPopen(object):
+    def __init__(self, test):
+        self.test = test
+
+    def __call__(self, args, stdout = None, stderr = None):
+        self.test.assertEqual(stdout, subprocess.PIPE)
+        self.test.assertEqual(stderr, subprocess.PIPE)
+        if args[0] == 'objdump':
+            self.test.assertEqual(args[1], '-t')
+            self.test.assertTrue(args[2] in OBJDUMPS)
+            return FakeProcess(OBJDUMPS[args[2]])
+        else:
+            return FakeProcess('', PRINT_ICF)
 
-            # Use an order containing object files from libraries
-            order_files = [self.libx_files[1], self.libx_files[0], self.liby_files[2], self.files[1]]
-            order = [os.path.splitext(os.path.basename(f))[0] for f in order_files]
-            args.reorder(order[:2] + ['unknown'] + order[2:])
+class TestSectionFinder(unittest.TestCase):
+    def test_getSections(self):
+        '''Test SectionFinder'''
+        # Divert subprocess.Popen
+        subprocess_popen = subprocess.Popen
+        subprocess.Popen = SubprocessPopen(self)
+        config.EXPAND_LIBS_ORDER_STYLE = 'linkerscript'
+        config.OBJ_SUFFIX = '.o'
+        config.LIB_SUFFIX = '.a'
+        finder = SectionFinder(['foo.o', 'bar.o'])
+        self.assertEqual(finder.getSections('foobar'), [])
+        self.assertEqual(finder.getSections('_Z6barbazv'), ['.text.hot._Z6barbazv'])
+        self.assertEqual(finder.getSections('_Z6foobarv'), ['.text._Z6foobarv', '.text._ZThn4_6foobarv'])
+        self.assertEqual(finder.getSections('_ZThn4_6foobarv'), ['.text._Z6foobarv', '.text._ZThn4_6foobarv'])
+        subprocess.Popen = subprocess_popen
 
-            # self.files has objects at #1, #2, #4
-            self.assertRelEqual(args[:3], ['foo', '-bar'] + self.files[:1])
-            self.assertRelEqual(args[3:7], order_files)
-            self.assertRelEqual(args[7:9], [self.files[2], self.files[4]])
-            self.assertRelEqual(args[9:11], self.liby_files[:2])
-            self.assertRelEqual(args[11:12], [self.libx_files[2]])
-            self.assertRelEqual(args[12:14], [self.files[3], self.files[5]])
-            self.assertRelEqual(args[14:], [self.liby_files[3]])
+class TestSymbolOrder(unittest.TestCase):
+    def test_getOrderedSections(self):
+        '''Test ExpandMoreArgs' _getOrderedSections'''
+        # Divert subprocess.Popen
+        subprocess_popen = subprocess.Popen
+        subprocess.Popen = SubprocessPopen(self)
+        config.EXPAND_LIBS_ORDER_STYLE = 'linkerscript'
+        config.OBJ_SUFFIX = '.o'
+        config.LIB_SUFFIX = '.a'
+        config.LD_PRINT_ICF_SECTIONS = ''
+        args = ExpandArgsMore(['foo', '-bar', 'bar.o', 'foo.o'])
+        self.assertEqual(args._getOrderedSections(['_Z6foobarv', '_Z6barbazv']), ['.text._Z6foobarv', '.text._ZThn4_6foobarv', '.text.hot._Z6barbazv'])
+        self.assertEqual(args._getOrderedSections(['_ZThn4_6foobarv', '_Z6barbazv']), ['.text._Z6foobarv', '.text._ZThn4_6foobarv', '.text.hot._Z6barbazv'])
+        subprocess.Popen = subprocess_popen
+
+    def test_getFoldedSections(self):
+        '''Test ExpandMoreArgs' _getFoldedSections'''
+        # Divert subprocess.Popen
+        subprocess_popen = subprocess.Popen
+        subprocess.Popen = SubprocessPopen(self)
+        config.LD_PRINT_ICF_SECTIONS = '-Wl,--print-icf-sections'
+        args = ExpandArgsMore(['foo', '-bar', 'bar.o', 'foo.o'])
+        self.assertEqual(args._getFoldedSections(), {'.text.hello': '.text.hi', '.text.hi': ['.text.hello']})
+        subprocess.Popen = subprocess_popen
+
+    def test_getOrderedSectionsWithICF(self):
+        '''Test ExpandMoreArgs' _getOrderedSections, with ICF'''
+        # Divert subprocess.Popen
+        subprocess_popen = subprocess.Popen
+        subprocess.Popen = SubprocessPopen(self)
+        config.EXPAND_LIBS_ORDER_STYLE = 'linkerscript'
+        config.OBJ_SUFFIX = '.o'
+        config.LIB_SUFFIX = '.a'
+        config.LD_PRINT_ICF_SECTIONS = '-Wl,--print-icf-sections'
+        args = ExpandArgsMore(['foo', '-bar', 'bar.o', 'foo.o'])
+        self.assertEqual(args._getOrderedSections(['hello', '_Z6barbazv']), ['.text.hi', '.text.hello', '.text.hot._Z6barbazv'])
+        self.assertEqual(args._getOrderedSections(['_ZThn4_6foobarv', 'hi', '_Z6barbazv']), ['.text._Z6foobarv', '.text._ZThn4_6foobarv', '.text.hi', '.text.hello', '.text.hot._Z6barbazv'])
+        subprocess.Popen = subprocess_popen
+
 
 if __name__ == '__main__':
     unittest.main(testRunner=MozTestRunner())
--- a/configure.in
+++ b/configure.in
@@ -2519,16 +2519,18 @@ ia64*-hpux*)
     AC_DEFINE(NSCAP_DISABLE_DEBUG_PTR_TYPES)
     ;;
 
 *-android*|*-linuxandroid*)
     AC_DEFINE(NO_PW_GECOS)
     no_x=yes
     if test -n "$gonkdir"; then
         _PLATFORM_DEFAULT_TOOLKIT=cairo-gonk
+        MOZ_B2G_RIL=1
+        MOZ_B2G_BT=1
     else
         _PLATFORM_DEFAULT_TOOLKIT=cairo-android
         MOZ_LINKER=1
     fi
     TARGET_NSPR_MDCPUCFG='\"md/_linux.cfg\"'
 
     MOZ_GFX_OPTIMIZE_MOBILE=1
     MOZ_OPTIMIZE_FLAGS="-Os -freorder-blocks -fno-reorder-functions"
@@ -5033,17 +5035,16 @@ cairo-android)
 cairo-gonk)
     AC_DEFINE(MOZ_WIDGET_GONK)
     AC_DEFINE(MOZ_TOUCH)
     MOZ_WIDGET_TOOLKIT=gonk
     TK_CFLAGS='$(MOZ_CAIRO_CFLAGS)'
     TK_LIBS='$(MOZ_CAIRO_LIBS)'
     MOZ_WEBGL=1
     MOZ_PDF_PRINTING=1
-    MOZ_B2G_RIL=1
     MOZ_TOUCH=1
     ;;
 
 esac
 
 AC_SUBST(MOZ_OLD_LINKER)
 AC_SUBST(MOZ_PDF_PRINTING)
 if test "$MOZ_PDF_PRINTING"; then
@@ -7175,88 +7176,16 @@ MOZ_ARG_ENABLE_STRING(debug-symbols,
   MOZ_DEBUG_SYMBOLS=1)
 
 if test -n "$MOZ_DEBUG" -o -n "$MOZ_DEBUG_SYMBOLS"; then
     AC_DEFINE(MOZ_DEBUG_SYMBOLS)
     export MOZ_DEBUG_SYMBOLS
 fi
 
 dnl ========================================================
-dnl = Identical Code Folding
-dnl ========================================================
-
-MOZ_ARG_DISABLE_BOOL(icf,
-[  --disable-icf          Disable Identical Code Folding],
-    MOZ_DISABLE_ICF=1,
-    MOZ_DISABLE_ICF= )
-
-if test "$GNU_CC" -a "$GCC_USE_GNU_LD" -a -z "$MOZ_DISABLE_ICF"; then
-    AC_CACHE_CHECK([whether the linker supports Identical Code Folding],
-        LD_SUPPORTS_ICF,
-        [echo 'int foo() {return 42;}' \
-              'int bar() {return 42;}' \
-              'int main() {return foo() - bar();}' > conftest.${ac_ext}
-        # If the linker supports ICF, foo and bar symbols will have
-        # the same address
-        if AC_TRY_COMMAND([${CC-cc} -o conftest${ac_exeext} $LDFLAGS -Wl,--icf=safe -ffunction-sections conftest.${ac_ext} $LIBS 1>&2]) &&
-           test -s conftest${ac_exeext} &&
-           objdump -t conftest${ac_exeext} | awk '{a[[$6]] = $1} END {if (a[["foo"]] && (a[["foo"]] != a[["bar"]])) { exit 1 }}'; then
-            LD_SUPPORTS_ICF=yes
-        else
-            LD_SUPPORTS_ICF=no
-        fi
-        rm -rf conftest*])
-    if test "$LD_SUPPORTS_ICF" = yes; then
-        LDFLAGS="$LDFLAGS -Wl,--icf=safe"
-        CFLAGS="$CFLAGS -ffunction-sections"
-        CXXFLAGS="$CXXFLAGS -ffunction-sections"
-    fi
-fi
-
-dnl ========================================================
-dnl = Automatically remove dead symbols
-dnl ========================================================
-
-if test "$GNU_CC" -a "$GCC_USE_GNU_LD" -a -n "$MOZ_DEBUG_FLAGS"; then
-   dnl See bug 670659
-   AC_CACHE_CHECK([whether removing dead symbols breaks debugging],
-       GC_SECTIONS_BREAKS_DEBUG_RANGES,
-       [echo 'int foo() {return 42;}' \
-             'int bar() {return 1;}' \
-             'int main() {return foo();}' > conftest.${ac_ext}
-        if AC_TRY_COMMAND([${CC-cc} -o conftest.${ac_objext} $CFLAGS $MOZ_DEBUG_FLAGS -ffunction-sections -c conftest.${ac_ext} 1>&2]) &&
-           AC_TRY_COMMAND([${CC-cc} -o conftest${ac_exeext} $LDFLAGS $MOZ_DEBUG_FLAGS -Wl,--gc-sections conftest.${ac_objext} $LIBS 1>&2]) &&
-           test -s conftest${ac_exeext} -a -s conftest.${ac_objext}; then
-            if test "`$PYTHON "$_topsrcdir"/build/unix/check_debug_ranges.py conftest.${ac_objext} conftest.${ac_ext}`" = \
-                    "`$PYTHON "$_topsrcdir"/build/unix/check_debug_ranges.py conftest${ac_exeext} conftest.${ac_ext}`"; then
-                GC_SECTIONS_BREAKS_DEBUG_RANGES=no
-            else
-                GC_SECTIONS_BREAKS_DEBUG_RANGES=yes
-            fi
-        else
-             dnl We really don't expect to get here, but just in case
-             GC_SECTIONS_BREAKS_DEBUG_RANGES="no, but it's broken in some other way"
-        fi
-        rm -rf conftest*])
-    if test "$GC_SECTIONS_BREAKS_DEBUG_RANGES" = no; then
-        DSO_LDOPTS="$DSO_LDOPTS -Wl,--gc-sections"
-        case "$CFLAGS" in
-        *-ffunction-sections*)
-            CFLAGS="$CFLAGS -fdata-sections"
-            CXXFLAGS="$CXXFLAGS -fdata-sections"
-            ;;
-        *)
-            CFLAGS="$CFLAGS -ffunction-sections -fdata-sections"
-            CXXFLAGS="$CXXFLAGS -ffunction-sections -fdata-sections"
-            ;;
-        esac
-    fi
-fi
-
-dnl ========================================================
 dnl = Enable any treating of compile warnings as errors
 dnl ========================================================
 MOZ_ARG_ENABLE_BOOL(warnings-as-errors,
 [  --enable-warnings-as-errors
                           Enable treating of warnings as errors],
     MOZ_ENABLE_WARNINGS_AS_ERRORS=1,
     MOZ_ENABLE_WARNINGS_AS_ERRORS=)
 if test -z "$MOZ_ENABLE_WARNINGS_AS_ERRORS"; then
@@ -8067,47 +7996,17 @@ CXXFLAGS="$_SAVE_CXXFLAGS"
 if test "$ac_nscap_nonconst_opeq_bug" = "yes" ; then
     AC_DEFINE(NSCAP_DONT_PROVIDE_NONCONST_OPEQ)
 fi
 fi # ! SKIP_COMPILER_CHECKS
 
 AC_DEFINE(CPP_THROW_NEW, [throw()])
 AC_LANG_C
 
-dnl ========================================================
-dnl =
-dnl = Check what kind of list files are supported by the
-dnl = linker
-dnl =
-dnl ========================================================
-
-AC_CACHE_CHECK(what kind of list files are supported by the linker,
-    EXPAND_LIBS_LIST_STYLE,
-    [echo "int main() {return 0;}" > conftest.${ac_ext}
-     if AC_TRY_COMMAND(${CC-cc} -o conftest.${OBJ_SUFFIX} -c $CFLAGS $CPPFLAGS conftest.${ac_ext} 1>&2) && test -s conftest.${OBJ_SUFFIX}; then
-         echo "INPUT(conftest.${OBJ_SUFFIX})" > conftest.list
-         if AC_TRY_COMMAND(${CC-cc} -o conftest${ac_exeext} $LDFLAGS conftest.list $LIBS 1>&2) && test -s conftest${ac_exeext}; then
-             EXPAND_LIBS_LIST_STYLE=linkerscript
-         else
-             echo "conftest.${OBJ_SUFFIX}" > conftest.list
-             if AC_TRY_COMMAND(${CC-cc} -o conftest${ac_exeext} $LDFLAGS @conftest.list $LIBS 1>&2) && test -s conftest${ac_exeext}; then
-                 EXPAND_LIBS_LIST_STYLE=list
-             else
-                 EXPAND_LIBS_LIST_STYLE=none
-             fi
-         fi
-     else
-         dnl We really don't expect to get here, but just in case
-         AC_ERROR([couldn't compile a simple C file])
-     fi
-     rm -rf conftest*])
-
-LIBS_DESC_SUFFIX=desc
-AC_SUBST(LIBS_DESC_SUFFIX)
-AC_SUBST(EXPAND_LIBS_LIST_STYLE)
+MOZ_EXPAND_LIBS
 
 dnl ========================================================
 dnl =
 dnl = Build depencency options
 dnl =
 dnl ========================================================
 MOZ_ARG_HEADER(Build dependencies)
 
--- a/content/base/public/Makefile.in
+++ b/content/base/public/Makefile.in
@@ -60,17 +60,16 @@ nsIMutationObserver.h \
 nsIMutationObserver2.h \
 nsINameSpaceManager.h \
 nsINode.h \
 nsINodeInfo.h \
 nsINodeList.h \
 nsIScriptElement.h \
 nsIStyleSheetLinkingElement.h \
 nsIContentSerializer.h \
-nsIHTMLToTextSink.h \
 nsIXPathEvaluatorInternal.h \
 mozISanitizingSerializer.h \
 nsCaseTreatment.h \
 nsContentCID.h \
 nsCopySupport.h \
 nsContentCreatorFunctions.h \
 nsDOMFile.h \
 nsLineBreaker.h \
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -437,16 +437,26 @@ public:
    * We define whitespace using the list in HTML5 and css3-selectors:
    * U+0009, U+000A, U+000C, U+000D, U+0020
    *
    * HTML 4.01 also lists U+200B (zero-width space).
    */
   static bool IsHTMLWhitespace(PRUnichar aChar);
 
   /**
+   * Is the HTML local name a block element?
+   */
+  static bool IsHTMLBlock(nsIAtom* aLocalName);
+
+  /**
+   * Is the HTML local name a void element?
+   */
+  static bool IsHTMLVoid(nsIAtom* aLocalName);
+
+  /**
    * Parse a margin string of format 'top, right, bottom, left' into
    * an nsIntMargin.
    *
    * @param aString the string to parse
    * @param aResult the resulting integer
    * @return whether the value could be parsed
    */
   static bool ParseIntMarginValue(const nsAString& aString, nsIntMargin& aResult);
@@ -833,21 +843,32 @@ public:
   static nsresult GetLocalizedString(PropertiesFile aFile,
                                      const char* aKey,
                                      nsXPIDLString& aResult);
 
   /**
    * Fill (with the parameters given) the localized string named |aKey| in
    * properties file |aFile|.
    */
+private:
   static nsresult FormatLocalizedString(PropertiesFile aFile,
                                         const char* aKey,
-                                        const PRUnichar **aParams,
+                                        const PRUnichar** aParams,
                                         PRUint32 aParamsLength,
                                         nsXPIDLString& aResult);
+  
+public:
+  template<PRUint32 N>
+  static nsresult FormatLocalizedString(PropertiesFile aFile,
+                                        const char* aKey,
+                                        const PRUnichar* (&aParams)[N],
+                                        nsXPIDLString& aResult)
+  {
+    return FormatLocalizedString(aFile, aKey, aParams, N, aResult);
+  }
 
   /**
    * Returns true if aDocument is a chrome document
    */
   static bool IsChromeDoc(nsIDocument *aDocument);
 
   /**
    * Returns true if aDocument is in a docshell whose parent is the same type
deleted file mode 100644
--- a/content/base/public/nsIHTMLToTextSink.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is mozilla.org code.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 1998
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either of the GNU General Public License Version 2 or later (the "GPL"),
- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef _nsIPlainTextSink_h__
-#define _nsIPlainTextSink_h__
-
-#include "nsISupports.h"
-#include "nsStringGlue.h"
-
-#define NS_PLAINTEXTSINK_CONTRACTID "@mozilla.org/layout/plaintextsink;1"
-
-/* starting interface:    nsIContentSerializer */
-#define NS_IHTMLTOTEXTSINK_IID_STR "b12b5643-07cb-401e-aabb-64b2dcd2717f"
-
-#define NS_IHTMLTOTEXTSINK_IID \
-  {0xb12b5643, 0x07cb, 0x401e, \
-    { 0xaa, 0xbb, 0x64, 0xb2, 0xdc, 0xd2, 0x71, 0x7f }}
-
-
-class nsIHTMLToTextSink : public nsISupports {
- public: 
-
-  NS_DECLARE_STATIC_IID_ACCESSOR(NS_IHTMLTOTEXTSINK_IID)
-
-  NS_IMETHOD Initialize(nsAString* aOutString,
-                        PRUint32 aFlags, PRUint32 aWrapCol) = 0;
-     // This function violates string ownership rules, see impl.
-};
-
-NS_DEFINE_STATIC_IID_ACCESSOR(nsIHTMLToTextSink, NS_IHTMLTOTEXTSINK_IID)
-
-#endif
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -1187,16 +1187,82 @@ nsContentUtils::IsHTMLWhitespace(PRUnich
          aChar == PRUnichar(0x000A) ||
          aChar == PRUnichar(0x000C) ||
          aChar == PRUnichar(0x000D) ||
          aChar == PRUnichar(0x0020);
 }
 
 /* static */
 bool
+nsContentUtils::IsHTMLBlock(nsIAtom* aLocalName)
+{
+  return
+    (aLocalName == nsGkAtoms::address) ||
+    (aLocalName == nsGkAtoms::article) ||
+    (aLocalName == nsGkAtoms::aside) ||
+    (aLocalName == nsGkAtoms::blockquote) ||
+    (aLocalName == nsGkAtoms::center) ||
+    (aLocalName == nsGkAtoms::dir) ||
+    (aLocalName == nsGkAtoms::div) ||
+    (aLocalName == nsGkAtoms::dl) || // XXX why not dt and dd?
+    (aLocalName == nsGkAtoms::fieldset) ||
+    (aLocalName == nsGkAtoms::figure) || // XXX shouldn't figcaption be on this list
+    (aLocalName == nsGkAtoms::footer) ||
+    (aLocalName == nsGkAtoms::form) ||
+    (aLocalName == nsGkAtoms::h1) ||
+    (aLocalName == nsGkAtoms::h2) ||
+    (aLocalName == nsGkAtoms::h3) ||
+    (aLocalName == nsGkAtoms::h4) ||
+    (aLocalName == nsGkAtoms::h5) ||
+    (aLocalName == nsGkAtoms::h6) ||
+    (aLocalName == nsGkAtoms::header) ||
+    (aLocalName == nsGkAtoms::hgroup) ||
+    (aLocalName == nsGkAtoms::hr) ||
+    (aLocalName == nsGkAtoms::li) ||
+    (aLocalName == nsGkAtoms::listing) ||
+    (aLocalName == nsGkAtoms::menu) ||
+    (aLocalName == nsGkAtoms::multicol) || // XXX get rid of this one?
+    (aLocalName == nsGkAtoms::nav) ||
+    (aLocalName == nsGkAtoms::ol) ||
+    (aLocalName == nsGkAtoms::p) ||
+    (aLocalName == nsGkAtoms::pre) ||
+    (aLocalName == nsGkAtoms::section) ||
+    (aLocalName == nsGkAtoms::table) ||
+    (aLocalName == nsGkAtoms::ul) ||
+    (aLocalName == nsGkAtoms::xmp);
+}
+
+/* static */
+bool
+nsContentUtils::IsHTMLVoid(nsIAtom* aLocalName)
+{
+  return
+    (aLocalName == nsGkAtoms::area) ||
+    (aLocalName == nsGkAtoms::base) ||
+    (aLocalName == nsGkAtoms::basefont) ||
+    (aLocalName == nsGkAtoms::bgsound) ||
+    (aLocalName == nsGkAtoms::br) ||
+    (aLocalName == nsGkAtoms::col) ||
+    (aLocalName == nsGkAtoms::command) ||
+    (aLocalName == nsGkAtoms::embed) ||
+    (aLocalName == nsGkAtoms::frame) ||
+    (aLocalName == nsGkAtoms::hr) ||
+    (aLocalName == nsGkAtoms::img) ||
+    (aLocalName == nsGkAtoms::input) ||
+    (aLocalName == nsGkAtoms::keygen) ||
+    (aLocalName == nsGkAtoms::link) ||
+    (aLocalName == nsGkAtoms::meta) ||
+    (aLocalName == nsGkAtoms::param) ||
+    (aLocalName == nsGkAtoms::source) ||
+    (aLocalName == nsGkAtoms::track) ||
+    (aLocalName == nsGkAtoms::wbr);
+}
+
+/* static */
+bool
 nsContentUtils::ParseIntMarginValue(const nsAString& aString, nsIntMargin& result)
 {
   nsAutoString marginStr(aString);
   marginStr.CompressWhitespace(true, true);
   if (marginStr.IsEmpty()) {
     return false;
   }
 
--- a/content/base/src/nsGenericElement.cpp
+++ b/content/base/src/nsGenericElement.cpp
@@ -2731,16 +2731,19 @@ nsGenericElement::SetAttribute(const nsA
 }
 
 nsresult
 nsGenericElement::RemoveAttribute(const nsAString& aName)
 {
   const nsAttrName* name = InternalGetExistingAttrNameFromQName(aName);
 
   if (!name) {
+    // If there is no canonical nsAttrName for this attribute name, then the
+    // attribute does not exist and we can't get its namespace ID and
+    // local name below, so we return early.
     return NS_OK;
   }
 
   // Hold a strong reference here so that the atom or nodeinfo doesn't go
   // away during UnsetAttr. If it did UnsetAttr would be left with a
   // dangling pointer as argument without knowing it.
   nsAttrName tmp(*name);
 
@@ -2884,18 +2887,19 @@ nsresult
 nsGenericElement::RemoveAttributeNS(const nsAString& aNamespaceURI,
                                     const nsAString& aLocalName)
 {
   nsCOMPtr<nsIAtom> name = do_GetAtom(aLocalName);
   PRInt32 nsid =
     nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNamespaceURI);
 
   if (nsid == kNameSpaceID_Unknown) {
-    // Unknown namespace means no attr...
-
+    // If the namespace ID is unknown, it means there can't possibly be an
+    // existing attribute. We would need a known namespace ID to pass into
+    // UnsetAttr, so we return early if we don't have one.
     return NS_OK;
   }
 
   UnsetAttr(nsid, name, true);
 
   return NS_OK;
 }
 
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -137,16 +137,17 @@ GK_ATOM(basefont, "basefont")
 GK_ATOM(baseline, "baseline")
 GK_ATOM(bdi, "bdi")
 GK_ATOM(bdo, "bdo")
 GK_ATOM(before, "before")
 GK_ATOM(before_end, "before_end")
 GK_ATOM(before_start, "before_start")
 GK_ATOM(below, "below")
 GK_ATOM(bgcolor, "bgcolor")
+GK_ATOM(bgsound, "bgsound")
 GK_ATOM(big, "big")
 GK_ATOM(binding, "binding")
 GK_ATOM(bindings, "bindings")
 GK_ATOM(blankrow, "blankrow")
 GK_ATOM(block, "block")
 GK_ATOM(blockquote, "blockquote")
 GK_ATOM(blur, "blur")
 GK_ATOM(body, "body")
@@ -488,16 +489,17 @@ GK_ATOM(itemref, "itemref")
 GK_ATOM(itemscope, "itemscope")
 GK_ATOM(itemtype, "itemtype")
 GK_ATOM(kbd, "kbd")
 GK_ATOM(noautofocus, "noautofocus")
 GK_ATOM(keepcurrentinview, "keepcurrentinview")
 GK_ATOM(key, "key")
 GK_ATOM(keycode, "keycode")
 GK_ATOM(keydown, "keydown")
+GK_ATOM(keygen, "keygen")
 GK_ATOM(keypress, "keypress")
 GK_ATOM(keyset, "keyset")
 GK_ATOM(keytext, "keytext")
 GK_ATOM(keyup, "keyup")
 GK_ATOM(kind, "kind")
 GK_ATOM(label, "label")
 GK_ATOM(lang, "lang")
 GK_ATOM(language, "language")
--- a/content/base/src/nsGkAtoms.cpp
+++ b/content/base/src/nsGkAtoms.cpp
@@ -60,11 +60,11 @@ using namespace mozilla;
 static const nsStaticAtom GkAtoms_info[] = {
 #define GK_ATOM(name_, value_) NS_STATIC_ATOM(name_##_buffer, &nsGkAtoms::name_),
 #include "nsGkAtomList.h"
 #undef GK_ATOM
 };
 
 void nsGkAtoms::AddRefAtoms()
 {
-  NS_RegisterStaticAtoms(GkAtoms_info, ArrayLength(GkAtoms_info));
+  NS_RegisterStaticAtoms(GkAtoms_info);
 }
 
--- a/content/base/src/nsPlainTextSerializer.cpp
+++ b/content/base/src/nsPlainTextSerializer.cpp
@@ -48,17 +48,16 @@
 #include "nsIServiceManager.h"
 #include "nsGkAtoms.h"
 #include "nsINameSpaceManager.h"
 #include "nsTextFragment.h"
 #include "nsContentUtils.h"
 #include "nsReadableUtils.h"
 #include "nsUnicharUtils.h"
 #include "nsCRT.h"
-#include "nsIParserService.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/Preferences.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 #define PREF_STRUCTS "converter.html2txt.structs"
 #define PREF_HEADER_STRATEGY "converter.html2txt.header_strategy"
@@ -74,17 +73,17 @@ static const  PRInt32 kIndentIncrementHe
                                                 indent h(x+1) this many
                                                 columns more than h(x) */
 static const  PRInt32 kIndentSizeList = kTabSize;
                                // Indention of non-first lines of ul and ol
 static const  PRInt32 kIndentSizeDD = kTabSize;  // Indention of <dd>
 static const  PRUnichar  kNBSP = 160;
 static const  PRUnichar kSPACE = ' ';
 
-static PRInt32 HeaderLevel(eHTMLTags aTag);
+static PRInt32 HeaderLevel(nsIAtom* aTag);
 static PRInt32 GetUnicharWidth(PRUnichar ucs);
 static PRInt32 GetUnicharStringWidth(const PRUnichar* pwcs, PRInt32 n);
 
 // Someday may want to make this non-const:
 static const PRUint32 TagStackSize = 500;
 static const PRUint32 OLStackSize = 100;
 
 nsresult NS_NewPlainTextSerializer(nsIContentSerializer** aSerializer)
@@ -121,17 +120,19 @@ nsPlainTextSerializer::nsPlainTextSerial
 
   // Flow
   mEmptyLines = 1; // The start of the document is an "empty line" in itself,
   mInWhitespace = false;
   mPreFormatted = false;
   mStartedOutput = false;
 
   // initialize the tag stack to zero:
-  mTagStack = new nsHTMLTag[TagStackSize];
+  // The stack only ever contains pointers to static atoms, so they don't
+  // need refcounting.
+  mTagStack = new nsIAtom*[TagStackSize];
   mTagStackIndex = 0;
   mIgnoreAboveIndex = (PRUint32)kNotFound;
 
   // initialize the OL stack, where numbers for ordered lists are kept
   mOLStack = new PRInt32[OLStackSize];
   mOLStackIndex = 0;
 
   mULCount = 0;
@@ -139,44 +140,39 @@ nsPlainTextSerializer::nsPlainTextSerial
 
 nsPlainTextSerializer::~nsPlainTextSerializer()
 {
   delete[] mTagStack;
   delete[] mOLStack;
   NS_WARN_IF_FALSE(mHeadLevel == 0, "Wrong head level!");
 }
 
-NS_IMPL_ISUPPORTS4(nsPlainTextSerializer, 
-                   nsIContentSerializer,
-                   nsIContentSink,
-                   nsIHTMLContentSink,
-                   nsIHTMLToTextSink)
+NS_IMPL_ISUPPORTS1(nsPlainTextSerializer,
+                   nsIContentSerializer)
 
 
 NS_IMETHODIMP 
 nsPlainTextSerializer::Init(PRUint32 aFlags, PRUint32 aWrapColumn,
                             const char* aCharSet, bool aIsCopying,
                             bool aIsWholeDocument)
 {
 #ifdef DEBUG
   // Check if the major control flags are set correctly.
-  if(aFlags & nsIDocumentEncoder::OutputFormatFlowed) {
+  if (aFlags & nsIDocumentEncoder::OutputFormatFlowed) {
     NS_ASSERTION(aFlags & nsIDocumentEncoder::OutputFormatted,
                  "If you want format=flowed, you must combine it with "
                  "nsIDocumentEncoder::OutputFormatted");
   }
 
-  if(aFlags & nsIDocumentEncoder::OutputFormatted) {
+  if (aFlags & nsIDocumentEncoder::OutputFormatted) {
     NS_ASSERTION(!(aFlags & nsIDocumentEncoder::OutputPreformatted),
                  "Can't do formatted and preformatted output at the same time!");
   }
 #endif
 
-  NS_ENSURE_TRUE(nsContentUtils::GetParserService(), NS_ERROR_UNEXPECTED);
-
   mFlags = aFlags;
   mWrapColumn = aWrapColumn;
 
   // Only create a linebreaker if we will handle wrapping.
   if (MayWrap()) {
     mLineBreaker = nsContentUtils::LineBreaker();
   }
 
@@ -265,31 +261,16 @@ nsPlainTextSerializer::PopBool(nsTArray<
   PRUint32 size = aStack.Length();
   if (size > 0) {
     returnValue = aStack.ElementAt(size-1);
     aStack.RemoveElementAt(size-1);
   }
   return returnValue;
 }
 
-NS_IMETHODIMP
-nsPlainTextSerializer::Initialize(nsAString* aOutString,
-                                  PRUint32 aFlags, PRUint32 aWrapCol)
-{
-  nsresult rv = Init(aFlags, aWrapCol, nsnull, false, false);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // XXX This is wrong. It violates XPCOM string ownership rules.
-  // We're only getting away with this because instances of this
-  // class are restricted to single function scope.
-  mOutputString = aOutString;
-
-  return NS_OK;
-}
-
 NS_IMETHODIMP 
 nsPlainTextSerializer::AppendText(nsIContent* aText,
                                   PRInt32 aStartOffset,
                                   PRInt32 aEndOffset, 
                                   nsAString& aStr)
 {
   if (mIgnoreAboveIndex != (PRUint32)kNotFound) {
     return NS_OK;
@@ -330,41 +311,36 @@ nsPlainTextSerializer::AppendText(nsICon
   mOutputString = &aStr;
 
   // We have to split the string across newlines
   // to match parser behavior
   PRInt32 start = 0;
   PRInt32 offset = textstr.FindCharInSet("\n\r");
   while (offset != kNotFound) {
 
-    if(offset>start) {
+    if (offset>start) {
       // Pass in the line
-      rv = DoAddLeaf(nsnull,
-                     eHTMLTag_text,
-                     Substring(textstr, start, offset-start));
-      if (NS_FAILED(rv)) break;
+      DoAddText(false,
+                Substring(textstr, start, offset-start));
     }
 
     // Pass in a newline
-    rv = DoAddLeaf(nsnull, eHTMLTag_newline, mLineBreak);
-    if (NS_FAILED(rv)) break;
+    DoAddText(true, mLineBreak);
     
     start = offset+1;
     offset = textstr.FindCharInSet("\n\r", start);
   }
 
   // Consume the last bit of the string if there's any left
-  if (NS_SUCCEEDED(rv) && start < length) {
+  if (start < length) {
     if (start) {
-      rv = DoAddLeaf(nsnull,
-                     eHTMLTag_text,
-                     Substring(textstr, start, length-start));
+      DoAddText(false, Substring(textstr, start, length - start));
     }
     else {
-      rv = DoAddLeaf(nsnull, eHTMLTag_text, textstr);
+      DoAddText(false, textstr);
     }
   }
   
   mOutputString = nsnull;
 
   return rv;
 }
 
@@ -382,63 +358,63 @@ nsPlainTextSerializer::AppendElementStar
                                           Element* aOriginalElement,
                                           nsAString& aStr)
 {
   NS_ENSURE_ARG(aElement);
 
   mElement = aElement;
 
   nsresult rv;
-  PRInt32 id = GetIdForContent(mElement);
+  nsIAtom* id = GetIdForContent(mElement);
 
-  bool isContainer = IsContainer(id);
+  bool isContainer = !nsContentUtils::IsHTMLVoid(id);
 
   mOutputString = &aStr;
 
   if (isContainer) {
-    rv = DoOpenContainer(nsnull, id);
+    rv = DoOpenContainer(id);
   }
   else {
-    rv = DoAddLeaf(nsnull, id, EmptyString());
+    rv = DoAddLeaf(id);
   }
 
   mElement = nsnull;
   mOutputString = nsnull;
 
-  if (id == eHTMLTag_head) {
+  if (id == nsGkAtoms::head) {
     ++mHeadLevel;
   }
 
   return rv;
 } 
  
 NS_IMETHODIMP 
 nsPlainTextSerializer::AppendElementEnd(Element* aElement,
                                         nsAString& aStr)
 {
   NS_ENSURE_ARG(aElement);
 
   mElement = aElement;
 
   nsresult rv;
-  PRInt32 id = GetIdForContent(mElement);
+  nsIAtom* id = GetIdForContent(mElement);
 
-  bool isContainer = IsContainer(id);
+  bool isContainer = !nsContentUtils::IsHTMLVoid(id);
 
   mOutputString = &aStr;
 
   rv = NS_OK;
   if (isContainer) {
     rv = DoCloseContainer(id);
   }
 
   mElement = nsnull;
   mOutputString = nsnull;
 
-  if (id == eHTMLTag_head) {
+  if (id == nsGkAtoms::head) {
     --mHeadLevel;
     NS_ASSERTION(mHeadLevel >= 0, "mHeadLevel < 0");
   }
 
   return rv;
 }
 
 NS_IMETHODIMP 
@@ -452,159 +428,77 @@ nsPlainTextSerializer::Flush(nsAString& 
 
 NS_IMETHODIMP
 nsPlainTextSerializer::AppendDocumentStart(nsIDocument *aDocument,
                                            nsAString& aStr)
 {
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsPlainTextSerializer::OpenContainer(const nsIParserNode& aNode)
-{
-  PRInt32 type = aNode.GetNodeType();
-
-  if (type == eHTMLTag_head) {
-    ++mHeadLevel;
-    return NS_OK;
-  }
-
-  return DoOpenContainer(&aNode, type);
-}
-
-NS_IMETHODIMP 
-nsPlainTextSerializer::CloseContainer(const nsHTMLTag aTag)
-{
-  if (aTag == eHTMLTag_head) {
-    --mHeadLevel;
-    NS_ASSERTION(mHeadLevel >= 0, "mHeadLevel < 0");
-    return NS_OK;
-  }
-
-  return DoCloseContainer(aTag);
-}
-
-NS_IMETHODIMP 
-nsPlainTextSerializer::AddLeaf(const nsIParserNode& aNode)
-{
-  if (mIgnoreAboveIndex != (PRUint32)kNotFound) {
-    return NS_OK;
-  }
-
-  eHTMLTags type = (eHTMLTags)aNode.GetNodeType();
-  const nsAString& text = aNode.GetText();
-
-  if ((type == eHTMLTag_text) ||
-      (type == eHTMLTag_whitespace) ||
-      (type == eHTMLTag_newline)) {
-    // Copy the text out, stripping out CRs
-    nsAutoString str;
-    PRUint32 length;
-    str.SetCapacity(text.Length());
-    nsReadingIterator<PRUnichar> srcStart, srcEnd;
-    length = nsContentUtils::CopyNewlineNormalizedUnicodeTo(text.BeginReading(srcStart), text.EndReading(srcEnd), str);
-    str.SetLength(length);
-    return DoAddLeaf(&aNode, type, str);
-  }
-  else {
-    return DoAddLeaf(&aNode, type, text);
-  }
-}
-
-NS_IMETHODIMP 
-nsPlainTextSerializer::OpenHead()
-{
-  ++mHeadLevel;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsPlainTextSerializer::IsEnabled(PRInt32 aTag, bool* aReturn)
-{
-  nsHTMLTag theHTMLTag = nsHTMLTag(aTag);
-
-  if (theHTMLTag == eHTMLTag_script) {
-    *aReturn = !(mFlags & nsIDocumentEncoder::OutputNoScriptContent);
-  }
-  else if (theHTMLTag == eHTMLTag_frameset) {
-    *aReturn = !(mFlags & nsIDocumentEncoder::OutputNoFramesContent);
-  }
-  else {
-    *aReturn = false;
-  }
-
-  return NS_OK;
-}
-
-/**
- * aNode may be null when we're working with the DOM, but then mElement is
- * useable instead.
- */
 nsresult
-nsPlainTextSerializer::DoOpenContainer(const nsIParserNode* aNode, PRInt32 aTag)
+nsPlainTextSerializer::DoOpenContainer(nsIAtom* aTag)
 {
   if (mFlags & nsIDocumentEncoder::OutputRaw) {
     // Raw means raw.  Don't even think about doing anything fancy
     // here like indenting, adding line breaks or any other
     // characters such as list item bullets, quote characters
     // around <q>, etc.  I mean it!  Don't make me smack you!
 
     return NS_OK;
   }
 
-  eHTMLTags type = (eHTMLTags)aTag;
-
   if (mTagStackIndex < TagStackSize) {
-    mTagStack[mTagStackIndex++] = type;
+    mTagStack[mTagStackIndex++] = aTag;
   }
 
   if (mIgnoreAboveIndex != (PRUint32)kNotFound) {
     return NS_OK;
   }
 
   // Reset this so that <blockquote type=cite> doesn't affect the whitespace
   // above random <pre>s below it.
-  mHasWrittenCiteBlockquote = mHasWrittenCiteBlockquote && aTag == eHTMLTag_pre;
+  mHasWrittenCiteBlockquote = mHasWrittenCiteBlockquote &&
+                              aTag == nsGkAtoms::pre;
 
   bool isInCiteBlockquote = false;
 
   // XXX special-case <blockquote type=cite> so that we don't add additional
   // newlines before the text.
-  if (aTag == eHTMLTag_blockquote) {
+  if (aTag == nsGkAtoms::blockquote) {
     nsAutoString value;
-    nsresult rv = GetAttributeValue(aNode, nsGkAtoms::type, value);
+    nsresult rv = GetAttributeValue(nsGkAtoms::type, value);
     isInCiteBlockquote = NS_SUCCEEDED(rv) && value.EqualsIgnoreCase("cite");
   }
 
   if (mLineBreakDue && !isInCiteBlockquote)
     EnsureVerticalSpace(mFloatingLines);
 
   // Check if this tag's content that should not be output
-  if ((type == eHTMLTag_noscript &&
+  if ((aTag == nsGkAtoms::noscript &&
        !(mFlags & nsIDocumentEncoder::OutputNoScriptContent)) ||
-      ((type == eHTMLTag_iframe || type == eHTMLTag_noframes) &&
+      ((aTag == nsGkAtoms::iframe || aTag == nsGkAtoms::noframes) &&
        !(mFlags & nsIDocumentEncoder::OutputNoFramesContent))) {
     // Ignore everything that follows the current tag in 
     // question until a matching end tag is encountered.
     mIgnoreAboveIndex = mTagStackIndex - 1;
     return NS_OK;
   }
 
-  if (type == eHTMLTag_body) {
+  if (aTag == nsGkAtoms::body) {
     // Try to figure out here whether we have a
     // preformatted style attribute.
     //
     // Trigger on the presence of a "pre-wrap" in the
     // style attribute. That's a very simplistic way to do
     // it, but better than nothing.
     // Also set mWrapColumn to the value given there
     // (which arguably we should only do if told to do so).
     nsAutoString style;
     PRInt32 whitespace;
-    if(NS_SUCCEEDED(GetAttributeValue(aNode, nsGkAtoms::style, style)) &&
+    if (NS_SUCCEEDED(GetAttributeValue(nsGkAtoms::style, style)) &&
        (kNotFound != (whitespace = style.Find("white-space:")))) {
 
       if (kNotFound != style.Find("pre-wrap", true, whitespace)) {
 #ifdef DEBUG_preformatted
         printf("Set mPreFormatted based on style pre-wrap\n");
 #endif
         mPreFormatted = true;
         PRInt32 widthOffset = style.Find("width:");
@@ -647,32 +541,32 @@ nsPlainTextSerializer::DoOpenContainer(c
     return NS_OK;
   }
 
   // Keep this in sync with DoCloseContainer!
   if (!DoOutput()) {
     return NS_OK;
   }
 
-  if (type == eHTMLTag_p)
+  if (aTag == nsGkAtoms::p)
     EnsureVerticalSpace(1);
-  else if (type == eHTMLTag_pre) {
+  else if (aTag == nsGkAtoms::pre) {
     if (GetLastBool(mIsInCiteBlockquote))
       EnsureVerticalSpace(0);
     else if (mHasWrittenCiteBlockquote) {
       EnsureVerticalSpace(0);
       mHasWrittenCiteBlockquote = false;
     }
     else
       EnsureVerticalSpace(1);
   }
-  else if (type == eHTMLTag_tr) {
+  else if (aTag == nsGkAtoms::tr) {
     PushBool(mHasWrittenCellsForRow, false);
   }
-  else if (type == eHTMLTag_td || type == eHTMLTag_th) {
+  else if (aTag == nsGkAtoms::td || aTag == nsGkAtoms::th) {
     // We must make sure that the content of two table cells get a
     // space between them.
 
     // To make the separation between cells most obvious and
     // importable, we use a TAB.
     if (GetLastBool(mHasWrittenCellsForRow)) {
       // Bypass |Write| so that the TAB isn't compressed away.
       AddToLine(NS_LITERAL_STRING("\t").get(), 1);
@@ -682,49 +576,49 @@ nsPlainTextSerializer::DoOpenContainer(c
       // We don't always see a <tr> (nor a <table>) before the <td> if we're
       // copying part of a table
       PushBool(mHasWrittenCellsForRow, true); // will never be popped
     }
     else {
       SetLastBool(mHasWrittenCellsForRow, true);
     }
   }
-  else if (type == eHTMLTag_ul) {
+  else if (aTag == nsGkAtoms::ul) {
     // Indent here to support nested lists, which aren't included in li :-(
     EnsureVerticalSpace(mULCount + mOLStackIndex == 0 ? 1 : 0);
          // Must end the current line before we change indention
     mIndent += kIndentSizeList;
     mULCount++;
   }
-  else if (type == eHTMLTag_ol) {
+  else if (aTag == nsGkAtoms::ol) {
     EnsureVerticalSpace(mULCount + mOLStackIndex == 0 ? 1 : 0);
     if (mFlags & nsIDocumentEncoder::OutputFormatted) {
       // Must end the current line before we change indention
       if (mOLStackIndex < OLStackSize) {
         nsAutoString startAttr;
         PRInt32 startVal = 1;
-        if(NS_SUCCEEDED(GetAttributeValue(aNode, nsGkAtoms::start, startAttr))){
+        if (NS_SUCCEEDED(GetAttributeValue(nsGkAtoms::start, startAttr))) {
           PRInt32 rv = 0;
           startVal = startAttr.ToInteger(&rv);
           if (NS_FAILED(rv))
             startVal = 1;
         }
         mOLStack[mOLStackIndex++] = startVal;
       }
     } else {
       mOLStackIndex++;
     }
     mIndent += kIndentSizeList;  // see ul
   }
-  else if (type == eHTMLTag_li &&
+  else if (aTag == nsGkAtoms::li &&
            (mFlags & nsIDocumentEncoder::OutputFormatted)) {
     if (mTagStackIndex > 1 && IsInOL()) {
       if (mOLStackIndex > 0) {
         nsAutoString valueAttr;
-        if(NS_SUCCEEDED(GetAttributeValue(aNode, nsGkAtoms::value, valueAttr))){
+        if (NS_SUCCEEDED(GetAttributeValue(nsGkAtoms::value, valueAttr))) {
           PRInt32 rv = 0;
           PRInt32 valueAttrVal = valueAttr.ToInteger(&rv);
           if (NS_SUCCEEDED(rv))
             mOLStack[mOLStackIndex-1] = valueAttrVal;
         }
         // This is what nsBulletFrame does for OLs:
         mInIndentString.AppendInt(mOLStack[mOLStackIndex-1]++, 10);
       }
@@ -739,73 +633,72 @@ nsPlainTextSerializer::DoOpenContainer(c
       static char bulletCharArray[] = "*o+#";
       PRUint32 index = mULCount > 0 ? (mULCount - 1) : 3;
       char bulletChar = bulletCharArray[index % 4];
       mInIndentString.Append(PRUnichar(bulletChar));
     }
 
     mInIndentString.Append(PRUnichar(' '));
   }
-  else if (type == eHTMLTag_dl) {
+  else if (aTag == nsGkAtoms::dl) {
     EnsureVerticalSpace(1);
   }
-  else if (type == eHTMLTag_dt) {
+  else if (aTag == nsGkAtoms::dt) {
     EnsureVerticalSpace(0);
   }
-  else if (type == eHTMLTag_dd) {
+  else if (aTag == nsGkAtoms::dd) {
     EnsureVerticalSpace(0);
     mIndent += kIndentSizeDD;
   }
-  else if (type == eHTMLTag_span) {
+  else if (aTag == nsGkAtoms::span) {
     ++mSpanLevel;
   }
-  else if (type == eHTMLTag_blockquote) {
+  else if (aTag == nsGkAtoms::blockquote) {
     // Push
     PushBool(mIsInCiteBlockquote, isInCiteBlockquote);
     if (isInCiteBlockquote) {
       EnsureVerticalSpace(0);
       mCiteQuoteLevel++;
     }
     else {
       EnsureVerticalSpace(1);
       mIndent += kTabSize; // Check for some maximum value?
     }
   }
-  else if (type == eHTMLTag_q) {
+  else if (aTag == nsGkAtoms::q) {
     Write(NS_LITERAL_STRING("\""));
   }
 
   // Else make sure we'll separate block level tags,
   // even if we're about to leave, before doing any other formatting.
-  else if (IsBlockLevel(aTag)) {
+  else if (nsContentUtils::IsHTMLBlock(aTag)) {
     EnsureVerticalSpace(0);
   }
 
   //////////////////////////////////////////////////////////////
   if (!(mFlags & nsIDocumentEncoder::OutputFormatted)) {
     return NS_OK;
   }
   //////////////////////////////////////////////////////////////
   // The rest of this routine is formatted output stuff,
   // which we should skip if we're not formatted:
   //////////////////////////////////////////////////////////////
 
   // Push on stack
-  bool currentNodeIsConverted = IsCurrentNodeConverted(aNode);
-  PushBool(mCurrentNodeIsConverted, currentNodeIsConverted);
+  bool currentNodeIsConverted = IsCurrentNodeConverted();
 
-  if (type == eHTMLTag_h1 || type == eHTMLTag_h2 ||
-      type == eHTMLTag_h3 || type == eHTMLTag_h4 ||
-      type == eHTMLTag_h5 || type == eHTMLTag_h6)
+  if (aTag == nsGkAtoms::h1 || aTag == nsGkAtoms::h2 ||
+      aTag == nsGkAtoms::h3 || aTag == nsGkAtoms::h4 ||
+      aTag == nsGkAtoms::h5 || aTag == nsGkAtoms::h6)
   {
     EnsureVerticalSpace(2);
     if (mHeaderStrategy == 2) {  // numbered
       mIndent += kIndentSizeHeaders;
       // Caching
-      PRInt32 level = HeaderLevel(type);
+      PRInt32 level = HeaderLevel(aTag);
       // Increase counter for current level
       mHeaderCounter[level]++;
       // Reset all lower levels
       PRInt32 i;
 
       for (i = level + 1; i <= 6; i++) {
         mHeaderCounter[i] = 0;
       }
@@ -816,62 +709,62 @@ nsPlainTextSerializer::DoOpenContainer(c
         leadup.AppendInt(mHeaderCounter[i]);
         leadup.Append(PRUnichar('.'));
       }
       leadup.Append(PRUnichar(' '));
       Write(leadup);
     }
     else if (mHeaderStrategy == 1) { // indent increasingly
       mIndent += kIndentSizeHeaders;
-      for (PRInt32 i = HeaderLevel(type); i > 1; i--) {
+      for (PRInt32 i = HeaderLevel(aTag); i > 1; i--) {
            // for h(x), run x-1 times
         mIndent += kIndentIncrementHeaders;
       }
     }
   }
-  else if (type == eHTMLTag_a && !currentNodeIsConverted) {
+  else if (aTag == nsGkAtoms::a && !currentNodeIsConverted) {
     nsAutoString url;
-    if (NS_SUCCEEDED(GetAttributeValue(aNode, nsGkAtoms::href, url))
+    if (NS_SUCCEEDED(GetAttributeValue(nsGkAtoms::href, url))
         && !url.IsEmpty()) {
       mURL = url;
     }
   }
-  else if (type == eHTMLTag_sup && mStructs && !currentNodeIsConverted) {
+  else if (aTag == nsGkAtoms::sup && mStructs && !currentNodeIsConverted) {
     Write(NS_LITERAL_STRING("^"));
   }
-  else if (type == eHTMLTag_sub && mStructs && !currentNodeIsConverted) { 
+  else if (aTag == nsGkAtoms::sub && mStructs && !currentNodeIsConverted) {
     Write(NS_LITERAL_STRING("_"));
   }
-  else if (type == eHTMLTag_code && mStructs && !currentNodeIsConverted) {
+  else if (aTag == nsGkAtoms::code && mStructs && !currentNodeIsConverted) {
     Write(NS_LITERAL_STRING("|"));
   }
-  else if ((type == eHTMLTag_strong || type == eHTMLTag_b)
+  else if ((aTag == nsGkAtoms::strong || aTag == nsGkAtoms::b)
            && mStructs && !currentNodeIsConverted) {
     Write(NS_LITERAL_STRING("*"));
   }
-  else if ((type == eHTMLTag_em || type == eHTMLTag_i)
+  else if ((aTag == nsGkAtoms::em || aTag == nsGkAtoms::i)
            && mStructs && !currentNodeIsConverted) {
     Write(NS_LITERAL_STRING("/"));
   }
-  else if (type == eHTMLTag_u && mStructs && !currentNodeIsConverted) {
+  else if (aTag == nsGkAtoms::u && mStructs && !currentNodeIsConverted) {
     Write(NS_LITERAL_STRING("_"));
   }
 
   /* Container elements are always block elements, so we shouldn't
      output any whitespace immediately after the container tag even if
      there's extra whitespace there because the HTML is pretty-printed
      or something. To ensure that happens, tell the serializer we're
      already in whitespace so it won't output more. */
   mInWhitespace = true;
 
   return NS_OK;
 }
 
 nsresult
-nsPlainTextSerializer::DoCloseContainer(PRInt32 aTag)
+nsPlainTextSerializer::DoCloseContainer(nsIAtom* aTag)
 {
   if (mFlags & nsIDocumentEncoder::OutputRaw) {
     // Raw means raw.  Don't even think about doing anything fancy
     // here like indenting, adding line breaks or any other
     // characters such as list item bullets, quote characters
     // around <q>, etc.  I mean it!  Don't make me smack you!
 
     return NS_OK;
@@ -886,19 +779,18 @@ nsPlainTextSerializer::DoCloseContainer(
       // We're dealing with the close tag whose matching
       // open tag had set the mIgnoreAboveIndex value.
       // Reset mIgnoreAboveIndex before discarding this tag.
       mIgnoreAboveIndex = (PRUint32)kNotFound;
     }
     return NS_OK;
   }
 
-  eHTMLTags type = (eHTMLTags)aTag;
   // End current line if we're ending a block level tag
-  if((type == eHTMLTag_body) || (type == eHTMLTag_html)) {
+  if ((aTag == nsGkAtoms::body) || (aTag == nsGkAtoms::html)) {
     // We want the output to end with a new line,
     // but in preformatted areas like text fields,
     // we can't emit newlines that weren't there.
     // So add the newline only in the case of formatted output.
     if (mFlags & nsIDocumentEncoder::OutputFormatted) {
       EnsureVerticalSpace(0);
     }
     else {
@@ -909,71 +801,71 @@ nsPlainTextSerializer::DoCloseContainer(
     return NS_OK;
   }
 
   // Keep this in sync with DoOpenContainer!
   if (!DoOutput()) {
     return NS_OK;
   }
 
-  if (type == eHTMLTag_tr) {
+  if (aTag == nsGkAtoms::tr) {
     PopBool(mHasWrittenCellsForRow);
     // Should always end a line, but get no more whitespace
     if (mFloatingLines < 0)
       mFloatingLines = 0;
     mLineBreakDue = true;
   }
-  else if (((type == eHTMLTag_li) ||
-            (type == eHTMLTag_dt)) &&
+  else if (((aTag == nsGkAtoms::li) ||
+            (aTag == nsGkAtoms::dt)) &&
            (mFlags & nsIDocumentEncoder::OutputFormatted)) {
     // Items that should always end a line, but get no more whitespace
     if (mFloatingLines < 0)
       mFloatingLines = 0;
     mLineBreakDue = true;
   }
-  else if (type == eHTMLTag_pre) {
+  else if (aTag == nsGkAtoms::pre) {
     mFloatingLines = GetLastBool(mIsInCiteBlockquote) ? 0 : 1;
     mLineBreakDue = true;
   }
-  else if (type == eHTMLTag_ul) {
+  else if (aTag == nsGkAtoms::ul) {
     FlushLine();
     mIndent -= kIndentSizeList;
     if (--mULCount + mOLStackIndex == 0) {
       mFloatingLines = 1;
       mLineBreakDue = true;
     }
   }
-  else if (type == eHTMLTag_ol) {
+  else if (aTag == nsGkAtoms::ol) {
     FlushLine(); // Doing this after decreasing OLStackIndex would be wrong.
     mIndent -= kIndentSizeList;
     NS_ASSERTION(mOLStackIndex, "Wrong OLStack level!");
     mOLStackIndex--;
     if (mULCount + mOLStackIndex == 0) {
       mFloatingLines = 1;
       mLineBreakDue = true;
     }
   }  
-  else if (type == eHTMLTag_dl) {
+  else if (aTag == nsGkAtoms::dl) {
     mFloatingLines = 1;
     mLineBreakDue = true;
   }
-  else if (type == eHTMLTag_dd) {
+  else if (aTag == nsGkAtoms::dd) {
     FlushLine();
     mIndent -= kIndentSizeDD;
   }
-  else if (type == eHTMLTag_span) {
+  else if (aTag == nsGkAtoms::span) {
     NS_ASSERTION(mSpanLevel, "Span level will be negative!");
     --mSpanLevel;
   }
-  else if (type == eHTMLTag_div) {
+  else if (aTag == nsGkAtoms::div) {
     if (mFloatingLines < 0)
       mFloatingLines = 0;
     mLineBreakDue = true;
   }
-  else if (type == eHTMLTag_blockquote) {
+  else if (aTag == nsGkAtoms::blockquote) {
     FlushLine();    // Is this needed?
 
     // Pop
     bool isInCiteBlockquote = PopBool(mIsInCiteBlockquote);
 
     if (isInCiteBlockquote) {
       NS_ASSERTION(mCiteQuoteLevel, "CiteQuote level will be negative!");
       mCiteQuoteLevel--;
@@ -981,23 +873,21 @@ nsPlainTextSerializer::DoCloseContainer(
       mHasWrittenCiteBlockquote = true;
     }
     else {
       mIndent -= kTabSize;
       mFloatingLines = 1;
     }
     mLineBreakDue = true;
   }
-  else if (type == eHTMLTag_q) {
+  else if (aTag == nsGkAtoms::q) {
     Write(NS_LITERAL_STRING("\""));
   }
-  else if (IsBlockLevel(aTag)
-           && type != eHTMLTag_script
-           && type != eHTMLTag_doctypeDecl
-           && type != eHTMLTag_markupDecl) {
+  else if (nsContentUtils::IsHTMLBlock(aTag)
+           && aTag != nsGkAtoms::script) {
     // All other blocks get 1 vertical space after them
     // in formatted mode, otherwise 0.
     // This is hard. Sometimes 0 is a better number, but
     // how to know?
     if (mFlags & nsIDocumentEncoder::OutputFormatted)
       EnsureVerticalSpace(1);
     else {
       if (mFloatingLines < 0)
@@ -1011,211 +901,210 @@ nsPlainTextSerializer::DoCloseContainer(
     return NS_OK;
   }
   //////////////////////////////////////////////////////////////
   // The rest of this routine is formatted output stuff,
   // which we should skip if we're not formatted:
   //////////////////////////////////////////////////////////////
 
   // Pop the currentConverted stack
-  bool currentNodeIsConverted = PopBool(mCurrentNodeIsConverted);
+  bool currentNodeIsConverted = IsCurrentNodeConverted();
   
-  if (type == eHTMLTag_h1 || type == eHTMLTag_h2 ||
-      type == eHTMLTag_h3 || type == eHTMLTag_h4 ||
-      type == eHTMLTag_h5 || type == eHTMLTag_h6) {
+  if (aTag == nsGkAtoms::h1 || aTag == nsGkAtoms::h2 ||
+      aTag == nsGkAtoms::h3 || aTag == nsGkAtoms::h4 ||
+      aTag == nsGkAtoms::h5 || aTag == nsGkAtoms::h6) {
     
     if (mHeaderStrategy) {  /*numbered or indent increasingly*/ 
       mIndent -= kIndentSizeHeaders;
     }
     if (mHeaderStrategy == 1 /*indent increasingly*/ ) {
-      for (PRInt32 i = HeaderLevel(type); i > 1; i--) {
+      for (PRInt32 i = HeaderLevel(aTag); i > 1; i--) {
            // for h(x), run x-1 times
         mIndent -= kIndentIncrementHeaders;
       }
     }
     EnsureVerticalSpace(1);
   }
-  else if (type == eHTMLTag_a && !currentNodeIsConverted && !mURL.IsEmpty()) {
+  else if (aTag == nsGkAtoms::a && !currentNodeIsConverted && !mURL.IsEmpty()) {
     nsAutoString temp; 
     temp.AssignLiteral(" <");
     temp += mURL;
     temp.Append(PRUnichar('>'));
     Write(temp);
     mURL.Truncate();
   }
-  else if ((type == eHTMLTag_sup || type == eHTMLTag_sub) 
+  else if ((aTag == nsGkAtoms::sup || aTag == nsGkAtoms::sub)
            && mStructs && !currentNodeIsConverted) {
     Write(kSpace);
   }
-  else if (type == eHTMLTag_code && mStructs && !currentNodeIsConverted) {
+  else if (aTag == nsGkAtoms::code && mStructs && !currentNodeIsConverted) {
     Write(NS_LITERAL_STRING("|"));
   }
-  else if ((type == eHTMLTag_strong || type == eHTMLTag_b)
+  else if ((aTag == nsGkAtoms::strong || aTag == nsGkAtoms::b)
            && mStructs && !currentNodeIsConverted) {
     Write(NS_LITERAL_STRING("*"));
   }
-  else if ((type == eHTMLTag_em || type == eHTMLTag_i)
+  else if ((aTag == nsGkAtoms::em || aTag == nsGkAtoms::i)
            && mStructs && !currentNodeIsConverted) {
     Write(NS_LITERAL_STRING("/"));
   }
-  else if (type == eHTMLTag_u && mStructs && !currentNodeIsConverted) {
+  else if (aTag == nsGkAtoms::u && mStructs && !currentNodeIsConverted) {
     Write(NS_LITERAL_STRING("_"));
   }
 
   return NS_OK;
 }
 
-/**
- * aNode may be null when we're working with the DOM, but then mElement is
- * useable instead.
- */
+bool
+nsPlainTextSerializer::MustSuppressLeaf()
+{
+  if ((mTagStackIndex > 1 &&
+       mTagStack[mTagStackIndex-2] == nsGkAtoms::select) ||
+      (mTagStackIndex > 0 &&
+        mTagStack[mTagStackIndex-1] == nsGkAtoms::select)) {
+    // Don't output the contents of SELECT elements;
+    // Might be nice, eventually, to output just the selected element.
+    // Read more in bug 31994.
+    return true;
+  }
+
+  if (mTagStackIndex > 0 &&
+      (mTagStack[mTagStackIndex-1] == nsGkAtoms::script ||
+       mTagStack[mTagStackIndex-1] == nsGkAtoms::style)) {
+    // Don't output the contents of <script> or <style> tags;
+    return true;
+  }
+
+  return false;
+}
+
+void
+nsPlainTextSerializer::DoAddText(bool aIsLineBreak, const nsAString& aText)
+{
+  // If we don't want any output, just return
+  if (!DoOutput()) {
+    return;
+  }
+
+  if (!aIsLineBreak) {
+    // Make sure to reset this, since it's no longer true.
+    mHasWrittenCiteBlockquote = false;
+  }
+
+  if (mLineBreakDue)
+    EnsureVerticalSpace(mFloatingLines);
+
+  if (MustSuppressLeaf()) {
+    return;
+  }
+
+  if (aIsLineBreak) {
+    // The only times we want to pass along whitespace from the original
+    // html source are if we're forced into preformatted mode via flags,
+    // or if we're prettyprinting and we're inside a <pre>.
+    // Otherwise, either we're collapsing to minimal text, or we're
+    // prettyprinting to mimic the html format, and in neither case
+    // does the formatting of the html source help us.
+    if ((mFlags & nsIDocumentEncoder::OutputPreformatted) ||
+        (mPreFormatted && !mWrapColumn) ||
+        IsInPre()) {
+      EnsureVerticalSpace(mEmptyLines+1);
+    }
+    else if (!mInWhitespace) {
+      Write(kSpace);
+      mInWhitespace = true;
+    }
+    return;
+  }
+
+  /* Check, if we are in a link (symbolized with mURL containing the URL)
+     and the text is equal to the URL. In that case we don't want to output
+     the URL twice so we scrap the text in mURL. */
+  if (!mURL.IsEmpty() && mURL.Equals(aText)) {
+    mURL.Truncate();
+  }
+  Write(aText);
+}
+
 nsresult
-nsPlainTextSerializer::DoAddLeaf(const nsIParserNode *aNode, PRInt32 aTag, 
-                                 const nsAString& aText)
+nsPlainTextSerializer::DoAddLeaf(nsIAtom* aTag)
 {
   // If we don't want any output, just return
   if (!DoOutput()) {
     return NS_OK;
   }
 
-  if (aTag != eHTMLTag_whitespace && aTag != eHTMLTag_newline) {
-    // Make sure to reset this, since it's no longer true.
-    mHasWrittenCiteBlockquote = false;
-  }
-  
   if (mLineBreakDue)
     EnsureVerticalSpace(mFloatingLines);
 
-  eHTMLTags type = (eHTMLTags)aTag;
-  
-  if ((mTagStackIndex > 1 &&
-       mTagStack[mTagStackIndex-2] == eHTMLTag_select) ||
-      (mTagStackIndex > 0 &&
-        mTagStack[mTagStackIndex-1] == eHTMLTag_select)) {
-    // Don't output the contents of SELECT elements;
-    // Might be nice, eventually, to output just the selected element.
-    // Read more in bug 31994.
-    return NS_OK;
-  }
-  else if (mTagStackIndex > 0 &&
-           (mTagStack[mTagStackIndex-1] == eHTMLTag_script ||
-            mTagStack[mTagStackIndex-1] == eHTMLTag_style)) {
-    // Don't output the contents of <script> or <style> tags;
+  if (MustSuppressLeaf()) {
     return NS_OK;
   }
-  else if (type == eHTMLTag_text) {
-    /* Check, if we are in a link (symbolized with mURL containing the URL)
-       and the text is equal to the URL. In that case we don't want to output
-       the URL twice so we scrap the text in mURL. */
-    if (!mURL.IsEmpty() && mURL.Equals(aText)) {
-      mURL.Truncate();
-    }
-    Write(aText);
-  }
-  else if (type == eHTMLTag_entity) {
-    nsIParserService* parserService = nsContentUtils::GetParserService();
-    if (parserService) {
-      nsAutoString str(aText);
-      PRInt32 entity;
-      parserService->HTMLConvertEntityToUnicode(str, &entity);
-      if (entity == -1 && 
-          !str.IsEmpty() &&
-          str.First() == (PRUnichar) '#') {
-        PRInt32 err = 0;
-        entity = str.ToInteger(&err, kAutoDetect);  // NCR
-      }
-      nsAutoString temp;
-      temp.Append(PRUnichar(entity));
-      Write(temp);
-    }
-  }
-  else if (type == eHTMLTag_br) {
+
+  if (aTag == nsGkAtoms::br) {
     // Another egregious editor workaround, see bug 38194:
     // ignore the bogus br tags that the editor sticks here and there.
-    nsAutoString typeAttr;
-    if (NS_FAILED(GetAttributeValue(aNode, nsGkAtoms::type, typeAttr))
-        || !typeAttr.EqualsLiteral("_moz")) {
+    nsAutoString tagAttr;
+    if (NS_FAILED(GetAttributeValue(nsGkAtoms::type, tagAttr))
+        || !tagAttr.EqualsLiteral("_moz")) {
       EnsureVerticalSpace(mEmptyLines+1);
     }
   }
-  else if (type == eHTMLTag_whitespace || type == eHTMLTag_newline) {
-    // The only times we want to pass along whitespace from the original
-    // html source are if we're forced into preformatted mode via flags,
-    // or if we're prettyprinting and we're inside a <pre>.
-    // Otherwise, either we're collapsing to minimal text, or we're
-    // prettyprinting to mimic the html format, and in neither case
-    // does the formatting of the html source help us.
-    if (mFlags & nsIDocumentEncoder::OutputPreformatted ||
-        (mPreFormatted && !mWrapColumn) ||
-        IsInPre()) {
-      if (type == eHTMLTag_newline)
-        EnsureVerticalSpace(mEmptyLines+1);
-      else  
-        Write(aText);
-    }
-    else if(!mInWhitespace) {
-      Write(kSpace);
-      mInWhitespace = true;
-    }
-  }
-  else if (type == eHTMLTag_hr &&
+  else if (aTag == nsGkAtoms::hr &&
            (mFlags & nsIDocumentEncoder::OutputFormatted)) {
     EnsureVerticalSpace(0);
 
     // Make a line of dashes as wide as the wrap width
     // XXX honoring percentage would be nice
     nsAutoString line;
     PRUint32 width = (mWrapColumn > 0 ? mWrapColumn : 25);
     while (line.Length() < width) {
       line.Append(PRUnichar('-'));
     }
     Write(line);
 
     EnsureVerticalSpace(0);
   }
-  else if (type == eHTMLTag_img) {
+  else if (aTag == nsGkAtoms::img) {
     /* Output (in decreasing order of preference)
        alt, title or nothing */
     // See <http://www.w3.org/TR/REC-html40/struct/objects.html#edef-IMG>
     nsAutoString imageDescription;
-    if (NS_SUCCEEDED(GetAttributeValue(aNode,
-                                       nsGkAtoms::alt,
+    if (NS_SUCCEEDED(GetAttributeValue(nsGkAtoms::alt,
                                        imageDescription))) {
       // If the alt attribute has an empty value (|alt=""|), output nothing
     }
-    else if (NS_SUCCEEDED(GetAttributeValue(aNode,
-                                            nsGkAtoms::title,
+    else if (NS_SUCCEEDED(GetAttributeValue(nsGkAtoms::title,
                                             imageDescription))
              && !imageDescription.IsEmpty()) {
       imageDescription = NS_LITERAL_STRING(" [") +
                          imageDescription +
                          NS_LITERAL_STRING("] ");
     }
    
     Write(imageDescription);
   }
 
-
   return NS_OK;
 }
 
 /**
  * Adds as many newline as necessary to get |noOfRows| empty lines
  *
  * noOfRows = -1    :   Being in the middle of some line of text
  * noOfRows =  0    :   Being at the start of a line
  * noOfRows =  n>0  :   Having n empty lines before the current line.
  */
 void
 nsPlainTextSerializer::EnsureVerticalSpace(PRInt32 noOfRows)
 {
   // If we have something in the indent we probably want to output
   // it and it's not included in the count for empty lines so we don't
   // realize that we should start a new line.
-  if(noOfRows >= 0 && !mInIndentString.IsEmpty()) {
+  if (noOfRows >= 0 && !mInIndentString.IsEmpty()) {
     EndLine(false);
     mInWhitespace = true;
   }
 
   while(mEmptyLines < noOfRows) {
     EndLine(false);
     mInWhitespace = true;
   }
@@ -1229,18 +1118,18 @@ nsPlainTextSerializer::EnsureVerticalSpa
  * this function destroys the cache information.
  *
  * It will also write indentation and quotes if we believe us to be
  * at the start of the line.
  */
 void
 nsPlainTextSerializer::FlushLine()
 {
-  if(!mCurrentLine.IsEmpty()) {
-    if(mAtFirstColumn) {
+  if (!mCurrentLine.IsEmpty()) {
+    if (mAtFirstColumn) {
       OutputQuotesAndIndent(); // XXX: Should we always do this? Bug?
     }
 
     Output(mCurrentLine);
     mAtFirstColumn = mAtFirstColumn && mCurrentLine.IsEmpty();
     mCurrentLine.Truncate();
     mCurrentLineWidth = 0;
   }
@@ -1288,60 +1177,60 @@ nsPlainTextSerializer::AddToLine(const P
                                  PRInt32 aLineFragmentLength)
 {
   PRUint32 prefixwidth = (mCiteQuoteLevel > 0 ? mCiteQuoteLevel + 1:0)+mIndent;
   
   if (mLineBreakDue)
     EnsureVerticalSpace(mFloatingLines);
 
   PRInt32 linelength = mCurrentLine.Length();
-  if(0 == linelength) {
-    if(0 == aLineFragmentLength) {
+  if (0 == linelength) {
+    if (0 == aLineFragmentLength) {
       // Nothing at all. Are you kidding me?
       return;
     }
 
-    if(mFlags & nsIDocumentEncoder::OutputFormatFlowed) {
-      if(IsSpaceStuffable(aLineFragment)
+    if (mFlags & nsIDocumentEncoder::OutputFormatFlowed) {
+      if (IsSpaceStuffable(aLineFragment)
          && mCiteQuoteLevel == 0  // We space-stuff quoted lines anyway
          )
         {
           // Space stuffing a la RFC 2646 (format=flowed).
           mCurrentLine.Append(PRUnichar(' '));
           
-          if(MayWrap()) {
+          if (MayWrap()) {
             mCurrentLineWidth += GetUnicharWidth(' ');
 #ifdef DEBUG_wrapping
             NS_ASSERTION(GetUnicharStringWidth(mCurrentLine.get(),
                                                mCurrentLine.Length()) ==
                          (PRInt32)mCurrentLineWidth,
                          "mCurrentLineWidth and reality out of sync!");
 #endif
           }
         }
     }
     mEmptyLines=-1;
   }
     
   mCurrentLine.Append(aLineFragment, aLineFragmentLength);
-  if(MayWrap()) {
+  if (MayWrap()) {
     mCurrentLineWidth += GetUnicharStringWidth(aLineFragment,
                                                aLineFragmentLength);
 #ifdef DEBUG_wrapping
     NS_ASSERTION(GetUnicharstringWidth(mCurrentLine.get(),
                                        mCurrentLine.Length()) ==
                  (PRInt32)mCurrentLineWidth,
                  "mCurrentLineWidth and reality out of sync!");
 #endif
   }
 
   linelength = mCurrentLine.Length();
 
   //  Wrap?
-  if(MayWrap())
+  if (MayWrap())
   {
 #ifdef DEBUG_wrapping
     NS_ASSERTION(GetUnicharstringWidth(mCurrentLine.get(),
                                   mCurrentLine.Length()) ==
                  (PRInt32)mCurrentLineWidth,
                  "mCurrentLineWidth and reality out of sync!");
 #endif
     // Yes, wrap!
@@ -1397,35 +1286,35 @@ nsPlainTextSerializer::AddToLine(const P
           goodSpace=(prefixwidth>mWrapColumn)?1:mWrapColumn-prefixwidth;
           while (goodSpace < linelength &&
                  !nsCRT::IsAsciiSpace(mCurrentLine.CharAt(goodSpace))) {
             goodSpace++;
           }
         }
       }
       
-      if((goodSpace < linelength) && (goodSpace > 0)) {
+      if ((goodSpace < linelength) && (goodSpace > 0)) {
         // Found a place to break
 
         // -1 (trim a char at the break position)
         // only if the line break was a space.
         if (nsCRT::IsAsciiSpace(mCurrentLine.CharAt(goodSpace))) {
           mCurrentLine.Right(restOfLine, linelength-goodSpace-1);
         }
         else {
           mCurrentLine.Right(restOfLine, linelength-goodSpace);
         }
         // if breaker was U+0020, it has to consider for delsp=yes support
         bool breakBySpace = mCurrentLine.CharAt(goodSpace) == ' ';
         mCurrentLine.Truncate(goodSpace); 
         EndLine(true, breakBySpace);
         mCurrentLine.Truncate();
         // Space stuff new line?
-        if(mFlags & nsIDocumentEncoder::OutputFormatFlowed) {
-          if(!restOfLine.IsEmpty() && IsSpaceStuffable(restOfLine.get())
+        if (mFlags & nsIDocumentEncoder::OutputFormatFlowed) {
+          if (!restOfLine.IsEmpty() && IsSpaceStuffable(restOfLine.get())
               && mCiteQuoteLevel == 0  // We space-stuff quoted lines anyway
             )
           {
             // Space stuffing a la RFC 2646 (format=flowed).
             mCurrentLine.Append(PRUnichar(' '));
             //XXX doesn't seem to work correctly for ' '
           }
         }
@@ -1453,66 +1342,66 @@ nsPlainTextSerializer::AddToLine(const P
  * one specified. Strips ending spaces from the line if it isn't
  * preformatted.
  */
 void
 nsPlainTextSerializer::EndLine(bool aSoftlinebreak, bool aBreakBySpace)
 {
   PRUint32 currentlinelength = mCurrentLine.Length();
 
-  if(aSoftlinebreak && 0 == currentlinelength) {
+  if (aSoftlinebreak && 0 == currentlinelength) {
     // No meaning
     return;
   }
 
   /* In non-preformatted mode, remove spaces from the end of the line for
    * format=flowed compatibility. Don't do this for these special cases:
    * "-- ", the signature separator (RFC 2646) shouldn't be touched and
    * "- -- ", the OpenPGP dash-escaped signature separator in inline
    * signed messages according to the OpenPGP standard (RFC 2440).
    */  
-  if(!(mFlags & nsIDocumentEncoder::OutputPreformatted) &&
+  if (!(mFlags & nsIDocumentEncoder::OutputPreformatted) &&
      (aSoftlinebreak || 
      !(mCurrentLine.EqualsLiteral("-- ") || mCurrentLine.EqualsLiteral("- -- ")))) {
     // Remove spaces from the end of the line.
     while(currentlinelength > 0 &&
           mCurrentLine[currentlinelength-1] == ' ') {
       --currentlinelength;
     }
     mCurrentLine.SetLength(currentlinelength);
   }
   
-  if(aSoftlinebreak &&
+  if (aSoftlinebreak &&
      (mFlags & nsIDocumentEncoder::OutputFormatFlowed) &&
      (mIndent == 0)) {
     // Add the soft part of the soft linebreak (RFC 2646 4.1)
     // We only do this when there is no indentation since format=flowed
     // lines and indentation doesn't work well together.
 
     // If breaker character is ASCII space with RFC 3676 support (delsp=yes),
     // add twice space.
-    if (mFlags & nsIDocumentEncoder::OutputFormatDelSp && aBreakBySpace)
+    if ((mFlags & nsIDocumentEncoder::OutputFormatDelSp) && aBreakBySpace)
       mCurrentLine.Append(NS_LITERAL_STRING("  "));
     else
       mCurrentLine.Append(PRUnichar(' '));
   }
 
-  if(aSoftlinebreak) {
+  if (aSoftlinebreak) {
     mEmptyLines=0;
   } 
   else {
     // Hard break
-    if(!mCurrentLine.IsEmpty() || !mInIndentString.IsEmpty()) {
+    if (!mCurrentLine.IsEmpty() || !mInIndentString.IsEmpty()) {
       mEmptyLines=-1;
     }
 
     mEmptyLines++;
   }
 
-  if(mAtFirstColumn) {
+  if (mAtFirstColumn) {
     // If we don't have anything "real" to output we have to
     // make sure the indent doesn't end in a space since that
     // would trick a format=flowed-aware receiver.
     bool stripTrailingSpaces = mCurrentLine.IsEmpty();
     OutputQuotesAndIndent(stripTrailingSpaces);
   }
 
   mCurrentLine.Append(mLineBreak);
@@ -1562,32 +1451,32 @@ nsPlainTextSerializer::OutputQuotesAndIn
       ) {
     nsAutoString spaces;
     for (int i=0; i < indentwidth; ++i)
       spaces.Append(PRUnichar(' '));
     stringToOutput += spaces;
     mAtFirstColumn = false;
   }
   
-  if(!mInIndentString.IsEmpty()) {
+  if (!mInIndentString.IsEmpty()) {
     stringToOutput += mInIndentString;
     mAtFirstColumn = false;
     mInIndentString.Truncate();
   }
 
-  if(stripTrailingSpaces) {
+  if (stripTrailingSpaces) {
     PRInt32 lineLength = stringToOutput.Length();
     while(lineLength > 0 &&
           ' ' == stringToOutput[lineLength-1]) {
       --lineLength;
     }
     stringToOutput.SetLength(lineLength);
   }
 
-  if(!stringToOutput.IsEmpty()) {
+  if (!stringToOutput.IsEmpty()) {
     Output(stringToOutput);
   }
     
 }
 
 /**
  * Write a string. This is the highlevel function to use to get text output.
  * By using AddToLine, Output, EndLine and other functions it handles quotation,
@@ -1654,34 +1543,34 @@ nsPlainTextSerializer::Write(const nsASt
       // Find one of '\n' or '\r' using iterators since nsAString
       // doesn't have the old FindCharInSet function.
       nsAString::const_iterator iter;           str.BeginReading(iter);
       nsAString::const_iterator done_searching; str.EndReading(done_searching);
       iter.advance(bol); 
       PRInt32 new_newline = bol;
       newline = kNotFound;
       while(iter != done_searching) {
-        if('\n' == *iter || '\r' == *iter) {
+        if ('\n' == *iter || '\r' == *iter) {
           newline = new_newline;
           break;
         }
-        if(' ' != *iter)
+        if (' ' != *iter)
           spacesOnly = false;
         ++new_newline;
         ++iter;
       }
 
       // Done searching
       nsAutoString stringpart;
-      if(newline == kNotFound) {
+      if (newline == kNotFound) {
         // No new lines.
         stringpart.Assign(Substring(str, bol, totLen - bol));
-        if(!stringpart.IsEmpty()) {
+        if (!stringpart.IsEmpty()) {
           PRUnichar lastchar = stringpart[stringpart.Length()-1];
-          if((lastchar == '\t') || (lastchar == ' ') ||
+          if ((lastchar == '\t') || (lastchar == ' ') ||
              (lastchar == '\r') ||(lastchar == '\n')) {
             mInWhitespace = true;
           } 
           else {
             mInWhitespace = false;
           }
         }
         mEmptyLines=-1;
@@ -1691,17 +1580,17 @@ nsPlainTextSerializer::Write(const nsASt
       else {
         // There is a newline
         stringpart.Assign(Substring(str, bol, newline-bol));
         mInWhitespace = true;
         outputLineBreak = true;
         mEmptyLines=0;
         atFirstColumn = true;
         bol = newline+1;
-        if('\r' == *iter && bol < totLen && '\n' == *++iter) {
+        if ('\r' == *iter && bol < totLen && '\n' == *++iter) {
           // There was a CRLF in the input. This used to be illegal and
           // stripped by the parser. Apparently not anymore. Let's skip
           // over the LF.
           bol++;
         }
       }
 
       mCurrentLine.AssignLiteral("");
@@ -1710,17 +1599,17 @@ nsPlainTextSerializer::Write(const nsASt
             !stringpart.EqualsLiteral("-- ") &&
             !stringpart.EqualsLiteral("- -- "))
           stringpart.Trim(" ", false, true, true);
         if (IsSpaceStuffable(stringpart.get()) && stringpart[0] != '>')
           mCurrentLine.Append(PRUnichar(' '));
       }
       mCurrentLine.Append(stringpart);
 
-      if(outputQuotes) {
+      if (outputQuotes) {
         // Note: this call messes with mAtFirstColumn
         OutputQuotesAndIndent();
       }
 
       Output(mCurrentLine);
       if (outputLineBreak) {
         Output(mLineBreak);
       }
@@ -1750,17 +1639,17 @@ nsPlainTextSerializer::Write(const nsASt
     nsAutoString remaining;
     str.Right(remaining, totLen - bol);
     foo = ToNewCString(remaining);
     //    printf("Next line: bol = %d, newlinepos = %d, totLen = %d, string = '%s'\n",
     //           bol, nextpos, totLen, foo);
     nsMemory::Free(foo);
 #endif
 
-    if(nextpos == kNotFound) {
+    if (nextpos == kNotFound) {
       // The rest of the string
       offsetIntoBuffer = str.get() + bol;
       AddToLine(offsetIntoBuffer, totLen-bol);
       bol=totLen;
       mInWhitespace=false;
     } 
     else {
       // There's still whitespace left in the string
@@ -1777,29 +1666,29 @@ nsPlainTextSerializer::Write(const nsASt
       // If we're already in whitespace and not preformatted, just skip it:
       if (mInWhitespace && (nextpos == bol) && !mPreFormatted &&
           !(mFlags & nsIDocumentEncoder::OutputPreformatted)) {
         // Skip whitespace
         bol++;
         continue;
       }
 
-      if(nextpos == bol) {
+      if (nextpos == bol) {
         // Note that we are in whitespace.
         mInWhitespace = true;
         offsetIntoBuffer = str.get() + nextpos;
         AddToLine(offsetIntoBuffer, 1);
         bol++;
         continue;
       }
       
       mInWhitespace = true;
       
       offsetIntoBuffer = str.get() + bol;
-      if(mPreFormatted || (mFlags & nsIDocumentEncoder::OutputPreformatted)) {
+      if (mPreFormatted || (mFlags & nsIDocumentEncoder::OutputPreformatted)) {
         // Preserve the real whitespace character
         nextpos++;
         AddToLine(offsetIntoBuffer, nextpos-bol);
         bol = nextpos;
       } 
       else {
         // Replace the whitespace with a space
         AddToLine(offsetIntoBuffer, nextpos-bol);
@@ -1811,118 +1700,70 @@ nsPlainTextSerializer::Write(const nsASt
 }
 
 
 /**
  * Gets the value of an attribute in a string. If the function returns
  * NS_ERROR_NOT_AVAILABLE, there was none such attribute specified.
  */
 nsresult
-nsPlainTextSerializer::GetAttributeValue(const nsIParserNode* aNode,
-                                         nsIAtom* aName,
+nsPlainTextSerializer::GetAttributeValue(nsIAtom* aName,
                                          nsString& aValueRet)
 {
   if (mElement) {
     if (mElement->GetAttr(kNameSpaceID_None, aName, aValueRet)) {
       return NS_OK;
     }
   }
-  else if (aNode) {
-    nsDependentAtomString name(aName); 
-
-    PRInt32 count = aNode->GetAttributeCount();
-    for (PRInt32 i=0;i<count;i++) {
-      const nsAString& key = aNode->GetKeyAt(i);
-      if (key.Equals(name, nsCaseInsensitiveStringComparator())) {
-        aValueRet = aNode->GetValueAt(i);
-        return NS_OK;
-      }
-    }
-  }
 
   return NS_ERROR_NOT_AVAILABLE;
 }
 
 /**
  * Returns true, if the element was inserted by Moz' TXT->HTML converter.
  * In this case, we should ignore it.
  */
 bool 
-nsPlainTextSerializer::IsCurrentNodeConverted(const nsIParserNode* aNode)
+nsPlainTextSerializer::IsCurrentNodeConverted()
 {
   nsAutoString value;
-  nsresult rv = GetAttributeValue(aNode, nsGkAtoms::_class, value);
+  nsresult rv = GetAttributeValue(nsGkAtoms::_class, value);
   return (NS_SUCCEEDED(rv) &&
           (value.EqualsIgnoreCase("moz-txt", 7) ||
            value.EqualsIgnoreCase("\"moz-txt", 8)));
 }
 
 
 // static
-PRInt32
+nsIAtom*
 nsPlainTextSerializer::GetIdForContent(nsIContent* aContent)
 {
   if (!aContent->IsHTML()) {
-    return eHTMLTag_unknown;
+    return nsnull;
   }
 
-  nsIParserService* parserService = nsContentUtils::GetParserService();
-
-  return parserService ? parserService->HTMLAtomTagToId(aContent->Tag()) :
-                         eHTMLTag_unknown;
-}
-
-/**
- * Returns true if the id represents an element of block type.
- * Can be used to determine if a new paragraph should be started.
- */
-bool 
-nsPlainTextSerializer::IsBlockLevel(PRInt32 aId)
-{
-  bool isBlock = false;
-
-  nsIParserService* parserService = nsContentUtils::GetParserService();
-  if (parserService) {
-    parserService->IsBlock(aId, isBlock);
-  }
-
-  return isBlock;
-}
-
-/**
- * Returns true if the id represents a container.
- */
-bool 
-nsPlainTextSerializer::IsContainer(PRInt32 aId)
-{
-  bool isContainer = false;
-
-  nsIParserService* parserService = nsContentUtils::GetParserService();
-  if (parserService) {
-    parserService->IsContainer(aId, isContainer);
-  }
-
-  return isContainer;
+  nsIAtom* localName = aContent->Tag();
+  return localName->IsStaticAtom() ? localName : nsnull;
 }
 
 /**
  * Returns true if we currently are inside a <pre>. The check is done
  * by traversing the tag stack looking for <pre> until we hit a block
  * level tag which is assumed to override any <pre>:s below it in
  * the stack. To do this correctly to a 100% would require access
  * to style which we don't support in this converter.
  */  
 bool
 nsPlainTextSerializer::IsInPre()
 {
   PRInt32 i = mTagStackIndex;
   while(i > 0) {
-    if(mTagStack[i-1] == eHTMLTag_pre)
+    if (mTagStack[i - 1] == nsGkAtoms::pre)
       return true;
-    if(IsBlockLevel(mTagStack[i-1])) {
+    if (nsContentUtils::IsHTMLBlock(mTagStack[i - 1])) {
       // We assume that every other block overrides a <pre>
       return false;
     }
     --i;
   }
 
   // Not a <pre> in the whole stack
   return false;
@@ -1932,51 +1773,51 @@ nsPlainTextSerializer::IsInPre()
  * This method is required only to identify LI's inside OL.
  * Returns TRUE if we are inside an OL tag and FALSE otherwise.
  */
 bool
 nsPlainTextSerializer::IsInOL()
 {
   PRInt32 i = mTagStackIndex;
   while(--i >= 0) {
-    if(mTagStack[i] == eHTMLTag_ol)
+    if (mTagStack[i] == nsGkAtoms::ol)
       return true;
-    if (mTagStack[i] == eHTMLTag_ul) {
+    if (mTagStack[i] == nsGkAtoms::ul) {
       // If a UL is reached first, LI belongs the UL nested in OL.
       return false;
     }
   }
   // We may reach here for orphan LI's.
   return false;
 }
 
 /*
   @return 0 = no header, 1 = h1, ..., 6 = h6
 */
-PRInt32 HeaderLevel(eHTMLTags aTag)
+PRInt32 HeaderLevel(nsIAtom* aTag)
 {
-  PRInt32 result;
-  switch (aTag)
-  {
-    case eHTMLTag_h1:
-      result = 1; break;
-    case eHTMLTag_h2:
-      result = 2; break;
-    case eHTMLTag_h3:
-      result = 3; break;
-    case eHTMLTag_h4:
-      result = 4; break;
-    case eHTMLTag_h5:
-      result = 5; break;
-    case eHTMLTag_h6:
-      result = 6; break;
-    default:
-      result = 0; break;
+  if (aTag == nsGkAtoms::h1) {
+    return 1;
+  }
+  if (aTag == nsGkAtoms::h2) {
+    return 2;
+  }
+  if (aTag == nsGkAtoms::h3) {
+    return 3;
   }
-  return result;
+  if (aTag == nsGkAtoms::h4) {
+    return 4;
+  }
+  if (aTag == nsGkAtoms::h5) {
+    return 5;
+  }
+  if (aTag == nsGkAtoms::h6) {
+    return 6;
+  }
+  return 0;
 }
 
 
 /*
  * This is an implementation of GetUnicharWidth() and
  * GetUnicharStringWidth() as defined in
  * "The Single UNIX Specification, Version 2, The Open Group, 1997"
  * <http://www.UNIX-systems.org/online.html>
--- a/content/base/src/nsPlainTextSerializer.h
+++ b/content/base/src/nsPlainTextSerializer.h
@@ -40,36 +40,31 @@
  * nsIDocumentEncoder to convert a DOM into plaintext in a nice way
  * (eg for copy/paste as plaintext).
  */
 
 #ifndef nsPlainTextSerializer_h__
 #define nsPlainTextSerializer_h__
 
 #include "nsIContentSerializer.h"
-#include "nsIHTMLContentSink.h"
-#include "nsHTMLTags.h"
 #include "nsCOMPtr.h"
 #include "nsString.h"
 #include "nsILineBreaker.h"
 #include "nsIContent.h"
 #include "nsIAtom.h"
-#include "nsIHTMLToTextSink.h"
 #include "nsIDocumentEncoder.h"
 #include "nsTArray.h"
 
 namespace mozilla {
 namespace dom {
 class Element;
 } // namespace dom
 } // namespace mozilla
 
-class nsPlainTextSerializer : public nsIContentSerializer,
-                              public nsIHTMLContentSink,
-                              public nsIHTMLToTextSink
+class nsPlainTextSerializer : public nsIContentSerializer
 {
 public:
   nsPlainTextSerializer();
   virtual ~nsPlainTextSerializer();
 
   NS_DECL_ISUPPORTS
 
   // nsIContentSerializer
@@ -95,63 +90,39 @@ public:
                                 nsAString& aStr); 
   NS_IMETHOD AppendElementEnd(mozilla::dom::Element* aElement,
                               nsAString& aStr);
   NS_IMETHOD Flush(nsAString& aStr);
 
   NS_IMETHOD AppendDocumentStart(nsIDocument *aDocument,
                                  nsAString& aStr);
 
-  // nsIContentSink
-  NS_IMETHOD WillParse(void) { return NS_OK; }
-  NS_IMETHOD WillInterrupt(void) { return NS_OK; }
-  NS_IMETHOD WillResume(void) { return NS_OK; }
-  NS_IMETHOD SetParser(nsParserBase* aParser) { return NS_OK; }
-  NS_IMETHOD OpenContainer(const nsIParserNode& aNode);
-  NS_IMETHOD CloseContainer(const nsHTMLTag aTag);
-  NS_IMETHOD AddLeaf(const nsIParserNode& aNode);
-  virtual void FlushPendingNotifications(mozFlushType aType) { }
-  NS_IMETHOD SetDocumentCharset(nsACString& aCharset) { return NS_OK; }
-  virtual nsISupports *GetTarget() { return nsnull; }
-
-  // nsIHTMLContentSink
-  NS_IMETHOD OpenHead();
-  NS_IMETHOD IsEnabled(PRInt32 aTag, bool* aReturn);
-  NS_IMETHOD NotifyTagObservers(nsIParserNode* aNode) { return NS_OK; }
-
-  NS_IMETHOD BeginContext(PRInt32 aPosition) { return NS_OK; }
-  NS_IMETHOD EndContext(PRInt32 aPosition) { return NS_OK; }
-  NS_IMETHOD DidProcessTokens(void) { return NS_OK; }
-  NS_IMETHOD WillProcessAToken(void) { return NS_OK; }
-  NS_IMETHOD DidProcessAToken(void) { return NS_OK; }
-
-  // nsIHTMLToTextSink
-  NS_IMETHOD Initialize(nsAString* aOutString,
-                        PRUint32 aFlags, PRUint32 aWrapCol);
-
 protected:
-  nsresult GetAttributeValue(const nsIParserNode* node, nsIAtom* aName, nsString& aValueRet);
+  nsresult GetAttributeValue(nsIAtom* aName, nsString& aValueRet);
   void AddToLine(const PRUnichar* aStringToAdd, PRInt32 aLength);
   void EndLine(bool softlinebreak, bool aBreakBySpace = false);
   void EnsureVerticalSpace(PRInt32 noOfRows);
   void FlushLine();
   void OutputQuotesAndIndent(bool stripTrailingSpaces=false);
   void Output(nsString& aString);
   void Write(const nsAString& aString);
-  bool IsBlockLevel(PRInt32 aId);
-  bool IsContainer(PRInt32 aId);
   bool IsInPre();
   bool IsInOL();
-  bool IsCurrentNodeConverted(const nsIParserNode* aNode);
-  static PRInt32 GetIdForContent(nsIContent* aContent);
-  nsresult DoOpenContainer(const nsIParserNode* aNode, PRInt32 aTag);
-  nsresult DoCloseContainer(PRInt32 aTag);
-  nsresult DoAddLeaf(const nsIParserNode* aNode,
-                     PRInt32 aTag,
-                     const nsAString& aText);
+  bool IsCurrentNodeConverted();
+  bool MustSuppressLeaf();
+
+  /**
+   * Returns the local name of the element as an atom if the element is an
+   * HTML element and the atom is a static atom. Otherwise, nsnull is returned.
+   */
+  static nsIAtom* GetIdForContent(nsIContent* aContent);
+  nsresult DoOpenContainer(nsIAtom* aTag);
+  nsresult DoCloseContainer(nsIAtom* aTag);
+  nsresult DoAddLeaf(nsIAtom* aTag);
+  void DoAddText(bool aIsWhitespace, const nsAString& aText);
 
   // Inlined functions
   inline bool MayWrap()
   {
     return mWrapColumn &&
       ((mFlags & nsIDocumentEncoder::OutputFormatted) ||
        (mFlags & nsIDocumentEncoder::OutputWrap));
   }
@@ -235,24 +206,25 @@ protected:
                                           mHeaderCounter[1] for <h1> etc. */
 
   nsRefPtr<mozilla::dom::Element> mElement;
 
   // For handling table rows
   nsAutoTArray<bool, 8> mHasWrittenCellsForRow;
   
   // Values gotten in OpenContainer that is (also) needed in CloseContainer
-  nsAutoTArray<bool, 8> mCurrentNodeIsConverted;
   nsAutoTArray<bool, 8> mIsInCiteBlockquote;
 
   // The output data
   nsAString*            mOutputString;
 
-  // The tag stack: the stack of tags we're operating on, so we can nest:
-  nsHTMLTag       *mTagStack;
+  // The tag stack: the stack of tags we're operating on, so we can nest.
+  // The stack only ever points to static atoms, so they don't need to be
+  // refcounted.
+  nsIAtom**        mTagStack;
   PRUint32         mTagStackIndex;
 
   // Content in the stack above this index should be ignored:
   PRUint32          mIgnoreAboveIndex;
 
   // The stack for ordered lists
   PRInt32         *mOLStack;
   PRUint32         mOLStackIndex;
--- a/content/events/test/test_eventctors.html
+++ b/content/events/test/test_eventctors.html
@@ -321,20 +321,58 @@ ok(e.type, "hello", "Wrong event type!")
 ok(!e.isTrusted, "Event shouldn't be trusted!");
 ok(e.bubbles, "Event should bubble!");
 ok(e.cancelable, "Event should be cancelable!");
 is(e.detail, 1, "detail should be 1");
 is(e.view, window, "view should be window");
 document.dispatchEvent(e);
 is(receivedEvent, e, "Wrong event!");
 
-// UIEvent
+// StorageEvent
 
 try {
-  e = new UIEvent();
+  e = new StorageEvent();
+} catch(exp) {
+  ex = true;
+}
+ok(ex, "First parameter is required!");
+ex = false;
+
+e = new StorageEvent("hello");
+ok(e.type, "hello", "Wrong event type!");
+ok(!e.isTrusted, "Event shouldn't be trusted!");
+ok(!e.bubbles, "Event shouldn't bubble!");
+ok(!e.cancelable, "Event shouldn't be cancelable!");
+is(e.key, "", "key should be ''");
+is(e.oldValue, null, "oldValue should be null");
+is(e.newValue, null, "newValue should be null");
+is(e.url, "", "url should be ''");
+document.dispatchEvent(e);
+is(receivedEvent, e, "Wrong event!");
+
+e = new StorageEvent("hello",
+  { bubbles: true, cancelable: true, key: "key",
+    oldValue: "oldValue", newValue: "newValue", url: "url",
+    storageArea: localStorage });
+ok(e.type, "hello", "Wrong event type!");
+ok(!e.isTrusted, "Event shouldn't be trusted!");
+ok(e.bubbles, "Event should bubble!");
+ok(e.cancelable, "Event should be cancelable!");
+is(e.key, "key", "Wrong value");
+is(e.oldValue, "oldValue", "Wrong value");
+is(e.newValue, "newValue", "Wrong value");
+is(e.url, "url", "Wrong value");
+is(e.storageArea, localStorage, "Wrong value");
+document.dispatchEvent(e);
+is(receivedEvent, e, "Wrong event!");
+
+// MouseEvent
+
+try {
+  e = new MouseEvent();
 } catch(exp) {
   ex = true;
 }
 ok(ex, "First parameter is required!");
 ex = false;
 
 e = new MouseEvent("hello");
 ok(e.type, "hello", "Wrong event type!");
--- a/content/html/content/src/nsFormSubmission.cpp
+++ b/content/html/content/src/nsFormSubmission.cpp
@@ -264,17 +264,16 @@ HandleMailtoSubject(nsCString& aPath) {
     if (NS_FAILED(rv))
       return;
     const PRUnichar *formatStrings[] = { brandName.get() };
     nsXPIDLString subjectStr;
     rv = nsContentUtils::FormatLocalizedString(
                                            nsContentUtils::eFORMS_PROPERTIES,
                                            "DefaultFormSubject",
                                            formatStrings,
-                                           ArrayLength(formatStrings),
                                            subjectStr);
     if (NS_FAILED(rv))
       return;
     aPath.AppendLiteral("subject=");
     nsCString subjectStrEscaped;
     aPath.Append(NS_EscapeURL(NS_ConvertUTF16toUTF8(subjectStr), esc_Query,
                               subjectStrEscaped));
   }
--- a/content/html/content/src/nsHTMLInputElement.cpp
+++ b/content/html/content/src/nsHTMLInputElement.cpp
@@ -3825,17 +3825,17 @@ nsHTMLInputElement::GetValidationMessage
       GetTextLength(&textLength);
 
       strMaxLength.AppendInt(maxLength);
       strTextLength.AppendInt(textLength);
 
       const PRUnichar* params[] = { strMaxLength.get(), strTextLength.get() };
       rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
                                                  "FormValidationTextTooLong",
-                                                 params, 2, message);
+                                                 params, message);
       aValidationMessage = message;
       break;
     }
     case VALIDITY_STATE_VALUE_MISSING:
     {
       nsXPIDLString message;
       nsCAutoString key;
       switch (mType)
@@ -3884,17 +3884,17 @@ nsHTMLInputElement::GetValidationMessage
                                                 message);
       } else {
         if (title.Length() > nsIConstraintValidation::sContentSpecifiedMaxLengthMessage) {
           title.Truncate(nsIConstraintValidation::sContentSpecifiedMaxLengthMessage);
         }
         const PRUnichar* params[] = { title.get() };
         rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
                                                    "FormValidationPatternMismatchWithTitle",
-                                                   params, 1, message);
+                                                   params, message);
       }
       aValidationMessage = message;
       break;
     }
     default:
       rv = nsIConstraintValidation::GetValidationMessage(aValidationMessage, aType);
   }
 
--- a/content/html/content/src/nsHTMLTextAreaElement.cpp
+++ b/content/html/content/src/nsHTMLTextAreaElement.cpp
@@ -1418,17 +1418,17 @@ nsHTMLTextAreaElement::GetValidationMess
         GetTextLength(&textLength);
 
         strMaxLength.AppendInt(maxLength);
         strTextLength.AppendInt(textLength);
 
         const PRUnichar* params[] = { strMaxLength.get(), strTextLength.get() };
         rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
                                                    "FormValidationTextTooLong",
-                                                   params, 2, message);
+                                                   params, message);
         aValidationMessage = message;
       }
       break;
     case VALIDITY_STATE_VALUE_MISSING:
       {
         nsXPIDLString message;
         rv = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
                                                 "FormValidationValueMissing",
--- a/content/svg/content/src/nsSVGElement.cpp
+++ b/content/svg/content/src/nsSVGElement.cpp
@@ -1461,20 +1461,24 @@ nsSVGElement::MaybeSerializeAttrBeforeRe
 {
   if (!aNotify ||
       !nsContentUtils::HasMutationListeners(this,
                                             NS_EVENT_BITS_MUTATION_ATTRMODIFIED,
                                             this)) {
     return;
   }
 
+  const nsAttrValue* attrValue = mAttrsAndChildren.GetAttr(aName);
+  if (!attrValue)
+    return;
+
   nsAutoString serializedValue;
-  mAttrsAndChildren.GetAttr(aName)->ToString(serializedValue);
-  nsAttrValue attrValue(serializedValue);
-  mAttrsAndChildren.SetAndTakeAttr(aName, attrValue);
+  attrValue->ToString(serializedValue);
+  nsAttrValue oldAttrValue(serializedValue);
+  mAttrsAndChildren.SetAndTakeAttr(aName, oldAttrValue);
 }
 
 /* static */
 nsIAtom* nsSVGElement::GetEventNameForAttr(nsIAtom* aAttr)
 {
   if (aAttr == nsGkAtoms::onload)
     return nsGkAtoms::onSVGLoad;
   if (aAttr == nsGkAtoms::onunload)
--- a/content/svg/content/test/test_SVGLengthList.xhtml
+++ b/content/svg/content/test/test_SVGLengthList.xhtml
@@ -56,16 +56,23 @@ function run_tests()
   eventChecker.expect("modify");
   lengths[0].valueAsString = "10";
   eventChecker.expect("");
   lengths[0].value = 10;
   lengths[0].valueInSpecifiedUnits = 10;
   lengths[0].valueAsString = "10";
   lengths[0].convertToSpecifiedUnits(SVGLength.SVG_LENGTHTYPE_NUMBER);
   lengths[0].newValueSpecifiedUnits(SVGLength.SVG_LENGTHTYPE_NUMBER, 10);
+  // -- Attribute removal
+  eventChecker.expect("remove");
+  text.removeAttribute("x");
+  // -- Non-existent attribute removal
+  eventChecker.expect("");
+  text.removeAttribute("x");
+  text.removeAttributeNS(null, "x");
   eventChecker.finish();
 
   SimpleTest.finish();
 }
 
 window.addEventListener("load", run_tests, false);
 
 ]]>
--- a/content/svg/content/test/test_SVGNumberList.xhtml
+++ b/content/svg/content/test/test_SVGNumberList.xhtml
@@ -45,16 +45,23 @@ function run_tests()
   eventChecker.expect("modify modify");
   numbers[0].value = 15;
   text.setAttribute("rotate", "17 20 30");
   // -- Redundant changes
   eventChecker.expect("");
   numbers[0].value = 17;
   numbers[1].value = 20;
   text.setAttribute("rotate", "17 20 30");
+  // -- Attribute removal
+  eventChecker.expect("remove");
+  text.removeAttribute("rotate");
+  // -- Non-existent attribute removal
+  eventChecker.expect("");
+  text.removeAttribute("rotate");
+  text.removeAttributeNS(null, "rotate");
   eventChecker.finish();
 
   SimpleTest.finish();
 }
 
 window.addEventListener("load", run_tests, false);
 
 ]]>
--- a/content/svg/content/test/test_SVGPathSegList.xhtml
+++ b/content/svg/content/test/test_SVGPathSegList.xhtml
@@ -100,16 +100,25 @@ function run_tests()
   list[0].y = 5;
   path.setAttribute("d", "M20,5 L12,34");
 
   // -- Redundant changes
   eventChecker.expect("");
   list[0].x = 20;
   list[1].y = 34;
   path.setAttribute("d", "M20,5 L12,34");
+
+  // -- Attribute removal
+  eventChecker.expect("remove");
+  path.removeAttribute("d");
+
+  // -- Non-existent attribute removal
+  eventChecker.expect("");
+  path.removeAttribute("d");
+  path.removeAttributeNS(null, "d");
   eventChecker.finish();
 
   SimpleTest.finish();
 }
 
 window.addEventListener("load", run_tests, false);
 
 ]]>
--- a/content/svg/content/test/test_SVGPointList.xhtml
+++ b/content/svg/content/test/test_SVGPointList.xhtml
@@ -45,16 +45,23 @@ function run_tests()
   eventChecker.expect("modify modify");
   points[0].x = 40;
   polyline.setAttribute("points", "30,375 150,380");
   // -- Redundant changes
   eventChecker.expect("");
   points[0].x = 30;
   points[1].y = 380;
   polyline.setAttribute("points", "30,375 150,380");
+  // -- Attribute removal
+  eventChecker.expect("remove");
+  polyline.removeAttribute("points");
+  // -- Non-existent attribute removal
+  eventChecker.expect("");
+  polyline.removeAttribute("points");
+  polyline.removeAttributeNS(null, "points");
   eventChecker.finish();
 
   SimpleTest.finish();
 }
 
 window.addEventListener("load", run_tests, false);
 
 ]]>
--- a/content/svg/content/test/test_SVGTransformList.xhtml
+++ b/content/svg/content/test/test_SVGTransformList.xhtml
@@ -419,16 +419,26 @@ function testMutationEvents(g)
   list[0].matrix.e = 5;
 
   // setAttribute interaction
   eventChecker.expect("modify");
   list[0].setMatrix(mx);
   eventChecker.expect("");
   g.setAttribute("transform", "matrix(1, 0, 0, 1, 0, 0)");
   list[0].setMatrix(mx);
+
+  // Attribute removal
+  eventChecker.expect("remove");
+  g.removeAttribute("transform");
+
+  // Non-existent attribute removal
+  eventChecker.expect("");
+  g.removeAttribute("transform");
+  g.removeAttributeNS(null, "transform");
+
   eventChecker.finish();
 }
 
 window.addEventListener("load", main, false);
 
 ]]>
 </script>
 </pre>
--- a/content/svg/content/test/test_SVGxxxList.xhtml
+++ b/content/svg/content/test/test_SVGxxxList.xhtml
@@ -830,16 +830,17 @@ function run_baseVal_API_tests()
          'an object of the wrong type.');
       eventChecker.ignoreEvents();
     }
 
     // Test removal and addition events
 
     eventChecker.expect("remove add");
     t.element.removeAttribute(t.attr_name);
+    t.element.removeAttributeNS(null, t.attr_name);
     res = t.baseVal.appendItem(item);
     eventChecker.finish();
   }
 }
 
 
 /**
  * This function tests the SVGXxxList API for the anim val list (see also the
--- a/content/svg/content/test/test_dataTypesModEvents.html
+++ b/content/svg/content/test/test_dataTypesModEvents.html
@@ -33,16 +33,17 @@ function runTests()
 
   // class attribute
  
   eventChecker.watchAttr(filter, "class");
   eventChecker.expect("add modify remove add");
   filter.setAttribute("class", "foo");
   filter.className.baseVal = "bar";
   filter.removeAttribute("class");
+  filter.removeAttributeNS(null, "class");
   filter.className.baseVal = "foo";
 
   eventChecker.expect("");
   filter.className.baseVal = "foo";
   filter.setAttribute("class", "foo");
 
   // length attribute
 
@@ -52,16 +53,17 @@ function runTests()
   marker.markerWidth.baseVal.value = 8;
   marker.markerWidth.baseVal.valueInSpecifiedUnits = 9;
   marker.markerWidth.baseVal.valueAsString = "10";
   marker.markerWidth.baseVal.convertToSpecifiedUnits(
     SVGLength.SVG_LENGTHTYPE_CM);
   marker.markerWidth.baseVal.newValueSpecifiedUnits(
     SVGLength.SVG_LENGTHTYPE_MM, 11);
   marker.removeAttribute("markerWidth");
+  marker.removeAttributeNS(null, "markerWidth");
   marker.markerWidth.baseVal.value = 8;
 
   eventChecker.expect("remove add modify");
   marker.removeAttribute("markerWidth");
   console.log(marker.getAttribute("markerWidth"));
   marker.markerWidth.baseVal.convertToSpecifiedUnits(
     SVGLength.SVG_LENGTHTYPE_NUMBER);
   console.log(marker.getAttribute("markerWidth"));
@@ -79,43 +81,46 @@ function runTests()
 
   // number attribute
 
   eventChecker.watchAttr(convolve, "divisor");
   eventChecker.expect("add modify remove add");
   convolve.setAttribute("divisor", "12.5");
   convolve.divisor.baseVal = 6;
   convolve.removeAttribute("divisor");
+  convolve.removeAttributeNS(null, "divisor");
   convolve.divisor.baseVal = 8;
 
   eventChecker.expect("");
   convolve.divisor.baseVal = 8;
   convolve.setAttribute("divisor", "8");
 
   // number-optional-number attribute
 
   eventChecker.watchAttr(blur, "stdDeviation");
   eventChecker.expect("add modify remove add");
   blur.setAttribute("stdDeviation", "5, 6");
   blur.stdDeviationX.baseVal = 8;
   blur.removeAttribute("stdDeviation");
+  blur.removeAttributeNS(null, "stdDeviation");
   blur.setAttribute("stdDeviation", "2, 3");
 
   eventChecker.expect("");
   blur.stdDeviationX.baseVal = 2;
   blur.stdDeviationY.baseVal = 3;
   blur.setAttribute("stdDeviation", "2, 3");
 
   // integer attribute
 
   eventChecker.watchAttr(convolve, "targetX");
   eventChecker.expect("add modify remove add");
   convolve.setAttribute("targetX", "12");
   convolve.targetX.baseVal = 6;
   convolve.removeAttribute("targetX");
+  convolve.removeAttributeNS(null, "targetX");
   convolve.targetX.baseVal = 8;
 
   // Check redundant change when comparing typed value to attribute value
   eventChecker.expect("");
   convolve.setAttribute("targetX", "8");
   // Check redundant change when comparing attribute value to typed value
   eventChecker.expect("remove add");
   convolve.removeAttribute("targetX");
@@ -124,16 +129,17 @@ function runTests()
 
   // integer-optional-integer attribute
 
   eventChecker.watchAttr(filter, "filterRes");
   eventChecker.expect("add modify remove add");
   filter.setAttribute("filterRes", "60, 70");
   filter.filterResX.baseVal = 50;
   filter.removeAttribute("filterRes");
+  filter.removeAttributeNS(null, "filterRes");
   filter.setAttribute("filterRes", "50, 60");
 
   eventChecker.expect("");
   filter.filterResX.baseVal = 50;
   filter.setAttribute("filterRes", "50, 60");
   filter.filterResY.baseVal = 60;
 
   // angle attribute
@@ -144,16 +150,17 @@ function runTests()
   marker.orientAngle.baseVal.value = 12;
   marker.orientAngle.baseVal.valueInSpecifiedUnits = 23;
   marker.orientAngle.baseVal.valueAsString = "34";
   marker.orientAngle.baseVal.newValueSpecifiedUnits(
     SVGAngle.SVG_ANGLETYPE_GRAD, 34);
   marker.orientAngle.baseVal.newValueSpecifiedUnits(
     SVGAngle.SVG_ANGLETYPE_GRAD, 45);
   marker.removeAttribute("orient");
+  marker.removeAttributeNS(null, "orient");
   marker.orientAngle.baseVal.value = 40;
 
   eventChecker.expect("");
   marker.orientAngle.baseVal.value = 40;
   marker.orientAngle.baseVal.valueInSpecifiedUnits = 40;
   marker.orientAngle.baseVal.valueAsString = "40";
   marker.orientAngle.baseVal.convertToSpecifiedUnits(
     SVGAngle.SVG_ANGLETYPE_UNSPECIFIED);
@@ -162,73 +169,78 @@ function runTests()
 
   // boolean attribute
 
   eventChecker.watchAttr(convolve, "preserveAlpha");
   eventChecker.expect("add modify remove add");
   convolve.setAttribute("preserveAlpha", "true");
   convolve.preserveAlpha.baseVal = false;
   convolve.removeAttribute("preserveAlpha");
+  convolve.removeAttributeNS(null, "preserveAlpha");
   convolve.preserveAlpha.baseVal = true;
 
   eventChecker.expect("");
   convolve.preserveAlpha.baseVal = true;
   convolve.setAttribute("preserveAlpha", "true");
 
   // enum attribute
 
   eventChecker.watchAttr(convolve, "edgeMode");
   eventChecker.expect("add modify remove add");
   convolve.setAttribute("edgeMode", "none");
   convolve.edgeMode.baseVal = SVGFEConvolveMatrixElement.SVG_EDGEMODE_WRAP;
   convolve.removeAttribute("edgeMode");
+  convolve.removeAttributeNS(null, "edgeMode");
   convolve.edgeMode.baseVal = SVGFEConvolveMatrixElement.SVG_EDGEMODE_NONE;
 
   eventChecker.expect("");
   convolve.edgeMode.baseVal = SVGFEConvolveMatrixElement.SVG_EDGEMODE_NONE;
   convolve.setAttribute("edgeMode", "none");
   convolve.edgeMode.baseVal = SVGFEConvolveMatrixElement.SVG_EDGEMODE_NONE;
 
   // string attribute
 
   eventChecker.watchAttr(convolve, "result");
   eventChecker.expect("add modify remove add");
   convolve.setAttribute("result", "bar");
   convolve.result.baseVal = "foo";
   convolve.removeAttribute("result");
+  convolve.removeAttributeNS(null, "result");
   convolve.result.baseVal = "bar";
 
   eventChecker.expect("");
   convolve.result.baseVal = "bar";
   convolve.setAttribute("result", "bar");
   convolve.result.baseVal = "bar";
 
   // preserveAspectRatio attribute
 
   eventChecker.watchAttr(marker, "preserveAspectRatio");
   eventChecker.expect("add modify remove add");
   marker.setAttribute("preserveAspectRatio", "xMaxYMid slice");
   marker.preserveAspectRatio.baseVal.align =
     SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMAX;
   marker.removeAttribute("preserveAspectRatio");
+  marker.removeAttributeNS(null, "preserveAspectRatio");
   marker.preserveAspectRatio.baseVal.align =
     SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMIN;
 
   eventChecker.expect("");
   marker.preserveAspectRatio.baseVal.meetOrSlice =
     SVGPreserveAspectRatio.SVG_MEETORSLICE_MEET;
   marker.setAttribute("preserveAspectRatio", "xMidYMin meet");
 
   // viewBox attribute
 
   eventChecker.watchAttr(marker, "viewBox");
   eventChecker.expect("add modify remove add");
   marker.setAttribute("viewBox", "1 2 3 4");
   marker.viewBox.baseVal.height = 5;
   marker.removeAttribute("viewBox");
+  marker.removeAttributeNS(null, "viewBox");
   marker.viewBox.baseVal.height = 4;
 
   eventChecker.ignoreEvents();
   marker.setAttribute("viewBox", "1 2 3 4");
   eventChecker.expect("");
   marker.viewBox.baseVal.height = 4;
   marker.viewBox.baseVal.x = 1;
   marker.setAttribute("viewBox", "1 2 3 4");
--- a/content/xbl/test/test_bug389322.xhtml
+++ b/content/xbl/test/test_bug389322.xhtml
@@ -108,17 +108,17 @@ function report(testName, success) {
     let (x=1) (x);
     var success = true;
   }
   catch (e) { success = false; }
   report("HTML script tags with explicit version", success)
 ]]></script>
 <script type="text/javascript"><![CDATA[
   try {
-    let (x=1) (x);
+    eval("let (x=1) (x)");
     var success = false;
   }
   catch (e) { success = true; }
   is(success, true, "JS 1.7 should not work in versionless HTML script tags");
 ]]></script>
 </pre>
 </body>
 </html>
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -1670,16 +1670,22 @@ static const nsContractIDMapData kConstr
 NS_DEFINE_EVENT_CTOR(Event)
 NS_DEFINE_EVENT_CTOR(CustomEvent)
 NS_DEFINE_EVENT_CTOR(PopStateEvent)
 NS_DEFINE_EVENT_CTOR(HashChangeEvent)
 NS_DEFINE_EVENT_CTOR(PageTransitionEvent)
 NS_DEFINE_EVENT_CTOR(CloseEvent)
 NS_DEFINE_EVENT_CTOR(UIEvent)
 NS_DEFINE_EVENT_CTOR(MouseEvent)
+nsresult
+NS_DOMStorageEventCtor(nsISupports** aInstancePtrResult)
+{
+  nsDOMStorageEvent* e = new nsDOMStorageEvent();
+  return CallQueryInterface(e, aInstancePtrResult);
+}
 
 struct nsConstructorFuncMapData
 {
   PRInt32 mDOMClassInfoID;
   nsDOMConstructorFunc mConstructorFunc;
 };
 
 #define NS_DEFINE_CONSTRUCTOR_FUNC_DATA(_class, _func)                        \
@@ -1695,16 +1701,17 @@ static const nsConstructorFuncMapData kC
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(Event)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(CustomEvent)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(PopStateEvent)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(HashChangeEvent)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(PageTransitionEvent)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(CloseEvent)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(UIEvent)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(MouseEvent)
+  NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(StorageEvent)
   NS_DEFINE_CONSTRUCTOR_FUNC_DATA(MozSmsFilter, sms::SmsFilter::NewSmsFilter)
 };
 
 nsIXPConnect *nsDOMClassInfo::sXPConnect = nsnull;
 nsIScriptSecurityManager *nsDOMClassInfo::sSecMan = nsnull;
 bool nsDOMClassInfo::sIsInitialized = false;
 bool nsDOMClassInfo::sDisableDocumentAllSupport = false;
 bool nsDOMClassInfo::sDisableGlobalScopePollutionSupport = false;
@@ -3890,16 +3897,17 @@ nsDOMClassInfo::Init()
 
   DOM_CLASSINFO_MAP_BEGIN(StorageItem, nsIDOMStorageItem)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMStorageItem)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMToString)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(StorageEvent, nsIDOMStorageEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMStorageEvent)
+    DOM_CLASSINFO_EVENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(StorageEventObsolete, nsIDOMStorageEventObsolete)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMStorageEventObsolete)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(DOMParser, nsIDOMParser)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMParser)
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -1928,22 +1928,16 @@ nsGlobalWindow::SetNewDocument(nsIDocume
      happens, setting status isn't a big requirement, so don't. (Doesn't happen
      under normal circumstances, but bug 49615 describes a case.) */
 
   nsContentUtils::AddScriptRunner(
     NS_NewRunnableMethod(this, &nsGlobalWindow::ClearStatus));
 
   bool reUseInnerWindow = aForceReuseInnerWindow || wouldReuseInnerWindow;
 
-  // Remember the old document's principal.
-  nsIPrincipal *oldPrincipal = nsnull;
-  if (oldDoc) {
-    oldPrincipal = oldDoc->NodePrincipal();
-  }
-
   nsresult rv = NS_OK;
 
   // Set mDocument even if this is an outer window to avoid
   // having to *always* reach into the inner window to find the
   // document.
   mDocument = do_QueryInterface(aDocument);
   mDoc = aDocument;
 
@@ -1951,16 +1945,17 @@ nsGlobalWindow::SetNewDocument(nsIDocume
   mLastOpenedURI = aDocument->GetDocumentURI();
 #endif
 
   mContext->WillInitializeContext();
 
   nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal();
 
   nsRefPtr<nsGlobalWindow> newInnerWindow;
+  bool createdInnerWindow = false;
 
   bool thisChrome = IsChromeWindow();
 
   bool isChrome = false;
 
   nsCxPusher cxPusher;
   if (!cxPusher.Push(cx)) {
     return NS_ERROR_FAILURE;
@@ -2029,16 +2024,17 @@ nsGlobalWindow::SetNewDocument(nsIDocume
       rv = mContext->CreateNativeGlobalForInner(sgo, isChrome,
                                                 aDocument->NodePrincipal(),
                                                 &newInnerWindow->mJSObject,
                                                 getter_AddRefs(holder));
       NS_ASSERTION(NS_SUCCEEDED(rv) && newInnerWindow->mJSObject && holder,
                    "Failed to get script global and holder");
 
       mCreatingInnerWindow = false;
+      createdInnerWindow = true;
       Thaw();
 
       NS_ENSURE_SUCCESS(rv, rv);
     }
 
     if (currentInner && currentInner->mJSObject) {
       if (oldDoc == aDocument) {
         // Move the navigator from the old inner window to the new one since
@@ -2109,16 +2105,29 @@ nsGlobalWindow::SetNewDocument(nsIDocume
             cx,
             newInnerWindow->mJSObject
           };
           priv->waiverWrapperMap->Enumerate(ReparentWaiverWrappers, &closure);
         }
       }
     }
 
+    // If we created a new inner window above, we need to do the last little bit
+    // of initialization now that the dust has settled.
+    if (createdInnerWindow) {
+      nsIXPConnect *xpc = nsContentUtils::XPConnect();
+      nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
+      nsresult rv = xpc->GetWrappedNativeOfJSObject(cx, newInnerWindow->mJSObject,
+                                                    getter_AddRefs(wrapper));
+      NS_ENSURE_SUCCESS(rv, rv);
+      NS_ABORT_IF_FALSE(wrapper, "bad wrapper");
+      rv = wrapper->FinishInitForWrappedGlobal();
+      NS_ENSURE_SUCCESS(rv, rv);
+    }
+
     JSAutoEnterCompartment ac;
     if (!ac.enter(cx, mJSObject)) {
       NS_ERROR("unable to enter a compartment");
       return NS_ERROR_FAILURE;
     }
 
     // XXX Not sure if this is needed.
     if (aState) {
@@ -4688,17 +4697,17 @@ nsGlobalWindow::MakeScriptDialogTitle(ns
               nsCAutoString prepath;
               fixedURI->GetPrePath(prepath);
 
               NS_ConvertUTF8toUTF16 ucsPrePath(prepath);
               const PRUnichar *formatStrings[] = { ucsPrePath.get() };
               nsXPIDLString tempString;
               nsContentUtils::FormatLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
                                                     "ScriptDlgHeading",
-                                                    formatStrings, ArrayLength(formatStrings),
+                                                    formatStrings,
                                                     tempString);
               aOutTitle = tempString;
             }
           }
         }
       }
     }
     else { // failed to get subject principal
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -142,31 +142,34 @@ static PRLogModuleInfo* gJSDiagnostics;
 // and doing the actual CC.
 #define NS_CC_DELAY                 6000 // ms
 
 #define NS_CC_SKIPPABLE_DELAY       400 // ms
 
 // Force a CC after this long if there's anything in the purple buffer.
 #define NS_CC_FORCED                (2 * 60 * PR_USEC_PER_SEC) // 2 min
 
+// Don't allow an incremental GC to lock out the CC for too long.
+#define NS_MAX_CC_LOCKEDOUT_TIME    (5 * PR_USEC_PER_SEC) // 5 seconds
+
 // Trigger a CC if the purple buffer exceeds this size when we check it.
 #define NS_CC_PURPLE_LIMIT          250
 
 #define JAVASCRIPT nsIProgrammingLanguage::JAVASCRIPT
 
 // if you add statics here, add them to the list in nsJSRuntime::Startup
 
 static nsITimer *sGCTimer;
 static nsITimer *sShrinkGCBuffersTimer;
 static nsITimer *sCCTimer;
 
 static PRTime sLastCCEndTime;
 
-static bool sGCHasRun;
 static bool sCCLockedOut;
+static PRTime sCCLockedOutTime;
 
 static js::GCSliceCallback sPrevGCSliceCallback;
 
 // The number of currently pending document loads. This count isn't
 // guaranteed to always reflect reality and can't easily as we don't
 // have an easy place to know when a load ends or is interrupted in
 // all cases. This counter also gets reset if we end up GC'ing while
 // we're waiting for a slow page to load. IOW, this count may be 0
@@ -807,17 +810,17 @@ nsJSContext::DOMOperationCallback(JSCont
   if (script) {
     const char *filename = ::JS_GetScriptFilename(cx, script);
     if (filename) {
       nsXPIDLString scriptLocation;
       NS_ConvertUTF8toUTF16 filenameUTF16(filename);
       const PRUnichar *formatParams[] = { filenameUTF16.get() };
       rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
                                                  "KillScriptLocation",
-                                                 formatParams, 1,
+                                                 formatParams,
                                                  scriptLocation);
 
       if (NS_SUCCEEDED(rv) && scriptLocation) {
         msg.AppendLiteral("\n\n");
         msg.Append(scriptLocation);
 
         JSStackFrame *fp, *iterator = nsnull;
         fp = ::JS_FrameIterator(cx, &iterator);
@@ -2309,29 +2312,21 @@ nsJSContext::CreateOuterObject(nsIScript
 
   return SetOuterObject(outer);
 }
 
 nsresult
 nsJSContext::SetOuterObject(JSObject* aOuterObject)
 {
   // Force our context's global object to be the outer.
+  // NB: JS_SetGlobalObject sets mContext->compartment.
   JS_SetGlobalObject(mContext, aOuterObject);
 
-  // NB: JS_SetGlobalObject sets mContext->compartment.
+  // Set up the prototype for the outer object.
   JSObject *inner = JS_GetParent(aOuterObject);
-
-  nsIXPConnect *xpc = nsContentUtils::XPConnect();
-  nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
-  nsresult rv = xpc->GetWrappedNativeOfJSObject(mContext, inner,
-                                                getter_AddRefs(wrapper));
-  NS_ENSURE_SUCCESS(rv, rv);
-  NS_ABORT_IF_FALSE(wrapper, "bad wrapper");
-
-  wrapper->FinishInitForWrappedGlobal();
   JS_SetPrototype(mContext, aOuterObject, JS_GetPrototype(inner));
 
   return NS_OK;
 }
 
 nsresult
 nsJSContext::InitOuterWindow()
 {
@@ -3313,19 +3308,34 @@ TimerFireForgetSkippable(PRUint32 aSuspe
   sTotalForgetSkippableTime += delta;
   sRemovedPurples += (aSuspected - sPreviousSuspectedCount);
   ++sForgetSkippableBeforeCC;
 }
 
 static void
 CCTimerFired(nsITimer *aTimer, void *aClosure)
 {
-  if (sDidShutdown || sCCLockedOut) {
+  if (sDidShutdown) {
     return;
   }
+
+  if (sCCLockedOut) {
+    PRTime now = PR_Now();
+    if (sCCLockedOutTime == 0) {
+      sCCLockedOutTime = now;
+      return;
+    }
+    if (now - sCCLockedOutTime < NS_MAX_CC_LOCKEDOUT_TIME) {
+      return;
+    }
+
+    // Finish the current incremental GC
+    nsJSContext::GarbageCollectNow(js::gcreason::CC_FORCED, nsGCNormal);
+  }
+
   ++sCCTimerFireCount;
 
   // During early timer fires, we only run forgetSkippable. During the first
   // late timer fire, we decide if we are going to have a second and final
   // late timer fire, where we may run the CC.
   const PRUint32 numEarlyTimerFires = NS_CC_DELAY / NS_CC_SKIPPABLE_DELAY - 2;
   bool isLateTimerFire = sCCTimerFireCount > numEarlyTimerFires;
   PRUint32 suspected = nsCycleCollector_suspectedCount();
@@ -3481,16 +3491,18 @@ nsJSContext::KillShrinkGCBuffersTimer()
     NS_RELEASE(sShrinkGCBuffersTimer);
   }
 }
 
 //static
 void
 nsJSContext::KillCCTimer()
 {
+  sCCLockedOutTime = 0;
+
   if (sCCTimer) {
     sCCTimer->Cancel();
 
     NS_RELEASE(sCCTimer);
   }
 }
 
 void
@@ -3519,63 +3531,52 @@ DOMGCSliceCallback(JSRuntime *aRt, js::G
                                         double(delta) / PR_USEC_PER_SEC,
                                         aDesc.logMessage));
     nsCOMPtr<nsIConsoleService> cs = do_GetService(NS_CONSOLESERVICE_CONTRACTID);
     if (cs) {
       cs->LogStringMessage(msg.get());
     }
   }
 
-  // Prevent cycle collections during incremental GC.
+  // Prevent cycle collections and shrinking during incremental GC.
   if (aProgress == js::GC_CYCLE_BEGIN) {
     sCCLockedOut = true;
+    nsJSContext::KillShrinkGCBuffersTimer();
   } else if (aProgress == js::GC_CYCLE_END) {
     sCCLockedOut = false;
   }
 
   // The GC has more work to do, so schedule another GC slice.
   if (aProgress == js::GC_SLICE_END) {
     nsJSContext::KillGCTimer();
-    nsJSContext::KillCCTimer();
-
     nsJSContext::PokeGC(js::gcreason::INTER_SLICE_GC, NS_INTERSLICE_GC_DELAY);
   }
 
   if (aProgress == js::GC_CYCLE_END) {
+    // May need to kill the inter-slice GC timer
+    nsJSContext::KillGCTimer();
+
     sCCollectedWaitingForGC = 0;
     sCleanupSinceLastGC = false;
 
-    if (sGCTimer) {
-      // If we were waiting for a GC to happen, kill the timer.
-      nsJSContext::KillGCTimer();
-
+    if (aDesc.isCompartment) {
       // If this is a compartment GC, restart it. We still want
       // a full GC to happen. Compartment GCs usually happen as a
-      // result of last-ditch or MaybeGC. In both cases its
+      // result of last-ditch or MaybeGC. In both cases it is
       // probably a time of heavy activity and we want to delay
       // the full GC, but we do want it to happen eventually.
-      if (aDesc.isCompartment) {
-        nsJSContext::PokeGC(js::gcreason::POST_COMPARTMENT);
-
-        // We poked the GC, so we can kill any pending CC here.
-        nsJSContext::KillCCTimer();
-      }
-    } else {
-      // If this was a full GC, poke the CC to run soon.
-      if (!aDesc.isCompartment) {
-        sGCHasRun = true;
-        sNeedsFullCC = true;
-        nsJSContext::MaybePokeCC();
-      }
+      nsJSContext::PokeGC(js::gcreason::POST_COMPARTMENT);
     }
 
-    // If we didn't end up scheduling a GC, make sure that we release GC buffers
-    // soon after canceling previous shrinking attempt.
-    nsJSContext::KillShrinkGCBuffersTimer();
-    if (!sGCTimer) {
+    sNeedsFullCC = true;
+    nsJSContext::MaybePokeCC();
+
+    if (!aDesc.isCompartment) {
+      // Avoid shrinking during heavy activity, which is suggested by
+      // compartment GC.
       nsJSContext::PokeShrinkGCBuffers();
     }
   }
 
   if (sPrevGCSliceCallback)
     (*sPrevGCSliceCallback)(aRt, aProgress, aDesc);
 }
 
@@ -3664,18 +3665,18 @@ nsJSRuntime::ParseVersion(const nsString
 }
 
 //static
 void
 nsJSRuntime::Startup()
 {
   // initialize all our statics, so that we can restart XPCOM
   sGCTimer = sCCTimer = nsnull;
-  sGCHasRun = false;
   sCCLockedOut = false;
+  sCCLockedOutTime = 0;
   sLastCCEndTime = 0;
   sPendingLoadCount = 0;
   sLoadingInProgress = false;
   sCCollectedWaitingForGC = 0;
   sPostGCEventsToConsole = false;
   sNeedsFullCC = false;
   gNameSpaceManager = nsnull;
   sRuntimeService = nsnull;
--- a/dom/bluetooth/BluetoothAdapter.cpp
+++ b/dom/bluetooth/BluetoothAdapter.cpp
@@ -4,24 +4,70 @@
  * 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 "nsDOMClassInfo.h"
 #include "nsDOMEvent.h"
 #include "nsThreadUtils.h"
 #include "nsXPCOMCIDInternal.h"
 #include "mozilla/LazyIdleThread.h"
-
+#include <dlfcn.h>
 #include "BluetoothAdapter.h"
 
-#if defined(MOZ_WIDGET_GONK)
-#include <bluedroid/bluetooth.h>
-#endif
+USING_BLUETOOTH_NAMESPACE
+
+static struct BluedroidFunctions {
+  bool initialized;
+  bool tried_initialization;
+
+  BluedroidFunctions() :
+    initialized(false),
+    tried_initialization(false)
+  {
+  }
+  
+  int (* bt_enable)();
+  int (* bt_disable)();
+  int (* bt_is_enabled)();
+} sBluedroidFunctions;
+
+static bool EnsureBluetoothInit() {
+  if (sBluedroidFunctions.tried_initialization)
+  {
+    return sBluedroidFunctions.initialized;
+  }
 
-USING_BLUETOOTH_NAMESPACE
+  sBluedroidFunctions.initialized = false;
+  sBluedroidFunctions.tried_initialization = true;
+  
+  void* handle = dlopen("libbluedroid.so", RTLD_LAZY);
+
+  if(!handle) {
+    NS_ERROR("Failed to open libbluedroid.so, bluetooth cannot run");
+    return false;
+  }
+
+  sBluedroidFunctions.bt_enable = (int (*)())dlsym(handle, "bt_enable");
+  if(sBluedroidFunctions.bt_enable == NULL) {
+    NS_ERROR("Failed to attach bt_enable function");
+    return false;
+  }
+  sBluedroidFunctions.bt_disable = (int (*)())dlsym(handle, "bt_disable");
+  if(sBluedroidFunctions.bt_disable == NULL) {
+    NS_ERROR("Failed to attach bt_disable function");
+    return false;
+  }
+  sBluedroidFunctions.bt_is_enabled = (int (*)())dlsym(handle, "bt_is_enabled");
+  if(sBluedroidFunctions.bt_is_enabled == NULL) {
+    NS_ERROR("Failed to attach bt_is_enabled function");
+    return false;
+  }
+  sBluedroidFunctions.initialized = true;
+  return true;
+}
 
 class ToggleBtResultTask : public nsRunnable
 {
   public:
     ToggleBtResultTask(nsRefPtr<BluetoothAdapter>& adapterPtr, bool result)
       : mResult(result)
     {
       MOZ_ASSERT(!NS_IsMainThread());
@@ -49,53 +95,55 @@ class ToggleBtResultTask : public nsRunn
   private:
     nsRefPtr<BluetoothAdapter> mAdapterPtr;
     bool mResult;
 };
 
 class ToggleBtTask : public nsRunnable
 {
   public:
-    ToggleBtTask(bool onOff, BluetoothAdapter* adapterPtr) 
+    ToggleBtTask(bool onOff, BluetoothAdapter* adapterPtr)
       : mOnOff(onOff),
         mAdapterPtr(adapterPtr) 
     {
       MOZ_ASSERT(NS_IsMainThread());
     }
 
     NS_IMETHOD Run() 
     {
       MOZ_ASSERT(!NS_IsMainThread());
 
+      if(!EnsureBluetoothInit()) {
+        NS_ERROR("Failed to load bluedroid library.\n");
+        return NS_ERROR_FAILURE;
+      }
+
       bool result;
 
       //Toggle BT here
-#if defined(MOZ_WIDGET_GONK)  
+
       if (mOnOff) {
-        result = bt_enable();
+        result = sBluedroidFunctions.bt_enable();
       } else {
-        result = bt_disable();
+        result = sBluedroidFunctions.bt_disable();
       }
-#else 
-      result = true;
-#endif
 
       // Create a result thread and pass it to Main Thread, 
       nsCOMPtr<nsIRunnable> resultRunnable = new ToggleBtResultTask(mAdapterPtr, result);
 
       if (NS_FAILED(NS_DispatchToMainThread(resultRunnable))) {
         NS_WARNING("Failed to dispatch to main thread!");
       }
 
       return NS_OK;
     }
 
   private:
+    bool mOnOff;
     nsRefPtr<BluetoothAdapter> mAdapterPtr;
-    bool mOnOff;
 };
 
 DOMCI_DATA(BluetoothAdapter, BluetoothAdapter)
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(BluetoothAdapter)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(BluetoothAdapter, 
                                                   nsDOMEventTargetHelper)
@@ -118,28 +166,47 @@ NS_IMPL_RELEASE_INHERITED(BluetoothAdapt
 BluetoothAdapter::BluetoothAdapter() 
   : mPower(false)
 {
 }
 
 NS_IMETHODIMP
 BluetoothAdapter::GetPower(bool* aPower)
 {
+#ifdef MOZ_WIDGET_GONK
+  if(!EnsureBluetoothInit()) {
+    NS_ERROR("Failed to load bluedroid library.\n");
+    return NS_ERROR_FAILURE;
+  }
+  *aPower = sBluedroidFunctions.bt_is_enabled();
+#else
   *aPower = mPower;
-
+#endif
   return NS_OK;
 }
 
 NS_IMETHODIMP
 BluetoothAdapter::SetPower(bool aPower)
 {
+
+#ifdef MOZ_WIDGET_GONK
+  // Platform specific check for gonk until object is divided in
+  // different implementations per platform. Linux doesn't require
+  // bluetooth firmware loading, but code should work otherwise.
+  if(!EnsureBluetoothInit()) {
+    NS_ERROR("Failed to load bluedroid library.\n");
+    return NS_ERROR_FAILURE;
+  }
+#endif
   if (mPower != aPower) {
     mPower = aPower;
 
+#ifdef MOZ_WIDGET_GONK
     return ToggleBluetoothAsync();
+#endif
   }
 
   return NS_OK;
 }
 
 nsresult
 BluetoothAdapter::ToggleBluetoothAsync()
 {
--- a/dom/interfaces/storage/nsIDOMStorageEvent.idl
+++ b/dom/interfaces/storage/nsIDOMStorageEvent.idl
@@ -89,8 +89,18 @@ interface nsIDOMStorageEvent : nsIDOMEve
                         in boolean canBubbleArg, 
                         in boolean cancelableArg, 
                         in DOMString keyArg,
                         in DOMString oldValueArg,
                         in DOMString newValueArg,
                         in DOMString urlArg,
                         in nsIDOMStorage storageAreaArg);
 };
+
+[scriptable, uuid(6335e5b5-13ce-4c8a-b452-5c5895f4e90e)]
+interface nsIStorageEventInit : nsIEventInit
+{
+  attribute DOMString key;
+  attribute DOMString oldValue;
+  attribute DOMString newValue;
+  attribute DOMString url;
+  attribute nsIDOMStorage storageArea;
+};
--- a/dom/sms/src/ril/SmsDatabaseService.js
+++ b/dom/sms/src/ril/SmsDatabaseService.js
@@ -482,17 +482,17 @@ SmsDatabaseService.prototype = {
       if (error) {
         errorCb(error);
         return;
       }
 
       // In first place, we retrieve the keys that match the filter.startDate
       // and filter.endDate search criteria.
       let timeKeyRange = null;
-      if (!filter.startDate != null && filter.endDate != null) {
+      if (filter.startDate != null && filter.endDate != null) {
         timeKeyRange = IDBKeyRange.bound(filter.startDate.getTime(),
                                          filter.endDate.getTime());
       } else if (filter.startDate != null) {
         timeKeyRange = IDBKeyRange.lowerBound(filter.startDate.getTime());
       } else if (filter.endDate != null) {
         timeKeyRange = IDBKeyRange.upperBound(filter.endDate.getTime());
       }
       let direction = reverse ? Ci.nsIIDBCursor.PREV : Ci.nsIIDBCursor.NEXT;
--- a/dom/src/storage/nsDOMStorage.cpp
+++ b/dom/src/storage/nsDOMStorage.cpp
@@ -69,16 +69,17 @@ using mozilla::dom::StorageChild;
 #include "nsIOfflineCacheUpdate.h"
 #include "nsIJSContextStack.h"
 #include "nsIPrivateBrowsingService.h"
 #include "nsDOMString.h"
 #include "nsNetCID.h"
 #include "mozilla/Preferences.h"
 #include "nsThreadUtils.h"
 #include "mozilla/Telemetry.h"
+#include "DictionaryHelpers.h"
 
 // calls FlushAndDeleteTemporaryTables(false)
 #define NS_DOMSTORAGE_FLUSH_TIMER_TOPIC "domstorage-flush-timer"
 
 // calls FlushAndDeleteTemporaryTables(true)
 #define NS_DOMSTORAGE_FLUSH_FORCE_TOPIC "domstorage-flush-force"
 
 using namespace mozilla;
@@ -2385,16 +2386,29 @@ NS_IMETHODIMP nsDOMStorageEvent::InitSto
   mOldValue = oldValueArg;
   mNewValue = newValueArg;
   mUrl = urlArg;
   mStorageArea = storageAreaArg;
 
   return NS_OK;
 }
 
+nsresult
+nsDOMStorageEvent::InitFromCtor(const nsAString& aType,
+                                JSContext* aCx, jsval* aVal)
+{
+  mozilla::dom::StorageEventInit d;
+  d.oldValue.SetIsVoid(true);
+  d.newValue.SetIsVoid(true);
+  nsresult rv = d.Init(aCx, aVal);
+  NS_ENSURE_SUCCESS(rv, rv);
+  return InitStorageEvent(aType, d.bubbles, d.cancelable, d.key, d.oldValue,
+                          d.newValue, d.url, d.storageArea);
+}
+
 // Obsolete globalStorage event
 
 DOMCI_DATA(StorageEventObsolete, nsDOMStorageEventObsolete)
 
 // QueryInterface implementation for nsDOMStorageEventObsolete
 NS_INTERFACE_MAP_BEGIN(nsDOMStorageEventObsolete)
   NS_INTERFACE_MAP_ENTRY(nsIDOMStorageEventObsolete)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(StorageEventObsolete)
--- a/dom/src/storage/nsDOMStorage.h
+++ b/dom/src/storage/nsDOMStorage.h
@@ -595,16 +595,18 @@ public:
   nsresult Init();
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsDOMStorageEvent, nsDOMEvent)
 
   NS_DECL_NSIDOMSTORAGEEVENT
   NS_FORWARD_NSIDOMEVENT(nsDOMEvent::)
 
+  virtual nsresult InitFromCtor(const nsAString& aType,
+                                JSContext* aCx, jsval* aVal);
 protected:
   nsString mKey;
   nsString mOldValue;
   nsString mNewValue;
   nsString mUrl;
   nsCOMPtr<nsIDOMStorage> mStorageArea;
 };
 
--- a/dom/system/b2g/ril_worker.js
+++ b/dom/system/b2g/ril_worker.js
@@ -2607,20 +2607,22 @@ let GsmPDUHelper = {
    *
    * @param message
    *        message string to be encoded.
    * @param langTable
    *        locking shift table string.
    * @param langShiftTable
    *        single shift table string.
    *
+   * @return encoded length in septets.
+   *
    * @note that the algorithm used in this function must match exactly with
    * #writeStringAsSeptets.
    */
-  _calculateLangEncodedLength: function _calculateLangEncodedLength(message, langTable, langShiftTable) {
+  _calculateLangEncodedSeptets: function _calculateLangEncodedSeptets(message, langTable, langShiftTable) {
     let length = 0;
     for (let msgIndex = 0; msgIndex < message.length; msgIndex++) {
       let septet = langTable.indexOf(message.charAt(msgIndex));
 
       // According to 3GPP TS 23.038, section 6.1.1 General notes, "The
       // characters marked '1)' are not used but are displayed as a space."
       if (septet == PDU_NL_EXTENDED_ESCAPE) {
         continue;
@@ -2681,56 +2683,52 @@ let GsmPDUHelper = {
     //TODO: support multipart SMS, see bug 712933
     options.dcs = PDU_DCS_MSG_CODING_7BITS_ALPHABET;
     options.langIndex = PDU_NL_IDENTIFIER_DEFAULT;
     options.langShiftIndex = PDU_NL_IDENTIFIER_DEFAULT;
     options.encodedBodyLength = 0;
     options.userDataHeaderLength = 0;
 
     let needUCS2 = true;
-    let minUserDataLength = Number.MAX_VALUE;
+    let minUserDataSeptets = Number.MAX_VALUE;
     for (let i = 0; i < this.enabledGsmTableTuples.length; i++) {
       let [langIndex, langShiftIndex] = this.enabledGsmTableTuples[i];
 
       const langTable = PDU_NL_LOCKING_SHIFT_TABLES[langIndex];
       const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[langShiftIndex];
 
-      let length = this._calculateLangEncodedLength(options.body,
-                                                    langTable,
-                                                    langShiftTable);
-      if (length < 0) {
+      let bodySeptets = this._calculateLangEncodedSeptets(options.body,
+                                                          langTable,
+                                                          langShiftTable);
+      if (bodySeptets < 0) {
         continue;
       }
 
       let headerLen = 0;
       if (langIndex != PDU_NL_IDENTIFIER_DEFAULT) {
         headerLen += 3; // IEI + len + langIndex
       }
       if (langShiftIndex != PDU_NL_IDENTIFIER_DEFAULT) {
         headerLen += 3; // IEI + len + langShiftIndex
       }
 
       // Calculate full user data length, note the extra byte is for header len
-      let userDataLength = length + (headerLen ? headerLen + 1 : 0);
-      if (userDataLength >= minUserDataLength) {
+      let headerSeptets = Math.ceil((headerLen ? headerLen + 1 : 0) * 8 / 7);
+      let userDataSeptets = bodySeptets + headerSeptets;
+      if (userDataSeptets >= minUserDataSeptets) {
         continue;
       }
 
       needUCS2 = false;
-      minUserDataLength = userDataLength;
-
-      options.encodedBodyLength = length;
+      minUserDataSeptets = userDataSeptets;
+
+      options.encodedBodyLength = bodySeptets;
       options.userDataHeaderLength = headerLen;
       options.langIndex = langIndex;
       options.langShiftIndex = langShiftIndex;
-
-      if (userDataLength <= options.body.length) {
-        // Found minimum user data length already
-        return;
-      }
     }
 
     if (needUCS2) {
       options.dcs = PDU_DCS_MSG_CODING_16BITS_ALPHABET;
       options.encodedBodyLength = options.body.length * 2;
       options.userDataHeaderLength = 0;
     }
   },
--- a/dom/system/b2g/tests/test_ril_worker_sms.js
+++ b/dom/system/b2g/tests/test_ril_worker_sms.js
@@ -50,20 +50,20 @@ add_test(function test_nl_single_shift_t
     do_check_eq(table[PDU_NL_PAGE_BREAK], FF);
     do_check_eq(table[PDU_NL_RESERVED_CONTROL], RESCTL);
   }
 
   run_next_test();
 });
 
 /**
- * Verify GsmPDUHelper#_calculateLangEncodedLength() and
+ * Verify GsmPDUHelper#_calculateLangEncodedSeptets() and
  * GsmPDUHelper#writeStringAsSeptets() algorithm match each other.
  */
-add_test(function test_GsmPDUHelper__calculateLangEncodedLength() {
+add_test(function test_GsmPDUHelper__calculateLangEncodedSeptets() {
   let worker = newWorker({
     postRILMessage: function fakePostRILMessage(data) {
       // Do nothing
     },
     postMessage: function fakePostMessage(message) {
       // Do nothing
     }
   });
@@ -73,19 +73,19 @@ add_test(function test_GsmPDUHelper__cal
     helper.octetsWritten = 0;
   };
   helper.writeHexOctet = function () {
     helper.octetsWritten++;
   };
 
   function do_check_calc(str, expectedCalcLen, lst, sst) {
     do_check_eq(expectedCalcLen,
-                helper._calculateLangEncodedLength(str,
-                                                   PDU_NL_LOCKING_SHIFT_TABLES[lst],
-                                                   PDU_NL_SINGLE_SHIFT_TABLES[sst]));
+                helper._calculateLangEncodedSeptets(str,
+                                                    PDU_NL_LOCKING_SHIFT_TABLES[lst],
+                                                    PDU_NL_SINGLE_SHIFT_TABLES[sst]));
 
     helper.resetOctetWritten();
     helper.writeStringAsSeptets(str, 0, lst, sst);
     do_check_eq(Math.ceil(expectedCalcLen * 7 / 8), helper.octetsWritten);
   }
 
   // Test calculation encoded message length using both locking/single shift tables.
   for (let lst = 0; lst < PDU_NL_LOCKING_SHIFT_TABLES.length; lst++) {
@@ -188,16 +188,31 @@ add_test(function test_GsmPDUHelper_calc
   // - 'A' is defined in single shift table
   test_calc("A", [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 2, 6, 2, 4], [[2, 0], [2, 4]]);
   test_calc("A", [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 2, 6, 2, 4], [[2, 4], [2, 0]]);
   // - 'A' is defined in locking shift table of one tuple and in single shift
   //   table of another.
   test_calc("A", [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 1, 3, 1, 0], [[1, 0], [2, 4]]);
   test_calc("A", [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 1, 3, 1, 0], [[2, 4], [1, 0]]);
 
+  // Test Bug 733981
+  // - Case 1, headerLen is in octets, not septets. "\\" is defined in default
+  //   single shift table and Portuguese locking shift table. The original code
+  //   will add headerLen 7(octets), which should be 8(septets), to calculated
+  //   cost and gets 14, which should be 15 in total for the first run. As for
+  //   the second run, it will be undoubtedly 14 in total. With correct fix,
+  //   the best choice should be the second one.
+  test_calc("\\\\\\\\\\\\\\",
+            [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 14, 0, 0, 0], [[3, 1], [0, 0]]);
+  // - Case 2, possible early return non-best choice. The original code will
+  //   get total cost 6 in the first run and returns immediately. With correct
+  //   fix, the best choice should be the second one.
+  test_calc(ESCAPE + ESCAPE + ESCAPE + ESCAPE + ESCAPE + "\\",
+            [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 2, 0, 0, 0], [[3, 0], [0, 0]]);
+
   run_next_test();
 });
 
 /**
  * Verify GsmPDUHelper#writeStringAsSeptets() padding bits handling.
  */
 add_test(function test_GsmPDUHelper_writeStringAsSeptets() {
   let worker = newWorker({
@@ -385,18 +400,18 @@ function test_receiving_7bit_alphabets(l
 
   let langTable = PDU_NL_LOCKING_SHIFT_TABLES[lst];
   let langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[sst];
 
   let text = removeSpecialChar(langTable + langShiftTable, ESCAPE + RESCTL);
   for (let i = 0; i < text.length;) {
     let len = Math.min(70, text.length - i);
     let expected = text.substring(i, i + len);
-    let septets = helper._calculateLangEncodedLength(expected, langTable,
-                                                     langShiftTable);
+    let septets = helper._calculateLangEncodedSeptets(expected, langTable,
+                                                      langShiftTable);
     let rawBytes = get7bitRawBytes(expected);
     let pdu = compose7bitPdu(lst, sst, rawBytes, septets);
     add_test_receiving_sms(expected, pdu);
 
     i += len;
   }
 }
 
--- a/dom/tests/mochitest/general/file_frameElementWrapping.html
+++ b/dom/tests/mochitest/general/file_frameElementWrapping.html
@@ -1,26 +1,32 @@
 <html>
     <script>
-        function check(elt, expectProxy, message) {
-            netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
-            var utils = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
-                              .getInterface(Components.interfaces.nsIDOMWindowUtils);
-            var result = ((utils.getClassName(elt) === 'Proxy') === expectProxy)
-                         ? "PASS"
-                         : "FAIL";
+        function check(elt, expectAccess, prop) {
+            var access = false;
+            try {
+                elt[prop];
+                access = true;
+            }
+            catch (e) {}
+            return access === expectAccess;
+        }
 
+        function sendMessage(success, sameOrigin, prop) {
+            var result = success ? 'PASS' : 'FAIL';
+            var message;
+            if (sameOrigin)
+                message = 'Can access |' + prop + '| if same origin';
+            else
+                message = 'Cannot access |' + prop + '| if not same origin';
             parent.postMessage(result + ',' + message, '*');
         }
 
-        try {
-            // true if same origin, throws otherwise
-            var sameOrigin = parent.location.href !== '';
-        } catch (e) {
-            sameOrigin = false;
+        var sameOrigin = location.host !== 'example.org';
+        var pass = check(frameElement, sameOrigin, 'src');
+        if (!pass) {
+            sendMessage(false, sameOrigin, 'src');
+        } else {
+            pass = check(parent.location, sameOrigin, 'href');
+            sendMessage(pass, sameOrigin, 'href');
         }
-
-        check(frameElement, !sameOrigin,
-              sameOrigin
-              ? 'no wrapper needed if same origin'
-              : 'wrapper needed if not same origin');
     </script>
 </html>
--- a/dom/tests/mochitest/general/test_frameElementWrapping.html
+++ b/dom/tests/mochitest/general/test_frameElementWrapping.html
@@ -1,24 +1,32 @@
 <!DOCTYPE HTML>
 <html>
 <head>
-  <title>Test for location object behaviors</title>
+  <title>Test for same-origin and cross-origin wrapping of frameElement</title>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <p id="display"></p>
 <div id="content" style="display: none">
  
 </div>
 <iframe id="ifr" src="file_frameElementWrapping.html"></iframe>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
+//
+// This test has sort of morphed over time to become less and less useful.
+// In the past, we had special security policy for frameElement, but that's
+// more or less gone away with compartment/proxy wrapping. So we just go
+// through the motions to make sure that, indeed, frameElement is subject
+// to the same-origin policy.
+//
+
 SimpleTest.waitForExplicitFinish();
 
 var count = 0;
 
 function runTest(result, message) {
     ok(result === 'PASS', message);
 
     if (++count === 2)
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -2920,17 +2920,17 @@ WorkerPrivate::Dispatch(WorkerRunnable* 
       }
     }
 
     if (!aQueue->Push(event)) {
       return false;
     }
 
     if (aQueue == &mControlQueue && mJSContext) {
-      JS_TriggerOperationCallback(mJSContext);
+      JS_TriggerOperationCallback(JS_GetRuntime(mJSContext));
     }
 
     mCondVar.Notify();
   }
 
   event.forget();
   return true;
 }
--- a/editor/libeditor/html/nsEditProperty.cpp
+++ b/editor/libeditor/html/nsEditProperty.cpp
@@ -80,10 +80,10 @@ nsEditProperty::RegisterAtoms()
 {
   // inline tags
   static const nsStaticAtom property_atoms[] = {
 #define EDITOR_ATOM(name_, value_) NS_STATIC_ATOM(name_##_buffer, &name_),
 #include "nsEditPropertyAtomList.h"
 #undef EDITOR_ATOM
   };
   
-  NS_RegisterStaticAtoms(property_atoms, ArrayLength(property_atoms));
+  NS_RegisterStaticAtoms(property_atoms);
 }
--- a/editor/txtsvc/src/nsTextServicesDocument.cpp
+++ b/editor/txtsvc/src/nsTextServicesDocument.cpp
@@ -129,17 +129,17 @@ void
 nsTextServicesDocument::RegisterAtoms()
 {
   static const nsStaticAtom ts_atoms[] = {
 #define TS_ATOM(name_, value_) NS_STATIC_ATOM(name_##_buffer, &name_),
 #include "nsTSAtomList.h"
 #undef TS_ATOM
   };
 
-  NS_RegisterStaticAtoms(ts_atoms, ArrayLength(ts_atoms));
+  NS_RegisterStaticAtoms(ts_atoms);
 }
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsTextServicesDocument)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsTextServicesDocument)
 
 NS_INTERFACE_MAP_BEGIN(nsTextServicesDocument)
   NS_INTERFACE_MAP_ENTRY(nsITextServicesDocument)
   NS_INTERFACE_MAP_ENTRY(nsIEditActionListener)
--- a/embedding/components/windowwatcher/src/nsWindowWatcher.cpp
+++ b/embedding/components/windowwatcher/src/nsWindowWatcher.cpp
@@ -1535,18 +1535,27 @@ PRUint32 nsWindowWatcher::CalculateChrom
   chromeFlags |= WinHasOption(aFeatures, "extrachrome", 0, nsnull) ?
     nsIWebBrowserChrome::CHROME_EXTRA : 0;
   chromeFlags |= WinHasOption(aFeatures, "centerscreen", 0, nsnull) ?
     nsIWebBrowserChrome::CHROME_CENTER_SCREEN : 0;
   chromeFlags |= WinHasOption(aFeatures, "dependent", 0, nsnull) ?
     nsIWebBrowserChrome::CHROME_DEPENDENT : 0;
   chromeFlags |= WinHasOption(aFeatures, "modal", 0, nsnull) ?
     (nsIWebBrowserChrome::CHROME_MODAL | nsIWebBrowserChrome::CHROME_DEPENDENT) : 0;
-  chromeFlags |= WinHasOption(aFeatures, "dialog", 0, nsnull) ?
-    nsIWebBrowserChrome::CHROME_OPENAS_DIALOG : 0;
+
+  /* On mobile we want to ignore the dialog window feature, since the mobile UI
+     does not provide any affordance for dialog windows. This does not interfere
+     with dialog windows created through openDialog. */
+  bool disableDialogFeature = false;
+  nsCOMPtr<nsIPrefBranch> branch = do_QueryInterface(prefs);
+  branch->GetBoolPref("dom.disable_window_open_dialog_feature", &disableDialogFeature);
+  if (!disableDialogFeature) {
+    chromeFlags |= WinHasOption(aFeatures, "dialog", 0, nsnull) ?
+      nsIWebBrowserChrome::CHROME_OPENAS_DIALOG : 0;
+  }
 
   /* and dialogs need to have the last word. assume dialogs are dialogs,
      and opened as chrome, unless explicitly told otherwise. */
   if (aDialog) {
     if (!PL_strcasestr(aFeatures, "dialog"))
       chromeFlags |= nsIWebBrowserChrome::CHROME_OPENAS_DIALOG;
     if (!PL_strcasestr(aFeatures, "chrome"))
       chromeFlags |= nsIWebBrowserChrome::CHROME_OPENAS_CHROME;
--- a/gfx/gl/GLContextProviderEGL.cpp
+++ b/gfx/gl/GLContextProviderEGL.cpp
@@ -37,16 +37,19 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "mozilla/Preferences.h"
 #include "mozilla/Util.h"
 
+#include "nsIScreen.h"
+#include "nsIScreenManager.h"
+
 #if defined(XP_UNIX)
 
 #ifdef MOZ_WIDGET_GTK2
 #include <gdk/gdkx.h>
 // we're using default display for now
 #define GET_NATIVE_WINDOW(aWidget) (EGLNativeWindowType)GDK_WINDOW_XID((GdkWindow *) aWidget->GetNativeData(NS_NATIVE_WINDOW))
 #elif defined(MOZ_WIDGET_QT)
 #include <QtOpenGL/QGLContext>
@@ -2185,72 +2188,59 @@ static const EGLint kEGLConfigAttribsRGB
     LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT,
     LOCAL_EGL_RED_SIZE,        8,
     LOCAL_EGL_GREEN_SIZE,      8,
     LOCAL_EGL_BLUE_SIZE,       8,
     LOCAL_EGL_ALPHA_SIZE,      8,
     LOCAL_EGL_NONE
 };
 
-// This struct is used only by CreateConfig below, but ISO C++98 forbids
-// instantiating a template dependent on a locally-defined type.  Boo-urns!
-struct EGLAttribs {
-    gfxASurface::gfxImageFormat mFormat;
-    const EGLint* mAttribs;
-};
-
 // Return true if a suitable EGLConfig was found and pass it out
 // through aConfig.  Return false otherwise.
 //
 // NB: It's entirely legal for the returned EGLConfig to be valid yet
 // have the value null.
 static bool
 CreateConfig(EGLConfig* aConfig)
 {
-    EGLAttribs attribsToTry[] = {
-#ifdef MOZ_GFX_OPTIMIZE_MOBILE
-        // Prefer r5g6b5 for potential savings in memory bandwidth.
-        // This needs to be reevaluated for newer devices.
-        { gfxASurface::ImageFormatRGB16_565, kEGLConfigAttribsRGB16 },
-#endif
-        { gfxASurface::ImageFormatARGB32, kEGLConfigAttribsRGBA32 },
-    };
+    nsCOMPtr<nsIScreenManager> screenMgr = do_GetService("@mozilla.org/gfx/screenmanager;1");
+    nsCOMPtr<nsIScreen> screen;
+    screenMgr->GetPrimaryScreen(getter_AddRefs(screen));
+    PRInt32 depth = 24;
+    screen->GetColorDepth(&depth);
 
     EGLConfig configs[64];
-    for (unsigned i = 0; i < ArrayLength(attribsToTry); ++i) {
-        const EGLAttribs& attribs = attribsToTry[i];
-        EGLint ncfg = ArrayLength(configs);
-
-        if (!sEGLLibrary.fChooseConfig(EGL_DISPLAY(), attribs.mAttribs,
-                                       configs, ncfg, &ncfg) ||
-            ncfg < 1)
+    gfxASurface::gfxImageFormat format;
+    const EGLint* attribs = depth == 16 ? kEGLConfigAttribsRGB16 :
+                                          kEGLConfigAttribsRGBA32;
+    EGLint ncfg = ArrayLength(configs);
+
+    if (!sEGLLibrary.fChooseConfig(EGL_DISPLAY(), attribs,
+                                   configs, ncfg, &ncfg) ||
+        ncfg < 1) {
+        return false;
+    }
+
+    for (int j = 0; j < ncfg; ++j) {
+        EGLConfig config = configs[j];
+        EGLint r, g, b, a;
+
+        if (sEGLLibrary.fGetConfigAttrib(EGL_DISPLAY(), config,
+                                         LOCAL_EGL_RED_SIZE, &r) &&
+            sEGLLibrary.fGetConfigAttrib(EGL_DISPLAY(), config,
+                                         LOCAL_EGL_GREEN_SIZE, &g) &&
+            sEGLLibrary.fGetConfigAttrib(EGL_DISPLAY(), config,
+                                         LOCAL_EGL_BLUE_SIZE, &b) &&
+            sEGLLibrary.fGetConfigAttrib(EGL_DISPLAY(), config,
+                                         LOCAL_EGL_ALPHA_SIZE, &a) &&
+            ((depth == 16 && r == 5 && g == 6 && b == 5) ||
+             (depth == 24 && r == 8 && g == 8 && b == 8 && a == 8)))
         {
-            continue;
-        }
-
-        for (int j = 0; j < ncfg; ++j) {
-            EGLConfig config = configs[j];
-            EGLint r, g, b, a;
-
-            if (sEGLLibrary.fGetConfigAttrib(EGL_DISPLAY(), config,
-                                             LOCAL_EGL_RED_SIZE, &r) &&
-                sEGLLibrary.fGetConfigAttrib(EGL_DISPLAY(), config,
-                                             LOCAL_EGL_GREEN_SIZE, &g) &&
-                sEGLLibrary.fGetConfigAttrib(EGL_DISPLAY(), config,
-                                             LOCAL_EGL_BLUE_SIZE, &b) &&
-                sEGLLibrary.fGetConfigAttrib(EGL_DISPLAY(), config,
-                                             LOCAL_EGL_ALPHA_SIZE, &a) &&
-                ((gfxASurface::ImageFormatRGB16_565 == attribs.mFormat &&
-                  r == 5 && g == 6 && b == 5) ||
-                 (gfxASurface::ImageFormatARGB32 == attribs.mFormat &&
-                  r == 8 && g == 8 && b == 8 && a == 8)))
-            {
-                *aConfig = config;
-                return true;
-            }
+            *aConfig = config;
+            return true;
         }
     }
     return false;
 }
 
 static EGLSurface
 CreateSurfaceForWindow(nsIWidget *aWidget, EGLConfig config)
 {
--- a/gfx/thebes/gfxAtoms.cpp
+++ b/gfx/thebes/gfxAtoms.cpp
@@ -53,10 +53,10 @@ using namespace mozilla;
 static const nsStaticAtom atoms[] = {
 #define GFX_ATOM(name_, value_) NS_STATIC_ATOM(name_##_buffer, &gfxAtoms::name_),
 #include "gfxAtomList.h"
 #undef GFX_ATOM
 };
 
 void gfxAtoms::RegisterAtoms()
 {
-    NS_RegisterStaticAtoms(atoms, ArrayLength(atoms));
+    NS_RegisterStaticAtoms(atoms);
 }
--- a/gfx/thebes/gfxDWriteFontList.cpp
+++ b/gfx/thebes/gfxDWriteFontList.cpp
@@ -63,16 +63,20 @@ using namespace mozilla;
                                    PR_LOG_DEBUG)
 
 #define LOG_FONTINIT(args) PR_LOG(gfxPlatform::GetLog(eGfxLog_fontinit), \
                                PR_LOG_DEBUG, args)
 #define LOG_FONTINIT_ENABLED() PR_LOG_TEST( \
                                    gfxPlatform::GetLog(eGfxLog_fontinit), \
                                    PR_LOG_DEBUG)
 
+#define LOG_CMAPDATA_ENABLED() PR_LOG_TEST( \
+                                   gfxPlatform::GetLog(eGfxLog_cmapdata), \
+                                   PR_LOG_DEBUG)
+
 // font info loader constants
 
 // avoid doing this during startup even on slow machines but try to start
 // it soon enough so that system fallback doesn't happen first
 static const PRUint32 kDelayBeforeLoadingFonts = 120 * 1000; // 2 minutes after init
 static const PRUint32 kIntervalBetweenLoadingFonts = 2000;   // every 2 seconds until complete
 
 static __inline void
@@ -366,16 +370,26 @@ gfxDWriteFontEntry::ReadCMAP()
         if (GetFontTable(kCmapTag, buffer) != NS_OK)
             return NS_ERROR_FAILURE;
         PRUint8 *cmap = buffer.Elements();
 
         bool          unicodeFont = false, symbolFont = false;
         rv = gfxFontUtils::ReadCMAP(cmap, buffer.Length(),
                                     mCharacterMap, mUVSOffset,
                                     unicodeFont, symbolFont);
+#ifdef PR_LOGGING
+        LOG_FONTLIST(("(fontlist-cmap) name: %s, size: %d\n",
+                      NS_ConvertUTF16toUTF8(mName).get(), mCharacterMap.GetSize()));
+        if (LOG_CMAPDATA_ENABLED()) {
+            char prefix[256];
+            sprintf(prefix, "(cmapdata) name: %.220s",
+                    NS_ConvertUTF16toUTF8(mName).get());
+            mCharacterMap.Dump(prefix, eGfxLog_cmapdata);
+        }
+#endif
         mHasCmapTable = NS_SUCCEEDED(rv);
         return rv;
     }
 
     // loading using dwrite, don't use GetFontTable to avoid copy
     nsRefPtr<IDWriteFontFace> fontFace;
     rv = CreateFontFace(getter_AddRefs(fontFace));
 
@@ -406,16 +420,22 @@ gfxDWriteFontEntry::ReadCMAP()
                                     isUnicode,
                                     isSymbol);
     }
     fontFace->ReleaseFontTable(tableContext);
 
 #ifdef PR_LOGGING
     LOG_FONTLIST(("(fontlist-cmap) name: %s, size: %d\n",
                   NS_ConvertUTF16toUTF8(mName).get(), mCharacterMap.GetSize()));
+    if (LOG_CMAPDATA_ENABLED()) {
+        char prefix[256];
+        sprintf(prefix, "(cmapdata) name: %.220s",
+                NS_ConvertUTF16toUTF8(mName).get());
+        mCharacterMap.Dump(prefix, eGfxLog_cmapdata);
+    }
 #endif
 
     mHasCmapTable = NS_SUCCEEDED(rv);
     return rv;
 }
 
 gfxFont *
 gfxDWriteFontEntry::CreateFontInstance(const gfxFontStyle* aFontStyle,
@@ -1169,8 +1189,187 @@ gfxDWriteFontList::ResolveFontName(const
     }
 
     if (mNonExistingFonts.Contains(keyName)) {
         return false;
     }
 
     return gfxPlatformFontList::ResolveFontName(aFontName, aResolvedFontName);
 }
+
+static nsresult GetFamilyName(IDWriteFont *aFont, nsString& aFamilyName)
+{
+    HRESULT hr;
+    nsRefPtr<IDWriteFontFamily> family;
+
+    // clean out previous value
+    aFamilyName.Truncate();
+
+    hr = aFont->GetFontFamily(getter_AddRefs(family));
+    if (FAILED(hr)) {
+        return hr;
+    }
+
+    nsRefPtr<IDWriteLocalizedStrings> familyNames;
+
+    hr = family->GetFamilyNames(getter_AddRefs(familyNames));
+    if (FAILED(hr)) {
+        return hr;
+    }
+
+    UINT32 index = 0;
+    BOOL exists = false;
+
+    hr = familyNames->FindLocaleName(L"en-us", &index, &exists);
+    if (FAILED(hr)) {
+        return hr;
+    }
+
+    // If the specified locale doesn't exist, select the first on the list.
+    if (!exists) {
+        index = 0;
+    }
+
+    nsAutoTArray<WCHAR, 32> name;
+    UINT32 length;
+
+    hr = familyNames->GetStringLength(index, &length);
+    if (FAILED(hr)) {
+        return hr;
+    }
+
+    if (!name.SetLength(length + 1)) {
+        return NS_ERROR_FAILURE;
+    }
+    hr = familyNames->GetString(index, name.Elements(), length + 1);
+    if (FAILED(hr)) {
+        return hr;
+    }
+
+    aFamilyName.Assign(name.Elements());
+    return NS_OK;
+}
+
+// bug 705594 - the method below doesn't actually do any "drawing", it's only
+// used to invoke the DirectWrite layout engine to determine the fallback font
+// for a given character.
+
+IFACEMETHODIMP FontFallbackRenderer::DrawGlyphRun(
+    __maybenull void* clientDrawingContext,
+    FLOAT baselineOriginX,
+    FLOAT baselineOriginY,
+    DWRITE_MEASURING_MODE measuringMode,
+    __in DWRITE_GLYPH_RUN const* glyphRun,
+    __in DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
+    __maybenull IUnknown* clientDrawingEffect
+    )
+{
+    if (!mSystemFonts) {
+        return E_FAIL;
+    }
+
+    HRESULT hr = S_OK;
+
+    nsRefPtr<IDWriteFont> font;
+    hr = mSystemFonts->GetFontFromFontFace(glyphRun->fontFace,
+                                           getter_AddRefs(font));
+    if (FAILED(hr)) {
+        return hr;
+    }
+
+    // copy the family name
+    hr = GetFamilyName(font, mFamilyName);
+    if (FAILED(hr)) {
+        return hr;
+    }
+
+    // Arial is used as the default fallback font
+    // so if it matches ==> no font found
+    if (mFamilyName.EqualsLiteral("Arial")) {
+        mFamilyName.Truncate();
+        return E_FAIL;
+    }
+    return hr;
+}
+
+gfxFontEntry*
+gfxDWriteFontList::GlobalFontFallback(const PRUint32 aCh,
+                                      PRInt32 aRunScript,
+                                      const gfxFontStyle* aMatchStyle,
+                                      PRUint32& aCmapCount)
+{
+    bool useCmaps = gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback();
+
+    if (useCmaps) {
+        return gfxPlatformFontList::GlobalFontFallback(aCh,
+                                                       aRunScript,
+                                                       aMatchStyle,
+                                                       aCmapCount);
+    }
+
+    HRESULT hr;
+
+    nsRefPtr<IDWriteFactory> dwFactory =
+        gfxWindowsPlatform::GetPlatform()->GetDWriteFactory();
+    if (!dwFactory) {
+        return nsnull;
+    }
+
+    // initialize fallback renderer
+    if (!mFallbackRenderer) {
+        mFallbackRenderer = new FontFallbackRenderer(dwFactory);
+    }
+
+    // initialize text format
+    if (!mFallbackFormat) {
+        hr = dwFactory->CreateTextFormat(L"Arial", NULL,
+                                         DWRITE_FONT_WEIGHT_REGULAR,
+                                         DWRITE_FONT_STYLE_NORMAL,
+                                         DWRITE_FONT_STRETCH_NORMAL,
+                                         72.0f, L"en-us",
+                                         getter_AddRefs(mFallbackFormat));
+        if (FAILED(hr)) {
+            return nsnull;
+        }
+    }
+
+    // set up string with fallback character
+    wchar_t str[16];
+    PRUint32 strLen;
+
+    if (IS_IN_BMP(aCh)) {
+        str[0] = static_cast<wchar_t> (aCh);
+        str[1] = 0;
+        strLen = 1;
+    } else {
+        str[0] = static_cast<wchar_t> (H_SURROGATE(aCh));
+        str[1] = static_cast<wchar_t> (L_SURROGATE(aCh));
+        str[2] = 0;
+        strLen = 2;
+    }
+
+    // set up layout
+    nsRefPtr<IDWriteTextLayout> fallbackLayout;
+
+    hr = dwFactory->CreateTextLayout(str, strLen, mFallbackFormat,
+                                     200.0f, 200.0f,
+                                     getter_AddRefs(fallbackLayout));
+    if (FAILED(hr)) {
+        return nsnull;
+    }
+
+    // call the draw method to invoke the DirectWrite layout functions
+    // which determine the fallback font
+    hr = fallbackLayout->Draw(NULL, mFallbackRenderer, 50.0f, 50.0f);
+    if (FAILED(hr)) {
+        return nsnull;
+    }
+
+    gfxFontEntry *fontEntry = nsnull;
+    bool needsBold;  // ignored in the system fallback case
+    fontEntry = FindFontForFamily(mFallbackRenderer->FallbackFamilyName(),
+                                  aMatchStyle, needsBold);
+    if (fontEntry && !fontEntry->TestCharacterMap(aCh)) {
+        fontEntry = nsnull;
+        Telemetry::Accumulate(Telemetry::BAD_FALLBACK_FONT, true);
+    }
+    return fontEntry;
+}
--- a/gfx/thebes/gfxDWriteFontList.h
+++ b/gfx/thebes/gfxDWriteFontList.h
@@ -199,16 +199,155 @@ protected:
     nsRefPtr<IDWriteFont> mFont;
     nsRefPtr<IDWriteFontFile> mFontFile;
     DWRITE_FONT_FACE_TYPE mFaceType;
 
     PRInt8 mIsCJK;
     bool mForceGDIClassic;
 };
 
+// custom text renderer used to determine the fallback font for a given char
+class FontFallbackRenderer : public IDWriteTextRenderer
+{
+public:
+    FontFallbackRenderer(IDWriteFactory *aFactory)
+        : mRefCount(0)
+    {
+        HRESULT hr = S_OK;
+
+        hr = aFactory->GetSystemFontCollection(getter_AddRefs(mSystemFonts));
+        NS_ASSERTION(SUCCEEDED(hr), "GetSystemFontCollection failed!");
+    }
+
+    ~FontFallbackRenderer()
+    {}
+
+    // IDWriteTextRenderer methods
+    IFACEMETHOD(DrawGlyphRun)(
+        __maybenull void* clientDrawingContext,
+        FLOAT baselineOriginX,
+        FLOAT baselineOriginY,
+        DWRITE_MEASURING_MODE measuringMode,
+        __in DWRITE_GLYPH_RUN const* glyphRun,
+        __in DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
+        __maybenull IUnknown* clientDrawingEffect
+        );
+
+    IFACEMETHOD(DrawUnderline)(
+        __maybenull void* clientDrawingContext,
+        FLOAT baselineOriginX,
+        FLOAT baselineOriginY,
+        __in DWRITE_UNDERLINE const* underline,
+        __maybenull IUnknown* clientDrawingEffect
+        )
+    {
+        return E_NOTIMPL;
+    }
+
+
+    IFACEMETHOD(DrawStrikethrough)(
+        __maybenull void* clientDrawingContext,
+        FLOAT baselineOriginX,
+        FLOAT baselineOriginY,
+        __in DWRITE_STRIKETHROUGH const* strikethrough,
+        __maybenull IUnknown* clientDrawingEffect
+        )
+    {
+        return E_NOTIMPL;
+    }
+
+
+    IFACEMETHOD(DrawInlineObject)(
+        __maybenull void* clientDrawingContext,
+        FLOAT originX,
+        FLOAT originY,
+        IDWriteInlineObject* inlineObject,
+        BOOL isSideways,
+        BOOL isRightToLeft,
+        __maybenull IUnknown* clientDrawingEffect
+        )
+    {
+        return E_NOTIMPL;
+    }
+
+    // IDWritePixelSnapping methods
+
+    IFACEMETHOD(IsPixelSnappingDisabled)(
+        __maybenull void* clientDrawingContext,
+        __out BOOL* isDisabled
+        )
+    {
+        *isDisabled = FALSE;
+        return S_OK;
+    }
+
+    IFACEMETHOD(GetCurrentTransform)(
+        __maybenull void* clientDrawingContext,
+        __out DWRITE_MATRIX* transform
+        )
+    {
+        const DWRITE_MATRIX ident = {1.0, 0.0, 0.0, 1.0, 0.0, 0.0};
+        *transform = ident;
+        return S_OK;
+    }
+
+    IFACEMETHOD(GetPixelsPerDip)(
+        __maybenull void* clientDrawingContext,
+        __out FLOAT* pixelsPerDip
+        )
+    {
+        *pixelsPerDip = 1.0f;
+        return S_OK;
+    }
+
+    // IUnknown methods
+
+    IFACEMETHOD_(unsigned long, AddRef) ()
+    {
+        return InterlockedIncrement(&mRefCount);
+    }
+
+    IFACEMETHOD_(unsigned long,  Release) ()
+    {
+        unsigned long newCount = InterlockedDecrement(&mRefCount);
+        if (newCount == 0)
+        {
+            delete this;
+            return 0;
+        }
+
+        return newCount;
+    }
+
+    IFACEMETHOD(QueryInterface) (IID const& riid, void** ppvObject)
+    {
+        if (__uuidof(IDWriteTextRenderer) == riid) {
+            *ppvObject = this;
+        } else if (__uuidof(IDWritePixelSnapping) == riid) {
+            *ppvObject = this;
+        } else if (__uuidof(IUnknown) == riid) {
+            *ppvObject = this;
+        } else {
+            *ppvObject = NULL;
+            return E_FAIL;
+        }
+
+        this->AddRef();
+        return S_OK;
+    }
+
+    const nsString& FallbackFamilyName() { return mFamilyName; }
+
+protected:
+    unsigned long mRefCount;
+    nsRefPtr<IDWriteFontCollection> mSystemFonts;
+    nsString mFamilyName;
+};
+
+
 
 class gfxDWriteFontList : public gfxPlatformFontList {
 public:
     gfxDWriteFontList();
 
     static gfxDWriteFontList* PlatformFontList() {
         return static_cast<gfxDWriteFontList*>(sPlatformFontList);
     }
@@ -243,16 +382,24 @@ public:
 
 private:
     friend class gfxDWriteFontFamily;
 
     nsresult GetFontSubstitutes();
 
     void GetDirectWriteSubstitutes();
 
+    // search fonts system-wide for a given character, null otherwise
+    virtual gfxFontEntry* GlobalFontFallback(const PRUint32 aCh,
+                                             PRInt32 aRunScript,
+                                             const gfxFontStyle* aMatchStyle,
+                                             PRUint32& aCmapCount);
+
+    virtual bool UsesSystemFallback() { return true; }
+
     /**
      * Fonts listed in the registry as substitutes but for which no actual
      * font family is found.
      */
     nsTArray<nsString> mNonExistingFonts;
 
     typedef nsDataHashtable<nsStringHashKey, nsRefPtr<gfxFontFamily> > FontTable;
 
@@ -265,12 +412,15 @@ private:
     bool mInitialized;
     virtual nsresult DelayedInitFontList();
 
     gfxFloat mForceGDIClassicMaxFontSize;
 
     // whether to use GDI font table access routines
     bool mGDIFontTableAccess;
     nsRefPtr<IDWriteGdiInterop> mGDIInterop;
+
+    nsRefPtr<FontFallbackRenderer> mFallbackRenderer;
+    nsRefPtr<IDWriteTextFormat>    mFallbackFormat;
 };
 
 
 #endif /* GFX_DWRITEFONTLIST_H */
--- a/gfx/thebes/gfxFT2Fonts.cpp
+++ b/gfx/thebes/gfxFT2Fonts.cpp
@@ -392,21 +392,22 @@ gfxFT2FontGroup::WhichPrefFontSupportsCh
         nsRefPtr<gfxFont> f = static_cast<gfxFont*>(selectedFont.get());
         return f.forget();
     }
 
     return nsnull;
 }
 
 already_AddRefed<gfxFont>
-gfxFT2FontGroup::WhichSystemFontSupportsChar(PRUint32 aCh)
+gfxFT2FontGroup::WhichSystemFontSupportsChar(PRUint32 aCh, PRInt32 aRunScript)
 {
 #if defined(XP_WIN) || defined(ANDROID)
     FontEntry *fe = static_cast<FontEntry*>
-        (gfxPlatformFontList::PlatformFontList()->FindFontForChar(aCh, GetFontAt(0)));
+        (gfxPlatformFontList::PlatformFontList()->
+            SystemFindFontForChar(aCh, aRunScript, &mStyle));
     if (fe) {
         nsRefPtr<gfxFT2Font> f = gfxFT2Font::GetOrMakeFont(fe, &mStyle);
         nsRefPtr<gfxFont> font = f.get();
         return font.forget();
     }
 #else
     nsRefPtr<gfxFont> selectedFont;
     nsRefPtr<gfxFont> refFont = GetFontAt(0);
--- a/gfx/thebes/gfxFT2Fonts.h
+++ b/gfx/thebes/gfxFT2Fonts.h
@@ -136,17 +136,18 @@ protected: // new functions
                       nsTArray<nsRefPtr<gfxFontEntry> >& aFontEntryList);
     void GetCJKPrefFonts(nsTArray<nsRefPtr<gfxFontEntry> >& aFontEntryList);
     void FamilyListToArrayList(const nsString& aFamilies,
                                nsIAtom *aLangGroup,
                                nsTArray<nsRefPtr<gfxFontEntry> > *aFontEntryList);
     already_AddRefed<gfxFT2Font> WhichFontSupportsChar(const nsTArray<nsRefPtr<gfxFontEntry> >& aFontEntryList,
                                                        PRUint32 aCh);
     already_AddRefed<gfxFont> WhichPrefFontSupportsChar(PRUint32 aCh);
-    already_AddRefed<gfxFont> WhichSystemFontSupportsChar(PRUint32 aCh);
+    already_AddRefed<gfxFont>
+        WhichSystemFontSupportsChar(PRUint32 aCh, PRInt32 aRunScript);
 
     nsTArray<gfxTextRange> mRanges;
     nsString mString;
 };
 #endif // !ANDROID
 
 #endif /* GFX_FT2FONTS_H */
 
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -685,102 +685,125 @@ gfxFontFamily::FindWeightsForStyle(gfxFo
 
 
 void gfxFontFamily::LocalizedName(nsAString& aLocalizedName)
 {
     // just return the primary name; subclasses should override
     aLocalizedName = mName;
 }
 
+// metric for how close a given font matches a style
+static PRInt32
+CalcStyleMatch(gfxFontEntry *aFontEntry, const gfxFontStyle *aStyle)
+{
+    PRInt32 rank = 0;
+    if (aStyle) {
+         // italics
+         bool wantItalic =
+             ((aStyle->style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) != 0);
+         if (aFontEntry->IsItalic() == wantItalic) {
+             rank += 10;
+         }
+
+        // measure of closeness of weight to the desired value
+        rank += 9 - abs(aFontEntry->Weight() / 100 - aStyle->ComputeWeight());
+    } else {
+        // if no font to match, prefer non-bold, non-italic fonts
+        if (!aFontEntry->IsItalic()) {
+            rank += 3;
+        }
+        if (!aFontEntry->IsBold()) {
+            rank += 2;
+        }
+    }
+
+    return rank;
+}
+
+#define RANK_MATCHED_CMAP   20
 
 void
-gfxFontFamily::FindFontForChar(FontSearch *aMatchData)
+gfxFontFamily::FindFontForChar(GlobalFontMatch *aMatchData)
 {
-    if (!mHasStyles) {
-        FindStyleVariations();
-    }
-
-    if (!TestCharacterMap(aMatchData->mCh)) {
+    if (mCharacterMapInitialized && !TestCharacterMap(aMatchData->mCh)) {
         // none of the faces in the family support the required char,
         // so bail out immediately
         return;
     }
 
-    // iterate over fonts
-    PRUint32 numFonts = mAvailableFonts.Length();
-    for (PRUint32 i = 0; i < numFonts; i++) {
-        gfxFontEntry *fe = mAvailableFonts[i];
-
-        // skip certain fonts during system fallback
-        if (!fe || fe->SkipDuringSystemFallback())
-            continue;
-
+    bool needsBold;
+    gfxFontStyle normal;
+    gfxFontEntry *fe = FindFontForStyle(
+                  (aMatchData->mStyle == nsnull) ? *aMatchData->mStyle : normal,
+                  needsBold);
+
+    if (fe && !fe->SkipDuringSystemFallback()) {
         PRInt32 rank = 0;
 
         if (fe->TestCharacterMap(aMatchData->mCh)) {
-            rank += 20;
+            rank += RANK_MATCHED_CMAP;
             aMatchData->mCount++;
 #ifdef PR_LOGGING
             PRLogModuleInfo *log = gfxPlatform::GetLog(eGfxLog_textrun);
-        
+
             if (NS_UNLIKELY(log)) {
                 PRUint32 charRange = gfxFontUtils::CharRangeBit(aMatchData->mCh);
                 PRUint32 unicodeRange = FindCharUnicodeRange(aMatchData->mCh);
                 PRUint32 script = GetScriptCode(aMatchData->mCh);
                 PR_LOG(log, PR_LOG_DEBUG,\
                        ("(textrun-systemfallback-fonts) char: u+%6.6x "
                         "char-range: %d unicode-range: %d script: %d match: [%s]\n",
                         aMatchData->mCh,
                         charRange, unicodeRange, script,
                         NS_ConvertUTF16toUTF8(fe->Name()).get()));
             }
 #endif
         }
 
-        // if we didn't match any characters don't bother wasting more time with this face.
-        if (rank == 0)
-            continue;
-            
-        // omitting from original windows code -- family name, lang group, pitch
-        // not available in current FontEntry implementation
-
-        if (aMatchData->mFontToMatch) { 
-            const gfxFontStyle *style = aMatchData->mFontToMatch->GetStyle();
-
-            // matching italics takes precedence over weight
-            bool wantItalic =
-                ((style->style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) != 0);
-            if (fe->IsItalic() == wantItalic) {
-                rank += 10;
-            }
-
-            // measure of closeness of weight to the desired value
-            rank += 9 - abs(fe->Weight() / 100 - style->ComputeWeight());
-        } else {
-            // if no font to match, prefer non-bold, non-italic fonts
-            if (!fe->IsItalic()) {
-                rank += 3;
-            }
-            if (!fe->IsBold()) {
-                rank += 2;
-            }
+        aMatchData->mCmapsTested++;
+        if (rank == 0) {
+            return;
         }
-        
+
+         // omitting from original windows code -- family name, lang group, pitch
+         // not available in current FontEntry implementation
+        rank += CalcStyleMatch(fe, aMatchData->mStyle);
+
         // xxx - add whether AAT font with morphing info for specific lang groups
-        
+
         if (rank > aMatchData->mMatchRank
             || (rank == aMatchData->mMatchRank &&
-                Compare(fe->Name(), aMatchData->mBestMatch->Name()) > 0)) 
+                Compare(fe->Name(), aMatchData->mBestMatch->Name()) > 0))
         {
             aMatchData->mBestMatch = fe;
             aMatchData->mMatchRank = rank;
         }
     }
 }
 
+void
+gfxFontFamily::SearchAllFontsForChar(GlobalFontMatch *aMatchData)
+{
+    PRUint32 i, numFonts = mAvailableFonts.Length();
+    for (i = 0; i < numFonts; i++) {
+        gfxFontEntry *fe = mAvailableFonts[i];
+        if (fe && fe->TestCharacterMap(aMatchData->mCh)) {
+            PRInt32 rank = RANK_MATCHED_CMAP;
+            rank += CalcStyleMatch(fe, aMatchData->mStyle);
+            if (rank > aMatchData->mMatchRank
+                || (rank == aMatchData->mMatchRank &&
+                    Compare(fe->Name(), aMatchData->mBestMatch->Name()) > 0))
+            {
+                aMatchData->mBestMatch = fe;
+                aMatchData->mMatchRank = rank;
+            }
+        }
+    }
+}
+
 // returns true if other names were found, false otherwise
 bool
 gfxFontFamily::ReadOtherFamilyNamesForFace(gfxPlatformFontList *aPlatformFontList,
                                            FallibleTArray<PRUint8>& aNameTable,
                                            bool useFullName)
 {
     const PRUint8 *nameData = aNameTable.Elements();
     PRUint32 dataLength = aNameTable.Length();
@@ -3148,17 +3171,17 @@ gfxFontGroup::InitTextRun(gfxContext *aC
         PRInt32 runScript = MOZ_SCRIPT_LATIN;
         while (scriptRuns.Next(runStart, runLimit, runScript)) {
 
 #ifdef PR_LOGGING
             if (NS_UNLIKELY(log)) {
                 nsCAutoString lang;
                 mStyle.language->ToUTF8String(lang);
                 PRUint32 runLen = runLimit - runStart;
-                PR_LOG(log, PR_LOG_DEBUG,\
+                PR_LOG(log, PR_LOG_WARNING,\
                        ("(%s) fontgroup: [%s] lang: %s script: %d len %d "
                         "weight: %d width: %d style: %s "
                         "TEXTRUN [%s] ENDTEXTRUN\n",
                         (mStyle.systemFont ? "textrunui" : "textrun"),
                         NS_ConvertUTF16toUTF8(mFamilies).get(),
                         lang.get(), runScript, runLen,
                         PRUint32(mStyle.weight), PRUint32(mStyle.stretch),
                         (mStyle.style & FONT_STYLE_ITALIC ? "italic" :
@@ -3354,21 +3377,22 @@ gfxFontGroup::FindFontForChar(PRUint32 a
 
     // 1. check fonts in the font group
     for (PRUint32 i = 0; i < FontListLength(); i++) {
         nsRefPtr<gfxFont> font = GetFontAt(i);
         if (font->HasCharacter(aCh)) {
             *aMatchType = gfxTextRange::kFontGroup;
             return font.forget();
         }
+
         // check other faces of the family
         gfxFontFamily *family = font->GetFontEntry()->Family();
         if (family && family->TestCharacterMap(aCh)) {
-            FontSearch matchData(aCh, font);
-            family->FindFontForChar(&matchData);
+            GlobalFontMatch matchData(aCh, aRunScript, &mStyle);
+            family->SearchAllFontsForChar(&matchData);
             gfxFontEntry *fe = matchData.mBestMatch;
             if (fe) {
                 bool needsBold =
                     font->GetStyle()->weight >= 600 && !fe->IsBold();
                 selectedFont =
                     fe->FindOrMakeFont(font->GetStyle(), needsBold);
                 if (selectedFont) {
                     return selectedFont.forget();
@@ -3390,29 +3414,34 @@ gfxFontGroup::FindFontForChar(PRUint32 a
     // 3. use fallback fonts
     // -- before searching for something else check the font used for the previous character
     if (!selectedFont && aPrevMatchedFont && aPrevMatchedFont->HasCharacter(aCh)) {
         *aMatchType = gfxTextRange::kSystemFallback;
         selectedFont = aPrevMatchedFont;
         return selectedFont.forget();
     }
 
+    // never fall back for characters from unknown scripts
+    if (aRunScript == HB_SCRIPT_UNKNOWN) {
+        return nsnull;
+    }
+
     // for known "space" characters, don't do a full system-fallback search;
     // we'll synthesize appropriate-width spaces instead of missing-glyph boxes
     if (GetGeneralCategory(aCh) ==
             HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR &&
         GetFontAt(0)->SynthesizeSpaceWidth(aCh) >= 0.0)
     {
         return nsnull;
     }
 
     // -- otherwise look for other stuff
     if (!selectedFont) {
         *aMatchType = gfxTextRange::kSystemFallback;
-        selectedFont = WhichSystemFontSupportsChar(aCh);
+        selectedFont = WhichSystemFontSupportsChar(aCh, aRunScript);
         return selectedFont.forget();
     }
 
     return nsnull;
 }
 
 template<typename T>
 void gfxFontGroup::ComputeRanges(nsTArray<gfxTextRange>& aRanges,
@@ -3547,20 +3576,16 @@ struct PrefFontCallbackData {
     }
 };
 
 already_AddRefed<gfxFont>
 gfxFontGroup::WhichPrefFontSupportsChar(PRUint32 aCh)
 {
     gfxFont *font;
 
-    // FindCharUnicodeRange only supports BMP character points and there are no non-BMP fonts in prefs
-    if (aCh > 0xFFFF)
-        return nsnull;
-
     // get the pref font list if it hasn't been set up already
     PRUint32 unicodeRange = FindCharUnicodeRange(aCh);
     eFontPrefLang charLang = gfxPlatform::GetPlatform()->GetFontPrefLangFor(unicodeRange);
 
     // if the last pref font was the first family in the pref list, no need to recheck through a list of families
     if (mLastPrefFont && charLang == mLastPrefLang &&
         mLastPrefFirstFont && mLastPrefFont->HasCharacter(aCh)) {
         font = mLastPrefFont;
@@ -3622,22 +3647,24 @@ gfxFontGroup::WhichPrefFontSupportsChar(
 
         }
     }
 
     return nsnull;
 }
 
 already_AddRefed<gfxFont>
-gfxFontGroup::WhichSystemFontSupportsChar(PRUint32 aCh)
+gfxFontGroup::WhichSystemFontSupportsChar(PRUint32 aCh, PRInt32 aRunScript)
 {
     gfxFontEntry *fe = 
-        gfxPlatformFontList::PlatformFontList()->FindFontForChar(aCh, GetFontAt(0));
+        gfxPlatformFontList::PlatformFontList()->
+            SystemFindFontForChar(aCh, aRunScript, &mStyle);
     if (fe) {
-        nsRefPtr<gfxFont> font = fe->FindOrMakeFont(&mStyle, false); // ignore bolder considerations in system fallback case...
+        // ignore bolder considerations in system fallback case...
+        nsRefPtr<gfxFont> font = fe->FindOrMakeFont(&mStyle, false);
         return font.forget();
     }
 
     return nsnull;
 }
 
 /*static*/ void
 gfxFontGroup::Shutdown()
--- a/gfx/thebes/gfxFont.h
+++ b/gfx/thebes/gfxFont.h
@@ -482,26 +482,34 @@ private:
 
     nsTHashtable<FontTableHashEntry> mFontTableCache;
 
     gfxFontEntry(const gfxFontEntry&);
     gfxFontEntry& operator=(const gfxFontEntry&);
 };
 
 
-// used when picking fallback font
-struct FontSearch {
-    FontSearch(const PRUint32 aCharacter, gfxFont *aFont) :
-        mCh(aCharacter), mFontToMatch(aFont), mMatchRank(0), mCount(0) {
-    }
-    const PRUint32         mCh;
-    gfxFont*               mFontToMatch;
-    PRInt32                mMatchRank;
-    nsRefPtr<gfxFontEntry> mBestMatch;
-    PRUint32               mCount;
+// used when iterating over all fonts looking for a match for a given character
+struct GlobalFontMatch {
+    GlobalFontMatch(const PRUint32 aCharacter,
+                    PRInt32 aRunScript,
+                    const gfxFontStyle *aStyle) :
+        mCh(aCharacter), mRunScript(aRunScript), mStyle(aStyle),
+        mMatchRank(0), mCount(0), mCmapsTested(0)
+        {
+
+        }
+
+    const PRUint32         mCh;          // codepoint to be matched
+    PRInt32                mRunScript;   // Unicode script for the codepoint
+    const gfxFontStyle*    mStyle;       // style to match
+    PRInt32                mMatchRank;   // metric indicating closest match
+    nsRefPtr<gfxFontEntry> mBestMatch;   // current best match
+    PRUint32               mCount;       // number of fonts matched
+    PRUint32               mCmapsTested; // number of cmaps tested
 };
 
 class gfxFontFamily {
 public:
     NS_INLINE_DECL_REFCOUNTING(gfxFontFamily)
 
     gfxFontFamily(const nsAString& aName) :
         mName(aName),
@@ -552,19 +560,22 @@ public:
     // choose a specific face to match a style using CSS font matching
     // rules (weight matching occurs here).  may return a face that doesn't
     // precisely match (e.g. normal face when no italic face exists).
     // aNeedsSyntheticBold is set to true when synthetic bolding is
     // needed, false otherwise
     gfxFontEntry *FindFontForStyle(const gfxFontStyle& aFontStyle, 
                                    bool& aNeedsSyntheticBold);
 
-    // iterates over faces looking for a match with a given characters
+    // checks for a matching font within the family
     // used as part of the font fallback process
-    void FindFontForChar(FontSearch *aMatchData);
+    void FindFontForChar(GlobalFontMatch *aMatchData);
+
+    // checks all fonts for a matching font within the family
+    void SearchAllFontsForChar(GlobalFontMatch *aMatchData);
 
     // read in other family names, if any, and use functor to add each into cache
     virtual void ReadOtherFamilyNames(gfxPlatformFontList *aPlatformFontList);
 
     // set when other family names have been read in
     void SetOtherFamilyNamesInitialized() {
         mOtherFamilyNamesInitialized = true;
     }
@@ -577,33 +588,33 @@ public:
     // find faces belonging to this family (platform implementations override this;
     // should be made pure virtual once all subclasses have been updated)
     virtual void FindStyleVariations() { }
 
     // search for a specific face using the Postscript name
     gfxFontEntry* FindFont(const nsAString& aPostscriptName);
 
     // read in cmaps for all the faces
-    void ReadCMAP() {
+    void ReadAllCMAPs() {
         PRUint32 i, numFonts = mAvailableFonts.Length();
         for (i = 0; i < numFonts; i++) {
             gfxFontEntry *fe = mAvailableFonts[i];
             if (!fe) {
                 continue;
             }
             fe->ReadCMAP();
             mCharacterMap.Union(fe->mCharacterMap);
         }
         mCharacterMap.Compact();
         mCharacterMapInitialized = true;
     }
 
     bool TestCharacterMap(PRUint32 aCh) {
         if (!mCharacterMapInitialized) {
-            ReadCMAP();
+            ReadAllCMAPs();
         }
         return mCharacterMap.test(aCh);
     }
 
     void ResetCharacterMap() {
         mCharacterMap.reset();
         mCharacterMapInitialized = false;
     }
@@ -2970,17 +2981,18 @@ public:
     virtual already_AddRefed<gfxFont>
         FindFontForChar(PRUint32 ch, PRUint32 prevCh, PRInt32 aRunScript,
                         gfxFont *aPrevMatchedFont,
                         PRUint8 *aMatchType);
 
     // search through pref fonts for a character, return nsnull if no matching pref font
     virtual already_AddRefed<gfxFont> WhichPrefFontSupportsChar(PRUint32 aCh);
 
-    virtual already_AddRefed<gfxFont> WhichSystemFontSupportsChar(PRUint32 aCh);
+    virtual already_AddRefed<gfxFont>
+        WhichSystemFontSupportsChar(PRUint32 aCh, PRInt32 aRunScript);
 
     template<typename T>
     void ComputeRanges(nsTArray<gfxTextRange>& mRanges,
                        const T *aString, PRUint32 aLength,
                        PRInt32 aRunScript);
 
     gfxUserFontSet* GetUserFontSet();
 
--- a/gfx/thebes/gfxFontUtils.cpp
+++ b/gfx/thebes/gfxFontUtils.cpp
@@ -32,37 +32,50 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+#ifdef MOZ_LOGGING
+#define FORCE_PR_LOG /* Allow logging in the release build */
+#endif
+#include "prlog.h"
+
 #include "mozilla/Util.h"
 
 #include "gfxFontUtils.h"
 
 #include "nsServiceManagerUtils.h"
 
 #include "mozilla/Preferences.h"
 
 #include "nsIStreamBufferAccess.h"
 #include "nsIUUIDGenerator.h"
 #include "nsMemory.h"
 #include "nsICharsetConverterManager.h"
 
 #include "plbase64.h"
+#include "prlog.h"
 
 #include "woff.h"
 
 #ifdef XP_MACOSX
 #include <CoreFoundation/CoreFoundation.h>
 #endif
 
+#ifdef PR_LOGGING
+
+#define LOG(log, args) PR_LOG(gfxPlatform::GetLog(log), \
+                               PR_LOG_DEBUG, args)
+
+#endif // PR_LOGGING
+
 #define NO_RANGE_FOUND 126 // bit 126 in the font unicode ranges is required to be 0
 
 #define UNICODE_BMP_LIMIT 0x10000
 
 using namespace mozilla;
 
 /* Unicode subrange table
  *   from: http://msdn.microsoft.com/en-us/library/dd374090
@@ -264,16 +277,47 @@ typedef struct {
 typedef struct {
     AutoSwap_PRUint32 startCharCode;
     AutoSwap_PRUint32 endCharCode;
     AutoSwap_PRUint32 startGlyphId;
 } Format12Group;
 
 #pragma pack()
 
+#if PR_LOGGING
+void
+gfxSparseBitSet::Dump(const char* aPrefix, eGfxLog aWhichLog) const
+{
+    NS_ASSERTION(mBlocks.DebugGetHeader(), "mHdr is null, this is bad");
+    PRUint32 b, numBlocks = mBlocks.Length();
+
+    for (b = 0; b < numBlocks; b++) {
+        Block *block = mBlocks[b];
+        if (!block) continue;
+        char outStr[256];
+        int index = 0;
+        index += sprintf(&outStr[index], "%s u+%6.6x [", aPrefix, (b << BLOCK_INDEX_SHIFT));
+        for (int i = 0; i < 32; i += 4) {
+            for (int j = i; j < i + 4; j++) {
+                PRUint8 bits = block->mBits[j];
+                PRUint8 flip1 = ((bits & 0xaa) >> 1) | ((bits & 0x55) << 1);
+                PRUint8 flip2 = ((flip1 & 0xcc) >> 2) | ((flip1 & 0x33) << 2);
+                PRUint8 flipped = ((flip2 & 0xf0) >> 4) | ((flip2 & 0x0f) << 4);
+
+                index += sprintf(&outStr[index], "%2.2x", flipped);
+            }
+            if (i + 4 != 32) index += sprintf(&outStr[index], " ");
+        }
+        index += sprintf(&outStr[index], "]");
+        LOG(aWhichLog, ("%s", outStr));
+    }
+}
+#endif
+
+
 nsresult
 gfxFontUtils::ReadCMAPTableFormat12(const PRUint8 *aBuf, PRUint32 aLength,
                                     gfxSparseBitSet& aCharacterMap) 
 {
     // Ensure table is large enough that we can safely read the header
     NS_ENSURE_TRUE(aLength >= sizeof(Format12CmapHeader),
                     NS_ERROR_GFX_CMAP_MALFORMED);
 
--- a/gfx/thebes/gfxFontUtils.h
+++ b/gfx/thebes/gfxFontUtils.h
@@ -36,16 +36,17 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef GFX_FONT_UTILS_H
 #define GFX_FONT_UTILS_H
 
 #include "gfxTypes.h"
+#include "gfxPlatform.h"
 
 #include "prtypes.h"
 #include "nsAlgorithm.h"
 #include "prcpucfg.h"
 
 #include "nsDataHashtable.h"
 
 #include "nsITimer.h"
@@ -92,16 +93,21 @@ public:
         if (blockIndex >= mBlocks.Length())
             return false;
         Block *block = mBlocks[blockIndex];
         if (!block)
             return false;
         return ((block->mBits[(aIndex>>3) & (BLOCK_SIZE - 1)]) & (1 << (aIndex & 0x7))) != 0;
     }
 
+#if PR_LOGGING
+    // dump out contents of bitmap
+    void Dump(const char* aPrefix, eGfxLog aWhichLog) const;
+#endif
+
     bool TestRange(PRUint32 aStart, PRUint32 aEnd) {
         PRUint32 startBlock, endBlock, blockLen;
         
         // start point is beyond the end of the block array? return false immediately
         startBlock = aStart >> BLOCK_INDEX_SHIFT;
         blockLen = mBlocks.Length();
         if (startBlock >= blockLen) return false;
         
--- a/gfx/thebes/gfxGDIFontList.cpp
+++ b/gfx/thebes/gfxGDIFontList.cpp
@@ -78,16 +78,20 @@ using namespace mozilla;
 
 #ifdef PR_LOGGING
 #define LOG_FONTLIST(args) PR_LOG(gfxPlatform::GetLog(eGfxLog_fontlist), \
                                PR_LOG_DEBUG, args)
 #define LOG_FONTLIST_ENABLED() PR_LOG_TEST( \
                                    gfxPlatform::GetLog(eGfxLog_fontlist), \
                                    PR_LOG_DEBUG)
 
+#define LOG_CMAPDATA_ENABLED() PR_LOG_TEST( \
+                                   gfxPlatform::GetLog(eGfxLog_cmapdata), \
+                                   PR_LOG_DEBUG)
+
 #endif // PR_LOGGING
 
 // font info loader constants
 
 // avoid doing this during startup even on slow machines but try to start
 // it soon enough so that system fallback doesn't happen first
 static const PRUint32 kDelayBeforeLoadingFonts = 120 * 1000; // 2 minutes after init
 static const PRUint32 kIntervalBetweenLoadingFonts = 2000;   // every 2 seconds until complete
@@ -222,16 +226,22 @@ GDIFontEntry::ReadCMAP()
                                          mCharacterMap, mUVSOffset,
                                          unicodeFont, symbolFont);
     mSymbolFont = symbolFont;
     mHasCmapTable = NS_SUCCEEDED(rv);
 
 #ifdef PR_LOGGING
     LOG_FONTLIST(("(fontlist-cmap) name: %s, size: %d\n",
                   NS_ConvertUTF16toUTF8(mName).get(), mCharacterMap.GetSize()));
+    if (LOG_CMAPDATA_ENABLED()) {
+        char prefix[256];
+        sprintf(prefix, "(cmapdata) name: %.220s",
+                NS_ConvertUTF16toUTF8(mName).get());
+        mCharacterMap.Dump(prefix, eGfxLog_cmapdata);
+    }
 #endif
     return rv;
 }
 
 bool
 GDIFontEntry::IsSymbolFont()
 {
     // initialize cmap first
--- a/gfx/thebes/gfxMacPlatformFontList.h
+++ b/gfx/thebes/gfxMacPlatformFontList.h
@@ -161,32 +161,44 @@ public:
     static bool UseATSFontEntry() {
         return gfxPlatformMac::GetPlatform()->OSXVersion() < MAC_OS_X_VERSION_10_6_HEX;
     }
 
 private:
     friend class gfxPlatformMac;
 
     gfxMacPlatformFontList();
+    virtual ~gfxMacPlatformFontList();
 
     // initialize font lists
     virtual nsresult InitFontList();
 
     // special case font faces treated as font families (set via prefs)
     void InitSingleFaceList();
 
     gfxFontEntry* MakePlatformFontCG(const gfxProxyFontEntry *aProxyEntry,
                                      const PRUint8 *aFontData, PRUint32 aLength);
 
     gfxFontEntry* MakePlatformFontATS(const gfxProxyFontEntry *aProxyEntry,
                                       const PRUint8 *aFontData, PRUint32 aLength);
 
     static void ATSNotification(ATSFontNotificationInfoRef aInfo, void* aUserArg);
 
+    // search fonts system-wide for a given character, null otherwise
+    virtual gfxFontEntry* GlobalFontFallback(const PRUint32 aCh,
+                                             PRInt32 aRunScript,
+                                             const gfxFontStyle* aMatchStyle,
+                                             PRUint32& aCmapCount);
+
+    virtual bool UsesSystemFallback() { return true; }
+
     // keep track of ATS generation to prevent unneeded updates when loading downloaded fonts
     PRUint32 mATSGeneration;
 
     enum {
         kATSGenerationInitial = -1
     };
+
+    // default font for use with system-wide font fallback
+    CTFontRef mDefaultFont;
 };
 
 #endif /* gfxMacPlatformFontList_H_ */
--- a/gfx/thebes/gfxMacPlatformFontList.mm
+++ b/gfx/thebes/gfxMacPlatformFontList.mm
@@ -53,16 +53,17 @@
 #include "gfxUserFontSet.h"
 
 #include "nsServiceManagerUtils.h"
 #include "nsTArray.h"
 
 #include "nsDirectoryServiceUtils.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsISimpleEnumerator.h"
+#include "nsCharTraits.h"
 
 #include "mozilla/Telemetry.h"
 
 #include <unistd.h>
 #include <time.h>
 
 using namespace mozilla;
 
@@ -131,16 +132,19 @@ static NSString* GetNSStringForString(co
 
 #ifdef PR_LOGGING
 
 #define LOG_FONTLIST(args) PR_LOG(gfxPlatform::GetLog(eGfxLog_fontlist), \
                                PR_LOG_DEBUG, args)
 #define LOG_FONTLIST_ENABLED() PR_LOG_TEST( \
                                    gfxPlatform::GetLog(eGfxLog_fontlist), \
                                    PR_LOG_DEBUG)
+#define LOG_CMAPDATA_ENABLED() PR_LOG_TEST( \
+                                   gfxPlatform::GetLog(eGfxLog_cmapdata), \
+                                   PR_LOG_DEBUG)
 
 #endif // PR_LOGGING
 
 /* MacOSFontEntry - abstract superclass for ATS and CG font entries */
 #pragma mark-
 
 MacOSFontEntry::MacOSFontEntry(const nsAString& aPostscriptName,
                                PRInt32 aWeight,
@@ -262,16 +266,22 @@ MacOSFontEntry::ReadCMAP()
             }
         }
     }
 
 #ifdef PR_LOGGING
     LOG_FONTLIST(("(fontlist-cmap) name: %s, size: %d\n",
                   NS_ConvertUTF16toUTF8(mName).get(),
                   mCharacterMap.GetSize()));
+    if (LOG_CMAPDATA_ENABLED()) {
+        char prefix[256];
+        sprintf(prefix, "(cmapdata) name: %.220s",
+                NS_ConvertUTF16toUTF8(mName).get());
+        mCharacterMap.Dump(prefix, eGfxLog_cmapdata);
+    }
 #endif
 
     return rv;
 }
 
 gfxFont*
 MacOSFontEntry::CreateFontInstance(const gfxFontStyle *aFontStyle, bool aNeedsBold)
 {
@@ -690,31 +700,39 @@ gfxSingleFaceMacFontFamily::ReadOtherFam
     mOtherFamilyNamesInitialized = true;
 }
 
 
 /* gfxMacPlatformFontList */
 #pragma mark-
 
 gfxMacPlatformFontList::gfxMacPlatformFontList() :
-    gfxPlatformFontList(false), mATSGeneration(PRUint32(kATSGenerationInitial))
+    gfxPlatformFontList(false), mATSGeneration(PRUint32(kATSGenerationInitial)),
+    mDefaultFont(nsnull)
 {
     ::ATSFontNotificationSubscribe(ATSNotification,
                                    kATSFontNotifyOptionDefault,
                                    (void*)this, nsnull);
 
     // this should always be available (though we won't actually fail if it's missing,
     // we'll just end up doing a search and then caching the new result instead)
     mReplacementCharFallbackFamily = NS_LITERAL_STRING("Lucida Grande");
 
     // cache this in a static variable so that MacOSFontFamily objects
     // don't have to repeatedly look it up
     sFontManager = [NSFontManager sharedFontManager];
 }
 
+gfxMacPlatformFontList::~gfxMacPlatformFontList()
+{
+    if (mDefaultFont) {
+        ::CFRelease(mDefaultFont);
+    }
+}
+
 nsresult
 gfxMacPlatformFontList::InitFontList()
 {
     nsAutoreleasePool localPool;
 
     ATSGeneration currentGeneration = ::ATSGetGeneration();
 
     // need to ignore notifications after adding each font
@@ -862,16 +880,103 @@ gfxMacPlatformFontList::ATSNotification(
                                     void* aUserArg)
 {
     // xxx - should be carefully pruning the list of fonts, not rebuilding it from scratch
     gfxMacPlatformFontList *qfc = (gfxMacPlatformFontList*)aUserArg;
     qfc->UpdateFontList();
 }
 
 gfxFontEntry*
+gfxMacPlatformFontList::GlobalFontFallback(const PRUint32 aCh,
+                                           PRInt32 aRunScript,
+                                           const gfxFontStyle* aMatchStyle,
+                                           PRUint32& aCmapCount)
+{
+    bool useCmaps = gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback();
+
+    if (useCmaps) {
+        return gfxPlatformFontList::GlobalFontFallback(aCh,
+                                                       aRunScript,
+                                                       aMatchStyle,
+                                                       aCmapCount);
+    }
+
+    CFStringRef str;
+    UniChar ch[2];
+    CFIndex len = 1;
+
+    if (IS_IN_BMP(aCh)) {
+        ch[0] = aCh;
+        str = ::CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, ch, 1,
+                                                   kCFAllocatorNull);
+    } else {
+        ch[0] = H_SURROGATE(aCh);
+        ch[1] = L_SURROGATE(aCh);
+        str = ::CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, ch, 2,
+                                                   kCFAllocatorNull);
+        if (!str) {
+            return nsnull;
+        }
+        len = 2;
+    }
+
+    // use CoreText to find the fallback family
+
+    gfxFontEntry *fontEntry = nsnull;
+    CTFontRef fallback;
+    bool cantUseFallbackFont = false;
+
+    if (!mDefaultFont) {
+        mDefaultFont = ::CTFontCreateWithName(CFSTR("Lucida Grande"), 12.f,
+                                              NULL);
+    }
+
+    fallback = ::CTFontCreateForString(mDefaultFont, str,
+                                       ::CFRangeMake(0, len));
+
+    if (fallback) {
+        CFStringRef familyName = ::CTFontCopyFamilyName(fallback);
+        ::CFRelease(fallback);
+
+        if (familyName &&
+            ::CFStringCompare(familyName, CFSTR("LastResort"),
+                              kCFCompareCaseInsensitive) != kCFCompareEqualTo)
+        {
+            nsAutoTArray<UniChar, 1024> buffer;
+            CFIndex len = ::CFStringGetLength(familyName);
+            buffer.SetLength(len+1);
+            ::CFStringGetCharacters(familyName, ::CFRangeMake(0, len),
+                                    buffer.Elements());
+            buffer[len] = 0;
+            nsDependentString family(buffer.Elements(), len);
+
+            bool needsBold;  // ignored in the system fallback case
+
+            fontEntry = FindFontForFamily(family, aMatchStyle, needsBold);
+            if (fontEntry && !fontEntry->TestCharacterMap(aCh)) {
+                fontEntry = nsnull;
+                cantUseFallbackFont = true;
+            }
+        }
+
+        if (familyName) {
+            ::CFRelease(familyName);
+        }
+    }
+
+    if (cantUseFallbackFont) {
+        Telemetry::Accumulate(Telemetry::BAD_FALLBACK_FONT, cantUseFallbackFont);
+    }
+
+    ::CFRelease(str);
+
+    return fontEntry;
+}
+
+gfxFontEntry*
 gfxMacPlatformFontList::GetDefaultFont(const gfxFontStyle* aStyle, bool& aNeedsBold)
 {
     nsAutoreleasePool localPool;
 
     NSString *defaultFamily = [[NSFont userFontOfSize:aStyle->size] familyName];
     nsAutoString familyName;
 
     GetStringForNSString(defaultFamily, familyName);
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -113,16 +113,17 @@ static void MigratePrefs();
 using namespace mozilla::gfx;
 
 // logs shared across gfx
 #ifdef PR_LOGGING
 static PRLogModuleInfo *sFontlistLog = nsnull;
 static PRLogModuleInfo *sFontInitLog = nsnull;
 static PRLogModuleInfo *sTextrunLog = nsnull;
 static PRLogModuleInfo *sTextrunuiLog = nsnull;
+static PRLogModuleInfo *sCmapDataLog = nsnull;
 #endif
 
 /* Class to listen for pref changes so that chrome code can dynamically
    force sRGB as an output profile. See Bug #452125. */
 class SRGBOverrideObserver : public nsIObserver,
                              public nsSupportsWeakReference
 {
 public:
@@ -144,16 +145,17 @@ SRGBOverrideObserver::Observe(nsISupport
     return NS_OK;
 }
 
 #define GFX_DOWNLOADABLE_FONTS_ENABLED "gfx.downloadable_fonts.enabled"
 #define GFX_DOWNLOADABLE_FONTS_SANITIZE "gfx.downloadable_fonts.sanitize"
 
 #define GFX_PREF_HARFBUZZ_SCRIPTS "gfx.font_rendering.harfbuzz.scripts"
 #define HARFBUZZ_SCRIPTS_DEFAULT  mozilla::unicode::SHAPING_DEFAULT
+#define GFX_PREF_FALLBACK_USE_CMAPS  "gfx.font_rendering.fallback.always_use_cmaps"
 
 #ifdef MOZ_GRAPHITE
 #define GFX_PREF_GRAPHITE_SHAPING "gfx.font_rendering.graphite.enabled"
 #endif
 
 #define BIDI_NUMERAL_PREF "bidi.numeral"
 
 static const char* kObservedPrefs[] = {
@@ -227,16 +229,18 @@ static const char *gPrefLangNames[] = {
 };
 
 gfxPlatform::gfxPlatform()
   : mAzureBackendCollector(this, &gfxPlatform::GetAzureBackendInfo)
 {
     mUseHarfBuzzScripts = UNINITIALIZED_VALUE;
     mAllowDownloadableFonts = UNINITIALIZED_VALUE;
     mDownloadableFontsSanitize = UNINITIALIZED_VALUE;
+    mFallbackUsesCmaps = UNINITIALIZED_VALUE;
+
 #ifdef MOZ_GRAPHITE
     mGraphiteShapingEnabled = UNINITIALIZED_VALUE;
 #endif
     mBidiNumeralOption = UNINITIALIZED_VALUE;
 
     if (Preferences::GetBool("gfx.canvas.azure.prefer-skia", false)) {
         mPreferredDrawTargetBackend = BACKEND_SKIA;
     } else {
@@ -263,16 +267,17 @@ gfxPlatform::Init()
 
     gfxAtoms::RegisterAtoms();
 
 #ifdef PR_LOGGING
     sFontlistLog = PR_NewLogModule("fontlist");;
     sFontInitLog = PR_NewLogModule("fontinit");;
     sTextrunLog = PR_NewLogModule("textrun");;
     sTextrunuiLog = PR_NewLogModule("textrunui");;
+    sCmapDataLog = PR_NewLogModule("cmapdata");;
 #endif
 
 
     /* Initialize the GfxInfo service.
      * Note: we can't call functions on GfxInfo that depend
      * on gPlatform until after it has been initialized
      * below. GfxInfo initialization annotates our
      * crash reports so we want to do it before
@@ -675,16 +680,27 @@ gfxPlatform::SanitizeDownloadedFonts()
     if (mDownloadableFontsSanitize == UNINITIALIZED_VALUE) {
         mDownloadableFontsSanitize =
             Preferences::GetBool(GFX_DOWNLOADABLE_FONTS_SANITIZE, true);
     }
 
     return mDownloadableFontsSanitize;
 }
 
+bool
+gfxPlatform::UseCmapsDuringSystemFallback()
+{
+    if (mFallbackUsesCmaps == UNINITIALIZED_VALUE) {
+        mFallbackUsesCmaps =
+            Preferences::GetBool(GFX_PREF_FALLBACK_USE_CMAPS, false);
+    }
+
+    return mFallbackUsesCmaps;
+}
+
 #ifdef MOZ_GRAPHITE
 bool
 gfxPlatform::UseGraphiteShaping()
 {
     if (mGraphiteShapingEnabled == UNINITIALIZED_VALUE) {
         mGraphiteShapingEnabled =
             Preferences::GetBool(GFX_PREF_GRAPHITE_SHAPING, false);
     }
@@ -1353,16 +1369,18 @@ gfxPlatform::GetBidiNumeralOption()
 void
 gfxPlatform::FontsPrefsChanged(const char *aPref)
 {
     NS_ASSERTION(aPref != nsnull, "null preference");
     if (!strcmp(GFX_DOWNLOADABLE_FONTS_ENABLED, aPref)) {
         mAllowDownloadableFonts = UNINITIALIZED_VALUE;
     } else if (!strcmp(GFX_DOWNLOADABLE_FONTS_SANITIZE, aPref)) {
         mDownloadableFontsSanitize = UNINITIALIZED_VALUE;
+    } else if (!strcmp(GFX_PREF_FALLBACK_USE_CMAPS, aPref)) {
+        mFallbackUsesCmaps = UNINITIALIZED_VALUE;
 #ifdef MOZ_GRAPHITE
     } else if (!strcmp(GFX_PREF_GRAPHITE_SHAPING, aPref)) {
         mGraphiteShapingEnabled = UNINITIALIZED_VALUE;
         gfxFontCache *fontCache = gfxFontCache::GetCache();
         if (fontCache) {
             fontCache->AgeAllGenerations();
             fontCache->FlushShapedWordCaches();
         }
@@ -1392,16 +1410,19 @@ gfxPlatform::GetLog(eGfxLog aWhichLog)
         return sFontInitLog;
         break;
     case eGfxLog_textrun:
         return sTextrunLog;
         break;
     case eGfxLog_textrunui:
         return sTextrunuiLog;
         break;
+    case eGfxLog_cmapdata:
+        return sCmapDataLog;
+        break;
     default:
         break;
     }
 
     return nsnull;
 #else
     return nsnull;
 #endif
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -131,17 +131,19 @@ enum eCMSMode {
 enum eGfxLog {
     // all font enumerations, localized names, fullname/psnames, cmap loads
     eGfxLog_fontlist         = 0,
     // timing info on font initialization
     eGfxLog_fontinit         = 1,
     // dump text runs, font matching, system fallback for content
     eGfxLog_textrun          = 2,
     // dump text runs, font matching, system fallback for chrome
-    eGfxLog_textrunui        = 3
+    eGfxLog_textrunui        = 3,
+    // dump cmap coverage data as they are loaded
+    eGfxLog_cmapdata         = 4
 };
 
 // when searching through pref langs, max number of pref langs
 const PRUint32 kMaxLenPrefLangList = 32;
 
 #define UNINITIALIZED_VALUE  (-1)
 
 typedef gfxASurface::gfxImageFormat gfxImageFormat;
@@ -312,16 +314,21 @@ public:
      * True when hinting should be enabled.  This setting shouldn't
      * change per gecko process, while the process is live.  If so the
      * results are not defined.
      *
      * NB: this bit is only honored by the FT2 backend, currently.
      */
     virtual bool FontHintingEnabled() { return true; }
 
+    /**
+     * Whether to check all font cmaps during system font fallback
+     */
+    bool UseCmapsDuringSystemFallback();
+
 #ifdef MOZ_GRAPHITE
     /**
      * Whether to use the SIL Graphite rendering engine
      * (for fonts that include Graphite tables)
      */
     bool UseGraphiteShaping();
 #endif
 
@@ -364,16 +371,25 @@ public:
     static eFontPrefLang GetFontPrefLangFor(PRUint8 aUnicodeRange);
 
     // returns true if a pref lang is CJK
     static bool IsLangCJK(eFontPrefLang aLang);
     
     // helper method to add a pref lang to an array, if not already in array
     static void AppendPrefLang(eFontPrefLang aPrefLangs[], PRUint32& aLen, eFontPrefLang aAddLang);
 
+    // returns a list of commonly used fonts for a given character
+    // these are *possible* matches, no cmap-checking is done at this level
+    virtual void GetCommonFallbackFonts(const PRUint32 /*aCh*/,
+                                        PRInt32 /*aRunScript*/,
+                                        nsTArray<const char*>& /*aFontList*/)
+    {
+        // platform-specific override, by default do nothing
+    }
+
     // helper method to indicate if we want to use Azure content drawing
     static bool UseAzureContentDrawing();
     
     /**
      * Are we going to try color management?
      */
     static eCMSMode GetCMSMode();
 
@@ -449,16 +465,20 @@ protected:
     PRInt8  mAllowDownloadableFonts;
     PRInt8  mDownloadableFontsSanitize;
 #ifdef MOZ_GRAPHITE
     PRInt8  mGraphiteShapingEnabled;
 #endif
 
     PRInt8  mBidiNumeralOption;
 
+    // whether to always search font cmaps globally 
+    // when doing system font fallback
+    PRInt8  mFallbackUsesCmaps;
+
     // which scripts should be shaped with harfbuzz
     PRInt32 mUseHarfBuzzScripts;
 
     // The preferred draw target backend to use
     mozilla::gfx::BackendType mPreferredDrawTargetBackend;
 
 private:
     virtual qcms_profile* GetPlatformCMSOutputProfile();
--- a/gfx/thebes/gfxPlatformFontList.cpp
+++ b/gfx/thebes/gfxPlatformFontList.cpp
@@ -15,16 +15,17 @@
  * The Original Code is Mozilla Corporation code.
  *
  * The Initial Developer of the Original Code is Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2006-2009
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Jonathan Kew <jfkthame@gmail.com>
+ *   John Daggett <jdaggett@mozilla.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -371,103 +372,163 @@ struct FontFamilyListData {
 
 void
 gfxPlatformFontList::GetFontFamilyList(nsTArray<nsRefPtr<gfxFontFamily> >& aFamilyArray)
 {
     FontFamilyListData data(aFamilyArray);
     mFontFamilies.Enumerate(FontFamilyListData::AppendFamily, &data);
 }
 
-gfxFontEntry*  
-gfxPlatformFontList::FindFontForChar(const PRUint32 aCh, gfxFont *aPrevFont)
-{
+gfxFontEntry*
+gfxPlatformFontList::SystemFindFontForChar(const PRUint32 aCh,
+                                           PRInt32 aRunScript,
+                                           const gfxFontStyle* aStyle)
+ {
+    gfxFontEntry* fontEntry = nsnull;
+
     // is codepoint with no matching font? return null immediately
     if (mCodepointsWithNoFonts.test(aCh)) {
         return nsnull;
     }
 
-    // TODO: optimize fallback e.g. by caching lists of fonts to try for a given
-    // unicode range or script
-
-    // try to short-circuit font fallback for U+FFFD, used to represent encoding errors:
-    // just use a platform-specific fallback system font that is guaranteed (or at least
-    // highly likely) to be around, or a cached family from last time U+FFFD was seen.
-    // this helps speed up pages with lots of encoding errors, binary-as-text, etc.
+    // try to short-circuit font fallback for U+FFFD, used to represent
+    // encoding errors: just use a platform-specific fallback system
+    // font that is guaranteed (or at least highly likely) to be around,
+    // or a cached family from last time U+FFFD was seen. this helps
+    // speed up pages with lots of encoding errors, binary-as-text, etc.
     if (aCh == 0xFFFD && mReplacementCharFallbackFamily.Length() > 0) {
-        gfxFontEntry* fontEntry = nsnull;
         bool needsBold;  // ignored in the system fallback case
 
-        if (aPrevFont) {
-            fontEntry = FindFontForFamily(mReplacementCharFallbackFamily, aPrevFont->GetStyle(), needsBold);
-        } else {
-            gfxFontStyle normalStyle;
-            fontEntry = FindFontForFamily(mReplacementCharFallbackFamily, &normalStyle, needsBold);
-        }
+        fontEntry = FindFontForFamily(mReplacementCharFallbackFamily,
+                                      aStyle, needsBold);
 
         if (fontEntry && fontEntry->TestCharacterMap(aCh))
             return fontEntry;
     }
 
-    static bool first = true;
     TimeStamp start = TimeStamp::Now();
 
-    FontSearch data(aCh, aPrevFont);
-
-    // iterate over all font families to find a font that support the character
-    mFontFamilies.Enumerate(gfxPlatformFontList::FindFontForCharProc, &data);
-
+    // search commonly available fonts
+    bool common = true;
+    fontEntry = CommonFontFallback(aCh, aRunScript, aStyle);
+ 
+    // if didn't find a font, do system-wide fallback (except for specials)
+    PRUint32 cmapCount = 0;
+    if (!fontEntry) {
+        common = false;
+        fontEntry = GlobalFontFallback(aCh, aRunScript, aStyle, cmapCount);
+    }
     TimeDuration elapsed = TimeStamp::Now() - start;
 
 #ifdef PR_LOGGING
     PRLogModuleInfo *log = gfxPlatform::GetLog(eGfxLog_textrun);
 
     if (NS_UNLIKELY(log)) {
         PRUint32 charRange = gfxFontUtils::CharRangeBit(aCh);
         PRUint32 unicodeRange = FindCharUnicodeRange(aCh);
         PRInt32 script = mozilla::unicode::GetScriptCode(aCh);
-        PR_LOG(log, PR_LOG_DEBUG,\
-               ("(textrun-systemfallback) char: u+%6.6x "
-                "char-range: %d unicode-range: %d script: %d match: [%s]"
-                " count: %d time: %dus\n",
-                aCh,
-                charRange, unicodeRange, script,
-                (data.mBestMatch ?
-                 NS_ConvertUTF16toUTF8(data.mBestMatch->Name()).get() :
-                 "<none>"),
-                data.mCount,
-                PRInt32(elapsed.ToMicroseconds())));
+        PR_LOG(log, PR_LOG_WARNING,\
+               ("(textrun-systemfallback-%s) char: u+%6.6x "
+                 "char-range: %d unicode-range: %d script: %d match: [%s]"
+                " time: %dus cmaps: %d\n",
+                (common ? "common" : "global"), aCh,
+                 charRange, unicodeRange, script,
+                (fontEntry ? NS_ConvertUTF16toUTF8(fontEntry->Name()).get() :
+                    "<none>"),
+                PRInt32(elapsed.ToMicroseconds()),
+                cmapCount));
     }
 #endif
 
     // no match? add to set of non-matching codepoints
-    if (!data.mBestMatch) {
-        mCodepointsWithNoFonts.set(aCh);
-    } else if (aCh == 0xFFFD) {
-        mReplacementCharFallbackFamily = data.mBestMatch->FamilyName();
-    }
-
+    if (!fontEntry) {
+         mCodepointsWithNoFonts.set(aCh);
+    } else if (aCh == 0xFFFD && fontEntry) {
+        mReplacementCharFallbackFamily = fontEntry->FamilyName();
+     }
+ 
+    // track system fallback time
+    static bool first = true;
     PRInt32 intElapsed = PRInt32(first ? elapsed.ToMilliseconds() :
                                          elapsed.ToMicroseconds());
     Telemetry::Accumulate((first ? Telemetry::SYSTEM_FONT_FALLBACK_FIRST :
                                    Telemetry::SYSTEM_FONT_FALLBACK),
                           intElapsed);
     first = false;
 
-    return data.mBestMatch;
+    // track the script for which fallback occurred (incremented one make it
+    // 1-based)
+    Telemetry::Accumulate(Telemetry::SYSTEM_FONT_FALLBACK_SCRIPT, aRunScript + 1);
+
+    return fontEntry;
 }
 
 PLDHashOperator PR_CALLBACK 
 gfxPlatformFontList::FindFontForCharProc(nsStringHashKey::KeyType aKey, nsRefPtr<gfxFontFamily>& aFamilyEntry,
      void *userArg)
 {
-    FontSearch *data = static_cast<FontSearch*>(userArg);
+    GlobalFontMatch *data = static_cast<GlobalFontMatch*>(userArg);
+ 
+     // evaluate all fonts in this family for a match
+     aFamilyEntry->FindFontForChar(data);
+
+     return PL_DHASH_NEXT;
+}
+
+#define NUM_FALLBACK_FONTS        8
+
+gfxFontEntry*
+gfxPlatformFontList::CommonFontFallback(const PRUint32 aCh,
+                                        PRInt32 aRunScript,
+                                        const gfxFontStyle* aMatchStyle)
+{
+    nsAutoTArray<const char*,NUM_FALLBACK_FONTS> defaultFallbacks;
+    PRUint32 i, numFallbacks;
+
+    gfxPlatform::GetPlatform()->GetCommonFallbackFonts(aCh, aRunScript,
+                                                       defaultFallbacks);
+    numFallbacks = defaultFallbacks.Length();
+    for (i = 0; i < numFallbacks; i++) {
+        nsAutoString familyName;
+        const char *fallbackFamily = defaultFallbacks[i];
 
-    // evaluate all fonts in this family for a match
-    aFamilyEntry->FindFontForChar(data);
-    return PL_DHASH_NEXT;
+        familyName.AppendASCII(fallbackFamily);
+        gfxFontFamily *fallback =
+                gfxPlatformFontList::PlatformFontList()->FindFamily(familyName);
+        if (!fallback)
+            continue;
+
+        gfxFontEntry *fontEntry;
+        bool needsBold;  // ignored in the system fallback case
+
+        // use first font in list that supports a given character
+        fontEntry = fallback->FindFontForStyle(*aMatchStyle, needsBold);
+        if (fontEntry && fontEntry->TestCharacterMap(aCh)) {
+            return fontEntry;
+        }
+    }
+
+    return nsnull;
+}
+
+gfxFontEntry*
+gfxPlatformFontList::GlobalFontFallback(const PRUint32 aCh,
+                                        PRInt32 aRunScript,
+                                        const gfxFontStyle* aMatchStyle,
+                                        PRUint32& aCmapCount)
+{
+    // otherwise, try to find it among local fonts
+    GlobalFontMatch data(aCh, aRunScript, aMatchStyle);
+
+    // iterate over all font families to find a font that support the character
+    mFontFamilies.Enumerate(gfxPlatformFontList::FindFontForCharProc, &data);
+
+    aCmapCount = data.mCmapsTested;
+
+    return data.mBestMatch;
 }
 
 #ifdef XP_WIN
 #include <windows.h>
 
 // crude hack for using when monitoring process
 static void LogRegistryEvent(const wchar_t *msg)
 {
@@ -604,37 +665,41 @@ gfxPlatformFontList::GetStandardFamilyNa
 void 
 gfxPlatformFontList::InitLoader()
 {
     GetFontFamilyList(mFontFamiliesToLoad);
     mStartIndex = 0;
     mNumFamilies = mFontFamiliesToLoad.Length();
 }
 
-bool 
+bool
 gfxPlatformFontList::RunLoader()
 {
     PRUint32 i, endIndex = (mStartIndex + mIncrement < mNumFamilies ? mStartIndex + mIncrement : mNumFamilies);
+    bool loadCmaps = !UsesSystemFallback() ||
+        gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback();
 
     // for each font family, load in various font info
     for (i = mStartIndex; i < endIndex; i++) {
         gfxFontFamily* familyEntry = mFontFamiliesToLoad[i];
 
         // find all faces that are members of this family
         familyEntry->FindStyleVariations();
         if (familyEntry->GetFontList().Length() == 0) {
             // failed to load any faces for this family, so discard it
             nsAutoString key;
             GenerateFontListKey(familyEntry->Name(), key);
             mFontFamilies.Remove(key);
             continue;
         }
 
-        // load the cmaps
-        familyEntry->ReadCMAP();
+        // load the cmaps if needed
+        if (loadCmaps) {
+            familyEntry->ReadAllCMAPs();
+        }
 
         // read in face names
         familyEntry->ReadFaceNames(this, mNeedFullnamePostscriptNames);
 
         // check whether the family can be considered "simple" for style matching
         familyEntry->CheckForSimpleFamily();
     }
 
--- a/gfx/thebes/gfxPlatformFontList.h
+++ b/gfx/thebes/gfxPlatformFontList.h
@@ -15,16 +15,17 @@
  * The Original Code is Mozilla Corporation code.
  *
  * The Initial Developer of the Original Code is Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2008-2009
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Jonathan Kew <jfkthame@gmail.com>
+ *   John Daggett <jdaggett@mozilla.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -92,17 +93,20 @@ public:
                                    nsAString& aResolvedFontName);
 
     void UpdateFontList() { InitFontList(); }
 
     void ClearPrefFonts() { mPrefFonts.Clear(); }
 
     virtual void GetFontFamilyList(nsTArray<nsRefPtr<gfxFontFamily> >& aFamilyArray);
 
-    gfxFontEntry* FindFontForChar(const PRUint32 aCh, gfxFont *aPrevFont);
+    virtual gfxFontEntry*
+    SystemFindFontForChar(const PRUint32 aCh,
+                          PRInt32 aRunScript,
+                          const gfxFontStyle* aStyle);
 
     // TODO: make this virtual, for lazily adding to the font list
     virtual gfxFontFamily* FindFamily(const nsAString& aFamily);
 
     gfxFontEntry* FindFontForFamily(const nsAString& aFamily, const gfxFontStyle* aStyle, bool& aNeedsBold);
 
     bool GetPrefFontFamilyEntries(eFontPrefLang aLangGroup, nsTArray<nsRefPtr<gfxFontFamily> > *array);
     void SetPrefFontFamilyEntries(eFontPrefLang aLangGroup, nsTArray<nsRefPtr<gfxFontFamily> >& array);
@@ -141,16 +145,31 @@ protected:
     gfxPlatformFontList(bool aNeedFullnamePostscriptNames = true);
 
     static gfxPlatformFontList *sPlatformFontList;
 
     static PLDHashOperator FindFontForCharProc(nsStringHashKey::KeyType aKey,
                                                nsRefPtr<gfxFontFamily>& aFamilyEntry,
                                                void* userArg);
 
+    // returns default font for a given character, null otherwise
+    virtual gfxFontEntry* CommonFontFallback(const PRUint32 aCh,
+                                             PRInt32 aRunScript,
+                                             const gfxFontStyle* aMatchStyle);
+
+    // search fonts system-wide for a given character, null otherwise
+    virtual gfxFontEntry* GlobalFontFallback(const PRUint32 aCh,
+                                             PRInt32 aRunScript,
+                                             const gfxFontStyle* aMatchStyle,
+                                             PRUint32& aCmapCount);
+
+    // whether system-based font fallback is used or not
+    // if system fallback is used, no need to load all cmaps
+    virtual bool UsesSystemFallback() { return false; }
+
     // separate initialization for reading in name tables, since this is expensive
     void InitOtherFamilyNames();
 
     static PLDHashOperator InitOtherFamilyNamesProc(nsStringHashKey::KeyType aKey,
                                                     nsRefPtr<gfxFontFamily>& aFamilyEntry,
                                                     void* userArg);
 
     // read in all fullname/Postscript names for all font faces
--- a/gfx/thebes/gfxPlatformGtk.cpp
+++ b/gfx/thebes/gfxPlatformGtk.cpp
@@ -40,16 +40,17 @@
 #ifdef MOZ_PANGO
 #define PANGO_ENABLE_BACKEND
 #define PANGO_ENABLE_ENGINE
 #endif
 
 #include "gfxPlatformGtk.h"
 
 #include "nsUnicharUtils.h"
+#include "nsUnicodeProperties.h"
 #include "gfxFontconfigUtils.h"
 #ifdef MOZ_PANGO
 #include "gfxPangoFonts.h"
 #include "gfxContext.h"
 #include "gfxUserFontSet.h"
 #else
 #include <ft2build.h>
 #include FT_FREETYPE_H
@@ -77,16 +78,17 @@
 #include <fontconfig/fontconfig.h>
 
 #include "nsMathUtils.h"
 
 #define GDK_PIXMAP_SIZE_MAX 32767
 
 using namespace mozilla;
 using namespace mozilla::gfx;
+using namespace mozilla::unicode;
 
 gfxFontconfigUtils *gfxPlatformGtk::sFontconfigUtils = nsnull;
 
 #ifndef MOZ_PANGO
 typedef nsDataHashtable<nsStringHashKey, nsRefPtr<FontFamily> > FontTable;
 typedef nsDataHashtable<nsCStringHashKey, nsTArray<nsRefPtr<gfxFontEntry> > > PrefFontTable;
 static FontTable *gPlatformFonts = NULL;
 static FontTable *gPlatformFontAliases = NULL;
@@ -663,33 +665,34 @@ gfxPlatformGtk::FindFontEntry(const nsAS
     return ff->FindFontEntry(aFontStyle);
 }
 
 static PLDHashOperator
 FindFontForCharProc(nsStringHashKey::KeyType aKey,
                     nsRefPtr<FontFamily>& aFontFamily,
                     void* aUserArg)
 {
-    FontSearch *data = (FontSearch*)aUserArg;
+    GlobalFontMatch *data = (GlobalFontMatch*)aUserArg;
     aFontFamily->FindFontForChar(data);
     return PL_DHASH_NEXT;
 }
 
 already_AddRefed<gfxFont>
 gfxPlatformGtk::FindFontForChar(PRUint32 aCh, gfxFont *aFont)
 {
     if (!gPlatformFonts || !gCodepointsWithNoFonts)
         return nsnull;
 
     // is codepoint with no matching font? return null immediately
     if (gCodepointsWithNoFonts->test(aCh)) {
         return nsnull;
     }
 
-    FontSearch data(aCh, aFont);
+    GlobalFontMatch data(aCh, GetScriptCode(aCh),
+                         (aFont ? aFont->GetStyle() : nsnull));
 
     // find fonts that support the character
     gPlatformFonts->Enumerate(FindFontForCharProc, &data);
 
     if (data.mBestMatch) {
         nsRefPtr<gfxFT2Font> font =
             gfxFT2Font::GetOrMakeFont(static_cast<FontEntry*>(data.mBestMatch.get()),
                                       aFont->GetStyle()); 
--- a/gfx/thebes/gfxPlatformMac.cpp
+++ b/gfx/thebes/gfxPlatformMac.cpp
@@ -258,16 +258,118 @@ gfxPlatformMac::GetFontList(nsIAtom *aLa
 
 nsresult
 gfxPlatformMac::UpdateFontList()
 {
     gfxPlatformFontList::PlatformFontList()->UpdateFontList();
     return NS_OK;
 }
 
+static const char kFontArialUnicodeMS[] = "Arial Unicode MS";
+static const char kFontAppleBraille[] = "Apple Braille";
+static const char kFontAppleSymbols[] = "Apple Symbols";
+static const char kFontAppleMyungjo[] = "AppleMyungjo";
+static const char kFontGeneva[] = "Geneva";
+static const char kFontGeezaPro[] = "Geeza Pro";
+static const char kFontHiraginoKakuGothic[] = "Hiragino Kaku Gothic ProN";
+static const char kFontLucidaGrande[] = "Lucida Grande";
+static const char kFontMenlo[] = "Menlo";
+static const char kFontPlantagenetCherokee[] = "Plantagenet Cherokee";
+static const char kFontSTHeiti[] = "STHeiti";
+
+void
+gfxPlatformMac::GetCommonFallbackFonts(const PRUint32 aCh,
+                                       PRInt32 aRunScript,
+                                       nsTArray<const char*>& aFontList)
+{
+    aFontList.AppendElement(kFontLucidaGrande);
+
+    if (!IS_IN_BMP(aCh)) {
+        PRUint32 p = aCh >> 16;
+        if (p == 1) {
+            aFontList.AppendElement(kFontAppleSymbols);
+            aFontList.AppendElement(kFontGeneva);
+        }
+    } else {
+        PRUint32 b = (aCh >> 8) & 0xff;
+
+        switch (b) {
+        case 0x03:
+        case 0x05:
+            aFontList.AppendElement(kFontGeneva);
+            break;
+        case 0x07:
+            aFontList.AppendElement(kFontGeezaPro);
+            break;
+        case 0x10:
+            aFontList.AppendElement(kFontMenlo);
+            break;
+        case 0x13:  // Cherokee
+            aFontList.AppendElement(kFontPlantagenetCherokee);
+            break;
+        case 0x18:  // Mongolian
+            aFontList.AppendElement(kFontSTHeiti);
+            break;
+        case 0x1d:
+        case 0x1e:
+            aFontList.AppendElement(kFontGeneva);
+            break;
+        case 0x20:  // Symbol ranges
+        case 0x21:
+        case 0x22:
+        case 0x23:
+        case 0x24:
+        case 0x25:
+        case 0x26:
+        case 0x27:
+        case 0x29:
+        case 0x2a:
+        case 0x2b:
+        case 0x2e:
+            aFontList.AppendElement(kFontAppleSymbols);
+            aFontList.AppendElement(kFontMenlo);
+            aFontList.AppendElement(kFontGeneva);
+            aFontList.AppendElement(kFontHiraginoKakuGothic);
+            break;
+        case 0x2c:
+        case 0x2d:
+            aFontList.AppendElement(kFontGeneva);
+            break;
+        case 0x28:  // Braille
+            aFontList.AppendElement(kFontAppleBraille);
+            break;
+        case 0x4d:
+            aFontList.AppendElement(kFontAppleSymbols);
+            break;
+        case 0xa0:  // Yi
+        case 0xa1:
+        case 0xa2:
+        case 0xa3:
+        case 0xa4:
+            aFontList.AppendElement(kFontSTHeiti);
+            break;
+        case 0xa6:
+        case 0xa7:
+            aFontList.AppendElement(kFontGeneva);
+            aFontList.AppendElement(kFontAppleSymbols);
+            break;
+        case 0xfc:
+        case 0xff:
+            aFontList.AppendElement(kFontAppleSymbols);
+            break;
+        default:
+            break;
+        }
+    }
+
+    // Arial Unicode MS has lots of glyphs for obscure, use it as a last resort
+    aFontList.AppendElement(kFontArialUnicodeMS);
+}
+
+
 PRInt32 
 gfxPlatformMac::OSXVersion()
 {
     if (!mOSXVersion) {
         // minor version is not accurate, use gestaltSystemVersionMajor, gestaltSystemVersionMinor, gestaltSystemVersionBugFix for these
         OSErr err = ::Gestalt(gestaltSystemVersion, reinterpret_cast<SInt32*>(&mOSXVersion));
         if (err != noErr) {
             //This should probably be changed when our minimum version changes
--- a/gfx/thebes/gfxPlatformMac.h
+++ b/gfx/thebes/gfxPlatformMac.h
@@ -45,16 +45,17 @@
 #define MAC_OS_X_VERSION_10_4_HEX 0x00001040
 #define MAC_OS_X_VERSION_10_5_HEX 0x00001050
 #define MAC_OS_X_VERSION_10_6_HEX 0x00001060
 #define MAC_OS_X_VERSION_10_7_HEX 0x00001070
 
 #define MAC_OS_X_MAJOR_VERSION_MASK 0xFFFFFFF0U
 
 class gfxTextRun;
+class gfxFontFamily;
 class mozilla::gfx::DrawTarget;
 
 class THEBES_API gfxPlatformMac : public gfxPlatform {
 public:
     gfxPlatformMac();
     virtual ~gfxPlatformMac();
 
     static gfxPlatformMac *GetPlatform() {
@@ -93,16 +94,20 @@ public:
 
     bool IsFontFormatSupported(nsIURI *aFontURI, PRUint32 aFormatFlags);
 
     nsresult GetFontList(nsIAtom *aLangGroup,
                          const nsACString& aGenericFamily,
                          nsTArray<nsString>& aListOfFonts);
     nsresult UpdateFontList();
 
+    virtual void GetCommonFallbackFonts(const PRUint32 aCh,
+                                        PRInt32 aRunScript,
+                                        nsTArray<const char*>& aFontList);
+
     // Returns the OS X version as returned from Gestalt(gestaltSystemVersion, ...)
     // Ex: Mac OS X 10.4.x ==> 0x104x 
     PRInt32 OSXVersion();
 
     // lower threshold on font anti-aliasing
     PRUint32 GetAntiAliasingThreshold() { return mFontAntiAliasingThreshold; }
 
     virtual already_AddRefed<gfxASurface>
--- a/gfx/thebes/gfxQtPlatform.cpp
+++ b/gfx/thebes/gfxQtPlatform.cpp
@@ -45,16 +45,17 @@
 #include "gfxQtPlatform.h"
 
 #include "gfxFontconfigUtils.h"
 
 #include "cairo.h"
 
 #include "gfxImageSurface.h"
 #include "gfxQPainterSurface.h"
+#include "nsUnicodeProperties.h"
 
 #ifdef MOZ_PANGO
 #include "gfxPangoFonts.h"
 #include "gfxContext.h"
 #include "gfxUserFontSet.h"
 #else
 #include "gfxFT2Fonts.h"
 #endif
@@ -74,16 +75,17 @@
 #ifndef MOZ_PANGO
 #include <ft2build.h>
 #include FT_FREETYPE_H
 #endif
 
 #include "mozilla/Preferences.h"
 
 using namespace mozilla;
+using namespace mozilla::unicode;
 
 #define DEFAULT_RENDER_MODE RENDER_DIRECT
 
 static QPaintEngine::Type sDefaultQtPaintEngineType = QPaintEngine::Raster;
 gfxFontconfigUtils *gfxQtPlatform::sFontconfigUtils = nsnull;
 static cairo_user_data_key_t cairo_qt_pixmap_key;
 static void do_qt_pixmap_unref (void *data)
 {
@@ -521,33 +523,34 @@ gfxQtPlatform::FindFontEntry(const nsASt
     return ff->FindFontEntry(aFontStyle);
 }
 
 static PLDHashOperator
 FindFontForCharProc(nsStringHashKey::KeyType aKey,
                     nsRefPtr<FontFamily>& aFontFamily,
                     void* aUserArg)
 {
-    FontSearch *data = (FontSearch*)aUserArg;
+    GlobalFontMatch *data = (GlobalFontMatch*)aUserArg;
     aFontFamily->FindFontForChar(data);
     return PL_DHASH_NEXT;
 }
 
 already_AddRefed<gfxFont>
 gfxQtPlatform::FindFontForChar(PRUint32 aCh, gfxFont *aFont)
 {
     if (!gPlatformFonts || !gCodepointsWithNoFonts)
         return nsnull;
 
     // is codepoint with no matching font? return null immediately
     if (gCodepointsWithNoFonts->test(aCh)) {
         return nsnull;
     }
 
-    FontSearch data(aCh, aFont);
+    GlobalFontMatch data(aCh, GetScriptCode(aCh),
+                         (aFont ? aFont->GetStyle() : nsnull));
 
     // find fonts that support the character
     gPlatformFonts->Enumerate(FindFontForCharProc, &data);
 
     if (data.mBestMatch) {
         nsRefPtr<gfxFT2Font> font =
             gfxFT2Font::GetOrMakeFont(static_cast<FontEntry*>(data.mBestMatch.get()),
                                       aFont->GetStyle()); 
--- a/gfx/thebes/gfxUserFontSet.cpp
+++ b/gfx/thebes/gfxUserFontSet.cpp
@@ -397,43 +397,44 @@ StoreUserFontData(gfxFontEntry* aFontEnt
     userFontData->mFormat = src.mFormatFlags;
     userFontData->mRealName = aOriginalName;
     if (aMetadata) {
         userFontData->mMetadata.SwapElements(*aMetadata);
         userFontData->mMetaOrigLen = aMetaOrigLen;
     }
 }
 
+struct WOFFHeader {
+    AutoSwap_PRUint32 signature;
+    AutoSwap_PRUint32 flavor;
+    AutoSwap_PRUint32 length;
+    AutoSwap_PRUint16 numTables;
+    AutoSwap_PRUint16 reserved;
+    AutoSwap_PRUint32 totalSfntSize;
+    AutoSwap_PRUint16 majorVersion;
+    AutoSwap_PRUint16 minorVersion;
+    AutoSwap_PRUint32 metaOffset;
+    AutoSwap_PRUint32 metaCompLen;
+    AutoSwap_PRUint32 metaOrigLen;
+    AutoSwap_PRUint32 privOffset;
+    AutoSwap_PRUint32 privLen;
+};
+
 void
 gfxUserFontSet::CopyWOFFMetadata(const PRUint8* aFontData,
                                  PRUint32 aLength,
                                  nsTArray<PRUint8>* aMetadata,
                                  PRUint32* aMetaOrigLen)
 {
     // This function may be called with arbitrary, unvalidated "font" data
     // from @font-face, so it needs to be careful to bounds-check, etc.,
     // before trying to read anything.
     // This just saves a copy of the compressed data block; it does NOT check
     // that the block can be successfully decompressed, or that it contains
     // well-formed/valid XML metadata.
-    struct WOFFHeader {
-        AutoSwap_PRUint32 signature;
-        AutoSwap_PRUint32 flavor;
-        AutoSwap_PRUint32 length;
-        AutoSwap_PRUint16 numTables;
-        AutoSwap_PRUint16 reserved;
-        AutoSwap_PRUint32 totalSfntSize;
-        AutoSwap_PRUint16 majorVersion;
-        AutoSwap_PRUint16 minorVersion;
-        AutoSwap_PRUint32 metaOffset;
-        AutoSwap_PRUint32 metaCompLen;
-        AutoSwap_PRUint32 metaOrigLen;
-        AutoSwap_PRUint32 privOffset;
-        AutoSwap_PRUint32 privLen;
-    };
     if (aLength < sizeof(WOFFHeader)) {
         return;
     }
     const WOFFHeader* woff = reinterpret_cast<const WOFFHeader*>(aFontData);
     PRUint32 metaOffset = woff->metaOffset;
     PRUint32 metaCompLen = woff->metaCompLen;
     if (!metaOffset || !metaCompLen || !woff->metaOrigLen) {
         return;
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -823,16 +823,185 @@ RemoveCharsetFromFontSubstitute(nsAStrin
 nsresult
 gfxWindowsPlatform::UpdateFontList()
 {
     gfxPlatformFontList::PlatformFontList()->UpdateFontList();
 
     return NS_OK;
 }
 
+static const char kFontArabicTypesetting[] = "Arabic Typesetting";
+static const char kFontArial[] = "Arial";
+static const char kFontArialUnicodeMS[] = "Arial Unicode MS";
+static const char kFontCambria[] = "Cambria";
+static const char kFontCambriaMath[] = "Cambria Math";
+static const char kFontEbrima[] = "Ebrima";
+static const char kFontEstrangeloEdessa[] = "Estrangelo Edessa";
+static const char kFontEuphemia[] = "Euphemia";
+static const char kFontGabriola[] = "Gabriola";
+static const char kFontKhmerUI[] = "Khmer UI";
+static const char kFontLaoUI[] = "Lao UI";
+static const char kFontMVBoli[] = "MV Boli";
+static const char kFontMalgunGothic[] = "Malgun Gothic";
+static const char kFontMicrosoftJhengHei[] = "Microsoft JhengHei";
+static const char kFontMicrosoftNewTaiLue[] = "Microsoft New Tai Lue";
+static const char kFontMicrosoftPhagsPa[] = "Microsoft PhagsPa";
+static const char kFontMicrosoftTaiLe[] = "Microsoft Tai Le";
+static const char kFontMicrosoftUighur[] = "Microsoft Uighur";
+static const char kFontMicrosoftYaHei[] = "Microsoft YaHei";
+static const char kFontMicrosoftYiBaiti[] = "Microsoft Yi Baiti";
+static const char kFontMeiryo[] = "Meiryo";
+static const char kFontMongolianBaiti[] = "Mongolian Baiti";
+static const char kFontNyala[] = "Nyala";
+static const char kFontPlantagenetCherokee[] = "Plantagenet Cherokee";
+static const char kFontSegoeUI[] = "Segoe UI";
+static const char kFontSegoeUISymbol[] = "Segoe UI Symbol";
+static const char kFontSylfaen[] = "Sylfaen";
+static const char kFontTraditionalArabic[] = "Traditional Arabic";
+
+void
+gfxWindowsPlatform::GetCommonFallbackFonts(const PRUint32 aCh,
+                                           PRInt32 aRunScript,
+                                           nsTArray<const char*>& aFontList)
+{
+    // Arial is used as the default fallback for system fallback
+    aFontList.AppendElement(kFontArial);
+
+    if (!IS_IN_BMP(aCh)) {
+        PRUint32 p = aCh >> 16;
+        if (p == 1) { // SMP plane
+            aFontList.AppendElement(kFontCambriaMath);
+            aFontList.AppendElement(kFontSegoeUISymbol);
+            aFontList.AppendElement(kFontEbrima);
+        }
+    } else {
+        PRUint32 b = (aCh >> 8) & 0xff;
+
+        switch (b) {
+        case 0x05:
+            aFontList.AppendElement(kFontEstrangeloEdessa);
+            aFontList.AppendElement(kFontCambria);
+            break;
+        case 0x06:
+            aFontList.AppendElement(kFontMicrosoftUighur);
+            break;
+        case 0x07:
+            aFontList.AppendElement(kFontEstrangeloEdessa);
+            aFontList.AppendElement(kFontMVBoli);
+            aFontList.AppendElement(kFontEbrima);
+            break;
+        case 0x0e:
+            aFontList.AppendElement(kFontLaoUI);
+            break;
+        case 0x12:
+        case 0x13:
+            aFontList.AppendElement(kFontNyala);
+            aFontList.AppendElement(kFontPlantagenetCherokee);
+            break;
+        case 0x14:
+        case 0x15:
+        case 0x16:
+            aFontList.AppendElement(kFontEuphemia);
+            aFontList.AppendElement(kFontSegoeUISymbol);
+            break;
+        case 0x17:
+            aFontList.AppendElement(kFontKhmerUI);
+            break;
+        case 0x18:  // Mongolian
+            aFontList.AppendElement(kFontMongolianBaiti);
+            break;
+        case 0x19:
+            aFontList.AppendElement(kFontMicrosoftTaiLe);
+            aFontList.AppendElement(kFontMicrosoftNewTaiLue);
+            aFontList.AppendElement(kFontKhmerUI);
+            break;
+            break;
+        case 0x20:  // Symbol ranges
+        case 0x21:
+        case 0x22:
+        case 0x23:
+        case 0x24:
+        case 0x25:
+        case 0x26:
+        case 0x27:
+        case 0x29:
+        case 0x2a:
+        case 0x2b:
+        case 0x2c:
+            aFontList.AppendElement(kFontSegoeUI);
+            aFontList.AppendElement(kFontSegoeUISymbol);
+            aFontList.AppendElement(kFontCambria);
+            aFontList.AppendElement(kFontCambriaMath);
+            aFontList.AppendElement(kFontMeiryo);
+            aFontList.AppendElement(kFontArial);
+            aFontList.AppendElement(kFontEbrima);
+            break;
+        case 0x2d:
+        case 0x2e:
+        case 0x2f:
+            aFontList.AppendElement(kFontEbrima);
+            aFontList.AppendElement(kFontNyala);
+            aFontList.AppendElement(kFontMeiryo);
+            break;
+        case 0x28:  // Braille
+            aFontList.AppendElement(kFontSegoeUISymbol);
+            break;
+        case 0x30:
+        case 0x31:
+            aFontList.AppendElement(kFontMicrosoftYaHei);
+            break;
+        case 0x32:
+            aFontList.AppendElement(kFontMalgunGothic);
+            break;
+        case 0x4d:
+            aFontList.AppendElement(kFontSegoeUISymbol);
+            break;
+        case 0xa0:  // Yi
+        case 0xa1:
+        case 0xa2:
+        case 0xa3:
+        case 0xa4:
+            aFontList.AppendElement(kFontMicrosoftYiBaiti);
+            break;
+        case 0xa5:
+        case 0xa6:
+        case 0xa7:
+            aFontList.AppendElement(kFontEbrima);
+            aFontList.AppendElement(kFontCambriaMath);
+            break;
+        case 0xa8:
+             aFontList.AppendElement(kFontMicrosoftPhagsPa);
+             break;
+        case 0xfb:
+            aFontList.AppendElement(kFontMicrosoftUighur);
+            aFontList.AppendElement(kFontGabriola);
+            aFontList.AppendElement(kFontSylfaen);
+            break;
+        case 0xfc:
+        case 0xfd:
+            aFontList.AppendElement(kFontTraditionalArabic);
+            aFontList.AppendElement(kFontArabicTypesetting);
+            break;
+        case 0xfe:
+            aFontList.AppendElement(kFontTraditionalArabic);
+            aFontList.AppendElement(kFontMicrosoftJhengHei);
+           break;
+       case 0xff:
+            aFontList.AppendElement(kFontMicrosoftJhengHei);
+            break;
+        default:
+            break;
+        }
+    }
+
+    // Arial Unicode MS has lots of glyphs for obscure characters,
+    // use it as a last resort
+    aFontList.AppendElement(kFontArialUnicodeMS);
+}
+
 struct ResolveData {
     ResolveData(gfxPlatform::FontResolverCallback aCallback,
                 gfxWindowsPlatform *aCaller, const nsAString *aFontName,
                 void *aClosure) :
         mFoundCount(0), mCallback(aCallback), mCaller(aCaller),
         mFontName(aFontName), mClosure(aClosure) {}
     PRUint32 mFoundCount;
     gfxPlatform::FontResolverCallback mCallback;
--- a/gfx/thebes/gfxWindowsPlatform.h
+++ b/gfx/thebes/gfxWindowsPlatform.h
@@ -174,16 +174,20 @@ public:
     HDC GetScreenDC() { return mScreenDC; }
 
     nsresult GetFontList(nsIAtom *aLangGroup,
                          const nsACString& aGenericFamily,
                          nsTArray<nsString>& aListOfFonts);
 
     nsresult UpdateFontList();
 
+    virtual void GetCommonFallbackFonts(const PRUint32 aCh,
+                                        PRInt32 aRunScript,
+                                        nsTArray<const char*>& aFontList);
+
     nsresult ResolveFontName(const nsAString& aFontName,
                              FontResolverCallback aCallback,
                              void *aClosure, bool& aAborted);
 
     nsresult GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName);
 
     gfxFontGroup *CreateFontGroup(const nsAString &aFamilies,
                                   const gfxFontStyle *aStyle,
--- a/gfx/thebes/nsUnicodeRange.cpp
+++ b/gfx/thebes/nsUnicodeRange.cpp
@@ -208,17 +208,17 @@ static nsIAtom **gUnicodeRangeToLangGrou
  * Misc - small form variants
  *  fe50 - fe6f
  * Misc - Specials
  *  fff0 - ffff
  *********************************************************************/
 
 
 
-#define NUM_OF_SUBTABLES      9
+#define NUM_OF_SUBTABLES      10
 #define SUBTABLE_SIZE         16
 
 static const PRUint8 gUnicodeSubrangeTable[NUM_OF_SUBTABLES][SUBTABLE_SIZE] = 
 { 
   { // table for X---
     kRangeTableBase+1,  //u0xxx
     kRangeTableBase+2,  //u1xxx
     kRangeTableBase+3,  //u2xxx
@@ -247,17 +247,17 @@ static const PRUint8 gUnicodeSubrangeTab
     kRangeTertiaryTable,     //u07xx
     kRangeUnassigned,        //u08xx
     kRangeTertiaryTable,     //u09xx
     kRangeTertiaryTable,     //u0axx
     kRangeTertiaryTable,     //u0bxx
     kRangeTertiaryTable,     //u0cxx
     kRangeTertiaryTable,     //u0dxx
     kRangeTertiaryTable,     //u0exx
-    kRangeTibetan,           //u0fxx
+    kRangeTibetan            //u0fxx
   },
   { //table for 1x--
     kRangeTertiaryTable,     //u10xx
     kRangeKorean,            //u11xx
     kRangeEthiopic,          //u12xx
     kRangeTertiaryTable,     //u13xx
     kRangeCanadian,          //u14xx
     kRangeCanadian,          //u15xx
@@ -265,17 +265,17 @@ static const PRUint8 gUnicodeSubrangeTab
     kRangeKhmer,             //u17xx
     kRangeMongolian,         //u18xx
     kRangeUnassigned,        //u19xx
     kRangeUnassigned,        //u1axx
     kRangeUnassigned,        //u1bxx
     kRangeUnassigned,        //u1cxx
     kRangeUnassigned,        //u1dxx
     kRangeSetLatin,          //u1exx
-    kRangeGreek,             //u1fxx
+    kRangeGreek              //u1fxx
   },
   { //table for 2x--
     kRangeSetLatin,          //u20xx
     kRangeSetLatin,          //u21xx
     kRangeMathOperators,     //u22xx
     kRangeMiscTechnical,     //u23xx
     kRangeControlOpticalEnclose, //u24xx
     kRangeBoxBlockGeometrics, //u25xx
@@ -283,17 +283,17 @@ static const PRUint8 gUnicodeSubrangeTab
     kRangeDingbats,          //u27xx
     kRangeBraillePattern,    //u28xx
     kRangeUnassigned,        //u29xx
     kRangeUnassigned,        //u2axx
     kRangeUnassigned,        //u2bxx
     kRangeUnassigned,        //u2cxx
     kRangeUnassigned,        //u2dxx
     kRangeSetCJK,            //u2exx
-    kRangeSetCJK,            //u2fxx
+    kRangeSetCJK             //u2fxx
   },
   {  //table for ax--
     kRangeYi,                //ua0xx
     kRangeYi,                //ua1xx
     kRangeYi,                //ua2xx
     kRangeYi,                //ua3xx
     kRangeYi,                //ua4xx
     kRangeUnassigned,        //ua5xx
@@ -301,17 +301,17 @@ static const PRUint8 gUnicodeSubrangeTab
     kRangeUnassigned,        //ua7xx
     kRangeUnassigned,        //ua8xx
     kRangeUnassigned,        //ua9xx
     kRangeUnassigned,        //uaaxx
     kRangeUnassigned,        //uabxx
     kRangeKorean,            //uacxx
     kRangeKorean,            //uadxx
     kRangeKorean,            //uaexx
-    kRangeKorean,            //uafxx
+    kRangeKorean             //uafxx
   },
   {  //table for dx--
     kRangeKorean,            //ud0xx
     kRangeKorean,            //ud1xx
     kRangeKorean,            //ud2xx
     kRangeKorean,            //ud3xx
     kRangeKorean,            //ud4xx
     kRangeKorean,            //ud5xx
@@ -319,38 +319,35 @@ static const PRUint8 gUnicodeSubrangeTab
     kRangeKorean,            //ud7xx
     kRangeSurrogate,         //ud8xx
     kRangeSurrogate,         //ud9xx
     kRangeSurrogate,         //udaxx
     kRangeSurrogate,         //udbxx
     kRangeSurrogate,         //udcxx
     kRangeSurrogate,         //uddxx
     kRangeSurrogate,         //udexx
-    kRangeSurrogate,         //udfxx
+    kRangeSurrogate          //udfxx
   },
   { // table for fx--
     kRangePrivate,           //uf0xx 
     kRangePrivate,           //uf1xx 
     kRangePrivate,           //uf2xx 
     kRangePrivate,           //uf3xx 
     kRangePrivate,           //uf4xx 
     kRangePrivate,           //uf5xx 
     kRangePrivate,           //uf6xx 
     kRangePrivate,           //uf7xx 
     kRangePrivate,           //uf8xx 
     kRangeSetCJK,            //uf9xx 
     kRangeSetCJK,            //ufaxx 
     kRangeArabic,            //ufbxx, includes alphabic presentation form
     kRangeArabic,            //ufcxx
     kRangeArabic,            //ufdxx
-    kRangeArabic,            //ufexx, includes Combining half marks, 
-                             //                CJK compatibility forms, 
-                             //                CJK compatibility forms, 
-                             //                small form variants
-    kRangeTableBase+8,       //uffxx, halfwidth and fullwidth forms, includes Specials
+    kRangeTableBase+8,       //ufexx
+    kRangeTableBase+9        //uffxx, halfwidth and fullwidth forms, includes Specials
   },
   { //table for 0x0500 - 0x05ff
     kRangeCyrillic,          //u050x
     kRangeCyrillic,          //u051x
     kRangeCyrillic,          //u052x
     kRangeArmenian,          //u053x
     kRangeArmenian,          //u054x
     kRangeArmenian,          //u055x
@@ -358,17 +355,35 @@ static const PRUint8 gUnicodeSubrangeTab
     kRangeArmenian,          //u057x
     kRangeArmenian,          //u058x
     kRangeHebrew,            //u059x
     kRangeHebrew,            //u05ax
     kRangeHebrew,            //u05bx
     kRangeHebrew,            //u05cx
     kRangeHebrew,            //u05dx
     kRangeHebrew,            //u05ex
-    kRangeHebrew,            //u05fx
+    kRangeHebrew             //u05fx
+  },
+  { //table for 0xfe00 - 0xfeff
+    kRangeSetCJK,            //ufe0x
+    kRangeSetCJK,            //ufe1x
+    kRangeSetCJK,            //ufe2x
+    kRangeSetCJK,            //ufe3x
+    kRangeSetCJK,            //ufe4x
+    kRangeSetCJK,            //ufe5x
+    kRangeSetCJK,            //ufe6x
+    kRangeArabic,            //ufe7x
+    kRangeArabic,            //ufe8x
+    kRangeArabic,            //ufe9x
+    kRangeArabic,            //ufeax
+    kRangeArabic,            //ufebx
+    kRangeArabic,            //ufecx
+    kRangeArabic,            //ufedx
+    kRangeArabic,            //ufeex
+    kRangeArabic             //ufefx
   },
   { //table for 0xff00 - 0xffff
     kRangeSetCJK,            //uff0x, fullwidth latin
     kRangeSetCJK,            //uff1x, fullwidth latin
     kRangeSetCJK,            //uff2x, fullwidth latin
     kRangeSetCJK,            //uff3x, fullwidth latin
     kRangeSetCJK,            //uff4x, fullwidth latin
     kRangeSetCJK,            //uff5x, fullwidth latin
@@ -420,39 +435,52 @@ static const PRUint8 gUnicodeTertiaryRan
     kRangeEthiopic,          //u128x  place holder(resolved in the 2ndary tab.)
     kRangeEthiopic,          //u130x  
     kRangeCherokee,          //u138x
     kRangeCanadian,          //u140x  place holder(resolved in the 2ndary tab.)
     kRangeCanadian,          //u148x  place holder(resolved in the 2ndary tab.)
     kRangeCanadian,          //u150x  place holder(resolved in the 2ndary tab.)
     kRangeCanadian,          //u158x  place holder(resolved in the 2ndary tab.)
     kRangeCanadian,          //u160x  
-    kRangeOghamRunic,        //u168x  this contains two scripts, Ogham & Runic
+    kRangeOghamRunic         //u168x  this contains two scripts, Ogham & Runic
 };
 
 // A two level index is almost enough for locating a range, with the 
 // exception of u03xx and u05xx. Since we don't really care about range for
 // combining diacritical marks in our font application, they are 
 // not discriminated further. But future adoption of this module for other use 
 // should be aware of this limitation. The implementation can be extended if 
 // there is such a need.
 // For Indic, Southeast Asian scripts and some other scripts between
 // U+0700 and U+16FF, it's extended to the third level.
-PRUint32 FindCharUnicodeRange(PRUnichar ch)
+PRUint32 FindCharUnicodeRange(PRUint32 ch)
 {
   PRUint32 range;
+  
+  // aggregate ranges for non-BMP codepoints
+  if (ch > 0xFFFF) {
+    PRUint32 p = (ch >> 16);
+    if (p == 1) {
+        return kRangeSMP;
+    } else if (p == 2) {
+        return kRangeSetCJK;
+    }
+    return kRangeHigherPlanes;
+  }
 
-  //search the first table
+  // lookup explicit range for BMP codepoints
+  // first general range
   range = gUnicodeSubrangeTable[0][ch >> 12];
   
+  // if general range is good enough, return that
   if (range < kRangeTableBase)
     // we try to get a specific range 
     return range;
 
-  // otherwise, we have one more table to look at
+  // otherwise, use subrange tables
   range = gUnicodeSubrangeTable[range - kRangeTableBase][(ch & 0x0f00) >> 8];
   if (range < kRangeTableBase)
     return range;
   if (range < kRangeTertiaryTable)
     return gUnicodeSubrangeTable[range - kRangeTableBase][(ch & 0x00f0) >> 4];
 
   // Yet another table to look at : U+0700 - U+16FF : 128 code point blocks
   return gUnicodeTertiaryRangeTable[(ch - 0x0700) >> 7];
--- a/gfx/thebes/nsUnicodeRange.h
+++ b/gfx/thebes/nsUnicodeRange.h
@@ -103,17 +103,21 @@ const PRUint8   kRangeControlOpticalEncl
 const PRUint8   kRangeBoxBlockGeometrics   = 46;
 const PRUint8   kRangeMiscSymbols          = 47;
 const PRUint8   kRangeDingbats             = 48;
 const PRUint8   kRangeBraillePattern       = 49;
 const PRUint8   kRangeYi                   = 50;
 const PRUint8   kRangeCombiningDiacriticalMarks = 51;
 const PRUint8   kRangeSpecials             = 52;
 
+// aggregate ranges for non-BMP codepoints (u+2xxxx are all CJK)
+const PRUint8   kRangeSMP                  = 53;  // u+1xxxx
+const PRUint8   kRangeHigherPlanes         = 54;  // u+3xxxx and above
+
 const PRUint8   kRangeTableBase   = 128;    //values over 127 are reserved for internal use only
 const PRUint8   kRangeTertiaryTable  = 145; // leave room for 16 subtable 
                                             // indices (kRangeTableBase + 1 ..
                                             // kRangeTableBase + 16)
 
 
 
-PRUint32 FindCharUnicodeRange(PRUnichar ch);
+PRUint32 FindCharUnicodeRange(PRUint32 ch);
 nsIAtom* LangGroupFromUnicodeRange(PRUint8 unicodeRange);
--- a/image/src/RasterImage.cpp
+++ b/image/src/RasterImage.cpp
@@ -2576,16 +2576,26 @@ RasterImage::Draw(gfxContext *aContext,
   if (mFrameDecodeFlags != DECODE_FLAGS_DEFAULT) {
     if (!CanForciblyDiscard())
       return NS_ERROR_NOT_AVAILABLE;
     ForceDiscard();
 
     mFrameDecodeFlags = DECODE_FLAGS_DEFAULT;
   }
 
+  // If this image is a candidate for discarding, reset its position in the
+  // discard tracker so we're less likely to discard it right away.
+  //
+  // (We don't normally draw unlocked images, so this conditition will usually
+  // be false.  But we will draw unlocked images if image locking is globally
+  // disabled via the content.image.allow_locking pref.)
+  if (DiscardingActive()) {
+    DiscardTracker::Reset(&mDiscardTrackerNode);
+  }
+
   // We use !mDecoded && mHasSourceData to mean discarded.
   if (!mDecoded && mHasSourceData) {
       mDrawStartTime = TimeStamp::Now();
 
       // We're drawing this image, so indicate that we should decode it as soon
       // as possible.
       DecodeWorker::Singleton()->MarkAsASAP(this);
   }
--- a/image/test/reftest/reftest.list
+++ b/image/test/reftest/reftest.list
@@ -1,10 +1,10 @@
 # Check for 24-bit color mode (test for bug 414720)
-== colordepth.html about:blank
+skip-if(Android) == colordepth.html about:blank
 
 # "PngSuite, the official set of PNG test images"
 # Images by Willem van Schaik
 #
 # http://www.schaik.com/pngsuite/pngsuite.html
 # http://www.libpng.org/pub/png/pngsuite.html
 include pngsuite-basic-n/reftest.list
 include pngsuite-basic-i/reftest.list
--- a/js/src/aclocal.m4
+++ b/js/src/aclocal.m4
@@ -10,10 +10,11 @@ builtin(include, build/autoconf/moznbyte
 builtin(include, build/autoconf/mozprog.m4)dnl
 builtin(include, build/autoconf/mozheader.m4)dnl
 builtin(include, build/autoconf/mozcommonheader.m4)dnl
 builtin(include, build/autoconf/acwinpaths.m4)dnl
 builtin(include, build/autoconf/lto.m4)dnl
 builtin(include, build/autoconf/gcc-pr49911.m4)dnl
 builtin(include, build/autoconf/frameptr.m4)dnl
 builtin(include, build/autoconf/compiler-opts.m4)dnl
+builtin(include, build/autoconf/expandlibs.m4)dnl
 
 MOZ_PROG_CHECKMSYS()
copy from build/unix/check_debug_ranges.py
copy to js/src/build/autoconf/check_debug_ranges.py
--- a/js/src/build/autoconf/compiler-opts.m4
+++ b/js/src/build/autoconf/compiler-opts.m4
@@ -4,10 +4,81 @@ AC_DEFUN([MOZ_COMPILER_OPTS],
 [
 if test "$CLANG_CXX"; then
     ## We disable return-type-c-linkage because jsval is defined as a C++ type but is
     ## returned by C functions. This is possible because we use knowledge about the ABI
     ## to typedef it to a C type with the same layout when the headers are included
     ## from C.
     _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wno-unknown-warning-option -Wno-return-type-c-linkage"
 fi
+
+if test "$GNU_CC"; then
+    CFLAGS="$CFLAGS -ffunction-sections -fdata-sections"
+    CXXFLAGS="$CXXFLAGS -ffunction-sections -fdata-sections"
+fi
+
+dnl ========================================================
+dnl = Identical Code Folding
+dnl ========================================================
+
+MOZ_ARG_DISABLE_BOOL(icf,
+[  --disable-icf          Disable Identical Code Folding],
+    MOZ_DISABLE_ICF=1,
+    MOZ_DISABLE_ICF= )
+
+if test "$GNU_CC" -a "$GCC_USE_GNU_LD" -a -z "$MOZ_DISABLE_ICF"; then
+    AC_CACHE_CHECK([whether the linker supports Identical Code Folding],
+        LD_SUPPORTS_ICF,
+        [echo 'int foo() {return 42;}' \
+              'int bar() {return 42;}' \
+              'int main() {return foo() - bar();}' > conftest.${ac_ext}
+        # If the linker supports ICF, foo and bar symbols will have
+        # the same address
+        if AC_TRY_COMMAND([${CC-cc} -o conftest${ac_exeext} $LDFLAGS -Wl,--icf=safe -ffunction-sections conftest.${ac_ext} $LIBS 1>&2]) &&
+           test -s conftest${ac_exeext} &&
+           objdump -t conftest${ac_exeext} | awk changequote(<<, >>)'{a[<<$>>6] = <<$>>1} END {if (a["foo"] && (a["foo"] != a["bar"])) { exit 1 }}'changequote([, ]); then
+            LD_SUPPORTS_ICF=yes
+        else
+            LD_SUPPORTS_ICF=no
+        fi
+        rm -rf conftest*])
+    if test "$LD_SUPPORTS_ICF" = yes; then
+        _SAVE_LDFLAGS="$LDFLAGS -Wl,--icf=safe"
+        LDFLAGS="$LDFLAGS -Wl,--icf=safe -Wl,--print-icf-sections"
+        AC_TRY_LINK([], [],
+                    [LD_PRINT_ICF_SECTIONS=-Wl,--print-icf-sections],
+                    [LD_PRINT_ICF_SECTIONS=])
+        AC_SUBST([LD_PRINT_ICF_SECTIONS])
+        LDFLAGS="$_SAVE_LDFLAGS"
+    fi
+fi
+
+dnl ========================================================
+dnl = Automatically remove dead symbols
+dnl ========================================================
+
+if test "$GNU_CC" -a "$GCC_USE_GNU_LD" -a -n "$MOZ_DEBUG_FLAGS"; then
+   dnl See bug 670659
+   AC_CACHE_CHECK([whether removing dead symbols breaks debugging],
+       GC_SECTIONS_BREAKS_DEBUG_RANGES,
+       [echo 'int foo() {return 42;}' \
+             'int bar() {return 1;}' \
+             'int main() {return foo();}' > conftest.${ac_ext}
+        if AC_TRY_COMMAND([${CC-cc} -o conftest.${ac_objext} $CFLAGS $MOZ_DEBUG_FLAGS -c conftest.${ac_ext} 1>&2]) &&
+           AC_TRY_COMMAND([${CC-cc} -o conftest${ac_exeext} $LDFLAGS $MOZ_DEBUG_FLAGS -Wl,--gc-sections conftest.${ac_objext} $LIBS 1>&2]) &&
+           test -s conftest${ac_exeext} -a -s conftest.${ac_objext}; then
+            if test "`$PYTHON "$_topsrcdir"/build/autoconf/check_debug_ranges.py conftest.${ac_objext} conftest.${ac_ext}`" = \
+                    "`$PYTHON "$_topsrcdir"/build/autoconf/check_debug_ranges.py conftest${ac_exeext} conftest.${ac_ext}`"; then
+                GC_SECTIONS_BREAKS_DEBUG_RANGES=no
+            else
+                GC_SECTIONS_BREAKS_DEBUG_RANGES=yes
+            fi
+        else
+             dnl We really don't expect to get here, but just in case
+             GC_SECTIONS_BREAKS_DEBUG_RANGES="no, but it's broken in some other way"
+        fi
+        rm -rf conftest*])
+    if test "$GC_SECTIONS_BREAKS_DEBUG_RANGES" = no; then
+        DSO_LDOPTS="$DSO_LDOPTS -Wl,--gc-sections"
+    fi
+fi
+
 ])
-
new file mode 100644
--- /dev/null
+++ b/js/src/build/autoconf/expandlibs.m4
@@ -0,0 +1,56 @@
+AC_DEFUN([MOZ_EXPAND_LIBS],
+[
+dnl ========================================================
+dnl =
+dnl = Check what kind of list files are supported by the
+dnl = linker
+dnl =
+dnl ========================================================
+
+AC_CACHE_CHECK(what kind of list files are supported by the linker,
+    EXPAND_LIBS_LIST_STYLE,
+    [echo "int main() {return 0;}" > conftest.${ac_ext}
+     if AC_TRY_COMMAND(${CC-cc} -o conftest.${OBJ_SUFFIX} -c $CFLAGS $CPPFLAGS conftest.${ac_ext} 1>&5) && test -s conftest.${OBJ_SUFFIX}; then
+         echo "INPUT(conftest.${OBJ_SUFFIX})" > conftest.list
+         if AC_TRY_COMMAND(${CC-cc} -o conftest${ac_exeext} $LDFLAGS conftest.list $LIBS 1>&5) && test -s conftest${ac_exeext}; then
+             EXPAND_LIBS_LIST_STYLE=linkerscript
+         else
+             echo "conftest.${OBJ_SUFFIX}" > conftest.list
+             if AC_TRY_COMMAND(${CC-cc} -o conftest${ac_exeext} $LDFLAGS @conftest.list $LIBS 1>&5) && test -s conftest${ac_exeext}; then
+                 EXPAND_LIBS_LIST_STYLE=list
+             else
+                 EXPAND_LIBS_LIST_STYLE=none
+             fi
+         fi
+     else
+         dnl We really don't expect to get here, but just in case
+         AC_ERROR([couldn't compile a simple C file])
+     fi
+     rm -rf conftest*])
+
+LIBS_DESC_SUFFIX=desc
+AC_SUBST(LIBS_DESC_SUFFIX)
+AC_SUBST(EXPAND_LIBS_LIST_STYLE)
+
+if test "$GCC_USE_GNU_LD"; then
+    AC_CACHE_CHECK(what kind of ordering can be done with the linker,
+        EXPAND_LIBS_ORDER_STYLE,
+        [> conftest.order
+         _SAVE_LDFLAGS="$LDFLAGS"
+         LDFLAGS="${LDFLAGS} -Wl,--section-ordering-file,conftest.order"
+         AC_TRY_LINK([], [],
+             EXPAND_LIBS_ORDER_STYLE=section-ordering-file,
+             EXPAND_LIBS_ORDER_STYLE=)
+         LDFLAGS="$_SAVE_LDFLAGS"
+         if test -z "$EXPAND_LIBS_ORDER_STYLE"; then
+             if AC_TRY_COMMAND(${CC-cc} ${DSO_LDOPTS} ${LDFLAGS} -o ${DLL_PREFIX}conftest${DLL_SUFFIX} -Wl,--verbose 2> /dev/null | sed -n '/^===/,/^===/p' | grep '\.text'); then
+                 EXPAND_LIBS_ORDER_STYLE=linkerscript
+             else
+                 EXPAND_LIBS_ORDER_STYLE=none
+             fi
+             rm -f ${DLL_PREFIX}conftest${DLL_SUFFIX}
+         fi])
+fi
+AC_SUBST(EXPAND_LIBS_ORDER_STYLE)
+
+])
--- a/js/src/config/config.mk
+++ b/js/src/config/config.mk
@@ -784,18 +784,22 @@ OPTIMIZE_JARS_CMD = $(PYTHON) $(call cor
 CREATE_PRECOMPLETE_CMD = $(PYTHON) $(call core_abspath,$(topsrcdir)/config/createprecomplete.py)
 
 EXPAND_LIBS = $(PYTHON) -I$(DEPTH)/config $(topsrcdir)/config/expandlibs.py
 EXPAND_LIBS_EXEC = $(PYTHON) $(topsrcdir)/config/pythonpath.py -I$(DEPTH)/config $(topsrcdir)/config/expandlibs_exec.py
 EXPAND_LIBS_GEN = $(PYTHON) $(topsrcdir)/config/pythonpath.py -I$(DEPTH)/config $(topsrcdir)/config/expandlibs_gen.py
 EXPAND_AR = $(EXPAND_LIBS_EXEC) --extract -- $(AR)
 EXPAND_CC = $(EXPAND_LIBS_EXEC) --uselist -- $(CC)
 EXPAND_CCC = $(EXPAND_LIBS_EXEC) --uselist -- $(CCC)
-EXPAND_LD = $(EXPAND_LIBS_EXEC) --uselist $(if $(REORDER),--reorder $(REORDER))-- $(LD)
-EXPAND_MKSHLIB = $(EXPAND_LIBS_EXEC) --uselist $(if $(REORDER),--reorder $(REORDER))-- $(MKSHLIB)
+EXPAND_LD = $(EXPAND_LIBS_EXEC) --uselist -- $(LD)
+EXPAND_MKSHLIB_ARGS = --uselist
+ifdef SYMBOL_ORDER
+EXPAND_MKSHLIB_ARGS += --symbol-order $(SYMBOL_ORDER)
+endif
+EXPAND_MKSHLIB = $(EXPAND_LIBS_EXEC) $(EXPAND_MKSHLIB_ARGS) -- $(MKSHLIB)
 
 ifdef STDCXX_COMPAT
 ifneq ($(OS_ARCH),Darwin)
 CHECK_STDCXX = objdump -p $(1) | grep -e 'GLIBCXX_3\.4\.\(9\|[1-9][0-9]\)' > /dev/null && echo "TEST-UNEXPECTED-FAIL | | We don't want these libstdc++ symbols to be used:" && objdump -T $(1) | grep -e 'GLIBCXX_3\.4\.\(9\|[1-9][0-9]\)' && exit 1 || exit 0
 endif
 endif
 
 # autoconf.mk sets OBJ_SUFFIX to an error to avoid use before including
--- a/js/src/config/expandlibs_config.py.in
+++ b/js/src/config/expandlibs_config.py.in
@@ -49,8 +49,10 @@ AR_EXTRACT = "@AR_EXTRACT@".replace('$(A
 DLL_PREFIX = "@DLL_PREFIX@"
 LIB_PREFIX = "@LIB_PREFIX@"
 OBJ_SUFFIX = normalize_suffix("@OBJ_SUFFIX@")
 LIB_SUFFIX = normalize_suffix("@LIB_SUFFIX@")
 DLL_SUFFIX = normalize_suffix("@DLL_SUFFIX@")
 IMPORT_LIB_SUFFIX = normalize_suffix("@IMPORT_LIB_SUFFIX@")
 LIBS_DESC_SUFFIX = normalize_suffix("@LIBS_DESC_SUFFIX@")
 EXPAND_LIBS_LIST_STYLE = "@EXPAND_LIBS_LIST_STYLE@"
+EXPAND_LIBS_ORDER_STYLE = "@EXPAND_LIBS_ORDER_STYLE@"
+LD_PRINT_ICF_SECTIONS = "@LD_PRINT_ICF_SECTIONS@"
--- a/js/src/config/expandlibs_exec.py
+++ b/js/src/config/expandlibs_exec.py
@@ -44,29 +44,41 @@ from static libraries (or use those list
 
 With the --uselist argument (useful for e.g. $(CC)), it replaces all object
 files with a list file. This can be used to avoid limitations in the length
 of a command line. The kind of list file format used depends on the
 EXPAND_LIBS_LIST_STYLE variable: 'list' for MSVC style lists (@file.list)
 or 'linkerscript' for GNU ld linker scripts.
 See https://bugzilla.mozilla.org/show_bug.cgi?id=584474#c59 for more details.
 
-With the --reorder argument, followed by a file name, it will reorder the
-object files from the command line according to the order given in the file.
-Implies --extract.
+With the --symbol-order argument, followed by a file name, it will add the
+relevant linker options to change the order in which the linker puts the
+symbols appear in the resulting binary. Only works for ELF targets.
 '''
 from __future__ import with_statement
 import sys
 import os
 from expandlibs import ExpandArgs, relativize, isObject
 import expandlibs_config as conf
 from optparse import OptionParser
 import subprocess
 import tempfile
 import shutil
+import subprocess
+import re
+
+# The are the insert points for a GNU ld linker script, assuming a more
+# or less "standard" default linker script. This is not a dict because
+# order is important.
+SECTION_INSERT_BEFORE = [
+  ('.text', '.fini'),
+  ('.rodata', '.rodata1'),
+  ('.data.rel.ro', '.dynamic'),
+  ('.data', '.data1'),
+]
 
 class ExpandArgsMore(ExpandArgs):
     ''' Meant to be used as 'with ExpandArgsMore(args) as ...: '''
     def __enter__(self):
         self.tmp = []
         return self
         
     def __exit__(self, type, value, tb):
@@ -114,61 +126,203 @@ class ExpandArgsMore(ExpandArgs):
         fd, tmp = tempfile.mkstemp(suffix=".list",dir=os.curdir)
         if conf.EXPAND_LIBS_LIST_STYLE == "linkerscript":
             content = ["INPUT(%s)\n" % obj for obj in objs]
             ref = tmp
         elif conf.EXPAND_LIBS_LIST_STYLE == "list":
             content = ["%s\n" % obj for obj in objs]
             ref = "@" + tmp
         else:
+            os.close(fd)
             os.remove(tmp)
             return
         self.tmp.append(tmp)
         f = os.fdopen(fd, "w")
         f.writelines(content)
         f.close()
         idx = self.index(objs[0])
         newlist = self[0:idx] + [ref] + [item for item in self[idx:] if item not in objs]
         self[0:] = newlist
 
-    def reorder(self, order_list):
-        '''Given a list of file names without OBJ_SUFFIX, rearrange self
-        so that the object file names it contains are ordered according to
-        that list.
-        '''
-        objs = [o for o in self if isObject(o)]
-        if not objs: return
-        idx = self.index(objs[0])
-        # Keep everything before the first object, then the ordered objects,
-        # then any other objects, then any non-objects after the first object
-        objnames = dict([(os.path.splitext(os.path.basename(o))[0], o) for o in objs])
-        self[0:] = self[0:idx] + [objnames[o] for o in order_list if o in objnames] + \
-                   [o for o in objs if os.path.splitext(os.path.basename(o))[0] not in order_list] + \
-                   [x for x in self[idx:] if not isObject(x)]
+    def _getFoldedSections(self):
+        '''Returns a dict about folded sections.
+        When section A and B are folded into section C, the dict contains:
+        { 'A': 'C',
+          'B': 'C',
+          'C': ['A', 'B'] }'''
+        if not conf.LD_PRINT_ICF_SECTIONS:
+            return {}
+
+        proc = subprocess.Popen(self + [conf.LD_PRINT_ICF_SECTIONS], stdout = subprocess.PIPE, stderr = subprocess.PIPE)
+        (stdout, stderr) = proc.communicate()
+        result = {}
+        # gold's --print-icf-sections output looks like the following:
+        # ld: ICF folding section '.section' in file 'file.o'into '.section' in file 'file.o'
+        # In terms of words, chances are this will change in the future,
+        # especially considering "into" is misplaced. Splitting on quotes
+        # seems safer.
+        for l in stderr.split('\n'):
+            quoted = l.split("'")
+            if len(quoted) > 5 and quoted[1] != quoted[5]:
+                result[quoted[1]] = quoted[5]
+                if quoted[5] in result:
+                    result[quoted[5]].append(quoted[1])
+                else:
+                    result[quoted[5]] = [quoted[1]]
+        return result
+
+    def _getOrderedSections(self, ordered_symbols):
+        '''Given an ordered list of symbols, returns the corresponding list
+        of sections following the order.'''
+        if not conf.EXPAND_LIBS_ORDER_STYLE in ['linkerscript', 'section-ordering-file']:
+            raise Exception('EXPAND_LIBS_ORDER_STYLE "%s" is not supported' % conf.EXPAND_LIBS_ORDER_STYLE)
+        finder = SectionFinder([arg for arg in self if isObject(arg) or os.path.splitext(arg)[1] == conf.LIB_SUFFIX])
+        folded = self._getFoldedSections()
+        sections = set()
+        ordered_sections = []
+        for symbol in ordered_symbols:
+            symbol_sections = finder.getSections(symbol)
+            all_symbol_sections = []
+            for section in symbol_sections:
+                if section in folded:
+                    if isinstance(folded[section], str):
+                        section = folded[section]
+                    all_symbol_sections.append(section)
+                    all_symbol_sections.extend(folded[section])
+                else:
+                    all_symbol_sections.append(section)
+            for section in all_symbol_sections:
+                if not section in sections:
+                    ordered_sections.append(section)
+                    sections.add(section)
+        return ordered_sections
+
+    def orderSymbols(self, order):
+        '''Given a file containing a list of symbols, adds the appropriate
+        argument to make the linker put the symbols in that order.'''
+        with open(order) as file:
+            sections = self._getOrderedSections([l.strip() for l in file.readlines() if l.strip()])
+        split_sections = {}
+        linked_sections = [s[0] for s in SECTION_INSERT_BEFORE]
+        for s in sections:
+            for linked_section in linked_sections:
+                if s.startswith(linked_section):
+                    if linked_section in split_sections:
+                        split_sections[linked_section].append(s)
+                    else:
+                        split_sections[linked_section] = [s]
+                    break
+        content = []
+        # Order is important
+        linked_sections = [s for s in linked_sections if s in split_sections]
 
+        if conf.EXPAND_LIBS_ORDER_STYLE == 'section-ordering-file':
+            option = '-Wl,--section-ordering-file,%s'
+            content = sections
+            for linked_section in linked_sections:
+                content.extend(split_sections[linked_section])
+                content.append('%s.*' % linked_section)
+                content.append(linked_section)
+
+        elif conf.EXPAND_LIBS_ORDER_STYLE == 'linkerscript':
+            option = '-Wl,-T,%s'
+            section_insert_before = dict(SECTION_INSERT_BEFORE)
+            for linked_section in linked_sections:
+                content.append('SECTIONS {')
+                content.append('  %s : {' % linked_section)
+                content.extend('    *(%s)' % s for s in split_sections[linked_section])
+                content.append('  }')
+                content.append('}')
+                content.append('INSERT BEFORE %s' % section_insert_before[linked_section])
+        else:
+            raise Exception('EXPAND_LIBS_ORDER_STYLE "%s" is not supported' % conf.EXPAND_LIBS_ORDER_STYLE)
+
+        fd, tmp = tempfile.mkstemp(dir=os.curdir)
+        f = os.fdopen(fd, "w")
+        f.write('\n'.join(content)+'\n')
+        f.close()
+        self.tmp.append(tmp)
+        self.append(option % tmp)
+
+class SectionFinder(object):
+    '''Instances of this class allow to map symbol names to sections in
+    object files.'''
+
+    def __init__(self, objs):
+        '''Creates an instance, given a list of object files.'''
+        if not conf.EXPAND_LIBS_ORDER_STYLE in ['linkerscript', 'section-ordering-file']:
+            raise Exception('EXPAND_LIBS_ORDER_STYLE "%s" is not supported' % conf.EXPAND_LIBS_ORDER_STYLE)
+        self.mapping = {}
+        for obj in objs:
+            if not isObject(obj) and os.path.splitext(obj)[1] != conf.LIB_SUFFIX:
+                raise Exception('%s is not an object nor a static library' % obj)
+            for symbol, section in SectionFinder._getSymbols(obj):
+                sym = SectionFinder._normalize(symbol)
+                if sym in self.mapping:
+                    if not section in self.mapping[sym]:
+                        self.mapping[sym].append(section)
+                else:
+                    self.mapping[sym] = [section]
+
+    def getSections(self, symbol):
+        '''Given a symbol, returns a list of sections containing it or the
+        corresponding thunks. When the given symbol is a thunk, returns the
+        list of sections containing its corresponding normal symbol and the
+        other thunks for that symbol.'''
+        sym = SectionFinder._normalize(symbol)
+        if sym in self.mapping:
+            return self.mapping[sym]
+        return []
+
+    @staticmethod
+    def _normalize(symbol):
+        '''For normal symbols, return the given symbol. For thunks, return
+        the corresponding normal symbol.'''
+        if re.match('^_ZThn[0-9]+_', symbol):
+            return re.sub('^_ZThn[0-9]+_', '_Z', symbol)
+        return symbol
+
+    @staticmethod
+    def _getSymbols(obj):
+        '''Returns a list of (symbol, section) contained in the given object
+        file.'''
+        proc = subprocess.Popen(['objdump', '-t', obj], stdout = subprocess.PIPE, stderr = subprocess.PIPE)
+        (stdout, stderr) = proc.communicate()
+        syms = []
+        for line in stdout.splitlines():
+            # Each line has the following format:
+            # <addr> [lgu!][w ][C ][W ][Ii ][dD ][FfO ] <section>\t<length> <symbol>
+            tmp = line.split(' ',1)
+            # This gives us ["<addr>", "[lgu!][w ][C ][W ][Ii ][dD ][FfO ] <section>\t<length> <symbol>"]
+            # We only need to consider cases where "<section>\t<length> <symbol>" is present,
+            # and where the [FfO] flag is either F (function) or O (object).
+            if len(tmp) > 1 and len(tmp[1]) > 6 and tmp[1][6] in ['O', 'F']:
+                tmp = tmp[1][8:].split()
+                # That gives us ["<section>","<length>", "<symbol>"]
+                syms.append((tmp[-1], tmp[0]))
+        return syms
 
 def main():
     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("--reorder", dest="reorder",
-        help="reorder the objects according to the given list", metavar="FILE")
+    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()
 
     with ExpandArgsMore(args) as args:
-        if options.extract or options.reorder:
+        if options.extract:
             args.extract()
-        if options.reorder:
-            with open(options.reorder) as file:
-                args.reorder([l.strip() for l in file.readlines()])
+        if options.symbol_order:
+            args.orderSymbols(options.symbol_order)
         if options.uselist:
             args.makelist()
 
         if options.verbose:
             print >>sys.stderr, "Executing: " + " ".join(args)
             for tmp in [f for f in args.tmp if os.path.isfile(f)]:
                 print >>sys.stderr, tmp + ":"
                 with open(tmp) as file:
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -4824,47 +4824,17 @@ else
    _MOZ_RTTI_FLAGS=$_MOZ_RTTI_FLAGS_OFF
 fi
 
 AC_SUBST(_MOZ_RTTI_FLAGS_ON)
 
 AC_DEFINE(CPP_THROW_NEW, [throw()])
 AC_LANG_C
 
-dnl ========================================================
-dnl =
-dnl = Check what kind of list files are supported by the
-dnl = linker
-dnl =
-dnl ========================================================
-
-AC_CACHE_CHECK(what kind of list files are supported by the linker,
-    EXPAND_LIBS_LIST_STYLE,
-    [echo "int main() {return 0;}" > conftest.${ac_ext}
-     if AC_TRY_COMMAND(${CC-cc} -o conftest.${OBJ_SUFFIX} -c $CFLAGS $CPPFLAGS conftest.${ac_ext} 1>&2) && test -s conftest.${OBJ_SUFFIX}; then
-         echo "INPUT(conftest.${OBJ_SUFFIX})" > conftest.list
-         if AC_TRY_COMMAND(${CC-cc} -o conftest${ac_exeext} $LDFLAGS conftest.list $LIBS 1>&2) && test -s conftest${ac_exeext}; then
-             EXPAND_LIBS_LIST_STYLE=linkerscript
-         else
-             echo "conftest.${OBJ_SUFFIX}" > conftest.list
-             if AC_TRY_COMMAND(${CC-cc} -o conftest${ac_exeext} $LDFLAGS @conftest.list $LIBS 1>&2) && test -s conftest${ac_exeext}; then
-                 EXPAND_LIBS_LIST_STYLE=list
-             else
-                 EXPAND_LIBS_LIST_STYLE=none
-             fi
-         fi
-     else
-         dnl We really don't expect to get here, but just in case
-         AC_ERROR([couldn't compile a simple C file])
-     fi
-     rm -rf conftest*])
-
-LIBS_DESC_SUFFIX=desc
-AC_SUBST(LIBS_DESC_SUFFIX)
-AC_SUBST(EXPAND_LIBS_LIST_STYLE)
+MOZ_EXPAND_LIBS
 
 dnl ========================================================
 dnl =
 dnl = Build depencency options
 dnl =
 dnl ========================================================
 MOZ_ARG_HEADER(Build dependencies)
 
--- a/js/src/frontend/TokenStream.cpp
+++ b/js/src/frontend/TokenStream.cpp
@@ -1317,22 +1317,28 @@ TokenStream::checkForKeyword(const jscha
                 *ttp = kw->tokentype;
                 *topp = (JSOp) kw->op;
                 return true;
             }
             return ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR,
                                             JSMSG_RESERVED_ID, kw->chars);
         }
 
+        /* The let keyword is reserved on <1.7 */
+        if (kw->tokentype == TOK_LET) {
+            return ReportCompileErrorNumber(cx, this, NULL, JSREPORT_ERROR,
+                                            JSMSG_RESERVED_ID, kw->chars);
+        }
+
         /*
          * The keyword is not in this version. Treat it as an identifier,
-         * unless it is let or yield which we treat as TOK_STRICT_RESERVED by
-         * falling through to the code below (ES5 forbids them in strict mode).
+         * unless it is yield which we treat as TOK_STRICT_RESERVED by
+         * falling through to the code below (ES5 forbids it in strict mode).
          */
-        if (kw->tokentype != TOK_LET && kw->tokentype != TOK_YIELD)
+        if (kw->tokentype != TOK_YIELD)
             return true;
     }
 
     /* Strict reserved word. */
     if (isStrictMode())
         return ReportStrictModeError(cx, this, NULL, NULL, JSMSG_RESERVED_ID, kw->chars);
     return ReportCompileErrorNumber(cx, this, NULL, JSREPORT_STRICT | JSREPORT_WARNING,
                                     JSMSG_RESERVED_ID, kw->chars);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug734196.js
@@ -0,0 +1,4 @@
+var x = new ArrayBuffer(2);
+gczeal(4);
+actual = [].concat(x).toString();
+var count2 = countHeap();
--- a/js/src/jit-test/tests/basic/regress-bug720680.js
+++ b/js/src/jit-test/tests/basic/regress-bug720680.js
@@ -4,12 +4,12 @@ eval("\
 function TimeFromYear( y ) {}\
 addTestCase( -2208988800000 );\
 function addTestCase( t ) {\
   var start = TimeFromYear((addTestCase(addTestCase << t, 0)));\
     new TestCase( \
                   SECTION,\
                   '(new Date('+d+')).getUTCDay()',\
                   WeekDay((d)),\
-                  (new Date(let ({ stop } = 'properties.length' )('/ab[c\\\n]/'))).getUTCDay() \
+                  (new Date(foo ({ stop } = 'properties.length' )('/ab[c\\\n]/'))).getUTCDay() \
                 );\
 }\
 ");
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/jaeger/bug732423.js
@@ -0,0 +1,23 @@
+function testXML(x, y) {
+    for (var i = 0; i < 60; i++) {
+        x[y]();
+        x[y];
+    }
+}
+testXML(<x/>, "elements");
+
+var o = {
+    res: 0,
+    f: function() { this.res += 3; },
+    __noSuchMethod__: function() { this.res += 5; }
+};
+
+function testNoSuchMethod(x, y) {
+    for (var i = 0; i < 60; i++) {
+        x[y]();
+    }
+}
+
+testNoSuchMethod(o, "f");
+testNoSuchMethod(o, "g");
+assertEq(o.res, 480);
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -836,17 +836,17 @@ JSRuntime::init(uint32_t maxbytes)
     if (!(atomsCompartment = this->new_<JSCompartment>(this)) ||
         !atomsCompartment->init(NULL) ||
         !compartments.append(atomsCompartment)) {
         Foreground::delete_(atomsCompartment);
         return false;
     }
 
     atomsCompartment->isSystemCompartment = true;
-    atomsCompartment->setGCLastBytes(8192, GC_NORMAL);
+    atomsCompartment->setGCLastBytes(8192, 8192, GC_NORMAL);
 
     if (!js_InitAtomState(this))
         return false;
 
     if (!InitRuntimeNumberState(this))
         return false;
 
     dtoaState = js_NewDtoaState();
@@ -1009,18 +1009,16 @@ static void
 StartRequest(JSContext *cx)
 {
     JSRuntime *rt = cx->runtime;
     JS_ASSERT(rt->onOwnerThread());
 
     if (rt->requestDepth) {
         rt->requestDepth++;
     } else {
-        AutoLockGC lock(rt);
-
         /* Indicate that a request is running. */
         rt->requestDepth = 1;
 
         if (rt->activityCallback)
             rt->activityCallback(rt->activityCallbackArg, true);
     }
 }
 
@@ -1029,20 +1027,16 @@ StopRequest(JSContext *cx)
 {
     JSRuntime *rt = cx->runtime;
     JS_ASSERT(rt->onOwnerThread());
     JS_ASSERT(rt->requestDepth != 0);
     if (rt->requestDepth != 1) {
         rt->requestDepth--;
     } else {
         rt->conservativeGC.updateForRequestEnd(rt->suspendCount);
-
-        /* Lock before clearing to interlock with ClaimScope, in jslock.c. */
-        AutoLockGC lock(rt);
-
         rt->requestDepth = 0;
 
         if (rt->activityCallback)
             rt->activityCallback(rt->activityCallbackArg, false);
     }
 }
 #endif /* JS_THREADSAFE */
 
@@ -1302,24 +1296,22 @@ SetOptionsCommon(JSContext *cx, unsigned
     cx->setCompileOptions(newcopts);
     cx->updateJITEnabled();
     return oldopts;
 }
 
 JS_PUBLIC_API(uint32_t)
 JS_SetOptions(JSContext *cx, uint32_t options)
 {
-    AutoLockGC lock(cx->runtime);
     return SetOptionsCommon(cx, options);
 }
 
 JS_PUBLIC_API(uint32_t)
 JS_ToggleOptions(JSContext *cx, uint32_t options)
 {
-    AutoLockGC lock(cx->runtime);
     unsigned oldopts = cx->allOptions();
     unsigned newopts = oldopts ^ options;
     return SetOptionsCommon(cx, newopts);
 }
 
 JS_PUBLIC_API(void)
 JS_SetJitHardening(JSRuntime *rt, JSBool enabled)
 {
@@ -2198,16 +2190,28 @@ JS_ComputeThis(JSContext *cx, jsval *vp)
     AssertNoGC(cx);
     assertSameCompartment(cx, JSValueArray(vp, 2));
     CallReceiver call = CallReceiverFromVp(vp);
     if (!BoxNonStrictThis(cx, call))
         return JSVAL_NULL;
     return call.thisv();
 }
 
+JS_PUBLIC_API(void)
+JS_MallocInCompartment(JSCompartment *comp, size_t nbytes)
+{
+    comp->mallocInCompartment(nbytes);
+}
+
+JS_PUBLIC_API(void)
+JS_FreeInCompartment(JSCompartment *comp, size_t nbytes)
+{
+    comp->freeInCompartment(nbytes);
+}
+
 JS_PUBLIC_API(void *)
 JS_malloc(JSContext *cx, size_t nbytes)
 {
     AssertNoGC(cx);
     CHECK_REQUEST(cx);
     return cx->malloc_(nbytes);
 }
 
@@ -2879,17 +2883,16 @@ JS_IsAboutToBeFinalized(void *thing)
     return IsAboutToBeFinalized(t);
 }
 
 JS_PUBLIC_API(void)
 JS_SetGCParameter(JSRuntime *rt, JSGCParamKey key, uint32_t value)
 {
     switch (key) {
       case JSGC_MAX_BYTES: {
-        AutoLockGC lock(rt);
         JS_ASSERT(value >= rt->gcBytes);
         rt->gcMaxBytes = value;
         break;
       }
       case JSGC_MAX_MALLOC_BYTES:
         rt->setGCMaxMallocBytes(value);
         break;
       case JSGC_SLICE_TIME_BUDGET:
@@ -4263,17 +4266,17 @@ prop_iter_trace(JSTracer *trc, JSObject 
     if (obj->getSlot(JSSLOT_ITER_INDEX).toInt32() < 0) {
         /*
          * Native case: just mark the next property to visit. We don't need a
          * barrier here because the pointer is updated via setPrivate, which
          * always takes a barrier.
          */
         Shape *tmp = (Shape *)pdata;
         MarkShapeUnbarriered(trc, &tmp, "prop iter shape");
-        JS_ASSERT(tmp == pdata);
+        obj->setPrivateUnbarriered(tmp);
     } else {
         /* Non-native case: mark each id in the JSIdArray private. */
         JSIdArray *ida = (JSIdArray *) pdata;
         MarkIdRange(trc, ida->length, ida->vector, "prop iter");
     }
 }
 
 static Class prop_iter_class = {
@@ -5506,30 +5509,18 @@ JS_SetOperationCallback(JSContext *cx, J
 
 JS_PUBLIC_API(JSOperationCallback)
 JS_GetOperationCallback(JSContext *cx)
 {
     return cx->operationCallback;
 }
 
 JS_PUBLIC_API(void)
-JS_TriggerOperationCallback(JSContext *cx)
-{
-#ifdef JS_THREADSAFE
-    AutoLockGC lock(cx->runtime);
-#endif
-    cx->runtime->triggerOperationCallback();
-}
-
-JS_PUBLIC_API(void)
-JS_TriggerRuntimeOperationCallback(JSRuntime *rt)
-{
-#ifdef JS_THREADSAFE
-    AutoLockGC lock(rt);
-#endif
+JS_TriggerOperationCallback(JSRuntime *rt)
+{
     rt->triggerOperationCallback();
 }
 
 JS_PUBLIC_API(JSBool)
 JS_IsRunning(JSContext *cx)
 {
     StackFrame *fp = cx->maybefp();
     while (fp && fp->isDummyFrame())
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -2874,16 +2874,22 @@ JS_THIS(JSContext *cx, jsval *vp)
  * or vice versa.  Either use the provided this value with this macro, or
  * compute the boxed this value using those.
  *
  * N.B. constructors must not use JS_THIS_VALUE, as no 'this' object has been
  * created.
  */
 #define JS_THIS_VALUE(cx,vp)    ((vp)[1])
 
+extern JS_PUBLIC_API(void)
+JS_MallocInCompartment(JSCompartment *comp, size_t nbytes);
+
+extern JS_PUBLIC_API(void)
+JS_FreeInCompartment(JSCompartment *comp, size_t nbytes);
+
 extern JS_PUBLIC_API(void *)
 JS_malloc(JSContext *cx, size_t nbytes);
 
 extern JS_PUBLIC_API(void *)
 JS_realloc(JSContext *cx, void *p, size_t nbytes);
 
 extern JS_PUBLIC_API(void)
 JS_free(JSContext *cx, void *p);
@@ -4493,42 +4499,35 @@ Call(JSContext *cx, jsval thisv, JSObjec
 
 } /* namespace JS */
 
 JS_BEGIN_EXTERN_C
 #endif /* __cplusplus */
 
 /*
  * These functions allow setting an operation callback that will be called
- * from the thread the context is associated with some time after any thread
- * triggered the callback using JS_TriggerOperationCallback(cx).
+ * from the JS thread some time after any thread triggered the callback using
+ * JS_TriggerOperationCallback(rt).
  *
- * In a threadsafe build the engine internally triggers operation callbacks
- * under certain circumstances (i.e. GC and title transfer) to force the
- * context to yield its current request, which the engine always
- * automatically does immediately prior to calling the callback function.
- * The embedding should thus not rely on callbacks being triggered through
- * the external API only.
+ * To schedule the GC and for other activities the engine internally triggers
+ * operation callbacks. The embedding should thus not rely on callbacks being
+ * triggered through the external API only.
  *
  * Important note: Additional callbacks can occur inside the callback handler
  * if it re-enters the JS engine. The embedding must ensure that the callback
  * is disconnected before attempting such re-entry.
  */
-
 extern JS_PUBLIC_API(JSOperationCallback)
 JS_SetOperationCallback(JSContext *cx, JSOperationCallback callback);
 
 extern JS_PUBLIC_API(JSOperationCallback)
 JS_GetOperationCallback(JSContext *cx);
 
 extern JS_PUBLIC_API(void)
-JS_TriggerOperationCallback(JSContext *cx);
-
-extern JS_PUBLIC_API(void)
-JS_TriggerRuntimeOperationCallback(JSRuntime *rt);
+JS_TriggerOperationCallback(JSRuntime *rt);
 
 extern JS_PUBLIC_API(JSBool)
 JS_IsRunning(JSContext *cx);
 
 /*
  * Saving and restoring frame chains.
  *
  * These two functions are used to set aside cx's call stack while that stack
--- a/js/src/jsbool.cpp
+++ b/js/src/jsbool.cpp
@@ -181,23 +181,16 @@ js_InitBooleanClass(JSContext *cx, JSObj
 }
 
 JSString *
 js_BooleanToString(JSContext *cx, JSBool b)
 {
     return cx->runtime->atomState.booleanAtoms[b ? 1 : 0];
 }
 
-/* This function implements E-262-3 section 9.8, toString. */
-bool
-js::BooleanToStringBuffer(JSContext *cx, JSBool b, StringBuffer &sb)
-{
-    return b ? sb.append("true") : sb.append("false");
-}
-
 namespace js {
 
 bool
 BooleanGetPrimitiveValueSlow(JSContext *cx, JSObject &obj, Value *vp)
 {
     JS_ASSERT(ObjectClassIs(obj, ESClass_Boolean, cx));
     JS_ASSERT(obj.isProxy());
 
--- a/js/src/jsbool.h
+++ b/js/src/jsbool.h
@@ -49,19 +49,16 @@
 extern JSObject *
 js_InitBooleanClass(JSContext *cx, JSObject *obj);
 
 extern JSString *
 js_BooleanToString(JSContext *cx, JSBool b);
 
 namespace js {
 
-extern bool
-BooleanToStringBuffer(JSContext *cx, JSBool b, StringBuffer &sb);
-
 inline bool
 BooleanGetPrimitiveValue(JSContext *cx, JSObject &obj, Value *vp);
 
 } /* namespace js */
 
 extern JSBool
 js_ValueToBoolean(const js::Value &v);
 
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -113,17 +113,17 @@ JSRuntime::sizeOfExcludingThis(JSMallocS
 
     if (stackCommitted)
         *stackCommitted = stackSpace.sizeOfCommitted();
 
     if (gcMarkerSize)
         *gcMarkerSize = gcMarker.sizeOfExcludingThis(mallocSizeOf);
 }
 
-JS_FRIEND_API(void)
+void
 JSRuntime::triggerOperationCallback()
 {
     /*
      * Use JS_ATOMIC_SET in the hope that it ensures the write will become
      * immediately visible to other processors polling the flag.
      */
     JS_ATOMIC_SET(&interrupt, 1);
 }
@@ -245,59 +245,58 @@ js_DestroyContext(JSContext *cx, JSDestr
              * JSCONTEXT_DESTROY callback is not allowed to fail and must
              * return true.
              */
             DebugOnly<JSBool> callbackStatus = cxCallback(cx, JSCONTEXT_DESTROY);
             JS_ASSERT(callbackStatus);
         }
     }
 
-    JS_LOCK_GC(rt);
     JS_REMOVE_LINK(&cx->link);
     bool last = !rt->hasContexts();
-    if (last || mode == JSDCM_FORCE_GC || mode == JSDCM_MAYBE_GC) {
+    if (last) {
         JS_ASSERT(!rt->gcRunning);
 
 #ifdef JS_THREADSAFE
-        rt->gcHelperThread.waitBackgroundSweepEnd();
+        {
+            AutoLockGC lock(rt);
+            rt->gcHelperThread.waitBackgroundSweepEnd();
+        }
 #endif
-        JS_UNLOCK_GC(rt);
-
-        if (last) {
-            /*
-             * Dump remaining type inference results first. This printing
-             * depends on atoms still existing.
-             */
-            {
-                AutoLockGC lock(rt);
-                for (CompartmentsIter c(rt); !c.done(); c.next())
-                    c->types.print(cx, false);
-            }
-
-            /* Unpin all common atoms before final GC. */
-            js_FinishCommonAtoms(cx);
+        
+        /*
+         * Dump remaining type inference results first. This printing
+         * depends on atoms still existing.
+         */
+        for (CompartmentsIter c(rt); !c.done(); c.next())
+            c->types.print(cx, false);
 
-            /* Clear debugging state to remove GC roots. */
-            for (CompartmentsIter c(rt); !c.done(); c.next())
-                c->clearTraps(cx);
-            JS_ClearAllWatchPoints(cx);
-
-            GC(cx, NULL, GC_NORMAL, gcreason::LAST_CONTEXT);
+        /* Unpin all common atoms before final GC. */
+        js_FinishCommonAtoms(cx);
+        
+        /* Clear debugging state to remove GC roots. */
+        for (CompartmentsIter c(rt); !c.done(); c.next())
+            c->clearTraps(cx);
+        JS_ClearAllWatchPoints(cx);
+        
+        GC(cx, NULL, GC_NORMAL, gcreason::LAST_CONTEXT);
+    } else if (mode == JSDCM_FORCE_GC) {
+        JS_ASSERT(!rt->gcRunning);
+        GC(cx, NULL, GC_NORMAL, gcreason::DESTROY_CONTEXT);
+    } else if (mode == JSDCM_MAYBE_GC) {
+        JS_ASSERT(!rt->gcRunning);
+        JS_MaybeGC(cx);
+    }
 
-        } else if (mode == JSDCM_FORCE_GC) {
-            GC(cx, NULL, GC_NORMAL, gcreason::DESTROY_CONTEXT);
-        } else if (mode == JSDCM_MAYBE_GC) {
-            JS_MaybeGC(cx);
-        }
-        JS_LOCK_GC(rt);
+#ifdef JS_THREADSAFE
+    {
+        AutoLockGC lock(rt);
+        rt->gcHelperThread.waitBackgroundSweepEnd();
     }
-#ifdef JS_THREADSAFE
-    rt->gcHelperThread.waitBackgroundSweepEnd();
 #endif
-    JS_UNLOCK_GC(rt);
     Foreground::delete_(cx);
 }
 
 namespace js {
 
 bool
 AutoResolving::alreadyStartedSlow() const
 {
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -681,17 +681,17 @@ struct JSRuntime : js::RuntimeFriendFiel
      * to recove some memory or to report an error. Failures in malloc and
      * calloc are signaled by p == null and p == reinterpret_cast<void *>(1).
      * Other values of p mean a realloc failure.
      *
      * The function must be called outside the GC lock.
      */
     JS_FRIEND_API(void *) onOutOfMemory(void *p, size_t nbytes, JSContext *cx);
 
-    JS_FRIEND_API(void) triggerOperationCallback();
+    void triggerOperationCallback();
 
     void setJitHardening(bool enabled);
     bool getJitHardening() const {
         return jitHardening;
     }
 
     void sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf, size_t *normal, size_t *temporary,
                              size_t *regexpCode, size_t *stackCommitted, size_t *gcMarker);
@@ -1245,16 +1245,50 @@ class AutoXMLRooter : private AutoGCRoot
 #ifdef JS_THREADSAFE
 # define JS_LOCK_GC(rt)    PR_Lock((rt)->gcLock)
 # define JS_UNLOCK_GC(rt)  PR_Unlock((rt)->gcLock)
 #else
 # define JS_LOCK_GC(rt)
 # define JS_UNLOCK_GC(rt)
 #endif
 
+class AutoLockGC
+{
+  public:
+    explicit AutoLockGC(JSRuntime *rt = NULL
+                        MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
+      : runtime(rt)
+    {
+        MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+        if (rt)
+            JS_LOCK_GC(rt);
+    }
+
+    ~AutoLockGC()
+    {
+        if (runtime)
+            JS_UNLOCK_GC(runtime);
+    }
+
+    bool locked() const {
+        return !!runtime;
+    }
+
+    void lock(JSRuntime *rt) {
+        JS_ASSERT(rt);
+        JS_ASSERT(!runtime);
+        runtime = rt;
+        JS_LOCK_GC(rt);
+    }
+
+  private:
+    JSRuntime *runtime;
+    MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
+
 class AutoUnlockGC {
   private:
     JSRuntime *rt;
     JS_DECL_USE_GUARD_OBJECT_NOTIFIER
 
   public:
     explicit AutoUnlockGC(JSRuntime *rt
                           JS_GUARD_OBJECT_NOTIFIER_PARAM)
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -70,27 +70,29 @@ using namespace js;
 using namespace js::gc;
 
 JSCompartment::JSCompartment(JSRuntime *rt)
   : rt(rt),
     principals(NULL),
     needsBarrier_(false),
     gcBytes(0),
     gcTriggerBytes(0),
-    gcLastBytes(0),
     hold(false),
     typeLifoAlloc(TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
     data(NULL),
     active(false),
 #ifdef JS_METHODJIT
     jaegerCompartment_(NULL),
 #endif
     regExps(rt),
     propertyTree(thisForCtor()),
     emptyTypeObject(NULL),
+    gcMallocAndFreeBytes(0),
+    gcTriggerMallocAndFreeBytes(0),
+    gcMallocBytes(0),
     debugModeBits(rt->debugMode ? DebugFromC : 0),
     mathCache(NULL),
     watchpointMap(NULL)
 {
     PodArrayZero(evalCache);
     setGCMaxMallocBytes(rt->gcMaxMallocBytes * 0.9);
 }
 
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -200,17 +200,16 @@ struct JSCompartment
 
     js::GCMarker *barrierTracer() {
         JS_ASSERT(needsBarrier_);
         return &rt->gcMarker;
     }
 
     size_t                       gcBytes;
     size_t                       gcTriggerBytes;
-    size_t                       gcLastBytes;
     size_t                       gcMaxMallocBytes;
 
     bool                         hold;
     bool                         isSystemCompartment;
 
     /*
      * Pool for analysis and intermediate type information in this compartment.
      * Cleared on every GC, unless the GC happens during analysis (indicated
@@ -262,24 +261,16 @@ struct JSCompartment
     size_t sizeOfShapeTable(JSMallocSizeOfFun mallocSizeOf);
     void sizeOfTypeInferenceData(JS::TypeInferenceSizes *stats, JSMallocSizeOfFun mallocSizeOf);
 
     /*
      * Shared scope property tree, and arena-pool for allocating its nodes.
      */
     js::PropertyTree             propertyTree;
 
-#ifdef DEBUG
-    /* Property metering. */
-    unsigned                     livePropTreeNodes;
-    unsigned                     totalPropTreeNodes;
-    unsigned                     propTreeKidsChunks;
-    unsigned                     liveDictModeNodes;
-#endif
-
     /* Set of all unowned base shapes in the compartment. */
     js::BaseShapeSet             baseShapes;
     void sweepBaseShapeTable(JSContext *cx);
 
     /* Set of initial shapes in the compartment. */
     js::InitialShapeSet          initialShapes;
     void sweepInitialShapeTable(JSContext *cx);
 
@@ -293,26 +284,36 @@ struct JSCompartment
     /* Get the default 'new' type for objects with a NULL prototype. */
     inline js::types::TypeObject *getEmptyType(JSContext *cx);
 
     js::types::TypeObject *getLazyType(JSContext *cx, JSObject *proto);
 
     /* Cache to speed up object creation. */
     js::NewObjectCache           newObjectCache;
 
+    /*
+     * Keeps track of the total number of malloc bytes connected to a
+     * compartment's GC things. This counter should be used in preference to
+     * gcMallocBytes. These counters affect collection in the same way as
+     * gcBytes and gcTriggerBytes.
+     */
+    size_t                       gcMallocAndFreeBytes;
+    size_t                       gcTriggerMallocAndFreeBytes;
+
   private:
+    /*
+     * Malloc counter to measure memory pressure for GC scheduling. It runs from
+     * gcMaxMallocBytes down to zero. This counter should be used only when it's
+     * not possible to know the size of a free.
+     */
+    ptrdiff_t                    gcMallocBytes;
+
     enum { DebugFromC = 1, DebugFromJS = 2 };
 
-    unsigned                        debugModeBits;  // see debugMode() below
-    
-    /*
-     * Malloc counter to measure memory pressure for GC scheduling. It runs
-     * from gcMaxMallocBytes down to zero.
-     */
-    volatile ptrdiff_t           gcMallocBytes;
+    unsigned                     debugModeBits;  // see debugMode() below
 
   public:
     js::NativeIterCache          nativeIterCache;
 
     typedef js::Maybe<js::ToSourceCache> LazyToSourceCache;
     LazyToSourceCache            toSourceCache;
 
     js::ScriptFilenameTable      scriptFilenameTable;
@@ -335,31 +336,40 @@ struct JSCompartment
     bool wrap(JSContext *cx, js::PropertyDescriptor *desc);
     bool wrap(JSContext *cx, js::AutoIdVector &props);
 
     void markTypes(JSTracer *trc);
     void discardJitCode(JSContext *cx);
     void sweep(JSContext *cx, bool releaseTypes);
     void purge();
 
-    void setGCLastBytes(size_t lastBytes, js::JSGCInvocationKind gckind);
+    void setGCLastBytes(size_t lastBytes, size_t lastMallocBytes, js::JSGCInvocationKind gckind);
     void reduceGCTriggerBytes(size_t amount);
-    
+
     void resetGCMallocBytes();
     void setGCMaxMallocBytes(size_t value);
     void updateMallocCounter(size_t nbytes) {
         ptrdiff_t oldCount = gcMallocBytes;
         ptrdiff_t newCount = oldCount - ptrdiff_t(nbytes);
         gcMallocBytes = newCount;
         if (JS_UNLIKELY(newCount <= 0 && oldCount > 0))
             onTooMuchMalloc();
     }
-    
+
     void onTooMuchMalloc();
 
+    void mallocInCompartment(size_t nbytes) {
+        gcMallocAndFreeBytes += nbytes;
+    }
+
+    void freeInCompartment(size_t nbytes) {
+        JS_ASSERT(gcMallocAndFreeBytes >= nbytes);
+        gcMallocAndFreeBytes -= nbytes;
+    }
+
     js::DtoaCache dtoaCache;
 
   private:
     js::MathCache                *mathCache;
 
     js::MathCache *allocMathCache(JSContext *cx);
 
     /*
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -604,39 +604,16 @@ js::DumpHeapComplete(JSRuntime *rt, FILE
     dtrc.visited.finish();
     fflush(dtrc.output);
 }
 
 #endif
 
 namespace js {
 
-/* static */ void
-AutoLockGC::LockGC(JSRuntime *rt)
-{
-    JS_ASSERT(rt);
-    JS_LOCK_GC(rt);
-}
-
-/* static */ void
-AutoLockGC::UnlockGC(JSRuntime *rt)
-{
-    JS_ASSERT(rt);
-    JS_UNLOCK_GC(rt);
-}
-
-void
-AutoLockGC::lock(JSRuntime *rt)
-{
-    JS_ASSERT(rt);
-    JS_ASSERT(!runtime);
-    runtime = rt;
-    JS_LOCK_GC(rt);
-}
-
 JS_FRIEND_API(const JSStructuredCloneCallbacks *)
 GetContextStructuredCloneCallbacks(JSContext *cx)
 {
     return cx->runtime->structuredCloneCallbacks;
 }
 
 JS_FRIEND_API(JSVersion)
 VersionSetXML(JSVersion version, bool enable)
@@ -669,22 +646,16 @@ GetOwnerThread(const JSContext *cx)
 }
 
 JS_FRIEND_API(unsigned)
 GetContextOutstandingRequests(const JSContext *cx)
 {
     return cx->outstandingRequests;
 }
 
-JS_FRIEND_API(PRLock *)
-GetRuntimeGCLock(const JSRuntime *rt)
-{
-    return rt->gcLock;
-}
-
 AutoSkipConservativeScan::AutoSkipConservativeScan(JSContext *cx
                                                    MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
   : context(cx)
 {
     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
 
     JSRuntime *rt = context->runtime;
     JS_ASSERT(rt->requestDepth >= 1);
@@ -721,22 +692,16 @@ SetActivityCallback(JSRuntime *rt, Activ
 }
 
 JS_FRIEND_API(bool)
 IsContextRunningJS(JSContext *cx)
 {
     return !cx->stack.empty();
 }
 
-JS_FRIEND_API(void)
-TriggerOperationCallback(JSRuntime *rt)
-{
-    rt->triggerOperationCallback();
-}
-
 JS_FRIEND_API(const CompartmentVector&)
 GetRuntimeCompartments(JSRuntime *rt)
 {
     return rt->compartments;
 }
 
 JS_FRIEND_API(size_t)
 SizeOfJSContext()
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -182,18 +182,16 @@ extern JS_FRIEND_API(bool)
 JS_DefineFunctionsWithHelp(JSContext *cx, JSObject *obj, const JSFunctionSpecWithHelp *fs);
 
 #endif
 
 JS_END_EXTERN_C
 
 #ifdef __cplusplus
 
-struct PRLock;
-
 namespace js {
 
 struct ContextFriendFields {
     JSRuntime *const    runtime;
 
     ContextFriendFields(JSRuntime *rt)
       : runtime(rt) { }
 
@@ -568,19 +566,16 @@ GetPCCountScriptContents(JSContext *cx, 
 
 #ifdef JS_THREADSAFE
 JS_FRIEND_API(void *)
 GetOwnerThread(const JSContext *cx);
 
 JS_FRIEND_API(unsigned)
 GetContextOutstandingRequests(const JSContext *cx);
 
-JS_FRIEND_API(PRLock *)
-GetRuntimeGCLock(const JSRuntime *rt);
-
 class JS_FRIEND_API(AutoSkipConservativeScan)
 {
   public:
     AutoSkipConservativeScan(JSContext *cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
     ~AutoSkipConservativeScan();
 
   private:
     JSContext *context;
@@ -595,72 +590,36 @@ JS_FRIEND_API(bool)
 HasUnrootedGlobal(const JSContext *cx);
 
 typedef void
 (* ActivityCallback)(void *arg, JSBool active);
 
 /*
  * Sets a callback that is run whenever the runtime goes idle - the
  * last active request ceases - and begins activity - when it was
- * idle and a request begins. Note: The callback is called under the
- * GC lock.
+ * idle and a request begins.
  */
 JS_FRIEND_API(void)
 SetActivityCallback(JSRuntime *rt, ActivityCallback cb, void *arg);
 
-class JS_FRIEND_API(AutoLockGC)
-{
-  public:
-    explicit AutoLockGC(JSRuntime *rt = NULL
-                        MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
-      : runtime(rt)
-    {
-        MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-        if (rt)
-            LockGC(rt);
-    }
-
-    ~AutoLockGC()