Merge inbound to m-c.
authorRyan VanderMeulen <ryanvm@gmail.com>
Tue, 19 Nov 2013 13:21:57 -0500
changeset 156290 d316d1dd062efe054d6aa456f380ccb11bcf0aa8
parent 156213 c335eaa4494a78be68cfc8a619f3795efe8338f2 (current diff)
parent 156289 9c5256d1d8a74aefc9c72c8a4452358dbe7cc671 (diff)
child 156324 efaeb105b189f7ebfa0899faaaa9afada16f4136
push id25673
push userryanvm@gmail.com
push dateTue, 19 Nov 2013 18:22:02 +0000
treeherdermozilla-central@d316d1dd062e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone28.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to m-c.
dom/contacts/tests/test_contacts_upgrade.html
dom/indexedDB/test/test_globalObjects.html
dom/indexedDB/test/test_globalObjects.xul
dom/indexedDB/test/unit/test_globalObjects.js
js/xpconnect/loader/mozJSComponentLoader.h
toolkit/library/nsStaticXULComponents.cpp
--- a/browser/components/build/Makefile.in
+++ b/browser/components/build/Makefile.in
@@ -15,18 +15,17 @@ LOCAL_INCLUDES = \
 	-I$(srcdir)/../dirprovider \
 	$(NULL)
 
 ifeq ($(OS_ARCH),WINNT)
 OS_LIBS += $(call EXPAND_LIBNAME,version)
 endif
 
 EXTRA_DSO_LDOPTS += \
-	$(call EXPAND_LIBNAME_PATH,unicharutil_external_s,$(LIBXUL_DIST)/lib) \
-	$(XPCOM_STATICRUNTIME_GLUE_LDOPTS) \
+	$(XPCOM_GLUE_LDOPTS) \
 	$(MOZ_COMPONENT_LIBS) \
 	$(NULL)
 
 ifdef JS_SHARED_LIBRARY
 EXTRA_DSO_LDOPTS += $(MOZ_JS_LIBS)
 endif
 
 LOCAL_INCLUDES += -I$(srcdir)/../migration/src
--- a/browser/components/shell/src/nsWindowsShellService.cpp
+++ b/browser/components/shell/src/nsWindowsShellService.cpp
@@ -455,23 +455,23 @@ nsWindowsShellService::IsDefaultBrowser(
 
     ::ZeroMemory(currValue, sizeof(currValue));
     DWORD len = sizeof currValue;
     res = ::RegQueryValueExW(theKey, L"", nullptr, nullptr,
                              (LPBYTE)currValue, &len);
     // Close the key that was opened.
     ::RegCloseKey(theKey);
     if (REG_FAILED(res) ||
-        !valueData.Equals(currValue, CaseInsensitiveCompare)) {
+        _wcsicmp(valueData.get(), currValue)) {
       // Key wasn't set or was set to something other than our registry entry.
       NS_ConvertUTF8toUTF16 oldValueData(settings->oldValueData);
       offset = oldValueData.Find("%APPPATH%");
       oldValueData.Replace(offset, 9, appLongPath);
       // The current registry value doesn't match the current or the old format.
-      if (!oldValueData.Equals(currValue, CaseInsensitiveCompare)) {
+      if (_wcsicmp(oldValueData.get(), currValue)) {
         *aIsDefaultBrowser = false;
         return NS_OK;
       }
 
       res = ::RegOpenKeyExW(HKEY_CLASSES_ROOT, PromiseFlatString(keyName).get(),
                             0, KEY_SET_VALUE, &theKey);
       if (REG_FAILED(res)) {
         // If updating the open command fails try to update it using the helper
@@ -574,17 +574,17 @@ nsWindowsShellService::IsDefaultBrowser(
     ::ZeroMemory(currValue, sizeof(currValue));
     DWORD len = sizeof currValue;
     res = ::RegQueryValueExW(theKey, L"", nullptr, nullptr, (LPBYTE)currValue,
                              &len);
 
     // Don't update the FTP protocol handler's shell open command when the
     // current registry value doesn't exist or matches the old format.
     if (REG_FAILED(res) ||
-        !oldValueOpen.Equals(currValue, CaseInsensitiveCompare)) {
+        _wcsicmp(oldValueOpen.get(), currValue)) {
       ::RegCloseKey(theKey);
       return NS_OK;
     }
 
     NS_ConvertUTF8toUTF16 valueData(VAL_OPEN);
     valueData.Replace(offset, 9, appLongPath);
     const nsString &flatValue = PromiseFlatString(valueData);
     res = ::RegSetValueExW(theKey, L"", 0, REG_SZ,
--- a/browser/metro/base/content/contenthandlers/Content.js
+++ b/browser/metro/base/content/contenthandlers/Content.js
@@ -109,16 +109,17 @@ function getOverflowContentBoundingRect(
 
 /*
  * Content
  *
  * Browser event receiver for content.
  */
 let Content = {
   _debugEvents: false,
+  _isZoomedIn: false,
 
   get formAssistant() {
     delete this.formAssistant;
     return this.formAssistant = new FormAssistant();
   },
 
   init: function init() {
     this._isZoomedToElement = false;
@@ -128,16 +129,17 @@ let Content = {
     addMessageListener("Browser:SaveAs", this);
     addMessageListener("Browser:MozApplicationCache:Fetch", this);
     addMessageListener("Browser:SetCharset", this);
     addMessageListener("Browser:CanUnload", this);
     addMessageListener("Browser:PanBegin", this);
 
     addEventListener("touchstart", this, false);
     addEventListener("click", this, true);
+    addEventListener("dblclick", this, true);
     addEventListener("keydown", this);
     addEventListener("keyup", this);
 
     // Synchronous events caught during the bubbling phase
     addEventListener("MozApplicationManifest", this, false);
     addEventListener("DOMContentLoaded", this, false);
     addEventListener("DOMAutoComplete", this, false);
     addEventListener("DOMFormHasPassword", this, false);
@@ -175,16 +177,25 @@ let Content = {
         // Allow down arrow to trigger autofill popup on empty input.
         if ((!aEvent.target.value && aEvent.keyCode != aEvent.DOM_VK_DOWN)
           || aEvent.keyCode == aEvent.DOM_VK_ESCAPE)
           this.formAssistant.close();
         else
           this.formAssistant.open(aEvent.target, aEvent);
         break;
 
+      case "dblclick":
+        // XXX Once gesture listners are used(Bug 933236), apzc will notify us
+        if (aEvent.mozInputSource == Ci.nsIDOMMouseEvent.MOZ_SOURCE_TOUCH) {
+          let selection = content.getSelection();
+          selection.removeAllRanges();
+          this._onZoomToTappedContent(aEvent.target);
+        }
+        break;
+
       case "click":
         // Workaround for bug 925457: we sometimes don't recognize the
         // correct tap target or are unable to identify if it's editable.
         // Instead always save tap co-ordinates for the keyboard to look for
         // when it is up.
         SelectionHandler.onClickCoords(aEvent.clientX, aEvent.clientY);
 
         if (aEvent.eventPhase == aEvent.BUBBLING_PHASE)
@@ -358,16 +369,85 @@ let Content = {
         let webNav = docShell.QueryInterface(Ci.nsIWebNavigation);
         webNav.loadURI(content.location,
                        Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CLASSIFIER,
                        null, null, null);
       }
     }
   },
 
+  _onZoomToTappedContent: function (aElement) {
+    if (!aElement || this._isZoomedIn) {
+      this._zoomOut();
+      return;
+    }
+
+    while (aElement && !this._shouldZoomToElement(aElement)) {
+      aElement = aElement.parentNode;
+    }
+
+    if (!aElement) {
+      this._zoomOut();
+    } else {
+      this._zoomToElement(aElement);
+    }
+  },
+
+  /******************************************************
+   * Zoom utilities
+   */
+  _zoomOut: function() {
+    let rect = getBoundingContentRect(content.document.documentElement);
+
+    let utils = Util.getWindowUtils(content);
+    let viewId = utils.getViewId(content.document.documentElement);
+    let presShellId = {};
+    utils.getPresShellId(presShellId);
+    let zoomData = [rect.x,
+                    rect.y,
+                    rect.width,
+                    rect.height,
+                    presShellId.value,
+                    viewId].join(",");
+    Services.obs.notifyObservers(null, "Metro:ZoomToRect", zoomData);
+    this._isZoomedIn = false;
+  },
+
+  _zoomToElement: function(aElement) {
+    let rect = getBoundingContentRect(aElement);
+    let utils = Util.getWindowUtils(content);
+    let viewId = utils.getViewId(content.document.documentElement);
+    let presShellId = {};
+    utils.getPresShellId(presShellId);
+    let zoomData = [rect.x,
+                    rect.y,
+                    rect.width,
+                    rect.height,
+                    presShellId.value,
+                    viewId].join(",");
+    Services.obs.notifyObservers(null, "Metro:ZoomToRect", zoomData);
+    this._isZoomedIn = true;
+  },
+
+  _shouldZoomToElement: function(aElement) {
+    let win = aElement.ownerDocument.defaultView;
+    if (win.getComputedStyle(aElement, null).display == "inline") {
+      return false;
+    }
+    else if (aElement instanceof Ci.nsIDOMHTMLLIElement) {
+      return false;
+    }
+    else if (aElement instanceof Ci.nsIDOMHTMLQuoteElement) {
+      return false;
+    }
+    else {
+      return true;
+    }
+  },
+
 
   /******************************************************
    * General utilities
    */
 
   _getContentClientRects: function getContentClientRects(aElement) {
     let offset = ContentScroll.getScrollOffset(content);
     offset = new Point(offset.x, offset.y);
--- a/browser/metro/base/content/input.js
+++ b/browser/metro/base/content/input.js
@@ -88,17 +88,16 @@ var TouchModule = {
     this._targetScrollbox = null;
     this._targetScrollInterface = null;
 
     this._kinetic = new KineticController(this._dragBy.bind(this),
                                           this._kineticStop.bind(this));
 
     // capture phase events
     window.addEventListener("CancelTouchSequence", this, true);
-    window.addEventListener("dblclick", this, true);
     window.addEventListener("keydown", this, true);
     window.addEventListener("MozMouseHittest", this, true);
 
     // bubble phase
     window.addEventListener("contextmenu", this, false);
     window.addEventListener("touchstart", this, false);
     window.addEventListener("touchmove", this, false);
     window.addEventListener("touchend", this, false);
@@ -139,30 +138,16 @@ var TouchModule = {
             this._onTouchStart(aEvent);
             break;
           case "touchmove":
             this._onTouchMove(aEvent);
             break;
           case "touchend":
             this._onTouchEnd(aEvent);
             break;
-          case "dblclick":
-            // XXX This will get picked up somewhere below us for "double tap to zoom"
-            // once we get omtc and the apzc. Currently though dblclick is delivered to
-            // content and triggers selection of text, so fire up the SelectionHelperUI
-            // once selection is present.
-            if (!InputSourceHelper.isPrecise &&
-                !SelectionHelperUI.isActive &&
-                !FindHelperUI.isActive) {
-              setTimeout(function () {
-                SelectionHelperUI.attachEditSession(Browser.selectedTab.browser,
-                                                    aEvent.clientX, aEvent.clientY);
-              }, 50);
-            }
-            break;
           case "keydown":
             this._handleKeyDown(aEvent);
             break;
           case "MozMouseHittest":
             // Used by widget to hit test chrome vs content. Make sure the XUl scrollbars
             // are counted as "chrome". Since the XUL scrollbars have sub-elements we walk
             // the parent chain to ensure we catch all of those as well.
             let onScrollbar = false;
--- a/browser/metro/base/tests/mochitest/browser_selection_basic.js
+++ b/browser/metro/base/tests/mochitest/browser_selection_basic.js
@@ -58,31 +58,16 @@ gTests.push({
         return SelectionHelperUI.isSelectionUIVisible;
       }, kCommonWaitMs, kCommonPollMs);
 
     is(getTrimmedSelection(gWindow).toString(), "There", "selection test");
   },
 });
 
 gTests.push({
-  desc: "double-tap to select",
-  setUp: setUpAndTearDown,
-  tearDown: setUpAndTearDown,
-  run: function test() {
-    sendDoubleTap(gWindow, 30, 20);
-
-    yield waitForCondition(function () {
-        return SelectionHelperUI.isSelectionUIVisible;
-      }, kCommonWaitMs, kCommonPollMs);
-
-    is(getTrimmedSelection(gWindow).toString(), "There", "selection test");
-  },
-});
-
-gTests.push({
   desc: "appbar interactions",
   setUp: setUpAndTearDown,
   tearDown: setUpAndTearDown,
   run: function test() {
     sendContextMenuClick(100, 20);
 
     yield waitForCondition(function () {
         return SelectionHelperUI.isSelectionUIVisible;
--- a/build/automation.py.in
+++ b/build/automation.py.in
@@ -516,29 +516,22 @@ class Automation(object):
       llvmsym = os.path.join(xrePath, "llvm-symbolizer")
       if os.path.isfile(llvmsym):
         env["ASAN_SYMBOLIZER_PATH"] = llvmsym
         self.log.info("INFO | automation.py | ASan using symbolizer at %s", llvmsym)
 
       try:
         totalMemory = int(os.popen("free").readlines()[1].split()[1])
 
-        # Only 2 GB RAM or less available? Use custom ASan options to reduce
+        # Only 4 GB RAM or less available? Use custom ASan options to reduce
         # the amount of resources required to do the tests. Standard options 
         # will otherwise lead to OOM conditions on the current test slaves.
-        # 
-        # If we have more than 2 GB or RAM but still less than 4 GB, we need
-        # another set of options to prevent OOM in some memory-intensive
-        # tests.
-        if totalMemory <= 1024 * 1024 * 2:
+        if totalMemory <= 1024 * 1024 * 4:
           self.log.info("INFO | automation.py | ASan running in low-memory configuration")
-          env["ASAN_OPTIONS"] = "quarantine_size=50331648:redzone=64"
-        elif totalMemory <= 1024 * 1024 * 4:
-          self.log.info("INFO | automation.py | ASan running in mid-memory configuration")
-          env["ASAN_OPTIONS"] = "quarantine_size=100663296:redzone=64"
+          env["ASAN_OPTIONS"] = "quarantine_size=50331648"
         else:
           self.log.info("INFO | automation.py | ASan running in default memory configuration")
       except OSError,err:
         self.log.info("Failed determine available memory, disabling ASan low-memory configuration: %s", err.strerror)
       except:
         self.log.info("Failed determine available memory, disabling ASan low-memory configuration")
 
     return env
--- a/build/automationutils.py
+++ b/build/automationutils.py
@@ -452,30 +452,23 @@ def environment(xrePath, env=None, crash
       # Symbolizer support
       llvmsym = os.path.join(xrePath, "llvm-symbolizer")
       if os.path.isfile(llvmsym):
         env["ASAN_SYMBOLIZER_PATH"] = llvmsym
         log.info("ASan using symbolizer at %s", llvmsym)
 
       totalMemory = systemMemory()
 
-      # Only 2 GB RAM or less available? Use custom ASan options to reduce
+      # Only 4 GB RAM or less available? Use custom ASan options to reduce
       # the amount of resources required to do the tests. Standard options
       # will otherwise lead to OOM conditions on the current test slaves.
-      #
-      # If we have more than 2 GB or RAM but still less than 4 GB, we need
-      # another set of options to prevent OOM in some memory-intensive
-      # tests.
       message = "INFO | runtests.py | ASan running in %s configuration"
-      if totalMemory <= 1024 * 1024 * 2:
+      if totalMemory <= 1024 * 1024 * 4:
         message = message % 'low-memory'
-        env["ASAN_OPTIONS"] = "quarantine_size=50331648:redzone=64"
-      elif totalMemory <= 1024 * 1024 * 4:
-        message = message % 'mid-memory'
-        env["ASAN_OPTIONS"] = "quarantine_size=80530636:redzone=64"
+        env["ASAN_OPTIONS"] = "quarantine_size=50331648"
       else:
         message = message % 'default memory'
     except OSError,err:
       log.info("Failed determine available memory, disabling ASan low-memory configuration: %s", err.strerror)
     except:
       log.info("Failed determine available memory, disabling ASan low-memory configuration")
     else:
       log.info(message)
--- a/config/expandlibs_exec.py
+++ b/config/expandlibs_exec.py
@@ -79,18 +79,24 @@ class ExpandArgsMore(ExpandArgs):
                 if os.path.exists(arg + conf.LIBS_DESC_SUFFIX):
                     newlist += self._extract(self._expand_desc(arg))
                     continue
                 elif os.path.exists(arg) and (len(ar_extract) or conf.AR == 'lib'):
                     tmp = tempfile.mkdtemp(dir=os.curdir)
                     self.tmp.append(tmp)
                     if conf.AR == 'lib':
                         out = subprocess.check_output([conf.AR, '-NOLOGO', '-LIST', arg])
-                        for l in out.splitlines():
-                            subprocess.call([conf.AR, '-NOLOGO', '-EXTRACT:%s' % l, os.path.abspath(arg)], cwd=tmp)
+                        files = out.splitlines()
+                        # If lib -list returns a list full of dlls, it's an
+                        # import lib.
+                        if all(isDynamicLib(f) for f in files):
+                            newlist += [arg]
+                            continue
+                        for f in files:
+                            subprocess.call([conf.AR, '-NOLOGO', '-EXTRACT:%s' % f, os.path.abspath(arg)], cwd=tmp)
                     else:
                         subprocess.call(ar_extract + [os.path.abspath(arg)], cwd=tmp)
                     objs = []
                     for root, dirs, files in os.walk(tmp):
                         objs += [relativize(os.path.join(root, f)) for f in files if isObject(f)]
                     newlist += sorted(objs)
                     continue
             newlist += [arg]
--- a/configure.in
+++ b/configure.in
@@ -3100,16 +3100,19 @@ AC_CACHE_CHECK(
     [if test "$OS_TARGET" = NetBSD -o "$OS_TARGET" = OpenBSD; then
         dnl no need for res_ninit() on NetBSD and OpenBSD
         ac_cv_func_res_ninit=no
      else
         AC_TRY_LINK([
             #ifdef linux
             #define _BSD_SOURCE 1
             #endif
+            #include <sys/types.h>
+            #include <netinet/in.h>
+            #include <arpa/nameser.h>
             #include <resolv.h>
             ],
             [int foo = res_ninit(&_res);],
             [ac_cv_func_res_ninit=yes],
             [ac_cv_func_res_ninit=no])
      fi
     ])
 
--- a/content/base/public/nsINode.h
+++ b/content/base/public/nsINode.h
@@ -1073,16 +1073,22 @@ public:
   mozilla::dom::Element* QuerySelector(const nsAString& aSelector,
                                        mozilla::ErrorResult& aResult);
   already_AddRefed<nsINodeList> QuerySelectorAll(const nsAString& aSelector,
                                                  mozilla::ErrorResult& aResult);
 
   nsresult QuerySelector(const nsAString& aSelector, nsIDOMElement **aReturn);
   nsresult QuerySelectorAll(const nsAString& aSelector, nsIDOMNodeList **aReturn);
 
+protected:
+  // nsIDocument overrides this with its own (faster) version.  This
+  // should really only be called for elements and document fragments.
+  mozilla::dom::Element* GetElementById(const nsAString& aId);
+
+public:
   /**
    * Associate an object aData to aKey on this node. If aData is null any
    * previously registered object and UserDataHandler associated to aKey on
    * this node will be removed.
    * Should only be used to implement the DOM Level 3 UserData API.
    *
    * @param aKey the key to associate the object to
    * @param aData the object to associate to aKey on this node (may be null)
--- a/content/base/src/DocumentFragment.h
+++ b/content/base/src/DocumentFragment.h
@@ -35,16 +35,18 @@ private:
                                         kNameSpaceID_None),
                       "Bad NodeType in aNodeInfo");
   }
 
 public:
   using FragmentOrElement::GetFirstChild;
   using nsINode::QuerySelector;
   using nsINode::QuerySelectorAll;
+  // Make sure bindings can see our superclass' protected GetElementById method.
+  using nsINode::GetElementById;
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
   // interface nsIDOMNode
   NS_FORWARD_NSIDOMNODE_TO_NSINODE
 
   // interface nsIDOMDocumentFragment
--- a/content/base/src/nsContentList.cpp
+++ b/content/base/src/nsContentList.cpp
@@ -200,17 +200,17 @@ NS_GetContentList(nsINode* aRootNode,
   nsContentListKey hashKey(aRootNode, aMatchNameSpaceId, aTagname);
   uint32_t recentlyUsedCacheIndex = RecentlyUsedCacheIndex(hashKey);
   nsContentList* cachedList = sRecentlyUsedContentLists[recentlyUsedCacheIndex];
   if (cachedList && cachedList->MatchesKey(hashKey)) {
     list = cachedList;
     return list.forget();
   }
 
-  static PLDHashTableOps hash_table_ops =
+  static const PLDHashTableOps hash_table_ops =
   {
     PL_DHashAllocTable,
     PL_DHashFreeTable,
     ContentListHashtableHashKey,
     ContentListHashtableMatchEntry,
     PL_DHashMoveEntryStub,
     PL_DHashClearEntryStub,
     PL_DHashFinalizeStub
@@ -321,17 +321,17 @@ GetFuncStringContentList(nsINode* aRootN
                          nsContentListDestroyFunc aDestroyFunc,
                          nsFuncStringContentListDataAllocator aDataAllocator,
                          const nsAString& aString)
 {
   NS_ASSERTION(aRootNode, "content list has to have a root");
 
   nsRefPtr<nsCacheableFuncStringContentList> list;
 
-  static PLDHashTableOps hash_table_ops =
+  static const PLDHashTableOps hash_table_ops =
   {
     PL_DHashAllocTable,
     PL_DHashFreeTable,
     FuncStringContentListHashtableHashKey,
     FuncStringContentListHashtableMatchEntry,
     PL_DHashMoveEntryStub,
     PL_DHashClearEntryStub,
     PL_DHashFinalizeStub
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -390,17 +390,17 @@ nsContentUtils::Init()
   
   rv = CallGetService(NS_WBRK_CONTRACTID, &sWordBreaker);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!InitializeEventTable())
     return NS_ERROR_FAILURE;
 
   if (!sEventListenerManagersHash.ops) {
-    static PLDHashTableOps hash_table_ops =
+    static const PLDHashTableOps hash_table_ops =
     {
       PL_DHashAllocTable,
       PL_DHashFreeTable,
       PL_DHashVoidPtrKeyStub,
       PL_DHashMatchEntryStub,
       PL_DHashMoveEntryStub,
       EventListenerManagerHashClearEntry,
       PL_DHashFinalizeStub,
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -3587,17 +3587,17 @@ nsDocument::SetSubDocumentFor(Element* a
       if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
         PL_DHashTableRawRemove(mSubDocuments, entry);
       }
     }
   } else {
     if (!mSubDocuments) {
       // Create a new hashtable
 
-      static PLDHashTableOps hash_table_ops =
+      static const PLDHashTableOps hash_table_ops =
       {
         PL_DHashAllocTable,
         PL_DHashFreeTable,
         PL_DHashVoidPtrKeyStub,
         PL_DHashMatchEntryStub,
         PL_DHashMoveEntryStub,
         SubDocClearEntry,
         PL_DHashFinalizeStub,
--- a/content/base/src/nsINode.cpp
+++ b/content/base/src/nsINode.cpp
@@ -2314,24 +2314,76 @@ AddScopeElements(TreeMatchContext& aMatc
                  nsINode* aMatchContextNode)
 {
   if (aMatchContextNode->IsElement()) {
     aMatchContext.SetHasSpecifiedScope();
     aMatchContext.AddScopeElement(aMatchContextNode->AsElement());
   }
 }
 
+namespace {
+struct SelectorMatchInfo {
+  nsCSSSelectorList* const mSelectorList;
+  TreeMatchContext& mMatchContext;
+};
+}
+
+// Given an id, find elements with that id under aRoot that match aMatchInfo if
+// any is provided.  If no SelectorMatchInfo is provided, just find the ones
+// with the given id.  aRoot must be in the document.
+template<bool onlyFirstMatch, class T>
+inline static void
+FindMatchingElementsWithId(const nsAString& aId, nsINode* aRoot,
+                           SelectorMatchInfo* aMatchInfo,
+                           T& aList)
+{
+  MOZ_ASSERT(aRoot->IsInDoc(),
+             "Don't call me if the root is not in the document");
+  MOZ_ASSERT(aRoot->IsElement() || aRoot->IsNodeOfType(nsINode::eDOCUMENT),
+             "The optimization below to check ContentIsDescendantOf only for "
+             "elements depends on aRoot being either an element or a "
+             "document if it's in the document.  Note that document fragments "
+             "can't be IsInDoc(), so should never show up here.");
+
+  const nsSmallVoidArray* elements = aRoot->OwnerDoc()->GetAllElementsForId(aId);
+
+  if (!elements) {
+    // Nothing to do; we're done
+    return;
+  }
+
+  // XXXbz: Should we fall back to the tree walk if aRoot is not the
+  // document and |elements| is long, for some value of "long"?
+  for (int32_t i = 0; i < elements->Count(); ++i) {
+    Element *element = static_cast<Element*>(elements->ElementAt(i));
+    if (!aRoot->IsElement() ||
+        (element != aRoot &&
+           nsContentUtils::ContentIsDescendantOf(element, aRoot))) {
+      // We have an element with the right id and it's a strict descendant
+      // of aRoot.  Make sure it really matches the selector.
+      if (!aMatchInfo ||
+          nsCSSRuleProcessor::SelectorListMatches(element,
+                                                  aMatchInfo->mMatchContext,
+                                                  aMatchInfo->mSelectorList)) {
+        aList.AppendElement(element);
+        if (onlyFirstMatch) {
+          return;
+        }
+      }
+    }
+  }
+}
+
 // Actually find elements matching aSelectorList (which must not be
 // null) and which are descendants of aRoot and put them in aList.  If
 // onlyFirstMatch, then stop once the first one is found.
 template<bool onlyFirstMatch, class Collector, class T>
 MOZ_ALWAYS_INLINE static nsresult
 FindMatchingElements(nsINode* aRoot, const nsAString& aSelector, T &aList)
 {
-
   nsIDocument* doc = aRoot->OwnerDoc();
   nsIDocument::SelectorCache& cache = doc->GetSelectorCache();
   nsCSSSelectorList* selectorList = nullptr;
   bool haveCachedList = cache.GetList(aSelector, &selectorList);
 
   if (!haveCachedList) {
     nsresult rv = ParseSelectorList(aRoot, aSelector, &selectorList);
     if (NS_FAILED(rv)) {
@@ -2375,42 +2427,19 @@ FindMatchingElements(nsINode* aRoot, con
                "The optimization below to check ContentIsDescendantOf only for "
                "elements depends on aRoot being either an element or a "
                "document if it's in the document.");
   if (aRoot->IsInDoc() &&
       doc->GetCompatibilityMode() != eCompatibility_NavQuirks &&
       !selectorList->mNext &&
       selectorList->mSelectors->mIDList) {
     nsIAtom* id = selectorList->mSelectors->mIDList->mAtom;
-    const nsSmallVoidArray* elements =
-      doc->GetAllElementsForId(nsDependentAtomString(id));
-
-    // XXXbz: Should we fall back to the tree walk if aRoot is not the
-    // document and |elements| is long, for some value of "long"?
-    if (elements) {
-      for (int32_t i = 0; i < elements->Count(); ++i) {
-        Element *element = static_cast<Element*>(elements->ElementAt(i));
-        if (!aRoot->IsElement() ||
-            (element != aRoot &&
-             nsContentUtils::ContentIsDescendantOf(element, aRoot))) {
-          // We have an element with the right id and it's a strict descendant
-          // of aRoot.  Make sure it really matches the selector.
-          if (nsCSSRuleProcessor::SelectorListMatches(element, matchingContext,
-                                                      selectorList)) {
-            aList.AppendElement(element);
-            if (onlyFirstMatch) {
-              return NS_OK;
-            }
-          }
-        }
-      }
-    }
-
-    // No elements with this id, or none of them are our descendants,
-    // or none of them match.  We're done here.
+    SelectorMatchInfo info = { selectorList, matchingContext };
+    FindMatchingElementsWithId<onlyFirstMatch, T>(nsDependentAtomString(id),
+                                                  aRoot, &info, aList);
     return NS_OK;
   }
 
   Collector results;
   for (nsIContent* cur = aRoot->GetFirstChild();
        cur;
        cur = cur->GetNextNode(aRoot)) {
     if (cur->IsElement() &&
@@ -2487,16 +2516,39 @@ nsINode::QuerySelector(const nsAString& 
 nsresult
 nsINode::QuerySelectorAll(const nsAString& aSelector, nsIDOMNodeList **aReturn)
 {
   ErrorResult rv;
   *aReturn = nsINode::QuerySelectorAll(aSelector, rv).get();
   return rv.ErrorCode();
 }
 
+Element*
+nsINode::GetElementById(const nsAString& aId)
+{
+  MOZ_ASSERT(IsElement() || IsNodeOfType(eDOCUMENT_FRAGMENT),
+             "Bogus this object for GetElementById call");
+  if (IsInDoc()) {
+    ElementHolder holder;
+    FindMatchingElementsWithId<true>(aId, this, nullptr, holder);
+    return holder.mElement;
+  }
+
+  for (nsIContent* kid = GetFirstChild(); kid; kid = kid->GetNextNode(this)) {
+    if (!kid->IsElement()) {
+      continue;
+    }
+    nsIAtom* id = kid->AsElement()->GetID();
+    if (id && id->Equals(aId)) {
+      return kid->AsElement();
+    }
+  }
+  return nullptr;
+}
+
 JSObject*
 nsINode::WrapObject(JSContext *aCx, JS::Handle<JSObject*> aScope)
 {
   MOZ_ASSERT(IsDOMBinding());
 
   // Make sure one of these is true
   // (1) our owner document has a script handling object,
   // (2) Our owner document has had a script handling object, or has been marked
--- a/content/base/test/mochitest.ini
+++ b/content/base/test/mochitest.ini
@@ -527,16 +527,17 @@ support-files =
 [test_copypaste.xhtml]
 [test_createHTMLDocument.html]
 [test_declare_stylesheet_obsolete.html]
 [test_domparser_null_char.html]
 [test_domparsing.html]
 [test_elementTraversal.html]
 [test_fileapi.html]
 [test_fileapi_slice.html]
+[test_getElementById.html]
 [test_html_colors_quirks.html]
 [test_html_colors_standards.html]
 [test_html_in_xhr.html]
 [test_htmlcopyencoder.html]
 [test_htmlcopyencoder.xhtml]
 [test_ipc_messagemanager_blob.html]
 [test_meta_viewport0.html]
 [test_meta_viewport1.html]
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_getElementById.html
@@ -0,0 +1,58 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=933193
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 933193</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=933193">Mozilla Bug 933193</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+  <script type="application/javascript">
+
+  /** Test for Bug 933193 **/
+    var kid = document.createElement("span");
+    kid.id = "test";
+    var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
+    svg.appendChild(kid);
+    is(svg.getElementById("test"), kid,
+       "Should find the right node when not in the DOM");
+
+    var newKid = document.createElement("span");
+    newKid.id = "test";
+    var newKidParent = document.createElement("span");
+    newKidParent.appendChild(newKid);
+    svg.insertBefore(newKidParent, kid);
+    is(svg.getElementById("test"), newKid,
+       "Should find the first right node when not in the DOM");
+    newKid.remove();
+    is(svg.getElementById("test"), kid,
+       "Should find the right node again when not in the DOM");
+
+    document.body.appendChild(svg);
+    is(svg.getElementById("test"), kid,
+       "Should find the right node when in the DOM");
+
+    is(document.getElementById("test").localName, "pre",
+       "document.getElementById should find the first element in the " +
+       "document with that id");
+
+    var frag = document.createDocumentFragment();
+    is(frag.getElementById("test"), null, "Shouldn't find what does not exist");
+    frag.appendChild(kid);
+    is(frag.getElementById("test"), kid,
+       "Should find the right node in the document fragment");
+    is(svg.getElementById("test"), null,
+       "Shouldn't find the kid since it's gone now");
+  </script>
+</body>
+</html>
--- a/content/events/src/moz.build
+++ b/content/events/src/moz.build
@@ -15,17 +15,17 @@ EXPORTS += [
 
 EXPORTS.mozilla.dom += [
     'Touch.h',
 ]
 
 if CONFIG['MOZ_WEBSPEECH']:
     EXPORTS.mozilla.dom += ['SpeechRecognitionError.h']
 
-SOURCES += [
+UNIFIED_SOURCES += [
     'DOMWheelEvent.cpp',
     'EventTarget.cpp',
     'nsAsyncDOMEvent.cpp',
     'nsContentEventHandler.cpp',
     'nsDOMAnimationEvent.cpp',
     'nsDOMBeforeUnloadEvent.cpp',
     'nsDOMClipboardEvent.cpp',
     'nsDOMCommandEvent.cpp',
@@ -49,26 +49,30 @@ SOURCES += [
     'nsDOMTextEvent.cpp',
     'nsDOMTouchEvent.cpp',
     'nsDOMTransitionEvent.cpp',
     'nsDOMUIEvent.cpp',
     'nsDOMXULCommandEvent.cpp',
     'nsEventDispatcher.cpp',
     'nsEventListenerManager.cpp',
     'nsEventListenerService.cpp',
-    'nsEventStateManager.cpp',
     'nsIMEStateManager.cpp',
     'nsPaintRequest.cpp',
     'nsPrivateTextRange.cpp',
     'TextComposition.cpp',
     'Touch.cpp',
 ]
 
+# nsEventStateManager.cpp should be built separately because of Mac OS X headers.
+SOURCES += [
+    'nsEventStateManager.cpp',
+]
+
 if CONFIG['MOZ_WEBSPEECH']:
-    SOURCES += ['SpeechRecognitionError.cpp']
+    UNIFIED_SOURCES += ['SpeechRecognitionError.cpp']
 
 FAIL_ON_WARNINGS = True
 
 MSVC_ENABLE_PGO = True
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'gklayout'
--- a/content/media/AudioSegment.cpp
+++ b/content/media/AudioSegment.cpp
@@ -121,46 +121,55 @@ AudioSegment::WriteTo(uint64_t aID, Audi
     TrackTicks offset = 0;
     while (offset < c.mDuration) {
       TrackTicks durationTicks =
         std::min<TrackTicks>(c.mDuration - offset, AUDIO_PROCESSING_FRAMES);
       if (uint64_t(outputChannels)*durationTicks > INT32_MAX || offset > INT32_MAX) {
         NS_ERROR("Buffer overflow");
         return;
       }
+
       uint32_t duration = uint32_t(durationTicks);
-      buf.SetLength(outputChannels*duration);
-      if (c.mBuffer) {
-        channelData.SetLength(c.mChannelData.Length());
-        for (uint32_t i = 0; i < channelData.Length(); ++i) {
-          channelData[i] =
-            AddAudioSampleOffset(c.mChannelData[i], c.mBufferFormat, int32_t(offset));
-        }
 
-        if (channelData.Length() < outputChannels) {
-          // Up-mix. Note that this might actually make channelData have more
-          // than outputChannels temporarily.
-          AudioChannelsUpMix(&channelData, outputChannels, gZeroChannel);
-        }
+      // If we have written data in the past, or we have real (non-silent) data
+      // to write, we can proceed. Otherwise, it means we just started the
+      // AudioStream, and we don't have real data to write to it (just silence).
+      // To avoid overbuffering in the AudioStream, we simply drop the silence,
+      // here. The stream will underrun and output silence anyways.
+      if (c.mBuffer || aOutput->GetWritten()) {
+        buf.SetLength(outputChannels*duration);
+        if (c.mBuffer) {
+          channelData.SetLength(c.mChannelData.Length());
+          for (uint32_t i = 0; i < channelData.Length(); ++i) {
+            channelData[i] =
+              AddAudioSampleOffset(c.mChannelData[i], c.mBufferFormat, int32_t(offset));
+          }
 
-        if (channelData.Length() > outputChannels) {
-          // Down-mix.
-          DownmixAndInterleave(channelData, c.mBufferFormat, duration,
-                               c.mVolume, outputChannels, buf.Elements());
+          if (channelData.Length() < outputChannels) {
+            // Up-mix. Note that this might actually make channelData have more
+            // than outputChannels temporarily.
+            AudioChannelsUpMix(&channelData, outputChannels, gZeroChannel);
+          }
+
+          if (channelData.Length() > outputChannels) {
+            // Down-mix.
+            DownmixAndInterleave(channelData, c.mBufferFormat, duration,
+                                 c.mVolume, outputChannels, buf.Elements());
+          } else {
+            InterleaveAndConvertBuffer(channelData.Elements(), c.mBufferFormat,
+                                       duration, c.mVolume,
+                                       outputChannels,
+                                       buf.Elements());
+          }
         } else {
-          InterleaveAndConvertBuffer(channelData.Elements(), c.mBufferFormat,
-                                     duration, c.mVolume,
-                                     outputChannels,
-                                     buf.Elements());
+          // Assumes that a bit pattern of zeroes == 0.0f
+          memset(buf.Elements(), 0, buf.Length()*sizeof(AudioDataValue));
         }
-      } else {
-        // Assumes that a bit pattern of zeroes == 0.0f
-        memset(buf.Elements(), 0, buf.Length()*sizeof(AudioDataValue));
+        aOutput->Write(buf.Elements(), int32_t(duration), &(c.mTimeStamp));
       }
-      aOutput->Write(buf.Elements(), int32_t(duration), &(c.mTimeStamp));
       if(!c.mTimeStamp.IsNull()) {
         TimeStamp now = TimeStamp::Now();
         // would be more efficient to c.mTimeStamp to ms on create time then pass here
         LogTime(AsyncLatencyLogger::AudioMediaStreamTrack, aID,
                 (now - c.mTimeStamp).ToMilliseconds(), c.mTimeStamp);
       }
       offset += duration;
     }
--- a/content/media/AudioStream.cpp
+++ b/content/media/AudioStream.cpp
@@ -139,16 +139,17 @@ static cubeb_stream_type ConvertChannelT
 #endif
 
 AudioStream::AudioStream()
 : mInRate(0),
   mOutRate(0),
   mChannels(0),
   mWritten(0),
   mAudioClock(MOZ_THIS_IN_INITIALIZER_LIST()),
+  mLatencyRequest(HighLatency),
   mReadPoint(0)
 {}
 
 void AudioStream::InitLibrary()
 {
 #ifdef PR_LOGGING
   gAudioStreamLog = PR_NewLogModule("AudioStream");
 #endif
@@ -359,16 +360,17 @@ private:
   }
 
   long DataCallback(void* aBuffer, long aFrames);
   void StateCallback(cubeb_state aState);
 
   // aTime is the time in ms the samples were inserted into MediaStreamGraph
   long GetUnprocessed(void* aBuffer, long aFrames, int64_t &aTime);
   long GetTimeStretched(void* aBuffer, long aFrames, int64_t &aTime);
+  long GetUnprocessedWithSilencePadding(void* aBuffer, long aFrames, int64_t &aTime);
 
   // Shared implementation of underflow adjusted position calculation.
   // Caller must own the monitor.
   int64_t GetPositionInFramesUnlocked();
 
   void StartUnlocked();
 
   // The monitor is held to protect all access to member variables.  Write()
@@ -572,16 +574,17 @@ BufferedAudioStream::Init(int32_t aNumCh
   if (!cubebContext || aNumChannels < 0 || aRate < 0) {
     return NS_ERROR_FAILURE;
   }
 
   PR_LOG(gAudioStreamLog, PR_LOG_DEBUG,
     ("%s  channels: %d, rate: %d", __FUNCTION__, aNumChannels, aRate));
   mInRate = mOutRate = aRate;
   mChannels = aNumChannels;
+  mLatencyRequest = aLatencyRequest;
 
   mDumpFile = OpenDumpFile(this);
 
   cubeb_stream_params params;
   params.rate = aRate;
   params.channels = aNumChannels;
 #if defined(__ANDROID__)
 #if defined(MOZ_B2G)
@@ -629,16 +632,23 @@ BufferedAudioStream::Init(int32_t aNumCh
 
   // Size mBuffer for one second of audio.  This value is arbitrary, and was
   // selected based on the observed behaviour of the existing AudioStream
   // implementations.
   uint32_t bufferLimit = FramesToBytes(aRate);
   NS_ABORT_IF_FALSE(bufferLimit % mBytesPerFrame == 0, "Must buffer complete frames");
   mBuffer.SetCapacity(bufferLimit);
 
+  // Start the stream right away when low latency has been requested. This means
+  // that the DataCallback will feed silence to cubeb, until the first frames
+  // are writtent to this BufferedAudioStream.
+  if (mLatencyRequest == AudioStream::LowLatency) {
+    Start();
+  }
+
   return NS_OK;
 }
 
 void
 BufferedAudioStream::Shutdown()
 {
   if (mState == STARTED) {
     Pause();
@@ -907,16 +917,42 @@ BufferedAudioStream::GetUnprocessed(void
 
   // First time block now has our first returned sample
   mReadPoint += BytesToFrames(available);
   GetBufferInsertTime(aTimeMs);
 
   return BytesToFrames(available) + flushedFrames;
 }
 
+// Get unprocessed samples, and pad the beginning of the buffer with silence if
+// there is not enough data.
+long
+BufferedAudioStream::GetUnprocessedWithSilencePadding(void* aBuffer, long aFrames, int64_t& aTimeMs)
+{
+  uint32_t toPopBytes = FramesToBytes(aFrames);
+  uint32_t available = std::min(toPopBytes, mBuffer.Length());
+  uint32_t silenceOffset = toPopBytes - available;
+
+  uint8_t* wpos = reinterpret_cast<uint8_t*>(aBuffer);
+
+  memset(wpos, 0, silenceOffset);
+  wpos += silenceOffset;
+
+  void* input[2];
+  uint32_t input_size[2];
+  mBuffer.PopElements(available, &input[0], &input_size[0], &input[1], &input_size[1]);
+  memcpy(wpos, input[0], input_size[0]);
+  wpos += input_size[0];
+  memcpy(wpos, input[1], input_size[1]);
+
+  GetBufferInsertTime(aTimeMs);
+
+  return aFrames;
+}
+
 long
 BufferedAudioStream::GetTimeStretched(void* aBuffer, long aFrames, int64_t &aTimeMs)
 {
   long processedFrames = 0;
 
   // We need to call the non-locking version, because we already have the lock.
   if (AudioStream::EnsureTimeStretcherInitialized() != NS_OK) {
     return 0;
@@ -960,18 +996,26 @@ BufferedAudioStream::DataCallback(void* 
   uint32_t available = std::min(static_cast<uint32_t>(FramesToBytes(aFrames)), mBuffer.Length());
   NS_ABORT_IF_FALSE(available % mBytesPerFrame == 0, "Must copy complete frames");
   AudioDataValue* output = reinterpret_cast<AudioDataValue*>(aBuffer);
   uint32_t underrunFrames = 0;
   uint32_t servicedFrames = 0;
   int64_t insertTime;
 
   if (available) {
+    // When we are playing a low latency stream, and it is the first time we are
+    // getting data from the buffer, we prefer to add the silence for an
+    // underrun at the beginning of the buffer, so the first buffer is not cut
+    // in half by the silence inserted to compensate for the underrun.
     if (mInRate == mOutRate) {
-      servicedFrames = GetUnprocessed(output, aFrames, insertTime);
+      if (mLatencyRequest == AudioStream::LowLatency && !mWritten) {
+        servicedFrames = GetUnprocessedWithSilencePadding(output, aFrames, insertTime);
+      } else {
+        servicedFrames = GetUnprocessed(output, aFrames, insertTime);
+      }
     } else {
       servicedFrames = GetTimeStretched(output, aFrames, insertTime);
     }
     float scaled_volume = float(GetVolumeScale() * mVolume);
 
     ScaleAudioSamples(output, aFrames * mChannels, scaled_volume);
 
     NS_ABORT_IF_FALSE(mBuffer.Length() % mBytesPerFrame == 0, "Must copy complete frames");
--- a/content/media/AudioStream.h
+++ b/content/media/AudioStream.h
@@ -202,16 +202,18 @@ protected:
   // Number of frames written to the buffers.
   int64_t mWritten;
   AudioClock mAudioClock;
   nsAutoPtr<soundtouch::SoundTouch> mTimeStretcher;
   nsRefPtr<AsyncLatencyLogger> mLatencyLog;
 
   // copy of Latency logger's starting time for offset calculations
   TimeStamp mStartTime;
+  // Whether we are playing a low latency stream, or a normal stream.
+  LatencyRequest mLatencyRequest;
   // Where in the current mInserts[0] block cubeb has read to
   int64_t mReadPoint;
   // Keep track of each inserted block of samples and the time it was inserted
   // so we can estimate the clock time for a specific sample's insertion (for when
   // we send data to cubeb).  Blocks are aged out as needed.
   struct Inserts {
     int64_t mTimeMs;
     int64_t mFrames;
--- a/content/svg/content/src/SVGSVGElement.cpp
+++ b/content/svg/content/src/SVGSVGElement.cpp
@@ -430,28 +430,16 @@ SVGSVGElement::CreateSVGTransform()
 
 already_AddRefed<SVGTransform>
 SVGSVGElement::CreateSVGTransformFromMatrix(SVGMatrix& matrix)
 {
   nsRefPtr<SVGTransform> transform = new SVGTransform(matrix.Matrix());
   return transform.forget();
 }
 
-Element*
-SVGSVGElement::GetElementById(const nsAString& elementId, ErrorResult& rv)
-{
-  nsAutoString selector(NS_LITERAL_STRING("#"));
-  nsStyleUtil::AppendEscapedCSSIdent(PromiseFlatString(elementId), selector);
-  nsIContent* element = QuerySelector(selector, rv);
-  if (!rv.Failed() && element) {
-    return element->AsElement();
-  }
-  return nullptr;
-}
-
 //----------------------------------------------------------------------
 
 already_AddRefed<SVGAnimatedRect>
 SVGSVGElement::ViewBox()
 {
   return mViewBox.ToSVGAnimatedRect(this);
 }
 
--- a/content/svg/content/src/SVGSVGElement.h
+++ b/content/svg/content/src/SVGSVGElement.h
@@ -241,17 +241,17 @@ public:
   already_AddRefed<nsIDOMSVGNumber> CreateSVGNumber();
   already_AddRefed<nsIDOMSVGLength> CreateSVGLength();
   already_AddRefed<SVGAngle> CreateSVGAngle();
   already_AddRefed<nsISVGPoint> CreateSVGPoint();
   already_AddRefed<SVGMatrix> CreateSVGMatrix();
   already_AddRefed<SVGIRect> CreateSVGRect();
   already_AddRefed<SVGTransform> CreateSVGTransform();
   already_AddRefed<SVGTransform> CreateSVGTransformFromMatrix(SVGMatrix& matrix);
-  Element* GetElementById(const nsAString& elementId, ErrorResult& rv);
+  using nsINode::GetElementById; // This does what we want
   already_AddRefed<SVGAnimatedRect> ViewBox();
   already_AddRefed<DOMSVGAnimatedPreserveAspectRatio> PreserveAspectRatio();
   uint16_t ZoomAndPan();
   void SetZoomAndPan(uint16_t aZoomAndPan, ErrorResult& rv);
 
 private:
   // nsSVGElement overrides
 
--- a/content/xbl/src/nsBindingManager.cpp
+++ b/content/xbl/src/nsBindingManager.cpp
@@ -87,17 +87,17 @@ static bool
 InitObjectEntry(PLDHashTable* table, PLDHashEntryHdr* entry, const void* key)
 {
   new (entry) ObjectEntry;
   return true;
 }
   
 
 
-static PLDHashTableOps ObjectTableOps = {
+static const PLDHashTableOps ObjectTableOps = {
   PL_DHashAllocTable,
   PL_DHashFreeTable,
   PL_DHashVoidPtrKeyStub,
   PL_DHashMatchEntryStub,
   PL_DHashMoveEntryStub,
   ClearObjectEntry,
   PL_DHashFinalizeStub,
   InitObjectEntry
--- a/content/xul/document/src/XULDocument.cpp
+++ b/content/xul/document/src/XULDocument.cpp
@@ -775,17 +775,17 @@ XULDocument::AddBroadcastListenerFor(Ele
 
     rv = nsContentUtils::CheckSameOrigin(this, &aListener);
 
     if (NS_FAILED(rv)) {
         aRv.Throw(rv);
         return;
     }
 
-    static PLDHashTableOps gOps = {
+    static const PLDHashTableOps gOps = {
         PL_DHashAllocTable,
         PL_DHashFreeTable,
         PL_DHashVoidPtrKeyStub,
         PL_DHashMatchEntryStub,
         PL_DHashMoveEntryStub,
         ClearBroadcasterMapEntry,
         PL_DHashFinalizeStub,
         nullptr
--- a/dom/base/nsScriptNameSpaceManager.cpp
+++ b/dom/base/nsScriptNameSpaceManager.cpp
@@ -332,17 +332,17 @@ nsScriptNameSpaceManager::RegisterInterf
   return NS_OK;
 }
 
 #define GLOBALNAME_HASHTABLE_INITIAL_SIZE	1024
 
 nsresult
 nsScriptNameSpaceManager::Init()
 {
-  static PLDHashTableOps hash_table_ops =
+  static const PLDHashTableOps hash_table_ops =
   {
     PL_DHashAllocTable,
     PL_DHashFreeTable,
     GlobalNameHashHashKey,
     GlobalNameHashMatchEntry,
     PL_DHashMoveEntryStub,
     GlobalNameHashClearEntry,
     PL_DHashFinalizeStub,
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -2162,16 +2162,23 @@ ThreadsafeCheckIsChrome(JSContext* aCx, 
 
 void
 TraceGlobal(JSTracer* aTrc, JSObject* aObj)
 {
   MOZ_ASSERT(js::GetObjectClass(aObj)->flags & JSCLASS_DOM_GLOBAL);
   mozilla::dom::TraceProtoAndIfaceCache(aTrc, aObj);
 }
 
+void
+FinalizeGlobal(JSFreeOp* aFreeOp, JSObject* aObj)
+{
+  MOZ_ASSERT(js::GetObjectClass(aObj)->flags & JSCLASS_DOM_GLOBAL);
+  mozilla::dom::DestroyProtoAndIfaceCache(aObj);
+}
+
 bool
 ResolveGlobal(JSContext* aCx, JS::Handle<JSObject*> aObj,
               JS::MutableHandle<jsid> aId, unsigned aFlags,
               JS::MutableHandle<JSObject*> aObjp)
 {
   bool resolved;
   if (!JS_ResolveStandardClass(aCx, aObj, aId, &resolved)) {
     return false;
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -15,16 +15,17 @@
 #include "mozilla/dom/DOMJSClass.h"
 #include "mozilla/dom/DOMJSProxyHandler.h"
 #include "mozilla/dom/Exceptions.h"
 #include "mozilla/dom/NonRefcountedDOMObject.h"
 #include "mozilla/dom/Nullable.h"
 #include "mozilla/dom/RootedDictionary.h"
 #include "mozilla/dom/workers/Workers.h"
 #include "mozilla/ErrorResult.h"
+#include "mozilla/HoldDropJSObjects.h"
 #include "mozilla/Likely.h"
 #include "mozilla/Util.h"
 #include "nsCycleCollector.h"
 #include "nsIXPConnect.h"
 #include "MainThreadUtils.h"
 #include "nsTraceRefcnt.h"
 #include "qsObjectHelper.h"
 #include "xpcpublic.h"
@@ -284,16 +285,21 @@ AllocateProtoAndIfaceCache(JSObject* obj
 {
   MOZ_ASSERT(js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL);
   MOZ_ASSERT(js::GetReservedSlot(obj, DOM_PROTOTYPE_SLOT).isUndefined());
 
   JS::Heap<JSObject*>* protoAndIfaceArray = new JS::Heap<JSObject*>[kProtoAndIfaceCacheCount];
 
   js::SetReservedSlot(obj, DOM_PROTOTYPE_SLOT,
                       JS::PrivateValue(protoAndIfaceArray));
+
+#ifdef NS_BUILD_REFCNT_LOGGING
+  NS_LogCtor((void*)protoAndIfaceArray, "ProtoAndIfaceArray",
+             sizeof(JS::Heap<JSObject*>) * kProtoAndIfaceCacheCount);
+#endif
 }
 
 inline void
 TraceProtoAndIfaceCache(JSTracer* trc, JSObject* obj)
 {
   MOZ_ASSERT(js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL);
 
   if (!HasProtoAndIfaceArray(obj))
@@ -308,16 +314,21 @@ TraceProtoAndIfaceCache(JSTracer* trc, J
 
 inline void
 DestroyProtoAndIfaceCache(JSObject* obj)
 {
   MOZ_ASSERT(js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL);
 
   JS::Heap<JSObject*>* protoAndIfaceArray = GetProtoAndIfaceArray(obj);
 
+#ifdef NS_BUILD_REFCNT_LOGGING
+  NS_LogDtor((void*)protoAndIfaceArray, "ProtoAndIfaceArray",
+             sizeof(JS::Heap<JSObject*>) * kProtoAndIfaceCacheCount);
+#endif
+
   delete [] protoAndIfaceArray;
 }
 
 /**
  * Add constants to an object.
  */
 bool
 DefineConstants(JSContext* cx, JS::Handle<JSObject*> obj,
@@ -2268,16 +2279,19 @@ public:
 };
 
 bool
 ThreadsafeCheckIsChrome(JSContext* aCx, JSObject* aObj);
 
 void
 TraceGlobal(JSTracer* aTrc, JSObject* aObj);
 
+void
+FinalizeGlobal(JSFreeOp* aFop, JSObject* aObj);
+
 bool
 ResolveGlobal(JSContext* aCx, JS::Handle<JSObject*> aObj,
               JS::MutableHandle<jsid> aId, unsigned aFlags,
               JS::MutableHandle<JSObject*> aObjp);
 
 bool
 EnumerateGlobal(JSContext* aCx, JS::Handle<JSObject*> aObj);
 
@@ -2318,15 +2332,17 @@ CreateGlobal(JSContext* aCx, T* aObject,
   JS::Handle<JSObject*> proto = ProtoGetter(aCx, global);
   NS_ENSURE_TRUE(proto, nullptr);
 
   if (!JS_SetPrototype(aCx, global, proto)) {
     NS_WARNING("Failed to set proto");
     return nullptr;
   }
 
+  mozilla::HoldJSObjects(aObject);
+
   return global;
 }
 
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_BindingUtils_h__ */
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -1079,16 +1079,18 @@ def finalizeHook(descriptor, hookName, c
     if descriptor.customFinalize:
         finalize = "self->%s(%s);" % (hookName, context)
     else:
         finalize = "JSBindingFinalized<%s>::Finalized(self);\n" % descriptor.nativeType
         if descriptor.wrapperCache:
             finalize += "ClearWrapper(self, self);\n"
         if descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
             finalize += "self->mExpandoAndGeneration.expando = JS::UndefinedValue();\n"
+        if descriptor.interface.getExtendedAttribute("Global"):
+            finalize += "mozilla::dom::FinalizeGlobal(fop, obj);\n"
         if descriptor.nativeOwnership == 'worker':
             finalize += "self->Release();"
         else:
             finalize += ("AddForDeferredFinalization<%s, %s >(self);" %
                 (descriptor.nativeType, DeferredFinalizeSmartPtr(descriptor)))
     return CGIfWrapper(CGGeneric(finalize), "self")
 
 class CGClassFinalizeHook(CGAbstractClassHook):
--- a/dom/plugins/base/android/ANPNativeWindow.cpp
+++ b/dom/plugins/base/android/ANPNativeWindow.cpp
@@ -21,15 +21,16 @@ using namespace mozilla;
 static ANPNativeWindow anp_native_window_acquireNativeWindow(NPP instance) {
   nsNPAPIPluginInstance* pinst = static_cast<nsNPAPIPluginInstance*>(instance->ndata);
   return pinst->AcquireContentWindow();
 }
 
 static void anp_native_window_invertPluginContent(NPP instance, bool isContentInverted) {
   nsNPAPIPluginInstance* pinst = static_cast<nsNPAPIPluginInstance*>(instance->ndata);
   pinst->SetInverted(isContentInverted);
+  pinst->RedrawPlugin();
 }
 
 
 void InitNativeWindowInterface(ANPNativeWindowInterfaceV0* i) {
     ASSIGN(i, acquireNativeWindow);
     ASSIGN(i, invertPluginContent);
 }
--- a/dom/plugins/base/nsJSNPRuntime.cpp
+++ b/dom/plugins/base/nsJSNPRuntime.cpp
@@ -988,17 +988,17 @@ nsJSObjWrapper::GetNewOrUsed(NPP npp, JS
 
     if (LookupNPP(npobj) == npp)
       return _retainobject(npobj);
   }
 
   if (!sJSObjWrappers.ops) {
     // No hash yet (or any more), initialize it.
 
-    static PLDHashTableOps ops =
+    static const PLDHashTableOps ops =
       {
         PL_DHashAllocTable,
         PL_DHashFreeTable,
         JSObjWrapperHash,
         JSObjWrapperHashMatchEntry,
         PL_DHashMoveEntryStub,
         PL_DHashClearEntryStub,
         PL_DHashFinalizeStub
--- a/dom/webidl/DocumentFragment.webidl
+++ b/dom/webidl/DocumentFragment.webidl
@@ -8,23 +8,17 @@
  * http://www.w3.org/TR/2012/WD-selectors-api-20120628/#interface-definitions
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
 [Constructor]
 interface DocumentFragment : Node {
-  // NEW
-  /*
-    FIXME: not implemented yet
-
-  void prepend((Node or DOMString)... nodes);
-  void append((Node or DOMString)... nodes);
-  */
+  Element? getElementById(DOMString elementId);
 };
 
 // http://www.w3.org/TR/2012/WD-selectors-api-20120628/#interface-definitions
 partial interface DocumentFragment {
   [Throws]
   Element?  querySelector(DOMString selectors);
   [Throws]
   NodeList  querySelectorAll(DOMString selectors);
--- a/dom/webidl/SVGSVGElement.webidl
+++ b/dom/webidl/SVGSVGElement.webidl
@@ -54,17 +54,16 @@ interface SVGSVGElement : SVGGraphicsEle
   [NewObject]
   SVGMatrix createSVGMatrix();
   [NewObject]
   SVGRect createSVGRect();
   [NewObject]
   SVGTransform createSVGTransform();
   [NewObject]
   SVGTransform createSVGTransformFromMatrix(SVGMatrix matrix);
-  [Throws]
   Element? getElementById(DOMString elementId);
 };
 
 /*SVGSVGElement implements ViewCSS;
 SVGSVGElement implements DocumentCSS;*/
 SVGSVGElement implements SVGFitToViewBox;
 SVGSVGElement implements SVGZoomAndPan;
 
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -4235,16 +4235,21 @@ WorkerPrivate::ResumeInternal(JSContext*
 void
 WorkerPrivate::TraceTimeouts(const TraceCallbacks& aCallbacks,
                              void* aClosure) const
 {
   AssertIsOnWorkerThread();
 
   for (uint32_t index = 0; index < mTimeouts.Length(); index++) {
     TimeoutInfo* info = mTimeouts[index];
+
+    if (info->mTimeoutCallable.isUndefined()) {
+      continue;
+    }
+
     aCallbacks.Trace(&info->mTimeoutCallable, "mTimeoutCallable", aClosure);
     for (uint32_t index2 = 0; index2 < info->mExtraArgVals.Length(); index2++) {
       aCallbacks.Trace(&info->mExtraArgVals[index2], "mExtraArgVals[i]", aClosure);
     }
   }
 }
 
 bool
--- a/dom/workers/WorkerScope.cpp
+++ b/dom/workers/WorkerScope.cpp
@@ -36,16 +36,18 @@ WorkerGlobalScope::WorkerGlobalScope(Wor
 {
   mWorkerPrivate->AssertIsOnWorkerThread();
 
   SetIsDOMBinding();
 }
 
 WorkerGlobalScope::~WorkerGlobalScope()
 {
+  // Matches the HoldJSObjects in CreateGlobal.
+  mozilla::DropJSObjects(this);
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(WorkerGlobalScope)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(WorkerGlobalScope,
                                                   nsDOMEventTargetHelper)
   tmp->mWorkerPrivate->AssertIsOnWorkerThread();
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
--- a/dom/workers/test/mochitest.ini
+++ b/dom/workers/test/mochitest.ini
@@ -40,16 +40,17 @@ support-files =
   terminate_worker.js
   testXHR.txt
   threadErrors_worker1.js
   threadErrors_worker2.js
   threadErrors_worker3.js
   threadErrors_worker4.js
   threadTimeouts_worker.js
   throwingOnerror_worker.js
+  timeoutTracing_worker.js
   transferable_worker.js
   urlApi_worker.js
   url_worker.js
   workersDisabled_worker.js
   xhr2_worker.js
   xhrAbort_worker.js
   xhr_implicit_cancel_worker.js
   xhr_worker.js
@@ -91,16 +92,17 @@ support-files =
 [test_rvals.html]
 [test_sharedWorker.html]
 [test_simpleThread.html]
 [test_suspend.html]
 [test_terminate.html]
 [test_threadErrors.html]
 [test_threadTimeouts.html]
 [test_throwingOnerror.html]
+[test_timeoutTracing.html]
 [test_transferable.html]
 [test_url.html]
 [test_urlApi.html]
 [test_workersDisabled.html]
 [test_xhr.html]
 [test_xhr2.html]
 [test_xhrAbort.html]
 [test_xhr_implicit_cancel.html]
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/test_timeoutTracing.html
@@ -0,0 +1,47 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE HTML>
+<html>
+<!--
+Tests of DOM Worker Threads
+-->
+<head>
+  <title>Test for DOM Worker Threads</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+  var worker = new Worker("timeoutTracing_worker.js");
+
+  worker.onmessage = function(event) {
+    // begin
+    worker.onmessage = null;
+
+    // 1 second should be enough to crash.
+    window.setTimeout(function(event) {
+      ok(true, "Didn't crash!");
+      SimpleTest.finish();
+    }, 1000);
+
+    var os = SpecialPowers.Cc["@mozilla.org/observer-service;1"]
+                          .getService(SpecialPowers.Ci.nsIObserverService);
+    os.notifyObservers(null, "memory-pressure", "heap-minimize");
+  }
+
+  worker.onerror = function(event) {
+    ok(false, "I was expecting a crash, not an error");
+    SimpleTest.finish();
+  };
+
+  SimpleTest.waitForExplicitFinish();
+
+</script>
+</pre>
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/timeoutTracing_worker.js
@@ -0,0 +1,13 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+onmessage = function(event) {
+  throw "No messages should reach me!";
+}
+
+setInterval(function() { postMessage("Still alive!"); }, 20);
+setInterval(";", 20);
+
+postMessage("Begin!");
--- a/embedding/components/commandhandler/src/nsCommandParams.cpp
+++ b/embedding/components/commandhandler/src/nsCommandParams.cpp
@@ -8,17 +8,17 @@
 #include "nscore.h"
 #include "nsCRT.h"
 
 #include "nsCommandParams.h"
 #include "mozilla/HashFunctions.h"
 
 using namespace mozilla;
 
-PLDHashTableOps nsCommandParams::sHashOps =
+const PLDHashTableOps nsCommandParams::sHashOps =
 {
     PL_DHashAllocTable,
     PL_DHashFreeTable,
     HashKey,
     HashMatchEntry,
     HashMoveEntry,
     HashClearEntry,
     PL_DHashFinalizeStub
--- a/embedding/components/commandhandler/src/nsCommandParams.h
+++ b/embedding/components/commandhandler/src/nsCommandParams.h
@@ -142,13 +142,13 @@ protected:
   // internally.
   
   PLDHashTable    mValuesHash;
   
   // enumerator data
   int32_t         mCurEntry;
   int32_t         mNumEntries;      // number of entries at start of enumeration (-1 indicates not known)
     
-  static PLDHashTableOps    sHashOps;
+  static const PLDHashTableOps    sHashOps;
 };
 
 
 #endif // nsCommandParams_h__
--- a/extensions/auth/nsAuthGSSAPI.cpp
+++ b/extensions/auth/nsAuthGSSAPI.cpp
@@ -35,16 +35,19 @@ typedef KLStatus (*KLCacheHasValidTicket
     KLPrincipal,
     KLKerberosVersion,
     KLBoolean *,
     KLPrincipal *,
     char **);
 #endif
 
 #if defined(HAVE_RES_NINIT)
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
 #include <resolv.h>
 #endif
 
 using namespace mozilla;
 
 //-----------------------------------------------------------------------------
 
 // We define GSS_C_NT_HOSTBASED_SERVICE explicitly since it may be referenced
--- a/extensions/cookie/nsPermissionManager.cpp
+++ b/extensions/cookie/nsPermissionManager.cpp
@@ -127,16 +127,30 @@ GetHostForPrincipal(nsIPrincipal* aPrinc
   uri = NS_GetInnermostURI(uri);
   NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE);
 
   rv = uri->GetAsciiHost(aHost);
   if (NS_SUCCEEDED(rv) && !aHost.IsEmpty()) {
     return NS_OK;
   }
 
+  // For the mailto scheme, we use the path of the URI. We have to chop off the
+  // query part if one exists, so we eliminate everything after a ?.
+  bool isMailTo = false;
+  if (NS_SUCCEEDED(uri->SchemeIs("mailto", &isMailTo)) && isMailTo) {
+    rv = uri->GetPath(aHost);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    int32_t spart = aHost.FindChar('?', 0);
+    if (spart >= 0) {
+      aHost.Cut(spart, aHost.Length() - spart);
+    }
+    return NS_OK;
+  }
+
   // Some entries like "file://" uses the origin.
   rv = aPrincipal->GetOrigin(getter_Copies(aHost));
   if (NS_SUCCEEDED(rv) && !aHost.IsEmpty()) {
     return NS_OK;
   }
 
   return NS_ERROR_UNEXPECTED;
 }
new file mode 100644
--- /dev/null
+++ b/extensions/cookie/test/unit/test_permmanager_mailto.js
@@ -0,0 +1,38 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function run_test() {
+  // initialize the permission manager service
+  const kTestAddr = "test@example.org";
+  const kType = "test-mailto";
+  const kCapability = 1;
+
+  // make a mailto: URI with parameters
+  let uri = Services.io.newURI("mailto:" + kTestAddr + "?subject=test", null,
+                               null);
+
+  // add a permission entry for that URI
+  Services.permissions.add(uri, kType, kCapability);
+  do_check_true(permission_exists(kTestAddr, kType, kCapability));
+
+  Services.permissions.removeAll();
+
+  uri = Services.io.newURI("mailto:" + kTestAddr, null, null);
+  Services.permissions.add(uri, kType, kCapability);
+  do_check_true(permission_exists(kTestAddr, kType, kCapability));
+
+  Services.permissions.removeAll();
+}
+
+function permission_exists(aHost, aType, aCapability) {
+  let e = Services.permissions.enumerator;
+  while (e.hasMoreElements()) {
+    let perm = e.getNext().QueryInterface(Ci.nsIPermission);
+    if (perm.host == aHost &&
+        perm.type == aType &&
+        perm.capability == aCapability) {
+      return true;
+    }
+  }
+  return false;
+}
--- a/extensions/cookie/test/unit/xpcshell.ini
+++ b/extensions/cookie/test/unit/xpcshell.ini
@@ -22,11 +22,12 @@ support-files =
 [test_permmanager_getPermissionObject.js]
 [test_permmanager_notifications.js]
 [test_permmanager_removeall.js]
 [test_permmanager_load_invalid_entries.js]
 skip-if = debug == true
 [test_permmanager_idn.js]
 [test_permmanager_subdomains.js]
 [test_permmanager_local_files.js]
+[test_permmanager_mailto.js]
 [test_permmanager_cleardata.js]
 [test_schema_2_migration.js]
 [test_schema_3_migration.js]
--- a/extensions/spellcheck/hunspell/src/moz.build
+++ b/extensions/spellcheck/hunspell/src/moz.build
@@ -1,15 +1,15 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-SOURCES += [
+UNIFIED_SOURCES += [
     'mozHunspell.cpp',
     'mozHunspellDirProvider.cpp',
 ]
 
 if not CONFIG['MOZ_NATIVE_HUNSPELL']:
     SOURCES += [
         'affentry.cpp',
         'affixmgr.cpp',
--- a/extensions/spellcheck/hunspell/src/mozHunspell.cpp
+++ b/extensions/spellcheck/hunspell/src/mozHunspell.cpp
@@ -73,17 +73,16 @@
 #include "nsCRT.h"
 #include "mozInlineSpellChecker.h"
 #include "mozilla/Services.h"
 #include <stdlib.h>
 #include "nsIMemoryReporter.h"
 #include "nsIPrefService.h"
 #include "nsIPrefBranch.h"
 
-static NS_DEFINE_CID(kCharsetConverterManagerCID, NS_ICHARSETCONVERTERMANAGER_CID);
 static NS_DEFINE_CID(kUnicharUtilCID, NS_UNICHARUTIL_CID);
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(mozHunspell)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(mozHunspell)
 
 NS_INTERFACE_MAP_BEGIN(mozHunspell)
   NS_INTERFACE_MAP_ENTRY(mozISpellCheckingEngine)
   NS_INTERFACE_MAP_ENTRY(nsIObserver)
--- a/extensions/spellcheck/src/moz.build
+++ b/extensions/spellcheck/src/moz.build
@@ -1,15 +1,15 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-SOURCES += [
+UNIFIED_SOURCES += [
     'mozEnglishWordUtils.cpp',
     'mozGenericWordUtils.cpp',
     'mozInlineSpellChecker.cpp',
     'mozInlineSpellWordUtil.cpp',
     'mozPersonalDictionary.cpp',
     'mozSpellChecker.cpp',
     'mozSpellCheckerFactory.cpp',
     'mozSpellI18NManager.cpp',
--- a/extensions/spellcheck/src/mozInlineSpellWordUtil.h
+++ b/extensions/spellcheck/src/mozInlineSpellWordUtil.h
@@ -1,13 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#ifndef mozInlineSpellWordUtil_h
+#define mozInlineSpellWordUtil_h
+
 #include "nsCOMPtr.h"
 #include "nsIDOMDocument.h"
 #include "nsIDocument.h"
 #include "nsString.h"
 #include "nsTArray.h"
 
 //#define DEBUG_SPELLCHECK
 
@@ -154,8 +157,10 @@ private:
   void BuildRealWords();
 
   void SplitDOMWord(int32_t aStart, int32_t aEnd);
 
   // Convenience functions, object must be initialized
   nsresult MakeRange(NodeOffset aBegin, NodeOffset aEnd, nsRange** aRange);
   nsresult MakeRangeForWord(const RealWord& aWord, nsRange** aRange);
 };
+
+#endif
--- a/extensions/spellcheck/src/mozPersonalDictionary.cpp
+++ b/extensions/spellcheck/src/mozPersonalDictionary.cpp
@@ -148,17 +148,17 @@ NS_IMETHODIMP mozPersonalDictionary::Sav
   //FIXME Deinst  -- get dictionary name from prefs;
   res = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(theFile));
   if(NS_FAILED(res)) return res;
   if(!theFile)return NS_ERROR_FAILURE;
   res = theFile->Append(NS_LITERAL_STRING(MOZ_PERSONAL_DICT_NAME));
   if(NS_FAILED(res)) return res;
 
   nsCOMPtr<nsIOutputStream> outStream;
-  NS_NewLocalFileOutputStream(getter_AddRefs(outStream), theFile, PR_CREATE_FILE | PR_WRONLY | PR_TRUNCATE ,0664);
+  NS_NewSafeLocalFileOutputStream(getter_AddRefs(outStream), theFile, PR_CREATE_FILE | PR_WRONLY | PR_TRUNCATE ,0664);
 
   // get a buffered output stream 4096 bytes big, to optimize writes
   nsCOMPtr<nsIOutputStream> bufferedOutputStream;
   res = NS_NewBufferedOutputStream(getter_AddRefs(bufferedOutputStream), outStream, 4096);
   if (NS_FAILED(res)) return res;
 
   nsTArray<nsString> array(mDictionaryTable.Count());
   mDictionaryTable.EnumerateEntries(AddHostToStringArray, &array);
@@ -166,16 +166,24 @@ NS_IMETHODIMP mozPersonalDictionary::Sav
   uint32_t bytesWritten;
   nsAutoCString utf8Key;
   for (uint32_t i = 0; i < array.Length(); ++i ) {
     CopyUTF16toUTF8(array[i], utf8Key);
 
     bufferedOutputStream->Write(utf8Key.get(), utf8Key.Length(), &bytesWritten);
     bufferedOutputStream->Write("\n", 1, &bytesWritten);
   }
+  nsCOMPtr<nsISafeOutputStream> safeStream = do_QueryInterface(bufferedOutputStream);
+  NS_ASSERTION(safeStream, "expected a safe output stream!");
+  if (safeStream) {
+    res = safeStream->Finish();
+    if (NS_FAILED(res)) {
+      NS_WARNING("failed to save personal dictionary file! possible data loss");
+    }
+  }
   return res;
 }
 
 /* readonly attribute nsIStringEnumerator GetWordList() */
 NS_IMETHODIMP mozPersonalDictionary::GetWordList(nsIStringEnumerator **aWords)
 {
   NS_ENSURE_ARG_POINTER(aWords);
   *aWords = nullptr;
--- a/gfx/2d/DrawTargetCG.h
+++ b/gfx/2d/DrawTargetCG.h
@@ -1,13 +1,16 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#ifndef mozilla_gfx_DrawTargetCG_h
+#define mozilla_gfx_DrawTargetCG_h
+
 #include <ApplicationServices/ApplicationServices.h>
 
 #include "2D.h"
 #include "Rect.h"
 #include "PathCG.h"
 #include "SourceSurfaceCG.h"
 #include "GLDefs.h"
 #include "Tools.h"
@@ -171,8 +174,11 @@ private:
    */
   AlignedArray<uint8_t> mData;
 
   RefPtr<SourceSurfaceCGContext> mSnapshot;
 };
 
 }
 }
+
+#endif
+
--- a/gfx/2d/PathCG.h
+++ b/gfx/2d/PathCG.h
@@ -90,17 +90,16 @@ public:
   virtual FillRule GetFillRule() const { return mFillRule; }
 
   CGMutablePathRef GetPath() const { return mPath; }
 
 private:
   friend class DrawTargetCG;
 
   CGMutablePathRef mPath;
-  bool mEndedActive;
   Point mEndPoint;
   FillRule mFillRule;
 };
 
 }
 }
 
 #endif
--- a/gfx/2d/RecordedEvent.cpp
+++ b/gfx/2d/RecordedEvent.cpp
@@ -272,17 +272,17 @@ RecordedDrawingEvent::RecordedDrawingEve
 
 void
 RecordedDrawingEvent::RecordToStream(ostream &aStream) const
 {
   WriteElement(aStream, mDT);
 }
 
 ReferencePtr
-RecordedDrawingEvent::GetObject() const
+RecordedDrawingEvent::GetObjectRef() const
 {
   return mDT;
 }
 
 void
 RecordedDrawTargetCreation::PlayEvent(Translator *aTranslator) const
 {
   RefPtr<DrawTarget> newDT =
--- a/gfx/2d/RecordedEvent.h
+++ b/gfx/2d/RecordedEvent.h
@@ -173,17 +173,17 @@ public:
   void RecordPatternData(std::ostream &aStream, const PatternStorage &aPatternStorage) const;
   void ReadPatternData(std::istream &aStream, PatternStorage &aPatternStorage) const;
   void StorePattern(PatternStorage &aDestination, const Pattern &aSource) const;
   void RecordStrokeOptions(std::ostream &aStream, const StrokeOptions &aStrokeOptions) const;
   void ReadStrokeOptions(std::istream &aStream, StrokeOptions &aStrokeOptions);
 
   virtual std::string GetName() const = 0;
 
-  virtual ReferencePtr GetObject() const = 0;
+  virtual ReferencePtr GetObjectRef() const = 0;
 
   virtual ReferencePtr GetDestinedDT() { return nullptr; }
 
   void OutputSimplePatternInfo(const PatternStorage &aStorage, std::stringstream &aOutput) const;
 
   static RecordedEvent *LoadEventFromStream(std::istream &aStream, EventType aType);
 
   EventType GetType() { return (EventType)mType; }
@@ -206,34 +206,34 @@ protected:
   RecordedDrawingEvent(EventType aType, DrawTarget *aTarget)
     : RecordedEvent(aType), mDT(aTarget)
   {
   }
 
   RecordedDrawingEvent(EventType aType, std::istream &aStream);
   virtual void RecordToStream(std::ostream &aStream) const;
 
-  virtual ReferencePtr GetObject() const;
+  virtual ReferencePtr GetObjectRef() const;
 
   ReferencePtr mDT;
 };
 
 class RecordedDrawTargetCreation : public RecordedEvent {
 public:
   RecordedDrawTargetCreation(ReferencePtr aRefPtr, BackendType aType, const IntSize &aSize, SurfaceFormat aFormat)
     : RecordedEvent(DRAWTARGETCREATION), mRefPtr(aRefPtr), mBackendType(aType), mSize(aSize), mFormat(aFormat)
   {}
 
   virtual void PlayEvent(Translator *aTranslator) const;
 
   virtual void RecordToStream(std::ostream &aStream) const;
   virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const;
 
   virtual std::string GetName() const { return "DrawTarget Creation"; }
-  virtual ReferencePtr GetObject() const { return mRefPtr; }
+  virtual ReferencePtr GetObjectRef() const { return mRefPtr; }
 
   ReferencePtr mRefPtr;
   BackendType mBackendType;
   IntSize mSize;
   SurfaceFormat mFormat;
   
 private:
   friend class RecordedEvent;
@@ -248,17 +248,17 @@ public:
   {}
 
   virtual void PlayEvent(Translator *aTranslator) const;
 
   virtual void RecordToStream(std::ostream &aStream) const;
   virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const;
 
   virtual std::string GetName() const { return "DrawTarget Destruction"; }
-  virtual ReferencePtr GetObject() const { return mRefPtr; }
+  virtual ReferencePtr GetObjectRef() const { return mRefPtr; }
 
   ReferencePtr mRefPtr;
 
   BackendType mBackendType;
 private:
   friend class RecordedEvent;
 
   RecordedDrawTargetDestruction(std::istream &aStream);
@@ -641,17 +641,17 @@ public:
   ~RecordedPathCreation();
   
   virtual void PlayEvent(Translator *aTranslator) const;
 
   virtual void RecordToStream(std::ostream &aStream) const;
   virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const;
   
   virtual std::string GetName() const { return "Path Creation"; }
-  virtual ReferencePtr GetObject() const { return mRefPtr; }
+  virtual ReferencePtr GetObjectRef() const { return mRefPtr; }
 private:
   friend class RecordedEvent;
 
   ReferencePtr mRefPtr;
   FillRule mFillRule;
   std::vector<PathOp> mPathOps;
 
   RecordedPathCreation(std::istream &aStream);
@@ -665,17 +665,17 @@ public:
   }
   
   virtual void PlayEvent(Translator *aTranslator) const;
 
   virtual void RecordToStream(std::ostream &aStream) const;
   virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const;
   
   virtual std::string GetName() const { return "Path Destruction"; }
-  virtual ReferencePtr GetObject() const { return mRefPtr; }
+  virtual ReferencePtr GetObjectRef() const { return mRefPtr; }
 private:
   friend class RecordedEvent;
 
   ReferencePtr mRefPtr;
 
   RecordedPathDestruction(std::istream &aStream);
 };
 
@@ -691,17 +691,17 @@ public:
   ~RecordedSourceSurfaceCreation();
 
   virtual void PlayEvent(Translator *aTranslator) const;
 
   virtual void RecordToStream(std::ostream &aStream) const;
   virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const;
   
   virtual std::string GetName() const { return "SourceSurface Creation"; }
-  virtual ReferencePtr GetObject() const { return mRefPtr; }
+  virtual ReferencePtr GetObjectRef() const { return mRefPtr; }
 private:
   friend class RecordedEvent;
 
   ReferencePtr mRefPtr;
   uint8_t *mData;
   int32_t mStride;
   IntSize mSize;
   SurfaceFormat mFormat;
@@ -718,17 +718,17 @@ public:
   }
 
   virtual void PlayEvent(Translator *aTranslator) const;
 
   virtual void RecordToStream(std::ostream &aStream) const;
   virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const;
   
   virtual std::string GetName() const { return "SourceSurface Destruction"; }
-  virtual ReferencePtr GetObject() const { return mRefPtr; }
+  virtual ReferencePtr GetObjectRef() const { return mRefPtr; }
 private:
   friend class RecordedEvent;
 
   ReferencePtr mRefPtr;
 
   RecordedSourceSurfaceDestruction(std::istream &aStream);
 };
 
@@ -744,17 +744,17 @@ public:
   ~RecordedGradientStopsCreation();
 
   virtual void PlayEvent(Translator *aTranslator) const;
 
   virtual void RecordToStream(std::ostream &aStream) const;
   virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const;
   
   virtual std::string GetName() const { return "GradientStops Creation"; }
-  virtual ReferencePtr GetObject() const { return mRefPtr; }
+  virtual ReferencePtr GetObjectRef() const { return mRefPtr; }
 private:
   friend class RecordedEvent;
 
   ReferencePtr mRefPtr;
   GradientStop *mStops;
   uint32_t mNumStops;
   ExtendMode mExtendMode;
   bool mDataOwned;
@@ -770,17 +770,17 @@ public:
   }
 
   virtual void PlayEvent(Translator *aTranslator) const;
 
   virtual void RecordToStream(std::ostream &aStream) const;
   virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const;
   
   virtual std::string GetName() const { return "GradientStops Destruction"; }
-  virtual ReferencePtr GetObject() const { return mRefPtr; }
+  virtual ReferencePtr GetObjectRef() const { return mRefPtr; }
 private:
   friend class RecordedEvent;
 
   ReferencePtr mRefPtr;
 
   RecordedGradientStopsDestruction(std::istream &aStream);
 };
 
@@ -792,17 +792,17 @@ public:
   }
 
   virtual void PlayEvent(Translator *aTranslator) const;
 
   virtual void RecordToStream(std::ostream &aStream) const;
   virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const;
   
   virtual std::string GetName() const { return "Snapshot"; }
-  virtual ReferencePtr GetObject() const { return mRefPtr; }
+  virtual ReferencePtr GetObjectRef() const { return mRefPtr; }
 private:
   friend class RecordedEvent;
 
   ReferencePtr mRefPtr;
   ReferencePtr mDT;
 
   RecordedSnapshot(std::istream &aStream);
 };
@@ -823,17 +823,17 @@ public:
   ~RecordedScaledFontCreation();
 
   virtual void PlayEvent(Translator *aTranslator) const;
 
   virtual void RecordToStream(std::ostream &aStream) const;
   virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const;
   
   virtual std::string GetName() const { return "ScaledFont Creation"; }
-  virtual ReferencePtr GetObject() const { return mRefPtr; }
+  virtual ReferencePtr GetObjectRef() const { return mRefPtr; }
 
   void SetFontData(const uint8_t *aData, uint32_t aSize, uint32_t aIndex, Float aGlyphSize);
 
 private:
   friend class RecordedEvent;
 
   ReferencePtr mRefPtr;
   uint8_t *mData;
@@ -852,17 +852,17 @@ public:
   }
 
   virtual void PlayEvent(Translator *aTranslator) const;
 
   virtual void RecordToStream(std::ostream &aStream) const;
   virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const;
   
   virtual std::string GetName() const { return "ScaledFont Destruction"; }
-  virtual ReferencePtr GetObject() const { return mRefPtr; }
+  virtual ReferencePtr GetObjectRef() const { return mRefPtr; }
 private:
   friend class RecordedEvent;
 
   ReferencePtr mRefPtr;
 
   RecordedScaledFontDestruction(std::istream &aStream);
 };
 
--- a/gfx/2d/moz.build
+++ b/gfx/2d/moz.build
@@ -31,17 +31,17 @@ EXPORTS.mozilla.gfx += [
     'UserData.h',
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
     EXPORTS.mozilla.gfx += [
         'MacIOSurface.h',
         'QuartzSupport.h',
     ]
-    SOURCES += [
+    UNIFIED_SOURCES += [
         'DrawTargetCG.cpp',
         'PathCG.cpp',
         'ScaledFontMac.cpp',
         'SourceSurfaceCG.cpp',
     ]
 elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
     SOURCES += [
         'DrawTargetD2D.cpp',
@@ -57,34 +57,36 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'wi
             'SourceSurfaceD2D1.cpp'
         ]
     if CONFIG['MOZ_ENABLE_SKIA']:
         SOURCES += [
             'ScaledFontWin.cpp',
         ]
 
 if CONFIG['MOZ_ENABLE_SKIA']:
-    SOURCES += [
+    UNIFIED_SOURCES += [
         'convolver.cpp',
         'DrawTargetSkia.cpp',
-        'image_operations.cpp',
         'PathSkia.cpp',
         'SourceSurfaceSkia.cpp',
     ]
+    SOURCES += [
+        'image_operations.cpp', # Uses _USE_MATH_DEFINES
+    ]
 
 # Are we targeting x86 or x64?  If so, build SSE2 files.
 if CONFIG['INTEL_ARCHITECTURE']:
     # VC2005 doesn't support _mm_castsi128_ps, so SSE2 is turned off
     if CONFIG['_MSC_VER'] != '1400':
         SOURCES += [
             'BlurSSE2.cpp',
             'ImageScalingSSE2.cpp',
         ]
 
-SOURCES += [
+UNIFIED_SOURCES += [
     'Blur.cpp',
     'DrawEventRecorder.cpp',
     'DrawTargetCairo.cpp',
     'DrawTargetDual.cpp',
     'DrawTargetRecording.cpp',
     'Factory.cpp',
     'ImageScaling.cpp',
     'Matrix.cpp',
--- a/gfx/cairo/cairo/src/cairo-rename.h
+++ b/gfx/cairo/cairo/src/cairo-rename.h
@@ -357,135 +357,9 @@
 #define cairo_xlib_surface_get_drawable _moz_cairo_xlib_surface_get_drawable
 #define cairo_xlib_surface_get_height _moz_cairo_xlib_surface_get_height
 #define cairo_xlib_surface_get_screen _moz_cairo_xlib_surface_get_screen
 #define cairo_xlib_surface_get_visual _moz_cairo_xlib_surface_get_visual
 #define cairo_xlib_surface_get_width _moz_cairo_xlib_surface_get_width
 #define cairo_xlib_surface_get_xrender_format _moz_cairo_xlib_surface_get_xrender_format
 #define cairo_xlib_surface_set_drawable _moz_cairo_xlib_surface_set_drawable
 #define cairo_xlib_surface_set_size _moz_cairo_xlib_surface_set_size
-#ifdef MOZ_TREE_PIXMAN
-#define pixman_region_set_static_pointers _moz_pixman_region_set_static_pointers
-#define pixman_region_init _moz_pixman_region_init
-#define pixman_region_init_rect _moz_pixman_region_init_rect
-#define pixman_region_init_rects _moz_pixman_region_init_rects
-#define pixman_region_init_with_extents _moz_pixman_region_init_with_extents
-#define pixman_region_fini _moz_pixman_region_fini
-#define pixman_region_translate _moz_pixman_region_translate
-#define pixman_region_copy _moz_pixman_region_copy
-#define pixman_region_intersect _moz_pixman_region_intersect
-#define pixman_region_union _moz_pixman_region_union
-#define pixman_region_union_rect _moz_pixman_region_union_rect
-#define pixman_region_subtract _moz_pixman_region_subtract
-#define pixman_region_inverse _moz_pixman_region_inverse
-#define pixman_region_contains_point _moz_pixman_region_contains_point
-#define pixman_region_contains_rectangle _moz_pixman_region_contains_rectangle
-#define pixman_region_not_empty _moz_pixman_region_not_empty
-#define pixman_region_extents _moz_pixman_region_extents
-#define pixman_region_n_rects _moz_pixman_region_n_rects
-#define pixman_region_rectangles _moz_pixman_region_rectangles
-#define pixman_region_equal _moz_pixman_region_equal
-#define pixman_region_selfcheck _moz_pixman_region_selfcheck
-#define pixman_region_reset _moz_pixman_region_reset
-#define pixman_region32_init _moz_pixman_region32_init
-#define pixman_region32_init_rect _moz_pixman_region32_init_rect
-#define pixman_region32_init_rects _moz_pixman_region32_init_rects
-#define pixman_region32_init_with_extents _moz_pixman_region32_init_with_extents
-#define pixman_region32_fini _moz_pixman_region32_fini
-#define pixman_region32_translate _moz_pixman_region32_translate
-#define pixman_region32_copy _moz_pixman_region32_copy
-#define pixman_region32_intersect _moz_pixman_region32_intersect
-#define pixman_region32_union _moz_pixman_region32_union
-#define pixman_region32_union_rect _moz_pixman_region32_union_rect
-#define pixman_region32_subtract _moz_pixman_region32_subtract
-#define pixman_region32_inverse _moz_pixman_region32_inverse
-#define pixman_region32_contains_point _moz_pixman_region32_contains_point
-#define pixman_region32_contains_rectangle _moz_pixman_region32_contains_rectangle
-#define pixman_region32_not_empty _moz_pixman_region32_not_empty
-#define pixman_region32_extents _moz_pixman_region32_extents
-#define pixman_region32_n_rects _moz_pixman_region32_n_rects
-#define pixman_region32_rectangles _moz_pixman_region32_rectangles
-#define pixman_region32_equal _moz_pixman_region32_equal
-#define pixman_region32_selfcheck _moz_pixman_region32_selfcheck
-#define pixman_region32_reset _moz_pixman_region32_reset
-#define pixman_blt _moz_pixman_blt
-#define pixman_fill _moz_pixman_fill
-#define pixman_transform_point_3d _moz_pixman_transform_point_3d
-#define pixman_version _moz_pixman_version
-#define pixman_version_string _moz_pixman_version_string
-#define pixman_format_supported_destination _moz_pixman_format_supported_destination
-#define pixman_format_supported_source _moz_pixman_format_supported_source
-#define pixman_image_create_solid_fill _moz_pixman_image_create_solid_fill
-#define pixman_image_create_linear_gradient _moz_pixman_image_create_linear_gradient
-#define pixman_image_create_radial_gradient _moz_pixman_image_create_radial_gradient
-#define pixman_image_create_conical_gradient _moz_pixman_image_create_conical_gradient
-#define pixman_image_create_bits _moz_pixman_image_create_bits
-#define pixman_image_ref _moz_pixman_image_ref
-#define pixman_image_unref _moz_pixman_image_unref
-#define pixman_image_set_clip_region _moz_pixman_image_set_clip_region
-#define pixman_image_set_clip_region32 _moz_pixman_image_set_clip_region32
-#define pixman_image_set_has_client_clip _moz_pixman_image_set_has_client_clip
-#define pixman_image_set_transform _moz_pixman_image_set_transform
-#define pixman_image_set_repeat _moz_pixman_image_set_repeat
-#define pixman_image_set_filter _moz_pixman_image_set_filter
-#define pixman_image_set_source_clipping _moz_pixman_image_set_source_clipping
-#define pixman_image_set_alpha_map _moz_pixman_image_set_alpha_map
-#define pixman_image_set_component_alpha _moz_pixman_image_set_component_alpha
-#define pixman_image_set_accessors	 _moz_pixman_image_set_accessors	
-#define pixman_image_set_indexed	 _moz_pixman_image_set_indexed	
-#define pixman_image_get_data _moz_pixman_image_get_data
-#define pixman_image_get_width _moz_pixman_image_get_width
-#define pixman_image_get_height _moz_pixman_image_get_height
-#define pixman_image_get_stride _moz_pixman_image_get_stride
-#define pixman_image_get_depth _moz_pixman_image_get_depth
-#define pixman_image_fill_rectangles	 _moz_pixman_image_fill_rectangles	
-#define pixman_compute_composite_region _moz_pixman_compute_composite_region
-#define pixman_image_composite _moz_pixman_image_composite
-#define pixman_sample_ceil_y _moz_pixman_sample_ceil_y
-#define pixman_sample_floor_y _moz_pixman_sample_floor_y
-#define pixman_edge_step _moz_pixman_edge_step
-#define pixman_edge_init _moz_pixman_edge_init
-#define pixman_line_fixed_edge_init _moz_pixman_line_fixed_edge_init
-#define pixman_rasterize_edges _moz_pixman_rasterize_edges
-#define pixman_add_traps _moz_pixman_add_traps
-#define pixman_add_trapezoids _moz_pixman_add_trapezoids
-#define pixman_rasterize_trapezoid _moz_pixman_rasterize_trapezoid
-#define pixman_disable_out_of_bounds_workaround _moz_pixman_disable_out_of_bounds_workaround
-#define pixman_f_transform_bounds _moz_pixman_f_transform_bounds
-#define pixman_f_transform_from_pixman_transform _moz_pixman_f_transform_from_pixman_transform
-#define pixman_f_transform_init_identity _moz_pixman_f_transform_init_identity
-#define pixman_f_transform_init_rotate _moz_pixman_f_transform_init_rotate
-#define pixman_f_transform_init_scale _moz_pixman_f_transform_init_scale
-#define pixman_f_transform_init_translate _moz_pixman_f_transform_init_translate
-#define pixman_f_transform_invert _moz_pixman_f_transform_invert
-#define pixman_f_transform_multiply _moz_pixman_f_transform_multiply
-#define pixman_f_transform_point _moz_pixman_f_transform_point
-#define pixman_f_transform_point_3d _moz_pixman_f_transform_point_3d
-#define pixman_f_transform_rotate _moz_pixman_f_transform_rotate
-#define pixman_f_transform_scale _moz_pixman_f_transform_scale
-#define pixman_f_transform_translate _moz_pixman_f_transform_translate
-#define pixman_image_composite32 _moz_pixman_image_composite32
-#define pixman_image_fill_boxes _moz_pixman_image_fill_boxes
-#define pixman_image_get_component_alpha _moz_pixman_image_get_component_alpha
-#define pixman_image_get_destroy_data _moz_pixman_image_get_destroy_data
-#define pixman_image_get_format _moz_pixman_image_get_format
-#define pixman_image_set_destroy_function _moz_pixman_image_set_destroy_function
-#define pixman_region_init_from_image _moz_pixman_region_init_from_image
-#define pixman_region_intersect_rect _moz_pixman_region_intersect_rect
-#define pixman_region32_init_from_image _moz_pixman_region32_init_from_image
-#define pixman_region32_intersect_rect _moz_pixman_region32_intersect_rect
-#define pixman_transform_bounds _moz_pixman_transform_bounds
-#define pixman_transform_from_pixman_f_transform _moz_pixman_transform_from_pixman_f_transform
-#define pixman_transform_init_identity _moz_pixman_transform_init_identity
-#define pixman_transform_init_rotate _moz_pixman_transform_init_rotate
-#define pixman_transform_init_scale _moz_pixman_transform_init_scale
-#define pixman_transform_init_translate _moz_pixman_transform_init_translate
-#define pixman_transform_invert _moz_pixman_transform_invert
-#define pixman_transform_is_identity _moz_pixman_transform_is_identity
-#define pixman_transform_is_int_translate _moz_pixman_transform_is_int_translate
-#define pixman_transform_is_inverse _moz_pixman_transform_is_inverse
-#define pixman_transform_is_scale _moz_pixman_transform_is_scale
-#define pixman_transform_multiply _moz_pixman_transform_multiply
-#define pixman_transform_point _moz_pixman_transform_point
-#define pixman_transform_rotate _moz_pixman_transform_rotate
-#define pixman_transform_scale _moz_pixman_transform_scale
-#define pixman_transform_translate _moz_pixman_transform_translate
-#endif
+#include "pixman-rename.h"
--- a/gfx/cairo/cairo/src/moz.build
+++ b/gfx/cairo/cairo/src/moz.build
@@ -8,16 +8,17 @@ CONFIGURE_SUBST_FILES += ['cairo-feature
 
 EXPORTS.cairo += [
     'cairo-deprecated.h',
     'cairo-platform.h',
     'cairo-rename.h',
     'cairo-tee.h',
     'cairo-version.h',
     'cairo.h',
+    'pixman-rename.h',
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] not in ('cocoa', 'uikit'):
     EXPORTS.cairo += [
         'cairo-pdf.h',
     ]
     SOURCES += [
         'cairo-base85-stream.c',
new file mode 100644
--- /dev/null
+++ b/gfx/cairo/cairo/src/pixman-rename.h
@@ -0,0 +1,128 @@
+#ifdef MOZ_TREE_PIXMAN
+#define pixman_region_set_static_pointers _moz_pixman_region_set_static_pointers
+#define pixman_region_init _moz_pixman_region_init
+#define pixman_region_init_rect _moz_pixman_region_init_rect
+#define pixman_region_init_rects _moz_pixman_region_init_rects
+#define pixman_region_init_with_extents _moz_pixman_region_init_with_extents
+#define pixman_region_fini _moz_pixman_region_fini
+#define pixman_region_translate _moz_pixman_region_translate
+#define pixman_region_copy _moz_pixman_region_copy
+#define pixman_region_intersect _moz_pixman_region_intersect
+#define pixman_region_union _moz_pixman_region_union
+#define pixman_region_union_rect _moz_pixman_region_union_rect
+#define pixman_region_subtract _moz_pixman_region_subtract
+#define pixman_region_inverse _moz_pixman_region_inverse
+#define pixman_region_contains_point _moz_pixman_region_contains_point
+#define pixman_region_contains_rectangle _moz_pixman_region_contains_rectangle
+#define pixman_region_not_empty _moz_pixman_region_not_empty
+#define pixman_region_extents _moz_pixman_region_extents
+#define pixman_region_n_rects _moz_pixman_region_n_rects
+#define pixman_region_rectangles _moz_pixman_region_rectangles
+#define pixman_region_equal _moz_pixman_region_equal
+#define pixman_region_selfcheck _moz_pixman_region_selfcheck
+#define pixman_region_reset _moz_pixman_region_reset
+#define pixman_region32_init _moz_pixman_region32_init
+#define pixman_region32_init_rect _moz_pixman_region32_init_rect
+#define pixman_region32_init_rects _moz_pixman_region32_init_rects
+#define pixman_region32_init_with_extents _moz_pixman_region32_init_with_extents
+#define pixman_region32_init_from_image _moz_pixman_region32_init_from_image
+#define pixman_region32_fini _moz_pixman_region32_fini
+#define pixman_region32_translate _moz_pixman_region32_translate
+#define pixman_region32_copy _moz_pixman_region32_copy
+#define pixman_region32_intersect _moz_pixman_region32_intersect
+#define pixman_region32_intersect_rect _moz_pixman_region32_intersect_rect
+#define pixman_region32_union _moz_pixman_region32_union
+#define pixman_region32_union_rect _moz_pixman_region32_union_rect
+#define pixman_region32_subtract _moz_pixman_region32_subtract
+#define pixman_region32_inverse _moz_pixman_region32_inverse
+#define pixman_region32_contains_point _moz_pixman_region32_contains_point
+#define pixman_region32_contains_rectangle _moz_pixman_region32_contains_rectangle
+#define pixman_region32_not_empty _moz_pixman_region32_not_empty
+#define pixman_region32_extents _moz_pixman_region32_extents
+#define pixman_region32_n_rects _moz_pixman_region32_n_rects
+#define pixman_region32_rectangles _moz_pixman_region32_rectangles
+#define pixman_region32_equal _moz_pixman_region32_equal
+#define pixman_region32_selfcheck _moz_pixman_region32_selfcheck
+#define pixman_region32_reset _moz_pixman_region32_reset
+#define pixman_region32_clear _moz_pixman_region32_clear
+#define pixman_blt _moz_pixman_blt
+#define pixman_fill _moz_pixman_fill
+#define pixman_transform_point_3d _moz_pixman_transform_point_3d
+#define pixman_version _moz_pixman_version
+#define pixman_version_string _moz_pixman_version_string
+#define pixman_format_supported_destination _moz_pixman_format_supported_destination
+#define pixman_format_supported_source _moz_pixman_format_supported_source
+#define pixman_image_create_solid_fill _moz_pixman_image_create_solid_fill
+#define pixman_image_create_linear_gradient _moz_pixman_image_create_linear_gradient
+#define pixman_image_create_radial_gradient _moz_pixman_image_create_radial_gradient
+#define pixman_image_create_conical_gradient _moz_pixman_image_create_conical_gradient
+#define pixman_image_create_bits _moz_pixman_image_create_bits
+#define pixman_image_ref _moz_pixman_image_ref
+#define pixman_image_unref _moz_pixman_image_unref
+#define pixman_image_set_clip_region _moz_pixman_image_set_clip_region
+#define pixman_image_set_clip_region32 _moz_pixman_image_set_clip_region32
+#define pixman_image_set_has_client_clip _moz_pixman_image_set_has_client_clip
+#define pixman_image_set_transform _moz_pixman_image_set_transform
+#define pixman_image_set_repeat _moz_pixman_image_set_repeat
+#define pixman_image_set_filter _moz_pixman_image_set_filter
+#define pixman_image_set_source_clipping _moz_pixman_image_set_source_clipping
+#define pixman_image_set_alpha_map _moz_pixman_image_set_alpha_map
+#define pixman_image_set_component_alpha _moz_pixman_image_set_component_alpha
+#define pixman_image_set_accessors	 _moz_pixman_image_set_accessors	
+#define pixman_image_set_indexed	 _moz_pixman_image_set_indexed	
+#define pixman_image_get_data _moz_pixman_image_get_data
+#define pixman_image_get_width _moz_pixman_image_get_width
+#define pixman_image_get_height _moz_pixman_image_get_height
+#define pixman_image_get_stride _moz_pixman_image_get_stride
+#define pixman_image_get_depth _moz_pixman_image_get_depth
+#define pixman_image_fill_rectangles	 _moz_pixman_image_fill_rectangles	
+#define pixman_compute_composite_region _moz_pixman_compute_composite_region
+#define pixman_image_composite _moz_pixman_image_composite
+#define pixman_sample_ceil_y _moz_pixman_sample_ceil_y
+#define pixman_sample_floor_y _moz_pixman_sample_floor_y
+#define pixman_edge_step _moz_pixman_edge_step
+#define pixman_edge_init _moz_pixman_edge_init
+#define pixman_line_fixed_edge_init _moz_pixman_line_fixed_edge_init
+#define pixman_rasterize_edges _moz_pixman_rasterize_edges
+#define pixman_add_traps _moz_pixman_add_traps
+#define pixman_add_trapezoids _moz_pixman_add_trapezoids
+#define pixman_rasterize_trapezoid _moz_pixman_rasterize_trapezoid
+#define pixman_disable_out_of_bounds_workaround _moz_pixman_disable_out_of_bounds_workaround
+#define pixman_f_transform_bounds _moz_pixman_f_transform_bounds
+#define pixman_f_transform_from_pixman_transform _moz_pixman_f_transform_from_pixman_transform
+#define pixman_f_transform_init_identity _moz_pixman_f_transform_init_identity
+#define pixman_f_transform_init_rotate _moz_pixman_f_transform_init_rotate
+#define pixman_f_transform_init_scale _moz_pixman_f_transform_init_scale
+#define pixman_f_transform_init_translate _moz_pixman_f_transform_init_translate
+#define pixman_f_transform_invert _moz_pixman_f_transform_invert
+#define pixman_f_transform_multiply _moz_pixman_f_transform_multiply
+#define pixman_f_transform_point _moz_pixman_f_transform_point
+#define pixman_f_transform_point_3d _moz_pixman_f_transform_point_3d
+#define pixman_f_transform_rotate _moz_pixman_f_transform_rotate
+#define pixman_f_transform_scale _moz_pixman_f_transform_scale
+#define pixman_f_transform_translate _moz_pixman_f_transform_translate
+#define pixman_image_composite32 _moz_pixman_image_composite32
+#define pixman_image_fill_boxes _moz_pixman_image_fill_boxes
+#define pixman_image_get_component_alpha _moz_pixman_image_get_component_alpha
+#define pixman_image_get_destroy_data _moz_pixman_image_get_destroy_data
+#define pixman_image_get_format _moz_pixman_image_get_format
+#define pixman_image_set_destroy_function _moz_pixman_image_set_destroy_function
+#define pixman_region_init_from_image _moz_pixman_region_init_from_image
+#define pixman_region_intersect_rect _moz_pixman_region_intersect_rect
+#define pixman_transform_bounds _moz_pixman_transform_bounds
+#define pixman_transform_from_pixman_f_transform _moz_pixman_transform_from_pixman_f_transform
+#define pixman_transform_init_identity _moz_pixman_transform_init_identity
+#define pixman_transform_init_rotate _moz_pixman_transform_init_rotate
+#define pixman_transform_init_scale _moz_pixman_transform_init_scale
+#define pixman_transform_init_translate _moz_pixman_transform_init_translate
+#define pixman_transform_invert _moz_pixman_transform_invert
+#define pixman_transform_is_identity _moz_pixman_transform_is_identity
+#define pixman_transform_is_int_translate _moz_pixman_transform_is_int_translate
+#define pixman_transform_is_inverse _moz_pixman_transform_is_inverse
+#define pixman_transform_is_scale _moz_pixman_transform_is_scale
+#define pixman_transform_multiply _moz_pixman_transform_multiply
+#define pixman_transform_point _moz_pixman_transform_point
+#define pixman_transform_rotate _moz_pixman_transform_rotate
+#define pixman_transform_scale _moz_pixman_transform_scale
+#define pixman_transform_translate _moz_pixman_transform_translate
+#endif
--- a/gfx/cairo/libpixman/src/pixman-compiler.h
+++ b/gfx/cairo/libpixman/src/pixman-compiler.h
@@ -80,17 +80,29 @@
 #   endif
 #   ifndef noinline
 #      define noinline
 #   endif
 #endif
 
 /* In libxul builds we don't ever want to export pixman symbols */
 #if 1
-#   define PIXMAN_EXPORT cairo_public
+#include "prcpucfg.h"
+
+#ifdef HAVE_VISIBILITY_HIDDEN_ATTRIBUTE
+#define CVISIBILITY_HIDDEN __attribute__((visibility("hidden")))
+#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550)
+#define CVISIBILITY_HIDDEN __hidden
+#else
+#define CVISIBILITY_HIDDEN
+#endif
+
+/* In libxul builds we don't ever want to export cairo symbols */
+#define PIXMAN_EXPORT extern CVISIBILITY_HIDDEN
+
 #else
 
 /* GCC visibility */
 #if defined(__GNUC__) && __GNUC__ >= 4 && !defined(_WIN32)
 #   define PIXMAN_EXPORT __attribute__ ((visibility("default")))
 /* Sun Studio 8 visibility */
 #elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550)
 #   define PIXMAN_EXPORT __global
--- a/gfx/cairo/libpixman/src/pixman.h
+++ b/gfx/cairo/libpixman/src/pixman.h
@@ -64,17 +64,20 @@ SOFTWARE.
  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
 #ifndef PIXMAN_H__
 #define PIXMAN_H__
 
-#include "cairo-platform.h"
+#ifdef MOZILLA_VERSION
+#include "cairo/pixman-rename.h"
+#endif
+
 
 #include <pixman-version.h>
 
 #ifdef  __cplusplus
 #define PIXMAN_BEGIN_DECLS extern "C" {
 #define PIXMAN_END_DECLS }
 #else
 #define PIXMAN_BEGIN_DECLS
--- a/gfx/layers/client/CanvasClient.cpp
+++ b/gfx/layers/client/CanvasClient.cpp
@@ -101,16 +101,24 @@ CanvasClient2D::Update(gfx::IntSize aSiz
 TemporaryRef<BufferTextureClient>
 CanvasClient2D::CreateBufferTextureClient(gfx::SurfaceFormat aFormat, TextureFlags aFlags)
 {
   return CompositableClient::CreateBufferTextureClient(aFormat,
                                                        mTextureInfo.mTextureFlags | aFlags);
 }
 
 void
+CanvasClient2D::OnActorDestroy()
+{
+  if (mBuffer) {
+    mBuffer->OnActorDestroy();
+  }
+}
+
+void
 DeprecatedCanvasClient2D::Updated()
 {
   mForwarder->UpdateTexture(this, 1, mDeprecatedTextureClient->LockSurfaceDescriptor());
 }
 
 
 DeprecatedCanvasClient2D::DeprecatedCanvasClient2D(CompositableForwarder* aFwd,
                                                    TextureFlags aFlags)
@@ -152,16 +160,24 @@ DeprecatedCanvasClient2D::Update(gfx::In
   }
 
   gfxASurface* surface = mDeprecatedTextureClient->LockSurface();
   aLayer->UpdateSurface(surface);
   mDeprecatedTextureClient->Unlock();
 }
 
 void
+DeprecatedCanvasClient2D::OnActorDestroy()
+{
+  if (mDeprecatedTextureClient) {
+    mDeprecatedTextureClient->OnActorDestroy();
+  }
+}
+
+void
 DeprecatedCanvasClientSurfaceStream::Updated()
 {
   mForwarder->UpdateTextureNoSwap(this, 1, mDeprecatedTextureClient->LockSurfaceDescriptor());
 }
 
 
 DeprecatedCanvasClientSurfaceStream::DeprecatedCanvasClientSurfaceStream(CompositableForwarder* aFwd,
                                                                          TextureFlags aFlags)
@@ -219,10 +235,18 @@ DeprecatedCanvasClientSurfaceStream::Upd
     // Ref this so the SurfaceStream doesn't disappear unexpectedly. The
     // Compositor will need to unref it when finished.
     aLayer->mGLContext->AddRef();
   }
 
   aLayer->Painted();
 }
 
+void
+DeprecatedCanvasClientSurfaceStream::OnActorDestroy()
+{
+  if (mDeprecatedTextureClient) {
+    mDeprecatedTextureClient->OnActorDestroy();
+  }
+}
+
 }
 }
--- a/gfx/layers/client/CanvasClient.h
+++ b/gfx/layers/client/CanvasClient.h
@@ -86,19 +86,22 @@ public:
   CreateBufferTextureClient(gfx::SurfaceFormat aFormat,
                             TextureFlags aFlags = TEXTURE_FLAGS_DEFAULT) MOZ_OVERRIDE;
 
   virtual void OnDetach() MOZ_OVERRIDE
   {
     mBuffer = nullptr;
   }
 
+  virtual void OnActorDestroy() MOZ_OVERRIDE;
+
 private:
   RefPtr<TextureClient> mBuffer;
 };
+
 class DeprecatedCanvasClient2D : public CanvasClient
 {
 public:
   DeprecatedCanvasClient2D(CompositableForwarder* aLayerForwarder,
                            TextureFlags aFlags);
 
   TextureInfo GetTextureInfo() const MOZ_OVERRIDE
   {
@@ -109,16 +112,18 @@ public:
   virtual void Updated() MOZ_OVERRIDE;
 
   virtual void SetDescriptorFromReply(TextureIdentifier aTextureId,
                                       const SurfaceDescriptor& aDescriptor) MOZ_OVERRIDE
   {
     mDeprecatedTextureClient->SetDescriptorFromReply(aDescriptor);
   }
 
+  virtual void OnActorDestroy() MOZ_OVERRIDE;
+
 private:
   RefPtr<DeprecatedTextureClient> mDeprecatedTextureClient;
 };
 
 // Used for GL canvases where we don't need to do any readback, i.e., with a
 // GL backend.
 class DeprecatedCanvasClientSurfaceStream : public CanvasClient
 {
@@ -135,16 +140,18 @@ public:
   virtual void Updated() MOZ_OVERRIDE;
 
   virtual void SetDescriptorFromReply(TextureIdentifier aTextureId,
                                       const SurfaceDescriptor& aDescriptor) MOZ_OVERRIDE
   {
     mDeprecatedTextureClient->SetDescriptorFromReply(aDescriptor);
   }
 
+  virtual void OnActorDestroy() MOZ_OVERRIDE;
+
 private:
   RefPtr<DeprecatedTextureClient> mDeprecatedTextureClient;
 };
 
 }
 }
 
 #endif
--- a/gfx/layers/client/CompositableClient.cpp
+++ b/gfx/layers/client/CompositableClient.cpp
@@ -30,17 +30,16 @@ CompositableClient::CompositableClient(C
 
 
 CompositableClient::~CompositableClient()
 {
   MOZ_COUNT_DTOR(CompositableClient);
   Destroy();
 
   FlushTexturesToRemoveCallbacks();
-
   MOZ_ASSERT(mTexturesToRemove.Length() == 0, "would leak textures pending for deletion");
 }
 
 void
 CompositableClient::FlushTexturesToRemoveCallbacks()
 {
   std::map<uint64_t,TextureClientData*>::iterator it
     = mTexturesToRemoveCallbacks.begin();
@@ -82,16 +81,17 @@ CompositableClient::Connect()
 }
 
 void
 CompositableClient::Destroy()
 {
   if (!mCompositableChild) {
     return;
   }
+  mCompositableChild->SetClient(nullptr);
   mCompositableChild->Destroy();
   mCompositableChild = nullptr;
 }
 
 uint64_t
 CompositableClient::GetAsyncID() const
 {
   if (mCompositableChild) {
@@ -252,10 +252,18 @@ CompositableClient::OnTransaction()
 {
   for (unsigned i = 0; i < mTexturesToRemove.Length(); ++i) {
     const TextureIDAndFlags& texture = mTexturesToRemove[i];
     mForwarder->RemoveTexture(this, texture.mID, texture.mFlags);
   }
   mTexturesToRemove.Clear();
 }
 
+
+void
+CompositableChild::ActorDestroy(ActorDestroyReason why)
+{
+  if (mCompositableClient && why == AbnormalShutdown) {
+    mCompositableClient->OnActorDestroy();
+  }
+}
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/client/CompositableClient.h
+++ b/gfx/layers/client/CompositableClient.h
@@ -156,16 +156,22 @@ public:
    */
   void OnReplyTextureRemoved(uint64_t aTextureID);
 
   /**
    * Run all he registered callbacks (see the comment for OnReplyTextureRemoved).
    * Only call this if you know what you are doing.
    */
   void FlushTexturesToRemoveCallbacks();
+
+  /**
+   * Our IPDL actor is being destroyed, get rid of any shmem resources now.
+   */
+  virtual void OnActorDestroy() = 0;
+
 protected:
   struct TextureIDAndFlags {
     TextureIDAndFlags(uint64_t aID, TextureFlags aFlags)
     : mID(aID), mFlags(aFlags) {}
     uint64_t mID;
     TextureFlags mFlags;
   };
   // The textures to destroy in the next transaction;
@@ -202,16 +208,18 @@ public:
     mCompositableClient = aClient;
   }
 
   CompositableClient* GetCompositableClient() const
   {
     return mCompositableClient;
   }
 
+  virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
+
   void SetAsyncID(uint64_t aID) { mID = aID; }
   uint64_t GetAsyncID() const
   {
     return mID;
   }
 private:
   CompositableClient* mCompositableClient;
   uint64_t mID;
--- a/gfx/layers/client/ContentClient.cpp
+++ b/gfx/layers/client/ContentClient.cpp
@@ -322,16 +322,31 @@ ContentClientRemoteBuffer::SwapBuffers(c
 
   mFrontAndBackBufferDiffer = true;
   mDeprecatedTextureClient->SetAccessMode(DeprecatedTextureClient::ACCESS_READ_WRITE);
   if (mDeprecatedTextureClientOnWhite) {
     mDeprecatedTextureClientOnWhite->SetAccessMode(DeprecatedTextureClient::ACCESS_READ_WRITE);
   }
 }
 
+
+void
+ContentClientRemoteBuffer::OnActorDestroy()
+{
+  if (mDeprecatedTextureClient) {
+    mDeprecatedTextureClient->OnActorDestroy();
+  }
+  if (mDeprecatedTextureClientOnWhite) {
+    mDeprecatedTextureClientOnWhite->OnActorDestroy();
+  }
+  for (size_t i = 0; i < mOldTextures.Length(); ++i) {
+    mOldTextures[i]->OnActorDestroy();
+  }
+}
+
 ContentClientDoubleBuffered::~ContentClientDoubleBuffered()
 {
   if (mDeprecatedTextureClient) {
     MOZ_ASSERT(mFrontClient);
     mDeprecatedTextureClient->SetDescriptor(SurfaceDescriptor());
     mFrontClient->SetDescriptor(SurfaceDescriptor());
   }
   if (mDeprecatedTextureClientOnWhite) {
@@ -422,16 +437,36 @@ ContentClientDoubleBuffered::SwapBuffers
   mFrontClient->SetAccessMode(DeprecatedTextureClient::ACCESS_READ_ONLY);
   if (mFrontClientOnWhite) {
     mFrontClientOnWhite->SetAccessMode(DeprecatedTextureClient::ACCESS_READ_ONLY);
   }
 
   ContentClientRemoteBuffer::SwapBuffers(aFrontUpdatedRegion);
 }
 
+void
+ContentClientDoubleBuffered::OnActorDestroy()
+{
+  if (mDeprecatedTextureClient) {
+    mDeprecatedTextureClient->OnActorDestroy();
+  }
+  if (mDeprecatedTextureClientOnWhite) {
+    mDeprecatedTextureClientOnWhite->OnActorDestroy();
+  }
+  for (size_t i = 0; i < mOldTextures.Length(); ++i) {
+    mOldTextures[i]->OnActorDestroy();
+  }
+  if (mFrontClient) {
+    mFrontClient->OnActorDestroy();
+  }
+  if (mFrontClientOnWhite) {
+    mFrontClientOnWhite->OnActorDestroy();
+  }
+}
+
 struct AutoDeprecatedTextureClient {
   AutoDeprecatedTextureClient()
     : mTexture(nullptr)
   {}
   ~AutoDeprecatedTextureClient()
   {
     if (mTexture) {
       mTexture->Unlock();
--- a/gfx/layers/client/ContentClient.h
+++ b/gfx/layers/client/ContentClient.h
@@ -158,16 +158,18 @@ public:
                             RefPtr<gfx::DrawTarget>* aBlackDT, RefPtr<gfx::DrawTarget>* aWhiteDT) MOZ_OVERRIDE;
   virtual bool SupportsAzureContent() const;
 
   virtual TextureInfo GetTextureInfo() const MOZ_OVERRIDE
   {
     MOZ_CRASH("Should not be called on non-remote ContentClient");
   }
 
+  virtual void OnActorDestroy() MOZ_OVERRIDE {}
+
 private:
   BasicLayerManager* mManager;
 };
 
 /**
  * A ContentClientRemote backed by a ThebesLayerBuffer.
  *
  * When using a ContentClientRemote, SurfaceDescriptors are created on
@@ -242,16 +244,18 @@ public:
 
   void DestroyBuffers();
 
   virtual TextureInfo GetTextureInfo() const MOZ_OVERRIDE
   {
     return mTextureInfo;
   }
 
+  virtual void OnActorDestroy() MOZ_OVERRIDE;
+
 protected:
   virtual nsIntRegion GetUpdatedRegion(const nsIntRegion& aRegionToDraw,
                                        const nsIntRegion& aVisibleRegion,
                                        bool aDidSelfCopy);
 
   // create and configure mDeprecatedTextureClient
   void BuildDeprecatedTextureClients(ContentType aType,
                                      const nsIntRect& aRect,
@@ -305,16 +309,18 @@ public:
 
   virtual void SyncFrontBufferToBackBuffer() MOZ_OVERRIDE;
 
 protected:
   virtual void CreateFrontBufferAndNotify(const nsIntRect& aBufferRect) MOZ_OVERRIDE;
   virtual void DestroyFrontBuffer() MOZ_OVERRIDE;
   virtual void LockFrontBuffer() MOZ_OVERRIDE;
 
+  virtual void OnActorDestroy() MOZ_OVERRIDE;
+
 private:
   void UpdateDestinationFrom(const RotatedBuffer& aSource,
                              const nsIntRegion& aUpdateRegion);
 
   RefPtr<DeprecatedTextureClient> mFrontClient;
   RefPtr<DeprecatedTextureClient> mFrontClientOnWhite;
   nsIntRegion mFrontUpdatedRegion;
   nsIntRect mFrontBufferRect;
@@ -390,16 +396,18 @@ public:
     if (IsSurfaceDescriptorValid(mUpdateDescriptor)) {
       mForwarder->DestroySharedSurface(&mUpdateDescriptor);
     }
     if (IsSurfaceDescriptorValid(mUpdateDescriptorOnWhite)) {
       mForwarder->DestroySharedSurface(&mUpdateDescriptorOnWhite);
     }
   }
 
+  virtual void OnActorDestroy() MOZ_OVERRIDE {}
+
 private:
 
   enum BufferType{
     BUFFER_BLACK,
     BUFFER_WHITE
   };
 
   void NotifyBufferCreated(ContentType aType, uint32_t aFlags)
--- a/gfx/layers/client/ImageClient.cpp
+++ b/gfx/layers/client/ImageClient.cpp
@@ -275,16 +275,35 @@ ImageClientBuffered::UpdateImage(ImageCo
                                  uint32_t aContentFlags)
 {
   RefPtr<TextureClient> temp = mFrontBuffer;
   mFrontBuffer = mBackBuffer;
   mBackBuffer = temp;
   return ImageClientSingle::UpdateImage(aContainer, aContentFlags);
 }
 
+void
+ImageClientSingle::OnActorDestroy()
+{
+  if (mFrontBuffer) {
+    mFrontBuffer->OnActorDestroy();
+  }
+}
+
+void
+ImageClientBuffered::OnActorDestroy()
+{
+  if (mFrontBuffer) {
+    mFrontBuffer->OnActorDestroy();
+  }
+  if (mBackBuffer) {
+    mBackBuffer->OnActorDestroy();
+  }
+}
+
 bool
 ImageClientSingle::AddTextureClient(TextureClient* aTexture)
 {
   MOZ_ASSERT((mTextureFlags & aTexture->GetFlags()) == mTextureFlags);
   return CompositableClient::AddTextureClient(aTexture);
 }
 
 TemporaryRef<BufferTextureClient>
@@ -460,16 +479,24 @@ DeprecatedImageClientSingle::Updated()
 ImageClientBridge::ImageClientBridge(CompositableForwarder* aFwd,
                                      TextureFlags aFlags)
 : ImageClient(aFwd, BUFFER_BRIDGE)
 , mAsyncContainerID(0)
 , mLayer(nullptr)
 {
 }
 
+void
+DeprecatedImageClientSingle::OnActorDestroy()
+{
+  if (mDeprecatedTextureClient) {
+    mDeprecatedTextureClient->OnActorDestroy();
+  }
+}
+
 bool
 ImageClientBridge::UpdateImage(ImageContainer* aContainer, uint32_t aContentFlags)
 {
   if (!GetForwarder() || !mLayer) {
     return false;
   }
   if (mAsyncContainerID == aContainer->GetAsyncContainerID()) {
     return true;
--- a/gfx/layers/client/ImageClient.h
+++ b/gfx/layers/client/ImageClient.h
@@ -97,16 +97,18 @@ public:
 
   virtual TextureInfo GetTextureInfo() const MOZ_OVERRIDE;
 
   virtual already_AddRefed<Image> CreateImage(const uint32_t *aFormats,
                                               uint32_t aNumFormats) MOZ_OVERRIDE;
 
   virtual void FlushAllImages(bool aExceptFront) MOZ_OVERRIDE;
 
+  virtual void OnActorDestroy() MOZ_OVERRIDE;
+
 protected:
   RefPtr<TextureClient> mFrontBuffer;
   // Some layers may want to enforce some flags to all their textures
   // (like disallowing tiling)
   TextureFlags mTextureFlags;
 };
 
 /**
@@ -120,16 +122,18 @@ public:
                       CompositableType aType);
 
   virtual bool UpdateImage(ImageContainer* aContainer, uint32_t aContentFlags);
 
   virtual void OnDetach() MOZ_OVERRIDE;
 
   virtual void FlushAllImages(bool aExceptFront) MOZ_OVERRIDE;
 
+  virtual void OnActorDestroy() MOZ_OVERRIDE;
+
 protected:
   RefPtr<TextureClient> mBackBuffer;
 };
 
 /**
  * An image client which uses a single texture client, may be single or double
  * buffered. (As opposed to using two texture clients for buffering, as in
  * ContentClientDoubleBuffered, or using multiple clients for YCbCr or tiled
@@ -164,16 +168,18 @@ public:
   virtual TextureInfo GetTextureInfo() const MOZ_OVERRIDE
   {
     return mTextureInfo;
   }
 
   virtual already_AddRefed<Image> CreateImage(const uint32_t *aFormats,
                                               uint32_t aNumFormats) MOZ_OVERRIDE;
 
+  virtual void OnActorDestroy() MOZ_OVERRIDE;
+
 private:
   RefPtr<DeprecatedTextureClient> mDeprecatedTextureClient;
   TextureInfo mTextureInfo;
 };
 
 /**
  * Image class to be used for async image uploads using the image bridge
  * protocol.
@@ -205,16 +211,18 @@ public:
 
   virtual already_AddRefed<Image> CreateImage(const uint32_t *aFormats,
                                               uint32_t aNumFormats) MOZ_OVERRIDE
   {
     NS_WARNING("Should not create an image through an ImageClientBridge");
     return nullptr;
   }
 
+  virtual void OnActorDestroy() MOZ_OVERRIDE {}
+
 protected:
   uint64_t mAsyncContainerID;
   ShadowableLayer* mLayer;
 };
 
 }
 }
 
--- a/gfx/layers/client/TextureClient.cpp
+++ b/gfx/layers/client/TextureClient.cpp
@@ -385,16 +385,25 @@ DeprecatedTextureClient::DeprecatedTextu
 }
 
 DeprecatedTextureClient::~DeprecatedTextureClient()
 {
   MOZ_COUNT_DTOR(DeprecatedTextureClient);
   MOZ_ASSERT(mDescriptor.type() == SurfaceDescriptor::T__None, "Need to release surface!");
 }
 
+void
+DeprecatedTextureClient::OnActorDestroy()
+{
+  if (ISurfaceAllocator::IsShmem(&mDescriptor)) {
+    mDescriptor = SurfaceDescriptor();
+  }
+}
+
+
 DeprecatedTextureClientShmem::DeprecatedTextureClientShmem(CompositableForwarder* aForwarder,
                                        const TextureInfo& aTextureInfo)
   : DeprecatedTextureClient(aForwarder, aTextureInfo)
 {
 }
 
 DeprecatedTextureClientShmem::~DeprecatedTextureClientShmem()
 {
--- a/gfx/layers/client/TextureClient.h
+++ b/gfx/layers/client/TextureClient.h
@@ -211,16 +211,20 @@ public:
   bool IsValid() const { return mValid; }
 
   /**
    * An invalid TextureClient cannot provide access to its shared data
    * anymore. This usually means it will soon be destroyed.
    */
   void MarkInvalid() { mValid = false; }
 
+  // If a texture client holds a reference to shmem, it should override this
+  // method to forget about the shmem _without_ releasing it.
+  virtual void OnActorDestroy() {}
+
 protected:
   void AddFlags(TextureFlags  aFlags)
   {
     MOZ_ASSERT(!IsSharedWithCompositor());
     mFlags |= aFlags;
   }
 
   uint64_t mID;
@@ -311,16 +315,21 @@ public:
   virtual bool IsAllocated() const MOZ_OVERRIDE { return mAllocated; }
 
   virtual TextureClientData* DropTextureData() MOZ_OVERRIDE;
 
   ISurfaceAllocator* GetAllocator() const;
 
   ipc::Shmem& GetShmem() { return mShmem; }
 
+  virtual void OnActorDestroy() MOZ_OVERRIDE
+  {
+    mShmem = ipc::Shmem();
+  }
+
 protected:
   ipc::Shmem mShmem;
   ISurfaceAllocator* mAllocator;
   bool mAllocated;
 };
 
 /**
  * TextureClient that wraps raw memory.
@@ -487,16 +496,18 @@ public:
 
   AccessMode GetAccessMode() const
   {
     return mAccessMode;
   }
 
   virtual gfxContentType GetContentType() = 0;
 
+  void OnActorDestroy();
+
 protected:
   DeprecatedTextureClient(CompositableForwarder* aForwarder,
                 const TextureInfo& aTextureInfo);
 
   CompositableForwarder* mForwarder;
   // So far all DeprecatedTextureClients use a SurfaceDescriptor, so it makes sense to
   // keep the reference here.
   SurfaceDescriptor mDescriptor;
--- a/gfx/layers/client/TiledContentClient.h
+++ b/gfx/layers/client/TiledContentClient.h
@@ -196,16 +196,24 @@ public:
                          LayerManager::DrawThebesLayerCallback aCallback,
                          void* aCallbackData);
 
   SurfaceDescriptorTiles GetSurfaceDescriptorTiles();
 
   static BasicTiledLayerBuffer OpenDescriptor(ISurfaceAllocator* aAllocator,
                                               const SurfaceDescriptorTiles& aDescriptor);
 
+  void OnActorDestroy()
+  {
+    for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
+      if (mRetainedTiles[i].IsPlaceholderTile()) continue;
+      mRetainedTiles[i].mDeprecatedTextureClient->OnActorDestroy();
+    }
+  }
+
 protected:
   BasicTiledLayerTile ValidateTile(BasicTiledLayerTile aTile,
                                    const nsIntPoint& aTileRect,
                                    const nsIntRegion& dirtyRect);
 
   // If this returns true, we perform the paint operation into a single large
   // buffer and copy it out to the tiles instead of calling PaintThebes() on
   // each tile individually. Somewhat surprisingly, this turns out to be faster
@@ -285,16 +293,22 @@ public:
   }
 
   enum TiledBufferType {
     TILED_BUFFER,
     LOW_PRECISION_TILED_BUFFER
   };
   void LockCopyAndWrite(TiledBufferType aType);
 
+  virtual void OnActorDestroy() MOZ_OVERRIDE
+  {
+    mTiledBuffer.OnActorDestroy();
+    mLowPrecisionTiledBuffer.OnActorDestroy();
+  }
+
 private:
   BasicTiledLayerBuffer mTiledBuffer;
   BasicTiledLayerBuffer mLowPrecisionTiledBuffer;
 };
 
 }
 }
 
--- a/gfx/layers/composite/CompositableHost.cpp
+++ b/gfx/layers/composite/CompositableHost.cpp
@@ -232,17 +232,24 @@ CompositableHost::DumpTextureHost(FILE* 
   surf->DumpAsDataURL(aFile ? aFile : stderr);
 }
 #endif
 
 void
 CompositableParent::ActorDestroy(ActorDestroyReason why)
 {
   if (mHost) {
-    mHost->Detach();
+    // XXX: sadness warning. We should be able to do this whenever we get ActorDestroy,
+    // not just for abnormal shutdowns (which is the only case we _need_ to - so that
+    // we don't double release our shmems). But, for some reason, that causes a
+    // crash, we don't know why. (Bug 925773).
+    if (why == AbnormalShutdown) {
+      mHost->OnActorDestroy();
+    }
+    mHost->Detach(nullptr, CompositableHost::FORCE_DETACH);
   }
 }
 
 CompositableParent::CompositableParent(CompositableParentManager* aMgr,
                                        const TextureInfo& aTextureInfo,
                                        uint64_t aID)
 : mManager(aMgr)
 , mType(aTextureInfo.mCompositableType)
--- a/gfx/layers/composite/CompositableHost.h
+++ b/gfx/layers/composite/CompositableHost.h
@@ -102,16 +102,22 @@ public:
     return mBackendData;
   }
 
   virtual void SetCompositableBackendSpecificData(CompositableBackendSpecificData* aBackendData)
   {
     mBackendData = aBackendData;
   }
 
+  /**
+   * Our IPDL actor is being destroyed, get rid of any shmem resources now and
+   * don't worry about compositing anymore.
+   */
+  virtual void OnActorDestroy() = 0;
+
   // If base class overrides, it should still call the parent implementation
   virtual void SetCompositor(Compositor* aCompositor);
 
   // composite the contents of this buffer host to the compositor's surface
   virtual void Composite(EffectChain& aEffectChain,
                          float aOpacity,
                          const gfx::Matrix4x4& aTransform,
                          const gfx::Filter& aFilter,
@@ -232,16 +238,17 @@ public:
   void SetLayer(Layer* aLayer) { mLayer = aLayer; }
 
   virtual TiledLayerComposer* AsTiledLayerComposer() { return nullptr; }
 
   typedef uint32_t AttachFlags;
   static const AttachFlags NO_FLAGS = 0;
   static const AttachFlags ALLOW_REATTACH = 1;
   static const AttachFlags KEEP_ATTACHED = 2;
+  static const AttachFlags FORCE_DETACH = 2;
 
   virtual void Attach(Layer* aLayer,
                       Compositor* aCompositor,
                       AttachFlags aFlags = NO_FLAGS)
   {
     MOZ_ASSERT(aCompositor, "Compositor is required");
     NS_ASSERTION(aFlags & ALLOW_REATTACH || !mAttached,
                  "Re-attaching compositables must be explicitly authorised");
@@ -252,20 +259,22 @@ public:
   }
   // Detach this compositable host from its layer.
   // If we are used for async video, then it is not safe to blindly detach since
   // we might be re-attached to a different layer. aLayer is the layer which the
   // caller expects us to be attached to, we will only detach if we are in fact
   // attached to that layer. If we are part of a normal layer, then we will be
   // detached in any case. if aLayer is null, then we will only detach if we are
   // not async.
-  void Detach(Layer* aLayer = nullptr)
+  // Only force detach if the IPDL tree is being shutdown.
+  void Detach(Layer* aLayer = nullptr, AttachFlags aFlags = NO_FLAGS)
   {
     if (!mKeepAttached ||
-        aLayer == mLayer) {
+        aLayer == mLayer ||
+        aFlags & FORCE_DETACH) {
       SetLayer(nullptr);
       SetCompositor(nullptr);
       mAttached = false;
       mKeepAttached = false;
       if (mBackendData) {
         mBackendData->ClearData();
       }
     }
--- a/gfx/layers/composite/ContentHost.cpp
+++ b/gfx/layers/composite/ContentHost.cpp
@@ -48,16 +48,33 @@ ContentHostBase::DestroyFrontHost()
              "We won't be able to destroy our SurfaceDescriptor");
   MOZ_ASSERT(!mDeprecatedTextureHostOnWhite || mDeprecatedTextureHostOnWhite->GetDeAllocator(),
              "We won't be able to destroy our SurfaceDescriptor");
   mDeprecatedTextureHost = nullptr;
   mDeprecatedTextureHostOnWhite = nullptr;
 }
 
 void
+ContentHostBase::OnActorDestroy()
+{
+  if (mDeprecatedTextureHost) {
+    mDeprecatedTextureHost->OnActorDestroy();
+  }
+  if (mDeprecatedTextureHostOnWhite) {
+    mDeprecatedTextureHostOnWhite->OnActorDestroy();
+  }
+  if (mNewFrontHost) {
+    mNewFrontHost->OnActorDestroy();
+  }
+  if (mNewFrontHostOnWhite) {
+    mNewFrontHostOnWhite->OnActorDestroy();
+  }
+}
+
+void
 ContentHostBase::Composite(EffectChain& aEffectChain,
                            float aOpacity,
                            const gfx::Matrix4x4& aTransform,
                            const Filter& aFilter,
                            const Rect& aClipRect,
                            const nsIntRegion* aVisibleRegion,
                            TiledLayerProperties* aLayerProperties)
 {
@@ -404,39 +421,59 @@ ContentHostDoubleBuffered::EnsureDepreca
 void
 ContentHostDoubleBuffered::DestroyTextures()
 {
   if (mNewFrontHost) {
     MOZ_ASSERT(mNewFrontHost->GetDeAllocator(),
                "We won't be able to destroy our SurfaceDescriptor");
     mNewFrontHost = nullptr;
   }
-
   if (mNewFrontHostOnWhite) {
     MOZ_ASSERT(mNewFrontHostOnWhite->GetDeAllocator(),
                "We won't be able to destroy our SurfaceDescriptor");
     mNewFrontHostOnWhite = nullptr;
   }
-
   if (mBackHost) {
     MOZ_ASSERT(mBackHost->GetDeAllocator(),
                "We won't be able to destroy our SurfaceDescriptor");
     mBackHost = nullptr;
   }
-
   if (mBackHostOnWhite) {
     MOZ_ASSERT(mBackHostOnWhite->GetDeAllocator(),
                "We won't be able to destroy our SurfaceDescriptor");
     mBackHostOnWhite = nullptr;
   }
 
   // don't touch mDeprecatedTextureHost, we might need it for compositing
 }
 
 void
+ContentHostDoubleBuffered::OnActorDestroy()
+{
+  if (mDeprecatedTextureHost) {
+    mDeprecatedTextureHost->OnActorDestroy();
+  }
+  if (mDeprecatedTextureHostOnWhite) {
+    mDeprecatedTextureHostOnWhite->OnActorDestroy();
+  }
+  if (mNewFrontHost) {
+    mNewFrontHost->OnActorDestroy();
+  }
+  if (mNewFrontHostOnWhite) {
+    mNewFrontHostOnWhite->OnActorDestroy();
+  }
+  if (mBackHost) {
+    mBackHost->OnActorDestroy();
+  }
+  if (mBackHostOnWhite) {
+    mBackHostOnWhite->OnActorDestroy();
+  }
+}
+
+void
 ContentHostDoubleBuffered::UpdateThebes(const ThebesBufferData& aData,
                                         const nsIntRegion& aUpdated,
                                         const nsIntRegion& aOldValidRegionBack,
                                         nsIntRegion* aUpdatedRegionBack)
 {
   if (!mDeprecatedTextureHost && !mNewFrontHost) {
     mInitialised = false;
 
--- a/gfx/layers/composite/ContentHost.h
+++ b/gfx/layers/composite/ContentHost.h
@@ -122,16 +122,18 @@ public:
   virtual DeprecatedTextureHost* GetDeprecatedTextureHost() MOZ_OVERRIDE;
 
   virtual void SetPaintWillResample(bool aResample) { mPaintWillResample = aResample; }
   // The client has destroyed its texture clients and we should destroy our
   // texture hosts and SurfaceDescriptors. Note that we don't immediately
   // destroy our front buffer so that we can continue to composite.
   virtual void DestroyTextures() = 0;
 
+  virtual void OnActorDestroy() MOZ_OVERRIDE;
+
 protected:
   virtual nsIntPoint GetOriginOffset()
   {
     return mBufferRect.TopLeft() - mBufferRotation;
   }
 
   bool PaintWillResample() { return mPaintWillResample; }
 
@@ -172,16 +174,18 @@ public:
                             nsIntRegion* aUpdatedRegionBack);
 
   virtual void EnsureDeprecatedTextureHost(TextureIdentifier aTextureId,
                                  const SurfaceDescriptor& aSurface,
                                  ISurfaceAllocator* aAllocator,
                                  const TextureInfo& aTextureInfo) MOZ_OVERRIDE;
   virtual void DestroyTextures() MOZ_OVERRIDE;
 
+  virtual void OnActorDestroy() MOZ_OVERRIDE;
+
 #ifdef MOZ_DUMP_PAINTING
   virtual void Dump(FILE* aFile=nullptr,
                     const char* aPrefix="",
                     bool aDumpHtml=false) MOZ_OVERRIDE;
 #endif
 
   virtual void PrintInfo(nsACString& aTo, const char* aPrefix);
 protected:
--- a/gfx/layers/composite/ImageHost.h
+++ b/gfx/layers/composite/ImageHost.h
@@ -63,16 +63,23 @@ public:
   virtual void SetPictureRect(const nsIntRect& aPictureRect) MOZ_OVERRIDE
   {
     mPictureRect = aPictureRect;
     mHasPictureRect = true;
   }
 
   virtual LayerRenderState GetRenderState() MOZ_OVERRIDE;
 
+  virtual void OnActorDestroy() MOZ_OVERRIDE
+  {
+    if (mFrontBuffer) {
+      mFrontBuffer->OnActorDestroy();
+    }
+  }
+
   virtual void PrintInfo(nsACString& aTo, const char* aPrefix);
 
 #ifdef MOZ_DUMP_PAINTING
   virtual void Dump(FILE* aFile=NULL,
                     const char* aPrefix="",
                     bool aDumpHtml=false) MOZ_OVERRIDE;
 
   virtual already_AddRefed<gfxImageSurface> GetAsSurface() MOZ_OVERRIDE;
@@ -123,16 +130,23 @@ public:
     mPictureRect = aPictureRect;
     mHasPictureRect = true;
   }
 
   virtual LayerRenderState GetRenderState() MOZ_OVERRIDE;
 
   virtual void SetCompositor(Compositor* aCompositor) MOZ_OVERRIDE;
 
+  virtual void OnActorDestroy() MOZ_OVERRIDE
+  {
+    if (mDeprecatedTextureHost) {
+      mDeprecatedTextureHost->OnActorDestroy();
+    }
+  }
+
   virtual void PrintInfo(nsACString& aTo, const char* aPrefix);
 
 #ifdef MOZ_DUMP_PAINTING
   virtual void Dump(FILE* aFile=nullptr,
                     const char* aPrefix="",
                     bool aDumpHtml=false) MOZ_OVERRIDE;
 
   virtual already_AddRefed<gfxImageSurface> GetAsSurface() MOZ_OVERRIDE;
--- a/gfx/layers/composite/TextureHost.cpp
+++ b/gfx/layers/composite/TextureHost.cpp
@@ -238,16 +238,25 @@ DeprecatedTextureHost::SwapTextures(cons
   // register the TextureHost with the GrallocBufferActor.
   // The reason why this SetBuffer calls is needed here is that just above we
   // overwrote *mBuffer in place, so we need to tell the new mBuffer about this
   // TextureHost.
   SetBuffer(mBuffer, mDeAllocator);
 }
 
 void
+DeprecatedTextureHost::OnActorDestroy()
+{
+  if (ISurfaceAllocator::IsShmem(mBuffer)) {
+    *mBuffer = SurfaceDescriptor();
+    mBuffer = nullptr;
+  }
+}
+
+void
 DeprecatedTextureHost::PrintInfo(nsACString& aTo, const char* aPrefix)
 {
   aTo += aPrefix;
   aTo += nsPrintfCString("%s (0x%p)", Name(), this);
   AppendToString(aTo, GetSize(), " [size=", "]");
   AppendToString(aTo, GetFormat(), " [format=", "]");
   AppendToString(aTo, mFlags, " [flags=", "]");
 }
@@ -501,16 +510,23 @@ ShmemTextureHost::DeallocateSharedData()
 {
   if (mShmem) {
     MOZ_ASSERT(mDeallocator,
                "Shared memory would leak without a ISurfaceAllocator");
     mDeallocator->DeallocShmem(*mShmem);
   }
 }
 
+void
+ShmemTextureHost::OnActorDestroy()
+{
+  delete mShmem;
+  mShmem = nullptr;
+}
+
 uint8_t* ShmemTextureHost::GetBuffer()
 {
   return mShmem ? mShmem->get<uint8_t>() : nullptr;
 }
 
 MemoryTextureHost::MemoryTextureHost(uint64_t aID,
                                      uint8_t* aBuffer,
                                      gfx::SurfaceFormat aFormat,
--- a/gfx/layers/composite/TextureHost.h
+++ b/gfx/layers/composite/TextureHost.h
@@ -379,16 +379,20 @@ public:
   {
     // By default we return an empty render state, this should be overridden
     // by the TextureHost implementations that are used on B2G with Composer2D
     return LayerRenderState();
   }
 
   virtual void SetCompositableBackendSpecificData(CompositableBackendSpecificData* aBackendData);
 
+  // If a texture host holds a reference to shmem, it should override this method
+  // to forget about the shmem _without_ releasing it.
+  virtual void OnActorDestroy() {}
+
   virtual const char *Name() { return "TextureHost"; }
   virtual void PrintInfo(nsACString& aTo, const char* aPrefix);
 
 protected:
   uint64_t mID;
   RefPtr<TextureHost> mNextTexture;
   TextureFlags mFlags;
   RefPtr<CompositableBackendSpecificData> mCompositableBackendData;
@@ -475,16 +479,18 @@ public:
   ~ShmemTextureHost();
 
   virtual void DeallocateSharedData() MOZ_OVERRIDE;
 
   virtual uint8_t* GetBuffer() MOZ_OVERRIDE;
 
   virtual const char *Name() MOZ_OVERRIDE { return "ShmemTextureHost"; }
 
+  virtual void OnActorDestroy() MOZ_OVERRIDE;
+
 protected:
   mozilla::ipc::Shmem* mShmem;
   ISurfaceAllocator* mDeallocator;
 };
 
 /**
  * TextureHost that wraps raw memory.
  * The corresponding texture on the client side is MemoryTextureClient.
@@ -705,16 +711,18 @@ public:
     mBuffer = aBuffer;
     mDeAllocator = aAllocator;
   }
 
   // used only for hacky fix in gecko 23 for bug 862324
   // see bug 865908 about fixing this.
   virtual void ForgetBuffer() {}
 
+  void OnActorDestroy();
+
 protected:
   /**
    * Should be implemented by the backend-specific DeprecatedTextureHost classes
    *
    * It should not take a reference to aImage, unless it knows the data
    * to be thread-safe.
    */
   virtual void UpdateImpl(const SurfaceDescriptor& aImage,
--- a/gfx/layers/composite/TiledContentHost.h
+++ b/gfx/layers/composite/TiledContentHost.h
@@ -114,16 +114,26 @@ public:
   // by the sum of the resolutions of all parent layers' FrameMetrics.
   const gfxSize& GetFrameResolution() { return mFrameResolution; }
 
   void SetCompositor(Compositor* aCompositor)
   {
     mCompositor = aCompositor;
   }
 
+  void OnActorDestroy()
+  {
+    Iterator end = TilesEnd();
+    for (Iterator it = TilesBegin(); it != end; ++it) {
+      if (it->mDeprecatedTextureHost) {
+        it->mDeprecatedTextureHost->OnActorDestroy();
+      }
+    }
+  }
+
 protected:
   TiledTexture ValidateTile(TiledTexture aTile,
                             const nsIntPoint& aTileRect,
                             const nsIntRegion& dirtyRect);
 
   // do nothing, the desctructor in the texture host takes care of releasing resources
   void ReleaseTile(TiledTexture aTile) {}
 
@@ -234,16 +244,22 @@ public:
     mVideoMemoryTiledBuffer.SetCompositor(aCompositor);
     mLowPrecisionVideoMemoryTiledBuffer.SetCompositor(aCompositor);
   }
 
   virtual void Attach(Layer* aLayer,
                       Compositor* aCompositor,
                       AttachFlags aFlags = NO_FLAGS) MOZ_OVERRIDE;
 
+  virtual void OnActorDestroy() MOZ_OVERRIDE
+  {
+    mVideoMemoryTiledBuffer.OnActorDestroy();
+    mLowPrecisionVideoMemoryTiledBuffer.OnActorDestroy();
+  }
+
 #ifdef MOZ_DUMP_PAINTING
   virtual void Dump(FILE* aFile=nullptr,
                     const char* aPrefix="",
                     bool aDumpHtml=false) MOZ_OVERRIDE;
 #endif
 
   virtual void PrintInfo(nsACString& aTo, const char* aPrefix);
 
--- a/gfx/layers/ipc/ISurfaceAllocator.cpp
+++ b/gfx/layers/ipc/ISurfaceAllocator.cpp
@@ -107,16 +107,23 @@ ISurfaceAllocator::AllocSurfaceDescripto
                                getter_AddRefs(buffer))) {
     return false;
   }
 
   *aBuffer = buffer->GetShmem();
   return true;
 }
 
+/* static */ bool
+ISurfaceAllocator::IsShmem(SurfaceDescriptor* aSurface)
+{
+  return aSurface && (aSurface->type() == SurfaceDescriptor::TShmem ||
+                      aSurface->type() == SurfaceDescriptor::TYCbCrImage ||
+                      aSurface->type() == SurfaceDescriptor::TRGBImage);
+}
 
 void
 ISurfaceAllocator::DestroySharedSurface(SurfaceDescriptor* aSurface)
 {
   MOZ_ASSERT(aSurface);
   if (!aSurface) {
     return;
   }
--- a/gfx/layers/ipc/ISurfaceAllocator.h
+++ b/gfx/layers/ipc/ISurfaceAllocator.h
@@ -118,16 +118,20 @@ ISurfaceAllocator() {}
   // method that does the actual allocation work
   virtual PGrallocBufferChild* AllocGrallocBuffer(const gfxIntSize& aSize,
                                                   uint32_t aFormat,
                                                   uint32_t aUsage,
                                                   MaybeMagicGrallocBufferHandle* aHandle)
   {
     return nullptr;
   }
+
+  // Returns true if aSurface wraps a Shmem.
+  static bool IsShmem(SurfaceDescriptor* aSurface);
+
 protected:
   // this method is needed for a temporary fix, will be removed after
   // DeprecatedTextureClient/Host rework.
   virtual bool IsOnCompositorSide() const = 0;
   static bool PlatformDestroySharedSurface(SurfaceDescriptor* aSurface);
   virtual bool PlatformAllocSurfaceDescriptor(const gfxIntSize& aSize,
                                               gfxContentType aContent,
                                               uint32_t aCaps,
--- a/gfx/layers/ipc/ShadowLayerUtilsGralloc.cpp
+++ b/gfx/layers/ipc/ShadowLayerUtilsGralloc.cpp
@@ -381,19 +381,16 @@ ISurfaceAllocator::PlatformAllocSurfaceD
 
   if (!checkedDevice) {
     char propValue[PROPERTY_VALUE_MAX];
     property_get("ro.product.device", propValue, "None");
 
     if (strcmp("crespo",propValue) == 0) {
       NS_WARNING("Nexus S has issues with gralloc, falling back to shmem");
       disableGralloc = true;
-    } else if (strcmp("peak", propValue) == 0) {
-      NS_WARNING("Geeksphone Peak has issues with gralloc, falling back to shmem");
-      disableGralloc = true;
     }
 
     checkedDevice = true;
   }
 
   if (disableGralloc) {
     return false;
   }
--- a/gfx/layers/opengl/TextureHostOGL.cpp
+++ b/gfx/layers/opengl/TextureHostOGL.cpp
@@ -295,20 +295,18 @@ TextureImageTextureSourceOGL::BindTextur
 }
 
 SharedTextureSourceOGL::SharedTextureSourceOGL(CompositorOGL* aCompositor,
                                                gl::SharedTextureHandle aHandle,
                                                gfx::SurfaceFormat aFormat,
                                                GLenum aTarget,
                                                GLenum aWrapMode,
                                                SharedTextureShareType aShareType,
-                                               gfx::IntSize aSize,
-                                               const gfx3DMatrix& aTexTransform)
-  : mTextureTransform(aTexTransform)
-  , mSize(aSize)
+                                               gfx::IntSize aSize)
+  : mSize(aSize)
   , mCompositor(aCompositor)
   , mSharedHandle(aHandle)
   , mFormat(aFormat)
   , mShareType(aShareType)
   , mTextureTarget(aTarget)
   , mWrapMode(aWrapMode)
 {}
 
@@ -352,16 +350,28 @@ SharedTextureSourceOGL::IsValid() const
 }
 
 gl::GLContext*
 SharedTextureSourceOGL::gl() const
 {
   return mCompositor ? mCompositor->gl() : nullptr;
 }
 
+gfx3DMatrix
+SharedTextureSourceOGL::GetTextureTransform()
+{
+  GLContext::SharedHandleDetails handleDetails;
+  if (!gl()->GetSharedHandleDetails(mShareType, mSharedHandle, handleDetails)) {
+    NS_WARNING("Could not get shared handle details");
+    return gfx3DMatrix();
+  }
+
+  return handleDetails.mTextureTransform;
+}
+
 SharedTextureHostOGL::SharedTextureHostOGL(uint64_t aID,
                                            TextureFlags aFlags,
                                            gl::SharedTextureShareType aShareType,
                                            gl::SharedTextureHandle aSharedHandle,
                                            gfx::IntSize aSize,
                                            bool inverted)
   : TextureHost(aID, aFlags)
   , mSize(aSize)
@@ -401,18 +411,17 @@ SharedTextureHostOGL::Lock()
 
     GLenum wrapMode = LOCAL_GL_CLAMP_TO_EDGE;
     mTextureSource = new SharedTextureSourceOGL(mCompositor,
                                                 mSharedHandle,
                                                 handleDetails.mTextureFormat,
                                                 handleDetails.mTarget,
                                                 wrapMode,
                                                 mShareType,
-                                                mSize,
-                                                handleDetails.mTextureTransform);
+                                                mSize);
   }
   return true;
 }
 
 void
 SharedTextureHostOGL::Unlock()
 {
   if (!mTextureSource) {
--- a/gfx/layers/opengl/TextureHostOGL.h
+++ b/gfx/layers/opengl/TextureHostOGL.h
@@ -246,30 +246,29 @@ public:
   typedef gl::SharedTextureShareType SharedTextureShareType;
 
   SharedTextureSourceOGL(CompositorOGL* aCompositor,
                          gl::SharedTextureHandle aHandle,
                          gfx::SurfaceFormat aFormat,
                          GLenum aTarget,
                          GLenum aWrapMode,
                          SharedTextureShareType aShareType,
-                         gfx::IntSize aSize,
-                         const gfx3DMatrix& aTexTransform);
+                         gfx::IntSize aSize);
 
   virtual TextureSourceOGL* AsSourceOGL() { return this; }
 
   virtual void BindTexture(GLenum activetex) MOZ_OVERRIDE;
 
   virtual bool IsValid() const MOZ_OVERRIDE;
 
   virtual gfx::IntSize GetSize() const MOZ_OVERRIDE { return mSize; }
 
   virtual gfx::SurfaceFormat GetFormat() const MOZ_OVERRIDE { return mFormat; }
 
-  virtual gfx3DMatrix GetTextureTransform() MOZ_OVERRIDE { return mTextureTransform; }
+  virtual gfx3DMatrix GetTextureTransform() MOZ_OVERRIDE;
 
   virtual GLenum GetTextureTarget() const { return mTextureTarget; }
 
   virtual GLenum GetWrapMode() const MOZ_OVERRIDE { return mWrapMode; }
 
   virtual void UnbindTexture() MOZ_OVERRIDE {}
 
   // SharedTextureSource doesn't own any gl texture
@@ -277,17 +276,16 @@ public:
 
   void DetachSharedHandle();
 
   void SetCompositor(CompositorOGL* aCompositor);
 
   gl::GLContext* gl() const;
 
 protected:
-  gfx3DMatrix mTextureTransform;
   gfx::IntSize mSize;
   CompositorOGL* mCompositor;
   gl::SharedTextureHandle mSharedHandle;
   gfx::SurfaceFormat mFormat;
   SharedTextureShareType mShareType;
   GLenum mTextureTarget;
   GLenum mWrapMode;
 };
--- a/gfx/src/nsFont.cpp
+++ b/gfx/src/nsFont.cpp
@@ -255,16 +255,17 @@ const gfxFontFeature eastAsianDefaults[]
 };
 
 static_assert(NS_ARRAY_LENGTH(eastAsianDefaults) ==
               eFeatureEastAsian_numFeatures,
               "eFeatureEastAsian_numFeatures should be correct");
 
 // NS_FONT_VARIANT_LIGATURES_xxx values
 const gfxFontFeature ligDefaults[] = {
+  { TRUETYPE_TAG('l','i','g','a'), 0 },  // none value means all off
   { TRUETYPE_TAG('l','i','g','a'), 1 },
   { TRUETYPE_TAG('l','i','g','a'), 0 },
   { TRUETYPE_TAG('d','l','i','g'), 1 },
   { TRUETYPE_TAG('d','l','i','g'), 0 },
   { TRUETYPE_TAG('h','l','i','g'), 1 },
   { TRUETYPE_TAG('h','l','i','g'), 0 },
   { TRUETYPE_TAG('c','a','l','t'), 1 },
   { TRUETYPE_TAG('c','a','l','t'), 0 }
@@ -381,29 +382,41 @@ void nsFont::AddFontFeaturesToStyle(gfxF
                            NS_FONT_VARIANT_EAST_ASIAN_JIS78,
                            NS_FONT_VARIANT_EAST_ASIAN_RUBY,
                            eastAsianDefaults, aStyle->featureSettings);
   }
 
   // -- ligatures
   if (variantLigatures) {
     AddFontFeaturesBitmask(variantLigatures,
-                           NS_FONT_VARIANT_LIGATURES_COMMON,
+                           NS_FONT_VARIANT_LIGATURES_NONE,
                            NS_FONT_VARIANT_LIGATURES_NO_CONTEXTUAL,
                            ligDefaults, aStyle->featureSettings);
 
-    // special case common ligs, which also enable/disable clig
     if (variantLigatures & NS_FONT_VARIANT_LIGATURES_COMMON) {
+      // liga already enabled, need to enable clig also
       setting.mTag = TRUETYPE_TAG('c','l','i','g');
       setting.mValue = 1;
       aStyle->featureSettings.AppendElement(setting);
     } else if (variantLigatures & NS_FONT_VARIANT_LIGATURES_NO_COMMON) {
+      // liga already disabled, need to disable clig also
       setting.mTag = TRUETYPE_TAG('c','l','i','g');
       setting.mValue = 0;
       aStyle->featureSettings.AppendElement(setting);
+    } else if (variantLigatures & NS_FONT_VARIANT_LIGATURES_NONE) {
+      // liga already disabled, need to disable dlig, hlig, calt, clig
+      setting.mValue = 0;
+      setting.mTag = TRUETYPE_TAG('d','l','i','g');
+      aStyle->featureSettings.AppendElement(setting);
+      setting.mTag = TRUETYPE_TAG('h','l','i','g');
+      aStyle->featureSettings.AppendElement(setting);
+      setting.mTag = TRUETYPE_TAG('c','a','l','t');
+      aStyle->featureSettings.AppendElement(setting);
+      setting.mTag = TRUETYPE_TAG('c','l','i','g');
+      aStyle->featureSettings.AppendElement(setting);
     }
   }
 
   // -- numeric
   if (variantNumeric) {
     AddFontFeaturesBitmask(variantNumeric,
                            NS_FONT_VARIANT_NUMERIC_LINING,
                            NS_FONT_VARIANT_NUMERIC_ORDINAL,
--- a/gfx/src/nsFont.h
+++ b/gfx/src/nsFont.h
@@ -51,20 +51,20 @@ struct NS_GFX nsFont {
   bool systemFont;
 
   // The variant of the font (normal, small-caps)
   uint8_t variant;
 
   // Variant subproperties
   // (currently -moz- versions, will replace variant above eventually)
   uint8_t variantCaps;
-  uint8_t variantLigatures;
   uint8_t variantNumeric;
   uint8_t variantPosition;
 
+  uint16_t variantLigatures;
   uint16_t variantEastAsian;
 
   // Some font-variant-alternates property values require
   // font-specific settings defined via @font-feature-values rules.
   // These are resolved *after* font matching occurs.
 
   // -- bitmask for both enumerated and functional propvals
   uint16_t variantAlternates;
--- a/gfx/src/nsRegion.cpp
+++ b/gfx/src/nsRegion.cpp
@@ -1,1400 +1,218 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+
 #include "nsRegion.h"
-#include <algorithm>                    // for max, min
-#include "mozilla/Assertions.h"         // for MOZ_ASSERT_HELPER2, etc
-#include "mozilla/ThreadLocal.h"        // for ThreadLocal
-#include "mozilla/mozalloc.h"           // for operator delete, etc
-#include "nsDebug.h"                    // for NS_ASSERTION, NS_ERROR
-#include "nsISupports.h"                // for NS_ASSERT_OWNINGTHREAD, etc
-#include "nsPrintfCString.h"            // for nsPrintfCString
-#include "nsTArray.h"                   // for nsTArray, nsTArray_Impl, etc
-
-/*
- * The SENTINEL values below guaranties that a < or >
- * comparison with it will be false for all values of the
- * underlying nscoord type.  E.g. this is always false:
- *   aCoord > NS_COORD_GREATER_SENTINEL
- * Setting the mRectListHead dummy rectangle to these values
- * allows us to loop without checking for the list end.
- */
-#ifdef NS_COORD_IS_FLOAT
-#define NS_COORD_LESS_SENTINEL nscoord_MIN
-#define NS_COORD_GREATER_SENTINEL nscoord_MAX
-#else
-#define NS_COORD_LESS_SENTINEL INT32_MIN
-#define NS_COORD_GREATER_SENTINEL INT32_MAX
-#endif
-
-// Fast inline analogues of nsRect methods for nsRegion::nsRectFast.
-// Check for emptiness is not required - it is guaranteed by caller.
-
-inline bool nsRegion::nsRectFast::Contains (const nsRect& aRect) const
-{
-  return (bool) ((aRect.x >= x) && (aRect.y >= y) &&
-                   (aRect.XMost () <= XMost ()) && (aRect.YMost () <= YMost ()));
-}
-
-inline bool nsRegion::nsRectFast::Intersects (const nsRect& aRect) const
-{
-  return (bool) ((x < aRect.XMost ()) && (y < aRect.YMost ()) &&
-                   (aRect.x < XMost ()) && (aRect.y < YMost ()));
-}
-
-inline bool nsRegion::nsRectFast::IntersectRect (const nsRect& aRect1, const nsRect& aRect2)
-{
-  const nscoord xmost = std::min (aRect1.XMost (), aRect2.XMost ());
-  x = std::max (aRect1.x, aRect2.x);
-  width = xmost - x;
-  if (width <= 0) return false;
-
-  const nscoord ymost = std::min (aRect1.YMost (), aRect2.YMost ());
-  y = std::max (aRect1.y, aRect2.y);
-  height = ymost - y;
-  if (height <= 0) return false;
-
-  return true;
-}
-
-inline void nsRegion::nsRectFast::UnionRect (const nsRect& aRect1, const nsRect& aRect2)
-{
-  const nscoord xmost = std::max (aRect1.XMost (), aRect2.XMost ());
-  const nscoord ymost = std::max (aRect1.YMost (), aRect2.YMost ());
-  x = std::min(aRect1.x, aRect2.x);
-  y = std::min(aRect1.y, aRect2.y);
-  width  = xmost - x;
-  height = ymost - y;
-}
-
-
-
-// Custom memory allocator for nsRegion::RgnRect structures.
-// Entries are allocated from global memory pool.
-// Memory pool can grow in size, but it can't shrink.
-
-#define INIT_MEM_CHUNK_ENTRIES 100
-#define INCR_MEM_CHUNK_ENTRIES 100
-
-class RgnRectMemoryAllocator
-{
-  nsRegion::RgnRect*  mFreeListHead;
-  uint32_t  mFreeEntries;
-  void*     mChunkListHead;
-#if defined (DEBUG)
-  NS_DECL_OWNINGTHREAD
-
-  void InitLock ()    { NS_ASSERT_OWNINGTHREAD (RgnRectMemoryAllocator); }
-  void DestroyLock () { NS_ASSERT_OWNINGTHREAD (RgnRectMemoryAllocator); }
-  void Lock ()        { NS_ASSERT_OWNINGTHREAD (RgnRectMemoryAllocator); }
-  void Unlock ()      { NS_ASSERT_OWNINGTHREAD (RgnRectMemoryAllocator); }
-#else
-  void InitLock ()    { }
-  void DestroyLock () { }
-  void Lock ()        { }
-  void Unlock ()      { }
-#endif
-
-  void* AllocChunk (uint32_t aEntries, void* aNextChunk, nsRegion::RgnRect* aTailDest)
-  {
-    uint8_t* pBuf = new uint8_t [aEntries * sizeof (nsRegion::RgnRect) + sizeof (void*)];
-    *reinterpret_cast<void**>(pBuf) = aNextChunk;
-    nsRegion::RgnRect* pRect = reinterpret_cast<nsRegion::RgnRect*>(pBuf + sizeof (void*));
-
-    for (uint32_t cnt = 0 ; cnt < aEntries - 1 ; cnt++)
-      pRect [cnt].next = &pRect [cnt + 1];
-
-    pRect [aEntries - 1].next = aTailDest;
-
-    return pBuf;
-  }
-
-  void FreeChunk (void* aChunk) {  delete [] (uint8_t *) aChunk;  }
-  void* NextChunk (void* aThisChunk) const { return *static_cast<void**>(aThisChunk); }
-
-  nsRegion::RgnRect* ChunkHead (void* aThisChunk) const
-  {   return reinterpret_cast<nsRegion::RgnRect*>(static_cast<uint8_t*>(aThisChunk) + sizeof (void*));  }
-
-public:
-  RgnRectMemoryAllocator (uint32_t aNumOfEntries);
- ~RgnRectMemoryAllocator ();
-
-  nsRegion::RgnRect* Alloc ();
-  void Free (nsRegion::RgnRect* aRect);
-};
-
-
-RgnRectMemoryAllocator::RgnRectMemoryAllocator (uint32_t aNumOfEntries)
-{
-  InitLock ();
-  mChunkListHead = AllocChunk (aNumOfEntries, nullptr, nullptr);
-  mFreeEntries   = aNumOfEntries;
-  mFreeListHead  = ChunkHead (mChunkListHead);
-}
-
-RgnRectMemoryAllocator::~RgnRectMemoryAllocator ()
-{
-  while (mChunkListHead)
-  {
-    void* tmp = mChunkListHead;
-    mChunkListHead = NextChunk (mChunkListHead);
-    FreeChunk (tmp);
-  }
-
-#if 0
-  /*
-   * As a static object this class outlives any library which would implement
-   * locking. So we intentionally leak the 'lock'.
-   *
-   * Currently RgnRectMemoryAllocator is only used from the primary thread,
-   * so we aren't using a lock which means that there is no lock to leak.
-   * If we ever switch to multiple GUI threads (e.g. one per window),
-   * we'd probably use one allocator per window-thread to avoid the
-   * locking overhead and just require consumers not to pass regions
-   * across threads/windows, which would be a reasonable restriction
-   * because they wouldn't be useful outside their window.
-   */
-  DestroyLock ();
-#endif
-}
-
-nsRegion::RgnRect* RgnRectMemoryAllocator::Alloc ()
-{
-  Lock ();
-
-  if (mFreeEntries == 0)
-  {
-    mChunkListHead = AllocChunk (INCR_MEM_CHUNK_ENTRIES, mChunkListHead, mFreeListHead);
-    mFreeEntries   = INCR_MEM_CHUNK_ENTRIES;
-    mFreeListHead  = ChunkHead (mChunkListHead);
-  }
-
-  nsRegion::RgnRect* tmp = mFreeListHead;
-  mFreeListHead = mFreeListHead->next;
-  mFreeEntries--;
-  Unlock ();
-
-  return tmp;
-}
-
-void RgnRectMemoryAllocator::Free (nsRegion::RgnRect* aRect)
-{
-  Lock ();
-  mFreeEntries++;
-  aRect->next = mFreeListHead;
-  mFreeListHead = aRect;
-  Unlock ();
-}
-
-
-// Global pool for nsRegion::RgnRect allocation
-mozilla::ThreadLocal<RgnRectMemoryAllocator*> gRectPoolTlsIndex;
-
-void RgnRectMemoryAllocatorDTOR(void *priv)
-{
-  RgnRectMemoryAllocator* allocator = gRectPoolTlsIndex.get();
-  delete allocator;
-}
-
-nsresult nsRegion::InitStatic()
-{
-  if (gRectPoolTlsIndex.initialized()) {
-    // It's ok to call InitStatic if we called ShutdownStatic first
-    MOZ_ASSERT(gRectPoolTlsIndex.get() == nullptr);
-    return NS_OK;
-  }
-
-  return gRectPoolTlsIndex.init() ? NS_OK : NS_ERROR_FAILURE;
-}
-
-void nsRegion::ShutdownStatic()
-{
-  RgnRectMemoryAllocator* allocator = gRectPoolTlsIndex.get();
-  if (!allocator)
-    return;
-
-  delete allocator;
-
-  gRectPoolTlsIndex.set(nullptr);
-}
-
-void* nsRegion::RgnRect::operator new (size_t) CPP_THROW_NEW
-{
-  RgnRectMemoryAllocator* allocator = gRectPoolTlsIndex.get();
-  if (!allocator) {
-    allocator = new RgnRectMemoryAllocator(INIT_MEM_CHUNK_ENTRIES);
-    gRectPoolTlsIndex.set(allocator);
-  }
-  return allocator->Alloc ();
-}
-
-void nsRegion::RgnRect::operator delete (void* aRect, size_t)
-{
-  RgnRectMemoryAllocator* allocator = gRectPoolTlsIndex.get();
-  if (!allocator) {
-    NS_ERROR("Invalid nsRegion::RgnRect delete");
-    return;
-  }
-  allocator->Free (static_cast<RgnRect*>(aRect));
-}
-
-
-
-void nsRegion::Init()
-{
-  mRectListHead.prev = mRectListHead.next = &mRectListHead;
-  mCurRect = &mRectListHead;
-  mRectCount = 0;
-  mBoundRect.SetRect (0, 0, 0, 0);
-}
-
-inline void nsRegion::InsertBefore (RgnRect* aNewRect, RgnRect* aRelativeRect)
-{
-  aNewRect->prev = aRelativeRect->prev;
-  aNewRect->next = aRelativeRect;
-  aRelativeRect->prev->next = aNewRect;
-  aRelativeRect->prev = aNewRect;
-  mCurRect = aNewRect;
-  mRectCount++;
-}
-
-inline void nsRegion::InsertAfter (RgnRect* aNewRect, RgnRect* aRelativeRect)
-{
-  aNewRect->prev = aRelativeRect;
-  aNewRect->next = aRelativeRect->next;
-  aRelativeRect->next->prev = aNewRect;
-  aRelativeRect->next = aNewRect;
-  mCurRect = aNewRect;
-  mRectCount++;
-}
-
-
-// Adjust the number of rectangles in region.
-// Content of rectangles should be changed by caller.
-
-void nsRegion::SetToElements (uint32_t aCount)
-{
-  if (mRectCount < aCount)        // Add missing rectangles
-  {
-    uint32_t InsertCount = aCount - mRectCount;
-    mRectCount = aCount;
-    RgnRect* pPrev = &mRectListHead;
-    RgnRect* pNext = mRectListHead.next;
-
-    while (InsertCount--)
-    {
-      mCurRect = new RgnRect;
-      mCurRect->prev = pPrev;
-      pPrev->next = mCurRect;
-      pPrev = mCurRect;
-    }
-
-    pPrev->next = pNext;
-    pNext->prev = pPrev;
-  } else
-  if (mRectCount > aCount)        // Remove unnecessary rectangles
-  {
-    uint32_t RemoveCount = mRectCount - aCount;
-    mRectCount = aCount;
-    mCurRect = mRectListHead.next;
-
-    while (RemoveCount--)
-    {
-      RgnRect* tmp = mCurRect;
-      mCurRect = mCurRect->next;
-      delete tmp;
-    }
-
-    mRectListHead.next = mCurRect;
-    mCurRect->prev = &mRectListHead;
-  }
-}
-
-
-// Save the entire chain of linked elements in 'prev' field of the RgnRect structure.
-// After that forward-only iterations using 'next' field could still be used.
-// Some elements from forward-only chain could be temporarily removed to optimize inner loops.
-// The original double linked state could be restored by call to RestoreLinkChain ().
-// Both functions despite size can be inline because they are called only from one function.
-
-inline void nsRegion::SaveLinkChain ()
-{
-  RgnRect* pRect = &mRectListHead;
-
-  do
-  {
-    pRect->prev = pRect->next;
-    pRect = pRect->next;
-  } while (pRect != &mRectListHead);
-}
-
-
-inline void nsRegion::RestoreLinkChain ()
-{
-  RgnRect* pPrev = &mRectListHead;
-  RgnRect* pRect = mRectListHead.next = mRectListHead.prev;
-
-  while (pRect != &mRectListHead)
-  {
-    pRect->next = pRect->prev;
-    pRect->prev = pPrev;
-    pPrev = pRect;
-    pRect = pRect->next;
-  }
-
-  mRectListHead.prev = pPrev;
-}
-
-
-// Insert node in right place of sorted list
-// If necessary then bounding rectangle could be updated and rectangle combined
-// with neighbour rectangles. This is usually done in Optimize ()
-
-void nsRegion::InsertInPlace (RgnRect* aRect, bool aOptimizeOnFly)
-{
-  if (mRectCount == 0)
-    InsertAfter (aRect, &mRectListHead);
-  else
-  {
-    if (aRect->y > mCurRect->y)
-    {
-      mRectListHead.y = NS_COORD_GREATER_SENTINEL;
-      while (aRect->y > mCurRect->next->y)
-        mCurRect = mCurRect->next;
-
-      mRectListHead.x = NS_COORD_GREATER_SENTINEL;
-      while (aRect->y == mCurRect->next->y && aRect->x > mCurRect->next->x)
-        mCurRect = mCurRect->next;
-
-      InsertAfter (aRect, mCurRect);
-    } else
-    if (aRect->y < mCurRect->y)
-    {
-      mRectListHead.y = NS_COORD_LESS_SENTINEL;
-      while (aRect->y < mCurRect->prev->y)
-        mCurRect = mCurRect->prev;
-
-      mRectListHead.x = NS_COORD_LESS_SENTINEL;
-      while (aRect->y == mCurRect->prev->y && aRect->x < mCurRect->prev->x)
-        mCurRect = mCurRect->prev;
-
-      InsertBefore (aRect, mCurRect);
-    } else
-    {
-      if (aRect->x > mCurRect->x)
-      {
-        mRectListHead.x = NS_COORD_GREATER_SENTINEL;
-        while (aRect->y == mCurRect->next->y && aRect->x > mCurRect->next->x)
-          mCurRect = mCurRect->next;
-
-        InsertAfter (aRect, mCurRect);
-      } else
-      {
-        mRectListHead.x = NS_COORD_LESS_SENTINEL;
-        while (aRect->y == mCurRect->prev->y && aRect->x < mCurRect->prev->x)
-          mCurRect = mCurRect->prev;
-
-        InsertBefore (aRect, mCurRect);
-      }
-    }
-  }
-
-
-  if (aOptimizeOnFly)
-  {
-    if (mRectCount == 1)
-      mBoundRect = *mCurRect;
-    else
-    {
-      mBoundRect.UnionRect (mBoundRect, *mCurRect);
-
-      // Check if we can go left or up before starting to combine rectangles
-      if ((mCurRect->y == mCurRect->prev->y && mCurRect->height == mCurRect->prev->height &&
-           mCurRect->x == mCurRect->prev->XMost ()) ||
-          (mCurRect->x == mCurRect->prev->x && mCurRect->width == mCurRect->prev->width &&
-           mCurRect->y == mCurRect->prev->YMost ()) )
-        mCurRect = mCurRect->prev;
-
-      // Try to combine with rectangle on right side
-      while (mCurRect->y == mCurRect->next->y && mCurRect->height == mCurRect->next->height &&
-             mCurRect->XMost () == mCurRect->next->x)
-      {
-        mCurRect->width += mCurRect->next->width;
-        delete Remove (mCurRect->next);
-      }
-
-      // Try to combine with rectangle under this one
-      while (mCurRect->x == mCurRect->next->x && mCurRect->width == mCurRect->next->width &&
-             mCurRect->YMost () == mCurRect->next->y)
-      {
-        mCurRect->height += mCurRect->next->height;
-        delete Remove (mCurRect->next);
-      }
-    }
-  }
-}
-
-
-nsRegion::RgnRect* nsRegion::Remove (RgnRect* aRect)
-{
-  aRect->prev->next = aRect->next;
-  aRect->next->prev = aRect->prev;
-  mRectCount--;
-
-  if (mCurRect == aRect)
-    mCurRect = (aRect->next != &mRectListHead) ? aRect->next : aRect->prev;
-
-  return aRect;
-}
-
-
-// Try to reduce the number of rectangles in complex region by combining with
-// surrounding ones on right and bottom sides of each rectangle in list.
-// Update bounding rectangle
-
-void nsRegion::Optimize ()
-{
-  if (mRectCount == 0)
-    mBoundRect.SetRect (0, 0, 0, 0);
-  else
-  {
-    RgnRect* pRect = mRectListHead.next;
-    int32_t xmost = mRectListHead.prev->XMost ();
-    int32_t ymost = mRectListHead.prev->YMost ();
-    mBoundRect.x = mRectListHead.next->x;
-    mBoundRect.y = mRectListHead.next->y;
-
-    while (pRect != &mRectListHead)
-    {
-      // Try to combine with rectangle on right side
-      while (pRect->y == pRect->next->y && pRect->height == pRect->next->height &&
-             pRect->XMost () == pRect->next->x)
-      {
-        pRect->width += pRect->next->width;
-        delete Remove (pRect->next);
-      }
-
-      // Try to combine with rectangle under this one
-      while (pRect->x == pRect->next->x && pRect->width == pRect->next->width &&
-             pRect->YMost () == pRect->next->y)
-      {
-        pRect->height += pRect->next->height;
-        delete Remove (pRect->next);
-      }
-
-      // Determine bound rectangle. Use fact that rectangles are sorted.
-      if (pRect->x < mBoundRect.x) mBoundRect.x = pRect->x;
-      if (pRect->XMost () > xmost) xmost = pRect->XMost ();
-      if (pRect->YMost () > ymost) ymost = pRect->YMost ();
-
-      pRect = pRect->next;
-    }
-
-    mBoundRect.width  = xmost - mBoundRect.x;
-    mBoundRect.height = ymost - mBoundRect.y;
-  }
-}
+#include "nsPrintfCString.h"
+#include "nsTArray.h"
 
 
-// Move rectangles starting from 'aStartRect' till end of the list to the destionation region.
-// Important for temporary objects - instead of copying rectangles with Merge () and then
-// emptying region in destructor they could be moved to destination region in one step.
-
-void nsRegion::MoveInto (nsRegion& aDestRegion, const RgnRect* aStartRect)
-{
-  RgnRect* pRect = const_cast<RgnRect*>(aStartRect);
-  RgnRect* pPrev = pRect->prev;
-
-  while (pRect != &mRectListHead)
-  {
-    RgnRect* next = pRect->next;
-    aDestRegion.InsertInPlace (pRect);
-
-    mRectCount--;
-    pRect = next;
-  }
-
-  pPrev->next = &mRectListHead;
-  mRectListHead.prev = pPrev;
-  mCurRect = mRectListHead.next;
-}
-
-
-// Merge two non-overlapping regions into one.
-// Automatically optimize region by calling Optimize ()
-
-void nsRegion::Merge (const nsRegion& aRgn1, const nsRegion& aRgn2)
-{
-  if (aRgn1.mRectCount == 0)            // Region empty. Result is equal to other region
-    Copy (aRgn2);
-  else
-  if (aRgn2.mRectCount == 0)            // Region empty. Result is equal to other region
-    Copy (aRgn1);
-  if (aRgn1.mRectCount == 1)            // Region is single rectangle. Optimize on fly
-  {
-    RgnRect* TmpRect = new RgnRect (*aRgn1.mRectListHead.next);
-    Copy (aRgn2);
-    InsertInPlace (TmpRect, true);
-  } else
-  if (aRgn2.mRectCount == 1)            // Region is single rectangle. Optimize on fly
-  {
-    RgnRect* TmpRect = new RgnRect (*aRgn2.mRectListHead.next);
-    Copy (aRgn1);
-    InsertInPlace (TmpRect, true);
-  } else
-  {
-    const nsRegion* pCopyRegion, *pInsertRegion;
-
-    // Determine which region contains more rectangles. Copy the larger one
-    if (aRgn1.mRectCount >= aRgn2.mRectCount)
-    {
-      pCopyRegion = &aRgn1;
-      pInsertRegion = &aRgn2;
-    } else
-    {
-      pCopyRegion = &aRgn2;
-      pInsertRegion = &aRgn1;
-    }
-
-    if (pInsertRegion == this)          // Do merge in-place
-      pInsertRegion = pCopyRegion;
-    else
-      Copy (*pCopyRegion);
-
-    const RgnRect* pSrcRect = pInsertRegion->mRectListHead.next;
-
-    while (pSrcRect != &pInsertRegion->mRectListHead)
-    {
-      InsertInPlace (new RgnRect (*pSrcRect));
-
-      pSrcRect = pSrcRect->next;
-    }
-
-    Optimize ();
-  }
-}
-
-
-nsRegion& nsRegion::Copy (const nsRegion& aRegion)
-{
-  if (&aRegion == this)
-    return *this;
-
-  if (aRegion.mRectCount == 0)
-    SetEmpty ();
-  else
-  {
-    SetToElements (aRegion.mRectCount);
-
-    const RgnRect* pSrc = aRegion.mRectListHead.next;
-    RgnRect* pDest = mRectListHead.next;
-
-    while (pSrc != &aRegion.mRectListHead)
-    {
-      *pDest = *pSrc;
-
-      pSrc  = pSrc->next;
-      pDest = pDest->next;
-    }
-
-    mCurRect = mRectListHead.next;
-    mBoundRect = aRegion.mBoundRect;
-  }
-
-  return *this;
-}
-
-
-nsRegion& nsRegion::Copy (const nsRect& aRect)
-{
-  if (aRect.IsEmpty ())
-    SetEmpty ();
-  else
-  {
-    SetToElements (1);
-    *mRectListHead.next = static_cast<const RgnRect&>(aRect);
-    mBoundRect = static_cast<const nsRectFast&>(aRect);
-  }
-
-  return *this;
-}
-
-
-nsRegion& nsRegion::And (const nsRegion& aRgn1, const nsRegion& aRgn2)
-{
-  if (&aRgn1 == &aRgn2)                                       // And with self
-    Copy (aRgn1);
-  else
-  if (aRgn1.mRectCount == 0 || aRgn2.mRectCount == 0)         // If either region is empty then result is empty
-    SetEmpty ();
-  else
-  {
-    nsRectFast TmpRect;
-
-    if (aRgn1.mRectCount == 1 && aRgn2.mRectCount == 1)       // Intersect rectangle with rectangle
-    {
-      TmpRect.IntersectRect (*aRgn1.mRectListHead.next, *aRgn2.mRectListHead.next);
-      Copy (TmpRect);
-    } else
-    {
-      if (!aRgn1.mBoundRect.Intersects (aRgn2.mBoundRect))    // Regions do not intersect
-        SetEmpty ();
-      else
-      {
-        // Region is simple rectangle and it fully overlays other region
-        if (aRgn1.mRectCount == 1 && aRgn1.mBoundRect.Contains (aRgn2.mBoundRect))
-          Copy (aRgn2);
-        else
-        // Region is simple rectangle and it fully overlays other region
-        if (aRgn2.mRectCount == 1 && aRgn2.mBoundRect.Contains (aRgn1.mBoundRect))
-          Copy (aRgn1);
-        else
-        {
-          nsRegion TmpRegion;
-          nsRegion* pSrcRgn1 = const_cast<nsRegion*>(&aRgn1);
-          nsRegion* pSrcRgn2 = const_cast<nsRegion*>(&aRgn2);
-
-          if (&aRgn1 == this)     // Copy region if it is both source and result
-          {
-            TmpRegion.Copy (aRgn1);
-            pSrcRgn1 = &TmpRegion;
-          }
-
-          if (&aRgn2 == this)     // Copy region if it is both source and result
-          {
-            TmpRegion.Copy (aRgn2);
-            pSrcRgn2 = &TmpRegion;
-          }
-
-          // For outer loop prefer region for which at least one rectangle is below other's bound rectangle
-          if (pSrcRgn2->mRectListHead.prev->y >= pSrcRgn1->mBoundRect.YMost ())
-          {
-            nsRegion* Tmp = pSrcRgn1;
-            pSrcRgn1 = pSrcRgn2;
-            pSrcRgn2 = Tmp;
-          }
-
-
-          SetToElements (0);
-          pSrcRgn2->SaveLinkChain ();
-
-          pSrcRgn1->mRectListHead.y = NS_COORD_GREATER_SENTINEL;
-          pSrcRgn2->mRectListHead.y = NS_COORD_GREATER_SENTINEL;
-
-          for (RgnRect* pSrcRect1 = pSrcRgn1->mRectListHead.next ;
-               pSrcRect1->y < pSrcRgn2->mBoundRect.YMost () ; pSrcRect1 = pSrcRect1->next)
-          {
-            if (pSrcRect1->Intersects (pSrcRgn2->mBoundRect))   // Rectangle intersects region. Process each rectangle
-            {
-              RgnRect* pPrev2 = &pSrcRgn2->mRectListHead;
-
-              for (RgnRect* pSrcRect2 = pSrcRgn2->mRectListHead.next ;
-                   pSrcRect2->y < pSrcRect1->YMost () ; pSrcRect2 = pSrcRect2->next)
-              {
-                if (pSrcRect2->YMost () <= pSrcRect1->y)        // Rect2's bottom is above the top of Rect1.
-                {                                               // No successive rectangles in Rgn1 can intersect it.
-                  pPrev2->next = pSrcRect2->next;               // Remove Rect2 from Rgn2's checklist
-                  continue;
-                }
-
-                if (pSrcRect1->Contains (*pSrcRect2))           // Rect1 fully overlays Rect2.
-                {                                               // No any other rectangle in Rgn1 can intersect it.
-                  pPrev2->next = pSrcRect2->next;               // Remove Rect2 from Rgn2's checklist
-                  InsertInPlace (new RgnRect (*pSrcRect2));
-                  continue;
-                }
-
-
-                if (TmpRect.IntersectRect (*pSrcRect1, *pSrcRect2))
-                  InsertInPlace (new RgnRect (TmpRect));
-
-                pPrev2 = pSrcRect2;
-              }
-            }
-          }
-
-          pSrcRgn2->RestoreLinkChain ();
-          Optimize ();
-        }
-      }
-    }
-  }
-
-  return *this;
-}
-
-
-nsRegion& nsRegion::And (const nsRegion& aRegion, const nsRect& aRect)
-{
-  // If either region or rectangle is empty then result is empty
-  if (aRegion.mRectCount == 0 || aRect.IsEmpty ())
-    SetEmpty ();
-  else                            // Intersect region with rectangle
-  {
-    const nsRectFast& aRectFast = static_cast<const nsRectFast&>(aRect);
-    nsRectFast TmpRect;
-
-    if (aRegion.mRectCount == 1)  // Intersect rectangle with rectangle
-    {
-      TmpRect.IntersectRect (*aRegion.mRectListHead.next, aRectFast);
-      Copy (TmpRect);
-    } else                        // Intersect complex region with rectangle
-    {
-      if (!aRectFast.Intersects (aRegion.mBoundRect))   // Rectangle does not intersect region
-        SetEmpty ();
-      else
-      {
-        if (aRectFast.Contains (aRegion.mBoundRect))    // Rectangle fully overlays region
-          Copy (aRegion);
-        else
-        {
-          nsRegion TmpRegion;
-          nsRegion* pSrcRegion = const_cast<nsRegion*>(&aRegion);
-
-          if (&aRegion == this)   // Copy region if it is both source and result
-          {
-            TmpRegion.Copy (aRegion);
-            pSrcRegion = &TmpRegion;
-          }
-
-          SetToElements (0);
-          pSrcRegion->mRectListHead.y = NS_COORD_GREATER_SENTINEL;
-
-          for (const RgnRect* pSrcRect = pSrcRegion->mRectListHead.next ;
-               pSrcRect->y < aRectFast.YMost () ; pSrcRect = pSrcRect->next)
-          {
-            if (TmpRect.IntersectRect (*pSrcRect, aRectFast))
-              InsertInPlace (new RgnRect (TmpRect));
-          }
-
-          Optimize ();
-        }
-      }
-    }
-  }
-
-  return *this;
-}
-
-
-nsRegion& nsRegion::Or (const nsRegion& aRgn1, const nsRegion& aRgn2)
-{
-  if (&aRgn1 == &aRgn2)                 // Or with self
-    Copy (aRgn1);
-  else
-  if (aRgn1.mRectCount == 0)            // Region empty. Result is equal to other region
-    Copy (aRgn2);
-  else
-  if (aRgn2.mRectCount == 0)            // Region empty. Result is equal to other region
-    Copy (aRgn1);
-  else
-  {
-    if (!aRgn1.mBoundRect.Intersects (aRgn2.mBoundRect))  // Regions do not intersect
-      Merge (aRgn1, aRgn2);
-    else
-    {
-      // Region is simple rectangle and it fully overlays other region
-      if (aRgn1.mRectCount == 1 && aRgn1.mBoundRect.Contains (aRgn2.mBoundRect))
-        Copy (aRgn1);
-      else
-      // Region is simple rectangle and it fully overlays other region
-      if (aRgn2.mRectCount == 1 && aRgn2.mBoundRect.Contains (aRgn1.mBoundRect))
-        Copy (aRgn2);
-      else
-      {
-        nsRegion TmpRegion;
-        aRgn1.SubRegion (aRgn2, TmpRegion);               // Get only parts of region which not overlap the other region
-        Copy (aRgn2);
-        TmpRegion.MoveInto (*this);
-        Optimize ();
-      }
-    }
-  }
-
-  return *this;
-}
-
-
-nsRegion& nsRegion::Or (const nsRegion& aRegion, const nsRect& aRect)
-{
-  if (aRegion.mRectCount == 0)          // Region empty. Result is equal to rectangle
-    Copy (aRect);
-  else
-  if (aRect.IsEmpty ())                 // Rectangle is empty. Result is equal to region
-    Copy (aRegion);
-  else
-  {
-    const nsRectFast& aRectFast = static_cast<const nsRectFast&>(aRect);
-
-    if (!aRectFast.Intersects (aRegion.mBoundRect))     // Rectangle does not intersect region
-    {
-      Copy (aRegion);
-      InsertInPlace (new RgnRect (aRectFast), true);
-    } else
-    {
-      // Region is simple rectangle and it fully overlays rectangle
-      if (aRegion.mRectCount == 1 && aRegion.mBoundRect.Contains (aRectFast))
-        Copy (aRegion);
-      else
-      if (aRectFast.Contains (aRegion.mBoundRect))      // Rectangle fully overlays region
-        Copy (aRectFast);
-      else
-      {
-        aRegion.SubRect (aRectFast, *this);             // Exclude from region parts that overlap the rectangle
-        InsertInPlace (new RgnRect (aRectFast));
-        Optimize ();
-      }
-    }
-  }
-
-  return *this;
-}
-
-
-nsRegion& nsRegion::Xor (const nsRegion& aRgn1, const nsRegion& aRgn2)
-{
-  if (&aRgn1 == &aRgn2)                 // Xor with self
-    SetEmpty ();
-  else
-  if (aRgn1.mRectCount == 0)            // Region empty. Result is equal to other region
-    Copy (aRgn2);
-  else
-  if (aRgn2.mRectCount == 0)            // Region empty. Result is equal to other region
-    Copy (aRgn1);
-  else
-  {
-    if (!aRgn1.mBoundRect.Intersects (aRgn2.mBoundRect))      // Regions do not intersect
-      Merge (aRgn1, aRgn2);
-    else
-    {
-      // Region is simple rectangle and it fully overlays other region
-      if (aRgn1.mRectCount == 1 && aRgn1.mBoundRect.Contains (aRgn2.mBoundRect))
-      {
-        aRgn1.SubRegion (aRgn2, *this);
-        Optimize ();
-      } else
-      // Region is simple rectangle and it fully overlays other region
-      if (aRgn2.mRectCount == 1 && aRgn2.mBoundRect.Contains (aRgn1.mBoundRect))
-      {
-        aRgn2.SubRegion (aRgn1, *this);
-        Optimize ();
-      } else
-      {
-        nsRegion TmpRegion;
-        aRgn1.SubRegion (aRgn2, TmpRegion);
-        aRgn2.SubRegion (aRgn1, *this);
-        TmpRegion.MoveInto (*this);
-        Optimize ();
-      }
-    }
-  }
-
-  return *this;
-}
-
-
-nsRegion& nsRegion::Xor (const nsRegion& aRegion, const nsRect& aRect)
-{
-  if (aRegion.mRectCount == 0)          // Region empty. Result is equal to rectangle
-    Copy (aRect);
-  else
-  if (aRect.IsEmpty ())                 // Rectangle is empty. Result is equal to region
-    Copy (aRegion);
-  else
-  {
-    const nsRectFast& aRectFast = static_cast<const nsRectFast&>(aRect);
-
-    if (!aRectFast.Intersects (aRegion.mBoundRect))     // Rectangle does not intersect region
-    {
-      Copy (aRegion);
-      InsertInPlace (new RgnRect (aRectFast), true);
-    } else
-    {
-      // Region is simple rectangle and it fully overlays rectangle
-      if (aRegion.mRectCount == 1 && aRegion.mBoundRect.Contains (aRectFast))
-      {
-        aRegion.SubRect (aRectFast, *this);
-        Optimize ();
-      } else
-      if (aRectFast.Contains (aRegion.mBoundRect))      // Rectangle fully overlays region
-      {
-        nsRegion TmpRegion;
-        TmpRegion.Copy (aRectFast);
-        TmpRegion.SubRegion (aRegion, *this);
-        Optimize ();
-      } else
-      {
-        nsRegion TmpRegion;
-        TmpRegion.Copy (aRectFast);
-        TmpRegion.SubRegion (aRegion, TmpRegion);
-        aRegion.SubRect (aRectFast, *this);
-        TmpRegion.MoveInto (*this);
-        Optimize ();
-      }
-    }
-  }
-
-  return *this;
-}
-
-
-nsRegion& nsRegion::Sub (const nsRegion& aRgn1, const nsRegion& aRgn2)
-{
-  if (&aRgn1 == &aRgn2)         // Sub from self
-    SetEmpty ();
-  else
-  if (aRgn1.mRectCount == 0)    // If source is empty then result is empty, too
-    SetEmpty ();
-  else
-  if (aRgn2.mRectCount == 0)    // Nothing to subtract
-    Copy (aRgn1);
-  else
-  {
-    if (!aRgn1.mBoundRect.Intersects (aRgn2.mBoundRect))   // Regions do not intersect
-      Copy (aRgn1);
-    else
-    {
-      aRgn1.SubRegion (aRgn2, *this);
-      Optimize ();
-    }
-  }
-
-  return *this;
-}
-
-
-nsRegion& nsRegion::Sub (const nsRegion& aRegion, const nsRect& aRect)
-{
-  if (aRegion.mRectCount == 0)    // If source is empty then result is empty, too
-    SetEmpty ();
-  else
-  if (aRect.IsEmpty ())           // Nothing to subtract
-    Copy (aRegion);
-  else
-  {
-    const nsRectFast& aRectFast = static_cast<const nsRectFast&>(aRect);
-
-    if (!aRectFast.Intersects (aRegion.mBoundRect))   // Rectangle does not intersect region
-      Copy (aRegion);
-    else
-    {
-      if (aRectFast.Contains (aRegion.mBoundRect))    // Rectangle fully overlays region
-        SetEmpty ();
-      else
-      {
-        aRegion.SubRect (aRectFast, *this);
-        Optimize ();
-      }
-    }
-  }
-
-  return *this;
-}
-
-bool nsRegion::Contains (const nsRect& aRect) const
-{
-  if (aRect.IsEmpty())
-    return true;
-  if (IsEmpty())
-    return false;
-  if (!IsComplex())
-    return mBoundRect.Contains (aRect);
-
-  nsRegion tmpRgn;
-  tmpRgn.Sub(aRect, *this);
-  return tmpRgn.IsEmpty();
-}
-
-bool nsRegion::Contains (const nsRegion& aRgn) const
+bool nsRegion::Contains(const nsRegion& aRgn) const
 {
   // XXX this could be made faster
   nsRegionRectIterator iter(aRgn);
   while (const nsRect* r = iter.Next()) {
     if (!Contains (*r)) {
       return false;
     }
   }
   return true;
 }
 
-bool nsRegion::Intersects (const nsRect& aRect) const
+bool nsRegion::Intersects(const nsRect& aRect) const
 {
-  if (aRect.IsEmpty() || IsEmpty())
-    return false;
-
-  const RgnRect* r = mRectListHead.next;
-  while (r != &mRectListHead)
-  {
-    if (r->Intersects(aRect))
+  // XXX this could be made faster
+  nsRegionRectIterator iter(*this);
+  while (const nsRect* r = iter.Next()) {
+    if (r->Intersects(aRect)) {
       return true;
-    r = r->next;
+    }
   }
   return false;
 }
 
-// Subtract region from current region.
-// Both regions are non-empty and they intersect each other.
-// Result could be empty region if aRgn2 is rectangle that fully overlays aRgn1.
-// Optimize () is not called on exit (bound rectangle is not updated).
-
-void nsRegion::SubRegion (const nsRegion& aRegion, nsRegion& aResult) const
+void nsRegion::SimplifyOutward (uint32_t aMaxRects)
 {
-  if (aRegion.mRectCount == 1)    // Subtract simple rectangle
-  {
-    if (aRegion.mBoundRect.Contains (mBoundRect))
-      aResult.SetEmpty ();
-    else
-      SubRect (*aRegion.mRectListHead.next, aResult);
-  } else
-  {
-    nsRegion TmpRegion, CompletedRegion;
-    const nsRegion* pSubRgn = &aRegion;
+  MOZ_ASSERT(aMaxRects >= 1, "Invalid max rect count");
+
+  if (GetNumRects() <= aMaxRects)
+    return;
+
+  pixman_box32_t *boxes;
+  int n;
+  boxes = pixman_region32_rectangles(&mImpl, &n);
 
-    if (&aResult == &aRegion)     // Copy region if it is both source and result
-    {
-      TmpRegion.Copy (aRegion);
-      pSubRgn = &TmpRegion;
+  // Try combining rects in horizontal bands into a single rect
+  int dest = 0;
+  for (int src = 1; src < n; src++)
+  {
+    // The goal here is to try to keep groups of rectangles that are vertically
+    // discontiguous as separate rectangles in the final region. This is
+    // simple and fast to implement and page contents tend to vary more
+    // vertically than horizontally (which is why our rectangles are stored
+    // sorted by y-coordinate, too).
+    //
+    // Note: if boxes share y1 because of the canonical representation they
+    // will share y2
+    while ((src < (n)) && boxes[dest].y1 == boxes[src].y1) {
+      // merge box[i] and box[i+1]
+      boxes[dest].x2 = boxes[src].x2;
+      src++;
     }
-
-    const RgnRect* pSubRect = pSubRgn->mRectListHead.next;
+    if (src < n) {
+      dest++;
+      boxes[dest] = boxes[src];
+    }
+  }
 
-    SubRect (*pSubRect, aResult, CompletedRegion);
-    pSubRect = pSubRect->next;
-
-    while (pSubRect != &pSubRgn->mRectListHead)
-    {
-      aResult.SubRect (*pSubRect, aResult, CompletedRegion);
-      pSubRect = pSubRect->next;
-    }
-
-    CompletedRegion.MoveInto (aResult);
+  uint32_t reducedCount = dest+1;
+  // pixman has a special representation for
+  // regions of 1 rectangle. So just use the
+  // bounds in that case
+  if (reducedCount > 1 && reducedCount <= aMaxRects) {
+    // reach into pixman and lower the number
+    // of rects stored in data.
+    mImpl.data->numRects = reducedCount;
+  } else {
+    *this = GetBounds();
   }
 }
 
-
-// Subtract rectangle from current region.
-// Both region and rectangle are non-empty and they intersect each other.
-// Result could be empty region if aRect fully overlays aRegion.
-// Could be called repeatedly with 'this' as input and result - bound rectangle is not known.
-// Optimize () is not called on exit (bound rectangle is not updated).
-//
-// aCompleted is filled with rectangles which are already checked and could be safely
-// removed from further examination in case aRect rectangles come from ordered list.
-// aCompleted is not automatically emptied. aCompleted and aResult could be the same region.
-
-void nsRegion::SubRect (const nsRectFast& aRect, nsRegion& aResult, nsRegion& aCompleted) const
+void nsRegion::SimplifyInward (uint32_t aMaxRects)
 {
-  nsRegion TmpRegion;
-  const nsRegion* pSrcRegion = this;
-
-  if (&aResult == this)           // Copy region if it is both source and result
-  {
-    TmpRegion.Copy (*this);
-    pSrcRegion = &TmpRegion;
-  }
-
-  aResult.SetToElements (0);
-
-  const_cast<nsRegion*>(pSrcRegion)->mRectListHead.y = NS_COORD_GREATER_SENTINEL;
-  const RgnRect* pSrcRect = pSrcRegion->mRectListHead.next;
-
-  for ( ; pSrcRect->y < aRect.YMost () ; pSrcRect = pSrcRect->next)
-  {
-    nsRectFast TmpRect;
-
-    // If bottom of current rectangle is above the top of aRect then this rectangle
-    // could be moved to aCompleted region. Successive aRect rectangles from ordered
-    // list do not have to check this rectangle again.
-    if (pSrcRect->YMost () <= aRect.y)
-    {
-      aCompleted.InsertInPlace (new RgnRect (*pSrcRect));
-      continue;
-    }
-
-    if (!TmpRect.IntersectRect (*pSrcRect, aRect))
-      aResult.InsertInPlace (new RgnRect (*pSrcRect));
-    else
-    {
-      // Rectangle A. Subtract from this rectangle B
-      const nscoord ax  = pSrcRect->x;
-      const nscoord axm = pSrcRect->XMost ();
-      const nscoord aw  = pSrcRect->width;
-      const nscoord ay  = pSrcRect->y;
-      const nscoord aym = pSrcRect->YMost ();
-      const nscoord ah  = pSrcRect->height;
-      // Rectangle B. Subtract this from rectangle A
-      const nscoord bx  = aRect.x;
-      const nscoord bxm = aRect.XMost ();
-      const nscoord by  = aRect.y;
-      const nscoord bym = aRect.YMost ();
-      // Rectangle I. Area where rectangles A and B intersect
-      const nscoord ix  = TmpRect.x;
-      const nscoord ixm = TmpRect.XMost ();
-      const nscoord iy  = TmpRect.y;
-      const nscoord iym = TmpRect.YMost ();
-      const nscoord ih  = TmpRect.height;
-
-      // There are 16 combinations how rectangles could intersect
+  NS_ASSERTION(aMaxRects >= 1, "Invalid max rect count");
 
-      if (bx <= ax && by <= ay)
-      {
-        if (bxm < axm && bym < aym)     // 1.
-        {
-          aResult.InsertInPlace (new RgnRect (ixm, ay, axm - ixm, ih));
-          aResult.InsertInPlace (new RgnRect (ax, iym, aw, aym - iym));
-        } else
-        if (bxm >= axm && bym < aym)    // 2.
-        {
-          aResult.InsertInPlace (new RgnRect (ax, iym, aw, aym - iym));
-        } else
-        if (bxm < axm && bym >= aym)    // 3.
-        {
-          aResult.InsertInPlace (new RgnRect (ixm, ay, axm - ixm, ah));
-        } else
-        if (pSrcRect->IsEqualInterior(aRect)) // 4. subset
-        {                               // Current rectangle is equal to aRect
-          pSrcRect = pSrcRect->next;    // don't add this one to the result, it's removed
-          break;                        // No any other rectangle in region can intersect it
-        }
-      } else
-      if (bx > ax && by <= ay)
-      {
-        if (bxm < axm && bym < aym)     // 5.
-        {
-          aResult.InsertInPlace (new RgnRect (ax, ay, ix - ax, ih));
-          aResult.InsertInPlace (new RgnRect (ixm, ay, axm - ixm, ih));
-          aResult.InsertInPlace (new RgnRect (ax, iym, aw, aym - iym));
-        } else
-        if (bxm >= axm && bym < aym)    // 6.
-        {
-          aResult.InsertInPlace (new RgnRect (ax, ay, ix - ax, ih));
-          aResult.InsertInPlace (new RgnRect (ax, iym, aw, aym - iym));
-        } else
-        if (bxm < axm && bym >= aym)    // 7.
-        {
-          aResult.InsertInPlace (new RgnRect (ax, ay, ix - ax, ah));
-          aResult.InsertInPlace (new RgnRect (ixm, ay, axm - ixm, ah));
-        } else
-        if (bxm >= axm && bym >= aym)   // 8.
-        {
-          aResult.InsertInPlace (new RgnRect (ax, ay, ix - ax, ah));
-        }
-      } else
-      if (bx <= ax && by > ay)
-      {
-        if (bxm < axm && bym < aym)     // 9.
-        {
-          aResult.InsertInPlace (new RgnRect (ax, ay, aw, iy - ay));
-          aResult.InsertInPlace (new RgnRect (ixm, iy, axm - ixm, ih));
-          aResult.InsertInPlace (new RgnRect (ax, iym, aw, aym - iym));
-        } else
-        if (bxm >= axm && bym < aym)    // 10.
-        {
-          aResult.InsertInPlace (new RgnRect (ax, ay, aw, iy - ay));
-          aResult.InsertInPlace (new RgnRect (ax, iym, aw, aym - iym));
-        } else
-        if (bxm < axm && bym >= aym)    // 11.
-        {
-          aResult.InsertInPlace (new RgnRect (ax, ay, aw, iy - ay));
-          aResult.InsertInPlace (new RgnRect (ixm, iy, axm - ixm, ih));
-        } else
-        if (bxm >= axm && bym >= aym)   // 12.
-        {
-          aResult.InsertInPlace (new RgnRect (ax, ay, aw, iy - ay));
-        }
-      } else
-      if (bx > ax && by > ay)
-      {
-        if (bxm < axm && bym < aym)     // 13.
-        {
-          aResult.InsertInPlace (new RgnRect (ax, ay, aw, iy - ay));
-          aResult.InsertInPlace (new RgnRect (ax, iy, ix - ax, ih));
-          aResult.InsertInPlace (new RgnRect (ixm, iy, axm - ixm, ih));
-          aResult.InsertInPlace (new RgnRect (ax, iym, aw, aym - iym));
+  if (GetNumRects() <= aMaxRects)
+    return;
 
-          // Current rectangle fully overlays aRect. No any other rectangle can intersect it.
-          pSrcRect = pSrcRect->next;    // don't add this one to the result, it's removed
-          break;
-        } else
-        if (bxm >= axm && bym < aym)    // 14.
-        {
-          aResult.InsertInPlace (new RgnRect (ax, ay, aw, iy - ay));
-          aResult.InsertInPlace (new RgnRect (ax, iy, ix - ax, ih));
-          aResult.InsertInPlace (new RgnRect (ax, iym, aw, aym - iym));
-        } else
-        if (bxm < axm && bym >= aym)    // 15.
-        {
-          aResult.InsertInPlace (new RgnRect (ax, ay, aw, iy - ay));
-          aResult.InsertInPlace (new RgnRect (ax, iy, ix - ax, ih));
-          aResult.InsertInPlace (new RgnRect (ixm, iy, axm - ixm, ih));
-        } else
-        if (bxm >= axm && bym >= aym)   // 16.
-        {
-          aResult.InsertInPlace (new RgnRect (ax, ay, aw, iy - ay));
-          aResult.InsertInPlace (new RgnRect (ax, iy, ix - ax, ih));
-        }
-      }
-    }
-  }
-
-  // Just copy remaining rectangles in region which are below aRect and can't intersect it.
-  // If rectangles are in temporary region then they could be moved.
-  if (pSrcRegion == &TmpRegion)
-    TmpRegion.MoveInto (aResult, pSrcRect);
-  else
-  {
-    while (pSrcRect != &pSrcRegion->mRectListHead)
-    {
-      aResult.InsertInPlace (new RgnRect (*pSrcRect));
-      pSrcRect = pSrcRect->next;
-    }
-  }
+  SetEmpty();
 }
 
-
-bool nsRegion::IsEqual (const nsRegion& aRegion) const
-{
-  if (mRectCount == 0)
-    return (aRegion.mRectCount == 0) ? true : false;
-
-  if (aRegion.mRectCount == 0)
-    return (mRectCount == 0) ? true : false;
-
-  if (mRectCount == 1 && aRegion.mRectCount == 1) // Both regions are simple rectangles
-    return (mRectListHead.next->IsEqualInterior(*aRegion.mRectListHead.next));
-  else                                            // At least one is complex region.
-  {
-    if (!mBoundRect.IsEqualInterior(aRegion.mBoundRect)) // If regions are equal then bounding rectangles should match
-      return false;
-    else
-    {
-      nsRegion TmpRegion;
-      TmpRegion.Xor (*this, aRegion);             // Get difference between two regions
-
-      return (TmpRegion.mRectCount == 0);
-    }
-  }
-}
-
-
 uint64_t nsRegion::Area () const
 {
   uint64_t area = 0;
   nsRegionRectIterator iter(*this);
   const nsRect* r;
   while ((r = iter.Next()) != nullptr) {
     area += uint64_t(r->width)*r->height;
   }
   return area;
 }
 
-
-void nsRegion::MoveBy (nsPoint aPt)
-{
-  if (aPt.x || aPt.y)
-  {
-    RgnRect* pRect = mRectListHead.next;
-
-    while (pRect != &mRectListHead)
-    {
-      pRect->MoveBy (aPt.x, aPt.y);
-      pRect = pRect->next;
-    }
-
-    mBoundRect.MoveBy (aPt.x, aPt.y);
-  }
-}
-
 nsRegion& nsRegion::ScaleRoundOut (float aXScale, float aYScale)
 {
-  nsRegion region;
-  nsRegionRectIterator iter(*this);
-  for (;;) {
-    const nsRect* r = iter.Next();
-    if (!r)
-      break;
-    nsRect rect = *r;
+  int n;
+  pixman_box32_t *boxes = pixman_region32_rectangles(&mImpl, &n);
+  for (int i=0; i<n; i++) {
+    nsRect rect = BoxToRect(boxes[i]);
     rect.ScaleRoundOut(aXScale, aYScale);
-    region.Or(region, rect);
+    boxes[i] = RectToBox(rect);
   }
-  *this = region;
+
+  pixman_region32_t region;
+  // This will union all of the rectangles and runs in about O(n lg(n))
+  pixman_region32_init_rects(&region, boxes, n);
+
+  pixman_region32_fini(&mImpl);
+  mImpl = region;
   return *this;
 }
 
 nsRegion& nsRegion::ScaleInverseRoundOut (float aXScale, float aYScale)
 {
-  nsRegion region;
-  nsRegionRectIterator iter(*this);
-  for (;;) {
-    const nsRect* r = iter.Next();
-    if (!r)
-      break;
-    nsRect rect = *r;
+  int n;
+  pixman_box32_t *boxes = pixman_region32_rectangles(&mImpl, &n);
+  for (int i=0; i<n; i++) {
+    nsRect rect = BoxToRect(boxes[i]);
     rect.ScaleInverseRoundOut(aXScale, aYScale);
-    region.Or(region, rect);
+    boxes[i] = RectToBox(rect);
   }
-  *this = region;
+
+  pixman_region32_t region;
+  // This will union all of the rectangles and runs in about O(n lg(n))
+  pixman_region32_init_rects(&region, boxes, n);
+
+  pixman_region32_fini(&mImpl);
+  mImpl = region;
   return *this;
 }
 
 nsRegion nsRegion::ConvertAppUnitsRoundOut (int32_t aFromAPP, int32_t aToAPP) const
 {
   if (aFromAPP == aToAPP) {
     return *this;
   }
-  // Do it in a simplistic and slow way to avoid any weird behaviour with
-  // rounding causing rects to overlap. Should be fast enough for what we need.
-  nsRegion region;
-  nsRegionRectIterator iter(*this);
-  for (;;) {
-    const nsRect* r = iter.Next();
-    if (!r)
-      break;
-    nsRect rect = r->ConvertAppUnitsRoundOut(aFromAPP, aToAPP);
-    region.Or(region, rect);
+
+  nsRegion region = *this;
+  int n;
+  pixman_box32_t *boxes = pixman_region32_rectangles(&region.mImpl, &n);
+  for (int i=0; i<n; i++) {
+    nsRect rect = BoxToRect(boxes[i]);
+    rect = rect.ConvertAppUnitsRoundOut(aFromAPP, aToAPP);
+    boxes[i] = RectToBox(rect);
   }
+
+  pixman_region32_t pixmanRegion;
+  // This will union all of the rectangles and runs in about O(n lg(n))
+  pixman_region32_init_rects(&pixmanRegion, boxes, n);
+
+  pixman_region32_fini(&region.mImpl);
+  region.mImpl = pixmanRegion;
   return region;
 }
 
 nsRegion nsRegion::ConvertAppUnitsRoundIn (int32_t aFromAPP, int32_t aToAPP) const
 {
   if (aFromAPP == aToAPP) {
     return *this;
   }
-  // Do it in a simplistic and slow way to avoid any weird behaviour with
-  // rounding causing rects to overlap. Should be fast enough for what we need.
-  nsRegion region;
-  nsRegionRectIterator iter(*this);
-  for (;;) {
-    const nsRect* r = iter.Next();
-    if (!r)
-      break;
-    nsRect rect = r->ConvertAppUnitsRoundIn(aFromAPP, aToAPP);
-    region.Or(region, rect);
+
+  nsRegion region = *this;
+  int n;
+  pixman_box32_t *boxes = pixman_region32_rectangles(&region.mImpl, &n);
+  for (int i=0; i<n; i++) {
+    nsRect rect = BoxToRect(boxes[i]);
+    rect = rect.ConvertAppUnitsRoundIn(aFromAPP, aToAPP);
+    boxes[i] = RectToBox(rect);
   }
+
+  pixman_region32_t pixmanRegion;
+  // This will union all of the rectangles and runs in about O(n lg(n))
+  pixman_region32_init_rects(&pixmanRegion, boxes, n);
+
+  pixman_region32_fini(&region.mImpl);
+  region.mImpl = pixmanRegion;
   return region;
 }
 
 nsIntRegion nsRegion::ToPixels (nscoord aAppUnitsPerPixel, bool aOutsidePixels) const
 {
-  nsIntRegion result;
-  nsRegionRectIterator rgnIter(*this);
-  const nsRect* currentRect;
-  while ((currentRect = rgnIter.Next())) {
+  nsRegion region = *this;
+  int n;
+  pixman_box32_t *boxes = pixman_region32_rectangles(&region.mImpl, &n);
+  for (int i=0; i<n; i++) {
+    nsRect rect = BoxToRect(boxes[i]);
     nsIntRect deviceRect;
     if (aOutsidePixels)
-      deviceRect = currentRect->ToOutsidePixels(aAppUnitsPerPixel);
+      deviceRect = rect.ToOutsidePixels(aAppUnitsPerPixel);
     else
-      deviceRect = currentRect->ToNearestPixels(aAppUnitsPerPixel);
-    result.Or(result, deviceRect);
+      deviceRect = rect.ToNearestPixels(aAppUnitsPerPixel);
+
+    boxes[i] = RectToBox(deviceRect);
   }
-  return result;
+
+  nsIntRegion intRegion;
+  pixman_region32_fini(&intRegion.mImpl.mImpl);
+  // This will union all of the rectangles and runs in about O(n lg(n))
+  pixman_region32_init_rects(&intRegion.mImpl.mImpl, boxes, n);
+
+  return intRegion;
 }
 
 nsIntRegion nsRegion::ToOutsidePixels (nscoord aAppUnitsPerPixel) const
 {
   return ToPixels(aAppUnitsPerPixel, true);
 }
 
 nsIntRegion nsRegion::ToNearestPixels (nscoord aAppUnitsPerPixel) const
@@ -1441,59 +259,67 @@ nsIntRegion nsRegion::ScaleToInsidePixel
    *
    * If it is, then the contained edge can be moved (in scaled pixels) to ensure that no
    * gap exists.
    *
    * Since this could be potentially expensive - O(n^2), we only attempt this algorithm
    * for the first rect.
    */
 
-  nsIntRegion result;
-  RgnRect* pRect = mRectListHead.next;
-  RgnRect* first = pRect;
+  // make a copy of this region so that we can mutate it in place
+  nsRegion region = *this;
+  int n;
+  pixman_box32_t *boxes = pixman_region32_rectangles(&region.mImpl, &n);
 
-  nsIntRect firstDeviceRect;
-  if (pRect != &mRectListHead) {
-    firstDeviceRect =
-      pRect->ScaleToInsidePixels(aScaleX, aScaleY, aAppUnitsPerPixel);
-    pRect = pRect->next;
-  }
+  nsIntRegion intRegion;
+  if (n) {
+    nsRect first = BoxToRect(boxes[0]);
+    nsIntRect firstDeviceRect =
+      first.ScaleToInsidePixels(aScaleX, aScaleY, aAppUnitsPerPixel);
 
-  while (pRect != &mRectListHead)
-  {
-    nsIntRect deviceRect =
-      pRect->ScaleToInsidePixels(aScaleX, aScaleY, aAppUnitsPerPixel);
+    for (int i=1; i<n; i++) {
+      nsRect rect = nsRect(boxes[i].x1, boxes[i].y1,
+	  boxes[i].x2 - boxes[i].x1,
+	  boxes[i].y2 - boxes[i].y1);
+      nsIntRect deviceRect =
+	rect.ScaleToInsidePixels(aScaleX, aScaleY, aAppUnitsPerPixel);
 
-    if (pRect->y <= first->YMost()) {
-      if (pRect->XMost() == first->x && pRect->YMost() <= first->YMost()) {
-        // pRect is touching on the left edge of the first rect and contained within
-        // the length of its left edge
-        deviceRect.SetRightEdge(firstDeviceRect.x);
-      } else if (pRect->x == first->XMost() && pRect->YMost() <= first->YMost()) {
-        // pRect is touching on the right edge of the first rect and contained within
-        // the length of its right edge
-        deviceRect.SetLeftEdge(firstDeviceRect.XMost());
-      } else if (pRect->y == first->YMost()) {
-        // The bottom of the first rect is on the same line as the top of pRect, but 
-        // they aren't necessarily contained.
-        if (pRect->x <= first->x && pRect->XMost() >= first->XMost()) {
-          // The top of pRect contains the bottom of the first rect
-          firstDeviceRect.SetBottomEdge(deviceRect.y);
-        } else if (pRect->x >= first->x && pRect->XMost() <= first->XMost()) {
-          // The bottom of the first contains the top of pRect
-          deviceRect.SetTopEdge(firstDeviceRect.YMost());
-        }
+      if (rect.y <= first.YMost()) {
+	if (rect.XMost() == first.x && rect.YMost() <= first.YMost()) {
+	  // rect is touching on the left edge of the first rect and contained within
+	  // the length of its left edge
+	  deviceRect.SetRightEdge(firstDeviceRect.x);
+	} else if (rect.x == first.XMost() && rect.YMost() <= first.YMost()) {
+	  // rect is touching on the right edge of the first rect and contained within
+	  // the length of its right edge
+	  deviceRect.SetLeftEdge(firstDeviceRect.XMost());
+	} else if (rect.y == first.YMost()) {
+	  // The bottom of the first rect is on the same line as the top of rect, but
+	  // they aren't necessarily contained.
+	  if (rect.x <= first.x && rect.XMost() >= first.XMost()) {
+	    // The top of rect contains the bottom of the first rect
+	    firstDeviceRect.SetBottomEdge(deviceRect.y);
+	  } else if (rect.x >= first.x && rect.XMost() <= first.XMost()) {
+	    // The bottom of the first contains the top of rect
+	    deviceRect.SetTopEdge(firstDeviceRect.YMost());
+	  }
+	}
       }
+
+      boxes[i] = RectToBox(deviceRect);
     }
-    pRect = pRect->next;
-    result.Or(result, deviceRect);
+
+    boxes[0] = RectToBox(firstDeviceRect);
+
+    pixman_region32_fini(&intRegion.mImpl.mImpl);
+    // This will union all of the rectangles and runs in about O(n lg(n))
+    pixman_region32_init_rects(&intRegion.mImpl.mImpl, boxes, n);
   }
+  return intRegion;
 
-  result.Or(result, firstDeviceRect);
-  return result;
 }
 
 // A cell's "value" is a pair consisting of
 // a) the area of the subrectangle it corresponds to, if it's in
 // aContainingRect and in the region, 0 otherwise
 // b) the area of the subrectangle it corresponds to, if it's in the region,
 // 0 otherwise
 // Addition, subtraction and identity are defined on these values in the
@@ -1682,18 +508,18 @@ namespace {
 
     return max;
   }
 }
 
 nsRect nsRegion::GetLargestRectangle (const nsRect& aContainingRect) const {
   nsRect bestRect;
 
-  if (mRectCount <= 1) {
-    bestRect = mBoundRect;
+  if (GetNumRects() <= 1) {
+    bestRect = GetBounds();
     return bestRect;
   }
 
   AxisPartition xaxis, yaxis;
 
   // Step 1: Calculate the grid lines
   nsRegionRectIterator iter(*this);
   const nsRect *currentRect;
@@ -1789,120 +615,35 @@ nsRect nsRegion::GetLargestRectangle (co
                     yaxis.StopAt(bestRectIndices.top));
     bestRect.SizeTo(xaxis.StopAt(bestRectIndices.right) - bestRect.x,
                     yaxis.StopAt(bestRectIndices.bottom) - bestRect.y);
   }
 
   return bestRect;
 }
 
-void nsRegion::SimplifyOutward (uint32_t aMaxRects)
-{
-  NS_ASSERTION(aMaxRects >= 1, "Invalid max rect count");
-  
-  if (mRectCount <= aMaxRects)
-    return;
+nsCString
+nsRegion::ToString() const {
+    nsCString result;
+    result.AppendLiteral("[");
 
-  // Try combining rects in horizontal bands into a single rect
-  RgnRect* pRect = mRectListHead.next;
-  while (pRect != &mRectListHead)
-  {
-    // Combine with the following rectangle if they have the same YMost
-    // or if they overlap vertically. This ensures that all overlapping
-    // rectangles are merged, preserving the invariant that rectangles
-    // don't overlap.
-    // The goal here is to try to keep groups of rectangles that are vertically
-    // discontiguous as separate rectangles in the final region. This is
-    // simple and fast to implement and page contents tend to vary more
-    // vertically than horizontally (which is why our rectangles are stored
-    // sorted by y-coordinate, too).
-    while (pRect->next != &mRectListHead &&
-           pRect->YMost () >= pRect->next->y)
-    {
-      pRect->UnionRect(*pRect, *pRect->next);
-      delete Remove (pRect->next);
+    int n;
+    pixman_box32_t *boxes = pixman_region32_rectangles(const_cast<pixman_region32_t*>(&mImpl), &n);
+    for (int i=0; i<n; i++) {
+        if (i != 0) {
+            result.AppendLiteral("; ");
+        }
+        result.Append(nsPrintfCString("%d,%d,%d,%d", boxes[i].x1, boxes[i].y1, boxes[i].x2, boxes[i].y2));
+
     }
-
-    pRect = pRect->next;
-  }
-
-  if (mRectCount <= aMaxRects)
-    return;
+    result.AppendLiteral("]");
 
-  *this = GetBounds();
-}
-
-void nsRegion::SimplifyInward (uint32_t aMaxRects)
-{
-  NS_ASSERTION(aMaxRects >= 1, "Invalid max rect count");
-
-  if (mRectCount <= aMaxRects)
-    return;
-
-  SetEmpty();
+    return result;
 }
 
-void nsRegion::SimpleSubtract (const nsRect& aRect)
-{
-  if (aRect.IsEmpty())
-    return;
-
-  // protect against aRect being one of our own rectangles
-  nsRect param = aRect;
-  RgnRect* r = mRectListHead.next;
-  while (r != &mRectListHead)
-  {
-    RgnRect* next = r->next;
-    if (param.Contains(*r)) {
-      delete Remove(r);
-    }
-    r = next;
-  }
-  
-  Optimize();
-}
-
-void nsRegion::SimpleSubtract (const nsRegion& aRegion)
-{
-  if (aRegion.IsEmpty())
-    return;
-
-  if (&aRegion == this) {
-    SetEmpty();
-    return;
-  }
-
-  const RgnRect* r = aRegion.mRectListHead.next;
-  while (r != &aRegion.mRectListHead)
-  {
-    SimpleSubtract(*r);
-    r = r->next;
-  }
-
-  Optimize();
-}
-
-nsCString
-nsRegion::ToString() const
-{
-  nsCString result;
-  result.AppendLiteral("[");
-  const RgnRect* r = mRectListHead.next;
-  while (r != &mRectListHead)
-  {
-    if (r != mRectListHead.next) {
-      result.AppendLiteral("; ");
-    }
-    result.Append(nsPrintfCString("%d,%d,%d,%d", r->x, r->y, r->XMost(), r->YMost()));
-    r = r->next;
-  }
-  result.AppendLiteral("]");
-
-  return result;
-}
 
 nsRegion nsIntRegion::ToAppUnits (nscoord aAppUnitsPerPixel) const
 {
   nsRegion result;
   nsIntRegionRectIterator rgnIter(*this);
   const nsIntRect* currentRect;
   while ((currentRect = rgnIter.Next())) {
     nsRect appRect = currentRect->ToAppUnits(aAppUnitsPerPixel);
--- a/gfx/src/nsRegion.h
+++ b/gfx/src/nsRegion.h
@@ -14,151 +14,175 @@
 #include "nsError.h"                    // for nsresult
 #include "nsPoint.h"                    // for nsIntPoint, nsPoint
 #include "nsRect.h"                     // for nsIntRect, nsRect
 #include "nsString.h"               // for nsCString
 #include "xpcom-config.h"               // for CPP_THROW_NEW
 
 class nsIntRegion;
 
-/**
- * Implementation of regions.
- * A region is represented as circular double-linked list of nsRegion::RgnRect structures.
- * Rectangles in this list do not overlap and are sorted by (y, x) coordinates.
- *
- * nsRegions use nscoord coordinates and nsRects.
- */
-class NS_GFX nsRegion
-{
-  friend class nsRegionRectIterator;
-  friend class RgnRectMemoryAllocator;
-
-
-// Special version of nsRect structure for speed optimizations in nsRegion code.
-// Most important functions could be made inline and be sure that passed rectangles
-// will always be non-empty.
-// 
-// Do not add any new member variables to this structure! 
-// Otherwise it will break casts from nsRect to nsRectFast, which expect data parts to be identical.
-  struct nsRectFast : public nsRect
-  {
-    nsRectFast () {}      // No need to call parent constructor to set default values
-    nsRectFast (int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeight) : nsRect (aX, aY, aWidth, aHeight) {}
-    nsRectFast (const nsRect& aRect) : nsRect (aRect) {}
+#include "pixman.h"
 
-    // Override nsRect methods to make them inline. Do not check for emptiness.
-    inline bool Contains (const nsRect& aRect) const;
-    inline bool Intersects (const nsRect& aRect) const;
-    inline bool IntersectRect (const nsRect& aRect1, const nsRect& aRect2);
-    inline void UnionRect (const nsRect& aRect1, const nsRect& aRect2);
-  };
-
-
-  struct RgnRect : public nsRectFast
-  {
-    RgnRect* prev;
-    RgnRect* next;
+/* For information on the internal representation look at pixman-region.c
+ *
+ * This replaces an older homebrew implementation of nsRegion. The
+ * representation used here may use more rectangles than nsRegion however, the
+ * representation is canonical.  This means that there's no need for an
+ * Optimize() method because for a paticular region there is only one
+ * representation. This means that nsIntRegion will have more predictable
+ * performance characteristics than the old nsRegion and should not become
+ * degenerate.
+ *
+ * The pixman region code originates from X11 which has spread to a variety of
+ * projects including Qt, Gtk, Wine. It should perform reasonably well.
+ */
 
-    RgnRect () {}                           // No need to call parent constructor to set default values
-    RgnRect (int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeight) : nsRectFast (aX, aY, aWidth, aHeight) {}
-    RgnRect (const nsRectFast& aRect) : nsRectFast (aRect) {}
-
-    void* operator new (size_t) CPP_THROW_NEW;
-    void  operator delete (void* aRect, size_t);
+class nsRegionRectIterator;
 
-    RgnRect& operator = (const RgnRect& aRect)      // Do not overwrite prev/next pointers
-    {
-      x = aRect.x;
-      y = aRect.y;
-      width = aRect.width;
-      height = aRect.height;
-      return *this;
-    }
-  };
+class nsRegion
+{
 
+  friend class nsRegionRectIterator;
 
 public:
-  nsRegion () { Init (); }
-  nsRegion (const nsRect& aRect) { Init (); Copy (aRect); }
-  nsRegion (const nsRegion& aRegion) { Init (); Copy (aRegion); }
- ~nsRegion () { SetToElements (0); }
+  nsRegion () { pixman_region32_init(&mImpl); }
+  nsRegion (const nsRect& aRect) { pixman_region32_init_rect(&mImpl,
+                                                                    aRect.x,
+                                                                    aRect.y,
+                                                                    aRect.width,
+                                                                    aRect.height); }
+  nsRegion (const nsRegion& aRegion) { pixman_region32_init(&mImpl); pixman_region32_copy(&mImpl,aRegion.Impl()); }
+ ~nsRegion () { pixman_region32_fini(&mImpl); }
   nsRegion& operator = (const nsRect& aRect) { Copy (aRect); return *this; }
   nsRegion& operator = (const nsRegion& aRegion) { Copy (aRegion); return *this; }
+  bool operator==(const nsRegion& aRgn) const
+  {
+    return IsEqual(aRgn);
+  }
 
+  static
+  nsresult InitStatic()
+  {
+    return NS_OK;
+  }
+
+  static
+  void ShutdownStatic() {}
 
-  nsRegion& And  (const nsRegion& aRgn1,   const nsRegion& aRgn2);
-  nsRegion& And  (const nsRegion& aRegion, const nsRect& aRect);
-  nsRegion& And  (const nsRect& aRect, const nsRegion& aRegion)
+  nsRegion& And(const nsRegion& aRgn1,   const nsRegion& aRgn2)
+  {
+    pixman_region32_intersect(&mImpl, aRgn1.Impl(), aRgn2.Impl());
+    return *this;
+  }
+  nsRegion& And(const nsRect& aRect, const nsRegion& aRegion)
   {
-    return  And  (aRegion, aRect);
+    return And(aRegion, aRect);
   }
-  nsRegion& And  (const nsRect& aRect1, const nsRect& aRect2)
+  nsRegion& And(const nsRegion& aRegion, const nsRect& aRect)
+  {
+    pixman_region32_intersect_rect(&mImpl, aRegion.Impl(), aRect.x, aRect.y, aRect.width, aRect.height);
+    return *this;
+  }
+  nsRegion& And(const nsRect& aRect1, const nsRect& aRect2)
   {
     nsRect TmpRect;
 
-    TmpRect.IntersectRect (aRect1, aRect2);
-    return Copy (TmpRect);
+    TmpRect.IntersectRect(aRect1, aRect2);
+    return Copy(TmpRect);
   }
 
-  nsRegion& Or   (const nsRegion& aRgn1,   const nsRegion& aRgn2);
-  nsRegion& Or   (const nsRegion& aRegion, const nsRect& aRect);
-  nsRegion& Or   (const nsRect& aRect, const nsRegion& aRegion)
+  nsRegion& Or(const nsRegion& aRgn1, const nsRegion& aRgn2)
+  {
+    pixman_region32_union(&mImpl, aRgn1.Impl(), aRgn2.Impl());
+    return *this;
+  }
+  nsRegion& Or(const nsRegion& aRegion, const nsRect& aRect)
   {
-    return  Or   (aRegion, aRect);
+    pixman_region32_union_rect(&mImpl, aRegion.Impl(), aRect.x, aRect.y, aRect.width, aRect.height);
+    return *this;
   }
-  nsRegion& Or   (const nsRect& aRect1, const nsRect& aRect2)
+  nsRegion& Or(const nsRect& aRect, const nsRegion& aRegion)
+  {
+    return  Or(aRegion, aRect);
+  }
+  nsRegion& Or(const nsRect& aRect1, const nsRect& aRect2)
   {
     Copy (aRect1);
     return Or (*this, aRect2);
   }
 
-  nsRegion& Xor  (const nsRegion& aRgn1,   const nsRegion& aRgn2);
-  nsRegion& Xor  (const nsRegion& aRegion, const nsRect& aRect);
-  nsRegion& Xor  (const nsRect& aRect, const nsRegion& aRegion)
+  nsRegion& Xor(const nsRegion& aRgn1,   const nsRegion& aRgn2)
   {
-    return  Xor  (aRegion, aRect);
+    // this could be implemented better if pixman had direct
+    // support for xoring regions.
+    nsRegion p;
+    p.Sub(aRgn1, aRgn2);
+    nsRegion q;
+    q.Sub(aRgn2, aRgn1);
+    return Or(p, q);
   }
-  nsRegion& Xor  (const nsRect& aRect1, const nsRect& aRect2)
+  nsRegion& Xor(const nsRegion& aRegion, const nsRect& aRect)
+  {
+    return Xor(aRegion, nsRegion(aRect));
+  }
+  nsRegion& Xor(const nsRect& aRect, const nsRegion& aRegion)
   {
-    Copy (aRect1);
-    return Xor (*this, aRect2);
+    return Xor(nsRegion(aRect), aRegion);
+  }
+  nsRegion& Xor(const nsRect& aRect1, const nsRect& aRect2)
+  {
+    return Xor(nsRegion(aRect1), nsRegion(aRect2));
   }
 
-  nsRegion& Sub  (const nsRegion& aRgn1,   const nsRegion& aRgn2);
-  nsRegion& Sub  (const nsRegion& aRegion, const nsRect& aRect);
-  nsRegion& Sub  (const nsRect& aRect, const nsRegion& aRegion)
+  nsRegion ToAppUnits (nscoord aAppUnitsPerPixel) const;
+  nsRegion& Sub(const nsRegion& aRgn1, const nsRegion& aRgn2)
+  {
+    pixman_region32_subtract(&mImpl, aRgn1.Impl(), aRgn2.Impl());
+    return *this;
+  }
+  nsRegion& Sub(const nsRegion& aRegion, const nsRect& aRect)
   {
-    return Sub (nsRegion (aRect), aRegion);
+    return Sub(aRegion, nsRegion(aRect));
   }
-  nsRegion& Sub  (const nsRect& aRect1, const nsRect& aRect2)
+  nsRegion& Sub(const nsRect& aRect, const nsRegion& aRegion)
   {
-    Copy (aRect1);
-    return Sub (*this, aRect2);
+    return Sub(nsRegion(aRect), aRegion);
+  }
+  nsRegion& Sub(const nsRect& aRect1, const nsRect& aRect2)
+  {
+    Copy(aRect1);
+    return Sub(*this, aRect2);
   }
 
-  bool Contains (const nsRect& aRect) const;
+  bool Contains (const nsRect& aRect) const
+  {
+    pixman_box32_t box = RectToBox(aRect);
+    return pixman_region32_contains_rectangle(Impl(), &box) == PIXMAN_REGION_IN;
+  }
   bool Contains (const nsRegion& aRgn) const;
   bool Intersects (const nsRect& aRect) const;
 
   void MoveBy (int32_t aXOffset, int32_t aYOffset)
   {
     MoveBy (nsPoint (aXOffset, aYOffset));
   }
-  void MoveBy (nsPoint aPt);
+  void MoveBy (nsPoint aPt) { pixman_region32_translate(&mImpl, aPt.x, aPt.y); }
   void SetEmpty ()
   {
-    SetToElements (0);
-    mBoundRect.SetRect (0, 0, 0, 0);
+    pixman_region32_clear(&mImpl);
   }
 
-  bool IsEmpty () const { return mRectCount == 0; }
-  bool IsComplex () const { return mRectCount > 1; }
-  bool IsEqual (const nsRegion& aRegion) const;
-  uint32_t GetNumRects () const { return mRectCount; }
-  const nsRect& GetBounds () const { return mBoundRect; }
+  bool IsEmpty () const { return !pixman_region32_not_empty(Impl()); }
+  bool IsComplex () const { return GetNumRects() > 1; }
+  bool IsEqual (const nsRegion& aRegion) const
+  {
+    return pixman_region32_equal(Impl(), aRegion.Impl());
+  }
+  uint32_t GetNumRects () const { return pixman_region32_n_rects(Impl()); }
+  const nsRect GetBounds () const { return BoxToRect(mImpl.extents); }
   uint64_t Area () const;
   // Converts this region from aFromAPP, an appunits per pixel ratio, to
   // aToAPP. This applies nsRect::ConvertAppUnitsRoundOut/In to each rect of
   // the region.
   nsRegion ConvertAppUnitsRoundOut (int32_t aFromAPP, int32_t aToAPP) const;
   nsRegion ConvertAppUnitsRoundIn (int32_t aFromAPP, int32_t aToAPP) const;
   nsRegion& ScaleRoundOut(float aXScale, float aYScale);
   nsRegion& ScaleInverseRoundOut(float aXScale, float aYScale);
@@ -184,114 +208,111 @@ public:
    */
   void SimplifyOutward (uint32_t aMaxRects);
   /**
    * Make sure the region has at most aMaxRects by removing area from
    * it if necessary. The simplified region will be a subset of the
    * original region.
    */
   void SimplifyInward (uint32_t aMaxRects);
-  /**
-   * Efficiently try to remove a rectangle from this region. The actual
-   * area removed could be some sub-area contained by the rectangle
-   * (even possibly nothing at all).
-   * 
-   * We remove all rectangles that are contained by aRect.
-   */
-  void SimpleSubtract (const nsRect& aRect);
-  /**
-   * Efficiently try to remove a region from this region. The actual
-   * area removed could be some sub-area contained by aRegion
-   * (even possibly nothing at all).
-   * 
-   * We remove all rectangles of this region that are contained by
-   * a rectangle of aRegion.
-   */
-  void SimpleSubtract (const nsRegion& aRegion);
 
   nsCString ToString() const;
+private:
+  pixman_region32_t mImpl;
 
-  /**
-   * Initialize any static data associated with nsRegion.
-   */
-  static nsresult InitStatic();
+  nsIntRegion ToPixels(nscoord aAppUnitsPerPixel, bool aOutsidePixels) const;
 
-  /**
-   * Deinitialize static data.
-   */
-  static void ShutdownStatic();
+  nsRegion& Copy (const nsRegion& aRegion)
+  {
+    pixman_region32_copy(&mImpl, aRegion.Impl());
+    return *this;
+  }
 
-private:
-  uint32_t    mRectCount;
-  RgnRect*    mCurRect;
-  RgnRect     mRectListHead;
-  nsRectFast  mBoundRect;
+  nsRegion& Copy (const nsRect& aRect)
+  {
+    pixman_box32_t box = RectToBox(aRect);
+    pixman_region32_reset(&mImpl, &box);
+    return *this;
+  }
 
-  void Init ();
-  nsRegion& Copy (const nsRegion& aRegion);
-  nsRegion& Copy (const nsRect& aRect);
-  void InsertBefore (RgnRect* aNewRect, RgnRect* aRelativeRect);
-  void InsertAfter (RgnRect* aNewRect, RgnRect* aRelativeRect);
-  void SetToElements (uint32_t aCount);
-  RgnRect* Remove (RgnRect* aRect);
-  void InsertInPlace (RgnRect* aRect, bool aOptimizeOnFly = false);
-  inline void SaveLinkChain ();
-  inline void RestoreLinkChain ();
-  void Optimize ();
-  void SubRegion (const nsRegion& aRegion, nsRegion& aResult) const;
-  void SubRect (const nsRectFast& aRect, nsRegion& aResult, nsRegion& aCompleted) const;
-  void SubRect (const nsRectFast& aRect, nsRegion& aResult) const
-  {    SubRect (aRect, aResult, aResult);  }
-  void Merge (const nsRegion& aRgn1, const nsRegion& aRgn2);
-  void MoveInto (nsRegion& aDestRegion, const RgnRect* aStartRect);
-  void MoveInto (nsRegion& aDestRegion)
-  {    MoveInto (aDestRegion, mRectListHead.next);  }
-  nsIntRegion ToPixels(nscoord aAppUnitsPerPixel, bool aOutsidePixels) const;
+  static inline pixman_box32_t RectToBox(const nsRect &aRect)
+  {
+    pixman_box32_t box = { aRect.x, aRect.y, aRect.XMost(), aRect.YMost() };
+    return box;
+  }
+
+  static inline pixman_box32_t RectToBox(const nsIntRect &aRect)
+  {
+    pixman_box32_t box = { aRect.x, aRect.y, aRect.XMost(), aRect.YMost() };
+    return box;
+  }
+
+
+  static inline nsRect BoxToRect(const pixman_box32_t &aBox)
+  {
+    return nsRect(aBox.x1, aBox.y1,
+                  aBox.x2 - aBox.x1,
+                  aBox.y2 - aBox.y1);
+  }
+
+  pixman_region32_t* Impl() const
+  {
+    return const_cast<pixman_region32_t*>(&mImpl);
+  }
+
 };
 
 
-
-// Allow read-only access to region rectangles by iterating the list
-
 class NS_GFX nsRegionRectIterator
 {
   const nsRegion*  mRegion;
-  const nsRegion::RgnRect* mCurPtr;
+  int i;
+  int n;
+  nsRect rect;
+  pixman_box32_t *boxes;
 
 public:
   nsRegionRectIterator (const nsRegion& aRegion)
   {
     mRegion = &aRegion;
-    mCurPtr = &aRegion.mRectListHead;
+    i = 0;
+    boxes = pixman_region32_rectangles(aRegion.Impl(), &n);
   }
 
   const nsRect* Next ()
   {
-    mCurPtr = mCurPtr->next;
-    return (mCurPtr != &mRegion->mRectListHead) ? mCurPtr : nullptr;
+    if (i == n)
+      return nullptr;
+    rect = nsRegion::BoxToRect(boxes[i]);
+    i++;
+    return &rect;
   }
 
   const nsRect* Prev ()
   {
-    mCurPtr = mCurPtr->prev;
-    return (mCurPtr != &mRegion->mRectListHead) ? mCurPtr : nullptr;
+    if (i == -1)
+      return nullptr;
+    rect = nsRegion::BoxToRect(boxes[i]);
+    i--;
+    return &rect;
   }
 
   void Reset ()
   {
-    mCurPtr = &mRegion->mRectListHead;
+    i = 0;
   }
 };
 
 /**
  * nsIntRegions use int32_t coordinates and nsIntRects.
  */
 class NS_GFX nsIntRegion
 {
   friend class nsIntRegionRectIterator;
+  friend class nsRegion;
 
 public:
   nsIntRegion () {}
   nsIntRegion (const nsIntRect& aRect) : mImpl (ToRect(aRect)) {}
   nsIntRegion (const nsIntRegion& aRegion) : mImpl (aRegion.mImpl) {}
   nsIntRegion& operator = (const nsIntRect& aRect) { mImpl = ToRect (aRect); return *this; }
   nsIntRegion& operator = (const nsIntRegion& aRegion) { mImpl = aRegion.mImpl; return *this; }
 
@@ -444,39 +465,16 @@ public:
    * Make sure the region has at most aMaxRects by removing area from
    * it if necessary. The simplified region will be a subset of the
    * original region.
    */
   void SimplifyInward (uint32_t aMaxRects)
   {
     mImpl.SimplifyInward (aMaxRects);
   }
-  /**
-   * Efficiently try to remove a rectangle from this region. The actual
-   * area removed could be some sub-area contained by the rectangle
-   * (even possibly nothing at all).
-   * 
-   * We remove all rectangles that are contained by aRect.
-   */
-  void SimpleSubtract (const nsIntRect& aRect)
-  {
-    mImpl.SimpleSubtract (ToRect (aRect));
-  }
-  /**
-   * Efficiently try to remove a region from this region. The actual
-   * area removed could be some sub-area contained by aRegion
-   * (even possibly nothing at all).
-   * 
-   * We remove all rectangles of this region that are contained by
-   * a rectangle of aRegion.
-   */
-  void SimpleSubtract (const nsIntRegion& aRegion)
-  {
-    mImpl.SimpleSubtract (aRegion.mImpl);
-  }
 
   nsCString ToString() const { return mImpl.ToString(); }
 
 private:
   nsRegion mImpl;
 
   static nsRect ToRect(const nsIntRect& aRect)
   {
@@ -514,10 +512,9 @@ public:
     return &mTmp;
   }
 
   void Reset ()
   {
     mImpl.Reset ();
   }
 };
-
 #endif
--- a/gfx/tests/gtest/TestRegion.cpp
+++ b/gfx/tests/gtest/TestRegion.cpp
@@ -119,8 +119,55 @@ TEST(Gfx, RegionTwoRectTest) {
 TEST(Gfx, RegionContainsSpecifiedRect) {
   TestLargestRegion::TestContainsSpecifiedRect();
 }
 
 TEST(Gfx, RegionTestContainsSpecifiedOverflowingRect) {
   TestLargestRegion::TestContainsSpecifiedOverflowingRect();
 }
 
+TEST(Gfx, RegionScaleToInside) {
+  { // no rectangles
+    nsRegion r;
+
+    nsIntRegion scaled = r.ScaleToInsidePixels(1, 1, 60);
+    nsIntRegion result;
+
+    EXPECT_TRUE(result.IsEqual(scaled)) <<
+      "scaled result incorrect";
+  }
+
+  { // one rectangle
+    nsRegion r(nsRect(0,44760,19096,264));
+
+    nsIntRegion scaled = r.ScaleToInsidePixels(1, 1, 60);
+    nsIntRegion result(nsIntRect(0,746,318,4));
+
+    EXPECT_TRUE(result.IsEqual(scaled)) <<
+      "scaled result incorrect";
+  }
+
+
+  { // the first rectangle gets adjusted
+    nsRegion r(nsRect(0,44760,19096,264));
+    r.Or(r, nsRect(0,45024,19360,1056));
+
+    nsIntRegion scaled = r.ScaleToInsidePixels(1, 1, 60);
+    nsIntRegion result(nsIntRect(0,746,318,5));
+    result.Or(result, nsIntRect(0,751,322,17));
+
+    EXPECT_TRUE(result.IsEqual(scaled)) <<
+      "scaled result incorrect";
+  }
+
+  { // the second rectangle gets adjusted
+    nsRegion r(nsRect(0,44760,19360,264));
+    r.Or(r, nsRect(0,45024,19096,1056));
+
+    nsIntRegion scaled = r.ScaleToInsidePixels(1, 1, 60);
+    nsIntRegion result(nsIntRect(0,746,322,4));
+    result.Or(result, nsIntRect(0,750,318,18));
+
+    EXPECT_TRUE(result.IsEqual(scaled)) <<
+      "scaled result incorrect";
+  }
+
+}
--- a/gfx/thebes/gfxFontConstants.h
+++ b/gfx/thebes/gfxFontConstants.h
@@ -114,28 +114,30 @@ enum {
     NS_FONT_VARIANT_EAST_ASIAN_SIMPLIFIED | \
     NS_FONT_VARIANT_EAST_ASIAN_TRADITIONAL )
 
 #define NS_FONT_VARIANT_EAST_ASIAN_WIDTH_MASK ( \
     NS_FONT_VARIANT_EAST_ASIAN_FULL_WIDTH | \
     NS_FONT_VARIANT_EAST_ASIAN_PROP_WIDTH )
 
 enum {
+    eFeatureLigatures_none,
     eFeatureLigatures_common,
     eFeatureLigatures_no_common,
     eFeatureLigatures_discretionary,
     eFeatureLigatures_no_discretionary,
     eFeatureLigatures_historical,
     eFeatureLigatures_no_historical,
     eFeatureLigatures_contextual,
     eFeatureLigatures_no_contextual,
 
     eFeatureLigatures_numFeatures
 };
 
+#define NS_FONT_VARIANT_LIGATURES_NONE              (1 << eFeatureLigatures_none)
 #define NS_FONT_VARIANT_LIGATURES_COMMON            (1 << eFeatureLigatures_common)
 #define NS_FONT_VARIANT_LIGATURES_NO_COMMON         (1 << eFeatureLigatures_no_common)
 #define NS_FONT_VARIANT_LIGATURES_DISCRETIONARY     (1 << eFeatureLigatures_discretionary)
 #define NS_FONT_VARIANT_LIGATURES_NO_DISCRETIONARY  (1 << eFeatureLigatures_no_discretionary)
 #define NS_FONT_VARIANT_LIGATURES_HISTORICAL        (1 << eFeatureLigatures_historical)
 #define NS_FONT_VARIANT_LIGATURES_NO_HISTORICAL     (1 << eFeatureLigatures_no_historical)
 #define NS_FONT_VARIANT_LIGATURES_CONTEXTUAL        (1 << eFeatureLigatures_contextual)
 #define NS_FONT_VARIANT_LIGATURES_NO_CONTEXTUAL     (1 << eFeatureLigatures_no_contextual)
--- a/image/decoders/moz.build
+++ b/image/decoders/moz.build
@@ -18,17 +18,17 @@ if CONFIG['OS_ARCH'] == 'WINNT':
 elif CONFIG['OS_ARCH'] == 'OS2':
     DIRS += ['icon/os2', 'icon']
 
 if toolkit == 'cocoa':
     DIRS += ['icon/mac', 'icon']
 elif toolkit == 'android':
     DIRS += ['icon/android', 'icon']
 
-SOURCES += [
+UNIFIED_SOURCES += [
     'EXIF.cpp',
     'nsBMPDecoder.cpp',
     'nsGIFDecoder2.cpp',
     'nsICODecoder.cpp',
     'nsIconDecoder.cpp',
     'nsJPEGDecoder.cpp',
     'nsPNGDecoder.cpp',
 ]
--- a/ipc/chromium/moz.build
+++ b/ipc/chromium/moz.build
@@ -30,17 +30,17 @@ else:
         os_netbsd = 1
         os_bsd = 1
     elif CONFIG['OS_ARCH'] == 'OpenBSD':
         os_openbsd = 1
         os_bsd = 1
     else:
         os_linux = 1
 
-SOURCES += [
+UNIFIED_SOURCES += [
     'src/base/at_exit.cc',
     'src/base/base_paths.cc',
     'src/base/base_switches.cc',
     'src/base/command_line.cc',
     'src/base/debug_util.cc',
     'src/base/file_path.cc',
     'src/base/file_util.cc',
     'src/base/histogram.cc',
@@ -174,17 +174,17 @@ if os_posix:
         'src/chrome/common/process_watcher_posix_sigchld.cc',
     ]
     if CONFIG['OS_TARGET'] == 'Android':
         SOURCES += [
             'src/base/message_pump_android.cc',
         ]
 
 if os_macosx:
-    SOURCES += [
+    UNIFIED_SOURCES += [
         'src/base/debug_util_mac.cc',
         'src/base/hmac_mac.cc',
         'src/base/idle_timer.cc',
         'src/base/sys_info_mac.cc',
         'src/base/time_mac.cc',
         'src/chrome/common/mach_message_source_mac.cc',
         'src/chrome/common/transport_dib_mac.cc',
     ]
@@ -199,17 +199,17 @@ if os_macosx:
         'src/base/process_util_mac.mm',
         'src/base/scoped_nsautorelease_pool.mm',
         'src/base/sys_string_conversions_mac.mm',
         'src/base/worker_pool_mac.mm',
         'src/chrome/common/chrome_paths_mac.mm',
         'src/chrome/common/mach_ipc_mac.mm',
     ]
     if not CONFIG['MOZ_NATIVE_LIBEVENT']:
-        SOURCES += [
+        UNIFIED_SOURCES += [
             'src/third_party/libevent/kqueue.c',
         ]
 
 if os_linux:
     SOURCES += [
         'src/base/atomicops_internals_x86_gcc.cc',
         'src/base/base_paths_linux.cc',
         'src/base/file_version_info_linux.cc',
--- a/ipc/testshell/XPCShellEnvironment.cpp
+++ b/ipc/testshell/XPCShellEnvironment.cpp
@@ -368,19 +368,20 @@ XPCShellEnvironment::ProcessFile(JSConte
                 break;
             }
             bufp += strlen(bufp);
             lineno++;
         } while (!JS_BufferIsCompilableUnit(cx, obj, buffer, strlen(buffer)));
 
         /* Clear any pending exception from previous failed compiles.  */
         JS_ClearPendingException(cx);
-        script =
-            JS_CompileScriptForPrincipals(cx, obj, env->GetPrincipal(), buffer,
-                                          strlen(buffer), "typein", startline);
+        JS::CompileOptions options(cx);
+        options.setFileAndLine("typein", startline)
+               .setPrincipals(env->GetPrincipal());
+        script = JS_CompileScript(cx, obj, buffer, strlen(buffer), options);
         if (script) {
             JSErrorReporter older;
 
             ok = JS_ExecuteScript(cx, obj, script, result.address());
             if (ok && result != JSVAL_VOID) {
                 /* Suppress error reports from JS::ToString(). */
                 older = JS_SetErrorReporter(cx, nullptr);
                 str = JS::ToString(cx, result);
@@ -578,20 +579,21 @@ XPCShellEnvironment::Init()
 bool
 XPCShellEnvironment::EvaluateString(const nsString& aString,
                                     nsString* aResult)
 {
   AutoSafeJSContext cx;
   JS::Rooted<JSObject*> global(cx, GetGlobalObject());
   JSAutoCompartment ac(cx, global);
 
-  JSScript* script =
-      JS_CompileUCScriptForPrincipals(cx, global, GetPrincipal(),
-                                      aString.get(), aString.Length(),
-                                      "typein", 0);
+  JS::CompileOptions options(cx);
+  options.setFileAndLine("typein", 0)
+         .setPrincipals(GetPrincipal());
+  JSScript* script = JS_CompileUCScript(cx, global, aString.get(),
+                                        aString.Length(), options);
   if (!script) {
      return false;
   }
 
   if (aResult) {
       aResult->Truncate();
   }
 
--- a/js/jsd/jsd_xpc.cpp
+++ b/js/jsd/jsd_xpc.cpp
@@ -1004,18 +1004,20 @@ jsdScript::CreatePPLineMap()
         }
 
         JS::Anchor<JSString *> kungFuDeathGrip(jsstr);
         static const char *const argnames[] = {
             "arg1", "arg2", "arg3", "arg4",
             "arg5", "arg6", "arg7", "arg8",
             "arg9", "arg10", "arg11", "arg12"
         };
+        JS::CompileOptions options(cx);
+        options.setFileAndLine("x-jsd:ppbuffer?type=function", 3);
         fun = JS_CompileUCFunction (cx, obj, "ppfun", nargs, argnames, chars,
-                                    length, "x-jsd:ppbuffer?type=function", 3);
+                                    length, options);
         if (!fun || !(script = JS_GetFunctionScript(cx, fun)))
             return nullptr;
         baseLine = 3;
     } else {
         script = JSD_GetJSScript(mCx, mScript);
         JSString *jsstr;
 
         {
@@ -1025,17 +1027,19 @@ jsdScript::CreatePPLineMap()
             if (!jsstr)
                 return nullptr;
 
             if (!(chars = JS_GetStringCharsAndLength(cx, jsstr, &length)))
                 return nullptr;
         }
 
         JS::Anchor<JSString *> kungFuDeathGrip(jsstr);
-        script = JS_CompileUCScript (cx, obj, chars, length, "x-jsd:ppbuffer?type=script", 1);
+        JS::CompileOptions options(cx);
+        options.setFileAndLine("x-jsd:ppbuffer?type=script", 1);
+        script = JS_CompileUCScript(cx, obj, chars, length, options);
         if (!script)
             return nullptr;
         baseLine = 1;
     }
 
     uint32_t scriptExtent = JS_GetScriptLineExtent (cx, script);
     jsbytecode* firstPC = JS_LineNumberToPC (cx, script, 0);
     /* allocate worst case size of map (number of lines in script + 1
@@ -1642,17 +1646,16 @@ jsdContext::GetJSContext(JSContext **_rv
 
 /* Simulate the old options API in terms of the new one for backwards
  * compatibility */
 
 #define JSOPTION_EXTRA_WARNINGS                 JS_BIT(0)
 #define JSOPTION_WERROR                         JS_BIT(1)
 #define JSOPTION_VAROBJFIX                      JS_BIT(2)
 #define JSOPTION_PRIVATE_IS_NSISUPPORTS         JS_BIT(3)
-#define JSOPTION_COMPILE_N_GO                   JS_BIT(4)
 #define JSOPTION_DONT_REPORT_UNCAUGHT           JS_BIT(8)
 #define JSOPTION_NO_DEFAULT_COMPARTMENT_OBJECT  JS_BIT(11)
 #define JSOPTION_NO_SCRIPT_RVAL                 JS_BIT(12)
 #define JSOPTION_BASELINE                       JS_BIT(14)
 #define JSOPTION_TYPE_INFERENCE                 JS_BIT(16)
 #define JSOPTION_STRICT_MODE                    JS_BIT(17)
 #define JSOPTION_ION                            JS_BIT(18)
 #define JSOPTION_ASMJS                          JS_BIT(19)
@@ -1661,17 +1664,16 @@ jsdContext::GetJSContext(JSContext **_rv
 NS_IMETHODIMP
 jsdContext::GetOptions(uint32_t *_rval)
 {
     ASSERT_VALID_EPHEMERAL;
     *_rval = (JS::ContextOptionsRef(mJSCx).extraWarnings() ? JSOPTION_EXTRA_WARNINGS : 0)
            | (JS::ContextOptionsRef(mJSCx).werror() ? JSOPTION_WERROR : 0)
            | (JS::ContextOptionsRef(mJSCx).varObjFix() ? JSOPTION_VAROBJFIX : 0)
            | (JS::ContextOptionsRef(mJSCx).privateIsNSISupports() ? JSOPTION_PRIVATE_IS_NSISUPPORTS : 0)
-           | (JS::ContextOptionsRef(mJSCx).compileAndGo() ? JSOPTION_COMPILE_N_GO : 0)
            | (JS::ContextOptionsRef(mJSCx).dontReportUncaught() ? JSOPTION_DONT_REPORT_UNCAUGHT : 0)
            | (JS::ContextOptionsRef(mJSCx).noDefaultCompartmentObject() ? JSOPTION_NO_DEFAULT_COMPARTMENT_OBJECT : 0)
            | (JS::ContextOptionsRef(mJSCx).noScriptRval() ? JSOPTION_NO_SCRIPT_RVAL : 0)
            | (JS::ContextOptionsRef(mJSCx).strictMode() ? JSOPTION_STRICT_MODE : 0)
            | (JS::ContextOptionsRef(mJSCx).baseline() ? JSOPTION_BASELINE : 0)
            | (JS::ContextOptionsRef(mJSCx).typeInference() ? JSOPTION_TYPE_INFERENCE : 0)
            | (JS::ContextOptionsRef(mJSCx).ion() ? JSOPTION_ION : 0)
            | (JS::ContextOptionsRef(mJSCx).asmJS() ? JSOPTION_ASMJS : 0);
@@ -1687,17 +1689,16 @@ jsdContext::SetOptions(uint32_t options)
      * in the foot. */
     if (JS::ContextOptionsRef(mJSCx).privateIsNSISupports() !=
         (options & JSOPTION_PRIVATE_IS_NSISUPPORTS))
         return NS_ERROR_ILLEGAL_VALUE;
 
     JS::ContextOptionsRef(mJSCx).setExtraWarnings(options & JSOPTION_EXTRA_WARNINGS)
                                 .setWerror(options & JSOPTION_WERROR)
                                 .setVarObjFix(options & JSOPTION_VAROBJFIX)
-                                .setCompileAndGo(options & JSOPTION_COMPILE_N_GO)
                                 .setDontReportUncaught(options & JSOPTION_DONT_REPORT_UNCAUGHT)
                                 .setNoDefaultCompartmentObject(options & JSOPTION_NO_DEFAULT_COMPARTMENT_OBJECT)
                                 .setNoScriptRval(options & JSOPTION_NO_SCRIPT_RVAL)
                                 .setStrictMode(options & JSOPTION_STRICT_MODE)
                                 .setBaseline(options & JSOPTION_BASELINE)
                                 .setTypeInference(options & JSOPTION_TYPE_INFERENCE)
                                 .setIon(options & JSOPTION_ION)
                                 .setAsmJS(options & JSOPTION_ASMJS);
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -280,17 +280,17 @@ GCParameter(JSContext *cx, unsigned argc
     JSFlatString *flatStr = JS_FlattenString(cx, str);
     if (!flatStr)
         return false;
 
     size_t paramIndex = 0;
     for (;; paramIndex++) {
         if (paramIndex == ArrayLength(paramMap)) {
             JS_ReportError(cx,
-                           "the first argument argument must be maxBytes, "
+                           "the first argument must be maxBytes, "
                            "maxMallocBytes, gcStackpoolLifespan, gcBytes or "
                            "gcNumber");
             return false;
         }
         if (JS_FlatStringEqualsAscii(flatStr, paramMap[paramIndex].name))
             break;
     }
     JSGCParamKey param = paramMap[paramIndex].param;
@@ -358,18 +358,18 @@ InternalConst(JSContext *cx, unsigned ar
 
     JSString *str = ToString(cx, args[0]);
     if (!str)
         return false;
     JSFlatString *flat = JS_FlattenString(cx, str);
     if (!flat)
         return false;
 
-    if (JS_FlatStringEqualsAscii(flat, "MARK_STACK_LENGTH")) {
-        vp[0] = UINT_TO_JSVAL(js::MARK_STACK_LENGTH);
+    if (JS_FlatStringEqualsAscii(flat, "INCREMENTAL_MARK_STACK_BASE_CAPACITY")) {
+        vp[0] = UINT_TO_JSVAL(js::INCREMENTAL_MARK_STACK_BASE_CAPACITY);
     } else {
         JS_ReportError(cx, "unknown const name");
         return false;
     }
     return true;
 }
 
 static bool
--- a/js/src/config/expandlibs_exec.py
+++ b/js/src/config/expandlibs_exec.py
@@ -79,18 +79,24 @@ class ExpandArgsMore(ExpandArgs):
                 if os.path.exists(arg + conf.LIBS_DESC_SUFFIX):
                     newlist += self._extract(self._expand_desc(arg))
                     continue
                 elif os.path.exists(arg) and (len(ar_extract) or conf.AR == 'lib'):
                     tmp = tempfile.mkdtemp(dir=os.curdir)
                     self.tmp.append(tmp)
                     if conf.AR == 'lib':
                         out = subprocess.check_output([conf.AR, '-NOLOGO', '-LIST', arg])
-                        for l in out.splitlines():
-                            subprocess.call([conf.AR, '-NOLOGO', '-EXTRACT:%s' % l, os.path.abspath(arg)], cwd=tmp)
+                        files = out.splitlines()
+                        # If lib -list returns a list full of dlls, it's an
+                        # import lib.
+                        if all(isDynamicLib(f) for f in files):
+                            newlist += [arg]
+                            continue
+                        for f in files:
+                            subprocess.call([conf.AR, '-NOLOGO', '-EXTRACT:%s' % f, os.path.abspath(arg)], cwd=tmp)
                     else:
                         subprocess.call(ar_extract + [os.path.abspath(arg)], cwd=tmp)
                     objs = []
                     for root, dirs, files in os.walk(tmp):
                         objs += [relativize(os.path.join(root, f)) for f in files if isObject(f)]
                     newlist += sorted(objs)
                     continue
             newlist += [arg]
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -2549,16 +2549,19 @@ AC_CACHE_CHECK(
     [if test "$OS_TARGET" = NetBSD -o "$OS_TARGET" = OpenBSD; then
         dnl no need for res_ninit() on NetBSD and OpenBSD
         ac_cv_func_res_ninit=no
      else
        AC_TRY_LINK([
             #ifdef linux
             #define _BSD_SOURCE 1
             #endif
+            #include <sys/types.h>
+            #include <netinet/in.h>
+            #include <arpa/nameser.h>
             #include <resolv.h>
             ],
             [int foo = res_ninit(&_res);],
             [ac_cv_func_res_ninit=yes],
             [ac_cv_func_res_ninit=no])
      fi
     ])
 
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -1265,17 +1265,17 @@ struct SlotArrayLayout
  * that are stored on the stack. To prevent this from happening, we replace all
  * ValueArrayTag stack items with SavedValueArrayTag. In the latter, slots
  * pointers are replaced with slot indexes, and slot array end pointers are
  * replaced with the kind of index (properties vs. elements).
  */
 void
 GCMarker::saveValueRanges()
 {
-    for (uintptr_t *p = stack.tos; p > stack.stack; ) {
+    for (uintptr_t *p = stack.tos_; p > stack.stack_; ) {
         uintptr_t tag = *--p & StackTagMask;
         if (tag == ValueArrayTag) {
             *p &= ~StackTagMask;
             p -= 2;
             SlotArrayLayout *arr = reinterpret_cast<SlotArrayLayout *>(p);
             JSObject *obj = arr->obj;
             JS_ASSERT(obj->isNative());
 
@@ -1469,17 +1469,17 @@ GCMarker::processMarkStackTop(SliceBudge
         PushMarkStack(this, type);
 
         Shape *shape = obj->lastProperty();
         PushMarkStack(this, shape);
 
         /* Call the trace hook if necessary. */
         const Class *clasp = type->clasp;
         if (clasp->trace) {
-            JS_ASSERT_IF(runtime->gcMode == JSGC_MODE_INCREMENTAL &&
+            JS_ASSERT_IF(runtime->gcMode() == JSGC_MODE_INCREMENTAL &&
                          runtime->gcIncrementalEnabled,
                          clasp->flags & JSCLASS_IMPLEMENTS_BARRIERS);
             clasp->trace(this, obj);
         }
 
         if (!shape->isNative())
             return;
 
--- a/js/src/jit-test/tests/basic/bug656261.js
+++ b/js/src/jit-test/tests/basic/bug656261.js
@@ -1,16 +1,16 @@
 function build_getter(i) {
     var x = [i];
     return function f() { return x; }
 }
 
 function test()
 {
-    var N = internalConst("MARK_STACK_LENGTH") + 2;
+    var N = internalConst("INCREMENTAL_MARK_STACK_BASE_CAPACITY") + 2;
     var o = {};
     var descriptor = { enumerable: true};
     for (var i = 0; i != N; ++i) {
 	descriptor.get = build_getter(i);
 	Object.defineProperty(o, i, descriptor);
     }
 
     // At this point we have an object o with N getters. Each getter in turn
--- a/js/src/jit-test/tests/debug/Script-startLine.js
+++ b/js/src/jit-test/tests/debug/Script-startLine.js
@@ -3,19 +3,21 @@ var dbg = Debugger(g);
 var start, count;
 dbg.onDebuggerStatement = function (frame) {
     assertEq(start, undefined);
     start = frame.script.startLine;
     count = frame.script.lineCount;
     assertEq(typeof frame.script.url, 'string');
 };
 
-function test(f) {
+function test(f, manualCount) {
     start = count = g.first = g.last = undefined;
     f();
+    if (manualCount)
+        g.last = g.first + manualCount - 1;
     assertEq(start, g.first);
     assertEq(count, g.last + 1 - g.first);
     print(start, count);
 }
 
 test(function () {
     g.eval("first = Error().lineNumber;\n" +
            "debugger;\n" +
@@ -36,8 +38,24 @@ test(function () {
            "f1();");
 });
 
 g.eval("function f2() {\n" +
        "    eval('first = Error().lineNumber\\n\\ndebugger;\\n\\nlast = Error().lineNumber;');\n" +
        "}\n");
 test(g.f2);
 test(g.f2);
+
+// Having a last = Error().lineNumber forces a setline srcnote, so test a
+// function that ends with newline srcnotes.
+g.eval("/* Any copyright is dedicated to the Public Domain.\n" +
+       " http://creativecommons.org/publicdomain/zero/1.0/ */\n" +
+       "\n" +
+       "function secondCall() { first = Error().lineNumber;\n" +
+       "    debugger;\n" +
+       "    // Comment\n" +
+       "    eval(\"42;\");\n" +
+       "    function foo() {}\n" +
+       "    if (true) {\n" +
+       "        foo();\n" +  // <- this is +6 and must be within the extent
+       "    }\n" +
+       "}");
+test(g.secondCall, 7);
--- a/js/src/jsapi-tests/testChromeBuffer.cpp
+++ b/js/src/jsapi-tests/testChromeBuffer.cpp
@@ -59,19 +59,21 @@ BEGIN_TEST(testChromeBuffer)
      * buffer space.
      */
     {
         {
             JSAutoCompartment ac(cx, trusted_glob);
             const char *paramName = "x";
             const char *bytes = "return x ? 1 + trusted(x-1) : 0";
             JS::HandleObject global = JS::HandleObject::fromMarkedLocation(&trusted_glob);
-            CHECK(fun = JS_CompileFunctionForPrincipals(cx, global, &system_principals,
-                                                        "trusted", 1, &paramName, bytes, strlen(bytes),
-                                                        "", 0));
+            JS::CompileOptions options(cx);
+            options.setFileAndLine("", 0)
+                   .setPrincipals(&system_principals);
+            CHECK(fun = JS_CompileFunction(cx, global, "trusted", 1, &paramName,
+                                           bytes, strlen(bytes), options));
             trusted_fun = JS_GetFunctionObject(fun);
             if (!JS_AddNamedObjectRoot(cx, &trusted_fun, "trusted-function"))
                 return false;
         }
 
         JS::RootedValue v(cx, JS::ObjectValue(*trusted_fun));
         CHECK(JS_WrapValue(cx, &v));
 
@@ -80,18 +82,20 @@ BEGIN_TEST(testChromeBuffer)
                             "    return untrusted(trusted);             "
                             "} catch (e) {                              "
                             "    try {                                  "
                             "        return trusted(100);               "
                             "    } catch(e) {                           "
                             "        return -1;                         "
                             "    }                                      "
                             "}                                          ";
+        JS::CompileOptions options(cx);
+        options.setFileAndLine("", 0);
         CHECK(fun = JS_CompileFunction(cx, global, "untrusted", 1, &paramName,
-                                       bytes, strlen(bytes), "", 0));
+                                       bytes, strlen(bytes), options));
 
         JS::RootedValue rval(cx);
         CHECK(JS_CallFunction(cx, nullptr, fun, 1, v.address(), rval.address()));
         CHECK(JSVAL_TO_INT(rval) == 100);
     }
 
     /*
      * Check that content called from chrome in the reserved-buffer space
@@ -102,33 +106,37 @@ BEGIN_TEST(testChromeBuffer)
             JSAutoCompartment ac(cx, trusted_glob);
             const char *paramName = "untrusted";
             const char *bytes = "try {                                  "
                                 "  untrusted();                         "
                                 "} catch (e) {                          "
                                 "  return 'From trusted: ' + e;         "
                                 "}                                      ";
             JS::HandleObject global = JS::HandleObject::fromMarkedLocation(&trusted_glob);
-            CHECK(fun = JS_CompileFunctionForPrincipals(cx, global, &system_principals,
-                                                        "trusted", 1, &paramName, bytes, strlen(bytes),
-                                                        "", 0));
+            JS::CompileOptions options(cx);
+            options.setFileAndLine("", 0)
+                   .setPrincipals(&system_principals);
+            CHECK(fun = JS_CompileFunction(cx, global, "trusted", 1, &paramName,
+                                           bytes, strlen(bytes), options));
             trusted_fun = JS_GetFunctionObject(fun);
         }
 
         JS::RootedValue v(cx, JS::ObjectValue(*trusted_fun));
         CHECK(JS_WrapValue(cx, &v));
 
         const char *paramName = "trusted";
         const char *bytes = "try {                                      "
                             "  return untrusted(trusted);               "
                             "} catch (e) {                              "
                             "  return trusted(untrusted);               "
                             "}                                          ";
+        JS::CompileOptions options(cx);
+        options.setFileAndLine("", 0);
         CHECK(fun = JS_CompileFunction(cx, global, "untrusted", 1, &paramName,
-                                       bytes, strlen(bytes), "", 0));
+                                       bytes, strlen(bytes), options));
 
         JS::RootedValue rval(cx);
         CHECK(JS_CallFunction(cx, nullptr, fun, 1, v.address(), rval.address()));
         bool match;
         CHECK(JS_StringEqualsAscii(cx, JSVAL_TO_STRING(rval), "From trusted: InternalError: too much recursion", &match));
         CHECK(match);
     }
 
@@ -136,33 +144,37 @@ BEGIN_TEST(testChromeBuffer)
      * Check that JS_SaveFrameChain called on the way from content to chrome
      * (say, as done by XPCJSContextSTack::Push) works.
      */
     {
         {
             JSAutoCompartment ac(cx, trusted_glob);
             const char *bytes = "return 42";
             JS::HandleObject global = JS::HandleObject::fromMarkedLocation(&trusted_glob);
-            CHECK(fun = JS_CompileFunctionForPrincipals(cx, global, &system_principals,
-                                                        "trusted", 0, nullptr,
-                                                        bytes, strlen(bytes), "", 0));
+            JS::CompileOptions options(cx);
+            options.setFileAndLine("", 0)
+                   .setPrincipals(&system_principals);
+            CHECK(fun = JS_CompileFunction(cx, global, "trusted", 0, nullptr,
+                                           bytes, strlen(bytes), options));
             trusted_fun = JS_GetFunctionObject(fun);
         }
 
         JS::RootedFunction fun(cx, JS_NewFunction(cx, CallTrusted, 0, 0, global, "callTrusted"));
         JS::RootedObject callTrusted(cx, JS_GetFunctionObject(fun));
 
         const char *paramName = "f";
         const char *bytes = "try {                                      "
                             "  return untrusted(trusted);               "
                             "} catch (e) {                              "
                             "  return f();                              "
                             "}                                          ";
+        JS::CompileOptions options(cx);
+        options.setFileAndLine("", 0);
         CHECK(fun = JS_CompileFunction(cx, global, "untrusted", 1, &paramName,
-                                       bytes, strlen(bytes), "", 0));
+                                       bytes, strlen(bytes), options));
 
         JS::RootedValue arg(cx, JS::ObjectValue(*callTrusted));
         JS::RootedValue rval(cx);
         CHECK(JS_CallFunction(cx, nullptr, fun, 1, arg.address(), rval.address()));
         CHECK(JSVAL_TO_INT(rval) == 42);
     }
 
     return true;
--- a/js/src/jsapi-tests/testCloneScript.cpp
+++ b/js/src/jsapi-tests/testCloneScript.cpp
@@ -28,18 +28,20 @@ BEGIN_TEST(test_cloneScript)
         "(sum);\n";
 
     JS::RootedObject obj(cx);
 
     // compile for A
     {
         JSAutoCompartment a(cx, A);
         JSFunction *fun;
-        CHECK(fun = JS_CompileFunction(cx, A, "f", 0, nullptr, source, strlen(source),
-                                       __FILE__, 1));
+        JS::CompileOptions options(cx);
+        options.setFileAndLine(__FILE__, 1);
+        CHECK(fun = JS_CompileFunction(cx, A, "f", 0, nullptr, source,
+                                       strlen(source), options));
         CHECK(obj = JS_GetFunctionObject(fun));
     }
 
     // clone into B
     {
         JSAutoCompartment b(cx, B);
         CHECK(JS_CloneFunctionObject(cx, obj, B));
     }
@@ -99,19 +101,22 @@ BEGIN_TEST(test_cloneScriptWithPrincipal
     const char *argnames[] = { "arg" };
     const char *source = "return function() { return arg; }";
 
     JS::RootedObject obj(cx);
 
     // Compile in A
     {
         JSAutoCompartment a(cx, A);
-        JS::RootedFunction fun(cx, JS_CompileFunctionForPrincipals(cx, A, principalsA, "f",
-                                                               mozilla::ArrayLength(argnames), argnames,
-                                                               source, strlen(source), __FILE__, 1));
+        JS::CompileOptions options(cx);
+        options.setFileAndLine(__FILE__, 1)
+               .setPrincipals(principalsA);
+        JS::RootedFunction fun(cx, JS_CompileFunction(cx, A, "f",
+                mozilla::ArrayLength(argnames), argnames, source,
+                strlen(source), options));
         CHECK(fun);
 
         JSScript *script;
         CHECK(script = JS_GetFunctionScript(cx, fun));
 
         CHECK(JS_GetScriptPrincipals(script) == principalsA);
         CHECK(obj = JS_GetFunctionObject(fun));
     }
--- a/js/src/jsapi-tests/testEnclosingFunction.cpp
+++ b/js/src/jsapi-tests/testEnclosingFunction.cpp
@@ -31,32 +31,35 @@ BEGIN_TEST(test_enclosingFunction)
 {
     CHECK(JS_DefineFunction(cx, global, "checkEnclosing", CheckEnclosing, 0, 0));
 
     EXEC("checkEnclosing()");
     CHECK(found == nullptr);
 
     RootedFunction fun(cx);
 
+    JS::CompileOptions options(cx);
+    options.setFileAndLine(__FILE__, __LINE__);
+
     const char s1chars[] = "checkEnclosing()";
-    fun = JS_CompileFunction(cx, global, "s1", 0, nullptr, s1chars, strlen(s1chars),
-                             __FILE__, __LINE__);
+    fun = JS_CompileFunction(cx, global, "s1", 0, nullptr, s1chars,
+                             strlen(s1chars), options);
     CHECK(fun);
     EXEC("s1()");
     CHECK(found == JS_GetFunctionScript(cx, fun));
 
     const char s2chars[] = "return function() { checkEnclosing() }";
-    fun = JS_CompileFunction(cx, global, "s2", 0, nullptr, s2chars, strlen(s2chars),
-                             __FILE__, __LINE__);
+    fun = JS_CompileFunction(cx, global, "s2", 0, nullptr, s2chars,
+                             strlen(s2chars), options);
     CHECK(fun);
     EXEC("s2()()");
     CHECK(found == JS_GetFunctionScript(cx, fun));
 
     const char s3chars[] = "return function() { let (x) { function g() { checkEnclosing() } return g() } }";
-    fun = JS_CompileFunction(cx, global, "s3", 0, nullptr, s3chars, strlen(s3chars),
-                             __FILE__, __LINE__);
+    fun = JS_CompileFunction(cx, global, "s3", 0, nullptr, s3chars,
+                             strlen(s3chars), options);
     CHECK(fun);
     EXEC("s3()()");
     CHECK(found == JS_GetFunctionScript(cx, fun));
 
     return true;
 }
 END_TEST(test_enclosingFunction)
--- a/js/src/jsapi-tests/testScriptInfo.cpp
+++ b/js/src/jsapi-tests/testScriptInfo.cpp
@@ -32,17 +32,20 @@ CharsMatch(const jschar *p, const char *
     return true;
 }
 
 // Bug 670958 - fix JS_GetScriptLineExtent, among others
 BEGIN_TEST(testScriptInfo)
 {
     unsigned startLine = 1000;
 
-    JS::RootedScript script(cx, JS_CompileScript(cx, global, code, strlen(code), __FILE__, startLine));
+    JS::CompileOptions options(cx);
+    options.setFileAndLine(__FILE__, startLine);
+    JS::RootedScript script(cx, JS_CompileScript(cx, global, code, strlen(code),
+                                                 options));
 
     CHECK(script);
 
     jsbytecode *start = JS_LineNumberToPC(cx, script, startLine);
     CHECK_EQUAL(JS_GetScriptBaseLineNumber(cx, script), startLine);
     CHECK_EQUAL(JS_PCToLineNumber(cx, script, start), startLine);
     CHECK_EQUAL(JS_GetScriptLineExtent(cx, script), 11);
     CHECK(strcmp(JS_GetScriptFilename(cx, script), __FILE__) == 0);
--- a/js/src/jsapi-tests/testScriptObject.cpp
+++ b/js/src/jsapi-tests/testScriptObject.cpp
@@ -35,57 +35,66 @@ struct ScriptObjectFixture : public JSAP
 
 const char ScriptObjectFixture::code[] =
     "(function(a, b){return a+' '+b;}('hello', 'world'))";
 const int ScriptObjectFixture::code_size = sizeof(ScriptObjectFixture::code) - 1;
 jschar ScriptObjectFixture::uc_code[ScriptObjectFixture::code_size];
 
 BEGIN_FIXTURE_TEST(ScriptObjectFixture, bug438633_CompileScript)
 {
+    JS::CompileOptions options(cx);
+    options.setFileAndLine(__FILE__, __LINE__);
     return tryScript(global, JS_CompileScript(cx, global, code, code_size,
-                                              __FILE__, __LINE__));
+                                              options));
 }
 END_FIXTURE_TEST(ScriptObjectFixture, bug438633_CompileScript)
 
 BEGIN_FIXTURE_TEST(ScriptObjectFixture, bug438633_CompileScript_empty)
 {
-    return tryScript(global, JS_CompileScript(cx, global, "", 0,
-                                              __FILE__, __LINE__));
+    JS::CompileOptions options(cx);
+    options.setFileAndLine(__FILE__, __LINE__);
+    return tryScript(global, JS_CompileScript(cx, global, "", 0, options));
 }
 END_FIXTURE_TEST(ScriptObjectFixture, bug438633_CompileScript_empty)
 
 BEGIN_FIXTURE_TEST(ScriptObjectFixture, bug438633_CompileScriptForPrincipals)
 {
-    return tryScript(global, JS_CompileScriptForPrincipals(cx, global, nullptr,
-                                                           code, code_size,
-                                                           __FILE__, __LINE__));
+    JS::CompileOptions options(cx);
+    options.setFileAndLine(__FILE__, __LINE__)
+           .setPrincipals(nullptr);
+    return tryScript(global, JS_CompileScript(cx, global, code, code_size,
+                                              options));
 }
 END_FIXTURE_TEST(ScriptObjectFixture, bug438633_CompileScriptForPrincipals)
 
 BEGIN_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileUCScript)
 {
-    return tryScript(global, JS_CompileUCScript(cx, global,
-                                                uc_code, code_size,
-                                                __FILE__, __LINE__));
+    JS::CompileOptions options(cx);
+    options.setFileAndLine(__FILE__, __LINE__);
+    return tryScript(global, JS_CompileUCScript(cx, global, uc_code, code_size,
+                                                options));
 }
 END_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileUCScript)
 
 BEGIN_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileUCScript_empty)
 {
-    return tryScript(global, JS_CompileUCScript(cx, global,
-                                                uc_code, 0,
-                                                __FILE__, __LINE__));
+    JS::CompileOptions options(cx);
+    options.setFileAndLine(__FILE__, __LINE__);
+    return tryScript(global, JS_CompileUCScript(cx, global, uc_code, 0,
+                                                options));
 }
 END_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileUCScript_empty)
 
 BEGIN_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileUCScriptForPrincipals)
 {
-    return tryScript(global, JS_CompileUCScriptForPrincipals(cx, global, nullptr,
-                                                             uc_code, code_size,
-                                                             __FILE__, __LINE__));
+    JS::CompileOptions options(cx);
+    options.setFileAndLine(__FILE__, __LINE__)
+           .setPrincipals(nullptr);
+    return tryScript(global, JS_CompileUCScript(cx, global, uc_code, code_size,
+                                                options));
 }
 END_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileUCScriptForPrincipals)
 
 BEGIN_FIXTURE_TEST(ScriptObjectFixture, bug438633_JS_CompileFile)
 {
     TempFile tempScript;
     static const char script_filename[] = "temp-bug438633_JS_CompileFile";
     FILE *script_stream = tempScript.open(script_filename);
--- a/js/src/jsapi-tests/testTrap.cpp
+++ b/js/src/jsapi-tests/testTrap.cpp
@@ -29,17 +29,20 @@ BEGIN_TEST(testTrap_gc)
 "while (i < 10) {\n"
 "    sum += i;\n"
 "    ++i;\n"
 "}\n"
 "({ result: sum });\n"
         ;
 
     // compile
-    JS::RootedScript script(cx, JS_CompileScript(cx, global, source, strlen(source), __FILE__, 1));
+    JS::CompileOptions options(cx);
+    options.setFileAndLine(__FILE__, 1);
+    JS::RootedScript script(cx, JS_CompileScript(cx, global, source,
+                                                 strlen(source), options));
     CHECK(script);
 
     // execute
     JS::RootedValue v2(cx);
     CHECK(JS_ExecuteScript(cx, global, script, v2.address()));
     CHECK(v2.isObject());
     CHECK_EQUAL(emptyTrapCallCount, 0);
 
--- a/js/src/jsapi-tests/testXDR.cpp
+++ b/js/src/jsapi-tests/testXDR.cpp
@@ -158,17 +158,20 @@ BEGIN_TEST(testXDR_bug506491)
         "function makeClosure(s, name, value) {\n"
         "    eval(s);\n"
         "    Math.sin(value);\n"
         "    return let (n = name, v = value) function () { return String(v); };\n"
         "}\n"
         "var f = makeClosure('0;', 'status', 'ok');\n";
 
     // compile
-    JS::RootedScript script(cx, JS_CompileScript(cx, global, s, strlen(s), __FILE__, __LINE__));
+    JS::CompileOptions options(cx);
+    options.setFileAndLine(__FILE__, __LINE__);
+    JS::RootedScript script(cx, JS_CompileScript(cx, global, s, strlen(s),
+                                                 options));
     CHECK(script);
 
     script = FreezeThaw(cx, script);
     CHECK(script);
 
     // execute
     JS::RootedValue v2(cx);
     CHECK(JS_ExecuteScript(cx, global, script, v2.address()));
@@ -182,17 +185,19 @@ BEGIN_TEST(testXDR_bug506491)
     CHECK_SAME(v2, trueval);
     return true;
 }
 END_TEST(testXDR_bug506491)
 
 BEGIN_TEST(testXDR_bug516827)
 {
     // compile an empty script
-    JS::RootedScript script(cx, JS_CompileScript(cx, global, "", 0, __FILE__, __LINE__));
+    JS::CompileOptions options(cx);
+    options.setFileAndLine(__FILE__, __LINE__);
+    JS::RootedScript script(cx, JS_CompileScript(cx, global, "", 0, options));
     CHECK(script);
 
     script = FreezeThaw(cx, script);
     CHECK(script);
 
     // execute with null result meaning no result wanted
     CHECK(JS_ExecuteScript(cx, global, script, nullptr));
     return true;
@@ -203,17 +208,20 @@ BEGIN_TEST(testXDR_source)
 {
     const char *samples[] = {
         // This can't possibly fail to compress well, can it?
         "function f(x) { return x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x }",
         "short",
         nullptr
     };
     for (const char **s = samples; *s; s++) {
-        JS::RootedScript script(cx, JS_CompileScript(cx, global, *s, strlen(*s), __FILE__, __LINE__));
+        JS::CompileOptions options(cx);
+        options.setFileAndLine(__FILE__, __LINE__);
+        JS::RootedScript script(cx, JS_CompileScript(cx, global, *s, strlen(*s),
+                                                     options));
         CHECK(script);
         script = FreezeThaw(cx, script);
         CHECK(script);
         JSString *out = JS_DecompileScript(cx, script, "testing", 0);
         CHECK(out);
         bool equal;
         CHECK(JS_StringEqualsAscii(cx, out, *s, &equal));
         CHECK(equal);
@@ -226,17 +234,19 @@ BEGIN_TEST(testXDR_sourceMap)
 {
     const char *sourceMaps[] = {
         "http://example.com/source-map.json",
         "file:///var/source-map.json",
         nullptr
     };
     JS::RootedScript script(cx);
     for (const char **sm = sourceMaps; *sm; sm++) {
-        script = JS_CompileScript(cx, global, "", 0, __FILE__, __LINE__);
+        JS::CompileOptions options(cx);
+        options.setFileAndLine(__FILE__, __LINE__);
+        script = JS_CompileScript(cx, global, "", 0, options);
         CHECK(script);
 
         size_t len = strlen(*sm);
         jschar *expected = js::InflateString(cx, *sm, &len);
         CHECK(expected);
 
         // The script source takes responsibility of free'ing |expected|.
         CHECK(script->scriptSource()->setSourceMapURL(cx, expected));
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -2062,44 +2062,44 @@ JS_SetGCParameter(JSRuntime *rt, JSGCPar
       case JSGC_ALLOCATION_THRESHOLD:
         rt->gcAllocationThreshold = value * 1024 * 1024;
         break;
       case JSGC_DECOMMIT_THRESHOLD:
         rt->gcDecommitThreshold = value * 1024 * 1024;
         break;
       default:
         JS_ASSERT(key == JSGC_MODE);
-        rt->gcMode = JSGCMode(value);
-        JS_ASSERT(rt->gcMode == JSGC_MODE_GLOBAL ||
-                  rt->gcMode == JSGC_MODE_COMPARTMENT ||
-                  rt->gcMode == JSGC_MODE_INCREMENTAL);
+        rt->setGCMode(JSGCMode(value));
+        JS_ASSERT(rt->gcMode() == JSGC_MODE_GLOBAL ||
+                  rt->gcMode() == JSGC_MODE_COMPARTMENT ||
+                  rt->gcMode() == JSGC_MODE_INCREMENTAL);
         return;
     }
 }
 
 JS_PUBLIC_API(uint32_t)
 JS_GetGCParameter(JSRuntime *rt, JSGCParamKey key)
 {
     switch (key) {
       case JSGC_MAX_BYTES:
         return uint32_t(rt->gcMaxBytes);
       case JSGC_MAX_MALLOC_BYTES:
         return rt->gcMaxMallocBytes;
       case JSGC_BYTES:
         return uint32_t(rt->gcBytes);
       case JSGC_MODE:
-        return uint32_t(rt->gcMode);
+        return uint32_t(rt->gcMode());
       case JSGC_UNUSED_CHUNKS:
         return uint32_t(rt->gcChunkPool.getEmptyCount());
       case JSGC_TOTAL_CHUNKS:
         return uint32_t(rt->gcChunkSet.count() + rt->gcChunkPool.getEmptyCount());
       case JSGC_SLICE_TIME_BUDGET:
         return uint32_t(rt->gcSliceBudget > 0 ? rt->gcSliceBudget / PRMJ_USEC_PER_MSEC : 0);
       case JSGC_MARK_STACK_LIMIT:
-        return rt->gcMarker.sizeLimit();
+        return rt->gcMarker.maxCapacity();
       case JSGC_HIGH_FREQUENCY_TIME_LIMIT:
         return rt->gcHighFrequencyTimeThreshold;
       case JSGC_HIGH_FREQUENCY_LOW_LIMIT:
         return rt->gcHighFrequencyLowLimitBytes / 1024 / 1024;
       case JSGC_HIGH_FREQUENCY_HIGH_LIMIT:
         return rt->gcHighFrequencyHighLimitBytes / 1024 / 1024;
       case JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MAX:
         return uint32_t(rt->gcHighFrequencyHeapGrowthMax * 100);
@@ -4394,17 +4394,17 @@ JS::OwningCompileOptions::setSourceMapUR
     return true;
 }
 
 JS::CompileOptions::CompileOptions(JSContext *cx, JSVersion version)
     : ReadOnlyCompileOptions(), elementRoot(cx)
 {
     this->version = (version != JSVERSION_UNKNOWN) ? version : cx->findVersion();
 
-    compileAndGo = cx->options().compileAndGo();
+    compileAndGo = false;
     noScriptRval = cx->options().noScriptRval();
     strictOption = cx->options().strictMode();
     extraWarningsOption = cx->options().extraWarnings();
     werrorOption = cx->options().werror();
     asmJSOption = cx->options().asmJS();
 }
 
 JSScript *
@@ -4509,62 +4509,27 @@ JS::FinishOffThreadScript(JSContext *may
 
     return rt->workerThreadState->finishParseTask(maybecx, rt, token);
 #else
     MOZ_ASSUME_UNREACHABLE("Off thread compilation is not available.");
 #endif
 }
 
 JS_PUBLIC_API(JSScript *)
-JS_CompileUCScriptForPrincipals(JSContext *cx, JSObject *objArg, JSPrincipals *principals,
-                                const jschar *chars, size_t length,
-                                const char *filename, unsigned lineno)
-{
-    RootedObject obj(cx, objArg);
-    CompileOptions options(cx);
-    options.setPrincipals(principals)
-           .setFileAndLine(filename, lineno);
-
-    return Compile(cx, obj, options, chars, length);
-}
-
-JS_PUBLIC_API(JSScript *)
-JS_CompileUCScript(JSContext *cx, JSObject *objArg, const jschar *chars, size_t length,
-                   const char *filename, unsigned lineno)
-{
-    RootedObject obj(cx, objArg);
-    CompileOptions options(cx);
-    options.setFileAndLine(filename, lineno);
-
-    return Compile(cx, obj, options, chars, length);
-}
-
-JS_PUBLIC_API(JSScript *)
-JS_CompileScriptForPrincipals(JSContext *cx, JSObject *objArg,
-                              JSPrincipals *principals,
-                              const char *ascii, size_t length,
-                              const char *filename, unsigned lineno)
-{
-    RootedObject obj(cx, objArg);
-    CompileOptions options(cx);
-    options.setPrincipals(principals)
-           .setFileAndLine(filename, lineno);
-
+JS_CompileScript(JSContext *cx, JS::HandleObject obj, const char *ascii,
+                 size_t length, const JS::CompileOptions &options)
+{
     return Compile(cx, obj, options, ascii, length);
 }
 
 JS_PUBLIC_API(JSScript *)
-JS_CompileScript(JSContext *cx, JSObject *objArg, const char *ascii, size_t length,
-                 const char *filename, unsigned lineno)
-{
-    RootedObject obj(cx, objArg);
-    CompileOptions options(cx);
-    options.setFileAndLine(filename, lineno);
-
-    return Compile(cx, obj, options, ascii, length);
+JS_CompileUCScript(JSContext *cx, JS::HandleObject obj, const jschar *chars,
+                   size_t length, const JS::CompileOptions &options)
+{
+    return Compile(cx, obj, options, chars, length);
 }
 
 JS_PUBLIC_API(bool)
 JS_BufferIsCompilableUnit(JSContext *cx, JSObject *objArg, const char *utf8, size_t length)
 {
     RootedObject obj(cx, objArg);
     bool result;
     JSExceptionState *exnState;
@@ -4670,53 +4635,30 @@ JS::CompileFunction(JSContext *cx, Handl
         return nullptr;
 
     JSFunction *fun = CompileFunction(cx, obj, options, name, nargs, argnames, chars, length);
     js_free(chars);
     return fun;
 }
 
 JS_PUBLIC_API(JSFunction *)
-JS_CompileUCFunction(JSContext *cx, JSObject *objArg, const char *name,
+JS_CompileUCFunction(JSContext *cx, JS::HandleObject obj, const char *name,
                      unsigned nargs, const char *const *argnames,
                      const jschar *chars, size_t length,
-                     const char *filename, unsigned lineno)
-{
-    RootedObject obj(cx, objArg);
-    CompileOptions options(cx);
-    options.setFileAndLine(filename, lineno);
-
+                     const CompileOptions &options)
+{
     return CompileFunction(cx, obj, options, name, nargs, argnames, chars, length);
 }
 
 JS_PUBLIC_API(JSFunction *)
-JS_CompileFunctionForPrincipals(JSContext *cx, JSObject *objArg,
-                                JSPrincipals *principals, const char *name,
-                                unsigned nargs, const char *const *argnames,
-                                const char *ascii, size_t length,
-                                const char *filename, unsigned lineno)
-{
-    RootedObject obj(cx, objArg);
-    CompileOptions options(cx);
-    options.setPrincipals(principals)
-           .setFileAndLine(filename, lineno);
-
-    return CompileFunction(cx, obj, options, name, nargs, argnames, ascii, length);
-}
-
-JS_PUBLIC_API(JSFunction *)
-JS_CompileFunction(JSContext *cx, JSObject *objArg, const char *name,
+JS_CompileFunction(JSContext *cx, JS::HandleObject obj, const char *name,
                    unsigned nargs, const char *const *argnames,
                    const char *ascii, size_t length,
-                   const char *filename, unsigned lineno)
-{
-    RootedObject obj(cx, objArg);
-    CompileOptions options(cx);
-    options.setFileAndLine(filename, lineno);
-
+                   const JS::CompileOptions &options)
+{
     return CompileFunction(cx, obj, options, name, nargs, argnames, ascii, length);
 }
 
 JS_PUBLIC_API(JSString *)
 JS_DecompileScript(JSContext *cx, JSScript *scriptArg, const char *name, unsigned indent)
 {
     JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
 
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1442,17 +1442,16 @@ namespace JS {
 
 class JS_PUBLIC_API(ContextOptions) {
   public:
     ContextOptions()
       : extraWarnings_(false),
         werror_(false),
         varObjFix_(false),
         privateIsNSISupports_(false),
-        compileAndGo_(false),
         dontReportUncaught_(false),
         noDefaultCompartmentObject_(false),
         noScriptRval_(false),
         strictMode_(false),
         baseline_(false),
         typeInference_(false),
         ion_(false),
         asmJS_(false)
@@ -1494,26 +1493,16 @@ class JS_PUBLIC_API(ContextOptions) {
         privateIsNSISupports_ = flag;
         return *this;
     }
     ContextOptions &togglePrivateIsNSISupports() {
         privateIsNSISupports_ = !privateIsNSISupports_;
         return *this;
     }
 
-    bool compileAndGo() const { return compileAndGo_; }
-    ContextOptions &setCompileAndGo(bool flag) {
-        compileAndGo_ = flag;
-        return *this;
-    }
-    ContextOptions &toggleCompileAndGo() {
-        compileAndGo_ = !compileAndGo_;
-        return *this;
-    }
-
     bool dontReportUncaught() const { return dontReportUncaught_; }
     ContextOptions &setDontReportUncaught(bool flag) {
         dontReportUncaught_ = flag;
         return *this;
     }
     ContextOptions &toggleDontReportUncaught() {
         dontReportUncaught_ = !dontReportUncaught_;
         return *this;
@@ -1589,17 +1578,16 @@ class JS_PUBLIC_API(ContextOptions) {
         return *this;
     }
 
   private:
     bool extraWarnings_ : 1;
     bool werror_ : 1;
     bool varObjFix_ : 1;
     bool privateIsNSISupports_ : 1;
-    bool compileAndGo_ : 1;
     bool dontReportUncaught_ : 1;
     bool noDefaultCompartmentObject_ : 1;
     bool noScriptRval_ : 1;
     bool strictMode_ : 1;
     bool baseline_ : 1;
     bool typeInference_ : 1;
     bool ion_ : 1;
     bool asmJS_ : 1;
@@ -3328,58 +3316,39 @@ JS_CloneFunctionObject(JSContext *cx, JS
  * true.  The intent is to support interactive compilation - accumulate
  * lines in a buffer until JS_BufferIsCompilableUnit is true, then pass it to
  * the compiler.
  */
 extern JS_PUBLIC_API(bool)
 JS_BufferIsCompilableUnit(JSContext *cx, JSObject *obj, const char *utf8, size_t length);
 
 extern JS_PUBLIC_API(JSScript *)
-JS_CompileScript(JSContext *cx, JSObject *obj,
+JS_CompileScript(JSContext *cx, JS::HandleObject obj,
                  const char *ascii, size_t length,
-                 const char *filename, unsigned lineno);
+                 const JS::CompileOptions &options);
 
 extern JS_PUBLIC_API(JSScript *)
-JS_CompileScriptForPrincipals(JSContext *cx, JSObject *obj,
-                              JSPrincipals *principals,
-                              const char *ascii, size_t length,
-                              const char *filename, unsigned lineno);
-
-extern JS_PUBLIC_API(JSScript *)
-JS_CompileUCScript(JSContext *cx, JSObject *obj,
+JS_CompileUCScript(JSContext *cx, JS::HandleObject obj,
                    const jschar *chars, size_t length,
-                   const char *filename, unsigned lineno);
-
-extern JS_PUBLIC_API(JSScript *)
-JS_CompileUCScriptForPrincipals(JSContext *cx, JSObject *obj,
-                                JSPrincipals *principals,
-                                const jschar *chars, size_t length,
-                                const char *filename, unsigned lineno);
+                   const JS::CompileOptions &options);
 
 extern JS_PUBLIC_API(JSObject *)
 JS_GetGlobalFromScript(JSScript *script);
 
 extern JS_PUBLIC_API(JSFunction *)
-JS_CompileFunction(JSContext *cx, JSObject *obj, const char *name,
+JS_CompileFunction(JSContext *cx, JS::HandleObject obj, const char *name,
                    unsigned nargs, const char *const *argnames,
                    const char *bytes, size_t length,
-                   const char *filename, unsigned lineno);
+                   const JS::CompileOptions &options);
 
 extern JS_PUBLIC_API(JSFunction *)
-JS_CompileFunctionForPrincipals(JSContext *cx, JSObject *obj,
-                                JSPrincipals *principals, const char *name,
-                                unsigned nargs, const char *const *argnames,
-                                const char *bytes, size_t length,
-                                const char *filename, unsigned lineno);
-
-extern JS_PUBLIC_API(JSFunction *)
-JS_CompileUCFunction(JSContext *cx, JSObject *obj, const char *name,
+JS_CompileUCFunction(JSContext *cx, JS::HandleObject obj, const char *name,
                      unsigned nargs, const char *const *argnames,
                      const jschar *chars, size_t length,
-                     const char *filename, unsigned lineno);
+                     const JS::CompileOptions &options);
 
 namespace JS {
 
 /* Options for JavaScript compilation. */
 
 /*
  * In the most common use case, a CompileOptions instance is allocated on the
  * stack, and holds non-owning references to non-POD option values: strings;
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -896,17 +896,17 @@ JS::NotifyDidPaint(JSRuntime *rt)
     }
 
     rt->gcInterFrameGC = false;
 }
 
 JS_FRIEND_API(bool)
 JS::IsIncrementalGCEnabled(JSRuntime *rt)
 {
-    return rt->gcIncrementalEnabled && rt->gcMode == JSGC_MODE_INCREMENTAL;
+    return rt->gcIncrementalEnabled && rt->gcMode() == JSGC_MODE_INCREMENTAL;
 }
 
 JS_FRIEND_API(bool)
 JS::IsIncrementalGCInProgress(JSRuntime *rt)
 {
     return (rt->gcIncrementalState != gc::NO_INCREMENTAL && !rt->gcVerifyPreData);
 }
 
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -1671,19 +1671,19 @@ GCMarker::GCMarker(JSRuntime *rt)
     unmarkedArenaStackTop(nullptr),
     markLaterArenas(0),
     grayFailed(false)
 {
     InitTracer(this, rt, nullptr);
 }
 
 bool
-GCMarker::init()
-{
-    return stack.init(MARK_STACK_LENGTH);
+GCMarker::init(JSGCMode gcMode)
+{
+    return stack.init(gcMode);
 }
 
 void
 GCMarker::start()
 {
     JS_ASSERT(!started);
     started = true;
     color = BLACK;
@@ -1932,17 +1932,17 @@ GCMarker::sizeOfExcludingThis(mozilla::M
         size += zone->gcGrayRoots.sizeOfExcludingThis(mallocSizeOf);
     return size;
 }
 
 void
 js::SetMarkStackLimit(JSRuntime *rt, size_t limit)
 {
     JS_ASSERT(!rt->isHeapBusy());
-    rt->gcMarker.setSizeLimit(limit);
+    rt->gcMarker.setMaxCapacity(limit);
 }
 
 void
 js::MarkCompartmentActive(StackFrame *fp)
 {
     fp->script()->compartment()->zone()->active = true;
 }
 
@@ -4545,17 +4545,17 @@ BudgetIncrementalGC(JSRuntime *rt, int64
     IncrementalSafety safe = IsIncrementalGCSafe(rt);
     if (!safe) {
         ResetIncrementalGC(rt, safe.reason());
         *budget = SliceBudget::Unlimited;
         rt->gcStats.nonincremental(safe.reason());
         return;
     }
 
-    if (rt->gcMode != JSGC_MODE_INCREMENTAL) {
+    if (rt->gcMode() != JSGC_MODE_INCREMENTAL) {
         ResetIncrementalGC(rt, "GC mode change");
         *budget = SliceBudget::Unlimited;
         rt->gcStats.nonincremental("GC mode");
         return;
     }
 
     if (rt->isTooMuchMalloc()) {
         *budget = SliceBudget::Unlimited;
@@ -4736,17 +4736,17 @@ Collect(JSRuntime *rt, bool incremental,
     AutoDisableStoreBuffer adsb(rt);
 
     RecordNativeStackTopForGC(rt);
 
     int zoneCount = 0;
     int compartmentCount = 0;
     int collectedCount = 0;
     for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
-        if (rt->gcMode == JSGC_MODE_GLOBAL)
+        if (rt->gcMode() == JSGC_MODE_GLOBAL)
             zone->scheduleGC();
 
         /* This is a heuristic to avoid resets. */
         if (rt->gcIncrementalState != NO_INCREMENTAL && zone->needsBarrier())
             zone->scheduleGC();
 
         zoneCount++;
         if (zone->isGCScheduled())
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -903,150 +903,166 @@ struct GCChunkHasher {
         JS_ASSERT(!(uintptr_t(k) & gc::ChunkMask));
         JS_ASSERT(!(uintptr_t(l) & gc::ChunkMask));
         return k == l;
     }
 };
 
 typedef HashSet<js::gc::Chunk *, GCChunkHasher, SystemAllocPolicy> GCChunkSet;
 
+static const size_t NON_INCREMENTAL_MARK_STACK_BASE_CAPACITY = 4096;
+static const size_t INCREMENTAL_MARK_STACK_BASE_CAPACITY = 32768;
+
 template<class T>
 struct MarkStack {
-    T *stack;
-    T *tos;
-    T *limit;
+    T *stack_;
+    T *tos_;
+    T *end_;
 
-    T *ballast;
-    T *ballastLimit;
+    // The capacity we start with and reset() to.
+    size_t baseCapacity_;
+    size_t maxCapacity_;
 
-    size_t sizeLimit;
-
-    MarkStack(size_t sizeLimit)
-      : stack(nullptr),
-        tos(nullptr),
-        limit(nullptr),
-        ballast(nullptr),
-        ballastLimit(nullptr),
-        sizeLimit(sizeLimit) { }
+    MarkStack(size_t maxCapacity)
+      : stack_(nullptr),
+        tos_(nullptr),
+        end_(nullptr),
+        baseCapacity_(0),
+        maxCapacity_(maxCapacity)
+    {}
 
     ~MarkStack() {
-        if (stack != ballast)
-            js_free(stack);
-        js_free(ballast);
+        js_free(stack_);
+    }
+
+    size_t capacity() { return end_ - stack_; }
+
+    ptrdiff_t position() const { return tos_ - stack_; }
+
+    void setStack(T *stack, size_t tosIndex, size_t capacity) {
+        stack_ = stack;
+        tos_ = stack + tosIndex;
+        end_ = stack + capacity;
     }
 
-    bool init(size_t ballastcap) {
-        JS_ASSERT(!stack);
-
-        if (ballastcap == 0)
-            return true;
+    void setBaseCapacity(JSGCMode mode) {
+        switch (mode) {
+          case JSGC_MODE_GLOBAL:
+          case JSGC_MODE_COMPARTMENT:
+            baseCapacity_ = NON_INCREMENTAL_MARK_STACK_BASE_CAPACITY;
+            break;
+          case JSGC_MODE_INCREMENTAL:
+            baseCapacity_ = INCREMENTAL_MARK_STACK_BASE_CAPACITY;
+            break;
+          default:
+            MOZ_ASSUME_UNREACHABLE("bad gc mode");
+        }
 
-        ballast = js_pod_malloc<T>(ballastcap);
-        if (!ballast)
+        if (baseCapacity_ > maxCapacity_)
+            baseCapacity_ = maxCapacity_;
+    }
+
+    bool init(JSGCMode gcMode) {
+        setBaseCapacity(gcMode);
+
+        JS_ASSERT(!stack_);
+        T *newStack = js_pod_malloc<T>(baseCapacity_);
+        if (!newStack)
             return false;
-        ballastLimit = ballast + ballastcap;
-        initFromBallast();
+
+        setStack(newStack, 0, baseCapacity_);
         return true;
     }
 
-    void initFromBallast() {
-        stack = ballast;
-        limit = ballastLimit;
-        if (size_t(limit - stack) > sizeLimit)
-            limit = stack + sizeLimit;
-        tos = stack;
-    }
+    void setMaxCapacity(size_t maxCapacity) {
+        JS_ASSERT(isEmpty());
+        maxCapacity_ = maxCapacity;
+        if (baseCapacity_ > maxCapacity_)
+            baseCapacity_ = maxCapacity_;
 
-    void setSizeLimit(size_t size) {
-        JS_ASSERT(isEmpty());
-
-        sizeLimit = size;
         reset();
     }
 
     bool push(T item) {
-        if (tos == limit) {
+        if (tos_ == end_) {
             if (!enlarge())
                 return false;
         }
-        JS_ASSERT(tos < limit);
-        *tos++ = item;
+        JS_ASSERT(tos_ < end_);
+        *tos_++ = item;
         return true;
     }
 
     bool push(T item1, T item2, T item3) {
-        T *nextTos = tos + 3;
-        if (nextTos > limit) {
+        T *nextTos = tos_ + 3;
+        if (nextTos > end_) {
             if (!enlarge())
                 return false;
-            nextTos = tos + 3;
+            nextTos = tos_ + 3;
         }
-        JS_ASSERT(nextTos <= limit);
-        tos[0] = item1;
-        tos[1] = item2;
-        tos[2] = item3;
-        tos = nextTos;
+        JS_ASSERT(nextTos <= end_);
+        tos_[0] = item1;
+        tos_[1] = item2;
+        tos_[2] = item3;
+        tos_ = nextTos;
         return true;
     }
 
     bool isEmpty() const {
-        return tos == stack;
+        return tos_ == stack_;
     }
 
     T pop() {
         JS_ASSERT(!isEmpty());
-        return *--tos;
-    }
-
-    ptrdiff_t position() const {
-        return tos - stack;
+        return *--tos_;
     }
 
     void reset() {
-        if (stack != ballast)
-            js_free(stack);
-        initFromBallast();
-        JS_ASSERT(stack == ballast);
+        if (capacity() == baseCapacity_) {
+            // No size change; keep the current stack.
+            setStack(stack_, 0, baseCapacity_);
+            return;
+        }
+
+        T *newStack = (T *)js_realloc(stack_, sizeof(T) * baseCapacity_);
+        if (!newStack) {
+            // If the realloc fails, just keep using the existing stack; it's
+            // not ideal but better than failing.
+            newStack = stack_;
+            baseCapacity_ = capacity();
+        }
+        setStack(newStack, 0, baseCapacity_);
     }
 
     bool enlarge() {
-        size_t tosIndex = tos - stack;
-        size_t cap = limit - stack;
-        if (cap == sizeLimit)
+        if (capacity() == maxCapacity_)
             return false;
-        size_t newcap = cap * 2;
-        if (newcap == 0)
-            newcap = 32;
-        if (newcap > sizeLimit)
-            newcap = sizeLimit;
+
+        size_t newCapacity = capacity() * 2;
+        if (newCapacity > maxCapacity_)
+            newCapacity = maxCapacity_;
 
-        T *newStack;
-        if (stack == ballast) {
-            newStack = js_pod_malloc<T>(newcap);
-            if (!newStack)
-                return false;
-            for (T *src = stack, *dst = newStack; src < tos; )
-                *dst++ = *src++;
-        } else {
-            newStack = (T *)js_realloc(stack, sizeof(T) * newcap);
-            if (!newStack)
-                return false;
-        }
-        stack = newStack;
-        tos = stack + tosIndex;
-        limit = newStack + newcap;
+        size_t tosIndex = position();
+
+        T *newStack = (T *)js_realloc(stack_, sizeof(T) * newCapacity);
+        if (!newStack)
+            return false;
+
+        setStack(newStack, tosIndex, newCapacity);
         return true;
     }
 
+    void setGCMode(JSGCMode gcMode) {
+        // The mark stack won't be resized until the next call to reset(), but
+        // that will happen at the end of the next GC.
+        setBaseCapacity(gcMode);
+    }
+
     size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
-        size_t n = 0;
-        if (stack != ballast)
-            n += mallocSizeOf(stack);
-        n += mallocSizeOf(ballast);
-        return n;
+        return mallocSizeOf(stack_);
     }
 };
 
 /*
  * This class records how much work has been done in a given GC slice, so that
  * we can return before pausing for too long. Some slices are allowed to run for
  * unlimited time, and others are bounded. To reduce the number of gettimeofday
  * calls, we only check the time every 1000 operations.
@@ -1080,18 +1096,16 @@ struct SliceBudget {
 
     bool isOverBudget() {
         if (counter >= 0)
             return false;
         return checkOverBudget();
     }
 };
 
-static const size_t MARK_STACK_LENGTH = 32768;
-
 struct GrayRoot {
     void *thing;
     JSGCTraceKind kind;
 #ifdef DEBUG
     JSTraceNamePrinter debugPrinter;
     const void *debugPrintArg;
     size_t debugPrintIndex;
 #endif
@@ -1122,20 +1136,20 @@ struct GCMarker : public JSTracer {
 
     static void staticAsserts() {
         JS_STATIC_ASSERT(StackTagMask >= uintptr_t(LastTag));
         JS_STATIC_ASSERT(StackTagMask <= gc::CellMask);
     }
 
   public:
     explicit GCMarker(JSRuntime *rt);
-    bool init();
+    bool init(JSGCMode gcMode);
 
-    void setSizeLimit(size_t size) { stack.setSizeLimit(size); }
-    size_t sizeLimit() const { return stack.sizeLimit; }
+    void setMaxCapacity(size_t maxCap) { stack.setMaxCapacity(maxCap); }
+    size_t maxCapacity() const { return stack.maxCapacity_; }
 
     void start();
     void stop();
     void reset();
 
     void pushObject(ObjectImpl *obj) {
         pushTaggedPtr(ObjectTag, obj);
     }
@@ -1201,16 +1215,18 @@ struct GCMarker : public JSTracer {
     bool hasBufferedGrayRoots() const;
     void startBufferingGrayRoots();
     void endBufferingGrayRoots();
     void resetBufferedGrayRoots();
     void markBufferedGrayRoots(JS::Zone *zone);
 
     static void GrayCallback(JSTracer *trc, void **thing, JSGCTraceKind kind);
 
+    void setGCMode(JSGCMode mode) { stack.setGCMode(mode); }
+
     size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
 
     MarkStack<uintptr_t> stack;
 
   private:
 #ifdef DEBUG
     void checkZone(void *p);
 #else
--- a/js/src/jsmath.cpp
+++ b/js/src/jsmath.cpp
@@ -289,26 +289,25 @@ js::ecmaAtan2(double y, double x)
     return atan2(y, x);
 }
 
 bool
 js::math_atan2(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
-    if (args.length() <= 1) {
-        args.rval().setNaN();
-        return true;
-    }
-
-    double x, y;
-    if (!ToNumber(cx, args[0], &x) || !ToNumber(cx, args[1], &y))
+    double y;
+    if (!ToNumber(cx, args.get(0), &y))
         return false;
 
-    double z = ecmaAtan2(x, y);
+    double x;
+    if (!ToNumber(cx, args.get(1), &x))
+        return false;
+
+    double z = ecmaAtan2(y, x);
     args.rval().setDouble(z);
     return true;
 }
 
 double
 js::math_ceil_impl(double x)
 {
 #ifdef __APPLE__
@@ -635,23 +634,22 @@ js::ecmaPow(double x, double y)
 #if defined(_MSC_VER)
 # pragma optimize("g", off)
 #endif
 bool
 js_math_pow(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
-    if (args.length() <= 1) {
-        args.rval().setNaN();
-        return true;
-    }
+    double x;
+    if (!ToNumber(cx, args.get(0), &x))
+        return false;
 
-    double x, y;
-    if (!ToNumber(cx, args[0], &x) || !ToNumber(cx, args[1], &y))
+    double y;
+    if (!ToNumber(cx, args.get(1), &y))
         return false;
 
     /*
      * Special case for square roots. Note that pow(x, 0.5) != sqrt(x)
      * when x = -0.0, so we have to guard for this.
      */
     if (IsFinite(x) && x != 0.0) {
         if (y == 0.5) {
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -1296,17 +1296,17 @@ NewObject(ExclusiveContext *cx, const Cl
      */
     if (clasp->trace && !(clasp->flags & JSCLASS_IMPLEMENTS_BARRIERS)) {
         if (!cx->shouldBeJSContext())
             return nullptr;
         JSRuntime *rt = cx->asJSContext()->runtime();
         rt->gcIncrementalEnabled = false;
 
 #ifdef DEBUG
-        if (rt->gcMode == JSGC_MODE_INCREMENTAL) {
+        if (rt->gcMode() == JSGC_MODE_INCREMENTAL) {
             fprintf(stderr,
                     "The class %s has a trace hook but does not declare the\n"
                     "JSCLASS_IMPLEMENTS_BARRIERS flag. Please ensure that it correctly\n"
                     "implements write barriers and then set the flag.\n",
                     clasp->name);
             MOZ_CRASH();
         }
 #endif
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -2242,39 +2242,29 @@ js_LineNumberToPC(JSScript *script, unsi
 out:
     return script->code + offset;
 }
 
 JS_FRIEND_API(unsigned)
 js_GetScriptLineExtent(JSScript *script)
 {
     unsigned lineno = script->lineno;
-    unsigned maxLineNo = 0;
-    bool counting = true;
+    unsigned maxLineNo = lineno;
     for (jssrcnote *sn = script->notes(); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) {
         SrcNoteType type = (SrcNoteType) SN_TYPE(sn);
-        if (type == SRC_SETLINE) {
-            if (maxLineNo < lineno)
-                maxLineNo = lineno;
+        if (type == SRC_SETLINE)
             lineno = (unsigned) js_GetSrcNoteOffset(sn, 0);
-            counting = true;
-            if (maxLineNo < lineno)
-                maxLineNo = lineno;
-            else
-                counting = false;
-        } else if (type == SRC_NEWLINE) {
-            if (counting)
-                lineno++;
-        }
+        else if (type == SRC_NEWLINE)
+            lineno++;
+
+        if (maxLineNo < lineno)
+            maxLineNo = lineno;
     }
 
-    if (maxLineNo > lineno)
-        lineno = maxLineNo;
-
-    return 1 + lineno - script->lineno;
+    return 1 + maxLineNo - script->lineno;
 }
 
 void
 js::CurrentScriptFileLineOrigin(JSContext *cx, const char **file, unsigned *linenop,
                                 JSPrincipals **origin, LineOption opt)
 {
     if (opt == CALLED_FROM_JSOP_EVAL) {
         jsbytecode *pc = nullptr;
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -383,22 +383,22 @@ RunFile(JSContext *cx, Handle<JSObject*>
     }
     ungetc(ch, file);
 
     int64_t t1 = PRMJ_Now();
     RootedScript script(cx);
 
     {
         JS::AutoSaveContextOptions asco(cx);
-        JS::ContextOptionsRef(cx).setCompileAndGo(true)
-                                 .setNoScriptRval(true);
+        JS::ContextOptionsRef(cx).setNoScriptRval(true);
 
         CompileOptions options(cx);
         options.setUTF8(true)
-               .setFileAndLine(filename, 1);
+               .setFileAndLine(filename, 1)
+               .setCompileAndGo(true);
 
         gGotError = false;
         script = JS::Compile(cx, obj, options, file);
         JS_ASSERT_IF(!script, gGotError);
     }
 
     #ifdef DEBUG
         if (dumpEntrainedVariables)
@@ -1002,23 +1002,23 @@ Evaluate(JSContext *cx, unsigned argc, j
         if (saveFrameChain && !asfc.save())
             return false;
 
         JSAutoCompartment ac(cx, global);
         RootedScript script(cx);
 
         {
             JS::AutoSaveContextOptions asco(cx);
-            JS::ContextOptionsRef(cx).setCompileAndGo(compileAndGo)
-                                 .setNoScriptRval(noScriptRval);
+            JS::ContextOptionsRef(cx).setNoScriptRval(noScriptRval);
 
             CompileOptions options(cx);
             options.setFileAndLine(fileName, lineNumber)
                    .setElement(element)
-                   .setSourcePolicy(sourcePolicy);
+                   .setSourcePolicy(sourcePolicy)
+                   .setCompileAndGo(compileAndGo);
 
             script = JS::Compile(cx, global, options, codeChars, codeLength);
             if (!script)
                 return false;
         }
 
         if (sourceURL && !script->scriptSource()->hasSourceURL()) {
             const jschar *surl = JS_GetStringCharsZ(cx, sourceURL);
@@ -1165,20 +1165,22 @@ Run(JSContext *cx, unsigned argc, jsval 
         return false;
 
     JS::Anchor<JSString *> a_str(str);
 
     RootedScript script(cx);
     int64_t startClock = PRMJ_Now();
     {
         JS::AutoSaveContextOptions asco(cx);
-        JS::ContextOptionsRef(cx).setCompileAndGo(true)
-                                 .setNoScriptRval(true);
-
-        script = JS_CompileUCScript(cx, thisobj, ucbuf, buflen, filename.ptr(), 1);
+        JS::ContextOptionsRef(cx).setNoScriptRval(true);
+
+        JS::CompileOptions options(cx);
+        options.setFileAndLine(filename.ptr(), 1)
+               .setCompileAndGo(true);
+        script = JS_CompileUCScript(cx, thisobj, ucbuf, buflen, options);
         if (!script)
             return false;
     }
 
     if (!JS_ExecuteScript(cx, thisobj, script, nullptr))
         return false;
 
     int64_t endClock = PRMJ_Now();
@@ -2000,22 +2002,22 @@ DisassFile(JSContext *cx, unsigned argc,
         return false;
     JSAutoByteString filename(cx, str);
     if (!filename)
         return false;
     RootedScript script(cx);
 
     {
         JS::AutoSaveContextOptions asco(cx);
-        JS::ContextOptionsRef(cx).setCompileAndGo(true)
-                                 .setNoScriptRval(true);
+        JS::ContextOptionsRef(cx).setNoScriptRval(true);
 
         CompileOptions options(cx);
         options.setUTF8(true)
-               .setFileAndLine(filename.ptr(), 1);
+               .setFileAndLine(filename.ptr(), 1)
+               .setCompileAndGo(true);
 
         script = JS::Compile(cx, thisobj, options, filename.ptr());
         if (!script)
             return false;
     }
 
     Sprinter sprinter(cx);
     if (!sprinter.init())
@@ -3076,20 +3078,22 @@ Compile(JSContext *cx, unsigned argc, js
         const char *typeName = JS_GetTypeName(cx, JS_TypeOfValue(cx, arg0));
         JS_ReportError(cx, "expected string to compile, got %s", typeName);
         return false;
     }
 
     RootedObject global(cx, JS::CurrentGlobalOrNull(cx));
     JSString *scriptContents = JSVAL_TO_STRING(arg0);
     JS::AutoSaveContextOptions asco(cx);
-    JS::ContextOptionsRef(cx).setCompileAndGo(true)
-                              .setNoScriptRval(true);
+    JS::ContextOptionsRef(cx).setNoScriptRval(true);
+    JS::CompileOptions options(cx);
+    options.setFileAndLine("<string>", 1)
+           .setCompileAndGo(true);
     bool ok = JS_CompileUCScript(cx, global, JS_GetStringCharsZ(cx, scriptContents),
-                                 JS_GetStringLength(scriptContents), "<string>", 1);
+                                 JS_GetStringLength(scriptContents), options);
     JS_SET_RVAL(cx, vp, UndefinedValue());
     return ok;
 }
 
 static bool
 Parse(JSContext *cx, unsigned argc, jsval *vp)
 {
     using namespace js::frontend;
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/Math/20.2.2.ToNumber.js
@@ -0,0 +1,112 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ */
+
+/*
+ *   ECMA-262 6th Edition / Draft November 8, 2013
+ *
+ *   20.2.2 Function Properties of the Math Object
+ */
+
+/*
+ * This custom object will allow us to check if valueOf() is called
+ */
+
+TestNumber.prototype = new Number();
+
+function TestNumber(value) {
+    this.value = value;
+    this.valueOfCalled = false;
+}
+
+TestNumber.prototype = {
+    valueOf: function() {
+        this.valueOfCalled = true;
+        return this.value;
+    }
+}
+
+// Verify that each TestNumber's flag is set after calling Math func
+function test(func /*, args */) {
+    var args = Array.prototype.slice.call(arguments, 1);
+    func.apply(null, args);
+
+    for (var i = 0; i < args.length; ++i)
+        assertEq(args[i].valueOfCalled, true);
+}
+
+// Note that we are not testing these functions' return values
+// We only test whether valueOf() is called for each argument
+
+// 1. Test Math.atan2()
+var x = new TestNumber(1);
+test(Math.atan2, x);
+
+var x = new TestNumber(1);
+var y = new TestNumber(2);
+test(Math.atan2, y, x);
+
+// Remove comment block once patch for bug 896264 is approved
+/*
+// 2. Test Math.hypot()
+var x = new TestNumber(1);
+test(Math.hypot, x);
+
+var x = new TestNumber(1);
+var y = new TestNumber(2);
+test(Math.hypot, x, y);
+
+var x = new TestNumber(1);
+var y = new TestNumber(2);
+var z = new TestNumber(3);
+test(Math.hypot, x, y, z);
+*/
+
+// Remove comment block once patch for bug 808148 is approved
+/*
+// 3. Test Math.imul()
+var x = new TestNumber(1);
+test(Math.imul, x);
+
+var x = new TestNumber(1);
+var y = new TestNumber(2);
+test(Math.imul, x, y);
+*/
+
+// 4. Test Math.max()
+var x = new TestNumber(1);
+test(Math.max, x);
+
+var x = new TestNumber(1);
+var y = new TestNumber(2);
+test(Math.max, x, y);
+
+var x = new TestNumber(1);
+var y = new TestNumber(2);
+var z = new TestNumber(3);
+test(Math.max, x, y, z);
+
+// 5. Test Math.min()
+var x = new TestNumber(1);
+test(Math.min, x);
+
+var x = new TestNumber(1);
+var y = new TestNumber(2);
+test(Math.min, x, y);
+
+var x = new TestNumber(1);
+var y = new TestNumber(2);
+var z = new TestNumber(3);
+test(Math.min, x, y, z);
+
+// 6. Test Math.pow()
+var x = new TestNumber(1);
+test(Math.pow, x);
+
+var x = new TestNumber(1);
+var y = new TestNumber(2);
+test(Math.pow, x, y);
+
+reportCompare(0, 0, "ok");
+
--- a/js/src/vm/Runtime.cpp
+++ b/js/src/vm/Runtime.cpp
@@ -163,17 +163,16 @@ JSRuntime::JSRuntime(JSUseHelperThreads 
     gcNumArenasFreeCommitted(0),
     gcMarker(this),
     gcVerifyPreData(nullptr),
     gcVerifyPostData(nullptr),
     gcChunkAllocationSinceLastGC(false),
     gcNextFullGCTime(0),
     gcLastGCTime(0),
     gcJitReleaseTime(0),
-    gcMode(JSGC_MODE_GLOBAL),
     gcAllocationThreshold(30 * 1024 * 1024),
     gcHighFrequencyGC(false),
     gcHighFrequencyTimeThreshold(1000),
     gcHighFrequencyLowLimitBytes(100 * 1024 * 1024),
     gcHighFrequencyHighLimitBytes(500 * 1024 * 1024),
     gcHighFrequencyHeapGrowthMax(3.0),
     gcHighFrequencyHeapGrowthMin(1.5),
     gcLowFrequencyHeapGrowth(1.5),
@@ -289,16 +288,18 @@ JSRuntime::JSRuntime(JSUseHelperThreads 
     useHelperThreadsForIonCompilation_(true),
     useHelperThreadsForParsing_(true)
 #ifdef DEBUG
     , enteredPolicy(nullptr)
 #endif
 {
     liveRuntimesCount++;
 
+    setGCMode(JSGC_MODE_GLOBAL);
+
     /* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */
     JS_INIT_CLIST(&onNewGlobalObjectWatchers);
 
     PodZero(&debugHooks);
     PodZero(&atomState);
     PodArrayZero(nativeStackQuota);
     PodZero(&asmJSCacheOps);
 
@@ -350,17 +351,17 @@ JSRuntime::init(uint32_t maxbytes)
         return false;
 
     js::TlsPerThreadData.set(&mainThread);
     mainThread.addToThreadList();
 
     if (!js_InitGC(this, maxbytes))
         return false;
 
-    if (!gcMarker.init())
+    if (!gcMarker.init(gcMode()))
         return false;
 
     const char *size = getenv("JSGC_MARK_STACK_LIMIT");
     if (size)
         SetMarkStackLimit(this, atoi(size));
 
     ScopedJSDeletePtr<Zone> atomsZone(new_<Zone>(this));
     if (!atomsZone)
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -1010,17 +1010,26 @@ struct JSRuntime : public JS::shadow::Ru
     mozilla::Atomic<uint32_t, mozilla::ReleaseAcquire> gcNumArenasFreeCommitted;
     js::GCMarker        gcMarker;
     void                *gcVerifyPreData;
     void                *gcVerifyPostData;
     bool                gcChunkAllocationSinceLastGC;
     int64_t             gcNextFullGCTime;
     int64_t             gcLastGCTime;
     int64_t             gcJitReleaseTime;
-    JSGCMode            gcMode;
+  private:
+    JSGCMode            gcMode_;
+
+  public:
+    JSGCMode gcMode() const { return gcMode_; }
+    void setGCMode(JSGCMode mode) {
+        gcMode_ = mode;
+        gcMarker.setGCMode(mode);
+    }
+
     size_t              gcAllocationThreshold;
     bool                gcHighFrequencyGC;
     uint64_t            gcHighFrequencyTimeThreshold;
     uint64_t            gcHighFrequencyLowLimitBytes;
     uint64_t            gcHighFrequencyHighLimitBytes;
     double              gcHighFrequencyHeapGrowthMax;
     double              gcHighFrequencyHeapGrowthMin;
     double              gcLowFrequencyHeapGrowth;
--- a/js/xpconnect/loader/mozJSComponentLoader.cpp
+++ b/js/xpconnect/loader/mozJSComponentLoader.cpp
@@ -27,17 +27,16 @@
 #include "mozilla/Module.h"
 #include "nsIFile.h"
 #include "mozJSComponentLoader.h"
 #include "mozJSLoaderUtils.h"
 #include "nsIJSRuntimeService.h"
 #include "nsIXPConnect.h"
 #include "nsIObserverService.h"
 #include "nsIScriptSecurityManager.h"
-#include "nsIURI.h"
 #include "nsIFileURL.h"
 #include "nsIJARURI.h"
 #include "nsNetUtil.h"
 #include "nsDOMBlobBuilder.h"
 #include "jsprf.h"
 #include "nsJSPrincipals.h"
 #include "xpcprivate.h"
 #include "xpcpublic.h"
--- a/js/xpconnect/loader/mozJSComponentLoader.h
+++ b/js/xpconnect/loader/mozJSComponentLoader.h
@@ -2,16 +2,17 @@
  *
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/ModuleLoader.h"
 #include "nsISupports.h"
 #include "nsIObserver.h"
+#include "nsIURI.h"
 #include "xpcIJSModuleLoader.h"
 #include "nsClassHashtable.h"
 #include "nsDataHashtable.h"
 #include "jsapi.h"
 
 #include "xpcIJSGetFactory.h"
 
 class nsIFile;
--- a/js/xpconnect/src/XPCShellImpl.cpp
+++ b/js/xpconnect/src/XPCShellImpl.cpp
@@ -941,18 +941,20 @@ ProcessFile(JSContext *cx, JS::Handle<JS
             }
             bufp += strlen(bufp);
             lineno++;
         } while (!JS_BufferIsCompilableUnit(cx, obj, buffer, strlen(buffer)));
 
         DoBeginRequest(cx);
         /* Clear any pending exception from previous failed compiles.  */
         JS_ClearPendingException(cx);
-        script = JS_CompileScriptForPrincipals(cx, obj, gJSPrincipals, buffer,
-                                               strlen(buffer), "typein", startline);
+        JS::CompileOptions options(cx);
+        options.setFileAndLine("typein", startline)
+               .setPrincipals(gJSPrincipals);
+        script = JS_CompileScript(cx, obj, buffer, strlen(buffer), options);
         if (script) {
             JSErrorReporter older;
 
             if (!compileOnly) {
                 ok = JS_ExecuteScript(cx, obj, script, result.address());
                 if (ok && result != JSVAL_VOID) {
                     /* Suppress error reports from JS::ToString(). */
                     older = JS_SetErrorReporter(cx, nullptr);
@@ -1018,18 +1020,17 @@ ProcessArgsForCompartment(JSContext *cx,
                 return;
             break;
         case 'S':
             ContextOptionsRef(cx).toggleWerror();
         case 's':
             ContextOptionsRef(cx).toggleExtraWarnings();
             break;
         case 'I':
-            ContextOptionsRef(cx).toggleCompileAndGo()
-                                 .toggleIon()
+            ContextOptionsRef(cx).toggleIon()
                                  .toggleAsmJS();
             break;
         case 'n':
             ContextOptionsRef(cx).toggleTypeInference();
             break;
         }
     }
 }
--- a/layout/base/nsFrameManager.cpp
+++ b/layout/base/nsFrameManager.cpp
@@ -60,17 +60,17 @@ PlaceholderMapMatchEntry(PLDHashTable *t
   const PlaceholderMapEntry *entry =
     static_cast<const PlaceholderMapEntry*>(hdr);
   NS_ASSERTION(entry->placeholderFrame->GetOutOfFlowFrame() !=
                (void*)0xdddddddd,
                "Dead placeholder in placeholder map");
   return entry->placeholderFrame->GetOutOfFlowFrame() == key;
 }
 
-static PLDHashTableOps PlaceholderMapOps = {
+static const PLDHashTableOps PlaceholderMapOps = {
   PL_DHashAllocTable,
   PL_DHashFreeTable,
   PL_DHashVoidPtrKeyStub,
   PlaceholderMapMatchEntry,
   PL_DHashMoveEntryStub,
   PL_DHashClearEntryStub,
   PL_DHashFinalizeStub,
   nullptr
--- a/layout/mathml/nsMathMLmpaddedFrame.cpp
+++ b/layout/mathml/nsMathMLmpaddedFrame.cpp
@@ -261,35 +261,35 @@ nsMathMLmpaddedFrame::ParseAttribute(nsS
   aSign = NS_MATHML_SIGN_INVALID;
   return false;
 }
 
 void
 nsMathMLmpaddedFrame::UpdateValue(int32_t                  aSign,
                                   int32_t                  aPseudoUnit,
                                   const nsCSSValue&        aCSSValue,
-                                  const nsBoundingMetrics& aBoundingMetrics,
+                                  const nsHTMLReflowMetrics& aDesiredSize,
                                   nscoord&                 aValueToUpdate) const
 {
   nsCSSUnit unit = aCSSValue.GetUnit();
   if (NS_MATHML_SIGN_INVALID != aSign && eCSSUnit_Null != unit) {
     nscoord scaler = 0, amount = 0;
 
     if (eCSSUnit_Percent == unit || eCSSUnit_Number == unit) {
       switch(aPseudoUnit) {
         case NS_MATHML_PSEUDO_UNIT_WIDTH:
-             scaler = aBoundingMetrics.width;
+             scaler = aDesiredSize.width;
              break;
 
         case NS_MATHML_PSEUDO_UNIT_HEIGHT:
-             scaler = aBoundingMetrics.ascent;
+             scaler = aDesiredSize.ascent;
              break;
 
         case NS_MATHML_PSEUDO_UNIT_DEPTH:
-             scaler = aBoundingMetrics.descent;
+             scaler = aDesiredSize.height - aDesiredSize.ascent;
              break;
 
         default:
           // if we ever reach here, it would mean something is wrong 
           // somewhere with the setup and/or the caller
           NS_ERROR("Unexpected Pseudo Unit");
           return;
       }
@@ -334,18 +334,18 @@ nsMathMLmpaddedFrame::Place(nsRenderingC
 {
   nsresult rv =
     nsMathMLContainerFrame::Place(aRenderingContext, false, aDesiredSize);
   if (NS_MATHML_HAS_ERROR(mPresentationData.flags) || NS_FAILED(rv)) {
     DidReflowChildren(GetFirstPrincipalChild());
     return rv;
   }
 
-  nscoord height = mBoundingMetrics.ascent;
-  nscoord depth  = mBoundingMetrics.descent;
+  nscoord height = aDesiredSize.ascent;
+  nscoord depth  = aDesiredSize.height - aDesiredSize.ascent;
   // The REC says:
   //
   // "The lspace attribute ('leading' space) specifies the horizontal location
   // of the positioning point of the child content with respect to the
   // positioning point of the mpadded element. By default they coincide, and
   // therefore absolute values for lspace have the same effect as relative
   // values."
   //
@@ -361,55 +361,55 @@ nsMathMLmpaddedFrame::Place(nsRenderingC
   // a side of an object when which side to use depends on the directionality;
   // ie. leading means left in LTR but right in RTL."
   // (http://www.w3.org/TR/MathML/chapter3.html#presm.bidi.math)
   nscoord lspace = 0;
   // In MathML3, "width" will be the bounding box width and "advancewidth" will
   // refer "to the horizontal distance between the positioning point of the
   // mpadded and the positioning point for the following content".  MathML2
   // doesn't make the distinction.
-  nscoord width  = mBoundingMetrics.width;
+  nscoord width  = aDesiredSize.width;
   nscoord voffset = 0;
 
   int32_t pseudoUnit;
   nscoord initialWidth = width;
 
   // update width
   pseudoUnit = (mWidthPseudoUnit == NS_MATHML_PSEUDO_UNIT_ITSELF)
              ? NS_MATHML_PSEUDO_UNIT_WIDTH : mWidthPseudoUnit;
   UpdateValue(mWidthSign, pseudoUnit, mWidth,
-              mBoundingMetrics, width);
+              aDesiredSize, width);
   width = std::max(0, width);
 
   // update "height" (this is the ascent in the terminology of the REC)
   pseudoUnit = (mHeightPseudoUnit == NS_MATHML_PSEUDO_UNIT_ITSELF)
              ? NS_MATHML_PSEUDO_UNIT_HEIGHT : mHeightPseudoUnit;
   UpdateValue(mHeightSign, pseudoUnit, mHeight,
-              mBoundingMetrics, height);
+              aDesiredSize, height);
   height = std::max(0, height);
 
   // update "depth" (this is the descent in the terminology of the REC)
   pseudoUnit = (mDepthPseudoUnit == NS_MATHML_PSEUDO_UNIT_ITSELF)
              ? NS_MATHML_PSEUDO_UNIT_DEPTH : mDepthPseudoUnit;
   UpdateValue(mDepthSign, pseudoUnit, mDepth,
-              mBoundingMetrics, depth);
+              aDesiredSize, depth);
   depth = std::max(0, depth);
 
   // update lspace
   if (mLeadingSpacePseudoUnit != NS_MATHML_PSEUDO_UNIT_ITSELF) {
     pseudoUnit = mLeadingSpacePseudoUnit;
     UpdateValue(mLeadingSpaceSign, pseudoUnit, mLeadingSpace,
-                mBoundingMetrics, lspace);
+                aDesiredSize, lspace);
   }
 
   // update voffset
   if (mVerticalOffsetPseudoUnit != NS_MATHML_PSEUDO_UNIT_ITSELF) {
     pseudoUnit = mVerticalOffsetPseudoUnit;
     UpdateValue(mVerticalOffsetSign, pseudoUnit, mVerticalOffset,
-                mBoundingMetrics, voffset);
+                aDesiredSize, voffset);
   }
   // do the padding now that we have everything
   // The idea here is to maintain the invariant that <mpadded>...</mpadded> (i.e.,
   // with no attributes) looks the same as <mrow>...</mrow>. But when there are
   // attributes, tweak our metrics and move children to achieve the desired visual
   // effects.
 
   if ((StyleVisibility()->mDirection ?
@@ -422,23 +422,22 @@ nsMathMLmpaddedFrame::Place(nsRenderingC
   if ((StyleVisibility()->mDirection ?
        mLeadingSpaceSign : mWidthSign) != NS_MATHML_SIGN_INVALID) {
     // there was padding on the right. dismiss the right italic correction now
     // (so that our parent won't correct us)
     mBoundingMetrics.width = width;
     mBoundingMetrics.rightBearing = mBoundingMetrics.width;
   }
 
-  nscoord dy = height - mBoundingMetrics.ascent;
   nscoord dx = (StyleVisibility()->mDirection ?
                 width - initialWidth - lspace : lspace);
     
-  aDesiredSize.ascent += dy;
+  aDesiredSize.ascent = height;
   aDesiredSize.width = mBoundingMetrics.width;
-  aDesiredSize.height += dy + depth - mBoundingMetrics.descent;
+  aDesiredSize.height = depth + aDesiredSize.ascent;
   mBoundingMetrics.ascent = height;
   mBoundingMetrics.descent = depth;
   aDesiredSize.mBoundingMetrics = mBoundingMetrics;
 
   mReference.x = 0;
   mReference.y = aDesiredSize.ascent;
 
   if (aPlaceOrigin) {
--- a/layout/mathml/nsMathMLmpaddedFrame.h
+++ b/layout/mathml/nsMathMLmpaddedFrame.h
@@ -74,13 +74,13 @@ private:
                  int32_t&    aSign,
                  nsCSSValue& aCSSValue,
                  int32_t&    aPseudoUnit);
 
   void
   UpdateValue(int32_t                  aSign,
               int32_t                  aPseudoUnit,
               const nsCSSValue&        aCSSValue,
-              const nsBoundingMetrics& aBoundingMetrics,
+              const nsHTMLReflowMetrics& aDesiredSize,
               nscoord&                 aValueToUpdate) const;
 };
 
 #endif /* nsMathMLmpaddedFrame_h___ */
--- a/layout/media/symbols.def.in
+++ b/layout/media/symbols.def.in
@@ -481,16 +481,40 @@ MOZ_XML_StopParser
 _moz_cairo_win32_surface_get_image
 #ifdef MOZ_TREE_PIXMAN
 _moz_pixman_image_composite32
 _moz_pixman_image_create_bits
 _moz_pixman_image_set_transform
 _moz_pixman_image_unref
 _moz_pixman_transform_from_pixman_f_transform
 _moz_pixman_transform_invert
+_moz_pixman_region32_reset
+_moz_pixman_region32_init
+_moz_pixman_region32_init_rect
+_moz_pixman_region32_init_rects
+_moz_pixman_region32_init_with_extents
+_moz_pixman_region32_fini
+_moz_pixman_region32_translate
+_moz_pixman_region32_copy
+_moz_pixman_region32_intersect
+_moz_pixman_region32_intersect_rect
+_moz_pixman_region32_union
+_moz_pixman_region32_union_rect
+_moz_pixman_region32_subtract
+_moz_pixman_region32_inverse
+_moz_pixman_region32_contains_point
+_moz_pixman_region32_contains_rectangle
+_moz_pixman_region32_not_empty
+_moz_pixman_region32_extents
+_moz_pixman_region32_n_rects
+_moz_pixman_region32_rectangles
+_moz_pixman_region32_equal
+_moz_pixman_region32_selfcheck
+_moz_pixman_region32_reset
+_moz_pixman_region32_clear
 #endif
 cairo_d2d_create_device
 cairo_d2d_create_device_from_d3d10device
 cairo_d2d_device_get_device
 cairo_d2d_get_dc
 cairo_d2d_get_image_surface_cache_usage
 cairo_d2d_get_surface_vram_usage
 cairo_d2d_present_backbuffer
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-features/font-features-ligatures-none.html
@@ -0,0 +1,20 @@
+<html>
+<head>
+<style type="text/css">
+@font-face {
+  font-family: libertine;
+  src: url(../fonts/LinLibertine_Re-4.7.5.woff) format("woff");
+  font-feature-settings: "hlig";
+}
+body {
+  font-family: libertine, sans-serif;
+  font-size: 400%;
+  line-height: 2em;
+  font-variant-ligatures: none;
+}
+</style>
+</head>
+<body lang="en">
+fastest firefox
+</body>
+</html>
--- a/layout/reftests/font-features/font-variant-features.js
+++ b/layout/reftests/font-features/font-variant-features.js
@@ -48,31 +48,34 @@ var gPropertyData = [
   { prop: "font-variant-east-asian", value: "jis90 jis04", features: {"jp90": 0, "jp04": 0}, invalid: true },
   { prop: "font-variant-east-asian", value: "simplified traditional", features: {"smpl": 0, "trad": 0}, invalid: true },
   { prop: "font-variant-east-asian", value: "full-width proportional-width", features: {"fwid": 0, "pwid": 0}, invalid: true },
   { prop: "font-variant-east-asian", value: "ruby simplified ruby", features: {"ruby": 0, "smpl": 0, "jp04": 0}, invalid: true },
   { prop: "font-variant-east-asian", value: "jis78 ruby simplified", features: {"ruby": 0, "smpl": 0, "jp78": 0}, invalid: true },
 
   // font-variant-ligatures
   // valid values
+  { prop: "font-variant-ligatures", value: "none", features: {"liga": 0, "dlig": 0, "clig": 0, "calt": 0, "hlig": 0} },
   { prop: "font-variant-ligatures", value: "normal", features: {"liga": 1, "dlig": 0} },
   { prop: "font-variant-ligatures", value: "common-ligatures", features: {"liga": 1, "clig": 1, "dlig": 0, "hlig": 0, "calt": 1} },
   { prop: "font-variant-ligatures", value: "no-common-ligatures", features: {"liga": 0, "clig": 0, "dlig": 0, "hlig": 0, "calt": 1} },
   { prop: "font-variant-ligatures", value: "discretionary-ligatures", features: {"liga": 1, "clig": 1, "dlig": 1, "hlig": 0, "calt": 1} },
   { prop: "font-variant-ligatures", value: "no-discretionary-ligatures", features: {"liga": 1, "clig": 1, "dlig": 0, "hlig": 0, "calt": 1} },
   { prop: "font-variant-ligatures", value: "historical-ligatures", features: {"liga": 1, "clig": 1, "dlig": 0, "hlig": 1, "calt": 1} },
   { prop: "font-variant-ligatures", value: "no-historical-ligatures", features: {"liga": 1, "clig": 1, "dlig": 0, "hlig": 0, "calt": 1} },
   { prop: "font-variant-ligatures", value: "contextual", features: {"liga": 1, "clig": 1, "dlig": 0, "hlig": 0, "calt": 1} },
   { prop: "font-variant-ligatures", value: "no-contextual", features: {"liga": 1, "clig": 1, "dlig": 0, "hlig": 0, "calt": 0} },
   { prop: "font-variant-ligatures", value: "common-ligatures no-discretionary-ligatures", features: {"liga": 1, "clig": 1, "dlig": 0, "hlig": 0, "calt": 1} },
   { prop: "font-variant-ligatures", value: "historical-ligatures no-common-ligatures", features: {"clig": 0, "liga": 0, "dlig": 0, "hlig": 1, "calt": 1} },
   { prop: "font-variant-ligatures", value: "no-historical-ligatures discretionary-ligatures", features: {"liga": 1, "clig": 1, "dlig": 1, "hlig": 0, "calt": 1} },
   { prop: "font-variant-ligatures", value: "common-ligatures no-discretionary-ligatures historical-ligatures no-contextual", features: {"clig": 1, "dlig": 0, "hlig": 1, "liga": 1, "calt": 0} },
 
   // invalid values
+  { prop: "font-variant-ligatures", value: "common-ligatures none", features: {"liga": 1, "clig": 1, "dlig": 0}, invalid: true },
+  { prop: "font-variant-ligatures", value: "none common-ligatures", features: {"liga": 1, "clig": 1, "dlig": 0}, invalid: true },
   { prop: "font-variant-ligatures", value: "common-ligatures normal", features: {"liga": 1, "clig": 1, "dlig": 0}, invalid: true },
   { prop: "font-variant-ligatures", value: "common-ligatures no-common-ligatures", features: {"liga": 1, "clig": 1, "dlig": 0}, invalid: true },
   { prop: "font-variant-ligatures", value: "common-ligatures common-ligatures", features: {"liga": 1, "clig": 1, "dlig": 0}, invalid: true },
   { prop: "font-variant-ligatures", value: "no-historical-ligatures historical-ligatures", features: {"liga": 1, "clig": 1, "dlig": 0, "hlig": 0}, invalid: true },
   { prop: "font-variant-ligatures", value: "no-contextual contextual", features: {"liga": 1, "clig": 1, "dlig": 0, "hlig": 0}, invalid: true },
   { prop: "font-variant-ligatures", value: "no-discretionary-ligatures discretionary-ligatures", features: {"liga": 1, "clig": 1, "dlig": 0}, invalid: true },
   { prop: "font-variant-ligatures", value: "common-ligatures no-discretionary-ligatures no-common-ligatures", features: {"liga": 1, "clig": 1, "dlig": 0}, invalid: true },
 
--- a/layout/reftests/font-features/reftest.list
+++ b/layout/reftests/font-features/reftest.list
@@ -23,16 +23,17 @@ HTTP(..) == font-features-turkish.html f
 # The following should pass even if feature support isn't available,
 # because both testcase and reference will have the default rendering,
 # though they're not really meaningful unless the tests above passed already.
 
 # compare feature specified within @font-face to same feature in style rule
 HTTP(..) == font-features-hlig-2.html font-features-hlig.html
 HTTP(..) == font-features-hlig-4.html font-features-hlig.html
 HTTP(..) != font-features-hlig-5.html font-features-hlig.html
+pref(layout.css.font-features.enabled,true) HTTP(..) == font-features-ligatures-none.html font-features-noliga.html
 
 # check that feature in style rule overrides @font-face
 skip-if(B2G) HTTP(..) == font-features-hlig-3.html font-features-noliga.html # bug 773482
 
 # make sure old syntax usage never interferes with new syntax usage
 HTTP(..) == font-features-oldsyntax-1.html font-features-ref.html
 HTTP(..) == font-features-oldsyntax-2.html font-features-ref.html
 HTTP(..) == font-features-oldsyntax-3.html font-features-hlig.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/mathml/mpadded-7-ref.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Test mpadded</title>
+  </head>
+  <body>
+    <math>
+      <mpadded mathbackground="red" height="100height" depth="0">
+        <mphantom>
+          <mtext mathvariant="monospace">X</mtext>
+        </mphantom>
+      </mpadded>
+    </math>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/mathml/mpadded-7.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Test mpadded</title>
+  </head>
+  <body>
+    <math>
+      <!--height in term of height should not depend on the characters-->
+      <mpadded mathbackground="red" height="100height" depth="0">
+        <mphantom>
+          <mtext mathvariant="monospace">_</mtext>
+        </mphantom>
+      </mpadded>
+    </math>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/mathml/mpadded-8-ref.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Test mpadded</title>
+  </head>
+  <body>
+    <math>
+      <mpadded mathbackground="red" height="100width" depth="0">
+        <mphantom>
+          <mtext mathvariant="monospace">X</mtext>
+        </mphantom>
+      </mpadded>
+    </math>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/mathml/mpadded-8.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Test mpadded</title>
+  </head>
+  <body>
+    <math>
+      <!--height in term of width should not depend on the characters-->
+      <mpadded mathbackground="red" height="100width" depth="0">
+        <mphantom>
+          <mtext mathvariant="monospace">|</mtext>
+        </mphantom>
+      </mpadded>
+    </math>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/mathml/mpadded-9-ref.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Test mpadded</title>
+  </head>
+  <body>
+    <math>
+      <mpadded mathbackground="red" width="100width">
+        <mphantom>
+          <mtext mathvariant="monospace">X</mtext>
+        </mphantom>
+      </mpadded>
+    </math>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/mathml/mpadded-9.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Test mpadded</title>
+  </head>
+  <body>
+    <math>
+      <!--with fixed width, height + depth should not depend on the characters-->
+      <mpadded mathbackground="red" width="100width">
+        <mphantom>
+          <mtext mathvariant="monospace">|</mtext>
+        </mphantom>
+      </mpadded>
+    </math>
+  </body>
+</html>
--- a/layout/reftests/mathml/reftest.list
+++ b/layout/reftests/mathml/reftest.list
@@ -87,16 +87,19 @@ fails == mstyle-5.xhtml mstyle-5-ref.xht
 == mspace-1.html mspace-1-ref.html
 == mpadded-1.html mpadded-1-ref.html
 == mpadded-2.html mpadded-2-ref.html
 == mpadded-3.html mpadded-3-ref.html
 == mpadded-4.html mpadded-4-ref.html
 == mpadded-5.html mpadded-5-ref.html
 == mpadded-1-2.html mpadded-1-2-ref.html
 == mpadded-6.html mpadded-6-ref.html
+== mpadded-7.html mpadded-7-ref.html
+== mpadded-8.html mpadded-8-ref.html
+== mpadded-9.html mpadded-9-ref.html
 == math-display.html math-display-ref.html
 == scriptlevel-movablelimits-1.html scriptlevel-movablelimits-1-ref.html
 == munderover-align-accent-false.html munderover-align-accent-false-ref.html
 == munderover-align-accent-true.html munderover-align-accent-true-ref.html
 == munder-mover-align-accent-true.html munder-mover-align-accent-true-ref.html
 == munder-mover-align-accent-false.html munder-mover-align-accent-false-ref.html
 == mfrac-linethickness-1.xhtml mfrac-linethickness-1-ref.xhtml
 == mfrac-linethickness-2.xhtml mfrac-linethickness-2-ref.xhtml
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -8984,18 +8984,30 @@ static const int32_t maskLigatures[] = {
 
 bool
 CSSParserImpl::ParseFontVariantLigatures(nsCSSValue& aValue)
 {
   NS_ASSERTION(maskLigatures[NS_ARRAY_LENGTH(maskLigatures) - 1] ==
                  MASK_END_VALUE,
                "incorrectly terminated array");
 
-  return ParseBitmaskValues(aValue, nsCSSProps::kFontVariantLigaturesKTable,
-                            maskLigatures);
+  bool parsed =
+    ParseBitmaskValues(aValue, nsCSSProps::kFontVariantLigaturesKTable,
+                       maskLigatures);
+
+  // if none value included, no other values are possible
+  if (parsed && eCSSUnit_Enumerated == aValue.GetUnit()) {
+    int32_t val = aValue.GetIntValue();
+    if ((val & NS_FONT_VARIANT_LIGATURES_NONE) &&
+        (val & ~int32_t(NS_FONT_VARIANT_LIGATURES_NONE))) {
+      parsed = false;
+    }
+  }
+
+  return parsed;
 }
 
 static const int32_t maskNumeric[] = {
   NS_FONT_VARIANT_NUMERIC_FIGURE_MASK,
   NS_FONT_VARIANT_NUMERIC_SPACING_MASK,
   NS_FONT_VARIANT_NUMERIC_FRACTION_MASK,
   MASK_END_VALUE
 };
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -1139,16 +1139,17 @@ const int32_t nsCSSProps::kFontVariantEa
   eCSSKeyword_traditional, NS_FONT_VARIANT_EAST_ASIAN_TRADITIONAL,
   eCSSKeyword_full_width, NS_FONT_VARIANT_EAST_ASIAN_FULL_WIDTH,
   eCSSKeyword_proportional_width, NS_FONT_VARIANT_EAST_ASIAN_PROP_WIDTH,
   eCSSKeyword_ruby, NS_FONT_VARIANT_EAST_ASIAN_RUBY,
   eCSSKeyword_UNKNOWN,-1
 };
 
 const int32_t nsCSSProps::kFontVariantLigaturesKTable[] = {
+  eCSSKeyword_none, NS_FONT_VARIANT_LIGATURES_NONE,
   eCSSKeyword_common_ligatures, NS_FONT_VARIANT_LIGATURES_COMMON,
   eCSSKeyword_no_common_ligatures, NS_FONT_VARIANT_LIGATURES_NO_COMMON,
   eCSSKeyword_discretionary_ligatures, NS_FONT_VARIANT_LIGATURES_DISCRETIONARY,
   eCSSKeyword_no_discretionary_ligatures, NS_FONT_VARIANT_LIGATURES_NO_DISCRETIONARY,
   eCSSKeyword_historical_ligatures, NS_FONT_VARIANT_LIGATURES_HISTORICAL,
   eCSSKeyword_no_historical_ligatures, NS_FONT_VARIANT_LIGATURES_NO_HISTORICAL,
   eCSSKeyword_contextual, NS_FONT_VARIANT_LIGATURES_CONTEXTUAL,
   eCSSKeyword_no_contextual, NS_FONT_VARIANT_LIGATURES_NO_CONTEXTUAL,
--- a/layout/style/nsCSSRuleProcessor.cpp
+++ b/layout/style/nsCSSRuleProcessor.cpp
@@ -189,17 +189,17 @@ RuleHash_CIHashKey(PLDHashTable *table, 
   nsContentUtils::ASCIIToLower(str);
   return HashString(str);
 }
 
 typedef nsIAtom*
 (* RuleHashGetKey) (PLDHashTable *table, const PLDHashEntryHdr *entry);
 
 struct RuleHashTableOps {
-  PLDHashTableOps ops;
+  const PLDHashTableOps ops;
   // Extra callback to avoid duplicating the matchEntry callback for
   // each table.  (There used to be a getKey callback in
   // PLDHashTableOps.)
   RuleHashGetKey getKey;
 };
 
 inline const RuleHashTableOps*
 ToLocalOps(const PLDHashTableOps *aOps)
@@ -3092,17 +3092,17 @@ static bool
 InitWeightEntry(PLDHashTable *table, PLDHashEntryHdr *hdr,
                 const void *key)
 {
   RuleByWeightEntry* entry = static_cast<RuleByWeightEntry*>(hdr);
   new (entry) RuleByWeightEntry();
   return true;
 }
 
-static PLDHashTableOps gRulesByWeightOps = {
+static const PLDHashTableOps gRulesByWeightOps = {
     PL_DHashAllocTable,
     PL_DHashFreeTable,
     HashIntKey,
     MatchWeightEntry,
     PL_DHashMoveEntryStub,
     PL_DHashClearEntryStub,
     PL_DHashFinalizeStub,
     InitWeightEntry
--- a/layout/style/nsCSSValue.cpp
+++ b/layout/style/nsCSSValue.cpp
@@ -904,17 +904,17 @@ nsCSSValue::AppendToString(nsCSSProperty
       nsStyleUtil::AppendBitmaskCSSValue(aProperty, intValue,
                                          NS_FONT_VARIANT_EAST_ASIAN_JIS78,
                                          NS_FONT_VARIANT_EAST_ASIAN_RUBY,
                                          aResult);
       break;
 
     case eCSSProperty_font_variant_ligatures:
       nsStyleUtil::AppendBitmaskCSSValue(aProperty, intValue,
-                                         NS_FONT_VARIANT_LIGATURES_COMMON,
+                                         NS_FONT_VARIANT_LIGATURES_NONE,
                                          NS_FONT_VARIANT_LIGATURES_NO_CONTEXTUAL,
                                          aResult);
       break;
 
     case eCSSProperty_font_variant_numeric:
       nsStyleUtil::AppendBitmaskCSSValue(aProperty, intValue,
                                          NS_FONT_VARIANT_NUMERIC_LINING,
                                          NS_FONT_VARIANT_NUMERIC_ORDINAL,
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -1607,17 +1607,17 @@ nsComputedDOMStyle::DoGetFontVariantLiga
   int32_t intValue = StyleFont()->mFont.variantLigatures;
 
   if (0 == intValue) {
     val->SetIdent(eCSSKeyword_normal);
   } else {
     nsAutoString valueStr;
 
     nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_font_variant_ligatures,
-      intValue, NS_FONT_VARIANT_LIGATURES_COMMON,
+      intValue, NS_FONT_VARIANT_LIGATURES_NONE,
       NS_FONT_VARIANT_LIGATURES_NO_CONTEXTUAL, valueStr);
     val->SetString(valueStr);
   }
 
   return val;
 }
 
 CSSValue*
--- a/layout/style/nsHTMLStyleSheet.cpp
+++ b/layout/style/nsHTMLStyleSheet.cpp
@@ -153,17 +153,17 @@ MappedAttrTable_MatchEntry(PLDHashTable 
   nsMappedAttributes *attributes =
     static_cast<nsMappedAttributes*>(const_cast<void*>(key));
   const MappedAttrTableEntry *entry =
     static_cast<const MappedAttrTableEntry*>(hdr);
 
   return attributes->Equals(entry->mAttributes);
 }
 
-static PLDHashTableOps MappedAttrTable_Ops = {
+static const PLDHashTableOps MappedAttrTable_Ops = {
   PL_DHashAllocTable,
   PL_DHashFreeTable,
   MappedAttrTable_HashKey,
   MappedAttrTable_MatchEntry,
   PL_DHashMoveEntryStub,
   MappedAttrTable_ClearEntry,
   PL_DHashFinalizeStub,
   nullptr
@@ -210,17 +210,17 @@ LangRuleTable_InitEntry(PLDHashTable *ta
   LangRuleTableEntry *entry = new (hdr) LangRuleTableEntry();
 
   // Create the unique rule for this language
   entry->mRule = new nsHTMLStyleSheet::LangRule(*lang);
 
   return true;
 }
 
-static PLDHashTableOps LangRuleTable_Ops = {
+static const PLDHashTableOps LangRuleTable_Ops = {
   PL_DHashAllocTable,
   PL_DHashFreeTable,
   LangRuleTable_HashKey,
   LangRuleTable_MatchEntry,
   PL_DHashMoveEntryStub,
   LangRuleTable_ClearEntry,
   PL_DHashFinalizeStub,
   LangRuleTable_InitEntry
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -99,17 +99,17 @@ nsRuleNode::ChildrenHashMatchEntry(PLDHa
 {
   const ChildrenHashEntry *entry =
     static_cast<const ChildrenHashEntry*>(aHdr);
   const nsRuleNode::Key *key =
     static_cast<const nsRuleNode::Key*>(aKey);
   return entry->mRuleNode->GetKey() == *key;
 }
 
-/* static */ PLDHashTableOps
+/* static */ const PLDHashTableOps
 nsRuleNode::ChildrenHashOps = {
   // It's probably better to allocate the table itself using malloc and
   // free rather than the pres shell's arena because the table doesn't
   // grow very often and the pres shell's arena doesn't recycle very
   // large size allocations.
   PL_DHashAllocTable,
   PL_DHashFreeTable,
   ChildrenHashHashKey,
--- a/layout/style/nsRuleNode.h
+++ b/layout/style/nsRuleNode.h
@@ -299,17 +299,17 @@ private:
   static PLDHashNumber
   ChildrenHashHashKey(PLDHashTable *aTable, const void *aKey);
 
   static bool
   ChildrenHashMatchEntry(PLDHashTable *aTable,
                          const PLDHashEntryHdr *aHdr,
                          const void *aKey);
 
-  static PLDHashTableOps ChildrenHashOps;
+  static const PLDHashTableOps ChildrenHashOps;
 
   static PLDHashOperator
   EnqueueRuleNodeChildren(PLDHashTable *table, PLDHashEntryHdr *hdr,
                           uint32_t number, void *arg);
 
   Key GetKey() const {
     return Key(mRule, GetLevel(), IsImportantRule());
   }
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -4308,24 +4308,25 @@ if (SpecialPowers.getBoolPref("layout.cs
 			invalid_values: [ "jis78 normal", "jis90 jis04", "simplified traditional", "full-width proportional-width",
 	                          "ruby simplified ruby", "jis78 ruby simplified" ]
 		},
 		"font-variant-ligatures": {
 			domProp: "fontVariantLigatures",
 			inherited: true,
 			type: CSS_TYPE_LONGHAND,
 			initial_values: [ "normal" ],
-			other_values: [ "common-ligatures", "no-common-ligatures", "discretionary-ligatures", "no-discretionary-ligatures",
+			other_values: [ "none", "common-ligatures", "no-common-ligatures", "discretionary-ligatures", "no-discretionary-ligatures",
 			                "historical-ligatures", "no-historical-ligatures", "contextual", "no-contextual",
 			                "common-ligatures no-discretionary-ligatures", "contextual no-discretionary-ligatures",
 			                "historical-ligatures no-common-ligatures", "no-historical-ligatures discretionary-ligatures",
 			                "common-ligatures no-discretionary-ligatures historical-ligatures no-contextual" ],
 			invalid_values: [ "common-ligatures normal", "common-ligatures no-common-ligatures", "common-ligatures common-ligatures",
 			                  "no-historical-ligatures historical-ligatures", "no-discretionary-ligatures discretionary-ligatures",
-			                  "no-contextual contextual", "common-ligatures no-discretionary-ligatures no-common-ligatures" ]
+			                  "no-contextual contextual", "common-ligatures no-discretionary-ligatures no-common-ligatures",
+			                  "common-ligatures none", "no-discretionary-ligatures none", "none common-ligatures" ]
 		},
 		"font-variant-numeric": {
 			domProp: "fontVariantNumeric",
 			inherited: true,
 			type: CSS_TYPE_LONGHAND,
 			initial_values: [ "normal" ],
 			other_values: [ "lining-nums", "oldstyle-nums", "proportional-nums", "tabular-nums", "diagonal-fractions",
 			                "stacked-fractions", "slashed-zero", "ordinal", "lining-nums diagonal-fractions",
--- a/layout/tables/SpanningCellSorter.cpp
+++ b/layout/tables/SpanningCellSorter.cpp
@@ -26,17 +26,17 @@ SpanningCellSorter::~SpanningCellSorter(
 {
     if (mHashTable.entryCount) {
         PL_DHashTableFinish(&mHashTable);
         mHashTable.entryCount = 0;
     }
     delete [] mSortedHashTable;
 }
 
-/* static */ PLDHashTableOps
+/* static */ const PLDHashTableOps
 SpanningCellSorter::HashTableOps = {
     PL_DHashAllocTable,
     PL_DHashFreeTable,
     HashTableHashKey,
     HashTableMatchEntry,
     PL_DHashMoveEntryStub,
     PL_DHashClearEntryStub,
     PL_DHashFinalizeStub,
--- a/layout/tables/SpanningCellSorter.h
+++ b/layout/tables/SpanningCellSorter.h
@@ -65,17 +65,17 @@ private:
     }
 
     PLDHashTable mHashTable;
     struct HashTableEntry : public PLDHashEntryHdr {
         int32_t mColSpan;
         Item *mItems;
     };
 
-    static PLDHashTableOps HashTableOps;
+    static const PLDHashTableOps HashTableOps;
 
     static PLDHashNumber
         HashTableHashKey(PLDHashTable *table, const void *key);
     static bool
         HashTableMatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr,
                             const void *key);
 
     static PLDHashOperator
--- a/modules/libpref/src/Preferences.cpp
+++ b/modules/libpref/src/Preferences.cpp
@@ -934,17 +934,17 @@ Preferences::WritePrefFile(nsIFile* aFil
 
   // tell the safe output stream to overwrite the real prefs file
   // (it'll abort if there were any errors during writing)
   nsCOMPtr<nsISafeOutputStream> safeStream = do_QueryInterface(outStream);
   NS_ASSERTION(safeStream, "expected a safe output stream!");
   if (safeStream) {
     rv = safeStream->Finish();
     if (NS_FAILED(rv)) {
-      NS_WARNING("failed to save prefs file! possible dataloss");
+      NS_WARNING("failed to save prefs file! possible data loss");
       return rv;
     }
   }
 
   gDirty = false;
   return NS_OK;
 }
 
--- a/netwerk/base/src/ProxyAutoConfig.cpp
+++ b/netwerk/base/src/ProxyAutoConfig.cpp
@@ -611,20 +611,22 @@ ProxyAutoConfig::SetupJS()
   JSAutoCompartment ac(mJSRuntime->Context(), mJSRuntime->Global());
 
   // check if this is a data: uri so that we don't spam the js console with
   // huge meaningless strings. this is not on the main thread, so it can't
   // use nsIRUI scheme methods
   bool isDataURI = nsDependentCSubstring(mPACURI, 0, 5).LowerCaseEqualsASCII("data:", 5);
 
   sRunning = this;
-  JSScript *script = JS_CompileScript(mJSRuntime->Context(),
-                                      mJSRuntime->Global(),
+  JS::Rooted<JSObject *> global(mJSRuntime->Context(), mJSRuntime->Global());
+  JS::CompileOptions options(mJSRuntime->Context());
+  options.setFileAndLine(mPACURI.get(), 1);
+  JSScript *script = JS_CompileScript(mJSRuntime->Context(), global,
                                       mPACScript.get(), mPACScript.Length(),
-                                      mPACURI.get(), 1);
+                                      options);
   if (!script ||
       !JS_ExecuteScript(mJSRuntime->Context(), mJSRuntime->Global(), script, nullptr)) {
     nsString alertMessage(NS_LITERAL_STRING("PAC file failed to install from "));
     if (isDataURI) {
       alertMessage += NS_LITERAL_STRING("data: URI");
     }
     else {
       alertMessage += NS_ConvertUTF8toUTF16(mPACURI);
--- a/netwerk/base/src/nsBufferedStreams.cpp
+++ b/netwerk/base/src/nsBufferedStreams.cpp
@@ -624,17 +624,17 @@ nsBufferedOutputStream::Write(const char
 }
 
 NS_IMETHODIMP
 nsBufferedOutputStream::Flush()
 {
     nsresult rv;
     uint32_t amt;
     if (!mStream) {
-        // Stream already cancelled/flushed; probably because of error.
+        // Stream already cancelled/flushed; probably because of previous error.
         return NS_OK;
     }
     rv = Sink()->Write(mBuffer, mFillPoint, &amt);
     if (NS_FAILED(rv)) return rv;
     mBufferStartOffset += amt;
     if (amt == mFillPoint) {
         mFillPoint = mCursor = 0;
         return NS_OK;   // flushed everything
--- a/netwerk/streamconv/converters/ParseFTPList.h
+++ b/netwerk/streamconv/converters/ParseFTPList.h
@@ -1,13 +1,16 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#ifndef ParseRTPList_h___
+#define ParseRTPList_h___
+
 #include <stdint.h>
 #include <string.h>
 #include "prtime.h"
 
 /* ParseFTPList() parses lines from an FTP LIST command.
 **
 ** Written July 2002 by Cyrus Patel <cyp@fb14.uni-mainz.de>
 ** with acknowledgements to squid, lynx, wget and ftpmirror.
@@ -89,12 +92,13 @@ struct list_result
   const char *      fe_lname;     /* pointer to symlink name */
   uint32_t          fe_lnlen;     /* length of symlink name */
   char              fe_size[40];  /* size of file in bytes (<= (2^128 - 1)) */
   PRExplodedTime    fe_time;      /* last-modified time */
   int32_t           fe_cinfs;     /* file system is definitely case insensitive */
                                   /* (converting all-upcase names may be desirable) */
 };
 
-int ParseFTPList(const char *line, 
+int ParseFTPList(const char *line,
                  struct list_state *state,
                  struct list_result *result );
 
+#endif /* !ParseRTPList_h___ */
--- a/netwerk/streamconv/converters/moz.build
+++ b/netwerk/streamconv/converters/moz.build
@@ -1,33 +1,33 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-SOURCES += [
+UNIFIED_SOURCES += [
     'mozTXTToHTMLConv.cpp',
     'nsDirIndex.cpp',
     'nsDirIndexParser.cpp',
     'nsHTTPCompressConv.cpp',
     'nsIndexedToHTML.cpp',
     'nsMultiMixedConv.cpp',
     'nsTXTToHTMLConv.cpp',
     'nsUnknownDecoder.cpp',
 ]
 
 if 'ftp' in CONFIG['NECKO_PROTOCOLS']:
-    SOURCES += [
+    UNIFIED_SOURCES += [
         'nsFTPDirListingConv.cpp',
         'ParseFTPList.cpp',
     ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'cocoa':
-    SOURCES += [
+    UNIFIED_SOURCES += [
         'nsBinHexDecoder.cpp',
     ]
 
 FAIL_ON_WARNINGS = True
 
 MSVC_ENABLE_PGO = True
 
 FINAL_LIBRARY = 'necko'
--- a/netwerk/streamconv/converters/nsBinHexDecoder.cpp
+++ b/netwerk/streamconv/converters/nsBinHexDecoder.cpp
@@ -15,21 +15,16 @@
 #include "prnetdb.h"
 #include "nsIURI.h"
 #include "nsIURL.h"
 
 #include "nsIMIMEService.h"
 #include "nsMimeTypes.h"
 #include <algorithm>
 
-
-// sadly I couldn't find char defintions for CR LF elsehwere in the code (they are defined as strings in nsCRT.h)
-#define CR  '\015'
-#define LF '\012'
-
 nsBinHexDecoder::nsBinHexDecoder() :
   mState(0), mCRC(0), mFileCRC(0), mOctetin(26),
   mDonePos(3), mInCRC(0), mCount(0), mMarker(0), mPosInbuff(0),
   mPosOutputBuff(0)
 {
   mDataBuffer = nullptr;
   mOutgoingBuffer = nullptr;
 
@@ -57,17 +52,17 @@ NS_INTERFACE_MAP_BEGIN(nsBinHexDecoder)
   NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
   NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 
 // The binhex 4.0 decoder table....
 
-static signed char binhex_decode[256] =
+static const signed char binhex_decode[256] =
 {
   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, -1, -1,
   13, 14, 15, 16, 17, 18, 19, -1, 20, 21, -1, -1, -1, -1, -1, -1,
   22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, -1,
   37, 38, 39, 40, 41, 42, 43, -1, 44, 45, 46, 47, -1, -1, -1, -1,
   48, 49, 50, 51, 52, 53, 54, -1, 55, 56, 57, 58, 59, 60, -1, -1,
@@ -316,17 +311,17 @@ nsresult nsBinHexDecoder::ProcessNextChu
   //  if it is the first time, seek to the right start place.
   if (mState == BINHEX_STATE_START)
   {
     foundStart = false;
     // go through the line, until we get a ':'
     while (mPosInDataBuffer < numBytesInBuffer)
     {
       c = mDataBuffer[mPosInDataBuffer++];
-      while (c == CR || c == LF)
+      while (c == nsCRT::CR || c == nsCRT::LF)
       {
         if (mPosInDataBuffer >= numBytesInBuffer)
           break;
 
         c = mDataBuffer[mPosInDataBuffer++];
         if (c == ':')
         {
           foundStart = true;
@@ -425,20 +420,20 @@ nsresult nsBinHexDecoder::ProcessNextChu
 
 int16_t nsBinHexDecoder::GetNextChar(uint32_t numBytesInBuffer)
 {
   char c = 0;
 
   while (mPosInDataBuffer < numBytesInBuffer)
   {
     c = mDataBuffer[mPosInDataBuffer++];
-    if (c != LF && c != CR)
+    if (c != nsCRT::LF && c != nsCRT::CR)
       break;
   }
-  return (c == LF || c == CR) ? 0 : (int) c;
+  return (c == nsCRT::LF || c == nsCRT::CR) ? 0 : (int) c;
 }
 
 //////////////////////////////////////////////////////
 // nsIRequestObserver methods...
 //////////////////////////////////////////////////////
 
 NS_IMETHODIMP
 nsBinHexDecoder::OnStartRequest(nsIRequest* request, nsISupports *aCtxt)
--- a/netwerk/streamconv/test/Converters.cpp
+++ b/netwerk/streamconv/test/Converters.cpp
@@ -1,20 +1,29 @@
 #include "Converters.h"
 #include "nsIStringStream.h"
 #include "nsCOMPtr.h"
 #include "nsComponentManagerUtils.h"
 
 #include <stdio.h>
-#include <algorithm>
 
 //////////////////////////////////////////////////
 // TestConverter
 //////////////////////////////////////////////////
 
+#define NS_TESTCONVERTER_CID                         \
+{ /* B8A067B0-4450-11d3-A16E-0050041CAF44 */         \
+    0xb8a067b0,                                      \
+    0x4450,                                          \
+    0x11d3,                                          \
+    {0xa1, 0x6e, 0x00, 0x50, 0x04, 0x1c, 0xaf, 0x44} \
+}
+
+NS_DEFINE_CID(kTestConverterCID, NS_TESTCONVERTER_CID);
+
 NS_IMPL_ISUPPORTS3(TestConverter,
                    nsIStreamConverter,
                    nsIStreamListener,
                    nsIRequestObserver)
 
 TestConverter::TestConverter() {
 }
 
@@ -74,22 +83,16 @@ TestConverter::AsyncConvertData(const ch
 
     // based on these types, setup internal state to handle the appropriate conversion.
     fromType = aFromType;
     toType = aToType;
 
     return NS_OK; 
 }
 
-static inline uint32_t
-saturated(uint64_t aValue)
-{
-    return (uint32_t) std::min(aValue, (uint64_t) UINT32_MAX);
-}
-
 // nsIStreamListener method
 /* This method handles asyncronous conversion of data. */
 NS_IMETHODIMP
 TestConverter::OnDataAvailable(nsIRequest* request,
                                nsISupports *ctxt, 
                                nsIInputStream *inStr, 
                                uint64_t sourceOffset, 
                                uint32_t count) {
--- a/netwerk/streamconv/test/Converters.h
+++ b/netwerk/streamconv/test/Converters.h
@@ -1,28 +1,27 @@
+#ifndef Converters_h___
+#define Converters_h___
+
 #include "nsIStreamConverter.h"
 #include "nsIFactory.h"
 #include "nsCOMPtr.h"
 #include "nsStringAPI.h"
 
+#include <algorithm>
+
 /* This file defines stream converter components, and their accompanying factory class.
  * These converters implement the nsIStreamConverter interface and support both
  * asynchronous and synchronous stream conversion.
  */
 
 ///////////////////////////////////////////////
 // TestConverter
-#define NS_TESTCONVERTER_CID                         \
-{ /* B8A067B0-4450-11d3-A16E-0050041CAF44 */         \
-    0xb8a067b0,                                      \
-    0x4450,                                          \
-    0x11d3,                                          \
-    {0xa1, 0x6e, 0x00, 0x50, 0x04, 0x1c, 0xaf, 0x44} \
-}
-static NS_DEFINE_CID(kTestConverterCID,          NS_TESTCONVERTER_CID);
+
+extern const nsCID kTestConverterCID;
 
 class TestConverter : public nsIStreamConverter {
 public:
     NS_DECL_ISUPPORTS
     NS_DECL_NSIREQUESTOBSERVER
     NS_DECL_NSISTREAMLISTENER
 
     TestConverter();
@@ -38,8 +37,16 @@ public:
 
     // member data
     nsCOMPtr<nsIStreamListener> mListener;
     nsCString fromType;
     nsCString toType;
 };
 
 nsresult CreateTestConverter(nsISupports* aOuter, REFNSIID aIID, void** aResult);
+
+static inline uint32_t
+saturated(uint64_t aValue)
+{
+    return (uint32_t) std::min(aValue, (uint64_t) UINT32_MAX);
+}
+
+#endif /* !Converters_h___ */
--- a/netwerk/streamconv/test/TestStreamConv.cpp
+++ b/netwerk/streamconv/test/TestStreamConv.cpp
@@ -14,18 +14,16 @@
 #include "nsThreadUtils.h"
 #include "mozilla/Attributes.h"
 #include "nsMemory.h"
 #include "nsServiceManagerUtils.h"
 #include "nsComponentManagerUtils.h"
 #include "nsIRequest.h"
 #include "nsNetCID.h"
 
-#include <algorithm>
-
 #define ASYNC_TEST // undefine this if you want to test sycnronous conversion.
 
 /////////////////////////////////
 // Event pump setup
 /////////////////////////////////
 #ifdef XP_WIN
 #include <windows.h>
 #endif
@@ -94,22 +92,16 @@ public:
 NS_IMPL_ISUPPORTS2(EndListener,
                    nsIStreamListener,
                    nsIRequestObserver)
 
 ////////////////////////////////////////////////////////////////////////
 // EndListener END
 ////////////////////////////////////////////////////////////////////////
 
-static uint32_t 
-saturated(uint64_t aValue)
-{
-    return (uint32_t)std::min(aValue, (uint64_t)UINT32_MAX);
-}
- 
 nsresult SendData(const char * aData, nsIStreamListener* aListener, nsIRequest* request) {
     nsresult rv;
 
     nsCOMPtr<nsIStringInputStream> dataStream
       (do_CreateInstance("@mozilla.org/io/string-input-stream;1", &rv));
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = dataStream->SetData(aData, strlen(aData));
--- a/netwerk/streamconv/test/moz.build
+++ b/netwerk/streamconv/test/moz.build
@@ -1,15 +1,15 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 PROGRAM = 'TestStreamConv'
 
-SOURCES += [
+UNIFIED_SOURCES += [
     'Converters.cpp',
     'TestStreamConv.cpp',
 ]
 
 FAIL_ON_WARNINGS = True
 
--- a/python/mozbuild/mozbuild/backend/recursivemake.py
+++ b/python/mozbuild/mozbuild/backend/recursivemake.py
@@ -1064,19 +1064,27 @@ class RecursiveMakeBackend(CommonBackend
             backend_file.write('%s_EXTRA_JARS := %s\n' %
                 (target, ' '.join(jar.extra_jars)))
         if jar.javac_flags:
             backend_file.write('%s_JAVAC_FLAGS := %s\n' %
                 (target, ' '.join(jar.javac_flags)))
 
     def _process_library_definition(self, libdef, backend_file):
         backend_file.write('LIBRARY_NAME = %s\n' % libdef.basename)
-        for reldir, basename in libdef.static_libraries:
-            backend_file.write('SHARED_LIBRARY_LIBS += $(DEPTH)/%s/$(LIB_PREFIX)%s.$(LIB_SUFFIX)\n'
-                               % (reldir, basename))
+        thisobjdir = libdef.objdir
+        topobjdir = libdef.topobjdir.replace(os.sep, '/')
+        for objdir, basename in libdef.static_libraries:
+            # If this is an external objdir (i.e., comm-central), use the other
+            # directory instead of $(DEPTH).
+            if objdir.startswith(topobjdir + '/'):
+                relpath = '$(DEPTH)/%s' % mozpath.relpath(objdir, topobjdir)
+            else:
+                relpath = mozpath.relpath(objdir, thisobjdir)
+            backend_file.write('SHARED_LIBRARY_LIBS += %s/$(LIB_PREFIX)%s.$(LIB_SUFFIX)\n'
+                               % (relpath, basename))
 
     def _write_manifests(self, dest, manifests):
         man_dir = os.path.join(self.environment.topobjdir, '_build_manifests',
             dest)
 
         # We have a purger for the manifests themselves to ensure legacy
         # manifests are deleted.
         purger = FilePurger()
--- a/python/mozbuild/mozbuild/frontend/data.py
+++ b/python/mozbuild/mozbuild/frontend/data.py
@@ -340,18 +340,18 @@ class LibraryDefinition(SandboxDerived):
 
     def __init__(self, sandbox, basename):
         SandboxDerived.__init__(self, sandbox)
 
         self.basename = basename
         self.refcount = 0
         self.static_libraries = []
 
-    def link_static_lib(self, reldir, basename):
-        self.static_libraries.append((reldir, basename))
+    def link_static_lib(self, objdir, basename):
+        self.static_libraries.append((objdir, basename))
 
 
 class TestManifest(SandboxDerived):
     """Represents a manifest file containing information about tests."""
 
     __slots__ = (
         # The type of test manifest this is.
         'flavor',
--- a/python/mozbuild/mozbuild/frontend/emitter.py
+++ b/python/mozbuild/mozbuild/frontend/emitter.py
@@ -82,46 +82,46 @@ class TreeMetadataEmitter(LoggingMixin):
         """
         file_count = 0
         execution_time = 0.0
         sandboxes = {}
 
         for out in output:
             if isinstance(out, MozbuildSandbox):
                 # Keep all sandboxes around, we will need them later.
-                sandboxes[out['RELATIVEDIR']] = out
+                sandboxes[out['OBJDIR']] = out
 
                 for o in self.emit_from_sandbox(out):
                     yield o
                     if not o._ack:
                         raise Exception('Unhandled object of type %s' % type(o))
 
                 # Update the stats.
                 file_count += len(out.all_paths)
                 execution_time += out.execution_time
 
             else:
                 raise Exception('Unhandled output type: %s' % out)
 
-        for reldir, libname, final_lib in self._final_libs:
+        for objdir, libname, final_lib in self._final_libs:
             if final_lib not in self._libs:
                 raise Exception('FINAL_LIBRARY in %s (%s) does not match any '
-                                'LIBRARY_NAME' % (reldir, final_lib))
+                                'LIBRARY_NAME' % (objdir, final_lib))
             libs = self._libs[final_lib]
             if len(libs) > 1:
                 raise Exception('FINAL_LIBRARY in %s (%s) matches a '
                                 'LIBRARY_NAME defined in multiple places (%s)' %
-                                (reldir, final_lib, ', '.join(libs.keys())))
-            libs.values()[0].link_static_lib(reldir, libname)
-            self._libs[libname][reldir].refcount += 1
+                                (objdir, final_lib, ', '.join(libs.keys())))
+            libs.values()[0].link_static_lib(objdir, libname)
+            self._libs[libname][objdir].refcount += 1
             # The refcount can't go above 1 right now. It might in the future,
             # but that will have to be specifically handled. At which point the
             # refcount might have to be a list of referencees, for better error
             # reporting.
-            assert self._libs[libname][reldir].refcount <= 1
+            assert self._libs[libname][objdir].refcount <= 1
 
         def recurse_libs(path, name):
             for p, n in self._libs[name][path].static_libraries:
                 yield p
                 for q in recurse_libs(p, n):
                     yield q
 
         for basename, libs in self._libs.items():
@@ -305,23 +305,23 @@ class TreeMetadataEmitter(LoggingMixin):
             yield InstallationTarget(sandbox)
 
         libname = sandbox.get('LIBRARY_NAME')
         final_lib = sandbox.get('FINAL_LIBRARY')
         if not libname and final_lib:
             # If no LIBRARY_NAME is given, create one.
             libname = sandbox['RELATIVEDIR'].replace('/', '_')
         if libname:
-            self._libs.setdefault(libname, {})[sandbox['RELATIVEDIR']] = \
+            self._libs.setdefault(libname, {})[sandbox['OBJDIR']] = \
                 LibraryDefinition(sandbox, libname)
 
         if final_lib:
             if sandbox.get('FORCE_STATIC_LIB'):
                 raise SandboxValidationError('FINAL_LIBRARY implies FORCE_STATIC_LIB')
-            self._final_libs.append((sandbox['RELATIVEDIR'], libname, final_lib))
+            self._final_libs.append((sandbox['OBJDIR'], libname, final_lib))
             passthru.variables['FORCE_STATIC_LIB'] = True
 
         # While there are multiple test manifests, the behavior is very similar
         # across them. We enforce this by having common handling of all
         # manifests and outputting a single class type with the differences
         # described inside the instance.
         #
         # Keys are variable prefixes and values are tuples describing how these
--- a/rdf/base/src/nsRDFService.cpp
+++ b/rdf/base/src/nsRDFService.cpp
@@ -134,17 +134,17 @@ struct ResourceHashEntry : public PLDHas
         const ResourceHashEntry *entry =
             static_cast<const ResourceHashEntry *>(hdr);
 
         return 0 == nsCRT::strcmp(static_cast<const char *>(key),
                                   entry->mKey);
     }
 };
 
-static PLDHashTableOps gResourceTableOps = {
+static const PLDHashTableOps gResourceTableOps = {
     PL_DHashAllocTable,
     PL_DHashFreeTable,
     ResourceHashEntry::HashKey,
     ResourceHashEntry::MatchEntry,
     PL_DHashMoveEntryStub,
     PL_DHashClearEntryStub,
     PL_DHashFinalizeStub,
     nullptr
@@ -172,17 +172,17 @@ struct LiteralHashEntry : public PLDHash
         const LiteralHashEntry *entry =
             static_cast<const LiteralHashEntry *>(hdr);
 
         return 0 == nsCRT::strcmp(static_cast<const PRUnichar *>(key),
                                   entry->mKey);
     }
 };
 
-static PLDHashTableOps gLiteralTableOps = {
+static const PLDHashTableOps gLiteralTableOps = {
     PL_DHashAllocTable,
     PL_DHashFreeTable,
     LiteralHashEntry::HashKey,
     LiteralHashEntry::MatchEntry,
     PL_DHashMoveEntryStub,
     PL_DHashClearEntryStub,
     PL_DHashFinalizeStub,
     nullptr
@@ -209,17 +209,17 @@ struct IntHashEntry : public PLDHashEntr
     {
         const IntHashEntry *entry =
             static_cast<const IntHashEntry *>(hdr);
 
         return *static_cast<const int32_t *>(key) == entry->mKey;
     }
 };
 
-static PLDHashTableOps gIntTableOps = {
+static const PLDHashTableOps gIntTableOps = {
     PL_DHashAllocTable,
     PL_DHashFreeTable,
     IntHashEntry::HashKey,
     IntHashEntry::MatchEntry,
     PL_DHashMoveEntryStub,
     PL_DHashClearEntryStub,
     PL_DHashFinalizeStub,
     nullptr
@@ -250,17 +250,17 @@ struct DateHashEntry : public PLDHashEnt
     {
         const DateHashEntry *entry =
             static_cast<const DateHashEntry *>(hdr);
 
         return *static_cast<const PRTime *>(key) == entry->mKey;
     }
 };
 
-static PLDHashTableOps gDateTableOps = {
+static const PLDHashTableOps gDateTableOps = {
     PL_DHashAllocTable,
     PL_DHashFreeTable,
     DateHashEntry::HashKey,
     DateHashEntry::MatchEntry,
     PL_DHashMoveEntryStub,
     PL_DHashClearEntryStub,
     PL_DHashFinalizeStub,
     nullptr
@@ -368,17 +368,17 @@ struct BlobHashEntry : public PLDHashEnt
         const BlobImpl::Data *right =
             static_cast<const BlobImpl::Data *>(key);
 
         return (left->mLength == right->mLength)
             && 0 == memcmp(left->mBytes, right->mBytes, right->mLength);
     }
 };
 
-static PLDHashTableOps gBlobTableOps = {
+static const PLDHashTableOps gBlobTableOps = {
     PL_DHashAllocTable,
     PL_DHashFreeTable,
     BlobHashEntry::HashKey,
     BlobHashEntry::MatchEntry,
     PL_DHashMoveEntryStub,
     PL_DHashClearEntryStub,
     PL_DHashFinalizeStub,
     nullptr
--- a/startupcache/moz.build
+++ b/startupcache/moz.build
@@ -13,15 +13,15 @@ XPIDL_SOURCES += [
 
 XPIDL_MODULE = 'startupcache'
 
 EXPORTS.mozilla.scache += [
     'StartupCache.h',
     'StartupCacheUtils.h',
 ]
 
-SOURCES += [
+UNIFIED_SOURCES += [
     'StartupCache.cpp',
     'StartupCacheModule.cpp',
     'StartupCacheUtils.cpp',
 ]
 
 FINAL_LIBRARY = 'xul'
--- a/storage/src/mozStorageService.cpp
+++ b/storage/src/mozStorageService.cpp
@@ -55,16 +55,20 @@
 #define PREF_TS_PAGESIZE_DEFAULT 32768
 
 namespace mozilla {
 namespace storage {
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Memory Reporting
 
+#ifdef MOZ_DMD
+static mozilla::Atomic<size_t> gSqliteMemoryUsed;
+#endif
+
 static int64_t
 StorageSQLiteDistinguishedAmount()
 {
   return ::sqlite3_memory_used();
 }
 
 class StorageSQLiteReporter MOZ_FINAL : public MemoryMultiReporter
 {
@@ -133,16 +137,23 @@ public:
                         SQLITE_DBSTATUS_CACHE_USED, &totalConnSize);
         NS_ENSURE_SUCCESS(rv, rv);
 
         rv = reportConn(aCb, aClosure, *conn.get(), pathHead,
                         NS_LITERAL_CSTRING("schema"), mSchemaDesc,
                         SQLITE_DBSTATUS_SCHEMA_USED, &totalConnSize);
         NS_ENSURE_SUCCESS(rv, rv);
       }
+
+#ifdef MOZ_DMD
+      if (::sqlite3_memory_used() != int64_t(gSqliteMemoryUsed)) {
+        NS_WARNING("memory consumption reported by SQLite doesn't match "
+                   "our measurements");
+      }
+#endif
     }
 
     int64_t other = ::sqlite3_memory_used() - totalConnSize;
 
     rv = aCb->Callback(NS_LITERAL_CSTRING(""),
                        NS_LITERAL_CSTRING("explicit/storage/sqlite/other"),
                        nsIMemoryReporter::KIND_HEAP,
                        nsIMemoryReporter::UNITS_BYTES, other,
@@ -382,50 +393,53 @@ namespace {
 // sqlite does its own memory accounting, and we use its numbers in our memory
 // reporters.  But we don't want sqlite's heap blocks to show up in DMD's
 // output as unreported, so we mark them as reported when they're allocated and
 // mark them as unreported when they are freed.
 //
 // In other words, we are marking all sqlite heap blocks as reported even
 // though we're not reporting them ourselves.  Instead we're trusting that
 // sqlite is fully and correctly accounting for all of its heap blocks via its
-// own memory accounting.
+// own memory accounting.  Well, we don't have to trust it entirely, because
+// it's easy to keep track (while doing this DMD-specific marking) of exactly
+// how much memory SQLite is using.  And we can compare that against what
+// SQLite reports it is using.
 
 NS_MEMORY_REPORTER_MALLOC_SIZEOF_ON_ALLOC_FUN(SqliteMallocSizeOfOnAlloc)
 NS_MEMORY_REPORTER_MALLOC_SIZEOF_ON_FREE_FUN(SqliteMallocSizeOfOnFree)
 
 #endif
 
 static void *sqliteMemMalloc(int n)
 {
   void* p = ::moz_malloc(n);
 #ifdef MOZ_DMD
-  SqliteMallocSizeOfOnAlloc(p);
+  gSqliteMemoryUsed += SqliteMallocSizeOfOnAlloc(p);
 #endif
   return p;
 }
 
 static void sqliteMemFree(void *p)
 {
 #ifdef MOZ_DMD
-  SqliteMallocSizeOfOnFree(p);
+  gSqliteMemoryUsed -= SqliteMallocSizeOfOnFree(p);
 #endif
   ::moz_free(p);
 }
 
 static void *sqliteMemRealloc(void *p, int n)
 {
 #ifdef MOZ_DMD
-  SqliteMallocSizeOfOnFree(p);
+  gSqliteMemoryUsed -= SqliteMallocSizeOfOnFree(p);
   void *pnew = ::moz_realloc(p, n);
   if (pnew) {
-    SqliteMallocSizeOfOnAlloc(pnew);
+    gSqliteMemoryUsed += SqliteMallocSizeOfOnAlloc(pnew);
   } else {
     // realloc failed;  undo the SqliteMallocSizeOfOnFree from above
-    SqliteMallocSizeOfOnAlloc(p);
+    gSqliteMemoryUsed += SqliteMallocSizeOfOnAlloc(p);
   }
   return pnew;
 #else
   return ::moz_realloc(p, n);
 #endif
 }
 
 static int sqliteMemSize(void *p)
--- a/toolkit/xre/nsWindowsDllInterceptor.h
+++ b/toolkit/xre/nsWindowsDllInterceptor.h
@@ -476,18 +476,20 @@ protected:
             // REG=r64, R/M=r64 or REG=r64, R/M=[r64]
             nBytes += 2;
           } else {
             // complex MOV
             return;
           }
         } else if (origBytes[nBytes] == 0xc7) {
           // MOV r/m64, imm32
-          if ((origBytes[nBytes + 1] & 0xf8) == 0x40) {
-            nBytes += 6;
+          if (origBytes[nBytes + 1] == 0x44) {
+            // MOV [r64+disp8], imm32
+            // ModR/W + SIB + disp8 + imm32
+            nBytes += 8;
           } else {
             return;
           }
         } else if (origBytes[nBytes] == 0xff) {
           pJmp32 = nBytes - 1;
           // JMP /4
           if ((origBytes[nBytes+1] & 0xc0) == 0x0 &&
               (origBytes[nBytes+1] & 0x07) == 0x5) {
--- a/uriloader/base/nsDocLoader.cpp
+++ b/uriloader/base/nsDocLoader.cpp
@@ -111,17 +111,17 @@ nsDocLoader::nsDocLoader()
     mIsFlushingLayout(false)
 {
 #if defined(PR_LOGGING)
   if (nullptr == gDocLoaderLog) {
       gDocLoaderLog = PR_NewLogModule("DocLoader");
   }
 #endif /* PR_LOGGING */
 
-  static PLDHashTableOps hash_table_ops =
+  static const PLDHashTableOps hash_table_ops =
   {
     PL_DHashAllocTable,
     PL_DHashFreeTable,
     PL_DHashVoidPtrKeyStub,
     PL_DHashMatchEntryStub,
     PL_DHashMoveEntryStub,
     RequestInfoHashClearEntry,
     PL_DHashFinalizeStub,
--- a/uriloader/exthandler/Makefile.in
+++ b/uriloader/exthandler/Makefile.in
@@ -37,16 +37,16 @@ LOCAL_INCLUDES += -I$(topsrcdir)/dom/bas
             -I$(topsrcdir)/netwerk/base/src \
             -I$(topsrcdir)/netwerk/protocol/http
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
 LOCAL_INCLUDES += -I$(srcdir)/win
 endif
 
 ifdef MOZ_ENABLE_DBUS
-LOCAL_INCLUDES   += $(TK_CFLAGS) $(MOZ_DBUS_CFLAGS)
+OS_INCLUDES   += $(TK_CFLAGS) $(MOZ_DBUS_CFLAGS)
 endif
 
 include $(topsrcdir)/config/rules.mk
 
 ifneq (,$(filter qt gtk2 gtk3, $(MOZ_WIDGET_TOOLKIT)))
 CXXFLAGS += $(TK_CFLAGS) $(MOZ_DBUS_GLIB_CFLAGS)
 endif
--- a/widget/windows/winrt/MetroInput.cpp
+++ b/widget/windows/winrt/MetroInput.cpp
@@ -891,26 +891,29 @@ MetroInput::OnTapped(UI::Input::IGesture
 {
 #ifdef DEBUG_INPUT
   LogFunction();
 #endif
 
   Devices::Input::PointerDeviceType deviceType;
   aArgs->get_PointerDeviceType(&deviceType);
 
+  unsigned int tapCount;
+  aArgs->get_TapCount(&tapCount);
+
   // For mouse and pen input, we send mousedown/mouseup/mousemove
   // events as soon as we detect the input event.  For touch input, a set of
   // mousedown/mouseup events will be sent only once a tap has been detected.
   if (deviceType != Devices::Input::PointerDeviceType::PointerDeviceType_Touch) {
     return S_OK;
   }
 
   Foundation::Point position;
   aArgs->get_Position(&position);
-  HandleSingleTap(position);
+  HandleTap(position, tapCount);
   return S_OK;
 }
 
 // This event is raised when a sequence of pointer events has been
 // interpreted by the GestureRecognizer as a right tap.
 // This could be a mouse right-click, a right-click on a pen, or
 // a tap-and-hold on a touch surface.
 HRESULT
@@ -927,69 +930,68 @@ MetroInput::OnRightTapped(UI::Input::IGe
   Foundation::Point position;
   aArgs->get_Position(&position);
   HandleLongTap(position);
 
   return S_OK;
 }
 
 void
-MetroInput::HandleSingleTap(const Foundation::Point& aPoint)
+MetroInput::HandleTap(const Foundation::Point& aPoint, unsigned int aTapCount)
 {
 #ifdef DEBUG_INPUT
   LogFunction();
 #endif
   
   LayoutDeviceIntPoint refPoint;
   TransformRefPoint(aPoint, refPoint);
 
   // send mousemove
   WidgetMouseEvent* mouseEvent =
     new WidgetMouseEvent(true, NS_MOUSE_MOVE, mWidget.Get(),
                          WidgetMouseEvent::eReal, WidgetMouseEvent::eNormal);
   mouseEvent->refPoint = refPoint;
-  mouseEvent->clickCount = 1;
+  mouseEvent->clickCount = aTapCount;
   mouseEvent->inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
   DispatchAsyncEventIgnoreStatus(mouseEvent);
 
   // Send the mousedown
   mouseEvent =
     new WidgetMouseEvent(true, NS_MOUSE_BUTTON_DOWN, mWidget.Get(),
                          WidgetMouseEvent::eReal, WidgetMouseEvent::eNormal);
   mouseEvent->refPoint = refPoint;
-  mouseEvent->clickCount = 1;
+  mouseEvent->clickCount = aTapCount;
   mouseEvent->inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
   mouseEvent->button = WidgetMouseEvent::buttonType::eLeftButton;
   DispatchAsyncEventIgnoreStatus(mouseEvent);
 
   mouseEvent =
     new WidgetMouseEvent(true, NS_MOUSE_BUTTON_UP, mWidget.Get(),
                          WidgetMouseEvent::eReal, WidgetMouseEvent::eNormal);
   mouseEvent->refPoint = refPoint;
-  mouseEvent->clickCount = 1;
+  mouseEvent->clickCount = aTapCount;
   mouseEvent->inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
   mouseEvent->button = WidgetMouseEvent::buttonType::eLeftButton;
   DispatchAsyncEventIgnoreStatus(mouseEvent);
 
   // Send one more mousemove to avoid getting a hover state.
   // In the Metro environment for any application, a tap does not imply a
   // mouse cursor move.  In desktop environment for any application a tap
   // does imply a cursor move.
   POINT point;
   if (GetCursorPos(&point)) {
     ScreenToClient((HWND)mWidget->GetNativeData(NS_NATIVE_WINDOW), &point);
     mouseEvent =
       new WidgetMouseEvent(true, NS_MOUSE_MOVE, mWidget.Get(),
                            WidgetMouseEvent::eReal, WidgetMouseEvent::eNormal);
     mouseEvent->refPoint = LayoutDeviceIntPoint(point.x, point.y);
-    mouseEvent->clickCount = 1;
+    mouseEvent->clickCount = aTapCount;
     mouseEvent->inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
     DispatchAsyncEventIgnoreStatus(mouseEvent);
   }
-
 }
 
 void
 MetroInput::HandleLongTap(const Foundation::Point& aPoint)
 {
 #ifdef DEBUG_INPUT
   LogFunction();
 #endif
--- a/widget/windows/winrt/MetroInput.h
+++ b/widget/windows/winrt/MetroInput.h
@@ -137,17 +137,17 @@ public:
   HRESULT OnManipulationCompleted(IGestureRecognizer* aSender,
                                   IManipulationCompletedEventArgs* aArgs);
 
   // Tap gesture callback from the GestureRecognizer.
   HRESULT OnTapped(IGestureRecognizer* aSender, ITappedEventArgs* aArgs);
   HRESULT OnRightTapped(IGestureRecognizer* aSender,
                         IRightTappedEventArgs* aArgs);
 
-  void HandleSingleTap(const Point& aPoint);
+  void HandleTap(const Point& aPoint, unsigned int aTapCount);
   void HandleLongTap(const Point& aPoint);
 
 private:
   Microsoft::WRL::ComPtr<ICoreWindow> mWindow;
   Microsoft::WRL::ComPtr<MetroWidget> mWidget;
   Microsoft::WRL::ComPtr<IGestureRecognizer> mGestureRecognizer;
 
   ModifierKeyState mModifierKeyState;
--- a/widget/windows/winrt/MetroWidget.cpp
+++ b/widget/windows/winrt/MetroWidget.cpp
@@ -273,16 +273,17 @@ MetroWidget::Destroy()
 
   nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
 
   if (ShouldUseAPZC()) {
     nsresult rv;
     nsCOMPtr<nsIObserverService> observerService = do_GetService("@mozilla.org/observer-service;1", &rv);
     if (NS_SUCCEEDED(rv)) {
       observerService->RemoveObserver(this, "apzc-scroll-offset-changed");
+      observerService->RemoveObserver(this, "Metro:ZoomToRect");
     }
   }
 
   RemoveSubclass();
   NotifyWindowDestroyed();
 
   // Prevent the widget from sending additional events.
   mWidgetListener = nullptr;
@@ -961,16 +962,17 @@ CompositorParent* MetroWidget::NewCompos
 
     APZController::sAPZC = CompositorParent::GetAPZCTreeManager(compositor->RootLayerTreeId());
     APZController::sAPZC->SetDPI(GetDPI());
 
     nsresult rv;
     nsCOMPtr<nsIObserverService> observerService = do_GetService("@mozilla.org/observer-service;1", &rv);
     if (NS_SUCCEEDED(rv)) {
       observerService->AddObserver(this, "apzc-scroll-offset-changed", false);
+      observerService->AddObserver(this, "Metro:ZoomToRect", false);
     }
   }
 
   return compositor;
 }
 
 void
 MetroWidget::ApzContentConsumingTouch(const ScrollableLayerGuid& aGuid)
@@ -1556,10 +1558,27 @@ MetroWidget::Observe(nsISupports *subjec
       return NS_ERROR_UNEXPECTED;
     }
     if (!mController) {
       return NS_ERROR_UNEXPECTED;
     }
     mController->UpdateScrollOffset(ScrollableLayerGuid(mRootLayerTreeId, presShellId, scrollId),
                                     scrollOffset);
   }
-  return NS_OK;
+  else if (!strcmp(topic, "Metro:ZoomToRect")) {
+    CSSRect rect = CSSRect();
+    uint64_t viewId = 0;
+    int32_t presShellId = 0;
+
+    int reScan = swscanf(data, L"%f,%f,%f,%f,%d,%llu",
+                 &rect.x, &rect.y, &rect.width, &rect.height,
+                 &presShellId, &viewId);
+    if(reScan != 6) {
+      NS_WARNING("Malformed Metro:ZoomToRect message");
+    }
+
+    ScrollableLayerGuid guid = ScrollableLayerGuid(mRootLayerTreeId, presShellId, viewId);
+    APZController::sAPZC->ZoomToRect(guid, rect);
+  }
+  else {
+    return NS_OK;
+  }
 }
--- a/xpcom/base/moz.build
+++ b/xpcom/base/moz.build
@@ -81,17 +81,17 @@ EXPORTS.mozilla += [
     'VisualEventTracer.h',
 ]
 
 if CONFIG['OS_ARCH'] == 'WINNT':
     EXPORTS.mozilla += [
         'WindowsVersion.h',
     ]
 
-SOURCES += [
+UNIFIED_SOURCES += [
     'AvailableMemoryTracker.cpp',
     'ClearOnShutdown.cpp',
     'CycleCollectedJSRuntime.cpp',
     'Debug.cpp',
     'nsConsoleMessage.cpp',
     'nsConsoleService.cpp',
     'nsCycleCollector.cpp',
     'nsDebugImpl.cpp',
@@ -115,17 +115,17 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'coco
     SOURCES += [
         'nsMacUtilsImpl.cpp',
     ]
 elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
     SOURCES += [
         'nsCrashOnException.cpp',
     ]
 
-SOURCES += [
+UNIFIED_SOURCES += [
     'nsErrorAssertsC.c',
 ]
 
 
 
 MSVC_ENABLE_PGO = True
 
 include('/ipc/chromium/chromium-config.mozbuild')
--- a/xpcom/base/nsGZFileWriter.h
+++ b/xpcom/base/nsGZFileWriter.h
@@ -1,14 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#ifndef nsGZFileWriter_h
+#define nsGZFileWriter_h
+
 #include "nsIGZFileWriter.h"
 #include "zlib.h"
 
 /**
  * A simple class for writing .gz files.
  */
 class nsGZFileWriter : public nsIGZFileWriter
 {
@@ -34,8 +37,10 @@ public:
     return nsIGZFileWriter::Write(aStr, aLen);
   }
 
 private:
   bool mInitialized;
   bool mFinished;
   gzFile mGZFile;
 };
+
+#endif
--- a/xpcom/build/FileLocation.h
+++ b/xpcom/build/FileLocation.h
@@ -4,17 +4,16 @@
 
 #ifndef mozilla_FileLocation_h
 #define mozilla_FileLocation_h
 
 #include "nsString.h"
 #include "nsCOMPtr.h"
 #include "nsAutoPtr.h"
 #include "nsIFile.h"
-#include "nsIURI.h"
 #include "FileUtils.h"
 
 class nsZipArchive;
 class nsZipItem;
 
 namespace mozilla {
 
 class FileLocation
--- a/xpcom/build/moz.build
+++ b/xpcom/build/moz.build
@@ -39,20 +39,20 @@ elif CONFIG['OS_ARCH'] == 'Darwin' and C
         'PoisonIOInterposerBase.cpp',
         'PoisonIOInterposerMac.cpp',
     ]
 else:
     SOURCES += ['PoisonIOInterposerStub.cpp']
 
 include('../glue/objs.mozbuild')
 
-SOURCES += xpcom_gluens_src_cppsrcs
-SOURCES += xpcom_glue_src_cppsrcs
+UNIFIED_SOURCES += xpcom_gluens_src_cppsrcs
+UNIFIED_SOURCES += xpcom_glue_src_cppsrcs
 
-SOURCES += [
+UNIFIED_SOURCES += [
     'FileLocation.cpp',
     'FrozenFunctions.cpp',
     'LateWriteChecks.cpp',
     'nsXPComInit.cpp',
     'nsXPCOMStrings.cpp',
     'Omnijar.cpp',
     'Services.cpp',
 ]
--- a/xpcom/components/moz.build
+++ b/xpcom/components/moz.build
@@ -21,18 +21,23 @@ EXPORTS += [
 ]
 
 EXPORTS.mozilla += [
     'Module.h',
     'ModuleLoader.h',
     'ModuleUtils.h',
 ]
 
+# These two files cannot be built in unified mode because they use the
+# PL_ARENA_CONST_ALIGN_MASK macro with plarena.h.
 SOURCES += [
-    'ManifestParser.cpp',
     'nsCategoryManager.cpp',
     'nsComponentManager.cpp',
+]
+
+UNIFIED_SOURCES += [
+    'ManifestParser.cpp',
     'nsNativeComponentLoader.cpp',
 ]
 
 MSVC_ENABLE_PGO = True
 
 FINAL_LIBRARY = 'xpcom_core'
--- a/xpcom/components/nsComponentManager.cpp
+++ b/xpcom/components/nsComponentManager.cpp
@@ -60,19 +60,22 @@
 #include "nsTArray.h"
 #include "prio.h"
 #include "ManifestParser.h"
 #include "mozilla/Services.h"
 
 #include "nsManifestLineReader.h"
 #include "mozilla/GenericFactory.h"
 #include "nsSupportsPrimitives.h"
+#include "nsArray.h"
+#include "nsIMutableArray.h"
 #include "nsArrayEnumerator.h"
 #include "nsStringEnumerator.h"
 #include "mozilla/FileUtils.h"
+#include "nsNetUtil.h"
 
 #include <new>     // for placement new
 
 #include "mozilla/Omnijar.h"
 
 #include "prlog.h"
 
 using namespace mozilla;
@@ -1909,16 +1912,42 @@ nsComponentManagerImpl::RemoveBootstrapp
 
   // Remove reference.
   nsComponentManagerImpl::sModuleLocations->RemoveElement(elem, ComponentLocationComparator());
 
   rv = cr->CheckForNewChrome();
   return rv;
 }
 
+NS_IMETHODIMP
+nsComponentManagerImpl::GetManifestLocations(nsIArray **aLocations)
+{
+  NS_ENSURE_ARG_POINTER(aLocations);
+  *aLocations = nullptr;
+
+  if (!sModuleLocations)
+    return NS_ERROR_NOT_INITIALIZED;
+
+  nsCOMPtr<nsIMutableArray> locations = nsArray::Create();
+  nsresult rv;
+  for (uint32_t i = 0; i < sModuleLocations->Length(); ++i) {
+    ComponentLocation& l = sModuleLocations->ElementAt(i);
+    FileLocation loc = l.location;
+    nsCString uriString;
+    loc.GetURIString(uriString);
+    nsCOMPtr<nsIURI> uri;
+    rv = NS_NewURI(getter_AddRefs(uri), uriString);
+    if (NS_SUCCEEDED(rv))
+      locations->AppendElement(uri, false);
+  }
+
+  locations.forget(aLocations);
+  return NS_OK;
+}
+
 EXPORT_XPCOM_API(nsresult)
 XRE_AddManifestLocation(NSLocationType aType, nsIFile* aLocation)
 {
     nsComponentManagerImpl::InitializeModuleLocations();
     nsComponentManagerImpl::ComponentLocation* c = 
         nsComponentManagerImpl::sModuleLocations->AppendElement();
     c->type = aType;
     c->location.Init(aLocation);
--- a/xpcom/components/nsIComponentManager.idl
+++ b/xpcom/components/nsIComponentManager.idl
@@ -1,25 +1,26 @@
 /* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-  
+
 /**
  * The nsIComponentManager interface.
  */
 
 #include "nsISupports.idl"
 
 interface nsIFile;
 interface nsIFactory;
+interface nsIArray;
 
-[scriptable, uuid(1d940426-5fe5-42c3-84ae-a300f2d9ebd5)]
+[scriptable, uuid(d604ffc3-1ba3-4f6c-b65f-1ed4199364c3)]
 interface nsIComponentManager : nsISupports
-{    
+{
     /**
      * getClassObject
      *
      * Returns the factory object that can be used to create instances of
      * CID aClass
      *
      * @param aClass The classid of the factory that is being requested
      */
@@ -84,16 +85,22 @@ interface nsIComponentManager : nsISuppo
      *
      * Removes a bootstrapped manifest location on runtime.
      *
      * @param aLocation : A directory where chrome.manifest resides,
      *                    or an XPI with it on the root.
      */
     void removeBootstrappedManifestLocation(in nsIFile aLocation);
 
+    /**
+     * getManifestLocations
+     *
+     * Get an array of nsIURIs of all registered and builtin manifest locations.
+     */
+    nsIArray getManifestLocations();
 };
 
 
 %{ C++
 #ifdef MOZILLA_INTERNAL_API
 #include "nsComponentManagerUtils.h"
 #endif
 %} C++
--- a/xpcom/ds/moz.build
+++ b/xpcom/ds/moz.build
@@ -65,37 +65,42 @@ EXPORTS += [
 ]
 
 EXPORTS.mozilla += [
     'CharTokenizer.h',
     'StringBuilder.h',
     'TimeStamp.h',
 ]
 
-SOURCES += [
+UNIFIED_SOURCES += [
     'nsArray.cpp',
     'nsAtomService.cpp',
     'nsAtomTable.cpp',
     'nsCRT.cpp',
     'nsHashPropertyBag.cpp',
     'nsHashtable.cpp',
     'nsINIParserImpl.cpp',
     'nsObserverList.cpp',
     'nsObserverService.cpp',
-    'nsPersistentProperties.cpp',
     'nsProperties.cpp',
-    'nsStaticNameTable.cpp',
     'nsStringEnumerator.cpp',
     'nsSupportsArray.cpp',
     'nsSupportsArrayEnumerator.cpp',
     'nsSupportsPrimitives.cpp',
     'nsVariant.cpp',
     'TimeStamp.cpp',
 ]
 
+# These two files cannot be built in unified mode because they use the
+# PL_ARENA_CONST_ALIGN_MASK macro with plarena.h.
+SOURCES += [
+    'nsPersistentProperties.cpp',
+    'nsStaticNameTable.cpp',
+]
+
 if CONFIG['OS_ARCH'] == 'WINNT':
     SOURCES += [
         'TimeStamp_windows.cpp',
     ]
 elif CONFIG['HAVE_CLOCK_MONOTONIC']:
     SOURCES += [
         'TimeStamp_posix.cpp',
     ]
--- a/xpcom/ds/nsWindowsRegKey.cpp
+++ b/xpcom/ds/nsWindowsRegKey.cpp
@@ -282,28 +282,33 @@ nsWindowsRegKey::ReadStringValue(const n
   // The buffer size must be a multiple of 2.
   NS_ENSURE_STATE(size % 2 == 0);
 
   if (size == 0) {
     result.Truncate();
     return NS_OK;
   }
 
-  // |size| includes room for the terminating null character
-  DWORD resultLen = size / 2 - 1;
+  // |size| may or may not include the terminating null character.
+  DWORD resultLen = size / 2;
 
   result.SetLength(resultLen);
   nsAString::iterator begin;
   result.BeginWriting(begin);
   if (begin.size_forward() != resultLen)
     return NS_ERROR_OUT_OF_MEMORY;
 
   rv = RegQueryValueExW(mKey, flatName.get(), 0, &type, (LPBYTE) begin.get(),
                         &size);
 
+  if (!result.CharAt(resultLen-1)) {
+    // The string passed to us had a null terminator in the final position.
+    result.Truncate(resultLen-1);
+  }
+