Merge inbound to m-c a=merge
authorWes Kocher <wkocher@mozilla.com>
Fri, 24 Oct 2014 15:05:02 -0700
changeset 212260 c70f62375f7d496edee7ebd2535fce746500e96c
parent 212216 be08d039123b9a62241fe114072a6d52847a8c8a (current diff)
parent 212259 5fcda0c427935b3ead2b8e8cbfab2374efc7562d (diff)
child 212270 e8a6f40728b76f6388b01b890a21bbd9c78b829d
child 212323 6a37732cb6b219176e41d6e6eb60a000037da18c
child 212327 fce4cd8717a4d23bd45aa555e472f4fa12c349b5
push id27702
push userkwierso@gmail.com
push dateFri, 24 Oct 2014 22:05:50 +0000
treeherdermozilla-central@c70f62375f7d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone36.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to m-c a=merge
content/base/test/mochitest.ini
--- a/accessible/tests/mochitest/text/test_hypertext.html
+++ b/accessible/tests/mochitest/text/test_hypertext.html
@@ -1,16 +1,19 @@
 <!DOCTYPE html>
 <html>
 <head>
   <title>nsIAccessibleText getText related function tests for rich text</title>
   <link rel="stylesheet" type="text/css"
         href="chrome://mochikit/content/tests/SimpleTest/test.css" />
 
   <style>
+    #listitemnone {
+      list-style-type: none;
+    }
     h6.gencontent:before {
       content: "aga"
     }
   </style>
 
   <script type="application/javascript"
           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <script type="application/javascript"
@@ -62,23 +65,27 @@
       testTextAtOffset(0, BOUNDARY_LINE_START, "line ", 0, 5,
                        "hypertext4", kTodo, kOk, kTodo);
 
       //////////////////////////////////////////////////////////////////////////
       // list
       //////////////////////////////////////////////////////////////////////////
 
       IDs = [ "list" ];
-      testCharacterCount(IDs, 1);
-      testText(IDs, 0, 1, kEmbedChar);
+      testCharacterCount(IDs, 2);
+      testText(IDs, 0, 2, kEmbedChar + kEmbedChar);
 
       IDs = [ "listitem" ];
       testCharacterCount(IDs, 6);
       testText(IDs, 0, 6, "1. foo");
 
+      IDs = [ "listitemnone" ];
+      testCharacterCount(IDs, 3);
+      testText(IDs, 0, 3, "bar");
+
       testText(["testbr"], 0, 3, "foo");
 
       testTextAtOffset(2, nsIAccessibleText.BOUNDARY_CHAR, "o", 2, 3, "testbr",
                        kOk, kOk, kOk);
       testTextAtOffset(2, nsIAccessibleText.BOUNDARY_WORD_START, "foo\n", 0, 4,
                        "testbr", kTodo, kOk, kTodo);
       testTextBeforeOffset(2, nsIAccessibleText.BOUNDARY_LINE_START, "foo\n",
                            0, 4, "testbr", kTodo, kOk, kTodo);
@@ -112,17 +119,20 @@
   <div id="content" style="display: none"></div>
   <pre id="test">
   </pre>
 
   <div id="nulltext"></div>
 
   <div id="hypertext">hello <a>friend</a> see <img></div>
   <div id="hypertext2">hello <a>friend</a> see <input></div>
-  <ol id="list"><li id="listitem">foo</li></ol>
+  <ol id="list">
+    <li id="listitem">foo</li>
+    <li id="listitemnone">bar</li>
+  </ol>
 
   <div id="hypertext3">line
 <!-- haha -->
 <!-- hahaha -->
 <h6>heading</h6>
   </div>
 
   <div id="hypertext4">line
--- a/addon-sdk/source/lib/sdk/deprecated/unit-test.js
+++ b/addon-sdk/source/lib/sdk/deprecated/unit-test.js
@@ -57,17 +57,18 @@ TestRunner.prototype = {
 
   _logTestFailed: function _logTestFailed(why) {
     if (!(why in this.test.errors))
       this.test.errors[why] = 0;
     this.test.errors[why]++;
   },
 
   _uncaughtErrorObserver: function({message, date, fileName, stack, lineNumber}) {
-    this.fail("There was an uncaught Promise rejection: " + stack);
+    this.fail("There was an uncaught Promise rejection: " + message + " @ " +
+              fileName + ":" + lineNumber + "\n" + stack);
   },
 
   pass: function pass(message) {
     if(!this.expectFailure) {
       if ("testMessage" in this.console)
         this.console.testMessage(true, true, this.test.name, message);
       else
         this.console.info("pass:", message);
--- a/browser/base/content/pageinfo/security.js
+++ b/browser/base/content/pageinfo/security.js
@@ -47,40 +47,59 @@ var security = {
       var issuerName =
         this.mapIssuerOrganization(cert.issuerOrganization) || cert.issuerName;
 
       var retval = {
         hostName : hName,
         cAName : issuerName,
         encryptionAlgorithm : undefined,
         encryptionStrength : undefined,
+        version: undefined,
         isBroken : isBroken,
         isEV : isEV,
         cert : cert,
         fullLocation : gWindow.location
       };
 
+      var version;
       try {
         retval.encryptionAlgorithm = status.cipherName;
         retval.encryptionStrength = status.secretKeyLength;
+        version = status.protocolVersion;
       }
       catch (e) {
       }
 
+      switch (version) {
+        case nsISSLStatus.SSL_VERSION_3:
+          retval.version = "SSL 3";
+          break;
+        case nsISSLStatus.TLS_VERSION_1:
+          retval.version = "TLS 1.0";
+          break;
+        case nsISSLStatus.TLS_VERSION_1_1:
+          retval.version = "TLS 1.1";
+          break;
+        case nsISSLStatus.TLS_VERSION_1_2:
+          retval.version = "TLS 1.2"
+          break;
+      }
+
       return retval;
     } else {
       return {
         hostName : hName,
         cAName : "",
         encryptionAlgorithm : "",
         encryptionStrength : 0,
+        version: "",
         isBroken : isBroken,
         isEV : isEV,
         cert : null,
-        fullLocation : gWindow.location        
+        fullLocation : gWindow.location
       };
     }
   },
 
   // Find the secureBrowserUI object (if present)
   _getSecurityUI : function() {
     if (window.opener.gBrowser)
       return window.opener.gBrowser.securityUI;
@@ -234,25 +253,29 @@ function securityOnLoad() {
   var msg2;
 
   if (info.isBroken) {
     hdr = pkiBundle.getString("pageInfo_MixedContent");
     msg1 = pkiBundle.getString("pageInfo_Privacy_Mixed1");
     msg2 = pkiBundle.getString("pageInfo_Privacy_None2");
   }
   else if (info.encryptionStrength >= 90) {
-    hdr = pkiBundle.getFormattedString("pageInfo_StrongEncryptionWithBits",
-                                       [info.encryptionAlgorithm, info.encryptionStrength + ""]);
+    hdr = pkiBundle.getFormattedString("pageInfo_StrongEncryptionWithBitsAndProtocol",
+                                       [info.encryptionAlgorithm,
+                                        info.encryptionStrength + "",
+                                        info.version]);
     msg1 = pkiBundle.getString("pageInfo_Privacy_Strong1");
     msg2 = pkiBundle.getString("pageInfo_Privacy_Strong2");
     security._cert = info.cert;
   }
   else if (info.encryptionStrength > 0) {
-    hdr  = pkiBundle.getFormattedString("pageInfo_WeakEncryptionWithBits",
-                                        [info.encryptionAlgorithm, info.encryptionStrength + ""]);
+    hdr  = pkiBundle.getFormattedString("pageInfo_WeakEncryptionWithBitsAndProtocol",
+                                        [info.encryptionAlgorithm,
+                                         info.encryptionStrength + "",
+                                         info.version]);
     msg1 = pkiBundle.getFormattedString("pageInfo_Privacy_Weak1", [info.hostName]);
     msg2 = pkiBundle.getString("pageInfo_Privacy_Weak2");
   }
   else {
     hdr = pkiBundle.getString("pageInfo_NoEncryption");
     if (info.hostName != null)
       msg1 = pkiBundle.getFormattedString("pageInfo_Privacy_None1", [info.hostName]);
     else
--- a/content/base/public/nsIScriptElement.h
+++ b/content/base/public/nsIScriptElement.h
@@ -23,17 +23,17 @@
 /**
  * Internal interface implemented by script elements
  */
 class nsIScriptElement : public nsIScriptLoaderObserver {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ISCRIPTELEMENT_IID)
 
   explicit nsIScriptElement(mozilla::dom::FromParser aFromParser)
-    : mLineNumber(0),
+    : mLineNumber(1),
       mAlreadyStarted(false),
       mMalformed(false),
       mDoneAddingChildren(aFromParser == mozilla::dom::NOT_FROM_PARSER ||
                           aFromParser == mozilla::dom::FROM_PARSER_FRAGMENT),
       mForceAsync(aFromParser == mozilla::dom::NOT_FROM_PARSER ||
                   aFromParser == mozilla::dom::FROM_PARSER_FRAGMENT),
       mFrozen(false),
       mDefer(false),
--- a/content/base/test/mochitest.ini
+++ b/content/base/test/mochitest.ini
@@ -552,16 +552,17 @@ skip-if = buildapp == 'mulet' || buildap
 [test_bug895239.html]
 [test_bug895974.html]
 [test_bug902847.html]
 [test_bug907892.html]
 [test_bug922681.html]
 [test_bug927196.html]
 [test_bug945152.html]
 run-if = os == 'linux'
+[test_bug982153.html]
 [test_bug1008126.html]
 run-if = os == 'linux'
 [test_bug1057176.html]
 [test_caretPositionFromPoint.html]
 [test_classList.html]
 # This test fails on the Mac for some reason
 [test_copyimage.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') || toolkit != 'gtk2' && toolkit != 'gtk3' && toolkit != 'windows' || e10s #b2g-desktop(Bug 931116, b2g desktop specific, initial triage)
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_bug982153.html
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=982153
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 982153</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script>
+
+var sc = document.createElement("script");
+var error = null;
+sc.textContent = "try {\n reference_error; } catch(e) { error = e; }";
+document.documentElement.appendChild(sc);
+is(error.lineNumber, 2, "Error line number must be correct");
+
+  </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=982153">Mozilla Bug 982153</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
--- a/content/media/webrtc/MediaEngine.h
+++ b/content/media/webrtc/MediaEngine.h
@@ -225,16 +225,20 @@ private:
 class MediaEngineVideoSource : public MediaEngineSource
 {
 public:
   virtual ~MediaEngineVideoSource() {}
 
   /* This call reserves but does not start the device. */
   virtual nsresult Allocate(const VideoTrackConstraintsN &aConstraints,
                             const MediaEnginePrefs &aPrefs) = 0;
+
+  virtual bool SatisfiesConstraintSets(
+      const nsTArray<const dom::MediaTrackConstraintSet*>& aConstraintSets) = 0;
+
 protected:
   explicit MediaEngineVideoSource(MediaEngineState aState)
     : MediaEngineSource(aState) {}
   MediaEngineVideoSource()
     : MediaEngineSource(kReleased) {}
 };
 
 /**
--- a/content/media/webrtc/MediaEngineCameraVideoSource.cpp
+++ b/content/media/webrtc/MediaEngineCameraVideoSource.cpp
@@ -1,16 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "MediaEngineCameraVideoSource.h"
 
 namespace mozilla {
 
+using namespace mozilla::gfx;
 using dom::ConstrainLongRange;
 using dom::ConstrainDoubleRange;
 using dom::MediaTrackConstraintSet;
 
 #ifdef PR_LOGGING
 extern PRLogModuleInfo* GetMediaManagerLog();
 #define LOG(msg) PR_LOG(GetMediaManagerLog(), PR_LOG_DEBUG, msg)
 #define LOGFRAME(msg) PR_LOG(GetMediaManagerLog(), 6, msg)
@@ -42,16 +43,36 @@ MediaEngineCameraVideoSource::AreInterse
 /* static */ bool
 MediaEngineCameraVideoSource::Intersect(ConstrainLongRange& aA, const ConstrainLongRange& aB) {
   MOZ_ASSERT(AreIntersecting(aA, aB));
   aA.mMin = std::max(aA.mMin, aB.mMin);
   aA.mMax = std::min(aA.mMax, aB.mMax);
   return true;
 }
 
+// guts for appending data to the MSG track
+bool MediaEngineCameraVideoSource::AppendToTrack(SourceMediaStream* aSource,
+                                                 layers::Image* aImage,
+                                                 TrackID aID,
+                                                 TrackTicks delta)
+{
+  MOZ_ASSERT(aSource);
+
+  VideoSegment segment;
+  nsRefPtr<layers::Image> image = aImage;
+  IntSize size(image ? mWidth : 0, image ? mHeight : 0);
+  segment.AppendFrame(image.forget(), delta, size);
+
+  // This is safe from any thread, and is safe if the track is Finished
+  // or Destroyed.
+  // This can fail if either a) we haven't added the track yet, or b)
+  // we've removed or finished the track.
+  return aSource->AppendToTrack(aID, &(segment));
+}
+
 // A special version of the algorithm for cameras that don't list capabilities.
 void
 MediaEngineCameraVideoSource::GuessCapability(
     const VideoTrackConstraintsN& aConstraints,
     const MediaEnginePrefs& aPrefs)
 {
   LOG(("GuessCapability: prefs: %dx%d @%d-%dfps",
        aPrefs.mWidth, aPrefs.mHeight, aPrefs.mFPS, aPrefs.mMinFPS));
--- a/content/media/webrtc/MediaEngineCameraVideoSource.h
+++ b/content/media/webrtc/MediaEngineCameraVideoSource.h
@@ -23,16 +23,17 @@ public:
                                const char* aMonitorName = "Camera.Monitor")
     : MediaEngineVideoSource(kReleased)
     , mMonitor(aMonitorName)
     , mWidth(0)
     , mHeight(0)
     , mInitDone(false)
     , mHasDirectListeners(false)
     , mCaptureIndex(aIndex)
+    , mTrackID(0)
     , mFps(-1)
   {}
 
 
   virtual void GetName(nsAString& aName) MOZ_OVERRIDE;
   virtual void GetUUID(nsAString& aUUID) MOZ_OVERRIDE;
   virtual void SetDirectListeners(bool aHasListeners) MOZ_OVERRIDE;
   virtual nsresult Config(bool aEchoOn, uint32_t aEcho,
@@ -55,16 +56,22 @@ public:
   virtual nsresult TakePhoto(PhotoCallback* aCallback) MOZ_OVERRIDE
   {
     return NS_ERROR_NOT_IMPLEMENTED;
   }
 
 protected:
   ~MediaEngineCameraVideoSource() {}
 
+  // guts for appending data to the MSG track
+  virtual bool AppendToTrack(SourceMediaStream* aSource,
+                             layers::Image* aImage,
+                             TrackID aID,
+                             TrackTicks delta);
+
   static bool IsWithin(int32_t n, const dom::ConstrainLongRange& aRange);
   static bool IsWithin(double n, const dom::ConstrainDoubleRange& aRange);
   static int32_t Clamp(int32_t n, const dom::ConstrainLongRange& aRange);
   static bool AreIntersecting(const dom::ConstrainLongRange& aA,
                               const dom::ConstrainLongRange& aB);
   static bool Intersect(dom::ConstrainLongRange& aA, const dom::ConstrainLongRange& aB);
   void GuessCapability(const VideoTrackConstraintsN& aConstraints,
                        const MediaEnginePrefs& aPrefs);
@@ -82,16 +89,17 @@ protected:
   int mWidth, mHeight; // protected with mMonitor on Gonk due to different threading
   // end of data protected by mMonitor
 
   nsTArray<SourceMediaStream*> mSources; // When this goes empty, we shut down HW
 
   bool mInitDone;
   bool mHasDirectListeners;
   int mCaptureIndex;
+  TrackID mTrackID;
   int mFps; // Track rate (30 fps by default)
 
   webrtc::CaptureCapability mCapability; // Doesn't work on OS X.
 
   nsString mDeviceName;
   nsString mUniqueId;
 };
 
--- a/content/media/webrtc/MediaEngineDefault.h
+++ b/content/media/webrtc/MediaEngineDefault.h
@@ -50,16 +50,21 @@ public:
                           bool aAgcOn, uint32_t aAGC,
                           bool aNoiseOn, uint32_t aNoise,
                           int32_t aPlayoutDelay) { return NS_OK; };
   virtual void NotifyPull(MediaStreamGraph* aGraph,
                           SourceMediaStream *aSource,
                           TrackID aId,
                           StreamTime aDesiredTime,
                           TrackTicks &aLastEndTime);
+  virtual bool SatisfiesConstraintSets(
+      const nsTArray<const dom::MediaTrackConstraintSet*>& aConstraintSets)
+  {
+    return true;
+  }
 
   virtual bool IsFake() {
     return true;
   }
 
   virtual const MediaSourceType GetMediaSource() {
     return MediaSourceType::Camera;
   }
--- a/content/media/webrtc/MediaEngineGonkVideoSource.cpp
+++ b/content/media/webrtc/MediaEngineGonkVideoSource.cpp
@@ -149,16 +149,17 @@ MediaEngineGonkVideoSource::Start(Source
   aStream->AddTrack(aID, USECS_PER_S, 0, new VideoSegment());
   aStream->AdvanceKnownTracksTime(STREAM_TIME_MAX);
 
   ReentrantMonitorAutoEnter sync(mCallbackMonitor);
 
   if (mState == kStarted) {
     return NS_OK;
   }
+  mTrackID = aID;
   mImageContainer = layers::LayerManager::CreateImageContainer();
 
   NS_DispatchToMainThread(WrapRunnable(nsRefPtr<MediaEngineGonkVideoSource>(this),
                                        &MediaEngineGonkVideoSource::StartImpl,
                                        mCapability));
   mCallbackMonitor.Wait();
   if (mState != kStarted) {
     return NS_ERROR_FAILURE;
@@ -616,16 +617,31 @@ MediaEngineGonkVideoSource::RotateImage(
   data.mPicY = 0;
   data.mPicSize = IntSize(dstWidth, dstHeight);
   data.mStereoMode = StereoMode::MONO;
 
   videoImage->SetDataNoCopy(data);
 
   // implicitly releases last image
   mImage = image.forget();
+
+  // Push the frame into the MSG with a minimal duration.  This will likely
+  // mean we'll still get NotifyPull calls which will then return the same
+  // frame again with a longer duration.  However, this means we won't
+  // fail to get the frame in and drop frames.
+
+  // XXX The timestamp for the frame should be base on the Capture time,
+  // not the MSG time, and MSG should never, ever block on a (realtime)
+  // video frame (or even really for streaming - audio yes, video probably no).
+  uint32_t len = mSources.Length();
+  for (uint32_t i = 0; i < len; i++) {
+    if (mSources[i]) {
+      AppendToTrack(mSources[i], mImage, mTrackID, 1); // shortest possible duration
+    }
+  }
 }
 
 bool
 MediaEngineGonkVideoSource::OnNewPreviewFrame(layers::Image* aImage, uint32_t aWidth, uint32_t aHeight) {
   {
     ReentrantMonitorAutoEnter sync(mCallbackMonitor);
     if (mState == kStopped) {
       return false;
--- a/content/media/webrtc/MediaEngineGonkVideoSource.h
+++ b/content/media/webrtc/MediaEngineGonkVideoSource.h
@@ -59,16 +59,21 @@ public:
   virtual nsresult Deallocate() MOZ_OVERRIDE;
   virtual nsresult Start(SourceMediaStream* aStream, TrackID aID) MOZ_OVERRIDE;
   virtual nsresult Stop(SourceMediaStream* aSource, TrackID aID) MOZ_OVERRIDE;
   virtual void NotifyPull(MediaStreamGraph* aGraph,
                           SourceMediaStream* aSource,
                           TrackID aId,
                           StreamTime aDesiredTime,
                           TrackTicks& aLastEndTime) MOZ_OVERRIDE;
+  virtual bool SatisfiesConstraintSets(
+      const nsTArray<const dom::MediaTrackConstraintSet*>& aConstraintSets)
+  {
+    return true;
+  }
 
   void OnHardwareStateChange(HardwareState aState);
   void GetRotation();
   bool OnNewPreviewFrame(layers::Image* aImage, uint32_t aWidth, uint32_t aHeight);
   void OnUserError(UserContext aContext, nsresult aError);
   void OnTakePictureComplete(uint8_t* aData, uint32_t aLength, const nsAString& aMimeType);
 
   void AllocImpl();
--- a/content/media/webrtc/MediaEngineTabVideoSource.h
+++ b/content/media/webrtc/MediaEngineTabVideoSource.h
@@ -27,16 +27,21 @@ class MediaEngineTabVideoSource : public
     virtual void SetDirectListeners(bool aHasDirectListeners) {};
     virtual void NotifyPull(mozilla::MediaStreamGraph*, mozilla::SourceMediaStream*, mozilla::TrackID, mozilla::StreamTime, mozilla::TrackTicks&);
     virtual nsresult Stop(mozilla::SourceMediaStream*, mozilla::TrackID);
     virtual nsresult Config(bool, uint32_t, bool, uint32_t, bool, uint32_t, int32_t);
     virtual bool IsFake();
     virtual const MediaSourceType GetMediaSource() {
       return MediaSourceType::Browser;
     }
+    virtual bool SatisfiesConstraintSets(
+      const nsTArray<const dom::MediaTrackConstraintSet*>& aConstraintSets)
+    {
+      return true;
+    }
 
     virtual nsresult TakePhoto(PhotoCallback* aCallback)
     {
       return NS_ERROR_NOT_IMPLEMENTED;
     }
 
     void Draw();
 
--- a/content/media/webrtc/MediaEngineWebRTC.h
+++ b/content/media/webrtc/MediaEngineWebRTC.h
@@ -105,16 +105,19 @@ public:
   }
   virtual nsresult TakePhoto(PhotoCallback* aCallback)
   {
     return NS_ERROR_NOT_IMPLEMENTED;
   }
 
   void Refresh(int aIndex);
 
+  bool SatisfiesConstraintSets(
+      const nsTArray<const dom::MediaTrackConstraintSet*>& aConstraintSets);
+
 protected:
   ~MediaEngineWebRTCVideoSource() { Shutdown(); }
 
 private:
   // Initialize the needed Video engine interfaces.
   void Init();
   void Shutdown();
 
@@ -123,18 +126,18 @@ private:
   webrtc::ViEBase* mViEBase;
   webrtc::ViECapture* mViECapture;
   webrtc::ViERender* mViERender;
   webrtc::CaptureCapability mCapability; // Doesn't work on OS X.
 
   int mMinFps; // Min rate we want to accept
   MediaSourceType mMediaSource; // source of media (camera | application | screen)
 
-  static bool SatisfyConstraintSet(const dom::MediaTrackConstraintSet& aConstraints,
-                                   const webrtc::CaptureCapability& aCandidate);
+  static bool SatisfiesConstraintSet(const dom::MediaTrackConstraintSet& aConstraints,
+                                     const webrtc::CaptureCapability& aCandidate);
   void ChooseCapability(const VideoTrackConstraintsN& aConstraints,
                         const MediaEnginePrefs& aPrefs);
 };
 
 class MediaEngineWebRTCAudioSource : public MediaEngineAudioSource,
                                      public webrtc::VoEMediaProcess
 {
 public:
--- a/content/media/webrtc/MediaEngineWebRTCAudio.cpp
+++ b/content/media/webrtc/MediaEngineWebRTCAudio.cpp
@@ -34,18 +34,20 @@ namespace mozilla {
 
 #ifdef LOG
 #undef LOG
 #endif
 
 #ifdef PR_LOGGING
 extern PRLogModuleInfo* GetMediaManagerLog();
 #define LOG(msg) PR_LOG(GetMediaManagerLog(), PR_LOG_DEBUG, msg)
+#define LOG_FRAMES(msg) PR_LOG(GetMediaManagerLog(), 6, msg)
 #else
 #define LOG(msg)
+#define LOG_FRAMES(msg)
 #endif
 
 /**
  * Webrtc audio source.
  */
 NS_IMPL_ISUPPORTS0(MediaEngineWebRTCAudioSource)
 
 // XXX temp until MSG supports registration
@@ -396,17 +398,17 @@ MediaEngineWebRTCAudioSource::NotifyPull
                                          TrackID aID,
                                          StreamTime aDesiredTime,
                                          TrackTicks &aLastEndTime)
 {
   // Ignore - we push audio data
 #ifdef DEBUG
   TrackTicks target = aSource->TimeToTicksRoundUp(SAMPLE_FREQUENCY, aDesiredTime);
   TrackTicks delta = target - aLastEndTime;
-  LOG(("Audio: NotifyPull: aDesiredTime %ld, target %ld, delta %ld",(int64_t) aDesiredTime, (int64_t) target, (int64_t) delta));
+  LOG_FRAMES(("Audio: NotifyPull: aDesiredTime %ld, target %ld, delta %ld",(int64_t) aDesiredTime, (int64_t) target, (int64_t) delta));
   aLastEndTime = target;
 #endif
 }
 
 void
 MediaEngineWebRTCAudioSource::Init()
 {
   mVoEBase = webrtc::VoEBase::GetInterface(mVoiceEngine);
--- a/content/media/webrtc/MediaEngineWebRTCVideo.cpp
+++ b/content/media/webrtc/MediaEngineWebRTCVideo.cpp
@@ -93,78 +93,124 @@ MediaEngineWebRTCVideoSource::DeliverFra
 
   // we don't touch anything in 'this' until here (except for snapshot,
   // which has it's own lock)
   MonitorAutoLock lock(mMonitor);
 
   // implicitly releases last image
   mImage = image.forget();
 
+  // Push the frame into the MSG with a minimal duration.  This will likely
+  // mean we'll still get NotifyPull calls which will then return the same
+  // frame again with a longer duration.  However, this means we won't
+  // fail to get the frame in and drop frames.
+
+  // XXX The timestamp for the frame should be based on the Capture time,
+  // not the MSG time, and MSG should never, ever block on a (realtime)
+  // video frame (or even really for streaming - audio yes, video probably no).
+  // Note that MediaPipeline currently ignores the timestamps from MSG
+  uint32_t len = mSources.Length();
+  for (uint32_t i = 0; i < len; i++) {
+    if (mSources[i]) {
+      AppendToTrack(mSources[i], mImage, mTrackID, 1); // shortest possible duration
+    }
+  }
+
   return 0;
 }
 
 // Called if the graph thinks it's running out of buffered video; repeat
 // the last frame for whatever minimum period it think it needs.  Note that
 // this means that no *real* frame can be inserted during this period.
 void
 MediaEngineWebRTCVideoSource::NotifyPull(MediaStreamGraph* aGraph,
-                                         SourceMediaStream *aSource,
+                                         SourceMediaStream* aSource,
                                          TrackID aID,
                                          StreamTime aDesiredTime,
                                          TrackTicks &aLastEndTime)
 {
   VideoSegment segment;
 
   MonitorAutoLock lock(mMonitor);
   // B2G does AddTrack, but holds kStarted until the hardware changes state.
   // So mState could be kReleased here.  We really don't care about the state,
   // though.
 
-  // Note: we're not giving up mImage here
-  nsRefPtr<layers::Image> image = mImage;
   TrackTicks target = aSource->TimeToTicksRoundUp(USECS_PER_S, aDesiredTime);
   TrackTicks delta = target - aLastEndTime;
   LOGFRAME(("NotifyPull, desired = %ld, target = %ld, delta = %ld %s", (int64_t) aDesiredTime,
-            (int64_t) target, (int64_t) delta, image ? "" : "<null>"));
+            (int64_t) target, (int64_t) delta, mImage ? "" : "<null>"));
 
   // Bug 846188 We may want to limit incoming frames to the requested frame rate
   // mFps - if you want 30FPS, and the camera gives you 60FPS, this could
   // cause issues.
   // We may want to signal if the actual frame rate is below mMinFPS -
   // cameras often don't return the requested frame rate especially in low
   // light; we should consider surfacing this so that we can switch to a
   // lower resolution (which may up the frame rate)
 
   // Don't append if we've already provided a frame that supposedly goes past the current aDesiredTime
   // Doing so means a negative delta and thus messes up handling of the graph
   if (delta > 0) {
     // nullptr images are allowed
-    IntSize size(image ? mWidth : 0, image ? mHeight : 0);
-    segment.AppendFrame(image.forget(), delta, size);
-    // This can fail if either a) we haven't added the track yet, or b)
-    // we've removed or finished the track.
-    if (aSource->AppendToTrack(aID, &(segment))) {
+    if (AppendToTrack(aSource, mImage, aID, delta)) {
       aLastEndTime = target;
     }
   }
 }
 
 /*static*/
-bool MediaEngineWebRTCVideoSource::SatisfyConstraintSet(const MediaTrackConstraintSet &aConstraints,
-                                                        const webrtc::CaptureCapability& aCandidate) {
+bool
+MediaEngineWebRTCVideoSource::SatisfiesConstraintSet(const MediaTrackConstraintSet &aConstraints,
+                                                     const webrtc::CaptureCapability& aCandidate) {
   if (!MediaEngineCameraVideoSource::IsWithin(aCandidate.width, aConstraints.mWidth) ||
       !MediaEngineCameraVideoSource::IsWithin(aCandidate.height, aConstraints.mHeight)) {
     return false;
   }
   if (!MediaEngineCameraVideoSource::IsWithin(aCandidate.maxFPS, aConstraints.mFrameRate)) {
     return false;
   }
   return true;
 }
 
+typedef nsTArray<uint8_t> CapabilitySet;
+
+// SatisfiesConstraintSets (plural) answers for the capture device as a whole
+// whether it can satisfy an accumulated number of capabilitySets.
+
+bool
+MediaEngineWebRTCVideoSource::SatisfiesConstraintSets(
+    const nsTArray<const MediaTrackConstraintSet*>& aConstraintSets)
+{
+  NS_ConvertUTF16toUTF8 uniqueId(mUniqueId);
+  int num = mViECapture->NumberOfCapabilities(uniqueId.get(), kMaxUniqueIdLength);
+  if (num <= 0) {
+    return true;
+  }
+
+  CapabilitySet candidateSet;
+  for (int i = 0; i < num; i++) {
+    candidateSet.AppendElement(i);
+  }
+
+  for (size_t j = 0; j < aConstraintSets.Length(); j++) {
+    for (size_t i = 0; i < candidateSet.Length();  ) {
+      webrtc::CaptureCapability cap;
+      mViECapture->GetCaptureCapability(uniqueId.get(), kMaxUniqueIdLength,
+                                        candidateSet[i], cap);
+      if (!SatisfiesConstraintSet(*aConstraintSets[j], cap)) {
+        candidateSet.RemoveElementAt(i);
+      } else {
+        ++i;
+      }
+    }
+  }
+  return !!candidateSet.Length();
+}
+
 void
 MediaEngineWebRTCVideoSource::ChooseCapability(
     const VideoTrackConstraintsN &aConstraints,
     const MediaEnginePrefs &aPrefs)
 {
   NS_ConvertUTF16toUTF8 uniqueId(mUniqueId);
   int num = mViECapture->NumberOfCapabilities(uniqueId.get(), kMaxUniqueIdLength);
   if (num <= 0) {
@@ -172,50 +218,48 @@ MediaEngineWebRTCVideoSource::ChooseCapa
     return GuessCapability(aConstraints, aPrefs);
   }
 
   // The rest is the full algorithm for cameras that can list their capabilities.
 
   LOG(("ChooseCapability: prefs: %dx%d @%d-%dfps",
        aPrefs.mWidth, aPrefs.mHeight, aPrefs.mFPS, aPrefs.mMinFPS));
 
-  typedef nsTArray<uint8_t> SourceSet;
-
-  SourceSet candidateSet;
+  CapabilitySet candidateSet;
   for (int i = 0; i < num; i++) {
     candidateSet.AppendElement(i);
   }
 
   // Pick among capabilities: First apply required constraints.
 
   for (uint32_t i = 0; i < candidateSet.Length();) {
     webrtc::CaptureCapability cap;
     mViECapture->GetCaptureCapability(uniqueId.get(), kMaxUniqueIdLength,
                                       candidateSet[i], cap);
-    if (!SatisfyConstraintSet(aConstraints.mRequired, cap)) {
+    if (!SatisfiesConstraintSet(aConstraints.mRequired, cap)) {
       candidateSet.RemoveElementAt(i);
     } else {
       ++i;
     }
   }
 
-  SourceSet tailSet;
+  CapabilitySet tailSet;
 
   // Then apply advanced (formerly known as optional) constraints.
 
   if (aConstraints.mAdvanced.WasPassed()) {
     auto &array = aConstraints.mAdvanced.Value();
 
     for (uint32_t i = 0; i < array.Length(); i++) {
-      SourceSet rejects;
+      CapabilitySet rejects;
       for (uint32_t j = 0; j < candidateSet.Length();) {
         webrtc::CaptureCapability cap;
         mViECapture->GetCaptureCapability(uniqueId.get(), kMaxUniqueIdLength,
                                           candidateSet[j], cap);
-        if (!SatisfyConstraintSet(array[i], cap)) {
+        if (!SatisfiesConstraintSet(array[i], cap)) {
           rejects.AppendElement(candidateSet[j]);
           candidateSet.RemoveElementAt(j);
         } else {
           ++j;
         }
       }
       (candidateSet.Length()? tailSet : candidateSet).MoveElementsFrom(rejects);
     }
@@ -358,16 +402,18 @@ MediaEngineWebRTCVideoSource::Start(Sour
   aStream->AdvanceKnownTracksTime(STREAM_TIME_MAX);
 
   if (mState == kStarted) {
     return NS_OK;
   }
   mImageContainer = layers::LayerManager::CreateImageContainer();
 
   mState = kStarted;
+  mTrackID = aID;
+
   error = mViERender->AddRenderer(mCaptureIndex, webrtc::kVideoI420, (webrtc::ExternalRenderer*)this);
   if (error == -1) {
     return NS_ERROR_FAILURE;
   }
 
   error = mViERender->StartRender(mCaptureIndex);
   if (error == -1) {
     return NS_ERROR_FAILURE;
--- a/dom/ipc/AppProcessChecker.cpp
+++ b/dom/ipc/AppProcessChecker.cpp
@@ -34,89 +34,125 @@ class PContentParent;
 
 class nsIPrincipal;
 #endif
 
 namespace mozilla {
 
 #ifdef MOZ_CHILD_PERMISSIONS
 
+static bool
+CheckAppTypeHelper(mozIApplication* aApp,
+                   AssertAppProcessType aType,
+                   const char* aCapability,
+                   bool aIsBrowserElement)
+{
+  bool aValid = false;
+
+  // isBrowser frames inherit their app descriptor to identify their
+  // data storage, but they don't inherit the capability associated
+  // with that descriptor.
+  if (aApp && (aType == ASSERT_APP_HAS_PERMISSION || !aIsBrowserElement)) {
+    switch (aType) {
+      case ASSERT_APP_HAS_PERMISSION:
+      case ASSERT_APP_PROCESS_PERMISSION:
+        if (!NS_SUCCEEDED(aApp->HasPermission(aCapability, &aValid))) {
+          aValid = false;
+        }
+        break;
+      case ASSERT_APP_PROCESS_MANIFEST_URL: {
+        nsAutoString manifestURL;
+        if (NS_SUCCEEDED(aApp->GetManifestURL(manifestURL)) &&
+            manifestURL.EqualsASCII(aCapability)) {
+          aValid = true;
+        }
+        break;
+      }
+      default:
+        break;
+    }
+  }
+  return aValid;
+}
+
 bool
 AssertAppProcess(PBrowserParent* aActor,
                  AssertAppProcessType aType,
                  const char* aCapability)
 {
   if (!aActor) {
     NS_WARNING("Testing process capability for null actor");
     return false;
   }
 
   TabParent* tab = static_cast<TabParent*>(aActor);
   nsCOMPtr<mozIApplication> app = tab->GetOwnOrContainingApp();
-  bool aValid = false;
+
+  return CheckAppTypeHelper(app, aType, aCapability, tab->IsBrowserElement());
+}
 
-  // isBrowser frames inherit their app descriptor to identify their
-  // data storage, but they don't inherit the capability associated
-  // with that descriptor.
-  if (app && (aType == ASSERT_APP_HAS_PERMISSION || !tab->IsBrowserElement())) {
-    switch (aType) {
-      case ASSERT_APP_HAS_PERMISSION:
-      case ASSERT_APP_PROCESS_PERMISSION:
-        if (!NS_SUCCEEDED(app->HasPermission(aCapability, &aValid))) {
-          aValid = false;
-        }
-        break;
-      case ASSERT_APP_PROCESS_MANIFEST_URL: {
-        nsAutoString manifestURL;
-        if (NS_SUCCEEDED(app->GetManifestURL(manifestURL)) &&
-            manifestURL.EqualsASCII(aCapability)) {
-          aValid = true;
-        }
-        break;
-      }
-      default:
-        break;
+static bool
+CheckAppStatusHelper(mozIApplication* aApp,
+                     unsigned short aStatus)
+{
+  bool valid = false;
+
+  if (aApp) {
+    unsigned short appStatus = 0;
+    if (NS_SUCCEEDED(aApp->GetAppStatus(&appStatus))) {
+      valid = appStatus == aStatus;
     }
   }
-  return aValid;
+
+  return valid;
 }
 
 bool
 AssertAppStatus(PBrowserParent* aActor,
                 unsigned short aStatus)
 {
   if (!aActor) {
     NS_WARNING("Testing process capability for null actor");
     return false;
   }
 
   TabParent* tab = static_cast<TabParent*>(aActor);
   nsCOMPtr<mozIApplication> app = tab->GetOwnOrContainingApp();
 
-  bool valid = false;
+  return CheckAppStatusHelper(app, aStatus);
+}
+
+bool
+AssertAppProcess(TabContext& aContext,
+                 AssertAppProcessType aType,
+                 const char* aCapability)
+{
 
-  if (app) {
-    unsigned short appStatus = 0;
-    if (NS_SUCCEEDED(app->GetAppStatus(&appStatus))) {
-      valid = appStatus == aStatus;
-    }
-  }
+  nsCOMPtr<mozIApplication> app = aContext.GetOwnOrContainingApp();
+  return CheckAppTypeHelper(app, aType, aCapability, aContext.IsBrowserElement());
+}
 
-  return valid;
+bool
+AssertAppStatus(TabContext& aContext,
+                unsigned short aStatus)
+{
+
+  nsCOMPtr<mozIApplication> app = aContext.GetOwnOrContainingApp();
+  return CheckAppStatusHelper(app, aStatus);
 }
 
 bool
 AssertAppProcess(PContentParent* aActor,
                  AssertAppProcessType aType,
                  const char* aCapability)
 {
-  const InfallibleTArray<PBrowserParent*>& browsers =
-    aActor->ManagedPBrowserParent();
-  for (uint32_t i = 0; i < browsers.Length(); ++i) {
-    if (AssertAppProcess(browsers[i], aType, aCapability)) {
+  nsTArray<TabContext> contextArray =
+    static_cast<ContentParent*>(aActor)->GetManagedTabContext();
+  for (uint32_t i = 0; i < contextArray.Length(); ++i) {
+    if (AssertAppProcess(contextArray[i], aType, aCapability)) {
       return true;
     }
   }
 
   NS_ERROR(
     nsPrintfCString(
       "Security problem: Content process does not have `%s'.  It will be killed.\n",
       aCapability).get());
@@ -125,20 +161,20 @@ AssertAppProcess(PContentParent* aActor,
 
   return false;
 }
 
 bool
 AssertAppStatus(PContentParent* aActor,
                 unsigned short aStatus)
 {
-  const InfallibleTArray<PBrowserParent*>& browsers =
-    aActor->ManagedPBrowserParent();
-  for (uint32_t i = 0; i < browsers.Length(); ++i) {
-    if (AssertAppStatus(browsers[i], aStatus)) {
+  nsTArray<TabContext> contextArray =
+    static_cast<ContentParent*>(aActor)->GetManagedTabContext();
+  for (uint32_t i = 0; i < contextArray.Length(); ++i) {
+    if (AssertAppStatus(contextArray[i], aStatus)) {
       return true;
     }
   }
 
   NS_ERROR(
     nsPrintfCString(
       "Security problem: Content process does not have `%d' status.  It will be killed.",
       aStatus).get());
@@ -165,24 +201,23 @@ AssertAppPrincipal(PContentParent* aActo
     static_cast<ContentParent*>(aActor)->KillHard();
     return false;
   }
 
   uint32_t principalAppId = aPrincipal->GetAppId();
   bool inBrowserElement = aPrincipal->GetIsInBrowserElement();
 
   // Check if the permission's appId matches a child we manage.
-  const InfallibleTArray<PBrowserParent*>& browsers =
-    aActor->ManagedPBrowserParent();
-  for (uint32_t i = 0; i < browsers.Length(); ++i) {
-    TabParent* tab = static_cast<TabParent*>(browsers[i]);
-    if (tab->OwnOrContainingAppId() == principalAppId) {
+  nsTArray<TabContext> contextArray =
+    static_cast<ContentParent*>(aActor)->GetManagedTabContext();
+  for (uint32_t i = 0; i < contextArray.Length(); ++i) {
+    if (contextArray[i].OwnOrContainingAppId() == principalAppId) {
       // If the child only runs inBrowserElement content and the principal claims
       // it's not in a browser element, it's lying.
-      if (!tab->IsBrowserElement() || inBrowserElement) {
+      if (!contextArray[i].IsBrowserElement() || inBrowserElement) {
         return true;
       }
       break;
     }
   }
 
   NS_WARNING("Principal is invalid, killing app process");
   static_cast<ContentParent*>(aActor)->KillHard();
@@ -282,16 +317,31 @@ AssertAppProcess(mozilla::dom::PBrowserP
 
 bool
 AssertAppStatus(mozilla::dom::PBrowserParent* aActor,
                 unsigned short aStatus)
 {
   return true;
 }
 
+bool
+AssertAppProcess(const mozilla::dom::TabContext& aContext,
+                 AssertAppProcessType aType,
+                 const char* aCapability)
+{
+  return true;
+}
+
+bool
+AssertAppStatus(const mozilla::dom::TabContext& aContext,
+                unsigned short aStatus)
+{
+  return true;
+}
+
 
 bool
 AssertAppProcess(mozilla::dom::PContentParent* aActor,
                  AssertAppProcessType aType,
                  const char* aCapability)
 {
   return true;
 }
--- a/dom/ipc/AppProcessChecker.h
+++ b/dom/ipc/AppProcessChecker.h
@@ -10,16 +10,17 @@
 
 #include <stdint.h>
 
 class nsIPrincipal;
 
 namespace mozilla {
 
 namespace dom {
+class TabContext;
 class PBrowserParent;
 class PContentParent;
 }
 
 namespace hal_sandbox {
 class PHalParent;
 }
 
@@ -43,16 +44,34 @@ AssertAppProcess(mozilla::dom::PBrowserP
  * Return true if the specified app has the specified status.
  * If this returns false, the browser will be killed.
  */
 bool
 AssertAppStatus(mozilla::dom::PBrowserParent* aActor,
                 unsigned short aStatus);
 
 /**
+ * Return true if the specified browser has the specified capability.
+ * If this returns false, the browser didn't have the capability and
+ * will be killed.
+ */
+bool
+AssertAppProcess(const mozilla::dom::TabContext& aContext,
+                 AssertAppProcessType aType,
+                 const char* aCapability);
+
+/**
+ * Return true if the specified app has the specified status.
+ * If this returns false, the browser will be killed.
+ */
+bool
+AssertAppStatus(const mozilla::dom::TabContext& aContext,
+                unsigned short aStatus);
+
+/**
  * Return true if any of the PBrowsers loaded in this content process
  * has the specified capability.  If this returns false, the process
  * didn't have the capability and will be killed.
  */
 bool
 AssertAppProcess(mozilla::dom::PContentParent* aActor,
                  AssertAppProcessType aType,
                  const char* aCapability);
--- a/dom/ipc/ContentBridgeChild.cpp
+++ b/dom/ipc/ContentBridgeChild.cpp
@@ -76,26 +76,28 @@ PBlobChild*
 ContentBridgeChild::SendPBlobConstructor(PBlobChild* actor,
                                          const BlobConstructorParams& params)
 {
   return PContentBridgeChild::SendPBlobConstructor(actor, params);
 }
 
 bool
 ContentBridgeChild::SendPBrowserConstructor(PBrowserChild* aActor,
+                                            const TabId& aTabId,
                                             const IPCTabContext& aContext,
                                             const uint32_t& aChromeFlags,
-                                            const uint64_t& aID,
+                                            const ContentParentId& aCpID,
                                             const bool& aIsForApp,
                                             const bool& aIsForBrowser)
 {
   return PContentBridgeChild::SendPBrowserConstructor(aActor,
+                                                      aTabId,
                                                       aContext,
                                                       aChromeFlags,
-                                                      aID,
+                                                      aCpID,
                                                       aIsForApp,
                                                       aIsForBrowser);
 }
 
 // This implementation is identical to ContentChild::GetCPOWManager but we can't
 // move it to nsIContentChild because it calls ManagedPJavaScriptChild() which
 // only exists in PContentChild and PContentBridgeChild.
 jsipc::JavaScriptShared*
@@ -116,47 +118,51 @@ ContentBridgeChild::AllocPJavaScriptChil
 
 bool
 ContentBridgeChild::DeallocPJavaScriptChild(PJavaScriptChild *child)
 {
   return nsIContentChild::DeallocPJavaScriptChild(child);
 }
 
 PBrowserChild*
-ContentBridgeChild::AllocPBrowserChild(const IPCTabContext &aContext,
+ContentBridgeChild::AllocPBrowserChild(const TabId& aTabId,
+                                       const IPCTabContext &aContext,
                                        const uint32_t& aChromeFlags,
-                                       const uint64_t& aID,
+                                       const ContentParentId& aCpID,
                                        const bool& aIsForApp,
                                        const bool& aIsForBrowser)
 {
-  return nsIContentChild::AllocPBrowserChild(aContext,
+  return nsIContentChild::AllocPBrowserChild(aTabId,
+                                             aContext,
                                              aChromeFlags,
-                                             aID,
+                                             aCpID,
                                              aIsForApp,
                                              aIsForBrowser);
 }
 
 bool
 ContentBridgeChild::DeallocPBrowserChild(PBrowserChild* aChild)
 {
   return nsIContentChild::DeallocPBrowserChild(aChild);
 }
 
 bool
 ContentBridgeChild::RecvPBrowserConstructor(PBrowserChild* aActor,
+                                            const TabId& aTabId,
                                             const IPCTabContext& aContext,
                                             const uint32_t& aChromeFlags,
-                                            const uint64_t& aID,
+                                            const ContentParentId& aCpID,
                                             const bool& aIsForApp,
                                             const bool& aIsForBrowser)
 {
   return ContentChild::GetSingleton()->RecvPBrowserConstructor(aActor,
+                                                               aTabId,
                                                                aContext,
                                                                aChromeFlags,
-                                                               aID,
+                                                               aCpID,
                                                                aIsForApp,
                                                                aIsForBrowser);
 }
 
 PBlobChild*
 ContentBridgeChild::AllocPBlobChild(const BlobConstructorParams& aParams)
 {
   return nsIContentChild::AllocPBlobChild(aParams);
--- a/dom/ipc/ContentBridgeChild.h
+++ b/dom/ipc/ContentBridgeChild.h
@@ -34,35 +34,38 @@ public:
 
   virtual PBlobChild*
   SendPBlobConstructor(PBlobChild* actor,
                        const BlobConstructorParams& params);
 
   jsipc::JavaScriptShared* GetCPOWManager() MOZ_OVERRIDE;
 
   virtual bool SendPBrowserConstructor(PBrowserChild* aActor,
+                                       const TabId& aTabId,
                                        const IPCTabContext& aContext,
                                        const uint32_t& aChromeFlags,
-                                       const uint64_t& aID,
+                                       const ContentParentId& aCpID,
                                        const bool& aIsForApp,
                                        const bool& aIsForBrowser) MOZ_OVERRIDE;
 
 protected:
   virtual ~ContentBridgeChild();
 
-  virtual PBrowserChild* AllocPBrowserChild(const IPCTabContext& aContext,
+  virtual PBrowserChild* AllocPBrowserChild(const TabId& aTabId,
+                                            const IPCTabContext& aContext,
                                             const uint32_t& aChromeFlags,
-                                            const uint64_t& aID,
+                                            const ContentParentId& aCpID,
                                             const bool& aIsForApp,
                                             const bool& aIsForBrowser) MOZ_OVERRIDE;
   virtual bool DeallocPBrowserChild(PBrowserChild*) MOZ_OVERRIDE;
   virtual bool RecvPBrowserConstructor(PBrowserChild* aCctor,
+                                       const TabId& aTabId,
                                        const IPCTabContext& aContext,
                                        const uint32_t& aChromeFlags,
-                                       const uint64_t& aID,
+                                       const ContentParentId& aCpID,
                                        const bool& aIsForApp,
                                        const bool& aIsForBrowser) MOZ_OVERRIDE;
 
   virtual mozilla::jsipc::PJavaScriptChild* AllocPJavaScriptChild() MOZ_OVERRIDE;
   virtual bool DeallocPJavaScriptChild(mozilla::jsipc::PJavaScriptChild*) MOZ_OVERRIDE;
 
   virtual PBlobChild* AllocPBlobChild(const BlobConstructorParams& aParams) MOZ_OVERRIDE;
   virtual bool DeallocPBlobChild(PBlobChild*) MOZ_OVERRIDE;
--- a/dom/ipc/ContentBridgeParent.cpp
+++ b/dom/ipc/ContentBridgeParent.cpp
@@ -82,26 +82,28 @@ PBlobParent*
 ContentBridgeParent::SendPBlobConstructor(PBlobParent* actor,
                                           const BlobConstructorParams& params)
 {
   return PContentBridgeParent::SendPBlobConstructor(actor, params);
 }
 
 PBrowserParent*
 ContentBridgeParent::SendPBrowserConstructor(PBrowserParent* aActor,
+                                             const TabId& aTabId,
                                              const IPCTabContext& aContext,
                                              const uint32_t& aChromeFlags,
-                                             const uint64_t& aID,
+                                             const ContentParentId& aCpID,
                                              const bool& aIsForApp,
                                              const bool& aIsForBrowser)
 {
   return PContentBridgeParent::SendPBrowserConstructor(aActor,
+                                                       aTabId,
                                                        aContext,
                                                        aChromeFlags,
-                                                       aID,
+                                                       aCpID,
                                                        aIsForApp,
                                                        aIsForBrowser);
 }
 
 PBlobParent*
 ContentBridgeParent::AllocPBlobParent(const BlobConstructorParams& aParams)
 {
   return nsIContentParent::AllocPBlobParent(aParams);
@@ -121,25 +123,27 @@ ContentBridgeParent::AllocPJavaScriptPar
 
 bool
 ContentBridgeParent::DeallocPJavaScriptParent(PJavaScriptParent *parent)
 {
   return nsIContentParent::DeallocPJavaScriptParent(parent);
 }
 
 PBrowserParent*
-ContentBridgeParent::AllocPBrowserParent(const IPCTabContext &aContext,
+ContentBridgeParent::AllocPBrowserParent(const TabId& aTabId,
+                                         const IPCTabContext &aContext,
                                          const uint32_t& aChromeFlags,
-                                         const uint64_t& aID,
+                                         const ContentParentId& aCpID,
                                          const bool& aIsForApp,
                                          const bool& aIsForBrowser)
 {
-  return nsIContentParent::AllocPBrowserParent(aContext,
+  return nsIContentParent::AllocPBrowserParent(aTabId,
+                                               aContext,
                                                aChromeFlags,
-                                               aID,
+                                               aCpID,
                                                aIsForApp,
                                                aIsForBrowser);
 }
 
 bool
 ContentBridgeParent::DeallocPBrowserParent(PBrowserParent* aParent)
 {
   return nsIContentParent::DeallocPBrowserParent(aParent);
--- a/dom/ipc/ContentBridgeParent.h
+++ b/dom/ipc/ContentBridgeParent.h
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_ContentBridgeParent_h
 #define mozilla_dom_ContentBridgeParent_h
 
 #include "mozilla/dom/PContentBridgeParent.h"
 #include "mozilla/dom/nsIContentParent.h"
+#include "mozilla/dom/ipc/IdType.h"
 
 namespace mozilla {
 namespace dom {
 
 class ContentBridgeParent : public PContentBridgeParent
                           , public nsIContentParent
 {
 public:
@@ -28,41 +29,42 @@ public:
   Create(Transport* aTransport, ProcessId aOtherProcess);
 
   virtual PBlobParent*
   SendPBlobConstructor(PBlobParent* actor,
                        const BlobConstructorParams& params) MOZ_OVERRIDE;
 
   virtual PBrowserParent*
   SendPBrowserConstructor(PBrowserParent* aActor,
+                          const TabId& aTabId,
                           const IPCTabContext& aContext,
                           const uint32_t& aChromeFlags,
-                          const uint64_t& aID,
+                          const ContentParentId& aCpID,
                           const bool& aIsForApp,
                           const bool& aIsForBrowser) MOZ_OVERRIDE;
 
   jsipc::JavaScriptShared* GetCPOWManager() MOZ_OVERRIDE;
 
-  virtual uint64_t ChildID() MOZ_OVERRIDE
+  virtual ContentParentId ChildID() MOZ_OVERRIDE
   {
     return mChildID;
   }
   virtual bool IsForApp() MOZ_OVERRIDE
   {
     return mIsForApp;
   }
   virtual bool IsForBrowser() MOZ_OVERRIDE
   {
     return mIsForBrowser;
   }
 
 protected:
   virtual ~ContentBridgeParent();
 
-  void SetChildID(uint64_t aId)
+  void SetChildID(ContentParentId aId)
   {
     mChildID = aId;
   }
   void SetIsForApp(bool aIsForApp)
   {
     mIsForApp = aIsForApp;
   }
   void SetIsForBrowser(bool aIsForBrowser)
@@ -81,34 +83,35 @@ protected:
                                 const InfallibleTArray<jsipc::CpowEntry>& aCpows,
                                 const IPC::Principal& aPrincipal) MOZ_OVERRIDE;
 
   virtual jsipc::PJavaScriptParent* AllocPJavaScriptParent() MOZ_OVERRIDE;
   virtual bool
   DeallocPJavaScriptParent(jsipc::PJavaScriptParent*) MOZ_OVERRIDE;
 
   virtual PBrowserParent*
-  AllocPBrowserParent(const IPCTabContext &aContext,
+  AllocPBrowserParent(const TabId& aTabId,
+                      const IPCTabContext &aContext,
                       const uint32_t& aChromeFlags,
-                      const uint64_t& aID,
+                      const ContentParentId& aCpID,
                       const bool& aIsForApp,
                       const bool& aIsForBrowser) MOZ_OVERRIDE;
   virtual bool DeallocPBrowserParent(PBrowserParent*) MOZ_OVERRIDE;
 
   virtual PBlobParent*
   AllocPBlobParent(const BlobConstructorParams& aParams) MOZ_OVERRIDE;
 
   virtual bool DeallocPBlobParent(PBlobParent*) MOZ_OVERRIDE;
 
   DISALLOW_EVIL_CONSTRUCTORS(ContentBridgeParent);
 
 protected: // members
   nsRefPtr<ContentBridgeParent> mSelfRef;
   Transport* mTransport; // owned
-  uint64_t mChildID;
+  ContentParentId mChildID;
   bool mIsForApp;
   bool mIsForBrowser;
 
 private:
   friend class ContentParent;
 };
 
 } // dom
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -1104,50 +1104,55 @@ ContentChild::AllocPJavaScriptChild()
 
 bool
 ContentChild::DeallocPJavaScriptChild(PJavaScriptChild *aChild)
 {
     return nsIContentChild::DeallocPJavaScriptChild(aChild);
 }
 
 PBrowserChild*
-ContentChild::AllocPBrowserChild(const IPCTabContext& aContext,
+ContentChild::AllocPBrowserChild(const TabId& aTabId,
+                                 const IPCTabContext& aContext,
                                  const uint32_t& aChromeFlags,
-                                 const uint64_t& aID,
+                                 const ContentParentId& aCpID,
                                  const bool& aIsForApp,
                                  const bool& aIsForBrowser)
 {
-    return nsIContentChild::AllocPBrowserChild(aContext,
+    return nsIContentChild::AllocPBrowserChild(aTabId,
+                                               aContext,
                                                aChromeFlags,
-                                               aID,
+                                               aCpID,
                                                aIsForApp,
                                                aIsForBrowser);
 }
 
 bool
 ContentChild::SendPBrowserConstructor(PBrowserChild* aActor,
+                                      const TabId& aTabId,
                                       const IPCTabContext& aContext,
                                       const uint32_t& aChromeFlags,
-                                      const uint64_t& aID,
+                                      const ContentParentId& aCpID,
                                       const bool& aIsForApp,
                                       const bool& aIsForBrowser)
 {
     return PContentChild::SendPBrowserConstructor(aActor,
+                                                  aTabId,
                                                   aContext,
                                                   aChromeFlags,
-                                                  aID,
+                                                  aCpID,
                                                   aIsForApp,
                                                   aIsForBrowser);
 }
 
 bool
 ContentChild::RecvPBrowserConstructor(PBrowserChild* aActor,
+                                      const TabId& aTabId,
                                       const IPCTabContext& aContext,
                                       const uint32_t& aChromeFlags,
-                                      const uint64_t& aID,
+                                      const ContentParentId& aCpID,
                                       const bool& aIsForApp,
                                       const bool& aIsForBrowser)
 {
     // This runs after AllocPBrowserChild() returns and the IPC machinery for this
     // PBrowserChild has been set up.
 
     nsCOMPtr<nsIObserverService> os = services::GetObserverService();
     if (os) {
@@ -1161,17 +1166,17 @@ ContentChild::RecvPBrowserConstructor(PB
         hasRunOnce = true;
 
         MOZ_ASSERT(!sFirstIdleTask);
         sFirstIdleTask = NewRunnableFunction(FirstIdle);
         MessageLoop::current()->PostIdleTask(FROM_HERE, sFirstIdleTask);
 
         // Redo InitProcessAttributes() when the app or browser is really
         // launching so the attributes will be correct.
-        mID = aID;
+        mID = aCpID;
         mIsForApp = aIsForApp;
         mIsForBrowser = aIsForBrowser;
         InitProcessAttributes();
     }
 
     return true;
 }
 
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -126,19 +126,20 @@ public:
 #endif
 
     virtual bool RecvSetProcessSandbox() MOZ_OVERRIDE;
 
     PBackgroundChild*
     AllocPBackgroundChild(Transport* aTransport, ProcessId aOtherProcess)
                           MOZ_OVERRIDE;
 
-    virtual PBrowserChild* AllocPBrowserChild(const IPCTabContext& aContext,
+    virtual PBrowserChild* AllocPBrowserChild(const TabId& aTabId,
+                                              const IPCTabContext& aContext,
                                               const uint32_t& aChromeFlags,
-                                              const uint64_t& aID,
+                                              const ContentParentId& aCpID,
                                               const bool& aIsForApp,
                                               const bool& aIsForBrowser);
     virtual bool DeallocPBrowserChild(PBrowserChild*);
 
     virtual PDeviceStorageRequestChild* AllocPDeviceStorageRequestChild(const DeviceStorageParams&);
     virtual bool DeallocPDeviceStorageRequestChild(PDeviceStorageRequestChild*);
 
     virtual PFileSystemRequestChild* AllocPFileSystemRequestChild(const FileSystemParams&);
@@ -349,42 +350,44 @@ public:
 #ifdef ANDROID
     gfxIntSize GetScreenSize() { return mScreenSize; }
 #endif
 
     // Get the directory for IndexedDB files. We query the parent for this and
     // cache the value
     nsString &GetIndexedDBPath();
 
-    uint64_t GetID() { return mID; }
+    ContentParentId GetID() { return mID; }
 
     bool IsForApp() { return mIsForApp; }
     bool IsForBrowser() { return mIsForBrowser; }
 
     virtual PBlobChild*
     SendPBlobConstructor(PBlobChild* actor,
                          const BlobConstructorParams& params) MOZ_OVERRIDE;
 
     virtual PFileDescriptorSetChild*
     AllocPFileDescriptorSetChild(const FileDescriptor&) MOZ_OVERRIDE;
 
     virtual bool
     DeallocPFileDescriptorSetChild(PFileDescriptorSetChild*) MOZ_OVERRIDE;
 
     virtual bool SendPBrowserConstructor(PBrowserChild* actor,
+                                         const TabId& aTabId,
                                          const IPCTabContext& context,
                                          const uint32_t& chromeFlags,
-                                         const uint64_t& aID,
+                                         const ContentParentId& aCpID,
                                          const bool& aIsForApp,
                                          const bool& aIsForBrowser) MOZ_OVERRIDE;
 
     virtual bool RecvPBrowserConstructor(PBrowserChild* aCctor,
+                                         const TabId& aTabId,
                                          const IPCTabContext& aContext,
                                          const uint32_t& aChromeFlags,
-                                         const uint64_t& aID,
+                                         const ContentParentId& aCpID,
                                          const bool& aIsForApp,
                                          const bool& aIsForBrowser) MOZ_OVERRIDE;
     virtual PDocAccessibleChild* AllocPDocAccessibleChild(PDocAccessibleChild*, const uint64_t&) MOZ_OVERRIDE;
     virtual bool DeallocPDocAccessibleChild(PDocAccessibleChild*) MOZ_OVERRIDE;
 
     void GetAvailableDictionaries(InfallibleTArray<nsString>& aDictionaries);
 
 private:
@@ -407,17 +410,17 @@ private:
 
     /**
      * An ID unique to the process containing our corresponding
      * content parent.
      *
      * We expect our content parent to set this ID immediately after opening a
      * channel to us.
      */
-    uint64_t mID;
+    ContentParentId mID;
 
     AppInfo mAppInfo;
 
 #ifdef ANDROID
     gfxIntSize mScreenSize;
 #endif
 
     bool mIsForApp;
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -126,16 +126,17 @@
 #include "TabParent.h"
 #include "URIUtils.h"
 #include "nsIWebBrowserChrome.h"
 #include "nsIDocShell.h"
 #include "mozilla/net/NeckoMessageUtils.h"
 #include "gfxPrefs.h"
 #include "prio.h"
 #include "private/pprio.h"
+#include "ContentProcessManager.h"
 
 #if defined(ANDROID) || defined(LINUX)
 #include "nsSystemInfo.h"
 #endif
 
 #if defined(XP_LINUX)
 #include "mozilla/Hal.h"
 #endif
@@ -840,27 +841,24 @@ ContentParent::PreallocatedProcessReady(
 {
 #ifdef MOZ_NUWA_PROCESS
     return PreallocatedProcessManager::PreallocatedProcessReady();
 #else
     return true;
 #endif
 }
 
-typedef std::map<ContentParent*, std::set<ContentParent*> > GrandchildMap;
-static GrandchildMap sGrandchildProcessMap;
-
-std::map<uint64_t, ContentParent*> sContentParentMap;
-
 bool
 ContentParent::RecvCreateChildProcess(const IPCTabContext& aContext,
                                       const hal::ProcessPriority& aPriority,
-                                      uint64_t* aId,
+                                      const TabId& aOpenerTabId,
+                                      ContentParentId* aCpId,
                                       bool* aIsForApp,
-                                      bool* aIsForBrowser)
+                                      bool* aIsForBrowser,
+                                      TabId* aTabId)
 {
 #if 0
     if (!CanOpenBrowser(aContext)) {
         return false;
     }
 #endif
     nsRefPtr<ContentParent> cp;
     MaybeInvalidTabContext tc(aContext);
@@ -879,114 +877,143 @@ ContentParent::RecvCreateChildProcess(co
     }
     else {
         cp = GetNewOrUsedBrowserProcess(/* isBrowserElement = */ true,
                                         aPriority,
                                         this);
     }
 
     if (!cp) {
-        *aId = 0;
+        *aCpId = 0;
         *aIsForApp = false;
         *aIsForBrowser = false;
         return true;
     }
 
-    *aId = cp->ChildID();
+    *aCpId = cp->ChildID();
     *aIsForApp = cp->IsForApp();
     *aIsForBrowser = cp->IsForBrowser();
-    sContentParentMap[*aId] = cp;
-    auto iter = sGrandchildProcessMap.find(this);
-    if (iter == sGrandchildProcessMap.end()) {
-        std::set<ContentParent*> children;
-        children.insert(cp);
-        sGrandchildProcessMap[this] = children;
-    } else {
-        iter->second.insert(cp);
+
+    ContentProcessManager *cpm = ContentProcessManager::GetSingleton();
+    cpm->AddContentProcess(cp, this->ChildID());
+
+    if (cpm->AddGrandchildProcess(this->ChildID(), cp->ChildID())) {
+        // Pre-allocate a TabId here to save one time IPC call at app startup.
+        *aTabId = AllocateTabId(aOpenerTabId,
+                                aContext,
+                                cp->ChildID());
+        return (*aTabId != 0);
     }
-    return true;
+
+    return false;
 }
 
 bool
-ContentParent::AnswerBridgeToChildProcess(const uint64_t& id)
+ContentParent::AnswerBridgeToChildProcess(const ContentParentId& aCpId)
 {
-    ContentParent* cp = sContentParentMap[id];
-    auto iter = sGrandchildProcessMap.find(this);
-    if (iter != sGrandchildProcessMap.end() &&
-        iter->second.find(cp) != iter->second.end()) {
-        return PContentBridge::Bridge(this, cp);
-    } else {
-        // You can't bridge to a process you didn't open!
-        KillHard();
-        return false;
+    ContentProcessManager *cpm = ContentProcessManager::GetSingleton();
+    ContentParent* cp = cpm->GetContentProcessById(aCpId);
+
+    if (cp) {
+        ContentParentId parentId;
+        if (cpm->GetParentProcessId(cp->ChildID(), &parentId) &&
+            parentId == this->ChildID()) {
+            return PContentBridge::Bridge(this, cp);
+        }
     }
+
+    // You can't bridge to a process you didn't open!
+    KillHard();
+    return false;
+}
+
+static nsIDocShell* GetOpenerDocShellHelper(Element* aFrameElement)
+{
+    // Propagate the private-browsing status of the element's parent
+    // docshell to the remote docshell, via the chrome flags.
+    nsCOMPtr<Element> frameElement = do_QueryInterface(aFrameElement);
+    MOZ_ASSERT(frameElement);
+    nsPIDOMWindow* win = frameElement->OwnerDoc()->GetWindow();
+    if (!win) {
+        NS_WARNING("Remote frame has no window");
+        return nullptr;
+    }
+    nsIDocShell* docShell = win->GetDocShell();
+    if (!docShell) {
+        NS_WARNING("Remote frame has no docshell");
+        return nullptr;
+    }
+
+    return docShell;
 }
 
 /*static*/ TabParent*
 ContentParent::CreateBrowserOrApp(const TabContext& aContext,
                                   Element* aFrameElement,
                                   ContentParent* aOpenerContentParent)
 {
     if (!sCanLaunchSubprocesses) {
         return nullptr;
     }
 
     ProcessPriority initialPriority = GetInitialProcessPriority(aFrameElement);
     bool isInContentProcess = (XRE_GetProcessType() != GeckoProcessType_Default);
+    TabId tabId;
+
+    nsIDocShell* docShell = GetOpenerDocShellHelper(aFrameElement);
+    TabId openerTabId;
+    if (docShell) {
+        openerTabId = TabParent::GetTabIdFrom(docShell);
+    }
 
     if (aContext.IsBrowserElement() || !aContext.HasOwnApp()) {
         nsRefPtr<TabParent> tp;
         nsRefPtr<nsIContentParent> constructorSender;
         if (isInContentProcess) {
             MOZ_ASSERT(aContext.IsBrowserElement());
-            constructorSender =
-                CreateContentBridgeParent(aContext, initialPriority);
+            constructorSender = CreateContentBridgeParent(aContext,
+                                                          initialPriority,
+                                                          openerTabId,
+                                                          &tabId);
         } else {
-          if (aOpenerContentParent) {
-            constructorSender = aOpenerContentParent;
-          } else {
-            constructorSender =
-                GetNewOrUsedBrowserProcess(aContext.IsBrowserElement(),
-                                           initialPriority);
-          }
+            if (aOpenerContentParent) {
+                constructorSender = aOpenerContentParent;
+            } else {
+                constructorSender =
+                    GetNewOrUsedBrowserProcess(aContext.IsBrowserElement(),
+                                               initialPriority);
+            }
+            tabId = AllocateTabId(openerTabId,
+                                  aContext.AsIPCTabContext(),
+                                  constructorSender->ChildID());
         }
         if (constructorSender) {
             uint32_t chromeFlags = 0;
 
-            // Propagate the private-browsing status of the element's parent
-            // docshell to the remote docshell, via the chrome flags.
-            nsCOMPtr<Element> frameElement = do_QueryInterface(aFrameElement);
-            MOZ_ASSERT(frameElement);
-            nsPIDOMWindow* win = frameElement->OwnerDoc()->GetWindow();
-            if (!win) {
-                NS_WARNING("Remote frame has no window");
-                return nullptr;
-            }
-            nsIDocShell* docShell = win->GetDocShell();
-            if (!docShell) {
-                NS_WARNING("Remote frame has no docshell");
-                return nullptr;
-            }
             nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell);
             if (loadContext && loadContext->UsePrivateBrowsing()) {
                 chromeFlags |= nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW;
             }
             bool affectLifetime;
             docShell->GetAffectPrivateSessionLifetime(&affectLifetime);
             if (affectLifetime) {
                 chromeFlags |= nsIWebBrowserChrome::CHROME_PRIVATE_LIFETIME;
             }
 
-            nsRefPtr<TabParent> tp(new TabParent(constructorSender,
+            if (tabId == 0) {
+                return nullptr;
+            }
+            nsRefPtr<TabParent> tp(new TabParent(constructorSender, tabId,
                                                  aContext, chromeFlags));
             tp->SetOwnerElement(aFrameElement);
 
             PBrowserParent* browser = constructorSender->SendPBrowserConstructor(
                 // DeallocPBrowserParent() releases this ref.
                 tp.forget().take(),
+                tabId,
                 aContext.AsIPCTabContext(),
                 chromeFlags,
                 constructorSender->ChildID(),
                 constructorSender->IsForApp(),
                 constructorSender->IsForBrowser());
             return static_cast<TabParent*>(browser);
         }
         return nullptr;
@@ -996,17 +1023,20 @@ ContentParent::CreateBrowserOrApp(const 
     // shouldn't be null, because we otherwise would have gone into the
     // !HasOwnApp() branch above.
     nsRefPtr<nsIContentParent> parent;
     bool reused = false;
     bool tookPreallocated = false;
     nsAutoString manifestURL;
 
     if (isInContentProcess) {
-      parent = CreateContentBridgeParent(aContext, initialPriority);
+      parent = CreateContentBridgeParent(aContext,
+                                         initialPriority,
+                                         openerTabId,
+                                         &tabId);
     }
     else {
         nsCOMPtr<mozIApplication> ownApp = aContext.GetOwnApp();
 
         if (!sAppContentParents) {
             sAppContentParents =
                 new nsDataHashtable<nsStringHashKey, ContentParent*>();
         }
@@ -1044,16 +1074,19 @@ ContentParent::CreateBrowserOrApp(const 
                 if (app &&
                     NS_SUCCEEDED(app->GetAppStatus(&appStatus)) &&
                     appStatus == nsIPrincipal::APP_STATUS_CERTIFIED &&
                     parentApp &&
                     NS_SUCCEEDED(parentApp->GetAppStatus(&parentAppStatus)) &&
                     parentAppStatus == nsIPrincipal::APP_STATUS_CERTIFIED) {
                     // Check if we can re-use the process of the parent app.
                     p = sAppContentParents->Get(parentAppManifestURL);
+                    tabId = AllocateTabId(openerTabId,
+                                          aContext.AsIPCTabContext(),
+                                          p->ChildID());
                 }
             }
         }
 
         if (p) {
             // Check that the process is still alive and set its priority.
             // Hopefully the process won't die after this point, if this call
             // succeeds.
@@ -1065,31 +1098,35 @@ ContentParent::CreateBrowserOrApp(const 
         reused = !!p;
         if (!p) {
             p = GetNewOrPreallocatedAppProcess(ownApp,
                                                initialPriority,
                                                nullptr,
                                                &tookPreallocated);
             MOZ_ASSERT(p);
             sAppContentParents->Put(manifestURL, p);
+            tabId = AllocateTabId(openerTabId,
+                                  aContext.AsIPCTabContext(),
+                                  p->ChildID());
         }
         parent = static_cast<nsIContentParent*>(p);
     }
 
-    if (!parent) {
+    if (!parent || (tabId == 0)) {
         return nullptr;
     }
 
     uint32_t chromeFlags = 0;
 
-    nsRefPtr<TabParent> tp = new TabParent(parent, aContext, chromeFlags);
+    nsRefPtr<TabParent> tp = new TabParent(parent, tabId, aContext, chromeFlags);
     tp->SetOwnerElement(aFrameElement);
     PBrowserParent* browser = parent->SendPBrowserConstructor(
         // DeallocPBrowserParent() releases this ref.
         nsRefPtr<TabParent>(tp).forget().take(),
+        tabId,
         aContext.AsIPCTabContext(),
         chromeFlags,
         parent->ChildID(),
         parent->IsForApp(),
         parent->IsForBrowser());
 
     if (isInContentProcess) {
         // Just return directly without the following check in content process.
@@ -1122,37 +1159,43 @@ ContentParent::CreateBrowserOrApp(const 
 
     parent->AsContentParent()->MaybeTakeCPUWakeLock(aFrameElement);
 
     return static_cast<TabParent*>(browser);
 }
 
 /*static*/ ContentBridgeParent*
 ContentParent::CreateContentBridgeParent(const TabContext& aContext,
-                                         const hal::ProcessPriority& aPriority)
+                                         const hal::ProcessPriority& aPriority,
+                                         const TabId& aOpenerTabId,
+                                         /*out*/ TabId* aTabId)
 {
+    MOZ_ASSERT(aTabId);
+
     ContentChild* child = ContentChild::GetSingleton();
-    uint64_t id;
+    ContentParentId cpId;
     bool isForApp;
     bool isForBrowser;
     if (!child->SendCreateChildProcess(aContext.AsIPCTabContext(),
                                        aPriority,
-                                       &id,
+                                       aOpenerTabId,
+                                       &cpId,
                                        &isForApp,
-                                       &isForBrowser)) {
+                                       &isForBrowser,
+                                       aTabId)) {
         return nullptr;
     }
-    if (id == 0) {
+    if (cpId == 0) {
         return nullptr;
     }
-    if (!child->CallBridgeToChildProcess(id)) {
+    if (!child->CallBridgeToChildProcess(cpId)) {
         return nullptr;
     }
     ContentBridgeParent* parent = child->GetLastBridge();
-    parent->SetChildID(id);
+    parent->SetChildID(cpId);
     parent->SetIsForApp(isForApp);
     parent->SetIsForBrowser(isForBrowser);
     return parent;
 }
 
 void
 ContentParent::GetAll(nsTArray<ContentParent*>& aArray)
 {
@@ -1471,23 +1514,16 @@ ContentParent::MarkAsDead()
         sPrivateContent->RemoveElement(this);
         if (!sPrivateContent->Length()) {
             delete sPrivateContent;
             sPrivateContent = nullptr;
         }
     }
 
     mIsAlive = false;
-
-    sGrandchildProcessMap.erase(this);
-    for (auto iter = sGrandchildProcessMap.begin();
-         iter != sGrandchildProcessMap.end();
-         iter++) {
-        iter->second.erase(this);
-    }
 }
 
 void
 ContentParent::OnChannelError()
 {
     nsRefPtr<ContentParent> content(this);
 #ifdef MOZ_NUWA_PROCESS
     // Handle app or Nuwa process exit before normal channel error handling.
@@ -1715,27 +1751,27 @@ ContentParent::ActorDestroy(ActorDestroy
     // |this|.  If so, when we go out of scope here, we're deleted and
     // all hell breaks loose.
     //
     // This runnable ensures that a reference to |this| lives on at
     // least until after the current task finishes running.
     NS_DispatchToCurrentThread(new DelayedDeleteContentParentTask(this));
 
     // Destroy any processes created by this ContentParent
-    auto iter = sGrandchildProcessMap.find(this);
-    if (iter != sGrandchildProcessMap.end()) {
-        for(auto child = iter->second.begin();
-            child != iter->second.end();
-            child++) {
-            MessageLoop::current()->PostTask(
-                FROM_HERE,
-                NewRunnableMethod(*child, &ContentParent::ShutDownProcess,
-                                  /* closeWithError */ false));
-        }
+    ContentProcessManager *cpm = ContentProcessManager::GetSingleton();
+    nsTArray<ContentParentId> childIDArray =
+        cpm->GetAllChildProcessById(this->ChildID());
+    for(uint32_t i = 0; i < childIDArray.Length(); i++) {
+        ContentParent* cp = cpm->GetContentProcessById(childIDArray[i]);
+        MessageLoop::current()->PostTask(
+            FROM_HERE,
+            NewRunnableMethod(cp, &ContentParent::ShutDownProcess,
+                              /* closeWithError */ false));
     }
+    cpm->RemoveContentProcess(this->ChildID());
 }
 
 void
 ContentParent::NotifyTabDestroying(PBrowserParent* aTab)
 {
     // There can be more than one PBrowser for a given app process
     // because of popup windows.  PBrowsers can also destroy
     // concurrently.  When all the PBrowsers are destroying, kick off
@@ -1888,16 +1924,18 @@ ContentParent::ContentParent(mozIApplica
     }
     mSubprocess->LaunchAndWaitForProcessHandle(extraArgs);
 
     Open(mSubprocess->GetChannel(), mSubprocess->GetOwnedChildProcessHandle());
 
     InitInternal(aInitialPriority,
                  true, /* Setup off-main thread compositing */
                  true  /* Send registered chrome */);
+
+    ContentProcessManager::GetSingleton()->AddContentProcess(this);
 }
 
 #ifdef MOZ_NUWA_PROCESS
 static const mozilla::ipc::FileDescriptor*
 FindFdProtocolFdMapping(const nsTArray<ProtocolFdMapping>& aFds,
                         ProtocolId aProtoId)
 {
     for (unsigned int i = 0; i < aFds.Length(); i++) {
@@ -1965,16 +2003,18 @@ ContentParent::ContentParent(ContentPare
         priority = PROCESS_PRIORITY_PREALLOC;
     } else {
         priority = PROCESS_PRIORITY_FOREGROUND;
     }
 
     InitInternal(priority,
                  false, /* Setup Off-main thread compositing */
                  false  /* Send registered chrome */);
+
+    ContentProcessManager::GetSingleton()->AddContentProcess(this);
 }
 #endif  // MOZ_NUWA_PROCESS
 
 ContentParent::~ContentParent()
 {
     if (mForceKillTask) {
         mForceKillTask->Cancel();
     }
@@ -2775,20 +2815,20 @@ ContentParent::AllocPBackgroundParent(Tr
 PSharedBufferManagerParent*
 ContentParent::AllocPSharedBufferManagerParent(mozilla::ipc::Transport* aTransport,
                                                 base::ProcessId aOtherProcess)
 {
     return SharedBufferManagerParent::Create(aTransport, aOtherProcess);
 }
 
 bool
-ContentParent::RecvGetProcessAttributes(uint64_t* aId,
+ContentParent::RecvGetProcessAttributes(ContentParentId* aCpId,
                                         bool* aIsForApp, bool* aIsForBrowser)
 {
-    *aId = mChildID;
+    *aCpId = mChildID;
     *aIsForApp = IsForApp();
     *aIsForBrowser = mIsForBrowser;
 
     return true;
 }
 
 bool
 ContentParent::RecvGetXPCOMProcessAttributes(bool* aIsOffline,
@@ -2826,25 +2866,27 @@ ContentParent::AllocPJavaScriptParent()
 
 bool
 ContentParent::DeallocPJavaScriptParent(PJavaScriptParent *parent)
 {
     return nsIContentParent::DeallocPJavaScriptParent(parent);
 }
 
 PBrowserParent*
-ContentParent::AllocPBrowserParent(const IPCTabContext& aContext,
+ContentParent::AllocPBrowserParent(const TabId& aTabId,
+                                   const IPCTabContext& aContext,
                                    const uint32_t& aChromeFlags,
-                                   const uint64_t& aId,
+                                   const ContentParentId& aCpId,
                                    const bool& aIsForApp,
                                    const bool& aIsForBrowser)
 {
-    return nsIContentParent::AllocPBrowserParent(aContext,
+    return nsIContentParent::AllocPBrowserParent(aTabId,
+                                                 aContext,
                                                  aChromeFlags,
-                                                 aId,
+                                                 aCpId,
                                                  aIsForApp,
                                                  aIsForBrowser);
 }
 
 bool
 ContentParent::DeallocPBrowserParent(PBrowserParent* frame)
 {
     return nsIContentParent::DeallocPBrowserParent(frame);
@@ -3820,26 +3862,28 @@ bool
 ContentParent::RecvSystemMessageHandled()
 {
     SystemMessageHandledListener::OnSystemMessageHandled();
     return true;
 }
 
 PBrowserParent*
 ContentParent::SendPBrowserConstructor(PBrowserParent* aActor,
+                                       const TabId& aTabId,
                                        const IPCTabContext& aContext,
                                        const uint32_t& aChromeFlags,
-                                       const uint64_t& aId,
+                                       const ContentParentId& aCpId,
                                        const bool& aIsForApp,
                                        const bool& aIsForBrowser)
 {
     return PContentParent::SendPBrowserConstructor(aActor,
+                                                   aTabId,
                                                    aContext,
                                                    aChromeFlags,
-                                                   aId,
+                                                   aCpId,
                                                    aIsForApp,
                                                    aIsForBrowser);
 }
 
 bool
 ContentParent::RecvCreateFakeVolume(const nsString& fsName, const nsString& mountPoint)
 {
 #ifdef MOZ_WIDGET_GONK
@@ -4128,16 +4172,76 @@ ContentParent::NotifyUpdatedDictionaries
     InfallibleTArray<nsString> dictionaries;
     spellChecker->GetDictionaryList(&dictionaries);
 
     for (size_t i = 0; i < processes.Length(); ++i) {
         unused << processes[i]->SendUpdateDictionaryList(dictionaries);
     }
 }
 
+/*static*/ TabId
+ContentParent::AllocateTabId(const TabId& aOpenerTabId,
+                             const IPCTabContext& aContext,
+                             const ContentParentId& aCpId)
+{
+    TabId tabId;
+    if (XRE_GetProcessType() == GeckoProcessType_Default) {
+        ContentProcessManager *cpm = ContentProcessManager::GetSingleton();
+        tabId = cpm->AllocateTabId(aOpenerTabId, aContext, aCpId);
+    }
+    else {
+        ContentChild::GetSingleton()->SendAllocateTabId(aOpenerTabId,
+                                                        aContext,
+                                                        aCpId,
+                                                        &tabId);
+    }
+    return tabId;
+}
+
+/*static*/ void
+ContentParent::DeallocateTabId(const TabId& aTabId,
+                               const ContentParentId& aCpId)
+{
+    if (XRE_GetProcessType() == GeckoProcessType_Default) {
+        ContentProcessManager::GetSingleton()->DeallocateTabId(aCpId,
+                                                               aTabId);
+    }
+    else {
+        ContentChild::GetSingleton()->SendDeallocateTabId(aTabId);
+    }
+}
+
+bool
+ContentParent::RecvAllocateTabId(const TabId& aOpenerTabId,
+                                 const IPCTabContext& aContext,
+                                 const ContentParentId& aCpId,
+                                 TabId* aTabId)
+{
+    *aTabId = AllocateTabId(aOpenerTabId, aContext, aCpId);
+    if (!(*aTabId)) {
+        return false;
+    }
+    return true;
+}
+
+bool
+ContentParent::RecvDeallocateTabId(const TabId& aTabId)
+{
+    DeallocateTabId(aTabId, this->ChildID());
+    return true;
+}
+
+nsTArray<TabContext>
+ContentParent::GetManagedTabContext()
+{
+    return Move(ContentProcessManager::GetSingleton()->
+        GetTabContextByContentProcess(this->ChildID()));
+}
+
+
 } // namespace dom
 } // namespace mozilla
 
 NS_IMPL_ISUPPORTS(ParentIdleListener, nsIObserver)
 
 NS_IMETHODIMP
 ParentIdleListener::Observe(nsISupports*, const char* aTopic, const char16_t* aData) {
     mozilla::unused << mParent->SendNotifyIdleObserver(mObserver,
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -138,20 +138,22 @@ public:
     static void GetAllEvenIfDead(nsTArray<ContentParent*>& aArray);
 
     static bool IgnoreIPCPrincipal();
 
     static void NotifyUpdatedDictionaries();
 
     virtual bool RecvCreateChildProcess(const IPCTabContext& aContext,
                                         const hal::ProcessPriority& aPriority,
-                                        uint64_t* aId,
+                                        const TabId& aOpenerTabId,
+                                        ContentParentId* aCpId,
                                         bool* aIsForApp,
-                                        bool* aIsForBrowser) MOZ_OVERRIDE;
-    virtual bool AnswerBridgeToChildProcess(const uint64_t& id) MOZ_OVERRIDE;
+                                        bool* aIsForBrowser,
+                                        TabId* aTabId) MOZ_OVERRIDE;
+    virtual bool AnswerBridgeToChildProcess(const ContentParentId& aCpId) MOZ_OVERRIDE;
 
     NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(ContentParent, nsIObserver)
 
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     NS_DECL_NSIOBSERVER
     NS_DECL_NSIDOMGEOPOSITIONCALLBACK
 
     /**
@@ -174,16 +176,23 @@ public:
     void NotifyTabDestroyed(PBrowserParent* aTab,
                             bool aNotifiedDestroying);
 
     TestShellParent* CreateTestShell();
     bool DestroyTestShell(TestShellParent* aTestShell);
     TestShellParent* GetTestShellSingleton();
     jsipc::JavaScriptShared* GetCPOWManager() MOZ_OVERRIDE;
 
+    static TabId
+    AllocateTabId(const TabId& aOpenerTabId,
+                  const IPCTabContext& aContext,
+                  const ContentParentId& aCpId);
+    static void
+    DeallocateTabId(const TabId& aTabId, const ContentParentId& aCpId);
+
     void ReportChildAlreadyBlocked();
     bool RequestRunToCompletion();
 
     bool IsAlive();
     virtual bool IsForApp() MOZ_OVERRIDE;
     virtual bool IsForBrowser() MOZ_OVERRIDE
     {
       return mIsForBrowser;
@@ -212,17 +221,17 @@ public:
 
     /**
      * Kill our subprocess and make sure it dies.  Should only be used
      * in emergency situations since it bypasses the normal shutdown
      * process.
      */
     void KillHard();
 
-    uint64_t ChildID() MOZ_OVERRIDE { return mChildID; }
+    ContentParentId ChildID() MOZ_OVERRIDE { return mChildID; }
     const nsString& AppManifestURL() const { return mAppManifestURL; }
 
     bool IsPreallocated();
 
     /**
      * Get a user-friendly name for this ContentParent.  We make no guarantees
      * about this name: It might not be unique, apps can spoof special names,
      * etc.  So please don't use this name to make any decisions about the
@@ -277,16 +286,24 @@ public:
     bool CycleCollectWithLogs(bool aDumpAllTraces,
                               nsICycleCollectorLogSink* aSink,
                               nsIDumpGCAndCCLogsCallback* aCallback);
 
     virtual PBlobParent* SendPBlobConstructor(
         PBlobParent* aActor,
         const BlobConstructorParams& aParams) MOZ_OVERRIDE;
 
+    virtual bool RecvAllocateTabId(const TabId& aOpenerTabId,
+                                   const IPCTabContext& aContext,
+                                   const ContentParentId& aCpId,
+                                   TabId* aTabId) MOZ_OVERRIDE;
+
+    virtual bool RecvDeallocateTabId(const TabId& aTabId) MOZ_OVERRIDE;
+
+    nsTArray<TabContext> GetManagedTabContext();
 protected:
     void OnChannelConnected(int32_t pid) MOZ_OVERRIDE;
     virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
     void OnNuwaForkTimeout();
 
     bool ShouldContinueFromReplyTimeout() MOZ_OVERRIDE;
 
 private:
@@ -305,25 +322,28 @@ private:
     GetNewOrPreallocatedAppProcess(mozIApplication* aApp,
                                    hal::ProcessPriority aInitialPriority,
                                    ContentParent* aOpener,
                                    /*out*/ bool* aTookPreAllocated = nullptr);
 
     static hal::ProcessPriority GetInitialProcessPriority(Element* aFrameElement);
 
     static ContentBridgeParent* CreateContentBridgeParent(const TabContext& aContext,
-                                                          const hal::ProcessPriority& aPriority);
+                                                          const hal::ProcessPriority& aPriority,
+                                                          const TabId& aOpenerTabId,
+                                                          /*out*/ TabId* aTabId);
 
     // Hide the raw constructor methods since we don't want client code
     // using them.
     virtual PBrowserParent* SendPBrowserConstructor(
         PBrowserParent* actor,
+        const TabId& aTabId,
         const IPCTabContext& context,
         const uint32_t& chromeFlags,
-        const uint64_t& aId,
+        const ContentParentId& aCpId,
         const bool& aIsForApp,
         const bool& aIsForBrowser) MOZ_OVERRIDE;
     using PContentParent::SendPTestShellConstructor;
 
     // No more than one of !!aApp, aIsForBrowser, and aIsForPreallocated may be
     // true.
     ContentParent(mozIApplication* aApp,
                   ContentParent* aOpener,
@@ -404,30 +424,31 @@ private:
 
     PSharedBufferManagerParent*
     AllocPSharedBufferManagerParent(mozilla::ipc::Transport* aTranport,
                                      base::ProcessId aOtherProcess) MOZ_OVERRIDE;
     PBackgroundParent*
     AllocPBackgroundParent(Transport* aTransport, ProcessId aOtherProcess)
                            MOZ_OVERRIDE;
 
-    virtual bool RecvGetProcessAttributes(uint64_t* aId,
+    virtual bool RecvGetProcessAttributes(ContentParentId* aCpId,
                                           bool* aIsForApp,
                                           bool* aIsForBrowser) MOZ_OVERRIDE;
     virtual bool RecvGetXPCOMProcessAttributes(bool* aIsOffline,
                                                InfallibleTArray<nsString>* dictionaries,
                                                ClipboardCapabilities* clipboardCaps)
         MOZ_OVERRIDE;
 
     virtual bool DeallocPJavaScriptParent(mozilla::jsipc::PJavaScriptParent*) MOZ_OVERRIDE;
 
     virtual bool DeallocPRemoteSpellcheckEngineParent(PRemoteSpellcheckEngineParent*) MOZ_OVERRIDE;
-    virtual PBrowserParent* AllocPBrowserParent(const IPCTabContext& aContext,
+    virtual PBrowserParent* AllocPBrowserParent(const TabId& aTabId,
+                                                const IPCTabContext& aContext,
                                                 const uint32_t& aChromeFlags,
-                                                const uint64_t& aId,
+                                                const ContentParentId& aCpId,
                                                 const bool& aIsForApp,
                                                 const bool& aIsForBrowser) MOZ_OVERRIDE;
     virtual bool DeallocPBrowserParent(PBrowserParent* frame) MOZ_OVERRIDE;
 
     virtual PDeviceStorageRequestParent*
     AllocPDeviceStorageRequestParent(const DeviceStorageParams&) MOZ_OVERRIDE;
     virtual bool DeallocPDeviceStorageRequestParent(PDeviceStorageRequestParent*) MOZ_OVERRIDE;
 
@@ -687,17 +708,17 @@ private:
 
     // If you add strong pointers to cycle collected objects here, be sure to
     // release these objects in ShutDownProcess.  See the comment there for more
     // details.
 
     GeckoChildProcessHost* mSubprocess;
     ContentParent* mOpener;
 
-    uint64_t mChildID;
+    ContentParentId mChildID;
     int32_t mGeolocationWatchID;
 
     nsString mAppManifestURL;
 
     /**
      * We cache mAppName instead of looking it up using mAppManifestURL when we
      * need it because it turns out that getting an app from the apps service is
      * expensive.
new file mode 100644
--- /dev/null
+++ b/dom/ipc/ContentProcessManager.cpp
@@ -0,0 +1,276 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et ft=cpp : */
+/* 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 "ContentProcessManager.h"
+#include "ContentParent.h"
+
+#include "mozilla/StaticPtr.h"
+#include "mozilla/ClearOnShutdown.h"
+
+#include "nsPrintfCString.h"
+
+// XXX need another bug to move this to a common header.
+#ifdef DISABLE_ASSERTS_FOR_FUZZING
+#define ASSERT_UNLESS_FUZZING(...) do { } while (0)
+#else
+#define ASSERT_UNLESS_FUZZING(...) MOZ_ASSERT(false, __VA_ARGS__)
+#endif
+
+namespace mozilla {
+namespace dom {
+
+static uint64_t gTabId = 0;
+
+/* static */
+StaticAutoPtr<ContentProcessManager>
+ContentProcessManager::sSingleton;
+
+/* static */ ContentProcessManager*
+ContentProcessManager::GetSingleton()
+{
+  MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
+
+  if (!sSingleton) {
+    sSingleton = new ContentProcessManager();
+    ClearOnShutdown(&sSingleton);
+  }
+  return sSingleton;
+}
+
+void
+ContentProcessManager::AddContentProcess(ContentParent* aChildCp,
+                                         const ContentParentId& aParentCpId)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aChildCp);
+
+  ContentProcessInfo info;
+  info.mCp = aChildCp;
+  info.mParentCpId = aParentCpId;
+  mContentParentMap[aChildCp->ChildID()] = info;
+}
+
+void
+ContentProcessManager::RemoveContentProcess(const ContentParentId& aChildCpId)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mContentParentMap.find(aChildCpId) != mContentParentMap.end());
+
+  mContentParentMap.erase(aChildCpId);
+  for (auto iter = mContentParentMap.begin();
+       iter != mContentParentMap.end();
+       ++iter) {
+    if (!iter->second.mChildrenCpId.empty()) {
+      iter->second.mChildrenCpId.erase(aChildCpId);
+    }
+  }
+}
+
+bool
+ContentProcessManager::AddGrandchildProcess(const ContentParentId& aParentCpId,
+                                            const ContentParentId& aChildCpId)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  auto iter = mContentParentMap.find(aParentCpId);
+  if (NS_WARN_IF(iter == mContentParentMap.end())) {
+    ASSERT_UNLESS_FUZZING("Parent process should be already in map!");
+    return false;
+  }
+  iter->second.mChildrenCpId.insert(aChildCpId);
+  return true;
+}
+
+bool
+ContentProcessManager::GetParentProcessId(const ContentParentId& aChildCpId,
+                                          /*out*/ ContentParentId* aParentCpId)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  auto iter = mContentParentMap.find(aChildCpId);
+  if (NS_WARN_IF(iter == mContentParentMap.end())) {
+    ASSERT_UNLESS_FUZZING();
+    return false;
+  }
+  *aParentCpId = iter->second.mParentCpId;
+  return true;
+}
+
+ContentParent*
+ContentProcessManager::GetContentProcessById(const ContentParentId& aChildCpId)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  auto iter = mContentParentMap.find(aChildCpId);
+  if (NS_WARN_IF(iter == mContentParentMap.end())) {
+    ASSERT_UNLESS_FUZZING();
+    return nullptr;
+  }
+  return iter->second.mCp;
+}
+
+nsTArray<ContentParentId>
+ContentProcessManager::GetAllChildProcessById(const ContentParentId& aParentCpId)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsTArray<ContentParentId> cpIdArray;
+  auto iter = mContentParentMap.find(aParentCpId);
+  if (NS_WARN_IF(iter == mContentParentMap.end())) {
+    ASSERT_UNLESS_FUZZING();
+    return Move(cpIdArray);
+  }
+
+  for (auto cpIter = iter->second.mChildrenCpId.begin();
+       cpIter != iter->second.mChildrenCpId.end();
+       ++cpIter) {
+    cpIdArray.AppendElement(*cpIter);
+  }
+
+  return Move(cpIdArray);
+}
+
+TabId
+ContentProcessManager::AllocateTabId(const TabId& aOpenerTabId,
+                                     const IPCTabContext& aContext,
+                                     const ContentParentId& aChildCpId)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  auto iter = mContentParentMap.find(aChildCpId);
+  if (NS_WARN_IF(iter == mContentParentMap.end())) {
+    ASSERT_UNLESS_FUZZING();
+    return TabId(0);
+  }
+
+  struct RemoteFrameInfo info;
+
+  const IPCTabAppBrowserContext& appBrowser = aContext.appBrowserContext();
+  // If it's a PopupIPCTabContext, it's the case that a TabChild want to
+  // open a new tab. aOpenerTabId has to be it's parent frame's opener id.
+  if (appBrowser.type() == IPCTabAppBrowserContext::TPopupIPCTabContext) {
+    auto remoteFrameIter = iter->second.mRemoteFrames.find(aOpenerTabId);
+    if (remoteFrameIter == iter->second.mRemoteFrames.end()) {
+      ASSERT_UNLESS_FUZZING("Failed to find parent frame's opener id.");
+      return TabId(0);
+    }
+
+    info.mOpenerTabId = remoteFrameIter->second.mOpenerTabId;
+
+    const PopupIPCTabContext &ipcContext = appBrowser.get_PopupIPCTabContext();
+    MOZ_ASSERT(ipcContext.opener().type() == PBrowserOrId::TTabId);
+
+    remoteFrameIter = iter->second.mRemoteFrames.find(ipcContext.opener().get_TabId());
+    if (remoteFrameIter == iter->second.mRemoteFrames.end()) {
+      ASSERT_UNLESS_FUZZING("Failed to find tab id.");
+      return TabId(0);
+    }
+
+    info.mContext = remoteFrameIter->second.mContext;
+  }
+  else {
+    MaybeInvalidTabContext tc(aContext);
+    if (!tc.IsValid()) {
+      NS_ERROR(nsPrintfCString("Received an invalid TabContext from "
+                               "the child process. (%s)",
+                               tc.GetInvalidReason()).get());
+      return TabId(0);
+    }
+    info.mOpenerTabId = aOpenerTabId;
+    info.mContext = tc.GetTabContext();
+  }
+
+  mUniqueId = ++gTabId;
+  iter->second.mRemoteFrames[mUniqueId] = info;
+
+  return mUniqueId;
+}
+
+void
+ContentProcessManager::DeallocateTabId(const ContentParentId& aChildCpId,
+                                       const TabId& aChildTabId)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  auto iter = mContentParentMap.find(aChildCpId);
+  if (NS_WARN_IF(iter == mContentParentMap.end())) {
+    ASSERT_UNLESS_FUZZING();
+    return;
+  }
+
+  auto remoteFrameIter = iter->second.mRemoteFrames.find(aChildTabId);
+  if (remoteFrameIter != iter->second.mRemoteFrames.end()) {
+    iter->second.mRemoteFrames.erase(aChildTabId);
+  }
+}
+
+nsTArray<uint64_t>
+ContentProcessManager::GetAppIdsByContentProcess(const ContentParentId& aChildCpId)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsTArray<uint64_t> appIdArray;
+  auto iter = mContentParentMap.find(aChildCpId);
+  if (NS_WARN_IF(iter == mContentParentMap.end())) {
+    ASSERT_UNLESS_FUZZING();
+    return Move(appIdArray);
+  }
+
+  for (auto remoteFrameIter = iter->second.mRemoteFrames.begin();
+       remoteFrameIter != iter->second.mRemoteFrames.end();
+       ++remoteFrameIter) {
+    appIdArray.AppendElement(remoteFrameIter->second.mContext.OwnOrContainingAppId());
+  }
+
+  return Move(appIdArray);
+}
+
+nsTArray<TabContext>
+ContentProcessManager::GetTabContextByContentProcess(const ContentParentId& aChildCpId)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsTArray<TabContext> tabContextArray;
+  auto iter = mContentParentMap.find(aChildCpId);
+  if (NS_WARN_IF(iter == mContentParentMap.end())) {
+    ASSERT_UNLESS_FUZZING();
+    return Move(tabContextArray);
+  }
+
+  for (auto remoteFrameIter = iter->second.mRemoteFrames.begin();
+       remoteFrameIter != iter->second.mRemoteFrames.end();
+       ++remoteFrameIter) {
+    tabContextArray.AppendElement(remoteFrameIter->second.mContext);
+  }
+
+  return Move(tabContextArray);
+}
+
+bool
+ContentProcessManager::GetRemoteFrameOpenerTabId(const ContentParentId& aChildCpId,
+                                                 const TabId& aChildTabId,
+                                                 /*out*/TabId* aOpenerTabId)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  auto iter = mContentParentMap.find(aChildCpId);
+  if (NS_WARN_IF(iter == mContentParentMap.end())) {
+    ASSERT_UNLESS_FUZZING();
+    return false;
+  }
+
+  auto remoteFrameIter = iter->second.mRemoteFrames.find(aChildTabId);
+  if (NS_WARN_IF(remoteFrameIter == iter->second.mRemoteFrames.end())) {
+    ASSERT_UNLESS_FUZZING();
+    return false;
+  }
+
+  *aOpenerTabId = remoteFrameIter->second.mOpenerTabId;
+
+  return true;
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/ipc/ContentProcessManager.h
@@ -0,0 +1,122 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et ft=cpp : */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_ContentProcessManager_h
+#define mozilla_dom_ContentProcessManager_h
+
+#include <map>
+#include <set>
+#include "mozilla/StaticPtr.h"
+#include "mozilla/dom/TabContext.h"
+#include "mozilla/dom/ipc/IdType.h"
+#include "nsTArray.h"
+
+namespace mozilla {
+namespace dom {
+class ContentParent;
+
+struct RemoteFrameInfo
+{
+  TabId mOpenerTabId;
+  TabContext mContext;
+};
+
+struct ContentProcessInfo
+{
+  ContentParent* mCp;
+  ContentParentId mParentCpId;
+  std::set<ContentParentId> mChildrenCpId;
+  std::map<TabId, RemoteFrameInfo> mRemoteFrames;
+};
+
+class ContentProcessManager MOZ_FINAL
+{
+public:
+  static ContentProcessManager* GetSingleton();
+  ~ContentProcessManager() {MOZ_COUNT_DTOR(ContentProcessManager);};
+
+  /**
+   * Add a new content process into the map.
+   * If aParentCpId is not 0, it's a nested content process.
+   */
+  void AddContentProcess(ContentParent* aChildCp,
+                         const ContentParentId& aParentCpId = ContentParentId(0));
+  /**
+   * Remove the content process by id.
+   */
+  void RemoveContentProcess(const ContentParentId& aChildCpId);
+  /**
+   * Add a grandchild content process into the map.
+   * aParentCpId must be already added in the map by AddContentProcess().
+   */
+  bool AddGrandchildProcess(const ContentParentId& aParentCpId,
+                            const ContentParentId& aChildCpId);
+  /**
+   * Get the parent process's id by child process's id.
+   * Used to check if a child really belongs to the parent.
+   */
+  bool GetParentProcessId(const ContentParentId& aChildCpId,
+                          /*out*/ ContentParentId* aParentCpId);
+  /**
+   * Return the ContentParent pointer by id.
+   */
+  ContentParent* GetContentProcessById(const ContentParentId& aChildCpId);
+
+  /**
+   * Return a list of all child process's id.
+   */
+  nsTArray<ContentParentId>
+  GetAllChildProcessById(const ContentParentId& aParentCpId);
+
+  /**
+   * Allocate a tab id for the given content process's id.
+   * Used when a content process wants to create a new tab. aOpenerTabId and
+   * aContext are saved in RemoteFrameInfo, which is a part of ContentProcessInfo.
+   * We can use the tab id and process id to locate the TabContext for future use.
+   */
+  TabId AllocateTabId(const TabId& aOpenerTabId,
+                      const IPCTabContext& aContext,
+                      const ContentParentId& aChildCpId);
+
+  /**
+   * Remove the RemoteFrameInfo by the given process and tab id.
+   */
+  void DeallocateTabId(const ContentParentId& aChildCpId,
+                       const TabId& aChildTabId);
+
+  /**
+   * Get all app ids which are inside the given content process.
+   * XXX Currently not used. Plan to be used for bug 1020186.
+   */
+  nsTArray<uint64_t>
+  GetAppIdsByContentProcess(const ContentParentId& aChildCpId);
+
+  /**
+   * Get all TabContext which are inside the given content process.
+   * Used for AppProcessChecker to cehck app status.
+   */
+  nsTArray<TabContext>
+  GetTabContextByContentProcess(const ContentParentId& aChildCpId);
+
+  /**
+   * Query a tab's opener id by the given process and tab id.
+   * XXX Currently not used. Plan to be used for bug 1020179.
+   */
+  bool GetRemoteFrameOpenerTabId(const ContentParentId& aChildCpId,
+                                 const TabId& aChildTabId,
+                                 /*out*/ TabId* aOpenerTabId);
+
+private:
+  static StaticAutoPtr<ContentProcessManager> sSingleton;
+  TabId mUniqueId;
+  std::map<ContentParentId, ContentProcessInfo> mContentParentMap;
+
+  ContentProcessManager() {MOZ_COUNT_CTOR(ContentProcessManager);};
+};
+
+} // namespace dom
+} // namespace mozilla
+#endif
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/ipc/IdType.h
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set sw=4 ts=8 et 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 mozilla_dom_IdType_h
+#define mozilla_dom_IdType_h
+
+#include "ipc/IPCMessageUtils.h"
+
+namespace IPC {
+template<typename T> struct ParamTraits;
+}
+
+namespace mozilla {
+namespace dom {
+class ContentParent;
+class TabParent;
+
+
+template<typename T>
+class IdType
+{
+
+  friend struct IPC::ParamTraits<IdType<T>>;
+
+public:
+  IdType() : mId(0) {}
+  explicit IdType(uint64_t aId) : mId(aId) {}
+
+  operator uint64_t() const { return mId; }
+
+  IdType& operator=(uint64_t aId)
+  {
+    mId = aId;
+    return *this;
+  }
+
+  bool operator<(const IdType& rhs)
+  {
+    return mId < rhs.mId;
+  }
+private:
+  uint64_t mId;
+};
+
+typedef IdType<TabParent> TabId;
+typedef IdType<ContentParent> ContentParentId;
+
+} // namespace dom
+} // namespace mozilla
+
+namespace IPC {
+
+template<typename T>
+struct ParamTraits<mozilla::dom::IdType<T>>
+{
+  typedef mozilla::dom::IdType<T> paramType;
+
+  static void Write(Message* aMsg, const paramType& aParam)
+  {
+    WriteParam(aMsg, aParam.mId);
+  }
+
+  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  {
+    return ReadParam(aMsg, aIter, &aResult->mId);
+  }
+};
+
+}
+
+#endif
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/ipc/PBrowserOrId.ipdlh
@@ -0,0 +1,21 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et tw=80 ft=c: */
+/* 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 protocol PBrowser;
+
+using mozilla::dom::TabId from "mozilla/dom/ipc/IdType.h";
+
+namespace mozilla {
+namespace dom {
+
+union PBrowserOrId
+{
+  nullable PBrowser;
+  TabId;
+};
+
+} // namespace dom
+} // namespace mozilla
\ No newline at end of file
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -62,16 +62,18 @@ using struct mozilla::void_t from "ipc/I
 using mozilla::dom::asmjscache::OpenMode from "mozilla/dom/asmjscache/AsmJSCache.h";
 using mozilla::dom::asmjscache::WriteParams from "mozilla/dom/asmjscache/AsmJSCache.h";
 using mozilla::dom::AudioChannel from "mozilla/dom/AudioChannelBinding.h";
 using mozilla::dom::AudioChannelState from "AudioChannelCommon.h";
 using mozilla::dom::NativeThreadId from "mozilla/dom/TabMessageUtils.h";
 using mozilla::dom::quota::PersistenceType from "mozilla/dom/quota/PersistenceType.h";
 using mozilla::hal::ProcessPriority from "mozilla/HalTypes.h";
 using gfxIntSize from "nsSize.h";
+using mozilla::dom::TabId from "mozilla/dom/ipc/IdType.h";
+using mozilla::dom::ContentParentId from "mozilla/dom/ipc/IdType.h";
 
 union ChromeRegistryItem
 {
     ChromePackage;
     OverrideMapping;
     ResourceMapping;
 };
 
@@ -380,18 +382,18 @@ both:
     // browser element.
     //
     // This allows the parent to prevent a malicious child from escalating its
     // privileges by requesting a PBrowser corresponding to a highly-privileged
     // app; the child can only request privileges for an app which the child has
     // access to (in the form of a TabChild).
     //
     // Keep the last 3 attributes in sync with GetProcessAttributes!
-    async PBrowser(IPCTabContext context, uint32_t chromeFlags,
-                   uint64_t id, bool isForApp, bool isForBrowser);
+    async PBrowser(TabId tabId, IPCTabContext context, uint32_t chromeFlags,
+                   ContentParentId cpId, bool isForApp, bool isForBrowser);
 
     async PBlob(BlobConstructorParams params);
 
     PFileDescriptorSet(FileDescriptor fd);
 
 child:
     /**
      * Enable system-level sandboxing features, if available.  Can
@@ -515,25 +517,26 @@ parent:
      * |id| is a unique ID among all subprocesses.  When |isForApp &&
      * isForBrowser|, we're loading <browser> for an app.  When
      * |isForBrowser|, we're loading <browser>.  When |!isForApp &&
      * !isForBrowser|, we're probably loading <xul:browser remote>.
      *
      * Keep the return values in sync with PBrowser()!
      */
     sync GetProcessAttributes()
-        returns (uint64_t id, bool isForApp, bool isForBrowser);
+        returns (ContentParentId cpId, bool isForApp, bool isForBrowser);
     sync GetXPCOMProcessAttributes()
         returns (bool isOffline, nsString[] dictionaries,
                  ClipboardCapabilities clipboardCaps);
 
     sync CreateChildProcess(IPCTabContext context,
-                            ProcessPriority priority)
-        returns (uint64_t id, bool isForApp, bool isForBrowser);
-    intr BridgeToChildProcess(uint64_t id);
+                            ProcessPriority priority,
+                            TabId openerTabId)
+        returns (ContentParentId cpId, bool isForApp, bool isForBrowser, TabId tabId);
+    intr BridgeToChildProcess(ContentParentId cpId);
 
     async PJavaScript();
 
     sync PRemoteSpellcheckEngine();
     PDeviceStorageRequest(DeviceStorageParams params);
 
     PFileSystemRequest(FileSystemParams params);
 
@@ -738,15 +741,23 @@ parent:
     // Use only for testing!
     sync GetFileReferences(PersistenceType persistenceType,
                            nsCString origin,
                            nsString databaseName,
                            int64_t fileId)
       returns (int32_t refCnt, int32_t dBRefCnt, int32_t sliceRefCnt,
                bool result);
 
+    /**
+     * Tell the chrome process there is an creation of PBrowser.
+     * return a system-wise unique Id.
+     */
+    sync AllocateTabId(TabId openerTabId, IPCTabContext context, ContentParentId cpId)
+        returns (TabId tabId);
+    async DeallocateTabId(TabId tabId);
+
 both:
      AsyncMessage(nsString aMessage, ClonedMessageData aData,
                   CpowEntry[] aCpows, Principal aPrincipal);
 };
 
 }
 }
--- a/dom/ipc/PContentBridge.ipdl
+++ b/dom/ipc/PContentBridge.ipdl
@@ -9,16 +9,18 @@ include protocol PBrowser;
 include protocol PContent;
 include protocol PJavaScript;
 
 include DOMTypes;
 include JavaScriptTypes;
 include PTabContext;
 
 using class IPC::Principal from "mozilla/dom/PermissionMessageUtils.h";
+using mozilla::dom::TabId from "mozilla/dom/ipc/IdType.h";
+using mozilla::dom::ContentParentId from "mozilla/dom/ipc/IdType.h";
 
 namespace mozilla {
 namespace dom {
 
 /*
  * PContentBridge allows us to represent a parent/child relationship between two
  * child processes.  When a child process wants to open its own child, it asks
  * the root process to create a new process and then bridge them.  The first
@@ -36,18 +38,18 @@ prio(normal upto high) intr protocol PCo
 
 parent:
     sync SyncMessage(nsString aMessage, ClonedMessageData aData,
                      CpowEntry[] aCpows, Principal aPrincipal)
       returns (nsString[] retval);
 both:
     // Both the parent and the child can construct the PBrowser.
     // See the comment in PContent::PBrowser().
-    async PBrowser(IPCTabContext context, uint32_t chromeFlags,
-                   uint64_t id, bool isForApp, bool isForBrowser);
+    async PBrowser(TabId tabId, IPCTabContext context, uint32_t chromeFlags,
+                   ContentParentId cpId, bool isForApp, bool isForBrowser);
 
     async PBlob(BlobConstructorParams params);
 
     async PJavaScript();
 
     AsyncMessage(nsString aMessage, ClonedMessageData aData,
                  CpowEntry[] aCpows, Principal aPrincipal);
 };
--- a/dom/ipc/PTabContext.ipdlh
+++ b/dom/ipc/PTabContext.ipdlh
@@ -1,16 +1,16 @@
 /* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 8 -*- */
 /* vim: set sw=4 ts=8 et tw=80 ft=cpp : */
 /* 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 protocol PBrowser;
-
+include PBrowserOrId;
 
 using mozilla::layout::ScrollingBehavior from "mozilla/layout/RenderFrameUtils.h";
 
 namespace mozilla {
 namespace dom {
 
 // An IPCTabContext which corresponds to a PBrowser opened by a child when it
 // receives window.open().
@@ -22,17 +22,17 @@ namespace dom {
 // If isBrowserElement is true, the frame's browserFrameOwnerAppId will be equal
 // to the opener's app-id.
 //
 // It's an error to set isBrowserElement == false if opener is a browser
 // element.  Such a PopupIPCTabContext should be rejected by code which receives
 // it.
 struct PopupIPCTabContext
 {
-  PBrowser opener;
+  PBrowserOrId opener;
   bool isBrowserElement;
 };
 
 // An IPCTabContext which corresponds to an app frame.
 struct AppFrameIPCTabContext
 {
   // The ID of the app this frame corresponds to.  May be NO_APP_ID.
   uint32_t ownAppId;
--- a/dom/ipc/ProcessPriorityManager.cpp
+++ b/dom/ipc/ProcessPriorityManager.cpp
@@ -467,24 +467,25 @@ ProcessPriorityManagerImpl::Observe(
   return NS_OK;
 }
 
 already_AddRefed<ParticularProcessPriorityManager>
 ProcessPriorityManagerImpl::GetParticularProcessPriorityManager(
   ContentParent* aContentParent)
 {
   nsRefPtr<ParticularProcessPriorityManager> pppm;
-  mParticularManagers.Get(aContentParent->ChildID(), &pppm);
+  uint64_t cpId = aContentParent->ChildID();
+  mParticularManagers.Get(cpId, &pppm);
   if (!pppm) {
     pppm = new ParticularProcessPriorityManager(aContentParent);
     pppm->Init();
-    mParticularManagers.Put(aContentParent->ChildID(), pppm);
+    mParticularManagers.Put(cpId, pppm);
 
     FireTestOnlyObserverNotification("process-created",
-      nsPrintfCString("%lld", aContentParent->ChildID()));
+      nsPrintfCString("%lld", cpId));
   }
 
   return pppm.forget();
 }
 
 void
 ProcessPriorityManagerImpl::SetProcessPriority(ContentParent* aContentParent,
                                                ProcessPriority aPriority,
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -728,33 +728,34 @@ private:
         mInfo->FireCallback();
         return NS_OK;
     }
 };
 
 StaticRefPtr<TabChild> sPreallocatedTab;
 
 /*static*/
-std::map<uint64_t, nsRefPtr<TabChild> >&
+std::map<TabId, nsRefPtr<TabChild>>&
 TabChild::NestedTabChildMap()
 {
   MOZ_ASSERT(NS_IsMainThread());
-  static std::map<uint64_t, nsRefPtr<TabChild> > sNestedTabChildMap;
+  static std::map<TabId, nsRefPtr<TabChild>> sNestedTabChildMap;
   return sNestedTabChildMap;
 }
 
 /*static*/ void
 TabChild::PreloadSlowThings()
 {
     MOZ_ASSERT(!sPreallocatedTab);
 
     // Pass nullptr to aManager since at this point the TabChild is
     // not connected to any manager. Any attempt to use the TabChild
     // in IPC will crash.
     nsRefPtr<TabChild> tab(new TabChild(nullptr,
+                                        TabId(0),
                                         TabContext(), /* chromeFlags */ 0));
     if (!NS_SUCCEEDED(tab->Init()) ||
         !tab->InitTabChildGlobal(DONT_LOAD_SCRIPTS)) {
         return;
     }
     // Just load and compile these scripts, but don't run them.
     tab->TryCacheLoadAndCompileScript(BROWSER_ELEMENT_CHILD_SCRIPT, true);
     // Load, compile, and run these scripts.
@@ -775,41 +776,44 @@ TabChild::PreloadSlowThings()
     }
 
     sPreallocatedTab = tab;
     ClearOnShutdown(&sPreallocatedTab);
 }
 
 /*static*/ already_AddRefed<TabChild>
 TabChild::Create(nsIContentChild* aManager,
+                 const TabId& aTabId,
                  const TabContext &aContext,
                  uint32_t aChromeFlags)
 {
     if (sPreallocatedTab &&
         sPreallocatedTab->mChromeFlags == aChromeFlags &&
         aContext.IsBrowserOrApp()) {
 
         nsRefPtr<TabChild> child = sPreallocatedTab.get();
         sPreallocatedTab = nullptr;
 
         MOZ_ASSERT(!child->mTriedBrowserInit);
 
         child->mManager = aManager;
+        child->SetTabId(aTabId);
         child->SetTabContext(aContext);
         child->NotifyTabContextUpdated();
         return child.forget();
     }
 
-    nsRefPtr<TabChild> iframe = new TabChild(aManager,
+    nsRefPtr<TabChild> iframe = new TabChild(aManager, aTabId,
                                              aContext, aChromeFlags);
     return NS_SUCCEEDED(iframe->Init()) ? iframe.forget() : nullptr;
 }
 
 
 TabChild::TabChild(nsIContentChild* aManager,
+                   const TabId& aTabId,
                    const TabContext& aContext,
                    uint32_t aChromeFlags)
   : TabContext(aContext)
   , mRemoteFrame(nullptr)
   , mManager(aManager)
   , mChromeFlags(aChromeFlags)
   , mLayersId(0)
   , mOuterRect(0, 0, 0, 0)
@@ -822,25 +826,31 @@ TabChild::TabChild(nsIContentChild* aMan
   , mOrientation(eScreenOrientation_PortraitPrimary)
   , mUpdateHitRegion(false)
   , mPendingTouchPreventedResponse(false)
   , mTouchEndCancelled(false)
   , mEndTouchIsClick(false)
   , mIgnoreKeyPressEvent(false)
   , mActiveElementManager(new ActiveElementManager())
   , mHasValidInnerSize(false)
-  , mUniqueId(0)
   , mDestroyed(false)
+  , mUniqueId(aTabId)
 {
   if (!sActiveDurationMsSet) {
     Preferences::AddIntVarCache(&sActiveDurationMs,
                                 "ui.touch_activation.duration_ms",
                                 sActiveDurationMs);
     sActiveDurationMsSet = true;
   }
+
+  // preloaded TabChild should not be added to child map
+  if (mUniqueId) {
+    MOZ_ASSERT(NestedTabChildMap().find(mUniqueId) == NestedTabChildMap().end());
+    NestedTabChildMap()[mUniqueId] = this;
+  }
 }
 
 NS_IMETHODIMP
 TabChild::HandleEvent(nsIDOMEvent* aEvent)
 {
   nsAutoString eventType;
   aEvent->GetType(eventType);
   if (eventType.EqualsLiteral("DOMMetaAdded")) {
@@ -1428,36 +1438,46 @@ TabChild::BrowserFrameProvideWindow(nsID
                                     nsIURI* aURI,
                                     const nsAString& aName,
                                     const nsACString& aFeatures,
                                     bool* aWindowIsNew,
                                     nsIDOMWindow** aReturn)
 {
   *aReturn = nullptr;
 
-  nsRefPtr<TabChild> newChild =
-      new TabChild(ContentChild::GetSingleton(),
-                   /* TabContext */ *this, /* chromeFlags */ 0);
-  if (!NS_SUCCEEDED(newChild->Init())) {
-      return NS_ERROR_ABORT;
-  }
+  ContentChild* cc = ContentChild::GetSingleton();
+  const TabId openerTabId = GetTabId();
 
   // We must use PopupIPCTabContext here; ContentParent will not accept the
   // result of this->AsIPCTabContext() (which will be a
   // BrowserFrameIPCTabContext or an AppFrameIPCTabContext), for security
   // reasons.
   PopupIPCTabContext context;
-  context.openerChild() = this;
+  context.opener() = openerTabId;
   context.isBrowserElement() = IsBrowserElement();
 
-  ContentChild* cc = static_cast<ContentChild*>(Manager());
+  IPCTabContext ipcContext(context, mScrolling);
+
+  TabId tabId;
+  cc->SendAllocateTabId(openerTabId,
+                        ipcContext,
+                        cc->GetID(),
+                        &tabId);
+
+  nsRefPtr<TabChild> newChild = new TabChild(ContentChild::GetSingleton(), tabId,
+                                             /* TabContext */ *this, /* chromeFlags */ 0);
+  if (NS_FAILED(newChild->Init())) {
+    return NS_ERROR_ABORT;
+  }
+
+  context.opener() = this;
   unused << Manager()->SendPBrowserConstructor(
       // We release this ref in DeallocPBrowserChild
       nsRefPtr<TabChild>(newChild).forget().take(),
-      IPCTabContext(context, mScrolling), /* chromeFlags */ 0,
+      tabId, IPCTabContext(context, mScrolling), /* chromeFlags */ 0,
       cc->GetID(), cc->IsForApp(), cc->IsForBrowser());
 
   nsAutoCString spec;
   if (aURI) {
     aURI->GetSpec(spec);
   }
 
   NS_ConvertUTF8toUTF16 url(spec);
@@ -1557,18 +1577,18 @@ TabChild::ActorDestroy(ActorDestroyReaso
     static_cast<nsFrameMessageManager*>
       (mTabChildGlobal->mMessageManager.get())->Disconnect();
     mTabChildGlobal->mMessageManager = nullptr;
   }
 
   CompositorChild* compositorChild = static_cast<CompositorChild*>(CompositorChild::Get());
   compositorChild->CancelNotifyAfterRemotePaint(this);
 
-  if (Id() != 0) {
-    NestedTabChildMap().erase(Id());
+  if (GetTabId() != 0) {
+    NestedTabChildMap().erase(GetTabId());
   }
 }
 
 TabChild::~TabChild()
 {
     DestroyWindow();
 
     nsCOMPtr<nsIWebBrowser> webBrowser = do_QueryInterface(WebNavigation());
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -29,16 +29,17 @@
 #include "nsITooltipListener.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/TabContext.h"
 #include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/EventForwards.h"
 #include "mozilla/layers/CompositorTypes.h"
 #include "nsIWebBrowserChrome3.h"
+#include "mozilla/dom/ipc/IdType.h"
 
 class nsICachedFileDescriptorListener;
 class nsIDOMWindowUtils;
 
 namespace mozilla {
 namespace layout {
 class RenderFrameChild;
 }
@@ -249,48 +250,35 @@ class TabChild MOZ_FINAL : public TabChi
                            public nsITooltipListener
 {
     typedef mozilla::dom::ClonedMessageData ClonedMessageData;
     typedef mozilla::layout::RenderFrameChild RenderFrameChild;
     typedef mozilla::layout::ScrollingBehavior ScrollingBehavior;
     typedef mozilla::layers::ActiveElementManager ActiveElementManager;
 
 public:
-    static std::map<uint64_t, nsRefPtr<TabChild> >& NestedTabChildMap();
+    static std::map<TabId, nsRefPtr<TabChild>>& NestedTabChildMap();
 
 public:
     /** 
      * This is expected to be called off the critical path to content
      * startup.  This is an opportunity to load things that are slow
      * on the critical path.
      */
     static void PreloadSlowThings();
 
     /** Return a TabChild with the given attributes. */
     static already_AddRefed<TabChild>
-    Create(nsIContentChild* aManager, const TabContext& aContext, uint32_t aChromeFlags);
+    Create(nsIContentChild* aManager, const TabId& aTabId, const TabContext& aContext, uint32_t aChromeFlags);
 
     bool IsRootContentDocument();
 
-    const uint64_t Id() const {
-        return mUniqueId;
-    }
-
-    static uint64_t
-    GetTabChildId(TabChild* aTabChild)
-    {
-        MOZ_ASSERT(NS_IsMainThread());
-        if (aTabChild->Id() != 0) {
-            return aTabChild->Id();
-        }
-        static uint64_t sId = 0;
-        sId++;
-        aTabChild->mUniqueId = sId;
-        NestedTabChildMap()[sId] = aTabChild;
-        return sId;
+    const TabId GetTabId() const {
+      MOZ_ASSERT(mUniqueId != 0);
+      return mUniqueId;
     }
 
     NS_DECL_ISUPPORTS_INHERITED
     NS_DECL_NSIWEBBROWSERCHROME
     NS_DECL_NSIWEBBROWSERCHROME2
     NS_DECL_NSIEMBEDDINGSITEWINDOW
     NS_DECL_NSIWEBBROWSERCHROMEFOCUS
     NS_DECL_NSIINTERFACEREQUESTOR
@@ -511,17 +499,20 @@ private:
     /**
      * Create a new TabChild object.
      *
      * |aOwnOrContainingAppId| is the app-id of our frame or of the closest app
      * frame in the hierarchy which contains us.
      *
      * |aIsBrowserElement| indicates whether we're a browser (but not an app).
      */
-    TabChild(nsIContentChild* aManager, const TabContext& aContext, uint32_t aChromeFlags);
+    TabChild(nsIContentChild* aManager,
+             const TabId& aTabId,
+             const TabContext& aContext,
+             uint32_t aChromeFlags);
 
     nsresult Init();
 
     class DelayedFireSingleTapEvent;
     class DelayedFireContextMenuEvent;
 
     // Notify others that our TabContext has been updated.  (At the moment, this
     // sets the appropriate app-id and is-browser flags on our docshell.)
@@ -559,16 +550,24 @@ private:
                               bool* aWindowIsNew,
                               nsIDOMWindow** aReturn);
 
     bool HasValidInnerSize();
 
     void SendPendingTouchPreventedResponse(bool aPreventDefault,
                                            const ScrollableLayerGuid& aGuid);
 
+    void SetTabId(const TabId& aTabId)
+    {
+      MOZ_ASSERT(mUniqueId == 0);
+
+      mUniqueId = aTabId;
+      NestedTabChildMap()[mUniqueId] = this;
+    }
+
     class CachedFileDescriptorInfo;
     class CachedFileDescriptorCallbackRunnable;
 
     TextureFactoryIdentifier mTextureFactoryIdentifier;
     nsCOMPtr<nsIWebNavigation> mWebNav;
     nsCOMPtr<nsIWidget> mWidget;
     nsCOMPtr<nsIURI> mLastURI;
     RenderFrameChild* mRemoteFrame;
@@ -601,18 +600,18 @@ private:
     void FireSingleTapEvent(LayoutDevicePoint aPoint);
 
     bool mTouchEndCancelled;
     bool mEndTouchIsClick;
 
     bool mIgnoreKeyPressEvent;
     nsRefPtr<ActiveElementManager> mActiveElementManager;
     bool mHasValidInnerSize;
-    uint64_t mUniqueId;
     bool mDestroyed;
+    TabId mUniqueId;
 
     DISALLOW_EVIL_CONSTRUCTORS(TabChild);
 };
 
 }
 }
 
 #endif // mozilla_dom_TabChild_h
--- a/dom/ipc/TabContext.cpp
+++ b/dom/ipc/TabContext.cpp
@@ -251,29 +251,34 @@ MaybeInvalidTabContext::MaybeInvalidTabC
   uint32_t containingAppId = NO_APP_ID;
 
   const IPCTabAppBrowserContext& appBrowser = aParams.appBrowserContext();
   switch(appBrowser.type()) {
     case IPCTabAppBrowserContext::TPopupIPCTabContext: {
       const PopupIPCTabContext &ipcContext = appBrowser.get_PopupIPCTabContext();
 
       TabContext *context;
-      if (ipcContext.openerParent()) {
-        context = static_cast<TabParent*>(ipcContext.openerParent());
+      if (ipcContext.opener().type() == PBrowserOrId::TPBrowserParent) {
+        context = static_cast<TabParent*>(ipcContext.opener().get_PBrowserParent());
         if (context->IsBrowserElement() && !ipcContext.isBrowserElement()) {
           // If the TabParent corresponds to a browser element, then it can only
           // open other browser elements, for security reasons.  We should have
           // checked this before calling the TabContext constructor, so this is
           // a fatal error.
           mInvalidReason = "Child is-browser process tried to "
                            "open a non-browser tab.";
           return;
         }
-      } else if (ipcContext.openerChild()) {
-        context = static_cast<TabChild*>(ipcContext.openerChild());
+      } else if (ipcContext.opener().type() == PBrowserOrId::TPBrowserChild) {
+        context = static_cast<TabChild*>(ipcContext.opener().get_PBrowserChild());
+      } else if (ipcContext.opener().type() == PBrowserOrId::TTabId) {
+        // We should never get here because this PopupIPCTabContext is only
+        // used for allocating a new tab id, not for allocating a PBrowser.
+        mInvalidReason = "Child process tried to open an tab without the opener information.";
+        return;
       } else {
         // This should be unreachable because PopupIPCTabContext::opener is not a
         // nullable field.
         mInvalidReason = "PopupIPCTabContext::opener was null (?!).";
         return;
       }
 
       // Browser elements can't nest other browser elements.  So if
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -213,17 +213,20 @@ TabParent* sEventCapturer;
 TabParent *TabParent::mIMETabParent = nullptr;
 
 NS_IMPL_ISUPPORTS(TabParent,
                   nsITabParent,
                   nsIAuthPromptProvider,
                   nsISecureBrowserUI,
                   nsISupportsWeakReference)
 
-TabParent::TabParent(nsIContentParent* aManager, const TabContext& aContext, uint32_t aChromeFlags)
+TabParent::TabParent(nsIContentParent* aManager,
+                     const TabId& aTabId,
+                     const TabContext& aContext,
+                     uint32_t aChromeFlags)
   : TabContext(aContext)
   , mFrameElement(nullptr)
   , mIMESelectionAnchor(0)
   , mIMESelectionFocus(0)
   , mIMEComposing(false)
   , mIMECompositionEnding(false)
   , mIMECompositionStart(0)
   , mIMESeqno(0)
@@ -237,16 +240,17 @@ TabParent::TabParent(nsIContentParent* a
   , mShown(false)
   , mUpdatedDimensions(false)
   , mManager(aManager)
   , mMarkedDestroying(false)
   , mIsDestroyed(false)
   , mAppPackageFileDescriptorSent(false)
   , mSendOfflineStatus(true)
   , mChromeFlags(aChromeFlags)
+  , mTabId(aTabId)
 {
   MOZ_ASSERT(aManager);
 }
 
 TabParent::~TabParent()
 {
 }
 
@@ -313,17 +317,23 @@ TabParent::Destroy()
   mMarkedDestroying = true;
 }
 
 bool
 TabParent::Recv__delete__()
 {
   if (XRE_GetProcessType() == GeckoProcessType_Default) {
     Manager()->AsContentParent()->NotifyTabDestroyed(this, mMarkedDestroying);
+    ContentParent::DeallocateTabId(mTabId,
+                                   Manager()->AsContentParent()->ChildID());
   }
+  else {
+    ContentParent::DeallocateTabId(mTabId, ContentParentId(0));
+  }
+
   return true;
 }
 
 void
 TabParent::ActorDestroy(ActorDestroyReason why)
 {
   if (sEventCapturer == this) {
     sEventCapturer = nullptr;
@@ -1643,16 +1653,26 @@ TabParent::GetFrom(nsIContent* aContent)
   nsCOMPtr<nsIFrameLoaderOwner> loaderOwner = do_QueryInterface(aContent);
   if (!loaderOwner) {
     return nullptr;
   }
   nsRefPtr<nsFrameLoader> frameLoader = loaderOwner->GetFrameLoader();
   return GetFrom(frameLoader);
 }
 
+/*static*/ TabId
+TabParent::GetTabIdFrom(nsIDocShell *docShell)
+{
+  nsCOMPtr<nsITabChild> tabChild(TabChild::GetFrom(docShell));
+  if (tabChild) {
+    return static_cast<TabChild*>(tabChild.get())->GetTabId();
+  }
+  return TabId(0);
+}
+
 RenderFrameParent*
 TabParent::GetRenderFrame()
 {
   if (ManagedPRenderFrameParent().IsEmpty()) {
     return nullptr;
   }
   return static_cast<RenderFrameParent*>(ManagedPRenderFrameParent()[0]);
 }
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -6,16 +6,17 @@
 
 #ifndef mozilla_tabs_TabParent_h
 #define mozilla_tabs_TabParent_h
 
 #include "mozilla/EventForwards.h"
 #include "mozilla/dom/PBrowserParent.h"
 #include "mozilla/dom/PFilePickerParent.h"
 #include "mozilla/dom/TabContext.h"
+#include "mozilla/dom/ipc/IdType.h"
 #include "nsCOMPtr.h"
 #include "nsIAuthPromptProvider.h"
 #include "nsIBrowserDOMWindow.h"
 #include "nsISecureBrowserUI.h"
 #include "nsITabParent.h"
 #include "nsIXULBrowserWindow.h"
 #include "nsWeakReference.h"
 #include "Units.h"
@@ -23,16 +24,17 @@
 
 class nsFrameLoader;
 class nsIContent;
 class nsIPrincipal;
 class nsIURI;
 class nsIWidget;
 class nsILoadContext;
 class CpowHolder;
+class nsIDocShell;
 
 namespace mozilla {
 
 namespace layers {
 struct FrameMetrics;
 struct TextureFactoryIdentifier;
 }
 
@@ -62,17 +64,20 @@ class TabParent : public PBrowserParent
     typedef mozilla::layout::ScrollingBehavior ScrollingBehavior;
 
     virtual ~TabParent();
 
 public:
     // nsITabParent
     NS_DECL_NSITABPARENT
 
-    TabParent(nsIContentParent* aManager, const TabContext& aContext, uint32_t aChromeFlags);
+    TabParent(nsIContentParent* aManager,
+              const TabId& aTabId,
+              const TabContext& aContext,
+              uint32_t aChromeFlags);
     Element* GetOwnerElement() const { return mFrameElement; }
     void SetOwnerElement(Element* aElement);
 
     /**
      * Get the mozapptype attribute from this TabParent's owner DOM element.
      */
     void GetAppType(nsAString& aOut);
 
@@ -317,27 +322,33 @@ public:
 
     static TabParent *GetIMETabParent() { return mIMETabParent; }
     bool HandleQueryContentEvent(mozilla::WidgetQueryContentEvent& aEvent);
     bool SendCompositionEvent(mozilla::WidgetCompositionEvent& event);
     bool SendSelectionEvent(mozilla::WidgetSelectionEvent& event);
 
     static TabParent* GetFrom(nsFrameLoader* aFrameLoader);
     static TabParent* GetFrom(nsIContent* aContent);
+    static TabId GetTabIdFrom(nsIDocShell* docshell);
 
     nsIContentParent* Manager() { return mManager; }
 
     /**
      * Let managees query if Destroy() is already called so they don't send out
      * messages when the PBrowser actor is being destroyed.
      */
     bool IsDestroyed() const { return mIsDestroyed; }
 
     already_AddRefed<nsIWidget> GetWidget() const;
 
+    const TabId GetTabId() const
+    {
+      return mTabId;
+    }
+
 protected:
     bool ReceiveMessage(const nsString& aMessage,
                         bool aSync,
                         const StructuredCloneData* aCloneData,
                         CpowHolder* aCpows,
                         nsIPrincipal* aPrincipal,
                         InfallibleTArray<nsString>* aJSONRetVal = nullptr);
 
@@ -430,14 +441,16 @@ private:
 
     // Whether we need to send the offline status to the TabChild
     // This is true, until the first call of LoadURL
     bool mSendOfflineStatus;
 
     uint32_t mChromeFlags;
 
     nsCOMPtr<nsILoadContext> mLoadContext;
+
+    TabId mTabId;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif
--- a/dom/ipc/moz.build
+++ b/dom/ipc/moz.build
@@ -6,25 +6,27 @@
 
 EXPORTS += [
     'nsICachedFileDescriptorListener.h',
 ]
 
 EXPORTS.mozilla.dom.ipc += [
     'BlobChild.h',
     'BlobParent.h',
+    'IdType.h',
     'nsIRemoteBlob.h',
 ]
 
 EXPORTS.mozilla.dom += [
     'ContentBridgeChild.h',
     'ContentBridgeParent.h',
     'ContentChild.h',
     'ContentParent.h',
     'ContentProcess.h',
+    'ContentProcessManager.h',
     'CPOWManagerGetter.h',
     'CrashReporterChild.h',
     'CrashReporterParent.h',
     'FilePickerParent.h',
     'nsIContentChild.h',
     'nsIContentParent.h',
     'PermissionMessageUtils.h',
     'StructuredCloneUtils.h',
@@ -42,16 +44,17 @@ EXPORTS.mozilla += [
 
 UNIFIED_SOURCES += [
     'AppProcessChecker.cpp',
     'ColorPickerParent.cpp',
     'ContentBridgeChild.cpp',
     'ContentBridgeParent.cpp',
     'ContentParent.cpp',
     'ContentProcess.cpp',
+    'ContentProcessManager.cpp',
     'CrashReporterParent.cpp',
     'FilePickerParent.cpp',
     'nsIContentChild.cpp',
     'nsIContentParent.cpp',
     'PermissionMessageUtils.cpp',
     'PreallocatedProcessManager.cpp',
     'ProcessPriorityManager.cpp',
     'ScreenManagerParent.cpp',
@@ -72,16 +75,17 @@ SOURCES += [
     'CrashReporterChild.cpp',
 ]
 
 IPDL_SOURCES += [
     'DOMTypes.ipdlh',
     'PBlob.ipdl',
     'PBlobStream.ipdl',
     'PBrowser.ipdl',
+    'PBrowserOrId.ipdlh',
     'PColorPicker.ipdl',
     'PContent.ipdl',
     'PContentBridge.ipdl',
     'PContentPermission.ipdlh',
     'PContentPermissionRequest.ipdl',
     'PCrashReporter.ipdl',
     'PCycleCollectWithLogs.ipdl',
     'PDocumentRenderer.ipdl',
--- a/dom/ipc/nsIContentChild.cpp
+++ b/dom/ipc/nsIContentChild.cpp
@@ -45,36 +45,37 @@ nsIContentChild::AllocPJavaScriptChild()
 bool
 nsIContentChild::DeallocPJavaScriptChild(PJavaScriptChild* aChild)
 {
   static_cast<JavaScriptChild*>(aChild)->decref();
   return true;
 }
 
 PBrowserChild*
-nsIContentChild::AllocPBrowserChild(const IPCTabContext& aContext,
+nsIContentChild::AllocPBrowserChild(const TabId& aTabId,
+                                    const IPCTabContext& aContext,
                                     const uint32_t& aChromeFlags,
-                                    const uint64_t& aID,
+                                    const ContentParentId& aCpID,
                                     const bool& aIsForApp,
                                     const bool& aIsForBrowser)
 {
   // We'll happily accept any kind of IPCTabContext here; we don't need to
   // check that it's of a certain type for security purposes, because we
   // believe whatever the parent process tells us.
 
   MaybeInvalidTabContext tc(aContext);
   if (!tc.IsValid()) {
     NS_ERROR(nsPrintfCString("Received an invalid TabContext from "
                              "the parent process. (%s)  Crashing...",
                              tc.GetInvalidReason()).get());
     MOZ_CRASH("Invalid TabContext received from the parent process.");
   }
 
   nsRefPtr<TabChild> child =
-    TabChild::Create(this, tc.GetTabContext(), aChromeFlags);
+    TabChild::Create(this, aTabId, tc.GetTabContext(), aChromeFlags);
 
   // The ref here is released in DeallocPBrowserChild.
   return child.forget().take();
 }
 
 bool
 nsIContentChild::DeallocPBrowserChild(PBrowserChild* aIframe)
 {
--- a/dom/ipc/nsIContentChild.h
+++ b/dom/ipc/nsIContentChild.h
@@ -2,16 +2,18 @@
 /* vim: set ts=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 mozilla_dom_nsIContentChild_h
 #define mozilla_dom_nsIContentChild_h
 
+#include "mozilla/dom/ipc/IdType.h"
+
 #include "nsISupports.h"
 #include "nsTArrayForwardDeclare.h"
 #include "mozilla/dom/CPOWManagerGetter.h"
 
 #define NS_ICONTENTCHILD_IID                                    \
   { 0x4eed2e73, 0x94ba, 0x48a8,                                 \
     { 0xa2, 0xd1, 0xa5, 0xed, 0x86, 0xd7, 0xbb, 0xe4 } }
 
@@ -47,28 +49,30 @@ public:
   BlobChild* GetOrCreateActorForBlob(File* aBlob);
 
   virtual PBlobChild* SendPBlobConstructor(
     PBlobChild* aActor,
     const BlobConstructorParams& aParams) = 0;
 
   virtual bool
   SendPBrowserConstructor(PBrowserChild* aActor,
+                          const TabId& aTabId,
                           const IPCTabContext& aContext,
                           const uint32_t& aChromeFlags,
-                          const uint64_t& aID,
+                          const ContentParentId& aCpID,
                           const bool& aIsForApp,
                           const bool& aIsForBrowser) = 0;
 protected:
   virtual jsipc::PJavaScriptChild* AllocPJavaScriptChild();
   virtual bool DeallocPJavaScriptChild(jsipc::PJavaScriptChild*);
 
-  virtual PBrowserChild* AllocPBrowserChild(const IPCTabContext& aContext,
+  virtual PBrowserChild* AllocPBrowserChild(const TabId& aTabId,
+                                            const IPCTabContext& aContext,
                                             const uint32_t& aChromeFlags,
-                                            const uint64_t& aID,
+                                            const ContentParentId& aCpId,
                                             const bool& aIsForApp,
                                             const bool& aIsForBrowser);
   virtual bool DeallocPBrowserChild(PBrowserChild*);
 
   virtual PBlobChild* AllocPBlobChild(const BlobConstructorParams& aParams);
 
   virtual bool DeallocPBlobChild(PBlobChild* aActor);
 
--- a/dom/ipc/nsIContentParent.cpp
+++ b/dom/ipc/nsIContentParent.cpp
@@ -19,16 +19,23 @@
 
 #include "JavaScriptParent.h"
 #include "nsFrameMessageManager.h"
 #include "nsIJSRuntimeService.h"
 #include "nsPrintfCString.h"
 
 using namespace mozilla::jsipc;
 
+// XXX need another bug to move this to a common header.
+#ifdef DISABLE_ASSERTS_FOR_FUZZING
+#define ASSERT_UNLESS_FUZZING(...) do { } while (0)
+#else
+#define ASSERT_UNLESS_FUZZING(...) MOZ_ASSERT(false, __VA_ARGS__)
+#endif
+
 namespace mozilla {
 namespace dom {
 
 nsIContentParent::nsIContentParent()
 {
   mMessageManager = nsFrameMessageManager::NewProcessMessageManager(this);
 }
 
@@ -69,65 +76,70 @@ nsIContentParent::CanOpenBrowser(const I
 {
   const IPCTabAppBrowserContext& appBrowser = aContext.appBrowserContext();
 
   // We don't trust the IPCTabContext we receive from the child, so we'll bail
   // if we receive an IPCTabContext that's not a PopupIPCTabContext.
   // (PopupIPCTabContext lets the child process prove that it has access to
   // the app it's trying to open.)
   if (appBrowser.type() != IPCTabAppBrowserContext::TPopupIPCTabContext) {
-    NS_ERROR("Unexpected IPCTabContext type.  Aborting AllocPBrowserParent.");
+    ASSERT_UNLESS_FUZZING("Unexpected IPCTabContext type.  Aborting AllocPBrowserParent.");
     return false;
   }
 
   const PopupIPCTabContext& popupContext = appBrowser.get_PopupIPCTabContext();
-  TabParent* opener = static_cast<TabParent*>(popupContext.openerParent());
+  if (popupContext.opener().type() != PBrowserOrId::TPBrowserParent) {
+    ASSERT_UNLESS_FUZZING("Unexpected PopupIPCTabContext type.  Aborting AllocPBrowserParent.");
+    return false;
+  }
+
+  auto opener = static_cast<TabParent*>(popupContext.opener().get_PBrowserParent());
   if (!opener) {
-    NS_ERROR("Got null opener from child; aborting AllocPBrowserParent.");
+    ASSERT_UNLESS_FUZZING("Got null opener from child; aborting AllocPBrowserParent.");
     return false;
   }
 
   // Popup windows of isBrowser frames must be isBrowser if the parent
   // isBrowser.  Allocating a !isBrowser frame with same app ID would allow
   // the content to access data it's not supposed to.
   if (!popupContext.isBrowserElement() && opener->IsBrowserElement()) {
-    NS_ERROR("Child trying to escalate privileges!  Aborting AllocPBrowserParent.");
+    ASSERT_UNLESS_FUZZING("Child trying to escalate privileges!  Aborting AllocPBrowserParent.");
     return false;
   }
 
   MaybeInvalidTabContext tc(aContext);
   if (!tc.IsValid()) {
     NS_ERROR(nsPrintfCString("Child passed us an invalid TabContext.  (%s)  "
                              "Aborting AllocPBrowserParent.",
                              tc.GetInvalidReason()).get());
     return false;
   }
 
   return true;
 }
 
 PBrowserParent*
-nsIContentParent::AllocPBrowserParent(const IPCTabContext& aContext,
+nsIContentParent::AllocPBrowserParent(const TabId& aTabId,
+                                      const IPCTabContext& aContext,
                                       const uint32_t& aChromeFlags,
-                                      const uint64_t& aId,
+                                      const ContentParentId& aCpId,
                                       const bool& aIsForApp,
                                       const bool& aIsForBrowser)
 {
-  unused << aChromeFlags;
-  unused << aId;
+  unused << aCpId;
   unused << aIsForApp;
   unused << aIsForBrowser;
 
   if (!CanOpenBrowser(aContext)) {
     return nullptr;
   }
 
   MaybeInvalidTabContext tc(aContext);
   MOZ_ASSERT(tc.IsValid());
-  TabParent* parent = new TabParent(this, tc.GetTabContext(), aChromeFlags);
+  TabParent* parent = new TabParent(this, aTabId, tc.GetTabContext(), aChromeFlags);
 
   // We release this ref in DeallocPBrowserParent()
   NS_ADDREF(parent);
   return parent;
 }
 
 bool
 nsIContentParent::DeallocPBrowserParent(PBrowserParent* aFrame)
--- a/dom/ipc/nsIContentParent.h
+++ b/dom/ipc/nsIContentParent.h
@@ -2,16 +2,18 @@
 /* vim: set ts=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 mozilla_dom_nsIContentParent_h
 #define mozilla_dom_nsIContentParent_h
 
+#include "mozilla/dom/ipc/IdType.h"
+
 #include "nsFrameMessageManager.h"
 #include "nsISupports.h"
 #include "mozilla/dom/CPOWManagerGetter.h"
 
 #define NS_ICONTENTPARENT_IID                                   \
   { 0xeeec9ebf, 0x8ecf, 0x4e38,                                 \
     { 0x81, 0xda, 0xb7, 0x34, 0x13, 0x7e, 0xac, 0xf3 } }
 
@@ -44,45 +46,47 @@ class nsIContentParent : public nsISuppo
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ICONTENTPARENT_IID)
 
   nsIContentParent();
 
   BlobParent* GetOrCreateActorForBlob(File* aBlob);
 
-  virtual uint64_t ChildID() = 0;
+  virtual ContentParentId ChildID() = 0;
   virtual bool IsForApp() = 0;
   virtual bool IsForBrowser() = 0;
 
   virtual PBlobParent* SendPBlobConstructor(
     PBlobParent* aActor,
     const BlobConstructorParams& aParams) NS_WARN_UNUSED_RESULT = 0;
 
   virtual PBrowserParent* SendPBrowserConstructor(
     PBrowserParent* actor,
+    const TabId& aTabId,
     const IPCTabContext& context,
     const uint32_t& chromeFlags,
-    const uint64_t& aId,
+    const ContentParentId& aCpId,
     const bool& aIsForApp,
     const bool& aIsForBrowser) NS_WARN_UNUSED_RESULT = 0;
 
   virtual bool IsContentParent() { return false; }
   ContentParent* AsContentParent();
 
 protected: // methods
   bool CanOpenBrowser(const IPCTabContext& aContext);
 
 protected: // IPDL methods
   virtual mozilla::jsipc::PJavaScriptParent* AllocPJavaScriptParent();
   virtual bool DeallocPJavaScriptParent(mozilla::jsipc::PJavaScriptParent*);
 
-  virtual PBrowserParent* AllocPBrowserParent(const IPCTabContext& aContext,
+  virtual PBrowserParent* AllocPBrowserParent(const TabId& aTabId,
+                                              const IPCTabContext& aContext,
                                               const uint32_t& aChromeFlags,
-                                              const uint64_t& aId,
+                                              const ContentParentId& aCpId,
                                               const bool& aIsForApp,
                                               const bool& aIsForBrowser);
   virtual bool DeallocPBrowserParent(PBrowserParent* frame);
 
   virtual PBlobParent* AllocPBlobParent(const BlobConstructorParams& aParams);
 
   virtual bool DeallocPBlobParent(PBlobParent* aActor);
 
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -282,17 +282,17 @@ private:
  */
 class DeviceSuccessCallbackRunnable: public nsRunnable
 {
 public:
   DeviceSuccessCallbackRunnable(
     uint64_t aWindowID,
     nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback>& aSuccess,
     nsCOMPtr<nsIDOMGetUserMediaErrorCallback>& aError,
-    nsTArray<nsCOMPtr<nsIMediaDevice> >* aDevices)
+    nsTArray<nsRefPtr<MediaDevice>>* aDevices)
     : mDevices(aDevices)
     , mWindowID(aWindowID)
     , mManager(MediaManager::GetInstance())
   {
     mSuccess.swap(aSuccess);
     mError.swap(aError);
   }
 
@@ -333,17 +333,17 @@ public:
 
     mSuccess->OnSuccess(devices);
     return NS_OK;
   }
 
 private:
   nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback> mSuccess;
   nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mError;
-  nsAutoPtr<nsTArray<nsCOMPtr<nsIMediaDevice> > > mDevices;
+  nsAutoPtr<nsTArray<nsRefPtr<MediaDevice>>> mDevices;
   uint64_t mWindowID;
   nsRefPtr<MediaManager> mManager;
 };
 
 // Handle removing GetUserMediaCallbackMediaStreamListener from main thread
 class GetUserMediaListenerRemove: public nsRunnable
 {
 public:
@@ -366,24 +366,16 @@ protected:
   nsRefPtr<GetUserMediaCallbackMediaStreamListener> mListener;
 };
 
 /**
  * nsIMediaDevice implementation.
  */
 NS_IMPL_ISUPPORTS(MediaDevice, nsIMediaDevice)
 
-MediaDevice* MediaDevice::Create(MediaEngineVideoSource* source) {
-  return new VideoDevice(source);
-}
-
-MediaDevice* MediaDevice::Create(MediaEngineAudioSource* source) {
-  return new AudioDevice(source);
-}
-
 MediaDevice::MediaDevice(MediaEngineSource* aSource)
   : mHasFacingMode(false)
   , mSource(aSource) {
   mSource->GetName(mName);
   mSource->GetUUID(mID);
 }
 
 VideoDevice::VideoDevice(MediaEngineVideoSource* aSource)
@@ -416,19 +408,60 @@ VideoDevice::VideoDevice(MediaEngineVide
   if (mName.Find(NS_LITERAL_STRING("Face")) != -1) {
     mHasFacingMode = true;
     mFacingMode = dom::VideoFacingModeEnum::User;
   }
 #endif
   mMediaSource = aSource->GetMediaSource();
 }
 
+/**
+ * Helper functions that implement the constraints algorithm from
+ * http://dev.w3.org/2011/webrtc/editor/getusermedia.html#methods-5
+ */
+
+// Reminder: add handling for new constraints both here and in GetSources below!
+
+bool
+VideoDevice::SatisfiesConstraintSets(
+    const nsTArray<const MediaTrackConstraintSet*>& aConstraintSets)
+{
+  // Interrogate device-inherent properties first.
+  for (size_t i = 0; i < aConstraintSets.Length(); i++) {
+    auto& c = *aConstraintSets[i];
+    if (c.mFacingMode.WasPassed()) {
+      nsString s;
+      GetFacingMode(s);
+      if (!s.EqualsASCII(dom::VideoFacingModeEnumValues::strings[
+          static_cast<uint32_t>(c.mFacingMode.Value())].value)) {
+        return false;
+      }
+    }
+    nsString s;
+    GetMediaSource(s);
+    if (!s.EqualsASCII(dom::MediaSourceEnumValues::strings[
+        static_cast<uint32_t>(c.mMediaSource)].value)) {
+      return false;
+    }
+  }
+  // Forward request to underlying object to interrogate per-mode capabilities.
+  return GetSource()->SatisfiesConstraintSets(aConstraintSets);
+}
+
 AudioDevice::AudioDevice(MediaEngineAudioSource* aSource)
   : MediaDevice(aSource) {}
 
+bool
+AudioDevice::SatisfiesConstraintSets(
+    const nsTArray<const MediaTrackConstraintSet*>& aConstraintSets)
+{
+  // TODO: Add audio-specific constraints
+  return true;
+}
+
 NS_IMETHODIMP
 MediaDevice::GetName(nsAString& aName)
 {
   aName.Assign(mName);
   return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -479,26 +512,26 @@ MediaDevice::GetMediaSource(nsAString& a
     aMediaSource.Assign(NS_LITERAL_STRING("window"));
   } else { // all the rest are shared
     aMediaSource.Assign(NS_ConvertUTF8toUTF16(
       dom::MediaSourceEnumValues::strings[uint32_t(mMediaSource)].value));
   }
   return NS_OK;
 }
 
-MediaEngineVideoSource*
+VideoDevice::Source*
 VideoDevice::GetSource()
 {
-  return static_cast<MediaEngineVideoSource*>(&*mSource);
+  return static_cast<Source*>(&*mSource);
 }
 
-MediaEngineAudioSource*
+AudioDevice::Source*
 AudioDevice::GetSource()
 {
-  return static_cast<MediaEngineAudioSource*>(&*mSource);
+  return static_cast<Source*>(&*mSource);
 }
 
 /**
  * A subclass that we only use to stash internal pointers to MediaStreamGraph objects
  * that need to be cleaned up.
  */
 class nsDOMUserMediaStream : public DOMLocalMediaStream
 {
@@ -881,110 +914,79 @@ IsOn(const OwningBooleanOrMediaTrackCons
 
 static const MediaTrackConstraints&
 GetInvariant(const OwningBooleanOrMediaTrackConstraints &aUnion) {
   static const MediaTrackConstraints empty;
   return aUnion.IsMediaTrackConstraints() ?
       aUnion.GetAsMediaTrackConstraints() : empty;
 }
 
-/**
- * Helper functions that implement the constraints algorithm from
- * http://dev.w3.org/2011/webrtc/editor/getusermedia.html#methods-5
- */
-
-// Reminder: add handling for new constraints both here and in GetSources below!
-
-static bool SatisfyConstraintSet(const MediaEngineVideoSource *,
-                                 const MediaTrackConstraintSet &aConstraints,
-                                 nsIMediaDevice &aCandidate)
-{
-  nsString s;
-  if (aConstraints.mFacingMode.WasPassed()) {
-    aCandidate.GetFacingMode(s);
-    if (!s.EqualsASCII(dom::VideoFacingModeEnumValues::strings[
-        uint32_t(aConstraints.mFacingMode.Value())].value)) {
-      return false;
-    }
-  }
-  aCandidate.GetMediaSource(s);
-  if (!s.EqualsASCII(dom::MediaSourceEnumValues::strings[
-      uint32_t(aConstraints.mMediaSource)].value)) {
-    return false;
-  }
-  // TODO: Add more video-specific constraints
-  return true;
-}
-
-static bool SatisfyConstraintSet(const MediaEngineAudioSource *,
-                                 const MediaTrackConstraintSet &aConstraints,
-                                 nsIMediaDevice &aCandidate)
-{
-  // TODO: Add audio-specific constraints
-  return true;
-}
-
-typedef nsTArray<nsCOMPtr<nsIMediaDevice> > SourceSet;
-
 // Source getter that constrains list returned
 
-template<class SourceType, class ConstraintsType>
-static SourceSet *
+template<class DeviceType, class ConstraintsType>
+static void
   GetSources(MediaEngine *engine,
              ConstraintsType &aConstraints,
-             void (MediaEngine::* aEnumerate)(MediaSourceType, nsTArray<nsRefPtr<SourceType> >*),
+             void (MediaEngine::* aEnumerate)(MediaSourceType,
+                 nsTArray<nsRefPtr<typename DeviceType::Source> >*),
+             nsTArray<nsRefPtr<DeviceType>>& aResult,
              const char* media_device_name = nullptr)
 {
-  ScopedDeletePtr<SourceSet> result(new SourceSet);
+  typedef nsTArray<nsRefPtr<DeviceType>> SourceSet;
 
-  const SourceType * const type = nullptr;
   nsString deviceName;
   // First collect sources
   SourceSet candidateSet;
   {
-    nsTArray<nsRefPtr<SourceType> > sources;
+    nsTArray<nsRefPtr<typename DeviceType::Source> > sources;
     // all MediaSourceEnums are contained in MediaSourceType
     (engine->*aEnumerate)((MediaSourceType)((int)aConstraints.mMediaSource), &sources);
     /**
       * We're allowing multiple tabs to access the same camera for parity
       * with Chrome.  See bug 811757 for some of the issues surrounding
       * this decision.  To disallow, we'd filter by IsAvailable() as we used
       * to.
       */
     for (uint32_t len = sources.Length(), i = 0; i < len; i++) {
       sources[i]->GetName(deviceName);
       if (media_device_name && strlen(media_device_name) > 0)  {
         if (deviceName.EqualsASCII(media_device_name)) {
-          candidateSet.AppendElement(MediaDevice::Create(sources[i]));
+          candidateSet.AppendElement(new DeviceType(sources[i]));
           break;
         }
       } else {
-        candidateSet.AppendElement(MediaDevice::Create(sources[i]));
+        candidateSet.AppendElement(new DeviceType(sources[i]));
       }
     }
   }
 
   // Apply constraints to the list of sources.
 
   auto& c = aConstraints;
   if (c.mUnsupportedRequirement) {
     // Check upfront the names of required constraints that are unsupported for
     // this media-type. The spec requires these to fail, so getting them out of
     // the way early provides a necessary invariant for the remaining algorithm
     // which maximizes code-reuse by ignoring constraints of the other type
-    // (specifically, SatisfyConstraintSet is reused for the advanced algorithm
+    // (specifically, SatisfiesConstraintSets is reused for the advanced algorithm
     // where the spec requires it to ignore constraints of the other type)
-    return result.forget();
+    return;
   }
 
   // Now on to the actual algorithm: First apply required constraints.
 
+  // Stack constraintSets that pass, starting with the required one, because the
+  // whole stack must be re-satisfied each time a capability-set is ruled out
+  // (this avoids storing state and pushing algorithm into the lower-level code).
+  nsTArray<const MediaTrackConstraintSet*> aggregateConstraints;
+  aggregateConstraints.AppendElement(&c.mRequired);
+
   for (uint32_t i = 0; i < candidateSet.Length();) {
     // Overloading instead of template specialization keeps things local
-    if (!SatisfyConstraintSet(type, c.mRequired, *candidateSet[i])) {
+    if (!candidateSet[i]->SatisfiesConstraintSets(aggregateConstraints)) {
       candidateSet.RemoveElementAt(i);
     } else {
       ++i;
     }
   }
 
   // TODO(jib): Proper non-ordered handling of nonrequired constraints (907352)
   //
@@ -1013,34 +1015,37 @@ static SourceSet *
   // the wrong one (UX-fail). Webpage-preferred devices will be listed first.
 
   SourceSet tailSet;
 
   if (c.mAdvanced.WasPassed()) {
     auto &array = c.mAdvanced.Value();
 
     for (int i = 0; i < int(array.Length()); i++) {
+      aggregateConstraints.AppendElement(&array[i]);
       SourceSet rejects;
       for (uint32_t j = 0; j < candidateSet.Length();) {
-        if (!SatisfyConstraintSet(type, array[i], *candidateSet[j])) {
+        if (!candidateSet[j]->SatisfiesConstraintSets(aggregateConstraints)) {
           rejects.AppendElement(candidateSet[j]);
           candidateSet.RemoveElementAt(j);
         } else {
           ++j;
         }
       }
       (candidateSet.Length()? tailSet : candidateSet).MoveElementsFrom(rejects);
+      if (!candidateSet.Length()) {
+        aggregateConstraints.RemoveElementAt(aggregateConstraints.Length() - 1);
+      }
     }
   }
 
   // TODO: Proper non-ordered handling of nonrequired constraints (Bug 907352)
 
-  result->MoveElementsFrom(candidateSet);
-  result->MoveElementsFrom(tailSet);
-  return result.forget();
+  aResult.MoveElementsFrom(candidateSet);
+  aResult.MoveElementsFrom(tailSet);
 }
 
 /**
  * Runs on a seperate thread and is responsible for enumerating devices.
  * Depending on whether a picture or stream was asked for, either
  * ProcessGetUserMedia is called, and the results are sent back to the DOM.
  *
  * Do not run this on the main thread. The success and error callbacks *MUST*
@@ -1188,39 +1193,38 @@ public:
 
   nsresult
   SelectDevice(MediaEngine* backend)
   {
     MOZ_ASSERT(mSuccess);
     MOZ_ASSERT(mError);
     if (IsOn(mConstraints.mVideo)) {
       VideoTrackConstraintsN constraints(GetInvariant(mConstraints.mVideo));
-      ScopedDeletePtr<SourceSet> sources(GetSources(backend, constraints,
-                               &MediaEngine::EnumerateVideoDevices));
+      nsTArray<nsRefPtr<VideoDevice>> sources;
+      GetSources(backend, constraints, &MediaEngine::EnumerateVideoDevices, sources);
 
-      if (!sources->Length()) {
+      if (!sources.Length()) {
         Fail(NS_LITERAL_STRING("NO_DEVICES_FOUND"));
         return NS_ERROR_FAILURE;
       }
       // Pick the first available device.
-      mVideoDevice = do_QueryObject((*sources)[0]);
+      mVideoDevice = sources[0];
       LOG(("Selected video device"));
     }
-
     if (IsOn(mConstraints.mAudio)) {
       AudioTrackConstraintsN constraints(GetInvariant(mConstraints.mAudio));
-      ScopedDeletePtr<SourceSet> sources (GetSources(backend, constraints,
-          &MediaEngine::EnumerateAudioDevices));
+      nsTArray<nsRefPtr<AudioDevice>> sources;
+      GetSources(backend, constraints, &MediaEngine::EnumerateAudioDevices, sources);
 
-      if (!sources->Length()) {
+      if (!sources.Length()) {
         Fail(NS_LITERAL_STRING("NO_DEVICES_FOUND"));
         return NS_ERROR_FAILURE;
       }
       // Pick the first available device.
-      mAudioDevice = do_QueryObject((*sources)[0]);
+      mAudioDevice = sources[0];
       LOG(("Selected audio device"));
     }
 
     return NS_OK;
   }
 
   /**
    * Allocates a video or audio device and returns a MediaStream via
@@ -1336,30 +1340,36 @@ public:
     NS_ASSERTION(!NS_IsMainThread(), "Don't call on main thread");
 
     nsRefPtr<MediaEngine> backend;
     if (mConstraints.mFake)
       backend = new MediaEngineDefault();
     else
       backend = mManager->GetBackend(mWindowId);
 
+    typedef nsTArray<nsRefPtr<MediaDevice>> SourceSet;
+
     ScopedDeletePtr<SourceSet> final(new SourceSet);
     if (IsOn(mConstraints.mVideo)) {
       VideoTrackConstraintsN constraints(GetInvariant(mConstraints.mVideo));
-      ScopedDeletePtr<SourceSet> s(GetSources(backend, constraints,
-              &MediaEngine::EnumerateVideoDevices,
-              mLoopbackVideoDevice.get()));
-      final->MoveElementsFrom(*s);
+      nsTArray<nsRefPtr<VideoDevice>> s;
+      GetSources(backend, constraints, &MediaEngine::EnumerateVideoDevices, s,
+                 mLoopbackVideoDevice.get());
+      for (uint32_t i = 0; i < s.Length(); i++) {
+        final->AppendElement(s[i]);
+      }
     }
     if (IsOn(mConstraints.mAudio)) {
       AudioTrackConstraintsN constraints(GetInvariant(mConstraints.mAudio));
-      ScopedDeletePtr<SourceSet> s (GetSources(backend, constraints,
-          &MediaEngine::EnumerateAudioDevices,
-          mLoopbackAudioDevice.get()));
-      final->MoveElementsFrom(*s);
+      nsTArray<nsRefPtr<AudioDevice>> s;
+      GetSources(backend, constraints, &MediaEngine::EnumerateAudioDevices, s,
+                 mLoopbackAudioDevice.get());
+      for (uint32_t i = 0; i < s.Length(); i++) {
+        final->AppendElement(s[i]);
+      }
     }
 
     NS_DispatchToMainThread(new DeviceSuccessCallbackRunnable(mWindowId,
                                                               mSuccess, mError,
                                                               final.forget()));
     // DeviceSuccessCallbackRunnable should have taken these.
     MOZ_ASSERT(!mSuccess && !mError);
   }
--- a/dom/media/MediaManager.h
+++ b/dom/media/MediaManager.h
@@ -41,16 +41,17 @@
 #include "DOMCameraManager.h"
 #endif
 
 namespace mozilla {
 namespace dom {
 struct MediaStreamConstraints;
 class NavigatorUserMediaSuccessCallback;
 class NavigatorUserMediaErrorCallback;
+struct MediaTrackConstraintSet;
 }
 
 #ifdef PR_LOGGING
 extern PRLogModuleInfo* GetMediaManagerLog();
 #define MM_LOG(msg) PR_LOG(GetMediaManagerLog(), PR_LOG_DEBUG, msg)
 #else
 #define MM_LOG(msg)
 #endif
@@ -496,44 +497,49 @@ typedef nsTArray<nsRefPtr<GetUserMediaCa
 typedef nsClassHashtable<nsUint64HashKey, StreamListeners> WindowTable;
 
 class MediaDevice : public nsIMediaDevice
 {
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIMEDIADEVICE
 
-  static MediaDevice* Create(MediaEngineVideoSource* source);
-  static MediaDevice* Create(MediaEngineAudioSource* source);
-
 protected:
   virtual ~MediaDevice() {}
   explicit MediaDevice(MediaEngineSource* aSource);
   nsString mName;
   nsString mID;
   bool mHasFacingMode;
   dom::VideoFacingModeEnum mFacingMode;
   MediaSourceType mMediaSource;
   nsRefPtr<MediaEngineSource> mSource;
 };
 
 class VideoDevice : public MediaDevice
 {
 public:
-  explicit VideoDevice(MediaEngineVideoSource* aSource);
+  typedef MediaEngineVideoSource Source;
+
+  explicit VideoDevice(Source* aSource);
   NS_IMETHOD GetType(nsAString& aType);
-  MediaEngineVideoSource* GetSource();
+  Source* GetSource();
+  bool SatisfiesConstraintSets(
+    const nsTArray<const dom::MediaTrackConstraintSet*>& aConstraintSets);
 };
 
 class AudioDevice : public MediaDevice
 {
 public:
-  explicit AudioDevice(MediaEngineAudioSource* aSource);
+  typedef MediaEngineAudioSource Source;
+
+  explicit AudioDevice(Source* aSource);
   NS_IMETHOD GetType(nsAString& aType);
-  MediaEngineAudioSource* GetSource();
+  Source* GetSource();
+  bool SatisfiesConstraintSets(
+    const nsTArray<const dom::MediaTrackConstraintSet*>& aConstraintSets);
 };
 
 // we could add MediaManager if needed
 typedef void (*WindowListenerCallback)(MediaManager *aThis,
                                        uint64_t aWindowID,
                                        StreamListeners *aListeners,
                                        void *aData);
 
--- a/gfx/src/nsRenderingContext.cpp
+++ b/gfx/src/nsRenderingContext.cpp
@@ -1,139 +1,19 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsRenderingContext.h"
-#include <string.h>                     // for strlen
-#include <algorithm>                    // for min
-#include "gfxColor.h"                   // for gfxRGBA
-#include "gfxMatrix.h"                  // for gfxMatrix
-#include "gfxPoint.h"                   // for gfxPoint, gfxSize
-#include "gfxRect.h"                    // for gfxRect
-#include "gfxTypes.h"                   // for gfxFloat
-#include "mozilla/gfx/BasePoint.h"      // for BasePoint
-#include "mozilla/mozalloc.h"           // for operator delete[], etc
-#include "nsBoundingMetrics.h"          // for nsBoundingMetrics
-#include "nsCharTraits.h"               // for NS_IS_LOW_SURROGATE
-#include "nsDebug.h"                    // for NS_ERROR
-#include "nsPoint.h"                    // for nsPoint
-#include "nsRect.h"                     // for nsRect, nsIntRect
-#include "nsRegion.h"                   // for nsIntRegionRectIterator, etc
-
-// Hard limit substring lengths to 8000 characters ... this lets us statically
-// size the cluster buffer array in FindSafeLength
-#define MAX_GFX_TEXT_BUF_SIZE 8000
-
-/*static*/ int32_t
-nsRenderingContext::FindSafeLength(const char16_t *aString, uint32_t aLength,
-                              uint32_t aMaxChunkLength)
-{
-    if (aLength <= aMaxChunkLength)
-        return aLength;
-
-    int32_t len = aMaxChunkLength;
-
-    // Ensure that we don't break inside a surrogate pair
-    while (len > 0 && NS_IS_LOW_SURROGATE(aString[len])) {
-        len--;
-    }
-    if (len == 0) {
-        // We don't want our caller to go into an infinite loop, so don't
-        // return zero. It's hard to imagine how we could actually get here
-        // unless there are languages that allow clusters of arbitrary size.
-        // If there are and someone feeds us a 500+ character cluster, too
-        // bad.
-        return aMaxChunkLength;
-    }
-    return len;
-}
-
-//////////////////////////////////////////////////////////////////////
-//// nsRenderingContext
 
 void
 nsRenderingContext::Init(gfxContext *aThebesContext)
 {
     mThebes = aThebesContext;
     mThebes->SetLineWidth(1.0);
 }
 
 void
 nsRenderingContext::Init(DrawTarget *aDrawTarget)
 {
     Init(new gfxContext(aDrawTarget));
 }
-
-
-//
-// text
-//
-
-void
-nsRenderingContext::SetTextRunRTL(bool aIsRTL)
-{
-    mFontMetrics->SetTextRunRTL(aIsRTL);
-}
-
-void
-nsRenderingContext::SetFont(nsFontMetrics *aFontMetrics)
-{
-    mFontMetrics = aFontMetrics;
-}
-
-int32_t
-nsRenderingContext::GetMaxChunkLength()
-{
-    return std::min(mFontMetrics->GetMaxStringLength(), MAX_GFX_TEXT_BUF_SIZE);
-}
-
-nscoord
-nsRenderingContext::GetWidth(char16_t aC)
-{
-    return GetWidth(&aC, 1);
-}
-
-nscoord
-nsRenderingContext::GetWidth(const nsString& aString)
-{
-    return GetWidth(aString.get(), aString.Length());
-}
-
-nscoord
-nsRenderingContext::GetWidth(const char16_t *aString, uint32_t aLength)
-{
-    uint32_t maxChunkLength = GetMaxChunkLength();
-    nscoord width = 0;
-    while (aLength > 0) {
-        int32_t len = FindSafeLength(aString, aLength, maxChunkLength);
-        width += mFontMetrics->GetWidth(aString, len, this);
-        aLength -= len;
-        aString += len;
-    }
-    return width;
-}
-
-nsBoundingMetrics
-nsRenderingContext::GetBoundingMetrics(const char16_t* aString,
-                                       uint32_t aLength)
-{
-    uint32_t maxChunkLength = GetMaxChunkLength();
-    int32_t len = FindSafeLength(aString, aLength, maxChunkLength);
-    // Assign directly in the first iteration. This ensures that
-    // negative ascent/descent can be returned and the left bearing
-    // is properly initialized.
-    nsBoundingMetrics totalMetrics
-        = mFontMetrics->GetBoundingMetrics(aString, len, this);
-    aLength -= len;
-    aString += len;
-
-    while (aLength > 0) {
-        len = FindSafeLength(aString, aLength, maxChunkLength);
-        nsBoundingMetrics metrics
-            = mFontMetrics->GetBoundingMetrics(aString, len, this);
-        totalMetrics += metrics;
-        aLength -= len;
-        aString += len;
-    }
-    return totalMetrics;
-}
--- a/gfx/src/nsRenderingContext.h
+++ b/gfx/src/nsRenderingContext.h
@@ -1,70 +1,41 @@
 /* -*- Mode: C++; tab-width: 20; 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 NSRENDERINGCONTEXT__H__
 #define NSRENDERINGCONTEXT__H__
 
-#include <stdint.h>                     // for uint32_t
-#include <sys/types.h>                  // for int32_t
-#include "gfxContext.h"                 // for gfxContext
-#include "mozilla/Assertions.h"         // for MOZ_ASSERT_HELPER2
-#include "mozilla/gfx/2D.h"
-#include "nsAutoPtr.h"                  // for nsRefPtr
-#include "nsBoundingMetrics.h"          // for nsBoundingMetrics
-#include "nsColor.h"                    // for nscolor
-#include "nsCoord.h"                    // for nscoord, NSToIntRound
-#include "nsFontMetrics.h"              // for nsFontMetrics
-#include "nsISupports.h"                // for NS_INLINE_DECL_REFCOUNTING, etc
-#include "nsString.h"               // for nsString
-#include "nscore.h"                     // for char16_t
+#include "gfxContext.h"
+#include "mozilla/Attributes.h"
+#include "nsISupportsImpl.h"
+#include "nsRefPtr.h"
 
-class nsIntRegion;
-struct nsPoint;
-struct nsRect;
+namespace mozilla {
+namespace gfx {
+class DrawTarget;
+}
+}
 
 class nsRenderingContext MOZ_FINAL
 {
     typedef mozilla::gfx::DrawTarget DrawTarget;
 
 public:
-    nsRenderingContext() {}
-
     NS_INLINE_DECL_REFCOUNTING(nsRenderingContext)
 
     void Init(gfxContext* aThebesContext);
     void Init(DrawTarget* aDrawTarget);
 
     // These accessors will never return null.
     gfxContext *ThebesContext() { return mThebes; }
     DrawTarget *GetDrawTarget() { return mThebes->GetDrawTarget(); }
 
-    // Text
-
-    void SetFont(nsFontMetrics *aFontMetrics);
-    nsFontMetrics *FontMetrics() { return mFontMetrics; } // may be null
-
-    void SetTextRunRTL(bool aIsRTL);
-
-    nscoord GetWidth(char16_t aC);
-    nscoord GetWidth(const nsString& aString);
-    nscoord GetWidth(const char16_t *aString, uint32_t aLength);
-
-    nsBoundingMetrics GetBoundingMetrics(const char16_t *aString,
-                                         uint32_t aLength);
-
-    int32_t GetMaxChunkLength();
-    static int32_t FindSafeLength(const char16_t *aString, uint32_t aLength,
-                                  uint32_t aMaxChunkLength);
 private:
     // Private destructor, to discourage deletion outside of Release():
-    ~nsRenderingContext()
-    {
-    }
+    ~nsRenderingContext() {}
 
     nsRefPtr<gfxContext> mThebes;
-    nsRefPtr<nsFontMetrics> mFontMetrics;
 };
 
 #endif  // NSRENDERINGCONTEXT__H__
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug1066659.js
@@ -0,0 +1,13 @@
+
+function reportCompare (expected, actual) {
+        var actual_t = typeof actual;
+            var output = "";
+                output += "x" + actual_t + " ";
+                    expected != actual;
+                        output += undefined;
+}
+gczeal(7,1);
+for (var i=0; i<900; i++) {
+        reportCompare("abc", function() {});
+        reportCompare(null, 10);
+}
--- a/js/src/jit/CompactBuffer.h
+++ b/js/src/jit/CompactBuffer.h
@@ -114,23 +114,36 @@ class CompactBufferWriter
     { }
 
     // Note: writeByte() takes uint32 to catch implicit casts with a runtime
     // assert.
     void writeByte(uint32_t byte) {
         MOZ_ASSERT(byte <= 0xFF);
         enoughMemory_ &= buffer_.append(byte);
     }
+    void writeByteAt(uint32_t pos, uint32_t byte) {
+        MOZ_ASSERT(byte <= 0xFF);
+        buffer_[pos] = byte;
+    }
     void writeUnsigned(uint32_t value) {
         do {
             uint8_t byte = ((value & 0x7F) << 1) | (value > 0x7F);
             writeByte(byte);
             value >>= 7;
         } while (value);
     }
+    void writeUnsignedAt(uint32_t pos, uint32_t value, uint32_t original) {
+        MOZ_ASSERT(value <= original);
+        do {
+            uint8_t byte = ((value & 0x7F) << 1) | (original > 0x7F);
+            writeByteAt(pos++, byte);
+            value >>= 7;
+            original >>= 7;
+        } while (original);
+    }
     void writeSigned(int32_t v) {
         bool isNegative = v < 0;
         uint32_t value = isNegative ? -v : v;
         uint8_t byte = ((value & 0x3F) << 2) | ((value > 0x3F) << 1) | uint32_t(isNegative);
         writeByte(byte);
 
         // Write out the rest of the bytes, if needed.
         value >>= 6;
--- a/js/src/jit/JitFrameIterator.h
+++ b/js/src/jit/JitFrameIterator.h
@@ -270,17 +270,17 @@ class RInstructionResults
     IonJSFrameLayout *fp_;
 
     // Record if we tried and succeed at allocating and filling the vector of
     // recover instruction results, if needed.  This flag is needed in order to
     // avoid evaluating the recover instruction twice.
     bool initialized_;
 
   public:
-    RInstructionResults(IonJSFrameLayout *fp);
+    explicit RInstructionResults(IonJSFrameLayout *fp);
     RInstructionResults(RInstructionResults&& src);
 
     RInstructionResults& operator=(RInstructionResults&& rhs);
 
     ~RInstructionResults();
 
     bool init(JSContext *cx, uint32_t numResults);
     bool isInitialized() const;
@@ -305,17 +305,17 @@ struct MaybeReadFallback
     };
 
     JSContext *maybeCx;
     JitActivation *activation;
     JitFrameIterator *frame;
     const NoGCValue unreadablePlaceholder_;
     const FallbackConsequence consequence;
 
-    MaybeReadFallback(const Value &placeholder = UndefinedValue())
+    explicit MaybeReadFallback(const Value &placeholder = UndefinedValue())
       : maybeCx(nullptr),
         activation(nullptr),
         frame(nullptr),
         unreadablePlaceholder_(noGCPlaceholder(placeholder)),
         consequence(Fallback_Invalidate)
     {
     }
 
--- a/js/src/jit/LIR-Common.h
+++ b/js/src/jit/LIR-Common.h
@@ -228,17 +228,17 @@ class LSimdSignMaskX4 : public LInstruct
         setOperand(0, input);
     }
 };
 
 // Base class for both int32x4 and float32x4 shuffle instructions.
 class LSimdSwizzleBase : public LInstructionHelper<1, 1, 0>
 {
   public:
-    LSimdSwizzleBase(const LAllocation &base)
+    explicit LSimdSwizzleBase(const LAllocation &base)
     {
         setOperand(0, base);
     }
 
     const LAllocation *getBase() {
         return getOperand(0);
     }
 
@@ -252,25 +252,25 @@ class LSimdSwizzleBase : public LInstruc
     }
 };
 
 // Shuffles a int32x4 into another int32x4 vector.
 class LSimdSwizzleI : public LSimdSwizzleBase
 {
   public:
     LIR_HEADER(SimdSwizzleI);
-    LSimdSwizzleI(const LAllocation &base) : LSimdSwizzleBase(base)
+    explicit LSimdSwizzleI(const LAllocation &base) : LSimdSwizzleBase(base)
     {}
 };
 // Shuffles a float32x4 into another float32x4 vector.
 class LSimdSwizzleF : public LSimdSwizzleBase
 {
   public:
     LIR_HEADER(SimdSwizzleF);
-    LSimdSwizzleF(const LAllocation &base) : LSimdSwizzleBase(base)
+    explicit LSimdSwizzleF(const LAllocation &base) : LSimdSwizzleBase(base)
     {}
 };
 
 // Base class for both int32x4 and float32x4 shuffle instructions.
 class LSimdShuffle : public LInstructionHelper<1, 2, 1>
 {
   public:
     LIR_HEADER(SimdShuffle);
@@ -4198,17 +4198,17 @@ class LTypedObjectProto : public LCallIn
 };
 
 // Load an unsized typed object's length.
 class LTypedObjectUnsizedLength : public LInstructionHelper<1, 1, 0>
 {
   public:
     LIR_HEADER(TypedObjectUnsizedLength)
 
-    LTypedObjectUnsizedLength(const LAllocation &object) {
+    explicit LTypedObjectUnsizedLength(const LAllocation &object) {
         setOperand(0, object);
     }
     const LAllocation *object() {
         return getOperand(0);
     }
 };
 
 // Load a typed object's elements vector.
--- a/js/src/jit/LIR.h
+++ b/js/src/jit/LIR.h
@@ -1229,22 +1229,23 @@ class LSnapshot : public TempObject
     }
     void setBailoutKind(BailoutKind kind) {
         bailoutKind_ = kind;
     }
     void rewriteRecoveredInput(LUse input);
 };
 
 struct SafepointNunboxEntry {
+    uint32_t typeVreg;
     LAllocation type;
     LAllocation payload;
 
     SafepointNunboxEntry() { }
-    SafepointNunboxEntry(LAllocation type, LAllocation payload)
-      : type(type), payload(payload)
+    SafepointNunboxEntry(uint32_t typeVreg, LAllocation type, LAllocation payload)
+      : typeVreg(typeVreg), type(type), payload(payload)
     { }
 };
 
 class LSafepoint : public TempObject
 {
     typedef SafepointNunboxEntry NunboxEntry;
 
   public:
@@ -1317,17 +1318,16 @@ class LSafepoint : public TempObject
 
     explicit LSafepoint(TempAllocator &alloc)
       : safepointOffset_(INVALID_SAFEPOINT_OFFSET)
       , osiCallPointOffset_(0)
       , gcSlots_(alloc)
       , valueSlots_(alloc)
 #ifdef JS_NUNBOX32
       , nunboxParts_(alloc)
-      , partialNunboxes_(0)
 #endif
       , slotsOrElementsSlots_(alloc)
     {
       assertInvariants();
     }
     void addLiveRegister(AnyRegister reg) {
         liveRegs_.addUnchecked(reg);
         assertInvariants();
@@ -1436,95 +1436,89 @@ class LSafepoint : public TempObject
             if (valueSlots_[i] == slot)
                 return true;
         }
         return false;
     }
 
 #ifdef JS_NUNBOX32
 
-    bool addNunboxParts(LAllocation type, LAllocation payload) {
-        bool result = nunboxParts_.append(NunboxEntry(type, payload));
+    bool addNunboxParts(uint32_t typeVreg, LAllocation type, LAllocation payload) {
+        bool result = nunboxParts_.append(NunboxEntry(typeVreg, type, payload));
         if (result)
             assertInvariants();
         return result;
     }
 
     bool addNunboxType(uint32_t typeVreg, LAllocation type) {
         for (size_t i = 0; i < nunboxParts_.length(); i++) {
             if (nunboxParts_[i].type == type)
                 return true;
             if (nunboxParts_[i].type == LUse(typeVreg, LUse::ANY)) {
                 nunboxParts_[i].type = type;
-                partialNunboxes_--;
                 return true;
             }
         }
-        partialNunboxes_++;
 
         // vregs for nunbox pairs are adjacent, with the type coming first.
         uint32_t payloadVreg = typeVreg + 1;
-        bool result = nunboxParts_.append(NunboxEntry(type, LUse(payloadVreg, LUse::ANY)));
+        bool result = nunboxParts_.append(NunboxEntry(typeVreg, type, LUse(payloadVreg, LUse::ANY)));
         if (result)
             assertInvariants();
         return result;
     }
 
-    bool hasNunboxType(LAllocation type) const {
-        if (type.isArgument())
-            return true;
-        if (type.isStackSlot() && hasValueSlot(type.toStackSlot()->slot() + 1))
-            return true;
-        for (size_t i = 0; i < nunboxParts_.length(); i++) {
-            if (nunboxParts_[i].type == type)
-                return true;
-        }
-        return false;
-    }
-
     bool addNunboxPayload(uint32_t payloadVreg, LAllocation payload) {
         for (size_t i = 0; i < nunboxParts_.length(); i++) {
             if (nunboxParts_[i].payload == payload)
                 return true;
             if (nunboxParts_[i].payload == LUse(payloadVreg, LUse::ANY)) {
-                partialNunboxes_--;
                 nunboxParts_[i].payload = payload;
                 return true;
             }
         }
-        partialNunboxes_++;
 
         // vregs for nunbox pairs are adjacent, with the type coming first.
         uint32_t typeVreg = payloadVreg - 1;
-        bool result = nunboxParts_.append(NunboxEntry(LUse(typeVreg, LUse::ANY), payload));
+        bool result = nunboxParts_.append(NunboxEntry(typeVreg, LUse(typeVreg, LUse::ANY), payload));
         if (result)
             assertInvariants();
         return result;
     }
 
+    LAllocation findTypeAllocation(uint32_t typeVreg) {
+        // Look for some allocation for the specified type vreg, to go with a
+        // partial nunbox entry for the payload. Note that we don't need to
+        // look at the value slots in the safepoint, as these aren't used by
+        // register allocators which add partial nunbox entries.
+        for (size_t i = 0; i < nunboxParts_.length(); i++) {
+            if (nunboxParts_[i].typeVreg == typeVreg && !nunboxParts_[i].type.isUse())
+                return nunboxParts_[i].type;
+        }
+        return LUse(typeVreg, LUse::ANY);
+    }
+
+#ifdef DEBUG
     bool hasNunboxPayload(LAllocation payload) const {
         if (payload.isArgument())
             return true;
         if (payload.isStackSlot() && hasValueSlot(payload.toStackSlot()->slot()))
             return true;
         for (size_t i = 0; i < nunboxParts_.length(); i++) {
             if (nunboxParts_[i].payload == payload)
                 return true;
         }
         return false;
     }
+#endif
 
     NunboxList &nunboxParts() {
         return nunboxParts_;
     }
 
-    uint32_t partialNunboxes() {
-        return partialNunboxes_;
-    }
-
 #elif JS_PUNBOX64
 
     void addValueRegister(Register reg) {
         valueRegs_.add(reg);
         assertInvariants();
     }
     GeneralRegisterSet valueRegs() const {
         return valueRegs_;
--- a/js/src/jit/LinearScan.cpp
+++ b/js/src/jit/LinearScan.cpp
@@ -604,24 +604,28 @@ LinearScanAllocator::populateSafepoints(
 
                 if (!ins->isCall() &&
                     (!isSpilledAt(typeInterval, inputOf(ins)) || payloadAlloc->isGeneralReg()))
                 {
                     // Either the payload is on the stack but the type is
                     // in a register, or the payload is in a register. In
                     // both cases, we don't have a contiguous spill so we
                     // add a torn entry.
-                    if (!safepoint->addNunboxParts(*typeAlloc, *payloadAlloc))
+                    uint32_t typeVreg = type->def()->virtualRegister();
+                    if (!safepoint->addNunboxParts(typeVreg, *typeAlloc, *payloadAlloc))
                         return false;
 
                     // If the nunbox is stored in multiple places, we need to
                     // trace all of them to allow the GC to relocate objects.
                     if (payloadAlloc->isGeneralReg() && isSpilledAt(payloadInterval, inputOf(ins))) {
-                        if (!safepoint->addNunboxParts(*typeAlloc, *payload->canonicalSpill()))
+                        if (!safepoint->addNunboxParts(typeVreg, *typeAlloc,
+                                                       *payload->canonicalSpill()))
+                        {
                             return false;
+                        }
                     }
                 }
 #endif
             }
         }
 
 #ifdef JS_NUNBOX32
         if (IsNunbox(reg)) {
--- a/js/src/jit/Safepoints.cpp
+++ b/js/src/jit/Safepoints.cpp
@@ -294,28 +294,39 @@ SafepointWriter::writeNunboxParts(LSafep
             fprintf(JitSpewFile, ")\n");
         }
     }
 # endif
 
     // Safepoints are permitted to have partially filled in entries for nunboxes,
     // provided that only the type is live and not the payload. Omit these from
     // the written safepoint.
-    uint32_t partials = safepoint->partialNunboxes();
 
-    stream_.writeUnsigned(entries.length() - partials);
+    size_t pos = stream_.length();
+    stream_.writeUnsigned(entries.length());
 
+    size_t count = 0;
     for (size_t i = 0; i < entries.length(); i++) {
         SafepointNunboxEntry &entry = entries[i];
 
-        if (entry.type.isUse() || entry.payload.isUse()) {
-            partials--;
+        if (entry.payload.isUse()) {
+            // No allocation associated with the payload.
             continue;
         }
 
+        if (entry.type.isUse()) {
+            // No allocation associated with the type. Look for another
+            // safepoint entry with an allocation for the type.
+            entry.type = safepoint->findTypeAllocation(entry.typeVreg);
+            if (entry.type.isUse())
+                continue;
+        }
+
+        count++;
+
         uint16_t header = 0;
 
         header |= (AllocationToPartKind(entry.type) << TYPE_KIND_SHIFT);
         header |= (AllocationToPartKind(entry.payload) << PAYLOAD_KIND_SHIFT);
 
         uint32_t typeVal;
         bool typeExtra = !CanEncodeInfoInHeader(entry.type, &typeVal);
         if (!typeExtra)
@@ -332,17 +343,18 @@ SafepointWriter::writeNunboxParts(LSafep
 
         stream_.writeFixedUint16_t(header);
         if (typeExtra)
             stream_.writeUnsigned(typeVal);
         if (payloadExtra)
             stream_.writeUnsigned(payloadVal);
     }
 
-    MOZ_ASSERT(partials == 0);
+    // Update the stream with the actual number of safepoint entries written.
+    stream_.writeUnsignedAt(pos, count, entries.length());
 }
 #endif
 
 void
 SafepointWriter::encode(LSafepoint *safepoint)
 {
     uint32_t safepointOffset = startEntry();
 
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -4681,17 +4681,17 @@ GCRuntime::endMarkingZoneGroup()
     marker.setMarkColorBlack();
 }
 
 #define MAKE_GC_PARALLEL_TASK(name) \
     class name : public GCParallelTask {\
         JSRuntime *runtime;\
         virtual void run() MOZ_OVERRIDE;\
       public:\
-        name (JSRuntime *rt) : runtime(rt) {}\
+        explicit name (JSRuntime *rt) : runtime(rt) {}\
     }
 MAKE_GC_PARALLEL_TASK(SweepAtomsTask);
 MAKE_GC_PARALLEL_TASK(SweepInnerViewsTask);
 MAKE_GC_PARALLEL_TASK(SweepCCWrappersTask);
 MAKE_GC_PARALLEL_TASK(SweepBaseShapesTask);
 MAKE_GC_PARALLEL_TASK(SweepInitialShapesTask);
 MAKE_GC_PARALLEL_TASK(SweepTypeObjectsTask);
 MAKE_GC_PARALLEL_TASK(SweepRegExpsTask);
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -1101,22 +1101,22 @@ struct TypeObject : public gc::TenuredCe
   public:
 
     TypeObjectFlags flags() {
         maybeSweep(nullptr);
         return flags_;
     }
 
     void addFlags(TypeObjectFlags flags) {
-        MOZ_ASSERT(!needsSweep());
+        maybeSweep(nullptr);
         flags_ |= flags;
     }
 
     void clearFlags(TypeObjectFlags flags) {
-        MOZ_ASSERT(!needsSweep());
+        maybeSweep(nullptr);
         flags_ &= ~flags;
     }
 
     TypeNewScript *newScript() {
         maybeSweep(nullptr);
         return newScript_;
     }
 
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -303,23 +303,28 @@ class TypedArrayObjectTemplate : public 
 
         return &obj->as<TypedArrayObject>();
     }
 
     static TypedArrayObject *
     makeTypedInstance(JSContext *cx, uint32_t len, gc::AllocKind allocKind)
     {
         const Class *clasp = instanceClass();
-        bool largeAllocation = len * sizeof(NativeType) >= TypedArrayObject::SINGLETON_TYPE_BYTE_LENGTH;
+        if (len * sizeof(NativeType) >= TypedArrayObject::SINGLETON_TYPE_BYTE_LENGTH) {
+            JSObject *obj = NewBuiltinClassInstance(cx, clasp, allocKind, SingletonObject);
+            if (!obj)
+                return nullptr;
+            return &obj->as<TypedArrayObject>();
+        }
 
         jsbytecode *pc;
         RootedScript script(cx, cx->currentScript(&pc));
         NewObjectKind newKind = script
                                 ? UseNewTypeForInitializer(script, pc, clasp)
-                                : (largeAllocation ? SingletonObject : GenericObject);
+                                : GenericObject;
         RootedObject obj(cx, NewBuiltinClassInstance(cx, clasp, allocKind, newKind));
         if (!obj)
             return nullptr;
 
         if (script) {
             if (!types::SetInitializerObjectType(cx, script, pc, obj, newKind))
                 return nullptr;
         }
--- a/layout/base/nsBidiPresUtils.cpp
+++ b/layout/base/nsBidiPresUtils.cpp
@@ -1,14 +1,15 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsBidiPresUtils.h"
+#include "nsFontMetrics.h"
 #include "nsGkAtoms.h"
 #include "nsPresContext.h"
 #include "nsRenderingContext.h"
 #include "nsBidiUtils.h"
 #include "nsCSSFrameConstructor.h"
 #include "nsContainerFrame.h"
 #include "nsInlineFrame.h"
 #include "nsPlaceholderFrame.h"
@@ -2049,71 +2050,84 @@ nsresult nsBidiPresUtils::ProcessText(co
   } // for
 
   if (aWidth) {
     *aWidth = totalWidth;
   }
   return NS_OK;
 }
 
-class MOZ_STACK_CLASS nsIRenderingContextBidiProcessor : public nsBidiPresUtils::BidiProcessor {
+class MOZ_STACK_CLASS nsIRenderingContextBidiProcessor MOZ_FINAL
+  : public nsBidiPresUtils::BidiProcessor
+{
 public:
   nsIRenderingContextBidiProcessor(nsRenderingContext* aCtx,
                                    nsRenderingContext* aTextRunConstructionContext,
+                                   nsFontMetrics* aFontMetrics,
                                    const nsPoint&       aPt)
-    : mCtx(aCtx), mTextRunConstructionContext(aTextRunConstructionContext), mPt(aPt) { }
+    : mCtx(aCtx)
+    , mTextRunConstructionContext(aTextRunConstructionContext)
+    , mFontMetrics(aFontMetrics)
+    , mPt(aPt)
+  {}
 
   ~nsIRenderingContextBidiProcessor()
   {
-    mCtx->SetTextRunRTL(false);
+    mFontMetrics->SetTextRunRTL(false);
   }
 
   virtual void SetText(const char16_t* aText,
                        int32_t          aLength,
                        nsBidiDirection  aDirection) MOZ_OVERRIDE
   {
-    mTextRunConstructionContext->SetTextRunRTL(aDirection==NSBIDI_RTL);
+    mFontMetrics->SetTextRunRTL(aDirection==NSBIDI_RTL);
     mText = aText;
     mLength = aLength;
   }
 
   virtual nscoord GetWidth() MOZ_OVERRIDE
   {
-    return mTextRunConstructionContext->GetWidth(mText, mLength);
+    return nsLayoutUtils::AppUnitWidthOfString(mText, mLength, *mFontMetrics,
+                                               *mTextRunConstructionContext);
   }
 
   virtual void DrawText(nscoord aXOffset,
                         nscoord) MOZ_OVERRIDE
   {
-    mCtx->FontMetrics()->DrawString(mText, mLength, mPt.x + aXOffset, mPt.y,
-                                    mCtx, mTextRunConstructionContext);
+    mFontMetrics->DrawString(mText, mLength, mPt.x + aXOffset, mPt.y,
+                             mCtx, mTextRunConstructionContext);
   }
 
 private:
   nsRenderingContext* mCtx;
   nsRenderingContext* mTextRunConstructionContext;
+  nsFontMetrics* mFontMetrics;
   nsPoint mPt;
   const char16_t* mText;
   int32_t mLength;
 };
 
 nsresult nsBidiPresUtils::ProcessTextForRenderingContext(const char16_t*       aText,
                                                          int32_t                aLength,
                                                          nsBidiLevel            aBaseLevel,
                                                          nsPresContext*         aPresContext,
                                                          nsRenderingContext&   aRenderingContext,
                                                          nsRenderingContext&   aTextRunConstructionContext,
+                                                         nsFontMetrics&         aFontMetrics,
                                                          Mode                   aMode,
                                                          nscoord                aX,
                                                          nscoord                aY,
                                                          nsBidiPositionResolve* aPosResolve,
                                                          int32_t                aPosResolveCount,
                                                          nscoord*               aWidth)
 {
-  nsIRenderingContextBidiProcessor processor(&aRenderingContext, &aTextRunConstructionContext, nsPoint(aX, aY));
+  nsIRenderingContextBidiProcessor processor(&aRenderingContext,
+                                             &aTextRunConstructionContext,
+                                             &aFontMetrics,
+                                             nsPoint(aX, aY));
   nsBidi bidiEngine;
   return ProcessText(aText, aLength, aBaseLevel, aPresContext, processor,
                      aMode, aPosResolve, aPosResolveCount, aWidth, &bidiEngine);
 }
 
 /* static */
 void nsBidiPresUtils::WriteReverse(const char16_t* aSrc,
                                    uint32_t aSrcLength,
--- a/layout/base/nsBidiPresUtils.h
+++ b/layout/base/nsBidiPresUtils.h
@@ -13,16 +13,17 @@
 #include "nsCoord.h"
 
 #ifdef DrawText
 #undef DrawText
 #endif
 
 struct BidiParagraphData;
 struct BidiLineData;
+class nsFontMetrics;
 class nsIFrame;
 class nsBlockFrame;
 class nsPresContext;
 class nsRenderingContext;
 class nsBlockInFlowLineIterator;
 class nsStyleContext;
 template<class T> class nsTHashtable;
 namespace mozilla { class WritingMode; }
@@ -201,34 +202,39 @@ public:
    * @param aPosResolveCount number of items in the aPosResolve array
    */
   static nsresult RenderText(const char16_t*       aText,
                              int32_t                aLength,
                              nsBidiLevel            aBaseLevel,
                              nsPresContext*         aPresContext,
                              nsRenderingContext&    aRenderingContext,
                              nsRenderingContext&    aTextRunConstructionContext,
+                             nsFontMetrics&         aFontMetrics,
                              nscoord                aX,
                              nscoord                aY,
                              nsBidiPositionResolve* aPosResolve = nullptr,
                              int32_t                aPosResolveCount = 0)
   {
     return ProcessTextForRenderingContext(aText, aLength, aBaseLevel, aPresContext, aRenderingContext,
-                                          aTextRunConstructionContext, MODE_DRAW, aX, aY, aPosResolve, aPosResolveCount, nullptr);
+                                          aTextRunConstructionContext,
+                                          aFontMetrics,
+                                          MODE_DRAW, aX, aY, aPosResolve, aPosResolveCount, nullptr);
   }
   
   static nscoord MeasureTextWidth(const char16_t*     aText,
                                   int32_t              aLength,
                                   nsBidiLevel          aBaseLevel,
                                   nsPresContext*       aPresContext,
-                                  nsRenderingContext&  aRenderingContext)
+                                  nsRenderingContext&  aRenderingContext,
+                                  nsFontMetrics&       aFontMetrics)
   {
     nscoord length;
     nsresult rv = ProcessTextForRenderingContext(aText, aLength, aBaseLevel, aPresContext,
                                                  aRenderingContext, aRenderingContext,
+                                                 aFontMetrics,
                                                  MODE_MEASURE, 0, 0, nullptr, 0, &length);
     return NS_SUCCEEDED(rv) ? length : 0;
   }
 
   /**
    * Check if a line is reordered, i.e., if the child frames are not
    * all laid out left-to-right.
    * @param aFirstFrameOnLine : first frame of the line to be tested
@@ -355,16 +361,17 @@ public:
 private:
   static nsresult
   ProcessTextForRenderingContext(const char16_t*       aText,
                                  int32_t                aLength,
                                  nsBidiLevel            aBaseLevel,
                                  nsPresContext*         aPresContext,
                                  nsRenderingContext&    aRenderingContext,
                                  nsRenderingContext&    aTextRunConstructionContext,
+                                 nsFontMetrics&         aFontMetrics,
                                  Mode                   aMode,
                                  nscoord                aX, // DRAW only
                                  nscoord                aY, // DRAW only
                                  nsBidiPositionResolve* aPosResolve,  /* may be null */
                                  int32_t                aPosResolveCount,
                                  nscoord*               aWidth /* may be null */);
 
   /**
--- a/layout/base/nsCaret.cpp
+++ b/layout/base/nsCaret.cpp
@@ -8,16 +8,17 @@
 
 #include "nsCaret.h"
 
 #include <algorithm>
 
 #include "gfxUtils.h"
 #include "mozilla/gfx/2D.h"
 #include "nsCOMPtr.h"
+#include "nsFontMetrics.h"
 #include "nsITimer.h"
 #include "nsFrameSelection.h"
 #include "nsIFrame.h"
 #include "nsIScrollableFrame.h"
 #include "nsIDOMNode.h"
 #include "nsISelection.h"
 #include "nsISelectionPrivate.h"
 #include "nsIContent.h"
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -6,16 +6,18 @@
 
 #include "nsLayoutUtils.h"
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/BasicEvents.h"
 #include "mozilla/gfx/PathHelpers.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/MemoryReporting.h"
+#include "nsCharTraits.h"
+#include "nsFontMetrics.h"
 #include "nsPresContext.h"
 #include "nsIContent.h"
 #include "nsIDOMHTMLDocument.h"
 #include "nsIDOMHTMLElement.h"
 #include "nsFrameList.h"
 #include "nsGkAtoms.h"
 #include "nsIAtom.h"
 #include "nsCSSPseudoElements.h"
@@ -3180,53 +3182,62 @@ nsLayoutUtils::PaintFrame(nsRenderingCon
  * of the text that has already been measured, and aBaseInx contains
  * the index of the text that has already been measured.
  *
  * @param aTextWidth returns the (in twips) the length of the text that falls
  * before the cursor aIndex contains the index of the text where the cursor falls
  */
 bool
 nsLayoutUtils::BinarySearchForPosition(nsRenderingContext* aRendContext,
+                                       nsFontMetrics& aFontMetrics,
                         const char16_t* aText,
                         int32_t    aBaseWidth,
                         int32_t    aBaseInx,
                         int32_t    aStartInx,
                         int32_t    aEndInx,
                         int32_t    aCursorPos,
                         int32_t&   aIndex,
                         int32_t&   aTextWidth)
 {
   int32_t range = aEndInx - aStartInx;
   if ((range == 1) || (range == 2 && NS_IS_HIGH_SURROGATE(aText[aStartInx]))) {
     aIndex   = aStartInx + aBaseInx;
-    aTextWidth = aRendContext->GetWidth(aText, aIndex);
+    aTextWidth = nsLayoutUtils::AppUnitWidthOfString(aText, aIndex,
+                                                     aFontMetrics,
+                                                     *aRendContext);
     return true;
   }
 
   int32_t inx = aStartInx + (range / 2);
 
   // Make sure we don't leave a dangling low surrogate
   if (NS_IS_HIGH_SURROGATE(aText[inx-1]))
     inx++;
 
-  int32_t textWidth = aRendContext->GetWidth(aText, inx);
+  int32_t textWidth = nsLayoutUtils::AppUnitWidthOfString(aText, inx,
+                                                          aFontMetrics,
+                                                          *aRendContext);
 
   int32_t fullWidth = aBaseWidth + textWidth;
   if (fullWidth == aCursorPos) {
     aTextWidth = textWidth;
     aIndex = inx;
     return true;
   } else if (aCursorPos < fullWidth) {
     aTextWidth = aBaseWidth;
-    if (BinarySearchForPosition(aRendContext, aText, aBaseWidth, aBaseInx, aStartInx, inx, aCursorPos, aIndex, aTextWidth)) {
+    if (BinarySearchForPosition(aRendContext, aFontMetrics, aText, aBaseWidth,
+                                aBaseInx, aStartInx, inx, aCursorPos, aIndex,
+                                aTextWidth)) {
       return true;
     }
   } else {
     aTextWidth = fullWidth;
-    if (BinarySearchForPosition(aRendContext, aText, aBaseWidth, aBaseInx, inx, aEndInx, aCursorPos, aIndex, aTextWidth)) {
+    if (BinarySearchForPosition(aRendContext, aFontMetrics, aText, aBaseWidth,
+                                aBaseInx, inx, aEndInx, aCursorPos, aIndex,
+                                aTextWidth)) {
       return true;
     }
   }
   return false;
 }
 
 static void
 AddBoxesForFrame(nsIFrame* aFrame,
@@ -4623,95 +4634,185 @@ nsLayoutUtils::GetSnappedBaselineY(nsIFr
   gfxFloat appUnitsPerDevUnit = aFrame->PresContext()->AppUnitsPerDevPixel();
   gfxFloat baseline = gfxFloat(aY) + aAscent;
   gfxRect putativeRect(0, baseline/appUnitsPerDevUnit, 1, 1);
   if (!aContext->UserToDevicePixelSnapped(putativeRect, true))
     return baseline;
   return aContext->DeviceToUser(putativeRect.TopLeft()).y * appUnitsPerDevUnit;
 }
 
+// Hard limit substring lengths to 8000 characters ... this lets us statically
+// size the cluster buffer array in FindSafeLength
+#define MAX_GFX_TEXT_BUF_SIZE 8000
+
+static int32_t FindSafeLength(const char16_t *aString, uint32_t aLength,
+                              uint32_t aMaxChunkLength)
+{
+  if (aLength <= aMaxChunkLength)
+    return aLength;
+
+  int32_t len = aMaxChunkLength;
+
+  // Ensure that we don't break inside a surrogate pair
+  while (len > 0 && NS_IS_LOW_SURROGATE(aString[len])) {
+    len--;
+  }
+  if (len == 0) {
+    // We don't want our caller to go into an infinite loop, so don't
+    // return zero. It's hard to imagine how we could actually get here
+    // unless there are languages that allow clusters of arbitrary size.
+    // If there are and someone feeds us a 500+ character cluster, too
+    // bad.
+    return aMaxChunkLength;
+  }
+  return len;
+}
+
+static int32_t GetMaxChunkLength(nsFontMetrics& aFontMetrics)
+{
+  return std::min(aFontMetrics.GetMaxStringLength(), MAX_GFX_TEXT_BUF_SIZE);
+}
+
+nscoord
+nsLayoutUtils::AppUnitWidthOfString(const nsString& aString,
+                                    nsFontMetrics& aFontMetrics,
+                                    nsRenderingContext& aContext)
+{
+  return AppUnitWidthOfString(aString.get(), aString.Length(),
+                              aFontMetrics, aContext);
+}
+
+nscoord
+nsLayoutUtils::AppUnitWidthOfString(const char16_t *aString,
+                                    uint32_t aLength,
+                                    nsFontMetrics& aFontMetrics,
+                                    nsRenderingContext& aContext)
+{
+  uint32_t maxChunkLength = GetMaxChunkLength(aFontMetrics);
+  nscoord width = 0;
+  while (aLength > 0) {
+    int32_t len = FindSafeLength(aString, aLength, maxChunkLength);
+    width += aFontMetrics.GetWidth(aString, len, &aContext);
+    aLength -= len;
+    aString += len;
+  }
+  return width;
+}
+
+nsBoundingMetrics
+nsLayoutUtils::AppUnitBoundsOfString(const char16_t* aString,
+                                     uint32_t aLength,
+                                     nsFontMetrics& aFontMetrics,
+                                     nsRenderingContext& aContext)
+{
+  uint32_t maxChunkLength = GetMaxChunkLength(aFontMetrics);
+  int32_t len = FindSafeLength(aString, aLength, maxChunkLength);
+  // Assign directly in the first iteration. This ensures that
+  // negative ascent/descent can be returned and the left bearing
+  // is properly initialized.
+  nsBoundingMetrics totalMetrics =
+    aFontMetrics.GetBoundingMetrics(aString, len, &aContext);
+  aLength -= len;
+  aString += len;
+
+  while (aLength > 0) {
+    len = FindSafeLength(aString, aLength, maxChunkLength);
+    nsBoundingMetrics metrics =
+      aFontMetrics.GetBoundingMetrics(aString, len, &aContext);
+    totalMetrics += metrics;
+    aLength -= len;
+    aString += len;
+  }
+  return totalMetrics;
+}
+
 void
 nsLayoutUtils::DrawString(const nsIFrame*       aFrame,
+                          nsFontMetrics&        aFontMetrics,
                           nsRenderingContext*   aContext,
                           const char16_t*      aString,
                           int32_t               aLength,
                           nsPoint               aPoint,
                           nsStyleContext*       aStyleContext)
 {
   nsresult rv = NS_ERROR_FAILURE;
   nsPresContext* presContext = aFrame->PresContext();
   if (presContext->BidiEnabled()) {
     nsBidiLevel level =
       nsBidiPresUtils::BidiLevelFromStyle(aStyleContext ?
                                           aStyleContext : aFrame->StyleContext());
     rv = nsBidiPresUtils::RenderText(aString, aLength, level,
                                      presContext, *aContext, *aContext,
+                                     aFontMetrics,
                                      aPoint.x, aPoint.y);
   }
   if (NS_FAILED(rv))
   {
-    aContext->SetTextRunRTL(false);
-    DrawUniDirString(aString, aLength, aPoint, *aContext);
+    aFontMetrics.SetTextRunRTL(false);
+    DrawUniDirString(aString, aLength, aPoint, aFontMetrics, *aContext);
   }
 }
 
 void
 nsLayoutUtils::DrawUniDirString(const char16_t* aString,
                                 uint32_t aLength,
                                 nsPoint aPoint,
+                                nsFontMetrics& aFontMetrics,
                                 nsRenderingContext& aContext)
 {
   nscoord x = aPoint.x;
   nscoord y = aPoint.y;
 
-  nsFontMetrics* fm = aContext.FontMetrics();
-
-  uint32_t maxChunkLength = aContext.GetMaxChunkLength();
+  uint32_t maxChunkLength = GetMaxChunkLength(aFontMetrics);
   if (aLength <= maxChunkLength) {
-    fm->DrawString(aString, aLength, x, y, &aContext, &aContext);
+    aFontMetrics.DrawString(aString, aLength, x, y, &aContext, &aContext);
     return;
   }
 
-  bool isRTL = fm->GetTextRunRTL();
+  bool isRTL = aFontMetrics.GetTextRunRTL();
 
   // If we're drawing right to left, we must start at the end.
   if (isRTL) {
-    x += aContext.GetWidth(aString, aLength);
+    x += nsLayoutUtils::AppUnitWidthOfString(aString, aLength, aFontMetrics,
+                                             aContext);
   }
 
   while (aLength > 0) {
-    int32_t len = nsRenderingContext::FindSafeLength(aString, aLength, maxChunkLength);
-    nscoord width = fm->GetWidth(aString, len, &aContext);
+    int32_t len = FindSafeLength(aString, aLength, maxChunkLength);
+    nscoord width = aFontMetrics.GetWidth(aString, len, &aContext);
     if (isRTL) {
       x -= width;
     }
-    fm->DrawString(aString, len, x, y, &aContext, &aContext);
+    aFontMetrics.DrawString(aString, len, x, y, &aContext, &aContext);
     if (!isRTL) {
       x += width;
     }
     aLength -= len;
     aString += len;
   }
 }
 
 nscoord
 nsLayoutUtils::GetStringWidth(const nsIFrame*      aFrame,
                               nsRenderingContext* aContext,
+                              nsFontMetrics&      aFontMetrics,
                               const char16_t*     aString,
                               int32_t              aLength)
 {
   nsPresContext* presContext = aFrame->PresContext();
   if (presContext->BidiEnabled()) {
     nsBidiLevel level =
       nsBidiPresUtils::BidiLevelFromStyle(aFrame->StyleContext());
     return nsBidiPresUtils::MeasureTextWidth(aString, aLength,
-                                             level, presContext, *aContext);
-  }
-  aContext->SetTextRunRTL(false);
-  return aContext->GetWidth(aString, aLength);
+                                             level, presContext, *aContext,
+                                             aFontMetrics);
+  }
+  aFontMetrics.SetTextRunRTL(false);
+  return nsLayoutUtils::AppUnitWidthOfString(aString, aLength, aFontMetrics,
+                                             *aContext);
 }
 
 /* static */ void
 nsLayoutUtils::PaintTextShadow(const nsIFrame* aFrame,
                                nsRenderingContext* aContext,
                                const nsRect& aTextRect,
                                const nsRect& aDirtyRect,
                                const nscolor& aForegroundColor,
@@ -7170,17 +7271,16 @@ nsLayoutUtils::SetBSizeFromFontMetrics(c
                                        const nsHTMLReflowState& aReflowState,
                                        LogicalMargin aFramePadding, 
                                        WritingMode aLineWM,
                                        WritingMode aFrameWM)
 {
   nsRefPtr<nsFontMetrics> fm;
   float inflation = nsLayoutUtils::FontSizeInflationFor(aFrame);
   nsLayoutUtils::GetFontMetricsForFrame(aFrame, getter_AddRefs(fm), inflation);
-  aReflowState.rendContext->SetFont(fm);
 
   if (fm) {
     // Compute final height of the frame.
     //
     // Do things the standard css2 way -- though it's hard to find it
     // in the css2 spec! It's actually found in the css1 spec section
     // 4.4 (you will have to read between the lines to really see
     // it).
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -3,16 +3,17 @@
  * 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 nsLayoutUtils_h__
 #define nsLayoutUtils_h__
 
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/ArrayUtils.h"
+#include "nsBoundingMetrics.h"
 #include "nsChangeHint.h"
 #include "nsAutoPtr.h"
 #include "nsFrameList.h"
 #include "mozilla/layout/FrameChildList.h"
 #include "nsThreadUtils.h"
 #include "nsIPrincipal.h"
 #include "GraphicsFilter.h"
 #include "nsCSSPseudoElements.h"
@@ -953,16 +954,17 @@ public:
    * the index of the text that has already been measured.
    *
    * @param aTextWidth returns (in twips) the length of the text that falls
    * before the cursor aIndex contains the index of the text where the cursor
    * falls.
    */
   static bool
   BinarySearchForPosition(nsRenderingContext* acx,
+                          nsFontMetrics& aFontMetrics,
                           const char16_t* aText,
                           int32_t    aBaseWidth,
                           int32_t    aBaseInx,
                           int32_t    aStartInx,
                           int32_t    aEndInx,
                           int32_t    aCursorPos,
                           int32_t&   aIndex,
                           int32_t&   aTextWidth);
@@ -1312,33 +1314,53 @@ public:
 
   // Get a suitable foreground color for painting aProperty for aFrame.
   static nscolor GetColor(nsIFrame* aFrame, nsCSSProperty aProperty);
 
   // Get a baseline y position in app units that is snapped to device pixels.
   static gfxFloat GetSnappedBaselineY(nsIFrame* aFrame, gfxContext* aContext,
                                       nscoord aY, nscoord aAscent);
 
+  static nscoord AppUnitWidthOfString(char16_t aC,
+                                      nsFontMetrics& aFontMetrics,
+                                      nsRenderingContext& aContext) {
+    return AppUnitWidthOfString(&aC, 1, aFontMetrics, aContext);
+  }
+  static nscoord AppUnitWidthOfString(const nsString& aString,
+                                      nsFontMetrics& aFontMetrics,
+                                      nsRenderingContext& aContext);
+  static nscoord AppUnitWidthOfString(const char16_t *aString,
+                                      uint32_t aLength,
+                                      nsFontMetrics& aFontMetrics,
+                                      nsRenderingContext& aContext);
+  static nsBoundingMetrics AppUnitBoundsOfString(const char16_t* aString,
+                                                 uint32_t aLength,
+                                                 nsFontMetrics& aFontMetrics,
+                                                 nsRenderingContext& aContext);
+
   static void DrawString(const nsIFrame*       aFrame,
+                         nsFontMetrics&        aFontMetrics,
                          nsRenderingContext*   aContext,
                          const char16_t*      aString,
                          int32_t               aLength,
                          nsPoint               aPoint,
                          nsStyleContext*       aStyleContext = nullptr);
 
   /**
    * Supports only LTR or RTL. Bidi (mixed direction) is not supported.
    */
   static void DrawUniDirString(const char16_t* aString,
                                uint32_t aLength,
                                nsPoint aPoint,
+                               nsFontMetrics& aFontMetrics,
                                nsRenderingContext& aContext);
 
   static nscoord GetStringWidth(const nsIFrame*      aFrame,
                                 nsRenderingContext* aContext,
+                                nsFontMetrics&      aFontMetrics,
                                 const char16_t*     aString,
                                 int32_t              aLength);
 
   /**
    * Helper function for drawing text-shadow. The callback's job
    * is to draw whatever needs to be blurred onto the given context.
    */
   typedef void (* TextShadowCallback)(nsRenderingContext* aCtx,
--- a/layout/forms/nsTextControlFrame.cpp
+++ b/layout/forms/nsTextControlFrame.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/DebugOnly.h"
 
 #include "nsCOMPtr.h"
+#include "nsFontMetrics.h"
 #include "nsTextControlFrame.h"
 #include "nsIPlaintextEditor.h"
 #include "nsCaret.h"
 #include "nsGenericHTMLElement.h"
 #include "nsIEditor.h"
 #include "nsIEditorIMESupport.h"
 #include "nsIPhonetic.h"
 #include "nsTextFragment.h"
@@ -150,17 +151,16 @@ nsTextControlFrame::CalcIntrinsicSize(ns
   nscoord charWidth   = 0;
   nscoord charMaxAdvance  = 0;
 
   nsRefPtr<nsFontMetrics> fontMet;
   nsresult rv =
     nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fontMet),
                                           aFontSizeInflation);
   NS_ENSURE_SUCCESS(rv, rv);
-  aRenderingContext->SetFont(fontMet);
 
   lineHeight =
     nsHTMLReflowState::CalcLineHeight(GetContent(), StyleContext(),
                                       NS_AUTOHEIGHT, aFontSizeInflation);
   charWidth = fontMet->AveCharWidth();
   charMaxAdvance = fontMet->MaxAdvance();
 
   // Set the width equal to the width in characters
--- a/layout/generic/TextOverflow.cpp
+++ b/layout/generic/TextOverflow.cpp
@@ -7,16 +7,17 @@
 #include "TextOverflow.h"
 #include <algorithm>
 
 // Please maintain alphabetical order below
 #include "nsBlockFrame.h"
 #include "nsCaret.h"
 #include "nsContentUtils.h"
 #include "nsCSSAnonBoxes.h"
+#include "nsFontMetrics.h"
 #include "nsGfxScrollFrame.h"
 #include "nsIScrollableFrame.h"
 #include "nsLayoutUtils.h"
 #include "nsPresContext.h"
 #include "nsRect.h"
 #include "nsRenderingContext.h"
 #include "nsTextFrame.h"
 #include "nsIFrameInlines.h"
@@ -233,18 +234,17 @@ nsDisplayTextOverflowMarker::PaintTextTo
       gfxPoint gfxPt(pt.x, pt.y);
       textRun->Draw(aCtx->ThebesContext(), gfxPt, DrawMode::GLYPH_FILL,
                     0, textRun->GetLength(), nullptr, nullptr, nullptr);
     }
   } else {
     nsRefPtr<nsFontMetrics> fm;
     nsLayoutUtils::GetFontMetricsForFrame(mFrame, getter_AddRefs(fm),
       nsLayoutUtils::FontSizeInflationFor(mFrame));
-    aCtx->SetFont(fm);
-    nsLayoutUtils::DrawString(mFrame, aCtx, mStyle->mString.get(),
+    nsLayoutUtils::DrawString(mFrame, *fm, aCtx, mStyle->mString.get(),
                               mStyle->mString.Length(), pt);
   }
 }
 
 void
 TextOverflow::Init(nsDisplayListBuilder*   aBuilder,
                    nsIFrame*               aBlockFrame)
 {
@@ -758,18 +758,18 @@ TextOverflow::Marker::SetupString(nsIFra
       mWidth = 0;
     }
   } else {
     nsRefPtr<nsRenderingContext> rc =
       aFrame->PresContext()->PresShell()->CreateReferenceRenderingContext();
     nsRefPtr<nsFontMetrics> fm;
     nsLayoutUtils::GetFontMetricsForFrame(aFrame, getter_AddRefs(fm),
       nsLayoutUtils::FontSizeInflationFor(aFrame));
-    rc->SetFont(fm);
-    mWidth = nsLayoutUtils::GetStringWidth(aFrame, rc, mStyle->mString.get(),
+    mWidth = nsLayoutUtils::GetStringWidth(aFrame, rc, *fm,
+                                           mStyle->mString.get(),
                                            mStyle->mString.Length());
   }
   mIntrinsicISize = mWidth;
   mInitialized = true;
 }
 
 }  // namespace css
 }  // namespace mozilla
--- a/layout/generic/nsBRFrame.cpp
+++ b/layout/generic/nsBRFrame.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; 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/. */
 
 /* rendering object for HTML <br> elements */
 
 #include "nsCOMPtr.h"
+#include "nsFontMetrics.h"
 #include "nsFrame.h"
 #include "nsPresContext.h"
 #include "nsLineLayout.h"
 #include "nsStyleConsts.h"
 #include "nsGkAtoms.h"
 #include "nsRenderingContext.h"
 #include "nsLayoutUtils.h"
 
@@ -113,17 +114,16 @@ BRFrame::Reflow(nsPresContext* aPresCont
       // of the full line-height
 
       // We also do this in strict mode because BR should act like a
       // normal inline frame.  That line-height is used is important
       // here for cases where the line-height is less than 1.
       nsRefPtr<nsFontMetrics> fm;
       nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm),
         nsLayoutUtils::FontSizeInflationFor(this));
-      aReflowState.rendContext->SetFont(fm); // FIXME: maybe not needed?
       if (fm) {
         nscoord logicalHeight = aReflowState.CalcLineHeight();
         finalSize.BSize(wm) = logicalHeight;
         aMetrics.SetBlockStartAscent(nsLayoutUtils::GetCenteredFontBaseline(fm, logicalHeight));
       }
       else {
         aMetrics.SetBlockStartAscent(aMetrics.BSize(wm) = 0);
       }
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -13,16 +13,17 @@
 
 #include "mozilla/DebugOnly.h"
 
 #include "nsCOMPtr.h"
 #include "nsAbsoluteContainingBlock.h"
 #include "nsBlockReflowContext.h"
 #include "nsBlockReflowState.h"
 #include "nsBulletFrame.h"
+#include "nsFontMetrics.h"
 #include "nsLineBox.h"
 #include "nsLineLayout.h"
 #include "nsPlaceholderFrame.h"
 #include "nsStyleConsts.h"
 #include "nsFrameManager.h"
 #include "nsPresContext.h"
 #include "nsIPresShell.h"
 #include "nsStyleContext.h"
@@ -2508,17 +2509,16 @@ nsBlockFrame::ReflowDirtyLines(nsBlockRe
         } else {
           metrics.SetBlockStartAscent(metrics.BSize(wm));
         }
       }
 
       nsRefPtr<nsFontMetrics> fm;
       nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm),
         nsLayoutUtils::FontSizeInflationFor(this));
-      aState.mReflowState.rendContext->SetFont(fm); // FIXME: needed?
 
       nscoord minAscent =
         nsLayoutUtils::GetCenteredFontBaseline(fm, aState.mMinLineHeight);
       nscoord minDescent = aState.mMinLineHeight - minAscent;
 
       aState.mBCoord += std::max(minAscent, metrics.BlockStartAscent()) +
                         std::max(minDescent, metrics.BSize(wm) -
                                              metrics.BlockStartAscent());
@@ -3060,20 +3060,20 @@ nsBlockFrame::ReflowBlockFrame(nsBlockRe
       if (treatWithClearance) {
         aState.mBCoord += aState.mPrevBEndMargin.get();
         aState.mPrevBEndMargin.Zero();
       }
 
       // Now compute the collapsed margin-block-start value into
       // aState.mPrevBEndMargin, assuming that all child margins
       // collapse down to clearanceFrame.
-      nsBlockReflowContext::ComputeCollapsedBStartMargin(reflowState,
-                                                         &aState.mPrevBEndMargin,
-                                                         clearanceFrame,
-                                                         &mayNeedRetry);
+      brc.ComputeCollapsedBStartMargin(reflowState,
+                                       &aState.mPrevBEndMargin,
+                                       clearanceFrame,
+                                       &mayNeedRetry);
 
       // XXX optimization; we could check the collapsing children to see if they are sure
       // to require clearance, and so avoid retrying them
 
       if (clearanceFrame) {
         // Don't allow retries on the second pass. The clearance decisions for the
         // blocks whose top-margins collapse with ours are now fixed.
         mayNeedRetry = false;
@@ -3096,20 +3096,20 @@ nsBlockFrame::ReflowBlockFrame(nsBlockRe
           aLine->SetHasClearance();
 
           // Apply incoming margins
           aState.mBCoord += aState.mPrevBEndMargin.get();
           aState.mPrevBEndMargin.Zero();
 
           // Compute the collapsed margin again, ignoring the incoming margin this time
           mayNeedRetry = false;
-          nsBlockReflowContext::ComputeCollapsedBStartMargin(reflowState,
-                                                             &aState.mPrevBEndMargin,
-                                                             clearanceFrame,
-                                                             &mayNeedRetry);
+          brc.ComputeCollapsedBStartMargin(reflowState,
+                                           &aState.mPrevBEndMargin,
+                                           clearanceFrame,
+                                           &mayNeedRetry);
         }
       }
 
       // Temporarily advance the running Y value so that the
       // GetAvailableSpace method will return the right available
       // space. This undone as soon as the horizontal margins are
       // computed.
       bStartMargin = aState.mPrevBEndMargin.get();
@@ -5850,19 +5850,19 @@ nsBlockFrame::ReflowFloat(nsBlockReflowS
 
   nsIFrame* clearanceFrame = nullptr;
   do {
     nsCollapsingMargin margin;
     bool mayNeedRetry = false;
     floatRS.mDiscoveredClearance = nullptr;
     // Only first in flow gets a top margin.
     if (!aFloat->GetPrevInFlow()) {
-      nsBlockReflowContext::ComputeCollapsedBStartMargin(floatRS, &margin,
-                                                         clearanceFrame,
-                                                         &mayNeedRetry);
+      brc.ComputeCollapsedBStartMargin(floatRS, &margin,
+                                       clearanceFrame,
+                                       &mayNeedRetry);
 
       if (mayNeedRetry && !clearanceFrame) {
         floatRS.mDiscoveredClearance = &clearanceFrame;
         // We don't need to push the float manager state because the the block has its own
         // float manager that will be destroyed and recreated
       }
     }
 
--- a/layout/generic/nsBlockReflowContext.cpp
+++ b/layout/generic/nsBlockReflowContext.cpp
@@ -52,18 +52,20 @@ static nsIFrame* DescendIntoBlockLevelFr
 bool
 nsBlockReflowContext::ComputeCollapsedBStartMargin(const nsHTMLReflowState& aRS,
                                                    nsCollapsingMargin* aMargin,
                                                    nsIFrame* aClearanceFrame,
                                                    bool* aMayNeedRetry,
                                                    bool* aBlockIsEmpty)
 {
   WritingMode wm = aRS.GetWritingMode();
-  // Include frame's block-start margin
-  aMargin->Include(aRS.ComputedLogicalMargin().BStart(wm));
+  WritingMode parentWM = mMetrics.GetWritingMode();
+
+  // Include block-start element of frame's margin
+  aMargin->Include(aRS.ComputedLogicalMargin().ConvertTo(parentWM, wm).BStart(parentWM));
 
   // The inclusion of the block-end margin when empty is done by the caller
   // since it doesn't need to be done by the top-level (non-recursive)
   // caller.
 
 #ifdef NOISY_BLOCKDIR_MARGINS
   nsFrame::ListTag(stdout, aRS.frame);
   printf(": %d => %d\n", aRS.ComputedLogicalMargin().BStart(wm), aMargin->get());
@@ -169,18 +171,18 @@ nsBlockReflowContext::ComputeCollapsedBS
                                              aClearanceFrame, aMayNeedRetry,
                                              &isEmpty)) {
               line->MarkDirty();
               dirtiedLine = true;
             }
             if (isEmpty) {
               WritingMode innerWM = innerReflowState.GetWritingMode();
               LogicalMargin innerMargin =
-                innerReflowState.ComputedLogicalMargin().ConvertTo(wm, innerWM);
-              aMargin->Include(innerMargin.BEnd(wm));
+                innerReflowState.ComputedLogicalMargin().ConvertTo(parentWM, innerWM);
+              aMargin->Include(innerMargin.BEnd(parentWM));
             }
           }
           if (outerReflowState != &aRS) {
             delete const_cast<nsHTMLReflowState*>(outerReflowState);
           }
         }
         if (!isEmpty) {
           if (!setBlockIsEmpty && aBlockIsEmpty) {
--- a/layout/generic/nsBlockReflowContext.h
+++ b/layout/generic/nsBlockReflowContext.h
@@ -49,37 +49,39 @@ public:
     return mMetrics.mCarriedOutBottomMargin;
   }
 
   const nsHTMLReflowMetrics& GetMetrics() const {
     return mMetrics;
   }
 
   /**
-   * Computes the collapsed block-start margin for a block whose reflow state
-   * is in aRS.
-   * The computed margin is added into aMargin.
+   * Computes the collapsed block-start margin (in the context's parent's
+   * writing mode) for a block whose reflow state is in aRS.
+   * The computed margin is added into aMargin, whose writing mode is the
+   * parent's mode as found in mMetrics.GetWritingMode(); note this may not be
+   * the block's own writing mode as found in aRS.
    * If aClearanceFrame is null then this is the first optimistic pass which
    * shall assume that no frames have clearance, and we clear the HasClearance
    * on all frames encountered.
    * If non-null, this is the second pass and the caller has decided
    * aClearanceFrame needs clearance (and we will therefore stop collapsing
    * there); also, this function is responsible for marking it with
    * SetHasClearance.
    * If in the optimistic pass any frame is encountered that might possibly
    * need clearance (i.e., if we really needed the optimism assumption) then
    * we set aMayNeedRetry to true.
    * We return true if we changed the clearance state of any line and marked it
    * dirty.
    */
-  static bool ComputeCollapsedBStartMargin(const nsHTMLReflowState& aRS,
-                                           nsCollapsingMargin* aMargin,
-                                           nsIFrame* aClearanceFrame,
-                                           bool* aMayNeedRetry,
-                                           bool* aIsEmpty = nullptr);
+  bool ComputeCollapsedBStartMargin(const nsHTMLReflowState& aRS,
+                                    nsCollapsingMargin* aMargin,
+                                    nsIFrame* aClearanceFrame,
+                                    bool* aMayNeedRetry,
+                                    bool* aIsEmpty = nullptr);
 
 protected:
   nsPresContext* mPresContext;
   const nsHTMLReflowState& mOuterReflowState;
 
   nsIFrame* mFrame;
   mozilla::LogicalRect mSpace;
 
--- a/layout/generic/nsBulletFrame.cpp
+++ b/layout/generic/nsBulletFrame.cpp
@@ -8,16 +8,17 @@
 #include "nsBulletFrame.h"
 
 #include "gfx2DGlue.h"
 #include "gfxUtils.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/PathHelpers.h"
 #include "mozilla/MathAlgorithms.h"
 #include "nsCOMPtr.h"
+#include "nsFontMetrics.h"
 #include "nsGkAtoms.h"
 #include "nsGenericHTMLElement.h"
 #include "nsAttrValueInlines.h"
 #include "nsPresContext.h"
 #include "nsIPresShell.h"
 #include "nsIDocument.h"
 #include "nsRenderingContext.h"
 #include "nsDisplayList.h"
@@ -423,26 +424,25 @@ nsBulletFrame::PaintBullet(nsRenderingCo
 
   default:
     aRenderingContext.ThebesContext()->SetColor(
                         nsLayoutUtils::GetColor(this, eCSSProperty_color));
 
     nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm),
                                           GetFontSizeInflation());
     GetListItemText(text);
-    aRenderingContext.SetFont(fm);
     nscoord ascent = fm->MaxAscent();
     aPt.MoveBy(padding.left, padding.top);
     aPt.y = NSToCoordRound(nsLayoutUtils::GetSnappedBaselineY(
             this, aRenderingContext.ThebesContext(), aPt.y, ascent));
     nsPresContext* presContext = PresContext();
     if (!presContext->BidiEnabled() && HasRTLChars(text)) {
       presContext->SetBidiEnabled();
     }
-    nsLayoutUtils::DrawString(this, &aRenderingContext,
+    nsLayoutUtils::DrawString(this, *fm, &aRenderingContext,
                               text.get(), text.Length(), aPt);
     break;
   }
 }
 
 int32_t
 nsBulletFrame::SetListItemOrdinal(int32_t aNextOrdinal,
                                   bool* aChanged,
@@ -596,19 +596,18 @@ nsBulletFrame::GetDesiredSize(nsPresCont
         aMetrics.SetBlockStartAscent(bulletSize + mPadding.BEnd(wm));
       }
       AppendSpacingToPadding(fm);
       break;
 
     default:
       GetListItemText(text);
       finalSize.BSize(wm) = fm->MaxHeight();
-      aRenderingContext->SetFont(fm);
       finalSize.ISize(wm) =
-        nsLayoutUtils::GetStringWidth(this, aRenderingContext,
+        nsLayoutUtils::GetStringWidth(this, aRenderingContext, *fm,
                                       text.get(), text.Length());
       aMetrics.SetBlockStartAscent(fm->MaxAscent());
       break;
   }
   aMetrics.SetSize(wm, finalSize);
 }
 
 void
@@ -857,17 +856,19 @@ nsBulletFrame::GetLogicalBaseline(Writin
 
 void
 nsBulletFrame::GetSpokenText(nsAString& aText)
 {
   CounterStyle* style = StyleList()->GetCounterStyle();
   bool isBullet;
   style->GetSpokenCounterText(mOrdinal, GetWritingMode(), aText, isBullet);
   if (isBullet) {
-    aText.Append(' ');
+    if (!style->IsNone()) {
+      aText.Append(' ');
+    }
   } else {
     nsAutoString prefix, suffix;
     style->GetPrefix(prefix);
     style->GetSuffix(suffix);
     aText = prefix + aText + suffix;
   }
 }
 
--- a/layout/generic/nsHTMLReflowState.cpp
+++ b/layout/generic/nsHTMLReflowState.cpp
@@ -2162,17 +2162,17 @@ nsHTMLReflowState::InitConstraints(nsPre
       NS_ASSERTION(ComputedBSize() == NS_UNCONSTRAINEDSIZE ||
                    ComputedBSize() >= 0, "Bogus block-size");
 
       // Exclude inline tables and flex items from the block margin calculations
       if (isBlock &&
           !IsSideCaption(frame, mStyleDisplay) &&
           mStyleDisplay->mDisplay != NS_STYLE_DISPLAY_INLINE_TABLE &&
           !flexContainerFrame) {
-        CalculateBlockSideMargins(AvailableWidth(), ComputedWidth(), aFrameType);
+        CalculateBlockSideMargins(AvailableISize(), ComputedISize(), aFrameType);
       }
     }
   }
 }
 
 static void
 UpdateProp(FrameProperties& aProps,
            const FramePropertyDescriptor* aProperty,
@@ -2308,105 +2308,134 @@ nsCSSOffsetState::InitOffsets(nscoord aH
 // This code enforces section 10.3.3 of the CSS2 spec for this formula:
 //
 // 'margin-left' + 'border-left-width' + 'padding-left' + 'width' +
 //   'padding-right' + 'border-right-width' + 'margin-right'
 //   = width of containing block 
 //
 // Note: the width unit is not auto when this is called
 void
-nsHTMLReflowState::CalculateBlockSideMargins(nscoord aAvailWidth,
-                                             nscoord aComputedWidth,
+nsHTMLReflowState::CalculateBlockSideMargins(nscoord aAvailISize,
+                                             nscoord aComputedISize,
                                              nsIAtom* aFrameType)
 {
-  NS_WARN_IF_FALSE(NS_UNCONSTRAINEDSIZE != aComputedWidth &&
-                   NS_UNCONSTRAINEDSIZE != aAvailWidth,
-                   "have unconstrained width; this should only result from "
-                   "very large sizes, not attempts at intrinsic width "
+  NS_WARN_IF_FALSE(NS_UNCONSTRAINEDSIZE != aComputedISize &&
+                   NS_UNCONSTRAINEDSIZE != aAvailISize,
+                   "have unconstrained inline-size; this should only result from "
+                   "very large sizes, not attempts at intrinsic inline-size "
                    "calculation");
 
-  nscoord sum = ComputedPhysicalMargin().left + ComputedPhysicalBorderPadding().left +
-    aComputedWidth + ComputedPhysicalBorderPadding().right + ComputedPhysicalMargin().right;
-  if (sum == aAvailWidth)
+  nscoord sum = ComputedLogicalMargin().IStartEnd(mWritingMode) +
+    ComputedLogicalBorderPadding().IStartEnd(mWritingMode) + aComputedISize;
+  if (sum == aAvailISize) {
     // The sum is already correct
     return;
+  }
 
-  // Determine the left and right margin values. The width value
+  // Determine the start and end margin values. The isize value
   // remains constant while we do this.
 
   // Calculate how much space is available for margins
-  nscoord availMarginSpace = aAvailWidth - sum;
+  nscoord availMarginSpace = aAvailISize - sum;
+
+  LogicalMargin margin = ComputedLogicalMargin();
 
   // If the available margin space is negative, then don't follow the
   // usual overconstraint rules.
   if (availMarginSpace < 0) {
     if (mCBReflowState &&
-        mCBReflowState->mStyleVisibility->mDirection == NS_STYLE_DIRECTION_RTL) {
-      ComputedPhysicalMargin().left += availMarginSpace;
+        mCBReflowState->GetWritingMode().IsBidiLTR() !=
+          mWritingMode.IsBidiLTR()) {
+      margin.IStart(mWritingMode) += availMarginSpace;
     } else {
-      ComputedPhysicalMargin().right += availMarginSpace;
+      margin.IEnd(mWritingMode) += availMarginSpace;
     }
+    SetComputedLogicalMargin(margin);
     return;
   }
 
   // The css2 spec clearly defines how block elements should behave
   // in section 10.3.3.
-  bool isAutoLeftMargin =
-    eStyleUnit_Auto == mStyleMargin->mMargin.GetLeftUnit();
-  bool isAutoRightMargin =
-    eStyleUnit_Auto == mStyleMargin->mMargin.GetRightUnit();
-  if (!isAutoLeftMargin && !isAutoRightMargin) {
+  bool isAutoStartMargin, isAutoEndMargin;
+  const nsStyleSides& styleSides = mStyleMargin->mMargin;
+  if (mWritingMode.IsVertical()) {
+    if (mWritingMode.IsBidiLTR()) {
+      isAutoStartMargin = eStyleUnit_Auto == styleSides.GetTopUnit();
+      isAutoEndMargin = eStyleUnit_Auto == styleSides.GetBottomUnit();
+    } else {
+      isAutoStartMargin = eStyleUnit_Auto == styleSides.GetBottomUnit();
+      isAutoEndMargin = eStyleUnit_Auto == styleSides.GetTopUnit();
+    }
+  } else {
+    if (mWritingMode.IsBidiLTR()) {
+      isAutoStartMargin = eStyleUnit_Auto == styleSides.GetLeftUnit();
+      isAutoEndMargin = eStyleUnit_Auto == styleSides.GetRightUnit();
+    } else {
+      isAutoStartMargin = eStyleUnit_Auto == styleSides.GetRightUnit();
+      isAutoEndMargin = eStyleUnit_Auto == styleSides.GetLeftUnit();
+    }
+  }
+  if (!isAutoStartMargin && !isAutoEndMargin) {
     // Neither margin is 'auto' so we're over constrained. Use the
     // 'direction' property of the parent to tell which margin to
     // ignore
     // First check if there is an HTML alignment that we should honor
     const nsHTMLReflowState* prs = parentReflowState;
     if (aFrameType == nsGkAtoms::tableFrame) {
       NS_ASSERTION(prs->frame->GetType() == nsGkAtoms::tableOuterFrame,
                    "table not inside outer table");
       // Center the table within the outer table based on the alignment
       // of the outer table's parent.
       prs = prs->parentReflowState;
     }
     if (prs &&
         (prs->mStyleText->mTextAlign == NS_STYLE_TEXT_ALIGN_MOZ_LEFT ||
          prs->mStyleText->mTextAlign == NS_STYLE_TEXT_ALIGN_MOZ_CENTER ||
          prs->mStyleText->mTextAlign == NS_STYLE_TEXT_ALIGN_MOZ_RIGHT)) {
-      isAutoLeftMargin =
-        prs->mStyleText->mTextAlign != NS_STYLE_TEXT_ALIGN_MOZ_LEFT;
-      isAutoRightMargin =
-        prs->mStyleText->mTextAlign != NS_STYLE_TEXT_ALIGN_MOZ_RIGHT;
+      if (prs->mWritingMode.IsBidiLTR()) {
+        isAutoStartMargin =
+          prs->mStyleText->mTextAlign != NS_STYLE_TEXT_ALIGN_MOZ_LEFT;
+        isAutoEndMargin =
+          prs->mStyleText->mTextAlign != NS_STYLE_TEXT_ALIGN_MOZ_RIGHT;
+      } else {
+        isAutoStartMargin =
+          prs->mStyleText->mTextAlign != NS_STYLE_TEXT_ALIGN_MOZ_RIGHT;
+        isAutoEndMargin =
+          prs->mStyleText->mTextAlign != NS_STYLE_TEXT_ALIGN_MOZ_LEFT;
+      }
     }
     // Otherwise apply the CSS rules, and ignore one margin by forcing
     // it to 'auto', depending on 'direction'.
     else if (mCBReflowState &&
-             NS_STYLE_DIRECTION_RTL == mCBReflowState->mStyleVisibility->mDirection) {
-      isAutoLeftMargin = true;
+             mCBReflowState->GetWritingMode().IsBidiLTR() !=
+               mWritingMode.IsBidiLTR()) {
+      isAutoStartMargin = true;
     }
     else {
-      isAutoRightMargin = true;
+      isAutoEndMargin = true;
     }
   }
 
   // Logic which is common to blocks and tables
   // The computed margins need not be zero because the 'auto' could come from
   // overconstraint or from HTML alignment so values need to be accumulated
 
-  if (isAutoLeftMargin) {
-    if (isAutoRightMargin) {
+  if (isAutoStartMargin) {
+    if (isAutoEndMargin) {
       // Both margins are 'auto' so the computed addition should be equal
-      nscoord forLeft = availMarginSpace / 2;
-      ComputedPhysicalMargin().left  += forLeft;
-      ComputedPhysicalMargin().right += availMarginSpace - forLeft;
+      nscoord forStart = availMarginSpace / 2;
+      margin.IStart(mWritingMode) += forStart;
+      margin.IEnd(mWritingMode) += availMarginSpace - forStart;
     } else {
-      ComputedPhysicalMargin().left += availMarginSpace;
+      margin.IStart(mWritingMode) += availMarginSpace;
     }
-  } else if (isAutoRightMargin) {
-    ComputedPhysicalMargin().right += availMarginSpace;
+  } else if (isAutoEndMargin) {
+    margin.IEnd(mWritingMode) += availMarginSpace;
   }
+  SetComputedLogicalMargin(margin);
 }
 
 #define NORMAL_LINE_HEIGHT_FACTOR 1.2f    // in term of emHeight 
 // For "normal" we use the font's normal line height (em height + leading).
 // If both internal leading and  external leading specified by font itself
 // are zeros, we should compensate this by creating extra (external) leading 
 // in eCompensateLeading mode. This is necessary because without this 
 // compensation, normal line height might looks too tight. 
--- a/layout/generic/nsHTMLReflowState.h
+++ b/layout/generic/nsHTMLReflowState.h
@@ -112,23 +112,30 @@ public:
   const nsMargin& ComputedPhysicalPadding() const { return mComputedPadding; }
 
   // We may need to eliminate the (few) users of these writable-reference accessors
   // as part of migrating to logical coordinates.
   nsMargin& ComputedPhysicalMargin() { return mComputedMargin; }
   nsMargin& ComputedPhysicalBorderPadding() { return mComputedBorderPadding; }
   nsMargin& ComputedPhysicalPadding() { return mComputedPadding; }
 
-  LogicalMargin ComputedLogicalMargin() const
+  const LogicalMargin ComputedLogicalMargin() const
     { return LogicalMargin(mWritingMode, mComputedMargin); }
-  LogicalMargin ComputedLogicalBorderPadding() const
+  const LogicalMargin ComputedLogicalBorderPadding() const
     { return LogicalMargin(mWritingMode, mComputedBorderPadding); }
-  LogicalMargin ComputedLogicalPadding() const
+  const LogicalMargin ComputedLogicalPadding() const
     { return LogicalMargin(mWritingMode, mComputedPadding); }
 
+  void SetComputedLogicalMargin(const LogicalMargin& aMargin)
+    { mComputedMargin = aMargin.GetPhysicalMargin(mWritingMode); }
+  void SetComputedLogicalBorderPadding(const LogicalMargin& aMargin)
+    { mComputedBorderPadding = aMargin.GetPhysicalMargin(mWritingMode); }
+  void SetComputedLogicalPadding(const LogicalMargin& aMargin)
+    { mComputedPadding = aMargin.GetPhysicalMargin(mWritingMode); }
+
   WritingMode GetWritingMode() const { return mWritingMode; }
 
 protected:
   // cached copy of the frame's writing-mode, for logical coordinates
   WritingMode      mWritingMode;
 
   // These are PHYSICAL coordinates (for now).
   // Will probably become logical in due course.
@@ -798,15 +805,15 @@ protected:
   void ComputeMinMaxValues(nscoord                  aContainingBlockWidth,
                            nscoord                  aContainingBlockHeight,
                            const nsHTMLReflowState* aContainingBlockRS);
 
   void CalculateHorizBorderPaddingMargin(nscoord aContainingBlockWidth,
                                          nscoord* aInsideBoxSizing,
                                          nscoord* aOutsideBoxSizing);
 
-  void CalculateBlockSideMargins(nscoord aAvailWidth,
-                                 nscoord aComputedWidth,
+  void CalculateBlockSideMargins(nscoord aAvailISize,
+                                 nscoord aComputedISize,
                                  nsIAtom* aFrameType);
 };
 
 #endif /* nsHTMLReflowState_h___ */
 
--- a/layout/generic/nsImageFrame.cpp
+++ b/layout/generic/nsImageFrame.cpp
@@ -12,16 +12,17 @@
 #include "mozilla/DebugOnly.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/Helpers.h"
 #include "mozilla/gfx/PathHelpers.h"
 #include "mozilla/MouseEvents.h"
 
 #include "nsCOMPtr.h"
+#include "nsFontMetrics.h"
 #include "nsIImageLoadingContent.h"
 #include "nsString.h"
 #include "nsPrintfCString.h"
 #include "nsPresContext.h"
 #include "nsRenderingContext.h"
 #include "nsIPresShell.h"
 #include "nsGkAtoms.h"
 #include "nsIDocument.h"
@@ -1007,38 +1008,39 @@ nsImageFrame::ReflowCallbackCanceled()
 // The number of characters that fit within the maximum width are returned in
 // aMaxFit. NOTE: it is assumed that the fontmetrics have already been selected
 // into the rendering context before this is called (for performance). MMP
 nscoord
 nsImageFrame::MeasureString(const char16_t*     aString,
                             int32_t              aLength,
                             nscoord              aMaxWidth,
                             uint32_t&            aMaxFit,
-                            nsRenderingContext& aContext)
+                            nsRenderingContext& aContext,
+                            nsFontMetrics& aFontMetrics)
 {
   nscoord totalWidth = 0;
-  aContext.FontMetrics()->SetTextRunRTL(false);
-  nscoord spaceWidth = aContext.FontMetrics()->SpaceWidth();
+  aFontMetrics.SetTextRunRTL(false);
+  nscoord spaceWidth = aFontMetrics.SpaceWidth();
 
   aMaxFit = 0;
   while (aLength > 0) {
     // Find the next place we can line break
     uint32_t  len = aLength;
     bool      trailingSpace = false;
     for (int32_t i = 0; i < aLength; i++) {
       if (dom::IsSpaceCharacter(aString[i]) && (i > 0)) {
         len = i;  // don't include the space when measuring
         trailingSpace = true;
         break;
       }
     }
   
     // Measure this chunk of text, and see if it fits
     nscoord width =
-      nsLayoutUtils::GetStringWidth(this, &aContext, aString, len);
+      nsLayoutUtils::GetStringWidth(this, &aContext, aFontMetrics, aString, len);
     bool    fits = (totalWidth + width) <= aMaxWidth;
 
     // If it fits on the line, or it's the first word we've processed then
     // include it
     if (fits || (0 == totalWidth)) {
       // New piece fits
       totalWidth += width;
 
@@ -1075,17 +1077,16 @@ nsImageFrame::DisplayAltText(nsPresConte
                              const nsString&      aAltText,
                              const nsRect&        aRect)
 {
   // Set font and color
   aRenderingContext.ThebesContext()->SetColor(StyleColor()->mColor);
   nsRefPtr<nsFontMetrics> fm;
   nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm),
     nsLayoutUtils::FontSizeInflationFor(this));
-  aRenderingContext.SetFont(fm);
 
   // Format the text to display within the formatting rect
 
   nscoord maxAscent = fm->MaxAscent();
   nscoord maxDescent = fm->MaxDescent();
   nscoord height = fm->MaxHeight();
 
   // XXX It would be nice if there was a way to have the font metrics tell
@@ -1100,37 +1101,37 @@ nsImageFrame::DisplayAltText(nsPresConte
   }
 
   // Always show the first line, even if we have to clip it below
   bool firstLine = true;
   while ((strLen > 0) && (firstLine || (y + maxDescent) < aRect.YMost())) {
     // Determine how much of the text to display on this line
     uint32_t  maxFit;  // number of characters that fit
     nscoord strWidth = MeasureString(str, strLen, aRect.width, maxFit,
-                                     aRenderingContext);
+                                     aRenderingContext, *fm);
     
     // Display the text
     nsresult rv = NS_ERROR_FAILURE;
 
     if (aPresContext->BidiEnabled()) {
       const nsStyleVisibility* vis = StyleVisibility();
       if (vis->mDirection == NS_STYLE_DIRECTION_RTL)
         rv = nsBidiPresUtils::RenderText(str, maxFit, NSBIDI_RTL,
                                          aPresContext, aRenderingContext,
-                                         aRenderingContext,
+                                         aRenderingContext, *fm,
                                          aRect.XMost() - strWidth, y + maxAscent);
       else
         rv = nsBidiPresUtils::RenderText(str, maxFit, NSBIDI_LTR,
                                          aPresContext, aRenderingContext,
-                                         aRenderingContext,
+                                         aRenderingContext, *fm,
                                          aRect.x, y + maxAscent);
     }
     if (NS_FAILED(rv)) {
       nsLayoutUtils::DrawUniDirString(str, maxFit,
-                                      nsPoint(aRect.x, y + maxAscent),
+                                      nsPoint(aRect.x, y + maxAscent), *fm,
                                       aRenderingContext);
     }
 
     // Move to the next line
     str += maxFit;
     strLen -= maxFit;
     y += height;
     firstLine = false;
--- a/layout/generic/nsImageFrame.h
+++ b/layout/generic/nsImageFrame.h
@@ -16,16 +16,17 @@
 
 #include "nsDisplayList.h"
 #include "imgIContainer.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/DebugOnly.h"
 #include "nsIReflowCallback.h"
 #include "nsTObserverArray.h"
 
+class nsFontMetrics;
 class nsImageMap;
 class nsIURI;
 class nsILoadGroup;
 struct nsHTMLReflowState;
 class nsHTMLReflowMetrics;
 class nsDisplayImage;
 class nsPresContext;
 class nsImageFrame;
@@ -200,17 +201,18 @@ protected:
    * @param out aMaxFit length of the string that fits within aMaxWidth
    *            in PRUnichars
    * @return width of the string that fits within aMaxWidth
    */
   nscoord MeasureString(const char16_t*     aString,
                         int32_t              aLength,
                         nscoord              aMaxWidth,
                         uint32_t&            aMaxFit,
-                        nsRenderingContext& aContext);
+                        nsRenderingContext& aContext,
+                        nsFontMetrics&      aFontMetrics);
 
   void DisplayAltText(nsPresContext*      aPresContext,
                       nsRenderingContext& aRenderingContext,
                       const nsString&      aAltText,
                       const nsRect&        aRect);
 
   void PaintImage(nsRenderingContext& aRenderingContext, nsPoint aPt,
                   const nsRect& aDirtyRect, imgIContainer* aImage,
--- a/layout/generic/nsLineLayout.cpp
+++ b/layout/generic/nsLineLayout.cpp
@@ -7,16 +7,17 @@
 
 // This has to be defined before nsLineLayout.h is included, because
 // nsLineLayout.h has a #include for plarena.h, which needs this defined:
 #define PL_ARENA_CONST_ALIGN_MASK (sizeof(void*)-1)
 #include "nsLineLayout.h"
 
 #include "SVGTextFrame.h"
 #include "nsBlockFrame.h"
+#include "nsFontMetrics.h"
 #include "nsStyleConsts.h"
 #include "nsContainerFrame.h"
 #include "nsFloatManager.h"
 #include "nsStyleContext.h"
 #include "nsPresContext.h"
 #include "nsRenderingContext.h"
 #include "nsGkAtoms.h"
 #include "nsIContent.h"
@@ -1096,26 +1097,26 @@ nsLineLayout::AllowForStartMargin(PerFra
   if ((pfd->mFrame->GetPrevContinuation() ||
        pfd->mFrame->FrameIsNonFirstInIBSplit()) &&
       aReflowState.mStyleBorder->mBoxDecorationBreak ==
         NS_STYLE_BOX_DECORATION_BREAK_SLICE) {
     // Zero this out so that when we compute the max-element-width of
     // the frame we will properly avoid adding in the starting margin.
     pfd->mMargin.IStart(frameWM) = 0;
   } else {
-    NS_WARN_IF_FALSE(NS_UNCONSTRAINEDSIZE != aReflowState.AvailableWidth(),
-                     "have unconstrained width; this should only result from "
-                     "very large sizes, not attempts at intrinsic width "
-                     "calculation");
-    if (NS_UNCONSTRAINEDSIZE == aReflowState.ComputedWidth()) {
+    NS_WARN_IF_FALSE(NS_UNCONSTRAINEDSIZE != aReflowState.AvailableISize(),
+                     "have unconstrained inline-size; this should only result "
+                     "from very large sizes, not attempts at intrinsic "
+                     "inline-size calculation");
+    if (NS_UNCONSTRAINEDSIZE == aReflowState.ComputedISize()) {
       // For inline-ish and text-ish things (which don't compute widths
-      // in the reflow state), adjust available width to account for the
+      // in the reflow state), adjust available inline-size to account for the
       // start margin. The end margin will be accounted for when we
       // finish flowing the frame.
-      aReflowState.AvailableWidth() -= pfd->mMargin.IStart(frameWM);
+      aReflowState.AvailableISize() -= pfd->mMargin.IStart(frameWM);
     }
   }
 }
 
 nscoord
 nsLineLayout::GetCurrentFrameInlineDistanceFromBlock()
 {
   PerSpanData* psd;
@@ -1584,17 +1585,16 @@ nsLineLayout::VerticalAlignFrames(PerSpa
   nsIFrame* spanFrame = spanFramePFD->mFrame;
 
   // Get the parent frame's font for all of the frames in this span
   nsRefPtr<nsFontMetrics> fm;
   float inflation =
     GetInflationForBlockDirAlignment(spanFrame, mInflationMinFontSize);
   nsLayoutUtils::GetFontMetricsForFrame(spanFrame, getter_AddRefs(fm),
                                         inflation);
-  mBlockReflowState->rendContext->SetFont(fm);
 
   bool preMode = mStyleText->WhiteSpaceIsSignificant();
 
   // See if the span is an empty continuation. It's an empty continuation iff:
   // - it has a prev-in-flow
   // - it has no next in flow
   // - it's zero sized
   WritingMode frameWM = spanFramePFD->mFrame->GetWritingMode();
--- a/layout/generic/nsPageFrame.cpp
+++ b/layout/generic/nsPageFrame.cpp
@@ -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 "nsPageFrame.h"
 
 #include "mozilla/gfx/2D.h"
 #include "nsDeviceContext.h"
+#include "nsFontMetrics.h"
 #include "nsLayoutUtils.h"
 #include "nsPresContext.h"
 #include "nsRenderingContext.h"
 #include "nsGkAtoms.h"
 #include "nsIPresShell.h"
 #include "nsPageContentFrame.h"
 #include "nsDisplayList.h"
 #include "nsLayoutUtils.h" // for function BinarySearchForPosition
@@ -231,22 +232,24 @@ nsPageFrame::ProcessSpecialCodes(const n
     char16_t * uStr = nsTextFormatter::smprintf(mPD->mPageNumFormat.get(), mTotNumPages);
     aNewStr.ReplaceSubstring(kPageTotal.get(), uStr);
     nsMemory::Free(uStr);
   }
 }
 
 
 //------------------------------------------------------------------------------
-nscoord nsPageFrame::GetXPosition(nsRenderingContext& aRenderingContext, 
+nscoord nsPageFrame::GetXPosition(nsRenderingContext& aRenderingContext,
+                                  nsFontMetrics&       aFontMetrics,
                                   const nsRect&        aRect, 
                                   int32_t              aJust,
                                   const nsString&      aStr)
 {
   nscoord width = nsLayoutUtils::GetStringWidth(this, &aRenderingContext,
+                                                aFontMetrics,
                                                 aStr.get(), aStr.Length());
 
   nscoord x = aRect.x;
   switch (aJust) {
     case nsIPrintSettings::kJustLeft:
       x += mPD->mEdgePaperMargin.left;
       break;
 
@@ -268,16 +271,17 @@ nscoord nsPageFrame::GetXPosition(nsRend
 // @param aStrLeft - string for the left header or footer; can be empty
 // @param aStrCenter - string for the center header or footer; can be empty
 // @param aStrRight - string for the right header or footer; can be empty
 // @param aRect - the rect of the page
 // @param aAscent - the ascent of the font
 // @param aHeight - the height of the font
 void
 nsPageFrame::DrawHeaderFooter(nsRenderingContext& aRenderingContext,
+                              nsFontMetrics&       aFontMetrics,
                               nsHeaderFooterEnum   aHeaderFooter,
                               const nsString&      aStrLeft,
                               const nsString&      aStrCenter,
                               const nsString&      aStrRight,
                               const nsRect&        aRect,
                               nscoord              aAscent,
                               nscoord              aHeight)
 {
@@ -285,43 +289,44 @@ nsPageFrame::DrawHeaderFooter(nsRenderin
   if (!aStrLeft.IsEmpty()) numStrs++;
   if (!aStrCenter.IsEmpty()) numStrs++;
   if (!aStrRight.IsEmpty()) numStrs++;
 
   if (numStrs == 0) return;
   nscoord strSpace = aRect.width / numStrs;
 
   if (!aStrLeft.IsEmpty()) {
-    DrawHeaderFooter(aRenderingContext, aHeaderFooter,
+    DrawHeaderFooter(aRenderingContext, aFontMetrics, aHeaderFooter,
                      nsIPrintSettings::kJustLeft, aStrLeft, aRect, aAscent,
                      aHeight, strSpace);
   }
   if (!aStrCenter.IsEmpty()) {
-    DrawHeaderFooter(aRenderingContext, aHeaderFooter,
+    DrawHeaderFooter(aRenderingContext, aFontMetrics, aHeaderFooter,
                      nsIPrintSettings::kJustCenter, aStrCenter, aRect, aAscent,
                      aHeight, strSpace);
   }
   if (!aStrRight.IsEmpty()) {
-    DrawHeaderFooter(aRenderingContext, aHeaderFooter,
+    DrawHeaderFooter(aRenderingContext, aFontMetrics, aHeaderFooter,
                      nsIPrintSettings::kJustRight, aStrRight, aRect, aAscent,
                      aHeight, strSpace);
   }
 }
 
 // Draw a header or footer string
 // @param aRenderingContext - rendering context to draw into
 // @param aHeaderFooter - indicates whether it is a header or footer
 // @param aJust - indicates where the string is located within the header/footer
 // @param aStr - the string to be drawn
 // @param aRect - the rect of the page
 // @param aHeight - the height of the font
 // @param aAscent - the ascent of the font
 // @param aWidth - available width for the string
 void
 nsPageFrame::DrawHeaderFooter(nsRenderingContext& aRenderingContext,
+                              nsFontMetrics&       aFontMetrics,
                               nsHeaderFooterEnum   aHeaderFooter,
                               int32_t              aJust,
                               const nsString&      aStr,
                               const nsRect&        aRect,
                               nscoord              aAscent,
                               nscoord              aHeight,
                               nscoord              aWidth)
 {
@@ -337,17 +342,18 @@ nsPageFrame::DrawHeaderFooter(nsRenderin
     int32_t textWidth = 0;
     const char16_t* text = str.get();
 
     int32_t len = (int32_t)str.Length();
     if (len == 0) {
       return; // bail is empty string
     }
     // find how much text fits, the "position" is the size of the available area
-    if (nsLayoutUtils::BinarySearchForPosition(&aRenderingContext, text, 0, 0, 0, len,
+    if (nsLayoutUtils::BinarySearchForPosition(&aRenderingContext, aFontMetrics,
+                                               text, 0, 0, 0, len,
                                 int32_t(contentWidth), indx, textWidth)) {
       if (indx < len-1 ) {
         // we can't fit in all the text
         if (indx > 3) {
           // But we can fit in at least 4 chars.  Show all but 3 of them, then
           // an ellipsis.
           // XXXbz for non-plane0 text, this may be cutting things in the
           // middle of a codepoint!  Also, we have no guarantees that the three
@@ -364,33 +370,35 @@ nsPageFrame::DrawHeaderFooter(nsRenderin
       return; // bail if couldn't find the correct length
     }
     
     if (HasRTLChars(str)) {
       PresContext()->SetBidiEnabled();
     }
 
     // cacl the x and y positions of the text
-    nscoord x = GetXPosition(aRenderingContext, aRect, aJust, str);
+    nscoord x = GetXPosition(aRenderingContext, aFontMetrics, aRect, aJust, str);
     nscoord y;
     if (aHeaderFooter == eHeader) {
       y = aRect.y + mPD->mEdgePaperMargin.top;
     } else {
       y = aRect.YMost() - aHeight - mPD->mEdgePaperMargin.bottom;
     }
 
     DrawTarget* drawTarget = aRenderingContext.GetDrawTarget();
     gfxContext* gfx = aRenderingContext.ThebesContext();
 
     // set up new clip and draw the text
     gfx->Save();
     gfx->Clip(NSRectToSnappedRect(aRect, PresContext()->AppUnitsPerDevPixel(),
                                   *drawTarget));
     aRenderingContext.ThebesContext()->SetColor(NS_RGB(0,0,0));
-    nsLayoutUtils::DrawString(this, &aRenderingContext, str.get(), str.Length(), nsPoint(x, y + aAscent));
+    nsLayoutUtils::DrawString(this, aFontMetrics, &aRenderingContext,
+                              str.get(), str.Length(),
+                              nsPoint(x, y + aAscent));
     gfx->Restore();
   }
 }
 
 /**
  * Remove all leaf display items that are not for descendants of
  * aBuilder->GetReferenceFrame() from aList.
  * @param aPage the page we're constructing the display list for
@@ -592,39 +600,37 @@ nsPageFrame::PaintHeaderFooter(nsRenderi
   // Get the FontMetrics to determine width.height of strings
   nsRefPtr<nsFontMetrics> fontMet;
   pc->DeviceContext()->GetMetricsFor(mPD->mHeadFootFont, nullptr,
                                      gfxFont::eHorizontal,
                                      pc->GetUserFontSet(),
                                      pc->GetTextPerfMetrics(),
                                      *getter_AddRefs(fontMet));
 
-  aRenderingContext.SetFont(fontMet);
-
   nscoord ascent = 0;
   nscoord visibleHeight = 0;
   if (fontMet) {
     visibleHeight = fontMet->MaxHeight();
     ascent = fontMet->MaxAscent();
   }
 
   // print document headers and footers
   nsXPIDLString headerLeft, headerCenter, headerRight;
   mPD->mPrintSettings->GetHeaderStrLeft(getter_Copies(headerLeft));
   mPD->mPrintSettings->GetHeaderStrCenter(getter_Copies(headerCenter));
   mPD->mPrintSettings->GetHeaderStrRight(getter_Copies(headerRight));
-  DrawHeaderFooter(aRenderingContext, eHeader,
+  DrawHeaderFooter(aRenderingContext, *fontMet, eHeader,
                    headerLeft, headerCenter, headerRight,
                    rect, ascent, visibleHeight);
 
   nsXPIDLString footerLeft, footerCenter, footerRight;
   mPD->mPrintSettings->GetFooterStrLeft(getter_Copies(footerLeft));
   mPD->mPrintSettings->GetFooterStrCenter(getter_Copies(footerCenter));
   mPD->mPrintSettings->GetFooterStrRight(getter_Copies(footerRight));
-  DrawHeaderFooter(aRenderingContext, eFooter,
+  DrawHeaderFooter(aRenderingContext, *fontMet, eFooter,
                    footerLeft, footerCenter, footerRight,
                    rect, ascent, visibleHeight);
 }
 
 void
 nsPageFrame::SetSharedPageData(nsSharedPageData* aPD) 
 { 
   mPD = aPD;
--- a/layout/generic/nsPageFrame.h
+++ b/layout/generic/nsPageFrame.h
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #ifndef nsPageFrame_h___
 #define nsPageFrame_h___
 
 #include "mozilla/Attributes.h"
 #include "nsContainerFrame.h"
 #include "nsLeafFrame.h"
 
+class nsFontMetrics;
 class nsSharedPageData;
 
 // Page frame class used by the simple page sequence frame
 class nsPageFrame MOZ_FINAL : public nsContainerFrame {
 
 public:
   NS_DECL_FRAMEARENA_HELPERS
 
@@ -60,31 +61,34 @@ protected:
   explicit nsPageFrame(nsStyleContext* aContext);
   virtual ~nsPageFrame();
 
   typedef enum {
     eHeader,
     eFooter
   } nsHeaderFooterEnum;
 
-  nscoord GetXPosition(nsRenderingContext& aRenderingContext, 
+  nscoord GetXPosition(nsRenderingContext& aRenderingContext,
+                       nsFontMetrics&       aFontMetrics,
                        const nsRect&        aRect, 
                        int32_t              aJust,
                        const nsString&      aStr);
 
   void DrawHeaderFooter(nsRenderingContext& aRenderingContext,
+                        nsFontMetrics&       aFontMetrics,
                         nsHeaderFooterEnum   aHeaderFooter,
                         int32_t              aJust,
                         const nsString&      sStr,
                         const nsRect&        aRect,
                         nscoord              aHeight,
                         nscoord              aAscent,
                         nscoord              aWidth);
 
   void DrawHeaderFooter(nsRenderingContext& aRenderingContext,
+                        nsFontMetrics&       aFontMetrics,
                         nsHeaderFooterEnum   aHeaderFooter,
                         const nsString&      aStrLeft,
                         const nsString&      aStrRight,
                         const nsString&      aStrCenter,
                         const nsRect&        aRect,
                         nscoord              aAscent,
                         nscoord              aHeight);
 
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -12,16 +12,17 @@
 #include "mozilla/Likely.h"
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/TextEvents.h"
 #include "mozilla/BinarySearch.h"
 
 #include "nsCOMPtr.h"
 #include "nsBlockFrame.h"
 #include "nsCRT.h"
+#include "nsFontMetrics.h"
 #include "nsSplittableFrame.h"
 #include "nsLineLayout.h"
 #include "nsString.h"
 #include "nsUnicharUtils.h"
 #include "nsPresContext.h"
 #include "nsIContent.h"
 #include "nsStyleConsts.h"
 #include "nsStyleContext.h"
--- a/layout/mathml/nsMathMLChar.cpp
+++ b/layout/mathml/nsMathMLChar.cpp
@@ -1,21 +1,23 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsMathMLChar.h"
 
+#include "gfxTextRun.h"
 #include "gfxUtils.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/MathAlgorithms.h"
 
 #include "nsCOMPtr.h"
 #include "nsDeviceContext.h"
+#include "nsFontMetrics.h"
 #include "nsIFrame.h"
 #include "nsLayoutUtils.h"
 #include "nsPresContext.h"
 #include "nsStyleContext.h"
 #include "nsUnicharUtils.h"
 #include "nsRenderingContext.h"
 
 #include "mozilla/Preferences.h"
--- a/layout/mathml/nsMathMLContainerFrame.cpp
+++ b/layout/mathml/nsMathMLContainerFrame.cpp
@@ -48,22 +48,22 @@ nsMathMLContainerFrame::ReflowError(nsRe
   // clear all other flags and record that there is an error with this frame
   mEmbellishData.flags = 0;
   mPresentationData.flags = NS_MATHML_ERROR;
 
   ///////////////
   // Set font
   nsRefPtr<nsFontMetrics> fm;
   nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm));
-  aRenderingContext.SetFont(fm);
 
   // bounding metrics
   nsAutoString errorMsg; errorMsg.AssignLiteral("invalid-markup");
   mBoundingMetrics =
-    aRenderingContext.GetBoundingMetrics(errorMsg.get(), errorMsg.Length());
+    nsLayoutUtils::AppUnitBoundsOfString(errorMsg.get(), errorMsg.Length(),
+                                         *fm, aRenderingContext);
 
   // reflow metrics
   WritingMode wm = aDesiredSize.GetWritingMode();
   aDesiredSize.SetBlockStartAscent(fm->MaxAscent());
   nscoord descent = fm->MaxDescent();
   aDesiredSize.BSize(wm) = aDesiredSize.BlockStartAscent() + descent;
   aDesiredSize.ISize(wm) = mBoundingMetrics.width;
 
@@ -91,34 +91,31 @@ public:
 };
 
 void nsDisplayMathMLError::Paint(nsDisplayListBuilder* aBuilder,
                                  nsRenderingContext* aCtx)
 {
   // Set color and font ...
   nsRefPtr<nsFontMetrics> fm;
   nsLayoutUtils::GetFontMetricsForFrame(mFrame, getter_AddRefs(fm));
-  aCtx->SetFont(fm);
 
   nsPoint pt = ToReferenceFrame();
   int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
   DrawTarget* drawTarget = aCtx->GetDrawTarget();
   Rect rect = NSRectToSnappedRect(nsRect(pt, mFrame->GetSize()),
                                   appUnitsPerDevPixel,
                                   *drawTarget);
   ColorPattern red(ToDeviceColor(Color(1.f, 0.f, 0.f, 1.f)));
   drawTarget->FillRect(rect, red);
 
   aCtx->ThebesContext()->SetColor(NS_RGB(255,255,255));
-  nscoord ascent = aCtx->FontMetrics()->MaxAscent();
+  nscoord ascent = fm->MaxAscent();
   NS_NAMED_LITERAL_STRING(errorMsg, "invalid-markup");
-  nsLayoutUtils::DrawUniDirString(errorMsg.get(),
-                                  uint32_t(errorMsg.Length()),
-                                  nsPoint(pt.x, pt.y + ascent),
-                                  *aCtx);
+  nsLayoutUtils::DrawUniDirString(errorMsg.get(), uint32_t(errorMsg.Length()),
+                                  nsPoint(pt.x, pt.y + ascent), *fm, *aCtx);
 }
 
 /* /////////////
  * nsIMathMLFrame - support methods for stretchy elements
  * =============================================================================
  */
 
 static bool
--- a/layout/mathml/nsMathMLFrame.cpp
+++ b/layout/mathml/nsMathMLFrame.cpp
@@ -167,25 +167,21 @@ nsMathMLFrame::GetPresentationDataFrom(n
                    "bad MathML markup - could not find the top <math> element");
 }
 
 /* static */ void
 nsMathMLFrame::GetRuleThickness(nsRenderingContext& aRenderingContext,
                                 nsFontMetrics*      aFontMetrics,
                                 nscoord&             aRuleThickness)
 {
-  // get the bounding metrics of the overbar char, the rendering context
-  // is assumed to have been set with the font of the current style context
-  NS_ASSERTION(aRenderingContext.FontMetrics()->Font().
-               Equals(aFontMetrics->Font()),
-               "unexpected state");
-
   nscoord xHeight = aFontMetrics->XHeight();
   char16_t overBar = 0x00AF;
-  nsBoundingMetrics bm = aRenderingContext.GetBoundingMetrics(&overBar, 1);
+  nsBoundingMetrics bm =
+    nsLayoutUtils::AppUnitBoundsOfString(&overBar, 1, *aFontMetrics,
+                                         aRenderingContext);
   aRuleThickness = bm.ascent + bm.descent;
   if (aRuleThickness <= 0 || aRuleThickness >= xHeight) {
     // fall-back to the other version
     GetRuleThickness(aFontMetrics, aRuleThickness);
   }
 }
 
 /* static */ void
@@ -196,25 +192,21 @@ nsMathMLFrame::GetAxisHeight(nsRendering
   gfxFont* mathFont = aFontMetrics->GetThebesFontGroup()->GetFirstMathFont();
   if (mathFont) {
     aAxisHeight =
       mathFont->GetMathConstant(gfxFontEntry::AxisHeight,
                                 aFontMetrics->AppUnitsPerDevPixel());
     return;
   }
 
-  // get the bounding metrics of the minus sign, the rendering context
-  // is assumed to have been set with the font of the current style context
-  NS_ASSERTION(aRenderingContext.FontMetrics()->Font().
-               Equals(aFontMetrics->Font()),
-               "unexpected state");
-
   nscoord xHeight = aFontMetrics->XHeight();
   char16_t minus = 0x2212; // not '-', but official Unicode minus sign
-  nsBoundingMetrics bm = aRenderingContext.GetBoundingMetrics(&minus, 1);
+  nsBoundingMetrics bm =
+    nsLayoutUtils::AppUnitBoundsOfString(&minus, 1, *aFontMetrics,
+                                         aRenderingContext);
   aAxisHeight = bm.ascent - (bm.ascent + bm.descent)/2;
   if (aAxisHeight <= 0 || aAxisHeight >= xHeight) {
     // fall-back to the other version
     GetAxisHeight(aFontMetrics, aAxisHeight);
   }
 }
 
 /* static */ nscoord
--- a/layout/mathml/nsMathMLmencloseFrame.cpp
+++ b/layout/mathml/nsMathMLmencloseFrame.cpp
@@ -340,24 +340,24 @@ nsMathMLmencloseFrame::PlaceInternal(nsR
   nscoord leading = 0;
 
   ///////////////
   // Thickness of bars and font metrics
   nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
 
   nsRefPtr<nsFontMetrics> fm;
   nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm));
-  aRenderingContext.SetFont(fm);
   GetRuleThickness(aRenderingContext, fm, mRuleThickness);
   if (mRuleThickness < onePixel) {
     mRuleThickness = onePixel;
   }
 
   char16_t one = '1';
-  nsBoundingMetrics bmOne = aRenderingContext.GetBoundingMetrics(&one, 1);
+  nsBoundingMetrics bmOne =
+    nsLayoutUtils::AppUnitBoundsOfString(&one, 1, *fm, aRenderingContext);
 
   ///////////////
   // General rules: the menclose element takes the size of the enclosed content.
   // We add a padding when needed.
 
   // determine padding & psi
   nscoord padding = 3 * mRuleThickness;
   nscoord delta = padding % onePixel;
--- a/layout/mathml/nsMathMLmfencedFrame.cpp
+++ b/layout/mathml/nsMathMLmfencedFrame.cpp
@@ -216,17 +216,16 @@ nsMathMLmfencedFrame::Reflow(nsPresConte
   aDesiredSize.ClearSize();
   aDesiredSize.SetBlockStartAscent(0);
   aDesiredSize.mBoundingMetrics = nsBoundingMetrics();
 
   int32_t i;
   const nsStyleFont* font = StyleFont();
   nsRefPtr<nsFontMetrics> fm;
   nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm));
-  aReflowState.rendContext->SetFont(fm);
   nscoord axisHeight, em;
   GetAxisHeight(*aReflowState.rendContext, fm, axisHeight);
   GetEmHeight(fm, em);
   // leading to be left at the top and the bottom of stretched chars
   nscoord leading = NSToCoordRound(0.2f * em); 
 
   /////////////
   // Reflow children
@@ -335,29 +334,29 @@ nsMathMLmfencedFrame::Reflow(nsPresConte
   // we need to center around the axis
   nscoord delta = std::max(containerSize.ascent - axisHeight, 
                          containerSize.descent + axisHeight);
   containerSize.ascent = delta + axisHeight;
   containerSize.descent = delta - axisHeight;
 
   /////////////////
   // opening fence ...
-  ReflowChar(aPresContext, *aReflowState.rendContext, mOpenChar,
+  ReflowChar(aPresContext, *aReflowState.rendContext, *fm, mOpenChar,
              NS_MATHML_OPERATOR_FORM_PREFIX, font->mScriptLevel, 
              axisHeight, leading, em, containerSize, ascent, descent, isRTL);
   /////////////////
   // separators ...
   for (i = 0; i < mSeparatorsCount; i++) {
-    ReflowChar(aPresContext, *aReflowState.rendContext, &mSeparatorsChar[i],
+    ReflowChar(aPresContext, *aReflowState.rendContext, *fm, &mSeparatorsChar[i],
                NS_MATHML_OPERATOR_FORM_INFIX, font->mScriptLevel,
                axisHeight, leading, em, containerSize, ascent, descent, isRTL);
   }
   /////////////////
   // closing fence ...
-  ReflowChar(aPresContext, *aReflowState.rendContext, mCloseChar,
+  ReflowChar(aPresContext, *aReflowState.rendContext, *fm, mCloseChar,
              NS_MATHML_OPERATOR_FORM_POSTFIX, font->mScriptLevel,
              axisHeight, leading, em, containerSize, ascent, descent, isRTL);
 
   //////////////////
   // Adjust the origins of each child.
   // and update our bounding metrics
 
   i = 0;
@@ -465,16 +464,17 @@ GetCharSpacing(nsMathMLChar*        aMat
   aLeftSpace = NSToCoordRound(lspace * em);
   aRightSpace = NSToCoordRound(rspace * em);
 }
 
 // helper functions to perform the common task of formatting our chars
 /*static*/ nsresult
 nsMathMLmfencedFrame::ReflowChar(nsPresContext*      aPresContext,
                                  nsRenderingContext& aRenderingContext,
+                                 nsFontMetrics&       aFontMetrics,
                                  nsMathMLChar*        aMathMLChar,
                                  nsOperatorFlags      aForm,
                                  int32_t              aScriptLevel,
                                  nscoord              axisHeight,
                                  nscoord              leading,
                                  nscoord              em,
                                  nsBoundingMetrics&   aContainerSize,
                                  nscoord&             aAscent,
@@ -496,23 +496,24 @@ nsMathMLmfencedFrame::ReflowChar(nsPresC
     if (NS_STRETCH_DIRECTION_UNSUPPORTED != aMathMLChar->GetStretchDirection()) {
       // has changed... so center the char around the axis
       nscoord height = charSize.ascent + charSize.descent;
       charSize.ascent = height/2 + axisHeight;
       charSize.descent = height - charSize.ascent;
     }
     else {
       // either it hasn't changed or stretching the char failed (i.e.,
-      // GetBoundingMetrics failed)
+      // nsLayoutUtils::AppUnitBoundsOfString failed)
       leading = 0;
       if (NS_FAILED(res)) {
         nsAutoString data;
         aMathMLChar->GetData(data);
         nsBoundingMetrics metrics =
-          aRenderingContext.GetBoundingMetrics(data.get(), data.Length());
+          nsLayoutUtils::AppUnitBoundsOfString(data.get(), data.Length(),
+                                               aFontMetrics, aRenderingContext);
         charSize.ascent = metrics.ascent;
         charSize.descent = metrics.descent;
         charSize.width = metrics.width;
         // Set this as the bounding metrics of the MathMLChar to leave
         // the necessary room to paint the char.
         aMathMLChar->SetBoundingMetrics(charSize);
       }
     }
--- a/layout/mathml/nsMathMLmfencedFrame.h
+++ b/layout/mathml/nsMathMLmfencedFrame.h
@@ -4,16 +4,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsMathMLmfencedFrame_h
 #define nsMathMLmfencedFrame_h
 
 #include "mozilla/Attributes.h"
 #include "nsMathMLContainerFrame.h"
 
+class nsFontMetrics;
+
 //
 // <mfenced> -- surround content with a pair of fences
 //
 
 class nsMathMLmfencedFrame MOZ_FINAL : public nsMathMLContainerFrame {
 public:
   NS_DECL_FRAMEARENA_HELPERS
 
@@ -58,16 +60,17 @@ public:
   // override the base method so that we can deal with fences and separators
   virtual nscoord
   FixInterFrameSpacing(nsHTMLReflowMetrics& aDesiredSize) MOZ_OVERRIDE;
 
   // helper routines to format the MathMLChars involved here
   static nsresult
   ReflowChar(nsPresContext*      aPresContext,
              nsRenderingContext& aRenderingContext,
+             nsFontMetrics&       aFontMetrics,
              nsMathMLChar*        aMathMLChar,
              nsOperatorFlags      aForm,
              int32_t              aScriptLevel,
              nscoord              axisHeight,
              nscoord              leading,
              nscoord              em,
              nsBoundingMetrics&   aContainerSize,
              nscoord&             aAscent,
--- a/layout/mathml/nsMathMLmfracFrame.cpp
+++ b/layout/mathml/nsMathMLmfracFrame.cpp
@@ -211,17 +211,16 @@ nsMathMLmfracFrame::PlaceInternal(nsRend
   GetReflowAndBoundingMetricsFor(frameNum, sizeNum, bmNum);
   GetReflowAndBoundingMetricsFor(frameDen, sizeDen, bmDen);
 
   nsPresContext* presContext = PresContext();
   nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
 
   nsRefPtr<nsFontMetrics> fm;
   nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm));
-  aRenderingContext.SetFont(fm);
 
   nscoord defaultRuleThickness, axisHeight;
   nscoord oneDevPixel = fm->AppUnitsPerDevPixel();
   gfxFont* mathFont = fm->GetThebesFontGroup()->GetFirstMathFont();
   if (mathFont) {
     defaultRuleThickness =
       mathFont->GetMathConstant(gfxFontEntry::FractionRuleThickness,
                                 oneDevPixel);
--- a/layout/mathml/nsMathMLmmultiscriptsFrame.cpp
+++ b/layout/mathml/nsMathMLmmultiscriptsFrame.cpp
@@ -180,17 +180,16 @@ nsMathMLmmultiscriptsFrame::PlaceMultiSc
       aFrame->ReportChildCountError();
     return aFrame->ReflowError(aRenderingContext, aDesiredSize);
   }
 
   // get x-height (an ex)
   const nsStyleFont* font = aFrame->StyleFont();
   nsRefPtr<nsFontMetrics> fm;
   nsLayoutUtils::GetFontMetricsForFrame(baseFrame, getter_AddRefs(fm));
-  aRenderingContext.SetFont(fm);
 
   nscoord xHeight = fm->XHeight();
 
   nscoord oneDevPixel = fm->AppUnitsPerDevPixel();
   gfxFont* mathFont = fm->GetThebesFontGroup()->GetFirstMathFont();
   // scriptspace from TeX for extra spacing after sup/subscript
   nscoord scriptSpace;
   if (mathFont) {
--- a/layout/mathml/nsMathMLmoFrame.cpp
+++ b/layout/mathml/nsMathMLmoFrame.cpp
@@ -606,17 +606,16 @@ nsMathMLmoFrame::Stretch(nsRenderingCont
   }
   mPresentationData.flags |= NS_MATHML_STRETCH_DONE;
 
   nsIFrame* firstChild = mFrames.FirstChild();
 
   // get the axis height;
   nsRefPtr<nsFontMetrics> fm;
   nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm));
-  aRenderingContext.SetFont(fm);
   nscoord axisHeight, height;
   GetAxisHeight(aRenderingContext, fm, axisHeight);
 
   // get the leading to be left at the top and the bottom of the stretched char
   // this seems more reliable than using fm->GetLeading() on suspicious fonts
   nscoord em;
   GetEmHeight(fm, em);
   nscoord leading = NSToCoordRound(0.2f * em);
--- a/layout/mathml/nsMathMLmrootFrame.cpp
+++ b/layout/mathml/nsMathMLmrootFrame.cpp
@@ -220,26 +220,26 @@ nsMathMLmrootFrame::Reflow(nsPresContext
     return;
   }
 
   ////////////
   // Prepare the radical symbol and the overline bar
 
   nsRefPtr<nsFontMetrics> fm;
   nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm));
-  renderingContext.SetFont(fm);
 
   nscoord ruleThickness, leading, psi;
   GetRadicalParameters(fm, StyleFont()->mMathDisplay ==
                        NS_MATHML_DISPLAYSTYLE_BLOCK,
                        ruleThickness, leading, psi);
 
   // built-in: adjust clearance psi to emulate \mathstrut using '1' (TexBook, p.131)
   char16_t one = '1';
-  nsBoundingMetrics bmOne = renderingContext.GetBoundingMetrics(&one, 1);
+  nsBoundingMetrics bmOne =
+    nsLayoutUtils::AppUnitBoundsOfString(&one, 1, *fm, renderingContext);
   if (bmOne.ascent > bmBase.ascent)
     psi += bmOne.ascent - bmBase.ascent;
 
   // make sure that the rule appears on on screen
   nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
   if (ruleThickness < onePixel) {
     ruleThickness = onePixel;
   }
--- a/layout/mathml/nsMathMLmtableFrame.cpp
+++ b/layout/mathml/nsMathMLmtableFrame.cpp
@@ -852,21 +852,18 @@ nsMathMLmtableOuterFrame::Reflow(nsPresC
       // in other situations, fallback to center
       aDesiredSize.SetBlockStartAscent(dy + blockSize / 2);
       break;
     case eAlign_axis:
     default: {
       // XXX should instead use style data from the row of reference here ?
       nsRefPtr<nsFontMetrics> fm;
       nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm));
-      aReflowState.rendContext->SetFont(fm);
       nscoord axisHeight;
-      GetAxisHeight(*aReflowState.rendContext,
-                    aReflowState.rendContext->FontMetrics(),
-                    axisHeight);
+      GetAxisHeight(*aReflowState.rendContext, fm, axisHeight);
       if (rowFrame) {
         // anchor the table on the axis of the row of reference
         // XXX fallback to baseline because it is a hard problem
         // XXX need to fetch the axis of the row; would need rowalign=axis to work better
         nscoord rowAscent = ((nsTableRowFrame*)rowFrame)->GetMaxCellAscent();
         if (rowAscent) { // the row has at least one cell with 'vertical-align: baseline'
           aDesiredSize.SetBlockStartAscent(dy + rowAscent);
           break;
--- a/layout/mathml/nsMathMLmunderoverFrame.cpp
+++ b/layout/mathml/nsMathMLmunderoverFrame.cpp
@@ -391,17 +391,16 @@ nsMathMLmunderoverFrame::Place(nsRenderi
 
   nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
 
   ////////////////////
   // Place Children
 
   nsRefPtr<nsFontMetrics> fm;
   nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm));
-  aRenderingContext.SetFont(fm);
 
   nscoord xHeight = fm->XHeight();
   nscoord oneDevPixel = fm->AppUnitsPerDevPixel();
   gfxFont* mathFont = fm->GetThebesFontGroup()->GetFirstMathFont();
 
   nscoord ruleThickness;
   GetRuleThickness (aRenderingContext, fm, ruleThickness);
 
new file mode 100644
--- /dev/null
+++ b/layout/reftests/writing-mode/1083892-1-ref.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Bug 1083892</title>
+<style>
+div {
+  width:400px;
+  height:400px;
+  padding:10px;
+  border:1px solid black;
+  writing-mode:vertical-lr;
+}
+p {
+  margin: 0;
+}
+</style>
+</head>
+
+<body>
+<div>
+  This is the first line.<br>
+  Line two.<br>
+  Third and final line.
+</div>
+</body>
+
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/writing-mode/1083892-1.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Bug 1083892</title>
+<style>
+div {
+  width:400px;
+  height:400px;
+  padding:10px;
+  border:1px solid black;
+  writing-mode:vertical-lr;
+}
+p {
+  margin: 0;
+}
+</style>
+</head>
+
+<body>
+<div>
+  <p>This is the first line.
+  <p>Line two.
+  <p>Third and final line.
+</div>
+</body>
+
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/writing-mode/1086883-1-ref.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Bug 1086883</title>
+<!-- writing mode of #inner div should not affect its position within #outer -->
+<style>
+#outer {
+  width:400px;
+  height:300px;
+  padding:50px;
+  border:1px solid black;
+}
+#inner {
+  width:200px;
+  height:100px;
+  background:red;
+}
+</style>
+</head>
+
+<body>
+<div id="outer">
+  <div id="inner">
+  </div>
+</div>
+</body>
+
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/writing-mode/1086883-1a.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Bug 1086883</title>
+<!-- writing mode of #inner div should not affect its position within #outer -->
+<style>
+#outer {
+  width:400px;
+  height:300px;
+  padding:50px;
+  border:1px solid black;
+}
+#inner {
+  width:200px;
+  height:100px;
+  background:red;
+  writing-mode:vertical-lr;
+}
+</style>
+</head>
+
+<body>
+<div id="outer">
+  <div id="inner">
+  </div>
+</div>
+</body>
+
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/writing-mode/1086883-1b.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Bug 1086883</title>
+<!-- writing mode of #inner div should not affect its position within #outer -->
+<style>
+#outer {
+  width:400px;
+  height:300px;
+  padding:50px;
+  border:1px solid black;
+}
+#inner {
+  width:200px;
+  height:100px;
+  background:red;
+  writing-mode:vertical-rl;
+}
+</style>
+</head>
+
+<body>
+<div id="outer">
+  <div id="inner">
+  </div>
+</div>
+</body>
+
+</html>
--- a/layout/reftests/writing-mode/reftest.list
+++ b/layout/reftests/writing-mode/reftest.list
@@ -1,5 +1,8 @@
 # This directory contains tests for vertical text and logical layout coordinates
 # It should not be included in layout/reftests/reftest.list until vertical layout
 # is turned on
 == 1082844.html 1082844-ref.html
 == 1083748.html 1083748-ref.html
+== 1083892-1.html 1083892-1-ref.html
+== 1086883-1a.html 1086883-1-ref.html
+== 1086883-1b.html 1086883-1-ref.html
--- a/layout/xul/nsListBoxBodyFrame.cpp
+++ b/layout/xul/nsListBoxBodyFrame.cpp
@@ -720,20 +720,20 @@ nsListBoxBodyFrame::ComputeIntrinsicISiz
             if (text && text->IsNodeOfType(nsINode::eTEXT)) {
               text->AppendTextTo(value);
             }
           }
 
           nsRefPtr<nsFontMetrics> fm;
           nsLayoutUtils::GetFontMetricsForStyleContext(styleContext,
                                                        getter_AddRefs(fm));
-          rendContext->SetFont(fm);
 
           nscoord textWidth =
-            nsLayoutUtils::GetStringWidth(this, rendContext, value.get(), value.Length());
+            nsLayoutUtils::GetStringWidth(this, rendContext, *fm,
+                                          value.get(), value.Length());
           textWidth += width;
 
           if (textWidth > largestWidth) 
             largestWidth = textWidth;
         }
       }
     }
   }
--- a/layout/xul/nsTextBoxFrame.cpp
+++ b/layout/xul/nsTextBoxFrame.cpp
@@ -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 "nsTextBoxFrame.h"
 
 #include "gfxUtils.h"
 #include "mozilla/gfx/2D.h"
+#include "nsFontMetrics.h"
 #include "nsReadableUtils.h"
 #include "nsCOMPtr.h"
 #include "nsGkAtoms.h"
 #include "nsPresContext.h"
 #include "nsRenderingContext.h"
 #include "nsStyleContext.h"
 #include "nsIContent.h"
 #include "nsNameSpaceManager.h"
@@ -495,20 +496,17 @@ nsTextBoxFrame::DrawText(nsRenderingCont
                           NS_STYLE_TEXT_DECORATION_LINE_OVERLINE, overStyle,
                           vertical);
       }
     }
 
     nsRefPtr<nsRenderingContext> refContext =
         PresContext()->PresShell()->CreateReferenceRenderingContext();
 
-    aRenderingContext.SetFont(fontMet);
-    refContext->SetFont(fontMet);
-
-    CalculateUnderline(*refContext);
+    CalculateUnderline(*refContext, *fontMet);
 
     nscolor c = aOverrideColor ? *aOverrideColor : StyleColor()->mColor;
     ColorPattern color(ToDeviceColor(c));
     aRenderingContext.ThebesContext()->SetColor(c);
 
     nsresult rv = NS_ERROR_FAILURE;
 
     if (mState & NS_FRAME_IS_BIDI) {
@@ -516,42 +514,43 @@ nsTextBoxFrame::DrawText(nsRenderingCont
       nsBidiLevel level = nsBidiPresUtils::BidiLevelFromStyle(StyleContext());
       if (mAccessKeyInfo && mAccessKeyInfo->mAccesskeyIndex != kNotFound) {
           // We let the RenderText function calculate the mnemonic's
           // underline position for us.
           nsBidiPositionResolve posResolve;
           posResolve.logicalIndex = mAccessKeyInfo->mAccesskeyIndex;
           rv = nsBidiPresUtils::RenderText(mCroppedTitle.get(), mCroppedTitle.Length(), level,
                                            presContext, aRenderingContext,
-                                           *refContext,
+                                           *refContext, *fontMet,
                                            aTextRect.x, baseline,
                                            &posResolve,
                                            1);
           mAccessKeyInfo->mBeforeWidth = posResolve.visualLeftTwips;
           mAccessKeyInfo->mAccessWidth = posResolve.visualWidth;
       }
       else
       {
           rv = nsBidiPresUtils::RenderText(mCroppedTitle.get(), mCroppedTitle.Length(), level,
                                            presContext, aRenderingContext,
-                                           *refContext,
+                                           *refContext, *fontMet,
                                            aTextRect.x, baseline);
       }
     }
     if (NS_FAILED(rv)) {
-       aRenderingContext.SetTextRunRTL(false);
+       fontMet->SetTextRunRTL(false);
 
        if (mAccessKeyInfo && mAccessKeyInfo->mAccesskeyIndex != kNotFound) {
            // In the simple (non-BiDi) case, we calculate the mnemonic's
            // underline position by getting the text metric.
            // XXX are attribute values always two byte?
            if (mAccessKeyInfo->mAccesskeyIndex > 0)
-               mAccessKeyInfo->mBeforeWidth =
-                   refContext->GetWidth(mCroppedTitle.get(),
-                                        mAccessKeyInfo->mAccesskeyIndex);
+               mAccessKeyInfo->mBeforeWidth = nsLayoutUtils::
+                   AppUnitWidthOfString(mCroppedTitle.get(),
+                                        mAccessKeyInfo->mAccesskeyIndex,
+                                        *fontMet, *refContext);
            else
                mAccessKeyInfo->mBeforeWidth = 0;
        }
 
        fontMet->DrawString(mCroppedTitle.get(), mCroppedTitle.Length(),
                            aTextRect.x, baseline, &aRenderingContext,
                            refContext.get());
     }
@@ -576,69 +575,70 @@ nsTextBoxFrame::DrawText(nsRenderingCont
       nsCSSRendering::PaintDecorationLine(this, ctx, dirtyRect, strikeColor,
                         pt, xInFrame, gfxSize(width, sizePixel), ascentPixel,
                         offsetPixel, NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH,
                         strikeStyle, vertical);
     }
 }
 
 void
-nsTextBoxFrame::CalculateUnderline(nsRenderingContext& aRenderingContext)
+nsTextBoxFrame::CalculateUnderline(nsRenderingContext& aRenderingContext,
+                                   nsFontMetrics& aFontMetrics)
 {
     if (mAccessKeyInfo && mAccessKeyInfo->mAccesskeyIndex != kNotFound) {
          // Calculate all fields of mAccessKeyInfo which
          // are the same for both BiDi and non-BiDi frames.
          const char16_t *titleString = mCroppedTitle.get();
-         aRenderingContext.SetTextRunRTL(false);
-         mAccessKeyInfo->mAccessWidth =
-             aRenderingContext.GetWidth(titleString[mAccessKeyInfo->
-                                                    mAccesskeyIndex]);
+         aFontMetrics.SetTextRunRTL(false);
+         mAccessKeyInfo->mAccessWidth = nsLayoutUtils::
+             AppUnitWidthOfString(titleString[mAccessKeyInfo->mAccesskeyIndex],
+                                  aFontMetrics, aRenderingContext);
 
          nscoord offset, baseline;
-         nsFontMetrics* metrics = aRenderingContext.FontMetrics();
-         metrics->GetUnderline(offset, mAccessKeyInfo->mAccessUnderlineSize);
-         baseline = metrics->MaxAscent();
+         aFontMetrics.GetUnderline(offset, mAccessKeyInfo->mAccessUnderlineSize);
+         baseline = aFontMetrics.MaxAscent();
          mAccessKeyInfo->mAccessOffset = baseline - offset;
     }
 }
 
 nscoord
 nsTextBoxFrame::CalculateTitleForWidth(nsPresContext*      aPresContext,
                                        nsRenderingContext& aRenderingContext,
                                        nscoord              aWidth)
 {
     if (mTitle.IsEmpty()) {
         mCroppedTitle.Truncate();
         return 0;
     }
 
     nsRefPtr<nsFontMetrics> fm;
     nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm));
-    aRenderingContext.SetFont(fm);
 
     // see if the text will completely fit in the width given
     nscoord titleWidth = nsLayoutUtils::GetStringWidth(this, &aRenderingContext,
+                                                       *fm,
                                                        mTitle.get(), mTitle.Length());
 
     if (titleWidth <= aWidth) {
         mCroppedTitle = mTitle;
         if (HasRTLChars(mTitle)) {
             mState |= NS_FRAME_IS_BIDI;
         }
         return titleWidth;  // fits, done.
     }
 
     const nsDependentString& kEllipsis = nsContentUtils::GetLocalizedEllipsis();
     // start with an ellipsis
     mCroppedTitle.Assign(kEllipsis);
 
     // see if the width is even smaller than the ellipsis
     // if so, clear the text (XXX set as many '.' as we can?).
-    aRenderingContext.SetTextRunRTL(false);
-    titleWidth = aRenderingContext.GetWidth(kEllipsis);
+    fm->SetTextRunRTL(false);
+    titleWidth = nsLayoutUtils::AppUnitWidthOfString(kEllipsis, *fm,
+                                                     aRenderingContext);
 
     if (titleWidth > aWidth) {
         mCroppedTitle.SetLength(0);
         return 0;
     }
 
     // if the ellipsis fits perfectly, no use in trying to insert
     if (titleWidth == aWidth)
@@ -656,17 +656,18 @@ nsTextBoxFrame::CalculateTitleForWidth(n
         {
             nscoord cwidth;
             nscoord twidth = 0;
             int length = mTitle.Length();
             int i;
             for (i = 0; i < length; ++i) {
                 char16_t ch = mTitle.CharAt(i);
                 // still in LTR mode
-                cwidth = aRenderingContext.GetWidth(ch);
+                cwidth = nsLayoutUtils::AppUnitWidthOfString(ch, *fm,
+                                                             aRenderingContext);
                 if (twidth + cwidth > aWidth)
                     break;
 
                 twidth += cwidth;
                 if (UCS2_CHAR_IS_BIDI(ch) ) {
                   mState |= NS_FRAME_IS_BIDI;
                 }
             }
@@ -684,17 +685,18 @@ nsTextBoxFrame::CalculateTitleForWidth(n
         case CropLeft:
         {
             nscoord cwidth;
             nscoord twidth = 0;
             int length = mTitle.Length();
             int i;
             for (i=length-1; i >= 0; --i) {
                 char16_t ch = mTitle.CharAt(i);
-                cwidth = aRenderingContext.GetWidth(ch);
+                cwidth = nsLayoutUtils::AppUnitWidthOfString(ch, *fm,
+                                                             aRenderingContext);
                 if (twidth + cwidth > aWidth)
                     break;
 
                 twidth += cwidth;
                 if (UCS2_CHAR_IS_BIDI(ch) ) {
                   mState |= NS_FRAME_IS_BIDI;
                 }
             }
@@ -706,51 +708,54 @@ nsTextBoxFrame::CalculateTitleForWidth(n
             mTitle.Right(copy, length-1-i);
             mCroppedTitle += copy;
         }
         break;
 
         case CropCenter:
         {
             nscoord stringWidth =
-                nsLayoutUtils::GetStringWidth(this, &aRenderingContext,
+                nsLayoutUtils::GetStringWidth(this, &aRenderingContext, *fm,
                                               mTitle.get(), mTitle.Length());
             if (stringWidth <= aWidth) {
                 // the entire string will fit in the maximum width
                 mCroppedTitle.Insert(mTitle, 0);
                 break;
             }
 
             // determine how much of the string will fit in the max width
             nscoord charWidth = 0;
             nscoord totalWidth = 0;
             char16_t ch;
             int leftPos, rightPos;
             nsAutoString leftString, rightString;
 
             rightPos = mTitle.Length() - 1;
-            aRenderingContext.SetTextRunRTL(false);
+            fm->SetTextRunRTL(false);
             for (leftPos = 0; leftPos <= rightPos;) {
                 // look at the next character on the left end
                 ch = mTitle.CharAt(leftPos);
-                charWidth = aRenderingContext.GetWidth(ch);
+                charWidth = nsLayoutUtils::AppUnitWidthOfString(ch, *fm,
+                                                                aRenderingContext);
                 totalWidth += charWidth;
                 if (totalWidth > aWidth)
                     // greater than the allowable width
                     break;
                 leftString.Insert(ch, leftString.Length());
 
                 if (UCS2_CHAR_IS_BIDI(ch))
                     mState |= NS_FRAME_IS_BIDI;
 
                 // look at the next character on the right end
                 if (rightPos > leftPos) {
                     // haven't looked at this character yet
                     ch = mTitle.CharAt(rightPos);
-                    charWidth = aRenderingContext.GetWidth(ch);
+                    charWidth =
+                        nsLayoutUtils::AppUnitWidthOfString(ch, *fm,
+                                                            aRenderingContext);
                     totalWidth += charWidth;
                     if (totalWidth > aWidth)
                         // greater than the allowable width
                         break;
                     rightString.Insert(ch, 0);
 
                     if (UCS2_CHAR_IS_BIDI(ch))
                         mState |= NS_FRAME_IS_BIDI;
@@ -761,17 +766,17 @@ nsTextBoxFrame::CalculateTitleForWidth(n
                 rightPos--;
             }
 
             mCroppedTitle = leftString + kEllipsis + rightString;
         }
         break;
     }
 
-    return nsLayoutUtils::GetStringWidth(this, &aRenderingContext,
+    return nsLayoutUtils::GetStringWidth(this, &aRenderingContext, *fm,
                                          mCroppedTitle.get(), mCroppedTitle.Length());
 }
 
 #define OLD_ELLIPSIS NS_LITERAL_STRING("...")
 
 // the following block is to append the accesskey to mTitle if there is an accesskey
 // but the mTitle doesn't have the character
 void
@@ -989,19 +994,18 @@ void
 nsTextBoxFrame::GetTextSize(nsPresContext* aPresContext,
                             nsRenderingContext& aRenderingContext,
                             const nsString& aString,
                             nsSize& aSize, nscoord& aAscent)
 {
     nsRefPtr<nsFontMetrics> fontMet;
     nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fontMet));
     aSize.height = fontMet->MaxHeight();
-    aRenderingContext.SetFont(fontMet);
     aSize.width =
-      nsLayoutUtils::GetStringWidth(this, &aRenderingContext,
+      nsLayoutUtils::GetStringWidth(this, &aRenderingContext, *fontMet,
                                     aString.get(), aString.Length());
     aAscent = fontMet->MaxAscent();
 }
 
 void
 nsTextBoxFrame::CalcTextSize(nsBoxLayoutState& aBoxLayoutState)
 {
     if (mNeedsRecalc)
--- a/layout/xul/nsTextBoxFrame.h
+++ b/layout/xul/nsTextBoxFrame.h
@@ -5,16 +5,17 @@
 #ifndef nsTextBoxFrame_h___
 #define nsTextBoxFrame_h___
 
 #include "mozilla/Attributes.h"
 #include "nsLeafBoxFrame.h"
 
 class nsAccessKeyInfo;
 class nsAsyncAccesskeyUpdate;
+class nsFontMetrics;
 
 typedef nsLeafBoxFrame nsTextBoxFrameSuper;
 class nsTextBoxFrame : public nsTextBoxFrameSuper
 {
 public:
   NS_DECL_QUERYFRAME_TARGET(nsTextBoxFrame)
   NS_DECL_QUERYFRAME
   NS_DECL_FRAMEARENA_HELPERS
@@ -79,17 +80,18 @@ protected:
   // account text-transform.
   void RecomputeTitle();
 
   // REVIEW: SORRY! Couldn't resist devirtualizing these
   void LayoutTitle(nsPresContext*      aPresContext,
                    nsRenderingContext& aRenderingContext,
                    const nsRect&        aRect);
 
-  void CalculateUnderline(nsRenderingContext& aRenderingContext);
+  void CalculateUnderline(nsRenderingContext& aRenderingContext,
+                          nsFontMetrics& aFontMetrics);
 
   void CalcTextSize(nsBoxLayoutState& aBoxLayoutState);
 
   void CalcDrawRect(nsRenderingContext &aRenderingContext);
 
   nsTextBoxFrame(nsIPresShell* aShell, nsStyleContext* aContext);
 
   nscoord CalculateTitleForWidth(nsPresContext*      aPresContext,
--- a/layout/xul/tree/nsTreeBodyFrame.cpp
+++ b/layout/xul/tree/nsTreeBodyFrame.cpp
@@ -11,16 +11,17 @@
 #include "mozilla/gfx/PathHelpers.h"
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/Likely.h"
 
 #include "gfxUtils.h"
 #include "nsAlgorithm.h"
 #include "nsCOMPtr.h"
+#include "nsFontMetrics.h"
 #include "nsPresContext.h"
 #include "nsNameSpaceManager.h"
 
 #include "nsTreeBodyFrame.h"
 #include "nsTreeSelection.h"
 #include "nsTreeImageListener.h"
 
 #include "nsGkAtoms.h"
@@ -1263,18 +1264,17 @@ nsTreeBodyFrame::GetCoordsForCellItem(in
       textRect.y += (textRect.height - height) / 2;
       textRect.height = height;
     }
 
     nsMargin bp(0,0,0,0);
     GetBorderPadding(textContext, bp);
     textRect.height += bp.top + bp.bottom;
 
-    rc->SetFont(fm);
-    AdjustForCellText(cellText, aRow, currCol, *rc, textRect);
+    AdjustForCellText(cellText, aRow, currCol, *rc, *fm, textRect);
 
     theRect = textRect;
   }
 
   if (isRTL)
     theRect.x = mInnerBox.width - theRect.x - theRect.width;
 
   *aX = nsPresContext::AppUnitsToIntCSSPixels(theRect.x);
@@ -1309,22 +1309,24 @@ nsTreeBodyFrame::CheckTextForBidi(nsAuto
     PresContext()->SetBidiEnabled();
   }
 }
 
 void
 nsTreeBodyFrame::AdjustForCellText(nsAutoString& aText,
                                    int32_t aRowIndex,  nsTreeColumn* aColumn,
                                    nsRenderingContext& aRenderingContext,
+                                   nsFontMetrics& aFontMetrics,
                                    nsRect& aTextRect)
 {
   NS_PRECONDITION(aColumn && aColumn->GetFrame(), "invalid column passed");
 
   nscoord width =
-    nsLayoutUtils::GetStringWidth(this, &aRenderingContext, aText.get(), aText.Length());
+    nsLayoutUtils::GetStringWidth(this, &aRenderingContext, aFontMetrics,
+                                  aText.get(), aText.Length());
   nscoord maxWidth = aTextRect.width;
 
   if (aColumn->Overflow()) {
     DebugOnly<nsresult> rv;
     nsTreeColumn* nextColumn = aColumn->GetNext();
     while (nextColumn && width > maxWidth) {
       while (nextColumn) {
         nscoord width;
@@ -1358,18 +1360,20 @@ nsTreeBodyFrame::AdjustForCellText(nsAut
       }
     }
   }
 
   if (width > maxWidth) {
     // See if the width is even smaller than the ellipsis
     // If so, clear the text completely.
     const nsDependentString& kEllipsis = nsContentUtils::GetLocalizedEllipsis();
-    aRenderingContext.SetTextRunRTL(false);
-    nscoord ellipsisWidth = aRenderingContext.GetWidth(kEllipsis);
+    aFontMetrics.SetTextRunRTL(false);
+    nscoord ellipsisWidth =
+      nsLayoutUtils::AppUnitWidthOfString(kEllipsis, aFontMetrics,
+                                          aRenderingContext);
 
     width = maxWidth;
     if (ellipsisWidth > width)
       aText.SetLength(0);
     else if (ellipsisWidth == width)
       aText.Assign(kEllipsis);
     else {
       // We will be drawing an ellipsis, thank you very much.
@@ -1384,17 +1388,18 @@ nsTreeBodyFrame::AdjustForCellText(nsAut
           // Crop right.
           nscoord cwidth;
           nscoord twidth = 0;
           uint32_t length = aText.Length();
           uint32_t i;
           for (i = 0; i < length; ++i) {
             char16_t ch = aText[i];
             // XXX this is horrible and doesn't handle clusters
-            cwidth = aRenderingContext.GetWidth(ch);
+            cwidth = nsLayoutUtils::AppUnitWidthOfString(ch, aFontMetrics,
+                                                         aRenderingContext);
             if (twidth + cwidth > width)
               break;
             twidth += cwidth;
           }
           aText.Truncate(i);
           aText.Append(kEllipsis);
         }
         break;
@@ -1402,17 +1407,18 @@ nsTreeBodyFrame::AdjustForCellText(nsAut
         case 2: {
           // Crop left.
           nscoord cwidth;
           nscoord twidth = 0;
           int32_t length = aText.Length();
           int32_t i;
           for (i=length-1; i >= 0; --i) {
             char16_t ch = aText[i];
-            cwidth = aRenderingContext.GetWidth(ch);
+            cwidth = nsLayoutUtils::AppUnitWidthOfString(ch, aFontMetrics,
+                                                         aRenderingContext);
             if (twidth + cwidth > width)
               break;
             twidth += cwidth;
           }
 
           nsAutoString copy;
           aText.Right(copy, length-1-i);
           aText.Assign(kEllipsis);
@@ -1424,39 +1430,43 @@ nsTreeBodyFrame::AdjustForCellText(nsAut
         {
           // Crop center.
           nsAutoString leftStr, rightStr;
           nscoord cwidth, twidth = 0;
           int32_t length = aText.Length();
           int32_t rightPos = length - 1;
           for (int32_t leftPos = 0; leftPos < rightPos; ++leftPos) {
             char16_t ch = aText[leftPos];
-            cwidth = aRenderingContext.GetWidth(ch);
+            cwidth = nsLayoutUtils::AppUnitWidthOfString(ch, aFontMetrics,
+                                                         aRenderingContext);
             twidth += cwidth;
             if (twidth > width)
               break;
             leftStr.Append(ch);
 
             ch = aText[rightPos];
-            cwidth = aRenderingContext.GetWidth(ch);
+            cwidth = nsLayoutUtils::AppUnitWidthOfString(ch, aFontMetrics,
+                                                         aRenderingContext);
             twidth += cwidth;
             if (twidth > width)
               break;
             rightStr.Insert(ch, 0);
             --rightPos;
           }
           aText = leftStr;
           aText.Append(kEllipsis);
           aText += rightStr;
         }
         break;
       }
     }
 
-    width = nsLayoutUtils::GetStringWidth(this, &aRenderingContext, aText.get(), aText.Length());
+    width = nsLayoutUtils::GetStringWidth(this, &aRenderingContext,
+                                          aFontMetrics, aText.get(),
+                                          aText.Length());
   }
 
   switch (aColumn->GetTextAlignment()) {
     case NS_STYLE_TEXT_ALIGN_RIGHT: {
       aTextRect.x += aTextRect.width - width;
     }
     break;
     case NS_STYLE_TEXT_ALIGN_CENTER: {
@@ -1604,19 +1614,17 @@ nsTreeBodyFrame::GetItemWithinCellAt(nsc
   textContext->StyleMargin()->GetMargin(textMargin);
   textRect.Deflate(textMargin);
 
   AdjustForBorderPadding(textContext, textRect);
 
   nsRefPtr<nsFontMetrics> fm;
   nsLayoutUtils::GetFontMetricsForStyleContext(textContext,
                                                getter_AddRefs(fm));
-  rc->SetFont(fm);
-
-  AdjustForCellText(cellText, aRowIndex, aColumn, *rc, textRect);
+  AdjustForCellText(cellText, aRowIndex, aColumn, *rc, *fm, textRect);
 
   if (aX >= textRect.x && aX < textRect.x + textRect.width)
     return nsCSSAnonBoxes::moztreecelltext;
   else
     return nsCSSAnonBoxes::moztreecell;
 }
 
 void
@@ -1734,21 +1742,20 @@ nsTreeBodyFrame::GetCellWidth(int32_t aR
   nsStyleContext* textContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreecelltext);
 
   // Get the borders and padding for the text.
   GetBorderPadding(textContext, bp);
 
   nsRefPtr<nsFontMetrics> fm;
   nsLayoutUtils::GetFontMetricsForStyleContext(textContext,
                                                getter_AddRefs(fm));
-  aRenderingContext->SetFont(fm);
-
   // Get the width of the text itself
   nscoord width =
-    nsLayoutUtils::GetStringWidth(this, aRenderingContext, cellText.get(), cellText.Length());
+    nsLayoutUtils::GetStringWidth(this, aRenderingContext, *fm,
+                                  cellText.get(), cellText.Length());
   nscoord totalTextWidth = width + bp.left + bp.right;
   aDesiredSize += totalTextWidth;
   return NS_OK;
 }
 
 nsresult
 nsTreeBodyFrame::IsCellCropped(int32_t aRow, nsITreeColumn* aCol, bool *_retval)
 {  
@@ -3598,19 +3605,17 @@ nsTreeBodyFrame::PaintText(int32_t      
 
   // Center the text. XXX Obey vertical-align style prop?
   if (height < textRect.height) {
     textRect.y += (textRect.height - height)/2;
     textRect.height = height;
   }
 
   // Set our font.
-  aRenderingContext.SetFont(fontMet);
-
-  AdjustForCellText(text, aRowIndex, aColumn, aRenderingContext, textRect);
+  AdjustForCellText(text, aRowIndex, aColumn, aRenderingContext, *fontMet, textRect);
   textRect.Inflate(bp);
 
   // Subtract out the remaining width.
   if (!isRTL)
     aCurrX += textRect.width + textMargin.LeftRight();
 
   PaintBackgroundLayer(textContext, aPresContext, aRenderingContext, textRect, aDirtyRect);
 
@@ -3651,18 +3656,20 @@ nsTreeBodyFrame::PaintText(int32_t      
   nsStyleContext* cellContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreecell);
 
   gfxContext* ctx = aRenderingContext.ThebesContext();
   if (opacity != 1.0f) {
     ctx->PushGroup(gfxContentType::COLOR_ALPHA);
   }
 
   ctx->SetColor(textContext->StyleColor()->mColor);
-  nsLayoutUtils::DrawString(this, &aRenderingContext, text.get(), text.Length(),
-                            textRect.TopLeft() + nsPoint(0, baseline), cellContext);
+  nsLayoutUtils::DrawString(this, *fontMet, &aRenderingContext, text.get(),
+                            text.Length(),
+                            textRect.TopLeft() + nsPoint(0, baseline),
+                            cellContext);
 
   if (opacity != 1.0f) {
     ctx->PopGroupToSource();
     ctx->Paint(opacity);
   }
 
 }
 
--- a/layout/xul/tree/nsTreeBodyFrame.h
+++ b/layout/xul/tree/nsTreeBodyFrame.h
@@ -20,16 +20,17 @@
 #include "nsAutoPtr.h"
 #include "nsDataHashtable.h"
 #include "imgIRequest.h"
 #include "imgINotificationObserver.h"
 #include "nsScrollbarFrame.h"
 #include "nsThreadUtils.h"
 #include "mozilla/LookAndFeel.h"
 
+class nsFontMetrics;
 class nsOverflowChecker;
 class nsTreeImageListener;
 
 namespace mozilla {
 namespace layout {
 class ScrollbarActivity;
 }
 }
@@ -291,16 +292,17 @@ protected:
 
   // Check for bidi characters in the text, and if there are any, ensure
   // that the prescontext is in bidi mode.
   void CheckTextForBidi(nsAutoString& aText);
 
   void AdjustForCellText(nsAutoString& aText,
                          int32_t aRowIndex,  nsTreeColumn* aColumn,
                          nsRenderingContext& aRenderingContext,
+                         nsFontMetrics& aFontMetrics,
                          nsRect& aTextRect);
 
   // A helper used when hit testing.
   nsIAtom* GetItemWithinCellAt(nscoord aX, const nsRect& aCellRect,
                                int32_t aRowIndex, nsTreeColumn* aColumn);
 
   // An internal hit test.  aX and aY are expected to be in twips in the
   // coordinate system of this frame.
--- a/mfbt/MemoryChecking.h
+++ b/mfbt/MemoryChecking.h
@@ -29,16 +29,17 @@
 
 #if defined(MOZ_ASAN) || defined(MOZ_VALGRIND)
 #define MOZ_HAVE_MEM_CHECKS 1
 #endif
 
 #if defined(MOZ_ASAN)
 #include <stddef.h>
 
+#include "mozilla/Attributes.h"
 #include "mozilla/Types.h"
 
 #ifdef _MSC_VER
 // In clang-cl based ASAN, we link against the memory poisoning functions
 // statically.
 #define MOZ_ASAN_VISIBILITY
 #else
 #define MOZ_ASAN_VISIBILITY MOZ_EXPORT
@@ -56,16 +57,24 @@ void MOZ_ASAN_VISIBILITY
 #define MOZ_MAKE_MEM_NOACCESS(addr, size) \
   __asan_poison_memory_region((addr), (size))
 
 #define MOZ_MAKE_MEM_UNDEFINED(addr, size) \
   __asan_unpoison_memory_region((addr), (size))
 
 #define MOZ_MAKE_MEM_DEFINED(addr, size) \
   __asan_unpoison_memory_region((addr), (size))
+
+/*
+ * These definitions are usually provided through the
+ * sanitizer/lsan_interface.h header installed by LSan.
+ */
+void MOZ_EXPORT
+__lsan_ignore_object(const void *p);
+
 }
 #elif defined(MOZ_MSAN)
 #include <stddef.h>
 
 #include "mozilla/Types.h"
 
 extern "C" {
 /* These definitions are usually provided through the
@@ -97,9 +106,24 @@ void MOZ_EXPORT
 #else
 
 #define MOZ_MAKE_MEM_NOACCESS(addr, size) do {} while (0)
 #define MOZ_MAKE_MEM_UNDEFINED(addr, size) do {} while (0)
 #define MOZ_MAKE_MEM_DEFINED(addr, size) do {} while (0)
 
 #endif
 
+/*
+ * MOZ_LSAN_INTENTIONAL_LEAK(X) is a macro to tell LeakSanitizer that X
+ * points to a value that will intentionally never be deallocated during
+ * the execution of the process.
+ *
+ * Additional uses of this macro should be reviewed by people
+ * conversant in leak-checking and/or MFBT peers.
+ */
+#if defined(MOZ_ASAN)
+#  define MOZ_LSAN_INTENTIONALLY_LEAK_OBJECT(X) __lsan_ignore_object(X)
+#else
+#  define MOZ_LSAN_INTENTIONALLY_LEAK_OBJECT(X) /* nothing */
+#endif // defined(MOZ_ASAN)
+
+
 #endif /* mozilla_MemoryChecking_h */
--- a/netwerk/base/src/ProxyAutoConfig.cpp
+++ b/netwerk/base/src/ProxyAutoConfig.cpp
@@ -497,18 +497,21 @@ static const JSFunctionSpec PACGlobalFun
 // JSRuntimeWrapper is a c++ object that manages the runtime and context
 // for the JS engine used on the PAC thread. It is initialized and destroyed
 // on the PAC thread.
 class JSRuntimeWrapper
 {
  public:
   static JSRuntimeWrapper *Create()
   {
-    JSRuntimeWrapper *entry = new JSRuntimeWrapper();
+    JSRuntime *runtime = JS_NewRuntime(sRuntimeHeapSize);
+    if (NS_WARN_IF(!runtime))
+      return nullptr;
 
+    JSRuntimeWrapper *entry = new JSRuntimeWrapper(runtime);
     if (NS_FAILED(entry->Init())) {
       delete entry;
       return nullptr;
     }
 
     return entry;
   }
 
@@ -519,16 +522,18 @@ class JSRuntimeWrapper
 
   JSObject *Global() const
   {
     return mGlobal;
   }
 
   ~JSRuntimeWrapper()
   {
+    mGlobal = nullptr;
+
     MOZ_COUNT_DTOR(JSRuntimeWrapper);
     if (mContext) {
       JS_DestroyContext(mContext);
     }
 
     if (mRuntime) {
       JS_DestroyRuntime(mRuntime);
     }
@@ -544,32 +549,29 @@ class JSRuntimeWrapper
     return mOK;
   }
 
 private:
   static const unsigned sRuntimeHeapSize = 2 << 20;
 
   JSRuntime *mRuntime;
   JSContext *mContext;
-  JSObject  *mGlobal;
+  JS::PersistentRooted<JSObject*> mGlobal;
   bool      mOK;
 
   static const JSClass sGlobalClass;
 
-  JSRuntimeWrapper()
-    : mRuntime(nullptr), mContext(nullptr), mGlobal(nullptr), mOK(false)
+  JSRuntimeWrapper(JSRuntime* rt)
+     : mRuntime(rt), mContext(nullptr), mGlobal(rt, nullptr), mOK(false)
   {
       MOZ_COUNT_CTOR(JSRuntimeWrapper);
   }
 
   nsresult Init()
   {
-    mRuntime = JS_NewRuntime(sRuntimeHeapSize);
-    NS_ENSURE_TRUE(mRuntime, NS_ERROR_OUT_OF_MEMORY);
-
     /*
      * Not setting this will cause JS_CHECK_RECURSION to report false
      * positives
      */
     JS_SetNativeStackQuota(mRuntime, 128 * sizeof(size_t) * 1024); 
 
     JS_SetErrorReporter(mRuntime, PACErrorReporter);
 
--- a/netwerk/ipc/NeckoChild.cpp
+++ b/netwerk/ipc/NeckoChild.cpp
@@ -298,17 +298,17 @@ NeckoChild::AllocPChannelDiverterChild(c
 bool
 NeckoChild::DeallocPChannelDiverterChild(PChannelDiverterChild* child)
 {
   delete static_cast<ChannelDiverterChild*>(child);
   return true;
 }
 
 bool
-NeckoChild::RecvAsyncAuthPromptForNestedFrame(const uint64_t& aNestedFrameId,
+NeckoChild::RecvAsyncAuthPromptForNestedFrame(const TabId& aNestedFrameId,
                                               const nsCString& aUri,
                                               const nsString& aRealm,
                                               const uint64_t& aCallbackId)
 {
   auto iter = dom::TabChild::NestedTabChildMap().find(aNestedFrameId);
   if (iter == dom::TabChild::NestedTabChildMap().end()) {
     MOZ_CRASH();
     return false;
--- a/netwerk/ipc/NeckoChild.h
+++ b/netwerk/ipc/NeckoChild.h
@@ -66,17 +66,17 @@ protected:
   virtual PRtspChannelChild*
     AllocPRtspChannelChild(const RtspChannelConnectArgs& aArgs)
                            MOZ_OVERRIDE;
   virtual bool DeallocPRtspChannelChild(PRtspChannelChild*) MOZ_OVERRIDE;
   virtual PChannelDiverterChild*
   AllocPChannelDiverterChild(const ChannelDiverterArgs& channel) MOZ_OVERRIDE;
   virtual bool
   DeallocPChannelDiverterChild(PChannelDiverterChild* actor) MOZ_OVERRIDE;
-  virtual bool RecvAsyncAuthPromptForNestedFrame(const uint64_t& aNestedFrameId,
+  virtual bool RecvAsyncAuthPromptForNestedFrame(const TabId& aNestedFrameId,
                                                  const nsCString& aUri,
                                                  const nsString& aRealm,
                                                  const uint64_t& aCallbackId) MOZ_OVERRIDE;
   virtual bool RecvAppOfflineStatus(const uint32_t& aId, const bool& aOffline) MOZ_OVERRIDE;
 };
 
 /**
  * Reference to the PNecko Child protocol.
--- a/netwerk/ipc/NeckoParent.cpp
+++ b/netwerk/ipc/NeckoParent.cpp
@@ -183,19 +183,19 @@ NeckoParent::CreateChannelLoadContext(co
         dom::Element* topFrameElement = nullptr;
         if (tabParent) {
           topFrameElement = tabParent->GetOwnerElement();
         }
         aResult = new LoadContext(aSerialized, topFrameElement,
                                   appId, inBrowser);
         break;
       }
-      case PBrowserOrId::Tuint64_t:
+      case PBrowserOrId::TTabId:
       {
-        aResult = new LoadContext(aSerialized, aBrowser.get_uint64_t(),
+        aResult = new LoadContext(aSerialized, aBrowser.get_TabId(),
                                   appId, inBrowser);
         break;
       }
       default:
         MOZ_CRASH();
     }
   }
 
@@ -728,17 +728,17 @@ CallbackMap()
   static std::map<uint64_t, nsCOMPtr<nsIAuthPromptCallback> > sCallbackMap;
   return sCallbackMap;
 }
 } // anonymous namespace
 
 NS_IMPL_ISUPPORTS(NeckoParent::NestedFrameAuthPrompt, nsIAuthPrompt2)
 
 NeckoParent::NestedFrameAuthPrompt::NestedFrameAuthPrompt(PNeckoParent* aParent,
-                                                          uint64_t aNestedFrameId)
+                                                          TabId aNestedFrameId)
   : mNeckoParent(aParent)
   , mNestedFrameId(aNestedFrameId)
 {}
 
 NS_IMETHODIMP
 NeckoParent::NestedFrameAuthPrompt::AsyncPromptAuth(
   nsIChannel* aChannel, nsIAuthPromptCallback* callback,
   nsISupports*, uint32_t,
--- a/netwerk/ipc/NeckoParent.h
+++ b/netwerk/ipc/NeckoParent.h
@@ -73,17 +73,17 @@ public:
    */
   class NestedFrameAuthPrompt MOZ_FINAL : public nsIAuthPrompt2
   {
     ~NestedFrameAuthPrompt() {}
 
   public:
     NS_DECL_ISUPPORTS
 
-    NestedFrameAuthPrompt(PNeckoParent* aParent, uint64_t aNestedFrameId);
+    NestedFrameAuthPrompt(PNeckoParent* aParent, TabId aNestedFrameId);
 
     NS_IMETHOD PromptAuth(nsIChannel*, uint32_t, nsIAuthInformation*, bool*)
     {
       return NS_ERROR_NOT_IMPLEMENTED;
     }
 
     NS_IMETHOD AsyncPromptAuth(nsIChannel* aChannel, nsIAuthPromptCallback* callback,
                                nsISupports*, uint32_t,
@@ -93,17 +93,17 @@ public:
                                 nsIAuthPromptCallback*, nsISupports*,
                                 uint32_t, nsIAuthInformation*, nsICancelable**)
     {
       return NS_ERROR_NOT_IMPLEMENTED;
     }
 
   protected:
     PNeckoParent* mNeckoParent;
-    uint64_t mNestedFrameId;
+    TabId mNestedFrameId;
   };
 
 protected:
   virtual PHttpChannelParent*
     AllocPHttpChannelParent(const PBrowserOrId&, const SerializedLoadContext&,
                             const HttpChannelCreationArgs& aOpenArgs) MOZ_OVERRIDE;
   virtual bool
     RecvPHttpChannelConstructor(
--- a/netwerk/ipc/PNecko.ipdl
+++ b/netwerk/ipc/PNecko.ipdl
@@ -21,28 +21,24 @@ include protocol PChannelDiverter;
 include protocol PBlob; //FIXME: bug #792908
 include protocol PFileDescriptorSet;
 
 include protocol PRtspController;
 include protocol PRtspChannel;
 include URIParams;
 include InputStreamParams;
 include NeckoChannelParams;
-
+include PBrowserOrId;
 
 using class IPC::SerializedLoadContext from "SerializedLoadContext.h";
+using mozilla::dom::TabId from "mozilla/dom/ipc/IdType.h";
 
 namespace mozilla {
 namespace net {
 
-union PBrowserOrId {
-  nullable PBrowser;
-  uint64_t;
-};
-
 //-------------------------------------------------------------------
 sync protocol PNecko
 {
   manager PContent;
   manages PHttpChannel;
   manages PCookieService;
   manages PWyciwygChannel;
   manages PFTPChannel;
@@ -93,17 +89,17 @@ parent:
   OnAuthCancelled(uint64_t callbackId, bool userCancel);
 
 child:
   /*
    * Bring up the http auth prompt for a nested remote mozbrowser.
    * NestedFrameId is the id corresponding to the PBrowser.  It is the same id
    * that was passed to the PBrowserOrId param in to the PHttpChannel constructor
    */
-  AsyncAuthPromptForNestedFrame(uint64_t nestedFrameId, nsCString uri,
+  AsyncAuthPromptForNestedFrame(TabId nestedFrameId, nsCString uri,
                                 nsString realm, uint64_t callbackId);
   // Notifies child that a given app is now offline (or online)
   AppOfflineStatus(uint32_t appId, bool offline);
 
 both:
   // Actually we need PTCPSocket() for parent. But ipdl disallows us having different
   // signatures on parent and child. So when constructing the parent side object, we just 
   // leave host/port unused.
--- a/netwerk/protocol/http/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/HttpChannelChild.cpp
@@ -1050,17 +1050,17 @@ HttpChannelChild::ConnectParent(uint32_t
   AddIPDLReference();
 
   HttpChannelConnectArgs connectArgs(id);
   PBrowserOrId browser;
   if (!tabChild ||
       static_cast<ContentChild*>(gNeckoChild->Manager()) == tabChild->Manager()) {
     browser = tabChild;
   } else {
-    browser = TabChild::GetTabChildId(tabChild);
+    browser = tabChild->GetTabId();
   }
   if (!gNeckoChild->
         SendPHttpChannelConstructor(this, browser,
                                     IPC::SerializedLoadContext(this),
                                     connectArgs)) {
     return NS_ERROR_FAILURE;
   }
 
@@ -1505,17 +1505,17 @@ HttpChannelChild::ContinueAsyncOpen()
   // until OnStopRequest, or we do a redirect, or we hit an IPDL error.
   AddIPDLReference();
 
   PBrowserOrId browser;
   if (!tabChild ||
       static_cast<ContentChild*>(gNeckoChild->Manager()) == tabChild->Manager()) {
     browser = tabChild;
   } else {
-    browser = TabChild::GetTabChildId(tabChild);
+    browser = tabChild->GetTabId();
   }
   gNeckoChild->SendPHttpChannelConstructor(this, browser,
                                            IPC::SerializedLoadContext(this),
                                            openArgs);
 
   if (fdSet) {
     FileDescriptorSetChild* fdSetActor =
       static_cast<FileDescriptorSetChild*>(fdSet);
--- a/netwerk/protocol/http/HttpChannelParent.cpp
+++ b/netwerk/protocol/http/HttpChannelParent.cpp
@@ -62,17 +62,17 @@ HttpChannelParent::HttpChannelParent(con
     do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http");
 
   MOZ_ASSERT(gHttpHandler);
   mHttpHandler = gHttpHandler;
 
   if (iframeEmbedding.type() == PBrowserOrId::TPBrowserParent) {
     mTabParent = static_cast<dom::TabParent*>(iframeEmbedding.get_PBrowserParent());
   } else {
-    mNestedFrameId = iframeEmbedding.get_uint64_t();
+    mNestedFrameId = iframeEmbedding.get_TabId();
   }
 
   mObserver = new OfflineObserver(this);
 }
 
 HttpChannelParent::~HttpChannelParent()
 {
   if (mObserver) {
--- a/netwerk/protocol/http/HttpChannelParent.h
+++ b/netwerk/protocol/http/HttpChannelParent.h
@@ -14,30 +14,31 @@
 #include "mozilla/net/NeckoCommon.h"
 #include "mozilla/net/NeckoParent.h"
 #include "OfflineObserver.h"
 #include "nsIObserver.h"
 #include "nsIParentRedirectingChannel.h"
 #include "nsIProgressEventSink.h"
 #include "nsHttpChannel.h"
 #include "nsIAuthPromptProvider.h"
+#include "mozilla/dom/ipc/IdType.h"
 
 class nsICacheEntry;
 class nsIAssociatedContentSecurity;
 
 namespace mozilla {
 
 namespace dom{
 class TabParent;
+class PBrowserOrId;
 }
 
 namespace net {
 
 class HttpChannelParentListener;
-class PBrowserOrId;
 
 class HttpChannelParent : public PHttpChannelParent
                         , public nsIParentRedirectingChannel
                         , public nsIProgressEventSink
                         , public nsIInterfaceRequestor
                         , public ADivertableParentChannel
                         , public nsIAuthPromptProvider
                         , public DisconnectableParent
@@ -49,17 +50,17 @@ public:
   NS_DECL_NSIREQUESTOBSERVER
   NS_DECL_NSISTREAMLISTENER
   NS_DECL_NSIPARENTCHANNEL
   NS_DECL_NSIPARENTREDIRECTINGCHANNEL
   NS_DECL_NSIPROGRESSEVENTSINK
   NS_DECL_NSIINTERFACEREQUESTOR
   NS_DECL_NSIAUTHPROMPTPROVIDER
 
-  HttpChannelParent(const PBrowserOrId& iframeEmbedding,
+  HttpChannelParent(const dom::PBrowserOrId& iframeEmbedding,
                     nsILoadContext* aLoadContext,
                     PBOverrideStatus aStatus);
 
   bool Init(const HttpChannelCreationArgs& aOpenArgs);
 
   // ADivertableParentChannel functions.
   void DivertTo(nsIStreamListener *aListener) MOZ_OVERRIDE;
   nsresult SuspendForDiversion() MOZ_OVERRIDE;
@@ -180,15 +181,15 @@ private:
   // received from the child channel.
   bool mDivertingFromChild;
 
   // Set if OnStart|StopRequest was called during a diversion from the child.
   bool mDivertedOnStartRequest;
 
   bool mSuspendedForDiversion;
 
-  uint64_t mNestedFrameId;
+  dom::TabId mNestedFrameId;
 };
 
 } // namespace net
 } // namespace mozilla
 
 #endif // mozilla_net_HttpChannelParent_h
--- a/python/mozbuild/mozbuild/backend/cpp_eclipse.py
+++ b/python/mozbuild/mozbuild/backend/cpp_eclipse.py
@@ -22,18 +22,19 @@ from ..frontend.data import (
 class CppEclipseBackend(CommonBackend):
     """Backend that generates Cpp Eclipse project files.
     """
 
     def _init(self):
         CommonBackend._init(self)
 
         self._paths_to_defines = {}
+        self._project_name = 'Gecko'
         self._workspace_dir = self._get_workspace_path()
-        self._project_dir = os.path.join(self._workspace_dir, 'gecko')
+        self._project_dir = os.path.join(self._workspace_dir, self._project_name)
         self._overwriting_workspace = os.path.isdir(self._workspace_dir)
 
         self._macbundle = self.environment.substs['MOZ_MACBUNDLE_NAME']
         self._appname = self.environment.substs['MOZ_APP_NAME']
         self._bin_suffix = self.environment.substs['BIN_SUFFIX']
         self._cxx = self.environment.substs['CXX']
         # Note: We need the C Pre Processor (CPP) flags, not the CXX flags
         self._cppflags = self.environment.substs.get('CPPFLAGS', '')
@@ -194,17 +195,17 @@ class CppEclipseBackend(CommonBackend):
                 launch = launch.replace('@OBJDIR@', self.environment.topobjdir)
                 fh.write(launch)
 
         #TODO Add more launch configs (and delegate calls to mach)
 
     def _write_project(self, fh):
         project = PROJECT_TEMPLATE;
 
-        project = project.replace('@PROJECT_NAME@', 'Gecko')
+        project = project.replace('@PROJECT_NAME@', self._project_name)
         project = project.replace('@PROJECT_TOPSRCDIR@', self.environment.topsrcdir)
         fh.write(project)
 
     def _write_cproject(self, fh):
         cproject_header = CPROJECT_TEMPLATE_HEADER
         cproject_header = cproject_header.replace('@PROJECT_TOPSRCDIR@', self.environment.topobjdir)
         cproject_header = cproject_header.replace('@MACH_COMMAND@', os.path.join(self.environment.topsrcdir, 'mach'))
         fh.write(cproject_header)
--- a/security/manager/locales/en-US/chrome/pippki/pippki.properties
+++ b/security/manager/locales/en-US/chrome/pippki/pippki.properties
@@ -68,24 +68,26 @@ clientAuthMessage2=Issued Under: "%S"
 pageInfo_SiteNotVerified=Website Identity Not Verified
 pageInfo_WebSiteVerified=Website Identity Verified
 pageInfo_Identity_Verified=The website %S supports authentication for the page you are viewing. The identity of this website has been verified by %S, a certificate authority you trust for this purpose.
 pageInfo_ViewCertificate=View the security certificate that verifies this website's identity.
 pageInfo_NoEncryption=Connection Not Encrypted
 pageInfo_Privacy_None1=The website %S does not support encryption for the page you are viewing.
 pageInfo_Privacy_None2=Information sent over the Internet without encryption can be seen by other people while it is in transit. 
 pageInfo_Privacy_None3=The page you are viewing is not encrypted.
-# LOCALIZATION NOTE (pageInfo_StrongEncryptionWithBits): %1$S is the name of the encryption standard,
+# LOCALIZATION NOTE (pageInfo_StrongEncryptionWithBitsAndProtocol): %1$S is the name of the encryption standard,
 # %2$S is the key size of the cipher.
-pageInfo_StrongEncryptionWithBits=Connection Encrypted: High-grade Encryption (%1$S, %2$S bit keys)
+# %3$S is protocol version like "SSL 3" or "TLS 1.2"
+pageInfo_StrongEncryptionWithBitsAndProtocol=Connection Encrypted: High-grade Encryption (%1$S, %2$S bit keys, %3$S)
 pageInfo_Privacy_Strong1=The page you are viewing was encrypted before being transmitted over the Internet.
 pageInfo_Privacy_Strong2=Encryption makes it very difficult for unauthorized people to view information traveling between computers. It is therefore very unlikely that anyone read this page as it traveled across the network.
 # LOCALIZATION NOTE (pageInfo_WeakEncryptionWithBits): %1$S is the name of the encryption standard,
 # %2$S is the key size of the cipher.
-pageInfo_WeakEncryptionWithBits=Connection Encrypted: Low-grade Encryption (%1$S, %2$S bit keys)
+# %3$S is protocol version like "SSL 3" or "TLS 1.2"
+pageInfo_WeakEncryptionWithBitsAndProtocol=Connection Encrypted: Low-grade Encryption (%1$S, %2$S bit keys, %3$S)
 pageInfo_Privacy_Weak1=The website %S is using low-grade encryption for the page you are viewing.
 pageInfo_Privacy_Weak2=Low-grade encryption may allow some unauthorized people to view this information.
 pageInfo_MixedContent=Connection Partially Encrypted
 pageInfo_Privacy_Mixed1=Parts of the page you are viewing were not encrypted before being transmitted over the Internet.
 
 #Cert Viewer
 certDetails=Certificate Viewer:
 notPresent=<Not Part Of Certificate>
--- a/security/manager/ssl/public/nsISSLStatus.idl
+++ b/security/manager/ssl/public/nsISSLStatus.idl
@@ -3,30 +3,36 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
 interface nsIX509Cert;
 
-[scriptable, uuid(3f1fcd83-c5a9-4cd1-a250-7676ca7c7e34)]
+[scriptable, uuid(fa9ba95b-ca3b-498a-b889-7c79cf28fee8)]
 interface nsISSLStatus : nsISupports {
   readonly attribute nsIX509Cert serverCert;
 
-  readonly attribute string cipherName;
+  readonly attribute ACString cipherName;
   readonly attribute unsigned long keyLength;
   readonly attribute unsigned long secretKeyLength;
 
+  const short SSL_VERSION_3   = 0;
+  const short TLS_VERSION_1   = 1;
+  const short TLS_VERSION_1_1 = 2;
+  const short TLS_VERSION_1_2 = 3;
+  readonly attribute unsigned short protocolVersion;
+
   readonly attribute boolean isDomainMismatch;
   readonly attribute boolean isNotValidAtThisTime;
 
-  /* Note: To distinguish between 
+  /* Note: To distinguish between
    *         "unstrusted because missing or untrusted issuer"
-   *       and 
+   *       and
    *         "untrusted because self signed"
    *       query nsIX509Cert::isSelfSigned
    */
   readonly attribute boolean isUntrusted;
 
   /**
    * True only if (and after) serverCert was successfully validated as
    * Extended Validation (EV).
--- a/security/manager/ssl/src/TransportSecurityInfo.cpp
+++ b/security/manager/ssl/src/TransportSecurityInfo.cpp
@@ -284,18 +284,18 @@ TransportSecurityInfo::GetInterface(cons
   }
   return rv;
 }
 
 // This is a new magic value. However, it re-uses the first 4 bytes
 // of the previous value. This is so when older versions attempt to
 // read a newer serialized TransportSecurityInfo, they will actually
 // fail and return NS_ERROR_FAILURE instead of silently failing.
-#define TRANSPORTSECURITYINFOMAGIC { 0xa9863a23, 0xda1f, 0x4008, \
-  { 0xac, 0x3c, 0x52, 0x86, 0x21, 0x54, 0x10, 0x70 } }
+#define TRANSPORTSECURITYINFOMAGIC { 0xa9863a23, 0x2429, 0x4866, \
+  { 0x92, 0x89, 0x45, 0x51, 0xc2, 0x01, 0xca, 0xf2 } }
 static NS_DEFINE_CID(kTransportSecurityInfoMagic, TRANSPORTSECURITYINFOMAGIC);
 
 NS_IMETHODIMP
 TransportSecurityInfo::Write(nsIObjectOutputStream* stream)
 {
   nsresult rv = stream->WriteID(kTransportSecurityInfoMagic);
   if (NS_FAILED(rv)) {
     return rv;
--- a/security/manager/ssl/src/nsNSSCallbacks.cpp
+++ b/security/manager/ssl/src/nsNSSCallbacks.cpp
@@ -887,20 +887,19 @@ PreliminaryHandshakeDone(PRFileDesc* fd)
                                sizeof cipherInfo) == SECSuccess) {
       /* Set the SSL Status information */
       RefPtr<nsSSLStatus> status(infoObject->SSLStatus());
       if (!status) {
         status = new nsSSLStatus();
         infoObject->SetSSLStatus(status);
       }
 
-      status->mHaveKeyLengthAndCipher = true;
-      status->mKeyLength = cipherInfo.symKeyBits;
-      status->mSecretKeyLength = cipherInfo.effectiveKeyBits;
-      status->mCipherName.Assign(cipherInfo.cipherSuiteName);
+      status->mHaveCipherSuiteAndProtocol = true;
+      status->mCipherSuite = channelInfo.cipherSuite;
+      status->mProtocolVersion = channelInfo.protocolVersion & 0xFF;
       infoObject->SetKEAUsed(cipherInfo.keaType);
       infoObject->SetKEAKeyBits(channelInfo.keaKeyBits);
       infoObject->SetMACAlgorithmUsed(cipherInfo.macAlgorithm);
     }
   }
 
   // Get the NPN value.
   SSLNextProtoState state;
--- a/security/manager/ssl/src/nsSSLStatus.cpp
+++ b/security/manager/ssl/src/nsSSLStatus.cpp
@@ -6,259 +6,281 @@
 
 #include "nsSSLStatus.h"
 #include "plstr.h"
 #include "nsIClassInfoImpl.h"
 #include "nsIIdentityInfo.h"
 #include "nsIProgrammingLanguage.h"
 #include "nsIObjectOutputStream.h"
 #include "nsIObjectInputStream.h"
+#include "ssl.h"
 
 NS_IMETHODIMP
-nsSSLStatus::GetServerCert(nsIX509Cert** _result)
+nsSSLStatus::GetServerCert(nsIX509Cert** aServerCert)
 {
-  NS_ASSERTION(_result, "non-NULL destination required");
+  NS_ENSURE_ARG_POINTER(aServerCert);
 
-  *_result = mServerCert;
-  NS_IF_ADDREF(*_result);
-
+  nsCOMPtr<nsIX509Cert> cert = mServerCert;
+  cert.forget(aServerCert);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsSSLStatus::GetKeyLength(uint32_t* _result)
+nsSSLStatus::GetKeyLength(uint32_t* aKeyLength)
 {
-  NS_ASSERTION(_result, "non-NULL destination required");
-  if (!mHaveKeyLengthAndCipher)
+  NS_ENSURE_ARG_POINTER(aKeyLength);
+  if (!mHaveCipherSuiteAndProtocol) {
     return NS_ERROR_NOT_AVAILABLE;
+  }
 
-  *_result = mKeyLength;
+  SSLCipherSuiteInfo cipherInfo;
+  if (SSL_GetCipherSuiteInfo(mCipherSuite, &cipherInfo,
+                             sizeof(cipherInfo)) != SECSuccess) {
+    return NS_ERROR_FAILURE;
+  }
 
+  *aKeyLength = cipherInfo.symKeyBits;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsSSLStatus::GetSecretKeyLength(uint32_t* _result)
+nsSSLStatus::GetSecretKeyLength(uint32_t* aSecretKeyLength)
 {
-  NS_ASSERTION(_result, "non-NULL destination required");
-  if (!mHaveKeyLengthAndCipher)
+  NS_ENSURE_ARG_POINTER(aSecretKeyLength);
+  if (!mHaveCipherSuiteAndProtocol) {
     return NS_ERROR_NOT_AVAILABLE;
+  }
 
-  *_result = mSecretKeyLength;
+  SSLCipherSuiteInfo cipherInfo;
+  if (SSL_GetCipherSuiteInfo(mCipherSuite, &cipherInfo,
+                             sizeof(cipherInfo)) != SECSuccess) {
+    return NS_ERROR_FAILURE;
+  }
 
+  *aSecretKeyLength = cipherInfo.effectiveKeyBits;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsSSLStatus::GetCipherName(char** _result)
+nsSSLStatus::GetCipherName(nsACString& aCipherName)
 {
-  NS_ASSERTION(_result, "non-NULL destination required");
-  if (!mHaveKeyLengthAndCipher)
+  if (!mHaveCipherSuiteAndProtocol) {
     return NS_ERROR_NOT_AVAILABLE;
+  }
 
-  *_result = ToNewCString(mCipherName);
+  SSLCipherSuiteInfo cipherInfo;
+  if (SSL_GetCipherSuiteInfo(mCipherSuite, &cipherInfo,
+                             sizeof(cipherInfo)) != SECSuccess) {
+    return NS_ERROR_FAILURE;
+  }
 
+  aCipherName.Assign(cipherInfo.cipherSuiteName);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsSSLStatus::GetIsDomainMismatch(bool* _result)
+nsSSLStatus::GetProtocolVersion(uint16_t* aProtocolVersion)
 {
-  NS_ASSERTION(_result, "non-NULL destination required");
+  NS_ENSURE_ARG_POINTER(aProtocolVersion);
+  if (!mHaveCipherSuiteAndProtocol) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
 
-  *_result = mHaveCertErrorBits && mIsDomainMismatch;
-
+  *aProtocolVersion = mProtocolVersion;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsSSLStatus::GetIsNotValidAtThisTime(bool* _result)
+nsSSLStatus::GetIsDomainMismatch(bool* aIsDomainMismatch)
 {
-  NS_ASSERTION(_result, "non-NULL destination required");
+  NS_ENSURE_ARG_POINTER(aIsDomainMismatch);
 
-  *_result = mHaveCertErrorBits && mIsNotValidAtThisTime;
-
+  *aIsDomainMismatch = mHaveCertErrorBits && mIsDomainMismatch;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsSSLStatus::GetIsUntrusted(bool* _result)
+nsSSLStatus::GetIsNotValidAtThisTime(bool* aIsNotValidAtThisTime)
 {
-  NS_ASSERTION(_result, "non-NULL destination required");
+  NS_ENSURE_ARG_POINTER(aIsNotValidAtThisTime);
+
+  *aIsNotValidAtThisTime = mHaveCertErrorBits && mIsNotValidAtThisTime;
+  return NS_OK;
+}
 
-  *_result = mHaveCertErrorBits && mIsUntrusted;
+NS_IMETHODIMP
+nsSSLStatus::GetIsUntrusted(bool* aIsUntrusted)
+{
+  NS_ENSURE_ARG_POINTER(aIsUntrusted);
 
+  *aIsUntrusted = mHaveCertErrorBits && mIsUntrusted;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsSSLStatus::GetIsExtendedValidation(bool* aIsEV)
 {
   NS_ENSURE_ARG_POINTER(aIsEV);
   *aIsEV = false;
 
 #ifdef MOZ_NO_EV_CERTS
   return NS_OK;
 #else
   nsCOMPtr<nsIX509Cert> cert = mServerCert;
-  nsresult rv;
-  nsCOMPtr<nsIIdentityInfo> idinfo = do_QueryInterface(cert, &rv);
-
   // mServerCert should never be null when this method is called because
   // nsSSLStatus objects always have mServerCert set right after they are
   // constructed and before they are returned. GetIsExtendedValidation should
   // only be called in the chrome process (in e10s), and mServerCert will always
   // implement nsIIdentityInfo in the chrome process.
+  nsCOMPtr<nsIIdentityInfo> idinfo = do_QueryInterface(cert);
   if (!idinfo) {
     NS_ERROR("nsSSLStatus has null mServerCert or was called in the content "
              "process");
     return NS_ERROR_UNEXPECTED;
   }
 
   // Never allow bad certs for EV, regardless of overrides.
   if (mHaveCertErrorBits) {
     return NS_OK;
   }
 
   return idinfo->GetIsExtendedValidation(aIsEV);
 #endif
 }
 
 NS_IMETHODIMP
-nsSSLStatus::Read(nsIObjectInputStream* stream)
+nsSSLStatus::Read(nsIObjectInputStream* aStream)
 {
   nsCOMPtr<nsISupports> cert;
-  nsresult rv = stream->ReadObject(true, getter_AddRefs(cert));
+  nsresult rv = aStream->ReadObject(true, getter_AddRefs(cert));
   NS_ENSURE_SUCCESS(rv, rv);
 
   mServerCert = do_QueryInterface(cert);
-  if (!mServerCert)
+  if (!mServerCert) {
     return NS_NOINTERFACE;
+  }
 
-  rv = stream->Read32(&mKeyLength);
+  rv = aStream->Read16(&mCipherSuite);
   NS_ENSURE_SUCCESS(rv, rv);
-  rv = stream->Read32(&mSecretKeyLength);
-  NS_ENSURE_SUCCESS(rv, rv);
-  rv = stream->ReadCString(mCipherName);
+  rv = aStream->Read16(&mProtocolVersion);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = stream->ReadBoolean(&mIsDomainMismatch);
+  rv = aStream->ReadBoolean(&mIsDomainMismatch);
   NS_ENSURE_SUCCESS(rv, rv);
-  rv = stream->ReadBoolean(&mIsNotValidAtThisTime);
+  rv = aStream->ReadBoolean(&mIsNotValidAtThisTime);
   NS_ENSURE_SUCCESS(rv, rv);
-  rv = stream->ReadBoolean(&mIsUntrusted);
+  rv = aStream->ReadBoolean(&mIsUntrusted);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = stream->ReadBoolean(&mHaveKeyLengthAndCipher);
+  rv = aStream->ReadBoolean(&mHaveCipherSuiteAndProtocol);
   NS_ENSURE_SUCCESS(rv, rv);
-  rv = stream->ReadBoolean(&mHaveCertErrorBits);
+  rv = aStream->ReadBoolean(&mHaveCertErrorBits);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsSSLStatus::Write(nsIObjectOutputStream* stream)
+nsSSLStatus::Write(nsIObjectOutputStream* aStream)
 {
-  nsresult rv = stream->WriteCompoundObject(mServerCert,
-                                            NS_GET_IID(nsIX509Cert),
-                                            true);
+  nsresult rv = aStream->WriteCompoundObject(mServerCert,
+                                             NS_GET_IID(nsIX509Cert),
+                                             true);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = stream->Write32(mKeyLength);
+  rv = aStream->Write16(mCipherSuite);
   NS_ENSURE_SUCCESS(rv, rv);
-  rv = stream->Write32(mSecretKeyLength);
-  NS_ENSURE_SUCCESS(rv, rv);
-  rv = stream->WriteStringZ(mCipherName.get());
+  rv = aStream->Write16(mProtocolVersion);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = stream->WriteBoolean(mIsDomainMismatch);
+  rv = aStream->WriteBoolean(mIsDomainMismatch);
   NS_ENSURE_SUCCESS(rv, rv);
-  rv = stream->WriteBoolean(mIsNotValidAtThisTime);
+  rv = aStream->WriteBoolean(mIsNotValidAtThisTime);
   NS_ENSURE_SUCCESS(rv, rv);
-  rv = stream->WriteBoolean(mIsUntrusted);
+  rv = aStream->WriteBoolean(mIsUntrusted);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = stream->WriteBoolean(mHaveKeyLengthAndCipher);
+  rv = aStream->WriteBoolean(mHaveCipherSuiteAndProtocol);
   NS_ENSURE_SUCCESS(rv, rv);
-  rv = stream->WriteBoolean(mHaveCertErrorBits);
+  rv = aStream->WriteBoolean(mHaveCertErrorBits);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsSSLStatus::GetInterfaces(uint32_t *count, nsIID * **array)
+nsSSLStatus::GetInterfaces(uint32_t* aCount, nsIID*** aArray)
 {
-  *count = 0;
-  *array = nullptr;
+  *aCount = 0;
+  *aArray = nullptr;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsSSLStatus::GetHelperForLanguage(uint32_t language, nsISupports **_retval)
+nsSSLStatus::GetHelperForLanguage(uint32_t aLanguage, nsISupports** aHelper)
 {
-  *_retval = nullptr;
+  *aHelper = nullptr;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsSSLStatus::GetContractID(char * *aContractID)
+nsSSLStatus::GetContractID(char** aContractID)
 {
   *aContractID = nullptr;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsSSLStatus::GetClassDescription(char * *aClassDescription)
+nsSSLStatus::GetClassDescription(char** aClassDescription)
 {
   *aClassDescription = nullptr;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsSSLStatus::GetClassID(nsCID * *aClassID)
+nsSSLStatus::GetClassID(nsCID** aClassID)
 {
   *aClassID = (nsCID*) nsMemory::Alloc(sizeof(nsCID));
-  if (!*aClassID)
+  if (!*aClassID) {
     return NS_ERROR_OUT_OF_MEMORY;
+  }
   return GetClassIDNoAlloc(*aClassID);
 }
 
 NS_IMETHODIMP
-nsSSLStatus::GetImplementationLanguage(uint32_t *aImplementationLanguage)
+nsSSLStatus::GetImplementationLanguage(uint32_t* aImplementationLanguage)
 {
   *aImplementationLanguage = nsIProgrammingLanguage::CPLUSPLUS;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsSSLStatus::GetFlags(uint32_t *aFlags)
+nsSSLStatus::GetFlags(uint32_t* aFlags)
 {
   *aFlags = 0;
   return NS_OK;
 }
 
 static NS_DEFINE_CID(kSSLStatusCID, NS_SSLSTATUS_CID);
 
 NS_IMETHODIMP
-nsSSLStatus::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)
+nsSSLStatus::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc)
 {
   *aClassIDNoAlloc = kSSLStatusCID;
   return NS_OK;
 }
 
 nsSSLStatus::nsSSLStatus()
-: mKeyLength(0), mSecretKeyLength(0)
+: mCipherSuite(0)
+, mProtocolVersion(0)
 , mIsDomainMismatch(false)
 , mIsNotValidAtThisTime(false)
 , mIsUntrusted(false)
-, mHaveKeyLengthAndCipher(false)
+, mHaveCipherSuiteAndProtocol(false)
 , mHaveCertErrorBits(false)
 {
-  mCipherName = "";
 }
 
 NS_IMPL_ISUPPORTS(nsSSLStatus, nsISSLStatus, nsISerializable, nsIClassInfo)
 
 nsSSLStatus::~nsSSLStatus()
 {
 }
--- a/security/manager/ssl/src/nsSSLStatus.h
+++ b/security/manager/ssl/src/nsSSLStatus.h
@@ -27,29 +27,27 @@ public:
   NS_DECL_NSISERIALIZABLE
   NS_DECL_NSICLASSINFO
 
   nsSSLStatus();
 
   /* public for initilization in this file */
   nsCOMPtr<nsIX509Cert> mServerCert;
 
-  uint32_t mKeyLength;
-  uint32_t mSecretKeyLength;
-  nsXPIDLCString mCipherName;
+  uint16_t mCipherSuite;
+  uint16_t mProtocolVersion;
 
   bool mIsDomainMismatch;
   bool mIsNotValidAtThisTime;
   bool mIsUntrusted;
 
-  bool mHaveKeyLengthAndCipher;
+  bool mHaveCipherSuiteAndProtocol;
 
   /* mHaveCertErrrorBits is relied on to determine whether or not a SPDY
      connection is eligible for joining in nsNSSSocketInfo::JoinConnection() */
   bool mHaveCertErrorBits;
 };
 
-// 2c3837af-8b85-4a68-b0d8-0aed88985b32
 #define NS_SSLSTATUS_CID \
-{ 0x2c3837af, 0x8b85, 0x4a68, \
-  { 0xb0, 0xd8, 0x0a, 0xed, 0x88, 0x98, 0x5b, 0x32 } }
+{ 0x61f69c85, 0x0fed, 0x44fb, \
+  { 0x89, 0x8f, 0xa4, 0xb1, 0x3c, 0x33, 0x3c, 0x8d } }
 
 #endif
--- a/security/pkix/lib/pkixocsp.cpp
+++ b/security/pkix/lib/pkixocsp.cpp
@@ -776,16 +776,19 @@ KeyHash(TrustDomain& trustDomain, const 
   //
   // SubjectPublicKeyInfo  ::=  SEQUENCE  {
   //    algorithm            AlgorithmIdentifier,
   //    subjectPublicKey     BIT STRING  }
 
   Reader spki;
   Result rv = der::ExpectTagAndGetValueAtEnd(subjectPublicKeyInfo,
                                              der::SEQUENCE, spki);
+  if (rv != Success) {
+    return rv;
+  }
 
   // Skip AlgorithmIdentifier
   rv = der::ExpectTagAndSkipValue(spki, der::SEQUENCE);
   if (rv != Success) {
     return rv;
   }
 
   Input subjectPublicKey;
--- a/testing/mozbase/mozdevice/mozdevice/droid.py
+++ b/testing/mozbase/mozdevice/mozdevice/droid.py
@@ -168,17 +168,21 @@ class DroidADB(DeviceManagerADB, DroidMi
             m = re.search('FocusedApplication(.+)/', data)
         if m:
             line = m.group(0)
             # Extract package name: string of non-whitespace ending in forward slash
             m = re.search('(\S+)/$', line)
             if m:
                 package = m.group(1)
         if not package:
-            raise DMError("unable to find focused app")
+            # On some Android 4.4 devices, when the home screen is displayed,
+            # dumpsys reports "mFocusedApp=null". Guard against this case and
+            # others where the focused app can not be determined by returning
+            # an empty string -- same as sutagent.
+            package = ""
         return package
 
     def getAppRoot(self, packageName):
         """
         Returns the root directory for the specified android application
         """
         # relying on convention
         return '/data/data/%s' % packageName
--- a/toolkit/components/workerloader/require.js
+++ b/toolkit/components/workerloader/require.js
@@ -55,90 +55,39 @@
      * Mapping from module paths to module exports.
      *
      * @keys {string} The absolute path to a module.
      * @values {object} The |exports| objects for that module.
      */
     let modules = new Map();
 
     /**
-     * Mapping from object urls to module paths.
-     */
-    let paths = {
-      /**
-       * @keys {string} The object url holding a module.
-       * @values {string} The absolute path to that module.
-       */
-      _map: new Map(),
-      /**
-       * A regexp that may be used to search for all mapped paths.
-       */
-      get regexp() {
-        if (this._regexp) {
-          return this._regexp;
-        }
-        let objectURLs = [];
-        for (let [objectURL, _] of this._map) {
-          objectURLs.push(objectURL);
-        }
-        return this._regexp = new RegExp(objectURLs.join("|"), "g");
-      },
-      _regexp: null,
-      /**
-       * Add a mapping from an object url to a path.
-       */
-      set: function(url, path) {
-        this._regexp = null; // invalidate regexp
-        this._map.set(url, path);
-      },
-      /**
-       * Get a mapping from an object url to a path.
-       */
-      get: function(url) {
-        return this._map.get(url);
-      },
-      /**
-       * Transform a string by replacing all the instances of objectURLs
-       * appearing in that string with the corresponding module path.
-       *
-       * This is used typically to translate exception stacks.
-       *
-       * @param {string} source A source string.
-       * @return {string} The same string as |source|, in which every occurrence
-       * of an objectURL registered in this object has been replaced with the
-       * corresponding module path.
-       */
-      substitute: function(source) {
-        let map = this._map;
-        return source.replace(this.regexp, function(url) {
-          return map.get(url) || url;
-        }, "g");
-      }
-    };
-
-    /**
      * A human-readable version of |stack|.
      *
      * @type {string}
      */
     Object.defineProperty(Error.prototype, "moduleStack",
     {
       get: function() {
-        return paths.substitute(this.stack);
+        return this.stack;
       }
     });
     /**
      * A human-readable version of |fileName|.
      *
      * @type {string}
      */
     Object.defineProperty(Error.prototype, "moduleName",
     {
       get: function() {
-        return paths.substitute(this.fileName);
+        let match = this.stack.match(/\@(.*):.*:/);
+        if (match) {
+          return match[1];
+        }
+        return "(unknown module)";
       }
     });
 
     /**
      * Import a module
      *
      * @param {string} path The path to the module.
      * @return {*} An object containing the properties exported by the module.
@@ -182,62 +131,33 @@
         xhr.send();
 
 
         let source = xhr.responseText;
         if (source == "") {
           // There doesn't seem to be a better way to detect that the file couldn't be found
           throw new Error("Could not find module " + path);
         }
-        // From the source, build a function and an object URL. We
-        // avoid any newline at the start of the file to ensure that
-        // we do not mess up with line numbers. However, using object URLs
-        // messes up with stack traces in instances of Error().
-        source = "require._tmpModules[\"" + name + "\"] = " +
-          "function(exports, require, module) {" +
-          source +
-        "\n}\n";
-        let blob = new Blob(
-          [
-            (new TextEncoder()).encode(source)
-          ], {
-            type: "application/javascript"
-          });
-        objectURL = URL.createObjectURL(blob);
-        paths.set(objectURL, path);
-        importScripts(objectURL);
-        require._tmpModules[name].call(null, exports, require, module);
-
+        let code = new Function("exports", "require", "module",
+          source + "\n//# sourceURL=" + uri + "\n"
+        );
+        code(exports, require, module);
       } catch (ex) {
         // Module loading has failed, exports should not be made available
         // after all.
         modules.delete(path);
         throw ex;
-      } finally {
-        if (objectURL) {
-          // Clean up the object url as soon as possible. It will not be needed.
-          URL.revokeObjectURL(objectURL);
-        }
-        delete require._tmpModules[name];
       }
 
       Object.freeze(module.exports);
       Object.freeze(module);
       return module.exports;
     };
   })();
 
-  /**
-   * An object used to hold temporarily the module constructors
-   * while they are being loaded.
-   *
-   * @keys {string} The path to the module, prefixed with ":".
-   * @values {function} A function wrapping the module.
-   */
-  require._tmpModules = Object.create(null);
   Object.freeze(require);
 
   Object.defineProperty(exports, "require", {
     value: require,
     enumerable: true,
     configurable: false
   });
 })(this);
--- a/widget/windows/winrt/UIABridge.cpp
+++ b/widget/windows/winrt/UIABridge.cpp
@@ -145,19 +145,19 @@ UIABridge::ClearFocus()
 static void
 DumpChildInfo(nsRefPtr<Accessible>& aChild)
 {
 #ifdef DEBUG
   if (!aChild) {
     return;
   }
   nsString str;
-  aChild->GetName(str);
+  aChild->Name(str);
   BridgeLog("name: %ls", str.BeginReading());
-  aChild->GetDescription(str);
+  aChild->Description(str);
   BridgeLog("description: %ls", str.BeginReading());
 #endif
 }
 
 static bool
 ChildHasFocus(nsRefPtr<Accessible>& aChild)
 {
   BridgeLog("Focus element flags: editable:%d focusable:%d readonly:%d",
@@ -552,25 +552,24 @@ UIATextElement::get_BoundingRectangle(Ui
 {
   LogFunction();
   
   if (!mAccessItem) {
     return UIA_E_ELEMENTNOTAVAILABLE;
   }
 
   // bounds are in physical pixels
-  int32_t docX = 0, docY = 0, docWidth = 0, docHeight = 0;
-  mAccessItem->GetBounds(&docX, &docY, &docWidth, &docHeight);
-  
-  retVal->left = (float)docX;
-  retVal->top = (float)docY;
-  retVal->width = (float)docWidth;
-  retVal->height = (float)docHeight;
+  nsIntRect rect = mAccessItem->Bounds();
 
-  BridgeLog("get_BoundingRectangle: left=%d top=%d right=%d bottom=%d", docX, docY, docX + docWidth, docY + docHeight);
+  retVal->left = rect.x;
+  retVal->top = rect.y;
+  retVal->width = rect.width;
+  retVal->height = rect.height;
+
+  BridgeLog("get_BoundingRectangle: left=%d top=%d right=%d bottom=%d", rect.x, rect.y, rect.x + rect.width, rect.y + rect.height);
   return S_OK;
 }
 
 HRESULT
 UIATextElement::GetEmbeddedFragmentRoots(SAFEARRAY ** retVal)
 {
   *retVal = nullptr;
   return S_OK;
@@ -691,17 +690,16 @@ UIATextElement::GetPropertyValue(PROPERT
 
     case UIA_LocalizedControlTypePropertyId:
     case UIA_LabeledByPropertyId:
       break;
 
     case UIA_HasKeyboardFocusPropertyId:
     {
       if (mAccessItem) {
-        uint32_t state, extraState;
         if (mAccessItem->NativeState() & mozilla::a11y::states::FOCUSED) {
           pRetVal->vt = VT_BOOL;
           pRetVal->boolVal = VARIANT_TRUE;
           return S_OK;
         }
       }
       pRetVal->vt = VT_BOOL;
       pRetVal->boolVal = VARIANT_FALSE;
--- a/widget/windows/winrt/UIABridgePrivate.h
+++ b/widget/windows/winrt/UIABridgePrivate.h
@@ -128,12 +128,12 @@ public:
   IFACEMETHODIMP get_IsReadOnly(BOOL *pRetVal);
 
   void SetIndexID(int id) {
     mIndexID = id;
   }
 
 private:
   int mIndexID;
-  nsRefPtr<Accessible> mAccessItem;
+  nsRefPtr<a11y::Accessible> mAccessItem;
 };
 
 } } }