Merge inbound to m-c. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Thu, 18 Dec 2014 17:59:14 -0500
changeset 246245 1427b365cd39118bcec66d232c62d4c806b66b46
parent 246212 9acb15a52030764ee4dca78905995f6b9edecd15 (current diff)
parent 246244 def6ed9d1c1a06efdb0cc6a43ce66550c45c0a72 (diff)
child 246246 b5b0aa7b124d77aaa5bf1371c18fe8eb66ddfad7
child 246267 8ad1a662bf1f520d68a6e3fd88a4c7bd8aa6ab9d
child 246332 9681f98152a136899255b469a5c2ec5c36d87230
push id4489
push userraliiev@mozilla.com
push dateMon, 23 Feb 2015 15:17:55 +0000
treeherdermozilla-beta@fd7c3dc24146 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone37.0a1
first release with
nightly linux32
1427b365cd39 / 37.0a1 / 20141219030202 / files
nightly linux64
1427b365cd39 / 37.0a1 / 20141219030202 / files
nightly mac
1427b365cd39 / 37.0a1 / 20141219030202 / files
nightly win32
1427b365cd39 / 37.0a1 / 20141219030202 / files
nightly win64
1427b365cd39 / 37.0a1 / 20141219030202 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to m-c. a=merge
--- a/dom/apps/AppsServiceChild.jsm
+++ b/dom/apps/AppsServiceChild.jsm
@@ -98,33 +98,38 @@ this.DOMApplicationRegistry = {
   init: function init() {
     this.cpmm = Cc["@mozilla.org/childprocessmessagemanager;1"]
                   .getService(Ci.nsISyncMessageSender);
 
     APPS_IPC_MSG_NAMES.forEach((function(aMsgName) {
       this.cpmm.addMessageListener(aMsgName, this);
     }).bind(this));
 
+    this.resetList();
+
+    Services.obs.addObserver(this, "xpcom-shutdown", false);
+  },
+
+  resetList: function() {
     this.cpmm.sendAsyncMessage("Webapps:RegisterForMessages", {
       messages: APPS_IPC_MSG_NAMES
     });
 
     // We need to prime the cache with the list of apps.
     let list = this.cpmm.sendSyncMessage("Webapps:GetList", { })[0];
     this.webapps = list.webapps;
+
     // We need a fast mapping from localId -> app, so we add an index.
     // We also add the manifest to the app object.
     this.localIdIndex = { };
     for (let id in this.webapps) {
       let app = this.webapps[id];
       this.localIdIndex[app.localId] = app;
       app.manifest = list.manifests[id];
     }
-
-    Services.obs.addObserver(this, "xpcom-shutdown", false);
   },
 
   observe: function(aSubject, aTopic, aData) {
     // cpmm.addMessageListener causes the DOMApplicationRegistry object to
     // live forever if we don't clean up properly.
     this.webapps = null;
     this.DOMApps = null;
 
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -10,16 +10,17 @@
 #include "Navigator.h"
 #include "nsIXULAppInfo.h"
 #include "nsPluginArray.h"
 #include "nsMimeTypeArray.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/dom/DesktopNotification.h"
 #include "mozilla/dom/File.h"
 #include "nsGeolocation.h"
+#include "nsIClassOfService.h"
 #include "nsIHttpProtocolHandler.h"
 #include "nsIContentPolicy.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsContentPolicyUtils.h"
 #include "nsCrossSiteListenerProxy.h"
 #include "nsISupportsPriority.h"
 #include "nsICachingChannel.h"
 #include "nsIWebContentHandlerRegistrar.h"
@@ -1185,16 +1186,21 @@ Navigator::SendBeacon(const nsAString& a
     httpChannel->SetRequestMethod(NS_LITERAL_CSTRING("POST"));
   }
 
   nsCOMPtr<nsISupportsPriority> p = do_QueryInterface(channel);
   if (p) {
     p->SetPriority(nsISupportsPriority::PRIORITY_LOWEST);
   }
 
+  nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(channel));
+  if (cos) {
+    cos->AddClassFlags(nsIClassOfService::Background);
+  }
+
   nsRefPtr<nsCORSListenerProxy> cors = new nsCORSListenerProxy(new BeaconStreamListener(),
                                                                principal,
                                                                true);
 
   // Start a preflight if cross-origin and content type is not whitelisted
   rv = secMan->CheckSameOriginURI(documentURI, uri, false);
   bool crossOrigin = NS_FAILED(rv);
   nsAutoCString contentType, parsedCharset;
--- a/dom/base/nsScriptLoader.cpp
+++ b/dom/base/nsScriptLoader.cpp
@@ -22,17 +22,17 @@
 #include "nsIJSRuntimeService.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIScriptContext.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIPrincipal.h"
 #include "nsJSPrincipals.h"
 #include "nsContentPolicyUtils.h"
 #include "nsIHttpChannel.h"
-#include "nsIHttpChannelInternal.h"
+#include "nsIClassOfService.h"
 #include "nsITimedChannel.h"
 #include "nsIScriptElement.h"
 #include "nsIDOMHTMLScriptElement.h"
 #include "nsIDocShell.h"
 #include "nsContentUtils.h"
 #include "nsUnicharUtils.h"
 #include "nsAutoPtr.h"
 #include "nsIXPConnect.h"
@@ -316,28 +316,27 @@ nsScriptLoader::StartLoad(nsScriptLoadRe
                      loadGroup,
                      prompter,
                      nsIRequest::LOAD_NORMAL |
                      nsIChannel::LOAD_CLASSIFY_URI);
 
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsIScriptElement *script = aRequest->mElement;
-  nsCOMPtr<nsIHttpChannelInternal>
-    internalHttpChannel(do_QueryInterface(channel));
+  nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(channel));
 
-  if (internalHttpChannel) {
+  if (cos) {
     if (aScriptFromHead &&
         !(script && (script->GetScriptAsync() || script->GetScriptDeferred()))) {
       // synchronous head scripts block lading of most other non js/css
       // content such as images
-      internalHttpChannel->SetLoadAsBlocking(true);
+      cos->AddClassFlags(nsIClassOfService::Leader);
     } else if (!(script && script->GetScriptDeferred())) {
       // other scripts are neither blocked nor prioritized unless marked deferred
-      internalHttpChannel->SetLoadUnblocked(true);
+      cos->AddClassFlags(nsIClassOfService::Unblocked);
     }
   }
 
   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
   if (httpChannel) {
     // HTTP content negotation has little value in this context.
     httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
                                   NS_LITERAL_CSTRING("*/*"),
--- a/dom/base/nsXMLHttpRequest.cpp
+++ b/dom/base/nsXMLHttpRequest.cpp
@@ -61,16 +61,17 @@
 #include "GeckoProfiler.h"
 #include "mozilla/dom/EncodingUtils.h"
 #include "nsIUnicodeDecoder.h"
 #include "mozilla/dom/XMLHttpRequestBinding.h"
 #include "mozilla/Attributes.h"
 #include "nsIPermissionManager.h"
 #include "nsMimeTypes.h"
 #include "nsIHttpChannelInternal.h"
+#include "nsIClassOfService.h"
 #include "nsCharSeparatedTokenizer.h"
 #include "nsFormData.h"
 #include "nsStreamListenerWrapper.h"
 #include "xpcjsid.h"
 #include "nsITimedChannel.h"
 #include "nsWrapperCacheInlines.h"
 #include "nsZipArchive.h"
 #include "mozilla/Preferences.h"
@@ -2398,20 +2399,18 @@ nsXMLHttpRequest::SendAsBinary(const nsA
 static nsresult
 GetRequestBody(nsIDOMDocument* aDoc, nsIInputStream** aResult,
                uint64_t* aContentLength, nsACString& aContentType,
                nsACString& aCharset)
 {
   aContentType.AssignLiteral("application/xml");
   nsCOMPtr<nsIDocument> doc(do_QueryInterface(aDoc));
   NS_ENSURE_STATE(doc);
-  aCharset = doc->GetDocumentCharacterSet();
-
-  // Serialize to a stream so that the encoding used will
-  // match the document's.
+  aCharset.AssignLiteral("UTF-8");
+
   nsresult rv;
   nsCOMPtr<nsIDOMSerializer> serializer =
     do_CreateInstance(NS_XMLSERIALIZER_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIStorageStream> storStream;
   rv = NS_NewStorageStream(4096, UINT32_MAX, getter_AddRefs(storStream));
   NS_ENSURE_SUCCESS(rv, rv);
@@ -2886,24 +2885,27 @@ nsXMLHttpRequest::Send(nsIVariant* aVari
   // Hook us up to listen to redirects and the like
   mChannel->GetNotificationCallbacks(getter_AddRefs(mNotificationCallbacks));
   mChannel->SetNotificationCallbacks(this);
 
   // Blocking gets are common enough out of XHR that we should mark
   // the channel slow by default for pipeline purposes
   AddLoadFlags(mChannel, nsIRequest::INHIBIT_PIPELINE);
 
+  nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(mChannel));
+  if (cos) {
+    // we never let XHR be blocked by head CSS/JS loads to avoid
+    // potential deadlock where server generation of CSS/JS requires
+    // an XHR signal.
+    cos->AddClassFlags(nsIClassOfService::Unblocked);
+  }
+
   nsCOMPtr<nsIHttpChannelInternal>
     internalHttpChannel(do_QueryInterface(mChannel));
   if (internalHttpChannel) {
-    // we never let XHR be blocked by head CSS/JS loads to avoid
-    // potential deadlock where server generation of CSS/JS requires
-    // an XHR signal.
-    internalHttpChannel->SetLoadUnblocked(true);
-
     // Disable Necko-internal response timeouts.
     internalHttpChannel->SetResponseTimeoutEnabled(false);
   }
 
   nsCOMPtr<nsIStreamListener> listener = this;
   if (!IsSystemXHR()) {
     // Always create a nsCORSListenerProxy here even if it's
     // a same-origin request right now, since it could be redirected.
--- a/dom/base/test/test_XHRSendData.html
+++ b/dom/base/test/test_XHRSendData.html
@@ -122,32 +122,32 @@ tests = [{ body: null,
          },
          { body: "hi",
            contentType: "foo/bar; charset=uTf-8",
            resBody: "hi",
            resContentType: "foo/bar; charset=uTf-8",
          },
          { body: testDoc1,
            resBody: "<!-- comment -->\n<out>hi</out>",
-           resContentType: "application/xml; charset=windows-1252",
+           resContentType: "application/xml; charset=UTF-8",
          },
          { body: testDoc1,
            contentType: "foo/bar",
            resBody: "<!-- comment -->\n<out>hi</out>",
-           resContentType: "foo/bar; charset=windows-1252",
+           resContentType: "foo/bar; charset=UTF-8",
          },
          { body: testDoc1,
            contentType: "foo/bar; charset=ascii; baz=bin",
            resBody: "<!-- comment -->\n<out>hi</out>",
-           resContentType: "foo/bar; charset=windows-1252; baz=bin",
+           resContentType: "foo/bar; charset=UTF-8; baz=bin",
          },
          { body: testDoc1,
            contentType: "foo/bar; charset=wIndows-1252",
            resBody: "<!-- comment -->\n<out>hi</out>",
-           resContentType: "foo/bar; charset=wIndows-1252",
+           resContentType: "foo/bar; charset=UTF-8",
          },
          { body: testDoc2,
            resBody: "<!-- doc 2 -->\n<res>text</res>",
            resContentType: "application/xml; charset=UTF-8",
          },
          { body: testDoc2,
            contentType: "foo/bar",
            resBody: "<!-- doc 2 -->\n<res>text</res>",
--- a/dom/camera/GonkCameraControl.cpp
+++ b/dom/camera/GonkCameraControl.cpp
@@ -898,16 +898,22 @@ nsGonkCameraControl::SetThumbnailSizeImp
   if (size.width > INT32_MAX || size.height > INT32_MAX) {
     DOM_CAMERA_LOGE("Supported thumbnail size is too big, no change\n");
     return NS_ERROR_FAILURE;
   }
 
   return SetAndPush(CAMERA_PARAM_THUMBNAILSIZE, size);
 }
 
+android::sp<android::GonkCameraHardware>
+nsGonkCameraControl::GetCameraHw()
+{
+  return mCameraHw;
+}
+
 nsresult
 nsGonkCameraControl::SetThumbnailSize(const Size& aSize)
 {
   class SetThumbnailSize : public nsRunnable
   {
   public:
     SetThumbnailSize(nsGonkCameraControl* aCameraControl, const Size& aSize)
       : mCameraControl(aCameraControl)
--- a/dom/camera/GonkCameraControl.h
+++ b/dom/camera/GonkCameraControl.h
@@ -27,16 +27,17 @@
 #include "GonkRecorder.h"
 #include "GonkCameraHwMgr.h"
 #include "GonkCameraParameters.h"
 
 namespace android {
   class GonkCameraHardware;
   class MediaProfiles;
   class GonkRecorder;
+  class GonkCameraSource;
 }
 
 namespace mozilla {
 
 namespace layers {
   class TextureClient;
   class ImageContainer;
 }
@@ -149,16 +150,19 @@ protected:
   friend class SetPictureSize;
   friend class SetThumbnailSize;
   nsresult SetPictureSize(const Size& aSize);
   nsresult SetPictureSizeImpl(const Size& aSize);
   nsresult SetThumbnailSize(const Size& aSize);
   nsresult UpdateThumbnailSize();
   nsresult SetThumbnailSizeImpl(const Size& aSize);
 
+  friend class android::GonkCameraSource;
+  android::sp<android::GonkCameraHardware> GetCameraHw();
+
   int32_t RationalizeRotation(int32_t aRotation);
 
   uint32_t                  mCameraId;
 
   android::sp<android::GonkCameraHardware> mCameraHw;
 
   Size                      mLastThumbnailSize;
   Size                      mLastRecorderSize;
--- a/dom/camera/GonkCameraSource.cpp
+++ b/dom/camera/GonkCameraSource.cpp
@@ -41,16 +41,17 @@
 #include <media/stagefright/MetaData.h>
 #include <camera/CameraParameters.h>
 #include <utils/String8.h>
 #include <cutils/properties.h>
 
 #include "GonkCameraSource.h"
 #include "GonkCameraListener.h"
 #include "GonkCameraHwMgr.h"
+#include "ICameraControl.h"
 
 using namespace mozilla;
 
 namespace android {
 
 static const int64_t CAMERA_SOURCE_TIMEOUT_NS = 3000000000LL;
 
 struct GonkCameraSourceListener : public GonkCameraListener {
@@ -152,16 +153,26 @@ GonkCameraSource *GonkCameraSource::Crea
     bool storeMetaDataInVideoBuffers) {
 
     GonkCameraSource *source = new GonkCameraSource(aCameraHw,
                     videoSize, frameRate,
                     storeMetaDataInVideoBuffers);
     return source;
 }
 
+GonkCameraSource *GonkCameraSource::Create(
+    ICameraControl* aControl,
+    Size videoSize,
+    int32_t frameRate)
+{
+    mozilla::nsGonkCameraControl* control =
+        static_cast<mozilla::nsGonkCameraControl*>(aControl);
+    return Create(control->GetCameraHw(), videoSize, frameRate, false);
+}
+
 GonkCameraSource::GonkCameraSource(
     const sp<GonkCameraHardware>& aCameraHw,
     Size videoSize,
     int32_t frameRate,
     bool storeMetaDataInVideoBuffers)
     : mCameraFlags(0),
       mNumInputBuffers(0),
       mVideoFrameRate(-1),
@@ -591,16 +602,20 @@ status_t GonkCameraSource::reset() {
     }
     stopCameraRecording();
     if (mRateLimit) {
       mRateLimit = false;
       mCameraHw->OnRateLimitPreview(false);
     }
     releaseCamera();
 
+    if (mDirectBufferListener.get()) {
+      mDirectBufferListener = nullptr;
+    }
+
     if (mCollectStats) {
         CS_LOGI("Frames received/encoded/dropped: %d/%d/%d in %lld us",
                 mNumFramesReceived, mNumFramesEncoded, mNumFramesDropped,
                 mLastFrameTimestampUs - mFirstFrameTimeUs);
     }
 
     if (mNumGlitches > 0) {
         CS_LOGW("%d long delays between neighboring video frames", mNumGlitches);
@@ -647,16 +662,24 @@ void GonkCameraSource::signalBufferRetur
             buffer->release();
             mFrameCompleteCondition.signal();
             return;
         }
     }
     CHECK(!"signalBufferReturned: bogus buffer");
 }
 
+status_t GonkCameraSource::AddDirectBufferListener(DirectBufferListener* aListener) {
+    if (mDirectBufferListener.get()) {
+        return UNKNOWN_ERROR;
+    }
+    mDirectBufferListener = aListener;
+    return OK;
+}
+
 status_t GonkCameraSource::read(
         MediaBuffer **buffer, const ReadOptions *options) {
     CS_LOGV("read");
 
     *buffer = NULL;
 
     int64_t seekTimeUs;
     ReadOptions::SeekMode mode;
@@ -756,16 +779,25 @@ void GonkCameraSource::dataCallbackTimes
         CS_LOGV("initial delay: %lld, current time stamp: %lld",
             mStartTimeUs, timeUs);
         mFrameAvailableCondition.signal();
     }
 
     if(prevRateLimit != rateLimit) {
         mCameraHw->OnRateLimitPreview(rateLimit);
     }
+
+    if (mDirectBufferListener.get()) {
+        MediaBuffer* mediaBuffer;
+        if (read(&mediaBuffer) == OK) {
+            mDirectBufferListener->BufferAvailable(mediaBuffer);
+            // read() calls MediaBuffer->add_ref() so it needs to be released here.
+            mediaBuffer->release();
+        }
+    }
 }
 
 bool GonkCameraSource::isMetaDataStoredInVideoBuffers() const {
     CS_LOGV("isMetaDataStoredInVideoBuffers");
     return mIsMetaDataStoredInVideoBuffers;
 }
 
 }  // namespace android
--- a/dom/camera/GonkCameraSource.h
+++ b/dom/camera/GonkCameraSource.h
@@ -22,28 +22,36 @@
 #include <media/stagefright/MediaSource.h>
 #include <camera/CameraParameters.h>
 #include <utils/List.h>
 #include <utils/RefBase.h>
 #include <utils/String16.h>
 
 #include "GonkCameraHwMgr.h"
 
+namespace mozilla {
+class ICameraControl;
+}
+
 namespace android {
 
 class IMemory;
 
 class GonkCameraSource : public MediaSource, public MediaBufferObserver {
 public:
 
     static GonkCameraSource *Create(const sp<GonkCameraHardware>& aCameraHw,
                                     Size videoSize,
                                     int32_t frameRate,
                                     bool storeMetaDataInVideoBuffers = false);
 
+    static GonkCameraSource *Create(mozilla::ICameraControl* aControl,
+                                    Size videoSize,
+                                    int32_t frameRate);
+
     virtual ~GonkCameraSource();
 
     virtual status_t start(MetaData *params = NULL);
     virtual status_t stop() { return reset(); }
     virtual status_t read(
             MediaBuffer **buffer, const ReadOptions *options = NULL);
 
     /**
@@ -70,16 +78,34 @@ public:
      * @return true if meta data is stored in the video
      *      buffers; false if real YUV data is stored in
      *      the video buffers.
      */
     bool isMetaDataStoredInVideoBuffers() const;
 
     virtual void signalBufferReturned(MediaBuffer* buffer);
 
+    /**
+     * It sends recording frames to listener directly in the same thread.
+     * Because recording frame is critical resource and it should not be
+     * propagated to other thread as much as possible or there could be frame
+     * rate jitter due to camera HAL waiting for resource.
+     */
+    class DirectBufferListener : public RefBase {
+    public:
+        DirectBufferListener() {};
+
+        virtual status_t BufferAvailable(MediaBuffer* aBuffer) = 0;
+
+    protected:
+        virtual ~DirectBufferListener() {}
+    };
+
+    status_t AddDirectBufferListener(DirectBufferListener* aListener);
+
 protected:
 
     enum CameraFlags {
         FLAGS_SET_CAMERA = 1L << 0,
         FLAGS_HOT_CAMERA = 1L << 1,
     };
 
     int32_t  mCameraFlags;
@@ -131,16 +157,17 @@ private:
 
     int64_t mFirstFrameTimeUs;
     int32_t mNumFramesDropped;
     int32_t mNumGlitches;
     int64_t mGlitchDurationThresholdUs;
     bool mCollectStats;
     bool mIsMetaDataStoredInVideoBuffers;
     sp<GonkCameraHardware> mCameraHw;
+    sp<DirectBufferListener> mDirectBufferListener;
 
     void releaseQueuedFrames();
     void releaseOneRecordingFrame(const sp<IMemory>& frame);
 
     status_t init(Size videoSize, int32_t frameRate,
                   bool storeMetaDataInVideoBuffers);
     status_t isCameraColorFormatSupported(const CameraParameters& params);
     status_t configureCamera(CameraParameters* params,
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -3239,20 +3239,17 @@ void HTMLMediaElement::UpdateReadyStateF
   // Now see if we should set HAVE_ENOUGH_DATA.
   // If it's something we don't know the size of, then we can't
   // make a real estimate, so we go straight to HAVE_ENOUGH_DATA once
   // we've downloaded enough data that our download rate is considered
   // reliable. We have to move to HAVE_ENOUGH_DATA at some point or
   // autoplay elements for live streams will never play. Otherwise we
   // move to HAVE_ENOUGH_DATA if we can play through the entire media
   // without stopping to buffer.
-  MediaDecoder::Statistics stats = mDecoder->GetStatistics();
-  if (stats.mTotalBytes < 0 ? stats.mDownloadRateReliable
-                            : stats.mTotalBytes == stats.mDownloadPosition ||
-                              mDecoder->CanPlayThrough())
+  if (mDecoder->CanPlayThrough())
   {
     ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA);
     return;
   }
   ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_FUTURE_DATA);
 }
 
 #ifdef PR_LOGGING
--- a/dom/indexedDB/TransactionThreadPool.cpp
+++ b/dom/indexedDB/TransactionThreadPool.cpp
@@ -14,16 +14,17 @@
 #include "nsIEventTarget.h"
 #include "nsIRunnable.h"
 #include "nsISupportsPriority.h"
 #include "nsIThreadPool.h"
 #include "nsThreadUtils.h"
 #include "nsServiceManagerUtils.h"
 #include "nsXPCOMCIDInternal.h"
 #include "ProfilerHelpers.h"
+#include "nsThread.h"
 
 namespace mozilla {
 namespace dom {
 namespace indexedDB {
 
 using mozilla::ipc::AssertIsOnBackgroundThread;
 
 namespace {
@@ -171,16 +172,20 @@ public:
   void Dispatch(nsIRunnable* aRunnable);
 
   void Finish(FinishCallback* aFinishCallback);
 
 private:
   ~TransactionQueue()
   { }
 
+#ifdef MOZ_NUWA_PROCESS
+  nsThread* mThread;
+#endif
+
   NS_DECL_NSIRUNNABLE
 };
 
 struct TransactionThreadPool::TransactionInfo MOZ_FINAL
 {
   uint64_t transactionId;
   nsCString databaseId;
   nsRefPtr<TransactionQueue> queue;
@@ -784,16 +789,19 @@ TransactionQueue::TransactionQueue(Trans
   , mOwningThreadPool(aThreadPool)
   , mTransactionId(aTransactionId)
   , mBackgroundChildLoggingId(aBackgroundChildLoggingId)
   , mLoggingSerialNumber(aLoggingSerialNumber)
   , mDatabaseId(aDatabaseId)
   , mObjectStoreNames(aObjectStoreNames)
   , mMode(aMode)
   , mShouldFinish(false)
+#ifdef MOZ_NUWA_PROCESS
+, mThread(nullptr)
+#endif
 {
   MOZ_ASSERT(aThreadPool);
   aThreadPool->AssertIsOnOwningThread();
 }
 
 void
 TransactionThreadPool::TransactionQueue::Unblock()
 {
@@ -809,16 +817,22 @@ void
 TransactionThreadPool::TransactionQueue::Dispatch(nsIRunnable* aRunnable)
 {
   MonitorAutoLock lock(mMonitor);
 
   NS_ASSERTION(!mShouldFinish, "Dispatch called after Finish!");
 
   mQueue.AppendElement(aRunnable);
 
+#ifdef MOZ_NUWA_PROCESS
+  if (mThread) {
+    mThread->SetWorking();
+  }
+#endif
+
   mMonitor.Notify();
 }
 
 void
 TransactionThreadPool::TransactionQueue::Finish(FinishCallback* aFinishCallback)
 {
   MonitorAutoLock lock(mMonitor);
 
@@ -844,23 +858,32 @@ TransactionThreadPool::TransactionQueue:
                  "Beginning database work",
                "IndexedDB %s: P T[%lld]: DB Start",
                IDB_LOG_ID_STRING(mBackgroundChildLoggingId),
                mLoggingSerialNumber);
 
   nsAutoTArray<nsCOMPtr<nsIRunnable>, 10> queue;
   nsRefPtr<FinishCallback> finishCallback;
   bool shouldFinish = false;
+#ifdef MOZ_NUWA_PROCESS
+  mThread = static_cast<nsThread*>(NS_GetCurrentThread());
+  // Set ourself as working thread. We can reset later if we found
+  // our queue is empty.
+  mThread->SetWorking();
+#endif
 
   do {
     NS_ASSERTION(queue.IsEmpty(), "Should have cleared this!");
 
     {
       MonitorAutoLock lock(mMonitor);
       while (!mShouldFinish && mQueue.IsEmpty()) {
+#ifdef MOZ_NUWA_PROCESS
+        mThread->SetIdle();
+#endif
         if (NS_FAILED(mMonitor.Wait())) {
           NS_ERROR("Failed to wait!");
         }
       }
 
       mQueue.SwapElements(queue);
       if (mShouldFinish) {
         mFinishCallback.swap(finishCallback);
@@ -883,16 +906,20 @@ TransactionThreadPool::TransactionQueue:
       runnable = nullptr;
     }
 
     if (count) {
       queue.Clear();
     }
   } while (!shouldFinish);
 
+#ifdef MOZ_NUWA_PROCESS
+  mThread = nullptr;
+#endif
+
 #ifdef DEBUG
   if (kDEBUGThreadSleepMS) {
     MOZ_ALWAYS_TRUE(
       PR_Sleep(PR_MillisecondsToInterval(kDEBUGThreadSleepMS)) == PR_SUCCESS);
   }
 #endif // DEBUG
 
   IDB_LOG_MARK("IndexedDB %s: Parent Transaction[%lld]: "
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -505,26 +505,33 @@ private:
         MOZ_CRASH("Failed to create a PBackgroundChild actor!");
     }
 };
 
 NS_IMPL_ISUPPORTS(BackgroundChildPrimer, nsIIPCBackgroundChildCreateCallback)
 
 ContentChild* ContentChild::sSingleton;
 
+static void
+PostForkPreload()
+{
+    TabChild::PostForkPreload();
+}
+
 // Performs initialization that is not fork-safe, i.e. that must be done after
 // forking from the Nuwa process.
 static void
 InitOnContentProcessCreated()
 {
 #ifdef MOZ_NUWA_PROCESS
     // Wait until we are forked from Nuwa
     if (IsNuwaProcess()) {
         return;
     }
+    PostForkPreload();
 #endif
 
     // This will register cross-process observer.
     mozilla::dom::time::InitializeDateCacheCleaner();
 }
 
 #if defined(MOZ_TASK_TRACER) && defined(MOZ_NUWA_PROCESS)
 static void
@@ -1238,17 +1245,16 @@ ContentChild::RecvPBrowserConstructor(PB
                                       const IPCTabContext& aContext,
                                       const uint32_t& aChromeFlags,
                                       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) {
         nsITabChild* tc =
             static_cast<nsITabChild*>(static_cast<TabChild*>(aActor));
         os->NotifyObservers(tc, "tab-child-created", nullptr);
     }
 
     static bool hasRunOnce = false;
@@ -1986,18 +1992,21 @@ ContentChild::RecvScreenSizeChanged(cons
 #endif
     return true;
 }
 
 bool
 ContentChild::RecvFlushMemory(const nsString& reason)
 {
 #ifdef MOZ_NUWA_PROCESS
-    if (IsNuwaProcess()) {
+    if (IsNuwaProcess() || ManagedPBrowserChild().Length() == 0) {
         // Don't flush memory in the nuwa process: the GC thread could be frozen.
+        // If there's no PBrowser child, don't flush memory, either. GC writes
+        // to copy-on-write pages and makes preallocated process take more memory
+        // before it actually becomes an app.
         return true;
     }
 #endif
     nsCOMPtr<nsIObserverService> os =
         mozilla::services::GetObserverService();
     if (os)
         os->NotifyObservers(nullptr, "memory-pressure", reason.get());
     return true;
@@ -2075,30 +2084,45 @@ ContentChild::RecvAppInfo(const nsCStrin
 
     // If we're part of the mozbrowser machinery, go ahead and start
     // preloading things.  We can only do this for mozbrowser because
     // PreloadSlowThings() may set the docshell of the first TabChild
     // inactive, and we can only safely restore it to active from
     // BrowserElementChild.js.
     if ((mIsForApp || mIsForBrowser)
 #ifdef MOZ_NUWA_PROCESS
-        && !IsNuwaProcess()
+        && IsNuwaProcess()
 #endif
        ) {
         PreloadSlowThings();
+#ifndef MOZ_NUWA_PROCESS
+        PostForkPreload();
+#endif
     }
 
 #ifdef MOZ_NUWA_PROCESS
+    // Some modules are initialized in preloading. We need to wait until the
+    // tasks they dispatched to chrome process are done.
+    if (IsNuwaProcess()) {
+        SendNuwaWaitForFreeze();
+    }
+#endif
+    return true;
+}
+
+bool
+ContentChild::RecvNuwaFreeze()
+{
+#ifdef MOZ_NUWA_PROCESS
     if (IsNuwaProcess()) {
         ContentChild::GetSingleton()->RecvGarbageCollect();
         MessageLoop::current()->PostTask(
             FROM_HERE, NewRunnableFunction(OnFinishNuwaPreparation));
     }
 #endif
-
     return true;
 }
 
 bool
 ContentChild::RecvLastPrivateDocShellDestroyed()
 {
     nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
     obs->NotifyObservers(nullptr, "last-pb-context-exited", nullptr);
@@ -2339,43 +2363,60 @@ DoNuwaFork()
  */
 static void
 RunNuwaFork()
 {
     if (NuwaCheckpointCurrentThread()) {
       DoNuwaFork();
     }
 }
+
+class NuwaForkCaller: public nsRunnable
+{
+public:
+    NS_IMETHODIMP
+    Run() {
+        // We want to ensure that the PBackground actor gets cloned in the Nuwa
+        // process before we freeze. Also, we have to do this to avoid deadlock.
+        // Protocols that are "opened" (e.g. PBackground, PCompositor) block the
+        // main thread to wait for the IPC thread during the open operation.
+        // NuwaSpawnWait() blocks the IPC thread to wait for the main thread when
+        // the Nuwa process is forked. Unless we ensure that the two cannot happen
+        // at the same time then we risk deadlock. Spinning the event loop here
+        // guarantees the ordering is safe for PBackground.
+        if (!BackgroundChild::GetForCurrentThread()) {
+            // Dispatch ourself again.
+            NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL);
+        } else {
+            MessageLoop* ioloop = XRE_GetIOMessageLoop();
+            ioloop->PostTask(FROM_HERE, NewRunnableFunction(RunNuwaFork));
+        }
+        return NS_OK;
+    }
+private:
+    virtual
+    ~NuwaForkCaller()
+    {
+    }
+};
+
 #endif
 
 bool
 ContentChild::RecvNuwaFork()
 {
 #ifdef MOZ_NUWA_PROCESS
     if (sNuwaForking) {           // No reentry.
         return true;
     }
     sNuwaForking = true;
 
-    // We want to ensure that the PBackground actor gets cloned in the Nuwa
-    // process before we freeze. Also, we have to do this to avoid deadlock.
-    // Protocols that are "opened" (e.g. PBackground, PCompositor) block the
-    // main thread to wait for the IPC thread during the open operation.
-    // NuwaSpawnWait() blocks the IPC thread to wait for the main thread when
-    // the Nuwa process is forked. Unless we ensure that the two cannot happen
-    // at the same time then we risk deadlock. Spinning the event loop here
-    // guarantees the ordering is safe for PBackground.
-    while (!BackgroundChild::GetForCurrentThread()) {
-        if (NS_WARN_IF(!NS_ProcessNextEvent())) {
-            return false;
-        }
-    }
+    nsRefPtr<NuwaForkCaller> runnable = new NuwaForkCaller();
+    NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL);
 
-    MessageLoop* ioloop = XRE_GetIOMessageLoop();
-    ioloop->PostTask(FROM_HERE, NewRunnableFunction(RunNuwaFork));
     return true;
 #else
     return false; // Makes the underlying IPC channel abort.
 #endif
 }
 
 bool
 ContentChild::RecvOnAppThemeChanged()
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -345,16 +345,18 @@ public:
     virtual bool RecvMinimizeMemoryUsage() MOZ_OVERRIDE;
 
     virtual bool RecvLoadAndRegisterSheet(const URIParams& aURI,
                                           const uint32_t& aType) MOZ_OVERRIDE;
     virtual bool RecvUnregisterSheet(const URIParams& aURI, const uint32_t& aType) MOZ_OVERRIDE;
 
     virtual bool RecvNotifyPhoneStateChange(const nsString& state) MOZ_OVERRIDE;
 
+    virtual bool RecvNuwaFreeze() MOZ_OVERRIDE;
+
     void AddIdleObserver(nsIObserver* aObserver, uint32_t aIdleTimeInS);
     void RemoveIdleObserver(nsIObserver* aObserver, uint32_t aIdleTimeInS);
     virtual bool RecvNotifyIdleObserver(const uint64_t& aObserver,
                                         const nsCString& aTopic,
                                         const nsString& aData) MOZ_OVERRIDE;
 
     virtual bool RecvOnAppThemeChanged() MOZ_OVERRIDE;
 
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -119,16 +119,17 @@
 #include "nsIURIFixup.h"
 #include "nsIWindowWatcher.h"
 #include "nsIXULRuntime.h"
 #include "nsMemoryInfoDumper.h"
 #include "nsMemoryReporterManager.h"
 #include "nsServiceManagerUtils.h"
 #include "nsStyleSheetService.h"
 #include "nsThreadUtils.h"
+#include "nsThreadManager.h"
 #include "nsToolkitCompsCID.h"
 #include "nsWidgetsCID.h"
 #include "PreallocatedProcessManager.h"
 #include "ProcessPriorityManager.h"
 #include "SandboxHal.h"
 #include "ScreenManagerParent.h"
 #include "StructuredCloneUtils.h"
 #include "TabParent.h"
@@ -1367,16 +1368,38 @@ private:
 };
 
 StaticAutoPtr<LinkedList<SystemMessageHandledListener> >
     SystemMessageHandledListener::sListeners;
 
 NS_IMPL_ISUPPORTS(SystemMessageHandledListener,
                   nsITimerCallback)
 
+#ifdef MOZ_NUWA_PROCESS
+class NuwaFreezeListener : public nsThreadManager::AllThreadsWereIdleListener
+{
+public:
+    NuwaFreezeListener(ContentParent* parent)
+        : mParent(parent)
+    {
+    }
+
+    void OnAllThreadsWereIdle()
+    {
+        unused << mParent->SendNuwaFreeze();
+        nsThreadManager::get()->RemoveAllThreadsWereIdleListener(this);
+    }
+private:
+    nsRefPtr<ContentParent> mParent;
+    virtual ~NuwaFreezeListener()
+    {
+    }
+};
+#endif // MOZ_NUWA_PROCESS
+
 } // anonymous namespace
 
 void
 ContentParent::MaybeTakeCPUWakeLock(Element* aFrameElement)
 {
     // Take the CPU wake lock on behalf of this processs if it's expecting a
     // system message.  We'll release the CPU lock once the message is
     // delivered, or after some period of time, which ever comes first.
@@ -2057,16 +2080,18 @@ ContentParent::ContentParent(ContentPare
     // memory priority, which it has inherited from this process.
     ProcessPriority priority;
     if (IsPreallocated()) {
         priority = PROCESS_PRIORITY_PREALLOC;
     } else {
         priority = PROCESS_PRIORITY_FOREGROUND;
     }
 
+    mSendPermissionUpdates = aTemplate->mSendPermissionUpdates;
+
     InitInternal(priority,
                  false, /* Setup Off-main thread compositing */
                  false  /* Send registered chrome */);
 
     ContentProcessManager::GetSingleton()->AddContentProcess(this);
 }
 #endif  // MOZ_NUWA_PROCESS
 
@@ -2214,17 +2239,17 @@ ContentParent::IsAlive()
 bool
 ContentParent::IsForApp()
 {
     return !mAppManifestURL.IsEmpty();
 }
 
 #ifdef MOZ_NUWA_PROCESS
 bool
-ContentParent::IsNuwaProcess()
+ContentParent::IsNuwaProcess() const
 {
     return mIsNuwaProcess;
 }
 #endif
 
 int32_t
 ContentParent::Pid()
 {
@@ -2564,16 +2589,29 @@ ContentParent::RecvNuwaReady()
     return true;
 #else
     NS_ERROR("ContentParent::RecvNuwaReady() not implemented!");
     return false;
 #endif
 }
 
 bool
+ContentParent::RecvNuwaWaitForFreeze()
+{
+#ifdef MOZ_NUWA_PROCESS
+    nsRefPtr<NuwaFreezeListener> listener = new NuwaFreezeListener(this);
+    nsThreadManager::get()->AddAllThreadsWereIdleListener(listener);
+    return true;
+#else // MOZ_NUWA_PROCESS
+    NS_ERROR("ContentParent::RecvNuwaWaitForFreeze() not implemented!");
+    return false;
+#endif // MOZ_NUWA_PROCESS
+}
+
+bool
 ContentParent::RecvAddNewProcess(const uint32_t& aPid,
                                  const InfallibleTArray<ProtocolFdMapping>& aFds)
 {
 #ifdef MOZ_NUWA_PROCESS
     if (!IsNuwaProcess()) {
         NS_ERROR(
             nsPrintfCString(
                 "Terminating child process %d for unauthorized IPC message: "
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -201,31 +201,35 @@ public:
 
     bool IsAlive();
     virtual bool IsForApp() MOZ_OVERRIDE;
     virtual bool IsForBrowser() MOZ_OVERRIDE
     {
       return mIsForBrowser;
     }
 #ifdef MOZ_NUWA_PROCESS
-    bool IsNuwaProcess();
+    bool IsNuwaProcess() const;
 #endif
 
     GeckoChildProcessHost* Process() {
         return mSubprocess;
     }
 
     int32_t Pid();
 
     ContentParent* Opener() {
         return mOpener;
     }
 
     bool NeedsPermissionsUpdate() const {
+#ifdef MOZ_NUWA_PROCESS
+        return !IsNuwaProcess() && mSendPermissionUpdates;
+#else
         return mSendPermissionUpdates;
+#endif
     }
 
     bool NeedsDataStoreInfos() const {
         return mSendDataStoreInfos;
     }
 
     /**
      * Kill our subprocess and make sure it dies.  Should only be used
@@ -675,16 +679,18 @@ private:
     virtual bool RecvSpeakerManagerGetSpeakerStatus(bool* aValue) MOZ_OVERRIDE;
 
     virtual bool RecvSpeakerManagerForceSpeaker(const bool& aEnable) MOZ_OVERRIDE;
 
     virtual bool RecvSystemMessageHandled() MOZ_OVERRIDE;
 
     virtual bool RecvNuwaReady() MOZ_OVERRIDE;
 
+    virtual bool RecvNuwaWaitForFreeze() MOZ_OVERRIDE;
+
     virtual bool RecvAddNewProcess(const uint32_t& aPid,
                                    const InfallibleTArray<ProtocolFdMapping>& aFds) MOZ_OVERRIDE;
 
     virtual bool RecvCreateFakeVolume(const nsString& fsName, const nsString& mountPoint) MOZ_OVERRIDE;
 
     virtual bool RecvSetFakeVolumeState(const nsString& fsName, const int32_t& fsState) MOZ_OVERRIDE;
 
     virtual bool RecvKeywordToURI(const nsCString& aKeyword,
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -519,16 +519,17 @@ child:
      * Control the Gecko Profiler in the child process.
      */
     async StartProfiler(uint32_t aEntries, double aInterval, nsCString[] aFeatures,
                         nsCString[] aThreadNameFilters);
     async StopProfiler();
     intr GetProfile()
       returns (nsCString aProfile);
 
+    NuwaFreeze();
 parent:
     /**
      * Tell the parent process a new accessible document has been created.
      * aParentDoc is the accessible document it was created in if any, and
      * aParentAcc is the id of the accessible in that document the new document
      * is a child of.
      */
     PDocAccessible(nullable PDocAccessible aParentDoc, uint64_t aParentAcc);
@@ -730,16 +731,19 @@ parent:
                                nsCString aReason);
 
     sync GetVolumes() returns (VolumeInfo[] volumes);
 
     // Notify the parent that the child has finished handling a system message.
     async SystemMessageHandled();
 
     NuwaReady();
+    // Sent when nuwa finished its initialization process and is waiting for
+    // parent's signal to make it freeze.
+    NuwaWaitForFreeze();
 
     sync AddNewProcess(uint32_t pid, ProtocolFdMapping[] aFds);
 
     // called by the child (test code only) to propagate volume changes to the parent
     async CreateFakeVolume(nsString fsName, nsString mountPoint);
     async SetFakeVolumeState(nsString fsName, int32_t fsState);
 
     sync KeywordToURI(nsCString keyword)
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -829,16 +829,31 @@ TabChild::PreloadSlowThings()
         // work.
         presShell->MakeZombie();
     }
 
     sPreallocatedTab = tab;
     ClearOnShutdown(&sPreallocatedTab);
 }
 
+/*static*/ void
+TabChild::PostForkPreload()
+{
+    // Preallocated Tab can be null if we are forked directly from b2g. In such
+    // case we don't need to preload anything, just return.
+    if (!sPreallocatedTab) {
+        return;
+    }
+
+    // Rebuild connections to parent.
+    sPreallocatedTab->RecvLoadRemoteScript(
+      NS_LITERAL_STRING("chrome://global/content/post-fork-preload.js"),
+      true);
+}
+
 /*static*/ already_AddRefed<TabChild>
 TabChild::Create(nsIContentChild* aManager,
                  const TabId& aTabId,
                  const TabContext &aContext,
                  uint32_t aChromeFlags)
 {
     if (sPreallocatedTab &&
         sPreallocatedTab->mChromeFlags == aChromeFlags &&
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -263,16 +263,17 @@ public:
 
 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();
+    static void PostForkPreload();
 
     /** Return a TabChild with the given attributes. */
     static already_AddRefed<TabChild>
     Create(nsIContentChild* aManager, const TabId& aTabId, const TabContext& aContext, uint32_t aChromeFlags);
 
     bool IsRootContentDocument();
 
     const TabId GetTabId() const {
--- a/dom/ipc/jar.mn
+++ b/dom/ipc/jar.mn
@@ -4,8 +4,9 @@
 
 toolkit.jar:
         content/global/test-ipc.xul (test.xul)
         content/global/remote-test-ipc.js (remote-test.js)
         content/global/BrowserElementChild.js (../browser-element/BrowserElementChild.js)
         content/global/BrowserElementChildPreload.js (../browser-element/BrowserElementChildPreload.js)
 *       content/global/BrowserElementPanning.js (../browser-element/BrowserElementPanning.js)
         content/global/preload.js (preload.js)
+        content/global/post-fork-preload.js (post-fork-preload.js)
new file mode 100644
--- /dev/null
+++ b/dom/ipc/post-fork-preload.js
@@ -0,0 +1,20 @@
+/* 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/. */
+
+// Preload some things, in an attempt to make app startup faster.
+//
+// This script is run when the preallocated process starts.  It is injected as
+// a frame script.
+// If Nuwa process is enabled, this script will run in preallocated process
+// forked by Nuwa.
+
+(function (global) {
+  "use strict";
+
+  Components.utils.import("resource://gre/modules/AppsServiceChild.jsm");
+  Components.classes["@mozilla.org/network/protocol-proxy-service;1"].
+    getService(Ci["nsIProtocolProxyService"]);
+
+  DOMApplicationRegistry.resetList();
+})(this);
--- a/dom/ipc/preload.js
+++ b/dom/ipc/preload.js
@@ -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/. */
 
 // Preload some things, in an attempt to make app startup faster.
 //
 // This script is run when the preallocated process starts.  It is injected as
 // a frame script.
+// If nuwa is enabled, this script will run in Nuwa process before frozen.
 
 const BrowserElementIsPreloaded = true;
 
 (function (global) {
   "use strict";
 
   let Cu = Components.utils;
   let Cc = Components.classes;
@@ -53,17 +54,16 @@ const BrowserElementIsPreloaded = true;
   Cc["@mozilla.org/message-loop;1"].getService(Ci["nsIMessageLoop"]);
   Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci["mozIJSSubScriptLoader"]);
   Cc["@mozilla.org/network/application-cache-service;1"].getService(Ci["nsIApplicationCacheService"]);
   Cc["@mozilla.org/network/dns-service;1"].getService(Ci["nsIDNSService"]);
   Cc["@mozilla.org/network/effective-tld-service;1"].getService(Ci["nsIEffectiveTLDService"]);
   Cc["@mozilla.org/network/idn-service;1"].getService(Ci["nsIIDNService"]);
   Cc["@mozilla.org/network/io-service;1"].getService(Ci["nsIIOService2"]);
   Cc["@mozilla.org/network/mime-hdrparam;1"].getService(Ci["nsIMIMEHeaderParam"]);
-  Cc["@mozilla.org/network/protocol-proxy-service;1"].getService(Ci["nsIProtocolProxyService"]);
   Cc["@mozilla.org/network/socket-transport-service;1"].getService(Ci["nsISocketTransportService"]);
   Cc["@mozilla.org/network/stream-transport-service;1"].getService(Ci["nsIStreamTransportService"]);
   Cc["@mozilla.org/network/url-parser;1?auth=maybe"].getService(Ci["nsIURLParser"]);
   Cc["@mozilla.org/network/url-parser;1?auth=no"].getService(Ci["nsIURLParser"]);
   Cc["@mozilla.org/network/url-parser;1?auth=yes"].getService(Ci["nsIURLParser"]);
   Cc["@mozilla.org/observer-service;1"].getService(Ci["nsIObserverService"]);
   Cc["@mozilla.org/permissionmanager;1"].getService(Ci["nsIPermissionManager"]);
   Cc["@mozilla.org/preferences-service;1"].getService(Ci["nsIPrefBranch"]);
--- a/dom/ipc/tests/test_NuwaProcessCreation.html
+++ b/dom/ipc/tests/test_NuwaProcessCreation.html
@@ -72,17 +72,17 @@ function runTest()
         is(seenNuwaReady, true, "Receive nuwa-add-new-process before nuwa-ready");
         testEnd();
       }
     }
   };
   let timeout = setTimeout(function() {
     ok(false, "Nuwa process is not launched");
     testEnd();
-  }, 60000);
+  }, 240000);
 
   function testEnd() {
     cpmm.removeMessageListener("TEST-ONLY:nuwa-ready", msgHandler);
     cpmm.removeMessageListener("TEST-ONLY:nuwa-add-new-process", msgHandler);
     clearTimeout(timeout);
     SimpleTest.finish();
   }
 
--- a/dom/ipc/tests/test_NuwaProcessDeadlock.html
+++ b/dom/ipc/tests/test_NuwaProcessDeadlock.html
@@ -73,17 +73,17 @@ function runTest()
         is(seenNuwaReady, true, "Receive nuwa-add-new-process before nuwa-ready");
         testEnd();
       }
     }
   };
   let timeout = setTimeout(function() {
     ok(false, "Nuwa process is not launched");
     testEnd();
-  }, 90000);
+  }, 240000);
 
   function testEnd() {
     cpmm.removeMessageListener("TEST-ONLY:nuwa-ready", msgHandler);
     cpmm.removeMessageListener("TEST-ONLY:nuwa-add-new-process", msgHandler);
     clearTimeout(timeout);
     setPref('dom.ipc.processPrelaunch.testMode', false);
     SimpleTest.finish();
   }
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -1557,16 +1557,20 @@ void MediaDecoder::UnpinForSeek()
   }
   mPinnedForSeek = false;
   resource->Unpin();
 }
 
 bool MediaDecoder::CanPlayThrough()
 {
   Statistics stats = GetStatistics();
+  if ((stats.mTotalBytes < 0 && stats.mDownloadRateReliable) ||
+      (stats.mTotalBytes >= 0 && stats.mTotalBytes == stats.mDownloadPosition)) {
+    return true;
+  }
   if (!stats.mDownloadRateReliable || !stats.mPlaybackRateReliable) {
     return false;
   }
   int64_t bytesToDownload = stats.mTotalBytes - stats.mDownloadPosition;
   int64_t bytesToPlayback = stats.mTotalBytes - stats.mPlaybackPosition;
   double timeToDownload = bytesToDownload / stats.mDownloadRate;
   double timeToPlay = bytesToPlayback / stats.mPlaybackRate;
 
@@ -1580,18 +1584,17 @@ bool MediaDecoder::CanPlayThrough()
   // We can probably play through without having to buffer, but ensure that
   // we've got a reasonable amount of data buffered after the current
   // playback position, so that if the bitrate of the media fluctuates, or if
   // our download rate or decode rate estimation is otherwise inaccurate,
   // we don't suddenly discover that we need to buffer. This is particularly
   // required near the start of the media, when not much data is downloaded.
   int64_t readAheadMargin =
     static_cast<int64_t>(stats.mPlaybackRate * CAN_PLAY_THROUGH_MARGIN);
-  return stats.mTotalBytes == stats.mDownloadPosition ||
-         stats.mDownloadPosition > stats.mPlaybackPosition + readAheadMargin;
+  return stats.mDownloadPosition > stats.mPlaybackPosition + readAheadMargin;
 }
 
 #ifdef MOZ_EME
 nsresult
 MediaDecoder::SetCDMProxy(CDMProxy* aProxy)
 {
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
   MOZ_ASSERT(NS_IsMainThread());
new file mode 100644
--- /dev/null
+++ b/dom/media/webrtc/GonkCameraImage.cpp
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#include "GonkCameraImage.h"
+#include "stagefright/MediaBuffer.h"
+
+namespace mozilla {
+
+GonkCameraImage::GonkCameraImage()
+  : GrallocImage()
+  , mMonitor("GonkCameraImage.Monitor")
+  , mMediaBuffer(nullptr)
+  , mThread(nullptr)
+{
+  mFormat = ImageFormat::GONK_CAMERA_IMAGE;
+}
+
+GonkCameraImage::~GonkCameraImage()
+{
+  ReentrantMonitorAutoEnter mon(mMonitor);
+  // mMediaBuffer must be cleared before destructor.
+  MOZ_ASSERT(mMediaBuffer == nullptr);
+}
+
+nsresult
+GonkCameraImage::GetBuffer(android::MediaBuffer** aBuffer)
+{
+  ReentrantMonitorAutoEnter mon(mMonitor);
+
+  if (!mMediaBuffer) {
+    return NS_ERROR_FAILURE;
+  }
+
+  MOZ_ASSERT(NS_GetCurrentThread() == mThread);
+
+  *aBuffer = mMediaBuffer;
+  mMediaBuffer->add_ref();
+
+  return NS_OK;
+}
+
+bool
+GonkCameraImage::HasMediaBuffer()
+{
+  ReentrantMonitorAutoEnter mon(mMonitor);
+  return mMediaBuffer != nullptr;
+}
+
+nsresult
+GonkCameraImage::SetBuffer(android::MediaBuffer* aBuffer)
+{
+  ReentrantMonitorAutoEnter mon(mMonitor);
+  MOZ_ASSERT(!mMediaBuffer);
+
+  mMediaBuffer = aBuffer;
+  mMediaBuffer->add_ref();
+  mThread = NS_GetCurrentThread();
+
+  return NS_OK;
+}
+
+nsresult
+GonkCameraImage::ClearBuffer()
+{
+  ReentrantMonitorAutoEnter mon(mMonitor);
+
+  if (mMediaBuffer) {
+    MOZ_ASSERT(NS_GetCurrentThread() == mThread);
+    mMediaBuffer->release();
+    mMediaBuffer = nullptr;
+    mThread = nullptr;
+  }
+  return NS_OK;
+}
+
+} // namespace mozilla
+
+
new file mode 100644
--- /dev/null
+++ b/dom/media/webrtc/GonkCameraImage.h
@@ -0,0 +1,75 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef GONKCAMERAIMAGE_H
+#define GONKCAMERAIMAGE_H
+
+#include "mozilla/ReentrantMonitor.h"
+#include "ImageLayers.h"
+#include "ImageContainer.h"
+#include "GrallocImages.h"
+
+namespace android {
+class MOZ_EXPORT MediaBuffer;
+}
+
+namespace mozilla {
+
+/**
+ * GonkCameraImage has two parts. One is preview image which will be saved in
+ * GrallocImage, another kind is the MediaBuffer keeps in mMediaBuffer
+ * which is from gonk camera recording callback. The data in MediaBuffer is Gonk
+ * shared memory based on android binder (IMemory), the actual format in IMemory
+ * is platform dependent.
+ * This instance is created in MediaEngine when the preview image arrives.
+ * The MediaBuffer is attached to the current created GonkCameraImage via SetBuffer().
+ * After sending this image to MediaStreamGraph by AppendToTrack(), ClearBuffer()
+ * must be called to clear MediaBuffer to avoid MediaBuffer be kept in MSG thread.
+ * The reason to keep MediaBuffer be accessed from MSG thread is MediaBuffer is
+ * limited resource and it could cause frame rate jitter if MediaBuffer stay too
+ * long in other threads.
+ * So there will be 3 threads to accessed this class. First is camera preview
+ * thread which creates an instance of this class and initialize the preview
+ * image in the base class GrallocImage. Second is the camera recording
+ * thread which attaches MediaBuffer and sends this image to MediaStreamDirectListener.
+ * Third is the MSG thread via NotifyPull, the image should have preview image
+ * only in NotifyPull.
+ *
+ * Note: SetBuffer() and GetBuffer() should be called from the same thread. It
+ *       is forbidden to call GetBuffer() from other threads.
+ */
+class GonkCameraImage : public layers::GrallocImage
+{
+public:
+  GonkCameraImage();
+
+  // The returned aBuffer has called aBuffer->add_ref() already, so it is caller's
+  // duty to release aBuffer. It should be called from the same thread which
+  // called SetBuffer().
+  nsresult GetBuffer(android::MediaBuffer** aBuffer);
+
+  // Set MediaBuffer to image. It is caller's responsibility to call ClearBuffer()
+  // after the MediaBuffer is sent via MediaStreamGraph.
+  nsresult SetBuffer(android::MediaBuffer* aBuffer);
+
+  // It should be called from the same thread which called SetBuffer().
+  nsresult ClearBuffer();
+
+  bool HasMediaBuffer();
+
+protected:
+  virtual ~GonkCameraImage();
+
+  // mMonitor protects mMediaBuffer and mThread.
+  ReentrantMonitor mMonitor;
+  android::MediaBuffer* mMediaBuffer;
+  // Check if current thread is the same one which called SetBuffer().
+  // It doesn't need to hold reference count.
+  DebugOnly<nsIThread*> mThread;
+};
+
+} // namespace mozilla
+
+#endif /* GONKCAMERAIMAGE_H */
--- a/dom/media/webrtc/MediaEngineGonkVideoSource.cpp
+++ b/dom/media/webrtc/MediaEngineGonkVideoSource.cpp
@@ -10,31 +10,56 @@
 #include "GrallocImages.h"
 #include "mozilla/layers/GrallocTextureClient.h"
 #include "mozilla/layers/ImageBridgeChild.h"
 #include "VideoUtils.h"
 #include "ScreenOrientation.h"
 
 #include "libyuv.h"
 #include "mtransport/runnable_utils.h"
+#include "GonkCameraImage.h"
 
 namespace mozilla {
 
 using namespace mozilla::dom;
 using namespace mozilla::gfx;
+using namespace android;
 
 #ifdef PR_LOGGING
 extern PRLogModuleInfo* GetMediaManagerLog();
 #define LOG(msg) PR_LOG(GetMediaManagerLog(), PR_LOG_DEBUG, msg)
 #define LOGFRAME(msg) PR_LOG(GetMediaManagerLog(), 6, msg)
 #else
 #define LOG(msg)
 #define LOGFRAME(msg)
 #endif
 
+class MediaBufferListener : public GonkCameraSource::DirectBufferListener {
+public:
+  MediaBufferListener(MediaEngineGonkVideoSource* aMediaEngine)
+    : mMediaEngine(aMediaEngine)
+  {
+  }
+
+  status_t BufferAvailable(MediaBuffer* aBuffer)
+  {
+    nsresult rv = mMediaEngine->OnNewMediaBufferFrame(aBuffer);
+    if (NS_SUCCEEDED(rv)) {
+      return OK;
+    }
+    return UNKNOWN_ERROR;
+  }
+
+  ~MediaBufferListener()
+  {
+  }
+
+  nsRefPtr<MediaEngineGonkVideoSource> mMediaEngine;
+};
+
 #define WEBRTC_GONK_VIDEO_SOURCE_POOL_BUFFERS 10
 
 // We are subclassed from CameraControlListener, which implements a
 // threadsafe reference-count for us.
 NS_IMPL_QUERY_INTERFACE(MediaEngineGonkVideoSource, nsISupports)
 NS_IMPL_ADDREF_INHERITED(MediaEngineGonkVideoSource, CameraControlListener)
 NS_IMPL_RELEASE_INHERITED(MediaEngineGonkVideoSource, CameraControlListener)
 
@@ -163,16 +188,56 @@ MediaEngineGonkVideoSource::Start(Source
   NS_DispatchToMainThread(WrapRunnable(nsRefPtr<MediaEngineGonkVideoSource>(this),
                                        &MediaEngineGonkVideoSource::StartImpl,
                                        mCapability));
   mCallbackMonitor.Wait();
   if (mState != kStarted) {
     return NS_ERROR_FAILURE;
   }
 
+  if (NS_FAILED(InitDirectMediaBuffer())) {
+    return NS_ERROR_FAILURE;
+  }
+
+  return NS_OK;
+}
+
+nsresult
+MediaEngineGonkVideoSource::InitDirectMediaBuffer()
+{
+  // Check available buffer resolution.
+  nsTArray<ICameraControl::Size> videoSizes;
+  mCameraControl->Get(CAMERA_PARAM_SUPPORTED_VIDEOSIZES, videoSizes);
+  if (!videoSizes.Length()) {
+    return NS_ERROR_FAILURE;
+  }
+
+  // TODO: MediaEgnine should use supported recording frame sizes as the size
+  //       range in MediaTrackConstraintSet and find the best match.
+  //       Here we use the first one as the default size (largest supported size).
+  android::Size videoSize;
+  videoSize.width = videoSizes[0].width;
+  videoSize.height = videoSizes[0].height;
+
+  LOG(("Intial size, width: %d, height: %d", videoSize.width, videoSize.height));
+  mCameraSource = GonkCameraSource::Create(mCameraControl,
+                                           videoSize,
+                                           MediaEngine::DEFAULT_VIDEO_FPS);
+
+  status_t rv;
+  rv = mCameraSource->AddDirectBufferListener(new MediaBufferListener(this));
+  if (rv != OK) {
+    return NS_ERROR_FAILURE;
+  }
+
+  rv = mCameraSource->start(nullptr);
+  if (rv != OK) {
+    return NS_ERROR_FAILURE;
+  }
+
   return NS_OK;
 }
 
 nsresult
 MediaEngineGonkVideoSource::Stop(SourceMediaStream* aSource, TrackID aID)
 {
   LOG((__FUNCTION__));
   if (!mSources.RemoveElement(aSource)) {
@@ -348,16 +413,19 @@ MediaEngineGonkVideoSource::StartImpl(we
 
   hal::RegisterScreenConfigurationObserver(this);
 }
 
 void
 MediaEngineGonkVideoSource::StopImpl() {
   MOZ_ASSERT(NS_IsMainThread());
 
+  mCameraSource->stop();
+  mCameraSource = nullptr;
+
   hal::UnregisterScreenConfigurationObserver(this);
   mCameraControl->Stop();
 }
 
 void
 MediaEngineGonkVideoSource::OnHardwareStateChange(HardwareState aState,
                                                   nsresult aReason)
 {
@@ -584,27 +652,27 @@ MediaEngineGonkVideoSource::ConvertPixel
     return libyuv::FOURCC_ANY;
     }
   }
 }
 
 void
 MediaEngineGonkVideoSource::RotateImage(layers::Image* aImage, uint32_t aWidth, uint32_t aHeight) {
   layers::GrallocImage *nativeImage = static_cast<layers::GrallocImage*>(aImage);
-  android::sp<android::GraphicBuffer> graphicBuffer = nativeImage->GetGraphicBuffer();
+  android::sp<GraphicBuffer> graphicBuffer = nativeImage->GetGraphicBuffer();
   void *pMem = nullptr;
   // Bug 1109957 size will be wrong if width or height are odd
   uint32_t size = aWidth * aHeight * 3 / 2;
   MOZ_ASSERT(!(aWidth & 1) && !(aHeight & 1));
 
-  graphicBuffer->lock(android::GraphicBuffer::USAGE_SW_READ_MASK, &pMem);
+  graphicBuffer->lock(GraphicBuffer::USAGE_SW_READ_MASK, &pMem);
 
   uint8_t* srcPtr = static_cast<uint8_t*>(pMem);
   // Create a video frame and append it to the track.
-  ImageFormat format = ImageFormat::GRALLOC_PLANAR_YCBCR;
+  ImageFormat format = ImageFormat::GONK_CAMERA_IMAGE;
   nsRefPtr<layers::Image> image = mImageContainer->CreateImage(format);
 
   uint32_t dstWidth;
   uint32_t dstHeight;
 
   if (mRotation == 90 || mRotation == 270) {
     dstWidth = aHeight;
     dstHeight = aWidth;
@@ -652,33 +720,18 @@ MediaEngineGonkVideoSource::RotateImage(
   graphicBuffer->unlock();
 
   layers::GrallocImage::GrallocData data;
 
   data.mPicSize = gfx::IntSize(dstWidth, dstHeight);
   data.mGraphicBuffer = textureClient;
   videoImage->SetData(data);
 
-  // implicitly releases last image
+  // Implicitly releases last preview 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;
@@ -697,9 +750,45 @@ MediaEngineGonkVideoSource::OnNewPreview
     mWidth = aWidth;
     mHeight = aHeight;
     LOG(("Video FrameSizeChange: %ux%u", mWidth, mHeight));
   }
 
   return true; // return true because we're accepting the frame
 }
 
+nsresult
+MediaEngineGonkVideoSource::OnNewMediaBufferFrame(MediaBuffer* aBuffer)
+{
+  {
+    ReentrantMonitorAutoEnter sync(mCallbackMonitor);
+    if (mState == kStopped) {
+      return NS_OK;
+    }
+  }
+
+  MonitorAutoLock enter(mMonitor);
+  if (mImage) {
+    GonkCameraImage* cameraImage = static_cast<GonkCameraImage*>(mImage.get());
+
+    cameraImage->SetBuffer(aBuffer);
+
+    uint32_t len = mSources.Length();
+    for (uint32_t i = 0; i < len; i++) {
+      if (mSources[i]) {
+        // Duration is 1 here.
+        // Ideally, it should be camera timestamp here and the MSG will have
+        // enough sample duration without calling NotifyPull() anymore.
+        // Unfortunately, clock in gonk camera looks like is a different one
+        // comparing to MSG. As result, it causes time inaccurate. (frames be
+        // queued in MSG longer and longer as time going by in device like Frame)
+        AppendToTrack(mSources[i], cameraImage, mTrackID, 1);
+      }
+    }
+    // Clear MediaBuffer immediately, it prevents MediaBuffer is kept in
+    // MediaStreamGraph thread.
+    cameraImage->ClearBuffer();
+  }
+
+  return NS_OK;
+}
+
 } // namespace mozilla
--- a/dom/media/webrtc/MediaEngineGonkVideoSource.h
+++ b/dom/media/webrtc/MediaEngineGonkVideoSource.h
@@ -11,16 +11,21 @@
 
 #include "CameraControlListener.h"
 #include "MediaEngineCameraVideoSource.h"
 
 #include "mozilla/Hal.h"
 #include "mozilla/ReentrantMonitor.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/layers/TextureClientRecycleAllocator.h"
+#include "GonkCameraSource.h"
+
+namespace android {
+class MOZ_EXPORT MediaBuffer;
+}
 
 namespace mozilla {
 
 /**
  * The B2G implementation of the MediaEngine interface.
  *
  * On B2G platform, member data may accessed from different thread after construction:
  *
@@ -86,32 +91,43 @@ public:
   void Notify(const mozilla::hal::ScreenConfiguration& aConfiguration);
 
   nsresult TakePhoto(PhotoCallback* aCallback) MOZ_OVERRIDE;
 
   // It sets the correct photo orientation via camera parameter according to
   // current screen orientation.
   nsresult UpdatePhotoOrientation();
 
+  // It adds aBuffer to current preview image and sends this image to MediaStreamDirectListener
+  // via AppendToTrack(). Due to MediaBuffer is limited resource, it will clear
+  // image's MediaBuffer by calling GonkCameraImage::ClearBuffer() before leaving
+  // this function.
+  nsresult OnNewMediaBufferFrame(android::MediaBuffer* aBuffer);
+
 protected:
   ~MediaEngineGonkVideoSource()
   {
     Shutdown();
   }
   // Initialize the needed Video engine interfaces.
   void Init();
   void Shutdown();
   void ChooseCapability(const VideoTrackConstraintsN& aConstraints,
                         const MediaEnginePrefs& aPrefs);
+  // Initialize the recording frame (MediaBuffer) callback and Gonk camera.
+  // MediaBuffer will transfers to MediaStreamGraph via AppendToTrack.
+  nsresult InitDirectMediaBuffer();
 
   mozilla::ReentrantMonitor mCallbackMonitor; // Monitor for camera callback handling
   // This is only modified on MainThread (AllocImpl and DeallocImpl)
   nsRefPtr<ICameraControl> mCameraControl;
   nsCOMPtr<nsIDOMFile> mLastCapture;
 
+  android::sp<android::GonkCameraSource> mCameraSource;
+
   // These are protected by mMonitor in parent class
   nsTArray<nsRefPtr<PhotoCallback>> mPhotoCallbacks;
   int mRotation;
   int mCameraAngle; // See dom/base/ScreenOrientation.h
   bool mBackCamera;
   bool mOrientationChanged; // True when screen rotates.
 
   RefPtr<layers::TextureClientRecycleAllocator> mTextureClientAllocator;
--- a/dom/media/webrtc/moz.build
+++ b/dom/media/webrtc/moz.build
@@ -31,18 +31,22 @@ if CONFIG['MOZ_WEBRTC']:
         '/dom/camera',
         '/media/libyuv/include',
         '/media/webrtc/signaling/src/common',
         '/media/webrtc/signaling/src/common/browser_logging',
         '/media/webrtc/trunk',
     ]
     # Gonk camera source.
     if CONFIG['MOZ_B2G_CAMERA']:
-        EXPORTS += ['MediaEngineGonkVideoSource.h']
+        EXPORTS += [
+            'GonkCameraImage.h',
+            'MediaEngineGonkVideoSource.h',
+        ]
         UNIFIED_SOURCES += [
+            'GonkCameraImage.cpp',
             'MediaEngineGonkVideoSource.cpp',
         ]
 
 XPIDL_SOURCES += [
     'nsITabSource.idl'
 ]
 
 UNIFIED_SOURCES += [
--- a/dom/settings/SettingsRequestManager.jsm
+++ b/dom/settings/SettingsRequestManager.jsm
@@ -12,22 +12,25 @@ this.EXPORTED_SYMBOLS = [];
 
 Cu.import("resource://gre/modules/SettingsDB.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/PermissionsTable.jsm");
 
 let DEBUG = false;
 let VERBOSE = false;
+let TRACK = false;
 
 try {
   DEBUG   =
     Services.prefs.getBoolPref("dom.mozSettings.SettingsRequestManager.debug.enabled");
   VERBOSE =
     Services.prefs.getBoolPref("dom.mozSettings.SettingsRequestManager.verbose.enabled");
+  TRACK =
+    Services.prefs.getBoolPref("dom.mozSettings.trackTasksUsage");
 } catch (ex) { }
 
 let allowForceReadOnly = false;
 try {
   allowForceReadOnly = Services.prefs.getBoolPref("dom.mozSettings.allowForceReadOnly");
 } catch (ex) { }
 
 function debug(s) {
@@ -202,17 +205,22 @@ let SettingsRequestManager = {
   // until they hit the front of the queue.
   settingsLockQueue: [],
   children: [],
   // Since we need to call observers at times when we may not have
   // just received a message from a child process, we cache principals
   // for message managers and check permissions on them before we send
   // settings notifications to child processes.
   observerPrincipalCache: new Map(),
-  tasksConsumed: 0,
+  totalProcessed: 0,
+  tasksConsumed: {},
+  totalSetProcessed: 0,
+  tasksSetConsumed: {},
+  totalGetProcessed: 0,
+  tasksGetConsumed: {},
 
   init: function() {
     if (VERBOSE) debug("init");
     this.settingsDB.init();
     this.messages.forEach((function(msgName) {
       ppmm.addMessageListener(msgName, this);
     }).bind(this));
     Services.obs.addObserver(this, kXpcomShutdownObserverTopic, false);
@@ -645,31 +653,49 @@ let SettingsRequestManager = {
     if (VERBOSE) debug("Running tasks for " + aLockID);
     let lock = this.lockInfo[aLockID];
     if (!lock) {
       if (DEBUG) debug("Lock no longer alive, cannot run tasks");
       return;
     }
     let currentTask = lock.tasks.shift();
     let promises = [];
+    if (TRACK) {
+      if (this.tasksConsumed[aLockID] === undefined) {
+        this.tasksConsumed[aLockID] = 0;
+        this.tasksGetConsumed[aLockID] = 0;
+        this.tasksSetConsumed[aLockID] = 0;
+      }
+    }
     while (currentTask) {
       if (VERBOSE) debug("Running Operation " + currentTask.operation);
       if (lock.finalizing) {
         // We should really never get to this point, but if we do,
         // fail every task that happens.
         Cu.reportError("Settings lock trying to run more tasks after finalizing. Ignoring tasks, but this is bad. Lock: " + aLockID);
         currentTask.defer.reject("Cannot call new task after finalizing");
       } else {
       let p;
-      this.tasksConsumed++;
+      this.totalProcessed++;
+      if (TRACK) {
+        this.tasksConsumed[aLockID]++;
+      }
       switch (currentTask.operation) {
         case "get":
+          this.totalGetProcessed++;
+          if (TRACK) {
+            this.tasksGetConsumed[aLockID]++;
+          }
           p = this.taskGet(currentTask);
           break;
         case "set":
+          this.totalSetProcessed++;
+          if (TRACK) {
+            this.tasksSetConsumed[aLockID]++;
+          }
           p = this.taskSet(currentTask);
           break;
         case "clear":
           p = this.taskClear(currentTask);
           break;
         case "finalize":
           p = this.finalizeSets(currentTask);
           break;
@@ -748,33 +774,85 @@ let SettingsRequestManager = {
     for (let lockId of Object.keys(this.lockInfo)) {
       let lock = this.lockInfo[lockId];
       let length = lock.tasks.length;
 
       if (length === 0) {
         continue;
       }
 
-      let path = "settings-locks/tasks/queue-length(id=" + lockId + ")";
+      let path = "settings-locks/tasks/lock(id=" + lockId + ")/";
 
-      aCallback.callback("", path,
+      aCallback.callback("", path + "alive",
                          Ci.nsIMemoryReporter.KIND_OTHER,
                          Ci.nsIMemoryReporter.UNITS_COUNT,
                          length,
-                         "Tasks queue length for this lock",
+                         "Alive tasks for this lock",
                          aData);
     }
 
     aCallback.callback("",
-                       "settings-locks/tasks/processed",
+                       "settings-locks/tasks-total/processed",
+                       Ci.nsIMemoryReporter.KIND_OTHER,
+                       Ci.nsIMemoryReporter.UNITS_COUNT,
+                       this.totalProcessed,
+                       "The total number of tasks that were executed.",
+                       aData);
+
+    aCallback.callback("",
+                       "settings-locks/tasks-total/set",
+                       Ci.nsIMemoryReporter.KIND_OTHER,
+                       Ci.nsIMemoryReporter.UNITS_COUNT,
+                       this.totalSetProcessed,
+                       "The total number of set tasks that were executed.",
+                       aData);
+
+    aCallback.callback("",
+                       "settings-locks/tasks-total/get",
                        Ci.nsIMemoryReporter.KIND_OTHER,
                        Ci.nsIMemoryReporter.UNITS_COUNT,
-                       this.tasksConsumed,
-                       "The number of tasks that were executed.",
+                       this.totalGetProcessed,
+                       "The total number of get tasks that were executed.",
                        aData);
+
+    // if TRACK is not enabled, then, no details are available
+    if (!TRACK) {
+      return;
+    }
+
+    for (let lockId of Object.keys(this.tasksConsumed)) {
+      let lock = this.lockInfo[lockId];
+      let length = 0;
+      if (lock) {
+        length = lock.tasks.length;
+      }
+
+      let path = "settings-locks/tasks/lock(id=" + lockId + ")/";
+
+      aCallback.callback("", path + "set",
+                         Ci.nsIMemoryReporter.KIND_OTHER,
+                         Ci.nsIMemoryReporter.UNITS_COUNT,
+                         this.tasksSetConsumed[lockId],
+                         "Set tasks for this lock.",
+                         aData);
+
+      aCallback.callback("", path + "get",
+                         Ci.nsIMemoryReporter.KIND_OTHER,
+                         Ci.nsIMemoryReporter.UNITS_COUNT,
+                         this.tasksGetConsumed[lockId],
+                         "Get tasks for this lock.",
+                         aData);
+
+      aCallback.callback("", path + "processed",
+                         Ci.nsIMemoryReporter.KIND_OTHER,
+                         Ci.nsIMemoryReporter.UNITS_COUNT,
+                         this.tasksConsumed[lockId],
+                         "Number of tasks that were executed.",
+                         aData);
+    }
   },
 
   sendSettingsChange: function(aKey, aValue, aIsServiceLock) {
     this.broadcastMessage("Settings:Change:Return:OK",
       { key: aKey, value: aValue });
     var setting = {
       key: aKey,
       value: aValue,
--- a/dom/settings/SettingsService.js
+++ b/dom/settings/SettingsService.js
@@ -27,18 +27,22 @@ function debug(s) {
 }
 
 XPCOMUtils.defineLazyServiceGetter(this, "uuidgen",
                                    "@mozilla.org/uuid-generator;1",
                                    "nsIUUIDGenerator");
 XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
                                    "@mozilla.org/childprocessmessagemanager;1",
                                    "nsIMessageSender");
+XPCOMUtils.defineLazyServiceGetter(this, "mrm",
+                                   "@mozilla.org/memory-reporter-manager;1",
+                                   "nsIMemoryReporterManager");
 
-const nsIClassInfo            = Ci.nsIClassInfo;
+const nsIClassInfo                   = Ci.nsIClassInfo;
+const kXpcomShutdownObserverTopic    = "xpcom-shutdown";
 
 const SETTINGSSERVICELOCK_CONTRACTID = "@mozilla.org/settingsServiceLock;1";
 const SETTINGSSERVICELOCK_CID        = Components.ID("{d7a395a0-e292-11e1-834e-1761d57f5f99}");
 const nsISettingsServiceLock         = Ci.nsISettingsServiceLock;
 
 function makeSettingsServiceRequest(aCallback, aName, aValue) {
   return {
     callback: aCallback,
@@ -80,16 +84,17 @@ function SettingsServiceLock(aSettingsSe
 
 SettingsServiceLock.prototype = {
   get closed() {
     return !this._open;
   },
 
   runOrFinalizeQueries: function() {
     if (!this._requests || Object.keys(this._requests).length == 0) {
+      this._settingsService.unregisterLock(this._id);
       cpmm.sendAsyncMessage("Settings:Finalize", {lockID: this._id}, undefined, Services.scriptSecurityManager.getSystemPrincipal());
     } else {
       cpmm.sendAsyncMessage("Settings:Run", {lockID: this._id}, undefined, Services.scriptSecurityManager.getSystemPrincipal());
     }
   },
 
   receiveMessage: function(aMessage) {
 
@@ -224,22 +229,86 @@ SettingsServiceLock.prototype = {
   QueryInterface : XPCOMUtils.generateQI([nsISettingsServiceLock])
 };
 
 const SETTINGSSERVICE_CID        = Components.ID("{f656f0c0-f776-11e1-a21f-0800200c9a66}");
 
 function SettingsService()
 {
   if (VERBOSE) debug("settingsService Constructor");
+  this._locks = [];
+  this._createdLocks = 0;
+  this._unregisteredLocks = 0;
+  this.init();
 }
 
 SettingsService.prototype = {
 
+  init: function() {
+    Services.obs.addObserver(this, kXpcomShutdownObserverTopic, false);
+    mrm.registerStrongReporter(this);
+  },
+
+  uninit: function() {
+    Services.obs.removeObserver(this, kXpcomShutdownObserverTopic);
+    mrm.unregisterStrongReporter(this);
+  },
+
+  observe: function(aSubject, aTopic, aData) {
+    if (VERBOSE) debug("observe: " + aTopic);
+    if (aTopic === kXpcomShutdownObserverTopic) {
+      this.uninit();
+    }
+  },
+
   createLock: function createLock(aCallback) {
     var lock = new SettingsServiceLock(this, aCallback);
+    this.registerLock(lock._id);
     return lock;
   },
 
+  registerLock: function(aLockID) {
+    this._locks.push(aLockID);
+    this._createdLocks++;
+  },
+
+  unregisterLock: function(aLockID) {
+    let lock_index = this._locks.indexOf(aLockID);
+    if (lock_index != -1) {
+      if (VERBOSE) debug("Unregistering lock " + aLockID);
+      this._locks.splice(lock_index, 1);
+      this._unregisteredLocks++;
+    }
+  },
+
+  collectReports: function(aCallback, aData, aAnonymize) {
+    aCallback.callback("",
+                       "settings-service-locks/alive",
+                       Ci.nsIMemoryReporter.KIND_OTHER,
+                       Ci.nsIMemoryReporter.UNITS_COUNT,
+                       this._locks.length,
+                       "The number of service locks that are currently alives.",
+                       aData);
+
+    aCallback.callback("",
+                       "settings-service-locks/created",
+                       Ci.nsIMemoryReporter.KIND_OTHER,
+                       Ci.nsIMemoryReporter.UNITS_COUNT,
+                       this._createdLocks,
+                       "The number of service locks that were created.",
+                       aData);
+
+    aCallback.callback("",
+                       "settings-service-locks/deleted",
+                       Ci.nsIMemoryReporter.KIND_OTHER,
+                       Ci.nsIMemoryReporter.UNITS_COUNT,
+                       this._unregisteredLocks,
+                       "The number of service locks that were deleted.",
+                       aData);
+  },
+
   classID : SETTINGSSERVICE_CID,
-  QueryInterface : XPCOMUtils.generateQI([Ci.nsISettingsService])
+  QueryInterface : XPCOMUtils.generateQI([Ci.nsISettingsService,
+                                          Ci.nsIObserver,
+                                          Ci.nsIMemoryReporter])
 };
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SettingsService, SettingsServiceLock]);
--- a/dom/wifi/WifiProxyService.cpp
+++ b/dom/wifi/WifiProxyService.cpp
@@ -60,16 +60,19 @@ public:
     : mInterface(aInterface)
   {
     MOZ_ASSERT(NS_IsMainThread());
   }
 
   NS_IMETHOD Run()
   {
     MOZ_ASSERT(!NS_IsMainThread());
+#ifdef MOZ_NUWA_PROCESS
+    NS_SetIgnoreStatusOfCurrentThread();
+#endif
     nsAutoString event;
     gWpaSupplicant->WaitForEvent(event, mInterface);
     if (!event.IsEmpty()) {
 #ifdef MOZ_TASK_TRACER
       // Make wifi initialization events to be the source events of TaskTracer,
       // and originate the rest correlation tasks from here.
       AutoSourceEvent taskTracerEvent(SourceEventType::Wifi);
       AddLabel("%s %s", mInterface.get(), NS_ConvertUTF16toUTF8(event).get());
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -68,16 +68,17 @@
 #include "nsHostObjectProtocolHandler.h"
 #include "nsJSEnvironment.h"
 #include "nsJSUtils.h"
 #include "nsNetUtil.h"
 #include "nsPrintfCString.h"
 #include "nsProxyRelease.h"
 #include "nsSandboxFlags.h"
 #include "prthread.h"
+#include "nsThread.h"
 #include "xpcpublic.h"
 
 #ifdef ANDROID
 #include <android/log.h>
 #endif
 
 #ifdef DEBUG
 #include "nsThreadManager.h"
@@ -4327,16 +4328,27 @@ WorkerPrivate::DoRunLoop(JSContext* aCx)
     }
 
     Status currentStatus;
     bool normalRunnablesPending = false;
 
     {
       MutexAutoLock lock(mMutex);
 
+#ifdef MOZ_NUWA_PROCESS
+      {
+        nsThread *thr = static_cast<nsThread*>(NS_GetCurrentThread());
+        ReentrantMonitorAutoEnter mon(thr->ThreadStatusMonitor());
+        if (mControlQueue.IsEmpty() &&
+            !(normalRunnablesPending = NS_HasPendingEvents(mThread))) {
+          thr->SetIdle();
+        }
+      }
+#endif // MOZ_NUWA_PROCESS
+
       while (mControlQueue.IsEmpty() &&
              !(normalRunnablesPending = NS_HasPendingEvents(mThread))) {
         WaitForWorkerEvents();
       }
 
       ProcessAllControlRunnablesLocked();
 
       currentStatus = mStatus;
--- a/gfx/layers/GrallocImages.h
+++ b/gfx/layers/GrallocImages.h
@@ -92,16 +92,21 @@ public:
   void* GetNativeBuffer();
 
   virtual bool IsValid() { return !!mTextureClient; }
 
   virtual ISharedImage* AsSharedImage() MOZ_OVERRIDE { return this; }
 
   virtual TextureClient* GetTextureClient(CompositableClient* aClient) MOZ_OVERRIDE;
 
+  virtual GrallocImage* AsGrallocImage() MOZ_OVERRIDE
+  {
+    return this;
+  }
+
   virtual uint8_t* GetBuffer()
   {
     return static_cast<uint8_t*>(GetNativeBuffer());
   }
 
   int GetUsage()
   {
     return (static_cast<ANativeWindowBuffer*>(GetNativeBuffer()))->usage;
--- a/gfx/layers/ImageContainer.cpp
+++ b/gfx/layers/ImageContainer.cpp
@@ -14,16 +14,17 @@
 #include "mozilla/ipc/CrossProcessMutex.h"  // for CrossProcessMutex, etc
 #include "mozilla/layers/CompositorTypes.h"
 #include "mozilla/layers/ImageBridgeChild.h"  // for ImageBridgeChild
 #include "mozilla/layers/ImageClient.h"  // for ImageClient
 #include "nsISupportsUtils.h"           // for NS_IF_ADDREF
 #include "YCbCrUtils.h"                 // for YCbCr conversions
 #ifdef MOZ_WIDGET_GONK
 #include "GrallocImages.h"
+#include "GonkCameraImage.h"
 #endif
 #include "gfx2DGlue.h"
 #include "mozilla/gfx/2D.h"
 
 #ifdef XP_MACOSX
 #include "mozilla/gfx/QuartzSupport.h"
 #include "MacIOSurfaceImage.h"
 #endif
@@ -55,16 +56,20 @@ ImageFactory::CreateImage(ImageFormat aF
   if (aFormat == ImageFormat::GRALLOC_PLANAR_YCBCR) {
     img = new GrallocImage();
     return img.forget();
   }
   if (aFormat == ImageFormat::OVERLAY_IMAGE) {
     img = new OverlayImage();
     return img.forget();
   }
+  if (aFormat == ImageFormat::GONK_CAMERA_IMAGE) {
+    img = new GonkCameraImage();
+    return img.forget();
+  }
 #endif
   if (aFormat == ImageFormat::PLANAR_YCBCR) {
     img = new PlanarYCbCrImage(aRecycleBin);
     return img.forget();
   }
   if (aFormat == ImageFormat::CAIRO_SURFACE) {
     img = new CairoImage();
     return img.forget();
--- a/gfx/layers/ImageContainer.h
+++ b/gfx/layers/ImageContainer.h
@@ -100,16 +100,17 @@ class CrossProcessMutex;
 namespace layers {
 
 class ImageClient;
 class SharedPlanarYCbCrImage;
 class TextureClient;
 class CompositableClient;
 class CompositableForwarder;
 class SurfaceDescriptor;
+class GrallocImage;
 
 struct ImageBackendData
 {
   virtual ~ImageBackendData() {}
 
 protected:
   ImageBackendData() {}
 };
@@ -162,16 +163,21 @@ public:
 
   int32_t GetSerial() { return mSerial; }
 
   void MarkSent() { mSent = true; }
   bool IsSentToCompositor() { return mSent; }
 
   virtual TemporaryRef<gfx::SourceSurface> GetAsSourceSurface() = 0;
 
+  virtual GrallocImage* AsGrallocImage()
+  {
+    return nullptr;
+  }
+
 protected:
   Image(void* aImplData, ImageFormat aFormat) :
     mImplData(aImplData),
     mSerial(++sSerialCounter),
     mFormat(aFormat),
     mSent(false)
   {}
 
--- a/gfx/layers/ImageTypes.h
+++ b/gfx/layers/ImageTypes.h
@@ -21,16 +21,26 @@ MOZ_BEGIN_ENUM_CLASS(ImageFormat)
   /**
    * The GRALLOC_PLANAR_YCBCR format creates a GrallocImage, a subtype of
    * PlanarYCbCrImage. It takes a PlanarYCbCrImage data or the raw gralloc
    * data and can be used as a texture by Gonk backend directly.
    */
   GRALLOC_PLANAR_YCBCR,
 
   /**
+   * The GONK_CAMERA_IMAGE format creates a GonkCameraImage, which contains two
+   * parts. One is GrallocImage image for preview image. Another one is
+   * MediaBuffer from Gonk recording image. The preview image can be rendered in
+   * a layer for display. And the MediaBuffer will be used in component like OMX
+   * encoder. It is for GUM to support preview and recording image on Gonk
+   * camera.
+   */
+  GONK_CAMERA_IMAGE,
+
+  /**
    * The SHARED_RGB format creates a SharedRGBImage, which stores RGB data in
    * shared memory. Some Android hardware video decoders require this format.
    * Currently only used on Android.
    */
   SHARED_RGB,
 
   /**
    * The CAIRO_SURFACE format creates a CairoImage. All backends should
--- a/gfx/layers/client/CanvasClient.cpp
+++ b/gfx/layers/client/CanvasClient.cpp
@@ -368,16 +368,21 @@ CanvasClientSharedSurface::Update(gfx::I
   if (!newTex) {
     auto manager = aLayer->ClientManager();
     auto shadowForwarder = manager->AsShadowForwarder();
     auto layersBackend = shadowForwarder->GetCompositorBackendType();
 
     newTex = TexClientFromReadback(surf, forwarder, flags, layersBackend);
   }
   MOZ_ASSERT(newTex);
+  if (!newTex) {
+    // May happen in a release build in case of memory pressure.
+    gfxCriticalError() << "Failed to allocate a TextureClient for SharedSurface Canvas. size: " << aSize;
+    return;
+  }
 
   // Add the new TexClient.
   MOZ_ALWAYS_TRUE( AddTextureClient(newTex) );
 
   // Remove the old TexClient.
   if (mFrontTex) {
     // remove old buffer from CompositableHost
     RefPtr<AsyncTransactionTracker> tracker = new RemoveTextureFromCompositableTracker();
--- a/gfx/layers/ipc/CompositorParent.cpp
+++ b/gfx/layers/ipc/CompositorParent.cpp
@@ -191,48 +191,60 @@ static Thread* CompositorThread() {
   return sCompositorThreadHolder ? sCompositorThreadHolder->GetCompositorThread() : nullptr;
 }
 
 static void SetThreadPriority()
 {
   hal::SetCurrentThreadPriority(hal::THREAD_PRIORITY_COMPOSITOR);
 }
 
-CompositorVsyncObserver::CompositorVsyncObserver(CompositorParent* aCompositorParent)
+CompositorVsyncObserver::CompositorVsyncObserver(CompositorParent* aCompositorParent, nsIWidget* aWidget)
   : mNeedsComposite(false)
   , mIsObservingVsync(false)
   , mCompositorParent(aCompositorParent)
   , mCurrentCompositeTaskMonitor("CurrentCompositeTaskMonitor")
   , mCurrentCompositeTask(nullptr)
 {
-
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aWidget != nullptr);
+  mVsyncDispatcher = aWidget->GetVsyncDispatcher();
+#ifdef MOZ_WIDGET_GONK
+  GeckoTouchDispatcher::SetCompositorVsyncObserver(this);
+#endif
 }
 
 CompositorVsyncObserver::~CompositorVsyncObserver()
 {
-  MOZ_ASSERT(NS_IsMainThread());
-  UnobserveVsync();
+  MOZ_ASSERT(CompositorParent::IsInCompositorThread());
+  MOZ_ASSERT(!mIsObservingVsync);
+  // The VsyncDispatcher is cleaned up before this in the nsBaseWidget, which stops vsync listeners
+  CancelCurrentCompositeTask();
   mCompositorParent = nullptr;
+  mVsyncDispatcher = nullptr;
   mNeedsComposite = false;
-  CancelCurrentCompositeTask();
 }
 
 /**
  * TODO Potential performance heuristics:
  * If a composite takes 17 ms, do we composite ASAP or wait until next vsync?
  * If a layer transaction comes after vsync, do we composite ASAP or wait until
  * next vsync?
  * How many skipped vsync events until we stop listening to vsync events?
  */
 void
 CompositorVsyncObserver::SetNeedsComposite(bool aNeedsComposite)
 {
-  MOZ_ASSERT(CompositorParent::IsInCompositorThread());
+  if (aNeedsComposite && !CompositorParent::IsInCompositorThread()) {
+    CompositorParent::CompositorLoop()->PostTask(FROM_HERE,
+      NewRunnableMethod(this,
+                        &CompositorVsyncObserver::SetNeedsComposite,
+                        aNeedsComposite));
+  }
+
   mNeedsComposite = aNeedsComposite;
-
   if (!mIsObservingVsync && mNeedsComposite) {
     ObserveVsync();
   }
 }
 
 bool
 CompositorVsyncObserver::NotifyVsync(TimeStamp aVsyncTimestamp)
 {
@@ -268,59 +280,49 @@ CompositorVsyncObserver::Composite(TimeS
   {
     MonitorAutoLock lock(mCurrentCompositeTaskMonitor);
     mCurrentCompositeTask = nullptr;
   }
 
   if (mNeedsComposite && mCompositorParent) {
     mNeedsComposite = false;
     mCompositorParent->CompositeCallback(aVsyncTimestamp);
-  } else {
-    // We're getting vsync notifications but we don't need to composite so
-    // unregister the vsync.
-    UnobserveVsync();
   }
 
   DispatchTouchEvents(aVsyncTimestamp);
 }
 
 bool
 CompositorVsyncObserver::NeedsComposite()
 {
   MOZ_ASSERT(CompositorParent::IsInCompositorThread());
   return mNeedsComposite;
 }
 
-/**
- * Since the vsync thread has its own locks before notifying us of vsync
- * we can't register/unregister from the vsync thread. Any other thread is fine
- */
 void
 CompositorVsyncObserver::ObserveVsync()
 {
   MOZ_ASSERT(CompositorParent::IsInCompositorThread());
-  VsyncDispatcher::GetInstance()->AddCompositorVsyncObserver(this);
+  mVsyncDispatcher->SetCompositorVsyncObserver(this);
   mIsObservingVsync = true;
 }
 
 void
 CompositorVsyncObserver::UnobserveVsync()
 {
   MOZ_ASSERT(CompositorParent::IsInCompositorThread() || NS_IsMainThread());
-  VsyncDispatcher::GetInstance()->RemoveCompositorVsyncObserver(this);
+  mVsyncDispatcher->SetCompositorVsyncObserver(nullptr);
   mIsObservingVsync = false;
 }
 
 void
 CompositorVsyncObserver::DispatchTouchEvents(TimeStamp aVsyncTimestamp)
 {
 #ifdef MOZ_WIDGET_GONK
-  if (gfxPrefs::TouchResampling()) {
-    GeckoTouchDispatcher::NotifyVsync(aVsyncTimestamp);
-  }
+  GeckoTouchDispatcher::NotifyVsync(aVsyncTimestamp);
 #endif
 }
 
 void CompositorParent::StartUp()
 {
   MOZ_ASSERT(NS_IsMainThread(), "Should be on the main Thread!");
   MOZ_ASSERT(!sCompositorThreadHolder, "The compositor thread has already been started!");
 
@@ -380,17 +382,17 @@ CompositorParent::CompositorParent(nsIWi
   mRootLayerTreeID = AllocateLayerTreeId();
   sIndirectLayerTrees[mRootLayerTreeID].mParent = this;
 
   if (gfxPrefs::AsyncPanZoomEnabled()) {
     mApzcTreeManager = new APZCTreeManager();
   }
 
   if (gfxPrefs::VsyncAlignedCompositor()) {
-    mCompositorVsyncObserver = new CompositorVsyncObserver(this);
+    mCompositorVsyncObserver = new CompositorVsyncObserver(this, aWidget);
   }
 
   gfxPlatform::GetPlatform()->ComputeTileSize();
 }
 
 bool
 CompositorParent::IsInCompositorThread()
 {
@@ -423,17 +425,20 @@ CompositorParent::Destroy()
   mCompositor = nullptr;
 
   mCompositionManager = nullptr;
   if (mApzcTreeManager) {
     mApzcTreeManager->ClearTree();
     mApzcTreeManager = nullptr;
   }
   sIndirectLayerTrees.erase(mRootLayerTreeID);
-  mCompositorVsyncObserver = nullptr;
+  if (mCompositorVsyncObserver) {
+    mCompositorVsyncObserver->UnobserveVsync();
+    mCompositorVsyncObserver = nullptr;
+  }
 }
 
 void
 CompositorParent::ForceIsFirstPaint()
 {
   mCompositionManager->ForceIsFirstPaint();
 }
 
--- a/gfx/layers/ipc/CompositorParent.h
+++ b/gfx/layers/ipc/CompositorParent.h
@@ -95,34 +95,35 @@ private:
  * Turns vsync notifications into scheduled composites.
  **/
 
 class CompositorVsyncObserver MOZ_FINAL : public VsyncObserver
 {
   friend class CompositorParent;
 
 public:
-  explicit CompositorVsyncObserver(CompositorParent* aCompositorParent);
+  explicit CompositorVsyncObserver(CompositorParent* aCompositorParent, nsIWidget* aWidget);
   virtual bool NotifyVsync(TimeStamp aVsyncTimestamp) MOZ_OVERRIDE;
   void SetNeedsComposite(bool aSchedule);
   bool NeedsComposite();
   void CancelCurrentCompositeTask();
- 
+
 private:
   virtual ~CompositorVsyncObserver();
 
   void Composite(TimeStamp aVsyncTimestamp);
   void NotifyCompositeTaskExecuted();
   void ObserveVsync();
   void UnobserveVsync();
   void DispatchTouchEvents(TimeStamp aVsyncTimestamp);
 
   bool mNeedsComposite;
   bool mIsObservingVsync;
   nsRefPtr<CompositorParent> mCompositorParent;
+  nsRefPtr<VsyncDispatcher> mVsyncDispatcher;
 
   mozilla::Monitor mCurrentCompositeTaskMonitor;
   CancelableTask* mCurrentCompositeTask;
 };
 
 class CompositorParent MOZ_FINAL : public PCompositorParent,
                                    public ShadowLayersManager
 {
new file mode 100644
--- /dev/null
+++ b/gfx/thebes/VsyncSource.cpp
@@ -0,0 +1,66 @@
+/* -*- 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 "VsyncSource.h"
+#include "gfxPlatform.h"
+#include "mozilla/TimeStamp.h"
+#include "mozilla/VsyncDispatcher.h"
+
+using namespace mozilla;
+using namespace mozilla::gfx;
+
+void
+VsyncSource::AddVsyncDispatcher(VsyncDispatcher* aVsyncDispatcher)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  GetGlobalDisplay().AddVsyncDispatcher(aVsyncDispatcher);
+}
+
+void
+VsyncSource::RemoveVsyncDispatcher(VsyncDispatcher* aVsyncDispatcher)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  GetGlobalDisplay().RemoveVsyncDispatcher(aVsyncDispatcher);
+}
+
+VsyncSource::Display&
+VsyncSource::FindDisplay(VsyncDispatcher* aVsyncDispatcher)
+{
+  return GetGlobalDisplay();
+}
+
+void
+VsyncSource::Display::NotifyVsync(TimeStamp aVsyncTimestamp)
+{
+  // Called on the hardware vsync thread
+  for (size_t i = 0; i < mVsyncDispatchers.Length(); i++) {
+    mVsyncDispatchers[i]->NotifyVsync(aVsyncTimestamp);
+  }
+}
+
+VsyncSource::Display::Display()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+}
+
+VsyncSource::Display::~Display()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  mVsyncDispatchers.Clear();
+}
+
+void
+VsyncSource::Display::AddVsyncDispatcher(VsyncDispatcher* aVsyncDispatcher)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  mVsyncDispatchers.AppendElement(aVsyncDispatcher);
+}
+
+void
+VsyncSource::Display::RemoveVsyncDispatcher(VsyncDispatcher* aVsyncDispatcher)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  mVsyncDispatchers.RemoveElement(aVsyncDispatcher);
+}
new file mode 100644
--- /dev/null
+++ b/gfx/thebes/VsyncSource.h
@@ -0,0 +1,50 @@
+/* -*- 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 "mozilla/RefPtr.h"
+#include "mozilla/TimeStamp.h"
+#include "nsISupportsImpl.h"
+#include "nsTArray.h"
+
+namespace mozilla {
+class VsyncDispatcher;
+
+namespace gfx {
+
+// Controls how and when to enable/disable vsync. Lives as long as the
+// gfxPlatform does on the parent process
+class VsyncSource
+{
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VsyncSource)
+public:
+  // Controls vsync unique to each display and unique on each platform
+  class Display {
+    public:
+      Display();
+      virtual ~Display();
+      void AddVsyncDispatcher(mozilla::VsyncDispatcher* aVsyncDispatcher);
+      void RemoveVsyncDispatcher(mozilla::VsyncDispatcher* aVsyncDispatcher);
+      // Notified when this display's vsync occurs, on the hardware vsync thread
+      void NotifyVsync(mozilla::TimeStamp aVsyncTimestamp);
+
+      // These should all only be called on the main thread
+      virtual void EnableVsync() = 0;
+      virtual void DisableVsync() = 0;
+      virtual bool IsVsyncEnabled() = 0;
+
+    private:
+      nsTArray<nsRefPtr<mozilla::VsyncDispatcher>> mVsyncDispatchers;
+  }; // end Display
+
+  void AddVsyncDispatcher(mozilla::VsyncDispatcher* aVsyncDispatcher);
+  void RemoveVsyncDispatcher(mozilla::VsyncDispatcher* aVsyncDispatcher);
+
+protected:
+  virtual Display& GetGlobalDisplay() = 0; // Works across all displays
+  virtual Display& FindDisplay(mozilla::VsyncDispatcher* aVsyncDispatcher);
+  virtual ~VsyncSource() {}
+}; // VsyncSource
+} // gfx
+} // mozilla
--- a/gfx/thebes/gfxAndroidPlatform.cpp
+++ b/gfx/thebes/gfxAndroidPlatform.cpp
@@ -18,23 +18,26 @@
 #include "mozilla/dom/ContentChild.h"
 #include "nsXULAppAPI.h"
 #include "nsIScreen.h"
 #include "nsIScreenManager.h"
 #include "nsILocaleService.h"
 #include "nsServiceManagerUtils.h"
 #include "gfxPrefs.h"
 #include "cairo.h"
+#include "VsyncSource.h"
 
 #ifdef MOZ_WIDGET_ANDROID
 #include "AndroidBridge.h"
 #endif
 
 #ifdef MOZ_WIDGET_GONK
 #include <cutils/properties.h>
+#include "mozilla/layers/CompositorParent.h"
+#include "HwcComposer2D.h"
 #endif
 
 #include "ft2build.h"
 #include FT_FREETYPE_H
 #include FT_MODULE_H
 
 using namespace mozilla;
 using namespace mozilla::dom;
@@ -415,8 +418,77 @@ bool gfxAndroidPlatform::HaveChoiceOfHWA
 #ifdef MOZ_WIDGET_ANDROID
     if (AndroidBridge::Bridge()->GetAPIVersion() < 11) {
         // It's slower than software due to not having a compositing fast path
         return false;
     }
 #endif
     return gfxPlatform::HaveChoiceOfHWAndSWCanvas();
 }
+
+#ifdef MOZ_WIDGET_GONK
+class GonkVsyncSource MOZ_FINAL : public VsyncSource
+{
+public:
+  GonkVsyncSource()
+  {
+  }
+
+  virtual Display& GetGlobalDisplay() MOZ_OVERRIDE
+  {
+    return mGlobalDisplay;
+  }
+
+protected:
+  class GonkDisplay MOZ_FINAL : public VsyncSource::Display
+  {
+  public:
+    GonkDisplay() : mVsyncEnabled(false)
+    {
+      EnableVsync();
+    }
+
+    ~GonkDisplay()
+    {
+      DisableVsync();
+    }
+
+    virtual void EnableVsync() MOZ_OVERRIDE
+    {
+      MOZ_ASSERT(NS_IsMainThread());
+      mVsyncEnabled = HwcComposer2D::GetInstance()->EnableVsync(true);
+    }
+
+    virtual void DisableVsync() MOZ_OVERRIDE
+    {
+      MOZ_ASSERT(NS_IsMainThread());
+      mVsyncEnabled = HwcComposer2D::GetInstance()->EnableVsync(false);
+    }
+
+    virtual bool IsVsyncEnabled() MOZ_OVERRIDE
+    {
+      MOZ_ASSERT(NS_IsMainThread());
+      return mVsyncEnabled;
+    }
+  private:
+    bool mVsyncEnabled;
+  }; // GonkDisplay
+
+private:
+  virtual ~GonkVsyncSource()
+  {
+  }
+
+  GonkDisplay mGlobalDisplay;
+}; // GonkVsyncSource
+#endif
+
+already_AddRefed<mozilla::gfx::VsyncSource>
+gfxAndroidPlatform::CreateHardwareVsyncSource()
+{
+#ifdef MOZ_WIDGET_GONK
+    nsRefPtr<VsyncSource> vsyncSource = new GonkVsyncSource();
+    return vsyncSource.forget();
+#else
+    NS_WARNING("Hardware vsync not supported on android yet");
+    return nullptr;
+#endif
+}
--- a/gfx/thebes/gfxAndroidPlatform.h
+++ b/gfx/thebes/gfxAndroidPlatform.h
@@ -84,16 +84,18 @@ public:
     virtual int GetScreenDepth() const;
 
     virtual bool CanRenderContentToDataSurface() const MOZ_OVERRIDE {
       return true;
     }
 
     virtual bool HaveChoiceOfHWAndSWCanvas() MOZ_OVERRIDE;
     virtual bool UseAcceleratedSkiaCanvas() MOZ_OVERRIDE;
+    virtual already_AddRefed<mozilla::gfx::VsyncSource> CreateHardwareVsyncSource() MOZ_OVERRIDE;
+
 
 #ifdef MOZ_WIDGET_GONK
     virtual bool IsInGonkEmulator() const { return mIsInGonkEmulator; }
 #endif
 
 private:
     int mScreenDepth;
     gfxImageFormat mOffscreenFormat;
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -99,16 +99,17 @@ class mozilla::gl::SkiaGLGlue : public G
 
 #include "mozilla/Preferences.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Mutex.h"
 
 #include "nsIGfxInfo.h"
 #include "nsIXULRuntime.h"
+#include "VsyncSource.h"
 
 namespace mozilla {
 namespace layers {
 #ifdef MOZ_WIDGET_GONK
 void InitGralloc();
 #endif
 void ShutdownTileCache();
 }
@@ -543,18 +544,18 @@ gfxPlatform::Init()
     // Request the imgITools service, implicitly initializing ImageLib.
     nsCOMPtr<imgITools> imgTools = do_GetService("@mozilla.org/image/tools;1");
     if (!imgTools) {
       NS_RUNTIMEABORT("Could not initialize ImageLib");
     }
 
     RegisterStrongMemoryReporter(new GfxMemoryImageReporter());
 
-    if (gfxPrefs::HardwareVsyncEnabled() && gfxPrefs::VsyncAlignedCompositor()) {
-      gPlatform->InitHardwareVsync();
+    if (XRE_IsParentProcess() && gfxPrefs::HardwareVsyncEnabled()) {
+      gPlatform->mVsyncSource = gPlatform->CreateHardwareVsyncSource();
     }
 }
 
 static bool sLayersIPCIsUp = false;
 
 void
 gfxPlatform::Shutdown()
 {
@@ -592,16 +593,17 @@ gfxPlatform::Shutdown()
         NS_ASSERTION(gPlatform->mMemoryPressureObserver, "mMemoryPressureObserver has already gone");
         nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
         if (obs) {
             obs->RemoveObserver(gPlatform->mMemoryPressureObserver, "memory-pressure");
         }
 
         gPlatform->mMemoryPressureObserver = nullptr;
         gPlatform->mSkiaGlue = nullptr;
+        gPlatform->mVsyncSource = nullptr;
     }
 
 #ifdef MOZ_WIDGET_ANDROID
     // Shut down the texture pool
     mozilla::gl::TexturePoolOGL::Shutdown();
 #endif
 
     // Shut down the default GL context provider.
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -45,16 +45,17 @@ class GLContext;
 class SkiaGLGlue;
 }
 namespace gfx {
 class DrawTarget;
 class SourceSurface;
 class DataSourceSurface;
 class ScaledFont;
 class DrawEventRecorder;
+class VsyncSource;
 
 inline uint32_t
 BackendTypeBit(BackendType b)
 {
   return 1 << uint8_t(b);
 }
 }
 }
@@ -578,27 +579,41 @@ public:
     mozilla::gl::SkiaGLGlue* GetSkiaGLGlue();
     void PurgeSkiaCache();
 
     virtual bool IsInGonkEmulator() const { return false; }
 
     static bool UsesOffMainThreadCompositing();
 
     bool HasEnoughTotalSystemMemoryForSkiaGL();
+
+    /**
+     * Get the hardware vsync source for each platform.
+     * Should only exist and be valid on the parent process
+     */
+    virtual mozilla::gfx::VsyncSource* GetHardwareVsync() {
+      MOZ_ASSERT(mVsyncSource != nullptr);
+      MOZ_ASSERT(XRE_IsParentProcess());
+      return mVsyncSource;
+    }
+
 protected:
     gfxPlatform();
     virtual ~gfxPlatform();
 
     void AppendCJKPrefLangs(eFontPrefLang aPrefLangs[], uint32_t &aLen,
                             eFontPrefLang aCharLang, eFontPrefLang aPageLang);
 
     /**
      * Initialized hardware vsync based on each platform.
      */
-    virtual void InitHardwareVsync() {}
+    virtual already_AddRefed<mozilla::gfx::VsyncSource> CreateHardwareVsyncSource() {
+      NS_WARNING("Hardware vsync not supported on platform yet");
+      return nullptr;
+    }
 
     /**
      * Helper method, creates a draw target for a specific Azure backend.
      * Used by CreateOffscreenDrawTarget.
      */
     mozilla::TemporaryRef<DrawTarget>
       CreateDrawTargetForBackend(mozilla::gfx::BackendType aBackend,
                                  const mozilla::gfx::IntSize& aSize,
@@ -654,16 +669,19 @@ protected:
     // max character limit for words in word cache
     int32_t mWordCacheCharLimit;
 
     // max number of entries in word cache
     int32_t mWordCacheMaxEntries;
 
     uint32_t mTotalSystemMemory;
 
+    // Hardware vsync source. Only valid on parent process
+    nsRefPtr<mozilla::gfx::VsyncSource> mVsyncSource;
+
 private:
     /**
      * Start up Thebes.
      */
     static void Init();
 
     static void CreateCMSOutputProfile();
 
--- a/gfx/thebes/gfxPlatformMac.cpp
+++ b/gfx/thebes/gfxPlatformMac.cpp
@@ -21,29 +21,31 @@
 #include "qcms.h"
 #include "gfx2DGlue.h"
 #include "gfxPrefs.h"
 
 #include <dlfcn.h>
 #include <CoreVideo/CoreVideo.h>
 
 #include "nsCocoaFeatures.h"
+#include "mozilla/layers/CompositorParent.h"
+#include "VsyncSource.h"
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 
 // cribbed from CTFontManager.h
 enum {
    kAutoActivationDisabled = 1
 };
 typedef uint32_t AutoActivationSetting;
 
 // bug 567552 - disable auto-activation of fonts
 
-static void 
+static void
 DisableFontActivation()
 {
     // get the main bundle identifier
     CFBundleRef mainBundle = ::CFBundleGetMainBundle();
     CFStringRef mainBundleID = nullptr;
 
     if (mainBundle) {
         mainBundleID = ::CFBundleGetIdentifier(mainBundle);
@@ -424,91 +426,108 @@ gfxPlatformMac::UseProgressivePaint()
 // This is the renderer output callback function, called on the vsync thread
 static CVReturn VsyncCallback(CVDisplayLinkRef aDisplayLink,
                               const CVTimeStamp* aNow,
                               const CVTimeStamp* aOutputTime,
                               CVOptionFlags aFlagsIn,
                               CVOptionFlags* aFlagsOut,
                               void* aDisplayLinkContext)
 {
-  mozilla::VsyncSource* vsyncSource = (mozilla::VsyncSource*) aDisplayLinkContext;
-  if (vsyncSource->IsVsyncEnabled()) {
-    // Now refers to "Now" as in when this callback is called or when the current frame
-    // is displayed. aOutputTime is when the next frame should be displayed.
-    // Now is VERY VERY noisy, aOutputTime is in the future though.
-    int64_t timestamp = aOutputTime->hostTime;
-    mozilla::TimeStamp vsyncTime = mozilla::TimeStamp::FromSystemTime(timestamp);
-    mozilla::VsyncDispatcher::GetInstance()->NotifyVsync(vsyncTime);
-    return kCVReturnSuccess;
-  } else {
-    return kCVReturnDisplayLinkNotRunning;
-  }
+  VsyncSource::Display* display = (VsyncSource::Display*) aDisplayLinkContext;
+  int64_t timestamp = aOutputTime->hostTime;
+  mozilla::TimeStamp vsyncTime = mozilla::TimeStamp::FromSystemTime(timestamp);
+  display->NotifyVsync(vsyncTime);
+  return kCVReturnSuccess;
 }
 
-class OSXVsyncSource MOZ_FINAL : public mozilla::VsyncSource
+class OSXVsyncSource MOZ_FINAL : public VsyncSource
 {
 public:
   OSXVsyncSource()
   {
-    EnableVsync();
+  }
+
+  virtual Display& GetGlobalDisplay() MOZ_OVERRIDE
+  {
+    return mGlobalDisplay;
   }
 
-  virtual void EnableVsync() MOZ_OVERRIDE
+protected:
+  class OSXDisplay MOZ_FINAL : public VsyncSource::Display
   {
-    // Create a display link capable of being used with all active displays
-    // TODO: See if we need to create an active DisplayLink for each monitor in multi-monitor
-    // situations. According to the docs, it is compatible with all displays running on the computer
-    // But if we have different monitors at different display rates, we may hit issues.
-    if (CVDisplayLinkCreateWithActiveCGDisplays(&mDisplayLink) != kCVReturnSuccess) {
-      NS_WARNING("Could not create a display link, returning");
-      return;
+  public:
+    OSXDisplay()
+    {
+      EnableVsync();
     }
 
-    // Set the renderer output callback function
-    if (CVDisplayLinkSetOutputCallback(mDisplayLink, &VsyncCallback, this) != kCVReturnSuccess) {
-      NS_WARNING("Could not set displaylink output callback");
-      return;
+    ~OSXDisplay()
+    {
+      DisableVsync();
     }
 
-    // Activate the display link
-    if (CVDisplayLinkStart(mDisplayLink) != kCVReturnSuccess) {
-      NS_WARNING("Could not activate the display link");
-      mDisplayLink = nullptr;
-    }
-  }
+    virtual void EnableVsync() MOZ_OVERRIDE
+    {
+      MOZ_ASSERT(NS_IsMainThread());
+
+      // Create a display link capable of being used with all active displays
+      // TODO: See if we need to create an active DisplayLink for each monitor in multi-monitor
+      // situations. According to the docs, it is compatible with all displays running on the computer
+      // But if we have different monitors at different display rates, we may hit issues.
+      if (CVDisplayLinkCreateWithActiveCGDisplays(&mDisplayLink) != kCVReturnSuccess) {
+        NS_WARNING("Could not create a display link, returning");
+        return;
+      }
+
+      if (CVDisplayLinkSetOutputCallback(mDisplayLink, &VsyncCallback, this) != kCVReturnSuccess) {
+        NS_WARNING("Could not set displaylink output callback");
+        return;
+      }
 
-  virtual void DisableVsync() MOZ_OVERRIDE
-  {
-    // Release the display link
-    if (mDisplayLink) {
-      CVDisplayLinkRelease(mDisplayLink);
-      mDisplayLink = nullptr;
+      if (CVDisplayLinkStart(mDisplayLink) != kCVReturnSuccess) {
+        NS_WARNING("Could not activate the display link");
+        mDisplayLink = nullptr;
+      }
     }
-  }
+
+    virtual void DisableVsync() MOZ_OVERRIDE
+    {
+      MOZ_ASSERT(NS_IsMainThread());
 
-  virtual bool IsVsyncEnabled() MOZ_OVERRIDE
-  {
-    return mDisplayLink != nullptr;
-  }
+      // Release the display link
+      if (mDisplayLink) {
+        CVDisplayLinkRelease(mDisplayLink);
+        mDisplayLink = nullptr;
+      }
+    }
+
+    virtual bool IsVsyncEnabled() MOZ_OVERRIDE
+    {
+      MOZ_ASSERT(NS_IsMainThread());
+      return mDisplayLink != nullptr;
+    }
+
+  private:
+    // Manages the display link render thread
+    CVDisplayLinkRef   mDisplayLink;
+  }; // OSXDisplay
 
 private:
   virtual ~OSXVsyncSource()
   {
-    DisableVsync();
   }
 
-  // Manages the display link render thread
-  CVDisplayLinkRef   mDisplayLink;
+  OSXDisplay mGlobalDisplay;
 }; // OSXVsyncSource
 
-void
-gfxPlatformMac::InitHardwareVsync()
+already_AddRefed<mozilla::gfx::VsyncSource>
+gfxPlatformMac::CreateHardwareVsyncSource()
 {
   nsRefPtr<VsyncSource> osxVsyncSource = new OSXVsyncSource();
-  mozilla::VsyncDispatcher::GetInstance()->SetVsyncSource(osxVsyncSource);
+  return osxVsyncSource.forget();
 }
 
 void
 gfxPlatformMac::GetPlatformCMSOutputProfile(void* &mem, size_t &size)
 {
     mem = nullptr;
     size = 0;
 
--- a/gfx/thebes/gfxPlatformMac.h
+++ b/gfx/thebes/gfxPlatformMac.h
@@ -4,17 +4,22 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_PLATFORM_MAC_H
 #define GFX_PLATFORM_MAC_H
 
 #include "nsTArrayForwardDeclare.h"
 #include "gfxPlatform.h"
 
-namespace mozilla { namespace gfx { class DrawTarget; }}
+namespace mozilla {
+namespace gfx {
+class DrawTarget;
+class VsyncSource;
+} // gfx
+} // mozilla
 
 class gfxPlatformMac : public gfxPlatform {
 public:
     gfxPlatformMac();
     virtual ~gfxPlatformMac();
 
     static gfxPlatformMac *GetPlatform() {
         return (gfxPlatformMac*) gfxPlatform::GetPlatform();
@@ -62,17 +67,17 @@ public:
     virtual bool CanRenderContentToDataSurface() const MOZ_OVERRIDE {
       return true;
     }
 
     bool UseAcceleratedCanvas();
 
     virtual bool UseTiling() MOZ_OVERRIDE;
     virtual bool UseProgressivePaint() MOZ_OVERRIDE;
-    virtual void InitHardwareVsync() MOZ_OVERRIDE;
+    virtual already_AddRefed<mozilla::gfx::VsyncSource> CreateHardwareVsyncSource() MOZ_OVERRIDE;
 
     // lower threshold on font anti-aliasing
     uint32_t GetAntiAliasingThreshold() { return mFontAntiAliasingThreshold; }
 
 private:
     virtual void GetPlatformCMSOutputProfile(void* &mem, size_t &size);
 
     // read in the pref value for the lower threshold on font anti-aliasing
--- a/gfx/thebes/moz.build
+++ b/gfx/thebes/moz.build
@@ -47,16 +47,17 @@ EXPORTS += [
     'gfxTeeSurface.h',
     'gfxTextRun.h',
     'gfxTypes.h',
     'gfxUserFontSet.h',
     'gfxUtils.h',
     'gfxVR.h',
     'GraphicsFilter.h',
     'RoundedRect.h',
+    'VsyncSource.h',
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
     EXPORTS += [
         'gfxAndroidPlatform.h',
         'gfxFT2FontBase.h',
         'gfxFT2Fonts.h',
         'gfxPDFSurface.h',
@@ -241,16 +242,17 @@ UNIFIED_SOURCES += [
     'gfxSkipChars.cpp',
     'gfxSVGGlyphs.cpp',
     'gfxTeeSurface.cpp',
     'gfxTextRun.cpp',
     'gfxUserFontSet.cpp',
     'gfxUtils.cpp',
     'gfxVR.cpp',
     'nsUnicodeRange.cpp',
+    'VsyncSource.cpp',
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
     UNIFIED_SOURCES += [
         'gfxMacPlatformFontList.mm',
     ]
 
 FAIL_ON_WARNINGS = not CONFIG['_MSC_VER']
@@ -264,16 +266,19 @@ FINAL_LIBRARY = 'xul'
 GENERATED_FILES = [
     'DeprecatedPremultiplyTables.h',
 ]
 
 LOCAL_INCLUDES += [
     '/dom/xml',
 ]
 
+if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
+  LOCAL_INCLUDES += ['/widget/gonk']
+
 if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('android', 'gtk2', 'gtk3', 'gonk', 'qt'):
     DEFINES['MOZ_ENABLE_FREETYPE'] = True
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
     for var in ('MOZ_ENABLE_D3D9_LAYER', 'MOZ_ENABLE_D3D10_LAYER'):
         if CONFIG[var]:
             DEFINES[var] = True
 
--- a/js/src/jit-test/tests/gc/bug-1109922.js
+++ b/js/src/jit-test/tests/gc/bug-1109922.js
@@ -1,5 +1,6 @@
-
-gczeal(14); 
-b = {};
-b.__proto__ = evalcx("lazy");
-(function m(b) {})(b.Intl.Collator(0)) 
+if (this.hasOwnProperty("Intl")) {
+    gczeal(14);
+    b = {};
+    b.__proto__ = evalcx("lazy");
+    (function m(b) {})(b.Intl.Collator(0))
+}
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -417,20 +417,17 @@ if CONFIG['HAVE_LINUX_PERF_EVENT_H']:
         'perf/pm_linux.cpp'
     ]
     SOURCES['perf/pm_linux.cpp'].flags += [CONFIG['LINUX_HEADERS_INCLUDES']]
 else:
     SOURCES += [
         'perf/pm_stub.cpp'
     ]
 
-# Disable PGO for MSVC 2010 due to unpredictable performance, see
-# bug 1030706.
-if CONFIG['_MSC_VER'] != '1600':
-    MSVC_ENABLE_PGO = True
+MSVC_ENABLE_PGO = True
 
 HostSimplePrograms([
     'host_jskwgen',
 ])
 
 # JavaScript must be built shared, even for static builds, as it is used by
 # other modules which are always built shared. Failure to do so results in
 # the js code getting copied into xpinstall and jsd as well as mozilla-bin,
--- a/layout/style/Loader.cpp
+++ b/layout/style/Loader.cpp
@@ -31,17 +31,17 @@
 #include "nsIDOMNode.h"
 #include "nsIDOMDocument.h"
 #include "nsIURI.h"
 #include "nsNetUtil.h"
 #include "nsContentUtils.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsContentPolicyUtils.h"
 #include "nsIHttpChannel.h"
-#include "nsIHttpChannelInternal.h"
+#include "nsIClassOfService.h"
 #include "nsIScriptError.h"
 #include "nsMimeTypes.h"
 #include "nsIStyleSheetLinkingElement.h"
 #include "nsICSSLoaderObserver.h"
 #include "nsCSSParser.h"
 #include "mozilla/CSSStyleSheet.h"
 #include "mozilla/css/ImportRule.h"
 #include "nsThreadUtils.h"
@@ -1618,20 +1618,22 @@ Loader::LoadSheet(SheetLoadData* aLoadDa
 #ifdef DEBUG
     mSyncCallback = false;
 #endif
     LOG_ERROR(("  Failed to create channel"));
     SheetComplete(aLoadData, rv);
     return rv;
   }
 
-  nsCOMPtr<nsIHttpChannelInternal>
-    internalHttpChannel(do_QueryInterface(channel));
-  if (internalHttpChannel)
-      internalHttpChannel->SetLoadAsBlocking(!aLoadData->mWasAlternate);
+  if (!aLoadData->mWasAlternate) {
+    nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(channel));
+    if (cos) {
+      cos->AddClassFlags(nsIClassOfService::Leader);
+    }
+  }
 
   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
   if (httpChannel) {
     // send a minimal Accept header for text/css
     httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
                                   NS_LITERAL_CSTRING("text/css,*/*;q=0.1"),
                                   false);
     nsCOMPtr<nsIURI> referrerURI = aLoadData->GetReferrerURI();
--- a/media/libvpx/moz.build
+++ b/media/libvpx/moz.build
@@ -87,17 +87,17 @@ if CONFIG['OS_TARGET'] == 'Android':
     # the OS they're on, so do it for them.
     DEFINES['__linux__'] = True
 
     if not CONFIG['MOZ_WEBRTC']:
         SOURCES += [
             '%s/sources/android/cpufeatures/cpu-features.c' % CONFIG['ANDROID_NDK'],
         ]
 
-if not CONFIG['_MSC_VER']:
+if CONFIG['CLANG_CL'] or not CONFIG['_MSC_VER']:
     for f in SOURCES:
         if f.endswith('.c'):
             if 'sse2' in f:
                 SOURCES[f].flags += CONFIG['SSE2_FLAGS']
             if 'ssse3' in f:
                 SOURCES[f].flags += ['-mssse3']
             if 'sse4' in f:
                 SOURCES[f].flags += ['-msse4.1']
--- a/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp
+++ b/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp
@@ -1167,18 +1167,18 @@ void MediaPipelineTransmit::PipelineList
   int32_t serial = img->GetSerial();
   if (serial == last_img_) {
     return;
   }
   last_img_ = serial;
 
   ImageFormat format = img->GetFormat();
 #ifdef WEBRTC_GONK
-  if (format == ImageFormat::GRALLOC_PLANAR_YCBCR) {
-    layers::GrallocImage *nativeImage = static_cast<layers::GrallocImage*>(img);
+  layers::GrallocImage* nativeImage = img->AsGrallocImage();
+  if (nativeImage) {
     android::sp<android::GraphicBuffer> graphicBuffer = nativeImage->GetGraphicBuffer();
     int pixelFormat = graphicBuffer->getPixelFormat(); /* PixelFormat is an enum == int */
     mozilla::VideoType destFormat;
     switch (pixelFormat) {
       case HAL_PIXEL_FORMAT_YV12:
         // all android must support this
         destFormat = mozilla::kVideoYV12;
         break;
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -1279,16 +1279,17 @@ pref("network.http.bypass-cachelock-thre
 pref("network.http.bypass-cachelock-threshold", 250);
 #endif
 
 // Try and use SPDY when using SSL
 pref("network.http.spdy.enabled", true);
 pref("network.http.spdy.enabled.v3-1", true);
 pref("network.http.spdy.enabled.http2draft", true);
 pref("network.http.spdy.enabled.http2", true);
+pref("network.http.spdy.enabled.deps", true);
 pref("network.http.spdy.enforce-tls-profile", true);
 pref("network.http.spdy.chunk-size", 16000);
 pref("network.http.spdy.timeout", 180);
 pref("network.http.spdy.coalesce-hostnames", true);
 pref("network.http.spdy.persistent-settings", false);
 pref("network.http.spdy.ping-threshold", 58);
 pref("network.http.spdy.ping-timeout", 8);
 pref("network.http.spdy.send-buffer-size", 131072);
--- a/netwerk/base/public/moz.build
+++ b/netwerk/base/public/moz.build
@@ -25,16 +25,17 @@ XPIDL_SOURCES += [
     'nsIBufferedStreams.idl',
     'nsIByteRangeRequest.idl',
     'nsICacheInfoChannel.idl',
     'nsICachingChannel.idl',
     'nsICancelable.idl',
     'nsIChannel.idl',
     'nsIChannelEventSink.idl',
     'nsIChildChannel.idl',
+    'nsIClassOfService.idl',
     'nsIContentSniffer.idl',
     'nsICryptoFIPSInfo.idl',
     'nsICryptoHash.idl',
     'nsICryptoHMAC.idl',
     'nsIDashboard.idl',
     'nsIDashboardEventNotifier.idl',
     'nsIDivertableChannel.idl',
     'nsIDownloader.idl',
new file mode 100644
--- /dev/null
+++ b/netwerk/base/public/nsIClassOfService.idl
@@ -0,0 +1,45 @@
+/* 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"
+
+/**
+ * nsIClassOfService.idl
+ *
+ * Used to express class dependencies and characteristics - complimentary to
+ * nsISupportsPriority which is used to express weight
+ *
+ * Channels that implement this interface may make use of this
+ * information in different ways.
+ *
+ * The default gecko HTTP/1 stack makes Followers wait for Leaders to
+ * complete before dispatching followers. Other classes run in
+ * parallel - neither being blocked nor blocking. All grouping is done
+ * based on the Load Group - separate load groups proceed
+ * independently.
+ *
+ * HTTP/2 does not use the load group, but prioritization is done per
+ * HTTP/2 session. HTTP/2 dispatches all the requests as soon as
+ * possible.
+ * The various classes are assigned logical priority
+ * dependency groups and then transactions of that class depend on the
+ * group. In this model Followers block on Leaders and Speculative
+ * depends on Background. See Http2Stream.cpp for weighting details.
+ *
+ */
+
+[scriptable, uuid(1ccb58ec-5e07-4cf9-a30d-ac5490d23b41)]
+interface nsIClassOfService : nsISupports
+{
+  attribute unsigned long classFlags;
+
+  void clearClassFlags(in unsigned long flags);
+  void addClassFlags(in unsigned long flags);
+
+  const unsigned long Leader = 1 << 0;
+  const unsigned long Follower = 1 << 1;
+  const unsigned long Speculative = 1 << 2;
+  const unsigned long Background = 1 << 3;
+  const unsigned long Unblocked = 1 << 4;
+};
--- a/netwerk/base/src/Dashboard.cpp
+++ b/netwerk/base/src/Dashboard.cpp
@@ -775,19 +775,20 @@ HttpConnInfo::SetHTTP1ProtocolVersion(ui
     }
 }
 
 void
 HttpConnInfo::SetHTTP2ProtocolVersion(uint8_t pv)
 {
     if (pv == SPDY_VERSION_31) {
         protocolVersion.AssignLiteral(MOZ_UTF16("spdy/3.1"));
-    } else if (pv == NS_HTTP2_DRAFT_VERSION) {
-        MOZ_ASSERT (pv == NS_HTTP2_DRAFT_VERSION);
-        protocolVersion.Assign(NS_LITERAL_STRING(NS_HTTP2_DRAFT_TOKEN));
+    } else if (pv == HTTP_VERSION_2_DRAFT_15) {
+        protocolVersion.AssignLiteral(MOZ_UTF16("h2-14/15"));
+    } else if (pv == HTTP_VERSION_2_DRAFT_LATEST) {
+        protocolVersion.Assign(NS_LITERAL_STRING(HTTP2_DRAFT_LATEST_TOKEN));
     } else {
         MOZ_ASSERT (pv == HTTP_VERSION_2);
         protocolVersion.Assign(MOZ_UTF16("h2"));
     }
 }
 
 NS_IMETHODIMP
 Dashboard::RequestConnection(const nsACString& aHost, uint32_t aPort,
--- a/netwerk/base/src/nsSocketTransportService2.cpp
+++ b/netwerk/base/src/nsSocketTransportService2.cpp
@@ -694,16 +694,17 @@ NS_IMETHODIMP
 nsSocketTransportService::Run()
 {
     PR_SetCurrentThreadName("Socket Thread");
 
 #ifdef MOZ_NUWA_PROCESS
     if (IsNuwaProcess()) {
         NuwaMarkCurrentThread(nullptr, nullptr);
     }
+    NS_SetIgnoreStatusOfCurrentThread();
 #endif
 
     SOCKET_LOG(("STS thread init\n"));
 
     psm::InitializeSSLServerCertVerificationThreads();
 
     gSocketThread = PR_GetCurrentThread();
 
--- a/netwerk/ipc/NeckoChannelParams.ipdlh
+++ b/netwerk/ipc/NeckoChannelParams.ipdlh
@@ -36,16 +36,17 @@ struct HttpChannelOpenArgs
   OptionalURIParams           apiRedirectTo;
   OptionalURIParams           topWindowURI;
   uint32_t                    loadFlags;
   RequestHeaderTuples         requestHeaders;
   nsCString                   requestMethod;
   OptionalInputStreamParams   uploadStream;
   bool                        uploadStreamHasHeaders;
   uint16_t                    priority;
+  uint32_t                    classOfService;
   uint8_t                     redirectionLimit;
   bool                        allowPipelining;
   bool                        allowSTS;
   uint32_t                    thirdPartyFlags;
   bool                        resumeAt;
   uint64_t                    startPos;
   nsCString                   entityID;
   bool                        chooseApplicationCache;
--- a/netwerk/protocol/http/ASpdySession.cpp
+++ b/netwerk/protocol/http/ASpdySession.cpp
@@ -37,30 +37,32 @@ ASpdySession::~ASpdySession()
 ASpdySession *
 ASpdySession::NewSpdySession(uint32_t version,
                              nsISocketTransport *aTransport)
 {
   // This is a necko only interface, so we can enforce version
   // requests as a precondition
   MOZ_ASSERT(version == SPDY_VERSION_31 ||
              version == HTTP_VERSION_2 ||
-             version == NS_HTTP2_DRAFT_VERSION,
+             version == HTTP_VERSION_2_DRAFT_LATEST ||
+             version == HTTP_VERSION_2_DRAFT_15,
              "Unsupported spdy version");
 
   // Don't do a runtime check of IsSpdyV?Enabled() here because pref value
   // may have changed since starting negotiation. The selected protocol comes
   // from a list provided in the SERVER HELLO filtered by our acceptable
   // versions, so there is no risk of the server ignoring our prefs.
 
   Telemetry::Accumulate(Telemetry::SPDY_VERSION2, version);
 
   if (version == SPDY_VERSION_31) {
     return new SpdySession31(aTransport);
-  } else if (version == NS_HTTP2_DRAFT_VERSION || version == HTTP_VERSION_2) {
-    return new Http2Session(aTransport);
+  } else if (version == HTTP_VERSION_2_DRAFT_LATEST || version == HTTP_VERSION_2 ||
+             version == HTTP_VERSION_2_DRAFT_15) {
+    return new Http2Session(aTransport, version);
   }
 
   return nullptr;
 }
 static bool SpdySessionTrue(nsISupports *securityInfo)
 {
   return true;
 }
@@ -72,26 +74,26 @@ SpdyInformation::SpdyInformation()
   Version[0] = SPDY_VERSION_31;
   VersionString[0] = NS_LITERAL_CSTRING("spdy/3.1");
   ALPNCallbacks[0] = SpdySessionTrue;
 
   Version[1] = HTTP_VERSION_2;
   VersionString[1] = NS_LITERAL_CSTRING("h2");
   ALPNCallbacks[1] = Http2Session::ALPNCallback;
 
-  Version[2] = NS_HTTP2_DRAFT_VERSION;
+  Version[2] = HTTP_VERSION_2_DRAFT_15; // 14 and 15 are aliased
   VersionString[2] = NS_LITERAL_CSTRING("h2-14");
   ALPNCallbacks[2] = Http2Session::ALPNCallback;
 
-  Version[3] = NS_HTTP2_DRAFT_VERSION;
+  Version[3] = HTTP_VERSION_2_DRAFT_15; // 14 and 15 are aliased
   VersionString[3] = NS_LITERAL_CSTRING("h2-15");
   ALPNCallbacks[3] = Http2Session::ALPNCallback;
 
-  Version[4] = NS_HTTP2_DRAFT_VERSION;
-  VersionString[4] = NS_LITERAL_CSTRING(NS_HTTP2_DRAFT_TOKEN);
+  Version[4] = HTTP_VERSION_2_DRAFT_LATEST;
+  VersionString[4] = NS_LITERAL_CSTRING(HTTP2_DRAFT_LATEST_TOKEN);
   ALPNCallbacks[4] = Http2Session::ALPNCallback;
 }
 
 bool
 SpdyInformation::ProtocolEnabled(uint32_t index) const
 {
   MOZ_ASSERT(index < kCount, "index out of range");
 
--- a/netwerk/protocol/http/Http2Session.cpp
+++ b/netwerk/protocol/http/Http2Session.cpp
@@ -61,17 +61,17 @@ const uint8_t Http2Session::kMagicHello[
 };
 
 #define RETURN_SESSION_ERROR(o,x)  \
 do {                             \
   (o)->mGoAwayReason = (x);      \
   return NS_ERROR_ILLEGAL_VALUE; \
   } while (0)
 
-Http2Session::Http2Session(nsISocketTransport *aSocketTransport)
+Http2Session::Http2Session(nsISocketTransport *aSocketTransport, uint32_t version)
   : mSocketTransport(aSocketTransport)
   , mSegmentReader(nullptr)
   , mSegmentWriter(nullptr)
   , mNextStreamID(3) // 1 is reserved for Updgrade handshakes
   , mConcurrentHighWater(0)
   , mDownstreamState(BUFFERING_OPENING_SETTINGS)
   , mInputFrameBufferSize(kDefaultBufferSize)
   , mInputFrameBufferUsed(0)
@@ -98,16 +98,18 @@ Http2Session::Http2Session(nsISocketTran
   , mOutputQueueSize(kDefaultQueueSize)
   , mOutputQueueUsed(0)
   , mOutputQueueSent(0)
   , mLastReadEpoch(PR_IntervalNow())
   , mPingSentEpoch(0)
   , mPreviousUsed(false)
   , mWaitingForSettingsAck(false)
   , mGoAwayOnPush(false)
+  , mUseH2Deps(false)
+  , mVersion(version)
 {
   MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
 
   static uint64_t sSerial;
   mSerial = ++sSerial;
 
   LOG3(("Http2Session::Http2Session %p serial=0x%X\n", this, mSerial));
 
@@ -120,17 +122,17 @@ Http2Session::Http2Session(nsISocketTran
 
   mSendingChunkSize = gHttpHandler->SpdySendingChunkSize();
   SendHello();
 
   mLastDataReadEpoch = mLastReadEpoch;
 
   mPingThreshold = gHttpHandler->SpdyPingThreshold();
 
-  mNegotiatedToken.AssignLiteral(NS_HTTP2_DRAFT_TOKEN);
+  mNegotiatedToken.AssignLiteral(HTTP2_DRAFT_LATEST_TOKEN);
 }
 
 // Copy the 32 bit number into the destination, using network byte order
 // in the destination.
 template<typename charType> static void
 CopyAsNetwork32(charType dest,   // where to store it
                 uint32_t number) // the 32 bit number in native format
 {
@@ -784,30 +786,36 @@ Http2Session::GenerateGoAway(uint32_t aS
 
   // bytes 13-16 are the status code.
   CopyAsNetwork32(packet + frameSize - 4, aStatusCode);
 
   LogIO(this, nullptr, "Generate GoAway", packet, frameSize);
   FlushOutputQueue();
 }
 
-// The Hello is comprised of 24 octets of magic, which are designed to
-// flush out silent but broken intermediaries, followed by a settings
-// frame which sets a small flow control window for pushes and a
-// window update frame which creates a large session flow control window
+// The Hello is comprised of
+// 1] 24 octets of magic, which are designed to
+// flush out silent but broken intermediaries
+// 2] a settings frame which sets a small flow control window for pushes
+// 3] a window update frame which creates a large session flow control window
+// 4] 5 priority frames for streams which will never be opened with headers
+//    these streams (3, 5, 7, 9, b) build a dependency tree that all other
+//    streams will be direct leaves of.
 void
 Http2Session::SendHello()
 {
   MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
   LOG3(("Http2Session::SendHello %p\n", this));
 
-  // sized for magic + 4 settings and a session window update to follow
-  // 24 magic, 33 for settings (9 header + 4 settings @6), 13 for window update
+  // sized for magic + 4 settings and a session window update and 5 priority frames
+  // 24 magic, 33 for settings (9 header + 4 settings @6), 13 for window update,
+  // 5 priority frames at 14 (9 + 5) each
   static const uint32_t maxSettings = 4;
-  static const uint32_t maxDataLen = 24 + kFrameHeaderBytes + maxSettings * 6 + 13;
+  static const uint32_t prioritySize = 5 * (kFrameHeaderBytes + 5);
+  static const uint32_t maxDataLen = 24 + kFrameHeaderBytes + maxSettings * 6 + 13 + prioritySize;
   char *packet = EnsureOutputBuffer(maxDataLen);
   memcpy(packet, kMagicHello, 24);
   mOutputQueueUsed += 24;
   LogIO(this, nullptr, "Magic Connection Header", packet, 24);
 
   packet = mOutputQueueBuffer.get() + mOutputQueueUsed;
   memset(packet, 0, maxDataLen - 24);
 
@@ -850,35 +858,71 @@ Http2Session::SendHello()
   uint32_t dataLen = 6 * numberOfEntries;
   CreateFrameHeader(packet, dataLen, FRAME_TYPE_SETTINGS, 0, 0);
   mOutputQueueUsed += kFrameHeaderBytes + dataLen;
 
   LogIO(this, nullptr, "Generate Settings", packet, kFrameHeaderBytes + dataLen);
 
   // now bump the local session window from 64KB
   uint32_t sessionWindowBump = ASpdySession::kInitialRwin - kDefaultRwin;
-  if (kDefaultRwin >= ASpdySession::kInitialRwin)
-    goto sendHello_complete;
-
-  // send a window update for the session (Stream 0) for something large
-  mLocalSessionWindow = ASpdySession::kInitialRwin;
-
-  packet = mOutputQueueBuffer.get() + mOutputQueueUsed;
-  CreateFrameHeader(packet, 4, FRAME_TYPE_WINDOW_UPDATE, 0, 0);
-  mOutputQueueUsed += kFrameHeaderBytes + 4;
-  CopyAsNetwork32(packet + kFrameHeaderBytes, sessionWindowBump);
-
-  LOG3(("Session Window increase at start of session %p %u\n",
-        this, sessionWindowBump));
-  LogIO(this, nullptr, "Session Window Bump ", packet, kFrameHeaderBytes + 4);
-
-sendHello_complete:
+  if (kDefaultRwin < ASpdySession::kInitialRwin) {
+    // send a window update for the session (Stream 0) for something large
+    mLocalSessionWindow = ASpdySession::kInitialRwin;
+
+    packet = mOutputQueueBuffer.get() + mOutputQueueUsed;
+    CreateFrameHeader(packet, 4, FRAME_TYPE_WINDOW_UPDATE, 0, 0);
+    mOutputQueueUsed += kFrameHeaderBytes + 4;
+    CopyAsNetwork32(packet + kFrameHeaderBytes, sessionWindowBump);
+
+    LOG3(("Session Window increase at start of session %p %u\n",
+          this, sessionWindowBump));
+    LogIO(this, nullptr, "Session Window Bump ", packet, kFrameHeaderBytes + 4);
+  }
+
+  // draft-14 and draft-15 are the only versions we support that do not
+  // allow our priority scheme. Blacklist them here - they are aliased
+  // as draft-15
+  if ((mVersion != HTTP_VERSION_2_DRAFT_15) &&
+      gHttpHandler->UseH2Deps() && gHttpHandler->CriticalRequestPrioritization()) {
+    mUseH2Deps = true;
+    MOZ_ASSERT(mNextStreamID == kLeaderGroupID);
+    CreatePriorityNode(kLeaderGroupID, 0, 200, "leader");
+    mNextStreamID += 2;
+    MOZ_ASSERT(mNextStreamID == kOtherGroupID);
+    CreatePriorityNode(kOtherGroupID, 0, 100, "other");
+    mNextStreamID += 2;
+    MOZ_ASSERT(mNextStreamID == kBackgroundGroupID);
+    CreatePriorityNode(kBackgroundGroupID, 0, 0, "background");
+    mNextStreamID += 2;
+    MOZ_ASSERT(mNextStreamID == kSpeculativeGroupID);
+    CreatePriorityNode(kSpeculativeGroupID, kBackgroundGroupID, 0, "speculative");
+    mNextStreamID += 2;
+    MOZ_ASSERT(mNextStreamID == kFollowerGroupID);
+    CreatePriorityNode(kFollowerGroupID, kLeaderGroupID, 0, "follower");
+    mNextStreamID += 2;
+  }
+
   FlushOutputQueue();
 }
 
+void
+Http2Session::CreatePriorityNode(uint32_t streamID, uint32_t dependsOn, uint8_t weight,
+                                 const char *label)
+{
+  char *packet = mOutputQueueBuffer.get() + mOutputQueueUsed;
+  CreateFrameHeader(packet, 5, FRAME_TYPE_PRIORITY, 0, streamID);
+  mOutputQueueUsed += kFrameHeaderBytes + 5;
+  CopyAsNetwork32(packet + kFrameHeaderBytes, dependsOn); // depends on
+  packet[kFrameHeaderBytes + 4] = weight; // weight
+
+  LOG3(("Http2Session %p generate Priority Frame 0x%X depends on 0x%X "
+        "weight %d for %s class\n", this, streamID, dependsOn, weight, label));
+  LogIO(this, nullptr, "Priority dep node", packet, kFrameHeaderBytes + 5);
+}
+
 // perform a bunch of integrity checks on the stream.
 // returns true if passed, false (plus LOG and ABORT) if failed.
 bool
 Http2Session::VerifyStream(Http2Stream *aStream, uint32_t aOptionalID = 0)
 {
   // This is annoying, but at least it is O(1)
   MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
 
@@ -3317,17 +3361,17 @@ Http2Session::ConfirmTLSProfile()
    * anyway, so it'll never be on. All the same, see https://bugzil.la/965881
    * for the possibility for an interface to ensure it never gets turned on. */
 
   nsresult rv = ssl->GetNegotiatedNPN(mNegotiatedToken);
   if (NS_FAILED(rv)) {
     // Fallback to showing the draft version, just in case
     LOG3(("Http2Session::ConfirmTLSProfile %p could not get negotiated token. "
           "Falling back to draft token.", this));
-    mNegotiatedToken.AssignLiteral(NS_HTTP2_DRAFT_TOKEN);
+    mNegotiatedToken.AssignLiteral(HTTP2_DRAFT_LATEST_TOKEN);
   }
 
   mTLSProfileConfirmed = true;
   return NS_OK;
 }
 
 
 //-----------------------------------------------------------------------------
--- a/netwerk/protocol/http/Http2Session.h
+++ b/netwerk/protocol/http/Http2Session.h
@@ -36,17 +36,17 @@ class Http2Session MOZ_FINAL : public AS
 
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSAHTTPTRANSACTION
   NS_DECL_NSAHTTPCONNECTION(mConnection)
   NS_DECL_NSAHTTPSEGMENTREADER
   NS_DECL_NSAHTTPSEGMENTWRITER
 
-  explicit Http2Session(nsISocketTransport *);
+ Http2Session(nsISocketTransport *, uint32_t version);
 
   bool AddStream(nsAHttpTransaction *, int32_t,
                  bool, nsIInterfaceRequestor *);
   bool CanReuse() { return !mShouldGoAway && !mClosed; }
   bool RoomForMoreStreams();
 
   // When the connection is active this is called up to once every 1 second
   // return the interval (in seconds) that the connection next wants to
@@ -156,16 +156,24 @@ public:
 
   const static uint8_t kFrameLengthBytes = 3;
   const static uint8_t kFrameStreamIDBytes = 4;
   const static uint8_t kFrameFlagBytes = 1;
   const static uint8_t kFrameTypeBytes = 1;
   const static uint8_t kFrameHeaderBytes = kFrameLengthBytes + kFrameFlagBytes +
     kFrameTypeBytes + kFrameStreamIDBytes;
 
+  enum {
+    kLeaderGroupID =     0x3,
+    kOtherGroupID =       0x5,
+    kBackgroundGroupID =  0x7,
+    kSpeculativeGroupID = 0x9,
+    kFollowerGroupID =    0xB
+  };
+
   static nsresult RecvHeaders(Http2Session *);
   static nsresult RecvPriority(Http2Session *);
   static nsresult RecvRstStream(Http2Session *);
   static nsresult RecvSettings(Http2Session *);
   static nsresult RecvPushPromise(Http2Session *);
   static nsresult RecvPing(Http2Session *);
   static nsresult RecvGoAway(Http2Session *);
   static nsresult RecvWindowUpdate(Http2Session *);
@@ -213,16 +221,18 @@ public:
   Http2Compressor *Compressor() { return &mCompressor; }
   nsISocketTransport *SocketTransport() { return mSocketTransport; }
   int64_t ServerSessionWindow() { return mServerSessionWindow; }
   void DecrementServerSessionWindow (uint32_t bytes) { mServerSessionWindow -= bytes; }
   void GetNegotiatedToken(nsACString &s) { s.Assign(mNegotiatedToken); }
 
   void SendPing() MOZ_OVERRIDE;
 
+  bool UseH2Deps() { return mUseH2Deps; }
+
 private:
 
   // These internal states do not correspond to the states of the HTTP/2 specification
   enum internalStateType {
     BUFFERING_OPENING_SETTINGS,
     BUFFERING_FRAME_HEADER,
     BUFFERING_CONTROL_FRAME,
     PROCESSING_DATA_FRAME_PADDING_CONTROL,
@@ -255,16 +265,17 @@ private:
 
   void        SetWriteCallbacks();
   void        RealignOutputQueue();
 
   bool        RoomForMoreConcurrent();
   void        ActivateStream(Http2Stream *);
   void        ProcessPending();
   nsresult    SetInputFrameDataStream(uint32_t);
+  void        CreatePriorityNode(uint32_t, uint32_t, uint8_t, const char *);
   bool        VerifyStream(Http2Stream *, uint32_t);
   void        SetNeedsCleanup();
 
   void        UpdateLocalRwin(Http2Stream *stream, uint32_t bytes);
   void        UpdateLocalStreamWindow(Http2Stream *stream, uint32_t bytes);
   void        UpdateLocalSessionWindow(uint32_t bytes);
 
   // a wrapper for all calls to the nshttpconnection level segment writer. Used
@@ -464,16 +475,19 @@ private:
   // we can actually tell the other end to go away. These help us keep track
   // of that state so we can behave appropriately.
   bool mWaitingForSettingsAck;
   bool mGoAwayOnPush;
 
   // For caching whether we negotiated "h2" or "h2-<draft>"
   nsCString mNegotiatedToken;
 
+  bool mUseH2Deps;
+  uint32_t mVersion; // HTTP2_VERSION_ from nsHttp.h remove when draft support removed
+
 private:
 /// connect tunnels
   void DispatchOnTunnel(nsAHttpTransaction *, nsIInterfaceRequestor *);
   void RegisterTunnel(Http2Stream *);
   void UnRegisterTunnel(Http2Stream *);
   uint32_t FindTunnelCount(nsHttpConnectionInfo *);
 
   nsDataHashtable<nsCStringHashKey, uint32_t> mTunnelHash;
--- a/netwerk/protocol/http/Http2Stream.cpp
+++ b/netwerk/protocol/http/Http2Stream.cpp
@@ -21,16 +21,17 @@
 #include "Http2Push.h"
 #include "TunnelUtils.h"
 
 #include "mozilla/Telemetry.h"
 #include "nsAlgorithm.h"
 #include "nsHttp.h"
 #include "nsHttpHandler.h"
 #include "nsHttpRequestHead.h"
+#include "nsIClassOfService.h"
 #include "nsISocketTransport.h"
 #include "nsStandardURL.h"
 #include "prnetdb.h"
 
 #ifdef DEBUG
 // defined by the socket transport service while active
 extern PRThread *gSocketThread;
 #endif
@@ -499,18 +500,21 @@ Http2Stream::ParseHttpRequestHeaders(con
   uint32_t messageSize = dataLength;
   messageSize += Http2Session::kFrameHeaderBytes + 5; // frame header + priority overhead in HEADERS frame
   messageSize += (numFrames - 1) * Http2Session::kFrameHeaderBytes; // frame header overhead in CONTINUATION frames
 
   EnsureBuffer(mTxInlineFrame, dataLength + messageSize,
                mTxInlineFrameUsed, mTxInlineFrameSize);
 
   mTxInlineFrameUsed += messageSize;
-  LOG3(("%p Generating %d bytes of HEADERS for stream 0x%X with priority weight %u frames %u\n",
-        this, mTxInlineFrameUsed, mStreamID, mPriorityWeight, numFrames));
+  UpdatePriorityDependency();
+  LOG3(("Http2Stream %p Generating %d bytes of HEADERS for stream 0x%X with "
+        "priority weight %u dep 0x%X frames %u uri=%s\n",
+        this, mTxInlineFrameUsed, mStreamID, mPriorityWeight,
+        mPriorityDependency, numFrames, nsCString(head->RequestURI()).get()));
 
   uint32_t outputOffset = 0;
   uint32_t compressedDataOffset = 0;
   for (uint32_t idx = 0; idx < numFrames; ++idx) {
     uint32_t flags, frameLen;
     bool lastFrame = (idx == numFrames - 1);
 
     flags = 0;
@@ -529,19 +533,17 @@ Http2Stream::ParseHttpRequestHeaders(con
     mSession->CreateFrameHeader(
       mTxInlineFrame.get() + outputOffset,
       frameLen + (idx ? 0 : 5),
       (idx) ? Http2Session::FRAME_TYPE_CONTINUATION : Http2Session::FRAME_TYPE_HEADERS,
       flags, mStreamID);
     outputOffset += Http2Session::kFrameHeaderBytes;
 
     if (!idx) {
-      // Priority - Dependency is 0, weight is our gecko-calculated weight,
-      // non-exclusive dependency
-      memset(mTxInlineFrame.get() + outputOffset, 0, 4);
+      memcpy(mTxInlineFrame.get() + outputOffset, &mPriorityDependency, 4);
       memcpy(mTxInlineFrame.get() + outputOffset + 4, &mPriorityWeight, 1);
       outputOffset += 5;
     }
 
     memcpy(mTxInlineFrame.get() + outputOffset,
            compressedData.BeginReading() + compressedDataOffset, frameLen);
     compressedDataOffset += frameLen;
     outputOffset += frameLen;
@@ -1058,29 +1060,78 @@ Http2Stream::SetPriority(uint32_t newPri
   if (httpPriority > kWorstPriority) {
     httpPriority = kWorstPriority;
   } else if (httpPriority < kBestPriority) {
     httpPriority = kBestPriority;
   }
   mPriority = static_cast<uint32_t>(httpPriority);
   mPriorityWeight = (nsISupportsPriority::PRIORITY_LOWEST + 1) -
     (httpPriority - kNormalPriority);
+
+  mPriorityDependency = 0; // maybe adjusted later
 }
 
 void
 Http2Stream::SetPriorityDependency(uint32_t newDependency, uint8_t newWeight,
                                    bool exclusive)
 {
-  // XXX - we ignore this for now... why is the server sending priority frames?!
+  // undefined what it means when the server sends a priority frame. ignore it.
   LOG3(("Http2Stream::SetPriorityDependency %p 0x%X received dependency=0x%X "
         "weight=%u exclusive=%d", this, mStreamID, newDependency, newWeight,
         exclusive));
 }
 
 void
+Http2Stream::UpdatePriorityDependency()
+{
+  if (!mSession->UseH2Deps()) {
+    return;
+  }
+
+  nsHttpTransaction *trans = mTransaction->QueryHttpTransaction();
+  if (!trans) {
+    return;
+  }
+
+  // we create 5 fake dependency streams per session,
+  // these streams are never opened with HEADERS. our first opened stream is 0xd
+  // 3 depends 0, weight 200, leader class (kLeaderGroupID)
+  // 5 depends 0, weight 100, other (kOtherGroupID)
+  // 7 depends 0, weight 0, background (kBackgroundGroupID)
+  // 9 depends 7, weight 0, speculative (kSpeculativeGroupID)
+  // b depends 3, weight 0, follower class (kFollowerGroupID)
+  //
+  // streams for leaders (html, js, css) depend on 3
+  // streams for folowers (images) depend on b
+  // default streams (xhr, async js) depend on 5
+  // explicit bg streams (beacon, etc..) depend on 7
+  // spculative bg streams depend on 9
+
+  uint32_t classFlags = trans->ClassOfService();
+
+  if (classFlags & nsIClassOfService::Leader) {
+    mPriorityDependency = Http2Session::kLeaderGroupID;
+  } else if (classFlags & nsIClassOfService::Follower) {
+    mPriorityDependency = Http2Session::kFollowerGroupID;
+  } else if (classFlags & nsIClassOfService::Speculative) {
+    mPriorityDependency = Http2Session::kSpeculativeGroupID;
+  } else if (classFlags & nsIClassOfService::Background) {
+    mPriorityDependency = Http2Session::kBackgroundGroupID;
+  } else if (classFlags & nsIClassOfService::Unblocked) {
+    mPriorityDependency = Http2Session::kOtherGroupID;
+  } else {
+    mPriorityDependency = Http2Session::kFollowerGroupID; // unmarked followers
+  }
+
+  LOG3(("Http2Stream::UpdatePriorityDependency %p "
+        "classFlags %X depends on stream 0x%X\n",
+        this, classFlags, mPriorityDependency));
+}
+
+void
 Http2Stream::SetRecvdFin(bool aStatus)
 {
   mRecvdFin = aStatus ? 1 : 0;
   if (!aStatus)
     return;
 
   if (mState == OPEN || mState == RESERVED_BY_REMOTE) {
     mState = CLOSED_BY_REMOTE;
--- a/netwerk/protocol/http/Http2Stream.h
+++ b/netwerk/protocol/http/Http2Stream.h
@@ -121,16 +121,17 @@ public:
   uint64_t LocalUnAcked() { return mLocalUnacked; }
   int64_t  ClientReceiveWindow()  { return mClientReceiveWindow; }
 
   bool     BlockedOnRwin() { return mBlockedOnRwin; }
 
   uint32_t Priority() { return mPriority; }
   void SetPriority(uint32_t);
   void SetPriorityDependency(uint32_t, uint8_t, bool);
+  void UpdatePriorityDependency();
 
   // A pull stream has an implicit sink, a pushed stream has a sink
   // once it is matched to a pull stream.
   virtual bool HasSink() { return true; }
 
   virtual ~Http2Stream();
 
   Http2Session *Session() { return mSession; }
@@ -259,18 +260,19 @@ private:
   // Track the content-length of a request body so that we can
   // place the fin flag on the last data packet instead of waiting
   // for a stream closed indication. Relying on stream close results
   // in an extra 0-length runt packet and seems to have some interop
   // problems with the google servers. Connect does rely on stream
   // close by setting this to the max value.
   int64_t                      mRequestBodyLenRemaining;
 
-  uint32_t                     mPriority;
-  uint8_t                      mPriorityWeight;
+  uint32_t                     mPriority; // geckoish weight
+  uint8_t                      mPriorityWeight; // h2 weight
+  uint8_t                      mPriorityDependency; // h2 stream id 3 - 0xb
 
   // mClientReceiveWindow, mServerReceiveWindow, and mLocalUnacked are for flow control.
   // *window are signed because the race conditions in asynchronous SETTINGS
   // messages can force them temporarily negative.
 
   // mClientReceiveWindow is how much data the server will send without getting a
   //   window update
   int64_t                      mClientReceiveWindow;
--- a/netwerk/protocol/http/HttpBaseChannel.cpp
+++ b/netwerk/protocol/http/HttpBaseChannel.cpp
@@ -42,16 +42,17 @@
 namespace mozilla {
 namespace net {
 
 HttpBaseChannel::HttpBaseChannel()
   : mStartPos(UINT64_MAX)
   , mStatus(NS_OK)
   , mLoadFlags(LOAD_NORMAL)
   , mCaps(0)
+  , mClassOfService(0)
   , mPriority(PRIORITY_NORMAL)
   , mRedirectionLimit(gHttpHandler->RedirectionLimit())
   , mApplyConversion(true)
   , mCanceled(false)
   , mIsPending(false)
   , mWasOpened(false)
   , mRequestObserversCalled(false)
   , mResponseHeadersModified(false)
@@ -61,18 +62,16 @@ HttpBaseChannel::HttpBaseChannel()
   , mUploadStreamHasHeaders(false)
   , mInheritApplicationCache(true)
   , mChooseApplicationCache(false)
   , mLoadedFromApplicationCache(false)
   , mChannelIsForDownload(false)
   , mTracingEnabled(true)
   , mTimingEnabled(false)
   , mAllowSpdy(true)
-  , mLoadAsBlocking(false)
-  , mLoadUnblocked(false)
   , mResponseTimeoutEnabled(true)
   , mAllRedirectsSameOrigin(true)
   , mAllRedirectsPassTimingAllowCheck(true)
   , mForceNoIntercept(false)
   , mSuspendCount(0)
   , mProxyResolveFlags(0)
   , mContentDispositionHint(UINT32_MAX)
   , mHttpHandler(gHttpHandler)
@@ -1709,46 +1708,16 @@ HttpBaseChannel::GetAllowSpdy(bool *aAll
 NS_IMETHODIMP
 HttpBaseChannel::SetAllowSpdy(bool aAllowSpdy)
 {
   mAllowSpdy = aAllowSpdy;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-HttpBaseChannel::GetLoadAsBlocking(bool *aLoadAsBlocking)
-{
-  NS_ENSURE_ARG_POINTER(aLoadAsBlocking);
-  *aLoadAsBlocking = mLoadAsBlocking;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-HttpBaseChannel::SetLoadAsBlocking(bool aLoadAsBlocking)
-{
-  mLoadAsBlocking = aLoadAsBlocking;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-HttpBaseChannel::GetLoadUnblocked(bool *aLoadUnblocked)
-{
-  NS_ENSURE_ARG_POINTER(aLoadUnblocked);
-  *aLoadUnblocked = mLoadUnblocked;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-HttpBaseChannel::SetLoadUnblocked(bool aLoadUnblocked)
-{
-  mLoadUnblocked = aLoadUnblocked;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
 HttpBaseChannel::GetApiRedirectToURI(nsIURI ** aResult)
 {
   NS_ENSURE_ARG_POINTER(aResult);
   NS_IF_ADDREF(*aResult = mAPIRedirectToURI);
   return NS_OK;
 }
 
 NS_IMETHODIMP
--- a/netwerk/protocol/http/HttpBaseChannel.h
+++ b/netwerk/protocol/http/HttpBaseChannel.h
@@ -23,16 +23,17 @@
 #include "nsIRedirectHistory.h"
 #include "nsIUploadChannel.h"
 #include "nsIUploadChannel2.h"
 #include "nsIProgressEventSink.h"
 #include "nsIURI.h"
 #include "nsIEffectiveTLDService.h"
 #include "nsIStringEnumerator.h"
 #include "nsISupportsPriority.h"
+#include "nsIClassOfService.h"
 #include "nsIApplicationCache.h"
 #include "nsIResumableChannel.h"
 #include "nsITraceableChannel.h"
 #include "nsILoadContext.h"
 #include "nsILoadInfo.h"
 #include "mozilla/net/NeckoCommon.h"
 #include "nsThreadUtils.h"
 #include "PrivateBrowsingChannel.h"
@@ -60,16 +61,17 @@ namespace net {
 class HttpBaseChannel : public nsHashPropertyBag
                       , public nsIEncodedChannel
                       , public nsIHttpChannel
                       , public nsIHttpChannelInternal
                       , public nsIRedirectHistory
                       , public nsIUploadChannel
                       , public nsIUploadChannel2
                       , public nsISupportsPriority
+                      , public nsIClassOfService
                       , public nsIResumableChannel
                       , public nsITraceableChannel
                       , public PrivateBrowsingChannel<HttpBaseChannel>
                       , public nsITimedChannel
                       , public nsIForcePendingChannel
 {
 protected:
   virtual ~HttpBaseChannel();
@@ -171,20 +173,16 @@ public:
   NS_IMETHOD SetChannelIsForDownload(bool aChannelIsForDownload);
   NS_IMETHOD SetCacheKeysRedirectChain(nsTArray<nsCString> *cacheKeys);
   NS_IMETHOD GetLocalAddress(nsACString& addr);
   NS_IMETHOD GetLocalPort(int32_t* port);
   NS_IMETHOD GetRemoteAddress(nsACString& addr);
   NS_IMETHOD GetRemotePort(int32_t* port);
   NS_IMETHOD GetAllowSpdy(bool *aAllowSpdy);
   NS_IMETHOD SetAllowSpdy(bool aAllowSpdy);
-  NS_IMETHOD GetLoadAsBlocking(bool *aLoadAsBlocking);
-  NS_IMETHOD SetLoadAsBlocking(bool aLoadAsBlocking);
-  NS_IMETHOD GetLoadUnblocked(bool *aLoadUnblocked);
-  NS_IMETHOD SetLoadUnblocked(bool aLoadUnblocked);
   NS_IMETHOD GetApiRedirectToURI(nsIURI * *aApiRedirectToURI);
   NS_IMETHOD AddSecurityMessage(const nsAString &aMessageTag, const nsAString &aMessageCategory);
   NS_IMETHOD TakeAllSecurityMessages(nsCOMArray<nsISecurityConsoleMessage> &aMessages);
   NS_IMETHOD GetResponseTimeoutEnabled(bool *aEnable);
   NS_IMETHOD SetResponseTimeoutEnabled(bool aEnable);
   NS_IMETHOD AddRedirect(nsIPrincipal *aRedirect);
   NS_IMETHOD ForcePending(bool aForcePending);
   NS_IMETHOD GetLastModifiedTime(PRTime* lastModifiedTime);
@@ -197,16 +195,19 @@ public:
   }
   NS_IMETHOD HTTPUpgrade(const nsACString & aProtocolName,
                          nsIHttpUpgradeListener *aListener);
 
   // nsISupportsPriority
   NS_IMETHOD GetPriority(int32_t *value);
   NS_IMETHOD AdjustPriority(int32_t delta);
 
+  // nsIClassOfService
+  NS_IMETHOD GetClassFlags(uint32_t *outFlags) { *outFlags = mClassOfService; return NS_OK; }
+
   // nsIResumableChannel
   NS_IMETHOD GetEntityID(nsACString& aEntityID);
 
   class nsContentEncodings : public nsIUTF8StringEnumerator
     {
     public:
         NS_DECL_ISUPPORTS
         NS_DECL_NSIUTF8STRINGENUMERATOR
@@ -329,16 +330,17 @@ protected:
 
   // Resumable channel specific data
   nsCString                         mEntityID;
   uint64_t                          mStartPos;
 
   nsresult                          mStatus;
   uint32_t                          mLoadFlags;
   uint32_t                          mCaps;
+  uint32_t                          mClassOfService;
   int16_t                           mPriority;
   uint8_t                           mRedirectionLimit;
 
   uint32_t                          mApplyConversion            : 1;
   uint32_t                          mCanceled                   : 1;
   uint32_t                          mIsPending                  : 1;
   uint32_t                          mWasOpened                  : 1;
   // if 1 all "http-on-{opening|modify|etc}-request" observers have been called
@@ -351,18 +353,16 @@ protected:
   uint32_t                          mInheritApplicationCache    : 1;
   uint32_t                          mChooseApplicationCache     : 1;
   uint32_t                          mLoadedFromApplicationCache : 1;
   uint32_t                          mChannelIsForDownload       : 1;
   uint32_t                          mTracingEnabled             : 1;
   // True if timing collection is enabled
   uint32_t                          mTimingEnabled              : 1;
   uint32_t                          mAllowSpdy                  : 1;
-  uint32_t                          mLoadAsBlocking             : 1;
-  uint32_t                          mLoadUnblocked              : 1;
   uint32_t                          mResponseTimeoutEnabled     : 1;
   // A flag that should be false only if a cross-domain redirect occurred
   uint32_t                          mAllRedirectsSameOrigin     : 1;
 
   // Is 1 if no redirects have occured or if all redirects
   // pass the Resource Timing timing-allow-check
   uint32_t                          mAllRedirectsPassTimingAllowCheck : 1;
 
--- a/netwerk/protocol/http/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/HttpChannelChild.cpp
@@ -122,16 +122,17 @@ NS_IMETHODIMP_(MozExternalRefCountType) 
 NS_INTERFACE_MAP_BEGIN(HttpChannelChild)
   NS_INTERFACE_MAP_ENTRY(nsIRequest)
   NS_INTERFACE_MAP_ENTRY(nsIChannel)
   NS_INTERFACE_MAP_ENTRY(nsIHttpChannel)
   NS_INTERFACE_MAP_ENTRY(nsIHttpChannelInternal)
   NS_INTERFACE_MAP_ENTRY(nsICacheInfoChannel)
   NS_INTERFACE_MAP_ENTRY(nsIResumableChannel)
   NS_INTERFACE_MAP_ENTRY(nsISupportsPriority)
+  NS_INTERFACE_MAP_ENTRY(nsIClassOfService)
   NS_INTERFACE_MAP_ENTRY(nsIProxiedChannel)
   NS_INTERFACE_MAP_ENTRY(nsITraceableChannel)
   NS_INTERFACE_MAP_ENTRY(nsIApplicationCacheContainer)
   NS_INTERFACE_MAP_ENTRY(nsIApplicationCacheChannel)
   NS_INTERFACE_MAP_ENTRY(nsIAsyncVerifyRedirectCallback)
   NS_INTERFACE_MAP_ENTRY(nsIChildChannel)
   NS_INTERFACE_MAP_ENTRY(nsIHttpChannelChild)
   NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIAssociatedContentSecurity, GetAssociatedContentSecurity())
@@ -1536,16 +1537,17 @@ HttpChannelChild::ContinueAsyncOpen()
   }
 
   SerializeURI(mTopWindowURI, openArgs.topWindowURI());
 
   openArgs.fds() = optionalFDs;
 
   openArgs.uploadStreamHasHeaders() = mUploadStreamHasHeaders;
   openArgs.priority() = mPriority;
+  openArgs.classOfService() = mClassOfService;
   openArgs.redirectionLimit() = mRedirectionLimit;
   openArgs.allowPipelining() = mAllowPipelining;
   openArgs.allowSTS() = mAllowSTS;
   openArgs.thirdPartyFlags() = mThirdPartyFlags;
   openArgs.resumeAt() = mSendResumeAt;
   openArgs.startPos() = mStartPos;
   openArgs.entityID() = mEntityID;
   openArgs.chooseApplicationCache() = mChooseApplicationCache;
@@ -1721,16 +1723,53 @@ HttpChannelChild::SetPriority(int32_t aP
     return NS_OK;
   mPriority = newValue;
   if (RemoteChannelExists())
     SendSetPriority(mPriority);
   return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
+// HttpChannelChild::nsIClassOfService
+//-----------------------------------------------------------------------------
+NS_IMETHODIMP
+HttpChannelChild::SetClassFlags(uint32_t inFlags)
+{
+  if (mClassOfService == inFlags) {
+    return NS_OK;
+  }
+
+  mClassOfService = inFlags;
+  if (RemoteChannelExists()) {
+    SendSetClassOfService(mClassOfService);
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HttpChannelChild::AddClassFlags(uint32_t inFlags)
+{
+  mClassOfService |= inFlags;
+  if (RemoteChannelExists()) {
+    SendSetClassOfService(mClassOfService);
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HttpChannelChild::ClearClassFlags(uint32_t inFlags)
+{
+  mClassOfService &= ~inFlags;
+  if (RemoteChannelExists()) {
+    SendSetClassOfService(mClassOfService);
+  }
+  return NS_OK;
+}
+
+//-----------------------------------------------------------------------------
 // HttpChannelChild::nsIProxiedChannel
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 HttpChannelChild::GetProxyInfo(nsIProxyInfo **aProxyInfo)
 {
   DROP_DEAD();
 }
--- a/netwerk/protocol/http/HttpChannelChild.h
+++ b/netwerk/protocol/http/HttpChannelChild.h
@@ -82,16 +82,20 @@ public:
   // nsIHttpChannelInternal
   NS_IMETHOD SetupFallbackChannel(const char *aFallbackKey);
   NS_IMETHOD GetLocalAddress(nsACString& addr);
   NS_IMETHOD GetLocalPort(int32_t* port);
   NS_IMETHOD GetRemoteAddress(nsACString& addr);
   NS_IMETHOD GetRemotePort(int32_t* port);
   // nsISupportsPriority
   NS_IMETHOD SetPriority(int32_t value);
+  // nsIClassOfService
+  NS_IMETHOD SetClassFlags(uint32_t inFlags);
+  NS_IMETHOD AddClassFlags(uint32_t inFlags);
+  NS_IMETHOD ClearClassFlags(uint32_t inFlags);
   // nsIResumableChannel
   NS_IMETHOD ResumeAt(uint64_t startPos, const nsACString& entityID);
 
   // IPDL holds a reference while the PHttpChannel protocol is live (starting at
   // AsyncOpen, and ending at either OnStopRequest or any IPDL error, either of
   // which call NeckoChild::DeallocPHttpChannelChild()).
   void AddIPDLReference();
   void ReleaseIPDLReference();
--- a/netwerk/protocol/http/HttpChannelParent.cpp
+++ b/netwerk/protocol/http/HttpChannelParent.cpp
@@ -95,17 +95,17 @@ HttpChannelParent::Init(const HttpChanne
   switch (aArgs.type()) {
   case HttpChannelCreationArgs::THttpChannelOpenArgs:
   {
     const HttpChannelOpenArgs& a = aArgs.get_HttpChannelOpenArgs();
     return DoAsyncOpen(a.uri(), a.original(), a.doc(), a.referrer(),
                        a.referrerPolicy(), a.apiRedirectTo(), a.topWindowURI(),
                        a.loadFlags(), a.requestHeaders(),
                        a.requestMethod(), a.uploadStream(),
-                       a.uploadStreamHasHeaders(), a.priority(),
+                       a.uploadStreamHasHeaders(), a.priority(), a.classOfService(),
                        a.redirectionLimit(), a.allowPipelining(), a.allowSTS(),
                        a.thirdPartyFlags(), a.resumeAt(), a.startPos(),
                        a.entityID(), a.chooseApplicationCache(),
                        a.appCacheClientID(), a.allowSpdy(), a.fds(),
                        a.requestingPrincipalInfo(), a.triggeringPrincipalInfo(),
                        a.securityFlags(), a.contentPolicyType());
   }
   case HttpChannelCreationArgs::THttpChannelConnectArgs:
@@ -176,16 +176,17 @@ HttpChannelParent::DoAsyncOpen(  const U
                                  const OptionalURIParams&   aAPIRedirectToURI,
                                  const OptionalURIParams&   aTopWindowURI,
                                  const uint32_t&            aLoadFlags,
                                  const RequestHeaderTuples& requestHeaders,
                                  const nsCString&           requestMethod,
                                  const OptionalInputStreamParams& uploadStream,
                                  const bool&                uploadStreamHasHeaders,
                                  const uint16_t&            priority,
+                                 const uint32_t&            classOfService,
                                  const uint8_t&             redirectionLimit,
                                  const bool&                allowPipelining,
                                  const bool&                allowSTS,
                                  const uint32_t&            thirdPartyFlags,
                                  const bool&                doResumeAt,
                                  const uint64_t&            startPos,
                                  const nsCString&           entityID,
                                  const bool&                chooseApplicationCache,
@@ -310,18 +311,22 @@ HttpChannelParent::DoAsyncOpen(  const U
   }
 
   nsCOMPtr<nsIInputStream> stream = DeserializeInputStream(uploadStream, fds);
   if (stream) {
     mChannel->InternalSetUploadStream(stream);
     mChannel->SetUploadStreamHasHeaders(uploadStreamHasHeaders);
   }
 
-  if (priority != nsISupportsPriority::PRIORITY_NORMAL)
+  if (priority != nsISupportsPriority::PRIORITY_NORMAL) {
     mChannel->SetPriority(priority);
+  }
+  if (classOfService) {
+    mChannel->SetClassFlags(classOfService);
+  }
   mChannel->SetRedirectionLimit(redirectionLimit);
   mChannel->SetAllowPipelining(allowPipelining);
   mChannel->SetAllowSTS(allowSTS);
   mChannel->SetThirdPartyFlags(thirdPartyFlags);
   mChannel->SetAllowSpdy(allowSpdy);
 
   nsCOMPtr<nsIApplicationCacheChannel> appCacheChan =
     do_QueryObject(mChannel);
@@ -422,16 +427,25 @@ HttpChannelParent::RecvSetPriority(const
       do_QueryInterface(mRedirectChannel);
   if (priorityRedirectChannel)
     priorityRedirectChannel->SetPriority(priority);
 
   return true;
 }
 
 bool
+HttpChannelParent::RecvSetClassOfService(const uint32_t& cos)
+{
+  if (mChannel) {
+    mChannel->SetClassFlags(cos);
+  }
+  return true;
+}
+
+bool
 HttpChannelParent::RecvSuspend()
 {
   if (mChannel) {
     mChannel->Suspend();
   }
   return true;
 }
 
--- a/netwerk/protocol/http/HttpChannelParent.h
+++ b/netwerk/protocol/http/HttpChannelParent.h
@@ -94,16 +94,17 @@ protected:
                    const OptionalURIParams&   internalRedirectUri,
                    const OptionalURIParams&   topWindowUri,
                    const uint32_t&            loadFlags,
                    const RequestHeaderTuples& requestHeaders,
                    const nsCString&           requestMethod,
                    const OptionalInputStreamParams& uploadStream,
                    const bool&                uploadStreamHasHeaders,
                    const uint16_t&            priority,
+                   const uint32_t&            classOfService,
                    const uint8_t&             redirectionLimit,
                    const bool&                allowPipelining,
                    const bool&                allowSTS,
                    const uint32_t&            thirdPartyFlags,
                    const bool&                doResumeAt,
                    const uint64_t&            startPos,
                    const nsCString&           entityID,
                    const bool&                chooseApplicationCache,
@@ -111,16 +112,17 @@ protected:
                    const bool&                allowSpdy,
                    const OptionalFileDescriptorSet& aFds,
                    const ipc::PrincipalInfo&  aRequestingPrincipalInfo,
                    const ipc::PrincipalInfo&  aTriggeringPrincipalInfo,
                    const uint32_t&            aSecurityFlags,
                    const uint32_t&            aContentPolicyType);
 
   virtual bool RecvSetPriority(const uint16_t& priority) MOZ_OVERRIDE;
+  virtual bool RecvSetClassOfService(const uint32_t& cos) MOZ_OVERRIDE;
   virtual bool RecvSetCacheTokenCachedCharset(const nsCString& charset) MOZ_OVERRIDE;
   virtual bool RecvSuspend() MOZ_OVERRIDE;
   virtual bool RecvResume() MOZ_OVERRIDE;
   virtual bool RecvCancel(const nsresult& status) MOZ_OVERRIDE;
   virtual bool RecvRedirect2Verify(const nsresult& result,
                                    const RequestHeaderTuples& changedHeaders,
                                    const OptionalURIParams& apiRedirectUri) MOZ_OVERRIDE;
   virtual bool RecvUpdateAssociatedContentSecurity(const int32_t& broken,
--- a/netwerk/protocol/http/PHttpChannel.ipdl
+++ b/netwerk/protocol/http/PHttpChannel.ipdl
@@ -28,16 +28,17 @@ protocol PHttpChannel
 {
   manager PNecko;
 
 parent:
   // Note: channels are opened during construction, so no open method here:
   // see PNecko.ipdl
 
   SetPriority(uint16_t priority);
+  SetClassOfService(uint32_t cos);
 
   SetCacheTokenCachedCharset(nsCString charset);
 
   UpdateAssociatedContentSecurity(int32_t broken,
                                   int32_t no);
   Suspend();
   Resume();
 
--- a/netwerk/protocol/http/nsHttp.h
+++ b/netwerk/protocol/http/nsHttp.h
@@ -34,25 +34,26 @@ namespace net {
 
         // leave room for official versions. telem goes to 48
         // 24 was a internal spdy/3.1
         // 25 was spdy/4a2
         // 26 was http/2-draft08 and http/2-draft07 (they were the same)
         // 27 was http/2-draft09, h2-10, and h2-11
         // 28 was http/2-draft12
         // 29 was http/2-draft13
-        // 30 was also h2-14 and -15. They're effectively the same, -15 added an
+        // 30 was also h2-14. They're effectively the same, -15 added an
         // error code. So, we advertise all, but our "default position" is -16.
-        HTTP2_VERSION_DRAFT16 = 30
+        HTTP_VERSION_2_DRAFT_15 = 30,
+        HTTP_VERSION_2_DRAFT_16 = 31
     };
 
 typedef uint8_t nsHttpVersion;
 
-#define NS_HTTP2_DRAFT_VERSION HTTP2_VERSION_DRAFT16
-#define NS_HTTP2_DRAFT_TOKEN "h2-16"
+#define HTTP_VERSION_2_DRAFT_LATEST HTTP_VERSION_2_DRAFT_16
+#define HTTP2_DRAFT_LATEST_TOKEN "h2-16"
 
 //-----------------------------------------------------------------------------
 // http connection capabilities
 //-----------------------------------------------------------------------------
 
 #define NS_HTTP_ALLOW_KEEPALIVE      (1<<0)
 #define NS_HTTP_ALLOW_PIPELINING     (1<<1)
 
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -38,16 +38,17 @@
 #include "nsAlgorithm.h"
 #include "GeckoProfiler.h"
 #include "nsIConsoleService.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/VisualEventTracer.h"
 #include "nsISSLSocketControl.h"
 #include "sslt.h"
 #include "nsContentUtils.h"
+#include "nsIClassOfService.h"
 #include "nsIPermissionManager.h"
 #include "nsIPrincipal.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsISSLStatus.h"
 #include "nsISSLStatusProvider.h"
 #include "nsITransportSecurityInfo.h"
 #include "nsIWebProgressListener.h"
 #include "LoadContextInfo.h"
@@ -830,16 +831,17 @@ nsHttpChannel::SetupTransaction()
                             mUploadStream, mUploadStreamHasHeaders,
                             NS_GetCurrentThread(), callbacks, this,
                             getter_AddRefs(responseStream));
     if (NS_FAILED(rv)) {
         mTransaction = nullptr;
         return rv;
     }
 
+    mTransaction->SetClassOfService(mClassOfService);
     SetupTransactionLoadGroupInfo();
 
     rv = nsInputStreamPump::Create(getter_AddRefs(mTransactionPump),
                                    responseStream);
     return rv;
 }
 
 // NOTE: This function duplicates code from nsBaseChannel. This will go away
@@ -2779,20 +2781,18 @@ nsHttpChannel::OpenCacheEntry(bool isHtt
     }
     else {
         rv = cacheStorageService->DiskCacheStorage(info,
             !mPostID && (mChooseApplicationCache || (mLoadFlags & LOAD_CHECK_OFFLINE_CACHE)),
             getter_AddRefs(cacheStorage));
     }
     NS_ENSURE_SUCCESS(rv, rv);
 
-    // Don't consider mLoadUnblocked here, since it's not indication of a demand
-    // to load prioritly. It's mostly used to load XHR requests, but those should
-    // not be considered as influencing the page load performance.
-    if (mLoadAsBlocking || (mLoadFlags & LOAD_INITIAL_DOCUMENT_URI))
+    if ((mClassOfService & nsIClassOfService::Leader) ||
+        (mLoadFlags & LOAD_INITIAL_DOCUMENT_URI))
         cacheEntryOpenFlags |= nsICacheStorage::OPEN_PRIORITY;
 
     // Only for backward compatibility with the old cache back end.
     // When removed, remove the flags and related code snippets.
     if (mLoadFlags & LOAD_BYPASS_LOCAL_CACHE_IF_BUSY)
         cacheEntryOpenFlags |= nsICacheStorage::OPEN_BYPASS_IF_BUSY;
 
     if (mPostID) {
@@ -4589,16 +4589,17 @@ NS_IMPL_RELEASE_INHERITED(nsHttpChannel,
 NS_INTERFACE_MAP_BEGIN(nsHttpChannel)
     NS_INTERFACE_MAP_ENTRY(nsIRequest)
     NS_INTERFACE_MAP_ENTRY(nsIChannel)
     NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
     NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
     NS_INTERFACE_MAP_ENTRY(nsIHttpChannel)
     NS_INTERFACE_MAP_ENTRY(nsICacheInfoChannel)
     NS_INTERFACE_MAP_ENTRY(nsICachingChannel)
+    NS_INTERFACE_MAP_ENTRY(nsIClassOfService)
     NS_INTERFACE_MAP_ENTRY(nsIUploadChannel)
     NS_INTERFACE_MAP_ENTRY(nsIUploadChannel2)
     NS_INTERFACE_MAP_ENTRY(nsICacheEntryOpenCallback)
     NS_INTERFACE_MAP_ENTRY(nsIHttpChannelInternal)
     NS_INTERFACE_MAP_ENTRY(nsIResumableChannel)
     NS_INTERFACE_MAP_ENTRY(nsITransportEventSink)
     NS_INTERFACE_MAP_ENTRY(nsISupportsPriority)
     NS_INTERFACE_MAP_ENTRY(nsIProtocolProxyCallback)
@@ -4907,20 +4908,22 @@ nsHttpChannel::BeginConnect()
 
     // Adjust mCaps according to our request headers:
     //  - If "Connection: close" is set as a request header, then do not bother
     //    trying to establish a keep-alive connection.
     if (mRequestHead.HasHeaderValue(nsHttp::Connection, "close"))
         mCaps &= ~(NS_HTTP_ALLOW_KEEPALIVE | NS_HTTP_ALLOW_PIPELINING);
 
     if (gHttpHandler->CriticalRequestPrioritization()) {
-        if (mLoadAsBlocking)
+        if (mClassOfService & nsIClassOfService::Leader) {
             mCaps |= NS_HTTP_LOAD_AS_BLOCKING;
-        if (mLoadUnblocked)
+        }
+        if (mClassOfService & nsIClassOfService::Unblocked) {
             mCaps |= NS_HTTP_LOAD_UNBLOCKED;
+        }
     }
 
     // Force-Reload should reset the persistent connection pool for this host
     if (mLoadFlags & LOAD_FRESH_CONNECTION) {
         // just the initial document resets the whole pool
         if (mLoadFlags & LOAD_INITIAL_DOCUMENT_URI) {
             gHttpHandler->ConnMgr()->DoShiftReloadConnectionCleanup(mConnectionInfo);
         }
@@ -4979,16 +4982,40 @@ nsHttpChannel::SetPriority(int32_t value
         return NS_OK;
     mPriority = newValue;
     if (mTransaction)
         gHttpHandler->RescheduleTransaction(mTransaction, mPriority);
     return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
+// HttpChannel::nsIClassOfService
+//-----------------------------------------------------------------------------
+NS_IMETHODIMP
+nsHttpChannel::SetClassFlags(uint32_t inFlags)
+{
+    mClassOfService = inFlags;
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+nsHttpChannel::AddClassFlags(uint32_t inFlags)
+{
+    mClassOfService |= inFlags;
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+nsHttpChannel::ClearClassFlags(uint32_t inFlags)
+{
+    mClassOfService &= ~inFlags;
+    return NS_OK;
+}
+
+//-----------------------------------------------------------------------------
 // nsHttpChannel::nsIProtocolProxyCallback
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 nsHttpChannel::OnProxyAvailable(nsICancelable *request, nsIURI *uri,
                                 nsIProxyInfo *pi, nsresult status)
 {
     LOG(("nsHttpChannel::OnProxyAvailable [this=%p pi=%p status=%x mStatus=%x]\n",
--- a/netwerk/protocol/http/nsHttpChannel.h
+++ b/netwerk/protocol/http/nsHttpChannel.h
@@ -116,16 +116,21 @@ public:
     NS_IMETHOD Resume();
     // nsIChannel
     NS_IMETHOD GetSecurityInfo(nsISupports **aSecurityInfo);
     NS_IMETHOD AsyncOpen(nsIStreamListener *listener, nsISupports *aContext);
     // nsIHttpChannelInternal
     NS_IMETHOD SetupFallbackChannel(const char *aFallbackKey);
     // nsISupportsPriority
     NS_IMETHOD SetPriority(int32_t value);
+    // nsIClassOfService
+    NS_IMETHOD SetClassFlags(uint32_t inFlags);
+    NS_IMETHOD AddClassFlags(uint32_t inFlags);
+    NS_IMETHOD ClearClassFlags(uint32_t inFlags);
+
     // nsIResumableChannel
     NS_IMETHOD ResumeAt(uint64_t startPos, const nsACString& entityID);
 
     NS_IMETHOD SetNotificationCallbacks(nsIInterfaceRequestor *aCallbacks);
     NS_IMETHOD SetLoadGroup(nsILoadGroup *aLoadGroup);
     // nsITimedChannel
     NS_IMETHOD GetDomainLookupStart(mozilla::TimeStamp *aDomainLookupStart);
     NS_IMETHOD GetDomainLookupEnd(mozilla::TimeStamp *aDomainLookupEnd);
--- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp
+++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp
@@ -1748,18 +1748,17 @@ nsHttpConnectionMgr::TryDispatchTransact
                 if (NS_SUCCEEDED(loadGroupCI->GetBlockingTransactionCount(&blockers)) &&
                     blockers) {
                     // need to wait for blockers to clear
                     LOG(("   blocked by load group: [blockers=%d]\n", blockers));
                     return NS_ERROR_NOT_AVAILABLE;
                 }
             }
         }
-    }
-    else {
+    } else {
         // Mark the transaction and its load group as blocking right now to prevent
         // other transactions from being reordered in the queue due to slow syns.
         trans->DispatchedAsBlocking();
     }
 
     // step 1
     // If connection pressure, then we want to favor pipelining of any kind
     if (IsUnderPressure(ent, classification) && !attemptedOptimisticPipeline) {
--- a/netwerk/protocol/http/nsHttpHandler.cpp
+++ b/netwerk/protocol/http/nsHttpHandler.cpp
@@ -177,16 +177,17 @@ nsHttpHandler::nsHttpHandler()
     , mParentalControlEnabled(false)
     , mTelemetryEnabled(false)
     , mAllowExperiments(true)
     , mHandlerActive(false)
     , mEnableSpdy(false)
     , mSpdyV31(true)
     , mHttp2DraftEnabled(true)
     , mHttp2Enabled(true)
+    , mUseH2Deps(true)
     , mEnforceHttp2TlsProfile(true)
     , mCoalesceSpdy(true)
     , mSpdyPersistentSettings(false)
     , mAllowPush(true)
     , mEnableAltSvc(true)
     , mEnableAltSvcOE(true)
     , mSpdySendingChunkSize(ASpdySession::kSendingChunkSize)
     , mSpdySendBufferSize(ASpdySession::kTCPSendBufferSize)
@@ -1189,16 +1190,22 @@ nsHttpHandler::PrefsChanged(nsIPrefBranc
     }
 
     if (PREF_CHANGED(HTTP_PREF("spdy.enabled.http2"))) {
         rv = prefs->GetBoolPref(HTTP_PREF("spdy.enabled.http2"), &cVar);
         if (NS_SUCCEEDED(rv))
             mHttp2Enabled = cVar;
     }
 
+    if (PREF_CHANGED(HTTP_PREF("spdy.enabled.deps"))) {
+        rv = prefs->GetBoolPref(HTTP_PREF("spdy.enabled.deps"), &cVar);
+        if (NS_SUCCEEDED(rv))
+            mUseH2Deps = cVar;
+    }
+
     if (PREF_CHANGED(HTTP_PREF("spdy.enforce-tls-profile"))) {
         rv = prefs->GetBoolPref(HTTP_PREF("spdy.enforce-tls-profile"), &cVar);
         if (NS_SUCCEEDED(rv))
             mEnforceHttp2TlsProfile = cVar;
     }
 
     if (PREF_CHANGED(HTTP_PREF("spdy.coalesce-hostnames"))) {
         rv = prefs->GetBoolPref(HTTP_PREF("spdy.coalesce-hostnames"), &cVar);
--- a/netwerk/protocol/http/nsHttpHandler.h
+++ b/netwerk/protocol/http/nsHttpHandler.h
@@ -108,16 +108,17 @@ public:
     PRIntervalTime SpdyPingThreshold() { return mSpdyPingThreshold; }
     PRIntervalTime SpdyPingTimeout() { return mSpdyPingTimeout; }
     bool           AllowPush()   { return mAllowPush; }
     bool           AllowAltSvc() { return mEnableAltSvc; }
     bool           AllowAltSvcOE() { return mEnableAltSvcOE; }
     uint32_t       ConnectTimeout()  { return mConnectTimeout; }
     uint32_t       ParallelSpeculativeConnectLimit() { return mParallelSpeculativeConnectLimit; }
     bool           CriticalRequestPrioritization() { return mCriticalRequestPrioritization; }
+    bool           UseH2Deps() { return mUseH2Deps; }
 
     uint32_t       MaxConnectionsPerOrigin() { return mMaxPersistentConnectionsPerServer; }
     bool           UseRequestTokenBucket() { return mRequestTokenBucketEnabled; }
     uint16_t       RequestTokenBucketMinParallelism() { return mRequestTokenBucketMinParallelism; }
     uint32_t       RequestTokenBucketHz() { return mRequestTokenBucketHz; }
     uint32_t       RequestTokenBucketBurst() {return mRequestTokenBucketBurst; }
 
     bool           PromptTempRedirect()      { return mPromptTempRedirect; }
@@ -465,16 +466,17 @@ private:
 
     // true in between init and shutdown states
     uint32_t           mHandlerActive : 1;
 
     uint32_t           mEnableSpdy : 1;
     uint32_t           mSpdyV31 : 1;
     uint32_t           mHttp2DraftEnabled : 1;
     uint32_t           mHttp2Enabled : 1;
+    uint32_t           mUseH2Deps : 1;
     uint32_t           mEnforceHttp2TlsProfile : 1;
     uint32_t           mCoalesceSpdy : 1;
     uint32_t           mSpdyPersistentSettings : 1;
     uint32_t           mAllowPush : 1;
     uint32_t           mEnableAltSvc : 1;
     uint32_t           mEnableAltSvcOE : 1;
 
     // Try to use SPDY features instead of HTTP/1.1 over SSL
--- a/netwerk/protocol/http/nsHttpTransaction.cpp
+++ b/netwerk/protocol/http/nsHttpTransaction.cpp
@@ -131,16 +131,17 @@ nsHttpTransaction::nsHttpTransaction()
     , mForTakeResponseHead(nullptr)
     , mResponseHeadTaken(false)
     , mSubmittedRatePacing(false)
     , mPassedRatePacing(false)
     , mSynchronousRatePaceRequest(false)
     , mCountRecv(0)
     , mCountSent(0)
     , mAppId(NECKO_NO_APP_ID)
+    , mClassOfService(0)
 {
     LOG(("Creating nsHttpTransaction @%p\n", this));
     gHttpHandler->GetMaxPipelineObjectSize(&mMaxPipelineObjectSize);
 }
 
 nsHttpTransaction::~nsHttpTransaction()
 {
     LOG(("Destroying nsHttpTransaction @%p\n", this));
@@ -1744,17 +1745,17 @@ nsHttpTransaction::CancelPipeline(uint32
 
     // Avoid pipelining this transaction on restart by classifying it as solo.
     // This also prevents BadUnexpectedLarge from being reported more
     // than one time per transaction.
     mClassification = CLASS_SOLO;
 }
 
 // Called when the transaction marked for blocking is associated with a connection
-// (i.e. added to a spdy session, an idle http connection, or placed into
+// (i.e. added to a new h1 conn, an idle http connection, or placed into
 // a http pipeline). It is safe to call this multiple times with it only
 // having an effect once.
 void
 nsHttpTransaction::DispatchedAsBlocking()
 {
     if (mDispatchedAsBlocking)
         return;
 
--- a/netwerk/protocol/http/nsHttpTransaction.h
+++ b/netwerk/protocol/http/nsHttpTransaction.h
@@ -400,13 +400,18 @@ private:
         mCountRecv += recvBytes;
         SaveNetworkStats(false);
     }
     void                               CountSentBytes(uint64_t sentBytes)
     {
         mCountSent += sentBytes;
         SaveNetworkStats(false);
     }
+public:
+    void     SetClassOfService(uint32_t cos) { mClassOfService = cos; }
+    uint32_t ClassOfService() { return mClassOfService; }
+private:
+    uint32_t mClassOfService;
 };
 
 }} // namespace mozilla::net
 
 #endif // nsHttpTransaction_h__
--- a/netwerk/protocol/http/nsIHttpChannelInternal.idl
+++ b/netwerk/protocol/http/nsIHttpChannelInternal.idl
@@ -33,17 +33,17 @@ interface nsIHttpUpgradeListener : nsISu
                               in nsIAsyncOutputStream aSocketOut);
 };
 
 /**
  * Dumping ground for http.  This interface will never be frozen.  If you are
  * using any feature exposed by this interface, be aware that this interface
  * will change and you will be broken.  You have been warned.
  */
-[scriptable, uuid(62a8d6e2-3418-4c6f-9d90-88573838f6dd)]
+[scriptable, uuid(bbf9d5bb-8daf-4909-88bc-f3b2f6a886d0)]
 interface nsIHttpChannelInternal : nsISupports
 {
     /**
      * An http channel can own a reference to the document URI
      */
     attribute nsIURI documentURI;
 
     /**
@@ -190,32 +190,16 @@ interface nsIHttpChannelInternal : nsISu
     /**
      * Enable/Disable Spdy negotiation on per channel basis.
      * The network.http.spdy.enabled preference is still a pre-requisite
      * for starting spdy.
      */
     attribute boolean allowSpdy;
 
     /**
-     * Set (e.g., by the docshell) to indicate whether or not the channel
-     * corresponds to content that should be given a degree of network exclusivity
-     * with respect to other members of its load group.
-     * Examples are js from the HTML head and css which are latency
-     * sensitive and should not compete with images for bandwidth. Default false.
-     */
-    attribute boolean loadAsBlocking;
-
-    /**
-     * If set, this channel will load in parallel with the rest of the load
-     * group even if a blocking subset of the group would normally be given
-     * exclusivity. Default false.
-     */
-    attribute boolean loadUnblocked;
-
-    /**
      * This attribute en/disables the timeout for the first byte of an HTTP
      * response. Enabled by default.
      */
     attribute boolean responseTimeoutEnabled;
 
     /**
      * Get value of the URI passed to nsIHttpChannel.redirectTo() if any.
      * May return null when redirectTo() has not been called.
--- a/netwerk/protocol/websocket/WebSocketChannel.cpp
+++ b/netwerk/protocol/websocket/WebSocketChannel.cpp
@@ -14,16 +14,17 @@
 
 #include "nsIURI.h"
 #include "nsIChannel.h"
 #include "nsICryptoHash.h"
 #include "nsIRunnable.h"
 #include "nsIPrefBranch.h"
 #include "nsIPrefService.h"
 #include "nsICancelable.h"
+#include "nsIClassOfService.h"
 #include "nsIDNSRecord.h"
 #include "nsIDNSService.h"
 #include "nsIStreamConverterService.h"
 #include "nsIIOService2.h"
 #include "nsIProtocolProxyService.h"
 #include "nsIProxyInfo.h"
 #include "nsIProxiedChannel.h"
 #include "nsIAsyncVerifyRedirectCallback.h"
@@ -2288,18 +2289,20 @@ WebSocketChannel::SetupRequest()
   rv = mHttpChannel->SetLoadFlags(nsIRequest::LOAD_BACKGROUND |
                                   nsIRequest::INHIBIT_CACHING |
                                   nsIRequest::LOAD_BYPASS_CACHE);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // we never let websockets be blocked by head CSS/JS loads to avoid
   // potential deadlock where server generation of CSS/JS requires
   // an XHR signal.
-  rv = mChannel->SetLoadUnblocked(true);
-  NS_ENSURE_SUCCESS(rv, rv);
+  nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(mChannel));
+  if (cos) {
+    cos->AddClassFlags(nsIClassOfService::Unblocked);
+  }
 
   // draft-ietf-hybi-thewebsocketprotocol-07 illustrates Upgrade: websocket
   // in lower case, so go with that. It is technically case insensitive.
   rv = mChannel->HTTPUpgrade(NS_LITERAL_CSTRING("websocket"), this);
   NS_ENSURE_SUCCESS(rv, rv);
 
   mHttpChannel->SetRequestHeader(
     NS_LITERAL_CSTRING("Sec-WebSocket-Version"),
--- a/netwerk/test/unit/test_http2.js
+++ b/netwerk/test/unit/test_http2.js
@@ -198,16 +198,24 @@ function makeChan(url) {
 
 // Make sure we make a HTTP2 connection and both us and the server mark it as such
 function test_http2_basic() {
   var chan = makeChan("https://localhost:6944/");
   var listener = new Http2CheckListener();
   chan.asyncOpen(listener, null);
 }
 
+function test_http2_basic_unblocked_dep() {
+  var chan = makeChan("https://localhost:6944/basic_unblocked_dep");
+  var cos = chan.QueryInterface(Ci.nsIClassOfService);
+  cos.addClassFlags(Ci.nsIClassOfService.Unblocked);
+  var listener = new Http2CheckListener();
+  chan.asyncOpen(listener, null);
+}
+
 // make sure we don't use h2 when disallowed
 function test_http2_nospdy() {
   var chan = makeChan("https://localhost:6944/");
   var listener = new Http2CheckListener();
   var internalChannel = chan.QueryInterface(Ci.nsIHttpChannelInternal);
   internalChannel.allowSpdy = false;
   listener.shouldBeHttp2 = false;
   chan.asyncOpen(listener, null);
@@ -516,16 +524,17 @@ function test_complete() {
 
 // hack - the header test resets the multiplex object on the server,
 // so make sure header is always run before the multiplex test.
 //
 // make sure post_big runs first to test race condition in restarting
 // a stalled stream when a SETTINGS frame arrives
 var tests = [ test_http2_post_big
             , test_http2_basic
+            , test_http2_basic_unblocked_dep
             , test_http2_nospdy
             , test_http2_push1
             , test_http2_push2
             , test_http2_push3
             , test_http2_push4
 	    , test_http2_altsvc
             , test_http2_doubleheader
             , test_http2_xhr
--- a/parser/html/javasrc/AttributeName.java
+++ b/parser/html/javasrc/AttributeName.java
@@ -1016,16 +1016,17 @@ public final class AttributeName
     public static final AttributeName KEYSYSTEM = new AttributeName(ALL_NO_NS, SAME_LOCAL("keysystem"), ALL_NO_PREFIX, NCNAME_HTML | NCNAME_FOREIGN | NCNAME_LANG);
     public static final AttributeName KEYPOINTS = new AttributeName(ALL_NO_NS, SVG_DIFFERENT("keypoints", "keyPoints"), ALL_NO_PREFIX, NCNAME_HTML | NCNAME_FOREIGN | NCNAME_LANG);
     public static final AttributeName HIDEFOCUS = new AttributeName(ALL_NO_NS, SAME_LOCAL("hidefocus"), ALL_NO_PREFIX, NCNAME_HTML | NCNAME_FOREIGN | NCNAME_LANG);
     public static final AttributeName ONMESSAGE = new AttributeName(ALL_NO_NS, SAME_LOCAL("onmessage"), ALL_NO_PREFIX, NCNAME_HTML | NCNAME_FOREIGN | NCNAME_LANG);
     public static final AttributeName INTERCEPT = new AttributeName(ALL_NO_NS, SAME_LOCAL("intercept"), ALL_NO_PREFIX, NCNAME_HTML | NCNAME_FOREIGN | NCNAME_LANG);
     public static final AttributeName ONDRAGEND = new AttributeName(ALL_NO_NS, SAME_LOCAL("ondragend"), ALL_NO_PREFIX, NCNAME_HTML | NCNAME_FOREIGN | NCNAME_LANG);
     public static final AttributeName ONMOVEEND = new AttributeName(ALL_NO_NS, SAME_LOCAL("onmoveend"), ALL_NO_PREFIX, NCNAME_HTML | NCNAME_FOREIGN | NCNAME_LANG);
     public static final AttributeName ONINVALID = new AttributeName(ALL_NO_NS, SAME_LOCAL("oninvalid"), ALL_NO_PREFIX, NCNAME_HTML | NCNAME_FOREIGN | NCNAME_LANG);
+    public static final AttributeName INTEGRITY = new AttributeName(ALL_NO_NS, SAME_LOCAL("integrity"), ALL_NO_PREFIX, NCNAME_HTML | NCNAME_FOREIGN | NCNAME_LANG);
     public static final AttributeName ONKEYDOWN = new AttributeName(ALL_NO_NS, SAME_LOCAL("onkeydown"), ALL_NO_PREFIX, NCNAME_HTML | NCNAME_FOREIGN | NCNAME_LANG);
     public static final AttributeName ONFOCUSIN = new AttributeName(ALL_NO_NS, SAME_LOCAL("onfocusin"), ALL_NO_PREFIX, NCNAME_HTML | NCNAME_FOREIGN | NCNAME_LANG);
     public static final AttributeName ONMOUSEUP = new AttributeName(ALL_NO_NS, SAME_LOCAL("onmouseup"), ALL_NO_PREFIX, NCNAME_HTML | NCNAME_FOREIGN | NCNAME_LANG);
     public static final AttributeName INPUTMODE = new AttributeName(ALL_NO_NS, SAME_LOCAL("inputmode"), ALL_NO_PREFIX, NCNAME_HTML | NCNAME_FOREIGN | NCNAME_LANG);
     public static final AttributeName ONROWEXIT = new AttributeName(ALL_NO_NS, SAME_LOCAL("onrowexit"), ALL_NO_PREFIX, NCNAME_HTML | NCNAME_FOREIGN | NCNAME_LANG);
     public static final AttributeName MATHCOLOR = new AttributeName(ALL_NO_NS, SAME_LOCAL("mathcolor"), ALL_NO_PREFIX, NCNAME_HTML | NCNAME_FOREIGN | NCNAME_LANG);
     public static final AttributeName MASKUNITS = new AttributeName(ALL_NO_NS, SVG_DIFFERENT("maskunits", "maskUnits"), ALL_NO_PREFIX, NCNAME_HTML | NCNAME_FOREIGN | NCNAME_LANG);
     public static final AttributeName MAXLENGTH = new AttributeName(ALL_NO_NS, SAME_LOCAL("maxlength"), ALL_NO_PREFIX, NCNAME_HTML | NCNAME_FOREIGN | NCNAME_LANG);
@@ -1597,16 +1598,17 @@ public final class AttributeName
     KEYSYSTEM,
     KEYPOINTS,
     HIDEFOCUS,
     ONMESSAGE,
     INTERCEPT,
     ONDRAGEND,
     ONMOVEEND,
     ONINVALID,
+    INTEGRITY,
     ONKEYDOWN,
     ONFOCUSIN,
     ONMOUSEUP,
     INPUTMODE,
     ONROWEXIT,
     MATHCOLOR,
     MASKUNITS,
     MAXLENGTH,
@@ -2179,16 +2181,17 @@ public final class AttributeName
     310833159,
     311015256,
     313357609,
     313683893,
     313701861,
     313706996,
     313707317,
     313710350,
+    313795700,
     314027746,
     314038181,
     314091299,
     314205627,
     314233813,
     316741830,
     316797986,
     317486755,
--- a/parser/html/nsHtml5AtomList.h
+++ b/parser/html/nsHtml5AtomList.h
@@ -376,16 +376,17 @@ HTML5_ATOM(keysystem, "keysystem")
 HTML5_ATOM(keypoints, "keypoints")
 HTML5_ATOM(keyPoints, "keyPoints")
 HTML5_ATOM(hidefocus, "hidefocus")
 HTML5_ATOM(onmessage, "onmessage")
 HTML5_ATOM(intercept, "intercept")
 HTML5_ATOM(ondragend, "ondragend")
 HTML5_ATOM(onmoveend, "onmoveend")
 HTML5_ATOM(oninvalid, "oninvalid")
+HTML5_ATOM(integrity, "integrity")
 HTML5_ATOM(onkeydown, "onkeydown")
 HTML5_ATOM(onfocusin, "onfocusin")
 HTML5_ATOM(onmouseup, "onmouseup")
 HTML5_ATOM(inputmode, "inputmode")
 HTML5_ATOM(onrowexit, "onrowexit")
 HTML5_ATOM(mathcolor, "mathcolor")
 HTML5_ATOM(maskunits, "maskunits")
 HTML5_ATOM(maskUnits, "maskUnits")
--- a/parser/html/nsHtml5AttributeName.cpp
+++ b/parser/html/nsHtml5AttributeName.cpp
@@ -494,16 +494,17 @@ nsHtml5AttributeName* nsHtml5AttributeNa
 nsHtml5AttributeName* nsHtml5AttributeName::ATTR_KEYSYSTEM = nullptr;
 nsHtml5AttributeName* nsHtml5AttributeName::ATTR_KEYPOINTS = nullptr;
 nsHtml5AttributeName* nsHtml5AttributeName::ATTR_HIDEFOCUS = nullptr;
 nsHtml5AttributeName* nsHtml5AttributeName::ATTR_ONMESSAGE = nullptr;
 nsHtml5AttributeName* nsHtml5AttributeName::ATTR_INTERCEPT = nullptr;
 nsHtml5AttributeName* nsHtml5AttributeName::ATTR_ONDRAGEND = nullptr;
 nsHtml5AttributeName* nsHtml5AttributeName::ATTR_ONMOVEEND = nullptr;
 nsHtml5AttributeName* nsHtml5AttributeName::ATTR_ONINVALID = nullptr;
+nsHtml5AttributeName* nsHtml5AttributeName::ATTR_INTEGRITY = nullptr;
 nsHtml5AttributeName* nsHtml5AttributeName::ATTR_ONKEYDOWN = nullptr;
 nsHtml5AttributeName* nsHtml5AttributeName::ATTR_ONFOCUSIN = nullptr;
 nsHtml5AttributeName* nsHtml5AttributeName::ATTR_ONMOUSEUP = nullptr;
 nsHtml5AttributeName* nsHtml5AttributeName::ATTR_INPUTMODE = nullptr;
 nsHtml5AttributeName* nsHtml5AttributeName::ATTR_ONROWEXIT = nullptr;
 nsHtml5AttributeName* nsHtml5AttributeName::ATTR_MATHCOLOR = nullptr;
 nsHtml5AttributeName* nsHtml5AttributeName::ATTR_MASKUNITS = nullptr;
 nsHtml5AttributeName* nsHtml5AttributeName::ATTR_MAXLENGTH = nullptr;
@@ -771,17 +772,17 @@ nsHtml5AttributeName* nsHtml5AttributeNa
 nsHtml5AttributeName* nsHtml5AttributeName::ATTR_VERYVERYTHINMATHSPACE = nullptr;
 nsHtml5AttributeName* nsHtml5AttributeName::ATTR_VERYVERYTHICKMATHSPACE = nullptr;
 nsHtml5AttributeName* nsHtml5AttributeName::ATTR_STRIKETHROUGH_POSITION = nullptr;
 nsHtml5AttributeName* nsHtml5AttributeName::ATTR_STRIKETHROUGH_THICKNESS = nullptr;
 nsHtml5AttributeName* nsHtml5AttributeName::ATTR_GLYPH_ORIENTATION_VERTICAL = nullptr;
 nsHtml5AttributeName* nsHtml5AttributeName::ATTR_COLOR_INTERPOLATION_FILTERS = nullptr;
 nsHtml5AttributeName* nsHtml5AttributeName::ATTR_GLYPH_ORIENTATION_HORIZONTAL = nullptr;
 nsHtml5AttributeName** nsHtml5AttributeName::ATTRIBUTE_NAMES = 0;
-static int32_t const ATTRIBUTE_HASHES_DATA[] = { 1153, 1383, 1601, 1793, 1827, 1857, 68600, 69146, 69177, 70237, 70270, 71572, 71669, 72415, 72444, 74846, 74904, 74943, 75001, 75276, 75590, 84742, 84839, 85575, 85963, 85992, 87204, 88074, 88171, 89130, 89163, 3207892, 3283895, 3284791, 3338752, 3358197, 3369562, 3539124, 3562402, 3574260, 3670335, 3696933, 3721879, 135280021, 135346322, 136317019, 136475749, 136548517, 136652214, 136884919, 136902418, 136942992, 137292068, 139120259, 139785574, 142250603, 142314056, 142331176, 142519584, 144752417, 145106895, 146147200, 146765926, 148805544, 149655723, 149809441, 150018784, 150445028, 150813181, 150923321, 152528754, 152536216, 152647366, 152962785, 155219321, 155654904, 157317483, 157350248, 157437941, 157447478, 157604838, 157685404, 157894402, 158315188, 166078431, 169409980, 169700259, 169856932, 170007032, 170409695, 170466488, 170513710, 170608367, 173028944, 173896963, 176090625, 176129212, 179390001, 179489057, 179627464, 179840468, 179849042, 180004216, 181779081, 183027151, 183645319, 183698797, 185922012, 185997252, 188312483, 188675799, 190977533, 190992569, 191006194, 191033518, 191038774, 191096249, 191166163, 191194426, 191443343, 191522106, 191568039, 200104642, 202506661, 202537381, 202602917, 203070590, 203120766, 203389054, 203690071, 203971238, 203986524, 209040857, 209125756, 212055489, 212322418, 212746849, 213002877, 213055164, 213088023, 213259873, 213273386, 213435118, 213437318, 213438231, 213493071, 213532268, 213542834, 213584431, 213659891, 215285828, 215880731, 216112976, 216684637, 217369699, 217565298, 217576549, 218186795, 219743185, 220082234, 221623802, 221986406, 222283890, 223089542, 223138630, 223311265, 224431494, 224547358, 224587256, 224589550, 224655650, 224785518, 224810917, 224813302, 225126263, 225429618, 225432950, 225440869, 236107233, 236709921, 236838947, 237117095, 237143271, 237172455, 237209953, 237354143, 237372743, 237668065, 237703073, 237714273, 239743521, 240512803, 240522627, 240560417, 240656513, 241015715, 241062755, 241065383, 243523041, 245865199, 246261793, 246556195, 246774817, 246923491, 246928419, 246981667, 247014847, 247058369, 247112833, 247118177, 247119137, 247128739, 247316903, 249533729, 250235623, 250269543, 251402351, 252339047, 253260911, 253293679, 254844367, 255547879, 256077281, 256345377, 258124199, 258354465, 258605063, 258744193, 258845603, 258856961, 258926689, 269869248, 270174334, 270709417, 270778994, 270781796, 271102503, 271478858, 271490090, 272870654, 273335275, 273369140, 273924313, 274108530, 274116736, 276818662, 277476156, 279156579, 279349675, 280108533, 280128712, 280132869, 280162403, 280280292, 280413430, 280506130, 280677397, 280678580, 280686710, 280689066, 282736758, 283110901, 283275116, 283823226, 283890012, 284479340, 284606461, 286700477, 286798916, 291557706, 291665349, 291804100, 292138018, 292166446, 292418738, 292451039, 300298041, 300374839, 300597935, 303073389, 303083839, 303266673, 303354997, 303430688, 303576261, 303724281, 303819694, 304242723, 304382625, 306247792, 307227811, 307468786, 307724489, 310252031, 310358241, 310373094, 310833159, 311015256, 313357609, 313683893, 313701861, 313706996, 313707317, 313710350, 314027746, 314038181, 314091299, 314205627, 314233813, 316741830, 316797986, 317486755, 317794164, 320076137, 322657125, 322887778, 323506876, 323572412, 323605180, 325060058, 325320188, 325398738, 325541490, 325671619, 333868843, 336806130, 337212108, 337282686, 337285434, 337585223, 338036037, 338298087, 338566051, 340943551, 341190970, 342995704, 343352124, 343912673, 344585053, 346977248, 347218098, 347262163, 347278576, 347438191, 347655959, 347684788, 347726430, 347727772, 347776035, 347776629, 349500753, 350880161, 350887073, 353384123, 355496998, 355906922, 355979793, 356545959, 358637867, 358905016, 359164318, 359247286, 359350571, 359579447, 365560330, 367399355, 367420285, 367510727, 368013212, 370234760, 370353345, 370710317, 371074566, 371122285, 371194213, 371448425, 371448430, 371545055, 371593469, 371596922, 371758751, 371964792, 372151328, 376550136, 376710172, 376795771, 376826271, 376906556, 380514830, 380774774, 380775037, 381030322, 381136500, 381281631, 381282269, 381285504, 381330595, 381331422, 381335911, 381336484, 383907298, 383917408, 384595009, 384595013, 387799894, 387823201, 392581647, 392584937, 392742684, 392906485, 393003349, 400644707, 400973830, 404428547, 404432113, 404432865, 404469244, 404478897, 404694860, 406887479, 408294949, 408789955, 410022510, 410467324, 410586448, 410945965, 411845275, 414327152, 414327932, 414329781, 414346257, 414346439, 414639928, 414835998, 414894517, 414986533, 417465377, 417465381, 417492216, 418259232, 419310946, 420103495, 420242342, 420380455, 420658662, 420717432, 423183880, 424539259, 425929170, 425972964, 426050649, 426126450, 426142833, 426607922, 437289840, 437347469, 437412335, 437423943, 437455540, 437462252, 437597991, 437617485, 437986305, 437986507, 437986828, 437987072, 438015591, 438034813, 438038966, 438179623, 438347971, 438483573, 438547062, 438895551, 441592676, 442032555, 443548979, 447881379, 447881655, 447881895, 447887844, 448416189, 448445746, 448449012, 450942191, 452816744, 453668677, 454434495, 456610076, 456642844, 456738709, 457544600, 459451897, 459680944, 468058810, 468083581, 470964084, 471470955, 471567278, 472267822, 481177859, 481210627, 481435874, 481455115, 481485378, 481490218, 485105638, 486005878, 486383494, 487988916, 488103783, 490661867, 491574090, 491578272, 493041952, 493441205, 493582844, 493716979, 504577572, 504740359, 505091638, 505592418, 505656212, 509516275, 514998531, 515571132, 515594682, 518712698, 521362273, 526592419, 526807354, 527348842, 538294791, 544689535, 545535009, 548544752, 548563346, 548595116, 551679010, 558034099, 560329411, 560356209, 560671018, 560671152, 560692590, 560845442, 569212097, 569474241, 572252718, 575326764, 576174758, 576190819, 582099184, 582099438, 582372519, 582558889, 586552164, 591325418, 594231990, 594243961, 605711268, 615672071, 616086845, 621792370, 624879850, 627432831, 640040548, 654392808, 658675477, 659420283, 672891587, 694768102, 705890982, 725543146, 759097578, 761686526, 795383908, 878105336, 908643300, 945213471 };
+static int32_t const ATTRIBUTE_HASHES_DATA[] = { 1153, 1383, 1601, 1793, 1827, 1857, 68600, 69146, 69177, 70237, 70270, 71572, 71669, 72415, 72444, 74846, 74904, 74943, 75001, 75276, 75590, 84742, 84839, 85575, 85963, 85992, 87204, 88074, 88171, 89130, 89163, 3207892, 3283895, 3284791, 3338752, 3358197, 3369562, 3539124, 3562402, 3574260, 3670335, 3696933, 3721879, 135280021, 135346322, 136317019, 136475749, 136548517, 136652214, 136884919, 136902418, 136942992, 137292068, 139120259, 139785574, 142250603, 142314056, 142331176, 142519584, 144752417, 145106895, 146147200, 146765926, 148805544, 149655723, 149809441, 150018784, 150445028, 150813181, 150923321, 152528754, 152536216, 152647366, 152962785, 155219321, 155654904, 157317483, 157350248, 157437941, 157447478, 157604838, 157685404, 157894402, 158315188, 166078431, 169409980, 169700259, 169856932, 170007032, 170409695, 170466488, 170513710, 170608367, 173028944, 173896963, 176090625, 176129212, 179390001, 179489057, 179627464, 179840468, 179849042, 180004216, 181779081, 183027151, 183645319, 183698797, 185922012, 185997252, 188312483, 188675799, 190977533, 190992569, 191006194, 191033518, 191038774, 191096249, 191166163, 191194426, 191443343, 191522106, 191568039, 200104642, 202506661, 202537381, 202602917, 203070590, 203120766, 203389054, 203690071, 203971238, 203986524, 209040857, 209125756, 212055489, 212322418, 212746849, 213002877, 213055164, 213088023, 213259873, 213273386, 213435118, 213437318, 213438231, 213493071, 213532268, 213542834, 213584431, 213659891, 215285828, 215880731, 216112976, 216684637, 217369699, 217565298, 217576549, 218186795, 219743185, 220082234, 221623802, 221986406, 222283890, 223089542, 223138630, 223311265, 224431494, 224547358, 224587256, 224589550, 224655650, 224785518, 224810917, 224813302, 225126263, 225429618, 225432950, 225440869, 236107233, 236709921, 236838947, 237117095, 237143271, 237172455, 237209953, 237354143, 237372743, 237668065, 237703073, 237714273, 239743521, 240512803, 240522627, 240560417, 240656513, 241015715, 241062755, 241065383, 243523041, 245865199, 246261793, 246556195, 246774817, 246923491, 246928419, 246981667, 247014847, 247058369, 247112833, 247118177, 247119137, 247128739, 247316903, 249533729, 250235623, 250269543, 251402351, 252339047, 253260911, 253293679, 254844367, 255547879, 256077281, 256345377, 258124199, 258354465, 258605063, 258744193, 258845603, 258856961, 258926689, 269869248, 270174334, 270709417, 270778994, 270781796, 271102503, 271478858, 271490090, 272870654, 273335275, 273369140, 273924313, 274108530, 274116736, 276818662, 277476156, 279156579, 279349675, 280108533, 280128712, 280132869, 280162403, 280280292, 280413430, 280506130, 280677397, 280678580, 280686710, 280689066, 282736758, 283110901, 283275116, 283823226, 283890012, 284479340, 284606461, 286700477, 286798916, 291557706, 291665349, 291804100, 292138018, 292166446, 292418738, 292451039, 300298041, 300374839, 300597935, 303073389, 303083839, 303266673, 303354997, 303430688, 303576261, 303724281, 303819694, 304242723, 304382625, 306247792, 307227811, 307468786, 307724489, 310252031, 310358241, 310373094, 310833159, 311015256, 313357609, 313683893, 313701861, 313706996, 313707317, 313710350, 313795700, 314027746, 314038181, 314091299, 314205627, 314233813, 316741830, 316797986, 317486755, 317794164, 320076137, 322657125, 322887778, 323506876, 323572412, 323605180, 325060058, 325320188, 325398738, 325541490, 325671619, 333868843, 336806130, 337212108, 337282686, 337285434, 337585223, 338036037, 338298087, 338566051, 340943551, 341190970, 342995704, 343352124, 343912673, 344585053, 346977248, 347218098, 347262163, 347278576, 347438191, 347655959, 347684788, 347726430, 347727772, 347776035, 347776629, 349500753, 350880161, 350887073, 353384123, 355496998, 355906922, 355979793, 356545959, 358637867, 358905016, 359164318, 359247286, 359350571, 359579447, 365560330, 367399355, 367420285, 367510727, 368013212, 370234760, 370353345, 370710317, 371074566, 371122285, 371194213, 371448425, 371448430, 371545055, 371593469, 371596922, 371758751, 371964792, 372151328, 376550136, 376710172, 376795771, 376826271, 376906556, 380514830, 380774774, 380775037, 381030322, 381136500, 381281631, 381282269, 381285504, 381330595, 381331422, 381335911, 381336484, 383907298, 383917408, 384595009, 384595013, 387799894, 387823201, 392581647, 392584937, 392742684, 392906485, 393003349, 400644707, 400973830, 404428547, 404432113, 404432865, 404469244, 404478897, 404694860, 406887479, 408294949, 408789955, 410022510, 410467324, 410586448, 410945965, 411845275, 414327152, 414327932, 414329781, 414346257, 414346439, 414639928, 414835998, 414894517, 414986533, 417465377, 417465381, 417492216, 418259232, 419310946, 420103495, 420242342, 420380455, 420658662, 420717432, 423183880, 424539259, 425929170, 425972964, 426050649, 426126450, 426142833, 426607922, 437289840, 437347469, 437412335, 437423943, 437455540, 437462252, 437597991, 437617485, 437986305, 437986507, 437986828, 437987072, 438015591, 438034813, 438038966, 438179623, 438347971, 438483573, 438547062, 438895551, 441592676, 442032555, 443548979, 447881379, 447881655, 447881895, 447887844, 448416189, 448445746, 448449012, 450942191, 452816744, 453668677, 454434495, 456610076, 456642844, 456738709, 457544600, 459451897, 459680944, 468058810, 468083581, 470964084, 471470955, 471567278, 472267822, 481177859, 481210627, 481435874, 481455115, 481485378, 481490218, 485105638, 486005878, 486383494, 487988916, 488103783, 490661867, 491574090, 491578272, 493041952, 493441205, 493582844, 493716979, 504577572, 504740359, 505091638, 505592418, 505656212, 509516275, 514998531, 515571132, 515594682, 518712698, 521362273, 526592419, 526807354, 527348842, 538294791, 544689535, 545535009, 548544752, 548563346, 548595116, 551679010, 558034099, 560329411, 560356209, 560671018, 560671152, 560692590, 560845442, 569212097, 569474241, 572252718, 575326764, 576174758, 576190819, 582099184, 582099438, 582372519, 582558889, 586552164, 591325418, 594231990, 594243961, 605711268, 615672071, 616086845, 621792370, 624879850, 627432831, 640040548, 654392808, 658675477, 659420283, 672891587, 694768102, 705890982, 725543146, 759097578, 761686526, 795383908, 878105336, 908643300, 945213471 };
 staticJArray<int32_t,int32_t> nsHtml5AttributeName::ATTRIBUTE_HASHES = { ATTRIBUTE_HASHES_DATA, MOZ_ARRAY_LENGTH(ATTRIBUTE_HASHES_DATA) };
 void
 nsHtml5AttributeName::initializeStatics()
 {
   ALL_NO_NS = new int32_t[3];
   ALL_NO_NS[0] = kNameSpaceID_None;
   ALL_NO_NS[1] = kNameSpaceID_None;
   ALL_NO_NS[2] = kNameSpaceID_None;
@@ -1112,16 +1113,17 @@ nsHtml5AttributeName::initializeStatics(
   ATTR_KEYSYSTEM = new nsHtml5AttributeName(ALL_NO_NS, SAME_LOCAL(nsHtml5Atoms::keysystem), ALL_NO_PREFIX);
   ATTR_KEYPOINTS = new nsHtml5AttributeName(ALL_NO_NS, SVG_DIFFERENT(nsHtml5Atoms::keypoints, nsHtml5Atoms::keyPoints), ALL_NO_PREFIX);
   ATTR_HIDEFOCUS = new nsHtml5AttributeName(ALL_NO_NS, SAME_LOCAL(nsHtml5Atoms::hidefocus), ALL_NO_PREFIX);
   ATTR_ONMESSAGE = new nsHtml5AttributeName(ALL_NO_NS, SAME_LOCAL(nsHtml5Atoms::onmessage), ALL_NO_PREFIX);
   ATTR_INTERCEPT = new nsHtml5AttributeName(ALL_NO_NS, SAME_LOCAL(nsHtml5Atoms::intercept), ALL_NO_PREFIX);
   ATTR_ONDRAGEND = new nsHtml5AttributeName(ALL_NO_NS, SAME_LOCAL(nsHtml5Atoms::ondragend), ALL_NO_PREFIX);
   ATTR_ONMOVEEND = new nsHtml5AttributeName(ALL_NO_NS, SAME_LOCAL(nsHtml5Atoms::onmoveend), ALL_NO_PREFIX);
   ATTR_ONINVALID = new nsHtml5AttributeName(ALL_NO_NS, SAME_LOCAL(nsHtml5Atoms::oninvalid), ALL_NO_PREFIX);
+  ATTR_INTEGRITY = new nsHtml5AttributeName(ALL_NO_NS, SAME_LOCAL(nsHtml5Atoms::integrity), ALL_NO_PREFIX);
   ATTR_ONKEYDOWN = new nsHtml5AttributeName(ALL_NO_NS, SAME_LOCAL(nsHtml5Atoms::onkeydown), ALL_NO_PREFIX);
   ATTR_ONFOCUSIN = new nsHtml5AttributeName(ALL_NO_NS, SAME_LOCAL(nsHtml5Atoms::onfocusin), ALL_NO_PREFIX);
   ATTR_ONMOUSEUP = new nsHtml5AttributeName(ALL_NO_NS, SAME_LOCAL(nsHtml5Atoms::onmouseup), ALL_NO_PREFIX);
   ATTR_INPUTMODE = new nsHtml5AttributeName(ALL_NO_NS, SAME_LOCAL(nsHtml5Atoms::inputmode), ALL_NO_PREFIX);
   ATTR_ONROWEXIT = new nsHtml5AttributeName(ALL_NO_NS, SAME_LOCAL(nsHtml5Atoms::onrowexit), ALL_NO_PREFIX);
   ATTR_MATHCOLOR = new nsHtml5AttributeName(ALL_NO_NS, SAME_LOCAL(nsHtml5Atoms::mathcolor), ALL_NO_PREFIX);
   ATTR_MASKUNITS = new nsHtml5AttributeName(ALL_NO_NS, SVG_DIFFERENT(nsHtml5Atoms::maskunits, nsHtml5Atoms::maskUnits), ALL_NO_PREFIX);
   ATTR_MAXLENGTH = new nsHtml5AttributeName(ALL_NO_NS, SAME_LOCAL(nsHtml5Atoms::maxlength), ALL_NO_PREFIX);
@@ -1388,17 +1390,17 @@ nsHtml5AttributeName::initializeStatics(
   ATTR_ARIA_ACTIVEDESCENDANT = new nsHtml5AttributeName(ALL_NO_NS, SAME_LOCAL(nsHtml5Atoms::aria_activedescendant), ALL_NO_PREFIX);
   ATTR_VERYVERYTHINMATHSPACE = new nsHtml5AttributeName(ALL_NO_NS, SAME_LOCAL(nsHtml5Atoms::veryverythinmathspace), ALL_NO_PREFIX);
   ATTR_VERYVERYTHICKMATHSPACE = new nsHtml5AttributeName(ALL_NO_NS, SAME_LOCAL(nsHtml5Atoms::veryverythickmathspace), ALL_NO_PREFIX);
   ATTR_STRIKETHROUGH_POSITION = new nsHtml5AttributeName(ALL_NO_NS, SAME_LOCAL(nsHtml5Atoms::strikethrough_position), ALL_NO_PREFIX);
   ATTR_STRIKETHROUGH_THICKNESS = new nsHtml5AttributeName(ALL_NO_NS, SAME_LOCAL(nsHtml5Atoms::strikethrough_thickness), ALL_NO_PREFIX);
   ATTR_GLYPH_ORIENTATION_VERTICAL = new nsHtml5AttributeName(ALL_NO_NS, SAME_LOCAL(nsHtml5Atoms::glyph_orientation_vertical), ALL_NO_PREFIX);
   ATTR_COLOR_INTERPOLATION_FILTERS = new nsHtml5AttributeName(ALL_NO_NS, SAME_LOCAL(nsHtml5Atoms::color_interpolation_filters), ALL_NO_PREFIX);
   ATTR_GLYPH_ORIENTATION_HORIZONTAL = new nsHtml5AttributeName(ALL_NO_NS, SAME_LOCAL(nsHtml5Atoms::glyph_orientation_horizontal), ALL_NO_PREFIX);
-  ATTRIBUTE_NAMES = new nsHtml5AttributeName*[580];
+  ATTRIBUTE_NAMES = new nsHtml5AttributeName*[581];
   ATTRIBUTE_NAMES[0] = ATTR_D;
   ATTRIBUTE_NAMES[1] = ATTR_K;
   ATTRIBUTE_NAMES[2] = ATTR_R;
   ATTRIBUTE_NAMES[3] = ATTR_X;
   ATTRIBUTE_NAMES[4] = ATTR_Y;
   ATTRIBUTE_NAMES[5] = ATTR_Z;
   ATTRIBUTE_NAMES[6] = ATTR_BY;
   ATTRIBUTE_NAMES[7] = ATTR_CX;
@@ -1693,292 +1695,293 @@ nsHtml5AttributeName::initializeStatics(
   ATTRIBUTE_NAMES[296] = ATTR_KEYSYSTEM;
   ATTRIBUTE_NAMES[297] = ATTR_KEYPOINTS;
   ATTRIBUTE_NAMES[298] = ATTR_HIDEFOCUS;
   ATTRIBUTE_NAMES[299] = ATTR_ONMESSAGE;
   ATTRIBUTE_NAMES[300] = ATTR_INTERCEPT;
   ATTRIBUTE_NAMES[301] = ATTR_ONDRAGEND;
   ATTRIBUTE_NAMES[302] = ATTR_ONMOVEEND;
   ATTRIBUTE_NAMES[303] = ATTR_ONINVALID;
-  ATTRIBUTE_NAMES[304] = ATTR_ONKEYDOWN;
-  ATTRIBUTE_NAMES[305] = ATTR_ONFOCUSIN;
-  ATTRIBUTE_NAMES[306] = ATTR_ONMOUSEUP;
-  ATTRIBUTE_NAMES[307] = ATTR_INPUTMODE;
-  ATTRIBUTE_NAMES[308] = ATTR_ONROWEXIT;
-  ATTRIBUTE_NAMES[309] = ATTR_MATHCOLOR;
-  ATTRIBUTE_NAMES[310] = ATTR_MASKUNITS;
-  ATTRIBUTE_NAMES[311] = ATTR_MAXLENGTH;
-  ATTRIBUTE_NAMES[312] = ATTR_LINEBREAK;
-  ATTRIBUTE_NAMES[313] = ATTR_TRANSFORM;
-  ATTRIBUTE_NAMES[314] = ATTR_V_HANGING;
-  ATTRIBUTE_NAMES[315] = ATTR_VALUETYPE;
-  ATTRIBUTE_NAMES[316] = ATTR_POINTSATZ;
-  ATTRIBUTE_NAMES[317] = ATTR_POINTSATX;
-  ATTRIBUTE_NAMES[318] = ATTR_POINTSATY;
-  ATTRIBUTE_NAMES[319] = ATTR_SYMMETRIC;
-  ATTRIBUTE_NAMES[320] = ATTR_SCROLLING;
-  ATTRIBUTE_NAMES[321] = ATTR_REPEATDUR;
-  ATTRIBUTE_NAMES[322] = ATTR_SELECTION;
-  ATTRIBUTE_NAMES[323] = ATTR_SEPARATOR;
-  ATTRIBUTE_NAMES[324] = ATTR_XML_SPACE;
-  ATTRIBUTE_NAMES[325] = ATTR_AUTOSUBMIT;
-  ATTRIBUTE_NAMES[326] = ATTR_ALPHABETIC;
-  ATTRIBUTE_NAMES[327] = ATTR_ACTIONTYPE;
-  ATTRIBUTE_NAMES[328] = ATTR_ACCUMULATE;
-  ATTRIBUTE_NAMES[329] = ATTR_ARIA_LEVEL;
-  ATTRIBUTE_NAMES[330] = ATTR_COLUMNSPAN;
-  ATTRIBUTE_NAMES[331] = ATTR_CAP_HEIGHT;
-  ATTRIBUTE_NAMES[332] = ATTR_BACKGROUND;
-  ATTRIBUTE_NAMES[333] = ATTR_GLYPH_NAME;
-  ATTRIBUTE_NAMES[334] = ATTR_GROUPALIGN;
-  ATTRIBUTE_NAMES[335] = ATTR_FONTFAMILY;
-  ATTRIBUTE_NAMES[336] = ATTR_FONTWEIGHT;
-  ATTRIBUTE_NAMES[337] = ATTR_FONT_STYLE;
-  ATTRIBUTE_NAMES[338] = ATTR_KEYSPLINES;
-  ATTRIBUTE_NAMES[339] = ATTR_HTTP_EQUIV;
-  ATTRIBUTE_NAMES[340] = ATTR_ONACTIVATE;
-  ATTRIBUTE_NAMES[341] = ATTR_OCCURRENCE;
-  ATTRIBUTE_NAMES[342] = ATTR_IRRELEVANT;
-  ATTRIBUTE_NAMES[343] = ATTR_ONDBLCLICK;
-  ATTRIBUTE_NAMES[344] = ATTR_ONDRAGDROP;
-  ATTRIBUTE_NAMES[345] = ATTR_ONKEYPRESS;
-  ATTRIBUTE_NAMES[346] = ATTR_ONROWENTER;
-  ATTRIBUTE_NAMES[347] = ATTR_ONDRAGOVER;
-  ATTRIBUTE_NAMES[348] = ATTR_ONFOCUSOUT;
-  ATTRIBUTE_NAMES[349] = ATTR_ONMOUSEOUT;
-  ATTRIBUTE_NAMES[350] = ATTR_NUMOCTAVES;
-  ATTRIBUTE_NAMES[351] = ATTR_MARKER_MID;
-  ATTRIBUTE_NAMES[352] = ATTR_MARKER_END;
-  ATTRIBUTE_NAMES[353] = ATTR_TEXTLENGTH;
-  ATTRIBUTE_NAMES[354] = ATTR_VISIBILITY;
-  ATTRIBUTE_NAMES[355] = ATTR_VIEWTARGET;
-  ATTRIBUTE_NAMES[356] = ATTR_VERT_ADV_Y;
-  ATTRIBUTE_NAMES[357] = ATTR_PATHLENGTH;
-  ATTRIBUTE_NAMES[358] = ATTR_REPEAT_MAX;
-  ATTRIBUTE_NAMES[359] = ATTR_RADIOGROUP;
-  ATTRIBUTE_NAMES[360] = ATTR_STOP_COLOR;
-  ATTRIBUTE_NAMES[361] = ATTR_SEPARATORS;
-  ATTRIBUTE_NAMES[362] = ATTR_REPEAT_MIN;
-  ATTRIBUTE_NAMES[363] = ATTR_ROWSPACING;
-  ATTRIBUTE_NAMES[364] = ATTR_ZOOMANDPAN;
-  ATTRIBUTE_NAMES[365] = ATTR_XLINK_TYPE;
-  ATTRIBUTE_NAMES[366] = ATTR_XLINK_ROLE;
-  ATTRIBUTE_NAMES[367] = ATTR_XLINK_HREF;
-  ATTRIBUTE_NAMES[368] = ATTR_XLINK_SHOW;
-  ATTRIBUTE_NAMES[369] = ATTR_ACCENTUNDER;
-  ATTRIBUTE_NAMES[370] = ATTR_ARIA_SECRET;
-  ATTRIBUTE_NAMES[371] = ATTR_ARIA_ATOMIC;
-  ATTRIBUTE_NAMES[372] = ATTR_ARIA_HIDDEN;
-  ATTRIBUTE_NAMES[373] = ATTR_ARIA_FLOWTO;
-  ATTRIBUTE_NAMES[374] = ATTR_ARABIC_FORM;
-  ATTRIBUTE_NAMES[375] = ATTR_CELLPADDING;
-  ATTRIBUTE_NAMES[376] = ATTR_CELLSPACING;
-  ATTRIBUTE_NAMES[377] = ATTR_COLUMNWIDTH;
-  ATTRIBUTE_NAMES[378] = ATTR_CROSSORIGIN;
-  ATTRIBUTE_NAMES[379] = ATTR_COLUMNALIGN;
-  ATTRIBUTE_NAMES[380] = ATTR_COLUMNLINES;
-  ATTRIBUTE_NAMES[381] = ATTR_CONTEXTMENU;
-  ATTRIBUTE_NAMES[382] = ATTR_BASEPROFILE;
-  ATTRIBUTE_NAMES[383] = ATTR_FONT_FAMILY;
-  ATTRIBUTE_NAMES[384] = ATTR_FRAMEBORDER;
-  ATTRIBUTE_NAMES[385] = ATTR_FILTERUNITS;
-  ATTRIBUTE_NAMES[386] = ATTR_FLOOD_COLOR;
-  ATTRIBUTE_NAMES[387] = ATTR_FONT_WEIGHT;
-  ATTRIBUTE_NAMES[388] = ATTR_HORIZ_ADV_X;
-  ATTRIBUTE_NAMES[389] = ATTR_ONDRAGLEAVE;
-  ATTRIBUTE_NAMES[390] = ATTR_ONMOUSEMOVE;
-  ATTRIBUTE_NAMES[391] = ATTR_ORIENTATION;
-  ATTRIBUTE_NAMES[392] = ATTR_ONMOUSEDOWN;
-  ATTRIBUTE_NAMES[393] = ATTR_ONMOUSEOVER;
-  ATTRIBUTE_NAMES[394] = ATTR_ONDRAGENTER;
-  ATTRIBUTE_NAMES[395] = ATTR_IDEOGRAPHIC;
-  ATTRIBUTE_NAMES[396] = ATTR_ONBEFORECUT;
-  ATTRIBUTE_NAMES[397] = ATTR_ONFORMINPUT;
-  ATTRIBUTE_NAMES[398] = ATTR_ONDRAGSTART;
-  ATTRIBUTE_NAMES[399] = ATTR_ONMOVESTART;
-  ATTRIBUTE_NAMES[400] = ATTR_MARKERUNITS;
-  ATTRIBUTE_NAMES[401] = ATTR_MATHVARIANT;
-  ATTRIBUTE_NAMES[402] = ATTR_MARGINWIDTH;
-  ATTRIBUTE_NAMES[403] = ATTR_MARKERWIDTH;
-  ATTRIBUTE_NAMES[404] = ATTR_TEXT_ANCHOR;
-  ATTRIBUTE_NAMES[405] = ATTR_TABLEVALUES;
-  ATTRIBUTE_NAMES[406] = ATTR_SCRIPTLEVEL;
-  ATTRIBUTE_NAMES[407] = ATTR_REPEATCOUNT;
-  ATTRIBUTE_NAMES[408] = ATTR_STITCHTILES;
-  ATTRIBUTE_NAMES[409] = ATTR_STARTOFFSET;
-  ATTRIBUTE_NAMES[410] = ATTR_SCROLLDELAY;
-  ATTRIBUTE_NAMES[411] = ATTR_XMLNS_XLINK;
-  ATTRIBUTE_NAMES[412] = ATTR_XLINK_TITLE;
-  ATTRIBUTE_NAMES[413] = ATTR_ARIA_INVALID;
-  ATTRIBUTE_NAMES[414] = ATTR_ARIA_PRESSED;
-  ATTRIBUTE_NAMES[415] = ATTR_ARIA_CHECKED;
-  ATTRIBUTE_NAMES[416] = ATTR_AUTOCOMPLETE;
-  ATTRIBUTE_NAMES[417] = ATTR_ARIA_SETSIZE;
-  ATTRIBUTE_NAMES[418] = ATTR_ARIA_CHANNEL;
-  ATTRIBUTE_NAMES[419] = ATTR_EQUALCOLUMNS;
-  ATTRIBUTE_NAMES[420] = ATTR_DISPLAYSTYLE;
-  ATTRIBUTE_NAMES[421] = ATTR_DATAFORMATAS;
-  ATTRIBUTE_NAMES[422] = ATTR_FILL_OPACITY;
-  ATTRIBUTE_NAMES[423] = ATTR_FONT_VARIANT;
-  ATTRIBUTE_NAMES[424] = ATTR_FONT_STRETCH;
-  ATTRIBUTE_NAMES[425] = ATTR_FRAMESPACING;
-  ATTRIBUTE_NAMES[426] = ATTR_KERNELMATRIX;
-  ATTRIBUTE_NAMES[427] = ATTR_ONDEACTIVATE;
-  ATTRIBUTE_NAMES[428] = ATTR_ONROWSDELETE;
-  ATTRIBUTE_NAMES[429] = ATTR_ONMOUSELEAVE;
-  ATTRIBUTE_NAMES[430] = ATTR_ONFORMCHANGE;
-  ATTRIBUTE_NAMES[431] = ATTR_ONCELLCHANGE;
-  ATTRIBUTE_NAMES[432] = ATTR_ONMOUSEWHEEL;
-  ATTRIBUTE_NAMES[433] = ATTR_ONMOUSEENTER;
-  ATTRIBUTE_NAMES[434] = ATTR_ONAFTERPRINT;
-  ATTRIBUTE_NAMES[435] = ATTR_ONBEFORECOPY;
-  ATTRIBUTE_NAMES[436] = ATTR_MARGINHEIGHT;
-  ATTRIBUTE_NAMES[437] = ATTR_MARKERHEIGHT;
-  ATTRIBUTE_NAMES[438] = ATTR_MARKER_START;
-  ATTRIBUTE_NAMES[439] = ATTR_MATHEMATICAL;
-  ATTRIBUTE_NAMES[440] = ATTR_LENGTHADJUST;
-  ATTRIBUTE_NAMES[441] = ATTR_UNSELECTABLE;
-  ATTRIBUTE_NAMES[442] = ATTR_UNICODE_BIDI;
-  ATTRIBUTE_NAMES[443] = ATTR_UNITS_PER_EM;
-  ATTRIBUTE_NAMES[444] = ATTR_WORD_SPACING;
-  ATTRIBUTE_NAMES[445] = ATTR_WRITING_MODE;
-  ATTRIBUTE_NAMES[446] = ATTR_V_ALPHABETIC;
-  ATTRIBUTE_NAMES[447] = ATTR_PATTERNUNITS;
-  ATTRIBUTE_NAMES[448] = ATTR_SPREADMETHOD;
-  ATTRIBUTE_NAMES[449] = ATTR_SURFACESCALE;
-  ATTRIBUTE_NAMES[450] = ATTR_STROKE_WIDTH;
-  ATTRIBUTE_NAMES[451] = ATTR_REPEAT_START;
-  ATTRIBUTE_NAMES[452] = ATTR_STDDEVIATION;
-  ATTRIBUTE_NAMES[453] = ATTR_STOP_OPACITY;
-  ATTRIBUTE_NAMES[454] = ATTR_ARIA_CONTROLS;
-  ATTRIBUTE_NAMES[455] = ATTR_ARIA_HASPOPUP;
-  ATTRIBUTE_NAMES[456] = ATTR_ACCENT_HEIGHT;
-  ATTRIBUTE_NAMES[457] = ATTR_ARIA_VALUENOW;
-  ATTRIBUTE_NAMES[458] = ATTR_ARIA_RELEVANT;
-  ATTRIBUTE_NAMES[459] = ATTR_ARIA_POSINSET;
-  ATTRIBUTE_NAMES[460] = ATTR_ARIA_VALUEMAX;
-  ATTRIBUTE_NAMES[461] = ATTR_ARIA_READONLY;
-  ATTRIBUTE_NAMES[462] = ATTR_ARIA_SELECTED;
-  ATTRIBUTE_NAMES[463] = ATTR_ARIA_REQUIRED;
-  ATTRIBUTE_NAMES[464] = ATTR_ARIA_EXPANDED;
-  ATTRIBUTE_NAMES[465] = ATTR_ARIA_DISABLED;
-  ATTRIBUTE_NAMES[466] = ATTR_ATTRIBUTETYPE;
-  ATTRIBUTE_NAMES[467] = ATTR_ATTRIBUTENAME;
-  ATTRIBUTE_NAMES[468] = ATTR_ARIA_DATATYPE;
-  ATTRIBUTE_NAMES[469] = ATTR_ARIA_VALUEMIN;
-  ATTRIBUTE_NAMES[470] = ATTR_BASEFREQUENCY;
-  ATTRIBUTE_NAMES[471] = ATTR_COLUMNSPACING;
-  ATTRIBUTE_NAMES[472] = ATTR_COLOR_PROFILE;
-  ATTRIBUTE_NAMES[473] = ATTR_CLIPPATHUNITS;
-  ATTRIBUTE_NAMES[474] = ATTR_DEFINITIONURL;
-  ATTRIBUTE_NAMES[475] = ATTR_GRADIENTUNITS;
-  ATTRIBUTE_NAMES[476] = ATTR_FLOOD_OPACITY;
-  ATTRIBUTE_NAMES[477] = ATTR_ONAFTERUPDATE;
-  ATTRIBUTE_NAMES[478] = ATTR_ONERRORUPDATE;
-  ATTRIBUTE_NAMES[479] = ATTR_ONBEFOREPASTE;
-  ATTRIBUTE_NAMES[480] = ATTR_ONLOSECAPTURE;
-  ATTRIBUTE_NAMES[481] = ATTR_ONCONTEXTMENU;
-  ATTRIBUTE_NAMES[482] = ATTR_ONSELECTSTART;
-  ATTRIBUTE_NAMES[483] = ATTR_ONBEFOREPRINT;
-  ATTRIBUTE_NAMES[484] = ATTR_MOVABLELIMITS;
-  ATTRIBUTE_NAMES[485] = ATTR_LINETHICKNESS;
-  ATTRIBUTE_NAMES[486] = ATTR_UNICODE_RANGE;
-  ATTRIBUTE_NAMES[487] = ATTR_THINMATHSPACE;
-  ATTRIBUTE_NAMES[488] = ATTR_VERT_ORIGIN_X;
-  ATTRIBUTE_NAMES[489] = ATTR_VERT_ORIGIN_Y;
-  ATTRIBUTE_NAMES[490] = ATTR_V_IDEOGRAPHIC;
-  ATTRIBUTE_NAMES[491] = ATTR_PRESERVEALPHA;
-  ATTRIBUTE_NAMES[492] = ATTR_SCRIPTMINSIZE;
-  ATTRIBUTE_NAMES[493] = ATTR_SPECIFICATION;
-  ATTRIBUTE_NAMES[494] = ATTR_XLINK_ACTUATE;
-  ATTRIBUTE_NAMES[495] = ATTR_XLINK_ARCROLE;
-  ATTRIBUTE_NAMES[496] = ATTR_ACCEPT_CHARSET;
-  ATTRIBUTE_NAMES[497] = ATTR_ALIGNMENTSCOPE;
-  ATTRIBUTE_NAMES[498] = ATTR_ARIA_MULTILINE;
-  ATTRIBUTE_NAMES[499] = ATTR_BASELINE_SHIFT;
-  ATTRIBUTE_NAMES[500] = ATTR_HORIZ_ORIGIN_X;
-  ATTRIBUTE_NAMES[501] = ATTR_HORIZ_ORIGIN_Y;
-  ATTRIBUTE_NAMES[502] = ATTR_ONBEFOREUPDATE;
-  ATTRIBUTE_NAMES[503] = ATTR_ONFILTERCHANGE;
-  ATTRIBUTE_NAMES[504] = ATTR_ONROWSINSERTED;
-  ATTRIBUTE_NAMES[505] = ATTR_ONBEFOREUNLOAD;
-  ATTRIBUTE_NAMES[506] = ATTR_MATHBACKGROUND;
-  ATTRIBUTE_NAMES[507] = ATTR_LETTER_SPACING;
-  ATTRIBUTE_NAMES[508] = ATTR_LIGHTING_COLOR;
-  ATTRIBUTE_NAMES[509] = ATTR_THICKMATHSPACE;
-  ATTRIBUTE_NAMES[510] = ATTR_TEXT_RENDERING;
-  ATTRIBUTE_NAMES[511] = ATTR_V_MATHEMATICAL;
-  ATTRIBUTE_NAMES[512] = ATTR_POINTER_EVENTS;
-  ATTRIBUTE_NAMES[513] = ATTR_PRIMITIVEUNITS;
-  ATTRIBUTE_NAMES[514] = ATTR_SYSTEMLANGUAGE;
-  ATTRIBUTE_NAMES[515] = ATTR_STROKE_LINECAP;
-  ATTRIBUTE_NAMES[516] = ATTR_SUBSCRIPTSHIFT;
-  ATTRIBUTE_NAMES[517] = ATTR_STROKE_OPACITY;
-  ATTRIBUTE_NAMES[518] = ATTR_ARIA_DROPEFFECT;
-  ATTRIBUTE_NAMES[519] = ATTR_ARIA_LABELLEDBY;
-  ATTRIBUTE_NAMES[520] = ATTR_ARIA_TEMPLATEID;
-  ATTRIBUTE_NAMES[521] = ATTR_COLOR_RENDERING;
-  ATTRIBUTE_NAMES[522] = ATTR_CONTENTEDITABLE;
-  ATTRIBUTE_NAMES[523] = ATTR_DIFFUSECONSTANT;
-  ATTRIBUTE_NAMES[524] = ATTR_ONDATAAVAILABLE;
-  ATTRIBUTE_NAMES[525] = ATTR_ONCONTROLSELECT;
-  ATTRIBUTE_NAMES[526] = ATTR_IMAGE_RENDERING;
-  ATTRIBUTE_NAMES[527] = ATTR_MEDIUMMATHSPACE;
-  ATTRIBUTE_NAMES[528] = ATTR_TEXT_DECORATION;
-  ATTRIBUTE_NAMES[529] = ATTR_SHAPE_RENDERING;
-  ATTRIBUTE_NAMES[530] = ATTR_STROKE_LINEJOIN;
-  ATTRIBUTE_NAMES[531] = ATTR_REPEAT_TEMPLATE;
-  ATTRIBUTE_NAMES[532] = ATTR_ARIA_DESCRIBEDBY;
-  ATTRIBUTE_NAMES[533] = ATTR_FONT_SIZE_ADJUST;
-  ATTRIBUTE_NAMES[534] = ATTR_KERNELUNITLENGTH;
-  ATTRIBUTE_NAMES[535] = ATTR_ONBEFOREACTIVATE;
-  ATTRIBUTE_NAMES[536] = ATTR_ONPROPERTYCHANGE;
-  ATTRIBUTE_NAMES[537] = ATTR_ONDATASETCHANGED;
-  ATTRIBUTE_NAMES[538] = ATTR_MASKCONTENTUNITS;
-  ATTRIBUTE_NAMES[539] = ATTR_PATTERNTRANSFORM;
-  ATTRIBUTE_NAMES[540] = ATTR_REQUIREDFEATURES;
-  ATTRIBUTE_NAMES[541] = ATTR_RENDERING_INTENT;
-  ATTRIBUTE_NAMES[542] = ATTR_SPECULAREXPONENT;
-  ATTRIBUTE_NAMES[543] = ATTR_SPECULARCONSTANT;
-  ATTRIBUTE_NAMES[544] = ATTR_SUPERSCRIPTSHIFT;
-  ATTRIBUTE_NAMES[545] = ATTR_STROKE_DASHARRAY;
-  ATTRIBUTE_NAMES[546] = ATTR_XCHANNELSELECTOR;
-  ATTRIBUTE_NAMES[547] = ATTR_YCHANNELSELECTOR;
-  ATTRIBUTE_NAMES[548] = ATTR_ARIA_AUTOCOMPLETE;
-  ATTRIBUTE_NAMES[549] = ATTR_ENABLE_BACKGROUND;
-  ATTRIBUTE_NAMES[550] = ATTR_DOMINANT_BASELINE;
-  ATTRIBUTE_NAMES[551] = ATTR_GRADIENTTRANSFORM;
-  ATTRIBUTE_NAMES[552] = ATTR_ONBEFORDEACTIVATE;
-  ATTRIBUTE_NAMES[553] = ATTR_ONDATASETCOMPLETE;
-  ATTRIBUTE_NAMES[554] = ATTR_OVERLINE_POSITION;
-  ATTRIBUTE_NAMES[555] = ATTR_ONBEFOREEDITFOCUS;
-  ATTRIBUTE_NAMES[556] = ATTR_LIMITINGCONEANGLE;
-  ATTRIBUTE_NAMES[557] = ATTR_VERYTHINMATHSPACE;
-  ATTRIBUTE_NAMES[558] = ATTR_STROKE_DASHOFFSET;
-  ATTRIBUTE_NAMES[559] = ATTR_STROKE_MITERLIMIT;
-  ATTRIBUTE_NAMES[560] = ATTR_ALIGNMENT_BASELINE;
-  ATTRIBUTE_NAMES[561] = ATTR_ONREADYSTATECHANGE;
-  ATTRIBUTE_NAMES[562] = ATTR_OVERLINE_THICKNESS;
-  ATTRIBUTE_NAMES[563] = ATTR_UNDERLINE_POSITION;
-  ATTRIBUTE_NAMES[564] = ATTR_VERYTHICKMATHSPACE;
-  ATTRIBUTE_NAMES[565] = ATTR_REQUIREDEXTENSIONS;
-  ATTRIBUTE_NAMES[566] = ATTR_COLOR_INTERPOLATION;
-  ATTRIBUTE_NAMES[567] = ATTR_UNDERLINE_THICKNESS;
-  ATTRIBUTE_NAMES[568] = ATTR_PRESERVEASPECTRATIO;
-  ATTRIBUTE_NAMES[569] = ATTR_PATTERNCONTENTUNITS;
-  ATTRIBUTE_NAMES[570] = ATTR_ARIA_MULTISELECTABLE;
-  ATTRIBUTE_NAMES[571] = ATTR_SCRIPTSIZEMULTIPLIER;
-  ATTRIBUTE_NAMES[572] = ATTR_ARIA_ACTIVEDESCENDANT;
-  ATTRIBUTE_NAMES[573] = ATTR_VERYVERYTHINMATHSPACE;
-  ATTRIBUTE_NAMES[574] = ATTR_VERYVERYTHICKMATHSPACE;
-  ATTRIBUTE_NAMES[575] = ATTR_STRIKETHROUGH_POSITION;
-  ATTRIBUTE_NAMES[576] = ATTR_STRIKETHROUGH_THICKNESS;
-  ATTRIBUTE_NAMES[577] = ATTR_GLYPH_ORIENTATION_VERTICAL;
-  ATTRIBUTE_NAMES[578] = ATTR_COLOR_INTERPOLATION_FILTERS;
-  ATTRIBUTE_NAMES[579] = ATTR_GLYPH_ORIENTATION_HORIZONTAL;
+  ATTRIBUTE_NAMES[304] = ATTR_INTEGRITY;
+  ATTRIBUTE_NAMES[305] = ATTR_ONKEYDOWN;
+  ATTRIBUTE_NAMES[306] = ATTR_ONFOCUSIN;
+  ATTRIBUTE_NAMES[307] = ATTR_ONMOUSEUP;
+  ATTRIBUTE_NAMES[308] = ATTR_INPUTMODE;
+  ATTRIBUTE_NAMES[309] = ATTR_ONROWEXIT;
+  ATTRIBUTE_NAMES[310] = ATTR_MATHCOLOR;
+  ATTRIBUTE_NAMES[311] = ATTR_MASKUNITS;
+  ATTRIBUTE_NAMES[312] = ATTR_MAXLENGTH;
+  ATTRIBUTE_NAMES[313] = ATTR_LINEBREAK;
+  ATTRIBUTE_NAMES[314] = ATTR_TRANSFORM;
+  ATTRIBUTE_NAMES[315] = ATTR_V_HANGING;
+  ATTRIBUTE_NAMES[316] = ATTR_VALUETYPE;
+  ATTRIBUTE_NAMES[317] = ATTR_POINTSATZ;
+  ATTRIBUTE_NAMES[318] = ATTR_POINTSATX;
+  ATTRIBUTE_NAMES[319] = ATTR_POINTSATY;
+  ATTRIBUTE_NAMES[320] = ATTR_SYMMETRIC;
+  ATTRIBUTE_NAMES[321] = ATTR_SCROLLING;
+  ATTRIBUTE_NAMES[322] = ATTR_REPEATDUR;
+  ATTRIBUTE_NAMES[323] = ATTR_SELECTION;
+  ATTRIBUTE_NAMES[324] = ATTR_SEPARATOR;
+  ATTRIBUTE_NAMES[325] = ATTR_XML_SPACE;
+  ATTRIBUTE_NAMES[326] = ATTR_AUTOSUBMIT;
+  ATTRIBUTE_NAMES[327] = ATTR_ALPHABETIC;
+  ATTRIBUTE_NAMES[328] = ATTR_ACTIONTYPE;
+  ATTRIBUTE_NAMES[329] = ATTR_ACCUMULATE;
+  ATTRIBUTE_NAMES[330] = ATTR_ARIA_LEVEL;
+  ATTRIBUTE_NAMES[331] = ATTR_COLUMNSPAN;
+  ATTRIBUTE_NAMES[332] = ATTR_CAP_HEIGHT;
+  ATTRIBUTE_NAMES[333] = ATTR_BACKGROUND;
+  ATTRIBUTE_NAMES[334] = ATTR_GLYPH_NAME;
+  ATTRIBUTE_NAMES[335] = ATTR_GROUPALIGN;
+  ATTRIBUTE_NAMES[336] = ATTR_FONTFAMILY;
+  ATTRIBUTE_NAMES[337] = ATTR_FONTWEIGHT;
+  ATTRIBUTE_NAMES[338] = ATTR_FONT_STYLE;
+  ATTRIBUTE_NAMES[339] = ATTR_KEYSPLINES;
+  ATTRIBUTE_NAMES[340] = ATTR_HTTP_EQUIV;
+  ATTRIBUTE_NAMES[341] = ATTR_ONACTIVATE;
+  ATTRIBUTE_NAMES[342] = ATTR_OCCURRENCE;
+  ATTRIBUTE_NAMES[343] = ATTR_IRRELEVANT;
+  ATTRIBUTE_NAMES[344] = ATTR_ONDBLCLICK;
+  ATTRIBUTE_NAMES[345] = ATTR_ONDRAGDROP;
+  ATTRIBUTE_NAMES[346] = ATTR_ONKEYPRESS;
+  ATTRIBUTE_NAMES[347] = ATTR_ONROWENTER;
+  ATTRIBUTE_NAMES[348] = ATTR_ONDRAGOVER;
+  ATTRIBUTE_NAMES[349] = ATTR_ONFOCUSOUT;
+  ATTRIBUTE_NAMES[350] = ATTR_ONMOUSEOUT;
+  ATTRIBUTE_NAMES[351] = ATTR_NUMOCTAVES;
+  ATTRIBUTE_NAMES[352] = ATTR_MARKER_MID;
+  ATTRIBUTE_NAMES[353] = ATTR_MARKER_END;
+  ATTRIBUTE_NAMES[354] = ATTR_TEXTLENGTH;
+  ATTRIBUTE_NAMES[355] = ATTR_VISIBILITY;
+  ATTRIBUTE_NAMES[356] = ATTR_VIEWTARGET;
+  ATTRIBUTE_NAMES[357] = ATTR_VERT_ADV_Y;
+  ATTRIBUTE_NAMES[358] = ATTR_PATHLENGTH;
+  ATTRIBUTE_NAMES[359] = ATTR_REPEAT_MAX;
+  ATTRIBUTE_NAMES[360] = ATTR_RADIOGROUP;
+  ATTRIBUTE_NAMES[361] = ATTR_STOP_COLOR;
+  ATTRIBUTE_NAMES[362] = ATTR_SEPARATORS;
+  ATTRIBUTE_NAMES[363] = ATTR_REPEAT_MIN;
+  ATTRIBUTE_NAMES[364] = ATTR_ROWSPACING;
+  ATTRIBUTE_NAMES[365] = ATTR_ZOOMANDPAN;
+  ATTRIBUTE_NAMES[366] = ATTR_XLINK_TYPE;
+  ATTRIBUTE_NAMES[367] = ATTR_XLINK_ROLE;
+  ATTRIBUTE_NAMES[368] = ATTR_XLINK_HREF;
+  ATTRIBUTE_NAMES[369] = ATTR_XLINK_SHOW;
+  ATTRIBUTE_NAMES[370] = ATTR_ACCENTUNDER;
+  ATTRIBUTE_NAMES[371] = ATTR_ARIA_SECRET;
+  ATTRIBUTE_NAMES[372] = ATTR_ARIA_ATOMIC;
+  ATTRIBUTE_NAMES[373] = ATTR_ARIA_HIDDEN;
+  ATTRIBUTE_NAMES[374] = ATTR_ARIA_FLOWTO;
+  ATTRIBUTE_NAMES[375] = ATTR_ARABIC_FORM;
+  ATTRIBUTE_NAMES[376] = ATTR_CELLPADDING;
+  ATTRIBUTE_NAMES[377] = ATTR_CELLSPACING;
+  ATTRIBUTE_NAMES[378] = ATTR_COLUMNWIDTH;
+  ATTRIBUTE_NAMES[379] = ATTR_CROSSORIGIN;
+  ATTRIBUTE_NAMES[380] = ATTR_COLUMNALIGN;
+  ATTRIBUTE_NAMES[381] = ATTR_COLUMNLINES;
+  ATTRIBUTE_NAMES[382] = ATTR_CONTEXTMENU;
+  ATTRIBUTE_NAMES[383] = ATTR_BASEPROFILE;
+  ATTRIBUTE_NAMES[384] = ATTR_FONT_FAMILY;
+  ATTRIBUTE_NAMES[385] = ATTR_FRAMEBORDER;
+  ATTRIBUTE_NAMES[386] = ATTR_FILTERUNITS;
+  ATTRIBUTE_NAMES[387] = ATTR_FLOOD_COLOR;
+  ATTRIBUTE_NAMES[388] = ATTR_FONT_WEIGHT;
+  ATTRIBUTE_NAMES[389] = ATTR_HORIZ_ADV_X;
+  ATTRIBUTE_NAMES[390] = ATTR_ONDRAGLEAVE;
+  ATTRIBUTE_NAMES[391] = ATTR_ONMOUSEMOVE;
+  ATTRIBUTE_NAMES[392] = ATTR_ORIENTATION;
+  ATTRIBUTE_NAMES[393] = ATTR_ONMOUSEDOWN;
+  ATTRIBUTE_NAMES[394] = ATTR_ONMOUSEOVER;
+  ATTRIBUTE_NAMES[395] = ATTR_ONDRAGENTER;
+  ATTRIBUTE_NAMES[396] = ATTR_IDEOGRAPHIC;
+  ATTRIBUTE_NAMES[397] = ATTR_ONBEFORECUT;
+  ATTRIBUTE_NAMES[398] = ATTR_ONFORMINPUT;
+  ATTRIBUTE_NAMES[399] = ATTR_ONDRAGSTART;
+  ATTRIBUTE_NAMES[400] = ATTR_ONMOVESTART;
+  ATTRIBUTE_NAMES[401] = ATTR_MARKERUNITS;
+  ATTRIBUTE_NAMES[402] = ATTR_MATHVARIANT;
+  ATTRIBUTE_NAMES[403] = ATTR_MARGINWIDTH;
+  ATTRIBUTE_NAMES[404] = ATTR_MARKERWIDTH;
+  ATTRIBUTE_NAMES[405] = ATTR_TEXT_ANCHOR;
+  ATTRIBUTE_NAMES[406] = ATTR_TABLEVALUES;
+  ATTRIBUTE_NAMES[407] = ATTR_SCRIPTLEVEL;
+  ATTRIBUTE_NAMES[408] = ATTR_REPEATCOUNT;
+  ATTRIBUTE_NAMES[409] = ATTR_STITCHTILES;
+  ATTRIBUTE_NAMES[410] = ATTR_STARTOFFSET;
+  ATTRIBUTE_NAMES[411] = ATTR_SCROLLDELAY;
+  ATTRIBUTE_NAMES[412] = ATTR_XMLNS_XLINK;
+  ATTRIBUTE_NAMES[413] = ATTR_XLINK_TITLE;
+  ATTRIBUTE_NAMES[414] = ATTR_ARIA_INVALID;
+  ATTRIBUTE_NAMES[415] = ATTR_ARIA_PRESSED;
+  ATTRIBUTE_NAMES[416] = ATTR_ARIA_CHECKED;
+  ATTRIBUTE_NAMES[417] = ATTR_AUTOCOMPLETE;
+  ATTRIBUTE_NAMES[418] = ATTR_ARIA_SETSIZE;
+  ATTRIBUTE_NAMES[419] = ATTR_ARIA_CHANNEL;
+  ATTRIBUTE_NAMES[420] = ATTR_EQUALCOLUMNS;
+  ATTRIBUTE_NAMES[421] = ATTR_DISPLAYSTYLE;
+  ATTRIBUTE_NAMES[422] = ATTR_DATAFORMATAS;
+  ATTRIBUTE_NAMES[423] = ATTR_FILL_OPACITY;
+  ATTRIBUTE_NAMES[424] = ATTR_FONT_VARIANT;
+  ATTRIBUTE_NAMES[425] = ATTR_FONT_STRETCH;
+  ATTRIBUTE_NAMES[426] = ATTR_FRAMESPACING;
+  ATTRIBUTE_NAMES[427] = ATTR_KERNELMATRIX;
+  ATTRIBUTE_NAMES[428] = ATTR_ONDEACTIVATE;
+  ATTRIBUTE_NAMES[429] = ATTR_ONROWSDELETE;
+  ATTRIBUTE_NAMES[430] = ATTR_ONMOUSELEAVE;
+  ATTRIBUTE_NAMES[431] = ATTR_ONFORMCHANGE;
+  ATTRIBUTE_NAMES[432] = ATTR_ONCELLCHANGE;
+  ATTRIBUTE_NAMES[433] = ATTR_ONMOUSEWHEEL;
+  ATTRIBUTE_NAMES[434] = ATTR_ONMOUSEENTER;
+  ATTRIBUTE_NAMES[435] = ATTR_ONAFTERPRINT;
+  ATTRIBUTE_NAMES[436] = ATTR_ONBEFORECOPY;
+  ATTRIBUTE_NAMES[437] = ATTR_MARGINHEIGHT;
+  ATTRIBUTE_NAMES[438] = ATTR_MARKERHEIGHT;
+  ATTRIBUTE_NAMES[439] = ATTR_MARKER_START;
+  ATTRIBUTE_NAMES[440] = ATTR_MATHEMATICAL;
+  ATTRIBUTE_NAMES[441] = ATTR_LENGTHADJUST;
+  ATTRIBUTE_NAMES[442] = ATTR_UNSELECTABLE;
+  ATTRIBUTE_NAMES[443] = ATTR_UNICODE_BIDI;
+  ATTRIBUTE_NAMES[444] = ATTR_UNITS_PER_EM;
+  ATTRIBUTE_NAMES[445] = ATTR_WORD_SPACING;
+  ATTRIBUTE_NAMES[446] = ATTR_WRITING_MODE;
+  ATTRIBUTE_NAMES[447] = ATTR_V_ALPHABETIC;
+  ATTRIBUTE_NAMES[448] = ATTR_PATTERNUNITS;
+  ATTRIBUTE_NAMES[449] = ATTR_SPREADMETHOD;
+  ATTRIBUTE_NAMES[450] = ATTR_SURFACESCALE;
+  ATTRIBUTE_NAMES[451] = ATTR_STROKE_WIDTH;
+  ATTRIBUTE_NAMES[452] = ATTR_REPEAT_START;
+  ATTRIBUTE_NAMES[453] = ATTR_STDDEVIATION;
+  ATTRIBUTE_NAMES[454] = ATTR_STOP_OPACITY;
+  ATTRIBUTE_NAMES[455] = ATTR_ARIA_CONTROLS;
+  ATTRIBUTE_NAMES[456] = ATTR_ARIA_HASPOPUP;
+  ATTRIBUTE_NAMES[457] = ATTR_ACCENT_HEIGHT;
+  ATTRIBUTE_NAMES[458] = ATTR_ARIA_VALUENOW;
+  ATTRIBUTE_NAMES[459] = ATTR_ARIA_RELEVANT;
+  ATTRIBUTE_NAMES[460] = ATTR_ARIA_POSINSET;
+  ATTRIBUTE_NAMES[461] = ATTR_ARIA_VALUEMAX;
+  ATTRIBUTE_NAMES[462] = ATTR_ARIA_READONLY;
+  ATTRIBUTE_NAMES[463] = ATTR_ARIA_SELECTED;
+  ATTRIBUTE_NAMES[464] = ATTR_ARIA_REQUIRED;
+  ATTRIBUTE_NAMES[465] = ATTR_ARIA_EXPANDED;
+  ATTRIBUTE_NAMES[466] = ATTR_ARIA_DISABLED;
+  ATTRIBUTE_NAMES[467] = ATTR_ATTRIBUTETYPE;
+  ATTRIBUTE_NAMES[468] = ATTR_ATTRIBUTENAME;
+  ATTRIBUTE_NAMES[469] = ATTR_ARIA_DATATYPE;
+  ATTRIBUTE_NAMES[470] = ATTR_ARIA_VALUEMIN;
+  ATTRIBUTE_NAMES[471] = ATTR_BASEFREQUENCY;
+  ATTRIBUTE_NAMES[472] = ATTR_COLUMNSPACING;
+  ATTRIBUTE_NAMES[473] = ATTR_COLOR_PROFILE;
+  ATTRIBUTE_NAMES[474] = ATTR_CLIPPATHUNITS;
+  ATTRIBUTE_NAMES[475] = ATTR_DEFINITIONURL;
+  ATTRIBUTE_NAMES[476] = ATTR_GRADIENTUNITS;
+  ATTRIBUTE_NAMES[477] = ATTR_FLOOD_OPACITY;
+  ATTRIBUTE_NAMES[478] = ATTR_ONAFTERUPDATE;
+  ATTRIBUTE_NAMES[479] = ATTR_ONERRORUPDATE;
+  ATTRIBUTE_NAMES[480] = ATTR_ONBEFOREPASTE;
+  ATTRIBUTE_NAMES[481] = ATTR_ONLOSECAPTURE;
+  ATTRIBUTE_NAMES[482] = ATTR_ONCONTEXTMENU;
+  ATTRIBUTE_NAMES[483] = ATTR_ONSELECTSTART;
+  ATTRIBUTE_NAMES[484] = ATTR_ONBEFOREPRINT;
+  ATTRIBUTE_NAMES[485] = ATTR_MOVABLELIMITS;
+  ATTRIBUTE_NAMES[486] = ATTR_LINETHICKNESS;
+  ATTRIBUTE_NAMES[487] = ATTR_UNICODE_RANGE;
+  ATTRIBUTE_NAMES[488] = ATTR_THINMATHSPACE;
+  ATTRIBUTE_NAMES[489] = ATTR_VERT_ORIGIN_X;
+  ATTRIBUTE_NAMES[490] = ATTR_VERT_ORIGIN_Y;
+  ATTRIBUTE_NAMES[491] = ATTR_V_IDEOGRAPHIC;
+  ATTRIBUTE_NAMES[492] = ATTR_PRESERVEALPHA;
+  ATTRIBUTE_NAMES[493] = ATTR_SCRIPTMINSIZE;
+  ATTRIBUTE_NAMES[494] = ATTR_SPECIFICATION;
+  ATTRIBUTE_NAMES[495] = ATTR_XLINK_ACTUATE;
+  ATTRIBUTE_NAMES[496] = ATTR_XLINK_ARCROLE;
+  ATTRIBUTE_NAMES[497] = ATTR_ACCEPT_CHARSET;
+  ATTRIBUTE_NAMES[498] = ATTR_ALIGNMENTSCOPE;
+  ATTRIBUTE_NAMES[499] = ATTR_ARIA_MULTILINE;
+  ATTRIBUTE_NAMES[500] = ATTR_BASELINE_SHIFT;
+  ATTRIBUTE_NAMES[501] = ATTR_HORIZ_ORIGIN_X;
+  ATTRIBUTE_NAMES[502] = ATTR_HORIZ_ORIGIN_Y;
+  ATTRIBUTE_NAMES[503] = ATTR_ONBEFOREUPDATE;
+  ATTRIBUTE_NAMES[504] = ATTR_ONFILTERCHANGE;
+  ATTRIBUTE_NAMES[505] = ATTR_ONROWSINSERTED;
+  ATTRIBUTE_NAMES[506] = ATTR_ONBEFOREUNLOAD;
+  ATTRIBUTE_NAMES[507] = ATTR_MATHBACKGROUND;
+  ATTRIBUTE_NAMES[508] = ATTR_LETTER_SPACING;
+  ATTRIBUTE_NAMES[509] = ATTR_LIGHTING_COLOR;
+  ATTRIBUTE_NAMES[510] = ATTR_THICKMATHSPACE;
+  ATTRIBUTE_NAMES[511] = ATTR_TEXT_RENDERING;
+  ATTRIBUTE_NAMES[512] = ATTR_V_MATHEMATICAL;
+  ATTRIBUTE_NAMES[513] = ATTR_POINTER_EVENTS;
+  ATTRIBUTE_NAMES[514] = ATTR_PRIMITIVEUNITS;
+  ATTRIBUTE_NAMES[515] = ATTR_SYSTEMLANGUAGE;
+  ATTRIBUTE_NAMES[516] = ATTR_STROKE_LINECAP;
+  ATTRIBUTE_NAMES[517] = ATTR_SUBSCRIPTSHIFT;
+  ATTRIBUTE_NAMES[518] = ATTR_STROKE_OPACITY;
+  ATTRIBUTE_NAMES[519] = ATTR_ARIA_DROPEFFECT;
+  ATTRIBUTE_NAMES[520] = ATTR_ARIA_LABELLEDBY;
+  ATTRIBUTE_NAMES[521] = ATTR_ARIA_TEMPLATEID;
+  ATTRIBUTE_NAMES[522] = ATTR_COLOR_RENDERING;
+  ATTRIBUTE_NAMES[523] = ATTR_CONTENTEDITABLE;
+  ATTRIBUTE_NAMES[524] = ATTR_DIFFUSECONSTANT;
+  ATTRIBUTE_NAMES[525] = ATTR_ONDATAAVAILABLE;
+  ATTRIBUTE_NAMES[526] = ATTR_ONCONTROLSELECT;
+  ATTRIBUTE_NAMES[527] = ATTR_IMAGE_RENDERING;
+  ATTRIBUTE_NAMES[528] = ATTR_MEDIUMMATHSPACE;
+  ATTRIBUTE_NAMES[529] = ATTR_TEXT_DECORATION;
+  ATTRIBUTE_NAMES[530] = ATTR_SHAPE_RENDERING;
+  ATTRIBUTE_NAMES[531] = ATTR_STROKE_LINEJOIN;
+  ATTRIBUTE_NAMES[532] = ATTR_REPEAT_TEMPLATE;
+  ATTRIBUTE_NAMES[533] = ATTR_ARIA_DESCRIBEDBY;
+  ATTRIBUTE_NAMES[534] = ATTR_FONT_SIZE_ADJUST;
+  ATTRIBUTE_NAMES[535] = ATTR_KERNELUNITLENGTH;
+  ATTRIBUTE_NAMES[536] = ATTR_ONBEFOREACTIVATE;
+  ATTRIBUTE_NAMES[537] = ATTR_ONPROPERTYCHANGE;
+  ATTRIBUTE_NAMES[538] = ATTR_ONDATASETCHANGED;
+  ATTRIBUTE_NAMES[539] = ATTR_MASKCONTENTUNITS;
+  ATTRIBUTE_NAMES[540] = ATTR_PATTERNTRANSFORM;
+  ATTRIBUTE_NAMES[541] = ATTR_REQUIREDFEATURES;
+  ATTRIBUTE_NAMES[542] = ATTR_RENDERING_INTENT;
+  ATTRIBUTE_NAMES[543] = ATTR_SPECULAREXPONENT;
+  ATTRIBUTE_NAMES[544] = ATTR_SPECULARCONSTANT;
+  ATTRIBUTE_NAMES[545] = ATTR_SUPERSCRIPTSHIFT;
+  ATTRIBUTE_NAMES[546] = ATTR_STROKE_DASHARRAY;
+  ATTRIBUTE_NAMES[547] = ATTR_XCHANNELSELECTOR;
+  ATTRIBUTE_NAMES[548] = ATTR_YCHANNELSELECTOR;
+  ATTRIBUTE_NAMES[549] = ATTR_ARIA_AUTOCOMPLETE;
+  ATTRIBUTE_NAMES[550] = ATTR_ENABLE_BACKGROUND;
+  ATTRIBUTE_NAMES[551] = ATTR_DOMINANT_BASELINE;
+  ATTRIBUTE_NAMES[552] = ATTR_GRADIENTTRANSFORM;
+  ATTRIBUTE_NAMES[553] = ATTR_ONBEFORDEACTIVATE;
+  ATTRIBUTE_NAMES[554] = ATTR_ONDATASETCOMPLETE;
+  ATTRIBUTE_NAMES[555] = ATTR_OVERLINE_POSITION;
+  ATTRIBUTE_NAMES[556] = ATTR_ONBEFOREEDITFOCUS;
+  ATTRIBUTE_NAMES[557] = ATTR_LIMITINGCONEANGLE;
+  ATTRIBUTE_NAMES[558] = ATTR_VERYTHINMATHSPACE;
+  ATTRIBUTE_NAMES[559] = ATTR_STROKE_DASHOFFSET;
+  ATTRIBUTE_NAMES[560] = ATTR_STROKE_MITERLIMIT;
+  ATTRIBUTE_NAMES[561] = ATTR_ALIGNMENT_BASELINE;
+  ATTRIBUTE_NAMES[562] = ATTR_ONREADYSTATECHANGE;
+  ATTRIBUTE_NAMES[563] = ATTR_OVERLINE_THICKNESS;
+  ATTRIBUTE_NAMES[564] = ATTR_UNDERLINE_POSITION;
+  ATTRIBUTE_NAMES[565] = ATTR_VERYTHICKMATHSPACE;
+  ATTRIBUTE_NAMES[566] = ATTR_REQUIREDEXTENSIONS;
+  ATTRIBUTE_NAMES[567] = ATTR_COLOR_INTERPOLATION;
+  ATTRIBUTE_NAMES[568] = ATTR_UNDERLINE_THICKNESS;
+  ATTRIBUTE_NAMES[569] = ATTR_PRESERVEASPECTRATIO;
+  ATTRIBUTE_NAMES[570] = ATTR_PATTERNCONTENTUNITS;
+  ATTRIBUTE_NAMES[571] = ATTR_ARIA_MULTISELECTABLE;
+  ATTRIBUTE_NAMES[572] = ATTR_SCRIPTSIZEMULTIPLIER;
+  ATTRIBUTE_NAMES[573] = ATTR_ARIA_ACTIVEDESCENDANT;
+  ATTRIBUTE_NAMES[574] = ATTR_VERYVERYTHINMATHSPACE;
+  ATTRIBUTE_NAMES[575] = ATTR_VERYVERYTHICKMATHSPACE;
+  ATTRIBUTE_NAMES[576] = ATTR_STRIKETHROUGH_POSITION;
+  ATTRIBUTE_NAMES[577] = ATTR_STRIKETHROUGH_THICKNESS;
+  ATTRIBUTE_NAMES[578] = ATTR_GLYPH_ORIENTATION_VERTICAL;
+  ATTRIBUTE_NAMES[579] = ATTR_COLOR_INTERPOLATION_FILTERS;
+  ATTRIBUTE_NAMES[580] = ATTR_GLYPH_ORIENTATION_HORIZONTAL;
 }
 
 void
 nsHtml5AttributeName::releaseStatics()
 {
   delete[] ALL_NO_NS;
   delete[] XMLNS_NS;
   delete[] XML_NS;
@@ -2286,16 +2289,17 @@ nsHtml5AttributeName::releaseStatics()
   delete ATTR_KEYSYSTEM;
   delete ATTR_KEYPOINTS;
   delete ATTR_HIDEFOCUS;
   delete ATTR_ONMESSAGE;
   delete ATTR_INTERCEPT;
   delete ATTR_ONDRAGEND;
   delete ATTR_ONMOVEEND;
   delete ATTR_ONINVALID;
+  delete ATTR_INTEGRITY;
   delete ATTR_ONKEYDOWN;
   delete ATTR_ONFOCUSIN;
   delete ATTR_ONMOUSEUP;
   delete ATTR_INPUTMODE;
   delete ATTR_ONROWEXIT;
   delete ATTR_MATHCOLOR;
   delete ATTR_MASKUNITS;
   delete ATTR_MAXLENGTH;
--- a/parser/html/nsHtml5AttributeName.h
+++ b/parser/html/nsHtml5AttributeName.h
@@ -391,16 +391,17 @@ class nsHtml5AttributeName
     static nsHtml5AttributeName* ATTR_KEYSYSTEM;
     static nsHtml5AttributeName* ATTR_KEYPOINTS;
     static nsHtml5AttributeName* ATTR_HIDEFOCUS;
     static nsHtml5AttributeName* ATTR_ONMESSAGE;
     static nsHtml5AttributeName* ATTR_INTERCEPT;
     static nsHtml5AttributeName* ATTR_ONDRAGEND;
     static nsHtml5AttributeName* ATTR_ONMOVEEND;
     static nsHtml5AttributeName* ATTR_ONINVALID;
+    static nsHtml5AttributeName* ATTR_INTEGRITY;
     static nsHtml5AttributeName* ATTR_ONKEYDOWN;
     static nsHtml5AttributeName* ATTR_ONFOCUSIN;
     static nsHtml5AttributeName* ATTR_ONMOUSEUP;
     static nsHtml5AttributeName* ATTR_INPUTMODE;
     static nsHtml5AttributeName* ATTR_ONROWEXIT;
     static nsHtml5AttributeName* ATTR_MATHCOLOR;
     static nsHtml5AttributeName* ATTR_MASKUNITS;
     static nsHtml5AttributeName* ATTR_MAXLENGTH;
--- a/parser/html/nsHtml5TreeBuilder.cpp
+++ b/parser/html/nsHtml5TreeBuilder.cpp
@@ -3207,25 +3207,21 @@ nsHtml5TreeBuilder::isSecondOnStackBody(
   return currentPtr >= 1 && stack[1]->getGroup() == NS_HTML5TREE_BUILDER_BODY;
 }
 
 void 
 nsHtml5TreeBuilder::documentModeInternal(nsHtml5DocumentMode m, nsString* publicIdentifier, nsString* systemIdentifier, bool html4SpecificAdditionalErrorChecks)
 {
   if (isSrcdocDocument) {
     quirks = false;
-    if (this) {
-      this->documentMode(STANDARDS_MODE);
-    }
+    this->documentMode(STANDARDS_MODE);
     return;
   }
   quirks = (m == QUIRKS_MODE);
-  if (this) {
-    this->documentMode(m);
-  }
+  this->documentMode(m);
 }
 
 bool 
 nsHtml5TreeBuilder::isAlmostStandards(nsString* publicIdentifier, nsString* systemIdentifier)
 {
   if (nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString("-//w3c//dtd xhtml 1.0 transitional//en", publicIdentifier)) {
     return true;
   }
--- a/services/healthreport/healthreporter.jsm
+++ b/services/healthreport/healthreporter.jsm
@@ -333,19 +333,20 @@ function AbstractHealthReporter(branch, 
 
   this._lastDailyDate = null;
 
   // Yes, this will probably run concurrently with remaining constructor work.
   let hasFirstRun = this._prefs.get("service.firstRun", false);
   this._initHistogram = hasFirstRun ? TELEMETRY_INIT : TELEMETRY_INIT_FIRSTRUN;
   this._dbOpenHistogram = hasFirstRun ? TELEMETRY_DB_OPEN : TELEMETRY_DB_OPEN_FIRSTRUN;
 
-  // This is set to the name of the provider that we are currently shutting down, if any.
-  // It is used for AsyncShutdownTimeout diagnostics.
+  // This is set to the name for the provider that we are currently initializing
+  // or shutting down, if any. This is used for AsyncShutdownTimeout diagnostics.
   this._currentProviderInShutdown = null;
+  this._currentProviderInInit = null;
 }
 
 AbstractHealthReporter.prototype = Object.freeze({
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
 
   /**
    * Whether the service is fully initialized and running.
    *
@@ -408,16 +409,17 @@ AbstractHealthReporter.prototype = Objec
             shutdownRequested: this._shutdownRequested,
             initializeHadError: this._initializeHadError,
             providerManagerInProgress: this._providerManagerInProgress,
             storageInProgress: this._storageInProgress,
             hasProviderManager: !!this._providerManager,
             hasStorage: !!this._storage,
             shutdownComplete: this._shutdownComplete,
             currentProviderInShutdown: this._currentProviderInShutdown,
+            currentProviderInInit: this._currentProviderInInit,
           }));
 
       try {
         this._storageInProgress = true;
         TelemetryStopwatch.start(this._dbOpenHistogram, this);
         let storage = yield Metrics.Storage(this._dbName);
         TelemetryStopwatch.finish(this._dbOpenHistogram, this);
         yield this._onStorageCreated();
@@ -495,18 +497,20 @@ AbstractHealthReporter.prototype = Objec
     this._providerManager = new Metrics.ProviderManager(this._storage);
     this._providerManager.onProviderError = this._recordError.bind(this);
     this._providerManager.onProviderInit = this._initProvider.bind(this);
     this._providerManagerInProgress = true;
 
     let catString = this._prefs.get("service.providerCategories") || "";
     if (catString.length) {
       for (let category of catString.split(",")) {
-        yield this._providerManager.registerProvidersFromCategoryManager(category);
+        yield this._providerManager.registerProvidersFromCategoryManager(category,
+                     providerName => this._currentProviderInInit = providerName);
       }
+      this._currentProviderInInit = null;
     }
   }),
 
   _onProviderManagerInitialized: function () {
     TelemetryStopwatch.finish(this._initHistogram, this);
     delete this._initHistogram;
     this._log.debug("Provider manager initialized.");
     this._providerManagerInProgress = false;
--- a/services/metrics/providermanager.jsm
+++ b/services/metrics/providermanager.jsm
@@ -96,53 +96,58 @@ this.ProviderManager.prototype = Object.
    *
    *   let reporter = getHealthReporter("healthreport.");
    *   reporter.registerProvidersFromCategoryManager("healthreport-js-provider-default");
    *
    * If the category has no defined members, this call has no effect, and no error is raised.
    *
    * @param category
    *        (string) Name of category from which to query and load.
+   * @param providerDiagnostic
+   *        (function) Optional, called with the name of the provider currently being initialized.
    * @return a newly spawned Task.
    */
-  registerProvidersFromCategoryManager: function (category) {
+  registerProvidersFromCategoryManager: function (category, providerDiagnostic) {
     this._log.info("Registering providers from category: " + category);
     let cm = Cc["@mozilla.org/categorymanager;1"]
                .getService(Ci.nsICategoryManager);
 
-    let promises = [];
+    let promiseList = [];
     let enumerator = cm.enumerateCategory(category);
     while (enumerator.hasMoreElements()) {
       let entry = enumerator.getNext()
                             .QueryInterface(Ci.nsISupportsCString)
                             .toString();
 
       let uri = cm.getCategoryEntry(category, entry);
       this._log.info("Attempting to load provider from category manager: " +
                      entry + " from " + uri);
 
       try {
         let ns = {};
         Cu.import(uri, ns);
 
         let promise = this.registerProviderFromType(ns[entry]);
         if (promise) {
-          promises.push(promise);
+          promiseList.push({name: entry, promise: promise});
         }
       } catch (ex) {
         this._recordProviderError(entry,
                                   "Error registering provider from category manager",
                                   ex);
         continue;
       }
     }
 
-    return Task.spawn(function wait() {
-      for (let promise of promises) {
-        yield promise;
+    return Task.spawn(function* wait() {
+      for (let entry of promiseList) {
+        if (providerDiagnostic) {
+          providerDiagnostic(entry.name);
+        }
+        yield entry.promise;
       }
     });
   },
 
   /**
    * Registers a `MetricsProvider` with this manager.
    *
    * Once a `MetricsProvider` is registered, data will be collected from it
--- a/testing/marionette/client/marionette/geckoinstance.py
+++ b/testing/marionette/client/marionette/geckoinstance.py
@@ -47,16 +47,25 @@ class GeckoInstance(object):
         self.symbols_path = symbols_path
         self.gecko_log = gecko_log
 
     def start(self):
         profile_args = {"preferences": deepcopy(self.required_prefs)}
         profile_args["preferences"]["marionette.defaultPrefs.port"] = self.marionette_port
         if self.prefs:
             profile_args["preferences"].update(self.prefs)
+        if '-jsdebugger' in self.app_args:
+            profile_args["preferences"].update({
+                "devtools.browsertoolbox.panel": "jsdebugger",
+                "devtools.debugger.remote-enabled": True,
+                "devtools.debugger.chrome-enabled": True,
+                "devtools.chrome.enabled": True,
+                "devtools.debugger.prompt-connection": False,
+                "marionette.debugging.clicktostart": True,
+            })
 
         if hasattr(self, "profile_path") and self.profile is None:
             if not self.profile_path:
                 profile_args["restore"] = False
                 self.profile = Profile(**profile_args)
             else:
                 profile_args["path_from"] = self.profile_path
                 self.profile = Profile.clone(**profile_args)
--- a/testing/marionette/client/marionette/runner/base.py
+++ b/testing/marionette/client/marionette/runner/base.py
@@ -385,17 +385,21 @@ class BaseMarionetteOptions(OptionParser
                              " given the format gecko-(timestamp).log. If it is"
                              " a file, if will be used directly. '-' may be passed"
                              " to write to stdout. Default: './gecko.log'")
         self.add_option('--logger-name',
                         dest='logger_name',
                         action='store',
                         default='Marionette-based Tests',
                         help='Define the name to associate with the logger used')
-
+        self.add_option('--jsdebugger',
+                        dest='jsdebugger',
+                        action='store_true',
+                        default=False,
+                        help='Enable the jsdebugger for marionette javascript.')
 
     def parse_args(self, args=None, values=None):
         options, tests = OptionParser.parse_args(self, args, values)
         for handler in self.parse_args_handlers:
             handler(options, tests, args, values)
 
         return (options, tests)
 
@@ -435,16 +439,19 @@ class BaseMarionetteOptions(OptionParser
             self.error('You must specify how many chunks to split the tests into.')
 
         if options.total_chunks is not None:
             if not 1 <= options.total_chunks:
                 self.error('Total chunks must be greater than 1.')
             if not 1 <= options.this_chunk <= options.total_chunks:
                 self.error('Chunk to run must be between 1 and %s.' % options.total_chunks)
 
+        if options.jsdebugger:
+            options.app_args.append('-jsdebugger')
+
         for handler in self.verify_usage_handlers:
             handler(options, tests)
 
         return (options, tests)
 
 
 class BaseMarionetteTestRunner(object):
 
--- a/testing/marionette/mach_commands.py
+++ b/testing/marionette/mach_commands.py
@@ -125,13 +125,15 @@ class MachCommands(MachCommandBase):
         help='host:port of running Gecko instance to connect to.')
     @CommandArgument('--type',
         default='browser',
         help='Test type, usually one of: browser, b2g, b2g-qemu.')
     @CommandArgument('--profile',
         help='Path to gecko profile to use.')
     @CommandArgument('--gecko-log',
         help='Path to gecko log file, or "-" for stdout.')
+    @CommandArgument('--jsdebugger', action='store_true',
+        help='Enable the jsdebugger for marionette javascript.')
     @CommandArgument('tests', nargs='*', metavar='TESTS',
         help='Path to test(s) to run.')
     def run_marionette_test(self, tests, **kwargs):
         binary = self.get_binary_path('app')
         return run_marionette(tests, binary=binary, topsrcdir=self.topsrcdir, **kwargs)
--- a/testing/marionette/marionette-server.js
+++ b/testing/marionette/marionette-server.js
@@ -606,17 +606,34 @@ MarionetteServerConnection.prototype = {
             return;
           }
           win.removeEventListener("load", listener);
           waitForWindow.call(this);
         };
         win.addEventListener("load", listener, true);
       }
       else {
-        this.startBrowser(win, true);
+        let clickToStart;
+        try {
+          clickToStart = Services.prefs.getBoolPref('marionette.debugging.clicktostart');
+          Services.prefs.setBoolPref('marionette.debugging.clicktostart', false);
+        } catch (e) { }
+        if (clickToStart && (appName != "B2G")) {
+          let nbox = win.gBrowser.getNotificationBox();
+          let message = "Starting marionette tests with chrome debugging enabled...";
+          let buttons = [{
+            label: "Start execution of marionette tests",
+            accessKey: 'S',
+            callback: () => this.startBrowser(win, true)
+          }];
+          nbox.appendNotification(message, null, null,
+                                  nbox.PRIORITY_WARNING_MEDIUM, buttons);
+        } else {
+          this.startBrowser(win, true);
+        }
       }
     }
 
     function runSessionStart() {
       if (!Services.prefs.getBoolPref("marionette.contentListener")) {
         waitForWindow.call(this);
       }
       else if ((appName != "Firefox") && (this.curBrowser === null)) {
--- a/testing/mochitest/mochitest_options.py
+++ b/testing/mochitest/mochitest_options.py
@@ -804,17 +804,17 @@ class B2GOptions(MochitestOptions):
         defaults["httpPort"] = DEFAULT_PORTS['http']
         defaults["sslPort"] = DEFAULT_PORTS['https']
         defaults["logFile"] = "mochitest.log"
         defaults["autorun"] = True
         defaults["closeWhenDone"] = True
         defaults["testPath"] = ""
         defaults["extensionsToExclude"] = ["specialpowers"]
         # See dependencies of bug 1038943.
-        defaults["defaultLeakThreshold"] = 5180
+        defaults["defaultLeakThreshold"] = 5308
         self.set_defaults(**defaults)
 
     def verifyRemoteOptions(self, options):
         if options.remoteWebServer == None:
             if os.name != "nt":
                 options.remoteWebServer = moznetwork.get_ip()
             else:
                 self.error("You must specify a --remote-webserver=<ip address>")
--- a/testing/xpcshell/node-http2/lib/protocol/stream.js
+++ b/testing/xpcshell/node-http2/lib/protocol/stream.js
@@ -438,16 +438,18 @@ Stream.prototype._transition = function 
       if (HEADERS) {
         this._setState('OPEN');
         if (frame.flags.END_STREAM) {
           this._setState(sending ? 'HALF_CLOSED_LOCAL' : 'HALF_CLOSED_REMOTE');
         }
         this._initiated = sending;
       } else if (sending && RST_STREAM) {
         this._setState('CLOSED');
+      } else if (PRIORITY) {
+        /* No state change */
       } else {
         connectionError = 'PROTOCOL_ERROR';
       }
       break;
 
     // A stream in the **reserved (local)** state is one that has been promised by sending a
     // PUSH_PROMISE frame.
     //
--- a/widget/VsyncDispatcher.cpp
+++ b/widget/VsyncDispatcher.cpp
@@ -2,116 +2,72 @@
 /* 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 "VsyncDispatcher.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/layers/CompositorParent.h"
 #include "gfxPrefs.h"
+#include "gfxPlatform.h"
+#include "VsyncSource.h"
 
 #ifdef MOZ_ENABLE_PROFILER_SPS
 #include "GeckoProfiler.h"
 #include "ProfilerMarkers.h"
 #endif
 
 #ifdef MOZ_WIDGET_GONK
 #include "GeckoTouchDispatcher.h"
 #endif
 
 using namespace mozilla::layers;
 
 namespace mozilla {
 
-StaticRefPtr<VsyncDispatcher> sVsyncDispatcher;
-
-/*static*/ VsyncDispatcher*
-VsyncDispatcher::GetInstance()
-{
-  if (!sVsyncDispatcher) {
-    sVsyncDispatcher = new VsyncDispatcher();
-    ClearOnShutdown(&sVsyncDispatcher);
-  }
-
-  return sVsyncDispatcher;
-}
-
 VsyncDispatcher::VsyncDispatcher()
   : mCompositorObserverLock("CompositorObserverLock")
 {
-
+  MOZ_ASSERT(XRE_IsParentProcess());
+  gfxPlatform::GetPlatform()->GetHardwareVsync()->AddVsyncDispatcher(this);
 }
 
 VsyncDispatcher::~VsyncDispatcher()
 {
-  MutexAutoLock lock(mCompositorObserverLock);
-  mCompositorObservers.Clear();
-}
-
-void
-VsyncDispatcher::SetVsyncSource(VsyncSource* aVsyncSource)
-{
-  mVsyncSource = aVsyncSource;
-}
-
-void
-VsyncDispatcher::DispatchTouchEvents(bool aNotifiedCompositors, TimeStamp aVsyncTime)
-{
-  // Touch events can sometimes start a composite, so make sure we dispatch touches
-  // even if we don't composite
-#ifdef MOZ_WIDGET_GONK
-  if (!aNotifiedCompositors && gfxPrefs::TouchResampling()) {
-    GeckoTouchDispatcher::NotifyVsync(aVsyncTime);
-  }
-#endif
+  // We auto remove this vsync dispatcher from the vsync source in the nsBaseWidget
+  MOZ_ASSERT(NS_IsMainThread());
 }
 
 void
 VsyncDispatcher::NotifyVsync(TimeStamp aVsyncTimestamp)
 {
-  bool notifiedCompositors = false;
+  // In hardware vsync thread
 #ifdef MOZ_ENABLE_PROFILER_SPS
     if (profiler_is_active()) {
         CompositorParent::PostInsertVsyncProfilerMarker(aVsyncTimestamp);
     }
 #endif
 
-  if (gfxPrefs::VsyncAlignedCompositor()) {
-    MutexAutoLock lock(mCompositorObserverLock);
-    notifiedCompositors = NotifyVsyncObservers(aVsyncTimestamp, mCompositorObservers);
-  }
-
-  DispatchTouchEvents(notifiedCompositors, aVsyncTimestamp);
-}
-
-bool
-VsyncDispatcher::NotifyVsyncObservers(TimeStamp aVsyncTimestamp, nsTArray<nsRefPtr<VsyncObserver>>& aObservers)
-{
-  // Callers should lock the respective lock for the aObservers before calling this function
-  for (size_t i = 0; i < aObservers.Length(); i++) {
-    aObservers[i]->NotifyVsync(aVsyncTimestamp);
- }
- return !aObservers.IsEmpty();
-}
-
-void
-VsyncDispatcher::AddCompositorVsyncObserver(VsyncObserver* aVsyncObserver)
-{
-  MOZ_ASSERT(CompositorParent::IsInCompositorThread());
   MutexAutoLock lock(mCompositorObserverLock);
-  if (!mCompositorObservers.Contains(aVsyncObserver)) {
-    mCompositorObservers.AppendElement(aVsyncObserver);
+  if (gfxPrefs::VsyncAlignedCompositor() && mCompositorVsyncObserver) {
+    mCompositorVsyncObserver->NotifyVsync(aVsyncTimestamp);
   }
 }
 
 void
-VsyncDispatcher::RemoveCompositorVsyncObserver(VsyncObserver* aVsyncObserver)
+VsyncDispatcher::SetCompositorVsyncObserver(VsyncObserver* aVsyncObserver)
 {
-  MOZ_ASSERT(CompositorParent::IsInCompositorThread() || NS_IsMainThread());
+  MOZ_ASSERT(CompositorParent::IsInCompositorThread());
   MutexAutoLock lock(mCompositorObserverLock);
-  if (mCompositorObservers.Contains(aVsyncObserver)) {
-    mCompositorObservers.RemoveElement(aVsyncObserver);
-  } else {
-    NS_WARNING("Could not delete a compositor vsync observer\n");
-  }
+  mCompositorVsyncObserver = aVsyncObserver;
 }
 
+void
+VsyncDispatcher::Shutdown()
+{
+  // Need to explicitly remove VsyncDispatcher when the nsBaseWidget shuts down.
+  // Otherwise, we would get dead vsync notifications between when the nsBaseWidget
+  // shuts down and the CompositorParent shuts down.
+  MOZ_ASSERT(XRE_IsParentProcess());
+  MOZ_ASSERT(NS_IsMainThread());
+  gfxPlatform::GetPlatform()->GetHardwareVsync()->RemoveVsyncDispatcher(this);
+}
 } // namespace mozilla
--- a/widget/VsyncDispatcher.h
+++ b/widget/VsyncDispatcher.h
@@ -7,42 +7,27 @@
 #define mozilla_widget_VsyncDispatcher_h
 
 #include "base/message_loop.h"
 #include "mozilla/Mutex.h"
 #include "nsISupportsImpl.h"
 #include "nsTArray.h"
 #include "ThreadSafeRefcountingWithMainThreadDestruction.h"
 
-class MessageLoop;
-
 namespace mozilla {
 class TimeStamp;
 
 namespace layers {
 class CompositorVsyncObserver;
 }
 
-// Controls how and when to enable/disable vsync.
-class VsyncSource
-{
-public:
-  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VsyncSource)
-  virtual void EnableVsync() = 0;
-  virtual void DisableVsync() = 0;
-  virtual bool IsVsyncEnabled() = 0;
-
-protected:
-  virtual ~VsyncSource() {}
-}; // VsyncSource
-
 class VsyncObserver
 {
   // Must be destroyed on main thread since the compositor is as well
-  NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(VsyncObserver)
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VsyncObserver)
 
 public:
   // The method called when a vsync occurs. Return true if some work was done.
   // Vsync notifications will occur on the hardware vsync thread
   virtual bool NotifyVsync(TimeStamp aVsyncTimestamp) = 0;
 
 protected:
   VsyncObserver() {}
@@ -50,39 +35,31 @@ protected:
 }; // VsyncObserver
 
 // VsyncDispatcher is used to dispatch vsync events to the registered observers.
 class VsyncDispatcher
 {
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VsyncDispatcher)
 
 public:
-  static VsyncDispatcher* GetInstance();
+  VsyncDispatcher();
+
   // Called on the vsync thread when a hardware vsync occurs
   // The aVsyncTimestamp can mean different things depending on the platform:
   // b2g - The vsync timestamp of the previous frame that was just displayed
   // OSX - The vsync timestamp of the upcoming frame
   // TODO: Windows / Linux. DOCUMENT THIS WHEN IMPLEMENTING ON THOSE PLATFORMS
   // Android: TODO
   void NotifyVsync(TimeStamp aVsyncTimestamp);
-  void SetVsyncSource(VsyncSource* aVsyncSource);
 
   // Compositor vsync observers must be added/removed on the compositor thread
-  void AddCompositorVsyncObserver(VsyncObserver* aVsyncObserver);
-  void RemoveCompositorVsyncObserver(VsyncObserver* aVsyncObserver);
+  void SetCompositorVsyncObserver(VsyncObserver* aVsyncObserver);
+  void Shutdown();
 
 private:
-  VsyncDispatcher();
   virtual ~VsyncDispatcher();
-  void DispatchTouchEvents(bool aNotifiedCompositors, TimeStamp aVsyncTime);
-
-  // Called on the vsync thread. Returns true if observers were notified
-  bool NotifyVsyncObservers(TimeStamp aVsyncTimestamp, nsTArray<nsRefPtr<VsyncObserver>>& aObservers);
-
-  // Can have multiple compositors. On desktop, this is 1 compositor per window
   Mutex mCompositorObserverLock;
-  nsTArray<nsRefPtr<VsyncObserver>> mCompositorObservers;
-  nsRefPtr<VsyncSource> mVsyncSource;
+  nsRefPtr<VsyncObserver> mCompositorVsyncObserver;
 }; // VsyncDispatcher
 
 } // namespace mozilla
 
 #endif // __mozilla_widget_VsyncDispatcher_h
--- a/widget/gonk/GeckoTouchDispatcher.cpp
+++ b/widget/gonk/GeckoTouchDispatcher.cpp
@@ -24,16 +24,17 @@
 #include "gfxPrefs.h"
 #include "libui/Input.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/TouchEvents.h"
 #include "mozilla/dom/Touch.h"
+#include "mozilla/layers/CompositorParent.h"
 #include "nsAppShell.h"
 #include "nsDebug.h"
 #include "nsThreadUtils.h"
 #include "nsWindow.h"
 #include <sys/types.h>
 #include <unistd.h>
 #include <utils/Timers.h>
 
@@ -110,21 +111,33 @@ public:
     return NS_OK;
   }
 
 private:
   nsRefPtr<GeckoTouchDispatcher> mTouchDispatcher;
   MultiTouchInput mTouch;
 };
 
+/* static */ void
+GeckoTouchDispatcher::SetCompositorVsyncObserver(mozilla::layers::CompositorVsyncObserver *aObserver)
+{
+  MOZ_ASSERT(sTouchDispatcher != nullptr);
+  MOZ_ASSERT(NS_IsMainThread());
+  // We assume on b2g that there is only 1 CompositorParent
+  MOZ_ASSERT(sTouchDispatcher->mCompositorVsyncObserver == nullptr);
+  if (gfxPrefs::TouchResampling()) {
+    sTouchDispatcher->mCompositorVsyncObserver = aObserver;
+  }
+}
+
 // Timestamp is in nanoseconds
 /* static */ bool
 GeckoTouchDispatcher::NotifyVsync(TimeStamp aVsyncTimestamp)
 {
-  if (sTouchDispatcher == nullptr) {
+  if ((sTouchDispatcher == nullptr) || !gfxPrefs::TouchResampling()) {
     return false;
   }
 
   MOZ_ASSERT(sTouchDispatcher->mResamplingEnabled);
   bool haveTouchData = false;
   {
     MutexAutoLock lock(sTouchDispatcher->mTouchQueueLock);
     haveTouchData = !sTouchDispatcher->mTouchMoveEvents.empty();
@@ -136,16 +149,20 @@ GeckoTouchDispatcher::NotifyVsync(TimeSt
 
   return haveTouchData;
 }
 
 // Touch data timestamps are in milliseconds, aEventTime is in nanoseconds
 void
 GeckoTouchDispatcher::NotifyTouch(MultiTouchInput& aTouch, TimeStamp aEventTime)
 {
+  if (aTouch.mType == MultiTouchInput::MULTITOUCH_START && mCompositorVsyncObserver) {
+    mCompositorVsyncObserver->SetNeedsComposite(true);
+  }
+
   if (aTouch.mType == MultiTouchInput::MULTITOUCH_MOVE) {
     MutexAutoLock lock(mTouchQueueLock);
     if (mResamplingEnabled) {
       mTouchMoveEvents.push_back(aTouch);
       return;
     }
 
     if (mTouchMoveEvents.empty()) {
--- a/widget/gonk/GeckoTouchDispatcher.h
+++ b/widget/gonk/GeckoTouchDispatcher.h
@@ -17,22 +17,27 @@
 
 #ifndef GECKO_TOUCH_INPUT_DISPATCHER_h
 #define GECKO_TOUCH_INPUT_DISPATCHER_h
 
 #include "InputData.h"
 #include "Units.h"
 #include "mozilla/Mutex.h"
 #include <vector>
+#include "nsRefPtr.h"
 
 class nsIWidget;
 
 namespace mozilla {
 class WidgetMouseEvent;
 
+namespace layers {
+class CompositorVsyncObserver;
+}
+
 // Used to resample touch events whenever a vsync event occurs. It batches
 // touch moves and on every vsync, resamples the touch position to create smooth
 // scrolls. We use the Android touch resample algorithm. It uses a combination of
 // extrapolation and interpolation. The algorithm takes the vsync time and
 // subtracts mVsyncAdjust time in ms and creates a sample time. All touch events are
 // relative to this sample time. If the last touch event occurs AFTER this
 // sample time, interpolate the last two touch events. If the last touch event occurs BEFORE
 // this sample time, we extrapolate the last two touch events to the sample
@@ -43,16 +48,17 @@ class GeckoTouchDispatcher
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GeckoTouchDispatcher)
 
 public:
   GeckoTouchDispatcher();
   void NotifyTouch(MultiTouchInput& aTouch, TimeStamp aEventTime);
   void DispatchTouchEvent(MultiTouchInput& aMultiTouch);
   void DispatchTouchMoveEvents(TimeStamp aVsyncTime);
   static bool NotifyVsync(TimeStamp aVsyncTimestamp);
+  static void SetCompositorVsyncObserver(layers::CompositorVsyncObserver* aObserver);
 
 private:
   void ResampleTouchMoves(MultiTouchInput& aOutTouch, TimeStamp vsyncTime);
   void SendTouchEvent(MultiTouchInput& aData);
   void DispatchMouseEvent(MultiTouchInput& aMultiTouch,
                           bool aForwardToChildren);
   WidgetMouseEvent ToWidgetMouseEvent(const MultiTouchInput& aData, nsIWidget* aWidget) const;
 
@@ -73,12 +79,14 @@ private:
   // resample
   TimeDuration mMinResampleTime;
 
   // Threshold if a vsync event runs too far behind touch events
   TimeDuration mDelayedVsyncThreshold;
 
   // How far ahead can vsync events get ahead of touch events.
   TimeDuration mOldTouchThreshold;
+
+  nsRefPtr<layers::CompositorVsyncObserver> mCompositorVsyncObserver;
 };
 
 } // namespace mozilla
 #endif // GECKO_TOUCH_INPUT_DISPATCHER_h
--- a/widget/gonk/GonkMemoryPressureMonitoring.cpp
+++ b/widget/gonk/GonkMemoryPressureMonitoring.cpp
@@ -122,16 +122,18 @@ public:
 #ifdef MOZ_NUWA_PROCESS
     if (IsNuwaProcess()) {
       NS_ASSERTION(NuwaMarkCurrentThread != nullptr,
                    "NuwaMarkCurrentThread is undefined!");
       NuwaMarkCurrentThread(nullptr, nullptr);
     }
 #endif
 
+    NS_SetIgnoreStatusOfCurrentThread();
+
     int lowMemFd = open("/sys/kernel/mm/lowmemkiller/notify_trigger_active",
                         O_RDONLY | O_CLOEXEC);
     NS_ENSURE_STATE(lowMemFd != -1);
     ScopedClose autoClose(lowMemFd);
 
     nsresult rv = CheckForMemoryPressure(lowMemFd, nullptr);
     NS_ENSURE_SUCCESS(rv, rv);
 
--- a/widget/gonk/HwcComposer2D.cpp
+++ b/widget/gonk/HwcComposer2D.cpp
@@ -25,16 +25,17 @@
 #include "mozilla/layers/CompositorParent.h"
 #include "mozilla/layers/LayerManagerComposite.h"
 #include "mozilla/layers/PLayerTransaction.h"
 #include "mozilla/layers/ShadowLayerUtilsGralloc.h"
 #include "mozilla/layers/TextureHostOGL.h"  // for TextureHostOGL
 #include "mozilla/StaticPtr.h"
 #include "cutils/properties.h"
 #include "gfx2DGlue.h"
+#include "nsWindow.h"
 
 #if ANDROID_VERSION >= 17
 #include "libdisplay/FramebufferSurface.h"
 #include "gfxPrefs.h"
 #include "nsThreadUtils.h"
 
 #ifndef HWC_BLIT
 #define HWC_BLIT (HWC_FRAMEBUFFER_TARGET + 1)
@@ -219,17 +220,17 @@ void
 HwcComposer2D::Vsync(int aDisplay, nsecs_t aVsyncTimestamp)
 {
     TimeStamp vsyncTime = mozilla::TimeStamp::FromSystemTime(aVsyncTimestamp);
     nsecs_t vsyncInterval = aVsyncTimestamp - mLastVsyncTime;
     if (vsyncInterval < 16000000 || vsyncInterval > 17000000) {
       LOGE("Non-uniform vsync interval: %lld\n", vsyncInterval);
     }
     mLastVsyncTime = aVsyncTimestamp;
-    VsyncDispatcher::GetInstance()->NotifyVsync(vsyncTime);
+    nsWindow::NotifyVsync(vsyncTime);
 }
 
 // Called on the "invalidator" thread (run from HAL).
 void
 HwcComposer2D::Invalidate()
 {
     if (!Initialized()) {
         LOGE("HwcComposer2D::Invalidate failed!");
--- a/widget/gonk/nsAppShell.cpp
+++ b/widget/gonk/nsAppShell.cpp
@@ -68,16 +68,17 @@
 #include "ipc/Nuwa.h"
 #endif
 
 #include "mozilla/Preferences.h"
 #include "GeckoProfiler.h"
 
 // Defines kKeyMapping and GetKeyNameIndex()
 #include "GonkKeyMapping.h"
+#include "mozilla/layers/CompositorParent.h"
 #include "GeckoTouchDispatcher.h"
 
 #define LOG(args...)                                            \
     __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args)
 #ifdef VERBOSE_LOG_ENABLED
 # define VERBOSE_LOG(args...)                           \
     __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args)
 #else
--- a/widget/gonk/nsWindow.cpp
+++ b/widget/gonk/nsWindow.cpp
@@ -208,16 +208,31 @@ nsWindow::DoDraw(void)
     }
 
     listener = targetWindow->GetWidgetListener();
     if (listener) {
         listener->DidPaintWindow();
     }
 }
 
+/* static */ void
+nsWindow::NotifyVsync(TimeStamp aVsyncTimestamp)
+{
+    if (!gFocusedWindow) {
+      return;
+    }
+
+    VsyncDispatcher* vsyncDispatcher = gFocusedWindow->GetVsyncDispatcher();
+    // During bootup, there is a delay between when the nsWindow is created
+    // and when the Compositor is created, but vsync is already turned on
+    if (vsyncDispatcher) {
+      vsyncDispatcher->NotifyVsync(aVsyncTimestamp);
+    }
+}
+
 nsEventStatus
 nsWindow::DispatchInputEvent(WidgetGUIEvent& aEvent, bool* aWasCaptured)
 {
     if (aWasCaptured) {
         *aWasCaptured = false;
     }
     if (!gFocusedWindow) {
         return nsEventStatus_eIgnore;
--- a/widget/gonk/nsWindow.h
+++ b/widget/gonk/nsWindow.h
@@ -44,16 +44,17 @@ struct InputContextAction;
 }
 
 class nsWindow : public nsBaseWidget
 {
 public:
     nsWindow();
     virtual ~nsWindow();
 
+    static void NotifyVsync(mozilla::TimeStamp aVsyncTimestamp);
     static void DoDraw(void);
     static nsEventStatus DispatchInputEvent(mozilla::WidgetGUIEvent& aEvent,
                                             bool* aWasCaptured = nullptr);
 
     NS_IMETHOD Create(nsIWidget *aParent,
                       void *aNativeParent,
                       const nsIntRect &aRect,
                       nsDeviceContext *aContext,
--- a/widget/nsBaseWidget.cpp
+++ b/widget/nsBaseWidget.cpp
@@ -38,16 +38,17 @@
 #include "mozilla/Attributes.h"
 #include "mozilla/unused.h"
 #include "nsContentUtils.h"
 #include "gfxPrefs.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/MouseEvents.h"
 #include "GLConsts.h"
 #include "mozilla/unused.h"
+#include "mozilla/VsyncDispatcher.h"
 #include "mozilla/layers/APZCTreeManager.h"
 #include "mozilla/layers/ChromeProcessController.h"
 
 #ifdef ACCESSIBILITY
 #include "nsAccessibilityService.h"
 #endif
 
 #ifdef DEBUG
@@ -106,16 +107,17 @@ nsAutoRollup::~nsAutoRollup()
 // nsBaseWidget constructor
 //
 //-------------------------------------------------------------------------
 
 nsBaseWidget::nsBaseWidget()
 : mWidgetListener(nullptr)
 , mAttachedWidgetListener(nullptr)
 , mContext(nullptr)
+, mVsyncDispatcher(nullptr)
 , mCursor(eCursor_standard)
 , mUpdateCursor(true)
 , mBorderStyle(eBorderStyle_none)
 , mUseLayersAcceleration(false)
 , mForceLayersAcceleration(false)
 , mTemporarilyUseBasicLayerManager(false)
 , mUseAttachedEvents(false)
 , mContextInitialized(false)
@@ -224,19 +226,23 @@ nsBaseWidget::~nsBaseWidget()
 
 #ifdef NOISY_WIDGET_LEAKS
   gNumWidgets--;
   printf("WIDGETS- = %d\n", gNumWidgets);
 #endif
 
   NS_IF_RELEASE(mContext);
   delete mOriginalBounds;
+
+  // Can have base widgets that are things like tooltips which don't have vsyncDispatchers
+  if (mVsyncDispatcher) {
+    mVsyncDispatcher->Shutdown();
+  }
 }
 
-
 //-------------------------------------------------------------------------
 //
 // Basic create.
 //
 //-------------------------------------------------------------------------
 void nsBaseWidget::BaseCreate(nsIWidget *aParent,
                               const nsIntRect &aRect,
                               nsDeviceContext *aContext,
@@ -939,16 +945,34 @@ nsBaseWidget::GetPreferredCompositorBack
 {
   if (mUseLayersAcceleration) {
     aHints.AppendElement(LayersBackend::LAYERS_OPENGL);
   }
 
   aHints.AppendElement(LayersBackend::LAYERS_BASIC);
 }
 
+void nsBaseWidget::CreateVsyncDispatcher()
+{
+  if (gfxPrefs::HardwareVsyncEnabled()) {
+    // Parent directly listens to the vsync source whereas
+    // child process communicate via IPC
+    // Should be called AFTER gfxPlatform is initialized
+    if (XRE_IsParentProcess()) {
+      mVsyncDispatcher = new VsyncDispatcher();
+    }
+  }
+}
+
+VsyncDispatcher*
+nsBaseWidget::GetVsyncDispatcher()
+{
+  return mVsyncDispatcher;
+}
+
 void nsBaseWidget::CreateCompositor(int aWidth, int aHeight)
 {
   // This makes sure that gfxPlatforms gets initialized if it hasn't by now.
   gfxPlatform::GetPlatform();
 
   MOZ_ASSERT(gfxPlatform::UsesOffMainThreadCompositing(),
              "This function assumes OMTC");
 
@@ -956,16 +980,17 @@ void nsBaseWidget::CreateCompositor(int 
   // to make sure it's properly destroyed by calling DestroyCompositor!
 
   // If we've already received a shutdown notification, don't try
   // create a new compositor.
   if (!mShutdownObserver) {
     return;
   }
 
+  CreateVsyncDispatcher();
   mCompositorParent = NewCompositorParent(aWidth, aHeight);
   MessageChannel *parentChannel = mCompositorParent->GetIPCChannel();
   nsRefPtr<ClientLayerManager> lm = new ClientLayerManager(this);
   MessageLoop *childMessageLoop = CompositorParent::CompositorLoop();
   mCompositorChild = new CompositorChild(lm);
   mCompositorChild->Open(parentChannel, childMessageLoop, ipc::ChildSide);
 
   if (gfxPrefs::AsyncPanZoomEnabled()) {
--- a/widget/nsBaseWidget.h
+++ b/widget/nsBaseWidget.h
@@ -32,16 +32,18 @@ class Accessible;
 
 namespace layers {
 class BasicLayerManager;
 class CompositorChild;
 class CompositorParent;
 class APZCTreeManager;
 class GeckoContentController;
 }
+
+class VsyncDispatcher;
 }
 
 namespace base {
 class Thread;
 }
 
 // Windows specific constant indicating the maximum number of touch points the
 // inject api will allow. This also sets the maximum numerical value for touch
@@ -133,16 +135,18 @@ public:
   NS_IMETHOD              HideWindowChrome(bool aShouldHide);
   NS_IMETHOD              MakeFullScreen(bool aFullScreen, nsIScreen* aScreen = nullptr);
   virtual nsDeviceContext* GetDeviceContext();
   virtual LayerManager*   GetLayerManager(PLayerTransactionChild* aShadowManager = nullptr,
                                           LayersBackend aBackendHint = mozilla::layers::LayersBackend::LAYERS_NONE,
                                           LayerManagerPersistence aPersistence = LAYER_MANAGER_CURRENT,
                                           bool* aAllowRetaining = nullptr);
 
+  VsyncDispatcher*        GetVsyncDispatcher() MOZ_OVERRIDE;
+  virtual void            CreateVsyncDispatcher();
   virtual CompositorParent* NewCompositorParent(int aSurfaceWidth, int aSurfaceHeight);
   virtual void            CreateCompositor();
   virtual void            CreateCompositor(int aWidth, int aHeight);
   virtual void            PrepareWindowEffects() {}
   virtual void            CleanupWindowEffects() {}
   virtual bool            PreRender(LayerManagerComposite* aManager) { return true; }
   virtual void            PostRender(LayerManagerComposite* aManager) {}
   virtual void            DrawWindowUnderlay(LayerManagerComposite* aManager, nsIntRect aRect) {}
@@ -409,16 +413,17 @@ protected:
 
   nsIWidgetListener* mWidgetListener;
   nsIWidgetListener* mAttachedWidgetListener;
   nsDeviceContext* mContext;
   nsRefPtr<LayerManager> mLayerManager;
   nsRefPtr<LayerManager> mBasicLayerManager;
   nsRefPtr<CompositorChild> mCompositorChild;
   nsRefPtr<CompositorParent> mCompositorParent;
+  nsRefPtr<mozilla::VsyncDispatcher> mVsyncDispatcher;
   nsRefPtr<APZCTreeManager> mAPZC;
   nsRefPtr<WidgetShutdownObserver> mShutdownObserver;
   nsCursor          mCursor;
   bool              mUpdateCursor;
   nsBorderStyle     mBorderStyle;
   bool              mUseLayersAcceleration;
   bool              mForceLayersAcceleration;
   bool              mTemporarilyUseBasicLayerManager;
--- a/widget/nsIWidget.h
+++ b/widget/nsIWidget.h
@@ -31,16 +31,17 @@ class   nsIRollupListener;
 class   imgIContainer;
 class   nsIContent;
 class   ViewWrapper;
 class   nsIWidgetListener;
 class   nsIntRegion;
 class   nsIScreen;
 
 namespace mozilla {
+class VsyncDispatcher;
 namespace dom {
 class TabChild;
 }
 namespace plugins {
 class PluginWidgetChild;
 }
 namespace layers {
 class Composer2D;
@@ -686,16 +687,17 @@ class nsIWidget : public nsISupports {
     typedef mozilla::layers::LayersBackend LayersBackend;
     typedef mozilla::layers::PLayerTransactionChild PLayerTransactionChild;
     typedef mozilla::widget::IMEMessage IMEMessage;
     typedef mozilla::widget::IMENotification IMENotification;
     typedef mozilla::widget::IMEState IMEState;
     typedef mozilla::widget::InputContext InputContext;
     typedef mozilla::widget::InputContextAction InputContextAction;
     typedef mozilla::widget::SizeConstraints SizeConstraints;
+    typedef mozilla::VsyncDispatcher VsyncDispatcher;
 
     // Used in UpdateThemeGeometries.
     struct ThemeGeometry {
       // The -moz-appearance value for the themed widget
       uint8_t mWidgetType;
       // The device-pixel rect within the window for the themed widget
       nsIntRect mRect;
 
@@ -865,16 +867,21 @@ class nsIWidget : public nsISupports {
 
     /**
      * Return the physical DPI of the screen containing the window ...
      * the number of device pixels per inch.
      */
     virtual float GetDPI() = 0;
 
     /**
+     * Returns the VsyncDispatcher associated with this widget
+     */
+    virtual VsyncDispatcher* GetVsyncDispatcher() = 0;
+
+    /**
      * Return the default scale factor for the window. This is the
      * default number of device pixels per CSS pixel to use. This should
      * depend on OS/platform settings such as the Mac's "UI scale factor"
      * or Windows' "font DPI". This will take into account Gecko preferences
      * overriding the system setting.
      */
     mozilla::CSSToLayoutDeviceScale GetDefaultScale();
 
--- a/xpcom/glue/nsThreadUtils.cpp
+++ b/xpcom/glue/nsThreadUtils.cpp
@@ -370,8 +370,16 @@ nsAutoLowPriorityIO::~nsAutoLowPriorityI
   }
 #elif defined(XP_MACOSX)
   if (MOZ_LIKELY(lowIOPrioritySet)) {
     setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_THREAD, oldPriority);
   }
 #endif
 }
 
+#ifdef MOZ_NUWA_PROCESS
+#ifdef MOZILLA_INTERNAL_API
+void
+NS_SetIgnoreStatusOfCurrentThread() {
+  nsThreadManager::get()->SetIgnoreThreadStatus();
+}
+#endif // MOZILLA_INTERNAL_API
+#endif // MOZ_NUWA_PROCESS
--- a/xpcom/glue/nsThreadUtils.h
+++ b/xpcom/glue/nsThreadUtils.h
@@ -560,9 +560,24 @@ private:
 #if defined(XP_MACOSX)
   int oldPriority;
 #endif
 };
 
 void
 NS_SetMainThread();
 
+/**
+ * Helpers for thread to report their status when compiled with Nuwa.
+ */
+#ifdef MOZILLA_INTERNAL_API
+#ifdef MOZ_NUWA_PROCESS
+extern void
+NS_SetIgnoreStatusOfCurrentThread();
+#else // MOZ_NUWA_PROCESS
+inline void
+NS_SetIgnoreStatusOfCurrentThread()
+{
+}
+#endif // MOZ_NUWA_PROCESS
+#endif // MOZILLA_INTERNAL_API
+
 #endif  // nsThreadUtils_h__
--- a/xpcom/threads/TimerThread.cpp
+++ b/xpcom/threads/TimerThread.cpp
@@ -200,16 +200,17 @@ TimerThread::Run()
   PR_SetCurrentThreadName("Timer");
 
 #ifdef MOZ_NUWA_PROCESS
   if (IsNuwaProcess()) {
     NuwaMarkCurrentThread(nullptr, nullptr);
   }
 #endif
 
+  NS_SetIgnoreStatusOfCurrentThread();
   MonitorAutoLock lock(mMonitor);
 
   // We need to know how many microseconds give a positive PRIntervalTime. This
   // is platform-dependent and we calculate it at runtime, finding a value |v|
   // such that |PR_MicrosecondsToInterval(v) > 0| and then binary-searching in
   // the range [0, v) to find the ms-to-interval scale.
   uint32_t usForPosInterval = 1;
   while (PR_MicrosecondsToInterval(usForPosInterval) == 0) {
--- a/xpcom/threads/nsThread.cpp
+++ b/xpcom/threads/nsThread.cpp
@@ -8,17 +8,16 @@
 
 #include "base/message_loop.h"
 
 // Chromium's logging can sometimes leak through...
 #ifdef LOG
 #undef LOG
 #endif
 
-#include "mozilla/ReentrantMonitor.h"
 #include "nsMemoryPressure.h"
 #include "nsThreadManager.h"
 #include "nsIClassInfoImpl.h"
 #include "nsIProgrammingLanguage.h"
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
 #include "pratom.h"
 #include "prlog.h"
@@ -327,16 +326,20 @@ nsThread::ThreadFunc(void* aArg)
   using mozilla::ipc::BackgroundChild;
 
   nsThread* self = static_cast<nsThread*>(aArg);  // strong reference
   self->mThread = PR_GetCurrentThread();
   SetupCurrentThreadForChaosMode();
 
   // Inform the ThreadManager
   nsThreadManager::get()->RegisterCurrentThread(self);
+#ifdef MOZ_NUWA_PROCESS
+  self->mThreadStatusInfo =
+    static_cast<void*>(nsThreadManager::get()->GetCurrentThreadStatusInfo());
+#endif
 
   mozilla::IOInterposer::RegisterCurrentThread();
 
   // Wait for and process startup event
   nsCOMPtr<nsIRunnable> event;
   if (!self->GetEvent(true, getter_AddRefs(event))) {
     NS_WARNING("failed waiting for thread startup event");
     return;
@@ -434,16 +437,20 @@ nsThread::nsThread(MainThreadFlag aMainT
   , mPriority(PRIORITY_NORMAL)
   , mThread(nullptr)
   , mRunningEvent(0)
   , mStackSize(aStackSize)
   , mShutdownContext(nullptr)
   , mShutdownRequired(false)
   , mEventsAreDoomed(false)
   , mIsMainThread(aMainThread)
+#ifdef MOZ_NUWA_PROCESS
+  , mThreadStatusMonitor("nsThread.mThreadStatusLock")
+  , mThreadStatusInfo(nullptr)
+#endif
 {
 }
 
 nsThread::~nsThread()
 {
 }
 
 nsresult
@@ -481,32 +488,45 @@ nsThread::Init()
 
 nsresult
 nsThread::InitCurrentThread()
 {
   mThread = PR_GetCurrentThread();
   SetupCurrentThreadForChaosMode();
 
   nsThreadManager::get()->RegisterCurrentThread(this);
+#ifdef MOZ_NUWA_PROCESS
+  mThreadStatusInfo =
+    static_cast<void*>(nsThreadManager::get()->GetCurrentThreadStatusInfo());
+#endif
+
   return NS_OK;
 }
 
 nsresult
 nsThread::PutEvent(nsIRunnable* aEvent, nsNestedEventTarget* aTarget)
 {
   nsCOMPtr<nsIThreadObserver> obs;
 
   {
     MutexAutoLock lock(mLock);
     nsChainedEventQueue* queue = aTarget ? aTarget->mQueue : &mEventsRoot;
     if (!queue || (queue == &mEventsRoot && mEventsAreDoomed)) {
       NS_WARNING("An event was posted to a thread that will never run it (rejected)");
       return NS_ERROR_UNEXPECTED;
     }
-    queue->PutEvent(aEvent);
+#ifdef MOZ_NUWA_PROCESS
+    {
+      ReentrantMonitorAutoEnter mon(mThreadStatusMonitor);
+      SetWorking();
+#endif // MOZ_NUWA_PROCESS
+      queue->PutEvent(aEvent);
+#ifdef MOZ_NUWA_PROCESS
+    }
+#endif // MOZ_NUWA_PROCESS
 
     // Make sure to grab the observer before dropping the lock, otherwise the
     // event that we just placed into the queue could run and eventually delete
     // this nsThread before the calling thread is scheduled again. We would then
     // crash while trying to access a dead nsThread.
     obs = mObserver;
   }
 
@@ -837,16 +857,37 @@ nsThread::ProcessNextEvent(bool aMayWait
       MOZ_ASSERT(ShuttingDown(),
                  "This should only happen when shutting down");
       rv = NS_ERROR_UNEXPECTED;
     }
   }
 
   --mRunningEvent;
 
+#ifdef MOZ_NUWA_PROCESS
+  nsCOMPtr<nsIRunnable> notifyAllIdleRunnable;
+  {
+    ReentrantMonitorAutoEnter mon(mThreadStatusMonitor);
+    if ((!mEvents->GetEvent(false, nullptr)) && (mRunningEvent == 0)) {
+      nsThreadManager::get()->SetThreadIsWorking(
+        static_cast<nsThreadManager::ThreadStatusInfo*>(mThreadStatusInfo),
+        false, getter_AddRefs(notifyAllIdleRunnable));
+    }
+  }
+  if (notifyAllIdleRunnable) {
+    // Dispatching a task leads us to acquire |mLock| of the thread. If we
+    // dispatch to main thread while holding main thread's
+    // |mThreadStatusMonitor|, deadlock could happen if other thread is
+    // blocked by main thread's |mThreadStatusMonitor| and is holding
+    // main thread's |mLock|.
+    Dispatch(notifyAllIdleRunnable, NS_DISPATCH_NORMAL);
+    nsThreadManager::get()->ResetIsDispatchingToMainThread();
+  }
+#endif // MOZ_NUWA_PROCESS
+
   NOTIFY_EVENT_OBSERVERS(AfterProcessNextEvent,
                          (this, mRunningEvent, *aResult));
 
   if (obs) {
     obs->AfterProcessNextEvent(this, mRunningEvent, *aResult);
   }
 
   if (notifyMainThreadObserver && sMainThreadObserver) {
@@ -1046,16 +1087,34 @@ nsThread::SetMainThreadObserver(nsIThrea
   if (!NS_IsMainThread()) {
     return NS_ERROR_UNEXPECTED;
   }
 
   nsThread::sMainThreadObserver = aObserver;
   return NS_OK;
 }
 
+#ifdef MOZ_NUWA_PROCESS
+void
+nsThread::SetWorking()
+{
+  nsThreadManager::get()->SetThreadIsWorking(
+    static_cast<nsThreadManager::ThreadStatusInfo*>(mThreadStatusInfo),
+    true, nullptr);
+}
+
+void
+nsThread::SetIdle()
+{
+  nsThreadManager::get()->SetThreadIsWorking(
+    static_cast<nsThreadManager::ThreadStatusInfo*>(mThreadStatusInfo),
+    false, nullptr);
+}
+#endif
+
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 nsThreadSyncDispatch::Run()
 {
   if (mSyncTask) {
     mResult = mSyncTask->Run();
     mSyncTask = nullptr;
--- a/xpcom/threads/nsThread.h
+++ b/xpcom/threads/nsThread.h
@@ -11,16 +11,17 @@
 #include "nsIThreadInternal.h"
 #include "nsISupportsPriority.h"
 #include "nsEventQueue.h"
 #include "nsThreadUtils.h"
 #include "nsString.h"
 #include "nsTObserverArray.h"
 #include "mozilla/Attributes.h"
 #include "nsAutoPtr.h"
+#include "mozilla/ReentrantMonitor.h"
 
 // A native thread
 class nsThread
   : public nsIThreadInternal
   , public nsISupportsPriority
 {
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
@@ -60,16 +61,24 @@ public:
   void ClearObservers()
   {
     mEventObservers.Clear();
   }
 
   static nsresult
   SetMainThreadObserver(nsIThreadObserver* aObserver);
 
+#ifdef MOZ_NUWA_PROCESS
+  void SetWorking();
+  void SetIdle();
+  mozilla::ReentrantMonitor& ThreadStatusMonitor() {
+    return mThreadStatusMonitor;
+  }
+#endif
+
 protected:
   static nsIThreadObserver* sMainThreadObserver;
 
   class nsChainedEventQueue;
 
   class nsNestedEventTarget;
   friend class nsNestedEventTarget;
 
@@ -177,16 +186,22 @@ protected:
   uint32_t  mStackSize;
 
   struct nsThreadShutdownContext* mShutdownContext;
 
   bool mShutdownRequired;
   // Set to true when events posted to this thread will never run.
   bool mEventsAreDoomed;
   MainThreadFlag mIsMainThread;
+#ifdef MOZ_NUWA_PROCESS
+  mozilla::ReentrantMonitor mThreadStatusMonitor;
+  // The actual type is defined in nsThreadManager.h which is not exposed to
+  // file out of thread module.
+  void* mThreadStatusInfo;
+#endif
 };
 
 //-----------------------------------------------------------------------------
 
 class nsThreadSyncDispatch : public nsRunnable
 {
 public:
   nsThreadSyncDispatch(nsIThread* aOrigin, nsIRunnable* aTask)
--- a/xpcom/threads/nsThreadManager.cpp
+++ b/xpcom/threads/nsThreadManager.cpp
@@ -6,16 +6,17 @@
 
 #include "nsThreadManager.h"
 #include "nsThread.h"
 #include "nsThreadUtils.h"
 #include "nsIClassInfoImpl.h"
 #include "nsTArray.h"
 #include "nsAutoPtr.h"
 #include "mozilla/ThreadLocal.h"
+#include "mozilla/ReentrantMonitor.h"
 #ifdef MOZ_CANARY
 #include <fcntl.h>
 #include <unistd.h>
 #endif
 
 using namespace mozilla;
 
 #ifdef XP_WIN
@@ -42,24 +43,81 @@ NS_SetMainThread()
     }
     sTLSIsMainThread.set(true);
   }
   MOZ_ASSERT(NS_IsMainThread());
 }
 
 typedef nsTArray<nsRefPtr<nsThread>> nsThreadArray;
 
+#ifdef MOZ_NUWA_PROCESS
+class NotifyAllThreadsWereIdle: public nsRunnable
+{
+public:
+
+  NotifyAllThreadsWereIdle(
+    nsTArray<nsRefPtr<nsThreadManager::AllThreadsWereIdleListener>>* aListeners)
+    : mListeners(aListeners)
+  {
+  }
+
+  virtual NS_IMETHODIMP
+  Run() {
+    // Copy listener array, which may be modified during call back.
+    nsTArray<nsRefPtr<nsThreadManager::AllThreadsWereIdleListener>> arr(*mListeners);
+    for (size_t i = 0; i < arr.Length(); i++) {
+      arr[i]->OnAllThreadsWereIdle();
+    }
+    return NS_OK;
+  }
+
+private:
+  // Raw pointer, since it's pointing to a  member of thread manager.
+  nsTArray<nsRefPtr<nsThreadManager::AllThreadsWereIdleListener>>* mListeners;
+};
+
+struct nsThreadManager::ThreadStatusInfo {
+  Atomic<bool> mWorking;
+  Atomic<bool> mWillBeWorking;
+  bool mIgnored;
+  ThreadStatusInfo()
+    : mWorking(false)
+    , mWillBeWorking(false)
+    , mIgnored(false)
+  {
+  }
+};
+#endif // MOZ_NUWA_PROCESS
+
 //-----------------------------------------------------------------------------
 
 static void
 ReleaseObject(void* aData)
 {
   static_cast<nsISupports*>(aData)->Release();
 }
 
+#ifdef MOZ_NUWA_PROCESS
+void
+nsThreadManager::DeleteThreadStatusInfo(void* aData)
+{
+  nsThreadManager* mgr = nsThreadManager::get();
+  nsThreadManager::ThreadStatusInfo* thrInfo =
+    static_cast<nsThreadManager::ThreadStatusInfo*>(aData);
+  {
+    ReentrantMonitorAutoEnter mon(*(mgr->mMonitor));
+    mgr->mThreadStatusInfos.RemoveElement(thrInfo);
+    if (NS_IsMainThread()) {
+      mgr->mMainThreadStatusInfo = nullptr;
+    }
+  }
+  delete thrInfo;
+}
+#endif
+
 static PLDHashOperator
 AppendAndRemoveThread(PRThread* aKey, nsRefPtr<nsThread>& aThread, void* aArg)
 {
   nsThreadArray* threads = static_cast<nsThreadArray*>(aArg);
   threads->AppendElement(aThread);
   return PL_DHASH_REMOVE;
 }
 
@@ -91,17 +149,28 @@ nsThreadManager::Init()
   if (mInitialized) {
     return NS_OK;
   }
 
   if (PR_NewThreadPrivateIndex(&mCurThreadIndex, ReleaseObject) == PR_FAILURE) {
     return NS_ERROR_FAILURE;
   }
 
+#ifdef MOZ_NUWA_PROCESS
+  if (PR_NewThreadPrivateIndex(
+      &mThreadStatusInfoIndex,
+      nsThreadManager::DeleteThreadStatusInfo) == PR_FAILURE) {
+    return NS_ERROR_FAILURE;
+  }
+#endif // MOZ_NUWA_PROCESS
+
   mLock = new Mutex("nsThreadManager.mLock");
+#ifdef MOZ_NUWA_PROCESS
+  mMonitor = MakeUnique<ReentrantMonitor>("nsThreadManager.mMonitor");
+#endif // MOZ_NUWA_PROCESS
 
 #ifdef MOZ_CANARY
   const int flags = O_WRONLY | O_APPEND | O_CREAT | O_NONBLOCK;
   const mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
   char* env_var_flag = getenv("MOZ_KILL_CANARIES");
   sCanaryOutputFD =
     env_var_flag ? (env_var_flag[0] ? open(env_var_flag, flags, mode) :
                                       STDERR_FILENO) :
@@ -189,16 +258,19 @@ nsThreadManager::Shutdown()
   mMainThread->ClearObservers();
 
   // Release main thread object.
   mMainThread = nullptr;
   mLock = nullptr;
 
   // Remove the TLS entry for the main thread.
   PR_SetThreadPrivate(mCurThreadIndex, nullptr);
+#ifdef MOZ_NUWA_PROCESS
+  PR_SetThreadPrivate(mThreadStatusInfoIndex, nullptr);
+#endif
 }
 
 void
 nsThreadManager::RegisterCurrentThread(nsThread* aThread)
 {
   MOZ_ASSERT(aThread->GetPRThread() == PR_GetCurrentThread(), "bad aThread");
 
   MutexAutoLock lock(*mLock);
@@ -221,16 +293,19 @@ nsThreadManager::UnregisterCurrentThread
 
   MutexAutoLock lock(*mLock);
 
   --mCurrentNumberOfThreads;
   mThreadsByPRThread.Remove(aThread->GetPRThread());
 
   PR_SetThreadPrivate(mCurThreadIndex, nullptr);
   // Ref-count balanced via ReleaseObject
+#ifdef MOZ_NUWA_PROCESS
+  PR_SetThreadPrivate(mThreadStatusInfoIndex, nullptr);
+#endif
 }
 
 nsThread*
 nsThreadManager::GetCurrentThread()
 {
   // read thread local storage
   void* data = PR_GetThreadPrivate(mCurThreadIndex);
   if (data) {
@@ -245,16 +320,37 @@ nsThreadManager::GetCurrentThread()
   nsRefPtr<nsThread> thread = new nsThread(nsThread::NOT_MAIN_THREAD, 0);
   if (!thread || NS_FAILED(thread->InitCurrentThread())) {
     return nullptr;
   }
 
   return thread.get();  // reference held in TLS
 }
 
+#ifdef MOZ_NUWA_PROCESS
+nsThreadManager::ThreadStatusInfo*
+nsThreadManager::GetCurrentThreadStatusInfo()
+{
+  void* data = PR_GetThreadPrivate(mThreadStatusInfoIndex);
+  if (!data) {
+    ThreadStatusInfo *thrInfo = new ThreadStatusInfo();
+    PR_SetThreadPrivate(mThreadStatusInfoIndex, thrInfo);
+    data = thrInfo;
+
+    ReentrantMonitorAutoEnter mon(*mMonitor);
+    mThreadStatusInfos.AppendElement(thrInfo);
+    if (NS_IsMainThread()) {
+      mMainThreadStatusInfo = thrInfo;
+    }
+  }
+
+  return static_cast<ThreadStatusInfo*>(data);
+}
+#endif
+
 NS_IMETHODIMP
 nsThreadManager::NewThread(uint32_t aCreationFlags,
                            uint32_t aStackSize,
                            nsIThread** aResult)
 {
   // No new threads during Shutdown
   if (NS_WARN_IF(!mInitialized)) {
     return NS_ERROR_NOT_INITIALIZED;
@@ -337,8 +433,162 @@ nsThreadManager::GetIsMainThread(bool* a
 }
 
 uint32_t
 nsThreadManager::GetHighestNumberOfThreads()
 {
   MutexAutoLock lock(*mLock);
   return mHighestNumberOfThreads;
 }
+
+#ifdef MOZ_NUWA_PROCESS
+void
+nsThreadManager::SetIgnoreThreadStatus()
+{
+  GetCurrentThreadStatusInfo()->mIgnored = true;
+}
+
+void
+nsThreadManager::SetThreadIdle(nsIRunnable **aReturnRunnable)
+{
+  SetThreadIsWorking(GetCurrentThreadStatusInfo(), false, aReturnRunnable);
+}
+
+void
+nsThreadManager::SetThreadWorking()
+{
+  SetThreadIsWorking(GetCurrentThreadStatusInfo(), true, nullptr);
+}
+
+void
+nsThreadManager::SetThreadIsWorking(ThreadStatusInfo* aInfo,
+                                    bool aIsWorking,
+                                    nsIRunnable **aReturnRunnable)
+{
+  aInfo->mWillBeWorking = aIsWorking;
+  if (mThreadsIdledListeners.Length() > 0) {
+
+    // A race condition occurs since we don't want threads to try to enter the
+    // monitor (nsThreadManager::mMonitor) when no one cares about their status.
+    // And thus the race can happen when we put the first listener into
+    // |mThreadsIdledListeners|:
+    //
+    // (1) Thread A wants to dispatch a task to Thread B.
+    // (2) Thread A checks |mThreadsIdledListeners|, and nothing is in the
+    //     list. So Thread A decides not to enter |mMonitor| when updating B's
+    //     status.
+    // (3) Thread A is suspended just before it changed status of B.
+    // (4) A listener is added to |mThreadsIdledListeners|
+    // (5) Now is Thread C's turn to run. Thread C finds there's something in
+    //     |mThreadsIdledListeners|, so it enters |mMonitor| and check all
+    //     thread info structs in |mThreadStatusInfos| while A is in the middle
+    //     of changing B's status.
+    //
+    // Then C may find Thread B is an idle thread (which is not correct, because
+    // A attempted to change B's status prior to C starting to walk throught
+    // |mThreadStatusInfo|), but the fact that thread A is working (thread A
+    // hasn't finished dispatching a task to thread B) can prevent thread C from
+    // firing a bogus notification.
+    //
+    // If the state transition that happens outside the monitor is in the other
+    // direction, the race condition could be:
+    //
+    // (1) Thread D has just finished its jobs and wants to set its status to idle.
+    // (2) Thread D checks |mThreadsIdledListeners|, and nothing is in the list.
+    //     So Thread D decides not to enter |mMonitor|.
+    // (3) Thread D is is suspended before it updates its own status.
+    // (4) A listener is put into |mThreadsIdledListeners|.
+    // (5) Thread C wants to changes status of itself. It checks
+    //     |mThreadsIdledListeners| and finds something inside the list. Thread C
+    //     then enters |mMonitor|, updates its status and checks thread info in
+    //     |mThreadStatusInfos| while D is changing status of itself out of monitor.
+    //
+    // Thread C will find that thread D is working (D actually wants to change its
+    // status to idle before C starting to check), then C returns without firing
+    // any notification. Finding that thread D is working can make our checking
+    // mechanism miss a chance to fire a notification: because thread D thought
+    // there's nothing in |mThreadsIdledListeners| and thus won't check the
+    // |mThreadStatusInfos| after changing the status of itself.
+    //
+    // |mWillBeWorking| can be used to address this problem. We require each
+    // thread to put the value that is going to be set to |mWorking| to
+    // |mWillBeWorking| before the thread decide whether it should enter
+    // |mMonitor| to change status or not. Thus C finds that D is working while
+    // D's |mWillBeWorking| is false, and C realizes that D is just updating and
+    // can treat D as an idle thread.
+    //
+    // It doesn't matter whether D will check thread status after changing its
+    // own status or not. If D checks, which means D will enter the monitor
+    // before updating status, thus D must be blocked until C has finished
+    // dispatching the notification task to main thread, and D will find that main
+    // thread is working and will not fire an additional event. On the other hand,
+    // if D doesn't check |mThreadStatusInfos|, it's still ok, because C has
+    // treated D as an idle thread already.
+
+    bool hasWorkingThread = false;
+    nsRefPtr<NotifyAllThreadsWereIdle> runnable;
+    {
+      ReentrantMonitorAutoEnter mon(*mMonitor);
+      // Get data structure of thread info.
+      aInfo->mWorking = aIsWorking;
+      if (aIsWorking) {
+        // We are working, so there's no need to check futher.
+        return;
+      }
+
+      for (size_t i = 0; i < mThreadStatusInfos.Length(); i++) {
+        ThreadStatusInfo *info = mThreadStatusInfos[i];
+        if (!info->mIgnored) {
+          if (info->mWorking) {
+            if (info->mWillBeWorking) {
+              hasWorkingThread = true;
+              break;
+            }
+          }
+        }
+      }
+      if (!hasWorkingThread && !mDispatchingToMainThread) {
+        runnable = new NotifyAllThreadsWereIdle(&mThreadsIdledListeners);
+        mDispatchingToMainThread = true;
+      }
+    }
+
+    if (runnable) {
+      if (NS_IsMainThread()) {
+        // We are holding the main thread's |nsThread::mThreadStatusMonitor|.
+        // If we dispatch a task to ourself, then we are in danger of causing
+        // deadlock. Instead, return the task, and let the caller dispatch it
+        // for us.
+        MOZ_ASSERT(aReturnRunnable,
+                   "aReturnRunnable must be provided on main thread");
+        runnable.forget(aReturnRunnable);
+      } else {
+        NS_DispatchToMainThread(runnable);
+        ResetIsDispatchingToMainThread();
+      }
+    }
+  } else {
+    // Update thread info without holding any lock.
+    aInfo->mWorking = aIsWorking;
+  }
+}
+
+void
+nsThreadManager::ResetIsDispatchingToMainThread()
+{
+  ReentrantMonitorAutoEnter mon(*mMonitor);
+  mDispatchingToMainThread = false;
+}
+
+void
+nsThreadManager::AddAllThreadsWereIdleListener(AllThreadsWereIdleListener *listener)
+{
+  MOZ_ASSERT(GetCurrentThreadStatusInfo()->mWorking);
+  mThreadsIdledListeners.AppendElement(listener);
+}
+
+void
+nsThreadManager::RemoveAllThreadsWereIdleListener(AllThreadsWereIdleListener *listener)
+{
+  mThreadsIdledListeners.RemoveElement(listener);
+}
+
+#endif // MOZ_NUWA_PROCESS
--- a/xpcom/threads/nsThreadManager.h
+++ b/xpcom/threads/nsThreadManager.h
@@ -9,19 +9,36 @@
 
 #include "mozilla/Mutex.h"
 #include "nsIThreadManager.h"
 #include "nsRefPtrHashtable.h"
 #include "nsThread.h"
 
 class nsIRunnable;
 
+namespace mozilla {
+class ReentrantMonitor;
+}
+
 class nsThreadManager : public nsIThreadManager
 {
 public:
+#ifdef MOZ_NUWA_PROCESS
+  struct ThreadStatusInfo;
+  class AllThreadsWereIdleListener {
+  public:
+    NS_INLINE_DECL_REFCOUNTING(AllThreadsWereIdleListener);
+    virtual void OnAllThreadsWereIdle() = 0;
+  protected:
+    virtual ~AllThreadsWereIdleListener()
+    {
+    }
+  };
+#endif // MOZ_NUWA_PROCESS
+
   NS_DECL_ISUPPORTS
   NS_DECL_NSITHREADMANAGER
 
   static nsThreadManager* get()
   {
     static nsThreadManager sInstance;
     return &sInstance;
   }
@@ -49,40 +66,83 @@ public:
   uint32_t GetHighestNumberOfThreads();
 
   // This needs to be public in order to support static instantiation of this
   // class with older compilers (e.g., egcs-2.91.66).
   ~nsThreadManager()
   {
   }
 
+#ifdef MOZ_NUWA_PROCESS
+  void SetIgnoreThreadStatus();
+
+  // |SetThreadWorking| and |SetThreadIdle| set status of thread that is
+  // currently running. They get thread status information from TLS and pass
+  // the information to |SetThreadIsWorking|.
+  void SetThreadIdle(nsIRunnable** aReturnRunnable);
+  void SetThreadWorking();
+
+  // |SetThreadIsWorking| is where is status actually changed. Thread status
+  // information is passed as a argument so caller must obtain the structure
+  // by itself. If this method is invoked on main thread, |aReturnRunnable|
+  // should be provided to receive the runnable of notifying listeners.
+  // |ResetIsDispatchingToMainThread| should be invoked after caller on main
+  // thread dispatched the task to main thread's queue.
+  void SetThreadIsWorking(ThreadStatusInfo* aInfo,
+                          bool aIsWorking,
+                          nsIRunnable** aReturnRunnable);
+  void ResetIsDispatchingToMainThread();
+
+  void AddAllThreadsWereIdleListener(AllThreadsWereIdleListener *listener);
+  void RemoveAllThreadsWereIdleListener(AllThreadsWereIdleListener *listener);
+  ThreadStatusInfo* GetCurrentThreadStatusInfo();
+#endif // MOZ_NUWA_PROCESS
+
 private:
   nsThreadManager()
     : mCurThreadIndex(0)
     , mMainPRThread(nullptr)
     , mLock(nullptr)
     , mInitialized(false)
     , mCurrentNumberOfThreads(1)
     , mHighestNumberOfThreads(1)
+#ifdef MOZ_NUWA_PROCESS
+    , mMonitor(nullptr)
+    , mMainThreadStatusInfo(nullptr)
+    , mDispatchingToMainThread(nullptr)
+#endif
   {
   }
 
   nsRefPtrHashtable<nsPtrHashKey<PRThread>, nsThread> mThreadsByPRThread;
   unsigned             mCurThreadIndex;  // thread-local-storage index
   nsRefPtr<nsThread>  mMainThread;
   PRThread*           mMainPRThread;
   // This is a pointer in order to allow creating nsThreadManager from
   // the static context in debug builds.
   nsAutoPtr<mozilla::Mutex> mLock;  // protects tables
   bool                mInitialized;
 
   // The current number of threads
   uint32_t            mCurrentNumberOfThreads;
   // The highest number of threads encountered so far during the session
   uint32_t            mHighestNumberOfThreads;
+
+#ifdef MOZ_NUWA_PROCESS
+  static void DeleteThreadStatusInfo(void *aData);
+  unsigned mThreadStatusInfoIndex;
+  nsTArray<nsRefPtr<AllThreadsWereIdleListener>> mThreadsIdledListeners;
+  nsTArray<ThreadStatusInfo*> mThreadStatusInfos;
+  mozilla::UniquePtr<mozilla::ReentrantMonitor> mMonitor;
+  ThreadStatusInfo* mMainThreadStatusInfo;
+  // |mDispatchingToMainThread| is set when all thread are found to be idle
+  // before task of notifying all listeners are dispatched to main thread.
+  // The flag is protected by |mMonitor|.
+  bool mDispatchingToMainThread;
+#endif // MOZ_NUWA_PROCESS
 };
 
 #define NS_THREADMANAGER_CID                       \
 { /* 7a4204c6-e45a-4c37-8ebb-6709a22c917c */       \
   0x7a4204c6,                                      \
   0xe45a,                                          \
   0x4c37,                                          \
   {0x8e, 0xbb, 0x67, 0x09, 0xa2, 0x2c, 0x91, 0x7c} \
--- a/xpcom/threads/nsThreadPool.cpp
+++ b/xpcom/threads/nsThreadPool.cpp
@@ -145,17 +145,16 @@ nsThreadPool::ShutdownThread(nsIThread* 
   nsRefPtr<nsIRunnable> r = NS_NewRunnableMethod(aThread, &nsIThread::Shutdown);
   NS_DispatchToMainThread(r);
 }
 
 NS_IMETHODIMP
 nsThreadPool::Run()
 {
   LOG(("THRD-P(%p) enter\n", this));
-
   mThreadNaming.SetThreadPoolName(mName);
 
   nsCOMPtr<nsIThread> current;
   nsThreadManager::get()->GetCurrentThread(getter_AddRefs(current));
 
   bool shutdownThreadOnExit = false;
   bool exitThread = false;
   bool wasIdle = false;
@@ -203,25 +202,31 @@ nsThreadPool::Run()
         if (exitThread) {
           if (wasIdle) {
             --mIdleCount;
           }
           shutdownThreadOnExit = mThreads.RemoveObject(current);
         } else {
           PRIntervalTime delta = timeout - (now - idleSince);
           LOG(("THRD-P(%p) waiting [%d]\n", this, delta));
+#ifdef MOZ_NUWA_PROCESS
+          nsThreadManager::get()->SetThreadIdle(nullptr);
+#endif // MOZ_NUWA_PROCESS
           mon.Wait(delta);
         }
       } else if (wasIdle) {
         wasIdle = false;
         --mIdleCount;
       }
     }
     if (event) {
       LOG(("THRD-P(%p) running [%p]\n", this, event.get()));
+#ifdef MOZ_NUWA_PROCESS
+      nsThreadManager::get()->SetThreadWorking();
+#endif // MOZ_NUWA_PROCESS
       event->Run();
     }
   } while (!exitThread);
 
   if (listener) {
     listener->OnThreadShuttingDown();
   }
 
--- a/xpcom/threads/nsTimerImpl.cpp
+++ b/xpcom/threads/nsTimerImpl.cpp
@@ -554,16 +554,23 @@ nsTimerImpl::SetTarget(nsIEventTarget* a
 
 void
 nsTimerImpl::Fire()
 {
   if (mCanceled) {
     return;
   }
 
+#ifdef MOZ_NUWA_PROCESS
+  if (IsNuwaProcess() && IsNuwaReady()) {
+    // A timer event fired after Nuwa frozen can freeze main thread.
+    return;
+  }
+#endif
+
   PROFILER_LABEL("Timer", "Fire",
                  js::ProfileEntry::Category::OTHER);
 
 #ifdef MOZ_TASK_TRACER
   // mTracedTask is an instance of FakeTracedTask created by
   // DispatchTracedTask(). AutoRunFakeTracedTask logs the begin/end time of the
   // timer/FakeTracedTask instance in ctor/dtor.
   mozilla::tasktracer::AutoRunFakeTracedTask runTracedTask(mTracedTask);